diff -Nru rustc-1.56.0+dfsg1+llvm/Cargo.lock rustc-1.57.0+dfsg1+llvm/Cargo.lock --- rustc-1.56.0+dfsg1+llvm/Cargo.lock 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/Cargo.lock 2021-11-29 19:27:11.000000000 +0000 @@ -26,9 +26,9 @@ [[package]] name = "aho-corasick" -version = "0.7.13" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -221,6 +221,18 @@ version = "0.1.0" [[package]] +name = "bump-stage0" +version = "0.1.0" +dependencies = [ + "anyhow", + "curl", + "indexmap", + "serde", + "serde_json", + "toml", +] + +[[package]] name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -255,7 +267,7 @@ [[package]] name = "cargo" -version = "0.57.0" +version = "0.58.0" dependencies = [ "anyhow", "atty", @@ -281,7 +293,7 @@ "humantime 2.0.1", "ignore", "im-rc", - "itertools 0.10.0", + "itertools 0.10.1", "jobserver", "lazy_static", "lazycell", @@ -292,6 +304,7 @@ "num_cpus", "opener", "openssl", + "os_info", "percent-encoding 2.1.0", "pretty_env_logger", "rustc-workspace-hack", @@ -348,7 +361,7 @@ dependencies = [ "directories", "rustc-workspace-hack", - "rustc_version", + "rustc_version 0.3.3", "serde", "serde_json", "vergen", @@ -376,7 +389,7 @@ "flate2", "git2", "glob", - "itertools 0.10.0", + "itertools 0.10.1", "lazy_static", "remove_dir_all", "serde_json", @@ -542,13 +555,16 @@ [[package]] name = "clippy" -version = "0.1.56" +version = "0.1.57" dependencies = [ "cargo_metadata 0.12.0", "clippy_lints", + "clippy_utils", "compiletest_rs", "derive-new", "filetime", + "if_chain", + "itertools 0.10.1", "quote", "regex", "rustc-workspace-hack", @@ -566,7 +582,7 @@ dependencies = [ "bytecount", "clap", - "itertools 0.9.0", + "itertools 0.10.1", "opener", "regex", "shell-escape", @@ -575,12 +591,12 @@ [[package]] name = "clippy_lints" -version = "0.1.56" +version = "0.1.57" dependencies = [ "cargo_metadata 0.12.0", "clippy_utils", "if_chain", - "itertools 0.9.0", + "itertools 0.10.1", "pulldown-cmark 0.8.0", "quine-mc_cluskey", "regex-syntax", @@ -596,14 +612,10 @@ [[package]] name = "clippy_utils" -version = "0.1.56" +version = "0.1.57" dependencies = [ "if_chain", - "itertools 0.9.0", - "regex-syntax", "rustc-semver", - "serde", - "unicode-normalization", ] [[package]] @@ -678,9 +690,9 @@ [[package]] name = "compiletest_rs" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb" +checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca" dependencies = [ "diff", "filetime", @@ -856,9 +868,9 @@ [[package]] name = "curl" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003cb79c1c6d1c93344c7e1201bb51c2148f24ec2bd9c253709d6b2efb796515" +checksum = "aaa3b8db7f3341ddef15786d250106334d4a6c4b0ae4a46cd77082777d9849b9" dependencies = [ "curl-sys", "libc", @@ -1083,19 +1095,6 @@ [[package]] name = "env_logger" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd" -dependencies = [ - "atty", - "humantime 2.0.1", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "env_logger" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" @@ -1429,9 +1428,9 @@ [[package]] name = "git2" -version = "0.13.17" +version = "0.13.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986" +checksum = "2a8057932925d3a9d9e4434ea016570d37420ddb1ceed45a174d577f24ed6700" dependencies = [ "bitflags", "libc", @@ -1649,7 +1648,7 @@ dependencies = [ "bitmaps", "rand_core 0.5.1", - "rand_xoshiro", + "rand_xoshiro 0.4.0", "sized-chunks", "typenum", "version_check", @@ -1663,6 +1662,7 @@ dependencies = [ "autocfg", "hashbrown", + "serde", ] [[package]] @@ -1708,9 +1708,9 @@ [[package]] name = "itertools" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" dependencies = [ "either", ] @@ -1880,18 +1880,18 @@ [[package]] name = "libc" -version = "0.2.99" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" dependencies = [ "rustc-std-workspace-core", ] [[package]] name = "libgit2-sys" -version = "0.12.18+1.1.0" +version = "0.12.24+1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885" +checksum = "ddbd6021eef06fb289a8f54b3c2acfdd85ff2a585dfbb24b8576325373d2152c" dependencies = [ "cc", "libc", @@ -2242,15 +2242,15 @@ dependencies = [ "colored", "compiletest_rs", - "env_logger 0.8.1", + "env_logger 0.9.0", "getrandom 0.2.0", "hex 0.4.2", "libc", "log", "measureme", - "rand 0.8.3", + "rand 0.8.4", "rustc-workspace-hack", - "rustc_version", + "rustc_version 0.4.0", "shell-escape", "smallvec", ] @@ -2314,6 +2314,15 @@ ] [[package]] +name = "odht" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a518809ac14b25b569624d0268eba1e88498f71615893dca57982bed7621abb" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] name = "once_cell" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2400,6 +2409,17 @@ checksum = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024" [[package]] +name = "os_info" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac91020bfed8cc3f8aa450d4c3b5fa1d3373fc091c8a92009f3b27749d5a227" +dependencies = [ + "log", + "serde", + "winapi", +] + +[[package]] name = "output_vt100" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2835,9 +2855,9 @@ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha 0.3.0", @@ -2929,6 +2949,15 @@ ] [[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.2", +] + +[[package]] name = "rayon" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2974,9 +3003,9 @@ [[package]] name = "regex" -version = "1.4.6" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -3590,6 +3619,33 @@ ] [[package]] +name = "rustc_borrowck" +version = "0.0.0" +dependencies = [ + "either", + "itertools 0.9.0", + "polonius-engine", + "rustc_const_eval", + "rustc_data_structures", + "rustc_errors", + "rustc_graphviz", + "rustc_hir", + "rustc_index", + "rustc_infer", + "rustc_lexer", + "rustc_middle", + "rustc_mir_dataflow", + "rustc_serialize", + "rustc_session", + "rustc_span", + "rustc_target", + "rustc_trait_selection", + "rustc_traits", + "smallvec", + "tracing", +] + +[[package]] name = "rustc_builtin_macros" version = "0.0.0" dependencies = [ @@ -3619,6 +3675,7 @@ "libc", "measureme", "rustc-demangle", + "rustc_arena", "rustc_ast", "rustc_attr", "rustc_codegen_ssa", @@ -3630,6 +3687,7 @@ "rustc_llvm", "rustc_metadata", "rustc_middle", + "rustc_query_system", "rustc_serialize", "rustc_session", "rustc_span", @@ -3661,7 +3719,9 @@ "rustc_incremental", "rustc_index", "rustc_macros", + "rustc_metadata", "rustc_middle", + "rustc_query_system", "rustc_serialize", "rustc_session", "rustc_span", @@ -3673,6 +3733,29 @@ ] [[package]] +name = "rustc_const_eval" +version = "0.0.0" +dependencies = [ + "rustc_apfloat", + "rustc_ast", + "rustc_attr", + "rustc_data_structures", + "rustc_errors", + "rustc_hir", + "rustc_index", + "rustc_infer", + "rustc_macros", + "rustc_middle", + "rustc_mir_dataflow", + "rustc_query_system", + "rustc_session", + "rustc_span", + "rustc_target", + "rustc_trait_selection", + "tracing", +] + +[[package]] name = "rustc_data_structures" version = "0.0.0" dependencies = [ @@ -3710,6 +3793,7 @@ "rustc_ast", "rustc_ast_pretty", "rustc_codegen_ssa", + "rustc_const_eval", "rustc_data_structures", "rustc_error_codes", "rustc_errors", @@ -3720,7 +3804,6 @@ "rustc_lint", "rustc_metadata", "rustc_middle", - "rustc_mir", "rustc_parse", "rustc_plugin_impl", "rustc_save_analysis", @@ -3799,6 +3882,7 @@ name = "rustc_hir" version = "0.0.0" dependencies = [ + "odht", "rustc_ast", "rustc_data_structures", "rustc_feature", @@ -3879,9 +3963,11 @@ "rustc_ast_lowering", "rustc_ast_passes", "rustc_attr", + "rustc_borrowck", "rustc_builtin_macros", "rustc_codegen_llvm", "rustc_codegen_ssa", + "rustc_const_eval", "rustc_data_structures", "rustc_errors", "rustc_expand", @@ -3890,8 +3976,9 @@ "rustc_lint", "rustc_metadata", "rustc_middle", - "rustc_mir", "rustc_mir_build", + "rustc_mir_transform", + "rustc_monomorphize", "rustc_parse", "rustc_passes", "rustc_plugin_impl", @@ -3982,6 +4069,7 @@ version = "0.0.0" dependencies = [ "libc", + "odht", "rustc_ast", "rustc_attr", "rustc_data_structures", @@ -4009,7 +4097,11 @@ dependencies = [ "bitflags", "chalk-ir", + "either", + "gsgdt", "polonius-engine", + "rand 0.8.4", + "rand_xoshiro 0.6.0", "rustc-rayon-core", "rustc_apfloat", "rustc_arena", @@ -4018,6 +4110,7 @@ "rustc_data_structures", "rustc_errors", "rustc_feature", + "rustc_graphviz", "rustc_hir", "rustc_index", "rustc_macros", @@ -4032,51 +4125,64 @@ ] [[package]] -name = "rustc_mir" +name = "rustc_mir_build" version = "0.0.0" dependencies = [ - "coverage_test_macros", - "either", - "gsgdt", - "itertools 0.9.0", - "polonius-engine", - "regex", "rustc_apfloat", + "rustc_arena", "rustc_ast", "rustc_attr", "rustc_data_structures", "rustc_errors", - "rustc_graphviz", "rustc_hir", "rustc_index", "rustc_infer", - "rustc_lexer", - "rustc_macros", "rustc_middle", "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_traits", "smallvec", "tracing", ] [[package]] -name = "rustc_mir_build" +name = "rustc_mir_dataflow" version = "0.0.0" dependencies = [ - "rustc_apfloat", - "rustc_arena", + "polonius-engine", + "regex", + "rustc_ast", + "rustc_data_structures", + "rustc_graphviz", + "rustc_hir", + "rustc_index", + "rustc_middle", + "rustc_serialize", + "rustc_session", + "rustc_span", + "rustc_target", + "smallvec", + "tracing", +] + +[[package]] +name = "rustc_mir_transform" +version = "0.0.0" +dependencies = [ + "coverage_test_macros", + "itertools 0.9.0", "rustc_ast", "rustc_attr", + "rustc_const_eval", "rustc_data_structures", "rustc_errors", "rustc_hir", "rustc_index", - "rustc_infer", "rustc_middle", + "rustc_mir_dataflow", + "rustc_query_system", "rustc_serialize", "rustc_session", "rustc_span", @@ -4087,6 +4193,22 @@ ] [[package]] +name = "rustc_monomorphize" +version = "0.0.0" +dependencies = [ + "rustc_data_structures", + "rustc_errors", + "rustc_hir", + "rustc_index", + "rustc_middle", + "rustc_session", + "rustc_span", + "rustc_target", + "smallvec", + "tracing", +] + +[[package]] name = "rustc_parse" version = "0.0.0" dependencies = [ @@ -4101,6 +4223,7 @@ "rustc_span", "tracing", "unicode-normalization", + "unicode-width", ] [[package]] @@ -4191,13 +4314,17 @@ "parking_lot", "rustc-rayon-core", "rustc_arena", + "rustc_ast", "rustc_data_structures", "rustc_errors", + "rustc_feature", + "rustc_hir", "rustc_index", "rustc_macros", "rustc_serialize", "rustc_session", "rustc_span", + "rustc_target", "smallvec", "tracing", ] @@ -4265,6 +4392,7 @@ "rustc_errors", "rustc_feature", "rustc_fs_util", + "rustc_hir", "rustc_lint_defs", "rustc_macros", "rustc_serialize", @@ -4300,6 +4428,7 @@ "rustc_data_structures", "rustc_hir", "rustc_middle", + "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", @@ -4340,9 +4469,11 @@ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_lint_defs", "rustc_macros", "rustc_middle", "rustc_parse_format", + "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", @@ -4432,6 +4563,15 @@ ] [[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.3", +] + +[[package]] name = "rustdoc" version = "0.0.0" dependencies = [ @@ -4791,9 +4931,9 @@ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "snap" @@ -4991,7 +5131,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", + "rand 0.8.4", "redox_syscall", "remove_dir_all", "winapi", @@ -5240,9 +5380,9 @@ [[package]] name = "tracing" -version = "0.1.25" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -5252,9 +5392,9 @@ [[package]] name = "tracing-attributes" -version = "0.1.13" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a9bd1db7706f2373a190b0d067146caa39350c486f3d455b0e33b431f94c07" +checksum = "c4f915eb6abf914599c200260efced9203504c4c37380af10cdf3b7d36970650" dependencies = [ "proc-macro2", "quote", @@ -5263,9 +5403,9 @@ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ "lazy_static", ] diff -Nru rustc-1.56.0+dfsg1+llvm/Cargo.toml rustc-1.57.0+dfsg1+llvm/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -35,12 +35,14 @@ "src/tools/expand-yaml-anchors", "src/tools/jsondocck", "src/tools/html-checker", + "src/tools/bump-stage0", "src/tools/lld-wrapper", ] exclude = [ "build", "compiler/rustc_codegen_cranelift", + "compiler/rustc_codegen_gcc", "src/test/rustdoc-gui", # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`. "obj", @@ -87,6 +89,15 @@ miniz_oxide.debug = 0 object.debug = 0 +# The only package that ever uses debug builds is bootstrap. +# We care a lot about bootstrap's compile times, so don't include debug info for +# dependencies, only bootstrap itself. +[profile.dev] +debug = 0 +[profile.dev.package] +# Only use debuginfo=1 to further reduce compile times. +bootstrap.debug = 1 + # We want the RLS to use the version of Cargo that we've got vendored in this # repository to ensure that the same exact version of Cargo is used by both the # RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc-main" version = "0.0.0" -edition = '2018' +edition = "2021" [dependencies] rustc_driver = { path = "../rustc_driver" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_apfloat/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_apfloat/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_apfloat/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_apfloat/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_apfloat" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] bitflags = "1.2.1" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_apfloat/src/ieee.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_apfloat/src/ieee.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_apfloat/src/ieee.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_apfloat/src/ieee.rs 2021-11-29 19:27:11.000000000 +0000 @@ -389,6 +389,7 @@ let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize); // Change the exponent from 2^e to 10^e. + #[allow(clippy::comparison_chain)] if exp == 0 { // Nothing to do. } else if exp > 0 { @@ -2526,6 +2527,7 @@ if *a_sign ^ b_sign { let (reverse, loss); + #[allow(clippy::comparison_chain)] if bits == 0 { reverse = cmp(a_sig, b_sig) == Ordering::Less; loss = Loss::ExactlyZero; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_arena/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_arena/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_arena/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_arena/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_arena" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustc_data_structures = { path = "../rustc_data_structures" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_ast" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/src/ast.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/src/ast.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/src/ast.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/src/ast.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1211,6 +1211,8 @@ } } + ExprKind::Underscore => TyKind::Infer, + // This expression doesn't look like a type syntactically. _ => return None, }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/src/attr/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/src/attr/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/src/attr/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/src/attr/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -367,7 +367,7 @@ let is_first = i == 0; if !is_first { let mod_sep_span = - Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt()); + Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt(), None); idents.push(TokenTree::token(token::ModSep, mod_sep_span).into()); } idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into()); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,29 +9,17 @@ test(attr(deny(warnings))) )] #![feature(box_patterns)] -#![cfg_attr(bootstrap, feature(const_fn_transmute))] #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(iter_zip)] #![feature(label_break_value)] #![feature(nll)] #![feature(min_specialization)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard #![recursion_limit = "256"] #[macro_use] extern crate rustc_macros; -#[macro_export] -macro_rules! unwrap_or { - ($opt:expr, $default:expr) => { - match $opt { - Some(x) => x, - None => $default, - } - }; -} - pub mod util { pub mod classify; pub mod comments; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/src/token.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/src/token.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast/src/token.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast/src/token.rs 2021-11-29 19:27:11.000000000 +0000 @@ -295,6 +295,7 @@ match *self { Comma => Some(vec![Dot, Lt, Semi]), Semi => Some(vec![Colon, Comma]), + FatArrow => Some(vec![Eq, RArrow]), _ => None, } } @@ -586,6 +587,13 @@ self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) } + pub fn is_numeric_lit(&self) -> bool { + matches!( + self.kind, + Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. }) + ) + } + /// Returns `true` if the token is a non-raw identifier for which `pred` holds. pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool { match self.ident() { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_ast_lowering" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/asm.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/asm.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/asm.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/asm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -202,39 +202,20 @@ let mut used_input_regs = FxHashMap::default(); let mut used_output_regs = FxHashMap::default(); - let mut required_features: Vec<&str> = vec![]; + for (idx, &(ref op, op_sp)) in operands.iter().enumerate() { if let Some(reg) = op.reg() { - // Make sure we don't accidentally carry features from the - // previous iteration. - required_features.clear(); - let reg_class = reg.reg_class(); if reg_class == asm::InlineAsmRegClass::Err { continue; } - // We ignore target feature requirements for clobbers: if the - // feature is disabled then the compiler doesn't care what we - // do with the registers. - // - // Note that this is only possible for explicit register - // operands, which cannot be used in the asm string. - let is_clobber = matches!( - op, - hir::InlineAsmOperand::Out { - reg: asm::InlineAsmRegOrRegClass::Reg(_), - late: _, - expr: None - } - ); - // Some register classes can only be used as clobbers. This // means that we disallow passing a value in/out of the asm and // require that the operand name an explicit register, not a // register class. if reg_class.is_clobber_only(asm_arch.unwrap()) - && !(is_clobber && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_))) + && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_))) { let msg = format!( "register class `{}` can only be used as a clobber, \ @@ -245,47 +226,6 @@ continue; } - if !is_clobber { - // Validate register classes against currently enabled target - // features. We check that at least one type is available for - // the current target. - for &(_, feature) in reg_class.supported_types(asm_arch.unwrap()) { - if let Some(feature) = feature { - if self.sess.target_features.contains(&Symbol::intern(feature)) { - required_features.clear(); - break; - } else { - required_features.push(feature); - } - } else { - required_features.clear(); - break; - } - } - // We are sorting primitive strs here and can use unstable sort here - required_features.sort_unstable(); - required_features.dedup(); - match &required_features[..] { - [] => {} - [feature] => { - let msg = format!( - "register class `{}` requires the `{}` target feature", - reg_class.name(), - feature - ); - sess.struct_span_err(op_sp, &msg).emit(); - } - features => { - let msg = format!( - "register class `{}` requires at least one target feature: {}", - reg_class.name(), - features.join(", ") - ); - sess.struct_span_err(op_sp, &msg).emit(); - } - } - } - // Check for conflicts between explicit register operands. if let asm::InlineAsmRegOrRegClass::Reg(reg) = reg { let (input, output) = match op { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/block.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/block.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/block.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/block.rs 2021-11-29 19:27:11.000000000 +0000 @@ -55,7 +55,7 @@ } } StmtKind::Item(ref it) => { - stmts.extend(self.lower_item_id(it).into_iter().enumerate().map( + stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map( |(i, item_id)| { let hir_id = match i { 0 => self.lower_node_id(s.id), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/expr.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/expr.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/expr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/expr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -55,7 +55,6 @@ 0, ParenthesizedGenericArgs::Err, ImplTraitContext::disallowed(), - None, )); let args = self.lower_exprs(args); hir::ExprKind::MethodCall( @@ -101,10 +100,13 @@ ExprKind::If(ref cond, ref then, ref else_opt) => { self.lower_expr_if(cond, then, else_opt.as_deref()) } - ExprKind::While(ref cond, ref body, opt_label) => self - .with_loop_scope(e.id, |this| { - this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label) - }), + ExprKind::While(ref cond, ref body, opt_label) => { + self.with_loop_scope(e.id, |this| { + let span = + this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); + this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) + }) + } ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { hir::ExprKind::Loop( this.lower_block(body, false), @@ -328,7 +330,7 @@ let mut generic_args = vec![]; for (idx, arg) in args.into_iter().enumerate() { if legacy_args_idx.contains(&idx) { - let parent_def_id = self.current_hir_id_owner.0; + let parent_def_id = self.current_hir_id_owner; let node_id = self.resolver.next_node_id(); // Add a definition for the in-band const def. @@ -422,7 +424,9 @@ let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr)); let if_expr = self.expr(span, if_kind, ThinVec::new()); let block = self.block_expr(self.arena.alloc(if_expr)); - hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span.with_hi(cond.span.hi())) + let span = self.lower_span(span.with_hi(cond.span.hi())); + let opt_label = self.lower_label(opt_label); + hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span) } /// Desugar `try { ; }` into `{ ; ::std::ops::Try::from_output() }`, @@ -1186,9 +1190,7 @@ } } None => self - .loop_scopes - .last() - .cloned() + .loop_scope .map(|id| Ok(self.lower_node_id(id))) .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)), }; @@ -1208,18 +1210,9 @@ } fn with_catch_scope(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - let len = self.catch_scopes.len(); - self.catch_scopes.push(catch_id); - + let old_scope = self.catch_scope.replace(catch_id); let result = f(self); - assert_eq!( - len + 1, - self.catch_scopes.len(), - "catch scopes should be added and removed in stack order" - ); - - self.catch_scopes.pop().unwrap(); - + self.catch_scope = old_scope; result } @@ -1228,17 +1221,9 @@ let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; - let len = self.loop_scopes.len(); - self.loop_scopes.push(loop_id); - + let old_scope = self.loop_scope.replace(loop_id); let result = f(self); - assert_eq!( - len + 1, - self.loop_scopes.len(), - "loop scopes should be added and removed in stack order" - ); - - self.loop_scopes.pop().unwrap(); + self.loop_scope = old_scope; self.is_in_loop_condition = was_in_loop_condition; @@ -1469,8 +1454,13 @@ ) }; + // #82462: to correctly diagnose borrow errors, the block that contains + // the iter expr needs to have a span that covers the loop body. + let desugared_full_span = + self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None); + let match_expr = self.arena.alloc(self.expr_match( - desugared_span, + desugared_full_span, into_iter_expr, arena_vec![self; iter_arm], hir::MatchSource::ForLoopDesugar, @@ -1484,7 +1474,7 @@ // surrounding scope of the `match` since the `match` is not a terminating scope. // // Also, add the attributes to the outer returned expr node. - self.expr_drop_temps_mut(desugared_span, match_expr, attrs.into()) + self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into()) } /// Desugar `ExprKind::Try` from: `?` into: @@ -1565,8 +1555,7 @@ unstable_span, ); let thin_attrs = ThinVec::from(attrs); - let catch_scope = self.catch_scopes.last().copied(); - let ret_expr = if let Some(catch_node) = catch_scope { + let ret_expr = if let Some(catch_node) = self.catch_scope { let target_id = Ok(self.lower_node_id(catch_node)); self.arena.alloc(self.expr( try_span, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/item.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/item.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/item.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/item.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,6 @@ use super::{ImplTraitContext, ImplTraitPosition}; use crate::Arena; -use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::*; @@ -42,21 +41,13 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { fn visit_item(&mut self, item: &'a Item) { let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| { - lctx.without_in_scope_lifetime_defs(|lctx| { - let hir_item = lctx.lower_item(item); - lctx.insert_item(hir_item) - }) + let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item)); + hir::OwnerNode::Item(node) }); self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { let this = &mut ItemLowerer { lctx: this }; match item.kind { - ItemKind::Mod(..) => { - let def_id = this.lctx.lower_node_id(item.id).expect_owner(); - let old_current_module = mem::replace(&mut this.lctx.current_module, def_id); - visit::walk_item(this, item); - this.lctx.current_module = old_current_module; - } ItemKind::Impl(box ImplKind { ref of_trait, .. }) => { this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); } @@ -79,24 +70,16 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt { - AssocCtxt::Trait => { - let hir_item = lctx.lower_trait_item(item); - lctx.insert_trait_item(hir_item); - } - AssocCtxt::Impl => { - let hir_item = lctx.lower_impl_item(item); - lctx.insert_impl_item(hir_item); - } + AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)), }); visit::walk_assoc_item(self, item, ctxt); } fn visit_foreign_item(&mut self, item: &'a ForeignItem) { - self.lctx.allocate_hir_id_counter(item.id); self.lctx.with_hir_id_owner(item.id, |lctx| { - let hir_item = lctx.lower_foreign_item(item); - lctx.insert_foreign_item(hir_item); + hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)) }); visit::walk_foreign_item(self, item); @@ -111,12 +94,12 @@ // only used when lowering a child item of a trait or impl. fn with_parent_item_lifetime_defs( &mut self, - parent_hir_id: hir::ItemId, + parent_hir_id: LocalDefId, f: impl FnOnce(&mut Self) -> T, ) -> T { let old_len = self.in_scope_lifetimes.len(); - let parent_generics = match self.owners[parent_hir_id.def_id].unwrap().expect_item().kind { + let parent_generics = match self.owners[parent_hir_id].unwrap().expect_item().kind { hir::ItemKind::Impl(hir::Impl { ref generics, .. }) | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, _ => &[], @@ -155,41 +138,28 @@ pub(super) fn lower_mod(&mut self, items: &[P], inner: Span) -> hir::Mod<'hir> { hir::Mod { inner: self.lower_span(inner), - item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))), + item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_ref(x))), } } - pub(super) fn lower_item_id(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> { - let node_ids = match i.kind { - ItemKind::Use(ref use_tree) => { - let mut vec = smallvec![i.id]; - self.lower_item_id_use_tree(use_tree, i.id, &mut vec); - vec - } - ItemKind::Fn(..) | ItemKind::Impl(box ImplKind { of_trait: None, .. }) => { - smallvec![i.id] - } - _ => smallvec![i.id], - }; - + pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> { + let mut node_ids = smallvec![hir::ItemId { def_id: self.resolver.local_def_id(i.id) }]; + if let ItemKind::Use(ref use_tree) = &i.kind { + self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids); + } node_ids - .into_iter() - .map(|node_id| hir::ItemId { - def_id: self.allocate_hir_id_counter(node_id).expect_owner(), - }) - .collect() } fn lower_item_id_use_tree( &mut self, tree: &UseTree, base_id: NodeId, - vec: &mut SmallVec<[NodeId; 1]>, + vec: &mut SmallVec<[hir::ItemId; 1]>, ) { match tree.kind { UseTreeKind::Nested(ref nested_vec) => { for &(ref nested, id) in nested_vec { - vec.push(id); + vec.push(hir::ItemId { def_id: self.resolver.local_def_id(id) }); self.lower_item_id_use_tree(nested, id, vec); } } @@ -198,25 +168,26 @@ for (_, &id) in iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2]) { - vec.push(id); + vec.push(hir::ItemId { def_id: self.resolver.local_def_id(id) }); } } } } - pub fn lower_item(&mut self, i: &Item) -> hir::Item<'hir> { + fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let mut ident = i.ident; - let mut vis = self.lower_visibility(&i.vis, None); + let mut vis = self.lower_visibility(&i.vis); let hir_id = self.lower_node_id(i.id); let attrs = self.lower_attrs(hir_id, &i.attrs); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind); - hir::Item { + let item = hir::Item { def_id: hir_id.expect_owner(), ident: self.lower_ident(ident), kind, vis, span: self.lower_span(i.span), - } + }; + self.arena.alloc(item) } fn lower_item_kind( @@ -487,7 +458,7 @@ } } - let mut resolutions = self.expect_full_res_from_use(id); + let mut resolutions = self.expect_full_res_from_use(id).fuse(); // We want to return *something* from this function, so hold onto the first item // for later. let ret_res = self.lower_res(resolutions.next().unwrap_or(Res::Err)); @@ -497,7 +468,18 @@ // won't be dealing with macros in the rest of the compiler. // Essentially a single `use` which imports two names is desugared into // two imports. - for (res, &new_node_id) in iter::zip(resolutions, &[id1, id2]) { + for new_node_id in [id1, id2] { + let new_id = self.resolver.local_def_id(new_node_id); + let res = if let Some(res) = resolutions.next() { + res + } else { + // Associate an HirId to both ids even if there is no resolution. + let _old = self + .node_id_to_hir_id + .insert(new_node_id, hir::HirId::make_owner(new_id)); + debug_assert!(_old.is_none()); + continue; + }; let ident = *ident; let mut path = path.clone(); for seg in &mut path.segments { @@ -506,26 +488,26 @@ let span = path.span; self.with_hir_id_owner(new_node_id, |this| { - let new_id = this.lower_node_id(new_node_id); let res = this.lower_res(res); - let path = this.lower_path_extra(res, &path, ParamMode::Explicit, None); + let path = this.lower_path_extra(res, &path, ParamMode::Explicit); let kind = hir::ItemKind::Use(path, hir::UseKind::Single); let vis = this.rebuild_vis(&vis); if let Some(attrs) = attrs { - this.attrs.insert(new_id, attrs); + this.attrs.insert(hir::HirId::make_owner(new_id), attrs); } - this.insert_item(hir::Item { - def_id: new_id.expect_owner(), + let item = hir::Item { + def_id: new_id, ident: this.lower_ident(ident), kind, vis, span: this.lower_span(span), - }); + }; + hir::OwnerNode::Item(this.arena.alloc(item)) }); } - let path = self.lower_path_extra(ret_res, &path, ParamMode::Explicit, None); + let path = self.lower_path_extra(ret_res, &path, ParamMode::Explicit); hir::ItemKind::Use(path, hir::UseKind::Single) } UseTreeKind::Glob => { @@ -565,7 +547,7 @@ // Add all the nested `PathListItem`s to the HIR. for &(ref use_tree, id) in trees { - let new_hir_id = self.lower_node_id(id); + let new_hir_id = self.resolver.local_def_id(id); let mut prefix = prefix.clone(); @@ -586,16 +568,17 @@ let kind = this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs); if let Some(attrs) = attrs { - this.attrs.insert(new_hir_id, attrs); + this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs); } - this.insert_item(hir::Item { - def_id: new_hir_id.expect_owner(), + let item = hir::Item { + def_id: new_hir_id, ident: this.lower_ident(ident), kind, vis, span: this.lower_span(use_tree.span), - }); + }; + hir::OwnerNode::Item(this.arena.alloc(item)) }); } @@ -625,7 +608,7 @@ let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err); let res = self.lower_res(res); - let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit, None); + let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit); hir::ItemKind::Use(path, hir::UseKind::ListStem) } } @@ -662,11 +645,11 @@ respan(self.lower_span(vis.span), vis_kind) } - fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> { + fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = self.lower_node_id(i.id); let def_id = hir_id.expect_owner(); self.lower_attrs(hir_id, &i.attrs); - hir::ForeignItem { + let item = hir::ForeignItem { def_id, ident: self.lower_ident(i.ident), kind: match i.kind { @@ -694,17 +677,17 @@ ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), }, - vis: self.lower_visibility(&i.vis, None), + vis: self.lower_visibility(&i.vis), span: self.lower_span(i.span), - } + }; + self.arena.alloc(item) } - fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef<'hir> { + fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef { hir::ForeignItemRef { - id: hir::ForeignItemId { def_id: self.lower_node_id(i.id).expect_owner() }, + id: hir::ForeignItemId { def_id: self.resolver.local_def_id(i.id) }, ident: self.lower_ident(i.ident), span: self.lower_span(i.span), - vis: self.lower_visibility(&i.vis, Some(i.id)), } } @@ -772,12 +755,12 @@ // FIXME(jseyfried): positional field hygiene. None => Ident::new(sym::integer(index), self.lower_span(f.span)), }, - vis: self.lower_visibility(&f.vis, None), + vis: self.lower_visibility(&f.vis), ty, } } - fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> { + fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = self.lower_node_id(i.id); let trait_item_def_id = hir_id.expect_owner(); @@ -820,13 +803,14 @@ }; self.lower_attrs(hir_id, &i.attrs); - hir::TraitItem { + let item = hir::TraitItem { def_id: trait_item_def_id, ident: self.lower_ident(i.ident), generics, kind, span: self.lower_span(i.span), - } + }; + self.arena.alloc(item) } fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef { @@ -840,7 +824,7 @@ } AssocItemKind::MacCall(..) => unimplemented!(), }; - let id = hir::TraitItemId { def_id: self.lower_node_id(i.id).expect_owner() }; + let id = hir::TraitItemId { def_id: self.resolver.local_def_id(i.id) }; let defaultness = hir::Defaultness::Default { has_value: has_default }; hir::TraitItemRef { id, @@ -856,7 +840,7 @@ self.expr(span, hir::ExprKind::Err, AttrVec::new()) } - fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem<'hir> { + fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { let impl_item_def_id = self.resolver.local_def_id(i.id); let (generics, kind) = match &i.kind { @@ -910,26 +894,26 @@ let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = self.lower_node_id(i.id); self.lower_attrs(hir_id, &i.attrs); - hir::ImplItem { + let item = hir::ImplItem { def_id: hir_id.expect_owner(), ident: self.lower_ident(i.ident), generics, - vis: self.lower_visibility(&i.vis, None), + vis: self.lower_visibility(&i.vis), defaultness, kind, span: self.lower_span(i.span), - } + }; + self.arena.alloc(item) } - fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef<'hir> { + fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); hir::ImplItemRef { - id: hir::ImplItemId { def_id: self.lower_node_id(i.id).expect_owner() }, + id: hir::ImplItemId { def_id: self.resolver.local_def_id(i.id) }, ident: self.lower_ident(i.ident), span: self.lower_span(i.span), - vis: self.lower_visibility(&i.vis, Some(i.id)), defaultness, kind: match &i.kind { AssocItemKind::Const(..) => hir::AssocItemKind::Const, @@ -947,25 +931,15 @@ /// lowered. This can happen during `lower_impl_item_ref()` where we need to /// lower a `Visibility` value although we haven't lowered the owning /// `ImplItem` in question yet. - fn lower_visibility( - &mut self, - v: &Visibility, - explicit_owner: Option, - ) -> hir::Visibility<'hir> { + fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility<'hir> { let node = match v.kind { VisibilityKind::Public => hir::VisibilityKind::Public, VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar), VisibilityKind::Restricted { ref path, id } => { debug!("lower_visibility: restricted path id = {:?}", id); - let lowered_id = if let Some(owner) = explicit_owner { - self.lower_node_id_with_owner(id, owner) - } else { - self.lower_node_id(id) - }; - let res = self.expect_full_res(id); - let res = self.lower_res(res); + let lowered_id = self.lower_node_id(id); hir::VisibilityKind::Restricted { - path: self.lower_path_extra(res, path, ParamMode::Explicit, explicit_owner), + path: self.lower_path(id, path, ParamMode::Explicit), hir_id: lowered_id, } } @@ -1348,42 +1322,56 @@ generics: &Generics, itctx: ImplTraitContext<'_, 'hir>, ) -> GenericsCtor<'hir> { - // Collect `?Trait` bounds in where clause and move them to parameter definitions. - let mut add_bounds: NodeMap> = Default::default(); + // Error if `?Trait` bounds in where clauses don't refer directly to type paramters. + // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering + // these into hir when we lower thee where clauses), but this makes it quite difficult to + // keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and + // where clauses for `?Sized`. for pred in &generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(ref bound_pred) = *pred { - 'next_bound: for bound in &bound_pred.bounds { - if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound { - // Check if the where clause type is a plain type parameter. - match self - .resolver - .get_partial_res(bound_pred.bounded_ty.id) - .map(|d| (d.base_res(), d.unresolved_segments())) - { - Some((Res::Def(DefKind::TyParam, def_id), 0)) - if bound_pred.bound_generic_params.is_empty() => - { - for param in &generics.params { - if def_id == self.resolver.local_def_id(param.id).to_def_id() { - add_bounds.entry(param.id).or_default().push(bound.clone()); - continue 'next_bound; - } - } - } - _ => {} - } - self.diagnostic().span_err( - bound_pred.bounded_ty.span, - "`?Trait` bounds are only permitted at the \ - point where a type parameter is declared", - ); + let bound_pred = match *pred { + WherePredicate::BoundPredicate(ref bound_pred) => bound_pred, + _ => continue, + }; + let compute_is_param = || { + // Check if the where clause type is a plain type parameter. + match self + .resolver + .get_partial_res(bound_pred.bounded_ty.id) + .map(|d| (d.base_res(), d.unresolved_segments())) + { + Some((Res::Def(DefKind::TyParam, def_id), 0)) + if bound_pred.bound_generic_params.is_empty() => + { + generics + .params + .iter() + .any(|p| def_id == self.resolver.local_def_id(p.id).to_def_id()) } + // Either the `bounded_ty` is not a plain type parameter, or + // it's not found in the generic type parameters list. + _ => false, + } + }; + // We only need to compute this once per `WherePredicate`, but don't + // need to compute this at all unless there is a Maybe bound. + let mut is_param: Option = None; + for bound in &bound_pred.bounds { + if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) { + continue; + } + let is_param = *is_param.get_or_insert_with(compute_is_param); + if !is_param { + self.diagnostic().span_err( + bound.span(), + "`?Trait` bounds are only permitted at the \ + point where a type parameter is declared", + ); } } } GenericsCtor { - params: self.lower_generic_params_mut(&generics.params, &add_bounds, itctx).collect(), + params: self.lower_generic_params_mut(&generics.params, itctx).collect(), where_clause: self.lower_where_clause(&generics.where_clause), span: self.lower_span(generics.span), } @@ -1416,32 +1404,17 @@ ref bounded_ty, ref bounds, span, - }) => { - self.with_in_scope_lifetime_defs(&bound_generic_params, |this| { - hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_generic_params: this.lower_generic_params( - bound_generic_params, - &NodeMap::default(), - ImplTraitContext::disallowed(), - ), - bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()), - bounds: this.arena.alloc_from_iter(bounds.iter().map( - |bound| match bound { - // We used to ignore `?Trait` bounds, as they were copied into type - // parameters already, but we need to keep them around only for - // diagnostics when we suggest removal of `?Sized` bounds. See - // `suggest_constraining_type_param`. This will need to change if - // we ever allow something *other* than `?Sized`. - GenericBound::Trait(p, TraitBoundModifier::Maybe) => { - hir::GenericBound::Unsized(this.lower_span(p.span)) - } - _ => this.lower_param_bound(bound, ImplTraitContext::disallowed()), - }, - )), - span: this.lower_span(span), - }) + }) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| { + hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bound_generic_params: this + .lower_generic_params(bound_generic_params, ImplTraitContext::disallowed()), + bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()), + bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| { + this.lower_param_bound(bound, ImplTraitContext::disallowed()) + })), + span: this.lower_span(span), }) - } + }), WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, ref bounds, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -38,7 +38,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree}; -use rustc_ast::visit::{self, AssocCtxt, Visitor}; +use rustc_ast::visit; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; use rustc_data_structures::captures::Captures; @@ -64,7 +64,6 @@ use smallvec::SmallVec; use std::collections::BTreeMap; -use std::mem; use tracing::{debug, trace}; macro_rules! arena_vec { @@ -81,8 +80,6 @@ mod pat; mod path; -const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; - rustc_hir::arena_types!(rustc_arena::declare_arena, 'tcx); struct LoweringContext<'a, 'hir: 'a> { @@ -103,8 +100,6 @@ owners: IndexVec>>, bodies: BTreeMap>, - modules: BTreeMap, - generator_kind: Option, attrs: BTreeMap, @@ -117,8 +112,8 @@ /// outside of an `async fn`. current_item: Option, - catch_scopes: Vec, - loop_scopes: Vec, + catch_scope: Option, + loop_scope: Option, is_in_loop_condition: bool, is_in_trait_impl: bool, is_in_dyn_type: bool, @@ -153,10 +148,8 @@ /// vector. in_scope_lifetimes: Vec, - current_module: LocalDefId, - - current_hir_id_owner: (LocalDefId, u32), - item_local_id_counters: NodeMap, + current_hir_id_owner: LocalDefId, + item_local_id_counter: hir::ItemLocalId, node_id_to_hir_id: IndexVec>, allow_try_trait: Option>, @@ -166,12 +159,14 @@ pub trait ResolverAstLowering { fn def_key(&mut self, id: DefId) -> DefKey; + fn def_span(&self, id: LocalDefId) -> Span; + fn item_generics_num_lifetimes(&self, def: DefId) -> usize; fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option>; /// Obtains resolution for a `NodeId` with a single resolution. - fn get_partial_res(&mut self, id: NodeId) -> Option; + fn get_partial_res(&self, id: NodeId) -> Option; /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`. fn get_import_res(&mut self, id: NodeId) -> PerNS>>; @@ -217,6 +212,11 @@ } #[inline] + fn def_span(&self, id: LocalDefId) -> Span { + self.resolver.def_span(id) + } + + #[inline] fn def_path_hash(&self, def_id: DefId) -> DefPathHash { self.resolver.def_path_hash(def_id) } @@ -321,17 +321,15 @@ arena, owners: IndexVec::default(), bodies: BTreeMap::new(), - modules: BTreeMap::new(), attrs: BTreeMap::default(), - catch_scopes: Vec::new(), - loop_scopes: Vec::new(), + catch_scope: None, + loop_scope: None, is_in_loop_condition: false, is_in_trait_impl: false, is_in_dyn_type: false, anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, - current_module: CRATE_DEF_ID, - current_hir_id_owner: (CRATE_DEF_ID, 0), - item_local_id_counters: Default::default(), + current_hir_id_owner: CRATE_DEF_ID, + item_local_id_counter: hir::ItemLocalId::new(0), node_id_to_hir_id: IndexVec::new(), generator_kind: None, task_context: None, @@ -412,66 +410,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> { - /// Full-crate AST visitor that inserts into a fresh - /// `LoweringContext` any information that may be - /// needed from arbitrary locations in the crate, - /// e.g., the number of lifetime generic parameters - /// declared for every type and trait definition. - struct MiscCollector<'tcx, 'lowering, 'hir> { - lctx: &'tcx mut LoweringContext<'lowering, 'hir>, - } - - impl MiscCollector<'_, '_, '_> { - fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) { - match tree.kind { - UseTreeKind::Simple(_, id1, id2) => { - for id in [id1, id2] { - self.lctx.allocate_hir_id_counter(id); - } - } - UseTreeKind::Glob => (), - UseTreeKind::Nested(ref trees) => { - for &(ref use_tree, id) in trees { - self.lctx.allocate_hir_id_counter(id); - self.allocate_use_tree_hir_id_counters(use_tree); - } - } - } - } - } - - impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> { - fn visit_item(&mut self, item: &'tcx Item) { - self.lctx.allocate_hir_id_counter(item.id); - - if let ItemKind::Use(ref use_tree) = item.kind { - self.allocate_use_tree_hir_id_counters(use_tree); - } - - visit::walk_item(self, item); - } - - fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) { - self.lctx.allocate_hir_id_counter(item.id); - visit::walk_assoc_item(self, item, ctxt); - } - - fn visit_foreign_item(&mut self, item: &'tcx ForeignItem) { - self.lctx.allocate_hir_id_counter(item.id); - visit::walk_foreign_item(self, item); - } - } - - self.lower_node_id(CRATE_NODE_ID); - debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == Some(hir::CRATE_HIR_ID)); + debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); - visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c); visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c); - let module = self.arena.alloc(self.lower_mod(&c.items, c.span)); - self.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); - self.owners.ensure_contains_elem(CRATE_DEF_ID, || None); - self.owners[CRATE_DEF_ID] = Some(hir::OwnerNode::Crate(module)); + self.with_hir_id_owner(CRATE_NODE_ID, |lctx| { + let module = lctx.lower_mod(&c.items, c.span); + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); + hir::OwnerNode::Crate(lctx.arena.alloc(module)) + }); let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); for (k, v) in self.resolver.take_trait_map().into_iter() { @@ -502,61 +449,11 @@ } } - let krate = hir::Crate { - owners: self.owners, - bodies: self.bodies, - modules: self.modules, - trait_map, - attrs: self.attrs, - }; + let krate = + hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs }; self.arena.alloc(krate) } - fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId { - let id = item.item_id(); - let item = self.arena.alloc(item); - self.owners.ensure_contains_elem(id.def_id, || None); - self.owners[id.def_id] = Some(hir::OwnerNode::Item(item)); - self.modules.entry(self.current_module).or_default().items.insert(id); - id - } - - fn insert_foreign_item(&mut self, item: hir::ForeignItem<'hir>) -> hir::ForeignItemId { - let id = item.foreign_item_id(); - let item = self.arena.alloc(item); - self.owners.ensure_contains_elem(id.def_id, || None); - self.owners[id.def_id] = Some(hir::OwnerNode::ForeignItem(item)); - self.modules.entry(self.current_module).or_default().foreign_items.insert(id); - id - } - - fn insert_impl_item(&mut self, item: hir::ImplItem<'hir>) -> hir::ImplItemId { - let id = item.impl_item_id(); - let item = self.arena.alloc(item); - self.owners.ensure_contains_elem(id.def_id, || None); - self.owners[id.def_id] = Some(hir::OwnerNode::ImplItem(item)); - self.modules.entry(self.current_module).or_default().impl_items.insert(id); - id - } - - fn insert_trait_item(&mut self, item: hir::TraitItem<'hir>) -> hir::TraitItemId { - let id = item.trait_item_id(); - let item = self.arena.alloc(item); - self.owners.ensure_contains_elem(id.def_id, || None); - self.owners[id.def_id] = Some(hir::OwnerNode::TraitItem(item)); - self.modules.entry(self.current_module).or_default().trait_items.insert(id); - id - } - - fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId { - // Set up the counter if needed. - self.item_local_id_counters.entry(owner).or_insert(0); - // Always allocate the first `HirId` for the owner itself. - let lowered = self.lower_node_id_with_owner(owner, owner); - debug_assert_eq!(lowered.local_id.as_u32(), 0); - lowered - } - fn create_stable_hashing_context(&self) -> LoweringHasher<'_> { LoweringHasher { source_map: CachingSourceMapView::new(self.sess.source_map()), @@ -564,47 +461,30 @@ } } - fn lower_node_id_generic( + fn with_hir_id_owner( &mut self, - ast_node_id: NodeId, - alloc_hir_id: impl FnOnce(&mut Self) -> hir::HirId, - ) -> hir::HirId { - assert_ne!(ast_node_id, DUMMY_NODE_ID); - - let min_size = ast_node_id.as_usize() + 1; + owner: NodeId, + f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>, + ) -> LocalDefId { + let def_id = self.resolver.local_def_id(owner); - if min_size > self.node_id_to_hir_id.len() { - self.node_id_to_hir_id.resize(min_size, None); - } + // Always allocate the first `HirId` for the owner itself. + let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id)); + debug_assert_eq!(_old, None); - if let Some(existing_hir_id) = self.node_id_to_hir_id[ast_node_id] { - existing_hir_id - } else { - // Generate a new `HirId`. - let hir_id = alloc_hir_id(self); - self.node_id_to_hir_id[ast_node_id] = Some(hir_id); + let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id); + let current_local_counter = + std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); - hir_id - } - } + let item = f(self); - fn with_hir_id_owner(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - let counter = self - .item_local_id_counters - .insert(owner, HIR_ID_COUNTER_LOCKED) - .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner)); - let def_id = self.resolver.local_def_id(owner); - let old_owner = std::mem::replace(&mut self.current_hir_id_owner, (def_id, counter)); - let ret = f(self); - let (new_def_id, new_counter) = - std::mem::replace(&mut self.current_hir_id_owner, old_owner); + self.current_hir_id_owner = current_owner; + self.item_local_id_counter = current_local_counter; - debug_assert!(def_id == new_def_id); - debug_assert!(new_counter >= counter); + let _old = self.owners.insert(def_id, item); + debug_assert!(_old.is_none()); - let prev = self.item_local_id_counters.insert(owner, new_counter).unwrap(); - debug_assert!(prev == HIR_ID_COUNTER_LOCKED); - ret + def_id } /// This method allocates a new `HirId` for the given `NodeId` and stores it in @@ -614,34 +494,14 @@ /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped /// properly. Calling the method twice with the same `NodeId` is fine though. fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId { - self.lower_node_id_generic(ast_node_id, |this| { - let &mut (owner, ref mut local_id_counter) = &mut this.current_hir_id_owner; - let local_id = *local_id_counter; - *local_id_counter += 1; - hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) } - }) - } - - fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> hir::HirId { - self.lower_node_id_generic(ast_node_id, |this| { - let local_id_counter = this - .item_local_id_counters - .get_mut(&owner) - .expect("called `lower_node_id_with_owner` before `allocate_hir_id_counter`"); - let local_id = *local_id_counter; - - // We want to be sure not to modify the counter in the map while it - // is also on the stack. Otherwise we'll get lost updates when writing - // back from the stack to the map. - debug_assert!(local_id != HIR_ID_COUNTER_LOCKED); - - *local_id_counter += 1; - let owner = this.resolver.opt_local_def_id(owner).expect( - "you forgot to call `create_def` or are lowering node-IDs \ - that do not belong to the current owner", - ); + assert_ne!(ast_node_id, DUMMY_NODE_ID); - hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) } + *self.node_id_to_hir_id.get_or_insert_with(ast_node_id, || { + // Generate a new `HirId`. + let owner = self.current_hir_id_owner; + let local_id = self.item_local_id_counter; + self.item_local_id_counter.increment_by(1); + hir::HirId { owner, local_id } }) } @@ -652,7 +512,7 @@ fn lower_res(&mut self, res: Res) -> Res { res.map_id(|id| { - self.lower_node_id_generic(id, |_| { + self.node_id_to_hir_id.get(id).copied().flatten().unwrap_or_else(|| { panic!("expected `NodeId` to be lowered already for res {:#?}", res); }) }) @@ -712,9 +572,14 @@ } /// Intercept all spans entering HIR. - /// For now we are not doing anything with the intercepted spans. + /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { - span + if self.sess.opts.debugging_opts.incremental_relative_spans { + span.with_parent(Some(self.current_hir_id_owner)) + } else { + // Do not make spans relative when not using incremental compilation. + span + } } fn lower_ident(&self, ident: Ident) -> Ident { @@ -782,7 +647,7 @@ node_id, DefPathData::LifetimeNs(str_name), ExpnId::root(), - span, + span.with_parent(None), ); hir::GenericParam { @@ -883,7 +748,7 @@ // wouldn't have been added yet. let generics = this.lower_generics_mut( generics, - ImplTraitContext::Universal(&mut params, this.current_hir_id_owner.0), + ImplTraitContext::Universal(&mut params, this.current_hir_id_owner), ); let res = f(this, &mut params); (params, (generics, res)) @@ -911,11 +776,11 @@ let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; - let catch_scopes = mem::take(&mut self.catch_scopes); - let loop_scopes = mem::take(&mut self.loop_scopes); + let catch_scope = self.catch_scope.take(); + let loop_scope = self.loop_scope.take(); let ret = f(self); - self.catch_scopes = catch_scopes; - self.loop_scopes = loop_scopes; + self.catch_scope = catch_scope; + self.loop_scope = loop_scope; self.is_in_loop_condition = was_in_loop_condition; @@ -1089,7 +954,7 @@ } AssocTyConstraintKind::Bound { ref bounds } => { let mut capturable_lifetimes; - let mut parent_def_id = self.current_hir_id_owner.0; + let mut parent_def_id = self.current_hir_id_owner; // Piggy-back on the `impl Trait` context to figure out the correct behavior. let (desugar_to_impl_trait, itctx) = match itctx { // We are in the return position: @@ -1217,7 +1082,7 @@ // Construct an AnonConst where the expr is the "ty"'s path. - let parent_def_id = self.current_hir_id_owner.0; + let parent_def_id = self.current_hir_id_owner; let node_id = self.resolver.next_node_id(); // Add a definition for the in-band const def. @@ -1305,7 +1170,6 @@ hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { generic_params: this.lower_generic_params( &f.generic_params, - &NodeMap::default(), ImplTraitContext::disallowed(), ), unsafety: this.lower_unsafety(f.unsafety), @@ -1486,22 +1350,51 @@ let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id); - self.allocate_hir_id_counter(opaque_ty_node_id); + let mut collected_lifetimes = Vec::new(); + self.with_hir_id_owner(opaque_ty_node_id, |lctx| { + let hir_bounds = lower_bounds(lctx); + + collected_lifetimes = lifetimes_from_impl_trait_bounds( + opaque_ty_node_id, + &hir_bounds, + capturable_lifetimes, + ); - let hir_bounds = self.with_hir_id_owner(opaque_ty_node_id, lower_bounds); + let lifetime_defs = + lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(|&(name, span)| { + let def_node_id = lctx.resolver.next_node_id(); + let hir_id = lctx.lower_node_id(def_node_id); + lctx.resolver.create_def( + opaque_ty_def_id, + def_node_id, + DefPathData::LifetimeNs(name.ident().name), + ExpnId::root(), + span.with_parent(None), + ); - let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds( - opaque_ty_node_id, - opaque_ty_def_id, - &hir_bounds, - capturable_lifetimes, - ); + let (name, kind) = match name { + hir::LifetimeName::Underscore => ( + hir::ParamName::Plain(Ident::with_dummy_span(kw::UnderscoreLifetime)), + hir::LifetimeParamKind::Elided, + ), + hir::LifetimeName::Param(param_name) => { + (param_name, hir::LifetimeParamKind::Explicit) + } + _ => panic!("expected `LifetimeName::Param` or `ParamName::Plain`"), + }; - debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes); + hir::GenericParam { + hir_id, + name, + span, + pure_wrt_drop: false, + bounds: &[], + kind: hir::GenericParamKind::Lifetime { kind }, + } + })); - debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs); + debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs); - self.with_hir_id_owner(opaque_ty_node_id, move |lctx| { let opaque_ty_item = hir::OpaqueTy { generics: hir::Generics { params: lifetime_defs, @@ -1514,11 +1407,18 @@ }; trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id); - lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span); + lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) + }); - // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. - hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes) - }) + let lifetimes = + self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(name, span)| { + hir::GenericArg::Lifetime(hir::Lifetime { hir_id: self.next_id(), span, name }) + })); + + debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes); + + // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. + hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes) } /// Registers a new opaque type with the proper `NodeId`s and @@ -1529,7 +1429,7 @@ opaque_ty_item: hir::OpaqueTy<'hir>, span: Span, opaque_ty_span: Span, - ) { + ) -> hir::OwnerNode<'hir> { let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item); // Generate an `type Foo = impl Trait;` declaration. trace!("registering opaque type with id {:#?}", opaque_ty_id); @@ -1540,198 +1440,7 @@ vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited), span: self.lower_span(opaque_ty_span), }; - - // Insert the item into the global item list. This usually happens - // automatically for all AST items. But this opaque type item - // does not actually exist in the AST. - self.insert_item(opaque_ty_item); - } - - fn lifetimes_from_impl_trait_bounds( - &mut self, - opaque_ty_id: NodeId, - parent_def_id: LocalDefId, - bounds: hir::GenericBounds<'hir>, - lifetimes_to_include: Option<&FxHashSet>, - ) -> (&'hir [hir::GenericArg<'hir>], &'hir [hir::GenericParam<'hir>]) { - debug!( - "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \ - parent_def_id={:?}, \ - bounds={:#?})", - opaque_ty_id, parent_def_id, bounds, - ); - - // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that - // appear in the bounds, excluding lifetimes that are created within the bounds. - // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`. - struct ImplTraitLifetimeCollector<'r, 'a, 'hir> { - context: &'r mut LoweringContext<'a, 'hir>, - parent: LocalDefId, - opaque_ty_id: NodeId, - collect_elided_lifetimes: bool, - currently_bound_lifetimes: Vec, - already_defined_lifetimes: FxHashSet, - output_lifetimes: Vec>, - output_lifetime_params: Vec>, - lifetimes_to_include: Option<&'r FxHashSet>, - } - - impl<'r, 'a, 'v, 'hir> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a, 'hir> { - type Map = intravisit::ErasedMap<'v>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs<'v>) { - // Don't collect elided lifetimes used inside of `Fn()` syntax. - if parameters.parenthesized { - let old_collect_elided_lifetimes = self.collect_elided_lifetimes; - self.collect_elided_lifetimes = false; - intravisit::walk_generic_args(self, span, parameters); - self.collect_elided_lifetimes = old_collect_elided_lifetimes; - } else { - intravisit::walk_generic_args(self, span, parameters); - } - } - - fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { - // Don't collect elided lifetimes used inside of `fn()` syntax. - if let hir::TyKind::BareFn(_) = t.kind { - let old_collect_elided_lifetimes = self.collect_elided_lifetimes; - self.collect_elided_lifetimes = false; - - // Record the "stack height" of `for<'a>` lifetime bindings - // to be able to later fully undo their introduction. - let old_len = self.currently_bound_lifetimes.len(); - intravisit::walk_ty(self, t); - self.currently_bound_lifetimes.truncate(old_len); - - self.collect_elided_lifetimes = old_collect_elided_lifetimes; - } else { - intravisit::walk_ty(self, t) - } - } - - fn visit_poly_trait_ref( - &mut self, - trait_ref: &'v hir::PolyTraitRef<'v>, - modifier: hir::TraitBoundModifier, - ) { - // Record the "stack height" of `for<'a>` lifetime bindings - // to be able to later fully undo their introduction. - let old_len = self.currently_bound_lifetimes.len(); - intravisit::walk_poly_trait_ref(self, trait_ref, modifier); - self.currently_bound_lifetimes.truncate(old_len); - } - - fn visit_generic_param(&mut self, param: &'v hir::GenericParam<'v>) { - // Record the introduction of 'a in `for<'a> ...`. - if let hir::GenericParamKind::Lifetime { .. } = param.kind { - // Introduce lifetimes one at a time so that we can handle - // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`. - let lt_name = hir::LifetimeName::Param(param.name); - self.currently_bound_lifetimes.push(lt_name); - } - - intravisit::walk_generic_param(self, param); - } - - fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { - let name = match lifetime.name { - hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { - if self.collect_elided_lifetimes { - // Use `'_` for both implicit and underscore lifetimes in - // `type Foo<'_> = impl SomeTrait<'_>;`. - hir::LifetimeName::Underscore - } else { - return; - } - } - hir::LifetimeName::Param(_) => lifetime.name, - - // Refers to some other lifetime that is "in - // scope" within the type. - hir::LifetimeName::ImplicitObjectLifetimeDefault => return, - - hir::LifetimeName::Error | hir::LifetimeName::Static => return, - }; - - if !self.currently_bound_lifetimes.contains(&name) - && !self.already_defined_lifetimes.contains(&name) - && self.lifetimes_to_include.map_or(true, |lifetimes| lifetimes.contains(&name)) - { - self.already_defined_lifetimes.insert(name); - - self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime { - hir_id: self.context.next_id(), - span: self.context.lower_span(lifetime.span), - name, - })); - - let def_node_id = self.context.resolver.next_node_id(); - let hir_id = - self.context.lower_node_id_with_owner(def_node_id, self.opaque_ty_id); - self.context.resolver.create_def( - self.parent, - def_node_id, - DefPathData::LifetimeNs(name.ident().name), - ExpnId::root(), - lifetime.span, - ); - - let (name, kind) = match name { - hir::LifetimeName::Underscore => ( - hir::ParamName::Plain(Ident::with_dummy_span(kw::UnderscoreLifetime)), - hir::LifetimeParamKind::Elided, - ), - hir::LifetimeName::Param(param_name) => { - (param_name, hir::LifetimeParamKind::Explicit) - } - _ => panic!("expected `LifetimeName::Param` or `ParamName::Plain`"), - }; - let name = match name { - hir::ParamName::Plain(ident) => { - hir::ParamName::Plain(self.context.lower_ident(ident)) - } - name => name, - }; - - self.output_lifetime_params.push(hir::GenericParam { - hir_id, - name, - span: self.context.lower_span(lifetime.span), - pure_wrt_drop: false, - bounds: &[], - kind: hir::GenericParamKind::Lifetime { kind }, - }); - } - } - } - - let mut lifetime_collector = ImplTraitLifetimeCollector { - context: self, - parent: parent_def_id, - opaque_ty_id, - collect_elided_lifetimes: true, - currently_bound_lifetimes: Vec::new(), - already_defined_lifetimes: FxHashSet::default(), - output_lifetimes: Vec::new(), - output_lifetime_params: Vec::new(), - lifetimes_to_include, - }; - - for bound in bounds { - intravisit::walk_param_bound(&mut lifetime_collector, &bound); - } - - let ImplTraitLifetimeCollector { output_lifetimes, output_lifetime_params, .. } = - lifetime_collector; - - ( - self.arena.alloc_from_iter(output_lifetimes), - self.arena.alloc_from_iter(output_lifetime_params), - ) + hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item)) } fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { @@ -1800,7 +1509,7 @@ if let Some((_, ibty)) = &mut in_band_ty_params { this.lower_ty_direct( ¶m.ty, - ImplTraitContext::Universal(ibty, this.current_hir_id_owner.0), + ImplTraitContext::Universal(ibty, this.current_hir_id_owner), ) } else { this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed()) @@ -1893,8 +1602,6 @@ let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id); - self.allocate_hir_id_counter(opaque_ty_node_id); - // When we create the opaque type for this async fn, it is going to have // to capture all the lifetimes involved in the signature (including in the // return type). This is done by introducing lifetime parameters for: @@ -1943,7 +1650,8 @@ // grow. let input_lifetimes_count = self.in_scope_lifetimes.len() + self.lifetimes_to_define.len(); - let lifetime_params = self.with_hir_id_owner(opaque_ty_node_id, |this| { + let mut lifetime_params = Vec::new(); + self.with_hir_id_owner(opaque_ty_node_id, |this| { // We have to be careful to get elision right here. The // idea is that we create a lifetime parameter for each // lifetime in the return type. So, given a return type @@ -1965,7 +1673,7 @@ // // Note: this must be done after lowering the output type, // as the output type may introduce new in-band lifetimes. - let lifetime_params: Vec<(Span, ParamName)> = this + lifetime_params = this .in_scope_lifetimes .iter() .cloned() @@ -1994,9 +1702,7 @@ }; trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id); - this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span); - - lifetime_params + this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) }); // As documented above on the variable @@ -2138,30 +1844,25 @@ fn lower_generic_params_mut<'s>( &'s mut self, params: &'s [GenericParam], - add_bounds: &'s NodeMap>, mut itctx: ImplTraitContext<'s, 'hir>, ) -> impl Iterator> + Captures<'a> + Captures<'s> { - params - .iter() - .map(move |param| self.lower_generic_param(param, add_bounds, itctx.reborrow())) + params.iter().map(move |param| self.lower_generic_param(param, itctx.reborrow())) } fn lower_generic_params( &mut self, params: &[GenericParam], - add_bounds: &NodeMap>, itctx: ImplTraitContext<'_, 'hir>, ) -> &'hir [hir::GenericParam<'hir>] { - self.arena.alloc_from_iter(self.lower_generic_params_mut(params, add_bounds, itctx)) + self.arena.alloc_from_iter(self.lower_generic_params_mut(params, itctx)) } fn lower_generic_param( &mut self, param: &GenericParam, - add_bounds: &NodeMap>, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::GenericParam<'hir> { - let mut bounds: Vec<_> = self + let bounds: Vec<_> = self .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { this.lower_param_bounds_mut(¶m.bounds, itctx.reborrow()).collect() }); @@ -2197,12 +1898,6 @@ (param_name, kind) } GenericParamKind::Type { ref default, .. } => { - let add_bounds = add_bounds.get(¶m.id).map_or(&[][..], |x| &x); - if !add_bounds.is_empty() { - let params = self.lower_param_bounds_mut(add_bounds, itctx.reborrow()); - bounds.extend(params); - } - let kind = hir::GenericParamKind::Type { default: default.as_ref().map(|x| { self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other)) @@ -2263,11 +1958,8 @@ p: &PolyTraitRef, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::PolyTraitRef<'hir> { - let bound_generic_params = self.lower_generic_params( - &p.bound_generic_params, - &NodeMap::default(), - itctx.reborrow(), - ); + let bound_generic_params = + self.lower_generic_params(&p.bound_generic_params, itctx.reborrow()); let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| { // Any impl Trait types defined within this scope can capture @@ -2714,3 +2406,132 @@ this.arena.alloc(ga) } } + +fn lifetimes_from_impl_trait_bounds( + opaque_ty_id: NodeId, + bounds: hir::GenericBounds<'_>, + lifetimes_to_include: Option<&FxHashSet>, +) -> Vec<(hir::LifetimeName, Span)> { + debug!( + "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \ + bounds={:#?})", + opaque_ty_id, bounds, + ); + + // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that + // appear in the bounds, excluding lifetimes that are created within the bounds. + // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`. + struct ImplTraitLifetimeCollector<'r> { + collect_elided_lifetimes: bool, + currently_bound_lifetimes: Vec, + already_defined_lifetimes: FxHashSet, + lifetimes: Vec<(hir::LifetimeName, Span)>, + lifetimes_to_include: Option<&'r FxHashSet>, + } + + impl<'r, 'v> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r> { + type Map = intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs<'v>) { + // Don't collect elided lifetimes used inside of `Fn()` syntax. + if parameters.parenthesized { + let old_collect_elided_lifetimes = self.collect_elided_lifetimes; + self.collect_elided_lifetimes = false; + intravisit::walk_generic_args(self, span, parameters); + self.collect_elided_lifetimes = old_collect_elided_lifetimes; + } else { + intravisit::walk_generic_args(self, span, parameters); + } + } + + fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { + // Don't collect elided lifetimes used inside of `fn()` syntax. + if let hir::TyKind::BareFn(_) = t.kind { + let old_collect_elided_lifetimes = self.collect_elided_lifetimes; + self.collect_elided_lifetimes = false; + + // Record the "stack height" of `for<'a>` lifetime bindings + // to be able to later fully undo their introduction. + let old_len = self.currently_bound_lifetimes.len(); + intravisit::walk_ty(self, t); + self.currently_bound_lifetimes.truncate(old_len); + + self.collect_elided_lifetimes = old_collect_elided_lifetimes; + } else { + intravisit::walk_ty(self, t) + } + } + + fn visit_poly_trait_ref( + &mut self, + trait_ref: &'v hir::PolyTraitRef<'v>, + modifier: hir::TraitBoundModifier, + ) { + // Record the "stack height" of `for<'a>` lifetime bindings + // to be able to later fully undo their introduction. + let old_len = self.currently_bound_lifetimes.len(); + intravisit::walk_poly_trait_ref(self, trait_ref, modifier); + self.currently_bound_lifetimes.truncate(old_len); + } + + fn visit_generic_param(&mut self, param: &'v hir::GenericParam<'v>) { + // Record the introduction of 'a in `for<'a> ...`. + if let hir::GenericParamKind::Lifetime { .. } = param.kind { + // Introduce lifetimes one at a time so that we can handle + // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`. + let lt_name = hir::LifetimeName::Param(param.name); + self.currently_bound_lifetimes.push(lt_name); + } + + intravisit::walk_generic_param(self, param); + } + + fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { + let name = match lifetime.name { + hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { + if self.collect_elided_lifetimes { + // Use `'_` for both implicit and underscore lifetimes in + // `type Foo<'_> = impl SomeTrait<'_>;`. + hir::LifetimeName::Underscore + } else { + return; + } + } + hir::LifetimeName::Param(_) => lifetime.name, + + // Refers to some other lifetime that is "in + // scope" within the type. + hir::LifetimeName::ImplicitObjectLifetimeDefault => return, + + hir::LifetimeName::Error | hir::LifetimeName::Static => return, + }; + + if !self.currently_bound_lifetimes.contains(&name) + && !self.already_defined_lifetimes.contains(&name) + && self.lifetimes_to_include.map_or(true, |lifetimes| lifetimes.contains(&name)) + { + self.already_defined_lifetimes.insert(name); + + self.lifetimes.push((name, lifetime.span)); + } + } + } + + let mut lifetime_collector = ImplTraitLifetimeCollector { + collect_elided_lifetimes: true, + currently_bound_lifetimes: Vec::new(), + already_defined_lifetimes: FxHashSet::default(), + lifetimes: Vec::new(), + lifetimes_to_include, + }; + + for bound in bounds { + intravisit::walk_param_bound(&mut lifetime_collector, &bound); + } + + lifetime_collector.lifetimes +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/path.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/path.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/path.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_lowering/src/path.rs 2021-11-29 19:27:11.000000000 +0000 @@ -99,7 +99,6 @@ num_lifetimes, parenthesized_generic_args, itctx.reborrow(), - None, ) }, )), @@ -147,7 +146,6 @@ 0, ParenthesizedGenericArgs::Err, itctx.reborrow(), - None, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); @@ -178,7 +176,6 @@ res: Res, p: &Path, param_mode: ParamMode, - explicit_owner: Option, ) -> &'hir hir::Path<'hir> { self.arena.alloc(hir::Path { res, @@ -190,7 +187,6 @@ 0, ParenthesizedGenericArgs::Err, ImplTraitContext::disallowed(), - explicit_owner, ) })), span: self.lower_span(p.span), @@ -205,7 +201,7 @@ ) -> &'hir hir::Path<'hir> { let res = self.expect_full_res(id); let res = self.lower_res(res); - self.lower_path_extra(res, p, param_mode, None) + self.lower_path_extra(res, p, param_mode) } crate fn lower_path_segment( @@ -216,7 +212,6 @@ expected_lifetimes: usize, parenthesized_generic_args: ParenthesizedGenericArgs, itctx: ImplTraitContext<'_, 'hir>, - explicit_owner: Option, ) -> hir::PathSegment<'hir> { debug!( "path_span: {:?}, lower_path_segment(segment: {:?}, expected_lifetimes: {:?})", @@ -354,11 +349,7 @@ } let res = self.expect_full_res(segment.id); - let id = if let Some(owner) = explicit_owner { - self.lower_node_id_with_owner(segment.id, owner) - } else { - self.lower_node_id(segment.id) - }; + let id = self.lower_node_id(segment.id); debug!( "lower_path_segment: ident={:?} original-id={:?} new-id={:?}", segment.ident, segment.id, id, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_passes/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_passes/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_passes/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_passes/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_ast_passes" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] itertools = "0.9" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_passes/src/ast_validation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_passes/src/ast_validation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_passes/src/ast_validation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_passes/src/ast_validation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -356,11 +356,25 @@ } fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { + self.check_decl_num_args(fn_decl); self.check_decl_cvaradic_pos(fn_decl); self.check_decl_attrs(fn_decl); self.check_decl_self_param(fn_decl, self_semantic); } + /// Emits fatal error if function declaration has more than `u16::MAX` arguments + /// Error is fatal to prevent errors during typechecking + fn check_decl_num_args(&self, fn_decl: &FnDecl) { + let max_num_args: usize = u16::MAX.into(); + if fn_decl.inputs.len() > max_num_args { + let Param { span, .. } = fn_decl.inputs[0]; + self.err_handler().span_fatal( + span, + &format!("function can not have more than {} arguments", max_num_args), + ); + } + } + fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) { match &*fn_decl.inputs { [Param { ty, span, .. }] => { @@ -576,7 +590,7 @@ ) .span_label(self.current_extern_span(), "in this `extern` block") .note(&format!( - "This limitation may be lifted in the future; see issue #{} for more information", + "this limitation may be lifted in the future; see issue #{} for more information", n, n, )) .emit(); @@ -669,31 +683,53 @@ } } + fn emit_e0568(&self, span: Span, ident_span: Span) { + struct_span_err!( + self.session, + span, + E0568, + "auto traits cannot have super traits or lifetime bounds" + ) + .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds") + .span_suggestion( + span, + "remove the super traits or lifetime bounds", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { - if let [first @ last] | [first, .., last] = &bounds[..] { - let span = first.span().to(last.span()); - struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits") - .span_label(ident_span, "auto trait cannot have super traits") - .span_suggestion( - span, - "remove the super traits", - String::new(), - Applicability::MachineApplicable, - ) - .emit(); + if let [.., last] = &bounds[..] { + let span = ident_span.shrink_to_hi().to(last.span()); + self.emit_e0568(span, ident_span); + } + } + + fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) { + if !where_clause.predicates.is_empty() { + self.emit_e0568(where_clause.span, ident_span); } } fn deny_items(&self, trait_items: &[P], ident_span: Span) { if !trait_items.is_empty() { let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); + let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); struct_span_err!( self.session, spans, E0380, - "auto traits cannot have methods or associated items" + "auto traits cannot have associated items" + ) + .span_suggestion( + total_span, + "remove these associated items", + String::new(), + Applicability::MachineApplicable, ) - .span_label(ident_span, "auto trait cannot have items") + .span_label(ident_span, "auto trait cannot have associated items") .emit(); } } @@ -1170,6 +1206,7 @@ // Auto traits cannot have generics, super traits nor contain items. self.deny_generic_params(generics, item.ident.span); self.deny_super_traits(bounds, item.ident.span); + self.deny_where_clause(&generics.where_clause, item.ident.span); self.deny_items(trait_items, item.ident.span); } self.no_questions_in_bounds(bounds, "supertraits", true); @@ -1587,7 +1624,9 @@ walk_list!(self, visit_ty, ty); } AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body)) - if self.in_const_trait_impl || ctxt == AssocCtxt::Trait => + if self.in_const_trait_impl + || ctxt == AssocCtxt::Trait + || matches!(sig.header.constness, Const::Yes(_)) => { self.visit_vis(&item.vis); self.visit_ident(item.ident); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_passes/src/feature_gate.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_passes/src/feature_gate.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_passes/src/feature_gate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_passes/src/feature_gate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -319,6 +319,7 @@ gate_doc!( cfg => doc_cfg + cfg_hide => doc_cfg_hide masked => doc_masked notable_trait => doc_notable_trait keyword => doc_keyword @@ -762,10 +763,16 @@ } fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { + // checks if `#![feature]` has been used to enable any lang feature + // does not check the same for lib features unless there's at least one + // declared lang feature use rustc_errors::Applicability; if !sess.opts.unstable_features.is_nightly_build() { let lang_features = &sess.features_untracked().declared_lang_features; + if lang_features.len() == 0 { + return; + } for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { let mut err = struct_span_err!( sess.parse_sess.span_diagnostic, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_passes/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_passes/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_passes/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_passes/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ //! //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`. -#![cfg_attr(bootstrap, feature(bindings_after_at))] #![feature(iter_is_partitioned)] #![feature(box_patterns)] #![recursion_limit = "256"] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_pretty/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_pretty/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ast_pretty/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ast_pretty/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_ast_pretty" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_attr/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_attr/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_attr/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_attr/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_attr" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_attr/src/builtin.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_attr/src/builtin.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_attr/src/builtin.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_attr/src/builtin.rs 2021-11-29 19:27:11.000000000 +0000 @@ -66,7 +66,7 @@ } } -#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum InlineAttr { None, Hint, @@ -74,13 +74,13 @@ Never, } -#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)] pub enum InstructionSetAttr { ArmA32, ArmT32, } -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub enum OptimizeAttr { None, Speed, @@ -802,7 +802,7 @@ /// Valid repr contents: any of the primitive integral type names (see /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use /// the same discriminant size that the corresponding C enum would or C -/// structure layout, `packed` to remove padding, and `transparent` to elegate representation +/// structure layout, `packed` to remove padding, and `transparent` to delegate representation /// concerns to the only non-ZST field. pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec { use ReprAttr::*; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +[package] +name = "rustc_borrowck" +version = "0.0.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +either = "1.5.0" +itertools = "0.9" +tracing = "0.1" +polonius-engine = "0.13.0" +smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_graphviz = { path = "../rustc_graphviz" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_middle = { path = "../rustc_middle" } +rustc_const_eval = { path = "../rustc_const_eval" } +rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_traits = { path = "../rustc_traits" } +rustc_span = { path = "../rustc_span" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/borrowck_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/borrowck_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/borrowck_errors.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/borrowck_errors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,487 @@ +use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{MultiSpan, Span}; + +impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { + crate fn cannot_move_when_borrowed(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> { + struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,) + } + + crate fn cannot_use_when_mutably_borrowed( + &self, + span: Span, + desc: &str, + borrow_span: Span, + borrow_desc: &str, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + span, + E0503, + "cannot use {} because it was mutably borrowed", + desc, + ); + + err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_desc)); + err.span_label(span, format!("use of borrowed {}", borrow_desc)); + err + } + + crate fn cannot_act_on_uninitialized_variable( + &self, + span: Span, + verb: &str, + desc: &str, + ) -> DiagnosticBuilder<'cx> { + struct_span_err!( + self, + span, + E0381, + "{} of possibly-uninitialized variable: `{}`", + verb, + desc, + ) + } + + crate fn cannot_mutably_borrow_multiply( + &self, + new_loan_span: Span, + desc: &str, + opt_via: &str, + old_loan_span: Span, + old_opt_via: &str, + old_load_end_span: Option, + ) -> DiagnosticBuilder<'cx> { + let via = + |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; + let mut err = struct_span_err!( + self, + new_loan_span, + E0499, + "cannot borrow {}{} as mutable more than once at a time", + desc, + via(opt_via), + ); + if old_loan_span == new_loan_span { + // Both borrows are happening in the same place + // Meaning the borrow is occurring in a loop + err.span_label( + new_loan_span, + format!( + "{}{} was mutably borrowed here in the previous iteration of the loop{}", + desc, + via(opt_via), + opt_via, + ), + ); + if let Some(old_load_end_span) = old_load_end_span { + err.span_label(old_load_end_span, "mutable borrow ends here"); + } + } else { + err.span_label( + old_loan_span, + format!("first mutable borrow occurs here{}", via(old_opt_via)), + ); + err.span_label( + new_loan_span, + format!("second mutable borrow occurs here{}", via(opt_via)), + ); + if let Some(old_load_end_span) = old_load_end_span { + err.span_label(old_load_end_span, "first borrow ends here"); + } + } + err + } + + crate fn cannot_uniquely_borrow_by_two_closures( + &self, + new_loan_span: Span, + desc: &str, + old_loan_span: Span, + old_load_end_span: Option, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + new_loan_span, + E0524, + "two closures require unique access to {} at the same time", + desc, + ); + if old_loan_span == new_loan_span { + err.span_label( + old_loan_span, + "closures are constructed here in different iterations of loop", + ); + } else { + err.span_label(old_loan_span, "first closure is constructed here"); + err.span_label(new_loan_span, "second closure is constructed here"); + } + if let Some(old_load_end_span) = old_load_end_span { + err.span_label(old_load_end_span, "borrow from first closure ends here"); + } + err + } + + crate fn cannot_uniquely_borrow_by_one_closure( + &self, + new_loan_span: Span, + container_name: &str, + desc_new: &str, + opt_via: &str, + old_loan_span: Span, + noun_old: &str, + old_opt_via: &str, + previous_end_span: Option, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + new_loan_span, + E0500, + "closure requires unique access to {} but {} is already borrowed{}", + desc_new, + noun_old, + old_opt_via, + ); + err.span_label( + new_loan_span, + format!("{} construction occurs here{}", container_name, opt_via), + ); + err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via)); + if let Some(previous_end_span) = previous_end_span { + err.span_label(previous_end_span, "borrow ends here"); + } + err + } + + crate fn cannot_reborrow_already_uniquely_borrowed( + &self, + new_loan_span: Span, + container_name: &str, + desc_new: &str, + opt_via: &str, + kind_new: &str, + old_loan_span: Span, + old_opt_via: &str, + previous_end_span: Option, + second_borrow_desc: &str, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + new_loan_span, + E0501, + "cannot borrow {}{} as {} because previous closure \ + requires unique access", + desc_new, + opt_via, + kind_new, + ); + err.span_label( + new_loan_span, + format!("{}borrow occurs here{}", second_borrow_desc, opt_via), + ); + err.span_label( + old_loan_span, + format!("{} construction occurs here{}", container_name, old_opt_via), + ); + if let Some(previous_end_span) = previous_end_span { + err.span_label(previous_end_span, "borrow from closure ends here"); + } + err + } + + crate fn cannot_reborrow_already_borrowed( + &self, + span: Span, + desc_new: &str, + msg_new: &str, + kind_new: &str, + old_span: Span, + noun_old: &str, + kind_old: &str, + msg_old: &str, + old_load_end_span: Option, + ) -> DiagnosticBuilder<'cx> { + let via = + |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; + let mut err = struct_span_err!( + self, + span, + E0502, + "cannot borrow {}{} as {} because {} is also borrowed as {}{}", + desc_new, + via(msg_new), + kind_new, + noun_old, + kind_old, + via(msg_old), + ); + + if msg_new == "" { + // If `msg_new` is empty, then this isn't a borrow of a union field. + err.span_label(span, format!("{} borrow occurs here", kind_new)); + err.span_label(old_span, format!("{} borrow occurs here", kind_old)); + } else { + // If `msg_new` isn't empty, then this a borrow of a union field. + err.span_label( + span, + format!( + "{} borrow of {} -- which overlaps with {} -- occurs here", + kind_new, msg_new, msg_old, + ), + ); + err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, via(msg_old))); + } + + if let Some(old_load_end_span) = old_load_end_span { + err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old)); + } + err + } + + crate fn cannot_assign_to_borrowed( + &self, + span: Span, + borrow_span: Span, + desc: &str, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + span, + E0506, + "cannot assign to {} because it is borrowed", + desc, + ); + + err.span_label(borrow_span, format!("borrow of {} occurs here", desc)); + err.span_label(span, format!("assignment to borrowed {} occurs here", desc)); + err + } + + crate fn cannot_reassign_immutable( + &self, + span: Span, + desc: &str, + is_arg: bool, + ) -> DiagnosticBuilder<'cx> { + let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; + struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc) + } + + crate fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> { + struct_span_err!(self, span, E0594, "cannot assign to {}", desc) + } + + crate fn cannot_move_out_of( + &self, + move_from_span: Span, + move_from_desc: &str, + ) -> DiagnosticBuilder<'cx> { + struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,) + } + + /// Signal an error due to an attempt to move out of the interior + /// of an array or slice. `is_index` is None when error origin + /// didn't capture whether there was an indexing operation or not. + crate fn cannot_move_out_of_interior_noncopy( + &self, + move_from_span: Span, + ty: Ty<'_>, + is_index: Option, + ) -> DiagnosticBuilder<'cx> { + let type_name = match (&ty.kind(), is_index) { + (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", + (&ty::Slice(_), _) => "slice", + _ => span_bug!(move_from_span, "this path should not cause illegal move"), + }; + let mut err = struct_span_err!( + self, + move_from_span, + E0508, + "cannot move out of type `{}`, a non-copy {}", + ty, + type_name, + ); + err.span_label(move_from_span, "cannot move out of here"); + err + } + + crate fn cannot_move_out_of_interior_of_drop( + &self, + move_from_span: Span, + container_ty: Ty<'_>, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + move_from_span, + E0509, + "cannot move out of type `{}`, which implements the `Drop` trait", + container_ty, + ); + err.span_label(move_from_span, "cannot move out of here"); + err + } + + crate fn cannot_act_on_moved_value( + &self, + use_span: Span, + verb: &str, + optional_adverb_for_moved: &str, + moved_path: Option, + ) -> DiagnosticBuilder<'cx> { + let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default(); + + struct_span_err!( + self, + use_span, + E0382, + "{} of {}moved value{}", + verb, + optional_adverb_for_moved, + moved_path, + ) + } + + crate fn cannot_borrow_path_as_mutable_because( + &self, + span: Span, + path: &str, + reason: &str, + ) -> DiagnosticBuilder<'cx> { + struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,) + } + + crate fn cannot_mutate_in_immutable_section( + &self, + mutate_span: Span, + immutable_span: Span, + immutable_place: &str, + immutable_section: &str, + action: &str, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + mutate_span, + E0510, + "cannot {} {} in {}", + action, + immutable_place, + immutable_section, + ); + err.span_label(mutate_span, format!("cannot {}", action)); + err.span_label(immutable_span, format!("value is immutable in {}", immutable_section)); + err + } + + crate fn cannot_borrow_across_generator_yield( + &self, + span: Span, + yield_span: Span, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + span, + E0626, + "borrow may still be in use when generator yields", + ); + err.span_label(yield_span, "possible yield occurs here"); + err + } + + crate fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> DiagnosticBuilder<'cx> { + struct_span_err!( + self, + borrow_span, + E0713, + "borrow may still be in use when destructor runs", + ) + } + + crate fn path_does_not_live_long_enough( + &self, + span: Span, + path: &str, + ) -> DiagnosticBuilder<'cx> { + struct_span_err!(self, span, E0597, "{} does not live long enough", path,) + } + + crate fn cannot_return_reference_to_local( + &self, + span: Span, + return_kind: &str, + reference_desc: &str, + path_desc: &str, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + span, + E0515, + "cannot {RETURN} {REFERENCE} {LOCAL}", + RETURN = return_kind, + REFERENCE = reference_desc, + LOCAL = path_desc, + ); + + err.span_label( + span, + format!("{}s a {} data owned by the current function", return_kind, reference_desc), + ); + + err + } + + crate fn cannot_capture_in_long_lived_closure( + &self, + closure_span: Span, + closure_kind: &str, + borrowed_path: &str, + capture_span: Span, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + closure_span, + E0373, + "{} may outlive the current function, \ + but it borrows {}, \ + which is owned by the current function", + closure_kind, + borrowed_path, + ); + err.span_label(capture_span, format!("{} is borrowed here", borrowed_path)) + .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path)); + err + } + + crate fn thread_local_value_does_not_live_long_enough( + &self, + span: Span, + ) -> DiagnosticBuilder<'cx> { + struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",) + } + + crate fn temporary_value_borrowed_for_too_long(&self, span: Span) -> DiagnosticBuilder<'cx> { + struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",) + } + + fn struct_span_err_with_code>( + &self, + sp: S, + msg: &str, + code: DiagnosticId, + ) -> DiagnosticBuilder<'tcx> { + self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code) + } +} + +crate fn borrowed_data_escapes_closure<'tcx>( + tcx: TyCtxt<'tcx>, + escape_span: Span, + escapes_from: &str, +) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + tcx.sess, + escape_span, + E0521, + "borrowed data escapes outside of {}", + escapes_from, + ) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/borrow_set.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/borrow_set.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/borrow_set.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/borrow_set.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,351 @@ +use crate::nll::ToRegionVid; +use crate::path_utils::allow_two_phase_borrow; +use crate::place_ext::PlaceExt; +use crate::BorrowIndex; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::traversal; +use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::{self, Body, Local, Location}; +use rustc_middle::ty::{RegionVid, TyCtxt}; +use rustc_mir_dataflow::move_paths::MoveData; +use std::fmt; +use std::ops::Index; + +crate struct BorrowSet<'tcx> { + /// The fundamental map relating bitvector indexes to the borrows + /// in the MIR. Each borrow is also uniquely identified in the MIR + /// by the `Location` of the assignment statement in which it + /// appears on the right hand side. Thus the location is the map + /// key, and its position in the map corresponds to `BorrowIndex`. + crate location_map: FxIndexMap>, + + /// Locations which activate borrows. + /// NOTE: a given location may activate more than one borrow in the future + /// when more general two-phase borrow support is introduced, but for now we + /// only need to store one borrow index. + crate activation_map: FxHashMap>, + + /// Map from local to all the borrows on that local. + crate local_map: FxHashMap>, + + crate locals_state_at_exit: LocalsStateAtExit, +} + +impl<'tcx> Index for BorrowSet<'tcx> { + type Output = BorrowData<'tcx>; + + fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> { + &self.location_map[index.as_usize()] + } +} + +/// Location where a two-phase borrow is activated, if a borrow +/// is in fact a two-phase borrow. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +crate enum TwoPhaseActivation { + NotTwoPhase, + NotActivated, + ActivatedAt(Location), +} + +#[derive(Debug, Clone)] +crate struct BorrowData<'tcx> { + /// Location where the borrow reservation starts. + /// In many cases, this will be equal to the activation location but not always. + crate reserve_location: Location, + /// Location where the borrow is activated. + crate activation_location: TwoPhaseActivation, + /// What kind of borrow this is + crate kind: mir::BorrowKind, + /// The region for which this borrow is live + crate region: RegionVid, + /// Place from which we are borrowing + crate borrowed_place: mir::Place<'tcx>, + /// Place to which the borrow was stored + crate assigned_place: mir::Place<'tcx>, +} + +impl<'tcx> fmt::Display for BorrowData<'tcx> { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + let kind = match self.kind { + mir::BorrowKind::Shared => "", + mir::BorrowKind::Shallow => "shallow ", + mir::BorrowKind::Unique => "uniq ", + mir::BorrowKind::Mut { .. } => "mut ", + }; + write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) + } +} + +crate enum LocalsStateAtExit { + AllAreInvalidated, + SomeAreInvalidated { has_storage_dead_or_moved: BitSet }, +} + +impl LocalsStateAtExit { + fn build( + locals_are_invalidated_at_exit: bool, + body: &Body<'tcx>, + move_data: &MoveData<'tcx>, + ) -> Self { + struct HasStorageDead(BitSet); + + impl<'tcx> Visitor<'tcx> for HasStorageDead { + fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { + if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) { + self.0.insert(*local); + } + } + } + + if locals_are_invalidated_at_exit { + LocalsStateAtExit::AllAreInvalidated + } else { + let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body.local_decls.len())); + has_storage_dead.visit_body(&body); + let mut has_storage_dead_or_moved = has_storage_dead.0; + for move_out in &move_data.moves { + if let Some(index) = move_data.base_local(move_out.path) { + has_storage_dead_or_moved.insert(index); + } + } + LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } + } + } +} + +impl<'tcx> BorrowSet<'tcx> { + pub fn build( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + locals_are_invalidated_at_exit: bool, + move_data: &MoveData<'tcx>, + ) -> Self { + let mut visitor = GatherBorrows { + tcx, + body: &body, + location_map: Default::default(), + activation_map: Default::default(), + local_map: Default::default(), + pending_activations: Default::default(), + locals_state_at_exit: LocalsStateAtExit::build( + locals_are_invalidated_at_exit, + body, + move_data, + ), + }; + + for (block, block_data) in traversal::preorder(&body) { + visitor.visit_basic_block_data(block, block_data); + } + + BorrowSet { + location_map: visitor.location_map, + activation_map: visitor.activation_map, + local_map: visitor.local_map, + locals_state_at_exit: visitor.locals_state_at_exit, + } + } + + crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] { + self.activation_map.get(&location).map_or(&[], |activations| &activations[..]) + } + + crate fn len(&self) -> usize { + self.location_map.len() + } + + crate fn indices(&self) -> impl Iterator { + BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len()) + } + + crate fn iter_enumerated(&self) -> impl Iterator)> { + self.indices().zip(self.location_map.values()) + } + + crate fn get_index_of(&self, location: &Location) -> Option { + self.location_map.get_index_of(location).map(BorrowIndex::from) + } + + crate fn contains(&self, location: &Location) -> bool { + self.location_map.contains_key(location) + } +} + +struct GatherBorrows<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + location_map: FxIndexMap>, + activation_map: FxHashMap>, + local_map: FxHashMap>, + + /// When we encounter a 2-phase borrow statement, it will always + /// be assigning into a temporary TEMP: + /// + /// TEMP = &foo + /// + /// We add TEMP into this map with `b`, where `b` is the index of + /// the borrow. When we find a later use of this activation, we + /// remove from the map (and add to the "tombstone" set below). + pending_activations: FxHashMap, + + locals_state_at_exit: LocalsStateAtExit, +} + +impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { + fn visit_assign( + &mut self, + assigned_place: &mir::Place<'tcx>, + rvalue: &mir::Rvalue<'tcx>, + location: mir::Location, + ) { + if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue { + if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) { + debug!("ignoring_borrow of {:?}", borrowed_place); + return; + } + + let region = region.to_region_vid(); + + let borrow = BorrowData { + kind, + region, + reserve_location: location, + activation_location: TwoPhaseActivation::NotTwoPhase, + borrowed_place: *borrowed_place, + assigned_place: *assigned_place, + }; + let (idx, _) = self.location_map.insert_full(location, borrow); + let idx = BorrowIndex::from(idx); + + self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx); + + self.local_map.entry(borrowed_place.local).or_default().insert(idx); + } + + self.super_assign(assigned_place, rvalue, location) + } + + fn visit_local(&mut self, temp: &Local, context: PlaceContext, location: Location) { + if !context.is_use() { + return; + } + + // We found a use of some temporary TMP + // check whether we (earlier) saw a 2-phase borrow like + // + // TMP = &mut place + if let Some(&borrow_index) = self.pending_activations.get(temp) { + let borrow_data = &mut self.location_map[borrow_index.as_usize()]; + + // Watch out: the use of TMP in the borrow itself + // doesn't count as an activation. =) + if borrow_data.reserve_location == location + && context == PlaceContext::MutatingUse(MutatingUseContext::Store) + { + return; + } + + if let TwoPhaseActivation::ActivatedAt(other_location) = borrow_data.activation_location + { + span_bug!( + self.body.source_info(location).span, + "found two uses for 2-phase borrow temporary {:?}: \ + {:?} and {:?}", + temp, + location, + other_location, + ); + } + + // Otherwise, this is the unique later use that we expect. + // Double check: This borrow is indeed a two-phase borrow (that is, + // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and + // we've not found any other activations (checked above). + assert_eq!( + borrow_data.activation_location, + TwoPhaseActivation::NotActivated, + "never found an activation for this borrow!", + ); + self.activation_map.entry(location).or_default().push(borrow_index); + + borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location); + } + } + + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) { + if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue { + // double-check that we already registered a BorrowData for this + + let borrow_data = &self.location_map[&location]; + assert_eq!(borrow_data.reserve_location, location); + assert_eq!(borrow_data.kind, kind); + assert_eq!(borrow_data.region, region.to_region_vid()); + assert_eq!(borrow_data.borrowed_place, *place); + } + + self.super_rvalue(rvalue, location) + } +} + +impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { + /// If this is a two-phase borrow, then we will record it + /// as "pending" until we find the activating use. + fn insert_as_pending_if_two_phase( + &mut self, + start_location: Location, + assigned_place: &mir::Place<'tcx>, + kind: mir::BorrowKind, + borrow_index: BorrowIndex, + ) { + debug!( + "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})", + start_location, assigned_place, borrow_index, + ); + + if !allow_two_phase_borrow(kind) { + debug!(" -> {:?}", start_location); + return; + } + + // When we encounter a 2-phase borrow statement, it will always + // be assigning into a temporary TEMP: + // + // TEMP = &foo + // + // so extract `temp`. + let temp = if let Some(temp) = assigned_place.as_local() { + temp + } else { + span_bug!( + self.body.source_info(start_location).span, + "expected 2-phase borrow to assign to a local, not `{:?}`", + assigned_place, + ); + }; + + // Consider the borrow not activated to start. When we find an activation, we'll update + // this field. + { + let borrow_data = &mut self.location_map[borrow_index.as_usize()]; + borrow_data.activation_location = TwoPhaseActivation::NotActivated; + } + + // Insert `temp` into the list of pending activations. From + // now on, we'll be on the lookout for a use of it. Note that + // we are guaranteed that this use will come after the + // assignment. + let old_value = self.pending_activations.insert(temp, borrow_index); + if let Some(old_index) = old_value { + span_bug!( + self.body.source_info(start_location).span, + "found already pending activation for temp: {:?} \ + at borrow_index: {:?} with associated data {:?}", + temp, + old_index, + self.location_map[old_index.as_usize()] + ); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraint_generation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraint_generation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraint_generation.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraint_generation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,252 @@ +use rustc_infer::infer::InferCtxt; +use rustc_middle::mir::visit::TyContext; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{ + BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, + SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, +}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, RegionVid, Ty}; + +use crate::{ + borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid, + places_conflict, region_infer::values::LivenessValues, +}; + +pub(super) fn generate_constraints<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + liveness_constraints: &mut LivenessValues, + all_facts: &mut Option, + location_table: &LocationTable, + body: &Body<'tcx>, + borrow_set: &BorrowSet<'tcx>, +) { + let mut cg = ConstraintGeneration { + borrow_set, + infcx, + liveness_constraints, + location_table, + all_facts, + body, + }; + + for (bb, data) in body.basic_blocks().iter_enumerated() { + cg.visit_basic_block_data(bb, data); + } +} + +/// 'cg = the duration of the constraint generation process itself. +struct ConstraintGeneration<'cg, 'cx, 'tcx> { + infcx: &'cg InferCtxt<'cx, 'tcx>, + all_facts: &'cg mut Option, + location_table: &'cg LocationTable, + liveness_constraints: &'cg mut LivenessValues, + borrow_set: &'cg BorrowSet<'tcx>, + body: &'cg Body<'tcx>, +} + +impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { + fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { + self.super_basic_block_data(bb, data); + } + + /// We sometimes have `substs` within an rvalue, or within a + /// call. Make them live at the location where they appear. + fn visit_substs(&mut self, substs: &SubstsRef<'tcx>, location: Location) { + self.add_regular_live_constraint(*substs, location); + self.super_substs(substs); + } + + /// We sometimes have `region` within an rvalue, or within a + /// call. Make them live at the location where they appear. + fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) { + self.add_regular_live_constraint(*region, location); + self.super_region(region); + } + + /// We sometimes have `ty` within an rvalue, or within a + /// call. Make them live at the location where they appear. + fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) { + match ty_context { + TyContext::ReturnTy(SourceInfo { span, .. }) + | TyContext::YieldTy(SourceInfo { span, .. }) + | TyContext::UserTy(span) + | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => { + span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context); + } + TyContext::Location(location) => { + self.add_regular_live_constraint(ty, location); + } + } + + self.super_ty(ty); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + if let Some(all_facts) = self.all_facts { + let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); + all_facts.cfg_edge.push(( + self.location_table.start_index(location), + self.location_table.mid_index(location), + )); + + all_facts.cfg_edge.push(( + self.location_table.mid_index(location), + self.location_table.start_index(location.successor_within_block()), + )); + + // If there are borrows on this now dead local, we need to record them as `killed`. + if let StatementKind::StorageDead(local) = statement.kind { + record_killed_borrows_for_local( + all_facts, + self.borrow_set, + self.location_table, + local, + location, + ); + } + } + + self.super_statement(statement, location); + } + + fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { + // When we see `X = ...`, then kill borrows of + // `(*X).foo` and so forth. + self.record_killed_borrows_for_place(*place, location); + + self.super_assign(place, rvalue, location); + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + if let Some(all_facts) = self.all_facts { + let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); + all_facts.cfg_edge.push(( + self.location_table.start_index(location), + self.location_table.mid_index(location), + )); + + let successor_blocks = terminator.successors(); + all_facts.cfg_edge.reserve(successor_blocks.size_hint().0); + for successor_block in successor_blocks { + all_facts.cfg_edge.push(( + self.location_table.mid_index(location), + self.location_table.start_index(successor_block.start_location()), + )); + } + } + + // A `Call` terminator's return value can be a local which has borrows, + // so we need to record those as `killed` as well. + if let TerminatorKind::Call { destination, .. } = terminator.kind { + if let Some((place, _)) = destination { + self.record_killed_borrows_for_place(place, location); + } + } + + self.super_terminator(terminator, location); + } + + fn visit_ascribe_user_ty( + &mut self, + _place: &Place<'tcx>, + _variance: &ty::Variance, + _user_ty: &UserTypeProjection, + _location: Location, + ) { + } +} + +impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { + /// Some variable with type `live_ty` is "regular live" at + /// `location` -- i.e., it may be used later. This means that all + /// regions appearing in the type `live_ty` must be live at + /// `location`. + fn add_regular_live_constraint(&mut self, live_ty: T, location: Location) + where + T: TypeFoldable<'tcx>, + { + debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location); + + self.infcx.tcx.for_each_free_region(&live_ty, |live_region| { + let vid = live_region.to_region_vid(); + self.liveness_constraints.add_element(vid, location); + }); + } + + /// When recording facts for Polonius, records the borrows on the specified place + /// as `killed`. For example, when assigning to a local, or on a call's return destination. + fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) { + if let Some(all_facts) = self.all_facts { + let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); + + // Depending on the `Place` we're killing: + // - if it's a local, or a single deref of a local, + // we kill all the borrows on the local. + // - if it's a deeper projection, we have to filter which + // of the borrows are killed: the ones whose `borrowed_place` + // conflicts with the `place`. + match place.as_ref() { + PlaceRef { local, projection: &[] } + | PlaceRef { local, projection: &[ProjectionElem::Deref] } => { + debug!( + "Recording `killed` facts for borrows of local={:?} at location={:?}", + local, location + ); + + record_killed_borrows_for_local( + all_facts, + self.borrow_set, + self.location_table, + local, + location, + ); + } + + PlaceRef { local, projection: &[.., _] } => { + // Kill conflicting borrows of the innermost local. + debug!( + "Recording `killed` facts for borrows of \ + innermost projected local={:?} at location={:?}", + local, location + ); + + if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { + for &borrow_index in borrow_indices { + let places_conflict = places_conflict::places_conflict( + self.infcx.tcx, + self.body, + self.borrow_set[borrow_index].borrowed_place, + place, + places_conflict::PlaceConflictBias::NoOverlap, + ); + + if places_conflict { + let location_index = self.location_table.mid_index(location); + all_facts.loan_killed_at.push((borrow_index, location_index)); + } + } + } + } + } + } + } +} + +/// When recording facts for Polonius, records the borrows on the specified local as `killed`. +fn record_killed_borrows_for_local( + all_facts: &mut AllFacts, + borrow_set: &BorrowSet<'_>, + location_table: &LocationTable, + local: Local, + location: Location, +) { + if let Some(borrow_indices) = borrow_set.local_map.get(&local) { + all_facts.loan_killed_at.reserve(borrow_indices.len()); + for &borrow_index in borrow_indices { + let location_index = location_table.mid_index(location); + all_facts.loan_killed_at.push((borrow_index, location_index)); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraints/graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraints/graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraints/graph.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraints/graph.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,233 @@ +use rustc_data_structures::graph; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; +use rustc_span::DUMMY_SP; + +use crate::{ + constraints::OutlivesConstraintIndex, + constraints::{OutlivesConstraint, OutlivesConstraintSet}, + type_check::Locations, +}; + +/// The construct graph organizes the constraints by their end-points. +/// It can be used to view a `R1: R2` constraint as either an edge `R1 +/// -> R2` or `R2 -> R1` depending on the direction type `D`. +crate struct ConstraintGraph { + _direction: D, + first_constraints: IndexVec>, + next_constraints: IndexVec>, +} + +crate type NormalConstraintGraph = ConstraintGraph; + +crate type ReverseConstraintGraph = ConstraintGraph; + +/// Marker trait that controls whether a `R1: R2` constraint +/// represents an edge `R1 -> R2` or `R2 -> R1`. +crate trait ConstraintGraphDirecton: Copy + 'static { + fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid; + fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid; + fn is_normal() -> bool; +} + +/// In normal mode, a `R1: R2` constraint results in an edge `R1 -> +/// R2`. This is what we use when constructing the SCCs for +/// inference. This is because we compute the value of R1 by union'ing +/// all the things that it relies on. +#[derive(Copy, Clone, Debug)] +crate struct Normal; + +impl ConstraintGraphDirecton for Normal { + fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { + c.sup + } + + fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { + c.sub + } + + fn is_normal() -> bool { + true + } +} + +/// In reverse mode, a `R1: R2` constraint results in an edge `R2 -> +/// R1`. We use this for optimizing liveness computation, because then +/// we wish to iterate from a region (e.g., R2) to all the regions +/// that will outlive it (e.g., R1). +#[derive(Copy, Clone, Debug)] +crate struct Reverse; + +impl ConstraintGraphDirecton for Reverse { + fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { + c.sub + } + + fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { + c.sup + } + + fn is_normal() -> bool { + false + } +} + +impl ConstraintGraph { + /// Creates a "dependency graph" where each region constraint `R1: + /// R2` is treated as an edge `R1 -> R2`. We use this graph to + /// construct SCCs for region inference but also for error + /// reporting. + crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self { + let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars); + let mut next_constraints = IndexVec::from_elem(None, &set.outlives); + + for (idx, constraint) in set.outlives.iter_enumerated().rev() { + let head = &mut first_constraints[D::start_region(constraint)]; + let next = &mut next_constraints[idx]; + debug_assert!(next.is_none()); + *next = *head; + *head = Some(idx); + } + + Self { _direction: direction, first_constraints, next_constraints } + } + + /// Given the constraint set from which this graph was built + /// creates a region graph so that you can iterate over *regions* + /// and not constraints. + crate fn region_graph<'rg, 'tcx>( + &'rg self, + set: &'rg OutlivesConstraintSet<'tcx>, + static_region: RegionVid, + ) -> RegionGraph<'rg, 'tcx, D> { + RegionGraph::new(set, self, static_region) + } + + /// Given a region `R`, iterate over all constraints `R: R1`. + crate fn outgoing_edges<'a, 'tcx>( + &'a self, + region_sup: RegionVid, + constraints: &'a OutlivesConstraintSet<'tcx>, + static_region: RegionVid, + ) -> Edges<'a, 'tcx, D> { + //if this is the `'static` region and the graph's direction is normal, + //then setup the Edges iterator to return all regions #53178 + if region_sup == static_region && D::is_normal() { + Edges { + graph: self, + constraints, + pointer: None, + next_static_idx: Some(0), + static_region, + } + } else { + //otherwise, just setup the iterator as normal + let first = self.first_constraints[region_sup]; + Edges { graph: self, constraints, pointer: first, next_static_idx: None, static_region } + } + } +} + +crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> { + graph: &'s ConstraintGraph, + constraints: &'s OutlivesConstraintSet<'tcx>, + pointer: Option, + next_static_idx: Option, + static_region: RegionVid, +} + +impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> { + type Item = OutlivesConstraint<'tcx>; + + fn next(&mut self) -> Option { + if let Some(p) = self.pointer { + self.pointer = self.graph.next_constraints[p]; + + Some(self.constraints[p].clone()) + } else if let Some(next_static_idx) = self.next_static_idx { + self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) { + None + } else { + Some(next_static_idx + 1) + }; + + Some(OutlivesConstraint { + sup: self.static_region, + sub: next_static_idx.into(), + locations: Locations::All(DUMMY_SP), + category: ConstraintCategory::Internal, + variance_info: VarianceDiagInfo::default(), + }) + } else { + None + } + } +} + +/// This struct brings together a constraint set and a (normal, not +/// reverse) constraint graph. It implements the graph traits and is +/// usd for doing the SCC computation. +crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> { + set: &'s OutlivesConstraintSet<'tcx>, + constraint_graph: &'s ConstraintGraph, + static_region: RegionVid, +} + +impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> { + /// Creates a "dependency graph" where each region constraint `R1: + /// R2` is treated as an edge `R1 -> R2`. We use this graph to + /// construct SCCs for region inference but also for error + /// reporting. + crate fn new( + set: &'s OutlivesConstraintSet<'tcx>, + constraint_graph: &'s ConstraintGraph, + static_region: RegionVid, + ) -> Self { + Self { set, constraint_graph, static_region } + } + + /// Given a region `R`, iterate over all regions `R1` such that + /// there exists a constraint `R: R1`. + crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> { + Successors { + edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), + } + } +} + +crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> { + edges: Edges<'s, 'tcx, D>, +} + +impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> { + type Item = RegionVid; + + fn next(&mut self) -> Option { + self.edges.next().map(|c| D::end_region(&c)) + } +} + +impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { + type Node = RegionVid; +} + +impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> { + fn num_nodes(&self) -> usize { + self.constraint_graph.first_constraints.len() + } +} + +impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { + fn successors(&self, node: Self::Node) -> >::Iter { + self.outgoing_regions(node) + } +} + +impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> + for RegionGraph<'s, 'tcx, D> +{ + type Item = RegionVid; + // FIXME - why can't this be `'graph, 'tcx` + type Iter = Successors<'graph, 'graph, D>; +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraints/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraints/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraints/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/constraints/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,117 @@ +use rustc_data_structures::graph::scc::Sccs; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; +use std::fmt; +use std::ops::Index; + +use crate::type_check::Locations; + +crate mod graph; + +/// A set of NLL region constraints. These include "outlives" +/// constraints of the form `R1: R2`. Each constraint is identified by +/// a unique `OutlivesConstraintIndex` and you can index into the set +/// (`constraint_set[i]`) to access the constraint details. +#[derive(Clone, Default)] +crate struct OutlivesConstraintSet<'tcx> { + outlives: IndexVec>, +} + +impl<'tcx> OutlivesConstraintSet<'tcx> { + crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) { + debug!( + "OutlivesConstraintSet::push({:?}: {:?} @ {:?}", + constraint.sup, constraint.sub, constraint.locations + ); + if constraint.sup == constraint.sub { + // 'a: 'a is pretty uninteresting + return; + } + self.outlives.push(constraint); + } + + /// Constructs a "normal" graph from the constraint set; the graph makes it + /// easy to find the constraints affecting a particular region. + /// + /// N.B., this graph contains a "frozen" view of the current + /// constraints. Any new constraints added to the `OutlivesConstraintSet` + /// after the graph is built will not be present in the graph. + crate fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph { + graph::ConstraintGraph::new(graph::Normal, self, num_region_vars) + } + + /// Like `graph`, but constraints a reverse graph where `R1: R2` + /// represents an edge `R2 -> R1`. + crate fn reverse_graph(&self, num_region_vars: usize) -> graph::ReverseConstraintGraph { + graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars) + } + + /// Computes cycles (SCCs) in the graph of regions. In particular, + /// find all regions R1, R2 such that R1: R2 and R2: R1 and group + /// them into an SCC, and find the relationships between SCCs. + crate fn compute_sccs( + &self, + constraint_graph: &graph::NormalConstraintGraph, + static_region: RegionVid, + ) -> Sccs { + let region_graph = &constraint_graph.region_graph(self, static_region); + Sccs::new(region_graph) + } + + crate fn outlives(&self) -> &IndexVec> { + &self.outlives + } +} + +impl<'tcx> Index for OutlivesConstraintSet<'tcx> { + type Output = OutlivesConstraint<'tcx>; + + fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output { + &self.outlives[i] + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct OutlivesConstraint<'tcx> { + // NB. The ordering here is not significant for correctness, but + // it is for convenience. Before we dump the constraints in the + // debugging logs, we sort them, and we'd like the "super region" + // to be first, etc. (In particular, span should remain last.) + /// The region SUP must outlive SUB... + pub sup: RegionVid, + + /// Region that must be outlived. + pub sub: RegionVid, + + /// Where did this constraint arise? + pub locations: Locations, + + /// What caused this constraint? + pub category: ConstraintCategory, + + /// Variance diagnostic information + pub variance_info: VarianceDiagInfo<'tcx>, +} + +impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + formatter, + "({:?}: {:?}) due to {:?} ({:?})", + self.sup, self.sub, self.locations, self.variance_info + ) + } +} + +rustc_index::newtype_index! { + pub struct OutlivesConstraintIndex { + DEBUG_FORMAT = "OutlivesConstraintIndex({})" + } +} + +rustc_index::newtype_index! { + pub struct ConstraintSccIndex { + DEBUG_FORMAT = "ConstraintSccIndex({})" + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/consumers.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/consumers.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/consumers.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/consumers.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +//! This file provides API for compiler consumers. + +use rustc_hir::def_id::LocalDefId; +use rustc_index::vec::IndexVec; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::mir::Body; +use rustc_middle::ty::{self, TyCtxt}; + +pub use super::{ + facts::{AllFacts as PoloniusInput, RustcFacts}, + location::{LocationTable, RichLocation}, + nll::PoloniusOutput, + BodyWithBorrowckFacts, +}; + +/// This function computes Polonius facts for the given body. It makes a copy of +/// the body because it needs to regenerate the region identifiers. This function +/// should never be invoked during a typical compilation session due to performance +/// issues with Polonius. +/// +/// Note: +/// * This function will panic if the required body was already stolen. This +/// can, for example, happen when requesting a body of a `const` function +/// because they are evaluated during typechecking. The panic can be avoided +/// by overriding the `mir_borrowck` query. You can find a complete example +/// that shows how to do this at `src/test/run-make/obtain-borrowck/`. +/// +/// * Polonius is highly unstable, so expect regular changes in its signature or other details. +pub fn get_body_with_borrowck_facts<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> BodyWithBorrowckFacts<'tcx> { + let (input_body, promoted) = tcx.mir_promoted(def); + tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| { + let input_body: &Body<'_> = &input_body.borrow(); + let promoted: &IndexVec<_, _> = &promoted.borrow(); + *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() + }) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/dataflow.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/dataflow.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/dataflow.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/dataflow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,448 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::{self, BasicBlock, Body, Location, Place}; +use rustc_middle::ty::RegionVid; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; +use rustc_mir_dataflow::ResultsVisitable; +use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill}; +use rustc_mir_dataflow::{Analysis, Direction, Results}; +use std::fmt; +use std::iter; + +use crate::{ + places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, +}; + +/// A tuple with named fields that can hold either the results or the transient state of the +/// dataflow analyses used by the borrow checker. +#[derive(Debug)] +pub struct BorrowckAnalyses { + pub borrows: B, + pub uninits: U, + pub ever_inits: E, +} + +/// The results of the dataflow analyses used by the borrow checker. +pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses< + Results<'tcx, Borrows<'mir, 'tcx>>, + Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, + Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>, +>; + +/// The transient state of the dataflow analyses used by the borrow checker. +pub type BorrowckFlowState<'mir, 'tcx> = + as ResultsVisitable<'tcx>>::FlowState; + +macro_rules! impl_visitable { + ( $( + $T:ident { $( $field:ident : $A:ident ),* $(,)? } + )* ) => { $( + impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*> + where + $( $A: Analysis<'tcx, Direction = D>, )* + { + type Direction = D; + type FlowState = $T<$( $A::Domain ),*>; + + fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { + $T { + $( $field: self.$field.analysis.bottom_value(body) ),* + } + } + + fn reset_to_block_entry( + &self, + state: &mut Self::FlowState, + block: BasicBlock, + ) { + $( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )* + } + + fn reconstruct_before_statement_effect( + &self, + state: &mut Self::FlowState, + stmt: &mir::Statement<'tcx>, + loc: Location, + ) { + $( self.$field.analysis + .apply_before_statement_effect(&mut state.$field, stmt, loc); )* + } + + fn reconstruct_statement_effect( + &self, + state: &mut Self::FlowState, + stmt: &mir::Statement<'tcx>, + loc: Location, + ) { + $( self.$field.analysis + .apply_statement_effect(&mut state.$field, stmt, loc); )* + } + + fn reconstruct_before_terminator_effect( + &self, + state: &mut Self::FlowState, + term: &mir::Terminator<'tcx>, + loc: Location, + ) { + $( self.$field.analysis + .apply_before_terminator_effect(&mut state.$field, term, loc); )* + } + + fn reconstruct_terminator_effect( + &self, + state: &mut Self::FlowState, + term: &mir::Terminator<'tcx>, + loc: Location, + ) { + $( self.$field.analysis + .apply_terminator_effect(&mut state.$field, term, loc); )* + } + } + )* } +} + +impl_visitable! { + BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E } +} + +rustc_index::newtype_index! { + pub struct BorrowIndex { + DEBUG_FORMAT = "bw{}" + } +} + +/// `Borrows` stores the data used in the analyses that track the flow +/// of borrows. +/// +/// It uniquely identifies every borrow (`Rvalue::Ref`) by a +/// `BorrowIndex`, and maps each such index to a `BorrowData` +/// describing the borrow. These indexes are used for representing the +/// borrows in compact bitvectors. +pub struct Borrows<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + + borrow_set: &'a BorrowSet<'tcx>, + borrows_out_of_scope_at_location: FxHashMap>, +} + +struct StackEntry { + bb: mir::BasicBlock, + lo: usize, + hi: usize, +} + +struct OutOfScopePrecomputer<'a, 'tcx> { + visited: BitSet, + visit_stack: Vec, + body: &'a Body<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, + borrows_out_of_scope_at_location: FxHashMap>, +} + +impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> { + fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self { + OutOfScopePrecomputer { + visited: BitSet::new_empty(body.basic_blocks().len()), + visit_stack: vec![], + body, + regioncx, + borrows_out_of_scope_at_location: FxHashMap::default(), + } + } +} + +impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { + fn precompute_borrows_out_of_scope( + &mut self, + borrow_index: BorrowIndex, + borrow_region: RegionVid, + location: Location, + ) { + // We visit one BB at a time. The complication is that we may start in the + // middle of the first BB visited (the one containing `location`), in which + // case we may have to later on process the first part of that BB if there + // is a path back to its start. + + // For visited BBs, we record the index of the first statement processed. + // (In fully processed BBs this index is 0.) Note also that we add BBs to + // `visited` once they are added to `stack`, before they are actually + // processed, because this avoids the need to look them up again on + // completion. + self.visited.insert(location.block); + + let mut first_lo = location.statement_index; + let first_hi = self.body[location.block].statements.len(); + + self.visit_stack.push(StackEntry { bb: location.block, lo: first_lo, hi: first_hi }); + + while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() { + // If we process the first part of the first basic block (i.e. we encounter that block + // for the second time), we no longer have to visit its successors again. + let mut finished_early = bb == location.block && hi != first_hi; + for i in lo..=hi { + let location = Location { block: bb, statement_index: i }; + // If region does not contain a point at the location, then add to list and skip + // successor locations. + if !self.regioncx.region_contains(borrow_region, location) { + debug!("borrow {:?} gets killed at {:?}", borrow_index, location); + self.borrows_out_of_scope_at_location + .entry(location) + .or_default() + .push(borrow_index); + finished_early = true; + break; + } + } + + if !finished_early { + // Add successor BBs to the work list, if necessary. + let bb_data = &self.body[bb]; + debug_assert!(hi == bb_data.statements.len()); + for &succ_bb in bb_data.terminator().successors() { + if !self.visited.insert(succ_bb) { + if succ_bb == location.block && first_lo > 0 { + // `succ_bb` has been seen before. If it wasn't + // fully processed, add its first part to `stack` + // for processing. + self.visit_stack.push(StackEntry { + bb: succ_bb, + lo: 0, + hi: first_lo - 1, + }); + + // And update this entry with 0, to represent the + // whole BB being processed. + first_lo = 0; + } + } else { + // succ_bb hasn't been seen before. Add it to + // `stack` for processing. + self.visit_stack.push(StackEntry { + bb: succ_bb, + lo: 0, + hi: self.body[succ_bb].statements.len(), + }); + } + } + } + } + + self.visited.clear(); + } +} + +impl<'a, 'tcx> Borrows<'a, 'tcx> { + crate fn new( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + nonlexical_regioncx: &'a RegionInferenceContext<'tcx>, + borrow_set: &'a BorrowSet<'tcx>, + ) -> Self { + let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx); + for (borrow_index, borrow_data) in borrow_set.iter_enumerated() { + let borrow_region = borrow_data.region.to_region_vid(); + let location = borrow_data.reserve_location; + + prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location); + } + + Borrows { + tcx, + body, + borrow_set, + borrows_out_of_scope_at_location: prec.borrows_out_of_scope_at_location, + } + } + + pub fn location(&self, idx: BorrowIndex) -> &Location { + &self.borrow_set[idx].reserve_location + } + + /// Add all borrows to the kill set, if those borrows are out of scope at `location`. + /// That means they went out of a nonlexical scope + fn kill_loans_out_of_scope_at_location( + &self, + trans: &mut impl GenKill, + location: Location, + ) { + // NOTE: The state associated with a given `location` + // reflects the dataflow on entry to the statement. + // Iterate over each of the borrows that we've precomputed + // to have went out of scope at this location and kill them. + // + // We are careful always to call this function *before* we + // set up the gen-bits for the statement or + // terminator. That way, if the effect of the statement or + // terminator *does* introduce a new loan of the same + // region, then setting that gen-bit will override any + // potential kill introduced here. + if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { + trans.kill_all(indices.iter().copied()); + } + } + + /// Kill any borrows that conflict with `place`. + fn kill_borrows_on_place(&self, trans: &mut impl GenKill, place: Place<'tcx>) { + debug!("kill_borrows_on_place: place={:?}", place); + + let other_borrows_of_local = self + .borrow_set + .local_map + .get(&place.local) + .into_iter() + .flat_map(|bs| bs.iter()) + .copied(); + + // If the borrowed place is a local with no projections, all other borrows of this + // local must conflict. This is purely an optimization so we don't have to call + // `places_conflict` for every borrow. + if place.projection.is_empty() { + if !self.body.local_decls[place.local].is_ref_to_static() { + trans.kill_all(other_borrows_of_local); + } + return; + } + + // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given + // pair of array indices are unequal, so that when `places_conflict` returns true, we + // will be assured that two places being compared definitely denotes the same sets of + // locations. + let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { + places_conflict( + self.tcx, + self.body, + self.borrow_set[i].borrowed_place, + place, + PlaceConflictBias::NoOverlap, + ) + }); + + trans.kill_all(definitely_conflicting_borrows); + } +} + +impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { + type Domain = BitSet; + + const NAME: &'static str = "borrows"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = nothing is reserved or activated yet; + BitSet::new_empty(self.borrow_set.len() * 2) + } + + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { + // no borrows of code region_scopes have been taken prior to + // function execution, so this method has no effect. + } +} + +impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { + type Idx = BorrowIndex; + + fn before_statement_effect( + &self, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.kill_loans_out_of_scope_at_location(trans, location); + } + + fn statement_effect( + &self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + location: Location, + ) { + match stmt.kind { + mir::StatementKind::Assign(box (lhs, ref rhs)) => { + if let mir::Rvalue::Ref(_, _, place) = *rhs { + if place.ignore_borrow( + self.tcx, + self.body, + &self.borrow_set.locals_state_at_exit, + ) { + return; + } + let index = self.borrow_set.get_index_of(&location).unwrap_or_else(|| { + panic!("could not find BorrowIndex for location {:?}", location); + }); + + trans.gen(index); + } + + // Make sure there are no remaining borrows for variables + // that are assigned over. + self.kill_borrows_on_place(trans, lhs); + } + + mir::StatementKind::StorageDead(local) => { + // Make sure there are no remaining borrows for locals that + // are gone out of scope. + self.kill_borrows_on_place(trans, Place::from(local)); + } + + mir::StatementKind::LlvmInlineAsm(ref asm) => { + for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) { + if !kind.is_indirect && !kind.is_rw { + self.kill_borrows_on_place(trans, *output); + } + } + } + + mir::StatementKind::FakeRead(..) + | mir::StatementKind::SetDiscriminant { .. } + | mir::StatementKind::StorageLive(..) + | mir::StatementKind::Retag { .. } + | mir::StatementKind::AscribeUserType(..) + | mir::StatementKind::Coverage(..) + | mir::StatementKind::CopyNonOverlapping(..) + | mir::StatementKind::Nop => {} + } + } + + fn before_terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + self.kill_loans_out_of_scope_at_location(trans, location); + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + teminator: &mir::Terminator<'tcx>, + _location: Location, + ) { + if let mir::TerminatorKind::InlineAsm { operands, .. } = &teminator.kind { + for op in operands { + if let mir::InlineAsmOperand::Out { place: Some(place), .. } + | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op + { + self.kill_borrows_on_place(trans, place); + } + } + } + } + + fn call_return_effect( + &self, + _trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + _dest_place: mir::Place<'tcx>, + ) { + } +} + +impl DebugWithContext> for BorrowIndex { + fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", ctxt.location(*self)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/def_use.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/def_use.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/def_use.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/def_use.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,78 @@ +use rustc_middle::mir::visit::{ + MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, +}; + +#[derive(Eq, PartialEq, Clone)] +pub enum DefUse { + Def, + Use, + Drop, +} + +pub fn categorize(context: PlaceContext) -> Option { + match context { + /////////////////////////////////////////////////////////////////////////// + // DEFS + + PlaceContext::MutatingUse(MutatingUseContext::Store) | + + // This is potentially both a def and a use... + PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | + + // We let Call define the result in both the success and + // unwind cases. This is not really correct, however it + // does not seem to be observable due to the way that we + // generate MIR. To do things properly, we would apply + // the def in call only to the input from the success + // path and not the unwind path. -nmatsakis + PlaceContext::MutatingUse(MutatingUseContext::Call) | + PlaceContext::MutatingUse(MutatingUseContext::Yield) | + + // Storage live and storage dead aren't proper defines, but we can ignore + // values that come before them. + PlaceContext::NonUse(NonUseContext::StorageLive) | + PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def), + + /////////////////////////////////////////////////////////////////////////// + // REGULAR USES + // + // These are uses that occur *outside* of a drop. For the + // purposes of NLL, these are special in that **all** the + // lifetimes appearing in the variable must be live for each regular use. + + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) | + PlaceContext::MutatingUse(MutatingUseContext::Projection) | + + // Borrows only consider their local used at the point of the borrow. + // This won't affect the results since we use this analysis for generators + // and we only care about the result at suspension points. Borrows cannot + // cross suspension points so this behavior is unproblematic. + PlaceContext::MutatingUse(MutatingUseContext::Borrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | + + PlaceContext::MutatingUse(MutatingUseContext::AddressOf) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) | + PlaceContext::NonUse(NonUseContext::AscribeUserTy) | + PlaceContext::MutatingUse(MutatingUseContext::Retag) => + Some(DefUse::Use), + + /////////////////////////////////////////////////////////////////////////// + // DROP USES + // + // These are uses that occur in a DROP (a MIR drop, not a + // call to `std::mem::drop()`). For the purposes of NLL, + // uses in drop are special because `#[may_dangle]` + // attributes can affect whether lifetimes must be live. + + PlaceContext::MutatingUse(MutatingUseContext::Drop) => + Some(DefUse::Drop), + + // Debug info is neither def nor use. + PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,402 @@ +use rustc_errors::DiagnosticBuilder; +use rustc_infer::infer::canonical::Canonical; +use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; +use rustc_infer::infer::region_constraints::Constraint; +use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _}; +use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_span::Span; +use rustc_trait_selection::traits::query::type_op; +use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _}; +use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; + +use std::fmt; +use std::rc::Rc; + +use crate::region_infer::values::RegionElement; +use crate::MirBorrowckCtxt; + +#[derive(Clone)] +crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>); + +/// What operation a universe was created for. +#[derive(Clone)] +enum UniverseInfoInner<'tcx> { + /// Relating two types which have binders. + RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> }, + /// Created from performing a `TypeOp`. + TypeOp(Rc + 'tcx>), + /// Any other reason. + Other, +} + +impl UniverseInfo<'tcx> { + crate fn other() -> UniverseInfo<'tcx> { + UniverseInfo(UniverseInfoInner::Other) + } + + crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> { + UniverseInfo(UniverseInfoInner::RelateTys { expected, found }) + } + + crate fn report_error( + &self, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, + placeholder: ty::PlaceholderRegion, + error_element: RegionElement, + cause: ObligationCause<'tcx>, + ) { + match self.0 { + UniverseInfoInner::RelateTys { expected, found } => { + let err = mbcx.infcx.report_mismatched_types( + &cause, + expected, + found, + TypeError::RegionsPlaceholderMismatch, + ); + err.buffer(&mut mbcx.errors_buffer); + } + UniverseInfoInner::TypeOp(ref type_op_info) => { + type_op_info.report_error(mbcx, placeholder, error_element, cause); + } + UniverseInfoInner::Other => { + // FIXME: This error message isn't great, but it doesn't show + // up in the existing UI tests. Consider investigating this + // some more. + mbcx.infcx + .tcx + .sess + .struct_span_err(cause.span, "higher-ranked subtype error") + .buffer(&mut mbcx.errors_buffer); + } + } + } +} + +crate trait ToUniverseInfo<'tcx> { + fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>; +} + +impl<'tcx> ToUniverseInfo<'tcx> + for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>> +{ + fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery { + canonical_query: self, + base_universe, + }))) + } +} + +impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx> + for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>> +{ + fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery { + canonical_query: self, + base_universe, + }))) + } +} + +impl<'tcx> ToUniverseInfo<'tcx> + for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>> +{ + fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery { + canonical_query: self, + base_universe, + }))) + } +} + +impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp> { + fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + // We can't rerun custom type ops. + UniverseInfo::other() + } +} + +#[allow(unused_lifetimes)] +trait TypeOpInfo<'tcx> { + /// Returns an error to be reported if rerunning the type op fails to + /// recover the error's cause. + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; + + fn base_universe(&self) -> ty::UniverseIndex; + + fn nice_error( + &self, + tcx: TyCtxt<'tcx>, + cause: ObligationCause<'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option>, + ) -> Option>; + + fn report_error( + &self, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, + placeholder: ty::PlaceholderRegion, + error_element: RegionElement, + cause: ObligationCause<'tcx>, + ) { + let tcx = mbcx.infcx.tcx; + let base_universe = self.base_universe(); + + let adjusted_universe = if let Some(adjusted) = + placeholder.universe.as_u32().checked_sub(base_universe.as_u32()) + { + adjusted + } else { + self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer); + return; + }; + + let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder { + name: placeholder.name, + universe: adjusted_universe.into(), + })); + + let error_region = + if let RegionElement::PlaceholderRegion(error_placeholder) = error_element { + let adjusted_universe = + error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); + adjusted_universe.map(|adjusted| { + tcx.mk_region(ty::RePlaceholder(ty::Placeholder { + name: error_placeholder.name, + universe: adjusted.into(), + })) + }) + } else { + None + }; + + debug!(?placeholder_region); + + let span = cause.span; + let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region); + + if let Some(nice_error) = nice_error { + nice_error.buffer(&mut mbcx.errors_buffer); + } else { + self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer); + } + } +} + +struct PredicateQuery<'tcx> { + canonical_query: + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>, + base_universe: ty::UniverseIndex, +} + +impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> { + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); + err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate)); + err + } + + fn base_universe(&self) -> ty::UniverseIndex { + self.base_universe + } + + fn nice_error( + &self, + tcx: TyCtxt<'tcx>, + cause: ObligationCause<'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option>, + ) -> Option> { + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) + } +} + +struct NormalizeQuery<'tcx, T> { + canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>>, + base_universe: ty::UniverseIndex, +} + +impl TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> +where + T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx, +{ + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); + err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value)); + err + } + + fn base_universe(&self) -> ty::UniverseIndex { + self.base_universe + } + + fn nice_error( + &self, + tcx: TyCtxt<'tcx>, + cause: ObligationCause<'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option>, + ) -> Option> { + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + + let mut selcx = SelectionContext::new(infcx); + + // FIXME(lqd): Unify and de-duplicate the following with the actual + // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the + // `ObligationCause`. The normalization results are currently different between + // `AtExt::normalize` used in the query and `normalize` called below: the former fails + // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check + // after #85499 lands to see if its fixes have erased this difference. + let (param_env, value) = key.into_parts(); + let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( + &mut selcx, + param_env, + cause, + value.value, + ); + fulfill_cx.register_predicate_obligations(infcx, obligations); + + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) + } +} + +struct AscribeUserTypeQuery<'tcx> { + canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>, + base_universe: ty::UniverseIndex, +} + +impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { + fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, + // and is only the fallback when the nice error fails. Consider improving this some more. + tcx.sess.struct_span_err(span, "higher-ranked lifetime error") + } + + fn base_universe(&self) -> ty::UniverseIndex { + self.base_universe + } + + fn nice_error( + &self, + tcx: TyCtxt<'tcx>, + cause: ObligationCause<'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option>, + ) -> Option> { + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) + .ok()?; + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) + } +} + +#[instrument(skip(fulfill_cx, infcx), level = "debug")] +fn try_extract_error_from_fulfill_cx<'tcx>( + mut fulfill_cx: Box + 'tcx>, + infcx: &InferCtxt<'_, 'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option>, +) -> Option> { + let tcx = infcx.tcx; + + // We generally shouldn't have errors here because the query was + // already run, but there's no point using `delay_span_bug` + // when we're going to emit an error here anyway. + let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new); + + let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| { + debug!("{:#?}", region_constraints); + region_constraints.constraints.iter().find_map(|(constraint, cause)| { + match *constraint { + Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => { + Some((sub, cause.clone())) + } + // FIXME: Should this check the universe of the var? + Constraint::VarSubReg(vid, sup) if sup == placeholder_region => { + Some((tcx.mk_region(ty::ReVar(vid)), cause.clone())) + } + _ => None, + } + }) + })?; + + debug!(?sub_region, "cause = {:#?}", cause); + let nice_error = match (error_region, sub_region) { + (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new( + infcx, + RegionResolutionError::SubSupConflict( + vid, + infcx.region_var_origin(vid), + cause.clone(), + error_region, + cause.clone(), + placeholder_region, + ), + ), + (Some(error_region), _) => NiceRegionError::new( + infcx, + RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region), + ), + // Note universe here is wrong... + (None, &ty::ReVar(vid)) => NiceRegionError::new( + infcx, + RegionResolutionError::UpperBoundUniverseConflict( + vid, + infcx.region_var_origin(vid), + infcx.universe_of_region(sub_region), + cause.clone(), + placeholder_region, + ), + ), + (None, _) => NiceRegionError::new( + infcx, + RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region), + ), + }; + nice_error.try_report_from_nll().or_else(|| { + if let SubregionOrigin::Subtype(trace) = cause { + Some( + infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch), + ) + } else { + None + } + }) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,2359 @@ +use either::Either; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; +use rustc_middle::mir::{ + self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, + FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, + ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, +}; +use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; +use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; +use rustc_span::source_map::DesugaringKind; +use rustc_span::symbol::sym; +use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt; + +use crate::borrowck_errors; + +use crate::{ + borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, + InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, +}; + +use super::{ + explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName, + RegionNameSource, UseSpans, +}; + +#[derive(Debug)] +struct MoveSite { + /// Index of the "move out" that we found. The `MoveData` can + /// then tell us where the move occurred. + moi: MoveOutIndex, + + /// `true` if we traversed a back edge while walking from the point + /// of error to the move site. + traversed_back_edge: bool, +} + +/// Which case a StorageDeadOrDrop is for. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum StorageDeadOrDrop<'tcx> { + LocalStorageDead, + BoxedStorageDead, + Destructor(Ty<'tcx>), +} + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + pub(crate) fn report_use_of_moved_or_uninitialized( + &mut self, + location: Location, + desired_action: InitializationRequiringAction, + (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span), + mpi: MovePathIndex, + ) { + debug!( + "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \ + moved_place={:?} used_place={:?} span={:?} mpi={:?}", + location, desired_action, moved_place, used_place, span, mpi + ); + + let use_spans = + self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location)); + let span = use_spans.args_or_use(); + + let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi); + debug!( + "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}", + move_site_vec, use_spans + ); + let move_out_indices: Vec<_> = + move_site_vec.iter().map(|move_site| move_site.moi).collect(); + + if move_out_indices.is_empty() { + let root_place = PlaceRef { projection: &[], ..used_place }; + + if !self.uninitialized_error_reported.insert(root_place) { + debug!( + "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", + root_place + ); + return; + } + + let item_msg = + match self.describe_place_with_options(used_place, IncludingDowncast(true)) { + Some(name) => format!("`{}`", name), + None => "value".to_owned(), + }; + let mut err = self.cannot_act_on_uninitialized_variable( + span, + desired_action.as_noun(), + &self + .describe_place_with_options(moved_place, IncludingDowncast(true)) + .unwrap_or_else(|| "_".to_owned()), + ); + err.span_label(span, format!("use of possibly-uninitialized {}", item_msg)); + + use_spans.var_span_label_path_only( + &mut err, + format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), + ); + + err.buffer(&mut self.errors_buffer); + } else { + if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) { + if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) { + debug!( + "report_use_of_moved_or_uninitialized place: error suppressed \ + mois={:?}", + move_out_indices + ); + return; + } + } + + let is_partial_move = move_site_vec.iter().any(|move_site| { + let move_out = self.move_data.moves[(*move_site).moi]; + let moved_place = &self.move_data.move_paths[move_out.path].place; + // `*(_1)` where `_1` is a `Box` is actually a move out. + let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref] + && self.body.local_decls[moved_place.local].ty.is_box(); + + !is_box_move + && used_place != moved_place.as_ref() + && used_place.is_prefix_of(moved_place.as_ref()) + }); + + let partial_str = if is_partial_move { "partial " } else { "" }; + let partially_str = if is_partial_move { "partially " } else { "" }; + + let mut err = self.cannot_act_on_moved_value( + span, + desired_action.as_noun(), + partially_str, + self.describe_place_with_options(moved_place, IncludingDowncast(true)), + ); + + let reinit_spans = maybe_reinitialized_locations + .iter() + .take(3) + .map(|loc| { + self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc) + .args_or_use() + }) + .collect::>(); + let reinits = maybe_reinitialized_locations.len(); + if reinits == 1 { + err.span_label(reinit_spans[0], "this reinitialization might get skipped"); + } else if reinits > 1 { + err.span_note( + MultiSpan::from_spans(reinit_spans), + &if reinits <= 3 { + format!("these {} reinitializations might get skipped", reinits) + } else { + format!( + "these 3 reinitializations and {} other{} might get skipped", + reinits - 3, + if reinits == 4 { "" } else { "s" } + ) + }, + ); + } + + self.add_moved_or_invoked_closure_note(location, used_place, &mut err); + + let mut is_loop_move = false; + let mut in_pattern = false; + + for move_site in &move_site_vec { + let move_out = self.move_data.moves[(*move_site).moi]; + let moved_place = &self.move_data.move_paths[move_out.path].place; + + let move_spans = self.move_spans(moved_place.as_ref(), move_out.source); + let move_span = move_spans.args_or_use(); + + let move_msg = if move_spans.for_closure() { " into closure" } else { "" }; + + let loop_message = if location == move_out.source || move_site.traversed_back_edge { + ", in previous iteration of loop" + } else { + "" + }; + + if location == move_out.source { + is_loop_move = true; + } + + if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { + let place_name = self + .describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "value".to_owned()); + match kind { + FnSelfUseKind::FnOnceCall => { + err.span_label( + fn_call_span, + &format!( + "{} {}moved due to this call{}", + place_name, partially_str, loop_message + ), + ); + err.span_note( + var_span, + "this value implements `FnOnce`, which causes it to be moved when called", + ); + } + FnSelfUseKind::Operator { self_arg } => { + err.span_label( + fn_call_span, + &format!( + "{} {}moved due to usage in operator{}", + place_name, partially_str, loop_message + ), + ); + if self.fn_self_span_reported.insert(fn_span) { + err.span_note( + // Check whether the source is accessible + if self + .infcx + .tcx + .sess + .source_map() + .span_to_snippet(self_arg.span) + .is_ok() + { + self_arg.span + } else { + fn_call_span + }, + "calling this operator moves the left-hand side", + ); + } + } + FnSelfUseKind::Normal { + self_arg, + implicit_into_iter, + is_option_or_result, + } => { + if implicit_into_iter { + err.span_label( + fn_call_span, + &format!( + "{} {}moved due to this implicit call to `.into_iter()`{}", + place_name, partially_str, loop_message + ), + ); + } else { + err.span_label( + fn_call_span, + &format!( + "{} {}moved due to this method call{}", + place_name, partially_str, loop_message + ), + ); + } + if is_option_or_result && maybe_reinitialized_locations.is_empty() { + err.span_suggestion_verbose( + fn_call_span.shrink_to_lo(), + "consider calling `.as_ref()` to borrow the type's contents", + "as_ref().".to_string(), + Applicability::MachineApplicable, + ); + } + // Avoid pointing to the same function in multiple different + // error messages. + if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) + { + err.span_note( + self_arg.span, + &format!("this function takes ownership of the receiver `self`, which moves {}", place_name) + ); + } + } + // Deref::deref takes &self, which cannot cause a move + FnSelfUseKind::DerefCoercion { .. } => unreachable!(), + } + } else { + err.span_label( + move_span, + format!("value {}moved{} here{}", partially_str, move_msg, loop_message), + ); + // If the move error occurs due to a loop, don't show + // another message for the same span + if loop_message.is_empty() { + move_spans.var_span_label( + &mut err, + format!( + "variable {}moved due to use{}", + partially_str, + move_spans.describe() + ), + "moved", + ); + } + } + + if let (UseSpans::PatUse(span), []) = + (move_spans, &maybe_reinitialized_locations[..]) + { + if maybe_reinitialized_locations.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "borrow this field in the pattern to avoid moving {}", + self.describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "the value".to_string()) + ), + "ref ".to_string(), + Applicability::MachineApplicable, + ); + in_pattern = true; + } + } + + if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() { + let sess = self.infcx.tcx.sess; + let ty = used_place.ty(self.body, self.infcx.tcx).ty; + // If we have a `&mut` ref, we need to reborrow. + if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { + // If we are in a loop this will be suggested later. + if !is_loop_move { + err.span_suggestion_verbose( + move_span.shrink_to_lo(), + &format!( + "consider creating a fresh reborrow of {} here", + self.describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "the mutable reference".to_string()), + ), + "&mut *".to_string(), + Applicability::MachineApplicable, + ); + } + } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) { + err.span_suggestion( + move_span, + "consider borrowing to avoid moving into the for loop", + format!("&{}", snippet), + Applicability::MaybeIncorrect, + ); + } + } + } + + use_spans.var_span_label_path_only( + &mut err, + format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), + ); + + if !is_loop_move { + err.span_label( + span, + format!( + "value {} here after {}move", + desired_action.as_verb_in_past_tense(), + partial_str + ), + ); + } + + let ty = used_place.ty(self.body, self.infcx.tcx).ty; + let needs_note = match ty.kind() { + ty::Closure(id, _) => { + let tables = self.infcx.tcx.typeck(id.expect_local()); + let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local()); + + tables.closure_kind_origins().get(hir_id).is_none() + } + _ => true, + }; + + let mpi = self.move_data.moves[move_out_indices[0]].path; + let place = &self.move_data.move_paths[mpi].place; + let ty = place.ty(self.body, self.infcx.tcx).ty; + + // If we're in pattern, we do nothing in favor of the previous suggestion (#80913). + if is_loop_move & !in_pattern { + if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { + // We have a `&mut` ref, we need to reborrow on each iteration (#62112). + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "consider creating a fresh reborrow of {} here", + self.describe_place(moved_place) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "the mutable reference".to_string()), + ), + "&mut *".to_string(), + Applicability::MachineApplicable, + ); + } + } + + if needs_note { + let opt_name = + self.describe_place_with_options(place.as_ref(), IncludingDowncast(true)); + let note_msg = match opt_name { + Some(ref name) => format!("`{}`", name), + None => "value".to_owned(), + }; + if let ty::Param(param_ty) = ty.kind() { + let tcx = self.infcx.tcx; + let generics = tcx.generics_of(self.mir_def_id()); + let param = generics.type_param(¶m_ty, tcx); + if let Some(generics) = tcx + .hir() + .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id())) + { + suggest_constraining_type_param( + tcx, + generics, + &mut err, + ¶m.name.as_str(), + "Copy", + None, + ); + } + } + let span = if let Some(local) = place.as_local() { + let decl = &self.body.local_decls[local]; + Some(decl.source_info.span) + } else { + None + }; + self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str); + } + + if let UseSpans::FnSelfUse { + kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty }, + .. + } = use_spans + { + err.note(&format!( + "{} occurs due to deref coercion to `{}`", + desired_action.as_noun(), + deref_target_ty + )); + + // Check first whether the source is accessible (issue #87060) + if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() { + err.span_note(deref_target, "deref defined here"); + } + } + + if let Some((_, mut old_err)) = + self.move_error_reported.insert(move_out_indices, (used_place, err)) + { + // Cancel the old error so it doesn't ICE. + old_err.cancel(); + } + } + } + + pub(crate) fn report_move_out_while_borrowed( + &mut self, + location: Location, + (place, span): (Place<'tcx>, Span), + borrow: &BorrowData<'tcx>, + ) { + debug!( + "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}", + location, place, span, borrow + ); + let value_msg = self.describe_any_place(place.as_ref()); + let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref()); + + let borrow_spans = self.retrieve_borrow_spans(borrow); + let borrow_span = borrow_spans.args_or_use(); + + let move_spans = self.move_spans(place.as_ref(), location); + let span = move_spans.args_or_use(); + + let mut err = + self.cannot_move_when_borrowed(span, &self.describe_any_place(place.as_ref())); + err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg)); + err.span_label(span, format!("move out of {} occurs here", value_msg)); + + borrow_spans.var_span_label_path_only( + &mut err, + format!("borrow occurs due to use{}", borrow_spans.describe()), + ); + + move_spans.var_span_label( + &mut err, + format!("move occurs due to use{}", move_spans.describe()), + "moved", + ); + + self.explain_why_borrow_contains_point(location, borrow, None) + .add_explanation_to_diagnostic( + self.infcx.tcx, + &self.body, + &self.local_names, + &mut err, + "", + Some(borrow_span), + None, + ); + err.buffer(&mut self.errors_buffer); + } + + pub(crate) fn report_use_while_mutably_borrowed( + &mut self, + location: Location, + (place, _span): (Place<'tcx>, Span), + borrow: &BorrowData<'tcx>, + ) -> DiagnosticBuilder<'cx> { + let borrow_spans = self.retrieve_borrow_spans(borrow); + let borrow_span = borrow_spans.args_or_use(); + + // Conflicting borrows are reported separately, so only check for move + // captures. + let use_spans = self.move_spans(place.as_ref(), location); + let span = use_spans.var_or_use(); + + // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use + // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure + let mut err = self.cannot_use_when_mutably_borrowed( + span, + &self.describe_any_place(place.as_ref()), + borrow_span, + &self.describe_any_place(borrow.borrowed_place.as_ref()), + ); + + borrow_spans.var_span_label( + &mut err, + { + let place = &borrow.borrowed_place; + let desc_place = self.describe_any_place(place.as_ref()); + format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe()) + }, + "mutable", + ); + + self.explain_why_borrow_contains_point(location, borrow, None) + .add_explanation_to_diagnostic( + self.infcx.tcx, + &self.body, + &self.local_names, + &mut err, + "", + None, + None, + ); + err + } + + pub(crate) fn report_conflicting_borrow( + &mut self, + location: Location, + (place, span): (Place<'tcx>, Span), + gen_borrow_kind: BorrowKind, + issued_borrow: &BorrowData<'tcx>, + ) -> DiagnosticBuilder<'cx> { + let issued_spans = self.retrieve_borrow_spans(issued_borrow); + let issued_span = issued_spans.args_or_use(); + + let borrow_spans = self.borrow_spans(span, location); + let span = borrow_spans.args_or_use(); + + let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() { + "generator" + } else { + "closure" + }; + + let (desc_place, msg_place, msg_borrow, union_type_name) = + self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place); + + let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None); + let second_borrow_desc = if explanation.is_explained() { "second " } else { "" }; + + // FIXME: supply non-"" `opt_via` when appropriate + let first_borrow_desc; + let mut err = match (gen_borrow_kind, issued_borrow.kind) { + (BorrowKind::Shared, BorrowKind::Mut { .. }) => { + first_borrow_desc = "mutable "; + self.cannot_reborrow_already_borrowed( + span, + &desc_place, + &msg_place, + "immutable", + issued_span, + "it", + "mutable", + &msg_borrow, + None, + ) + } + (BorrowKind::Mut { .. }, BorrowKind::Shared) => { + first_borrow_desc = "immutable "; + self.cannot_reborrow_already_borrowed( + span, + &desc_place, + &msg_place, + "mutable", + issued_span, + "it", + "immutable", + &msg_borrow, + None, + ) + } + + (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { + first_borrow_desc = "first "; + let mut err = self.cannot_mutably_borrow_multiply( + span, + &desc_place, + &msg_place, + issued_span, + &msg_borrow, + None, + ); + self.suggest_split_at_mut_if_applicable( + &mut err, + place, + issued_borrow.borrowed_place, + ); + err + } + + (BorrowKind::Unique, BorrowKind::Unique) => { + first_borrow_desc = "first "; + self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) + } + + (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => { + if let Some(immutable_section_description) = + self.classify_immutable_section(issued_borrow.assigned_place) + { + let mut err = self.cannot_mutate_in_immutable_section( + span, + issued_span, + &desc_place, + immutable_section_description, + "mutably borrow", + ); + borrow_spans.var_span_label( + &mut err, + format!( + "borrow occurs due to use of {}{}", + desc_place, + borrow_spans.describe(), + ), + "immutable", + ); + + return err; + } else { + first_borrow_desc = "immutable "; + self.cannot_reborrow_already_borrowed( + span, + &desc_place, + &msg_place, + "mutable", + issued_span, + "it", + "immutable", + &msg_borrow, + None, + ) + } + } + + (BorrowKind::Unique, _) => { + first_borrow_desc = "first "; + self.cannot_uniquely_borrow_by_one_closure( + span, + container_name, + &desc_place, + "", + issued_span, + "it", + "", + None, + ) + } + + (BorrowKind::Shared, BorrowKind::Unique) => { + first_borrow_desc = "first "; + self.cannot_reborrow_already_uniquely_borrowed( + span, + container_name, + &desc_place, + "", + "immutable", + issued_span, + "", + None, + second_borrow_desc, + ) + } + + (BorrowKind::Mut { .. }, BorrowKind::Unique) => { + first_borrow_desc = "first "; + self.cannot_reborrow_already_uniquely_borrowed( + span, + container_name, + &desc_place, + "", + "mutable", + issued_span, + "", + None, + second_borrow_desc, + ) + } + + (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow) + | ( + BorrowKind::Shallow, + BorrowKind::Mut { .. } + | BorrowKind::Unique + | BorrowKind::Shared + | BorrowKind::Shallow, + ) => unreachable!(), + }; + + if issued_spans == borrow_spans { + borrow_spans.var_span_label( + &mut err, + format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),), + gen_borrow_kind.describe_mutability(), + ); + } else { + let borrow_place = &issued_borrow.borrowed_place; + let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); + issued_spans.var_span_label( + &mut err, + format!( + "first borrow occurs due to use of {}{}", + borrow_place_desc, + issued_spans.describe(), + ), + issued_borrow.kind.describe_mutability(), + ); + + borrow_spans.var_span_label( + &mut err, + format!( + "second borrow occurs due to use of {}{}", + desc_place, + borrow_spans.describe(), + ), + gen_borrow_kind.describe_mutability(), + ); + } + + if union_type_name != "" { + err.note(&format!( + "{} is a field of the union `{}`, so it overlaps the field {}", + msg_place, union_type_name, msg_borrow, + )); + } + + explanation.add_explanation_to_diagnostic( + self.infcx.tcx, + &self.body, + &self.local_names, + &mut err, + first_borrow_desc, + None, + Some((issued_span, span)), + ); + + err + } + + fn suggest_split_at_mut_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + place: Place<'tcx>, + borrowed_place: Place<'tcx>, + ) { + if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) = + (&place.projection[..], &borrowed_place.projection[..]) + { + err.help( + "consider using `.split_at_mut(position)` or similar method to obtain \ + two mutable non-overlapping sub-slices", + ); + } + } + + /// Returns the description of the root place for a conflicting borrow and the full + /// descriptions of the places that caused the conflict. + /// + /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is + /// attempted while a shared borrow is live, then this function will return: + /// + /// ("x", "", "") + /// + /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while + /// a shared borrow of another field `x.y`, then this function will return: + /// + /// ("x", "x.z", "x.y") + /// + /// In the more complex union case, where the union is a field of a struct, then if a mutable + /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of + /// another field `x.u.y`, then this function will return: + /// + /// ("x.u", "x.u.z", "x.u.y") + /// + /// This is used when creating error messages like below: + /// + /// ```text + /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as + /// mutable (via `a.u.s.b`) [E0502] + /// ``` + pub(crate) fn describe_place_for_conflicting_borrow( + &self, + first_borrowed_place: Place<'tcx>, + second_borrowed_place: Place<'tcx>, + ) -> (String, String, String, String) { + // Define a small closure that we can use to check if the type of a place + // is a union. + let union_ty = |place_base| { + // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`; + // using a type annotation in the closure argument instead leads to a lifetime error. + let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty; + ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) + }; + + // Start with an empty tuple, so we can use the functions on `Option` to reduce some + // code duplication (particularly around returning an empty description in the failure + // case). + Some(()) + .filter(|_| { + // If we have a conflicting borrow of the same place, then we don't want to add + // an extraneous "via x.y" to our diagnostics, so filter out this case. + first_borrowed_place != second_borrowed_place + }) + .and_then(|_| { + // We're going to want to traverse the first borrowed place to see if we can find + // field access to a union. If we find that, then we will keep the place of the + // union being accessed and the field that was being accessed so we can check the + // second borrowed place for the same union and an access to a different field. + for (place_base, elem) in first_borrowed_place.iter_projections().rev() { + match elem { + ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => { + return Some((place_base, field)); + } + _ => {} + } + } + None + }) + .and_then(|(target_base, target_field)| { + // With the place of a union and a field access into it, we traverse the second + // borrowed place and look for an access to a different field of the same union. + for (place_base, elem) in second_borrowed_place.iter_projections().rev() { + if let ProjectionElem::Field(field, _) = elem { + if let Some(union_ty) = union_ty(place_base) { + if field != target_field && place_base == target_base { + return Some(( + self.describe_any_place(place_base), + self.describe_any_place(first_borrowed_place.as_ref()), + self.describe_any_place(second_borrowed_place.as_ref()), + union_ty.to_string(), + )); + } + } + } + } + None + }) + .unwrap_or_else(|| { + // If we didn't find a field access into a union, or both places match, then + // only return the description of the first place. + ( + self.describe_any_place(first_borrowed_place.as_ref()), + "".to_string(), + "".to_string(), + "".to_string(), + ) + }) + } + + /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`. + /// + /// This means that some data referenced by `borrow` needs to live + /// past the point where the StorageDeadOrDrop of `place` occurs. + /// This is usually interpreted as meaning that `place` has too + /// short a lifetime. (But sometimes it is more useful to report + /// it as a more direct conflict between the execution of a + /// `Drop::drop` with an aliasing borrow.) + pub(crate) fn report_borrowed_value_does_not_live_long_enough( + &mut self, + location: Location, + borrow: &BorrowData<'tcx>, + place_span: (Place<'tcx>, Span), + kind: Option, + ) { + debug!( + "report_borrowed_value_does_not_live_long_enough(\ + {:?}, {:?}, {:?}, {:?}\ + )", + location, borrow, place_span, kind + ); + + let drop_span = place_span.1; + let root_place = + self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); + + let borrow_spans = self.retrieve_borrow_spans(borrow); + let borrow_span = borrow_spans.var_or_use_path_span(); + + assert!(root_place.projection.is_empty()); + let proper_span = self.body.local_decls[root_place.local].source_info.span; + + let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection); + + if self.access_place_error_reported.contains(&( + Place { local: root_place.local, projection: root_place_projection }, + borrow_span, + )) { + debug!( + "suppressing access_place error when borrow doesn't live long enough for {:?}", + borrow_span + ); + return; + } + + self.access_place_error_reported.insert(( + Place { local: root_place.local, projection: root_place_projection }, + borrow_span, + )); + + let borrowed_local = borrow.borrowed_place.local; + if self.body.local_decls[borrowed_local].is_ref_to_thread_local() { + let err = + self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span); + err.buffer(&mut self.errors_buffer); + return; + } + + if let StorageDeadOrDrop::Destructor(dropped_ty) = + self.classify_drop_access_kind(borrow.borrowed_place.as_ref()) + { + // If a borrow of path `B` conflicts with drop of `D` (and + // we're not in the uninteresting case where `B` is a + // prefix of `D`), then report this as a more interesting + // destructor conflict. + if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) { + self.report_borrow_conflicts_with_destructor( + location, borrow, place_span, kind, dropped_ty, + ); + return; + } + } + + let place_desc = self.describe_place(borrow.borrowed_place.as_ref()); + + let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0)); + let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place); + + debug!( + "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})", + place_desc, explanation + ); + let err = match (place_desc, explanation) { + // If the outlives constraint comes from inside the closure, + // for example: + // + // let x = 0; + // let y = &x; + // Box::new(|| y) as Box &'static i32> + // + // then just use the normal error. The closure isn't escaping + // and `move` will not help here. + ( + Some(ref name), + BorrowExplanation::MustBeValidFor { + category: + category + @ + (ConstraintCategory::Return(_) + | ConstraintCategory::CallArgument + | ConstraintCategory::OpaqueType), + from_closure: false, + ref region_name, + span, + .. + }, + ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self + .report_escaping_closure_capture( + borrow_spans, + borrow_span, + region_name, + category, + span, + &format!("`{}`", name), + ), + ( + ref name, + BorrowExplanation::MustBeValidFor { + category: ConstraintCategory::Assignment, + from_closure: false, + region_name: + RegionName { + source: + RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name), + .. + }, + span, + .. + }, + ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span), + (Some(name), explanation) => self.report_local_value_does_not_live_long_enough( + location, + &name, + &borrow, + drop_span, + borrow_spans, + explanation, + ), + (None, explanation) => self.report_temporary_value_does_not_live_long_enough( + location, + &borrow, + drop_span, + borrow_spans, + proper_span, + explanation, + ), + }; + + err.buffer(&mut self.errors_buffer); + } + + fn report_local_value_does_not_live_long_enough( + &mut self, + location: Location, + name: &str, + borrow: &BorrowData<'tcx>, + drop_span: Span, + borrow_spans: UseSpans<'tcx>, + explanation: BorrowExplanation, + ) -> DiagnosticBuilder<'cx> { + debug!( + "report_local_value_does_not_live_long_enough(\ + {:?}, {:?}, {:?}, {:?}, {:?}\ + )", + location, name, borrow, drop_span, borrow_spans + ); + + let borrow_span = borrow_spans.var_or_use_path_span(); + if let BorrowExplanation::MustBeValidFor { + category, + span, + ref opt_place_desc, + from_closure: false, + .. + } = explanation + { + if let Some(diag) = self.try_report_cannot_return_reference_to_local( + borrow, + borrow_span, + span, + category, + opt_place_desc.as_ref(), + ) { + return diag; + } + } + + let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name)); + + if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { + let region_name = annotation.emit(self, &mut err); + + err.span_label( + borrow_span, + format!("`{}` would have to be valid for `{}`...", name, region_name), + ); + + let fn_hir_id = self.mir_hir_id(); + err.span_label( + drop_span, + format!( + "...but `{}` will be dropped here, when the {} returns", + name, + self.infcx + .tcx + .hir() + .opt_name(fn_hir_id) + .map(|name| format!("function `{}`", name)) + .unwrap_or_else(|| { + match &self + .infcx + .tcx + .typeck(self.mir_def_id()) + .node_type(fn_hir_id) + .kind() + { + ty::Closure(..) => "enclosing closure", + ty::Generator(..) => "enclosing generator", + kind => bug!("expected closure or generator, found {:?}", kind), + } + .to_string() + }) + ), + ); + + err.note( + "functions cannot return a borrow to data owned within the function's scope, \ + functions can only return borrows to data passed as arguments", + ); + err.note( + "to learn more, visit ", + ); + + if let BorrowExplanation::MustBeValidFor { .. } = explanation { + } else { + explanation.add_explanation_to_diagnostic( + self.infcx.tcx, + &self.body, + &self.local_names, + &mut err, + "", + None, + None, + ); + } + } else { + err.span_label(borrow_span, "borrowed value does not live long enough"); + err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name)); + + let within = if borrow_spans.for_generator() { " by generator" } else { "" }; + + borrow_spans.args_span_label(&mut err, format!("value captured here{}", within)); + + explanation.add_explanation_to_diagnostic( + self.infcx.tcx, + &self.body, + &self.local_names, + &mut err, + "", + None, + None, + ); + } + + err + } + + fn report_borrow_conflicts_with_destructor( + &mut self, + location: Location, + borrow: &BorrowData<'tcx>, + (place, drop_span): (Place<'tcx>, Span), + kind: Option, + dropped_ty: Ty<'tcx>, + ) { + debug!( + "report_borrow_conflicts_with_destructor(\ + {:?}, {:?}, ({:?}, {:?}), {:?}\ + )", + location, borrow, place, drop_span, kind, + ); + + let borrow_spans = self.retrieve_borrow_spans(borrow); + let borrow_span = borrow_spans.var_or_use(); + + let mut err = self.cannot_borrow_across_destructor(borrow_span); + + let what_was_dropped = match self.describe_place(place.as_ref()) { + Some(name) => format!("`{}`", name), + None => String::from("temporary value"), + }; + + let label = match self.describe_place(borrow.borrowed_place.as_ref()) { + Some(borrowed) => format!( + "here, drop of {D} needs exclusive access to `{B}`, \ + because the type `{T}` implements the `Drop` trait", + D = what_was_dropped, + T = dropped_ty, + B = borrowed + ), + None => format!( + "here is drop of {D}; whose type `{T}` implements the `Drop` trait", + D = what_was_dropped, + T = dropped_ty + ), + }; + err.span_label(drop_span, label); + + // Only give this note and suggestion if they could be relevant. + let explanation = + self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place))); + match explanation { + BorrowExplanation::UsedLater { .. } + | BorrowExplanation::UsedLaterWhenDropped { .. } => { + err.note("consider using a `let` binding to create a longer lived value"); + } + _ => {} + } + + explanation.add_explanation_to_diagnostic( + self.infcx.tcx, + &self.body, + &self.local_names, + &mut err, + "", + None, + None, + ); + + err.buffer(&mut self.errors_buffer); + } + + fn report_thread_local_value_does_not_live_long_enough( + &mut self, + drop_span: Span, + borrow_span: Span, + ) -> DiagnosticBuilder<'cx> { + debug!( + "report_thread_local_value_does_not_live_long_enough(\ + {:?}, {:?}\ + )", + drop_span, borrow_span + ); + + let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span); + + err.span_label( + borrow_span, + "thread-local variables cannot be borrowed beyond the end of the function", + ); + err.span_label(drop_span, "end of enclosing function is here"); + + err + } + + fn report_temporary_value_does_not_live_long_enough( + &mut self, + location: Location, + borrow: &BorrowData<'tcx>, + drop_span: Span, + borrow_spans: UseSpans<'tcx>, + proper_span: Span, + explanation: BorrowExplanation, + ) -> DiagnosticBuilder<'cx> { + debug!( + "report_temporary_value_does_not_live_long_enough(\ + {:?}, {:?}, {:?}, {:?}\ + )", + location, borrow, drop_span, proper_span + ); + + if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = + explanation + { + if let Some(diag) = self.try_report_cannot_return_reference_to_local( + borrow, + proper_span, + span, + category, + None, + ) { + return diag; + } + } + + let mut err = self.temporary_value_borrowed_for_too_long(proper_span); + err.span_label(proper_span, "creates a temporary which is freed while still in use"); + err.span_label(drop_span, "temporary value is freed at the end of this statement"); + + match explanation { + BorrowExplanation::UsedLater(..) + | BorrowExplanation::UsedLaterInLoop(..) + | BorrowExplanation::UsedLaterWhenDropped { .. } => { + // Only give this note and suggestion if it could be relevant. + err.note("consider using a `let` binding to create a longer lived value"); + } + _ => {} + } + explanation.add_explanation_to_diagnostic( + self.infcx.tcx, + &self.body, + &self.local_names, + &mut err, + "", + None, + None, + ); + + let within = if borrow_spans.for_generator() { " by generator" } else { "" }; + + borrow_spans.args_span_label(&mut err, format!("value captured here{}", within)); + + err + } + + fn try_report_cannot_return_reference_to_local( + &self, + borrow: &BorrowData<'tcx>, + borrow_span: Span, + return_span: Span, + category: ConstraintCategory, + opt_place_desc: Option<&String>, + ) -> Option> { + let return_kind = match category { + ConstraintCategory::Return(_) => "return", + ConstraintCategory::Yield => "yield", + _ => return None, + }; + + // FIXME use a better heuristic than Spans + let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span { + "reference to" + } else { + "value referencing" + }; + + let (place_desc, note) = if let Some(place_desc) = opt_place_desc { + let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { + match self.body.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Temp => { + bug!("temporary or return pointer with a name") + } + LocalKind::Var => "local variable ", + LocalKind::Arg + if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL => + { + "variable captured by `move` " + } + LocalKind::Arg => "function parameter ", + } + } else { + "local data " + }; + ( + format!("{}`{}`", local_kind, place_desc), + format!("`{}` is borrowed here", place_desc), + ) + } else { + let root_place = + self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); + let local = root_place.local; + match self.body.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Temp => { + ("temporary value".to_string(), "temporary value created here".to_string()) + } + LocalKind::Arg => ( + "function parameter".to_string(), + "function parameter borrowed here".to_string(), + ), + LocalKind::Var => { + ("local binding".to_string(), "local binding introduced here".to_string()) + } + } + }; + + let mut err = self.cannot_return_reference_to_local( + return_span, + return_kind, + reference_desc, + &place_desc, + ); + + if return_span != borrow_span { + err.span_label(borrow_span, note); + + let tcx = self.infcx.tcx; + let ty_params = ty::List::empty(); + + let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; + let return_ty = tcx.erase_regions(return_ty); + + // to avoid panics + if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { + if self + .infcx + .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env) + .must_apply_modulo_regions() + { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { + err.span_suggestion_hidden( + return_span, + "use `.collect()` to allocate the iterator", + format!("{}{}", snippet, ".collect::>()"), + Applicability::MaybeIncorrect, + ); + } + } + } + } + + Some(err) + } + + fn report_escaping_closure_capture( + &mut self, + use_span: UseSpans<'tcx>, + var_span: Span, + fr_name: &RegionName, + category: ConstraintCategory, + constraint_span: Span, + captured_var: &str, + ) -> DiagnosticBuilder<'cx> { + let tcx = self.infcx.tcx; + let args_span = use_span.args_or_use(); + + let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) { + Ok(string) => { + if string.starts_with("async ") { + let pos = args_span.lo() + BytePos(6); + (args_span.with_lo(pos).with_hi(pos), "move ".to_string()) + } else if string.starts_with("async|") { + let pos = args_span.lo() + BytePos(5); + (args_span.with_lo(pos).with_hi(pos), " move".to_string()) + } else { + (args_span.shrink_to_lo(), "move ".to_string()) + } + } + Err(_) => (args_span, "move || ".to_string()), + }; + let kind = match use_span.generator_kind() { + Some(generator_kind) => match generator_kind { + GeneratorKind::Async(async_kind) => match async_kind { + AsyncGeneratorKind::Block => "async block", + AsyncGeneratorKind::Closure => "async closure", + _ => bug!("async block/closure expected, but async function found."), + }, + GeneratorKind::Gen => "generator", + }, + None => "closure", + }; + + let mut err = + self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span); + err.span_suggestion_verbose( + sugg_span, + &format!( + "to force the {} to take ownership of {} (and any \ + other referenced variables), use the `move` keyword", + kind, captured_var + ), + suggestion, + Applicability::MachineApplicable, + ); + + match category { + ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => { + let msg = format!("{} is returned here", kind); + err.span_note(constraint_span, &msg); + } + ConstraintCategory::CallArgument => { + fr_name.highlight_region_name(&mut err); + if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) { + err.note( + "async blocks are not executed immediately and must either take a \ + reference or ownership of outside variables they use", + ); + } else { + let msg = format!("function requires argument type to outlive `{}`", fr_name); + err.span_note(constraint_span, &msg); + } + } + _ => bug!( + "report_escaping_closure_capture called with unexpected constraint \ + category: `{:?}`", + category + ), + } + + err + } + + fn report_escaping_data( + &mut self, + borrow_span: Span, + name: &Option, + upvar_span: Span, + upvar_name: &str, + escape_span: Span, + ) -> DiagnosticBuilder<'cx> { + let tcx = self.infcx.tcx; + + let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id()); + + let mut err = + borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from); + + err.span_label( + upvar_span, + format!("`{}` declared here, outside of the {} body", upvar_name, escapes_from), + ); + + err.span_label(borrow_span, format!("borrow is only valid in the {} body", escapes_from)); + + if let Some(name) = name { + err.span_label( + escape_span, + format!("reference to `{}` escapes the {} body here", name, escapes_from), + ); + } else { + err.span_label( + escape_span, + format!("reference escapes the {} body here", escapes_from), + ); + } + + err + } + + fn get_moved_indexes( + &mut self, + location: Location, + mpi: MovePathIndex, + ) -> (Vec, Vec) { + fn predecessor_locations( + body: &'a mir::Body<'tcx>, + location: Location, + ) -> impl Iterator + 'a { + if location.statement_index == 0 { + let predecessors = body.predecessors()[location.block].to_vec(); + Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) + } else { + Either::Right(std::iter::once(Location { + statement_index: location.statement_index - 1, + ..location + })) + } + } + + let mut mpis = vec![mpi]; + let move_paths = &self.move_data.move_paths; + mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi)); + + let mut stack = Vec::new(); + let mut back_edge_stack = Vec::new(); + + predecessor_locations(self.body, location).for_each(|predecessor| { + if location.dominates(predecessor, &self.dominators) { + back_edge_stack.push(predecessor) + } else { + stack.push(predecessor); + } + }); + + let mut reached_start = false; + + /* Check if the mpi is initialized as an argument */ + let mut is_argument = false; + for arg in self.body.args_iter() { + let path = self.move_data.rev_lookup.find_local(arg); + if mpis.contains(&path) { + is_argument = true; + } + } + + let mut visited = FxHashSet::default(); + let mut move_locations = FxHashSet::default(); + let mut reinits = vec![]; + let mut result = vec![]; + + let mut dfs_iter = |result: &mut Vec, location: Location, is_back_edge: bool| { + debug!( + "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})", + location, is_back_edge + ); + + if !visited.insert(location) { + return true; + } + + // check for moves + let stmt_kind = + self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind); + if let Some(StatementKind::StorageDead(..)) = stmt_kind { + // this analysis only tries to find moves explicitly + // written by the user, so we ignore the move-outs + // created by `StorageDead` and at the beginning + // of a function. + } else { + // If we are found a use of a.b.c which was in error, then we want to look for + // moves not only of a.b.c but also a.b and a. + // + // Note that the moves data already includes "parent" paths, so we don't have to + // worry about the other case: that is, if there is a move of a.b.c, it is already + // marked as a move of a.b and a as well, so we will generate the correct errors + // there. + for moi in &self.move_data.loc_map[location] { + debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); + let path = self.move_data.moves[*moi].path; + if mpis.contains(&path) { + debug!( + "report_use_of_moved_or_uninitialized: found {:?}", + move_paths[path].place + ); + result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge }); + move_locations.insert(location); + + // Strictly speaking, we could continue our DFS here. There may be + // other moves that can reach the point of error. But it is kind of + // confusing to highlight them. + // + // Example: + // + // ``` + // let a = vec![]; + // let b = a; + // let c = a; + // drop(a); // <-- current point of error + // ``` + // + // Because we stop the DFS here, we only highlight `let c = a`, + // and not `let b = a`. We will of course also report an error at + // `let c = a` which highlights `let b = a` as the move. + return true; + } + } + } + + // check for inits + let mut any_match = false; + for ii in &self.move_data.init_loc_map[location] { + let init = self.move_data.inits[*ii]; + match init.kind { + InitKind::Deep | InitKind::NonPanicPathOnly => { + if mpis.contains(&init.path) { + any_match = true; + } + } + InitKind::Shallow => { + if mpi == init.path { + any_match = true; + } + } + } + } + if any_match { + reinits.push(location); + return true; + } + return false; + }; + + while let Some(location) = stack.pop() { + if dfs_iter(&mut result, location, false) { + continue; + } + + let mut has_predecessor = false; + predecessor_locations(self.body, location).for_each(|predecessor| { + if location.dominates(predecessor, &self.dominators) { + back_edge_stack.push(predecessor) + } else { + stack.push(predecessor); + } + has_predecessor = true; + }); + + if !has_predecessor { + reached_start = true; + } + } + if (is_argument || !reached_start) && result.is_empty() { + /* Process back edges (moves in future loop iterations) only if + the move path is definitely initialized upon loop entry, + to avoid spurious "in previous iteration" errors. + During DFS, if there's a path from the error back to the start + of the function with no intervening init or move, then the + move path may be uninitialized at loop entry. + */ + while let Some(location) = back_edge_stack.pop() { + if dfs_iter(&mut result, location, true) { + continue; + } + + predecessor_locations(self.body, location) + .for_each(|predecessor| back_edge_stack.push(predecessor)); + } + } + + // Check if we can reach these reinits from a move location. + let reinits_reachable = reinits + .into_iter() + .filter(|reinit| { + let mut visited = FxHashSet::default(); + let mut stack = vec![*reinit]; + while let Some(location) = stack.pop() { + if !visited.insert(location) { + continue; + } + if move_locations.contains(&location) { + return true; + } + stack.extend(predecessor_locations(self.body, location)); + } + false + }) + .collect::>(); + (result, reinits_reachable) + } + + pub(crate) fn report_illegal_mutation_of_borrowed( + &mut self, + location: Location, + (place, span): (Place<'tcx>, Span), + loan: &BorrowData<'tcx>, + ) { + let loan_spans = self.retrieve_borrow_spans(loan); + let loan_span = loan_spans.args_or_use(); + + let descr_place = self.describe_any_place(place.as_ref()); + if loan.kind == BorrowKind::Shallow { + if let Some(section) = self.classify_immutable_section(loan.assigned_place) { + let mut err = self.cannot_mutate_in_immutable_section( + span, + loan_span, + &descr_place, + section, + "assign", + ); + loan_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", loan_spans.describe()), + loan.kind.describe_mutability(), + ); + + err.buffer(&mut self.errors_buffer); + + return; + } + } + + let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); + + loan_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", loan_spans.describe()), + loan.kind.describe_mutability(), + ); + + self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic( + self.infcx.tcx, + &self.body, + &self.local_names, + &mut err, + "", + None, + None, + ); + + self.explain_deref_coercion(loan, &mut err); + + err.buffer(&mut self.errors_buffer); + } + + fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) { + let tcx = self.infcx.tcx; + if let ( + Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }), + Some((method_did, method_substs)), + ) = ( + &self.body[loan.reserve_location.block].terminator, + rustc_const_eval::util::find_self_call( + tcx, + self.body, + loan.assigned_place.local, + loan.reserve_location.block, + ), + ) { + if tcx.is_diagnostic_item(sym::deref_method, method_did) { + let deref_target = + tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { + Instance::resolve(tcx, self.param_env, deref_target, method_substs) + .transpose() + }); + if let Some(Ok(instance)) = deref_target { + let deref_target_ty = instance.ty(tcx, self.param_env); + err.note(&format!( + "borrow occurs due to deref coercion to `{}`", + deref_target_ty + )); + err.span_note(tcx.def_span(instance.def_id()), "deref defined here"); + } + } + } + } + + /// Reports an illegal reassignment; for example, an assignment to + /// (part of) a non-`mut` local that occurs potentially after that + /// local has already been initialized. `place` is the path being + /// assigned; `err_place` is a place providing a reason why + /// `place` is not mutable (e.g., the non-`mut` local `x` in an + /// assignment to `x.f`). + pub(crate) fn report_illegal_reassignment( + &mut self, + _location: Location, + (place, span): (Place<'tcx>, Span), + assigned_span: Span, + err_place: Place<'tcx>, + ) { + let (from_arg, local_decl, local_name) = match err_place.as_local() { + Some(local) => ( + self.body.local_kind(local) == LocalKind::Arg, + Some(&self.body.local_decls[local]), + self.local_names[local], + ), + None => (false, None, None), + }; + + // If root local is initialized immediately (everything apart from let + // PATTERN;) then make the error refer to that local, rather than the + // place being assigned later. + let (place_description, assigned_span) = match local_decl { + Some(LocalDecl { + local_info: + Some(box LocalInfo::User( + ClearCrossCrate::Clear + | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + opt_match_place: None, + .. + })), + )) + | Some(box LocalInfo::StaticRef { .. }) + | None, + .. + }) + | None => (self.describe_any_place(place.as_ref()), assigned_span), + Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span), + }; + + let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg); + let msg = if from_arg { + "cannot assign to immutable argument" + } else { + "cannot assign twice to immutable variable" + }; + if span != assigned_span { + if !from_arg { + err.span_label(assigned_span, format!("first assignment to {}", place_description)); + } + } + if let Some(decl) = local_decl { + if let Some(name) = local_name { + if decl.can_be_made_mutable() { + err.span_suggestion( + decl.source_info.span, + "consider making this binding mutable", + format!("mut {}", name), + Applicability::MachineApplicable, + ); + } + } + } + err.span_label(span, msg); + err.buffer(&mut self.errors_buffer); + } + + fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> { + let tcx = self.infcx.tcx; + match place.last_projection() { + None => StorageDeadOrDrop::LocalStorageDead, + Some((place_base, elem)) => { + // FIXME(spastorino) make this iterate + let base_access = self.classify_drop_access_kind(place_base); + match elem { + ProjectionElem::Deref => match base_access { + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + assert!( + place_base.ty(self.body, tcx).ty.is_box(), + "Drop of value behind a reference or raw pointer" + ); + StorageDeadOrDrop::BoxedStorageDead + } + StorageDeadOrDrop::Destructor(_) => base_access, + }, + ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { + let base_ty = place_base.ty(self.body, tcx).ty; + match base_ty.kind() { + ty::Adt(def, _) if def.has_dtor(tcx) => { + // Report the outermost adt with a destructor + match base_access { + StorageDeadOrDrop::Destructor(_) => base_access, + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + StorageDeadOrDrop::Destructor(base_ty) + } + } + } + _ => base_access, + } + } + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Index(_) => base_access, + } + } + } + } + + /// Describe the reason for the fake borrow that was assigned to `place`. + fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> { + use rustc_middle::mir::visit::Visitor; + struct FakeReadCauseFinder<'tcx> { + place: Place<'tcx>, + cause: Option, + } + impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { + match statement { + Statement { kind: StatementKind::FakeRead(box (cause, place)), .. } + if *place == self.place => + { + self.cause = Some(*cause); + } + _ => (), + } + } + } + let mut visitor = FakeReadCauseFinder { place, cause: None }; + visitor.visit_body(&self.body); + match visitor.cause { + Some(FakeReadCause::ForMatchGuard) => Some("match guard"), + Some(FakeReadCause::ForIndex) => Some("indexing expression"), + _ => None, + } + } + + /// Annotate argument and return type of function and closure with (synthesized) lifetime for + /// borrow of local value that does not live long enough. + fn annotate_argument_and_return_for_borrow( + &self, + borrow: &BorrowData<'tcx>, + ) -> Option> { + // Define a fallback for when we can't match a closure. + let fallback = || { + let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id()); + if is_closure { + None + } else { + let ty = self.infcx.tcx.type_of(self.mir_def_id()); + match ty.kind() { + ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( + self.mir_def_id().to_def_id(), + self.infcx.tcx.fn_sig(self.mir_def_id()), + ), + _ => None, + } + } + }; + + // In order to determine whether we need to annotate, we need to check whether the reserve + // place was an assignment into a temporary. + // + // If it was, we check whether or not that temporary is eventually assigned into the return + // place. If it was, we can add annotations about the function's return type and arguments + // and it'll make sense. + let location = borrow.reserve_location; + debug!("annotate_argument_and_return_for_borrow: location={:?}", location); + if let Some(&Statement { kind: StatementKind::Assign(box (ref reservation, _)), .. }) = + &self.body[location.block].statements.get(location.statement_index) + { + debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation); + // Check that the initial assignment of the reserve location is into a temporary. + let mut target = match reservation.as_local() { + Some(local) if self.body.local_kind(local) == LocalKind::Temp => local, + _ => return None, + }; + + // Next, look through the rest of the block, checking if we are assigning the + // `target` (that is, the place that contains our borrow) to anything. + let mut annotated_closure = None; + for stmt in &self.body[location.block].statements[location.statement_index + 1..] { + debug!( + "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", + target, stmt + ); + if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind { + if let Some(assigned_to) = place.as_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_to={:?} \ + rvalue={:?}", + assigned_to, rvalue + ); + // Check if our `target` was captured by a closure. + if let Rvalue::Aggregate( + box AggregateKind::Closure(def_id, substs), + operands, + ) = rvalue + { + for operand in operands { + let assigned_from = match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from + ); + + // Find the local from the operand. + let assigned_from_local = match assigned_from.local_or_deref_local() + { + Some(local) => local, + None => continue, + }; + + if assigned_from_local != target { + continue; + } + + // If a closure captured our `target` and then assigned + // into a place then we should annotate the closure in + // case it ends up being assigned into the return place. + annotated_closure = + self.annotate_fn_sig(*def_id, substs.as_closure().sig()); + debug!( + "annotate_argument_and_return_for_borrow: \ + annotated_closure={:?} assigned_from_local={:?} \ + assigned_to={:?}", + annotated_closure, assigned_from_local, assigned_to + ); + + if assigned_to == mir::RETURN_PLACE { + // If it was assigned directly into the return place, then + // return now. + return annotated_closure; + } else { + // Otherwise, update the target. + target = assigned_to; + } + } + + // If none of our closure's operands matched, then skip to the next + // statement. + continue; + } + + // Otherwise, look at other types of assignment. + let assigned_from = match rvalue { + Rvalue::Ref(_, _, assigned_from) => assigned_from, + Rvalue::Use(operand) => match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }, + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from={:?}", + assigned_from, + ); + + // Find the local from the rvalue. + let assigned_from_local = match assigned_from.local_or_deref_local() { + Some(local) => local, + None => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?}", + assigned_from_local, + ); + + // Check if our local matches the target - if so, we've assigned our + // borrow to a new place. + if assigned_from_local != target { + continue; + } + + // If we assigned our `target` into a new place, then we should + // check if it was the return place. + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?} assigned_to={:?}", + assigned_from_local, assigned_to + ); + if assigned_to == mir::RETURN_PLACE { + // If it was then return the annotated closure if there was one, + // else, annotate this function. + return annotated_closure.or_else(fallback); + } + + // If we didn't assign into the return place, then we just update + // the target. + target = assigned_to; + } + } + } + + // Check the terminator if we didn't find anything in the statements. + let terminator = &self.body[location.block].terminator(); + debug!( + "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}", + target, terminator + ); + if let TerminatorKind::Call { destination: Some((place, _)), args, .. } = + &terminator.kind + { + if let Some(assigned_to) = place.as_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", + assigned_to, args + ); + for operand in args { + let assigned_from = match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from, + ); + + if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", + assigned_from_local, + ); + + if assigned_to == mir::RETURN_PLACE && assigned_from_local == target { + return annotated_closure.or_else(fallback); + } + } + } + } + } + } + + // If we haven't found an assignment into the return place, then we need not add + // any annotations. + debug!("annotate_argument_and_return_for_borrow: none found"); + None + } + + /// Annotate the first argument and return type of a function signature if they are + /// references. + fn annotate_fn_sig( + &self, + did: DefId, + sig: ty::PolyFnSig<'tcx>, + ) -> Option> { + debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); + let is_closure = self.infcx.tcx.is_closure(did); + let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did.as_local()?); + let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?; + + // We need to work out which arguments to highlight. We do this by looking + // at the return type, where there are three cases: + // + // 1. If there are named arguments, then we should highlight the return type and + // highlight any of the arguments that are also references with that lifetime. + // If there are no arguments that have the same lifetime as the return type, + // then don't highlight anything. + // 2. The return type is a reference with an anonymous lifetime. If this is + // the case, then we can take advantage of (and teach) the lifetime elision + // rules. + // + // We know that an error is being reported. So the arguments and return type + // must satisfy the elision rules. Therefore, if there is a single argument + // then that means the return type and first (and only) argument have the same + // lifetime and the borrow isn't meeting that, we can highlight the argument + // and return type. + // + // If there are multiple arguments then the first argument must be self (else + // it would not satisfy the elision rules), so we can highlight self and the + // return type. + // 3. The return type is not a reference. In this case, we don't highlight + // anything. + let return_ty = sig.output(); + match return_ty.skip_binder().kind() { + ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { + // This is case 1 from above, return type is a named reference so we need to + // search for relevant arguments. + let mut arguments = Vec::new(); + for (index, argument) in sig.inputs().skip_binder().iter().enumerate() { + if let ty::Ref(argument_region, _, _) = argument.kind() { + if argument_region == return_region { + // Need to use the `rustc_middle::ty` types to compare against the + // `return_region`. Then use the `rustc_hir` type to get only + // the lifetime span. + if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind { + // With access to the lifetime, we can get + // the span of it. + arguments.push((*argument, lifetime.span)); + } else { + bug!("ty type is a ref but hir type is not"); + } + } + } + } + + // We need to have arguments. This shouldn't happen, but it's worth checking. + if arguments.is_empty() { + return None; + } + + // We use a mix of the HIR and the Ty types to get information + // as the HIR doesn't have full types for closure arguments. + let return_ty = sig.output().skip_binder(); + let mut return_span = fn_decl.output.span(); + if let hir::FnRetTy::Return(ty) = &fn_decl.output { + if let hir::TyKind::Rptr(lifetime, _) = ty.kind { + return_span = lifetime.span; + } + } + + Some(AnnotatedBorrowFnSignature::NamedFunction { + arguments, + return_ty, + return_span, + }) + } + ty::Ref(_, _, _) if is_closure => { + // This is case 2 from above but only for closures, return type is anonymous + // reference so we select + // the first argument. + let argument_span = fn_decl.inputs.first()?.span; + let argument_ty = sig.inputs().skip_binder().first()?; + + // Closure arguments are wrapped in a tuple, so we need to get the first + // from that. + if let ty::Tuple(elems) = argument_ty.kind() { + let argument_ty = elems.first()?.expect_ty(); + if let ty::Ref(_, _, _) = argument_ty.kind() { + return Some(AnnotatedBorrowFnSignature::Closure { + argument_ty, + argument_span, + }); + } + } + + None + } + ty::Ref(_, _, _) => { + // This is also case 2 from above but for functions, return type is still an + // anonymous reference so we select the first argument. + let argument_span = fn_decl.inputs.first()?.span; + let argument_ty = sig.inputs().skip_binder().first()?; + + let return_span = fn_decl.output.span(); + let return_ty = sig.output().skip_binder(); + + // We expect the first argument to be a reference. + match argument_ty.kind() { + ty::Ref(_, _, _) => {} + _ => return None, + } + + Some(AnnotatedBorrowFnSignature::AnonymousFunction { + argument_ty, + argument_span, + return_ty, + return_span, + }) + } + _ => { + // This is case 3 from above, return type is not a reference so don't highlight + // anything. + None + } + } + } +} + +#[derive(Debug)] +enum AnnotatedBorrowFnSignature<'tcx> { + NamedFunction { + arguments: Vec<(Ty<'tcx>, Span)>, + return_ty: Ty<'tcx>, + return_span: Span, + }, + AnonymousFunction { + argument_ty: Ty<'tcx>, + argument_span: Span, + return_ty: Ty<'tcx>, + return_span: Span, + }, + Closure { + argument_ty: Ty<'tcx>, + argument_span: Span, + }, +} + +impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { + /// Annotate the provided diagnostic with information about borrow from the fn signature that + /// helps explain. + pub(crate) fn emit( + &self, + cx: &mut MirBorrowckCtxt<'_, 'tcx>, + diag: &mut DiagnosticBuilder<'_>, + ) -> String { + match self { + AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => { + diag.span_label( + *argument_span, + format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)), + ); + + cx.get_region_name_for_ty(argument_ty, 0) + } + AnnotatedBorrowFnSignature::AnonymousFunction { + argument_ty, + argument_span, + return_ty, + return_span, + } => { + let argument_ty_name = cx.get_name_for_ty(argument_ty, 0); + diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name)); + + let return_ty_name = cx.get_name_for_ty(return_ty, 0); + let types_equal = return_ty_name == argument_ty_name; + diag.span_label( + *return_span, + format!( + "{}has type `{}`", + if types_equal { "also " } else { "" }, + return_ty_name, + ), + ); + + diag.note( + "argument and return type have the same lifetime due to lifetime elision rules", + ); + diag.note( + "to learn more, visit ", + ); + + cx.get_region_name_for_ty(return_ty, 0) + } + AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => { + // Region of return type and arguments checked to be the same earlier. + let region_name = cx.get_region_name_for_ty(return_ty, 0); + for (_, argument_span) in arguments { + diag.span_label(*argument_span, format!("has lifetime `{}`", region_name)); + } + + diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,)); + + diag.help(&format!( + "use data from the highlighted arguments which match the `{}` lifetime of \ + the return type", + region_name, + )); + + region_name + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,744 @@ +//! Print diagnostics to explain why values are borrowed. + +use std::collections::VecDeque; + +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_index::vec::IndexVec; +use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_middle::mir::{ + Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue, + Statement, StatementKind, TerminatorKind, +}; +use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::{self, RegionVid, TyCtxt}; +use rustc_span::symbol::Symbol; +use rustc_span::Span; + +use crate::region_infer::BlameConstraint; +use crate::{ + borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt, + WriteKind, +}; + +use super::{find_use, RegionName, UseSpans}; + +#[derive(Debug)] +pub(crate) enum BorrowExplanation { + UsedLater(LaterUseKind, Span, Option), + UsedLaterInLoop(LaterUseKind, Span, Option), + UsedLaterWhenDropped { + drop_loc: Location, + dropped_local: Local, + should_note_order: bool, + }, + MustBeValidFor { + category: ConstraintCategory, + from_closure: bool, + span: Span, + region_name: RegionName, + opt_place_desc: Option, + }, + Unexplained, +} + +#[derive(Clone, Copy, Debug)] +pub(crate) enum LaterUseKind { + TraitCapture, + ClosureCapture, + Call, + FakeLetRead, + Other, +} + +impl BorrowExplanation { + pub(crate) fn is_explained(&self) -> bool { + match self { + BorrowExplanation::Unexplained => false, + _ => true, + } + } + pub(crate) fn add_explanation_to_diagnostic<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + local_names: &IndexVec>, + err: &mut DiagnosticBuilder<'_>, + borrow_desc: &str, + borrow_span: Option, + multiple_borrow_span: Option<(Span, Span)>, + ) { + match *self { + BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { + let message = match later_use_kind { + LaterUseKind::TraitCapture => "captured here by trait object", + LaterUseKind::ClosureCapture => "captured here by closure", + LaterUseKind::Call => "used by call", + LaterUseKind::FakeLetRead => "stored here", + LaterUseKind::Other => "used here", + }; + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { + if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, message), + ); + } + } else { + // path_span must be `Some` as otherwise the if condition is true + let path_span = path_span.unwrap(); + // path_span is only present in the case of closure capture + assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); + if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { + let path_label = "used here by closure"; + let capture_kind_label = message; + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, capture_kind_label), + ); + err.span_label(path_span, path_label); + } + } + } + BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => { + let message = match later_use_kind { + LaterUseKind::TraitCapture => { + "borrow captured here by trait object, in later iteration of loop" + } + LaterUseKind::ClosureCapture => { + "borrow captured here by closure, in later iteration of loop" + } + LaterUseKind::Call => "borrow used by call, in later iteration of loop", + LaterUseKind::FakeLetRead => "borrow later stored here", + LaterUseKind::Other => "borrow used here, in later iteration of loop", + }; + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { + err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); + } else { + // path_span must be `Some` as otherwise the if condition is true + let path_span = path_span.unwrap(); + // path_span is only present in the case of closure capture + assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); + if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { + let path_label = "used here by closure"; + let capture_kind_label = message; + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, capture_kind_label), + ); + err.span_label(path_span, path_label); + } + } + } + BorrowExplanation::UsedLaterWhenDropped { + drop_loc, + dropped_local, + should_note_order, + } => { + let local_decl = &body.local_decls[dropped_local]; + let (dtor_desc, type_desc) = match local_decl.ty.kind() { + // If type is an ADT that implements Drop, then + // simplify output by reporting just the ADT name. + ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => { + ("`Drop` code", format!("type `{}`", tcx.def_path_str(adt.did))) + } + + // Otherwise, just report the whole type (and use + // the intentionally fuzzy phrase "destructor") + ty::Closure(..) => ("destructor", "closure".to_owned()), + ty::Generator(..) => ("destructor", "generator".to_owned()), + + _ => ("destructor", format!("type `{}`", local_decl.ty)), + }; + + match local_names[dropped_local] { + Some(local_name) if !local_decl.from_compiler_desugaring() => { + let message = format!( + "{B}borrow might be used here, when `{LOC}` is dropped \ + and runs the {DTOR} for {TYPE}", + B = borrow_desc, + LOC = local_name, + TYPE = type_desc, + DTOR = dtor_desc + ); + err.span_label(body.source_info(drop_loc).span, message); + + if should_note_order { + err.note( + "values in a scope are dropped \ + in the opposite order they are defined", + ); + } + } + _ => { + err.span_label( + local_decl.source_info.span, + format!( + "a temporary with access to the {B}borrow \ + is created here ...", + B = borrow_desc + ), + ); + let message = format!( + "... and the {B}borrow might be used here, \ + when that temporary is dropped \ + and runs the {DTOR} for {TYPE}", + B = borrow_desc, + TYPE = type_desc, + DTOR = dtor_desc + ); + err.span_label(body.source_info(drop_loc).span, message); + + if let Some(info) = &local_decl.is_block_tail { + if info.tail_result_is_ignored { + // #85581: If the first mutable borrow's scope contains + // the second borrow, this suggestion isn't helpful. + if !multiple_borrow_span + .map(|(old, new)| { + old.to(info.span.shrink_to_hi()).contains(new) + }) + .unwrap_or(false) + { + err.span_suggestion_verbose( + info.span.shrink_to_hi(), + "consider adding semicolon after the expression so its \ + temporaries are dropped sooner, before the local variables \ + declared by the block are dropped", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + } + } else { + err.note( + "the temporary is part of an expression at the end of a \ + block;\nconsider forcing this temporary to be dropped sooner, \ + before the block's local variables are dropped", + ); + err.multipart_suggestion( + "for example, you could save the expression's value in a new \ + local variable `x` and then make `x` be the expression at the \ + end of the block", + vec![ + (info.span.shrink_to_lo(), "let x = ".to_string()), + (info.span.shrink_to_hi(), "; x".to_string()), + ], + Applicability::MaybeIncorrect, + ); + }; + } + } + } + } + BorrowExplanation::MustBeValidFor { + category, + span, + ref region_name, + ref opt_place_desc, + from_closure: _, + } => { + region_name.highlight_region_name(err); + + if let Some(desc) = opt_place_desc { + err.span_label( + span, + format!( + "{}requires that `{}` is borrowed for `{}`", + category.description(), + desc, + region_name, + ), + ); + } else { + err.span_label( + span, + format!( + "{}requires that {}borrow lasts for `{}`", + category.description(), + borrow_desc, + region_name, + ), + ); + }; + + self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); + } + _ => {} + } + } + pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic( + &self, + err: &mut DiagnosticBuilder<'_>, + category: &ConstraintCategory, + span: Span, + region_name: &RegionName, + ) { + if let ConstraintCategory::OpaqueType = category { + let suggestable_name = + if region_name.was_named() { region_name.to_string() } else { "'_".to_string() }; + + let msg = format!( + "you can add a bound to the {}to make it last less than `'static` and match `{}`", + category.description(), + region_name, + ); + + err.span_suggestion_verbose( + span.shrink_to_hi(), + &msg, + format!(" + {}", suggestable_name), + Applicability::Unspecified, + ); + } + } +} + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + fn free_region_constraint_info( + &self, + borrow_region: RegionVid, + outlived_region: RegionVid, + ) -> (ConstraintCategory, bool, Span, Option) { + let BlameConstraint { category, from_closure, cause, variance_info: _ } = + self.regioncx.best_blame_constraint( + &self.body, + borrow_region, + NllRegionVariableOrigin::FreeRegion, + |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), + ); + + let outlived_fr_name = self.give_region_a_name(outlived_region); + + (category, from_closure, cause.span, outlived_fr_name) + } + + /// Returns structured explanation for *why* the borrow contains the + /// point from `location`. This is key for the "3-point errors" + /// [described in the NLL RFC][d]. + /// + /// # Parameters + /// + /// - `borrow`: the borrow in question + /// - `location`: where the borrow occurs + /// - `kind_place`: if Some, this describes the statement that triggered the error. + /// - first half is the kind of write, if any, being performed + /// - second half is the place being accessed + /// + /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points + pub(crate) fn explain_why_borrow_contains_point( + &self, + location: Location, + borrow: &BorrowData<'tcx>, + kind_place: Option<(WriteKind, Place<'tcx>)>, + ) -> BorrowExplanation { + debug!( + "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})", + location, borrow, kind_place + ); + + let regioncx = &self.regioncx; + let body: &Body<'_> = &self.body; + let tcx = self.infcx.tcx; + + let borrow_region_vid = borrow.region; + debug!("explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid); + + let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location); + debug!("explain_why_borrow_contains_point: region_sub={:?}", region_sub); + + match find_use::find(body, regioncx, tcx, region_sub, location) { + Some(Cause::LiveVar(local, location)) => { + let span = body.source_info(location).span; + let spans = self + .move_spans(Place::from(local).as_ref(), location) + .or_else(|| self.borrow_spans(span, location)); + + let borrow_location = location; + if self.is_use_in_later_iteration_of_loop(borrow_location, location) { + let later_use = self.later_use_kind(borrow, spans, location); + BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2) + } else { + // Check if the location represents a `FakeRead`, and adapt the error + // message to the `FakeReadCause` it is from: in particular, + // the ones inserted in optimized `let var = ` patterns. + let later_use = self.later_use_kind(borrow, spans, location); + BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2) + } + } + + Some(Cause::DropVar(local, location)) => { + let mut should_note_order = false; + if self.local_names[local].is_some() { + if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { + if let Some(borrowed_local) = place.as_local() { + if self.local_names[borrowed_local].is_some() && local != borrowed_local + { + should_note_order = true; + } + } + } + } + + BorrowExplanation::UsedLaterWhenDropped { + drop_loc: location, + dropped_local: local, + should_note_order, + } + } + + None => { + if let Some(region) = self.to_error_region_vid(borrow_region_vid) { + let (category, from_closure, span, region_name) = + self.free_region_constraint_info(borrow_region_vid, region); + if let Some(region_name) = region_name { + let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref()); + BorrowExplanation::MustBeValidFor { + category, + from_closure, + span, + region_name, + opt_place_desc, + } + } else { + debug!( + "explain_why_borrow_contains_point: \ + Could not generate a region name" + ); + BorrowExplanation::Unexplained + } + } else { + debug!( + "explain_why_borrow_contains_point: \ + Could not generate an error region vid" + ); + BorrowExplanation::Unexplained + } + } + } + } + + /// true if `borrow_location` can reach `use_location` by going through a loop and + /// `use_location` is also inside of that loop + fn is_use_in_later_iteration_of_loop( + &self, + borrow_location: Location, + use_location: Location, + ) -> bool { + let back_edge = self.reach_through_backedge(borrow_location, use_location); + back_edge.map_or(false, |back_edge| self.can_reach_head_of_loop(use_location, back_edge)) + } + + /// Returns the outmost back edge if `from` location can reach `to` location passing through + /// that back edge + fn reach_through_backedge(&self, from: Location, to: Location) -> Option { + let mut visited_locations = FxHashSet::default(); + let mut pending_locations = VecDeque::new(); + visited_locations.insert(from); + pending_locations.push_back(from); + debug!("reach_through_backedge: from={:?} to={:?}", from, to,); + + let mut outmost_back_edge = None; + while let Some(location) = pending_locations.pop_front() { + debug!( + "reach_through_backedge: location={:?} outmost_back_edge={:?} + pending_locations={:?} visited_locations={:?}", + location, outmost_back_edge, pending_locations, visited_locations + ); + + if location == to && outmost_back_edge.is_some() { + // We've managed to reach the use location + debug!("reach_through_backedge: found!"); + return outmost_back_edge; + } + + let block = &self.body.basic_blocks()[location.block]; + + if location.statement_index < block.statements.len() { + let successor = location.successor_within_block(); + if visited_locations.insert(successor) { + pending_locations.push_back(successor); + } + } else { + pending_locations.extend( + block + .terminator() + .successors() + .map(|bb| Location { statement_index: 0, block: *bb }) + .filter(|s| visited_locations.insert(*s)) + .map(|s| { + if self.is_back_edge(location, s) { + match outmost_back_edge { + None => { + outmost_back_edge = Some(location); + } + + Some(back_edge) + if location.dominates(back_edge, &self.dominators) => + { + outmost_back_edge = Some(location); + } + + Some(_) => {} + } + } + + s + }), + ); + } + } + + None + } + + /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the + /// intermediate nodes + fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool { + self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default()) + } + + fn find_loop_head_dfs( + &self, + from: Location, + loop_head: Location, + visited_locations: &mut FxHashSet, + ) -> bool { + visited_locations.insert(from); + + if from == loop_head { + return true; + } + + if loop_head.dominates(from, &self.dominators) { + let block = &self.body.basic_blocks()[from.block]; + + if from.statement_index < block.statements.len() { + let successor = from.successor_within_block(); + + if !visited_locations.contains(&successor) + && self.find_loop_head_dfs(successor, loop_head, visited_locations) + { + return true; + } + } else { + for bb in block.terminator().successors() { + let successor = Location { statement_index: 0, block: *bb }; + + if !visited_locations.contains(&successor) + && self.find_loop_head_dfs(successor, loop_head, visited_locations) + { + return true; + } + } + } + } + + false + } + + /// True if an edge `source -> target` is a backedge -- in other words, if the target + /// dominates the source. + fn is_back_edge(&self, source: Location, target: Location) -> bool { + target.dominates(source, &self.dominators) + } + + /// Determine how the borrow was later used. + /// First span returned points to the location of the conflicting use + /// Second span if `Some` is returned in the case of closures and points + /// to the use of the path + fn later_use_kind( + &self, + borrow: &BorrowData<'tcx>, + use_spans: UseSpans<'tcx>, + location: Location, + ) -> (LaterUseKind, Span, Option) { + match use_spans { + UseSpans::ClosureUse { capture_kind_span, path_span, .. } => { + // Used in a closure. + (LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span)) + } + UseSpans::PatUse(span) + | UseSpans::OtherUse(span) + | UseSpans::FnSelfUse { var_span: span, .. } => { + let block = &self.body.basic_blocks()[location.block]; + + let kind = if let Some(&Statement { + kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)), + .. + }) = block.statements.get(location.statement_index) + { + LaterUseKind::FakeLetRead + } else if self.was_captured_by_trait_object(borrow) { + LaterUseKind::TraitCapture + } else if location.statement_index == block.statements.len() { + if let TerminatorKind::Call { ref func, from_hir_call: true, .. } = + block.terminator().kind + { + // Just point to the function, to reduce the chance of overlapping spans. + let function_span = match func { + Operand::Constant(c) => c.span, + Operand::Copy(place) | Operand::Move(place) => { + if let Some(l) = place.as_local() { + let local_decl = &self.body.local_decls[l]; + if self.local_names[l].is_none() { + local_decl.source_info.span + } else { + span + } + } else { + span + } + } + }; + return (LaterUseKind::Call, function_span, None); + } else { + LaterUseKind::Other + } + } else { + LaterUseKind::Other + }; + + (kind, span, None) + } + } + } + + /// Checks if a borrowed value was captured by a trait object. We do this by + /// looking forward in the MIR from the reserve location and checking if we see + /// an unsized cast to a trait object on our data. + fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { + // Start at the reserve location, find the place that we want to see cast to a trait object. + let location = borrow.reserve_location; + let block = &self.body[location.block]; + let stmt = block.statements.get(location.statement_index); + debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt); + + // We make a `queue` vector that has the locations we want to visit. As of writing, this + // will only ever have one item at any given time, but by using a vector, we can pop from + // it which simplifies the termination logic. + let mut queue = vec![location]; + let mut target = if let Some(&Statement { + kind: StatementKind::Assign(box (ref place, _)), + .. + }) = stmt + { + if let Some(local) = place.as_local() { + local + } else { + return false; + } + } else { + return false; + }; + + debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); + while let Some(current_location) = queue.pop() { + debug!("was_captured_by_trait: target={:?}", target); + let block = &self.body[current_location.block]; + // We need to check the current location to find out if it is a terminator. + let is_terminator = current_location.statement_index == block.statements.len(); + if !is_terminator { + let stmt = &block.statements[current_location.statement_index]; + debug!("was_captured_by_trait_object: stmt={:?}", stmt); + + // The only kind of statement that we care about is assignments... + if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind { + let into = match place.local_or_deref_local() { + Some(into) => into, + None => { + // Continue at the next location. + queue.push(current_location.successor_within_block()); + continue; + } + }; + + match rvalue { + // If we see a use, we should check whether it is our data, and if so + // update the place that we're looking for to that new place. + Rvalue::Use(operand) => match operand { + Operand::Copy(place) | Operand::Move(place) => { + if let Some(from) = place.as_local() { + if from == target { + target = into; + } + } + } + _ => {} + }, + // If we see an unsized cast, then if it is our data we should check + // whether it is being cast to a trait object. + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, ty) => { + match operand { + Operand::Copy(place) | Operand::Move(place) => { + if let Some(from) = place.as_local() { + if from == target { + debug!("was_captured_by_trait_object: ty={:?}", ty); + // Check the type for a trait object. + return match ty.kind() { + // `&dyn Trait` + ty::Ref(_, ty, _) if ty.is_trait() => true, + // `Box` + _ if ty.is_box() && ty.boxed_ty().is_trait() => { + true + } + // `dyn Trait` + _ if ty.is_trait() => true, + // Anything else. + _ => false, + }; + } + } + return false; + } + _ => return false, + } + } + _ => {} + } + } + + // Continue at the next location. + queue.push(current_location.successor_within_block()); + } else { + // The only thing we need to do for terminators is progress to the next block. + let terminator = block.terminator(); + debug!("was_captured_by_trait_object: terminator={:?}", terminator); + + if let TerminatorKind::Call { destination: Some((place, block)), args, .. } = + &terminator.kind + { + if let Some(dest) = place.as_local() { + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + // Check if one of the arguments to this function is the target place. + let found_target = args.iter().any(|arg| { + if let Operand::Move(place) = arg { + if let Some(potential) = place.as_local() { + potential == target + } else { + false + } + } else { + false + } + }); + + // If it is, follow this to the next block and update the target. + if found_target { + target = dest; + queue.push(block.start_location()); + } + } + } + } + + debug!("was_captured_by_trait: queue={:?}", queue); + } + + // We didn't find anything and ran out of locations to check. + false + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/find_use.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/find_use.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/find_use.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/find_use.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,128 @@ +use std::collections::VecDeque; +use std::rc::Rc; + +use crate::{ + def_use::{self, DefUse}, + nll::ToRegionVid, + region_infer::{Cause, RegionInferenceContext}, +}; +use rustc_data_structures::fx::FxHashSet; +use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location}; +use rustc_middle::ty::{RegionVid, TyCtxt}; + +crate fn find<'tcx>( + body: &Body<'tcx>, + regioncx: &Rc>, + tcx: TyCtxt<'tcx>, + region_vid: RegionVid, + start_point: Location, +) -> Option { + let mut uf = UseFinder { body, regioncx, tcx, region_vid, start_point }; + + uf.find() +} + +struct UseFinder<'cx, 'tcx> { + body: &'cx Body<'tcx>, + regioncx: &'cx Rc>, + tcx: TyCtxt<'tcx>, + region_vid: RegionVid, + start_point: Location, +} + +impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { + fn find(&mut self) -> Option { + let mut queue = VecDeque::new(); + let mut visited = FxHashSet::default(); + + queue.push_back(self.start_point); + while let Some(p) = queue.pop_front() { + if !self.regioncx.region_contains(self.region_vid, p) { + continue; + } + + if !visited.insert(p) { + continue; + } + + let block_data = &self.body[p.block]; + + match self.def_use(p, block_data.visitable(p.statement_index)) { + Some(DefUseResult::Def) => {} + + Some(DefUseResult::UseLive { local }) => { + return Some(Cause::LiveVar(local, p)); + } + + Some(DefUseResult::UseDrop { local }) => { + return Some(Cause::DropVar(local, p)); + } + + None => { + if p.statement_index < block_data.statements.len() { + queue.push_back(p.successor_within_block()); + } else { + queue.extend( + block_data + .terminator() + .successors() + .filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind()) + .map(|&bb| Location { statement_index: 0, block: bb }), + ); + } + } + } + } + + None + } + + fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option { + let mut visitor = DefUseVisitor { + body: self.body, + tcx: self.tcx, + region_vid: self.region_vid, + def_use_result: None, + }; + + thing.apply(location, &mut visitor); + + visitor.def_use_result + } +} + +struct DefUseVisitor<'cx, 'tcx> { + body: &'cx Body<'tcx>, + tcx: TyCtxt<'tcx>, + region_vid: RegionVid, + def_use_result: Option, +} + +enum DefUseResult { + Def, + UseLive { local: Local }, + UseDrop { local: Local }, +} + +impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + let local_ty = self.body.local_decls[local].ty; + + let mut found_it = false; + self.tcx.for_each_free_region(&local_ty, |r| { + if r.to_region_vid() == self.region_vid { + found_it = true; + } + }); + + if found_it { + self.def_use_result = match def_use::categorize(context) { + Some(DefUse::Def) => Some(DefUseResult::Def), + Some(DefUse::Use) => Some(DefUseResult::UseLive { local }), + Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }), + None => None, + }; + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1098 @@ +//! Borrow checker diagnostics. + +use rustc_errors::DiagnosticBuilder; +use rustc_hir as hir; +use rustc_hir::def::Namespace; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItemGroup; +use rustc_hir::GeneratorKind; +use rustc_middle::mir::{ + AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand, + Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, +}; +use rustc_middle::ty::print::Print; +use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; +use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; +use rustc_span::{ + hygiene::{DesugaringKind, ForLoopLoc}, + symbol::sym, + Span, +}; +use rustc_target::abi::VariantIdx; + +use super::borrow_set::BorrowData; +use super::MirBorrowckCtxt; + +mod find_use; +mod outlives_suggestion; +mod region_name; +mod var_name; + +mod bound_region_errors; +mod conflict_errors; +mod explain_borrow; +mod move_errors; +mod mutability_errors; +mod region_errors; + +crate use bound_region_errors::{ToUniverseInfo, UniverseInfo}; +crate use mutability_errors::AccessKind; +crate use outlives_suggestion::OutlivesSuggestionBuilder; +crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; +crate use region_name::{RegionName, RegionNameSource}; +use rustc_span::symbol::Ident; + +pub(super) struct IncludingDowncast(pub(super) bool); + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure + /// is moved after being invoked. + /// + /// ```text + /// note: closure cannot be invoked more than once because it moves the variable `dict` out of + /// its environment + /// --> $DIR/issue-42065.rs:16:29 + /// | + /// LL | for (key, value) in dict { + /// | ^^^^ + /// ``` + pub(super) fn add_moved_or_invoked_closure_note( + &self, + location: Location, + place: PlaceRef<'tcx>, + diag: &mut DiagnosticBuilder<'_>, + ) { + debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); + let mut target = place.local_or_deref_local(); + for stmt in &self.body[location.block].statements[location.statement_index..] { + debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target); + if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind { + debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from); + match from { + Operand::Copy(ref place) | Operand::Move(ref place) + if target == place.local_or_deref_local() => + { + target = into.local_or_deref_local() + } + _ => {} + } + } + } + + // Check if we are attempting to call a closure after it has been invoked. + let terminator = self.body[location.block].terminator(); + debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); + if let TerminatorKind::Call { + func: Operand::Constant(box Constant { literal, .. }), + args, + .. + } = &terminator.kind + { + if let ty::FnDef(id, _) = *literal.ty().kind() { + debug!("add_moved_or_invoked_closure_note: id={:?}", id); + if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { + let closure = match args.first() { + Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place)) + if target == place.local_or_deref_local() => + { + place.local_or_deref_local().unwrap() + } + _ => return, + }; + + debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); + if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { + let did = did.expect_local(); + let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); + + if let Some((span, hir_place)) = + self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) + { + diag.span_note( + *span, + &format!( + "closure cannot be invoked more than once because it moves the \ + variable `{}` out of its environment", + ty::place_to_string_for_capture(self.infcx.tcx, hir_place) + ), + ); + return; + } + } + } + } + } + + // Check if we are just moving a closure after it has been invoked. + if let Some(target) = target { + if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { + let did = did.expect_local(); + let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); + + if let Some((span, hir_place)) = + self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) + { + diag.span_note( + *span, + &format!( + "closure cannot be moved more than once as it is not `Copy` due to \ + moving the variable `{}` out of its environment", + ty::place_to_string_for_capture(self.infcx.tcx, hir_place) + ), + ); + } + } + } + } + + /// End-user visible description of `place` if one can be found. + /// If the place is a temporary for instance, `"value"` will be returned. + pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String { + match self.describe_place(place_ref) { + Some(mut descr) => { + // Surround descr with `backticks`. + descr.reserve(2); + descr.insert(0, '`'); + descr.push('`'); + descr + } + None => "value".to_string(), + } + } + + /// End-user visible description of `place` if one can be found. + /// If the place is a temporary for instance, None will be returned. + pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option { + self.describe_place_with_options(place_ref, IncludingDowncast(false)) + } + + /// End-user visible description of `place` if one can be found. If the + /// place is a temporary for instance, None will be returned. + /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is + /// `Downcast` and `IncludingDowncast` is true + pub(super) fn describe_place_with_options( + &self, + place: PlaceRef<'tcx>, + including_downcast: IncludingDowncast, + ) -> Option { + let mut buf = String::new(); + match self.append_place_to_string(place, &mut buf, false, &including_downcast) { + Ok(()) => Some(buf), + Err(()) => None, + } + } + + /// Appends end-user visible description of `place` to `buf`. + fn append_place_to_string( + &self, + place: PlaceRef<'tcx>, + buf: &mut String, + mut autoderef: bool, + including_downcast: &IncludingDowncast, + ) -> Result<(), ()> { + match place { + PlaceRef { local, projection: [] } => { + self.append_local_to_string(local, buf)?; + } + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[local].is_ref_for_guard() => + { + self.append_place_to_string( + PlaceRef { local, projection: &[] }, + buf, + autoderef, + &including_downcast, + )?; + } + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[local].is_ref_to_static() => + { + let local_info = &self.body.local_decls[local].local_info; + if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { + buf.push_str(&self.infcx.tcx.item_name(def_id).as_str()); + } else { + unreachable!(); + } + } + PlaceRef { local, projection: [proj_base @ .., elem] } => { + match elem { + ProjectionElem::Deref => { + let upvar_field_projection = self.is_upvar_field_projection(place); + if let Some(field) = upvar_field_projection { + let var_index = field.index(); + let name = self.upvars[var_index].place.to_string(self.infcx.tcx); + if self.upvars[var_index].by_ref { + buf.push_str(&name); + } else { + buf.push('*'); + buf.push_str(&name); + } + } else { + if autoderef { + // FIXME turn this recursion into iteration + self.append_place_to_string( + PlaceRef { local, projection: proj_base }, + buf, + autoderef, + &including_downcast, + )?; + } else { + buf.push('*'); + self.append_place_to_string( + PlaceRef { local, projection: proj_base }, + buf, + autoderef, + &including_downcast, + )?; + } + } + } + ProjectionElem::Downcast(..) => { + self.append_place_to_string( + PlaceRef { local, projection: proj_base }, + buf, + autoderef, + &including_downcast, + )?; + if including_downcast.0 { + return Err(()); + } + } + ProjectionElem::Field(field, _ty) => { + autoderef = true; + + // FIXME(project-rfc_2229#36): print capture precisely here. + let upvar_field_projection = self.is_upvar_field_projection(place); + if let Some(field) = upvar_field_projection { + let var_index = field.index(); + let name = self.upvars[var_index].place.to_string(self.infcx.tcx); + buf.push_str(&name); + } else { + let field_name = self + .describe_field(PlaceRef { local, projection: proj_base }, *field); + self.append_place_to_string( + PlaceRef { local, projection: proj_base }, + buf, + autoderef, + &including_downcast, + )?; + buf.push('.'); + buf.push_str(&field_name); + } + } + ProjectionElem::Index(index) => { + autoderef = true; + + self.append_place_to_string( + PlaceRef { local, projection: proj_base }, + buf, + autoderef, + &including_downcast, + )?; + buf.push('['); + if self.append_local_to_string(*index, buf).is_err() { + buf.push('_'); + } + buf.push(']'); + } + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { + autoderef = true; + // Since it isn't possible to borrow an element on a particular index and + // then use another while the borrow is held, don't output indices details + // to avoid confusing the end-user + self.append_place_to_string( + PlaceRef { local, projection: proj_base }, + buf, + autoderef, + &including_downcast, + )?; + buf.push_str("[..]"); + } + }; + } + } + + Ok(()) + } + + /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have + /// a name, or its name was generated by the compiler, then `Err` is returned + fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> { + let decl = &self.body.local_decls[local]; + match self.local_names[local] { + Some(name) if !decl.from_compiler_desugaring() => { + buf.push_str(&name.as_str()); + Ok(()) + } + _ => Err(()), + } + } + + /// End-user visible description of the `field`nth field of `base` + fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String { + // FIXME Place2 Make this work iteratively + match place { + PlaceRef { local, projection: [] } => { + let local = &self.body.local_decls[local]; + self.describe_field_from_ty(&local.ty, field, None) + } + PlaceRef { local, projection: [proj_base @ .., elem] } => match elem { + ProjectionElem::Deref => { + self.describe_field(PlaceRef { local, projection: proj_base }, field) + } + ProjectionElem::Downcast(_, variant_index) => { + let base_ty = place.ty(self.body, self.infcx.tcx).ty; + self.describe_field_from_ty(&base_ty, field, Some(*variant_index)) + } + ProjectionElem::Field(_, field_type) => { + self.describe_field_from_ty(&field_type, field, None) + } + ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => { + self.describe_field(PlaceRef { local, projection: proj_base }, field) + } + }, + } + } + + /// End-user visible description of the `field_index`nth field of `ty` + fn describe_field_from_ty( + &self, + ty: Ty<'_>, + field: Field, + variant_index: Option, + ) -> String { + if ty.is_box() { + // If the type is a box, the field is described from the boxed type + self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index) + } else { + match *ty.kind() { + ty::Adt(def, _) => { + let variant = if let Some(idx) = variant_index { + assert!(def.is_enum()); + &def.variants[idx] + } else { + def.non_enum_variant() + }; + variant.fields[field.index()].ident.to_string() + } + ty::Tuple(_) => field.index().to_string(), + ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { + self.describe_field_from_ty(&ty, field, variant_index) + } + ty::Array(ty, _) | ty::Slice(ty) => { + self.describe_field_from_ty(&ty, field, variant_index) + } + ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { + // We won't be borrowck'ing here if the closure came from another crate, + // so it's safe to call `expect_local`. + // + // We know the field exists so it's safe to call operator[] and `unwrap` here. + let var_id = self + .infcx + .tcx + .typeck(def_id.expect_local()) + .closure_min_captures_flattened(def_id) + .nth(field.index()) + .unwrap() + .get_root_variable(); + + self.infcx.tcx.hir().name(var_id).to_string() + } + _ => { + // Might need a revision when the fields in trait RFC is implemented + // (https://github.com/rust-lang/rfcs/pull/1546) + bug!("End-user description not implemented for field access on `{:?}`", ty); + } + } + } + } + + /// Add a note that a type does not implement `Copy` + pub(super) fn note_type_does_not_implement_copy( + &self, + err: &mut DiagnosticBuilder<'a>, + place_desc: &str, + ty: Ty<'tcx>, + span: Option, + move_prefix: &str, + ) { + let message = format!( + "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait", + move_prefix, place_desc, ty, + ); + if let Some(span) = span { + err.span_label(span, message); + } else { + err.note(&message); + } + } + + pub(super) fn borrowed_content_source( + &self, + deref_base: PlaceRef<'tcx>, + ) -> BorrowedContentSource<'tcx> { + let tcx = self.infcx.tcx; + + // Look up the provided place and work out the move path index for it, + // we'll use this to check whether it was originally from an overloaded + // operator. + match self.move_data.rev_lookup.find(deref_base) { + LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => { + debug!("borrowed_content_source: mpi={:?}", mpi); + + for i in &self.move_data.init_path_map[mpi] { + let init = &self.move_data.inits[*i]; + debug!("borrowed_content_source: init={:?}", init); + // We're only interested in statements that initialized a value, not the + // initializations from arguments. + let loc = match init.location { + InitLocation::Statement(stmt) => stmt, + _ => continue, + }; + + let bbd = &self.body[loc.block]; + let is_terminator = bbd.statements.len() == loc.statement_index; + debug!( + "borrowed_content_source: loc={:?} is_terminator={:?}", + loc, is_terminator, + ); + if !is_terminator { + continue; + } else if let Some(Terminator { + kind: TerminatorKind::Call { ref func, from_hir_call: false, .. }, + .. + }) = bbd.terminator + { + if let Some(source) = + BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx) + { + return source; + } + } + } + } + // Base is a `static` so won't be from an overloaded operator + _ => (), + }; + + // If we didn't find an overloaded deref or index, then assume it's a + // built in deref and check the type of the base. + let base_ty = deref_base.ty(self.body, tcx).ty; + if base_ty.is_unsafe_ptr() { + BorrowedContentSource::DerefRawPointer + } else if base_ty.is_mutable_ptr() { + BorrowedContentSource::DerefMutableRef + } else { + BorrowedContentSource::DerefSharedRef + } + } +} + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime + /// name where required. + pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); + + // We need to add synthesized lifetimes where appropriate. We do + // this by hooking into the pretty printer and telling it to label the + // lifetimes without names with the value `'0`. + match ty.kind() { + ty::Ref( + ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. }) + | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), + _, + _, + ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter), + _ => {} + } + + let _ = ty.print(printer); + s + } + + /// Returns the name of the provided `Ty` (that must be a reference)'s region with a + /// synthesized lifetime name where required. + pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); + + let region = match ty.kind() { + ty::Ref(region, _, _) => { + match region { + ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. }) + | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { + printer.region_highlight_mode.highlighting_bound_region(*br, counter) + } + _ => {} + } + + region + } + _ => bug!("ty for annotation of borrow region is not a reference"), + }; + + let _ = region.print(printer); + s + } +} + +/// The span(s) associated to a use of a place. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(super) enum UseSpans<'tcx> { + /// The access is caused by capturing a variable for a closure. + ClosureUse { + /// This is true if the captured variable was from a generator. + generator_kind: Option, + /// The span of the args of the closure, including the `move` keyword if + /// it's present. + args_span: Span, + /// The span of the use resulting in capture kind + /// Check `ty::CaptureInfo` for more details + capture_kind_span: Span, + /// The span of the use resulting in the captured path + /// Check `ty::CaptureInfo` for more details + path_span: Span, + }, + /// The access is caused by using a variable as the receiver of a method + /// that takes 'self' + FnSelfUse { + /// The span of the variable being moved + var_span: Span, + /// The span of the method call on the variable + fn_call_span: Span, + /// The definition span of the method being called + fn_span: Span, + kind: FnSelfUseKind<'tcx>, + }, + /// This access is caused by a `match` or `if let` pattern. + PatUse(Span), + /// This access has a single span associated to it: common case. + OtherUse(Span), +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(super) enum FnSelfUseKind<'tcx> { + /// A normal method call of the form `receiver.foo(a, b, c)` + Normal { + self_arg: Ident, + implicit_into_iter: bool, + /// Whether the self type of the method call has an `.as_ref()` method. + /// Used for better diagnostics. + is_option_or_result: bool, + }, + /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` + FnOnceCall, + /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) + Operator { self_arg: Ident }, + DerefCoercion { + /// The `Span` of the `Target` associated type + /// in the `Deref` impl we are using. + deref_target: Span, + /// The type `T::Deref` we are dereferencing to + deref_target_ty: Ty<'tcx>, + }, +} + +impl UseSpans<'_> { + pub(super) fn args_or_use(self) -> Span { + match self { + UseSpans::ClosureUse { args_span: span, .. } + | UseSpans::PatUse(span) + | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, + } + } + + /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span` + pub(super) fn var_or_use_path_span(self) -> Span { + match self { + UseSpans::ClosureUse { path_span: span, .. } + | UseSpans::PatUse(span) + | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, + } + } + + /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span` + pub(super) fn var_or_use(self) -> Span { + match self { + UseSpans::ClosureUse { capture_kind_span: span, .. } + | UseSpans::PatUse(span) + | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, + } + } + + pub(super) fn generator_kind(self) -> Option { + match self { + UseSpans::ClosureUse { generator_kind, .. } => generator_kind, + _ => None, + } + } + + // Add a span label to the arguments of the closure, if it exists. + pub(super) fn args_span_label( + self, + err: &mut DiagnosticBuilder<'_>, + message: impl Into, + ) { + if let UseSpans::ClosureUse { args_span, .. } = self { + err.span_label(args_span, message); + } + } + + // Add a span label to the use of the captured variable, if it exists. + // only adds label to the `path_span` + pub(super) fn var_span_label_path_only( + self, + err: &mut DiagnosticBuilder<'_>, + message: impl Into, + ) { + if let UseSpans::ClosureUse { path_span, .. } = self { + err.span_label(path_span, message); + } + } + + // Add a span label to the use of the captured variable, if it exists. + pub(super) fn var_span_label( + self, + err: &mut DiagnosticBuilder<'_>, + message: impl Into, + kind_desc: impl Into, + ) { + if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self { + if capture_kind_span == path_span { + err.span_label(capture_kind_span, message); + } else { + let capture_kind_label = + format!("capture is {} because of use here", kind_desc.into()); + let path_label = message; + err.span_label(capture_kind_span, capture_kind_label); + err.span_label(path_span, path_label); + } + } + } + + /// Returns `false` if this place is not used in a closure. + pub(super) fn for_closure(&self) -> bool { + match *self { + UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(), + _ => false, + } + } + + /// Returns `false` if this place is not used in a generator. + pub(super) fn for_generator(&self) -> bool { + match *self { + UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(), + _ => false, + } + } + + /// Describe the span associated with a use of a place. + pub(super) fn describe(&self) -> String { + match *self { + UseSpans::ClosureUse { generator_kind, .. } => { + if generator_kind.is_some() { + " in generator".to_string() + } else { + " in closure".to_string() + } + } + _ => String::new(), + } + } + + pub(super) fn or_else(self, if_other: F) -> Self + where + F: FnOnce() -> Self, + { + match self { + closure @ UseSpans::ClosureUse { .. } => closure, + UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(), + fn_self @ UseSpans::FnSelfUse { .. } => fn_self, + } + } +} + +pub(super) enum BorrowedContentSource<'tcx> { + DerefRawPointer, + DerefMutableRef, + DerefSharedRef, + OverloadedDeref(Ty<'tcx>), + OverloadedIndex(Ty<'tcx>), +} + +impl BorrowedContentSource<'tcx> { + pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String { + match *self { + BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(), + BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(), + BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(), + BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { + "an `Rc`".to_string() + } + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { + "an `Arc`".to_string() + } + _ => format!("dereference of `{}`", ty), + }, + BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty), + } + } + + pub(super) fn describe_for_named_place(&self) -> Option<&'static str> { + match *self { + BorrowedContentSource::DerefRawPointer => Some("raw pointer"), + BorrowedContentSource::DerefSharedRef => Some("shared reference"), + BorrowedContentSource::DerefMutableRef => Some("mutable reference"), + // Overloaded deref and index operators should be evaluated into a + // temporary. So we don't need a description here. + BorrowedContentSource::OverloadedDeref(_) + | BorrowedContentSource::OverloadedIndex(_) => None, + } + } + + pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String { + match *self { + BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(), + BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(), + BorrowedContentSource::DerefMutableRef => { + bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") + } + BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { + "an `Rc`".to_string() + } + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { + "an `Arc`".to_string() + } + _ => format!("a dereference of `{}`", ty), + }, + BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty), + } + } + + fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option { + match *func.kind() { + ty::FnDef(def_id, substs) => { + let trait_id = tcx.trait_of_item(def_id)?; + + let lang_items = tcx.lang_items(); + if Some(trait_id) == lang_items.deref_trait() + || Some(trait_id) == lang_items.deref_mut_trait() + { + Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0))) + } else if Some(trait_id) == lang_items.index_trait() + || Some(trait_id) == lang_items.index_mut_trait() + { + Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0))) + } else { + None + } + } + _ => None, + } + } +} + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + /// Finds the spans associated to a move or copy of move_place at location. + pub(super) fn move_spans( + &self, + moved_place: PlaceRef<'tcx>, // Could also be an upvar. + location: Location, + ) -> UseSpans<'tcx> { + use self::UseSpans::*; + + let stmt = match self.body[location.block].statements.get(location.statement_index) { + Some(stmt) => stmt, + None => return OtherUse(self.body.source_info(location).span), + }; + + debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); + if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind { + match kind { + box AggregateKind::Closure(def_id, _) + | box AggregateKind::Generator(def_id, _, _) => { + debug!("move_spans: def_id={:?} places={:?}", def_id, places); + if let Some((args_span, generator_kind, capture_kind_span, path_span)) = + self.closure_span(*def_id, moved_place, places) + { + return ClosureUse { + generator_kind, + args_span, + capture_kind_span, + path_span, + }; + } + } + _ => {} + } + } + + // StatementKind::FakeRead only contains a def_id if they are introduced as a result + // of pattern matching within a closure. + if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind { + match cause { + FakeReadCause::ForMatchedPlace(Some(closure_def_id)) + | FakeReadCause::ForLet(Some(closure_def_id)) => { + debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place); + let places = &[Operand::Move(*place)]; + if let Some((args_span, generator_kind, capture_kind_span, path_span)) = + self.closure_span(closure_def_id, moved_place, places) + { + return ClosureUse { + generator_kind, + args_span, + capture_kind_span, + path_span, + }; + } + } + _ => {} + } + } + + let normal_ret = + if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { + PatUse(stmt.source_info.span) + } else { + OtherUse(stmt.source_info.span) + }; + + // We are trying to find MIR of the form: + // ``` + // _temp = _moved_val; + // ... + // FnSelfCall(_temp, ...) + // ``` + // + // where `_moved_val` is the place we generated the move error for, + // `_temp` is some other local, and `FnSelfCall` is a function + // that has a `self` parameter. + + let target_temp = match stmt.kind { + StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => { + temp.as_local().unwrap() + } + _ => return normal_ret, + }; + + debug!("move_spans: target_temp = {:?}", target_temp); + + if let Some(Terminator { + kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. + }) = &self.body[location.block].terminator + { + let (method_did, method_substs) = if let Some(info) = + rustc_const_eval::util::find_self_call( + self.infcx.tcx, + &self.body, + target_temp, + location.block, + ) { + info + } else { + return normal_ret; + }; + + let tcx = self.infcx.tcx; + let parent = tcx.parent(method_did); + let is_fn_once = parent == tcx.lang_items().fn_once_trait(); + let is_operator = !from_hir_call + && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p)); + let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); + let fn_call_span = *fn_span; + + let self_arg = tcx.fn_arg_names(method_did)[0]; + + debug!( + "terminator = {:?} from_hir_call={:?}", + self.body[location.block].terminator, from_hir_call + ); + + // Check for a 'special' use of 'self' - + // an FnOnce call, an operator (e.g. `<<`), or a + // deref coercion. + let kind = if is_fn_once { + Some(FnSelfUseKind::FnOnceCall) + } else if is_operator { + Some(FnSelfUseKind::Operator { self_arg }) + } else if is_deref { + let deref_target = + tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { + Instance::resolve(tcx, self.param_env, deref_target, method_substs) + .transpose() + }); + if let Some(Ok(instance)) = deref_target { + let deref_target_ty = instance.ty(tcx, self.param_env); + Some(FnSelfUseKind::DerefCoercion { + deref_target: tcx.def_span(instance.def_id()), + deref_target_ty, + }) + } else { + None + } + } else { + None + }; + + let kind = kind.unwrap_or_else(|| { + // This isn't a 'special' use of `self` + debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); + let implicit_into_iter = matches!( + fn_call_span.desugaring_kind(), + Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ); + let parent_self_ty = parent + .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl) + .and_then(|did| match tcx.type_of(did).kind() { + ty::Adt(def, ..) => Some(def.did), + _ => None, + }); + let is_option_or_result = parent_self_ty.map_or(false, |def_id| { + tcx.is_diagnostic_item(sym::Option, def_id) + || tcx.is_diagnostic_item(sym::Result, def_id) + }); + FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result } + }); + + return FnSelfUse { + var_span: stmt.source_info.span, + fn_call_span, + fn_span: self + .infcx + .tcx + .sess + .source_map() + .guess_head_span(self.infcx.tcx.def_span(method_did)), + kind, + }; + } + normal_ret + } + + /// Finds the span of arguments of a closure (within `maybe_closure_span`) + /// and its usage of the local assigned at `location`. + /// This is done by searching in statements succeeding `location` + /// and originating from `maybe_closure_span`. + pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> { + use self::UseSpans::*; + debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); + + let target = match self.body[location.block].statements.get(location.statement_index) { + Some(&Statement { kind: StatementKind::Assign(box (ref place, _)), .. }) => { + if let Some(local) = place.as_local() { + local + } else { + return OtherUse(use_span); + } + } + _ => return OtherUse(use_span), + }; + + if self.body.local_kind(target) != LocalKind::Temp { + // operands are always temporaries. + return OtherUse(use_span); + } + + for stmt in &self.body[location.block].statements[location.statement_index + 1..] { + if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = + stmt.kind + { + let (def_id, is_generator) = match kind { + box AggregateKind::Closure(def_id, _) => (def_id, false), + box AggregateKind::Generator(def_id, _, _) => (def_id, true), + _ => continue, + }; + + debug!( + "borrow_spans: def_id={:?} is_generator={:?} places={:?}", + def_id, is_generator, places + ); + if let Some((args_span, generator_kind, capture_kind_span, path_span)) = + self.closure_span(*def_id, Place::from(target).as_ref(), places) + { + return ClosureUse { generator_kind, args_span, capture_kind_span, path_span }; + } else { + return OtherUse(use_span); + } + } + + if use_span != stmt.source_info.span { + break; + } + } + + OtherUse(use_span) + } + + /// Finds the spans of a captured place within a closure or generator. + /// The first span is the location of the use resulting in the capture kind of the capture + /// The second span is the location the use resulting in the captured path of the capture + fn closure_span( + &self, + def_id: DefId, + target_place: PlaceRef<'tcx>, + places: &[Operand<'tcx>], + ) -> Option<(Span, Option, Span, Span)> { + debug!( + "closure_span: def_id={:?} target_place={:?} places={:?}", + def_id, target_place, places + ); + let local_did = def_id.as_local()?; + let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did); + let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; + debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); + if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { + for (captured_place, place) in self + .infcx + .tcx + .typeck(def_id.expect_local()) + .closure_min_captures_flattened(def_id) + .zip(places) + { + match place { + Operand::Copy(place) | Operand::Move(place) + if target_place == place.as_ref() => + { + debug!("closure_span: found captured local {:?}", place); + let body = self.infcx.tcx.hir().body(*body_id); + let generator_kind = body.generator_kind(); + + return Some(( + *args_span, + generator_kind, + captured_place.get_capture_kind_span(self.infcx.tcx), + captured_place.get_path_span(self.infcx.tcx), + )); + } + _ => {} + } + } + } + None + } + + /// Helper to retrieve span(s) of given borrow from the current MIR + /// representation + pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> { + let span = self.body.source_info(borrow.reserve_location).span; + self.borrow_spans(span, borrow.reserve_location) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/move_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/move_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/move_errors.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/move_errors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,571 @@ +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::mir::*; +use rustc_middle::ty; +use rustc_mir_dataflow::move_paths::{ + IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex, +}; +use rustc_span::source_map::DesugaringKind; +use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; + +use crate::diagnostics::UseSpans; +use crate::prefixes::PrefixSet; +use crate::MirBorrowckCtxt; + +// Often when desugaring a pattern match we may have many individual moves in +// MIR that are all part of one operation from the user's point-of-view. For +// example: +// +// let (x, y) = foo() +// +// would move x from the 0 field of some temporary, and y from the 1 field. We +// group such errors together for cleaner error reporting. +// +// Errors are kept separate if they are from places with different parent move +// paths. For example, this generates two errors: +// +// let (&x, &y) = (&String::new(), &String::new()); +#[derive(Debug)] +enum GroupedMoveError<'tcx> { + // Place expression can't be moved from, + // e.g., match x[0] { s => (), } where x: &[String] + MovesFromPlace { + original_path: Place<'tcx>, + span: Span, + move_from: Place<'tcx>, + kind: IllegalMoveOriginKind<'tcx>, + binds_to: Vec, + }, + // Part of a value expression can't be moved from, + // e.g., match &String::new() { &x => (), } + MovesFromValue { + original_path: Place<'tcx>, + span: Span, + move_from: MovePathIndex, + kind: IllegalMoveOriginKind<'tcx>, + binds_to: Vec, + }, + // Everything that isn't from pattern matching. + OtherIllegalMove { + original_path: Place<'tcx>, + use_spans: UseSpans<'tcx>, + kind: IllegalMoveOriginKind<'tcx>, + }, +} + +impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { + pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) { + let grouped_errors = self.group_move_errors(move_errors); + for error in grouped_errors { + self.report(error); + } + } + + fn group_move_errors( + &self, + errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, + ) -> Vec> { + let mut grouped_errors = Vec::new(); + for (original_path, error) in errors { + self.append_to_grouped_errors(&mut grouped_errors, original_path, error); + } + grouped_errors + } + + fn append_to_grouped_errors( + &self, + grouped_errors: &mut Vec>, + original_path: Place<'tcx>, + error: MoveError<'tcx>, + ) { + match error { + MoveError::UnionMove { .. } => { + unimplemented!("don't know how to report union move errors yet.") + } + MoveError::IllegalMove { cannot_move_out_of: IllegalMoveOrigin { location, kind } } => { + // Note: that the only time we assign a place isn't a temporary + // to a user variable is when initializing it. + // If that ever stops being the case, then the ever initialized + // flow could be used. + if let Some(StatementKind::Assign(box ( + place, + Rvalue::Use(Operand::Move(move_from)), + ))) = self.body.basic_blocks()[location.block] + .statements + .get(location.statement_index) + .map(|stmt| &stmt.kind) + { + if let Some(local) = place.as_local() { + let local_decl = &self.body.local_decls[local]; + // opt_match_place is the + // match_span is the span of the expression being matched on + // match *x.y { ... } match_place is Some(*x.y) + // ^^^^ match_span is the span of *x.y + // + // opt_match_place is None for let [mut] x = ... statements, + // whether or not the right-hand side is a place expression + if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { + opt_match_place: Some((opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + pat_span: _, + }, + )))) = local_decl.local_info + { + let stmt_source_info = self.body.source_info(location); + self.append_binding_error( + grouped_errors, + kind, + original_path, + *move_from, + local, + opt_match_place, + match_span, + stmt_source_info.span, + ); + return; + } + } + } + + let move_spans = self.move_spans(original_path.as_ref(), location); + grouped_errors.push(GroupedMoveError::OtherIllegalMove { + use_spans: move_spans, + original_path, + kind, + }); + } + } + } + + fn append_binding_error( + &self, + grouped_errors: &mut Vec>, + kind: IllegalMoveOriginKind<'tcx>, + original_path: Place<'tcx>, + move_from: Place<'tcx>, + bind_to: Local, + match_place: Option>, + match_span: Span, + statement_span: Span, + ) { + debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span); + + let from_simple_let = match_place.is_none(); + let match_place = match_place.unwrap_or(move_from); + + match self.move_data.rev_lookup.find(match_place.as_ref()) { + // Error with the match place + LookupResult::Parent(_) => { + for ge in &mut *grouped_errors { + if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge { + if match_span == *span { + debug!("appending local({:?}) to list", bind_to); + if !binds_to.is_empty() { + binds_to.push(bind_to); + } + return; + } + } + } + debug!("found a new move error location"); + + // Don't need to point to x in let x = ... . + let (binds_to, span) = if from_simple_let { + (vec![], statement_span) + } else { + (vec![bind_to], match_span) + }; + grouped_errors.push(GroupedMoveError::MovesFromPlace { + span, + move_from, + original_path, + kind, + binds_to, + }); + } + // Error with the pattern + LookupResult::Exact(_) => { + let mpi = match self.move_data.rev_lookup.find(move_from.as_ref()) { + LookupResult::Parent(Some(mpi)) => mpi, + // move_from should be a projection from match_place. + _ => unreachable!("Probably not unreachable..."), + }; + for ge in &mut *grouped_errors { + if let GroupedMoveError::MovesFromValue { + span, + move_from: other_mpi, + binds_to, + .. + } = ge + { + if match_span == *span && mpi == *other_mpi { + debug!("appending local({:?}) to list", bind_to); + binds_to.push(bind_to); + return; + } + } + } + debug!("found a new move error location"); + grouped_errors.push(GroupedMoveError::MovesFromValue { + span: match_span, + move_from: mpi, + original_path, + kind, + binds_to: vec![bind_to], + }); + } + }; + } + + fn report(&mut self, error: GroupedMoveError<'tcx>) { + let (mut err, err_span) = { + let (span, use_spans, original_path, kind): ( + Span, + Option>, + Place<'tcx>, + &IllegalMoveOriginKind<'_>, + ) = match error { + GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. } + | GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => { + (span, None, original_path, kind) + } + GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => { + (use_spans.args_or_use(), Some(use_spans), original_path, kind) + } + }; + debug!( + "report: original_path={:?} span={:?}, kind={:?} \ + original_path.is_upvar_field_projection={:?}", + original_path, + span, + kind, + self.is_upvar_field_projection(original_path.as_ref()) + ); + ( + match kind { + IllegalMoveOriginKind::BorrowedContent { target_place } => self + .report_cannot_move_from_borrowed_content( + original_path, + *target_place, + span, + use_spans, + ), + IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { + self.cannot_move_out_of_interior_of_drop(span, ty) + } + IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { + self.cannot_move_out_of_interior_noncopy(span, ty, Some(*is_index)) + } + }, + span, + ) + }; + + self.add_move_hints(error, &mut err, err_span); + err.buffer(&mut self.errors_buffer); + } + + fn report_cannot_move_from_static( + &mut self, + place: Place<'tcx>, + span: Span, + ) -> DiagnosticBuilder<'a> { + let description = if place.projection.len() == 1 { + format!("static item {}", self.describe_any_place(place.as_ref())) + } else { + let base_static = PlaceRef { local: place.local, projection: &[ProjectionElem::Deref] }; + + format!( + "{} as {} is a static item", + self.describe_any_place(place.as_ref()), + self.describe_any_place(base_static), + ) + }; + + self.cannot_move_out_of(span, &description) + } + + fn report_cannot_move_from_borrowed_content( + &mut self, + move_place: Place<'tcx>, + deref_target_place: Place<'tcx>, + span: Span, + use_spans: Option>, + ) -> DiagnosticBuilder<'a> { + // Inspect the type of the content behind the + // borrow to provide feedback about why this + // was a move rather than a copy. + let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty; + let upvar_field = self + .prefixes(move_place.as_ref(), PrefixSet::All) + .find_map(|p| self.is_upvar_field_projection(p)); + + let deref_base = match deref_target_place.projection.as_ref() { + [proj_base @ .., ProjectionElem::Deref] => { + PlaceRef { local: deref_target_place.local, projection: &proj_base } + } + _ => bug!("deref_target_place is not a deref projection"), + }; + + if let PlaceRef { local, projection: [] } = deref_base { + let decl = &self.body.local_decls[local]; + if decl.is_ref_for_guard() { + let mut err = self.cannot_move_out_of( + span, + &format!("`{}` in pattern guard", self.local_names[local].unwrap()), + ); + err.note( + "variables bound in patterns cannot be moved from \ + until after the end of the pattern guard", + ); + return err; + } else if decl.is_ref_to_static() { + return self.report_cannot_move_from_static(move_place, span); + } + } + + debug!("report: ty={:?}", ty); + let mut err = match ty.kind() { + ty::Array(..) | ty::Slice(..) => { + self.cannot_move_out_of_interior_noncopy(span, ty, None) + } + ty::Closure(def_id, closure_substs) + if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() => + { + let closure_kind_ty = closure_substs.as_closure().kind_ty(); + let closure_kind = match closure_kind_ty.to_opt_closure_kind() { + Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind, + Some(ty::ClosureKind::FnOnce) => { + bug!("closure kind does not match first argument type") + } + None => bug!("closure kind not inferred by borrowck"), + }; + let capture_description = + format!("captured variable in an `{}` closure", closure_kind); + + let upvar = &self.upvars[upvar_field.unwrap().index()]; + let upvar_hir_id = upvar.place.get_root_variable(); + let upvar_name = upvar.place.to_string(self.infcx.tcx); + let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); + + let place_name = self.describe_any_place(move_place.as_ref()); + + let place_description = + if self.is_upvar_field_projection(move_place.as_ref()).is_some() { + format!("{}, a {}", place_name, capture_description) + } else { + format!("{}, as `{}` is a {}", place_name, upvar_name, capture_description) + }; + + debug!( + "report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}", + closure_kind_ty, closure_kind, place_description, + ); + + let mut diag = self.cannot_move_out_of(span, &place_description); + + diag.span_label(upvar_span, "captured outer variable"); + diag.span_label( + self.body.span, + format!("captured by this `{}` closure", closure_kind), + ); + + diag + } + _ => { + let source = self.borrowed_content_source(deref_base); + match (self.describe_place(move_place.as_ref()), source.describe_for_named_place()) + { + (Some(place_desc), Some(source_desc)) => self.cannot_move_out_of( + span, + &format!("`{}` which is behind a {}", place_desc, source_desc), + ), + (_, _) => self.cannot_move_out_of( + span, + &source.describe_for_unnamed_place(self.infcx.tcx), + ), + } + } + }; + let ty = move_place.ty(self.body, self.infcx.tcx).ty; + let def_id = match *ty.kind() { + ty::Adt(self_def, _) => self_def.did, + ty::Foreign(def_id) + | ty::FnDef(def_id, _) + | ty::Closure(def_id, _) + | ty::Generator(def_id, ..) + | ty::Opaque(def_id, _) => def_id, + _ => return err, + }; + let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id); + let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id); + if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) { + err.span_suggestion_verbose( + span.shrink_to_hi(), + &format!( + "consider borrowing the `{}`'s content", + if is_option { "Option" } else { "Result" } + ), + ".as_ref()".to_string(), + Applicability::MaybeIncorrect, + ); + } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) { + let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { + Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| { + type_known_to_meet_bound_modulo_regions( + &infcx, + self.param_env, + infcx + .tcx + .mk_imm_ref(infcx.tcx.lifetimes.re_erased, infcx.tcx.erase_regions(ty)), + def_id, + DUMMY_SP, + ) + }), + _ => false, + }; + if suggest { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!("consider iterating over a slice of the `{}`'s content", ty), + "&".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + err + } + + fn add_move_hints( + &self, + error: GroupedMoveError<'tcx>, + err: &mut DiagnosticBuilder<'a>, + span: Span, + ) { + match error { + GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::Unspecified, + ); + } + + if binds_to.is_empty() { + let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; + let place_desc = match self.describe_place(move_from.as_ref()) { + Some(desc) => format!("`{}`", desc), + None => "value".to_string(), + }; + + self.note_type_does_not_implement_copy( + err, + &place_desc, + place_ty, + Some(span), + "", + ); + } else { + binds_to.sort(); + binds_to.dedup(); + + self.add_move_error_details(err, &binds_to); + } + } + GroupedMoveError::MovesFromValue { mut binds_to, .. } => { + binds_to.sort(); + binds_to.dedup(); + self.add_move_error_suggestions(err, &binds_to); + self.add_move_error_details(err, &binds_to); + } + // No binding. Nothing to suggest. + GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { + let span = use_spans.var_or_use(); + let place_ty = original_path.ty(self.body, self.infcx.tcx).ty; + let place_desc = match self.describe_place(original_path.as_ref()) { + Some(desc) => format!("`{}`", desc), + None => "value".to_string(), + }; + self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); + + use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc)); + use_spans.var_span_label( + err, + format!("move occurs due to use{}", use_spans.describe()), + "moved", + ); + } + } + } + + fn add_move_error_suggestions(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) { + let mut suggestions: Vec<(Span, &str, String)> = Vec::new(); + for local in binds_to { + let bind_to = &self.body.local_decls[*local]; + if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { pat_span, .. }, + )))) = bind_to.local_info + { + if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) + { + if let Some(stripped) = pat_snippet.strip_prefix('&') { + let pat_snippet = stripped.trim_start(); + let (suggestion, to_remove) = if pat_snippet.starts_with("mut") + && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace) + { + (pat_snippet["mut".len()..].trim_start(), "&mut") + } else { + (pat_snippet, "&") + }; + suggestions.push((pat_span, to_remove, suggestion.to_owned())); + } + } + } + } + suggestions.sort_unstable_by_key(|&(span, _, _)| span); + suggestions.dedup_by_key(|&mut (span, _, _)| span); + for (span, to_remove, suggestion) in suggestions { + err.span_suggestion( + span, + &format!("consider removing the `{}`", to_remove), + suggestion, + Applicability::MachineApplicable, + ); + } + } + + fn add_move_error_details(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) { + for (j, local) in binds_to.iter().enumerate() { + let bind_to = &self.body.local_decls[*local]; + let binding_span = bind_to.source_info.span; + + if j == 0 { + err.span_label(binding_span, "data moved here"); + } else { + err.span_label(binding_span, "...and here"); + } + + if binds_to.len() == 1 { + self.note_type_does_not_implement_copy( + err, + &format!("`{}`", self.local_names[*local].unwrap()), + bind_to.ty, + Some(binding_span), + "", + ); + } + } + + if binds_to.len() > 1 { + err.note( + "move occurs because these variables have types that \ + don't implement the `Copy` trait", + ); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1097 @@ +use rustc_hir as hir; +use rustc_hir::Node; +use rustc_middle::hir::map::Map; +use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{ + hir::place::PlaceBase, + mir::{ + self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo, + LocalKind, Location, + }, +}; +use rustc_span::source_map::DesugaringKind; +use rustc_span::symbol::{kw, Symbol}; +use rustc_span::{BytePos, Span}; + +use crate::diagnostics::BorrowedContentSource; +use crate::MirBorrowckCtxt; +use rustc_const_eval::util::collect_writes::FindAssignments; +use rustc_errors::{Applicability, DiagnosticBuilder}; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) enum AccessKind { + MutableBorrow, + Mutate, +} + +impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { + pub(crate) fn report_mutability_error( + &mut self, + access_place: Place<'tcx>, + span: Span, + the_place_err: PlaceRef<'tcx>, + error_access: AccessKind, + location: Location, + ) { + debug!( + "report_mutability_error(\ + access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\ + )", + access_place, span, the_place_err, error_access, location, + ); + + let mut err; + let item_msg; + let reason; + let mut opt_source = None; + let access_place_desc = self.describe_place(access_place.as_ref()); + debug!("report_mutability_error: access_place_desc={:?}", access_place_desc); + + match the_place_err { + PlaceRef { local, projection: [] } => { + item_msg = format!("`{}`", access_place_desc.unwrap()); + if access_place.as_local().is_some() { + reason = ", as it is not declared as mutable".to_string(); + } else { + let name = self.local_names[local].expect("immutable unnamed local"); + reason = format!(", as `{}` is not declared as mutable", name); + } + } + + PlaceRef { + local, + projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], + } => { + debug_assert!(is_closure_or_generator( + Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty + )); + + let imm_borrow_derefed = self.upvars[upvar_index.index()] + .place + .place + .deref_tys() + .any(|ty| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not))); + + // If the place is immutable then: + // + // - Either we deref an immutable ref to get to our final place. + // - We don't capture derefs of raw ptrs + // - Or the final place is immut because the root variable of the capture + // isn't marked mut and we should suggest that to the user. + if imm_borrow_derefed { + // If we deref an immutable ref then the suggestion here doesn't help. + return; + } else { + item_msg = format!("`{}`", access_place_desc.unwrap()); + if self.is_upvar_field_projection(access_place.as_ref()).is_some() { + reason = ", as it is not declared as mutable".to_string(); + } else { + let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx); + reason = format!(", as `{}` is not declared as mutable", name); + } + } + } + + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[local].is_ref_for_guard() => + { + item_msg = format!("`{}`", access_place_desc.unwrap()); + reason = ", as it is immutable for the pattern guard".to_string(); + } + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[local].is_ref_to_static() => + { + if access_place.projection.len() == 1 { + item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); + reason = String::new(); + } else { + item_msg = format!("`{}`", access_place_desc.unwrap()); + let local_info = &self.body.local_decls[local].local_info; + if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { + let static_name = &self.infcx.tcx.item_name(def_id); + reason = format!(", as `{}` is an immutable static item", static_name); + } else { + bug!("is_ref_to_static return true, but not ref to static?"); + } + } + } + PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => { + if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL + && proj_base.is_empty() + && !self.upvars.is_empty() + { + item_msg = format!("`{}`", access_place_desc.unwrap()); + debug_assert!( + self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr() + ); + debug_assert!(is_closure_or_generator( + Place::ty_from( + the_place_err.local, + the_place_err.projection, + self.body, + self.infcx.tcx + ) + .ty + )); + + reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() { + ", as it is a captured variable in a `Fn` closure".to_string() + } else { + ", as `Fn` closures cannot mutate their captured variables".to_string() + } + } else { + let source = self.borrowed_content_source(PlaceRef { + local: the_place_err.local, + projection: proj_base, + }); + let pointer_type = source.describe_for_immutable_place(self.infcx.tcx); + opt_source = Some(source); + if let Some(desc) = access_place_desc { + item_msg = format!("`{}`", desc); + reason = match error_access { + AccessKind::Mutate => format!(", which is behind {}", pointer_type), + AccessKind::MutableBorrow => { + format!(", as it is behind {}", pointer_type) + } + } + } else { + item_msg = format!("data in {}", pointer_type); + reason = String::new(); + } + } + } + + PlaceRef { + local: _, + projection: + [.., ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(..)], + } => bug!("Unexpected immutable place."), + } + + debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason); + + // `act` and `acted_on` are strings that let us abstract over + // the verbs used in some diagnostic messages. + let act; + let acted_on; + + let span = match error_access { + AccessKind::Mutate => { + err = self.cannot_assign(span, &(item_msg + &reason)); + act = "assign"; + acted_on = "written"; + span + } + AccessKind::MutableBorrow => { + act = "borrow as mutable"; + acted_on = "borrowed as mutable"; + + let borrow_spans = self.borrow_spans(span, location); + let borrow_span = borrow_spans.args_or_use(); + err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason); + borrow_spans.var_span_label( + &mut err, + format!( + "mutable borrow occurs due to use of {} in closure", + self.describe_any_place(access_place.as_ref()), + ), + "mutable", + ); + borrow_span + } + }; + + debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on); + + match the_place_err { + // Suggest making an existing shared borrow in a struct definition a mutable borrow. + // + // This is applicable when we have a deref of a field access to a deref of a local - + // something like `*((*_1).0`. The local that we get will be a reference to the + // struct we've got a field access of (it must be a reference since there's a deref + // after the field access). + PlaceRef { + local, + projection: + [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref], + } => { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + + if let Some((span, message)) = annotate_struct_field( + self.infcx.tcx, + Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty, + field, + ) { + err.span_suggestion( + span, + "consider changing this to be mutable", + message, + Applicability::MaybeIncorrect, + ); + } + } + + // Suggest removing a `&mut` from the use of a mutable reference. + PlaceRef { local, projection: [] } + if self + .body + .local_decls + .get(local) + .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) + .unwrap_or(false) => + { + let decl = &self.body.local_decls[local]; + err.span_label(span, format!("cannot {ACT}", ACT = act)); + if let Some(mir::Statement { + source_info, + kind: + mir::StatementKind::Assign(box ( + _, + mir::Rvalue::Ref( + _, + mir::BorrowKind::Mut { allow_two_phase_borrow: false }, + _, + ), + )), + .. + }) = &self.body[location.block].statements.get(location.statement_index) + { + match decl.local_info { + Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + opt_ty_info: Some(sp), + opt_match_place: _, + pat_span: _, + }, + )))) => { + err.span_note(sp, "the binding is already a mutable borrow"); + } + _ => { + err.span_note( + decl.source_info.span, + "the binding is already a mutable borrow", + ); + } + } + if let Ok(snippet) = + self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span) + { + if snippet.starts_with("&mut ") { + // We don't have access to the HIR to get accurate spans, but we can + // give a best effort structured suggestion. + err.span_suggestion_verbose( + source_info.span.with_hi(source_info.span.lo() + BytePos(5)), + "try removing `&mut` here", + String::new(), + Applicability::MachineApplicable, + ); + } else { + // This can occur with things like `(&mut self).foo()`. + err.span_help(source_info.span, "try removing `&mut` here"); + } + } else { + err.span_help(source_info.span, "try removing `&mut` here"); + } + } else if decl.mutability == Mutability::Not + && !matches!( + decl.local_info, + Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( + ImplicitSelfKind::MutRef + )))) + ) + { + err.span_suggestion_verbose( + decl.source_info.span.shrink_to_lo(), + "consider making the binding mutable", + "mut ".to_string(), + Applicability::MachineApplicable, + ); + } + } + + // We want to suggest users use `let mut` for local (user + // variable) mutations... + PlaceRef { local, projection: [] } + if self.body.local_decls[local].can_be_made_mutable() => + { + // ... but it doesn't make sense to suggest it on + // variables that are `ref x`, `ref mut x`, `&self`, + // or `&mut self` (such variables are simply not + // mutable). + let local_decl = &self.body.local_decls[local]; + assert_eq!(local_decl.mutability, Mutability::Not); + + err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_suggestion( + local_decl.source_info.span, + "consider changing this to be mutable", + format!("mut {}", self.local_names[local].unwrap()), + Applicability::MachineApplicable, + ); + let tcx = self.infcx.tcx; + if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() { + self.show_mutating_upvar(tcx, id, the_place_err, &mut err); + } + } + + // Also suggest adding mut for upvars + PlaceRef { + local, + projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], + } => { + debug_assert!(is_closure_or_generator( + Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty + )); + + let captured_place = &self.upvars[upvar_index.index()].place; + + err.span_label(span, format!("cannot {ACT}", ACT = act)); + + let upvar_hir_id = captured_place.get_root_variable(); + + if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) { + if let hir::PatKind::Binding( + hir::BindingAnnotation::Unannotated, + _, + upvar_ident, + _, + ) = pat.kind + { + err.span_suggestion( + upvar_ident.span, + "consider changing this to be mutable", + format!("mut {}", upvar_ident.name), + Applicability::MachineApplicable, + ); + } + } + + let tcx = self.infcx.tcx; + if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind() + { + if let ty::Closure(id, _) = ty.kind() { + self.show_mutating_upvar(tcx, id, the_place_err, &mut err); + } + } + } + + // complete hack to approximate old AST-borrowck + // diagnostic: if the span starts with a mutable borrow of + // a local variable, then just suggest the user remove it. + PlaceRef { local: _, projection: [] } + if { + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + snippet.starts_with("&mut ") + } else { + false + } + } => + { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_suggestion( + span, + "try removing `&mut` here", + String::new(), + Applicability::MaybeIncorrect, + ); + } + + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[local].is_ref_for_guard() => + { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.note( + "variables bound in patterns are immutable until the end of the pattern guard", + ); + } + + // We want to point out when a `&` can be readily replaced + // with an `&mut`. + // + // FIXME: can this case be generalized to work for an + // arbitrary base for the projection? + PlaceRef { local, projection: [ProjectionElem::Deref] } + if self.body.local_decls[local].is_user_variable() => + { + let local_decl = &self.body.local_decls[local]; + + let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() { + ("&", "reference") + } else { + ("*const", "pointer") + }; + + match self.local_names[local] { + Some(name) if !local_decl.from_compiler_desugaring() => { + let label = match local_decl.local_info.as_ref().unwrap() { + box LocalInfo::User(ClearCrossCrate::Set( + mir::BindingForm::ImplicitSelf(_), + )) => { + let (span, suggestion) = + suggest_ampmut_self(self.infcx.tcx, local_decl); + Some((true, span, suggestion)) + } + + box LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info, + .. + }, + ))) => { + // check if the RHS is from desugaring + let locations = self.body.find_assignments(local); + let opt_assignment_rhs_span = locations + .first() + .map(|&location| self.body.source_info(location).span); + let opt_desugaring_kind = + opt_assignment_rhs_span.and_then(|span| span.desugaring_kind()); + match opt_desugaring_kind { + // on for loops, RHS points to the iterator part + Some(DesugaringKind::ForLoop(_)) => { + self.suggest_similar_mut_method_for_for_loop(&mut err); + Some(( + false, + opt_assignment_rhs_span.unwrap(), + format!( + "this iterator yields `{SIGIL}` {DESC}s", + SIGIL = pointer_sigil, + DESC = pointer_desc + ), + )) + } + // don't create labels for compiler-generated spans + Some(_) => None, + None => { + let (span, suggestion) = suggest_ampmut( + self.infcx.tcx, + local_decl, + opt_assignment_rhs_span, + *opt_ty_info, + ); + Some((true, span, suggestion)) + } + } + } + + box LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByReference(_), + .. + }, + ))) => { + let pattern_span = local_decl.source_info.span; + suggest_ref_mut(self.infcx.tcx, pattern_span) + .map(|replacement| (true, pattern_span, replacement)) + } + + box LocalInfo::User(ClearCrossCrate::Clear) => { + bug!("saw cleared local state") + } + + _ => unreachable!(), + }; + + match label { + Some((true, err_help_span, suggested_code)) => { + let (is_trait_sig, local_trait) = self.is_error_in_trait(local); + if !is_trait_sig { + err.span_suggestion( + err_help_span, + &format!( + "consider changing this to be a mutable {}", + pointer_desc + ), + suggested_code, + Applicability::MachineApplicable, + ); + } else if let Some(x) = local_trait { + err.span_suggestion( + x, + &format!( + "consider changing that to be a mutable {}", + pointer_desc + ), + suggested_code, + Applicability::MachineApplicable, + ); + } + } + Some((false, err_label_span, message)) => { + err.span_label(err_label_span, &message); + } + None => {} + } + err.span_label( + span, + format!( + "`{NAME}` is a `{SIGIL}` {DESC}, \ + so the data it refers to cannot be {ACTED_ON}", + NAME = name, + SIGIL = pointer_sigil, + DESC = pointer_desc, + ACTED_ON = acted_on + ), + ); + } + _ => { + err.span_label( + span, + format!( + "cannot {ACT} through `{SIGIL}` {DESC}", + ACT = act, + SIGIL = pointer_sigil, + DESC = pointer_desc + ), + ); + } + } + } + + PlaceRef { local, projection: [ProjectionElem::Deref] } + if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() => + { + self.expected_fn_found_fn_mut_call(&mut err, span, act); + } + + PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + + match opt_source { + Some(BorrowedContentSource::OverloadedDeref(ty)) => { + err.help(&format!( + "trait `DerefMut` is required to modify through a dereference, \ + but it is not implemented for `{}`", + ty, + )); + } + Some(BorrowedContentSource::OverloadedIndex(ty)) => { + err.help(&format!( + "trait `IndexMut` is required to modify indexed content, \ + but it is not implemented for `{}`", + ty, + )); + } + _ => (), + } + } + + _ => { + err.span_label(span, format!("cannot {ACT}", ACT = act)); + } + } + + err.buffer(&mut self.errors_buffer); + } + + /// User cannot make signature of a trait mutable without changing the + /// trait. So we find if this error belongs to a trait and if so we move + /// suggestion to the trait or disable it if it is out of scope of this crate + fn is_error_in_trait(&self, local: Local) -> (bool, Option) { + if self.body.local_kind(local) != LocalKind::Arg { + return (false, None); + } + let hir_map = self.infcx.tcx.hir(); + let my_def = self.body.source.def_id(); + let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap()); + let td = if let Some(a) = + self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x)) + { + a + } else { + return (false, None); + }; + ( + true, + td.as_local().and_then(|tld| { + let h = hir_map.local_def_id_to_hir_id(tld); + match hir_map.find(h) { + Some(Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, _, _, items), + .. + })) => { + let mut f_in_trait_opt = None; + for hir::TraitItemRef { id: fi, kind: k, .. } in *items { + let hi = fi.hir_id(); + if !matches!(k, hir::AssocItemKind::Fn { .. }) { + continue; + } + if hir_map.name(hi) != hir_map.name(my_hir) { + continue; + } + f_in_trait_opt = Some(hi); + break; + } + f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) { + Some(Node::TraitItem(hir::TraitItem { + kind: + hir::TraitItemKind::Fn( + hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. }, + _, + ), + .. + })) => { + let hir::Ty { span, .. } = inputs[local.index() - 1]; + Some(span) + } + _ => None, + }) + } + _ => None, + } + }), + ) + } + + // point to span of upvar making closure call require mutable borrow + fn show_mutating_upvar( + &self, + tcx: TyCtxt<'_>, + id: &hir::def_id::DefId, + the_place_err: PlaceRef<'tcx>, + err: &mut DiagnosticBuilder<'_>, + ) { + let closure_local_def_id = id.expect_local(); + let tables = tcx.typeck(closure_local_def_id); + let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id); + if let Some((span, closure_kind_origin)) = + &tables.closure_kind_origins().get(closure_hir_id) + { + let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { + let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin); + let root_hir_id = upvar_id.var_path.hir_id; + // we have an origin for this closure kind starting at this root variable so it's safe to unwrap here + let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap(); + + let origin_projection = closure_kind_origin + .projections + .iter() + .map(|proj| proj.kind) + .collect::>(); + let mut capture_reason = String::new(); + for captured_place in captured_places { + let captured_place_kinds = captured_place + .place + .projections + .iter() + .map(|proj| proj.kind) + .collect::>(); + if rustc_middle::ty::is_ancestor_or_same_capture( + &captured_place_kinds, + &origin_projection, + ) { + match captured_place.info.capture_kind { + ty::UpvarCapture::ByRef(ty::UpvarBorrow { + kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, + .. + }) => { + capture_reason = format!("mutable borrow of `{}`", upvar); + } + ty::UpvarCapture::ByValue(_) => { + capture_reason = format!("possible mutation of `{}`", upvar); + } + _ => bug!("upvar `{}` borrowed, but not mutably", upvar), + } + break; + } + } + if capture_reason.is_empty() { + bug!("upvar `{}` borrowed, but cannot find reason", upvar); + } + capture_reason + } else { + bug!("not an upvar") + }; + err.span_label( + *span, + format!( + "calling `{}` requires mutable binding due to {}", + self.describe_place(the_place_err).unwrap(), + reason + ), + ); + } + } + + // Attempt to search similar mutable associated items for suggestion. + // In the future, attempt in all path but initially for RHS of for_loop + fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) { + use hir::{ + BodyId, Expr, + ExprKind::{Block, Call, DropTemps, Match, MethodCall}, + HirId, ImplItem, ImplItemKind, Item, ItemKind, + }; + + fn maybe_body_id_of_fn(hir_map: &Map<'tcx>, id: HirId) -> Option { + match hir_map.find(id) { + Some(Node::Item(Item { kind: ItemKind::Fn(_, _, body_id), .. })) + | Some(Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })) => { + Some(*body_id) + } + _ => None, + } + } + let hir_map = self.infcx.tcx.hir(); + let mir_body_hir_id = self.mir_hir_id(); + if let Some(fn_body_id) = maybe_body_id_of_fn(&hir_map, mir_body_hir_id) { + if let Block( + hir::Block { + expr: + Some(Expr { + kind: + DropTemps(Expr { + kind: + Match( + Expr { + kind: + Call( + _, + [Expr { + kind: MethodCall(path_segment, ..), + hir_id, + .. + }, ..], + ), + .. + }, + .., + ), + .. + }), + .. + }), + .. + }, + _, + ) = hir_map.body(fn_body_id).value.kind + { + let opt_suggestions = path_segment + .hir_id + .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner)) + .and_then(|typeck| typeck.type_dependent_def_id(*hir_id)) + .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) + .map(|def_id| self.infcx.tcx.associated_items(def_id)) + .map(|assoc_items| { + assoc_items + .in_definition_order() + .map(|assoc_item_def| assoc_item_def.ident) + .filter(|&ident| { + let original_method_ident = path_segment.ident; + original_method_ident != ident + && ident + .as_str() + .starts_with(&original_method_ident.name.to_string()) + }) + .map(|ident| format!("{}()", ident)) + .peekable() + }); + + if let Some(mut suggestions) = opt_suggestions { + if suggestions.peek().is_some() { + err.span_suggestions( + path_segment.ident.span, + "use mutable method", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + } + }; + } + + /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. + fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) { + err.span_label(sp, format!("cannot {}", act)); + + let hir = self.infcx.tcx.hir(); + let closure_id = self.mir_hir_id(); + let fn_call_id = hir.get_parent_node(closure_id); + let node = hir.get(fn_call_id); + let item_id = hir.enclosing_body_owner(fn_call_id); + let mut look_at_return = true; + // If we can detect the expression to be an `fn` call where the closure was an argument, + // we point at the `fn` definition argument... + if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Call(func, args), .. }) = node { + let arg_pos = args + .iter() + .enumerate() + .filter(|(_, arg)| arg.span == self.body.span) + .map(|(pos, _)| pos) + .next(); + let def_id = hir.local_def_id(item_id); + let tables = self.infcx.tcx.typeck(def_id); + if let Some(ty::FnDef(def_id, _)) = + tables.node_type_opt(func.hir_id).as_ref().map(|ty| ty.kind()) + { + let arg = match hir.get_if_local(*def_id) { + Some( + hir::Node::Item(hir::Item { + ident, kind: hir::ItemKind::Fn(sig, ..), .. + }) + | hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(sig, _), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(sig, _), + .. + }), + ) => Some( + arg_pos + .and_then(|pos| { + sig.decl.inputs.get( + pos + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ) + }) + .map(|arg| arg.span) + .unwrap_or(ident.span), + ), + _ => None, + }; + if let Some(span) = arg { + err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); + err.span_label(func.span, "expects `Fn` instead of `FnMut`"); + if self.infcx.tcx.sess.source_map().is_multiline(self.body.span) { + err.span_label(self.body.span, "in this closure"); + } + look_at_return = false; + } + } + } + + if look_at_return && hir.get_return_block(closure_id).is_some() { + // ...otherwise we are probably in the tail expression of the function, point at the + // return type. + match hir.get(hir.get_parent_item(fn_call_id)) { + hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) + | hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(sig, _), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(sig, _), + .. + }) => { + err.span_label(ident.span, ""); + err.span_label( + sig.decl.output.span(), + "change this to return `FnMut` instead of `Fn`", + ); + err.span_label(self.body.span, "in this closure"); + } + _ => {} + } + } + } +} + +fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option) -> bool { + debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind()); + + match local_decl.local_info.as_deref() { + // Check if mutably borrowing a mutable reference. + Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(Mutability::Not), .. + }, + )))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), + Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => { + // Check if the user variable is a `&mut self` and we can therefore + // suggest removing the `&mut`. + // + // Deliberately fall into this case for all implicit self types, + // so that we don't fall in to the next case with them. + *kind == mir::ImplicitSelfKind::MutRef + } + _ if Some(kw::SelfLower) == local_name => { + // Otherwise, check if the name is the `self` keyword - in which case + // we have an explicit self. Do the same thing in this case and check + // for a `self: &mut Self` to suggest removing the `&mut`. + matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)) + } + _ => false, + } +} + +fn suggest_ampmut_self<'tcx>( + tcx: TyCtxt<'tcx>, + local_decl: &mir::LocalDecl<'tcx>, +) -> (Span, String) { + let sp = local_decl.source_info.span; + ( + sp, + match tcx.sess.source_map().span_to_snippet(sp) { + Ok(snippet) => { + let lt_pos = snippet.find('\''); + if let Some(lt_pos) = lt_pos { + format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4]) + } else { + "&mut self".to_string() + } + } + _ => "&mut self".to_string(), + }, + ) +} + +// When we want to suggest a user change a local variable to be a `&mut`, there +// are three potential "obvious" things to highlight: +// +// let ident [: Type] [= RightHandSideExpression]; +// ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ +// (1.) (2.) (3.) +// +// We can always fallback on highlighting the first. But chances are good that +// the user experience will be better if we highlight one of the others if possible; +// for example, if the RHS is present and the Type is not, then the type is going to +// be inferred *from* the RHS, which means we should highlight that (and suggest +// that they borrow the RHS mutably). +// +// This implementation attempts to emulate AST-borrowck prioritization +// by trying (3.), then (2.) and finally falling back on (1.). +fn suggest_ampmut<'tcx>( + tcx: TyCtxt<'tcx>, + local_decl: &mir::LocalDecl<'tcx>, + opt_assignment_rhs_span: Option, + opt_ty_info: Option, +) -> (Span, String) { + if let Some(assignment_rhs_span) = opt_assignment_rhs_span { + if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) { + let is_mutbl = |ty: &str| -> bool { + if let Some(rest) = ty.strip_prefix("mut") { + match rest.chars().next() { + // e.g. `&mut x` + Some(c) if c.is_whitespace() => true, + // e.g. `&mut(x)` + Some('(') => true, + // e.g. `&mut{x}` + Some('{') => true, + // e.g. `&mutablevar` + _ => false, + } + } else { + false + } + }; + if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) { + let lt_name = &src[1..ws_pos]; + let ty = src[ws_pos..].trim_start(); + if !is_mutbl(ty) { + return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty)); + } + } else if let Some(stripped) = src.strip_prefix('&') { + let stripped = stripped.trim_start(); + if !is_mutbl(stripped) { + return (assignment_rhs_span, format!("&mut {}", stripped)); + } + } + } + } + + let highlight_span = match opt_ty_info { + // if this is a variable binding with an explicit type, + // try to highlight that for the suggestion. + Some(ty_span) => ty_span, + + // otherwise, just highlight the span associated with + // the (MIR) LocalDecl. + None => local_decl.source_info.span, + }; + + if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) { + if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) { + let lt_name = &src[1..ws_pos]; + let ty = &src[ws_pos..]; + return (highlight_span, format!("&{} mut{}", lt_name, ty)); + } + } + + let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); + assert_eq!(ty_mut.mutbl, hir::Mutability::Not); + ( + highlight_span, + if local_decl.ty.is_region_ptr() { + format!("&mut {}", ty_mut.ty) + } else { + format!("*mut {}", ty_mut.ty) + }, + ) +} + +fn is_closure_or_generator(ty: Ty<'_>) -> bool { + ty.is_closure() || ty.is_generator() +} + +/// Adds a suggestion to a struct definition given a field access to a local. +/// This function expects the local to be a reference to a struct in order to produce a suggestion. +/// +/// ```text +/// LL | s: &'a String +/// | ---------- use `&'a mut String` here to make mutable +/// ``` +fn annotate_struct_field( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + field: &mir::Field, +) -> Option<(Span, String)> { + // Expect our local to be a reference to a struct of some kind. + if let ty::Ref(_, ty, _) = ty.kind() { + if let ty::Adt(def, _) = ty.kind() { + let field = def.all_fields().nth(field.index())?; + // Use the HIR types to construct the diagnostic message. + let hir_id = tcx.hir().local_def_id_to_hir_id(field.did.as_local()?); + let node = tcx.hir().find(hir_id)?; + // Now we're dealing with the actual struct that we're going to suggest a change to, + // we can expect a field that is an immutable reference to a type. + if let hir::Node::Field(field) = node { + if let hir::TyKind::Rptr( + lifetime, + hir::MutTy { mutbl: hir::Mutability::Not, ref ty }, + ) = field.ty.kind + { + // Get the snippets in two parts - the named lifetime (if there is one) and + // type being referenced, that way we can reconstruct the snippet without loss + // of detail. + let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?; + let lifetime_snippet = if !lifetime.is_elided() { + format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?) + } else { + String::new() + }; + + return Some(( + field.ty.span, + format!("&{}mut {}", lifetime_snippet, &*type_snippet,), + )); + } + } + } + } + + None +} + +/// If possible, suggest replacing `ref` with `ref mut`. +fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option { + let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?; + if hi_src.starts_with("ref") && hi_src["ref".len()..].starts_with(rustc_lexer::is_whitespace) { + let replacement = format!("ref mut{}", &hi_src["ref".len()..]); + Some(replacement) + } else { + None + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,263 @@ +//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied +//! outlives constraints. + +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::DiagnosticBuilder; +use rustc_middle::ty::RegionVid; +use smallvec::SmallVec; +use std::collections::BTreeMap; +use tracing::debug; + +use crate::MirBorrowckCtxt; + +use super::{ErrorConstraintInfo, RegionName, RegionNameSource}; + +/// The different things we could suggest. +enum SuggestedConstraint { + /// Outlives(a, [b, c, d, ...]) => 'a: 'b + 'c + 'd + ... + Outlives(RegionName, SmallVec<[RegionName; 2]>), + + /// 'a = 'b + Equal(RegionName, RegionName), + + /// 'a: 'static i.e. 'a = 'static and the user should just use 'static + Static(RegionName), +} + +/// Collects information about outlives constraints that needed to be added for a given MIR node +/// corresponding to a function definition. +/// +/// Adds a help note suggesting adding a where clause with the needed constraints. +#[derive(Default)] +pub struct OutlivesSuggestionBuilder { + /// The list of outlives constraints that need to be added. Specifically, we map each free + /// region to all other regions that it must outlive. I will use the shorthand `fr: + /// outlived_frs`. Not all of these regions will already have names necessarily. Some could be + /// implicit free regions that we inferred. These will need to be given names in the final + /// suggestion message. + constraints_to_add: BTreeMap>, +} + +impl OutlivesSuggestionBuilder { + /// Returns `true` iff the `RegionNameSource` is a valid source for an outlives + /// suggestion. + // + // FIXME: Currently, we only report suggestions if the `RegionNameSource` is an early-bound + // region or a named region, avoiding using regions with synthetic names altogether. This + // allows us to avoid giving impossible suggestions (e.g. adding bounds to closure args). + // We can probably be less conservative, since some inferred free regions are namable (e.g. + // the user can explicitly name them. To do this, we would allow some regions whose names + // come from `MatchedAdtAndSegment`, being careful to filter out bad suggestions, such as + // naming the `'self` lifetime in methods, etc. + fn region_name_is_suggestable(name: &RegionName) -> bool { + match name.source { + RegionNameSource::NamedEarlyBoundRegion(..) + | RegionNameSource::NamedFreeRegion(..) + | RegionNameSource::Static => true, + + // Don't give suggestions for upvars, closure return types, or other unnamable + // regions. + RegionNameSource::SynthesizedFreeEnvRegion(..) + | RegionNameSource::AnonRegionFromArgument(..) + | RegionNameSource::AnonRegionFromUpvar(..) + | RegionNameSource::AnonRegionFromOutput(..) + | RegionNameSource::AnonRegionFromYieldTy(..) + | RegionNameSource::AnonRegionFromAsyncFn(..) => { + debug!("Region {:?} is NOT suggestable", name); + false + } + } + } + + /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`. + fn region_vid_to_name( + &self, + mbcx: &MirBorrowckCtxt<'_, '_>, + region: RegionVid, + ) -> Option { + mbcx.give_region_a_name(region).filter(Self::region_name_is_suggestable) + } + + /// Compiles a list of all suggestions to be printed in the final big suggestion. + fn compile_all_suggestions( + &self, + mbcx: &MirBorrowckCtxt<'_, '_>, + ) -> SmallVec<[SuggestedConstraint; 2]> { + let mut suggested = SmallVec::new(); + + // Keep track of variables that we have already suggested unifying so that we don't print + // out silly duplicate messages. + let mut unified_already = FxHashSet::default(); + + for (fr, outlived) in &self.constraints_to_add { + let fr_name = if let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) { + fr_name + } else { + continue; + }; + + let outlived = outlived + .iter() + // if there is a `None`, we will just omit that constraint + .filter_map(|fr| self.region_vid_to_name(mbcx, *fr).map(|rname| (fr, rname))) + .collect::>(); + + // No suggestable outlived lifetimes. + if outlived.is_empty() { + continue; + } + + // There are three types of suggestions we can make: + // 1) Suggest a bound: 'a: 'b + // 2) Suggest replacing 'a with 'static. If any of `outlived` is `'static`, then we + // should just replace 'a with 'static. + // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a + + if outlived + .iter() + .any(|(_, outlived_name)| matches!(outlived_name.source, RegionNameSource::Static)) + { + suggested.push(SuggestedConstraint::Static(fr_name)); + } else { + // We want to isolate out all lifetimes that should be unified and print out + // separate messages for them. + + let (unified, other): (Vec<_>, Vec<_>) = outlived.into_iter().partition( + // Do we have both 'fr: 'r and 'r: 'fr? + |(r, _)| { + self.constraints_to_add + .get(r) + .map(|r_outlived| r_outlived.as_slice().contains(fr)) + .unwrap_or(false) + }, + ); + + for (r, bound) in unified.into_iter() { + if !unified_already.contains(fr) { + suggested.push(SuggestedConstraint::Equal(fr_name.clone(), bound)); + unified_already.insert(r); + } + } + + if !other.is_empty() { + let other = + other.iter().map(|(_, rname)| rname.clone()).collect::>(); + suggested.push(SuggestedConstraint::Outlives(fr_name, other)) + } + } + } + + suggested + } + + /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest. + crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) { + debug!("Collected {:?}: {:?}", fr, outlived_fr); + + // Add to set of constraints for final help note. + self.constraints_to_add.entry(fr).or_default().push(outlived_fr); + } + + /// Emit an intermediate note on the given `Diagnostic` if the involved regions are + /// suggestable. + crate fn intermediate_suggestion( + &mut self, + mbcx: &MirBorrowckCtxt<'_, '_>, + errci: &ErrorConstraintInfo, + diag: &mut DiagnosticBuilder<'_>, + ) { + // Emit an intermediate note. + let fr_name = self.region_vid_to_name(mbcx, errci.fr); + let outlived_fr_name = self.region_vid_to_name(mbcx, errci.outlived_fr); + + if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) { + if !matches!(outlived_fr_name.source, RegionNameSource::Static) { + diag.help(&format!( + "consider adding the following bound: `{}: {}`", + fr_name, outlived_fr_name + )); + } + } + } + + /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final + /// suggestion including all collected constraints. + crate fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) { + // No constraints to add? Done. + if self.constraints_to_add.is_empty() { + debug!("No constraints to suggest."); + return; + } + + // If there is only one constraint to suggest, then we already suggested it in the + // intermediate suggestion above. + if self.constraints_to_add.len() == 1 + && self.constraints_to_add.values().next().unwrap().len() == 1 + { + debug!("Only 1 suggestion. Skipping."); + return; + } + + // Get all suggestable constraints. + let suggested = self.compile_all_suggestions(mbcx); + + // If there are no suggestable constraints... + if suggested.is_empty() { + debug!("Only 1 suggestable constraint. Skipping."); + return; + } + + // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a + // list of diagnostics. + let mut diag = if suggested.len() == 1 { + mbcx.infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() { + SuggestedConstraint::Outlives(a, bs) => { + let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect(); + format!("add bound `{}: {}`", a, bs.join(" + ")) + } + + SuggestedConstraint::Equal(a, b) => { + format!("`{}` and `{}` must be the same: replace one with the other", a, b) + } + SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a), + }) + } else { + // Create a new diagnostic. + let mut diag = mbcx + .infcx + .tcx + .sess + .diagnostic() + .struct_help("the following changes may resolve your lifetime errors"); + + // Add suggestions. + for constraint in suggested { + match constraint { + SuggestedConstraint::Outlives(a, bs) => { + let bs: SmallVec<[String; 2]> = + bs.iter().map(|r| format!("{}", r)).collect(); + diag.help(&format!("add bound `{}: {}`", a, bs.join(" + "))); + } + SuggestedConstraint::Equal(a, b) => { + diag.help(&format!( + "`{}` and `{}` must be the same: replace one with the other", + a, b + )); + } + SuggestedConstraint::Static(a) => { + diag.help(&format!("replace `{}` with `'static`", a)); + } + } + } + + diag + }; + + // We want this message to appear after other messages on the mir def. + let mir_span = mbcx.body.span; + diag.sort_span = mir_span.shrink_to_hi(); + + // Buffer the diagnostic + diag.buffer(&mut mbcx.errors_buffer); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/region_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/region_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/region_errors.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/region_errors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,687 @@ +//! Error reporting machinery for lifetime errors. + +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_infer::infer::{ + error_reporting::nice_region_error::NiceRegionError, + error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, +}; +use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, RegionVid, Ty}; +use rustc_span::symbol::{kw, sym}; +use rustc_span::{BytePos, Span}; + +use crate::borrowck_errors; + +use super::{OutlivesSuggestionBuilder, RegionName}; +use crate::region_infer::BlameConstraint; +use crate::{ + nll::ConstraintDescription, + region_infer::{values::RegionElement, TypeTest}, + universal_regions::DefiningTy, + MirBorrowckCtxt, +}; + +impl ConstraintDescription for ConstraintCategory { + fn description(&self) -> &'static str { + // Must end with a space. Allows for empty names to be provided. + match self { + ConstraintCategory::Assignment => "assignment ", + ConstraintCategory::Return(_) => "returning this value ", + ConstraintCategory::Yield => "yielding this value ", + ConstraintCategory::UseAsConst => "using this value as a constant ", + ConstraintCategory::UseAsStatic => "using this value as a static ", + ConstraintCategory::Cast => "cast ", + ConstraintCategory::CallArgument => "argument ", + ConstraintCategory::TypeAnnotation => "type annotation ", + ConstraintCategory::ClosureBounds => "closure body ", + ConstraintCategory::SizedBound => "proving this value is `Sized` ", + ConstraintCategory::CopyBound => "copying this value ", + ConstraintCategory::OpaqueType => "opaque type ", + ConstraintCategory::ClosureUpvar(_) => "closure capture ", + ConstraintCategory::Usage => "this usage ", + ConstraintCategory::Predicate(_) + | ConstraintCategory::Boring + | ConstraintCategory::BoringNoLocation + | ConstraintCategory::Internal => "", + } + } +} + +/// A collection of errors encountered during region inference. This is needed to efficiently +/// report errors after borrow checking. +/// +/// Usually we expect this to either be empty or contain a small number of items, so we can avoid +/// allocation most of the time. +crate type RegionErrors<'tcx> = Vec>; + +#[derive(Clone, Debug)] +crate enum RegionErrorKind<'tcx> { + /// A generic bound failure for a type test (`T: 'a`). + TypeTestError { type_test: TypeTest<'tcx> }, + + /// An unexpected hidden region for an opaque type. + UnexpectedHiddenRegion { + /// The span for the member constraint. + span: Span, + /// The hidden type. + hidden_ty: Ty<'tcx>, + /// The unexpected region. + member_region: ty::Region<'tcx>, + }, + + /// Higher-ranked subtyping error. + BoundUniversalRegionError { + /// The placeholder free region. + longer_fr: RegionVid, + /// The region element that erroneously must be outlived by `longer_fr`. + error_element: RegionElement, + /// The placeholder region. + placeholder: ty::PlaceholderRegion, + }, + + /// Any other lifetime error. + RegionError { + /// The origin of the region. + fr_origin: NllRegionVariableOrigin, + /// The region that should outlive `shorter_fr`. + longer_fr: RegionVid, + /// The region that should be shorter, but we can't prove it. + shorter_fr: RegionVid, + /// Indicates whether this is a reported error. We currently only report the first error + /// encountered and leave the rest unreported so as not to overwhelm the user. + is_reported: bool, + }, +} + +/// Information about the various region constraints involved in a borrow checker error. +#[derive(Clone, Debug)] +pub struct ErrorConstraintInfo { + // fr: outlived_fr + pub(super) fr: RegionVid, + pub(super) fr_is_local: bool, + pub(super) outlived_fr: RegionVid, + pub(super) outlived_fr_is_local: bool, + + // Category and span for best blame constraint + pub(super) category: ConstraintCategory, + pub(super) span: Span, +} + +impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { + /// Converts a region inference variable into a `ty::Region` that + /// we can use for error reporting. If `r` is universally bound, + /// then we use the name that we have on record for it. If `r` is + /// existentially bound, then we check its inferred value and try + /// to find a good name from that. Returns `None` if we can't find + /// one (e.g., this is just some random part of the CFG). + pub(super) fn to_error_region(&self, r: RegionVid) -> Option> { + self.to_error_region_vid(r).and_then(|r| self.regioncx.region_definition(r).external_name) + } + + /// Returns the `RegionVid` corresponding to the region returned by + /// `to_error_region`. + pub(super) fn to_error_region_vid(&self, r: RegionVid) -> Option { + if self.regioncx.universal_regions().is_universal_region(r) { + Some(r) + } else { + // We just want something nameable, even if it's not + // actually an upper bound. + let upper_bound = self.regioncx.approx_universal_upper_bound(r); + + if self.regioncx.upper_bound_in_region_scc(r, upper_bound) { + self.to_error_region_vid(upper_bound) + } else { + None + } + } + } + + /// Returns `true` if a closure is inferred to be an `FnMut` closure. + fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { + if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) { + if let ty::BoundRegionKind::BrEnv = free_region.bound_region { + if let DefiningTy::Closure(_, substs) = + self.regioncx.universal_regions().defining_ty + { + return substs.as_closure().kind() == ty::ClosureKind::FnMut; + } + } + } + + false + } + + /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`. + pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) { + // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are + // buffered in the `MirBorrowckCtxt`. + + let mut outlives_suggestion = OutlivesSuggestionBuilder::default(); + + for nll_error in nll_errors.into_iter() { + match nll_error { + RegionErrorKind::TypeTestError { type_test } => { + // Try to convert the lower-bound region into something named we can print for the user. + let lower_bound_region = self.to_error_region(type_test.lower_bound); + + let type_test_span = type_test.locations.span(&self.body); + + if let Some(lower_bound_region) = lower_bound_region { + self.infcx + .construct_generic_bound_failure( + type_test_span, + None, + type_test.generic_kind, + lower_bound_region, + ) + .buffer(&mut self.errors_buffer); + } else { + // FIXME. We should handle this case better. It + // indicates that we have e.g., some region variable + // whose value is like `'a+'b` where `'a` and `'b` are + // distinct unrelated univesal regions that are not + // known to outlive one another. It'd be nice to have + // some examples where this arises to decide how best + // to report it; we could probably handle it by + // iterating over the universal regions and reporting + // an error that multiple bounds are required. + self.infcx + .tcx + .sess + .struct_span_err( + type_test_span, + &format!("`{}` does not live long enough", type_test.generic_kind), + ) + .buffer(&mut self.errors_buffer); + } + } + + RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => { + let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); + let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); + unexpected_hidden_region_diagnostic( + self.infcx.tcx, + span, + named_ty, + named_region, + ) + .buffer(&mut self.errors_buffer); + } + + RegionErrorKind::BoundUniversalRegionError { + longer_fr, + placeholder, + error_element, + } => { + let error_vid = self.regioncx.region_from_element(longer_fr, &error_element); + + // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. + let (_, cause) = self.regioncx.find_outlives_blame_span( + &self.body, + longer_fr, + NllRegionVariableOrigin::Placeholder(placeholder), + error_vid, + ); + + let universe = placeholder.universe; + let universe_info = self.regioncx.universe_info(universe); + + universe_info.report_error(self, placeholder, error_element, cause); + } + + RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { + if is_reported { + self.report_region_error( + longer_fr, + fr_origin, + shorter_fr, + &mut outlives_suggestion, + ); + } else { + // We only report the first error, so as not to overwhelm the user. See + // `RegRegionErrorKind` docs. + // + // FIXME: currently we do nothing with these, but perhaps we can do better? + // FIXME: try collecting these constraints on the outlives suggestion + // builder. Does it make the suggestions any better? + debug!( + "Unreported region error: can't prove that {:?}: {:?}", + longer_fr, shorter_fr + ); + } + } + } + } + + // Emit one outlives suggestions for each MIR def we borrowck + outlives_suggestion.add_suggestion(self); + } + + /// Report an error because the universal region `fr` was required to outlive + /// `outlived_fr` but it is not known to do so. For example: + /// + /// ``` + /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } + /// ``` + /// + /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. + pub(crate) fn report_region_error( + &mut self, + fr: RegionVid, + fr_origin: NllRegionVariableOrigin, + outlived_fr: RegionVid, + outlives_suggestion: &mut OutlivesSuggestionBuilder, + ) { + debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); + + let BlameConstraint { category, cause, variance_info, from_closure: _ } = + self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| { + self.regioncx.provides_universal_region(r, fr, outlived_fr) + }); + + debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); + // Check if we can use one of the "nice region errors". + if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { + let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f); + if let Some(diag) = nice.try_report_from_nll() { + diag.buffer(&mut self.errors_buffer); + return; + } + } + + let (fr_is_local, outlived_fr_is_local): (bool, bool) = ( + self.regioncx.universal_regions().is_local_free_region(fr), + self.regioncx.universal_regions().is_local_free_region(outlived_fr), + ); + + debug!( + "report_region_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}", + fr_is_local, outlived_fr_is_local, category + ); + + let errci = ErrorConstraintInfo { + fr, + outlived_fr, + fr_is_local, + outlived_fr_is_local, + category, + span: cause.span, + }; + + let mut diag = match (category, fr_is_local, outlived_fr_is_local) { + (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => { + self.report_fnmut_error(&errci, kind) + } + (ConstraintCategory::Assignment, true, false) + | (ConstraintCategory::CallArgument, true, false) => { + let mut db = self.report_escaping_data_error(&errci); + + outlives_suggestion.intermediate_suggestion(self, &errci, &mut db); + outlives_suggestion.collect_constraint(fr, outlived_fr); + + db + } + _ => { + let mut db = self.report_general_error(&errci); + + outlives_suggestion.intermediate_suggestion(self, &errci, &mut db); + outlives_suggestion.collect_constraint(fr, outlived_fr); + + db + } + }; + + match variance_info { + ty::VarianceDiagInfo::None => {} + ty::VarianceDiagInfo::Mut { kind, ty } => { + let kind_name = match kind { + ty::VarianceDiagMutKind::Ref => "reference", + ty::VarianceDiagMutKind::RawPtr => "pointer", + }; + diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",)); + diag.note(&format!("mutable {kind_name}s are invariant over their type parameter")); + diag.help("see for more information about variance"); + } + } + + diag.buffer(&mut self.errors_buffer); + } + + /// Report a specialized error when `FnMut` closures return a reference to a captured variable. + /// This function expects `fr` to be local and `outlived_fr` to not be local. + /// + /// ```text + /// error: captured variable cannot escape `FnMut` closure body + /// --> $DIR/issue-53040.rs:15:8 + /// | + /// LL | || &mut v; + /// | -- ^^^^^^ creates a reference to a captured variable which escapes the closure body + /// | | + /// | inferred to be a `FnMut` closure + /// | + /// = note: `FnMut` closures only have access to their captured variables while they are + /// executing... + /// = note: ...therefore, returned references to captured variables will escape the closure + /// ``` + fn report_fnmut_error( + &self, + errci: &ErrorConstraintInfo, + kind: ReturnConstraint, + ) -> DiagnosticBuilder<'tcx> { + let ErrorConstraintInfo { outlived_fr, span, .. } = errci; + + let mut diag = self + .infcx + .tcx + .sess + .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body"); + + let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; + if let ty::Opaque(def_id, _) = *output_ty.kind() { + output_ty = self.infcx.tcx.type_of(def_id) + }; + + debug!("report_fnmut_error: output_ty={:?}", output_ty); + + let message = match output_ty.kind() { + ty::Closure(_, _) => { + "returns a closure that contains a reference to a captured variable, which then \ + escapes the closure body" + } + ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did) => { + "returns an `async` block that contains a reference to a captured variable, which then \ + escapes the closure body" + } + _ => "returns a reference to a captured variable which escapes the closure body", + }; + + diag.span_label(*span, message); + + // FIXME(project-rfc-2229#48): This should store a captured_place not a hir id + if let ReturnConstraint::ClosureUpvar(upvar) = kind { + let def_id = match self.regioncx.universal_regions().defining_ty { + DefiningTy::Closure(def_id, _) => def_id, + ty => bug!("unexpected DefiningTy {:?}", ty), + }; + + let upvar_def_span = self.infcx.tcx.hir().span(upvar); + let upvar_span = self.infcx.tcx.upvars_mentioned(def_id).unwrap()[&upvar].span; + diag.span_label(upvar_def_span, "variable defined here"); + diag.span_label(upvar_span, "variable captured here"); + } + + if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() { + diag.span_label(fr_span, "inferred to be a `FnMut` closure"); + } + + diag.note( + "`FnMut` closures only have access to their captured variables while they are \ + executing...", + ); + diag.note("...therefore, they cannot allow references to captured variables to escape"); + + diag + } + + /// Reports an error specifically for when data is escaping a closure. + /// + /// ```text + /// error: borrowed data escapes outside of function + /// --> $DIR/lifetime-bound-will-change-warning.rs:44:5 + /// | + /// LL | fn test2<'a>(x: &'a Box) { + /// | - `x` is a reference that is only valid in the function body + /// LL | // but ref_obj will not, so warn. + /// LL | ref_obj(x) + /// | ^^^^^^^^^^ `x` escapes the function body here + /// ``` + fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> { + let ErrorConstraintInfo { span, category, .. } = errci; + + let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( + self.infcx.tcx, + &self.body, + &self.local_names, + &self.upvars, + errci.fr, + ); + let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( + self.infcx.tcx, + &self.body, + &self.local_names, + &self.upvars, + errci.outlived_fr, + ); + + let (_, escapes_from) = self + .infcx + .tcx + .article_and_description(self.regioncx.universal_regions().defining_ty.def_id()); + + // Revert to the normal error in these cases. + // Assignments aren't "escapes" in function items. + if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none()) + || (*category == ConstraintCategory::Assignment + && self.regioncx.universal_regions().defining_ty.is_fn_def()) + || self.regioncx.universal_regions().defining_ty.is_const() + { + return self.report_general_error(&ErrorConstraintInfo { + fr_is_local: true, + outlived_fr_is_local: false, + ..*errci + }); + } + + let mut diag = + borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from); + + if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span { + diag.span_label( + outlived_fr_span, + format!( + "`{}` declared here, outside of the {} body", + outlived_fr_name, escapes_from + ), + ); + } + + if let Some((Some(fr_name), fr_span)) = fr_name_and_span { + diag.span_label( + fr_span, + format!( + "`{}` is a reference that is only valid in the {} body", + fr_name, escapes_from + ), + ); + + diag.span_label(*span, format!("`{}` escapes the {} body here", fr_name, escapes_from)); + } + + // Only show an extra note if we can find an 'error region' for both of the region + // variables. This avoids showing a noisy note that just mentions 'synthetic' regions + // that don't help the user understand the error. + if self.to_error_region(errci.fr).is_some() + && self.to_error_region(errci.outlived_fr).is_some() + { + let fr_region_name = self.give_region_a_name(errci.fr).unwrap(); + fr_region_name.highlight_region_name(&mut diag); + let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap(); + outlived_fr_region_name.highlight_region_name(&mut diag); + + diag.span_label( + *span, + format!( + "{}requires that `{}` must outlive `{}`", + category.description(), + fr_region_name, + outlived_fr_region_name, + ), + ); + } + diag + } + + /// Reports a region inference error for the general case with named/synthesized lifetimes to + /// explain what is happening. + /// + /// ```text + /// error: unsatisfied lifetime constraints + /// --> $DIR/regions-creating-enums3.rs:17:5 + /// | + /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> { + /// | -- -- lifetime `'b` defined here + /// | | + /// | lifetime `'a` defined here + /// LL | ast::add(x, y) + /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it + /// | is returning data with lifetime `'b` + /// ``` + fn report_general_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> { + let ErrorConstraintInfo { + fr, + fr_is_local, + outlived_fr, + outlived_fr_is_local, + span, + category, + .. + } = errci; + + let mut diag = + self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough"); + + let (_, mir_def_name) = + self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id()); + + let fr_name = self.give_region_a_name(*fr).unwrap(); + fr_name.highlight_region_name(&mut diag); + let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap(); + outlived_fr_name.highlight_region_name(&mut diag); + + match (category, outlived_fr_is_local, fr_is_local) { + (ConstraintCategory::Return(_), true, _) => { + diag.span_label( + *span, + format!( + "{} was supposed to return data with lifetime `{}` but it is returning \ + data with lifetime `{}`", + mir_def_name, outlived_fr_name, fr_name + ), + ); + } + _ => { + diag.span_label( + *span, + format!( + "{}requires that `{}` must outlive `{}`", + category.description(), + fr_name, + outlived_fr_name, + ), + ); + } + } + + self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); + + diag + } + + /// Adds a suggestion to errors where an `impl Trait` is returned. + /// + /// ```text + /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as + /// a constraint + /// | + /// LL | fn iter_values_anon(&self) -> impl Iterator + 'a { + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// ``` + fn add_static_impl_trait_suggestion( + &self, + diag: &mut DiagnosticBuilder<'tcx>, + fr: RegionVid, + // We need to pass `fr_name` - computing it again will label it twice. + fr_name: RegionName, + outlived_fr: RegionVid, + ) { + if let (Some(f), Some(ty::RegionKind::ReStatic)) = + (self.to_error_region(fr), self.to_error_region(outlived_fr)) + { + if let Some(&ty::Opaque(did, substs)) = self + .infcx + .tcx + .is_suitable_region(f) + .map(|r| r.def_id) + .and_then(|id| self.infcx.tcx.return_type_impl_trait(id)) + .map(|(ty, _)| ty.kind()) + { + // Check whether or not the impl trait return type is intended to capture + // data with the static lifetime. + // + // eg. check for `impl Trait + 'static` instead of `impl Trait`. + let has_static_predicate = { + let bounds = self.infcx.tcx.explicit_item_bounds(did); + + let mut found = false; + for (bound, _) in bounds { + if let ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, r)) = + bound.kind().skip_binder() + { + let r = r.subst(self.infcx.tcx, substs); + if let ty::RegionKind::ReStatic = r { + found = true; + break; + } else { + // If there's already a lifetime bound, don't + // suggest anything. + return; + } + } + } + + found + }; + + debug!( + "add_static_impl_trait_suggestion: has_static_predicate={:?}", + has_static_predicate + ); + let static_str = kw::StaticLifetime; + // If there is a static predicate, then the only sensible suggestion is to replace + // fr with `'static`. + if has_static_predicate { + diag.help(&format!("consider replacing `{}` with `{}`", fr_name, static_str)); + } else { + // Otherwise, we should suggest adding a constraint on the return type. + let span = self.infcx.tcx.def_span(did); + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + let suggestable_fr_name = if fr_name.was_named() { + fr_name.to_string() + } else { + "'_".to_string() + }; + let span = if snippet.ends_with(';') { + // `type X = impl Trait;` + span.with_hi(span.hi() - BytePos(1)) + } else { + span + }; + let suggestion = format!(" + {}", suggestable_fr_name); + let span = span.shrink_to_hi(); + diag.span_suggestion( + span, + &format!( + "to allow this `impl Trait` to capture borrowed data with lifetime \ + `{}`, add `{}` as a bound", + fr_name, suggestable_fr_name, + ), + suggestion, + Applicability::MachineApplicable, + ); + } + } + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/region_name.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/region_name.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/region_name.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/region_name.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,844 @@ +use std::fmt::{self, Display}; +use std::iter; + +use rustc_errors::DiagnosticBuilder; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_middle::ty::print::RegionHighlightMode; +use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; +use rustc_middle::ty::{self, RegionVid, Ty}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{Span, DUMMY_SP}; + +use crate::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt}; + +/// A name for a particular region used in emitting diagnostics. This name could be a generated +/// name like `'1`, a name used by the user like `'a`, or a name like `'static`. +#[derive(Debug, Clone)] +crate struct RegionName { + /// The name of the region (interned). + crate name: Symbol, + /// Where the region comes from. + crate source: RegionNameSource, +} + +/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that +/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`. +/// This helps to print the right kinds of diagnostics. +#[derive(Debug, Clone)] +crate enum RegionNameSource { + /// A bound (not free) region that was substituted at the def site (not an HRTB). + NamedEarlyBoundRegion(Span), + /// A free region that the user has a name (`'a`) for. + NamedFreeRegion(Span), + /// The `'static` region. + Static, + /// The free region corresponding to the environment of a closure. + SynthesizedFreeEnvRegion(Span, String), + /// The region corresponding to an argument. + AnonRegionFromArgument(RegionNameHighlight), + /// The region corresponding to a closure upvar. + AnonRegionFromUpvar(Span, String), + /// The region corresponding to the return type of a closure. + AnonRegionFromOutput(RegionNameHighlight, String), + /// The region from a type yielded by a generator. + AnonRegionFromYieldTy(Span, String), + /// An anonymous region from an async fn. + AnonRegionFromAsyncFn(Span), +} + +/// Describes what to highlight to explain to the user that we're giving an anonymous region a +/// synthesized name, and how to highlight it. +#[derive(Debug, Clone)] +crate enum RegionNameHighlight { + /// The anonymous region corresponds to a reference that was found by traversing the type in the HIR. + MatchedHirTy(Span), + /// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union. + MatchedAdtAndSegment(Span), + /// The anonymous region corresponds to a region where the type annotation is completely missing + /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference. + CannotMatchHirTy(Span, String), + /// The anonymous region corresponds to a region where the type annotation is completely missing + /// from the code, and *even if* we print out the full name of the type, the region name won't + /// be included. This currently occurs for opaque types like `impl Future`. + Occluded(Span, String), +} + +impl RegionName { + crate fn was_named(&self) -> bool { + match self.source { + RegionNameSource::NamedEarlyBoundRegion(..) + | RegionNameSource::NamedFreeRegion(..) + | RegionNameSource::Static => true, + RegionNameSource::SynthesizedFreeEnvRegion(..) + | RegionNameSource::AnonRegionFromArgument(..) + | RegionNameSource::AnonRegionFromUpvar(..) + | RegionNameSource::AnonRegionFromOutput(..) + | RegionNameSource::AnonRegionFromYieldTy(..) + | RegionNameSource::AnonRegionFromAsyncFn(..) => false, + } + } + + crate fn span(&self) -> Option { + match self.source { + RegionNameSource::Static => None, + RegionNameSource::NamedEarlyBoundRegion(span) + | RegionNameSource::NamedFreeRegion(span) + | RegionNameSource::SynthesizedFreeEnvRegion(span, _) + | RegionNameSource::AnonRegionFromUpvar(span, _) + | RegionNameSource::AnonRegionFromYieldTy(span, _) + | RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span), + RegionNameSource::AnonRegionFromArgument(ref highlight) + | RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight { + RegionNameHighlight::MatchedHirTy(span) + | RegionNameHighlight::MatchedAdtAndSegment(span) + | RegionNameHighlight::CannotMatchHirTy(span, _) + | RegionNameHighlight::Occluded(span, _) => Some(span), + }, + } + } + + crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) { + match &self.source { + RegionNameSource::NamedFreeRegion(span) + | RegionNameSource::NamedEarlyBoundRegion(span) => { + diag.span_label(*span, format!("lifetime `{}` defined here", self)); + } + RegionNameSource::SynthesizedFreeEnvRegion(span, note) => { + diag.span_label( + *span, + format!("lifetime `{}` represents this closure's body", self), + ); + diag.note(¬e); + } + RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy( + span, + type_name, + )) => { + diag.span_label(*span, format!("has type `{}`", type_name)); + } + RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span)) + | RegionNameSource::AnonRegionFromOutput(RegionNameHighlight::MatchedHirTy(span), _) + | RegionNameSource::AnonRegionFromAsyncFn(span) => { + diag.span_label( + *span, + format!("let's call the lifetime of this reference `{}`", self), + ); + } + RegionNameSource::AnonRegionFromArgument( + RegionNameHighlight::MatchedAdtAndSegment(span), + ) + | RegionNameSource::AnonRegionFromOutput( + RegionNameHighlight::MatchedAdtAndSegment(span), + _, + ) => { + diag.span_label(*span, format!("let's call this `{}`", self)); + } + RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::Occluded( + span, + type_name, + )) => { + diag.span_label( + *span, + format!("lifetime `{}` appears in the type {}", self, type_name), + ); + } + RegionNameSource::AnonRegionFromOutput( + RegionNameHighlight::Occluded(span, type_name), + mir_description, + ) => { + diag.span_label( + *span, + format!( + "return type{} `{}` contains a lifetime `{}`", + mir_description, type_name, self + ), + ); + } + RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => { + diag.span_label( + *span, + format!("lifetime `{}` appears in the type of `{}`", self, upvar_name), + ); + } + RegionNameSource::AnonRegionFromOutput( + RegionNameHighlight::CannotMatchHirTy(span, type_name), + mir_description, + ) => { + diag.span_label(*span, format!("return type{} is {}", mir_description, type_name)); + } + RegionNameSource::AnonRegionFromYieldTy(span, type_name) => { + diag.span_label(*span, format!("yield type is {}", type_name)); + } + RegionNameSource::Static => {} + } + } +} + +impl Display for RegionName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name) + } +} + +impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { + crate fn mir_def_id(&self) -> hir::def_id::LocalDefId { + self.body.source.def_id().as_local().unwrap() + } + + crate fn mir_hir_id(&self) -> hir::HirId { + self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id()) + } + + /// Generate a synthetic region named `'N`, where `N` is the next value of the counter. Then, + /// increment the counter. + /// + /// This is _not_ idempotent. Call `give_region_a_name` when possible. + fn synthesize_region_name(&self) -> Symbol { + let c = self.next_region_name.replace_with(|counter| *counter + 1); + Symbol::intern(&format!("'{:?}", c)) + } + + /// Maps from an internal MIR region vid to something that we can + /// report to the user. In some cases, the region vids will map + /// directly to lifetimes that the user has a name for (e.g., + /// `'static`). But frequently they will not, in which case we + /// have to find some way to identify the lifetime to the user. To + /// that end, this function takes a "diagnostic" so that it can + /// create auxiliary notes as needed. + /// + /// The names are memoized, so this is both cheap to recompute and idempotent. + /// + /// Example (function arguments): + /// + /// Suppose we are trying to give a name to the lifetime of the + /// reference `x`: + /// + /// ``` + /// fn foo(x: &u32) { .. } + /// ``` + /// + /// This function would create a label like this: + /// + /// ```text + /// | fn foo(x: &u32) { .. } + /// ------- fully elaborated type of `x` is `&'1 u32` + /// ``` + /// + /// and then return the name `'1` for us to use. + crate fn give_region_a_name(&self, fr: RegionVid) -> Option { + debug!( + "give_region_a_name(fr={:?}, counter={:?})", + fr, + self.next_region_name.try_borrow().unwrap() + ); + + assert!(self.regioncx.universal_regions().is_universal_region(fr)); + + if let Some(value) = self.region_names.try_borrow_mut().unwrap().get(&fr) { + return Some(value.clone()); + } + + let value = self + .give_name_from_error_region(fr) + .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)); + + if let Some(ref value) = value { + self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); + } + + debug!("give_region_a_name: gave name {:?}", value); + value + } + + /// Checks for the case where `fr` maps to something that the + /// *user* has a name for. In that case, we'll be able to map + /// `fr` to a `Region<'tcx>`, and that region will be one of + /// named variants. + fn give_name_from_error_region(&self, fr: RegionVid) -> Option { + let error_region = self.to_error_region(fr)?; + + let tcx = self.infcx.tcx; + + debug!("give_region_a_name: error_region = {:?}", error_region); + match error_region { + ty::ReEarlyBound(ebr) => { + if ebr.has_name() { + let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP); + Some(RegionName { + name: ebr.name, + source: RegionNameSource::NamedEarlyBoundRegion(span), + }) + } else { + None + } + } + + ty::ReStatic => { + Some(RegionName { name: kw::StaticLifetime, source: RegionNameSource::Static }) + } + + ty::ReFree(free_region) => match free_region.bound_region { + ty::BoundRegionKind::BrNamed(region_def_id, name) => { + // Get the span to point to, even if we don't use the name. + let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP); + debug!( + "bound region named: {:?}, is_named: {:?}", + name, + free_region.bound_region.is_named() + ); + + if free_region.bound_region.is_named() { + // A named region that is actually named. + Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) + } else { + // If we spuriously thought that the region is named, we should let the + // system generate a true name for error messages. Currently this can + // happen if we have an elided name in an async fn for example: the + // compiler will generate a region named `'_`, but reporting such a name is + // not actually useful, so we synthesize a name for it instead. + let name = self.synthesize_region_name(); + Some(RegionName { + name, + source: RegionNameSource::AnonRegionFromAsyncFn(span), + }) + } + } + + ty::BoundRegionKind::BrEnv => { + let def_ty = self.regioncx.universal_regions().defining_ty; + + if let DefiningTy::Closure(_, substs) = def_ty { + let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) = + tcx.hir().expect_expr(self.mir_hir_id()).kind + { + span + } else { + bug!("Closure is not defined by a closure expr"); + }; + let region_name = self.synthesize_region_name(); + + let closure_kind_ty = substs.as_closure().kind_ty(); + let note = match closure_kind_ty.to_opt_closure_kind() { + Some(ty::ClosureKind::Fn) => { + "closure implements `Fn`, so references to captured variables \ + can't escape the closure" + } + Some(ty::ClosureKind::FnMut) => { + "closure implements `FnMut`, so references to captured variables \ + can't escape the closure" + } + Some(ty::ClosureKind::FnOnce) => { + bug!("BrEnv in a `FnOnce` closure"); + } + None => bug!("Closure kind not inferred in borrow check"), + }; + + Some(RegionName { + name: region_name, + source: RegionNameSource::SynthesizedFreeEnvRegion( + args_span, + note.to_string(), + ), + }) + } else { + // Can't have BrEnv in functions, constants or generators. + bug!("BrEnv outside of closure."); + } + } + + ty::BoundRegionKind::BrAnon(_) => None, + }, + + ty::ReLateBound(..) + | ty::ReVar(..) + | ty::RePlaceholder(..) + | ty::ReEmpty(_) + | ty::ReErased => None, + } + } + + /// Finds an argument that contains `fr` and label it with a fully + /// elaborated type, returning something like `'1`. Result looks + /// like: + /// + /// ```text + /// | fn foo(x: &u32) { .. } + /// ------- fully elaborated type of `x` is `&'1 u32` + /// ``` + fn give_name_if_anonymous_region_appears_in_arguments( + &self, + fr: RegionVid, + ) -> Option { + let implicit_inputs = self.regioncx.universal_regions().defining_ty.implicit_inputs(); + let argument_index = self.regioncx.get_argument_index_for_region(self.infcx.tcx, fr)?; + + let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys + [implicit_inputs + argument_index]; + let (_, span) = self.regioncx.get_argument_name_and_span_for_region( + &self.body, + &self.local_names, + argument_index, + ); + + let highlight = self + .get_argument_hir_ty_for_highlighting(argument_index) + .and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty)) + .unwrap_or_else(|| { + // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to + // the anonymous region. If it succeeds, the `synthesize_region_name` call below + // will increment the counter, "reserving" the number we just used. + let counter = *self.next_region_name.try_borrow().unwrap(); + self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter) + }); + + Some(RegionName { + name: self.synthesize_region_name(), + source: RegionNameSource::AnonRegionFromArgument(highlight), + }) + } + + fn get_argument_hir_ty_for_highlighting( + &self, + argument_index: usize, + ) -> Option<&hir::Ty<'tcx>> { + let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(self.mir_hir_id())?; + let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?; + match argument_hir_ty.kind { + // This indicates a variable with no type annotation, like + // `|x|`... in that case, we can't highlight the type but + // must highlight the variable. + // NOTE(eddyb) this is handled in/by the sole caller + // (`give_name_if_anonymous_region_appears_in_arguments`). + hir::TyKind::Infer => None, + + _ => Some(argument_hir_ty), + } + } + + /// Attempts to highlight the specific part of a type in an argument + /// that has no type annotation. + /// For example, we might produce an annotation like this: + /// + /// ```text + /// | foo(|a, b| b) + /// | - - + /// | | | + /// | | has type `&'1 u32` + /// | has type `&'2 u32` + /// ``` + fn highlight_if_we_cannot_match_hir_ty( + &self, + needle_fr: RegionVid, + ty: Ty<'tcx>, + span: Span, + counter: usize, + ) -> RegionNameHighlight { + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(needle_fr, counter); + let type_name = + self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; + + debug!( + "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", + type_name, needle_fr + ); + if type_name.contains(&format!("'{}", counter)) { + // Only add a label if we can confirm that a region was labelled. + RegionNameHighlight::CannotMatchHirTy(span, type_name) + } else { + RegionNameHighlight::Occluded(span, type_name) + } + } + + /// Attempts to highlight the specific part of a type annotation + /// that contains the anonymous reference we want to give a name + /// to. For example, we might produce an annotation like this: + /// + /// ```text + /// | fn a(items: &[T]) -> Box> { + /// | - let's call the lifetime of this reference `'1` + /// ``` + /// + /// the way this works is that we match up `ty`, which is + /// a `Ty<'tcx>` (the internal form of the type) with + /// `hir_ty`, a `hir::Ty` (the syntax of the type + /// annotation). We are descending through the types stepwise, + /// looking in to find the region `needle_fr` in the internal + /// type. Once we find that, we can use the span of the `hir::Ty` + /// to add the highlight. + /// + /// This is a somewhat imperfect process, so along the way we also + /// keep track of the **closest** type we've found. If we fail to + /// find the exact `&` or `'_` to highlight, then we may fall back + /// to highlighting that closest type instead. + fn highlight_if_we_can_match_hir_ty( + &self, + needle_fr: RegionVid, + ty: Ty<'tcx>, + hir_ty: &hir::Ty<'_>, + ) -> Option { + let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)]; + + while let Some((ty, hir_ty)) = search_stack.pop() { + match (&ty.kind(), &hir_ty.kind) { + // Check if the `ty` is `&'X ..` where `'X` + // is the region we are looking for -- if so, and we have a `&T` + // on the RHS, then we want to highlight the `&` like so: + // + // & + // - let's call the lifetime of this reference `'1` + ( + ty::Ref(region, referent_ty, _), + hir::TyKind::Rptr(_lifetime, referent_hir_ty), + ) => { + if region.to_region_vid() == needle_fr { + // Just grab the first character, the `&`. + let source_map = self.infcx.tcx.sess.source_map(); + let ampersand_span = source_map.start_point(hir_ty.span); + + return Some(RegionNameHighlight::MatchedHirTy(ampersand_span)); + } + + // Otherwise, let's descend into the referent types. + search_stack.push((referent_ty, &referent_hir_ty.ty)); + } + + // Match up something like `Foo<'1>` + ( + ty::Adt(_adt_def, substs), + hir::TyKind::Path(hir::QPath::Resolved(None, path)), + ) => { + match path.res { + // Type parameters of the type alias have no reason to + // be the same as those of the ADT. + // FIXME: We should be able to do something similar to + // match_adt_and_segment in this case. + Res::Def(DefKind::TyAlias, _) => (), + _ => { + if let Some(last_segment) = path.segments.last() { + if let Some(highlight) = self.match_adt_and_segment( + substs, + needle_fr, + last_segment, + search_stack, + ) { + return Some(highlight); + } + } + } + } + } + + // The following cases don't have lifetimes, so we + // just worry about trying to match up the rustc type + // with the HIR types: + (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { + search_stack + .extend(iter::zip(elem_tys.iter().map(|k| k.expect_ty()), *elem_hir_tys)); + } + + (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) + | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => { + search_stack.push((elem_ty, elem_hir_ty)); + } + + (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => { + search_stack.push((mut_ty.ty, &mut_hir_ty.ty)); + } + + _ => { + // FIXME there are other cases that we could trace + } + } + } + + None + } + + /// We've found an enum/struct/union type with the substitutions + /// `substs` and -- in the HIR -- a path type with the final + /// segment `last_segment`. Try to find a `'_` to highlight in + /// the generic args (or, if not, to produce new zipped pairs of + /// types+hir to search through). + fn match_adt_and_segment<'hir>( + &self, + substs: SubstsRef<'tcx>, + needle_fr: RegionVid, + last_segment: &'hir hir::PathSegment<'hir>, + search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, + ) -> Option { + // Did the user give explicit arguments? (e.g., `Foo<..>`) + let args = last_segment.args.as_ref()?; + let lifetime = + self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; + match lifetime.name { + hir::LifetimeName::Param(_) + | hir::LifetimeName::Error + | hir::LifetimeName::Static + | hir::LifetimeName::Underscore => { + let lifetime_span = lifetime.span; + Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) + } + + hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => { + // In this case, the user left off the lifetime; so + // they wrote something like: + // + // ``` + // x: Foo + // ``` + // + // where the fully elaborated form is `Foo<'_, '1, + // T>`. We don't consider this a match; instead we let + // the "fully elaborated" type fallback above handle + // it. + None + } + } + } + + /// We've found an enum/struct/union type with the substitutions + /// `substs` and -- in the HIR -- a path with the generic + /// arguments `args`. If `needle_fr` appears in the args, return + /// the `hir::Lifetime` that corresponds to it. If not, push onto + /// `search_stack` the types+hir to search through. + fn try_match_adt_and_generic_args<'hir>( + &self, + substs: SubstsRef<'tcx>, + needle_fr: RegionVid, + args: &'hir hir::GenericArgs<'hir>, + search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, + ) -> Option<&'hir hir::Lifetime> { + for (kind, hir_arg) in iter::zip(substs, args.args) { + match (kind.unpack(), hir_arg) { + (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { + if r.to_region_vid() == needle_fr { + return Some(lt); + } + } + + (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => { + search_stack.push((ty, hir_ty)); + } + + (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { + // Lifetimes cannot be found in consts, so we don't need + // to search anything here. + } + + ( + GenericArgKind::Lifetime(_) + | GenericArgKind::Type(_) + | GenericArgKind::Const(_), + _, + ) => { + // HIR lowering sometimes doesn't catch this in erroneous + // programs, so we need to use delay_span_bug here. See #82126. + self.infcx.tcx.sess.delay_span_bug( + hir_arg.span(), + &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg), + ); + } + } + } + + None + } + + /// Finds a closure upvar that contains `fr` and label it with a + /// fully elaborated type, returning something like `'1`. Result + /// looks like: + /// + /// ```text + /// | let x = Some(&22); + /// - fully elaborated type of `x` is `Option<&'1 u32>` + /// ``` + fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option { + let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; + let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( + self.infcx.tcx, + &self.upvars, + upvar_index, + ); + let region_name = self.synthesize_region_name(); + + Some(RegionName { + name: region_name, + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()), + }) + } + + /// Checks for arguments appearing in the (closure) return type. It + /// must be a closure since, in a free fn, such an argument would + /// have to either also appear in an argument (if using elision) + /// or be early bound (named, not in argument). + fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option { + let tcx = self.infcx.tcx; + let hir = tcx.hir(); + + let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; + debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty); + if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { + return None; + } + + let mir_hir_id = self.mir_hir_id(); + + let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) { + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_, return_ty, body_id, span, _), + .. + }) => { + let (mut span, mut hir_ty) = match return_ty.output { + hir::FnRetTy::DefaultReturn(_) => { + (tcx.sess.source_map().end_point(*span), None) + } + hir::FnRetTy::Return(hir_ty) => (return_ty.output.span(), Some(hir_ty)), + }; + let mir_description = match hir.body(*body_id).generator_kind { + Some(hir::GeneratorKind::Async(gen)) => match gen { + hir::AsyncGeneratorKind::Block => " of async block", + hir::AsyncGeneratorKind::Closure => " of async closure", + hir::AsyncGeneratorKind::Fn => { + let parent_item = hir.get(hir.get_parent_item(mir_hir_id)); + let output = &parent_item + .fn_decl() + .expect("generator lowered from async fn should be in fn") + .output; + span = output.span(); + if let hir::FnRetTy::Return(ret) = output { + hir_ty = Some(self.get_future_inner_return_ty(*ret)); + } + " of async function" + } + }, + Some(hir::GeneratorKind::Gen) => " of generator", + None => " of closure", + }; + (span, mir_description, hir_ty) + } + node => match node.fn_decl() { + Some(fn_decl) => { + let hir_ty = match fn_decl.output { + hir::FnRetTy::DefaultReturn(_) => None, + hir::FnRetTy::Return(ty) => Some(ty), + }; + (fn_decl.output.span(), "", hir_ty) + } + None => (self.body.span, "", None), + }, + }; + + let highlight = hir_ty + .and_then(|hir_ty| self.highlight_if_we_can_match_hir_ty(fr, return_ty, hir_ty)) + .unwrap_or_else(|| { + // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to + // the anonymous region. If it succeeds, the `synthesize_region_name` call below + // will increment the counter, "reserving" the number we just used. + let counter = *self.next_region_name.try_borrow().unwrap(); + self.highlight_if_we_cannot_match_hir_ty(fr, return_ty, return_span, counter) + }); + + Some(RegionName { + name: self.synthesize_region_name(), + source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description.to_string()), + }) + } + + /// From the [`hir::Ty`] of an async function's lowered return type, + /// retrieve the `hir::Ty` representing the type the user originally wrote. + /// + /// e.g. given the function: + /// + /// ``` + /// async fn foo() -> i32 {} + /// ``` + /// + /// this function, given the lowered return type of `foo`, an [`OpaqueDef`] that implements `Future`, + /// returns the `i32`. + /// + /// [`OpaqueDef`]: hir::TyKind::OpaqueDef + fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { + let hir = self.infcx.tcx.hir(); + + if let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind { + let opaque_ty = hir.item(id); + if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { + bounds: + [hir::GenericBound::LangItemTrait( + hir::LangItem::Future, + _, + _, + hir::GenericArgs { + bindings: + [hir::TypeBinding { + ident: Ident { name: sym::Output, .. }, + kind: hir::TypeBindingKind::Equality { ty }, + .. + }], + .. + }, + )], + .. + }) = opaque_ty.kind + { + ty + } else { + span_bug!( + hir_ty.span, + "bounds from lowered return type of async fn did not match expected format: {:?}", + opaque_ty + ); + } + } else { + span_bug!( + hir_ty.span, + "lowered return type of async fn is not OpaqueDef: {:?}", + hir_ty + ); + } + } + + fn give_name_if_anonymous_region_appears_in_yield_ty( + &self, + fr: RegionVid, + ) -> Option { + // Note: generators from `async fn` yield `()`, so we don't have to + // worry about them here. + let yield_ty = self.regioncx.universal_regions().yield_ty?; + debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty,); + + let tcx = self.infcx.tcx; + + if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) { + return None; + } + + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); + let type_name = + self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; + + let yield_span = match tcx.hir().get(self.mir_hir_id()) { + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_, _, _, span, _), .. + }) => (tcx.sess.source_map().end_point(*span)), + _ => self.body.span, + }; + + debug!( + "give_name_if_anonymous_region_appears_in_yield_ty: \ + type_name = {:?}, yield_span = {:?}", + yield_span, type_name, + ); + + Some(RegionName { + name: self.synthesize_region_name(), + source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), + }) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/var_name.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/var_name.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/var_name.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/diagnostics/var_name.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,129 @@ +use crate::Upvar; +use crate::{nll::ToRegionVid, region_infer::RegionInferenceContext}; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::{Body, Local}; +use rustc_middle::ty::{RegionVid, TyCtxt}; +use rustc_span::source_map::Span; +use rustc_span::symbol::Symbol; + +impl<'tcx> RegionInferenceContext<'tcx> { + crate fn get_var_name_and_span_for_region( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + local_names: &IndexVec>, + upvars: &[Upvar<'tcx>], + fr: RegionVid, + ) -> Option<(Option, Span)> { + debug!("get_var_name_and_span_for_region(fr={:?})", fr); + assert!(self.universal_regions().is_universal_region(fr)); + + debug!("get_var_name_and_span_for_region: attempting upvar"); + self.get_upvar_index_for_region(tcx, fr) + .map(|index| { + // FIXME(project-rfc-2229#8): Use place span for diagnostics + let (name, span) = self.get_upvar_name_and_span_for_region(tcx, upvars, index); + (Some(name), span) + }) + .or_else(|| { + debug!("get_var_name_and_span_for_region: attempting argument"); + self.get_argument_index_for_region(tcx, fr).map(|index| { + self.get_argument_name_and_span_for_region(body, local_names, index) + }) + }) + } + + /// Search the upvars (if any) to find one that references fr. Return its index. + crate fn get_upvar_index_for_region(&self, tcx: TyCtxt<'tcx>, fr: RegionVid) -> Option { + let upvar_index = + self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| { + debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty); + tcx.any_free_region_meets(&upvar_ty, |r| { + let r = r.to_region_vid(); + debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr); + r == fr + }) + })?; + + let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index); + + debug!( + "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}", + fr, upvar_index, upvar_ty, + ); + + Some(upvar_index) + } + + /// Given the index of an upvar, finds its name and the span from where it was + /// declared. + crate fn get_upvar_name_and_span_for_region( + &self, + tcx: TyCtxt<'tcx>, + upvars: &[Upvar<'tcx>], + upvar_index: usize, + ) -> (Symbol, Span) { + let upvar_hir_id = upvars[upvar_index].place.get_root_variable(); + debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id); + + let upvar_name = tcx.hir().name(upvar_hir_id); + let upvar_span = tcx.hir().span(upvar_hir_id); + debug!( + "get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}", + upvar_name, upvar_span + ); + + (upvar_name, upvar_span) + } + + /// Search the argument types for one that references fr (which should be a free region). + /// Returns Some(_) with the index of the input if one is found. + /// + /// N.B., in the case of a closure, the index is indexing into the signature as seen by the + /// user - in particular, index 0 is not the implicit self parameter. + crate fn get_argument_index_for_region( + &self, + tcx: TyCtxt<'tcx>, + fr: RegionVid, + ) -> Option { + let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); + let argument_index = + self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position( + |arg_ty| { + debug!("get_argument_index_for_region: arg_ty = {:?}", arg_ty); + tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr) + }, + )?; + + debug!( + "get_argument_index_for_region: found {:?} in argument {} which has type {:?}", + fr, + argument_index, + self.universal_regions().unnormalized_input_tys[argument_index], + ); + + Some(argument_index) + } + + /// Given the index of an argument, finds its name (if any) and the span from where it was + /// declared. + crate fn get_argument_name_and_span_for_region( + &self, + body: &Body<'tcx>, + local_names: &IndexVec>, + argument_index: usize, + ) -> (Option, Span) { + let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); + let argument_local = Local::new(implicit_inputs + argument_index + 1); + debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local); + + let argument_name = local_names[argument_local]; + let argument_span = body.local_decls[argument_local].source_info.span; + debug!( + "get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}", + argument_name, argument_span + ); + + (argument_name, argument_span) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/facts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/facts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/facts.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/facts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,212 @@ +use crate::location::{LocationIndex, LocationTable}; +use crate::BorrowIndex; +use polonius_engine::AllFacts as PoloniusFacts; +use polonius_engine::Atom; +use rustc_index::vec::Idx; +use rustc_middle::mir::Local; +use rustc_middle::ty::{RegionVid, TyCtxt}; +use rustc_mir_dataflow::move_paths::MovePathIndex; +use std::error::Error; +use std::fmt::Debug; +use std::fs::{self, File}; +use std::io::{BufWriter, Write}; +use std::path::Path; + +#[derive(Copy, Clone, Debug)] +pub struct RustcFacts; + +impl polonius_engine::FactTypes for RustcFacts { + type Origin = RegionVid; + type Loan = BorrowIndex; + type Point = LocationIndex; + type Variable = Local; + type Path = MovePathIndex; +} + +pub type AllFacts = PoloniusFacts; + +crate trait AllFactsExt { + /// Returns `true` if there is a need to gather `AllFacts` given the + /// current `-Z` flags. + fn enabled(tcx: TyCtxt<'_>) -> bool; + + fn write_to_dir( + &self, + dir: impl AsRef, + location_table: &LocationTable, + ) -> Result<(), Box>; +} + +impl AllFactsExt for AllFacts { + /// Return + fn enabled(tcx: TyCtxt<'_>) -> bool { + tcx.sess.opts.debugging_opts.nll_facts || tcx.sess.opts.debugging_opts.polonius + } + + fn write_to_dir( + &self, + dir: impl AsRef, + location_table: &LocationTable, + ) -> Result<(), Box> { + let dir: &Path = dir.as_ref(); + fs::create_dir_all(dir)?; + let wr = FactWriter { location_table, dir }; + macro_rules! write_facts_to_path { + ($wr:ident . write_facts_to_path($this:ident . [ + $($field:ident,)* + ])) => { + $( + $wr.write_facts_to_path( + &$this.$field, + &format!("{}.facts", stringify!($field)) + )?; + )* + } + } + write_facts_to_path! { + wr.write_facts_to_path(self.[ + loan_issued_at, + universal_region, + cfg_edge, + loan_killed_at, + subset_base, + loan_invalidated_at, + var_used_at, + var_defined_at, + var_dropped_at, + use_of_var_derefs_origin, + drop_of_var_derefs_origin, + child_path, + path_is_var, + path_assigned_at_base, + path_moved_at_base, + path_accessed_at_base, + known_placeholder_subset, + placeholder, + ]) + } + Ok(()) + } +} + +impl Atom for BorrowIndex { + fn index(self) -> usize { + Idx::index(self) + } +} + +impl Atom for LocationIndex { + fn index(self) -> usize { + Idx::index(self) + } +} + +struct FactWriter<'w> { + location_table: &'w LocationTable, + dir: &'w Path, +} + +impl<'w> FactWriter<'w> { + fn write_facts_to_path(&self, rows: &[T], file_name: &str) -> Result<(), Box> + where + T: FactRow, + { + let file = &self.dir.join(file_name); + let mut file = BufWriter::new(File::create(file)?); + for row in rows { + row.write(&mut file, self.location_table)?; + } + Ok(()) + } +} + +trait FactRow { + fn write( + &self, + out: &mut dyn Write, + location_table: &LocationTable, + ) -> Result<(), Box>; +} + +impl FactRow for RegionVid { + fn write( + &self, + out: &mut dyn Write, + location_table: &LocationTable, + ) -> Result<(), Box> { + write_row(out, location_table, &[self]) + } +} + +impl FactRow for (A, B) +where + A: FactCell, + B: FactCell, +{ + fn write( + &self, + out: &mut dyn Write, + location_table: &LocationTable, + ) -> Result<(), Box> { + write_row(out, location_table, &[&self.0, &self.1]) + } +} + +impl FactRow for (A, B, C) +where + A: FactCell, + B: FactCell, + C: FactCell, +{ + fn write( + &self, + out: &mut dyn Write, + location_table: &LocationTable, + ) -> Result<(), Box> { + write_row(out, location_table, &[&self.0, &self.1, &self.2]) + } +} + +impl FactRow for (A, B, C, D) +where + A: FactCell, + B: FactCell, + C: FactCell, + D: FactCell, +{ + fn write( + &self, + out: &mut dyn Write, + location_table: &LocationTable, + ) -> Result<(), Box> { + write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3]) + } +} + +fn write_row( + out: &mut dyn Write, + location_table: &LocationTable, + columns: &[&dyn FactCell], +) -> Result<(), Box> { + for (index, c) in columns.iter().enumerate() { + let tail = if index == columns.len() - 1 { "\n" } else { "\t" }; + write!(out, "{:?}{}", c.to_string(location_table), tail)?; + } + Ok(()) +} + +trait FactCell { + fn to_string(&self, location_table: &LocationTable) -> String; +} + +impl FactCell for A { + default fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{:?}", self) + } +} + +impl FactCell for LocationIndex { + fn to_string(&self, location_table: &LocationTable) -> String { + format!("{:?}", location_table.to_location(*self)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/invalidation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/invalidation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/invalidation.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/invalidation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,469 @@ +use rustc_data_structures::graph::dominators::Dominators; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue}; +use rustc_middle::mir::{BorrowKind, Mutability, Operand}; +use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; +use rustc_middle::mir::{Statement, StatementKind}; +use rustc_middle::ty::TyCtxt; +use std::iter; + +use crate::{ + borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth, + Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode, + Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind, +}; + +pub(super) fn generate_invalidates<'tcx>( + tcx: TyCtxt<'tcx>, + all_facts: &mut Option, + location_table: &LocationTable, + body: &Body<'tcx>, + borrow_set: &BorrowSet<'tcx>, +) { + if all_facts.is_none() { + // Nothing to do if we don't have any facts + return; + } + + if let Some(all_facts) = all_facts { + let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); + let dominators = body.dominators(); + let mut ig = InvalidationGenerator { + all_facts, + borrow_set, + tcx, + location_table, + body: &body, + dominators, + }; + ig.visit_body(body); + } +} + +struct InvalidationGenerator<'cx, 'tcx> { + tcx: TyCtxt<'tcx>, + all_facts: &'cx mut AllFacts, + location_table: &'cx LocationTable, + body: &'cx Body<'tcx>, + dominators: Dominators, + borrow_set: &'cx BorrowSet<'tcx>, +} + +/// Visits the whole MIR and generates `invalidates()` facts. +/// Most of the code implementing this was stolen from `borrow_check/mod.rs`. +impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + self.check_activations(location); + + match &statement.kind { + StatementKind::Assign(box (lhs, rhs)) => { + self.consume_rvalue(location, rhs); + + self.mutate_place(location, *lhs, Shallow(None), JustWrite); + } + StatementKind::FakeRead(box (_, _)) => { + // Only relevant for initialized/liveness/safety checks. + } + StatementKind::SetDiscriminant { place, variant_index: _ } => { + self.mutate_place(location, **place, Shallow(None), JustWrite); + } + StatementKind::LlvmInlineAsm(asm) => { + for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) { + if o.is_indirect { + // FIXME(eddyb) indirect inline asm outputs should + // be encoded through MIR place derefs instead. + self.access_place( + location, + *output, + (Deep, Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + ); + } else { + self.mutate_place( + location, + *output, + if o.is_rw { Deep } else { Shallow(None) }, + if o.is_rw { WriteAndRead } else { JustWrite }, + ); + } + } + for (_, input) in asm.inputs.iter() { + self.consume_operand(location, input); + } + } + StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + ref src, + ref dst, + ref count, + }) => { + self.consume_operand(location, src); + self.consume_operand(location, dst); + self.consume_operand(location, count); + } + StatementKind::Nop + | StatementKind::Coverage(..) + | StatementKind::AscribeUserType(..) + | StatementKind::Retag { .. } + | StatementKind::StorageLive(..) => { + // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant + // to borrow check. + } + StatementKind::StorageDead(local) => { + self.access_place( + location, + Place::from(*local), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + ); + } + } + + self.super_statement(statement, location); + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.check_activations(location); + + match &terminator.kind { + TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => { + self.consume_operand(location, discr); + } + TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => { + self.access_place( + location, + *drop_place, + (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + ); + } + TerminatorKind::DropAndReplace { + place: drop_place, + value: ref new_value, + target: _, + unwind: _, + } => { + self.mutate_place(location, *drop_place, Deep, JustWrite); + self.consume_operand(location, new_value); + } + TerminatorKind::Call { + ref func, + ref args, + destination, + cleanup: _, + from_hir_call: _, + fn_span: _, + } => { + self.consume_operand(location, func); + for arg in args { + self.consume_operand(location, arg); + } + if let Some((dest, _ /*bb*/)) = destination { + self.mutate_place(location, *dest, Deep, JustWrite); + } + } + TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { + self.consume_operand(location, cond); + use rustc_middle::mir::AssertKind; + if let AssertKind::BoundsCheck { ref len, ref index } = *msg { + self.consume_operand(location, len); + self.consume_operand(location, index); + } + } + TerminatorKind::Yield { ref value, resume, resume_arg, drop: _ } => { + self.consume_operand(location, value); + + // Invalidate all borrows of local places + let borrow_set = self.borrow_set; + let resume = self.location_table.start_index(resume.start_location()); + for (i, data) in borrow_set.iter_enumerated() { + if borrow_of_local_data(data.borrowed_place) { + self.all_facts.loan_invalidated_at.push((resume, i)); + } + } + + self.mutate_place(location, *resume_arg, Deep, JustWrite); + } + TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { + // Invalidate all borrows of local places + let borrow_set = self.borrow_set; + let start = self.location_table.start_index(location); + for (i, data) in borrow_set.iter_enumerated() { + if borrow_of_local_data(data.borrowed_place) { + self.all_facts.loan_invalidated_at.push((start, i)); + } + } + } + TerminatorKind::InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination: _, + } => { + for op in operands { + match *op { + InlineAsmOperand::In { reg: _, ref value } => { + self.consume_operand(location, value); + } + InlineAsmOperand::Out { reg: _, late: _, place, .. } => { + if let Some(place) = place { + self.mutate_place(location, place, Shallow(None), JustWrite); + } + } + InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { + self.consume_operand(location, in_value); + if let Some(out_place) = out_place { + self.mutate_place(location, out_place, Shallow(None), JustWrite); + } + } + InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { def_id: _ } => {} + } + } + } + TerminatorKind::Goto { target: _ } + | TerminatorKind::Abort + | TerminatorKind::Unreachable + | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } + | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { + // no data used, thus irrelevant to borrowck + } + } + + self.super_terminator(terminator, location); + } +} + +impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { + /// Simulates mutation of a place. + fn mutate_place( + &mut self, + location: Location, + place: Place<'tcx>, + kind: AccessDepth, + _mode: MutateMode, + ) { + self.access_place( + location, + place, + (kind, Write(WriteKind::Mutate)), + LocalMutationIsAllowed::ExceptUpvars, + ); + } + + /// Simulates consumption of an operand. + fn consume_operand(&mut self, location: Location, operand: &Operand<'tcx>) { + match *operand { + Operand::Copy(place) => { + self.access_place( + location, + place, + (Deep, Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + ); + } + Operand::Move(place) => { + self.access_place( + location, + place, + (Deep, Write(WriteKind::Move)), + LocalMutationIsAllowed::Yes, + ); + } + Operand::Constant(_) => {} + } + } + + // Simulates consumption of an rvalue + fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) { + match *rvalue { + Rvalue::Ref(_ /*rgn*/, bk, place) => { + let access_kind = match bk { + BorrowKind::Shallow => { + (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) + } + BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), + BorrowKind::Unique | BorrowKind::Mut { .. } => { + let wk = WriteKind::MutableBorrow(bk); + if allow_two_phase_borrow(bk) { + (Deep, Reservation(wk)) + } else { + (Deep, Write(wk)) + } + } + }; + + self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); + } + + Rvalue::AddressOf(mutability, place) => { + let access_kind = match mutability { + Mutability::Mut => ( + Deep, + Write(WriteKind::MutableBorrow(BorrowKind::Mut { + allow_two_phase_borrow: false, + })), + ), + Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), + }; + + self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); + } + + Rvalue::ThreadLocalRef(_) => {} + + Rvalue::Use(ref operand) + | Rvalue::Repeat(ref operand, _) + | Rvalue::UnaryOp(_ /*un_op*/, ref operand) + | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) + | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { + self.consume_operand(location, operand) + } + + Rvalue::Len(place) | Rvalue::Discriminant(place) => { + let af = match *rvalue { + Rvalue::Len(..) => Some(ArtificialField::ArrayLength), + Rvalue::Discriminant(..) => None, + _ => unreachable!(), + }; + self.access_place( + location, + place, + (Shallow(af), Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + ); + } + + Rvalue::BinaryOp(_bin_op, box (ref operand1, ref operand2)) + | Rvalue::CheckedBinaryOp(_bin_op, box (ref operand1, ref operand2)) => { + self.consume_operand(location, operand1); + self.consume_operand(location, operand2); + } + + Rvalue::NullaryOp(_op, _ty) => {} + + Rvalue::Aggregate(_, ref operands) => { + for operand in operands { + self.consume_operand(location, operand); + } + } + } + } + + /// Simulates an access to a place. + fn access_place( + &mut self, + location: Location, + place: Place<'tcx>, + kind: (AccessDepth, ReadOrWrite), + _is_local_mutation_allowed: LocalMutationIsAllowed, + ) { + let (sd, rw) = kind; + // note: not doing check_access_permissions checks because they don't generate invalidates + self.check_access_for_conflict(location, place, sd, rw); + } + + fn check_access_for_conflict( + &mut self, + location: Location, + place: Place<'tcx>, + sd: AccessDepth, + rw: ReadOrWrite, + ) { + debug!( + "invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \ + rw={:?})", + location, place, sd, rw, + ); + let tcx = self.tcx; + let body = self.body; + let borrow_set = self.borrow_set; + let indices = self.borrow_set.indices(); + each_borrow_involving_path( + self, + tcx, + body, + location, + (sd, place), + borrow_set, + indices, + |this, borrow_index, borrow| { + match (rw, borrow.kind) { + // Obviously an activation is compatible with its own + // reservation (or even prior activating uses of same + // borrow); so don't check if they interfere. + // + // NOTE: *reservations* do conflict with themselves; + // thus aren't injecting unsoundenss w/ this check.) + (Activation(_, activating), _) if activating == borrow_index => { + // Activating a borrow doesn't generate any invalidations, since we + // have already taken the reservation + } + + (Read(_), BorrowKind::Shallow | BorrowKind::Shared) + | ( + Read(ReadKind::Borrow(BorrowKind::Shallow)), + BorrowKind::Unique | BorrowKind::Mut { .. }, + ) => { + // Reads don't invalidate shared or shallow borrows + } + + (Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + // Reading from mere reservations of mutable-borrows is OK. + if !is_active(&this.dominators, borrow, location) { + // If the borrow isn't active yet, reads don't invalidate it + assert!(allow_two_phase_borrow(borrow.kind)); + return Control::Continue; + } + + // Unique and mutable borrows are invalidated by reads from any + // involved path + this.emit_loan_invalidated_at(borrow_index, location); + } + + (Reservation(_) | Activation(_, _) | Write(_), _) => { + // unique or mutable borrows are invalidated by writes. + // Reservations count as writes since we need to check + // that activating the borrow will be OK + // FIXME(bob_twinkles) is this actually the right thing to do? + this.emit_loan_invalidated_at(borrow_index, location); + } + } + Control::Continue + }, + ); + } + + /// Generates a new `loan_invalidated_at(L, B)` fact. + fn emit_loan_invalidated_at(&mut self, b: BorrowIndex, l: Location) { + let lidx = self.location_table.start_index(l); + self.all_facts.loan_invalidated_at.push((lidx, b)); + } + + fn check_activations(&mut self, location: Location) { + // Two-phase borrow support: For each activation that is newly + // generated at this statement, check if it interferes with + // another borrow. + for &borrow_index in self.borrow_set.activations_at_location(location) { + let borrow = &self.borrow_set[borrow_index]; + + // only mutable borrows should be 2-phase + assert!(match borrow.kind { + BorrowKind::Shared | BorrowKind::Shallow => false, + BorrowKind::Unique | BorrowKind::Mut { .. } => true, + }); + + self.access_place( + location, + borrow.borrowed_place, + (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), + LocalMutationIsAllowed::No, + ); + + // We do not need to call `check_if_path_or_subpath_is_moved` + // again, as we already called it when we made the + // initial reservation. + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,2390 @@ +//! This query borrow-checks the MIR to (further) ensure it is not broken. + +#![feature(bool_to_option)] +#![feature(box_patterns)] +#![cfg_attr(bootstrap, feature(const_panic))] +#![feature(crate_visibility_modifier)] +#![feature(format_args_capture)] +#![feature(in_band_lifetimes)] +#![feature(iter_zip)] +#![feature(min_specialization)] +#![feature(stmt_expr_attributes)] +#![feature(trusted_step)] +#![feature(try_blocks)] +#![recursion_limit = "256"] + +#[macro_use] +extern crate rustc_middle; +#[macro_use] +extern crate tracing; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::graph::dominators::Dominators; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; +use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::Node; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_middle::mir::{ + traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, + PlaceRef, VarDebugInfoContents, +}; +use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; +use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; +use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt}; +use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT}; +use rustc_span::{Span, Symbol, DUMMY_SP}; + +use either::Either; +use smallvec::SmallVec; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::iter; +use std::mem; +use std::rc::Rc; + +use rustc_mir_dataflow::impls::{ + EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, +}; +use rustc_mir_dataflow::move_paths::{InitIndex, MoveOutIndex, MovePathIndex}; +use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveError}; +use rustc_mir_dataflow::Analysis; +use rustc_mir_dataflow::MoveDataParamEnv; + +use self::diagnostics::{AccessKind, RegionName}; +use self::location::LocationTable; +use self::prefixes::PrefixSet; +use self::MutateMode::{JustWrite, WriteAndRead}; +use facts::AllFacts; + +use self::path_utils::*; + +mod borrow_set; +mod borrowck_errors; +mod constraint_generation; +mod constraints; +mod dataflow; +mod def_use; +mod diagnostics; +mod facts; +mod invalidation; +mod location; +mod member_constraints; +mod nll; +mod path_utils; +mod place_ext; +mod places_conflict; +mod prefixes; +mod region_infer; +mod renumber; +mod type_check; +mod universal_regions; +mod used_muts; + +// A public API provided for the Rust compiler consumers. +pub mod consumers; + +use borrow_set::{BorrowData, BorrowSet}; +use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows}; +use nll::{PoloniusOutput, ToRegionVid}; +use place_ext::PlaceExt; +use places_conflict::{places_conflict, PlaceConflictBias}; +use region_infer::RegionInferenceContext; + +// FIXME(eddyb) perhaps move this somewhere more centrally. +#[derive(Debug)] +struct Upvar<'tcx> { + place: CapturedPlace<'tcx>, + + /// If true, the capture is behind a reference. + by_ref: bool, +} + +const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref]; + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + mir_borrowck: |tcx, did| { + if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { + tcx.mir_borrowck_const_arg(def) + } else { + mir_borrowck(tcx, ty::WithOptConstParam::unknown(did)) + } + }, + mir_borrowck_const_arg: |tcx, (did, param_did)| { + mir_borrowck(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) + }, + ..*providers + }; +} + +fn mir_borrowck<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> &'tcx BorrowCheckResult<'tcx> { + let (input_body, promoted) = tcx.mir_promoted(def); + debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); + + let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| { + let input_body: &Body<'_> = &input_body.borrow(); + let promoted: &IndexVec<_, _> = &promoted.borrow(); + do_mir_borrowck(&infcx, input_body, promoted, false).0 + }); + debug!("mir_borrowck done"); + + tcx.arena.alloc(opt_closure_req) +} + +/// Perform the actual borrow checking. +/// +/// If `return_body_with_facts` is true, then return the body with non-erased +/// region ids on which the borrow checking was performed together with Polonius +/// facts. +#[instrument(skip(infcx, input_body, input_promoted), level = "debug")] +fn do_mir_borrowck<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + input_body: &Body<'tcx>, + input_promoted: &IndexVec>, + return_body_with_facts: bool, +) -> (BorrowCheckResult<'tcx>, Option>>) { + let def = input_body.source.with_opt_param().as_local().unwrap(); + + debug!(?def); + + let tcx = infcx.tcx; + let param_env = tcx.param_env(def.did); + let id = tcx.hir().local_def_id_to_hir_id(def.did); + + let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); + for var_debug_info in &input_body.var_debug_info { + if let VarDebugInfoContents::Place(place) = var_debug_info.value { + if let Some(local) = place.as_local() { + if let Some(prev_name) = local_names[local] { + if var_debug_info.name != prev_name { + span_bug!( + var_debug_info.source_info.span, + "local {:?} has many names (`{}` vs `{}`)", + local, + prev_name, + var_debug_info.name + ); + } + } + local_names[local] = Some(var_debug_info.name); + } + } + } + + // Gather the upvars of a closure, if any. + let tables = tcx.typeck_opt_const_arg(def); + if let Some(ErrorReported) = tables.tainted_by_errors { + infcx.set_tainted_by_errors(); + } + let upvars: Vec<_> = tables + .closure_min_captures_flattened(def.did.to_def_id()) + .map(|captured_place| { + let capture = captured_place.info.capture_kind; + let by_ref = match capture { + ty::UpvarCapture::ByValue(_) => false, + ty::UpvarCapture::ByRef(..) => true, + }; + Upvar { place: captured_place.clone(), by_ref } + }) + .collect(); + + // Replace all regions with fresh inference variables. This + // requires first making our own copy of the MIR. This copy will + // be modified (in place) to contain non-lexical lifetimes. It + // will have a lifetime tied to the inference context. + let mut body_owned = input_body.clone(); + let mut promoted = input_promoted.clone(); + let free_regions = + nll::replace_regions_in_mir(infcx, param_env, &mut body_owned, &mut promoted); + let body = &body_owned; // no further changes + + let location_table_owned = LocationTable::new(body); + let location_table = &location_table_owned; + + let mut errors_buffer = Vec::new(); + let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) = + match MoveData::gather_moves(&body, tcx, param_env) { + Ok(move_data) => (move_data, Vec::new()), + Err((move_data, move_errors)) => (move_data, move_errors), + }; + let promoted_errors = promoted + .iter_enumerated() + .map(|(idx, body)| (idx, MoveData::gather_moves(&body, tcx, param_env))); + + let mdpe = MoveDataParamEnv { move_data, param_env }; + + let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe) + .into_engine(tcx, &body) + .pass_name("borrowck") + .iterate_to_fixpoint() + .into_results_cursor(&body); + + let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure(); + let borrow_set = + Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); + + let use_polonius = return_body_with_facts || infcx.tcx.sess.opts.debugging_opts.polonius; + + // Compute non-lexical lifetimes. + let nll::NllOutput { + regioncx, + opaque_type_values, + polonius_input, + polonius_output, + opt_closure_req, + nll_errors, + } = nll::compute_regions( + infcx, + free_regions, + body, + &promoted, + location_table, + param_env, + &mut flow_inits, + &mdpe.move_data, + &borrow_set, + &upvars, + use_polonius, + ); + + // Dump MIR results into a file, if that is enabled. This let us + // write unit-tests, as well as helping with debugging. + nll::dump_mir_results(infcx, &body, ®ioncx, &opt_closure_req); + + // We also have a `#[rustc_regions]` annotation that causes us to dump + // information. + nll::dump_annotation( + infcx, + &body, + ®ioncx, + &opt_closure_req, + &opaque_type_values, + &mut errors_buffer, + ); + + // The various `flow_*` structures can be large. We drop `flow_inits` here + // so it doesn't overlap with the others below. This reduces peak memory + // usage significantly on some benchmarks. + drop(flow_inits); + + let regioncx = Rc::new(regioncx); + + let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set) + .into_engine(tcx, body) + .pass_name("borrowck") + .iterate_to_fixpoint(); + let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe) + .into_engine(tcx, body) + .pass_name("borrowck") + .iterate_to_fixpoint(); + let flow_ever_inits = EverInitializedPlaces::new(tcx, body, &mdpe) + .into_engine(tcx, body) + .pass_name("borrowck") + .iterate_to_fixpoint(); + + let movable_generator = !matches!( + tcx.hir().get(id), + Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(.., Some(hir::Movability::Static)), + .. + }) + ); + + for (idx, move_data_results) in promoted_errors { + let promoted_body = &promoted[idx]; + + if let Err((move_data, move_errors)) = move_data_results { + let mut promoted_mbcx = MirBorrowckCtxt { + infcx, + param_env, + body: promoted_body, + move_data: &move_data, + location_table, // no need to create a real one for the promoted, it is not used + movable_generator, + fn_self_span_reported: Default::default(), + locals_are_invalidated_at_exit, + access_place_error_reported: Default::default(), + reservation_error_reported: Default::default(), + reservation_warnings: Default::default(), + move_error_reported: BTreeMap::new(), + uninitialized_error_reported: Default::default(), + errors_buffer, + regioncx: regioncx.clone(), + used_mut: Default::default(), + used_mut_upvars: SmallVec::new(), + borrow_set: Rc::clone(&borrow_set), + dominators: Dominators::dummy(), // not used + upvars: Vec::new(), + local_names: IndexVec::from_elem(None, &promoted_body.local_decls), + region_names: RefCell::default(), + next_region_name: RefCell::new(1), + polonius_output: None, + }; + promoted_mbcx.report_move_errors(move_errors); + errors_buffer = promoted_mbcx.errors_buffer; + }; + } + + let dominators = body.dominators(); + + let mut mbcx = MirBorrowckCtxt { + infcx, + param_env, + body, + move_data: &mdpe.move_data, + location_table, + movable_generator, + locals_are_invalidated_at_exit, + fn_self_span_reported: Default::default(), + access_place_error_reported: Default::default(), + reservation_error_reported: Default::default(), + reservation_warnings: Default::default(), + move_error_reported: BTreeMap::new(), + uninitialized_error_reported: Default::default(), + errors_buffer, + regioncx: Rc::clone(®ioncx), + used_mut: Default::default(), + used_mut_upvars: SmallVec::new(), + borrow_set: Rc::clone(&borrow_set), + dominators, + upvars, + local_names, + region_names: RefCell::default(), + next_region_name: RefCell::new(1), + polonius_output, + }; + + // Compute and report region errors, if any. + mbcx.report_region_errors(nll_errors); + + let results = BorrowckResults { + ever_inits: flow_ever_inits, + uninits: flow_uninits, + borrows: flow_borrows, + }; + + mbcx.report_move_errors(move_errors); + + rustc_mir_dataflow::visit_results( + body, + traversal::reverse_postorder(body).map(|(bb, _)| bb), + &results, + &mut mbcx, + ); + + // Convert any reservation warnings into lints. + let reservation_warnings = mem::take(&mut mbcx.reservation_warnings); + for (_, (place, span, location, bk, borrow)) in reservation_warnings { + let mut initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow); + + let scope = mbcx.body.source_info(location).scope; + let lint_root = match &mbcx.body.source_scopes[scope].local_data { + ClearCrossCrate::Set(data) => data.lint_root, + _ => id, + }; + + // Span and message don't matter; we overwrite them below anyway + mbcx.infcx.tcx.struct_span_lint_hir( + MUTABLE_BORROW_RESERVATION_CONFLICT, + lint_root, + DUMMY_SP, + |lint| { + let mut diag = lint.build(""); + + diag.message = initial_diag.styled_message().clone(); + diag.span = initial_diag.span.clone(); + + diag.buffer(&mut mbcx.errors_buffer); + }, + ); + initial_diag.cancel(); + } + + // For each non-user used mutable variable, check if it's been assigned from + // a user-declared local. If so, then put that local into the used_mut set. + // Note that this set is expected to be small - only upvars from closures + // would have a chance of erroneously adding non-user-defined mutable vars + // to the set. + let temporary_used_locals: FxHashSet = mbcx + .used_mut + .iter() + .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable()) + .cloned() + .collect(); + // For the remaining unused locals that are marked as mutable, we avoid linting any that + // were never initialized. These locals may have been removed as unreachable code; or will be + // linted as unused variables. + let unused_mut_locals = + mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect(); + mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals); + + debug!("mbcx.used_mut: {:?}", mbcx.used_mut); + let used_mut = mbcx.used_mut; + for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) { + let local_decl = &mbcx.body.local_decls[local]; + let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data { + ClearCrossCrate::Set(data) => data.lint_root, + _ => continue, + }; + + // Skip over locals that begin with an underscore or have no name + match mbcx.local_names[local] { + Some(name) => { + if name.as_str().starts_with('_') { + continue; + } + } + None => continue, + } + + let span = local_decl.source_info.span; + if span.desugaring_kind().is_some() { + // If the `mut` arises as part of a desugaring, we should ignore it. + continue; + } + + tcx.struct_span_lint_hir(UNUSED_MUT, lint_root, span, |lint| { + let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); + lint.build("variable does not need to be mutable") + .span_suggestion_short( + mut_span, + "remove this `mut`", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + }) + } + + // Buffer any move errors that we collected and de-duplicated. + for (_, (_, diag)) in mbcx.move_error_reported { + diag.buffer(&mut mbcx.errors_buffer); + } + + if !mbcx.errors_buffer.is_empty() { + mbcx.errors_buffer.sort_by_key(|diag| diag.sort_span); + + for diag in mbcx.errors_buffer.drain(..) { + mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag); + } + } + + let result = BorrowCheckResult { + concrete_opaque_types: opaque_type_values, + closure_requirements: opt_closure_req, + used_mut_upvars: mbcx.used_mut_upvars, + }; + + let body_with_facts = if return_body_with_facts { + let output_facts = mbcx.polonius_output.expect("Polonius output was not computed"); + Some(Box::new(BodyWithBorrowckFacts { + body: body_owned, + input_facts: *polonius_input.expect("Polonius input facts were not generated"), + output_facts, + location_table: location_table_owned, + })) + } else { + None + }; + + debug!("do_mir_borrowck: result = {:#?}", result); + + (result, body_with_facts) +} + +/// A `Body` with information computed by the borrow checker. This struct is +/// intended to be consumed by compiler consumers. +/// +/// We need to include the MIR body here because the region identifiers must +/// match the ones in the Polonius facts. +pub struct BodyWithBorrowckFacts<'tcx> { + /// A mir body that contains region identifiers. + pub body: Body<'tcx>, + /// Polonius input facts. + pub input_facts: AllFacts, + /// Polonius output facts. + pub output_facts: Rc, + /// The table that maps Polonius points to locations in the table. + pub location_table: LocationTable, +} + +struct MirBorrowckCtxt<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: ParamEnv<'tcx>, + body: &'cx Body<'tcx>, + move_data: &'cx MoveData<'tcx>, + + /// Map from MIR `Location` to `LocationIndex`; created + /// when MIR borrowck begins. + location_table: &'cx LocationTable, + + movable_generator: bool, + /// This keeps track of whether local variables are free-ed when the function + /// exits even without a `StorageDead`, which appears to be the case for + /// constants. + /// + /// I'm not sure this is the right approach - @eddyb could you try and + /// figure this out? + locals_are_invalidated_at_exit: bool, + /// This field keeps track of when borrow errors are reported in the access_place function + /// so that there is no duplicate reporting. This field cannot also be used for the conflicting + /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion + /// of the `Span` type (while required to mute some errors) stops the muting of the reservation + /// errors. + access_place_error_reported: FxHashSet<(Place<'tcx>, Span)>, + /// This field keeps track of when borrow conflict errors are reported + /// for reservations, so that we don't report seemingly duplicate + /// errors for corresponding activations. + // + // FIXME: ideally this would be a set of `BorrowIndex`, not `Place`s, + // but it is currently inconvenient to track down the `BorrowIndex` + // at the time we detect and report a reservation error. + reservation_error_reported: FxHashSet>, + /// This fields keeps track of the `Span`s that we have + /// used to report extra information for `FnSelfUse`, to avoid + /// unnecessarily verbose errors. + fn_self_span_reported: FxHashSet, + /// Migration warnings to be reported for #56254. We delay reporting these + /// so that we can suppress the warning if there's a corresponding error + /// for the activation of the borrow. + reservation_warnings: + FxHashMap, Span, Location, BorrowKind, BorrowData<'tcx>)>, + /// This field keeps track of move errors that are to be reported for given move indices. + /// + /// There are situations where many errors can be reported for a single move out (see #53807) + /// and we want only the best of those errors. + /// + /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the + /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the + /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once + /// all move errors have been reported, any diagnostics in this map are added to the buffer + /// to be emitted. + /// + /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary + /// when errors in the map are being re-added to the error buffer so that errors with the + /// same primary span come out in a consistent order. + move_error_reported: BTreeMap, (PlaceRef<'tcx>, DiagnosticBuilder<'cx>)>, + /// This field keeps track of errors reported in the checking of uninitialized variables, + /// so that we don't report seemingly duplicate errors. + uninitialized_error_reported: FxHashSet>, + /// Errors to be reported buffer + errors_buffer: Vec, + /// This field keeps track of all the local variables that are declared mut and are mutated. + /// Used for the warning issued by an unused mutable local variable. + used_mut: FxHashSet, + /// If the function we're checking is a closure, then we'll need to report back the list of + /// mutable upvars that have been used. This field keeps track of them. + used_mut_upvars: SmallVec<[Field; 8]>, + /// Region inference context. This contains the results from region inference and lets us e.g. + /// find out which CFG points are contained in each borrow region. + regioncx: Rc>, + + /// The set of borrows extracted from the MIR + borrow_set: Rc>, + + /// Dominators for MIR + dominators: Dominators, + + /// Information about upvars not necessarily preserved in types or MIR + upvars: Vec>, + + /// Names of local (user) variables (extracted from `var_debug_info`). + local_names: IndexVec>, + + /// Record the region names generated for each region in the given + /// MIR def so that we can reuse them later in help/error messages. + region_names: RefCell>, + + /// The counter for generating new region names. + next_region_name: RefCell, + + /// Results of Polonius analysis. + polonius_output: Option>, +} + +// Check that: +// 1. assignments are always made to mutable locations (FIXME: does that still really go here?) +// 2. loans made in overlapping scopes do not conflict +// 3. assignments do not affect things loaned out as immutable +// 4. moves do not affect things loaned out in any way +impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> { + type FlowState = Flows<'cx, 'tcx>; + + fn visit_statement_before_primary_effect( + &mut self, + flow_state: &Flows<'cx, 'tcx>, + stmt: &'cx Statement<'tcx>, + location: Location, + ) { + debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, flow_state); + let span = stmt.source_info.span; + + self.check_activations(location, span, flow_state); + + match &stmt.kind { + StatementKind::Assign(box (lhs, ref rhs)) => { + self.consume_rvalue(location, (rhs, span), flow_state); + + self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state); + } + StatementKind::FakeRead(box (_, ref place)) => { + // Read for match doesn't access any memory and is used to + // assert that a place is safe and live. So we don't have to + // do any checks here. + // + // FIXME: Remove check that the place is initialized. This is + // needed for now because matches don't have never patterns yet. + // So this is the only place we prevent + // let x: !; + // match x {}; + // from compiling. + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Use, + (place.as_ref(), span), + flow_state, + ); + } + StatementKind::SetDiscriminant { place, variant_index: _ } => { + self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state); + } + StatementKind::LlvmInlineAsm(ref asm) => { + for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) { + if o.is_indirect { + // FIXME(eddyb) indirect inline asm outputs should + // be encoded through MIR place derefs instead. + self.access_place( + location, + (*output, o.span), + (Deep, Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + flow_state, + ); + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Use, + (output.as_ref(), o.span), + flow_state, + ); + } else { + self.mutate_place( + location, + (*output, o.span), + if o.is_rw { Deep } else { Shallow(None) }, + if o.is_rw { WriteAndRead } else { JustWrite }, + flow_state, + ); + } + } + for (_, input) in asm.inputs.iter() { + self.consume_operand(location, (input, span), flow_state); + } + } + + StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + .. + }) => { + span_bug!( + span, + "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", + ) + } + StatementKind::Nop + | StatementKind::Coverage(..) + | StatementKind::AscribeUserType(..) + | StatementKind::Retag { .. } + | StatementKind::StorageLive(..) => { + // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant + // to borrow check. + } + StatementKind::StorageDead(local) => { + self.access_place( + location, + (Place::from(*local), span), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); + } + } + } + + fn visit_terminator_before_primary_effect( + &mut self, + flow_state: &Flows<'cx, 'tcx>, + term: &'cx Terminator<'tcx>, + loc: Location, + ) { + debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, flow_state); + let span = term.source_info.span; + + self.check_activations(loc, span, flow_state); + + match term.kind { + TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => { + self.consume_operand(loc, (discr, span), flow_state); + } + TerminatorKind::Drop { place, target: _, unwind: _ } => { + debug!( + "visit_terminator_drop \ + loc: {:?} term: {:?} place: {:?} span: {:?}", + loc, term, place, span + ); + + self.access_place( + loc, + (place, span), + (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); + } + TerminatorKind::DropAndReplace { + place: drop_place, + value: ref new_value, + target: _, + unwind: _, + } => { + self.mutate_place(loc, (drop_place, span), Deep, JustWrite, flow_state); + self.consume_operand(loc, (new_value, span), flow_state); + } + TerminatorKind::Call { + ref func, + ref args, + ref destination, + cleanup: _, + from_hir_call: _, + fn_span: _, + } => { + self.consume_operand(loc, (func, span), flow_state); + for arg in args { + self.consume_operand(loc, (arg, span), flow_state); + } + if let Some((dest, _ /*bb*/)) = *destination { + self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state); + } + } + TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { + self.consume_operand(loc, (cond, span), flow_state); + use rustc_middle::mir::AssertKind; + if let AssertKind::BoundsCheck { ref len, ref index } = *msg { + self.consume_operand(loc, (len, span), flow_state); + self.consume_operand(loc, (index, span), flow_state); + } + } + + TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => { + self.consume_operand(loc, (value, span), flow_state); + self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state); + } + + TerminatorKind::InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination: _, + } => { + for op in operands { + match *op { + InlineAsmOperand::In { reg: _, ref value } => { + self.consume_operand(loc, (value, span), flow_state); + } + InlineAsmOperand::Out { reg: _, late: _, place, .. } => { + if let Some(place) = place { + self.mutate_place( + loc, + (place, span), + Shallow(None), + JustWrite, + flow_state, + ); + } + } + InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { + self.consume_operand(loc, (in_value, span), flow_state); + if let Some(out_place) = out_place { + self.mutate_place( + loc, + (out_place, span), + Shallow(None), + JustWrite, + flow_state, + ); + } + } + InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { def_id: _ } => {} + } + } + } + + TerminatorKind::Goto { target: _ } + | TerminatorKind::Abort + | TerminatorKind::Unreachable + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } + | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { + // no data used, thus irrelevant to borrowck + } + } + } + + fn visit_terminator_after_primary_effect( + &mut self, + flow_state: &Flows<'cx, 'tcx>, + term: &'cx Terminator<'tcx>, + loc: Location, + ) { + let span = term.source_info.span; + + match term.kind { + TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => { + if self.movable_generator { + // Look for any active borrows to locals + let borrow_set = self.borrow_set.clone(); + for i in flow_state.borrows.iter() { + let borrow = &borrow_set[i]; + self.check_for_local_borrow(borrow, span); + } + } + } + + TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { + // Returning from the function implicitly kills storage for all locals and statics. + // Often, the storage will already have been killed by an explicit + // StorageDead, but we don't always emit those (notably on unwind paths), + // so this "extra check" serves as a kind of backup. + let borrow_set = self.borrow_set.clone(); + for i in flow_state.borrows.iter() { + let borrow = &borrow_set[i]; + self.check_for_invalidation_at_exit(loc, borrow, span); + } + } + + TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } + | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } + | TerminatorKind::Goto { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable + | TerminatorKind::InlineAsm { .. } => {} + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum MutateMode { + JustWrite, + WriteAndRead, +} + +use self::AccessDepth::{Deep, Shallow}; +use self::ReadOrWrite::{Activation, Read, Reservation, Write}; + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum ArtificialField { + ArrayLength, + ShallowBorrow, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum AccessDepth { + /// From the RFC: "A *shallow* access means that the immediate + /// fields reached at P are accessed, but references or pointers + /// found within are not dereferenced. Right now, the only access + /// that is shallow is an assignment like `x = ...;`, which would + /// be a *shallow write* of `x`." + Shallow(Option), + + /// From the RFC: "A *deep* access means that all data reachable + /// through the given place may be invalidated or accesses by + /// this action." + Deep, + + /// Access is Deep only when there is a Drop implementation that + /// can reach the data behind the reference. + Drop, +} + +/// Kind of access to a value: read or write +/// (For informational purposes only) +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum ReadOrWrite { + /// From the RFC: "A *read* means that the existing data may be + /// read, but will not be changed." + Read(ReadKind), + + /// From the RFC: "A *write* means that the data may be mutated to + /// new values or otherwise invalidated (for example, it could be + /// de-initialized, as in a move operation). + Write(WriteKind), + + /// For two-phase borrows, we distinguish a reservation (which is treated + /// like a Read) from an activation (which is treated like a write), and + /// each of those is furthermore distinguished from Reads/Writes above. + Reservation(WriteKind), + Activation(WriteKind, BorrowIndex), +} + +/// Kind of read access to a value +/// (For informational purposes only) +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum ReadKind { + Borrow(BorrowKind), + Copy, +} + +/// Kind of write access to a value +/// (For informational purposes only) +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum WriteKind { + StorageDeadOrDrop, + MutableBorrow(BorrowKind), + Mutate, + Move, +} + +/// When checking permissions for a place access, this flag is used to indicate that an immutable +/// local place can be mutated. +// +// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications: +// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`. +// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and +// `is_declared_mutable()`. +// - Take flow state into consideration in `is_assignable()` for local variables. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum LocalMutationIsAllowed { + Yes, + /// We want use of immutable upvars to cause a "write to immutable upvar" + /// error, not an "reassignment" error. + ExceptUpvars, + No, +} + +#[derive(Copy, Clone, Debug)] +enum InitializationRequiringAction { + Update, + Borrow, + MatchOn, + Use, + Assignment, + PartialAssignment, +} + +struct RootPlace<'tcx> { + place_local: Local, + place_projection: &'tcx [PlaceElem<'tcx>], + is_local_mutation_allowed: LocalMutationIsAllowed, +} + +impl InitializationRequiringAction { + fn as_noun(self) -> &'static str { + match self { + InitializationRequiringAction::Update => "update", + InitializationRequiringAction::Borrow => "borrow", + InitializationRequiringAction::MatchOn => "use", // no good noun + InitializationRequiringAction::Use => "use", + InitializationRequiringAction::Assignment => "assign", + InitializationRequiringAction::PartialAssignment => "assign to part", + } + } + + fn as_verb_in_past_tense(self) -> &'static str { + match self { + InitializationRequiringAction::Update => "updated", + InitializationRequiringAction::Borrow => "borrowed", + InitializationRequiringAction::MatchOn => "matched on", + InitializationRequiringAction::Use => "used", + InitializationRequiringAction::Assignment => "assigned", + InitializationRequiringAction::PartialAssignment => "partially assigned", + } + } +} + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + fn body(&self) -> &'cx Body<'tcx> { + self.body + } + + /// Checks an access to the given place to see if it is allowed. Examines the set of borrows + /// that are in scope, as well as which paths have been initialized, to ensure that (a) the + /// place is initialized and (b) it is not borrowed in some way that would prevent this + /// access. + /// + /// Returns `true` if an error is reported. + fn access_place( + &mut self, + location: Location, + place_span: (Place<'tcx>, Span), + kind: (AccessDepth, ReadOrWrite), + is_local_mutation_allowed: LocalMutationIsAllowed, + flow_state: &Flows<'cx, 'tcx>, + ) { + let (sd, rw) = kind; + + if let Activation(_, borrow_index) = rw { + if self.reservation_error_reported.contains(&place_span.0) { + debug!( + "skipping access_place for activation of invalid reservation \ + place: {:?} borrow_index: {:?}", + place_span.0, borrow_index + ); + return; + } + } + + // Check is_empty() first because it's the common case, and doing that + // way we avoid the clone() call. + if !self.access_place_error_reported.is_empty() + && self.access_place_error_reported.contains(&(place_span.0, place_span.1)) + { + debug!( + "access_place: suppressing error place_span=`{:?}` kind=`{:?}`", + place_span, kind + ); + return; + } + + let mutability_error = self.check_access_permissions( + place_span, + rw, + is_local_mutation_allowed, + flow_state, + location, + ); + let conflict_error = + self.check_access_for_conflict(location, place_span, sd, rw, flow_state); + + if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) { + // Suppress this warning when there's an error being emitted for the + // same borrow: fixing the error is likely to fix the warning. + self.reservation_warnings.remove(&borrow_idx); + } + + if conflict_error || mutability_error { + debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind); + + self.access_place_error_reported.insert((place_span.0, place_span.1)); + } + } + + fn check_access_for_conflict( + &mut self, + location: Location, + place_span: (Place<'tcx>, Span), + sd: AccessDepth, + rw: ReadOrWrite, + flow_state: &Flows<'cx, 'tcx>, + ) -> bool { + debug!( + "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})", + location, place_span, sd, rw, + ); + + let mut error_reported = false; + let tcx = self.infcx.tcx; + let body = self.body; + let borrow_set = self.borrow_set.clone(); + + // Use polonius output if it has been enabled. + let polonius_output = self.polonius_output.clone(); + let borrows_in_scope = if let Some(polonius) = &polonius_output { + let location = self.location_table.start_index(location); + Either::Left(polonius.errors_at(location).iter().copied()) + } else { + Either::Right(flow_state.borrows.iter()) + }; + + each_borrow_involving_path( + self, + tcx, + body, + location, + (sd, place_span.0), + &borrow_set, + borrows_in_scope, + |this, borrow_index, borrow| match (rw, borrow.kind) { + // Obviously an activation is compatible with its own + // reservation (or even prior activating uses of same + // borrow); so don't check if they interfere. + // + // NOTE: *reservations* do conflict with themselves; + // thus aren't injecting unsoundenss w/ this check.) + (Activation(_, activating), _) if activating == borrow_index => { + debug!( + "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \ + skipping {:?} b/c activation of same borrow_index", + place_span, + sd, + rw, + (borrow_index, borrow), + ); + Control::Continue + } + + (Read(_), BorrowKind::Shared | BorrowKind::Shallow) + | ( + Read(ReadKind::Borrow(BorrowKind::Shallow)), + BorrowKind::Unique | BorrowKind::Mut { .. }, + ) => Control::Continue, + + (Write(WriteKind::Move), BorrowKind::Shallow) => { + // Handled by initialization checks. + Control::Continue + } + + (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + // Reading from mere reservations of mutable-borrows is OK. + if !is_active(&this.dominators, borrow, location) { + assert!(allow_two_phase_borrow(borrow.kind)); + return Control::Continue; + } + + error_reported = true; + match kind { + ReadKind::Copy => { + this.report_use_while_mutably_borrowed(location, place_span, borrow) + .buffer(&mut this.errors_buffer); + } + ReadKind::Borrow(bk) => { + this.report_conflicting_borrow(location, place_span, bk, borrow) + .buffer(&mut this.errors_buffer); + } + } + Control::Break + } + + ( + Reservation(WriteKind::MutableBorrow(bk)), + BorrowKind::Shallow | BorrowKind::Shared, + ) if { tcx.migrate_borrowck() && this.borrow_set.contains(&location) } => { + let bi = this.borrow_set.get_index_of(&location).unwrap(); + debug!( + "recording invalid reservation of place: {:?} with \ + borrow index {:?} as warning", + place_span.0, bi, + ); + // rust-lang/rust#56254 - This was previously permitted on + // the 2018 edition so we emit it as a warning. We buffer + // these sepately so that we only emit a warning if borrow + // checking was otherwise successful. + this.reservation_warnings + .insert(bi, (place_span.0, place_span.1, location, bk, borrow.clone())); + + // Don't suppress actual errors. + Control::Continue + } + + (Reservation(kind) | Activation(kind, _) | Write(kind), _) => { + match rw { + Reservation(..) => { + debug!( + "recording invalid reservation of \ + place: {:?}", + place_span.0 + ); + this.reservation_error_reported.insert(place_span.0); + } + Activation(_, activating) => { + debug!( + "observing check_place for activation of \ + borrow_index: {:?}", + activating + ); + } + Read(..) | Write(..) => {} + } + + error_reported = true; + match kind { + WriteKind::MutableBorrow(bk) => { + this.report_conflicting_borrow(location, place_span, bk, borrow) + .buffer(&mut this.errors_buffer); + } + WriteKind::StorageDeadOrDrop => this + .report_borrowed_value_does_not_live_long_enough( + location, + borrow, + place_span, + Some(kind), + ), + WriteKind::Mutate => { + this.report_illegal_mutation_of_borrowed(location, place_span, borrow) + } + WriteKind::Move => { + this.report_move_out_while_borrowed(location, place_span, borrow) + } + } + Control::Break + } + }, + ); + + error_reported + } + + fn mutate_place( + &mut self, + location: Location, + place_span: (Place<'tcx>, Span), + kind: AccessDepth, + mode: MutateMode, + flow_state: &Flows<'cx, 'tcx>, + ) { + // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd. + match mode { + MutateMode::WriteAndRead => { + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Update, + (place_span.0.as_ref(), place_span.1), + flow_state, + ); + } + MutateMode::JustWrite => { + self.check_if_assigned_path_is_moved(location, place_span, flow_state); + } + } + + // Special case: you can assign an immutable local variable + // (e.g., `x = ...`) so long as it has never been initialized + // before (at this point in the flow). + if let Some(local) = place_span.0.as_local() { + if let Mutability::Not = self.body.local_decls[local].mutability { + // check for reassignments to immutable local variables + self.check_if_reassignment_to_immutable_state( + location, local, place_span, flow_state, + ); + return; + } + } + + // Otherwise, use the normal access permission rules. + self.access_place( + location, + place_span, + (kind, Write(WriteKind::Mutate)), + LocalMutationIsAllowed::No, + flow_state, + ); + } + + fn consume_rvalue( + &mut self, + location: Location, + (rvalue, span): (&'cx Rvalue<'tcx>, Span), + flow_state: &Flows<'cx, 'tcx>, + ) { + match *rvalue { + Rvalue::Ref(_ /*rgn*/, bk, place) => { + let access_kind = match bk { + BorrowKind::Shallow => { + (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) + } + BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), + BorrowKind::Unique | BorrowKind::Mut { .. } => { + let wk = WriteKind::MutableBorrow(bk); + if allow_two_phase_borrow(bk) { + (Deep, Reservation(wk)) + } else { + (Deep, Write(wk)) + } + } + }; + + self.access_place( + location, + (place, span), + access_kind, + LocalMutationIsAllowed::No, + flow_state, + ); + + let action = if bk == BorrowKind::Shallow { + InitializationRequiringAction::MatchOn + } else { + InitializationRequiringAction::Borrow + }; + + self.check_if_path_or_subpath_is_moved( + location, + action, + (place.as_ref(), span), + flow_state, + ); + } + + Rvalue::AddressOf(mutability, place) => { + let access_kind = match mutability { + Mutability::Mut => ( + Deep, + Write(WriteKind::MutableBorrow(BorrowKind::Mut { + allow_two_phase_borrow: false, + })), + ), + Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), + }; + + self.access_place( + location, + (place, span), + access_kind, + LocalMutationIsAllowed::No, + flow_state, + ); + + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Borrow, + (place.as_ref(), span), + flow_state, + ); + } + + Rvalue::ThreadLocalRef(_) => {} + + Rvalue::Use(ref operand) + | Rvalue::Repeat(ref operand, _) + | Rvalue::UnaryOp(_ /*un_op*/, ref operand) + | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) + | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { + self.consume_operand(location, (operand, span), flow_state) + } + + Rvalue::Len(place) | Rvalue::Discriminant(place) => { + let af = match *rvalue { + Rvalue::Len(..) => Some(ArtificialField::ArrayLength), + Rvalue::Discriminant(..) => None, + _ => unreachable!(), + }; + self.access_place( + location, + (place, span), + (Shallow(af), Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + flow_state, + ); + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Use, + (place.as_ref(), span), + flow_state, + ); + } + + Rvalue::BinaryOp(_bin_op, box (ref operand1, ref operand2)) + | Rvalue::CheckedBinaryOp(_bin_op, box (ref operand1, ref operand2)) => { + self.consume_operand(location, (operand1, span), flow_state); + self.consume_operand(location, (operand2, span), flow_state); + } + + Rvalue::NullaryOp(_op, _ty) => { + // nullary ops take no dynamic input; no borrowck effect. + // + // FIXME: is above actually true? Do we want to track + // the fact that uninitialized data can be created via + // `NullOp::Box`? + } + + Rvalue::Aggregate(ref aggregate_kind, ref operands) => { + // We need to report back the list of mutable upvars that were + // moved into the closure and subsequently used by the closure, + // in order to populate our used_mut set. + match **aggregate_kind { + AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) => { + let BorrowCheckResult { used_mut_upvars, .. } = + self.infcx.tcx.mir_borrowck(def_id.expect_local()); + debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); + for field in used_mut_upvars { + self.propagate_closure_used_mut_upvar(&operands[field.index()]); + } + } + AggregateKind::Adt(..) + | AggregateKind::Array(..) + | AggregateKind::Tuple { .. } => (), + } + + for operand in operands { + self.consume_operand(location, (operand, span), flow_state); + } + } + } + } + + fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { + let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| { + // We have three possibilities here: + // a. We are modifying something through a mut-ref + // b. We are modifying something that is local to our parent + // c. Current body is a nested closure, and we are modifying path starting from + // a Place captured by our parent closure. + + // Handle (c), the path being modified is exactly the path captured by our parent + if let Some(field) = this.is_upvar_field_projection(place.as_ref()) { + this.used_mut_upvars.push(field); + return; + } + + for (place_ref, proj) in place.iter_projections().rev() { + // Handle (a) + if proj == ProjectionElem::Deref { + match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() { + // We aren't modifying a variable directly + ty::Ref(_, _, hir::Mutability::Mut) => return, + + _ => {} + } + } + + // Handle (c) + if let Some(field) = this.is_upvar_field_projection(place_ref) { + this.used_mut_upvars.push(field); + return; + } + } + + // Handle(b) + this.used_mut.insert(place.local); + }; + + // This relies on the current way that by-value + // captures of a closure are copied/moved directly + // when generating MIR. + match *operand { + Operand::Move(place) | Operand::Copy(place) => { + match place.as_local() { + Some(local) if !self.body.local_decls[local].is_user_variable() => { + if self.body.local_decls[local].ty.is_mutable_ptr() { + // The variable will be marked as mutable by the borrow. + return; + } + // This is an edge case where we have a `move` closure + // inside a non-move closure, and the inner closure + // contains a mutation: + // + // let mut i = 0; + // || { move || { i += 1; }; }; + // + // In this case our usual strategy of assuming that the + // variable will be captured by mutable reference is + // wrong, since `i` can be copied into the inner + // closure from a shared reference. + // + // As such we have to search for the local that this + // capture comes from and mark it as being used as mut. + + let temp_mpi = self.move_data.rev_lookup.find_local(local); + let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { + &self.move_data.inits[init_index] + } else { + bug!("temporary should be initialized exactly once") + }; + + let loc = match init.location { + InitLocation::Statement(stmt) => stmt, + _ => bug!("temporary initialized in arguments"), + }; + + let body = self.body; + let bbd = &body[loc.block]; + let stmt = &bbd.statements[loc.statement_index]; + debug!("temporary assigned in: stmt={:?}", stmt); + + if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind + { + propagate_closure_used_mut_place(self, source); + } else { + bug!( + "closures should only capture user variables \ + or references to user variables" + ); + } + } + _ => propagate_closure_used_mut_place(self, place), + } + } + Operand::Constant(..) => {} + } + } + + fn consume_operand( + &mut self, + location: Location, + (operand, span): (&'cx Operand<'tcx>, Span), + flow_state: &Flows<'cx, 'tcx>, + ) { + match *operand { + Operand::Copy(place) => { + // copy of place: check if this is "copy of frozen path" + // (FIXME: see check_loans.rs) + self.access_place( + location, + (place, span), + (Deep, Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + flow_state, + ); + + // Finally, check if path was already moved. + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Use, + (place.as_ref(), span), + flow_state, + ); + } + Operand::Move(place) => { + // move of place: check if this is move of already borrowed path + self.access_place( + location, + (place, span), + (Deep, Write(WriteKind::Move)), + LocalMutationIsAllowed::Yes, + flow_state, + ); + + // Finally, check if path was already moved. + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Use, + (place.as_ref(), span), + flow_state, + ); + } + Operand::Constant(_) => {} + } + } + + /// Checks whether a borrow of this place is invalidated when the function + /// exits + fn check_for_invalidation_at_exit( + &mut self, + location: Location, + borrow: &BorrowData<'tcx>, + span: Span, + ) { + debug!("check_for_invalidation_at_exit({:?})", borrow); + let place = borrow.borrowed_place; + let mut root_place = PlaceRef { local: place.local, projection: &[] }; + + // FIXME(nll-rfc#40): do more precise destructor tracking here. For now + // we just know that all locals are dropped at function exit (otherwise + // we'll have a memory leak) and assume that all statics have a destructor. + // + // FIXME: allow thread-locals to borrow other thread locals? + + let (might_be_alive, will_be_dropped) = + if self.body.local_decls[root_place.local].is_ref_to_thread_local() { + // Thread-locals might be dropped after the function exits + // We have to dereference the outer reference because + // borrows don't conflict behind shared references. + root_place.projection = DEREF_PROJECTION; + (true, true) + } else { + (false, self.locals_are_invalidated_at_exit) + }; + + if !will_be_dropped { + debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place); + return; + } + + let sd = if might_be_alive { Deep } else { Shallow(None) }; + + if places_conflict::borrow_conflicts_with_place( + self.infcx.tcx, + &self.body, + place, + borrow.kind, + root_place, + sd, + places_conflict::PlaceConflictBias::Overlap, + ) { + debug!("check_for_invalidation_at_exit({:?}): INVALID", place); + // FIXME: should be talking about the region lifetime instead + // of just a span here. + let span = self.infcx.tcx.sess.source_map().end_point(span); + self.report_borrowed_value_does_not_live_long_enough( + location, + borrow, + (place, span), + None, + ) + } + } + + /// Reports an error if this is a borrow of local data. + /// This is called for all Yield expressions on movable generators + fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) { + debug!("check_for_local_borrow({:?})", borrow); + + if borrow_of_local_data(borrow.borrowed_place) { + let err = self.cannot_borrow_across_generator_yield( + self.retrieve_borrow_spans(borrow).var_or_use(), + yield_span, + ); + + err.buffer(&mut self.errors_buffer); + } + } + + fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flows<'cx, 'tcx>) { + // Two-phase borrow support: For each activation that is newly + // generated at this statement, check if it interferes with + // another borrow. + let borrow_set = self.borrow_set.clone(); + for &borrow_index in borrow_set.activations_at_location(location) { + let borrow = &borrow_set[borrow_index]; + + // only mutable borrows should be 2-phase + assert!(match borrow.kind { + BorrowKind::Shared | BorrowKind::Shallow => false, + BorrowKind::Unique | BorrowKind::Mut { .. } => true, + }); + + self.access_place( + location, + (borrow.borrowed_place, span), + (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), + LocalMutationIsAllowed::No, + flow_state, + ); + // We do not need to call `check_if_path_or_subpath_is_moved` + // again, as we already called it when we made the + // initial reservation. + } + } + + fn check_if_reassignment_to_immutable_state( + &mut self, + location: Location, + local: Local, + place_span: (Place<'tcx>, Span), + flow_state: &Flows<'cx, 'tcx>, + ) { + debug!("check_if_reassignment_to_immutable_state({:?})", local); + + // Check if any of the initializiations of `local` have happened yet: + if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) { + // And, if so, report an error. + let init = &self.move_data.inits[init_index]; + let span = init.span(&self.body); + self.report_illegal_reassignment(location, place_span, span, place_span.0); + } + } + + fn check_if_full_path_is_moved( + &mut self, + location: Location, + desired_action: InitializationRequiringAction, + place_span: (PlaceRef<'tcx>, Span), + flow_state: &Flows<'cx, 'tcx>, + ) { + let maybe_uninits = &flow_state.uninits; + + // Bad scenarios: + // + // 1. Move of `a.b.c`, use of `a.b.c` + // 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`) + // 3. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with + // partial initialization support, one might have `a.x` + // initialized but not `a.b`. + // + // OK scenarios: + // + // 4. Move of `a.b.c`, use of `a.b.d` + // 5. Uninitialized `a.x`, initialized `a.b`, use of `a.b` + // 6. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b` + // must have been initialized for the use to be sound. + // 7. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` + + // The dataflow tracks shallow prefixes distinctly (that is, + // field-accesses on P distinctly from P itself), in order to + // track substructure initialization separately from the whole + // structure. + // + // E.g., when looking at (*a.b.c).d, if the closest prefix for + // which we have a MovePath is `a.b`, then that means that the + // initialization state of `a.b` is all we need to inspect to + // know if `a.b.c` is valid (and from that we infer that the + // dereference and `.d` access is also valid, since we assume + // `a.b.c` is assigned a reference to an initialized and + // well-formed record structure.) + + // Therefore, if we seek out the *closest* prefix for which we + // have a MovePath, that should capture the initialization + // state for the place scenario. + // + // This code covers scenarios 1, 2, and 3. + + debug!("check_if_full_path_is_moved place: {:?}", place_span.0); + let (prefix, mpi) = self.move_path_closest_to(place_span.0); + if maybe_uninits.contains(mpi) { + self.report_use_of_moved_or_uninitialized( + location, + desired_action, + (prefix, place_span.0, place_span.1), + mpi, + ); + } // Only query longest prefix with a MovePath, not further + // ancestors; dataflow recurs on children when parents + // move (to support partial (re)inits). + // + // (I.e., querying parents breaks scenario 7; but may want + // to do such a query based on partial-init feature-gate.) + } + + /// Subslices correspond to multiple move paths, so we iterate through the + /// elements of the base array. For each element we check + /// + /// * Does this element overlap with our slice. + /// * Is any part of it uninitialized. + fn check_if_subslice_element_is_moved( + &mut self, + location: Location, + desired_action: InitializationRequiringAction, + place_span: (PlaceRef<'tcx>, Span), + maybe_uninits: &BitSet, + from: u64, + to: u64, + ) { + if let Some(mpi) = self.move_path_for_place(place_span.0) { + let move_paths = &self.move_data.move_paths; + + let root_path = &move_paths[mpi]; + for (child_mpi, child_move_path) in root_path.children(move_paths) { + let last_proj = child_move_path.place.projection.last().unwrap(); + if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj { + debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`."); + + if (from..to).contains(offset) { + let uninit_child = + self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| { + maybe_uninits.contains(mpi) + }); + + if let Some(uninit_child) = uninit_child { + self.report_use_of_moved_or_uninitialized( + location, + desired_action, + (place_span.0, place_span.0, place_span.1), + uninit_child, + ); + return; // don't bother finding other problems. + } + } + } + } + } + } + + fn check_if_path_or_subpath_is_moved( + &mut self, + location: Location, + desired_action: InitializationRequiringAction, + place_span: (PlaceRef<'tcx>, Span), + flow_state: &Flows<'cx, 'tcx>, + ) { + let maybe_uninits = &flow_state.uninits; + + // Bad scenarios: + // + // 1. Move of `a.b.c`, use of `a` or `a.b` + // partial initialization support, one might have `a.x` + // initialized but not `a.b`. + // 2. All bad scenarios from `check_if_full_path_is_moved` + // + // OK scenarios: + // + // 3. Move of `a.b.c`, use of `a.b.d` + // 4. Uninitialized `a.x`, initialized `a.b`, use of `a.b` + // 5. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b` + // must have been initialized for the use to be sound. + // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` + + self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); + + if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) = + place_span.0.last_projection() + { + let place_ty = place_base.ty(self.body(), self.infcx.tcx); + if let ty::Array(..) = place_ty.ty.kind() { + self.check_if_subslice_element_is_moved( + location, + desired_action, + (place_base, place_span.1), + maybe_uninits, + from, + to, + ); + return; + } + } + + // A move of any shallow suffix of `place` also interferes + // with an attempt to use `place`. This is scenario 3 above. + // + // (Distinct from handling of scenarios 1+2+4 above because + // `place` does not interfere with suffixes of its prefixes, + // e.g., `a.b.c` does not interfere with `a.b.d`) + // + // This code covers scenario 1. + + debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0); + if let Some(mpi) = self.move_path_for_place(place_span.0) { + let uninit_mpi = self + .move_data + .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi)); + + if let Some(uninit_mpi) = uninit_mpi { + self.report_use_of_moved_or_uninitialized( + location, + desired_action, + (place_span.0, place_span.0, place_span.1), + uninit_mpi, + ); + return; // don't bother finding other problems. + } + } + } + + /// Currently MoveData does not store entries for all places in + /// the input MIR. For example it will currently filter out + /// places that are Copy; thus we do not track places of shared + /// reference type. This routine will walk up a place along its + /// prefixes, searching for a foundational place that *is* + /// tracked in the MoveData. + /// + /// An Err result includes a tag indicated why the search failed. + /// Currently this can only occur if the place is built off of a + /// static variable, as we do not track those in the MoveData. + fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) { + match self.move_data.rev_lookup.find(place) { + LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => { + (self.move_data.move_paths[mpi].place.as_ref(), mpi) + } + LookupResult::Parent(None) => panic!("should have move path for every Local"), + } + } + + fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option { + // If returns None, then there is no move path corresponding + // to a direct owner of `place` (which means there is nothing + // that borrowck tracks for its analysis). + + match self.move_data.rev_lookup.find(place) { + LookupResult::Parent(_) => None, + LookupResult::Exact(mpi) => Some(mpi), + } + } + + fn check_if_assigned_path_is_moved( + &mut self, + location: Location, + (place, span): (Place<'tcx>, Span), + flow_state: &Flows<'cx, 'tcx>, + ) { + debug!("check_if_assigned_path_is_moved place: {:?}", place); + + // None case => assigning to `x` does not require `x` be initialized. + for (place_base, elem) in place.iter_projections().rev() { + match elem { + ProjectionElem::Index(_/*operand*/) | + ProjectionElem::ConstantIndex { .. } | + // assigning to P[i] requires P to be valid. + ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => + // assigning to (P->variant) is okay if assigning to `P` is okay + // + // FIXME: is this true even if P is an adt with a dtor? + { } + + // assigning to (*P) requires P to be initialized + ProjectionElem::Deref => { + self.check_if_full_path_is_moved( + location, InitializationRequiringAction::Use, + (place_base, span), flow_state); + // (base initialized; no need to + // recur further) + break; + } + + ProjectionElem::Subslice { .. } => { + panic!("we don't allow assignments to subslices, location: {:?}", + location); + } + + ProjectionElem::Field(..) => { + // if type of `P` has a dtor, then + // assigning to `P.f` requires `P` itself + // be already initialized + let tcx = self.infcx.tcx; + let base_ty = place_base.ty(self.body(), tcx).ty; + match base_ty.kind() { + ty::Adt(def, _) if def.has_dtor(tcx) => { + self.check_if_path_or_subpath_is_moved( + location, InitializationRequiringAction::Assignment, + (place_base, span), flow_state); + + // (base initialized; no need to + // recur further) + break; + } + + // Once `let s; s.x = V; read(s.x);`, + // is allowed, remove this match arm. + ty::Adt(..) | ty::Tuple(..) => { + check_parent_of_field(self, location, place_base, span, flow_state); + + // rust-lang/rust#21232, #54499, #54986: during period where we reject + // partial initialization, do not complain about unnecessary `mut` on + // an attempt to do a partial initialization. + self.used_mut.insert(place.local); + } + + _ => {} + } + } + } + } + + fn check_parent_of_field<'cx, 'tcx>( + this: &mut MirBorrowckCtxt<'cx, 'tcx>, + location: Location, + base: PlaceRef<'tcx>, + span: Span, + flow_state: &Flows<'cx, 'tcx>, + ) { + // rust-lang/rust#21232: Until Rust allows reads from the + // initialized parts of partially initialized structs, we + // will, starting with the 2018 edition, reject attempts + // to write to structs that are not fully initialized. + // + // In other words, *until* we allow this: + // + // 1. `let mut s; s.x = Val; read(s.x);` + // + // we will for now disallow this: + // + // 2. `let mut s; s.x = Val;` + // + // and also this: + // + // 3. `let mut s = ...; drop(s); s.x=Val;` + // + // This does not use check_if_path_or_subpath_is_moved, + // because we want to *allow* reinitializations of fields: + // e.g., want to allow + // + // `let mut s = ...; drop(s.x); s.x=Val;` + // + // This does not use check_if_full_path_is_moved on + // `base`, because that would report an error about the + // `base` as a whole, but in this scenario we *really* + // want to report an error about the actual thing that was + // moved, which may be some prefix of `base`. + + // Shallow so that we'll stop at any dereference; we'll + // report errors about issues with such bases elsewhere. + let maybe_uninits = &flow_state.uninits; + + // Find the shortest uninitialized prefix you can reach + // without going over a Deref. + let mut shortest_uninit_seen = None; + for prefix in this.prefixes(base, PrefixSet::Shallow) { + let mpi = match this.move_path_for_place(prefix) { + Some(mpi) => mpi, + None => continue, + }; + + if maybe_uninits.contains(mpi) { + debug!( + "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}", + shortest_uninit_seen, + Some((prefix, mpi)) + ); + shortest_uninit_seen = Some((prefix, mpi)); + } else { + debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi)); + } + } + + if let Some((prefix, mpi)) = shortest_uninit_seen { + // Check for a reassignment into an uninitialized field of a union (for example, + // after a move out). In this case, do not report an error here. There is an + // exception, if this is the first assignment into the union (that is, there is + // no move out from an earlier location) then this is an attempt at initialization + // of the union - we should error in that case. + let tcx = this.infcx.tcx; + if base.ty(this.body(), tcx).ty.is_union() { + if this.move_data.path_map[mpi].iter().any(|moi| { + this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) + }) { + return; + } + } + + this.report_use_of_moved_or_uninitialized( + location, + InitializationRequiringAction::PartialAssignment, + (prefix, base, span), + mpi, + ); + } + } + } + + /// Checks the permissions for the given place and read or write kind + /// + /// Returns `true` if an error is reported. + fn check_access_permissions( + &mut self, + (place, span): (Place<'tcx>, Span), + kind: ReadOrWrite, + is_local_mutation_allowed: LocalMutationIsAllowed, + flow_state: &Flows<'cx, 'tcx>, + location: Location, + ) -> bool { + debug!( + "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})", + place, kind, is_local_mutation_allowed + ); + + let error_access; + let the_place_err; + + match kind { + Reservation(WriteKind::MutableBorrow( + borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), + )) + | Write(WriteKind::MutableBorrow( + borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), + )) => { + let is_local_mutation_allowed = match borrow_kind { + BorrowKind::Unique => LocalMutationIsAllowed::Yes, + BorrowKind::Mut { .. } => is_local_mutation_allowed, + BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), + }; + match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { + Ok(root_place) => { + self.add_used_mut(root_place, flow_state); + return false; + } + Err(place_err) => { + error_access = AccessKind::MutableBorrow; + the_place_err = place_err; + } + } + } + Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { + match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { + Ok(root_place) => { + self.add_used_mut(root_place, flow_state); + return false; + } + Err(place_err) => { + error_access = AccessKind::Mutate; + the_place_err = place_err; + } + } + } + + Reservation( + WriteKind::Move + | WriteKind::StorageDeadOrDrop + | WriteKind::MutableBorrow(BorrowKind::Shared) + | WriteKind::MutableBorrow(BorrowKind::Shallow), + ) + | Write( + WriteKind::Move + | WriteKind::StorageDeadOrDrop + | WriteKind::MutableBorrow(BorrowKind::Shared) + | WriteKind::MutableBorrow(BorrowKind::Shallow), + ) => { + if let (Err(_), true) = ( + self.is_mutable(place.as_ref(), is_local_mutation_allowed), + self.errors_buffer.is_empty(), + ) { + // rust-lang/rust#46908: In pure NLL mode this code path should be + // unreachable, but we use `delay_span_bug` because we can hit this when + // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug` + // enabled. We don't want to ICE for that case, as other errors will have + // been emitted (#52262). + self.infcx.tcx.sess.delay_span_bug( + span, + &format!( + "Accessing `{:?}` with the kind `{:?}` shouldn't be possible", + place, kind, + ), + ); + } + return false; + } + Activation(..) => { + // permission checks are done at Reservation point. + return false; + } + Read( + ReadKind::Borrow( + BorrowKind::Unique + | BorrowKind::Mut { .. } + | BorrowKind::Shared + | BorrowKind::Shallow, + ) + | ReadKind::Copy, + ) => { + // Access authorized + return false; + } + } + + // rust-lang/rust#21232, #54986: during period where we reject + // partial initialization, do not complain about mutability + // errors except for actual mutation (as opposed to an attempt + // to do a partial initialization). + let previously_initialized = + self.is_local_ever_initialized(place.local, flow_state).is_some(); + + // at this point, we have set up the error reporting state. + if previously_initialized { + self.report_mutability_error(place, span, the_place_err, error_access, location); + true + } else { + false + } + } + + fn is_local_ever_initialized( + &self, + local: Local, + flow_state: &Flows<'cx, 'tcx>, + ) -> Option { + let mpi = self.move_data.rev_lookup.find_local(local); + let ii = &self.move_data.init_path_map[mpi]; + for &index in ii { + if flow_state.ever_inits.contains(index) { + return Some(index); + } + } + None + } + + /// Adds the place into the used mutable variables set + fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'cx, 'tcx>) { + match root_place { + RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { + // If the local may have been initialized, and it is now currently being + // mutated, then it is justified to be annotated with the `mut` + // keyword, since the mutation may be a possible reassignment. + if is_local_mutation_allowed != LocalMutationIsAllowed::Yes + && self.is_local_ever_initialized(local, flow_state).is_some() + { + self.used_mut.insert(local); + } + } + RootPlace { + place_local: _, + place_projection: _, + is_local_mutation_allowed: LocalMutationIsAllowed::Yes, + } => {} + RootPlace { + place_local, + place_projection: place_projection @ [.., _], + is_local_mutation_allowed: _, + } => { + if let Some(field) = self.is_upvar_field_projection(PlaceRef { + local: place_local, + projection: place_projection, + }) { + self.used_mut_upvars.push(field); + } + } + } + } + + /// Whether this value can be written or borrowed mutably. + /// Returns the root place if the place passed in is a projection. + fn is_mutable( + &self, + place: PlaceRef<'tcx>, + is_local_mutation_allowed: LocalMutationIsAllowed, + ) -> Result, PlaceRef<'tcx>> { + debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed); + match place.last_projection() { + None => { + let local = &self.body.local_decls[place.local]; + match local.mutability { + Mutability::Not => match is_local_mutation_allowed { + LocalMutationIsAllowed::Yes => Ok(RootPlace { + place_local: place.local, + place_projection: place.projection, + is_local_mutation_allowed: LocalMutationIsAllowed::Yes, + }), + LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace { + place_local: place.local, + place_projection: place.projection, + is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars, + }), + LocalMutationIsAllowed::No => Err(place), + }, + Mutability::Mut => Ok(RootPlace { + place_local: place.local, + place_projection: place.projection, + is_local_mutation_allowed, + }), + } + } + Some((place_base, elem)) => { + match elem { + ProjectionElem::Deref => { + let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty; + + // Check the kind of deref to decide + match base_ty.kind() { + ty::Ref(_, _, mutbl) => { + match mutbl { + // Shared borrowed data is never mutable + hir::Mutability::Not => Err(place), + // Mutably borrowed data is mutable, but only if we have a + // unique path to the `&mut` + hir::Mutability::Mut => { + let mode = match self.is_upvar_field_projection(place) { + Some(field) if self.upvars[field.index()].by_ref => { + is_local_mutation_allowed + } + _ => LocalMutationIsAllowed::Yes, + }; + + self.is_mutable(place_base, mode) + } + } + } + ty::RawPtr(tnm) => { + match tnm.mutbl { + // `*const` raw pointers are not mutable + hir::Mutability::Not => Err(place), + // `*mut` raw pointers are always mutable, regardless of + // context. The users have to check by themselves. + hir::Mutability::Mut => Ok(RootPlace { + place_local: place.local, + place_projection: place.projection, + is_local_mutation_allowed, + }), + } + } + // `Box` owns its content, so mutable if its location is mutable + _ if base_ty.is_box() => { + self.is_mutable(place_base, is_local_mutation_allowed) + } + // Deref should only be for reference, pointers or boxes + _ => bug!("Deref of unexpected type: {:?}", base_ty), + } + } + // All other projections are owned by their base path, so mutable if + // base path is mutable + ProjectionElem::Field(..) + | ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(..) => { + let upvar_field_projection = self.is_upvar_field_projection(place); + if let Some(field) = upvar_field_projection { + let upvar = &self.upvars[field.index()]; + debug!( + "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \ + place={:?}, place_base={:?}", + upvar, is_local_mutation_allowed, place, place_base + ); + match (upvar.place.mutability, is_local_mutation_allowed) { + ( + Mutability::Not, + LocalMutationIsAllowed::No + | LocalMutationIsAllowed::ExceptUpvars, + ) => Err(place), + (Mutability::Not, LocalMutationIsAllowed::Yes) + | (Mutability::Mut, _) => { + // Subtle: this is an upvar + // reference, so it looks like + // `self.foo` -- we want to double + // check that the location `*self` + // is mutable (i.e., this is not a + // `Fn` closure). But if that + // check succeeds, we want to + // *blame* the mutability on + // `place` (that is, + // `self.foo`). This is used to + // propagate the info about + // whether mutability declarations + // are used outwards, so that we register + // the outer variable as mutable. Otherwise a + // test like this fails to record the `mut` + // as needed: + // + // ``` + // fn foo(_f: F) { } + // fn main() { + // let var = Vec::new(); + // foo(move || { + // var.push(1); + // }); + // } + // ``` + let _ = + self.is_mutable(place_base, is_local_mutation_allowed)?; + Ok(RootPlace { + place_local: place.local, + place_projection: place.projection, + is_local_mutation_allowed, + }) + } + } + } else { + self.is_mutable(place_base, is_local_mutation_allowed) + } + } + } + } + } + } + + /// If `place` is a field projection, and the field is being projected from a closure type, + /// then returns the index of the field being projected. Note that this closure will always + /// be `self` in the current MIR, because that is the only time we directly access the fields + /// of a closure type. + fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option { + path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body()) + } +} + +/// The degree of overlap between 2 places for borrow-checking. +enum Overlap { + /// The places might partially overlap - in this case, we give + /// up and say that they might conflict. This occurs when + /// different fields of a union are borrowed. For example, + /// if `u` is a union, we have no way of telling how disjoint + /// `u.a.x` and `a.b.y` are. + Arbitrary, + /// The places have the same type, and are either completely disjoint + /// or equal - i.e., they can't "partially" overlap as can occur with + /// unions. This is the "base case" on which we recur for extensions + /// of the place. + EqualOrDisjoint, + /// The places are disjoint, so we know all extensions of them + /// will also be disjoint. + Disjoint, +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/location.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/location.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/location.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/location.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,107 @@ +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::{BasicBlock, Body, Location}; + +/// Maps between a MIR Location, which identifies a particular +/// statement within a basic block, to a "rich location", which +/// identifies at a finer granularity. In particular, we distinguish +/// the *start* of a statement and the *mid-point*. The mid-point is +/// the point *just* before the statement takes effect; in particular, +/// for an assignment `A = B`, it is the point where B is about to be +/// written into A. This mid-point is a kind of hack to work around +/// our inability to track the position information at sufficient +/// granularity through outlives relations; however, the rich location +/// table serves another purpose: it compresses locations from +/// multiple words into a single u32. +pub struct LocationTable { + num_points: usize, + statements_before_block: IndexVec, +} + +rustc_index::newtype_index! { + pub struct LocationIndex { + DEBUG_FORMAT = "LocationIndex({})" + } +} + +#[derive(Copy, Clone, Debug)] +pub enum RichLocation { + Start(Location), + Mid(Location), +} + +impl LocationTable { + crate fn new(body: &Body<'_>) -> Self { + let mut num_points = 0; + let statements_before_block = body + .basic_blocks() + .iter() + .map(|block_data| { + let v = num_points; + num_points += (block_data.statements.len() + 1) * 2; + v + }) + .collect(); + + debug!("LocationTable(statements_before_block={:#?})", statements_before_block); + debug!("LocationTable: num_points={:#?}", num_points); + + Self { num_points, statements_before_block } + } + + pub fn all_points(&self) -> impl Iterator { + (0..self.num_points).map(LocationIndex::new) + } + + pub fn start_index(&self, location: Location) -> LocationIndex { + let Location { block, statement_index } = location; + let start_index = self.statements_before_block[block]; + LocationIndex::new(start_index + statement_index * 2) + } + + pub fn mid_index(&self, location: Location) -> LocationIndex { + let Location { block, statement_index } = location; + let start_index = self.statements_before_block[block]; + LocationIndex::new(start_index + statement_index * 2 + 1) + } + + pub fn to_location(&self, index: LocationIndex) -> RichLocation { + let point_index = index.index(); + + // Find the basic block. We have a vector with the + // starting index of the statement in each block. Imagine + // we have statement #22, and we have a vector like: + // + // [0, 10, 20] + // + // In that case, this represents point_index 2 of + // basic block BB2. We know this because BB0 accounts for + // 0..10, BB1 accounts for 11..20, and BB2 accounts for + // 20... + // + // To compute this, we could do a binary search, but + // because I am lazy we instead iterate through to find + // the last point where the "first index" (0, 10, or 20) + // was less than the statement index (22). In our case, this will + // be (BB2, 20). + let (block, &first_index) = self + .statements_before_block + .iter_enumerated() + .filter(|(_, first_index)| **first_index <= point_index) + .last() + .unwrap(); + + let statement_index = (point_index - first_index) / 2; + if index.is_start() { + RichLocation::Start(Location { block, statement_index }) + } else { + RichLocation::Mid(Location { block, statement_index }) + } + } +} + +impl LocationIndex { + fn is_start(&self) -> bool { + // even indices are start points; odd indices are mid points + (self.index() % 2) == 0 + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/member_constraints.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/member_constraints.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/member_constraints.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/member_constraints.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,224 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::IndexVec; +use rustc_middle::infer::MemberConstraint; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; +use std::hash::Hash; +use std::ops::Index; + +/// Compactly stores a set of `R0 member of [R1...Rn]` constraints, +/// indexed by the region `R0`. +crate struct MemberConstraintSet<'tcx, R> +where + R: Copy + Eq, +{ + /// Stores the first "member" constraint for a given `R0`. This is an + /// index into the `constraints` vector below. + first_constraints: FxHashMap, + + /// Stores the data about each `R0 member of [R1..Rn]` constraint. + /// These are organized into a linked list, so each constraint + /// contains the index of the next constraint with the same `R0`. + constraints: IndexVec>, + + /// Stores the `R1..Rn` regions for *all* sets. For any given + /// constraint, we keep two indices so that we can pull out a + /// slice. + choice_regions: Vec, +} + +/// Represents a `R0 member of [R1..Rn]` constraint +crate struct NllMemberConstraint<'tcx> { + next_constraint: Option, + + /// The span where the hidden type was instantiated. + crate definition_span: Span, + + /// The hidden type in which `R0` appears. (Used in error reporting.) + crate hidden_ty: Ty<'tcx>, + + /// The region `R0`. + crate member_region_vid: ty::RegionVid, + + /// Index of `R1` in `choice_regions` vector from `MemberConstraintSet`. + start_index: usize, + + /// Index of `Rn` in `choice_regions` vector from `MemberConstraintSet`. + end_index: usize, +} + +rustc_index::newtype_index! { + crate struct NllMemberConstraintIndex { + DEBUG_FORMAT = "MemberConstraintIndex({})" + } +} + +impl Default for MemberConstraintSet<'tcx, ty::RegionVid> { + fn default() -> Self { + Self { + first_constraints: Default::default(), + constraints: Default::default(), + choice_regions: Default::default(), + } + } +} + +impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> { + /// Pushes a member constraint into the set. + /// + /// The input member constraint `m_c` is in the form produced by + /// the `rustc_middle::infer` code. + /// + /// The `to_region_vid` callback fn is used to convert the regions + /// within into `RegionVid` format -- it typically consults the + /// `UniversalRegions` data structure that is known to the caller + /// (but which this code is unaware of). + crate fn push_constraint( + &mut self, + m_c: &MemberConstraint<'tcx>, + mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid, + ) { + debug!("push_constraint(m_c={:?})", m_c); + let member_region_vid: ty::RegionVid = to_region_vid(m_c.member_region); + let next_constraint = self.first_constraints.get(&member_region_vid).cloned(); + let start_index = self.choice_regions.len(); + let end_index = start_index + m_c.choice_regions.len(); + debug!("push_constraint: member_region_vid={:?}", member_region_vid); + let constraint_index = self.constraints.push(NllMemberConstraint { + next_constraint, + member_region_vid, + definition_span: m_c.definition_span, + hidden_ty: m_c.hidden_ty, + start_index, + end_index, + }); + self.first_constraints.insert(member_region_vid, constraint_index); + self.choice_regions.extend(m_c.choice_regions.iter().map(|&r| to_region_vid(r))); + } +} + +impl MemberConstraintSet<'tcx, R1> +where + R1: Copy + Hash + Eq, +{ + /// Remap the "member region" key using `map_fn`, producing a new + /// member constraint set. This is used in the NLL code to map from + /// the original `RegionVid` to an scc index. In some cases, we + /// may have multiple `R1` values mapping to the same `R2` key -- that + /// is ok, the two sets will be merged. + crate fn into_mapped( + self, + mut map_fn: impl FnMut(R1) -> R2, + ) -> MemberConstraintSet<'tcx, R2> + where + R2: Copy + Hash + Eq, + { + // We can re-use most of the original data, just tweaking the + // linked list links a bit. + // + // For example if we had two keys `Ra` and `Rb` that both now + // wind up mapped to the same key `S`, we would append the + // linked list for `Ra` onto the end of the linked list for + // `Rb` (or vice versa) -- this basically just requires + // rewriting the final link from one list to point at the other + // other (see `append_list`). + + let MemberConstraintSet { first_constraints, mut constraints, choice_regions } = self; + + let mut first_constraints2 = FxHashMap::default(); + first_constraints2.reserve(first_constraints.len()); + + for (r1, start1) in first_constraints { + let r2 = map_fn(r1); + if let Some(&start2) = first_constraints2.get(&r2) { + append_list(&mut constraints, start1, start2); + } + first_constraints2.insert(r2, start1); + } + + MemberConstraintSet { first_constraints: first_constraints2, constraints, choice_regions } + } +} + +impl MemberConstraintSet<'tcx, R> +where + R: Copy + Hash + Eq, +{ + crate fn all_indices(&self) -> impl Iterator + '_ { + self.constraints.indices() + } + + /// Iterate down the constraint indices associated with a given + /// peek-region. You can then use `choice_regions` and other + /// methods to access data. + crate fn indices( + &self, + member_region_vid: R, + ) -> impl Iterator + '_ { + let mut next = self.first_constraints.get(&member_region_vid).cloned(); + std::iter::from_fn(move || -> Option { + if let Some(current) = next { + next = self.constraints[current].next_constraint; + Some(current) + } else { + None + } + }) + } + + /// Returns the "choice regions" for a given member + /// constraint. This is the `R1..Rn` from a constraint like: + /// + /// ``` + /// R0 member of [R1..Rn] + /// ``` + crate fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] { + let NllMemberConstraint { start_index, end_index, .. } = &self.constraints[pci]; + &self.choice_regions[*start_index..*end_index] + } +} + +impl<'tcx, R> Index for MemberConstraintSet<'tcx, R> +where + R: Copy + Eq, +{ + type Output = NllMemberConstraint<'tcx>; + + fn index(&self, i: NllMemberConstraintIndex) -> &NllMemberConstraint<'tcx> { + &self.constraints[i] + } +} + +/// Given a linked list starting at `source_list` and another linked +/// list starting at `target_list`, modify `target_list` so that it is +/// followed by `source_list`. +/// +/// Before: +/// +/// ``` +/// target_list: A -> B -> C -> (None) +/// source_list: D -> E -> F -> (None) +/// ``` +/// +/// After: +/// +/// ``` +/// target_list: A -> B -> C -> D -> E -> F -> (None) +/// ``` +fn append_list( + constraints: &mut IndexVec>, + target_list: NllMemberConstraintIndex, + source_list: NllMemberConstraintIndex, +) { + let mut p = target_list; + loop { + let mut r = &mut constraints[p]; + match r.next_constraint { + Some(q) => p = q, + None => { + r.next_constraint = Some(source_list); + return; + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/nll.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/nll.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/nll.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/nll.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,461 @@ +//! The entry point of the NLL borrow checker. + +use rustc_data_structures::vec_map::VecMap; +use rustc_errors::Diagnostic; +use rustc_index::vec::IndexVec; +use rustc_infer::infer::InferCtxt; +use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; +use rustc_middle::mir::{ + BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, + Promoted, +}; +use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty}; +use rustc_span::symbol::sym; +use std::env; +use std::fmt::Debug; +use std::io; +use std::path::PathBuf; +use std::rc::Rc; +use std::str::FromStr; + +use polonius_engine::{Algorithm, Output}; + +use rustc_mir_dataflow::impls::MaybeInitializedPlaces; +use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData}; +use rustc_mir_dataflow::ResultsCursor; + +use crate::{ + borrow_set::BorrowSet, + constraint_generation, + diagnostics::RegionErrors, + facts::{AllFacts, AllFactsExt, RustcFacts}, + invalidation, + location::LocationTable, + region_infer::{values::RegionValueElements, RegionInferenceContext}, + renumber, + type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, + universal_regions::UniversalRegions, + Upvar, +}; + +pub type PoloniusOutput = Output; + +/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any +/// closure requirements to propagate, and any generated errors. +crate struct NllOutput<'tcx> { + pub regioncx: RegionInferenceContext<'tcx>, + pub opaque_type_values: VecMap, Ty<'tcx>>, + pub polonius_input: Option>, + pub polonius_output: Option>, + pub opt_closure_req: Option>, + pub nll_errors: RegionErrors<'tcx>, +} + +/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal +/// regions (e.g., region parameters) declared on the function. That set will need to be given to +/// `compute_regions`. +#[instrument(skip(infcx, param_env, body, promoted), level = "debug")] +pub(crate) fn replace_regions_in_mir<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body: &mut Body<'tcx>, + promoted: &mut IndexVec>, +) -> UniversalRegions<'tcx> { + let def = body.source.with_opt_param().as_local().unwrap(); + + debug!(?def); + + // Compute named region information. This also renumbers the inputs/outputs. + let universal_regions = UniversalRegions::new(infcx, def, param_env); + + // Replace all remaining regions with fresh inference variables. + renumber::renumber_mir(infcx, body, promoted); + + dump_mir(infcx.tcx, None, "renumber", &0, body, |_, _| Ok(())); + + universal_regions +} + +// This function populates an AllFacts instance with base facts related to +// MovePaths and needed for the move analysis. +fn populate_polonius_move_facts( + all_facts: &mut AllFacts, + move_data: &MoveData<'_>, + location_table: &LocationTable, + body: &Body<'_>, +) { + all_facts + .path_is_var + .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (m, v))); + + for (child, move_path) in move_data.move_paths.iter_enumerated() { + if let Some(parent) = move_path.parent { + all_facts.child_path.push((child, parent)); + } + } + + let fn_entry_start = location_table + .start_index(Location { block: BasicBlock::from_u32(0u32), statement_index: 0 }); + + // initialized_at + for init in move_data.inits.iter() { + match init.location { + InitLocation::Statement(location) => { + let block_data = &body[location.block]; + let is_terminator = location.statement_index == block_data.statements.len(); + + if is_terminator && init.kind == InitKind::NonPanicPathOnly { + // We are at the terminator of an init that has a panic path, + // and where the init should not happen on panic + + for &successor in block_data.terminator().successors() { + if body[successor].is_cleanup { + continue; + } + + // The initialization happened in (or rather, when arriving at) + // the successors, but not in the unwind block. + let first_statement = Location { block: successor, statement_index: 0 }; + all_facts + .path_assigned_at_base + .push((init.path, location_table.start_index(first_statement))); + } + } else { + // In all other cases, the initialization just happens at the + // midpoint, like any other effect. + all_facts + .path_assigned_at_base + .push((init.path, location_table.mid_index(location))); + } + } + // Arguments are initialized on function entry + InitLocation::Argument(local) => { + assert!(body.local_kind(local) == LocalKind::Arg); + all_facts.path_assigned_at_base.push((init.path, fn_entry_start)); + } + } + } + + for (local, &path) in move_data.rev_lookup.iter_locals_enumerated() { + if body.local_kind(local) != LocalKind::Arg { + // Non-arguments start out deinitialised; we simulate this with an + // initial move: + all_facts.path_moved_at_base.push((path, fn_entry_start)); + } + } + + // moved_out_at + // deinitialisation is assumed to always happen! + all_facts + .path_moved_at_base + .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source)))); +} + +/// Computes the (non-lexical) regions from the input MIR. +/// +/// This may result in errors being reported. +pub(crate) fn compute_regions<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + universal_regions: UniversalRegions<'tcx>, + body: &Body<'tcx>, + promoted: &IndexVec>, + location_table: &LocationTable, + param_env: ty::ParamEnv<'tcx>, + flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, + move_data: &MoveData<'tcx>, + borrow_set: &BorrowSet<'tcx>, + upvars: &[Upvar<'tcx>], + use_polonius: bool, +) -> NllOutput<'tcx> { + let mut all_facts = + (use_polonius || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); + + let universal_regions = Rc::new(universal_regions); + + let elements = &Rc::new(RegionValueElements::new(&body)); + + // Run the MIR type-checker. + let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = + type_check::type_check( + infcx, + param_env, + body, + promoted, + &universal_regions, + location_table, + borrow_set, + &mut all_facts, + flow_inits, + move_data, + elements, + upvars, + ); + + if let Some(all_facts) = &mut all_facts { + let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation"); + all_facts.universal_region.extend(universal_regions.universal_regions()); + populate_polonius_move_facts(all_facts, move_data, location_table, &body); + + // Emit universal regions facts, and their relations, for Polonius. + // + // 1: universal regions are modeled in Polonius as a pair: + // - the universal region vid itself. + // - a "placeholder loan" associated to this universal region. Since they don't exist in + // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index + // added to the existing number of loans, as if they succeeded them in the set. + // + let borrow_count = borrow_set.len(); + debug!( + "compute_regions: polonius placeholders, num_universals={}, borrow_count={}", + universal_regions.len(), + borrow_count + ); + + for universal_region in universal_regions.universal_regions() { + let universal_region_idx = universal_region.index(); + let placeholder_loan_idx = borrow_count + universal_region_idx; + all_facts.placeholder.push((universal_region, placeholder_loan_idx.into())); + } + + // 2: the universal region relations `outlives` constraints are emitted as + // `known_placeholder_subset` facts. + for (fr1, fr2) in universal_region_relations.known_outlives() { + if fr1 != fr2 { + debug!( + "compute_regions: emitting polonius `known_placeholder_subset` \ + fr1={:?}, fr2={:?}", + fr1, fr2 + ); + all_facts.known_placeholder_subset.push((*fr1, *fr2)); + } + } + } + + // Create the region inference context, taking ownership of the + // region inference data that was contained in `infcx`, and the + // base constraints generated by the type-check. + let var_origins = infcx.take_region_var_origins(); + let MirTypeckRegionConstraints { + placeholder_indices, + placeholder_index_to_region: _, + mut liveness_constraints, + outlives_constraints, + member_constraints, + closure_bounds_mapping, + universe_causes, + type_tests, + } = constraints; + let placeholder_indices = Rc::new(placeholder_indices); + + constraint_generation::generate_constraints( + infcx, + &mut liveness_constraints, + &mut all_facts, + location_table, + &body, + borrow_set, + ); + + let mut regioncx = RegionInferenceContext::new( + var_origins, + universal_regions, + placeholder_indices, + universal_region_relations, + outlives_constraints, + member_constraints, + closure_bounds_mapping, + universe_causes, + type_tests, + liveness_constraints, + elements, + ); + + // Generate various additional constraints. + invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set); + + let def_id = body.source.def_id(); + + // Dump facts if requested. + let polonius_output = all_facts.as_ref().and_then(|all_facts| { + if infcx.tcx.sess.opts.debugging_opts.nll_facts { + let def_path = infcx.tcx.def_path(def_id); + let dir_path = PathBuf::from(&infcx.tcx.sess.opts.debugging_opts.nll_facts_dir) + .join(def_path.to_filename_friendly_no_crate()); + all_facts.write_to_dir(dir_path, location_table).unwrap(); + } + + if use_polonius { + let algorithm = + env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid")); + let algorithm = Algorithm::from_str(&algorithm).unwrap(); + debug!("compute_regions: using polonius algorithm {:?}", algorithm); + let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis"); + Some(Rc::new(Output::compute(&all_facts, algorithm, false))) + } else { + None + } + }); + + // Solve the region constraints. + let (closure_region_requirements, nll_errors) = + regioncx.solve(infcx, &body, polonius_output.clone()); + + if !nll_errors.is_empty() { + // Suppress unhelpful extra errors in `infer_opaque_types`. + infcx.set_tainted_by_errors(); + } + + let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span); + + NllOutput { + regioncx, + opaque_type_values: remapped_opaque_tys, + polonius_input: all_facts.map(Box::new), + polonius_output, + opt_closure_req: closure_region_requirements, + nll_errors, + } +} + +pub(super) fn dump_mir_results<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + body: &Body<'tcx>, + regioncx: &RegionInferenceContext<'tcx>, + closure_region_requirements: &Option>, +) { + if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) { + return; + } + + dump_mir(infcx.tcx, None, "nll", &0, body, |pass_where, out| { + match pass_where { + // Before the CFG, dump out the values for each region variable. + PassWhere::BeforeCFG => { + regioncx.dump_mir(infcx.tcx, out)?; + writeln!(out, "|")?; + + if let Some(closure_region_requirements) = closure_region_requirements { + writeln!(out, "| Free Region Constraints")?; + for_each_region_constraint(closure_region_requirements, &mut |msg| { + writeln!(out, "| {}", msg) + })?; + writeln!(out, "|")?; + } + } + + PassWhere::BeforeLocation(_) => {} + + PassWhere::AfterTerminator(_) => {} + + PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {} + } + Ok(()) + }); + + // Also dump the inference graph constraints as a graphviz file. + let _: io::Result<()> = try { + let mut file = + create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, body.source)?; + regioncx.dump_graphviz_raw_constraints(&mut file)?; + }; + + // Also dump the inference graph constraints as a graphviz file. + let _: io::Result<()> = try { + let mut file = + create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, body.source)?; + regioncx.dump_graphviz_scc_constraints(&mut file)?; + }; +} + +pub(super) fn dump_annotation<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + body: &Body<'tcx>, + regioncx: &RegionInferenceContext<'tcx>, + closure_region_requirements: &Option>, + opaque_type_values: &VecMap, Ty<'tcx>>, + errors_buffer: &mut Vec, +) { + let tcx = infcx.tcx; + let base_def_id = tcx.closure_base_def_id(body.source.def_id()); + if !tcx.has_attr(base_def_id, sym::rustc_regions) { + return; + } + + // When the enclosing function is tagged with `#[rustc_regions]`, + // we dump out various bits of state as warnings. This is useful + // for verifying that the compiler is behaving as expected. These + // warnings focus on the closure region requirements -- for + // viewing the intraprocedural state, the -Zdump-mir output is + // better. + + let mut err = if let Some(closure_region_requirements) = closure_region_requirements { + let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "external requirements"); + + regioncx.annotate(tcx, &mut err); + + err.note(&format!( + "number of external vids: {}", + closure_region_requirements.num_external_vids + )); + + // Dump the region constraints we are imposing *between* those + // newly created variables. + for_each_region_constraint(closure_region_requirements, &mut |msg| { + err.note(msg); + Ok(()) + }) + .unwrap(); + + err + } else { + let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements"); + regioncx.annotate(tcx, &mut err); + + err + }; + + if !opaque_type_values.is_empty() { + err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values)); + } + + err.buffer(errors_buffer); +} + +fn for_each_region_constraint( + closure_region_requirements: &ClosureRegionRequirements<'_>, + with_msg: &mut dyn FnMut(&str) -> io::Result<()>, +) -> io::Result<()> { + for req in &closure_region_requirements.outlives_requirements { + let subject: &dyn Debug = match &req.subject { + ClosureOutlivesSubject::Region(subject) => subject, + ClosureOutlivesSubject::Ty(ty) => ty, + }; + with_msg(&format!("where {:?}: {:?}", subject, req.outlived_free_region,))?; + } + Ok(()) +} + +/// Right now, we piggy back on the `ReVar` to store our NLL inference +/// regions. These are indexed with `RegionVid`. This method will +/// assert that the region is a `ReVar` and extract its internal index. +/// This is reasonable because in our MIR we replace all universal regions +/// with inference variables. +pub trait ToRegionVid { + fn to_region_vid(self) -> RegionVid; +} + +impl<'tcx> ToRegionVid for &'tcx RegionKind { + fn to_region_vid(self) -> RegionVid { + if let ty::ReVar(vid) = self { *vid } else { bug!("region is not an ReVar: {:?}", self) } + } +} + +impl ToRegionVid for RegionVid { + fn to_region_vid(self) -> RegionVid { + self + } +} + +crate trait ConstraintDescription { + fn description(&self) -> &'static str; +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/path_utils.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/path_utils.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/path_utils.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/path_utils.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,171 @@ +use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; +use crate::places_conflict; +use crate::AccessDepth; +use crate::BorrowIndex; +use crate::Upvar; +use rustc_data_structures::graph::dominators::Dominators; +use rustc_middle::mir::BorrowKind; +use rustc_middle::mir::{BasicBlock, Body, Field, Location, Place, PlaceRef, ProjectionElem}; +use rustc_middle::ty::TyCtxt; + +/// Returns `true` if the borrow represented by `kind` is +/// allowed to be split into separate Reservation and +/// Activation phases. +pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool { + kind.allows_two_phase_borrow() +} + +/// Control for the path borrow checking code +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(super) enum Control { + Continue, + Break, +} + +/// Encapsulates the idea of iterating over every borrow that involves a particular path +pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( + s: &mut S, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + _location: Location, + access_place: (AccessDepth, Place<'tcx>), + borrow_set: &BorrowSet<'tcx>, + candidates: I, + mut op: F, +) where + F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control, + I: Iterator, +{ + let (access, place) = access_place; + + // FIXME: analogous code in check_loans first maps `place` to + // its base_path. + + // check for loan restricting path P being used. Accounts for + // borrows of P, P.a.b, etc. + for i in candidates { + let borrowed = &borrow_set[i]; + + if places_conflict::borrow_conflicts_with_place( + tcx, + body, + borrowed.borrowed_place, + borrowed.kind, + place.as_ref(), + access, + places_conflict::PlaceConflictBias::Overlap, + ) { + debug!( + "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", + i, borrowed, place, access + ); + let ctrl = op(s, i, borrowed); + if ctrl == Control::Break { + return; + } + } + } +} + +pub(super) fn is_active<'tcx>( + dominators: &Dominators, + borrow_data: &BorrowData<'tcx>, + location: Location, +) -> bool { + debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location); + + let activation_location = match borrow_data.activation_location { + // If this is not a 2-phase borrow, it is always active. + TwoPhaseActivation::NotTwoPhase => return true, + // And if the unique 2-phase use is not an activation, then it is *never* active. + TwoPhaseActivation::NotActivated => return false, + // Otherwise, we derive info from the activation point `loc`: + TwoPhaseActivation::ActivatedAt(loc) => loc, + }; + + // Otherwise, it is active for every location *except* in between + // the reservation and the activation: + // + // X + // / + // R <--+ Except for this + // / \ | diamond + // \ / | + // A <------+ + // | + // Z + // + // Note that we assume that: + // - the reservation R dominates the activation A + // - the activation A post-dominates the reservation R (ignoring unwinding edges). + // + // This means that there can't be an edge that leaves A and + // comes back into that diamond unless it passes through R. + // + // Suboptimal: In some cases, this code walks the dominator + // tree twice when it only has to be walked once. I am + // lazy. -nmatsakis + + // If dominated by the activation A, then it is active. The + // activation occurs upon entering the point A, so this is + // also true if location == activation_location. + if activation_location.dominates(location, dominators) { + return true; + } + + // The reservation starts *on exiting* the reservation block, + // so check if the location is dominated by R.successor. If so, + // this point falls in between the reservation and location. + let reserve_location = borrow_data.reserve_location.successor_within_block(); + if reserve_location.dominates(location, dominators) { + false + } else { + // Otherwise, this point is outside the diamond, so + // consider the borrow active. This could happen for + // example if the borrow remains active around a loop (in + // which case it would be active also for the point R, + // which would generate an error). + true + } +} + +/// Determines if a given borrow is borrowing local data +/// This is called for all Yield expressions on movable generators +pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool { + // Reborrow of already borrowed data is ignored + // Any errors will be caught on the initial borrow + !place.is_indirect() +} + +/// If `place` is a field projection, and the field is being projected from a closure type, +/// then returns the index of the field being projected. Note that this closure will always +/// be `self` in the current MIR, because that is the only time we directly access the fields +/// of a closure type. +pub(crate) fn is_upvar_field_projection( + tcx: TyCtxt<'tcx>, + upvars: &[Upvar<'tcx>], + place_ref: PlaceRef<'tcx>, + body: &Body<'tcx>, +) -> Option { + let mut place_ref = place_ref; + let mut by_ref = false; + + if let Some((place_base, ProjectionElem::Deref)) = place_ref.last_projection() { + place_ref = place_base; + by_ref = true; + } + + match place_ref.last_projection() { + Some((place_base, ProjectionElem::Field(field, _ty))) => { + let base_ty = place_base.ty(body, tcx).ty; + if (base_ty.is_closure() || base_ty.is_generator()) + && (!by_ref || upvars[field.index()].by_ref) + { + Some(field) + } else { + None + } + } + _ => None, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/place_ext.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/place_ext.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/place_ext.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/place_ext.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,81 @@ +use crate::borrow_set::LocalsStateAtExit; +use rustc_hir as hir; +use rustc_middle::mir::ProjectionElem; +use rustc_middle::mir::{Body, Mutability, Place}; +use rustc_middle::ty::{self, TyCtxt}; + +/// Extension methods for the `Place` type. +crate trait PlaceExt<'tcx> { + /// Returns `true` if we can safely ignore borrows of this place. + /// This is true whenever there is no action that the user can do + /// to the place `self` that would invalidate the borrow. This is true + /// for borrows of raw pointer dereferents as well as shared references. + fn ignore_borrow( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + locals_state_at_exit: &LocalsStateAtExit, + ) -> bool; +} + +impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { + fn ignore_borrow( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + locals_state_at_exit: &LocalsStateAtExit, + ) -> bool { + // If a local variable is immutable, then we only need to track borrows to guard + // against two kinds of errors: + // * The variable being dropped while still borrowed (e.g., because the fn returns + // a reference to a local variable) + // * The variable being moved while still borrowed + // + // In particular, the variable cannot be mutated -- the "access checks" will fail -- + // so we don't have to worry about mutation while borrowed. + if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } = + locals_state_at_exit + { + let ignore = !has_storage_dead_or_moved.contains(self.local) + && body.local_decls[self.local].mutability == Mutability::Not; + debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore); + if ignore { + return true; + } + } + + for (i, elem) in self.projection.iter().enumerate() { + let proj_base = &self.projection[..i]; + + if elem == ProjectionElem::Deref { + let ty = Place::ty_from(self.local, proj_base, body, tcx).ty; + match ty.kind() { + ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { + // For references to thread-local statics, we do need + // to track the borrow. + if body.local_decls[self.local].is_ref_to_thread_local() { + continue; + } + return true; + } + ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Not) => { + // For both derefs of raw pointers and `&T` + // references, the original path is `Copy` and + // therefore not significant. In particular, + // there is nothing the user can do to the + // original path that would invalidate the + // newly created reference -- and if there + // were, then the user could have copied the + // original path into a new variable and + // borrowed *that* one, leaving the original + // path unborrowed. + return true; + } + _ => {} + } + } + } + + false + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/places_conflict.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/places_conflict.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/places_conflict.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/places_conflict.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,539 @@ +use crate::ArtificialField; +use crate::Overlap; +use crate::{AccessDepth, Deep, Shallow}; +use rustc_hir as hir; +use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem}; +use rustc_middle::ty::{self, TyCtxt}; +use std::cmp::max; +use std::iter; + +/// When checking if a place conflicts with another place, this enum is used to influence decisions +/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`. +/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these +/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate +/// being run in the calling context, the conservative choice is to assume the compared indices +/// are disjoint (and therefore, do not overlap). +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +crate enum PlaceConflictBias { + Overlap, + NoOverlap, +} + +/// Helper function for checking if places conflict with a mutable borrow and deep access depth. +/// This is used to check for places conflicting outside of the borrow checking code (such as in +/// dataflow). +crate fn places_conflict<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + borrow_place: Place<'tcx>, + access_place: Place<'tcx>, + bias: PlaceConflictBias, +) -> bool { + borrow_conflicts_with_place( + tcx, + body, + borrow_place, + BorrowKind::Mut { allow_two_phase_borrow: true }, + access_place.as_ref(), + AccessDepth::Deep, + bias, + ) +} + +/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and +/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime +/// array indices, for example) should be interpreted - this depends on what the caller wants in +/// order to make the conservative choice and preserve soundness. +pub(super) fn borrow_conflicts_with_place<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + borrow_place: Place<'tcx>, + borrow_kind: BorrowKind, + access_place: PlaceRef<'tcx>, + access: AccessDepth, + bias: PlaceConflictBias, +) -> bool { + debug!( + "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})", + borrow_place, access_place, access, bias, + ); + + // This Local/Local case is handled by the more general code below, but + // it's so common that it's a speed win to check for it first. + if let Some(l1) = borrow_place.as_local() { + if let Some(l2) = access_place.as_local() { + return l1 == l2; + } + } + + place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias) +} + +fn place_components_conflict<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + borrow_place: Place<'tcx>, + borrow_kind: BorrowKind, + access_place: PlaceRef<'tcx>, + access: AccessDepth, + bias: PlaceConflictBias, +) -> bool { + // The borrowck rules for proving disjointness are applied from the "root" of the + // borrow forwards, iterating over "similar" projections in lockstep until + // we can prove overlap one way or another. Essentially, we treat `Overlap` as + // a monoid and report a conflict if the product ends up not being `Disjoint`. + // + // At each step, if we didn't run out of borrow or place, we know that our elements + // have the same type, and that they only overlap if they are the identical. + // + // For example, if we are comparing these: + // BORROW: (*x1[2].y).z.a + // ACCESS: (*x1[i].y).w.b + // + // Then our steps are: + // x1 | x1 -- places are the same + // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ) + // x1[2].y | x1[i].y -- equal or disjoint + // *x1[2].y | *x1[i].y -- equal or disjoint + // (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more! + // + // Because `zip` does potentially bad things to the iterator inside, this loop + // also handles the case where the access might be a *prefix* of the borrow, e.g. + // + // BORROW: (*x1[2].y).z.a + // ACCESS: x1[i].y + // + // Then our steps are: + // x1 | x1 -- places are the same + // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ) + // x1[2].y | x1[i].y -- equal or disjoint + // + // -- here we run out of access - the borrow can access a part of it. If this + // is a full deep access, then we *know* the borrow conflicts with it. However, + // if the access is shallow, then we can proceed: + // + // x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we + // are disjoint + // + // Our invariant is, that at each step of the iteration: + // - If we didn't run out of access to match, our borrow and access are comparable + // and either equal or disjoint. + // - If we did run out of access, the borrow can access a part of it. + + let borrow_local = borrow_place.local; + let access_local = access_place.local; + + match place_base_conflict(borrow_local, access_local) { + Overlap::Arbitrary => { + bug!("Two base can't return Arbitrary"); + } + Overlap::EqualOrDisjoint => { + // This is the recursive case - proceed to the next element. + } + Overlap::Disjoint => { + // We have proven the borrow disjoint - further + // projections will remain disjoint. + debug!("borrow_conflicts_with_place: disjoint"); + return false; + } + } + + // loop invariant: borrow_c is always either equal to access_c or disjoint from it. + for (i, (borrow_c, &access_c)) in + iter::zip(borrow_place.projection, access_place.projection).enumerate() + { + debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); + let borrow_proj_base = &borrow_place.projection[..i]; + + debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); + + // Borrow and access path both have more components. + // + // Examples: + // + // - borrow of `a.(...)`, access to `a.(...)` + // - borrow of `a.(...)`, access to `b.(...)` + // + // Here we only see the components we have checked so + // far (in our examples, just the first component). We + // check whether the components being borrowed vs + // accessed are disjoint (as in the second example, + // but not the first). + match place_projection_conflict( + tcx, + body, + borrow_local, + borrow_proj_base, + borrow_c, + access_c, + bias, + ) { + Overlap::Arbitrary => { + // We have encountered different fields of potentially + // the same union - the borrow now partially overlaps. + // + // There is no *easy* way of comparing the fields + // further on, because they might have different types + // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and + // `.y` come from different structs). + // + // We could try to do some things here - e.g., count + // dereferences - but that's probably not a good + // idea, at least for now, so just give up and + // report a conflict. This is unsafe code anyway so + // the user could always use raw pointers. + debug!("borrow_conflicts_with_place: arbitrary -> conflict"); + return true; + } + Overlap::EqualOrDisjoint => { + // This is the recursive case - proceed to the next element. + } + Overlap::Disjoint => { + // We have proven the borrow disjoint - further + // projections will remain disjoint. + debug!("borrow_conflicts_with_place: disjoint"); + return false; + } + } + } + + if borrow_place.projection.len() > access_place.projection.len() { + for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate() + { + // Borrow path is longer than the access path. Examples: + // + // - borrow of `a.b.c`, access to `a.b` + // + // Here, we know that the borrow can access a part of + // our place. This is a conflict if that is a part our + // access cares about. + + let proj_base = &borrow_place.projection[..access_place.projection.len() + i]; + let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty; + + match (elem, &base_ty.kind(), access) { + (_, _, Shallow(Some(ArtificialField::ArrayLength))) + | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { + // The array length is like additional fields on the + // type; it does not overlap any existing data there. + // Furthermore, if cannot actually be a prefix of any + // borrowed place (at least in MIR as it is currently.) + // + // e.g., a (mutable) borrow of `a[5]` while we read the + // array length of `a`. + debug!("borrow_conflicts_with_place: implicit field"); + return false; + } + + (ProjectionElem::Deref, _, Shallow(None)) => { + // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some + // prefix thereof - the shallow access can't touch anything behind + // the pointer. + debug!("borrow_conflicts_with_place: shallow access behind ptr"); + return false; + } + (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Not), _) => { + // Shouldn't be tracked + bug!("Tracking borrow behind shared reference."); + } + (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Mut), AccessDepth::Drop) => { + // Values behind a mutable reference are not access either by dropping a + // value, or by StorageDead + debug!("borrow_conflicts_with_place: drop access behind ptr"); + return false; + } + + (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { + // Drop can read/write arbitrary projections, so places + // conflict regardless of further projections. + if def.has_dtor(tcx) { + return true; + } + } + + (ProjectionElem::Deref, _, Deep) + | (ProjectionElem::Deref, _, AccessDepth::Drop) + | (ProjectionElem::Field { .. }, _, _) + | (ProjectionElem::Index { .. }, _, _) + | (ProjectionElem::ConstantIndex { .. }, _, _) + | (ProjectionElem::Subslice { .. }, _, _) + | (ProjectionElem::Downcast { .. }, _, _) => { + // Recursive case. This can still be disjoint on a + // further iteration if this a shallow access and + // there's a deref later on, e.g., a borrow + // of `*x.y` while accessing `x`. + } + } + } + } + + // Borrow path ran out but access path may not + // have. Examples: + // + // - borrow of `a.b`, access to `a.b.c` + // - borrow of `a.b`, access to `a.b` + // + // In the first example, where we didn't run out of + // access, the borrow can access all of our place, so we + // have a conflict. + // + // If the second example, where we did, then we still know + // that the borrow can access a *part* of our place that + // our access cares about, so we still have a conflict. + if borrow_kind == BorrowKind::Shallow + && borrow_place.projection.len() < access_place.projection.len() + { + debug!("borrow_conflicts_with_place: shallow borrow"); + false + } else { + debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); + true + } +} + +// Given that the bases of `elem1` and `elem2` are always either equal +// or disjoint (and have the same type!), return the overlap situation +// between `elem1` and `elem2`. +fn place_base_conflict(l1: Local, l2: Local) -> Overlap { + if l1 == l2 { + // the same local - base case, equal + debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL"); + Overlap::EqualOrDisjoint + } else { + // different locals - base case, disjoint + debug!("place_element_conflict: DISJOINT-LOCAL"); + Overlap::Disjoint + } +} + +// Given that the bases of `elem1` and `elem2` are always either equal +// or disjoint (and have the same type!), return the overlap situation +// between `elem1` and `elem2`. +fn place_projection_conflict<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + pi1_local: Local, + pi1_proj_base: &[PlaceElem<'tcx>], + pi1_elem: PlaceElem<'tcx>, + pi2_elem: PlaceElem<'tcx>, + bias: PlaceConflictBias, +) -> Overlap { + match (pi1_elem, pi2_elem) { + (ProjectionElem::Deref, ProjectionElem::Deref) => { + // derefs (e.g., `*x` vs. `*x`) - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); + Overlap::EqualOrDisjoint + } + (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { + if f1 == f2 { + // same field (e.g., `a.y` vs. `a.y`) - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); + Overlap::EqualOrDisjoint + } else { + let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; + if ty.is_union() { + // Different fields of a union, we are basically stuck. + debug!("place_element_conflict: STUCK-UNION"); + Overlap::Arbitrary + } else { + // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! + debug!("place_element_conflict: DISJOINT-FIELD"); + Overlap::Disjoint + } + } + } + (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => { + // different variants are treated as having disjoint fields, + // even if they occupy the same "space", because it's + // impossible for 2 variants of the same enum to exist + // (and therefore, to be borrowed) at the same time. + // + // Note that this is different from unions - we *do* allow + // this code to compile: + // + // ``` + // fn foo(x: &mut Result) { + // let mut v = None; + // if let Ok(ref mut a) = *x { + // v = Some(a); + // } + // // here, you would *think* that the + // // *entirety* of `x` would be borrowed, + // // but in fact only the `Ok` variant is, + // // so the `Err` variant is *entirely free*: + // if let Err(ref mut a) = *x { + // v = Some(a); + // } + // drop(v); + // } + // ``` + if v1 == v2 { + debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-FIELD"); + Overlap::Disjoint + } + } + ( + ProjectionElem::Index(..), + ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. }, + ) + | ( + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }, + ProjectionElem::Index(..), + ) => { + // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint + // (if the indexes differ) or equal (if they are the same). + match bias { + PlaceConflictBias::Overlap => { + // If we are biased towards overlapping, then this is the recursive + // case that gives "equal *or* disjoint" its meaning. + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); + Overlap::EqualOrDisjoint + } + PlaceConflictBias::NoOverlap => { + // If we are biased towards no overlapping, then this is disjoint. + debug!("place_element_conflict: DISJOINT-ARRAY-INDEX"); + Overlap::Disjoint + } + } + } + ( + ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false }, + ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false }, + ) + | ( + ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true }, + ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: true }, + ) => { + if o1 == o2 { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); + Overlap::Disjoint + } + } + ( + ProjectionElem::ConstantIndex { + offset: offset_from_begin, + min_length: min_length1, + from_end: false, + }, + ProjectionElem::ConstantIndex { + offset: offset_from_end, + min_length: min_length2, + from_end: true, + }, + ) + | ( + ProjectionElem::ConstantIndex { + offset: offset_from_end, + min_length: min_length1, + from_end: true, + }, + ProjectionElem::ConstantIndex { + offset: offset_from_begin, + min_length: min_length2, + from_end: false, + }, + ) => { + // both patterns matched so it must be at least the greater of the two + let min_length = max(min_length1, min_length2); + // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last + // element (like -1 in Python) and `min_length` the first. + // Therefore, `min_length - offset_from_end` gives the minimal possible + // offset from the beginning + if offset_from_begin >= min_length - offset_from_end { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); + Overlap::Disjoint + } + } + ( + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, + ProjectionElem::Subslice { from, to, from_end: false }, + ) + | ( + ProjectionElem::Subslice { from, to, from_end: false }, + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, + ) => { + if (from..to).contains(&offset) { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::Disjoint + } + } + ( + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, + ProjectionElem::Subslice { from, .. }, + ) + | ( + ProjectionElem::Subslice { from, .. }, + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, + ) => { + if offset >= from { + debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE"); + Overlap::Disjoint + } + } + ( + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, + ProjectionElem::Subslice { to, from_end: true, .. }, + ) + | ( + ProjectionElem::Subslice { to, from_end: true, .. }, + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, + ) => { + if offset > to { + debug!( + "place_element_conflict: \ + DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE" + ); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE"); + Overlap::Disjoint + } + } + ( + ProjectionElem::Subslice { from: f1, to: t1, from_end: false }, + ProjectionElem::Subslice { from: f2, to: t2, from_end: false }, + ) => { + if f2 >= t1 || f1 >= t2 { + debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES"); + Overlap::Disjoint + } else { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); + Overlap::EqualOrDisjoint + } + } + (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { + debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES"); + Overlap::EqualOrDisjoint + } + ( + ProjectionElem::Deref + | ProjectionElem::Field(..) + | ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(..), + _, + ) => bug!( + "mismatched projections in place_element_conflict: {:?} and {:?}", + pi1_elem, + pi2_elem + ), + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/prefixes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/prefixes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/prefixes.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/prefixes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,145 @@ +//! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an +//! place are formed by stripping away fields and derefs, except that +//! we stop when we reach the deref of a shared reference. [...] " +//! +//! "Shallow prefixes are found by stripping away fields, but stop at +//! any dereference. So: writing a path like `a` is illegal if `a.b` +//! is borrowed. But: writing `a` is legal if `*a` is borrowed, +//! whether or not `a` is a shared or mutable reference. [...] " + +use super::MirBorrowckCtxt; + +use rustc_hir as hir; +use rustc_middle::mir::{Body, PlaceRef, ProjectionElem}; +use rustc_middle::ty::{self, TyCtxt}; + +pub trait IsPrefixOf<'tcx> { + fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool; +} + +impl<'tcx> IsPrefixOf<'tcx> for PlaceRef<'tcx> { + fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool { + self.local == other.local + && self.projection.len() <= other.projection.len() + && self.projection == &other.projection[..self.projection.len()] + } +} + +pub(super) struct Prefixes<'cx, 'tcx> { + body: &'cx Body<'tcx>, + tcx: TyCtxt<'tcx>, + kind: PrefixSet, + next: Option>, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(super) enum PrefixSet { + /// Doesn't stop until it returns the base case (a Local or + /// Static prefix). + All, + /// Stops at any dereference. + Shallow, + /// Stops at the deref of a shared reference. + Supporting, +} + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + /// Returns an iterator over the prefixes of `place` + /// (inclusive) from longest to smallest, potentially + /// terminating the iteration early based on `kind`. + pub(super) fn prefixes( + &self, + place_ref: PlaceRef<'tcx>, + kind: PrefixSet, + ) -> Prefixes<'cx, 'tcx> { + Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx } + } +} + +impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { + type Item = PlaceRef<'tcx>; + fn next(&mut self) -> Option { + let mut cursor = self.next?; + + // Post-processing `place`: Enqueue any remaining + // work. Also, `place` may not be a prefix itself, but + // may hold one further down (e.g., we never return + // downcasts here, but may return a base of a downcast). + + 'cursor: loop { + match cursor.last_projection() { + None => { + self.next = None; + return Some(cursor); + } + Some((cursor_base, elem)) => { + match elem { + ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { + // FIXME: add union handling + self.next = Some(cursor_base); + return Some(cursor); + } + ProjectionElem::Downcast(..) + | ProjectionElem::Subslice { .. } + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Index(_) => { + cursor = cursor_base; + continue 'cursor; + } + ProjectionElem::Deref => { + // (handled below) + } + } + + assert_eq!(elem, ProjectionElem::Deref); + + match self.kind { + PrefixSet::Shallow => { + // Shallow prefixes are found by stripping away + // fields, but stop at *any* dereference. + // So we can just stop the traversal now. + self.next = None; + return Some(cursor); + } + PrefixSet::All => { + // All prefixes: just blindly enqueue the base + // of the projection. + self.next = Some(cursor_base); + return Some(cursor); + } + PrefixSet::Supporting => { + // Fall through! + } + } + + assert_eq!(self.kind, PrefixSet::Supporting); + // Supporting prefixes: strip away fields and + // derefs, except we stop at the deref of a shared + // reference. + + let ty = cursor_base.ty(self.body, self.tcx).ty; + match ty.kind() { + ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => { + // don't continue traversing over derefs of raw pointers or shared + // borrows. + self.next = None; + return Some(cursor); + } + + ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => { + self.next = Some(cursor_base); + return Some(cursor); + } + + ty::Adt(..) if ty.is_box() => { + self.next = Some(cursor_base); + return Some(cursor); + } + + _ => panic!("unknown type fed to Projection Deref."), + } + } + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/dump_mir.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/dump_mir.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/dump_mir.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/dump_mir.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,89 @@ +//! As part of generating the regions, if you enable `-Zdump-mir=nll`, +//! we will generate an annotated copy of the MIR that includes the +//! state of region inference. This code handles emitting the region +//! context internal state. + +use super::{OutlivesConstraint, RegionInferenceContext}; +use crate::type_check::Locations; +use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_middle::ty::TyCtxt; +use std::io::{self, Write}; + +// Room for "'_#NNNNr" before things get misaligned. +// Easy enough to fix if this ever doesn't seem like +// enough. +const REGION_WIDTH: usize = 8; + +impl<'tcx> RegionInferenceContext<'tcx> { + /// Write out our state into the `.mir` files. + pub(crate) fn dump_mir(&self, tcx: TyCtxt<'tcx>, out: &mut dyn Write) -> io::Result<()> { + writeln!(out, "| Free Region Mapping")?; + + for region in self.regions() { + if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin { + let classification = self.universal_regions.region_classification(region).unwrap(); + let outlived_by = self.universal_region_relations.regions_outlived_by(region); + writeln!( + out, + "| {r:rw$?} | {c:cw$?} | {ob:?}", + r = region, + rw = REGION_WIDTH, + c = classification, + cw = 8, // "External" at most + ob = outlived_by + )?; + } + } + + writeln!(out, "|")?; + writeln!(out, "| Inferred Region Values")?; + for region in self.regions() { + writeln!( + out, + "| {r:rw$?} | {ui:4?} | {v}", + r = region, + rw = REGION_WIDTH, + ui = self.region_universe(region), + v = self.region_value_str(region), + )?; + } + + writeln!(out, "|")?; + writeln!(out, "| Inference Constraints")?; + self.for_each_constraint(tcx, &mut |msg| writeln!(out, "| {}", msg))?; + + Ok(()) + } + + /// Debugging aid: Invokes the `with_msg` callback repeatedly with + /// our internal region constraints. These are dumped into the + /// -Zdump-mir file so that we can figure out why the region + /// inference resulted in the values that it did when debugging. + fn for_each_constraint( + &self, + tcx: TyCtxt<'tcx>, + with_msg: &mut dyn FnMut(&str) -> io::Result<()>, + ) -> io::Result<()> { + for region in self.definitions.indices() { + let value = self.liveness_constraints.region_value_str(region); + if value != "{}" { + with_msg(&format!("{:?} live at {}", region, value))?; + } + } + + let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); + constraints.sort(); + for constraint in &constraints { + let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint; + let (name, arg) = match locations { + Locations::All(span) => { + ("All", tcx.sess.source_map().span_to_embeddable_string(*span)) + } + Locations::Single(loc) => ("Single", format!("{:?}", loc)), + }; + with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?; + } + + Ok(()) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/graphviz.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/graphviz.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/graphviz.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/graphviz.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,140 @@ +//! This module provides linkage between RegionInferenceContext and +//! `rustc_graphviz` traits, specialized to attaching borrowck analysis +//! data to rendered labels. + +use std::borrow::Cow; +use std::io::{self, Write}; + +use super::*; +use crate::constraints::OutlivesConstraint; +use rustc_graphviz as dot; + +impl<'tcx> RegionInferenceContext<'tcx> { + /// Write out the region constraint graph. + crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + dot::render(&RawConstraints { regioncx: self }, &mut w) + } + + /// Write out the region constraint graph. + crate fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + let mut nodes_per_scc: IndexVec = + self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect(); + + for region in self.definitions.indices() { + let scc = self.constraint_sccs.scc(region); + nodes_per_scc[scc].push(region); + } + + dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w) + } +} + +struct RawConstraints<'a, 'tcx> { + regioncx: &'a RegionInferenceContext<'tcx>, +} + +impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { + type Node = RegionVid; + type Edge = OutlivesConstraint<'tcx>; + + fn graph_id(&'this self) -> dot::Id<'this> { + dot::Id::new("RegionInferenceContext").unwrap() + } + fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> { + dot::Id::new(format!("r{}", n.index())).unwrap() + } + fn node_shape(&'this self, _node: &RegionVid) -> Option> { + Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) + } + fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { + dot::LabelText::LabelStr(format!("{:?}", n).into()) + } + fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> { + dot::LabelText::LabelStr(format!("{:?}", e.locations).into()) + } +} + +impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { + type Node = RegionVid; + type Edge = OutlivesConstraint<'tcx>; + + fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> { + let vids: Vec = self.regioncx.definitions.indices().collect(); + vids.into() + } + fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> { + (&self.regioncx.constraints.outlives().raw[..]).into() + } + + // Render `a: b` as `a -> b`, indicating the flow + // of data during inference. + + fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { + edge.sup + } + + fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { + edge.sub + } +} + +struct SccConstraints<'a, 'tcx> { + regioncx: &'a RegionInferenceContext<'tcx>, + nodes_per_scc: IndexVec>, +} + +impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { + type Node = ConstraintSccIndex; + type Edge = (ConstraintSccIndex, ConstraintSccIndex); + + fn graph_id(&'this self) -> dot::Id<'this> { + dot::Id::new("RegionInferenceContext".to_string()).unwrap() + } + fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> { + dot::Id::new(format!("r{}", n.index())).unwrap() + } + fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option> { + Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) + } + fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { + let nodes = &self.nodes_per_scc[*n]; + dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into()) + } +} + +impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> { + type Node = ConstraintSccIndex; + type Edge = (ConstraintSccIndex, ConstraintSccIndex); + + fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> { + let vids: Vec = self.regioncx.constraint_sccs.all_sccs().collect(); + vids.into() + } + fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> { + let edges: Vec<_> = self + .regioncx + .constraint_sccs + .all_sccs() + .flat_map(|scc_a| { + self.regioncx + .constraint_sccs + .successors(scc_a) + .iter() + .map(move |&scc_b| (scc_a, scc_b)) + }) + .collect(); + + edges.into() + } + + // Render `a: b` as `a -> b`, indicating the flow + // of data during inference. + + fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { + edge.0 + } + + fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { + edge.1 + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,2265 @@ +use std::collections::VecDeque; +use std::rc::Rc; + +use rustc_data_structures::binary_search_util; +use rustc_data_structures::frozen::Frozen; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::graph::scc::Sccs; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_hir::CRATE_HIR_ID; +use rustc_index::vec::IndexVec; +use rustc_infer::infer::canonical::QueryOutlivesConstraint; +use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; +use rustc_middle::mir::{ + Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, + ConstraintCategory, Local, Location, ReturnConstraint, +}; +use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::ObligationCauseCode; +use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; +use rustc_span::Span; + +use crate::{ + constraints::{ + graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet, + }, + diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}, + member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, + nll::{PoloniusOutput, ToRegionVid}, + region_infer::reverse_sccs::ReverseSccGraph, + region_infer::values::{ + LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, + ToElementIndex, + }, + type_check::{free_region_relations::UniversalRegionRelations, Locations}, + universal_regions::UniversalRegions, +}; + +mod dump_mir; +mod graphviz; +mod opaque_types; +mod reverse_sccs; + +pub mod values; + +pub struct RegionInferenceContext<'tcx> { + /// Contains the definition for every region variable. Region + /// variables are identified by their index (`RegionVid`). The + /// definition contains information about where the region came + /// from as well as its final inferred value. + definitions: IndexVec>, + + /// The liveness constraints added to each region. For most + /// regions, these start out empty and steadily grow, though for + /// each universally quantified region R they start out containing + /// the entire CFG and `end(R)`. + liveness_constraints: LivenessValues, + + /// The outlives constraints computed by the type-check. + constraints: Frozen>, + + /// The constraint-set, but in graph form, making it easy to traverse + /// the constraints adjacent to a particular region. Used to construct + /// the SCC (see `constraint_sccs`) and for error reporting. + constraint_graph: Frozen, + + /// The SCC computed from `constraints` and the constraint + /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to + /// compute the values of each region. + constraint_sccs: Rc>, + + /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if + /// `B: A`. This is used to compute the universal regions that are required + /// to outlive a given SCC. Computed lazily. + rev_scc_graph: Option>, + + /// The "R0 member of [R1..Rn]" constraints, indexed by SCC. + member_constraints: Rc>, + + /// Records the member constraints that we applied to each scc. + /// This is useful for error reporting. Once constraint + /// propagation is done, this vector is sorted according to + /// `member_region_scc`. + member_constraints_applied: Vec, + + /// Map closure bounds to a `Span` that should be used for error reporting. + closure_bounds_mapping: + FxHashMap>, + + /// Map universe indexes to information on why we created it. + universe_causes: FxHashMap>, + + /// Contains the minimum universe of any variable within the same + /// SCC. We will ensure that no SCC contains values that are not + /// visible from this index. + scc_universes: IndexVec, + + /// Contains a "representative" from each SCC. This will be the + /// minimal RegionVid belonging to that universe. It is used as a + /// kind of hacky way to manage checking outlives relationships, + /// since we can 'canonicalize' each region to the representative + /// of its SCC and be sure that -- if they have the same repr -- + /// they *must* be equal (though not having the same repr does not + /// mean they are unequal). + scc_representatives: IndexVec, + + /// The final inferred values of the region variables; we compute + /// one value per SCC. To get the value for any given *region*, + /// you first find which scc it is a part of. + scc_values: RegionValues, + + /// Type constraints that we check after solving. + type_tests: Vec>, + + /// Information about the universally quantified regions in scope + /// on this function. + universal_regions: Rc>, + + /// Information about how the universally quantified regions in + /// scope on this function relate to one another. + universal_region_relations: Frozen>, +} + +/// Each time that `apply_member_constraint` is successful, it appends +/// one of these structs to the `member_constraints_applied` field. +/// This is used in error reporting to trace out what happened. +/// +/// The way that `apply_member_constraint` works is that it effectively +/// adds a new lower bound to the SCC it is analyzing: so you wind up +/// with `'R: 'O` where `'R` is the pick-region and `'O` is the +/// minimal viable option. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +pub(crate) struct AppliedMemberConstraint { + /// The SCC that was affected. (The "member region".) + /// + /// The vector if `AppliedMemberConstraint` elements is kept sorted + /// by this field. + pub(crate) member_region_scc: ConstraintSccIndex, + + /// The "best option" that `apply_member_constraint` found -- this was + /// added as an "ad-hoc" lower-bound to `member_region_scc`. + pub(crate) min_choice: ty::RegionVid, + + /// The "member constraint index" -- we can find out details about + /// the constraint from + /// `set.member_constraints[member_constraint_index]`. + pub(crate) member_constraint_index: NllMemberConstraintIndex, +} + +pub(crate) struct RegionDefinition<'tcx> { + /// What kind of variable is this -- a free region? existential + /// variable? etc. (See the `NllRegionVariableOrigin` for more + /// info.) + pub(crate) origin: NllRegionVariableOrigin, + + /// Which universe is this region variable defined in? This is + /// most often `ty::UniverseIndex::ROOT`, but when we encounter + /// forall-quantifiers like `for<'a> { 'a = 'b }`, we would create + /// the variable for `'a` in a fresh universe that extends ROOT. + pub(crate) universe: ty::UniverseIndex, + + /// If this is 'static or an early-bound region, then this is + /// `Some(X)` where `X` is the name of the region. + pub(crate) external_name: Option>, +} + +/// N.B., the variants in `Cause` are intentionally ordered. Lower +/// values are preferred when it comes to error messages. Do not +/// reorder willy nilly. +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +pub(crate) enum Cause { + /// point inserted because Local was live at the given Location + LiveVar(Local, Location), + + /// point inserted because Local was dropped at the given Location + DropVar(Local, Location), +} + +/// A "type test" corresponds to an outlives constraint between a type +/// and a lifetime, like `T: 'x` or `::Bar: 'x`. They are +/// translated from the `Verify` region constraints in the ordinary +/// inference context. +/// +/// These sorts of constraints are handled differently than ordinary +/// constraints, at least at present. During type checking, the +/// `InferCtxt::process_registered_region_obligations` method will +/// attempt to convert a type test like `T: 'x` into an ordinary +/// outlives constraint when possible (for example, `&'a T: 'b` will +/// be converted into `'a: 'b` and registered as a `Constraint`). +/// +/// In some cases, however, there are outlives relationships that are +/// not converted into a region constraint, but rather into one of +/// these "type tests". The distinction is that a type test does not +/// influence the inference result, but instead just examines the +/// values that we ultimately inferred for each region variable and +/// checks that they meet certain extra criteria. If not, an error +/// can be issued. +/// +/// One reason for this is that these type tests typically boil down +/// to a check like `'a: 'x` where `'a` is a universally quantified +/// region -- and therefore not one whose value is really meant to be +/// *inferred*, precisely (this is not always the case: one can have a +/// type test like `>::Bar: 'x`, where `'?0` is an +/// inference variable). Another reason is that these type tests can +/// involve *disjunction* -- that is, they can be satisfied in more +/// than one way. +/// +/// For more information about this translation, see +/// `InferCtxt::process_registered_region_obligations` and +/// `InferCtxt::type_must_outlive` in `rustc_infer::infer::InferCtxt`. +#[derive(Clone, Debug)] +pub struct TypeTest<'tcx> { + /// The type `T` that must outlive the region. + pub generic_kind: GenericKind<'tcx>, + + /// The region `'x` that the type must outlive. + pub lower_bound: RegionVid, + + /// Where did this constraint arise and why? + pub locations: Locations, + + /// A test which, if met by the region `'x`, proves that this type + /// constraint is satisfied. + pub verify_bound: VerifyBound<'tcx>, +} + +/// When we have an unmet lifetime constraint, we try to propagate it outward (e.g. to a closure +/// environment). If we can't, it is an error. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum RegionRelationCheckResult { + Ok, + Propagated, + Error, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +enum Trace<'tcx> { + StartRegion, + FromOutlivesConstraint(OutlivesConstraint<'tcx>), + NotVisited, +} + +impl<'tcx> RegionInferenceContext<'tcx> { + /// Creates a new region inference context with a total of + /// `num_region_variables` valid inference variables; the first N + /// of those will be constant regions representing the free + /// regions defined in `universal_regions`. + /// + /// The `outlives_constraints` and `type_tests` are an initial set + /// of constraints produced by the MIR type check. + pub(crate) fn new( + var_infos: VarInfos, + universal_regions: Rc>, + placeholder_indices: Rc, + universal_region_relations: Frozen>, + outlives_constraints: OutlivesConstraintSet<'tcx>, + member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, + closure_bounds_mapping: FxHashMap< + Location, + FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, + >, + universe_causes: FxHashMap>, + type_tests: Vec>, + liveness_constraints: LivenessValues, + elements: &Rc, + ) -> Self { + // Create a RegionDefinition for each inference variable. + let definitions: IndexVec<_, _> = var_infos + .into_iter() + .map(|info| RegionDefinition::new(info.universe, info.origin)) + .collect(); + + let constraints = Frozen::freeze(outlives_constraints); + let constraint_graph = Frozen::freeze(constraints.graph(definitions.len())); + let fr_static = universal_regions.fr_static; + let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static)); + + let mut scc_values = + RegionValues::new(elements, universal_regions.len(), &placeholder_indices); + + for region in liveness_constraints.rows() { + let scc = constraint_sccs.scc(region); + scc_values.merge_liveness(scc, region, &liveness_constraints); + } + + let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions); + + let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions); + + let member_constraints = + Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); + + let mut result = Self { + definitions, + liveness_constraints, + constraints, + constraint_graph, + constraint_sccs, + rev_scc_graph: None, + member_constraints, + member_constraints_applied: Vec::new(), + closure_bounds_mapping, + universe_causes, + scc_universes, + scc_representatives, + scc_values, + type_tests, + universal_regions, + universal_region_relations, + }; + + result.init_free_and_bound_regions(); + + result + } + + /// Each SCC is the combination of many region variables which + /// have been equated. Therefore, we can associate a universe with + /// each SCC which is minimum of all the universes of its + /// constituent regions -- this is because whatever value the SCC + /// takes on must be a value that each of the regions within the + /// SCC could have as well. This implies that the SCC must have + /// the minimum, or narrowest, universe. + fn compute_scc_universes( + constraint_sccs: &Sccs, + definitions: &IndexVec>, + ) -> IndexVec { + let num_sccs = constraint_sccs.num_sccs(); + let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs); + + debug!("compute_scc_universes()"); + + // For each region R in universe U, ensure that the universe for the SCC + // that contains R is "no bigger" than U. This effectively sets the universe + // for each SCC to be the minimum of the regions within. + for (region_vid, region_definition) in definitions.iter_enumerated() { + let scc = constraint_sccs.scc(region_vid); + let scc_universe = &mut scc_universes[scc]; + let scc_min = std::cmp::min(region_definition.universe, *scc_universe); + if scc_min != *scc_universe { + *scc_universe = scc_min; + debug!( + "compute_scc_universes: lowered universe of {scc:?} to {scc_min:?} \ + because it contains {region_vid:?} in {region_universe:?}", + scc = scc, + scc_min = scc_min, + region_vid = region_vid, + region_universe = region_definition.universe, + ); + } + } + + // Walk each SCC `A` and `B` such that `A: B` + // and ensure that universe(A) can see universe(B). + // + // This serves to enforce the 'empty/placeholder' hierarchy + // (described in more detail on `RegionKind`): + // + // ``` + // static -----+ + // | | + // empty(U0) placeholder(U1) + // | / + // empty(U1) + // ``` + // + // In particular, imagine we have variables R0 in U0 and R1 + // created in U1, and constraints like this; + // + // ``` + // R1: !1 // R1 outlives the placeholder in U1 + // R1: R0 // R1 outlives R0 + // ``` + // + // Here, we wish for R1 to be `'static`, because it + // cannot outlive `placeholder(U1)` and `empty(U0)` any other way. + // + // Thanks to this loop, what happens is that the `R1: R0` + // constraint lowers the universe of `R1` to `U0`, which in turn + // means that the `R1: !1` constraint will (later) cause + // `R1` to become `'static`. + for scc_a in constraint_sccs.all_sccs() { + for &scc_b in constraint_sccs.successors(scc_a) { + let scc_universe_a = scc_universes[scc_a]; + let scc_universe_b = scc_universes[scc_b]; + let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b); + if scc_universe_a != scc_universe_min { + scc_universes[scc_a] = scc_universe_min; + + debug!( + "compute_scc_universes: lowered universe of {scc_a:?} to {scc_universe_min:?} \ + because {scc_a:?}: {scc_b:?} and {scc_b:?} is in universe {scc_universe_b:?}", + scc_a = scc_a, + scc_b = scc_b, + scc_universe_min = scc_universe_min, + scc_universe_b = scc_universe_b + ); + } + } + } + + debug!("compute_scc_universes: scc_universe = {:#?}", scc_universes); + + scc_universes + } + + /// For each SCC, we compute a unique `RegionVid` (in fact, the + /// minimal one that belongs to the SCC). See + /// `scc_representatives` field of `RegionInferenceContext` for + /// more details. + fn compute_scc_representatives( + constraints_scc: &Sccs, + definitions: &IndexVec>, + ) -> IndexVec { + let num_sccs = constraints_scc.num_sccs(); + let next_region_vid = definitions.next_index(); + let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs); + + for region_vid in definitions.indices() { + let scc = constraints_scc.scc(region_vid); + let prev_min = scc_representatives[scc]; + scc_representatives[scc] = region_vid.min(prev_min); + } + + scc_representatives + } + + /// Initializes the region variables for each universally + /// quantified region (lifetime parameter). The first N variables + /// always correspond to the regions appearing in the function + /// signature (both named and anonymous) and where-clauses. This + /// function iterates over those regions and initializes them with + /// minimum values. + /// + /// For example: + /// + /// fn foo<'a, 'b>(..) where 'a: 'b + /// + /// would initialize two variables like so: + /// + /// R0 = { CFG, R0 } // 'a + /// R1 = { CFG, R0, R1 } // 'b + /// + /// Here, R0 represents `'a`, and it contains (a) the entire CFG + /// and (b) any universally quantified regions that it outlives, + /// which in this case is just itself. R1 (`'b`) in contrast also + /// outlives `'a` and hence contains R0 and R1. + fn init_free_and_bound_regions(&mut self) { + // Update the names (if any) + for (external_name, variable) in self.universal_regions.named_universal_regions() { + debug!( + "init_universal_regions: region {:?} has external name {:?}", + variable, external_name + ); + self.definitions[variable].external_name = Some(external_name); + } + + for variable in self.definitions.indices() { + let scc = self.constraint_sccs.scc(variable); + + match self.definitions[variable].origin { + NllRegionVariableOrigin::FreeRegion => { + // For each free, universally quantified region X: + + // Add all nodes in the CFG to liveness constraints + self.liveness_constraints.add_all_points(variable); + self.scc_values.add_all_points(scc); + + // Add `end(X)` into the set for X. + self.scc_values.add_element(scc, variable); + } + + NllRegionVariableOrigin::Placeholder(placeholder) => { + // Each placeholder region is only visible from + // its universe `ui` and its extensions. So we + // can't just add it into `scc` unless the + // universe of the scc can name this region. + let scc_universe = self.scc_universes[scc]; + if scc_universe.can_name(placeholder.universe) { + self.scc_values.add_element(scc, placeholder); + } else { + debug!( + "init_free_and_bound_regions: placeholder {:?} is \ + not compatible with universe {:?} of its SCC {:?}", + placeholder, scc_universe, scc, + ); + self.add_incompatible_universe(scc); + } + } + + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::Existential { .. } => { + // For existential, regions, nothing to do. + } + } + } + } + + /// Returns an iterator over all the region indices. + pub fn regions(&self) -> impl Iterator + '_ { + self.definitions.indices() + } + + /// Given a universal region in scope on the MIR, returns the + /// corresponding index. + /// + /// (Panics if `r` is not a registered universal region.) + pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { + self.universal_regions.to_region_vid(r) + } + + /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. + crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut rustc_errors::DiagnosticBuilder<'_>) { + self.universal_regions.annotate(tcx, err) + } + + /// Returns `true` if the region `r` contains the point `p`. + /// + /// Panics if called before `solve()` executes, + crate fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + self.scc_values.contains(scc, p) + } + + /// Returns access to the value of `r` for debugging purposes. + crate fn region_value_str(&self, r: RegionVid) -> String { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + self.scc_values.region_value_str(scc) + } + + /// Returns access to the value of `r` for debugging purposes. + crate fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + self.scc_universes[scc] + } + + /// Once region solving has completed, this function will return + /// the member constraints that were applied to the value of a given + /// region `r`. See `AppliedMemberConstraint`. + pub(crate) fn applied_member_constraints( + &self, + r: impl ToRegionVid, + ) -> &[AppliedMemberConstraint] { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + binary_search_util::binary_search_slice( + &self.member_constraints_applied, + |applied| applied.member_region_scc, + &scc, + ) + } + + /// Performs region inference and report errors if we see any + /// unsatisfiable constraints. If this is a closure, returns the + /// region requirements to propagate to our creator, if any. + #[instrument(skip(self, infcx, body, polonius_output), level = "debug")] + pub(super) fn solve( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + polonius_output: Option>, + ) -> (Option>, RegionErrors<'tcx>) { + let mir_def_id = body.source.def_id(); + self.propagate_constraints(body); + + let mut errors_buffer = RegionErrors::new(); + + // If this is a closure, we can propagate unsatisfied + // `outlives_requirements` to our creator, so create a vector + // to store those. Otherwise, we'll pass in `None` to the + // functions below, which will trigger them to report errors + // eagerly. + let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new); + + self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer); + + // In Polonius mode, the errors about missing universal region relations are in the output + // and need to be emitted or propagated. Otherwise, we need to check whether the + // constraints were too strong, and if so, emit or propagate those errors. + if infcx.tcx.sess.opts.debugging_opts.polonius { + self.check_polonius_subset_errors( + body, + outlives_requirements.as_mut(), + &mut errors_buffer, + polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), + ); + } else { + self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer); + } + + if errors_buffer.is_empty() { + self.check_member_constraints(infcx, &mut errors_buffer); + } + + let outlives_requirements = outlives_requirements.unwrap_or_default(); + + if outlives_requirements.is_empty() { + (None, errors_buffer) + } else { + let num_external_vids = self.universal_regions.num_global_and_external_regions(); + ( + Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }), + errors_buffer, + ) + } + } + + /// Propagate the region constraints: this will grow the values + /// for each region variable until all the constraints are + /// satisfied. Note that some values may grow **too** large to be + /// feasible, but we check this later. + #[instrument(skip(self, _body), level = "debug")] + fn propagate_constraints(&mut self, _body: &Body<'tcx>) { + debug!("constraints={:#?}", { + let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); + constraints.sort(); + constraints + .into_iter() + .map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub))) + .collect::>() + }); + + // To propagate constraints, we walk the DAG induced by the + // SCC. For each SCC, we visit its successors and compute + // their values, then we union all those values to get our + // own. + let constraint_sccs = self.constraint_sccs.clone(); + for scc in constraint_sccs.all_sccs() { + self.compute_value_for_scc(scc); + } + + // Sort the applied member constraints so we can binary search + // through them later. + self.member_constraints_applied.sort_by_key(|applied| applied.member_region_scc); + } + + /// Computes the value of the SCC `scc_a`, which has not yet been + /// computed, by unioning the values of its successors. + /// Assumes that all successors have been computed already + /// (which is assured by iterating over SCCs in dependency order). + #[instrument(skip(self), level = "debug")] + fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { + let constraint_sccs = self.constraint_sccs.clone(); + + // Walk each SCC `B` such that `A: B`... + for &scc_b in constraint_sccs.successors(scc_a) { + debug!(?scc_b); + + // ...and add elements from `B` into `A`. One complication + // arises because of universes: If `B` contains something + // that `A` cannot name, then `A` can only contain `B` if + // it outlives static. + if self.universe_compatible(scc_b, scc_a) { + // `A` can name everything that is in `B`, so just + // merge the bits. + self.scc_values.add_region(scc_a, scc_b); + } else { + self.add_incompatible_universe(scc_a); + } + } + + // Now take member constraints into account. + let member_constraints = self.member_constraints.clone(); + for m_c_i in member_constraints.indices(scc_a) { + self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); + } + + debug!(value = ?self.scc_values.region_value_str(scc_a)); + } + + /// Invoked for each `R0 member of [R1..Rn]` constraint. + /// + /// `scc` is the SCC containing R0, and `choice_regions` are the + /// `R1..Rn` regions -- they are always known to be universal + /// regions (and if that's not true, we just don't attempt to + /// enforce the constraint). + /// + /// The current value of `scc` at the time the method is invoked + /// is considered a *lower bound*. If possible, we will modify + /// the constraint to set it equal to one of the option regions. + /// If we make any changes, returns true, else false. + #[instrument(skip(self, member_constraint_index), level = "debug")] + fn apply_member_constraint( + &mut self, + scc: ConstraintSccIndex, + member_constraint_index: NllMemberConstraintIndex, + choice_regions: &[ty::RegionVid], + ) -> bool { + // Create a mutable vector of the options. We'll try to winnow + // them down. + let mut choice_regions: Vec = choice_regions.to_vec(); + + // The 'member region' in a member constraint is part of the + // hidden type, which must be in the root universe. Therefore, + // it cannot have any placeholders in its value. + assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT); + debug_assert!( + self.scc_values.placeholders_contained_in(scc).next().is_none(), + "scc {:?} in a member constraint has placeholder value: {:?}", + scc, + self.scc_values.region_value_str(scc), + ); + + // The existing value for `scc` is a lower-bound. This will + // consist of some set `{P} + {LB}` of points `{P}` and + // lower-bound free regions `{LB}`. As each choice region `O` + // is a free region, it will outlive the points. But we can + // only consider the option `O` if `O: LB`. + choice_regions.retain(|&o_r| { + self.scc_values + .universal_regions_outlived_by(scc) + .all(|lb| self.universal_region_relations.outlives(o_r, lb)) + }); + debug!(?choice_regions, "after lb"); + + // Now find all the *upper bounds* -- that is, each UB is a + // free region that must outlive the member region `R0` (`UB: + // R0`). Therefore, we need only keep an option `O` if `UB: O` + // for all UB. + let rev_scc_graph = self.reverse_scc_graph(); + let universal_region_relations = &self.universal_region_relations; + for ub in rev_scc_graph.upper_bounds(scc) { + debug!(?ub); + choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); + } + debug!(?choice_regions, "after ub"); + + // If we ruled everything out, we're done. + if choice_regions.is_empty() { + return false; + } + + // Otherwise, we need to find the minimum remaining choice, if + // any, and take that. + debug!("choice_regions remaining are {:#?}", choice_regions); + let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option { + let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); + let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); + match (r1_outlives_r2, r2_outlives_r1) { + (true, true) => Some(r1.min(r2)), + (true, false) => Some(r2), + (false, true) => Some(r1), + (false, false) => None, + } + }; + let mut min_choice = choice_regions[0]; + for &other_option in &choice_regions[1..] { + debug!(?min_choice, ?other_option,); + match min(min_choice, other_option) { + Some(m) => min_choice = m, + None => { + debug!(?min_choice, ?other_option, "incomparable; no min choice",); + return false; + } + } + } + + let min_choice_scc = self.constraint_sccs.scc(min_choice); + debug!(?min_choice, ?min_choice_scc); + if self.scc_values.add_region(scc, min_choice_scc) { + self.member_constraints_applied.push(AppliedMemberConstraint { + member_region_scc: scc, + min_choice, + member_constraint_index, + }); + + true + } else { + false + } + } + + /// Returns `true` if all the elements in the value of `scc_b` are nameable + /// in `scc_a`. Used during constraint propagation, and only once + /// the value of `scc_b` has been computed. + fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { + let universe_a = self.scc_universes[scc_a]; + + // Quick check: if scc_b's declared universe is a subset of + // scc_a's declared univese (typically, both are ROOT), then + // it cannot contain any problematic universe elements. + if universe_a.can_name(self.scc_universes[scc_b]) { + return true; + } + + // Otherwise, we have to iterate over the universe elements in + // B's value, and check whether all of them are nameable + // from universe_a + self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe)) + } + + /// Extend `scc` so that it can outlive some placeholder region + /// from a universe it can't name; at present, the only way for + /// this to be true is if `scc` outlives `'static`. This is + /// actually stricter than necessary: ideally, we'd support bounds + /// like `for<'a: 'b`>` that might then allow us to approximate + /// `'a` with `'b` and not `'static`. But it will have to do for + /// now. + fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) { + debug!("add_incompatible_universe(scc={:?})", scc); + + let fr_static = self.universal_regions.fr_static; + self.scc_values.add_all_points(scc); + self.scc_values.add_element(scc, fr_static); + } + + /// Once regions have been propagated, this method is used to see + /// whether the "type tests" produced by typeck were satisfied; + /// type tests encode type-outlives relationships like `T: + /// 'a`. See `TypeTest` for more details. + fn check_type_tests( + &self, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + mut propagated_outlives_requirements: Option<&mut Vec>>, + errors_buffer: &mut RegionErrors<'tcx>, + ) { + let tcx = infcx.tcx; + + // Sometimes we register equivalent type-tests that would + // result in basically the exact same error being reported to + // the user. Avoid that. + let mut deduplicate_errors = FxHashSet::default(); + + for type_test in &self.type_tests { + debug!("check_type_test: {:?}", type_test); + + let generic_ty = type_test.generic_kind.to_ty(tcx); + if self.eval_verify_bound( + tcx, + body, + generic_ty, + type_test.lower_bound, + &type_test.verify_bound, + ) { + continue; + } + + if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { + if self.try_promote_type_test( + infcx, + body, + type_test, + propagated_outlives_requirements, + ) { + continue; + } + } + + // Type-test failed. Report the error. + let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind); + + // Skip duplicate-ish errors. + if deduplicate_errors.insert(( + erased_generic_kind, + type_test.lower_bound, + type_test.locations, + )) { + debug!( + "check_type_test: reporting error for erased_generic_kind={:?}, \ + lower_bound_region={:?}, \ + type_test.locations={:?}", + erased_generic_kind, type_test.lower_bound, type_test.locations, + ); + + errors_buffer.push(RegionErrorKind::TypeTestError { type_test: type_test.clone() }); + } + } + } + + /// Invoked when we have some type-test (e.g., `T: 'X`) that we cannot + /// prove to be satisfied. If this is a closure, we will attempt to + /// "promote" this type-test into our `ClosureRegionRequirements` and + /// hence pass it up the creator. To do this, we have to phrase the + /// type-test in terms of external free regions, as local free + /// regions are not nameable by the closure's creator. + /// + /// Promotion works as follows: we first check that the type `T` + /// contains only regions that the creator knows about. If this is + /// true, then -- as a consequence -- we know that all regions in + /// the type `T` are free regions that outlive the closure body. If + /// false, then promotion fails. + /// + /// Once we've promoted T, we have to "promote" `'X` to some region + /// that is "external" to the closure. Generally speaking, a region + /// may be the union of some points in the closure body as well as + /// various free lifetimes. We can ignore the points in the closure + /// body: if the type T can be expressed in terms of external regions, + /// we know it outlives the points in the closure body. That + /// just leaves the free regions. + /// + /// The idea then is to lower the `T: 'X` constraint into multiple + /// bounds -- e.g., if `'X` is the union of two free lifetimes, + /// `'1` and `'2`, then we would create `T: '1` and `T: '2`. + fn try_promote_type_test( + &self, + infcx: &InferCtxt<'_, 'tcx>, + body: &Body<'tcx>, + type_test: &TypeTest<'tcx>, + propagated_outlives_requirements: &mut Vec>, + ) -> bool { + let tcx = infcx.tcx; + + let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test; + + let generic_ty = generic_kind.to_ty(tcx); + let subject = match self.try_promote_type_test_subject(infcx, generic_ty) { + Some(s) => s, + None => return false, + }; + + // For each region outlived by lower_bound find a non-local, + // universal region (it may be the same region) and add it to + // `ClosureOutlivesRequirement`. + let r_scc = self.constraint_sccs.scc(*lower_bound); + for ur in self.scc_values.universal_regions_outlived_by(r_scc) { + // Check whether we can already prove that the "subject" outlives `ur`. + // If so, we don't have to propagate this requirement to our caller. + // + // To continue the example from the function, if we are trying to promote + // a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union + // `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here + // we check whether `T: '1` is something we *can* prove. If so, no need + // to propagate that requirement. + // + // This is needed because -- particularly in the case + // where `ur` is a local bound -- we are sometimes in a + // position to prove things that our caller cannot. See + // #53570 for an example. + if self.eval_verify_bound(tcx, body, generic_ty, ur, &type_test.verify_bound) { + continue; + } + + debug!("try_promote_type_test: ur={:?}", ur); + + let non_local_ub = self.universal_region_relations.non_local_upper_bounds(&ur); + debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub); + + // This is slightly too conservative. To show T: '1, given `'2: '1` + // and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to + // avoid potential non-determinism we approximate this by requiring + // T: '1 and T: '2. + for &upper_bound in non_local_ub { + debug_assert!(self.universal_regions.is_universal_region(upper_bound)); + debug_assert!(!self.universal_regions.is_local_free_region(upper_bound)); + + let requirement = ClosureOutlivesRequirement { + subject, + outlived_free_region: upper_bound, + blame_span: locations.span(body), + category: ConstraintCategory::Boring, + }; + debug!("try_promote_type_test: pushing {:#?}", requirement); + propagated_outlives_requirements.push(requirement); + } + } + true + } + + /// When we promote a type test `T: 'r`, we have to convert the + /// type `T` into something we can store in a query result (so + /// something allocated for `'tcx`). This is problematic if `ty` + /// contains regions. During the course of NLL region checking, we + /// will have replaced all of those regions with fresh inference + /// variables. To create a test subject, we want to replace those + /// inference variables with some region from the closure + /// signature -- this is not always possible, so this is a + /// fallible process. Presuming we do find a suitable region, we + /// will use it's *external name*, which will be a `RegionKind` + /// variant that can be used in query responses such as + /// `ReEarlyBound`. + fn try_promote_type_test_subject( + &self, + infcx: &InferCtxt<'_, 'tcx>, + ty: Ty<'tcx>, + ) -> Option> { + let tcx = infcx.tcx; + + debug!("try_promote_type_test_subject(ty = {:?})", ty); + + let ty = tcx.fold_regions(ty, &mut false, |r, _depth| { + let region_vid = self.to_region_vid(r); + + // The challenge if this. We have some region variable `r` + // whose value is a set of CFG points and universal + // regions. We want to find if that set is *equivalent* to + // any of the named regions found in the closure. + // + // To do so, we compute the + // `non_local_universal_upper_bound`. This will be a + // non-local, universal region that is greater than `r`. + // However, it might not be *contained* within `r`, so + // then we further check whether this bound is contained + // in `r`. If so, we can say that `r` is equivalent to the + // bound. + // + // Let's work through a few examples. For these, imagine + // that we have 3 non-local regions (I'll denote them as + // `'static`, `'a`, and `'b`, though of course in the code + // they would be represented with indices) where: + // + // - `'static: 'a` + // - `'static: 'b` + // + // First, let's assume that `r` is some existential + // variable with an inferred value `{'a, 'static}` (plus + // some CFG nodes). In this case, the non-local upper + // bound is `'static`, since that outlives `'a`. `'static` + // is also a member of `r` and hence we consider `r` + // equivalent to `'static` (and replace it with + // `'static`). + // + // Now let's consider the inferred value `{'a, 'b}`. This + // means `r` is effectively `'a | 'b`. I'm not sure if + // this can come about, actually, but assuming it did, we + // would get a non-local upper bound of `'static`. Since + // `'static` is not contained in `r`, we would fail to + // find an equivalent. + let upper_bound = self.non_local_universal_upper_bound(region_vid); + if self.region_contains(region_vid, upper_bound) { + self.definitions[upper_bound].external_name.unwrap_or(r) + } else { + // In the case of a failure, use a `ReVar` result. This will + // cause the `needs_infer` later on to return `None`. + r + } + }); + + debug!("try_promote_type_test_subject: folded ty = {:?}", ty); + + // `needs_infer` will only be true if we failed to promote some region. + if ty.needs_infer() { + return None; + } + + Some(ClosureOutlivesSubject::Ty(ty)) + } + + /// Given some universal or existential region `r`, finds a + /// non-local, universal region `r+` that outlives `r` at entry to (and + /// exit from) the closure. In the worst case, this will be + /// `'static`. + /// + /// This is used for two purposes. First, if we are propagated + /// some requirement `T: r`, we can use this method to enlarge `r` + /// to something we can encode for our creator (which only knows + /// about non-local, universal regions). It is also used when + /// encoding `T` as part of `try_promote_type_test_subject` (see + /// that fn for details). + /// + /// This is based on the result `'y` of `universal_upper_bound`, + /// except that it converts further takes the non-local upper + /// bound of `'y`, so that the final result is non-local. + fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid { + debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); + + let lub = self.universal_upper_bound(r); + + // Grow further to get smallest universal region known to + // creator. + let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub); + + debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub); + + non_local_lub + } + + /// Returns a universally quantified region that outlives the + /// value of `r` (`r` may be existentially or universally + /// quantified). + /// + /// Since `r` is (potentially) an existential region, it has some + /// value which may include (a) any number of points in the CFG + /// and (b) any number of `end('x)` elements of universally + /// quantified regions. To convert this into a single universal + /// region we do as follows: + /// + /// - Ignore the CFG points in `'r`. All universally quantified regions + /// include the CFG anyhow. + /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding + /// a result `'y`. + #[instrument(skip(self), level = "debug")] + pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { + debug!(r = %self.region_value_str(r)); + + // Find the smallest universal region that contains all other + // universal regions within `region`. + let mut lub = self.universal_regions.fr_fn_body; + let r_scc = self.constraint_sccs.scc(r); + for ur in self.scc_values.universal_regions_outlived_by(r_scc) { + lub = self.universal_region_relations.postdom_upper_bound(lub, ur); + } + + debug!(?lub); + + lub + } + + /// Like `universal_upper_bound`, but returns an approximation more suitable + /// for diagnostics. If `r` contains multiple disjoint universal regions + /// (e.g. 'a and 'b in `fn foo<'a, 'b> { ... }`, we pick the lower-numbered region. + /// This corresponds to picking named regions over unnamed regions + /// (e.g. picking early-bound regions over a closure late-bound region). + /// + /// This means that the returned value may not be a true upper bound, since + /// only 'static is known to outlive disjoint universal regions. + /// Therefore, this method should only be used in diagnostic code, + /// where displaying *some* named universal region is better than + /// falling back to 'static. + pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid { + debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); + + // Find the smallest universal region that contains all other + // universal regions within `region`. + let mut lub = self.universal_regions.fr_fn_body; + let r_scc = self.constraint_sccs.scc(r); + let static_r = self.universal_regions.fr_static; + for ur in self.scc_values.universal_regions_outlived_by(r_scc) { + let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); + debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub); + // The upper bound of two non-static regions is static: this + // means we know nothing about the relationship between these + // two regions. Pick a 'better' one to use when constructing + // a diagnostic + if ur != static_r && lub != static_r && new_lub == static_r { + // Prefer the region with an `external_name` - this + // indicates that the region is early-bound, so working with + // it can produce a nicer error. + if self.region_definition(ur).external_name.is_some() { + lub = ur; + } else if self.region_definition(lub).external_name.is_some() { + // Leave lub unchanged + } else { + // If we get here, we don't have any reason to prefer + // one region over the other. Just pick the + // one with the lower index for now. + lub = std::cmp::min(ur, lub); + } + } else { + lub = new_lub; + } + } + + debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub); + + lub + } + + /// Tests if `test` is true when applied to `lower_bound` at + /// `point`. + fn eval_verify_bound( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + generic_ty: Ty<'tcx>, + lower_bound: RegionVid, + verify_bound: &VerifyBound<'tcx>, + ) -> bool { + debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound); + + match verify_bound { + VerifyBound::IfEq(test_ty, verify_bound1) => { + self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1) + } + + VerifyBound::IsEmpty => { + let lower_bound_scc = self.constraint_sccs.scc(lower_bound); + self.scc_values.elements_contained_in(lower_bound_scc).next().is_none() + } + + VerifyBound::OutlivedBy(r) => { + let r_vid = self.to_region_vid(r); + self.eval_outlives(r_vid, lower_bound) + } + + VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| { + self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) + }), + + VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| { + self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) + }), + } + } + + fn eval_if_eq( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + generic_ty: Ty<'tcx>, + lower_bound: RegionVid, + test_ty: Ty<'tcx>, + verify_bound: &VerifyBound<'tcx>, + ) -> bool { + let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty); + let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty); + if generic_ty_normalized == test_ty_normalized { + self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) + } else { + false + } + } + + /// This is a conservative normalization procedure. It takes every + /// free region in `value` and replaces it with the + /// "representative" of its SCC (see `scc_representatives` field). + /// We are guaranteed that if two values normalize to the same + /// thing, then they are equal; this is a conservative check in + /// that they could still be equal even if they normalize to + /// different results. (For example, there might be two regions + /// with the same value that are not in the same SCC). + /// + /// N.B., this is not an ideal approach and I would like to revisit + /// it. However, it works pretty well in practice. In particular, + /// this is needed to deal with projection outlives bounds like + /// + /// ```text + /// >::Item: '1 + /// ``` + /// + /// In particular, this routine winds up being important when + /// there are bounds like `where >::Item: 'b` in the + /// environment. In this case, if we can show that `'0 == 'a`, + /// and that `'b: '1`, then we know that the clause is + /// satisfied. In such cases, particularly due to limitations of + /// the trait solver =), we usually wind up with a where-clause like + /// `T: Foo<'a>` in scope, which thus forces `'0 == 'a` to be added as + /// a constraint, and thus ensures that they are in the same SCC. + /// + /// So why can't we do a more correct routine? Well, we could + /// *almost* use the `relate_tys` code, but the way it is + /// currently setup it creates inference variables to deal with + /// higher-ranked things and so forth, and right now the inference + /// context is not permitted to make more inference variables. So + /// we use this kind of hacky solution. + fn normalize_to_scc_representatives(&self, tcx: TyCtxt<'tcx>, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + tcx.fold_regions(value, &mut false, |r, _db| { + let vid = self.to_region_vid(r); + let scc = self.constraint_sccs.scc(vid); + let repr = self.scc_representatives[scc]; + tcx.mk_region(ty::ReVar(repr)) + }) + } + + // Evaluate whether `sup_region == sub_region`. + fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool { + self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1) + } + + // Evaluate whether `sup_region: sub_region`. + #[instrument(skip(self), level = "debug")] + fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { + debug!( + "eval_outlives: sup_region's value = {:?} universal={:?}", + self.region_value_str(sup_region), + self.universal_regions.is_universal_region(sup_region), + ); + debug!( + "eval_outlives: sub_region's value = {:?} universal={:?}", + self.region_value_str(sub_region), + self.universal_regions.is_universal_region(sub_region), + ); + + let sub_region_scc = self.constraint_sccs.scc(sub_region); + let sup_region_scc = self.constraint_sccs.scc(sup_region); + + // Both the `sub_region` and `sup_region` consist of the union + // of some number of universal regions (along with the union + // of various points in the CFG; ignore those points for + // now). Therefore, the sup-region outlives the sub-region if, + // for each universal region R1 in the sub-region, there + // exists some region R2 in the sup-region that outlives R1. + let universal_outlives = + self.scc_values.universal_regions_outlived_by(sub_region_scc).all(|r1| { + self.scc_values + .universal_regions_outlived_by(sup_region_scc) + .any(|r2| self.universal_region_relations.outlives(r2, r1)) + }); + + if !universal_outlives { + return false; + } + + // Now we have to compare all the points in the sub region and make + // sure they exist in the sup region. + + if self.universal_regions.is_universal_region(sup_region) { + // Micro-opt: universal regions contain all points. + return true; + } + + self.scc_values.contains_points(sup_region_scc, sub_region_scc) + } + + /// Once regions have been propagated, this method is used to see + /// whether any of the constraints were too strong. In particular, + /// we want to check for a case where a universally quantified + /// region exceeded its bounds. Consider: + /// + /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } + /// + /// In this case, returning `x` requires `&'a u32 <: &'b u32` + /// and hence we establish (transitively) a constraint that + /// `'a: 'b`. The `propagate_constraints` code above will + /// therefore add `end('a)` into the region for `'b` -- but we + /// have no evidence that `'b` outlives `'a`, so we want to report + /// an error. + /// + /// If `propagated_outlives_requirements` is `Some`, then we will + /// push unsatisfied obligations into there. Otherwise, we'll + /// report them as errors. + fn check_universal_regions( + &self, + body: &Body<'tcx>, + mut propagated_outlives_requirements: Option<&mut Vec>>, + errors_buffer: &mut RegionErrors<'tcx>, + ) { + for (fr, fr_definition) in self.definitions.iter_enumerated() { + match fr_definition.origin { + NllRegionVariableOrigin::FreeRegion => { + // Go through each of the universal regions `fr` and check that + // they did not grow too large, accumulating any requirements + // for our caller into the `outlives_requirements` vector. + self.check_universal_region( + body, + fr, + &mut propagated_outlives_requirements, + errors_buffer, + ); + } + + NllRegionVariableOrigin::Placeholder(placeholder) => { + self.check_bound_universal_region(fr, placeholder, errors_buffer); + } + + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::Existential { .. } => { + // nothing to check here + } + } + } + } + + /// Checks if Polonius has found any unexpected free region relations. + /// + /// In Polonius terms, a "subset error" (or "illegal subset relation error") is the equivalent + /// of NLL's "checking if any region constraints were too strong": a placeholder origin `'a` + /// was unexpectedly found to be a subset of another placeholder origin `'b`, and means in NLL + /// terms that the "longer free region" `'a` outlived the "shorter free region" `'b`. + /// + /// More details can be found in this blog post by Niko: + /// + /// + /// In the canonical example + /// + /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } + /// + /// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a + /// constraint that `'a: 'b`. It is an error that we have no evidence that this + /// constraint holds. + /// + /// If `propagated_outlives_requirements` is `Some`, then we will + /// push unsatisfied obligations into there. Otherwise, we'll + /// report them as errors. + fn check_polonius_subset_errors( + &self, + body: &Body<'tcx>, + mut propagated_outlives_requirements: Option<&mut Vec>>, + errors_buffer: &mut RegionErrors<'tcx>, + polonius_output: Rc, + ) { + debug!( + "check_polonius_subset_errors: {} subset_errors", + polonius_output.subset_errors.len() + ); + + // Similarly to `check_universal_regions`: a free region relation, which was not explicitly + // declared ("known") was found by Polonius, so emit an error, or propagate the + // requirements for our caller into the `propagated_outlives_requirements` vector. + // + // Polonius doesn't model regions ("origins") as CFG-subsets or durations, but the + // `longer_fr` and `shorter_fr` terminology will still be used here, for consistency with + // the rest of the NLL infrastructure. The "subset origin" is the "longer free region", + // and the "superset origin" is the outlived "shorter free region". + // + // Note: Polonius will produce a subset error at every point where the unexpected + // `longer_fr`'s "placeholder loan" is contained in the `shorter_fr`. This can be helpful + // for diagnostics in the future, e.g. to point more precisely at the key locations + // requiring this constraint to hold. However, the error and diagnostics code downstream + // expects that these errors are not duplicated (and that they are in a certain order). + // Otherwise, diagnostics messages such as the ones giving names like `'1` to elided or + // anonymous lifetimes for example, could give these names differently, while others like + // the outlives suggestions or the debug output from `#[rustc_regions]` would be + // duplicated. The polonius subset errors are deduplicated here, while keeping the + // CFG-location ordering. + let mut subset_errors: Vec<_> = polonius_output + .subset_errors + .iter() + .flat_map(|(_location, subset_errors)| subset_errors.iter()) + .collect(); + subset_errors.sort(); + subset_errors.dedup(); + + for (longer_fr, shorter_fr) in subset_errors.into_iter() { + debug!( + "check_polonius_subset_errors: subset_error longer_fr={:?},\ + shorter_fr={:?}", + longer_fr, shorter_fr + ); + + let propagated = self.try_propagate_universal_region_error( + *longer_fr, + *shorter_fr, + body, + &mut propagated_outlives_requirements, + ); + if propagated == RegionRelationCheckResult::Error { + errors_buffer.push(RegionErrorKind::RegionError { + longer_fr: *longer_fr, + shorter_fr: *shorter_fr, + fr_origin: NllRegionVariableOrigin::FreeRegion, + is_reported: true, + }); + } + } + + // Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has + // a more complete picture on how to separate this responsibility. + for (fr, fr_definition) in self.definitions.iter_enumerated() { + match fr_definition.origin { + NllRegionVariableOrigin::FreeRegion => { + // handled by polonius above + } + + NllRegionVariableOrigin::Placeholder(placeholder) => { + self.check_bound_universal_region(fr, placeholder, errors_buffer); + } + + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::Existential { .. } => { + // nothing to check here + } + } + } + } + + /// Checks the final value for the free region `fr` to see if it + /// grew too large. In particular, examine what `end(X)` points + /// wound up in `fr`'s final value; for each `end(X)` where `X != + /// fr`, we want to check that `fr: X`. If not, that's either an + /// error, or something we have to propagate to our creator. + /// + /// Things that are to be propagated are accumulated into the + /// `outlives_requirements` vector. + #[instrument( + skip(self, body, propagated_outlives_requirements, errors_buffer), + level = "debug" + )] + fn check_universal_region( + &self, + body: &Body<'tcx>, + longer_fr: RegionVid, + propagated_outlives_requirements: &mut Option<&mut Vec>>, + errors_buffer: &mut RegionErrors<'tcx>, + ) { + let longer_fr_scc = self.constraint_sccs.scc(longer_fr); + + // Because this free region must be in the ROOT universe, we + // know it cannot contain any bound universes. + assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT); + debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none()); + + // Only check all of the relations for the main representative of each + // SCC, otherwise just check that we outlive said representative. This + // reduces the number of redundant relations propagated out of + // closures. + // Note that the representative will be a universal region if there is + // one in this SCC, so we will always check the representative here. + let representative = self.scc_representatives[longer_fr_scc]; + if representative != longer_fr { + if let RegionRelationCheckResult::Error = self.check_universal_region_relation( + longer_fr, + representative, + body, + propagated_outlives_requirements, + ) { + errors_buffer.push(RegionErrorKind::RegionError { + longer_fr, + shorter_fr: representative, + fr_origin: NllRegionVariableOrigin::FreeRegion, + is_reported: true, + }); + } + return; + } + + // Find every region `o` such that `fr: o` + // (because `fr` includes `end(o)`). + let mut error_reported = false; + for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { + if let RegionRelationCheckResult::Error = self.check_universal_region_relation( + longer_fr, + shorter_fr, + body, + propagated_outlives_requirements, + ) { + // We only report the first region error. Subsequent errors are hidden so as + // not to overwhelm the user, but we do record them so as to potentially print + // better diagnostics elsewhere... + errors_buffer.push(RegionErrorKind::RegionError { + longer_fr, + shorter_fr, + fr_origin: NllRegionVariableOrigin::FreeRegion, + is_reported: !error_reported, + }); + + error_reported = true; + } + } + } + + /// Checks that we can prove that `longer_fr: shorter_fr`. If we can't we attempt to propagate + /// the constraint outward (e.g. to a closure environment), but if that fails, there is an + /// error. + fn check_universal_region_relation( + &self, + longer_fr: RegionVid, + shorter_fr: RegionVid, + body: &Body<'tcx>, + propagated_outlives_requirements: &mut Option<&mut Vec>>, + ) -> RegionRelationCheckResult { + // If it is known that `fr: o`, carry on. + if self.universal_region_relations.outlives(longer_fr, shorter_fr) { + RegionRelationCheckResult::Ok + } else { + // If we are not in a context where we can't propagate errors, or we + // could not shrink `fr` to something smaller, then just report an + // error. + // + // Note: in this case, we use the unapproximated regions to report the + // error. This gives better error messages in some cases. + self.try_propagate_universal_region_error( + longer_fr, + shorter_fr, + body, + propagated_outlives_requirements, + ) + } + } + + /// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's + /// creator. If we cannot, then the caller should report an error to the user. + fn try_propagate_universal_region_error( + &self, + longer_fr: RegionVid, + shorter_fr: RegionVid, + body: &Body<'tcx>, + propagated_outlives_requirements: &mut Option<&mut Vec>>, + ) -> RegionRelationCheckResult { + if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { + // Shrink `longer_fr` until we find a non-local region (if we do). + // We'll call it `fr-` -- it's ever so slightly smaller than + // `longer_fr`. + if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) + { + debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); + + let blame_span_category = self.find_outlives_blame_span( + body, + longer_fr, + NllRegionVariableOrigin::FreeRegion, + shorter_fr, + ); + + // Grow `shorter_fr` until we find some non-local regions. (We + // always will.) We'll call them `shorter_fr+` -- they're ever + // so slightly larger than `shorter_fr`. + let shorter_fr_plus = + self.universal_region_relations.non_local_upper_bounds(&shorter_fr); + debug!( + "try_propagate_universal_region_error: shorter_fr_plus={:?}", + shorter_fr_plus + ); + for &&fr in &shorter_fr_plus { + // Push the constraint `fr-: shorter_fr+` + propagated_outlives_requirements.push(ClosureOutlivesRequirement { + subject: ClosureOutlivesSubject::Region(fr_minus), + outlived_free_region: fr, + blame_span: blame_span_category.1.span, + category: blame_span_category.0, + }); + } + return RegionRelationCheckResult::Propagated; + } + } + + RegionRelationCheckResult::Error + } + + fn check_bound_universal_region( + &self, + longer_fr: RegionVid, + placeholder: ty::PlaceholderRegion, + errors_buffer: &mut RegionErrors<'tcx>, + ) { + debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,); + + let longer_fr_scc = self.constraint_sccs.scc(longer_fr); + debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,); + + // If we have some bound universal region `'a`, then the only + // elements it can contain is itself -- we don't know anything + // else about it! + let error_element = match { + self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element { + RegionElement::Location(_) => true, + RegionElement::RootUniversalRegion(_) => true, + RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1, + }) + } { + Some(v) => v, + None => return, + }; + debug!("check_bound_universal_region: error_element = {:?}", error_element); + + // Find the region that introduced this `error_element`. + errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { + longer_fr, + error_element, + placeholder, + }); + } + + fn check_member_constraints( + &self, + infcx: &InferCtxt<'_, 'tcx>, + errors_buffer: &mut RegionErrors<'tcx>, + ) { + let member_constraints = self.member_constraints.clone(); + for m_c_i in member_constraints.all_indices() { + debug!("check_member_constraint(m_c_i={:?})", m_c_i); + let m_c = &member_constraints[m_c_i]; + let member_region_vid = m_c.member_region_vid; + debug!( + "check_member_constraint: member_region_vid={:?} with value {}", + member_region_vid, + self.region_value_str(member_region_vid), + ); + let choice_regions = member_constraints.choice_regions(m_c_i); + debug!("check_member_constraint: choice_regions={:?}", choice_regions); + + // Did the member region wind up equal to any of the option regions? + if let Some(o) = + choice_regions.iter().find(|&&o_r| self.eval_equal(o_r, m_c.member_region_vid)) + { + debug!("check_member_constraint: evaluated as equal to {:?}", o); + continue; + } + + // If not, report an error. + let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid)); + errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { + span: m_c.definition_span, + hidden_ty: m_c.hidden_ty, + member_region, + }); + } + } + + /// We have a constraint `fr1: fr2` that is not satisfied, where + /// `fr2` represents some universal region. Here, `r` is some + /// region where we know that `fr1: r` and this function has the + /// job of determining whether `r` is "to blame" for the fact that + /// `fr1: fr2` is required. + /// + /// This is true under two conditions: + /// + /// - `r == fr2` + /// - `fr2` is `'static` and `r` is some placeholder in a universe + /// that cannot be named by `fr1`; in that case, we will require + /// that `fr1: 'static` because it is the only way to `fr1: r` to + /// be satisfied. (See `add_incompatible_universe`.) + crate fn provides_universal_region( + &self, + r: RegionVid, + fr1: RegionVid, + fr2: RegionVid, + ) -> bool { + debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2); + let result = { + r == fr2 || { + fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r) + } + }; + debug!("provides_universal_region: result = {:?}", result); + result + } + + /// If `r2` represents a placeholder region, then this returns + /// `true` if `r1` cannot name that placeholder in its + /// value; otherwise, returns `false`. + crate fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool { + debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2); + + match self.definitions[r2].origin { + NllRegionVariableOrigin::Placeholder(placeholder) => { + let universe1 = self.definitions[r1].universe; + debug!( + "cannot_name_value_of: universe1={:?} placeholder={:?}", + universe1, placeholder + ); + universe1.cannot_name(placeholder.universe) + } + + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::FreeRegion + | NllRegionVariableOrigin::Existential { .. } => false, + } + } + + crate fn retrieve_closure_constraint_info( + &self, + body: &Body<'tcx>, + constraint: &OutlivesConstraint<'tcx>, + ) -> BlameConstraint<'tcx> { + let loc = match constraint.locations { + Locations::All(span) => { + return BlameConstraint { + category: constraint.category, + from_closure: false, + cause: ObligationCause::dummy_with_span(span), + variance_info: constraint.variance_info, + }; + } + Locations::Single(loc) => loc, + }; + + let opt_span_category = + self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)); + opt_span_category + .map(|&(category, span)| BlameConstraint { + category, + from_closure: true, + cause: ObligationCause::dummy_with_span(span), + variance_info: constraint.variance_info, + }) + .unwrap_or(BlameConstraint { + category: constraint.category, + from_closure: false, + cause: ObligationCause::dummy_with_span(body.source_info(loc).span), + variance_info: constraint.variance_info, + }) + } + + /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. + crate fn find_outlives_blame_span( + &self, + body: &Body<'tcx>, + fr1: RegionVid, + fr1_origin: NllRegionVariableOrigin, + fr2: RegionVid, + ) -> (ConstraintCategory, ObligationCause<'tcx>) { + let BlameConstraint { category, cause, .. } = + self.best_blame_constraint(body, fr1, fr1_origin, |r| { + self.provides_universal_region(r, fr1, fr2) + }); + (category, cause) + } + + /// Walks the graph of constraints (where `'a: 'b` is considered + /// an edge `'a -> 'b`) to find all paths from `from_region` to + /// `to_region`. The paths are accumulated into the vector + /// `results`. The paths are stored as a series of + /// `ConstraintIndex` values -- in other words, a list of *edges*. + /// + /// Returns: a series of constraints as well as the region `R` + /// that passed the target test. + crate fn find_constraint_paths_between_regions( + &self, + from_region: RegionVid, + target_test: impl Fn(RegionVid) -> bool, + ) -> Option<(Vec>, RegionVid)> { + let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions); + context[from_region] = Trace::StartRegion; + + // Use a deque so that we do a breadth-first search. We will + // stop at the first match, which ought to be the shortest + // path (fewest constraints). + let mut deque = VecDeque::new(); + deque.push_back(from_region); + + while let Some(r) = deque.pop_front() { + debug!( + "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}", + from_region, + r, + self.region_value_str(r), + ); + + // Check if we reached the region we were looking for. If so, + // we can reconstruct the path that led to it and return it. + if target_test(r) { + let mut result = vec![]; + let mut p = r; + loop { + match context[p].clone() { + Trace::NotVisited => { + bug!("found unvisited region {:?} on path to {:?}", p, r) + } + + Trace::FromOutlivesConstraint(c) => { + p = c.sup; + result.push(c); + } + + Trace::StartRegion => { + result.reverse(); + return Some((result, r)); + } + } + } + } + + // Otherwise, walk over the outgoing constraints and + // enqueue any regions we find, keeping track of how we + // reached them. + + // A constraint like `'r: 'x` can come from our constraint + // graph. + let fr_static = self.universal_regions.fr_static; + let outgoing_edges_from_graph = + self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static); + + // Always inline this closure because it can be hot. + let mut handle_constraint = #[inline(always)] + |constraint: OutlivesConstraint<'tcx>| { + debug_assert_eq!(constraint.sup, r); + let sub_region = constraint.sub; + if let Trace::NotVisited = context[sub_region] { + context[sub_region] = Trace::FromOutlivesConstraint(constraint); + deque.push_back(sub_region); + } + }; + + // This loop can be hot. + for constraint in outgoing_edges_from_graph { + handle_constraint(constraint); + } + + // Member constraints can also give rise to `'r: 'x` edges that + // were not part of the graph initially, so watch out for those. + // (But they are extremely rare; this loop is very cold.) + for constraint in self.applied_member_constraints(r) { + let p_c = &self.member_constraints[constraint.member_constraint_index]; + let constraint = OutlivesConstraint { + sup: r, + sub: constraint.min_choice, + locations: Locations::All(p_c.definition_span), + category: ConstraintCategory::OpaqueType, + variance_info: ty::VarianceDiagInfo::default(), + }; + handle_constraint(constraint); + } + } + + None + } + + /// Finds some region R such that `fr1: R` and `R` is live at `elem`. + #[instrument(skip(self), level = "trace")] + crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { + trace!(scc = ?self.constraint_sccs.scc(fr1)); + trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); + self.find_constraint_paths_between_regions(fr1, |r| { + // First look for some `r` such that `fr1: r` and `r` is live at `elem` + trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r)); + self.liveness_constraints.contains(r, elem) + }) + .or_else(|| { + // If we fail to find that, we may find some `r` such that + // `fr1: r` and `r` is a placeholder from some universe + // `fr1` cannot name. This would force `fr1` to be + // `'static`. + self.find_constraint_paths_between_regions(fr1, |r| { + self.cannot_name_placeholder(fr1, r) + }) + }) + .or_else(|| { + // If we fail to find THAT, it may be that `fr1` is a + // placeholder that cannot "fit" into its SCC. In that + // case, there should be some `r` where `fr1: r` and `fr1` is a + // placeholder that `r` cannot name. We can blame that + // edge. + // + // Remember that if `R1: R2`, then the universe of R1 + // must be able to name the universe of R2, because R2 will + // be at least `'empty(Universe(R2))`, and `R1` must be at + // larger than that. + self.find_constraint_paths_between_regions(fr1, |r| { + self.cannot_name_placeholder(r, fr1) + }) + }) + .map(|(_path, r)| r) + .unwrap() + } + + /// Get the region outlived by `longer_fr` and live at `element`. + crate fn region_from_element( + &self, + longer_fr: RegionVid, + element: &RegionElement, + ) -> RegionVid { + match *element { + RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l), + RegionElement::RootUniversalRegion(r) => r, + RegionElement::PlaceholderRegion(error_placeholder) => self + .definitions + .iter_enumerated() + .find_map(|(r, definition)| match definition.origin { + NllRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r), + _ => None, + }) + .unwrap(), + } + } + + /// Get the region definition of `r`. + crate fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> { + &self.definitions[r] + } + + /// Check if the SCC of `r` contains `upper`. + crate fn upper_bound_in_region_scc(&self, r: RegionVid, upper: RegionVid) -> bool { + let r_scc = self.constraint_sccs.scc(r); + self.scc_values.contains(r_scc, upper) + } + + crate fn universal_regions(&self) -> &UniversalRegions<'tcx> { + self.universal_regions.as_ref() + } + + /// Tries to find the best constraint to blame for the fact that + /// `R: from_region`, where `R` is some region that meets + /// `target_test`. This works by following the constraint graph, + /// creating a constraint path that forces `R` to outlive + /// `from_region`, and then finding the best choices within that + /// path to blame. + crate fn best_blame_constraint( + &self, + body: &Body<'tcx>, + from_region: RegionVid, + from_region_origin: NllRegionVariableOrigin, + target_test: impl Fn(RegionVid) -> bool, + ) -> BlameConstraint<'tcx> { + debug!( + "best_blame_constraint(from_region={:?}, from_region_origin={:?})", + from_region, from_region_origin + ); + + // Find all paths + let (path, target_region) = + self.find_constraint_paths_between_regions(from_region, target_test).unwrap(); + debug!( + "best_blame_constraint: path={:#?}", + path.iter() + .map(|c| format!( + "{:?} ({:?}: {:?})", + c, + self.constraint_sccs.scc(c.sup), + self.constraint_sccs.scc(c.sub), + )) + .collect::>() + ); + + // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. + // Instead, we use it to produce an improved `ObligationCauseCode`. + // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate` + // constraints. Currently, we just pick the first one. + let cause_code = path + .iter() + .find_map(|constraint| { + if let ConstraintCategory::Predicate(predicate_span) = constraint.category { + // We currentl'y doesn't store the `DefId` in the `ConstraintCategory` + // for perforamnce reasons. The error reporting code used by NLL only + // uses the span, so this doesn't cause any problems at the moment. + Some(ObligationCauseCode::BindingObligation( + CRATE_DEF_ID.to_def_id(), + predicate_span, + )) + } else { + None + } + }) + .unwrap_or_else(|| ObligationCauseCode::MiscObligation); + + // Classify each of the constraints along the path. + let mut categorized_path: Vec> = path + .iter() + .map(|constraint| { + if constraint.category == ConstraintCategory::ClosureBounds { + self.retrieve_closure_constraint_info(body, &constraint) + } else { + BlameConstraint { + category: constraint.category, + from_closure: false, + cause: ObligationCause::new( + constraint.locations.span(body), + CRATE_HIR_ID, + cause_code.clone(), + ), + variance_info: constraint.variance_info, + } + } + }) + .collect(); + debug!("best_blame_constraint: categorized_path={:#?}", categorized_path); + + // To find the best span to cite, we first try to look for the + // final constraint that is interesting and where the `sup` is + // not unified with the ultimate target region. The reason + // for this is that we have a chain of constraints that lead + // from the source to the target region, something like: + // + // '0: '1 ('0 is the source) + // '1: '2 + // '2: '3 + // '3: '4 + // '4: '5 + // '5: '6 ('6 is the target) + // + // Some of those regions are unified with `'6` (in the same + // SCC). We want to screen those out. After that point, the + // "closest" constraint we have to the end is going to be the + // most likely to be the point where the value escapes -- but + // we still want to screen for an "interesting" point to + // highlight (e.g., a call site or something). + let target_scc = self.constraint_sccs.scc(target_region); + let mut range = 0..path.len(); + + // As noted above, when reporting an error, there is typically a chain of constraints + // leading from some "source" region which must outlive some "target" region. + // In most cases, we prefer to "blame" the constraints closer to the target -- + // but there is one exception. When constraints arise from higher-ranked subtyping, + // we generally prefer to blame the source value, + // as the "target" in this case tends to be some type annotation that the user gave. + // Therefore, if we find that the region origin is some instantiation + // of a higher-ranked region, we start our search from the "source" point + // rather than the "target", and we also tweak a few other things. + // + // An example might be this bit of Rust code: + // + // ```rust + // let x: fn(&'static ()) = |_| {}; + // let y: for<'a> fn(&'a ()) = x; + // ``` + // + // In MIR, this will be converted into a combination of assignments and type ascriptions. + // In particular, the 'static is imposed through a type ascription: + // + // ```rust + // x = ...; + // AscribeUserType(x, fn(&'static ()) + // y = x; + // ``` + // + // We wind up ultimately with constraints like + // + // ```rust + // !a: 'temp1 // from the `y = x` statement + // 'temp1: 'temp2 + // 'temp2: 'static // from the AscribeUserType + // ``` + // + // and here we prefer to blame the source (the y = x statement). + let blame_source = match from_region_origin { + NllRegionVariableOrigin::FreeRegion + | NllRegionVariableOrigin::Existential { from_forall: false } => true, + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::Placeholder(_) + | NllRegionVariableOrigin::Existential { from_forall: true } => false, + }; + + let find_region = |i: &usize| { + let constraint = &path[*i]; + + let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup); + + if blame_source { + match categorized_path[*i].category { + ConstraintCategory::OpaqueType + | ConstraintCategory::Boring + | ConstraintCategory::BoringNoLocation + | ConstraintCategory::Internal + | ConstraintCategory::Predicate(_) => false, + ConstraintCategory::TypeAnnotation + | ConstraintCategory::Return(_) + | ConstraintCategory::Yield => true, + _ => constraint_sup_scc != target_scc, + } + } else { + match categorized_path[*i].category { + ConstraintCategory::OpaqueType + | ConstraintCategory::Boring + | ConstraintCategory::BoringNoLocation + | ConstraintCategory::Internal + | ConstraintCategory::Predicate(_) => false, + _ => true, + } + } + }; + + let best_choice = + if blame_source { range.rev().find(find_region) } else { range.find(find_region) }; + + debug!( + "best_blame_constraint: best_choice={:?} blame_source={}", + best_choice, blame_source + ); + + if let Some(i) = best_choice { + if let Some(next) = categorized_path.get(i + 1) { + if matches!(categorized_path[i].category, ConstraintCategory::Return(_)) + && next.category == ConstraintCategory::OpaqueType + { + // The return expression is being influenced by the return type being + // impl Trait, point at the return type and not the return expr. + return next.clone(); + } + } + + if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal) + { + let field = categorized_path.iter().find_map(|p| { + if let ConstraintCategory::ClosureUpvar(f) = p.category { + Some(f) + } else { + None + } + }); + + if let Some(field) = field { + categorized_path[i].category = + ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)); + } + } + + return categorized_path[i].clone(); + } + + // If that search fails, that is.. unusual. Maybe everything + // is in the same SCC or something. In that case, find what + // appears to be the most interesting point to report to the + // user via an even more ad-hoc guess. + categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category)); + debug!("best_blame_constraint: sorted_path={:#?}", categorized_path); + + categorized_path.remove(0) + } + + crate fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + self.universe_causes[&universe].clone() + } +} + +impl<'tcx> RegionDefinition<'tcx> { + fn new(universe: ty::UniverseIndex, rv_origin: RegionVariableOrigin) -> Self { + // Create a new region definition. Note that, for free + // regions, the `external_name` field gets updated later in + // `init_universal_regions`. + + let origin = match rv_origin { + RegionVariableOrigin::Nll(origin) => origin, + _ => NllRegionVariableOrigin::Existential { from_forall: false }, + }; + + Self { origin, universe, external_name: None } + } +} + +pub trait ClosureRegionRequirementsExt<'tcx> { + fn apply_requirements( + &self, + tcx: TyCtxt<'tcx>, + closure_def_id: DefId, + closure_substs: SubstsRef<'tcx>, + ) -> Vec>; +} + +impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx> { + /// Given an instance T of the closure type, this method + /// instantiates the "extra" requirements that we computed for the + /// closure into the inference context. This has the effect of + /// adding new outlives obligations to existing variables. + /// + /// As described on `ClosureRegionRequirements`, the extra + /// requirements are expressed in terms of regionvids that index + /// into the free regions that appear on the closure type. So, to + /// do this, we first copy those regions out from the type T into + /// a vector. Then we can just index into that vector to extract + /// out the corresponding region from T and apply the + /// requirements. + fn apply_requirements( + &self, + tcx: TyCtxt<'tcx>, + closure_def_id: DefId, + closure_substs: SubstsRef<'tcx>, + ) -> Vec> { + debug!( + "apply_requirements(closure_def_id={:?}, closure_substs={:?})", + closure_def_id, closure_substs + ); + + // Extract the values of the free regions in `closure_substs` + // into a vector. These are the regions that we will be + // relating to one another. + let closure_mapping = &UniversalRegions::closure_mapping( + tcx, + closure_substs, + self.num_external_vids, + tcx.closure_base_def_id(closure_def_id), + ); + debug!("apply_requirements: closure_mapping={:?}", closure_mapping); + + // Create the predicates. + self.outlives_requirements + .iter() + .map(|outlives_requirement| { + let outlived_region = closure_mapping[outlives_requirement.outlived_free_region]; + + match outlives_requirement.subject { + ClosureOutlivesSubject::Region(region) => { + let region = closure_mapping[region]; + debug!( + "apply_requirements: region={:?} \ + outlived_region={:?} \ + outlives_requirement={:?}", + region, outlived_region, outlives_requirement, + ); + ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region)) + } + + ClosureOutlivesSubject::Ty(ty) => { + debug!( + "apply_requirements: ty={:?} \ + outlived_region={:?} \ + outlives_requirement={:?}", + ty, outlived_region, outlives_requirement, + ); + ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)) + } + } + }) + .collect() + } +} + +#[derive(Clone, Debug)] +pub struct BlameConstraint<'tcx> { + pub category: ConstraintCategory, + pub from_closure: bool, + pub cause: ObligationCause<'tcx>, + pub variance_info: ty::VarianceDiagInfo<'tcx>, +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/opaque_types.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/opaque_types.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/opaque_types.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/opaque_types.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,239 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::vec_map::VecMap; +use rustc_hir::OpaqueTyOrigin; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; +use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; +use rustc_span::Span; +use rustc_trait_selection::opaque_types::InferCtxtExt; + +use super::RegionInferenceContext; + +impl<'tcx> RegionInferenceContext<'tcx> { + /// Resolve any opaque types that were encountered while borrow checking + /// this item. This is then used to get the type in the `type_of` query. + /// + /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. + /// This is lowered to give HIR something like + /// + /// type f<'a>::_Return<'_a> = impl Sized + '_a; + /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x } + /// + /// When checking the return type record the type from the return and the + /// type used in the return value. In this case they might be `_Return<'1>` + /// and `&'2 i32` respectively. + /// + /// Once we to this method, we have completed region inference and want to + /// call `infer_opaque_definition_from_instantiation` to get the inferred + /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation` + /// compares lifetimes directly, so we need to map the inference variables + /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`. + /// + /// First we map all the lifetimes in the concrete type to an equal + /// universal region that occurs in the concrete type's substs, in this case + /// this would result in `&'1 i32`. We only consider regions in the substs + /// in case there is an equal region that does not. For example, this should + /// be allowed: + /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` + /// + /// Then we map the regions in both the type and the subst to their + /// `external_name` giving `concrete_type = &'a i32`, + /// `substs = ['static, 'a]`. This will then allow + /// `infer_opaque_definition_from_instantiation` to determine that + /// `_Return<'_a> = &'_a i32`. + /// + /// There's a slight complication around closures. Given + /// `fn f<'a: 'a>() { || {} }` the closure's type is something like + /// `f::<'a>::{{closure}}`. The region parameter from f is essentially + /// ignored by type checking so ends up being inferred to an empty region. + /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, + /// which has no `external_name` in which case we use `'empty` as the + /// region to pass to `infer_opaque_definition_from_instantiation`. + #[instrument(level = "debug", skip(self, infcx))] + pub(crate) fn infer_opaque_types( + &self, + infcx: &InferCtxt<'_, 'tcx>, + opaque_ty_decls: VecMap, OpaqueTypeDecl<'tcx>>, + span: Span, + ) -> VecMap, Ty<'tcx>> { + opaque_ty_decls + .into_iter() + .filter_map(|(opaque_type_key, decl)| { + let substs = opaque_type_key.substs; + let concrete_type = decl.concrete_ty; + debug!(?concrete_type, ?substs); + + let mut subst_regions = vec![self.universal_regions.fr_static]; + let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| { + let vid = self.universal_regions.to_region_vid(region); + subst_regions.push(vid); + self.definitions[vid].external_name.unwrap_or_else(|| { + infcx + .tcx + .sess + .delay_span_bug(span, "opaque type with non-universal region substs"); + infcx.tcx.lifetimes.re_static + }) + }); + + subst_regions.sort(); + subst_regions.dedup(); + + let universal_concrete_type = + infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region { + ty::ReVar(vid) => subst_regions + .iter() + .find(|ur_vid| self.eval_equal(vid, **ur_vid)) + .and_then(|ur_vid| self.definitions[*ur_vid].external_name) + .unwrap_or(infcx.tcx.lifetimes.re_root_empty), + _ => region, + }); + + debug!(?universal_concrete_type, ?universal_substs); + + let opaque_type_key = + OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }; + let remapped_type = infcx.infer_opaque_definition_from_instantiation( + opaque_type_key, + universal_concrete_type, + span, + ); + + check_opaque_type_parameter_valid( + infcx.tcx, + opaque_type_key, + OpaqueTypeDecl { concrete_ty: remapped_type, ..decl }, + ) + .then_some((opaque_type_key, remapped_type)) + }) + .collect() + } + + /// Map the regions in the type to named regions. This is similar to what + /// `infer_opaque_types` does, but can infer any universal region, not only + /// ones from the substs for the opaque type. It also doesn't double check + /// that the regions produced are in fact equal to the named region they are + /// replaced with. This is fine because this function is only to improve the + /// region names in error messages. + pub(crate) fn name_regions(&self, tcx: TyCtxt<'tcx>, ty: T) -> T + where + T: TypeFoldable<'tcx>, + { + tcx.fold_regions(ty, &mut false, |region, _| match *region { + ty::ReVar(vid) => { + // Find something that we can name + let upper_bound = self.approx_universal_upper_bound(vid); + let upper_bound = &self.definitions[upper_bound]; + match upper_bound.external_name { + Some(reg) => reg, + None => { + // Nothing exact found, so we pick the first one that we find. + let scc = self.constraint_sccs.scc(vid); + for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) { + match self.definitions[vid].external_name { + None => {} + Some(&ty::ReStatic) => {} + Some(region) => return region, + } + } + region + } + } + } + _ => region, + }) + } +} + +fn check_opaque_type_parameter_valid( + tcx: TyCtxt<'_>, + opaque_type_key: OpaqueTypeKey<'_>, + decl: OpaqueTypeDecl<'_>, +) -> bool { + match decl.origin { + // No need to check return position impl trait (RPIT) + // because for type and const parameters they are correct + // by construction: we convert + // + // fn foo() -> impl Trait + // + // into + // + // type Foo + // fn foo() -> Foo. + // + // For lifetime parameters we convert + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // which would error here on all of the `'static` args. + OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true, + // Check these + OpaqueTyOrigin::TyAlias => {} + } + let span = decl.definition_span; + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); + for (i, arg) in opaque_type_key.substs.iter().enumerate() { + let arg_is_param = match arg.unpack() { + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), + GenericArgKind::Lifetime(ty::ReStatic) => { + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_label( + tcx.def_span(opaque_generics.param_at(i, tcx).def_id), + "cannot use static lifetime; use a bound lifetime \ + instead or remove the lifetime parameter from the \ + opaque type", + ) + .emit(); + return false; + } + GenericArgKind::Lifetime(lt) => { + matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + } + GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), + }; + + if arg_is_param { + seen_params.entry(arg).or_default().push(i); + } else { + // Prevent `fn foo() -> Foo` from being defining. + let opaque_param = opaque_generics.param_at(i, tcx); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note( + tcx.def_span(opaque_param.def_id), + &format!( + "used non-generic {} `{}` for generic parameter", + opaque_param.kind.descr(), + arg, + ), + ) + .emit(); + return false; + } + } + + for (_, indices) in seen_params { + if indices.len() > 1 { + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); + let spans: Vec<_> = indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note(spans, &format!("{} used multiple times", descr)) + .emit(); + return false; + } + } + true +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,68 @@ +use crate::constraints::ConstraintSccIndex; +use crate::RegionInferenceContext; +use itertools::Itertools; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::graph::vec_graph::VecGraph; +use rustc_data_structures::graph::WithSuccessors; +use rustc_middle::ty::RegionVid; +use std::ops::Range; +use std::rc::Rc; + +crate struct ReverseSccGraph { + graph: VecGraph, + /// For each SCC, the range of `universal_regions` that use that SCC as + /// their value. + scc_regions: FxHashMap>, + /// All of the universal regions, in grouped so that `scc_regions` can + /// index into here. + universal_regions: Vec, +} + +impl ReverseSccGraph { + /// Find all universal regions that are required to outlive the given SCC. + pub(super) fn upper_bounds<'a>( + &'a self, + scc0: ConstraintSccIndex, + ) -> impl Iterator + 'a { + let mut duplicates = FxHashSet::default(); + self.graph + .depth_first_search(scc0) + .flat_map(move |scc1| { + self.scc_regions + .get(&scc1) + .map_or(&[][..], |range| &self.universal_regions[range.clone()]) + }) + .copied() + .filter(move |r| duplicates.insert(*r)) + } +} + +impl RegionInferenceContext<'_> { + /// Compute and return the reverse SCC-based constraint graph (lazily). + pub(super) fn reverse_scc_graph(&mut self) -> Rc { + if let Some(g) = &self.rev_scc_graph { + return g.clone(); + } + + let graph = self.constraint_sccs.reverse(); + let mut paired_scc_regions = self + .universal_regions + .universal_regions() + .map(|region| (self.constraint_sccs.scc(region), region)) + .collect_vec(); + paired_scc_regions.sort(); + let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); + + let mut scc_regions = FxHashMap::default(); + let mut start = 0; + for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) { + let group_size = group.count(); + scc_regions.insert(scc, start..start + group_size); + start += group_size; + } + + let rev_graph = Rc::new(ReverseSccGraph { graph, scc_regions, universal_regions }); + self.rev_scc_graph = Some(rev_graph.clone()); + rev_graph + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/values.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/values.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/values.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/region_infer/values.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,498 @@ +use rustc_data_structures::fx::FxIndexSet; +use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; +use rustc_index::vec::Idx; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::{BasicBlock, Body, Location}; +use rustc_middle::ty::{self, RegionVid}; +use std::fmt::Debug; +use std::rc::Rc; + +/// Maps between a `Location` and a `PointIndex` (and vice versa). +crate struct RegionValueElements { + /// For each basic block, how many points are contained within? + statements_before_block: IndexVec, + + /// Map backward from each point to the basic block that it + /// belongs to. + basic_blocks: IndexVec, + + num_points: usize, +} + +impl RegionValueElements { + crate fn new(body: &Body<'_>) -> Self { + let mut num_points = 0; + let statements_before_block: IndexVec = body + .basic_blocks() + .iter() + .map(|block_data| { + let v = num_points; + num_points += block_data.statements.len() + 1; + v + }) + .collect(); + debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block); + debug!("RegionValueElements: num_points={:#?}", num_points); + + let mut basic_blocks = IndexVec::with_capacity(num_points); + for (bb, bb_data) in body.basic_blocks().iter_enumerated() { + basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); + } + + Self { statements_before_block, basic_blocks, num_points } + } + + /// Total number of point indices + crate fn num_points(&self) -> usize { + self.num_points + } + + /// Converts a `Location` into a `PointIndex`. O(1). + crate fn point_from_location(&self, location: Location) -> PointIndex { + let Location { block, statement_index } = location; + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index + statement_index) + } + + /// Converts a `Location` into a `PointIndex`. O(1). + crate fn entry_point(&self, block: BasicBlock) -> PointIndex { + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index) + } + + /// Converts a `PointIndex` back to a location. O(1). + crate fn to_location(&self, index: PointIndex) -> Location { + assert!(index.index() < self.num_points); + let block = self.basic_blocks[index]; + let start_index = self.statements_before_block[block]; + let statement_index = index.index() - start_index; + Location { block, statement_index } + } + + /// Sometimes we get point-indices back from bitsets that may be + /// out of range (because they round up to the nearest 2^N number + /// of bits). Use this function to filter such points out if you + /// like. + crate fn point_in_range(&self, index: PointIndex) -> bool { + index.index() < self.num_points + } + + /// Pushes all predecessors of `index` onto `stack`. + crate fn push_predecessors( + &self, + body: &Body<'_>, + index: PointIndex, + stack: &mut Vec, + ) { + let Location { block, statement_index } = self.to_location(index); + if statement_index == 0 { + // If this is a basic block head, then the predecessors are + // the terminators of other basic blocks + stack.extend( + body.predecessors()[block] + .iter() + .map(|&pred_bb| body.terminator_loc(pred_bb)) + .map(|pred_loc| self.point_from_location(pred_loc)), + ); + } else { + // Otherwise, the pred is just the previous statement + stack.push(PointIndex::new(index.index() - 1)); + } + } +} + +rustc_index::newtype_index! { + /// A single integer representing a `Location` in the MIR control-flow + /// graph. Constructed efficiently from `RegionValueElements`. + pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" } +} + +rustc_index::newtype_index! { + /// A single integer representing a `ty::Placeholder`. + pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" } +} + +/// An individual element in a region value -- the value of a +/// particular region variable consists of a set of these elements. +#[derive(Debug, Clone)] +crate enum RegionElement { + /// A point in the control-flow graph. + Location(Location), + + /// A universally quantified region from the root universe (e.g., + /// a lifetime parameter). + RootUniversalRegion(RegionVid), + + /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)` + /// type). + PlaceholderRegion(ty::PlaceholderRegion), +} + +/// When we initially compute liveness, we use a bit matrix storing +/// points for each region-vid. +crate struct LivenessValues { + elements: Rc, + points: SparseBitMatrix, +} + +impl LivenessValues { + /// Creates a new set of "region values" that tracks causal information. + /// Each of the regions in num_region_variables will be initialized with an + /// empty set of points and no causal information. + crate fn new(elements: Rc) -> Self { + Self { points: SparseBitMatrix::new(elements.num_points), elements } + } + + /// Iterate through each region that has a value in this set. + crate fn rows(&self) -> impl Iterator { + self.points.rows() + } + + /// Adds the given element to the value for the given region. Returns whether + /// the element is newly added (i.e., was not already present). + crate fn add_element(&mut self, row: N, location: Location) -> bool { + debug!("LivenessValues::add(r={:?}, location={:?})", row, location); + let index = self.elements.point_from_location(location); + self.points.insert(row, index) + } + + /// Adds all the elements in the given bit array into the given + /// region. Returns whether any of them are newly added. + crate fn add_elements(&mut self, row: N, locations: &HybridBitSet) -> bool { + debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); + self.points.union_row(row, locations) + } + + /// Adds all the control-flow points to the values for `r`. + crate fn add_all_points(&mut self, row: N) { + self.points.insert_all_into_row(row); + } + + /// Returns `true` if the region `r` contains the given element. + crate fn contains(&self, row: N, location: Location) -> bool { + let index = self.elements.point_from_location(location); + self.points.contains(row, index) + } + + /// Returns an iterator of all the elements contained by the region `r` + crate fn get_elements(&self, row: N) -> impl Iterator + '_ { + self.points + .row(row) + .into_iter() + .flat_map(|set| set.iter()) + .take_while(move |&p| self.elements.point_in_range(p)) + .map(move |p| self.elements.to_location(p)) + } + + /// Returns a "pretty" string value of the region. Meant for debugging. + crate fn region_value_str(&self, r: N) -> String { + region_value_str(self.get_elements(r).map(RegionElement::Location)) + } +} + +/// Maps from `ty::PlaceholderRegion` values that are used in the rest of +/// rustc to the internal `PlaceholderIndex` values that are used in +/// NLL. +#[derive(Default)] +crate struct PlaceholderIndices { + indices: FxIndexSet, +} + +impl PlaceholderIndices { + crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { + let (index, _) = self.indices.insert_full(placeholder); + index.into() + } + + crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { + self.indices.get_index_of(&placeholder).unwrap().into() + } + + crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion { + self.indices[placeholder.index()] + } + + crate fn len(&self) -> usize { + self.indices.len() + } +} + +/// Stores the full values for a set of regions (in contrast to +/// `LivenessValues`, which only stores those points in the where a +/// region is live). The full value for a region may contain points in +/// the CFG, but also free regions as well as bound universe +/// placeholders. +/// +/// Example: +/// +/// ```text +/// fn foo(x: &'a u32) -> &'a u32 { +/// let y: &'0 u32 = x; // let's call this `'0` +/// y +/// } +/// ``` +/// +/// Here, the variable `'0` would contain the free region `'a`, +/// because (since it is returned) it must live for at least `'a`. But +/// it would also contain various points from within the function. +#[derive(Clone)] +crate struct RegionValues { + elements: Rc, + placeholder_indices: Rc, + points: SparseBitMatrix, + free_regions: SparseBitMatrix, + + /// Placeholders represent bound regions -- so something like `'a` + /// in for<'a> fn(&'a u32)`. + placeholders: SparseBitMatrix, +} + +impl RegionValues { + /// Creates a new set of "region values" that tracks causal information. + /// Each of the regions in num_region_variables will be initialized with an + /// empty set of points and no causal information. + crate fn new( + elements: &Rc, + num_universal_regions: usize, + placeholder_indices: &Rc, + ) -> Self { + let num_placeholders = placeholder_indices.len(); + Self { + elements: elements.clone(), + points: SparseBitMatrix::new(elements.num_points), + placeholder_indices: placeholder_indices.clone(), + free_regions: SparseBitMatrix::new(num_universal_regions), + placeholders: SparseBitMatrix::new(num_placeholders), + } + } + + /// Adds the given element to the value for the given region. Returns whether + /// the element is newly added (i.e., was not already present). + crate fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool { + debug!("add(r={:?}, elem={:?})", r, elem); + elem.add_to_row(self, r) + } + + /// Adds all the control-flow points to the values for `r`. + crate fn add_all_points(&mut self, r: N) { + self.points.insert_all_into_row(r); + } + + /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to: + /// r_from`). + crate fn add_region(&mut self, r_to: N, r_from: N) -> bool { + self.points.union_rows(r_from, r_to) + | self.free_regions.union_rows(r_from, r_to) + | self.placeholders.union_rows(r_from, r_to) + } + + /// Returns `true` if the region `r` contains the given element. + crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool { + elem.contained_in_row(self, r) + } + + /// `self[to] |= values[from]`, essentially: that is, take all the + /// elements for the region `from` from `values` and add them to + /// the region `to` in `self`. + crate fn merge_liveness(&mut self, to: N, from: M, values: &LivenessValues) { + if let Some(set) = values.points.row(from) { + self.points.union_row(to, set); + } + } + + /// Returns `true` if `sup_region` contains all the CFG points that + /// `sub_region` contains. Ignores universal regions. + crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool { + if let Some(sub_row) = self.points.row(sub_region) { + if let Some(sup_row) = self.points.row(sup_region) { + sup_row.superset(sub_row) + } else { + // sup row is empty, so sub row must be empty + sub_row.is_empty() + } + } else { + // sub row is empty, always true + true + } + } + + /// Returns the locations contained within a given region `r`. + crate fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator + 'a { + self.points.row(r).into_iter().flat_map(move |set| { + set.iter() + .take_while(move |&p| self.elements.point_in_range(p)) + .map(move |p| self.elements.to_location(p)) + }) + } + + /// Returns just the universal regions that are contained in a given region's value. + crate fn universal_regions_outlived_by<'a>( + &'a self, + r: N, + ) -> impl Iterator + 'a { + self.free_regions.row(r).into_iter().flat_map(|set| set.iter()) + } + + /// Returns all the elements contained in a given region's value. + crate fn placeholders_contained_in<'a>( + &'a self, + r: N, + ) -> impl Iterator + 'a { + self.placeholders + .row(r) + .into_iter() + .flat_map(|set| set.iter()) + .map(move |p| self.placeholder_indices.lookup_placeholder(p)) + } + + /// Returns all the elements contained in a given region's value. + crate fn elements_contained_in<'a>(&'a self, r: N) -> impl Iterator + 'a { + let points_iter = self.locations_outlived_by(r).map(RegionElement::Location); + + let free_regions_iter = + self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion); + + let placeholder_universes_iter = + self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion); + + points_iter.chain(free_regions_iter).chain(placeholder_universes_iter) + } + + /// Returns a "pretty" string value of the region. Meant for debugging. + crate fn region_value_str(&self, r: N) -> String { + region_value_str(self.elements_contained_in(r)) + } +} + +crate trait ToElementIndex: Debug + Copy { + fn add_to_row(self, values: &mut RegionValues, row: N) -> bool; + + fn contained_in_row(self, values: &RegionValues, row: N) -> bool; +} + +impl ToElementIndex for Location { + fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { + let index = values.elements.point_from_location(self); + values.points.insert(row, index) + } + + fn contained_in_row(self, values: &RegionValues, row: N) -> bool { + let index = values.elements.point_from_location(self); + values.points.contains(row, index) + } +} + +impl ToElementIndex for RegionVid { + fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { + values.free_regions.insert(row, self) + } + + fn contained_in_row(self, values: &RegionValues, row: N) -> bool { + values.free_regions.contains(row, self) + } +} + +impl ToElementIndex for ty::PlaceholderRegion { + fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { + let index = values.placeholder_indices.lookup_index(self); + values.placeholders.insert(row, index) + } + + fn contained_in_row(self, values: &RegionValues, row: N) -> bool { + let index = values.placeholder_indices.lookup_index(self); + values.placeholders.contains(row, index) + } +} + +crate fn location_set_str( + elements: &RegionValueElements, + points: impl IntoIterator, +) -> String { + region_value_str( + points + .into_iter() + .take_while(|&p| elements.point_in_range(p)) + .map(|p| elements.to_location(p)) + .map(RegionElement::Location), + ) +} + +fn region_value_str(elements: impl IntoIterator) -> String { + let mut result = String::new(); + result.push('{'); + + // Set to Some(l1, l2) when we have observed all the locations + // from l1..=l2 (inclusive) but not yet printed them. This + // gets extended if we then see l3 where l3 is the successor + // to l2. + let mut open_location: Option<(Location, Location)> = None; + + let mut sep = ""; + let mut push_sep = |s: &mut String| { + s.push_str(sep); + sep = ", "; + }; + + for element in elements { + match element { + RegionElement::Location(l) => { + if let Some((location1, location2)) = open_location { + if location2.block == l.block + && location2.statement_index == l.statement_index - 1 + { + open_location = Some((location1, l)); + continue; + } + + push_sep(&mut result); + push_location_range(&mut result, location1, location2); + } + + open_location = Some((l, l)); + } + + RegionElement::RootUniversalRegion(fr) => { + if let Some((location1, location2)) = open_location { + push_sep(&mut result); + push_location_range(&mut result, location1, location2); + open_location = None; + } + + push_sep(&mut result); + result.push_str(&format!("{:?}", fr)); + } + + RegionElement::PlaceholderRegion(placeholder) => { + if let Some((location1, location2)) = open_location { + push_sep(&mut result); + push_location_range(&mut result, location1, location2); + open_location = None; + } + + push_sep(&mut result); + result.push_str(&format!("{:?}", placeholder)); + } + } + } + + if let Some((location1, location2)) = open_location { + push_sep(&mut result); + push_location_range(&mut result, location1, location2); + } + + result.push('}'); + + return result; + + fn push_location_range(str: &mut String, location1: Location, location2: Location) { + if location1 == location2 { + str.push_str(&format!("{:?}", location1)); + } else { + assert_eq!(location1.block, location2.block); + str.push_str(&format!( + "{:?}[{}..={}]", + location1.block, location1.statement_index, location2.statement_index + )); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/renumber.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/renumber.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/renumber.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/renumber.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,99 @@ +use rustc_index::vec::IndexVec; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; +use rustc_middle::mir::visit::{MutVisitor, TyContext}; +use rustc_middle::mir::{Body, Location, PlaceElem, Promoted}; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; + +/// Replaces all free regions appearing in the MIR with fresh +/// inference variables, returning the number of variables created. +#[instrument(skip(infcx, body, promoted), level = "debug")] +pub fn renumber_mir<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + body: &mut Body<'tcx>, + promoted: &mut IndexVec>, +) { + debug!(?body.arg_count); + + let mut visitor = NllVisitor { infcx }; + + for body in promoted.iter_mut() { + visitor.visit_body(body); + } + + visitor.visit_body(body); +} + +/// Replaces all regions appearing in `value` with fresh inference +/// variables. +#[instrument(skip(infcx), level = "debug")] +pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T +where + T: TypeFoldable<'tcx>, +{ + infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { + let origin = NllRegionVariableOrigin::Existential { from_forall: false }; + infcx.next_nll_region_var(origin) + }) +} + +struct NllVisitor<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> NllVisitor<'a, 'tcx> { + fn renumber_regions(&mut self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + renumber_regions(self.infcx, value) + } +} + +impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + #[instrument(skip(self), level = "debug")] + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { + *ty = self.renumber_regions(ty); + + debug!(?ty); + } + + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + _: Location, + ) -> Option> { + if let PlaceElem::Field(field, ty) = elem { + let new_ty = self.renumber_regions(ty); + + if new_ty != ty { + return Some(PlaceElem::Field(field, new_ty)); + } + } + + None + } + + #[instrument(skip(self), level = "debug")] + fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { + *substs = self.renumber_regions(*substs); + + debug!(?substs); + } + + #[instrument(skip(self), level = "debug")] + fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) { + let old_region = *region; + *region = self.renumber_regions(&old_region); + + debug!(?region); + } + + fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) { + *constant = self.renumber_regions(&*constant); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/canonical.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/canonical.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/canonical.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/canonical.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,169 @@ +use std::fmt; + +use rustc_infer::infer::canonical::Canonical; +use rustc_infer::traits::query::NoSolution; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::{self, ToPredicate, TypeFoldable}; +use rustc_span::def_id::DefId; +use rustc_span::Span; +use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; +use rustc_trait_selection::traits::query::Fallible; + +use crate::diagnostics::{ToUniverseInfo, UniverseInfo}; + +use super::{Locations, NormalizeLocation, TypeChecker}; + +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + /// Given some operation `op` that manipulates types, proves + /// predicates, or otherwise uses the inference context, executes + /// `op` and then executes all the further obligations that `op` + /// returns. This will yield a set of outlives constraints amongst + /// regions which are extracted and stored as having occurred at + /// `locations`. + /// + /// **Any `rustc_infer::infer` operations that might generate region + /// constraints should occur within this method so that those + /// constraints can be properly localized!** + #[instrument(skip(self, category, op), level = "trace")] + pub(super) fn fully_perform_op( + &mut self, + locations: Locations, + category: ConstraintCategory, + op: Op, + ) -> Fallible + where + Op: type_op::TypeOp<'tcx, Output = R>, + Canonical<'tcx, Op>: ToUniverseInfo<'tcx>, + { + let old_universe = self.infcx.universe(); + + let TypeOpOutput { output, constraints, canonicalized_query } = + op.fully_perform(self.infcx)?; + + if let Some(data) = &constraints { + self.push_region_constraints(locations, category, data); + } + + let universe = self.infcx.universe(); + + if old_universe != universe { + let universe_info = match canonicalized_query { + Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe), + None => UniverseInfo::other(), + }; + for u in old_universe..universe { + self.borrowck_context + .constraints + .universe_causes + .insert(u + 1, universe_info.clone()); + } + } + + Ok(output) + } + + pub(super) fn instantiate_canonical_with_fresh_inference_vars( + &mut self, + span: Span, + canonical: &Canonical<'tcx, T>, + ) -> T + where + T: TypeFoldable<'tcx>, + { + let (instantiated, _) = + self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); + + for u in 0..canonical.max_universe.as_u32() { + let info = UniverseInfo::other(); + self.borrowck_context + .constraints + .universe_causes + .insert(ty::UniverseIndex::from_u32(u), info); + } + + instantiated + } + + pub(super) fn prove_trait_ref( + &mut self, + trait_ref: ty::TraitRef<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) { + self.prove_predicates( + Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + }))), + locations, + category, + ); + } + + pub(super) fn normalize_and_prove_instantiated_predicates( + &mut self, + // Keep this parameter for now, in case we start using + // it in `ConstraintCategory` at some point. + _def_id: DefId, + instantiated_predicates: ty::InstantiatedPredicates<'tcx>, + locations: Locations, + ) { + for (predicate, span) in instantiated_predicates + .predicates + .into_iter() + .zip(instantiated_predicates.spans.into_iter()) + { + let predicate = self.normalize(predicate, locations); + self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span)); + } + } + + pub(super) fn prove_predicates( + &mut self, + predicates: impl IntoIterator>, + locations: Locations, + category: ConstraintCategory, + ) { + for predicate in predicates { + let predicate = predicate.to_predicate(self.tcx()); + debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,); + + self.prove_predicate(predicate, locations, category); + } + } + + #[instrument(skip(self), level = "debug")] + pub(super) fn prove_predicate( + &mut self, + predicate: ty::Predicate<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) { + let param_env = self.param_env; + self.fully_perform_op( + locations, + category, + param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)), + ) + .unwrap_or_else(|NoSolution| { + span_mirbug!(self, NoSolution, "could not prove {:?}", predicate); + }) + } + + #[instrument(skip(self), level = "debug")] + pub(super) fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T + where + T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, + { + let param_env = self.param_env; + self.fully_perform_op( + location.to_locations(), + ConstraintCategory::Boring, + param_env.and(type_op::normalize::Normalize::new(value)), + ) + .unwrap_or_else(|NoSolution| { + span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value); + value + }) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,177 @@ +use rustc_infer::infer::canonical::QueryOutlivesConstraint; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::outlives::env::RegionBoundPairs; +use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; +use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; +use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::DUMMY_SP; + +use crate::{ + constraints::OutlivesConstraint, + nll::ToRegionVid, + region_infer::TypeTest, + type_check::{Locations, MirTypeckRegionConstraints}, + universal_regions::UniversalRegions, +}; + +crate struct ConstraintConversion<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + tcx: TyCtxt<'tcx>, + universal_regions: &'a UniversalRegions<'tcx>, + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + implicit_region_bound: Option>, + param_env: ty::ParamEnv<'tcx>, + locations: Locations, + category: ConstraintCategory, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, +} + +impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { + crate fn new( + infcx: &'a InferCtxt<'a, 'tcx>, + universal_regions: &'a UniversalRegions<'tcx>, + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + implicit_region_bound: Option>, + param_env: ty::ParamEnv<'tcx>, + locations: Locations, + category: ConstraintCategory, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + ) -> Self { + Self { + infcx, + tcx: infcx.tcx, + universal_regions, + region_bound_pairs, + implicit_region_bound, + param_env, + locations, + category, + constraints, + } + } + + #[instrument(skip(self), level = "debug")] + pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { + let QueryRegionConstraints { outlives, member_constraints } = query_constraints; + + // Annoying: to invoke `self.to_region_vid`, we need access to + // `self.constraints`, but we also want to be mutating + // `self.member_constraints`. For now, just swap out the value + // we want and replace at the end. + let mut tmp = std::mem::take(&mut self.constraints.member_constraints); + for member_constraint in member_constraints { + tmp.push_constraint(member_constraint, |r| self.to_region_vid(r)); + } + self.constraints.member_constraints = tmp; + + for query_constraint in outlives { + self.convert(query_constraint); + } + } + + pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { + debug!("generate: constraints at: {:#?}", self.locations); + + // Extract out various useful fields we'll need below. + let ConstraintConversion { + tcx, region_bound_pairs, implicit_region_bound, param_env, .. + } = *self; + + // At the moment, we never generate any "higher-ranked" + // region constraints like `for<'a> 'a: 'b`. At some point + // when we move to universes, we will, and this assertion + // will start to fail. + let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| { + bug!("query_constraint {:?} contained bound vars", query_constraint,); + }); + + match k1.unpack() { + GenericArgKind::Lifetime(r1) => { + let r1_vid = self.to_region_vid(r1); + let r2_vid = self.to_region_vid(r2); + self.add_outlives(r1_vid, r2_vid); + } + + GenericArgKind::Type(t1) => { + // we don't actually use this for anything, but + // the `TypeOutlives` code needs an origin. + let origin = infer::RelateParamBound(DUMMY_SP, t1, None); + + TypeOutlives::new( + &mut *self, + tcx, + region_bound_pairs, + implicit_region_bound, + param_env, + ) + .type_must_outlive(origin, t1, r2); + } + + GenericArgKind::Const(_) => { + // Consts cannot outlive one another, so we + // don't need to handle any relations here. + } + } + } + + fn verify_to_type_test( + &mut self, + generic_kind: GenericKind<'tcx>, + region: ty::Region<'tcx>, + verify_bound: VerifyBound<'tcx>, + ) -> TypeTest<'tcx> { + let lower_bound = self.to_region_vid(region); + + TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound } + } + + fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid { + if let ty::RePlaceholder(placeholder) = r { + self.constraints.placeholder_region(self.infcx, *placeholder).to_region_vid() + } else { + self.universal_regions.to_region_vid(r) + } + } + + fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { + self.constraints.outlives_constraints.push(OutlivesConstraint { + locations: self.locations, + category: self.category, + sub, + sup, + variance_info: ty::VarianceDiagInfo::default(), + }); + } + + fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { + debug!("add_type_test(type_test={:?})", type_test); + self.constraints.type_tests.push(type_test); + } +} + +impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { + fn push_sub_region_constraint( + &mut self, + _origin: SubregionOrigin<'tcx>, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) { + let b = self.to_region_vid(b); + let a = self.to_region_vid(a); + self.add_outlives(b, a); + } + + fn push_verify( + &mut self, + _origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region<'tcx>, + bound: VerifyBound<'tcx>, + ) { + let type_test = self.verify_to_type_test(kind, a, bound); + self.add_type_test(type_test); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/free_region_relations.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/free_region_relations.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/free_region_relations.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/free_region_relations.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,401 @@ +use rustc_data_structures::frozen::Frozen; +use rustc_data_structures::transitive_relation::TransitiveRelation; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::free_regions::FreeRegionRelations; +use rustc_infer::infer::outlives; +use rustc_infer::infer::region_constraints::GenericKind; +use rustc_infer::infer::InferCtxt; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::traits::query::OutlivesBound; +use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; +use std::rc::Rc; +use type_op::TypeOpOutput; + +use crate::{ + nll::ToRegionVid, + type_check::constraint_conversion, + type_check::{Locations, MirTypeckRegionConstraints}, + universal_regions::UniversalRegions, +}; + +#[derive(Debug)] +crate struct UniversalRegionRelations<'tcx> { + universal_regions: Rc>, + + /// Stores the outlives relations that are known to hold from the + /// implied bounds, in-scope where-clauses, and that sort of + /// thing. + outlives: TransitiveRelation, + + /// This is the `<=` relation; that is, if `a: b`, then `b <= a`, + /// and we store that here. This is useful when figuring out how + /// to express some local region in terms of external regions our + /// caller will understand. + inverse_outlives: TransitiveRelation, +} + +/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to +/// be true. These encode relationships like `T: 'a` that are +/// added via implicit bounds. +/// +/// Each region here is guaranteed to be a key in the `indices` +/// map. We use the "original" regions (i.e., the keys from the +/// map, and not the values) because the code in +/// `process_registered_region_obligations` has some special-cased +/// logic expecting to see (e.g.) `ReStatic`, and if we supplied +/// our special inference variable there, we would mess that up. +type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; + +/// As part of computing the free region relations, we also have to +/// normalize the input-output types, which we then need later. So we +/// return those. This vector consists of first the input types and +/// then the output type as the last element. +type NormalizedInputsAndOutput<'tcx> = Vec>; + +crate struct CreateResult<'tcx> { + crate universal_region_relations: Frozen>, + crate region_bound_pairs: RegionBoundPairs<'tcx>, + crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, +} + +crate fn create( + infcx: &InferCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + implicit_region_bound: Option>, + universal_regions: &Rc>, + constraints: &mut MirTypeckRegionConstraints<'tcx>, +) -> CreateResult<'tcx> { + UniversalRegionRelationsBuilder { + infcx, + param_env, + implicit_region_bound, + constraints, + universal_regions: universal_regions.clone(), + region_bound_pairs: Vec::new(), + relations: UniversalRegionRelations { + universal_regions: universal_regions.clone(), + outlives: Default::default(), + inverse_outlives: Default::default(), + }, + } + .create() +} + +impl UniversalRegionRelations<'tcx> { + /// Records in the `outlives_relation` (and + /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the + /// builder below. + fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { + debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b); + self.outlives.add(fr_a, fr_b); + self.inverse_outlives.add(fr_b, fr_a); + } + + /// Given two universal regions, returns the postdominating + /// upper-bound (effectively the least upper bound). + /// + /// (See `TransitiveRelation::postdom_upper_bound` for details on + /// the postdominating upper bound in general.) + crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { + assert!(self.universal_regions.is_universal_region(fr1)); + assert!(self.universal_regions.is_universal_region(fr2)); + *self + .inverse_outlives + .postdom_upper_bound(&fr1, &fr2) + .unwrap_or(&self.universal_regions.fr_static) + } + + /// Finds an "upper bound" for `fr` that is not local. In other + /// words, returns the smallest (*) known region `fr1` that (a) + /// outlives `fr` and (b) is not local. + /// + /// (*) If there are multiple competing choices, we return all of them. + crate fn non_local_upper_bounds(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> { + debug!("non_local_upper_bound(fr={:?})", fr); + let res = self.non_local_bounds(&self.inverse_outlives, fr); + assert!(!res.is_empty(), "can't find an upper bound!?"); + res + } + + /// Returns the "postdominating" bound of the set of + /// `non_local_upper_bounds` for the given region. + crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { + let upper_bounds = self.non_local_upper_bounds(&fr); + + // In case we find more than one, reduce to one for + // convenience. This is to prevent us from generating more + // complex constraints, but it will cause spurious errors. + let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds); + + debug!("non_local_bound: post_dom={:?}", post_dom); + + post_dom + .and_then(|&post_dom| { + // If the mutual immediate postdom is not local, then + // there is no non-local result we can return. + if !self.universal_regions.is_local_free_region(post_dom) { + Some(post_dom) + } else { + None + } + }) + .unwrap_or(self.universal_regions.fr_static) + } + + /// Finds a "lower bound" for `fr` that is not local. In other + /// words, returns the largest (*) known region `fr1` that (a) is + /// outlived by `fr` and (b) is not local. + /// + /// (*) If there are multiple competing choices, we pick the "postdominating" + /// one. See `TransitiveRelation::postdom_upper_bound` for details. + crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option { + debug!("non_local_lower_bound(fr={:?})", fr); + let lower_bounds = self.non_local_bounds(&self.outlives, &fr); + + // In case we find more than one, reduce to one for + // convenience. This is to prevent us from generating more + // complex constraints, but it will cause spurious errors. + let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds); + + debug!("non_local_bound: post_dom={:?}", post_dom); + + post_dom.and_then(|&post_dom| { + // If the mutual immediate postdom is not local, then + // there is no non-local result we can return. + if !self.universal_regions.is_local_free_region(post_dom) { + Some(post_dom) + } else { + None + } + }) + } + + /// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`. + /// Repeatedly invokes `postdom_parent` until we find something that is not + /// local. Returns `None` if we never do so. + fn non_local_bounds<'a>( + &self, + relation: &'a TransitiveRelation, + fr0: &'a RegionVid, + ) -> Vec<&'a RegionVid> { + // This method assumes that `fr0` is one of the universally + // quantified region variables. + assert!(self.universal_regions.is_universal_region(*fr0)); + + let mut external_parents = vec![]; + let mut queue = vec![fr0]; + + // Keep expanding `fr` into its parents until we reach + // non-local regions. + while let Some(fr) = queue.pop() { + if !self.universal_regions.is_local_free_region(*fr) { + external_parents.push(fr); + continue; + } + + queue.extend(relation.parents(fr)); + } + + debug!("non_local_bound: external_parents={:?}", external_parents); + + external_parents + } + + /// Returns `true` if fr1 is known to outlive fr2. + /// + /// This will only ever be true for universally quantified regions. + crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { + self.outlives.contains(&fr1, &fr2) + } + + /// Returns a vector of free regions `x` such that `fr1: x` is + /// known to hold. + crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> { + self.outlives.reachable_from(&fr1) + } + + /// Returns the _non-transitive_ set of known `outlives` constraints between free regions. + crate fn known_outlives(&self) -> impl Iterator { + self.outlives.base_edges() + } +} + +struct UniversalRegionRelationsBuilder<'this, 'tcx> { + infcx: &'this InferCtxt<'this, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + universal_regions: Rc>, + implicit_region_bound: Option>, + constraints: &'this mut MirTypeckRegionConstraints<'tcx>, + + // outputs: + relations: UniversalRegionRelations<'tcx>, + region_bound_pairs: RegionBoundPairs<'tcx>, +} + +impl UniversalRegionRelationsBuilder<'cx, 'tcx> { + crate fn create(mut self) -> CreateResult<'tcx> { + let unnormalized_input_output_tys = self + .universal_regions + .unnormalized_input_tys + .iter() + .cloned() + .chain(Some(self.universal_regions.unnormalized_output_ty)); + + // For each of the input/output types: + // - Normalize the type. This will create some region + // constraints, which we buffer up because we are + // not ready to process them yet. + // - Then compute the implied bounds. This will adjust + // the `region_bound_pairs` and so forth. + // - After this is done, we'll process the constraints, once + // the `relations` is built. + let mut normalized_inputs_and_output = + Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); + let constraint_sets: Vec<_> = unnormalized_input_output_tys + .flat_map(|ty| { + debug!("build: input_or_output={:?}", ty); + // We add implied bounds from both the unnormalized and normalized ty + // See issue #87748 + let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self + .param_env + .and(type_op::normalize::Normalize::new(ty)) + .fully_perform(self.infcx) + .unwrap_or_else(|_| { + self.infcx + .tcx + .sess + .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty)); + TypeOpOutput { + output: self.infcx.tcx.ty_error(), + constraints: None, + canonicalized_query: None, + } + }); + // Note: we need this in examples like + // ``` + // trait Foo { + // type Bar; + // fn foo(&self) -> &Self::Bar; + // } + // impl Foo for () { + // type Bar = (); + // fn foo(&self) ->&() {} + // } + // ``` + // Both &Self::Bar and &() are WF + let constraints_implied = self.add_implied_bounds(norm_ty); + normalized_inputs_and_output.push(norm_ty); + constraints1.into_iter().chain(constraints_implied) + }) + .collect(); + + // Insert the facts we know from the predicates. Why? Why not. + let param_env = self.param_env; + self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); + + // Finally: + // - outlives is reflexive, so `'r: 'r` for every region `'r` + // - `'static: 'r` for every region `'r` + // - `'r: 'fn_body` for every (other) universally quantified + // region `'r`, all of which are provided by our caller + let fr_static = self.universal_regions.fr_static; + let fr_fn_body = self.universal_regions.fr_fn_body; + for fr in self.universal_regions.universal_regions() { + debug!("build: relating free region {:?} to itself and to 'static", fr); + self.relations.relate_universal_regions(fr, fr); + self.relations.relate_universal_regions(fr_static, fr); + self.relations.relate_universal_regions(fr, fr_fn_body); + } + + for data in &constraint_sets { + constraint_conversion::ConstraintConversion::new( + self.infcx, + &self.universal_regions, + &self.region_bound_pairs, + self.implicit_region_bound, + self.param_env, + Locations::All(DUMMY_SP), + ConstraintCategory::Internal, + &mut self.constraints, + ) + .convert_all(data); + } + + CreateResult { + universal_region_relations: Frozen::freeze(self.relations), + region_bound_pairs: self.region_bound_pairs, + normalized_inputs_and_output, + } + } + + /// Update the type of a single local, which should represent + /// either the return type of the MIR or one of its arguments. At + /// the same time, compute and add any implied bounds that come + /// from this local. + fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option>> { + debug!("add_implied_bounds(ty={:?})", ty); + let TypeOpOutput { output: bounds, constraints, .. } = self + .param_env + .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) + .fully_perform(self.infcx) + .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty)); + self.add_outlives_bounds(bounds); + constraints + } + + /// Registers the `OutlivesBound` items from `outlives_bounds` in + /// the outlives relation as well as the region-bound pairs + /// listing. + fn add_outlives_bounds(&mut self, outlives_bounds: I) + where + I: IntoIterator>, + { + for outlives_bound in outlives_bounds { + debug!("add_outlives_bounds(bound={:?})", outlives_bound); + + match outlives_bound { + OutlivesBound::RegionSubRegion(r1, r2) => { + // `where Type:` is lowered to `where Type: 'empty` so that + // we check `Type` is well formed, but there's no use for + // this bound here. + if let ty::ReEmpty(_) = r1 { + return; + } + + // The bound says that `r1 <= r2`; we store `r2: r1`. + let r1 = self.universal_regions.to_region_vid(r1); + let r2 = self.universal_regions.to_region_vid(r2); + self.relations.relate_universal_regions(r2, r1); + } + + OutlivesBound::RegionSubParam(r_a, param_b) => { + self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); + } + + OutlivesBound::RegionSubProjection(r_a, projection_b) => { + self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); + } + } + } + } +} + +/// This trait is used by the `impl-trait` constraint code to abstract +/// over the `FreeRegionMap` from lexical regions and +/// `UniversalRegions` (from NLL)`. +impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> { + fn sub_free_regions( + &self, + _tcx: TyCtxt<'tcx>, + shorter: ty::Region<'tcx>, + longer: ty::Region<'tcx>, + ) -> bool { + let shorter = shorter.to_region_vid(); + assert!(self.universal_regions.is_universal_region(shorter)); + let longer = longer.to_region_vid(); + assert!(self.universal_regions.is_universal_region(longer)); + self.outlives(longer, shorter) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/input_output.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/input_output.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/input_output.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/input_output.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,210 @@ +//! This module contains code to equate the input/output types appearing +//! in the MIR with the expected input/output types from the function +//! signature. This requires a bit of processing, as the expected types +//! are supplied to us before normalization and may contain opaque +//! `impl Trait` instances. In contrast, the input/output types found in +//! the MIR (specifically, in the special local variables for the +//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and +//! contain revealed `impl Trait` values). + +use rustc_index::vec::Idx; +use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_middle::mir::*; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; +use rustc_trait_selection::traits::query::normalize::AtExt; + +use crate::universal_regions::UniversalRegions; + +use super::{Locations, TypeChecker}; + +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + #[instrument(skip(self, body, universal_regions), level = "debug")] + pub(super) fn equate_inputs_and_outputs( + &mut self, + body: &Body<'tcx>, + universal_regions: &UniversalRegions<'tcx>, + normalized_inputs_and_output: &[Ty<'tcx>], + ) { + let (&normalized_output_ty, normalized_input_tys) = + normalized_inputs_and_output.split_last().unwrap(); + + let mir_def_id = body.source.def_id().expect_local(); + + // If the user explicitly annotated the input types, extract + // those. + // + // e.g., `|x: FxHashMap<_, &'static u32>| ...` + let user_provided_sig; + if !self.tcx().is_closure(mir_def_id.to_def_id()) { + user_provided_sig = None; + } else { + let typeck_results = self.tcx().typeck(mir_def_id); + user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map( + |user_provided_poly_sig| { + // Instantiate the canonicalized variables from + // user-provided signature (e.g., the `_` in the code + // above) with fresh variables. + let poly_sig = self.instantiate_canonical_with_fresh_inference_vars( + body.span, + &user_provided_poly_sig, + ); + + // Replace the bound items in the fn sig with fresh + // variables, so that they represent the view from + // "inside" the closure. + self.infcx + .replace_bound_vars_with_fresh_vars( + body.span, + LateBoundRegionConversionTime::FnCall, + poly_sig, + ) + .0 + }, + ); + } + + debug!(?normalized_input_tys, ?body.local_decls); + + // Equate expected input tys with those in the MIR. + for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { + if argument_index + 1 >= body.local_decls.len() { + self.tcx() + .sess + .delay_span_bug(body.span, "found more normalized_input_ty than local_decls"); + break; + } + // In MIR, argument N is stored in local N+1. + let local = Local::new(argument_index + 1); + + let mir_input_ty = body.local_decls[local].ty; + let mir_input_span = body.local_decls[local].source_info.span; + self.equate_normalized_input_or_output( + normalized_input_ty, + mir_input_ty, + mir_input_span, + ); + } + + if let Some(user_provided_sig) = user_provided_sig { + for (argument_index, &user_provided_input_ty) in + user_provided_sig.inputs().iter().enumerate() + { + // In MIR, closures begin an implicit `self`, so + // argument N is stored in local N+2. + let local = Local::new(argument_index + 2); + let mir_input_ty = body.local_decls[local].ty; + let mir_input_span = body.local_decls[local].source_info.span; + + // If the user explicitly annotated the input types, enforce those. + let user_provided_input_ty = + self.normalize(user_provided_input_ty, Locations::All(mir_input_span)); + self.equate_normalized_input_or_output( + user_provided_input_ty, + mir_input_ty, + mir_input_span, + ); + } + } + + assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some()); + if let Some(mir_yield_ty) = body.yield_ty() { + let ur_yield_ty = universal_regions.yield_ty.unwrap(); + let yield_span = body.local_decls[RETURN_PLACE].source_info.span; + self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span); + } + + // Return types are a bit more complex. They may contain opaque `impl Trait` types. + let mir_output_ty = body.local_decls[RETURN_PLACE].ty; + let output_span = body.local_decls[RETURN_PLACE].source_info.span; + if let Err(terr) = self.eq_opaque_type_and_type( + mir_output_ty, + normalized_output_ty, + Locations::All(output_span), + ConstraintCategory::BoringNoLocation, + ) { + span_mirbug!( + self, + Location::START, + "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", + normalized_output_ty, + mir_output_ty, + terr + ); + }; + + // If the user explicitly annotated the output types, enforce those. + // Note that this only happens for closures. + if let Some(user_provided_sig) = user_provided_sig { + let user_provided_output_ty = user_provided_sig.output(); + let user_provided_output_ty = + self.normalize(user_provided_output_ty, Locations::All(output_span)); + if let Err(err) = self.eq_opaque_type_and_type( + mir_output_ty, + user_provided_output_ty, + Locations::All(output_span), + ConstraintCategory::BoringNoLocation, + ) { + span_mirbug!( + self, + Location::START, + "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", + mir_output_ty, + user_provided_output_ty, + err + ); + } + } + } + + #[instrument(skip(self, span), level = "debug")] + fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { + if let Err(_) = + self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) + { + // FIXME(jackh726): This is a hack. It's somewhat like + // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd + // like to normalize *before* inserting into `local_decls`, but + // doing so ends up causing some other trouble. + let b = match self + .infcx + .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) + .normalize(b) + { + Ok(n) => { + debug!("equate_inputs_and_outputs: {:?}", n); + if n.obligations.iter().all(|o| { + matches!( + o.predicate.kind().skip_binder(), + ty::PredicateKind::RegionOutlives(_) + | ty::PredicateKind::TypeOutlives(_) + ) + }) { + n.value + } else { + b + } + } + Err(_) => { + debug!("equate_inputs_and_outputs: NoSolution"); + b + } + }; + // Note: if we have to introduce new placeholders during normalization above, then we won't have + // added those universes to the universe info, which we would want in `relate_tys`. + if let Err(terr) = + self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) + { + span_mirbug!( + self, + Location::START, + "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`", + a, + b, + terr + ); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,166 @@ +use rustc_data_structures::vec_linked_list as vll; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location}; + +use crate::def_use::{self, DefUse}; +use crate::region_infer::values::{PointIndex, RegionValueElements}; + +/// A map that cross references each local with the locations where it +/// is defined (assigned), used, or dropped. Used during liveness +/// computation. +/// +/// We keep track only of `Local`s we'll do the liveness analysis later, +/// this means that our internal `IndexVec`s will only be sparsely populated. +/// In the time-memory trade-off between keeping compact vectors with new +/// indexes (and needing to continuously map the `Local` index to its compact +/// counterpart) and having `IndexVec`s that we only use a fraction of, time +/// (and code simplicity) was favored. The rationale is that we only keep +/// a small number of `IndexVec`s throughout the entire analysis while, in +/// contrast, we're accessing each `Local` *many* times. +crate struct LocalUseMap { + /// Head of a linked list of **definitions** of each variable -- + /// definition in this context means assignment, e.g., `x` is + /// defined in `x = y` but not `y`; that first def is the head of + /// a linked list that lets you enumerate all places the variable + /// is assigned. + first_def_at: IndexVec>, + + /// Head of a linked list of **uses** of each variable -- use in + /// this context means that the existing value of the variable is + /// read or modified. e.g., `y` is used in `x = y` but not `x`. + /// Note that `DROP(x)` terminators are excluded from this list. + first_use_at: IndexVec>, + + /// Head of a linked list of **drops** of each variable -- these + /// are a special category of uses corresponding to the drop that + /// we add for each local variable. + first_drop_at: IndexVec>, + + appearances: IndexVec, +} + +struct Appearance { + point_index: PointIndex, + next: Option, +} + +rustc_index::newtype_index! { + pub struct AppearanceIndex { .. } +} + +impl vll::LinkElem for Appearance { + type LinkIndex = AppearanceIndex; + + fn next(elem: &Self) -> Option { + elem.next + } +} + +impl LocalUseMap { + crate fn build(live_locals: &[Local], elements: &RegionValueElements, body: &Body<'_>) -> Self { + let nones = IndexVec::from_elem_n(None, body.local_decls.len()); + let mut local_use_map = LocalUseMap { + first_def_at: nones.clone(), + first_use_at: nones.clone(), + first_drop_at: nones, + appearances: IndexVec::new(), + }; + + if live_locals.is_empty() { + return local_use_map; + } + + let mut locals_with_use_data: IndexVec = + IndexVec::from_elem_n(false, body.local_decls.len()); + live_locals.iter().for_each(|&local| locals_with_use_data[local] = true); + + LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data } + .visit_body(&body); + + local_use_map + } + + crate fn defs(&self, local: Local) -> impl Iterator + '_ { + vll::iter(self.first_def_at[local], &self.appearances) + .map(move |aa| self.appearances[aa].point_index) + } + + crate fn uses(&self, local: Local) -> impl Iterator + '_ { + vll::iter(self.first_use_at[local], &self.appearances) + .map(move |aa| self.appearances[aa].point_index) + } + + crate fn drops(&self, local: Local) -> impl Iterator + '_ { + vll::iter(self.first_drop_at[local], &self.appearances) + .map(move |aa| self.appearances[aa].point_index) + } +} + +struct LocalUseMapBuild<'me> { + local_use_map: &'me mut LocalUseMap, + elements: &'me RegionValueElements, + + // Vector used in `visit_local` to signal which `Local`s do we need + // def/use/drop information on, constructed from `live_locals` (that + // contains the variables we'll do the liveness analysis for). + // This vector serves optimization purposes only: we could have + // obtained the same information from `live_locals` but we want to + // avoid repeatedly calling `Vec::contains()` (see `LocalUseMap` for + // the rationale on the time-memory trade-off we're favoring here). + locals_with_use_data: IndexVec, +} + +impl LocalUseMapBuild<'_> { + fn insert_def(&mut self, local: Local, location: Location) { + Self::insert( + self.elements, + &mut self.local_use_map.first_def_at[local], + &mut self.local_use_map.appearances, + location, + ); + } + + fn insert_use(&mut self, local: Local, location: Location) { + Self::insert( + self.elements, + &mut self.local_use_map.first_use_at[local], + &mut self.local_use_map.appearances, + location, + ); + } + + fn insert_drop(&mut self, local: Local, location: Location) { + Self::insert( + self.elements, + &mut self.local_use_map.first_drop_at[local], + &mut self.local_use_map.appearances, + location, + ); + } + + fn insert( + elements: &RegionValueElements, + first_appearance: &mut Option, + appearances: &mut IndexVec, + location: Location, + ) { + let point_index = elements.point_from_location(location); + let appearance_index = + appearances.push(Appearance { point_index, next: *first_appearance }); + *first_appearance = Some(appearance_index); + } +} + +impl Visitor<'tcx> for LocalUseMapBuild<'_> { + fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { + if self.locals_with_use_data[local] { + match def_use::categorize(context) { + Some(DefUse::Def) => self.insert_def(local, location), + Some(DefUse::Use) => self.insert_use(local, location), + Some(DefUse::Drop) => self.insert_drop(local, location), + _ => (), + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,141 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_middle::mir::{Body, Local}; +use rustc_middle::ty::{RegionVid, TyCtxt}; +use std::rc::Rc; + +use rustc_mir_dataflow::impls::MaybeInitializedPlaces; +use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::ResultsCursor; + +use crate::{ + constraints::OutlivesConstraintSet, + facts::{AllFacts, AllFactsExt}, + location::LocationTable, + nll::ToRegionVid, + region_infer::values::RegionValueElements, + universal_regions::UniversalRegions, +}; + +use super::TypeChecker; + +mod local_use_map; +mod polonius; +mod trace; + +/// Combines liveness analysis with initialization analysis to +/// determine which variables are live at which points, both due to +/// ordinary uses and drops. Returns a set of (ty, location) pairs +/// that indicate which types must be live at which point in the CFG. +/// This vector is consumed by `constraint_generation`. +/// +/// N.B., this computation requires normalization; therefore, it must be +/// performed before +pub(super) fn generate<'mir, 'tcx>( + typeck: &mut TypeChecker<'_, 'tcx>, + body: &Body<'tcx>, + elements: &Rc, + flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + move_data: &MoveData<'tcx>, + location_table: &LocationTable, +) { + debug!("liveness::generate"); + + let free_regions = regions_that_outlive_free_regions( + typeck.infcx.num_region_vars(), + &typeck.borrowck_context.universal_regions, + &typeck.borrowck_context.constraints.outlives_constraints, + ); + let live_locals = compute_live_locals(typeck.tcx(), &free_regions, &body); + let facts_enabled = AllFacts::enabled(typeck.tcx()); + + let polonius_drop_used = if facts_enabled { + let mut drop_used = Vec::new(); + polonius::populate_access_facts(typeck, body, location_table, move_data, &mut drop_used); + Some(drop_used) + } else { + None + }; + + if !live_locals.is_empty() || facts_enabled { + trace::trace( + typeck, + body, + elements, + flow_inits, + move_data, + live_locals, + polonius_drop_used, + ); + } +} + +// The purpose of `compute_live_locals` is to define the subset of `Local` +// variables for which we need to do a liveness computation. We only need +// to compute whether a variable `X` is live if that variable contains +// some region `R` in its type where `R` is not known to outlive a free +// region (i.e., where `R` may be valid for just a subset of the fn body). +fn compute_live_locals( + tcx: TyCtxt<'tcx>, + free_regions: &FxHashSet, + body: &Body<'tcx>, +) -> Vec { + let live_locals: Vec = body + .local_decls + .iter_enumerated() + .filter_map(|(local, local_decl)| { + if tcx.all_free_regions_meet(&local_decl.ty, |r| { + free_regions.contains(&r.to_region_vid()) + }) { + None + } else { + Some(local) + } + }) + .collect(); + + debug!("{} total variables", body.local_decls.len()); + debug!("{} variables need liveness", live_locals.len()); + debug!("{} regions outlive free regions", free_regions.len()); + + live_locals +} + +/// Computes all regions that are (currently) known to outlive free +/// regions. For these regions, we do not need to compute +/// liveness, since the outlives constraints will ensure that they +/// are live over the whole fn body anyhow. +fn regions_that_outlive_free_regions( + num_region_vars: usize, + universal_regions: &UniversalRegions<'tcx>, + constraint_set: &OutlivesConstraintSet<'tcx>, +) -> FxHashSet { + // Build a graph of the outlives constraints thus far. This is + // a reverse graph, so for each constraint `R1: R2` we have an + // edge `R2 -> R1`. Therefore, if we find all regions + // reachable from each free region, we will have all the + // regions that are forced to outlive some free region. + let rev_constraint_graph = constraint_set.reverse_graph(num_region_vars); + let fr_static = universal_regions.fr_static; + let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static); + + // Stack for the depth-first search. Start out with all the free regions. + let mut stack: Vec<_> = universal_regions.universal_regions().collect(); + + // Set of all free regions, plus anything that outlives them. Initially + // just contains the free regions. + let mut outlives_free_region: FxHashSet<_> = stack.iter().cloned().collect(); + + // Do the DFS -- for each thing in the stack, find all things + // that outlive it and add them to the set. If they are not, + // push them onto the stack for later. + while let Some(sub_region) = stack.pop() { + stack.extend( + rev_region_graph + .outgoing_regions(sub_region) + .filter(|&r| outlives_free_region.insert(r)), + ); + } + + // Return the final set of things we visited. + outlives_free_region +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,140 @@ +use crate::def_use::{self, DefUse}; +use crate::location::{LocationIndex, LocationTable}; +use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location, Place}; +use rustc_middle::ty::subst::GenericArg; +use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; + +use super::TypeChecker; + +type VarPointRelation = Vec<(Local, LocationIndex)>; +type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>; + +struct UseFactsExtractor<'me> { + var_defined_at: &'me mut VarPointRelation, + var_used_at: &'me mut VarPointRelation, + location_table: &'me LocationTable, + var_dropped_at: &'me mut VarPointRelation, + move_data: &'me MoveData<'me>, + path_accessed_at_base: &'me mut PathPointRelation, +} + +// A Visitor to walk through the MIR and extract point-wise facts +impl UseFactsExtractor<'_> { + fn location_to_index(&self, location: Location) -> LocationIndex { + self.location_table.mid_index(location) + } + + fn insert_def(&mut self, local: Local, location: Location) { + debug!("UseFactsExtractor::insert_def()"); + self.var_defined_at.push((local, self.location_to_index(location))); + } + + fn insert_use(&mut self, local: Local, location: Location) { + debug!("UseFactsExtractor::insert_use()"); + self.var_used_at.push((local, self.location_to_index(location))); + } + + fn insert_drop_use(&mut self, local: Local, location: Location) { + debug!("UseFactsExtractor::insert_drop_use()"); + self.var_dropped_at.push((local, self.location_to_index(location))); + } + + fn insert_path_access(&mut self, path: MovePathIndex, location: Location) { + debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location); + self.path_accessed_at_base.push((path, self.location_to_index(location))); + } + + fn place_to_mpi(&self, place: &Place<'_>) -> Option { + match self.move_data.rev_lookup.find(place.as_ref()) { + LookupResult::Exact(mpi) => Some(mpi), + LookupResult::Parent(mmpi) => mmpi, + } + } +} + +impl Visitor<'tcx> for UseFactsExtractor<'_> { + fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { + match def_use::categorize(context) { + Some(DefUse::Def) => self.insert_def(local, location), + Some(DefUse::Use) => self.insert_use(local, location), + Some(DefUse::Drop) => self.insert_drop_use(local, location), + _ => (), + } + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + self.super_place(place, context, location); + match context { + PlaceContext::NonMutatingUse(_) => { + if let Some(mpi) = self.place_to_mpi(place) { + self.insert_path_access(mpi, location); + } + } + + PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { + if let Some(mpi) = self.place_to_mpi(place) { + self.insert_path_access(mpi, location); + } + } + _ => (), + } + } +} + +pub(super) fn populate_access_facts( + typeck: &mut TypeChecker<'_, 'tcx>, + body: &Body<'tcx>, + location_table: &LocationTable, + move_data: &MoveData<'_>, + dropped_at: &mut Vec<(Local, Location)>, +) { + debug!("populate_access_facts()"); + + if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { + let mut extractor = UseFactsExtractor { + var_defined_at: &mut facts.var_defined_at, + var_used_at: &mut facts.var_used_at, + var_dropped_at: &mut facts.var_dropped_at, + path_accessed_at_base: &mut facts.path_accessed_at_base, + location_table, + move_data, + }; + extractor.visit_body(&body); + + facts.var_dropped_at.extend( + dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))), + ); + + for (local, local_decl) in body.local_decls.iter_enumerated() { + debug!( + "add use_of_var_derefs_origin facts - local={:?}, type={:?}", + local, local_decl.ty + ); + let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); + let universal_regions = &typeck.borrowck_context.universal_regions; + typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| { + let region_vid = universal_regions.to_region_vid(region); + facts.use_of_var_derefs_origin.push((local, region_vid)); + }); + } + } +} + +// For every potentially drop()-touched region `region` in `local`'s type +// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact. +pub(super) fn add_drop_of_var_derefs_origin( + typeck: &mut TypeChecker<'_, 'tcx>, + local: Local, + kind: &GenericArg<'tcx>, +) { + debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind); + if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { + let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); + let universal_regions = &typeck.borrowck_context.universal_regions; + typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| { + let region_vid = universal_regions.to_region_vid(drop_live_region); + facts.drop_of_var_derefs_origin.push((local, region_vid)); + }); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/trace.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/trace.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/trace.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/liveness/trace.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,526 @@ +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_index::bit_set::HybridBitSet; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; +use rustc_middle::ty::{Ty, TypeFoldable}; +use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; +use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; +use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; +use std::rc::Rc; + +use rustc_mir_dataflow::impls::MaybeInitializedPlaces; +use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; +use rustc_mir_dataflow::ResultsCursor; + +use crate::{ + region_infer::values::{self, PointIndex, RegionValueElements}, + type_check::liveness::local_use_map::LocalUseMap, + type_check::liveness::polonius, + type_check::NormalizeLocation, + type_check::TypeChecker, +}; + +/// This is the heart of the liveness computation. For each variable X +/// that requires a liveness computation, it walks over all the uses +/// of X and does a reverse depth-first search ("trace") through the +/// MIR. This search stops when we find a definition of that variable. +/// The points visited in this search is the USE-LIVE set for the variable; +/// of those points is added to all the regions that appear in the variable's +/// type. +/// +/// We then also walks through each *drop* of those variables and does +/// another search, stopping when we reach a use or definition. This +/// is the DROP-LIVE set of points. Each of the points in the +/// DROP-LIVE set are to the liveness sets for regions found in the +/// `dropck_outlives` result of the variable's type (in particular, +/// this respects `#[may_dangle]` annotations). +pub(super) fn trace( + typeck: &mut TypeChecker<'_, 'tcx>, + body: &Body<'tcx>, + elements: &Rc, + flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + move_data: &MoveData<'tcx>, + live_locals: Vec, + polonius_drop_used: Option>, +) { + debug!("trace()"); + + let local_use_map = &LocalUseMap::build(&live_locals, elements, body); + + let cx = LivenessContext { + typeck, + body, + flow_inits, + elements, + local_use_map, + move_data, + drop_data: FxHashMap::default(), + }; + + let mut results = LivenessResults::new(cx); + + if let Some(drop_used) = polonius_drop_used { + results.add_extra_drop_facts(drop_used, live_locals.iter().copied().collect()) + } + + results.compute_for_all_locals(live_locals); +} + +/// Contextual state for the type-liveness generator. +struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { + /// Current type-checker, giving us our inference context etc. + typeck: &'me mut TypeChecker<'typeck, 'tcx>, + + /// Defines the `PointIndex` mapping + elements: &'me RegionValueElements, + + /// MIR we are analyzing. + body: &'me Body<'tcx>, + + /// Mapping to/from the various indices used for initialization tracking. + move_data: &'me MoveData<'tcx>, + + /// Cache for the results of `dropck_outlives` query. + drop_data: FxHashMap, DropData<'tcx>>, + + /// Results of dataflow tracking which variables (and paths) have been + /// initialized. + flow_inits: &'me mut ResultsCursor<'flow, 'tcx, MaybeInitializedPlaces<'flow, 'tcx>>, + + /// Index indicating where each variable is assigned, used, or + /// dropped. + local_use_map: &'me LocalUseMap, +} + +struct DropData<'tcx> { + dropck_result: DropckOutlivesResult<'tcx>, + region_constraint_data: Option>>, +} + +struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { + cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>, + + /// Set of points that define the current local. + defs: HybridBitSet, + + /// Points where the current variable is "use live" -- meaning + /// that there is a future "full use" that may use its value. + use_live_at: HybridBitSet, + + /// Points where the current variable is "drop live" -- meaning + /// that there is no future "full use" that may use its value, but + /// there is a future drop. + drop_live_at: HybridBitSet, + + /// Locations where drops may occur. + drop_locations: Vec, + + /// Stack used when doing (reverse) DFS. + stack: Vec, +} + +impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { + fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self { + let num_points = cx.elements.num_points(); + LivenessResults { + cx, + defs: HybridBitSet::new_empty(num_points), + use_live_at: HybridBitSet::new_empty(num_points), + drop_live_at: HybridBitSet::new_empty(num_points), + drop_locations: vec![], + stack: vec![], + } + } + + fn compute_for_all_locals(&mut self, live_locals: Vec) { + for local in live_locals { + self.reset_local_state(); + self.add_defs_for(local); + self.compute_use_live_points_for(local); + self.compute_drop_live_points_for(local); + + let local_ty = self.cx.body.local_decls[local].ty; + + if !self.use_live_at.is_empty() { + self.cx.add_use_live_facts_for(local_ty, &self.use_live_at); + } + + if !self.drop_live_at.is_empty() { + self.cx.add_drop_live_facts_for( + local, + local_ty, + &self.drop_locations, + &self.drop_live_at, + ); + } + } + } + + /// Add extra drop facts needed for Polonius. + /// + /// Add facts for all locals with free regions, since regions may outlive + /// the function body only at certain nodes in the CFG. + fn add_extra_drop_facts( + &mut self, + drop_used: Vec<(Local, Location)>, + live_locals: FxHashSet, + ) { + let locations = HybridBitSet::new_empty(self.cx.elements.num_points()); + + for (local, location) in drop_used { + if !live_locals.contains(&local) { + let local_ty = self.cx.body.local_decls[local].ty; + if local_ty.has_free_regions(self.cx.typeck.tcx()) { + self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); + } + } + } + } + + /// Clear the value of fields that are "per local variable". + fn reset_local_state(&mut self) { + self.defs.clear(); + self.use_live_at.clear(); + self.drop_live_at.clear(); + self.drop_locations.clear(); + assert!(self.stack.is_empty()); + } + + /// Adds the definitions of `local` into `self.defs`. + fn add_defs_for(&mut self, local: Local) { + for def in self.cx.local_use_map.defs(local) { + debug!("- defined at {:?}", def); + self.defs.insert(def); + } + } + + /// Computes all points where local is "use live" -- meaning its + /// current value may be used later (except by a drop). This is + /// done by walking backwards from each use of `local` until we + /// find a `def` of local. + /// + /// Requires `add_defs_for(local)` to have been executed. + fn compute_use_live_points_for(&mut self, local: Local) { + debug!("compute_use_live_points_for(local={:?})", local); + + self.stack.extend(self.cx.local_use_map.uses(local)); + while let Some(p) = self.stack.pop() { + if self.defs.contains(p) { + continue; + } + + if self.use_live_at.insert(p) { + self.cx.elements.push_predecessors(self.cx.body, p, &mut self.stack) + } + } + } + + /// Computes all points where local is "drop live" -- meaning its + /// current value may be dropped later (but not used). This is + /// done by iterating over the drops of `local` where `local` (or + /// some subpart of `local`) is initialized. For each such drop, + /// we walk backwards until we find a point where `local` is + /// either defined or use-live. + /// + /// Requires `compute_use_live_points_for` and `add_defs_for` to + /// have been executed. + fn compute_drop_live_points_for(&mut self, local: Local) { + debug!("compute_drop_live_points_for(local={:?})", local); + + let mpi = self.cx.move_data.rev_lookup.find_local(local); + debug!("compute_drop_live_points_for: mpi = {:?}", mpi); + + // Find the drops where `local` is initialized. + for drop_point in self.cx.local_use_map.drops(local) { + let location = self.cx.elements.to_location(drop_point); + debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); + + if self.cx.initialized_at_terminator(location.block, mpi) { + if self.drop_live_at.insert(drop_point) { + self.drop_locations.push(location); + self.stack.push(drop_point); + } + } + } + + debug!("compute_drop_live_points_for: drop_locations={:?}", self.drop_locations); + + // Reverse DFS. But for drops, we do it a bit differently. + // The stack only ever stores *terminators of blocks*. Within + // a block, we walk back the statements in an inner loop. + while let Some(term_point) = self.stack.pop() { + self.compute_drop_live_points_for_block(mpi, term_point); + } + } + + /// Executes one iteration of the drop-live analysis loop. + /// + /// The parameter `mpi` is the `MovePathIndex` of the local variable + /// we are currently analyzing. + /// + /// The point `term_point` represents some terminator in the MIR, + /// where the local `mpi` is drop-live on entry to that terminator. + /// + /// This method adds all drop-live points within the block and -- + /// where applicable -- pushes the terminators of preceding blocks + /// onto `self.stack`. + fn compute_drop_live_points_for_block(&mut self, mpi: MovePathIndex, term_point: PointIndex) { + debug!( + "compute_drop_live_points_for_block(mpi={:?}, term_point={:?})", + self.cx.move_data.move_paths[mpi].place, + self.cx.elements.to_location(term_point), + ); + + // We are only invoked with terminators where `mpi` is + // drop-live on entry. + debug_assert!(self.drop_live_at.contains(term_point)); + + // Otherwise, scan backwards through the statements in the + // block. One of them may be either a definition or use + // live point. + let term_location = self.cx.elements.to_location(term_point); + debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,); + let block = term_location.block; + let entry_point = self.cx.elements.entry_point(term_location.block); + for p in (entry_point..term_point).rev() { + debug!("compute_drop_live_points_for_block: p = {:?}", self.cx.elements.to_location(p)); + + if self.defs.contains(p) { + debug!("compute_drop_live_points_for_block: def site"); + return; + } + + if self.use_live_at.contains(p) { + debug!("compute_drop_live_points_for_block: use-live at {:?}", p); + return; + } + + if !self.drop_live_at.insert(p) { + debug!("compute_drop_live_points_for_block: already drop-live"); + return; + } + } + + let body = self.cx.body; + for &pred_block in body.predecessors()[block].iter() { + debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,); + + // Check whether the variable is (at least partially) + // initialized at the exit of this predecessor. If so, we + // want to enqueue it on our list. If not, go check the + // next block. + // + // Note that we only need to check whether `live_local` + // became de-initialized at basic block boundaries. If it + // were to become de-initialized within the block, that + // would have been a "use-live" transition in the earlier + // loop, and we'd have returned already. + // + // NB. It's possible that the pred-block ends in a call + // which stores to the variable; in that case, the + // variable may be uninitialized "at exit" because this + // call only considers the *unconditional effects* of the + // terminator. *But*, in that case, the terminator is also + // a *definition* of the variable, in which case we want + // to stop the search anyhow. (But see Note 1 below.) + if !self.cx.initialized_at_exit(pred_block, mpi) { + debug!("compute_drop_live_points_for_block: not initialized"); + continue; + } + + let pred_term_loc = self.cx.body.terminator_loc(pred_block); + let pred_term_point = self.cx.elements.point_from_location(pred_term_loc); + + // If the terminator of this predecessor either *assigns* + // our value or is a "normal use", then stop. + if self.defs.contains(pred_term_point) { + debug!("compute_drop_live_points_for_block: defined at {:?}", pred_term_loc); + continue; + } + + if self.use_live_at.contains(pred_term_point) { + debug!("compute_drop_live_points_for_block: use-live at {:?}", pred_term_loc); + continue; + } + + // Otherwise, we are drop-live on entry to the terminator, + // so walk it. + if self.drop_live_at.insert(pred_term_point) { + debug!("compute_drop_live_points_for_block: pushed to stack"); + self.stack.push(pred_term_point); + } + } + + // Note 1. There is a weird scenario that you might imagine + // being problematic here, but which actually cannot happen. + // The problem would be if we had a variable that *is* initialized + // (but dead) on entry to the terminator, and where the current value + // will be dropped in the case of unwind. In that case, we ought to + // consider `X` to be drop-live in between the last use and call. + // Here is the example: + // + // ``` + // BB0 { + // X = ... + // use(X); // last use + // ... // <-- X ought to be drop-live here + // X = call() goto BB1 unwind BB2 + // } + // + // BB1 { + // DROP(X) + // } + // + // BB2 { + // DROP(X) + // } + // ``` + // + // However, the current code would, when walking back from BB2, + // simply stop and never explore BB0. This seems bad! But it turns + // out this code is flawed anyway -- note that the existing value of + // `X` would leak in the case where unwinding did *not* occur. + // + // What we *actually* generate is a store to a temporary + // for the call (`TMP = call()...`) and then a + // `DropAndReplace` to swap that with `X` + // (`DropAndReplace` has very particular semantics). + } +} + +impl LivenessContext<'_, '_, '_, 'tcx> { + /// Returns `true` if the local variable (or some part of it) is initialized at the current + /// cursor position. Callers should call one of the `seek` methods immediately before to point + /// the cursor to the desired location. + fn initialized_at_curr_loc(&self, mpi: MovePathIndex) -> bool { + let state = self.flow_inits.get(); + if state.contains(mpi) { + return true; + } + + let move_paths = &self.flow_inits.analysis().move_data().move_paths; + move_paths[mpi].find_descendant(&move_paths, |mpi| state.contains(mpi)).is_some() + } + + /// Returns `true` if the local variable (or some part of it) is initialized in + /// the terminator of `block`. We need to check this to determine if a + /// DROP of some local variable will have an effect -- note that + /// drops, as they may unwind, are always terminators. + fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { + self.flow_inits.seek_before_primary_effect(self.body.terminator_loc(block)); + self.initialized_at_curr_loc(mpi) + } + + /// Returns `true` if the path `mpi` (or some part of it) is initialized at + /// the exit of `block`. + /// + /// **Warning:** Does not account for the result of `Call` + /// instructions. + fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { + self.flow_inits.seek_after_primary_effect(self.body.terminator_loc(block)); + self.initialized_at_curr_loc(mpi) + } + + /// Stores the result that all regions in `value` are live for the + /// points `live_at`. + fn add_use_live_facts_for( + &mut self, + value: impl TypeFoldable<'tcx>, + live_at: &HybridBitSet, + ) { + debug!("add_use_live_facts_for(value={:?})", value); + + Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at) + } + + /// Some variable with type `live_ty` is "drop live" at `location` + /// -- i.e., it may be dropped later. This means that *some* of + /// the regions in its type must be live at `location`. The + /// precise set will depend on the dropck constraints, and in + /// particular this takes `#[may_dangle]` into account. + fn add_drop_live_facts_for( + &mut self, + dropped_local: Local, + dropped_ty: Ty<'tcx>, + drop_locations: &[Location], + live_at: &HybridBitSet, + ) { + debug!( + "add_drop_live_constraint(\ + dropped_local={:?}, \ + dropped_ty={:?}, \ + drop_locations={:?}, \ + live_at={:?})", + dropped_local, + dropped_ty, + drop_locations, + values::location_set_str(self.elements, live_at.iter()), + ); + + let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({ + let typeck = &mut self.typeck; + move || Self::compute_drop_data(typeck, dropped_ty) + }); + + if let Some(data) = &drop_data.region_constraint_data { + for &drop_location in drop_locations { + self.typeck.push_region_constraints( + drop_location.to_locations(), + ConstraintCategory::Boring, + data, + ); + } + } + + drop_data.dropck_result.report_overflows( + self.typeck.infcx.tcx, + self.body.source_info(*drop_locations.first().unwrap()).span, + dropped_ty, + ); + + // All things in the `outlives` array may be touched by + // the destructor and must be live at this point. + for &kind in &drop_data.dropck_result.kinds { + Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at); + + polonius::add_drop_of_var_derefs_origin(&mut self.typeck, dropped_local, &kind); + } + } + + fn make_all_regions_live( + elements: &RegionValueElements, + typeck: &mut TypeChecker<'_, 'tcx>, + value: impl TypeFoldable<'tcx>, + live_at: &HybridBitSet, + ) { + debug!("make_all_regions_live(value={:?})", value); + debug!( + "make_all_regions_live: live_at={}", + values::location_set_str(elements, live_at.iter()), + ); + + let tcx = typeck.tcx(); + tcx.for_each_free_region(&value, |live_region| { + let live_region_vid = + typeck.borrowck_context.universal_regions.to_region_vid(live_region); + typeck + .borrowck_context + .constraints + .liveness_constraints + .add_elements(live_region_vid, live_at); + }); + } + + fn compute_drop_data( + typeck: &mut TypeChecker<'_, 'tcx>, + dropped_ty: Ty<'tcx>, + ) -> DropData<'tcx> { + debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); + + let param_env = typeck.param_env; + let TypeOpOutput { output, constraints, .. } = + param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap(); + + DropData { dropck_result: output, region_constraint_data: constraints } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,2730 @@ +//! This pass type-checks the MIR to ensure it is not broken. + +use std::rc::Rc; +use std::{fmt, iter, mem}; + +use either::Either; + +use rustc_data_structures::frozen::Frozen; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::vec_map::VecMap; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::lang_items::LangItem; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; +use rustc_infer::infer::outlives::env::RegionBoundPairs; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{ + InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin, +}; +use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::AssertKind; +use rustc_middle::mir::*; +use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::cast::CastTy; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; +use rustc_middle::ty::{ + self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, + ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, +}; +use rustc_span::def_id::CRATE_DEF_ID; +use rustc_span::{Span, DUMMY_SP}; +use rustc_target::abi::VariantIdx; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt}; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::query::type_op; +use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; +use rustc_trait_selection::traits::query::Fallible; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}; + +use rustc_const_eval::transform::{ + check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression, +}; +use rustc_mir_dataflow::impls::MaybeInitializedPlaces; +use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::ResultsCursor; + +use crate::{ + borrow_set::BorrowSet, + constraints::{OutlivesConstraint, OutlivesConstraintSet}, + diagnostics::UniverseInfo, + facts::AllFacts, + location::LocationTable, + member_constraints::MemberConstraintSet, + nll::ToRegionVid, + path_utils, + region_infer::values::{ + LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, + }, + region_infer::{ClosureRegionRequirementsExt, TypeTest}, + type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, + universal_regions::{DefiningTy, UniversalRegions}, + Upvar, +}; + +macro_rules! span_mirbug { + ($context:expr, $elem:expr, $($message:tt)*) => ({ + $crate::type_check::mirbug( + $context.tcx(), + $context.last_span, + &format!( + "broken MIR in {:?} ({:?}): {}", + $context.body.source.def_id(), + $elem, + format_args!($($message)*), + ), + ) + }) +} + +macro_rules! span_mirbug_and_err { + ($context:expr, $elem:expr, $($message:tt)*) => ({ + { + span_mirbug!($context, $elem, $($message)*); + $context.error() + } + }) +} + +mod canonical; +mod constraint_conversion; +pub mod free_region_relations; +mod input_output; +crate mod liveness; +mod relate_tys; + +/// Type checks the given `mir` in the context of the inference +/// context `infcx`. Returns any region constraints that have yet to +/// be proven. This result includes liveness constraints that +/// ensure that regions appearing in the types of all local variables +/// are live at all points where that local variable may later be +/// used. +/// +/// This phase of type-check ought to be infallible -- this is because +/// the original, HIR-based type-check succeeded. So if any errors +/// occur here, we will get a `bug!` reported. +/// +/// # Parameters +/// +/// - `infcx` -- inference context to use +/// - `param_env` -- parameter environment to use for trait solving +/// - `body` -- MIR body to type-check +/// - `promoted` -- map of promoted constants within `body` +/// - `universal_regions` -- the universal regions from `body`s function signature +/// - `location_table` -- MIR location map of `body` +/// - `borrow_set` -- information about borrows occurring in `body` +/// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts +/// - `flow_inits` -- results of a maybe-init dataflow analysis +/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis +/// - `elements` -- MIR region map +pub(crate) fn type_check<'mir, 'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body: &Body<'tcx>, + promoted: &IndexVec>, + universal_regions: &Rc>, + location_table: &LocationTable, + borrow_set: &BorrowSet<'tcx>, + all_facts: &mut Option, + flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + move_data: &MoveData<'tcx>, + elements: &Rc, + upvars: &[Upvar<'tcx>], +) -> MirTypeckResults<'tcx> { + let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); + let mut universe_causes = FxHashMap::default(); + universe_causes.insert(ty::UniverseIndex::from_u32(0), UniverseInfo::other()); + let mut constraints = MirTypeckRegionConstraints { + placeholder_indices: PlaceholderIndices::default(), + placeholder_index_to_region: IndexVec::default(), + liveness_constraints: LivenessValues::new(elements.clone()), + outlives_constraints: OutlivesConstraintSet::default(), + member_constraints: MemberConstraintSet::default(), + closure_bounds_mapping: Default::default(), + type_tests: Vec::default(), + universe_causes, + }; + + let CreateResult { + universal_region_relations, + region_bound_pairs, + normalized_inputs_and_output, + } = free_region_relations::create( + infcx, + param_env, + Some(implicit_region_bound), + universal_regions, + &mut constraints, + ); + + for u in ty::UniverseIndex::ROOT..infcx.universe() { + let info = UniverseInfo::other(); + constraints.universe_causes.insert(u, info); + } + + let mut borrowck_context = BorrowCheckContext { + universal_regions, + location_table, + borrow_set, + all_facts, + constraints: &mut constraints, + upvars, + }; + + let opaque_type_values = type_check_internal( + infcx, + param_env, + body, + promoted, + ®ion_bound_pairs, + implicit_region_bound, + &mut borrowck_context, + &universal_region_relations, + |mut cx| { + cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); + liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); + + translate_outlives_facts(&mut cx); + let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types); + + opaque_type_values + .into_iter() + .filter_map(|(opaque_type_key, mut decl)| { + decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); + trace!( + "finalized opaque type {:?} to {:#?}", + opaque_type_key, + decl.concrete_ty.kind() + ); + if decl.concrete_ty.has_infer_types_or_consts() { + infcx.tcx.sess.delay_span_bug( + body.span, + &format!("could not resolve {:#?}", decl.concrete_ty.kind()), + ); + decl.concrete_ty = infcx.tcx.ty_error(); + } + let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind() + { + *def_id == opaque_type_key.def_id + } else { + false + }; + + if concrete_is_opaque { + // We're using an opaque `impl Trait` type without + // 'revealing' it. For example, code like this: + // + // type Foo = impl Debug; + // fn foo1() -> Foo { ... } + // fn foo2() -> Foo { foo1() } + // + // In `foo2`, we're not revealing the type of `Foo` - we're + // just treating it as the opaque type. + // + // When this occurs, we do *not* want to try to equate + // the concrete type with the underlying defining type + // of the opaque type - this will always fail, since + // the defining type of an opaque type is always + // some other type (e.g. not itself) + // Essentially, none of the normal obligations apply here - + // we're just passing around some unknown opaque type, + // without actually looking at the underlying type it + // gets 'revealed' into + debug!( + "eq_opaque_type_and_type: non-defining use of {:?}", + opaque_type_key.def_id, + ); + None + } else { + Some((opaque_type_key, decl)) + } + }) + .collect() + }, + ); + + MirTypeckResults { constraints, universal_region_relations, opaque_type_values } +} + +#[instrument( + skip( + infcx, + body, + promoted, + region_bound_pairs, + borrowck_context, + universal_region_relations, + extra + ), + level = "debug" +)] +fn type_check_internal<'a, 'tcx, R>( + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body: &'a Body<'tcx>, + promoted: &'a IndexVec>, + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + implicit_region_bound: ty::Region<'tcx>, + borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, + universal_region_relations: &'a UniversalRegionRelations<'tcx>, + extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, +) -> R { + let mut checker = TypeChecker::new( + infcx, + body, + param_env, + region_bound_pairs, + implicit_region_bound, + borrowck_context, + universal_region_relations, + ); + let errors_reported = { + let mut verifier = TypeVerifier::new(&mut checker, body, promoted); + verifier.visit_body(&body); + verifier.errors_reported + }; + + if !errors_reported { + // if verifier failed, don't do further checks to avoid ICEs + checker.typeck_mir(body); + } + + extra(checker) +} + +fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { + let cx = &mut typeck.borrowck_context; + if let Some(facts) = cx.all_facts { + let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); + let location_table = cx.location_table; + facts.subset_base.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map( + |constraint: &OutlivesConstraint<'_>| { + if let Some(from_location) = constraint.locations.from_location() { + Either::Left(iter::once(( + constraint.sup, + constraint.sub, + location_table.mid_index(from_location), + ))) + } else { + Either::Right( + location_table + .all_points() + .map(move |location| (constraint.sup, constraint.sub, location)), + ) + } + }, + )); + } +} + +fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) { + // We sometimes see MIR failures (notably predicate failures) due to + // the fact that we check rvalue sized predicates here. So use `delay_span_bug` + // to avoid reporting bugs in those cases. + tcx.sess.diagnostic().delay_span_bug(span, msg); +} + +enum FieldAccessError { + OutOfRange { field_count: usize }, +} + +/// Verifies that MIR types are sane to not crash further checks. +/// +/// The sanitize_XYZ methods here take an MIR object and compute its +/// type, calling `span_mirbug` and returning an error type if there +/// is a problem. +struct TypeVerifier<'a, 'b, 'tcx> { + cx: &'a mut TypeChecker<'b, 'tcx>, + body: &'b Body<'tcx>, + promoted: &'b IndexVec>, + last_span: Span, + errors_reported: bool, +} + +impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { + fn visit_span(&mut self, span: &Span) { + if !span.is_dummy() { + self.last_span = *span; + } + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + self.sanitize_place(place, location, context); + } + + fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + self.super_constant(constant, location); + let ty = self.sanitize_type(constant, constant.literal.ty()); + + self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { + let live_region_vid = + self.cx.borrowck_context.universal_regions.to_region_vid(live_region); + self.cx + .borrowck_context + .constraints + .liveness_constraints + .add_element(live_region_vid, location); + }); + + if let Some(annotation_index) = constant.user_ty { + if let Err(terr) = self.cx.relate_type_and_user_type( + constant.literal.ty(), + ty::Variance::Invariant, + &UserTypeProjection { base: annotation_index, projs: vec![] }, + location.to_locations(), + ConstraintCategory::Boring, + ) { + let annotation = &self.cx.user_type_annotations[annotation_index]; + span_mirbug!( + self, + constant, + "bad constant user type {:?} vs {:?}: {:?}", + annotation, + constant.literal.ty(), + terr, + ); + } + } else { + let tcx = self.tcx(); + let maybe_uneval = match constant.literal { + ConstantKind::Ty(ct) => match ct.val { + ty::ConstKind::Unevaluated(uv) => Some(uv), + _ => None, + }, + _ => None, + }; + if let Some(uv) = maybe_uneval { + if let Some(promoted) = uv.promoted { + let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, + promoted: &Body<'tcx>, + ty, + san_ty| { + if let Err(terr) = verifier.cx.eq_types( + ty, + san_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + verifier, + promoted, + "bad promoted type ({:?}: {:?}): {:?}", + ty, + san_ty, + terr + ); + }; + }; + + if !self.errors_reported { + let promoted_body = &self.promoted[promoted]; + self.sanitize_promoted(promoted_body, location); + + let promoted_ty = promoted_body.return_ty(); + check_err(self, promoted_body, ty, promoted_ty); + } + } else { + if let Err(terr) = self.cx.fully_perform_op( + location.to_locations(), + ConstraintCategory::Boring, + self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( + constant.literal.ty(), + uv.def.did, + UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None }, + )), + ) { + span_mirbug!( + self, + constant, + "bad constant type {:?} ({:?})", + constant, + terr + ); + } + } + } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { + let unnormalized_ty = tcx.type_of(static_def_id); + let locations = location.to_locations(); + let normalized_ty = self.cx.normalize(unnormalized_ty, locations); + let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; + + if let Err(terr) = self.cx.eq_types( + literal_ty, + normalized_ty, + locations, + ConstraintCategory::Boring, + ) { + span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); + } + } + + if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); + self.cx.normalize_and_prove_instantiated_predicates( + def_id, + instantiated_predicates, + location.to_locations(), + ); + } + } + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + let rval_ty = rvalue.ty(self.body, self.tcx()); + self.sanitize_type(rvalue, rval_ty); + } + + fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { + self.super_local_decl(local, local_decl); + self.sanitize_type(local_decl, local_decl.ty); + + if let Some(user_ty) = &local_decl.user_ty { + for (user_ty, span) in user_ty.projections_and_spans() { + let ty = if !local_decl.is_nonref_binding() { + // If we have a binding of the form `let ref x: T = ..` + // then remove the outermost reference so we can check the + // type annotation for the remaining type. + if let ty::Ref(_, rty, _) = local_decl.ty.kind() { + rty + } else { + bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); + } + } else { + local_decl.ty + }; + + if let Err(terr) = self.cx.relate_type_and_user_type( + ty, + ty::Variance::Invariant, + user_ty, + Locations::All(*span), + ConstraintCategory::TypeAnnotation, + ) { + span_mirbug!( + self, + local, + "bad user type on variable {:?}: {:?} != {:?} ({:?})", + local, + local_decl.ty, + local_decl.user_ty, + terr, + ); + } + } + } + } + + fn visit_body(&mut self, body: &Body<'tcx>) { + self.sanitize_type(&"return type", body.return_ty()); + for local_decl in &body.local_decls { + self.sanitize_type(local_decl, local_decl.ty); + } + if self.errors_reported { + return; + } + self.super_body(body); + } +} + +impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { + fn new( + cx: &'a mut TypeChecker<'b, 'tcx>, + body: &'b Body<'tcx>, + promoted: &'b IndexVec>, + ) -> Self { + TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false } + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.cx.infcx.tcx + } + + fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.has_escaping_bound_vars() || ty.references_error() { + span_mirbug_and_err!(self, parent, "bad type {:?}", ty) + } else { + ty + } + } + + /// Checks that the types internal to the `place` match up with + /// what would be expected. + fn sanitize_place( + &mut self, + place: &Place<'tcx>, + location: Location, + context: PlaceContext, + ) -> PlaceTy<'tcx> { + debug!("sanitize_place: {:?}", place); + + let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); + + for elem in place.projection.iter() { + if place_ty.variant_index.is_none() { + if place_ty.ty.references_error() { + assert!(self.errors_reported); + return PlaceTy::from_ty(self.tcx().ty_error()); + } + } + place_ty = self.sanitize_projection(place_ty, elem, place, location); + } + + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { + let tcx = self.tcx(); + let trait_ref = ty::TraitRef { + def_id: tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), + substs: tcx.mk_substs_trait(place_ty.ty, &[]), + }; + + // To have a `Copy` operand, the type `T` of the + // value must be `Copy`. Note that we prove that `T: Copy`, + // rather than using the `is_copy_modulo_regions` + // test. This is important because + // `is_copy_modulo_regions` ignores the resulting region + // obligations and assumes they pass. This can result in + // bounds from `Copy` impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use `Copy` before knowing + // whether the bounds fully apply: in effect, the rule is + // that if a value of some type could implement `Copy`, then + // it must. + self.cx.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::CopyBound, + ); + } + + place_ty + } + + fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { + // Determine the constraints from the promoted MIR by running the type + // checker on the promoted MIR, then transfer the constraints back to + // the main MIR, changing the locations to the provided location. + + let parent_body = mem::replace(&mut self.body, promoted_body); + + // Use new sets of constraints and closure bounds so that we can + // modify their locations. + let all_facts = &mut None; + let mut constraints = Default::default(); + let mut closure_bounds = Default::default(); + let mut liveness_constraints = + LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body))); + // Don't try to add borrow_region facts for the promoted MIR + + let mut swap_constraints = |this: &mut Self| { + mem::swap(this.cx.borrowck_context.all_facts, all_facts); + mem::swap( + &mut this.cx.borrowck_context.constraints.outlives_constraints, + &mut constraints, + ); + mem::swap( + &mut this.cx.borrowck_context.constraints.closure_bounds_mapping, + &mut closure_bounds, + ); + mem::swap( + &mut this.cx.borrowck_context.constraints.liveness_constraints, + &mut liveness_constraints, + ); + }; + + swap_constraints(self); + + self.visit_body(&promoted_body); + + if !self.errors_reported { + // if verifier failed, don't do further checks to avoid ICEs + self.cx.typeck_mir(promoted_body); + } + + self.body = parent_body; + // Merge the outlives constraints back in, at the given location. + swap_constraints(self); + + let locations = location.to_locations(); + for constraint in constraints.outlives().iter() { + let mut constraint = constraint.clone(); + constraint.locations = locations; + if let ConstraintCategory::Return(_) + | ConstraintCategory::UseAsConst + | ConstraintCategory::UseAsStatic = constraint.category + { + // "Returning" from a promoted is an assignment to a + // temporary from the user's point of view. + constraint.category = ConstraintCategory::Boring; + } + self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) + } + for region in liveness_constraints.rows() { + // If the region is live at at least one location in the promoted MIR, + // then add a liveness constraint to the main MIR for this region + // at the location provided as an argument to this method + if let Some(_) = liveness_constraints.get_elements(region).next() { + self.cx + .borrowck_context + .constraints + .liveness_constraints + .add_element(region, location); + } + } + + if !closure_bounds.is_empty() { + let combined_bounds_mapping = + closure_bounds.into_iter().flat_map(|(_, value)| value).collect(); + let existing = self + .cx + .borrowck_context + .constraints + .closure_bounds_mapping + .insert(location, combined_bounds_mapping); + assert!(existing.is_none(), "Multiple promoteds/closures at the same location."); + } + } + + fn sanitize_projection( + &mut self, + base: PlaceTy<'tcx>, + pi: PlaceElem<'tcx>, + place: &Place<'tcx>, + location: Location, + ) -> PlaceTy<'tcx> { + debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); + let tcx = self.tcx(); + let base_ty = base.ty; + match pi { + ProjectionElem::Deref => { + let deref_ty = base_ty.builtin_deref(true); + PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| { + span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) + })) + } + ProjectionElem::Index(i) => { + let index_ty = Place::from(i).ty(self.body, tcx).ty; + if index_ty != tcx.types.usize { + PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)) + } else { + PlaceTy::from_ty(base_ty.builtin_index().unwrap_or_else(|| { + span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) + })) + } + } + ProjectionElem::ConstantIndex { .. } => { + // consider verifying in-bounds + PlaceTy::from_ty(base_ty.builtin_index().unwrap_or_else(|| { + span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) + })) + } + ProjectionElem::Subslice { from, to, from_end } => { + PlaceTy::from_ty(match base_ty.kind() { + ty::Array(inner, _) => { + assert!(!from_end, "array subslices should not use from_end"); + tcx.mk_array(inner, to - from) + } + ty::Slice(..) => { + assert!(from_end, "slice subslices should use from_end"); + base_ty + } + _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), + }) + } + ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind() { + ty::Adt(adt_def, _substs) if adt_def.is_enum() => { + if index.as_usize() >= adt_def.variants.len() { + PlaceTy::from_ty(span_mirbug_and_err!( + self, + place, + "cast to variant #{:?} but enum only has {:?}", + index, + adt_def.variants.len() + )) + } else { + PlaceTy { ty: base_ty, variant_index: Some(index) } + } + } + // We do not need to handle generators here, because this runs + // before the generator transform stage. + _ => { + let ty = if let Some(name) = maybe_name { + span_mirbug_and_err!( + self, + place, + "can't downcast {:?} as {:?}", + base_ty, + name + ) + } else { + span_mirbug_and_err!(self, place, "can't downcast {:?}", base_ty) + }; + PlaceTy::from_ty(ty) + } + }, + ProjectionElem::Field(field, fty) => { + let fty = self.sanitize_type(place, fty); + match self.field_ty(place, base, field, location) { + Ok(ty) => { + let ty = self.cx.normalize(ty, location); + if let Err(terr) = self.cx.eq_types( + ty, + fty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + self, + place, + "bad field access ({:?}: {:?}): {:?}", + ty, + fty, + terr + ); + } + } + Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!( + self, + place, + "accessed field #{} but variant only has {}", + field.index(), + field_count + ), + } + PlaceTy::from_ty(fty) + } + } + } + + fn error(&mut self) -> Ty<'tcx> { + self.errors_reported = true; + self.tcx().ty_error() + } + + fn field_ty( + &mut self, + parent: &dyn fmt::Debug, + base_ty: PlaceTy<'tcx>, + field: Field, + location: Location, + ) -> Result, FieldAccessError> { + let tcx = self.tcx(); + + let (variant, substs) = match base_ty { + PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() { + ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs), + ty::Generator(def_id, substs, _) => { + let mut variants = substs.as_generator().state_tys(def_id, tcx); + let mut variant = match variants.nth(variant_index.into()) { + Some(v) => v, + None => bug!( + "variant_index of generator out of range: {:?}/{:?}", + variant_index, + substs.as_generator().state_tys(def_id, tcx).count() + ), + }; + return match variant.nth(field.index()) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { field_count: variant.count() }), + }; + } + _ => bug!("can't have downcast of non-adt non-generator type"), + }, + PlaceTy { ty, variant_index: None } => match *ty.kind() { + ty::Adt(adt_def, substs) if !adt_def.is_enum() => { + (&adt_def.variants[VariantIdx::new(0)], substs) + } + ty::Closure(_, substs) => { + return match substs + .as_closure() + .tupled_upvars_ty() + .tuple_element_ty(field.index()) + { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.as_closure().upvar_tys().count(), + }), + }; + } + ty::Generator(_, substs, _) => { + // Only prefix fields (upvars and current state) are + // accessible without a variant index. + return match substs.as_generator().prefix_tys().nth(field.index()) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.as_generator().prefix_tys().count(), + }), + }; + } + ty::Tuple(tys) => { + return match tys.get(field.index()) { + Some(&ty) => Ok(ty.expect_ty()), + None => Err(FieldAccessError::OutOfRange { field_count: tys.len() }), + }; + } + _ => { + return Ok(span_mirbug_and_err!( + self, + parent, + "can't project out of {:?}", + base_ty + )); + } + }, + }; + + if let Some(field) = variant.fields.get(field.index()) { + Ok(self.cx.normalize(field.ty(tcx, substs), location)) + } else { + Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) + } + } +} + +/// The MIR type checker. Visits the MIR and enforces all the +/// constraints needed for it to be valid and well-typed. Along the +/// way, it accrues region constraints -- these can later be used by +/// NLL region checking. +struct TypeChecker<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + last_span: Span, + body: &'a Body<'tcx>, + /// User type annotations are shared between the main MIR and the MIR of + /// all of the promoted items. + user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + implicit_region_bound: ty::Region<'tcx>, + reported_errors: FxHashSet<(Ty<'tcx>, Span)>, + borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, + universal_region_relations: &'a UniversalRegionRelations<'tcx>, +} + +struct BorrowCheckContext<'a, 'tcx> { + universal_regions: &'a UniversalRegions<'tcx>, + location_table: &'a LocationTable, + all_facts: &'a mut Option, + borrow_set: &'a BorrowSet<'tcx>, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + upvars: &'a [Upvar<'tcx>], +} + +crate struct MirTypeckResults<'tcx> { + crate constraints: MirTypeckRegionConstraints<'tcx>, + crate universal_region_relations: Frozen>, + crate opaque_type_values: VecMap, OpaqueTypeDecl<'tcx>>, +} + +/// A collection of region constraints that must be satisfied for the +/// program to be considered well-typed. +crate struct MirTypeckRegionConstraints<'tcx> { + /// Maps from a `ty::Placeholder` to the corresponding + /// `PlaceholderIndex` bit that we will use for it. + /// + /// To keep everything in sync, do not insert this set + /// directly. Instead, use the `placeholder_region` helper. + crate placeholder_indices: PlaceholderIndices, + + /// Each time we add a placeholder to `placeholder_indices`, we + /// also create a corresponding "representative" region vid for + /// that wraps it. This vector tracks those. This way, when we + /// convert the same `ty::RePlaceholder(p)` twice, we can map to + /// the same underlying `RegionVid`. + crate placeholder_index_to_region: IndexVec>, + + /// In general, the type-checker is not responsible for enforcing + /// liveness constraints; this job falls to the region inferencer, + /// which performs a liveness analysis. However, in some limited + /// cases, the MIR type-checker creates temporary regions that do + /// not otherwise appear in the MIR -- in particular, the + /// late-bound regions that it instantiates at call-sites -- and + /// hence it must report on their liveness constraints. + crate liveness_constraints: LivenessValues, + + crate outlives_constraints: OutlivesConstraintSet<'tcx>, + + crate member_constraints: MemberConstraintSet<'tcx, RegionVid>, + + crate closure_bounds_mapping: + FxHashMap>, + + crate universe_causes: FxHashMap>, + + crate type_tests: Vec>, +} + +impl MirTypeckRegionConstraints<'tcx> { + fn placeholder_region( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + placeholder: ty::PlaceholderRegion, + ) -> ty::Region<'tcx> { + let placeholder_index = self.placeholder_indices.insert(placeholder); + match self.placeholder_index_to_region.get(placeholder_index) { + Some(&v) => v, + None => { + let origin = NllRegionVariableOrigin::Placeholder(placeholder); + let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe); + self.placeholder_index_to_region.push(region); + region + } + } + } +} + +/// The `Locations` type summarizes *where* region constraints are +/// required to hold. Normally, this is at a particular point which +/// created the obligation, but for constraints that the user gave, we +/// want the constraint to hold at all points. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Locations { + /// Indicates that a type constraint should always be true. This + /// is particularly important in the new borrowck analysis for + /// things like the type of the return slot. Consider this + /// example: + /// + /// ``` + /// fn foo<'a>(x: &'a u32) -> &'a u32 { + /// let y = 22; + /// return &y; // error + /// } + /// ``` + /// + /// Here, we wind up with the signature from the return type being + /// something like `&'1 u32` where `'1` is a universal region. But + /// the type of the return slot `_0` is something like `&'2 u32` + /// where `'2` is an existential region variable. The type checker + /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the + /// older NLL analysis, we required this only at the entry point + /// to the function. By the nature of the constraints, this wound + /// up propagating to all points reachable from start (because + /// `'1` -- as a universal region -- is live everywhere). In the + /// newer analysis, though, this doesn't work: `_0` is considered + /// dead at the start (it has no usable value) and hence this type + /// equality is basically a no-op. Then, later on, when we do `_0 + /// = &'3 y`, that region `'3` never winds up related to the + /// universal region `'1` and hence no error occurs. Therefore, we + /// use Locations::All instead, which ensures that the `'1` and + /// `'2` are equal everything. We also use this for other + /// user-given type annotations; e.g., if the user wrote `let mut + /// x: &'static u32 = ...`, we would ensure that all values + /// assigned to `x` are of `'static` lifetime. + /// + /// The span points to the place the constraint arose. For example, + /// it points to the type in a user-given type annotation. If + /// there's no sensible span then it's DUMMY_SP. + All(Span), + + /// An outlives constraint that only has to hold at a single location, + /// usually it represents a point where references flow from one spot to + /// another (e.g., `x = y`) + Single(Location), +} + +impl Locations { + pub fn from_location(&self) -> Option { + match self { + Locations::All(_) => None, + Locations::Single(from_location) => Some(*from_location), + } + } + + /// Gets a span representing the location. + pub fn span(&self, body: &Body<'_>) -> Span { + match self { + Locations::All(span) => *span, + Locations::Single(l) => body.source_info(*l).span, + } + } +} + +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + fn new( + infcx: &'a InferCtxt<'a, 'tcx>, + body: &'a Body<'tcx>, + param_env: ty::ParamEnv<'tcx>, + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + implicit_region_bound: ty::Region<'tcx>, + borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, + universal_region_relations: &'a UniversalRegionRelations<'tcx>, + ) -> Self { + let mut checker = Self { + infcx, + last_span: DUMMY_SP, + body, + user_type_annotations: &body.user_type_annotations, + param_env, + region_bound_pairs, + implicit_region_bound, + borrowck_context, + reported_errors: Default::default(), + universal_region_relations, + }; + checker.check_user_type_annotations(); + checker + } + + fn unsized_feature_enabled(&self) -> bool { + let features = self.tcx().features(); + features.unsized_locals || features.unsized_fn_params + } + + /// Equate the inferred type and the annotated type for user type annotations + fn check_user_type_annotations(&mut self) { + debug!( + "check_user_type_annotations: user_type_annotations={:?}", + self.user_type_annotations + ); + for user_annotation in self.user_type_annotations { + let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; + let inferred_ty = self.normalize(inferred_ty, Locations::All(span)); + let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); + match annotation { + UserType::Ty(mut ty) => { + ty = self.normalize(ty, Locations::All(span)); + + if let Err(terr) = self.eq_types( + ty, + inferred_ty, + Locations::All(span), + ConstraintCategory::BoringNoLocation, + ) { + span_mirbug!( + self, + user_annotation, + "bad user type ({:?} = {:?}): {:?}", + ty, + inferred_ty, + terr + ); + } + + self.prove_predicate( + ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into())) + .to_predicate(self.tcx()), + Locations::All(span), + ConstraintCategory::TypeAnnotation, + ); + } + UserType::TypeOf(def_id, user_substs) => { + if let Err(terr) = self.fully_perform_op( + Locations::All(span), + ConstraintCategory::BoringNoLocation, + self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( + inferred_ty, + def_id, + user_substs, + )), + ) { + span_mirbug!( + self, + user_annotation, + "bad user type AscribeUserType({:?}, {:?} {:?}, type_of={:?}): {:?}", + inferred_ty, + def_id, + user_substs, + self.tcx().type_of(def_id), + terr, + ); + } + } + } + } + } + + #[instrument(skip(self, data), level = "debug")] + fn push_region_constraints( + &mut self, + locations: Locations, + category: ConstraintCategory, + data: &QueryRegionConstraints<'tcx>, + ) { + debug!("constraints generated: {:#?}", data); + + constraint_conversion::ConstraintConversion::new( + self.infcx, + self.borrowck_context.universal_regions, + self.region_bound_pairs, + Some(self.implicit_region_bound), + self.param_env, + locations, + category, + &mut self.borrowck_context.constraints, + ) + .convert_all(data); + } + + /// Try to relate `sub <: sup` + fn sub_types( + &mut self, + sub: Ty<'tcx>, + sup: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + // Use this order of parameters because the sup type is usually the + // "expected" type in diagnostics. + self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) + } + + fn eq_types( + &mut self, + expected: Ty<'tcx>, + found: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + self.relate_types(expected, ty::Variance::Invariant, found, locations, category) + } + + #[instrument(skip(self), level = "debug")] + fn relate_type_and_user_type( + &mut self, + a: Ty<'tcx>, + v: ty::Variance, + user_ty: &UserTypeProjection, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; + let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); + + let tcx = self.infcx.tcx; + + for proj in &user_ty.projs { + let projected_ty = curr_projected_ty.projection_ty_core( + tcx, + self.param_env, + proj, + |this, field, &()| { + let ty = this.field_ty(tcx, field); + self.normalize(ty, locations) + }, + ); + curr_projected_ty = projected_ty; + } + debug!( + "user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}", + user_ty.base, annotated_type, user_ty.projs, curr_projected_ty + ); + + let ty = curr_projected_ty.ty; + self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?; + + Ok(()) + } + + /// Equates a type `anon_ty` that may contain opaque types whose + /// values are to be inferred by the MIR. + /// + /// The type `revealed_ty` contains the same type as `anon_ty`, but with the + /// hidden types for impl traits revealed. + /// + /// # Example + /// + /// Consider a piece of code like + /// + /// ```rust + /// type Foo = impl Debug; + /// + /// fn foo(t: T) -> Box> { + /// Box::new((t, 22_u32)) + /// } + /// ``` + /// + /// Here, the function signature would be something like + /// `fn(T) -> Box`. The MIR return slot would have + /// the type with the opaque type revealed, so `Box<(T, u32)>`. + /// + /// In terms of our function parameters: + /// + /// * `anon_ty` would be `Box>` where `Foo` is an opaque type + /// scoped to this function (note that it is parameterized by the + /// generics of `foo`). Note that `anon_ty` is not just the opaque type, + /// but the entire return type (which may contain opaque types within it). + /// * `revealed_ty` would be `Box<(T, u32)>` + #[instrument(skip(self), level = "debug")] + fn eq_opaque_type_and_type( + &mut self, + revealed_ty: Ty<'tcx>, + anon_ty: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + // Fast path for the common case. + if !anon_ty.has_opaque_types() { + if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) { + span_mirbug!( + self, + locations, + "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`", + revealed_ty, + anon_ty, + terr + ); + } + return Ok(()); + } + + let param_env = self.param_env; + let body = self.body; + let mir_def_id = body.source.def_id().expect_local(); + + debug!(?mir_def_id); + self.fully_perform_op( + locations, + category, + CustomTypeOp::new( + |infcx| { + let mut obligations = ObligationAccumulator::default(); + + let dummy_body_id = hir::CRATE_HIR_ID; + + // Replace the opaque types defined by this function with + // inference variables, creating a map. In our example above, + // this would transform the type `Box>` (where `Foo` is an opaque type) + // to `Box`, returning an `opaque_type_map` mapping `{Foo -> ?T}`. + // (Note that the key of the map is both the def-id of `Foo` along with + // any generic parameters.) + let output_ty = obligations.add(infcx.instantiate_opaque_types( + dummy_body_id, + param_env, + anon_ty, + locations.span(body), + )); + debug!(?output_ty, ?revealed_ty); + + // Make sure that the inferred types are well-formed. I'm + // not entirely sure this is needed (the HIR type check + // didn't do this) but it seems sensible to prevent opaque + // types hiding ill-formed types. + obligations.obligations.push(traits::Obligation::new( + ObligationCause::dummy(), + param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into())) + .to_predicate(infcx.tcx), + )); + obligations.add( + infcx + .at(&ObligationCause::dummy(), param_env) + .eq(output_ty, revealed_ty)?, + ); + + debug!("equated"); + + Ok(InferOk { value: (), obligations: obligations.into_vec() }) + }, + || "input_output".to_string(), + ), + )?; + + let universal_region_relations = self.universal_region_relations; + + // Finally, if we instantiated the anon types successfully, we + // have to solve any bounds (e.g., `-> impl Iterator` needs to + // prove that `T: Iterator` where `T` is the type we + // instantiated it with). + let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone(); + for (opaque_type_key, opaque_decl) in opaque_type_map { + self.fully_perform_op( + locations, + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |infcx| { + infcx.constrain_opaque_type( + opaque_type_key, + &opaque_decl, + GenerateMemberConstraints::IfNoStaticBound, + universal_region_relations, + ); + Ok(InferOk { value: (), obligations: vec![] }) + }, + || "opaque_type_map".to_string(), + ), + )?; + } + Ok(()) + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + #[instrument(skip(self, body, location), level = "debug")] + fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { + let tcx = self.tcx(); + match stmt.kind { + StatementKind::Assign(box (ref place, ref rv)) => { + // Assignments to temporaries are not "interesting"; + // they are not caused by the user, but rather artifacts + // of lowering. Assignments to other sorts of places *are* interesting + // though. + let category = match place.as_local() { + Some(RETURN_PLACE) => { + if let BorrowCheckContext { + universal_regions: + UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, + .. + } = self.borrowck_context + { + if tcx.is_static(*def_id) { + ConstraintCategory::UseAsStatic + } else { + ConstraintCategory::UseAsConst + } + } else { + ConstraintCategory::Return(ReturnConstraint::Normal) + } + } + Some(l) + if matches!( + body.local_decls[l].local_info, + Some(box LocalInfo::AggregateTemp) + ) => + { + ConstraintCategory::Usage + } + Some(l) if !body.local_decls[l].is_user_variable() => { + ConstraintCategory::Boring + } + _ => ConstraintCategory::Assignment, + }; + debug!( + "assignment category: {:?} {:?}", + category, + place.as_local().map(|l| &body.local_decls[l]) + ); + + let place_ty = place.ty(body, tcx).ty; + let place_ty = self.normalize(place_ty, location); + let rv_ty = rv.ty(body, tcx); + let rv_ty = self.normalize(rv_ty, location); + if let Err(terr) = + self.sub_types(rv_ty, place_ty, location.to_locations(), category) + { + span_mirbug!( + self, + stmt, + "bad assignment ({:?} = {:?}): {:?}", + place_ty, + rv_ty, + terr + ); + } + + if let Some(annotation_index) = self.rvalue_user_ty(rv) { + if let Err(terr) = self.relate_type_and_user_type( + rv_ty, + ty::Variance::Invariant, + &UserTypeProjection { base: annotation_index, projs: vec![] }, + location.to_locations(), + ConstraintCategory::Boring, + ) { + let annotation = &self.user_type_annotations[annotation_index]; + span_mirbug!( + self, + stmt, + "bad user type on rvalue ({:?} = {:?}): {:?}", + annotation, + rv_ty, + terr + ); + } + } + + self.check_rvalue(body, rv, location); + if !self.unsized_feature_enabled() { + let trait_ref = ty::TraitRef { + def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), + substs: tcx.mk_substs_trait(place_ty, &[]), + }; + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); + } + } + StatementKind::SetDiscriminant { ref place, variant_index } => { + let place_type = place.ty(body, tcx).ty; + let adt = match place_type.kind() { + ty::Adt(adt, _) if adt.is_enum() => adt, + _ => { + span_bug!( + stmt.source_info.span, + "bad set discriminant ({:?} = {:?}): lhs is not an enum", + place, + variant_index + ); + } + }; + if variant_index.as_usize() >= adt.variants.len() { + span_bug!( + stmt.source_info.span, + "bad set discriminant ({:?} = {:?}): value of of range", + place, + variant_index + ); + }; + } + StatementKind::AscribeUserType(box (ref place, ref projection), variance) => { + let place_ty = place.ty(body, tcx).ty; + if let Err(terr) = self.relate_type_and_user_type( + place_ty, + variance, + projection, + Locations::All(stmt.source_info.span), + ConstraintCategory::TypeAnnotation, + ) { + let annotation = &self.user_type_annotations[projection.base]; + span_mirbug!( + self, + stmt, + "bad type assert ({:?} <: {:?} with projections {:?}): {:?}", + place_ty, + annotation, + projection.projs, + terr + ); + } + } + StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + .. + }) => span_bug!( + stmt.source_info.span, + "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics", + ), + StatementKind::FakeRead(..) + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::LlvmInlineAsm { .. } + | StatementKind::Retag { .. } + | StatementKind::Coverage(..) + | StatementKind::Nop => {} + } + } + + #[instrument(skip(self, body, term_location), level = "debug")] + fn check_terminator( + &mut self, + body: &Body<'tcx>, + term: &Terminator<'tcx>, + term_location: Location, + ) { + let tcx = self.tcx(); + match term.kind { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::GeneratorDrop + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => { + // no checks needed for these + } + + TerminatorKind::DropAndReplace { ref place, ref value, target: _, unwind: _ } => { + let place_ty = place.ty(body, tcx).ty; + let rv_ty = value.ty(body, tcx); + + let locations = term_location.to_locations(); + if let Err(terr) = + self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment) + { + span_mirbug!( + self, + term, + "bad DropAndReplace ({:?} = {:?}): {:?}", + place_ty, + rv_ty, + terr + ); + } + } + TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { + let discr_ty = discr.ty(body, tcx); + if let Err(terr) = self.sub_types( + discr_ty, + switch_ty, + term_location.to_locations(), + ConstraintCategory::Assignment, + ) { + span_mirbug!( + self, + term, + "bad SwitchInt ({:?} on {:?}): {:?}", + switch_ty, + discr_ty, + terr + ); + } + if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() { + span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty); + } + // FIXME: check the values + } + TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { + let func_ty = func.ty(body, tcx); + debug!("check_terminator: call, func_ty={:?}", func_ty); + let sig = match func_ty.kind() { + ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx), + _ => { + span_mirbug!(self, term, "call to non-function {:?}", func_ty); + return; + } + }; + let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars( + term.source_info.span, + LateBoundRegionConversionTime::FnCall, + sig, + ); + let sig = self.normalize(sig, term_location); + self.check_call_dest(body, term, &sig, destination, term_location); + + self.prove_predicates( + sig.inputs_and_output + .iter() + .map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))), + term_location.to_locations(), + ConstraintCategory::Boring, + ); + + // The ordinary liveness rules will ensure that all + // regions in the type of the callee are live here. We + // then further constrain the late-bound regions that + // were instantiated at the call site to be live as + // well. The resulting is that all the input (and + // output) types in the signature must be live, since + // all the inputs that fed into it were live. + for &late_bound_region in map.values() { + let region_vid = + self.borrowck_context.universal_regions.to_region_vid(late_bound_region); + self.borrowck_context + .constraints + .liveness_constraints + .add_element(region_vid, term_location); + } + + self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call); + } + TerminatorKind::Assert { ref cond, ref msg, .. } => { + let cond_ty = cond.ty(body, tcx); + if cond_ty != tcx.types.bool { + span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); + } + + if let AssertKind::BoundsCheck { ref len, ref index } = *msg { + if len.ty(body, tcx) != tcx.types.usize { + span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) + } + if index.ty(body, tcx) != tcx.types.usize { + span_mirbug!(self, index, "bounds-check index non-usize {:?}", index) + } + } + } + TerminatorKind::Yield { ref value, .. } => { + let value_ty = value.ty(body, tcx); + match body.yield_ty() { + None => span_mirbug!(self, term, "yield in non-generator"), + Some(ty) => { + if let Err(terr) = self.sub_types( + value_ty, + ty, + term_location.to_locations(), + ConstraintCategory::Yield, + ) { + span_mirbug!( + self, + term, + "type of yield value is {:?}, but the yield type is {:?}: {:?}", + value_ty, + ty, + terr + ); + } + } + } + } + } + } + + fn check_call_dest( + &mut self, + body: &Body<'tcx>, + term: &Terminator<'tcx>, + sig: &ty::FnSig<'tcx>, + destination: &Option<(Place<'tcx>, BasicBlock)>, + term_location: Location, + ) { + let tcx = self.tcx(); + match *destination { + Some((ref dest, _target_block)) => { + let dest_ty = dest.ty(body, tcx).ty; + let dest_ty = self.normalize(dest_ty, term_location); + let category = match dest.as_local() { + Some(RETURN_PLACE) => { + if let BorrowCheckContext { + universal_regions: + UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, + .. + } = self.borrowck_context + { + if tcx.is_static(*def_id) { + ConstraintCategory::UseAsStatic + } else { + ConstraintCategory::UseAsConst + } + } else { + ConstraintCategory::Return(ReturnConstraint::Normal) + } + } + Some(l) if !body.local_decls[l].is_user_variable() => { + ConstraintCategory::Boring + } + _ => ConstraintCategory::Assignment, + }; + + let locations = term_location.to_locations(); + + if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { + span_mirbug!( + self, + term, + "call dest mismatch ({:?} <- {:?}): {:?}", + dest_ty, + sig.output(), + terr + ); + } + + // When `unsized_fn_params` and `unsized_locals` are both not enabled, + // this check is done at `check_local`. + if self.unsized_feature_enabled() { + let span = term.source_info.span; + self.ensure_place_sized(dest_ty, span); + } + } + None => { + if !self + .tcx() + .conservative_is_privately_uninhabited(self.param_env.and(sig.output())) + { + span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); + } + } + } + } + + fn check_call_inputs( + &mut self, + body: &Body<'tcx>, + term: &Terminator<'tcx>, + sig: &ty::FnSig<'tcx>, + args: &[Operand<'tcx>], + term_location: Location, + from_hir_call: bool, + ) { + debug!("check_call_inputs({:?}, {:?})", sig, args); + if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { + span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); + } + for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { + let op_arg_ty = op_arg.ty(body, self.tcx()); + let op_arg_ty = self.normalize(op_arg_ty, term_location); + let category = if from_hir_call { + ConstraintCategory::CallArgument + } else { + ConstraintCategory::Boring + }; + if let Err(terr) = + self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category) + { + span_mirbug!( + self, + term, + "bad arg #{:?} ({:?} <- {:?}): {:?}", + n, + fn_arg, + op_arg_ty, + terr + ); + } + } + } + + fn check_iscleanup(&mut self, body: &Body<'tcx>, block_data: &BasicBlockData<'tcx>) { + let is_cleanup = block_data.is_cleanup; + self.last_span = block_data.terminator().source_info.span; + match block_data.terminator().kind { + TerminatorKind::Goto { target } => { + self.assert_iscleanup(body, block_data, target, is_cleanup) + } + TerminatorKind::SwitchInt { ref targets, .. } => { + for target in targets.all_targets() { + self.assert_iscleanup(body, block_data, *target, is_cleanup); + } + } + TerminatorKind::Resume => { + if !is_cleanup { + span_mirbug!(self, block_data, "resume on non-cleanup block!") + } + } + TerminatorKind::Abort => { + if !is_cleanup { + span_mirbug!(self, block_data, "abort on non-cleanup block!") + } + } + TerminatorKind::Return => { + if is_cleanup { + span_mirbug!(self, block_data, "return on cleanup block") + } + } + TerminatorKind::GeneratorDrop { .. } => { + if is_cleanup { + span_mirbug!(self, block_data, "generator_drop in cleanup block") + } + } + TerminatorKind::Yield { resume, drop, .. } => { + if is_cleanup { + span_mirbug!(self, block_data, "yield in cleanup block") + } + self.assert_iscleanup(body, block_data, resume, is_cleanup); + if let Some(drop) = drop { + self.assert_iscleanup(body, block_data, drop, is_cleanup); + } + } + TerminatorKind::Unreachable => {} + TerminatorKind::Drop { target, unwind, .. } + | TerminatorKind::DropAndReplace { target, unwind, .. } + | TerminatorKind::Assert { target, cleanup: unwind, .. } => { + self.assert_iscleanup(body, block_data, target, is_cleanup); + if let Some(unwind) = unwind { + if is_cleanup { + span_mirbug!(self, block_data, "unwind on cleanup block") + } + self.assert_iscleanup(body, block_data, unwind, true); + } + } + TerminatorKind::Call { ref destination, cleanup, .. } => { + if let &Some((_, target)) = destination { + self.assert_iscleanup(body, block_data, target, is_cleanup); + } + if let Some(cleanup) = cleanup { + if is_cleanup { + span_mirbug!(self, block_data, "cleanup on cleanup block") + } + self.assert_iscleanup(body, block_data, cleanup, true); + } + } + TerminatorKind::FalseEdge { real_target, imaginary_target } => { + self.assert_iscleanup(body, block_data, real_target, is_cleanup); + self.assert_iscleanup(body, block_data, imaginary_target, is_cleanup); + } + TerminatorKind::FalseUnwind { real_target, unwind } => { + self.assert_iscleanup(body, block_data, real_target, is_cleanup); + if let Some(unwind) = unwind { + if is_cleanup { + span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind"); + } + self.assert_iscleanup(body, block_data, unwind, true); + } + } + TerminatorKind::InlineAsm { destination, .. } => { + if let Some(target) = destination { + self.assert_iscleanup(body, block_data, target, is_cleanup); + } + } + } + } + + fn assert_iscleanup( + &mut self, + body: &Body<'tcx>, + ctxt: &dyn fmt::Debug, + bb: BasicBlock, + iscleanuppad: bool, + ) { + if body[bb].is_cleanup != iscleanuppad { + span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}", bb, iscleanuppad); + } + } + + fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { + match body.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Arg => { + // return values of normal functions are required to be + // sized by typeck, but return values of ADT constructors are + // not because we don't include a `Self: Sized` bounds on them. + // + // Unbound parts of arguments were never required to be Sized + // - maybe we should make that a warning. + return; + } + LocalKind::Var | LocalKind::Temp => {} + } + + // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls + // and nullary ops are checked in `check_call_dest`. + if !self.unsized_feature_enabled() { + let span = local_decl.source_info.span; + let ty = local_decl.ty; + self.ensure_place_sized(ty, span); + } + } + + fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) { + let tcx = self.tcx(); + + // Erase the regions from `ty` to get a global type. The + // `Sized` bound in no way depends on precise regions, so this + // shouldn't affect `is_sized`. + let erased_ty = tcx.erase_regions(ty); + if !erased_ty.is_sized(tcx.at(span), self.param_env) { + // in current MIR construction, all non-control-flow rvalue + // expressions evaluate through `as_temp` or `into` a return + // slot or local, so to find all unsized rvalues it is enough + // to check all temps, return slots and locals. + if self.reported_errors.replace((ty, span)).is_none() { + let mut diag = struct_span_err!( + self.tcx().sess, + span, + E0161, + "cannot move a value of type {0}: the size of {0} \ + cannot be statically determined", + ty + ); + + // While this is located in `nll::typeck` this error is not + // an NLL error, it's a required check to prevent creation + // of unsized rvalues in a call expression. + diag.emit(); + } + } + } + + fn aggregate_field_ty( + &mut self, + ak: &AggregateKind<'tcx>, + field_index: usize, + location: Location, + ) -> Result, FieldAccessError> { + let tcx = self.tcx(); + + match *ak { + AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => { + let variant = &def.variants[variant_index]; + let adj_field_index = active_field_index.unwrap_or(field_index); + if let Some(field) = variant.fields.get(adj_field_index) { + Ok(self.normalize(field.ty(tcx, substs), location)) + } else { + Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) + } + } + AggregateKind::Closure(_, substs) => { + match substs.as_closure().upvar_tys().nth(field_index) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.as_closure().upvar_tys().count(), + }), + } + } + AggregateKind::Generator(_, substs, _) => { + // It doesn't make sense to look at a field beyond the prefix; + // these require a variant index, and are not initialized in + // aggregate rvalues. + match substs.as_generator().prefix_tys().nth(field_index) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.as_generator().prefix_tys().count(), + }), + } + } + AggregateKind::Array(ty) => Ok(ty), + AggregateKind::Tuple => { + unreachable!("This should have been covered in check_rvalues"); + } + } + } + + fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { + let tcx = self.tcx(); + + match rvalue { + Rvalue::Aggregate(ak, ops) => { + self.check_aggregate_rvalue(&body, rvalue, ak, ops, location) + } + + Rvalue::Repeat(operand, len) => { + // If the length cannot be evaluated we must assume that the length can be larger + // than 1. + // If the length is larger than 1, the repeat expression will need to copy the + // element, so we require the `Copy` trait. + if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { + match operand { + Operand::Copy(..) | Operand::Constant(..) => { + // These are always okay: direct use of a const, or a value that can evidently be copied. + } + Operand::Move(place) => { + // Make sure that repeated elements implement `Copy`. + let span = body.source_info(location).span; + let ty = operand.ty(body, tcx); + if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { + let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); + let is_const_fn = + is_const_fn_in_array_repeat_expression(&ccx, &place, &body); + + debug!("check_rvalue: is_const_fn={:?}", is_const_fn); + + let def_id = body.source.def_id().expect_local(); + let obligation = traits::Obligation::new( + ObligationCause::new( + span, + self.tcx().hir().local_def_id_to_hir_id(def_id), + traits::ObligationCauseCode::RepeatVec(is_const_fn), + ), + self.param_env, + ty::Binder::dummy(ty::TraitRef::new( + self.tcx().require_lang_item( + LangItem::Copy, + Some(self.last_span), + ), + tcx.mk_substs_trait(ty, &[]), + )) + .without_const() + .to_predicate(self.tcx()), + ); + self.infcx.report_selection_error( + obligation.clone(), + &obligation, + &traits::SelectionError::Unimplemented, + false, + ); + } + } + } + } + } + + Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => { + let trait_ref = ty::TraitRef { + def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), + substs: tcx.mk_substs_trait(ty, &[]), + }; + + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); + } + + Rvalue::Cast(cast_kind, op, ty) => { + match cast_kind { + CastKind::Pointer(PointerCast::ReifyFnPointer) => { + let fn_sig = op.ty(body, tcx).fn_sig(tcx); + + // The type that we see in the fcx is like + // `foo::<'a, 'b>`, where `foo` is the path to a + // function definition. When we extract the + // signature, it comes from the `fn_sig` query, + // and hence may contain unnormalized results. + let fn_sig = self.normalize(fn_sig, location); + + let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); + + if let Err(terr) = self.eq_types( + ty, + ty_fn_ptr_from, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "equating {:?} with {:?} yields {:?}", + ty_fn_ptr_from, + ty, + terr + ); + } + } + + CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { + let sig = match op.ty(body, tcx).kind() { + ty::Closure(_, substs) => substs.as_closure().sig(), + _ => bug!(), + }; + let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety)); + + if let Err(terr) = self.eq_types( + ty, + ty_fn_ptr_from, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "equating {:?} with {:?} yields {:?}", + ty_fn_ptr_from, + ty, + terr + ); + } + } + + CastKind::Pointer(PointerCast::UnsafeFnPointer) => { + let fn_sig = op.ty(body, tcx).fn_sig(tcx); + + // The type that we see in the fcx is like + // `foo::<'a, 'b>`, where `foo` is the path to a + // function definition. When we extract the + // signature, it comes from the `fn_sig` query, + // and hence may contain unnormalized results. + let fn_sig = self.normalize(fn_sig, location); + + let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); + + if let Err(terr) = self.eq_types( + ty, + ty_fn_ptr_from, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "equating {:?} with {:?} yields {:?}", + ty_fn_ptr_from, + ty, + terr + ); + } + } + + CastKind::Pointer(PointerCast::Unsize) => { + let &ty = ty; + let trait_ref = ty::TraitRef { + def_id: tcx + .require_lang_item(LangItem::CoerceUnsized, Some(self.last_span)), + substs: tcx.mk_substs_trait(op.ty(body, tcx), &[ty.into()]), + }; + + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::Cast, + ); + } + + CastKind::Pointer(PointerCast::MutToConstPointer) => { + let ty_from = match op.ty(body, tcx).kind() { + ty::RawPtr(ty::TypeAndMut { + ty: ty_from, + mutbl: hir::Mutability::Mut, + }) => ty_from, + _ => { + span_mirbug!( + self, + rvalue, + "unexpected base type for cast {:?}", + ty, + ); + return; + } + }; + let ty_to = match ty.kind() { + ty::RawPtr(ty::TypeAndMut { + ty: ty_to, + mutbl: hir::Mutability::Not, + }) => ty_to, + _ => { + span_mirbug!( + self, + rvalue, + "unexpected target type for cast {:?}", + ty, + ); + return; + } + }; + if let Err(terr) = self.sub_types( + ty_from, + ty_to, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "relating {:?} with {:?} yields {:?}", + ty_from, + ty_to, + terr + ); + } + } + + CastKind::Pointer(PointerCast::ArrayToPointer) => { + let ty_from = op.ty(body, tcx); + + let opt_ty_elem_mut = match ty_from.kind() { + ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => { + match array_ty.kind() { + ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)), + _ => None, + } + } + _ => None, + }; + + let (ty_elem, ty_mut) = match opt_ty_elem_mut { + Some(ty_elem_mut) => ty_elem_mut, + None => { + span_mirbug!( + self, + rvalue, + "ArrayToPointer cast from unexpected type {:?}", + ty_from, + ); + return; + } + }; + + let (ty_to, ty_to_mut) = match ty.kind() { + ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => { + (ty_to, *ty_to_mut) + } + _ => { + span_mirbug!( + self, + rvalue, + "ArrayToPointer cast to unexpected type {:?}", + ty, + ); + return; + } + }; + + if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not { + span_mirbug!( + self, + rvalue, + "ArrayToPointer cast from const {:?} to mut {:?}", + ty, + ty_to + ); + return; + } + + if let Err(terr) = self.sub_types( + ty_elem, + ty_to, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "relating {:?} with {:?} yields {:?}", + ty_elem, + ty_to, + terr + ) + } + } + + CastKind::Misc => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(ty); + match (cast_ty_from, cast_ty_to) { + (None, _) + | (_, None | Some(CastTy::FnPtr)) + | (Some(CastTy::Float), Some(CastTy::Ptr(_))) + | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => { + span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,) + } + ( + Some(CastTy::Int(_)), + Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)), + ) + | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float)) + | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_))) + | (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (), + } + } + } + } + + Rvalue::Ref(region, _borrow_kind, borrowed_place) => { + self.add_reborrow_constraint(&body, location, region, borrowed_place); + } + + Rvalue::BinaryOp( + BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, + box (left, right), + ) => { + let ty_left = left.ty(body, tcx); + match ty_left.kind() { + // Types with regions are comparable if they have a common super-type. + ty::RawPtr(_) | ty::FnPtr(_) => { + let ty_right = right.ty(body, tcx); + let common_ty = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: body.source_info(location).span, + }); + self.sub_types( + ty_left, + common_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) + .unwrap_or_else(|err| { + bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) + }); + if let Err(terr) = self.sub_types( + ty_right, + common_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + self, + rvalue, + "unexpected comparison types {:?} and {:?} yields {:?}", + ty_left, + ty_right, + terr + ) + } + } + // For types with no regions we can just check that the + // both operands have the same type. + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) + if ty_left == right.ty(body, tcx) => {} + // Other types are compared by trait methods, not by + // `Rvalue::BinaryOp`. + _ => span_mirbug!( + self, + rvalue, + "unexpected comparison types {:?} and {:?}", + ty_left, + right.ty(body, tcx) + ), + } + } + + Rvalue::AddressOf(..) + | Rvalue::ThreadLocalRef(..) + | Rvalue::Use(..) + | Rvalue::Len(..) + | Rvalue::BinaryOp(..) + | Rvalue::CheckedBinaryOp(..) + | Rvalue::UnaryOp(..) + | Rvalue::Discriminant(..) => {} + } + } + + /// If this rvalue supports a user-given type annotation, then + /// extract and return it. This represents the final type of the + /// rvalue and will be unified with the inferred type. + fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option { + match rvalue { + Rvalue::Use(_) + | Rvalue::ThreadLocalRef(_) + | Rvalue::Repeat(..) + | Rvalue::Ref(..) + | Rvalue::AddressOf(..) + | Rvalue::Len(..) + | Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) + | Rvalue::BinaryOp(..) + | Rvalue::CheckedBinaryOp(..) + | Rvalue::NullaryOp(..) + | Rvalue::UnaryOp(..) + | Rvalue::Discriminant(..) => None, + + Rvalue::Aggregate(aggregate, _) => match **aggregate { + AggregateKind::Adt(_, _, _, user_ty, _) => user_ty, + AggregateKind::Array(_) => None, + AggregateKind::Tuple => None, + AggregateKind::Closure(_, _) => None, + AggregateKind::Generator(_, _, _) => None, + }, + } + } + + fn check_aggregate_rvalue( + &mut self, + body: &Body<'tcx>, + rvalue: &Rvalue<'tcx>, + aggregate_kind: &AggregateKind<'tcx>, + operands: &[Operand<'tcx>], + location: Location, + ) { + let tcx = self.tcx(); + + self.prove_aggregate_predicates(aggregate_kind, location); + + if *aggregate_kind == AggregateKind::Tuple { + // tuple rvalue field type is always the type of the op. Nothing to check here. + return; + } + + for (i, operand) in operands.iter().enumerate() { + let field_ty = match self.aggregate_field_ty(aggregate_kind, i, location) { + Ok(field_ty) => field_ty, + Err(FieldAccessError::OutOfRange { field_count }) => { + span_mirbug!( + self, + rvalue, + "accessed field #{} but variant only has {}", + i, + field_count + ); + continue; + } + }; + let operand_ty = operand.ty(body, tcx); + let operand_ty = self.normalize(operand_ty, location); + + if let Err(terr) = self.sub_types( + operand_ty, + field_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + self, + rvalue, + "{:?} is not a subtype of {:?}: {:?}", + operand_ty, + field_ty, + terr + ); + } + } + } + + /// Adds the constraints that arise from a borrow expression `&'a P` at the location `L`. + /// + /// # Parameters + /// + /// - `location`: the location `L` where the borrow expression occurs + /// - `borrow_region`: the region `'a` associated with the borrow + /// - `borrowed_place`: the place `P` being borrowed + fn add_reborrow_constraint( + &mut self, + body: &Body<'tcx>, + location: Location, + borrow_region: ty::Region<'tcx>, + borrowed_place: &Place<'tcx>, + ) { + // These constraints are only meaningful during borrowck: + let BorrowCheckContext { borrow_set, location_table, all_facts, constraints, .. } = + self.borrowck_context; + + // In Polonius mode, we also push a `loan_issued_at` fact + // linking the loan to the region (in some cases, though, + // there is no loan associated with this borrow expression -- + // that occurs when we are borrowing an unsafe place, for + // example). + if let Some(all_facts) = all_facts { + let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); + if let Some(borrow_index) = borrow_set.get_index_of(&location) { + let region_vid = borrow_region.to_region_vid(); + all_facts.loan_issued_at.push(( + region_vid, + borrow_index, + location_table.mid_index(location), + )); + } + } + + // If we are reborrowing the referent of another reference, we + // need to add outlives relationships. In a case like `&mut + // *p`, where the `p` has type `&'b mut Foo`, for example, we + // need to ensure that `'b: 'a`. + + debug!( + "add_reborrow_constraint({:?}, {:?}, {:?})", + location, borrow_region, borrowed_place + ); + + let mut cursor = borrowed_place.projection.as_ref(); + let tcx = self.infcx.tcx; + let field = path_utils::is_upvar_field_projection( + tcx, + &self.borrowck_context.upvars, + borrowed_place.as_ref(), + body, + ); + let category = if let Some(field) = field { + let var_hir_id = self.borrowck_context.upvars[field.index()].place.get_root_variable(); + // FIXME(project-rfc-2229#8): Use Place for better diagnostics + ConstraintCategory::ClosureUpvar(var_hir_id) + } else { + ConstraintCategory::Boring + }; + + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + + debug!("add_reborrow_constraint - iteration {:?}", elem); + + match elem { + ProjectionElem::Deref => { + let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty; + + debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); + match base_ty.kind() { + ty::Ref(ref_region, _, mutbl) => { + constraints.outlives_constraints.push(OutlivesConstraint { + sup: ref_region.to_region_vid(), + sub: borrow_region.to_region_vid(), + locations: location.to_locations(), + category, + variance_info: ty::VarianceDiagInfo::default(), + }); + + match mutbl { + hir::Mutability::Not => { + // Immutable reference. We don't need the base + // to be valid for the entire lifetime of + // the borrow. + break; + } + hir::Mutability::Mut => { + // Mutable reference. We *do* need the base + // to be valid, because after the base becomes + // invalid, someone else can use our mutable deref. + + // This is in order to make the following function + // illegal: + // ``` + // fn unsafe_deref<'a, 'b>(x: &'a &'b mut T) -> &'b mut T { + // &mut *x + // } + // ``` + // + // As otherwise you could clone `&mut T` using the + // following function: + // ``` + // fn bad(x: &mut T) -> (&mut T, &mut T) { + // let my_clone = unsafe_deref(&'a x); + // ENDREGION 'a; + // (my_clone, x) + // } + // ``` + } + } + } + ty::RawPtr(..) => { + // deref of raw pointer, guaranteed to be valid + break; + } + ty::Adt(def, _) if def.is_box() => { + // deref of `Box`, need the base to be valid - propagate + } + _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place), + } + } + ProjectionElem::Field(..) + | ProjectionElem::Downcast(..) + | ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => { + // other field access + } + } + } + } + + fn prove_aggregate_predicates( + &mut self, + aggregate_kind: &AggregateKind<'tcx>, + location: Location, + ) { + let tcx = self.tcx(); + + debug!( + "prove_aggregate_predicates(aggregate_kind={:?}, location={:?})", + aggregate_kind, location + ); + + let (def_id, instantiated_predicates) = match aggregate_kind { + AggregateKind::Adt(def, _, substs, _, _) => { + (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs)) + } + + // For closures, we have some **extra requirements** we + // + // have to check. In particular, in their upvars and + // signatures, closures often reference various regions + // from the surrounding function -- we call those the + // closure's free regions. When we borrow-check (and hence + // region-check) closures, we may find that the closure + // requires certain relationships between those free + // regions. However, because those free regions refer to + // portions of the CFG of their caller, the closure is not + // in a position to verify those relationships. In that + // case, the requirements get "propagated" to us, and so + // we have to solve them here where we instantiate the + // closure. + // + // Despite the opacity of the previous parapgrah, this is + // actually relatively easy to understand in terms of the + // desugaring. A closure gets desugared to a struct, and + // these extra requirements are basically like where + // clauses on the struct. + AggregateKind::Closure(def_id, substs) + | AggregateKind::Generator(def_id, substs, _) => { + (*def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location)) + } + + AggregateKind::Array(_) | AggregateKind::Tuple => { + (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) + } + }; + + self.normalize_and_prove_instantiated_predicates( + def_id, + instantiated_predicates, + location.to_locations(), + ); + } + + fn prove_closure_bounds( + &mut self, + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + substs: SubstsRef<'tcx>, + location: Location, + ) -> ty::InstantiatedPredicates<'tcx> { + if let Some(ref closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements + { + let closure_constraints = QueryRegionConstraints { + outlives: closure_region_requirements.apply_requirements( + tcx, + def_id.to_def_id(), + substs, + ), + + // Presently, closures never propagate member + // constraints to their parents -- they are enforced + // locally. This is largely a non-issue as member + // constraints only come from `-> impl Trait` and + // friends which don't appear (thus far...) in + // closures. + member_constraints: vec![], + }; + + let bounds_mapping = closure_constraints + .outlives + .iter() + .enumerate() + .filter_map(|(idx, constraint)| { + let ty::OutlivesPredicate(k1, r2) = + constraint.no_bound_vars().unwrap_or_else(|| { + bug!("query_constraint {:?} contained bound vars", constraint,); + }); + + match k1.unpack() { + GenericArgKind::Lifetime(r1) => { + // constraint is r1: r2 + let r1_vid = self.borrowck_context.universal_regions.to_region_vid(r1); + let r2_vid = self.borrowck_context.universal_regions.to_region_vid(r2); + let outlives_requirements = + &closure_region_requirements.outlives_requirements[idx]; + Some(( + (r1_vid, r2_vid), + (outlives_requirements.category, outlives_requirements.blame_span), + )) + } + GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, + } + }) + .collect(); + + let existing = self + .borrowck_context + .constraints + .closure_bounds_mapping + .insert(location, bounds_mapping); + assert!(existing.is_none(), "Multiple closures at the same location."); + + self.push_region_constraints( + location.to_locations(), + ConstraintCategory::ClosureBounds, + &closure_constraints, + ); + } + + tcx.predicates_of(def_id).instantiate(tcx, substs) + } + + #[instrument(skip(self, body), level = "debug")] + fn typeck_mir(&mut self, body: &Body<'tcx>) { + self.last_span = body.span; + debug!(?body.span); + + for (local, local_decl) in body.local_decls.iter_enumerated() { + self.check_local(&body, local, local_decl); + } + + for (block, block_data) in body.basic_blocks().iter_enumerated() { + let mut location = Location { block, statement_index: 0 }; + for stmt in &block_data.statements { + if !stmt.source_info.span.is_dummy() { + self.last_span = stmt.source_info.span; + } + self.check_stmt(body, stmt, location); + location.statement_index += 1; + } + + self.check_terminator(&body, block_data.terminator(), location); + self.check_iscleanup(&body, block_data); + } + } +} + +trait NormalizeLocation: fmt::Debug + Copy { + fn to_locations(self) -> Locations; +} + +impl NormalizeLocation for Locations { + fn to_locations(self) -> Locations { + self + } +} + +impl NormalizeLocation for Location { + fn to_locations(self) -> Locations { + Locations::Single(self) + } +} + +#[derive(Debug, Default)] +struct ObligationAccumulator<'tcx> { + obligations: PredicateObligations<'tcx>, +} + +impl<'tcx> ObligationAccumulator<'tcx> { + fn add(&mut self, value: InferOk<'tcx, T>) -> T { + let InferOk { value, obligations } = value; + self.obligations.extend(obligations); + value + } + + fn into_vec(self) -> PredicateObligations<'tcx> { + self.obligations + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/relate_tys.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/relate_tys.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/relate_tys.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/type_check/relate_tys.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,129 @@ +use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; +use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::relate::TypeRelation; +use rustc_middle::ty::{self, Const, Ty}; +use rustc_trait_selection::traits::query::Fallible; + +use crate::constraints::OutlivesConstraint; +use crate::diagnostics::UniverseInfo; +use crate::type_check::{Locations, TypeChecker}; + +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: + /// + /// - "Covariant" `a <: b` + /// - "Invariant" `a == b` + /// - "Contravariant" `a :> b` + /// + /// N.B., the type `a` is permitted to have unresolved inference + /// variables, but not the type `b`. + #[instrument(skip(self), level = "debug")] + pub(super) fn relate_types( + &mut self, + a: Ty<'tcx>, + v: ty::Variance, + b: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + TypeRelating::new( + self.infcx, + NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)), + v, + ) + .relate(a, b)?; + Ok(()) + } +} + +struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { + type_checker: &'me mut TypeChecker<'bccx, 'tcx>, + + /// Where (and why) is this relation taking place? + locations: Locations, + + /// What category do we assign the resulting `'a: 'b` relationships? + category: ConstraintCategory, + + /// Information so that error reporting knows what types we are relating + /// when reporting a bound region error. + universe_info: UniverseInfo<'tcx>, +} + +impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { + fn new( + type_checker: &'me mut TypeChecker<'bccx, 'tcx>, + locations: Locations, + category: ConstraintCategory, + universe_info: UniverseInfo<'tcx>, + ) -> Self { + Self { type_checker, locations, category, universe_info } + } +} + +impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.type_checker.param_env + } + + fn create_next_universe(&mut self) -> ty::UniverseIndex { + let universe = self.type_checker.infcx.create_next_universe(); + self.type_checker + .borrowck_context + .constraints + .universe_causes + .insert(universe, self.universe_info.clone()); + universe + } + + fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { + let origin = NllRegionVariableOrigin::Existential { from_forall }; + self.type_checker.infcx.next_nll_region_var(origin) + } + + fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { + self.type_checker + .borrowck_context + .constraints + .placeholder_region(self.type_checker.infcx, placeholder) + } + + fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + self.type_checker.infcx.next_nll_region_var_in_universe( + NllRegionVariableOrigin::Existential { from_forall: false }, + universe, + ) + } + + fn push_outlives( + &mut self, + sup: ty::Region<'tcx>, + sub: ty::Region<'tcx>, + info: ty::VarianceDiagInfo<'tcx>, + ) { + let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub); + let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup); + self.type_checker.borrowck_context.constraints.outlives_constraints.push( + OutlivesConstraint { + sup, + sub, + locations: self.locations, + category: self.category, + variance_info: info, + }, + ); + } + + // We don't have to worry about the equality of consts during borrow checking + // as consts always have a static lifetime. + fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {} + + fn normalization() -> NormalizationStrategy { + NormalizationStrategy::Eager + } + + fn forbid_inference_vars() -> bool { + true + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/universal_regions.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/universal_regions.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/universal_regions.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/universal_regions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,817 @@ +//! Code to extract the universally quantified regions declared on a +//! function and the relationships between them. For example: +//! +//! ``` +//! fn foo<'a, 'b, 'c: 'b>() { } +//! ``` +//! +//! here we would return a map assigning each of `{'a, 'b, 'c}` +//! to an index, as well as the `FreeRegionMap` which can compute +//! relationships between them. +//! +//! The code in this file doesn't *do anything* with those results; it +//! just returns them for other code to use. + +use either::Either; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::DiagnosticBuilder; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{BodyOwnerKind, HirId}; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; +use std::iter; + +use crate::nll::ToRegionVid; + +#[derive(Debug)] +pub struct UniversalRegions<'tcx> { + indices: UniversalRegionIndices<'tcx>, + + /// The vid assigned to `'static` + pub fr_static: RegionVid, + + /// A special region vid created to represent the current MIR fn + /// body. It will outlive the entire CFG but it will not outlive + /// any other universal regions. + pub fr_fn_body: RegionVid, + + /// We create region variables such that they are ordered by their + /// `RegionClassification`. The first block are globals, then + /// externals, then locals. So, things from: + /// - `FIRST_GLOBAL_INDEX..first_extern_index` are global, + /// - `first_extern_index..first_local_index` are external, + /// - `first_local_index..num_universals` are local. + first_extern_index: usize, + + /// See `first_extern_index`. + first_local_index: usize, + + /// The total number of universal region variables instantiated. + num_universals: usize, + + /// A special region variable created for the `'empty(U0)` region. + /// Note that this is **not** a "universal" region, as it doesn't + /// represent a universally bound placeholder or any such thing. + /// But we do create it here in this type because it's a useful region + /// to have around in a few limited cases. + pub root_empty: RegionVid, + + /// The "defining" type for this function, with all universal + /// regions instantiated. For a closure or generator, this is the + /// closure type, but for a top-level function it's the `FnDef`. + pub defining_ty: DefiningTy<'tcx>, + + /// The return type of this function, with all regions replaced by + /// their universal `RegionVid` equivalents. + /// + /// N.B., associated types in this type have not been normalized, + /// as the name suggests. =) + pub unnormalized_output_ty: Ty<'tcx>, + + /// The fully liberated input types of this function, with all + /// regions replaced by their universal `RegionVid` equivalents. + /// + /// N.B., associated types in these types have not been normalized, + /// as the name suggests. =) + pub unnormalized_input_tys: &'tcx [Ty<'tcx>], + + pub yield_ty: Option>, +} + +/// The "defining type" for this MIR. The key feature of the "defining +/// type" is that it contains the information needed to derive all the +/// universal regions that are in scope as well as the types of the +/// inputs/output from the MIR. In general, early-bound universal +/// regions appear free in the defining type and late-bound regions +/// appear bound in the signature. +#[derive(Copy, Clone, Debug)] +pub enum DefiningTy<'tcx> { + /// The MIR is a closure. The signature is found via + /// `ClosureSubsts::closure_sig_ty`. + Closure(DefId, SubstsRef<'tcx>), + + /// The MIR is a generator. The signature is that generators take + /// no parameters and return the result of + /// `ClosureSubsts::generator_return_ty`. + Generator(DefId, SubstsRef<'tcx>, hir::Movability), + + /// The MIR is a fn item with the given `DefId` and substs. The signature + /// of the function can be bound then with the `fn_sig` query. + FnDef(DefId, SubstsRef<'tcx>), + + /// The MIR represents some form of constant. The signature then + /// is that it has no inputs and a single return value, which is + /// the value of the constant. + Const(DefId, SubstsRef<'tcx>), +} + +impl<'tcx> DefiningTy<'tcx> { + /// Returns a list of all the upvar types for this MIR. If this is + /// not a closure or generator, there are no upvars, and hence it + /// will be an empty list. The order of types in this list will + /// match up with the upvar order in the HIR, typesystem, and MIR. + pub fn upvar_tys(self) -> impl Iterator> + 'tcx { + match self { + DefiningTy::Closure(_, substs) => Either::Left(substs.as_closure().upvar_tys()), + DefiningTy::Generator(_, substs, _) => { + Either::Right(Either::Left(substs.as_generator().upvar_tys())) + } + DefiningTy::FnDef(..) | DefiningTy::Const(..) => { + Either::Right(Either::Right(iter::empty())) + } + } + } + + /// Number of implicit inputs -- notably the "environment" + /// parameter for closures -- that appear in MIR but not in the + /// user's code. + pub fn implicit_inputs(self) -> usize { + match self { + DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1, + DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0, + } + } + + pub fn is_fn_def(&self) -> bool { + match *self { + DefiningTy::FnDef(..) => true, + _ => false, + } + } + + pub fn is_const(&self) -> bool { + match *self { + DefiningTy::Const(..) => true, + _ => false, + } + } + + pub fn def_id(&self) -> DefId { + match *self { + DefiningTy::Closure(def_id, ..) + | DefiningTy::Generator(def_id, ..) + | DefiningTy::FnDef(def_id, ..) + | DefiningTy::Const(def_id, ..) => def_id, + } + } +} + +#[derive(Debug)] +struct UniversalRegionIndices<'tcx> { + /// For those regions that may appear in the parameter environment + /// ('static and early-bound regions), we maintain a map from the + /// `ty::Region` to the internal `RegionVid` we are using. This is + /// used because trait matching and type-checking will feed us + /// region constraints that reference those regions and we need to + /// be able to map them our internal `RegionVid`. This is + /// basically equivalent to an `InternalSubsts`, except that it also + /// contains an entry for `ReStatic` -- it might be nice to just + /// use a substs, and then handle `ReStatic` another way. + indices: FxHashMap, RegionVid>, +} + +#[derive(Debug, PartialEq)] +pub enum RegionClassification { + /// A **global** region is one that can be named from + /// anywhere. There is only one, `'static`. + Global, + + /// An **external** region is only relevant for closures. In that + /// case, it refers to regions that are free in the closure type + /// -- basically, something bound in the surrounding context. + /// + /// Consider this example: + /// + /// ``` + /// fn foo<'a, 'b>(a: &'a u32, b: &'b u32, c: &'static u32) { + /// let closure = for<'x> |x: &'x u32| { .. }; + /// ^^^^^^^ pretend this were legal syntax + /// for declaring a late-bound region in + /// a closure signature + /// } + /// ``` + /// + /// Here, the lifetimes `'a` and `'b` would be **external** to the + /// closure. + /// + /// If we are not analyzing a closure, there are no external + /// lifetimes. + External, + + /// A **local** lifetime is one about which we know the full set + /// of relevant constraints (that is, relationships to other named + /// regions). For a closure, this includes any region bound in + /// the closure's signature. For a fn item, this includes all + /// regions other than global ones. + /// + /// Continuing with the example from `External`, if we were + /// analyzing the closure, then `'x` would be local (and `'a` and + /// `'b` are external). If we are analyzing the function item + /// `foo`, then `'a` and `'b` are local (and `'x` is not in + /// scope). + Local, +} + +const FIRST_GLOBAL_INDEX: usize = 0; + +impl<'tcx> UniversalRegions<'tcx> { + /// Creates a new and fully initialized `UniversalRegions` that + /// contains indices for all the free regions found in the given + /// MIR -- that is, all the regions that appear in the function's + /// signature. This will also compute the relationships that are + /// known between those regions. + pub fn new( + infcx: &InferCtxt<'_, 'tcx>, + mir_def: ty::WithOptConstParam, + param_env: ty::ParamEnv<'tcx>, + ) -> Self { + let tcx = infcx.tcx; + let mir_hir_id = tcx.hir().local_def_id_to_hir_id(mir_def.did); + UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build() + } + + /// Given a reference to a closure type, extracts all the values + /// from its free regions and returns a vector with them. This is + /// used when the closure's creator checks that the + /// `ClosureRegionRequirements` are met. The requirements from + /// `ClosureRegionRequirements` are expressed in terms of + /// `RegionVid` entries that map into the returned vector `V`: so + /// if the `ClosureRegionRequirements` contains something like + /// `'1: '2`, then the caller would impose the constraint that + /// `V[1]: V[2]`. + pub fn closure_mapping( + tcx: TyCtxt<'tcx>, + closure_substs: SubstsRef<'tcx>, + expected_num_vars: usize, + closure_base_def_id: DefId, + ) -> IndexVec> { + let mut region_mapping = IndexVec::with_capacity(expected_num_vars); + region_mapping.push(tcx.lifetimes.re_static); + tcx.for_each_free_region(&closure_substs, |fr| { + region_mapping.push(fr); + }); + + for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + region_mapping.push(r); + }); + + assert_eq!( + region_mapping.len(), + expected_num_vars, + "index vec had unexpected number of variables" + ); + + region_mapping + } + + /// Returns `true` if `r` is a member of this set of universal regions. + pub fn is_universal_region(&self, r: RegionVid) -> bool { + (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index()) + } + + /// Classifies `r` as a universal region, returning `None` if this + /// is not a member of this set of universal regions. + pub fn region_classification(&self, r: RegionVid) -> Option { + let index = r.index(); + if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index) { + Some(RegionClassification::Global) + } else if (self.first_extern_index..self.first_local_index).contains(&index) { + Some(RegionClassification::External) + } else if (self.first_local_index..self.num_universals).contains(&index) { + Some(RegionClassification::Local) + } else { + None + } + } + + /// Returns an iterator over all the RegionVids corresponding to + /// universally quantified free regions. + pub fn universal_regions(&self) -> impl Iterator { + (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new) + } + + /// Returns `true` if `r` is classified as an local region. + pub fn is_local_free_region(&self, r: RegionVid) -> bool { + self.region_classification(r) == Some(RegionClassification::Local) + } + + /// Returns the number of universal regions created in any category. + pub fn len(&self) -> usize { + self.num_universals + } + + /// Returns the number of global plus external universal regions. + /// For closures, these are the regions that appear free in the + /// closure type (versus those bound in the closure + /// signature). They are therefore the regions between which the + /// closure may impose constraints that its creator must verify. + pub fn num_global_and_external_regions(&self) -> usize { + self.first_local_index + } + + /// Gets an iterator over all the early-bound regions that have names. + pub fn named_universal_regions<'s>( + &'s self, + ) -> impl Iterator, ty::RegionVid)> + 's { + self.indices.indices.iter().map(|(&r, &v)| (r, v)) + } + + /// See `UniversalRegionIndices::to_region_vid`. + pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { + if let ty::ReEmpty(ty::UniverseIndex::ROOT) = r { + self.root_empty + } else { + self.indices.to_region_vid(r) + } + } + + /// As part of the NLL unit tests, you can annotate a function with + /// `#[rustc_regions]`, and we will emit information about the region + /// inference context and -- in particular -- the external constraints + /// that this region imposes on others. The methods in this file + /// handle the part about dumping the inference context internal + /// state. + crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) { + match self.defining_ty { + DefiningTy::Closure(def_id, substs) => { + err.note(&format!( + "defining type: {} with closure substs {:#?}", + tcx.def_path_str_with_substs(def_id, substs), + &substs[tcx.generics_of(def_id).parent_count..], + )); + + // FIXME: It'd be nice to print the late-bound regions + // here, but unfortunately these wind up stored into + // tests, and the resulting print-outs include def-ids + // and other things that are not stable across tests! + // So we just include the region-vid. Annoying. + let closure_base_def_id = tcx.closure_base_def_id(def_id); + for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); + }); + } + DefiningTy::Generator(def_id, substs, _) => { + err.note(&format!( + "defining type: {} with generator substs {:#?}", + tcx.def_path_str_with_substs(def_id, substs), + &substs[tcx.generics_of(def_id).parent_count..], + )); + + // FIXME: As above, we'd like to print out the region + // `r` but doing so is not stable across architectures + // and so forth. + let closure_base_def_id = tcx.closure_base_def_id(def_id); + for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); + }); + } + DefiningTy::FnDef(def_id, substs) => { + err.note(&format!( + "defining type: {}", + tcx.def_path_str_with_substs(def_id, substs), + )); + } + DefiningTy::Const(def_id, substs) => { + err.note(&format!( + "defining constant type: {}", + tcx.def_path_str_with_substs(def_id, substs), + )); + } + } + } +} + +struct UniversalRegionsBuilder<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + mir_def: ty::WithOptConstParam, + mir_hir_id: HirId, + param_env: ty::ParamEnv<'tcx>, +} + +const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion; + +impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { + fn build(self) -> UniversalRegions<'tcx> { + debug!("build(mir_def={:?})", self.mir_def); + + let param_env = self.param_env; + debug!("build: param_env={:?}", param_env); + + assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); + + // Create the "global" region that is always free in all contexts: 'static. + let fr_static = self.infcx.next_nll_region_var(FR).to_region_vid(); + + // We've now added all the global regions. The next ones we + // add will be external. + let first_extern_index = self.infcx.num_region_vars(); + + let defining_ty = self.defining_ty(); + debug!("build: defining_ty={:?}", defining_ty); + + let mut indices = self.compute_indices(fr_static, defining_ty); + debug!("build: indices={:?}", indices); + + let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + + // If this is a closure or generator, then the late-bound regions from the enclosing + // function are actually external regions to us. For example, here, 'a is not local + // to the closure c (although it is local to the fn foo): + // fn foo<'a>() { + // let c = || { let x: &'a u32 = ...; } + // } + if self.mir_def.did.to_def_id() != closure_base_def_id { + self.infcx + .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices) + } + + let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); + + // "Liberate" the late-bound regions. These correspond to + // "local" free regions. + let first_local_index = self.infcx.num_region_vars(); + let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( + FR, + self.mir_def.did, + bound_inputs_and_output, + &mut indices, + ); + // Converse of above, if this is a function then the late-bound regions declared on its + // signature are local to the fn. + if self.mir_def.did.to_def_id() == closure_base_def_id { + self.infcx + .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices); + } + + let (unnormalized_output_ty, mut unnormalized_input_tys) = + inputs_and_output.split_last().unwrap(); + + // C-variadic fns also have a `VaList` input that's not listed in the signature + // (as it's created inside the body itself, not passed in from outside). + if let DefiningTy::FnDef(def_id, _) = defining_ty { + if self.infcx.tcx.fn_sig(def_id).c_variadic() { + let va_list_did = self.infcx.tcx.require_lang_item( + LangItem::VaList, + Some(self.infcx.tcx.def_span(self.mir_def.did)), + ); + let region = self + .infcx + .tcx + .mk_region(ty::ReVar(self.infcx.next_nll_region_var(FR).to_region_vid())); + let va_list_ty = + self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]); + + unnormalized_input_tys = self.infcx.tcx.mk_type_list( + unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)), + ); + } + } + + let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid(); + let num_universals = self.infcx.num_region_vars(); + + debug!("build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index); + debug!("build: extern regions = {}..{}", first_extern_index, first_local_index); + debug!("build: local regions = {}..{}", first_local_index, num_universals); + + let yield_ty = match defining_ty { + DefiningTy::Generator(_, substs, _) => Some(substs.as_generator().yield_ty()), + _ => None, + }; + + let root_empty = self + .infcx + .next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion) + .to_region_vid(); + + UniversalRegions { + indices, + fr_static, + fr_fn_body, + root_empty, + first_extern_index, + first_local_index, + num_universals, + defining_ty, + unnormalized_output_ty, + unnormalized_input_tys, + yield_ty, + } + } + + /// Returns the "defining type" of the current MIR; + /// see `DefiningTy` for details. + fn defining_ty(&self) -> DefiningTy<'tcx> { + let tcx = self.infcx.tcx; + let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + + match tcx.hir().body_owner_kind(self.mir_hir_id) { + BodyOwnerKind::Closure | BodyOwnerKind::Fn => { + let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id { + tcx.type_of(closure_base_def_id) + } else { + let tables = tcx.typeck(self.mir_def.did); + tables.node_type(self.mir_hir_id) + }; + + debug!("defining_ty (pre-replacement): {:?}", defining_ty); + + let defining_ty = + self.infcx.replace_free_regions_with_nll_infer_vars(FR, defining_ty); + + match *defining_ty.kind() { + ty::Closure(def_id, substs) => DefiningTy::Closure(def_id, substs), + ty::Generator(def_id, substs, movability) => { + DefiningTy::Generator(def_id, substs, movability) + } + ty::FnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs), + _ => span_bug!( + tcx.def_span(self.mir_def.did), + "expected defining type for `{:?}`: `{:?}`", + self.mir_def.did, + defining_ty + ), + } + } + + BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { + assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id); + let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); + let substs = + self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); + DefiningTy::Const(self.mir_def.did.to_def_id(), substs) + } + } + } + + /// Builds a hashmap that maps from the universal regions that are + /// in scope (as a `ty::Region<'tcx>`) to their indices (as a + /// `RegionVid`). The map returned by this function contains only + /// the early-bound regions. + fn compute_indices( + &self, + fr_static: RegionVid, + defining_ty: DefiningTy<'tcx>, + ) -> UniversalRegionIndices<'tcx> { + let tcx = self.infcx.tcx; + let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); + let fr_substs = match defining_ty { + DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => { + // In the case of closures, we rely on the fact that + // the first N elements in the ClosureSubsts are + // inherited from the `closure_base_def_id`. + // Therefore, when we zip together (below) with + // `identity_substs`, we will get only those regions + // that correspond to early-bound regions declared on + // the `closure_base_def_id`. + assert!(substs.len() >= identity_substs.len()); + assert_eq!(substs.regions().count(), identity_substs.regions().count()); + substs + } + + DefiningTy::FnDef(_, substs) | DefiningTy::Const(_, substs) => substs, + }; + + let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); + let subst_mapping = + iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid())); + + UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect() } + } + + fn compute_inputs_and_output( + &self, + indices: &UniversalRegionIndices<'tcx>, + defining_ty: DefiningTy<'tcx>, + ) -> ty::Binder<'tcx, &'tcx ty::List>> { + let tcx = self.infcx.tcx; + match defining_ty { + DefiningTy::Closure(def_id, substs) => { + assert_eq!(self.mir_def.did.to_def_id(), def_id); + let closure_sig = substs.as_closure().sig(); + let inputs_and_output = closure_sig.inputs_and_output(); + let bound_vars = tcx.mk_bound_variable_kinds( + inputs_and_output + .bound_vars() + .iter() + .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), + ); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BrEnv, + }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); + let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); + + // The "inputs" of the closure in the + // signature appear as a tuple. The MIR side + // flattens this tuple. + let (&output, tuplized_inputs) = + inputs_and_output.skip_binder().split_last().unwrap(); + assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); + let inputs = match tuplized_inputs[0].kind() { + ty::Tuple(inputs) => inputs, + _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]), + }; + + ty::Binder::bind_with_vars( + tcx.mk_type_list( + iter::once(closure_ty) + .chain(inputs.iter().map(|k| k.expect_ty())) + .chain(iter::once(output)), + ), + bound_vars, + ) + } + + DefiningTy::Generator(def_id, substs, movability) => { + assert_eq!(self.mir_def.did.to_def_id(), def_id); + let resume_ty = substs.as_generator().resume_ty(); + let output = substs.as_generator().return_ty(); + let generator_ty = tcx.mk_generator(def_id, substs, movability); + let inputs_and_output = + self.infcx.tcx.intern_type_list(&[generator_ty, resume_ty, output]); + ty::Binder::dummy(inputs_and_output) + } + + DefiningTy::FnDef(def_id, _) => { + let sig = tcx.fn_sig(def_id); + let sig = indices.fold_to_region_vids(tcx, sig); + sig.inputs_and_output() + } + + DefiningTy::Const(def_id, _) => { + // For a constant body, there are no inputs, and one + // "output" (the type of the constant). + assert_eq!(self.mir_def.did.to_def_id(), def_id); + let ty = tcx.type_of(self.mir_def.def_id_for_type_of()); + let ty = indices.fold_to_region_vids(tcx, ty); + ty::Binder::dummy(tcx.intern_type_list(&[ty])) + } + } + } +} + +trait InferCtxtExt<'tcx> { + fn replace_free_regions_with_nll_infer_vars( + &self, + origin: NllRegionVariableOrigin, + value: T, + ) -> T + where + T: TypeFoldable<'tcx>; + + fn replace_bound_regions_with_nll_infer_vars( + &self, + origin: NllRegionVariableOrigin, + all_outlive_scope: LocalDefId, + value: ty::Binder<'tcx, T>, + indices: &mut UniversalRegionIndices<'tcx>, + ) -> T + where + T: TypeFoldable<'tcx>; + + fn replace_late_bound_regions_with_nll_infer_vars( + &self, + mir_def_id: LocalDefId, + indices: &mut UniversalRegionIndices<'tcx>, + ); +} + +impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { + fn replace_free_regions_with_nll_infer_vars( + &self, + origin: NllRegionVariableOrigin, + value: T, + ) -> T + where + T: TypeFoldable<'tcx>, + { + self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin)) + } + + fn replace_bound_regions_with_nll_infer_vars( + &self, + origin: NllRegionVariableOrigin, + all_outlive_scope: LocalDefId, + value: ty::Binder<'tcx, T>, + indices: &mut UniversalRegionIndices<'tcx>, + ) -> T + where + T: TypeFoldable<'tcx>, + { + debug!( + "replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})", + value, all_outlive_scope, + ); + let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { + debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br); + let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { + scope: all_outlive_scope.to_def_id(), + bound_region: br.kind, + })); + let region_vid = self.next_nll_region_var(origin); + indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); + debug!( + "replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}", + liberated_region, region_vid + ); + region_vid + }); + value + } + + /// Finds late-bound regions that do not appear in the parameter listing and adds them to the + /// indices vector. Typically, we identify late-bound regions as we process the inputs and + /// outputs of the closure/function. However, sometimes there are late-bound regions which do + /// not appear in the fn parameters but which are nonetheless in scope. The simplest case of + /// this are unused functions, like fn foo<'a>() { } (see e.g., #51351). Despite not being used, + /// users can still reference these regions (e.g., let x: &'a u32 = &22;), so we need to create + /// entries for them and store them in the indices map. This code iterates over the complete + /// set of late-bound regions and checks for any that we have not yet seen, adding them to the + /// inputs vector. + fn replace_late_bound_regions_with_nll_infer_vars( + &self, + mir_def_id: LocalDefId, + indices: &mut UniversalRegionIndices<'tcx>, + ) { + debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); + let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id()); + for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| { + debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); + if !indices.indices.contains_key(&r) { + let region_vid = self.next_nll_region_var(FR); + indices.insert_late_bound_region(r, region_vid.to_region_vid()); + } + }); + } +} + +impl<'tcx> UniversalRegionIndices<'tcx> { + /// Initially, the `UniversalRegionIndices` map contains only the + /// early-bound regions in scope. Once that is all setup, we come + /// in later and instantiate the late-bound regions, and then we + /// insert the `ReFree` version of those into the map as + /// well. These are used for error reporting. + fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) { + debug!("insert_late_bound_region({:?}, {:?})", r, vid); + self.indices.insert(r, vid); + } + + /// Converts `r` into a local inference variable: `r` can either + /// by a `ReVar` (i.e., already a reference to an inference + /// variable) or it can be `'static` or some early-bound + /// region. This is useful when taking the results from + /// type-checking and trait-matching, which may sometimes + /// reference those regions from the `ParamEnv`. It is also used + /// during initialization. Relies on the `indices` map having been + /// fully initialized. + pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { + if let ty::ReVar(..) = r { + r.to_region_vid() + } else { + *self + .indices + .get(&r) + .unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r)) + } + } + + /// Replaces all free regions in `value` with region vids, as + /// returned by `to_region_vid`. + pub fn fold_to_region_vids(&self, tcx: TyCtxt<'tcx>, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + tcx.fold_regions(value, &mut false, |region, _| { + tcx.mk_region(ty::ReVar(self.to_region_vid(region))) + }) + } +} + +/// Iterates over the late-bound regions defined on fn_def_id and +/// invokes `f` with the liberated form of each one. +fn for_each_late_bound_region_defined_on<'tcx>( + tcx: TyCtxt<'tcx>, + fn_def_id: DefId, + mut f: impl FnMut(ty::Region<'tcx>), +) { + if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) { + for &late_bound in late_bounds.iter() { + let hir_id = HirId { owner, local_id: late_bound }; + let name = tcx.hir().name(hir_id); + let region_def_id = tcx.hir().local_def_id(hir_id); + let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { + scope: owner.to_def_id(), + bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name), + })); + f(liberated_region); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/used_muts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/used_muts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_borrowck/src/used_muts.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_borrowck/src/used_muts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,110 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{ + Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind, +}; + +use crate::MirBorrowckCtxt; + +impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { + /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes + /// of the `unused_mut` lint. + /// + /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and + /// used from borrow checking. This function looks for assignments into these locals from + /// user-declared locals and adds those user-defined locals to the `used_mut` set. This can + /// occur due to a rare case involving upvars in closures. + /// + /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals + /// (not arguments) that have not already been marked as being used. + /// This function then looks for assignments from statements or the terminator into the locals + /// from this set and removes them from the set. This leaves only those locals that have not + /// been assigned to - this set is used as a proxy for locals that were not initialized due to + /// unreachable code. These locals are then considered "used" to silence the lint for them. + /// See #55344 for context. + crate fn gather_used_muts( + &mut self, + temporary_used_locals: FxHashSet, + mut never_initialized_mut_locals: FxHashSet, + ) { + { + let mut visitor = GatherUsedMutsVisitor { + temporary_used_locals, + never_initialized_mut_locals: &mut never_initialized_mut_locals, + mbcx: self, + }; + visitor.visit_body(&visitor.mbcx.body); + } + + // Take the union of the existed `used_mut` set with those variables we've found were + // never initialized. + debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals); + self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect(); + } +} + +/// MIR visitor for collecting used mutable variables. +/// The 'visit lifetime represents the duration of the MIR walk. +struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { + temporary_used_locals: FxHashSet, + never_initialized_mut_locals: &'visit mut FxHashSet, + mbcx: &'visit mut MirBorrowckCtxt<'cx, 'tcx>, +} + +impl GatherUsedMutsVisitor<'_, '_, '_> { + fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) { + // Remove any locals that we found were initialized from the + // `never_initialized_mut_locals` set. At the end, the only remaining locals will + // be those that were never initialized - we will consider those as being used as + // they will either have been removed by unreachable code optimizations; or linted + // as unused variables. + self.never_initialized_mut_locals.remove(&into.local); + } +} + +impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + debug!("visit_terminator: terminator={:?}", terminator); + match &terminator.kind { + TerminatorKind::Call { destination: Some((into, _)), .. } => { + self.remove_never_initialized_mut_locals(*into); + } + TerminatorKind::DropAndReplace { place, .. } => { + self.remove_never_initialized_mut_locals(*place); + } + _ => {} + } + + self.super_terminator(terminator, location); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + if let StatementKind::Assign(box (into, _)) = &statement.kind { + debug!( + "visit_statement: statement={:?} local={:?} \ + never_initialized_mut_locals={:?}", + statement, into.local, self.never_initialized_mut_locals + ); + self.remove_never_initialized_mut_locals(*into); + } + + self.super_statement(statement, location); + } + + fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) { + if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) { + // Propagate the Local assigned at this Location as a used mutable local variable + for moi in &self.mbcx.move_data.loc_map[location] { + let mpi = &self.mbcx.move_data.moves[*moi].path; + let path = &self.mbcx.move_data.move_paths[*mpi]; + debug!( + "assignment of {:?} to {:?}, adding {:?} to used mutable set", + path.place, local, path.place + ); + if let Some(user_local) = path.place.as_local() { + self.mbcx.used_mut.insert(user_local); + } + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_builtin_macros" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/asm.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/asm.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/asm.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/asm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -117,6 +117,10 @@ let mut explicit_reg = false; let op = if !is_global_asm && p.eat_keyword(kw::In) { let reg = parse_reg(&mut p, &mut explicit_reg)?; + if p.eat_keyword(kw::Underscore) { + let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands"); + return Err(err); + } let expr = p.parse_expr()?; ast::InlineAsmOperand::In { reg, expr } } else if !is_global_asm && p.eat_keyword(sym::out) { @@ -129,6 +133,10 @@ ast::InlineAsmOperand::Out { reg, expr, late: true } } else if !is_global_asm && p.eat_keyword(sym::inout) { let reg = parse_reg(&mut p, &mut explicit_reg)?; + if p.eat_keyword(kw::Underscore) { + let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands"); + return Err(err); + } let expr = p.parse_expr()?; if p.eat(&token::FatArrow) { let out_expr = @@ -139,6 +147,10 @@ } } else if !is_global_asm && p.eat_keyword(sym::inlateout) { let reg = parse_reg(&mut p, &mut explicit_reg)?; + if p.eat_keyword(kw::Underscore) { + let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands"); + return Err(err); + } let expr = p.parse_expr()?; if p.eat(&token::FatArrow) { let out_expr = @@ -510,7 +522,7 @@ match expr_to_spanned_string(ecx, template_expr, msg) { Ok(template_part) => template_part, Err(err) => { - if let Some(mut err) = err { + if let Some((mut err, _)) = err { err.emit(); } return None; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/cfg_eval.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/cfg_eval.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/cfg_eval.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/cfg_eval.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,7 @@ use rustc_ast as ast; use rustc_ast::mut_visit::MutVisitor; +use rustc_ast::ptr::P; use rustc_ast::tokenstream::CanSynthesizeMissingTokens; use rustc_ast::visit::Visitor; use rustc_ast::{mut_visit, visit}; @@ -9,10 +10,10 @@ use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::config::StripUnconfigured; use rustc_expand::configure; +use rustc_feature::Features; use rustc_parse::parser::ForceCollect; use rustc_session::utils::FlattenNonterminals; - -use rustc_ast::ptr::P; +use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; @@ -24,21 +25,19 @@ annotatable: Annotatable, ) -> Vec { check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval); - vec![cfg_eval(ecx, annotatable)] + vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)] } -crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable { - CfgEval { - cfg: &mut StripUnconfigured { - sess: ecx.sess, - features: ecx.ecfg.features, - config_tokens: true, - }, - } - .configure_annotatable(annotatable) - // Since the item itself has already been configured by the `InvocationCollector`, - // we know that fold result vector will contain exactly one element. - .unwrap() +crate fn cfg_eval( + sess: &Session, + features: Option<&Features>, + annotatable: Annotatable, +) -> Annotatable { + CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } } + .configure_annotatable(annotatable) + // Since the item itself has already been configured by the `InvocationCollector`, + // we know that fold result vector will contain exactly one element. + .unwrap() } struct CfgEval<'a, 'b> { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/concat_idents.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/concat_idents.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/concat_idents.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/concat_idents.rs 2021-11-29 19:27:11.000000000 +0000 @@ -12,7 +12,7 @@ tts: TokenStream, ) -> Box { if tts.is_empty() { - cx.span_err(sp, "concat_idents! takes 1 or more arguments."); + cx.span_err(sp, "concat_idents! takes 1 or more arguments"); return DummyResult::any(sp); } @@ -22,7 +22,7 @@ match e { TokenTree::Token(Token { kind: token::Comma, .. }) => {} _ => { - cx.span_err(sp, "concat_idents! expecting comma."); + cx.span_err(sp, "concat_idents! expecting comma"); return DummyResult::any(sp); } } @@ -34,7 +34,7 @@ } } - cx.span_err(sp, "concat_idents! requires ident args."); + cx.span_err(sp, "concat_idents! requires ident args"); return DummyResult::any(sp); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/derive.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/derive.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/derive.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/derive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,13 @@ use crate::cfg_eval::cfg_eval; -use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast as ast; +use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_session::Session; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; crate struct Expander; @@ -26,8 +27,7 @@ return ExpandResult::Ready(vec![item]); } - let item = cfg_eval(ecx, item); - + let (sess, features) = (ecx.sess, ecx.ecfg.features); let result = ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { let template = @@ -40,7 +40,8 @@ template, ); - attr.meta_item_list() + let mut resolutions: Vec<_> = attr + .meta_item_list() .unwrap_or_default() .into_iter() .filter_map(|nested_meta| match nested_meta { @@ -56,8 +57,21 @@ report_path_args(sess, &meta); meta.path }) - .map(|path| (path, item.clone(), None)) - .collect() + .map(|path| (path, dummy_annotatable(), None)) + .collect(); + + // Do not configure or clone items unless necessary. + match &mut resolutions[..] { + [] => {} + [(_, first_item, _), others @ ..] => { + *first_item = cfg_eval(sess, features, item.clone()); + for (_, item, _) in others { + *item = first_item.clone(); + } + } + } + + resolutions }); match result { @@ -67,6 +81,18 @@ } } +// The cheapest `Annotatable` to construct. +fn dummy_annotatable() -> Annotatable { + Annotatable::GenericParam(ast::GenericParam { + id: ast::DUMMY_NODE_ID, + ident: Ident::invalid(), + attrs: Default::default(), + bounds: Default::default(), + is_placeholder: false, + kind: GenericParamKind::Lifetime, + }) +} + fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { let item_kind = match item { Annotatable::Item(item) => Some(&item.kind), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/deriving/debug.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/deriving/debug.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/deriving/debug.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/deriving/debug.rs 2021-11-29 19:27:11.000000000 +0000 @@ -65,15 +65,29 @@ // We want to make sure we have the ctxt set so that we can use unstable methods let span = cx.with_def_site_ctxt(span); let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); + let fmt = substr.nonself_args[0].clone(); + + // Special fast path for unit variants. In the common case of an enum that is entirely unit + // variants (i.e. a C-like enum), this fast path allows LLVM to eliminate the entire switch in + // favor of a lookup table. + if let ast::VariantData::Unit(..) = vdata { + let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]); + let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]); + let stmts = vec![cx.stmt_expr(expr)]; + let block = cx.block(span, stmts); + return cx.expr_block(block); + } + let builder = Ident::new(sym::debug_trait_builder, span); let builder_expr = cx.expr_ident(span, builder); - let fmt = substr.nonself_args[0].clone(); - let mut stmts = Vec::with_capacity(fields.len() + 2); let fn_path_finish; match vdata { - ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { + ast::VariantData::Unit(..) => { + cx.span_bug(span, "unit variants should have been handled above"); + } + ast::VariantData::Tuple(..) => { // tuple struct/"normal" variant let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]); let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -332,20 +332,27 @@ RefCell::new(f) } +struct TypeParameter { + bound_generic_params: Vec, + ty: P, +} + /// This method helps to extract all the type parameters referenced from a /// type. For a type parameter ``, it looks for either a `TyPath` that /// is not global and starts with `T`, or a `TyQPath`. +/// Also include bound generic params from the input type. fn find_type_parameters( ty: &ast::Ty, ty_param_names: &[Symbol], cx: &ExtCtxt<'_>, -) -> Vec> { +) -> Vec { use rustc_ast::visit; struct Visitor<'a, 'b> { cx: &'a ExtCtxt<'b>, ty_param_names: &'a [Symbol], - types: Vec>, + bound_generic_params_stack: Vec, + type_params: Vec, } impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { @@ -353,7 +360,10 @@ if let ast::TyKind::Path(_, ref path) = ty.kind { if let Some(segment) = path.segments.first() { if self.ty_param_names.contains(&segment.ident.name) { - self.types.push(P(ty.clone())); + self.type_params.push(TypeParameter { + bound_generic_params: self.bound_generic_params_stack.clone(), + ty: P(ty.clone()), + }); } } } @@ -361,15 +371,35 @@ visit::walk_ty(self, ty) } + // Place bound generic params on a stack, to extract them when a type is encountered. + fn visit_poly_trait_ref( + &mut self, + trait_ref: &'a ast::PolyTraitRef, + modifier: &'a ast::TraitBoundModifier, + ) { + let stack_len = self.bound_generic_params_stack.len(); + self.bound_generic_params_stack + .extend(trait_ref.bound_generic_params.clone().into_iter()); + + visit::walk_poly_trait_ref(self, trait_ref, modifier); + + self.bound_generic_params_stack.truncate(stack_len); + } + fn visit_mac_call(&mut self, mac: &ast::MacCall) { self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros"); } } - let mut visitor = Visitor { cx, ty_param_names, types: Vec::new() }; + let mut visitor = Visitor { + cx, + ty_param_names, + bound_generic_params_stack: Vec::new(), + type_params: Vec::new(), + }; visit::Visitor::visit_ty(&mut visitor, ty); - visitor.types + visitor.type_params } impl<'a> TraitDef<'a> { @@ -564,7 +594,7 @@ GenericParamKind::Const { ty, kw_span, .. } => { let const_nodefault_kind = GenericParamKind::Const { ty: ty.clone(), - kw_span: kw_span.clone(), + kw_span: *kw_span, // We can't have default values inside impl block default: None, @@ -617,11 +647,11 @@ ty_params.map(|ty_param| ty_param.ident.name).collect(); for field_ty in field_tys { - let tys = find_type_parameters(&field_ty, &ty_param_names, cx); + let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); - for ty in tys { + for field_ty_param in field_ty_params { // if we have already handled this type, skip it - if let ast::TyKind::Path(_, ref p) = ty.kind { + if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind { if p.segments.len() == 1 && ty_param_names.contains(&p.segments[0].ident.name) { @@ -639,8 +669,8 @@ let predicate = ast::WhereBoundPredicate { span: self.span, - bound_generic_params: Vec::new(), - bounded_ty: ty, + bound_generic_params: field_ty_param.bound_generic_params, + bounded_ty: field_ty_param.ty, bounds, }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ macro_rules! assert_eq_pnsat { ($lhs:expr, $rhs:expr) => { assert_eq!( - pns($lhs).and_then(|(s, _)| s.translate()), + pns($lhs).and_then(|(s, _)| s.translate().ok()), $rhs.map(>::from) ) }; @@ -98,7 +98,7 @@ #[test] fn test_iter() { let s = "The %d'th word %% is: `%.*s` %!\n"; - let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect(); + let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); assert_eq!( subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), vec![Some("{}"), None, Some("{:.*}"), None] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ macro_rules! assert_eq_pnsat { ($lhs:expr, $rhs:expr) => { assert_eq!( - pns($lhs).and_then(|(f, _)| f.translate()), + pns($lhs).and_then(|(f, _)| f.translate().ok()), $rhs.map(>::from) ) }; @@ -37,7 +37,7 @@ fn test_iter() { use super::iter_subs; let s = "The $0'th word $$ is: `$WORD` $!\n"; - let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect(); + let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); assert_eq!( subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), vec![Some("{0}"), None, Some("{WORD}")] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format_foreign.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -pub mod printf { +pub(crate) mod printf { use super::strcursor::StrCursor as Cur; use rustc_span::InnerSpan; @@ -36,10 +36,10 @@ /// /// This ignores cases where the substitution does not have an exact equivalent, or where /// the substitution would be unnecessary. - pub fn translate(&self) -> Option { + pub fn translate(&self) -> Result> { match *self { Substitution::Format(ref fmt) => fmt.translate(), - Substitution::Escape => None, + Substitution::Escape => Err(None), } } } @@ -68,9 +68,9 @@ impl Format<'_> { /// Translate this directive into an equivalent Rust formatting directive. /// - /// Returns `None` in cases where the `printf` directive does not have an exact Rust + /// Returns `Err` in cases where the `printf` directive does not have an exact Rust /// equivalent, rather than guessing. - pub fn translate(&self) -> Option { + pub fn translate(&self) -> Result> { use std::fmt::Write; let (c_alt, c_zero, c_left, c_plus) = { @@ -84,7 +84,12 @@ '0' => c_zero = true, '-' => c_left = true, '+' => c_plus = true, - _ => return None, + _ => { + return Err(Some(format!( + "the flag `{}` is unknown or unsupported", + c + ))); + } } } (c_alt, c_zero, c_left, c_plus) @@ -104,7 +109,9 @@ let width = match self.width { Some(Num::Next) => { // NOTE: Rust doesn't support this. - return None; + return Err(Some( + "you have to use a positional or named parameter for the width".to_string(), + )); } w @ Some(Num::Arg(_)) => w, w @ Some(Num::Num(_)) => w, @@ -125,13 +132,21 @@ "p" => (Some(self.type_), false, true), "g" => (Some("e"), true, false), "G" => (Some("E"), true, false), - _ => return None, + _ => { + return Err(Some(format!( + "the conversion specifier `{}` is unknown or unsupported", + self.type_ + ))); + } }; let (fill, width, precision) = match (is_int, width, precision) { (true, Some(_), Some(_)) => { // Rust can't duplicate this insanity. - return None; + return Err(Some( + "width and precision cannot both be specified for integer conversions" + .to_string(), + )); } (true, None, Some(p)) => (Some("0"), Some(p), None), (true, w, None) => (fill, w, None), @@ -169,7 +184,17 @@ s.push('{'); if let Some(arg) = self.parameter { - write!(s, "{}", arg.checked_sub(1)?).ok()?; + match write!( + s, + "{}", + match arg.checked_sub(1) { + Some(a) => a, + None => return Err(None), + } + ) { + Err(_) => return Err(None), + _ => {} + } } if has_options { @@ -199,12 +224,18 @@ } if let Some(width) = width { - width.translate(&mut s).ok()?; + match width.translate(&mut s) { + Err(_) => return Err(None), + _ => {} + } } if let Some(precision) = precision { s.push('.'); - precision.translate(&mut s).ok()?; + match precision.translate(&mut s) { + Err(_) => return Err(None), + _ => {} + } } if let Some(type_) = type_ { @@ -213,7 +244,7 @@ } s.push('}'); - Some(s) + Ok(s) } } @@ -623,11 +654,11 @@ } } - pub fn translate(&self) -> Option { + pub fn translate(&self) -> Result> { match *self { - Substitution::Ordinal(n, _) => Some(format!("{{{}}}", n)), - Substitution::Name(n, _) => Some(format!("{{{}}}", n)), - Substitution::Escape(_) => None, + Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)), + Substitution::Name(n, _) => Ok(format!("{{{}}}", n)), + Substitution::Escape(_) => Err(None), } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/format.rs 2021-11-29 19:27:11.000000000 +0000 @@ -164,23 +164,22 @@ p.clear_expected_tokens(); } - // `Parser::expect` tries to recover using the - // `Parser::unexpected_try_recover` function. This function is able - // to recover if the expected token is a closing delimiter. - // - // As `,` is not a closing delimiter, it will always return an `Err` - // variant. - let mut err = p.expect(&token::Comma).unwrap_err(); - - match token::TokenKind::Comma.similar_tokens() { - Some(tks) if tks.contains(&p.token.kind) => { - // If a similar token is found, then it may be a typo. We - // consider it as a comma, and continue parsing. - err.emit(); - p.bump(); + match p.expect(&token::Comma) { + Err(mut err) => { + match token::TokenKind::Comma.similar_tokens() { + Some(tks) if tks.contains(&p.token.kind) => { + // If a similar token is found, then it may be a typo. We + // consider it as a comma, and continue parsing. + err.emit(); + p.bump(); + } + // Otherwise stop the parsing and return the error. + _ => return Err(err), + } + } + Ok(recovered) => { + assert!(recovered); } - // Otherwise stop the parsing and return the error. - _ => return Err(err), } } first = false; @@ -845,8 +844,7 @@ self.ecx.expr_match(self.macsp, head, vec![arm]) }; - let ident = Ident::from_str_and_span("args", self.macsp); - let args_slice = self.ecx.expr_ident(self.macsp, ident); + let args_slice = self.ecx.expr_addr_of(self.macsp, args_match); // Now create the fmt::Arguments struct with all our locals we created. let (fn_name, fn_args) = if self.all_pieces_simple { @@ -856,25 +854,22 @@ // nonstandard placeholders, if there are any. let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces); - ("new_v1_formatted", vec![pieces, args_slice, fmt]) + let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]); + let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new()); + let unsafe_expr = self.ecx.expr_block(P(ast::Block { + stmts: vec![self.ecx.stmt_expr(unsafe_arg)], + id: ast::DUMMY_NODE_ID, + rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), + span: self.macsp, + tokens: None, + could_be_bare_literal: false, + })); + + ("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr]) }; let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]); - let arguments = self.ecx.expr_call_global(self.macsp, path, fn_args); - let body = self.ecx.expr_block(P(ast::Block { - stmts: vec![self.ecx.stmt_expr(arguments)], - id: ast::DUMMY_NODE_ID, - rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), - span: self.macsp, - tokens: None, - could_be_bare_literal: false, - })); - - let ident = Ident::from_str_and_span("args", self.macsp); - let binding_mode = ast::BindingMode::ByRef(ast::Mutability::Not); - let pat = self.ecx.pat_ident_binding_mode(self.macsp, ident, binding_mode); - let arm = self.ecx.arm(self.macsp, pat, body); - self.ecx.expr_match(self.macsp, args_match, vec![arm]) + self.ecx.expr_call_global(self.macsp, path, fn_args) } fn format_arg( @@ -964,17 +959,19 @@ } Ok(fmt) => fmt, Err(err) => { - if let Some(mut err) = err { + if let Some((mut err, suggested)) = err { let sugg_fmt = match args.len() { 0 => "{}".to_string(), _ => format!("{}{{}}", "{} ".repeat(args.len())), }; - err.span_suggestion( - fmt_sp.shrink_to_lo(), - "you might be missing a string literal to format with", - format!("\"{}\", ", sugg_fmt), - Applicability::MaybeIncorrect, - ); + if !suggested { + err.span_suggestion( + fmt_sp.shrink_to_lo(), + "you might be missing a string literal to format with", + format!("\"{}\", ", sugg_fmt), + Applicability::MaybeIncorrect, + ); + } err.emit(); } return DummyResult::raw_expr(sp, true); @@ -1157,11 +1154,12 @@ // account for `"` and account for raw strings `r#` let padding = str_style.map(|i| i + 2).unwrap_or(1); for sub in foreign::$kind::iter_subs(fmt_str, padding) { - let trn = match sub.translate() { - Some(trn) => trn, + let (trn, success) = match sub.translate() { + Ok(trn) => (trn, true), + Err(Some(msg)) => (msg, false), // If it has no translation, don't call it out specifically. - None => continue, + _ => continue, }; let pos = sub.position(); @@ -1178,9 +1176,24 @@ if let Some(inner_sp) = pos { let sp = fmt_sp.from_inner(inner_sp); - suggestions.push((sp, trn)); + + if success { + suggestions.push((sp, trn)); + } else { + diag.span_note( + sp, + &format!("format specifiers use curly braces, and {}", trn), + ); + } } else { - diag.help(&format!("`{}` should be written as `{}`", sub, trn)); + if success { + diag.help(&format!("`{}` should be written as `{}`", sub, trn)); + } else { + diag.note(&format!( + "`{}` should use curly braces, and {}", + sub, trn + )); + } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/test.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/test.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_builtin_macros/src/test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -382,7 +382,7 @@ .note( "errors in this attribute were erroneously \ allowed and will become a hard error in a \ - future release.", + future release", ) .emit(); ShouldPanic::Yes(None) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock 2021-11-29 19:27:11.000000000 +0000 @@ -4,9 +4,9 @@ [[package]] name = "addr2line" -version = "0.14.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" dependencies = [ "compiler_builtins", "gimli", @@ -40,9 +40,9 @@ [[package]] name = "cc" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cfg-if" @@ -56,7 +56,7 @@ [[package]] name = "compiler_builtins" -version = "0.1.46" +version = "0.1.50" dependencies = [ "rustc-std-workspace-core", ] @@ -99,9 +99,9 @@ [[package]] name = "gimli" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -132,14 +132,24 @@ [[package]] name = "libc" -version = "0.2.98" +version = "0.2.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" dependencies = [ "rustc-std-workspace-core", ] [[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] name = "miniz_oxide" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -154,11 +164,12 @@ [[package]] name = "object" -version = "0.22.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" dependencies = [ "compiler_builtins", + "memchr", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -195,9 +206,9 @@ [[package]] name = "rustc-demangle" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -286,9 +297,9 @@ [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/build_system/prepare.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/build_system/prepare.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/build_system/prepare.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/build_system/prepare.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,11 +28,11 @@ ); clone_repo( - "stdsimd", - "https://github.com/rust-lang/stdsimd", - "be96995d8ddec03fac9a0caf4d4c51c7fbc33507", + "portable-simd", + "https://github.com/rust-lang/portable-simd", + "8cf7a62e5d2552961df51e5200aaa5b7c890a4bf", ); - apply_patches("stdsimd", Path::new("stdsimd")); + apply_patches("portable-simd", Path::new("portable-simd")); clone_repo( "simple-raytracer", @@ -92,7 +92,7 @@ clone_repo( "build_sysroot/compiler-builtins", "https://github.com/rust-lang/compiler-builtins.git", - "0.1.46", + "0.1.50", ); apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins")); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/Cargo.lock rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/Cargo.lock --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/Cargo.lock 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/Cargo.lock 2021-11-29 19:27:11.000000000 +0000 @@ -33,16 +33,16 @@ [[package]] name = "cranelift-bforest" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", @@ -57,8 +57,8 @@ [[package]] name = "cranelift-codegen-meta" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -66,18 +66,18 @@ [[package]] name = "cranelift-codegen-shared" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" [[package]] name = "cranelift-entity" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" [[package]] name = "cranelift-frontend" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen", "log", @@ -87,8 +87,8 @@ [[package]] name = "cranelift-jit" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", @@ -104,8 +104,8 @@ [[package]] name = "cranelift-module" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", @@ -115,8 +115,8 @@ [[package]] name = "cranelift-native" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen", "libc", @@ -125,8 +125,8 @@ [[package]] name = "cranelift-object" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_codegen_cranelift" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["dylib"] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/clean_all.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/clean_all.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/clean_all.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/clean_all.sh 2021-11-29 19:27:11.000000000 +0000 @@ -3,4 +3,4 @@ rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} rm -rf target/ build/ perf.data{,.old} -rm -rf rand/ regex/ simple-raytracer/ stdsimd/ +rm -rf rand/ regex/ simple-raytracer/ portable-simd/ diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/docs/usage.md rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/docs/usage.md --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/docs/usage.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/docs/usage.md 2021-11-29 19:27:11.000000000 +0000 @@ -24,6 +24,8 @@ ## Jit mode +> âš âš âš  The JIT mode is highly experimental. It may be slower than AOT compilation due to lack of incremental compilation. It may also be hard to setup if you have cargo dependencies. âš âš âš  + In jit mode cg_clif will immediately execute your code without creating an executable file. > This requires all dependencies to be available as dynamic library. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/example/alloc_example.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/example/alloc_example.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/example/alloc_example.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/example/alloc_example.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler)] +#![feature(start, core_intrinsics, alloc_error_handler, box_syntax)] #![no_std] extern crate alloc; extern crate alloc_system; -use alloc::prelude::v1::*; +use alloc::boxed::Box; use alloc_system::System; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)] +#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)] #![no_core] #![allow(dead_code, non_camel_case_types)] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,152 @@ +From 6bfce5dc2cbf834c74dbccb7538adc08c6eb57e7 Mon Sep 17 00:00:00 2001 +From: bjorn3 +Date: Sun, 25 Jul 2021 18:39:31 +0200 +Subject: [PATCH] Disable unsupported tests + +--- + crates/core_simd/src/vector.rs | 2 ++ + crates/core_simd/src/math.rs | 4 ++++ + crates/core_simd/tests/masks.rs | 12 ------------ + crates/core_simd/tests/ops_macros.rs | 6 ++++++ + crates/core_simd/tests/round.rs | 2 ++ + 6 files changed, 15 insertions(+), 13 deletions(-) + +diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs +index 25c5309..2b3d819 100644 +--- a/crates/core_simd/src/vector.rs ++++ b/crates/core_simd/src/vector.rs +@@ -22,6 +22,7 @@ where + self.0 + } + ++ /* + /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. + /// If an index is out of bounds, that lane instead selects the value from the "or" vector. + /// ``` +@@ -150,6 +151,7 @@ where + // Cleared â˜¢ï¸ *mut T Zone + } + } ++ */ + } + + impl Copy for Simd +diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs +index 7290a28..e394730 100644 +--- a/crates/core_simd/src/math.rs ++++ b/crates/core_simd/src/math.rs +@@ -2,6 +2,7 @@ macro_rules! impl_uint_arith { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { + ++ /* + /// Lanewise saturating add. + /// + /// # Examples +@@ -38,6 +39,7 @@ macro_rules! impl_uint_arith { + pub fn saturating_sub(self, second: Self) -> Self { + unsafe { crate::intrinsics::simd_saturating_sub(self, second) } + } ++ */ + })+ + } + } +@@ -46,6 +48,7 @@ macro_rules! impl_int_arith { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { + ++ /* + /// Lanewise saturating add. + /// + /// # Examples +@@ -141,6 +144,7 @@ macro_rules! impl_int_arith { + pub fn saturating_neg(self) -> Self { + Self::splat(0).saturating_sub(self) + } ++ */ + })+ + } + } +diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs +index 61d8e44..2bccae2 100644 +--- a/crates/core_simd/tests/masks.rs ++++ b/crates/core_simd/tests/masks.rs +@@ -67,19 +67,6 @@ macro_rules! test_mask_api { + assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]); + assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask); + } +- +- #[cfg(feature = "generic_const_exprs")] +- #[test] +- fn roundtrip_bitmask_conversion() { +- let values = [ +- true, false, false, true, false, false, true, false, +- true, true, false, false, false, false, false, true, +- ]; +- let mask = core_simd::Mask::<$type, 16>::from_array(values); +- let bitmask = mask.to_bitmask(); +- assert_eq!(bitmask, [0b01001001, 0b10000011]); +- assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask); +- } + } + } + } +diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs +index cb39e73..fc0ebe1 100644 +--- a/crates/core_simd/tests/ops_macros.rs ++++ b/crates/core_simd/tests/ops_macros.rs +@@ -435,6 +435,7 @@ macro_rules! impl_float_tests { + ) + } + ++ /* + fn mul_add() { + test_helpers::test_ternary_elementwise( + &Vector::::mul_add, +@@ -442,6 +443,7 @@ macro_rules! impl_float_tests { + &|_, _, _| true, + ) + } ++ */ + + fn recip() { + test_helpers::test_unary_elementwise( +@@ -581,6 +585,7 @@ macro_rules! impl_float_tests { + }); + } + ++ /* + fn horizontal_max() { + test_helpers::test_1(&|x| { + let vmax = Vector::::from_array(x).horizontal_max(); +@@ -604,6 +609,7 @@ macro_rules! impl_float_tests { + Ok(()) + }); + } ++ */ + } + + #[cfg(feature = "std")] +diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs +index 37044a7..4cdc6b7 100644 +--- a/crates/core_simd/tests/round.rs ++++ b/crates/core_simd/tests/round.rs +@@ -25,6 +25,7 @@ macro_rules! float_rounding_test { + ) + } + ++ /* + fn round() { + test_helpers::test_unary_elementwise( + &Vector::::round, +@@ -32,6 +33,7 @@ macro_rules! float_rounding_test { + &|_| true, + ) + } ++ */ + + fn trunc() { + test_helpers::test_unary_elementwise( +-- +2.26.2.7.g19db9cfb68 + diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -From 6bfce5dc2cbf834c74dbccb7538adc08c6eb57e7 Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Sun, 25 Jul 2021 18:39:31 +0200 -Subject: [PATCH] Disable unsupported tests - ---- - crates/core_simd/src/array.rs | 2 ++ - crates/core_simd/src/lib.rs | 2 +- - crates/core_simd/src/math.rs | 4 ++++ - crates/core_simd/tests/masks.rs | 12 ------------ - crates/core_simd/tests/ops_macros.rs | 6 ++++++ - crates/core_simd/tests/round.rs | 2 ++ - 6 files changed, 15 insertions(+), 13 deletions(-) - -diff --git a/crates/core_simd/src/array.rs b/crates/core_simd/src/array.rs -index 25c5309..2b3d819 100644 ---- a/crates/core_simd/src/array.rs -+++ b/crates/core_simd/src/array.rs -@@ -22,6 +22,7 @@ where - #[must_use] - fn splat(val: Self::Scalar) -> Self; - -+ /* - /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. - /// If an index is out of bounds, that lane instead selects the value from the "or" vector. - /// ``` -@@ -150,6 +151,7 @@ where - // Cleared â˜¢ï¸ *mut T Zone - } - } -+ */ - } - - macro_rules! impl_simdarray_for { -diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs -index a64904d..299eb11 100644 ---- a/crates/core_simd/src/lib.rs -+++ b/crates/core_simd/src/lib.rs -@@ -1,7 +1,7 @@ - #![no_std] - #![allow(incomplete_features)] - #![feature( -- const_generics, -+ const_generics, - platform_intrinsics, - repr_simd, - simd_ffi, -diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs -index 7290a28..e394730 100644 ---- a/crates/core_simd/src/math.rs -+++ b/crates/core_simd/src/math.rs -@@ -2,6 +2,7 @@ macro_rules! impl_uint_arith { - ($(($name:ident, $n:ident)),+) => { - $( impl $name where Self: crate::LanesAtMost32 { - -+ /* - /// Lanewise saturating add. - /// - /// # Examples -@@ -38,6 +39,7 @@ macro_rules! impl_uint_arith { - pub fn saturating_sub(self, second: Self) -> Self { - unsafe { crate::intrinsics::simd_saturating_sub(self, second) } - } -+ */ - })+ - } - } -@@ -46,6 +48,7 @@ macro_rules! impl_int_arith { - ($(($name:ident, $n:ident)),+) => { - $( impl $name where Self: crate::LanesAtMost32 { - -+ /* - /// Lanewise saturating add. - /// - /// # Examples -@@ -141,6 +144,7 @@ macro_rules! impl_int_arith { - pub fn saturating_neg(self) -> Self { - Self::splat(0).saturating_sub(self) - } -+ */ - })+ - } - } -diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs -index 61d8e44..2bccae2 100644 ---- a/crates/core_simd/tests/masks.rs -+++ b/crates/core_simd/tests/masks.rs -@@ -67,18 +67,6 @@ macro_rules! test_mask_api { - assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]); - assert_eq!(core_simd::$name::<8>::from_int(int), mask); - } -- -- #[test] -- fn roundtrip_bitmask_conversion() { -- let values = [ -- true, false, false, true, false, false, true, false, -- true, true, false, false, false, false, false, true, -- ]; -- let mask = core_simd::$name::<16>::from_array(values); -- let bitmask = mask.to_bitmask(); -- assert_eq!(bitmask, [0b01001001, 0b10000011]); -- assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask); -- } - } - } - } -diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs -index cb39e73..fc0ebe1 100644 ---- a/crates/core_simd/tests/ops_macros.rs -+++ b/crates/core_simd/tests/ops_macros.rs -@@ -435,6 +435,7 @@ macro_rules! impl_float_tests { - ) - } - -+ /* - fn mul_add() { - test_helpers::test_ternary_elementwise( - &Vector::::mul_add, -@@ -442,6 +443,7 @@ macro_rules! impl_float_tests { - &|_, _, _| true, - ) - } -+ */ - - fn sqrt() { - test_helpers::test_unary_elementwise( -@@ -581,6 +585,7 @@ macro_rules! impl_float_tests { - }); - } - -+ /* - fn horizontal_max() { - test_helpers::test_1(&|x| { - let vmax = Vector::::from_array(x).horizontal_max(); -@@ -604,6 +609,7 @@ macro_rules! impl_float_tests { - Ok(()) - }); - } -+ */ - } - } - } -diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs -index 37044a7..4cdc6b7 100644 ---- a/crates/core_simd/tests/round.rs -+++ b/crates/core_simd/tests/round.rs -@@ -25,6 +25,7 @@ macro_rules! float_rounding_test { - ) - } - -+ /* - fn round() { - test_helpers::test_unary_elementwise( - &Vector::::round, -@@ -32,6 +33,7 @@ macro_rules! float_rounding_test { - &|_| true, - ) - } -+ */ - - fn trunc() { - test_helpers::test_unary_elementwise( --- -2.26.2.7.g19db9cfb68 - diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -From 6a4e6f5dc8c8a529a822eb9b57f9e57519595439 Mon Sep 17 00:00:00 2001 +From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 18 Feb 2021 18:45:28 +0100 Subject: [PATCH] Disable 128bit atomic operations @@ -8,7 +8,8 @@ library/core/src/panic/unwind_safe.rs | 6 ----- library/core/src/sync/atomic.rs | 38 --------------------------- library/core/tests/atomic.rs | 4 --- - 3 files changed, 48 deletions(-) + library/std/src/time/monotonic.rs | 6 +++-- + 4 files changed, 4 insertions(+), 50 deletions(-) diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 092b7cf..158cf71 100644 @@ -35,10 +36,10 @@ #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs -index 0194c58..25a0038 100644 +index d9de37e..8293fce 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -2229,44 +2229,6 @@ atomic_int! { +@@ -2234,44 +2234,6 @@ atomic_int! { "AtomicU64::new(0)", u64 AtomicU64 ATOMIC_U64_INIT } @@ -98,6 +99,38 @@ #[cfg(target_has_atomic = "ptr")] assert_eq!(align_of::(), size_of::()); #[cfg(target_has_atomic = "ptr")] +diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs +index fa96b7a..2854f9c 100644 +--- a/library/std/src/time/monotonic.rs ++++ b/library/std/src/time/monotonic.rs +@@ -5,7 +5,7 @@ pub(super) fn monotonize(raw: time::Instant) -> time::Instant { + inner::monotonize(raw) + } + +-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))] ++#[cfg(target_has_atomic = "64")] + pub mod inner { + use crate::sync::atomic::AtomicU64; + use crate::sync::atomic::Ordering::*; +@@ -70,6 +70,7 @@ pub mod inner { + } + } + ++/* + #[cfg(target_has_atomic = "128")] + pub mod inner { + use crate::sync::atomic::AtomicU128; +@@ -94,8 +95,9 @@ pub mod inner { + ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap() + } + } ++*/ + +-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))] ++#[cfg(not(target_has_atomic = "64"))] + pub mod inner { + use crate::cmp; + use crate::sys::time; -- 2.26.2.7.g19db9cfb68 diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/rust-toolchain rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/rust-toolchain --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/rust-toolchain 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/rust-toolchain 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-08-05" +channel = "nightly-2021-09-19" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs 2021-11-29 19:27:11.000000000 +0000 @@ -42,7 +42,7 @@ continue; } - if stack.contains("rustc_mir::monomorphize::partitioning::collect_and_partition_mono_items") + if stack.contains("rustc_monomorphize::partitioning::collect_and_partition_mono_items") || stack.contains("rustc_incremental::assert_dep_graph::assert_dep_graph") || stack.contains("rustc_symbol_mangling::test::report_symbol_names") { @@ -81,7 +81,7 @@ } const COLLECT_AND_PARTITION_MONO_ITEMS: &str = - "rustc_mir::monomorphize::partitioning::collect_and_partition_mono_items"; + "rustc_monomorphize::partitioning::collect_and_partition_mono_items"; if let Some(index) = stack.find(COLLECT_AND_PARTITION_MONO_ITEMS) { stack = &stack[..index + COLLECT_AND_PARTITION_MONO_ITEMS.len()]; } @@ -96,7 +96,7 @@ stack = &stack[..index + REPORT_SYMBOL_NAMES.len()]; } - const ENCODE_METADATA: &str = "rustc_middle::ty::context::TyCtxt::encode_metadata"; + const ENCODE_METADATA: &str = "rustc_metadata::rmeta::encoder::encode_metadata"; if let Some(index) = stack.find(ENCODE_METADATA) { stack = &stack[..index + ENCODE_METADATA.len()]; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ cargo install ripgrep rm -r src/test/ui/{extern/,panics/,unsized-locals/,thinlto/,simd*,*lto*.rs,linkage*,unwind-*.rs} || true -for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto" src/test/ui); do +for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto|// needs-asm-support" src/test/ui); do rm $test done diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/tests.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/tests.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/tests.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/scripts/tests.sh 2021-11-29 19:27:11.000000000 +0000 @@ -137,8 +137,8 @@ fi popd - pushd stdsimd - echo "[TEST] rust-lang/stdsimd" + pushd portable-simd + echo "[TEST] rust-lang/portable-simd" ../build/cargo clean ../build/cargo build --all-targets --target $TARGET_TRIPLE if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/abi/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/abi/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/abi/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/abi/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ mod returning; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::ty::layout::FnAbiExt; +use rustc_middle::ty::layout::FnAbiOf; use rustc_target::abi::call::{Conv, FnAbi}; use rustc_target::spec::abi::Abi; @@ -53,7 +53,11 @@ inst: Instance<'tcx>, ) -> Signature { assert!(!inst.substs.needs_infer()); - clif_sig_from_fn_abi(tcx, triple, &FnAbi::of_instance(&RevealAllLayoutCx(tcx), inst, &[])) + clif_sig_from_fn_abi( + tcx, + triple, + &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()), + ) } /// Instance must be monomorphized @@ -305,13 +309,13 @@ span: Span, func: &Operand<'tcx>, args: &[Operand<'tcx>], - destination: Option<(Place<'tcx>, BasicBlock)>, + mir_dest: Option<(Place<'tcx>, BasicBlock)>, ) { let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx)); let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx)); - let destination = destination.map(|(place, bb)| (codegen_place(fx, place), bb)); + let destination = mir_dest.map(|(place, bb)| (codegen_place(fx, place), bb)); // Handle special calls like instrinsics and empty drop glue. let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() { @@ -350,14 +354,13 @@ }; let extra_args = &args[fn_sig.inputs().len()..]; - let extra_args = extra_args - .iter() - .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))) - .collect::>(); + let extra_args = fx + .tcx + .mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))); let fn_abi = if let Some(instance) = instance { - FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args) + RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args) } else { - FnAbi::of_fn_ptr(&RevealAllLayoutCx(fx.tcx), fn_ty.fn_sig(fx.tcx), &extra_args) + RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args) }; let is_cold = instance @@ -525,7 +528,8 @@ def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), substs: drop_instance.substs, }; - let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), virtual_drop, &[]); + let fn_abi = + RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty()); let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi); let sig = fx.bcx.import_signature(sig); @@ -534,7 +538,8 @@ _ => { assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _))); - let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), drop_instance, &[]); + let fn_abi = + RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty()); let arg_value = drop_place.place_ref( fx, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs 2021-11-29 19:27:11.000000000 +0000 @@ -92,9 +92,9 @@ fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> { match self.mode { PassMode::Ignore => smallvec![], - PassMode::Direct(attrs) => match &self.layout.abi { + PassMode::Direct(attrs) => match self.layout.abi { Abi::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param( - AbiParam::new(scalar_to_clif_type(tcx, scalar.clone())), + AbiParam::new(scalar_to_clif_type(tcx, scalar)), attrs )], Abi::Vector { .. } => { @@ -103,10 +103,10 @@ } _ => unreachable!("{:?}", self.layout.abi), }, - PassMode::Pair(attrs_a, attrs_b) => match &self.layout.abi { + PassMode::Pair(attrs_a, attrs_b) => match self.layout.abi { Abi::ScalarPair(a, b) => { - let a = scalar_to_clif_type(tcx, a.clone()); - let b = scalar_to_clif_type(tcx, b.clone()); + let a = scalar_to_clif_type(tcx, a); + let b = scalar_to_clif_type(tcx, b); smallvec![ apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a), apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b), @@ -139,9 +139,9 @@ fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option, Vec) { match self.mode { PassMode::Ignore => (None, vec![]), - PassMode::Direct(_) => match &self.layout.abi { + PassMode::Direct(_) => match self.layout.abi { Abi::Scalar(scalar) => { - (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))]) + (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))]) } Abi::Vector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap(); @@ -149,10 +149,10 @@ } _ => unreachable!("{:?}", self.layout.abi), }, - PassMode::Pair(_, _) => match &self.layout.abi { + PassMode::Pair(_, _) => match self.layout.abi { Abi::ScalarPair(a, b) => { - let a = scalar_to_clif_type(tcx, a.clone()); - let b = scalar_to_clif_type(tcx, b.clone()); + let a = scalar_to_clif_type(tcx, a); + let b = scalar_to_clif_type(tcx, b); (None, vec![AbiParam::new(a), AbiParam::new(b)]) } _ => unreachable!("{:?}", self.layout.abi), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/archive.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/archive.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/archive.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/archive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,53 +1,51 @@ //! Creation of ar archives like for the lib and staticlib crate type use std::collections::BTreeMap; +use std::convert::TryFrom; use std::fs::File; +use std::io::{self, Read, Seek}; use std::path::{Path, PathBuf}; -use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; -use rustc_codegen_ssa::METADATA_FILENAME; +use rustc_codegen_ssa::back::archive::ArchiveBuilder; use rustc_session::Session; -use object::{Object, ObjectSymbol, SymbolKind}; +use object::read::archive::ArchiveFile; +use object::{Object, ObjectSymbol, ReadCache, SymbolKind}; #[derive(Debug)] enum ArchiveEntry { - FromArchive { archive_index: usize, entry_index: usize }, + FromArchive { archive_index: usize, file_range: (u64, u64) }, File(PathBuf), } pub(crate) struct ArArchiveBuilder<'a> { sess: &'a Session, dst: PathBuf, - lib_search_paths: Vec, use_gnu_style_archive: bool, no_builtin_ranlib: bool, - src_archives: Vec<(PathBuf, ar::Archive)>, + src_archives: Vec, // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at // the end of an archive for linkers to not get confused. - entries: Vec<(String, ArchiveEntry)>, + entries: Vec<(Vec, ArchiveEntry)>, } impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self { - use rustc_codegen_ssa::back::link::archive_search_paths; - let (src_archives, entries) = if let Some(input) = input { - let mut archive = ar::Archive::new(File::open(input).unwrap()); + let read_cache = ReadCache::new(File::open(input).unwrap()); + let archive = ArchiveFile::parse(&read_cache).unwrap(); let mut entries = Vec::new(); - let mut i = 0; - while let Some(entry) = archive.next_entry() { + for entry in archive.members() { let entry = entry.unwrap(); entries.push(( - String::from_utf8(entry.header().identifier().to_vec()).unwrap(), - ArchiveEntry::FromArchive { archive_index: 0, entry_index: i }, + entry.name().to_vec(), + ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() }, )); - i += 1; } - (vec![(input.to_owned(), archive)], entries) + (vec![read_cache.into_inner()], entries) } else { (vec![], Vec::new()) }; @@ -55,7 +53,6 @@ ArArchiveBuilder { sess, dst: output.to_path_buf(), - lib_search_paths: archive_search_paths(sess), use_gnu_style_archive: sess.target.archive_format == "gnu", // FIXME fix builtin ranlib on macOS no_builtin_ranlib: sess.target.is_like_osx, @@ -66,61 +63,47 @@ } fn src_files(&mut self) -> Vec { - self.entries.iter().map(|(name, _)| name.clone()).collect() + self.entries.iter().map(|(name, _)| String::from_utf8(name.clone()).unwrap()).collect() } fn remove_file(&mut self, name: &str) { let index = self .entries .iter() - .position(|(entry_name, _)| entry_name == name) + .position(|(entry_name, _)| entry_name == name.as_bytes()) .expect("Tried to remove file not existing in src archive"); self.entries.remove(index); } fn add_file(&mut self, file: &Path) { self.entries.push(( - file.file_name().unwrap().to_str().unwrap().to_string(), + file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(), ArchiveEntry::File(file.to_owned()), )); } - fn add_native_library(&mut self, name: rustc_span::symbol::Symbol, verbatim: bool) { - let location = find_library(name, verbatim, &self.lib_search_paths, self.sess); - self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| { - panic!("failed to add native library {}: {}", location.to_string_lossy(), e); - }); - } - - fn add_rlib( - &mut self, - rlib: &Path, - name: &str, - lto: bool, - skip_objects: bool, - ) -> std::io::Result<()> { - let obj_start = name.to_owned(); - - self.add_archive(rlib.to_owned(), move |fname: &str| { - // Ignore metadata files, no matter the name. - if fname == METADATA_FILENAME { - return true; - } - - // Don't include Rust objects if LTO is enabled - if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") { - return true; - } + fn add_archive(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()> + where + F: FnMut(&str) -> bool + 'static, + { + let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?); + let archive = ArchiveFile::parse(&read_cache).unwrap(); + let archive_index = self.src_archives.len(); - // Otherwise if this is *not* a rust object and we're skipping - // objects then skip this file - if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { - return true; + for entry in archive.members() { + let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; + let file_name = String::from_utf8(entry.name().to_vec()) + .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; + if !skip(&file_name) { + self.entries.push(( + file_name.into_bytes(), + ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, + )); } + } - // ok, don't skip this - false - }) + self.src_archives.push(read_cache.into_inner()); + Ok(()) } fn update_symbols(&mut self) {} @@ -141,14 +124,14 @@ // FIXME only read the symbol table of the object files to avoid having to keep all // object files in memory at once, or read them twice. let data = match entry { - ArchiveEntry::FromArchive { archive_index, entry_index } => { + ArchiveEntry::FromArchive { archive_index, file_range } => { // FIXME read symbols from symtab - use std::io::Read; - let (ref _src_archive_path, ref mut src_archive) = - self.src_archives[archive_index]; - let mut entry = src_archive.jump_to_entry(entry_index).unwrap(); - let mut data = Vec::new(); - entry.read_to_end(&mut data).unwrap(); + let src_read_cache = &mut self.src_archives[archive_index]; + + src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap(); + let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap()); + src_read_cache.read_exact(&mut data).unwrap(); + data } ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| { @@ -163,7 +146,7 @@ match object::File::parse(&*data) { Ok(object) => { symbol_table.insert( - entry_name.as_bytes().to_vec(), + entry_name.to_vec(), object .symbols() .filter_map(|symbol| { @@ -188,7 +171,8 @@ } else { sess.fatal(&format!( "error parsing `{}` during archive creation: {}", - entry_name, err + String::from_utf8_lossy(&entry_name), + err )); } } @@ -207,7 +191,7 @@ err )); }), - entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(), + entries.iter().map(|(name, _)| name.clone()).collect(), ar::GnuSymbolTableFormat::Size32, symbol_table, ) @@ -230,7 +214,7 @@ // Add all files for (entry_name, data) in entries.into_iter() { - let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64); + let header = ar::Header::new(entry_name, data.len() as u64); match builder { BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(), BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(), @@ -258,34 +242,9 @@ fn inject_dll_import_lib( &mut self, _lib_name: &str, - _dll_imports: &[rustc_middle::middle::cstore::DllImport], + _dll_imports: &[rustc_session::cstore::DllImport], _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir, ) { bug!("injecting dll imports is not supported"); } } - -impl<'a> ArArchiveBuilder<'a> { - fn add_archive(&mut self, archive_path: PathBuf, mut skip: F) -> std::io::Result<()> - where - F: FnMut(&str) -> bool + 'static, - { - let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); - let archive_index = self.src_archives.len(); - - let mut i = 0; - while let Some(entry) = archive.next_entry() { - let entry = entry?; - let file_name = String::from_utf8(entry.header().identifier().to_vec()) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; - if !skip(&file_name) { - self.entries - .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i })); - } - i += 1; - } - - self.src_archives.push((archive_path, archive)); - Ok(()) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/backend.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/backend.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/backend.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/backend.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,152 +0,0 @@ -//! Abstraction around the object writing crate - -use std::convert::{TryFrom, TryInto}; - -use rustc_data_structures::fx::FxHashMap; -use rustc_session::Session; - -use cranelift_codegen::isa::TargetIsa; -use cranelift_module::FuncId; -use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct}; - -use object::write::*; -use object::{RelocationEncoding, SectionKind, SymbolFlags}; - -use gimli::SectionId; - -use crate::debuginfo::{DebugReloc, DebugRelocName}; - -pub(crate) trait WriteMetadata { - fn add_rustc_section(&mut self, symbol_name: String, data: Vec); -} - -impl WriteMetadata for object::write::Object { - fn add_rustc_section(&mut self, symbol_name: String, data: Vec) { - let segment = self.segment_name(object::write::StandardSegment::Data).to_vec(); - let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data); - let offset = self.append_section_data(section_id, &data, 1); - // For MachO and probably PE this is necessary to prevent the linker from throwing away the - // .rustc section. For ELF this isn't necessary, but it also doesn't harm. - self.add_symbol(object::write::Symbol { - name: symbol_name.into_bytes(), - value: offset, - size: data.len() as u64, - kind: object::SymbolKind::Data, - scope: object::SymbolScope::Dynamic, - weak: false, - section: SymbolSection::Section(section_id), - flags: SymbolFlags::None, - }); - } -} - -pub(crate) trait WriteDebugInfo { - type SectionId: Copy; - - fn add_debug_section(&mut self, name: SectionId, data: Vec) -> Self::SectionId; - fn add_debug_reloc( - &mut self, - section_map: &FxHashMap, - from: &Self::SectionId, - reloc: &DebugReloc, - ); -} - -impl WriteDebugInfo for ObjectProduct { - type SectionId = (object::write::SectionId, object::write::SymbolId); - - fn add_debug_section( - &mut self, - id: SectionId, - data: Vec, - ) -> (object::write::SectionId, object::write::SymbolId) { - let name = if self.object.format() == object::BinaryFormat::MachO { - id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info - } else { - id.name().to_string() - } - .into_bytes(); - - let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); - // FIXME use SHT_X86_64_UNWIND for .eh_frame - let section_id = self.object.add_section( - segment, - name, - if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, - ); - self.object - .section_mut(section_id) - .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 }); - let symbol_id = self.object.section_symbol(section_id); - (section_id, symbol_id) - } - - fn add_debug_reloc( - &mut self, - section_map: &FxHashMap, - from: &Self::SectionId, - reloc: &DebugReloc, - ) { - let (symbol, symbol_offset) = match reloc.name { - DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), - DebugRelocName::Symbol(id) => { - let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap())); - self.object - .symbol_section_and_offset(symbol_id) - .expect("Debug reloc for undef sym???") - } - }; - self.object - .add_relocation( - from.0, - Relocation { - offset: u64::from(reloc.offset), - symbol, - kind: reloc.kind, - encoding: RelocationEncoding::Generic, - size: reloc.size * 8, - addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, - }, - ) - .unwrap(); - } -} - -pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec { - let triple = crate::target_triple(sess); - - let binary_format = match triple.binary_format { - target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf, - target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff, - target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO, - binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)), - }; - let architecture = match triple.architecture { - target_lexicon::Architecture::X86_32(_) => object::Architecture::I386, - target_lexicon::Architecture::X86_64 => object::Architecture::X86_64, - target_lexicon::Architecture::Arm(_) => object::Architecture::Arm, - target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64, - architecture => { - sess.fatal(&format!("target architecture {:?} is unsupported", architecture,)) - } - }; - let endian = match triple.endianness().unwrap() { - target_lexicon::Endianness::Little => object::Endianness::Little, - target_lexicon::Endianness::Big => object::Endianness::Big, - }; - - let mut metadata_object = object::write::Object::new(binary_format, architecture, endian); - metadata_object.add_file_symbol(name.as_bytes().to_vec()); - f(&mut metadata_object); - metadata_object.write().unwrap() -} - -pub(crate) fn make_module(sess: &Session, isa: Box, name: String) -> ObjectModule { - let mut builder = - ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); - // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size - // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections - // can easily double the amount of time necessary to perform linking. - builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false)); - ObjectModule::new(builder) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/base.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/base.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/base.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/base.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,7 @@ use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink}; use rustc_index::vec::IndexVec; use rustc_middle::ty::adjustment::PointerCast; -use rustc_middle::ty::layout::FnAbiExt; -use rustc_target::abi::call::FnAbi; +use rustc_middle::ty::layout::FnAbiOf; use crate::constant::ConstantCx; use crate::prelude::*; @@ -23,7 +22,7 @@ let mir = tcx.instance_mir(instance.def); let _mir_guard = crate::PrintOnPanic(|| { let mut buf = Vec::new(); - rustc_mir::util::write_mir_pretty(tcx, Some(instance.def_id()), &mut buf).unwrap(); + rustc_middle::mir::write_mir_pretty(tcx, Some(instance.def_id()), &mut buf).unwrap(); String::from_utf8_lossy(&buf).into_owned() }); @@ -62,7 +61,7 @@ instance, symbol_name, mir, - fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])), + fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())), bcx, block_map, @@ -702,6 +701,13 @@ let len = codegen_array_len(fx, place); lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); } + Rvalue::ShallowInitBox(ref operand, content_ty) => { + let content_ty = fx.monomorphize(content_ty); + let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty)); + let operand = codegen_operand(fx, operand); + let operand = operand.load_scalar(fx); + lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); + } Rvalue::NullaryOp(NullOp::Box, content_ty) => { let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap(); let content_ty = fx.monomorphize(content_ty); @@ -726,15 +732,20 @@ let ptr = fx.bcx.inst_results(call)[0]; lval.write_cvalue(fx, CValue::by_val(ptr, box_layout)); } - Rvalue::NullaryOp(NullOp::SizeOf, ty) => { + Rvalue::NullaryOp(null_op, ty) => { assert!( lval.layout() .ty .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all()) ); - let ty_size = fx.layout_of(fx.monomorphize(ty)).size.bytes(); + let layout = fx.layout_of(fx.monomorphize(ty)); + let val = match null_op { + NullOp::SizeOf => layout.size.bytes(), + NullOp::AlignOf => layout.align.abi.bytes(), + NullOp::Box => unreachable!(), + }; let val = - CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), ty_size.into()); + CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into()); lval.write_cvalue(fx, val); } Rvalue::Aggregate(ref kind, ref operands) => match kind.as_ref() { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,10 @@ //! target crates. #![feature(rustc_private)] +#![warn(rust_2018_idioms)] +#![warn(unused_lifetimes)] +#![warn(unreachable_pub)] -extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_interface; extern crate rustc_session; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ #![feature(rustc_private, once_cell)] +#![warn(rust_2018_idioms)] +#![warn(unused_lifetimes)] +#![warn(unreachable_pub)] extern crate rustc_data_structures; extern crate rustc_driver; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/common.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/common.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/common.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/common.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ use rustc_index::vec::IndexVec; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, +}; use rustc_middle::ty::SymbolName; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Integer, Primitive}; @@ -238,7 +241,7 @@ pub(crate) instance: Instance<'tcx>, pub(crate) symbol_name: SymbolName<'tcx>, pub(crate) mir: &'tcx Body<'tcx>, - pub(crate) fn_abi: Option>>, + pub(crate) fn_abi: Option<&'tcx FnAbi<'tcx, Ty<'tcx>>>, pub(crate) bcx: FunctionBuilder<'clif>, pub(crate) block_map: IndexVec, @@ -256,12 +259,26 @@ pub(crate) inline_asm_index: u32, } -impl<'tcx> LayoutOf<'tcx> for FunctionCx<'_, '_, 'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; +impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; - fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { - RevealAllLayoutCx(self.tcx).layout_of(ty) + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty) + } +} + +impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request) } } @@ -364,19 +381,53 @@ pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); -impl<'tcx> LayoutOf<'tcx> for RevealAllLayoutCx<'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; - - fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { - assert!(!ty.still_further_specializable()); - self.0.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap_or_else(|e| { - if let layout::LayoutError::SizeOverflow(_) = e { - self.0.sess.fatal(&e.to_string()) - } else { - bug!("failed to get layout for `{}`: {}", ty, e) +impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + if let layout::LayoutError::SizeOverflow(_) = err { + self.0.sess.span_fatal(span, &err.to_string()) + } else { + span_bug!(span, "failed to get layout for `{}`: {}", ty, err) + } + } +} + +impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { + self.0.sess.span_fatal(span, &err.to_string()) + } else { + match fn_abi_request { + FnAbiRequest::OfFnPtr { sig, extra_args } => { + span_bug!( + span, + "`fn_abi_of_fn_ptr({}, {:?})` failed: {}", + sig, + extra_args, + err + ); + } + FnAbiRequest::OfInstance { instance, extra_args } => { + span_bug!( + span, + "`fn_abi_of_instance({}, {:?})` failed: {}", + instance, + extra_args, + err + ); + } } - }) + } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/constant.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/constant.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/constant.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/constant.rs 2021-11-29 19:27:11.000000000 +0000 @@ -129,9 +129,7 @@ }; let const_val = match const_.val { ConstKind::Value(const_val) => const_val, - ConstKind::Unevaluated(uv) - if fx.tcx.is_static(uv.def.did) => - { + ConstKind::Unevaluated(uv) if fx.tcx.is_static(uv.def.did) => { assert!(uv.substs(fx.tcx).is_empty()); assert!(uv.promoted.is_none()); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,16 +1,16 @@ //! Write the debuginfo into an object file. +use cranelift_object::ObjectProduct; use rustc_data_structures::fx::FxHashMap; use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer}; use gimli::{RunTimeEndian, SectionId}; -use crate::backend::WriteDebugInfo; - +use super::object::WriteDebugInfo; use super::DebugContext; impl DebugContext<'_> { - pub(crate) fn emit(&mut self, product: &mut P) { + pub(crate) fn emit(&mut self, product: &mut ObjectProduct) { let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone()); let root = self.dwarf.unit.root(); let root = self.dwarf.unit.get_mut(root); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,7 @@ mod emit; mod line_info; +mod object; mod unwind; use crate::prelude::*; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,85 @@ +use std::convert::{TryFrom, TryInto}; + +use rustc_data_structures::fx::FxHashMap; + +use cranelift_module::FuncId; +use cranelift_object::ObjectProduct; + +use object::write::{Relocation, StandardSegment}; +use object::{RelocationEncoding, SectionKind}; + +use gimli::SectionId; + +use crate::debuginfo::{DebugReloc, DebugRelocName}; + +pub(super) trait WriteDebugInfo { + type SectionId: Copy; + + fn add_debug_section(&mut self, name: SectionId, data: Vec) -> Self::SectionId; + fn add_debug_reloc( + &mut self, + section_map: &FxHashMap, + from: &Self::SectionId, + reloc: &DebugReloc, + ); +} + +impl WriteDebugInfo for ObjectProduct { + type SectionId = (object::write::SectionId, object::write::SymbolId); + + fn add_debug_section( + &mut self, + id: SectionId, + data: Vec, + ) -> (object::write::SectionId, object::write::SymbolId) { + let name = if self.object.format() == object::BinaryFormat::MachO { + id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info + } else { + id.name().to_string() + } + .into_bytes(); + + let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); + // FIXME use SHT_X86_64_UNWIND for .eh_frame + let section_id = self.object.add_section( + segment, + name, + if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, + ); + self.object + .section_mut(section_id) + .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 }); + let symbol_id = self.object.section_symbol(section_id); + (section_id, symbol_id) + } + + fn add_debug_reloc( + &mut self, + section_map: &FxHashMap, + from: &Self::SectionId, + reloc: &DebugReloc, + ) { + let (symbol, symbol_offset) = match reloc.name { + DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), + DebugRelocName::Symbol(id) => { + let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap())); + self.object + .symbol_section_and_offset(symbol_id) + .expect("Debug reloc for undef sym???") + } + }; + self.object + .add_relocation( + from.0, + Relocation { + offset: u64::from(reloc.offset), + symbol, + kind: reloc.kind, + encoding: RelocationEncoding::Generic, + size: reloc.size * 8, + addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, + }, + ) + .unwrap(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,10 +4,11 @@ use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; +use cranelift_object::ObjectProduct; use gimli::write::{Address, CieId, EhFrame, FrameTable, Section}; use gimli::RunTimeEndian; -use crate::backend::WriteDebugInfo; +use super::object::WriteDebugInfo; pub(crate) struct UnwindContext { endian: RunTimeEndian, @@ -55,7 +56,7 @@ } } - pub(crate) fn emit(self, product: &mut P) { + pub(crate) fn emit(self, product: &mut ObjectProduct) { let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian)); self.frame_table.write_eh_frame(&mut eh_frame).unwrap(); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/driver/aot.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/driver/aot.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/driver/aot.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/driver/aot.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,13 +6,15 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{DebugInfo, OutputType}; +use rustc_session::Session; -use cranelift_object::ObjectModule; +use cranelift_codegen::isa::TargetIsa; +use cranelift_object::{ObjectBuilder, ObjectModule}; use crate::{prelude::*, BackendConfig}; @@ -24,6 +26,16 @@ } } +fn make_module(sess: &Session, isa: Box, name: String) -> ObjectModule { + let mut builder = + ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); + // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size + // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections + // can easily double the amount of time necessary to perform linking. + builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false)); + ObjectModule::new(builder) +} + fn emit_module( tcx: TyCtxt<'_>, backend_config: &BackendConfig, @@ -104,7 +116,7 @@ let mono_items = cgu.items_in_deterministic_order(tcx); let isa = crate::build_isa(tcx.sess, &backend_config); - let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string()); + let mut module = make_module(tcx.sess, isa, cgu_name.as_str().to_string()); let mut cx = crate::CodegenCx::new( tcx, @@ -227,8 +239,7 @@ tcx.sess.abort_if_errors(); let isa = crate::build_isa(tcx.sess, &backend_config); - let mut allocator_module = - crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string()); + let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string()); assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type()); let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true); let created_alloc_shim = @@ -266,9 +277,7 @@ let tmp_file = tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); - let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| { - crate::metadata::write_metadata(tcx, object); - }); + let obj = crate::metadata::new_metadata_object(tcx, &metadata_cgu_name, &metadata); if let Err(err) = std::fs::write(&tmp_file, obj) { tcx.sess.fatal(&format!("error writing metadata object file: {}", err)); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -143,8 +143,8 @@ } pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option { - let (element, count) = match &layout.abi { - Abi::Vector { element, count } => (element.clone(), *count), + let (element, count) = match layout.abi { + Abi::Vector { element, count } => (element, count), _ => unreachable!(), }; @@ -407,11 +407,9 @@ destination: Option<(CPlace<'tcx>, BasicBlock)>, span: Span, ) { - let def_id = instance.def_id(); + let intrinsic = fx.tcx.item_name(instance.def_id()); let substs = instance.substs; - let intrinsic = fx.tcx.item_name(def_id); - let ret = match destination { Some((place, _)) => place, None => { @@ -823,7 +821,7 @@ dest.write_cvalue(fx, val); }; - pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () { + pref_align_of | needs_drop | type_id | type_name | variant_count, () { let const_val = fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap(); let val = crate::constant::codegen_const_value( diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,5 @@ -#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)] +#![feature(rustc_private, decl_macro)] +#![cfg_attr(feature = "jit", feature(never_type, vec_into_raw_parts, once_cell))] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![warn(unreachable_pub)] @@ -16,7 +17,6 @@ extern crate rustc_index; extern crate rustc_interface; extern crate rustc_metadata; -extern crate rustc_mir; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -30,8 +30,8 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_errors::ErrorReported; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_session::config::OutputFilenames; use rustc_session::Session; @@ -45,7 +45,6 @@ mod allocator; mod analyze; mod archive; -mod backend; mod base; mod cast; mod codegen_i128; @@ -79,12 +78,12 @@ pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE}; pub(crate) use rustc_middle::bug; pub(crate) use rustc_middle::mir::{self, *}; - pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout}; + pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable, UintTy, }; - pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx}; + pub(crate) use rustc_target::abi::{Abi, Scalar, Size, VariantIdx}; pub(crate) use rustc_data_structures::fx::FxHashMap; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/metadata.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/metadata.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/metadata.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/metadata.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,20 +1,76 @@ //! Writing of the rustc metadata for dylibs -use rustc_middle::ty::TyCtxt; +use object::write::{Object, StandardSegment, Symbol, SymbolSection}; +use object::{SectionKind, SymbolFlags, SymbolKind, SymbolScope}; -use crate::backend::WriteMetadata; +use rustc_metadata::EncodedMetadata; +use rustc_middle::ty::TyCtxt; // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112 -pub(crate) fn write_metadata(tcx: TyCtxt<'_>, object: &mut O) { +pub(crate) fn new_metadata_object( + tcx: TyCtxt<'_>, + cgu_name: &str, + metadata: &EncodedMetadata, +) -> Vec { use snap::write::FrameEncoder; use std::io::Write; - let metadata = tcx.encode_metadata(); let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); - FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); + FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap(); + + let triple = crate::target_triple(tcx.sess); + + let binary_format = match triple.binary_format { + target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf, + target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff, + target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO, + binary_format => tcx.sess.fatal(&format!("binary format {} is unsupported", binary_format)), + }; + let architecture = match triple.architecture { + target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64, + target_lexicon::Architecture::Arm(_) => object::Architecture::Arm, + target_lexicon::Architecture::Avr => object::Architecture::Avr, + target_lexicon::Architecture::Hexagon => object::Architecture::Hexagon, + target_lexicon::Architecture::Mips32(_) => object::Architecture::Mips, + target_lexicon::Architecture::Mips64(_) => object::Architecture::Mips64, + target_lexicon::Architecture::Msp430 => object::Architecture::Msp430, + target_lexicon::Architecture::Powerpc => object::Architecture::PowerPc, + target_lexicon::Architecture::Powerpc64 => object::Architecture::PowerPc64, + target_lexicon::Architecture::Powerpc64le => todo!(), + target_lexicon::Architecture::Riscv32(_) => object::Architecture::Riscv32, + target_lexicon::Architecture::Riscv64(_) => object::Architecture::Riscv64, + target_lexicon::Architecture::S390x => object::Architecture::S390x, + target_lexicon::Architecture::Sparc64 => object::Architecture::Sparc64, + target_lexicon::Architecture::Sparcv9 => object::Architecture::Sparc64, + target_lexicon::Architecture::X86_32(_) => object::Architecture::I386, + target_lexicon::Architecture::X86_64 => object::Architecture::X86_64, + architecture => { + tcx.sess.fatal(&format!("target architecture {:?} is unsupported", architecture,)) + } + }; + let endian = match triple.endianness().unwrap() { + target_lexicon::Endianness::Little => object::Endianness::Little, + target_lexicon::Endianness::Big => object::Endianness::Big, + }; + + let mut object = Object::new(binary_format, architecture, endian); + object.add_file_symbol(cgu_name.as_bytes().to_vec()); + + let segment = object.segment_name(StandardSegment::Data).to_vec(); + let section_id = object.add_section(segment, b".rustc".to_vec(), SectionKind::Data); + let offset = object.append_section_data(section_id, &compressed, 1); + // For MachO and probably PE this is necessary to prevent the linker from throwing away the + // .rustc section. For ELF this isn't necessary, but it also doesn't harm. + object.add_symbol(Symbol { + name: rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx).into_bytes(), + value: offset, + size: compressed.len() as u64, + kind: SymbolKind::Data, + scope: SymbolScope::Dynamic, + weak: false, + section: SymbolSection::Section(section_id), + flags: SymbolFlags::None, + }); - object.add_rustc_section( - rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx), - compressed, - ); + object.write().unwrap() } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/pretty_clif.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/pretty_clif.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/pretty_clif.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/pretty_clif.rs 2021-11-29 19:27:11.000000000 +0000 @@ -61,9 +61,8 @@ write::{FuncWriter, PlainWriter}, }; -use rustc_middle::ty::layout::FnAbiExt; +use rustc_middle::ty::layout::FnAbiOf; use rustc_session::config::OutputType; -use rustc_target::abi::call::FnAbi; use crate::prelude::*; @@ -81,7 +80,10 @@ vec![ format!("symbol {}", tcx.symbol_name(instance).name), format!("instance {:?}", instance), - format!("abi {:?}", FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])), + format!( + "abi {:?}", + RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()) + ), String::new(), ] } else { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/value_and_place.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/value_and_place.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/value_and_place.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_cranelift/src/value_and_place.rs 2021-11-29 19:27:11.000000000 +0000 @@ -49,11 +49,7 @@ } } -fn scalar_pair_calculate_b_offset( - tcx: TyCtxt<'_>, - a_scalar: &Scalar, - b_scalar: &Scalar, -) -> Offset32 { +fn scalar_pair_calculate_b_offset(tcx: TyCtxt<'_>, a_scalar: Scalar, b_scalar: Scalar) -> Offset32 { let b_offset = a_scalar.value.size(&tcx).align_to(b_scalar.value.align(&tcx).abi); Offset32::new(b_offset.bytes().try_into().unwrap()) } @@ -124,12 +120,10 @@ match self.0 { CValueInner::ByRef(ptr, None) => { let clif_ty = match layout.abi { - Abi::Scalar(ref scalar) => scalar_to_clif_type(fx.tcx, scalar.clone()), - Abi::Vector { ref element, count } => { - scalar_to_clif_type(fx.tcx, element.clone()) - .by(u16::try_from(count).unwrap()) - .unwrap() - } + Abi::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar), + Abi::Vector { element, count } => scalar_to_clif_type(fx.tcx, element) + .by(u16::try_from(count).unwrap()) + .unwrap(), _ => unreachable!("{:?}", layout.ty), }; let mut flags = MemFlags::new(); @@ -147,13 +141,13 @@ let layout = self.1; match self.0 { CValueInner::ByRef(ptr, None) => { - let (a_scalar, b_scalar) = match &layout.abi { + let (a_scalar, b_scalar) = match layout.abi { Abi::ScalarPair(a, b) => (a, b), _ => unreachable!("load_scalar_pair({:?})", self), }; let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); - let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar.clone()); - let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar.clone()); + let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar); + let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar); let mut flags = MemFlags::new(); flags.set_notrap(); let val1 = ptr.load(fx, clif_ty1, flags); @@ -564,7 +558,7 @@ to_ptr.store(fx, val, flags); return; } - Abi::ScalarPair(ref a_scalar, ref b_scalar) => { + Abi::ScalarPair(a_scalar, b_scalar) => { let (value, extra) = from.load_scalar_pair(fx); let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); to_ptr.store(fx, value, flags); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,31 @@ +#!/bin/bash + +#set -x +set -e + +if [ -f ./gcc_path ]; then + export GCC_PATH=$(cat gcc_path) +else + echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' + exit 1 +fi + +export LD_LIBRARY_PATH="$GCC_PATH" +export LIBRARY_PATH="$GCC_PATH" + +if [[ "$1" == "--release" ]]; then + export CHANNEL='release' + CARGO_INCREMENTAL=1 cargo rustc --release +else + echo $LD_LIBRARY_PATH + export CHANNEL='debug' + cargo rustc +fi + +source config.sh + +rm -r target/out || true +mkdir -p target/out/gccjit + +echo "[BUILD] sysroot" +time ./build_sysroot/build_sysroot.sh $CHANNEL diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +#!/bin/bash + +# Requires the CHANNEL env var to be set to `debug` or `release.` + +set -e +cd $(dirname "$0") + +pushd ../ >/dev/null +source ./config.sh +popd >/dev/null + +# Cleanup for previous run +# v Clean target dir except for build scripts and incremental cache +rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true +rm Cargo.lock test_target/Cargo.lock 2>/dev/null || true +rm -r sysroot/ 2>/dev/null || true + +# Build libs +export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked -Cpanic=abort" +if [[ "$1" == "--release" ]]; then + sysroot_channel='release' + RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release +else + sysroot_channel='debug' + cargo build --target $TARGET_TRIPLE +fi + +# Copy files to sysroot +mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +[package] +authors = ["bjorn3 "] +name = "sysroot" +version = "0.0.0" + +[dependencies] +core = { path = "./sysroot_src/library/core" } +compiler_builtins = "0.1" +alloc = { path = "./sysroot_src/library/alloc" } +std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } +test = { path = "./sysroot_src/library/test" } + +[patch.crates-io] +rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" } +rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" } +rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" } + +[profile.release] +debug = true diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +#!/bin/bash +set -e +cd $(dirname "$0") + +SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/" +DST_DIR="sysroot_src" + +if [ ! -e $SRC_DIR ]; then + echo "Please install rust-src component" + exit 1 +fi + +rm -rf $DST_DIR +mkdir -p $DST_DIR/library +cp -r $SRC_DIR/library $DST_DIR/ + +pushd $DST_DIR +echo "[GIT] init" +git init +echo "[GIT] add" +git add . +echo "[GIT] commit" + +# This is needed on systems where nothing is configured. +# git really needs something here, or it will fail. +# Even using --author is not enough. +git config user.email || git config user.email "none@example.com" +git config user.name || git config user.name "None" + +git commit -m "Initial commit" -q +for file in $(ls ../../patches/ | grep -v patcha); do +echo "[GIT] apply" $file +git apply ../../patches/$file +git add -A +git commit --no-gpg-sign -m "Patch $file" +done +popd + +echo "Successfully prepared libcore for building" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +#![no_std] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Cargo.lock rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Cargo.lock --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Cargo.lock 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Cargo.lock 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,373 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ar" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68fda3cff2cce84c19e5dfa5179a4b35d2c0f18b893f108002b8a6a54984acca" +dependencies = [ + "regex", +] + +[[package]] +name = "gccjit" +version = "1.0.0" +source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e" +dependencies = [ + "gccjit_sys", +] + +[[package]] +name = "gccjit_sys" +version = "0.0.1" +source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e" +dependencies = [ + "libc 0.1.12", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc 0.2.102", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc 0.2.102", +] + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "lang_tester" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090" +dependencies = [ + "fm", + "getopts", + "libc 0.2.102", + "num_cpus", + "termcolor", + "threadpool", + "wait-timeout", + "walkdir", +] + +[[package]] +name = "libc" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" + +[[package]] +name = "libc" +version = "0.2.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc 0.2.102", +] + +[[package]] +name = "object" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" +dependencies = [ + "crc32fast", + "indexmap", + "memchr", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc 0.2.102", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rustc_codegen_gcc" +version = "0.1.0" +dependencies = [ + "ar", + "gccjit", + "lang_tester", + "object", + "target-lexicon", + "tempfile", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "target-lexicon" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc 0.2.102", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc 0.2.102", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/cargo.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/cargo.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/cargo.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/cargo.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ -z $CHANNEL ]; then +export CHANNEL='debug' +fi + +pushd $(dirname "$0") >/dev/null +source config.sh + +# read nightly compiler from rust-toolchain file +TOOLCHAIN=$(cat rust-toolchain) + +popd >/dev/null + +if [[ $(rustc -V) != $(rustc +${TOOLCHAIN} -V) ]]; then + echo "rustc_codegen_gcc is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)." + echo "Using $(rustc +${TOOLCHAIN} -V)." +fi + +cmd=$1 +shift + +RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd --target $TARGET_TRIPLE $@ diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +[package] +name = "rustc_codegen_gcc" +version = "0.1.0" +authors = ["Antoni Boucher "] +edition = "2018" +license = "MIT OR Apache-2.0" + +[lib] +crate-type = ["dylib"] + +[[test]] +name = "lang_tests" +path = "tests/lib.rs" +harness = false + +[dependencies] +gccjit = { git = "https://github.com/antoyo/gccjit.rs" } + +# Local copy. +#gccjit = { path = "../gccjit.rs" } + +target-lexicon = "0.10.0" + +ar = "0.8.0" + +[dependencies.object] +version = "0.25.0" +default-features = false +features = ["read", "std", "write"] # We don't need WASM support. + +[dev-dependencies] +lang_tester = "0.3.9" +tempfile = "3.1.0" + +[profile.dev] +# By compiling dependencies with optimizations, performing tests gets much faster. +opt-level = 3 + +[profile.dev.package.rustc_codegen_gcc] +# Disabling optimizations for cg_gccjit itself makes compilation after a change faster. +opt-level = 0 + +# Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the +# execution time of build scripts is so fast that optimizing them slows down the total build time. +[profile.dev.build-override] +opt-level = 0 +debug = false + +[profile.release.build-override] +opt-level = 0 +debug = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/clean_all.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/clean_all.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/clean_all.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/clean_all.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +#!/bin/bash --verbose +set -e + +rm -rf target/ build_sysroot/{sysroot/,sysroot_src/,target/,Cargo.lock} perf.data{,.old} +rm -rf regex/ simple-raytracer/ diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/config.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/config.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/config.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/config.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,52 @@ +set -e + +export CARGO_INCREMENTAL=0 + +if [ -f ./gcc_path ]; then + export GCC_PATH=$(cat gcc_path) +else + echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' + exit 1 +fi + +unamestr=`uname` +if [[ "$unamestr" == 'Linux' ]]; then + dylib_ext='so' +elif [[ "$unamestr" == 'Darwin' ]]; then + dylib_ext='dylib' +else + echo "Unsupported os" + exit 1 +fi + +HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") +TARGET_TRIPLE=$HOST_TRIPLE +#TARGET_TRIPLE="m68k-unknown-linux-gnu" + +linker='' +RUN_WRAPPER='' +if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then + if [[ "$TARGET_TRIPLE" == "m68k-unknown-linux-gnu" ]]; then + TARGET_TRIPLE="mips-unknown-linux-gnu" + linker='-Clinker=m68k-linux-gcc' + elif [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then + # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. + linker='-Clinker=aarch64-linux-gnu-gcc' + RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu' + else + echo "Unknown non-native platform" + fi +fi + +export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot" + +# FIXME(antoyo): remove once the atomic shim is gone +if [[ `uname` == 'Darwin' ]]; then + export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" +fi + +RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out" +export RUSTC_LOG=warn # display metadata load errors + +export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib:$GCC_PATH" +export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/alloc_example.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/alloc_example.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/alloc_example.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/alloc_example.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,41 @@ +#![feature(start, box_syntax, core_intrinsics, alloc_error_handler)] +#![no_std] + +extern crate alloc; +extern crate alloc_system; + +use alloc::boxed::Box; + +use alloc_system::System; + +#[global_allocator] +static ALLOC: System = System; + +#[link(name = "c")] +extern "C" { + fn puts(s: *const u8) -> i32; +} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + unsafe { + core::intrinsics::abort(); + } +} + +#[alloc_error_handler] +fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { + unsafe { + core::intrinsics::abort(); + } +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + let world: Box<&str> = box "Hello World!\0"; + unsafe { + puts(*world as *const str as *const u8); + } + + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/alloc_system.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/alloc_system.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/alloc_system.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/alloc_system.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,212 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![no_std] +#![feature(allocator_api, rustc_private)] +#![cfg_attr(any(unix, target_os = "redox"), feature(libc))] + +// The minimum alignment guaranteed by the architecture. This value is used to +// add fast paths for low alignment values. +#[cfg(all(any(target_arch = "x86", + target_arch = "arm", + target_arch = "mips", + target_arch = "powerpc", + target_arch = "powerpc64")))] +const MIN_ALIGN: usize = 8; +#[cfg(all(any(target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64")))] +const MIN_ALIGN: usize = 16; + +pub struct System; +#[cfg(any(windows, unix, target_os = "redox"))] +mod realloc_fallback { + use core::alloc::{GlobalAlloc, Layout}; + use core::cmp; + use core::ptr; + impl super::System { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout, + new_size: usize) -> *mut u8 { + // Docs for GlobalAlloc::realloc require this to be valid: + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + let new_ptr = GlobalAlloc::alloc(self, new_layout); + if !new_ptr.is_null() { + let size = cmp::min(old_layout.size(), new_size); + ptr::copy_nonoverlapping(ptr, new_ptr, size); + GlobalAlloc::dealloc(self, ptr, old_layout); + } + new_ptr + } + } +} +#[cfg(any(unix, target_os = "redox"))] +mod platform { + extern crate libc; + use core::ptr; + use MIN_ALIGN; + use System; + use core::alloc::{GlobalAlloc, Layout}; + unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::malloc(layout.size()) as *mut u8 + } else { + #[cfg(target_os = "macos")] + { + if layout.align() > (1 << 31) { + return ptr::null_mut() + } + } + aligned_malloc(&layout) + } + } + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::calloc(layout.size(), 1) as *mut u8 + } else { + let ptr = self.alloc(layout.clone()); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, layout.size()); + } + ptr + } + } + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + libc::free(ptr as *mut libc::c_void) + } + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + } else { + self.realloc_fallback(ptr, layout, new_size) + } + } + } + #[cfg(any(target_os = "android", + target_os = "hermit", + target_os = "redox", + target_os = "solaris"))] + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + // On android we currently target API level 9 which unfortunately + // doesn't have the `posix_memalign` API used below. Instead we use + // `memalign`, but this unfortunately has the property on some systems + // where the memory returned cannot be deallocated by `free`! + // + // Upon closer inspection, however, this appears to work just fine with + // Android, so for this platform we should be fine to call `memalign` + // (which is present in API level 9). Some helpful references could + // possibly be chromium using memalign [1], attempts at documenting that + // memalign + free is ok [2] [3], or the current source of chromium + // which still uses memalign on android [4]. + // + // [1]: https://codereview.chromium.org/10796020/ + // [2]: https://code.google.com/p/android/issues/detail?id=35391 + // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 + // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ + // /memory/aligned_memory.cc + libc::memalign(layout.align(), layout.size()) as *mut u8 + } + #[cfg(not(any(target_os = "android", + target_os = "hermit", + target_os = "redox", + target_os = "solaris")))] + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + let mut out = ptr::null_mut(); + let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); + if ret != 0 { + ptr::null_mut() + } else { + out as *mut u8 + } + } +} +#[cfg(windows)] +#[allow(nonstandard_style)] +mod platform { + use MIN_ALIGN; + use System; + use core::alloc::{GlobalAlloc, Layout}; + type LPVOID = *mut u8; + type HANDLE = LPVOID; + type SIZE_T = usize; + type DWORD = u32; + type BOOL = i32; + extern "system" { + fn GetProcessHeap() -> HANDLE; + fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; + fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; + fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; + fn GetLastError() -> DWORD; + } + #[repr(C)] + struct Header(*mut u8); + const HEAP_ZERO_MEMORY: DWORD = 0x00000008; + unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { + &mut *(ptr as *mut Header).offset(-1) + } + unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 { + let aligned = ptr.add(align - (ptr as usize & (align - 1))); + *get_header(aligned) = Header(ptr); + aligned + } + #[inline] + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 { + let ptr = if layout.align() <= MIN_ALIGN { + HeapAlloc(GetProcessHeap(), flags, layout.size()) + } else { + let size = layout.size() + layout.align(); + let ptr = HeapAlloc(GetProcessHeap(), flags, size); + if ptr.is_null() { + ptr + } else { + align_ptr(ptr, layout.align()) + } + }; + ptr as *mut u8 + } + unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + allocate_with_flags(layout, 0) + } + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + allocate_with_flags(layout, HEAP_ZERO_MEMORY) + } + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + if layout.align() <= MIN_ALIGN { + let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); + debug_assert!(err != 0, "Failed to free heap memory: {}", + GetLastError()); + } else { + let header = get_header(ptr); + let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); + debug_assert!(err != 0, "Failed to free heap memory: {}", + GetLastError()); + } + } + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN { + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8 + } else { + self.realloc_fallback(ptr, layout, new_size) + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,69 @@ +// Adapted from rustc run-pass test suite + +#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] +#![feature(rustc_attrs)] + +use std::{ + ops::{Deref, CoerceUnsized, DispatchFromDyn}, + marker::Unsize, +}; + +struct Ptr(Box); + +impl Deref for Ptr { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} + +impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} +impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} + +struct Wrapper(T); + +impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl, U> CoerceUnsized> for Wrapper {} +impl, U> DispatchFromDyn> for Wrapper {} + + +trait Trait { + // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable + // without unsized_locals), but wrappers arond `Self` currently are not. + // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented + // fn wrapper(self: Wrapper) -> i32; + fn ptr_wrapper(self: Ptr>) -> i32; + fn wrapper_ptr(self: Wrapper>) -> i32; + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; +} + +impl Trait for i32 { + fn ptr_wrapper(self: Ptr>) -> i32 { + **self + } + fn wrapper_ptr(self: Wrapper>) -> i32 { + **self + } + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32 { + ***self + } +} + +fn main() { + let pw = Ptr(Box::new(Wrapper(5))) as Ptr>; + assert_eq!(pw.ptr_wrapper(), 5); + + let wp = Wrapper(Ptr(Box::new(6))) as Wrapper>; + assert_eq!(wp.wrapper_ptr(), 6); + + let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper>>; + assert_eq!(wpw.wrapper_ptr_wrapper(), 7); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/dst-field-align.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/dst-field-align.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/dst-field-align.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/dst-field-align.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,67 @@ +// run-pass +#![allow(dead_code)] +struct Foo { + a: u16, + b: T +} + +trait Bar { + fn get(&self) -> usize; +} + +impl Bar for usize { + fn get(&self) -> usize { *self } +} + +struct Baz { + a: T +} + +struct HasDrop { + ptr: Box, + data: T +} + +fn main() { + // Test that zero-offset works properly + let b : Baz = Baz { a: 7 }; + assert_eq!(b.a.get(), 7); + let b : &Baz = &b; + assert_eq!(b.a.get(), 7); + + // Test that the field is aligned properly + let f : Foo = Foo { a: 0, b: 11 }; + assert_eq!(f.b.get(), 11); + let ptr1 : *const u8 = &f.b as *const _ as *const u8; + + let f : &Foo = &f; + let ptr2 : *const u8 = &f.b as *const _ as *const u8; + assert_eq!(f.b.get(), 11); + + // The pointers should be the same + assert_eq!(ptr1, ptr2); + + // Test that nested DSTs work properly + let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; + assert_eq!(f.b.b.get(), 17); + let f : &Foo> = &f; + assert_eq!(f.b.b.get(), 17); + + // Test that get the pointer via destructuring works + + let f : Foo = Foo { a: 0, b: 11 }; + let f : &Foo = &f; + let &Foo { a: _, b: ref bar } = f; + assert_eq!(bar.get(), 11); + + // Make sure that drop flags don't screw things up + + let d : HasDrop> = HasDrop { + ptr: Box::new(0), + data: Baz { a: [1,2,3,4] } + }; + assert_eq!([1,2,3,4], d.data.a); + + let d : &HasDrop> = &d; + assert_eq!(&[1,2,3,4], &d.data.a); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/example.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/example.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/example.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/example.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,208 @@ +#![feature(no_core, unboxed_closures)] +#![no_core] +#![allow(dead_code)] + +extern crate mini_core; + +use mini_core::*; + +fn abc(a: u8) -> u8 { + a * 2 +} + +fn bcd(b: bool, a: u8) -> u8 { + if b { + a * 2 + } else { + a * 3 + } +} + +fn call() { + abc(42); +} + +fn indirect_call() { + let f: fn() = call; + f(); +} + +enum BoolOption { + Some(bool), + None, +} + +fn option_unwrap_or(o: BoolOption, d: bool) -> bool { + match o { + BoolOption::Some(b) => b, + BoolOption::None => d, + } +} + +fn ret_42() -> u8 { + 42 +} + +fn return_str() -> &'static str { + "hello world" +} + +fn promoted_val() -> &'static u8 { + &(1 * 2) +} + +fn cast_ref_to_raw_ptr(abc: &u8) -> *const u8 { + abc as *const u8 +} + +fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool { + a == b +} + +fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) { + ( + a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8, + b as u32, + ) +} + +fn char_cast(c: char) -> u8 { + c as u8 +} + +pub struct DebugTuple(()); + +fn debug_tuple() -> DebugTuple { + DebugTuple(()) +} + +fn size_of() -> usize { + intrinsics::size_of::() +} + +fn use_size_of() -> usize { + size_of::() +} + +unsafe fn use_copy_intrinsic(src: *const u8, dst: *mut u8) { + intrinsics::copy::(src, dst, 1); +} + +unsafe fn use_copy_intrinsic_ref(src: *const u8, dst: *mut u8) { + let copy2 = &intrinsics::copy::; + copy2(src, dst, 1); +} + +const ABC: u8 = 6 * 7; + +fn use_const() -> u8 { + ABC +} + +pub fn call_closure_3arg() { + (|_, _, _| {})(0u8, 42u16, 0u8) +} + +pub fn call_closure_2arg() { + (|_, _| {})(0u8, 42u16) +} + +struct IsNotEmpty; + +impl<'a, 'b> FnOnce<(&'a &'b [u16],)> for IsNotEmpty { + type Output = (u8, u8); + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u16],)) -> (u8, u8) { + self.call_mut(arg) + } +} + +impl<'a, 'b> FnMut<(&'a &'b [u16],)> for IsNotEmpty { + #[inline] + extern "rust-call" fn call_mut(&mut self, _arg: (&'a &'b [u16],)) -> (u8, u8) { + (0, 42) + } +} + +pub fn call_is_not_empty() { + IsNotEmpty.call_once((&(&[0u16] as &[_]),)); +} + +fn eq_char(a: char, b: char) -> bool { + a == b +} + +unsafe fn transmute(c: char) -> u32 { + intrinsics::transmute(c) +} + +unsafe fn deref_str_ptr(s: *const str) -> &'static str { + &*s +} + +fn use_array(arr: [u8; 3]) -> u8 { + arr[1] +} + +fn repeat_array() -> [u8; 3] { + [0; 3] +} + +fn array_as_slice(arr: &[u8; 3]) -> &[u8] { + arr +} + +unsafe fn use_ctlz_nonzero(a: u16) -> u16 { + intrinsics::ctlz_nonzero(a) +} + +fn ptr_as_usize(ptr: *const u8) -> usize { + ptr as usize +} + +fn float_cast(a: f32, b: f64) -> (f64, f32) { + (a as f64, b as f32) +} + +fn int_to_float(a: u8, b: i32) -> (f64, f32) { + (a as f64, b as f32) +} + +fn make_array() -> [u8; 3] { + [42, 0, 5] +} + +fn some_promoted_tuple() -> &'static (&'static str, &'static str) { + &("abc", "some") +} + +fn index_slice(s: &[u8]) -> u8 { + s[2] +} + +pub struct StrWrapper { + s: str, +} + +fn str_wrapper_get(w: &StrWrapper) -> &str { + &w.s +} + +fn i16_as_i8(a: i16) -> i8 { + a as i8 +} + +struct Unsized(u8, str); + +fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 { + &u.0 +} + +fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str { + &u.1 +} + +pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 { + a.0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,424 @@ +// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs + +#![feature( + no_core, unboxed_closures, start, lang_items, box_syntax, never_type, linkage, + extern_types, thread_local +)] +#![no_core] +#![allow(dead_code, non_camel_case_types)] + +extern crate mini_core; + +use mini_core::*; +use mini_core::libc::*; + +unsafe extern "C" fn my_puts(s: *const u8) { + puts(s); +} + +#[lang = "termination"] +trait Termination { + fn report(self) -> i32; +} + +impl Termination for () { + fn report(self) -> i32 { + unsafe { + NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44 + *NUM_REF as i32 + } + } +} + +trait SomeTrait { + fn object_safe(&self); +} + +impl SomeTrait for &'static str { + fn object_safe(&self) { + unsafe { + puts(*self as *const str as *const u8); + } + } +} + +struct NoisyDrop { + text: &'static str, + inner: NoisyDropInner, +} + +struct NoisyDropInner; + +impl Drop for NoisyDrop { + fn drop(&mut self) { + unsafe { + puts(self.text as *const str as *const u8); + } + } +} + +impl Drop for NoisyDropInner { + fn drop(&mut self) { + unsafe { + puts("Inner got dropped!\0" as *const str as *const u8); + } + } +} + +impl SomeTrait for NoisyDrop { + fn object_safe(&self) {} +} + +enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +#[lang = "start"] +fn start( + main: fn() -> T, + argc: isize, + argv: *const *const u8, +) -> isize { + if argc == 3 { + unsafe { puts(*argv); } + unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const u8)); } + unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const u8)); } + } + + main().report(); + 0 +} + +static mut NUM: u8 = 6 * 7; +static NUM_REF: &'static u8 = unsafe { &NUM }; + +macro_rules! assert { + ($e:expr) => { + if !$e { + panic(stringify!(! $e)); + } + }; +} + +macro_rules! assert_eq { + ($l:expr, $r: expr) => { + if $l != $r { + panic(stringify!($l != $r)); + } + } +} + +struct Unique { + pointer: *const T, + _marker: PhantomData, +} + +impl CoerceUnsized> for Unique where T: Unsize {} + +unsafe fn zeroed() -> T { + let mut uninit = MaybeUninit { uninit: () }; + intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1); + uninit.value.value +} + +fn take_f32(_f: f32) {} +fn take_unique(_u: Unique<()>) {} + +fn return_u128_pair() -> (u128, u128) { + (0, 0) +} + +fn call_return_u128_pair() { + return_u128_pair(); +} + +fn main() { + take_unique(Unique { + pointer: 0 as *const (), + _marker: PhantomData, + }); + take_f32(0.1); + + //call_return_u128_pair(); + + let slice = &[0, 1] as &[i32]; + let slice_ptr = slice as *const [i32] as *const i32; + + assert_eq!(slice_ptr as usize % 4, 0); + + //return; + + unsafe { + printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8); + + let hello: &[u8] = b"Hello\0" as &[u8; 6]; + let ptr: *const u8 = hello as *const [u8] as *const u8; + puts(ptr); + + let world: Box<&str> = box "World!\0"; + puts(*world as *const str as *const u8); + world as Box; + + assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8); + + assert_eq!(intrinsics::bswap(0xabu8), 0xabu8); + assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16); + assert_eq!(intrinsics::bswap(0xffee_ddccu32), 0xccdd_eeffu32); + assert_eq!(intrinsics::bswap(0x1234_5678_ffee_ddccu64), 0xccdd_eeff_7856_3412u64); + + assert_eq!(intrinsics::size_of_val(hello) as u8, 6); + + let chars = &['C', 'h', 'a', 'r', 's']; + let chars = chars as &[char]; + assert_eq!(intrinsics::size_of_val(chars) as u8, 4 * 5); + + let a: &dyn SomeTrait = &"abc\0"; + a.object_safe(); + + assert_eq!(intrinsics::size_of_val(a) as u8, 16); + assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); + + assert_eq!(intrinsics::min_align_of::() as u8, 2); + assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8); + + assert!(!intrinsics::needs_drop::()); + assert!(intrinsics::needs_drop::()); + + Unique { + pointer: 0 as *const &str, + _marker: PhantomData, + } as Unique; + + struct MyDst(T); + + intrinsics::size_of_val(&MyDst([0u8; 4]) as &MyDst<[u8]>); + + struct Foo { + x: u8, + y: !, + } + + unsafe fn uninitialized() -> T { + MaybeUninit { uninit: () }.value.value + } + + zeroed::<(u8, u8)>(); + #[allow(unreachable_code)] + { + if false { + zeroed::(); + zeroed::(); + uninitialized::(); + } + } + } + + let _ = box NoisyDrop { + text: "Boxed outer got dropped!\0", + inner: NoisyDropInner, + } as Box; + + const FUNC_REF: Option = Some(main); + match FUNC_REF { + Some(_) => {}, + None => assert!(false), + } + + match Ordering::Less { + Ordering::Less => {}, + _ => assert!(false), + } + + [NoisyDropInner, NoisyDropInner]; + + let x = &[0u32, 42u32] as &[u32]; + match x { + [] => assert_eq!(0u32, 1), + [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize), + } + + assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42); + + extern { + #[linkage = "weak"] + static ABC: *const u8; + } + + { + extern { + #[linkage = "weak"] + static ABC: *const u8; + } + } + + // TODO(antoyo): to make this work, support weak linkage. + //unsafe { assert_eq!(ABC as usize, 0); } + + &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>; + + let f = 1000.0; + assert_eq!(f as u8, 255); + let f2 = -1000.0; + assert_eq!(f2 as i8, -128); + assert_eq!(f2 as u8, 0); + + static ANOTHER_STATIC: &u8 = &A_STATIC; + assert_eq!(*ANOTHER_STATIC, 42); + + check_niche_behavior(); + + extern "C" { + type ExternType; + } + + struct ExternTypeWrapper { + _a: ExternType, + } + + let nullptr = 0 as *const (); + let extern_nullptr = nullptr as *const ExternTypeWrapper; + extern_nullptr as *const (); + let slice_ptr = &[] as *const [u8]; + slice_ptr as *const u8; + + #[cfg(not(jit))] + test_tls(); +} + +#[repr(C)] +enum c_void { + _1, + _2, +} + +type c_int = i32; +type c_ulong = u64; + +type pthread_t = c_ulong; + +#[repr(C)] +struct pthread_attr_t { + __size: [u64; 7], +} + +#[link(name = "pthread")] +extern "C" { + fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; + + fn pthread_create( + native: *mut pthread_t, + attr: *const pthread_attr_t, + f: extern "C" fn(_: *mut c_void) -> *mut c_void, + value: *mut c_void + ) -> c_int; + + fn pthread_join( + native: pthread_t, + value: *mut *mut c_void + ) -> c_int; +} + +#[thread_local] +#[cfg(not(jit))] +static mut TLS: u8 = 42; + +#[cfg(not(jit))] +extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void { + unsafe { TLS = 0; } + 0 as *mut c_void +} + +#[cfg(not(jit))] +fn test_tls() { + unsafe { + let mut attr: pthread_attr_t = zeroed(); + let mut thread: pthread_t = 0; + + assert_eq!(TLS, 42); + + if pthread_attr_init(&mut attr) != 0 { + assert!(false); + } + + if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 { + assert!(false); + } + + let mut res = 0 as *mut c_void; + pthread_join(thread, &mut res); + + // TLS of main thread must not have been changed by the other thread. + assert_eq!(TLS, 42); + + puts("TLS works!\n\0" as *const str as *const u8); + } +} + +// Copied ui/issues/issue-61696.rs + +pub enum Infallible {} + +// The check that the `bool` field of `V1` is encoding a "niche variant" +// (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect, +// causing valid `V1` values to be interpreted as other variants. +pub enum E1 { + V1 { f: bool }, + V2 { f: Infallible }, + V3, + V4, +} + +// Computing the discriminant used to be done using the niche type (here `u8`, +// from the `bool` field of `V1`), overflowing for variants with large enough +// indices (`V3` and `V4`), causing them to be interpreted as other variants. +pub enum E2 { + V1 { f: bool }, + + /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X), + _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X), + _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X), + _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X), + _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X), + _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X), + _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X), + _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X), + _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X), + _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X), + _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X), + _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X), + _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X), + _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X), + _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X), + _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X), + _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X), + _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X), + _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X), + _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X), + _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X), + _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X), + _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X), + _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X), + _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X), + _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X), + _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X), + _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X), + _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X), + _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X), + _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X), + _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X), + + V3, + V4, +} + +fn check_niche_behavior () { + if let E1::V2 { .. } = (E1::V1 { f: true }) { + intrinsics::abort(); + } + + if let E2::V1 { .. } = E2::V3:: { + intrinsics::abort(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mini_core.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mini_core.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mini_core.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mini_core.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,585 @@ +#![feature( + no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, + untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits, + thread_local +)] +#![no_core] +#![allow(dead_code)] + +#[no_mangle] +unsafe extern "C" fn _Unwind_Resume() { + intrinsics::unreachable(); +} + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "unsize"] +pub trait Unsize {} + +#[lang = "coerce_unsized"] +pub trait CoerceUnsized {} + +impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +#[lang = "dispatch_from_dyn"] +pub trait DispatchFromDyn {} + +// &T -> &U +impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} +// &mut T -> &mut U +impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} +// *const T -> *const U +impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} +// *mut T -> *mut U +impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} +impl, U: ?Sized> DispatchFromDyn> for Box {} + +#[lang = "receiver"] +pub trait Receiver {} + +impl Receiver for &T {} +impl Receiver for &mut T {} +impl Receiver for Box {} + +#[lang = "copy"] +pub unsafe trait Copy {} + +unsafe impl Copy for bool {} +unsafe impl Copy for u8 {} +unsafe impl Copy for u16 {} +unsafe impl Copy for u32 {} +unsafe impl Copy for u64 {} +unsafe impl Copy for usize {} +unsafe impl Copy for i8 {} +unsafe impl Copy for i16 {} +unsafe impl Copy for i32 {} +unsafe impl Copy for isize {} +unsafe impl Copy for f32 {} +unsafe impl Copy for char {} +unsafe impl<'a, T: ?Sized> Copy for &'a T {} +unsafe impl Copy for *const T {} +unsafe impl Copy for *mut T {} + +#[lang = "sync"] +pub unsafe trait Sync {} + +unsafe impl Sync for bool {} +unsafe impl Sync for u8 {} +unsafe impl Sync for u16 {} +unsafe impl Sync for u32 {} +unsafe impl Sync for u64 {} +unsafe impl Sync for usize {} +unsafe impl Sync for i8 {} +unsafe impl Sync for i16 {} +unsafe impl Sync for i32 {} +unsafe impl Sync for isize {} +unsafe impl Sync for char {} +unsafe impl<'a, T: ?Sized> Sync for &'a T {} +unsafe impl Sync for [u8; 16] {} + +#[lang = "freeze"] +unsafe auto trait Freeze {} + +unsafe impl Freeze for PhantomData {} +unsafe impl Freeze for *const T {} +unsafe impl Freeze for *mut T {} +unsafe impl Freeze for &T {} +unsafe impl Freeze for &mut T {} + +#[lang = "structural_peq"] +pub trait StructuralPartialEq {} + +#[lang = "structural_teq"] +pub trait StructuralEq {} + +#[lang = "not"] +pub trait Not { + type Output; + + fn not(self) -> Self::Output; +} + +impl Not for bool { + type Output = bool; + + fn not(self) -> bool { + !self + } +} + +#[lang = "mul"] +pub trait Mul { + type Output; + + #[must_use] + fn mul(self, rhs: RHS) -> Self::Output; +} + +impl Mul for u8 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +impl Mul for usize { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +#[lang = "add"] +pub trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +#[lang = "rem"] +pub trait Rem { + type Output; + + fn rem(self, rhs: RHS) -> Self::Output; +} + +impl Rem for usize { + type Output = Self; + + fn rem(self, rhs: Self) -> Self { + self % rhs + } +} + +#[lang = "bitor"] +pub trait BitOr { + type Output; + + #[must_use] + fn bitor(self, rhs: RHS) -> Self::Output; +} + +impl BitOr for bool { + type Output = bool; + + fn bitor(self, rhs: bool) -> bool { + self | rhs + } +} + +impl<'a> BitOr for &'a bool { + type Output = bool; + + fn bitor(self, rhs: bool) -> bool { + *self | rhs + } +} + +#[lang = "eq"] +pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + fn ne(&self, other: &Rhs) -> bool; +} + +impl PartialEq for u8 { + fn eq(&self, other: &u8) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u8) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for u16 { + fn eq(&self, other: &u16) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u16) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for u32 { + fn eq(&self, other: &u32) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u32) -> bool { + (*self) != (*other) + } +} + + +impl PartialEq for u64 { + fn eq(&self, other: &u64) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u64) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for usize { + fn eq(&self, other: &usize) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &usize) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for i8 { + fn eq(&self, other: &i8) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &i8) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &i32) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &i32) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for isize { + fn eq(&self, other: &isize) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &isize) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for char { + fn eq(&self, other: &char) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &char) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for *const T { + fn eq(&self, other: &*const T) -> bool { + *self == *other + } + fn ne(&self, other: &*const T) -> bool { + *self != *other + } +} + +#[lang = "neg"] +pub trait Neg { + type Output; + + fn neg(self) -> Self::Output; +} + +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> i8 { + -self + } +} + +impl Neg for i16 { + type Output = i16; + + fn neg(self) -> i16 { + self + } +} + +impl Neg for isize { + type Output = isize; + + fn neg(self) -> isize { + -self + } +} + +impl Neg for f32 { + type Output = f32; + + fn neg(self) -> f32 { + -self + } +} + +pub enum Option { + Some(T), + None, +} + +pub use Option::*; + +#[lang = "phantom_data"] +pub struct PhantomData; + +#[lang = "fn_once"] +#[rustc_paren_sugar] +pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +#[lang = "fn_mut"] +#[rustc_paren_sugar] +pub trait FnMut: FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[lang = "panic"] +#[track_caller] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\n\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_bounds_check"] +#[track_caller] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +#[lang = "eh_personality"] +fn eh_personality() -> ! { + loop {} +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "deref"] +pub trait Deref { + type Target: ?Sized; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "owned_box"] +pub struct Box(*mut T); + +impl, U: ?Sized> CoerceUnsized> for Box {} + +impl Drop for Box { + fn drop(&mut self) { + // drop is currently performed by compiler. + } +} + +impl Deref for Box { + type Target = T; + + fn deref(&self) -> &Self::Target { + &**self + } +} + +#[lang = "exchange_malloc"] +unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { + libc::malloc(size) +} + +#[lang = "box_free"] +unsafe fn box_free(ptr: *mut T) { + libc::free(ptr as *mut u8); +} + +#[lang = "drop"] +pub trait Drop { + fn drop(&mut self); +} + +#[lang = "manually_drop"] +#[repr(transparent)] +pub struct ManuallyDrop { + pub value: T, +} + +#[lang = "maybe_uninit"] +#[repr(transparent)] +pub union MaybeUninit { + pub uninit: (), + pub value: ManuallyDrop, +} + +pub mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + pub fn size_of() -> usize; + pub fn size_of_val(val: *const T) -> usize; + pub fn min_align_of() -> usize; + pub fn min_align_of_val(val: *const T) -> usize; + pub fn copy(src: *const T, dst: *mut T, count: usize); + pub fn transmute(e: T) -> U; + pub fn ctlz_nonzero(x: T) -> T; + pub fn needs_drop() -> bool; + pub fn bitreverse(x: T) -> T; + pub fn bswap(x: T) -> T; + pub fn write_bytes(dst: *mut T, val: u8, count: usize); + pub fn unreachable() -> !; + } +} + +pub mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + pub fn malloc(size: usize) -> *mut u8; + pub fn free(ptr: *mut u8); + pub fn memcpy(dst: *mut u8, src: *const u8, size: usize); + pub fn memmove(dst: *mut u8, src: *const u8, size: usize); + pub fn strncpy(dst: *mut u8, src: *const u8, size: usize); + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +extern { + type VaListImpl; +} + +#[lang = "va_list"] +#[repr(transparent)] +pub struct VaList<'a>(&'a mut VaListImpl); + +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro stringify($($t:tt)*) { /* compiler built-in */ } + +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro file() { /* compiler built-in */ } + +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro line() { /* compiler built-in */ } + +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro cfg() { /* compiler built-in */ } + +pub static A_STATIC: u8 = 42; + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[no_mangle] +pub fn get_tls() -> u8 { + #[thread_local] + static A: u8 = 42; + + A +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mod_bench.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mod_bench.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mod_bench.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/mod_bench.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,37 @@ +#![feature(start, box_syntax, core_intrinsics, lang_items)] +#![no_std] + +#[link(name = "c")] +extern {} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + unsafe { + core::intrinsics::abort(); + } +} + +#[lang="eh_personality"] +fn eh_personality(){} + +// Required for rustc_codegen_llvm +#[no_mangle] +unsafe extern "C" fn _Unwind_Resume() { + core::intrinsics::unreachable(); +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + for i in 2..100_000_000 { + black_box((i + 1) % i); + } + + 0 +} + +#[inline(never)] +fn black_box(i: u32) { + if i != 1 { + unsafe { core::intrinsics::abort(); } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/std_example.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/std_example.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/std_example.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/std_example.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,278 @@ +#![feature(core_intrinsics, generators, generator_trait, is_sorted)] + +use std::arch::x86_64::*; +use std::io::Write; +use std::ops::Generator; + +extern { + pub fn printf(format: *const i8, ...) -> i32; +} + +fn main() { + let mutex = std::sync::Mutex::new(()); + let _guard = mutex.lock().unwrap(); + + let _ = ::std::iter::repeat('a' as u8).take(10).collect::>(); + let stderr = ::std::io::stderr(); + let mut stderr = stderr.lock(); + + std::thread::spawn(move || { + println!("Hello from another thread!"); + }); + + writeln!(stderr, "some {} text", "").unwrap(); + + let _ = std::process::Command::new("true").env("c", "d").spawn(); + + println!("cargo:rustc-link-lib=z"); + + static ONCE: std::sync::Once = std::sync::Once::new(); + ONCE.call_once(|| {}); + + let _eq = LoopState::Continue(()) == LoopState::Break(()); + + // Make sure ByValPair values with differently sized components are correctly passed + map(None::<(u8, Box)>); + + println!("{}", 2.3f32.exp()); + println!("{}", 2.3f32.exp2()); + println!("{}", 2.3f32.abs()); + println!("{}", 2.3f32.sqrt()); + println!("{}", 2.3f32.floor()); + println!("{}", 2.3f32.ceil()); + println!("{}", 2.3f32.min(1.0)); + println!("{}", 2.3f32.max(1.0)); + println!("{}", 2.3f32.powi(2)); + println!("{}", 2.3f32.log2()); + assert_eq!(2.3f32.copysign(-1.0), -2.3f32); + println!("{}", 2.3f32.powf(2.0)); + + assert_eq!(-128i8, (-128i8).saturating_sub(1)); + assert_eq!(127i8, 127i8.saturating_sub(-128)); + assert_eq!(-128i8, (-128i8).saturating_add(-128)); + assert_eq!(127i8, 127i8.saturating_add(1)); + + assert_eq!(-32768i16, (-32768i16).saturating_add(-32768)); + assert_eq!(32767i16, 32767i16.saturating_add(1)); + + assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26); + assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7); + + let _d = 0i128.checked_div(2i128); + let _d = 0u128.checked_div(2u128); + assert_eq!(1u128 + 2, 3); + + assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128); + assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128); + assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128); + + let tmp = 353985398u128; + assert_eq!(tmp * 932490u128, 330087843781020u128); + + let tmp = -0x1234_5678_9ABC_DEF0i64; + assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128); + + // Check that all u/i128 <-> float casts work correctly. + let houndred_u128 = 100u128; + let houndred_i128 = 100i128; + let houndred_f32 = 100.0f32; + let houndred_f64 = 100.0f64; + assert_eq!(houndred_u128 as f32, 100.0); + assert_eq!(houndred_u128 as f64, 100.0); + assert_eq!(houndred_f32 as u128, 100); + assert_eq!(houndred_f64 as u128, 100); + assert_eq!(houndred_i128 as f32, 100.0); + assert_eq!(houndred_i128 as f64, 100.0); + assert_eq!(houndred_f32 as i128, 100); + assert_eq!(houndred_f64 as i128, 100); + + let _a = 1u32 << 2u8; + + let empty: [i32; 0] = []; + assert!(empty.is_sorted()); + + println!("{:?}", std::intrinsics::caller_location()); + + /*unsafe { + test_simd(); + }*/ + + Box::pin(move |mut _task_context| { + yield (); + }).as_mut().resume(0); + + println!("End"); +} + +/*#[target_feature(enable = "sse2")] +unsafe fn test_simd() { + let x = _mm_setzero_si128(); + let y = _mm_set1_epi16(7); + let or = _mm_or_si128(x, y); + let cmp_eq = _mm_cmpeq_epi8(y, y); + let cmp_lt = _mm_cmplt_epi8(y, y); + + /*assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]); + assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]); + assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]); + + test_mm_slli_si128(); + test_mm_movemask_epi8(); + test_mm256_movemask_epi8(); + test_mm_add_epi8(); + test_mm_add_pd(); + test_mm_cvtepi8_epi16(); + test_mm_cvtsi128_si64(); + + // FIXME(#666) implement `#[rustc_arg_required_const(..)]` support + //test_mm_extract_epi8(); + + let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); + assert_eq!(mask1, 1);*/ +}*/ + +/*#[target_feature(enable = "sse2")] +unsafe fn test_mm_slli_si128() { + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, 1); + let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, 15); + let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + assert_eq_m128i(r, e); + + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, 16); + assert_eq_m128i(r, _mm_set1_epi8(0)); + + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, -1); + assert_eq_m128i(_mm_set1_epi8(0), r); + + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, -0x80000000); + assert_eq_m128i(r, _mm_set1_epi8(0)); +} + +#[target_feature(enable = "sse2")] +unsafe fn test_mm_movemask_epi8() { + #[rustfmt::skip] + let a = _mm_setr_epi8( + 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01, + 0b0101, 0b1111_0000u8 as i8, 0, 0, + 0, 0, 0b1111_0000u8 as i8, 0b0101, + 0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, + ); + let r = _mm_movemask_epi8(a); + assert_eq!(r, 0b10100100_00100101); +} + +#[target_feature(enable = "avx2")] +unsafe fn test_mm256_movemask_epi8() { + let a = _mm256_set1_epi8(-1); + let r = _mm256_movemask_epi8(a); + let e = -1; + assert_eq!(r, e); +} + +#[target_feature(enable = "sse2")] +unsafe fn test_mm_add_epi8() { + let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm_setr_epi8( + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ); + let r = _mm_add_epi8(a, b); + #[rustfmt::skip] + let e = _mm_setr_epi8( + 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, + ); + assert_eq_m128i(r, e); +} + +#[target_feature(enable = "sse2")] +unsafe fn test_mm_add_pd() { + let a = _mm_setr_pd(1.0, 2.0); + let b = _mm_setr_pd(5.0, 10.0); + let r = _mm_add_pd(a, b); + assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0)); +} + +fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) { + unsafe { + assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y)); + } +} + +#[target_feature(enable = "sse2")] +pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { + if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { + panic!("{:?} != {:?}", a, b); + } +} + +#[target_feature(enable = "sse2")] +unsafe fn test_mm_cvtsi128_si64() { + let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0])); + assert_eq!(r, 5); +} + +#[target_feature(enable = "sse4.1")] +unsafe fn test_mm_cvtepi8_epi16() { + let a = _mm_set1_epi8(10); + let r = _mm_cvtepi8_epi16(a); + let e = _mm_set1_epi16(10); + assert_eq_m128i(r, e); + let a = _mm_set1_epi8(-10); + let r = _mm_cvtepi8_epi16(a); + let e = _mm_set1_epi16(-10); + assert_eq_m128i(r, e); +} + +#[target_feature(enable = "sse4.1")] +unsafe fn test_mm_extract_epi8() { + #[rustfmt::skip] + let a = _mm_setr_epi8( + -1, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + ); + let r1 = _mm_extract_epi8(a, 0); + let r2 = _mm_extract_epi8(a, 19); + assert_eq!(r1, 0xFF); + assert_eq!(r2, 3); +}*/ + +#[derive(PartialEq)] +enum LoopState { + Continue(()), + Break(()) +} + +pub enum Instruction { + Increment, + Loop, +} + +fn map(a: Option<(u8, Box)>) -> Option> { + match a { + None => None, + Some((_, instr)) => Some(instr), + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,97 @@ +// Based on https://github.com/rust-lang/rust/blob/c5840f9d252c2f5cc16698dbf385a29c5de3ca07/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs + +// Test that array subslice patterns are correctly handled in const evaluation. + +// run-pass + +#[derive(PartialEq, Debug, Clone)] +struct N(u8); + +#[derive(PartialEq, Debug, Clone)] +struct Z; + +macro_rules! n { + ($($e:expr),* $(,)?) => { + [$(N($e)),*] + } +} + +// This macro has an unused variable so that it can be repeated base on the +// number of times a repeated variable (`$e` in `z`) occurs. +macro_rules! zed { + ($e:expr) => { Z } +} + +macro_rules! z { + ($($e:expr),* $(,)?) => { + [$(zed!($e)),*] + } +} + +// Compare constant evaluation and runtime evaluation of a given expression. +macro_rules! compare_evaluation { + ($e:expr, $t:ty $(,)?) => {{ + const CONST_EVAL: $t = $e; + const fn const_eval() -> $t { $e } + static CONST_EVAL2: $t = const_eval(); + let runtime_eval = $e; + assert_eq!(CONST_EVAL, runtime_eval); + assert_eq!(CONST_EVAL2, runtime_eval); + }} +} + +// Repeat `$test`, substituting the given macro variables with the given +// identifiers. +// +// For example: +// +// repeat! { +// ($name); X; Y: +// struct $name; +// } +// +// Expands to: +// +// struct X; struct Y; +// +// This is used to repeat the tests using both the `N` and `Z` +// types. +macro_rules! repeat { + (($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => { + macro_rules! single { + ($($dollar $placeholder:ident),*) => { $($test)* } + } + $(single!($($values),+);)* + } +} + +fn main() { + repeat! { + ($arr $Ty); n, N; z, Z: + compare_evaluation!({ let [_, x @ .., _] = $arr!(1, 2, 3, 4); x }, [$Ty; 2]); + compare_evaluation!({ let [_, ref x @ .., _] = $arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]); + compare_evaluation!({ let [_, x @ .., _] = &$arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]); + + compare_evaluation!({ let [_, _, x @ .., _, _] = $arr!(1, 2, 3, 4); x }, [$Ty; 0]); + compare_evaluation!( + { let [_, _, ref x @ .., _, _] = $arr!(1, 2, 3, 4); x }, + &'static [$Ty; 0], + ); + compare_evaluation!( + { let [_, _, x @ .., _, _] = &$arr!(1, 2, 3, 4); x }, + &'static [$Ty; 0], + ); + + compare_evaluation!({ let [_, .., x] = $arr!(1, 2, 3, 4); x }, $Ty); + compare_evaluation!({ let [_, .., ref x] = $arr!(1, 2, 3, 4); x }, &'static $Ty); + compare_evaluation!({ let [_, _y @ .., x] = &$arr!(1, 2, 3, 4); x }, &'static $Ty); + } + + compare_evaluation!({ let [_, .., N(x)] = n!(1, 2, 3, 4); x }, u8); + compare_evaluation!({ let [_, .., N(ref x)] = n!(1, 2, 3, 4); x }, &'static u8); + compare_evaluation!({ let [_, .., N(x)] = &n!(1, 2, 3, 4); x }, &'static u8); + + compare_evaluation!({ let [N(x), .., _] = n!(1, 2, 3, 4); x }, u8); + compare_evaluation!({ let [N(ref x), .., _] = n!(1, 2, 3, 4); x }, &'static u8); + compare_evaluation!({ let [N(x), .., _] = &n!(1, 2, 3, 4); x }, &'static u8); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,40 @@ +// Based on https://github.com/anp/rust/blob/175631311716d7dfeceec40d2587cde7142ffa8c/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs + +// run-pass + +use std::panic::Location; + +#[track_caller] +fn tracked() -> &'static Location<'static> { + Location::caller() +} + +fn nested_intrinsic() -> &'static Location<'static> { + Location::caller() +} + +fn nested_tracked() -> &'static Location<'static> { + tracked() +} + +fn main() { + let location = Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), 21); + assert_eq!(location.column(), 20); + + let tracked = tracked(); + assert_eq!(tracked.file(), file!()); + assert_eq!(tracked.line(), 26); + assert_eq!(tracked.column(), 19); + + let nested = nested_intrinsic(); + assert_eq!(nested.file(), file!()); + assert_eq!(nested.line(), 13); + assert_eq!(nested.column(), 5); + + let contained = nested_tracked(); + assert_eq!(contained.file(), file!()); + assert_eq!(contained.line(), 17); + assert_eq!(contained.column(), 5); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/.github/workflows/main.yml rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/.github/workflows/main.yml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/.github/workflows/main.yml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/.github/workflows/main.yml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,96 @@ +name: CI + +on: + - push + - pull_request + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v2 + + - name: Install packages + run: sudo apt-get install ninja-build ripgrep + + - name: Download artifact + uses: dawidd6/action-download-artifact@v2 + with: + workflow: main.yml + name: libgccjit.so + path: gcc-build + repo: antoyo/gcc + + - name: Setup path to libgccjit + run: | + echo $(readlink -f gcc-build) > gcc_path + ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0 + + - name: Set LIBRARY_PATH + run: | + echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV + + # https://github.com/actions/cache/issues/133 + - name: Fixup owner of ~/.cargo/ + # Don't remove the trailing /. It is necessary to follow the symlink. + run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/ + + - name: Cache cargo installed crates + uses: actions/cache@v1.1.2 + with: + path: ~/.cargo/bin + key: cargo-installed-crates2-ubuntu-latest + + - name: Cache cargo registry + uses: actions/cache@v1 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo index + uses: actions/cache@v1 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v1.1.2 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} + + - name: Build + run: | + ./prepare_build.sh + ./build.sh + cargo test + ./clean_all.sh + + - name: Prepare dependencies + run: | + git config --global user.email "user@example.com" + git config --global user.name "User" + ./prepare.sh + + # Compile is a separate step, as the actions-rs/cargo action supports error annotations + - name: Compile + uses: actions-rs/cargo@v1.0.3 + with: + command: build + args: --release + + - name: Test + run: | + # Enable backtraces for easier debugging + export RUST_BACKTRACE=1 + + # Reduce amount of benchmark runs as they are slow + export COMPILE_RUNS=2 + export RUN_RUNS=2 + + ./test.sh --release diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/LICENSE-APACHE rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/LICENSE-APACHE --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/LICENSE-APACHE 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/LICENSE-APACHE 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/LICENSE-MIT rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/LICENSE-MIT --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/LICENSE-MIT 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/LICENSE-MIT 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,63 @@ +From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001 +From: bjorn3 +Date: Sun, 24 Nov 2019 15:10:23 +0100 +Subject: [PATCH] [core] Disable not compiling tests + +--- + library/core/tests/Cargo.toml | 8 ++++++++ + library/core/tests/num/flt2dec/mod.rs | 1 - + library/core/tests/num/int_macros.rs | 2 ++ + library/core/tests/num/uint_macros.rs | 2 ++ + library/core/tests/ptr.rs | 2 ++ + library/core/tests/slice.rs | 2 ++ + 6 files changed, 16 insertions(+), 1 deletion(-) + create mode 100644 library/core/tests/Cargo.toml + +diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml +new file mode 100644 +index 0000000..46fd999 +--- /dev/null ++++ b/library/core/tests/Cargo.toml +@@ -0,0 +1,8 @@ ++[package] ++name = "core" ++version = "0.0.0" ++edition = "2018" ++ ++[lib] ++name = "coretests" ++path = "lib.rs" +diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs +index a35897e..f0bf645 100644 +--- a/library/core/tests/num/flt2dec/mod.rs ++++ b/library/core/tests/num/flt2dec/mod.rs +@@ -13,7 +13,6 @@ mod strategy { + mod dragon; + mod grisu; + } +-mod random; + + pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { +diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs +index 6609bc3..241b497 100644 +--- a/library/core/tests/slice.rs ++++ b/library/core/tests/slice.rs +@@ -1209,6 +1209,7 @@ fn brute_force_rotate_test_1() { + } + } + ++/* + #[test] + #[cfg(not(target_arch = "wasm32"))] + fn sort_unstable() { +@@ -1394,6 +1395,7 @@ fn partition_at_index() { + v.select_nth_unstable(0); + assert!(v == [0xDEADBEEF]); + } ++*/ + + #[test] + #[should_panic(expected = "index 0 greater than length of slice")] +-- +2.21.0 (Apple Git-122) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,49 @@ +From dd82e95c9de212524e14fc60155de1ae40156dfc Mon Sep 17 00:00:00 2001 +From: bjorn3 +Date: Sun, 24 Nov 2019 15:34:06 +0100 +Subject: [PATCH] [core] Ignore failing tests + +--- + library/core/tests/iter.rs | 4 ++++ + library/core/tests/num/bignum.rs | 10 ++++++++++ + library/core/tests/num/mod.rs | 5 +++-- + library/core/tests/time.rs | 1 + + 4 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs +index 4bc44e9..8e3c7a4 100644 +--- a/library/core/tests/array.rs ++++ b/library/core/tests/array.rs +@@ -242,6 +242,7 @@ fn iterator_drops() { + assert_eq!(i.get(), 5); + } + ++/* + // This test does not work on targets without panic=unwind support. + // To work around this problem, test is marked is should_panic, so it will + // be automagically skipped on unsuitable targets, such as +@@ -283,6 +284,7 @@ fn array_default_impl_avoids_leaks_on_panic() { + assert_eq!(COUNTER.load(Relaxed), 0); + panic!("test succeeded") + } ++*/ + + #[test] + fn empty_array_is_always_default() { +@@ -304,6 +304,7 @@ fn array_map() { + assert_eq!(b, [1, 2, 3]); + } + ++/* + // See note on above test for why `should_panic` is used. + #[test] + #[should_panic(expected = "test succeeded")] +@@ -332,6 +333,7 @@ fn array_map_drop_safety() { + assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); + panic!("test succeeded") + } ++*/ + + #[test] + fn cell_allows_array_cycle() { +-- 2.21.0 (Apple Git-122) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/prepare_build.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/prepare_build.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/prepare_build.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/prepare_build.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +#!/bin/bash --verbose +set -e + +rustup component add rust-src rustc-dev llvm-tools-preview +./build_sysroot/prepare_sysroot_src.sh diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/prepare.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/prepare.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/prepare.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/prepare.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +#!/bin/bash --verbose +set -e + +source prepare_build.sh + +cargo install hyperfine || echo "Skipping hyperfine install" + +git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned" +pushd regex +git checkout -- . +git checkout 341f207c1071f7290e3f228c710817c280c8dca1 +popd + +git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned" +pushd simple-raytracer +git checkout -- . +git checkout 804a7a21b9e673a482797aa289a18ed480e4d813 + +# build with cg_llvm for perf comparison +cargo build +mv target/debug/main raytracer_cg_llvm +popd diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Readme.md rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Readme.md --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Readme.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/Readme.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,135 @@ +# WIP libgccjit codegen backend for rust + +This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used. + +**Despite its name, libgccjit can be used for ahead-of-time compilation, as is used here.** + +## Motivation + +The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM. +A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc. + +## Building + +**This requires a patched libgccjit in order to work. +The patches in [this repostory](https://github.com/antoyo/libgccjit-patches) need to be applied. +(Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.) +You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.** + +**Put the path to your custom build of libgccjit in the file `gcc_path`.** + +```bash +$ git clone https://github.com/rust-lang/rustc_codegen_gcc.git +$ cd rustc_codegen_gcc +$ ./prepare_build.sh # download and patch sysroot src +$ ./build.sh --release +``` + +To run the tests: + +```bash +$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking +$ ./test.sh --release +``` + +## Usage + +`$cg_gccjit_dir` is the directory you cloned this repo into in the following instructions. + +### Cargo + +```bash +$ CHANNEL="release" $cg_gccjit_dir/cargo.sh run +``` + +If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely. + +### Rustc + +> You should prefer using the Cargo method. + +```bash +$ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_gccjit_dir/target/release/librustc_codegen_gcc.so --sysroot $cg_gccjit_dir/build_sysroot/sysroot my_crate.rs +``` + +## Env vars + +
+
CG_GCCJIT_INCR_CACHE_DISABLED
+
Don't cache object files in the incremental cache. Useful during development of cg_gccjit + to make it possible to use incremental mode for all analyses performed by rustc without caching + object files when their content should have been changed by a change to cg_gccjit.
+
CG_GCCJIT_DISPLAY_CG_TIME
+
Display the time it took to perform codegen for a crate
+
+ +## Debugging + +Sometimes, libgccjit will crash and output an error like this: + +``` +during RTL pass: expand +libgccjit.so: error: in expmed_mode_index, at expmed.h:249 +0x7f0da2e61a35 expmed_mode_index + ../../../gcc/gcc/expmed.h:249 +0x7f0da2e61aa4 expmed_op_cost_ptr + ../../../gcc/gcc/expmed.h:271 +0x7f0da2e620dc sdiv_cost_ptr + ../../../gcc/gcc/expmed.h:540 +0x7f0da2e62129 sdiv_cost + ../../../gcc/gcc/expmed.h:558 +0x7f0da2e73c12 expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int) + ../../../gcc/gcc/expmed.c:4335 +0x7f0da2ea1423 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier) + ../../../gcc/gcc/expr.c:9240 +0x7f0da2cd1a1e expand_gimple_stmt_1 + ../../../gcc/gcc/cfgexpand.c:3796 +0x7f0da2cd1c30 expand_gimple_stmt + ../../../gcc/gcc/cfgexpand.c:3857 +0x7f0da2cd90a9 expand_gimple_basic_block + ../../../gcc/gcc/cfgexpand.c:5898 +0x7f0da2cdade8 execute + ../../../gcc/gcc/cfgexpand.c:6582 +``` + +To see the code which causes this error, call the following function: + +```c +gcc_jit_context_dump_to_file(ctxt, "/tmp/output.c", 1 /* update_locations */) +``` + +This will create a C-like file and add the locations into the IR pointing to this C file. +Then, rerun the program and it will output the location in the second line: + +``` +libgccjit.so: /tmp/something.c:61322:0: error: in expmed_mode_index, at expmed.h:249 +``` + +Or add a breakpoint to `add_error` in gdb and print the line number using: + +``` +p loc->m_line +``` + +### How to use a custom-build rustc + + * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). + * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`. + +### How to build a cross-compiling libgccjit + +#### Building libgccjit + + * Follow these instructions: https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ with the following changes: + * Configure gcc with `../gcc/configure --enable-host-shared --disable-multilib --enable-languages=c,jit,c++ --disable-bootstrap --enable-checking=release --prefix=/opt/m68k-gcc/ --target=m68k-linux --without-headers`. + * Some shells, like fish, don't define the environment variable `$MACHTYPE`. + * Add `CFLAGS="-Wno-error=attributes -g -O2"` at the end of the configure command for building glibc (`CFLAGS="-Wno-error=attributes -Wno-error=array-parameter -Wno-error=stringop-overflow -Wno-error=array-bounds -g -O2"` for glibc 2.31, which is useful for Debian). + +#### Configuring rustc_codegen_gcc + + * Set `TARGET_TRIPLE="m68k-unknown-linux-gnu"` in config.sh. + * Since rustc doesn't support this architecture yet, set it back to `TARGET_TRIPLE="mips-unknown-linux-gnu"` (or another target having the same attributes). Alternatively, create a [target specification file](https://book.avr-rust.com/005.1-the-target-specification-json-file.html) (note that the `arch` specified in this file must be supported by the rust compiler). + * Set `linker='-Clinker=m68k-linux-gcc'`. + * Set the path to the cross-compiling libgccjit in `gcc_path`. + * Disable the 128-bit integer types if the target doesn't support them by using `let i128_type = context.new_type::();` in `context.rs` (same for u128_type). + * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?). diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/rust-toolchain rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/rust-toolchain --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/rust-toolchain 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/rust-toolchain 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +nightly-2021-09-28 diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/rustup.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/rustup.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/rustup.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/rustup.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/bash + +set -e + +case $1 in + "prepare") + TOOLCHAIN=$(date +%Y-%m-%d) + + echo "=> Installing new nightly" + rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists + echo nightly-${TOOLCHAIN} > rust-toolchain + + echo "=> Uninstalling all old nighlies" + for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do + rustup toolchain uninstall $nightly + done + + ./clean_all.sh + ./prepare.sh + ;; + "commit") + git add rust-toolchain + git commit -m "Rustup to $(rustc -V)" + ;; + *) + echo "Unknown command '$1'" + echo "Usage: ./rustup.sh prepare|commit" + ;; +esac diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/abi.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/abi.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/abi.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/abi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,160 @@ +use gccjit::{ToRValue, Type}; +use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods}; +use rustc_middle::bug; +use rustc_middle::ty::Ty; +use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind}; + +use crate::builder::Builder; +use crate::context::CodegenCx; +use crate::intrinsic::ArgAbiExt; +use crate::type_of::LayoutGccExt; + +impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) { + // TODO(antoyo) + } + + fn get_param(&self, index: usize) -> Self::Value { + self.cx.current_func.borrow().expect("current func") + .get_param(index as i32) + .to_rvalue() + } +} + +impl GccType for CastTarget { + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> { + let rest_gcc_unit = self.rest.unit.gcc_type(cx); + let (rest_count, rem_bytes) = + if self.rest.unit.size.bytes() == 0 { + (0, 0) + } + else { + (self.rest.total.bytes() / self.rest.unit.size.bytes(), self.rest.total.bytes() % self.rest.unit.size.bytes()) + }; + + if self.prefix.iter().all(|x| x.is_none()) { + // Simplify to a single unit when there is no prefix and size <= unit size + if self.rest.total <= self.rest.unit.size { + return rest_gcc_unit; + } + + // Simplify to array when all chunks are the same size and type + if rem_bytes == 0 { + return cx.type_array(rest_gcc_unit, rest_count); + } + } + + // Create list of fields in the main structure + let mut args: Vec<_> = self + .prefix + .iter() + .flat_map(|option_kind| { + option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.gcc_type(cx)) + }) + .chain((0..rest_count).map(|_| rest_gcc_unit)) + .collect(); + + // Append final integer + if rem_bytes != 0 { + // Only integers can be really split further. + assert_eq!(self.rest.unit.kind, RegKind::Integer); + args.push(cx.type_ix(rem_bytes * 8)); + } + + cx.type_struct(&args, false) + } +} + +pub trait GccType { + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>; +} + +impl GccType for Reg { + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> { + match self.kind { + RegKind::Integer => cx.type_ix(self.size.bits()), + RegKind::Float => { + match self.size.bits() { + 32 => cx.type_f32(), + 64 => cx.type_f64(), + _ => bug!("unsupported float: {:?}", self), + } + }, + RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()), + } + } +} + +pub trait FnAbiGccExt<'gcc, 'tcx> { + // TODO(antoyo): return a function pointer type instead? + fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec>, bool); + fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; +} + +impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { + fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec>, bool) { + let args_capacity: usize = self.args.iter().map(|arg| + if arg.pad.is_some() { + 1 + } + else { + 0 + } + + if let PassMode::Pair(_, _) = arg.mode { + 2 + } else { + 1 + } + ).sum(); + let mut argument_tys = Vec::with_capacity( + if let PassMode::Indirect { .. } = self.ret.mode { + 1 + } + else { + 0 + } + args_capacity, + ); + + let return_ty = + match self.ret.mode { + PassMode::Ignore => cx.type_void(), + PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), + PassMode::Cast(cast) => cast.gcc_type(cx), + PassMode::Indirect { .. } => { + argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); + cx.type_void() + } + }; + + for arg in &self.args { + // add padding + if let Some(ty) = arg.pad { + argument_tys.push(ty.gcc_type(cx)); + } + + let arg_ty = match arg.mode { + PassMode::Ignore => continue, + PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), + PassMode::Pair(..) => { + argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0, true)); + argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1, true)); + continue; + } + PassMode::Indirect { extra_attrs: Some(_), .. } => { + unimplemented!(); + } + PassMode::Cast(cast) => cast.gcc_type(cx), + PassMode::Indirect { extra_attrs: None, .. } => cx.type_ptr_to(arg.memory_ty(cx)), + }; + argument_tys.push(arg_ty); + } + + (return_ty, argument_tys, self.c_variadic) + } + + fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + let (return_type, params, variadic) = self.gcc_type(cx); + let pointer_type = cx.context.new_function_pointer_type(None, return_type, ¶ms, variadic); + pointer_type + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/allocator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/allocator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/allocator.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/allocator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,116 @@ +use gccjit::{FunctionType, ToRValue}; +use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; +use rustc_middle::bug; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::sym; + +use crate::GccContext; + +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) { + let context = &mods.context; + let usize = + match tcx.sess.target.pointer_width { + 16 => context.new_type::(), + 32 => context.new_type::(), + 64 => context.new_type::(), + tws => bug!("Unsupported target word size for int: {}", tws), + }; + let i8 = context.new_type::(); + let i8p = i8.make_pointer(); + let void = context.new_type::<()>(); + + for method in ALLOCATOR_METHODS { + let mut types = Vec::with_capacity(method.inputs.len()); + for ty in method.inputs.iter() { + match *ty { + AllocatorTy::Layout => { + types.push(usize); + types.push(usize); + } + AllocatorTy::Ptr => types.push(i8p), + AllocatorTy::Usize => types.push(usize), + + AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), + } + } + let output = match method.output { + AllocatorTy::ResultPtr => Some(i8p), + AllocatorTy::Unit => None, + + AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { + panic!("invalid allocator output") + } + }; + let name = format!("__rust_{}", method.name); + + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false); + + if tcx.sess.target.options.default_hidden_visibility { + // TODO(antoyo): set visibility. + } + if tcx.sess.must_emit_unwind_tables() { + // TODO(antoyo): emit unwind tables. + } + + let callee = kind.fn_name(method.name); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false); + // TODO(antoyo): set visibility. + + let block = func.new_block("entry"); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + block.end_with_return(None, ret); + } + else { + block.end_with_void_return(None); + } + + // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances + // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 + } + + let types = [usize, usize]; + let name = "__rust_alloc_error_handler".to_string(); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); + + let kind = + if has_alloc_error_handler { + AllocatorKind::Global + } + else { + AllocatorKind::Default + }; + let callee = kind.fn_name(sym::oom); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false); + //llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); + + let block = func.new_block("entry"); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let _ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + block.end_with_void_return(None); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/archive.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/archive.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/archive.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/archive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,217 @@ +use std::fs::File; +use std::path::{Path, PathBuf}; + +use rustc_codegen_ssa::back::archive::ArchiveBuilder; +use rustc_session::Session; + +use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_session::cstore::DllImport; + +struct ArchiveConfig<'a> { + sess: &'a Session, + dst: PathBuf, + use_native_ar: bool, + use_gnu_style_archive: bool, +} + +#[derive(Debug)] +enum ArchiveEntry { + FromArchive { + archive_index: usize, + entry_index: usize, + }, + File(PathBuf), +} + +pub struct ArArchiveBuilder<'a> { + config: ArchiveConfig<'a>, + src_archives: Vec<(PathBuf, ar::Archive)>, + // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at + // the end of an archive for linkers to not get confused. + entries: Vec<(String, ArchiveEntry)>, +} + +impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { + fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self { + let config = ArchiveConfig { + sess, + dst: output.to_path_buf(), + use_native_ar: false, + // FIXME test for linux and System V derivatives instead + use_gnu_style_archive: sess.target.options.archive_format == "gnu", + }; + + let (src_archives, entries) = if let Some(input) = input { + let mut archive = ar::Archive::new(File::open(input).unwrap()); + let mut entries = Vec::new(); + + let mut i = 0; + while let Some(entry) = archive.next_entry() { + let entry = entry.unwrap(); + entries.push(( + String::from_utf8(entry.header().identifier().to_vec()).unwrap(), + ArchiveEntry::FromArchive { + archive_index: 0, + entry_index: i, + }, + )); + i += 1; + } + + (vec![(input.to_owned(), archive)], entries) + } else { + (vec![], Vec::new()) + }; + + ArArchiveBuilder { + config, + src_archives, + entries, + } + } + + fn src_files(&mut self) -> Vec { + self.entries.iter().map(|(name, _)| name.clone()).collect() + } + + fn remove_file(&mut self, name: &str) { + let index = self + .entries + .iter() + .position(|(entry_name, _)| entry_name == name) + .expect("Tried to remove file not existing in src archive"); + self.entries.remove(index); + } + + fn add_file(&mut self, file: &Path) { + self.entries.push(( + file.file_name().unwrap().to_str().unwrap().to_string(), + ArchiveEntry::File(file.to_owned()), + )); + } + + fn add_archive(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()> + where + F: FnMut(&str) -> bool + 'static, + { + let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); + let archive_index = self.src_archives.len(); + + let mut i = 0; + while let Some(entry) = archive.next_entry() { + let entry = entry?; + let file_name = String::from_utf8(entry.header().identifier().to_vec()) + .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; + if !skip(&file_name) { + self.entries + .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i })); + } + i += 1; + } + + self.src_archives.push((archive_path.to_owned(), archive)); + Ok(()) + } + + fn update_symbols(&mut self) { + } + + fn build(mut self) { + use std::process::Command; + + fn add_file_using_ar(archive: &Path, file: &Path) { + Command::new("ar") + .arg("r") // add or replace file + .arg("-c") // silence created file message + .arg(archive) + .arg(&file) + .status() + .unwrap(); + } + + enum BuilderKind<'a> { + Bsd(ar::Builder), + Gnu(ar::GnuBuilder), + NativeAr(&'a Path), + } + + let mut builder = if self.config.use_native_ar { + BuilderKind::NativeAr(&self.config.dst) + } else if self.config.use_gnu_style_archive { + BuilderKind::Gnu(ar::GnuBuilder::new( + File::create(&self.config.dst).unwrap(), + self.entries + .iter() + .map(|(name, _)| name.as_bytes().to_vec()) + .collect(), + )) + } else { + BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap())) + }; + + // Add all files + for (entry_name, entry) in self.entries.into_iter() { + match entry { + ArchiveEntry::FromArchive { + archive_index, + entry_index, + } => { + let (ref src_archive_path, ref mut src_archive) = + self.src_archives[archive_index]; + let entry = src_archive.jump_to_entry(entry_index).unwrap(); + let header = entry.header().clone(); + + match builder { + BuilderKind::Bsd(ref mut builder) => { + builder.append(&header, entry).unwrap() + } + BuilderKind::Gnu(ref mut builder) => { + builder.append(&header, entry).unwrap() + } + BuilderKind::NativeAr(archive_file) => { + Command::new("ar") + .arg("x") + .arg(src_archive_path) + .arg(&entry_name) + .status() + .unwrap(); + add_file_using_ar(archive_file, Path::new(&entry_name)); + std::fs::remove_file(entry_name).unwrap(); + } + } + } + ArchiveEntry::File(file) => + match builder { + BuilderKind::Bsd(ref mut builder) => { + builder + .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder")) + .unwrap() + }, + BuilderKind::Gnu(ref mut builder) => { + builder + .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file))) + .unwrap() + }, + BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file), + }, + } + } + + // Finalize archive + std::mem::drop(builder); + + // Run ranlib to be able to link the archive + let status = std::process::Command::new("ranlib") + .arg(self.config.dst) + .status() + .expect("Couldn't run ranlib"); + + if !status.success() { + self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code())); + } + } + + fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) { + unimplemented!(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/asm.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/asm.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/asm.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/asm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,785 @@ +use gccjit::{LValue, RValue, ToRValue, Type}; +use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_codegen_ssa::mir::operand::OperandValue; +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; + +use rustc_hir::LlvmInlineAsmInner; +use rustc_middle::{bug, ty::Instance}; +use rustc_span::{Span, Symbol}; +use rustc_target::asm::*; + +use std::borrow::Cow; + +use crate::builder::Builder; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + + +// Rust asm! and GCC Extended Asm semantics differ substantially. +// +// 1. Rust asm operands go along as one list of operands. Operands themselves indicate +// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be +// both "in" and "out" (`inout(reg)`). +// +// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, +// this means that all "out" operands must go before "in" operands. "In" and "out" operands +// cannot interleave. +// +// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important +// because the asm template refers to operands by index. +// +// Mapping from Rust to GCC index would be 1-1 if it wasn't for... +// +// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. +// Contrary, Rust expresses clobbers through "out" operands that aren't tied to +// a variable (`_`), and such "clobbers" do have index. +// +// 4. Furthermore, GCC Extended Asm does not support explicit register constraints +// (like `out("eax")`) directly, offering so-called "local register variables" +// as a workaround. These variables need to be declared and initialized *before* +// the Extended Asm block but *after* normal local variables +// (see comment in `codegen_inline_asm` for explanation). +// +// With that in mind, let's see how we translate Rust syntax to GCC +// (from now on, `CC` stands for "constraint code"): +// +// * `out(reg_class) var` -> translated to output operand: `"=CC"(var)` +// * `inout(reg_class) var` -> translated to output operand: `"+CC"(var)` +// * `in(reg_class) var` -> translated to input operand: `"CC"(var)` +// +// * `out(reg_class) _` -> translated to one `=r(tmp)`, where "tmp" is a temporary unused variable +// +// * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list +// +// * `inout(reg_class) in_var => out_var` -> translated to two operands: +// output: `"=CC"(in_var)` +// input: `"num"(out_var)` where num is the GCC index +// of the corresponding output operand +// +// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, +// where "tmp" is a temporary unused variable +// +// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above +// with `"r"(var)` constraint, +// and one register variable assigned to the desired register. +// + +const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t"; +const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix"; + + +struct AsmOutOperand<'a, 'tcx, 'gcc> { + rust_idx: usize, + constraint: &'a str, + late: bool, + readwrite: bool, + + tmp_var: LValue<'gcc>, + out_place: Option>> +} + +struct AsmInOperand<'a, 'tcx> { + rust_idx: usize, + constraint: Cow<'a, str>, + val: RValue<'tcx> +} + +impl AsmOutOperand<'_, '_, '_> { + fn to_constraint(&self) -> String { + let mut res = String::with_capacity(self.constraint.len() + self.late as usize + 1); + + let sign = if self.readwrite { '+' } else { '=' }; + res.push(sign); + if !self.late { + res.push('&'); + } + + res.push_str(&self.constraint); + res + } +} + +enum ConstraintOrRegister { + Constraint(&'static str), + Register(&'static str) +} + + +impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec>>, _inputs: Vec>, span: Span) -> bool { + self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`") + .help("consider using the `asm!` macro instead") + .emit(); + + // We return `true` even if we've failed to generate the asm + // because we want to suppress the "malformed inline assembly" error + // generated by the frontend. + true + } + + fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) { + let asm_arch = self.tcx.sess.asm_arch.unwrap(); + let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64); + let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX); + let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX); + + // GCC index of an output operand equals its position in the array + let mut outputs = vec![]; + + // GCC index of an input operand equals its position in the array + // added to `outputs.len()` + let mut inputs = vec![]; + + // Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _` + let mut clobbers = vec![]; + + // We're trying to preallocate space for the template + let mut constants_len = 0; + + // There are rules we must adhere to if we want GCC to do the right thing: + // + // * Every local variable that the asm block uses as an output must be declared *before* + // the asm block. + // * There must be no instructions whatsoever between the register variables and the asm. + // + // Therefore, the backend must generate the instructions strictly in this order: + // + // 1. Output variables. + // 2. Register variables. + // 3. The asm block. + // + // We also must make sure that no input operands are emitted before output operands. + // + // This is why we work in passes, first emitting local vars, then local register vars. + // Also, we don't emit any asm operands immediately; we save them to + // the one of the buffers to be emitted later. + + // 1. Normal variables (and saving operands to buffers). + for (rust_idx, op) in rust_operands.iter().enumerate() { + match *op { + InlineAsmOperandRef::Out { reg, late, place } => { + use ConstraintOrRegister::*; + + let (constraint, ty) = match (reg_to_gcc(reg), place) { + (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)), + // When `reg` is a class and not an explicit register but the out place is not specified, + // we need to create an unused output variable to assign the output to. This var + // needs to be of a type that's "compatible" with the register class, but specific type + // doesn't matter. + (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())), + (Register(_), Some(_)) => { + // left for the next pass + continue + }, + (Register(reg_name), None) => { + // `clobber_abi` can add lots of clobbers that are not supported by the target, + // such as AVX-512 registers, so we just ignore unsupported registers + let is_target_supported = reg.reg_class().supported_types(asm_arch).iter() + .any(|&(_, feature)| { + if let Some(feature) = feature { + self.tcx.sess.target_features.contains(&Symbol::intern(feature)) + } else { + true // Register class is unconditionally supported + } + }); + + if is_target_supported && !clobbers.contains(®_name) { + clobbers.push(reg_name); + } + continue + } + }; + + let tmp_var = self.current_func().new_local(None, ty, "output_register"); + outputs.push(AsmOutOperand { + constraint, + rust_idx, + late, + readwrite: false, + tmp_var, + out_place: place + }); + } + + InlineAsmOperandRef::In { reg, value } => { + if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { + inputs.push(AsmInOperand { + constraint: Cow::Borrowed(constraint), + rust_idx, + val: value.immediate() + }); + } + else { + // left for the next pass + continue + } + } + + InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { + let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { + constraint + } + else { + // left for the next pass + continue + }; + + // Rustc frontend guarantees that input and output types are "compatible", + // so we can just use input var's type for the output variable. + // + // This decision is also backed by the fact that LLVM needs in and out + // values to be of *exactly the same type*, not just "compatible". + // I'm not sure if GCC is so picky too, but better safe than sorry. + let ty = in_value.layout.gcc_type(self.cx, false); + let tmp_var = self.current_func().new_local(None, ty, "output_register"); + + // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate + // it to one "readwrite (+) output variable", otherwise we translate it to two + // "out and tied in" vars as described above. + let readwrite = out_place.is_none(); + outputs.push(AsmOutOperand { + constraint, + rust_idx, + late, + readwrite, + tmp_var, + out_place, + }); + + if !readwrite { + let out_gcc_idx = outputs.len() - 1; + let constraint = Cow::Owned(out_gcc_idx.to_string()); + + inputs.push(AsmInOperand { + constraint, + rust_idx, + val: in_value.immediate() + }); + } + } + + InlineAsmOperandRef::Const { ref string } => { + constants_len += string.len() + att_dialect as usize; + } + + InlineAsmOperandRef::SymFn { instance } => { + constants_len += self.tcx.symbol_name(instance).name.len(); + } + InlineAsmOperandRef::SymStatic { def_id } => { + constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len(); + } + } + } + + // 2. Register variables. + for (rust_idx, op) in rust_operands.iter().enumerate() { + match *op { + // `out("explicit register") var` + InlineAsmOperandRef::Out { reg, late, place } => { + if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { + let out_place = if let Some(place) = place { + place + } + else { + // processed in the previous pass + continue + }; + + let ty = out_place.layout.gcc_type(self.cx, false); + let tmp_var = self.current_func().new_local(None, ty, "output_register"); + tmp_var.set_register_name(reg_name); + + outputs.push(AsmOutOperand { + constraint: "r".into(), + rust_idx, + late, + readwrite: false, + tmp_var, + out_place: Some(out_place) + }); + } + + // processed in the previous pass + } + + // `in("explicit register") var` + InlineAsmOperandRef::In { reg, value } => { + if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { + let ty = value.layout.gcc_type(self.cx, false); + let reg_var = self.current_func().new_local(None, ty, "input_register"); + reg_var.set_register_name(reg_name); + self.llbb().add_assignment(None, reg_var, value.immediate()); + + inputs.push(AsmInOperand { + constraint: "r".into(), + rust_idx, + val: reg_var.to_rvalue() + }); + } + + // processed in the previous pass + } + + // `inout("explicit register") in_var => out_var` + InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { + if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { + let out_place = if let Some(place) = out_place { + place + } + else { + // processed in the previous pass + continue + }; + + // See explanation in the first pass. + let ty = in_value.layout.gcc_type(self.cx, false); + let tmp_var = self.current_func().new_local(None, ty, "output_register"); + tmp_var.set_register_name(reg_name); + + outputs.push(AsmOutOperand { + constraint: "r".into(), + rust_idx, + late, + readwrite: false, + tmp_var, + out_place: Some(out_place) + }); + + let constraint = Cow::Owned((outputs.len() - 1).to_string()); + inputs.push(AsmInOperand { + constraint, + rust_idx, + val: in_value.immediate() + }); + } + + // processed in the previous pass + } + + InlineAsmOperandRef::Const { .. } + | InlineAsmOperandRef::SymFn { .. } + | InlineAsmOperandRef::SymStatic { .. } => { + // processed in the previous pass + } + } + } + + // 3. Build the template string + + let mut template_str = String::with_capacity(estimate_template_length(template, constants_len, att_dialect)); + if !intel_dialect { + template_str.push_str(ATT_SYNTAX_INS); + } + + for piece in template { + match *piece { + InlineAsmTemplatePiece::String(ref string) => { + // TODO(@Commeownist): switch to `Iterator::intersperse` once it's stable + let mut iter = string.split('%'); + if let Some(s) = iter.next() { + template_str.push_str(s); + } + + for s in iter { + template_str.push_str("%%"); + template_str.push_str(s); + } + } + InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => { + let mut push_to_template = |modifier, gcc_idx| { + use std::fmt::Write; + + template_str.push('%'); + if let Some(modifier) = modifier { + template_str.push(modifier); + } + write!(template_str, "{}", gcc_idx).expect("pushing to string failed"); + }; + + match rust_operands[operand_idx] { + InlineAsmOperandRef::Out { reg, .. } => { + let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); + let gcc_index = outputs.iter() + .position(|op| operand_idx == op.rust_idx) + .expect("wrong rust index"); + push_to_template(modifier, gcc_index); + } + + InlineAsmOperandRef::In { reg, .. } => { + let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); + let in_gcc_index = inputs.iter() + .position(|op| operand_idx == op.rust_idx) + .expect("wrong rust index"); + let gcc_index = in_gcc_index + outputs.len(); + push_to_template(modifier, gcc_index); + } + + InlineAsmOperandRef::InOut { reg, .. } => { + let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); + + // The input register is tied to the output, so we can just use the index of the output register + let gcc_index = outputs.iter() + .position(|op| operand_idx == op.rust_idx) + .expect("wrong rust index"); + push_to_template(modifier, gcc_index); + } + + InlineAsmOperandRef::SymFn { instance } => { + let name = self.tcx.symbol_name(instance).name; + template_str.push_str(name); + } + + InlineAsmOperandRef::SymStatic { def_id } => { + // TODO(@Commeownist): This may not be sufficient for all kinds of statics. + // Some statics may need the `@plt` suffix, like thread-local vars. + let instance = Instance::mono(self.tcx, def_id); + let name = self.tcx.symbol_name(instance).name; + template_str.push_str(name); + } + + InlineAsmOperandRef::Const { ref string } => { + // Const operands get injected directly into the template + if att_dialect { + template_str.push('$'); + } + template_str.push_str(string); + } + } + } + } + } + + if !intel_dialect { + template_str.push_str(INTEL_SYNTAX_INS); + } + + // 4. Generate Extended Asm block + + let block = self.llbb(); + let extended_asm = block.add_extended_asm(None, &template_str); + + for op in &outputs { + extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var); + } + + for op in &inputs { + extended_asm.add_input_operand(None, &op.constraint, op.val); + } + + for clobber in clobbers.iter() { + extended_asm.add_clobber(clobber); + } + + if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) { + // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient + // on all architectures. For instance, what about FP stack? + extended_asm.add_clobber("cc"); + } + if !options.contains(InlineAsmOptions::NOMEM) { + extended_asm.add_clobber("memory"); + } + if !options.contains(InlineAsmOptions::PURE) { + extended_asm.set_volatile_flag(true); + } + if !options.contains(InlineAsmOptions::NOSTACK) { + // TODO(@Commeownist): figure out how to align stack + } + if options.contains(InlineAsmOptions::NORETURN) { + let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); + let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) }; + self.call(self.type_void(), builtin_unreachable, &[], None); + } + + // Write results to outputs. + // + // We need to do this because: + // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases + // (especially with current `rustc_backend_ssa` API). + // 2. Not every output operand has an `out_place`, and it's required by `add_output_operand`. + // + // Instead, we generate a temporary output variable for each output operand, and then this loop, + // generates `out_place = tmp_var;` assignments if out_place exists. + for op in &outputs { + if let Some(place) = op.out_place { + OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place); + } + } + + } +} + +fn estimate_template_length(template: &[InlineAsmTemplatePiece], constants_len: usize, att_dialect: bool) -> usize { + let len: usize = template.iter().map(|piece| { + match *piece { + InlineAsmTemplatePiece::String(ref string) => { + string.len() + } + InlineAsmTemplatePiece::Placeholder { .. } => { + // '%' + 1 char modifier + 1 char index + 3 + } + } + }) + .sum(); + + // increase it by 5% to account for possible '%' signs that'll be duplicated + // I pulled the number out of blue, but should be fair enough + // as the upper bound + let mut res = (len as f32 * 1.05) as usize + constants_len; + + if att_dialect { + res += INTEL_SYNTAX_INS.len() + ATT_SYNTAX_INS.len(); + } + res +} + +/// Converts a register class to a GCC constraint code. +fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { + let constraint = match reg { + // For vector registers LLVM wants the register name to match the type size. + InlineAsmRegOrRegClass::Reg(reg) => { + match reg { + InlineAsmReg::X86(_) => { + // TODO(antoyo): add support for vector register. + // + // // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119 + return ConstraintOrRegister::Register(match reg.name() { + // Some of registers' names does not map 1-1 from rust to gcc + "st(0)" => "st", + + name => name, + }); + } + + _ => unimplemented!(), + } + }, + InlineAsmRegOrRegClass::RegClass(reg) => match reg { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => unimplemented!(), + InlineAsmRegClass::Bpf(_) => unimplemented!(), + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => unimplemented!(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + unreachable!("clobber-only") + }, + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q", + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q", + InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", + InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", + InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(), + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(), + InlineAsmRegClass::X86( + X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg, + ) => unreachable!("clobber-only"), + InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { + bug!("GCC backend does not support SPIR-V") + } + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::Err => unreachable!(), + } + }; + + ConstraintOrRegister::Constraint(constraint) +} + +/// Type to use for outputs that are discarded. It doesn't really matter what +/// the type is, as long as it is valid for the constraint code. +fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegClass) -> Type<'gcc> { + match reg { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { + unimplemented!() + } + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => cx.type_f64(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { + unimplemented!() + } + InlineAsmRegClass::Bpf(_) => unimplemented!(), + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + unreachable!("clobber-only") + }, + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => cx.type_f32(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::mmx_reg) => unimplemented!(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), + InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { + bug!("LLVM backend does not support SPIR-V") + }, + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), + InlineAsmRegClass::Err => unreachable!(), + } +} + +impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> { + fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef], options: InlineAsmOptions, _line_spans: &[Span]) { + let asm_arch = self.tcx.sess.asm_arch.unwrap(); + + // Default to Intel syntax on x86 + let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) + && !options.contains(InlineAsmOptions::ATT_SYNTAX); + + // Build the template string + let mut template_str = String::new(); + for piece in template { + match *piece { + InlineAsmTemplatePiece::String(ref string) => { + for line in string.lines() { + // NOTE: gcc does not allow inline comment, so remove them. + let line = + if let Some(index) = line.rfind("//") { + &line[..index] + } + else { + line + }; + template_str.push_str(line); + template_str.push('\n'); + } + }, + InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { + match operands[operand_idx] { + GlobalAsmOperandRef::Const { ref string } => { + // Const operands get injected directly into the + // template. Note that we don't need to escape % + // here unlike normal inline assembly. + template_str.push_str(string); + } + } + } + } + } + + let template_str = + if intel_syntax { + format!("{}\n\t.intel_syntax noprefix", template_str) + } + else { + format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str) + }; + // NOTE: seems like gcc will put the asm in the wrong section, so set it to .text manually. + let template_str = format!(".pushsection .text\n{}\n.popsection", template_str); + self.context.add_top_level_asm(None, &template_str); + } +} + +fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option) -> Option { + match reg { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier, + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => modifier, + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { + unimplemented!() + } + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { + unimplemented!() + } + InlineAsmRegClass::Bpf(_) => unimplemented!(), + InlineAsmRegClass::Hexagon(_) => unimplemented!(), + InlineAsmRegClass::Mips(_) => unimplemented!(), + InlineAsmRegClass::Nvptx(_) => unimplemented!(), + InlineAsmRegClass::PowerPC(_) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) + | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier { + None => if arch == InlineAsmArch::X86_64 { Some('q') } else { Some('k') }, + Some('l') => Some('b'), + Some('h') => Some('h'), + Some('x') => Some('w'), + Some('e') => Some('k'), + Some('r') => Some('q'), + _ => unreachable!(), + }, + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => None, + InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::xmm_reg) + | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::ymm_reg) + | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) { + (X86InlineAsmRegClass::xmm_reg, None) => Some('x'), + (X86InlineAsmRegClass::ymm_reg, None) => Some('t'), + (X86InlineAsmRegClass::zmm_reg, None) => Some('g'), + (_, Some('x')) => Some('x'), + (_, Some('y')) => Some('t'), + (_, Some('z')) => Some('g'), + _ => unreachable!(), + }, + InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, + InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => { + unreachable!("clobber-only") + } + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(), + InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { + bug!("LLVM backend does not support SPIR-V") + }, + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::Err => unreachable!(), + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/back/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/back/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/back/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/back/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +pub mod write; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/back/write.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/back/write.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/back/write.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/back/write.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,78 @@ +use std::fs; + +use gccjit::OutputKind; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; +use rustc_codegen_ssa::back::write::{CodegenContext, EmitObj, ModuleConfig}; +use rustc_errors::Handler; +use rustc_session::config::OutputType; +use rustc_span::fatal_error::FatalError; +use rustc_target::spec::SplitDebuginfo; + +use crate::{GccCodegenBackend, GccContext}; + +pub(crate) unsafe fn codegen(cgcx: &CodegenContext, _diag_handler: &Handler, module: ModuleCodegen, config: &ModuleConfig) -> Result { + let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &module.name[..]); + { + let context = &module.module_llvm.context; + + let module_name = module.name.clone(); + let module_name = Some(&module_name[..]); + + let _bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); + let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); + + if config.bitcode_needed() { + // TODO(antoyo) + } + + if config.emit_ir { + unimplemented!(); + } + + if config.emit_asm { + let _timer = cgcx + .prof + .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]); + let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); + context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str")); + } + + match config.emit_obj { + EmitObj::ObjectCode(_) => { + let _timer = cgcx + .prof + .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]); + match &*module.name { + "std_example.7rcbfp3g-cgu.15" => { + println!("Dumping reproducer {}", module.name); + let _ = fs::create_dir("/tmp/reproducers"); + // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by + // transmuting an rvalue to an lvalue. + // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue + context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name)); + println!("Dumped reproducer {}", module.name); + }, + _ => (), + } + context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str")); + } + + EmitObj::Bitcode => { + // TODO(antoyo) + } + + EmitObj::None => {} + } + } + + Ok(module.into_compiled_module( + config.emit_obj != EmitObj::None, + cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked, + config.emit_bc, + &cgcx.output_filenames, + )) +} + +pub(crate) fn link(_cgcx: &CodegenContext, _diag_handler: &Handler, mut _modules: Vec>) -> Result, FatalError> { + unimplemented!(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/base.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/base.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/base.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/base.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,165 @@ +use std::env; +use std::time::Instant; + +use gccjit::{ + Context, + FunctionType, + GlobalKind, +}; +use rustc_middle::dep_graph; +use rustc_middle::middle::exported_symbols; +use rustc_middle::ty::TyCtxt; +use rustc_middle::mir::mono::Linkage; +use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; +use rustc_codegen_ssa::base::maybe_create_entry_wrapper; +use rustc_codegen_ssa::mono_item::MonoItemExt; +use rustc_codegen_ssa::traits::DebugInfoMethods; +use rustc_metadata::EncodedMetadata; +use rustc_session::config::DebugInfo; +use rustc_span::Symbol; + +use crate::GccContext; +use crate::builder::Builder; +use crate::context::CodegenCx; + +pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind { + match linkage { + Linkage::External => GlobalKind::Imported, + Linkage::AvailableExternally => GlobalKind::Imported, + Linkage::LinkOnceAny => unimplemented!(), + Linkage::LinkOnceODR => unimplemented!(), + Linkage::WeakAny => unimplemented!(), + Linkage::WeakODR => unimplemented!(), + Linkage::Appending => unimplemented!(), + Linkage::Internal => GlobalKind::Internal, + Linkage::Private => GlobalKind::Internal, + Linkage::ExternalWeak => GlobalKind::Imported, // TODO(antoyo): should be weak linkage. + Linkage::Common => unimplemented!(), + } +} + +pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { + match linkage { + Linkage::External => FunctionType::Exported, + Linkage::AvailableExternally => FunctionType::Extern, + Linkage::LinkOnceAny => unimplemented!(), + Linkage::LinkOnceODR => unimplemented!(), + Linkage::WeakAny => FunctionType::Exported, // FIXME(antoyo): should be similar to linkonce. + Linkage::WeakODR => unimplemented!(), + Linkage::Appending => unimplemented!(), + Linkage::Internal => FunctionType::Internal, + Linkage::Private => FunctionType::Internal, + Linkage::ExternalWeak => unimplemented!(), + Linkage::Common => unimplemented!(), + } +} + +pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen, u64) { + let prof_timer = tcx.prof.generic_activity("codegen_module"); + let start_time = Instant::now(); + + let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); + let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result); + let time_to_codegen = start_time.elapsed(); + drop(prof_timer); + + // We assume that the cost to run GCC on a CGU is proportional to + // the time we needed for codegenning it. + let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64; + + fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { + let cgu = tcx.codegen_unit(cgu_name); + // Instantiate monomorphizations without filling out definitions yet... + //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); + let context = Context::default(); + // TODO(antoyo): only set on x86 platforms. + context.add_command_line_option("-masm=intel"); + for arg in &tcx.sess.opts.cg.llvm_args { + context.add_command_line_option(arg); + } + context.add_command_line_option("-fno-semantic-interposition"); + if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") { + context.set_dump_code_on_compile(true); + } + if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") { + context.set_dump_initial_gimple(true); + } + context.set_debug_info(true); + if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") { + context.set_dump_everything(true); + } + if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") { + context.set_keep_intermediates(true); + } + + { + let cx = CodegenCx::new(&context, cgu, tcx); + + let mono_items = cgu.items_in_deterministic_order(tcx); + for &(mono_item, (linkage, visibility)) in &mono_items { + mono_item.predefine::>(&cx, linkage, visibility); + } + + // ... and now that we have everything pre-defined, fill out those definitions. + for &(mono_item, _) in &mono_items { + mono_item.define::>(&cx); + } + + // If this codegen unit contains the main function, also create the + // wrapper here + maybe_create_entry_wrapper::>(&cx); + + // Finalize debuginfo + if cx.sess().opts.debuginfo != DebugInfo::None { + cx.debuginfo_finalize(); + } + } + + ModuleCodegen { + name: cgu_name.to_string(), + module_llvm: GccContext { + context + }, + kind: ModuleKind::Regular, + } + } + + (module, cost) +} + +pub fn write_compressed_metadata<'tcx>(tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut GccContext) { + use snap::write::FrameEncoder; + use std::io::Write; + + // Historical note: + // + // When using link.exe it was seen that the section name `.note.rustc` + // was getting shortened to `.note.ru`, and according to the PE and COFF + // specification: + // + // > Executable images do not use a string table and do not support + // > section names longer than 8 characters + // + // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format + // + // As a result, we choose a slightly shorter name! As to why + // `.note.rustc` works on MinGW, see + // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197 + let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }; + + let context = &gcc_module.context; + let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); + FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data()).unwrap(); + + let name = exported_symbols::metadata_symbol_name(tcx); + let typ = context.new_array_type(None, context.new_type::(), compressed.len() as i32); + let global = context.new_global(None, GlobalKind::Exported, typ, name); + global.global_set_initializer(&compressed); + global.set_link_section(section_name); + + // Also generate a .section directive to force no + // flags, at least for ELF outputs, so that the + // metadata doesn't get loaded into memory. + let directive = format!(".section {}", section_name); + context.add_top_level_asm(None, &directive); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/builder.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/builder.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/builder.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/builder.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1540 @@ +use std::borrow::Cow; +use std::cell::Cell; +use std::convert::TryFrom; +use std::ops::Deref; + +use gccjit::FunctionType; +use gccjit::{ + BinaryOp, + Block, + ComparisonOp, + Function, + LValue, + RValue, + ToRValue, + Type, + UnaryOp, +}; +use rustc_codegen_ssa::MemFlags; +use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope}; +use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{ + BackendTypes, + BaseTypeMethods, + BuilderMethods, + ConstMethods, + DerivedTypeMethods, + LayoutTypeMethods, + HasCodegen, + OverflowOp, + StaticBuilderMethods, +}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; +use rustc_span::Span; +use rustc_span::def_id::DefId; +use rustc_target::abi::{ + self, + call::FnAbi, + Align, + HasDataLayout, + Size, + TargetDataLayout, + WrappingRange, +}; +use rustc_target::spec::{HasTargetSpec, Target}; + +use crate::common::{SignType, TypeReflection, type_is_pointer}; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +// TODO(antoyo) +type Funclet = (); + +// TODO(antoyo): remove this variable. +static mut RETURN_VALUE_COUNT: usize = 0; + +enum ExtremumOperation { + Max, + Min, +} + +trait EnumClone { + fn clone(&self) -> Self; +} + +impl EnumClone for AtomicOrdering { + fn clone(&self) -> Self { + match *self { + AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic, + AtomicOrdering::Unordered => AtomicOrdering::Unordered, + AtomicOrdering::Monotonic => AtomicOrdering::Monotonic, + AtomicOrdering::Acquire => AtomicOrdering::Acquire, + AtomicOrdering::Release => AtomicOrdering::Release, + AtomicOrdering::AcquireRelease => AtomicOrdering::AcquireRelease, + AtomicOrdering::SequentiallyConsistent => AtomicOrdering::SequentiallyConsistent, + } + } +} + +pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { + pub cx: &'a CodegenCx<'gcc, 'tcx>, + pub block: Option>, + stack_var_count: Cell, +} + +impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { + fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>) -> Self { + Builder { + cx, + block: None, + stack_var_count: Cell::new(0), + } + } + + fn atomic_extremum(&mut self, operation: ExtremumOperation, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> { + let size = self.cx.int_width(src.get_type()) / 8; + + let func = self.current_func(); + + let load_ordering = + match order { + // TODO(antoyo): does this make sense? + AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire, + _ => order.clone(), + }; + let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering.clone(), Size::from_bytes(size)); + let previous_var = func.new_local(None, previous_value.get_type(), "previous_value"); + let return_value = func.new_local(None, previous_value.get_type(), "return_value"); + self.llbb().add_assignment(None, previous_var, previous_value); + self.llbb().add_assignment(None, return_value, previous_var.to_rvalue()); + + let while_block = func.new_block("while"); + let after_block = func.new_block("after_while"); + self.llbb().end_with_jump(None, while_block); + + // NOTE: since jumps were added and compare_exchange doesn't expect this, the current blocks in the + // state need to be updated. + self.block = Some(while_block); + *self.cx.current_block.borrow_mut() = Some(while_block); + + let comparison_operator = + match operation { + ExtremumOperation::Max => ComparisonOp::LessThan, + ExtremumOperation::Min => ComparisonOp::GreaterThan, + }; + + let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type())); + let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false); + let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange); + let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2); + + while_block.end_with_conditional(None, cond, while_block, after_block); + + // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the + // state need to be updated. + self.block = Some(after_block); + *self.cx.current_block.borrow_mut() = Some(after_block); + + return_value.to_rvalue() + } + + fn compare_exchange(&self, dst: RValue<'gcc>, cmp: LValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { + let size = self.cx.int_width(src.get_type()); + let compare_exchange = self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size / 8)); + let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + let failure_order = self.context.new_rvalue_from_int(self.i32_type, failure_order.to_gcc()); + let weak = self.context.new_rvalue_from_int(self.bool_type, weak as i32); + + let void_ptr_type = self.context.new_type::<*mut ()>(); + let volatile_void_ptr_type = void_ptr_type.make_volatile(); + let dst = self.context.new_cast(None, dst, volatile_void_ptr_type); + let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type); + + // NOTE: not sure why, but we have the wrong type here. + let int_type = compare_exchange.get_param(2).to_rvalue().get_type(); + let src = self.context.new_cast(None, src, int_type); + self.context.new_call(None, compare_exchange, &[dst, expected, src, weak, order, failure_order]) + } + + pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) { + self.llbb().add_assignment(None, lvalue, value); + } + + fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { + let mut all_args_match = true; + let mut param_types = vec![]; + let param_count = func.get_param_count(); + for (index, arg) in args.iter().enumerate().take(param_count) { + let param = func.get_param(index as i32); + let param = param.to_rvalue().get_type(); + if param != arg.get_type() { + all_args_match = false; + } + param_types.push(param); + } + + if all_args_match { + return Cow::Borrowed(args); + } + + let casted_args: Vec<_> = param_types + .into_iter() + .zip(args.iter()) + .enumerate() + .map(|(_i, (expected_ty, &actual_val))| { + let actual_ty = actual_val.get_type(); + if expected_ty != actual_ty { + self.bitcast(actual_val, expected_ty) + } + else { + actual_val + } + }) + .collect(); + + Cow::Owned(casted_args) + } + + fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { + let mut all_args_match = true; + let mut param_types = vec![]; + let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr"); + for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) { + let param = gcc_func.get_param_type(index); + if param != arg.get_type() { + all_args_match = false; + } + param_types.push(param); + } + + if all_args_match { + return Cow::Borrowed(args); + } + + let casted_args: Vec<_> = param_types + .into_iter() + .zip(args.iter()) + .enumerate() + .map(|(_i, (expected_ty, &actual_val))| { + let actual_ty = actual_val.get_type(); + if expected_ty != actual_ty { + self.bitcast(actual_val, expected_ty) + } + else { + actual_val + } + }) + .collect(); + + Cow::Owned(casted_args) + } + + fn check_store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { + let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO(antoyo): make sure make_pointer() is okay here. + let stored_ty = self.cx.val_ty(val); + let stored_ptr_ty = self.cx.type_ptr_to(stored_ty); + + if dest_ptr_ty == stored_ptr_ty { + ptr + } + else { + self.bitcast(ptr, stored_ptr_ty) + } + } + + pub fn current_func(&self) -> Function<'gcc> { + self.block.expect("block").get_function() + } + + fn function_call(&mut self, func: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + // TODO(antoyo): remove when the API supports a different type for functions. + let func: Function<'gcc> = self.cx.rvalue_as_function(func); + let args = self.check_call("call", func, args); + + // gccjit requires to use the result of functions, even when it's not used. + // That's why we assign the result to a local or call add_eval(). + let return_type = func.get_return_type(); + let current_block = self.current_block.borrow().expect("block"); + let void_type = self.context.new_type::<()>(); + let current_func = current_block.get_function(); + if return_type != void_type { + unsafe { RETURN_VALUE_COUNT += 1 }; + let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); + current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + result.to_rvalue() + } + else { + current_block.add_eval(None, self.cx.context.new_call(None, func, &args)); + // Return dummy value when not having return value. + self.context.new_rvalue_from_long(self.isize_type, 0) + } + } + + fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + let args = self.check_ptr_call("call", func_ptr, args); + + // gccjit requires to use the result of functions, even when it's not used. + // That's why we assign the result to a local or call add_eval(). + let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr"); + let mut return_type = gcc_func.get_return_type(); + let current_block = self.current_block.borrow().expect("block"); + let void_type = self.context.new_type::<()>(); + let current_func = current_block.get_function(); + + // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. + if gcc_func.get_param_count() == 0 && format!("{:?}", func_ptr) == "__builtin_ia32_pmovmskb128" { + return_type = self.int_type; + } + + if return_type != void_type { + unsafe { RETURN_VALUE_COUNT += 1 }; + let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); + current_block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + result.to_rvalue() + } + else { + if gcc_func.get_param_count() == 0 { + // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. + current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[])); + } + else { + current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + } + // Return dummy value when not having return value. + let result = current_func.new_local(None, self.isize_type, "dummyValueThatShouldNeverBeUsed"); + current_block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0)); + result.to_rvalue() + } + } + + pub fn overflow_call(&mut self, func: Function<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + // gccjit requires to use the result of functions, even when it's not used. + // That's why we assign the result to a local. + let return_type = self.context.new_type::(); + let current_block = self.current_block.borrow().expect("block"); + let current_func = current_block.get_function(); + // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects. + unsafe { RETURN_VALUE_COUNT += 1 }; + let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); + current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + result.to_rvalue() + } +} + +impl<'gcc, 'tcx> HasCodegen<'tcx> for Builder<'_, 'gcc, 'tcx> { + type CodegenCx = CodegenCx<'gcc, 'tcx>; +} + +impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.cx.tcx() + } +} + +impl HasDataLayout for Builder<'_, '_, '_> { + fn data_layout(&self) -> &TargetDataLayout { + self.cx.data_layout() + } +} + +impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + self.cx.handle_layout_err(err, span, ty) + } +} + +impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + self.cx.handle_fn_abi_err(err, span, fn_abi_request) + } +} + +impl<'gcc, 'tcx> Deref for Builder<'_, 'gcc, 'tcx> { + type Target = CodegenCx<'gcc, 'tcx>; + + fn deref(&self) -> &Self::Target { + self.cx + } +} + +impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { + type Value = as BackendTypes>::Value; + type Function = as BackendTypes>::Function; + type BasicBlock = as BackendTypes>::BasicBlock; + type Type = as BackendTypes>::Type; + type Funclet = as BackendTypes>::Funclet; + + type DIScope = as BackendTypes>::DIScope; + type DILocation = as BackendTypes>::DILocation; + type DIVariable = as BackendTypes>::DIVariable; +} + +impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { + fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { + let mut bx = Builder::with_cx(cx); + *cx.current_block.borrow_mut() = Some(block); + bx.block = Some(block); + bx + } + + fn build_sibling_block(&mut self, name: &str) -> Self { + let block = self.append_sibling_block(name); + Self::build(self.cx, block) + } + + fn llbb(&self) -> Block<'gcc> { + self.block.expect("block") + } + + fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> { + let func = cx.rvalue_as_function(func); + func.new_block(name) + } + + fn append_sibling_block(&mut self, name: &str) -> Block<'gcc> { + let func = self.current_func(); + func.new_block(name) + } + + fn ret_void(&mut self) { + self.llbb().end_with_void_return(None) + } + + fn ret(&mut self, value: RValue<'gcc>) { + let value = + if self.structs_as_pointer.borrow().contains(&value) { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + value.dereference(None).to_rvalue() + } + else { + value + }; + self.llbb().end_with_return(None, value); + } + + fn br(&mut self, dest: Block<'gcc>) { + self.llbb().end_with_jump(None, dest) + } + + fn cond_br(&mut self, cond: RValue<'gcc>, then_block: Block<'gcc>, else_block: Block<'gcc>) { + self.llbb().end_with_conditional(None, cond, then_block, else_block) + } + + fn switch(&mut self, value: RValue<'gcc>, default_block: Block<'gcc>, cases: impl ExactSizeIterator)>) { + let mut gcc_cases = vec![]; + let typ = self.val_ty(value); + for (on_val, dest) in cases { + let on_val = self.const_uint_big(typ, on_val); + gcc_cases.push(self.context.new_case(on_val, on_val, dest)); + } + self.block.expect("block").end_with_switch(None, value, default_block, &gcc_cases); + } + + fn invoke(&mut self, _typ: Type<'gcc>, _func: RValue<'gcc>, _args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + let condition = self.context.new_rvalue_from_int(self.bool_type, 0); + self.llbb().end_with_conditional(None, condition, then, catch); + self.context.new_rvalue_from_int(self.int_type, 0) + + // TODO(antoyo) + } + + fn unreachable(&mut self) { + let func = self.context.get_builtin_function("__builtin_unreachable"); + let block = self.block.expect("block"); + block.add_eval(None, self.context.new_call(None, func, &[])); + let return_type = block.get_function().get_return_type(); + let void_type = self.context.new_type::<()>(); + if return_type == void_type { + block.end_with_void_return(None) + } + else { + let return_value = self.current_func() + .new_local(None, return_type, "unreachableReturn"); + block.end_with_return(None, return_value) + } + } + + fn add(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): this should not be required. + if format!("{:?}", a.get_type()) != format!("{:?}", b.get_type()) { + b = self.context.new_cast(None, b, a.get_type()); + } + a + b + } + + fn fadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a + b + } + + fn sub(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + if a.get_type() != b.get_type() { + b = self.context.new_cast(None, b, a.get_type()); + } + a - b + } + + fn fsub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a - b + } + + fn mul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a * b + } + + fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a * b + } + + fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): convert the arguments to unsigned? + a / b + } + + fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): convert the arguments to unsigned? + // TODO(antoyo): poison if not exact. + a / b + } + + fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): convert the arguments to signed? + a / b + } + + fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): posion if not exact. + // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they + // should be the same. + let typ = a.get_type().to_signed(self); + let b = self.context.new_cast(None, b, typ); + a / b + } + + fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a / b + } + + fn urem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a % b + } + + fn srem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a % b + } + + fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + if a.get_type() == self.cx.float_type { + let fmodf = self.context.get_builtin_function("fmodf"); + // FIXME(antoyo): this seems to produce the wrong result. + return self.context.new_call(None, fmodf, &[a, b]); + } + assert_eq!(a.get_type(), self.cx.double_type); + + let fmod = self.context.get_builtin_function("fmod"); + return self.context.new_call(None, fmod, &[a, b]); + } + + fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. + let a_type = a.get_type(); + let b_type = b.get_type(); + if a_type.is_unsigned(self) && b_type.is_signed(self) { + let a = self.context.new_cast(None, a, b_type); + let result = a << b; + self.context.new_cast(None, result, a_type) + } + else if a_type.is_signed(self) && b_type.is_unsigned(self) { + let b = self.context.new_cast(None, b, a_type); + a << b + } + else { + a << b + } + } + + fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. + // TODO(antoyo): cast to unsigned to do a logical shift if that does not work. + let a_type = a.get_type(); + let b_type = b.get_type(); + if a_type.is_unsigned(self) && b_type.is_signed(self) { + let a = self.context.new_cast(None, a, b_type); + let result = a >> b; + self.context.new_cast(None, result, a_type) + } + else if a_type.is_signed(self) && b_type.is_unsigned(self) { + let b = self.context.new_cast(None, b, a_type); + a >> b + } + else { + a >> b + } + } + + fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): check whether behavior is an arithmetic shift for >> . + // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. + let a_type = a.get_type(); + let b_type = b.get_type(); + if a_type.is_unsigned(self) && b_type.is_signed(self) { + let a = self.context.new_cast(None, a, b_type); + let result = a >> b; + self.context.new_cast(None, result, a_type) + } + else if a_type.is_signed(self) && b_type.is_unsigned(self) { + let b = self.context.new_cast(None, b, a_type); + a >> b + } + else { + a >> b + } + } + + fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): hack by putting the result in a variable to workaround this bug: + // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498 + if a.get_type() != b.get_type() { + b = self.context.new_cast(None, b, a.get_type()); + } + let res = self.current_func().new_local(None, b.get_type(), "andResult"); + self.llbb().add_assignment(None, res, a & b); + res.to_rvalue() + } + + fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): hack by putting the result in a variable to workaround this bug: + // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498 + let res = self.current_func().new_local(None, b.get_type(), "orResult"); + self.llbb().add_assignment(None, res, a | b); + res.to_rvalue() + } + + fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a ^ b + } + + fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use new_unary_op()? + self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a + } + + fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { + self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) + } + + fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { + let operation = + if a.get_type().is_bool() { + UnaryOp::LogicalNegate + } + else { + UnaryOp::BitwiseNegate + }; + self.cx.context.new_unary_op(None, operation, a.get_type(), a) + } + + fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a + b + } + + fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a + b + } + + fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a - b + } + + fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): should generate poison value? + a - b + } + + fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a * b + } + + fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a * b + } + + fn fadd_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn fsub_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn fmul_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn fdiv_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn frem_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { + use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*}; + + let new_kind = + match typ.kind() { + Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), + Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), + t @ (Uint(_) | Int(_)) => t.clone(), + _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), + }; + + // TODO(antoyo): remove duplication with intrinsic? + let name = + match oop { + OverflowOp::Add => + match new_kind { + Int(I8) => "__builtin_add_overflow", + Int(I16) => "__builtin_add_overflow", + Int(I32) => "__builtin_sadd_overflow", + Int(I64) => "__builtin_saddll_overflow", + Int(I128) => "__builtin_add_overflow", + + Uint(U8) => "__builtin_add_overflow", + Uint(U16) => "__builtin_add_overflow", + Uint(U32) => "__builtin_uadd_overflow", + Uint(U64) => "__builtin_uaddll_overflow", + Uint(U128) => "__builtin_add_overflow", + + _ => unreachable!(), + }, + OverflowOp::Sub => + match new_kind { + Int(I8) => "__builtin_sub_overflow", + Int(I16) => "__builtin_sub_overflow", + Int(I32) => "__builtin_ssub_overflow", + Int(I64) => "__builtin_ssubll_overflow", + Int(I128) => "__builtin_sub_overflow", + + Uint(U8) => "__builtin_sub_overflow", + Uint(U16) => "__builtin_sub_overflow", + Uint(U32) => "__builtin_usub_overflow", + Uint(U64) => "__builtin_usubll_overflow", + Uint(U128) => "__builtin_sub_overflow", + + _ => unreachable!(), + }, + OverflowOp::Mul => + match new_kind { + Int(I8) => "__builtin_mul_overflow", + Int(I16) => "__builtin_mul_overflow", + Int(I32) => "__builtin_smul_overflow", + Int(I64) => "__builtin_smulll_overflow", + Int(I128) => "__builtin_mul_overflow", + + Uint(U8) => "__builtin_mul_overflow", + Uint(U16) => "__builtin_mul_overflow", + Uint(U32) => "__builtin_umul_overflow", + Uint(U64) => "__builtin_umulll_overflow", + Uint(U128) => "__builtin_mul_overflow", + + _ => unreachable!(), + }, + }; + + let intrinsic = self.context.get_builtin_function(&name); + let res = self.current_func() + // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? + .new_local(None, rhs.get_type(), "binopResult") + .get_address(None); + let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); + (res.dereference(None).to_rvalue(), overflow) + } + + fn alloca(&mut self, ty: Type<'gcc>, align: Align) -> RValue<'gcc> { + // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. + // Ideally, we shouldn't need to do this check. + let aligned_type = + if ty == self.cx.u128_type || ty == self.cx.i128_type { + ty + } + else { + ty.get_aligned(align.bytes()) + }; + // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. + self.stack_var_count.set(self.stack_var_count.get() + 1); + self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None) + } + + fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> { + unimplemented!(); + } + + fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { + unimplemented!(); + } + + fn load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> { + // TODO(antoyo): use ty. + let block = self.llbb(); + let function = block.get_function(); + // NOTE: instead of returning the dereference here, we have to assign it to a variable in + // the current basic block. Otherwise, it could be used in another basic block, causing a + // dereference after a drop, for instance. + // TODO(antoyo): handle align. + let deref = ptr.dereference(None).to_rvalue(); + let value_type = deref.get_type(); + unsafe { RETURN_VALUE_COUNT += 1 }; + let loaded_value = function.new_local(None, value_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); + block.add_assignment(None, loaded_value, deref); + loaded_value.to_rvalue() + } + + fn volatile_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use ty. + let ptr = self.context.new_cast(None, ptr, ptr.get_type().make_volatile()); + ptr.dereference(None).to_rvalue() + } + + fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> { + // TODO(antoyo): use ty. + // TODO(antoyo): handle alignment. + let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes())); + let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + + let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile(); + let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); + self.context.new_call(None, atomic_load, &[ptr, ordering]) + } + + fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> { + assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); + + if place.layout.is_zst() { + return OperandRef::new_zst(self, place.layout); + } + + fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) { + let vr = scalar.valid_range.clone(); + match scalar.value { + abi::Int(..) => { + if !scalar.is_always_valid(bx) { + bx.range_metadata(load, scalar.valid_range); + } + } + abi::Pointer if vr.start < vr.end && !vr.contains(0) => { + bx.nonnull_metadata(load); + } + _ => {} + } + } + + let val = + if let Some(llextra) = place.llextra { + OperandValue::Ref(place.llval, Some(llextra), place.align) + } + else if place.layout.is_gcc_immediate() { + let load = self.load(place.llval.get_type(), place.llval, place.align); + if let abi::Abi::Scalar(ref scalar) = place.layout.abi { + scalar_load_metadata(self, load, scalar); + } + OperandValue::Immediate(self.to_immediate(load, place.layout)) + } + else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { + let b_offset = a.value.size(self).align_to(b.value.align(self).abi); + let pair_type = place.layout.gcc_type(self, false); + + let mut load = |i, scalar: &abi::Scalar, align| { + let llptr = self.struct_gep(pair_type, place.llval, i as u64); + let load = self.load(llptr.get_type(), llptr, align); + scalar_load_metadata(self, load, scalar); + if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } + }; + + OperandValue::Pair( + load(0, a, place.align), + load(1, b, place.align.restrict_for_offset(b_offset)), + ) + } + else { + OperandValue::Ref(place.llval, None, place.align) + }; + + OperandRef { val, layout: place.layout } + } + + fn write_operand_repeatedly(mut self, cg_elem: OperandRef<'tcx, RValue<'gcc>>, count: u64, dest: PlaceRef<'tcx, RValue<'gcc>>) -> Self { + let zero = self.const_usize(0); + let count = self.const_usize(count); + let start = dest.project_index(&mut self, zero).llval; + let end = dest.project_index(&mut self, count).llval; + + let mut header_bx = self.build_sibling_block("repeat_loop_header"); + let mut body_bx = self.build_sibling_block("repeat_loop_body"); + let next_bx = self.build_sibling_block("repeat_loop_next"); + + let ptr_type = start.get_type(); + let current = self.llbb().get_function().new_local(None, ptr_type, "loop_var"); + let current_val = current.to_rvalue(); + self.assign(current, start); + + self.br(header_bx.llbb()); + + let keep_going = header_bx.icmp(IntPredicate::IntNE, current_val, end); + header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); + + let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); + cg_elem.val.store(&mut body_bx, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); + + let next = body_bx.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]); + body_bx.llbb().add_assignment(None, current, next); + body_bx.br(header_bx.llbb()); + + next_bx + } + + fn range_metadata(&mut self, _load: RValue<'gcc>, _range: WrappingRange) { + // TODO(antoyo) + } + + fn nonnull_metadata(&mut self, _load: RValue<'gcc>) { + // TODO(antoyo) + } + + fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { + self.store_with_flags(val, ptr, align, MemFlags::empty()) + } + + fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, _align: Align, _flags: MemFlags) -> RValue<'gcc> { + let ptr = self.check_store(val, ptr); + self.llbb().add_assignment(None, ptr.dereference(None), val); + // TODO(antoyo): handle align and flags. + // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here? + self.cx.context.new_rvalue_zero(self.type_i32()) + } + + fn atomic_store(&mut self, value: RValue<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) { + // TODO(antoyo): handle alignment. + let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes())); + let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile(); + let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); + + // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because + // the following cast is required to avoid this error: + // gcc_jit_context_new_call: mismatching types for argument 2 of function "__atomic_store_4": assignment to param arg1 (type: int) from loadedValue3577 (type: unsigned int __attribute__((aligned(4)))) + let int_type = atomic_store.get_param(1).to_rvalue().get_type(); + let value = self.context.new_cast(None, value, int_type); + self.llbb() + .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering])); + } + + fn gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + let mut result = ptr; + for index in indices { + result = self.context.new_array_access(None, result, *index).get_address(None).to_rvalue(); + } + result + } + + fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + // FIXME(antoyo): would be safer if doing the same thing (loop) as gep. + // TODO(antoyo): specify inbounds somehow. + match indices.len() { + 1 => { + self.context.new_array_access(None, ptr, indices[0]).get_address(None) + }, + 2 => { + let array = ptr.dereference(None); // TODO(antoyo): assert that first index is 0? + self.context.new_array_access(None, array, indices[1]).get_address(None) + }, + _ => unimplemented!(), + } + } + + fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> { + // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. + assert_eq!(idx as usize as u64, idx); + let value = ptr.dereference(None).to_rvalue(); + + if value_type.is_array().is_some() { + let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(None, value, index); + element.get_address(None) + } + else if let Some(vector_type) = value_type.is_vector() { + let array_type = vector_type.get_element_type().make_pointer(); + let array = self.bitcast(ptr, array_type); + let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(None, array, index); + element.get_address(None) + } + else if let Some(struct_type) = value_type.is_struct() { + ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None) + } + else { + panic!("Unexpected type {:?}", value_type); + } + } + + /* Casts */ + fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): check that it indeed truncate the value. + self.context.new_cast(None, value, dest_ty) + } + + fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): check that it indeed sign extend the value. + if dest_ty.is_vector().is_some() { + // TODO(antoyo): nothing to do as it is only for LLVM? + return value; + } + self.context.new_cast(None, value, dest_ty) + } + + fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): make sure it truncates. + self.context.new_cast(None, value, dest_ty) + } + + fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.cx.ptrtoint(self.block.expect("block"), value, dest_ty) + } + + fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.cx.inttoptr(self.block.expect("block"), value, dest_ty) + } + + fn bitcast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.cx.const_bitcast(value, dest_ty) + } + + fn intcast(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>, _is_signed: bool) -> RValue<'gcc> { + // NOTE: is_signed is for value, not dest_typ. + self.cx.context.new_cast(None, value, dest_typ) + } + + fn pointercast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + let val_type = value.get_type(); + match (type_is_pointer(val_type), type_is_pointer(dest_ty)) { + (false, true) => { + // NOTE: Projecting a field of a pointer type will attemp a cast from a signed char to + // a pointer, which is not supported by gccjit. + return self.cx.context.new_cast(None, self.inttoptr(value, val_type.make_pointer()), dest_ty); + }, + (false, false) => { + // When they are not pointers, we want a transmute (or reinterpret_cast). + self.bitcast(value, dest_ty) + }, + (true, true) => self.cx.context.new_cast(None, value, dest_ty), + (true, false) => unimplemented!(), + } + } + + /* Comparisons */ + fn icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> { + let left_type = lhs.get_type(); + let right_type = rhs.get_type(); + if left_type != right_type { + // NOTE: because libgccjit cannot compare function pointers. + if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() { + lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer()); + rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer()); + } + // NOTE: hack because we try to cast a vector type to the same vector type. + else if format!("{:?}", left_type) != format!("{:?}", right_type) { + rhs = self.context.new_cast(None, rhs, left_type); + } + } + self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + } + + fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + } + + /* Miscellaneous instructions */ + fn memcpy(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) { + if flags.contains(MemFlags::NONTEMPORAL) { + // HACK(nox): This is inefficient but there is no nontemporal memcpy. + let val = self.load(src.get_type(), src, src_align); + let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val))); + self.store_with_flags(val, ptr, dst_align, flags); + return; + } + let size = self.intcast(size, self.type_size_t(), false); + let _is_volatile = flags.contains(MemFlags::VOLATILE); + let dst = self.pointercast(dst, self.type_i8p()); + let src = self.pointercast(src, self.type_ptr_to(self.type_void())); + let memcpy = self.context.get_builtin_function("memcpy"); + let block = self.block.expect("block"); + // TODO(antoyo): handle aligns and is_volatile. + block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size])); + } + + fn memmove(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) { + if flags.contains(MemFlags::NONTEMPORAL) { + // HACK(nox): This is inefficient but there is no nontemporal memmove. + let val = self.load(src.get_type(), src, src_align); + let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val))); + self.store_with_flags(val, ptr, dst_align, flags); + return; + } + let size = self.intcast(size, self.type_size_t(), false); + let _is_volatile = flags.contains(MemFlags::VOLATILE); + let dst = self.pointercast(dst, self.type_i8p()); + let src = self.pointercast(src, self.type_ptr_to(self.type_void())); + + let memmove = self.context.get_builtin_function("memmove"); + let block = self.block.expect("block"); + // TODO(antoyo): handle is_volatile. + block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size])); + } + + fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) { + let _is_volatile = flags.contains(MemFlags::VOLATILE); + let ptr = self.pointercast(ptr, self.type_i8p()); + let memset = self.context.get_builtin_function("memset"); + let block = self.block.expect("block"); + // TODO(antoyo): handle align and is_volatile. + let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type); + let size = self.intcast(size, self.type_size_t(), false); + block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size])); + } + + fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> { + let func = self.current_func(); + let variable = func.new_local(None, then_val.get_type(), "selectVar"); + let then_block = func.new_block("then"); + let else_block = func.new_block("else"); + let after_block = func.new_block("after"); + self.llbb().end_with_conditional(None, cond, then_block, else_block); + + then_block.add_assignment(None, variable, then_val); + then_block.end_with_jump(None, after_block); + + if then_val.get_type() != else_val.get_type() { + else_val = self.context.new_cast(None, else_val, then_val.get_type()); + } + else_block.add_assignment(None, variable, else_val); + else_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the + // state need to be updated. + self.block = Some(after_block); + *self.cx.current_block.borrow_mut() = Some(after_block); + + variable.to_rvalue() + } + + #[allow(dead_code)] + fn va_arg(&mut self, _list: RValue<'gcc>, _ty: Type<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn extract_element(&mut self, _vec: RValue<'gcc>, _idx: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn extract_value(&mut self, aggregate_value: RValue<'gcc>, idx: u64) -> RValue<'gcc> { + // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. + assert_eq!(idx as usize as u64, idx); + let value_type = aggregate_value.get_type(); + + if value_type.is_array().is_some() { + let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(None, aggregate_value, index); + element.get_address(None) + } + else if value_type.is_vector().is_some() { + panic!(); + } + else if let Some(pointer_type) = value_type.get_pointee() { + if let Some(struct_type) = pointer_type.is_struct() { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)).to_rvalue() + } + else { + panic!("Unexpected type {:?}", value_type); + } + } + else if let Some(struct_type) = value_type.is_struct() { + aggregate_value.access_field(None, struct_type.get_field(idx as i32)).to_rvalue() + } + else { + panic!("Unexpected type {:?}", value_type); + } + } + + fn insert_value(&mut self, aggregate_value: RValue<'gcc>, value: RValue<'gcc>, idx: u64) -> RValue<'gcc> { + // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. + assert_eq!(idx as usize as u64, idx); + let value_type = aggregate_value.get_type(); + + let lvalue = + if value_type.is_array().is_some() { + let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + self.context.new_array_access(None, aggregate_value, index) + } + else if value_type.is_vector().is_some() { + panic!(); + } + else if let Some(pointer_type) = value_type.get_pointee() { + if let Some(struct_type) = pointer_type.is_struct() { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)) + } + else { + panic!("Unexpected type {:?}", value_type); + } + } + else { + panic!("Unexpected type {:?}", value_type); + }; + + let lvalue_type = lvalue.to_rvalue().get_type(); + let value = + // NOTE: sometimes, rustc will create a value with the wrong type. + if lvalue_type != value.get_type() { + self.context.new_cast(None, value, lvalue_type) + } + else { + value + }; + + self.llbb().add_assignment(None, lvalue, value); + + aggregate_value + } + + fn landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>, _num_clauses: usize) -> RValue<'gcc> { + let field1 = self.context.new_field(None, self.u8_type, "landing_pad_field_1"); + let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1"); + let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]); + self.current_func().new_local(None, struct_type.as_type(), "landing_pad") + .to_rvalue() + // TODO(antoyo): Properly implement unwinding. + // the above is just to make the compilation work as it seems + // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort. + } + + fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) { + // TODO(antoyo) + } + + fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn cleanup_pad(&mut self, _parent: Option>, _args: &[RValue<'gcc>]) -> Funclet { + unimplemented!(); + } + + fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option>) -> RValue<'gcc> { + unimplemented!(); + } + + fn catch_pad(&mut self, _parent: RValue<'gcc>, _args: &[RValue<'gcc>]) -> Funclet { + unimplemented!(); + } + + fn catch_switch(&mut self, _parent: Option>, _unwind: Option>, _num_handlers: usize) -> RValue<'gcc> { + unimplemented!(); + } + + fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) { + unimplemented!(); + } + + fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { + // TODO(antoyo) + } + + // Atomic Operations + fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { + let expected = self.current_func().new_local(None, cmp.get_type(), "expected"); + self.llbb().add_assignment(None, expected, cmp); + let success = self.compare_exchange(dst, expected, src, order, failure_order, weak); + + let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false); + let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result"); + let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align. + + let value_type = result.to_rvalue().get_type(); + if let Some(struct_type) = value_type.is_struct() { + self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align); + // NOTE: since success contains the call to the intrinsic, it must be stored before + // expected so that we store expected after the call. + self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align); + } + // TODO(antoyo): handle when value is not a struct. + + result.to_rvalue() + } + + fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> { + let size = self.cx.int_width(src.get_type()) / 8; + let name = + match op { + AtomicRmwBinOp::AtomicXchg => format!("__atomic_exchange_{}", size), + AtomicRmwBinOp::AtomicAdd => format!("__atomic_fetch_add_{}", size), + AtomicRmwBinOp::AtomicSub => format!("__atomic_fetch_sub_{}", size), + AtomicRmwBinOp::AtomicAnd => format!("__atomic_fetch_and_{}", size), + AtomicRmwBinOp::AtomicNand => format!("__atomic_fetch_nand_{}", size), + AtomicRmwBinOp::AtomicOr => format!("__atomic_fetch_or_{}", size), + AtomicRmwBinOp::AtomicXor => format!("__atomic_fetch_xor_{}", size), + AtomicRmwBinOp::AtomicMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order), + AtomicRmwBinOp::AtomicMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order), + AtomicRmwBinOp::AtomicUMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order), + AtomicRmwBinOp::AtomicUMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order), + }; + + + let atomic_function = self.context.get_builtin_function(name); + let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + + let void_ptr_type = self.context.new_type::<*mut ()>(); + let volatile_void_ptr_type = void_ptr_type.make_volatile(); + let dst = self.context.new_cast(None, dst, volatile_void_ptr_type); + // FIXME(antoyo): not sure why, but we have the wrong type here. + let new_src_type = atomic_function.get_param(1).to_rvalue().get_type(); + let src = self.context.new_cast(None, src, new_src_type); + let res = self.context.new_call(None, atomic_function, &[dst, src, order]); + self.context.new_cast(None, res, src.get_type()) + } + + fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) { + let name = + match scope { + SynchronizationScope::SingleThread => "__atomic_signal_fence", + SynchronizationScope::CrossThread => "__atomic_thread_fence", + }; + let thread_fence = self.context.get_builtin_function(name); + let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + self.llbb().add_eval(None, self.context.new_call(None, thread_fence, &[order])); + } + + fn set_invariant_load(&mut self, load: RValue<'gcc>) { + // NOTE: Hack to consider vtable function pointer as non-global-variable function pointer. + self.normal_function_addresses.borrow_mut().insert(load); + // TODO(antoyo) + } + + fn lifetime_start(&mut self, _ptr: RValue<'gcc>, _size: Size) { + // TODO(antoyo) + } + + fn lifetime_end(&mut self, _ptr: RValue<'gcc>, _size: Size) { + // TODO(antoyo) + } + + fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> { + // FIXME(antoyo): remove when having a proper API. + let gcc_func = unsafe { std::mem::transmute(func) }; + if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() { + self.function_call(func, args, funclet) + } + else { + // If it's a not function that was defined, it's a function pointer. + self.function_ptr_call(func, args, funclet) + } + } + + fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): this does not zero-extend. + if value.get_type().is_bool() && dest_typ.is_i8(&self.cx) { + // FIXME(antoyo): hack because base::from_immediate converts i1 to i8. + // Fix the code in codegen_ssa::base::from_immediate. + return value; + } + self.context.new_cast(None, value, dest_typ) + } + + fn cx(&self) -> &CodegenCx<'gcc, 'tcx> { + self.cx + } + + fn do_not_inline(&mut self, _llret: RValue<'gcc>) { + unimplemented!(); + } + + fn set_span(&mut self, _span: Span) {} + + fn from_immediate(&mut self, val: Self::Value) -> Self::Value { + if self.cx().val_ty(val) == self.cx().type_i1() { + self.zext(val, self.cx().type_i8()) + } + else { + val + } + } + + fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value { + if scalar.is_bool() { + return self.trunc(val, self.cx().type_i1()); + } + val + } + + fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option> { + None + } + + fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option> { + None + } + + fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) { + unimplemented!(); + } +} + +impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { + pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> { + let return_type = v1.get_type(); + let params = [ + self.context.new_parameter(None, return_type, "v1"), + self.context.new_parameter(None, return_type, "v2"), + self.context.new_parameter(None, mask.get_type(), "mask"), + ]; + let shuffle = self.context.new_function(None, FunctionType::Extern, return_type, ¶ms, "_mm_shuffle_epi8", false); + self.context.new_call(None, shuffle, &[v1, v2, mask]) + } +} + +impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> { + fn get_static(&mut self, def_id: DefId) -> RValue<'gcc> { + // Forward to the `get_static` method of `CodegenCx` + self.cx().get_static(def_id).get_address(None) + } +} + +impl<'tcx> HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + self.cx.param_env() + } +} + +impl<'tcx> HasTargetSpec for Builder<'_, '_, 'tcx> { + fn target_spec(&self) -> &Target { + &self.cx.target_spec() + } +} + +trait ToGccComp { + fn to_gcc_comparison(&self) -> ComparisonOp; +} + +impl ToGccComp for IntPredicate { + fn to_gcc_comparison(&self) -> ComparisonOp { + match *self { + IntPredicate::IntEQ => ComparisonOp::Equals, + IntPredicate::IntNE => ComparisonOp::NotEquals, + IntPredicate::IntUGT => ComparisonOp::GreaterThan, + IntPredicate::IntUGE => ComparisonOp::GreaterThanEquals, + IntPredicate::IntULT => ComparisonOp::LessThan, + IntPredicate::IntULE => ComparisonOp::LessThanEquals, + IntPredicate::IntSGT => ComparisonOp::GreaterThan, + IntPredicate::IntSGE => ComparisonOp::GreaterThanEquals, + IntPredicate::IntSLT => ComparisonOp::LessThan, + IntPredicate::IntSLE => ComparisonOp::LessThanEquals, + } + } +} + +impl ToGccComp for RealPredicate { + fn to_gcc_comparison(&self) -> ComparisonOp { + // TODO(antoyo): check that ordered vs non-ordered is respected. + match *self { + RealPredicate::RealPredicateFalse => unreachable!(), + RealPredicate::RealOEQ => ComparisonOp::Equals, + RealPredicate::RealOGT => ComparisonOp::GreaterThan, + RealPredicate::RealOGE => ComparisonOp::GreaterThanEquals, + RealPredicate::RealOLT => ComparisonOp::LessThan, + RealPredicate::RealOLE => ComparisonOp::LessThanEquals, + RealPredicate::RealONE => ComparisonOp::NotEquals, + RealPredicate::RealORD => unreachable!(), + RealPredicate::RealUNO => unreachable!(), + RealPredicate::RealUEQ => ComparisonOp::Equals, + RealPredicate::RealUGT => ComparisonOp::GreaterThan, + RealPredicate::RealUGE => ComparisonOp::GreaterThan, + RealPredicate::RealULT => ComparisonOp::LessThan, + RealPredicate::RealULE => ComparisonOp::LessThan, + RealPredicate::RealUNE => ComparisonOp::NotEquals, + RealPredicate::RealPredicateTrue => unreachable!(), + } + } +} + +#[repr(C)] +#[allow(non_camel_case_types)] +enum MemOrdering { + __ATOMIC_RELAXED, + __ATOMIC_CONSUME, + __ATOMIC_ACQUIRE, + __ATOMIC_RELEASE, + __ATOMIC_ACQ_REL, + __ATOMIC_SEQ_CST, +} + +trait ToGccOrdering { + fn to_gcc(self) -> i32; +} + +impl ToGccOrdering for AtomicOrdering { + fn to_gcc(self) -> i32 { + use MemOrdering::*; + + let ordering = + match self { + AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. + AtomicOrdering::Unordered => __ATOMIC_RELAXED, + AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. + AtomicOrdering::Acquire => __ATOMIC_ACQUIRE, + AtomicOrdering::Release => __ATOMIC_RELEASE, + AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL, + AtomicOrdering::SequentiallyConsistent => __ATOMIC_SEQ_CST, + }; + ordering as i32 + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/callee.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/callee.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/callee.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/callee.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,77 @@ +use gccjit::{FunctionType, RValue}; +use rustc_codegen_ssa::traits::BaseTypeMethods; +use rustc_middle::ty::{self, Instance, TypeFoldable}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; + +use crate::abi::FnAbiGccExt; +use crate::context::CodegenCx; + +/// Codegens a reference to a fn/method item, monomorphizing and +/// inlining as it goes. +/// +/// # Parameters +/// +/// - `cx`: the crate context +/// - `instance`: the instance to be instantiated +pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> RValue<'gcc> { + let tcx = cx.tcx(); + + assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_escaping_bound_vars()); + + if let Some(&func) = cx.function_instances.borrow().get(&instance) { + return func; + } + + let sym = tcx.symbol_name(instance).name; + + let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); + + let func = + if let Some(func) = cx.get_declared_value(&sym) { + // Create a fn pointer with the new signature. + let ptrty = fn_abi.ptr_to_gcc_type(cx); + + // This is subtle and surprising, but sometimes we have to bitcast + // the resulting fn pointer. The reason has to do with external + // functions. If you have two crates that both bind the same C + // library, they may not use precisely the same types: for + // example, they will probably each declare their own structs, + // which are distinct types from LLVM's point of view (nominal + // types). + // + // Now, if those two crates are linked into an application, and + // they contain inlined code, you can wind up with a situation + // where both of those functions wind up being loaded into this + // application simultaneously. In that case, the same function + // (from LLVM's point of view) requires two types. But of course + // LLVM won't allow one function to have two types. + // + // What we currently do, therefore, is declare the function with + // one of the two types (whichever happens to come first) and then + // bitcast as needed when the function is referenced to make sure + // it has the type we expect. + // + // This can occur on either a crate-local or crate-external + // reference. It also occurs when testing libcore and in some + // other weird situations. Annoying. + if cx.val_ty(func) != ptrty { + // TODO(antoyo): cast the pointer. + func + } + else { + func + } + } + else { + cx.linkage.set(FunctionType::Extern); + let func = cx.declare_fn(&sym, &fn_abi); + + // TODO(antoyo): set linkage and attributes. + func + }; + + cx.function_instances.borrow_mut().insert(instance, func); + + func +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/common.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/common.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/common.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/common.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,450 @@ +use std::convert::TryFrom; +use std::convert::TryInto; + +use gccjit::LValue; +use gccjit::{Block, CType, RValue, Type, ToRValue}; +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{ + BaseTypeMethods, + ConstMethods, + DerivedTypeMethods, + MiscMethods, + StaticMethods, +}; +use rustc_middle::mir::Mutability; +use rustc_middle::ty::ScalarInt; +use rustc_middle::ty::layout::{TyAndLayout, LayoutOf}; +use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar}; +use rustc_span::Symbol; +use rustc_target::abi::{self, HasDataLayout, Pointer, Size}; + +use crate::consts::const_alloc_to_gcc; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn const_bytes(&self, bytes: &[u8]) -> RValue<'gcc> { + bytes_in_context(self, bytes) + } + + fn const_cstr(&self, symbol: Symbol, _null_terminated: bool) -> LValue<'gcc> { + // TODO(antoyo): handle null_terminated. + if let Some(&value) = self.const_cstr_cache.borrow().get(&symbol) { + return value; + } + + let global = self.global_string(&*symbol.as_str()); + + self.const_cstr_cache.borrow_mut().insert(symbol, global); + global + } + + fn global_string(&self, string: &str) -> LValue<'gcc> { + // TODO(antoyo): handle non-null-terminated strings. + let string = self.context.new_string_literal(&*string); + let sym = self.generate_local_symbol_name("str"); + let global = self.declare_private_global(&sym, self.val_ty(string)); + global.global_set_initializer_value(string); + global + // TODO(antoyo): set linkage. + } + + pub fn inttoptr(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + let func = block.get_function(); + let local = func.new_local(None, value.get_type(), "intLocal"); + block.add_assignment(None, local, value); + let value_address = local.get_address(None); + + let ptr = self.context.new_cast(None, value_address, dest_ty.make_pointer()); + ptr.dereference(None).to_rvalue() + } + + pub fn ptrtoint(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): when libgccjit allow casting from pointer to int, remove this. + let func = block.get_function(); + let local = func.new_local(None, value.get_type(), "ptrLocal"); + block.add_assignment(None, local, value); + let ptr_address = local.get_address(None); + + let ptr = self.context.new_cast(None, ptr_address, dest_ty.make_pointer()); + ptr.dereference(None).to_rvalue() + } +} + +pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> { + let context = &cx.context; + let byte_type = context.new_type::(); + let typ = context.new_array_type(None, byte_type, bytes.len() as i32); + let elements: Vec<_> = + bytes.iter() + .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)) + .collect(); + context.new_rvalue_from_array(None, typ, &elements) +} + +pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool { + typ.get_pointee().is_some() +} + +impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { + if type_is_pointer(typ) { + self.context.new_null(typ) + } + else { + self.const_int(typ, 0) + } + } + + fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { + let local = self.current_func.borrow().expect("func") + .new_local(None, typ, "undefined"); + if typ.is_struct().is_some() { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + let pointer = local.get_address(None); + self.structs_as_pointer.borrow_mut().insert(pointer); + pointer + } + else { + local.to_rvalue() + } + } + + fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { + self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from")) + } + + fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> { + self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64) + } + + fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> { + let num64: Result = num.try_into(); + if let Ok(num) = num64 { + // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant. + // The operations >> 64 and | low are making the normal case a non-constant. + return self.context.new_rvalue_from_long(typ, num as i64); + } + + if num >> 64 != 0 { + // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()? + let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); + let high = self.context.new_rvalue_from_long(typ, (num >> 64) as u64 as i64); + + let sixty_four = self.context.new_rvalue_from_long(typ, 64); + (high << sixty_four) | self.context.new_cast(None, low, typ) + } + else if typ.is_i128(self) { + let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); + self.context.new_cast(None, num, typ) + } + else { + self.context.new_rvalue_from_long(typ, num as u64 as i64) + } + } + + fn const_bool(&self, val: bool) -> RValue<'gcc> { + self.const_uint(self.type_i1(), val as u64) + } + + fn const_i32(&self, i: i32) -> RValue<'gcc> { + self.const_int(self.type_i32(), i as i64) + } + + fn const_u32(&self, i: u32) -> RValue<'gcc> { + self.const_uint(self.type_u32(), i as u64) + } + + fn const_u64(&self, i: u64) -> RValue<'gcc> { + self.const_uint(self.type_u64(), i) + } + + fn const_usize(&self, i: u64) -> RValue<'gcc> { + let bit_size = self.data_layout().pointer_size.bits(); + if bit_size < 64 { + // make sure it doesn't overflow + assert!(i < (1 << bit_size)); + } + + self.const_uint(self.usize_type, i) + } + + fn const_u8(&self, _i: u8) -> RValue<'gcc> { + unimplemented!(); + } + + fn const_real(&self, _t: Type<'gcc>, _val: f64) -> RValue<'gcc> { + unimplemented!(); + } + + fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) { + let len = s.as_str().len(); + let cs = self.const_ptrcast(self.const_cstr(s, false).get_address(None), + self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)), + ); + (cs, self.const_usize(len as u64)) + } + + fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> { + let fields: Vec<_> = values.iter() + .map(|value| value.get_type()) + .collect(); + // TODO(antoyo): cache the type? It's anonymous, so probably not. + let typ = self.type_struct(&fields, packed); + let struct_type = typ.is_struct().expect("struct type"); + self.context.new_rvalue_from_struct(None, struct_type, values) + } + + fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option { + // TODO(antoyo) + None + } + + fn const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option { + // TODO(antoyo) + None + } + + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { + let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() }; + match cv { + Scalar::Int(ScalarInt::ZST) => { + assert_eq!(0, layout.value.size(self).bytes()); + self.const_undef(self.type_ix(0)) + } + Scalar::Int(int) => { + let data = int.assert_bits(layout.value.size(self)); + + // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code + // the paths for floating-point values. + if ty == self.float_type { + return self.context.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64); + } + else if ty == self.double_type { + return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64)); + } + + let value = self.const_uint_big(self.type_ix(bitsize), data); + if layout.value == Pointer { + self.inttoptr(self.current_block.borrow().expect("block"), value, ty) + } else { + self.const_bitcast(value, ty) + } + } + Scalar::Ptr(ptr, _size) => { + let (alloc_id, offset) = ptr.into_parts(); + let base_addr = + match self.tcx.global_alloc(alloc_id) { + GlobalAlloc::Memory(alloc) => { + let init = const_alloc_to_gcc(self, alloc); + let value = + match alloc.mutability { + Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), + _ => self.static_addr_of(init, alloc.align, None), + }; + if !self.sess().fewer_names() { + // TODO(antoyo): set value name. + } + value + }, + GlobalAlloc::Function(fn_instance) => { + self.get_fn_addr(fn_instance) + }, + GlobalAlloc::Static(def_id) => { + assert!(self.tcx.is_static(def_id)); + self.get_static(def_id).get_address(None) + }, + }; + let ptr_type = base_addr.get_type(); + let base_addr = self.const_bitcast(base_addr, self.usize_type); + let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64); + let ptr = self.const_bitcast(base_addr + offset, ptr_type); + if layout.value != Pointer { + self.const_bitcast(ptr.dereference(None).to_rvalue(), ty) + } + else { + self.const_bitcast(ptr, ty) + } + } + } + } + + fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value { + const_alloc_to_gcc(self, alloc) + } + + fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: &Allocation, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> { + assert_eq!(alloc.align, layout.align.abi); + let ty = self.type_ptr_to(layout.gcc_type(self, true)); + let value = + if layout.size == Size::ZERO { + let value = self.const_usize(alloc.align.bytes()); + self.context.new_cast(None, value, ty) + } + else { + let init = const_alloc_to_gcc(self, alloc); + let base_addr = self.static_addr_of(init, alloc.align, None); + + let array = self.const_bitcast(base_addr, self.type_i8p()); + let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None); + self.const_bitcast(value, ty) + }; + PlaceRef::new_sized(value, layout) + } + + fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, val, ty) + } +} + +pub trait SignType<'gcc, 'tcx> { + fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; + fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; +} + +impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> { + fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.is_i8(cx) || self.is_i16(cx) || self.is_i32(cx) || self.is_i64(cx) || self.is_i128(cx) + } + + fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.is_u8(cx) || self.is_u16(cx) || self.is_u32(cx) || self.is_u64(cx) || self.is_u128(cx) + } + + fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + if self.is_u8(cx) { + cx.i8_type + } + else if self.is_u16(cx) { + cx.i16_type + } + else if self.is_u32(cx) { + cx.i32_type + } + else if self.is_u64(cx) { + cx.i64_type + } + else if self.is_u128(cx) { + cx.i128_type + } + else { + self.clone() + } + } + + fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + if self.is_i8(cx) { + cx.u8_type + } + else if self.is_i16(cx) { + cx.u16_type + } + else if self.is_i32(cx) { + cx.u32_type + } + else if self.is_i64(cx) { + cx.u64_type + } + else if self.is_i128(cx) { + cx.u128_type + } + else { + self.clone() + } + } +} + +pub trait TypeReflection<'gcc, 'tcx> { + fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + + fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + + fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; +} + +impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> { + fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u8_type + } + + fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u16_type + } + + fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.uint_type + } + + fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.ulong_type + } + + fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.ulonglong_type + } + + fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.i8_type + } + + fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u8_type + } + + fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.i16_type + } + + fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u16_type + } + + fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.i32_type + } + + fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u32_type + } + + fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.i64_type + } + + fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u64_type + } + + fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.context.new_c_type(CType::Int128t) + } + + fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.context.new_c_type(CType::UInt128t) + } + + fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.context.new_type::() + } + + fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.context.new_type::() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/consts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/consts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/consts.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/consts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,390 @@ +use gccjit::{LValue, RValue, ToRValue, Type}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; +use rustc_hir as hir; +use rustc_hir::Node; +use rustc_middle::{bug, span_bug}; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::mir::interpret::{self, Allocation, ErrorHandled, Scalar as InterpScalar, read_target_uint}; +use rustc_span::Span; +use rustc_span::def_id::DefId; +use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange}; + +use crate::base; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { + if value.get_type() == self.bool_type.make_pointer() { + if let Some(pointee) = typ.get_pointee() { + if pointee.is_vector().is_some() { + panic!() + } + } + } + self.context.new_bitcast(None, value, typ) + } +} + +impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { + fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { + if let Some(global_value) = self.const_globals.borrow().get(&cv) { + // TODO(antoyo): upgrade alignment. + return *global_value; + } + let global_value = self.static_addr_of_mut(cv, align, kind); + // TODO(antoyo): set global constant. + self.const_globals.borrow_mut().insert(cv, global_value); + global_value + } + + fn codegen_static(&self, def_id: DefId, is_mutable: bool) { + let attrs = self.tcx.codegen_fn_attrs(def_id); + + let value = + match codegen_static_initializer(&self, def_id) { + Ok((value, _)) => value, + // Error has already been reported + Err(_) => return, + }; + + let global = self.get_static(def_id); + + // boolean SSA values are i1, but they have to be stored in i8 slots, + // otherwise some LLVM optimization passes don't work as expected + let val_llty = self.val_ty(value); + let value = + if val_llty == self.type_i1() { + unimplemented!(); + } + else { + value + }; + + let instance = Instance::mono(self.tcx, def_id); + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let gcc_type = self.layout_of(ty).gcc_type(self, true); + + // TODO(antoyo): set alignment. + + let value = + if value.get_type() != gcc_type { + self.context.new_bitcast(None, value, gcc_type) + } + else { + value + }; + global.global_set_initializer_value(value); + + // As an optimization, all shared statics which do not have interior + // mutability are placed into read-only memory. + if !is_mutable { + if self.type_is_freeze(ty) { + // TODO(antoyo): set global constant. + } + } + + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + // Do not allow LLVM to change the alignment of a TLS on macOS. + // + // By default a global's alignment can be freely increased. + // This allows LLVM to generate more performant instructions + // e.g., using load-aligned into a SIMD register. + // + // However, on macOS 10.10 or below, the dynamic linker does not + // respect any alignment given on the TLS (radar 24221680). + // This will violate the alignment assumption, and causing segfault at runtime. + // + // This bug is very easy to trigger. In `println!` and `panic!`, + // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS, + // which the values would be `mem::replace`d on initialization. + // The implementation of `mem::replace` will use SIMD + // whenever the size is 32 bytes or higher. LLVM notices SIMD is used + // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary, + // which macOS's dyld disregarded and causing crashes + // (see issues #51794, #51758, #50867, #48866 and #44056). + // + // To workaround the bug, we trick LLVM into not increasing + // the global's alignment by explicitly assigning a section to it + // (equivalent to automatically generating a `#[link_section]` attribute). + // See the comment in the `GlobalValue::canIncreaseAlignment()` function + // of `lib/IR/Globals.cpp` for why this works. + // + // When the alignment is not increased, the optimized `mem::replace` + // will use load-unaligned instructions instead, and thus avoiding the crash. + // + // We could remove this hack whenever we decide to drop macOS 10.10 support. + if self.tcx.sess.target.options.is_like_osx { + // The `inspect` method is okay here because we checked relocations, and + // because we are doing this access to inspect the final interpreter state + // (not as part of the interpreter execution). + // + // FIXME: This check requires that the (arbitrary) value of undefined bytes + // happens to be zero. Instead, we should only check the value of defined bytes + // and set all undefined bytes to zero if this allocation is headed for the + // BSS. + unimplemented!(); + } + } + + // Wasm statics with custom link sections get special treatment as they + // go into custom sections of the wasm executable. + if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + if let Some(_section) = attrs.link_section { + unimplemented!(); + } + } else { + // TODO(antoyo): set link section. + } + + if attrs.flags.contains(CodegenFnAttrFlags::USED) { + self.add_used_global(global.to_rvalue()); + } + } + + /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*. + fn add_used_global(&self, _global: RValue<'gcc>) { + // TODO(antoyo) + } + + fn add_compiler_used_global(&self, _global: RValue<'gcc>) { + // TODO(antoyo) + } +} + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn static_addr_of_mut(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { + let global = + match kind { + Some(kind) if !self.tcx.sess.fewer_names() => { + let name = self.generate_local_symbol_name(kind); + // TODO(antoyo): check if it's okay that TLS is off here. + // TODO(antoyo): check if it's okay that link_section is None here. + // TODO(antoyo): set alignment here as well. + let global = self.define_global(&name[..], self.val_ty(cv), false, None); + // TODO(antoyo): set linkage. + global + } + _ => { + let typ = self.val_ty(cv).get_aligned(align.bytes()); + let global = self.declare_unnamed_global(typ); + global + }, + }; + // FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used + // globally. + global.global_set_initializer_value(cv); + // TODO(antoyo): set unnamed address. + global.get_address(None) + } + + pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> { + let instance = Instance::mono(self.tcx, def_id); + let fn_attrs = self.tcx.codegen_fn_attrs(def_id); + if let Some(&global) = self.instances.borrow().get(&instance) { + return global; + } + + let defined_in_current_codegen_unit = + self.codegen_unit.items().contains_key(&MonoItem::Static(def_id)); + assert!( + !defined_in_current_codegen_unit, + "consts::get_static() should always hit the cache for \ + statics defined in the same CGU, but did not for `{:?}`", + def_id + ); + + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let sym = self.tcx.symbol_name(instance).name; + + let global = + if let Some(def_id) = def_id.as_local() { + let id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let llty = self.layout_of(ty).gcc_type(self, true); + // FIXME: refactor this to work without accessing the HIR + let global = match self.tcx.hir().get(id) { + Node::Item(&hir::Item { span, kind: hir::ItemKind::Static(..), .. }) => { + if let Some(global) = self.get_declared_value(&sym) { + if self.val_ty(global) != self.type_ptr_to(llty) { + span_bug!(span, "Conflicting types for static"); + } + } + + let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); + let global = self.declare_global(&sym, llty, is_tls, fn_attrs.link_section); + + if !self.tcx.is_reachable_non_generic(def_id) { + // TODO(antoyo): set visibility. + } + + global + } + + Node::ForeignItem(&hir::ForeignItem { + span, + kind: hir::ForeignItemKind::Static(..), + .. + }) => { + let fn_attrs = self.tcx.codegen_fn_attrs(def_id); + check_and_apply_linkage(&self, &fn_attrs, ty, sym, span) + } + + item => bug!("get_static: expected static, found {:?}", item), + }; + + global + } + else { + // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? + //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id)); + + let attrs = self.tcx.codegen_fn_attrs(def_id); + let span = self.tcx.def_span(def_id); + let global = check_and_apply_linkage(&self, &attrs, ty, sym, span); + + let needs_dll_storage_attr = false; // TODO(antoyo) + + // If this assertion triggers, there's something wrong with commandline + // argument validation. + debug_assert!( + !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() + && self.tcx.sess.target.options.is_like_msvc + && self.tcx.sess.opts.cg.prefer_dynamic) + ); + + if needs_dll_storage_attr { + // This item is external but not foreign, i.e., it originates from an external Rust + // crate. Since we don't know whether this crate will be linked dynamically or + // statically in the final application, we always mark such symbols as 'dllimport'. + // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs + // to make things work. + // + // However, in some scenarios we defer emission of statics to downstream + // crates, so there are cases where a static with an upstream DefId + // is actually present in the current crate. We can find out via the + // is_codegened_item query. + if !self.tcx.is_codegened_item(def_id) { + unimplemented!(); + } + } + global + }; + + // TODO(antoyo): set dll storage class. + + self.instances.borrow_mut().insert(instance, global); + global + } +} + +pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Allocation) -> RValue<'gcc> { + let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); + let dl = cx.data_layout(); + let pointer_size = dl.pointer_size.bytes() as usize; + + let mut next_offset = 0; + for &(offset, alloc_id) in alloc.relocations().iter() { + let offset = offset.bytes(); + assert_eq!(offset as usize as u64, offset); + let offset = offset as usize; + if offset > next_offset { + // This `inspect` is okay since we have checked that it is not within a relocation, it + // is within the bounds of the allocation, and it doesn't affect interpreter execution + // (we inspect the result after interpreter execution). Any undef byte is replaced with + // some arbitrary byte value. + // + // FIXME: relay undef bytes to codegen as undef const bytes + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset); + llvals.push(cx.const_bytes(bytes)); + } + let ptr_offset = + read_target_uint( dl.endian, + // This `inspect` is okay since it is within the bounds of the allocation, it doesn't + // affect interpreter execution (we inspect the result after interpreter execution), + // and we properly interpret the relocation as a relocation pointer offset. + alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), + ) + .expect("const_alloc_to_llvm: could not read relocation pointer") + as u64; + llvals.push(cx.scalar_to_backend( + InterpScalar::from_pointer( + interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), + &cx.tcx, + ), + abi::Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } }, + cx.type_i8p(), + )); + next_offset = offset + pointer_size; + } + if alloc.len() >= next_offset { + let range = next_offset..alloc.len(); + // This `inspect` is okay since we have check that it is after all relocations, it is + // within the bounds of the allocation, and it doesn't affect interpreter execution (we + // inspect the result after interpreter execution). Any undef byte is replaced with some + // arbitrary byte value. + // + // FIXME: relay undef bytes to codegen as undef const bytes + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range); + llvals.push(cx.const_bytes(bytes)); + } + + cx.const_struct(&llvals, true) +} + +pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> { + let alloc = cx.tcx.eval_static_initializer(def_id)?; + Ok((const_alloc_to_gcc(cx, alloc), alloc)) +} + +fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> { + let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); + let llty = cx.layout_of(ty).gcc_type(cx, true); + if let Some(linkage) = attrs.linkage { + // If this is a static with a linkage specified, then we need to handle + // it a little specially. The typesystem prevents things like &T and + // extern "C" fn() from being non-null, so we can't just declare a + // static and call it a day. Some linkages (like weak) will make it such + // that the static actually has a null value. + let llty2 = + if let ty::RawPtr(ref mt) = ty.kind() { + cx.layout_of(mt.ty).gcc_type(cx, true) + } + else { + cx.sess().span_fatal( + span, + "must have type `*const T` or `*mut T` due to `#[linkage]` attribute", + ) + }; + // Declare a symbol `foo` with the desired linkage. + let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage)); + + // Declare an internal global `extern_with_linkage_foo` which + // is initialized with the address of `foo`. If `foo` is + // discarded during linking (for example, if `foo` has weak + // linkage and there are no definitions), then + // `extern_with_linkage_foo` will instead be initialized to + // zero. + let mut real_name = "_rust_extern_with_linkage_".to_string(); + real_name.push_str(&sym); + let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section); + // TODO(antoyo): set linkage. + global2.global_set_initializer_value(global1.get_address(None)); + // TODO(antoyo): use global_set_initializer() when it will work. + global2 + } + else { + // Generate an external declaration. + // FIXME(nagisa): investigate whether it can be changed into define_global + + // Thread-local statics in some other crate need to *always* be linked + // against in a thread-local fashion, so we need to be sure to apply the + // thread-local attribute locally if it was present remotely. If we + // don't do this then linker errors can be generated where the linker + // complains that one object files has a thread local version of the + // symbol and another one doesn't. + cx.declare_global(&sym, llty, is_tls, attrs.link_section) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/context.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/context.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/context.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/context.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,475 @@ +use std::cell::{Cell, RefCell}; + +use gccjit::{ + Block, + Context, + CType, + Function, + FunctionType, + LValue, + RValue, + Struct, + Type, +}; +use rustc_codegen_ssa::base::wants_msvc_seh; +use rustc_codegen_ssa::traits::{ + BackendTypes, + MiscMethods, +}; +use rustc_data_structures::base_n; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::span_bug; +use rustc_middle::mir::mono::CodegenUnit; +use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; +use rustc_session::Session; +use rustc_span::{Span, Symbol}; +use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; +use rustc_target::spec::{HasTargetSpec, Target, TlsModel}; + +use crate::callee::get_fn; +use crate::declare::mangle_name; + +#[derive(Clone)] +pub struct FuncSig<'gcc> { + pub params: Vec>, + pub return_type: Type<'gcc>, +} + +pub struct CodegenCx<'gcc, 'tcx> { + pub check_overflow: bool, + pub codegen_unit: &'tcx CodegenUnit<'tcx>, + pub context: &'gcc Context<'gcc>, + + // TODO(antoyo): First set it to a dummy block to avoid using Option? + pub current_block: RefCell>>, + pub current_func: RefCell>>, + pub normal_function_addresses: RefCell>>, + + pub functions: RefCell>>, + + pub tls_model: gccjit::TlsModel, + + pub bool_type: Type<'gcc>, + pub i8_type: Type<'gcc>, + pub i16_type: Type<'gcc>, + pub i32_type: Type<'gcc>, + pub i64_type: Type<'gcc>, + pub i128_type: Type<'gcc>, + pub isize_type: Type<'gcc>, + + pub u8_type: Type<'gcc>, + pub u16_type: Type<'gcc>, + pub u32_type: Type<'gcc>, + pub u64_type: Type<'gcc>, + pub u128_type: Type<'gcc>, + pub usize_type: Type<'gcc>, + + pub int_type: Type<'gcc>, + pub uint_type: Type<'gcc>, + pub long_type: Type<'gcc>, + pub ulong_type: Type<'gcc>, + pub ulonglong_type: Type<'gcc>, + pub sizet_type: Type<'gcc>, + + pub float_type: Type<'gcc>, + pub double_type: Type<'gcc>, + + pub linkage: Cell, + pub scalar_types: RefCell, Type<'gcc>>>, + pub types: RefCell, Option), Type<'gcc>>>, + pub tcx: TyCtxt<'tcx>, + + pub struct_types: RefCell>, Type<'gcc>>>, + + pub types_with_fields_to_set: RefCell, (Struct<'gcc>, TyAndLayout<'tcx>)>>, + + /// Cache instances of monomorphic and polymorphic items + pub instances: RefCell, LValue<'gcc>>>, + /// Cache function instances of monomorphic and polymorphic items + pub function_instances: RefCell, RValue<'gcc>>>, + /// Cache generated vtables + pub vtables: RefCell, Option>), RValue<'gcc>>>, + + /// Cache of emitted const globals (value -> global) + pub const_globals: RefCell, RValue<'gcc>>>, + + /// Cache of constant strings, + pub const_cstr_cache: RefCell>>, + + /// Cache of globals. + pub globals: RefCell>>, + + /// A counter that is used for generating local symbol names + local_gen_sym_counter: Cell, + pub global_gen_sym_counter: Cell, + + eh_personality: Cell>>, + + pub pointee_infos: RefCell, Size), Option>>, + + /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such, + /// `const_undef()` returns struct as pointer so that they can later be assigned a value. + /// As such, this set remembers which of these pointers were returned by this function so that + /// they can be deferenced later. + /// FIXME(antoyo): fix the rustc API to avoid having this hack. + pub structs_as_pointer: RefCell>>, +} + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + let check_overflow = tcx.sess.overflow_checks(); + // TODO(antoyo): fix this mess. libgccjit seems to return random type when using new_int_type(). + let isize_type = context.new_c_type(CType::LongLong); + let usize_type = context.new_c_type(CType::ULongLong); + let bool_type = context.new_type::(); + let i8_type = context.new_type::(); + let i16_type = context.new_type::(); + let i32_type = context.new_type::(); + let i64_type = context.new_c_type(CType::LongLong); + let i128_type = context.new_c_type(CType::Int128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded? + let u8_type = context.new_type::(); + let u16_type = context.new_type::(); + let u32_type = context.new_type::(); + let u64_type = context.new_c_type(CType::ULongLong); + let u128_type = context.new_c_type(CType::UInt128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded? + + let tls_model = to_gcc_tls_mode(tcx.sess.tls_model()); + + let float_type = context.new_type::(); + let double_type = context.new_type::(); + + let int_type = context.new_c_type(CType::Int); + let uint_type = context.new_c_type(CType::UInt); + let long_type = context.new_c_type(CType::Long); + let ulong_type = context.new_c_type(CType::ULong); + let ulonglong_type = context.new_c_type(CType::ULongLong); + let sizet_type = context.new_c_type(CType::SizeT); + + assert_eq!(isize_type, i64_type); + assert_eq!(usize_type, u64_type); + + let mut functions = FxHashMap::default(); + let builtins = [ + "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow", + "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ + "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow", + "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow", + "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos", + "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf", + "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf", + "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round", + "__builtin_expect_with_probability", + ]; + + for builtin in builtins.iter() { + functions.insert(builtin.to_string(), context.get_builtin_function(builtin)); + } + + Self { + check_overflow, + codegen_unit, + context, + current_block: RefCell::new(None), + current_func: RefCell::new(None), + normal_function_addresses: Default::default(), + functions: RefCell::new(functions), + + tls_model, + + bool_type, + i8_type, + i16_type, + i32_type, + i64_type, + i128_type, + isize_type, + usize_type, + u8_type, + u16_type, + u32_type, + u64_type, + u128_type, + int_type, + uint_type, + long_type, + ulong_type, + ulonglong_type, + sizet_type, + + float_type, + double_type, + + linkage: Cell::new(FunctionType::Internal), + instances: Default::default(), + function_instances: Default::default(), + vtables: Default::default(), + const_globals: Default::default(), + const_cstr_cache: Default::default(), + globals: Default::default(), + scalar_types: Default::default(), + types: Default::default(), + tcx, + struct_types: Default::default(), + types_with_fields_to_set: Default::default(), + local_gen_sym_counter: Cell::new(0), + global_gen_sym_counter: Cell::new(0), + eh_personality: Cell::new(None), + pointee_infos: Default::default(), + structs_as_pointer: Default::default(), + } + } + + pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> { + let function: Function<'gcc> = unsafe { std::mem::transmute(value) }; + debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(), + "{:?} ({:?}) is not a function", value, value.get_type()); + function + } + + pub fn sess(&self) -> &Session { + &self.tcx.sess + } +} + +impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { + type Value = RValue<'gcc>; + type Function = RValue<'gcc>; + + type BasicBlock = Block<'gcc>; + type Type = Type<'gcc>; + type Funclet = (); // TODO(antoyo) + + type DIScope = (); // TODO(antoyo) + type DILocation = (); // TODO(antoyo) + type DIVariable = (); // TODO(antoyo) +} + +impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn vtables(&self) -> &RefCell, Option>), RValue<'gcc>>> { + &self.vtables + } + + fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> { + let func = get_fn(self, instance); + *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func)); + func + } + + fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { + let func = get_fn(self, instance); + let func = self.rvalue_as_function(func); + let ptr = func.get_address(None); + + // TODO(antoyo): don't do this twice: i.e. in declare_fn and here. + // FIXME(antoyo): the rustc API seems to call get_fn_addr() when not needed (e.g. for FFI). + + self.normal_function_addresses.borrow_mut().insert(ptr); + + ptr + } + + fn eh_personality(&self) -> RValue<'gcc> { + // The exception handling personality function. + // + // If our compilation unit has the `eh_personality` lang item somewhere + // within it, then we just need to codegen that. Otherwise, we're + // building an rlib which will depend on some upstream implementation of + // this function, so we just codegen a generic reference to it. We don't + // specify any of the types for the function, we just make it a symbol + // that LLVM can later use. + // + // Note that MSVC is a little special here in that we don't use the + // `eh_personality` lang item at all. Currently LLVM has support for + // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the + // *name of the personality function* to decide what kind of unwind side + // tables/landing pads to emit. It looks like Dwarf is used by default, + // injecting a dependency on the `_Unwind_Resume` symbol for resuming + // an "exception", but for MSVC we want to force SEH. This means that we + // can't actually have the personality function be our standard + // `rust_eh_personality` function, but rather we wired it up to the + // CRT's custom personality function, which forces LLVM to consider + // landing pads as "landing pads for SEH". + if let Some(llpersonality) = self.eh_personality.get() { + return llpersonality; + } + let tcx = self.tcx; + let llfn = match tcx.lang_items().eh_personality() { + Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr( + ty::Instance::resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + tcx.intern_substs(&[]), + ) + .unwrap().unwrap(), + ), + _ => { + let _name = if wants_msvc_seh(self.sess()) { + "__CxxFrameHandler3" + } else { + "rust_eh_personality" + }; + //let func = self.declare_func(name, self.type_i32(), &[], true); + // FIXME(antoyo): this hack should not be needed. That will probably be removed when + // unwinding support is added. + self.context.new_rvalue_from_int(self.int_type, 0) + } + }; + // TODO(antoyo): apply target cpu attributes. + self.eh_personality.set(Some(llfn)); + llfn + } + + fn sess(&self) -> &Session { + &self.tcx.sess + } + + fn check_overflow(&self) -> bool { + self.check_overflow + } + + fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { + self.codegen_unit + } + + fn used_statics(&self) -> &RefCell>> { + unimplemented!(); + } + + fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) { + // TODO(antoyo) + } + + fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) { + // TODO(antoyo) + } + + fn create_used_variable(&self) { + unimplemented!(); + } + + fn declare_c_main(&self, fn_type: Self::Type) -> Option { + if self.get_declared_value("main").is_none() { + Some(self.declare_cfn("main", fn_type)) + } + else { + // If the symbol already exists, it is an error: for example, the user wrote + // #[no_mangle] extern "C" fn main(..) {..} + // instead of #[start] + None + } + } + + fn compiler_used_statics(&self) -> &RefCell>> { + unimplemented!() + } + + fn create_compiler_used_variable(&self) { + unimplemented!() + } +} + +impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl<'gcc, 'tcx> HasDataLayout for CodegenCx<'gcc, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> { + fn target_spec(&self) -> &Target { + &self.tcx.sess.target + } +} + +impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + if let LayoutError::SizeOverflow(_) = err { + self.sess().span_fatal(span, &err.to_string()) + } else { + span_bug!(span, "failed to get layout for `{}`: {}", ty, err) + } + } +} + +impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { + self.sess().span_fatal(span, &err.to_string()) + } else { + match fn_abi_request { + FnAbiRequest::OfFnPtr { sig, extra_args } => { + span_bug!( + span, + "`fn_abi_of_fn_ptr({}, {:?})` failed: {}", + sig, + extra_args, + err + ); + } + FnAbiRequest::OfInstance { instance, extra_args } => { + span_bug!( + span, + "`fn_abi_of_instance({}, {:?})` failed: {}", + instance, + extra_args, + err + ); + } + } + } + } +} + +impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + ParamEnv::reveal_all() + } +} + +impl<'b, 'tcx> CodegenCx<'b, 'tcx> { + /// Generates a new symbol name with the given prefix. This symbol name must + /// only be used for definitions with `internal` or `private` linkage. + pub fn generate_local_symbol_name(&self, prefix: &str) -> String { + let idx = self.local_gen_sym_counter.get(); + self.local_gen_sym_counter.set(idx + 1); + // Include a '.' character, so there can be no accidental conflicts with + // user defined names + let mut name = String::with_capacity(prefix.len() + 6); + name.push_str(prefix); + name.push_str("."); + base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name); + name + } +} + +pub fn unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String { + let name = &codegen_unit.name().to_string(); + mangle_name(&name.replace('-', "_")) +} + +fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel { + match tls_model { + TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic, + TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic, + TlsModel::InitialExec => gccjit::TlsModel::InitialExec, + TlsModel::LocalExec => gccjit::TlsModel::LocalExec, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/coverageinfo.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/coverageinfo.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/coverageinfo.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/coverageinfo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,69 @@ +use gccjit::RValue; +use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods}; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::coverage::{ + CodeRegion, + CounterValueReference, + ExpressionOperandId, + InjectedExpressionId, + Op, +}; +use rustc_middle::ty::Instance; + +use crate::builder::Builder; +use crate::context::CodegenCx; + +impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn set_function_source_hash( + &mut self, + _instance: Instance<'tcx>, + _function_source_hash: u64, + ) -> bool { + unimplemented!(); + } + + fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool { + // TODO(antoyo) + false + } + + fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option) -> bool { + // TODO(antoyo) + false + } + + fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool { + // TODO(antoyo) + false + } +} + +impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn coverageinfo_finalize(&self) { + // TODO(antoyo) + } + + fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> { + unimplemented!(); + } + + /// Functions with MIR-based coverage are normally codegenned _only_ if + /// called. LLVM coverage tools typically expect every function to be + /// defined (even if unused), with at least one call to LLVM intrinsic + /// `instrprof.increment`. + /// + /// Codegen a small function that will never be called, with one counter + /// that will never be incremented. + /// + /// For used/called functions, the coverageinfo was already added to the + /// `function_coverage_map` (keyed by function `Instance`) during codegen. + /// But in this case, since the unused function was _not_ previously + /// codegenned, collect the coverage `CodeRegion`s from the MIR and add + /// them. The first `CodeRegion` is used to add a single counter, with the + /// same counter ID used in the injected `instrprof.increment` intrinsic + /// call. Since the function is never called, all other `CodeRegion`s can be + /// added as `unreachable_region`s. + fn define_unused_fn(&self, _def_id: DefId) { + unimplemented!(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/debuginfo.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/debuginfo.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/debuginfo.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/debuginfo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,62 @@ +use gccjit::RValue; +use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind}; +use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; +use rustc_middle::mir; +use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; +use rustc_span::{SourceFile, Span, Symbol}; +use rustc_target::abi::Size; +use rustc_target::abi::call::FnAbi; + +use crate::builder::Builder; +use crate::context::CodegenCx; + +impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { + // FIXME(eddyb) find a common convention for all of the debuginfo-related + // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). + fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) { + unimplemented!(); + } + + fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { + // TODO(antoyo): insert reference to gdb debug scripts section global. + } + + fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) { + unimplemented!(); + } + + fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) { + unimplemented!(); + } +} + +impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _trait_ref: Option>, _vtable: Self::Value) { + // TODO(antoyo) + } + + fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option> { + // TODO(antoyo) + None + } + + fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope { + unimplemented!(); + } + + fn debuginfo_finalize(&self) { + // TODO(antoyo) + } + + fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable { + unimplemented!(); + } + + fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option>) -> Self::DIScope { + unimplemented!(); + } + + fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option, _span: Span) -> Self::DILocation { + unimplemented!(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/declare.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/declare.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/declare.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/declare.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,144 @@ +use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type}; +use rustc_codegen_ssa::traits::BaseTypeMethods; +use rustc_middle::ty::Ty; +use rustc_span::Symbol; +use rustc_target::abi::call::FnAbi; + +use crate::abi::FnAbiGccExt; +use crate::context::{CodegenCx, unit_name}; +use crate::intrinsic::llvm; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { + if self.globals.borrow().contains_key(name) { + let typ = self.globals.borrow().get(name).expect("global").get_type(); + let global = self.context.new_global(None, GlobalKind::Imported, typ, name); + if is_tls { + global.set_tls_model(self.tls_model); + } + if let Some(link_section) = link_section { + global.set_link_section(&link_section.as_str()); + } + global + } + else { + self.declare_global(name, ty, is_tls, link_section) + } + } + + pub fn declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc> { + let index = self.global_gen_sym_counter.get(); + self.global_gen_sym_counter.set(index + 1); + let name = format!("global_{}_{}", index, unit_name(&self.codegen_unit)); + self.context.new_global(None, GlobalKind::Exported, ty, &name) + } + + pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc> { + let global = self.context.new_global(None, linkage, ty, name); + let global_address = global.get_address(None); + self.globals.borrow_mut().insert(name.to_string(), global_address); + global + } + + /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> { + self.linkage.set(FunctionType::Exported); + let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic); + // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. + unsafe { std::mem::transmute(func) } + }*/ + + pub fn declare_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { + let global = self.context.new_global(None, GlobalKind::Exported, ty, name); + if is_tls { + global.set_tls_model(self.tls_model); + } + if let Some(link_section) = link_section { + global.set_link_section(&link_section.as_str()); + } + let global_address = global.get_address(None); + self.globals.borrow_mut().insert(name.to_string(), global_address); + global + } + + pub fn declare_private_global(&self, name: &str, ty: Type<'gcc>) -> LValue<'gcc> { + let global = self.context.new_global(None, GlobalKind::Internal, ty, name); + let global_address = global.get_address(None); + self.globals.borrow_mut().insert(name.to_string(), global_address); + global + } + + pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use the fn_type parameter. + let const_string = self.context.new_type::().make_pointer().make_pointer(); + let return_type = self.type_i32(); + let variadic = false; + self.linkage.set(FunctionType::Exported); + let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic); + // NOTE: it is needed to set the current_func here as well, because get_fn() is not called + // for the main function. + *self.current_func.borrow_mut() = Some(func); + // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. + unsafe { std::mem::transmute(func) } + } + + pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc> { + let (return_type, params, variadic) = fn_abi.gcc_type(self); + let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, ¶ms, variadic); + // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. + unsafe { std::mem::transmute(func) } + } + + pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { + self.get_or_insert_global(name, ty, is_tls, link_section) + } + + pub fn get_declared_value(&self, name: &str) -> Option> { + // TODO(antoyo): use a different field than globals, because this seems to return a function? + self.globals.borrow().get(name).cloned() + } +} + +/// Declare a function. +/// +/// If there’s a value with the same name already declared, the function will +/// update the declaration and return existing Value instead. +fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc> { + if name.starts_with("llvm.") { + return llvm::intrinsic(name, cx); + } + let func = + if cx.functions.borrow().contains_key(name) { + *cx.functions.borrow().get(name).expect("function") + } + else { + let params: Vec<_> = param_types.into_iter().enumerate() + .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name. + .collect(); + let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, mangle_name(name), variadic); + cx.functions.borrow_mut().insert(name.to_string(), func); + func + }; + + // TODO(antoyo): set function calling convention. + // TODO(antoyo): set unnamed address. + // TODO(antoyo): set no red zone function attribute. + // TODO(antoyo): set attributes for optimisation. + // TODO(antoyo): set attributes for non lazy bind. + + // FIXME(antoyo): invalid cast. + func +} + +// FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _. +// Unsupported characters: `$` and `.`. +pub fn mangle_name(name: &str) -> String { + name.replace(|char: char| { + if !char.is_alphanumeric() && char != '_' { + debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char); + true + } + else { + false + } + }, "_") +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +use gccjit::Function; + +use crate::context::CodegenCx; + +pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> { + let _gcc_name = + match name { + "llvm.x86.xgetbv" => { + let gcc_name = "__builtin_trap"; + let func = cx.context.get_builtin_function(gcc_name); + cx.functions.borrow_mut().insert(gcc_name.to_string(), func); + return func; + }, + // NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html + "llvm.x86.sse2.cmp.pd" => "__builtin_ia32_cmppd", + "llvm.x86.sse2.movmsk.pd" => "__builtin_ia32_movmskpd", + "llvm.x86.sse2.pmovmskb.128" => "__builtin_ia32_pmovmskb128", + _ => unimplemented!("unsupported LLVM intrinsic {}", name) + }; + + unimplemented!(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1067 @@ +pub mod llvm; +mod simd; + +use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp}; +use rustc_codegen_ssa::MemFlags; +use rustc_codegen_ssa::base::wants_msvc_seh; +use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error}; +use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; +use rustc_middle::bug; +use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_span::{Span, Symbol, symbol::kw, sym}; +use rustc_target::abi::HasDataLayout; +use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use rustc_target::spec::PanicStrategy; + +use crate::abi::GccType; +use crate::builder::Builder; +use crate::common::{SignType, TypeReflection}; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; +use crate::intrinsic::simd::generic_simd_intrinsic; + +fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> Option> { + let gcc_name = match name { + sym::sqrtf32 => "sqrtf", + sym::sqrtf64 => "sqrt", + sym::powif32 => "__builtin_powif", + sym::powif64 => "__builtin_powi", + sym::sinf32 => "sinf", + sym::sinf64 => "sin", + sym::cosf32 => "cosf", + sym::cosf64 => "cos", + sym::powf32 => "powf", + sym::powf64 => "pow", + sym::expf32 => "expf", + sym::expf64 => "exp", + sym::exp2f32 => "exp2f", + sym::exp2f64 => "exp2", + sym::logf32 => "logf", + sym::logf64 => "log", + sym::log10f32 => "log10f", + sym::log10f64 => "log10", + sym::log2f32 => "log2f", + sym::log2f64 => "log2", + sym::fmaf32 => "fmaf", + sym::fmaf64 => "fma", + sym::fabsf32 => "fabsf", + sym::fabsf64 => "fabs", + sym::minnumf32 => "fminf", + sym::minnumf64 => "fmin", + sym::maxnumf32 => "fmaxf", + sym::maxnumf64 => "fmax", + sym::copysignf32 => "copysignf", + sym::copysignf64 => "copysign", + sym::floorf32 => "floorf", + sym::floorf64 => "floor", + sym::ceilf32 => "ceilf", + sym::ceilf64 => "ceil", + sym::truncf32 => "truncf", + sym::truncf64 => "trunc", + sym::rintf32 => "rintf", + sym::rintf64 => "rint", + sym::nearbyintf32 => "nearbyintf", + sym::nearbyintf64 => "nearbyint", + sym::roundf32 => "roundf", + sym::roundf64 => "round", + sym::abort => "abort", + _ => return None, + }; + Some(cx.context.get_builtin_function(&gcc_name)) +} + +impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) { + let tcx = self.tcx; + let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + + let (def_id, substs) = match *callee_ty.kind() { + ty::FnDef(def_id, substs) => (def_id, substs), + _ => bug!("expected fn item type, found {}", callee_ty), + }; + + let sig = callee_ty.fn_sig(tcx); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); + let arg_tys = sig.inputs(); + let ret_ty = sig.output(); + let name = tcx.item_name(def_id); + let name_str = &*name.as_str(); + + let llret_ty = self.layout_of(ret_ty).gcc_type(self, true); + let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); + + let simple = get_simple_intrinsic(self, name); + let llval = + match name { + _ if simple.is_some() => { + // FIXME(antoyo): remove this cast when the API supports function. + let func = unsafe { std::mem::transmute(simple.expect("simple")) }; + self.call(self.type_void(), func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) + }, + sym::likely => { + self.expect(args[0].immediate(), true) + } + sym::unlikely => { + self.expect(args[0].immediate(), false) + } + kw::Try => { + try_intrinsic( + self, + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + llresult, + ); + return; + } + sym::breakpoint => { + unimplemented!(); + } + sym::va_copy => { + unimplemented!(); + } + sym::va_arg => { + unimplemented!(); + } + + sym::volatile_load | sym::unaligned_volatile_load => { + let tp_ty = substs.type_at(0); + let mut ptr = args[0].immediate(); + if let PassMode::Cast(ty) = fn_abi.ret.mode { + ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self))); + } + let load = self.volatile_load(ptr.get_type(), ptr); + // TODO(antoyo): set alignment. + self.to_immediate(load, self.layout_of(tp_ty)) + } + sym::volatile_store => { + let dst = args[0].deref(self.cx()); + args[1].val.volatile_store(self, dst); + return; + } + sym::unaligned_volatile_store => { + let dst = args[0].deref(self.cx()); + args[1].val.unaligned_volatile_store(self, dst); + return; + } + sym::prefetch_read_data + | sym::prefetch_write_data + | sym::prefetch_read_instruction + | sym::prefetch_write_instruction => { + unimplemented!(); + } + sym::ctlz + | sym::ctlz_nonzero + | sym::cttz + | sym::cttz_nonzero + | sym::ctpop + | sym::bswap + | sym::bitreverse + | sym::rotate_left + | sym::rotate_right + | sym::saturating_add + | sym::saturating_sub => { + let ty = arg_tys[0]; + match int_type_width_signed(ty, self) { + Some((width, signed)) => match name { + sym::ctlz | sym::cttz => { + let func = self.current_func.borrow().expect("func"); + let then_block = func.new_block("then"); + let else_block = func.new_block("else"); + let after_block = func.new_block("after"); + + let arg = args[0].immediate(); + let result = func.new_local(None, arg.get_type(), "zeros"); + let zero = self.cx.context.new_rvalue_zero(arg.get_type()); + let cond = self.cx.context.new_comparison(None, ComparisonOp::Equals, arg, zero); + self.llbb().end_with_conditional(None, cond, then_block, else_block); + + let zero_result = self.cx.context.new_rvalue_from_long(arg.get_type(), width as i64); + then_block.add_assignment(None, result, zero_result); + then_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place + // count_leading_zeroes() does not expect, the current blocks + // in the state need to be updated. + *self.current_block.borrow_mut() = Some(else_block); + self.block = Some(else_block); + + let zeros = + match name { + sym::ctlz => self.count_leading_zeroes(width, arg), + sym::cttz => self.count_trailing_zeroes(width, arg), + _ => unreachable!(), + }; + else_block.add_assignment(None, result, zeros); + else_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current blocks in the state need to be updated. + *self.current_block.borrow_mut() = Some(after_block); + self.block = Some(after_block); + + result.to_rvalue() + } + sym::ctlz_nonzero => { + self.count_leading_zeroes(width, args[0].immediate()) + }, + sym::cttz_nonzero => { + self.count_trailing_zeroes(width, args[0].immediate()) + } + sym::ctpop => self.pop_count(args[0].immediate()), + sym::bswap => { + if width == 8 { + args[0].immediate() // byte swap a u8/i8 is just a no-op + } + else { + // TODO(antoyo): check if it's faster to use string literals and a + // match instead of format!. + let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width)); + let mut arg = args[0].immediate(); + // FIXME(antoyo): this cast should not be necessary. Remove + // when having proper sized integer types. + let param_type = bswap.get_param(0).to_rvalue().get_type(); + if param_type != arg.get_type() { + arg = self.bitcast(arg, param_type); + } + self.cx.context.new_call(None, bswap, &[arg]) + } + }, + sym::bitreverse => self.bit_reverse(width, args[0].immediate()), + sym::rotate_left | sym::rotate_right => { + // TODO(antoyo): implement using algorithm from: + // https://blog.regehr.org/archives/1063 + // for other platforms. + let is_left = name == sym::rotate_left; + let val = args[0].immediate(); + let raw_shift = args[1].immediate(); + if is_left { + self.rotate_left(val, raw_shift, width) + } + else { + self.rotate_right(val, raw_shift, width) + } + }, + sym::saturating_add => { + self.saturating_add(args[0].immediate(), args[1].immediate(), signed, width) + }, + sym::saturating_sub => { + self.saturating_sub(args[0].immediate(), args[1].immediate(), signed, width) + }, + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + tcx.sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + return; + } + } + } + + sym::raw_eq => { + use rustc_target::abi::Abi::*; + let tp_ty = substs.type_at(0); + let layout = self.layout_of(tp_ty).layout; + let _use_integer_compare = match layout.abi { + Scalar(_) | ScalarPair(_, _) => true, + Uninhabited | Vector { .. } => false, + Aggregate { .. } => { + // For rusty ABIs, small aggregates are actually passed + // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), + // so we re-use that same threshold here. + layout.size <= self.data_layout().pointer_size * 2 + } + }; + + let a = args[0].immediate(); + let b = args[1].immediate(); + if layout.size.bytes() == 0 { + self.const_bool(true) + } + /*else if use_integer_compare { + let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits. + let ptr_ty = self.type_ptr_to(integer_ty); + let a_ptr = self.bitcast(a, ptr_ty); + let a_val = self.load(integer_ty, a_ptr, layout.align.abi); + let b_ptr = self.bitcast(b, ptr_ty); + let b_val = self.load(integer_ty, b_ptr, layout.align.abi); + self.icmp(IntPredicate::IntEQ, a_val, b_val) + }*/ + else { + let void_ptr_type = self.context.new_type::<*const ()>(); + let a_ptr = self.bitcast(a, void_ptr_type); + let b_ptr = self.bitcast(b, void_ptr_type); + let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type); + let builtin = self.context.get_builtin_function("memcmp"); + let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]); + self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)) + } + } + + sym::black_box => { + args[0].val.store(self, result); + + let block = self.llbb(); + let extended_asm = block.add_extended_asm(None, ""); + extended_asm.add_input_operand(None, "r", result.llval); + extended_asm.add_clobber("memory"); + extended_asm.set_volatile_flag(true); + + // We have copied the value to `result` already. + return; + } + + _ if name_str.starts_with("simd_") => { + match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { + Ok(llval) => llval, + Err(()) => return, + } + } + + _ => bug!("unknown intrinsic '{}'", name), + }; + + if !fn_abi.ret.is_ignore() { + if let PassMode::Cast(ty) = fn_abi.ret.mode { + let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); + let ptr = self.pointercast(result.llval, ptr_llty); + self.store(llval, ptr, result.align); + } + else { + OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) + .val + .store(self, result); + } + } + } + + fn abort(&mut self) { + let func = self.context.get_builtin_function("abort"); + let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; + self.call(self.type_void(), func, &[], None); + } + + fn assume(&mut self, value: Self::Value) { + // TODO(antoyo): switch to asumme when it exists. + // Or use something like this: + // #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0) + self.expect(value, true); + } + + fn expect(&mut self, cond: Self::Value, _expected: bool) -> Self::Value { + // TODO(antoyo) + cond + } + + fn sideeffect(&mut self) { + // TODO(antoyo) + } + + fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } +} + +impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn store_fn_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>) { + arg_abi.store_fn_arg(self, idx, dst) + } + + fn store_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) { + arg_abi.store(self, val, dst) + } + + fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { + arg_abi.memory_ty(self) + } +} + +pub trait ArgAbiExt<'gcc, 'tcx> { + fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; + fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>); + fn store_fn_arg(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>); +} + +impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { + /// Gets the LLVM type for a place of the original Rust type of + /// this argument/return, i.e., the result of `type_of::type_of`. + fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + self.layout.gcc_type(cx, true) + } + + /// Stores a direct/indirect value described by this ArgAbi into a + /// place for the original Rust type of this argument/return. + /// Can be used for both storing formal arguments into Rust variables + /// or results of call/invoke instructions into their destinations. + fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) { + if self.is_ignore() { + return; + } + if self.is_sized_indirect() { + OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) + } + else if self.is_unsized_indirect() { + bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); + } + else if let PassMode::Cast(cast) = self.mode { + // FIXME(eddyb): Figure out when the simpler Store is safe, clang + // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. + let can_store_through_cast_ptr = false; + if can_store_through_cast_ptr { + let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx)); + let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty); + bx.store(val, cast_dst, self.layout.align.abi); + } + else { + // The actual return type is a struct, but the ABI + // adaptation code has cast it into some scalar type. The + // code that follows is the only reliable way I have + // found to do a transform like i64 -> {i32,i32}. + // Basically we dump the data onto the stack then memcpy it. + // + // Other approaches I tried: + // - Casting rust ret pointer to the foreign type and using Store + // is (a) unsafe if size of foreign type > size of rust type and + // (b) runs afoul of strict aliasing rules, yielding invalid + // assembly under -O (specifically, the store gets removed). + // - Truncating foreign type to correct integral type and then + // bitcasting to the struct type yields invalid cast errors. + + // We instead thus allocate some scratch space... + let scratch_size = cast.size(bx); + let scratch_align = cast.align(bx); + let llscratch = bx.alloca(cast.gcc_type(bx), scratch_align); + bx.lifetime_start(llscratch, scratch_size); + + // ... where we first store the value... + bx.store(val, llscratch, scratch_align); + + // ... and then memcpy it to the intended destination. + bx.memcpy( + dst.llval, + self.layout.align.abi, + llscratch, + scratch_align, + bx.const_usize(self.layout.size.bytes()), + MemFlags::empty(), + ); + + bx.lifetime_end(llscratch, scratch_size); + } + } + else { + OperandValue::Immediate(val).store(bx, dst); + } + } + + fn store_fn_arg<'a>(&self, bx: &mut Builder<'a, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>) { + let mut next = || { + let val = bx.current_func().get_param(*idx as i32); + *idx += 1; + val.to_rvalue() + }; + match self.mode { + PassMode::Ignore => {} + PassMode::Pair(..) => { + OperandValue::Pair(next(), next()).store(bx, dst); + } + PassMode::Indirect { extra_attrs: Some(_), .. } => { + OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); + } + PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => { + let next_arg = next(); + self.store(bx, next_arg.to_rvalue(), dst); + } + } + } +} + +fn int_type_width_signed<'gcc, 'tcx>(ty: Ty<'tcx>, cx: &CodegenCx<'gcc, 'tcx>) -> Option<(u64, bool)> { + match ty.kind() { + ty::Int(t) => Some(( + match t { + rustc_middle::ty::IntTy::Isize => u64::from(cx.tcx.sess.target.pointer_width), + rustc_middle::ty::IntTy::I8 => 8, + rustc_middle::ty::IntTy::I16 => 16, + rustc_middle::ty::IntTy::I32 => 32, + rustc_middle::ty::IntTy::I64 => 64, + rustc_middle::ty::IntTy::I128 => 128, + }, + true, + )), + ty::Uint(t) => Some(( + match t { + rustc_middle::ty::UintTy::Usize => u64::from(cx.tcx.sess.target.pointer_width), + rustc_middle::ty::UintTy::U8 => 8, + rustc_middle::ty::UintTy::U16 => 16, + rustc_middle::ty::UintTy::U32 => 32, + rustc_middle::ty::UintTy::U64 => 64, + rustc_middle::ty::UintTy::U128 => 128, + }, + false, + )), + _ => None, + } +} + +impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { + fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> { + let result_type = value.get_type(); + let typ = result_type.to_unsigned(self.cx); + + let value = + if result_type.is_signed(self.cx) { + self.context.new_bitcast(None, value, typ) + } + else { + value + }; + + let context = &self.cx.context; + let result = + match width { + 8 => { + // First step. + let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0)); + let left = self.lshr(left, context.new_rvalue_from_int(typ, 4)); + let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F)); + let right = self.shl(right, context.new_rvalue_from_int(typ, 4)); + let step1 = self.or(left, right); + + // Second step. + let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC)); + let left = self.lshr(left, context.new_rvalue_from_int(typ, 2)); + let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33)); + let right = self.shl(right, context.new_rvalue_from_int(typ, 2)); + let step2 = self.or(left, right); + + // Third step. + let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA)); + let left = self.lshr(left, context.new_rvalue_from_int(typ, 1)); + let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55)); + let right = self.shl(right, context.new_rvalue_from_int(typ, 1)); + let step3 = self.or(left, right); + + step3 + }, + 16 => { + // First step. + let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555)); + let left = self.shl(left, context.new_rvalue_from_int(typ, 1)); + let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA)); + let right = self.lshr(right, context.new_rvalue_from_int(typ, 1)); + let step1 = self.or(left, right); + + // Second step. + let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333)); + let left = self.shl(left, context.new_rvalue_from_int(typ, 2)); + let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC)); + let right = self.lshr(right, context.new_rvalue_from_int(typ, 2)); + let step2 = self.or(left, right); + + // Third step. + let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F)); + let left = self.shl(left, context.new_rvalue_from_int(typ, 4)); + let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0)); + let right = self.lshr(right, context.new_rvalue_from_int(typ, 4)); + let step3 = self.or(left, right); + + // Fourth step. + let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF)); + let left = self.shl(left, context.new_rvalue_from_int(typ, 8)); + let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00)); + let right = self.lshr(right, context.new_rvalue_from_int(typ, 8)); + let step4 = self.or(left, right); + + step4 + }, + 32 => { + // TODO(antoyo): Refactor with other implementations. + // First step. + let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 1)); + let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 1)); + let step1 = self.or(left, right); + + // Second step. + let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 2)); + let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 2)); + let step2 = self.or(left, right); + + // Third step. + let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 4)); + let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 4)); + let step3 = self.or(left, right); + + // Fourth step. + let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 8)); + let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 8)); + let step4 = self.or(left, right); + + // Fifth step. + let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 16)); + let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 16)); + let step5 = self.or(left, right); + + step5 + }, + 64 => { + // First step. + let left = self.shl(value, context.new_rvalue_from_long(typ, 32)); + let right = self.lshr(value, context.new_rvalue_from_long(typ, 32)); + let step1 = self.or(left, right); + + // Second step. + let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 15)); + let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead? + let right = self.lshr(right, context.new_rvalue_from_long(typ, 17)); + let step2 = self.or(left, right); + + // Third step. + let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10)); + let left = self.xor(step2, left); + let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F)); + + let left = self.shl(temp, context.new_rvalue_from_long(typ, 10)); + let left = self.or(temp, left); + let step3 = self.xor(left, step2); + + // Fourth step. + let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4)); + let left = self.xor(step3, left); + let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421)); + + let left = self.shl(temp, context.new_rvalue_from_long(typ, 4)); + let left = self.or(temp, left); + let step4 = self.xor(left, step3); + + // Fifth step. + let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2)); + let left = self.xor(step4, left); + let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842)); + + let left = self.shl(temp, context.new_rvalue_from_long(typ, 2)); + let left = self.or(temp, left); + let step5 = self.xor(left, step4); + + step5 + }, + 128 => { + // TODO(antoyo): find a more efficient implementation? + let sixty_four = self.context.new_rvalue_from_long(typ, 64); + let high = self.context.new_cast(None, value >> sixty_four, self.u64_type); + let low = self.context.new_cast(None, value, self.u64_type); + + let reversed_high = self.bit_reverse(64, high); + let reversed_low = self.bit_reverse(64, low); + + let new_low = self.context.new_cast(None, reversed_high, typ); + let new_high = self.context.new_cast(None, reversed_low, typ) << sixty_four; + + new_low | new_high + }, + _ => { + panic!("cannot bit reverse with width = {}", width); + }, + }; + + self.context.new_bitcast(None, result, result_type) + } + + fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use width? + let arg_type = arg.get_type(); + let count_leading_zeroes = + if arg_type.is_uint(&self.cx) { + "__builtin_clz" + } + else if arg_type.is_ulong(&self.cx) { + "__builtin_clzl" + } + else if arg_type.is_ulonglong(&self.cx) { + "__builtin_clzll" + } + else if width == 128 { + // Algorithm from: https://stackoverflow.com/a/28433850/389119 + let array_type = self.context.new_array_type(None, arg_type, 3); + let result = self.current_func() + .new_local(None, array_type, "count_loading_zeroes_results"); + + let sixty_four = self.context.new_rvalue_from_long(arg_type, 64); + let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type); + let low = self.context.new_cast(None, arg, self.u64_type); + + let zero = self.context.new_rvalue_zero(self.usize_type); + let one = self.context.new_rvalue_one(self.usize_type); + let two = self.context.new_rvalue_from_long(self.usize_type, 2); + + let clzll = self.context.get_builtin_function("__builtin_clzll"); + + let first_elem = self.context.new_array_access(None, result, zero); + let first_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[high]), arg_type); + self.llbb() + .add_assignment(None, first_elem, first_value); + + let second_elem = self.context.new_array_access(None, result, one); + let second_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[low]), arg_type) + sixty_four; + self.llbb() + .add_assignment(None, second_elem, second_value); + + let third_elem = self.context.new_array_access(None, result, two); + let third_value = self.context.new_rvalue_from_long(arg_type, 128); + self.llbb() + .add_assignment(None, third_elem, third_value); + + let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); + let not_low_and_not_high = not_low & not_high; + let index = not_high + not_low_and_not_high; + + let res = self.context.new_array_access(None, result, index); + + return self.context.new_cast(None, res, arg_type); + } + else { + let count_leading_zeroes = self.context.get_builtin_function("__builtin_clz"); + let arg = self.context.new_cast(None, arg, self.uint_type); + let diff = self.int_width(self.uint_type) - self.int_width(arg_type); + let diff = self.context.new_rvalue_from_long(self.int_type, diff); + let res = self.context.new_call(None, count_leading_zeroes, &[arg]) - diff; + return self.context.new_cast(None, res, arg_type); + }; + let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes); + let res = self.context.new_call(None, count_leading_zeroes, &[arg]); + self.context.new_cast(None, res, arg_type) + } + + fn count_trailing_zeroes(&self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + let result_type = arg.get_type(); + let arg = + if result_type.is_signed(self.cx) { + let new_type = result_type.to_unsigned(self.cx); + self.context.new_bitcast(None, arg, new_type) + } + else { + arg + }; + let arg_type = arg.get_type(); + let (count_trailing_zeroes, expected_type) = + if arg_type.is_uchar(&self.cx) || arg_type.is_ushort(&self.cx) || arg_type.is_uint(&self.cx) { + // NOTE: we don't need to & 0xFF for uchar because the result is undefined on zero. + ("__builtin_ctz", self.cx.uint_type) + } + else if arg_type.is_ulong(&self.cx) { + ("__builtin_ctzl", self.cx.ulong_type) + } + else if arg_type.is_ulonglong(&self.cx) { + ("__builtin_ctzll", self.cx.ulonglong_type) + } + else if arg_type.is_u128(&self.cx) { + // Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119 + let array_type = self.context.new_array_type(None, arg_type, 3); + let result = self.current_func() + .new_local(None, array_type, "count_loading_zeroes_results"); + + let sixty_four = self.context.new_rvalue_from_long(arg_type, 64); + let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type); + let low = self.context.new_cast(None, arg, self.u64_type); + + let zero = self.context.new_rvalue_zero(self.usize_type); + let one = self.context.new_rvalue_one(self.usize_type); + let two = self.context.new_rvalue_from_long(self.usize_type, 2); + + let ctzll = self.context.get_builtin_function("__builtin_ctzll"); + + let first_elem = self.context.new_array_access(None, result, zero); + let first_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[low]), arg_type); + self.llbb() + .add_assignment(None, first_elem, first_value); + + let second_elem = self.context.new_array_access(None, result, one); + let second_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[high]), arg_type) + sixty_four; + self.llbb() + .add_assignment(None, second_elem, second_value); + + let third_elem = self.context.new_array_access(None, result, two); + let third_value = self.context.new_rvalue_from_long(arg_type, 128); + self.llbb() + .add_assignment(None, third_elem, third_value); + + let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); + let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low_and_not_high = not_low & not_high; + let index = not_low + not_low_and_not_high; + + let res = self.context.new_array_access(None, result, index); + + return self.context.new_bitcast(None, res, result_type); + } + else { + unimplemented!("count_trailing_zeroes for {:?}", arg_type); + }; + let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes); + let arg = + if arg_type != expected_type { + self.context.new_cast(None, arg, expected_type) + } + else { + arg + }; + let res = self.context.new_call(None, count_trailing_zeroes, &[arg]); + self.context.new_bitcast(None, res, result_type) + } + + fn int_width(&self, typ: Type<'gcc>) -> i64 { + self.cx.int_width(typ) as i64 + } + + fn pop_count(&self, value: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use the optimized version with fewer operations. + let result_type = value.get_type(); + let value_type = result_type.to_unsigned(self.cx); + + let value = + if result_type.is_signed(self.cx) { + self.context.new_bitcast(None, value, value_type) + } + else { + value + }; + + if value_type.is_u128(&self.cx) { + // TODO(antoyo): implement in the normal algorithm below to have a more efficient + // implementation (that does not require a call to __popcountdi2). + let popcount = self.context.get_builtin_function("__builtin_popcountll"); + let sixty_four = self.context.new_rvalue_from_long(value_type, 64); + let high = self.context.new_cast(None, value >> sixty_four, self.cx.ulonglong_type); + let high = self.context.new_call(None, popcount, &[high]); + let low = self.context.new_cast(None, value, self.cx.ulonglong_type); + let low = self.context.new_call(None, popcount, &[low]); + let res = high + low; + return self.context.new_bitcast(None, res, result_type); + } + + // First step. + let mask = self.context.new_rvalue_from_long(value_type, 0x5555555555555555); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 1); + let right = shifted & mask; + let value = left + right; + + // Second step. + let mask = self.context.new_rvalue_from_long(value_type, 0x3333333333333333); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 2); + let right = shifted & mask; + let value = left + right; + + // Third step. + let mask = self.context.new_rvalue_from_long(value_type, 0x0F0F0F0F0F0F0F0F); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 4); + let right = shifted & mask; + let value = left + right; + + if value_type.is_u8(&self.cx) { + return self.context.new_bitcast(None, value, result_type); + } + + // Fourth step. + let mask = self.context.new_rvalue_from_long(value_type, 0x00FF00FF00FF00FF); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 8); + let right = shifted & mask; + let value = left + right; + + if value_type.is_u16(&self.cx) { + return self.context.new_bitcast(None, value, result_type); + } + + // Fifth step. + let mask = self.context.new_rvalue_from_long(value_type, 0x0000FFFF0000FFFF); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 16); + let right = shifted & mask; + let value = left + right; + + if value_type.is_u32(&self.cx) { + return self.context.new_bitcast(None, value, result_type); + } + + // Sixth step. + let mask = self.context.new_rvalue_from_long(value_type, 0x00000000FFFFFFFF); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 32); + let right = shifted & mask; + let value = left + right; + + self.context.new_bitcast(None, value, result_type) + } + + // Algorithm from: https://blog.regehr.org/archives/1063 + fn rotate_left(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> { + let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64); + let shift = shift % max; + let lhs = self.shl(value, shift); + let result_and = + self.and( + self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift), + self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1), + ); + let rhs = self.lshr(value, result_and); + self.or(lhs, rhs) + } + + // Algorithm from: https://blog.regehr.org/archives/1063 + fn rotate_right(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> { + let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64); + let shift = shift % max; + let lhs = self.lshr(value, shift); + let result_and = + self.and( + self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift), + self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1), + ); + let rhs = self.shl(value, result_and); + self.or(lhs, rhs) + } + + fn saturating_add(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> { + let func = self.current_func.borrow().expect("func"); + + if signed { + // Algorithm from: https://stackoverflow.com/a/56531252/389119 + let after_block = func.new_block("after"); + let func_name = + match width { + 8 => "__builtin_add_overflow", + 16 => "__builtin_add_overflow", + 32 => "__builtin_sadd_overflow", + 64 => "__builtin_saddll_overflow", + 128 => "__builtin_add_overflow", + _ => unreachable!(), + }; + let overflow_func = self.context.get_builtin_function(func_name); + let result_type = lhs.get_type(); + let res = func.new_local(None, result_type, "saturating_sum"); + let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None); + + let then_block = func.new_block("then"); + + let unsigned_type = self.context.new_int_type(width as i32 / 8, false); + let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1); + let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type, + self.context.new_rvalue_from_int(unsigned_type, 0) + ); + let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type); + then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type)); + then_block.end_with_jump(None, after_block); + + self.llbb().end_with_conditional(None, overflow, then_block, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current blocks in the state need to be updated. + *self.current_block.borrow_mut() = Some(after_block); + self.block = Some(after_block); + + res.to_rvalue() + } + else { + // Algorithm from: http://locklessinc.com/articles/sat_arithmetic/ + let res = lhs + rhs; + let res_type = res.get_type(); + let cond = self.context.new_comparison(None, ComparisonOp::LessThan, res, lhs); + let value = self.context.new_unary_op(None, UnaryOp::Minus, res_type, self.context.new_cast(None, cond, res_type)); + res | value + } + } + + // Algorithm from: https://locklessinc.com/articles/sat_arithmetic/ + fn saturating_sub(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> { + if signed { + // Also based on algorithm from: https://stackoverflow.com/a/56531252/389119 + let func_name = + match width { + 8 => "__builtin_sub_overflow", + 16 => "__builtin_sub_overflow", + 32 => "__builtin_ssub_overflow", + 64 => "__builtin_ssubll_overflow", + 128 => "__builtin_sub_overflow", + _ => unreachable!(), + }; + let overflow_func = self.context.get_builtin_function(func_name); + let result_type = lhs.get_type(); + let func = self.current_func.borrow().expect("func"); + let res = func.new_local(None, result_type, "saturating_diff"); + let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None); + + let then_block = func.new_block("then"); + let after_block = func.new_block("after"); + + let unsigned_type = self.context.new_int_type(width as i32 / 8, false); + let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1); + let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type, + self.context.new_rvalue_from_int(unsigned_type, 0) + ); + let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type); + then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type)); + then_block.end_with_jump(None, after_block); + + self.llbb().end_with_conditional(None, overflow, then_block, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current blocks in the state need to be updated. + *self.current_block.borrow_mut() = Some(after_block); + self.block = Some(after_block); + + res.to_rvalue() + } + else { + let res = lhs - rhs; + let comparison = self.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs); + let comparison = self.context.new_cast(None, comparison, lhs.get_type()); + let unary_op = self.context.new_unary_op(None, UnaryOp::Minus, comparison.get_type(), comparison); + self.and(res, unary_op) + } + } +} + +fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) { + if bx.sess().panic_strategy() == PanicStrategy::Abort { + bx.call(bx.type_void(), try_func, &[data], None); + // Return 0 unconditionally from the intrinsic call; + // we can never unwind. + let ret_align = bx.tcx.data_layout.i32_align.abi; + bx.store(bx.const_i32(0), dest, ret_align); + } + else if wants_msvc_seh(bx.sess()) { + unimplemented!(); + } + else { + unimplemented!(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,167 @@ +use gccjit::{RValue, Type}; +use rustc_codegen_ssa::base::compare_simd_types; +use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error}; +use rustc_codegen_ssa::mir::operand::OperandRef; +use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; +use rustc_hir as hir; +use rustc_middle::span_bug; +use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{Span, Symbol, sym}; + +use crate::builder::Builder; + +pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result, ()> { + // macros for error handling: + macro_rules! emit_error { + ($msg: tt) => { + emit_error!($msg, ) + }; + ($msg: tt, $($fmt: tt)*) => { + span_invalid_monomorphization_error( + bx.sess(), span, + &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg), + name, $($fmt)*)); + } + } + + macro_rules! return_error { + ($($fmt: tt)*) => { + { + emit_error!($($fmt)*); + return Err(()); + } + } + } + + macro_rules! require { + ($cond: expr, $($fmt: tt)*) => { + if !$cond { + return_error!($($fmt)*); + } + }; + } + + macro_rules! require_simd { + ($ty: expr, $position: expr) => { + require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty) + }; + } + + let tcx = bx.tcx(); + let sig = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); + let arg_tys = sig.inputs(); + let name_str = &*name.as_str(); + + // every intrinsic below takes a SIMD vector as its first argument + require_simd!(arg_tys[0], "input"); + let in_ty = arg_tys[0]; + + let comparison = match name { + sym::simd_eq => Some(hir::BinOpKind::Eq), + sym::simd_ne => Some(hir::BinOpKind::Ne), + sym::simd_lt => Some(hir::BinOpKind::Lt), + sym::simd_le => Some(hir::BinOpKind::Le), + sym::simd_gt => Some(hir::BinOpKind::Gt), + sym::simd_ge => Some(hir::BinOpKind::Ge), + _ => None, + }; + + let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx()); + if let Some(cmp_op) = comparison { + require_simd!(ret_ty, "return"); + + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + require!( + bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, + "expected return type with integer elements, found `{}` with non-integer `{}`", + ret_ty, + out_ty + ); + + return Ok(compare_simd_types( + bx, + args[0].immediate(), + args[1].immediate(), + in_elem, + llret_ty, + cmp_op, + )); + } + + if let Some(stripped) = name_str.strip_prefix("simd_shuffle") { + let n: u64 = stripped.parse().unwrap_or_else(|_| { + span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") + }); + + require_simd!(ret_ty, "return"); + + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + out_len == n, + "expected return type of length {}, found `{}` with length {}", + n, + ret_ty, + out_len + ); + require!( + in_elem == out_ty, + "expected return element type `{}` (element of input `{}`), \ + found `{}` with element type `{}`", + in_elem, + in_ty, + ret_ty, + out_ty + ); + + let vector = args[2].immediate(); + + return Ok(bx.shuffle_vector( + args[0].immediate(), + args[1].immediate(), + vector, + )); + } + + macro_rules! arith_binary { + ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { + $(if name == sym::$name { + match in_elem.kind() { + $($(ty::$p(_))|* => { + return Ok(bx.$call(args[0].immediate(), args[1].immediate())) + })* + _ => {}, + } + require!(false, + "unsupported operation on `{}` with element `{}`", + in_ty, + in_elem) + })* + } + } + + arith_binary! { + simd_add: Uint, Int => add, Float => fadd; + simd_sub: Uint, Int => sub, Float => fsub; + simd_mul: Uint, Int => mul, Float => fmul; + simd_div: Uint => udiv, Int => sdiv, Float => fdiv; + simd_rem: Uint => urem, Int => srem, Float => frem; + simd_shl: Uint, Int => shl; + simd_shr: Uint => lshr, Int => ashr; + simd_and: Uint, Int => and; + simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors. + simd_xor: Uint, Int => xor; + } + + unimplemented!("simd {}", name); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,293 @@ +/* + * TODO(antoyo): support #[inline] attributes. + * TODO(antoyo): support LTO. + * + * TODO(antoyo): remove the patches. + */ + +#![feature(rustc_private, decl_macro, associated_type_bounds, never_type, trusted_len)] +#![allow(broken_intra_doc_links)] +#![recursion_limit="256"] +#![warn(rust_2018_idioms)] +#![warn(unused_lifetimes)] + +extern crate rustc_ast; +extern crate rustc_codegen_ssa; +extern crate rustc_data_structures; +extern crate rustc_errors; +extern crate rustc_hir; +extern crate rustc_metadata; +extern crate rustc_middle; +extern crate rustc_session; +extern crate rustc_span; +extern crate rustc_symbol_mangling; +extern crate rustc_target; +extern crate snap; + +// This prevents duplicating functions and statics that are already part of the host rustc process. +#[allow(unused_extern_crates)] +extern crate rustc_driver; + +mod abi; +mod allocator; +mod archive; +mod asm; +mod back; +mod base; +mod builder; +mod callee; +mod common; +mod consts; +mod context; +mod coverageinfo; +mod debuginfo; +mod declare; +mod intrinsic; +mod mono_item; +mod type_; +mod type_of; + +use std::any::Any; +use std::sync::Arc; + +use gccjit::{Context, OptimizationLevel}; +use rustc_ast::expand::allocator::AllocatorKind; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; +use rustc_codegen_ssa::base::codegen_crate; +use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn}; +use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::target_features::supported_target_features; +use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{ErrorReported, Handler}; +use rustc_metadata::EncodedMetadata; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::{Lto, OptLevel, OutputFilenames}; +use rustc_session::Session; +use rustc_span::Symbol; +use rustc_span::fatal_error::FatalError; + +pub struct PrintOnPanic String>(pub F); + +impl String> Drop for PrintOnPanic { + fn drop(&mut self) { + if ::std::thread::panicking() { + println!("{}", (self.0)()); + } + } +} + +#[derive(Clone)] +pub struct GccCodegenBackend; + +impl CodegenBackend for GccCodegenBackend { + fn init(&self, sess: &Session) { + if sess.lto() != Lto::No { + sess.warn("LTO is not supported. You may get a linker error."); + } + } + + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box { + let target_cpu = target_cpu(tcx.sess); + let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module); + + rustc_symbol_mangling::test::report_symbol_names(tcx); + + Box::new(res) + } + + fn join_codegen(&self, ongoing_codegen: Box, sess: &Session) -> Result<(CodegenResults, FxHashMap), ErrorReported> { + let (codegen_results, work_products) = ongoing_codegen + .downcast::>() + .expect("Expected GccCodegenBackend's OngoingCodegen, found Box") + .join(sess); + + Ok((codegen_results, work_products)) + } + + fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorReported> { + use rustc_codegen_ssa::back::link::link_binary; + + link_binary::>( + sess, + &codegen_results, + outputs, + ) + } + + fn target_features(&self, sess: &Session) -> Vec { + target_features(sess) + } +} + +impl ExtraBackendMethods for GccCodegenBackend { + fn new_metadata<'tcx>(&self, _tcx: TyCtxt<'tcx>, _mod_name: &str) -> Self::Module { + GccContext { + context: Context::default(), + } + } + + fn write_compressed_metadata<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut Self::Module) { + base::write_compressed_metadata(tcx, metadata, gcc_module) + } + + fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) { + unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) } + } + + fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen, u64) { + base::compile_codegen_unit(tcx, cgu_name) + } + + fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel) -> TargetMachineFactoryFn { + // TODO(antoyo): set opt level. + Arc::new(|_| { + Ok(()) + }) + } + + fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str { + unimplemented!(); + } + + fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> { + None + // TODO(antoyo) + } +} + +pub struct ModuleBuffer; + +impl ModuleBufferMethods for ModuleBuffer { + fn data(&self) -> &[u8] { + unimplemented!(); + } +} + +pub struct ThinBuffer; + +impl ThinBufferMethods for ThinBuffer { + fn data(&self) -> &[u8] { + unimplemented!(); + } +} + +pub struct GccContext { + context: Context<'static>, +} + +unsafe impl Send for GccContext {} +// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". Try to disable it here. +unsafe impl Sync for GccContext {} + +impl WriteBackendMethods for GccCodegenBackend { + type Module = GccContext; + type TargetMachine = (); + type ModuleBuffer = ModuleBuffer; + type Context = (); + type ThinData = (); + type ThinBuffer = ThinBuffer; + + fn run_fat_lto(_cgcx: &CodegenContext, mut modules: Vec>, _cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result, FatalError> { + // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins. + // NOTE: implemented elsewhere. + // TODO: what is implemented elsewhere ^ ? + let module = + match modules.remove(0) { + FatLTOInput::InMemory(module) => module, + FatLTOInput::Serialized { .. } => { + unimplemented!(); + } + }; + Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: vec![] }) + } + + fn run_thin_lto(_cgcx: &CodegenContext, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result<(Vec>, Vec), FatalError> { + unimplemented!(); + } + + fn print_pass_timings(&self) { + unimplemented!(); + } + + unsafe fn optimize(_cgcx: &CodegenContext, _diag_handler: &Handler, module: &ModuleCodegen, config: &ModuleConfig) -> Result<(), FatalError> { + module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); + Ok(()) + } + + unsafe fn optimize_thin(_cgcx: &CodegenContext, _thin: &mut ThinModule) -> Result, FatalError> { + unimplemented!(); + } + + unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &Handler, module: ModuleCodegen, config: &ModuleConfig) -> Result { + back::write::codegen(cgcx, diag_handler, module, config) + } + + fn prepare_thin(_module: ModuleCodegen) -> (String, Self::ThinBuffer) { + unimplemented!(); + } + + fn serialize_module(_module: ModuleCodegen) -> (String, Self::ModuleBuffer) { + unimplemented!(); + } + + fn run_lto_pass_manager(_cgcx: &CodegenContext, _module: &ModuleCodegen, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> { + // TODO(antoyo) + Ok(()) + } + + fn run_link(cgcx: &CodegenContext, diag_handler: &Handler, modules: Vec>) -> Result, FatalError> { + back::write::link(cgcx, diag_handler, modules) + } +} + +/// This is the entrypoint for a hot plugged rustc_codegen_gccjit +#[no_mangle] +pub fn __rustc_codegen_backend() -> Box { + Box::new(GccCodegenBackend) +} + +fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { + match optlevel { + None => OptimizationLevel::None, + Some(level) => { + match level { + OptLevel::No => OptimizationLevel::None, + OptLevel::Less => OptimizationLevel::Limited, + OptLevel::Default => OptimizationLevel::Standard, + OptLevel::Aggressive => OptimizationLevel::Aggressive, + OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited, + } + }, + } +} + +fn handle_native(name: &str) -> &str { + if name != "native" { + return name; + } + + unimplemented!(); +} + +pub fn target_cpu(sess: &Session) -> &str { + let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu); + handle_native(name) +} + +pub fn target_features(sess: &Session) -> Vec { + supported_target_features(sess) + .iter() + .filter_map( + |&(feature, gate)| { + if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } + }, + ) + .filter(|_feature| { + // TODO(antoyo): implement a way to get enabled feature in libgccjit. + false + }) + .map(|feature| Symbol::intern(feature)) + .collect() +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/mono_item.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/mono_item.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/mono_item.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/mono_item.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,38 @@ +use rustc_codegen_ssa::traits::PreDefineMethods; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::ty::{self, Instance, TypeFoldable}; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; +use rustc_span::def_id::DefId; + +use crate::base; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn predefine_static(&self, def_id: DefId, _linkage: Linkage, _visibility: Visibility, symbol_name: &str) { + let attrs = self.tcx.codegen_fn_attrs(def_id); + let instance = Instance::mono(self.tcx, def_id); + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let gcc_type = self.layout_of(ty).gcc_type(self, true); + + let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); + let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section); + + // TODO(antoyo): set linkage and visibility. + self.instances.borrow_mut().insert(instance, global); + } + + fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, _visibility: Visibility, symbol_name: &str) { + assert!(!instance.substs.needs_infer()); + + let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); + self.linkage.set(base::linkage_to_gcc(linkage)); + let _decl = self.declare_fn(symbol_name, &fn_abi); + //let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); + + // TODO(antoyo): call set_link_section() to allow initializing argc/argv. + // TODO(antoyo): set unique comdat. + // TODO(antoyo): use inline attribute from there in linkage.set() above. + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/type_of.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/type_of.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/type_of.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/type_of.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,359 @@ +use std::fmt::Write; + +use gccjit::{Struct, Type}; +use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; +use rustc_middle::bug; +use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; +use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; + +use crate::abi::{FnAbiGccExt, GccType}; +use crate::context::CodegenCx; +use crate::type_::struct_fields; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + fn type_from_unsigned_integer(&self, i: Integer) -> Type<'gcc> { + use Integer::*; + match i { + I8 => self.type_u8(), + I16 => self.type_u16(), + I32 => self.type_u32(), + I64 => self.type_u64(), + I128 => self.type_u128(), + } + } +} + +pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> { + match layout.abi { + Abi::Scalar(_) => bug!("handled elsewhere"), + Abi::Vector { ref element, count } => { + let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO); + return cx.context.new_vector_type(element, count); + }, + Abi::ScalarPair(..) => { + return cx.type_struct( + &[ + layout.scalar_pair_element_gcc_type(cx, 0, false), + layout.scalar_pair_element_gcc_type(cx, 1, false), + ], + false, + ); + } + Abi::Uninhabited | Abi::Aggregate { .. } => {} + } + + let name = match layout.ty.kind() { + // FIXME(eddyb) producing readable type names for trait objects can result + // in problematically distinct types due to HRTB and subtyping (see #47638). + // ty::Dynamic(..) | + ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str + if !cx.sess().fewer_names() => + { + let mut name = with_no_trimmed_paths(|| layout.ty.to_string()); + if let (&ty::Adt(def, _), &Variants::Single { index }) = + (layout.ty.kind(), &layout.variants) + { + if def.is_enum() && !def.variants.is_empty() { + write!(&mut name, "::{}", def.variants[index].ident).unwrap(); + } + } + if let (&ty::Generator(_, _, _), &Variants::Single { index }) = + (layout.ty.kind(), &layout.variants) + { + write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap(); + } + Some(name) + } + ty::Adt(..) => { + // If `Some` is returned then a named struct is created in LLVM. Name collisions are + // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that + // can improve perf. + // FIXME(antoyo): I don't think that's true for libgccjit. + Some(String::new()) + } + _ => None, + }; + + match layout.fields { + FieldsShape::Primitive | FieldsShape::Union(_) => { + let fill = cx.type_padding_filler(layout.size, layout.align.abi); + let packed = false; + match name { + None => cx.type_struct(&[fill], packed), + Some(ref name) => { + let gcc_type = cx.type_named_struct(name); + cx.set_struct_body(gcc_type, &[fill], packed); + gcc_type.as_type() + }, + } + } + FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx, true), count), + FieldsShape::Arbitrary { .. } => + match name { + None => { + let (gcc_fields, packed) = struct_fields(cx, layout); + cx.type_struct(&gcc_fields, packed) + }, + Some(ref name) => { + let gcc_type = cx.type_named_struct(name); + *defer = Some((gcc_type, layout)); + gcc_type.as_type() + }, + }, + } +} + +pub trait LayoutGccExt<'tcx> { + fn is_gcc_immediate(&self) -> bool; + fn is_gcc_scalar_pair(&self) -> bool; + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc>; + fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; + fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>; + fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>; + fn gcc_field_index(&self, index: usize) -> u64; + fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option; +} + +impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { + fn is_gcc_immediate(&self) -> bool { + match self.abi { + Abi::Scalar(_) | Abi::Vector { .. } => true, + Abi::ScalarPair(..) => false, + Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(), + } + } + + fn is_gcc_scalar_pair(&self) -> bool { + match self.abi { + Abi::ScalarPair(..) => true, + Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + } + } + + /// Gets the GCC type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`. + /// The pointee type of the pointer in `PlaceRef` is always this type. + /// For sized types, it is also the right LLVM type for an `alloca` + /// containing a value of that type, and most immediates (except `bool`). + /// Unsized types, however, are represented by a "minimal unit", e.g. + /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this + /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. + /// If the type is an unsized struct, the regular layout is generated, + /// with the inner-most trailing unsized field using the "minimal unit" + /// of that field's type - this is useful for taking the address of + /// that field and ensuring the struct has the right alignment. + //TODO(antoyo): do we still need the set_fields parameter? + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc> { + if let Abi::Scalar(ref scalar) = self.abi { + // Use a different cache for scalars because pointers to DSTs + // can be either fat or thin (data pointers of fat pointers). + if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { + return ty; + } + let ty = + match *self.ty.kind() { + ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { + cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx, set_fields)) + } + ty::Adt(def, _) if def.is_box() => { + cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx, true)) + } + ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())), + _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), + }; + cx.scalar_types.borrow_mut().insert(self.ty, ty); + return ty; + } + + // Check the cache. + let variant_index = + match self.variants { + Variants::Single { index } => Some(index), + _ => None, + }; + let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned(); + if let Some(ty) = cached_type { + let type_to_set_fields = cx.types_with_fields_to_set.borrow_mut().remove(&ty); + if let Some((struct_type, layout)) = type_to_set_fields { + // Since we might be trying to generate a type containing another type which is not + // completely generated yet, we deferred setting the fields until now. + let (fields, packed) = struct_fields(cx, layout); + cx.set_struct_body(struct_type, &fields, packed); + } + return ty; + } + + assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty); + + // Make sure lifetimes are erased, to avoid generating distinct LLVM + // types for Rust types that only differ in the choice of lifetimes. + let normal_ty = cx.tcx.erase_regions(self.ty); + + let mut defer = None; + let ty = + if self.ty != normal_ty { + let mut layout = cx.layout_of(normal_ty); + if let Some(v) = variant_index { + layout = layout.for_variant(cx, v); + } + layout.gcc_type(cx, true) + } + else { + uncached_gcc_type(cx, *self, &mut defer) + }; + + cx.types.borrow_mut().insert((self.ty, variant_index), ty); + + if let Some((ty, layout)) = defer { + let (fields, packed) = struct_fields(cx, layout); + cx.set_struct_body(ty, &fields, packed); + } + + ty + } + + fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + if let Abi::Scalar(ref scalar) = self.abi { + if scalar.is_bool() { + return cx.type_i1(); + } + } + self.gcc_type(cx, true) + } + + fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> { + match scalar.value { + Int(i, true) => cx.type_from_integer(i), + Int(i, false) => cx.type_from_unsigned_integer(i), + F32 => cx.type_f32(), + F64 => cx.type_f64(), + Pointer => { + // If we know the alignment, pick something better than i8. + let pointee = + if let Some(pointee) = self.pointee_info_at(cx, offset) { + cx.type_pointee_for_align(pointee.align) + } + else { + cx.type_i8() + }; + cx.type_ptr_to(pointee) + } + } + } + + fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc> { + // TODO(antoyo): remove llvm hack: + // HACK(eddyb) special-case fat pointers until LLVM removes + // pointee types, to avoid bitcasting every `OperandRef::deref`. + match self.ty.kind() { + ty::Ref(..) | ty::RawPtr(_) => { + return self.field(cx, index).gcc_type(cx, true); + } + ty::Adt(def, _) if def.is_box() => { + let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); + return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate); + } + _ => {} + } + + let (a, b) = match self.abi { + Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self), + }; + let scalar = [a, b][index]; + + // Make sure to return the same type `immediate_gcc_type` would when + // dealing with an immediate pair. This means that `(bool, bool)` is + // effectively represented as `{i8, i8}` in memory and two `i1`s as an + // immediate, just like `bool` is typically `i8` in memory and only `i1` + // when immediate. We need to load/store `bool` as `i8` to avoid + // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. + // TODO(antoyo): this bugs certainly don't happen in this case since the bool type is used instead of i1. + if scalar.is_bool() { + return cx.type_i1(); + } + + let offset = + if index == 0 { + Size::ZERO + } + else { + a.value.size(cx).align_to(b.value.align(cx).abi) + }; + self.scalar_gcc_type_at(cx, scalar, offset) + } + + fn gcc_field_index(&self, index: usize) -> u64 { + match self.abi { + Abi::Scalar(_) | Abi::ScalarPair(..) => { + bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self) + } + _ => {} + } + match self.fields { + FieldsShape::Primitive | FieldsShape::Union(_) => { + bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self) + } + + FieldsShape::Array { .. } => index as u64, + + FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2, + } + } + + fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option { + if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) { + return pointee; + } + + let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset); + + cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); + result + } +} + +impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> { + layout.gcc_type(self, true) + } + + fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> { + layout.immediate_gcc_type(self) + } + + fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool { + layout.is_gcc_immediate() + } + + fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool { + layout.is_gcc_scalar_pair() + } + + fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 { + layout.gcc_field_index(index) + } + + fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool) -> Type<'gcc> { + layout.scalar_pair_element_gcc_type(self, index, immediate) + } + + fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> { + ty.gcc_type(self) + } + + fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { + fn_abi.ptr_to_gcc_type(self) + } + + fn reg_backend_type(&self, _ty: &Reg) -> Type<'gcc> { + unimplemented!(); + } + + fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { + // FIXME(antoyo): return correct type. + self.type_void() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/type_.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/type_.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/type_.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/src/type_.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,282 @@ +use std::convert::TryInto; + +use gccjit::{RValue, Struct, Type}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods}; +use rustc_codegen_ssa::common::TypeKind; +use rustc_middle::bug; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_target::abi::{AddressSpace, Align, Integer, Size}; + +use crate::common::TypeReflection; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn type_ix(&self, num_bits: u64) -> Type<'gcc> { + // gcc only supports 1, 2, 4 or 8-byte integers. + // FIXME(antoyo): this is misleading to use the next power of two as rustc_codegen_ssa + // sometimes use 96-bit numbers and the following code will give an integer of a different + // size. + let bytes = (num_bits / 8).next_power_of_two() as i32; + match bytes { + 1 => self.i8_type, + 2 => self.i16_type, + 4 => self.i32_type, + 8 => self.i64_type, + 16 => self.i128_type, + _ => panic!("unexpected num_bits: {}", num_bits), + } + } + + pub fn type_void(&self) -> Type<'gcc> { + self.context.new_type::<()>() + } + + pub fn type_size_t(&self) -> Type<'gcc> { + self.context.new_type::() + } + + pub fn type_u8(&self) -> Type<'gcc> { + self.u8_type + } + + pub fn type_u16(&self) -> Type<'gcc> { + self.u16_type + } + + pub fn type_u32(&self) -> Type<'gcc> { + self.u32_type + } + + pub fn type_u64(&self) -> Type<'gcc> { + self.u64_type + } + + pub fn type_u128(&self) -> Type<'gcc> { + self.u128_type + } + + pub fn type_pointee_for_align(&self, align: Align) -> Type<'gcc> { + // FIXME(eddyb) We could find a better approximation if ity.align < align. + let ity = Integer::approximate_align(self, align); + self.type_from_integer(ity) + } +} + +impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn type_i1(&self) -> Type<'gcc> { + self.bool_type + } + + fn type_i8(&self) -> Type<'gcc> { + self.i8_type + } + + fn type_i16(&self) -> Type<'gcc> { + self.i16_type + } + + fn type_i32(&self) -> Type<'gcc> { + self.i32_type + } + + fn type_i64(&self) -> Type<'gcc> { + self.i64_type + } + + fn type_i128(&self) -> Type<'gcc> { + self.i128_type + } + + fn type_isize(&self) -> Type<'gcc> { + self.isize_type + } + + fn type_f32(&self) -> Type<'gcc> { + self.context.new_type::() + } + + fn type_f64(&self) -> Type<'gcc> { + self.context.new_type::() + } + + fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> { + self.context.new_function_pointer_type(None, return_type, params, false) + } + + fn type_struct(&self, fields: &[Type<'gcc>], _packed: bool) -> Type<'gcc> { + let types = fields.to_vec(); + if let Some(typ) = self.struct_types.borrow().get(fields) { + return typ.clone(); + } + let fields: Vec<_> = fields.iter().enumerate() + .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index))) + .collect(); + // TODO(antoyo): use packed. + let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); + self.struct_types.borrow_mut().insert(types, typ); + typ + } + + fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { + if typ.is_integral() { + TypeKind::Integer + } + else if typ.is_vector().is_some() { + TypeKind::Vector + } + else { + // TODO(antoyo): support other types. + TypeKind::Void + } + } + + fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> { + ty.make_pointer() + } + + fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> { + // TODO(antoyo): use address_space + ty.make_pointer() + } + + fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> { + if let Some(typ) = ty.is_array() { + typ + } + else if let Some(vector_type) = ty.is_vector() { + vector_type.get_element_type() + } + else if let Some(typ) = ty.get_pointee() { + typ + } + else { + unreachable!() + } + } + + fn vector_length(&self, _ty: Type<'gcc>) -> usize { + unimplemented!(); + } + + fn float_width(&self, typ: Type<'gcc>) -> usize { + let f32 = self.context.new_type::(); + let f64 = self.context.new_type::(); + if typ == f32 { + 32 + } + else if typ == f64 { + 64 + } + else { + panic!("Cannot get width of float type {:?}", typ); + } + // TODO(antoyo): support other sizes. + } + + fn int_width(&self, typ: Type<'gcc>) -> u64 { + if typ.is_i8(self) || typ.is_u8(self) { + 8 + } + else if typ.is_i16(self) || typ.is_u16(self) { + 16 + } + else if typ.is_i32(self) || typ.is_u32(self) { + 32 + } + else if typ.is_i64(self) || typ.is_u64(self) { + 64 + } + else if typ.is_i128(self) || typ.is_u128(self) { + 128 + } + else { + panic!("Cannot get width of int type {:?}", typ); + } + } + + fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> { + value.get_type() + } +} + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn type_padding_filler(&self, size: Size, align: Align) -> Type<'gcc> { + let unit = Integer::approximate_align(self, align); + let size = size.bytes(); + let unit_size = unit.size().bytes(); + assert_eq!(size % unit_size, 0); + self.type_array(self.type_from_integer(unit), size / unit_size) + } + + pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], _packed: bool) { + // TODO(antoyo): use packed. + let fields: Vec<_> = fields.iter().enumerate() + .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index))) + .collect(); + typ.set_fields(None, &fields); + } + + pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> { + self.context.new_opaque_struct_type(None, name) + } + + pub fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { + if let Some(struct_type) = ty.is_struct() { + if struct_type.get_field_count() == 0 { + // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a + // size of usize::MAX in test_binary_search, we workaround this by setting the size to + // zero for ZSTs. + // FIXME(antoyo): fix gccjit API. + len = 0; + } + } + + // NOTE: see note above. Some other test uses usize::MAX. + if len == u64::MAX { + len = 0; + } + + let len: i32 = len.try_into().expect("array len"); + + self.context.new_array_type(None, ty, len) + } +} + +pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec>, bool) { + let field_count = layout.fields.count(); + + let mut packed = false; + let mut offset = Size::ZERO; + let mut prev_effective_align = layout.align.abi; + let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2); + for i in layout.fields.index_by_increasing_offset() { + let target_offset = layout.fields.offset(i as usize); + let field = layout.field(cx, i); + let effective_field_align = + layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset); + packed |= effective_field_align < field.align.abi; + + assert!(target_offset >= offset); + let padding = target_offset - offset; + let padding_align = prev_effective_align.min(effective_field_align); + assert_eq!(offset.align_to(padding_align) + padding, target_offset); + result.push(cx.type_padding_filler(padding, padding_align)); + + result.push(field.gcc_type(cx, !field.ty.is_any_ptr())); // FIXME(antoyo): might need to check if the type is inside another, like Box. + offset = target_offset + field.size; + prev_effective_align = effective_field_align; + } + if !layout.is_unsized() && field_count > 0 { + if offset > layout.size { + bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset); + } + let padding = layout.size - offset; + let padding_align = prev_effective_align; + assert_eq!(offset.align_to(padding_align) + padding, layout.size); + result.push(cx.type_padding_filler(padding, padding_align)); + assert_eq!(result.len(), 1 + field_count * 2); + } + + (result, packed) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,50 @@ +use std::{ + env::{self, current_dir}, + path::PathBuf, + process::Command, +}; + +use lang_tester::LangTester; +use tempfile::TempDir; + +fn main() { + let tempdir = TempDir::new().expect("temp dir"); + let current_dir = current_dir().expect("current dir"); + let current_dir = current_dir.to_str().expect("current dir").to_string(); + let gcc_path = include_str!("../gcc_path"); + let gcc_path = gcc_path.trim(); + env::set_var("LD_LIBRARY_PATH", gcc_path); + LangTester::new() + .test_dir("tests/run") + .test_file_filter(|path| path.extension().expect("extension").to_str().expect("to_str") == "rs") + .test_extract(|source| { + let lines = + source.lines() + .skip_while(|l| !l.starts_with("//")) + .take_while(|l| l.starts_with("//")) + .map(|l| &l[2..]) + .collect::>() + .join("\n"); + Some(lines) + }) + .test_cmds(move |path| { + // Test command 1: Compile `x.rs` into `tempdir/x`. + let mut exe = PathBuf::new(); + exe.push(&tempdir); + exe.push(path.file_stem().expect("file_stem")); + let mut compiler = Command::new("rustc"); + compiler.args(&[ + &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir), + "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir), + "-Zno-parallel-llvm", + "-C", "panic=abort", + "-C", "link-arg=-lc", + "-o", exe.to_str().expect("to_str"), + path.to_str().expect("to_str"), + ]); + // Test command 2: run `tempdir/x`. + let runtime = Command::new(exe); + vec![("Compiler", compiler), ("Run-time", runtime)] + }) + .run(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/abort1.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/abort1.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/abort1.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/abort1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +// Compiler: +// +// Run-time: +// status: signal + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod intrinsics { + use super::Sized; + + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +/* + * Code + */ + +fn test_fail() -> ! { + unsafe { intrinsics::abort() }; +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + test_fail(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/abort2.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/abort2.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/abort2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/abort2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,53 @@ +// Compiler: +// +// Run-time: +// status: signal + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod intrinsics { + use super::Sized; + + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +/* + * Code + */ + +fn fail() -> i32 { + unsafe { intrinsics::abort() }; + 0 +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + fail(); + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/array.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/array.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/array.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/array.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,229 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 42 +// 7 +// 5 +// 10 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i16 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + + +/* + * Code + */ + +static mut ONE: usize = 1; + +fn make_array() -> [u8; 3] { + [42, 10, 5] +} + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + let array = [42, 7, 5]; + let array2 = make_array(); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE - 1]); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE]); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE + 1]); + + libc::printf(b"%d\n\0" as *const u8 as *const i8, array2[argc as usize] as u32); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/asm.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/asm.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/asm.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/asm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,153 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(asm, global_asm)] + +global_asm!(" + .global add_asm +add_asm: + mov rax, rdi + add rax, rsi + ret" +); + +extern "C" { + fn add_asm(a: i64, b: i64) -> i64; +} + +fn main() { + unsafe { + asm!("nop"); + } + + let x: u64; + unsafe { + asm!("mov $5, {}", + out(reg) x, + options(att_syntax) + ); + } + assert_eq!(x, 5); + + let x: u64; + let input: u64 = 42; + unsafe { + asm!("mov {input}, {output}", + "add $1, {output}", + input = in(reg) input, + output = out(reg) x, + options(att_syntax) + ); + } + assert_eq!(x, 43); + + let x: u64; + unsafe { + asm!("mov {}, 6", + out(reg) x, + ); + } + assert_eq!(x, 6); + + let x: u64; + let input: u64 = 42; + unsafe { + asm!("mov {output}, {input}", + "add {output}, 1", + input = in(reg) input, + output = out(reg) x, + ); + } + assert_eq!(x, 43); + + // check inout(reg_class) x + let mut x: u64 = 42; + unsafe { + asm!("add {0}, {0}", + inout(reg) x + ); + } + assert_eq!(x, 84); + + // check inout("reg") x + let mut x: u64 = 42; + unsafe { + asm!("add r11, r11", + inout("r11") x + ); + } + assert_eq!(x, 84); + + // check a mix of + // in("reg") + // inout(class) x => y + // inout (class) x + let x: u64 = 702; + let y: u64 = 100; + let res: u64; + let mut rem: u64 = 0; + unsafe { + asm!("div r11", + in("r11") y, + inout("eax") x => res, + inout("edx") rem, + ); + } + assert_eq!(res, 7); + assert_eq!(rem, 2); + + // check const + let mut x: u64 = 42; + unsafe { + asm!("add {}, {}", + inout(reg) x, + const 1 + ); + } + assert_eq!(x, 43); + + // check const (ATT syntax) + let mut x: u64 = 42; + unsafe { + asm!("add {}, {}", + const 1, + inout(reg) x, + options(att_syntax) + ); + } + assert_eq!(x, 43); + + // check sym fn + extern "C" fn foo() -> u64 { 42 } + let x: u64; + unsafe { + asm!("call {}", sym foo, lateout("rax") x); + } + assert_eq!(x, 42); + + // check sym fn (ATT syntax) + let x: u64; + unsafe { + asm!("call {}", sym foo, lateout("rax") x, options(att_syntax)); + } + assert_eq!(x, 42); + + // check sym static + static FOO: u64 = 42; + let x: u64; + unsafe { + asm!("mov {1}, qword ptr [rip + {0}]", sym FOO, lateout(reg) x); + } + assert_eq!(x, 42); + + // check sym static (ATT syntax) + let x: u64; + unsafe { + asm!("movq {0}(%rip), {1}", sym FOO, lateout(reg) x, options(att_syntax)); + } + assert_eq!(x, 42); + + assert_eq!(unsafe { add_asm(40, 2) }, 42); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/assign.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/assign.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/assign.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/assign.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,153 @@ +// Compiler: +// +// Run-time: +// stdout: 2 +// 7 8 +// 10 + +#![allow(unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for *mut i32 {} +impl Copy for usize {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i32 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn fflush(stream: *mut i32) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + + pub static STDOUT: *mut i32; + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + libc::fflush(libc::STDOUT); + intrinsics::abort(); + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +/* + * Code + */ + +fn inc_ref(num: &mut isize) -> isize { + *num = *num + 5; + *num + 1 +} + +fn inc(num: isize) -> isize { + num + 1 +} + + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + argc = inc(argc); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); + } + + let b = inc_ref(&mut argc); + unsafe { + libc::printf(b"%ld %ld\n\0" as *const u8 as *const i8, argc, b); + } + + argc = 10; + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/closure.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/closure.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/closure.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,230 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: Arg: 1 +// Argument: 1 +// String arg: 1 +// Int argument: 2 +// Both args: 11 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, + unboxed_closures)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u32 {} +impl Copy for u8 {} +impl Copy for i8 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "unsize"] +pub trait Unsize {} + +#[lang = "coerce_unsized"] +pub trait CoerceUnsized {} + +impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +#[lang = "fn_once"] +#[rustc_paren_sugar] +pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +#[lang = "fn_mut"] +#[rustc_paren_sugar] +pub trait FnMut: FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let string = "Arg: %d\n\0"; + let mut closure = || { + unsafe { + libc::printf(string as *const str as *const i8, argc); + } + }; + closure(); + + let mut closure = || { + unsafe { + libc::printf("Argument: %d\n\0" as *const str as *const i8, argc); + } + }; + closure(); + + let mut closure = |string| { + unsafe { + libc::printf(string as *const str as *const i8, argc); + } + }; + closure("String arg: %d\n\0"); + + let mut closure = |arg: isize| { + unsafe { + libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg); + } + }; + closure(argc + 1); + + let mut closure = |string, arg: isize| { + unsafe { + libc::printf(string as *const str as *const i8, arg); + } + }; + closure("Both args: %d\n\0", argc + 10); + + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/condition.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/condition.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/condition.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/condition.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,320 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: true +// 1 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for u64 {} +impl Copy for i32 {} +impl Copy for u32 {} +impl Copy for bool {} +impl Copy for u16 {} +impl Copy for i16 {} +impl Copy for char {} +impl Copy for i8 {} +impl Copy for u8 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +#[lang = "eq"] +pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + fn ne(&self, other: &Rhs) -> bool; +} + +impl PartialEq for u8 { + fn eq(&self, other: &u8) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u8) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for u16 { + fn eq(&self, other: &u16) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u16) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for u32 { + fn eq(&self, other: &u32) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u32) -> bool { + (*self) != (*other) + } +} + + +impl PartialEq for u64 { + fn eq(&self, other: &u64) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u64) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for usize { + fn eq(&self, other: &usize) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &usize) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for i8 { + fn eq(&self, other: &i8) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &i8) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &i32) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &i32) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for isize { + fn eq(&self, other: &isize) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &isize) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for char { + fn eq(&self, other: &char) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &char) -> bool { + (*self) != (*other) + } +} + +/* + * Code + */ + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + unsafe { + if argc == 1 { + libc::printf(b"true\n\0" as *const u8 as *const i8); + } + + let string = + match argc { + 1 => b"1\n\0", + 2 => b"2\n\0", + 3 => b"3\n\0", + 4 => b"4\n\0", + 5 => b"5\n\0", + _ => b"_\n\0", + }; + libc::printf(string as *const u8 as *const i8); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/empty_main.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/empty_main.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/empty_main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/empty_main.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(auto_traits, lang_items, no_core, start)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/exit_code.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/exit_code.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/exit_code.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/exit_code.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +// Compiler: +// +// Run-time: +// status: 1 + +#![feature(auto_traits, lang_items, no_core, start)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + 1 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/exit.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/exit.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/exit.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/exit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,49 @@ +// Compiler: +// +// Run-time: +// status: 2 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn exit(status: i32); + } +} + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + unsafe { + libc::exit(2); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,223 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 1 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i16 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + + +/* + * Code + */ + +fn i16_as_i8(a: i16) -> i8 { + a as i8 +} + +fn call_func(func: fn(i16) -> i8, param: i16) -> i8 { + func(param) +} + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let result = call_func(i16_as_i8, argc as i16) as isize; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, result); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,129 @@ +// Compiler: +// +// Run-time: +// stdout: Panicking +// status: signal + +#![allow(unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for *mut i32 {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u8 {} +impl Copy for i8 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn fflush(stream: *mut i32) -> i32; + + pub static STDOUT: *mut i32; + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + libc::fflush(libc::STDOUT); + intrinsics::abort(); + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let int = 9223372036854775807isize; + let int = int + argc; + int +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,165 @@ + +// Compiler: +// +// Run-time: +// stdout: 2 +// 7 +// 6 +// 11 + +#![allow(unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for *mut i32 {} +impl Copy for usize {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i32 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn fflush(stream: *mut i32) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + + pub static STDOUT: *mut i32; + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + libc::fflush(libc::STDOUT); + intrinsics::abort(); + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +/* + * Code + */ + +struct Test { + field: isize, +} + +fn test(num: isize) -> Test { + Test { + field: num + 1, + } +} + +fn update_num(num: &mut isize) { + *num = *num + 5; +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let mut test = test(argc); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); + } + update_num(&mut test.field); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); + } + + update_num(&mut argc); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); + } + + let refe = &mut argc; + *refe = *refe + 5; + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); + } + + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/operations.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/operations.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/operations.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/operations.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,221 @@ +// Compiler: +// +// Run-time: +// stdout: 41 +// 39 +// 10 + +#![allow(unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for *mut i32 {} +impl Copy for usize {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} + +#[lang = "deref"] +pub trait Deref { + type Target: ?Sized; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + pub fn fflush(stream: *mut i32) -> i32; + + pub static STDOUT: *mut i32; + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + libc::fflush(libc::STDOUT); + intrinsics::abort(); + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +#[lang = "mul"] +pub trait Mul { + type Output; + + #[must_use] + fn mul(self, rhs: RHS) -> Self::Output; +} + +impl Mul for u8 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +impl Mul for usize { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +impl Mul for isize { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, 10 * argc); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,222 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 1 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i16 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + + +/* + * Code + */ + +static mut ONE: usize = 1; + +fn make_array() -> [u8; 3] { + [42, 10, 5] +} + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let ptr = ONE as *mut usize; + let value = ptr as usize; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, value); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,72 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 10 +// 10 +// 42 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +#[lang = "copy"] +pub unsafe trait Copy {} + +unsafe impl Copy for bool {} +unsafe impl Copy for u8 {} +unsafe impl Copy for u16 {} +unsafe impl Copy for u32 {} +unsafe impl Copy for u64 {} +unsafe impl Copy for usize {} +unsafe impl Copy for i8 {} +unsafe impl Copy for i16 {} +unsafe impl Copy for i32 {} +unsafe impl Copy for isize {} +unsafe impl Copy for f32 {} +unsafe impl Copy for char {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +/* + * Code + */ + +fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) { + ( + a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8, + b as u32, + ) +} + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42); + unsafe { + libc::printf(b"%d\n\0" as *const u8 as *const i8, c); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, d); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, j); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/slice.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/slice.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/slice.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/slice.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,128 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 5 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u32 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "unsize"] +pub trait Unsize {} + +#[lang = "coerce_unsized"] +pub trait CoerceUnsized {} + +impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + use super::Sized; + + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +/* + * Code + */ + +static mut TWO: usize = 2; + +fn index_slice(s: &[u32]) -> u32 { + unsafe { + s[TWO] + } +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let array = [42, 7, 5]; + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array)); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/static.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/static.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/static.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/static.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,106 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 10 +// 14 +// 1 +// 12 +// 12 +// 1 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod intrinsics { + use super::Sized; + + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +#[lang = "structural_peq"] +pub trait StructuralPartialEq {} + +#[lang = "structural_teq"] +pub trait StructuralEq {} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +/* + * Code + */ + +struct Test { + field: isize, +} + +struct WithRef { + refe: &'static Test, +} + +static mut CONSTANT: isize = 10; + +static mut TEST: Test = Test { + field: 12, +}; + +static mut TEST2: Test = Test { + field: 14, +}; + +static mut WITH_REF: WithRef = WithRef { + refe: unsafe { &TEST }, +}; + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field); + TEST2.field = argc; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field); + WITH_REF.refe = &TEST2; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST.field); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/structs.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/structs.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/structs.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/structs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,70 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 1 +// 2 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +/* + * Code + */ + +struct Test { + field: isize, +} + +struct Two { + two: isize, +} + +fn one() -> isize { + 1 +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let test = Test { + field: one(), + }; + let two = Two { + two: 2, + }; + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, two.two); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/tuple.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/tuple.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/tuple.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/tests/run/tuple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 3 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let test: (isize, isize, isize) = (3, 1, 4); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0); + } + 0 +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/test.sh rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/test.sh --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_gcc/test.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_gcc/test.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,217 @@ +#!/bin/bash + +# TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed? + +set -e + +if [ -f ./gcc_path ]; then + export GCC_PATH=$(cat gcc_path) +else + echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' + exit 1 +fi + +export LD_LIBRARY_PATH="$GCC_PATH" +export LIBRARY_PATH="$GCC_PATH" + +if [[ "$1" == "--release" ]]; then + export CHANNEL='release' + CARGO_INCREMENTAL=1 cargo rustc --release + shift +else + echo $LD_LIBRARY_PATH + export CHANNEL='debug' + cargo rustc +fi + +source config.sh + +function clean() { + rm -r target/out || true + mkdir -p target/out/gccjit +} + +function mini_tests() { + echo "[BUILD] mini_core" + $RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target $TARGET_TRIPLE + + echo "[BUILD] example" + $RUSTC example/example.rs --crate-type lib --target $TARGET_TRIPLE + + echo "[AOT] mini_core_hello_world" + $RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd +} + +function build_sysroot() { + echo "[BUILD] sysroot" + time ./build_sysroot/build_sysroot.sh +} + +function std_tests() { + echo "[AOT] arbitrary_self_types_pointers_and_wrappers" + $RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers + + echo "[AOT] alloc_system" + $RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE" + + echo "[AOT] alloc_example" + $RUSTC example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/alloc_example + + echo "[AOT] dst_field_align" + # FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed. + $RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false) + + echo "[AOT] std_example" + $RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE + + echo "[AOT] subslice-patterns-const-eval" + $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/subslice-patterns-const-eval + + echo "[AOT] track-caller-attribute" + $RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/track-caller-attribute + + echo "[BUILD] mod_bench" + $RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE +} + +# FIXME(antoyo): linker gives multiple definitions error on Linux +#echo "[BUILD] sysroot in release mode" +#./build_sysroot/build_sysroot.sh --release + +# TODO(antoyo): uncomment when it works. +#pushd simple-raytracer +#if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then + #echo "[BENCH COMPILE] ebobby/simple-raytracer" + #hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "rm -r target/*/debug || true" \ + #"RUSTFLAGS='' cargo build --target $TARGET_TRIPLE" \ + #"../cargo.sh build" + + #echo "[BENCH RUN] ebobby/simple-raytracer" + #cp ./target/*/debug/main ./raytracer_cg_gccjit + #hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_gccjit +#else + #echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" + #echo "[COMPILE] ebobby/simple-raytracer" + #../cargo.sh build + #echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" +#fi +#popd + +function test_libcore() { + pushd build_sysroot/sysroot_src/library/core/tests + echo "[TEST] libcore" + rm -r ./target || true + ../../../../../cargo.sh test + popd +} + +# TODO(antoyo): uncomment when it works. +#pushd regex +#echo "[TEST] rust-lang/regex example shootout-regex-dna" +#../cargo.sh clean +## Make sure `[codegen mono items] start` doesn't poison the diff +#../cargo.sh build --example shootout-regex-dna +#cat examples/regexdna-input.txt | ../cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt +#diff -u res.txt examples/regexdna-output.txt + +#echo "[TEST] rust-lang/regex tests" +#../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options +#popd + +#echo +#echo "[BENCH COMPILE] mod_bench" + +#COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline" +#COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o target/out/mod_bench_llvm_0 -Cpanic=abort" +#COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o target/out/mod_bench_llvm_1 -Cpanic=abort" +#COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o target/out/mod_bench_llvm_2 -Cpanic=abort" +#COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o target/out/mod_bench_llvm_3 -Cpanic=abort" + +## Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow +#hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3" + +#echo +#echo "[BENCH RUN] mod_bench" +#hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_* + +function test_rustc() { + echo + echo "[TEST] rust-lang/rust" + + rust_toolchain=$(cat rust-toolchain) + + git clone https://github.com/rust-lang/rust.git || true + cd rust + git fetch + git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') + export RUSTFLAGS= + + rm config.toml || true + + cat > config.toml <, callsite: &'ll Value) { - // FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite. + if self.ret.layout.abi.is_uninhabited() { + llvm::Attribute::NoReturn.apply_callsite(llvm::AttributePlace::Function, callsite); + } + if !self.can_unwind { + llvm::Attribute::NoUnwind.apply_callsite(llvm::AttributePlace::Function, callsite); + } let mut i = 0; let mut apply = |cx: &CodegenCx<'_, '_>, attrs: &ArgAttributes| { @@ -520,7 +526,7 @@ }; match self.ret.mode { PassMode::Direct(ref attrs) => { - attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, &bx.cx, callsite); + attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite); } PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => { assert!(!on_stack); @@ -535,16 +541,13 @@ } _ => {} } - if let abi::Abi::Scalar(ref scalar) = self.ret.layout.abi { + if let abi::Abi::Scalar(scalar) = self.ret.layout.abi { // If the value is a boolean, the range is 0..2 and that ultimately // become 0..0 when the type becomes i1, which would be rejected // by the LLVM verifier. if let Int(..) = scalar.value { - if !scalar.is_bool() { - let range = scalar.valid_range_exclusive(bx); - if range.start != range.end { - bx.range_metadata(callsite, range); - } + if !scalar.is_bool() && !scalar.is_always_valid(bx) { + bx.range_metadata(callsite, scalar.valid_range); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/allocator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/allocator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/allocator.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/allocator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,19 +3,22 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; +use rustc_session::config::DebugInfo; use rustc_span::symbol::sym; +use crate::debuginfo; use crate::llvm::{self, False, True}; use crate::ModuleLlvm; pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, - mods: &mut ModuleLlvm, + module_llvm: &mut ModuleLlvm, + module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool, ) { - let llcx = &*mods.llcx; - let llmod = mods.llmod(); + let llcx = &*module_llvm.llcx; + let llmod = module_llvm.llmod(); let usize = match tcx.sess.target.pointer_width { 16 => llvm::LLVMInt16TypeInContext(llcx), 32 => llvm::LLVMInt32TypeInContext(llcx), @@ -132,4 +135,10 @@ llvm::LLVMSetTailCall(ret, True); llvm::LLVMBuildRetVoid(llbuilder); llvm::LLVMDisposeBuilder(llbuilder); + + if tcx.sess.opts.debuginfo != DebugInfo::None { + let dbg_cx = debuginfo::CrateDebugContext::new(llmod); + debuginfo::metadata::compile_unit_metadata(tcx, module_name, &dbg_cx); + dbg_cx.finalize(tcx.sess); + } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/asm.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/asm.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/asm.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/asm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -105,7 +105,7 @@ let r = r.unwrap(); // Again, based on how many outputs we have - let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect); + let outputs = ia.outputs.iter().zip(&outputs).filter(|&(o, _)| !o.is_indirect); for (i, (_, &place)) in outputs.enumerate() { let v = if num_outputs == 1 { r } else { self.extract_value(r, i as u64) }; OperandValue::Immediate(v).store(self, place); @@ -331,7 +331,7 @@ let output_type = match &output_types[..] { [] => self.type_void(), [ty] => ty, - tys => self.type_struct(&tys, false), + tys => self.type_struct(tys, false), }; let dialect = match asm_arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 @@ -792,7 +792,7 @@ /// Helper function to get the LLVM type for a Scalar. Pointers are returned as /// the equivalent integer type. -fn llvm_asm_scalar_type(cx: &CodegenCx<'ll, 'tcx>, scalar: &Scalar) -> &'ll Type { +fn llvm_asm_scalar_type(cx: &CodegenCx<'ll, 'tcx>, scalar: Scalar) -> &'ll Type { match scalar.value { Primitive::Int(Integer::I8, _) => cx.type_i8(), Primitive::Int(Integer::I16, _) => cx.type_i16(), @@ -812,7 +812,7 @@ reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, ) -> &'ll Value { - match (reg, &layout.abi) { + match (reg, layout.abi) { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.value { let vec_ty = bx.cx.type_vector(bx.cx.type_i8(), 8); @@ -835,7 +835,7 @@ Abi::Vector { element, count }, ) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(bx.cx, element); - let vec_ty = bx.cx.type_vector(elem_ty, *count); + let vec_ty = bx.cx.type_vector(elem_ty, count); let indices: Vec<_> = (0..count * 2).map(|x| bx.const_i32(x as i32)).collect(); bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } @@ -890,7 +890,7 @@ reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, ) -> &'ll Value { - match (reg, &layout.abi) { + match (reg, layout.abi) { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.value { bx.extract_element(value, bx.const_i32(0)) @@ -910,8 +910,8 @@ Abi::Vector { element, count }, ) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(bx.cx, element); - let vec_ty = bx.cx.type_vector(elem_ty, *count * 2); - let indices: Vec<_> = (0..*count).map(|x| bx.const_i32(x as i32)).collect(); + let vec_ty = bx.cx.type_vector(elem_ty, count * 2); + let indices: Vec<_> = (0..count).map(|x| bx.const_i32(x as i32)).collect(); bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) @@ -965,7 +965,7 @@ reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, ) -> &'ll Type { - match (reg, &layout.abi) { + match (reg, layout.abi) { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.value { cx.type_vector(cx.type_i8(), 8) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/attributes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/attributes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/attributes.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/attributes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -263,6 +263,10 @@ attributes::emit_uwtable(llfn, true); } + if cx.sess().opts.debugging_opts.profile_sample_use.is_some() { + llvm::AddFunctionAttrString(llfn, Function, cstr!("use-sample-profile")); + } + // FIXME: none of these three functions interact with source level attributes. set_frame_pointer_type(cx, llfn); set_instrument_function(cx, llfn); @@ -305,9 +309,12 @@ let mut function_features = codegen_fn_attrs .target_features .iter() - .map(|f| { + .flat_map(|f| { let feature = &f.as_str(); - format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) + llvm_util::to_llvm_feature(cx.tcx.sess, feature) + .into_iter() + .map(|f| format!("+{}", f)) + .collect::>() }) .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x { InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/archive.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/archive.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/archive.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/archive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,18 +9,15 @@ use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; -use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; -use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME}; +use rustc_codegen_ssa::back::archive::ArchiveBuilder; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_middle::middle::cstore::{DllCallingConvention, DllImport}; +use rustc_session::cstore::{DllCallingConvention, DllImport}; use rustc_session::Session; -use rustc_span::symbol::Symbol; struct ArchiveConfig<'a> { pub sess: &'a Session, pub dst: PathBuf, pub src: Option, - pub lib_search_paths: Vec, } /// Helper for adding many files to an archive. @@ -54,13 +51,7 @@ } fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) -> ArchiveConfig<'a> { - use rustc_codegen_ssa::back::link::archive_search_paths; - ArchiveConfig { - sess, - dst: output.to_path_buf(), - src: input.map(|p| p.to_path_buf()), - lib_search_paths: archive_search_paths(sess), - } + ArchiveConfig { sess, dst: output.to_path_buf(), src: input.map(|p| p.to_path_buf()) } } /// Map machine type strings to values of LLVM's MachineTypes enum. @@ -111,57 +102,23 @@ .collect() } - /// Adds all of the contents of a native library to this archive. This will - /// search in the relevant locations for a library named `name`. - fn add_native_library(&mut self, name: Symbol, verbatim: bool) { - let location = - find_library(name, verbatim, &self.config.lib_search_paths, self.config.sess); - self.add_archive(&location, |_| false).unwrap_or_else(|e| { - self.config.sess.fatal(&format!( - "failed to add native library {}: {}", - location.to_string_lossy(), - e - )); + fn add_archive(&mut self, archive: &Path, skip: F) -> io::Result<()> + where + F: FnMut(&str) -> bool + 'static, + { + let archive_ro = match ArchiveRO::open(archive) { + Ok(ar) => ar, + Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), + }; + if self.additions.iter().any(|ar| ar.path() == archive) { + return Ok(()); + } + self.additions.push(Addition::Archive { + path: archive.to_path_buf(), + archive: archive_ro, + skip: Box::new(skip), }); - } - - /// Adds all of the contents of the rlib at the specified path to this - /// archive. - /// - /// This ignores adding the bytecode from the rlib, and if LTO is enabled - /// then the object file also isn't added. - fn add_rlib( - &mut self, - rlib: &Path, - name: &str, - lto: bool, - skip_objects: bool, - ) -> io::Result<()> { - // Ignoring obj file starting with the crate name - // as simple comparison is not enough - there - // might be also an extra name suffix - let obj_start = name.to_owned(); - - self.add_archive(rlib, move |fname: &str| { - // Ignore metadata files, no matter the name. - if fname == METADATA_FILENAME { - return true; - } - - // Don't include Rust objects if LTO is enabled - if lto && looks_like_rust_object_file(fname) { - return true; - } - - // Otherwise if this is *not* a rust object and we're skipping - // objects then skip this file - if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { - return true; - } - - // ok, don't skip this - false - }) + Ok(()) } /// Adds an arbitrary file to this archive @@ -206,13 +163,13 @@ // All import names are Rust identifiers and therefore cannot contain \0 characters. // FIXME: when support for #[link_name] implemented, ensure that import.name values don't // have any \0 characters - let import_name_vector: Vec = dll_imports + let import_name_and_ordinal_vector: Vec<(CString, Option)> = dll_imports .iter() .map(|import: &DllImport| { if self.config.sess.target.arch == "x86" { - LlvmArchiveBuilder::i686_decorated_name(import) + (LlvmArchiveBuilder::i686_decorated_name(import), import.ordinal) } else { - CString::new(import.name.to_string()).unwrap() + (CString::new(import.name.to_string()).unwrap(), import.ordinal) } }) .collect(); @@ -227,9 +184,9 @@ dll_imports.iter().map(|import| import.name.to_string()).collect::>().join(", "), ); - let ffi_exports: Vec = import_name_vector + let ffi_exports: Vec = import_name_and_ordinal_vector .iter() - .map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr())) + .map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal)) .collect(); let result = unsafe { crate::llvm::LLVMRustWriteImportLibrary( @@ -270,25 +227,6 @@ self.src_archive.as_ref().unwrap().as_ref() } - fn add_archive(&mut self, archive: &Path, skip: F) -> io::Result<()> - where - F: FnMut(&str) -> bool + 'static, - { - let archive_ro = match ArchiveRO::open(archive) { - Ok(ar) => ar, - Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), - }; - if self.additions.iter().any(|ar| ar.path() == archive) { - return Ok(()); - } - self.additions.push(Addition::Archive { - path: archive.to_path_buf(), - archive: archive_ro, - skip: Box::new(skip), - }); - Ok(()) - } - fn llvm_archive_kind(&self) -> Result { let kind = &*self.config.sess.target.archive_format; kind.parse().map_err(|_| kind) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/lto.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/lto.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/lto.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/lto.rs 2021-11-29 19:27:11.000000000 +0000 @@ -109,7 +109,7 @@ .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter)); } - let archive = ArchiveRO::open(&path).expect("wanted an rlib"); + let archive = ArchiveRO::open(path).expect("wanted an rlib"); let obj_files = archive .iter() .filter_map(|child| child.ok().and_then(|c| c.name().map(|name| (name, c)))) @@ -316,14 +316,28 @@ .generic_activity_with_arg("LLVM_fat_lto_link_module", format!("{:?}", name)); info!("linking {:?}", name); let data = bc_decoded.data(); - linker.add(&data).map_err(|()| { + linker.add(data).map_err(|()| { let msg = format!("failed to load bc of {:?}", name); - write::llvm_err(&diag_handler, &msg) + write::llvm_err(diag_handler, &msg) })?; serialized_bitcode.push(bc_decoded); } drop(linker); - save_temp_bitcode(&cgcx, &module, "lto.input"); + save_temp_bitcode(cgcx, &module, "lto.input"); + + // Fat LTO also suffers from the invalid DWARF issue similar to Thin LTO. + // Here we rewrite all `DICompileUnit` pointers if there is only one `DICompileUnit`. + // This only works around the problem when codegen-units = 1. + // Refer to the comments in the `optimize_thin_module` function for more details. + let mut cu1 = ptr::null_mut(); + let mut cu2 = ptr::null_mut(); + unsafe { llvm::LLVMRustLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2) }; + if !cu2.is_null() { + let _timer = + cgcx.prof.generic_activity_with_arg("LLVM_fat_lto_patch_debuginfo", &*module.name); + unsafe { llvm::LLVMRustLTOPatchDICompileUnit(llmod, cu1) }; + save_temp_bitcode(cgcx, &module, "fat-lto-after-patch"); + } // Internalize everything below threshold to help strip out more modules and such. unsafe { @@ -333,14 +347,14 @@ ptr as *const *const libc::c_char, symbols_below_threshold.len() as libc::size_t, ); - save_temp_bitcode(&cgcx, &module, "lto.after-restriction"); + save_temp_bitcode(cgcx, &module, "lto.after-restriction"); } if cgcx.no_landing_pads { unsafe { llvm::LLVMRustMarkAllFunctionsNounwind(llmod); } - save_temp_bitcode(&cgcx, &module, "lto.after-nounwind"); + save_temp_bitcode(cgcx, &module, "lto.after-nounwind"); } } @@ -484,7 +498,7 @@ symbols_below_threshold.as_ptr(), symbols_below_threshold.len() as u32, ) - .ok_or_else(|| write::llvm_err(&diag_handler, "failed to prepare thin LTO context"))?; + .ok_or_else(|| write::llvm_err(diag_handler, "failed to prepare thin LTO context"))?; let data = ThinData(data); @@ -558,7 +572,7 @@ if let Some(path) = key_map_path { if let Err(err) = curr_key_map.save_to_file(&path) { let msg = format!("Error while writing ThinLTO key data: {}", err); - return Err(write::llvm_err(&diag_handler, &msg)); + return Err(write::llvm_err(diag_handler, &msg)); } } @@ -582,7 +596,7 @@ // tools/lto/LTOCodeGenerator.cpp debug!("running the pass manager"); unsafe { - if write::should_use_new_llvm_pass_manager(config) { + if write::should_use_new_llvm_pass_manager(cgcx, config) { let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); write::optimize_with_new_llvm_pass_manager( @@ -730,8 +744,7 @@ // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = - parse_module(llcx, &module_name, thin_module.data(), &diag_handler)? as *const _; + let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _; let module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm }, name: thin_module.name().to_string(), @@ -740,7 +753,7 @@ { let target = &*module.module_llvm.tm; let llmod = module.module_llvm.llmod(); - save_temp_bitcode(&cgcx, &module, "thin-lto-input"); + save_temp_bitcode(cgcx, &module, "thin-lto-input"); // Before we do much else find the "main" `DICompileUnit` that we'll be // using below. If we find more than one though then rustc has changed @@ -748,7 +761,7 @@ // an error. let mut cu1 = ptr::null_mut(); let mut cu2 = ptr::null_mut(); - llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); + llvm::LLVMRustLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); if !cu2.is_null() { let msg = "multiple source DICompileUnits found"; return Err(write::llvm_err(&diag_handler, msg)); @@ -761,7 +774,7 @@ .prof .generic_activity_with_arg("LLVM_thin_lto_remove_landing_pads", thin_module.name()); llvm::LLVMRustMarkAllFunctionsNounwind(llmod); - save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind"); + save_temp_bitcode(cgcx, &module, "thin-lto-after-nounwind"); } // Up next comes the per-module local analyses that we do for Thin LTO. @@ -847,7 +860,7 @@ let _timer = cgcx .prof .generic_activity_with_arg("LLVM_thin_lto_patch_debuginfo", thin_module.name()); - llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); + llvm::LLVMRustLTOPatchDICompileUnit(llmod, cu1); save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); } @@ -933,7 +946,7 @@ llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr()).ok_or_else( || { let msg = "failed to parse bitcode for LTO module"; - write::llvm_err(&diag_handler, msg) + write::llvm_err(diag_handler, msg) }, ) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/write.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/write.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/write.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/back/write.rs 2021-11-29 19:27:11.000000000 +0000 @@ -41,7 +41,7 @@ pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError { match llvm::last_error() { Some(err) => handler.fatal(&format!("{}: {}", msg, err)), - None => handler.fatal(&msg), + None => handler.fatal(msg), } } @@ -96,7 +96,7 @@ None }; let config = TargetMachineFactoryConfig { split_dwarf_file }; - target_machine_factory(&tcx.sess, tcx.backend_optimization_level(()))(config) + target_machine_factory(tcx.sess, tcx.backend_optimization_level(()))(config) .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise()) } @@ -129,7 +129,8 @@ fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel { match relocation_model { RelocModel::Static => llvm::RelocModel::Static, - RelocModel::Pic => llvm::RelocModel::PIC, + // LLVM doesn't have a PIE relocation model, it represents PIE as PIC with an extra attribute. + RelocModel::Pic | RelocModel::Pie => llvm::RelocModel::PIC, RelocModel::DynamicNoPic => llvm::RelocModel::DynamicNoPic, RelocModel::Ropi => llvm::RelocModel::ROPI, RelocModel::Rwpi => llvm::RelocModel::RWPI, @@ -369,9 +370,22 @@ .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap()) } -pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool { - // The new pass manager is disabled by default. - config.new_llvm_pass_manager.unwrap_or(false) +fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option { + config + .pgo_sample_use + .as_ref() + .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap()) +} + +pub(crate) fn should_use_new_llvm_pass_manager( + _cgcx: &CodegenContext, + config: &ModuleConfig, +) -> bool { + // The new pass manager is causing significant performance issues such as #91128, and is + // therefore disabled in stable versions of rustc by default. + config + .new_llvm_pass_manager + .unwrap_or(false) } pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( @@ -387,6 +401,7 @@ let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed(); let pgo_gen_path = get_pgo_gen_path(config); let pgo_use_path = get_pgo_use_path(config); + let pgo_sample_use_path = get_pgo_sample_use_path(config); let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO; // Sanitizer instrumentation is only inserted during the pre-link optimization stage. let sanitizer_options = if !is_lto { @@ -404,13 +419,15 @@ None }; - let llvm_selfprofiler = if cgcx.prof.llvm_recording_enabled() { - let mut llvm_profiler = LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap()); - &mut llvm_profiler as *mut _ as *mut c_void + let mut llvm_profiler = if cgcx.prof.llvm_recording_enabled() { + Some(LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap())) } else { - std::ptr::null_mut() + None }; + let llvm_selfprofiler = + llvm_profiler.as_mut().map(|s| s as *mut _ as *mut c_void).unwrap_or(std::ptr::null_mut()); + let extra_passes = config.passes.join(","); // FIXME: NewPM doesn't provide a facility to pass custom InlineParams. @@ -435,6 +452,8 @@ pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), config.instrument_coverage, config.instrument_gcov, + pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.debug_info_for_profiling, llvm_selfprofiler, selfprofile_before_pass_callback, selfprofile_after_pass_callback, @@ -468,7 +487,7 @@ } if let Some(opt_level) = config.opt_level { - if should_use_new_llvm_pass_manager(config) { + if should_use_new_llvm_pass_manager(cgcx, config) { let opt_stage = match cgcx.lto { Lto::Fat => llvm::OptStage::PreLinkFatLTO, Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO, @@ -540,6 +559,9 @@ if config.instrument_coverage { llvm::LLVMRustAddPass(mpm, find_pass("instrprof").unwrap()); } + if config.debug_info_for_profiling { + llvm::LLVMRustAddPass(mpm, find_pass("add-discriminators").unwrap()); + } add_sanitizer_passes(config, &mut extra_passes); @@ -554,7 +576,7 @@ let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal || (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled()); - with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { + with_llvm_pmb(llmod, config, opt_level, prepare_for_thin_lto, &mut |b| { llvm::LLVMRustAddLastExtensionPasses( b, extra_passes.as_ptr(), @@ -656,9 +678,9 @@ let _timer = cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name)); let buffer = ModuleBuffer::new(module.module_llvm.llmod()); - linker.add(&buffer.data()).map_err(|()| { + linker.add(buffer.data()).map_err(|()| { let msg = format!("failed to serialize module {:?}", module.name); - llvm_err(&diag_handler, &msg) + llvm_err(diag_handler, &msg) })?; } drop(linker); @@ -997,6 +1019,7 @@ let inline_threshold = config.inline_threshold; let pgo_gen_path = get_pgo_gen_path(config); let pgo_use_path = get_pgo_use_path(config); + let pgo_sample_use_path = get_pgo_sample_use_path(config); llvm::LLVMRustConfigurePassManagerBuilder( builder, @@ -1007,6 +1030,7 @@ prepare_for_thin_lto, pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), + pgo_sample_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), ); llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/base.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/base.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/base.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/base.rs 2021-11-29 19:27:11.000000000 +0000 @@ -25,9 +25,9 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::exported_symbols; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::TyCtxt; @@ -64,7 +64,7 @@ let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod()); let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); - FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); + FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap(); let llmeta = common::bytes_in_context(metadata_llcx, &compressed); let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/builder.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/builder.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/builder.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/builder.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,15 +15,17 @@ use rustc_codegen_ssa::MemFlags; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, +}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; -use rustc_target::abi::{self, Align, Size}; +use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ffi::CStr; use std::iter; -use std::ops::{Deref, Range}; +use std::ops::Deref; use std::ptr; use tracing::debug; @@ -84,16 +86,30 @@ impl HasTargetSpec for Builder<'_, '_, 'tcx> { #[inline] fn target_spec(&self) -> &Target { - &self.cx.target_spec() + self.cx.target_spec() } } -impl abi::LayoutOf<'tcx> for Builder<'_, '_, 'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; +impl LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.cx.layout_of(ty) + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + self.cx.handle_layout_err(err, span, ty) + } +} + +impl FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + self.cx.handle_fn_abi_err(err, span, fn_abi_request) } } @@ -382,7 +398,7 @@ val } } - fn to_immediate_scalar(&mut self, val: Self::Value, scalar: &abi::Scalar) -> Self::Value { + fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value { if scalar.is_bool() { return self.trunc(val, self.cx().type_i1()); } @@ -460,16 +476,15 @@ fn scalar_load_metadata<'a, 'll, 'tcx>( bx: &mut Builder<'a, 'll, 'tcx>, load: &'ll Value, - scalar: &abi::Scalar, + scalar: abi::Scalar, ) { match scalar.value { abi::Int(..) => { - let range = scalar.valid_range_exclusive(bx); - if range.start != range.end { - bx.range_metadata(load, range); + if !scalar.is_always_valid(bx) { + bx.range_metadata(load, scalar.valid_range); } } - abi::Pointer if !scalar.valid_range.contains_zero() => { + abi::Pointer if !scalar.valid_range.contains(0) => { bx.nonnull_metadata(load); } _ => {} @@ -489,17 +504,17 @@ } let llval = const_llval.unwrap_or_else(|| { let load = self.load(place.layout.llvm_type(self), place.llval, place.align); - if let abi::Abi::Scalar(ref scalar) = place.layout.abi { + if let abi::Abi::Scalar(scalar) = place.layout.abi { scalar_load_metadata(self, load, scalar); } load }); OperandValue::Immediate(self.to_immediate(llval, place.layout)) - } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { + } else if let abi::Abi::ScalarPair(a, b) = place.layout.abi { let b_offset = a.value.size(self).align_to(b.value.align(self).abi); let pair_ty = place.layout.llvm_type(self); - let mut load = |i, scalar: &abi::Scalar, align| { + let mut load = |i, scalar: abi::Scalar, align| { let llptr = self.struct_gep(pair_ty, place.llval, i as u64); let llty = place.layout.scalar_pair_element_llvm_type(self, i, false); let load = self.load(llty, llptr, align); @@ -555,7 +570,7 @@ next_bx } - fn range_metadata(&mut self, load: &'ll Value, range: Range) { + fn range_metadata(&mut self, load: &'ll Value, range: WrappingRange) { if self.sess().target.arch == "amdgpu" { // amdgpu/LLVM does something weird and thinks an i64 value is // split into a v2i32, halving the bitwidth LLVM expects, @@ -568,7 +583,7 @@ let llty = self.cx.val_ty(load); let v = [ self.cx.const_uint_big(llty, range.start), - self.cx.const_uint_big(llty, range.end), + self.cx.const_uint_big(llty, range.end.wrapping_add(1)), ]; llvm::LLVMSetMetadata( @@ -813,6 +828,7 @@ } fn fcmp(&mut self, op: RealPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + let op = llvm::RealPredicate::from_generic(op); unsafe { llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED) } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/callee.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/callee.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/callee.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/callee.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -use crate::abi::{FnAbi, FnAbiLlvmExt}; +use crate::abi::FnAbiLlvmExt; use crate::attributes; use crate::context::CodegenCx; use crate::llvm; @@ -12,7 +12,7 @@ use rustc_codegen_ssa::traits::*; use tracing::debug; -use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use rustc_middle::ty::{self, Instance, TypeFoldable}; /// Codegens a reference to a fn/method item, monomorphizing and @@ -42,9 +42,9 @@ sym ); - let fn_abi = FnAbi::of_instance(cx, instance, &[]); + let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); - let llfn = if let Some(llfn) = cx.get_declared_value(&sym) { + let llfn = if let Some(llfn) = cx.get_declared_value(sym) { // Create a fn pointer with the new signature. let llptrty = fn_abi.ptr_to_llvm_type(cx); @@ -79,7 +79,7 @@ llfn } } else { - let llfn = cx.declare_fn(&sym, &fn_abi); + let llfn = cx.declare_fn(sym, fn_abi); debug!("get_fn: not casting pointer!"); attributes::from_fn_attrs(cx, llfn, instance); @@ -175,7 +175,7 @@ // should use dllimport for functions. if cx.use_dll_storage_attrs && tcx.is_dllimport_foreign_item(instance_def_id) - && tcx.sess.target.env != "gnu" + && !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc") { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/common.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/common.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/common.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/common.rs 2021-11-29 19:27:11.000000000 +0000 @@ -12,9 +12,10 @@ use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar}; -use rustc_middle::ty::{layout::TyAndLayout, ScalarInt}; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::ScalarInt; use rustc_span::symbol::Symbol; -use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size}; +use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size}; use libc::{c_char, c_uint}; use tracing::debug; @@ -227,7 +228,7 @@ }) } - fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: &'ll Type) -> &'ll Value { + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() }; match cv { Scalar::Int(ScalarInt::ZST) => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/consts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/consts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/consts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/consts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,10 +15,11 @@ Scalar as InterpScalar, }; use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; use rustc_target::abi::{ - AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size, WrappingRange, + AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange, }; use std::ops::Range; use tracing::debug; @@ -110,7 +111,7 @@ Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), &cx.tcx, ), - &Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } }, + Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } }, cx.type_i8p_ext(address_space), )); next_offset = offset + pointer_size; @@ -177,7 +178,7 @@ }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = cx.declare_global(&sym, llty2); + let g1 = cx.declare_global(sym, llty2); llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); // Declare an internal global `extern_with_linkage_foo` which @@ -187,7 +188,7 @@ // `extern_with_linkage_foo` will instead be initialized to // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(&sym); + real_name.push_str(sym); let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { cx.sess().span_fatal( cx.tcx.def_span(span_def_id), @@ -201,7 +202,7 @@ } else { // Generate an external declaration. // FIXME(nagisa): investigate whether it can be changed into define_global - cx.declare_global(&sym, llty) + cx.declare_global(sym, llty) } } @@ -233,7 +234,7 @@ _ => self.define_private_global(self.val_ty(cv)), }; llvm::LLVMSetInitializer(gv, cv); - set_global_alignment(&self, gv, align); + set_global_alignment(self, gv, align); llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); gv } @@ -278,7 +279,7 @@ g } else { - check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id) + check_and_apply_linkage(self, fn_attrs, ty, sym, def_id) }; // Thread-local statics in some other crate need to *always* be linked @@ -368,7 +369,7 @@ unsafe { let attrs = self.tcx.codegen_fn_attrs(def_id); - let (v, alloc) = match codegen_static_initializer(&self, def_id) { + let (v, alloc) = match codegen_static_initializer(self, def_id) { Ok(v) => v, // Error has already been reported Err(_) => return, @@ -416,7 +417,7 @@ self.statics_to_rauw.borrow_mut().push((g, new_g)); new_g }; - set_global_alignment(&self, g, self.align_of(ty)); + set_global_alignment(self, g, self.align_of(ty)); llvm::LLVMSetInitializer(g, v); if self.should_assume_dso_local(g, true) { @@ -429,7 +430,7 @@ llvm::LLVMSetGlobalConstant(g, llvm::True); } - debuginfo::create_global_var_metadata(&self, def_id, g); + debuginfo::create_global_var_metadata(self, def_id, g); if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { llvm::set_thread_local_mode(g, self.tls_model); @@ -517,7 +518,7 @@ ); } } else { - base::set_link_section(g, &attrs); + base::set_link_section(g, attrs); } if attrs.flags.contains(CodegenFnAttrFlags::USED) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/context.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/context.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/context.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/context.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,15 +14,20 @@ use rustc_data_structures::base_n; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_middle::bug; use rustc_middle::mir::mono::CodegenUnit; -use rustc_middle::ty::layout::{HasParamEnv, LayoutError, TyAndLayout}; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers, + TyAndLayout, +}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::config::{CFGuard, CrateType, DebugInfo}; use rustc_session::Session; -use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; -use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx}; +use rustc_target::abi::{ + call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx, +}; use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use smallvec::SmallVec; @@ -190,11 +195,14 @@ let llvm_target = SmallCStr::new(&sess.target.llvm_target); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); - if sess.relocation_model() == RelocModel::Pic { + let reloc_model = sess.relocation_model(); + if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) { llvm::LLVMRustSetModulePICLevel(llmod); // PIE is potentially more effective than PIC, but can only be used in executables. // If all our outputs are executables, then we can relax PIC to PIE. - if sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) { + if reloc_model == RelocModel::Pie + || sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) + { llvm::LLVMRustSetModulePIELevel(llmod); } } @@ -355,7 +363,7 @@ fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) { let section = cstr!("llvm.metadata"); - let array = self.const_array(&self.type_ptr_to(self.type_i8()), values); + let array = self.const_array(self.type_ptr_to(self.type_i8()), values); unsafe { let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); @@ -439,7 +447,7 @@ } fn sess(&self) -> &Session { - &self.tcx.sess + self.tcx.sess } fn check_overflow(&self) -> bool { @@ -835,27 +843,58 @@ } } -impl LayoutOf<'tcx> for CodegenCx<'ll, 'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; - - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.spanned_layout_of(ty, DUMMY_SP) +impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + ty::ParamEnv::reveal_all() } +} - fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::TyAndLayout { - self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap_or_else(|e| { - if let LayoutError::SizeOverflow(_) = e { - self.sess().span_fatal(span, &e.to_string()) - } else { - bug!("failed to get layout for `{}`: {}", ty, e) - } - }) +impl LayoutOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + if let LayoutError::SizeOverflow(_) = err { + self.sess().span_fatal(span, &err.to_string()) + } else { + span_bug!(span, "failed to get layout for `{}`: {}", ty, err) + } } } -impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx> { - ty::ParamEnv::reveal_all() +impl FnAbiOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { + self.sess().span_fatal(span, &err.to_string()) + } else { + match fn_abi_request { + FnAbiRequest::OfFnPtr { sig, extra_args } => { + span_bug!( + span, + "`fn_abi_of_fn_ptr({}, {:?})` failed: {}", + sig, + extra_args, + err + ); + } + FnAbiRequest::OfInstance { instance, extra_args } => { + span_bug!( + span, + "`fn_abi_of_instance({}, {:?})` failed: {}", + instance, + extra_args, + err + ); + } + } + } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs 2021-11-29 19:27:11.000000000 +0000 @@ -73,7 +73,7 @@ mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer); }); debug_assert!( - coverage_mapping_buffer.len() > 0, + !coverage_mapping_buffer.is_empty(), "Every `FunctionCoverage` should have at least one counter" ); @@ -311,8 +311,7 @@ // for each region in it's MIR. // Convert the `HashSet` of `codegenned_def_ids` to a sortable vector, and sort them. - let mut sorted_codegenned_def_ids: Vec = - codegenned_def_ids.iter().map(|def_id| *def_id).collect(); + let mut sorted_codegenned_def_ids: Vec = codegenned_def_ids.iter().copied().collect(); sorted_codegenned_def_ids.sort_unstable(); let mut first_covered_def_id_by_file: FxHashMap = FxHashMap::default(); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ use crate::llvm; -use crate::abi::{Abi, FnAbi}; +use crate::abi::Abi; use crate::builder::Builder; use crate::common::CodegenCx; @@ -20,7 +20,7 @@ CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op, }; use rustc_middle::ty; -use rustc_middle::ty::layout::FnAbiExt; +use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::Instance; @@ -199,9 +199,8 @@ ); let llfn = cx.declare_fn( - &tcx.symbol_name(instance).name, - &FnAbi::of_fn_ptr( - cx, + tcx.symbol_name(instance).name, + cx.fn_abi_of_fn_ptr( ty::Binder::dummy(tcx.mk_fn_sig( iter::once(tcx.mk_unit()), tcx.mk_unit(), @@ -209,7 +208,7 @@ hir::Unsafety::Unsafe, Abi::Rust, )), - &[], + ty::List::empty(), ), ); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,12 +3,11 @@ use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext}; use rustc_codegen_ssa::traits::*; -use crate::abi::FnAbi; use crate::common::CodegenCx; use crate::llvm; use crate::llvm::debuginfo::{DILocation, DIScope}; use rustc_middle::mir::{Body, SourceScope}; -use rustc_middle::ty::layout::FnAbiExt; +use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance}; use rustc_session::config::DebugInfo; @@ -42,7 +41,7 @@ // Instantiate all scopes. for idx in 0..mir.source_scopes.len() { let scope = SourceScope::new(idx); - make_mir_scope(cx, instance, &mir, fn_dbg_scope, &has_variables, debug_context, scope); + make_mir_scope(cx, instance, mir, fn_dbg_scope, &has_variables, debug_context, scope); } } @@ -94,8 +93,8 @@ ty::ParamEnv::reveal_all(), callee, ); - let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]); - cx.dbg_scope_fn(callee, &callee_fn_abi, None) + let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); + cx.dbg_scope_fn(callee, callee_fn_abi, None) } None => unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlock( diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs 2021-11-29 19:27:11.000000000 +0000 @@ -59,10 +59,8 @@ } pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { - let omit_gdb_pretty_printer_section = cx - .tcx - .sess - .contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); + let omit_gdb_pretty_printer_section = + cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); !omit_gdb_pretty_printer_section && cx.sess().opts.debuginfo != DebugInfo::None diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ use self::RecursiveTypeDescription::*; use super::namespace::mangled_name_of_instance; -use super::type_names::compute_debuginfo_type_name; +use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name}; use super::utils::{ create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB, }; @@ -26,18 +26,19 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::ich::NodeIdHashingMode; use rustc_middle::mir::{self, GeneratorLayout}; -use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout}; +use rustc_middle::ty::layout::{self, IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::Instance; -use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{ + self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES, +}; use rustc_middle::{bug, span_bug}; +use rustc_query_system::ich::NodeIdHashingMode; use rustc_session::config::{self, DebugInfo}; -use rustc_span::symbol::{Interner, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::FileNameDisplayPreference; use rustc_span::{self, SourceFile, SourceFileHash, Span}; -use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding}; +use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, TagEncoding}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{Primitive, Size, VariantIdx, Variants}; use tracing::debug; @@ -89,8 +90,54 @@ pub const NO_SCOPE_METADATA: Option<&DIScope> = None; -#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] -pub struct UniqueTypeId(Symbol); +mod unique_type_id { + use super::*; + use rustc_arena::DroplessArena; + + #[derive(Copy, Hash, Eq, PartialEq, Clone)] + pub(super) struct UniqueTypeId(u32); + + // The `&'static str`s in this type actually point into the arena. + // + // The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278 + // found that to regress performance up to 2% in some cases. This might be + // revisited after further improvements to `indexmap`. + #[derive(Default)] + pub(super) struct TypeIdInterner { + arena: DroplessArena, + names: FxHashMap<&'static str, UniqueTypeId>, + strings: Vec<&'static str>, + } + + impl TypeIdInterner { + #[inline] + pub(super) fn intern(&mut self, string: &str) -> UniqueTypeId { + if let Some(&name) = self.names.get(string) { + return name; + } + + let name = UniqueTypeId(self.strings.len() as u32); + + // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be + // UTF-8. + let string: &str = + unsafe { std::str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) }; + // It is safe to extend the arena allocation to `'static` because we only access + // these while the arena is still alive. + let string: &'static str = unsafe { &*(string as *const str) }; + self.strings.push(string); + self.names.insert(string, name); + name + } + + // Get the symbol as a string. `Symbol::as_str()` should be used in + // preference to this function. + pub(super) fn get(&self, symbol: UniqueTypeId) -> &str { + self.strings[symbol.0 as usize] + } + } +} +use unique_type_id::*; /// The `TypeMap` is where the `CrateDebugContext` holds the type metadata nodes /// created so far. The metadata nodes are indexed by `UniqueTypeId`, and, for @@ -99,7 +146,7 @@ #[derive(Default)] pub struct TypeMap<'ll, 'tcx> { /// The `UniqueTypeId`s created so far. - unique_id_interner: Interner, + unique_id_interner: TypeIdInterner, /// A map from `UniqueTypeId` to debuginfo metadata for that type. This is a 1:1 mapping. unique_id_to_metadata: FxHashMap, /// A map from types to debuginfo metadata. This is an N:1 mapping. @@ -166,8 +213,7 @@ /// Gets the string representation of a `UniqueTypeId`. This method will fail if /// the ID is unknown. fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str { - let UniqueTypeId(interner_key) = unique_type_id; - self.unique_id_interner.get(interner_key) + self.unique_id_interner.get(unique_type_id) } /// Gets the `UniqueTypeId` for the given type. If the `UniqueTypeId` for the given @@ -197,9 +243,9 @@ let unique_type_id = hasher.finish::().to_hex(); let key = self.unique_id_interner.intern(&unique_type_id); - self.type_to_unique_id.insert(type_, UniqueTypeId(key)); + self.type_to_unique_id.insert(type_, key); - UniqueTypeId(key) + key } /// Gets the `UniqueTypeId` for an enum variant. Enum variants are not really @@ -215,7 +261,7 @@ let enum_variant_type_id = format!("{}::{}", self.get_unique_type_id_as_string(enum_type_id), variant_name); let interner_key = self.unique_id_interner.intern(&enum_variant_type_id); - UniqueTypeId(interner_key) + interner_key } /// Gets the unique type ID string for an enum variant part. @@ -432,7 +478,7 @@ let signature_metadata: Vec<_> = iter::once( // return type match signature.output().kind() { - ty::Tuple(ref tys) if tys.is_empty() => None, + ty::Tuple(tys) if tys.is_empty() => None, _ => Some(type_metadata(cx, signature.output(), span)), }, ) @@ -602,7 +648,7 @@ ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } - ty::Tuple(ref elements) if elements.is_empty() => { + ty::Tuple(elements) if elements.is_empty() => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } ty::Array(typ, _) | ty::Slice(typ) => { @@ -701,7 +747,7 @@ .finalize(cx) } }, - ty::Tuple(ref elements) => { + ty::Tuple(elements) => { let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect(); prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA) .finalize(cx) @@ -887,7 +933,7 @@ let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), - ty::Tuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned), + ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned), ty::Bool => ("bool", DW_ATE_boolean), ty::Char => ("char", DW_ATE_unsigned_char), ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed), @@ -1078,7 +1124,7 @@ let gcov_cu_info = [ path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")), - path_to_mdstring(debug_context.llcontext, &gcda_path), + path_to_mdstring(debug_context.llcontext, gcda_path), cu_desc_metadata, ]; let gcov_metadata = llvm::LLVMMDNodeInContext( @@ -1656,7 +1702,7 @@ Variants::Multiple { tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant }, - ref tag, + tag, ref variants, tag_field, } => { @@ -1918,17 +1964,13 @@ } fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option> { - match self { - VariantInfo::Generator { def_id, variant_index, .. } => { - let span = cx.tcx.generator_layout(*def_id).unwrap().variant_source_info - [*variant_index] - .span; - if !span.is_dummy() { - let loc = cx.lookup_debug_loc(span.lo()); - return Some(SourceInfo { file: file_metadata(cx, &loc.file), line: loc.line }); - } + if let VariantInfo::Generator { def_id, variant_index, .. } = self { + let span = + cx.tcx.generator_layout(*def_id).unwrap().variant_source_info[*variant_index].span; + if !span.is_dummy() { + let loc = cx.lookup_debug_loc(span.lo()); + return Some(SourceInfo { file: file_metadata(cx, &loc.file), line: loc.line }); } - _ => {} } None } @@ -1949,11 +1991,11 @@ let unique_type_id = debug_context(cx) .type_map .borrow_mut() - .get_unique_type_id_of_enum_variant(cx, layout.ty, &variant_name); + .get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name); create_struct_stub( cx, layout.ty, - &variant_name, + variant_name, unique_type_id, Some(containing_scope), DIFlags::FlagZero, @@ -2082,10 +2124,8 @@ let layout = cx.layout_of(enum_type); - if let ( - &Abi::Scalar(_), - &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. }, - ) = (&layout.abi, &layout.variants) + if let (Abi::Scalar(_), Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. }) = + (layout.abi, &layout.variants) { return FinalMetadata(discriminant_type_metadata(tag.value)); } @@ -2093,8 +2133,8 @@ if use_enum_fallback(cx) { let discriminant_type_metadata = match layout.variants { Variants::Single { .. } => None, - Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. } - | Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => { + Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } + | Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => { Some(discriminant_type_metadata(tag.value)) } }; @@ -2146,9 +2186,7 @@ // A single-variant enum has no discriminant. Variants::Single { .. } => None, - Variants::Multiple { - tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, .. - } => { + Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, tag_field, .. } => { // Find the integer type of the correct size. let size = tag.value.size(cx); let align = tag.value.align(cx); @@ -2179,7 +2217,7 @@ } } - Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => { + Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, tag_field, .. } => { let discr_type = tag.value.to_ty(cx.tcx); let (size, align) = cx.size_and_align_of(discr_type); @@ -2344,7 +2382,7 @@ { let mut composite_types_completed = debug_context(cx).composite_types_completed.borrow_mut(); - if !composite_types_completed.insert(&composite_type_metadata) { + if !composite_types_completed.insert(composite_type_metadata) { bug!( "debuginfo::set_members_of_composite_type() - \ Already completed forward declaration re-encountered." @@ -2554,11 +2592,45 @@ } } +/// Generates LLVM debuginfo for a vtable. +fn vtable_type_metadata( + cx: &CodegenCx<'ll, 'tcx>, + ty: Ty<'tcx>, + poly_trait_ref: Option>, +) -> &'ll DIType { + let tcx = cx.tcx; + + let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { + let trait_ref = poly_trait_ref.with_self_ty(tcx, ty); + let trait_ref = tcx.erase_regions(trait_ref); + + tcx.vtable_entries(trait_ref) + } else { + COMMON_VTABLE_ENTRIES + }; + + // FIXME: We describe the vtable as an array of *const () pointers. The length of the array is + // correct - but we could create a more accurate description, e.g. by describing it + // as a struct where each field has a name that corresponds to the name of the method + // it points to. + // However, this is not entirely straightforward because there might be multiple + // methods with the same name if the vtable is for multiple traits. So for now we keep + // things simple instead of adding some ad-hoc disambiguation scheme. + let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64); + + type_metadata(cx, vtable_type, rustc_span::DUMMY_SP) +} + /// Creates debug information for the given vtable, which is for the /// given type. /// /// Adds the created metadata nodes directly to the crate's IR. -pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &'ll Value) { +pub fn create_vtable_metadata( + cx: &CodegenCx<'ll, 'tcx>, + ty: Ty<'tcx>, + poly_trait_ref: Option>, + vtable: &'ll Value, +) { if cx.dbg_cx.is_none() { return; } @@ -2568,42 +2640,16 @@ return; } - let type_metadata = type_metadata(cx, ty, rustc_span::DUMMY_SP); + let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref); + let vtable_type = vtable_type_metadata(cx, ty, poly_trait_ref); unsafe { - // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in `llvm/lib/IR/Value.cpp`. - let empty_array = create_DIArray(DIB(cx), &[]); - let name = "vtable"; - - // Create a new one each time. We don't want metadata caching - // here, because each vtable will refer to a unique containing - // type. - let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( - DIB(cx), - NO_SCOPE_METADATA, - name.as_ptr().cast(), - name.len(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - Size::ZERO.bits(), - cx.tcx.data_layout.pointer_align.abi.bits() as u32, - DIFlags::FlagArtificial, - None, - empty_array, - 0, - Some(type_metadata), - name.as_ptr().cast(), - name.len(), - ); - let linkage_name = ""; llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, - name.as_ptr().cast(), - name.len(), + vtable_name.as_ptr().cast(), + vtable_name.len(), linkage_name.as_ptr().cast(), linkage_name.len(), unknown_file_metadata(cx), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -25,13 +25,14 @@ use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_index::vec::IndexVec; use rustc_middle::mir; -use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable}; use rustc_session::config::{self, DebugInfo}; +use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, Span}; -use rustc_target::abi::{LayoutOf, Primitive, Size}; +use rustc_target::abi::{Primitive, Size}; use libc::c_uint; use smallvec::SmallVec; @@ -95,45 +96,52 @@ composite_types_completed: Default::default(), } } -} -/// Creates any deferred debug metadata nodes -pub fn finalize(cx: &CodegenCx<'_, '_>) { - if cx.dbg_cx.is_none() { - return; - } + pub fn finalize(&self, sess: &Session) { + unsafe { + llvm::LLVMRustDIBuilderFinalize(self.builder); - debug!("finalize"); + // Debuginfo generation in LLVM by default uses a higher + // version of dwarf than macOS currently understands. We can + // instruct LLVM to emit an older version of dwarf, however, + // for macOS to understand. For more info see #11352 + // This can be overridden using --llvm-opts -dwarf-version,N. + // Android has the same issue (#22398) + if let Some(version) = sess.target.dwarf_version { + llvm::LLVMRustAddModuleFlag(self.llmod, "Dwarf Version\0".as_ptr().cast(), version) + } - if gdb::needs_gdb_debug_scripts_section(cx) { - // Add a .debug_gdb_scripts section to this compile-unit. This will - // cause GDB to try and load the gdb_load_rust_pretty_printers.py file, - // which activates the Rust pretty printers for binary this section is - // contained in. - gdb::get_or_insert_gdb_debug_scripts_section_global(cx); - } + // Indicate that we want CodeView debug information on MSVC + if sess.target.is_like_msvc { + llvm::LLVMRustAddModuleFlag(self.llmod, "CodeView\0".as_ptr().cast(), 1) + } - unsafe { - llvm::LLVMRustDIBuilderFinalize(DIB(cx)); - // Debuginfo generation in LLVM by default uses a higher - // version of dwarf than macOS currently understands. We can - // instruct LLVM to emit an older version of dwarf, however, - // for macOS to understand. For more info see #11352 - // This can be overridden using --llvm-opts -dwarf-version,N. - // Android has the same issue (#22398) - if let Some(version) = cx.sess().target.dwarf_version { - llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), version) + // Prevent bitcode readers from deleting the debug info. + let ptr = "Debug Info Version\0".as_ptr(); + llvm::LLVMRustAddModuleFlag( + self.llmod, + ptr.cast(), + llvm::LLVMRustDebugMetadataVersion(), + ); } + } +} + +/// Creates any deferred debug metadata nodes +pub fn finalize(cx: &CodegenCx<'_, '_>) { + if let Some(dbg_cx) = &cx.dbg_cx { + debug!("finalize"); - // Indicate that we want CodeView debug information on MSVC - if cx.sess().target.is_like_msvc { - llvm::LLVMRustAddModuleFlag(cx.llmod, "CodeView\0".as_ptr().cast(), 1) + if gdb::needs_gdb_debug_scripts_section(cx) { + // Add a .debug_gdb_scripts section to this compile-unit. This will + // cause GDB to try and load the gdb_load_rust_pretty_printers.py file, + // which activates the Rust pretty printers for binary this section is + // contained in. + gdb::get_or_insert_gdb_debug_scripts_section_global(cx); } - // Prevent bitcode readers from deleting the debug info. - let ptr = "Debug Info Version\0".as_ptr(); - llvm::LLVMRustAddModuleFlag(cx.llmod, ptr.cast(), llvm::LLVMRustDebugMetadataVersion()); - }; + dbg_cx.finalize(cx.sess()); + } } impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> { @@ -320,7 +328,7 @@ // name if necessary. let generics = self.tcx().generics_of(enclosing_fn_def_id); let substs = instance.substs.truncate_to(self.tcx(), generics); - let template_parameters = get_template_parameters(self, &generics, substs, &mut name); + let template_parameters = get_template_parameters(self, generics, substs, &mut name); let linkage_name = &mangled_name_of_instance(self, instance).name; // Omit the linkage_name if it is the same as subprogram name. @@ -542,8 +550,13 @@ unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) } } - fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value) { - metadata::create_vtable_metadata(self, ty, vtable) + fn create_vtable_metadata( + &self, + ty: Ty<'tcx>, + trait_ref: Option>, + vtable: Self::Value, + ) { + metadata::create_vtable_metadata(self, ty, trait_ref, vtable) } fn extend_scope_to_file( @@ -551,7 +564,7 @@ scope_metadata: &'ll DIScope, file: &rustc_span::SourceFile, ) -> &'ll DILexicalBlock { - metadata::extend_scope_to_file(&self, scope_metadata, file) + metadata::extend_scope_to_file(self, scope_metadata, file) } fn debuginfo_finalize(&self) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/intrinsic.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/intrinsic.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/intrinsic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/intrinsic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,12 +15,12 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_hir as hir; -use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{sym, symbol::kw, Span, Symbol}; -use rustc_target::abi::{self, HasDataLayout, LayoutOf, Primitive}; -use rustc_target::spec::PanicStrategy; +use rustc_target::abi::{self, HasDataLayout, Primitive}; +use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use std::cmp::Ordering; use std::iter; @@ -71,7 +71,7 @@ sym::roundf64 => "llvm.round.f64", _ => return None, }; - Some(cx.get_intrinsic(&llvm_name)) + Some(cx.get_intrinsic(llvm_name)) } impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { @@ -96,7 +96,6 @@ let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = tcx.item_name(def_id); - let name_str = &*name.as_str(); let llret_ty = self.layout_of(ret_ty).llvm_type(self); let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); @@ -133,7 +132,7 @@ } sym::va_arg => { match fn_abi.ret.layout.abi { - abi::Abi::Scalar(ref scalar) => { + abi::Abi::Scalar(scalar) => { match scalar.value { Primitive::Int(..) => { if self.cx().size_of(ret_ty).bytes() < 4 { @@ -230,9 +229,14 @@ &[args[0].immediate(), y], ) } - sym::ctlz_nonzero | sym::cttz_nonzero => { + sym::ctlz_nonzero => { let y = self.const_bool(true); - let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width); + let llvm_name = &format!("llvm.ctlz.i{}", width); + self.call_intrinsic(llvm_name, &[args[0].immediate(), y]) + } + sym::cttz_nonzero => { + let y = self.const_bool(true); + let llvm_name = &format!("llvm.cttz.i{}", width); self.call_intrinsic(llvm_name, &[args[0].immediate(), y]) } sym::ctpop => self.call_intrinsic( @@ -353,7 +357,7 @@ return; } - _ if name_str.starts_with("simd_") => { + _ if name.as_str().starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, Err(()) => return, @@ -737,9 +741,9 @@ rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>), ) -> (&'ll Type, &'ll Value) { - let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]); + let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty()); let llty = fn_abi.llvm_type(cx); - let llfn = cx.declare_fn(name, &fn_abi); + let llfn = cx.declare_fn(name, fn_abi); cx.set_frame_pointer_type(llfn); cx.apply_target_cpu_attr(llfn); // FIXME(eddyb) find a nicer way to do this. @@ -843,7 +847,6 @@ let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); - let name_str = &*name.as_str(); if name == sym::simd_select_bitmask { let in_ty = arg_tys[0]; @@ -917,13 +920,30 @@ )); } - if let Some(stripped) = name_str.strip_prefix("simd_shuffle") { - let n: u64 = stripped.parse().unwrap_or_else(|_| { - span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") - }); + if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") { + // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer. + // If there is no suffix, use the index array length. + let n: u64 = if stripped.is_empty() { + // Make sure this is actually an array, since typeck only checks the length-suffixed + // version of this intrinsic. + match args[2].layout.ty.kind() { + ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { + len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| { + span_bug!(span, "could not evaluate shuffle index array length") + }) + } + _ => return_error!( + "simd_shuffle index must be an array of `u32`, got `{}`", + args[2].layout.ty + ), + } + } else { + stripped.parse().unwrap_or_else(|_| { + span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") + }) + }; require_simd!(ret_ty, "return"); - let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( out_len == n, @@ -1139,7 +1159,7 @@ _ => return_error!("unrecognized intrinsic `{}`", name), }; let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str); - let f = bx.declare_cfn(&llvm_name, llvm::UnnamedAddr::No, fn_ty); + let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty); let c = bx.call(fn_ty, f, &args.iter().map(|arg| arg.immediate()).collect::>(), None); Ok(c) @@ -1170,11 +1190,28 @@ // FIXME: use: // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 - fn llvm_vector_str(elem_ty: Ty<'_>, vec_len: u64, no_pointers: usize) -> String { + fn llvm_vector_str( + elem_ty: Ty<'_>, + vec_len: u64, + no_pointers: usize, + bx: &Builder<'a, 'll, 'tcx>, + ) -> String { let p0s: String = "p0".repeat(no_pointers); match *elem_ty.kind() { - ty::Int(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), - ty::Uint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::Int(v) => format!( + "v{}{}i{}", + vec_len, + p0s, + // Normalize to prevent crash if v: IntTy::Isize + v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() + ), + ty::Uint(v) => format!( + "v{}{}i{}", + vec_len, + p0s, + // Normalize to prevent crash if v: UIntTy::Usize + v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() + ), ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), _ => unreachable!(), } @@ -1310,11 +1347,11 @@ // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count); - let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1); - let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx); let llvm_intrinsic = format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str); @@ -1438,11 +1475,11 @@ // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count); - let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1); - let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx); let llvm_intrinsic = format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str); @@ -1773,7 +1810,7 @@ let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64); let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); + let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); let v = bx.call(fn_ty, f, &[lhs, rhs], None); return Ok(v); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -27,8 +27,8 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ErrorReported, FatalError, Handler}; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::ty::TyCtxt; use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; @@ -92,11 +92,12 @@ fn codegen_allocator<'tcx>( &self, tcx: TyCtxt<'tcx>, - mods: &mut ModuleLlvm, + module_llvm: &mut ModuleLlvm, + module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool, ) { - unsafe { allocator::codegen(tcx, mods, kind, has_alloc_error_handler) } + unsafe { allocator::codegen(tcx, module_llvm, module_name, kind, has_alloc_error_handler) } } fn compile_codegen_unit( &self, @@ -210,9 +211,16 @@ match req { PrintRequest::RelocationModels => { println!("Available relocation models:"); - for name in - &["static", "pic", "dynamic-no-pic", "ropi", "rwpi", "ropi-rwpi", "default"] - { + for name in &[ + "static", + "pic", + "pie", + "dynamic-no-pic", + "ropi", + "rwpi", + "ropi-rwpi", + "default", + ] { println!(" {}", name); } println!(); @@ -331,7 +339,7 @@ unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; - let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap()); + let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap()); let tm = match (cgcx.tm_factory)(tm_factory_config) { Ok(m) => m, Err(e) => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/llvm/ffi.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/llvm/ffi.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/llvm/ffi.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/llvm/ffi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -34,11 +34,18 @@ #[repr(C)] pub struct LLVMRustCOFFShortExport { pub name: *const c_char, + pub ordinal_present: bool, + // value of `ordinal` only important when `ordinal_present` is true + pub ordinal: u16, } impl LLVMRustCOFFShortExport { - pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport { - LLVMRustCOFFShortExport { name } + pub fn new(name: *const c_char, ordinal: Option) -> LLVMRustCOFFShortExport { + LLVMRustCOFFShortExport { + name, + ordinal_present: ordinal.is_some(), + ordinal: ordinal.unwrap_or(0), + } } } @@ -216,6 +223,33 @@ RealPredicateTrue = 15, } +impl RealPredicate { + pub fn from_generic(realp: rustc_codegen_ssa::common::RealPredicate) -> Self { + match realp { + rustc_codegen_ssa::common::RealPredicate::RealPredicateFalse => { + RealPredicate::RealPredicateFalse + } + rustc_codegen_ssa::common::RealPredicate::RealOEQ => RealPredicate::RealOEQ, + rustc_codegen_ssa::common::RealPredicate::RealOGT => RealPredicate::RealOGT, + rustc_codegen_ssa::common::RealPredicate::RealOGE => RealPredicate::RealOGE, + rustc_codegen_ssa::common::RealPredicate::RealOLT => RealPredicate::RealOLT, + rustc_codegen_ssa::common::RealPredicate::RealOLE => RealPredicate::RealOLE, + rustc_codegen_ssa::common::RealPredicate::RealONE => RealPredicate::RealONE, + rustc_codegen_ssa::common::RealPredicate::RealORD => RealPredicate::RealORD, + rustc_codegen_ssa::common::RealPredicate::RealUNO => RealPredicate::RealUNO, + rustc_codegen_ssa::common::RealPredicate::RealUEQ => RealPredicate::RealUEQ, + rustc_codegen_ssa::common::RealPredicate::RealUGT => RealPredicate::RealUGT, + rustc_codegen_ssa::common::RealPredicate::RealUGE => RealPredicate::RealUGE, + rustc_codegen_ssa::common::RealPredicate::RealULT => RealPredicate::RealULT, + rustc_codegen_ssa::common::RealPredicate::RealULE => RealPredicate::RealULE, + rustc_codegen_ssa::common::RealPredicate::RealUNE => RealPredicate::RealUNE, + rustc_codegen_ssa::common::RealPredicate::RealPredicateTrue => { + RealPredicate::RealPredicateTrue + } + } + } +} + /// LLVMTypeKind #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] @@ -789,7 +823,7 @@ start_line, start_col, end_line, - end_col: ((1 as u32) << 31) | end_col, + end_col: (1_u32 << 31) | end_col, kind: RegionKind::GapRegion, } } @@ -2176,6 +2210,7 @@ PrepareForThinLTO: bool, PGOGenPath: *const c_char, PGOUsePath: *const c_char, + PGOSampleUsePath: *const c_char, ); pub fn LLVMRustAddLibraryInfo( PM: &PassManager<'a>, @@ -2210,6 +2245,8 @@ PGOUsePath: *const c_char, InstrumentCoverage: bool, InstrumentGCOV: bool, + PGOSampleUsePath: *const c_char, + DebugInfoForProfiling: bool, llvm_selfprofiler: *mut c_void, begin_callback: SelfProfileBeforePassCallback, end_callback: SelfProfileAfterPassCallback, @@ -2377,12 +2414,8 @@ len: usize, out_len: &mut usize, ) -> *const u8; - pub fn LLVMRustThinLTOGetDICompileUnit( - M: &Module, - CU1: &mut *mut c_void, - CU2: &mut *mut c_void, - ); - pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void); + pub fn LLVMRustLTOGetDICompileUnit(M: &Module, CU1: &mut *mut c_void, CU2: &mut *mut c_void); + pub fn LLVMRustLTOPatchDICompileUnit(M: &Module, CU: *mut c_void); pub fn LLVMRustLinkerNew(M: &'a Module) -> &'a mut Linker<'a>; pub fn LLVMRustLinkerAdd( diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/llvm_util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/llvm_util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/llvm_util.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/llvm_util.rs 2021-11-29 19:27:11.000000000 +0000 @@ -166,25 +166,32 @@ // Though note that Rust can also be build with an external precompiled version of LLVM // which might lead to failures if the oldest tested / supported LLVM version // doesn't yet support the relevant intrinsics -pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { +pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> { let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { - ("x86", "pclmulqdq") => "pclmul", - ("x86", "rdrand") => "rdrnd", - ("x86", "bmi1") => "bmi", - ("x86", "cmpxchg16b") => "cx16", - ("x86", "avx512vaes") => "vaes", - ("x86", "avx512gfni") => "gfni", - ("x86", "avx512vpclmulqdq") => "vpclmulqdq", - ("aarch64", "fp") => "fp-armv8", - ("aarch64", "fp16") => "fullfp16", - ("aarch64", "fhm") => "fp16fml", - ("aarch64", "rcpc2") => "rcpc-immo", - ("aarch64", "dpb") => "ccpp", - ("aarch64", "dpb2") => "ccdp", - ("aarch64", "frintts") => "fptoint", - ("aarch64", "fcma") => "complxnum", - (_, s) => s, + ("x86", "sse4.2") => { + if get_version() >= (14, 0, 0) { + vec!["sse4.2", "crc32"] + } else { + vec!["sse4.2"] + } + } + ("x86", "pclmulqdq") => vec!["pclmul"], + ("x86", "rdrand") => vec!["rdrnd"], + ("x86", "bmi1") => vec!["bmi"], + ("x86", "cmpxchg16b") => vec!["cx16"], + ("x86", "avx512vaes") => vec!["vaes"], + ("x86", "avx512gfni") => vec!["gfni"], + ("x86", "avx512vpclmulqdq") => vec!["vpclmulqdq"], + ("aarch64", "fp") => vec!["fp-armv8"], + ("aarch64", "fp16") => vec!["fullfp16"], + ("aarch64", "fhm") => vec!["fp16fml"], + ("aarch64", "rcpc2") => vec!["rcpc-immo"], + ("aarch64", "dpb") => vec!["ccpp"], + ("aarch64", "dpb2") => vec!["ccdp"], + ("aarch64", "frintts") => vec!["fptoint"], + ("aarch64", "fcma") => vec!["complxnum"], + (_, s) => vec![s], } } @@ -198,9 +205,13 @@ }, ) .filter(|feature| { - let llvm_feature = to_llvm_feature(sess, feature); - let cstr = CString::new(llvm_feature).unwrap(); - unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } + for llvm_feature in to_llvm_feature(sess, feature) { + let cstr = CString::new(llvm_feature).unwrap(); + if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { + return true; + } + } + false }) .map(|feature| Symbol::intern(feature)) .collect() @@ -253,12 +264,19 @@ let mut rustc_target_features = supported_target_features(sess) .iter() .filter_map(|(feature, _gate)| { - let llvm_feature = to_llvm_feature(sess, *feature); - // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. - target_features.binary_search_by_key(&llvm_feature, |(f, _d)| *f).ok().map(|index| { - let (_f, desc) = target_features.remove(index); - (*feature, desc) - }) + for llvm_feature in to_llvm_feature(sess, *feature) { + // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. + match target_features.binary_search_by_key(&llvm_feature, |(f, _d)| (*f)).ok().map( + |index| { + let (_f, desc) = target_features.remove(index); + (*feature, desc) + }, + ) { + Some(v) => return Some(v), + None => {} + } + } + None }) .collect::>(); rustc_target_features.extend_from_slice(&[( @@ -280,7 +298,7 @@ for (feature, desc) in &target_features { println!(" {1:0$} - {2}.", max_feature_len, feature, desc); } - if target_features.len() == 0 { + if target_features.is_empty() { println!(" Target features listing is not supported by this LLVM version."); } println!("\nUse +feature to enable a feature, or -feature to disable it."); @@ -373,30 +391,38 @@ let filter = |s: &str| { if s.is_empty() { - return None; + return vec![]; } let feature = if s.starts_with('+') || s.starts_with('-') { &s[1..] } else { - return Some(s.to_string()); + return vec![s.to_string()]; }; // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. if RUSTC_SPECIFIC_FEATURES.contains(&feature) { - return None; + return vec![]; } // ... otherwise though we run through `to_llvm_feature` feature when // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two // different names when the LLVM name and the Rust name differ. - Some(format!("{}{}", &s[..1], to_llvm_feature(sess, feature))) + to_llvm_feature(sess, feature).iter().map(|f| format!("{}{}", &s[..1], f)).collect() }; // Features implied by an implicit or explicit `--target`. - features.extend(sess.target.features.split(',').filter_map(&filter)); + features.extend(sess.target.features.split(',').flat_map(&filter)); // -Ctarget-features - features.extend(sess.opts.cg.target_feature.split(',').filter_map(&filter)); + features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter)); + + // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12. + if get_version() >= (12, 0, 0) + && sess.target.llvm_target.contains("aarch64-unknown-linux") + && sess.target.llvm_target != "aarch64-unknown-linux-musl" + { + features.push("+outline-atomics".to_string()); + } features } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/mono_item.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/mono_item.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/mono_item.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/mono_item.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -use crate::abi::FnAbi; use crate::attributes; use crate::base; use crate::context::CodegenCx; @@ -8,10 +7,9 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; pub use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::layout::FnAbiExt; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeFoldable}; use rustc_session::config::CrateType; -use rustc_target::abi::LayoutOf; use rustc_target::spec::RelocModel; use tracing::debug; @@ -54,11 +52,11 @@ ) { assert!(!instance.substs.needs_infer()); - let fn_abi = FnAbi::of_instance(self, instance, &[]); - let lldecl = self.declare_fn(symbol_name, &fn_abi); + let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); + let lldecl = self.declare_fn(symbol_name, fn_abi); unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - base::set_link_section(lldecl, &attrs); + base::set_link_section(lldecl, attrs); if linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR { llvm::SetUniqueComdat(self.llmod, lldecl); } @@ -145,6 +143,8 @@ return true; } - return false; + // With pie relocation model calls of functions defined in the translation + // unit can use copy relocations. + self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/type_of.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/type_of.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/type_of.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/type_of.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,15 +1,14 @@ -use crate::abi::FnAbi; use crate::common::*; use crate::context::TypeLowering; use crate::type_::Type; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; -use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; +use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; -use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; +use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; use smallvec::{smallvec, SmallVec}; use tracing::debug; @@ -23,7 +22,7 @@ ) -> &'a Type { match layout.abi { Abi::Scalar(_) => bug!("handled elsewhere"), - Abi::Vector { ref element, count } => { + Abi::Vector { element, count } => { let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); return cx.type_vector(element, count); } @@ -44,7 +43,8 @@ // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str => { - let mut name = with_no_trimmed_paths(|| layout.ty.to_string()); + let mut name = + with_no_visible_paths(|| with_no_trimmed_paths(|| layout.ty.to_string())); if let (&ty::Adt(def, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) { @@ -177,7 +177,7 @@ fn scalar_llvm_type_at<'a>( &self, cx: &CodegenCx<'a, 'tcx>, - scalar: &Scalar, + scalar: Scalar, offset: Size, ) -> &'a Type; fn scalar_pair_element_llvm_type<'a>( @@ -218,7 +218,7 @@ /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { - if let Abi::Scalar(ref scalar) = self.abi { + if let Abi::Scalar(scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs // can be either fat or thin (data pointers of fat pointers). if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { @@ -231,7 +231,9 @@ ty::Adt(def, _) if def.is_box() => { cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx)) } - ty::FnPtr(sig) => cx.fn_ptr_backend_type(&FnAbi::of_fn_ptr(cx, sig, &[])), + ty::FnPtr(sig) => { + cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty())) + } _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO), }; cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); @@ -243,7 +245,7 @@ Variants::Single { index } => Some(index), _ => None, }; - if let Some(ref llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) { + if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) { return llty.lltype; } @@ -268,10 +270,9 @@ }; debug!("--> mapped {:#?} to llty={:?}", self, llty); - cx.type_lowering.borrow_mut().insert( - (self.ty, variant_index), - TypeLowering { lltype: llty, field_remapping: field_remapping }, - ); + cx.type_lowering + .borrow_mut() + .insert((self.ty, variant_index), TypeLowering { lltype: llty, field_remapping }); if let Some((llty, layout)) = defer { let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout); @@ -286,7 +287,7 @@ } fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { - if let Abi::Scalar(ref scalar) = self.abi { + if let Abi::Scalar(scalar) = self.abi { if scalar.is_bool() { return cx.type_i1(); } @@ -297,7 +298,7 @@ fn scalar_llvm_type_at<'a>( &self, cx: &CodegenCx<'a, 'tcx>, - scalar: &Scalar, + scalar: Scalar, offset: Size, ) -> &'a Type { match scalar.value { @@ -337,7 +338,7 @@ } let (a, b) = match self.abi { - Abi::ScalarPair(ref a, ref b) => (a, b), + Abi::ScalarPair(a, b) => (a, b), _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self), }; let scalar = [a, b][index]; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/type_.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/type_.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/type_.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/type_.rs 2021-11-29 19:27:11.000000000 +0000 @@ -248,7 +248,7 @@ } fn ptr_to(&self, address_space: AddressSpace) -> &Type { - unsafe { llvm::LLVMPointerType(&self, address_space.0) } + unsafe { llvm::LLVMPointerType(self, address_space.0) } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/va_arg.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/va_arg.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/va_arg.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_llvm/src/va_arg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,9 +7,9 @@ common::IntPredicate, traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods}, }; -use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::Ty; -use rustc_target::abi::{Align, Endian, HasDataLayout, LayoutOf, Size}; +use rustc_target::abi::{Align, Endian, HasDataLayout, Size}; fn round_pointer_up_to_alignment( bx: &mut Builder<'a, 'll, 'tcx>, @@ -125,7 +125,7 @@ // if the offset >= 0 then the value will be on the stack let mut reg_off_v = bx.load(bx.type_i32(), reg_off, offset_align); let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero); - bx.cond_br(use_stack, &on_stack.llbb(), &maybe_reg.llbb()); + bx.cond_br(use_stack, on_stack.llbb(), maybe_reg.llbb()); // The value at this point might be in a register, but there is a chance that // it could be on the stack so we have to update the offset and then check @@ -142,7 +142,7 @@ // Check to see if we have overflowed the registers as a result of this. // If we have then we need to use the stack for this value let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero); - maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb()); + maybe_reg.cond_br(use_stack, on_stack.llbb(), in_reg.llbb()); let top_type = bx.type_i8p(); let top = in_reg.struct_gep(va_list_ty, va_list_addr, reg_top_index); @@ -158,17 +158,17 @@ let reg_type = layout.llvm_type(bx); let reg_addr = in_reg.bitcast(reg_addr, bx.cx.type_ptr_to(reg_type)); let reg_value = in_reg.load(reg_type, reg_addr, layout.align.abi); - in_reg.br(&end.llbb()); + in_reg.br(end.llbb()); // On Stack block let stack_value = emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true); - on_stack.br(&end.llbb()); + on_stack.br(end.llbb()); let val = end.phi( layout.immediate_llvm_type(bx), &[reg_value, stack_value], - &[&in_reg.llbb(), &on_stack.llbb()], + &[in_reg.llbb(), on_stack.llbb()], ); *bx = end; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_codegen_ssa" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] test = false @@ -32,6 +32,8 @@ rustc_incremental = { path = "../rustc_incremental" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_query_system = { path = "../rustc_query_system" } rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/archive.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/archive.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/archive.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/archive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,12 @@ use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_middle::middle::cstore::DllImport; +use rustc_session::cstore::DllImport; use rustc_session::Session; use rustc_span::symbol::Symbol; use std::io; use std::path::{Path, PathBuf}; -pub fn find_library( +pub(super) fn find_library( name: Symbol, verbatim: bool, search_paths: &[PathBuf], @@ -48,14 +48,9 @@ fn remove_file(&mut self, name: &str); fn src_files(&mut self) -> Vec; - fn add_rlib( - &mut self, - path: &Path, - name: &str, - lto: bool, - skip_objects: bool, - ) -> io::Result<()>; - fn add_native_library(&mut self, name: Symbol, verbatim: bool); + fn add_archive(&mut self, archive: &Path, skip: F) -> io::Result<()> + where + F: FnMut(&str) -> bool + 'static; fn update_symbols(&mut self); fn build(self); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/linker.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/linker.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/linker.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/linker.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,7 +15,6 @@ use rustc_middle::ty::TyCtxt; use rustc_serialize::{json, Encoder}; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; -use rustc_session::search_paths::PathKind; use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; @@ -101,7 +100,7 @@ // The compiler's sysroot often has some bundled tools, so add it to the // PATH for the child. - let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained); + let mut new_path = sess.get_tools_search_paths(self_contained); let mut msvc_changed_path = false; if sess.target.is_like_msvc { if let Some(ref tool) = msvc_tool { @@ -287,6 +286,9 @@ config::OptLevel::Aggressive => "O3", }; + if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use { + self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); + }; self.linker_arg(&format!("-plugin-opt={}", opt_level)); self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu)); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/link.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/link.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/link.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/link.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,10 +3,10 @@ use rustc_errors::{ErrorReported, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::DllImport; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; +use rustc_session::cstore::DllImport; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; @@ -19,7 +19,7 @@ use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo}; use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target}; -use super::archive::ArchiveBuilder; +use super::archive::{find_library, ArchiveBuilder}; use super::command::Command; use super::linker::{self, Linker}; use super::rpath::{self, RPathConfig}; @@ -36,6 +36,7 @@ use tempfile::Builder as TempFileBuilder; use std::ffi::OsString; +use std::lazy::OnceCell; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{ascii, char, env, fmt, fs, io, mem, str}; @@ -230,6 +231,9 @@ tmpdir: &MaybeTempDir, ) -> Result { info!("preparing rlib to {:?}", out_filename); + + let lib_search_paths = archive_search_paths(sess); + let mut ab = ::new(sess, out_filename, None); for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { @@ -254,6 +258,19 @@ // metadata of the rlib we're generating somehow. for lib in codegen_results.crate_info.used_libraries.iter() { match lib.kind { + NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) } + if flavor == RlibFlavor::Normal => + { + // Don't allow mixing +bundle with +whole_archive since an rlib may contain + // multiple native libs, some of which are +whole-archive and some of which are + // -whole-archive and it isn't clear how we can currently handle such a + // situation correctly. + // See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897 + sess.err( + "the linking modifiers `+bundle` and `+whole-archive` are not compatible \ + with each other when generating rlibs", + ); + } NativeLibKind::Static { bundle: None | Some(true), .. } => {} NativeLibKind::Static { bundle: Some(false), .. } | NativeLibKind::Dylib { .. } @@ -262,7 +279,15 @@ | NativeLibKind::Unspecified => continue, } if let Some(name) = lib.name { - ab.add_native_library(name, lib.verbatim.unwrap_or(false)); + let location = + find_library(name, lib.verbatim.unwrap_or(false), &lib_search_paths, sess); + ab.add_archive(&location, |_| false).unwrap_or_else(|e| { + sess.fatal(&format!( + "failed to add native library {}: {}", + location.to_string_lossy(), + e + )); + }); } } @@ -302,7 +327,7 @@ // metadata in rlib files is wrapped in a "dummy" object file for // the target platform so the rlib can be processed entirely by // normal linkers for the platform. - let metadata = create_metadata_file(sess, &codegen_results.metadata.raw_data); + let metadata = create_metadata_file(sess, codegen_results.metadata.raw_data()); ab.add_file(&emit_metadata(sess, &metadata, tmpdir)); // After adding all files to the archive, we need to update the @@ -541,13 +566,35 @@ matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. }) && !relevant_lib(sess, lib) }); - ab.add_rlib( - path, - &name.as_str(), - are_upstream_rust_objects_already_included(sess) - && !ignored_for_lto(sess, &codegen_results.crate_info, cnum), - skip_object_files, - ) + + let lto = are_upstream_rust_objects_already_included(sess) + && !ignored_for_lto(sess, &codegen_results.crate_info, cnum); + + // Ignoring obj file starting with the crate name + // as simple comparison is not enough - there + // might be also an extra name suffix + let obj_start = name.as_str().to_owned(); + + ab.add_archive(path, move |fname: &str| { + // Ignore metadata files, no matter the name. + if fname == METADATA_FILENAME { + return true; + } + + // Don't include Rust objects if LTO is enabled + if lto && looks_like_rust_object_file(fname) { + return true; + } + + // Otherwise if this is *not* a rust object and we're skipping + // objects then skip this file + if skip_object_files && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { + return true; + } + + // ok, don't skip this + false + }) .unwrap(); all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned()); @@ -590,7 +637,7 @@ cmd.arg("-o"); cmd.arg(&dwp_out_filename); - let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(false); + let mut new_path = sess.get_tools_search_paths(false); if let Some(path) = env::var_os("PATH") { new_path.extend(env::split_paths(&path)); } @@ -796,19 +843,18 @@ let msg_bus = "clang: error: unable to execute command: Bus error: 10"; if out.contains(msg_segv) || out.contains(msg_bus) { warn!( + ?cmd, %out, "looks like the linker segfaulted when we tried to call it, \ - automatically retrying again. cmd = {:?}, out = {}.", - cmd, out, + automatically retrying again", ); continue; } if is_illegal_instruction(&output.status) { warn!( + ?cmd, %out, status = %output.status, "looks like the linker hit an illegal instruction when we \ - tried to call it, automatically retrying again. cmd = {:?}, ]\ - out = {}, status = {}.", - cmd, out, output.status, + tried to call it, automatically retrying again.", ); continue; } @@ -977,14 +1023,20 @@ } if sess.target.is_like_osx { - if let Some(option) = osx_strip_opt(sess.opts.debugging_opts.strip) { - strip_symbols_in_osx(sess, &out_filename, option); + match sess.opts.debugging_opts.strip { + Strip::Debuginfo => strip_symbols_in_osx(sess, &out_filename, Some("-S")), + Strip::Symbols => strip_symbols_in_osx(sess, &out_filename, None), + Strip::None => {} } } } -fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: &str) { - let prog = Command::new("strip").arg(option).arg(out_filename).output(); +fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) { + let mut cmd = Command::new("strip"); + if let Some(option) = option { + cmd.arg(option); + } + let prog = cmd.arg(out_filename).output(); match prog { Ok(prog) => { if !prog.status.success() { @@ -1002,14 +1054,6 @@ } } -fn osx_strip_opt<'a>(strip: Strip) -> Option<&'a str> { - match strip { - Strip::Debuginfo => Some("-S"), - Strip::Symbols => Some("-x"), - Strip::None => None, - } -} - fn escape_string(s: &[u8]) -> String { str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { let mut x = "Non-UTF-8 output: ".to_string(); @@ -1218,10 +1262,11 @@ sess.split_debuginfo() == SplitDebuginfo::Unpacked } -pub fn archive_search_paths(sess: &Session) -> Vec { +fn archive_search_paths(sess: &Session) -> Vec { sess.target_filesearch(PathKind::Native).search_path_dirs() } +#[derive(PartialEq)] enum RlibFlavor { Normal, StaticlibBase, @@ -1442,9 +1487,13 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { let kind = match (crate_type, sess.crt_static(Some(crate_type)), sess.relocation_model()) { (CrateType::Executable, _, _) if sess.is_wasi_reactor() => LinkOutputKind::WasiReactorExe, - (CrateType::Executable, false, RelocModel::Pic) => LinkOutputKind::DynamicPicExe, + (CrateType::Executable, false, RelocModel::Pic | RelocModel::Pie) => { + LinkOutputKind::DynamicPicExe + } (CrateType::Executable, false, _) => LinkOutputKind::DynamicNoPicExe, - (CrateType::Executable, true, RelocModel::Pic) => LinkOutputKind::StaticPicExe, + (CrateType::Executable, true, RelocModel::Pic | RelocModel::Pie) => { + LinkOutputKind::StaticPicExe + } (CrateType::Executable, true, _) => LinkOutputKind::StaticNoPicExe, (_, true, _) => LinkOutputKind::StaticDylib, (_, false, _) => LinkOutputKind::DynamicDylib, @@ -2001,7 +2050,7 @@ let relevant_libs = codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l)); - let search_path = archive_search_paths(sess); + let search_path = OnceCell::new(); let mut last = (NativeLibKind::Unspecified, None); for lib in relevant_libs { let name = match lib.name { @@ -2023,7 +2072,11 @@ } NativeLibKind::Static { bundle: None | Some(true), .. } | NativeLibKind::Static { whole_archive: Some(true), .. } => { - cmd.link_whole_staticlib(name, verbatim, &search_path); + cmd.link_whole_staticlib( + name, + verbatim, + &search_path.get_or_init(|| archive_search_paths(sess)), + ); } NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim), NativeLibKind::RawDylib => { @@ -2116,6 +2169,7 @@ } let mut compiler_builtins = None; + let search_path = OnceCell::new(); for &cnum in deps.iter() { if group_start == Some(cnum) { @@ -2149,16 +2203,35 @@ // external build system already has the native dependencies defined, and it // will provide them to the linker itself. if sess.opts.debugging_opts.link_native_libraries { - // Skip if this library is the same as the last. let mut last = None; for lib in &codegen_results.crate_info.native_libraries[&cnum] { - if lib.name.is_some() - && relevant_lib(sess, lib) - && matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. }) - && last != lib.name - { - cmd.link_staticlib(lib.name.unwrap(), lib.verbatim.unwrap_or(false)); - last = lib.name; + if !relevant_lib(sess, lib) { + // Skip libraries if they are disabled by `#[link(cfg=...)]` + continue; + } + + // Skip if this library is the same as the last. + if last == lib.name { + continue; + } + + if let Some(static_lib_name) = lib.name { + if let NativeLibKind::Static { bundle: Some(false), whole_archive } = + lib.kind + { + let verbatim = lib.verbatim.unwrap_or(false); + if whole_archive == Some(true) { + cmd.link_whole_staticlib( + static_lib_name, + verbatim, + search_path.get_or_init(|| archive_search_paths(sess)), + ); + } else { + cmd.link_staticlib(static_lib_name, verbatim); + } + + last = lib.name; + } } } } @@ -2483,8 +2556,7 @@ match ld_impl { LdImpl::Lld => { if sess.target.lld_flavor == LldFlavor::Ld64 { - let tools_path = - sess.host_filesearch(PathKind::All).get_tools_search_paths(false); + let tools_path = sess.get_tools_search_paths(false); let ld64_exe = tools_path .into_iter() .map(|p| p.join("gcc-ld")) @@ -2499,8 +2571,7 @@ arg }); } else { - let tools_path = - sess.host_filesearch(PathKind::All).get_tools_search_paths(false); + let tools_path = sess.get_tools_search_paths(false); let lld_path = tools_path .into_iter() .map(|p| p.join("gcc-ld")) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/metadata.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/metadata.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/metadata.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/metadata.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::rustc_erase_owner; use rustc_data_structures::sync::MetadataRef; -use rustc_middle::middle::cstore::MetadataLoader; +use rustc_session::cstore::MetadataLoader; use rustc_target::spec::Target; use crate::METADATA_FILENAME; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/write.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/write.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/write.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/back/write.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,8 +21,8 @@ use rustc_incremental::{ copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess, }; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::exported_symbols::SymbolExportLevel; use rustc_middle::ty::TyCtxt; use rustc_session::cgu_reuse_tracker::CguReuseTracker; @@ -83,6 +83,8 @@ pub pgo_gen: SwitchWithOptPath, pub pgo_use: Option, + pub pgo_sample_use: Option, + pub debug_info_for_profiling: bool, pub instrument_coverage: bool, pub instrument_gcov: bool, @@ -176,6 +178,8 @@ SwitchWithOptPath::Disabled ), pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None), + pgo_sample_use: if_regular!(sess.opts.debugging_opts.profile_sample_use.clone(), None), + debug_info_for_profiling: sess.opts.debugging_opts.debug_info_for_profiling, instrument_coverage: if_regular!(sess.instrument_coverage(), false), instrument_gcov: if_regular!( // compiler_builtins overrides the codegen-units settings, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/base.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/base.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/base.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/base.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,18 +18,18 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; +use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::lang_items; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; -use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, EntryFnType}; use rustc_session::Session; use rustc_span::symbol::sym; -use rustc_target::abi::{Align, LayoutOf, VariantIdx}; +use rustc_target::abi::{Align, VariantIdx}; use std::convert::TryFrom; use std::ops::{Deref, DerefMut}; @@ -538,12 +538,18 @@ } else if let Some(kind) = tcx.allocator_kind(()) { let llmod_id = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); - let mut modules = backend.new_metadata(tcx, &llmod_id); + let mut module_llvm = backend.new_metadata(tcx, &llmod_id); tcx.sess.time("write_allocator_module", || { - backend.codegen_allocator(tcx, &mut modules, kind, tcx.lang_items().oom().is_some()) + backend.codegen_allocator( + tcx, + &mut module_llvm, + &llmod_id, + kind, + tcx.lang_items().oom().is_some(), + ) }); - Some(ModuleCodegen { name: llmod_id, module_llvm: modules, kind: ModuleKind::Allocator }) + Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }) } else { None }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,10 +16,10 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; -use rustc_middle::ich::NodeIdHashingMode; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, AdtDef, ExistentialProjection, Ty, TyCtxt}; +use rustc_query_system::ich::NodeIdHashingMode; use rustc_target::abi::{Integer, TagEncoding, Variants}; use smallvec::SmallVec; @@ -404,7 +404,7 @@ // calculate the range of values for the dataful variant let dataful_discriminant_range = - &dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range; + dataful_variant_layout.largest_niche.unwrap().scalar.valid_range; let min = dataful_discriminant_range.start; let min = tag.value.size(&tcx).truncate(min); @@ -446,6 +446,59 @@ } } +/// Computes a name for the global variable storing a vtable. +/// +/// The name is of the form: +/// +/// `::{vtable}` +/// +/// or, when generating C++-like names: +/// +/// `impl$::vtable$` +pub fn compute_debuginfo_vtable_name<'tcx>( + tcx: TyCtxt<'tcx>, + t: Ty<'tcx>, + trait_ref: Option>, +) -> String { + let cpp_like_names = cpp_like_names(tcx); + + let mut vtable_name = String::with_capacity(64); + + if cpp_like_names { + vtable_name.push_str("impl$<"); + } else { + vtable_name.push('<'); + } + + let mut visited = FxHashSet::default(); + push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited); + + if cpp_like_names { + vtable_name.push_str(", "); + } else { + vtable_name.push_str(" as "); + } + + if let Some(trait_ref) = trait_ref { + let trait_ref = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref); + push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name); + visited.clear(); + push_generic_params_internal(tcx, trait_ref.substs, &mut vtable_name, &mut visited); + } else { + vtable_name.push_str("_"); + } + + push_close_angle_bracket(cpp_like_names, &mut vtable_name); + + let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" }; + + vtable_name.reserve_exact(suffix.len()); + vtable_name.push_str(suffix); + + vtable_name +} + pub fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) { let def_key = tcx.def_key(def_id); if qualified { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,6 +3,7 @@ #![feature(box_patterns)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] +#![feature(once_cell)] #![feature(nll)] #![feature(associated_type_bounds)] #![recursion_limit = "256"] @@ -24,10 +25,10 @@ use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::cstore::{self, CrateSource}; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::ty::query::Providers; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; +use rustc_session::cstore::{self, CrateSource}; use rustc_session::utils::NativeLibKind; use rustc_span::symbol::Symbol; use std::path::{Path, PathBuf}; @@ -157,7 +158,7 @@ pub modules: Vec, pub allocator_module: Option, pub metadata_module: Option, - pub metadata: rustc_middle::middle::cstore::EncodedMetadata, + pub metadata: rustc_metadata::EncodedMetadata, pub crate_info: CrateInfo, } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/meth.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/meth.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/meth.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/meth.rs 2021-11-29 19:27:11.000000000 +0000 @@ -78,7 +78,7 @@ let align = cx.data_layout().pointer_align.abi; let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); - cx.create_vtable_metadata(ty, vtable); + cx.create_vtable_metadata(ty, trait_ref, vtable); cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/analyze.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/analyze.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/analyze.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/analyze.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,8 +9,7 @@ use rustc_middle::mir::traversal; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, Location, TerminatorKind}; -use rustc_middle::ty::layout::HasTyCtxt; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx: &FunctionCx<'a, 'tcx, Bx>, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/block.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/block.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/block.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/block.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,13 +14,13 @@ use rustc_index::vec::Idx; use rustc_middle::mir::AssertKind; use rustc_middle::mir::{self, SwitchTargets}; -use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; -use rustc_target::abi::{self, HasDataLayout, LayoutOf}; +use rustc_target::abi::{self, HasDataLayout, WrappingRange}; use rustc_target::spec::abi::Abi; /// Used by `FunctionCx::codegen_terminator` for emitting common patterns @@ -124,7 +124,7 @@ &self, fx: &mut FunctionCx<'a, 'tcx, Bx>, bx: &mut Bx, - fn_abi: FnAbi<'tcx, Ty<'tcx>>, + fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, fn_ptr: Bx::Value, llargs: &[Bx::Value], destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, @@ -337,7 +337,7 @@ def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), substs: drop_fn.substs, }; - let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]); + let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); let vtable = args[1]; args = &args[..1]; ( @@ -346,7 +346,7 @@ fn_abi, ) } - _ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])), + _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())), }; helper.do_call( self, @@ -433,7 +433,7 @@ // Obtain the panic entry point. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_abi = FnAbi::of_instance(&bx, instance, &[]); + let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); let llfn = bx.get_fn_addr(instance); // Codegen the actual panic invoke/call. @@ -476,15 +476,20 @@ UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false), }; if do_panic { - let msg_str = with_no_trimmed_paths(|| { - if layout.abi.is_uninhabited() { - // Use this error even for the other intrinsics as it is more precise. - format!("attempted to instantiate uninhabited type `{}`", ty) - } else if intrinsic == ZeroValid { - format!("attempted to zero-initialize type `{}`, which is invalid", ty) - } else { - format!("attempted to leave type `{}` uninitialized, which is invalid", ty) - } + let msg_str = with_no_visible_paths(|| { + with_no_trimmed_paths(|| { + if layout.abi.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{}`", ty) + } else if intrinsic == ZeroValid { + format!("attempted to zero-initialize type `{}`, which is invalid", ty) + } else { + format!( + "attempted to leave type `{}` uninitialized, which is invalid", + ty + ) + } + }) }); let msg = bx.const_str(Symbol::intern(&msg_str)); let location = self.get_caller_location(bx, source_info).immediate(); @@ -494,7 +499,7 @@ let def_id = common::langcall(bx.tcx(), Some(source_info.span), "", LangItem::Panic); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_abi = FnAbi::of_instance(bx, instance, &[]); + let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); let llfn = bx.get_fn_addr(instance); // Codegen the actual panic invoke/call. @@ -570,17 +575,14 @@ }; let extra_args = &args[sig.inputs().skip_binder().len()..]; - let extra_args = extra_args - .iter() - .map(|op_arg| { - let op_ty = op_arg.ty(self.mir, bx.tcx()); - self.monomorphize(op_ty) - }) - .collect::>(); + let extra_args = bx.tcx().mk_type_list(extra_args.iter().map(|op_arg| { + let op_ty = op_arg.ty(self.mir, bx.tcx()); + self.monomorphize(op_ty) + })); let fn_abi = match instance { - Some(instance) => FnAbi::of_instance(&bx, instance, &extra_args), - None => FnAbi::of_fn_ptr(&bx, sig, &extra_args), + Some(instance) => bx.fn_abi_of_instance(instance, extra_args), + None => bx.fn_abi_of_fn_ptr(sig, extra_args), }; if intrinsic == Some(sym::transmute) { @@ -665,8 +667,12 @@ if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") { if let mir::Operand::Constant(constant) = arg { let c = self.eval_mir_constant(constant); - let (llval, ty) = - self.simd_shuffle_indices(&bx, constant.span, constant.ty(), c); + let (llval, ty) = self.simd_shuffle_indices( + &bx, + constant.span, + self.monomorphize(constant.ty()), + c, + ); return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty), @@ -776,22 +782,30 @@ self.codegen_argument(&mut bx, op, &mut llargs, &fn_abi.args[i]); } - if let Some(tup) = untuple { + let num_untupled = untuple.map(|tup| { self.codegen_arguments_untupled( &mut bx, tup, &mut llargs, &fn_abi.args[first_args.len()..], ) - } + }); let needs_location = instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx())); if needs_location { + let mir_args = if let Some(num_untupled) = num_untupled { + first_args.len() + num_untupled + } else { + args.len() + }; assert_eq!( fn_abi.args.len(), - args.len() + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + mir_args + 1, + "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {:?} {:?} {:?}", + instance, + fn_span, + fn_abi, ); let location = self.get_caller_location(&mut bx, mir::SourceInfo { span: fn_span, ..source_info }); @@ -1102,9 +1116,9 @@ // the load would just produce `OperandValue::Ref` instead // of the `OperandValue::Immediate` we need for the call. llval = bx.load(bx.backend_type(arg.layout), llval, align); - if let abi::Abi::Scalar(ref scalar) = arg.layout.abi { + if let abi::Abi::Scalar(scalar) = arg.layout.abi { if scalar.is_bool() { - bx.range_metadata(llval, 0..2); + bx.range_metadata(llval, WrappingRange { start: 0, end: 1 }); } } // We store bools as `i8` so we need to truncate to `i1`. @@ -1121,7 +1135,7 @@ operand: &mir::Operand<'tcx>, llargs: &mut Vec, args: &[ArgAbi<'tcx, Ty<'tcx>>], - ) { + ) -> usize { let tuple = self.codegen_operand(bx, operand); // Handle both by-ref and immediate tuples. @@ -1141,6 +1155,7 @@ self.codegen_argument(bx, op, llargs, &args[i]); } } + tuple.layout.fields.count() } fn get_caller_location( @@ -1424,7 +1439,7 @@ let src = self.codegen_operand(bx, src); // Special-case transmutes between scalars as simple bitcasts. - match (&src.layout.abi, &dst.layout.abi) { + match (src.layout.abi, dst.layout.abi) { (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => { // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers. if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/constant.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/constant.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/constant.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/constant.rs 2021-11-29 19:27:11.000000000 +0000 @@ -68,7 +68,7 @@ if let Some(prim) = field.val.try_to_scalar() { let layout = bx.layout_of(field_ty); let scalar = match layout.abi { - Abi::Scalar(ref x) => x, + Abi::Scalar(x) => x, _ => bug!("from_const: invalid ByVal layout: {:#?}", layout), }; bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,9 +3,11 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; +use rustc_middle::ty::layout::LayoutOf; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; +use rustc_target::abi::Abi; use rustc_target::abi::Size; use super::operand::{OperandRef, OperandValue}; @@ -368,21 +370,14 @@ { let arg_index = place.local.index() - 1; if target_is_msvc { - // Rust compiler decomposes every &str or slice argument into two components: - // a pointer to the memory address where the data is stored and a usize representing - // the length of the str (or slice). These components will later be used to reconstruct - // the original argument inside the body of the function that owns it (see the - // definition of debug_introduce_local for more details). - // - // Since the original argument is declared inside a function rather than being passed - // in as an argument, it must be marked as a LocalVariable for MSVC debuggers to visualize - // its data correctly. (See issue #81894 for an in-depth description of the problem). - match *var_ty.kind() { - ty::Ref(_, inner_type, _) => match *inner_type.kind() { - ty::Slice(_) | ty::Str => VariableKind::LocalVariable, - _ => VariableKind::ArgumentVariable(arg_index + 1), - }, - _ => VariableKind::ArgumentVariable(arg_index + 1), + // ScalarPair parameters are spilled to the stack so they need to + // be marked as a `LocalVariable` for MSVC debuggers to visualize + // their data correctly. (See #81894 & #88625) + let var_ty_layout = self.cx.layout_of(var_ty); + if let Abi::ScalarPair(_, _) = var_ty_layout.abi { + VariableKind::LocalVariable + } else { + VariableKind::ArgumentVariable(arg_index + 1) } } else { // FIXME(eddyb) shouldn't `ArgumentVariable` indices be diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -104,7 +104,6 @@ } } sym::pref_align_of - | sym::min_align_of | sym::needs_drop | sym::type_id | sym::type_name diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ use rustc_errors::ErrorReported; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_target::abi::call::{FnAbi, PassMode}; @@ -29,7 +29,7 @@ cx: &'a Bx::CodegenCx, - fn_abi: FnAbi<'tcx, Ty<'tcx>>, + fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, /// When unwinding is initiated, we have to store this personality /// value somewhere so that we can load it and re-use it in the @@ -129,6 +129,7 @@ /////////////////////////////////////////////////////////////////////////// +#[instrument(level = "debug", skip(cx))] pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, instance: Instance<'tcx>, @@ -139,7 +140,7 @@ let mir = cx.tcx().instance_mir(instance.def); - let fn_abi = FnAbi::of_instance(cx, instance, &[]); + let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); debug!("fn_abi: {:?}", fn_abi); let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir); @@ -152,20 +153,11 @@ } let cleanup_kinds = analyze::cleanup_kinds(&mir); - // Allocate a `Block` for every basic block, except - // the start block, if nothing loops back to it. - let reentrant_start_block = !mir.predecessors()[mir::START_BLOCK].is_empty(); - let cached_llbbs: IndexVec> = - mir.basic_blocks() - .indices() - .map(|bb| { - if bb == mir::START_BLOCK && !reentrant_start_block { - Some(start_llbb) - } else { - None - } - }) - .collect(); + let cached_llbbs: IndexVec> = mir + .basic_blocks() + .indices() + .map(|bb| if bb == mir::START_BLOCK { Some(start_llbb) } else { None }) + .collect(); let mut fx = FunctionCx { instance, @@ -247,11 +239,6 @@ // Apply debuginfo to the newly allocated locals. fx.debug_introduce_locals(&mut bx); - // Branch to the START block, if it's not the entry block. - if reentrant_start_block { - bx.br(fx.llbb(mir::START_BLOCK)); - } - // Codegen the body of each block using reverse postorder // FIXME(eddyb) reuse RPO iterator between `analysis` and this. for (bb, _) in traversal::reverse_postorder(&mir) { @@ -271,6 +258,8 @@ let mut idx = 0; let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize; + let mut num_untupled = None; + let args = mir .args_iter() .enumerate() @@ -299,6 +288,11 @@ let pr_field = place.project_field(bx, i); bx.store_fn_arg(arg, &mut llarg_idx, pr_field); } + assert_eq!( + None, + num_untupled.replace(tupled_arg_tys.len()), + "Replaced existing num_tupled" + ); return LocalRef::Place(place); } @@ -375,10 +369,17 @@ .collect::>(); if fx.instance.def.requires_caller_location(bx.tcx()) { + let mir_args = if let Some(num_untupled) = num_untupled { + // Subtract off the tupled argument that gets 'expanded' + args.len() - 1 + num_untupled + } else { + args.len() + }; assert_eq!( fx.fn_abi.args.len(), - args.len() + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + mir_args + 1, + "#[track_caller] instance {:?} must have 1 more argument in their ABI than in their MIR", + fx.instance ); let arg = fx.fn_abi.args.last().unwrap(); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/operand.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/operand.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/operand.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/operand.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,9 +8,9 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::{ConstValue, Pointer, Scalar}; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Ty; -use rustc_target::abi::{Abi, Align, LayoutOf, Size}; +use rustc_target::abi::{Abi, Align, Size}; use std::fmt; @@ -79,7 +79,7 @@ let val = match val { ConstValue::Scalar(x) => { let scalar = match layout.abi { - Abi::Scalar(ref x) => x, + Abi::Scalar(x) => x, _ => bug!("from_const: invalid ByVal layout: {:#?}", layout), }; let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); @@ -87,7 +87,7 @@ } ConstValue::Slice { data, start, end } => { let a_scalar = match layout.abi { - Abi::ScalarPair(ref a, _) => a, + Abi::ScalarPair(a, _) => a, _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout), }; let a = Scalar::from_pointer( @@ -162,7 +162,7 @@ llval: V, layout: TyAndLayout<'tcx>, ) -> Self { - let val = if let Abi::ScalarPair(ref a, ref b) = layout.abi { + let val = if let Abi::ScalarPair(a, b) = layout.abi { debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout); // Deconstruct the immediate aggregate. @@ -185,7 +185,7 @@ let field = self.layout.field(bx.cx(), i); let offset = self.layout.fields.offset(i); - let mut val = match (self.val, &self.layout.abi) { + let mut val = match (self.val, self.layout.abi) { // If the field is ZST, it has no data. _ if field.is_zst() => { return OperandRef::new_zst(bx, field); @@ -200,7 +200,7 @@ } // Extract a scalar component from a pair. - (OperandValue::Pair(a_llval, b_llval), &Abi::ScalarPair(ref a, ref b)) => { + (OperandValue::Pair(a_llval, b_llval), Abi::ScalarPair(a, b)) => { if offset.bytes() == 0 { assert_eq!(field.size, a.value.size(bx.cx())); OperandValue::Immediate(a_llval) @@ -212,14 +212,14 @@ } // `#[repr(simd)]` types are also immediate. - (OperandValue::Immediate(llval), &Abi::Vector { .. }) => { + (OperandValue::Immediate(llval), Abi::Vector { .. }) => { OperandValue::Immediate(bx.extract_element(llval, bx.cx().const_usize(i as u64))) } _ => bug!("OperandRef::extract_field({:?}): not applicable", self), }; - match (&mut val, &field.abi) { + match (&mut val, field.abi) { (OperandValue::Immediate(llval), _) => { // Bools in union fields needs to be truncated. *llval = bx.to_immediate(*llval, field); @@ -308,7 +308,7 @@ } OperandValue::Pair(a, b) => { let (a_scalar, b_scalar) = match dest.layout.abi { - Abi::ScalarPair(ref a, ref b) => (a, b), + Abi::ScalarPair(a, b) => (a, b), _ => bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout), }; let ty = bx.backend_type(dest.layout); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/place.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/place.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/place.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/place.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,10 +8,10 @@ use rustc_middle::mir; use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding}; -use rustc_target::abi::{LayoutOf, VariantIdx, Variants}; +use rustc_target::abi::{VariantIdx, Variants}; #[derive(Copy, Clone, Debug)] pub struct PlaceRef<'tcx, V> { @@ -99,7 +99,7 @@ // Also handles the first field of Scalar, ScalarPair, and Vector layouts. self.llval } - Abi::ScalarPair(ref a, ref b) + Abi::ScalarPair(a, b) if offset == a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi) => { // Offset matches second field. @@ -222,7 +222,7 @@ .map_or(index.as_u32() as u128, |discr| discr.val); return bx.cx().const_uint_big(cast_to, discr_val); } - Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => { + Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { (tag, tag_encoding, tag_field) } }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/rvalue.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/rvalue.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/rvalue.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mir/rvalue.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,10 +11,10 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir; use rustc_middle::ty::cast::{CastTy, IntTy}; -use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; -use rustc_target::abi::{Abi, Int, LayoutOf, Variants}; +use rustc_target::abi::{Abi, Int, Variants}; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_rvalue( @@ -300,7 +300,7 @@ let llval = operand.immediate(); let mut signed = false; - if let Abi::Scalar(ref scalar) = operand.layout.abi { + if let Abi::Scalar(scalar) = operand.layout.abi { if let Int(_, s) = scalar.value { // We use `i1` for bytes that are always `0` or `1`, // e.g., `#[repr(i8)] enum E { A, B }`, but we can't @@ -308,8 +308,7 @@ // then `i1 1` (i.e., E::B) is effectively `i8 -1`. signed = !scalar.is_bool() && s; - let er = scalar.valid_range_exclusive(bx.cx()); - if er.end != er.start + if !scalar.is_always_valid(bx.cx()) && scalar.valid_range.end >= scalar.valid_range.start { // We want `table[e as usize ± k]` to not @@ -487,20 +486,6 @@ ) } - mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.monomorphize(ty); - assert!(bx.cx().type_is_sized(ty)); - let val = bx.cx().const_usize(bx.cx().layout_of(ty).size.bytes()); - let tcx = self.cx.tcx(); - ( - bx, - OperandRef { - val: OperandValue::Immediate(val), - layout: self.cx.layout_of(tcx.types.usize), - }, - ) - } - mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { let content_ty = self.monomorphize(content_ty); let content_layout = bx.cx().layout_of(content_ty); @@ -525,6 +510,27 @@ let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout }; (bx, operand) } + + mir::Rvalue::NullaryOp(null_op, ty) => { + let ty = self.monomorphize(ty); + assert!(bx.cx().type_is_sized(ty)); + let layout = bx.cx().layout_of(ty); + let val = match null_op { + mir::NullOp::SizeOf => layout.size.bytes(), + mir::NullOp::AlignOf => layout.align.abi.bytes(), + mir::NullOp::Box => unreachable!(), + }; + let val = bx.cx().const_usize(val); + let tcx = self.cx.tcx(); + ( + bx, + OperandRef { + val: OperandValue::Immediate(val), + layout: self.cx.layout_of(tcx.types.usize), + }, + ) + } + mir::Rvalue::ThreadLocalRef(def_id) => { assert!(bx.cx().tcx().is_static(def_id)); let static_ = bx.get_static(def_id); @@ -544,6 +550,18 @@ OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty))); (bx, operand) } + mir::Rvalue::ShallowInitBox(ref operand, content_ty) => { + let operand = self.codegen_operand(&mut bx, operand); + let lloperand = operand.immediate(); + + let content_ty = self.monomorphize(content_ty); + let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty)); + let llty_ptr = bx.cx().backend_type(box_layout); + + let val = bx.pointercast(lloperand, llty_ptr); + let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout }; + (bx, operand) + } } } @@ -757,6 +775,7 @@ mir::Rvalue::AddressOf(..) | mir::Rvalue::Len(..) | mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::ShallowInitBox(..) | // (*) mir::Rvalue::BinaryOp(..) | mir::Rvalue::CheckedBinaryOp(..) | mir::Rvalue::UnaryOp(..) | diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mono_item.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mono_item.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mono_item.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/mono_item.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,8 +4,7 @@ use rustc_hir as hir; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::layout::HasTyCtxt; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; pub trait MonoItemExt<'a, 'tcx> { fn define>(&self, cx: &'a Bx::CodegenCx); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/backend.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/backend.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/backend.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/backend.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,17 +6,18 @@ use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorReported; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; -use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_session::{ config::{self, OutputFilenames, PrintRequest}, + cstore::MetadataLoaderDyn, Session, }; use rustc_span::symbol::Symbol; -use rustc_target::abi::LayoutOf; +use rustc_target::abi::call::FnAbi; use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; @@ -42,14 +43,16 @@ Sized + BackendTypes + HasTyCtxt<'tcx> - + LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> + + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> { } impl<'tcx, T> Backend<'tcx> for T where Self: BackendTypes + HasTyCtxt<'tcx> - + LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> + + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> { } @@ -120,7 +123,8 @@ fn codegen_allocator<'tcx>( &self, tcx: TyCtxt<'tcx>, - mods: &mut Self::Module, + module_llvm: &mut Self::Module, + module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool, ); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/builder.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/builder.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/builder.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/builder.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,11 +16,9 @@ use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout}; use rustc_middle::ty::Ty; use rustc_span::Span; -use rustc_target::abi::{Abi, Align, Scalar, Size}; +use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange}; use rustc_target::spec::HasTargetSpec; -use std::ops::Range; - #[derive(Copy, Clone)] pub enum OverflowOp { Add, @@ -126,13 +124,13 @@ fn from_immediate(&mut self, val: Self::Value) -> Self::Value; fn to_immediate(&mut self, val: Self::Value, layout: TyAndLayout<'_>) -> Self::Value { - if let Abi::Scalar(ref scalar) = layout.abi { + if let Abi::Scalar(scalar) = layout.abi { self.to_immediate_scalar(val, scalar) } else { val } } - fn to_immediate_scalar(&mut self, val: Self::Value, scalar: &Scalar) -> Self::Value; + fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value; fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value; fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value; @@ -158,7 +156,7 @@ dest: PlaceRef<'tcx, Self::Value>, ) -> Self; - fn range_metadata(&mut self, load: Self::Value, range: Range); + fn range_metadata(&mut self, load: Self::Value, range: WrappingRange); fn nonnull_metadata(&mut self, load: Self::Value); fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/consts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/consts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/consts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/consts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,7 +28,7 @@ fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value; - fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: Self::Type) -> Self::Value; + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; fn from_const_alloc( &self, layout: TyAndLayout<'tcx>, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,18 @@ use super::BackendTypes; use crate::mir::debuginfo::{FunctionDebugContext, VariableKind}; use rustc_middle::mir; -use rustc_middle::ty::{Instance, Ty}; +use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_span::{SourceFile, Span, Symbol}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; pub trait DebugInfoMethods<'tcx>: BackendTypes { - fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value); + fn create_vtable_metadata( + &self, + ty: Ty<'tcx>, + trait_ref: Option>, + vtable: Self::Value, + ); /// Creates the function-specific debug context. /// diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +[package] +name = "rustc_const_eval" +version = "0.0.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +tracing = "0.1" +rustc_apfloat = { path = "../rustc_apfloat" } +rustc_ast = { path = "../rustc_ast" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } +rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } +rustc_query_system = { path = "../rustc_query_system" } +rustc_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_span = { path = "../rustc_span" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/error.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/error.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/error.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,210 @@ +use std::error::Error; +use std::fmt; + +use rustc_errors::{DiagnosticBuilder, ErrorReported}; +use rustc_hir as hir; +use rustc_middle::mir::AssertKind; +use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt}; +use rustc_span::{Span, Symbol}; + +use super::InterpCx; +use crate::interpret::{ + struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, +}; + +/// The CTFE machine has some custom error kinds. +#[derive(Clone, Debug)] +pub enum ConstEvalErrKind { + NeedsRfc(String), + ConstAccessesStatic, + ModifiedGlobal, + AssertFailure(AssertKind), + Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + Abort(String), +} + +impl MachineStopType for ConstEvalErrKind { + fn is_hard_err(&self) -> bool { + match self { + Self::Panic { .. } => true, + _ => false, + } + } +} + +// The errors become `MachineStop` with plain strings when being raised. +// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to +// handle these. +impl<'tcx> Into> for ConstEvalErrKind { + fn into(self) -> InterpErrorInfo<'tcx> { + err_machine_stop!(self).into() + } +} + +impl fmt::Display for ConstEvalErrKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::ConstEvalErrKind::*; + match *self { + NeedsRfc(ref msg) => { + write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg) + } + ConstAccessesStatic => write!(f, "constant accesses static"), + ModifiedGlobal => { + write!(f, "modifying a static's initial value from another static's initializer") + } + AssertFailure(ref msg) => write!(f, "{:?}", msg), + Panic { msg, line, col, file } => { + write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) + } + Abort(ref msg) => write!(f, "{}", msg), + } + } +} + +impl Error for ConstEvalErrKind {} + +/// When const-evaluation errors, this type is constructed with the resulting information, +/// and then used to emit the error as a lint or hard error. +#[derive(Debug)] +pub struct ConstEvalErr<'tcx> { + pub span: Span, + pub error: InterpError<'tcx>, + pub stacktrace: Vec>, +} + +impl<'tcx> ConstEvalErr<'tcx> { + /// Turn an interpreter error into something to report to the user. + /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. + /// Should be called only if the error is actually going to to be reported! + pub fn new<'mir, M: Machine<'mir, 'tcx>>( + ecx: &InterpCx<'mir, 'tcx, M>, + error: InterpErrorInfo<'tcx>, + span: Option, + ) -> ConstEvalErr<'tcx> + where + 'tcx: 'mir, + { + error.print_backtrace(); + let stacktrace = ecx.generate_stacktrace(); + ConstEvalErr { + error: error.into_kind(), + stacktrace, + span: span.unwrap_or_else(|| ecx.cur_span()), + } + } + + pub fn struct_error( + &self, + tcx: TyCtxtAt<'tcx>, + message: &str, + emit: impl FnOnce(DiagnosticBuilder<'_>), + ) -> ErrorHandled { + self.struct_generic(tcx, message, emit, None) + } + + pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled { + self.struct_error(tcx, message, |mut e| e.emit()) + } + + pub fn report_as_lint( + &self, + tcx: TyCtxtAt<'tcx>, + message: &str, + lint_root: hir::HirId, + span: Option, + ) -> ErrorHandled { + self.struct_generic( + tcx, + message, + |mut lint: DiagnosticBuilder<'_>| { + // Apply the span. + if let Some(span) = span { + let primary_spans = lint.span.primary_spans().to_vec(); + // point at the actual error as the primary span + lint.replace_span_with(span); + // point to the `const` statement as a secondary span + // they don't have any label + for sp in primary_spans { + if sp != span { + lint.span_label(sp, ""); + } + } + } + lint.emit(); + }, + Some(lint_root), + ) + } + + /// Create a diagnostic for this const eval error. + /// + /// Sets the message passed in via `message` and adds span labels with detailed error + /// information before handing control back to `emit` to do any final processing. + /// It's the caller's responsibility to call emit(), stash(), etc. within the `emit` + /// function to dispose of the diagnostic properly. + /// + /// If `lint_root.is_some()` report it as a lint, else report it as a hard error. + /// (Except that for some errors, we ignore all that -- see `must_error` below.) + fn struct_generic( + &self, + tcx: TyCtxtAt<'tcx>, + message: &str, + emit: impl FnOnce(DiagnosticBuilder<'_>), + lint_root: Option, + ) -> ErrorHandled { + let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option| { + trace!("reporting const eval failure at {:?}", self.span); + if let Some(span_msg) = span_msg { + err.span_label(self.span, span_msg); + } + // Add spans for the stacktrace. Don't print a single-line backtrace though. + if self.stacktrace.len() > 1 { + for frame_info in &self.stacktrace { + err.span_label(frame_info.span, frame_info.to_string()); + } + } + // Let the caller finish the job. + emit(err) + }; + + // Special handling for certain errors + match &self.error { + // Don't emit a new diagnostic for these errors + err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { + return ErrorHandled::TooGeneric; + } + err_inval!(AlreadyReported(error_reported)) => { + return ErrorHandled::Reported(*error_reported); + } + err_inval!(Layout(LayoutError::SizeOverflow(_))) => { + // We must *always* hard error on these, even if the caller wants just a lint. + // The `message` makes little sense here, this is a more serious error than the + // caller thinks anyway. + // See . + finish(struct_error(tcx, &self.error.to_string()), None); + return ErrorHandled::Reported(ErrorReported); + } + _ => {} + }; + + let err_msg = self.error.to_string(); + + // Regular case - emit a lint. + if let Some(lint_root) = lint_root { + // Report as lint. + let hir_id = + self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root); + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::CONST_ERR, + hir_id, + tcx.span, + |lint| finish(lint.build(message), Some(err_msg)), + ); + ErrorHandled::Linted + } else { + // Report as hard error. + finish(struct_error(tcx, message), Some(err_msg)); + ErrorHandled::Reported(ErrorReported) + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/eval_queries.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/eval_queries.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/eval_queries.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/eval_queries.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,400 @@ +use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; +use crate::interpret::eval_nullary_intrinsic; +use crate::interpret::{ + intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, + Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, + ScalarMaybeUninit, StackPopCleanup, +}; + +use rustc_errors::ErrorReported; +use rustc_hir::def::DefKind; +use rustc_middle::mir; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir::pretty::display_allocation; +use rustc_middle::traits::Reveal; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, subst::Subst, TyCtxt}; +use rustc_span::source_map::Span; +use rustc_target::abi::Abi; +use std::borrow::Cow; +use std::convert::TryInto; + +pub fn note_on_undefined_behavior_error() -> &'static str { + "The rules on what exactly is undefined behavior aren't clear, \ + so this check might be overzealous. Please open an issue on the rustc \ + repository if you believe it should not be considered undefined behavior." +} + +// Returns a pointer to where the result lives +fn eval_body_using_ecx<'mir, 'tcx>( + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, + cid: GlobalId<'tcx>, + body: &'mir mir::Body<'tcx>, +) -> InterpResult<'tcx, MPlaceTy<'tcx>> { + debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); + let tcx = *ecx.tcx; + assert!( + cid.promoted.is_some() + || matches!( + ecx.tcx.def_kind(cid.instance.def_id()), + DefKind::Const + | DefKind::Static + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::AssocConst + ), + "Unexpected DefKind: {:?}", + ecx.tcx.def_kind(cid.instance.def_id()) + ); + let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; + assert!(!layout.is_unsized()); + let ret = ecx.allocate(layout, MemoryKind::Stack)?; + + trace!( + "eval_body_using_ecx: pushing stack frame for global: {}{}", + with_no_trimmed_paths(|| ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()))), + cid.promoted.map_or_else(String::new, |p| format!("::promoted[{:?}]", p)) + ); + + ecx.push_stack_frame( + cid.instance, + body, + Some(&ret.into()), + StackPopCleanup::None { cleanup: false }, + )?; + + // The main interpreter loop. + ecx.run()?; + + // Intern the result + let intern_kind = if cid.promoted.is_some() { + InternKind::Promoted + } else { + match tcx.static_mutability(cid.instance.def_id()) { + Some(m) => InternKind::Static(m), + None => InternKind::Constant, + } + }; + intern_const_alloc_recursive(ecx, intern_kind, &ret)?; + + debug!("eval_body_using_ecx done: {:?}", *ret); + Ok(ret) +} + +/// The `InterpCx` is only meant to be used to do field and index projections into constants for +/// `simd_shuffle` and const patterns in match arms. +/// +/// The function containing the `match` that is currently being analyzed may have generic bounds +/// that inform us about the generic bounds of the constant. E.g., using an associated constant +/// of a function's generic parameter will require knowledge about the bounds on the generic +/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. +pub(super) fn mk_eval_cx<'mir, 'tcx>( + tcx: TyCtxt<'tcx>, + root_span: Span, + param_env: ty::ParamEnv<'tcx>, + can_access_statics: bool, +) -> CompileTimeEvalContext<'mir, 'tcx> { + debug!("mk_eval_cx: {:?}", param_env); + InterpCx::new( + tcx, + root_span, + param_env, + CompileTimeInterpreter::new(tcx.const_eval_limit()), + MemoryExtra { can_access_statics }, + ) +} + +/// This function converts an interpreter value into a constant that is meant for use in the +/// type system. +pub(super) fn op_to_const<'tcx>( + ecx: &CompileTimeEvalContext<'_, 'tcx>, + op: &OpTy<'tcx>, +) -> ConstValue<'tcx> { + // We do not have value optimizations for everything. + // Only scalars and slices, since they are very common. + // Note that further down we turn scalars of uninitialized bits back to `ByRef`. These can result + // from scalar unions that are initialized with one of their zero sized variants. We could + // instead allow `ConstValue::Scalar` to store `ScalarMaybeUninit`, but that would affect all + // the usual cases of extracting e.g. a `usize`, without there being a real use case for the + // `Undef` situation. + let try_as_immediate = match op.layout.abi { + Abi::Scalar(..) => true, + Abi::ScalarPair(..) => match op.layout.ty.kind() { + ty::Ref(_, inner, _) => match *inner.kind() { + ty::Slice(elem) => elem == ecx.tcx.types.u8, + ty::Str => true, + _ => false, + }, + _ => false, + }, + _ => false, + }; + let immediate = if try_as_immediate { + Err(ecx.read_immediate(op).expect("normalization works on validated constants")) + } else { + // It is guaranteed that any non-slice scalar pair is actually ByRef here. + // When we come back from raw const eval, we are always by-ref. The only way our op here is + // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we + // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or + // structs containing such. + op.try_as_mplace() + }; + + // We know `offset` is relative to the allocation, so we can use `into_parts`. + let to_const_value = |mplace: &MPlaceTy<'_>| match mplace.ptr.into_parts() { + (Some(alloc_id), offset) => { + let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory(); + ConstValue::ByRef { alloc, offset } + } + (None, offset) => { + assert!(mplace.layout.is_zst()); + assert_eq!( + offset.bytes() % mplace.layout.align.abi.bytes(), + 0, + "this MPlaceTy must come from a validated constant, thus we can assume the \ + alignment is correct", + ); + ConstValue::Scalar(Scalar::ZST) + } + }; + match immediate { + Ok(ref mplace) => to_const_value(mplace), + // see comment on `let try_as_immediate` above + Err(imm) => match *imm { + Immediate::Scalar(x) => match x { + ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s), + ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place()), + }, + Immediate::ScalarPair(a, b) => { + // We know `offset` is relative to the allocation, so we can use `into_parts`. + let (data, start) = match ecx.scalar_to_ptr(a.check_init().unwrap()).into_parts() { + (Some(alloc_id), offset) => { + (ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes()) + } + (None, _offset) => ( + ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable( + b"" as &[u8], + )), + 0, + ), + }; + let len = b.to_machine_usize(ecx).unwrap(); + let start = start.try_into().unwrap(); + let len: usize = len.try_into().unwrap(); + ConstValue::Slice { data, start, end: start + len } + } + }, + } +} + +fn turn_into_const_value<'tcx>( + tcx: TyCtxt<'tcx>, + constant: ConstAlloc<'tcx>, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, +) -> ConstValue<'tcx> { + let cid = key.value; + let def_id = cid.instance.def.def_id(); + let is_static = tcx.is_static(def_id); + let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); + + let mplace = ecx.raw_const_to_mplace(constant).expect( + "can only fail if layout computation failed, \ + which should have given a good error before ever invoking this function", + ); + assert!( + !is_static || cid.promoted.is_some(), + "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" + ); + // Turn this into a proper constant. + op_to_const(&ecx, &mplace.into()) +} + +pub fn eval_to_const_value_raw_provider<'tcx>( + tcx: TyCtxt<'tcx>, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, +) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { + // see comment in eval_to_allocation_raw_provider for what we're doing here + if key.param_env.reveal() == Reveal::All { + let mut key = key; + key.param_env = key.param_env.with_user_facing(); + match tcx.eval_to_const_value_raw(key) { + // try again with reveal all as requested + Err(ErrorHandled::TooGeneric) => {} + // deduplicate calls + other => return other, + } + } + + // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. + // Catch such calls and evaluate them instead of trying to load a constant's MIR. + if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { + let ty = key.value.instance.ty(tcx, key.param_env); + let substs = match ty.kind() { + ty::FnDef(_, substs) => substs, + _ => bug!("intrinsic with type {:?}", ty), + }; + return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { + let span = tcx.def_span(def_id); + let error = ConstEvalErr { error: error.into_kind(), stacktrace: vec![], span }; + error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") + }); + } + + tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) +} + +pub fn eval_to_allocation_raw_provider<'tcx>( + tcx: TyCtxt<'tcx>, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, +) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { + // Because the constant is computed twice (once per value of `Reveal`), we are at risk of + // reporting the same error twice here. To resolve this, we check whether we can evaluate the + // constant in the more restrictive `Reveal::UserFacing`, which most likely already was + // computed. For a large percentage of constants that will already have succeeded. Only + // associated constants of generic functions will fail due to not enough monomorphization + // information being available. + + // In case we fail in the `UserFacing` variant, we just do the real computation. + if key.param_env.reveal() == Reveal::All { + let mut key = key; + key.param_env = key.param_env.with_user_facing(); + match tcx.eval_to_allocation_raw(key) { + // try again with reveal all as requested + Err(ErrorHandled::TooGeneric) => {} + // deduplicate calls + other => return other, + } + } + if cfg!(debug_assertions) { + // Make sure we format the instance even if we do not print it. + // This serves as a regression test against an ICE on printing. + // The next two lines concatenated contain some discussion: + // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ + // subject/anon_const_instance_printing/near/135980032 + let instance = with_no_trimmed_paths(|| key.value.instance.to_string()); + trace!("const eval: {:?} ({})", key, instance); + } + + let cid = key.value; + let def = cid.instance.def.with_opt_param(); + + if let Some(def) = def.as_local() { + if tcx.has_typeck_results(def.did) { + if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors { + return Err(ErrorHandled::Reported(error_reported)); + } + } + if !tcx.is_mir_available(def.did) { + tcx.sess.delay_span_bug( + tcx.def_span(def.did), + &format!("no MIR body is available for {:?}", def.did), + ); + return Err(ErrorHandled::Reported(ErrorReported {})); + } + if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured { + return Err(ErrorHandled::Reported(error_reported)); + } + } + + let is_static = tcx.is_static(def.did); + + let mut ecx = InterpCx::new( + tcx, + tcx.def_span(def.did), + key.param_env, + CompileTimeInterpreter::new(tcx.const_eval_limit()), + // Statics (and promoteds inside statics) may access other statics, because unlike consts + // they do not have to behave "as if" they were evaluated at runtime. + MemoryExtra { can_access_statics: is_static }, + ); + + let res = ecx.load_mir(cid.instance.def, cid.promoted); + match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { + Err(error) => { + let err = ConstEvalErr::new(&ecx, error, None); + // Some CTFE errors raise just a lint, not a hard error; see + // . + let is_hard_err = if let Some(def) = def.as_local() { + // (Associated) consts only emit a lint, since they might be unused. + !matches!(tcx.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst) + // check if the inner InterpError is hard + || err.error.is_hard_err() + } else { + // use of broken constant from other crate: always an error + true + }; + + if is_hard_err { + let msg = if is_static { + Cow::from("could not evaluate static initializer") + } else { + // If the current item has generics, we'd like to enrich the message with the + // instance and its substs: to show the actual compile-time values, in addition to + // the expression, leading to the const eval error. + let instance = &key.value.instance; + if !instance.substs.is_empty() { + let instance = with_no_trimmed_paths(|| instance.to_string()); + let msg = format!("evaluation of `{}` failed", instance); + Cow::from(msg) + } else { + Cow::from("evaluation of constant value failed") + } + }; + + Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg)) + } else { + let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did); + Err(err.report_as_lint( + tcx.at(tcx.def_span(def.did)), + "any use of this value will cause an error", + hir_id, + Some(err.span), + )) + } + } + Ok(mplace) => { + // Since evaluation had no errors, validate the resulting constant. + // This is a separate `try` block to provide more targeted error reporting. + let validation = try { + let mut ref_tracking = RefTracking::new(mplace); + let mut inner = false; + while let Some((mplace, path)) = ref_tracking.todo.pop() { + let mode = match tcx.static_mutability(cid.instance.def_id()) { + Some(_) if cid.promoted.is_some() => { + // Promoteds in statics are allowed to point to statics. + CtfeValidationMode::Const { inner, allow_static_ptrs: true } + } + Some(_) => CtfeValidationMode::Regular, // a `static` + None => CtfeValidationMode::Const { inner, allow_static_ptrs: false }, + }; + ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?; + inner = true; + } + }; + let alloc_id = mplace.ptr.provenance.unwrap(); + if let Err(error) = validation { + // Validation failed, report an error. This is always a hard error. + let err = ConstEvalErr::new(&ecx, error, None); + Err(err.struct_error( + ecx.tcx, + "it is undefined behavior to use this value", + |mut diag| { + diag.note(note_on_undefined_behavior_error()); + diag.note(&format!( + "the raw bytes of the constant ({}", + display_allocation( + *ecx.tcx, + ecx.tcx.global_alloc(alloc_id).unwrap_memory() + ) + )); + diag.emit(); + }, + )) + } else { + // Convert to raw constant + Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty }) + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/fn_queries.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/fn_queries.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/fn_queries.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/fn_queries.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,83 @@ +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::hir::map::blocks::FnLikeNode; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::Symbol; +use rustc_target::spec::abi::Abi; + +/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it +pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + if tcx.is_const_fn_raw(def_id) { + let const_stab = tcx.lookup_const_stability(def_id)?; + if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None } + } else { + None + } +} + +pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { + let parent_id = tcx.hir().get_parent_node(hir_id); + matches!( + tcx.hir().get(parent_id), + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }), + .. + }) + ) +} + +/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether +/// said intrinsic has a `rustc_const_{un,}stable` attribute. +fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + + let node = tcx.hir().get(hir_id); + + if let hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) = + node + { + // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other + // foreign items cannot be evaluated at compile-time. + if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = tcx.hir().get_foreign_abi(hir_id) { + tcx.lookup_const_stability(def_id).is_some() + } else { + false + } + } else if let Some(fn_like) = FnLikeNode::from_node(node) { + if fn_like.constness() == hir::Constness::Const { + return true; + } + + // If the function itself is not annotated with `const`, it may still be a `const fn` + // if it resides in a const trait impl. + is_parent_const_impl_raw(tcx, hir_id) + } else if let hir::Node::Ctor(_) = node { + true + } else { + false + } +} + +fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + tcx.is_const_fn(def_id) + && match tcx.lookup_const_stability(def_id) { + Some(stab) => { + if cfg!(debug_assertions) && stab.promotable { + let sig = tcx.fn_sig(def_id); + assert_eq!( + sig.unsafety(), + hir::Unsafety::Normal, + "don't mark const unsafe fns as promotable", + // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682 + ); + } + stab.promotable + } + None => false, + } +} + +pub fn provide(providers: &mut Providers) { + *providers = Providers { is_const_fn_raw, is_promotable_const_fn, ..*providers }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/machine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/machine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/machine.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/machine.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,500 @@ +use rustc_middle::mir; +use rustc_middle::ty::{self, Ty}; +use std::borrow::Borrow; +use std::collections::hash_map::Entry; +use std::hash::Hash; + +use rustc_data_structures::fx::FxHashMap; +use std::fmt; + +use rustc_ast::Mutability; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::AssertMessage; +use rustc_session::Limit; +use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::{Align, Size}; +use rustc_target::spec::abi::Abi; + +use crate::interpret::{ + self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, OpTy, + PlaceTy, Scalar, StackPopUnwind, +}; + +use super::error::*; + +impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { + /// "Intercept" a function call to a panic-related function + /// because we have something special to do for it. + /// If this returns successfully (`Ok`), the function should just be evaluated normally. + fn hook_special_const_fn( + &mut self, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx>], + is_const_fn: bool, + ) -> InterpResult<'tcx, Option>> { + // The list of functions we handle here must be in sync with + // `is_lang_special_const_fn` in `transform/check_consts/mod.rs`. + let def_id = instance.def_id(); + + if is_const_fn { + if Some(def_id) == self.tcx.lang_items().const_eval_select() { + // redirect to const_eval_select_ct + if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() { + return Ok(Some( + ty::Instance::resolve( + *self.tcx, + ty::ParamEnv::reveal_all(), + const_eval_select, + instance.substs, + ) + .unwrap() + .unwrap(), + )); + } + } + return Ok(None); + } + + if Some(def_id) == self.tcx.lang_items().panic_fn() + || Some(def_id) == self.tcx.lang_items().panic_str() + || Some(def_id) == self.tcx.lang_items().panic_display() + || Some(def_id) == self.tcx.lang_items().begin_panic_fn() + { + // &str or &&str + assert!(args.len() == 1); + + let mut msg_place = self.deref_operand(&args[0])?; + while msg_place.layout.ty.is_ref() { + msg_place = self.deref_operand(&msg_place.into())?; + } + + let msg = Symbol::intern(self.read_str(&msg_place)?); + let span = self.find_closest_untracked_caller_location(); + let (file, line, col) = self.location_triple_for_span(span); + return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); + } else if Some(def_id) == self.tcx.lang_items().panic_fmt() + || Some(def_id) == self.tcx.lang_items().begin_panic_fmt() + { + // For panic_fmt, call const_panic_fmt instead. + if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() { + return Ok(Some( + ty::Instance::resolve( + *self.tcx, + ty::ParamEnv::reveal_all(), + const_panic_fmt, + self.tcx.intern_substs(&[]), + ) + .unwrap() + .unwrap(), + )); + } + } + Ok(None) + } +} + +/// Extra machine state for CTFE, and the Machine instance +pub struct CompileTimeInterpreter<'mir, 'tcx> { + /// For now, the number of terminators that can be evaluated before we throw a resource + /// exhaustion error. + /// + /// Setting this to `0` disables the limit and allows the interpreter to run forever. + pub steps_remaining: usize, + + /// The virtual call stack. + pub(crate) stack: Vec>, +} + +#[derive(Copy, Clone, Debug)] +pub struct MemoryExtra { + /// We need to make sure consts never point to anything mutable, even recursively. That is + /// relied on for pattern matching on consts with references. + /// To achieve this, two pieces have to work together: + /// * Interning makes everything outside of statics immutable. + /// * Pointers to allocations inside of statics can never leak outside, to a non-static global. + /// This boolean here controls the second part. + pub(super) can_access_statics: bool, +} + +impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { + pub(super) fn new(const_eval_limit: Limit) -> Self { + CompileTimeInterpreter { steps_remaining: const_eval_limit.0, stack: Vec::new() } + } +} + +impl interpret::AllocMap for FxHashMap { + #[inline(always)] + fn contains_key(&mut self, k: &Q) -> bool + where + K: Borrow, + { + FxHashMap::contains_key(self, k) + } + + #[inline(always)] + fn insert(&mut self, k: K, v: V) -> Option { + FxHashMap::insert(self, k, v) + } + + #[inline(always)] + fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + { + FxHashMap::remove(self, k) + } + + #[inline(always)] + fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { + self.iter().filter_map(move |(k, v)| f(k, &*v)).collect() + } + + #[inline(always)] + fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E> { + match self.get(&k) { + Some(v) => Ok(v), + None => { + vacant()?; + bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading") + } + } + } + + #[inline(always)] + fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E> { + match self.entry(k) { + Entry::Occupied(e) => Ok(e.into_mut()), + Entry::Vacant(e) => { + let v = vacant()?; + Ok(e.insert(v)) + } + } + } +} + +crate type CompileTimeEvalContext<'mir, 'tcx> = + InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum MemoryKind { + Heap, +} + +impl fmt::Display for MemoryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MemoryKind::Heap => write!(f, "heap allocation"), + } + } +} + +impl interpret::MayLeak for MemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + match self { + MemoryKind::Heap => false, + } + } +} + +impl interpret::MayLeak for ! { + #[inline(always)] + fn may_leak(self) -> bool { + // `self` is uninhabited + self + } +} + +impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { + fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { + match (a, b) { + // Comparisons between integers are always known. + (Scalar::Int { .. }, Scalar::Int { .. }) => a == b, + // Equality with integers can never be known for sure. + (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => false, + // FIXME: return `true` for when both sides are the same pointer, *except* that + // some things (like functions and vtables) do not have stable addresses + // so we need to be careful around them (see e.g. #73722). + (Scalar::Ptr(..), Scalar::Ptr(..)) => false, + } + } + + fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool { + match (a, b) { + // Comparisons between integers are always known. + (Scalar::Int(_), Scalar::Int(_)) => a != b, + // Comparisons of abstract pointers with null pointers are known if the pointer + // is in bounds, because if they are in bounds, the pointer can't be null. + // Inequality with integers other than null can never be known for sure. + (Scalar::Int(int), Scalar::Ptr(ptr, _)) | (Scalar::Ptr(ptr, _), Scalar::Int(int)) => { + int.is_null() && !self.memory.ptr_may_be_null(ptr.into()) + } + // FIXME: return `true` for at least some comparisons where we can reliably + // determine the result of runtime inequality tests at compile-time. + // Examples include comparison of addresses in different static items. + (Scalar::Ptr(..), Scalar::Ptr(..)) => false, + } + } +} + +impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { + compile_time_machine!(<'mir, 'tcx>); + + type MemoryKind = MemoryKind; + + type MemoryExtra = MemoryExtra; + + const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error + + fn load_mir( + ecx: &InterpCx<'mir, 'tcx, Self>, + instance: ty::InstanceDef<'tcx>, + ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { + match instance { + ty::InstanceDef::Item(def) => { + if ecx.tcx.is_ctfe_mir_available(def.did) { + Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def)) + } else { + let path = ecx.tcx.def_path_str(def.did); + Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path)) + .into()) + } + } + _ => Ok(ecx.tcx.instance_mir(instance)), + } + } + + fn find_mir_or_eval_fn( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + instance: ty::Instance<'tcx>, + _abi: Abi, + args: &[OpTy<'tcx>], + _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, + _unwind: StackPopUnwind, // unwinding is not supported in consts + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + debug!("find_mir_or_eval_fn: {:?}", instance); + + // Only check non-glue functions + if let ty::InstanceDef::Item(def) = instance.def { + let mut is_const_fn = true; + + // Execution might have wandered off into other crates, so we cannot do a stability- + // sensitive check here. But we can at least rule out functions that are not const + // at all. + if !ecx.tcx.is_const_fn_raw(def.did) { + // allow calling functions marked with #[default_method_body_is_const]. + if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) { + is_const_fn = false; + } + } + + // Some functions we support even if they are non-const -- but avoid testing + // that for const fn! + // `const_eval_select` is a const fn because it must use const trait bounds. + if let Some(new_instance) = ecx.hook_special_const_fn(instance, args, is_const_fn)? { + // We call another const fn instead. + return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind); + } + + if !is_const_fn { + // We certainly do *not* want to actually call the fn + // though, so be sure we return here. + throw_unsup_format!("calling non-const function `{}`", instance) + } + } + // This is a const fn. Call it. + Ok(Some(ecx.load_mir(instance.def, None)?)) + } + + fn call_intrinsic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx>], + ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, + _unwind: StackPopUnwind, + ) -> InterpResult<'tcx> { + // Shared intrinsics. + if ecx.emulate_intrinsic(instance, args, ret)? { + return Ok(()); + } + let intrinsic_name = ecx.tcx.item_name(instance.def_id()); + + // CTFE-specific intrinsics. + let (dest, ret) = match ret { + None => { + return Err(ConstEvalErrKind::NeedsRfc(format!( + "calling intrinsic `{}`", + intrinsic_name + )) + .into()); + } + Some(p) => p, + }; + match intrinsic_name { + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { + let a = ecx.read_immediate(&args[0])?.to_scalar()?; + let b = ecx.read_immediate(&args[1])?.to_scalar()?; + let cmp = if intrinsic_name == sym::ptr_guaranteed_eq { + ecx.guaranteed_eq(a, b) + } else { + ecx.guaranteed_ne(a, b) + }; + ecx.write_scalar(Scalar::from_bool(cmp), dest)?; + } + sym::const_allocate => { + let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?; + let align = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?; + + let align = match Align::from_bytes(align) { + Ok(a) => a, + Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), + }; + + let ptr = ecx.memory.allocate( + Size::from_bytes(size as u64), + align, + interpret::MemoryKind::Machine(MemoryKind::Heap), + )?; + ecx.write_pointer(ptr, dest)?; + } + _ => { + return Err(ConstEvalErrKind::NeedsRfc(format!( + "calling intrinsic `{}`", + intrinsic_name + )) + .into()); + } + } + + ecx.go_to_block(ret); + Ok(()) + } + + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + msg: &AssertMessage<'tcx>, + _unwind: Option, + ) -> InterpResult<'tcx> { + use rustc_middle::mir::AssertKind::*; + // Convert `AssertKind` to `AssertKind`. + let eval_to_int = + |op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int()); + let err = match msg { + BoundsCheck { ref len, ref index } => { + let len = eval_to_int(len)?; + let index = eval_to_int(index)?; + BoundsCheck { len, index } + } + Overflow(op, l, r) => Overflow(*op, eval_to_int(l)?, eval_to_int(r)?), + OverflowNeg(op) => OverflowNeg(eval_to_int(op)?), + DivisionByZero(op) => DivisionByZero(eval_to_int(op)?), + RemainderByZero(op) => RemainderByZero(eval_to_int(op)?), + ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind), + ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind), + }; + Err(ConstEvalErrKind::AssertFailure(err).into()) + } + + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + Err(ConstEvalErrKind::Abort(msg).into()) + } + + fn binary_ptr_op( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _bin_op: mir::BinOp, + _left: &ImmTy<'tcx>, + _right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into()) + } + + fn box_alloc( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _dest: &PlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into()) + } + + fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + // The step limit has already been hit in a previous call to `before_terminator`. + if ecx.machine.steps_remaining == 0 { + return Ok(()); + } + + ecx.machine.steps_remaining -= 1; + if ecx.machine.steps_remaining == 0 { + throw_exhaust!(StepLimitReached) + } + + Ok(()) + } + + #[inline(always)] + fn init_frame_extra( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + frame: Frame<'mir, 'tcx>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { + // Enforce stack size limit. Add 1 because this is run before the new frame is pushed. + if !ecx.recursion_limit.value_within_limit(ecx.stack().len() + 1) { + throw_exhaust!(StackFrameLimitReached) + } else { + Ok(frame) + } + } + + #[inline(always)] + fn stack( + ecx: &'a InterpCx<'mir, 'tcx, Self>, + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + &ecx.machine.stack + } + + #[inline(always)] + fn stack_mut( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + ) -> &'a mut Vec> { + &mut ecx.machine.stack + } + + fn before_access_global( + memory_extra: &MemoryExtra, + alloc_id: AllocId, + allocation: &Allocation, + static_def_id: Option, + is_write: bool, + ) -> InterpResult<'tcx> { + if is_write { + // Write access. These are never allowed, but we give a targeted error message. + if allocation.mutability == Mutability::Not { + Err(err_ub!(WriteToReadOnly(alloc_id)).into()) + } else { + Err(ConstEvalErrKind::ModifiedGlobal.into()) + } + } else { + // Read access. These are usually allowed, with some exceptions. + if memory_extra.can_access_statics { + // Machine configuration allows us read from anything (e.g., `static` initializer). + Ok(()) + } else if static_def_id.is_some() { + // Machine configuration does not allow us to read statics + // (e.g., `const` initializer). + // See const_eval::machine::MemoryExtra::can_access_statics for why + // this check is so important: if we could read statics, we could read pointers + // to mutable allocations *inside* statics. These allocations are not themselves + // statics, so pointers to them can get around the check in `validity.rs`. + Err(ConstEvalErrKind::ConstAccessesStatic.into()) + } else { + // Immutable global, this read is fine. + // But make sure we never accept a read from something mutable, that would be + // unsound. The reason is that as the content of this allocation may be different + // now and at run-time, so if we permit reading now we might return the wrong value. + assert_eq!(allocation.mutability, Mutability::Not); + Ok(()) + } + } + } +} + +// Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups +// so we can end up having a file with just that impl, but for now, let's keep the impl discoverable +// at the bottom of this file. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/const_eval/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,207 @@ +// Not in interpret to make sure we do not use private implementation details + +use std::convert::TryFrom; + +use rustc_hir::Mutability; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::{ + mir::{self, interpret::ConstAlloc}, + ty::ScalarInt, +}; +use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; + +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar, +}; + +mod error; +mod eval_queries; +mod fn_queries; +mod machine; + +pub use error::*; +pub use eval_queries::*; +pub use fn_queries::*; +pub use machine::*; + +pub(crate) fn const_caller_location( + tcx: TyCtxt<'tcx>, + (file, line, col): (Symbol, u32, u32), +) -> ConstValue<'tcx> { + trace!("const_caller_location: {}:{}:{}", file, line, col); + let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); + + let loc_place = ecx.alloc_caller_location(file, line, col); + if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { + bug!("intern_const_alloc_recursive should not error in this case") + } + ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx)) +} + +/// Convert an evaluated constant to a type level constant +pub(crate) fn const_to_valtree<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + raw: ConstAlloc<'tcx>, +) -> Option> { + let ecx = mk_eval_cx( + tcx, DUMMY_SP, param_env, + // It is absolutely crucial for soundness that + // we do not read from static items or other mutable memory. + false, + ); + let place = ecx.raw_const_to_mplace(raw).unwrap(); + const_to_valtree_inner(&ecx, &place) +} + +fn const_to_valtree_inner<'tcx>( + ecx: &CompileTimeEvalContext<'tcx, 'tcx>, + place: &MPlaceTy<'tcx>, +) -> Option> { + let branches = |n, variant| { + let place = match variant { + Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(), + None => *place, + }; + let variant = + variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32())))); + let fields = (0..n).map(|i| { + let field = ecx.mplace_field(&place, i).unwrap(); + const_to_valtree_inner(ecx, &field) + }); + // For enums, we preped their variant index before the variant's fields so we can figure out + // the variant again when just seeing a valtree. + let branches = variant.into_iter().chain(fields); + Some(ty::ValTree::Branch( + ecx.tcx.arena.alloc_from_iter(branches.collect::>>()?), + )) + }; + match place.layout.ty.kind() { + ty::FnDef(..) => Some(ty::ValTree::zst()), + ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { + let val = ecx.read_immediate(&place.into()).unwrap(); + let val = val.to_scalar().unwrap(); + Some(ty::ValTree::Leaf(val.assert_int())) + } + + // Raw pointers are not allowed in type level constants, as we cannot properly test them for + // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`). + // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to + // agree with runtime equality tests. + ty::FnPtr(_) | ty::RawPtr(_) => None, + ty::Ref(..) => unimplemented!("need to use deref_const"), + + // Trait objects are not allowed in type level constants, as we have no concept for + // resolving their backing type, even if we can do that at const eval time. We may + // hypothetically be able to allow `dyn StructuralEq` trait objects in the future, + // but it is unclear if this is useful. + ty::Dynamic(..) => None, + + ty::Slice(_) | ty::Str => { + unimplemented!("need to find the backing data of the slice/str and recurse on that") + } + ty::Tuple(substs) => branches(substs.len(), None), + ty::Array(_, len) => branches(usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), None), + + ty::Adt(def, _) => { + if def.variants.is_empty() { + bug!("uninhabited types should have errored and never gotten converted to valtree") + } + + let variant = ecx.read_discriminant(&place.into()).unwrap().1; + + branches(def.variants[variant].fields.len(), def.is_enum().then_some(variant)) + } + + ty::Never + | ty::Error(_) + | ty::Foreign(..) + | ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) + | ty::Projection(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(..) + // FIXME(oli-obk): we could look behind opaque types + | ty::Opaque(..) + | ty::Infer(_) + // FIXME(oli-obk): we can probably encode closures just like structs + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) => None, + } +} + +/// This function uses `unwrap` copiously, because an already validated constant +/// must have valid fields and can thus never fail outside of compiler bugs. However, it is +/// invoked from the pretty printer, where it can receive enums with no variants and e.g. +/// `read_discriminant` needs to be able to handle that. +pub(crate) fn destructure_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: &'tcx ty::Const<'tcx>, +) -> mir::DestructuredConst<'tcx> { + trace!("destructure_const: {:?}", val); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let op = ecx.const_to_op(val, None).unwrap(); + + // We go to `usize` as we cannot allocate anything bigger anyway. + let (field_count, variant, down) = match val.ty.kind() { + ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), + ty::Adt(def, _) if def.variants.is_empty() => { + return mir::DestructuredConst { variant: None, fields: &[] }; + } + ty::Adt(def, _) => { + let variant = ecx.read_discriminant(&op).unwrap().1; + let down = ecx.operand_downcast(&op, variant).unwrap(); + (def.variants[variant].fields.len(), Some(variant), down) + } + ty::Tuple(substs) => (substs.len(), None, op), + _ => bug!("cannot destructure constant {:?}", val), + }; + + let fields_iter = (0..field_count).map(|i| { + let field_op = ecx.operand_field(&down, i).unwrap(); + let val = op_to_const(&ecx, &field_op); + ty::Const::from_value(tcx, val, field_op.layout.ty) + }); + let fields = tcx.arena.alloc_from_iter(fields_iter); + + mir::DestructuredConst { variant, fields } +} + +pub(crate) fn deref_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: &'tcx ty::Const<'tcx>, +) -> &'tcx ty::Const<'tcx> { + trace!("deref_const: {:?}", val); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let op = ecx.const_to_op(val, None).unwrap(); + let mplace = ecx.deref_operand(&op).unwrap(); + if let Some(alloc_id) = mplace.ptr.provenance { + assert_eq!( + tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().mutability, + Mutability::Not, + "deref_const cannot be used with mutable allocations as \ + that could allow pattern matching to observe mutable statics", + ); + } + + let ty = match mplace.meta { + MemPlaceMeta::None => mplace.layout.ty, + MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), + // In case of unsized types, figure out the real type behind. + MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { + ty::Str => bug!("there's no sized equivalent of a `str`"), + ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()), + _ => bug!( + "type {} should not have metadata, but had {:?}", + mplace.layout.ty, + mplace.meta + ), + }, + }; + + tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty }) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/cast.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/cast.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/cast.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/cast.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,365 @@ +use std::convert::TryFrom; + +use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::{Float, FloatConvert}; +use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; +use rustc_middle::mir::CastKind; +use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout}; +use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut}; +use rustc_target::abi::{Integer, Variants}; + +use super::{ + util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, +}; + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + pub fn cast( + &mut self, + src: &OpTy<'tcx, M::PointerTag>, + cast_kind: CastKind, + cast_ty: Ty<'tcx>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + use rustc_middle::mir::CastKind::*; + // FIXME: In which cases should we trigger UB when the source is uninit? + match cast_kind { + Pointer(PointerCast::Unsize) => { + let cast_ty = self.layout_of(cast_ty)?; + self.unsize_into(src, cast_ty, dest)?; + } + + Misc => { + let src = self.read_immediate(src)?; + let res = self.misc_cast(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + + Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer) => { + // These are NOPs, but can be wide pointers. + let v = self.read_immediate(src)?; + self.write_immediate(*v, dest)?; + } + + Pointer(PointerCast::ReifyFnPointer) => { + // The src operand does not matter, just its type + match *src.layout.ty.kind() { + ty::FnDef(def_id, substs) => { + // All reifications must be monomorphic, bail out otherwise. + ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; + + let instance = ty::Instance::resolve_for_fn_ptr( + *self.tcx, + self.param_env, + def_id, + substs, + ) + .ok_or_else(|| err_inval!(TooGeneric))?; + + let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); + self.write_pointer(fn_ptr, dest)?; + } + _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty), + } + } + + Pointer(PointerCast::UnsafeFnPointer) => { + let src = self.read_immediate(src)?; + match cast_ty.kind() { + ty::FnPtr(_) => { + // No change to value + self.write_immediate(*src, dest)?; + } + _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty), + } + } + + Pointer(PointerCast::ClosureFnPointer(_)) => { + // The src operand does not matter, just its type + match *src.layout.ty.kind() { + ty::Closure(def_id, substs) => { + // All reifications must be monomorphic, bail out otherwise. + ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; + + let instance = ty::Instance::resolve_closure( + *self.tcx, + def_id, + substs, + ty::ClosureKind::FnOnce, + ); + let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); + self.write_pointer(fn_ptr, dest)?; + } + _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), + } + } + } + Ok(()) + } + + fn misc_cast( + &self, + src: &ImmTy<'tcx, M::PointerTag>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate> { + use rustc_middle::ty::TyKind::*; + trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); + + match src.layout.ty.kind() { + // Floating point + Float(FloatTy::F32) => { + return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into()); + } + Float(FloatTy::F64) => { + return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into()); + } + // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that + // are represented as integers. + _ => assert!( + src.layout.ty.is_bool() + || src.layout.ty.is_char() + || src.layout.ty.is_enum() + || src.layout.ty.is_integral() + || src.layout.ty.is_any_ptr(), + "Unexpected cast from type {:?}", + src.layout.ty + ), + } + + // # First handle non-scalar source values. + + // Handle cast from a ZST enum (0 or 1 variants). + match src.layout.variants { + Variants::Single { index } => { + if src.layout.abi.is_uninhabited() { + // This is dead code, because an uninhabited enum is UB to + // instantiate. + throw_ub!(Unreachable); + } + if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) { + assert!(src.layout.is_zst()); + let discr_layout = self.layout_of(discr.ty)?; + return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into()); + } + } + Variants::Multiple { .. } => {} + } + + // Handle casting any ptr to raw ptr (might be a fat ptr). + if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() { + let dest_layout = self.layout_of(cast_ty)?; + if dest_layout.size == src.layout.size { + // Thin or fat pointer that just hast the ptr kind of target type changed. + return Ok(**src); + } else { + // Casting the metadata away from a fat ptr. + assert_eq!(src.layout.size, 2 * self.memory.pointer_size()); + assert_eq!(dest_layout.size, self.memory.pointer_size()); + assert!(src.layout.ty.is_unsafe_ptr()); + return match **src { + Immediate::ScalarPair(data, _) => Ok(data.into()), + Immediate::Scalar(..) => span_bug!( + self.cur_span(), + "{:?} input to a fat-to-thin cast ({:?} -> {:?})", + *src, + src.layout.ty, + cast_ty + ), + }; + } + } + + // # The remaining source values are scalar. + + // For all remaining casts, we either + // (a) cast a raw ptr to usize, or + // (b) cast from an integer-like (including bool, char, enums). + // In both cases we want the bits. + let bits = src.to_scalar()?.to_bits(src.layout.size)?; + Ok(self.cast_from_scalar(bits, src.layout, cast_ty).into()) + } + + pub(super) fn cast_from_scalar( + &self, + v: u128, // raw bits (there is no ScalarTy so we separate data+layout) + src_layout: TyAndLayout<'tcx>, + cast_ty: Ty<'tcx>, + ) -> Scalar { + // Let's make sure v is sign-extended *if* it has a signed type. + let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. + let v = if signed { self.sign_extend(v, src_layout) } else { v }; + trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty); + use rustc_middle::ty::TyKind::*; + match *cast_ty.kind() { + Int(_) | Uint(_) | RawPtr(_) => { + let size = match *cast_ty.kind() { + Int(t) => Integer::from_int_ty(self, t).size(), + Uint(t) => Integer::from_uint_ty(self, t).size(), + RawPtr(_) => self.pointer_size(), + _ => bug!(), + }; + let v = size.truncate(v); + Scalar::from_uint(v, size) + } + + Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value), + Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value), + Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value), + Float(FloatTy::F64) => Scalar::from_f64(Double::from_u128(v).value), + + Char => { + // `u8` to `char` cast + Scalar::from_u32(u8::try_from(v).unwrap().into()) + } + + // Casts to bool are not permitted by rustc, no need to handle them here. + _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty), + } + } + + fn cast_from_float(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar + where + F: Float + Into> + FloatConvert + FloatConvert, + { + use rustc_middle::ty::TyKind::*; + match *dest_ty.kind() { + // float -> uint + Uint(t) => { + let size = Integer::from_uint_ty(self, t).size(); + // `to_u128` is a saturating cast, which is what we need + // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). + let v = f.to_u128(size.bits_usize()).value; + // This should already fit the bit width + Scalar::from_uint(v, size) + } + // float -> int + Int(t) => { + let size = Integer::from_int_ty(self, t).size(); + // `to_i128` is a saturating cast, which is what we need + // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). + let v = f.to_i128(size.bits_usize()).value; + Scalar::from_int(v, size) + } + // float -> f32 + Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value), + // float -> f64 + Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value), + // That's it. + _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty), + } + } + + fn unsize_into_ptr( + &mut self, + src: &OpTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, + // The pointee types + source_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx> { + // A -> A conversion + let (src_pointee_ty, dest_pointee_ty) = + self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env); + + match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { + (&ty::Array(_, length), &ty::Slice(_)) => { + let ptr = self.read_immediate(src)?.to_scalar()?; + // u64 cast is from usize to u64, which is always good + let val = + Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self); + self.write_immediate(val, dest) + } + (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + let val = self.read_immediate(src)?; + if data_a.principal_def_id() == data_b.principal_def_id() { + return self.write_immediate(*val, dest); + } + // trait upcasting coercion + let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( + src_pointee_ty, + dest_pointee_ty, + )); + + if let Some(entry_idx) = vptr_entry_idx { + let entry_idx = u64::try_from(entry_idx).unwrap(); + let (old_data, old_vptr) = val.to_scalar_pair()?; + let old_vptr = self.scalar_to_ptr(old_vptr); + let new_vptr = self + .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?; + self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) + } else { + self.write_immediate(*val, dest) + } + } + (_, &ty::Dynamic(ref data, _)) => { + // Initial cast from sized to dyn trait + let vtable = self.get_vtable(src_pointee_ty, data.principal())?; + let ptr = self.read_immediate(src)?.to_scalar()?; + let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); + self.write_immediate(val, dest) + } + + _ => { + span_bug!(self.cur_span(), "invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty) + } + } + } + + fn unsize_into( + &mut self, + src: &OpTy<'tcx, M::PointerTag>, + cast_ty: TyAndLayout<'tcx>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty); + match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { + (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. })) + | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => { + self.unsize_into_ptr(src, dest, s, c) + } + (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { + assert_eq!(def_a, def_b); + if def_a.is_box() || def_b.is_box() { + if !def_a.is_box() || !def_b.is_box() { + span_bug!( + self.cur_span(), + "invalid unsizing between {:?} -> {:?}", + src.layout.ty, + cast_ty.ty + ); + } + return self.unsize_into_ptr( + src, + dest, + src.layout.ty.boxed_ty(), + cast_ty.ty.boxed_ty(), + ); + } + + // unsizing of generic struct with pointer fields + // Example: `Arc` -> `Arc` + // here we need to increase the size of every &T thin ptr field to a fat ptr + for i in 0..src.layout.fields.count() { + let cast_ty_field = cast_ty.field(self, i); + if cast_ty_field.is_zst() { + continue; + } + let src_field = self.operand_field(src, i)?; + let dst_field = self.place_field(dest, i)?; + if src_field.layout.ty == cast_ty_field.ty { + self.copy_op(&src_field, &dst_field)?; + } else { + self.unsize_into(&src_field, cast_ty_field, &dst_field)?; + } + } + Ok(()) + } + _ => span_bug!( + self.cur_span(), + "unsize_into: invalid conversion: {:?} -> {:?}", + src.layout, + dest.layout + ), + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/eval_context.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/eval_context.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/eval_context.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/eval_context.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1049 @@ +use std::cell::Cell; +use std::fmt; +use std::mem; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; +use rustc_index::vec::IndexVec; +use rustc_macros::HashStable; +use rustc_middle::mir; +use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; +use rustc_middle::ty::{ + self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, +}; +use rustc_mir_dataflow::storage::AlwaysLiveLocals; +use rustc_query_system::ich::StableHashingContext; +use rustc_session::Limit; +use rustc_span::{Pos, Span}; +use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; + +use super::{ + AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, + MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar, + ScalarMaybeUninit, StackPopJump, +}; +use crate::transform::validate::equal_up_to_regions; + +pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { + /// Stores the `Machine` instance. + /// + /// Note: the stack is provided by the machine. + pub machine: M, + + /// The results of the type checker, from rustc. + /// The span in this is the "root" of the evaluation, i.e., the const + /// we are evaluating (if this is CTFE). + pub tcx: TyCtxtAt<'tcx>, + + /// Bounds in scope for polymorphic evaluations. + pub(crate) param_env: ty::ParamEnv<'tcx>, + + /// The virtual memory system. + pub memory: Memory<'mir, 'tcx, M>, + + /// The recursion limit (cached from `tcx.recursion_limit(())`) + pub recursion_limit: Limit, +} + +// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread +// boundary and dropped in the other thread, it would exit the span in the other thread. +struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>); + +impl SpanGuard { + /// By default a `SpanGuard` does nothing. + fn new() -> Self { + Self(tracing::Span::none(), std::marker::PhantomData) + } + + /// If a span is entered, we exit the previous span (if any, normally none) and enter the + /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of + /// `Frame` by creating a dummy span to being with and then entering it once the frame has + /// been pushed. + fn enter(&mut self, span: tracing::Span) { + // This executes the destructor on the previous instance of `SpanGuard`, ensuring that + // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we + // can't protect the tracing stack, but that'll just lead to weird logging, no actual + // problems. + *self = Self(span, std::marker::PhantomData); + self.0.with_subscriber(|(id, dispatch)| { + dispatch.enter(id); + }); + } +} + +impl Drop for SpanGuard { + fn drop(&mut self) { + self.0.with_subscriber(|(id, dispatch)| { + dispatch.exit(id); + }); + } +} + +/// A stack frame. +pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { + //////////////////////////////////////////////////////////////////////////////// + // Function and callsite information + //////////////////////////////////////////////////////////////////////////////// + /// The MIR for the function called on this frame. + pub body: &'mir mir::Body<'tcx>, + + /// The def_id and substs of the current function. + pub instance: ty::Instance<'tcx>, + + /// Extra data for the machine. + pub extra: Extra, + + //////////////////////////////////////////////////////////////////////////////// + // Return place and locals + //////////////////////////////////////////////////////////////////////////////// + /// Work to perform when returning from this function. + pub return_to_block: StackPopCleanup, + + /// The location where the result of the current stack frame should be written to, + /// and its layout in the caller. + pub return_place: Option>, + + /// The list of locals for this stack frame, stored in order as + /// `[return_ptr, arguments..., variables..., temporaries...]`. + /// The locals are stored as `Option`s. + /// `None` represents a local that is currently dead, while a live local + /// can either directly contain `Scalar` or refer to some part of an `Allocation`. + pub locals: IndexVec>, + + /// The span of the `tracing` crate is stored here. + /// When the guard is dropped, the span is exited. This gives us + /// a full stack trace on all tracing statements. + tracing_span: SpanGuard, + + //////////////////////////////////////////////////////////////////////////////// + // Current position within the function + //////////////////////////////////////////////////////////////////////////////// + /// If this is `Err`, we are not currently executing any particular statement in + /// this frame (can happen e.g. during frame initialization, and during unwinding on + /// frames without cleanup code). + /// We basically abuse `Result` as `Either`. + pub(super) loc: Result, +} + +/// What we store about a frame in an interpreter backtrace. +#[derive(Debug)] +pub struct FrameInfo<'tcx> { + pub instance: ty::Instance<'tcx>, + pub span: Span, + pub lint_root: Option, +} + +/// Unwind information. +#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] +pub enum StackPopUnwind { + /// The cleanup block. + Cleanup(mir::BasicBlock), + /// No cleanup needs to be done. + Skip, + /// Unwinding is not allowed (UB). + NotAllowed, +} + +#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these +pub enum StackPopCleanup { + /// Jump to the next block in the caller, or cause UB if None (that's a function + /// that may never return). Also store layout of return place so + /// we can validate it at that layout. + /// `ret` stores the block we jump to on a normal return, while `unwind` + /// stores the block used for cleanup during unwinding. + Goto { ret: Option, unwind: StackPopUnwind }, + /// Just do nothing: Used by Main and for the `box_alloc` hook in miri. + /// `cleanup` says whether locals are deallocated. Static computation + /// wants them leaked to intern what they need (and just throw away + /// the entire `ecx` when it is done). + None { cleanup: bool }, +} + +/// State of a local variable including a memoized layout +#[derive(Clone, PartialEq, Eq, HashStable)] +pub struct LocalState<'tcx, Tag: Provenance = AllocId> { + pub value: LocalValue, + /// Don't modify if `Some`, this is only used to prevent computing the layout twice + #[stable_hasher(ignore)] + pub layout: Cell>>, +} + +/// Current value of a local variable +#[derive(Copy, Clone, PartialEq, Eq, HashStable, Debug)] // Miri debug-prints these +pub enum LocalValue { + /// This local is not currently alive, and cannot be used at all. + Dead, + /// This local is alive but not yet initialized. It can be written to + /// but not read from or its address taken. Locals get initialized on + /// first write because for unsized locals, we do not know their size + /// before that. + Uninitialized, + /// A normal, live local. + /// Mostly for convenience, we re-use the `Operand` type here. + /// This is an optimization over just always having a pointer here; + /// we can thus avoid doing an allocation when the local just stores + /// immediate values *and* never has its address taken. + Live(Operand), +} + +impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> { + /// Read the local's value or error if the local is not yet live or not live anymore. + /// + /// Note: This may only be invoked from the `Machine::access_local` hook and not from + /// anywhere else. You may be invalidating machine invariants if you do! + pub fn access(&self) -> InterpResult<'tcx, Operand> { + match self.value { + LocalValue::Dead => throw_ub!(DeadLocal), + LocalValue::Uninitialized => { + bug!("The type checker should prevent reading from a never-written local") + } + LocalValue::Live(val) => Ok(val), + } + } + + /// Overwrite the local. If the local can be overwritten in place, return a reference + /// to do so; otherwise return the `MemPlace` to consult instead. + /// + /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from + /// anywhere else. You may be invalidating machine invariants if you do! + pub fn access_mut( + &mut self, + ) -> InterpResult<'tcx, Result<&mut LocalValue, MemPlace>> { + match self.value { + LocalValue::Dead => throw_ub!(DeadLocal), + LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)), + ref mut + local @ (LocalValue::Live(Operand::Immediate(_)) | LocalValue::Uninitialized) => { + Ok(Ok(local)) + } + } + } +} + +impl<'mir, 'tcx, Tag: Provenance> Frame<'mir, 'tcx, Tag> { + pub fn with_extra(self, extra: Extra) -> Frame<'mir, 'tcx, Tag, Extra> { + Frame { + body: self.body, + instance: self.instance, + return_to_block: self.return_to_block, + return_place: self.return_place, + locals: self.locals, + loc: self.loc, + extra, + tracing_span: self.tracing_span, + } + } +} + +impl<'mir, 'tcx, Tag: Provenance, Extra> Frame<'mir, 'tcx, Tag, Extra> { + /// Get the current location within the Frame. + /// + /// If this is `Err`, we are not currently executing any particular statement in + /// this frame (can happen e.g. during frame initialization, and during unwinding on + /// frames without cleanup code). + /// We basically abuse `Result` as `Either`. + /// + /// Used by priroda. + pub fn current_loc(&self) -> Result { + self.loc + } + + /// Return the `SourceInfo` of the current instruction. + pub fn current_source_info(&self) -> Option<&mir::SourceInfo> { + self.loc.ok().map(|loc| self.body.source_info(loc)) + } + + pub fn current_span(&self) -> Span { + match self.loc { + Ok(loc) => self.body.source_info(loc).span, + Err(span) => span, + } + } +} + +impl<'tcx> fmt::Display for FrameInfo<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ty::tls::with(|tcx| { + if tcx.def_key(self.instance.def_id()).disambiguated_data.data + == DefPathData::ClosureExpr + { + write!(f, "inside closure")?; + } else { + write!(f, "inside `{}`", self.instance)?; + } + if !self.span.is_dummy() { + let sm = tcx.sess.source_map(); + let lo = sm.lookup_char_pos(self.span.lo()); + write!( + f, + " at {}:{}:{}", + sm.filename_for_diagnostics(&lo.file.name), + lo.line, + lo.col.to_usize() + 1 + )?; + } + Ok(()) + }) + } +} + +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> { + #[inline] + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'mir, 'tcx, M> +where + M: Machine<'mir, 'tcx>, +{ + #[inline] + fn tcx(&self) -> TyCtxt<'tcx> { + *self.tcx + } +} + +impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M> +where + M: Machine<'mir, 'tcx>, +{ + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M> { + type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>; + + #[inline] + fn layout_tcx_at_span(&self) -> Span { + self.tcx.span + } + + #[inline] + fn handle_layout_err( + &self, + err: LayoutError<'tcx>, + _: Span, + _: Ty<'tcx>, + ) -> InterpErrorInfo<'tcx> { + err_inval!(Layout(err)).into() + } +} + +/// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. +/// This test should be symmetric, as it is primarily about layout compatibility. +pub(super) fn mir_assign_valid_types<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + src: TyAndLayout<'tcx>, + dest: TyAndLayout<'tcx>, +) -> bool { + // Type-changing assignments can happen when subtyping is used. While + // all normal lifetimes are erased, higher-ranked types with their + // late-bound lifetimes are still around and can lead to type + // differences. So we compare ignoring lifetimes. + if equal_up_to_regions(tcx, param_env, src.ty, dest.ty) { + // Make sure the layout is equal, too -- just to be safe. Miri really + // needs layout equality. For performance reason we skip this check when + // the types are equal. Equal types *can* have different layouts when + // enum downcast is involved (as enum variants carry the type of the + // enum), but those should never occur in assignments. + if cfg!(debug_assertions) || src.ty != dest.ty { + assert_eq!(src.layout, dest.layout); + } + true + } else { + false + } +} + +/// Use the already known layout if given (but sanity check in debug mode), +/// or compute the layout. +#[cfg_attr(not(debug_assertions), inline(always))] +pub(super) fn from_known_layout<'tcx>( + tcx: TyCtxtAt<'tcx>, + param_env: ParamEnv<'tcx>, + known_layout: Option>, + compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, +) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + match known_layout { + None => compute(), + Some(known_layout) => { + if cfg!(debug_assertions) { + let check_layout = compute()?; + if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) { + span_bug!( + tcx.span, + "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}", + known_layout.ty, + check_layout.ty, + ); + } + } + Ok(known_layout) + } + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + pub fn new( + tcx: TyCtxt<'tcx>, + root_span: Span, + param_env: ty::ParamEnv<'tcx>, + machine: M, + memory_extra: M::MemoryExtra, + ) -> Self { + InterpCx { + machine, + tcx: tcx.at(root_span), + param_env, + memory: Memory::new(tcx, memory_extra), + recursion_limit: tcx.recursion_limit(), + } + } + + #[inline(always)] + pub fn cur_span(&self) -> Span { + self.stack() + .iter() + .rev() + .find(|frame| !frame.instance.def.requires_caller_location(*self.tcx)) + .map_or(self.tcx.span, |f| f.current_span()) + } + + #[inline(always)] + pub fn scalar_to_ptr(&self, scalar: Scalar) -> Pointer> { + self.memory.scalar_to_ptr(scalar) + } + + /// Call this to turn untagged "global" pointers (obtained via `tcx`) into + /// the machine pointer to the allocation. Must never be used + /// for any other pointers, nor for TLS statics. + /// + /// Using the resulting pointer represents a *direct* access to that memory + /// (e.g. by directly using a `static`), + /// as opposed to access through a pointer that was created by the program. + /// + /// This function can fail only if `ptr` points to an `extern static`. + #[inline(always)] + pub fn global_base_pointer(&self, ptr: Pointer) -> InterpResult<'tcx, Pointer> { + self.memory.global_base_pointer(ptr) + } + + #[inline(always)] + pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] { + M::stack(self) + } + + #[inline(always)] + pub(crate) fn stack_mut( + &mut self, + ) -> &mut Vec> { + M::stack_mut(self) + } + + #[inline(always)] + pub fn frame_idx(&self) -> usize { + let stack = self.stack(); + assert!(!stack.is_empty()); + stack.len() - 1 + } + + #[inline(always)] + pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { + self.stack().last().expect("no call frames exist") + } + + #[inline(always)] + pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { + self.stack_mut().last_mut().expect("no call frames exist") + } + + #[inline(always)] + pub(super) fn body(&self) -> &'mir mir::Body<'tcx> { + self.frame().body + } + + #[inline(always)] + pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { + assert!(ty.abi.is_signed()); + ty.size.sign_extend(value) + } + + #[inline(always)] + pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { + ty.size.truncate(value) + } + + #[inline] + pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { + ty.is_freeze(self.tcx, self.param_env) + } + + pub fn load_mir( + &self, + instance: ty::InstanceDef<'tcx>, + promoted: Option, + ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { + // do not continue if typeck errors occurred (can only occur in local crate) + let def = instance.with_opt_param(); + if let Some(def) = def.as_local() { + if self.tcx.has_typeck_results(def.did) { + if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors { + throw_inval!(AlreadyReported(error_reported)) + } + } + } + trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); + if let Some(promoted) = promoted { + return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]); + } + M::load_mir(self, instance) + } + + /// Call this on things you got out of the MIR (so it is as generic as the current + /// stack frame), to bring it into the proper environment for this interpreter. + pub(super) fn subst_from_current_frame_and_normalize_erasing_regions>( + &self, + value: T, + ) -> T { + self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value) + } + + /// Call this on things you got out of the MIR (so it is as generic as the provided + /// stack frame), to bring it into the proper environment for this interpreter. + pub(super) fn subst_from_frame_and_normalize_erasing_regions>( + &self, + frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, + value: T, + ) -> T { + frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) + } + + /// The `substs` are assumed to already be in our interpreter "universe" (param_env). + pub(super) fn resolve( + &self, + def: ty::WithOptConstParam, + substs: SubstsRef<'tcx>, + ) -> InterpResult<'tcx, ty::Instance<'tcx>> { + trace!("resolve: {:?}, {:#?}", def, substs); + trace!("param_env: {:#?}", self.param_env); + trace!("substs: {:#?}", substs); + match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) { + Ok(Some(instance)) => Ok(instance), + Ok(None) => throw_inval!(TooGeneric), + + // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. + Err(error_reported) => throw_inval!(AlreadyReported(error_reported)), + } + } + + #[inline(always)] + pub fn layout_of_local( + &self, + frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, + local: mir::Local, + layout: Option>, + ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + // `const_prop` runs into this with an invalid (empty) frame, so we + // have to support that case (mostly by skipping all caching). + match frame.locals.get(local).and_then(|state| state.layout.get()) { + None => { + let layout = from_known_layout(self.tcx, self.param_env, layout, || { + let local_ty = frame.body.local_decls[local].ty; + let local_ty = + self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty); + self.layout_of(local_ty) + })?; + if let Some(state) = frame.locals.get(local) { + // Layouts of locals are requested a lot, so we cache them. + state.layout.set(Some(layout)); + } + Ok(layout) + } + Some(layout) => Ok(layout), + } + } + + /// Returns the actual dynamic size and alignment of the place at the given type. + /// Only the "meta" (metadata) part of the place matters. + /// This can fail to provide an answer for extern types. + pub(super) fn size_and_align_of( + &self, + metadata: &MemPlaceMeta, + layout: &TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, Option<(Size, Align)>> { + if !layout.is_unsized() { + return Ok(Some((layout.size, layout.align.abi))); + } + match layout.ty.kind() { + ty::Adt(..) | ty::Tuple(..) => { + // First get the size of all statically known fields. + // Don't use type_of::sizing_type_of because that expects t to be sized, + // and it also rounds up to alignment, which we want to avoid, + // as the unsized field's alignment could be smaller. + assert!(!layout.ty.is_simd()); + assert!(layout.fields.count() > 0); + trace!("DST layout: {:?}", layout); + + let sized_size = layout.fields.offset(layout.fields.count() - 1); + let sized_align = layout.align.abi; + trace!( + "DST {} statically sized prefix size: {:?} align: {:?}", + layout.ty, + sized_size, + sized_align + ); + + // Recurse to get the size of the dynamically sized field (must be + // the last field). Can't have foreign types here, how would we + // adjust alignment and size for them? + let field = layout.field(self, layout.fields.count() - 1); + let (unsized_size, unsized_align) = + match self.size_and_align_of(metadata, &field)? { + Some(size_and_align) => size_and_align, + None => { + // A field with extern type. If this field is at offset 0, we behave + // like the underlying extern type. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. + if sized_size == Size::ZERO { + return Ok(None); + } else { + span_bug!( + self.cur_span(), + "Fields cannot be extern types, unless they are at offset 0" + ) + } + } + }; + + // FIXME (#26403, #27023): We should be adding padding + // to `sized_size` (to accommodate the `unsized_align` + // required of the unsized field that follows) before + // summing it with `sized_size`. (Note that since #26403 + // is unfixed, we do not yet add the necessary padding + // here. But this is where the add would go.) + + // Return the sum of sizes and max of aligns. + let size = sized_size + unsized_size; // `Size` addition + + // Choose max of two known alignments (combined value must + // be aligned according to more restrictive of the two). + let align = sized_align.max(unsized_align); + + // Issue #27023: must add any necessary padding to `size` + // (to make it a multiple of `align`) before returning it. + let size = size.align_to(align); + + // Check if this brought us over the size limit. + if size.bytes() >= self.tcx.data_layout.obj_size_bound() { + throw_ub!(InvalidMeta("total size is bigger than largest supported object")); + } + Ok(Some((size, align))) + } + ty::Dynamic(..) => { + let vtable = self.scalar_to_ptr(metadata.unwrap_meta()); + // Read size and align from vtable (already checks size). + Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) + } + + ty::Slice(_) | ty::Str => { + let len = metadata.unwrap_meta().to_machine_usize(self)?; + let elem = layout.field(self, 0); + + // Make sure the slice is not too big. + let size = elem.size.checked_mul(len, self).ok_or_else(|| { + err_ub!(InvalidMeta("slice is bigger than largest supported object")) + })?; + Ok(Some((size, elem.align.abi))) + } + + ty::Foreign(_) => Ok(None), + + _ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty), + } + } + #[inline] + pub fn size_and_align_of_mplace( + &self, + mplace: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Option<(Size, Align)>> { + self.size_and_align_of(&mplace.meta, &mplace.layout) + } + + pub fn push_stack_frame( + &mut self, + instance: ty::Instance<'tcx>, + body: &'mir mir::Body<'tcx>, + return_place: Option<&PlaceTy<'tcx, M::PointerTag>>, + return_to_block: StackPopCleanup, + ) -> InterpResult<'tcx> { + // first push a stack frame so we have access to the local substs + let pre_frame = Frame { + body, + loc: Err(body.span), // Span used for errors caused during preamble. + return_to_block, + return_place: return_place.copied(), + // empty local array, we fill it in below, after we are inside the stack frame and + // all methods actually know about the frame + locals: IndexVec::new(), + instance, + tracing_span: SpanGuard::new(), + extra: (), + }; + let frame = M::init_frame_extra(self, pre_frame)?; + self.stack_mut().push(frame); + + // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). + for const_ in &body.required_consts { + let span = const_.span; + let const_ = + self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal); + self.mir_const_to_op(&const_, None).map_err(|err| { + // If there was an error, set the span of the current frame to this constant. + // Avoiding doing this when evaluation succeeds. + self.frame_mut().loc = Err(span); + err + })?; + } + + // Locals are initially uninitialized. + let dummy = LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) }; + let mut locals = IndexVec::from_elem(dummy, &body.local_decls); + + // Now mark those locals as dead that we do not want to initialize + // Mark locals that use `Storage*` annotations as dead on function entry. + let always_live = AlwaysLiveLocals::new(self.body()); + for local in locals.indices() { + if !always_live.contains(local) { + locals[local].value = LocalValue::Dead; + } + } + // done + self.frame_mut().locals = locals; + M::after_stack_push(self)?; + self.frame_mut().loc = Ok(mir::Location::START); + + let span = info_span!("frame", "{}", instance); + self.frame_mut().tracing_span.enter(span); + + Ok(()) + } + + /// Jump to the given block. + #[inline] + pub fn go_to_block(&mut self, target: mir::BasicBlock) { + self.frame_mut().loc = Ok(mir::Location { block: target, statement_index: 0 }); + } + + /// *Return* to the given `target` basic block. + /// Do *not* use for unwinding! Use `unwind_to_block` instead. + /// + /// If `target` is `None`, that indicates the function cannot return, so we raise UB. + pub fn return_to_block(&mut self, target: Option) -> InterpResult<'tcx> { + if let Some(target) = target { + self.go_to_block(target); + Ok(()) + } else { + throw_ub!(Unreachable) + } + } + + /// *Unwind* to the given `target` basic block. + /// Do *not* use for returning! Use `return_to_block` instead. + /// + /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup + /// during unwinding, and we will just keep propagating that upwards. + /// + /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow + /// unwinding, and doing so is UB. + pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> { + self.frame_mut().loc = match target { + StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }), + StackPopUnwind::Skip => Err(self.frame_mut().body.span), + StackPopUnwind::NotAllowed => { + throw_ub_format!("unwinding past a stack frame that does not allow unwinding") + } + }; + Ok(()) + } + + /// Pops the current frame from the stack, deallocating the + /// memory for allocated locals. + /// + /// If `unwinding` is `false`, then we are performing a normal return + /// from a function. In this case, we jump back into the frame of the caller, + /// and continue execution as normal. + /// + /// If `unwinding` is `true`, then we are in the middle of a panic, + /// and need to unwind this frame. In this case, we jump to the + /// `cleanup` block for the function, which is responsible for running + /// `Drop` impls for any locals that have been initialized at this point. + /// The cleanup block ends with a special `Resume` terminator, which will + /// cause us to continue unwinding. + pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> { + info!( + "popping stack frame ({})", + if unwinding { "during unwinding" } else { "returning from function" } + ); + + // Sanity check `unwinding`. + assert_eq!( + unwinding, + match self.frame().loc { + Ok(loc) => self.body().basic_blocks()[loc.block].is_cleanup, + Err(_) => true, + } + ); + + if unwinding && self.frame_idx() == 0 { + throw_ub_format!("unwinding past the topmost frame of the stack"); + } + + let frame = + self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); + + if !unwinding { + // Copy the return value to the caller's stack frame. + if let Some(ref return_place) = frame.return_place { + let op = self.access_local(&frame, mir::RETURN_PLACE, None)?; + self.copy_op_transmute(&op, return_place)?; + trace!("{:?}", self.dump_place(**return_place)); + } else { + throw_ub!(Unreachable); + } + } + + let return_to_block = frame.return_to_block; + + // Now where do we jump next? + + // Usually we want to clean up (deallocate locals), but in a few rare cases we don't. + // In that case, we return early. We also avoid validation in that case, + // because this is CTFE and the final value will be thoroughly validated anyway. + let cleanup = match return_to_block { + StackPopCleanup::Goto { .. } => true, + StackPopCleanup::None { cleanup, .. } => cleanup, + }; + + if !cleanup { + assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); + assert!(!unwinding, "tried to skip cleanup during unwinding"); + // Leak the locals, skip validation, skip machine hook. + return Ok(()); + } + + // Cleanup: deallocate all locals that are backed by an allocation. + for local in &frame.locals { + self.deallocate_local(local.value)?; + } + + if M::after_stack_pop(self, frame, unwinding)? == StackPopJump::NoJump { + // The hook already did everything. + // We want to skip the `info!` below, hence early return. + return Ok(()); + } + // Normal return, figure out where to jump. + if unwinding { + // Follow the unwind edge. + let unwind = match return_to_block { + StackPopCleanup::Goto { unwind, .. } => unwind, + StackPopCleanup::None { .. } => { + panic!("Encountered StackPopCleanup::None when unwinding!") + } + }; + self.unwind_to_block(unwind) + } else { + // Follow the normal return edge. + match return_to_block { + StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret), + StackPopCleanup::None { .. } => Ok(()), + } + } + } + + /// Mark a storage as live, killing the previous content. + pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> { + assert!(local != mir::RETURN_PLACE, "Cannot make return place live"); + trace!("{:?} is now live", local); + + let local_val = LocalValue::Uninitialized; + // StorageLive expects the local to be dead, and marks it live. + let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); + if !matches!(old, LocalValue::Dead) { + throw_ub_format!("StorageLive on a local that was already live"); + } + Ok(()) + } + + pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> { + assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); + trace!("{:?} is now dead", local); + + // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR) + let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); + self.deallocate_local(old)?; + Ok(()) + } + + fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { + if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { + // All locals have a backing allocation, even if the allocation is empty + // due to the local having ZST type. Hence we can `unwrap`. + trace!( + "deallocating local {:?}: {:?}", + local, + self.memory.dump_alloc(ptr.provenance.unwrap().get_alloc_id()) + ); + self.memory.deallocate(ptr, None, MemoryKind::Stack)?; + }; + Ok(()) + } + + pub fn eval_to_allocation( + &self, + gid: GlobalId<'tcx>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics + // and thus don't care about the parameter environment. While we could just use + // `self.param_env`, that would mean we invoke the query to evaluate the static + // with different parameter environments, thus causing the static to be evaluated + // multiple times. + let param_env = if self.tcx.is_static(gid.instance.def_id()) { + ty::ParamEnv::reveal_all() + } else { + self.param_env + }; + let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?; + self.raw_const_to_mplace(val) + } + + #[must_use] + pub fn dump_place(&'a self, place: Place) -> PlacePrinter<'a, 'mir, 'tcx, M> { + PlacePrinter { ecx: self, place } + } + + #[must_use] + pub fn generate_stacktrace(&self) -> Vec> { + let mut frames = Vec::new(); + for frame in self + .stack() + .iter() + .rev() + .skip_while(|frame| frame.instance.def.requires_caller_location(*self.tcx)) + { + let lint_root = frame.current_source_info().and_then(|source_info| { + match &frame.body.source_scopes[source_info.scope].local_data { + mir::ClearCrossCrate::Set(data) => Some(data.lint_root), + mir::ClearCrossCrate::Clear => None, + } + }); + let span = frame.current_span(); + + frames.push(FrameInfo { span, instance: frame.instance, lint_root }); + } + trace!("generate stacktrace: {:#?}", frames); + frames + } +} + +#[doc(hidden)] +/// Helper struct for the `dump_place` function. +pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { + ecx: &'a InterpCx<'mir, 'tcx, M>, + place: Place, +} + +impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug + for PlacePrinter<'a, 'mir, 'tcx, M> +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.place { + Place::Local { frame, local } => { + let mut allocs = Vec::new(); + write!(fmt, "{:?}", local)?; + if frame != self.ecx.frame_idx() { + write!(fmt, " ({} frames up)", self.ecx.frame_idx() - frame)?; + } + write!(fmt, ":")?; + + match self.ecx.stack()[frame].locals[local].value { + LocalValue::Dead => write!(fmt, " is dead")?, + LocalValue::Uninitialized => write!(fmt, " is uninitialized")?, + LocalValue::Live(Operand::Indirect(mplace)) => { + write!( + fmt, + " by align({}){} ref {:?}:", + mplace.align.bytes(), + match mplace.meta { + MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), + MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), + }, + mplace.ptr, + )?; + allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id)); + } + LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { + write!(fmt, " {:?}", val)?; + if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val { + allocs.push(ptr.provenance.get_alloc_id()); + } + } + LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { + write!(fmt, " ({:?}, {:?})", val1, val2)?; + if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val1 { + allocs.push(ptr.provenance.get_alloc_id()); + } + if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val2 { + allocs.push(ptr.provenance.get_alloc_id()); + } + } + } + + write!(fmt, ": {:?}", self.ecx.memory.dump_allocs(allocs)) + } + Place::Ptr(mplace) => match mplace.ptr.provenance.map(Provenance::get_alloc_id) { + Some(alloc_id) => write!( + fmt, + "by align({}) ref {:?}: {:?}", + mplace.align.bytes(), + mplace.ptr, + self.ecx.memory.dump_alloc(alloc_id) + ), + ptr => write!(fmt, " integral by ref: {:?}", ptr), + }, + } + } +} + +impl<'ctx, 'mir, 'tcx, Tag: Provenance, Extra> HashStable> + for Frame<'mir, 'tcx, Tag, Extra> +where + Extra: HashStable>, + Tag: HashStable>, +{ + fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) { + // Exhaustive match on fields to make sure we forget no field. + let Frame { + body, + instance, + return_to_block, + return_place, + locals, + loc, + extra, + tracing_span: _, + } = self; + body.hash_stable(hcx, hasher); + instance.hash_stable(hcx, hasher); + return_to_block.hash_stable(hcx, hasher); + return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher); + locals.hash_stable(hcx, hasher); + loc.hash_stable(hcx, hasher); + extra.hash_stable(hcx, hasher); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intern.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intern.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intern.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intern.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,437 @@ +//! This module specifies the type based interner for constants. +//! +//! After a const evaluation has computed a value, before we destroy the const evaluator's session +//! memory, we need to extract all memory allocations to the global memory pool so they stay around. +//! +//! In principle, this is not very complicated: we recursively walk the final value, follow all the +//! pointers, and move all reachable allocations to the global `tcx` memory. The only complication +//! is picking the right mutability for the allocations in a `static` initializer: we want to make +//! as many allocations as possible immutable so LLVM can put them into read-only memory. At the +//! same time, we need to make memory that could be mutated by the program mutable to avoid +//! incorrect compilations. To achieve this, we do a type-based traversal of the final value, +//! tracking mutable and shared references and `UnsafeCell` to determine the current mutability. +//! (In principle, we could skip this type-based part for `const` and promoteds, as they need to be +//! always immutable. At least for `const` however we use this opportunity to reject any `const` +//! that contains allocations whose mutability we cannot identify.) + +use super::validity::RefTracking; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::ErrorReported; +use rustc_hir as hir; +use rustc_middle::mir::interpret::InterpResult; +use rustc_middle::ty::{self, layout::TyAndLayout, Ty}; + +use rustc_ast::Mutability; + +use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, ValueVisitor}; +use crate::const_eval; + +pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< + 'mir, + 'tcx, + MemoryKind = T, + PointerTag = AllocId, + ExtraFnVal = !, + FrameExtra = (), + AllocExtra = (), + MemoryMap = FxHashMap, Allocation)>, +>; + +struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> { + /// The ectx from which we intern. + ecx: &'rt mut InterpCx<'mir, 'tcx, M>, + /// Previously encountered safe references. + ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, InternMode)>, + /// A list of all encountered allocations. After type-based interning, we traverse this list to + /// also intern allocations that are only referenced by a raw pointer or inside a union. + leftover_allocations: &'rt mut FxHashSet, + /// The root kind of the value that we're looking at. This field is never mutated for a + /// particular allocation. It is primarily used to make as many allocations as possible + /// read-only so LLVM can place them in const memory. + mode: InternMode, + /// This field stores whether we are *currently* inside an `UnsafeCell`. This can affect + /// the intern mode of references we encounter. + inside_unsafe_cell: bool, +} + +#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] +enum InternMode { + /// A static and its current mutability. Below shared references inside a `static mut`, + /// this is *immutable*, and below mutable references inside an `UnsafeCell`, this + /// is *mutable*. + Static(hir::Mutability), + /// A `const`. + Const, +} + +/// Signalling data structure to ensure we don't recurse +/// into the memory of other constants or statics +struct IsStaticOrFn; + +/// Intern an allocation without looking at its children. +/// `mode` is the mode of the environment where we found this pointer. +/// `mutablity` is the mutability of the place to be interned; even if that says +/// `immutable` things might become mutable if `ty` is not frozen. +/// `ty` can be `None` if there is no potential interior mutability +/// to account for (e.g. for vtables). +fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>( + ecx: &'rt mut InterpCx<'mir, 'tcx, M>, + leftover_allocations: &'rt mut FxHashSet, + alloc_id: AllocId, + mode: InternMode, + ty: Option>, +) -> Option { + trace!("intern_shallow {:?} with {:?}", alloc_id, mode); + // remove allocation + let tcx = ecx.tcx; + let (kind, mut alloc) = match ecx.memory.alloc_map.remove(&alloc_id) { + Some(entry) => entry, + None => { + // Pointer not found in local memory map. It is either a pointer to the global + // map, or dangling. + // If the pointer is dangling (neither in local nor global memory), we leave it + // to validation to error -- it has the much better error messages, pointing out where + // in the value the dangling reference lies. + // The `delay_span_bug` ensures that we don't forget such a check in validation. + if tcx.get_global_alloc(alloc_id).is_none() { + tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer"); + } + // treat dangling pointers like other statics + // just to stop trying to recurse into them + return Some(IsStaticOrFn); + } + }; + // This match is just a canary for future changes to `MemoryKind`, which most likely need + // changes in this function. + match kind { + MemoryKind::Stack + | MemoryKind::Machine(const_eval::MemoryKind::Heap) + | MemoryKind::CallerLocation => {} + } + // Set allocation mutability as appropriate. This is used by LLVM to put things into + // read-only memory, and also by Miri when evaluating other globals that + // access this one. + if let InternMode::Static(mutability) = mode { + // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume + // no interior mutability. + let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env)); + // For statics, allocation mutability is the combination of place mutability and + // type mutability. + // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere. + let immutable = mutability == Mutability::Not && frozen; + if immutable { + alloc.mutability = Mutability::Not; + } else { + // Just making sure we are not "upgrading" an immutable allocation to mutable. + assert_eq!(alloc.mutability, Mutability::Mut); + } + } else { + // No matter what, *constants are never mutable*. Mutating them is UB. + // See const_eval::machine::MemoryExtra::can_access_statics for why + // immutability is so important. + + // Validation will ensure that there is no `UnsafeCell` on an immutable allocation. + alloc.mutability = Mutability::Not; + }; + // link the alloc id to the actual allocation + let alloc = tcx.intern_const_alloc(alloc); + leftover_allocations.extend(alloc.relocations().iter().map(|&(_, alloc_id)| alloc_id)); + tcx.set_alloc_id_memory(alloc_id, alloc); + None +} + +impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + InternVisitor<'rt, 'mir, 'tcx, M> +{ + fn intern_shallow( + &mut self, + alloc_id: AllocId, + mode: InternMode, + ty: Option>, + ) -> Option { + intern_shallow(self.ecx, self.leftover_allocations, alloc_id, mode, ty) + } +} + +impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + ValueVisitor<'mir, 'tcx, M> for InternVisitor<'rt, 'mir, 'tcx, M> +{ + type V = MPlaceTy<'tcx>; + + #[inline(always)] + fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { + &self.ecx + } + + fn visit_aggregate( + &mut self, + mplace: &MPlaceTy<'tcx>, + fields: impl Iterator>, + ) -> InterpResult<'tcx> { + // ZSTs cannot contain pointers, so we can skip them. + if mplace.layout.is_zst() { + return Ok(()); + } + + if let Some(def) = mplace.layout.ty.ty_adt_def() { + if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() { + // We are crossing over an `UnsafeCell`, we can mutate again. This means that + // References we encounter inside here are interned as pointing to mutable + // allocations. + // Remember the `old` value to handle nested `UnsafeCell`. + let old = std::mem::replace(&mut self.inside_unsafe_cell, true); + let walked = self.walk_aggregate(mplace, fields); + self.inside_unsafe_cell = old; + return walked; + } + } + + self.walk_aggregate(mplace, fields) + } + + fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { + // Handle Reference types, as these are the only relocations supported by const eval. + // Raw pointers (and boxes) are handled by the `leftover_relocations` logic. + let tcx = self.ecx.tcx; + let ty = mplace.layout.ty; + if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() { + let value = self.ecx.read_immediate(&(*mplace).into())?; + let mplace = self.ecx.ref_to_mplace(&value)?; + assert_eq!(mplace.layout.ty, referenced_ty); + // Handle trait object vtables. + if let ty::Dynamic(..) = + tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() + { + let ptr = self.ecx.scalar_to_ptr(mplace.meta.unwrap_meta()); + if let Some(alloc_id) = ptr.provenance { + // Explicitly choose const mode here, since vtables are immutable, even + // if the reference of the fat pointer is mutable. + self.intern_shallow(alloc_id, InternMode::Const, None); + } else { + // Validation will error (with a better message) on an invalid vtable pointer. + // Let validation show the error message, but make sure it *does* error. + tcx.sess + .delay_span_bug(tcx.span, "vtables pointers cannot be integer pointers"); + } + } + // Check if we have encountered this pointer+layout combination before. + // Only recurse for allocation-backed pointers. + if let Some(alloc_id) = mplace.ptr.provenance { + // Compute the mode with which we intern this. Our goal here is to make as many + // statics as we can immutable so they can be placed in read-only memory by LLVM. + let ref_mode = match self.mode { + InternMode::Static(mutbl) => { + // In statics, merge outer mutability with reference mutability and + // take into account whether we are in an `UnsafeCell`. + + // The only way a mutable reference actually works as a mutable reference is + // by being in a `static mut` directly or behind another mutable reference. + // If there's an immutable reference or we are inside a `static`, then our + // mutable reference is equivalent to an immutable one. As an example: + // `&&mut Foo` is semantically equivalent to `&&Foo` + match ref_mutability { + _ if self.inside_unsafe_cell => { + // Inside an `UnsafeCell` is like inside a `static mut`, the "outer" + // mutability does not matter. + InternMode::Static(ref_mutability) + } + Mutability::Not => { + // A shared reference, things become immutable. + // We do *not* consider `freeze` here: `intern_shallow` considers + // `freeze` for the actual mutability of this allocation; the intern + // mode for references contained in this allocation is tracked more + // precisely when traversing the referenced data (by tracking + // `UnsafeCell`). This makes sure that `&(&i32, &Cell)` still + // has the left inner reference interned into a read-only + // allocation. + InternMode::Static(Mutability::Not) + } + Mutability::Mut => { + // Mutable reference. + InternMode::Static(mutbl) + } + } + } + InternMode::Const => { + // Ignore `UnsafeCell`, everything is immutable. Validity does some sanity + // checking for mutable references that we encounter -- they must all be + // ZST. + InternMode::Const + } + }; + match self.intern_shallow(alloc_id, ref_mode, Some(referenced_ty)) { + // No need to recurse, these are interned already and statics may have + // cycles, so we don't want to recurse there + Some(IsStaticOrFn) => {} + // intern everything referenced by this value. The mutability is taken from the + // reference. It is checked above that mutable references only happen in + // `static mut` + None => self.ref_tracking.track((mplace, ref_mode), || ()), + } + } + Ok(()) + } else { + // Not a reference -- proceed recursively. + self.walk_value(mplace) + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] +pub enum InternKind { + /// The `mutability` of the static, ignoring the type which may have interior mutability. + Static(hir::Mutability), + Constant, + Promoted, +} + +/// Intern `ret` and everything it references. +/// +/// This *cannot raise an interpreter error*. Doing so is left to validation, which +/// tracks where in the value we are and thus can show much better error messages. +/// Any errors here would anyway be turned into `const_err` lints, whereas validation failures +/// are hard errors. +#[tracing::instrument(level = "debug", skip(ecx))] +pub fn intern_const_alloc_recursive>( + ecx: &mut InterpCx<'mir, 'tcx, M>, + intern_kind: InternKind, + ret: &MPlaceTy<'tcx>, +) -> Result<(), ErrorReported> +where + 'tcx: 'mir, +{ + let tcx = ecx.tcx; + let base_intern_mode = match intern_kind { + InternKind::Static(mutbl) => InternMode::Static(mutbl), + // `Constant` includes array lengths. + InternKind::Constant | InternKind::Promoted => InternMode::Const, + }; + + // Type based interning. + // `ref_tracking` tracks typed references we have already interned and still need to crawl for + // more typed information inside them. + // `leftover_allocations` collects *all* allocations we see, because some might not + // be available in a typed way. They get interned at the end. + let mut ref_tracking = RefTracking::empty(); + let leftover_allocations = &mut FxHashSet::default(); + + // start with the outermost allocation + intern_shallow( + ecx, + leftover_allocations, + // The outermost allocation must exist, because we allocated it with + // `Memory::allocate`. + ret.ptr.provenance.unwrap(), + base_intern_mode, + Some(ret.layout.ty), + ); + + ref_tracking.track((*ret, base_intern_mode), || ()); + + while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() { + let res = InternVisitor { + ref_tracking: &mut ref_tracking, + ecx, + mode, + leftover_allocations, + inside_unsafe_cell: false, + } + .visit_value(&mplace); + // We deliberately *ignore* interpreter errors here. When there is a problem, the remaining + // references are "leftover"-interned, and later validation will show a proper error + // and point at the right part of the value causing the problem. + match res { + Ok(()) => {} + Err(error) => { + ecx.tcx.sess.delay_span_bug( + ecx.tcx.span, + &format!( + "error during interning should later cause validation failure: {}", + error + ), + ); + } + } + } + + // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw + // pointers, ... So we can't intern them according to their type rules + + let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect(); + while let Some(alloc_id) = todo.pop() { + if let Some((_, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) { + // We can't call the `intern_shallow` method here, as its logic is tailored to safe + // references and a `leftover_allocations` set (where we only have a todo-list here). + // So we hand-roll the interning logic here again. + match intern_kind { + // Statics may contain mutable allocations even behind relocations. + // Even for immutable statics it would be ok to have mutable allocations behind + // raw pointers, e.g. for `static FOO: *const AtomicUsize = &AtomicUsize::new(42)`. + InternKind::Static(_) => {} + // Raw pointers in promoteds may only point to immutable things so we mark + // everything as immutable. + // It is UB to mutate through a raw pointer obtained via an immutable reference: + // Since all references and pointers inside a promoted must by their very definition + // be created from an immutable reference (and promotion also excludes interior + // mutability), mutating through them would be UB. + // There's no way we can check whether the user is using raw pointers correctly, + // so all we can do is mark this as immutable here. + InternKind::Promoted => { + // See const_eval::machine::MemoryExtra::can_access_statics for why + // immutability is so important. + alloc.mutability = Mutability::Not; + } + InternKind::Constant => { + // If it's a constant, we should not have any "leftovers" as everything + // is tracked by const-checking. + // FIXME: downgrade this to a warning? It rejects some legitimate consts, + // such as `const CONST_RAW: *const Vec = &Vec::new() as *const _;`. + ecx.tcx + .sess + .span_err(ecx.tcx.span, "untyped pointers are not allowed in constant"); + // For better errors later, mark the allocation as immutable. + alloc.mutability = Mutability::Not; + } + } + let alloc = tcx.intern_const_alloc(alloc); + tcx.set_alloc_id_memory(alloc_id, alloc); + for &(_, alloc_id) in alloc.relocations().iter() { + if leftover_allocations.insert(alloc_id) { + todo.push(alloc_id); + } + } + } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) { + // Codegen does not like dangling pointers, and generally `tcx` assumes that + // all allocations referenced anywhere actually exist. So, make sure we error here. + ecx.tcx.sess.span_err(ecx.tcx.span, "encountered dangling pointer in final constant"); + return Err(ErrorReported); + } else if ecx.tcx.get_global_alloc(alloc_id).is_none() { + // We have hit an `AllocId` that is neither in local or global memory and isn't + // marked as dangling by local memory. That should be impossible. + span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id); + } + } + Ok(()) +} + +impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> + InterpCx<'mir, 'tcx, M> +{ + /// A helper function that allocates memory for the layout given and gives you access to mutate + /// it. Once your own mutation code is done, the backing `Allocation` is removed from the + /// current `Memory` and returned. + pub fn intern_with_temp_alloc( + &mut self, + layout: TyAndLayout<'tcx>, + f: impl FnOnce( + &mut InterpCx<'mir, 'tcx, M>, + &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ()>, + ) -> InterpResult<'tcx, &'tcx Allocation> { + let dest = self.allocate(layout, MemoryKind::Stack)?; + f(self, &dest.into())?; + let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1; + alloc.mutability = Mutability::Not; + Ok(self.tcx.intern_const_alloc(alloc)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,123 @@ +use std::convert::TryFrom; + +use rustc_ast::Mutability; +use rustc_hir::lang_items::LangItem; +use rustc_middle::mir::TerminatorKind; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::subst::Subst; +use rustc_span::{Span, Symbol}; + +use crate::interpret::{ + intrinsics::{InterpCx, Machine}, + MPlaceTy, MemoryKind, Scalar, +}; + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a + /// frame which is not `#[track_caller]`. + crate fn find_closest_untracked_caller_location(&self) -> Span { + for frame in self.stack().iter().rev() { + debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance); + + // Assert that the frame we look at is actually executing code currently + // (`loc` is `Err` when we are unwinding and the frame does not require cleanup). + let loc = frame.loc.unwrap(); + + // This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all + // (such as `box`). Use the normal span by default. + let mut source_info = *frame.body.source_info(loc); + + // If this is a `Call` terminator, use the `fn_span` instead. + let block = &frame.body.basic_blocks()[loc.block]; + if loc.statement_index == block.statements.len() { + debug!( + "find_closest_untracked_caller_location: got terminator {:?} ({:?})", + block.terminator(), + block.terminator().kind + ); + if let TerminatorKind::Call { fn_span, .. } = block.terminator().kind { + source_info.span = fn_span; + } + } + + // Walk up the `SourceScope`s, in case some of them are from MIR inlining. + // If so, the starting `source_info.span` is in the innermost inlined + // function, and will be replaced with outer callsite spans as long + // as the inlined functions were `#[track_caller]`. + loop { + let scope_data = &frame.body.source_scopes[source_info.scope]; + + if let Some((callee, callsite_span)) = scope_data.inlined { + // Stop inside the most nested non-`#[track_caller]` function, + // before ever reaching its caller (which is irrelevant). + if !callee.def.requires_caller_location(*self.tcx) { + return source_info.span; + } + source_info.span = callsite_span; + } + + // Skip past all of the parents with `inlined: None`. + match scope_data.inlined_parent_scope { + Some(parent) => source_info.scope = parent, + None => break, + } + } + + // Stop inside the most nested non-`#[track_caller]` function, + // before ever reaching its caller (which is irrelevant). + if !frame.instance.def.requires_caller_location(*self.tcx) { + return source_info.span; + } + } + + bug!("no non-`#[track_caller]` frame found") + } + + /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. + crate fn alloc_caller_location( + &mut self, + filename: Symbol, + line: u32, + col: u32, + ) -> MPlaceTy<'tcx, M::PointerTag> { + let file = + self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not); + let line = Scalar::from_u32(line); + let col = Scalar::from_u32(col); + + // Allocate memory for `CallerLocation` struct. + let loc_ty = self + .tcx + .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None)) + .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter())); + let loc_layout = self.layout_of(loc_ty).unwrap(); + // This can fail if rustc runs out of memory right here. Trying to emit an error would be + // pointless, since that would require allocating more memory than a Location. + let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); + + // Initialize fields. + self.write_immediate(file.to_ref(self), &self.mplace_field(&location, 0).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); + self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); + self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); + + location + } + + crate fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { + let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); + let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); + ( + Symbol::intern(&caller.file.name.prefer_remapped().to_string_lossy()), + u32::try_from(caller.line).unwrap(), + u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(), + ) + } + + pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> { + let (file, line, column) = self.location_triple_for_span(span); + self.alloc_caller_location(file, line, column) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,197 @@ +use rustc_hir::def_id::CrateNum; +use rustc_hir::definitions::DisambiguatedDefPathData; +use rustc_middle::mir::interpret::Allocation; +use rustc_middle::ty::{ + self, + print::{PrettyPrinter, Print, Printer}, + subst::{GenericArg, GenericArgKind}, + Ty, TyCtxt, +}; +use std::fmt::Write; + +struct AbsolutePathPrinter<'tcx> { + tcx: TyCtxt<'tcx>, + path: String, +} + +impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { + type Error = std::fmt::Error; + + type Path = Self; + type Region = Self; + type Type = Self; + type DynExistential = Self; + type Const = Self; + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn print_region(self, _region: ty::Region<'_>) -> Result { + Ok(self) + } + + fn print_type(mut self, ty: Ty<'tcx>) -> Result { + match *ty.kind() { + // Types without identity. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnPtr(_) + | ty::Never + | ty::Tuple(_) + | ty::Dynamic(_, _) => self.pretty_print_type(ty), + + // Placeholders (all printed as `_` to uniformize them). + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { + write!(self, "_")?; + Ok(self) + } + + // Types with identity (print the module path). + ty::Adt(&ty::AdtDef { did: def_id, .. }, substs) + | ty::FnDef(def_id, substs) + | ty::Opaque(def_id, substs) + | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) + | ty::Closure(def_id, substs) + | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), + ty::Foreign(def_id) => self.print_def_path(def_id, &[]), + + ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), + } + } + + fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result { + self.pretty_print_const(ct, false) + } + + fn print_dyn_existential( + mut self, + predicates: &'tcx ty::List>>, + ) -> Result { + let mut first = true; + for p in predicates { + if !first { + write!(self, "+")?; + } + first = false; + self = p.print(self)?; + } + Ok(self) + } + + fn path_crate(mut self, cnum: CrateNum) -> Result { + self.path.push_str(&self.tcx.crate_name(cnum).as_str()); + Ok(self) + } + + fn path_qualified( + self, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.pretty_path_qualified(self_ty, trait_ref) + } + + fn path_append_impl( + self, + print_prefix: impl FnOnce(Self) -> Result, + _disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.pretty_path_append_impl( + |mut cx| { + cx = print_prefix(cx)?; + + cx.path.push_str("::"); + + Ok(cx) + }, + self_ty, + trait_ref, + ) + } + + fn path_append( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + self = print_prefix(self)?; + + write!(self.path, "::{}", disambiguated_data.data).unwrap(); + + Ok(self) + } + + fn path_generic_args( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + args: &[GenericArg<'tcx>], + ) -> Result { + self = print_prefix(self)?; + let args = args.iter().cloned().filter(|arg| match arg.unpack() { + GenericArgKind::Lifetime(_) => false, + _ => true, + }); + if args.clone().next().is_some() { + self.generic_delimiters(|cx| cx.comma_sep(args)) + } else { + Ok(self) + } + } +} + +impl PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { + fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool { + false + } + fn comma_sep(mut self, mut elems: impl Iterator) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error>, + { + if let Some(first) = elems.next() { + self = first.print(self)?; + for elem in elems { + self.path.push_str(", "); + self = elem.print(self)?; + } + } + Ok(self) + } + + fn generic_delimiters( + mut self, + f: impl FnOnce(Self) -> Result, + ) -> Result { + write!(self, "<")?; + + self = f(self)?; + + write!(self, ">")?; + + Ok(self) + } +} + +impl Write for AbsolutePathPrinter<'_> { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + self.path.push_str(s); + Ok(()) + } +} + +/// Directly returns an `Allocation` containing an absolute path representation of the given type. +crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation { + let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; + let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); + tcx.intern_const_alloc(alloc) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/intrinsics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,575 @@ +//! Intrinsics and other functions that the miri engine executes without +//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE +//! and miri. + +use std::convert::TryFrom; + +use rustc_hir::def_id::DefId; +use rustc_middle::mir::{ + self, + interpret::{ConstValue, GlobalId, InterpResult, Scalar}, + BinOp, +}; +use rustc_middle::ty; +use rustc_middle::ty::layout::LayoutOf as _; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::{Abi, Align, Primitive, Size}; + +use super::{ + util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy, + Pointer, +}; + +mod caller_location; +mod type_name; + +fn numeric_intrinsic(name: Symbol, bits: u128, kind: Primitive) -> Scalar { + let size = match kind { + Primitive::Int(integer, _) => integer.size(), + _ => bug!("invalid `{}` argument: {:?}", name, bits), + }; + let extra = 128 - u128::from(size.bits()); + let bits_out = match name { + sym::ctpop => u128::from(bits.count_ones()), + sym::ctlz => u128::from(bits.leading_zeros()) - extra, + sym::cttz => u128::from((bits << extra).trailing_zeros()) - extra, + sym::bswap => (bits << extra).swap_bytes(), + sym::bitreverse => (bits << extra).reverse_bits(), + _ => bug!("not a numeric intrinsic: {}", name), + }; + Scalar::from_uint(bits_out, size) +} + +/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated +/// inside an `InterpCx` and instead have their value computed directly from rustc internal info. +crate fn eval_nullary_intrinsic<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, +) -> InterpResult<'tcx, ConstValue<'tcx>> { + let tp_ty = substs.type_at(0); + let name = tcx.item_name(def_id); + Ok(match name { + sym::type_name => { + ensure_monomorphic_enough(tcx, tp_ty)?; + let alloc = type_name::alloc_type_name(tcx, tp_ty); + ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } + } + sym::needs_drop => { + ensure_monomorphic_enough(tcx, tp_ty)?; + ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)) + } + sym::pref_align_of => { + // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. + let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; + ConstValue::from_machine_usize(layout.align.pref.bytes(), &tcx) + } + sym::type_id => { + ensure_monomorphic_enough(tcx, tp_ty)?; + ConstValue::from_u64(tcx.type_id_hash(tp_ty)) + } + sym::variant_count => match tp_ty.kind() { + // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. + ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx), + ty::Projection(_) + | ty::Opaque(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) + | ty::Infer(_) => throw_inval!(TooGeneric), + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Tuple(_) + | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx), + }, + other => bug!("`{}` is not a zero arg intrinsic", other), + }) +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + /// Returns `true` if emulation happened. + /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own + /// intrinsic handling. + pub fn emulate_intrinsic( + &mut self, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx, M::PointerTag>], + ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx, bool> { + let substs = instance.substs; + let intrinsic_name = self.tcx.item_name(instance.def_id()); + + // First handle intrinsics without return place. + let (dest, ret) = match ret { + None => match intrinsic_name { + sym::transmute => throw_ub_format!("transmuting to uninhabited type"), + sym::abort => M::abort(self, "the program aborted execution".to_owned())?, + // Unsupported diverging intrinsic. + _ => return Ok(false), + }, + Some(p) => p, + }; + + // Keep the patterns in this match ordered the same as the list in + // `src/librustc_middle/ty/constness.rs` + match intrinsic_name { + sym::caller_location => { + let span = self.find_closest_untracked_caller_location(); + let location = self.alloc_caller_location_for_span(span); + self.write_immediate(location.to_ref(self), dest)?; + } + + sym::min_align_of_val | sym::size_of_val => { + // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be + // dereferencable! + let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?; + let (size, align) = self + .size_and_align_of_mplace(&place)? + .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?; + + let result = match intrinsic_name { + sym::min_align_of_val => align.bytes(), + sym::size_of_val => size.bytes(), + _ => bug!(), + }; + + self.write_scalar(Scalar::from_machine_usize(result, self), dest)?; + } + + sym::pref_align_of + | sym::needs_drop + | sym::type_id + | sym::type_name + | sym::variant_count => { + let gid = GlobalId { instance, promoted: None }; + let ty = match intrinsic_name { + sym::pref_align_of | sym::variant_count => self.tcx.types.usize, + sym::needs_drop => self.tcx.types.bool, + sym::type_id => self.tcx.types.u64, + sym::type_name => self.tcx.mk_static_str(), + _ => bug!("already checked for nullary intrinsics"), + }; + let val = + self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?; + let val = self.const_val_to_op(val, ty, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + + sym::ctpop + | sym::cttz + | sym::cttz_nonzero + | sym::ctlz + | sym::ctlz_nonzero + | sym::bswap + | sym::bitreverse => { + let ty = substs.type_at(0); + let layout_of = self.layout_of(ty)?; + let val = self.read_scalar(&args[0])?.check_init()?; + let bits = val.to_bits(layout_of.size)?; + let kind = match layout_of.abi { + Abi::Scalar(scalar) => scalar.value, + _ => span_bug!( + self.cur_span(), + "{} called on invalid type {:?}", + intrinsic_name, + ty + ), + }; + let (nonzero, intrinsic_name) = match intrinsic_name { + sym::cttz_nonzero => (true, sym::cttz), + sym::ctlz_nonzero => (true, sym::ctlz), + other => (false, other), + }; + if nonzero && bits == 0 { + throw_ub_format!("`{}_nonzero` called on 0", intrinsic_name); + } + let out_val = numeric_intrinsic(intrinsic_name, bits, kind); + self.write_scalar(out_val, dest)?; + } + sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { + let lhs = self.read_immediate(&args[0])?; + let rhs = self.read_immediate(&args[1])?; + let bin_op = match intrinsic_name { + sym::add_with_overflow => BinOp::Add, + sym::sub_with_overflow => BinOp::Sub, + sym::mul_with_overflow => BinOp::Mul, + _ => bug!("Already checked for int ops"), + }; + self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?; + } + sym::saturating_add | sym::saturating_sub => { + let l = self.read_immediate(&args[0])?; + let r = self.read_immediate(&args[1])?; + let is_add = intrinsic_name == sym::saturating_add; + let (val, overflowed, _ty) = self.overflowing_binary_op( + if is_add { BinOp::Add } else { BinOp::Sub }, + &l, + &r, + )?; + let val = if overflowed { + let size = l.layout.size; + let num_bits = size.bits(); + if l.layout.abi.is_signed() { + // For signed ints the saturated value depends on the sign of the first + // term since the sign of the second term can be inferred from this and + // the fact that the operation has overflowed (if either is 0 no + // overflow can occur) + let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; + let first_term_positive = first_term & (1 << (num_bits - 1)) == 0; + if first_term_positive { + // Negative overflow not possible since the positive first term + // can only increase an (in range) negative term for addition + // or corresponding negated positive term for subtraction + Scalar::from_uint( + (1u128 << (num_bits - 1)) - 1, // max positive + Size::from_bits(num_bits), + ) + } else { + // Positive overflow not possible for similar reason + // max negative + Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits)) + } + } else { + // unsigned + if is_add { + // max unsigned + Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits)) + } else { + // underflow to 0 + Scalar::from_uint(0u128, Size::from_bits(num_bits)) + } + } + } else { + val + }; + self.write_scalar(val, dest)?; + } + sym::discriminant_value => { + let place = self.deref_operand(&args[0])?; + let discr_val = self.read_discriminant(&place.into())?.0; + self.write_scalar(discr_val, dest)?; + } + sym::unchecked_shl + | sym::unchecked_shr + | sym::unchecked_add + | sym::unchecked_sub + | sym::unchecked_mul + | sym::unchecked_div + | sym::unchecked_rem => { + let l = self.read_immediate(&args[0])?; + let r = self.read_immediate(&args[1])?; + let bin_op = match intrinsic_name { + sym::unchecked_shl => BinOp::Shl, + sym::unchecked_shr => BinOp::Shr, + sym::unchecked_add => BinOp::Add, + sym::unchecked_sub => BinOp::Sub, + sym::unchecked_mul => BinOp::Mul, + sym::unchecked_div => BinOp::Div, + sym::unchecked_rem => BinOp::Rem, + _ => bug!("Already checked for int ops"), + }; + let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?; + if overflowed { + let layout = self.layout_of(substs.type_at(0))?; + let r_val = r.to_scalar()?.to_bits(layout.size)?; + if let sym::unchecked_shl | sym::unchecked_shr = intrinsic_name { + throw_ub_format!("overflowing shift by {} in `{}`", r_val, intrinsic_name); + } else { + throw_ub_format!("overflow executing `{}`", intrinsic_name); + } + } + self.write_scalar(val, dest)?; + } + sym::rotate_left | sym::rotate_right => { + // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) + // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) + let layout = self.layout_of(substs.type_at(0))?; + let val = self.read_scalar(&args[0])?.check_init()?; + let val_bits = val.to_bits(layout.size)?; + let raw_shift = self.read_scalar(&args[1])?.check_init()?; + let raw_shift_bits = raw_shift.to_bits(layout.size)?; + let width_bits = u128::from(layout.size.bits()); + let shift_bits = raw_shift_bits % width_bits; + let inv_shift_bits = (width_bits - shift_bits) % width_bits; + let result_bits = if intrinsic_name == sym::rotate_left { + (val_bits << shift_bits) | (val_bits >> inv_shift_bits) + } else { + (val_bits >> shift_bits) | (val_bits << inv_shift_bits) + }; + let truncated_bits = self.truncate(result_bits, layout); + let result = Scalar::from_uint(truncated_bits, layout.size); + self.write_scalar(result, dest)?; + } + sym::copy => { + self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?; + } + sym::offset => { + let ptr = self.read_pointer(&args[0])?; + let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?; + let pointee_ty = substs.type_at(0); + + let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; + self.write_pointer(offset_ptr, dest)?; + } + sym::arith_offset => { + let ptr = self.read_pointer(&args[0])?; + let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?; + let pointee_ty = substs.type_at(0); + + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); + let offset_bytes = offset_count.wrapping_mul(pointee_size); + let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, self); + self.write_pointer(offset_ptr, dest)?; + } + sym::ptr_offset_from => { + let a = self.read_immediate(&args[0])?.to_scalar()?; + let b = self.read_immediate(&args[1])?.to_scalar()?; + + // Special case: if both scalars are *equal integers* + // and not null, we pretend there is an allocation of size 0 right there, + // and their offset is 0. (There's never a valid object at null, making it an + // exception from the exception.) + // This is the dual to the special exception for offset-by-0 + // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`). + // + // Control flow is weird because we cannot early-return (to reach the + // `go_to_block` at the end). + let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) { + let a = a.try_to_machine_usize(*self.tcx).unwrap(); + let b = b.try_to_machine_usize(*self.tcx).unwrap(); + if a == b && a != 0 { + self.write_scalar(Scalar::from_machine_isize(0, self), dest)?; + true + } else { + false + } + } else { + false + }; + + if !done { + // General case: we need two pointers. + let a = self.scalar_to_ptr(a); + let b = self.scalar_to_ptr(b); + let (a_alloc_id, a_offset, _) = self.memory.ptr_get_alloc(a)?; + let (b_alloc_id, b_offset, _) = self.memory.ptr_get_alloc(b)?; + if a_alloc_id != b_alloc_id { + throw_ub_format!( + "ptr_offset_from cannot compute offset of pointers into different \ + allocations.", + ); + } + let usize_layout = self.layout_of(self.tcx.types.usize)?; + let isize_layout = self.layout_of(self.tcx.types.isize)?; + let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout); + let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout); + let (val, _overflowed, _ty) = + self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?; + let pointee_layout = self.layout_of(substs.type_at(0))?; + let val = ImmTy::from_scalar(val, isize_layout); + let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout); + self.exact_div(&val, &size, dest)?; + } + } + + sym::transmute => { + self.copy_op_transmute(&args[0], dest)?; + } + sym::assert_inhabited => { + let ty = instance.substs.type_at(0); + let layout = self.layout_of(ty)?; + + if layout.abi.is_uninhabited() { + // The run-time intrinsic panics just to get a good backtrace; here we abort + // since there is no problem showing a backtrace even for aborts. + M::abort( + self, + format!( + "aborted execution: attempted to instantiate uninhabited type `{}`", + ty + ), + )?; + } + } + sym::simd_insert => { + let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); + let elem = &args[2]; + let input = &args[0]; + let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx); + assert!( + index < len, + "Index `{}` must be in bounds of vector type `{}`: `[0, {})`", + index, + e_ty, + len + ); + assert_eq!( + input.layout, dest.layout, + "Return type `{}` must match vector type `{}`", + dest.layout.ty, input.layout.ty + ); + assert_eq!( + elem.layout.ty, e_ty, + "Scalar element type `{}` must match vector element type `{}`", + elem.layout.ty, e_ty + ); + + for i in 0..len { + let place = self.place_index(dest, i)?; + let value = if i == index { *elem } else { self.operand_index(input, i)? }; + self.copy_op(&value, &place)?; + } + } + sym::simd_extract => { + let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); + let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx); + assert!( + index < len, + "index `{}` is out-of-bounds of vector type `{}` with length `{}`", + index, + e_ty, + len + ); + assert_eq!( + e_ty, dest.layout.ty, + "Return type `{}` must match vector element type `{}`", + dest.layout.ty, e_ty + ); + self.copy_op(&self.operand_index(&args[0], index)?, dest)?; + } + sym::likely | sym::unlikely | sym::black_box => { + // These just return their argument + self.copy_op(&args[0], dest)?; + } + sym::assume => { + let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?; + if !cond { + throw_ub_format!("`assume` intrinsic called with `false`"); + } + } + sym::raw_eq => { + let result = self.raw_eq_intrinsic(&args[0], &args[1])?; + self.write_scalar(result, dest)?; + } + _ => return Ok(false), + } + + trace!("{:?}", self.dump_place(**dest)); + self.go_to_block(ret); + Ok(true) + } + + pub fn exact_div( + &mut self, + a: &ImmTy<'tcx, M::PointerTag>, + b: &ImmTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + // Performs an exact division, resulting in undefined behavior where + // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. + // First, check x % y != 0 (or if that computation overflows). + let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?; + if overflow || res.assert_bits(a.layout.size) != 0 { + // Then, check if `b` is -1, which is the "MIN / -1" case. + let minus1 = Scalar::from_int(-1, dest.layout.size); + let b_scalar = b.to_scalar().unwrap(); + if b_scalar == minus1 { + throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") + } else { + throw_ub_format!("exact_div: {} cannot be divided by {} without remainder", a, b,) + } + } + // `Rem` says this is all right, so we can let `Div` do its job. + self.binop_ignore_overflow(BinOp::Div, &a, &b, dest) + } + + /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its + /// allocation. For integer pointers, we consider each of them their own tiny allocation of size + /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value. + pub fn ptr_offset_inbounds( + &self, + ptr: Pointer>, + pointee_ty: Ty<'tcx>, + offset_count: i64, + ) -> InterpResult<'tcx, Pointer>> { + // We cannot overflow i64 as a type's size must be <= isize::MAX. + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); + // The computed offset, in bytes, cannot overflow an isize. + let offset_bytes = + offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?; + // The offset being in bounds cannot rely on "wrapping around" the address space. + // So, first rule out overflows in the pointer arithmetic. + let offset_ptr = ptr.signed_offset(offset_bytes, self)?; + // ptr and offset_ptr must be in bounds of the same allocated object. This means all of the + // memory between these pointers must be accessible. Note that we do not require the + // pointers to be properly aligned (unlike a read/write operation). + let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; + let size = offset_bytes.unsigned_abs(); + // This call handles checking for integer/null pointers. + self.memory.check_ptr_access_align( + min_ptr, + Size::from_bytes(size), + Align::ONE, + CheckInAllocMsg::PointerArithmeticTest, + )?; + Ok(offset_ptr) + } + + /// Copy `count*size_of::()` many bytes from `*src` to `*dst`. + pub(crate) fn copy_intrinsic( + &mut self, + src: &OpTy<'tcx, >::PointerTag>, + dst: &OpTy<'tcx, >::PointerTag>, + count: &OpTy<'tcx, >::PointerTag>, + nonoverlapping: bool, + ) -> InterpResult<'tcx> { + let count = self.read_scalar(&count)?.to_machine_usize(self)?; + let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?; + let (size, align) = (layout.size, layout.align.abi); + let size = size.checked_mul(count, self).ok_or_else(|| { + err_ub_format!( + "overflow computing total size of `{}`", + if nonoverlapping { "copy_nonoverlapping" } else { "copy" } + ) + })?; + + let src = self.read_pointer(&src)?; + let dst = self.read_pointer(&dst)?; + + self.memory.copy(src, align, dst, align, size, nonoverlapping) + } + + pub(crate) fn raw_eq_intrinsic( + &mut self, + lhs: &OpTy<'tcx, >::PointerTag>, + rhs: &OpTy<'tcx, >::PointerTag>, + ) -> InterpResult<'tcx, Scalar> { + let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; + assert!(!layout.is_unsized()); + + let lhs = self.read_pointer(lhs)?; + let rhs = self.read_pointer(rhs)?; + let lhs_bytes = self.memory.read_bytes(lhs, layout.size)?; + let rhs_bytes = self.memory.read_bytes(rhs, layout.size)?; + Ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/machine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/machine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/machine.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/machine.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,479 @@ +//! This module contains everything needed to instantiate an interpreter. +//! This separation exists to ensure that no fancy miri features like +//! interpreting common C functions leak into CTFE. + +use std::borrow::{Borrow, Cow}; +use std::fmt::Debug; +use std::hash::Hash; + +use rustc_middle::mir; +use rustc_middle::ty::{self, Ty}; +use rustc_span::def_id::DefId; +use rustc_target::abi::Size; +use rustc_target::spec::abi::Abi; + +use super::{ + AllocId, AllocRange, Allocation, Frame, ImmTy, InterpCx, InterpResult, LocalValue, MemPlace, + Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, +}; + +/// Data returned by Machine::stack_pop, +/// to provide further control over the popping of the stack frame +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum StackPopJump { + /// Indicates that no special handling should be + /// done - we'll either return normally or unwind + /// based on the terminator for the function + /// we're leaving. + Normal, + + /// Indicates that we should *not* jump to the return/unwind address, as the callback already + /// took care of everything. + NoJump, +} + +/// Whether this kind of memory is allowed to leak +pub trait MayLeak: Copy { + fn may_leak(self) -> bool; +} + +/// The functionality needed by memory to manage its allocations +pub trait AllocMap { + /// Tests if the map contains the given key. + /// Deliberately takes `&mut` because that is sufficient, and some implementations + /// can be more efficient then (using `RefCell::get_mut`). + fn contains_key(&mut self, k: &Q) -> bool + where + K: Borrow; + + /// Inserts a new entry into the map. + fn insert(&mut self, k: K, v: V) -> Option; + + /// Removes an entry from the map. + fn remove(&mut self, k: &Q) -> Option + where + K: Borrow; + + /// Returns data based on the keys and values in the map. + fn filter_map_collect(&self, f: impl FnMut(&K, &V) -> Option) -> Vec; + + /// Returns a reference to entry `k`. If no such entry exists, call + /// `vacant` and either forward its error, or add its result to the map + /// and return a reference to *that*. + fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E>; + + /// Returns a mutable reference to entry `k`. If no such entry exists, call + /// `vacant` and either forward its error, or add its result to the map + /// and return a reference to *that*. + fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E>; + + /// Read-only lookup. + fn get(&self, k: K) -> Option<&V> { + self.get_or(k, || Err(())).ok() + } + + /// Mutable lookup. + fn get_mut(&mut self, k: K) -> Option<&mut V> { + self.get_mut_or(k, || Err(())).ok() + } +} + +/// Methods of this trait signifies a point where CTFE evaluation would fail +/// and some use case dependent behaviour can instead be applied. +pub trait Machine<'mir, 'tcx>: Sized { + /// Additional memory kinds a machine wishes to distinguish from the builtin ones + type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static; + + /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. + type PointerTag: Provenance + Eq + Hash + 'static; + + /// Machines can define extra (non-instance) things that represent values of function pointers. + /// For example, Miri uses this to return a function pointer from `dlsym` + /// that can later be called to execute the right thing. + type ExtraFnVal: Debug + Copy; + + /// Extra data stored in every call frame. + type FrameExtra; + + /// Extra data stored in memory. A reference to this is available when `AllocExtra` + /// gets initialized, so you can e.g., have an `Rc` here if there is global state you + /// need access to in the `AllocExtra` hooks. + type MemoryExtra; + + /// Extra data stored in every allocation. + type AllocExtra: Debug + Clone + 'static; + + /// Memory's allocation map + type MemoryMap: AllocMap< + AllocId, + (MemoryKind, Allocation), + > + Default + + Clone; + + /// The memory kind to use for copied global memory (held in `tcx`) -- + /// or None if such memory should not be mutated and thus any such attempt will cause + /// a `ModifiedStatic` error to be raised. + /// Statics are copied under two circumstances: When they are mutated, and when + /// `tag_allocation` (see below) returns an owned allocation + /// that is added to the memory so that the work is not done twice. + const GLOBAL_KIND: Option; + + /// Should the machine panic on allocation failures? + const PANIC_ON_ALLOC_FAIL: bool; + + /// Whether memory accesses should be alignment-checked. + fn enforce_alignment(memory_extra: &Self::MemoryExtra) -> bool; + + /// Whether, when checking alignment, we should `force_int` and thus support + /// custom alignment logic based on whatever the integer address happens to be. + fn force_int_for_alignment_check(memory_extra: &Self::MemoryExtra) -> bool; + + /// Whether to enforce the validity invariant + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + + /// Whether function calls should be [ABI](Abi)-checked. + fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + true + } + + /// Entry point for obtaining the MIR of anything that should get evaluated. + /// So not just functions and shims, but also const/static initializers, anonymous + /// constants, ... + fn load_mir( + ecx: &InterpCx<'mir, 'tcx, Self>, + instance: ty::InstanceDef<'tcx>, + ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { + Ok(ecx.tcx.instance_mir(instance)) + } + + /// Entry point to all function calls. + /// + /// Returns either the mir to use for the call, or `None` if execution should + /// just proceed (which usually means this hook did all the work that the + /// called function should usually have done). In the latter case, it is + /// this hook's responsibility to advance the instruction pointer! + /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR + /// nor just jump to `ret`, but instead push their own stack frame.) + /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them + /// was used. + fn find_mir_or_eval_fn( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + instance: ty::Instance<'tcx>, + abi: Abi, + args: &[OpTy<'tcx, Self::PointerTag>], + ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, + unwind: StackPopUnwind, + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>; + + /// Execute `fn_val`. It is the hook's responsibility to advance the instruction + /// pointer as appropriate. + fn call_extra_fn( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + fn_val: Self::ExtraFnVal, + abi: Abi, + args: &[OpTy<'tcx, Self::PointerTag>], + ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, + unwind: StackPopUnwind, + ) -> InterpResult<'tcx>; + + /// Directly process an intrinsic without pushing a stack frame. It is the hook's + /// responsibility to advance the instruction pointer as appropriate. + fn call_intrinsic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx, Self::PointerTag>], + ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, + unwind: StackPopUnwind, + ) -> InterpResult<'tcx>; + + /// Called to evaluate `Assert` MIR terminators that trigger a panic. + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + msg: &mir::AssertMessage<'tcx>, + unwind: Option, + ) -> InterpResult<'tcx>; + + /// Called to evaluate `Abort` MIR terminator. + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> { + throw_unsup_format!("aborting execution is not supported") + } + + /// Called for all binary operations where the LHS has pointer type. + /// + /// Returns a (value, overflowed) pair if the operation succeeded + fn binary_ptr_op( + ecx: &InterpCx<'mir, 'tcx, Self>, + bin_op: mir::BinOp, + left: &ImmTy<'tcx, Self::PointerTag>, + right: &ImmTy<'tcx, Self::PointerTag>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; + + /// Heap allocations via the `box` keyword. + fn box_alloc( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + dest: &PlaceTy<'tcx, Self::PointerTag>, + ) -> InterpResult<'tcx>; + + /// Called to read the specified `local` from the `frame`. + /// Since reading a ZST is not actually accessing memory or locals, this is never invoked + /// for ZST reads. + #[inline] + fn access_local( + _ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: mir::Local, + ) -> InterpResult<'tcx, Operand> { + frame.locals[local].access() + } + + /// Called to write the specified `local` from the `frame`. + /// Since writing a ZST is not actually accessing memory or locals, this is never invoked + /// for ZST reads. + #[inline] + fn access_local_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + frame: usize, + local: mir::Local, + ) -> InterpResult<'tcx, Result<&'a mut LocalValue, MemPlace>> + where + 'tcx: 'mir, + { + ecx.stack_mut()[frame].locals[local].access_mut() + } + + /// Called before a basic block terminator is executed. + /// You can use this to detect endlessly running programs. + #[inline] + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + Ok(()) + } + + /// Called before a global allocation is accessed. + /// `def_id` is `Some` if this is the "lazy" allocation of a static. + #[inline] + fn before_access_global( + _memory_extra: &Self::MemoryExtra, + _alloc_id: AllocId, + _allocation: &Allocation, + _static_def_id: Option, + _is_write: bool, + ) -> InterpResult<'tcx> { + Ok(()) + } + + /// Return the `AllocId` for the given thread-local static in the current thread. + fn thread_local_static_base_pointer( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + def_id: DefId, + ) -> InterpResult<'tcx, Pointer> { + throw_unsup!(ThreadLocalStatic(def_id)) + } + + /// Return the root pointer for the given `extern static`. + fn extern_static_base_pointer( + mem: &Memory<'mir, 'tcx, Self>, + def_id: DefId, + ) -> InterpResult<'tcx, Pointer>; + + /// Return a "base" pointer for the given allocation: the one that is used for direct + /// accesses to this static/const/fn allocation, or the one returned from the heap allocator. + /// + /// Not called on `extern` or thread-local statics (those use the methods above). + fn tag_alloc_base_pointer( + mem: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, + ) -> Pointer; + + /// "Int-to-pointer cast" + fn ptr_from_addr( + mem: &Memory<'mir, 'tcx, Self>, + addr: u64, + ) -> Pointer>; + + /// Convert a pointer with provenance into an allocation-offset pair. + fn ptr_get_alloc( + mem: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, + ) -> (AllocId, Size); + + /// Called to initialize the "extra" state of an allocation and make the pointers + /// it contains (in relocations) tagged. The way we construct allocations is + /// to always first construct it without extra and then add the extra. + /// This keeps uniform code paths for handling both allocations created by CTFE + /// for globals, and allocations created by Miri during evaluation. + /// + /// `kind` is the kind of the allocation being tagged; it can be `None` when + /// it's a global and `GLOBAL_KIND` is `None`. + /// + /// This should avoid copying if no work has to be done! If this returns an owned + /// allocation (because a copy had to be done to add tags or metadata), machine memory will + /// cache the result. (This relies on `AllocMap::get_or` being able to add the + /// owned allocation to the map even when the map is shared.) + fn init_allocation_extra<'b>( + mem: &Memory<'mir, 'tcx, Self>, + id: AllocId, + alloc: Cow<'b, Allocation>, + kind: Option>, + ) -> Cow<'b, Allocation>; + + /// Hook for performing extra checks on a memory read access. + /// + /// Takes read-only access to the allocation so we can keep all the memory read + /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you + /// need to mutate. + #[inline(always)] + fn memory_read( + _memory_extra: &Self::MemoryExtra, + _alloc_extra: &Self::AllocExtra, + _tag: Self::PointerTag, + _range: AllocRange, + ) -> InterpResult<'tcx> { + Ok(()) + } + + /// Hook for performing extra checks on a memory write access. + #[inline(always)] + fn memory_written( + _memory_extra: &mut Self::MemoryExtra, + _alloc_extra: &mut Self::AllocExtra, + _tag: Self::PointerTag, + _range: AllocRange, + ) -> InterpResult<'tcx> { + Ok(()) + } + + /// Hook for performing extra operations on a memory deallocation. + #[inline(always)] + fn memory_deallocated( + _memory_extra: &mut Self::MemoryExtra, + _alloc_extra: &mut Self::AllocExtra, + _tag: Self::PointerTag, + _range: AllocRange, + ) -> InterpResult<'tcx> { + Ok(()) + } + + /// Executes a retagging operation. + #[inline] + fn retag( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _kind: mir::RetagKind, + _place: &PlaceTy<'tcx, Self::PointerTag>, + ) -> InterpResult<'tcx> { + Ok(()) + } + + /// Called immediately before a new stack frame gets pushed. + fn init_frame_extra( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + frame: Frame<'mir, 'tcx, Self::PointerTag>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>; + + /// Borrow the current thread's stack. + fn stack( + ecx: &'a InterpCx<'mir, 'tcx, Self>, + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>]; + + /// Mutably borrow the current thread's stack. + fn stack_mut( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + ) -> &'a mut Vec>; + + /// Called immediately after a stack frame got pushed and its locals got initialized. + fn after_stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + Ok(()) + } + + /// Called immediately after a stack frame got popped, but before jumping back to the caller. + fn after_stack_pop( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _frame: Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + _unwinding: bool, + ) -> InterpResult<'tcx, StackPopJump> { + // By default, we do not support unwinding from panics + Ok(StackPopJump::Normal) + } +} + +// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines +// (CTFE and ConstProp) use the same instance. Here, we share that code. +pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { + type PointerTag = AllocId; + type ExtraFnVal = !; + + type MemoryMap = + rustc_data_structures::fx::FxHashMap, Allocation)>; + const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory + + type AllocExtra = (); + type FrameExtra = (); + + #[inline(always)] + fn enforce_alignment(_memory_extra: &Self::MemoryExtra) -> bool { + // We do not check for alignment to avoid having to carry an `Align` + // in `ConstValue::ByRef`. + false + } + + #[inline(always)] + fn force_int_for_alignment_check(_memory_extra: &Self::MemoryExtra) -> bool { + // We do not support `force_int`. + false + } + + #[inline(always)] + fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + false // for now, we don't enforce validity + } + + #[inline(always)] + fn call_extra_fn( + _ecx: &mut InterpCx<$mir, $tcx, Self>, + fn_val: !, + _abi: Abi, + _args: &[OpTy<$tcx>], + _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>, + _unwind: StackPopUnwind, + ) -> InterpResult<$tcx> { + match fn_val {} + } + + #[inline(always)] + fn init_allocation_extra<'b>( + _mem: &Memory<$mir, $tcx, Self>, + _id: AllocId, + alloc: Cow<'b, Allocation>, + _kind: Option>, + ) -> Cow<'b, Allocation> { + // We do not use a tag so we can just cheaply forward the allocation + alloc + } + + fn extern_static_base_pointer( + mem: &Memory<$mir, $tcx, Self>, + def_id: DefId, + ) -> InterpResult<$tcx, Pointer> { + // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail. + Ok(Pointer::new(mem.tcx.create_static_alloc(def_id), Size::ZERO)) + } + + #[inline(always)] + fn tag_alloc_base_pointer( + _mem: &Memory<$mir, $tcx, Self>, + ptr: Pointer, + ) -> Pointer { + ptr + } + + #[inline(always)] + fn ptr_from_addr(_mem: &Memory<$mir, $tcx, Self>, addr: u64) -> Pointer> { + Pointer::new(None, Size::from_bytes(addr)) + } + + #[inline(always)] + fn ptr_get_alloc(_mem: &Memory<$mir, $tcx, Self>, ptr: Pointer) -> (AllocId, Size) { + // We know `offset` is relative to the allocation, so we can use `into_parts`. + let (alloc_id, offset) = ptr.into_parts(); + (alloc_id, offset) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/memory.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/memory.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/memory.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/memory.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1186 @@ +//! The memory subsystem. +//! +//! Generally, we use `Pointer` to denote memory addresses. However, some operations +//! have a "size"-like parameter, and they take `Scalar` for the address because +//! if the size is 0, then the pointer can also be a (properly aligned, non-null) +//! integer. It is crucial that these operations call `check_align` *before* +//! short-circuiting the empty case! + +use std::assert_matches::assert_matches; +use std::borrow::Cow; +use std::collections::VecDeque; +use std::convert::TryFrom; +use std::fmt; +use std::ptr; + +use rustc_ast::Mutability; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::mir::display_allocation; +use rustc_middle::ty::{Instance, ParamEnv, TyCtxt}; +use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; + +use super::{ + alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, + InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar, + ScalarMaybeUninit, +}; + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum MemoryKind { + /// Stack memory. Error if deallocated except during a stack pop. + Stack, + /// Memory allocated by `caller_location` intrinsic. Error if ever deallocated. + CallerLocation, + /// Additional memory kinds a machine wishes to distinguish from the builtin ones. + Machine(T), +} + +impl MayLeak for MemoryKind { + #[inline] + fn may_leak(self) -> bool { + match self { + MemoryKind::Stack => false, + MemoryKind::CallerLocation => true, + MemoryKind::Machine(k) => k.may_leak(), + } + } +} + +impl fmt::Display for MemoryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MemoryKind::Stack => write!(f, "stack variable"), + MemoryKind::CallerLocation => write!(f, "caller location"), + MemoryKind::Machine(m) => write!(f, "{}", m), + } + } +} + +/// Used by `get_size_and_align` to indicate whether the allocation needs to be live. +#[derive(Debug, Copy, Clone)] +pub enum AllocCheck { + /// Allocation must be live and not a function pointer. + Dereferenceable, + /// Allocations needs to be live, but may be a function pointer. + Live, + /// Allocation may be dead. + MaybeDead, +} + +/// The value of a function pointer. +#[derive(Debug, Copy, Clone)] +pub enum FnVal<'tcx, Other> { + Instance(Instance<'tcx>), + Other(Other), +} + +impl<'tcx, Other> FnVal<'tcx, Other> { + pub fn as_instance(self) -> InterpResult<'tcx, Instance<'tcx>> { + match self { + FnVal::Instance(instance) => Ok(instance), + FnVal::Other(_) => { + throw_unsup_format!("'foreign' function pointers are not supported in this context") + } + } + } +} + +// `Memory` has to depend on the `Machine` because some of its operations +// (e.g., `get`) call a `Machine` hook. +pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { + /// Allocations local to this instance of the miri engine. The kind + /// helps ensure that the same mechanism is used for allocation and + /// deallocation. When an allocation is not found here, it is a + /// global and looked up in the `tcx` for read access. Some machines may + /// have to mutate this map even on a read-only access to a global (because + /// they do pointer provenance tracking and the allocations in `tcx` have + /// the wrong type), so we let the machine override this type. + /// Either way, if the machine allows writing to a global, doing so will + /// create a copy of the global allocation here. + // FIXME: this should not be public, but interning currently needs access to it + pub(super) alloc_map: M::MemoryMap, + + /// Map for "extra" function pointers. + extra_fn_ptr_map: FxHashMap, + + /// To be able to compare pointers with null, and to check alignment for accesses + /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations + /// that do not exist any more. + // FIXME: this should not be public, but interning currently needs access to it + pub(super) dead_alloc_map: FxHashMap, + + /// Extra data added by the machine. + pub extra: M::MemoryExtra, + + /// Lets us implement `HasDataLayout`, which is awfully convenient. + pub tcx: TyCtxt<'tcx>, +} + +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> { + #[inline] + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +/// A reference to some allocation that was already bounds-checked for the given region +/// and had the on-access machine hooks run. +#[derive(Copy, Clone)] +pub struct AllocRef<'a, 'tcx, Tag, Extra> { + alloc: &'a Allocation, + range: AllocRange, + tcx: TyCtxt<'tcx>, + alloc_id: AllocId, +} +/// A reference to some allocation that was already bounds-checked for the given region +/// and had the on-access machine hooks run. +pub struct AllocRefMut<'a, 'tcx, Tag, Extra> { + alloc: &'a mut Allocation, + range: AllocRange, + tcx: TyCtxt<'tcx>, + alloc_id: AllocId, +} + +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { + pub fn new(tcx: TyCtxt<'tcx>, extra: M::MemoryExtra) -> Self { + Memory { + alloc_map: M::MemoryMap::default(), + extra_fn_ptr_map: FxHashMap::default(), + dead_alloc_map: FxHashMap::default(), + extra, + tcx, + } + } + + /// Call this to turn untagged "global" pointers (obtained via `tcx`) into + /// the machine pointer to the allocation. Must never be used + /// for any other pointers, nor for TLS statics. + /// + /// Using the resulting pointer represents a *direct* access to that memory + /// (e.g. by directly using a `static`), + /// as opposed to access through a pointer that was created by the program. + /// + /// This function can fail only if `ptr` points to an `extern static`. + #[inline] + pub fn global_base_pointer( + &self, + ptr: Pointer, + ) -> InterpResult<'tcx, Pointer> { + // We know `offset` is relative to the allocation, so we can use `into_parts`. + let (alloc_id, offset) = ptr.into_parts(); + // We need to handle `extern static`. + match self.tcx.get_global_alloc(alloc_id) { + Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => { + bug!("global memory cannot point to thread-local static") + } + Some(GlobalAlloc::Static(def_id)) if self.tcx.is_foreign_item(def_id) => { + return M::extern_static_base_pointer(self, def_id); + } + _ => {} + } + // And we need to get the tag. + Ok(M::tag_alloc_base_pointer(self, Pointer::new(alloc_id, offset))) + } + + pub fn create_fn_alloc( + &mut self, + fn_val: FnVal<'tcx, M::ExtraFnVal>, + ) -> Pointer { + let id = match fn_val { + FnVal::Instance(instance) => self.tcx.create_fn_alloc(instance), + FnVal::Other(extra) => { + // FIXME(RalfJung): Should we have a cache here? + let id = self.tcx.reserve_alloc_id(); + let old = self.extra_fn_ptr_map.insert(id, extra); + assert!(old.is_none()); + id + } + }; + // Functions are global allocations, so make sure we get the right base pointer. + // We know this is not an `extern static` so this cannot fail. + self.global_base_pointer(Pointer::from(id)).unwrap() + } + + pub fn allocate( + &mut self, + size: Size, + align: Align, + kind: MemoryKind, + ) -> InterpResult<'static, Pointer> { + let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?; + Ok(self.allocate_with(alloc, kind)) + } + + pub fn allocate_bytes( + &mut self, + bytes: &[u8], + align: Align, + kind: MemoryKind, + mutability: Mutability, + ) -> Pointer { + let alloc = Allocation::from_bytes(bytes, align, mutability); + self.allocate_with(alloc, kind) + } + + pub fn allocate_with( + &mut self, + alloc: Allocation, + kind: MemoryKind, + ) -> Pointer { + let id = self.tcx.reserve_alloc_id(); + debug_assert_ne!( + Some(kind), + M::GLOBAL_KIND.map(MemoryKind::Machine), + "dynamically allocating global memory" + ); + let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind)); + self.alloc_map.insert(id, (kind, alloc.into_owned())); + M::tag_alloc_base_pointer(self, Pointer::from(id)) + } + + pub fn reallocate( + &mut self, + ptr: Pointer>, + old_size_and_align: Option<(Size, Align)>, + new_size: Size, + new_align: Align, + kind: MemoryKind, + ) -> InterpResult<'tcx, Pointer> { + let (alloc_id, offset, ptr) = self.ptr_get_alloc(ptr)?; + if offset.bytes() != 0 { + throw_ub_format!( + "reallocating {:?} which does not point to the beginning of an object", + ptr + ); + } + + // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc". + // This happens so rarely, the perf advantage is outweighed by the maintenance cost. + let new_ptr = self.allocate(new_size, new_align, kind)?; + let old_size = match old_size_and_align { + Some((size, _align)) => size, + None => self.get_raw(alloc_id)?.size(), + }; + // This will also call the access hooks. + self.copy( + ptr.into(), + Align::ONE, + new_ptr.into(), + Align::ONE, + old_size.min(new_size), + /*nonoverlapping*/ true, + )?; + self.deallocate(ptr.into(), old_size_and_align, kind)?; + + Ok(new_ptr) + } + + pub fn deallocate( + &mut self, + ptr: Pointer>, + old_size_and_align: Option<(Size, Align)>, + kind: MemoryKind, + ) -> InterpResult<'tcx> { + let (alloc_id, offset, ptr) = self.ptr_get_alloc(ptr)?; + trace!("deallocating: {}", alloc_id); + + if offset.bytes() != 0 { + throw_ub_format!( + "deallocating {:?} which does not point to the beginning of an object", + ptr + ); + } + + let (alloc_kind, mut alloc) = match self.alloc_map.remove(&alloc_id) { + Some(alloc) => alloc, + None => { + // Deallocating global memory -- always an error + return Err(match self.tcx.get_global_alloc(alloc_id) { + Some(GlobalAlloc::Function(..)) => { + err_ub_format!("deallocating {}, which is a function", alloc_id) + } + Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { + err_ub_format!("deallocating {}, which is static memory", alloc_id) + } + None => err_ub!(PointerUseAfterFree(alloc_id)), + } + .into()); + } + }; + + if alloc.mutability == Mutability::Not { + throw_ub_format!("deallocating immutable allocation {}", alloc_id); + } + if alloc_kind != kind { + throw_ub_format!( + "deallocating {}, which is {} memory, using {} deallocation operation", + alloc_id, + alloc_kind, + kind + ); + } + if let Some((size, align)) = old_size_and_align { + if size != alloc.size() || align != alloc.align { + throw_ub_format!( + "incorrect layout on deallocation: {} has size {} and alignment {}, but gave size {} and alignment {}", + alloc_id, + alloc.size().bytes(), + alloc.align.bytes(), + size.bytes(), + align.bytes(), + ) + } + } + + // Let the machine take some extra action + let size = alloc.size(); + M::memory_deallocated( + &mut self.extra, + &mut alloc.extra, + ptr.provenance, + alloc_range(Size::ZERO, size), + )?; + + // Don't forget to remember size and align of this now-dead allocation + let old = self.dead_alloc_map.insert(alloc_id, (size, alloc.align)); + if old.is_some() { + bug!("Nothing can be deallocated twice"); + } + + Ok(()) + } + + /// Internal helper function to determine the allocation and offset of a pointer (if any). + #[inline(always)] + fn get_ptr_access( + &self, + ptr: Pointer>, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Option<(AllocId, Size, Pointer)>> { + let align = M::enforce_alignment(&self.extra).then_some(align); + self.check_and_deref_ptr( + ptr, + size, + align, + CheckInAllocMsg::MemoryAccessTest, + |alloc_id, offset, ptr| { + let (size, align) = + self.get_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; + Ok((size, align, (alloc_id, offset, ptr))) + }, + ) + } + + /// Check if the given pointer points to live memory of given `size` and `align` + /// (ignoring `M::enforce_alignment`). The caller can control the error message for the + /// out-of-bounds case. + #[inline(always)] + pub fn check_ptr_access_align( + &self, + ptr: Pointer>, + size: Size, + align: Align, + msg: CheckInAllocMsg, + ) -> InterpResult<'tcx> { + self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| { + let check = match msg { + CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => { + AllocCheck::Dereferenceable + } + CheckInAllocMsg::PointerArithmeticTest | CheckInAllocMsg::InboundsTest => { + AllocCheck::Live + } + }; + let (size, align) = self.get_size_and_align(alloc_id, check)?; + Ok((size, align, ())) + })?; + Ok(()) + } + + /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference + /// to the allocation it points to. Supports both shared and mutable references, as the actual + /// checking is offloaded to a helper closure. `align` defines whether and which alignment check + /// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned. + fn check_and_deref_ptr( + &self, + ptr: Pointer>, + size: Size, + align: Option, + msg: CheckInAllocMsg, + alloc_size: impl FnOnce( + AllocId, + Size, + Pointer, + ) -> InterpResult<'tcx, (Size, Align, T)>, + ) -> InterpResult<'tcx, Option> { + fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> { + if offset % align.bytes() == 0 { + Ok(()) + } else { + // The biggest power of two through which `offset` is divisible. + let offset_pow2 = 1 << offset.trailing_zeros(); + throw_ub!(AlignmentCheckFailed { + has: Align::from_bytes(offset_pow2).unwrap(), + required: align, + }) + } + } + + // Extract from the pointer an `Option` and an offset, which is relative to the + // allocation or (if that is `None`) an absolute address. + let ptr_or_addr = if size.bytes() == 0 { + // Let's see what we can do, but don't throw errors if there's nothing there. + self.ptr_try_get_alloc(ptr) + } else { + // A "real" access, we insist on getting an `AllocId`. + Ok(self.ptr_get_alloc(ptr)?) + }; + Ok(match ptr_or_addr { + Err(addr) => { + // No memory is actually being accessed. + debug_assert!(size.bytes() == 0); + // Must be non-null. + if addr == 0 { + throw_ub!(DanglingIntPointer(0, msg)) + } + // Must be aligned. + if let Some(align) = align { + check_offset_align(addr, align)?; + } + None + } + Ok((alloc_id, offset, ptr)) => { + let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, ptr)?; + // Test bounds. This also ensures non-null. + // It is sufficient to check this for the end pointer. Also check for overflow! + if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { + throw_ub!(PointerOutOfBounds { + alloc_id, + alloc_size, + ptr_offset: self.machine_usize_to_isize(offset.bytes()), + ptr_size: size, + msg, + }) + } + // Test align. Check this last; if both bounds and alignment are violated + // we want the error to be about the bounds. + if let Some(align) = align { + if M::force_int_for_alignment_check(&self.extra) { + let addr = Scalar::from_pointer(ptr, &self.tcx) + .to_machine_usize(&self.tcx) + .expect("ptr-to-int cast for align check should never fail"); + check_offset_align(addr, align)?; + } else { + // Check allocation alignment and offset alignment. + if alloc_align.bytes() < align.bytes() { + throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align }); + } + check_offset_align(offset.bytes(), align)?; + } + } + + // We can still be zero-sized in this branch, in which case we have to + // return `None`. + if size.bytes() == 0 { None } else { Some(ret_val) } + } + }) + } + + /// Test if the pointer might be null. + pub fn ptr_may_be_null(&self, ptr: Pointer>) -> bool { + match self.ptr_try_get_alloc(ptr) { + Ok((alloc_id, offset, _)) => { + let (size, _align) = self + .get_size_and_align(alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail"); + // If the pointer is out-of-bounds, it may be null. + // Note that one-past-the-end (offset == size) is still inbounds, and never null. + offset > size + } + Err(offset) => offset == 0, + } + } +} + +/// Allocation accessors +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { + /// Helper function to obtain a global (tcx) allocation. + /// This attempts to return a reference to an existing allocation if + /// one can be found in `tcx`. That, however, is only possible if `tcx` and + /// this machine use the same pointer tag, so it is indirected through + /// `M::tag_allocation`. + fn get_global_alloc( + &self, + id: AllocId, + is_write: bool, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + let (alloc, def_id) = match self.tcx.get_global_alloc(id) { + Some(GlobalAlloc::Memory(mem)) => { + // Memory of a constant or promoted or anonymous memory referenced by a static. + (mem, None) + } + Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), + None => throw_ub!(PointerUseAfterFree(id)), + Some(GlobalAlloc::Static(def_id)) => { + assert!(self.tcx.is_static(def_id)); + assert!(!self.tcx.is_thread_local_static(def_id)); + // Notice that every static has two `AllocId` that will resolve to the same + // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID, + // and the other one is maps to `GlobalAlloc::Memory`, this is returned by + // `eval_static_initializer` and it is the "resolved" ID. + // The resolved ID is never used by the interpreted program, it is hidden. + // This is relied upon for soundness of const-patterns; a pointer to the resolved + // ID would "sidestep" the checks that make sure consts do not point to statics! + // The `GlobalAlloc::Memory` branch here is still reachable though; when a static + // contains a reference to memory that was created during its evaluation (i.e., not + // to another static), those inner references only exist in "resolved" form. + if self.tcx.is_foreign_item(def_id) { + throw_unsup!(ReadExternStatic(def_id)); + } + + (self.tcx.eval_static_initializer(def_id)?, Some(def_id)) + } + }; + M::before_access_global(&self.extra, id, alloc, def_id, is_write)?; + let alloc = Cow::Borrowed(alloc); + // We got tcx memory. Let the machine initialize its "extra" stuff. + let alloc = M::init_allocation_extra( + self, + id, // always use the ID we got as input, not the "hidden" one. + alloc, + M::GLOBAL_KIND.map(MemoryKind::Machine), + ); + Ok(alloc) + } + + /// Gives raw access to the `Allocation`, without bounds or alignment checks. + /// The caller is responsible for calling the access hooks! + fn get_raw( + &self, + id: AllocId, + ) -> InterpResult<'tcx, &Allocation> { + // The error type of the inner closure here is somewhat funny. We have two + // ways of "erroring": An actual error, or because we got a reference from + // `get_global_alloc` that we can actually use directly without inserting anything anywhere. + // So the error type is `InterpResult<'tcx, &Allocation>`. + let a = self.alloc_map.get_or(id, || { + let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?; + match alloc { + Cow::Borrowed(alloc) => { + // We got a ref, cheaply return that as an "error" so that the + // map does not get mutated. + Err(Ok(alloc)) + } + Cow::Owned(alloc) => { + // Need to put it into the map and return a ref to that + let kind = M::GLOBAL_KIND.expect( + "I got a global allocation that I have to copy but the machine does \ + not expect that to happen", + ); + Ok((MemoryKind::Machine(kind), alloc)) + } + } + }); + // Now unpack that funny error type + match a { + Ok(a) => Ok(&a.1), + Err(a) => a, + } + } + + /// "Safe" (bounds and align-checked) allocation access. + pub fn get<'a>( + &'a self, + ptr: Pointer>, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Option>> { + let align = M::enforce_alignment(&self.extra).then_some(align); + let ptr_and_alloc = self.check_and_deref_ptr( + ptr, + size, + align, + CheckInAllocMsg::MemoryAccessTest, + |alloc_id, offset, ptr| { + let alloc = self.get_raw(alloc_id)?; + Ok((alloc.size(), alloc.align, (alloc_id, offset, ptr, alloc))) + }, + )?; + if let Some((alloc_id, offset, ptr, alloc)) = ptr_and_alloc { + let range = alloc_range(offset, size); + M::memory_read(&self.extra, &alloc.extra, ptr.provenance, range)?; + Ok(Some(AllocRef { alloc, range, tcx: self.tcx, alloc_id })) + } else { + // Even in this branch we have to be sure that we actually access the allocation, in + // order to ensure that `static FOO: Type = FOO;` causes a cycle error instead of + // magically pulling *any* ZST value from the ether. However, the `get_raw` above is + // always called when `ptr` has an `AllocId`. + Ok(None) + } + } + + /// Return the `extra` field of the given allocation. + pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> { + Ok(&self.get_raw(id)?.extra) + } + + /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. + /// The caller is responsible for calling the access hooks! + /// + /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the + /// allocation. + fn get_raw_mut( + &mut self, + id: AllocId, + ) -> InterpResult<'tcx, (&mut Allocation, &mut M::MemoryExtra)> + { + // We have "NLL problem case #3" here, which cannot be worked around without loss of + // efficiency even for the common case where the key is in the map. + // + // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.) + if self.alloc_map.get_mut(id).is_none() { + // Slow path. + // Allocation not found locally, go look global. + let alloc = self.get_global_alloc(id, /*is_write*/ true)?; + let kind = M::GLOBAL_KIND.expect( + "I got a global allocation that I have to copy but the machine does \ + not expect that to happen", + ); + self.alloc_map.insert(id, (MemoryKind::Machine(kind), alloc.into_owned())); + } + + let (_kind, alloc) = self.alloc_map.get_mut(id).unwrap(); + if alloc.mutability == Mutability::Not { + throw_ub!(WriteToReadOnly(id)) + } + Ok((alloc, &mut self.extra)) + } + + /// "Safe" (bounds and align-checked) allocation access. + pub fn get_mut<'a>( + &'a mut self, + ptr: Pointer>, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Option>> { + let parts = self.get_ptr_access(ptr, size, align)?; + if let Some((alloc_id, offset, ptr)) = parts { + let tcx = self.tcx; + // FIXME: can we somehow avoid looking up the allocation twice here? + // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. + let (alloc, extra) = self.get_raw_mut(alloc_id)?; + let range = alloc_range(offset, size); + M::memory_written(extra, &mut alloc.extra, ptr.provenance, range)?; + Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id })) + } else { + Ok(None) + } + } + + /// Return the `extra` field of the given allocation. + pub fn get_alloc_extra_mut<'a>( + &'a mut self, + id: AllocId, + ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M::MemoryExtra)> { + let (alloc, memory_extra) = self.get_raw_mut(id)?; + Ok((&mut alloc.extra, memory_extra)) + } + + /// Obtain the size and alignment of an allocation, even if that allocation has + /// been deallocated. + /// + /// If `liveness` is `AllocCheck::MaybeDead`, this function always returns `Ok`. + pub fn get_size_and_align( + &self, + id: AllocId, + liveness: AllocCheck, + ) -> InterpResult<'static, (Size, Align)> { + // # Regular allocations + // Don't use `self.get_raw` here as that will + // a) cause cycles in case `id` refers to a static + // b) duplicate a global's allocation in miri + if let Some((_, alloc)) = self.alloc_map.get(id) { + return Ok((alloc.size(), alloc.align)); + } + + // # Function pointers + // (both global from `alloc_map` and local from `extra_fn_ptr_map`) + if self.get_fn_alloc(id).is_some() { + return if let AllocCheck::Dereferenceable = liveness { + // The caller requested no function pointers. + throw_ub!(DerefFunctionPointer(id)) + } else { + Ok((Size::ZERO, Align::ONE)) + }; + } + + // # Statics + // Can't do this in the match argument, we may get cycle errors since the lock would + // be held throughout the match. + match self.tcx.get_global_alloc(id) { + Some(GlobalAlloc::Static(did)) => { + assert!(!self.tcx.is_thread_local_static(did)); + // Use size and align of the type. + let ty = self.tcx.type_of(did); + let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); + Ok((layout.size, layout.align.abi)) + } + Some(GlobalAlloc::Memory(alloc)) => { + // Need to duplicate the logic here, because the global allocations have + // different associated types than the interpreter-local ones. + Ok((alloc.size(), alloc.align)) + } + Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), + // The rest must be dead. + None => { + if let AllocCheck::MaybeDead = liveness { + // Deallocated pointers are allowed, we should be able to find + // them in the map. + Ok(*self + .dead_alloc_map + .get(&id) + .expect("deallocated pointers should all be recorded in `dead_alloc_map`")) + } else { + throw_ub!(PointerUseAfterFree(id)) + } + } + } + } + + fn get_fn_alloc(&self, id: AllocId) -> Option> { + if let Some(extra) = self.extra_fn_ptr_map.get(&id) { + Some(FnVal::Other(*extra)) + } else { + match self.tcx.get_global_alloc(id) { + Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), + _ => None, + } + } + } + + pub fn get_fn( + &self, + ptr: Pointer>, + ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { + trace!("get_fn({:?})", ptr); + let (alloc_id, offset, _ptr) = self.ptr_get_alloc(ptr)?; + if offset.bytes() != 0 { + throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) + } + self.get_fn_alloc(alloc_id) + .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) + } + + pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { + self.get_raw_mut(id)?.0.mutability = Mutability::Not; + Ok(()) + } + + /// Create a lazy debug printer that prints the given allocation and all allocations it points + /// to, recursively. + #[must_use] + pub fn dump_alloc<'a>(&'a self, id: AllocId) -> DumpAllocs<'a, 'mir, 'tcx, M> { + self.dump_allocs(vec![id]) + } + + /// Create a lazy debug printer for a list of allocations and all allocations they point to, + /// recursively. + #[must_use] + pub fn dump_allocs<'a>(&'a self, mut allocs: Vec) -> DumpAllocs<'a, 'mir, 'tcx, M> { + allocs.sort(); + allocs.dedup(); + DumpAllocs { mem: self, allocs } + } + + /// Print leaked memory. Allocations reachable from `static_roots` or a `Global` allocation + /// are not considered leaked. Leaks whose kind `may_leak()` returns true are not reported. + pub fn leak_report(&self, static_roots: &[AllocId]) -> usize { + // Collect the set of allocations that are *reachable* from `Global` allocations. + let reachable = { + let mut reachable = FxHashSet::default(); + let global_kind = M::GLOBAL_KIND.map(MemoryKind::Machine); + let mut todo: Vec<_> = self.alloc_map.filter_map_collect(move |&id, &(kind, _)| { + if Some(kind) == global_kind { Some(id) } else { None } + }); + todo.extend(static_roots); + while let Some(id) = todo.pop() { + if reachable.insert(id) { + // This is a new allocation, add its relocations to `todo`. + if let Some((_, alloc)) = self.alloc_map.get(id) { + todo.extend(alloc.relocations().values().map(|tag| tag.get_alloc_id())); + } + } + } + reachable + }; + + // All allocations that are *not* `reachable` and *not* `may_leak` are considered leaking. + let leaks: Vec<_> = self.alloc_map.filter_map_collect(|&id, &(kind, _)| { + if kind.may_leak() || reachable.contains(&id) { None } else { Some(id) } + }); + let n = leaks.len(); + if n > 0 { + eprintln!("The following memory was leaked: {:?}", self.dump_allocs(leaks)); + } + n + } + + /// This is used by [priroda](https://github.com/oli-obk/priroda) + pub fn alloc_map(&self) -> &M::MemoryMap { + &self.alloc_map + } +} + +#[doc(hidden)] +/// There's no way to use this directly, it's just a helper struct for the `dump_alloc(s)` methods. +pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { + mem: &'a Memory<'mir, 'tcx, M>, + allocs: Vec, +} + +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Cannot be a closure because it is generic in `Tag`, `Extra`. + fn write_allocation_track_relocs<'tcx, Tag: Provenance, Extra>( + fmt: &mut std::fmt::Formatter<'_>, + tcx: TyCtxt<'tcx>, + allocs_to_print: &mut VecDeque, + alloc: &Allocation, + ) -> std::fmt::Result { + for alloc_id in alloc.relocations().values().map(|tag| tag.get_alloc_id()) { + allocs_to_print.push_back(alloc_id); + } + write!(fmt, "{}", display_allocation(tcx, alloc)) + } + + let mut allocs_to_print: VecDeque<_> = self.allocs.iter().copied().collect(); + // `allocs_printed` contains all allocations that we have already printed. + let mut allocs_printed = FxHashSet::default(); + + while let Some(id) = allocs_to_print.pop_front() { + if !allocs_printed.insert(id) { + // Already printed, so skip this. + continue; + } + + write!(fmt, "{}", id)?; + match self.mem.alloc_map.get(id) { + Some(&(kind, ref alloc)) => { + // normal alloc + write!(fmt, " ({}, ", kind)?; + write_allocation_track_relocs( + &mut *fmt, + self.mem.tcx, + &mut allocs_to_print, + alloc, + )?; + } + None => { + // global alloc + match self.mem.tcx.get_global_alloc(id) { + Some(GlobalAlloc::Memory(alloc)) => { + write!(fmt, " (unchanged global, ")?; + write_allocation_track_relocs( + &mut *fmt, + self.mem.tcx, + &mut allocs_to_print, + alloc, + )?; + } + Some(GlobalAlloc::Function(func)) => { + write!(fmt, " (fn: {})", func)?; + } + Some(GlobalAlloc::Static(did)) => { + write!(fmt, " (static: {})", self.mem.tcx.def_path_str(did))?; + } + None => { + write!(fmt, " (deallocated)")?; + } + } + } + } + writeln!(fmt)?; + } + Ok(()) + } +} + +/// Reading and writing. +impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { + pub fn write_scalar( + &mut self, + range: AllocRange, + val: ScalarMaybeUninit, + ) -> InterpResult<'tcx> { + Ok(self + .alloc + .write_scalar(&self.tcx, self.range.subrange(range), val) + .map_err(|e| e.to_interp_error(self.alloc_id))?) + } + + pub fn write_ptr_sized( + &mut self, + offset: Size, + val: ScalarMaybeUninit, + ) -> InterpResult<'tcx> { + self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) + } +} + +impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { + pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit> { + Ok(self + .alloc + .read_scalar(&self.tcx, self.range.subrange(range)) + .map_err(|e| e.to_interp_error(self.alloc_id))?) + } + + pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit> { + self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size)) + } + + pub fn check_bytes(&self, range: AllocRange, allow_uninit_and_ptr: bool) -> InterpResult<'tcx> { + Ok(self + .alloc + .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit_and_ptr) + .map_err(|e| e.to_interp_error(self.alloc_id))?) + } +} + +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { + /// Reads the given number of bytes from memory. Returns them as a slice. + /// + /// Performs appropriate bounds checks. + pub fn read_bytes( + &self, + ptr: Pointer>, + size: Size, + ) -> InterpResult<'tcx, &[u8]> { + let alloc_ref = match self.get(ptr, size, Align::ONE)? { + Some(a) => a, + None => return Ok(&[]), // zero-sized access + }; + // Side-step AllocRef and directly access the underlying bytes more efficiently. + // (We are staying inside the bounds here so all is good.) + Ok(alloc_ref + .alloc + .get_bytes(&alloc_ref.tcx, alloc_ref.range) + .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?) + } + + /// Writes the given stream of bytes into memory. + /// + /// Performs appropriate bounds checks. + pub fn write_bytes( + &mut self, + ptr: Pointer>, + src: impl IntoIterator, + ) -> InterpResult<'tcx> { + let mut src = src.into_iter(); + let (lower, upper) = src.size_hint(); + let len = upper.expect("can only write bounded iterators"); + assert_eq!(lower, len, "can only write iterators with a precise length"); + + let size = Size::from_bytes(len); + let alloc_ref = match self.get_mut(ptr, size, Align::ONE)? { + Some(alloc_ref) => alloc_ref, + None => { + // zero-sized access + assert_matches!( + src.next(), + None, + "iterator said it was empty but returned an element" + ); + return Ok(()); + } + }; + + // Side-step AllocRef and directly access the underlying bytes more efficiently. + // (We are staying inside the bounds here so all is good.) + let alloc_id = alloc_ref.alloc_id; + let bytes = alloc_ref + .alloc + .get_bytes_mut(&alloc_ref.tcx, alloc_ref.range) + .map_err(move |e| e.to_interp_error(alloc_id))?; + // `zip` would stop when the first iterator ends; we want to definitely + // cover all of `bytes`. + for dest in bytes { + *dest = src.next().expect("iterator was shorter than it said it would be"); + } + assert_matches!(src.next(), None, "iterator was longer than it said it would be"); + Ok(()) + } + + pub fn copy( + &mut self, + src: Pointer>, + src_align: Align, + dest: Pointer>, + dest_align: Align, + size: Size, + nonoverlapping: bool, + ) -> InterpResult<'tcx> { + self.copy_repeatedly(src, src_align, dest, dest_align, size, 1, nonoverlapping) + } + + pub fn copy_repeatedly( + &mut self, + src: Pointer>, + src_align: Align, + dest: Pointer>, + dest_align: Align, + size: Size, + num_copies: u64, + nonoverlapping: bool, + ) -> InterpResult<'tcx> { + let tcx = self.tcx; + // We need to do our own bounds-checks. + let src_parts = self.get_ptr_access(src, size, src_align)?; + let dest_parts = self.get_ptr_access(dest, size * num_copies, dest_align)?; // `Size` multiplication + + // FIXME: we look up both allocations twice here, once ebfore for the `check_ptr_access` + // and once below to get the underlying `&[mut] Allocation`. + + // Source alloc preparations and access hooks. + let (src_alloc_id, src_offset, src) = match src_parts { + None => return Ok(()), // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do. + Some(src_ptr) => src_ptr, + }; + let src_alloc = self.get_raw(src_alloc_id)?; + let src_range = alloc_range(src_offset, size); + M::memory_read(&self.extra, &src_alloc.extra, src.provenance, src_range)?; + // We need the `dest` ptr for the next operation, so we get it now. + // We already did the source checks and called the hooks so we are good to return early. + let (dest_alloc_id, dest_offset, dest) = match dest_parts { + None => return Ok(()), // Zero-sized *destiantion*. + Some(dest_ptr) => dest_ptr, + }; + + // first copy the relocations to a temporary buffer, because + // `get_bytes_mut` will clear the relocations, which is correct, + // since we don't want to keep any relocations at the target. + // (`get_bytes_with_uninit_and_ptr` below checks that there are no + // relocations overlapping the edges; those would not be handled correctly). + let relocations = + src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies); + // Prepare a copy of the initialization mask. + let compressed = src_alloc.compress_uninit_range(src_range); + // This checks relocation edges on the src. + let src_bytes = src_alloc + .get_bytes_with_uninit_and_ptr(&tcx, src_range) + .map_err(|e| e.to_interp_error(src_alloc_id))? + .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation + + // Destination alloc preparations and access hooks. + let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?; + let dest_range = alloc_range(dest_offset, size * num_copies); + M::memory_written(extra, &mut dest_alloc.extra, dest.provenance, dest_range)?; + let dest_bytes = dest_alloc + .get_bytes_mut_ptr(&tcx, dest_range) + .map_err(|e| e.to_interp_error(dest_alloc_id))? + .as_mut_ptr(); + + if compressed.no_bytes_init() { + // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range + // is marked as uninitialized but we otherwise omit changing the byte representation which may + // be arbitrary for uninitialized bytes. + // This also avoids writing to the target bytes so that the backing allocation is never + // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary + // operating system this can avoid physically allocating the page. + dest_alloc.mark_init(dest_range, false); // `Size` multiplication + dest_alloc.mark_relocation_range(relocations); + return Ok(()); + } + + // SAFE: The above indexing would have panicked if there weren't at least `size` bytes + // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and + // `dest` could possibly overlap. + // The pointers above remain valid even if the `HashMap` table is moved around because they + // point into the `Vec` storing the bytes. + unsafe { + if src_alloc_id == dest_alloc_id { + if nonoverlapping { + // `Size` additions + if (src_offset <= dest_offset && src_offset + size > dest_offset) + || (dest_offset <= src_offset && dest_offset + size > src_offset) + { + throw_ub_format!("copy_nonoverlapping called on overlapping ranges") + } + } + + for i in 0..num_copies { + ptr::copy( + src_bytes, + dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication + size.bytes_usize(), + ); + } + } else { + for i in 0..num_copies { + ptr::copy_nonoverlapping( + src_bytes, + dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication + size.bytes_usize(), + ); + } + } + } + + // now fill in all the "init" data + dest_alloc.mark_compressed_init_range( + &compressed, + alloc_range(dest_offset, size), // just a single copy (i.e., not full `dest_range`) + num_copies, + ); + // copy the relocations to the destination + dest_alloc.mark_relocation_range(relocations); + + Ok(()) + } +} + +/// Machine pointer introspection. +impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { + pub fn scalar_to_ptr(&self, scalar: Scalar) -> Pointer> { + // We use `to_bits_or_ptr_internal` since we are just implementing the method people need to + // call to force getting out a pointer. + match scalar.to_bits_or_ptr_internal(self.pointer_size()) { + Err(ptr) => ptr.into(), + Ok(bits) => { + let addr = u64::try_from(bits).unwrap(); + let ptr = M::ptr_from_addr(&self, addr); + if addr == 0 { + assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId"); + } + ptr + } + } + } + + /// Turning a "maybe pointer" into a proper pointer (and some information + /// about where it points), or an absolute address. + pub fn ptr_try_get_alloc( + &self, + ptr: Pointer>, + ) -> Result<(AllocId, Size, Pointer), u64> { + match ptr.into_pointer_or_addr() { + Ok(ptr) => { + let (alloc_id, offset) = M::ptr_get_alloc(self, ptr); + Ok((alloc_id, offset, ptr)) + } + Err(addr) => Err(addr.bytes()), + } + } + + /// Turning a "maybe pointer" into a proper pointer (and some information about where it points). + #[inline(always)] + pub fn ptr_get_alloc( + &self, + ptr: Pointer>, + ) -> InterpResult<'tcx, (AllocId, Size, Pointer)> { + self.ptr_try_get_alloc(ptr).map_err(|offset| { + err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into() + }) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +//! An interpreter for MIR used in CTFE and by miri + +mod cast; +mod eval_context; +mod intern; +mod intrinsics; +mod machine; +mod memory; +mod operand; +mod operator; +mod place; +mod step; +mod terminator; +mod traits; +mod util; +mod validity; +mod visitor; + +pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here + +pub use self::eval_context::{ + Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind, +}; +pub use self::intern::{intern_const_alloc_recursive, InternKind}; +pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; +pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; +pub use self::operand::{ImmTy, Immediate, OpTy, Operand}; +pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; +pub use self::validity::{CtfeValidationMode, RefTracking}; +pub use self::visitor::{MutValueVisitor, ValueVisitor}; + +crate use self::intrinsics::eval_nullary_intrinsic; +use eval_context::{from_known_layout, mir_assign_valid_types}; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/operand.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/operand.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/operand.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/operand.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,763 @@ +//! Functions concerning immediate values and operands, and reading from operands. +//! All high-level functions to read from memory work on operands as sources. + +use std::convert::TryFrom; +use std::fmt::Write; + +use rustc_errors::ErrorReported; +use rustc_hir::def::Namespace; +use rustc_macros::HashStable; +use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; +use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; +use rustc_middle::ty::{ConstInt, Ty}; +use rustc_middle::{mir, ty}; +use rustc_target::abi::{Abi, HasDataLayout, Size, TagEncoding}; +use rustc_target::abi::{VariantIdx, Variants}; + +use super::{ + alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId, + InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Provenance, + Scalar, ScalarMaybeUninit, +}; + +/// An `Immediate` represents a single immediate self-contained Rust value. +/// +/// For optimization of a few very common cases, there is also a representation for a pair of +/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary +/// operations and wide pointers. This idea was taken from rustc's codegen. +/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely +/// defined on `Immediate`, and do not have to work with a `Place`. +#[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)] +pub enum Immediate { + Scalar(ScalarMaybeUninit), + ScalarPair(ScalarMaybeUninit, ScalarMaybeUninit), +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(Immediate, 56); + +impl From> for Immediate { + #[inline(always)] + fn from(val: ScalarMaybeUninit) -> Self { + Immediate::Scalar(val) + } +} + +impl From> for Immediate { + #[inline(always)] + fn from(val: Scalar) -> Self { + Immediate::Scalar(val.into()) + } +} + +impl<'tcx, Tag: Provenance> Immediate { + pub fn from_pointer(p: Pointer, cx: &impl HasDataLayout) -> Self { + Immediate::Scalar(ScalarMaybeUninit::from_pointer(p, cx)) + } + + pub fn from_maybe_pointer(p: Pointer>, cx: &impl HasDataLayout) -> Self { + Immediate::Scalar(ScalarMaybeUninit::from_maybe_pointer(p, cx)) + } + + pub fn new_slice(val: Scalar, len: u64, cx: &impl HasDataLayout) -> Self { + Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into()) + } + + pub fn new_dyn_trait( + val: Scalar, + vtable: Pointer>, + cx: &impl HasDataLayout, + ) -> Self { + Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx)) + } + + #[inline] + pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit { + match self { + Immediate::Scalar(val) => val, + Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"), + } + } + + #[inline] + pub fn to_scalar(self) -> InterpResult<'tcx, Scalar> { + self.to_scalar_or_uninit().check_init() + } + + #[inline] + pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { + match self { + Immediate::ScalarPair(val1, val2) => Ok((val1.check_init()?, val2.check_init()?)), + Immediate::Scalar(..) => { + bug!("Got a scalar where a scalar pair was expected") + } + } + } +} + +// ScalarPair needs a type to interpret, so we often have an immediate and a type together +// as input for binary and cast operations. +#[derive(Copy, Clone, Debug)] +pub struct ImmTy<'tcx, Tag: Provenance = AllocId> { + imm: Immediate, + pub layout: TyAndLayout<'tcx>, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(ImmTy<'_>, 72); + +impl std::fmt::Display for ImmTy<'tcx, Tag> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// Helper function for printing a scalar to a FmtPrinter + fn p<'a, 'tcx, F: std::fmt::Write, Tag: Provenance>( + cx: FmtPrinter<'a, 'tcx, F>, + s: ScalarMaybeUninit, + ty: Ty<'tcx>, + ) -> Result, std::fmt::Error> { + match s { + ScalarMaybeUninit::Scalar(Scalar::Int(int)) => { + cx.pretty_print_const_scalar_int(int, ty, true) + } + ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _sz)) => { + // Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to + // print what is points to, which would fail since it has no access to the local + // memory. + cx.pretty_print_const_pointer(ptr, ty, true) + } + ScalarMaybeUninit::Uninit => cx.typed_value( + |mut this| { + this.write_str("uninit ")?; + Ok(this) + }, + |this| this.print_type(ty), + " ", + ), + } + } + ty::tls::with(|tcx| { + match self.imm { + Immediate::Scalar(s) => { + if let Some(ty) = tcx.lift(self.layout.ty) { + let cx = FmtPrinter::new(tcx, f, Namespace::ValueNS); + p(cx, s, ty)?; + return Ok(()); + } + write!(f, "{}: {}", s, self.layout.ty) + } + Immediate::ScalarPair(a, b) => { + // FIXME(oli-obk): at least print tuples and slices nicely + write!(f, "({}, {}): {}", a, b, self.layout.ty,) + } + } + }) + } +} + +impl<'tcx, Tag: Provenance> std::ops::Deref for ImmTy<'tcx, Tag> { + type Target = Immediate; + #[inline(always)] + fn deref(&self) -> &Immediate { + &self.imm + } +} + +/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate, +/// or still in memory. The latter is an optimization, to delay reading that chunk of +/// memory and to avoid having to store arbitrary-sized data here. +#[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)] +pub enum Operand { + Immediate(Immediate), + Indirect(MemPlace), +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct OpTy<'tcx, Tag: Provenance = AllocId> { + op: Operand, // Keep this private; it helps enforce invariants. + pub layout: TyAndLayout<'tcx>, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(OpTy<'_>, 80); + +impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> { + type Target = Operand; + #[inline(always)] + fn deref(&self) -> &Operand { + &self.op + } +} + +impl<'tcx, Tag: Provenance> From> for OpTy<'tcx, Tag> { + #[inline(always)] + fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { + OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout } + } +} + +impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { + #[inline(always)] + fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { + OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout } + } +} + +impl<'tcx, Tag: Provenance> From> for OpTy<'tcx, Tag> { + #[inline(always)] + fn from(val: ImmTy<'tcx, Tag>) -> Self { + OpTy { op: Operand::Immediate(val.imm), layout: val.layout } + } +} + +impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { + #[inline] + pub fn from_scalar(val: Scalar, layout: TyAndLayout<'tcx>) -> Self { + ImmTy { imm: val.into(), layout } + } + + #[inline] + pub fn from_immediate(imm: Immediate, layout: TyAndLayout<'tcx>) -> Self { + ImmTy { imm, layout } + } + + #[inline] + pub fn try_from_uint(i: impl Into, layout: TyAndLayout<'tcx>) -> Option { + Some(Self::from_scalar(Scalar::try_from_uint(i, layout.size)?, layout)) + } + #[inline] + pub fn from_uint(i: impl Into, layout: TyAndLayout<'tcx>) -> Self { + Self::from_scalar(Scalar::from_uint(i, layout.size), layout) + } + + #[inline] + pub fn try_from_int(i: impl Into, layout: TyAndLayout<'tcx>) -> Option { + Some(Self::from_scalar(Scalar::try_from_int(i, layout.size)?, layout)) + } + + #[inline] + pub fn from_int(i: impl Into, layout: TyAndLayout<'tcx>) -> Self { + Self::from_scalar(Scalar::from_int(i, layout.size), layout) + } + + #[inline] + pub fn to_const_int(self) -> ConstInt { + assert!(self.layout.ty.is_integral()); + let int = self.to_scalar().expect("to_const_int doesn't work on scalar pairs").assert_int(); + ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral()) + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. + /// Returns `None` if the layout does not permit loading this as a value. + fn try_read_immediate_from_mplace( + &self, + mplace: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Option>> { + if mplace.layout.is_unsized() { + // Don't touch unsized + return Ok(None); + } + + let alloc = match self.get_alloc(mplace)? { + Some(ptr) => ptr, + None => { + return Ok(Some(ImmTy { + // zero-sized type + imm: Scalar::ZST.into(), + layout: mplace.layout, + })); + } + }; + + match mplace.layout.abi { + Abi::Scalar(..) => { + let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?; + Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })) + } + Abi::ScalarPair(a, b) => { + // We checked `ptr_align` above, so all fields will have the alignment they need. + // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, + // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. + let (a, b) = (a.value, b.value); + let (a_size, b_size) = (a.size(self), b.size(self)); + let b_offset = a_size.align_to(b.align(self).abi); + assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields + let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?; + let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?; + Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })) + } + _ => Ok(None), + } + } + + /// Try returning an immediate for the operand. + /// If the layout does not permit loading this as an immediate, return where in memory + /// we can find the data. + /// Note that for a given layout, this operation will either always fail or always + /// succeed! Whether it succeeds depends on whether the layout can be represented + /// in an `Immediate`, not on which data is stored there currently. + pub fn try_read_immediate( + &self, + src: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::PointerTag>>> { + Ok(match src.try_as_mplace() { + Ok(ref mplace) => { + if let Some(val) = self.try_read_immediate_from_mplace(mplace)? { + Ok(val) + } else { + Err(*mplace) + } + } + Err(val) => Ok(val), + }) + } + + /// Read an immediate from a place, asserting that that is possible with the given layout. + #[inline(always)] + pub fn read_immediate( + &self, + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + if let Ok(imm) = self.try_read_immediate(op)? { + Ok(imm) + } else { + span_bug!(self.cur_span(), "primitive read failed for type: {:?}", op.layout.ty); + } + } + + /// Read a scalar from a place + pub fn read_scalar( + &self, + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + Ok(self.read_immediate(op)?.to_scalar_or_uninit()) + } + + /// Read a pointer from a place. + pub fn read_pointer( + &self, + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Pointer>> { + Ok(self.scalar_to_ptr(self.read_scalar(op)?.check_init()?)) + } + + // Turn the wide MPlace into a string (must already be dereferenced!) + pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { + let len = mplace.len(self)?; + let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?; + let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; + Ok(str) + } + + /// Projection functions + pub fn operand_field( + &self, + op: &OpTy<'tcx, M::PointerTag>, + field: usize, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let base = match op.try_as_mplace() { + Ok(ref mplace) => { + // We can reuse the mplace field computation logic for indirect operands. + let field = self.mplace_field(mplace, field)?; + return Ok(field.into()); + } + Err(value) => value, + }; + + let field_layout = op.layout.field(self, field); + if field_layout.is_zst() { + let immediate = Scalar::ZST.into(); + return Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout }); + } + let offset = op.layout.fields.offset(field); + let immediate = match *base { + // the field covers the entire type + _ if offset.bytes() == 0 && field_layout.size == op.layout.size => *base, + // extract fields from types with `ScalarPair` ABI + Immediate::ScalarPair(a, b) => { + let val = if offset.bytes() == 0 { a } else { b }; + Immediate::from(val) + } + Immediate::Scalar(val) => span_bug!( + self.cur_span(), + "field access on non aggregate {:#?}, {:#?}", + val, + op.layout + ), + }; + Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout }) + } + + pub fn operand_index( + &self, + op: &OpTy<'tcx, M::PointerTag>, + index: u64, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + if let Ok(index) = usize::try_from(index) { + // We can just treat this as a field. + self.operand_field(op, index) + } else { + // Indexing into a big array. This must be an mplace. + let mplace = op.assert_mem_place(); + Ok(self.mplace_index(&mplace, index)?.into()) + } + } + + pub fn operand_downcast( + &self, + op: &OpTy<'tcx, M::PointerTag>, + variant: VariantIdx, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // Downcasts only change the layout + Ok(match op.try_as_mplace() { + Ok(ref mplace) => self.mplace_downcast(mplace, variant)?.into(), + Err(..) => { + let layout = op.layout.for_variant(self, variant); + OpTy { layout, ..*op } + } + }) + } + + pub fn operand_projection( + &self, + base: &OpTy<'tcx, M::PointerTag>, + proj_elem: mir::PlaceElem<'tcx>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + use rustc_middle::mir::ProjectionElem::*; + Ok(match proj_elem { + Field(field, _) => self.operand_field(base, field.index())?, + Downcast(_, variant) => self.operand_downcast(base, variant)?, + Deref => self.deref_operand(base)?.into(), + Subslice { .. } | ConstantIndex { .. } | Index(_) => { + // The rest should only occur as mplace, we do not use Immediates for types + // allowing such operations. This matches place_projection forcing an allocation. + let mplace = base.assert_mem_place(); + self.mplace_projection(&mplace, proj_elem)?.into() + } + }) + } + + /// Read from a local. Will not actually access the local if reading from a ZST. + /// Will not access memory, instead an indirect `Operand` is returned. + /// + /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an + /// OpTy from a local + pub fn access_local( + &self, + frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, + local: mir::Local, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let layout = self.layout_of_local(frame, local, layout)?; + let op = if layout.is_zst() { + // Do not read from ZST, they might not be initialized + Operand::Immediate(Scalar::ZST.into()) + } else { + M::access_local(&self, frame, local)? + }; + Ok(OpTy { op, layout }) + } + + /// Every place can be read from, so we can turn them into an operand. + /// This will definitely return `Indirect` if the place is a `Ptr`, i.e., this + /// will never actually read from memory. + #[inline(always)] + pub fn place_to_op( + &self, + place: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let op = match **place { + Place::Ptr(mplace) => Operand::Indirect(mplace), + Place::Local { frame, local } => { + *self.access_local(&self.stack()[frame], local, None)? + } + }; + Ok(OpTy { op, layout: place.layout }) + } + + // Evaluate a place with the goal of reading from it. This lets us sometimes + // avoid allocations. + pub fn eval_place_to_op( + &self, + place: mir::Place<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // Do not use the layout passed in as argument if the base we are looking at + // here is not the entire place. + let layout = if place.projection.is_empty() { layout } else { None }; + + let base_op = self.access_local(self.frame(), place.local, layout)?; + + let op = place + .projection + .iter() + .try_fold(base_op, |op, elem| self.operand_projection(&op, elem))?; + + trace!("eval_place_to_op: got {:?}", *op); + // Sanity-check the type we ended up with. + debug_assert!(mir_assign_valid_types( + *self.tcx, + self.param_env, + self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( + place.ty(&self.frame().body.local_decls, *self.tcx).ty + ))?, + op.layout, + )); + Ok(op) + } + + /// Evaluate the operand, returning a place where you can then find the data. + /// If you already know the layout, you can save two table lookups + /// by passing it in here. + #[inline] + pub fn eval_operand( + &self, + mir_op: &mir::Operand<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + use rustc_middle::mir::Operand::*; + let op = match *mir_op { + // FIXME: do some more logic on `move` to invalidate the old location + Copy(place) | Move(place) => self.eval_place_to_op(place, layout)?, + + Constant(ref constant) => { + let val = + self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal); + // This can still fail: + // * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all + // checked yet. + // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail. + + self.mir_const_to_op(&val, layout)? + } + }; + trace!("{:?}: {:?}", mir_op, *op); + Ok(op) + } + + /// Evaluate a bunch of operands at once + pub(super) fn eval_operands( + &self, + ops: &[mir::Operand<'tcx>], + ) -> InterpResult<'tcx, Vec>> { + ops.iter().map(|op| self.eval_operand(op, None)).collect() + } + + // Used when the miri-engine runs into a constant and for extracting information from constants + // in patterns via the `const_eval` module + /// The `val` and `layout` are assumed to already be in our interpreter + /// "universe" (param_env). + pub fn const_to_op( + &self, + val: &ty::Const<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + match val.val { + ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), + ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), + ty::ConstKind::Unevaluated(uv) => { + let instance = self.resolve(uv.def, uv.substs(*self.tcx))?; + Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into()) + } + ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { + span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) + } + ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty, layout), + } + } + + pub fn mir_const_to_op( + &self, + val: &mir::ConstantKind<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + match val { + mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout), + mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, layout), + } + } + + crate fn const_val_to_op( + &self, + val_val: ConstValue<'tcx>, + ty: Ty<'tcx>, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // Other cases need layout. + let tag_scalar = |scalar| -> InterpResult<'tcx, _> { + Ok(match scalar { + Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size), + Scalar::Int(int) => Scalar::Int(int), + }) + }; + let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; + let op = match val_val { + ConstValue::ByRef { alloc, offset } => { + let id = self.tcx.create_memory_alloc(alloc); + // We rely on mutability being set correctly in that allocation to prevent writes + // where none should happen. + let ptr = self.global_base_pointer(Pointer::new(id, offset))?; + Operand::Indirect(MemPlace::from_ptr(ptr.into(), layout.align.abi)) + } + ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()), + ConstValue::Slice { data, start, end } => { + // We rely on mutability being set correctly in `data` to prevent writes + // where none should happen. + let ptr = Pointer::new( + self.tcx.create_memory_alloc(data), + Size::from_bytes(start), // offset: `start` + ); + Operand::Immediate(Immediate::new_slice( + Scalar::from_pointer(self.global_base_pointer(ptr)?, &*self.tcx), + u64::try_from(end.checked_sub(start).unwrap()).unwrap(), // len: `end - start` + self, + )) + } + }; + Ok(OpTy { op, layout }) + } + + /// Read discriminant, return the runtime value as well as the variant index. + /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)! + pub fn read_discriminant( + &self, + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { + trace!("read_discriminant_value {:#?}", op.layout); + // Get type and layout of the discriminant. + let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?; + trace!("discriminant type: {:?}", discr_layout.ty); + + // We use "discriminant" to refer to the value associated with a particular enum variant. + // This is not to be confused with its "variant index", which is just determining its position in the + // declared list of variants -- they can differ with explicitly assigned discriminants. + // We use "tag" to refer to how the discriminant is encoded in memory, which can be either + // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`). + let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants { + Variants::Single { index } => { + let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) { + Some(discr) => { + // This type actually has discriminants. + assert_eq!(discr.ty, discr_layout.ty); + Scalar::from_uint(discr.val, discr_layout.size) + } + None => { + // On a type without actual discriminants, variant is 0. + assert_eq!(index.as_u32(), 0); + Scalar::from_uint(index.as_u32(), discr_layout.size) + } + }; + return Ok((discr, index)); + } + Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { + (tag, tag_encoding, tag_field) + } + }; + + // There are *three* layouts that come into play here: + // - The discriminant has a type for typechecking. This is `discr_layout`, and is used for + // the `Scalar` we return. + // - The tag (encoded discriminant) has layout `tag_layout`. This is always an integer type, + // and used to interpret the value we read from the tag field. + // For the return value, a cast to `discr_layout` is performed. + // - The field storing the tag has a layout, which is very similar to `tag_layout` but + // may be a pointer. This is `tag_val.layout`; we just use it for sanity checks. + + // Get layout for tag. + let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?; + + // Read tag and sanity-check `tag_layout`. + let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?; + assert_eq!(tag_layout.size, tag_val.layout.size); + assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); + let tag_val = tag_val.to_scalar()?; + trace!("tag value: {:?}", tag_val); + + // Figure out which discriminant and variant this corresponds to. + Ok(match *tag_encoding { + TagEncoding::Direct => { + let tag_bits = tag_val + .try_to_int() + .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))? + .assert_bits(tag_layout.size); + // Cast bits from tag layout to discriminant layout. + let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); + let discr_bits = discr_val.assert_bits(discr_layout.size); + // Convert discriminant to variant index, and catch invalid discriminants. + let index = match *op.layout.ty.kind() { + ty::Adt(adt, _) => { + adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits) + } + ty::Generator(def_id, substs, _) => { + let substs = substs.as_generator(); + substs + .discriminants(def_id, *self.tcx) + .find(|(_, var)| var.val == discr_bits) + } + _ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"), + } + .ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?; + // Return the cast value, and the index. + (discr_val, index.0) + } + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { + // Compute the variant this niche value/"tag" corresponds to. With niche layout, + // discriminant (encoded in niche/tag) and variant index are the same. + let variants_start = niche_variants.start().as_u32(); + let variants_end = niche_variants.end().as_u32(); + let variant = match tag_val.try_to_int() { + Err(dbg_val) => { + // So this is a pointer then, and casting to an int failed. + // Can only happen during CTFE. + let ptr = self.scalar_to_ptr(tag_val); + // The niche must be just 0, and the ptr not null, then we know this is + // okay. Everything else, we conservatively reject. + let ptr_valid = niche_start == 0 + && variants_start == variants_end + && !self.memory.ptr_may_be_null(ptr); + if !ptr_valid { + throw_ub!(InvalidTag(dbg_val)) + } + dataful_variant + } + Ok(tag_bits) => { + let tag_bits = tag_bits.assert_bits(tag_layout.size); + // We need to use machine arithmetic to get the relative variant idx: + // variant_index_relative = tag_val - niche_start_val + let tag_val = ImmTy::from_uint(tag_bits, tag_layout); + let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); + let variant_index_relative_val = + self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?; + let variant_index_relative = variant_index_relative_val + .to_scalar()? + .assert_bits(tag_val.layout.size); + // Check if this is in the range that indicates an actual discriminant. + if variant_index_relative <= u128::from(variants_end - variants_start) { + let variant_index_relative = u32::try_from(variant_index_relative) + .expect("we checked that this fits into a u32"); + // Then computing the absolute variant idx should not overflow any more. + let variant_index = variants_start + .checked_add(variant_index_relative) + .expect("overflow computing absolute variant idx"); + let variants_len = op + .layout + .ty + .ty_adt_def() + .expect("tagged layout for non adt") + .variants + .len(); + assert!(usize::try_from(variant_index).unwrap() < variants_len); + VariantIdx::from_u32(variant_index) + } else { + dataful_variant + } + } + }; + // Compute the size of the scalar we need to return. + // No need to cast, because the variant index directly serves as discriminant and is + // encoded in the tag. + (Scalar::from_uint(variant.as_u32(), discr_layout.size), variant) + } + }) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/operator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/operator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/operator.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/operator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,417 @@ +use std::convert::TryFrom; + +use rustc_apfloat::Float; +use rustc_middle::mir; +use rustc_middle::mir::interpret::{InterpResult, Scalar}; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::{self, FloatTy, Ty}; + +use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy}; + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + /// Applies the binary operation `op` to the two operands and writes a tuple of the result + /// and a boolean signifying the potential overflow to the destination. + pub fn binop_with_overflow( + &mut self, + op: mir::BinOp, + left: &ImmTy<'tcx, M::PointerTag>, + right: &ImmTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?; + debug_assert_eq!( + self.tcx.intern_tup(&[ty, self.tcx.types.bool]), + dest.layout.ty, + "type mismatch for result of {:?}", + op, + ); + let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into()); + self.write_immediate(val, dest) + } + + /// Applies the binary operation `op` to the arguments and writes the result to the + /// destination. + pub fn binop_ignore_overflow( + &mut self, + op: mir::BinOp, + left: &ImmTy<'tcx, M::PointerTag>, + right: &ImmTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?; + assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op); + self.write_scalar(val, dest) + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + fn binary_char_op( + &self, + bin_op: mir::BinOp, + l: char, + r: char, + ) -> (Scalar, bool, Ty<'tcx>) { + use rustc_middle::mir::BinOp::*; + + let res = match bin_op { + Eq => l == r, + Ne => l != r, + Lt => l < r, + Le => l <= r, + Gt => l > r, + Ge => l >= r, + _ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op), + }; + (Scalar::from_bool(res), false, self.tcx.types.bool) + } + + fn binary_bool_op( + &self, + bin_op: mir::BinOp, + l: bool, + r: bool, + ) -> (Scalar, bool, Ty<'tcx>) { + use rustc_middle::mir::BinOp::*; + + let res = match bin_op { + Eq => l == r, + Ne => l != r, + Lt => l < r, + Le => l <= r, + Gt => l > r, + Ge => l >= r, + BitAnd => l & r, + BitOr => l | r, + BitXor => l ^ r, + _ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op), + }; + (Scalar::from_bool(res), false, self.tcx.types.bool) + } + + fn binary_float_op>>( + &self, + bin_op: mir::BinOp, + ty: Ty<'tcx>, + l: F, + r: F, + ) -> (Scalar, bool, Ty<'tcx>) { + use rustc_middle::mir::BinOp::*; + + let (val, ty) = match bin_op { + Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), + Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), + Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), + Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), + Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), + Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), + Add => ((l + r).value.into(), ty), + Sub => ((l - r).value.into(), ty), + Mul => ((l * r).value.into(), ty), + Div => ((l / r).value.into(), ty), + Rem => ((l % r).value.into(), ty), + _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op), + }; + (val, false, ty) + } + + fn binary_int_op( + &self, + bin_op: mir::BinOp, + // passing in raw bits + l: u128, + left_layout: TyAndLayout<'tcx>, + r: u128, + right_layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + use rustc_middle::mir::BinOp::*; + + // Shift ops can have an RHS with a different numeric type. + if bin_op == Shl || bin_op == Shr { + let signed = left_layout.abi.is_signed(); + let size = u128::from(left_layout.size.bits()); + let overflow = r >= size; + let r = r % size; // mask to type size + let r = u32::try_from(r).unwrap(); // we masked so this will always fit + let result = if signed { + let l = self.sign_extend(l, left_layout) as i128; + let result = match bin_op { + Shl => l.checked_shl(r).unwrap(), + Shr => l.checked_shr(r).unwrap(), + _ => bug!("it has already been checked that this is a shift op"), + }; + result as u128 + } else { + match bin_op { + Shl => l.checked_shl(r).unwrap(), + Shr => l.checked_shr(r).unwrap(), + _ => bug!("it has already been checked that this is a shift op"), + } + }; + let truncated = self.truncate(result, left_layout); + return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty)); + } + + // For the remaining ops, the types must be the same on both sides + if left_layout.ty != right_layout.ty { + span_bug!( + self.cur_span(), + "invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})", + bin_op, + l, + left_layout.ty, + r, + right_layout.ty, + ) + } + + let size = left_layout.size; + + // Operations that need special treatment for signed integers + if left_layout.abi.is_signed() { + let op: Option bool> = match bin_op { + Lt => Some(i128::lt), + Le => Some(i128::le), + Gt => Some(i128::gt), + Ge => Some(i128::ge), + _ => None, + }; + if let Some(op) = op { + let l = self.sign_extend(l, left_layout) as i128; + let r = self.sign_extend(r, right_layout) as i128; + return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool)); + } + let op: Option (i128, bool)> = match bin_op { + Div if r == 0 => throw_ub!(DivisionByZero), + Rem if r == 0 => throw_ub!(RemainderByZero), + Div => Some(i128::overflowing_div), + Rem => Some(i128::overflowing_rem), + Add => Some(i128::overflowing_add), + Sub => Some(i128::overflowing_sub), + Mul => Some(i128::overflowing_mul), + _ => None, + }; + if let Some(op) = op { + let r = self.sign_extend(r, right_layout) as i128; + // We need a special check for overflowing remainder: + // "int_min % -1" overflows and returns 0, but after casting things to a larger int + // type it does *not* overflow nor give an unrepresentable result! + if bin_op == Rem { + if r == -1 && l == (1 << (size.bits() - 1)) { + return Ok((Scalar::from_int(0, size), true, left_layout.ty)); + } + } + let l = self.sign_extend(l, left_layout) as i128; + + let (result, oflo) = op(l, r); + // This may be out-of-bounds for the result type, so we have to truncate ourselves. + // If that truncation loses any information, we have an overflow. + let result = result as u128; + let truncated = self.truncate(result, left_layout); + return Ok(( + Scalar::from_uint(truncated, size), + oflo || self.sign_extend(truncated, left_layout) != result, + left_layout.ty, + )); + } + } + + let (val, ty) = match bin_op { + Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), + Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), + + Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), + Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), + Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), + Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), + + BitOr => (Scalar::from_uint(l | r, size), left_layout.ty), + BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty), + BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty), + + Add | Sub | Mul | Rem | Div => { + assert!(!left_layout.abi.is_signed()); + let op: fn(u128, u128) -> (u128, bool) = match bin_op { + Add => u128::overflowing_add, + Sub => u128::overflowing_sub, + Mul => u128::overflowing_mul, + Div if r == 0 => throw_ub!(DivisionByZero), + Rem if r == 0 => throw_ub!(RemainderByZero), + Div => u128::overflowing_div, + Rem => u128::overflowing_rem, + _ => bug!(), + }; + let (result, oflo) = op(l, r); + // Truncate to target type. + // If that truncation loses any information, we have an overflow. + let truncated = self.truncate(result, left_layout); + return Ok(( + Scalar::from_uint(truncated, size), + oflo || truncated != result, + left_layout.ty, + )); + } + + _ => span_bug!( + self.cur_span(), + "invalid binary op {:?}: {:?}, {:?} (both {:?})", + bin_op, + l, + r, + right_layout.ty, + ), + }; + + Ok((val, false, ty)) + } + + /// Returns the result of the specified operation, whether it overflowed, and + /// the result type. + pub fn overflowing_binary_op( + &self, + bin_op: mir::BinOp, + left: &ImmTy<'tcx, M::PointerTag>, + right: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + trace!( + "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", + bin_op, + *left, + left.layout.ty, + *right, + right.layout.ty + ); + + match left.layout.ty.kind() { + ty::Char => { + assert_eq!(left.layout.ty, right.layout.ty); + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) + } + ty::Bool => { + assert_eq!(left.layout.ty, right.layout.ty); + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) + } + ty::Float(fty) => { + assert_eq!(left.layout.ty, right.layout.ty); + let ty = left.layout.ty; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match fty { + FloatTy::F32 => { + self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?) + } + FloatTy::F64 => { + self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?) + } + }) + } + _ if left.layout.ty.is_integral() => { + // the RHS type can be different, e.g. for shifts -- but it has to be integral, too + assert!( + right.layout.ty.is_integral(), + "Unexpected types for BinOp: {:?} {:?} {:?}", + left.layout.ty, + bin_op, + right.layout.ty + ); + + let l = left.to_scalar()?.to_bits(left.layout.size)?; + let r = right.to_scalar()?.to_bits(right.layout.size)?; + self.binary_int_op(bin_op, l, left.layout, r, right.layout) + } + _ if left.layout.ty.is_any_ptr() => { + // The RHS type must be the same *or an integer type* (for `Offset`). + assert!( + right.layout.ty == left.layout.ty || right.layout.ty.is_integral(), + "Unexpected types for BinOp: {:?} {:?} {:?}", + left.layout.ty, + bin_op, + right.layout.ty + ); + + M::binary_ptr_op(self, bin_op, left, right) + } + _ => span_bug!( + self.cur_span(), + "Invalid MIR: bad LHS type for binop: {:?}", + left.layout.ty + ), + } + } + + /// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows. + #[inline] + pub fn binary_op( + &self, + bin_op: mir::BinOp, + left: &ImmTy<'tcx, M::PointerTag>, + right: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?; + Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) + } + + /// Returns the result of the specified operation, whether it overflowed, and + /// the result type. + pub fn overflowing_unary_op( + &self, + un_op: mir::UnOp, + val: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + use rustc_middle::mir::UnOp::*; + + let layout = val.layout; + let val = val.to_scalar()?; + trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); + + match layout.ty.kind() { + ty::Bool => { + let val = val.to_bool()?; + let res = match un_op { + Not => !val, + _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op), + }; + Ok((Scalar::from_bool(res), false, self.tcx.types.bool)) + } + ty::Float(fty) => { + let res = match (un_op, fty) { + (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), + (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), + _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), + }; + Ok((res, false, layout.ty)) + } + _ => { + assert!(layout.ty.is_integral()); + let val = val.to_bits(layout.size)?; + let (res, overflow) = match un_op { + Not => (self.truncate(!val, layout), false), // bitwise negation, then truncate + Neg => { + // arithmetic negation + assert!(layout.abi.is_signed()); + let val = self.sign_extend(val, layout) as i128; + let (res, overflow) = val.overflowing_neg(); + let res = res as u128; + // Truncate to target type. + // If that truncation loses any information, we have an overflow. + let truncated = self.truncate(res, layout); + (truncated, overflow || self.sign_extend(truncated, layout) != res) + } + }; + Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty)) + } + } + } + + pub fn unary_op( + &self, + un_op: mir::UnOp, + val: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?; + Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/place.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/place.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/place.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/place.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1104 @@ +//! Computations on places -- field projections, going from mir::Place, and writing +//! into a place. +//! All high-level functions to write to memory work on places as destinations. + +use std::convert::TryFrom; +use std::hash::Hash; + +use rustc_ast::Mutability; +use rustc_macros::HashStable; +use rustc_middle::mir; +use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; +use rustc_middle::ty::{self, Ty}; +use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; +use rustc_target::abi::{HasDataLayout, Size, VariantIdx, Variants}; + +use super::{ + alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg, + ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, + Operand, Pointer, PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, +}; + +#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] +/// Information required for the sound usage of a `MemPlace`. +pub enum MemPlaceMeta { + /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). + Meta(Scalar), + /// `Sized` types or unsized `extern type` + None, + /// The address of this place may not be taken. This protects the `MemPlace` from coming from + /// a ZST Operand without a backing allocation and being converted to an integer address. This + /// should be impossible, because you can't take the address of an operand, but this is a second + /// protection layer ensuring that we don't mess up. + Poison, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(MemPlaceMeta, 24); + +impl MemPlaceMeta { + pub fn unwrap_meta(self) -> Scalar { + match self { + Self::Meta(s) => s, + Self::None | Self::Poison => { + bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") + } + } + } + fn has_meta(self) -> bool { + match self { + Self::Meta(_) => true, + Self::None | Self::Poison => false, + } + } +} + +#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] +pub struct MemPlace { + /// The pointer can be a pure integer, with the `None` tag. + pub ptr: Pointer>, + pub align: Align, + /// Metadata for unsized places. Interpretation is up to the type. + /// Must not be present for sized types, but can be missing for unsized types + /// (e.g., `extern type`). + pub meta: MemPlaceMeta, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(MemPlace, 48); + +#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] +pub enum Place { + /// A place referring to a value allocated in the `Memory` system. + Ptr(MemPlace), + + /// To support alloc-free locals, we are able to write directly to a local. + /// (Without that optimization, we'd just always be a `MemPlace`.) + Local { frame: usize, local: mir::Local }, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(Place, 56); + +#[derive(Copy, Clone, Debug)] +pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> { + place: Place, // Keep this private; it helps enforce invariants. + pub layout: TyAndLayout<'tcx>, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72); + +impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> { + type Target = Place; + #[inline(always)] + fn deref(&self) -> &Place { + &self.place + } +} + +/// A MemPlace with its layout. Constructing it is only possible in this module. +#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] +pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> { + mplace: MemPlace, + pub layout: TyAndLayout<'tcx>, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64); + +impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> { + type Target = MemPlace; + #[inline(always)] + fn deref(&self) -> &MemPlace { + &self.mplace + } +} + +impl<'tcx, Tag: Provenance> From> for PlaceTy<'tcx, Tag> { + #[inline(always)] + fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { + PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout } + } +} + +impl MemPlace { + #[inline(always)] + pub fn from_ptr(ptr: Pointer>, align: Align) -> Self { + MemPlace { ptr, align, meta: MemPlaceMeta::None } + } + + /// Adjust the provenance of the main pointer (metadata is unaffected). + pub fn map_provenance(self, f: impl FnOnce(Option) -> Option) -> Self { + MemPlace { ptr: self.ptr.map_provenance(f), ..self } + } + + /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. + /// This is the inverse of `ref_to_mplace`. + #[inline(always)] + pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { + match self.meta { + MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)), + MemPlaceMeta::Meta(meta) => { + Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx).into(), meta.into()) + } + MemPlaceMeta::Poison => bug!( + "MPlaceTy::dangling may never be used to produce a \ + place that will have the address of its pointee taken" + ), + } + } + + #[inline] + pub fn offset( + self, + offset: Size, + meta: MemPlaceMeta, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Self> { + Ok(MemPlace { + ptr: self.ptr.offset(offset, cx)?, + align: self.align.restrict_for_offset(offset), + meta, + }) + } +} + +impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { + /// Produces a MemPlace that works for ZST but nothing else + #[inline] + pub fn dangling(layout: TyAndLayout<'tcx>) -> Self { + let align = layout.align.abi; + let ptr = Pointer::new(None, Size::from_bytes(align.bytes())); // no provenance, absolute address + // `Poison` this to make sure that the pointer value `ptr` is never observable by the program. + MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout } + } + + #[inline] + pub fn offset( + &self, + offset: Size, + meta: MemPlaceMeta, + layout: TyAndLayout<'tcx>, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Self> { + Ok(MPlaceTy { mplace: self.mplace.offset(offset, meta, cx)?, layout }) + } + + #[inline] + pub fn from_aligned_ptr(ptr: Pointer>, layout: TyAndLayout<'tcx>) -> Self { + MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout } + } + + #[inline] + pub(super) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { + if self.layout.is_unsized() { + // We need to consult `meta` metadata + match self.layout.ty.kind() { + ty::Slice(..) | ty::Str => self.mplace.meta.unwrap_meta().to_machine_usize(cx), + _ => bug!("len not supported on unsized type {:?}", self.layout.ty), + } + } else { + // Go through the layout. There are lots of types that support a length, + // e.g., SIMD types. + match self.layout.fields { + FieldsShape::Array { count, .. } => Ok(count), + _ => bug!("len not supported on sized type {:?}", self.layout.ty), + } + } + } + + #[inline] + pub(super) fn vtable(&self) -> Scalar { + match self.layout.ty.kind() { + ty::Dynamic(..) => self.mplace.meta.unwrap_meta(), + _ => bug!("vtable not supported on type {:?}", self.layout.ty), + } + } +} + +// These are defined here because they produce a place. +impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { + #[inline(always)] + /// Note: do not call `as_ref` on the resulting place. This function should only be used to + /// read from the resulting mplace, not to get its address back. + pub fn try_as_mplace(&self) -> Result, ImmTy<'tcx, Tag>> { + match **self { + Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), + Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout)), + Operand::Immediate(imm) => Err(ImmTy::from_immediate(imm, self.layout)), + } + } + + #[inline(always)] + /// Note: do not call `as_ref` on the resulting place. This function should only be used to + /// read from the resulting mplace, not to get its address back. + pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Tag> { + self.try_as_mplace().unwrap() + } +} + +impl Place { + #[inline] + pub fn assert_mem_place(self) -> MemPlace { + match self { + Place::Ptr(mplace) => mplace, + _ => bug!("assert_mem_place: expected Place::Ptr, got {:?}", self), + } + } +} + +impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> { + #[inline] + pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { + MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout } + } +} + +// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385 +impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> +where + // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 + Tag: Provenance + Eq + Hash + 'static, + M: Machine<'mir, 'tcx, PointerTag = Tag>, +{ + /// Take a value, which represents a (thin or wide) reference, and make it a place. + /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. + /// + /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not + /// want to ever use the place for memory access! + /// Generally prefer `deref_operand`. + pub fn ref_to_mplace( + &self, + val: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let pointee_type = + val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; + let layout = self.layout_of(pointee_type)?; + let (ptr, meta) = match **val { + Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None), + Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta.check_init()?)), + }; + + let mplace = MemPlace { + ptr: self.scalar_to_ptr(ptr.check_init()?), + // We could use the run-time alignment here. For now, we do not, because + // the point of tracking the alignment here is to make sure that the *static* + // alignment information emitted with the loads is correct. The run-time + // alignment can only be more restrictive. + align: layout.align.abi, + meta, + }; + Ok(MPlaceTy { mplace, layout }) + } + + /// Take an operand, representing a pointer, and dereference it to a place -- that + /// will always be a MemPlace. Lives in `place.rs` because it creates a place. + pub fn deref_operand( + &self, + src: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let val = self.read_immediate(src)?; + trace!("deref to {} on {:?}", val.layout.ty, *val); + let mplace = self.ref_to_mplace(&val)?; + self.check_mplace_access(mplace, CheckInAllocMsg::DerefTest)?; + Ok(mplace) + } + + #[inline] + pub(super) fn get_alloc( + &self, + place: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Option>> { + assert!(!place.layout.is_unsized()); + assert!(!place.meta.has_meta()); + let size = place.layout.size; + self.memory.get(place.ptr, size, place.align) + } + + #[inline] + pub(super) fn get_alloc_mut( + &mut self, + place: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Option>> { + assert!(!place.layout.is_unsized()); + assert!(!place.meta.has_meta()); + let size = place.layout.size; + self.memory.get_mut(place.ptr, size, place.align) + } + + /// Check if this mplace is dereferencable and sufficiently aligned. + fn check_mplace_access( + &self, + mplace: MPlaceTy<'tcx, M::PointerTag>, + msg: CheckInAllocMsg, + ) -> InterpResult<'tcx> { + let (size, align) = self + .size_and_align_of_mplace(&mplace)? + .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); + assert!(mplace.mplace.align <= align, "dynamic alignment less strict than static one?"); + let align = M::enforce_alignment(&self.memory.extra).then_some(align); + self.memory.check_ptr_access_align(mplace.ptr, size, align.unwrap_or(Align::ONE), msg)?; + Ok(()) + } + + /// Offset a pointer to project to a field of a struct/union. Unlike `place_field`, this is + /// always possible without allocating, so it can take `&self`. Also return the field's layout. + /// This supports both struct and array fields. + /// + /// This also works for arrays, but then the `usize` index type is restricting. + /// For indexing into arrays, use `mplace_index`. + #[inline(always)] + pub fn mplace_field( + &self, + base: &MPlaceTy<'tcx, M::PointerTag>, + field: usize, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let offset = base.layout.fields.offset(field); + let field_layout = base.layout.field(self, field); + + // Offset may need adjustment for unsized fields. + let (meta, offset) = if field_layout.is_unsized() { + // Re-use parent metadata to determine dynamic field layout. + // With custom DSTS, this *will* execute user-defined code, but the same + // happens at run-time so that's okay. + let align = match self.size_and_align_of(&base.meta, &field_layout)? { + Some((_, align)) => align, + None if offset == Size::ZERO => { + // An extern type at offset 0, we fall back to its static alignment. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. + field_layout.align.abi + } + None => span_bug!( + self.cur_span(), + "cannot compute offset for extern type field at non-0 offset" + ), + }; + (base.meta, offset.align_to(align)) + } else { + // base.meta could be present; we might be accessing a sized field of an unsized + // struct. + (MemPlaceMeta::None, offset) + }; + + // We do not look at `base.layout.align` nor `field_layout.align`, unlike + // codegen -- mostly to see if we can get away with that + base.offset(offset, meta, field_layout, self) + } + + /// Index into an array. + #[inline(always)] + pub fn mplace_index( + &self, + base: &MPlaceTy<'tcx, M::PointerTag>, + index: u64, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + // Not using the layout method because we want to compute on u64 + match base.layout.fields { + FieldsShape::Array { stride, .. } => { + let len = base.len(self)?; + if index >= len { + // This can only be reached in ConstProp and non-rustc-MIR. + throw_ub!(BoundsCheckFailed { len, index }); + } + let offset = stride * index; // `Size` multiplication + // All fields have the same layout. + let field_layout = base.layout.field(self, 0); + + assert!(!field_layout.is_unsized()); + base.offset(offset, MemPlaceMeta::None, field_layout, self) + } + _ => span_bug!( + self.cur_span(), + "`mplace_index` called on non-array type {:?}", + base.layout.ty + ), + } + } + + // Iterates over all fields of an array. Much more efficient than doing the + // same by repeatedly calling `mplace_array`. + pub(super) fn mplace_array_fields( + &self, + base: &'a MPlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx, impl Iterator>> + 'a> + { + let len = base.len(self)?; // also asserts that we have a type where this makes sense + let stride = match base.layout.fields { + FieldsShape::Array { stride, .. } => stride, + _ => span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout"), + }; + let layout = base.layout.field(self, 0); + let dl = &self.tcx.data_layout; + // `Size` multiplication + Ok((0..len).map(move |i| base.offset(stride * i, MemPlaceMeta::None, layout, dl))) + } + + fn mplace_subslice( + &self, + base: &MPlaceTy<'tcx, M::PointerTag>, + from: u64, + to: u64, + from_end: bool, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let len = base.len(self)?; // also asserts that we have a type where this makes sense + let actual_to = if from_end { + if from.checked_add(to).map_or(true, |to| to > len) { + // This can only be reached in ConstProp and non-rustc-MIR. + throw_ub!(BoundsCheckFailed { len: len, index: from.saturating_add(to) }); + } + len.checked_sub(to).unwrap() + } else { + to + }; + + // Not using layout method because that works with usize, and does not work with slices + // (that have count 0 in their layout). + let from_offset = match base.layout.fields { + FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked + _ => { + span_bug!(self.cur_span(), "unexpected layout of index access: {:#?}", base.layout) + } + }; + + // Compute meta and new layout + let inner_len = actual_to.checked_sub(from).unwrap(); + let (meta, ty) = match base.layout.ty.kind() { + // It is not nice to match on the type, but that seems to be the only way to + // implement this. + ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)), + ty::Slice(..) => { + let len = Scalar::from_machine_usize(inner_len, self); + (MemPlaceMeta::Meta(len), base.layout.ty) + } + _ => { + span_bug!(self.cur_span(), "cannot subslice non-array type: `{:?}`", base.layout.ty) + } + }; + let layout = self.layout_of(ty)?; + base.offset(from_offset, meta, layout, self) + } + + pub(crate) fn mplace_downcast( + &self, + base: &MPlaceTy<'tcx, M::PointerTag>, + variant: VariantIdx, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + // Downcasts only change the layout + assert!(!base.meta.has_meta()); + Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..*base }) + } + + /// Project into an mplace + pub(super) fn mplace_projection( + &self, + base: &MPlaceTy<'tcx, M::PointerTag>, + proj_elem: mir::PlaceElem<'tcx>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + use rustc_middle::mir::ProjectionElem::*; + Ok(match proj_elem { + Field(field, _) => self.mplace_field(base, field.index())?, + Downcast(_, variant) => self.mplace_downcast(base, variant)?, + Deref => self.deref_operand(&base.into())?, + + Index(local) => { + let layout = self.layout_of(self.tcx.types.usize)?; + let n = self.access_local(self.frame(), local, Some(layout))?; + let n = self.read_scalar(&n)?; + let n = n.to_machine_usize(self)?; + self.mplace_index(base, n)? + } + + ConstantIndex { offset, min_length, from_end } => { + let n = base.len(self)?; + if n < min_length { + // This can only be reached in ConstProp and non-rustc-MIR. + throw_ub!(BoundsCheckFailed { len: min_length, index: n }); + } + + let index = if from_end { + assert!(0 < offset && offset <= min_length); + n.checked_sub(offset).unwrap() + } else { + assert!(offset < min_length); + offset + }; + + self.mplace_index(base, index)? + } + + Subslice { from, to, from_end } => self.mplace_subslice(base, from, to, from_end)?, + }) + } + + /// Gets the place of a field inside the place, and also the field's type. + /// Just a convenience function, but used quite a bit. + /// This is the only projection that might have a side-effect: We cannot project + /// into the field of a local `ScalarPair`, we have to first allocate it. + pub fn place_field( + &mut self, + base: &PlaceTy<'tcx, M::PointerTag>, + field: usize, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + // FIXME: We could try to be smarter and avoid allocation for fields that span the + // entire place. + let mplace = self.force_allocation(base)?; + Ok(self.mplace_field(&mplace, field)?.into()) + } + + pub fn place_index( + &mut self, + base: &PlaceTy<'tcx, M::PointerTag>, + index: u64, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + let mplace = self.force_allocation(base)?; + Ok(self.mplace_index(&mplace, index)?.into()) + } + + pub fn place_downcast( + &self, + base: &PlaceTy<'tcx, M::PointerTag>, + variant: VariantIdx, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + // Downcast just changes the layout + Ok(match base.place { + Place::Ptr(mplace) => { + self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into() + } + Place::Local { .. } => { + let layout = base.layout.for_variant(self, variant); + PlaceTy { layout, ..*base } + } + }) + } + + /// Projects into a place. + pub fn place_projection( + &mut self, + base: &PlaceTy<'tcx, M::PointerTag>, + &proj_elem: &mir::ProjectionElem>, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + use rustc_middle::mir::ProjectionElem::*; + Ok(match proj_elem { + Field(field, _) => self.place_field(base, field.index())?, + Downcast(_, variant) => self.place_downcast(base, variant)?, + Deref => self.deref_operand(&self.place_to_op(base)?)?.into(), + // For the other variants, we have to force an allocation. + // This matches `operand_projection`. + Subslice { .. } | ConstantIndex { .. } | Index(_) => { + let mplace = self.force_allocation(base)?; + self.mplace_projection(&mplace, proj_elem)?.into() + } + }) + } + + /// Computes a place. You should only use this if you intend to write into this + /// place; for reading, a more efficient alternative is `eval_place_for_read`. + pub fn eval_place( + &mut self, + place: mir::Place<'tcx>, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + let mut place_ty = PlaceTy { + // This works even for dead/uninitialized locals; we check further when writing + place: Place::Local { frame: self.frame_idx(), local: place.local }, + layout: self.layout_of_local(self.frame(), place.local, None)?, + }; + + for elem in place.projection.iter() { + place_ty = self.place_projection(&place_ty, &elem)? + } + + trace!("{:?}", self.dump_place(place_ty.place)); + // Sanity-check the type we ended up with. + debug_assert!(mir_assign_valid_types( + *self.tcx, + self.param_env, + self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( + place.ty(&self.frame().body.local_decls, *self.tcx).ty + ))?, + place_ty.layout, + )); + Ok(place_ty) + } + + /// Write an immediate to a place + #[inline(always)] + pub fn write_immediate( + &mut self, + src: Immediate, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + self.write_immediate_no_validate(src, dest)?; + + if M::enforce_validity(self) { + // Data got changed, better make sure it matches the type! + self.validate_operand(&self.place_to_op(dest)?)?; + } + + Ok(()) + } + + /// Write a scalar to a place + #[inline(always)] + pub fn write_scalar( + &mut self, + val: impl Into>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + self.write_immediate(Immediate::Scalar(val.into()), dest) + } + + /// Write a pointer to a place + #[inline(always)] + pub fn write_pointer( + &mut self, + ptr: impl Into>>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest) + } + + /// Write an immediate to a place. + /// If you use this you are responsible for validating that things got copied at the + /// right type. + fn write_immediate_no_validate( + &mut self, + src: Immediate, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + if cfg!(debug_assertions) { + // This is a very common path, avoid some checks in release mode + assert!(!dest.layout.is_unsized(), "Cannot write unsized data"); + match src { + Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Ptr(..))) => assert_eq!( + self.pointer_size(), + dest.layout.size, + "Size mismatch when writing pointer" + ), + Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Int(int))) => { + assert_eq!(int.size(), dest.layout.size, "Size mismatch when writing bits") + } + Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // uninit can have any size + Immediate::ScalarPair(_, _) => { + // FIXME: Can we check anything here? + } + } + } + trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); + + // See if we can avoid an allocation. This is the counterpart to `try_read_immediate`, + // but not factored as a separate function. + let mplace = match dest.place { + Place::Local { frame, local } => { + match M::access_local_mut(self, frame, local)? { + Ok(local) => { + // Local can be updated in-place. + *local = LocalValue::Live(Operand::Immediate(src)); + return Ok(()); + } + Err(mplace) => { + // The local is in memory, go on below. + mplace + } + } + } + Place::Ptr(mplace) => mplace, // already referring to memory + }; + let dest = MPlaceTy { mplace, layout: dest.layout }; + + // This is already in memory, write there. + self.write_immediate_to_mplace_no_validate(src, &dest) + } + + /// Write an immediate to memory. + /// If you use this you are responsible for validating that things got copied at the + /// right type. + fn write_immediate_to_mplace_no_validate( + &mut self, + value: Immediate, + dest: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + // Note that it is really important that the type here is the right one, and matches the + // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here + // to handle padding properly, which is only correct if we never look at this data with the + // wrong type. + + // Invalid places are a thing: the return place of a diverging function + let tcx = *self.tcx; + let mut alloc = match self.get_alloc_mut(dest)? { + Some(a) => a, + None => return Ok(()), // zero-sized access + }; + + // FIXME: We should check that there are dest.layout.size many bytes available in + // memory. The code below is not sufficient, with enough padding it might not + // cover all the bytes! + match value { + Immediate::Scalar(scalar) => { + match dest.layout.abi { + Abi::Scalar(_) => {} // fine + _ => span_bug!( + self.cur_span(), + "write_immediate_to_mplace: invalid Scalar layout: {:#?}", + dest.layout + ), + } + alloc.write_scalar(alloc_range(Size::ZERO, dest.layout.size), scalar) + } + Immediate::ScalarPair(a_val, b_val) => { + // We checked `ptr_align` above, so all fields will have the alignment they need. + // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, + // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. + let (a, b) = match dest.layout.abi { + Abi::ScalarPair(a, b) => (a.value, b.value), + _ => span_bug!( + self.cur_span(), + "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", + dest.layout + ), + }; + let (a_size, b_size) = (a.size(&tcx), b.size(&tcx)); + let b_offset = a_size.align_to(b.align(&tcx).abi); + + // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, + // but that does not work: We could be a newtype around a pair, then the + // fields do not match the `ScalarPair` components. + + alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?; + alloc.write_scalar(alloc_range(b_offset, b_size), b_val) + } + } + } + + /// Copies the data from an operand to a place. This does not support transmuting! + /// Use `copy_op_transmute` if the layouts could disagree. + #[inline(always)] + pub fn copy_op( + &mut self, + src: &OpTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + self.copy_op_no_validate(src, dest)?; + + if M::enforce_validity(self) { + // Data got changed, better make sure it matches the type! + self.validate_operand(&self.place_to_op(dest)?)?; + } + + Ok(()) + } + + /// Copies the data from an operand to a place. This does not support transmuting! + /// Use `copy_op_transmute` if the layouts could disagree. + /// Also, if you use this you are responsible for validating that things get copied at the + /// right type. + fn copy_op_no_validate( + &mut self, + src: &OpTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + // We do NOT compare the types for equality, because well-typed code can + // actually "transmute" `&mut T` to `&T` in an assignment without a cast. + if !mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) { + span_bug!( + self.cur_span(), + "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", + src.layout.ty, + dest.layout.ty, + ); + } + + // Let us see if the layout is simple so we take a shortcut, avoid force_allocation. + let src = match self.try_read_immediate(src)? { + Ok(src_val) => { + assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); + // Yay, we got a value that we can write directly. + // FIXME: Add a check to make sure that if `src` is indirect, + // it does not overlap with `dest`. + return self.write_immediate_no_validate(*src_val, dest); + } + Err(mplace) => mplace, + }; + // Slow path, this does not fit into an immediate. Just memcpy. + trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); + + // This interprets `src.meta` with the `dest` local's layout, if an unsized local + // is being initialized! + let (dest, size) = self.force_allocation_maybe_sized(dest, src.meta)?; + let size = size.unwrap_or_else(|| { + assert!( + !dest.layout.is_unsized(), + "Cannot copy into already initialized unsized place" + ); + dest.layout.size + }); + assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances"); + + self.memory + .copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ true) + } + + /// Copies the data from an operand to a place. The layouts may disagree, but they must + /// have the same size. + pub fn copy_op_transmute( + &mut self, + src: &OpTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) { + // Fast path: Just use normal `copy_op` + return self.copy_op(src, dest); + } + // We still require the sizes to match. + if src.layout.size != dest.layout.size { + // FIXME: This should be an assert instead of an error, but if we transmute within an + // array length computation, `typeck` may not have yet been run and errored out. In fact + // most likey we *are* running `typeck` right now. Investigate whether we can bail out + // on `typeck_results().has_errors` at all const eval entry points. + debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + self.tcx.sess.delay_span_bug( + self.cur_span(), + "size-changing transmute, should have been caught by transmute checking", + ); + throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); + } + // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want + // to avoid that here. + assert!( + !src.layout.is_unsized() && !dest.layout.is_unsized(), + "Cannot transmute unsized data" + ); + + // The hard case is `ScalarPair`. `src` is already read from memory in this case, + // using `src.layout` to figure out which bytes to use for the 1st and 2nd field. + // We have to write them to `dest` at the offsets they were *read at*, which is + // not necessarily the same as the offsets in `dest.layout`! + // Hence we do the copy with the source layout on both sides. We also make sure to write + // into memory, because if `dest` is a local we would not even have a way to write + // at the `src` offsets; the fact that we came from a different layout would + // just be lost. + let dest = self.force_allocation(dest)?; + self.copy_op_no_validate( + src, + &PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }), + )?; + + if M::enforce_validity(self) { + // Data got changed, better make sure it matches the type! + self.validate_operand(&dest.into())?; + } + + Ok(()) + } + + /// Ensures that a place is in memory, and returns where it is. + /// If the place currently refers to a local that doesn't yet have a matching allocation, + /// create such an allocation. + /// This is essentially `force_to_memplace`. + /// + /// This supports unsized types and returns the computed size to avoid some + /// redundant computation when copying; use `force_allocation` for a simpler, sized-only + /// version. + pub fn force_allocation_maybe_sized( + &mut self, + place: &PlaceTy<'tcx, M::PointerTag>, + meta: MemPlaceMeta, + ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option)> { + let (mplace, size) = match place.place { + Place::Local { frame, local } => { + match M::access_local_mut(self, frame, local)? { + Ok(&mut local_val) => { + // We need to make an allocation. + + // We need the layout of the local. We can NOT use the layout we got, + // that might e.g., be an inner field of a struct with `Scalar` layout, + // that has different alignment than the outer field. + let local_layout = + self.layout_of_local(&self.stack()[frame], local, None)?; + // We also need to support unsized types, and hence cannot use `allocate`. + let (size, align) = self + .size_and_align_of(&meta, &local_layout)? + .expect("Cannot allocate for non-dyn-sized type"); + let ptr = self.memory.allocate(size, align, MemoryKind::Stack)?; + let mplace = MemPlace { ptr: ptr.into(), align, meta }; + if let LocalValue::Live(Operand::Immediate(value)) = local_val { + // Preserve old value. + // We don't have to validate as we can assume the local + // was already valid for its type. + let mplace = MPlaceTy { mplace, layout: local_layout }; + self.write_immediate_to_mplace_no_validate(value, &mplace)?; + } + // Now we can call `access_mut` again, asserting it goes well, + // and actually overwrite things. + *M::access_local_mut(self, frame, local).unwrap().unwrap() = + LocalValue::Live(Operand::Indirect(mplace)); + (mplace, Some(size)) + } + Err(mplace) => (mplace, None), // this already was an indirect local + } + } + Place::Ptr(mplace) => (mplace, None), + }; + // Return with the original layout, so that the caller can go on + Ok((MPlaceTy { mplace, layout: place.layout }, size)) + } + + #[inline(always)] + pub fn force_allocation( + &mut self, + place: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0) + } + + pub fn allocate( + &mut self, + layout: TyAndLayout<'tcx>, + kind: MemoryKind, + ) -> InterpResult<'static, MPlaceTy<'tcx, M::PointerTag>> { + let ptr = self.memory.allocate(layout.size, layout.align.abi, kind)?; + Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) + } + + /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation. + pub fn allocate_str( + &mut self, + str: &str, + kind: MemoryKind, + mutbl: Mutability, + ) -> MPlaceTy<'tcx, M::PointerTag> { + let ptr = self.memory.allocate_bytes(str.as_bytes(), Align::ONE, kind, mutbl); + let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self); + let mplace = + MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) }; + + let ty = self.tcx.mk_ref( + self.tcx.lifetimes.re_static, + ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, + ); + let layout = self.layout_of(ty).unwrap(); + MPlaceTy { mplace, layout } + } + + /// Writes the discriminant of the given variant. + pub fn write_discriminant( + &mut self, + variant_index: VariantIdx, + dest: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + // This must be an enum or generator. + match dest.layout.ty.kind() { + ty::Adt(adt, _) => assert!(adt.is_enum()), + ty::Generator(..) => {} + _ => span_bug!( + self.cur_span(), + "write_discriminant called on non-variant-type (neither enum nor generator)" + ), + } + // Layout computation excludes uninhabited variants from consideration + // therefore there's no way to represent those variants in the given layout. + // Essentially, uninhabited variants do not have a tag that corresponds to their + // discriminant, so we cannot do anything here. + // When evaluating we will always error before even getting here, but ConstProp 'executes' + // dead code, so we cannot ICE here. + if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() { + throw_ub!(UninhabitedEnumVariantWritten) + } + + match dest.layout.variants { + Variants::Single { index } => { + assert_eq!(index, variant_index); + } + Variants::Multiple { + tag_encoding: TagEncoding::Direct, + tag: tag_layout, + tag_field, + .. + } => { + // No need to validate that the discriminant here because the + // `TyAndLayout::for_variant()` call earlier already checks the variant is valid. + + let discr_val = + dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val; + + // raw discriminants for enums are isize or bigger during + // their computation, but the in-memory tag is the smallest possible + // representation + let size = tag_layout.value.size(self); + let tag_val = size.truncate(discr_val); + + let tag_dest = self.place_field(dest, tag_field)?; + self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?; + } + Variants::Multiple { + tag_encoding: + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + tag: tag_layout, + tag_field, + .. + } => { + // No need to validate that the discriminant here because the + // `TyAndLayout::for_variant()` call earlier already checks the variant is valid. + + if variant_index != dataful_variant { + let variants_start = niche_variants.start().as_u32(); + let variant_index_relative = variant_index + .as_u32() + .checked_sub(variants_start) + .expect("overflow computing relative variant idx"); + // We need to use machine arithmetic when taking into account `niche_start`: + // tag_val = variant_index_relative + niche_start_val + let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?; + let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); + let variant_index_relative_val = + ImmTy::from_uint(variant_index_relative, tag_layout); + let tag_val = self.binary_op( + mir::BinOp::Add, + &variant_index_relative_val, + &niche_start_val, + )?; + // Write result. + let niche_dest = self.place_field(dest, tag_field)?; + self.write_immediate(*tag_val, &niche_dest)?; + } + } + } + + Ok(()) + } + + pub fn raw_const_to_mplace( + &self, + raw: ConstAlloc<'tcx>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + // This must be an allocation in `tcx` + let _ = self.tcx.global_alloc(raw.alloc_id); + let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; + let layout = self.layout_of(raw.ty)?; + Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) + } + + /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. + /// Also return some more information so drop doesn't have to run the same code twice. + pub(super) fn unpack_dyn_trait( + &self, + mplace: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> { + let vtable = self.scalar_to_ptr(mplace.vtable()); // also sanity checks the type + let (instance, ty) = self.read_drop_type_from_vtable(vtable)?; + let layout = self.layout_of(ty)?; + + // More sanity checks + if cfg!(debug_assertions) { + let (size, align) = self.read_size_and_align_from_vtable(vtable)?; + assert_eq!(size, layout.size); + // only ABI alignment is preserved + assert_eq!(align, layout.align.abi); + } + + let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout }; + Ok((instance, mplace)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/step.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/step.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/step.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/step.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,328 @@ +//! This module contains the `InterpCx` methods for executing a single step of the interpreter. +//! +//! The main entry point is the `step` method. + +use rustc_middle::mir; +use rustc_middle::mir::interpret::{InterpResult, Scalar}; +use rustc_middle::ty::layout::LayoutOf; + +use super::{InterpCx, Machine}; + +/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the +/// same type as the result. +#[inline] +fn binop_left_homogeneous(op: mir::BinOp) -> bool { + use rustc_middle::mir::BinOp::*; + match op { + Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Offset | Shl | Shr => true, + Eq | Ne | Lt | Le | Gt | Ge => false, + } +} +/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the +/// same type as the LHS. +#[inline] +fn binop_right_homogeneous(op: mir::BinOp) -> bool { + use rustc_middle::mir::BinOp::*; + match op { + Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true, + Offset | Shl | Shr => false, + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + pub fn run(&mut self) -> InterpResult<'tcx> { + while self.step()? {} + Ok(()) + } + + /// Returns `true` as long as there are more things to do. + /// + /// This is used by [priroda](https://github.com/oli-obk/priroda) + /// + /// This is marked `#inline(always)` to work around adverserial codegen when `opt-level = 3` + #[inline(always)] + pub fn step(&mut self) -> InterpResult<'tcx, bool> { + if self.stack().is_empty() { + return Ok(false); + } + + let loc = match self.frame().loc { + Ok(loc) => loc, + Err(_) => { + // We are unwinding and this fn has no cleanup code. + // Just go on unwinding. + trace!("unwinding: skipping frame"); + self.pop_stack_frame(/* unwinding */ true)?; + return Ok(true); + } + }; + let basic_block = &self.body().basic_blocks()[loc.block]; + + let old_frames = self.frame_idx(); + + if let Some(stmt) = basic_block.statements.get(loc.statement_index) { + assert_eq!(old_frames, self.frame_idx()); + self.statement(stmt)?; + return Ok(true); + } + + M::before_terminator(self)?; + + let terminator = basic_block.terminator(); + assert_eq!(old_frames, self.frame_idx()); + self.terminator(terminator)?; + Ok(true) + } + + /// Runs the interpretation logic for the given `mir::Statement` at the current frame and + /// statement counter. This also moves the statement counter forward. + pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { + info!("{:?}", stmt); + + use rustc_middle::mir::StatementKind::*; + + // Some statements (e.g., box) push new stack frames. + // We have to record the stack frame number *before* executing the statement. + let frame_idx = self.frame_idx(); + + match &stmt.kind { + Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?, + + SetDiscriminant { place, variant_index } => { + let dest = self.eval_place(**place)?; + self.write_discriminant(*variant_index, &dest)?; + } + + // Mark locals as alive + StorageLive(local) => { + self.storage_live(*local)?; + } + + // Mark locals as dead + StorageDead(local) => { + self.storage_dead(*local)?; + } + + // No dynamic semantics attached to `FakeRead`; MIR + // interpreter is solely intended for borrowck'ed code. + FakeRead(..) => {} + + // Stacked Borrows. + Retag(kind, place) => { + let dest = self.eval_place(**place)?; + M::retag(self, *kind, &dest)?; + } + + // Call CopyNonOverlapping + CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => { + let src = self.eval_operand(src, None)?; + let dst = self.eval_operand(dst, None)?; + let count = self.eval_operand(count, None)?; + self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?; + } + + // Statements we do not track. + AscribeUserType(..) => {} + + // Currently, Miri discards Coverage statements. Coverage statements are only injected + // via an optional compile time MIR pass and have no side effects. Since Coverage + // statements don't exist at the source level, it is safe for Miri to ignore them, even + // for undefined behavior (UB) checks. + // + // A coverage counter inside a const expression (for example, a counter injected in a + // const function) is discarded when the const is evaluated at compile time. Whether + // this should change, and/or how to implement a const eval counter, is a subject of the + // following issue: + // + // FIXME(#73156): Handle source code coverage in const eval + Coverage(..) => {} + + // Defined to do nothing. These are added by optimization passes, to avoid changing the + // size of MIR constantly. + Nop => {} + + LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), + } + + self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1; + Ok(()) + } + + /// Evaluate an assignment statement. + /// + /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue + /// type writes its results directly into the memory specified by the place. + pub fn eval_rvalue_into_place( + &mut self, + rvalue: &mir::Rvalue<'tcx>, + place: mir::Place<'tcx>, + ) -> InterpResult<'tcx> { + let dest = self.eval_place(place)?; + + use rustc_middle::mir::Rvalue::*; + match *rvalue { + ThreadLocalRef(did) => { + let ptr = M::thread_local_static_base_pointer(self, did)?; + self.write_pointer(ptr, &dest)?; + } + + Use(ref operand) => { + // Avoid recomputing the layout + let op = self.eval_operand(operand, Some(dest.layout))?; + self.copy_op(&op, &dest)?; + } + + BinaryOp(bin_op, box (ref left, ref right)) => { + let layout = binop_left_homogeneous(bin_op).then_some(dest.layout); + let left = self.read_immediate(&self.eval_operand(left, layout)?)?; + let layout = binop_right_homogeneous(bin_op).then_some(left.layout); + let right = self.read_immediate(&self.eval_operand(right, layout)?)?; + self.binop_ignore_overflow(bin_op, &left, &right, &dest)?; + } + + CheckedBinaryOp(bin_op, box (ref left, ref right)) => { + // Due to the extra boolean in the result, we can never reuse the `dest.layout`. + let left = self.read_immediate(&self.eval_operand(left, None)?)?; + let layout = binop_right_homogeneous(bin_op).then_some(left.layout); + let right = self.read_immediate(&self.eval_operand(right, layout)?)?; + self.binop_with_overflow(bin_op, &left, &right, &dest)?; + } + + UnaryOp(un_op, ref operand) => { + // The operand always has the same type as the result. + let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?; + let val = self.unary_op(un_op, &val)?; + assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op); + self.write_immediate(*val, &dest)?; + } + + Aggregate(ref kind, ref operands) => { + // active_field_index is for union initialization. + let (dest, active_field_index) = match **kind { + mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { + self.write_discriminant(variant_index, &dest)?; + if adt_def.is_enum() { + assert!(active_field_index.is_none()); + (self.place_downcast(&dest, variant_index)?, None) + } else { + if active_field_index.is_some() { + assert_eq!(operands.len(), 1); + } + (dest, active_field_index) + } + } + _ => (dest, None), + }; + + for (i, operand) in operands.iter().enumerate() { + let op = self.eval_operand(operand, None)?; + let field_index = active_field_index.unwrap_or(i); + let field_dest = self.place_field(&dest, field_index)?; + self.copy_op(&op, &field_dest)?; + } + } + + Repeat(ref operand, _) => { + let src = self.eval_operand(operand, None)?; + assert!(!src.layout.is_unsized()); + let dest = self.force_allocation(&dest)?; + let length = dest.len(self)?; + + if length == 0 { + // Nothing to copy... but let's still make sure that `dest` as a place is valid. + self.get_alloc_mut(&dest)?; + } else { + // Write the src to the first element. + let first = self.mplace_field(&dest, 0)?; + self.copy_op(&src, &first.into())?; + + // This is performance-sensitive code for big static/const arrays! So we + // avoid writing each operand individually and instead just make many copies + // of the first element. + let elem_size = first.layout.size; + let first_ptr = first.ptr; + let rest_ptr = first_ptr.offset(elem_size, self)?; + self.memory.copy_repeatedly( + first_ptr, + first.align, + rest_ptr, + first.align, + elem_size, + length - 1, + /*nonoverlapping:*/ true, + )?; + } + } + + Len(place) => { + let src = self.eval_place(place)?; + let mplace = self.force_allocation(&src)?; + let len = mplace.len(self)?; + self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?; + } + + AddressOf(_, place) | Ref(_, _, place) => { + let src = self.eval_place(place)?; + let place = self.force_allocation(&src)?; + self.write_immediate(place.to_ref(self), &dest)?; + } + + NullaryOp(mir::NullOp::Box, _) => { + M::box_alloc(self, &dest)?; + } + + NullaryOp(null_op, ty) => { + let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty); + let layout = self.layout_of(ty)?; + if layout.is_unsized() { + // FIXME: This should be a span_bug (#80742) + self.tcx.sess.delay_span_bug( + self.frame().current_span(), + &format!("Nullary MIR operator called for unsized type {}", ty), + ); + throw_inval!(SizeOfUnsizedType(ty)); + } + let val = match null_op { + mir::NullOp::SizeOf => layout.size.bytes(), + mir::NullOp::AlignOf => layout.align.abi.bytes(), + mir::NullOp::Box => unreachable!(), + }; + self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?; + } + + ShallowInitBox(ref operand, _) => { + let src = self.eval_operand(operand, None)?; + let v = self.read_immediate(&src)?; + self.write_immediate(*v, &dest)?; + } + + Cast(cast_kind, ref operand, cast_ty) => { + let src = self.eval_operand(operand, None)?; + let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty); + self.cast(&src, cast_kind, cast_ty, &dest)?; + } + + Discriminant(place) => { + let op = self.eval_place_to_op(place, None)?; + let discr_val = self.read_discriminant(&op)?.0; + self.write_scalar(discr_val, &dest)?; + } + } + + trace!("{:?}", self.dump_place(*dest)); + + Ok(()) + } + + fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { + info!("{:?}", terminator.kind); + + self.eval_terminator(terminator)?; + if !self.stack().is_empty() { + if let Ok(loc) = self.frame().loc { + info!("// executing {:?}", loc.block); + } + } + Ok(()) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/terminator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/terminator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/terminator.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/terminator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,514 @@ +use std::borrow::Cow; +use std::convert::TryFrom; + +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::ty::layout::{self, LayoutOf as _, TyAndLayout}; +use rustc_middle::ty::Instance; +use rustc_middle::{ + mir, + ty::{self, Ty}, +}; +use rustc_target::abi; +use rustc_target::spec::abi::Abi; + +use super::{ + FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Scalar, + StackPopCleanup, StackPopUnwind, +}; + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool { + layout::fn_can_unwind(*self.tcx, attrs, abi) + } + + pub(super) fn eval_terminator( + &mut self, + terminator: &mir::Terminator<'tcx>, + ) -> InterpResult<'tcx> { + use rustc_middle::mir::TerminatorKind::*; + match terminator.kind { + Return => { + self.pop_stack_frame(/* unwinding */ false)? + } + + Goto { target } => self.go_to_block(target), + + SwitchInt { ref discr, ref targets, switch_ty } => { + let discr = self.read_immediate(&self.eval_operand(discr, None)?)?; + trace!("SwitchInt({:?})", *discr); + assert_eq!(discr.layout.ty, switch_ty); + + // Branch to the `otherwise` case by default, if no match is found. + assert!(!targets.iter().is_empty()); + let mut target_block = targets.otherwise(); + + for (const_int, target) in targets.iter() { + // Compare using binary_op, to also support pointer values + let res = self + .overflowing_binary_op( + mir::BinOp::Eq, + &discr, + &ImmTy::from_uint(const_int, discr.layout), + )? + .0; + if res.to_bool()? { + target_block = target; + break; + } + } + + self.go_to_block(target_block); + } + + Call { ref func, ref args, destination, ref cleanup, from_hir_call: _, fn_span: _ } => { + let old_stack = self.frame_idx(); + let old_loc = self.frame().loc; + let func = self.eval_operand(func, None)?; + let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() { + ty::FnPtr(sig) => { + let caller_abi = sig.abi(); + let fn_ptr = self.read_pointer(&func)?; + let fn_val = self.memory.get_fn(fn_ptr)?; + ( + fn_val, + caller_abi, + self.fn_can_unwind(CodegenFnAttrFlags::empty(), caller_abi), + ) + } + ty::FnDef(def_id, substs) => { + let sig = func.layout.ty.fn_sig(*self.tcx); + ( + FnVal::Instance( + self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?, + ), + sig.abi(), + self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()), + ) + } + _ => span_bug!( + terminator.source_info.span, + "invalid callee of type {:?}", + func.layout.ty + ), + }; + let args = self.eval_operands(args)?; + let dest_place; + let ret = match destination { + Some((dest, ret)) => { + dest_place = self.eval_place(dest)?; + Some((&dest_place, ret)) + } + None => None, + }; + self.eval_fn_call( + fn_val, + abi, + &args[..], + ret, + match (cleanup, caller_can_unwind) { + (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), + (None, true) => StackPopUnwind::Skip, + (_, false) => StackPopUnwind::NotAllowed, + }, + )?; + // Sanity-check that `eval_fn_call` either pushed a new frame or + // did a jump to another block. + if self.frame_idx() == old_stack && self.frame().loc == old_loc { + span_bug!(terminator.source_info.span, "evaluating this call made no progress"); + } + } + + Drop { place, target, unwind } => { + let place = self.eval_place(place)?; + let ty = place.layout.ty; + trace!("TerminatorKind::drop: {:?}, type {}", place, ty); + + let instance = Instance::resolve_drop_in_place(*self.tcx, ty); + self.drop_in_place(&place, instance, target, unwind)?; + } + + Assert { ref cond, expected, ref msg, target, cleanup } => { + let cond_val = + self.read_immediate(&self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?; + if expected == cond_val { + self.go_to_block(target); + } else { + M::assert_panic(self, msg, cleanup)?; + } + } + + Abort => { + M::abort(self, "the program aborted execution".to_owned())?; + } + + // When we encounter Resume, we've finished unwinding + // cleanup for the current stack frame. We pop it in order + // to continue unwinding the next frame + Resume => { + trace!("unwinding: resuming from cleanup"); + // By definition, a Resume terminator means + // that we're unwinding + self.pop_stack_frame(/* unwinding */ true)?; + return Ok(()); + } + + // It is UB to ever encounter this. + Unreachable => throw_ub!(Unreachable), + + // These should never occur for MIR we actually run. + DropAndReplace { .. } + | FalseEdge { .. } + | FalseUnwind { .. } + | Yield { .. } + | GeneratorDrop => span_bug!( + terminator.source_info.span, + "{:#?} should have been eliminated by MIR pass", + terminator.kind + ), + + // Inline assembly can't be interpreted. + InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), + } + + Ok(()) + } + + fn check_argument_compat( + rust_abi: bool, + caller: TyAndLayout<'tcx>, + callee: TyAndLayout<'tcx>, + ) -> bool { + if caller.ty == callee.ty { + // No question + return true; + } + if !rust_abi { + // Don't risk anything + return false; + } + // Compare layout + match (caller.abi, callee.abi) { + // Different valid ranges are okay (once we enforce validity, + // that will take care to make it UB to leave the range, just + // like for transmute). + (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => caller.value == callee.value, + (abi::Abi::ScalarPair(caller1, caller2), abi::Abi::ScalarPair(callee1, callee2)) => { + caller1.value == callee1.value && caller2.value == callee2.value + } + // Be conservative + _ => false, + } + } + + /// Pass a single argument, checking the types for compatibility. + fn pass_argument( + &mut self, + rust_abi: bool, + caller_arg: &mut impl Iterator>, + callee_arg: &PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + if rust_abi && callee_arg.layout.is_zst() { + // Nothing to do. + trace!("Skipping callee ZST"); + return Ok(()); + } + let caller_arg = caller_arg.next().ok_or_else(|| { + err_ub_format!("calling a function with fewer arguments than it requires") + })?; + if rust_abi { + assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); + } + // Now, check + if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) { + throw_ub_format!( + "calling a function with argument of type {:?} passing data of type {:?}", + callee_arg.layout.ty, + caller_arg.layout.ty + ) + } + // We allow some transmutes here + self.copy_op_transmute(&caller_arg, callee_arg) + } + + /// Call this function -- pushing the stack frame and initializing the arguments. + pub(crate) fn eval_fn_call( + &mut self, + fn_val: FnVal<'tcx, M::ExtraFnVal>, + caller_abi: Abi, + args: &[OpTy<'tcx, M::PointerTag>], + ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, + mut unwind: StackPopUnwind, + ) -> InterpResult<'tcx> { + trace!("eval_fn_call: {:#?}", fn_val); + + let instance = match fn_val { + FnVal::Instance(instance) => instance, + FnVal::Other(extra) => { + return M::call_extra_fn(self, extra, caller_abi, args, ret, unwind); + } + }; + + let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() { + ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(), + ty::Closure(..) => Abi::RustCall, + ty::Generator(..) => Abi::Rust, + _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty), + }; + + // ABI check + let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> { + let normalize_abi = |abi| match abi { + Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic => + // These are all the same ABI, really. + { + Abi::Rust + } + abi => abi, + }; + if normalize_abi(caller_abi) != normalize_abi(callee_abi) { + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + callee_abi.name(), + caller_abi.name() + ) + } + Ok(()) + }; + + match instance.def { + ty::InstanceDef::Intrinsic(..) => { + if M::enforce_abi(self) { + check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?; + } + assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic); + M::call_intrinsic(self, instance, args, ret, unwind) + } + ty::InstanceDef::VtableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::DropGlue(..) + | ty::InstanceDef::CloneShim(..) + | ty::InstanceDef::Item(_) => { + // We need MIR for this fn + let body = + match M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? { + Some(body) => body, + None => return Ok(()), + }; + + // Check against the ABI of the MIR body we are calling (not the ABI of `instance`; + // these can differ when `find_mir_or_eval_fn` does something clever like resolve + // exported symbol names). + let callee_def_id = body.source.def_id(); + let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id)); + + if M::enforce_abi(self) { + check_abi(callee_abi)?; + } + + if !matches!(unwind, StackPopUnwind::NotAllowed) + && !self + .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi) + { + // The callee cannot unwind. + unwind = StackPopUnwind::NotAllowed; + } + + self.push_stack_frame( + instance, + body, + ret.map(|p| p.0), + StackPopCleanup::Goto { ret: ret.map(|p| p.1), unwind }, + )?; + + // If an error is raised here, pop the frame again to get an accurate backtrace. + // To this end, we wrap it all in a `try` block. + let res: InterpResult<'tcx> = try { + trace!( + "caller ABI: {:?}, args: {:#?}", + caller_abi, + args.iter() + .map(|arg| (arg.layout.ty, format!("{:?}", **arg))) + .collect::>() + ); + trace!( + "spread_arg: {:?}, locals: {:#?}", + body.spread_arg, + body.args_iter() + .map(|local| ( + local, + self.layout_of_local(self.frame(), local, None).unwrap().ty + )) + .collect::>() + ); + + // Figure out how to pass which arguments. + // The Rust ABI is special: ZST get skipped. + let rust_abi = match caller_abi { + Abi::Rust | Abi::RustCall => true, + _ => false, + }; + // We have two iterators: Where the arguments come from, + // and where they go to. + + // For where they come from: If the ABI is RustCall, we untuple the + // last incoming argument. These two iterators do not have the same type, + // so to keep the code paths uniform we accept an allocation + // (for RustCall ABI only). + let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> = + if caller_abi == Abi::RustCall && !args.is_empty() { + // Untuple + let (untuple_arg, args) = args.split_last().unwrap(); + trace!("eval_fn_call: Will pass last argument by untupling"); + Cow::from( + args.iter() + .map(|&a| Ok(a)) + .chain( + (0..untuple_arg.layout.fields.count()) + .map(|i| self.operand_field(untuple_arg, i)), + ) + .collect::>>>( + )?, + ) + } else { + // Plain arg passing + Cow::from(args) + }; + // Skip ZSTs + let mut caller_iter = + caller_args.iter().filter(|op| !rust_abi || !op.layout.is_zst()).copied(); + + // Now we have to spread them out across the callee's locals, + // taking into account the `spread_arg`. If we could write + // this is a single iterator (that handles `spread_arg`), then + // `pass_argument` would be the loop body. It takes care to + // not advance `caller_iter` for ZSTs. + for local in body.args_iter() { + let dest = self.eval_place(mir::Place::from(local))?; + if Some(local) == body.spread_arg { + // Must be a tuple + for i in 0..dest.layout.fields.count() { + let dest = self.place_field(&dest, i)?; + self.pass_argument(rust_abi, &mut caller_iter, &dest)?; + } + } else { + // Normal argument + self.pass_argument(rust_abi, &mut caller_iter, &dest)?; + } + } + // Now we should have no more caller args + if caller_iter.next().is_some() { + throw_ub_format!("calling a function with more arguments than it expected") + } + // Don't forget to check the return type! + if let Some((caller_ret, _)) = ret { + let callee_ret = self.eval_place(mir::Place::return_place())?; + if !Self::check_argument_compat( + rust_abi, + caller_ret.layout, + callee_ret.layout, + ) { + throw_ub_format!( + "calling a function with return type {:?} passing \ + return place of type {:?}", + callee_ret.layout.ty, + caller_ret.layout.ty + ) + } + } else { + let local = mir::RETURN_PLACE; + let callee_layout = self.layout_of_local(self.frame(), local, None)?; + if !callee_layout.abi.is_uninhabited() { + throw_ub_format!("calling a returning function without a return place") + } + } + }; + match res { + Err(err) => { + self.stack_mut().pop(); + Err(err) + } + Ok(()) => Ok(()), + } + } + // cannot use the shim here, because that will only result in infinite recursion + ty::InstanceDef::Virtual(_, idx) => { + let mut args = args.to_vec(); + // We have to implement all "object safe receivers". Currently we + // support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do + // not yet support custom self types. + // Also see `compiler/rustc_codegen_llvm/src/abi.rs` and `compiler/rustc_codegen_ssa/src/mir/block.rs`. + let receiver_place = match args[0].layout.ty.builtin_deref(true) { + Some(_) => { + // Built-in pointer. + self.deref_operand(&args[0])? + } + None => { + // Unsized self. + args[0].assert_mem_place() + } + }; + // Find and consult vtable + let vtable = self.scalar_to_ptr(receiver_place.vtable()); + let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; + + // `*mut receiver_place.layout.ty` is almost the layout that we + // want for args[0]: We have to project to field 0 because we want + // a thin pointer. + assert!(receiver_place.layout.is_unsized()); + let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty); + let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0); + // Adjust receiver argument. + args[0] = OpTy::from(ImmTy::from_immediate( + Scalar::from_maybe_pointer(receiver_place.ptr, self).into(), + this_receiver_ptr, + )); + trace!("Patched self operand to {:#?}", args[0]); + // recurse with concrete function + self.eval_fn_call(fn_val, caller_abi, &args, ret, unwind) + } + } + } + + fn drop_in_place( + &mut self, + place: &PlaceTy<'tcx, M::PointerTag>, + instance: ty::Instance<'tcx>, + target: mir::BasicBlock, + unwind: Option, + ) -> InterpResult<'tcx> { + trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance); + // We take the address of the object. This may well be unaligned, which is fine + // for us here. However, unaligned accesses will probably make the actual drop + // implementation fail -- a problem shared by rustc. + let place = self.force_allocation(place)?; + + let (instance, place) = match place.layout.ty.kind() { + ty::Dynamic(..) => { + // Dropping a trait object. + self.unpack_dyn_trait(&place)? + } + _ => (instance, place), + }; + + let arg = ImmTy::from_immediate( + place.to_ref(self), + self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?, + ); + + let ty = self.tcx.mk_unit(); // return type is () + let dest = MPlaceTy::dangling(self.layout_of(ty)?); + + self.eval_fn_call( + FnVal::Instance(instance), + Abi::Rust, + &[arg.into()], + Some((&dest.into(), target)), + match unwind { + Some(cleanup) => StackPopUnwind::Cleanup(cleanup), + None => StackPopUnwind::Skip, + }, + ) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/traits.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/traits.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/traits.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/traits.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,142 @@ +use std::convert::TryFrom; + +use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic}; +use rustc_middle::ty::{ + self, Ty, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN, + COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE, +}; +use rustc_target::abi::{Align, Size}; + +use super::util::ensure_monomorphic_enough; +use super::{FnVal, InterpCx, Machine}; + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + /// Creates a dynamic vtable for the given type and vtable origin. This is used only for + /// objects. + /// + /// The `trait_ref` encodes the erased self type. Hence, if we are + /// making an object `Foo` from a value of type `Foo`, then + /// `trait_ref` would map `T: Trait`. + pub fn get_vtable( + &mut self, + ty: Ty<'tcx>, + poly_trait_ref: Option>, + ) -> InterpResult<'tcx, Pointer>> { + trace!("get_vtable(trait_ref={:?})", poly_trait_ref); + + let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); + + // All vtables must be monomorphic, bail out otherwise. + ensure_monomorphic_enough(*self.tcx, ty)?; + ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; + + let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref)); + + let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_allocation))?; + + Ok(vtable_ptr.into()) + } + + /// Resolves the function at the specified slot in the provided + /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`) + /// corresponds to the first method declared in the trait of the provided vtable. + pub fn get_vtable_slot( + &self, + vtable: Pointer>, + idx: u64, + ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { + let ptr_size = self.pointer_size(); + let vtable_slot = vtable.offset(ptr_size * idx, self)?; + let vtable_slot = self + .memory + .get(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? + .expect("cannot be a ZST"); + let fn_ptr = self.scalar_to_ptr(vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?); + self.memory.get_fn(fn_ptr) + } + + /// Returns the drop fn instance as well as the actual dynamic type. + pub fn read_drop_type_from_vtable( + &self, + vtable: Pointer>, + ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> { + let pointer_size = self.pointer_size(); + // We don't care about the pointee type; we just want a pointer. + let vtable = self + .memory + .get( + vtable, + pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(), + self.tcx.data_layout.pointer_align.abi, + )? + .expect("cannot be a ZST"); + let drop_fn = vtable + .read_ptr_sized( + pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap(), + )? + .check_init()?; + // We *need* an instance here, no other kind of function value, to be able + // to determine the type. + let drop_instance = self.memory.get_fn(self.scalar_to_ptr(drop_fn))?.as_instance()?; + trace!("Found drop fn: {:?}", drop_instance); + let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); + let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig); + // The drop function takes `*mut T` where `T` is the type being dropped, so get that. + let args = fn_sig.inputs(); + if args.len() != 1 { + throw_ub!(InvalidVtableDropFn(fn_sig)); + } + let ty = + args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty; + Ok((drop_instance, ty)) + } + + pub fn read_size_and_align_from_vtable( + &self, + vtable: Pointer>, + ) -> InterpResult<'tcx, (Size, Align)> { + let pointer_size = self.pointer_size(); + // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here), + // the size, and the align (which we read below). + let vtable = self + .memory + .get( + vtable, + pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(), + self.tcx.data_layout.pointer_align.abi, + )? + .expect("cannot be a ZST"); + let size = vtable + .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())? + .check_init()?; + let size = size.to_machine_usize(self)?; + let align = vtable + .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())? + .check_init()?; + let align = align.to_machine_usize(self)?; + let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?; + + if size >= self.tcx.data_layout.obj_size_bound() { + throw_ub!(InvalidVtableSize); + } + Ok((Size::from_bytes(size), align)) + } + + pub fn read_new_vtable_after_trait_upcasting_from_vtable( + &self, + vtable: Pointer>, + idx: u64, + ) -> InterpResult<'tcx, Pointer>> { + let pointer_size = self.pointer_size(); + + let vtable_slot = vtable.offset(pointer_size * idx, self)?; + let new_vtable = self + .memory + .get(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)? + .expect("cannot be a ZST"); + + let new_vtable = self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?); + + Ok(new_vtable) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/util.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/util.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,85 @@ +use rustc_middle::mir::interpret::InterpResult; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor}; +use std::convert::TryInto; +use std::ops::ControlFlow; + +/// Returns `true` if a used generic parameter requires substitution. +crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx> +where + T: TypeFoldable<'tcx>, +{ + debug!("ensure_monomorphic_enough: ty={:?}", ty); + if !ty.potentially_needs_subst() { + return Ok(()); + } + + struct FoundParam; + struct UsedParamsNeedSubstVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + } + + impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { + type BreakTy = FoundParam; + + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + if !ty.potentially_needs_subst() { + return ControlFlow::CONTINUE; + } + + match *ty.kind() { + ty::Param(_) => ControlFlow::Break(FoundParam), + ty::Closure(def_id, substs) + | ty::Generator(def_id, substs, ..) + | ty::FnDef(def_id, substs) => { + let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let unused_params = self.tcx.unused_generic_params(instance); + for (index, subst) in substs.into_iter().enumerate() { + let index = index + .try_into() + .expect("more generic parameters than can fit into a `u32`"); + let is_used = unused_params.contains(index).map_or(true, |unused| !unused); + // Only recurse when generic parameters in fns, closures and generators + // are used and require substitution. + match (is_used, subst.definitely_needs_subst(self.tcx)) { + // Just in case there are closures or generators within this subst, + // recurse. + (true, true) => return subst.super_visit_with(self), + // Confirm that polymorphization replaced the parameter with + // `ty::Param`/`ty::ConstKind::Param`. + (false, true) if cfg!(debug_assertions) => match subst.unpack() { + ty::subst::GenericArgKind::Type(ty) => { + assert!(matches!(ty.kind(), ty::Param(_))) + } + ty::subst::GenericArgKind::Const(ct) => { + assert!(matches!(ct.val, ty::ConstKind::Param(_))) + } + ty::subst::GenericArgKind::Lifetime(..) => (), + }, + _ => {} + } + } + ControlFlow::CONTINUE + } + _ => ty.super_visit_with(self), + } + } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { + match c.val { + ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), + _ => c.super_visit_with(self), + } + } + } + + let mut vis = UsedParamsNeedSubstVisitor { tcx }; + if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { + throw_inval!(TooGeneric); + } else { + Ok(()) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/validity.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/validity.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/validity.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/validity.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,963 @@ +//! Check the validity invariant of a given value, and tell the user +//! where in the value it got violated. +//! In const context, this goes even further and tries to approximate const safety. +//! That's useful because it means other passes (e.g. promotion) can rely on `const`s +//! to be const-safe. + +use std::convert::TryFrom; +use std::fmt::Write; +use std::num::NonZeroUsize; + +use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; +use rustc_middle::mir::interpret::InterpError; +use rustc_middle::ty; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange}; + +use std::hash::Hash; + +use super::{ + alloc_range, CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, + MemPlaceMeta, OpTy, ScalarMaybeUninit, ValueVisitor, +}; + +macro_rules! throw_validation_failure { + ($where:expr, { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )?) => {{ + let mut msg = String::new(); + msg.push_str("encountered "); + write!(&mut msg, $($what_fmt),+).unwrap(); + $( + msg.push_str(", but expected "); + write!(&mut msg, $($expected_fmt),+).unwrap(); + )? + let path = rustc_middle::ty::print::with_no_trimmed_paths(|| { + let where_ = &$where; + if !where_.is_empty() { + let mut path = String::new(); + write_path(&mut path, where_); + Some(path) + } else { + None + } + }); + throw_ub!(ValidationFailure { path, msg }) + }}; +} + +/// If $e throws an error matching the pattern, throw a validation failure. +/// Other errors are passed back to the caller, unchanged -- and if they reach the root of +/// the visitor, we make sure only validation errors and `InvalidProgram` errors are left. +/// This lets you use the patterns as a kind of validation list, asserting which errors +/// can possibly happen: +/// +/// ``` +/// let v = try_validation!(some_fn(), some_path, { +/// Foo | Bar | Baz => { "some failure" }, +/// }); +/// ``` +/// +/// An additional expected parameter can also be added to the failure message: +/// +/// ``` +/// let v = try_validation!(some_fn(), some_path, { +/// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" }, +/// }); +/// ``` +/// +/// An additional nicety is that both parameters actually take format args, so you can just write +/// the format string in directly: +/// +/// ``` +/// let v = try_validation!(some_fn(), some_path, { +/// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value }, +/// }); +/// ``` +/// +macro_rules! try_validation { + ($e:expr, $where:expr, + $( $( $p:pat_param )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)? + ) => {{ + match $e { + Ok(x) => x, + // We catch the error and turn it into a validation failure. We are okay with + // allocation here as this can only slow down builds that fail anyway. + Err(e) => match e.kind() { + $( + $($p)|+ => + throw_validation_failure!( + $where, + { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )? + ) + ),+, + #[allow(unreachable_patterns)] + _ => Err::(e)?, + } + } + }}; +} + +/// We want to show a nice path to the invalid field for diagnostics, +/// but avoid string operations in the happy case where no error happens. +/// So we track a `Vec` where `PathElem` contains all the data we +/// need to later print something for the user. +#[derive(Copy, Clone, Debug)] +pub enum PathElem { + Field(Symbol), + Variant(Symbol), + GeneratorState(VariantIdx), + CapturedVar(Symbol), + ArrayElem(usize), + TupleElem(usize), + Deref, + EnumTag, + GeneratorTag, + DynDowncast, +} + +/// Extra things to check for during validation of CTFE results. +pub enum CtfeValidationMode { + /// Regular validation, nothing special happening. + Regular, + /// Validation of a `const`. + /// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const + /// allocation). Being an inner allocation makes a difference because the top-level allocation + /// of a `const` is copied for each use, but the inner allocations are implicitly shared. + /// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics). + Const { inner: bool, allow_static_ptrs: bool }, +} + +/// State for tracking recursive validation of references +pub struct RefTracking { + pub seen: FxHashSet, + pub todo: Vec<(T, PATH)>, +} + +impl RefTracking { + pub fn empty() -> Self { + RefTracking { seen: FxHashSet::default(), todo: vec![] } + } + pub fn new(op: T) -> Self { + let mut ref_tracking_for_consts = + RefTracking { seen: FxHashSet::default(), todo: vec![(op, PATH::default())] }; + ref_tracking_for_consts.seen.insert(op); + ref_tracking_for_consts + } + + pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { + if self.seen.insert(op) { + trace!("Recursing below ptr {:#?}", op); + let path = path(); + // Remember to come back to this later. + self.todo.push((op, path)); + } + } +} + +/// Format a path +fn write_path(out: &mut String, path: &[PathElem]) { + use self::PathElem::*; + + for elem in path.iter() { + match elem { + Field(name) => write!(out, ".{}", name), + EnumTag => write!(out, "."), + Variant(name) => write!(out, ".", name), + GeneratorTag => write!(out, "."), + GeneratorState(idx) => write!(out, ".", idx.index()), + CapturedVar(name) => write!(out, ".", name), + TupleElem(idx) => write!(out, ".{}", idx), + ArrayElem(idx) => write!(out, "[{}]", idx), + // `.` does not match Rust syntax, but it is more readable for long paths -- and + // some of the other items here also are not Rust syntax. Actually we can't + // even use the usual syntax because we are just showing the projections, + // not the root. + Deref => write!(out, "."), + DynDowncast => write!(out, "."), + } + .unwrap() + } +} + +// Formats such that a sentence like "expected something {}" to mean +// "expected something " makes sense. +fn wrapping_range_format(r: WrappingRange, max_hi: u128) -> String { + let WrappingRange { start: lo, end: hi } = r; + assert!(hi <= max_hi); + if lo > hi { + format!("less or equal to {}, or greater or equal to {}", hi, lo) + } else if lo == hi { + format!("equal to {}", lo) + } else if lo == 0 { + assert!(hi < max_hi, "should not be printing if the range covers everything"); + format!("less or equal to {}", hi) + } else if hi == max_hi { + assert!(lo > 0, "should not be printing if the range covers everything"); + format!("greater or equal to {}", lo) + } else { + format!("in the range {:?}", r) + } +} + +struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { + /// The `path` may be pushed to, but the part that is present when a function + /// starts must not be changed! `visit_fields` and `visit_array` rely on + /// this stack discipline. + path: Vec, + ref_tracking: Option<&'rt mut RefTracking, Vec>>, + /// `None` indicates this is not validating for CTFE (but for runtime). + ctfe_mode: Option, + ecx: &'rt InterpCx<'mir, 'tcx, M>, +} + +impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> { + fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem { + // First, check if we are projecting to a variant. + match layout.variants { + Variants::Multiple { tag_field, .. } => { + if tag_field == field { + return match layout.ty.kind() { + ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, + ty::Generator(..) => PathElem::GeneratorTag, + _ => bug!("non-variant type {:?}", layout.ty), + }; + } + } + Variants::Single { .. } => {} + } + + // Now we know we are projecting to a field, so figure out which one. + match layout.ty.kind() { + // generators and closures. + ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { + let mut name = None; + // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar + // https://github.com/rust-lang/project-rfc-2229/issues/46 + if let Some(local_def_id) = def_id.as_local() { + let tables = self.ecx.tcx.typeck(local_def_id); + if let Some(captured_place) = + tables.closure_min_captures_flattened(*def_id).nth(field) + { + // Sometimes the index is beyond the number of upvars (seen + // for a generator). + let var_hir_id = captured_place.get_root_variable(); + let node = self.ecx.tcx.hir().get(var_hir_id); + if let hir::Node::Binding(pat) = node { + if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { + name = Some(ident.name); + } + } + } + } + + PathElem::CapturedVar(name.unwrap_or_else(|| { + // Fall back to showing the field index. + sym::integer(field) + })) + } + + // tuples + ty::Tuple(_) => PathElem::TupleElem(field), + + // enums + ty::Adt(def, ..) if def.is_enum() => { + // we might be projecting *to* a variant, or to a field *in* a variant. + match layout.variants { + Variants::Single { index } => { + // Inside a variant + PathElem::Field(def.variants[index].fields[field].ident.name) + } + Variants::Multiple { .. } => bug!("we handled variants above"), + } + } + + // other ADTs + ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name), + + // arrays/slices + ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field), + + // dyn traits + ty::Dynamic(..) => PathElem::DynDowncast, + + // nothing else has an aggregate layout + _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", layout.ty), + } + } + + fn with_elem( + &mut self, + elem: PathElem, + f: impl FnOnce(&mut Self) -> InterpResult<'tcx, R>, + ) -> InterpResult<'tcx, R> { + // Remember the old state + let path_len = self.path.len(); + // Record new element + self.path.push(elem); + // Perform operation + let r = f(self)?; + // Undo changes + self.path.truncate(path_len); + // Done + Ok(r) + } + + fn check_wide_ptr_meta( + &mut self, + meta: MemPlaceMeta, + pointee: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx> { + let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); + match tail.kind() { + ty::Dynamic(..) => { + let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta()); + // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. + try_validation!( + self.ecx.memory.check_ptr_access_align( + vtable, + 3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align + self.ecx.tcx.data_layout.pointer_align.abi, + CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message + ), + self.path, + err_ub!(DanglingIntPointer(..)) | + err_ub!(PointerUseAfterFree(..)) => + { "dangling vtable pointer in wide pointer" }, + err_ub!(AlignmentCheckFailed { .. }) => + { "unaligned vtable pointer in wide pointer" }, + err_ub!(PointerOutOfBounds { .. }) => + { "too small vtable" }, + ); + try_validation!( + self.ecx.read_drop_type_from_vtable(vtable), + self.path, + err_ub!(DanglingIntPointer(..)) | + err_ub!(InvalidFunctionPointer(..)) => + { "invalid drop function pointer in vtable (not pointing to a function)" }, + err_ub!(InvalidVtableDropFn(..)) => + { "invalid drop function pointer in vtable (function has incompatible signature)" }, + ); + try_validation!( + self.ecx.read_size_and_align_from_vtable(vtable), + self.path, + err_ub!(InvalidVtableSize) => + { "invalid vtable: size is bigger than largest supported object" }, + err_ub!(InvalidVtableAlignment(msg)) => + { "invalid vtable: alignment {}", msg }, + err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, + ); + // FIXME: More checks for the vtable. + } + ty::Slice(..) | ty::Str => { + let _len = try_validation!( + meta.unwrap_meta().to_machine_usize(self.ecx), + self.path, + err_unsup!(ReadPointerAsBytes) => { "non-integer slice length in wide pointer" }, + ); + // We do not check that `len * elem_size <= isize::MAX`: + // that is only required for references, and there it falls out of the + // "dereferenceable" check performed by Stacked Borrows. + } + ty::Foreign(..) => { + // Unsized, but not wide. + } + _ => bug!("Unexpected unsized type tail: {:?}", tail), + } + + Ok(()) + } + + /// Check a reference or `Box`. + fn check_safe_pointer( + &mut self, + value: &OpTy<'tcx, M::PointerTag>, + kind: &str, + ) -> InterpResult<'tcx> { + let value = try_validation!( + self.ecx.read_immediate(value), + self.path, + err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" }, + ); + // Handle wide pointers. + // Check metadata early, for better diagnostics + let place = try_validation!( + self.ecx.ref_to_mplace(&value), + self.path, + err_ub!(InvalidUninitBytes(None)) => { "uninitialized {}", kind }, + ); + if place.layout.is_unsized() { + self.check_wide_ptr_meta(place.meta, place.layout)?; + } + // Make sure this is dereferenceable and all. + let size_and_align = try_validation!( + self.ecx.size_and_align_of_mplace(&place), + self.path, + err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg }, + ); + let (size, align) = size_and_align + // for the purpose of validity, consider foreign types to have + // alignment and size determined by the layout (size will be 0, + // alignment should take attributes into account). + .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); + // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. + try_validation!( + self.ecx.memory.check_ptr_access_align( + place.ptr, + size, + align, + CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message + ), + self.path, + err_ub!(AlignmentCheckFailed { required, has }) => + { + "an unaligned {} (required {} byte alignment but found {})", + kind, + required.bytes(), + has.bytes() + }, + err_ub!(DanglingIntPointer(0, _)) => + { "a null {}", kind }, + err_ub!(DanglingIntPointer(i, _)) => + { "a dangling {} (address 0x{:x} is unallocated)", kind, i }, + err_ub!(PointerOutOfBounds { .. }) => + { "a dangling {} (going beyond the bounds of its allocation)", kind }, + // This cannot happen during const-eval (because interning already detects + // dangling pointers), but it can happen in Miri. + err_ub!(PointerUseAfterFree(..)) => + { "a dangling {} (use-after-free)", kind }, + ); + // Recursive checking + if let Some(ref mut ref_tracking) = self.ref_tracking { + // Proceed recursively even for ZST, no reason to skip them! + // `!` is a ZST and we want to validate it. + // Skip validation entirely for some external statics + if let Ok((alloc_id, _offset, _ptr)) = self.ecx.memory.ptr_try_get_alloc(place.ptr) { + // not a ZST + let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id); + if let Some(GlobalAlloc::Static(did)) = alloc_kind { + assert!(!self.ecx.tcx.is_thread_local_static(did)); + assert!(self.ecx.tcx.is_static(did)); + if matches!( + self.ctfe_mode, + Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) + ) { + // See const_eval::machine::MemoryExtra::can_access_statics for why + // this check is so important. + // This check is reachable when the const just referenced the static, + // but never read it (so we never entered `before_access_global`). + throw_validation_failure!(self.path, + { "a {} pointing to a static variable", kind } + ); + } + // We skip checking other statics. These statics must be sound by + // themselves, and the only way to get broken statics here is by using + // unsafe code. + // The reasons we don't check other statics is twofold. For one, in all + // sound cases, the static was already validated on its own, and second, we + // trigger cycle errors if we try to compute the value of the other static + // and that static refers back to us. + // We might miss const-invalid data, + // but things are still sound otherwise (in particular re: consts + // referring to statics). + return Ok(()); + } + } + let path = &self.path; + ref_tracking.track(place, || { + // We need to clone the path anyway, make sure it gets created + // with enough space for the additional `Deref`. + let mut new_path = Vec::with_capacity(path.len() + 1); + new_path.clone_from(path); + new_path.push(PathElem::Deref); + new_path + }); + } + Ok(()) + } + + fn read_scalar( + &self, + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + Ok(try_validation!( + self.ecx.read_scalar(op), + self.path, + err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "plain (non-pointer) bytes" }, + )) + } + + /// Check if this is a value of primitive type, and if yes check the validity of the value + /// at that type. Return `true` if the type is indeed primitive. + fn try_visit_primitive( + &mut self, + value: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, bool> { + // Go over all the primitive types + let ty = value.layout.ty; + match ty.kind() { + ty::Bool => { + let value = self.read_scalar(value)?; + try_validation!( + value.to_bool(), + self.path, + err_ub!(InvalidBool(..)) | err_ub!(InvalidUninitBytes(None)) => + { "{}", value } expected { "a boolean" }, + ); + Ok(true) + } + ty::Char => { + let value = self.read_scalar(value)?; + try_validation!( + value.to_char(), + self.path, + err_ub!(InvalidChar(..)) | err_ub!(InvalidUninitBytes(None)) => + { "{}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" }, + ); + Ok(true) + } + ty::Float(_) | ty::Int(_) | ty::Uint(_) => { + let value = self.read_scalar(value)?; + // NOTE: Keep this in sync with the array optimization for int/float + // types below! + if self.ctfe_mode.is_some() { + // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous + let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok()); + if !is_bits { + throw_validation_failure!(self.path, + { "{}", value } expected { "initialized plain (non-pointer) bytes" } + ) + } + } else { + // At run-time, for now, we accept *anything* for these types, including + // uninit. We should fix that, but let's start low. + } + Ok(true) + } + ty::RawPtr(..) => { + // We are conservative with uninit for integers, but try to + // actually enforce the strict rules for raw pointers (mostly because + // that lets us re-use `ref_to_mplace`). + let place = try_validation!( + self.ecx.read_immediate(value).and_then(|ref i| self.ecx.ref_to_mplace(i)), + self.path, + err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" }, + err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" }, + ); + if place.layout.is_unsized() { + self.check_wide_ptr_meta(place.meta, place.layout)?; + } + Ok(true) + } + ty::Ref(_, ty, mutbl) => { + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) + && *mutbl == hir::Mutability::Mut + { + // A mutable reference inside a const? That does not seem right (except if it is + // a ZST). + let layout = self.ecx.layout_of(ty)?; + if !layout.is_zst() { + throw_validation_failure!(self.path, { "mutable reference in a `const`" }); + } + } + self.check_safe_pointer(value, "reference")?; + Ok(true) + } + ty::Adt(def, ..) if def.is_box() => { + self.check_safe_pointer(value, "box")?; + Ok(true) + } + ty::FnPtr(_sig) => { + let value = try_validation!( + self.ecx.read_immediate(value), + self.path, + err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" }, + ); + // Make sure we print a `ScalarMaybeUninit` (and not an `ImmTy`) in the error + // message below. + let value = value.to_scalar_or_uninit(); + let _fn = try_validation!( + value.check_init().and_then(|ptr| self.ecx.memory.get_fn(self.ecx.scalar_to_ptr(ptr))), + self.path, + err_ub!(DanglingIntPointer(..)) | + err_ub!(InvalidFunctionPointer(..)) | + err_ub!(InvalidUninitBytes(None)) => + { "{}", value } expected { "a function pointer" }, + ); + // FIXME: Check if the signature matches + Ok(true) + } + ty::Never => throw_validation_failure!(self.path, { "a value of the never type `!`" }), + ty::Foreign(..) | ty::FnDef(..) => { + // Nothing to check. + Ok(true) + } + // The above should be all the primitive types. The rest is compound, we + // check them by visiting their fields/variants. + ty::Adt(..) + | ty::Tuple(..) + | ty::Array(..) + | ty::Slice(..) + | ty::Str + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) => Ok(false), + // Some types only occur during typechecking, they have no layout. + // We should not see them here and we could not check them anyway. + ty::Error(_) + | ty::Infer(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Param(..) + | ty::Opaque(..) + | ty::Projection(..) + | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty), + } + } + + fn visit_scalar( + &mut self, + op: &OpTy<'tcx, M::PointerTag>, + scalar_layout: ScalarAbi, + ) -> InterpResult<'tcx> { + if scalar_layout.valid_range.is_full_for(op.layout.size) { + // Nothing to check + return Ok(()); + } + // At least one value is excluded. + let valid_range = scalar_layout.valid_range; + let WrappingRange { start, end } = valid_range; + let max_value = op.layout.size.unsigned_int_max(); + assert!(end <= max_value); + // Determine the allowed range + let value = self.read_scalar(op)?; + let value = try_validation!( + value.check_init(), + self.path, + err_ub!(InvalidUninitBytes(None)) => { "{}", value } + expected { "something {}", wrapping_range_format(valid_range, max_value) }, + ); + let bits = match value.try_to_int() { + Err(_) => { + // So this is a pointer then, and casting to an int failed. + // Can only happen during CTFE. + let ptr = self.ecx.scalar_to_ptr(value); + if start == 1 && end == max_value { + // Only null is the niche. So make sure the ptr is NOT null. + if self.ecx.memory.ptr_may_be_null(ptr) { + throw_validation_failure!(self.path, + { "a potentially null pointer" } + expected { + "something that cannot possibly fail to be {}", + wrapping_range_format(valid_range, max_value) + } + ) + } + return Ok(()); + } else { + // Conservatively, we reject, because the pointer *could* have a bad + // value. + throw_validation_failure!(self.path, + { "a pointer" } + expected { + "something that cannot possibly fail to be {}", + wrapping_range_format(valid_range, max_value) + } + ) + } + } + Ok(int) => int.assert_bits(op.layout.size), + }; + // Now compare. This is slightly subtle because this is a special "wrap-around" range. + if valid_range.contains(bits) { + Ok(()) + } else { + throw_validation_failure!(self.path, + { "{}", bits } + expected { "something {}", wrapping_range_format(valid_range, max_value) } + ) + } + } +} + +impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> + for ValidityVisitor<'rt, 'mir, 'tcx, M> +{ + type V = OpTy<'tcx, M::PointerTag>; + + #[inline(always)] + fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { + &self.ecx + } + + fn read_discriminant( + &mut self, + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, VariantIdx> { + self.with_elem(PathElem::EnumTag, move |this| { + Ok(try_validation!( + this.ecx.read_discriminant(op), + this.path, + err_ub!(InvalidTag(val)) => + { "{}", val } expected { "a valid enum tag" }, + err_ub!(InvalidUninitBytes(None)) => + { "uninitialized bytes" } expected { "a valid enum tag" }, + err_unsup!(ReadPointerAsBytes) => + { "a pointer" } expected { "a valid enum tag" }, + ) + .1) + }) + } + + #[inline] + fn visit_field( + &mut self, + old_op: &OpTy<'tcx, M::PointerTag>, + field: usize, + new_op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + let elem = self.aggregate_field_path_elem(old_op.layout, field); + self.with_elem(elem, move |this| this.visit_value(new_op)) + } + + #[inline] + fn visit_variant( + &mut self, + old_op: &OpTy<'tcx, M::PointerTag>, + variant_id: VariantIdx, + new_op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + let name = match old_op.layout.ty.kind() { + ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name), + // Generators also have variants + ty::Generator(..) => PathElem::GeneratorState(variant_id), + _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty), + }; + self.with_elem(name, move |this| this.visit_value(new_op)) + } + + #[inline(always)] + fn visit_union( + &mut self, + _op: &OpTy<'tcx, M::PointerTag>, + _fields: NonZeroUsize, + ) -> InterpResult<'tcx> { + Ok(()) + } + + #[inline] + fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + trace!("visit_value: {:?}, {:?}", *op, op.layout); + + // Check primitive types -- the leafs of our recursive descend. + if self.try_visit_primitive(op)? { + return Ok(()); + } + // Sanity check: `builtin_deref` does not know any pointers that are not primitive. + assert!(op.layout.ty.builtin_deref(true).is_none()); + + // Special check preventing `UnsafeCell` in the inner part of constants + if let Some(def) = op.layout.ty.ty_adt_def() { + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) + && Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() + { + throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); + } + } + + // Recursively walk the value at its type. + self.walk_value(op)?; + + // *After* all of this, check the ABI. We need to check the ABI to handle + // types like `NonNull` where the `Scalar` info is more restrictive than what + // the fields say (`rustc_layout_scalar_valid_range_start`). + // But in most cases, this will just propagate what the fields say, + // and then we want the error to point at the field -- so, first recurse, + // then check ABI. + // + // FIXME: We could avoid some redundant checks here. For newtypes wrapping + // scalars, we do the same check on every "level" (e.g., first we check + // MyNewtype and then the scalar in there). + match op.layout.abi { + Abi::Uninhabited => { + throw_validation_failure!(self.path, + { "a value of uninhabited type {:?}", op.layout.ty } + ); + } + Abi::Scalar(scalar_layout) => { + self.visit_scalar(op, scalar_layout)?; + } + Abi::ScalarPair { .. } | Abi::Vector { .. } => { + // These have fields that we already visited above, so we already checked + // all their scalar-level restrictions. + // There is also no equivalent to `rustc_layout_scalar_valid_range_start` + // that would make skipping them here an issue. + } + Abi::Aggregate { .. } => { + // Nothing to do. + } + } + + Ok(()) + } + + fn visit_aggregate( + &mut self, + op: &OpTy<'tcx, M::PointerTag>, + fields: impl Iterator>, + ) -> InterpResult<'tcx> { + match op.layout.ty.kind() { + ty::Str => { + let mplace = op.assert_mem_place(); // strings are never immediate + let len = mplace.len(self.ecx)?; + try_validation!( + self.ecx.memory.read_bytes(mplace.ptr, Size::from_bytes(len)), + self.path, + err_ub!(InvalidUninitBytes(..)) => { "uninitialized data in `str`" }, + err_unsup!(ReadPointerAsBytes) => { "a pointer in `str`" }, + ); + } + ty::Array(tys, ..) | ty::Slice(tys) + // This optimization applies for types that can hold arbitrary bytes (such as + // integer and floating point types) or for structs or tuples with no fields. + // FIXME(wesleywiser) This logic could be extended further to arbitrary structs + // or tuples made up of integer/floating point types or inhabited ZSTs with no + // padding. + if matches!(tys.kind(), ty::Int(..) | ty::Uint(..) | ty::Float(..)) + => + { + // Optimized handling for arrays of integer/float type. + + // Arrays cannot be immediate, slices are never immediate. + let mplace = op.assert_mem_place(); + // This is the length of the array/slice. + let len = mplace.len(self.ecx)?; + // This is the element type size. + let layout = self.ecx.layout_of(tys)?; + // This is the size in bytes of the whole array. (This checks for overflow.) + let size = layout.size * len; + + // Optimization: we just check the entire range at once. + // NOTE: Keep this in sync with the handling of integer and float + // types above, in `visit_primitive`. + // In run-time mode, we accept pointers in here. This is actually more + // permissive than a per-element check would be, e.g., we accept + // a &[u8] that contains a pointer even though bytewise checking would + // reject it. However, that's good: We don't inherently want + // to reject those pointers, we just do not have the machinery to + // talk about parts of a pointer. + // We also accept uninit, for consistency with the slow path. + let alloc = match self.ecx.memory.get(mplace.ptr, size, mplace.align)? { + Some(a) => a, + None => { + // Size 0, nothing more to check. + return Ok(()); + } + }; + + match alloc.check_bytes( + alloc_range(Size::ZERO, size), + /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(), + ) { + // In the happy case, we needn't check anything else. + Ok(()) => {} + // Some error happened, try to provide a more detailed description. + Err(err) => { + // For some errors we might be able to provide extra information. + // (This custom logic does not fit the `try_validation!` macro.) + match err.kind() { + err_ub!(InvalidUninitBytes(Some((_alloc_id, access)))) => { + // Some byte was uninitialized, determine which + // element that byte belongs to so we can + // provide an index. + let i = usize::try_from( + access.uninit_offset.bytes() / layout.size.bytes(), + ) + .unwrap(); + self.path.push(PathElem::ArrayElem(i)); + + throw_validation_failure!(self.path, { "uninitialized bytes" }) + } + err_unsup!(ReadPointerAsBytes) => { + throw_validation_failure!(self.path, { "a pointer" } expected { "plain (non-pointer) bytes" }) + } + + // Propagate upwards (that will also check for unexpected errors). + _ => return Err(err), + } + } + } + } + // Fast path for arrays and slices of ZSTs. We only need to check a single ZST element + // of an array and not all of them, because there's only a single value of a specific + // ZST type, so either validation fails for all elements or none. + ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(tys)?.is_zst() => { + // Validate just the first element (if any). + self.walk_aggregate(op, fields.take(1))? + } + _ => { + self.walk_aggregate(op, fields)? // default handler + } + } + Ok(()) + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + fn validate_operand_internal( + &self, + op: &OpTy<'tcx, M::PointerTag>, + path: Vec, + ref_tracking: Option<&mut RefTracking, Vec>>, + ctfe_mode: Option, + ) -> InterpResult<'tcx> { + trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); + + // Construct a visitor + let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self }; + + // Run it. + match visitor.visit_value(&op) { + Ok(()) => Ok(()), + // Pass through validation failures. + Err(err) if matches!(err.kind(), err_ub!(ValidationFailure { .. })) => Err(err), + // Also pass through InvalidProgram, those just indicate that we could not + // validate and each caller will know best what to do with them. + Err(err) if matches!(err.kind(), InterpError::InvalidProgram(_)) => Err(err), + // Avoid other errors as those do not show *where* in the value the issue lies. + Err(err) => { + err.print_backtrace(); + bug!("Unexpected error during validation: {}", err); + } + } + } + + /// This function checks the data at `op` to be const-valid. + /// `op` is assumed to cover valid memory if it is an indirect operand. + /// It will error if the bits at the destination do not match the ones described by the layout. + /// + /// `ref_tracking` is used to record references that we encounter so that they + /// can be checked recursively by an outside driving loop. + /// + /// `constant` controls whether this must satisfy the rules for constants: + /// - no pointers to statics. + /// - no `UnsafeCell` or non-ZST `&mut`. + #[inline(always)] + pub fn const_validate_operand( + &self, + op: &OpTy<'tcx, M::PointerTag>, + path: Vec, + ref_tracking: &mut RefTracking, Vec>, + ctfe_mode: CtfeValidationMode, + ) -> InterpResult<'tcx> { + self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode)) + } + + /// This function checks the data at `op` to be runtime-valid. + /// `op` is assumed to cover valid memory if it is an indirect operand. + /// It will error if the bits at the destination do not match the ones described by the layout. + #[inline(always)] + pub fn validate_operand(&self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + self.validate_operand_internal(op, vec![], None, None) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/visitor.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/visitor.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/visitor.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/interpret/visitor.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,278 @@ +//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound +//! types until we arrive at the leaves, with custom handling for primitive types. + +use rustc_middle::mir::interpret::InterpResult; +use rustc_middle::ty; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_target::abi::{FieldsShape, VariantIdx, Variants}; + +use std::num::NonZeroUsize; + +use super::{InterpCx, MPlaceTy, Machine, OpTy}; + +// A thing that we can project into, and that has a layout. +// This wouldn't have to depend on `Machine` but with the current type inference, +// that's just more convenient to work with (avoids repeating all the `Machine` bounds). +pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { + /// Gets this value's layout. + fn layout(&self) -> TyAndLayout<'tcx>; + + /// Makes this into an `OpTy`. + fn to_op(&self, ecx: &InterpCx<'mir, 'tcx, M>) + -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + + /// Creates this from an `MPlaceTy`. + fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self; + + /// Projects to the given enum variant. + fn project_downcast( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self>; + + /// Projects to the n-th field. + fn project_field( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self>; +} + +// Operands and memory-places are both values. +// Places in general are not due to `place_field` having to do `force_allocation`. +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> { + #[inline(always)] + fn layout(&self) -> TyAndLayout<'tcx> { + self.layout + } + + #[inline(always)] + fn to_op( + &self, + _ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(*self) + } + + #[inline(always)] + fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self { + mplace.into() + } + + #[inline(always)] + fn project_downcast( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self> { + ecx.operand_downcast(self, variant) + } + + #[inline(always)] + fn project_field( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self> { + ecx.operand_field(self, field) + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> + for MPlaceTy<'tcx, M::PointerTag> +{ + #[inline(always)] + fn layout(&self) -> TyAndLayout<'tcx> { + self.layout + } + + #[inline(always)] + fn to_op( + &self, + _ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok((*self).into()) + } + + #[inline(always)] + fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self { + mplace + } + + #[inline(always)] + fn project_downcast( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self> { + ecx.mplace_downcast(self, variant) + } + + #[inline(always)] + fn project_field( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self> { + ecx.mplace_field(self, field) + } +} + +macro_rules! make_value_visitor { + ($visitor_trait_name:ident, $($mutability:ident)?) => { + // How to traverse a value and what to do when we are at the leaves. + pub trait $visitor_trait_name<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { + type V: Value<'mir, 'tcx, M>; + + /// The visitor must have an `InterpCx` in it. + fn ecx(&$($mutability)? self) + -> &$($mutability)? InterpCx<'mir, 'tcx, M>; + + /// `read_discriminant` can be hooked for better error messages. + #[inline(always)] + fn read_discriminant( + &mut self, + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, VariantIdx> { + Ok(self.ecx().read_discriminant(op)?.1) + } + + // Recursive actions, ready to be overloaded. + /// Visits the given value, dispatching as appropriate to more specialized visitors. + #[inline(always)] + fn visit_value(&mut self, v: &Self::V) -> InterpResult<'tcx> + { + self.walk_value(v) + } + /// Visits the given value as a union. No automatic recursion can happen here. + #[inline(always)] + fn visit_union(&mut self, _v: &Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx> + { + Ok(()) + } + /// Visits this value as an aggregate, you are getting an iterator yielding + /// all the fields (still in an `InterpResult`, you have to do error handling yourself). + /// Recurses into the fields. + #[inline(always)] + fn visit_aggregate( + &mut self, + v: &Self::V, + fields: impl Iterator>, + ) -> InterpResult<'tcx> { + self.walk_aggregate(v, fields) + } + + /// Called each time we recurse down to a field of a "product-like" aggregate + /// (structs, tuples, arrays and the like, but not enums), passing in old (outer) + /// and new (inner) value. + /// This gives the visitor the chance to track the stack of nested fields that + /// we are descending through. + #[inline(always)] + fn visit_field( + &mut self, + _old_val: &Self::V, + _field: usize, + new_val: &Self::V, + ) -> InterpResult<'tcx> { + self.visit_value(new_val) + } + /// Called when recursing into an enum variant. + /// This gives the visitor the chance to track the stack of nested fields that + /// we are descending through. + #[inline(always)] + fn visit_variant( + &mut self, + _old_val: &Self::V, + _variant: VariantIdx, + new_val: &Self::V, + ) -> InterpResult<'tcx> { + self.visit_value(new_val) + } + + // Default recursors. Not meant to be overloaded. + fn walk_aggregate( + &mut self, + v: &Self::V, + fields: impl Iterator>, + ) -> InterpResult<'tcx> { + // Now iterate over it. + for (idx, field_val) in fields.enumerate() { + self.visit_field(v, idx, &field_val?)?; + } + Ok(()) + } + fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx> + { + trace!("walk_value: type: {}", v.layout().ty); + + // Special treatment for special types, where the (static) layout is not sufficient. + match *v.layout().ty.kind() { + // If it is a trait object, switch to the real type that was used to create it. + ty::Dynamic(..) => { + // immediate trait objects are not a thing + let op = v.to_op(self.ecx())?; + let dest = op.assert_mem_place(); + let inner = self.ecx().unpack_dyn_trait(&dest)?.1; + trace!("walk_value: dyn object layout: {:#?}", inner.layout); + // recurse with the inner type + return self.visit_field(&v, 0, &Value::from_mem_place(inner)); + }, + // Slices do not need special handling here: they have `Array` field + // placement with length 0, so we enter the `Array` case below which + // indirectly uses the metadata to determine the actual length. + _ => {}, + }; + + // Visit the fields of this value. + match v.layout().fields { + FieldsShape::Primitive => {}, + FieldsShape::Union(fields) => { + self.visit_union(v, fields)?; + }, + FieldsShape::Arbitrary { ref offsets, .. } => { + // FIXME: We collect in a vec because otherwise there are lifetime + // errors: Projecting to a field needs access to `ecx`. + let fields: Vec> = + (0..offsets.len()).map(|i| { + v.project_field(self.ecx(), i) + }) + .collect(); + self.visit_aggregate(v, fields.into_iter())?; + }, + FieldsShape::Array { .. } => { + // Let's get an mplace first. + let op = v.to_op(self.ecx())?; + let mplace = op.assert_mem_place(); + // Now we can go over all the fields. + // This uses the *run-time length*, i.e., if we are a slice, + // the dynamic info from the metadata is used. + let iter = self.ecx().mplace_array_fields(&mplace)? + .map(|f| f.and_then(|f| { + Ok(Value::from_mem_place(f)) + })); + self.visit_aggregate(v, iter)?; + } + } + + match v.layout().variants { + // If this is a multi-variant layout, find the right variant and proceed + // with *its* fields. + Variants::Multiple { .. } => { + let op = v.to_op(self.ecx())?; + let idx = self.read_discriminant(&op)?; + let inner = v.project_downcast(self.ecx(), idx)?; + trace!("walk_value: variant layout: {:#?}", inner.layout()); + // recurse with the inner type + self.visit_variant(v, idx, &inner) + } + // For single-variant layouts, we already did anything there is to do. + Variants::Single { .. } => Ok(()) + } + } + } + } +} + +make_value_visitor!(ValueVisitor,); +make_value_visitor!(MutValueVisitor, mut); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,56 @@ +/*! + +Rust MIR: a lowered representation of Rust. + +*/ + +#![feature(assert_matches)] +#![feature(bool_to_option)] +#![feature(box_patterns)] +#![feature(control_flow_enum)] +#![feature(crate_visibility_modifier)] +#![feature(decl_macro)] +#![feature(exact_size_is_empty)] +#![feature(in_band_lifetimes)] +#![feature(iter_zip)] +#![feature(map_try_insert)] +#![feature(min_specialization)] +#![feature(slice_ptr_get)] +#![feature(option_get_or_insert_default)] +#![feature(never_type)] +#![feature(trait_alias)] +#![feature(trusted_len)] +#![feature(trusted_step)] +#![feature(try_blocks)] +#![recursion_limit = "256"] + +#[macro_use] +extern crate tracing; +#[macro_use] +extern crate rustc_middle; + +pub mod const_eval; +pub mod interpret; +pub mod transform; +pub mod util; + +use rustc_middle::ty::query::Providers; + +pub fn provide(providers: &mut Providers) { + const_eval::provide(providers); + providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; + providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; + providers.const_caller_location = const_eval::const_caller_location; + providers.destructure_const = |tcx, param_env_and_value| { + let (param_env, value) = param_env_and_value.into_parts(); + const_eval::destructure_const(tcx, param_env, value) + }; + providers.const_to_valtree = |tcx, param_env_and_value| { + let (param_env, raw) = param_env_and_value.into_parts(); + const_eval::const_to_valtree(tcx, param_env, raw) + }; + providers.deref_const = |tcx, param_env_and_value| { + let (param_env, value) = param_env_and_value.into_parts(); + const_eval::deref_const(tcx, param_env, value) + }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/check.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/check.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/check.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/check.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1132 @@ +//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. + +use rustc_errors::{Applicability, Diagnostic, ErrorReported}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, HirId, LangItem}; +use rustc_index::bit_set::BitSet; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; +use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::cast::CastTy; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; +use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; +use rustc_middle::ty::{Binder, TraitPredicate, TraitRef}; +use rustc_mir_dataflow::impls::MaybeMutBorrowedLocals; +use rustc_mir_dataflow::{self, Analysis}; +use rustc_span::{sym, Span, Symbol}; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine}; + +use std::mem; +use std::ops::Deref; + +use super::ops::{self, NonConstOp, Status}; +use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop}; +use super::resolver::FlowSensitiveAnalysis; +use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif}; +use crate::const_eval::is_unstable_const_fn; + +// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated +// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals` +// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`. +type IndirectlyMutableResults<'mir, 'tcx> = + rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>; + +type QualifResults<'mir, 'tcx, Q> = + rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; + +#[derive(Default)] +pub struct Qualifs<'mir, 'tcx> { + has_mut_interior: Option>, + needs_drop: Option>, + indirectly_mutable: Option>, +} + +impl Qualifs<'mir, 'tcx> { + pub fn indirectly_mutable( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + local: Local, + location: Location, + ) -> bool { + let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| { + let ConstCx { tcx, body, param_env, .. } = *ccx; + + // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not + // allowed in a const. + // + // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this + // without breaking stable code? + MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env) + .unsound_ignore_borrow_on_drop() + .into_engine(tcx, &body) + .pass_name("const_qualification") + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + indirectly_mutable.seek_before_primary_effect(location); + indirectly_mutable.get().contains(local) + } + + /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. + /// + /// Only updates the cursor if absolutely necessary + pub fn needs_drop( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + local: Local, + location: Location, + ) -> bool { + let ty = ccx.body.local_decls[local].ty; + if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) { + return false; + } + + let needs_drop = self.needs_drop.get_or_insert_with(|| { + let ConstCx { tcx, body, .. } = *ccx; + + FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) + .into_engine(tcx, &body) + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + needs_drop.seek_before_primary_effect(location); + needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location) + } + + /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. + /// + /// Only updates the cursor if absolutely necessary. + pub fn has_mut_interior( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + local: Local, + location: Location, + ) -> bool { + let ty = ccx.body.local_decls[local].ty; + if !HasMutInterior::in_any_value_of_ty(ccx, ty) { + return false; + } + + let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { + let ConstCx { tcx, body, .. } = *ccx; + + FlowSensitiveAnalysis::new(HasMutInterior, ccx) + .into_engine(tcx, &body) + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + has_mut_interior.seek_before_primary_effect(location); + has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location) + } + + fn in_return_place( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + error_occured: Option, + ) -> ConstQualifs { + // Find the `Return` terminator if one exists. + // + // If no `Return` terminator exists, this MIR is divergent. Just return the conservative + // qualifs for the return type. + let return_block = ccx + .body + .basic_blocks() + .iter_enumerated() + .find(|(_, block)| match block.terminator().kind { + TerminatorKind::Return => true, + _ => false, + }) + .map(|(bb, _)| bb); + + let return_block = match return_block { + None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured), + Some(bb) => bb, + }; + + let return_loc = ccx.body.terminator_loc(return_block); + + let custom_eq = match ccx.const_kind() { + // We don't care whether a `const fn` returns a value that is not structurally + // matchable. Functions calls are opaque and always use type-based qualification, so + // this value should never be used. + hir::ConstContext::ConstFn => true, + + // If we know that all values of the return type are structurally matchable, there's no + // need to run dataflow. + _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false, + + hir::ConstContext::Const | hir::ConstContext::Static(_) => { + let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) + .into_engine(ccx.tcx, &ccx.body) + .iterate_to_fixpoint() + .into_results_cursor(&ccx.body); + + cursor.seek_after_primary_effect(return_loc); + cursor.contains(RETURN_PLACE) + } + }; + + ConstQualifs { + needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), + has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), + custom_eq, + error_occured, + } + } +} + +pub struct Checker<'mir, 'tcx> { + ccx: &'mir ConstCx<'mir, 'tcx>, + qualifs: Qualifs<'mir, 'tcx>, + + /// The span of the current statement. + span: Span, + + /// A set that stores for each local whether it has a `StorageDead` for it somewhere. + local_has_storage_dead: Option>, + + error_emitted: Option, + secondary_errors: Vec, +} + +impl Deref for Checker<'mir, 'tcx> { + type Target = ConstCx<'mir, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.ccx + } +} + +impl Checker<'mir, 'tcx> { + pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { + Checker { + span: ccx.body.span, + ccx, + qualifs: Default::default(), + local_has_storage_dead: None, + error_emitted: None, + secondary_errors: Vec::new(), + } + } + + pub fn check_body(&mut self) { + let ConstCx { tcx, body, .. } = *self.ccx; + let def_id = self.ccx.def_id(); + + // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's + // no need to emit duplicate errors here. + if is_async_fn(self.ccx) || body.generator.is_some() { + tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`"); + return; + } + + // The local type and predicate checks are not free and only relevant for `const fn`s. + if self.const_kind() == hir::ConstContext::ConstFn { + // Prevent const trait methods from being annotated as `stable`. + // FIXME: Do this as part of stability checking. + if self.is_const_stable_const_fn() { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { + self.ccx + .tcx + .sess + .struct_span_err(self.span, "trait methods cannot be stable const fn") + .emit(); + } + } + + self.check_item_predicates(); + + for (idx, local) in body.local_decls.iter_enumerated() { + // Handle the return place below. + if idx == RETURN_PLACE || local.internal { + continue; + } + + self.span = local.source_info.span; + self.check_local_or_return_ty(local.ty, idx); + } + + // impl trait is gone in MIR, so check the return type of a const fn by its signature + // instead of the type of the return place. + self.span = body.local_decls[RETURN_PLACE].source_info.span; + let return_ty = tcx.fn_sig(def_id).output(); + self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); + } + + if !tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) { + self.visit_body(&body); + } + + // Ensure that the end result is `Sync` in a non-thread local `static`. + let should_check_for_sync = self.const_kind() + == hir::ConstContext::Static(hir::Mutability::Not) + && !tcx.is_thread_local_static(def_id.to_def_id()); + + if should_check_for_sync { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + check_return_ty_is_sync(tcx, &body, hir_id); + } + + // If we got through const-checking without emitting any "primary" errors, emit any + // "secondary" errors if they occurred. + let secondary_errors = mem::take(&mut self.secondary_errors); + if self.error_emitted.is_none() { + for error in secondary_errors { + self.tcx.sess.diagnostic().emit_diagnostic(&error); + } + } else { + assert!(self.tcx.sess.has_errors()); + } + } + + fn local_has_storage_dead(&mut self, local: Local) -> bool { + let ccx = self.ccx; + self.local_has_storage_dead + .get_or_insert_with(|| { + struct StorageDeads { + locals: BitSet, + } + impl Visitor<'tcx> for StorageDeads { + fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) { + if let StatementKind::StorageDead(l) = stmt.kind { + self.locals.insert(l); + } + } + } + let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) }; + v.visit_body(ccx.body); + v.locals + }) + .contains(local) + } + + pub fn qualifs_in_return_place(&mut self) -> ConstQualifs { + self.qualifs.in_return_place(self.ccx, self.error_emitted) + } + + /// Emits an error if an expression cannot be evaluated in the current context. + pub fn check_op(&mut self, op: impl NonConstOp) { + self.check_op_spanned(op, self.span); + } + + /// Emits an error at the given `span` if an expression cannot be evaluated in the current + /// context. + pub fn check_op_spanned(&mut self, op: O, span: Span) { + let gate = match op.status_in_item(self.ccx) { + Status::Allowed => return, + + Status::Unstable(gate) if self.tcx.features().enabled(gate) => { + let unstable_in_stable = self.ccx.is_const_stable_const_fn() + && !super::rustc_allow_const_fn_unstable( + self.tcx, + self.def_id().to_def_id(), + gate, + ); + if unstable_in_stable { + emit_unstable_in_stable_error(self.ccx, span, gate); + } + + return; + } + + Status::Unstable(gate) => Some(gate), + Status::Forbidden => None, + }; + + if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + self.tcx.sess.miri_unleashed_feature(span, gate); + return; + } + + let mut err = op.build_error(self.ccx, span); + assert!(err.is_error()); + + match op.importance() { + ops::DiagnosticImportance::Primary => { + self.error_emitted = Some(ErrorReported); + err.emit(); + } + + ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors), + } + } + + fn check_static(&mut self, def_id: DefId, span: Span) { + if self.tcx.is_thread_local_static(def_id) { + self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef"); + } + self.check_op_spanned(ops::StaticAccess, span) + } + + fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { + let kind = self.body.local_kind(local); + + for ty in ty.walk(self.tcx) { + let ty = match ty.unpack() { + GenericArgKind::Type(ty) => ty, + + // No constraints on lifetimes or constants, except potentially + // constants' types, but `walk` will get to them as well. + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + }; + + match *ty.kind() { + ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)), + ty::Opaque(..) => self.check_op(ops::ty::ImplTrait), + ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)), + + ty::Dynamic(preds, _) => { + for pred in preds.iter() { + match pred.skip_binder() { + ty::ExistentialPredicate::AutoTrait(_) + | ty::ExistentialPredicate::Projection(_) => { + self.check_op(ops::ty::DynTrait(kind)) + } + ty::ExistentialPredicate::Trait(trait_ref) => { + if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() { + self.check_op(ops::ty::DynTrait(kind)) + } + } + } + } + } + _ => {} + } + } + } + + fn check_item_predicates(&mut self) { + let ConstCx { tcx, .. } = *self.ccx; + + let mut current = self.def_id().to_def_id(); + loop { + let predicates = tcx.predicates_of(current); + for (predicate, _) in predicates.predicates { + match predicate.kind().skip_binder() { + ty::PredicateKind::RegionOutlives(_) + | ty::PredicateKind::TypeOutlives(_) + | ty::PredicateKind::WellFormed(_) + | ty::PredicateKind::Projection(_) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, + ty::PredicateKind::ObjectSafe(_) => { + bug!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateKind::ClosureKind(..) => { + bug!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => { + bug!("subtype/coerce predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Trait(pred) => { + if Some(pred.def_id()) == tcx.lang_items().sized_trait() { + continue; + } + match pred.self_ty().kind() { + ty::Param(p) => { + let generics = tcx.generics_of(current); + let def = generics.type_param(p, tcx); + let span = tcx.def_span(def.def_id); + + // These are part of the function signature, so treat them like + // arguments when determining importance. + let kind = LocalKind::Arg; + + self.check_op_spanned(ops::ty::TraitBound(kind), span); + } + // other kinds of bounds are either tautologies + // or cause errors in other passes + _ => continue, + } + } + } + } + match predicates.parent { + Some(parent) => current = parent, + None => break, + } + } + } + + fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) { + match self.const_kind() { + // In a const fn all borrows are transient or point to the places given via + // references in the arguments (so we already checked them with + // TransientMutBorrow/MutBorrow as appropriate). + // The borrow checker guarantees that no new non-transient borrows are created. + // NOTE: Once we have heap allocations during CTFE we need to figure out + // how to prevent `const fn` to create long-lived allocations that point + // to mutable memory. + hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)), + _ => { + // Locals with StorageDead do not live beyond the evaluation and can + // thus safely be borrowed without being able to be leaked to the final + // value of the constant. + if self.local_has_storage_dead(local) { + self.check_op(ops::TransientMutBorrow(kind)); + } else { + self.check_op(ops::MutBorrow(kind)); + } + } + } + } +} + +impl Visitor<'tcx> for Checker<'mir, 'tcx> { + fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) { + trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup); + + // We don't const-check basic blocks on the cleanup path since we never unwind during + // const-eval: a panic causes an immediate compile error. In other words, cleanup blocks + // are unreachable during const-eval. + // + // We can't be more conservative (e.g., by const-checking cleanup blocks anyways) because + // locals that would never be dropped during normal execution are sometimes dropped during + // unwinding, which means backwards-incompatible live-drop errors. + if block.is_cleanup { + return; + } + + self.super_basic_block_data(bb, block); + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); + + // Special-case reborrows to be more like a copy of a reference. + match *rvalue { + Rvalue::Ref(_, kind, place) => { + if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { + let ctx = match kind { + BorrowKind::Shared => { + PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) + } + BorrowKind::Shallow => { + PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) + } + BorrowKind::Unique => { + PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) + } + BorrowKind::Mut { .. } => { + PlaceContext::MutatingUse(MutatingUseContext::Borrow) + } + }; + self.visit_local(&reborrowed_place_ref.local, ctx, location); + self.visit_projection(reborrowed_place_ref, ctx, location); + return; + } + } + Rvalue::AddressOf(mutbl, place) => { + if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { + let ctx = match mutbl { + Mutability::Not => { + PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) + } + Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), + }; + self.visit_local(&reborrowed_place_ref.local, ctx, location); + self.visit_projection(reborrowed_place_ref, ctx, location); + return; + } + } + _ => {} + } + + self.super_rvalue(rvalue, location); + + match *rvalue { + Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess), + + Rvalue::Use(_) + | Rvalue::Repeat(..) + | Rvalue::Discriminant(..) + | Rvalue::Len(_) + | Rvalue::Aggregate(..) => {} + + Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place) + | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => { + let ty = place.ty(self.body, self.tcx).ty; + let is_allowed = match ty.kind() { + // Inside a `static mut`, `&mut [...]` is allowed. + ty::Array(..) | ty::Slice(_) + if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) => + { + true + } + + // FIXME(ecstaticmorse): We could allow `&mut []` inside a const context given + // that this is merely a ZST and it is already eligible for promotion. + // This may require an RFC? + /* + ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0) + => true, + */ + _ => false, + }; + + if !is_allowed { + if let BorrowKind::Mut { .. } = kind { + self.check_mut_borrow(place.local, hir::BorrowKind::Ref) + } else { + self.check_op(ops::CellBorrow); + } + } + } + + Rvalue::AddressOf(Mutability::Mut, ref place) => { + self.check_mut_borrow(place.local, hir::BorrowKind::Raw) + } + + Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place) + | Rvalue::AddressOf(Mutability::Not, ref place) => { + let borrowed_place_has_mut_interior = qualifs::in_place::( + &self.ccx, + &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location), + place.as_ref(), + ); + + if borrowed_place_has_mut_interior { + match self.const_kind() { + // In a const fn all borrows are transient or point to the places given via + // references in the arguments (so we already checked them with + // TransientCellBorrow/CellBorrow as appropriate). + // The borrow checker guarantees that no new non-transient borrows are created. + // NOTE: Once we have heap allocations during CTFE we need to figure out + // how to prevent `const fn` to create long-lived allocations that point + // to (interior) mutable memory. + hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow), + _ => { + // Locals with StorageDead are definitely not part of the final constant value, and + // it is thus inherently safe to permit such locals to have their + // address taken as we can't end up with a reference to them in the + // final value. + // Note: This is only sound if every local that has a `StorageDead` has a + // `StorageDead` in every control flow path leading to a `return` terminator. + if self.local_has_storage_dead(place.local) { + self.check_op(ops::TransientCellBorrow); + } else { + self.check_op(ops::CellBorrow); + } + } + } + } + } + + Rvalue::Cast( + CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), + _, + _, + ) => {} + + Rvalue::Cast( + CastKind::Pointer( + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer, + ), + _, + _, + ) => self.check_op(ops::FnPtrCast), + + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => { + // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur + // in the type of any local, which also excludes casts). + } + + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { + let operand_ty = operand.ty(self.body, self.tcx); + let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); + let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); + + if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + self.check_op(ops::RawPtrToIntCast); + } + } + + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} + Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), + Rvalue::ShallowInitBox(_, _) => {} + + Rvalue::UnaryOp(_, ref operand) => { + let ty = operand.ty(self.body, self.tcx); + if is_int_bool_or_char(ty) { + // Int, bool, and char operations are fine. + } else if ty.is_floating_point() { + self.check_op(ops::FloatingPointOp); + } else { + span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); + } + } + + Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) + | Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => { + let lhs_ty = lhs.ty(self.body, self.tcx); + let rhs_ty = rhs.ty(self.body, self.tcx); + + if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) { + // Int, bool, and char operations are fine. + } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { + assert_eq!(lhs_ty, rhs_ty); + assert!( + op == BinOp::Eq + || op == BinOp::Ne + || op == BinOp::Le + || op == BinOp::Lt + || op == BinOp::Ge + || op == BinOp::Gt + || op == BinOp::Offset + ); + + self.check_op(ops::RawPtrComparison); + } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { + self.check_op(ops::FloatingPointOp); + } else { + span_bug!( + self.span, + "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}", + lhs_ty, + rhs_ty + ); + } + } + } + } + + fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { + self.super_operand(op, location); + if let Operand::Constant(c) = op { + if let Some(def_id) = c.check_static_ptr(self.tcx) { + self.check_static(def_id, self.span); + } + } + } + fn visit_projection_elem( + &mut self, + place_local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + trace!( + "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \ + context={:?} location={:?}", + place_local, + proj_base, + elem, + context, + location, + ); + + self.super_projection_elem(place_local, proj_base, elem, context, location); + + match elem { + ProjectionElem::Deref => { + let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty; + if let ty::RawPtr(_) = base_ty.kind() { + if proj_base.is_empty() { + let decl = &self.body.local_decls[place_local]; + if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { + let span = decl.source_info.span; + self.check_static(def_id, span); + return; + } + } + self.check_op(ops::RawPtrDeref); + } + + if context.is_mutating_use() { + self.check_op(ops::MutDeref); + } + } + + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Downcast(..) + | ProjectionElem::Subslice { .. } + | ProjectionElem::Field(..) + | ProjectionElem::Index(_) => {} + } + } + + fn visit_source_info(&mut self, source_info: &SourceInfo) { + trace!("visit_source_info: source_info={:?}", source_info); + self.span = source_info.span; + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + trace!("visit_statement: statement={:?} location={:?}", statement, location); + + self.super_statement(statement, location); + + match statement.kind { + StatementKind::LlvmInlineAsm { .. } => { + self.check_op(ops::InlineAsm); + } + + StatementKind::Assign(..) + | StatementKind::SetDiscriminant { .. } + | StatementKind::FakeRead(..) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Retag { .. } + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::CopyNonOverlapping(..) + | StatementKind::Nop => {} + } + } + + #[instrument(level = "debug", skip(self))] + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + use rustc_target::spec::abi::Abi::RustIntrinsic; + + self.super_terminator(terminator, location); + + match &terminator.kind { + TerminatorKind::Call { func, args, .. } => { + let ConstCx { tcx, body, param_env, .. } = *self.ccx; + let caller = self.def_id().to_def_id(); + + let fn_ty = func.ty(body, tcx); + + let (mut callee, mut substs) = match *fn_ty.kind() { + ty::FnDef(def_id, substs) => (def_id, substs), + + ty::FnPtr(_) => { + self.check_op(ops::FnCallIndirect); + return; + } + _ => { + span_bug!(terminator.source_info.span, "invalid callee of type {:?}", fn_ty) + } + }; + + let mut nonconst_call_permission = false; + + // Attempting to call a trait method? + if let Some(trait_id) = tcx.trait_of_item(callee) { + trace!("attempting to call a trait method"); + if !self.tcx.features().const_trait_impl { + self.check_op(ops::FnCallNonConst); + return; + } + + let trait_ref = TraitRef::from_method(tcx, trait_id, substs); + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + Binder::dummy(TraitPredicate { + trait_ref, + constness: ty::BoundConstness::ConstIfConst, + }), + ); + + let implsrc = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = + SelectionContext::with_constness(&infcx, hir::Constness::Const); + selcx.select(&obligation) + }); + + match implsrc { + Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => { + debug!( + "const_trait_impl: provided {:?} via where-clause in {:?}", + trait_ref, param_env + ); + return; + } + Ok(Some(ImplSource::UserDefined(data))) => { + let callee_name = tcx.item_name(callee); + if let Some(&did) = tcx + .associated_item_def_ids(data.impl_def_id) + .iter() + .find(|did| tcx.item_name(**did) == callee_name) + { + // using internal substs is ok here, since this is only + // used for the `resolve` call below + substs = InternalSubsts::identity_for_item(tcx, did); + callee = did; + } + } + _ if !tcx.is_const_fn_raw(callee) => { + // At this point, it is only legal when the caller is marked with + // #[default_method_body_is_const], and the callee is in the same + // trait. + let callee_trait = tcx.trait_of_item(callee); + if callee_trait.is_some() { + if tcx.has_attr(caller, sym::default_method_body_is_const) { + if tcx.trait_of_item(caller) == callee_trait { + nonconst_call_permission = true; + } + } + } + + if !nonconst_call_permission { + self.check_op(ops::FnCallNonConst); + return; + } + } + _ => {} + } + + // Resolve a trait method call to its concrete implementation, which may be in a + // `const` trait impl. + let instance = Instance::resolve(tcx, param_env, callee, substs); + debug!("Resolving ({:?}) -> {:?}", callee, instance); + if let Ok(Some(func)) = instance { + if let InstanceDef::Item(def) = func.def { + callee = def.did; + } + } + } + + // At this point, we are calling a function, `callee`, whose `DefId` is known... + if is_lang_special_const_fn(tcx, callee) { + // `begin_panic` and `panic_display` are generic functions that accept + // types other than str. Check to enforce that only str can be used in + // const-eval. + + // const-eval of the `begin_panic` fn assumes the argument is `&str` + if Some(callee) == tcx.lang_items().begin_panic_fn() { + match args[0].ty(&self.ccx.body.local_decls, tcx).kind() { + ty::Ref(_, ty, _) if ty.is_str() => (), + _ => self.check_op(ops::PanicNonStr), + } + } + + // const-eval of the `panic_display` fn assumes the argument is `&&str` + if Some(callee) == tcx.lang_items().panic_display() { + match args[0].ty(&self.ccx.body.local_decls, tcx).kind() { + ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) => + {} + _ => self.check_op(ops::PanicNonStr), + } + } + + if is_lang_panic_fn(tcx, callee) { + // run stability check on non-panic special const fns. + return; + } + } + + if Some(callee) == tcx.lang_items().exchange_malloc_fn() { + self.check_op(ops::HeapAllocation); + return; + } + + // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`. + let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn(); + if is_async_block { + let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block); + self.check_op(ops::Generator(kind)); + return; + } + + let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic; + + if !tcx.is_const_fn_raw(callee) { + if tcx.trait_of_item(callee).is_some() { + if tcx.has_attr(callee, sym::default_method_body_is_const) { + // To get to here we must have already found a const impl for the + // trait, but for it to still be non-const can be that the impl is + // using default method bodies. + nonconst_call_permission = true; + } + } + + if !nonconst_call_permission { + self.check_op(ops::FnCallNonConst); + return; + } + } + + // If the `const fn` we are trying to call is not const-stable, ensure that we have + // the proper feature gate enabled. + if let Some(gate) = is_unstable_const_fn(tcx, callee) { + trace!(?gate, "calling unstable const fn"); + if self.span.allows_unstable(gate) { + return; + } + + // Calling an unstable function *always* requires that the corresponding gate + // be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`. + if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) { + self.check_op(ops::FnCallUnstable(callee, Some(gate))); + return; + } + + // If this crate is not using stability attributes, or the caller is not claiming to be a + // stable `const fn`, that is all that is required. + if !self.ccx.is_const_stable_const_fn() { + trace!("crate not using stability attributes or caller not stably const"); + return; + } + + // Otherwise, we are something const-stable calling a const-unstable fn. + + if super::rustc_allow_const_fn_unstable(tcx, caller, gate) { + trace!("rustc_allow_const_fn_unstable gate active"); + return; + } + + self.check_op(ops::FnCallUnstable(callee, Some(gate))); + return; + } + + // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that + // have no `rustc_const_stable` attributes to be const-unstable as well. This + // should be fixed later. + let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() + && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable()); + if callee_is_unstable_unmarked { + trace!("callee_is_unstable_unmarked"); + // We do not use `const` modifiers for intrinsic "functions", as intrinsics are + // `extern` funtions, and these have no way to get marked `const`. So instead we + // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const` + if self.ccx.is_const_stable_const_fn() || is_intrinsic { + self.check_op(ops::FnCallUnstable(callee, None)); + return; + } + } + trace!("permitting call"); + } + + // Forbid all `Drop` terminators unless the place being dropped is a local with no + // projections that cannot be `NeedsDrop`. + TerminatorKind::Drop { place: dropped_place, .. } + | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { + // If we are checking live drops after drop-elaboration, don't emit duplicate + // errors here. + if super::post_drop_elaboration::checking_enabled(self.ccx) { + return; + } + + let mut err_span = self.span; + + let ty_needs_non_const_drop = qualifs::NeedsNonConstDrop::in_any_value_of_ty( + self.ccx, + dropped_place.ty(self.body, self.tcx).ty, + ); + + if !ty_needs_non_const_drop { + return; + } + + let needs_drop = if let Some(local) = dropped_place.as_local() { + // Use the span where the local was declared as the span of the drop error. + err_span = self.body.local_decls[local].source_info.span; + self.qualifs.needs_drop(self.ccx, local, location) + } else { + true + }; + + if needs_drop { + self.check_op_spanned( + ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, + err_span, + ); + } + } + + TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), + + TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { + self.check_op(ops::Generator(hir::GeneratorKind::Gen)) + } + + TerminatorKind::Abort => { + // Cleanup blocks are skipped for const checking (see `visit_basic_block_data`). + span_bug!(self.span, "`Abort` terminator outside of cleanup block") + } + + TerminatorKind::Assert { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable => {} + } + } +} + +fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) { + let ty = body.return_ty(); + tcx.infer_ctxt().enter(|infcx| { + let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic); + let mut fulfillment_cx = traits::FulfillmentContext::new(); + let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span)); + fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause); + if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(&err, None, false); + } + }); +} + +fn place_as_reborrow( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + place: Place<'tcx>, +) -> Option> { + match place.as_ref().last_projection() { + Some((place_base, ProjectionElem::Deref)) => { + // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` + // that points to the allocation for the static. Don't treat these as reborrows. + if body.local_decls[place_base.local].is_ref_to_static() { + None + } else { + // Ensure the type being derefed is a reference and not a raw pointer. + // This is sufficient to prevent an access to a `static mut` from being marked as a + // reborrow, even if the check above were to disappear. + let inner_ty = place_base.ty(body, tcx).ty; + + if let ty::Ref(..) = inner_ty.kind() { + return Some(place_base); + } else { + return None; + } + } + } + _ => None, + } +} + +fn is_int_bool_or_char(ty: Ty<'_>) -> bool { + ty.is_bool() || ty.is_integral() || ty.is_char() +} + +fn is_async_fn(ccx: &ConstCx<'_, '_>) -> bool { + ccx.fn_sig().map_or(false, |sig| sig.header.asyncness == hir::IsAsync::Async) +} + +fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) { + let attr_span = ccx.fn_sig().map_or(ccx.body.span, |sig| sig.span.shrink_to_lo()); + + ccx.tcx + .sess + .struct_span_err( + span, + &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()), + ) + .span_suggestion( + attr_span, + "if it is not part of the public API, make this function unstably const", + concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(), + Applicability::HasPlaceholders, + ) + .span_suggestion( + attr_span, + "otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks", + format!("#[rustc_allow_const_fn_unstable({})]\n", gate), + Applicability::MaybeIncorrect, + ) + .emit(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,142 @@ +//! Check the bodies of `const`s, `static`s and `const fn`s for illegal operations. +//! +//! This module will eventually replace the parts of `qualify_consts.rs` that check whether a local +//! has interior mutability or needs to be dropped, as well as the visitor that emits errors when +//! it finds operations that are invalid in a certain context. + +use rustc_attr as attr; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::mir; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{sym, Symbol}; + +pub use self::qualifs::Qualif; + +pub mod check; +mod ops; +pub mod post_drop_elaboration; +pub mod qualifs; +mod resolver; + +/// Information about the item currently being const-checked, as well as a reference to the global +/// context. +pub struct ConstCx<'mir, 'tcx> { + pub body: &'mir mir::Body<'tcx>, + pub tcx: TyCtxt<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, + pub const_kind: Option, +} + +impl ConstCx<'mir, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self { + let def_id = body.source.def_id().expect_local(); + let param_env = tcx.param_env(def_id); + Self::new_with_param_env(tcx, body, param_env) + } + + pub fn new_with_param_env( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Self { + let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local()); + ConstCx { body, tcx, param_env, const_kind } + } + + pub fn def_id(&self) -> LocalDefId { + self.body.source.def_id().expect_local() + } + + /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.). + /// + /// Panics if this `Item` is not const. + pub fn const_kind(&self) -> hir::ConstContext { + self.const_kind.expect("`const_kind` must not be called on a non-const fn") + } + + pub fn is_const_stable_const_fn(&self) -> bool { + self.const_kind == Some(hir::ConstContext::ConstFn) + && self.tcx.features().staged_api + && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id()) + } + + /// Returns the function signature of the item being const-checked if it is a `fn` or `const fn`. + pub fn fn_sig(&self) -> Option<&'tcx hir::FnSig<'tcx>> { + // Get this from the HIR map instead of a query to avoid cycle errors. + // + // FIXME: Is this still an issue? + let hir_map = self.tcx.hir(); + let hir_id = hir_map.local_def_id_to_hir_id(self.def_id()); + hir_map.fn_sig_by_hir_id(hir_id) + } +} + +/// Returns `true` if this `DefId` points to one of the official `panic` lang items. +pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + Some(def_id) == tcx.lang_items().panic_fn() + || Some(def_id) == tcx.lang_items().panic_str() + || Some(def_id) == tcx.lang_items().panic_display() + || Some(def_id) == tcx.lang_items().begin_panic_fn() + || Some(def_id) == tcx.lang_items().panic_fmt() + || Some(def_id) == tcx.lang_items().begin_panic_fmt() +} + +/// Returns `true` if this `DefId` points to one of the lang items that will be handled differently +/// in const_eval. +pub fn is_lang_special_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + // We can allow calls to these functions because `hook_special_const_fn` in + // `const_eval/machine.rs` ensures the calls are handled specially. + // Keep in sync with what that function handles! + is_lang_panic_fn(tcx, def_id) || Some(def_id) == tcx.lang_items().const_eval_select() +} + +pub fn rustc_allow_const_fn_unstable( + tcx: TyCtxt<'tcx>, + def_id: DefId, + feature_gate: Symbol, +) -> bool { + let attrs = tcx.get_attrs(def_id); + attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate) +} + +// Returns `true` if the given `const fn` is "const-stable". +// +// Panics if the given `DefId` does not refer to a `const fn`. +// +// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" +// functions can be called in a const-context by users of the stable compiler. "const-stable" +// functions are subject to more stringent restrictions than "const-unstable" functions: They +// cannot use unstable features and can only call other "const-stable" functions. +pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + use attr::{ConstStability, Stability, StabilityLevel}; + + // A default body marked const is not const-stable because const + // trait fns currently cannot be const-stable. We shouldn't + // restrict default bodies to only call const-stable functions. + if tcx.has_attr(def_id, sym::default_method_body_is_const) { + return false; + } + + // Const-stability is only relevant for `const fn`. + assert!(tcx.is_const_fn_raw(def_id)); + + // Functions with `#[rustc_const_unstable]` are const-unstable. + match tcx.lookup_const_stability(def_id) { + Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false, + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true, + None => {} + } + + // Functions with `#[unstable]` are const-unstable. + // + // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability + // attributes. `#[unstable]` should be irrelevant. + if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) = + tcx.lookup_stability(def_id) + { + return false; + } + + true +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/ops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/ops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/ops.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/ops.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,659 @@ +//! Concrete error types for all operations which may be invalid in a certain const context. + +use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::mir; +use rustc_session::parse::feature_err; +use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; + +use super::ConstCx; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Status { + Allowed, + Unstable(Symbol), + Forbidden, +} + +#[derive(Clone, Copy)] +pub enum DiagnosticImportance { + /// An operation that must be removed for const-checking to pass. + Primary, + + /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere. + Secondary, +} + +/// An operation that is not *always* allowed in a const context. +pub trait NonConstOp: std::fmt::Debug { + /// Returns an enum indicating whether this operation is allowed within the given item. + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Forbidden + } + + fn importance(&self) -> DiagnosticImportance { + DiagnosticImportance::Primary + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; +} + +#[derive(Debug)] +pub struct FloatingPointOp; +impl NonConstOp for FloatingPointOp { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_fn_floating_point_arithmetic) + } else { + Status::Allowed + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_floating_point_arithmetic, + span, + &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()), + ) + } +} + +/// A function call where the callee is a pointer. +#[derive(Debug)] +pub struct FnCallIndirect; +impl NonConstOp for FnCallIndirect { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn") + } +} + +/// A function call where the callee is not marked as `const`. +#[derive(Debug)] +pub struct FnCallNonConst; +impl NonConstOp for FnCallNonConst { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + ccx.tcx.sess, + span, + E0015, + "calls in {}s are limited to constant functions, \ + tuple structs and tuple variants", + ccx.const_kind(), + ) + } +} + +/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function. +/// +/// Contains the name of the feature that would allow the use of this function. +#[derive(Debug)] +pub struct FnCallUnstable(pub DefId, pub Option); + +impl NonConstOp for FnCallUnstable { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let FnCallUnstable(def_id, feature) = *self; + + let mut err = ccx.tcx.sess.struct_span_err( + span, + &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)), + ); + + if ccx.is_const_stable_const_fn() { + err.help("const-stable functions can only call other const-stable functions"); + } else if ccx.tcx.sess.is_nightly_build() { + if let Some(feature) = feature { + err.help(&format!( + "add `#![feature({})]` to the crate attributes to enable", + feature + )); + } + } + + err + } +} + +#[derive(Debug)] +pub struct FnPtrCast; +impl NonConstOp for FnPtrCast { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_fn_ptr_basics) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_fn_ptr_basics, + span, + &format!("function pointer casts are not allowed in {}s", ccx.const_kind()), + ) + } +} + +#[derive(Debug)] +pub struct Generator(pub hir::GeneratorKind); +impl NonConstOp for Generator { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { + Status::Unstable(sym::const_async_blocks) + } else { + Status::Forbidden + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); + if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { + feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg) + } else { + ccx.tcx.sess.struct_span_err(span, &msg) + } + } +} + +#[derive(Debug)] +pub struct HeapAllocation; +impl NonConstOp for HeapAllocation { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0010, + "allocations are not allowed in {}s", + ccx.const_kind() + ); + err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind())); + if ccx.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "The value of statics and constants must be known at compile time, \ + and they live for the entire lifetime of a program. Creating a boxed \ + value allocates memory on the heap at runtime, and therefore cannot \ + be done at compile time.", + ); + } + err + } +} + +#[derive(Debug)] +pub struct InlineAsm; +impl NonConstOp for InlineAsm { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + ccx.tcx.sess, + span, + E0015, + "inline assembly is not allowed in {}s", + ccx.const_kind() + ) + } +} + +#[derive(Debug)] +pub struct LiveDrop { + pub dropped_at: Option, +} +impl NonConstOp for LiveDrop { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0493, + "destructors cannot be evaluated at compile-time" + ); + err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); + if let Some(span) = self.dropped_at { + err.span_label(span, "value is dropped here"); + } + err + } +} + +#[derive(Debug)] +/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to +/// the final value of the constant. +pub struct TransientCellBorrow; +impl NonConstOp for TransientCellBorrow { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_refs_to_cell) + } + fn importance(&self) -> DiagnosticImportance { + // The cases that cannot possibly work will already emit a `CellBorrow`, so we should + // not additionally emit a feature gate error if activating the feature gate won't work. + DiagnosticImportance::Secondary + } + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_refs_to_cell, + span, + "cannot borrow here, since the borrowed element may contain interior mutability", + ) + } +} + +#[derive(Debug)] +/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to +/// the final value of the constant, and thus we cannot allow this (for now). We may allow +/// it in the future for static items. +pub struct CellBorrow; +impl NonConstOp for CellBorrow { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0492, + "{}s cannot refer to interior mutable data", + ccx.const_kind(), + ); + err.span_label( + span, + "this borrow of an interior mutable value may end up in the final value", + ); + if let hir::ConstContext::Static(_) = ccx.const_kind() { + err.help( + "to fix this, the value can be extracted to a separate \ + `static` item and then referenced", + ); + } + if ccx.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "A constant containing interior mutable data behind a reference can allow you + to modify that data. This would make multiple uses of a constant to be able to + see different values and allow circumventing the `Send` and `Sync` requirements + for shared mutable data, which is unsound.", + ); + } + err + } +} + +#[derive(Debug)] +/// This op is for `&mut` borrows in the trailing expression of a constant +/// which uses the "enclosing scopes rule" to leak its locals into anonymous +/// static or const items. +pub struct MutBorrow(pub hir::BorrowKind); + +impl NonConstOp for MutBorrow { + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Forbidden + } + + fn importance(&self) -> DiagnosticImportance { + // If there were primary errors (like non-const function calls), do not emit further + // errors about mutable references. + DiagnosticImportance::Secondary + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let raw = match self.0 { + hir::BorrowKind::Raw => "raw ", + hir::BorrowKind::Ref => "", + }; + + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0764, + "{}mutable references are not allowed in the final value of {}s", + raw, + ccx.const_kind(), + ); + + if ccx.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "References in statics and constants may only refer \ + to immutable values.\n\n\ + Statics are shared everywhere, and if they refer to \ + mutable data one might violate memory safety since \ + holding multiple mutable references to shared data \ + is not allowed.\n\n\ + If you really want global mutable state, try using \ + static mut or a global UnsafeCell.", + ); + } + err + } +} + +#[derive(Debug)] +pub struct TransientMutBorrow(pub hir::BorrowKind); + +impl NonConstOp for TransientMutBorrow { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let raw = match self.0 { + hir::BorrowKind::Raw => "raw ", + hir::BorrowKind::Ref => "", + }; + + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()), + ) + } +} + +#[derive(Debug)] +pub struct MutDeref; +impl NonConstOp for MutDeref { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) + } + + fn importance(&self) -> DiagnosticImportance { + // Usually a side-effect of a `TransientMutBorrow` somewhere. + DiagnosticImportance::Secondary + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("mutation through a reference is not allowed in {}s", ccx.const_kind()), + ) + } +} + +/// A call to a `panic()` lang item where the first argument is _not_ a `&str`. +#[derive(Debug)] +pub struct PanicNonStr; +impl NonConstOp for PanicNonStr { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + ccx.tcx.sess.struct_span_err( + span, + "argument to `panic!()` in a const context must have type `&str`", + ) + } +} + +/// Comparing raw pointers for equality. +/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on +/// allocation base addresses that are not known at compile-time. +#[derive(Debug)] +pub struct RawPtrComparison; +impl NonConstOp for RawPtrComparison { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = ccx + .tcx + .sess + .struct_span_err(span, "pointers cannot be reliably compared during const eval"); + err.note( + "see issue #53020 \ + for more information", + ); + err + } +} + +#[derive(Debug)] +pub struct RawPtrDeref; +impl NonConstOp for RawPtrDeref { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_deref) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_raw_ptr_deref, + span, + &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),), + ) + } +} + +/// Casting raw pointer or function pointer to an integer. +/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on +/// allocation base addresses that are not known at compile-time. +#[derive(Debug)] +pub struct RawPtrToIntCast; +impl NonConstOp for RawPtrToIntCast { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = ccx + .tcx + .sess + .struct_span_err(span, "pointers cannot be cast to integers during const eval"); + err.note("at compile-time, pointers do not have an integer value"); + err.note( + "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior", + ); + err + } +} + +/// An access to a (non-thread-local) `static`. +#[derive(Debug)] +pub struct StaticAccess; +impl NonConstOp for StaticAccess { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if let hir::ConstContext::Static(_) = ccx.const_kind() { + Status::Allowed + } else { + Status::Forbidden + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0013, + "{}s cannot refer to statics", + ccx.const_kind() + ); + err.help( + "consider extracting the value of the `static` to a `const`, and referring to that", + ); + if ccx.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "`static` and `const` variables can refer to other `const` variables. \ + A `const` variable, however, cannot refer to a `static` variable.", + ); + err.help("To fix this, the value can be extracted to a `const` and then used."); + } + err + } +} + +/// An access to a thread-local `static`. +#[derive(Debug)] +pub struct ThreadLocalAccess; +impl NonConstOp for ThreadLocalAccess { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + ccx.tcx.sess, + span, + E0625, + "thread-local statics cannot be \ + accessed at compile-time" + ) + } +} + +// Types that cannot appear in the signature or locals of a `const fn`. +pub mod ty { + use super::*; + + #[derive(Debug)] + pub struct MutRef(pub mir::LocalKind); + impl NonConstOp for MutRef { + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) + } + + fn importance(&self) -> DiagnosticImportance { + match self.0 { + mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { + DiagnosticImportance::Primary + } + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("mutable references are not allowed in {}s", ccx.const_kind()), + ) + } + } + + #[derive(Debug)] + pub struct FnPtr(pub mir::LocalKind); + impl NonConstOp for FnPtr { + fn importance(&self) -> DiagnosticImportance { + match self.0 { + mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { + DiagnosticImportance::Primary + } + } + } + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_fn_ptr_basics) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_fn_ptr_basics, + span, + &format!("function pointers cannot appear in {}s", ccx.const_kind()), + ) + } + } + + #[derive(Debug)] + pub struct ImplTrait; + impl NonConstOp for ImplTrait { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_impl_trait) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_impl_trait, + span, + &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()), + ) + } + } + + #[derive(Debug)] + pub struct TraitBound(pub mir::LocalKind); + impl NonConstOp for TraitBound { + fn importance(&self) -> DiagnosticImportance { + match self.0 { + mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { + DiagnosticImportance::Primary + } + } + } + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_trait_bound) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_trait_bound, + span, + "trait bounds other than `Sized` on const fn parameters are unstable", + ); + + match ccx.fn_sig() { + Some(fn_sig) if !fn_sig.span.contains(span) => { + err.span_label(fn_sig.span, "function declared as const here"); + } + _ => {} + } + + err + } + } + + #[derive(Debug)] + pub struct DynTrait(pub mir::LocalKind); + impl NonConstOp for DynTrait { + fn importance(&self) -> DiagnosticImportance { + match self.0 { + mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { + DiagnosticImportance::Primary + } + } + } + + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_trait_bound) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_trait_bound, + span, + "trait objects in const fn are unstable", + ); + + match ccx.fn_sig() { + Some(fn_sig) if !fn_sig.span.contains(span) => { + err.span_label(fn_sig.span, "function declared as const here"); + } + _ => {} + } + + err + } + } + + /// A trait bound with the `?const Trait` opt-out + #[derive(Debug)] + pub struct TraitBoundNotConst; + impl NonConstOp for TraitBoundNotConst { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_trait_bound_opt_out) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_trait_bound_opt_out, + span, + "`?const Trait` syntax is unstable", + ) + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,127 @@ +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{self, BasicBlock, Location}; +use rustc_middle::ty::TyCtxt; +use rustc_span::{symbol::sym, Span}; + +use super::check::Qualifs; +use super::ops::{self, NonConstOp}; +use super::qualifs::{NeedsNonConstDrop, Qualif}; +use super::ConstCx; + +/// Returns `true` if we should use the more precise live drop checker that runs after drop +/// elaboration. +pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { + // Const-stable functions must always use the stable live drop checker. + if ccx.is_const_stable_const_fn() { + return false; + } + + ccx.tcx.features().const_precise_live_drops +} + +/// Look for live drops in a const context. +/// +/// This is separate from the rest of the const checking logic because it must run after drop +/// elaboration. +pub fn check_live_drops(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { + let def_id = body.source.def_id().expect_local(); + let const_kind = tcx.hir().body_const_context(def_id); + if const_kind.is_none() { + return; + } + + if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) { + return; + } + + let ccx = ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def_id) }; + if !checking_enabled(&ccx) { + return; + } + + let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() }; + + visitor.visit_body(body); +} + +struct CheckLiveDrops<'mir, 'tcx> { + ccx: &'mir ConstCx<'mir, 'tcx>, + qualifs: Qualifs<'mir, 'tcx>, +} + +// So we can access `body` and `tcx`. +impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { + type Target = ConstCx<'mir, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.ccx + } +} + +impl CheckLiveDrops<'mir, 'tcx> { + fn check_live_drop(&self, span: Span) { + ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit(); + } +} + +impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> { + fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &mir::BasicBlockData<'tcx>) { + trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup); + + // Ignore drop terminators in cleanup blocks. + if block.is_cleanup { + return; + } + + self.super_basic_block_data(bb, block); + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); + + match &terminator.kind { + mir::TerminatorKind::Drop { place: dropped_place, .. } => { + let dropped_ty = dropped_place.ty(self.body, self.tcx).ty; + if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) { + // Instead of throwing a bug, we just return here. This is because we have to + // run custom `const Drop` impls. + return; + } + + if dropped_place.is_indirect() { + self.check_live_drop(terminator.source_info.span); + return; + } + + // Drop elaboration is not precise enough to accept code like + // `src/test/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option>` is + // initialized with `None` and never changed, it still emits drop glue. + // Hence we additionally check the qualifs here to allow more code to pass. + if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) { + // Use the span where the dropped local was declared for the error. + let span = self.body.local_decls[dropped_place.local].source_info.span; + self.check_live_drop(span); + } + } + + mir::TerminatorKind::DropAndReplace { .. } => span_bug!( + terminator.source_info.span, + "`DropAndReplace` should be removed by drop elaboration", + ), + + mir::TerminatorKind::Abort + | mir::TerminatorKind::Call { .. } + | mir::TerminatorKind::Assert { .. } + | mir::TerminatorKind::FalseEdge { .. } + | mir::TerminatorKind::FalseUnwind { .. } + | mir::TerminatorKind::GeneratorDrop + | mir::TerminatorKind::Goto { .. } + | mir::TerminatorKind::InlineAsm { .. } + | mir::TerminatorKind::Resume + | mir::TerminatorKind::Return + | mir::TerminatorKind::SwitchInt { .. } + | mir::TerminatorKind::Unreachable + | mir::TerminatorKind::Yield { .. } => {} + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,313 @@ +//! Structural const qualification. +//! +//! See the `Qualif` trait for more info. + +use rustc_errors::ErrorReported; +use rustc_hir as hir; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; +use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::{ + self, ImplSource, Obligation, ObligationCause, SelectionContext, +}; + +use super::ConstCx; + +pub fn in_any_value_of_ty( + cx: &ConstCx<'_, 'tcx>, + ty: Ty<'tcx>, + error_occured: Option, +) -> ConstQualifs { + ConstQualifs { + has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), + needs_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), + custom_eq: CustomEq::in_any_value_of_ty(cx, ty), + error_occured, + } +} + +/// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some +/// code for promotion or prevent it from evaluating at compile time. +/// +/// Normally, we would determine what qualifications apply to each type and error when an illegal +/// operation is performed on such a type. However, this was found to be too imprecise, especially +/// in the presence of `enum`s. If only a single variant of an enum has a certain qualification, we +/// needn't reject code unless it actually constructs and operates on the qualified variant. +/// +/// To accomplish this, const-checking and promotion use a value-based analysis (as opposed to a +/// type-based one). Qualifications propagate structurally across variables: If a local (or a +/// projection of a local) is assigned a qualified value, that local itself becomes qualified. +pub trait Qualif { + /// The name of the file used to debug the dataflow analysis that computes this qualif. + const ANALYSIS_NAME: &'static str; + + /// Whether this `Qualif` is cleared when a local is moved from. + const IS_CLEARED_ON_MOVE: bool = false; + + /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`. + fn in_qualifs(qualifs: &ConstQualifs) -> bool; + + /// Returns `true` if *any* value of the given type could possibly have this `Qualif`. + /// + /// This function determines `Qualif`s when we cannot do a value-based analysis. Since qualif + /// propagation is context-insenstive, this includes function arguments and values returned + /// from a call to another function. + /// + /// It also determines the `Qualif`s for primitive types. + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool; + + /// Returns `true` if this `Qualif` is inherent to the given struct or enum. + /// + /// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes + /// qualified if part of it is assigned a value with that `Qualif`. However, some ADTs *always* + /// have a certain `Qualif`, regardless of whether their fields have it. For example, a type + /// with a custom `Drop` impl is inherently `NeedsDrop`. + /// + /// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound. + fn in_adt_inherently( + cx: &ConstCx<'_, 'tcx>, + adt: &'tcx AdtDef, + substs: SubstsRef<'tcx>, + ) -> bool; +} + +/// Constant containing interior mutability (`UnsafeCell`). +/// This must be ruled out to make sure that evaluating the constant at compile-time +/// and at *any point* during the run-time would produce the same result. In particular, +/// promotion of temporaries must not change program behavior; if the promoted could be +/// written to, that would be a problem. +pub struct HasMutInterior; + +impl Qualif for HasMutInterior { + const ANALYSIS_NAME: &'static str = "flow_has_mut_interior"; + + fn in_qualifs(qualifs: &ConstQualifs) -> bool { + qualifs.has_mut_interior + } + + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) + } + + fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { + // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. + // It arises structurally for all other types. + Some(adt.did) == cx.tcx.lang_items().unsafe_cell_type() + } +} + +/// Constant containing an ADT that implements `Drop`. +/// This must be ruled out (a) because we cannot run `Drop` during compile-time +/// as that might not be a `const fn`, and (b) because implicit promotion would +/// remove side-effects that occur as part of dropping that value. +pub struct NeedsNonConstDrop; + +impl Qualif for NeedsNonConstDrop { + const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop"; + const IS_CLEARED_ON_MOVE: bool = true; + + fn in_qualifs(qualifs: &ConstQualifs) -> bool { + qualifs.needs_drop + } + + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool { + // Avoid selecting for simple cases. + match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() { + Ok([]) => return false, + Err(ty::util::AlwaysRequiresDrop) => return true, + // If we've got a single component, select with that + // to increase the chance that we hit the selection cache. + Ok([t]) => ty = t, + Ok([..]) => {} + } + + let drop_trait = if let Some(did) = cx.tcx.lang_items().drop_trait() { + did + } else { + // there is no way to define a type that needs non-const drop + // without having the lang item present. + return false; + }; + let trait_ref = + ty::TraitRef { def_id: drop_trait, substs: cx.tcx.mk_substs_trait(ty, &[]) }; + let obligation = Obligation::new( + ObligationCause::dummy(), + cx.param_env, + ty::Binder::dummy(ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::ConstIfConst, + }), + ); + + let implsrc = cx.tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const); + selcx.select(&obligation) + }); + match implsrc { + Ok(Some(ImplSource::ConstDrop(_))) + | Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => false, + _ => true, + } + } + + fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { + adt.has_non_const_dtor(cx.tcx) + } +} + +/// A constant that cannot be used as part of a pattern in a `match` expression. +pub struct CustomEq; + +impl Qualif for CustomEq { + const ANALYSIS_NAME: &'static str = "flow_custom_eq"; + + fn in_qualifs(qualifs: &ConstQualifs) -> bool { + qualifs.custom_eq + } + + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`, + // we know that at least some values of that type are not structural-match. I say "some" + // because that component may be part of an enum variant (e.g., + // `Option::::Some`), in which case some values of this type may be + // structural-match (`Option::None`). + let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id()); + traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some() + } + + fn in_adt_inherently( + cx: &ConstCx<'_, 'tcx>, + adt: &'tcx AdtDef, + substs: SubstsRef<'tcx>, + ) -> bool { + let ty = cx.tcx.mk_ty(ty::Adt(adt, substs)); + !ty.is_structural_eq_shallow(cx.tcx) + } +} + +// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. + +/// Returns `true` if this `Rvalue` contains qualif `Q`. +pub fn in_rvalue(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, rvalue: &Rvalue<'tcx>) -> bool +where + Q: Qualif, + F: FnMut(Local) -> bool, +{ + match rvalue { + Rvalue::ThreadLocalRef(_) | Rvalue::NullaryOp(..) => { + Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) + } + + Rvalue::Discriminant(place) | Rvalue::Len(place) => { + in_place::(cx, in_local, place.as_ref()) + } + + Rvalue::Use(operand) + | Rvalue::Repeat(operand, _) + | Rvalue::UnaryOp(_, operand) + | Rvalue::Cast(_, operand, _) + | Rvalue::ShallowInitBox(operand, _) => in_operand::(cx, in_local, operand), + + Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { + in_operand::(cx, in_local, lhs) || in_operand::(cx, in_local, rhs) + } + + Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { + // Special-case reborrows to be more like a copy of the reference. + if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() { + let base_ty = place_base.ty(cx.body, cx.tcx).ty; + if let ty::Ref(..) = base_ty.kind() { + return in_place::(cx, in_local, place_base); + } + } + + in_place::(cx, in_local, place.as_ref()) + } + + Rvalue::Aggregate(kind, operands) => { + // Return early if we know that the struct or enum being constructed is always + // qualified. + if let AggregateKind::Adt(def, _, substs, ..) = **kind { + if Q::in_adt_inherently(cx, def, substs) { + return true; + } + } + + // Otherwise, proceed structurally... + operands.iter().any(|o| in_operand::(cx, in_local, o)) + } + } +} + +/// Returns `true` if this `Place` contains qualif `Q`. +pub fn in_place(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, place: PlaceRef<'tcx>) -> bool +where + Q: Qualif, + F: FnMut(Local) -> bool, +{ + let mut place = place; + while let Some((place_base, elem)) = place.last_projection() { + match elem { + ProjectionElem::Index(index) if in_local(index) => return true, + + ProjectionElem::Deref + | ProjectionElem::Field(_, _) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(_, _) + | ProjectionElem::Index(_) => {} + } + + let base_ty = place_base.ty(cx.body, cx.tcx); + let proj_ty = base_ty.projection_ty(cx.tcx, elem).ty; + if !Q::in_any_value_of_ty(cx, proj_ty) { + return false; + } + + place = place_base; + } + + assert!(place.projection.is_empty()); + in_local(place.local) +} + +/// Returns `true` if this `Operand` contains qualif `Q`. +pub fn in_operand(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, operand: &Operand<'tcx>) -> bool +where + Q: Qualif, + F: FnMut(Local) -> bool, +{ + let constant = match operand { + Operand::Copy(place) | Operand::Move(place) => { + return in_place::(cx, in_local, place.as_ref()); + } + + Operand::Constant(c) => c, + }; + + // Check the qualifs of the value of `const` items. + if let Some(ct) = constant.literal.const_for_ty() { + if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val { + assert!(promoted.is_none()); + // Don't peek inside trait associated constants. + if cx.tcx.trait_of_item(def.did).is_none() { + let qualifs = if let Some((did, param_did)) = def.as_const_arg() { + cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) + } else { + cx.tcx.at(constant.span).mir_const_qualif(def.did) + }; + + if !Q::in_qualifs(&qualifs) { + return false; + } + + // Just in case the type is more specific than + // the definition, e.g., impl associated const + // with type parameters, take it into account. + } + } + } + // Otherwise use the qualifs of the type. + Q::in_any_value_of_ty(cx, constant.literal.ty()) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,216 @@ +//! Propagate `Qualif`s between locals and query the results. +//! +//! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs. + +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{self, BasicBlock, Local, Location}; + +use std::marker::PhantomData; + +use super::{qualifs, ConstCx, Qualif}; + +/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of +/// `FlowSensitiveAnalysis`. +/// +/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on +/// the `MaybeMutBorrowedLocals` dataflow pass to see if a `Local` may have become qualified via +/// an indirect assignment or function call. +struct TransferFunction<'a, 'mir, 'tcx, Q> { + ccx: &'a ConstCx<'mir, 'tcx>, + qualifs_per_local: &'a mut BitSet, + + _qualif: PhantomData, +} + +impl TransferFunction<'a, 'mir, 'tcx, Q> +where + Q: Qualif, +{ + fn new(ccx: &'a ConstCx<'mir, 'tcx>, qualifs_per_local: &'a mut BitSet) -> Self { + TransferFunction { ccx, qualifs_per_local, _qualif: PhantomData } + } + + fn initialize_state(&mut self) { + self.qualifs_per_local.clear(); + + for arg in self.ccx.body.args_iter() { + let arg_ty = self.ccx.body.local_decls[arg].ty; + if Q::in_any_value_of_ty(self.ccx, arg_ty) { + self.qualifs_per_local.insert(arg); + } + } + } + + fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) { + debug_assert!(!place.is_indirect()); + + match (value, place.as_ref()) { + (true, mir::PlaceRef { local, .. }) => { + self.qualifs_per_local.insert(local); + } + + // For now, we do not clear the qualif if a local is overwritten in full by + // an unqualified rvalue (e.g. `y = 5`). This is to be consistent + // with aggregates where we overwrite all fields with assignments, which would not + // get this feature. + (false, mir::PlaceRef { local: _, projection: &[] }) => { + // self.qualifs_per_local.remove(*local); + } + + _ => {} + } + } + + fn apply_call_return_effect( + &mut self, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ) { + // We cannot reason about another function's internals, so use conservative type-based + // qualification for the result of a function call. + let return_ty = return_place.ty(self.ccx.body, self.ccx.tcx).ty; + let qualif = Q::in_any_value_of_ty(self.ccx, return_ty); + + if !return_place.is_indirect() { + self.assign_qualif_direct(&return_place, qualif); + } + } +} + +impl Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q> +where + Q: Qualif, +{ + fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { + self.super_operand(operand, location); + + if !Q::IS_CLEARED_ON_MOVE { + return; + } + + // If a local with no projections is moved from (e.g. `x` in `y = x`), record that + // it no longer needs to be dropped. + if let mir::Operand::Move(place) = operand { + if let Some(local) = place.as_local() { + self.qualifs_per_local.remove(local); + } + } + } + + fn visit_assign( + &mut self, + place: &mir::Place<'tcx>, + rvalue: &mir::Rvalue<'tcx>, + location: Location, + ) { + let qualif = qualifs::in_rvalue::( + self.ccx, + &mut |l| self.qualifs_per_local.contains(l), + rvalue, + ); + if !place.is_indirect() { + self.assign_qualif_direct(place, qualif); + } + + // We need to assign qualifs to the left-hand side before visiting `rvalue` since + // qualifs can be cleared on move. + self.super_assign(place, rvalue, location); + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + // The effect of assignment to the return place in `TerminatorKind::Call` is not applied + // here; that occurs in `apply_call_return_effect`. + + if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind { + let qualif = qualifs::in_operand::( + self.ccx, + &mut |l| self.qualifs_per_local.contains(l), + value, + ); + + if !place.is_indirect() { + self.assign_qualif_direct(place, qualif); + } + } + + // We need to assign qualifs to the dropped location before visiting the operand that + // replaces it since qualifs can be cleared on move. + self.super_terminator(terminator, location); + } +} + +/// The dataflow analysis used to propagate qualifs on arbitrary CFGs. +pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> { + ccx: &'a ConstCx<'mir, 'tcx>, + _qualif: PhantomData, +} + +impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> +where + Q: Qualif, +{ + pub(super) fn new(_: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self { + FlowSensitiveAnalysis { ccx, _qualif: PhantomData } + } + + fn transfer_function( + &self, + state: &'a mut BitSet, + ) -> TransferFunction<'a, 'mir, 'tcx, Q> { + TransferFunction::::new(self.ccx, state) + } +} + +impl rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> +where + Q: Qualif, +{ + type Domain = BitSet; + + const NAME: &'static str = Q::ANALYSIS_NAME; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + BitSet::new_empty(body.local_decls.len()) + } + + fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) { + self.transfer_function(state).initialize_state(); + } +} + +impl rustc_mir_dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> +where + Q: Qualif, +{ + fn apply_statement_effect( + &self, + state: &mut Self::Domain, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.transfer_function(state).visit_statement(statement, location); + } + + fn apply_terminator_effect( + &self, + state: &mut Self::Domain, + terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + self.transfer_function(state).visit_terminator(terminator, location); + } + + fn apply_call_return_effect( + &self, + state: &mut Self::Domain, + block: BasicBlock, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ) { + self.transfer_function(state).apply_call_return_effect(block, func, args, return_place) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +pub mod check_consts; +pub mod promote_consts; +pub mod validate; + +pub use rustc_middle::mir::MirPass; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/promote_consts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/promote_consts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/promote_consts.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/promote_consts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1092 @@ +//! A pass that promotes borrows of constant rvalues. +//! +//! The rvalues considered constant are trees of temps, +//! each with exactly one initialization, and holding +//! a constant value with no interior mutability. +//! They are placed into a new MIR constant body in +//! `promoted` and the borrow rvalue is replaced with +//! a `Literal::Promoted` using the index into `promoted` +//! of that constant MIR. +//! +//! This pass assumes that every use is dominated by an +//! initialization and can otherwise silence errors, if +//! move analysis runs after promotion on broken MIR. + +use rustc_hir as hir; +use rustc_middle::mir::traversal::ReversePostorder; +use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::cast::CastTy; +use rustc_middle::ty::subst::InternalSubsts; +use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable}; +use rustc_span::Span; + +use rustc_index::vec::{Idx, IndexVec}; + +use std::cell::Cell; +use std::{cmp, iter, mem}; + +use crate::transform::check_consts::{is_lang_special_const_fn, qualifs, ConstCx}; +use crate::transform::MirPass; + +/// A `MirPass` for promotion. +/// +/// Promotion is the extraction of promotable temps into separate MIR bodies so they can have +/// `'static` lifetime. +/// +/// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each +/// newly created `Constant`. +#[derive(Default)] +pub struct PromoteTemps<'tcx> { + pub promoted_fragments: Cell>>, +} + +impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // There's not really any point in promoting errorful MIR. + // + // This does not include MIR that failed const-checking, which we still try to promote. + if body.return_ty().references_error() { + tcx.sess.delay_span_bug(body.span, "PromoteTemps: MIR had errors"); + return; + } + + if body.source.promoted.is_some() { + return; + } + + let mut rpo = traversal::reverse_postorder(body); + let ccx = ConstCx::new(tcx, body); + let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo); + + let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates); + + let promoted = promote_candidates(body, tcx, temps, promotable_candidates); + self.promoted_fragments.set(promoted); + } +} + +/// State of a temporary during collection and promotion. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum TempState { + /// No references to this temp. + Undefined, + /// One direct assignment and any number of direct uses. + /// A borrow of this temp is promotable if the assigned + /// value is qualified as constant. + Defined { location: Location, uses: usize }, + /// Any other combination of assignments/uses. + Unpromotable, + /// This temp was part of an rvalue which got extracted + /// during promotion and needs cleanup. + PromotedOut, +} + +impl TempState { + pub fn is_promotable(&self) -> bool { + debug!("is_promotable: self={:?}", self); + matches!(self, TempState::Defined { .. }) + } +} + +/// A "root candidate" for promotion, which will become the +/// returned value in a promoted MIR, unless it's a subset +/// of a larger candidate. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Candidate { + /// Borrow of a constant temporary, candidate for lifetime extension. + Ref(Location), +} + +impl Candidate { + fn source_info(&self, body: &Body<'_>) -> SourceInfo { + match self { + Candidate::Ref(location) => *body.source_info(*location), + } + } +} + +struct Collector<'a, 'tcx> { + ccx: &'a ConstCx<'a, 'tcx>, + temps: IndexVec, + candidates: Vec, +} + +impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { + fn visit_local(&mut self, &index: &Local, context: PlaceContext, location: Location) { + debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); + // We're only interested in temporaries and the return place + match self.ccx.body.local_kind(index) { + LocalKind::Temp | LocalKind::ReturnPointer => {} + LocalKind::Arg | LocalKind::Var => return, + } + + // Ignore drops, if the temp gets promoted, + // then it's constant and thus drop is noop. + // Non-uses are also irrelevant. + if context.is_drop() || !context.is_use() { + debug!( + "visit_local: context.is_drop={:?} context.is_use={:?}", + context.is_drop(), + context.is_use(), + ); + return; + } + + let temp = &mut self.temps[index]; + debug!("visit_local: temp={:?}", temp); + if *temp == TempState::Undefined { + match context { + PlaceContext::MutatingUse(MutatingUseContext::Store) + | PlaceContext::MutatingUse(MutatingUseContext::Call) => { + *temp = TempState::Defined { location, uses: 0 }; + return; + } + _ => { /* mark as unpromotable below */ } + } + } else if let TempState::Defined { ref mut uses, .. } = *temp { + // We always allow borrows, even mutable ones, as we need + // to promote mutable borrows of some ZSTs e.g., `&mut []`. + let allowed_use = match context { + PlaceContext::MutatingUse(MutatingUseContext::Borrow) + | PlaceContext::NonMutatingUse(_) => true, + PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, + }; + debug!("visit_local: allowed_use={:?}", allowed_use); + if allowed_use { + *uses += 1; + return; + } + /* mark as unpromotable below */ + } + *temp = TempState::Unpromotable; + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + + match *rvalue { + Rvalue::Ref(..) => { + self.candidates.push(Candidate::Ref(location)); + } + _ => {} + } + } +} + +pub fn collect_temps_and_candidates( + ccx: &ConstCx<'mir, 'tcx>, + rpo: &mut ReversePostorder<'_, 'tcx>, +) -> (IndexVec, Vec) { + let mut collector = Collector { + temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls), + candidates: vec![], + ccx, + }; + for (bb, data) in rpo { + collector.visit_basic_block_data(bb, data); + } + (collector.temps, collector.candidates) +} + +/// Checks whether locals that appear in a promotion context (`Candidate`) are actually promotable. +/// +/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion. +struct Validator<'a, 'tcx> { + ccx: &'a ConstCx<'a, 'tcx>, + temps: &'a IndexVec, +} + +impl std::ops::Deref for Validator<'a, 'tcx> { + type Target = ConstCx<'a, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.ccx + } +} + +struct Unpromotable; + +impl<'tcx> Validator<'_, 'tcx> { + fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { + match candidate { + Candidate::Ref(loc) => { + let statement = &self.body[loc.block].statements[loc.statement_index]; + match &statement.kind { + StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => { + // We can only promote interior borrows of promotable temps (non-temps + // don't get promoted anyway). + self.validate_local(place.local)?; + + // The reference operation itself must be promotable. + // (Needs to come after `validate_local` to avoid ICEs.) + self.validate_ref(*kind, place)?; + + // We do not check all the projections (they do not get promoted anyway), + // but we do stay away from promoting anything involving a dereference. + if place.projection.contains(&ProjectionElem::Deref) { + return Err(Unpromotable); + } + + // We cannot promote things that need dropping, since the promoted value + // would not get dropped. + if self.qualif_local::(place.local) { + return Err(Unpromotable); + } + + Ok(()) + } + _ => bug!(), + } + } + } + } + + // FIXME(eddyb) maybe cache this? + fn qualif_local(&self, local: Local) -> bool { + if let TempState::Defined { location: loc, .. } = self.temps[local] { + let num_stmts = self.body[loc.block].statements.len(); + + if loc.statement_index < num_stmts { + let statement = &self.body[loc.block].statements[loc.statement_index]; + match &statement.kind { + StatementKind::Assign(box (_, rhs)) => qualifs::in_rvalue::( + &self.ccx, + &mut |l| self.qualif_local::(l), + rhs, + ), + _ => { + span_bug!( + statement.source_info.span, + "{:?} is not an assignment", + statement + ); + } + } + } else { + let terminator = self.body[loc.block].terminator(); + match &terminator.kind { + TerminatorKind::Call { .. } => { + let return_ty = self.body.local_decls[local].ty; + Q::in_any_value_of_ty(&self.ccx, return_ty) + } + kind => { + span_bug!(terminator.source_info.span, "{:?} not promotable", kind); + } + } + } + } else { + let span = self.body.local_decls[local].source_info.span; + span_bug!(span, "{:?} not promotable, qualif_local shouldn't have been called", local); + } + } + + // FIXME(eddyb) maybe cache this? + fn validate_local(&self, local: Local) -> Result<(), Unpromotable> { + if let TempState::Defined { location: loc, .. } = self.temps[local] { + let block = &self.body[loc.block]; + let num_stmts = block.statements.len(); + + if loc.statement_index < num_stmts { + let statement = &block.statements[loc.statement_index]; + match &statement.kind { + StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs), + _ => { + span_bug!( + statement.source_info.span, + "{:?} is not an assignment", + statement + ); + } + } + } else { + let terminator = block.terminator(); + match &terminator.kind { + TerminatorKind::Call { func, args, .. } => self.validate_call(func, args), + TerminatorKind::Yield { .. } => Err(Unpromotable), + kind => { + span_bug!(terminator.source_info.span, "{:?} not promotable", kind); + } + } + } + } else { + Err(Unpromotable) + } + } + + fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> { + match place.last_projection() { + None => self.validate_local(place.local), + Some((place_base, elem)) => { + // Validate topmost projection, then recurse. + match elem { + ProjectionElem::Deref => { + let mut promotable = false; + // We need to make sure this is a `Deref` of a local with no further projections. + // Discussion can be found at + // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 + if let Some(local) = place_base.as_local() { + // This is a special treatment for cases like *&STATIC where STATIC is a + // global static variable. + // This pattern is generated only when global static variables are directly + // accessed and is qualified for promotion safely. + if let TempState::Defined { location, .. } = self.temps[local] { + let def_stmt = self.body[location.block] + .statements + .get(location.statement_index); + if let Some(Statement { + kind: + StatementKind::Assign(box ( + _, + Rvalue::Use(Operand::Constant(c)), + )), + .. + }) = def_stmt + { + if let Some(did) = c.check_static_ptr(self.tcx) { + // Evaluating a promoted may not read statics except if it got + // promoted from a static (this is a CTFE check). So we + // can only promote static accesses inside statics. + if let Some(hir::ConstContext::Static(..)) = self.const_kind + { + if !self.tcx.is_thread_local_static(did) { + promotable = true; + } + } + } + } + } + } + if !promotable { + return Err(Unpromotable); + } + } + ProjectionElem::Downcast(..) => { + return Err(Unpromotable); + } + + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} + + ProjectionElem::Index(local) => { + let mut promotable = false; + // Only accept if we can predict the index and are indexing an array. + let val = + if let TempState::Defined { location: loc, .. } = self.temps[local] { + let block = &self.body[loc.block]; + if loc.statement_index < block.statements.len() { + let statement = &block.statements[loc.statement_index]; + match &statement.kind { + StatementKind::Assign(box ( + _, + Rvalue::Use(Operand::Constant(c)), + )) => c.literal.try_eval_usize(self.tcx, self.param_env), + _ => None, + } + } else { + None + } + } else { + None + }; + if let Some(idx) = val { + // Determine the type of the thing we are indexing. + let ty = place_base.ty(self.body, self.tcx).ty; + match ty.kind() { + ty::Array(_, len) => { + // It's an array; determine its length. + if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) + { + // If the index is in-bounds, go ahead. + if idx < len { + promotable = true; + } + } + } + _ => {} + } + } + if !promotable { + return Err(Unpromotable); + } + + self.validate_local(local)?; + } + + ProjectionElem::Field(..) => { + let base_ty = place_base.ty(self.body, self.tcx).ty; + if base_ty.is_union() { + // No promotion of union field accesses. + return Err(Unpromotable); + } + } + } + + self.validate_place(place_base) + } + } + } + + fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> { + match operand { + Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()), + + // The qualifs for a constant (e.g. `HasMutInterior`) are checked in + // `validate_rvalue` upon access. + Operand::Constant(c) => { + if let Some(def_id) = c.check_static_ptr(self.tcx) { + // Only allow statics (not consts) to refer to other statics. + // FIXME(eddyb) does this matter at all for promotion? + // FIXME(RalfJung) it makes little sense to not promote this in `fn`/`const fn`, + // and in `const` this cannot occur anyway. The only concern is that we might + // promote even `let x = &STATIC` which would be useless, but this applies to + // promotion inside statics as well. + let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_))); + if !is_static { + return Err(Unpromotable); + } + + let is_thread_local = self.tcx.is_thread_local_static(def_id); + if is_thread_local { + return Err(Unpromotable); + } + } + + Ok(()) + } + } + } + + fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> { + match kind { + // Reject these borrow types just to be safe. + // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. + BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), + + BorrowKind::Shared => { + let has_mut_interior = self.qualif_local::(place.local); + if has_mut_interior { + return Err(Unpromotable); + } + } + + BorrowKind::Mut { .. } => { + let ty = place.ty(self.body, self.tcx).ty; + + // In theory, any zero-sized value could be borrowed + // mutably without consequences. However, only &mut [] + // is allowed right now. + if let ty::Array(_, len) = ty.kind() { + match len.try_eval_usize(self.tcx, self.param_env) { + Some(0) => {} + _ => return Err(Unpromotable), + } + } else { + return Err(Unpromotable); + } + } + } + + Ok(()) + } + + fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { + match rvalue { + Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => { + self.validate_operand(operand)?; + } + + Rvalue::Discriminant(place) | Rvalue::Len(place) => { + self.validate_place(place.as_ref())? + } + + Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), + + Rvalue::Cast(kind, operand, cast_ty) => { + if matches!(kind, CastKind::Misc) { + let operand_ty = operand.ty(self.body, self.tcx); + let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); + let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); + if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + // ptr-to-int casts are not possible in consts and thus not promotable + return Err(Unpromotable); + } + // int-to-ptr casts are fine, they just use the integer value at pointer type. + } + + self.validate_operand(operand)?; + } + + Rvalue::NullaryOp(op, _) => match op { + NullOp::Box => return Err(Unpromotable), + NullOp::SizeOf => {} + NullOp::AlignOf => {} + }, + + Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), + + Rvalue::UnaryOp(op, operand) => { + match op { + // These operations can never fail. + UnOp::Neg | UnOp::Not => {} + } + + self.validate_operand(operand)?; + } + + Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => { + let op = *op; + let lhs_ty = lhs.ty(self.body, self.tcx); + + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() { + // Raw and fn pointer operations are not allowed inside consts and thus not promotable. + assert!(matches!( + op, + BinOp::Eq + | BinOp::Ne + | BinOp::Le + | BinOp::Lt + | BinOp::Ge + | BinOp::Gt + | BinOp::Offset + )); + return Err(Unpromotable); + } + + match op { + BinOp::Div | BinOp::Rem => { + if lhs_ty.is_integral() { + // Integer division: the RHS must be a non-zero const. + let const_val = match rhs { + Operand::Constant(c) => { + c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty) + } + _ => None, + }; + match const_val { + Some(x) if x != 0 => {} // okay + _ => return Err(Unpromotable), // value not known or 0 -- not okay + } + } + } + // The remaining operations can never fail. + BinOp::Eq + | BinOp::Ne + | BinOp::Le + | BinOp::Lt + | BinOp::Ge + | BinOp::Gt + | BinOp::Offset + | BinOp::Add + | BinOp::Sub + | BinOp::Mul + | BinOp::BitXor + | BinOp::BitAnd + | BinOp::BitOr + | BinOp::Shl + | BinOp::Shr => {} + } + + self.validate_operand(lhs)?; + self.validate_operand(rhs)?; + } + + Rvalue::AddressOf(_, place) => { + // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is + // no problem, only using it is. + if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() + { + let base_ty = place_base.ty(self.body, self.tcx).ty; + if let ty::Ref(..) = base_ty.kind() { + return self.validate_place(place_base); + } + } + return Err(Unpromotable); + } + + Rvalue::Ref(_, kind, place) => { + // Special-case reborrows to be more like a copy of the reference. + let mut place_simplified = place.as_ref(); + if let Some((place_base, ProjectionElem::Deref)) = + place_simplified.last_projection() + { + let base_ty = place_base.ty(self.body, self.tcx).ty; + if let ty::Ref(..) = base_ty.kind() { + place_simplified = place_base; + } + } + + self.validate_place(place_simplified)?; + + // Check that the reference is fine (using the original place!). + // (Needs to come after `validate_place` to avoid ICEs.) + self.validate_ref(*kind, place)?; + } + + Rvalue::Aggregate(_, operands) => { + for o in operands { + self.validate_operand(o)?; + } + } + } + + Ok(()) + } + + fn validate_call( + &self, + callee: &Operand<'tcx>, + args: &[Operand<'tcx>], + ) -> Result<(), Unpromotable> { + let fn_ty = callee.ty(self.body, self.tcx); + + // Inside const/static items, we promote all (eligible) function calls. + // Everywhere else, we require `#[rustc_promotable]` on the callee. + let promote_all_const_fn = matches!( + self.const_kind, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) + ); + if !promote_all_const_fn { + if let ty::FnDef(def_id, _) = *fn_ty.kind() { + // Never promote runtime `const fn` calls of + // functions without `#[rustc_promotable]`. + if !self.tcx.is_promotable_const_fn(def_id) { + return Err(Unpromotable); + } + } + } + + let is_const_fn = match *fn_ty.kind() { + ty::FnDef(def_id, _) => { + self.tcx.is_const_fn_raw(def_id) || is_lang_special_const_fn(self.tcx, def_id) + } + _ => false, + }; + if !is_const_fn { + return Err(Unpromotable); + } + + self.validate_operand(callee)?; + for arg in args { + self.validate_operand(arg)?; + } + + Ok(()) + } +} + +// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`. +pub fn validate_candidates( + ccx: &ConstCx<'_, '_>, + temps: &IndexVec, + candidates: &[Candidate], +) -> Vec { + let validator = Validator { ccx, temps }; + + candidates + .iter() + .copied() + .filter(|&candidate| validator.validate_candidate(candidate).is_ok()) + .collect() +} + +struct Promoter<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + source: &'a mut Body<'tcx>, + promoted: Body<'tcx>, + temps: &'a mut IndexVec, + extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>, + + /// If true, all nested temps are also kept in the + /// source MIR, not moved to the promoted MIR. + keep_original: bool, +} + +impl<'a, 'tcx> Promoter<'a, 'tcx> { + fn new_block(&mut self) -> BasicBlock { + let span = self.promoted.span; + self.promoted.basic_blocks_mut().push(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(span), + kind: TerminatorKind::Return, + }), + is_cleanup: false, + }) + } + + fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { + let last = self.promoted.basic_blocks().last().unwrap(); + let data = &mut self.promoted[last]; + data.statements.push(Statement { + source_info: SourceInfo::outermost(span), + kind: StatementKind::Assign(Box::new((Place::from(dest), rvalue))), + }); + } + + fn is_temp_kind(&self, local: Local) -> bool { + self.source.local_kind(local) == LocalKind::Temp + } + + /// Copies the initialization of this temp to the + /// promoted MIR, recursing through temps. + fn promote_temp(&mut self, temp: Local) -> Local { + let old_keep_original = self.keep_original; + let loc = match self.temps[temp] { + TempState::Defined { location, uses } if uses > 0 => { + if uses > 1 { + self.keep_original = true; + } + location + } + state => { + span_bug!(self.promoted.span, "{:?} not promotable: {:?}", temp, state); + } + }; + if !self.keep_original { + self.temps[temp] = TempState::PromotedOut; + } + + let num_stmts = self.source[loc.block].statements.len(); + let new_temp = self.promoted.local_decls.push(LocalDecl::new( + self.source.local_decls[temp].ty, + self.source.local_decls[temp].source_info.span, + )); + + debug!("promote({:?} @ {:?}/{:?}, {:?})", temp, loc, num_stmts, self.keep_original); + + // First, take the Rvalue or Call out of the source MIR, + // or duplicate it, depending on keep_original. + if loc.statement_index < num_stmts { + let (mut rvalue, source_info) = { + let statement = &mut self.source[loc.block].statements[loc.statement_index]; + let rhs = match statement.kind { + StatementKind::Assign(box (_, ref mut rhs)) => rhs, + _ => { + span_bug!( + statement.source_info.span, + "{:?} is not an assignment", + statement + ); + } + }; + + ( + if self.keep_original { + rhs.clone() + } else { + let unit = Rvalue::Use(Operand::Constant(Box::new(Constant { + span: statement.source_info.span, + user_ty: None, + literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit).into(), + }))); + mem::replace(rhs, unit) + }, + statement.source_info, + ) + }; + + self.visit_rvalue(&mut rvalue, loc); + self.assign(new_temp, rvalue, source_info.span); + } else { + let terminator = if self.keep_original { + self.source[loc.block].terminator().clone() + } else { + let terminator = self.source[loc.block].terminator_mut(); + let target = match terminator.kind { + TerminatorKind::Call { destination: Some((_, target)), .. } => target, + ref kind => { + span_bug!(terminator.source_info.span, "{:?} not promotable", kind); + } + }; + Terminator { + source_info: terminator.source_info, + kind: mem::replace(&mut terminator.kind, TerminatorKind::Goto { target }), + } + }; + + match terminator.kind { + TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => { + self.visit_operand(&mut func, loc); + for arg in &mut args { + self.visit_operand(arg, loc); + } + + let last = self.promoted.basic_blocks().last().unwrap(); + let new_target = self.new_block(); + + *self.promoted[last].terminator_mut() = Terminator { + kind: TerminatorKind::Call { + func, + args, + cleanup: None, + destination: Some((Place::from(new_temp), new_target)), + from_hir_call, + fn_span, + }, + source_info: SourceInfo::outermost(terminator.source_info.span), + ..terminator + }; + } + ref kind => { + span_bug!(terminator.source_info.span, "{:?} not promotable", kind); + } + }; + }; + + self.keep_original = old_keep_original; + new_temp + } + + fn promote_candidate( + mut self, + candidate: Candidate, + next_promoted_id: usize, + ) -> Option> { + let def = self.source.source.with_opt_param(); + let mut rvalue = { + let promoted = &mut self.promoted; + let promoted_id = Promoted::new(next_promoted_id); + let tcx = self.tcx; + let mut promoted_operand = |ty, span| { + promoted.span = span; + promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); + + Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: tcx + .mk_const(ty::Const { + ty, + val: ty::ConstKind::Unevaluated(ty::Unevaluated { + def, + substs_: Some(InternalSubsts::for_item( + tcx, + def.did, + |param, _| { + if let ty::GenericParamDefKind::Lifetime = param.kind { + tcx.lifetimes.re_erased.into() + } else { + tcx.mk_param_from_def(param) + } + }, + )), + promoted: Some(promoted_id), + }), + }) + .into(), + })) + }; + let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); + match candidate { + Candidate::Ref(loc) => { + let statement = &mut blocks[loc.block].statements[loc.statement_index]; + match statement.kind { + StatementKind::Assign(box ( + _, + Rvalue::Ref(ref mut region, borrow_kind, ref mut place), + )) => { + // Use the underlying local for this (necessarily interior) borrow. + let ty = local_decls.local_decls()[place.local].ty; + let span = statement.source_info.span; + + let ref_ty = tcx.mk_ref( + tcx.lifetimes.re_erased, + ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() }, + ); + + *region = tcx.lifetimes.re_erased; + + let mut projection = vec![PlaceElem::Deref]; + projection.extend(place.projection); + place.projection = tcx.intern_place_elems(&projection); + + // Create a temp to hold the promoted reference. + // This is because `*r` requires `r` to be a local, + // otherwise we would use the `promoted` directly. + let mut promoted_ref = LocalDecl::new(ref_ty, span); + promoted_ref.source_info = statement.source_info; + let promoted_ref = local_decls.push(promoted_ref); + assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref); + + let promoted_ref_statement = Statement { + source_info: statement.source_info, + kind: StatementKind::Assign(Box::new(( + Place::from(promoted_ref), + Rvalue::Use(promoted_operand(ref_ty, span)), + ))), + }; + self.extra_statements.push((loc, promoted_ref_statement)); + + Rvalue::Ref( + tcx.lifetimes.re_erased, + borrow_kind, + Place { + local: mem::replace(&mut place.local, promoted_ref), + projection: List::empty(), + }, + ) + } + _ => bug!(), + } + } + } + }; + + assert_eq!(self.new_block(), START_BLOCK); + self.visit_rvalue( + &mut rvalue, + Location { block: BasicBlock::new(0), statement_index: usize::MAX }, + ); + + let span = self.promoted.span; + self.assign(RETURN_PLACE, rvalue, span); + Some(self.promoted) + } +} + +/// Replaces all temporaries with their promoted counterparts. +impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { + if self.is_temp_kind(*local) { + *local = self.promote_temp(*local); + } + } +} + +pub fn promote_candidates<'tcx>( + body: &mut Body<'tcx>, + tcx: TyCtxt<'tcx>, + mut temps: IndexVec, + candidates: Vec, +) -> IndexVec> { + // Visit candidates in reverse, in case they're nested. + debug!("promote_candidates({:?})", candidates); + + let mut promotions = IndexVec::new(); + + let mut extra_statements = vec![]; + for candidate in candidates.into_iter().rev() { + match candidate { + Candidate::Ref(Location { block, statement_index }) => { + if let StatementKind::Assign(box (place, _)) = + &body[block].statements[statement_index].kind + { + if let Some(local) = place.as_local() { + if temps[local] == TempState::PromotedOut { + // Already promoted. + continue; + } + } + } + } + } + + // Declare return place local so that `mir::Body::new` doesn't complain. + let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect(); + + let mut scope = body.source_scopes[candidate.source_info(body).scope].clone(); + scope.parent_scope = None; + + let promoted = Body::new( + tcx, + body.source, // `promoted` gets filled in below + IndexVec::new(), + IndexVec::from_elem_n(scope, 1), + initial_locals, + IndexVec::new(), + 0, + vec![], + body.span, + body.generator_kind(), + ); + + let promoter = Promoter { + promoted, + tcx, + source: body, + temps: &mut temps, + extra_statements: &mut extra_statements, + keep_original: false, + }; + + //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice + if let Some(mut promoted) = promoter.promote_candidate(candidate, promotions.len()) { + promoted.source.promoted = Some(promotions.next_index()); + promotions.push(promoted); + } + } + + // Insert each of `extra_statements` before its indicated location, which + // has to be done in reverse location order, to not invalidate the rest. + extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc)); + for (loc, statement) in extra_statements { + body[loc.block].statements.insert(loc.statement_index, statement); + } + + // Eliminate assignments to, and drops of promoted temps. + let promoted = |index: Local| temps[index] == TempState::PromotedOut; + for block in body.basic_blocks_mut() { + block.statements.retain(|statement| match &statement.kind { + StatementKind::Assign(box (place, _)) => { + if let Some(index) = place.as_local() { + !promoted(index) + } else { + true + } + } + StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { + !promoted(*index) + } + _ => true, + }); + let terminator = block.terminator_mut(); + if let TerminatorKind::Drop { place, target, .. } = &terminator.kind { + if let Some(index) = place.as_local() { + if promoted(index) { + terminator.kind = TerminatorKind::Goto { target: *target }; + } + } + } + } + + promotions +} + +/// This function returns `true` if the function being called in the array +/// repeat expression is a `const` function. +pub fn is_const_fn_in_array_repeat_expression<'tcx>( + ccx: &ConstCx<'_, 'tcx>, + place: &Place<'tcx>, + body: &Body<'tcx>, +) -> bool { + match place.as_local() { + // rule out cases such as: `let my_var = some_fn(); [my_var; N]` + Some(local) if body.local_decls[local].is_user_variable() => return false, + None => return false, + _ => {} + } + + for block in body.basic_blocks() { + if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = + &block.terminator + { + if let Operand::Constant(box Constant { literal, .. }) = func { + if let ty::FnDef(def_id, _) = *literal.ty().kind() { + if let Some((destination_place, _)) = destination { + if destination_place == place { + if ccx.tcx.is_const_fn(def_id) { + return true; + } + } + } + } + } + } + } + + false +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/validate.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/validate.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/validate.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/transform/validate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,526 @@ +//! Validates the MIR to ensure that invariants are upheld. + +use super::MirPass; +use rustc_index::bit_set::BitSet; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::traversal; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{ + AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem, + PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator, + TerminatorKind, START_BLOCK, +}; +use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc_mir_dataflow::impls::MaybeStorageLive; +use rustc_mir_dataflow::storage::AlwaysLiveLocals; +use rustc_mir_dataflow::{Analysis, ResultsCursor}; +use rustc_target::abi::Size; + +#[derive(Copy, Clone, Debug)] +enum EdgeKind { + Unwind, + Normal, +} + +pub struct Validator { + /// Describes at which point in the pipeline this validation is happening. + pub when: String, + /// The phase for which we are upholding the dialect. If the given phase forbids a specific + /// element, this validator will now emit errors if that specific element is encountered. + /// Note that phases that change the dialect cause all *following* phases to check the + /// invariants of the new dialect. A phase that changes dialects never checks the new invariants + /// itself. + pub mir_phase: MirPhase, +} + +impl<'tcx> MirPass<'tcx> for Validator { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let def_id = body.source.def_id(); + let param_env = tcx.param_env(def_id); + let mir_phase = self.mir_phase; + + let always_live_locals = AlwaysLiveLocals::new(body); + let storage_liveness = MaybeStorageLive::new(always_live_locals) + .into_engine(tcx, body) + .iterate_to_fixpoint() + .into_results_cursor(body); + + TypeChecker { + when: &self.when, + body, + tcx, + param_env, + mir_phase, + reachable_blocks: traversal::reachable_as_bitset(body), + storage_liveness, + place_cache: Vec::new(), + } + .visit_body(body); + } +} + +/// Returns whether the two types are equal up to lifetimes. +/// All lifetimes, including higher-ranked ones, get ignored for this comparison. +/// (This is unlike the `erasing_regions` methods, which keep higher-ranked lifetimes for soundness reasons.) +/// +/// The point of this function is to approximate "equal up to subtyping". However, +/// the approximation is incorrect as variance is ignored. +pub fn equal_up_to_regions( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + src: Ty<'tcx>, + dest: Ty<'tcx>, +) -> bool { + // Fast path. + if src == dest { + return true; + } + + // Normalize lifetimes away on both sides, then compare. + let param_env = param_env.with_reveal_all_normalized(tcx); + let normalize = |ty: Ty<'tcx>| { + tcx.normalize_erasing_regions( + param_env, + ty.fold_with(&mut BottomUpFolder { + tcx, + // FIXME: We erase all late-bound lifetimes, but this is not fully correct. + // If you have a type like ` fn(&'a u32) as SomeTrait>::Assoc`, + // this is not necessarily equivalent to `::Assoc`, + // since one may have an `impl SomeTrait for fn(&32)` and + // `impl SomeTrait for fn(&'static u32)` at the same time which + // specify distinct values for Assoc. (See also #56105) + lt_op: |_| tcx.lifetimes.re_erased, + // Leave consts and types unchanged. + ct_op: |ct| ct, + ty_op: |ty| ty, + }), + ) + }; + tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok()) +} + +struct TypeChecker<'a, 'tcx> { + when: &'a str, + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + mir_phase: MirPhase, + reachable_blocks: BitSet, + storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>, + place_cache: Vec>, +} + +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + fn fail(&self, location: Location, msg: impl AsRef) { + let span = self.body.source_info(location).span; + // We use `delay_span_bug` as we might see broken MIR when other errors have already + // occurred. + self.tcx.sess.diagnostic().delay_span_bug( + span, + &format!( + "broken MIR in {:?} ({}) at {:?}:\n{}", + self.body.source.instance, + self.when, + location, + msg.as_ref() + ), + ); + } + + fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) { + if bb == START_BLOCK { + self.fail(location, "start block must not have predecessors") + } + if let Some(bb) = self.body.basic_blocks().get(bb) { + let src = self.body.basic_blocks().get(location.block).unwrap(); + match (src.is_cleanup, bb.is_cleanup, edge_kind) { + // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges + (false, false, EdgeKind::Normal) + // Non-cleanup blocks can jump to cleanup blocks along unwind edges + | (false, true, EdgeKind::Unwind) + // Cleanup blocks can jump to cleanup blocks along non-unwind edges + | (true, true, EdgeKind::Normal) => {} + // All other jumps are invalid + _ => { + self.fail( + location, + format!( + "{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})", + edge_kind, + bb, + src.is_cleanup, + bb.is_cleanup, + ) + ) + } + } + } else { + self.fail(location, format!("encountered jump to invalid basic block {:?}", bb)) + } + } + + /// Check if src can be assigned into dest. + /// This is not precise, it will accept some incorrect assignments. + fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { + // Fast path before we normalize. + if src == dest { + // Equal types, all is good. + return true; + } + // Normalize projections and things like that. + // FIXME: We need to reveal_all, as some optimizations change types in ways + // that require unfolding opaque types. + let param_env = self.param_env.with_reveal_all_normalized(self.tcx); + let src = self.tcx.normalize_erasing_regions(param_env, src); + let dest = self.tcx.normalize_erasing_regions(param_env, dest); + + // Type-changing assignments can happen when subtyping is used. While + // all normal lifetimes are erased, higher-ranked types with their + // late-bound lifetimes are still around and can lead to type + // differences. So we compare ignoring lifetimes. + equal_up_to_regions(self.tcx, param_env, src, dest) + } +} + +impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { + fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + if self.body.local_decls.get(*local).is_none() { + self.fail( + location, + format!("local {:?} has no corresponding declaration in `body.local_decls`", local), + ); + } + + if self.reachable_blocks.contains(location.block) && context.is_use() { + // Uses of locals must occur while the local's storage is allocated. + self.storage_liveness.seek_after_primary_effect(location); + let locals_with_storage = self.storage_liveness.get(); + if !locals_with_storage.contains(*local) { + self.fail(location, format!("use of local {:?}, which has no storage here", local)); + } + } + } + + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { + // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. + if self.tcx.sess.opts.debugging_opts.validate_mir { + // `Operand::Copy` is only supposed to be used with `Copy` types. + if let Operand::Copy(place) = operand { + let ty = place.ty(&self.body.local_decls, self.tcx).ty; + let span = self.body.source_info(location).span; + + if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) { + self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty)); + } + } + } + + self.super_operand(operand, location); + } + + fn visit_projection_elem( + &mut self, + local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + if let ProjectionElem::Index(index) = elem { + let index_ty = self.body.local_decls[index].ty; + if index_ty != self.tcx.types.usize { + self.fail(location, format!("bad index ({:?} != usize)", index_ty)) + } + } + self.super_projection_elem(local, proj_base, elem, context, location); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + match &statement.kind { + StatementKind::Assign(box (dest, rvalue)) => { + // LHS and RHS of the assignment must have the same type. + let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty; + let right_ty = rvalue.ty(&self.body.local_decls, self.tcx); + if !self.mir_assign_valid_types(right_ty, left_ty) { + self.fail( + location, + format!( + "encountered `{:?}` with incompatible types:\n\ + left-hand side has type: {}\n\ + right-hand side has type: {}", + statement.kind, left_ty, right_ty, + ), + ); + } + match rvalue { + // The sides of an assignment must not alias. Currently this just checks whether the places + // are identical. + Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => { + if dest == src { + self.fail( + location, + "encountered `Assign` statement with overlapping memory", + ); + } + } + // The deaggregator currently does not deaggreagate arrays. + // So for now, we ignore them here. + Rvalue::Aggregate(box AggregateKind::Array { .. }, _) => {} + // All other aggregates must be gone after some phases. + Rvalue::Aggregate(box kind, _) => { + if self.mir_phase > MirPhase::DropLowering + && !matches!(kind, AggregateKind::Generator(..)) + { + // Generators persist until the state machine transformation, but all + // other aggregates must have been lowered. + self.fail( + location, + format!("{:?} have been lowered to field assignments", rvalue), + ) + } else if self.mir_phase > MirPhase::GeneratorLowering { + // No more aggregates after drop and generator lowering. + self.fail( + location, + format!("{:?} have been lowered to field assignments", rvalue), + ) + } + } + Rvalue::Ref(_, BorrowKind::Shallow, _) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase", + ); + } + } + _ => {} + } + } + StatementKind::AscribeUserType(..) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`AscribeUserType` should have been removed after drop lowering phase", + ); + } + } + StatementKind::FakeRead(..) => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`FakeRead` should have been removed after drop lowering phase", + ); + } + } + StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + ref src, + ref dst, + ref count, + }) => { + let src_ty = src.ty(&self.body.local_decls, self.tcx); + let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { + src_deref.ty + } else { + self.fail( + location, + format!("Expected src to be ptr in copy_nonoverlapping, got: {}", src_ty), + ); + return; + }; + let dst_ty = dst.ty(&self.body.local_decls, self.tcx); + let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { + dst_deref.ty + } else { + self.fail( + location, + format!("Expected dst to be ptr in copy_nonoverlapping, got: {}", dst_ty), + ); + return; + }; + // since CopyNonOverlapping is parametrized by 1 type, + // we only need to check that they are equal and not keep an extra parameter. + if op_src_ty != op_dst_ty { + self.fail(location, format!("bad arg ({:?} != {:?})", op_src_ty, op_dst_ty)); + } + + let op_cnt_ty = count.ty(&self.body.local_decls, self.tcx); + if op_cnt_ty != self.tcx.types.usize { + self.fail(location, format!("bad arg ({:?} != usize)", op_cnt_ty)) + } + } + StatementKind::SetDiscriminant { .. } + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::LlvmInlineAsm(..) + | StatementKind::Retag(_, _) + | StatementKind::Coverage(_) + | StatementKind::Nop => {} + } + + self.super_statement(statement, location); + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + match &terminator.kind { + TerminatorKind::Goto { target } => { + self.check_edge(location, *target, EdgeKind::Normal); + } + TerminatorKind::SwitchInt { targets, switch_ty, discr } => { + let ty = discr.ty(&self.body.local_decls, self.tcx); + if ty != *switch_ty { + self.fail( + location, + format!( + "encountered `SwitchInt` terminator with type mismatch: {:?} != {:?}", + ty, switch_ty, + ), + ); + } + + let target_width = self.tcx.sess.target.pointer_width; + + let size = Size::from_bits(match switch_ty.kind() { + ty::Uint(uint) => uint.normalize(target_width).bit_width().unwrap(), + ty::Int(int) => int.normalize(target_width).bit_width().unwrap(), + ty::Char => 32, + ty::Bool => 1, + other => bug!("unhandled type: {:?}", other), + }); + + for (value, target) in targets.iter() { + if Scalar::<()>::try_from_uint(value, size).is_none() { + self.fail( + location, + format!("the value {:#x} is not a proper {:?}", value, switch_ty), + ) + } + + self.check_edge(location, target, EdgeKind::Normal); + } + self.check_edge(location, targets.otherwise(), EdgeKind::Normal); + } + TerminatorKind::Drop { target, unwind, .. } => { + self.check_edge(location, *target, EdgeKind::Normal); + if let Some(unwind) = unwind { + self.check_edge(location, *unwind, EdgeKind::Unwind); + } + } + TerminatorKind::DropAndReplace { target, unwind, .. } => { + if self.mir_phase > MirPhase::DropLowering { + self.fail( + location, + "`DropAndReplace` is not permitted to exist after drop elaboration", + ); + } + self.check_edge(location, *target, EdgeKind::Normal); + if let Some(unwind) = unwind { + self.check_edge(location, *unwind, EdgeKind::Unwind); + } + } + TerminatorKind::Call { func, args, destination, cleanup, .. } => { + let func_ty = func.ty(&self.body.local_decls, self.tcx); + match func_ty.kind() { + ty::FnPtr(..) | ty::FnDef(..) => {} + _ => self.fail( + location, + format!("encountered non-callable type {} in `Call` terminator", func_ty), + ), + } + if let Some((_, target)) = destination { + self.check_edge(location, *target, EdgeKind::Normal); + } + if let Some(cleanup) = cleanup { + self.check_edge(location, *cleanup, EdgeKind::Unwind); + } + + // The call destination place and Operand::Move place used as an argument might be + // passed by a reference to the callee. Consequently they must be non-overlapping. + // Currently this simply checks for duplicate places. + self.place_cache.clear(); + if let Some((destination, _)) = destination { + self.place_cache.push(destination.as_ref()); + } + for arg in args { + if let Operand::Move(place) = arg { + self.place_cache.push(place.as_ref()); + } + } + let all_len = self.place_cache.len(); + self.place_cache.sort_unstable(); + self.place_cache.dedup(); + let has_duplicates = all_len != self.place_cache.len(); + if has_duplicates { + self.fail( + location, + format!( + "encountered overlapping memory in `Call` terminator: {:?}", + terminator.kind, + ), + ); + } + } + TerminatorKind::Assert { cond, target, cleanup, .. } => { + let cond_ty = cond.ty(&self.body.local_decls, self.tcx); + if cond_ty != self.tcx.types.bool { + self.fail( + location, + format!( + "encountered non-boolean condition of type {} in `Assert` terminator", + cond_ty + ), + ); + } + self.check_edge(location, *target, EdgeKind::Normal); + if let Some(cleanup) = cleanup { + self.check_edge(location, *cleanup, EdgeKind::Unwind); + } + } + TerminatorKind::Yield { resume, drop, .. } => { + if self.mir_phase > MirPhase::GeneratorLowering { + self.fail(location, "`Yield` should have been replaced by generator lowering"); + } + self.check_edge(location, *resume, EdgeKind::Normal); + if let Some(drop) = drop { + self.check_edge(location, *drop, EdgeKind::Normal); + } + } + TerminatorKind::FalseEdge { real_target, imaginary_target } => { + self.check_edge(location, *real_target, EdgeKind::Normal); + self.check_edge(location, *imaginary_target, EdgeKind::Normal); + } + TerminatorKind::FalseUnwind { real_target, unwind } => { + self.check_edge(location, *real_target, EdgeKind::Normal); + if let Some(unwind) = unwind { + self.check_edge(location, *unwind, EdgeKind::Unwind); + } + } + TerminatorKind::InlineAsm { destination, .. } => { + if let Some(destination) = destination { + self.check_edge(location, *destination, EdgeKind::Normal); + } + } + // Nothing to validate for these. + TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop => {} + } + + self.super_terminator(terminator, location); + } + + fn visit_source_scope(&mut self, scope: &SourceScope) { + if self.body.source_scopes.get(*scope).is_none() { + self.tcx.sess.diagnostic().delay_span_bug( + self.body.span, + &format!( + "broken MIR in {:?} ({}):\ninvalid source scope {:?}", + self.body.source.instance, self.when, scope, + ), + ); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/aggregate.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/aggregate.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/aggregate.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/aggregate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,75 @@ +use rustc_index::vec::Idx; +use rustc_middle::mir::*; +use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_target::abi::VariantIdx; + +use std::convert::TryFrom; +use std::iter::TrustedLen; + +/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields. +/// +/// Produces something like +/// +/// (lhs as Variant).field0 = arg0; // We only have a downcast if this is an enum +/// (lhs as Variant).field1 = arg1; +/// discriminant(lhs) = variant_index; // If lhs is an enum or generator. +pub fn expand_aggregate<'tcx>( + mut lhs: Place<'tcx>, + operands: impl Iterator, Ty<'tcx>)> + TrustedLen, + kind: AggregateKind<'tcx>, + source_info: SourceInfo, + tcx: TyCtxt<'tcx>, +) -> impl Iterator> + TrustedLen { + let mut set_discriminant = None; + let active_field_index = match kind { + AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { + if adt_def.is_enum() { + set_discriminant = Some(Statement { + kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index }, + source_info, + }); + lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index); + } + active_field_index + } + AggregateKind::Generator(..) => { + // Right now we only support initializing generators to + // variant 0 (Unresumed). + let variant_index = VariantIdx::new(0); + set_discriminant = Some(Statement { + kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index }, + source_info, + }); + + // Operands are upvars stored on the base place, so no + // downcast is necessary. + + None + } + _ => None, + }; + + operands + .enumerate() + .map(move |(i, (op, ty))| { + let lhs_field = if let AggregateKind::Array(_) = kind { + let offset = u64::try_from(i).unwrap(); + tcx.mk_place_elem( + lhs, + ProjectionElem::ConstantIndex { + offset, + min_length: offset + 1, + from_end: false, + }, + ) + } else { + let field = Field::new(active_field_index.unwrap_or(i)); + tcx.mk_place_field(lhs, field, ty) + }; + Statement { + source_info, + kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))), + } + }) + .chain(set_discriminant) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/alignment.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/alignment.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/alignment.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/alignment.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,70 @@ +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_target::abi::Align; + +/// Returns `true` if this place is allowed to be less aligned +/// than its containing struct (because it is within a packed +/// struct). +pub fn is_disaligned<'tcx, L>( + tcx: TyCtxt<'tcx>, + local_decls: &L, + param_env: ty::ParamEnv<'tcx>, + place: Place<'tcx>, +) -> bool +where + L: HasLocalDecls<'tcx>, +{ + debug!("is_disaligned({:?})", place); + let pack = match is_within_packed(tcx, local_decls, place) { + None => { + debug!("is_disaligned({:?}) - not within packed", place); + return false; + } + Some(pack) => pack, + }; + + let ty = place.ty(local_decls, tcx).ty; + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) if layout.align.abi <= pack => { + // If the packed alignment is greater or equal to the field alignment, the type won't be + // further disaligned. + debug!( + "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", + place, + layout.align.abi.bytes(), + pack.bytes() + ); + false + } + _ => { + debug!("is_disaligned({:?}) - true", place); + true + } + } +} + +fn is_within_packed<'tcx, L>( + tcx: TyCtxt<'tcx>, + local_decls: &L, + place: Place<'tcx>, +) -> Option +where + L: HasLocalDecls<'tcx>, +{ + for (place_base, elem) in place.iter_projections().rev() { + match elem { + // encountered a Deref, which is ABI-aligned + ProjectionElem::Deref => break, + ProjectionElem::Field(..) => { + let ty = place_base.ty(local_decls, tcx).ty; + match ty.kind() { + ty::Adt(def, _) => return def.repr.pack, + _ => {} + } + } + _ => {} + } + } + + None +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/collect_writes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/collect_writes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/collect_writes.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/collect_writes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,36 @@ +use rustc_middle::mir::visit::PlaceContext; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{Body, Local, Location}; + +pub trait FindAssignments { + // Finds all statements that assign directly to local (i.e., X = ...) + // and returns their locations. + fn find_assignments(&self, local: Local) -> Vec; +} + +impl<'tcx> FindAssignments for Body<'tcx> { + fn find_assignments(&self, local: Local) -> Vec { + let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] }; + visitor.visit_body(self); + visitor.locations + } +} + +// The Visitor walks the MIR to return the assignment statements corresponding +// to a Local. +struct FindLocalAssignmentVisitor { + needle: Local, + locations: Vec, +} + +impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { + fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) { + if self.needle != *local { + return; + } + + if place_context.is_place_assignment() { + self.locations.push(location); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/find_self_call.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/find_self_call.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/find_self_call.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/find_self_call.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,36 @@ +use rustc_middle::mir::*; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::DefId; + +/// Checks if the specified `local` is used as the `self` parameter of a method call +/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is +/// returned. +pub fn find_self_call<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + local: Local, + block: BasicBlock, +) -> Option<(DefId, SubstsRef<'tcx>)> { + debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator); + if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = + &body[block].terminator + { + debug!("find_self_call: func={:?}", func); + if let Operand::Constant(box Constant { literal, .. }) = func { + if let ty::FnDef(def_id, substs) = *literal.ty().kind() { + if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = + tcx.opt_associated_item(def_id) + { + debug!("find_self_call: args={:?}", args); + if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args { + if self_place.as_local() == Some(local) { + return Some((def_id, substs)); + } + } + } + } + } + } + None +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_const_eval/src/util/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +pub mod aggregate; +mod alignment; +pub mod collect_writes; +mod find_self_call; + +pub use self::aggregate::expand_aggregate; +pub use self::alignment::is_disaligned; +pub use self::find_self_call::find_self_call; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_data_structures" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/base_n.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/base_n.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/base_n.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/base_n.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,7 +14,7 @@ #[inline] pub fn push_str(mut n: u128, base: usize, output: &mut String) { - debug_assert!(base >= 2 && base <= MAX_BASE); + debug_assert!((2..=MAX_BASE).contains(&base)); let mut s = [0u8; 128]; let mut index = 0; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/implementation/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/implementation/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/implementation/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/implementation/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -206,17 +206,11 @@ AdjacentEdges { graph: self, direction, next: first_edge } } - pub fn successor_nodes<'a>( - &'a self, - source: NodeIndex, - ) -> impl Iterator + 'a { + pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator + '_ { self.outgoing_edges(source).targets() } - pub fn predecessor_nodes<'a>( - &'a self, - target: NodeIndex, - ) -> impl Iterator + 'a { + pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator + '_ { self.incoming_edges(target).sources() } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/iterate/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/iterate/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/iterate/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/iterate/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -48,7 +48,7 @@ let node = frame.node; visited[node] = true; - while let Some(successor) = frame.iter.next() { + for successor in frame.iter.by_ref() { if !visited[successor] { stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) }); continue 'recurse; @@ -83,8 +83,58 @@ where G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, { - pub fn new(graph: &'graph G, start_node: G::Node) -> Self { - Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) } + pub fn new(graph: &'graph G) -> Self { + Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } + } + + /// Version of `push_start_node` that is convenient for chained + /// use. + pub fn with_start_node(mut self, start_node: G::Node) -> Self { + self.push_start_node(start_node); + self + } + + /// Pushes another start node onto the stack. If the node + /// has not already been visited, then you will be able to + /// walk its successors (and so forth) after the current + /// contents of the stack are drained. If multiple start nodes + /// are added into the walk, then their mutual successors + /// will all be walked. You can use this method once the + /// iterator has been completely drained to add additional + /// start nodes. + pub fn push_start_node(&mut self, start_node: G::Node) { + if self.visited.insert(start_node) { + self.stack.push(start_node); + } + } + + /// Searches all nodes reachable from the current start nodes. + /// This is equivalent to just invoke `next` repeatedly until + /// you get a `None` result. + pub fn complete_search(&mut self) { + for _ in self {} + } + + /// Returns true if node has been visited thus far. + /// A node is considered "visited" once it is pushed + /// onto the internal stack; it may not yet have been yielded + /// from the iterator. This method is best used after + /// the iterator is completely drained. + pub fn visited(&self, node: G::Node) -> bool { + self.visited.contains(node) + } +} + +impl std::fmt::Debug for DepthFirstSearch<'_, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut f = fmt.debug_set(); + for n in self.visited.iter() { + f.entry(&n); + } + f.finish() } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/iterate/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/iterate/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/iterate/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/iterate/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -20,3 +20,19 @@ assert!(!is_cyclic(&diamond_acyclic)); assert!(is_cyclic(&diamond_cyclic)); } + +#[test] +fn dfs() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); + + let result: Vec = DepthFirstSearch::new(&graph).with_start_node(0).collect(); + assert_eq!(result, vec![0, 2, 3, 1]); +} + +#[test] +fn dfs_debug() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); + let mut dfs = DepthFirstSearch::new(&graph).with_start_node(0); + dfs.complete_search(); + assert_eq!(format!("{{0, 1, 2, 3}}"), format!("{:?}", dfs)); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -32,7 +32,7 @@ where Self: WithNumNodes, { - iterate::DepthFirstSearch::new(self, from) + iterate::DepthFirstSearch::new(self).with_start_node(from) } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/scc/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/scc/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/scc/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/graph/scc/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ //! Also computes as the resulting DAG if each SCC is replaced with a //! node in the graph. This uses [Tarjan's algorithm]( //! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm) -//! that completes in *O(n)* time. +//! that completes in *O*(*n*) time. use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; @@ -405,6 +405,7 @@ /// Call this method when `inspect_node` has returned `None`. Having the /// caller decide avoids mutual recursion between the two methods and allows /// us to maintain an allocated stack for nodes on the path between calls. + #[instrument(skip(self, initial), level = "debug")] fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { struct VisitingNodeFrame { node: G::Node, @@ -451,7 +452,7 @@ Some(iter) => iter, None => { // This None marks that we still have the initialize this node's frame. - debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node); + debug!(?depth, ?node); debug_assert!(matches!(self.node_states[node], NodeState::NotVisited)); @@ -478,10 +479,7 @@ return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); let successor_walk = successors.by_ref().map(|successor_node| { - debug!( - "walk_unvisited_node: node = {:?} successor_ode = {:?}", - node, successor_node - ); + debug!(?node, ?successor_node); (successor_node, self.inspect_node(successor_node)) }); @@ -491,10 +489,7 @@ // Track the minimum depth we can reach. assert!(successor_min_depth <= depth); if successor_min_depth < *min_depth { - debug!( - "walk_unvisited_node: node = {:?} successor_min_depth = {:?}", - node, successor_min_depth - ); + debug!(?node, ?successor_min_depth); *min_depth = successor_min_depth; *min_cycle_root = successor_node; } @@ -503,16 +498,13 @@ Some(WalkReturn::Complete { scc_index: successor_scc_index }) => { // Push the completed SCC indices onto // the `successors_stack` for later. - debug!( - "walk_unvisited_node: node = {:?} successor_scc_index = {:?}", - node, successor_scc_index - ); + debug!(?node, ?successor_scc_index); successors_stack.push(successor_scc_index); } None => { let depth = depth + 1; - debug!("walk_node(depth = {:?}, node = {:?})", depth, successor_node); + debug!(?depth, ?successor_node); // Remember which node the return value will come from. frame.successor_node = successor_node; // Start a new stack frame the step into it. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,22 +7,20 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(allow_internal_unstable)] #![feature(array_windows)] #![feature(associated_type_bounds)] #![feature(auto_traits)] #![feature(bool_to_option)] -#![feature(const_panic)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(control_flow_enum)] #![feature(core_intrinsics)] #![feature(extend_one)] #![feature(hash_raw_entry)] #![feature(in_band_lifetimes)] -#![feature(iter_map_while)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] -#![cfg_attr(bootstrap, feature(min_type_alias_impl_trait))] -#![cfg_attr(not(bootstrap), feature(type_alias_impl_trait))] +#![feature(never_type)] +#![feature(type_alias_impl_trait)] #![feature(new_uninit)] #![feature(nll)] #![feature(once_cell)] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/obligation_forest/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/obligation_forest/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/obligation_forest/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/obligation_forest/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -390,7 +390,7 @@ .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) .collect(); - self.compress(|_| assert!(false)); + self.compress(|_| unreachable!()); errors } @@ -612,7 +612,7 @@ fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) { let orig_nodes_len = self.nodes.len(); let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec); - debug_assert!(node_rewrites.is_empty()); + assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; @@ -623,13 +623,13 @@ // self.nodes[0..index - dead_nodes] are the first remaining nodes // self.nodes[index - dead_nodes..index] are all dead // self.nodes[index..] are unchanged - for index in 0..orig_nodes_len { + for (index, node_rewrite) in node_rewrites.iter_mut().enumerate() { let node = &self.nodes[index]; match node.state.get() { NodeState::Pending | NodeState::Waiting => { if dead_nodes > 0 { self.nodes.swap(index, index - dead_nodes); - node_rewrites[index] -= dead_nodes; + *node_rewrite -= dead_nodes; } } NodeState::Done => { @@ -646,7 +646,7 @@ } // Extract the success stories. outcome_cb(&node.obligation); - node_rewrites[index] = orig_nodes_len; + *node_rewrite = orig_nodes_len; dead_nodes += 1; } NodeState::Error => { @@ -655,7 +655,7 @@ // check against. self.active_cache.remove(&node.obligation.as_cache_key()); self.insert_into_error_cache(index); - node_rewrites[index] = orig_nodes_len; + *node_rewrite = orig_nodes_len; dead_nodes += 1; } NodeState::Success => unreachable!(), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sharded.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sharded.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sharded.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sharded.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ use crate::fx::{FxHashMap, FxHasher}; use crate::sync::{Lock, LockGuard}; -use smallvec::SmallVec; use std::borrow::Borrow; use std::collections::hash_map::RawEntryMut; use std::hash::{Hash, Hasher}; @@ -37,24 +36,7 @@ impl Sharded { #[inline] pub fn new(mut value: impl FnMut() -> T) -> Self { - // Create a vector of the values we want - let mut values: SmallVec<[_; SHARDS]> = - (0..SHARDS).map(|_| CacheAligned(Lock::new(value()))).collect(); - - // Create an uninitialized array - let mut shards: mem::MaybeUninit<[CacheAligned>; SHARDS]> = - mem::MaybeUninit::uninit(); - - unsafe { - // Copy the values into our array - let first = shards.as_mut_ptr() as *mut CacheAligned>; - values.as_ptr().copy_to_nonoverlapping(first, SHARDS); - - // Ignore the content of the vector - values.set_len(0); - - Sharded { shards: shards.assume_init() } - } + Sharded { shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))) } } /// The shard is selected by hashing `val` with `FxHasher`. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sorted_map/index_map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sorted_map/index_map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sorted_map/index_map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sorted_map/index_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -75,7 +75,7 @@ /// /// If there are multiple items that are equivalent to `key`, they will be yielded in /// insertion order. - pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator { + pub fn get_by_key(&self, key: K) -> impl Iterator { self.get_by_key_enumerated(key).map(|(_, v)| v) } @@ -84,7 +84,7 @@ /// /// If there are multiple items that are equivalent to `key`, they will be yielded in /// insertion order. - pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator { + pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator { let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key); self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| { let (k, v) = &self.items[i]; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sorted_map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sorted_map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sorted_map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sorted_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ pub use index_map::SortedIndexMultiMap; /// `SortedMap` is a data structure with similar characteristics as BTreeMap but -/// slightly different trade-offs: lookup, insertion, and removal are O(log(N)) +/// slightly different trade-offs: lookup, insertion, and removal are *O*(log(*n*)) /// and elements can be iterated in order cheaply. /// /// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it @@ -205,10 +205,10 @@ R: RangeBounds, { let start = match range.start_bound() { - Bound::Included(ref k) => match self.lookup_index_for(k) { + Bound::Included(k) => match self.lookup_index_for(k) { Ok(index) | Err(index) => index, }, - Bound::Excluded(ref k) => match self.lookup_index_for(k) { + Bound::Excluded(k) => match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, }, @@ -216,11 +216,11 @@ }; let end = match range.end_bound() { - Bound::Included(ref k) => match self.lookup_index_for(k) { + Bound::Included(k) => match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, }, - Bound::Excluded(ref k) => match self.lookup_index_for(k) { + Bound::Excluded(k) => match self.lookup_index_for(k) { Ok(index) | Err(index) => index, }, Bound::Unbounded => self.data.len(), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sso/map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sso/map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sso/map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sso/map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,7 +31,7 @@ // // Missing HashMap API: // all hasher-related -// try_reserve (unstable) +// try_reserve // shrink_to (unstable) // drain_filter (unstable) // into_keys/into_values (unstable) @@ -257,11 +257,7 @@ pub fn remove(&mut self, key: &K) -> Option { match self { SsoHashMap::Array(array) => { - if let Some(index) = array.iter().position(|(k, _v)| k == key) { - Some(array.swap_remove(index).1) - } else { - None - } + array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1) } SsoHashMap::Map(map) => map.remove(key), } @@ -272,11 +268,7 @@ pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> { match self { SsoHashMap::Array(array) => { - if let Some(index) = array.iter().position(|(k, _v)| k == key) { - Some(array.swap_remove(index)) - } else { - None - } + array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index)) } SsoHashMap::Map(map) => map.remove_entry(key), } @@ -423,14 +415,14 @@ /// adapts Item of array reference iterator to Item of hashmap reference iterator. #[inline(always)] -fn adapt_array_ref_it(pair: &'a (K, V)) -> (&'a K, &'a V) { +fn adapt_array_ref_it(pair: &(K, V)) -> (&K, &V) { let (a, b) = pair; (a, b) } /// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator. #[inline(always)] -fn adapt_array_mut_it(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) { +fn adapt_array_mut_it(pair: &mut (K, V)) -> (&K, &mut V) { let (a, b) = pair; (a, b) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sso/set.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sso/set.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/sso/set.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/sso/set.rs 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ // // Missing HashSet API: // all hasher-related -// try_reserve (unstable) +// try_reserve // shrink_to (unstable) // drain_filter (unstable) // replace @@ -75,7 +75,7 @@ /// An iterator visiting all elements in arbitrary order. /// The iterator element type is `&'a T`. #[inline] - pub fn iter(&'a self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.into_iter() } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/stable_hasher.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/stable_hasher.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/stable_hasher.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/stable_hasher.rs 2021-11-29 19:27:11.000000000 +0000 @@ -209,6 +209,12 @@ impl_stable_hash_via_hash!(char); impl_stable_hash_via_hash!(()); +impl HashStable for ! { + fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) { + unreachable!() + } +} + impl HashStable for ::std::num::NonZeroU32 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.get().hash_stable(ctx, hasher) @@ -223,14 +229,14 @@ impl HashStable for f32 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u32 = unsafe { ::std::mem::transmute(*self) }; + let val: u32 = self.to_bits(); val.hash_stable(ctx, hasher); } } impl HashStable for f64 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u64 = unsafe { ::std::mem::transmute(*self) }; + let val: u64 = self.to_bits(); val.hash_stable(ctx, hasher); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/stack.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/stack.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/stack.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/stack.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,6 +5,7 @@ // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then // on. This flag has performance relevant characteristics. Don't set it too high. +#[allow(clippy::identity_op)] const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/steal.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/steal.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/steal.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/steal.rs 2021-11-29 19:27:11.000000000 +0000 @@ -33,10 +33,11 @@ #[track_caller] pub fn borrow(&self) -> MappedReadGuard<'_, T> { - ReadGuard::map(self.value.borrow(), |opt| match *opt { - None => panic!("attempted to read from stolen value"), - Some(ref v) => v, - }) + let borrow = self.value.borrow(); + if borrow.is_none() { + panic!("attempted to read from stolen value: {}", std::any::type_name::()); + } + ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) } #[track_caller] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/thin_vec.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/thin_vec.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/thin_vec.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/thin_vec.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ use std::iter::FromIterator; -/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`). +/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`). /// The `Option>` wrapping allows us to represent a zero sized vector with `None`, /// which uses only a single (null) pointer. #[derive(Clone, Encodable, Decodable, Debug)] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/tiny_list.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/tiny_list.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/tiny_list.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/tiny_list.rs 2021-11-29 19:27:11.000000000 +0000 @@ -48,7 +48,7 @@ #[inline] pub fn contains(&self, data: &T) -> bool { let mut elem = self.head.as_ref(); - while let Some(ref e) = elem { + while let Some(e) = elem { if &e.data == data { return true; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/vec_linked_list.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/vec_linked_list.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_data_structures/src/vec_linked_list.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_data_structures/src/vec_linked_list.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,8 @@ pub fn iter( first: Option, - links: &'a Ls, -) -> impl Iterator + 'a + links: &Ls, +) -> impl Iterator + '_ where Ls: Links, { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_driver/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_driver/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_driver/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_driver/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_driver" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["dylib"] @@ -9,7 +9,7 @@ [dependencies] libc = "0.2" atty = "0.2" -tracing = { version = "0.1.25" } +tracing = { version = "0.1.28" } tracing-subscriber = { version = "0.2.16", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } tracing-tree = "0.1.9" rustc_middle = { path = "../rustc_middle" } @@ -22,7 +22,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_metadata = { path = "../rustc_metadata" } -rustc_mir = { path = "../rustc_mir" } +rustc_const_eval = { path = "../rustc_const_eval" } rustc_parse = { path = "../rustc_parse" } rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_save_analysis = { path = "../rustc_save_analysis" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_driver/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_driver/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_driver/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_driver/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -25,12 +25,12 @@ use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; use rustc_metadata::locator; -use rustc_middle::middle::cstore::MetadataLoader; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; use rustc_serialize::json::{self, ToJson}; use rustc_session::config::{nightly_options, CG_OPTIONS, DB_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}; +use rustc_session::cstore::MetadataLoader; use rustc_session::getopts; use rustc_session::lint::{Lint, LintId}; use rustc_session::{config, DiagnosticOutput, Session}; @@ -128,7 +128,7 @@ } pub fn diagnostics_registry() -> Registry { - Registry::new(&rustc_error_codes::DIAGNOSTICS) + Registry::new(rustc_error_codes::DIAGNOSTICS) } /// This is the primary entry point for rustc. @@ -265,8 +265,8 @@ &***compiler.codegen_backend(), compiler.session(), None, - &compiler.output_dir(), - &compiler.output_file(), + compiler.output_dir(), + compiler.output_file(), ); if should_stop == Compilation::Stop { @@ -330,7 +330,7 @@ let krate = queries.parse()?.take(); pretty::print_after_parsing( sess, - &compiler.input(), + compiler.input(), &krate, *ppm, compiler.output_file().as_ref().map(|p| &**p), @@ -356,7 +356,7 @@ // Lint plugins are registered; now we can process command line flags. if sess.opts.describe_lints { - describe_lints(&sess, &lint_store, true); + describe_lints(sess, lint_store, true); return early_exit(); } } @@ -388,7 +388,7 @@ save::process_crate( tcx, &crate_name, - &compiler.input(), + compiler.input(), None, DumpHandler::new( compiler.output_dir().as_ref().map(|p| &**p), @@ -598,7 +598,7 @@ if let Input::File(file) = compiler.input() { // FIXME: #![crate_type] and #![crate_name] support not implemented yet sess.init_crate_types(collect_crate_types(sess, &[])); - let outputs = compiler.build_output_filenames(&sess, &[]); + let outputs = compiler.build_output_filenames(sess, &[]); let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| { sess.fatal(&format!("failed to read rlink file: {}", err)); }); @@ -606,7 +606,7 @@ json::decode(&rlink_data).unwrap_or_else(|err| { sess.fatal(&format!("failed to decode rlink: {}", err)); }); - let result = compiler.codegen_backend().link(&sess, codegen_results, &outputs); + let result = compiler.codegen_backend().link(sess, codegen_results, &outputs); abort_on_err(result, sess); } else { sess.fatal("rlink must be a file") @@ -677,10 +677,7 @@ println!("{}", targets.join("\n")); } Sysroot => println!("{}", sess.sysroot.display()), - TargetLibdir => println!( - "{}", - sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display() - ), + TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()), TargetSpec => println!("{}", sess.target.to_json().pretty()), FileNames | CrateName => { let input = input.unwrap_or_else(|| { @@ -897,9 +894,9 @@ }; println!("Lint groups provided by rustc:\n"); - println!(" {} {}", padded("name"), "sub-lints"); - println!(" {} {}", padded("----"), "---------"); - println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings"); + println!(" {} sub-lints", padded("name")); + println!(" {} ---------", padded("----")); + println!(" {} all lints that are set to issue warnings", padded("warnings")); let print_lint_groups = |lints: Vec<(&'static str, Vec)>| { for (name, to) in lints { @@ -1220,7 +1217,7 @@ } for note in &xs { - handler.note_without_error(¬e); + handler.note_without_error(note); } // If backtraces are enabled, also print the query stack @@ -1256,12 +1253,16 @@ /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var /// other than `RUSTC_LOG`. pub fn init_env_logger(env: &str) { - // Don't register a dispatcher if there's no filter to print anything - match std::env::var(env) { - Err(_) => return, - Ok(s) if s.is_empty() => return, - Ok(_) => {} - } + use tracing_subscriber::{ + filter::{self, EnvFilter, LevelFilter}, + layer::SubscriberExt, + }; + + let filter = match std::env::var(env) { + Ok(env) => EnvFilter::new(env), + _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)), + }; + let color_logs = match std::env::var(String::from(env) + "_COLOR") { Ok(value) => match value.as_ref() { "always" => true, @@ -1281,7 +1282,7 @@ "non-Unicode log color value: expected one of always, never, or auto", ), }; - let filter = tracing_subscriber::EnvFilter::from_env(env); + let layer = tracing_tree::HierarchicalLayer::default() .with_writer(io::stderr) .with_indent_lines(true) @@ -1291,7 +1292,6 @@ #[cfg(parallel_compiler)] let layer = layer.with_thread_ids(true).with_thread_names(true); - use tracing_subscriber::layer::SubscriberExt; let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); tracing::subscriber::set_global_default(subscriber).unwrap(); } @@ -1329,7 +1329,7 @@ std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap()) as *mut libc::c_void; alt_stack.ss_size = ALT_STACK_SIZE; - libc::sigaltstack(&mut alt_stack, std::ptr::null_mut()); + libc::sigaltstack(&alt_stack, std::ptr::null_mut()); let mut sa: libc::sigaction = std::mem::zeroed(); sa.sa_sigaction = print_stack_trace as libc::sighandler_t; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_driver/src/pretty.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_driver/src/pretty.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_driver/src/pretty.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_driver/src/pretty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,8 @@ use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; use rustc_middle::hir::map as hir_map; +use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_mir::util::{write_mir_graphviz, write_mir_pretty}; use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}; use rustc_session::Session; use rustc_span::symbol::Ident; @@ -88,7 +88,7 @@ /// Produces the pretty-print annotation object. /// /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its super-traits.) + /// an object for one of its supertraits.) fn pp_ann(&self) -> &dyn pprust::PpAnn; } @@ -104,7 +104,7 @@ /// Produces the pretty-print annotation object. /// /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its super-traits.) + /// an object for one of its supertraits.) fn pp_ann(&self) -> &dyn pprust_hir::PpAnn; } @@ -296,7 +296,7 @@ impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> { fn sess(&self) -> &Session { - &self.tcx.sess + self.tcx.sess } fn hir_map(&self) -> Option> { @@ -347,8 +347,7 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) { let src_name = input.source_name(); let src = String::clone( - &sess - .source_map() + sess.source_map() .get_source_file(&src_name) .expect("get_source_file") .src @@ -489,7 +488,7 @@ let mut out = String::new(); abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess); debug!("pretty printing THIR tree"); - for did in tcx.body_owners() { + for did in tcx.hir().body_owners() { let _ = writeln!( out, "{:?}:\n{}\n", diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ [package] name = "rustc_error_codes" version = "0.0.0" -edition = "2018" +edition = "2021" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0071.md rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0071.md --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0071.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0071.md 2021-11-29 19:27:11.000000000 +0000 @@ -15,13 +15,13 @@ For example, the code above can be fixed to: ``` -enum Foo { - FirstValue(i32) -} +type U32 = u32; +let t: U32 = 4; +``` -fn main() { - let u = Foo::FirstValue(0i32); +or: - let t = 4; -} +``` +struct U32 { value: u32 } +let t = U32 { value: 4 }; ``` diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0183.md rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0183.md --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0183.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0183.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +Manual implemetation of a `Fn*` trait. + +Erroneous code example: + +```compile_fail,E0183 +struct MyClosure { + foo: i32 +} + +impl FnOnce<()> for MyClosure { // error + type Output = (); + extern "rust-call" fn call_once(self, args: ()) -> Self::Output { + println!("{}", self.foo); + } +} +``` + +Manually implementing `Fn`, `FnMut` or `FnOnce` is unstable +and requires `#![feature(fn_traits, unboxed_closures)]`. + +``` +#![feature(fn_traits, unboxed_closures)] + +struct MyClosure { + foo: i32 +} + +impl FnOnce<()> for MyClosure { // ok! + type Output = (); + extern "rust-call" fn call_once(self, args: ()) -> Self::Output { + println!("{}", self.foo); + } +} +``` + +The argumements must be a tuple representing the argument list. +For more info, see the [tracking issue][iss29625]: + +[iss29625]: https://github.com/rust-lang/rust/issues/29625 diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0222.md rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0222.md --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0222.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0222.md 2021-11-29 19:27:11.000000000 +0000 @@ -16,9 +16,9 @@ fn dent_object(c: dyn BoxCar) {} // Invalid constraint ``` -In this example, `BoxCar` has two super-traits: `Vehicle` and `Box`. Both of +In this example, `BoxCar` has two supertraits: `Vehicle` and `Box`. Both of these traits define an associated type `Color`. `BoxCar` inherits two types -with that name from both super-traits. Because of this, we need to use the +with that name from both supertraits. Because of this, we need to use the fully qualified path syntax to refer to the appropriate `Color` associated type, either `::Color` or `::Color`, but this syntax is not allowed to be used in a function signature. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0439.md rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0439.md --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0439.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0439.md 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + The length of the platform-intrinsic function `simd_shuffle` wasn't specified. Erroneous code example: -```compile_fail,E0439 +```ignore (no longer emitted) #![feature(platform_intrinsics)] extern "platform-intrinsic" { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0464.md rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0464.md --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0464.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0464.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +The compiler found multiple library files with the requested crate name. + +This error can occur in several different cases -- for example, when using +`extern crate` or passing `--extern` options without crate paths. It can also be +caused by caching issues with the build directory, in which case `cargo clean` +may help. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0482.md rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0482.md --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0482.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes/E0482.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,73 @@ +A lifetime of a returned value does not outlive the function call. + +Erroneous code example: + +```compile_fail,E0482 +fn prefix<'a>( + words: impl Iterator +) -> impl Iterator { // error! + words.map(|v| format!("foo-{}", v)) +} +``` + +To fix this error, make the lifetime of the returned value explicit: + +``` +fn prefix<'a>( + words: impl Iterator + 'a +) -> impl Iterator + 'a { // ok! + words.map(|v| format!("foo-{}", v)) +} +``` + +The [`impl Trait`] feature in this example uses an implicit `'static` lifetime +restriction in the returned type. However the type implementing the `Iterator` +passed to the function lives just as long as `'a`, which is not long enough. + +The solution involves adding lifetime bound to both function argument and +the return value to make sure that the values inside the iterator +are not dropped when the function goes out of the scope. + +An alternative solution would be to guarantee that the `Item` references +in the iterator are alive for the whole lifetime of the program. + +``` +fn prefix( + words: impl Iterator +) -> impl Iterator { // ok! + words.map(|v| format!("foo-{}", v)) +} +``` + +A similar lifetime problem might arise when returning closures: + +```compile_fail,E0482 +fn foo( + x: &mut Vec +) -> impl FnMut(&mut Vec) -> &[i32] { // error! + |y| { + y.append(x); + y + } +} +``` + +Analogically, a solution here is to use explicit return lifetime +and move the ownership of the variable to the closure. + +``` +fn foo<'a>( + x: &'a mut Vec +) -> impl FnMut(&mut Vec) -> &[i32] + 'a { // ok! + move |y| { + y.append(x); + y + } +} +``` + +To better understand the lifetime treatment in the [`impl Trait`], +please see the [RFC 1951]. + +[`impl Trait`]: https://doc.rust-lang.org/reference/types/impl-trait.html +[RFC 1951]: https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_error_codes/src/error_codes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -92,6 +92,7 @@ E0165: include_str!("./error_codes/E0165.md"), E0170: include_str!("./error_codes/E0170.md"), E0178: include_str!("./error_codes/E0178.md"), +E0183: include_str!("./error_codes/E0183.md"), E0184: include_str!("./error_codes/E0184.md"), E0185: include_str!("./error_codes/E0185.md"), E0186: include_str!("./error_codes/E0186.md"), @@ -237,11 +238,13 @@ E0458: include_str!("./error_codes/E0458.md"), E0459: include_str!("./error_codes/E0459.md"), E0463: include_str!("./error_codes/E0463.md"), +E0464: include_str!("./error_codes/E0464.md"), E0466: include_str!("./error_codes/E0466.md"), E0468: include_str!("./error_codes/E0468.md"), E0469: include_str!("./error_codes/E0469.md"), E0477: include_str!("./error_codes/E0477.md"), E0478: include_str!("./error_codes/E0478.md"), +E0482: include_str!("./error_codes/E0482.md"), E0491: include_str!("./error_codes/E0491.md"), E0492: include_str!("./error_codes/E0492.md"), E0493: include_str!("./error_codes/E0493.md"), @@ -511,7 +514,6 @@ // E0173, // manual implementations of unboxed closure traits are experimental // E0174, // E0182, // merged into E0229 - E0183, // E0187, // cannot infer the kind of the closure // E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object @@ -586,7 +588,6 @@ E0460, // found possibly newer version of crate `..` E0461, // couldn't find crate `..` with expected target triple .. E0462, // found staticlib `..` instead of rlib or dylib - E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found // E0467, removed // E0470, removed @@ -599,7 +600,6 @@ // E0479, // the type `..` (provided as the value of a type parameter) is... // E0480, // lifetime of method receiver does not outlive the method call // E0481, // lifetime of function argument does not outlive the function call - E0482, // lifetime of return value does not outlive the function call // E0483, // lifetime of operand does not outlive the operation // E0484, // reference is not valid at the time of borrow // E0485, // automatically reference is not valid at the time of borrow diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_errors" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/src/diagnostic_builder.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/src/diagnostic_builder.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/src/diagnostic_builder.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/src/diagnostic_builder.rs 2021-11-29 19:27:11.000000000 +0000 @@ -242,6 +242,7 @@ sp: S, msg: &str, ) -> &mut Self); + forward!(pub fn set_is_lint(&mut self,) -> &mut Self); /// See [`Diagnostic::multipart_suggestion()`]. pub fn multipart_suggestion( @@ -257,6 +258,20 @@ self } + /// See [`Diagnostic::multipart_suggestion()`]. + pub fn multipart_suggestion_verbose( + &mut self, + msg: &str, + suggestion: Vec<(Span, String)>, + applicability: Applicability, + ) -> &mut Self { + if !self.0.allow_suggestions { + return self; + } + self.0.diagnostic.multipart_suggestion_verbose(msg, suggestion, applicability); + self + } + /// See [`Diagnostic::tool_only_multipart_suggestion()`]. pub fn tool_only_multipart_suggestion( &mut self, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/src/diagnostic.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/src/diagnostic.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/src/diagnostic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/src/diagnostic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,9 +9,10 @@ use rustc_serialize::json::Json; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; +use std::hash::{Hash, Hasher}; #[must_use] -#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] +#[derive(Clone, Debug, Encodable, Decodable)] pub struct Diagnostic { pub level: Level, pub message: Vec<(String, Style)>, @@ -24,6 +25,10 @@ /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of /// `span` if there is one. Otherwise, it is `DUMMY_SP`. pub sort_span: Span, + + /// If diagnostic is from Lint, custom hash function ignores notes + /// otherwise hash is based on the all the fields + pub is_lint: bool, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] @@ -69,6 +74,10 @@ pub fn highlighted>(t: S) -> DiagnosticStyledString { DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) } + + pub fn content(&self) -> String { + self.0.iter().map(|x| x.content()).collect::() + } } #[derive(Debug, PartialEq, Eq)] @@ -77,6 +86,14 @@ Highlighted(String), } +impl StringPart { + pub fn content(&self) -> &str { + match self { + &StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s, + } + } +} + impl Diagnostic { pub fn new(level: Level, message: &str) -> Self { Diagnostic::new_with_code(level, None, message) @@ -91,6 +108,7 @@ children: vec![], suggestions: vec![], sort_span: DUMMY_SP, + is_lint: false, } } @@ -298,6 +316,21 @@ ) } + /// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic. + /// In other words, multiple changes need to be applied as part of this suggestion. + pub fn multipart_suggestion_verbose( + &mut self, + msg: &str, + suggestion: Vec<(Span, String)>, + applicability: Applicability, + ) -> &mut Self { + self.multipart_suggestion_with_style( + msg, + suggestion, + applicability, + SuggestionStyle::ShowAlways, + ) + } /// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`]. pub fn multipart_suggestion_with_style( &mut self, @@ -558,6 +591,11 @@ self } + pub fn set_is_lint(&mut self) -> &mut Self { + self.is_lint = true; + self + } + pub fn code(&mut self, s: DiagnosticId) -> &mut Self { self.code = Some(s); self @@ -617,6 +655,42 @@ let sub = SubDiagnostic { level, message, span, render_span }; self.children.push(sub); } + + /// Fields used for Hash, and PartialEq trait + fn keys( + &self, + ) -> ( + &Level, + &Vec<(String, Style)>, + &Option, + &MultiSpan, + &Vec, + Option<&Vec>, + ) { + ( + &self.level, + &self.message, + &self.code, + &self.span, + &self.suggestions, + (if self.is_lint { None } else { Some(&self.children) }), + ) + } +} + +impl Hash for Diagnostic { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.keys().hash(state); + } +} + +impl PartialEq for Diagnostic { + fn eq(&self, other: &Self) -> bool { + self.keys() == other.keys() + } } impl SubDiagnostic { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/src/emitter.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/src/emitter.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/src/emitter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/src/emitter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2054,8 +2054,26 @@ MAX_DIGITS } +// We replace some characters so the CLI output is always consistent and underlines aligned. +const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[ + ('\t', " "), // We do our own tab replacement + ('\u{202A}', ""), // The following unicode text flow control characters are inconsistently + ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk + ('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always. + ('\u{202E}', ""), + ('\u{2066}', ""), + ('\u{2067}', ""), + ('\u{2068}', ""), + ('\u{202C}', ""), + ('\u{2069}', ""), +]; + fn replace_tabs(str: &str) -> String { - str.replace('\t', " ") + let mut s = str.to_string(); + for (c, replacement) in OUTPUT_REPLACEMENTS { + s = s.replace(*c, replacement); + } + s } fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { @@ -2308,7 +2326,7 @@ let found = match sm.span_to_snippet(sp) { Ok(snippet) => snippet, Err(e) => { - warn!("Invalid span {:?}. Err={:?}", sp, e); + warn!(error = ?e, "Invalid span {:?}", sp); return false; } }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_errors/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_errors/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,14 +9,15 @@ #![feature(format_args_capture)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + pub use emitter::ColorConfig; -use tracing::debug; use Level::*; use emitter::{is_case_difference, Emitter, EmitterWriter}; @@ -340,7 +341,7 @@ }); buf.push_str(&part.snippet); let cur_hi = sm.lookup_char_pos(part.span.hi()); - if prev_hi.line == cur_lo.line { + if prev_hi.line == cur_lo.line && cur_hi.line == cur_lo.line { // Account for the difference between the width of the current code and the // snippet being suggested, so that the *later* suggestions are correctly // aligned on the screen. @@ -1029,15 +1030,13 @@ let mut error_codes = self .emitted_diagnostic_codes .iter() - .filter_map(|x| { - match &x { + .filter_map(|x| match &x { DiagnosticId::Error(s) - if let Ok(Some(_explanation)) = registry.try_find_description(s) => + if registry.try_find_description(s).map_or(false, |o| o.is_some()) => { Some(s.clone()) } _ => None, - } }) .collect::>(); if !error_codes.is_empty() { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_expand" version = "0.0.0" -edition = "2018" +edition = "2021" build = false [lib] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/base.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/base.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/base.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/base.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,12 +10,12 @@ use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; -use rustc_errors::{DiagnosticBuilder, ErrorReported}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::BuiltinLintDiagnostics; use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; use rustc_session::{parse::ParseSess, Limit, Session}; -use rustc_span::def_id::{CrateNum, DefId}; +use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::source_map::SourceMap; @@ -843,6 +843,7 @@ pub trait ResolverExpand { fn next_node_id(&mut self) -> NodeId; + fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId; fn resolve_dollar_crates(&mut self); fn visit_ast_fragment_with_placeholders( @@ -1136,13 +1137,15 @@ } /// Extracts a string literal from the macro expanded version of `expr`, -/// emitting `err_msg` if `expr` is not a string literal. This does not stop -/// compilation on error, merely emits a non-fatal error and returns `None`. +/// returning a diagnostic error of `err_msg` if `expr` is not a string literal. +/// The returned bool indicates whether an applicable suggestion has already been +/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)` +/// indicates that an ast error was encountered. pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, expr: P, err_msg: &str, -) -> Result<(Symbol, ast::StrStyle, Span), Option>> { +) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> { // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); @@ -1150,14 +1153,27 @@ Err(match expr.kind { ast::ExprKind::Lit(ref l) => match l.kind { ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)), + ast::LitKind::ByteStr(_) => { + let mut err = cx.struct_span_err(l.span, err_msg); + err.span_suggestion( + expr.span.shrink_to_lo(), + "consider removing the leading `b`", + String::new(), + Applicability::MaybeIncorrect, + ); + Some((err, true)) + } ast::LitKind::Err(_) => None, - _ => Some(cx.struct_span_err(l.span, err_msg)), + _ => Some((cx.struct_span_err(l.span, err_msg), false)), }, ast::ExprKind::Err => None, - _ => Some(cx.struct_span_err(expr.span, err_msg)), + _ => Some((cx.struct_span_err(expr.span, err_msg), false)), }) } +/// Extracts a string literal from the macro expanded version of `expr`, +/// emitting `err_msg` if `expr` is not a string literal. This does not stop +/// compilation on error, merely emits a non-fatal error and returns `None`. pub fn expr_to_string( cx: &mut ExtCtxt<'_>, expr: P, @@ -1165,7 +1181,7 @@ ) -> Option<(Symbol, ast::StrStyle)> { expr_to_spanned_string(cx, expr, err_msg) .map_err(|err| { - err.map(|mut err| { + err.map(|(mut err, _)| { err.emit(); }) }) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/config.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/config.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/config.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/config.rs 2021-11-29 19:27:11.000000000 +0000 @@ -171,7 +171,7 @@ } if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() { - if allowed.iter().find(|&f| name.as_str() == *f).is_none() { + if allowed.iter().all(|f| name.as_str() != *f) { struct_span_err!( span_handler, mi.span(), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/expand.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/expand.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/expand.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/expand.rs 2021-11-29 19:27:11.000000000 +0000 @@ -588,7 +588,7 @@ // Resolve `$crate`s in the fragment for pretty-printing. self.cx.resolver.resolve_dollar_crates(); - let invocations = { + let mut invocations = { let mut collector = InvocationCollector { // Non-derive macro invocations cannot see the results of cfg expansion - they // will either be removed along with the item, or invoked before the cfg/cfg_attr @@ -613,6 +613,19 @@ self.cx .resolver .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment); + + if self.cx.sess.opts.debugging_opts.incremental_relative_spans { + for (invoc, _) in invocations.iter_mut() { + let expn_id = invoc.expansion_data.id; + let parent_def = self.cx.resolver.invocation_parent(expn_id); + let span = match &mut invoc.kind { + InvocationKind::Bang { ref mut span, .. } => span, + InvocationKind::Attr { attr, .. } => &mut attr.span, + InvocationKind::Derive { path, .. } => &mut path.span, + }; + *span = span.with_parent(Some(parent_def)); + } + } } (fragment, invocations) @@ -620,14 +633,18 @@ fn error_recursion_limit_reached(&mut self) { let expn_data = self.cx.current_expansion.id.expn_data(); - let suggested_limit = self.cx.ecfg.recursion_limit * 2; + let suggested_limit = match self.cx.ecfg.recursion_limit { + Limit(0) => Limit(2), + limit => limit * 2, + }; self.cx .struct_span_err( expn_data.call_site, &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()), ) .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", suggested_limit, self.cx.ecfg.crate_name, )) .emit(); @@ -1007,12 +1024,10 @@ placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis) } - fn collect_bang( - &mut self, - mac: ast::MacCall, - span: Span, - kind: AstFragmentKind, - ) -> AstFragment { + fn collect_bang(&mut self, mac: ast::MacCall, kind: AstFragmentKind) -> AstFragment { + // cache the macro call span so that it can be + // easily adjusted for incremental compilation + let span = mac.span(); self.collect(kind, InvocationKind::Bang { mac, span }) } @@ -1070,25 +1085,19 @@ let MacCallStmt { mac, style, attrs, .. } = mac.into_inner(); Ok((style == MacStmtStyle::Semicolon, mac, attrs.into())) } - StmtKind::Item(ref item) if matches!(item.kind, ItemKind::MacCall(..)) => { - match stmt.kind { - StmtKind::Item(item) => match item.into_inner() { - ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { - Ok((mac.args.need_semicolon(), mac, attrs)) - } - _ => unreachable!(), - }, + StmtKind::Item(item) if matches!(item.kind, ItemKind::MacCall(..)) => { + match item.into_inner() { + ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { + Ok((mac.args.need_semicolon(), mac, attrs)) + } _ => unreachable!(), } } - StmtKind::Semi(ref expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => { - match stmt.kind { - StmtKind::Semi(expr) => match expr.into_inner() { - ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => { - Ok((mac.args.need_semicolon(), mac, attrs.into())) - } - _ => unreachable!(), - }, + StmtKind::Semi(expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => { + match expr.into_inner() { + ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => { + Ok((mac.args.need_semicolon(), mac, attrs.into())) + } _ => unreachable!(), } } @@ -1205,7 +1214,7 @@ if let ast::ExprKind::MacCall(mac) = expr.kind { self.check_attributes(&expr.attrs, &mac); - self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner() + self.collect_bang(mac, AstFragmentKind::Expr).make_expr().into_inner() } else { assign_id!(self, &mut expr.id, || { ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); @@ -1301,7 +1310,7 @@ if let ast::ExprKind::MacCall(mac) = expr.kind { self.check_attributes(&expr.attrs, &mac); - self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr) + self.collect_bang(mac, AstFragmentKind::OptExpr) .make_opt_expr() .map(|expr| expr.into_inner()) } else { @@ -1322,9 +1331,7 @@ } visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { - PatKind::MacCall(mac) => { - self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat() - } + PatKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Pat).make_pat(), _ => unreachable!(), }); } @@ -1343,12 +1350,10 @@ .make_stmts(); } - let span = stmt.span; match self.take_stmt_bang(stmt) { Ok((add_semicolon, mac, attrs)) => { self.check_attributes(&attrs, &mac); - let mut stmts = - self.collect_bang(mac, span, AstFragmentKind::Stmts).make_stmts(); + let mut stmts = self.collect_bang(mac, AstFragmentKind::Stmts).make_stmts(); // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. @@ -1416,7 +1421,7 @@ item.attrs = attrs; item.and_then(|item| match item.kind { ItemKind::MacCall(mac) => { - self.collect_bang(mac, span, AstFragmentKind::Items).make_items() + self.collect_bang(mac, AstFragmentKind::Items).make_items() } _ => unreachable!(), }) @@ -1525,9 +1530,9 @@ ast::AssocItemKind::MacCall(ref mac) => { self.check_attributes(&item.attrs, &mac); item.and_then(|item| match item.kind { - ast::AssocItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::TraitItems) - .make_trait_items(), + ast::AssocItemKind::MacCall(mac) => { + self.collect_bang(mac, AstFragmentKind::TraitItems).make_trait_items() + } _ => unreachable!(), }) } @@ -1550,9 +1555,9 @@ ast::AssocItemKind::MacCall(ref mac) => { self.check_attributes(&item.attrs, &mac); item.and_then(|item| match item.kind { - ast::AssocItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::ImplItems) - .make_impl_items(), + ast::AssocItemKind::MacCall(mac) => { + self.collect_bang(mac, AstFragmentKind::ImplItems).make_impl_items() + } _ => unreachable!(), }) } @@ -1569,9 +1574,7 @@ }; visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { - ast::TyKind::MacCall(mac) => { - self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty() - } + ast::TyKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Ty).make_ty(), _ => unreachable!(), }); } @@ -1596,9 +1599,9 @@ ast::ForeignItemKind::MacCall(ref mac) => { self.check_attributes(&foreign_item.attrs, &mac); foreign_item.and_then(|item| match item.kind { - ast::ForeignItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::ForeignItems) - .make_foreign_items(), + ast::ForeignItemKind::MacCall(mac) => { + self.collect_bang(mac, AstFragmentKind::ForeignItems).make_foreign_items() + } _ => unreachable!(), }) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -#![cfg_attr(bootstrap, feature(bindings_after_at))] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(destructuring_assignment)] @@ -9,7 +8,6 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_span)] #![feature(try_blocks)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard #![recursion_limit = "256"] #[macro_use] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/mbe/quoted.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/mbe/quoted.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/mbe/quoted.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/mbe/quoted.rs 2021-11-29 19:27:11.000000000 +0000 @@ -72,7 +72,7 @@ // this with just `span.edition()`. A // `SyntaxContext::root()` from the current crate will // have the edition of the current crate, and a - // `SyntaxxContext::root()` from a foreign crate will + // `SyntaxContext::root()` from a foreign crate will // have the edition of that crate (which we manually // retrieve via the `edition` parameter). if span.ctxt() == SyntaxContext::root() { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/module.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/module.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/module.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/module.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,6 +3,7 @@ use rustc_ast::{token, Attribute, Inline, Item}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_parse::new_parser_from_file; +use rustc_parse::validate_attr; use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; @@ -168,7 +169,25 @@ dir_path: &Path, ) -> Option { // Extract path string from first `#[path = "path_string"]` attribute. - let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?.as_str(); + let first_path = attrs.iter().find(|at| at.has_name(sym::path))?; + let path_string = match first_path.value_str() { + Some(s) => s.as_str(), + None => { + // This check is here mainly to catch attempting to use a macro, + // such as #[path = concat!(...)]. This isn't currently supported + // because otherwise the InvocationCollector would need to defer + // loading a module until the #[path] attribute was expanded, and + // it doesn't support that (and would likely add a bit of + // complexity). Usually bad forms are checked in AstValidator (via + // `check_builtin_attribute`), but by the time that runs the macro + // is expanded, and it doesn't give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + first_path, + sym::path, + ); + } + }; // On windows, the base path might have the form // `\\?\foo\bar` in which case it does not tolerate diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/proc_macro_server.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/proc_macro_server.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_expand/src/proc_macro_server.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_expand/src/proc_macro_server.rs 2021-11-29 19:27:11.000000000 +0000 @@ -577,7 +577,7 @@ } // Synthesize a new symbol that includes the minus sign. - let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]); + let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]); lit = token::Lit::new(lit.kind, symbol, lit.suffix); } @@ -745,7 +745,7 @@ self.sess.source_map().lookup_char_pos(span.lo()).file } fn parent(&mut self, span: Self::Span) -> Option { - span.parent() + span.parent_callsite() } fn source(&mut self, span: Self::Span) -> Self::Span { span.source_callsite() @@ -758,6 +758,12 @@ let loc = self.sess.source_map().lookup_char_pos(span.hi()); LineColumn { line: loc.line, column: loc.col.to_usize() } } + fn before(&mut self, span: Self::Span) -> Self::Span { + span.shrink_to_lo() + } + fn after(&mut self, span: Self::Span) -> Self::Span { + span.shrink_to_hi() + } fn join(&mut self, first: Self::Span, second: Self::Span) -> Option { let self_loc = self.sess.source_map().lookup_char_pos(first.lo()); let other_loc = self.sess.source_map().lookup_char_pos(second.lo()); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_feature" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/accepted.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/accepted.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/accepted.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/accepted.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,6 @@ since: $ver, issue: to_nonzero($issue), edition: None, - description: concat!($($doc,)*), } ),+ ]; @@ -294,6 +293,10 @@ (accepted, const_fn_transmute, "1.56.0", Some(53605), None), /// Allows accessing fields of unions inside `const` functions. (accepted, const_fn_union, "1.56.0", Some(51909), None), + /// Allows macro attributes to observe output of `#[derive]`. + (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None), + /// Allows panicking during const eval (producing compile-time errors). + (accepted, const_panic, "1.57.0", Some(51999), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/active.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/active.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/active.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/active.rs 2021-11-29 19:27:11.000000000 +0000 @@ -37,7 +37,6 @@ since: $ver, issue: to_nonzero($issue), edition: $edition, - description: concat!($($doc,)*), } ),+]; @@ -426,9 +425,6 @@ /// Allows using the `amdgpu-kernel` ABI. (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - /// Allows panicking during const eval (producing compile-time errors). - (active, const_panic, "1.30.0", Some(51999), None), - /// Allows `#[marker]` on certain traits allowing overlapping implementations. (active, marker_trait_attr, "1.30.0", Some(29864), None), @@ -596,9 +592,6 @@ /// Lessens the requirements for structs to implement `Unsize`. (active, relaxed_struct_unsize, "1.51.0", Some(81793), None), - /// Allows macro attributes to observe output of `#[derive]`. - (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None), - /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995), None), @@ -679,6 +672,21 @@ /// Allows `let...else` statements. (active, let_else, "1.56.0", Some(87335), None), + /// Allows the `#[must_not_suspend]` attribute. + (active, must_not_suspend, "1.57.0", Some(83310), None), + + /// Allows `#[track_caller]` on closures and generators. + (active, closure_track_caller, "1.57.0", Some(87417), None), + + /// Allows `#[doc(cfg_hide(...))]`. + (active, doc_cfg_hide, "1.57.0", Some(43781), None), + + /// Allows using the `non_exhaustive_omitted_patterns` lint. + (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None), + + /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. + (active, doc_auto_cfg, "1.57.0", Some(43781), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/builtin_attrs.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/builtin_attrs.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/builtin_attrs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/builtin_attrs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -202,6 +202,10 @@ ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")), + gated!( + must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), must_not_suspend, + experimental!(must_not_suspend) + ), // FIXME(#14407) ungated!( deprecated, Normal, @@ -453,6 +457,9 @@ ), // Enumerates "identity-like" conversion methods to suggest on type mismatch. rustc_attr!(rustc_conversion_suggestion, Normal, template!(Word), INTERNAL_UNSTABLE), + // Prevents field reads in the marked trait or method to be considered + // during dead code analysis. + rustc_attr!(rustc_trivial_field_reads, Normal, template!(Word), INTERNAL_UNSTABLE), // ========================================================================== // Internal attributes, Const related: @@ -460,6 +467,8 @@ rustc_attr!(rustc_promotable, Normal, template!(Word), IMPL_DETAIL), rustc_attr!(rustc_legacy_const_generics, Normal, template!(List: "N"), INTERNAL_UNSTABLE), + // Do not const-check this function's body. It will always get replaced during CTFE. + rustc_attr!(rustc_do_not_const_check, Normal, template!(Word), INTERNAL_UNSTABLE), // ========================================================================== // Internal attributes, Layout related: diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -51,7 +51,6 @@ pub since: &'static str, issue: Option, pub edition: Option, - description: &'static str, } #[derive(Copy, Clone, Debug)] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/removed.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/removed.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_feature/src/removed.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_feature/src/removed.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,6 @@ since: $ver, issue: to_nonzero($issue), edition: None, - description: concat!($($doc,)*), } ),+ ]; @@ -34,7 +33,6 @@ since: $ver, issue: to_nonzero($issue), edition: None, - description: concat!($($doc,)*), } ),+ ]; @@ -104,7 +102,7 @@ (removed, quote, "1.33.0", Some(29601), None, None), /// Allows const generic types (e.g. `struct Foo(...);`). (removed, const_generics, "1.34.0", Some(44580), None, - Some("removed in favor of `#![feature(adt_const_params]` and `#![feature(generic_const_exprs)]`")), + Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")), /// Allows `[x; N]` where `x` is a constant (RFC 2203). (removed, const_in_array_repeat_expressions, "1.37.0", Some(49147), None, Some("removed due to causing promotable bugs")), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_fs_util/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_fs_util/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_fs_util/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_fs_util/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ [package] name = "rustc_fs_util" version = "0.0.0" -edition = "2018" +edition = "2021" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_graphviz/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_graphviz/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_graphviz/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_graphviz/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ [package] name = "rustc_graphviz" version = "0.0.0" -edition = "2018" +edition = "2021" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_graphviz/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_graphviz/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_graphviz/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_graphviz/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -512,7 +512,7 @@ pub fn to_dot_string(&self) -> String { match *self { LabelStr(ref s) => format!("\"{}\"", s.escape_default()), - EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)), + EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)), HtmlStr(ref s) => format!("<{}>", s), } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_hir" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false @@ -17,3 +17,4 @@ rustc_ast = { path = "../rustc_ast" } tracing = "0.1" smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +odht = { version = "0.3.1", features = ["nightly"] } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/arena.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/arena.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/arena.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/arena.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,9 +28,9 @@ [] pat_field: rustc_hir::PatField<$tcx>, [] fn_decl: rustc_hir::FnDecl<$tcx>, [] foreign_item: rustc_hir::ForeignItem<$tcx>, - [few] foreign_item_ref: rustc_hir::ForeignItemRef<$tcx>, + [few] foreign_item_ref: rustc_hir::ForeignItemRef, [] impl_item: rustc_hir::ImplItem<$tcx>, - [] impl_item_ref: rustc_hir::ImplItemRef<$tcx>, + [] impl_item_ref: rustc_hir::ImplItemRef, [] item: rustc_hir::Item<$tcx>, [few] inline_asm: rustc_hir::InlineAsm<$tcx>, [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/definitions.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/definitions.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/definitions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/definitions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,14 +6,15 @@ pub use crate::def_id::DefPathHash; use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::def_path_hash_map::DefPathHashMap; use crate::hir; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; -use rustc_data_structures::unhash::UnhashMap; use rustc_index::vec::IndexVec; use rustc_span::hygiene::ExpnId; use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::Span; use std::fmt::{self, Write}; use std::hash::Hash; @@ -27,7 +28,7 @@ pub struct DefPathTable { index_to_key: IndexVec, def_path_hashes: IndexVec, - def_path_hash_to_index: UnhashMap, + def_path_hash_to_index: DefPathHashMap, } impl DefPathTable { @@ -43,7 +44,7 @@ // Check for hash collisions of DefPathHashes. These should be // exceedingly rare. - if let Some(existing) = self.def_path_hash_to_index.insert(def_path_hash, index) { + if let Some(existing) = self.def_path_hash_to_index.insert(&def_path_hash, &index) { let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx)); let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx)); @@ -86,7 +87,7 @@ pub fn enumerated_keys_and_path_hashes( &self, - ) -> impl Iterator + '_ { + ) -> impl Iterator + ExactSizeIterator + '_ { self.index_to_key .iter_enumerated() .map(move |(index, key)| (index, key, &self.def_path_hashes[index])) @@ -107,6 +108,11 @@ /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. expansions_that_defined: FxHashMap, + + def_id_to_span: IndexVec, + + /// The [StableCrateId] of the local crate. + stable_crate_id: StableCrateId, } /// A unique identifier that we can use to lookup a definition @@ -324,7 +330,7 @@ } /// Adds a root definition (no parent) and a few other reserved definitions. - pub fn new(stable_crate_id: StableCrateId) -> Definitions { + pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions { let key = DefKey { parent: None, disambiguated_data: DisambiguatedDefPathData { @@ -341,11 +347,19 @@ let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) }; assert_eq!(root.local_def_index, CRATE_DEF_INDEX); + let mut def_id_to_span = IndexVec::new(); + // A relative span's parent must be an absolute span. + debug_assert_eq!(crate_span.data_untracked().parent, None); + let _root = def_id_to_span.push(crate_span); + debug_assert_eq!(_root, root); + Definitions { table, def_id_to_hir_id: Default::default(), hir_id_to_def_id: Default::default(), expansions_that_defined: Default::default(), + def_id_to_span, + stable_crate_id, } } @@ -361,6 +375,7 @@ data: DefPathData, expn_id: ExpnId, mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32, + span: Span, ) -> LocalDefId { debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id); @@ -385,6 +400,11 @@ self.expansions_that_defined.insert(def_id, expn_id); } + // A relative span's parent must be an absolute span. + debug_assert_eq!(span.data_untracked().parent, None); + let _id = self.def_id_to_span.push(span); + debug_assert_eq!(_id, def_id); + def_id } @@ -412,16 +432,28 @@ self.expansions_that_defined.get(&id).copied().unwrap_or_else(ExpnId::root) } + /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. + #[inline] + pub fn def_span(&self, def_id: LocalDefId) -> Span { + self.def_id_to_span[def_id] + } + pub fn iter_local_def_id(&self) -> impl Iterator + '_ { self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k) } #[inline(always)] - pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option { + pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> LocalDefId { + debug_assert!(hash.stable_crate_id() == self.stable_crate_id); self.table .def_path_hash_to_index .get(&hash) - .map(|&local_def_index| LocalDefId { local_def_index }) + .map(|local_def_index| LocalDefId { local_def_index }) + .unwrap() + } + + pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap { + &self.table.def_path_hash_to_index } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/def_path_hash_map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/def_path_hash_map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/def_path_hash_map.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/def_path_hash_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,37 @@ +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_span::def_id::{DefIndex, DefPathHash}; + +#[derive(Clone, Default)] +pub struct Config; + +impl odht::Config for Config { + type Key = DefPathHash; + type Value = DefIndex; + + type EncodedKey = [u8; 16]; + type EncodedValue = [u8; 4]; + + type H = odht::UnHashFn; + + #[inline] + fn encode_key(k: &DefPathHash) -> [u8; 16] { + k.0.to_le_bytes() + } + + #[inline] + fn encode_value(v: &DefIndex) -> [u8; 4] { + v.as_u32().to_le_bytes() + } + + #[inline] + fn decode_key(k: &[u8; 16]) -> DefPathHash { + DefPathHash(Fingerprint::from_le_bytes(*k)) + } + + #[inline] + fn decode_value(v: &[u8; 4]) -> DefIndex { + DefIndex::from_u32(u32::from_le_bytes(*v)) + } +} + +pub type DefPathHashMap = odht::HashTableOwned; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/def.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/def.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/def.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/def.rs 2021-11-29 19:27:11.000000000 +0000 @@ -598,6 +598,11 @@ } } + #[track_caller] + pub fn expect_non_local(self) -> Res { + self.map_id(|_| panic!("unexpected `Res::Local`")) + } + pub fn macro_kind(self) -> Option { match self { Res::Def(DefKind::Macro(kind), _) => Some(kind), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/diagnostic_items.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/diagnostic_items.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/diagnostic_items.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/diagnostic_items.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +use crate::def_id::DefId; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_span::Symbol; + +#[derive(Debug, Default)] +pub struct DiagnosticItems { + pub id_to_name: FxHashMap, + pub name_to_id: FxHashMap, +} + +impl HashStable for DiagnosticItems { + #[inline] + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.name_to_id.hash_stable(ctx, hasher); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/hir.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/hir.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/hir.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/hir.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ use crate::def::{CtorKind, DefKind, Res}; use crate::def_id::{DefId, CRATE_DEF_ID}; crate use crate::hir_id::{HirId, ItemLocalId}; -use crate::{itemlikevisit, LangItem}; +use crate::LangItem; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect}; @@ -10,7 +10,6 @@ pub use rustc_ast::{CaptureBy, Movability, Mutability}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; use rustc_span::source_map::Spanned; @@ -21,7 +20,7 @@ use rustc_target::spec::abi::Abi; use smallvec::SmallVec; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; use std::fmt; #[derive(Copy, Clone, Encodable, HashStable_Generic)] @@ -384,6 +383,16 @@ self.args.iter().any(|arg| matches!(arg, GenericArg::Type(_))) } + pub fn has_err(&self) -> bool { + self.args.iter().any(|arg| match arg { + GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err), + _ => false, + }) || self.bindings.iter().any(|arg| match arg.kind { + TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err), + _ => false, + }) + } + #[inline] pub fn num_type_params(&self) -> usize { self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count() @@ -441,10 +450,12 @@ Trait(PolyTraitRef<'hir>, TraitBoundModifier), // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem` LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>), - Unsized(Span), Outlives(Lifetime), } +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(GenericBound<'_>, 48); + impl GenericBound<'_> { pub fn trait_ref(&self) -> Option<&TraitRef<'_>> { match self { @@ -458,7 +469,6 @@ GenericBound::Trait(t, ..) => t.span, GenericBound::LangItemTrait(_, span, ..) => *span, GenericBound::Outlives(l) => l.span, - GenericBound::Unsized(span) => *span, } } } @@ -652,16 +662,6 @@ pub rhs_ty: &'hir Ty<'hir>, } -#[derive(Default, Encodable, Debug, HashStable_Generic)] -pub struct ModuleItems { - // Use BTreeSets here so items are in the same order as in the - // list of all items in Crate - pub items: BTreeSet, - pub trait_items: BTreeSet, - pub impl_items: BTreeSet, - pub foreign_items: BTreeSet, -} - /// The top-level data structure that stores the entire contents of /// the crate currently being compiled. /// @@ -673,10 +673,6 @@ pub owners: IndexVec>>, pub bodies: BTreeMap>, - /// A list of modules written out in the order in which they - /// appear in the crate. This includes the main crate module. - pub modules: BTreeMap, - /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. pub trait_map: FxHashMap>>, @@ -711,52 +707,6 @@ } } -impl Crate<'_> { - /// Visits all items in the crate in some deterministic (but - /// unspecified) order. If you just need to process every item, - /// but don't care about nesting, this method is the best choice. - /// - /// If you do care about nesting -- usually because your algorithm - /// follows lexical scoping rules -- then you want a different - /// approach. You should override `visit_nested_item` in your - /// visitor and then call `intravisit::walk_crate` instead. - pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V) - where - V: itemlikevisit::ItemLikeVisitor<'hir>, - { - for owner in self.owners.iter().filter_map(Option::as_ref) { - match owner { - OwnerNode::Item(item) => visitor.visit_item(item), - OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), - OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), - OwnerNode::TraitItem(item) => visitor.visit_trait_item(item), - OwnerNode::Crate(_) => {} - } - } - } - - /// A parallel version of `visit_all_item_likes`. - pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V) - where - V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, - { - par_for_each_in(&self.owners.raw, |owner| match owner { - Some(OwnerNode::Item(item)) => visitor.visit_item(item), - Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), - Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), - Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item), - Some(OwnerNode::Crate(_)) | None => {} - }) - } - - pub fn items<'hir>(&'hir self) -> impl Iterator> + 'hir { - self.owners.iter().filter_map(|owner| match owner { - Some(OwnerNode::Item(item)) => Some(*item), - _ => None, - }) - } -} - /// A block of statements `{ .. }`, which may have a label (in this case the /// `targeted_by_break` field will be `true`) and may be `unsafe` by means of /// the `rules` being anything but `DefaultBlock`. @@ -2285,8 +2235,7 @@ /// /// Type parameters may be stored in each `PathSegment`. Path(QPath<'hir>), - /// An opaque type definition itself. This is currently only used for the - /// `opaque type Foo: Trait` item that `impl Trait` in desugars to. + /// An opaque type definition itself. This is only used for `impl Trait`. /// /// The generic argument list contains the lifetimes (and in the future /// possibly parameters) that are actually bound on the `impl Trait`. @@ -2343,6 +2292,13 @@ Self::Const { .. } | Self::Sym { .. } => None, } } + + pub fn is_clobber(&self) -> bool { + matches!( + self, + InlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(_), late: _, expr: None } + ) + } } #[derive(Debug, HashStable_Generic)] @@ -2758,7 +2714,7 @@ /// A module. Mod(Mod<'hir>), /// An external module, e.g. `extern { .. }`. - ForeignMod { abi: Abi, items: &'hir [ForeignItemRef<'hir>] }, + ForeignMod { abi: Abi, items: &'hir [ForeignItemRef] }, /// Module-level inline assembly (from `global_asm!`). GlobalAsm(&'hir InlineAsm<'hir>), /// A type alias, e.g., `type Foo = Bar`. @@ -2795,7 +2751,7 @@ pub of_trait: Option>, pub self_ty: &'hir Ty<'hir>, - pub items: &'hir [ImplItemRef<'hir>], + pub items: &'hir [ImplItemRef], } impl ItemKind<'_> { @@ -2859,13 +2815,12 @@ /// passes to find the impl they want without loading the ID (which /// means fewer edges in the incremental compilation graph). #[derive(Debug, HashStable_Generic)] -pub struct ImplItemRef<'hir> { +pub struct ImplItemRef { pub id: ImplItemId, #[stable_hasher(project(name))] pub ident: Ident, pub kind: AssocItemKind, pub span: Span, - pub vis: Visibility<'hir>, pub defaultness: Defaultness, } @@ -2899,12 +2854,11 @@ /// passes to find the impl they want without loading the ID (which /// means fewer edges in the incremental compilation graph). #[derive(Debug, HashStable_Generic)] -pub struct ForeignItemRef<'hir> { +pub struct ForeignItemRef { pub id: ForeignItemId, #[stable_hasher(project(name))] pub ident: Ident, pub span: Span, - pub vis: Visibility<'hir>, } #[derive(Debug)] @@ -3233,12 +3187,7 @@ } } - /// Returns `Constness::Const` when this node is a const fn/impl/item, - /// - /// HACK(fee1-dead): or an associated type in a trait. This works because - /// only typeck cares about const trait predicates, so although the predicates - /// query would return const predicates when it does not need to be const, - /// it wouldn't have any effect. + /// Returns `Constness::Const` when this node is a const fn/impl/item. pub fn constness_for_typeck(&self) -> Constness { match self { Node::Item(Item { @@ -3257,7 +3206,6 @@ Node::Item(Item { kind: ItemKind::Const(..), .. }) | Node::TraitItem(TraitItem { kind: TraitItemKind::Const(..), .. }) - | Node::TraitItem(TraitItem { kind: TraitItemKind::Type(..), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Const(..), .. }) => Constness::Const, _ => Constness::NotConst, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/intravisit.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/intravisit.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/intravisit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/intravisit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -32,7 +32,6 @@ //! example generator inference, and possibly also HIR borrowck. use crate::hir::*; -use crate::hir_id::CRATE_HIR_ID; use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor}; use rustc_ast::walk_list; use rustc_ast::{Attribute, Label}; @@ -393,10 +392,10 @@ fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) { walk_impl_item(self, ii) } - fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef<'v>) { + fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef) { walk_foreign_item_ref(self, ii) } - fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef<'v>) { + fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) { walk_impl_item_ref(self, ii) } fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) { @@ -477,17 +476,6 @@ } } -/// Walks the contents of a crate. See also `Crate::visit_all_items`. -pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) { - let top_mod = krate.module(); - visitor.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID); - for (&id, attrs) in krate.attrs.iter() { - for a in *attrs { - visitor.visit_attribute(id, a) - } - } -} - pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) { visitor.visit_id(mod_hir_id); for &item_id in module.item_ids { @@ -883,7 +871,6 @@ visitor.visit_generic_args(span, args); } GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), - GenericBound::Unsized(_) => {} } } @@ -1055,22 +1042,20 @@ pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, - foreign_item_ref: &'v ForeignItemRef<'v>, + foreign_item_ref: &'v ForeignItemRef, ) { // N.B., deliberately force a compilation error if/when new fields are added. - let ForeignItemRef { id, ident, span: _, ref vis } = *foreign_item_ref; + let ForeignItemRef { id, ident, span: _ } = *foreign_item_ref; visitor.visit_nested_foreign_item(id); visitor.visit_ident(ident); - visitor.visit_vis(vis); } -pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef<'v>) { +pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) { // N.B., deliberately force a compilation error if/when new fields are added. - let ImplItemRef { id, ident, ref kind, span: _, ref vis, ref defaultness } = *impl_item_ref; + let ImplItemRef { id, ident, ref kind, span: _, ref defaultness } = *impl_item_ref; visitor.visit_nested_impl_item(id); visitor.visit_ident(ident); visitor.visit_associated_item_kind(kind); - visitor.visit_vis(vis); visitor.visit_defaultness(defaultness); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/lang_items.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/lang_items.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/lang_items.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/lang_items.rs 2021-11-29 19:27:11.000000000 +0000 @@ -283,6 +283,7 @@ // a weak lang item, but do not have it defined. Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::None; PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None; + PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None; PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None; ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None; PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::None; @@ -298,8 +299,10 @@ DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); Oom, sym::oom, oom, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; + ConstEvalSelect, sym::const_eval_select, const_eval_select, Target::Fn, GenericRequirement::Exact(4); + ConstConstEvalSelect, sym::const_eval_select_ct,const_eval_select_ct, Target::Fn, GenericRequirement::Exact(4); - Start, sym::start, start_fn, Target::Fn, GenericRequirement::None; + Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); EhPersonality, sym::eh_personality, eh_personality, Target::Fn, GenericRequirement::None; EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,9 @@ mod arena; pub mod def; +pub mod def_path_hash_map; pub mod definitions; +pub mod diagnostic_items; pub use rustc_span::def_id; mod hir; pub mod hir_id; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/stable_hash_impls.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/stable_hash_impls.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir/src/stable_hash_impls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir/src/stable_hash_impls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -33,6 +33,25 @@ } } +impl ToStableHashKey for ItemLocalId { + type KeyType = ItemLocalId; + + #[inline] + fn to_stable_hash_key(&self, _: &HirCtx) -> ItemLocalId { + *self + } +} + +impl ToStableHashKey for BodyId { + type KeyType = (DefPathHash, ItemLocalId); + + #[inline] + fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) { + let BodyId { hir_id } = *self; + hir_id.to_stable_hash_key(hcx) + } +} + impl ToStableHashKey for ItemId { type KeyType = DefPathHash; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir_pretty/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir_pretty/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir_pretty/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir_pretty/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_hir_pretty" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir_pretty/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir_pretty/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_hir_pretty/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_hir_pretty/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -51,19 +51,6 @@ impl PpAnn for NoAnn {} pub const NO_ANN: &dyn PpAnn = &NoAnn; -impl PpAnn for hir::Crate<'_> { - fn nested(&self, state: &mut State<'_>, nested: Nested) { - match nested { - Nested::Item(id) => state.print_item(self.item(id)), - Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), - Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), - Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)), - Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat), - } - } -} - /// Identical to the `PpAnn` implementation for `hir::Crate`, /// except it avoids creating a dependency on the whole crate. impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { @@ -1036,7 +1023,7 @@ self.maybe_print_comment(st.span.lo()); match st.kind { hir::StmtKind::Local(ref loc) => { - self.print_local(loc.init.as_deref(), |this| this.print_local_decl(&loc)); + self.print_local(loc.init, |this| this.print_local_decl(&loc)); } hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)), hir::StmtKind::Expr(ref expr) => { @@ -2232,9 +2219,6 @@ GenericBound::Outlives(lt) => { self.print_lifetime(lt); } - GenericBound::Unsized(_) => { - self.s.word("?Sized"); - } } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_incremental" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/assert_dep_graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/assert_dep_graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/assert_dep_graph.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/assert_dep_graph.rs 2021-11-29 19:27:11.000000000 +0000 @@ -74,7 +74,7 @@ let mut visitor = IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; visitor.process_attrs(hir::CRATE_HIR_ID); - tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); + tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor()); (visitor.if_this_changed, visitor.then_this_would_need) }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/dirty_clean.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/dirty_clean.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/dirty_clean.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/dirty_clean.rs 2021-11-29 19:27:11.000000000 +0000 @@ -137,12 +137,11 @@ } tcx.dep_graph.with_ignore(|| { - let krate = tcx.hir().krate(); let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() }; - krate.visit_all_item_likes(&mut dirty_clean_visitor); + tcx.hir().visit_all_item_likes(&mut dirty_clean_visitor); let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] }; - intravisit::walk_crate(&mut all_attrs, krate); + tcx.hir().walk_attributes(&mut all_attrs); // Note that we cannot use the existing "unused attribute"-infrastructure // here, since that is running before codegen. This is also the reason why diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/file_format.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/file_format.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/file_format.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/file_format.rs 2021-11-29 19:27:11.000000000 +0000 @@ -12,10 +12,12 @@ use std::env; use std::fs; use std::io::{self, Read}; -use std::path::Path; +use std::path::{Path, PathBuf}; +use rustc_data_structures::memmap::Mmap; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encoder; +use rustc_session::Session; /// The first few bytes of files generated by incremental compilation. const FILE_MAGIC: &[u8] = b"RSIC"; @@ -28,7 +30,7 @@ /// the Git commit hash. const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); -pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult { +pub(crate) fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult { stream.emit_raw_bytes(FILE_MAGIC)?; stream.emit_raw_bytes(&[ (HEADER_FORMAT_VERSION >> 0) as u8, @@ -41,6 +43,61 @@ stream.emit_raw_bytes(rustc_version.as_bytes()) } +pub(crate) fn save_in(sess: &Session, path_buf: PathBuf, name: &str, encode: F) +where + F: FnOnce(&mut FileEncoder) -> FileEncodeResult, +{ + debug!("save: storing data in {}", path_buf.display()); + + // Delete the old file, if any. + // Note: It's important that we actually delete the old file and not just + // truncate and overwrite it, since it might be a shared hard-link, the + // underlying data of which we don't want to modify. + // + // We have to ensure we have dropped the memory maps to this file + // before performing this removal. + match fs::remove_file(&path_buf) { + Ok(()) => { + debug!("save: remove old file"); + } + Err(err) if err.kind() == io::ErrorKind::NotFound => (), + Err(err) => { + sess.err(&format!( + "unable to delete old {} at `{}`: {}", + name, + path_buf.display(), + err + )); + return; + } + } + + let mut encoder = match FileEncoder::new(&path_buf) { + Ok(encoder) => encoder, + Err(err) => { + sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err)); + return; + } + }; + + if let Err(err) = write_file_header(&mut encoder, sess.is_nightly_build()) { + sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err)); + return; + } + + if let Err(err) = encode(&mut encoder) { + sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err)); + return; + } + + if let Err(err) = encoder.flush() { + sess.err(&format!("failed to flush {} to `{}`: {}", name, path_buf.display(), err)); + return; + } + + debug!("save: data written to disk successfully"); +} + /// Reads the contents of a file with a file header as defined in this module. /// /// - Returns `Ok(Some(data, pos))` if the file existed and was generated by a @@ -54,14 +111,21 @@ report_incremental_info: bool, path: &Path, nightly_build: bool, -) -> io::Result, usize)>> { - let data = match fs::read(path) { - Ok(data) => data, +) -> io::Result> { + let file = match fs::File::open(path) { + Ok(file) => file, Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), Err(err) => return Err(err), }; + // SAFETY: This process must not modify nor remove the backing file while the memory map lives. + // For the dep-graph and the work product index, it is as soon as the decoding is done. + // For the query result cache, the memory map is dropped in save_dep_graph before calling + // save_in and trying to remove the backing file. + // + // There is no way to prevent another process from modifying this file. + let mmap = unsafe { Mmap::map(file) }?; - let mut file = io::Cursor::new(data); + let mut file = io::Cursor::new(&*mmap); // Check FILE_MAGIC { @@ -103,7 +167,7 @@ } let post_header_start_pos = file.position() as usize; - Ok(Some((file.into_inner(), post_header_start_pos))) + Ok(Some((mmap, post_header_start_pos))) } fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &str) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/load.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/load.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/load.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/load.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ //! Code to save/load the dep-graph from files. use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::memmap::Mmap; use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::OnDiskCache; use rustc_serialize::opaque::Decoder; @@ -48,7 +49,7 @@ report_incremental_info: bool, path: &Path, nightly_build: bool, -) -> LoadResult<(Vec, usize)> { +) -> LoadResult<(Mmap, usize)> { match file_format::read_file(report_incremental_info, path, nightly_build) { Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, Ok(None) => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/save.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/save.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/save.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_incremental/src/persist/save.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ use rustc_serialize::Encodable as RustcEncodable; use rustc_session::Session; use std::fs; -use std::io; -use std::path::PathBuf; use super::data::*; use super::dirty_clean; @@ -44,7 +42,14 @@ join( move || { sess.time("incr_comp_persist_result_cache", || { - save_in(sess, query_cache_path, "query cache", |e| encode_query_cache(tcx, e)); + // Drop the memory map so that we can remove the file and write to it. + if let Some(odc) = &tcx.on_disk_cache { + odc.drop_serialized_data(tcx); + } + + file_format::save_in(sess, query_cache_path, "query cache", |e| { + encode_query_cache(tcx, e) + }); }); }, move || { @@ -86,7 +91,9 @@ debug!("save_work_product_index()"); dep_graph.assert_ignored(); let path = work_products_path(sess); - save_in(sess, path, "work product index", |e| encode_work_product_index(&new_work_products, e)); + file_format::save_in(sess, path, "work product index", |e| { + encode_work_product_index(&new_work_products, e) + }); // We also need to clean out old work-products, as not all of them are // deleted during invalidation. Some object files don't change their @@ -113,58 +120,6 @@ }); } -pub(crate) fn save_in(sess: &Session, path_buf: PathBuf, name: &str, encode: F) -where - F: FnOnce(&mut FileEncoder) -> FileEncodeResult, -{ - debug!("save: storing data in {}", path_buf.display()); - - // Delete the old file, if any. - // Note: It's important that we actually delete the old file and not just - // truncate and overwrite it, since it might be a shared hard-link, the - // underlying data of which we don't want to modify - match fs::remove_file(&path_buf) { - Ok(()) => { - debug!("save: remove old file"); - } - Err(err) if err.kind() == io::ErrorKind::NotFound => (), - Err(err) => { - sess.err(&format!( - "unable to delete old {} at `{}`: {}", - name, - path_buf.display(), - err - )); - return; - } - } - - let mut encoder = match FileEncoder::new(&path_buf) { - Ok(encoder) => encoder, - Err(err) => { - sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err)); - return; - } - }; - - if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) { - sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err)); - return; - } - - if let Err(err) = encode(&mut encoder) { - sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err)); - return; - } - - if let Err(err) = encoder.flush() { - sess.err(&format!("failed to flush {} to `{}`: {}", name, path_buf.display(), err)); - return; - } - - debug!("save: data written to disk successfully"); -} - fn encode_work_product_index( work_products: &FxHashMap, encoder: &mut FileEncoder, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_index/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_index/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_index/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_index/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_index" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_index/src/bit_set.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_index/src/bit_set.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_index/src/bit_set.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_index/src/bit_set.rs 2021-11-29 19:27:11.000000000 +0000 @@ -841,7 +841,7 @@ #[inline] pub fn contains(&self, elem: T) -> bool { let (word_index, mask) = word_index_and_mask(elem); - if let Some(word) = self.bit_set.words.get(word_index) { (word & mask) != 0 } else { false } + self.bit_set.words.get(word_index).map_or(false, |word| (word & mask) != 0) } } @@ -990,9 +990,8 @@ pub fn insert_all_into_row(&mut self, row: R) { assert!(row.index() < self.num_rows); let (start, end) = self.range(row); - let words = &mut self.words[..]; - for index in start..end { - words[index] = !0; + for word in self.words[start..end].iter_mut() { + *word = !0; } self.clear_excess_bits(row); } @@ -1072,13 +1071,9 @@ } fn ensure_row(&mut self, row: R) -> &mut HybridBitSet { - // Instantiate any missing rows up to and including row `row` with an - // empty HybridBitSet. - self.rows.ensure_contains_elem(row, || None); - + // Instantiate any missing rows up to and including row `row` with an empty HybridBitSet. // Then replace row `row` with a full HybridBitSet if necessary. - let num_columns = self.num_columns; - self.rows[row].get_or_insert_with(|| HybridBitSet::new_empty(num_columns)) + self.rows.get_or_insert_with(row, || HybridBitSet::new_empty(self.num_columns)) } /// Sets the cell at `(row, column)` to true. Put another way, insert @@ -1148,7 +1143,7 @@ /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { + pub fn iter(&self, row: R) -> impl Iterator + '_ { self.row(row).into_iter().flat_map(|r| r.iter()) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_index/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_index/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_index/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_index/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,8 @@ #![feature(bench_black_box)] #![feature(extend_one)] #![feature(iter_zip)] -#![feature(unboxed_closures)] +#![feature(min_specialization)] #![feature(test)] -#![feature(fn_traits)] pub mod bit_set; pub mod vec; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_index/src/vec.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_index/src/vec.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_index/src/vec.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_index/src/vec.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,9 +3,9 @@ use std::fmt; use std::fmt::Debug; use std::hash::Hash; -use std::iter::{self, FromIterator}; +use std::iter::FromIterator; use std::marker::PhantomData; -use std::ops::{Index, IndexMut, Range, RangeBounds}; +use std::ops::{Index, IndexMut, RangeBounds}; use std::slice; use std::vec; @@ -124,7 +124,9 @@ #[inline] $v const fn from_usize(value: usize) -> Self { - // FIXME: replace with `assert!(value <= ($max as usize));` once `const_panic` is stable + #[cfg(not(bootstrap))] + assert!(value <= ($max as usize)); + #[cfg(bootstrap)] [()][(value > ($max as usize)) as usize]; unsafe { Self::from_u32_unchecked(value as u32) @@ -133,7 +135,9 @@ #[inline] $v const fn from_u32(value: u32) -> Self { - // FIXME: replace with `assert!(value <= $max);` once `const_panic` is stable + #[cfg(not(bootstrap))] + assert!(value <= $max); + #[cfg(bootstrap)] [()][(value > $max) as usize]; unsafe { Self::from_u32_unchecked(value) @@ -518,8 +522,6 @@ } } -pub type Enumerated = iter::Map, IntoIdx>; - impl IndexVec { #[inline] pub fn new() -> Self { @@ -596,8 +598,10 @@ } #[inline] - pub fn into_iter_enumerated(self) -> Enumerated> { - self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData }) + pub fn into_iter_enumerated( + self, + ) -> impl DoubleEndedIterator + ExactSizeIterator { + self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] @@ -606,13 +610,15 @@ } #[inline] - pub fn iter_enumerated(&self) -> Enumerated> { - self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData }) + pub fn iter_enumerated( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator + '_ { + self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] - pub fn indices(&self) -> iter::Map, IntoIdx> { - (0..self.len()).map(IntoIdx { _marker: PhantomData }) + pub fn indices(&self) -> impl DoubleEndedIterator + ExactSizeIterator + 'static { + (0..self.len()).map(|n| I::new(n)) } #[inline] @@ -621,24 +627,23 @@ } #[inline] - pub fn iter_enumerated_mut(&mut self) -> Enumerated> { - self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData }) + pub fn iter_enumerated_mut( + &mut self, + ) -> impl DoubleEndedIterator + ExactSizeIterator + '_ { + self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] - pub fn drain<'a, R: RangeBounds>( - &'a mut self, - range: R, - ) -> impl Iterator + 'a { + pub fn drain>(&mut self, range: R) -> impl Iterator + '_ { self.raw.drain(range) } #[inline] - pub fn drain_enumerated<'a, R: RangeBounds>( - &'a mut self, + pub fn drain_enumerated>( + &mut self, range: R, - ) -> impl Iterator + 'a { - self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) + ) -> impl Iterator + '_ { + self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] @@ -720,6 +725,27 @@ } } +/// `IndexVec` is often used as a map, so it provides some map-like APIs. +impl IndexVec> { + #[inline] + pub fn insert(&mut self, index: I, value: T) -> Option { + self.ensure_contains_elem(index, || None); + self[index].replace(value) + } + + #[inline] + pub fn get_or_insert_with(&mut self, index: I, value: impl FnOnce() -> T) -> &mut T { + self.ensure_contains_elem(index, || None); + self[index].get_or_insert_with(value) + } + + #[inline] + pub fn remove(&mut self, index: I) -> Option { + self.ensure_contains_elem(index, || None); + self[index].take() + } +} + impl IndexVec { #[inline] pub fn resize(&mut self, new_len: usize, value: T) { @@ -817,36 +843,5 @@ } } -pub struct IntoIdx { - _marker: PhantomData, -} -impl FnOnce<((usize, T),)> for IntoIdx { - type Output = (I, T); - - extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output { - (I::new(n), t) - } -} - -impl FnMut<((usize, T),)> for IntoIdx { - extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output { - (I::new(n), t) - } -} - -impl FnOnce<(usize,)> for IntoIdx { - type Output = I; - - extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output { - I::new(n) - } -} - -impl FnMut<(usize,)> for IntoIdx { - extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output { - I::new(n) - } -} - #[cfg(test)] mod tests; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_infer" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/at.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/at.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/at.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/at.rs 2021-11-29 19:27:11.000000000 +0000 @@ -187,11 +187,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a <: b` where `a` may or may not be expected (if /// `a_is_expected` is true, then `a` is expected). + #[instrument(skip(self), level = "debug")] pub fn sub(self, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { - debug!("sub({:?} <: {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -204,11 +204,11 @@ /// Makes `a == b`; the expectation is set by the call to /// `trace()`. + #[instrument(skip(self), level = "debug")] pub fn eq(self, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { - debug!("eq({:?} == {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -219,11 +219,11 @@ }) } + #[instrument(skip(self), level = "debug")] pub fn lub(self, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { - debug!("lub({:?} \\/ {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -234,11 +234,11 @@ }) } + #[instrument(skip(self), level = "debug")] pub fn glb(self, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { - debug!("glb({:?} /\\ {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/canonical/query_response.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/canonical/query_response.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/canonical/query_response.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/canonical/query_response.rs 2021-11-29 19:27:11.000000000 +0000 @@ -49,6 +49,7 @@ /// the same thing happens, but the resulting query is marked as ambiguous. /// - Finally, if any of the obligations result in a hard error, /// then `Err(NoSolution)` is returned. + #[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")] pub fn make_canonicalized_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, @@ -62,7 +63,7 @@ let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; let canonical_result = self.canonicalize_response(query_response); - debug!("make_canonicalized_query_response: canonical_result = {:#?}", canonical_result); + debug!("canonical_result = {:#?}", canonical_result); Ok(self.tcx.arena.alloc(canonical_result)) } @@ -94,6 +95,7 @@ /// Helper for `make_canonicalized_query_response` that does /// everything up until the final canonicalization. + #[instrument(skip(self, fulfill_cx), level = "debug")] fn make_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, @@ -105,13 +107,6 @@ { let tcx = self.tcx; - debug!( - "make_query_response(\ - inference_vars={:?}, \ - answer={:?})", - inference_vars, answer, - ); - // Select everything, returning errors. let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new); debug!("true_errors = {:#?}", true_errors); @@ -669,8 +664,10 @@ self.obligations.push(Obligation { cause: self.cause.clone(), param_env: self.param_env, - predicate: ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)) - .to_predicate(self.infcx.tcx), + predicate: ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( + sup, sub, + ))) + .to_predicate(self.infcx.tcx), recursion_depth: 0, }); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/combine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/combine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/combine.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/combine.rs 2021-11-29 19:27:11.000000000 +0000 @@ -22,6 +22,7 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. +use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; @@ -29,7 +30,6 @@ use super::unify_key::replace_if_possible; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use super::{equate::Equate, type_variable::Diverging}; use super::{InferCtxt, MiscVariable, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; @@ -360,7 +360,8 @@ self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(b_ty.into())) + .to_predicate(self.infcx.tcx), )); } @@ -463,7 +464,7 @@ self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - predicate.to_predicate(self.tcx()), + ty::Binder::dummy(predicate).to_predicate(self.tcx()), )); } } @@ -645,7 +646,7 @@ .inner .borrow_mut() .type_variables() - .new_var(self.for_universe, Diverging::NotDiverging, origin); + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); // Record that we replaced `vid` with `new_var_id` as part of a generalization @@ -885,11 +886,12 @@ let origin = *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var( - self.for_universe, - Diverging::NotDiverging, - origin, - ); + let new_var_id = self + .infcx + .inner + .borrow_mut() + .type_variables() + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!( "ConstInferUnifier: replacing original vid={:?} with new={:?}", diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ //! inference graph arose so that we can explain to the user what gave //! rise to a particular error. //! -//! The basis of the system are the "origin" types. An "origin" is the +//! The system is based around a set of "origin" types. An "origin" is the //! reason that a constraint or inference variable arose. There are //! different "origin" enums for different kinds of constraints/variables //! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has @@ -116,7 +116,7 @@ emit_msg_span(err, prefix, description, span, suffix); } -pub(super) fn note_and_explain_free_region( +fn explain_free_region( tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>, prefix: &str, @@ -125,7 +125,7 @@ ) { let (description, span) = msg_span_from_free_region(tcx, region, None); - emit_msg_span(err, prefix, description, span, suffix); + label_msg_span(err, prefix, description, span, suffix); } fn msg_span_from_free_region( @@ -135,7 +135,8 @@ ) -> (String, Option) { match *region { ty::ReEarlyBound(_) | ty::ReFree(_) => { - msg_span_from_early_bound_and_free_regions(tcx, region) + let (msg, span) = msg_span_from_early_bound_and_free_regions(tcx, region); + (msg, Some(span)) } ty::ReStatic => ("the static lifetime".to_owned(), alt_span), ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span), @@ -147,20 +148,12 @@ fn msg_span_from_early_bound_and_free_regions( tcx: TyCtxt<'tcx>, region: ty::Region<'tcx>, -) -> (String, Option) { +) -> (String, Span) { let sm = tcx.sess.source_map(); let scope = region.free_region_binding_scope(tcx); let node = tcx.hir().local_def_id_to_hir_id(scope.expect_local()); - let tag = match tcx.hir().find(node) { - Some(Node::Block(_) | Node::Expr(_)) => "body", - Some(Node::Item(it)) => item_scope_tag(&it), - Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), - Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), - Some(Node::ForeignItem(it)) => foreign_item_scope_tag(&it), - _ => unreachable!(), - }; - let (prefix, span) = match *region { + match *region { ty::ReEarlyBound(ref br) => { let mut sp = sm.guess_head_span(tcx.hir().span(node)); if let Some(param) = @@ -168,7 +161,7 @@ { sp = param.span; } - (format!("the lifetime `{}` as defined on", br.name), sp) + (format!("the lifetime `{}` as defined here", br.name), sp) } ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegionKind::BrNamed(_, name), .. @@ -179,28 +172,26 @@ { sp = param.span; } - (format!("the lifetime `{}` as defined on", name), sp) + (format!("the lifetime `{}` as defined here", name), sp) } ty::ReFree(ref fr) => match fr.bound_region { ty::BrAnon(idx) => { if let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) { - ("the anonymous lifetime defined on".to_string(), ty.span) + ("the anonymous lifetime defined here".to_string(), ty.span) } else { ( - format!("the anonymous lifetime #{} defined on", idx + 1), + format!("the anonymous lifetime #{} defined here", idx + 1), tcx.hir().span(node), ) } } _ => ( - format!("the lifetime `{}` as defined on", region), + format!("the lifetime `{}` as defined here", region), sm.guess_head_span(tcx.hir().span(node)), ), }, _ => bug!(), - }; - let (msg, opt_span) = explain_span(tcx, tag, span); - (format!("{} {}", prefix, msg), opt_span) + } } fn emit_msg_span( @@ -219,44 +210,22 @@ } } -fn item_scope_tag(item: &hir::Item<'_>) -> &'static str { - match item.kind { - hir::ItemKind::Impl { .. } => "impl", - hir::ItemKind::Struct(..) => "struct", - hir::ItemKind::Union(..) => "union", - hir::ItemKind::Enum(..) => "enum", - hir::ItemKind::Trait(..) => "trait", - hir::ItemKind::Fn(..) => "function body", - _ => "item", - } -} - -fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str { - match item.kind { - hir::TraitItemKind::Fn(..) => "method body", - hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", - } -} - -fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str { - match item.kind { - hir::ImplItemKind::Fn(..) => "method body", - hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(..) => "associated item", - } -} +fn label_msg_span( + err: &mut DiagnosticBuilder<'_>, + prefix: &str, + description: String, + span: Option, + suffix: &str, +) { + let message = format!("{}{}{}", prefix, description, suffix); -fn foreign_item_scope_tag(item: &hir::ForeignItem<'_>) -> &'static str { - match item.kind { - hir::ForeignItemKind::Fn(..) => "method body", - hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => "associated item", + if let Some(span) = span { + err.span_label(span, &message); + } else { + err.note(&message); } } -fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option) { - let lo = tcx.sess.source_map().lookup_char_pos(span.lo()); - (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span)) -} - pub fn unexpected_hidden_region_diagnostic( tcx: TyCtxt<'tcx>, span: Span, @@ -291,13 +260,25 @@ // // (*) if not, the `tainted_by_errors` field would be set to // `Some(ErrorReported)` in any case, so we wouldn't be here at all. - note_and_explain_free_region( + explain_free_region( tcx, &mut err, &format!("hidden type `{}` captures ", hidden_ty), hidden_region, "", ); + if let Some(reg_info) = tcx.is_suitable_region(hidden_region) { + let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id); + nice_region_error::suggest_new_region_bound( + tcx, + &mut err, + fn_returns, + hidden_region.to_string(), + None, + format!("captures {}", hidden_region), + None, + ) + } } _ => { // Ugh. This is a painful case: the hidden region is not one @@ -609,6 +590,7 @@ err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>, exp_found: Option>>, + terr: &TypeError<'tcx>, ) { match cause.code { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { @@ -785,7 +767,15 @@ err.help("try adding a diverging expression, such as `return` or `panic!(..)`"); err.help("...or use `match` instead of `let...else`"); } - _ => (), + _ => { + if let ObligationCauseCode::BindingObligation(_, binding_span) = + cause.code.peel_derives() + { + if matches!(terr, TypeError::RegionsPlaceholderMismatch) { + err.span_note(*binding_span, "the lifetime requirement is introduced here"); + } + } + } } } @@ -1724,7 +1714,7 @@ // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, cause, exp_found); + self.note_error_origin(diag, cause, exp_found, terr); } pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { @@ -1971,6 +1961,8 @@ trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx> { + use crate::traits::ObligationCauseCode::MatchExpressionArm; + debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); let span = trace.cause.span(self.tcx); @@ -2013,6 +2005,19 @@ _ => {} } } + if let MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = + trace.cause.code + { + if let hir::MatchSource::TryDesugar = source { + if let Some((expected_ty, found_ty)) = self.values_str(trace.values) { + err.note(&format!( + "`?` operator cannot convert from `{}` to `{}`", + found_ty.content(), + expected_ty.content(), + )); + } + } + } err } FailureCode::Error0644(failure_str) => { @@ -2036,14 +2041,24 @@ expected: exp_found.expected.print_only_trait_path(), found: exp_found.found.print_only_trait_path(), }; - self.expected_found_str(pretty_exp_found) + match self.expected_found_str(pretty_exp_found) { + Some((expected, found)) if expected == found => { + self.expected_found_str(exp_found) + } + ret => ret, + } } infer::PolyTraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), found: exp_found.found.print_only_trait_path(), }; - self.expected_found_str(pretty_exp_found) + match self.expected_found_str(pretty_exp_found) { + Some((expected, found)) if expected == found => { + self.expected_found_str(exp_found) + } + ret => ret, + } } } } @@ -2345,7 +2360,7 @@ ); err.span_suggestion( generics.where_clause.tail_span_for_suggestion(), - "consider adding a where clause".into(), + "consider adding a where clause", suggestion, Applicability::MaybeIncorrect, ); @@ -2509,7 +2524,7 @@ /// within `?` desugaring. pub fn is_try_conversion(&self, span: Span, trait_def_id: DefId) -> bool { span.is_desugaring(DesugaringKind::QuestionMark) - && self.tcx.is_diagnostic_item(sym::from_trait, trait_def_id) + && self.tcx.is_diagnostic_item(sym::From, trait_def_id) } } @@ -2585,9 +2600,7 @@ CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"), MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { Error0308(match source { - hir::MatchSource::TryDesugar => { - "try expression alternatives have incompatible types" - } + hir::MatchSource::TryDesugar => "`?` operator has incompatible types", _ => "`match` arms have incompatible types", }) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs 2021-11-29 19:27:11.000000000 +0000 @@ -29,11 +29,17 @@ SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) => cause, _ => return None, }; - let (parent, impl_def_id) = match &cause.code { + // If we added a "points at argument expression" obligation, we remove it here, we care + // about the original obligation only. + let code = match &cause.code { + ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code, + _ => &cause.code, + }; + let (parent, impl_def_id) = match code { ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id), _ => return None, }; - let binding_span = match **parent { + let binding_span = match parent.code { ObligationCauseCode::BindingObligation(_def_id, binding_span) => binding_span, _ => return None, }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,6 +14,8 @@ mod trait_impl_difference; mod util; +pub use static_impl_trait::suggest_new_region_bound; + impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool { NiceRegionError::new(self, error.clone()).try_report().is_some() diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -189,7 +189,7 @@ } if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin { let code = match &cause.code { - ObligationCauseCode::MatchImpl(parent, ..) => &**parent, + ObligationCauseCode::MatchImpl(parent, ..) => &parent.code, _ => &cause.code, }; if let ObligationCauseCode::ItemObligation(item_def_id) = *code { @@ -217,128 +217,159 @@ )); } - debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); - // FIXME: account for the need of parens in `&(dyn Trait + '_)` - let consider = "consider changing the"; - let declare = "to declare that the"; let arg = match param.param.pat.simple_ident() { Some(simple_ident) => format!("argument `{}`", simple_ident), None => "the argument".to_string(), }; - let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name); - let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg); let captures = format!("captures data from {}", arg); - let add_static_bound = "alternatively, add an explicit `'static` bound to this reference"; - let plus_lt = format!(" + {}", lifetime_name); - for fn_return in fn_returns { - if fn_return.span.desugaring_kind().is_some() { - // Skip `async` desugaring `impl Future`. - continue; - } - match fn_return.kind { - TyKind::OpaqueDef(item_id, _) => { - let item = tcx.hir().item(item_id); - let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { - opaque - } else { - err.emit(); - return Some(ErrorReported); - }; + suggest_new_region_bound( + tcx, + &mut err, + fn_returns, + lifetime_name, + Some(arg), + captures, + Some((param.param_ty_span, param.param_ty.to_string())), + ); + + err.emit(); + Some(ErrorReported) + } +} + +pub fn suggest_new_region_bound( + tcx: TyCtxt<'tcx>, + err: &mut DiagnosticBuilder<'_>, + fn_returns: Vec<&rustc_hir::Ty<'_>>, + lifetime_name: String, + arg: Option, + captures: String, + param: Option<(Span, String)>, +) { + debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); + // FIXME: account for the need of parens in `&(dyn Trait + '_)` + let consider = "consider changing the"; + let declare = "to declare that the"; + let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name); + let explicit_static = + arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg)); + let add_static_bound = "alternatively, add an explicit `'static` bound to this reference"; + let plus_lt = format!(" + {}", lifetime_name); + for fn_return in fn_returns { + if fn_return.span.desugaring_kind().is_some() { + // Skip `async` desugaring `impl Future`. + continue; + } + match fn_return.kind { + TyKind::OpaqueDef(item_id, _) => { + let item = tcx.hir().item(item_id); + let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { + opaque + } else { + return; + }; - if let Some(span) = opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { - name: LifetimeName::Static, - span, - .. - }) => Some(*span), - _ => None, - }) - .next() - { + if let Some(span) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { + name: LifetimeName::Static, + span, + .. + }) => Some(*span), + _ => None, + }) + .next() + { + if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( span, &format!("{} `impl Trait`'s {}", consider, explicit_static), lifetime_name.clone(), Applicability::MaybeIncorrect, ); + } + if let Some((param_span, param_ty)) = param.clone() { err.span_suggestion_verbose( - param.param_ty_span, + param_span, add_static_bound, - param.param_ty.to_string(), - Applicability::MaybeIncorrect, - ); - } else if opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { name, span, .. }) - if name.ident().to_string() == lifetime_name => - { - Some(*span) - } - _ => None, - }) - .next() - .is_some() - { - } else { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "{declare} `impl Trait` {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), - plus_lt.clone(), + param_ty, Applicability::MaybeIncorrect, ); } + } else if opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { name, span, .. }) + if name.ident().to_string() == lifetime_name => + { + Some(*span) + } + _ => None, + }) + .next() + .is_some() + { + } else { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} `impl Trait` {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt.clone(), + Applicability::MaybeIncorrect, + ); } - TyKind::TraitObject(_, lt, _) => match lt.name { - LifetimeName::ImplicitObjectLifetimeDefault => { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "{declare} trait object {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), - plus_lt.clone(), - Applicability::MaybeIncorrect, - ); - } - name if name.ident().to_string() != lifetime_name => { - // With this check we avoid suggesting redundant bounds. This - // would happen if there are nested impl/dyn traits and only - // one of them has the bound we'd suggest already there, like - // in `impl Foo + '_`. + } + TyKind::TraitObject(_, lt, _) => match lt.name { + LifetimeName::ImplicitObjectLifetimeDefault => { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} trait object {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt.clone(), + Applicability::MaybeIncorrect, + ); + } + name if name.ident().to_string() != lifetime_name => { + // With this check we avoid suggesting redundant bounds. This + // would happen if there are nested impl/dyn traits and only + // one of them has the bound we'd suggest already there, like + // in `impl Foo + '_`. + if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( lt.span, &format!("{} trait object's {}", consider, explicit_static), lifetime_name.clone(), Applicability::MaybeIncorrect, ); + } + if let Some((param_span, param_ty)) = param.clone() { err.span_suggestion_verbose( - param.param_ty_span, + param_span, add_static_bound, - param.param_ty.to_string(), + param_ty, Applicability::MaybeIncorrect, ); } - _ => {} - }, + } _ => {} - } + }, + _ => {} } - err.emit(); - Some(ErrorReported) } +} +impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn get_impl_ident_and_self_ty_from_trait( &self, def_id: DefId, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::{Subtype, ValuePairs}; +use crate::infer::{SubregionOrigin, Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_errors::ErrorReported; use rustc_hir as hir; @@ -11,44 +11,55 @@ use rustc_hir::intravisit::Visitor; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::{MultiSpan, Span}; +use rustc_span::{MultiSpan, Span, Symbol}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option { - if let Some(ref error) = self.error { - debug!("try_report_impl_not_conforming_to_trait {:?}", error); - if let RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - _sub, - sup_origin, - _sup, - ) = error.clone() - { - if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = - (&sup_origin, &sub_origin) + let error = self.error.as_ref()?; + debug!("try_report_impl_not_conforming_to_trait {:?}", error); + if let RegionResolutionError::SubSupConflict( + _, + var_origin, + sub_origin, + _sub, + sup_origin, + _sup, + ) = error.clone() + { + if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) { + if let ( + ValuePairs::Types(sub_expected_found), + ValuePairs::Types(sup_expected_found), + CompareImplMethodObligation { trait_item_def_id, .. }, + ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) { - if let ( - ValuePairs::Types(sub_expected_found), - ValuePairs::Types(sup_expected_found), - CompareImplMethodObligation { trait_item_def_id, .. }, - ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) - { - if sup_expected_found == sub_expected_found { - self.emit_err( - var_origin.span(), - sub_expected_found.expected, - sub_expected_found.found, - *trait_item_def_id, - ); - return Some(ErrorReported); - } + if sup_expected_found == sub_expected_found { + self.emit_err( + var_origin.span(), + sub_expected_found.expected, + sub_expected_found.found, + *trait_item_def_id, + ); + return Some(ErrorReported); } } } } + if let RegionResolutionError::ConcreteFailure(origin, _, _) + | RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone() + { + if let SubregionOrigin::CompareImplTypeObligation { + span, + item_name, + impl_item_def_id, + trait_item_def_id, + } = origin + { + self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id); + return Some(ErrorReported); + } + } None } @@ -107,6 +118,25 @@ } err.emit(); } + + fn emit_associated_type_err( + &self, + span: Span, + item_name: Symbol, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + ) { + let impl_sp = self.tcx().def_span(impl_item_def_id); + let trait_sp = self.tcx().def_span(trait_item_def_id); + let mut err = self + .tcx() + .sess + .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name)); + err.span_label(impl_sp, "found"); + err.span_label(trait_sp, "expected"); + + err.emit(); + } } struct TypeParamSpanVisitor<'tcx> { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/note.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/note.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/note.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/error_reporting/note.rs 2021-11-29 19:27:11.000000000 +0000 @@ -99,6 +99,12 @@ "...so that the definition in impl matches the definition from the trait", ); } + infer::CompareImplTypeObligation { span, .. } => { + label_or_note( + span, + "...so that the definition in impl matches the definition from the trait", + ); + } } } @@ -348,6 +354,18 @@ span, item_name, impl_item_def_id, + trait_item_def_id, + } => self.report_extra_impl_obligation( + span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", sup, sub), + ), + infer::CompareImplTypeObligation { + span, + item_name, + impl_item_def_id, trait_item_def_id, } => self.report_extra_impl_obligation( span, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/fudge.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/fudge.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/fudge.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/fudge.rs 2021-11-29 19:27:11.000000000 +0000 @@ -94,13 +94,12 @@ /// the actual types (`?T`, `Option`) -- and remember that /// after the snapshot is popped, the variable `?T` is no longer /// unified. + #[instrument(skip(self, f), level = "debug")] pub fn fudge_inference_if_ok(&self, f: F) -> Result where F: FnOnce() -> Result, T: TypeFoldable<'tcx>, { - debug!("fudge_inference_if_ok()"); - let variable_lengths = self.variable_lengths(); let (mut fudger, value) = self.probe(|_| { match f() { @@ -187,7 +186,7 @@ if self.type_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. - let idx = (vid.index - self.type_vars.0.start.index) as usize; + let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize; let origin = self.type_vars.1[idx]; self.infcx.next_ty_var(origin) } else { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/higher_ranked/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/higher_ranked/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/higher_ranked/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/higher_ranked/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,7 @@ use rustc_middle::ty::{self, Binder, TypeFoldable}; impl<'a, 'tcx> CombineFields<'a, 'tcx> { + #[instrument(skip(self), level = "debug")] pub fn higher_ranked_sub( &mut self, a: Binder<'tcx, T>, @@ -18,8 +19,6 @@ where T: Relate<'tcx>, { - debug!("higher_ranked_sub(a={:?}, b={:?})", a, b); - // Rather than checking the subtype relationship between `a` and `b` // as-is, we need to do some extra work here in order to make sure // that function subtyping works correctly with respect to regions diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -46,7 +46,7 @@ use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; -use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind}; +use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; pub mod canonical; @@ -64,6 +64,7 @@ pub mod nll_relate; pub mod opaque_types; pub mod outlives; +mod projection; pub mod region_constraints; pub mod resolve; mod sub; @@ -427,6 +428,15 @@ impl_item_def_id: DefId, trait_item_def_id: DefId, }, + + /// Comparing the signature and requirements of an impl associated type + /// against the containing trait + CompareImplTypeObligation { + span: Span, + item_name: Symbol, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -692,17 +702,6 @@ t.fold_with(&mut self.freshener()) } - /// Returns whether `ty` is a diverging type variable or not. - /// (If `ty` is not a type variable at all, returns not diverging.) - /// - /// No attempt is made to resolve `ty`. - pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging { - match *ty.kind() { - ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid), - _ => Diverging::NotDiverging, - } - } - /// Returns the origin of the type variable identified by `vid`, or `None` /// if this is not a type variable. /// @@ -808,8 +807,8 @@ } } + #[instrument(skip(self, snapshot), level = "debug")] fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { - debug!("rollback_to(cause={})", cause); let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, @@ -826,8 +825,8 @@ inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); } + #[instrument(skip(self, snapshot), level = "debug")] fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { - debug!("commit_from()"); let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, @@ -842,11 +841,11 @@ } /// Executes `f` and commit the bindings. + #[instrument(skip(self, f), level = "debug")] pub fn commit_unconditionally(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("commit_unconditionally()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); self.commit_from(snapshot); @@ -854,11 +853,11 @@ } /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`. + #[instrument(skip(self, f), level = "debug")] pub fn commit_if_ok(&self, f: F) -> Result where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result, { - debug!("commit_if_ok()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); @@ -874,11 +873,11 @@ } /// Execute `f` then unroll any bindings it creates. + #[instrument(skip(self, f), level = "debug")] pub fn probe(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("probe()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); self.rollback_to("probe", snapshot); @@ -886,11 +885,11 @@ } /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. + #[instrument(skip(self, f), level = "debug")] pub fn probe_maybe_skip_leak_check(&self, should_skip: bool, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("probe()"); let snapshot = self.start_snapshot(); let was_skip_leak_check = self.skip_leak_check.get(); if should_skip { @@ -947,18 +946,19 @@ }) } + #[instrument(skip(self), level = "debug")] pub fn sub_regions( &self, origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) { - debug!("sub_regions({:?} <: {:?})", a, b); self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b); } /// Require that the region `r` be equal to one of the regions in /// the set `regions`. + #[instrument(skip(self), level = "debug")] pub fn member_constraint( &self, opaque_type_def_id: DefId, @@ -967,7 +967,6 @@ region: ty::Region<'tcx>, in_regions: &Lrc>>, ) { - debug!("member_constraint({:?} <: {:?})", region, in_regions); self.inner.borrow_mut().unwrap_region_constraints().member_constraint( opaque_type_def_id, definition_span, @@ -1061,12 +1060,17 @@ }) } - pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin) + /// Number of type variables created so far. + pub fn num_ty_vars(&self) -> usize { + self.inner.borrow_mut().type_variables().num_vars() + } + + pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(self.universe(), origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin)) + self.tcx.mk_ty_var(self.next_ty_var_id(origin)) } pub fn next_ty_var_in_universe( @@ -1074,18 +1078,10 @@ origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables().new_var( - universe, - Diverging::NotDiverging, - origin, - ); + let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin); self.tcx.mk_ty_var(vid) } - pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin)) - } - pub fn next_const_var( &self, ty: Ty<'tcx>, @@ -1197,7 +1193,6 @@ // as the substitutions for the default, `(T, U)`. let ty_var_id = self.inner.borrow_mut().type_variables().new_var( self.universe(), - Diverging::NotDiverging, TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition( param.name, @@ -1810,6 +1805,7 @@ ReferenceOutlivesReferent(_, a) => a, CallReturn(a) => a, CompareImplMethodObligation { span, .. } => span, + CompareImplTypeObligation { span, .. } => span, } } @@ -1830,6 +1826,17 @@ span: cause.span, item_name, impl_item_def_id, + trait_item_def_id, + }, + + traits::ObligationCauseCode::CompareImplTypeObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } => SubregionOrigin::CompareImplTypeObligation { + span: cause.span, + item_name, + impl_item_def_id, trait_item_def_id, }, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/nll_relate/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/nll_relate/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/nll_relate/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/nll_relate/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -22,7 +22,6 @@ //! constituents) use crate::infer::combine::ConstEquateRelation; -use crate::infer::type_variable::Diverging; use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; use rustc_data_structures::fx::FxHashMap; @@ -508,6 +507,7 @@ true } + #[instrument(skip(self, info), level = "trace")] fn relate_with_variance>( &mut self, variance: ty::Variance, @@ -515,23 +515,22 @@ a: T, b: T, ) -> RelateResult<'tcx, T> { - debug!("relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b); - let old_ambient_variance = self.ambient_variance; self.ambient_variance = self.ambient_variance.xform(variance); - self.ambient_variance_info = self.ambient_variance_info.clone().xform(info); + self.ambient_variance_info = self.ambient_variance_info.xform(info); - debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance); + debug!(?self.ambient_variance); let r = self.relate(a, b)?; self.ambient_variance = old_ambient_variance; - debug!("relate_with_variance: r={:?}", r); + debug!(?r); Ok(r) } + #[instrument(skip(self), level = "debug")] fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let a = self.infcx.shallow_resolve(a); @@ -574,7 +573,7 @@ } _ => { - debug!("tys(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); + debug!(?a, ?b, ?self.ambient_variance); // Will also handle unification of `IntVar` and `FloatVar`. self.infcx.super_combine_tys(self, a, b) @@ -582,27 +581,28 @@ } } + #[instrument(skip(self), level = "trace")] fn regions( &mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("regions(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); + debug!(?self.ambient_variance); let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes); let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes); - debug!("regions: v_a = {:?}", v_a); - debug!("regions: v_b = {:?}", v_b); + debug!(?v_a); + debug!(?v_b); if self.ambient_covariance() { // Covariance: a <= b. Hence, `b: a`. - self.push_outlives(v_b, v_a, self.ambient_variance_info.clone()); + self.push_outlives(v_b, v_a, self.ambient_variance_info); } if self.ambient_contravariance() { // Contravariant: b <= a. Hence, `a: b`. - self.push_outlives(v_a, v_b, self.ambient_variance_info.clone()); + self.push_outlives(v_a, v_b, self.ambient_variance_info); } Ok(a) @@ -629,6 +629,7 @@ } } + #[instrument(skip(self), level = "trace")] fn binders( &mut self, a: ty::Binder<'tcx, T>, @@ -656,7 +657,7 @@ // - Instantiate binders on `b` universally, yielding a universe U1. // - Instantiate binders on `a` existentially in U1. - debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance); + debug!(?self.ambient_variance); if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { // Fast path for the common case. @@ -674,8 +675,8 @@ let b_scope = self.create_scope(b, UniversallyQuantified(true)); let a_scope = self.create_scope(a, UniversallyQuantified(false)); - debug!("binders: a_scope = {:?} (existential)", a_scope); - debug!("binders: b_scope = {:?} (universal)", b_scope); + debug!(?a_scope, "(existential)"); + debug!(?b_scope, "(universal)"); self.b_scopes.push(b_scope); self.a_scopes.push(a_scope); @@ -718,8 +719,8 @@ let a_scope = self.create_scope(a, UniversallyQuantified(true)); let b_scope = self.create_scope(b, UniversallyQuantified(false)); - debug!("binders: a_scope = {:?} (universal)", a_scope); - debug!("binders: b_scope = {:?} (existential)", b_scope); + debug!(?a_scope, "(universal)"); + debug!(?b_scope, "(existential)"); self.a_scopes.push(a_scope); self.b_scopes.push(b_scope); @@ -927,8 +928,7 @@ // Replacing with a new variable in the universe `self.universe`, // it will be unified later with the original type variable in // the universe `_universe`. - let new_var_id = - variables.new_var(self.universe, Diverging::NotDiverging, origin); + let new_var_id = variables.new_var(self.universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/components.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/components.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/components.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/components.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,215 @@ +// The outlines relation `T: 'a` or `'a: 'b`. This code frequently +// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that +// RFC for reference. + +use rustc_data_structures::sso::SsoHashSet; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use smallvec::{smallvec, SmallVec}; + +#[derive(Debug)] +pub enum Component<'tcx> { + Region(ty::Region<'tcx>), + Param(ty::ParamTy), + UnresolvedInferenceVariable(ty::InferTy), + + // Projections like `T::Foo` are tricky because a constraint like + // `T::Foo: 'a` can be satisfied in so many ways. There may be a + // where-clause that says `T::Foo: 'a`, or the defining trait may + // include a bound like `type Foo: 'static`, or -- in the most + // conservative way -- we can prove that `T: 'a` (more generally, + // that all components in the projection outlive `'a`). This code + // is not in a position to judge which is the best technique, so + // we just product the projection as a component and leave it to + // the consumer to decide (but see `EscapingProjection` below). + Projection(ty::ProjectionTy<'tcx>), + + // In the case where a projection has escaping regions -- meaning + // regions bound within the type itself -- we always use + // the most conservative rule, which requires that all components + // outlive the bound. So for example if we had a type like this: + // + // for<'a> Trait1< >::Foo > + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + // + // then the inner projection (underlined) has an escaping region + // `'a`. We consider that outer trait `'c` to meet a bound if `'b` + // outlives `'b: 'c`, and we don't consider whether the trait + // declares that `Foo: 'static` etc. Therefore, we just return the + // free components of such a projection (in this case, `'b`). + // + // However, in the future, we may want to get smarter, and + // actually return a "higher-ranked projection" here. Therefore, + // we mark that these components are part of an escaping + // projection, so that implied bounds code can avoid relying on + // them. This gives us room to improve the regionck reasoning in + // the future without breaking backwards compat. + EscapingProjection(Vec>), +} + +/// Push onto `out` all the things that must outlive `'a` for the condition +/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. +pub fn push_outlives_components( + tcx: TyCtxt<'tcx>, + ty0: Ty<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, +) { + let mut visited = SsoHashSet::new(); + compute_components(tcx, ty0, out, &mut visited); + debug!("components({:?}) = {:?}", ty0, out); +} + +fn compute_components( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, + visited: &mut SsoHashSet>, +) { + // Descend through the types, looking for the various "base" + // components and collecting them into `out`. This is not written + // with `collect()` because of the need to sometimes skip subtrees + // in the `subtys` iterator (e.g., when encountering a + // projection). + match *ty.kind() { + ty::FnDef(_, substs) => { + // HACK(eddyb) ignore lifetimes found shallowly in `substs`. + // This is inconsistent with `ty::Adt` (including all substs) + // and with `ty::Closure` (ignoring all substs other than + // upvars, of which a `ty::FnDef` doesn't have any), but + // consistent with previous (accidental) behavior. + // See https://github.com/rust-lang/rust/issues/70917 + // for further background and discussion. + for child in substs { + match child.unpack() { + GenericArgKind::Type(ty) => { + compute_components(tcx, ty, out, visited); + } + GenericArgKind::Lifetime(_) => {} + GenericArgKind::Const(_) => { + compute_components_recursive(tcx, child, out, visited); + } + } + } + } + + ty::Array(element, _) => { + // Don't look into the len const as it doesn't affect regions + compute_components(tcx, element, out, visited); + } + + ty::Closure(_, ref substs) => { + let tupled_ty = substs.as_closure().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); + } + + ty::Generator(_, ref substs, _) => { + // Same as the closure case + let tupled_ty = substs.as_generator().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); + + // We ignore regions in the generator interior as we don't + // want these to affect region inference + } + + // All regions are bound inside a witness + ty::GeneratorWitness(..) => (), + + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` + // is implied by the environment is done in regionck. + ty::Param(p) => { + out.push(Component::Param(p)); + } + + // For projections, we prefer to generate an obligation like + // `>::Foo: 'a`, because this gives the + // regionck more ways to prove that it holds. However, + // regionck is not (at least currently) prepared to deal with + // higher-ranked regions that may appear in the + // trait-ref. Therefore, if we see any higher-ranke regions, + // we simply fallback to the most restrictive rule, which + // requires that `Pi: 'a` for all `i`. + ty::Projection(ref data) => { + if !data.has_escaping_bound_vars() { + // best case: no escaping regions, so push the + // projection and skip the subtree (thus generating no + // constraints for Pi). This defers the choice between + // the rules OutlivesProjectionEnv, + // OutlivesProjectionTraitDef, and + // OutlivesProjectionComponents to regionck. + out.push(Component::Projection(*data)); + } else { + // fallback case: hard code + // OutlivesProjectionComponents. Continue walking + // through and constrain Pi. + let mut subcomponents = smallvec![]; + let mut subvisited = SsoHashSet::new(); + compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); + out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); + } + } + + // We assume that inference variables are fully resolved. + // So, if we encounter an inference variable, just record + // the unresolved variable as a component. + ty::Infer(infer_ty) => { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); + } + + // Most types do not introduce any region binders, nor + // involve any other subtle cases, and so the WF relation + // simply constraints any regions referenced directly by + // the type and then visits the types that are lexically + // contained within. (The comments refer to relevant rules + // from RFC1214.) + ty::Bool | // OutlivesScalar + ty::Char | // OutlivesScalar + ty::Int(..) | // OutlivesScalar + ty::Uint(..) | // OutlivesScalar + ty::Float(..) | // OutlivesScalar + ty::Never | // ... + ty::Adt(..) | // OutlivesNominalType + ty::Opaque(..) | // OutlivesNominalType (ish) + ty::Foreign(..) | // OutlivesNominalType + ty::Str | // OutlivesScalar (ish) + ty::Slice(..) | // ... + ty::RawPtr(..) | // ... + ty::Ref(..) | // OutlivesReference + ty::Tuple(..) | // ... + ty::FnPtr(_) | // OutlivesFunction (*) + ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) + ty::Placeholder(..) | + ty::Bound(..) | + ty::Error(_) => { + // (*) Function pointers and trait objects are both binders. + // In the RFC, this means we would add the bound regions to + // the "bound regions list". In our representation, no such + // list is maintained explicitly, because bound regions + // themselves can be readily identified. + compute_components_recursive(tcx, ty.into(), out, visited); + } + } +} + +fn compute_components_recursive( + tcx: TyCtxt<'tcx>, + parent: GenericArg<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, + visited: &mut SsoHashSet>, +) { + for child in parent.walk_shallow(tcx, visited) { + match child.unpack() { + GenericArgKind::Type(ty) => { + compute_components(tcx, ty, out, visited); + } + GenericArgKind::Lifetime(lt) => { + // Ignore late-bound regions. + if !lt.is_late_bound() { + out.push(Component::Region(lt)); + } + } + GenericArgKind::Const(_) => { + compute_components_recursive(tcx, child, out, visited); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ //! Various code related to computing outlives relations. +pub mod components; pub mod env; pub mod obligations; pub mod verify; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/obligations.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/obligations.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/obligations.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/outlives/obligations.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ //! Code that handles "type-outlives" constraints like `T: 'a`. This -//! is based on the `push_outlives_components` function defined on the tcx, +//! is based on the `push_outlives_components` function defined in rustc_infer, //! but it adds a bit of heuristics on top, in particular to deal with //! associated types and projections. //! @@ -59,13 +59,13 @@ //! might later infer `?U` to something like `&'b u32`, which would //! imply that `'b: 'a`. +use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::{ self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound, }; use crate::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::outlives::Component; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; @@ -271,7 +271,7 @@ assert!(!ty.has_escaping_bound_vars()); let mut components = smallvec![]; - self.tcx.push_outlives_components(ty, &mut components); + push_outlives_components(self.tcx, ty, &mut components); self.components_must_outlive(origin, &components, region); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/projection.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/projection.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/projection.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/projection.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::{self, ToPredicate, Ty}; + +use crate::traits::{Obligation, PredicateObligation}; + +use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use super::InferCtxt; + +impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + /// Instead of normalizing an associated type projection, + /// this function generates an inference variable and registers + /// an obligation that this inference variable must be the result + /// of the given projection. This allows us to proceed with projections + /// while they cannot be resolved yet due to missing information or + /// simply due to the lack of access to the trait resolution machinery. + pub fn infer_projection( + &self, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + obligations: &mut Vec>, + ) -> Ty<'tcx> { + let def_id = projection_ty.item_def_id; + let ty_var = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::NormalizeProjectionType, + span: self.tcx.def_span(def_id), + }); + let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var }); + let obligation = Obligation::with_depth( + cause, + recursion_depth, + param_env, + projection.to_predicate(self.tcx), + ); + obligations.push(obligation); + ty_var + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/region_constraints/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/region_constraints/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/region_constraints/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/region_constraints/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -540,6 +540,7 @@ }); } + #[instrument(skip(self, origin), level = "debug")] pub fn make_subregion( &mut self, origin: SubregionOrigin<'tcx>, @@ -547,10 +548,7 @@ sup: Region<'tcx>, ) { // cannot add constraints once regions are resolved - debug!( - "RegionConstraintCollector: make_subregion({:?}, {:?}) due to {:?}", - sub, sup, origin - ); + debug!("origin = {:#?}", origin); match (sub, sup) { (&ReLateBound(..), _) | (_, &ReLateBound(..)) => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/sub.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/sub.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/sub.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/sub.rs 2021-11-29 19:27:11.000000000 +0000 @@ -97,11 +97,11 @@ self.fields.obligations.push(Obligation::new( self.fields.trace.cause.clone(), self.fields.param_env, - ty::PredicateKind::Subtype(ty::SubtypePredicate { + ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: self.a_is_expected, a, b, - }) + })) .to_predicate(self.tcx()), )); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/type_variable.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/type_variable.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/infer/type_variable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/infer/type_variable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -129,19 +129,16 @@ SubstitutionPlaceholder, AutoDeref, AdjustmentType, - DivergingFn, + + /// In type check, when we are type checking a function that + /// returns `-> dyn Foo`, we substitute a type variable for the + /// return type for diagnostic purposes. + DynReturnFn, LatticeVariable, } pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, - diverging: Diverging, -} - -#[derive(Copy, Clone, Debug)] -pub enum Diverging { - NotDiverging, - Diverges, } #[derive(Copy, Clone, Debug)] @@ -191,20 +188,12 @@ } impl<'tcx> TypeVariableTable<'_, 'tcx> { - /// Returns the diverges flag given when `vid` was created. - /// - /// Note that this function does not return care whether - /// `vid` has been unified with something else or not. - pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging { - self.storage.values.get(vid.index as usize).diverging - } - /// Returns the origin that was given when `vid` was created. /// /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.storage.values.get(vid.index as usize).origin + &self.storage.values.get(vid.as_usize()).origin } /// Records that `a == b`, depending on `dir`. @@ -260,7 +249,6 @@ pub fn new_var( &mut self, universe: ty::UniverseIndex, - diverging: Diverging, origin: TypeVariableOrigin, ) -> ty::TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); @@ -268,13 +256,10 @@ let sub_key = self.sub_relations().new_key(()); assert_eq!(eq_key.vid, sub_key); - let index = self.values().push(TypeVariableData { origin, diverging }); - assert_eq!(eq_key.vid.index, index as u32); + let index = self.values().push(TypeVariableData { origin }); + assert_eq!(eq_key.vid.as_u32(), index as u32); - debug!( - "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", - eq_key.vid, universe, diverging, origin, - ); + debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,); eq_key.vid } @@ -357,11 +342,11 @@ &mut self, value_count: usize, ) -> (Range, Vec) { - let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 }; + let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars()); ( range.start..range.end, - (range.start.index..range.end.index) - .map(|index| self.storage.values.get(index as usize).origin) + (range.start.as_usize()..range.end.as_usize()) + .map(|index| self.storage.values.get(index).origin) .collect(), ) } @@ -371,7 +356,7 @@ pub fn unsolved_variables(&mut self) -> Vec { (0..self.storage.values.len()) .filter_map(|i| { - let vid = ty::TyVid { index: i as u32 }; + let vid = ty::TyVid::from_usize(i); match self.probe(vid) { TypeVariableValue::Unknown { .. } => Some(vid), TypeVariableValue::Known { .. } => None, @@ -415,6 +400,7 @@ } impl<'tcx> From for TyVidEqKey<'tcx> { + #[inline] // make this function eligible for inlining - it is quite hot. fn from(vid: ty::TyVid) -> Self { TyVidEqKey { vid, phantom: PhantomData } } @@ -424,10 +410,10 @@ type Value = TypeVariableValue<'tcx>; #[inline(always)] fn index(&self) -> u32 { - self.vid.index + self.vid.as_u32() } fn from_index(i: u32) -> Self { - TyVidEqKey::from(ty::TyVid { index: i }) + TyVidEqKey::from(ty::TyVid::from_u32(i)) } fn tag() -> &'static str { "TyVidEqKey" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/engine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/engine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/engine.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/engine.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness}; @@ -34,7 +35,7 @@ cause, recursion_depth: 0, param_env, - predicate: trait_ref.without_const().to_predicate(infcx.tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(infcx.tcx), }, ); } @@ -73,6 +74,8 @@ } fn pending_obligations(&self) -> Vec>; + + fn relationships(&mut self) -> &mut FxHashMap; } pub trait TraitEngineExt<'tcx> { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/error_reporting/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/error_reporting/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/error_reporting/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/error_reporting/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -83,10 +83,6 @@ messages.push(msg.clone()); } } - if trait_span.is_some() { - // Only provide the help if its a local trait, otherwise it's not actionable. - violation.solution(&mut err); - } } } let has_multi_span = !multi_span.is_empty(); @@ -104,5 +100,13 @@ to be resolvable dynamically; for more information visit \ ", ); + if trait_span.is_some() { + let mut reported_violations: Vec<_> = reported_violations.into_iter().collect(); + reported_violations.sort(); + for violation in reported_violations { + // Only provide the help if its a local trait, otherwise it's not actionable. + violation.solution(&mut err); + } + } err } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -66,10 +66,6 @@ pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx>, - /// Diagnostics only: we opportunistically change the `code.span` when we encounter an - /// obligation error caused by a call argument. When this is the case, we also signal that in - /// this field to ensure accuracy of suggestions. - pub points_at_arg_span: bool, /// Diagnostics only: the 'root' obligation which resulted in /// the failure to process `obligation`. This is the obligation /// that was initially passed to `register_predicate_obligation` @@ -128,7 +124,7 @@ code: FulfillmentErrorCode<'tcx>, root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx> { - FulfillmentError { obligation, code, points_at_arg_span: false, root_obligation } + FulfillmentError { obligation, code, root_obligation } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/project.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/project.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/project.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/project.rs 2021-11-29 19:27:11.000000000 +0000 @@ -153,47 +153,6 @@ assert!(!fresh_key, "never started projecting `{:?}`", key); } - /// Mark the relevant projection cache key as having its derived obligations - /// complete, so they won't have to be re-computed (this is OK to do in a - /// snapshot - if the snapshot is rolled back, the obligations will be - /// marked as incomplete again). - pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) { - let mut map = self.map(); - let ty = match map.get(&key) { - Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => { - debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); - ty.value - } - ref value => { - // Type inference could "strand behind" old cache entries. Leave - // them alone for now. - debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value); - return; - } - }; - - map.insert( - key, - ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), - ); - } - - /// A specialized version of `complete` for when the key's value is known - /// to be a NormalizedTy. - pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) { - // We want to insert `ty` with no obligations. If the existing value - // already has no obligations (as is common) we don't insert anything. - if !ty.obligations.is_empty() { - self.map().insert( - key, - ProjectionCacheEntry::NormalizedTy(Normalized { - value: ty.value, - obligations: vec![], - }), - ); - } - } - /// Indicates that trying to normalize `key` resulted in /// ambiguity. No point in trying it again then until we gain more /// type information (in which case, the "fully resolved" key will diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_infer/src/traits/util.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_infer/src/traits/util.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ use smallvec::smallvec; +use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_middle::ty::outlives::Component; use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness}; use rustc_span::symbol::Ident; @@ -200,7 +200,7 @@ let visited = &mut self.visited; let mut components = smallvec![]; - tcx.push_outlives_components(ty_max, &mut components); + push_outlives_components(tcx, ty_max, &mut components); self.stack.extend( components .into_iter() @@ -231,6 +231,7 @@ None } }) + .map(ty::Binder::dummy) .map(|predicate_kind| predicate_kind.to_predicate(tcx)) .filter(|&predicate| visited.insert(predicate)) .map(|predicate| { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_interface" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false @@ -14,6 +14,7 @@ smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } +rustc_borrowck = { path = "../rustc_borrowck" } rustc_builtin_macros = { path = "../rustc_builtin_macros" } rustc_expand = { path = "../rustc_expand" } rustc_parse = { path = "../rustc_parse" } @@ -31,8 +32,10 @@ rustc_codegen_llvm = { path = "../rustc_codegen_llvm", optional = true } rustc_hir = { path = "../rustc_hir" } rustc_metadata = { path = "../rustc_metadata" } -rustc_mir = { path = "../rustc_mir" } +rustc_const_eval = { path = "../rustc_const_eval" } rustc_mir_build = { path = "../rustc_mir_build" } +rustc_mir_transform = { path = "../rustc_mir_transform" } +rustc_monomorphize = { path = "../rustc_monomorphize" } rustc_passes = { path = "../rustc_passes" } rustc_typeck = { path = "../rustc_typeck" } rustc_lint = { path = "../rustc_lint" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/callbacks.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/callbacks.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/callbacks.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/callbacks.rs 2021-11-29 19:27:11.000000000 +0000 @@ -25,13 +25,23 @@ }) } +fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { + tls::with_opt(|tcx| { + if let Some(tcx) = tcx { + let _span = tcx.source_span(def_id); + // Sanity check: relative span's parent must be an absolute span. + debug_assert_eq!(_span.data_untracked().parent, None); + } + }) +} + /// This is a callback from `rustc_ast` as it cannot access the implicit state /// in `rustc_middle` otherwise. It is used to when diagnostic messages are /// emitted and stores them in the current query, if there is one. fn track_diagnostic(diagnostic: &Diagnostic) { tls::with_context_opt(|icx| { if let Some(icx) = icx { - if let Some(ref diagnostics) = icx.diagnostics { + if let Some(diagnostics) = icx.diagnostics { let mut diagnostics = diagnostics.lock(); diagnostics.extend(Some(diagnostic.clone())); } @@ -56,6 +66,7 @@ /// TyCtxt in. pub fn setup_callbacks() { rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_))); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/interface.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/interface.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/interface.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/interface.rs 2021-11-29 19:27:11.000000000 +0000 @@ -65,13 +65,7 @@ sess: &Session, attrs: &[ast::Attribute], ) -> OutputFilenames { - util::build_output_filenames( - &self.input, - &self.output_dir, - &self.output_file, - &attrs, - &sess, - ) + util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess) } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(internal_output_capture)] +#![feature(thread_spawn_unchecked)] #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/passes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/passes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/passes.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/passes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,10 +4,11 @@ use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self as ast, visit}; +use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; -use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; +use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorReported, PResult}; use rustc_expand::base::ExtCtxt; @@ -15,26 +16,25 @@ use rustc_hir::Crate; use rustc_lint::LintStore; use rustc_metadata::creader::CStore; +use rustc_metadata::{encode_metadata, EncodedMetadata}; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::middle; -use rustc_middle::middle::cstore::{MetadataLoader, MetadataLoaderDyn}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; -use rustc_mir as mir; use rustc_mir_build as mir_build; -use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; +use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_serialize::json; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; +use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn}; use rustc_session::lint; use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; -use rustc_session::Session; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_session::{Limit, Session}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::FileName; use rustc_trait_selection::traits; use rustc_typeck as typeck; @@ -169,7 +169,7 @@ ) -> BoxedResolver { tracing::trace!("create_resolver"); BoxedResolver::new(sess, move |sess, resolver_arenas| { - Resolver::new(sess, &krate, &crate_name, metadata_loader, &resolver_arenas) + Resolver::new(sess, krate, crate_name, metadata_loader, resolver_arenas) }) } @@ -179,7 +179,7 @@ register_lints: impl Fn(&Session, &mut LintStore), mut krate: ast::Crate, crate_name: &str, -) -> Result<(ast::Crate, Lrc)> { +) -> Result<(ast::Crate, LintStore)> { krate = sess.time("attributes_injection", || { rustc_builtin_macros::cmdline_attrs::inject( krate, @@ -201,7 +201,7 @@ sess.opts.cg.metadata.clone(), ); sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized"); - rustc_incremental::prepare_session_directory(sess, &crate_name, stable_crate_id)?; + rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?; if sess.opts.incremental.is_some() { sess.time("incr_comp_garbage_collect_session_directories", || { @@ -219,7 +219,7 @@ sess.opts.debugging_opts.no_interleave_lints, sess.unstable_options(), ); - register_lints(&sess, &mut lint_store); + register_lints(sess, &mut lint_store); let registrars = sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate)); @@ -230,9 +230,6 @@ } }); - let lint_store = Lrc::new(lint_store); - sess.init_lint_store(lint_store.clone()); - Ok((krate, lint_store)) } @@ -240,13 +237,15 @@ sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], crate_name: &str, ) { sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| { rustc_lint::check_ast_crate( sess, lint_store, - &krate, + krate, + crate_attrs, true, None, rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), @@ -266,15 +265,15 @@ resolver: &mut Resolver<'_>, ) -> Result { tracing::trace!("configure_and_expand"); - pre_expansion_lint(sess, lint_store, &krate, crate_name); + pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); krate = sess.time("crate_injection", || { let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s)); - rustc_builtin_macros::standard_library_imports::inject(krate, resolver, &sess, alt_std_name) + rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess, alt_std_name) }); - util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer()); + util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer()); // Expand all macros krate = sess.time("macro_expand_crate", || { @@ -311,10 +310,9 @@ // Create the config for macro expansion let features = sess.features_untracked(); - let recursion_limit = - rustc_middle::middle::limits::get_recursion_limit(&krate.attrs, &sess); + let recursion_limit = get_recursion_limit(&krate.attrs, sess); let cfg = rustc_expand::expand::ExpansionConfig { - features: Some(&features), + features: Some(features), recursion_limit, trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, @@ -323,12 +321,13 @@ ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; + let crate_attrs = krate.attrs.clone(); let extern_mod_loaded = |ident: Ident, attrs, items, span| { let krate = ast::Crate { attrs, items, span }; - pre_expansion_lint(sess, lint_store, &krate, &ident.name.as_str()); + pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str()); (krate.attrs, krate.items) }; - let mut ecx = ExtCtxt::new(&sess, cfg, resolver, Some(&extern_mod_loaded)); + let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded)); // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); @@ -370,7 +369,7 @@ })?; sess.time("maybe_building_test_harness", || { - rustc_builtin_macros::test_harness::inject(&sess, resolver, &mut krate) + rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate) }); if let Some(PpMode::Source(PpSourceMode::EveryBodyLoops)) = sess.opts.pretty { @@ -393,8 +392,8 @@ // start passing '--crate-type proc-macro' if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate { let mut msg = sess.diagnostic().struct_warn( - &"Trying to document proc macro crate \ - without passing '--crate-type proc-macro to rustdoc", + "Trying to document proc macro crate \ + without passing '--crate-type proc-macro to rustdoc", ); msg.warn("The generated documentation may be incorrect"); @@ -404,7 +403,7 @@ let num_crate_types = crate_types.len(); let is_test_crate = sess.opts.test; rustc_builtin_macros::proc_macro_harness::inject( - &sess, + sess, resolver, krate, is_proc_macro_crate, @@ -438,12 +437,18 @@ }); // Add all buffered lints from the `ParseSess` to the `Session`. - sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { - info!("{} parse sess buffered_lints", buffered_lints.len()); - for early_lint in buffered_lints.drain(..) { - resolver.lint_buffer().add_early_lint(early_lint); - } - }); + // The ReplaceBodyWithLoop pass may have deleted some AST nodes, potentially + // causing a delay_span_bug later if a buffered lint refers to such a deleted + // AST node (issue #87308). Since everybody_loops is for pretty-printing only, + // anyway, we simply skip all buffered lints here. + if !matches!(sess.opts.pretty, Some(PpMode::Source(PpSourceMode::EveryBodyLoops))) { + sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { + info!("{} parse sess buffered_lints", buffered_lints.len()); + for early_lint in buffered_lints.drain(..) { + resolver.lint_buffer().add_early_lint(early_lint); + } + }); + } Ok(krate) } @@ -464,15 +469,12 @@ arena, ); - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_hir_stats(&hir_crate); - } - sess.time("early_lint_checks", || { rustc_lint::check_ast_crate( sess, lint_store, &krate, + &krate.attrs, false, Some(std::mem::take(resolver.lint_buffer())), rustc_lint::BuiltinCombinedEarlyLintPass::new(), @@ -695,7 +697,7 @@ ); let output_paths = - generated_output_paths(sess, &outputs, compiler.output_file.is_some(), &crate_name); + generated_output_paths(sess, &outputs, compiler.output_file.is_some(), crate_name); // Ensure the source file isn't accidentally overwritten during compilation. if let Some(ref input_path) = compiler.input_path { @@ -741,9 +743,12 @@ let providers = &mut Providers::default(); providers.analysis = analysis; proc_macro_decls::provide(providers); + rustc_const_eval::provide(providers); rustc_middle::hir::provide(providers); - mir::provide(providers); + mir_borrowck::provide(providers); mir_build::provide(providers); + rustc_mir_transform::provide(providers); + rustc_monomorphize::provide(providers); rustc_privacy::provide(providers); typeck::provide(providers); ty::provide(providers); @@ -833,7 +838,7 @@ dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), queries.as_dyn(), - &crate_name, + crate_name, outputs, ) }) @@ -862,7 +867,7 @@ CStore::from_tcx(tcx).report_unused_deps(tcx); }, { - par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { + tcx.hir().par_for_each_module(|module| { tcx.ensure().check_mod_loops(module); tcx.ensure().check_mod_attrs(module); tcx.ensure().check_mod_naked_functions(module); @@ -887,14 +892,12 @@ parallel!( { sess.time("match_checking", || { - tcx.par_body_owners(|def_id| { - tcx.ensure().check_match(def_id.to_def_id()); - }); + tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id.to_def_id())) }); }, { sess.time("liveness_and_intrinsic_checking", || { - par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { + tcx.hir().par_for_each_module(|module| { // this must run before MIR dump, because // "not all control paths return a value" is reported here. // @@ -908,14 +911,14 @@ }); sess.time("MIR_borrow_checking", || { - tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); + tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); }); sess.time("MIR_effect_checking", || { - for def_id in tcx.body_owners() { + for def_id in tcx.hir().body_owners() { tcx.ensure().thir_check_unsafety(def_id); if !tcx.sess.opts.debugging_opts.thir_unsafeck { - mir::transform::check_unsafety::check_unsafety(tcx, def_id); + rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id); } if tcx.hir().body_const_context(def_id).is_some() { @@ -964,7 +967,7 @@ }, { sess.time("privacy_checking_modules", || { - par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { + tcx.hir().par_for_each_module(|module| { tcx.ensure().check_mod_privacy(module); }); }); @@ -978,7 +981,7 @@ fn encode_and_write_metadata( tcx: TyCtxt<'_>, outputs: &OutputFilenames, -) -> (middle::cstore::EncodedMetadata, bool) { +) -> (EncodedMetadata, bool) { #[derive(PartialEq, Eq, PartialOrd, Ord)] enum MetadataKind { None, @@ -1001,8 +1004,8 @@ .unwrap_or(MetadataKind::None); let metadata = match metadata_kind { - MetadataKind::None => middle::cstore::EncodedMetadata::new(), - MetadataKind::Uncompressed | MetadataKind::Compressed => tcx.encode_metadata(), + MetadataKind::None => EncodedMetadata::new(), + MetadataKind::Uncompressed | MetadataKind::Compressed => encode_metadata(tcx), }; let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata"); @@ -1021,7 +1024,7 @@ .tempdir_in(out_filename.parent().unwrap()) .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))); let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); - let metadata_filename = emit_metadata(tcx.sess, &metadata.raw_data, &metadata_tmpdir); + let metadata_filename = emit_metadata(tcx.sess, metadata.raw_data(), &metadata_tmpdir); if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) { tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); } @@ -1063,7 +1066,7 @@ info!("Post-codegen\n{:?}", tcx.debug_stats()); if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) { + if let Err(e) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) { tcx.sess.err(&format!("could not emit MIR: {}", e)); tcx.sess.abort_if_errors(); } @@ -1071,3 +1074,24 @@ codegen } + +fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { + if let Some(attr) = krate_attrs + .iter() + .find(|attr| attr.has_name(sym::recursion_limit) && attr.value_str().is_none()) + { + // This is here mainly to check for using a macro, such as + // #![recursion_limit = foo!()]. That is not supported since that + // would require expanding this while in the middle of expansion, + // which needs to know the limit before expanding. Otherwise, + // validation would normally be caught in AstValidator (via + // `check_builtin_attribute`), but by the time that runs the macro + // is expanded, and it doesn't give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + attr, + sym::recursion_limit, + ); + } + rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/proc_macro_decls.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/proc_macro_decls.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/proc_macro_decls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/proc_macro_decls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option { let mut finder = Finder { tcx, decls: None }; - tcx.hir().krate().visit_all_item_likes(&mut finder); + tcx.hir().visit_all_item_likes(&mut finder); finder.decls.map(|id| tcx.hir().local_def_id(id)) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/queries.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/queries.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/queries.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/queries.rs 2021-11-29 19:27:11.000000000 +0000 @@ -110,7 +110,7 @@ &self.compiler.sess } fn codegen_backend(&self) -> &Lrc> { - &self.compiler.codegen_backend() + self.compiler.codegen_backend() } fn dep_graph_future(&self) -> Result<&Query>> { @@ -135,7 +135,7 @@ let krate = self.parse()?.take(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; - let result = passes::register_plugins( + let (krate, lint_store) = passes::register_plugins( self.session(), &*self.codegen_backend().metadata_loader(), self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), @@ -150,7 +150,7 @@ // called, which happens within passes::register_plugins(). self.dep_graph_future().ok(); - Ok(result) + Ok((krate, Lrc::new(lint_store))) }) } @@ -181,7 +181,7 @@ &crate_name, ); let krate = resolver.access(|resolver| { - passes::configure_and_expand(&sess, &lint_store, krate, &crate_name, resolver) + passes::configure_and_expand(sess, &lint_store, krate, &crate_name, resolver) })?; Ok((Rc::new(krate), Rc::new(RefCell::new(resolver)), lint_store)) }) @@ -343,7 +343,7 @@ let sess = &self.sess; let dep_graph = self.dep_graph; sess.time("serialize_work_products", || { - rustc_incremental::save_work_product_index(&sess, &dep_graph, work_products) + rustc_incremental::save_work_product_index(sess, &dep_graph, work_products) }); let prof = self.sess.prof.clone(); @@ -386,7 +386,7 @@ F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T, { let mut _timer = None; - let queries = Queries::new(&self); + let queries = Queries::new(self); let ret = f(&queries); // NOTE: intentionally does not compute the global context if it hasn't been built yet, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -715,6 +715,7 @@ tracked!(chalk, true); tracked!(codegen_backend, Some("abc".to_string())); tracked!(crate_attr, vec!["abc".to_string()]); + tracked!(debug_info_for_profiling, true); tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); tracked!(dual_proc_macros, true); @@ -743,6 +744,7 @@ tracked!(no_profiler_runtime, true); tracked!(osx_rpath_install_name, true); tracked!(panic_abort_tests, true); + tracked!(panic_in_drop, PanicStrategy::Abort); tracked!(partially_uninit_const_threshold, Some(123)); tracked!(plt, Some(true)); tracked!(polonius, true); @@ -751,8 +753,10 @@ tracked!(profile, true); tracked!(profile_emit, Some(PathBuf::from("abc"))); tracked!(profiler_runtime, "abc".to_string()); + tracked!(profile_sample_use, Some(PathBuf::from("abc"))); tracked!(relax_elf_relocations, Some(true)); tracked!(relro_level, Some(RelroLevel::Full)); + tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc"))); tracked!(report_delayed_bugs, true); tracked!(sanitizer, SanitizerSet::ADDRESS); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_interface/src/util.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_interface/src/util.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,6 +10,7 @@ use rustc_metadata::dynamic_lib::DynamicLibrary; #[cfg(parallel_compiler)] use rustc_middle::ty::tls; +use rustc_parse::validate_attr; #[cfg(parallel_compiler)] use rustc_query_impl::QueryCtxt; use rustc_resolve::{self, Resolver}; @@ -115,24 +116,11 @@ /// for `'static` bounds. #[cfg(not(parallel_compiler))] pub fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { - struct Ptr(*mut ()); - unsafe impl Send for Ptr {} - unsafe impl Sync for Ptr {} - - let mut f = Some(f); - let run = Ptr(&mut f as *mut _ as *mut ()); - let mut result = None; - let result_ptr = Ptr(&mut result as *mut _ as *mut ()); - - let thread = cfg.spawn(move || { - let run = unsafe { (*(run.0 as *mut Option)).take().unwrap() }; - let result = unsafe { &mut *(result_ptr.0 as *mut Option) }; - *result = Some(run()); - }); - - match thread.unwrap().join() { - Ok(()) => result.unwrap(), - Err(p) => panic::resume_unwind(p), + // SAFETY: join() is called immediately, so any closure captures are still + // alive. + match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { + Ok(v) => v, + Err(e) => panic::resume_unwind(e), } } @@ -414,7 +402,7 @@ .iter() .chain(sysroot_candidates.iter()) .map(|sysroot| { - filesearch::make_target_lib_path(&sysroot, &target).with_file_name("codegen-backends") + filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends") }) .find(|f| { info!("codegen backend candidate: {}", f.display()); @@ -488,7 +476,7 @@ } pub(crate) fn check_attr_crate_type( - _sess: &Session, + sess: &Session, attrs: &[ast::Attribute], lint_buffer: &mut LintBuffer, ) { @@ -528,6 +516,19 @@ ); } } + } else { + // This is here mainly to check for using a macro, such as + // #![crate_type = foo!()]. That is not supported since the + // crate type needs to be known very early in compilation long + // before expansion. Otherwise, validation would normally be + // caught in AstValidator (via `check_builtin_attribute`), but + // by the time that runs the macro is expanded, and it doesn't + // give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + a, + sym::crate_type, + ); } } } @@ -618,7 +619,7 @@ .opts .crate_name .clone() - .or_else(|| rustc_attr::find_crate_name(&sess, attrs).map(|n| n.to_string())) + .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string())) .unwrap_or_else(|| input.filestem().to_owned()); OutputFilenames::new( diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lexer/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_lexer/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lexer/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lexer/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ name = "rustc_lexer" version = "0.1.0" license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" repository = "https://github.com/rust-lang/rust/" description = """ diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lexer/src/unescape.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lexer/src/unescape.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lexer/src/unescape.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lexer/src/unescape.rs 2021-11-29 19:27:11.000000000 +0000 @@ -68,11 +68,10 @@ impl EscapeError { /// Returns true for actual errors, as opposed to warnings. pub fn is_fatal(&self) -> bool { - match self { - EscapeError::UnskippedWhitespaceWarning => false, - EscapeError::MultipleSkippedLinesWarning => false, - _ => true, - } + !matches!( + self, + EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning + ) } } @@ -330,7 +329,7 @@ callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning)); } let tail = &tail[first_non_space..]; - if let Some(c) = tail.chars().nth(0) { + if let Some(c) = tail.chars().next() { // For error reporting, we would like the span to contain the character that was not // skipped. The +1 is necessary to account for the leading \ that started the escape. let end = start + first_non_space + c.len_utf8() + 1; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_lint" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] if_chain = "1.0" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/array_into_iter.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/array_into_iter.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/array_into_iter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/array_into_iter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ /// /// ### Example /// - /// ```rust + /// ```rust,edition2018 /// # #![allow(unused)] /// [1, 2, 3].into_iter().for_each(|n| { *n; }); /// ``` @@ -124,7 +124,7 @@ let mut diag = lint.build(&format!( "this method call resolves to `<&{} as IntoIterator>::into_iter` \ (due to backwards compatibility), \ - but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.", + but will resolve to <{} as IntoIterator>::into_iter in Rust 2021", target, target, )); diag.span_suggestion( diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/builtin.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/builtin.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/builtin.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/builtin.rs 2021-11-29 19:27:11.000000000 +0000 @@ -41,16 +41,17 @@ use rustc_hir::{HirId, Node}; use rustc_index::vec::Idx; use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::ty::layout::{LayoutError, LayoutOf}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, Subst}; use rustc_middle::ty::Instance; -use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, MultiSpan, Span}; -use rustc_target::abi::{LayoutOf, VariantIdx}; +use rustc_target::abi::VariantIdx; use rustc_trait_selection::traits::misc::can_type_implement_copy; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -583,8 +584,14 @@ self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) { - self.check_missing_docs_attrs(cx, CRATE_DEF_ID, krate.module().inner, "the", "crate"); + fn check_crate(&mut self, cx: &LateContext<'_>) { + self.check_missing_docs_attrs( + cx, + CRATE_DEF_ID, + cx.tcx.def_span(CRATE_DEF_ID), + "the", + "crate", + ); } fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { @@ -805,7 +812,7 @@ _ => return, } - let debug = match cx.tcx.get_diagnostic_item(sym::debug_trait) { + let debug = match cx.tcx.get_diagnostic_item(sym::Debug) { Some(debug) => debug, None => return, }; @@ -911,7 +918,7 @@ lint.build( "anonymous parameters are deprecated and will be \ - removed in the next edition.", + removed in the next edition", ) .span_suggestion( arg.pat.span, @@ -1622,9 +1629,9 @@ let predicates = cx.tcx.predicates_of(item.def_id); for &(predicate, span) in predicates.predicates { let predicate_kind_name = match predicate.kind().skip_binder() { - Trait(..) => "Trait", + Trait(..) => "trait", TypeOutlives(..) | - RegionOutlives(..) => "Lifetime", + RegionOutlives(..) => "lifetime", // Ignore projections, as they can only be global // if the trait bound is global @@ -1685,7 +1692,7 @@ /// /// ### Example /// - /// ```rust + /// ```rust,edition2018 /// let x = 123; /// match x { /// 0...100 => {} @@ -2471,14 +2478,11 @@ // Find calls to `mem::{uninitialized,zeroed}` methods. if let hir::ExprKind::Path(ref qpath) = path_expr.kind { let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; - - if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) { - return Some(InitKind::Zeroed); - } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) { - return Some(InitKind::Uninit); - } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) && is_zero(&args[0]) - { - return Some(InitKind::Zeroed); + match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::mem_zeroed) => return Some(InitKind::Zeroed), + Some(sym::mem_uninitialized) => return Some(InitKind::Uninit), + Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed), + _ => {} } } } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind { @@ -2490,11 +2494,10 @@ if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind { if let hir::ExprKind::Path(ref qpath) = path_expr.kind { let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; - - if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) { - return Some(InitKind::Zeroed); - } else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) { - return Some(InitKind::Uninit); + match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed), + Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit), + _ => {} } } } @@ -3084,8 +3087,10 @@ rustc_hir::ExprKind::Call(ref path, _) => { if let rustc_hir::ExprKind::Path(ref qpath) = path.kind { if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() { - return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id) - || cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id); + return matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_null | sym::ptr_null_mut) + ); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/context.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/context.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/context.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/context.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,6 +16,7 @@ use self::TargetLint::*; +use crate::hidden_unicode_codepoints::UNICODE_TEXT_FLOW_CHARS; use crate::levels::{is_known_lint_tool, LintLevelsBuilder}; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_ast as ast; @@ -31,17 +32,16 @@ use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability; -use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; use rustc_serialize::json::Json; use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; -use rustc_session::SessionLintStore; use rustc_span::lev_distance::find_best_match_for_name; -use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; -use rustc_target::abi::{self, LayoutOf}; +use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP}; +use rustc_target::abi; use tracing::debug; use std::cell::Cell; @@ -75,20 +75,6 @@ lint_groups: FxHashMap<&'static str, LintGroup>, } -impl SessionLintStore for LintStore { - fn name_to_lint(&self, lint_name: &str) -> LintId { - let lints = self - .find_lints(lint_name) - .unwrap_or_else(|_| panic!("Failed to find lint with name `{}`", lint_name)); - - if let &[lint] = lints.as_slice() { - return lint; - } else { - panic!("Found mutliple lints with name `{}`: {:?}", lint_name, lints); - } - } -} - /// The target of the `by_name` map, which accounts for renaming/deprecation. #[derive(Debug)] enum TargetLint { @@ -612,6 +598,42 @@ // Now, set up surrounding context. let sess = self.sess(); match diagnostic { + BuiltinLintDiagnostics::UnicodeTextFlow(span, content) => { + let spans: Vec<_> = content + .char_indices() + .filter_map(|(i, c)| { + UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| { + let lo = span.lo() + BytePos(2 + i as u32); + (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) + }) + }) + .collect(); + let (an, s) = match spans.len() { + 1 => ("an ", ""), + _ => ("", "s"), + }; + db.span_label(span, &format!( + "this comment contains {}invisible unicode text flow control codepoint{}", + an, + s, + )); + for (c, span) in &spans { + db.span_label(*span, format!("{:?}", c)); + } + db.note( + "these kind of unicode codepoints change the way text flows on \ + applications that support them, but can cause confusion because they \ + change the order of characters on the screen", + ); + if !spans.is_empty() { + db.multipart_suggestion_with_style( + "if their presence wasn't intentional, you can remove them", + spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(), + Applicability::MachineApplicable, + SuggestionStyle::HideCodeAlways, + ); + } + }, BuiltinLintDiagnostics::Normal => (), BuiltinLintDiagnostics::BareTraitObject(span, is_global) => { let (sugg, app) = match sess.source_map().span_to_snippet(span) { @@ -805,6 +827,7 @@ sess: &'a Session, lint_store: &'a LintStore, krate: &'a ast::Crate, + crate_attrs: &'a [ast::Attribute], buffered: LintBuffer, warn_about_weird_lints: bool, ) -> EarlyContext<'a> { @@ -812,7 +835,7 @@ sess, krate, lint_store, - builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, &krate.attrs), + builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs), buffered, } } @@ -1080,12 +1103,12 @@ } } -impl<'tcx> LayoutOf<'tcx> for LateContext<'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = Result, LayoutError<'tcx>>; +impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> { + type LayoutOfResult = Result, LayoutError<'tcx>>; - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)) + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> { + err } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/early.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/early.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/early.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/early.rs 2021-11-29 19:27:11.000000000 +0000 @@ -329,12 +329,20 @@ sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], pass: T, buffered: LintBuffer, warn_about_weird_lints: bool, ) -> LintBuffer { let mut cx = EarlyContextAndPass { - context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints), + context: EarlyContext::new( + sess, + lint_store, + krate, + crate_attrs, + buffered, + warn_about_weird_lints, + ), pass, }; @@ -355,6 +363,7 @@ sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], pre_expansion: bool, lint_buffer: Option, builtin_lints: T, @@ -365,14 +374,22 @@ let mut buffered = lint_buffer.unwrap_or_default(); if !sess.opts.debugging_opts.no_interleave_lints { - buffered = - early_lint_crate(sess, lint_store, krate, builtin_lints, buffered, pre_expansion); + buffered = early_lint_crate( + sess, + lint_store, + krate, + crate_attrs, + builtin_lints, + buffered, + pre_expansion, + ); if !passes.is_empty() { buffered = early_lint_crate( sess, lint_store, krate, + crate_attrs, EarlyLintPassObjects { lints: &mut passes[..] }, buffered, false, @@ -386,6 +403,7 @@ sess, lint_store, krate, + crate_attrs, EarlyLintPassObjects { lints: slice::from_mut(pass) }, buffered, pre_expansion && i == 0, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,106 @@ +use crate::{context::LintContext, LateContext, LateLintPass}; +use rustc_hir as hir; +use rustc_middle::ty::{fold::TypeFoldable, Ty}; +use rustc_span::{symbol::sym, Span}; + +declare_lint! { + /// The `enum_intrinsics_non_enums` lint detects calls to + /// intrinsic functions that require an enum ([`core::mem::discriminant`], + /// [`core::mem::variant_count`]), but are called with a non-enum type. + /// + /// [`core::mem::discriminant`]: https://doc.rust-lang.org/core/mem/fn.discriminant.html + /// [`core::mem::variant_count`]: https://doc.rust-lang.org/core/mem/fn.variant_count.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(enum_intrinsics_non_enums)] + /// core::mem::discriminant::(&123); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In order to accept any enum, the `mem::discriminant` and + /// `mem::variant_count` functions are generic over a type `T`. + /// This makes it technically possible for `T` to be a non-enum, + /// in which case the return value is unspecified. + /// + /// This lint prevents such incorrect usage of these functions. + ENUM_INTRINSICS_NON_ENUMS, + Deny, + "detects calls to `core::mem::discriminant` and `core::mem::variant_count` with non-enum types" +} + +declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]); + +/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where +/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is. +fn is_non_enum(t: Ty<'_>) -> bool { + !t.is_enum() && !t.potentially_needs_subst() +} + +fn enforce_mem_discriminant( + cx: &LateContext<'_>, + func_expr: &hir::Expr<'_>, + expr_span: Span, + args_span: Span, +) { + let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0); + if is_non_enum(ty_param) { + cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| { + builder + .build( + "the return value of `mem::discriminant` is \ + unspecified when called with a non-enum type", + ) + .span_note( + args_span, + &format!( + "the argument to `discriminant` should be a \ + reference to an enum, but it was passed \ + a reference to a `{}`, which is not an enum.", + ty_param, + ), + ) + .emit(); + }); + } +} + +fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) { + let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0); + if is_non_enum(ty_param) { + cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| { + builder + .build( + "the return value of `mem::variant_count` is \ + unspecified when called with a non-enum type", + ) + .note(&format!( + "the type parameter of `variant_count` should \ + be an enum, but it was instantiated with \ + the type `{}`, which is not an enum.", + ty_param, + )) + .emit(); + }); + } +} + +impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + if let hir::ExprKind::Call(ref func, ref args) = expr.kind { + if let hir::ExprKind::Path(ref qpath) = func.kind { + if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() { + if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) { + enforce_mem_discriminant(cx, func, expr.span, args[0].span); + } else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) { + enforce_mem_variant_count(cx, func, expr.span); + } + } + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/hidden_unicode_codepoints.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/hidden_unicode_codepoints.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/hidden_unicode_codepoints.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/hidden_unicode_codepoints.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,161 @@ +use crate::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_ast as ast; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_span::{BytePos, Span, Symbol}; + +declare_lint! { + /// The `text_direction_codepoint_in_literal` lint detects Unicode codepoints that change the + /// visual representation of text on screen in a way that does not correspond to their on + /// memory representation. + /// + /// ### Explanation + /// + /// The unicode characters `\u{202A}`, `\u{202B}`, `\u{202D}`, `\u{202E}`, `\u{2066}`, + /// `\u{2067}`, `\u{2068}`, `\u{202C}` and `\u{2069}` make the flow of text on screen change + /// its direction on software that supports these codepoints. This makes the text "abc" display + /// as "cba" on screen. By leveraging software that supports these, people can write specially + /// crafted literals that make the surrounding code seem like it's performing one action, when + /// in reality it is performing another. Because of this, we proactively lint against their + /// presence to avoid surprises. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(text_direction_codepoint_in_literal)] + /// fn main() { + /// println!("{:?}", '‮'); + /// } + /// ``` + /// + /// {{produces}} + /// + pub TEXT_DIRECTION_CODEPOINT_IN_LITERAL, + Deny, + "detect special Unicode codepoints that affect the visual representation of text on screen, \ + changing the direction in which text flows", +} + +declare_lint_pass!(HiddenUnicodeCodepoints => [TEXT_DIRECTION_CODEPOINT_IN_LITERAL]); + +crate const UNICODE_TEXT_FLOW_CHARS: &[char] = &[ + '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', + '\u{2069}', +]; + +impl HiddenUnicodeCodepoints { + fn lint_text_direction_codepoint( + &self, + cx: &EarlyContext<'_>, + text: Symbol, + span: Span, + padding: u32, + point_at_inner_spans: bool, + label: &str, + ) { + // Obtain the `Span`s for each of the forbidden chars. + let spans: Vec<_> = text + .as_str() + .char_indices() + .filter_map(|(i, c)| { + UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| { + let lo = span.lo() + BytePos(i as u32 + padding); + (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) + }) + }) + .collect(); + + cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| { + let mut err = lint.build(&format!( + "unicode codepoint changing visible direction of text present in {}", + label + )); + let (an, s) = match spans.len() { + 1 => ("an ", ""), + _ => ("", "s"), + }; + err.span_label( + span, + &format!( + "this {} contains {}invisible unicode text flow control codepoint{}", + label, an, s, + ), + ); + if point_at_inner_spans { + for (c, span) in &spans { + err.span_label(*span, format!("{:?}", c)); + } + } + err.note( + "these kind of unicode codepoints change the way text flows on applications that \ + support them, but can cause confusion because they change the order of \ + characters on the screen", + ); + if point_at_inner_spans && !spans.is_empty() { + err.multipart_suggestion_with_style( + "if their presence wasn't intentional, you can remove them", + spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), + Applicability::MachineApplicable, + SuggestionStyle::HideCodeAlways, + ); + err.multipart_suggestion( + "if you want to keep them but make them visible in your source code, you can \ + escape them", + spans + .into_iter() + .map(|(c, span)| { + let c = format!("{:?}", c); + (span, c[1..c.len() - 1].to_string()) + }) + .collect(), + Applicability::MachineApplicable, + ); + } else { + // FIXME: in other suggestions we've reversed the inner spans of doc comments. We + // should do the same here to provide the same good suggestions as we do for + // literals above. + err.note("if their presence wasn't intentional, you can remove them"); + err.note(&format!( + "if you want to keep them but make them visible in your source code, you can \ + escape them: {}", + spans + .into_iter() + .map(|(c, _)| { format!("{:?}", c) }) + .collect::>() + .join(", "), + )); + } + err.emit(); + }); + } +} +impl EarlyLintPass for HiddenUnicodeCodepoints { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { + if let ast::AttrKind::DocComment(_, comment) = attr.kind { + if comment.as_str().contains(UNICODE_TEXT_FLOW_CHARS) { + self.lint_text_direction_codepoint(cx, comment, attr.span, 0, false, "doc comment"); + } + } + } + + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { + // byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString` + let (text, span, padding) = match &expr.kind { + ast::ExprKind::Lit(ast::Lit { token, kind, span }) => { + let text = token.symbol; + if !text.as_str().contains(UNICODE_TEXT_FLOW_CHARS) { + return; + } + let padding = match kind { + // account for `"` or `'` + ast::LitKind::Str(_, ast::StrStyle::Cooked) | ast::LitKind::Char(_) => 1, + // account for `r###"` + ast::LitKind::Str(_, ast::StrStyle::Raw(val)) => *val as u32 + 2, + _ => return, + }; + (text, span, padding) + } + _ => return, + }; + self.lint_text_direction_codepoint(cx, text, *span, padding, true, "literal"); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/internal.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/internal.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/internal.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/internal.rs 2021-11-29 19:27:11.000000000 +0000 @@ -33,12 +33,10 @@ // don't lint imports, only actual usages return; } - let replace = if cx.tcx.is_diagnostic_item(sym::hashmap_type, def_id) { - "FxHashMap" - } else if cx.tcx.is_diagnostic_item(sym::hashset_type, def_id) { - "FxHashSet" - } else { - return; + let replace = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::HashMap) => "FxHashMap", + Some(sym::HashSet) => "FxHashSet", + _ => return, }; cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| { let msg = format!( @@ -174,26 +172,29 @@ if let TyKind::Path(qpath) = &ty.kind { if let QPath::Resolved(_, path) = qpath { match path.res { - Res::Def(_, did) => { - if cx.tcx.is_diagnostic_item(sym::Ty, did) { - return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { - return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + Res::Def(_, def_id) => { + if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) + { + return Some(format!( + "{}{}", + name, + gen_args(path.segments.last().unwrap()) + )); } } // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. Res::SelfTy(None, Some((did, _))) => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { - if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + if let Some(name @ (sym::Ty | sym::TyCtxt)) = + cx.tcx.get_diagnostic_name(adt.did) + { // NOTE: This path is currently unreachable as `Ty<'tcx>` is // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` // is not actually allowed. // // I(@lcnr) still kept this branch in so we don't miss this // if we ever change it in the future. - return Some(format!("Ty<{}>", substs[0])); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { - return Some(format!("TyCtxt<{}>", substs[0])); + return Some(format!("{}<{}>", name, substs[0])); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/late.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/late.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/late.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/late.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,7 @@ use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; use rustc_ast as ast; -use rustc_data_structures::sync::{join, par_iter, ParallelIterator}; +use rustc_data_structures::sync::join; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit as hir_visit; @@ -430,8 +430,6 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) { let access_levels = &tcx.privacy_access_levels(()); - let krate = tcx.hir().krate(); - let context = LateContext { tcx, enclosing_body: None, @@ -450,11 +448,10 @@ cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| { // since the root module isn't visited as an item (because it isn't an // item), warn for it here. - lint_callback!(cx, check_crate, krate); - - hir_visit::walk_crate(cx, krate); - - lint_callback!(cx, check_crate_post, krate); + lint_callback!(cx, check_crate,); + tcx.hir().walk_toplevel_module(cx); + tcx.hir().walk_attributes(cx); + lint_callback!(cx, check_crate_post,); }) } @@ -502,9 +499,7 @@ || { tcx.sess.time("module_lints", || { // Run per-module lints - par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { - tcx.ensure().lint_mod(module); - }); + tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module)); }); }, ); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/levels.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/levels.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/levels.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/levels.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ use crate::context::{CheckLintNameResult, LintStore}; use crate::late::unerased_lint_store; use rustc_ast as ast; -use rustc_ast::unwrap_or; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; @@ -37,7 +36,7 @@ let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true); builder.levels.register_id(hir::CRATE_HIR_ID); - intravisit::walk_crate(&mut builder, krate); + tcx.hir().walk_toplevel_module(&mut builder); builder.levels.pop(push); builder.levels.build_map() @@ -233,7 +232,10 @@ Some(lvl) => lvl, }; - let mut metas = unwrap_or!(attr.meta_item_list(), continue); + let mut metas = match attr.meta_item_list() { + Some(x) => x, + None => continue, + }; if metas.is_empty() { // FIXME (#55112): issue unused-attributes lint for `#[level()]` diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -26,7 +26,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![cfg_attr(test, feature(test))] #![feature(array_windows)] #![feature(bool_to_option)] #![feature(box_patterns)] @@ -48,6 +47,8 @@ pub mod builtin; mod context; mod early; +mod enum_intrinsics_non_enums; +pub mod hidden_unicode_codepoints; mod internal; mod late; mod levels; @@ -77,6 +78,8 @@ use array_into_iter::ArrayIntoIter; use builtin::*; +use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; +use hidden_unicode_codepoints::*; use internal::*; use methods::*; use non_ascii_idents::*; @@ -128,6 +131,7 @@ DeprecatedAttr: DeprecatedAttr::new(), WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, + HiddenUnicodeCodepoints: HiddenUnicodeCodepoints, IncompleteFeatures: IncompleteFeatures, RedundantSemicolons: RedundantSemicolons, UnusedDocComment: UnusedDocComment, @@ -169,6 +173,7 @@ TemporaryCStringAsPtr: TemporaryCStringAsPtr, NonPanicFmt: NonPanicFmt, NoopMethodCall: NoopMethodCall, + EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums, InvalidAtomicOrdering: InvalidAtomicOrdering, NamedAsmLabels: NamedAsmLabels, ] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/methods.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/methods.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/methods.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/methods.rs 2021-11-29 19:27:11.000000000 +0000 @@ -84,7 +84,7 @@ ) { let source_type = cx.typeck_results().expr_ty(source); if let ty::Adt(def, substs) = source_type.kind() { - if cx.tcx.is_diagnostic_item(sym::result_type, def.did) { + if cx.tcx.is_diagnostic_item(sym::Result, def.did) { if let ty::Adt(adt, _) = substs.type_at(0).kind() { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did) { cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/non_ascii_idents.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/non_ascii_idents.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/non_ascii_idents.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/non_ascii_idents.rs 2021-11-29 19:27:11.000000000 +0000 @@ -331,9 +331,9 @@ for ((sp, ch_list), script_set) in lint_reports { cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| { let message = format!( - "The usage of Script Group `{}` in this crate consists solely of mixed script confusables", + "the usage of Script Group `{}` in this crate consists solely of mixed script confusables", script_set); - let mut note = "The usage includes ".to_string(); + let mut note = "the usage includes ".to_string(); for (idx, ch) in ch_list.into_iter().enumerate() { if idx != 0 { note += ", "; @@ -341,8 +341,7 @@ let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); note += &char_info; } - note += "."; - lint.build(&message).note(¬e).note("Please recheck to make sure their usages are indeed what you want.").emit() + lint.build(&message).note(¬e).note("please recheck to make sure their usages are indeed what you want").emit() }); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/non_fmt_panic.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/non_fmt_panic.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/non_fmt_panic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/non_fmt_panic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ /// /// ### Example /// - /// ```rust,no_run + /// ```rust,no_run,edition2018 /// panic!("{}"); /// panic!(123); /// ``` @@ -54,9 +54,10 @@ || Some(def_id) == cx.tcx.lang_items().panic_str() { if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id { - if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id) - || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id) - { + if matches!( + cx.tcx.get_diagnostic_name(id), + Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro) + ) { check_panic(cx, f, arg); } } @@ -130,14 +131,14 @@ ty::Ref(_, r, _) if *r.kind() == ty::Str, ) || matches!( ty.ty_adt_def(), - Some(ty_def) if cx.tcx.is_diagnostic_item(sym::string_type, ty_def.did), + Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did), ); let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| { - let display = is_str || cx.tcx.get_diagnostic_item(sym::display_trait).map(|t| { + let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() }) == Some(true); - let debug = !display && cx.tcx.get_diagnostic_item(sym::debug_trait).map(|t| { + let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() }) == Some(true); (display, debug) @@ -229,8 +230,7 @@ Err(_) => (None, None), }; - let mut fmt_parser = - Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format); + let mut fmt_parser = Parser::new(fmt, style, snippet.clone(), false, ParseMode::Format); let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count(); if n_arguments > 0 && fmt_parser.errors.is_empty() { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/nonstandard_style.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/nonstandard_style.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/nonstandard_style.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/nonstandard_style.rs 2021-11-29 19:27:11.000000000 +0000 @@ -437,12 +437,13 @@ if let hir::Node::Pat(parent_pat) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid)) { if let PatKind::Struct(_, field_pats, _) = &parent_pat.kind { - for field in field_pats.iter() { - if field.ident != ident { - // Only check if a new name has been introduced, to avoid warning - // on both the struct definition and this pattern. - self.check_snake_case(cx, "variable", &ident); - } + if field_pats + .iter() + .any(|field| !field.is_shorthand && field.pat.hir_id == p.hir_id) + { + // Only check if a new name has been introduced, to avoid warning + // on both the struct definition and this pattern. + self.check_snake_case(cx, "variable", &ident); } return; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/noop_method_call.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/noop_method_call.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/noop_method_call.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/noop_method_call.rs 2021-11-29 19:27:11.000000000 +0000 @@ -51,9 +51,10 @@ Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) { // Check that we're dealing with a trait method for one of the traits we care about. Some(trait_id) - if [sym::Clone, sym::Deref, sym::Borrow] - .iter() - .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => + if matches!( + cx.tcx.get_diagnostic_name(trait_id), + Some(sym::Borrow | sym::Clone | sym::Deref) + ) => { (trait_id, did) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/passes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/passes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/passes.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/passes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,8 +16,8 @@ fn check_body(a: &$hir hir::Body<$hir>); fn check_body_post(a: &$hir hir::Body<$hir>); fn check_name(a: Span, b: Symbol); - fn check_crate(a: &$hir hir::Crate<$hir>); - fn check_crate_post(a: &$hir hir::Crate<$hir>); + fn check_crate(); + fn check_crate_post(); fn check_mod(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId); fn check_mod_post(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId); fn check_foreign_item(a: &$hir hir::ForeignItem<$hir>); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/traits.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/traits.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/traits.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/traits.rs 2021-11-29 19:27:11.000000000 +0000 @@ -86,6 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + use rustc_middle::ty; use rustc_middle::ty::PredicateKind::*; let predicates = cx.tcx.explicit_predicates_of(item.def_id); @@ -94,6 +95,10 @@ Trait(trait_predicate) => trait_predicate, _ => continue, }; + if trait_predicate.constness == ty::BoundConstness::ConstIfConst { + // `~const Drop` definitely have meanings so avoid linting here. + continue; + } let def_id = trait_predicate.trait_ref.def_id; if cx.tcx.lang_items().drop_trait() == Some(def_id) { // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/types.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/types.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/types.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/types.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,14 +6,14 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; -use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton}; +use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_target::abi::Abi; -use rustc_target::abi::{Integer, LayoutOf, TagEncoding, Variants}; +use rustc_target::abi::{Integer, TagEncoding, Variants}; use rustc_target::spec::abi::Abi as SpecAbi; use if_chain::if_chain; @@ -851,12 +851,18 @@ use FfiResult::*; if def.repr.transparent() { - // Can assume that only one field is not a ZST, so only check + // Can assume that at most one field is not a ZST, so only check // that field's type for FFI-safety. if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) { self.check_field_type_for_ffi(cache, field, substs) } else { - bug!("malformed transparent type"); + // All fields are ZSTs; this means that the type should behave + // like (), which is FFI-unsafe + FfiUnsafe { + ty, + reason: "this struct contains only zero-sized fields".into(), + help: None, + } } } else { // We can't completely trust repr(C) markings; make sure the fields are @@ -1050,6 +1056,15 @@ FfiSafe } + ty::RawPtr(ty::TypeAndMut { ty, .. }) + if match ty.kind() { + ty::Tuple(tuple) => tuple.is_empty(), + _ => false, + } => + { + FfiSafe + } + ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { self.check_type_for_ffi(cache, ty) } @@ -1327,10 +1342,7 @@ }; let (variants, tag) = match layout.variants { Variants::Multiple { - tag_encoding: TagEncoding::Direct, - ref tag, - ref variants, - .. + tag_encoding: TagEncoding::Direct, tag, ref variants, .. } => (variants, tag), _ => return, }; @@ -1529,8 +1541,7 @@ if let ExprKind::Call(ref func, ref args) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::fence, def_id) || - cx.tcx.is_diagnostic_item(sym::compiler_fence, def_id); + if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence)); if let ExprKind::Path(ref ordering_qpath) = &args[0].kind; if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id(); if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/unused.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/unused.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint/src/unused.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint/src/unused.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,6 @@ use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; -use rustc_ast_pretty::pprust; use rustc_errors::{pluralize, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -12,7 +11,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, sym}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; declare_lint! { /// The `unused_must_use` lint detects unused result of a type flagged as @@ -461,13 +460,16 @@ let lhs_needs_parens = { let mut innermost = inner; loop { - if let ExprKind::Binary(_, lhs, _rhs) = &innermost.kind { - innermost = lhs; - if !classify::expr_requires_semi_to_be_stmt(innermost) { - break true; - } - } else { - break false; + innermost = match &innermost.kind { + ExprKind::Binary(_, lhs, _rhs) => lhs, + ExprKind::Call(fn_, _params) => fn_, + ExprKind::Cast(expr, _ty) => expr, + ExprKind::Type(expr, _ty) => expr, + ExprKind::Index(base, _subscript) => base, + _ => break false, + }; + if !classify::expr_requires_semi_to_be_stmt(innermost) { + break true; } } }; @@ -488,77 +490,60 @@ left_pos: Option, right_pos: Option, ) { - let expr_text = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(value.span) { - snippet - } else { - pprust::expr_to_string(value) + let spans = match value.kind { + ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => { + let start = block.stmts[0].span; + let end = block.stmts[block.stmts.len() - 1].span; + if value.span.from_expansion() || start.from_expansion() || end.from_expansion() { + ( + value.span.with_hi(value.span.lo() + BytePos(1)), + value.span.with_lo(value.span.hi() - BytePos(1)), + ) + } else { + (value.span.with_hi(start.lo()), value.span.with_lo(end.hi())) + } + } + ast::ExprKind::Paren(ref expr) => { + if value.span.from_expansion() || expr.span.from_expansion() { + ( + value.span.with_hi(value.span.lo() + BytePos(1)), + value.span.with_lo(value.span.hi() - BytePos(1)), + ) + } else { + (value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi())) + } + } + _ => return, }; let keep_space = ( left_pos.map_or(false, |s| s >= value.span.lo()), right_pos.map_or(false, |s| s <= value.span.hi()), ); - self.emit_unused_delims(cx, value.span, &expr_text, ctx.into(), keep_space); + self.emit_unused_delims(cx, spans, ctx.into(), keep_space); } fn emit_unused_delims( &self, cx: &EarlyContext<'_>, - span: Span, - pattern: &str, + spans: (Span, Span), msg: &str, keep_space: (bool, bool), ) { // FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc // properly. - if span == DUMMY_SP { + if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP { return; } - cx.struct_span_lint(self.lint(), span, |lint| { + cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| { let span_msg = format!("unnecessary {} around {}", Self::DELIM_STR, msg); let mut err = lint.build(&span_msg); - let mut ate_left_paren = false; - let mut ate_right_paren = false; - let parens_removed = pattern - .trim_matches(|c| match c { - '(' | '{' => { - if ate_left_paren { - false - } else { - ate_left_paren = true; - true - } - } - ')' | '}' => { - if ate_right_paren { - false - } else { - ate_right_paren = true; - true - } - } - _ => false, - }) - .trim(); - - let replace = { - let mut replace = if keep_space.0 { - let mut s = String::from(" "); - s.push_str(parens_removed); - s - } else { - String::from(parens_removed) - }; - - if keep_space.1 { - replace.push(' '); - } - replace - }; - + let replacement = vec![ + (spans.0, if keep_space.0 { " ".into() } else { "".into() }), + (spans.1, if keep_space.1 { " ".into() } else { "".into() }), + ]; let suggestion = format!("remove these {}", Self::DELIM_STR); - - err.span_suggestion_short(span, &suggestion, replace, Applicability::MachineApplicable); + err.multipart_suggestion(&suggestion, replacement, Applicability::MachineApplicable); err.emit(); }); } @@ -767,14 +752,15 @@ // Otherwise proceed with linting. _ => {} } - - let pattern_text = - if let Ok(snippet) = cx.sess().source_map().span_to_snippet(value.span) { - snippet - } else { - pprust::pat_to_string(value) - }; - self.emit_unused_delims(cx, value.span, &pattern_text, "pattern", (false, false)); + let spans = if value.span.from_expansion() || inner.span.from_expansion() { + ( + value.span.with_hi(value.span.lo() + BytePos(1)), + value.span.with_lo(value.span.hi() - BytePos(1)), + ) + } else { + (value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi())) + }; + self.emit_unused_delims(cx, spans, "pattern", (false, false)); } } } @@ -867,14 +853,15 @@ ); } _ => { - let pattern_text = - if let Ok(snippet) = cx.sess().source_map().span_to_snippet(ty.span) { - snippet - } else { - pprust::ty_to_string(ty) - }; - - self.emit_unused_delims(cx, ty.span, &pattern_text, "type", (false, false)); + let spans = if ty.span.from_expansion() || r.span.from_expansion() { + ( + ty.span.with_hi(ty.span.lo() + BytePos(1)), + ty.span.with_lo(ty.span.hi() - BytePos(1)), + ) + } else { + (ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi())) + }; + self.emit_unused_delims(cx, spans, "type", (false, false)); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint_defs/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint_defs/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint_defs/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint_defs/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_lint_defs" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustc_ast = { path = "../rustc_ast" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint_defs/src/builtin.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint_defs/src/builtin.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint_defs/src/builtin.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint_defs/src/builtin.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,6 +6,7 @@ use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason}; use rustc_span::edition::Edition; +use rustc_span::symbol::sym; declare_lint! { /// The `forbidden_lint_groups` lint detects violations of @@ -315,6 +316,46 @@ } declare_lint! { + /// The `must_not_suspend` lint guards against values that shouldn't be held across suspend points + /// (`.await`) + /// + /// ### Example + /// + /// ```rust + /// #![feature(must_not_suspend)] + /// #![warn(must_not_suspend)] + /// + /// #[must_not_suspend] + /// struct SyncThing {} + /// + /// async fn yield_now() {} + /// + /// pub async fn uhoh() { + /// let guard = SyncThing {}; + /// yield_now().await; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `must_not_suspend` lint detects values that are marked with the `#[must_not_suspend]` + /// attribute being held across suspend points. A "suspend" point is usually a `.await` in an async + /// function. + /// + /// This attribute can be used to mark values that are semantically incorrect across suspends + /// (like certain types of timers), values that have async alternatives, and values that + /// regularly cause problems with the `Send`-ness of async fn's returned futures (like + /// `MutexGuard`'s) + /// + pub MUST_NOT_SUSPEND, + Allow, + "use of a `#[must_not_suspend]` value across a yield point", + @feature_gate = rustc_span::symbol::sym::must_not_suspend; +} + +declare_lint! { /// The `unused_extern_crates` lint guards against `extern crate` items /// that are never used. /// @@ -1584,7 +1625,7 @@ /// /// ### Example /// - /// ```rust + /// ```rust,edition2018 /// trait Trait { } /// /// fn takes_trait_object(_: Box) { @@ -1922,6 +1963,7 @@ "detects proc macro derives using inaccessible names from parent modules", @future_incompatible = FutureIncompatibleInfo { reference: "issue #83583 ", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -2993,6 +3035,7 @@ CENUM_IMPL_DROP_CAST, CONST_EVALUATABLE_UNCHECKED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + MUST_NOT_SUSPEND, UNINHABITED_STATIC, FUNCTION_ITEM_REFERENCES, USELESS_DEPRECATED, @@ -3010,6 +3053,9 @@ UNSUPPORTED_CALLING_CONVENTIONS, BREAK_WITH_LABEL_AND_LOOP, UNUSED_ATTRIBUTES, + NON_EXHAUSTIVE_OMITTED_PATTERNS, + TEXT_DIRECTION_CODEPOINT_IN_COMMENT, + DEREF_INTO_DYN_SUPERTRAIT, ] } @@ -3312,7 +3358,7 @@ /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,edition2018,compile_fail /// #![deny(rust_2021_prefixes_incompatible_syntax)] /// /// macro_rules! m { @@ -3332,6 +3378,8 @@ /// /// This lint suggests to add whitespace between the `z` and `"hey"` tokens /// to keep them separated in Rust 2021. + // Allow this lint -- rustdoc doesn't yet support threading edition into this lint's parser. + #[allow(rustdoc::invalid_rust_codeblocks)] pub RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, Allow, "identifiers that will be parsed as a prefix in Rust 2021", @@ -3416,3 +3464,132 @@ Warn, "`break` expression with label and unlabeled loop as value expression" } + +declare_lint! { + /// The `non_exhaustive_omitted_patterns` lint detects when a wildcard (`_` or `..`) in a + /// pattern for a `#[non_exhaustive]` struct or enum is reachable. + /// + /// ### Example + /// + /// ```rust,ignore (needs separate crate) + /// // crate A + /// #[non_exhaustive] + /// pub enum Bar { + /// A, + /// B, // added variant in non breaking change + /// } + /// + /// // in crate B + /// #![feature(non_exhaustive_omitted_patterns_lint)] + /// + /// match Bar::A { + /// Bar::A => {}, + /// #[warn(non_exhaustive_omitted_patterns)] + /// _ => {}, + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: reachable patterns not covered of non exhaustive enum + /// --> $DIR/reachable-patterns.rs:70:9 + /// | + /// LL | _ => {} + /// | ^ pattern `B` not covered + /// | + /// note: the lint level is defined here + /// --> $DIR/reachable-patterns.rs:69:16 + /// | + /// LL | #[warn(non_exhaustive_omitted_patterns)] + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// = help: ensure that all possible cases are being handled by adding the suggested match arms + /// = note: the matched value is of type `Bar` and the `non_exhaustive_omitted_patterns` attribute was found + /// ``` + /// + /// ### Explanation + /// + /// Structs and enums tagged with `#[non_exhaustive]` force the user to add a + /// (potentially redundant) wildcard when pattern-matching, to allow for future + /// addition of fields or variants. The `non_exhaustive_omitted_patterns` lint + /// detects when such a wildcard happens to actually catch some fields/variants. + /// In other words, when the match without the wildcard would not be exhaustive. + /// This lets the user be informed if new fields/variants were added. + pub NON_EXHAUSTIVE_OMITTED_PATTERNS, + Allow, + "detect when patterns of types marked `non_exhaustive` are missed", + @feature_gate = sym::non_exhaustive_omitted_patterns_lint; +} + +declare_lint! { + /// The `text_direction_codepoint_in_comment` lint detects Unicode codepoints in comments that + /// change the visual representation of text on screen in a way that does not correspond to + /// their on memory representation. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(text_direction_codepoint_in_comment)] + /// fn main() { + /// println!("{:?}"); // '‮'); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unicode allows changing the visual flow of text on screen in order to support scripts that + /// are written right-to-left, but a specially crafted comment can make code that will be + /// compiled appear to be part of a comment, depending on the software used to read the code. + /// To avoid potential problems or confusion, such as in CVE-2021-42574, by default we deny + /// their use. + pub TEXT_DIRECTION_CODEPOINT_IN_COMMENT, + Deny, + "invisible directionality-changing codepoints in comment" +} + +declare_lint! { + /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the + /// `Deref` implementation with a `dyn SuperTrait` type as `Output`. + /// + /// These implementations will become shadowed when the `trait_upcasting` feature is stablized. + /// The `deref` functions will no longer be called implicitly, so there might be behavior change. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(deref_into_dyn_supertrait)] + /// #![allow(dead_code)] + /// + /// use core::ops::Deref; + /// + /// trait A {} + /// trait B: A {} + /// impl<'a> Deref for dyn 'a + B { + /// type Target = dyn A; + /// fn deref(&self) -> &Self::Target { + /// todo!() + /// } + /// } + /// + /// fn take_a(_: &dyn A) { } + /// + /// fn take_b(b: &dyn B) { + /// take_a(b); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The dyn upcasting coercion feature adds new coercion rules, taking priority + /// over certain other coercion rules, which will cause some behavior change. + pub DEREF_INTO_DYN_SUPERTRAIT, + Warn, + "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #89460 ", + }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint_defs/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint_defs/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_lint_defs/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_lint_defs/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -306,6 +306,7 @@ TrailingMacro(bool, Ident), BreakWithLabelAndLoop(Span), NamedAsmLabel(String), + UnicodeTextFlow(Span, String), } /// Lints that are buffered up early on in the `Session` before the diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/build.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/build.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/build.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/build.rs 2021-11-29 19:27:11.000000000 +0000 @@ -76,6 +76,7 @@ "aarch64", "amdgpu", "avr", + "m68k", "mips", "powerpc", "systemz", diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_llvm" version = "0.0.0" -edition = "2018" +edition = "2021" [features] static-libstdcpp = [] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp 2021-11-29 19:27:11.000000000 +0000 @@ -25,6 +25,7 @@ #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/IPO/FunctionImport.h" +#include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/LTO/LTO.h" #include "llvm-c/Transforms/PassManagerBuilder.h" @@ -39,6 +40,7 @@ #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/NameAnonGlobals.h" +#include "llvm/Transforms/Utils.h" using namespace llvm; @@ -201,6 +203,12 @@ #define SUBTARGET_AVR #endif +#ifdef LLVM_COMPONENT_M68k +#define SUBTARGET_M68K SUBTARGET(M68k) +#else +#define SUBTARGET_M68K +#endif + #ifdef LLVM_COMPONENT_MIPS #define SUBTARGET_MIPS SUBTARGET(Mips) #else @@ -248,6 +256,7 @@ SUBTARGET_ARM \ SUBTARGET_AARCH64 \ SUBTARGET_AVR \ + SUBTARGET_M68K \ SUBTARGET_MIPS \ SUBTARGET_PPC \ SUBTARGET_SYSTEMZ \ @@ -516,7 +525,7 @@ extern "C" void LLVMRustConfigurePassManagerBuilder( LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel, bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO, - const char* PGOGenPath, const char* PGOUsePath) { + const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath) { unwrap(PMBR)->MergeFunctions = MergeFunctions; unwrap(PMBR)->SLPVectorize = SLPVectorize; unwrap(PMBR)->OptLevel = fromRust(OptLevel); @@ -524,13 +533,14 @@ unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO; if (PGOGenPath) { - assert(!PGOUsePath); + assert(!PGOUsePath && !PGOSampleUsePath); unwrap(PMBR)->EnablePGOInstrGen = true; unwrap(PMBR)->PGOInstrGen = PGOGenPath; - } - if (PGOUsePath) { - assert(!PGOGenPath); + } else if (PGOUsePath) { + assert(!PGOSampleUsePath); unwrap(PMBR)->PGOInstrUse = PGOUsePath; + } else if (PGOSampleUsePath) { + unwrap(PMBR)->PGOSampleUse = PGOSampleUsePath; } } @@ -752,6 +762,7 @@ LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, const char *PGOUsePath, bool InstrumentCoverage, bool InstrumentGCOV, + const char *PGOSampleUsePath, bool DebugInfoForProfiling, void* LlvmSelfProfiler, LLVMRustSelfProfileBeforePassCallback BeforePassCallback, LLVMRustSelfProfileAfterPassCallback AfterPassCallback, @@ -790,11 +801,19 @@ Optional PGOOpt; if (PGOGenPath) { - assert(!PGOUsePath); - PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr); + assert(!PGOUsePath && !PGOSampleUsePath); + PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr, + PGOOptions::NoCSAction, DebugInfoForProfiling); } else if (PGOUsePath) { - assert(!PGOGenPath); - PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse); + assert(!PGOSampleUsePath); + PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse, + PGOOptions::NoCSAction, DebugInfoForProfiling); + } else if (PGOSampleUsePath) { + PGOOpt = PGOOptions(PGOSampleUsePath, "", "", PGOOptions::SampleUse, + PGOOptions::NoCSAction, DebugInfoForProfiling); + } else if (DebugInfoForProfiling) { + PGOOpt = PGOOptions("", "", "", PGOOptions::NoAction, + PGOOptions::NoCSAction, DebugInfoForProfiling); } #if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0) @@ -875,7 +894,11 @@ #if LLVM_VERSION_GE(11, 0) OptimizerLastEPCallbacks.push_back( [Options](ModulePassManager &MPM, OptimizationLevel Level) { +#if LLVM_VERSION_GE(14, 0) + MPM.addPass(ModuleMemorySanitizerPass(Options)); +#else MPM.addPass(MemorySanitizerPass(Options)); +#endif MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options))); } ); @@ -897,7 +920,11 @@ #if LLVM_VERSION_GE(11, 0) OptimizerLastEPCallbacks.push_back( [](ModulePassManager &MPM, OptimizationLevel Level) { +#if LLVM_VERSION_GE(14, 0) + MPM.addPass(ModuleThreadSanitizerPass()); +#else MPM.addPass(ThreadSanitizerPass()); +#endif MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); } ); @@ -989,7 +1016,10 @@ #endif bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { - if (OptLevel == OptimizationLevel::O0) { + // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead. + // At the same time, the LTO pipelines do support O0 and using them is required. + bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO; + if (OptLevel == OptimizationLevel::O0 && !IsLTO) { #if LLVM_VERSION_GE(12, 0) for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); @@ -1554,7 +1584,11 @@ LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { Module &Mod = *unwrap(M); const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier()); +#if LLVM_VERSION_GE(14, 0) + thinLTOFinalizeInModule(Mod, DefinedGlobals, /*PropagateAttrs=*/true); +#else thinLTOResolvePrevailingInModule(Mod, DefinedGlobals); +#endif return true; } @@ -1732,7 +1766,7 @@ // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See // the comment in `back/lto.rs` for why this exists. extern "C" void -LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod, +LLVMRustLTOGetDICompileUnit(LLVMModuleRef Mod, DICompileUnit **A, DICompileUnit **B) { Module *M = unwrap(Mod); @@ -1750,7 +1784,7 @@ // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See // the comment in `back/lto.rs` for why this exists. extern "C" void -LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { +LLVMRustLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { Module *M = unwrap(Mod); // If the original source module didn't have a `DICompileUnit` then try to diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp 2021-11-29 19:27:11.000000000 +0000 @@ -54,7 +54,11 @@ // // Notably it exits the process with code 101, unlike LLVM's default of 1. static void FatalErrorHandler(void *UserData, +#if LLVM_VERSION_LT(14, 0) const std::string& Reason, +#else + const char* Reason, +#endif bool GenCrashDiag) { // Do the same thing that the default error handler does. std::cerr << "LLVM ERROR: " << Reason << std::endl; @@ -203,56 +207,57 @@ report_fatal_error("bad AttributeKind"); } +template static inline void AddAttribute(T *t, unsigned Index, Attribute Attr) { +#if LLVM_VERSION_LT(14, 0) + t->addAttribute(Index, Attr); +#else + t->addAttributeAtIndex(Index, Attr); +#endif +} + extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index, LLVMRustAttribute RustAttr) { CallBase *Call = unwrap(Instr); Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr)); - Call->addAttribute(Index, Attr); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddCallSiteAttrString(LLVMValueRef Instr, unsigned Index, const char *Name) { CallBase *Call = unwrap(Instr); Attribute Attr = Attribute::get(Call->getContext(), Name); - Call->addAttribute(Index, Attr); + AddAttribute(Call, Index, Attr); } - extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint32_t Bytes) { CallBase *Call = unwrap(Instr); - AttrBuilder B; - B.addAlignmentAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); + Attribute Attr = Attribute::getWithAlignment(Call->getContext(), Align(Bytes)); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint64_t Bytes) { CallBase *Call = unwrap(Instr); - AttrBuilder B; - B.addDereferenceableAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); + Attribute Attr = Attribute::getWithDereferenceableBytes(Call->getContext(), Bytes); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint64_t Bytes) { CallBase *Call = unwrap(Instr); - AttrBuilder B; - B.addDereferenceableOrNullAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); + Attribute Attr = Attribute::getWithDereferenceableOrNullBytes(Call->getContext(), Bytes); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index, LLVMTypeRef Ty) { CallBase *Call = unwrap(Instr); Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty)); - Call->addAttribute(Index, Attr); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned Index, @@ -263,28 +268,28 @@ #else Attribute Attr = Attribute::get(Call->getContext(), Attribute::StructRet); #endif - Call->addAttribute(Index, Attr); + AddAttribute(Call, Index, Attr); } extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index, LLVMRustAttribute RustAttr) { Function *A = unwrap(Fn); Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr)); - A->addAttribute(Index, Attr); + AddAttribute(A, Index, Attr); } extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn, unsigned Index, uint32_t Bytes) { Function *A = unwrap(Fn); - A->addAttribute(Index, Attribute::getWithAlignment( + AddAttribute(A, Index, Attribute::getWithAlignment( A->getContext(), llvm::Align(Bytes))); } extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index, uint64_t Bytes) { Function *A = unwrap(Fn); - A->addAttribute(Index, Attribute::getWithDereferenceableBytes(A->getContext(), + AddAttribute(A, Index, Attribute::getWithDereferenceableBytes(A->getContext(), Bytes)); } @@ -292,7 +297,7 @@ unsigned Index, uint64_t Bytes) { Function *A = unwrap(Fn); - A->addAttribute(Index, Attribute::getWithDereferenceableOrNullBytes( + AddAttribute(A, Index, Attribute::getWithDereferenceableOrNullBytes( A->getContext(), Bytes)); } @@ -300,7 +305,7 @@ LLVMTypeRef Ty) { Function *F = unwrap(Fn); Attribute Attr = Attribute::getWithByValType(F->getContext(), unwrap(Ty)); - F->addAttribute(Index, Attr); + AddAttribute(F, Index, Attr); } extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index, @@ -311,7 +316,7 @@ #else Attribute Attr = Attribute::get(F->getContext(), Attribute::StructRet); #endif - F->addAttribute(Index, Attr); + AddAttribute(F, Index, Attr); } extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, @@ -319,7 +324,7 @@ const char *Name, const char *Value) { Function *F = unwrap(Fn); - F->addAttribute(Index, Attribute::get( + AddAttribute(F, Index, Attribute::get( F->getContext(), StringRef(Name), StringRef(Value))); } @@ -330,7 +335,12 @@ Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr)); AttrBuilder B(Attr); auto PAL = F->getAttributes(); - auto PALNew = PAL.removeAttributes(F->getContext(), Index, B); + AttributeList PALNew; +#if LLVM_VERSION_LT(14, 0) + PALNew = PAL.removeAttributes(F->getContext(), Index, B); +#else + PALNew = PAL.removeAttributesAtIndex(F->getContext(), Index, B); +#endif F->setAttributes(PALNew); } @@ -1743,10 +1753,11 @@ } // This struct contains all necessary info about a symbol exported from a DLL. -// At the moment, it's just the symbol's name, but we use a separate struct to -// make it easier to add other information like ordinal later. struct LLVMRustCOFFShortExport { const char* name; + bool ordinal_present; + // The value of `ordinal` is only meaningful if `ordinal_present` is true. + uint16_t ordinal; }; // Machine must be a COFF machine type, as defined in PE specs. @@ -1762,13 +1773,15 @@ ConvertedExports.reserve(NumExports); for (size_t i = 0; i < NumExports; ++i) { + bool ordinal_present = Exports[i].ordinal_present; + uint16_t ordinal = ordinal_present ? Exports[i].ordinal : 0; ConvertedExports.push_back(llvm::object::COFFShortExport{ Exports[i].name, // Name std::string{}, // ExtName std::string{}, // SymbolName std::string{}, // AliasTarget - 0, // Ordinal - false, // Noname + ordinal, // Ordinal + ordinal_present, // Noname false, // Data false, // Private false // Constant diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_llvm/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_llvm/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -17,6 +17,10 @@ pub fn len(&self) -> usize { self.bytes.borrow().len() } + + pub fn is_empty(&self) -> bool { + self.bytes.borrow().is_empty() + } } /// Appending to a Rust string -- used by RawRustStringOstream. @@ -91,6 +95,14 @@ LLVMInitializeAVRAsmParser ); init_target!( + llvm_component = "m68k", + LLVMInitializeM68kTargetInfo, + LLVMInitializeM68kTarget, + LLVMInitializeM68kTargetMC, + LLVMInitializeM68kAsmPrinter, + LLVMInitializeM68kAsmParser + ); + init_target!( llvm_component = "mips", LLVMInitializeMipsTargetInfo, LLVMInitializeMipsTarget, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_macros" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] proc-macro = true diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/src/hash_stable.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/src/hash_stable.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/src/hash_stable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/src/hash_stable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -24,11 +24,9 @@ } if meta.path().is_ident("project") { if let Meta::List(list) = meta { - if let Some(nested) = list.nested.iter().next() { - if let NestedMeta::Meta(meta) = nested { - attrs.project = meta.path().get_ident().cloned(); - any_attr = true; - } + if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() { + attrs.project = meta.path().get_ident().cloned(); + any_attr = true; } } } @@ -116,14 +114,14 @@ s.bound_impl( quote!( ::rustc_data_structures::stable_hasher::HashStable< - ::rustc_middle::ich::StableHashingContext<'__ctx>, + ::rustc_query_system::ich::StableHashingContext<'__ctx>, > ), quote! { #[inline] fn hash_stable( &self, - __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>, + __hcx: &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { #discriminant match *self { #body } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/src/query.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/src/query.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/src/query.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/src/query.rs 2021-11-29 19:27:11.000000000 +0000 @@ -455,28 +455,28 @@ // Pass on the fatal_cycle modifier if let Some(fatal_cycle) = &modifiers.fatal_cycle { - attributes.push(quote! { #fatal_cycle }); + attributes.push(quote! { (#fatal_cycle) }); }; // Pass on the storage modifier if let Some(ref ty) = modifiers.storage { let span = ty.span(); - attributes.push(quote_spanned! {span=> storage(#ty) }); + attributes.push(quote_spanned! {span=> (storage #ty) }); }; // Pass on the cycle_delay_bug modifier if let Some(cycle_delay_bug) = &modifiers.cycle_delay_bug { - attributes.push(quote! { #cycle_delay_bug }); + attributes.push(quote! { (#cycle_delay_bug) }); }; // Pass on the no_hash modifier if let Some(no_hash) = &modifiers.no_hash { - attributes.push(quote! { #no_hash }); + attributes.push(quote! { (#no_hash) }); }; // Pass on the anon modifier if let Some(anon) = &modifiers.anon { - attributes.push(quote! { #anon }); + attributes.push(quote! { (#anon) }); }; // Pass on the eval_always modifier if let Some(eval_always) = &modifiers.eval_always { - attributes.push(quote! { #eval_always }); + attributes.push(quote! { (#eval_always) }); }; // This uses the span of the query definition for the commas, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/src/session_diagnostic.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/src/session_diagnostic.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/src/session_diagnostic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/src/session_diagnostic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -349,14 +349,14 @@ ) -> Result { let field_binding = &info.binding.binding; - let option_ty = option_inner_ty(&info.ty); + let option_ty = option_inner_ty(info.ty); let generated_code = self.generate_non_option_field_code( attr, FieldInfo { vis: info.vis, binding: info.binding, - ty: option_ty.unwrap_or(&info.ty), + ty: option_ty.unwrap_or(info.ty), span: info.span, }, )?; @@ -388,7 +388,7 @@ let formatted_str = self.build_format(&s.value(), attr.span()); match name { "message" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + if type_matches_path(info.ty, &["rustc_span", "Span"]) { quote! { #diag.set_span(*#field_binding); #diag.set_primary_message(#formatted_str); @@ -401,7 +401,7 @@ } } "label" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + if type_matches_path(info.ty, &["rustc_span", "Span"]) { quote! { #diag.span_label(*#field_binding, #formatted_str); } @@ -448,7 +448,7 @@ span_idx = Some(syn::Index::from(idx)); } else { throw_span_err!( - info.span.clone().unwrap(), + info.span.unwrap(), "type of field annotated with `#[suggestion(...)]` contains more than one Span" ); } @@ -460,7 +460,7 @@ applicability_idx = Some(syn::Index::from(idx)); } else { throw_span_err!( - info.span.clone().unwrap(), + info.span.unwrap(), "type of field annotated with `#[suggestion(...)]` contains more than one Applicability" ); } @@ -479,7 +479,7 @@ return Ok((span, applicability)); } throw_span_err!( - info.span.clone().unwrap(), + info.span.unwrap(), "wrong types for suggestion", |diag| { diag.help("#[suggestion(...)] on a tuple field must be applied to fields of type (Span, Applicability)") @@ -487,7 +487,7 @@ ); } _ => throw_span_err!( - info.span.clone().unwrap(), + info.span.unwrap(), "wrong field type for suggestion", |diag| { diag.help("#[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)") diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/src/symbols.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/src/symbols.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_macros/src/symbols.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_macros/src/symbols.rs 2021-11-29 19:27:11.000000000 +0000 @@ -215,7 +215,7 @@ } impl Interner { - pub fn fresh() -> Self { + pub(crate) fn fresh() -> Self { Interner::prefill(&[ #prefill_stream ]) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,14 @@ [package] name = "rustc_metadata" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false [dependencies] libc = "0.2" +odht = { version = "0.3.1", features = ["nightly"] } snap = "1" tracing = "0.1" smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/creader.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/creader.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/creader.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/creader.rs 2021-11-29 19:27:11.000000000 +0000 @@ -13,11 +13,11 @@ use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_index::vec::IndexVec; -use rustc_middle::middle::cstore::{CrateDepKind, CrateSource, ExternCrate}; -use rustc_middle::middle::cstore::{ExternCrateSource, MetadataLoaderDyn}; use rustc_middle::ty::TyCtxt; use rustc_serialize::json::ToJson; use rustc_session::config::{self, CrateType, ExternLocation}; +use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate}; +use rustc_session::cstore::{ExternCrateSource, MetadataLoaderDyn}; use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; @@ -45,7 +45,7 @@ /// This map is used to verify we get no hash conflicts between /// `StableCrateId` values. - stable_crate_ids: FxHashMap, + pub(crate) stable_crate_ids: FxHashMap, /// Unused externs of the crate unused_externs: Vec, @@ -450,6 +450,7 @@ &self, locator: &mut CrateLocator<'b>, path_kind: PathKind, + host_hash: Option, ) -> Result)>, CrateError> where 'a: 'b, @@ -459,7 +460,7 @@ let mut proc_macro_locator = locator.clone(); // Try to load a proc macro - proc_macro_locator.is_proc_macro = Some(true); + proc_macro_locator.is_proc_macro = true; // Load the proc macro crate for the target let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros { @@ -471,7 +472,7 @@ Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)), None => return Ok(None), }; - locator.hash = locator.host_hash; + locator.hash = host_hash; // Use the locator when looking for the host proc macro crate, as that is required // so we want it to affect the error message (locator, result) @@ -482,7 +483,7 @@ // Load the proc macro crate for the host locator.reset(); - locator.is_proc_macro = Some(true); + locator.is_proc_macro = true; locator.target = &self.sess.host; locator.triple = TargetTriple::from_triple(config::host_triple()); locator.filesearch = self.sess.host_filesearch(path_kind); @@ -510,12 +511,9 @@ name: Symbol, span: Span, dep_kind: CrateDepKind, - dep: Option<(&'b CratePaths, &'b CrateDep)>, ) -> CrateNum { - if dep.is_none() { - self.used_extern_options.insert(name); - } - self.maybe_resolve_crate(name, dep_kind, dep).unwrap_or_else(|err| { + self.used_extern_options.insert(name); + self.maybe_resolve_crate(name, dep_kind, None).unwrap_or_else(|err| { let missing_core = self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err(); err.report(&self.sess, span, missing_core) @@ -551,21 +549,18 @@ &*self.metadata_loader, name, hash, - host_hash, extra_filename, false, // is_host path_kind, - root, - Some(false), // is_proc_macro ); match self.load(&mut locator)? { Some(res) => (res, None), None => { dep_kind = CrateDepKind::MacrosOnly; - match self.load_proc_macro(&mut locator, path_kind)? { + match self.load_proc_macro(&mut locator, path_kind, host_hash)? { Some(res) => res, - None => return Err(locator.into_error()), + None => return Err(locator.into_error(root.cloned())), } } } @@ -605,7 +600,7 @@ // FIXME: why is this condition necessary? It was adding in #33625 but I // don't know why and the original author doesn't remember ... let can_reuse_cratenum = - locator.triple == self.sess.opts.target_triple || locator.is_proc_macro == Some(true); + locator.triple == self.sess.opts.target_triple || locator.is_proc_macro; Ok(Some(if can_reuse_cratenum { let mut result = LoadResult::Loaded(library); self.cstore.iter_crate_data(|cnum, data| { @@ -755,7 +750,7 @@ }; info!("panic runtime not found -- loading {}", name); - let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, None); + let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit); let data = self.cstore.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a panic runtime @@ -795,7 +790,7 @@ ); } - let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, None); + let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit); let data = self.cstore.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a profiler runtime @@ -883,7 +878,7 @@ "no global memory allocator found but one is \ required; link to std or \ add `#[global_allocator]` to a static item \ - that implements the GlobalAlloc trait.", + that implements the GlobalAlloc trait", ); } self.cstore.allocator_kind = Some(AllocatorKind::Default); @@ -1015,7 +1010,7 @@ CrateDepKind::Explicit }; - let cnum = self.resolve_crate(name, item.span, dep_kind, None); + let cnum = self.resolve_crate(name, item.span, dep_kind); let path_len = definitions.def_path(def_id).data.len(); self.update_extern_crate( @@ -1034,7 +1029,7 @@ } pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum { - let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, None); + let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit); self.update_extern_crate( cnum, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/dependency_format.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/dependency_format.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/dependency_format.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/dependency_format.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,10 +11,10 @@ //! should be used when linking each output type requested in this session. This //! generally follows this set of rules: //! -//! 1. Each library must appear exactly once in the output. -//! 2. Each rlib contains only one library (it's just an object file) -//! 3. Each dylib can contain more than one library (due to static linking), -//! and can also bring in many dynamic dependencies. +//! 1. Each library must appear exactly once in the output. +//! 2. Each rlib contains only one library (it's just an object file) +//! 3. Each dylib can contain more than one library (due to static linking), +//! and can also bring in many dynamic dependencies. //! //! With these constraints in mind, it's generally a very difficult problem to //! find a solution that's not "all rlibs" or "all dylibs". I have suspicions @@ -22,24 +22,24 @@ //! //! The current selection algorithm below looks mostly similar to: //! -//! 1. If static linking is required, then require all upstream dependencies -//! to be available as rlibs. If not, generate an error. -//! 2. If static linking is requested (generating an executable), then -//! attempt to use all upstream dependencies as rlibs. If any are not -//! found, bail out and continue to step 3. -//! 3. Static linking has failed, at least one library must be dynamically -//! linked. Apply a heuristic by greedily maximizing the number of -//! dynamically linked libraries. -//! 4. Each upstream dependency available as a dynamic library is -//! registered. The dependencies all propagate, adding to a map. It is -//! possible for a dylib to add a static library as a dependency, but it -//! is illegal for two dylibs to add the same static library as a -//! dependency. The same dylib can be added twice. Additionally, it is -//! illegal to add a static dependency when it was previously found as a -//! dylib (and vice versa) -//! 5. After all dynamic dependencies have been traversed, re-traverse the -//! remaining dependencies and add them statically (if they haven't been -//! added already). +//! 1. If static linking is required, then require all upstream dependencies +//! to be available as rlibs. If not, generate an error. +//! 2. If static linking is requested (generating an executable), then +//! attempt to use all upstream dependencies as rlibs. If any are not +//! found, bail out and continue to step 3. +//! 3. Static linking has failed, at least one library must be dynamically +//! linked. Apply a heuristic by greedily maximizing the number of +//! dynamically linked libraries. +//! 4. Each upstream dependency available as a dynamic library is +//! registered. The dependencies all propagate, adding to a map. It is +//! possible for a dylib to add a static library as a dependency, but it +//! is illegal for two dylibs to add the same static library as a +//! dependency. The same dylib can be added twice. Additionally, it is +//! illegal to add a static dependency when it was previously found as a +//! dylib (and vice versa) +//! 5. After all dynamic dependencies have been traversed, re-traverse the +//! remaining dependencies and add them statically (if they haven't been +//! added already). //! //! While not perfect, this algorithm should help support use-cases such as leaf //! dependencies being static while the larger tree of inner dependencies are @@ -55,11 +55,11 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::CrateDepKind; -use rustc_middle::middle::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage}; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; +use rustc_session::cstore::CrateDepKind; +use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc_target::spec::PanicStrategy; crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies { @@ -277,7 +277,7 @@ let all_crates_available_as_rlib = tcx .crates(()) .iter() - .cloned() + .copied() .filter_map(|cnum| { if tcx.dep_kind(cnum).macros_only() { return None; @@ -291,10 +291,11 @@ // All crates are available in an rlib format, so we're just going to link // everything in explicitly so long as it's actually required. - let last_crate = tcx.crates(()).len(); - let mut ret = (1..last_crate + 1) - .map(|cnum| { - if tcx.dep_kind(CrateNum::new(cnum)) == CrateDepKind::Explicit { + let mut ret = tcx + .crates(()) + .iter() + .map(|&cnum| { + if tcx.dep_kind(cnum) == CrateDepKind::Explicit { Linkage::Static } else { Linkage::NotLinked @@ -400,21 +401,35 @@ continue; } let cnum = CrateNum::new(i + 1); - let found_strategy = tcx.panic_strategy(cnum); - let is_compiler_builtins = tcx.is_compiler_builtins(cnum); - if is_compiler_builtins || desired_strategy == found_strategy { + if tcx.is_compiler_builtins(cnum) { continue; } - sess.err(&format!( - "the crate `{}` is compiled with the \ + let found_strategy = tcx.panic_strategy(cnum); + if desired_strategy != found_strategy { + sess.err(&format!( + "the crate `{}` is compiled with the \ panic strategy `{}` which is \ incompatible with this crate's \ strategy of `{}`", - tcx.crate_name(cnum), - found_strategy.desc(), - desired_strategy.desc() - )); + tcx.crate_name(cnum), + found_strategy.desc(), + desired_strategy.desc() + )); + } + + let found_drop_strategy = tcx.panic_in_drop_strategy(cnum); + if tcx.sess.opts.debugging_opts.panic_in_drop != found_drop_strategy { + sess.err(&format!( + "the crate `{}` is compiled with the \ + panic-in-drop strategy `{}` which is \ + incompatible with this crate's \ + strategy of `{}`", + tcx.crate_name(cnum), + found_drop_strategy.desc(), + tcx.sess.opts.debugging_opts.panic_in_drop.desc() + )); + } } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/foreign_modules.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/foreign_modules.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/foreign_modules.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/foreign_modules.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_middle::middle::cstore::ForeignModule; use rustc_middle::ty::TyCtxt; +use rustc_session::cstore::ForeignModule; crate fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { modules: Vec::new() }; - tcx.hir().krate().visit_all_item_likes(&mut collector); + tcx.hir().visit_all_item_likes(&mut collector); collector.modules } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -30,4 +30,4 @@ pub mod dynamic_lib; pub mod locator; -pub use rmeta::METADATA_HEADER; +pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER}; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/locator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/locator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/locator.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/locator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -221,8 +221,8 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_errors::struct_span_err; -use rustc_middle::middle::cstore::{CrateSource, MetadataLoader}; use rustc_session::config::{self, CrateType}; +use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch}; use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; @@ -232,6 +232,7 @@ use rustc_target::spec::{Target, TargetTriple}; use snap::read::FrameDecoder; +use std::fmt::Write as _; use std::io::{Read, Result as IoResult, Write}; use std::path::{Path, PathBuf}; use std::{cmp, fmt, fs}; @@ -240,27 +241,22 @@ #[derive(Clone)] crate struct CrateLocator<'a> { // Immutable per-session configuration. - sess: &'a Session, + only_needs_metadata: bool, + sysroot: &'a Path, metadata_loader: &'a dyn MetadataLoader, // Immutable per-search configuration. crate_name: Symbol, exact_paths: Vec, pub hash: Option, - pub host_hash: Option, extra_filename: Option<&'a str>, pub target: &'a Target, pub triple: TargetTriple, pub filesearch: FileSearch<'a>, - root: Option<&'a CratePaths>, - pub is_proc_macro: Option, + pub is_proc_macro: bool, // Mutable in-progress state or output. - rejected_via_hash: Vec, - rejected_via_triple: Vec, - rejected_via_kind: Vec, - rejected_via_version: Vec, - rejected_via_filename: Vec, + crate_rejections: CrateRejections, } #[derive(Clone)] @@ -298,15 +294,22 @@ metadata_loader: &'a dyn MetadataLoader, crate_name: Symbol, hash: Option, - host_hash: Option, extra_filename: Option<&'a str>, is_host: bool, path_kind: PathKind, - root: Option<&'a CratePaths>, - is_proc_macro: Option, ) -> CrateLocator<'a> { + // The all loop is because `--crate-type=rlib --crate-type=rlib` is + // legal and produces both inside this type. + let is_rlib = sess.crate_types().iter().all(|c| *c == CrateType::Rlib); + let needs_object_code = sess.opts.output_types.should_codegen(); + // If we're producing an rlib, then we don't need object code. + // Or, if we're not producing object code, then we don't need it either + // (e.g., if we're a cdylib but emitting just metadata). + let only_needs_metadata = is_rlib || !needs_object_code; + CrateLocator { - sess, + only_needs_metadata, + sysroot: &sess.sysroot, metadata_loader, crate_name, exact_paths: if hash.is_none() { @@ -324,7 +327,6 @@ Vec::new() }, hash, - host_hash, extra_filename, target: if is_host { &sess.host } else { &sess.target }, triple: if is_host { @@ -337,22 +339,17 @@ } else { sess.target_filesearch(path_kind) }, - root, - is_proc_macro, - rejected_via_hash: Vec::new(), - rejected_via_triple: Vec::new(), - rejected_via_kind: Vec::new(), - rejected_via_version: Vec::new(), - rejected_via_filename: Vec::new(), + is_proc_macro: false, + crate_rejections: CrateRejections::default(), } } crate fn reset(&mut self) { - self.rejected_via_hash.clear(); - self.rejected_via_triple.clear(); - self.rejected_via_kind.clear(); - self.rejected_via_version.clear(); - self.rejected_via_filename.clear(); + self.crate_rejections.via_hash.clear(); + self.crate_rejections.via_triple.clear(); + self.crate_rejections.via_kind.clear(); + self.crate_rejections.via_version.clear(); + self.crate_rejections.via_filename.clear(); } crate fn maybe_load_library_crate(&mut self) -> Result, CrateError> { @@ -435,7 +432,7 @@ }; FileMatches }); - self.rejected_via_kind.extend(staticlibs); + self.crate_rejections.via_kind.extend(staticlibs); // We have now collected all known libraries into a set of candidates // keyed of the filename hash listed. For each filename, we also have a @@ -480,18 +477,11 @@ } fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool { - if flavor == CrateFlavor::Dylib && self.is_proc_macro == Some(true) { + if flavor == CrateFlavor::Dylib && self.is_proc_macro { return true; } - // The all loop is because `--crate-type=rlib --crate-type=rlib` is - // legal and produces both inside this type. - let is_rlib = self.sess.crate_types().iter().all(|c| *c == CrateType::Rlib); - let needs_object_code = self.sess.opts.output_types.should_codegen(); - // If we're producing an rlib, then we don't need object code. - // Or, if we're not producing object code, then we don't need it either - // (e.g., if we're a cdylib but emitting just metadata). - if is_rlib || !needs_object_code { + if self.only_needs_metadata { flavor == CrateFlavor::Rmeta } else { // we need all flavors (perhaps not true, but what we do for now) @@ -539,6 +529,15 @@ let mut err_data: Option> = None; for (lib, kind) in m { info!("{} reading metadata from: {}", flavor, lib.display()); + if flavor == CrateFlavor::Rmeta && lib.metadata().map_or(false, |m| m.len() == 0) { + // Empty files will cause get_metadata_section to fail. Rmeta + // files can be empty, for example with binaries (which can + // often appear with `cargo check` when checking a library as + // a unittest). We don't want to emit a user-visible warning + // in this case as it is not a real problem. + debug!("skipping empty file"); + continue; + } let (hash, metadata) = match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) { Ok(blob) => { @@ -591,7 +590,7 @@ // candidates are all canonicalized, so we canonicalize the sysroot // as well. if let Some((prev, _)) = &ret { - let sysroot = &self.sess.sysroot; + let sysroot = self.sysroot; let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf()); if prev.starts_with(&sysroot) { continue; @@ -613,21 +612,20 @@ let found_version = metadata.get_rustc_version(); if found_version != rustc_version { info!("Rejecting via version: expected {} got {}", rustc_version, found_version); - self.rejected_via_version + self.crate_rejections + .via_version .push(CrateMismatch { path: libpath.to_path_buf(), got: found_version }); return None; } let root = metadata.get_root(); - if let Some(expected_is_proc_macro) = self.is_proc_macro { - let is_proc_macro = root.is_proc_macro_crate(); - if is_proc_macro != expected_is_proc_macro { - info!( - "Rejecting via proc macro: expected {} got {}", - expected_is_proc_macro, is_proc_macro - ); - return None; - } + if root.is_proc_macro_crate() != self.is_proc_macro { + info!( + "Rejecting via proc macro: expected {} got {}", + self.is_proc_macro, + root.is_proc_macro_crate(), + ); + return None; } if self.exact_paths.is_empty() && self.crate_name != root.name() { @@ -637,7 +635,7 @@ if root.triple() != &self.triple { info!("Rejecting via crate triple: expected {} got {}", self.triple, root.triple()); - self.rejected_via_triple.push(CrateMismatch { + self.crate_rejections.via_triple.push(CrateMismatch { path: libpath.to_path_buf(), got: root.triple().to_string(), }); @@ -648,7 +646,8 @@ if let Some(expected_hash) = self.hash { if hash != expected_hash { info!("Rejecting via hash: expected {} got {}", expected_hash, hash); - self.rejected_via_hash + self.crate_rejections + .via_hash .push(CrateMismatch { path: libpath.to_path_buf(), got: hash.to_string() }); return None; } @@ -702,7 +701,8 @@ dylibs.insert(loc_canon, PathKind::ExternFlag); } } else { - self.rejected_via_filename + self.crate_rejections + .via_filename .push(CrateMismatch { path: loc.original().clone(), got: String::new() }); } } @@ -711,18 +711,14 @@ Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib)) } - crate fn into_error(self) -> CrateError { + crate fn into_error(self, root: Option) -> CrateError { CrateError::LocatorCombined(CombinedLocatorError { crate_name: self.crate_name, - root: self.root.cloned(), + root, triple: self.triple, dll_prefix: self.target.dll_prefix.clone(), dll_suffix: self.target.dll_suffix.clone(), - rejected_via_hash: self.rejected_via_hash, - rejected_via_triple: self.rejected_via_triple, - rejected_via_kind: self.rejected_via_kind, - rejected_via_version: self.rejected_via_version, - rejected_via_filename: self.rejected_via_filename, + crate_rejections: self.crate_rejections, }) } } @@ -754,7 +750,9 @@ // Header is okay -> inflate the actual metadata let compressed_bytes = &buf[header_len..]; debug!("inflating {} bytes of compressed metadata", compressed_bytes.len()); - let mut inflated = Vec::new(); + // Assume the decompressed data will be at least the size of the compressed data, so we + // don't have to grow the buffer as much. + let mut inflated = Vec::with_capacity(compressed_bytes.len()); match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) { Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()), Err(_) => { @@ -806,12 +804,9 @@ metadata_loader, name, None, // hash - None, // host_hash None, // extra_filename true, // is_host PathKind::Crate, - None, // root - None, // is_proc_macro ); match locator.maybe_load_library_crate()? { @@ -819,7 +814,7 @@ Some(dylib) => Ok(dylib.0), None => Err(CrateError::NonDylibPlugin(name)), }, - None => Err(locator.into_error()), + None => Err(locator.into_error(None)), } } @@ -852,6 +847,15 @@ got: String, } +#[derive(Clone, Default)] +struct CrateRejections { + via_hash: Vec, + via_triple: Vec, + via_kind: Vec, + via_version: Vec, + via_filename: Vec, +} + /// Candidate rejection reasons collected during crate search. /// If no candidate is accepted, then these reasons are presented to the user, /// otherwise they are ignored. @@ -861,11 +865,7 @@ triple: TargetTriple, dll_prefix: String, dll_suffix: String, - rejected_via_hash: Vec, - rejected_via_triple: Vec, - rejected_via_kind: Vec, - rejected_via_version: Vec, - rejected_via_filename: Vec, + crate_rejections: CrateRejections, } crate enum CrateError { @@ -920,23 +920,30 @@ "multiple matching crates for `{}`", crate_name ); + let mut libraries: Vec<_> = libraries.into_values().collect(); + // Make ordering of candidates deterministic. + // This has to `clone()` to work around lifetime restrictions with `sort_by_key()`. + // `sort_by()` could be used instead, but this is in the error path, + // so the performance shouldn't matter. + libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone()); let candidates = libraries .iter() - .filter_map(|(_, lib)| { + .map(|lib| { let crate_name = &lib.metadata.get_root().name().as_str(); - match (&lib.source.dylib, &lib.source.rlib) { - (Some((pd, _)), Some((pr, _))) => Some(format!( - "\ncrate `{}`: {}\n{:>padding$}", - crate_name, - pd.display(), - pr.display(), - padding = 8 + crate_name.len() - )), - (Some((p, _)), None) | (None, Some((p, _))) => { - Some(format!("\ncrate `{}`: {}", crate_name, p.display())) - } - (None, None) => None, + let mut paths = lib.source.paths(); + + // This `unwrap()` should be okay because there has to be at least one + // source file. `CrateSource`'s docs confirm that too. + let mut s = format!( + "\ncrate `{}`: {}", + crate_name, + paths.next().unwrap().display() + ); + let padding = 8 + crate_name.len(); + for path in paths { + write!(s, "\n{:>padding$}", path.display(), padding = padding).unwrap(); } + s }) .collect::(); err.note(&format!("candidates:{}", candidates)); @@ -974,7 +981,7 @@ Some(r) => format!(" which `{}` depends on", r.name), }; let mut msg = "the following crate versions were found:".to_string(); - let mut err = if !locator.rejected_via_hash.is_empty() { + let mut err = if !locator.crate_rejections.via_hash.is_empty() { let mut err = struct_span_err!( sess, span, @@ -984,7 +991,7 @@ add, ); err.note("perhaps that crate needs to be recompiled?"); - let mismatches = locator.rejected_via_hash.iter(); + let mismatches = locator.crate_rejections.via_hash.iter(); for CrateMismatch { path, .. } in mismatches { msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display())); } @@ -995,7 +1002,7 @@ } err.note(&msg); err - } else if !locator.rejected_via_triple.is_empty() { + } else if !locator.crate_rejections.via_triple.is_empty() { let mut err = struct_span_err!( sess, span, @@ -1005,7 +1012,7 @@ locator.triple, add, ); - let mismatches = locator.rejected_via_triple.iter(); + let mismatches = locator.crate_rejections.via_triple.iter(); for CrateMismatch { path, got } in mismatches { msg.push_str(&format!( "\ncrate `{}`, target triple {}: {}", @@ -1016,7 +1023,7 @@ } err.note(&msg); err - } else if !locator.rejected_via_kind.is_empty() { + } else if !locator.crate_rejections.via_kind.is_empty() { let mut err = struct_span_err!( sess, span, @@ -1026,13 +1033,13 @@ add, ); err.help("please recompile that crate using --crate-type lib"); - let mismatches = locator.rejected_via_kind.iter(); + let mismatches = locator.crate_rejections.via_kind.iter(); for CrateMismatch { path, .. } in mismatches { msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display())); } err.note(&msg); err - } else if !locator.rejected_via_version.is_empty() { + } else if !locator.crate_rejections.via_version.is_empty() { let mut err = struct_span_err!( sess, span, @@ -1042,10 +1049,11 @@ add, ); err.help(&format!( - "please recompile that crate using this compiler ({})", + "please recompile that crate using this compiler ({}) \ + (consider running `cargo clean` first)", rustc_version(), )); - let mismatches = locator.rejected_via_version.iter(); + let mismatches = locator.crate_rejections.via_version.iter(); for CrateMismatch { path, got } in mismatches { msg.push_str(&format!( "\ncrate `{}` compiled by {}: {}", @@ -1107,13 +1115,18 @@ == Symbol::intern(&sess.opts.debugging_opts.profiler_runtime) { err.note(&"the compiler may have been built without the profiler runtime"); + } else if crate_name.as_str().starts_with("rustc_") { + err.help( + "maybe you need to install the missing components with: \ + `rustup component add rust-src rustc-dev llvm-tools-preview`", + ); } err.span_label(span, "can't find crate"); err }; - if !locator.rejected_via_filename.is_empty() { - let mismatches = locator.rejected_via_filename.iter(); + if !locator.crate_rejections.via_filename.is_empty() { + let mismatches = locator.crate_rejections.via_filename.iter(); for CrateMismatch { path, .. } in mismatches { err.note(&format!( "extern location for {} is of an unknown type: {}", diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/native_libs.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/native_libs.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/native_libs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/native_libs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,8 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_middle::middle::cstore::{DllCallingConvention, DllImport, NativeLib}; use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; +use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib}; use rustc_session::parse::feature_err; use rustc_session::utils::NativeLibKind; use rustc_session::Session; @@ -14,7 +14,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { tcx, libs: Vec::new() }; - tcx.hir().krate().visit_all_item_likes(&mut collector); + tcx.hir().visit_all_item_likes(&mut collector); collector.process_command_line(); collector.libs } @@ -319,13 +319,13 @@ self.tcx.sess.err(&format!( "renaming of the library `{}` was specified, \ however this crate contains no `#[link(...)]` \ - attributes referencing this library.", + attributes referencing this library", lib.name )); } else if !renames.insert(&lib.name) { self.tcx.sess.err(&format!( "multiple renamings were \ - specified for library `{}` .", + specified for library `{}`", lib.name )); } @@ -363,7 +363,7 @@ .collect::>(); if existing.is_empty() { // Add if not found - let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> + let new_name: Option<&str> = passed_lib.new_name.as_deref(); let lib = NativeLib { name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))), kind: passed_lib.kind, @@ -382,7 +382,7 @@ } } - fn i686_arg_list_size(&self, item: &hir::ForeignItemRef<'_>) -> usize { + fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize { let argument_types: &List> = self.tcx.erase_late_bound_regions( self.tcx .type_of(item.id.def_id) @@ -406,7 +406,7 @@ .sum() } - fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef<'_>) -> DllImport { + fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport { let calling_convention = if self.tcx.sess.target.arch == "x86" { match abi { Abi::C { .. } | Abi::Cdecl => DllCallingConvention::C, @@ -433,6 +433,12 @@ } } }; - DllImport { name: item.ident.name, ordinal: None, calling_convention, span: item.span } + + DllImport { + name: item.ident.name, + ordinal: self.tcx.codegen_fn_attrs(item.id.def_id).link_ordinal, + calling_convention, + span: item.span, + } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,21 +1,18 @@ use crate::creader::{CStore, LoadedMacro}; use crate::foreign_modules; use crate::native_libs; -use crate::rmeta::encoder; use rustc_ast as ast; use rustc_data_structures::stable_map::FxHashMap; -use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::ForeignModule; -use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata}; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, Visibility}; +use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule}; use rustc_session::utils::NativeLibKind; use rustc_session::{Session, StableCrateId}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -86,6 +83,12 @@ } } +impl IntoArgs for ty::InstanceDef<'tcx> { + fn into_args(self) -> (DefId, DefId) { + (self.def_id(), self.def_id()) + } +} + provide! { <'tcx> tcx, def_id, other, cdata, type_of => { cdata.get_type(def_id.index, tcx) } generics_of => { cdata.get_generics(def_id.index, tcx.sess) } @@ -117,7 +120,7 @@ optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) } promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } - mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) } + thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) } unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } @@ -160,6 +163,7 @@ has_panic_handler => { cdata.root.has_panic_handler } is_profiler_runtime => { cdata.root.profiler_runtime } panic_strategy => { cdata.root.panic_strategy } + panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy } extern_crate => { let r = *cdata.extern_crate.lock(); r.map(|c| &*tcx.arena.alloc(c)) @@ -304,17 +308,7 @@ // traversal, but not globally minimal across all crates. let bfs_queue = &mut VecDeque::new(); - // Preferring shortest paths alone does not guarantee a - // deterministic result; so sort by crate num to avoid - // hashtable iteration non-determinism. This only makes - // things as deterministic as crate-nums assignment is, - // which is to say, its not deterministic in general. But - // we believe that libstd is consistently assigned crate - // num 1, so it should be enough to resolve #46112. - let mut crates: Vec = (*tcx.crates(())).to_owned(); - crates.sort(); - - for &cnum in crates.iter() { + for &cnum in tcx.crates(()) { // Ignore crates without a corresponding local `extern crate` item. if tcx.missing_extern_crate_item(cnum) { continue; @@ -323,37 +317,32 @@ bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX }); } - // (restrict scope of mutable-borrow of `visible_parent_map`) - { - let visible_parent_map = &mut visible_parent_map; - let mut add_child = - |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { - if child.vis != ty::Visibility::Public { - return; - } + let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { + if child.vis != ty::Visibility::Public { + return; + } - if let Some(child) = child.res.opt_def_id() { - match visible_parent_map.entry(child) { - Entry::Occupied(mut entry) => { - // If `child` is defined in crate `cnum`, ensure - // that it is mapped to a parent in `cnum`. - if child.is_local() && entry.get().is_local() { - entry.insert(parent); - } - } - Entry::Vacant(entry) => { - entry.insert(parent); - bfs_queue.push_back(child); - } + if let Some(child) = child.res.opt_def_id() { + match visible_parent_map.entry(child) { + Entry::Occupied(mut entry) => { + // If `child` is defined in crate `cnum`, ensure + // that it is mapped to a parent in `cnum`. + if child.is_local() && entry.get().is_local() { + entry.insert(parent); } } - }; - - while let Some(def) = bfs_queue.pop_front() { - for child in tcx.item_children(def).iter() { - add_child(bfs_queue, child, def); + Entry::Vacant(entry) => { + entry.insert(parent); + bfs_queue.push_back(child); + } } } + }; + + while let Some(def) = bfs_queue.pop_front() { + for child in tcx.item_children(def).iter() { + add_child(bfs_queue, child, def); + } } visible_parent_map @@ -393,11 +382,7 @@ self.get_crate_data(def.krate).get_visibility(def.index) } - pub fn item_children_untracked( - &self, - def_id: DefId, - sess: &Session, - ) -> Vec> { + pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec { let mut result = vec![]; self.get_crate_data(def_id.krate).each_child_of_item( def_id.index, @@ -503,6 +488,10 @@ self.get_crate_data(cnum).root.stable_crate_id } + fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum { + self.stable_crate_ids[&stable_crate_id] + } + /// Returns the `DefKey` for a given `DefId`. This indicates the /// parent `DefId` as well as some idea of what kind of data the /// `DefId` refers to. @@ -518,21 +507,18 @@ self.get_crate_data(def.krate).def_path_hash(def.index) } - // See `CrateMetadataRef::def_path_hash_to_def_id` for more details - fn def_path_hash_to_def_id( + 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); + DefId { krate: cnum, index: def_index } + } + + fn expn_hash_to_expn_id( &self, + sess: &Session, cnum: CrateNum, index_guess: u32, - hash: DefPathHash, - ) -> Option { - self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash) - } - - fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId { - self.get_crate_data(cnum).expn_hash_to_expn_id(index_guess, hash) - } - - fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata { - encoder::encode_metadata(tcx) + hash: ExpnHash, + ) -> ExpnId { + self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash) } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/decoder.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/decoder.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/decoder.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/decoder.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,17 +18,20 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; +use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::lang_items; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::{CrateSource, ExternCrate}; -use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, Body, Promoted}; +use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; +use rustc_session::cstore::{ + CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib, +}; use rustc_session::Session; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::source_map::{respan, Spanned}; @@ -47,7 +50,26 @@ mod cstore_impl; -crate struct MetadataBlob(MetadataRef); +/// A reference to the raw binary version of crate metadata. +/// A `MetadataBlob` internally is just a reference counted pointer to +/// the actual data, so cloning it is cheap. +#[derive(Clone)] +crate struct MetadataBlob(Lrc); + +// This is needed so we can create an OwningRef into the blob. +// The data behind a `MetadataBlob` has a stable address because it is +// contained within an Rc/Arc. +unsafe impl rustc_data_structures::owning_ref::StableAddress for MetadataBlob {} + +// This is needed so we can create an OwningRef into the blob. +impl std::ops::Deref for MetadataBlob { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.0[..] + } +} // A map from external crate numbers (as decoded from some crate file) to // local crate numbers (as generated during this session). Each external @@ -75,10 +97,8 @@ raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. source_map_import_info: OnceCell>, - /// For every definition in this crate, maps its `DefPathHash` to its - /// `DefIndex`. See `raw_def_id_to_def_id` for more details about how - /// this is used. - def_path_hash_map: OnceCell>, + /// For every definition in this crate, maps its `DefPathHash` to its `DefIndex`. + def_path_hash_map: DefPathHashMapRef<'static>, /// Likewise for ExpnHash. expn_hash_map: OnceCell>, /// Used for decoding interpret::AllocIds in a cached & thread-safe manner. @@ -133,6 +153,7 @@ pub(super) struct DecodeContext<'a, 'tcx> { opaque: opaque::Decoder<'a>, cdata: Option>, + blob: &'a MetadataBlob, sess: Option<&'tcx Session>, tcx: Option>, @@ -147,7 +168,8 @@ /// Abstract over the various ways one can create metadata decoders. pub(super) trait Metadata<'a, 'tcx>: Copy { - fn raw_bytes(self) -> &'a [u8]; + fn blob(self) -> &'a MetadataBlob; + fn cdata(self) -> Option> { None } @@ -161,8 +183,9 @@ fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { let tcx = self.tcx(); DecodeContext { - opaque: opaque::Decoder::new(self.raw_bytes(), pos), + opaque: opaque::Decoder::new(self.blob(), pos), cdata: self.cdata(), + blob: self.blob(), sess: self.sess().or(tcx.map(|tcx| tcx.sess)), tcx, last_source_file_index: 0, @@ -175,17 +198,19 @@ } impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob { - fn raw_bytes(self) -> &'a [u8] { - &self.0 + #[inline] + fn blob(self) -> &'a MetadataBlob { + self } } impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) { - fn raw_bytes(self) -> &'a [u8] { - let (blob, _) = self; - &blob.0 + #[inline] + fn blob(self) -> &'a MetadataBlob { + self.0 } + #[inline] fn sess(self) -> Option<&'tcx Session> { let (_, sess) = self; Some(sess) @@ -193,33 +218,41 @@ } impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> { - fn raw_bytes(self) -> &'a [u8] { - self.blob.raw_bytes() + #[inline] + fn blob(self) -> &'a MetadataBlob { + &self.blob } + #[inline] fn cdata(self) -> Option> { Some(*self) } } impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) { - fn raw_bytes(self) -> &'a [u8] { - self.0.raw_bytes() + #[inline] + fn blob(self) -> &'a MetadataBlob { + &self.0.blob } + #[inline] fn cdata(self) -> Option> { Some(*self.0) } + #[inline] fn sess(self) -> Option<&'tcx Session> { Some(&self.1) } } impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) { - fn raw_bytes(self) -> &'a [u8] { - self.0.raw_bytes() + #[inline] + fn blob(self) -> &'a MetadataBlob { + &self.0.blob } + #[inline] fn cdata(self) -> Option> { Some(*self.0) } + #[inline] fn tcx(self) -> Option> { Some(self.1) } @@ -245,12 +278,21 @@ } impl<'a, 'tcx> DecodeContext<'a, 'tcx> { + #[inline] fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx.expect("missing TyCtxt in DecodeContext") + debug_assert!(self.tcx.is_some(), "missing TyCtxt in DecodeContext"); + self.tcx.unwrap() } - fn cdata(&self) -> CrateMetadataRef<'a> { - self.cdata.expect("missing CrateMetadata in DecodeContext") + #[inline] + pub fn blob(&self) -> &'a MetadataBlob { + self.blob + } + + #[inline] + pub fn cdata(&self) -> CrateMetadataRef<'a> { + debug_assert!(self.cdata.is_some(), "missing CrateMetadata in DecodeContext"); + self.cdata.unwrap() } fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { @@ -275,6 +317,11 @@ self.lazy_state = LazyState::Previous(NonZeroUsize::new(position + min_size).unwrap()); Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta)) } + + #[inline] + pub fn read_raw_bytes(&mut self, len: usize) -> &'a [u8] { + self.opaque.read_raw_bytes(len) + } } impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { @@ -536,11 +583,12 @@ let hi = (hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos; - Ok(Span::new(lo, hi, ctxt)) + // Do not try to decode parent for foreign spans. + Ok(Span::new(lo, hi, ctxt, None)) } } -impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { ty::codec::RefDecodable::decode(d) } @@ -584,11 +632,11 @@ impl MetadataBlob { crate fn new(metadata_ref: MetadataRef) -> MetadataBlob { - MetadataBlob(metadata_ref) + MetadataBlob(Lrc::new(metadata_ref)) } crate fn is_compatible(&self) -> bool { - self.raw_bytes().starts_with(METADATA_HEADER) + self.blob().starts_with(METADATA_HEADER) } crate fn get_rustc_version(&self) -> String { @@ -597,7 +645,7 @@ } crate fn get_root(&self) -> CrateRoot<'tcx> { - let slice = self.raw_bytes(); + let slice = &self.blob()[..]; let offset = METADATA_HEADER.len(); let pos = (((slice[offset + 0] as u32) << 24) | ((slice[offset + 1] as u32) << 16) @@ -1005,24 +1053,28 @@ } /// Iterates over the diagnostic items in the given crate. - fn get_diagnostic_items(&self) -> FxHashMap { + fn get_diagnostic_items(&self) -> DiagnosticItems { if self.root.is_proc_macro_crate() { // Proc macro crates do not export any diagnostic-items to the target. Default::default() } else { - self.root + let mut id_to_name = FxHashMap::default(); + let name_to_id = self + .root .diagnostic_items .decode(self) - .map(|(name, def_index)| (name, self.local_def_id(def_index))) - .collect() + .map(|(name, def_index)| { + let id = self.local_def_id(def_index); + id_to_name.insert(id, name); + (name, id) + }) + .collect(); + DiagnosticItems { id_to_name, name_to_id } } } /// Iterates over each child of the given item. - fn each_child_of_item(&self, id: DefIndex, mut callback: F, sess: &Session) - where - F: FnMut(Export), - { + fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) { if let Some(data) = &self.root.proc_macro_data { /* If we are loading as a proc macro, we want to return the view of this crate * as a proc macro crate. @@ -1198,14 +1250,14 @@ .decode((self, tcx)) } - fn get_mir_abstract_const( + fn get_thir_abstract_const( &self, tcx: TyCtxt<'tcx>, id: DefIndex, - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { self.root .tables - .mir_abstract_consts + .thir_abstract_consts .get(self, id) .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) } @@ -1553,58 +1605,6 @@ .or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self)) } - /// Finds the corresponding `DefId` for the provided `DefPathHash`, if it exists. - /// This is used by incremental compilation to map a serialized `DefPathHash` to - /// its `DefId` in the current session. - /// Normally, only one 'main' crate will change between incremental compilation sessions: - /// all dependencies will be completely unchanged. In this case, we can avoid - /// decoding every `DefPathHash` in the crate, since the `DefIndex` from the previous - /// session will still be valid. If our 'guess' is wrong (the `DefIndex` no longer exists, - /// or has a different `DefPathHash`, then we need to decode all `DefPathHashes` to determine - /// the correct mapping). - fn def_path_hash_to_def_id( - &self, - krate: CrateNum, - index_guess: u32, - hash: DefPathHash, - ) -> Option { - let def_index_guess = DefIndex::from_u32(index_guess); - let old_hash = self - .root - .tables - .def_path_hashes - .get(self, def_index_guess) - .map(|lazy| lazy.decode(self)); - - // Fast path: the definition and its index is unchanged from the - // previous compilation session. There is no need to decode anything - // else - if old_hash == Some(hash) { - return Some(DefId { krate, index: def_index_guess }); - } - - let is_proc_macro = self.is_proc_macro_crate(); - - // Slow path: We need to find out the new `DefIndex` of the provided - // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash` - // stored in this crate. - let map = self.cdata.def_path_hash_map.get_or_init(|| { - let end_id = self.root.tables.def_path_hashes.size() as u32; - let mut map = UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default()); - for i in 0..end_id { - let def_index = DefIndex::from_u32(i); - // There may be gaps in the encoded table if we're decoding a proc-macro crate - if let Some(hash) = self.root.tables.def_path_hashes.get(self, def_index) { - map.insert(hash.decode(self), def_index); - } else if !is_proc_macro { - panic!("Missing def_path_hashes entry for {:?}", def_index); - } - } - map - }); - map.get(&hash).map(|index| DefId { krate, index: *index }) - } - // Returns the path leading to the thing with this `id`. fn def_path(&self, id: DefIndex) -> DefPath { debug!("def_path(cnum={:?}, id={:?})", self.cnum, id); @@ -1627,7 +1627,12 @@ self.def_path_hash_unlocked(index, &mut def_path_hashes) } - fn expn_hash_to_expn_id(&self, index_guess: u32, hash: ExpnHash) -> ExpnId { + #[inline] + fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> DefIndex { + self.def_path_hash_map.def_path_hash_to_def_index(&hash) + } + + fn expn_hash_to_expn_id(&self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId { debug_assert_eq!(ExpnId::from_hash(hash), None); let index_guess = ExpnIndex::from_u32(index_guess); let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self)); @@ -1649,8 +1654,6 @@ let i = ExpnIndex::from_u32(i); if let Some(hash) = self.root.expn_hashes.get(self, i) { map.insert(hash.decode(self), i); - } else { - panic!("Missing expn_hash entry for {:?}", i); } } map @@ -1658,7 +1661,7 @@ map[&hash] }; - let data = self.root.expn_data.get(self, index).unwrap().decode(self); + let data = self.root.expn_data.get(self, index).unwrap().decode((self, sess)); rustc_span::hygiene::register_expn_id(self.cnum, index, data, hash) } @@ -1893,13 +1896,18 @@ let alloc_decoding_state = AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect()); let dependencies = Lock::new(cnum_map.iter().cloned().collect()); + + // Pre-decode the DefPathHash->DefIndex table. This is a cheap operation + // that does not copy any data. It just does some data verification. + let def_path_hash_map = root.def_path_hash_map.decode(&blob); + CrateMetadata { blob, root, trait_impls, raw_proc_macros, source_map_import_info: OnceCell::new(), - def_path_hash_map: Default::default(), + def_path_hash_map, expn_hash_map: Default::default(), alloc_decoding_state, cnum, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,58 @@ +use crate::rmeta::DecodeContext; +use crate::rmeta::EncodeContext; +use crate::rmeta::MetadataBlob; +use rustc_data_structures::owning_ref::OwningRef; +use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap}; +use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; +use rustc_span::def_id::{DefIndex, DefPathHash}; + +crate enum DefPathHashMapRef<'tcx> { + OwnedFromMetadata(odht::HashTable>), + BorrowedFromTcx(&'tcx DefPathHashMap), +} + +impl DefPathHashMapRef<'tcx> { + #[inline] + pub fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex { + match *self { + DefPathHashMapRef::OwnedFromMetadata(ref map) => map.get(def_path_hash).unwrap(), + DefPathHashMapRef::BorrowedFromTcx(_) => { + panic!("DefPathHashMap::BorrowedFromTcx variant only exists for serialization") + } + } + } +} + +impl<'a, 'tcx> Encodable> for DefPathHashMapRef<'tcx> { + fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + match *self { + DefPathHashMapRef::BorrowedFromTcx(def_path_hash_map) => { + let bytes = def_path_hash_map.raw_bytes(); + e.emit_usize(bytes.len())?; + e.emit_raw_bytes(bytes) + } + DefPathHashMapRef::OwnedFromMetadata(_) => { + panic!("DefPathHashMap::OwnedFromMetadata variant only exists for deserialization") + } + } + } +} + +impl<'a, 'tcx> Decodable> for DefPathHashMapRef<'static> { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result, String> { + // Import TyDecoder so we can access the DecodeContext::position() method + use crate::rustc_middle::ty::codec::TyDecoder; + + let len = d.read_usize()?; + let pos = d.position(); + let o = OwningRef::new(d.blob().clone()).map(|x| &x[pos..pos + len]); + + // Although we already have the data we need via the OwningRef, we still need + // to advance the DecodeContext's position so it's in a valid state after + // the method. We use read_raw_bytes() for that. + let _ = d.read_raw_bytes(len); + + let inner = odht::HashTable::from_raw_bytes(o).map_err(|e| format!("{}", e))?; + Ok(DefPathHashMapRef::OwnedFromMetadata(inner)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/encoder.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/encoder.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/encoder.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/encoder.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,4 @@ +use crate::rmeta::def_path_hash_map::DefPathHashMapRef; use crate::rmeta::table::{FixedSizeEncoding, TableBuilder}; use crate::rmeta::*; @@ -17,17 +18,18 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_index::vec::Idx; use rustc_middle::hir::map::Map; -use rustc_middle::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportLevel, }; use rustc_middle::mir::interpret; +use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder}; use rustc_session::config::CrateType; +use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use rustc_span::{ @@ -344,7 +346,7 @@ } } -impl<'a, 'tcx> Encodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Encodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { (**self).encode(s) } @@ -438,8 +440,7 @@ } fn encode_info_for_items(&mut self) { - let krate = self.tcx.hir().krate(); - self.encode_info_for_mod(CRATE_DEF_ID, krate.module()); + self.encode_info_for_mod(CRATE_DEF_ID, self.tcx.hir().root_module()); // Proc-macro crates only export proc-macro items, which are looked // up using `proc_macro_data` @@ -447,7 +448,7 @@ return; } - krate.visit_all_item_likes(&mut self.as_deep_visitor()); + self.tcx.hir().visit_all_item_likes(&mut self.as_deep_visitor()); } fn encode_def_path_table(&mut self) { @@ -471,6 +472,12 @@ } } + fn encode_def_path_hash_map(&mut self) -> Lazy> { + self.lazy(DefPathHashMapRef::BorrowedFromTcx( + self.tcx.resolutions(()).definitions.def_path_hash_to_def_index_map(), + )) + } + fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> { let source_map = self.tcx.sess.source_map(); let all_source_files = source_map.files(); @@ -674,6 +681,10 @@ let (syntax_contexts, expn_data, expn_hashes) = self.encode_hygiene(); let hygiene_bytes = self.position() - i; + i = self.position(); + let def_path_hash_map = self.encode_def_path_hash_map(); + let def_path_hash_map_bytes = self.position() - i; + // Encode source_map. This needs to be done last, // since encoding `Span`s tells us which `SourceFiles` we actually // need to encode. @@ -691,6 +702,7 @@ hash: tcx.crate_hash(LOCAL_CRATE), stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), panic_strategy: tcx.sess.panic_strategy(), + panic_in_drop_strategy: tcx.sess.opts.debugging_opts.panic_in_drop, edition: tcx.sess.edition(), has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), @@ -720,6 +732,7 @@ syntax_contexts, expn_data, expn_hashes, + def_path_hash_map, }); let total_bytes = self.position(); @@ -742,6 +755,7 @@ eprintln!(" impl bytes: {}", impl_bytes); eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes); eprintln!(" def-path table bytes: {}", def_path_table_bytes); + eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes); eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes); eprintln!(" mir bytes: {}", mir_bytes); eprintln!(" item bytes: {}", item_bytes); @@ -1065,14 +1079,7 @@ // items - we encode information about proc-macros later on. let reexports = if !self.is_proc_macro { match tcx.module_exports(local_def_id) { - Some(exports) => { - let hir = self.tcx.hir(); - self.lazy( - exports - .iter() - .map(|export| export.map_id(|id| hir.local_def_id_to_hir_id(id))), - ) - } + Some(exports) => self.lazy(exports), _ => Lazy::empty(), } } else { @@ -1304,14 +1311,17 @@ if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id)); - let abstract_const = self.tcx.mir_abstract_const(def_id); + // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir` + let abstract_const = self.tcx.thir_abstract_const(def_id); if let Ok(Some(abstract_const)) = abstract_const { - record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const); + record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const); } } record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id)); - let unused = self.tcx.unused_generic_params(def_id); + let instance = + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())); + let unused = self.tcx.unused_generic_params(instance); if !unused.is_empty() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } @@ -1699,9 +1709,10 @@ fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> { empty_proc_macro!(self); - let crates = self.tcx.crates(()); - let mut deps = crates + let deps = self + .tcx + .crates(()) .iter() .map(|&cnum| { let dep = CrateDep { @@ -1715,8 +1726,6 @@ }) .collect::>(); - deps.sort_by_key(|&(cnum, _)| cnum); - { // Sanity-check the crate numbers let mut expected_cnum = 1; @@ -1743,7 +1752,7 @@ fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { empty_proc_macro!(self); let tcx = self.tcx; - let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE); + let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id; self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } @@ -1774,7 +1783,7 @@ debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() }; - tcx.hir().krate().visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes(&mut visitor); let mut all_impls: Vec<_> = visitor.impls.into_iter().collect(); @@ -2093,7 +2102,26 @@ // will allow us to slice the metadata to the precise length that we just // generated regardless of trailing bytes that end up in it. -pub(super) fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { +#[derive(Encodable, Decodable)] +pub struct EncodedMetadata { + raw_data: Vec, +} + +impl EncodedMetadata { + #[inline] + pub fn new() -> EncodedMetadata { + EncodedMetadata { raw_data: Vec::new() } + } + + #[inline] + pub fn raw_data(&self) -> &[u8] { + &self.raw_data[..] + } +} + +pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { + let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata"); + // Since encoding metadata is not in a query, and nothing is cached, // there's no need to do dep-graph tracking for any of it. tcx.dep_graph.assert_ignored(); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,5 @@ use decoder::Metadata; +use def_path_hash_map::DefPathHashMapRef; use table::{Table, TableBuilder}; use rustc_ast::{self as ast, MacroDef}; @@ -12,12 +13,13 @@ use rustc_hir::lang_items; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; +use rustc_middle::thir; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; +use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::symbol::{Ident, Symbol}; @@ -31,9 +33,11 @@ pub use decoder::{provide, provide_extern}; crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; use encoder::EncodeContext; +pub use encoder::{encode_metadata, EncodedMetadata}; use rustc_span::hygiene::SyntaxContextData; mod decoder; +mod def_path_hash_map; mod encoder; mod table; @@ -204,6 +208,7 @@ hash: Svh, stable_crate_id: StableCrateId, panic_strategy: PanicStrategy, + panic_in_drop_strategy: PanicStrategy, edition: Edition, has_global_allocator: bool, has_panic_handler: bool, @@ -229,6 +234,8 @@ expn_data: ExpnDataTable, expn_hashes: ExpnHashTable, + def_path_hash_map: Lazy>, + source_map: Lazy<[rustc_span::SourceFile]>, compiler_builtins: bool, @@ -305,7 +312,7 @@ mir: Table)>, mir_for_ctfe: Table)>, promoted_mir: Table>)>, - mir_abstract_consts: Table])>, + thir_abstract_consts: Table])>, const_defaults: Table>>, unused_generic_params: Table>>, // `def_keys` and `def_path_hashes` represent a lazy version of a @@ -359,7 +366,7 @@ #[derive(MetadataEncodable, MetadataDecodable)] struct ModData { - reexports: Lazy<[Export]>, + reexports: Lazy<[Export]>, expansion: ExpnId, } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/table.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/table.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/table.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_metadata/src/rmeta/table.rs 2021-11-29 19:27:11.000000000 +0000 @@ -199,7 +199,7 @@ debug!("Table::lookup: index={:?} len={:?}", i, self.meta); let start = self.position.get(); - let bytes = &metadata.raw_bytes()[start..start + self.meta]; + let bytes = &metadata.blob()[start..start + self.meta]; >::maybe_read_from_bytes_at(bytes, i.index())? } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_middle" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false @@ -9,6 +9,8 @@ [dependencies] rustc_arena = { path = "../rustc_arena" } bitflags = "1.2.1" +either = "1.5.0" +gsgdt = "0.1.2" tracing = "0.1" rustc-rayon-core = "0.3.1" polonius-engine = "0.13.0" @@ -21,6 +23,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_query_system = { path = "../rustc_query_system" } rustc_errors = { path = "../rustc_errors" } +rustc_graphviz = { path = "../rustc_graphviz" } rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } @@ -29,3 +32,5 @@ smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } rustc_session = { path = "../rustc_session" } rustc_type_ir = { path = "../rustc_type_ir" } +rand = "0.8.4" +rand_xoshiro = "0.6.0" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/arena.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/arena.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/arena.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/arena.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,8 @@ macro_rules! arena_types { ($macro:path, $tcx:lifetime) => ( $macro!([ - [] layouts: rustc_target::abi::Layout, + [] layout: rustc_target::abi::Layout, + [] fn_abi: rustc_target::abi::call::FnAbi<$tcx, rustc_middle::ty::Ty<$tcx>>, // AdtDef are interned and compared by address [] adt_def: rustc_middle::ty::AdtDef, [] steal_thir: rustc_data_structures::steal::Steal>, @@ -78,8 +79,8 @@ >, [few] all_traits: Vec, [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, - [few] foreign_module: rustc_middle::middle::cstore::ForeignModule, - [few] foreign_modules: Vec, + [few] foreign_module: rustc_session::cstore::ForeignModule, + [few] foreign_modules: Vec, [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap, [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/dep_graph/dep_node.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/dep_graph/dep_node.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/dep_graph/dep_node.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/dep_graph/dep_node.rs 2021-11-29 19:27:11.000000000 +0000 @@ -63,6 +63,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::DefPathHash; use rustc_hir::HirId; +use rustc_query_system::dep_graph::FingerprintStyle; use rustc_span::symbol::Symbol; use std::hash::Hash; @@ -89,9 +90,9 @@ /// Whether the query key can be recovered from the hashed fingerprint. /// See [DepNodeParams] trait for the behaviour of each key type. - // FIXME: Make this a simple boolean once DepNodeParams::can_reconstruct_query_key + // FIXME: Make this a simple boolean once DepNodeParams::fingerprint_style // can be made a specialized associated const. - can_reconstruct_query_key: fn() -> bool, + fingerprint_style: fn() -> FingerprintStyle, } impl std::ops::Deref for DepKind { @@ -103,14 +104,14 @@ impl DepKind { #[inline(always)] - pub fn can_reconstruct_query_key(&self) -> bool { + pub fn fingerprint_style(&self) -> FingerprintStyle { // Only fetch the DepKindStruct once. let data: &DepKindStruct = &**self; if data.is_anon { - return false; + return FingerprintStyle::Opaque; } - (data.can_reconstruct_query_key)() + (data.fingerprint_style)() } } @@ -140,17 +141,18 @@ } macro_rules! contains_anon_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false}); + ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false}); } macro_rules! contains_eval_always_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); + ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_eval_always_attr!($attr) | )* false}); } #[allow(non_upper_case_globals)] pub mod dep_kind { use super::*; use crate::ty::query::query_keys; + use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. pub const Null: DepKindStruct = DepKindStruct { @@ -158,7 +160,7 @@ is_anon: false, is_eval_always: false, - can_reconstruct_query_key: || true, + fingerprint_style: || FingerprintStyle::Unit, }; pub const TraitSelect: DepKindStruct = DepKindStruct { @@ -166,7 +168,7 @@ is_anon: true, is_eval_always: false, - can_reconstruct_query_key: || true, + fingerprint_style: || FingerprintStyle::Unit, }; pub const CompileCodegenUnit: DepKindStruct = DepKindStruct { @@ -174,7 +176,7 @@ is_anon: false, is_eval_always: false, - can_reconstruct_query_key: || false, + fingerprint_style: || FingerprintStyle::Opaque, }; pub const CompileMonoItem: DepKindStruct = DepKindStruct { @@ -182,7 +184,7 @@ is_anon: false, is_eval_always: false, - can_reconstruct_query_key: || false, + fingerprint_style: || FingerprintStyle::Opaque, }; macro_rules! define_query_dep_kinds { @@ -196,16 +198,16 @@ const is_eval_always: bool = contains_eval_always_attr!($($attrs)*); #[inline(always)] - fn can_reconstruct_query_key() -> bool { + fn fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle { as DepNodeParams>> - ::can_reconstruct_query_key() + ::fingerprint_style() } DepKindStruct { has_params, is_anon, is_eval_always, - can_reconstruct_query_key, + fingerprint_style, } };)* ); @@ -320,7 +322,7 @@ /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { - debug_assert!(kind.can_reconstruct_query_key() && kind.has_params); + debug_assert!(kind.fingerprint_style() == FingerprintStyle::DefPathHash); DepNode { kind, hash: def_path_hash.0.into() } } @@ -335,8 +337,12 @@ /// refers to something from the previous compilation session that /// has been removed. fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option { - if self.kind.can_reconstruct_query_key() { - tcx.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())) + if self.kind.fingerprint_style() == FingerprintStyle::DefPathHash { + Some( + tcx.on_disk_cache + .as_ref()? + .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())), + ) } else { None } @@ -346,14 +352,16 @@ fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result { let kind = dep_kind_from_label_string(label)?; - if !kind.can_reconstruct_query_key() { - return Err(()); - } - - if kind.has_params { - Ok(DepNode::from_def_path_hash(def_path_hash, kind)) - } else { - Ok(DepNode::new_no_params(kind)) + match kind.fingerprint_style() { + FingerprintStyle::Opaque => Err(()), + FingerprintStyle::Unit => { + if !kind.has_params { + Ok(DepNode::new_no_params(kind)) + } else { + Err(()) + } + } + FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)), } } @@ -365,8 +373,8 @@ impl<'tcx> DepNodeParams> for () { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - true + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::Unit } fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { @@ -380,22 +388,12 @@ impl<'tcx> DepNodeParams> for DefId { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - true + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::DefPathHash } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { - let hash = tcx.def_path_hash(*self); - // If this is a foreign `DefId`, store its current value - // in the incremental cache. When we decode the cache, - // we will use the old DefIndex as an initial guess for - // a lookup into the crate metadata. - if !self.is_local() { - if let Some(cache) = &tcx.on_disk_cache { - cache.store_foreign_def_id_hash(*self, hash); - } - } - hash.0 + tcx.def_path_hash(*self).0 } fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { @@ -409,8 +407,8 @@ impl<'tcx> DepNodeParams> for LocalDefId { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - true + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::DefPathHash } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { @@ -428,8 +426,8 @@ impl<'tcx> DepNodeParams> for CrateNum { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - true + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::DefPathHash } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { @@ -448,8 +446,8 @@ impl<'tcx> DepNodeParams> for (DefId, DefId) { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - false + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::Opaque } // We actually would not need to specialize the implementation of this @@ -473,8 +471,8 @@ impl<'tcx> DepNodeParams> for HirId { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - false + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::Opaque } // We actually would not need to specialize the implementation of this diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/dep_graph/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/dep_graph/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/dep_graph/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/dep_graph/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ -use crate::ich::StableHashingContext; use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; +use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; #[macro_use] @@ -25,8 +25,8 @@ const NULL: Self = DepKind::Null; #[inline(always)] - fn can_reconstruct_query_key(&self) -> bool { - DepKind::can_reconstruct_query_key(self) + fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle { + DepKind::fingerprint_style(self) } #[inline(always)] @@ -90,15 +90,9 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { type DepKind = DepKind; - type StableHashingContext = StableHashingContext<'tcx>; - fn register_reused_dep_node(&self, dep_node: &DepNode) { - if let Some(cache) = self.on_disk_cache.as_ref() { - cache.register_reused_dep_node(*self, dep_node) - } - } - - fn create_stable_hashing_context(&self) -> Self::StableHashingContext { + #[inline] + fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { TyCtxt::create_stable_hashing_context(*self) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/hir/exports.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/hir/exports.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/hir/exports.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/hir/exports.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,23 +11,18 @@ /// This is the replacement export map. It maps a module to all of the exports /// within. -pub type ExportMap = FxHashMap>>; +pub type ExportMap = FxHashMap>; #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct Export { +pub struct Export { /// The name of the target. pub ident: Ident, /// The resolution of the target. - pub res: Res, + /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter. + pub res: Res, /// The span of the target. pub span: Span, /// The visibility of the export. /// We include non-`pub` exports for hygienic macros that get used from extern crates. pub vis: ty::Visibility, } - -impl Export { - pub fn map_id(self, map: impl FnMut(Id) -> R) -> Export { - Export { ident: self.ident, res: self.res.map_id(map), span: self.span, vis: self.vis } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/hir/map/collector.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/hir/map/collector.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/hir/map/collector.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/hir/map/collector.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ use crate::arena::Arena; use crate::hir::map::Map; use crate::hir::{IndexedHir, OwnerNodes, ParentedNode}; -use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -12,6 +11,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::*; use rustc_index::vec::{Idx, IndexVec}; +use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::{Span, DUMMY_SP}; @@ -62,13 +62,6 @@ stable_hasher.finish() } -/// Represents an entry and its parent `HirId`. -#[derive(Copy, Clone, Debug)] -pub struct Entry<'hir> { - parent: HirId, - node: Node<'hir>, -} - impl<'a, 'hir> NodeCollector<'a, 'hir> { pub(super) fn root( sess: &'a Session, @@ -420,18 +413,18 @@ self.visit_nested_trait_item(id); } - fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef<'hir>) { + fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) { // Do not visit the duplicate information in ImplItemRef. We want to // map the actual nodes, not the duplicate ones in the *Ref. - let ImplItemRef { id, ident: _, kind: _, span: _, vis: _, defaultness: _ } = *ii; + let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii; self.visit_nested_impl_item(id); } - fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef<'hir>) { + fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) { // Do not visit the duplicate information in ForeignItemRef. We want to // map the actual nodes, not the duplicate ones in the *Ref. - let ForeignItemRef { id, ident: _, span: _, vis: _ } = *fi; + let ForeignItemRef { id, ident: _, span: _ } = *fi; self.visit_nested_foreign_item(id); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/hir/map/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/hir/map/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/hir/map/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/hir/map/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,15 +1,16 @@ use self::collector::NodeCollector; -use crate::hir::{AttributeMap, IndexedHir, Owner}; +use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner}; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; +use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; -use rustc_hir::intravisit; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::*; use rustc_index::vec::Idx; @@ -19,6 +20,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::spec::abi::Abi; +use std::collections::VecDeque; pub mod blocks; mod collector; @@ -82,12 +84,12 @@ /// An iterator that walks up the ancestor tree of a given `HirId`. /// Constructed using `tcx.hir().parent_iter(hir_id)`. -pub struct ParentHirIterator<'map, 'hir> { +pub struct ParentHirIterator<'hir> { current_id: HirId, - map: &'map Map<'hir>, + map: Map<'hir>, } -impl<'hir> Iterator for ParentHirIterator<'_, 'hir> { +impl<'hir> Iterator for ParentHirIterator<'hir> { type Item = (HirId, Node<'hir>); fn next(&mut self) -> Option { @@ -114,12 +116,12 @@ /// An iterator that walks up the ancestor tree of a given `HirId`. /// Constructed using `tcx.hir().parent_owner_iter(hir_id)`. -pub struct ParentOwnerIterator<'map, 'hir> { +pub struct ParentOwnerIterator<'hir> { current_id: HirId, - map: &'map Map<'hir>, + map: Map<'hir>, } -impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> { +impl<'hir> Iterator for ParentOwnerIterator<'hir> { type Item = (HirId, OwnerNode<'hir>); fn next(&mut self) -> Option { @@ -155,6 +157,21 @@ self.tcx.hir_crate(()) } + pub fn root_module(&self) -> &'hir Mod<'hir> { + match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) { + Some(OwnerNode::Crate(item)) => item, + _ => bug!(), + } + } + + pub fn items(&self) -> impl Iterator> + 'hir { + let krate = self.krate(); + krate.owners.iter().filter_map(|owner| match owner.as_ref()? { + OwnerNode::Item(item) => Some(*item), + _ => None, + }) + } + pub fn def_key(&self, def_id: LocalDefId) -> DefKey { // Accessing the DefKey is ok, since it is part of DefPathHash. self.tcx.untracked_resolutions.definitions.def_key(def_id) @@ -206,11 +223,6 @@ } pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option { - // FIXME(eddyb) support `find` on the crate root. - if local_def_id.to_def_id().index == CRATE_DEF_INDEX { - return Some(DefKind::Mod); - } - let hir_id = self.local_def_id_to_hir_id(local_def_id); let def_kind = match self.find(hir_id)? { Node::Item(item) => match item.kind { @@ -479,6 +491,17 @@ Some(ccx) } + /// Returns an iterator of the `DefId`s for all body-owners in this + /// crate. If you would prefer to iterate over the bodies + /// themselves, you can do `self.hir().krate().body_ids.iter()`. + pub fn body_owners(self) -> impl Iterator + 'hir { + self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id)) + } + + pub fn par_body_owners(self, f: F) { + par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id))); + } + pub fn ty_param_owner(&self, id: HirId) -> HirId { match self.get(id) { Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => id, @@ -519,38 +542,125 @@ } } + /// Walks the contents of a crate. See also `Crate::visit_all_items`. + pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) { + let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID); + visitor.visit_mod(top_mod, span, hir_id); + } + + /// Walks the attributes in a crate. + pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) { + let krate = self.krate(); + for (&id, attrs) in krate.attrs.iter() { + for a in *attrs { + visitor.visit_attribute(id, a) + } + } + } + + /// Visits all items in the crate in some deterministic (but + /// unspecified) order. If you just need to process every item, + /// but don't care about nesting, this method is the best choice. + /// + /// If you do care about nesting -- usually because your algorithm + /// follows lexical scoping rules -- then you want a different + /// approach. You should override `visit_nested_item` in your + /// visitor and then call `intravisit::walk_crate` instead. + pub fn visit_all_item_likes(&self, visitor: &mut V) + where + V: itemlikevisit::ItemLikeVisitor<'hir>, + { + let krate = self.krate(); + for owner in krate.owners.iter().filter_map(Option::as_ref) { + match owner { + OwnerNode::Item(item) => visitor.visit_item(item), + OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), + OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), + OwnerNode::TraitItem(item) => visitor.visit_trait_item(item), + OwnerNode::Crate(_) => {} + } + } + } + + /// A parallel version of `visit_all_item_likes`. + pub fn par_visit_all_item_likes(&self, visitor: &V) + where + V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, + { + let krate = self.krate(); + par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() { + Some(OwnerNode::Item(item)) => visitor.visit_item(item), + Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), + Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), + Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item), + Some(OwnerNode::Crate(_)) | None => {} + }) + } + pub fn visit_item_likes_in_module(&self, module: LocalDefId, visitor: &mut V) where V: ItemLikeVisitor<'hir>, { let module = self.tcx.hir_module_items(module); - for id in &module.items { + for id in module.items.iter() { visitor.visit_item(self.item(*id)); } - for id in &module.trait_items { + for id in module.trait_items.iter() { visitor.visit_trait_item(self.trait_item(*id)); } - for id in &module.impl_items { + for id in module.impl_items.iter() { visitor.visit_impl_item(self.impl_item(*id)); } - for id in &module.foreign_items { + for id in module.foreign_items.iter() { visitor.visit_foreign_item(self.foreign_item(*id)); } } + pub fn for_each_module(&self, f: impl Fn(LocalDefId)) { + let mut queue = VecDeque::new(); + queue.push_back(CRATE_DEF_ID); + + while let Some(id) = queue.pop_front() { + f(id); + let items = self.tcx.hir_module_items(id); + queue.extend(items.submodules.iter().copied()) + } + } + + #[cfg(not(parallel_compiler))] + #[inline] + pub fn par_for_each_module(&self, f: impl Fn(LocalDefId)) { + self.for_each_module(f) + } + + #[cfg(parallel_compiler)] + pub fn par_for_each_module(&self, f: impl Fn(LocalDefId) + Sync) { + use rustc_data_structures::sync::{par_iter, ParallelIterator}; + par_iter_submodules(self.tcx, CRATE_DEF_ID, &f); + + fn par_iter_submodules(tcx: TyCtxt<'_>, module: LocalDefId, f: &F) + where + F: Fn(LocalDefId) + Sync, + { + (*f)(module); + let items = tcx.hir_module_items(module); + par_iter(&items.submodules[..]).for_each(|&sm| par_iter_submodules(tcx, sm, f)); + } + } + /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. - pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> { + pub fn parent_iter(self, current_id: HirId) -> ParentHirIterator<'hir> { ParentHirIterator { current_id, map: self } } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. - pub fn parent_owner_iter(&self, current_id: HirId) -> ParentOwnerIterator<'_, 'hir> { + pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> { ParentOwnerIterator { current_id, map: self } } @@ -934,7 +1044,8 @@ &tcx.untracked_resolutions.definitions, hcx, ); - intravisit::walk_crate(&mut collector, tcx.untracked_crate); + let top_mod = tcx.untracked_crate.module(); + collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID); let map = collector.finalize_and_compute_crate_hash(); tcx.arena.alloc(map) @@ -952,22 +1063,12 @@ .iter_enumerated() .filter_map(|(def_id, hod)| { let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id); - let mut hasher = StableHasher::new(); - hod.as_ref()?.hash_stable(&mut hcx, &mut hasher); - AttributeMap { map: &tcx.untracked_crate.attrs, prefix: def_id } - .hash_stable(&mut hcx, &mut hasher); - Some((def_path_hash, hasher.finish())) + let hash = hod.as_ref()?.hash; + Some((def_path_hash, hash, def_id)) }) .collect(); hir_body_nodes.sort_unstable_by_key(|bn| bn.0); - let node_hashes = hir_body_nodes.iter().fold( - Fingerprint::ZERO, - |combined_fingerprint, &(def_path_hash, fingerprint)| { - combined_fingerprint.combine(def_path_hash.0.combine(fingerprint)) - }, - ); - let upstream_crates = upstream_crates(tcx); // We hash the final, remapped names of all local source files so we @@ -987,7 +1088,17 @@ source_file_names.sort_unstable(); let mut stable_hasher = StableHasher::new(); - node_hashes.hash_stable(&mut hcx, &mut stable_hasher); + for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() { + def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher); + fingerprint.hash_stable(&mut hcx, &mut stable_hasher); + AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id } + .hash_stable(&mut hcx, &mut stable_hasher); + if tcx.sess.opts.debugging_opts.incremental_relative_spans { + let span = tcx.untracked_resolutions.definitions.def_span(*def_id); + debug_assert_eq!(span.parent(), None); + span.hash_stable(&mut hcx, &mut stable_hasher); + } + } upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); @@ -1101,3 +1212,69 @@ None => format!("unknown node{}", id_str), } } + +pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems { + let mut collector = ModuleCollector { + tcx, + submodules: Vec::default(), + items: Vec::default(), + trait_items: Vec::default(), + impl_items: Vec::default(), + foreign_items: Vec::default(), + }; + + let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id); + collector.visit_mod(hir_mod, span, hir_id); + + let ModuleCollector { submodules, items, trait_items, impl_items, foreign_items, .. } = + collector; + return ModuleItems { + submodules: submodules.into_boxed_slice(), + items: items.into_boxed_slice(), + trait_items: trait_items.into_boxed_slice(), + impl_items: impl_items.into_boxed_slice(), + foreign_items: foreign_items.into_boxed_slice(), + }; + + struct ModuleCollector<'tcx> { + tcx: TyCtxt<'tcx>, + submodules: Vec, + items: Vec, + trait_items: Vec, + impl_items: Vec, + foreign_items: Vec, + } + + impl<'hir> Visitor<'hir> for ModuleCollector<'hir> { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::All(self.tcx.hir()) + } + + fn visit_item(&mut self, item: &'hir Item<'hir>) { + self.items.push(item.item_id()); + if let ItemKind::Mod(..) = item.kind { + // If this declares another module, do not recurse inside it. + self.submodules.push(item.def_id); + } else { + intravisit::walk_item(self, item) + } + } + + fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { + self.trait_items.push(item.trait_item_id()); + intravisit::walk_trait_item(self, item) + } + + fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { + self.impl_items.push(item.impl_item_id()); + intravisit::walk_impl_item(self, item) + } + + fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) { + self.foreign_items.push(item.foreign_item_id()); + intravisit::walk_foreign_item(self, item) + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/hir/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/hir/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/hir/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/hir/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,6 @@ pub mod map; pub mod place; -use crate::ich::StableHashingContext; use crate::ty::query::Providers; use crate::ty::TyCtxt; use rustc_ast::Attribute; @@ -16,6 +15,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::*; use rustc_index::vec::{Idx, IndexVec}; +use rustc_query_system::ich::StableHashingContext; use rustc_span::DUMMY_SP; use std::collections::BTreeMap; @@ -121,6 +121,17 @@ } } +/// Gather the LocalDefId for each item-like within a module, including items contained within +/// bodies. The Ids are in visitor order. This is used to partition a pass between modules. +#[derive(Debug, HashStable)] +pub struct ModuleItems { + submodules: Box<[LocalDefId]>, + items: Box<[ItemId]>, + trait_items: Box<[TraitItemId]>, + impl_items: Box<[ImplItemId]>, + foreign_items: Box<[ForeignItemId]>, +} + impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn hir(self) -> map::Map<'tcx> { @@ -140,7 +151,7 @@ providers.hir_crate = |tcx, ()| tcx.untracked_crate; providers.index_hir = map::index_hir; providers.crate_hash = map::crate_hash; - providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id]; + providers.hir_module_items = map::hir_module_items; providers.hir_owner = |tcx, id| { let owner = tcx.index_hir(()).map[id].as_ref()?; let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; @@ -153,6 +164,7 @@ index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) }; providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id }; + providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { let hir = tcx.hir(); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/hcx.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/hcx.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/hcx.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/hcx.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,276 +0,0 @@ -use crate::ich; -use crate::middle::cstore::CrateStore; -use crate::ty::{fast_reject, TyCtxt}; - -use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lrc; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::definitions::{DefPathHash, Definitions}; -use rustc_session::Session; -use rustc_span::source_map::SourceMap; -use rustc_span::symbol::Symbol; -use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData}; - -use smallvec::SmallVec; -use std::cmp::Ord; - -fn compute_ignored_attr_names() -> FxHashSet { - debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty()); - ich::IGNORED_ATTRIBUTES.iter().copied().collect() -} - -/// This is the context state available during incr. comp. hashing. It contains -/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e., -/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various -/// things (e.g., each `DefId`/`DefPath` is only hashed once). -#[derive(Clone)] -pub struct StableHashingContext<'a> { - sess: &'a Session, - definitions: &'a Definitions, - cstore: &'a dyn CrateStore, - pub(super) body_resolver: BodyResolver<'a>, - hash_spans: bool, - hash_bodies: bool, - pub(super) node_id_hashing_mode: NodeIdHashingMode, - - // Very often, we are hashing something that does not need the - // `CachingSourceMapView`, so we initialize it lazily. - raw_source_map: &'a SourceMap, - caching_source_map: Option>, -} - -#[derive(PartialEq, Eq, Clone, Copy)] -pub enum NodeIdHashingMode { - Ignore, - HashDefPath, -} - -/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`. -/// We could also just store a plain reference to the `hir::Crate` but we want -/// to avoid that the crate is used to get untracked access to all of the HIR. -#[derive(Clone, Copy)] -pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>); - -impl<'tcx> BodyResolver<'tcx> { - /// Returns a reference to the `hir::Body` with the given `BodyId`. - /// **Does not do any tracking**; use carefully. - pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> { - self.0.body(id) - } -} - -impl<'a> StableHashingContext<'a> { - /// The `krate` here is only used for mapping `BodyId`s to `Body`s. - /// Don't use it for anything else or you'll run the risk of - /// leaking data out of the tracking system. - #[inline] - fn new_with_or_without_spans( - sess: &'a Session, - krate: &'a hir::Crate<'a>, - definitions: &'a Definitions, - cstore: &'a dyn CrateStore, - always_ignore_spans: bool, - ) -> Self { - let hash_spans_initial = - !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans; - - StableHashingContext { - sess, - body_resolver: BodyResolver(krate), - definitions, - cstore, - caching_source_map: None, - raw_source_map: sess.source_map(), - hash_spans: hash_spans_initial, - hash_bodies: true, - node_id_hashing_mode: NodeIdHashingMode::HashDefPath, - } - } - - #[inline] - pub fn new( - sess: &'a Session, - krate: &'a hir::Crate<'a>, - definitions: &'a Definitions, - cstore: &'a dyn CrateStore, - ) -> Self { - Self::new_with_or_without_spans( - sess, - krate, - definitions, - cstore, - /*always_ignore_spans=*/ false, - ) - } - - #[inline] - pub fn ignore_spans( - sess: &'a Session, - krate: &'a hir::Crate<'a>, - definitions: &'a Definitions, - cstore: &'a dyn CrateStore, - ) -> Self { - let always_ignore_spans = true; - Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans) - } - - #[inline] - pub fn while_hashing_hir_bodies(&mut self, hash_bodies: bool, f: F) { - let prev_hash_bodies = self.hash_bodies; - self.hash_bodies = hash_bodies; - f(self); - self.hash_bodies = prev_hash_bodies; - } - - #[inline] - pub fn while_hashing_spans(&mut self, hash_spans: bool, f: F) { - let prev_hash_spans = self.hash_spans; - self.hash_spans = hash_spans; - f(self); - self.hash_spans = prev_hash_spans; - } - - #[inline] - pub fn with_node_id_hashing_mode( - &mut self, - mode: NodeIdHashingMode, - f: F, - ) { - let prev = self.node_id_hashing_mode; - self.node_id_hashing_mode = mode; - f(self); - self.node_id_hashing_mode = prev; - } - - #[inline] - pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash { - if let Some(def_id) = def_id.as_local() { - self.local_def_path_hash(def_id) - } else { - self.cstore.def_path_hash(def_id) - } - } - - #[inline] - pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash { - self.definitions.def_path_hash(def_id) - } - - #[inline] - pub fn hash_bodies(&self) -> bool { - self.hash_bodies - } - - #[inline] - pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> { - match self.caching_source_map { - Some(ref mut sm) => sm, - ref mut none => { - *none = Some(CachingSourceMapView::new(self.raw_source_map)); - none.as_mut().unwrap() - } - } - } - - #[inline] - pub fn is_ignored_attr(&self, name: Symbol) -> bool { - thread_local! { - static IGNORED_ATTRIBUTES: FxHashSet = compute_ignored_attr_names(); - } - IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name)) - } -} - -/// Something that can provide a stable hashing context. -pub trait StableHashingContextProvider<'a> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a>; -} - -impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - (**self).get_stable_hashing_context() - } -} - -impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - (**self).get_stable_hashing_context() - } -} - -impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> { - (*self).create_stable_hashing_context() - } -} - -impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - self.clone() - } -} - -impl<'a> HashStable> for ast::NodeId { - fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { - panic!("Node IDs should not appear in incremental state"); - } -} - -impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { - fn hash_spans(&self) -> bool { - self.hash_spans - } - - #[inline] - fn def_path_hash(&self, def_id: DefId) -> DefPathHash { - self.def_path_hash(def_id) - } - - fn span_data_to_lines_and_cols( - &mut self, - span: &SpanData, - ) -> Option<(Lrc, usize, BytePos, usize, BytePos)> { - self.source_map().span_data_to_lines_and_cols(span) - } -} - -impl rustc_session::HashStableContext for StableHashingContext<'a> {} - -pub fn hash_stable_trait_impls<'a>( - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - blanket_impls: &[DefId], - non_blanket_impls: &FxHashMap>, -) { - { - let mut blanket_impls: SmallVec<[_; 8]> = - blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect(); - - if blanket_impls.len() > 1 { - blanket_impls.sort_unstable(); - } - - blanket_impls.hash_stable(hcx, hasher); - } - - { - let mut keys: SmallVec<[_; 8]> = - non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect(); - keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2)); - keys.len().hash_stable(hcx, hasher); - for (key, ref stable_key) in keys { - stable_key.hash_stable(hcx, hasher); - let mut impls: SmallVec<[_; 8]> = - non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect(); - - if impls.len() > 1 { - impls.sort_unstable(); - } - - impls.hash_stable(hcx, hasher); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_hir.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_hir.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_hir.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_hir.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -//! This module contains `HashStable` implementations for various HIR data -//! types in no particular order. - -use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use rustc_attr as attr; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use rustc_hir as hir; -use rustc_hir::definitions::DefPathHash; -use smallvec::SmallVec; -use std::mem; - -impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { - #[inline] - fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) { - let hcx = self; - match hcx.node_id_hashing_mode { - NodeIdHashingMode::Ignore => { - // Don't do anything. - } - NodeIdHashingMode::HashDefPath => { - let hir::HirId { owner, local_id } = hir_id; - - hcx.local_def_path_hash(owner).hash_stable(hcx, hasher); - local_id.hash_stable(hcx, hasher); - } - } - } - - fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) { - let hcx = self; - if hcx.hash_bodies() { - hcx.body_resolver.body(id).hash_stable(hcx, hasher); - } - } - - fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) { - let hcx = self; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - id.hash_stable(hcx, hasher); - }) - } - - fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) { - let hcx = self; - let hir::Mod { inner: ref inner_span, ref item_ids } = *module; - - inner_span.hash_stable(hcx, hasher); - - // Combining the `DefPathHash`s directly is faster than feeding them - // into the hasher. Because we use a commutative combine, we also don't - // have to sort the array. - let item_ids_hash = item_ids - .iter() - .map(|id| { - let def_path_hash = id.to_stable_hash_key(hcx); - def_path_hash.0 - }) - .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b)); - - item_ids.len().hash_stable(hcx, hasher); - item_ids_hash.hash_stable(hcx, hasher); - } - - fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) { - self.while_hashing_hir_bodies(true, |hcx| { - let hir::Expr { hir_id: _, ref span, ref kind } = *expr; - - span.hash_stable(hcx, hasher); - kind.hash_stable(hcx, hasher); - }) - } - - fn hash_hir_ty(&mut self, ty: &hir::Ty<'_>, hasher: &mut StableHasher) { - self.while_hashing_hir_bodies(true, |hcx| { - let hir::Ty { hir_id: _, ref kind, ref span } = *ty; - - kind.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); - }) - } - - fn hash_hir_visibility_kind( - &mut self, - vis: &hir::VisibilityKind<'_>, - hasher: &mut StableHasher, - ) { - let hcx = self; - mem::discriminant(vis).hash_stable(hcx, hasher); - match *vis { - hir::VisibilityKind::Public | hir::VisibilityKind::Inherited => { - // No fields to hash. - } - hir::VisibilityKind::Crate(sugar) => { - sugar.hash_stable(hcx, hasher); - } - hir::VisibilityKind::Restricted { ref path, hir_id } => { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - hir_id.hash_stable(hcx, hasher); - }); - path.hash_stable(hcx, hasher); - } - } - } - - fn hash_hir_item_like(&mut self, f: F) { - let prev_hash_node_ids = self.node_id_hashing_mode; - self.node_id_hashing_mode = NodeIdHashingMode::Ignore; - - f(self); - - self.node_id_hashing_mode = prev_hash_node_ids; - } -} - -impl<'a> ToStableHashKey> for hir::ItemLocalId { - type KeyType = hir::ItemLocalId; - - #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> hir::ItemLocalId { - *self - } -} - -impl<'a> HashStable> for hir::Body<'_> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let hir::Body { params, value, generator_kind } = self; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| { - params.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - generator_kind.hash_stable(hcx, hasher); - }); - } -} - -impl<'a> ToStableHashKey> for hir::BodyId { - type KeyType = (DefPathHash, hir::ItemLocalId); - - #[inline] - fn to_stable_hash_key( - &self, - hcx: &StableHashingContext<'a>, - ) -> (DefPathHash, hir::ItemLocalId) { - let hir::BodyId { hir_id } = *self; - hir_id.to_stable_hash_key(hcx) - } -} - -impl<'a> HashStable> for hir::TraitCandidate { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - let hir::TraitCandidate { def_id, import_ids } = self; - - def_id.hash_stable(hcx, hasher); - import_ids.hash_stable(hcx, hasher); - }); - } -} - -impl<'a> ToStableHashKey> for hir::TraitCandidate { - type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>); - - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { - let hir::TraitCandidate { def_id, import_ids } = self; - - ( - hcx.def_path_hash(*def_id), - import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(), - ) - } -} - -impl<'hir> HashStable> for attr::InlineAttr { - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - } -} - -impl<'hir> HashStable> for attr::InstructionSetAttr { - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - } -} - -impl<'hir> HashStable> for attr::OptimizeAttr { - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_syntax.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_syntax.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_syntax.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_syntax.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -//! This module contains `HashStable` implementations for various data types -//! from `rustc_ast` in no particular order. - -use crate::ich::StableHashingContext; - -use rustc_ast as ast; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_span::{BytePos, NormalizedPos, SourceFile}; -use std::assert_matches::assert_matches; - -use smallvec::SmallVec; - -impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {} - -impl<'a> HashStable> for [ast::Attribute] { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - if self.is_empty() { - self.len().hash_stable(hcx, hasher); - return; - } - - // Some attributes are always ignored during hashing. - let filtered: SmallVec<[&ast::Attribute; 8]> = self - .iter() - .filter(|attr| { - !attr.is_doc_comment() - && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)) - }) - .collect(); - - filtered.len().hash_stable(hcx, hasher); - for attr in filtered { - attr.hash_stable(hcx, hasher); - } - } -} - -impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> { - fn hash_attr(&mut self, attr: &ast::Attribute, hasher: &mut StableHasher) { - // Make sure that these have been filtered out. - debug_assert!(!attr.ident().map_or(false, |ident| self.is_ignored_attr(ident.name))); - debug_assert!(!attr.is_doc_comment()); - - let ast::Attribute { kind, id: _, style, span } = attr; - if let ast::AttrKind::Normal(item, tokens) = kind { - item.hash_stable(self, hasher); - style.hash_stable(self, hasher); - span.hash_stable(self, hasher); - assert_matches!( - tokens.as_ref(), - None, - "Tokens should have been removed during lowering!" - ); - } else { - unreachable!(); - } - } -} - -impl<'a> HashStable> for SourceFile { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let SourceFile { - name: _, // We hash the smaller name_hash instead of this - name_hash, - cnum, - // Do not hash the source as it is not encoded - src: _, - ref src_hash, - external_src: _, - start_pos, - end_pos: _, - ref lines, - ref multibyte_chars, - ref non_narrow_chars, - ref normalized_pos, - } = *self; - - (name_hash as u64).hash_stable(hcx, hasher); - - src_hash.hash_stable(hcx, hasher); - - // We only hash the relative position within this source_file - lines.len().hash_stable(hcx, hasher); - for &line in lines.iter() { - stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); - } - - // We only hash the relative position within this source_file - multibyte_chars.len().hash_stable(hcx, hasher); - for &char_pos in multibyte_chars.iter() { - stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); - } - - non_narrow_chars.len().hash_stable(hcx, hasher); - for &char_pos in non_narrow_chars.iter() { - stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); - } - - normalized_pos.len().hash_stable(hcx, hasher); - for &char_pos in normalized_pos.iter() { - stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher); - } - - cnum.hash_stable(hcx, hasher); - } -} - -fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 { - pos.0 - source_file_start.0 -} - -fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) { - let rustc_span::MultiByteChar { pos, bytes } = mbc; - - (pos.0 - source_file_start.0, bytes as u32) -} - -fn stable_non_narrow_char( - swc: rustc_span::NonNarrowChar, - source_file_start: BytePos, -) -> (u32, u32) { - let pos = swc.pos(); - let width = swc.width(); - - (pos.0 - source_file_start.0, width as u32) -} - -fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) { - let NormalizedPos { pos, diff } = np; - - (pos.0 - source_file_start.0, diff) -} - -impl<'tcx> HashStable> for rustc_feature::Features { - fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { - // Unfortunately we cannot exhaustively list fields here, since the - // struct is macro generated. - self.declared_lang_features.hash_stable(hcx, hasher); - self.declared_lib_features.hash_stable(hcx, hasher); - - self.walk_feature_fields(|feature_name, value| { - feature_name.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - }); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_ty.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_ty.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_ty.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/impls_ty.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,196 +0,0 @@ -//! This module contains `HashStable` implementations for various data types -//! from `rustc_middle::ty` in no particular order. - -use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use crate::middle::region; -use crate::mir; -use crate::ty; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use std::cell::RefCell; -use std::mem; - -impl<'a, 'tcx, T> HashStable> for &'tcx ty::List -where - T: HashStable>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - thread_local! { - static CACHE: RefCell> = - RefCell::new(Default::default()); - } - - let hash = CACHE.with(|cache| { - let key = (self.as_ptr() as usize, self.len()); - if let Some(&hash) = cache.borrow().get(&key) { - return hash; - } - - let mut hasher = StableHasher::new(); - (&self[..]).hash_stable(hcx, &mut hasher); - - let hash: Fingerprint = hasher.finish(); - cache.borrow_mut().insert(key, hash); - hash - }); - - hash.hash_stable(hcx, hasher); - } -} - -impl<'a, 'tcx, T> ToStableHashKey> for &'tcx ty::List -where - T: HashStable>, -{ - type KeyType = Fingerprint; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint { - let mut hasher = StableHasher::new(); - let mut hcx: StableHashingContext<'a> = hcx.clone(); - self.hash_stable(&mut hcx, &mut hasher); - hasher.finish() - } -} - -impl<'a, 'tcx> HashStable> for ty::subst::GenericArg<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.unpack().hash_stable(hcx, hasher); - } -} - -impl<'a> HashStable> for ty::RegionKind { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - ty::ReErased | ty::ReStatic => { - // No variant fields to hash for these ... - } - ty::ReEmpty(universe) => { - universe.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => { - db.hash_stable(hcx, hasher); - i.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name), .. }) => { - db.hash_stable(hcx, hasher); - def_id.hash_stable(hcx, hasher); - name.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv, .. }) => { - db.hash_stable(hcx, hasher); - } - ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { - def_id.hash_stable(hcx, hasher); - index.hash_stable(hcx, hasher); - name.hash_stable(hcx, hasher); - } - ty::ReFree(ref free_region) => { - free_region.hash_stable(hcx, hasher); - } - ty::ReVar(..) | ty::RePlaceholder(..) => { - bug!("StableHasher: unexpected region {:?}", *self) - } - } - } -} - -impl<'a> HashStable> for ty::RegionVid { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.index().hash_stable(hcx, hasher); - } -} - -impl<'a, 'tcx> HashStable> for ty::ConstVid<'tcx> { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.index.hash_stable(hcx, hasher); - } -} - -impl<'tcx> HashStable> for ty::BoundVar { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { - self.index().hash_stable(hcx, hasher); - } -} - -impl<'a, 'tcx, T> HashStable> for ty::Binder<'tcx, T> -where - T: HashStable>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.as_ref().skip_binder().hash_stable(hcx, hasher); - self.bound_vars().hash_stable(hcx, hasher); - } -} - -// AllocIds get resolved to whatever they point to (to be stable) -impl<'a> HashStable> for mir::interpret::AllocId { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - ty::tls::with_opt(|tcx| { - trace!("hashing {:?}", *self); - let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - tcx.get_global_alloc(*self).hash_stable(hcx, hasher); - }); - } -} - -// `Relocations` with default type parameters is a sorted map. -impl<'a, Tag> HashStable> for mir::interpret::Relocations -where - Tag: HashStable>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.len().hash_stable(hcx, hasher); - for reloc in self.iter() { - reloc.hash_stable(hcx, hasher); - } - } -} - -impl<'a> ToStableHashKey> for region::Scope { - type KeyType = region::Scope; - - #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> region::Scope { - *self - } -} - -impl<'a> HashStable> for ty::TyVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `TyVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash a TyVid {:?}.", *self) - } -} - -impl<'a> HashStable> for ty::IntVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `IntVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash an IntVid {:?}.", *self) - } -} - -impl<'a> HashStable> for ty::FloatVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `FloatVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash a FloatVid {:?}.", *self) - } -} - -impl<'a> HashStable> for crate::middle::privacy::AccessLevels { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - let crate::middle::privacy::AccessLevels { ref map } = *self; - - map.hash_stable(hcx, hasher); - }); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ich/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ich/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -//! ICH - Incremental Compilation Hash - -pub use self::hcx::{ - hash_stable_trait_impls, NodeIdHashingMode, StableHashingContext, StableHashingContextProvider, -}; -use rustc_span::symbol::{sym, Symbol}; - -mod hcx; - -mod impls_hir; -mod impls_syntax; -mod impls_ty; - -pub const IGNORED_ATTRIBUTES: &[Symbol] = &[ - sym::cfg, - sym::rustc_if_this_changed, - sym::rustc_then_this_would_need, - sym::rustc_dirty, - sym::rustc_clean, - sym::rustc_partition_reused, - sym::rustc_partition_codegened, - sym::rustc_expected_cgu_reuse, -]; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ //! - **MIR.** The "mid-level (M) intermediate representation (IR)" is //! defined in the `mir` module. This module contains only the //! *definition* of the MIR; the passes that transform and operate -//! on MIR are found in `rustc_mir` crate. +//! on MIR are found in `rustc_const_eval` crate. //! - **Types.** The internal representation of types used in rustc is //! defined in the `ty` module. This includes the **type context** //! (or `tcx`), which is the central context during most of @@ -31,7 +31,9 @@ #![feature(box_patterns)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] +#![feature(exhaustive_patterns)] #![feature(if_let_guard)] +#![feature(map_first_last)] #![feature(never_type)] #![feature(extern_types)] #![feature(new_uninit)] @@ -39,21 +41,19 @@ #![feature(once_cell)] #![feature(min_specialization)] #![feature(trusted_len)] -#![feature(test)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(half_open_range_patterns)] -#![feature(exclusive_range_pattern)] #![feature(control_flow_enum)] #![feature(associated_type_defaults)] #![feature(iter_zip)] #![feature(thread_local_const_init)] -#![feature(try_reserve)] +#![feature(trusted_step)] +#![feature(try_blocks)] #![feature(try_reserve_kind)] #![feature(nonzero_ops)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard #![recursion_limit = "512"] #[macro_use] @@ -81,7 +81,6 @@ #[macro_use] pub mod dep_graph; pub mod hir; -pub mod ich; pub mod infer; pub mod lint; pub mod middle; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/lint.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/lint.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/lint.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/lint.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ use std::cmp; -use crate::ich::StableHashingContext; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; use rustc_index::vec::IndexVec; +use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS}, FutureIncompatibilityReason, Level, Lint, LintId, @@ -192,6 +192,7 @@ /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`. pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> { self.0.set_primary_message(msg); + self.0.set_is_lint(); self.0 } @@ -388,9 +389,9 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { let expn_data = span.ctxt().outer_expn_data(); match expn_data.kind { - ExpnKind::Inlined | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => { - false - } + ExpnKind::Inlined + | ExpnKind::Root + | ExpnKind::Desugaring(DesugaringKind::ForLoop(_) | DesugaringKind::WhileLoop) => false, ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { // Dummy span for the `def_site` means it's an external macro. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -22,7 +22,7 @@ /// imported function has in the dynamic library. Note that this must not /// be set when `link_name` is set. This is for foreign items with the /// "raw-dylib" kind. - pub link_ordinal: Option, + pub link_ordinal: Option, /// The `#[target_feature(enable = "...")]` attribute and the enabled /// features (only enabled features are supported right now). pub target_features: Vec, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/cstore.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/cstore.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/cstore.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/cstore.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,216 +0,0 @@ -//! the rustc crate store interface. This also includes types that -//! are *mostly* used as a part of that interface, but these should -//! probably get a better home if someone can find one. - -use crate::ty::TyCtxt; - -use rustc_ast as ast; -use rustc_data_structures::sync::{self, MetadataRef}; -use rustc_hir::def_id::{CrateNum, DefId, StableCrateId, LOCAL_CRATE}; -use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; -use rustc_macros::HashStable; -use rustc_session::search_paths::PathKind; -use rustc_session::utils::NativeLibKind; -use rustc_span::hygiene::{ExpnHash, ExpnId}; -use rustc_span::symbol::Symbol; -use rustc_span::Span; -use rustc_target::spec::Target; - -use std::any::Any; -use std::path::{Path, PathBuf}; - -// lonely orphan structs and enums looking for a better home - -/// Where a crate came from on the local filesystem. One of these three options -/// must be non-None. -#[derive(PartialEq, Clone, Debug, HashStable, Encodable, Decodable)] -pub struct CrateSource { - pub dylib: Option<(PathBuf, PathKind)>, - pub rlib: Option<(PathBuf, PathKind)>, - pub rmeta: Option<(PathBuf, PathKind)>, -} - -impl CrateSource { - pub fn paths(&self) -> impl Iterator { - self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0) - } -} - -#[derive(Encodable, Decodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] -#[derive(HashStable)] -pub enum CrateDepKind { - /// A dependency that is only used for its macros. - MacrosOnly, - /// A dependency that is always injected into the dependency list and so - /// doesn't need to be linked to an rlib, e.g., the injected allocator. - Implicit, - /// A dependency that is required by an rlib version of this crate. - /// Ordinary `extern crate`s result in `Explicit` dependencies. - Explicit, -} - -impl CrateDepKind { - pub fn macros_only(self) -> bool { - match self { - CrateDepKind::MacrosOnly => true, - CrateDepKind::Implicit | CrateDepKind::Explicit => false, - } - } -} - -#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable)] -pub enum LinkagePreference { - RequireDynamic, - RequireStatic, -} - -#[derive(Debug, Encodable, Decodable, HashStable)] -pub struct NativeLib { - pub kind: NativeLibKind, - pub name: Option, - pub cfg: Option, - pub foreign_module: Option, - pub wasm_import_module: Option, - pub verbatim: Option, - pub dll_imports: Vec, -} - -#[derive(Clone, Debug, Encodable, Decodable, HashStable)] -pub struct DllImport { - pub name: Symbol, - pub ordinal: Option, - /// Calling convention for the function. - /// - /// On x86_64, this is always `DllCallingConvention::C`; on i686, it can be any - /// of the values, and we use `DllCallingConvention::C` to represent `"cdecl"`. - pub calling_convention: DllCallingConvention, - /// Span of import's "extern" declaration; used for diagnostics. - pub span: Span, -} - -/// Calling convention for a function defined in an external library. -/// -/// The usize value, where present, indicates the size of the function's argument list -/// in bytes. -#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable)] -pub enum DllCallingConvention { - C, - Stdcall(usize), - Fastcall(usize), - Vectorcall(usize), -} - -#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] -pub struct ForeignModule { - pub foreign_items: Vec, - pub def_id: DefId, -} - -#[derive(Copy, Clone, Debug, HashStable)] -pub struct ExternCrate { - pub src: ExternCrateSource, - - /// span of the extern crate that caused this to be loaded - pub span: Span, - - /// Number of links to reach the extern; - /// used to select the extern with the shortest path - pub path_len: usize, - - /// Crate that depends on this crate - pub dependency_of: CrateNum, -} - -impl ExternCrate { - /// If true, then this crate is the crate named by the extern - /// crate referenced above. If false, then this crate is a dep - /// of the crate. - pub fn is_direct(&self) -> bool { - self.dependency_of == LOCAL_CRATE - } - - pub fn rank(&self) -> impl PartialOrd { - // Prefer: - // - direct extern crate to indirect - // - shorter paths to longer - (self.is_direct(), !self.path_len) - } -} - -#[derive(Copy, Clone, Debug, HashStable)] -pub enum ExternCrateSource { - /// Crate is loaded by `extern crate`. - Extern( - /// def_id of the item in the current crate that caused - /// this crate to be loaded; note that there could be multiple - /// such ids - DefId, - ), - /// Crate is implicitly loaded by a path resolving through extern prelude. - Path, -} - -#[derive(Encodable, Decodable)] -pub struct EncodedMetadata { - pub raw_data: Vec, -} - -impl EncodedMetadata { - pub fn new() -> EncodedMetadata { - EncodedMetadata { raw_data: Vec::new() } - } -} - -/// The backend's way to give the crate store access to the metadata in a library. -/// Note that it returns the raw metadata bytes stored in the library file, whether -/// it is compressed, uncompressed, some weird mix, etc. -/// rmeta files are backend independent and not handled here. -/// -/// At the time of this writing, there is only one backend and one way to store -/// metadata in library -- this trait just serves to decouple rustc_metadata from -/// the archive reader, which depends on LLVM. -pub trait MetadataLoader { - fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result; - fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result; -} - -pub type MetadataLoaderDyn = dyn MetadataLoader + Sync; - -/// A store of Rust crates, through which their metadata can be accessed. -/// -/// Note that this trait should probably not be expanding today. All new -/// functionality should be driven through queries instead! -/// -/// If you find a method on this trait named `{name}_untracked` it signifies -/// that it's *not* tracked for dependency information throughout compilation -/// (it'd break incremental compilation) and should only be called pre-HIR (e.g. -/// during resolve) -pub trait CrateStore: std::fmt::Debug { - fn as_any(&self) -> &dyn Any; - - // Foreign definitions. - // This information is safe to access, since it's hashed as part of the DefPathHash, which incr. - // comp. uses to identify a DefId. - fn def_key(&self, def: DefId) -> DefKey; - fn def_path(&self, def: DefId) -> DefPath; - fn def_path_hash(&self, def: DefId) -> DefPathHash; - - // This information is safe to access, since it's hashed as part of the StableCrateId, which - // incr. comp. uses to identify a CrateNum. - fn crate_name(&self, cnum: CrateNum) -> Symbol; - fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId; - - /// Fetch a DefId from a DefPathHash for a foreign crate. - fn def_path_hash_to_def_id( - &self, - cnum: CrateNum, - index_guess: u32, - hash: DefPathHash, - ) -> Option; - fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId; - - // utility functions - fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; -} - -pub type CrateStoreDyn = dyn CrateStore + sync::Sync; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ pub mod codegen_fn_attrs; -pub mod cstore; pub mod dependency_format; pub mod exported_symbols; pub mod lang_items; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/privacy.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/privacy.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/privacy.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/privacy.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,9 @@ //! which are available for use externally when compiled as a library. use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; +use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_span::def_id::LocalDefId; use std::hash::Hash; @@ -53,3 +55,12 @@ AccessLevels { map: Default::default() } } } + +impl<'a> HashStable> for AccessLevels { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + let AccessLevels { ref map } = *self; + map.hash_stable(hcx, hasher); + }); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/region.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/region.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/region.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/region.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,10 +6,10 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html -use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::ty::TyCtxt; use rustc_hir as hir; use rustc_hir::Node; +use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -257,7 +257,8 @@ /// ``` /// /// With the HIR tree (calls numbered for expository purposes) - /// ``` + /// + /// ```text /// Call#0(foo, [Call#1(f), Yield(y), Call#2(bar, Call#3(g))]) /// ``` /// diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/stability.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/stability.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/middle/stability.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/middle/stability.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,12 +15,11 @@ use rustc_hir::{self, HirId}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; -use rustc_session::lint::{BuiltinLintDiagnostics, Lint, LintBuffer}; +use rustc_session::lint::{BuiltinLintDiagnostics, Level, Lint, LintBuffer}; use rustc_session::parse::feature_err_issue; use rustc_session::{DiagnosticMessageId, Session}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{MultiSpan, Span}; - use std::num::NonZeroU32; #[derive(PartialEq, Clone, Copy, Debug)] @@ -125,7 +124,11 @@ /// Checks whether an item marked with `deprecated(since="X")` is currently /// deprecated (i.e., whether X is not greater than the current rustc version). -pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool { +pub fn deprecation_in_effect(depr: &Deprecation) -> bool { + let is_since_rustc_version = depr.is_since_rustc_version; + let since = depr.since.map(Symbol::as_str); + let since = since.as_deref(); + fn parse_version(ver: &str) -> Vec { // We ignore non-integer components of the version (e.g., "nightly"). ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect() @@ -175,33 +178,50 @@ } } -pub fn deprecation_message(depr: &Deprecation, kind: &str, path: &str) -> (String, &'static Lint) { - let since = depr.since.map(Symbol::as_str); - let (message, lint) = if deprecation_in_effect(depr.is_since_rustc_version, since.as_deref()) { - (format!("use of deprecated {} `{}`", kind, path), DEPRECATED) +fn deprecation_lint(is_in_effect: bool) -> &'static Lint { + if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE } +} + +fn deprecation_message( + is_in_effect: bool, + since: Option, + note: Option, + kind: &str, + path: &str, +) -> String { + let message = if is_in_effect { + format!("use of deprecated {} `{}`", kind, path) } else { - ( - if since.as_deref() == Some("TBD") { - format!( - "use of {} `{}` that will be deprecated in a future Rust version", - kind, path - ) - } else { - format!( - "use of {} `{}` that will be deprecated in future version {}", - kind, - path, - since.unwrap() - ) - }, - DEPRECATED_IN_FUTURE, - ) + let since = since.map(Symbol::as_str); + + if since.as_deref() == Some("TBD") { + format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path) + } else { + format!( + "use of {} `{}` that will be deprecated in future version {}", + kind, + path, + since.unwrap() + ) + } }; - let message = match depr.note { + + match note { Some(reason) => format!("{}: {}", message, reason), None => message, - }; - (message, lint) + } +} + +pub fn deprecation_message_and_lint( + depr: &Deprecation, + kind: &str, + path: &str, +) -> (String, &'static Lint) { + let is_in_effect = deprecation_in_effect(depr); + ( + deprecation_message(is_in_effect, depr.since, depr.note, kind, path), + deprecation_lint(is_in_effect), + ) } pub fn early_report_deprecation( @@ -303,20 +323,34 @@ // // #[rustc_deprecated] however wants to emit down the whole // hierarchy. - if !skip || depr_entry.attr.is_since_rustc_version { - let path = &with_no_trimmed_paths(|| self.def_path_str(def_id)); - let kind = self.def_kind(def_id).descr(def_id); - let (message, lint) = deprecation_message(&depr_entry.attr, kind, path); - late_report_deprecation( - self, - &message, - depr_entry.attr.suggestion, - lint, - span, - method_span, - id, - def_id, - ); + let depr_attr = &depr_entry.attr; + if !skip || depr_attr.is_since_rustc_version { + // Calculating message for lint involves calling `self.def_path_str`. + // Which by default to calculate visible path will invoke expensive `visible_parent_map` query. + // So we skip message calculation altogether, if lint is allowed. + let is_in_effect = deprecation_in_effect(depr_attr); + let lint = deprecation_lint(is_in_effect); + if self.lint_level_at_node(lint, id).0 != Level::Allow { + let def_path = &with_no_trimmed_paths(|| self.def_path_str(def_id)); + let def_kind = self.def_kind(def_id).descr(def_id); + + late_report_deprecation( + self, + &deprecation_message( + is_in_effect, + depr_attr.since, + depr_attr.note, + def_kind, + def_path, + ), + depr_attr.suggestion, + lint, + span, + method_span, + id, + def_id, + ); + } } }; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/abstract_const.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/abstract_const.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/abstract_const.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/abstract_const.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -//! A subset of a mir body used for const evaluatability checking. -use crate::mir::{self, CastKind}; -use crate::ty::{self, Ty}; - -rustc_index::newtype_index! { - /// An index into an `AbstractConst`. - pub struct NodeId { - derive [HashStable] - DEBUG_FORMAT = "n{}", - } -} - -/// A node of an `AbstractConst`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum Node<'tcx> { - Leaf(&'tcx ty::Const<'tcx>), - Binop(mir::BinOp, NodeId, NodeId), - UnaryOp(mir::UnOp, NodeId), - FunctionCall(NodeId, &'tcx [NodeId]), - Cast(CastKind, NodeId, Ty<'tcx>), -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum NotConstEvaluatable { - Error(rustc_errors::ErrorReported), - MentionsInfer, - MentionsParam, -} - -impl From for NotConstEvaluatable { - fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable { - NotConstEvaluatable::Error(e) - } -} - -TrivialTypeFoldableAndLiftImpls! { - NotConstEvaluatable, -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/generic_graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/generic_graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/generic_graph.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/generic_graph.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,69 @@ +use gsgdt::{Edge, Graph, Node, NodeStyle}; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +/// Convert an MIR function into a gsgdt Graph +pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph { + let def_id = body.source.def_id(); + let def_name = graphviz_safe_def_name(def_id); + let graph_name = format!("Mir_{}", def_name); + let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + + // Nodes + let nodes: Vec = body + .basic_blocks() + .iter_enumerated() + .map(|(block, _)| bb_to_graph_node(block, body, dark_mode)) + .collect(); + + // Edges + let mut edges = Vec::new(); + for (source, _) in body.basic_blocks().iter_enumerated() { + let def_id = body.source.def_id(); + let terminator = body[source].terminator(); + let labels = terminator.kind.fmt_successor_labels(); + + for (&target, label) in terminator.successors().zip(labels) { + let src = node(def_id, source); + let trg = node(def_id, target); + edges.push(Edge::new(src, trg, label.to_string())); + } + } + + Graph::new(graph_name, nodes, edges) +} + +fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node { + let def_id = body.source.def_id(); + let data = &body[block]; + let label = node(def_id, block); + + let (title, bgcolor) = if data.is_cleanup { + let color = if dark_mode { "royalblue" } else { "lightblue" }; + (format!("{} (cleanup)", block.index()), color) + } else { + let color = if dark_mode { "dimgray" } else { "gray" }; + (format!("{}", block.index()), color) + }; + + let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() }; + let mut stmts: Vec = data.statements.iter().map(|x| format!("{:?}", x)).collect(); + + // add the terminator to the stmts, gsgdt can print it out seperately + let mut terminator_head = String::new(); + data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); + stmts.push(terminator_head); + + Node::new(stmts, label, title, style) +} + +// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so +// it does not have to be user friendly. +pub fn graphviz_safe_def_name(def_id: DefId) -> String { + format!("{}_{}", def_id.krate.index(), def_id.index.index(),) +} + +fn node(def_id: DefId, block: BasicBlock) -> String { + format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id)) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/generic_graphviz.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/generic_graphviz.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/generic_graphviz.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/generic_graphviz.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,173 @@ +use rustc_data_structures::graph::{self, iterate}; +use rustc_graphviz as dot; +use rustc_middle::ty::TyCtxt; +use std::io::{self, Write}; + +pub struct GraphvizWriter< + 'a, + G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes, + NodeContentFn: Fn(::Node) -> Vec, + EdgeLabelsFn: Fn(::Node) -> Vec, +> { + graph: &'a G, + is_subgraph: bool, + graphviz_name: String, + graph_label: Option, + node_content_fn: NodeContentFn, + edge_labels_fn: EdgeLabelsFn, +} + +impl< + 'a, + G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes, + NodeContentFn: Fn(::Node) -> Vec, + EdgeLabelsFn: Fn(::Node) -> Vec, +> GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn> +{ + pub fn new( + graph: &'a G, + graphviz_name: &str, + node_content_fn: NodeContentFn, + edge_labels_fn: EdgeLabelsFn, + ) -> Self { + Self { + graph, + is_subgraph: false, + graphviz_name: graphviz_name.to_owned(), + graph_label: None, + node_content_fn, + edge_labels_fn, + } + } + + pub fn set_graph_label(&mut self, graph_label: &str) { + self.graph_label = Some(graph_label.to_owned()); + } + + /// Write a graphviz DOT of the graph + pub fn write_graphviz<'tcx, W>(&self, tcx: TyCtxt<'tcx>, w: &mut W) -> io::Result<()> + where + W: Write, + { + let kind = if self.is_subgraph { "subgraph" } else { "digraph" }; + let cluster = if self.is_subgraph { "cluster_" } else { "" }; // Print border around graph + // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation, + // prepend "Mir_" to the graphviz_safe_def_name(def_id) + writeln!(w, "{} {}{} {{", kind, cluster, self.graphviz_name)?; + + // Global graph properties + let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); + let mut graph_attrs = vec![&font[..]]; + let mut content_attrs = vec![&font[..]]; + + let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + if dark_mode { + graph_attrs.push(r#"bgcolor="black""#); + graph_attrs.push(r#"fontcolor="white""#); + content_attrs.push(r#"color="white""#); + content_attrs.push(r#"fontcolor="white""#); + } + + writeln!(w, r#" graph [{}];"#, graph_attrs.join(" "))?; + let content_attrs_str = content_attrs.join(" "); + writeln!(w, r#" node [{}];"#, content_attrs_str)?; + writeln!(w, r#" edge [{}];"#, content_attrs_str)?; + + // Graph label + if let Some(graph_label) = &self.graph_label { + self.write_graph_label(graph_label, w)?; + } + + // Nodes + for node in iterate::post_order_from(self.graph, self.graph.start_node()) { + self.write_node(node, dark_mode, w)?; + } + + // Edges + for source in iterate::post_order_from(self.graph, self.graph.start_node()) { + self.write_edges(source, w)?; + } + writeln!(w, "}}") + } + + /// Write a graphviz DOT node for the given node. + pub fn write_node(&self, node: G::Node, dark_mode: bool, w: &mut W) -> io::Result<()> + where + W: Write, + { + // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables. + write!(w, r#" {} [shape="none", label=<"#, self.node(node))?; + + write!(w, r#""#)?; + + // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation, + // we need generic way to know if node header should have a different color. For example, + // for MIR: + // + // let (blk, bgcolor) = if data.is_cleanup { + // let color = if dark_mode { "royalblue" } else { "lightblue" }; + // (format!("{:?} (cleanup)", node), color) + // } else { + // let color = if dark_mode { "dimgray" } else { "gray" }; + // (format!("{:?}", node), color) + // }; + let color = if dark_mode { "dimgray" } else { "gray" }; + let (blk, bgcolor) = (format!("{:?}", node), color); + write!( + w, + r#""#, + attrs = r#"align="center""#, + colspan = 1, + blk = blk, + bgcolor = bgcolor + )?; + + for section in (self.node_content_fn)(node) { + write!( + w, + r#""#, + dot::escape_html(§ion).replace("\n", "
") + )?; + } + + // Close the table + write!(w, "
{blk}
{}
")?; + + // Close the node label and the node itself. + writeln!(w, ">];") + } + + /// Write graphviz DOT edges with labels between the given node and all of its successors. + fn write_edges(&self, source: G::Node, w: &mut W) -> io::Result<()> + where + W: Write, + { + let edge_labels = (self.edge_labels_fn)(source); + for (index, target) in self.graph.successors(source).enumerate() { + let src = self.node(source); + let trg = self.node(target); + let escaped_edge_label = if let Some(edge_label) = edge_labels.get(index) { + dot::escape_html(edge_label).replace("\n", r#"
"#) + } else { + "".to_owned() + }; + writeln!(w, r#" {} -> {} [label=<{}>];"#, src, trg, escaped_edge_label)?; + } + Ok(()) + } + + /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that + /// will appear below the graph. + fn write_graph_label(&self, label: &str, w: &mut W) -> io::Result<()> + where + W: Write, + { + let lines = label.split('\n').map(|s| dot::escape_html(s)).collect::>(); + let escaped_label = lines.join(r#"
"#); + writeln!(w, r#" label=<

{}



>;"#, escaped_label) + } + + fn node(&self, node: G::Node) -> String { + format!("{:?}__{}", node, self.graphviz_name) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/graphviz.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/graphviz.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/graphviz.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/graphviz.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,134 @@ +use gsgdt::GraphvizSettings; +use rustc_graphviz as dot; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; +use std::fmt::Debug; +use std::io::{self, Write}; + +use super::generic_graph::mir_fn_to_generic_graph; +use super::pretty::dump_mir_def_ids; + +/// Write a graphviz DOT graph of a list of MIRs. +pub fn write_mir_graphviz(tcx: TyCtxt<'_>, single: Option, w: &mut W) -> io::Result<()> +where + W: Write, +{ + let def_ids = dump_mir_def_ids(tcx, single); + + let mirs = + def_ids + .iter() + .flat_map(|def_id| { + if tcx.is_const_fn_raw(*def_id) { + vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] + } else { + vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown( + *def_id, + )))] + } + }) + .collect::>(); + + let use_subgraphs = mirs.len() > 1; + if use_subgraphs { + writeln!(w, "digraph __crate__ {{")?; + } + + for mir in mirs { + write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?; + } + + if use_subgraphs { + writeln!(w, "}}")?; + } + + Ok(()) +} + +/// Write a graphviz DOT graph of the MIR. +pub fn write_mir_fn_graphviz<'tcx, W>( + tcx: TyCtxt<'tcx>, + body: &Body<'_>, + subgraph: bool, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + // Global graph properties + let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); + let mut graph_attrs = vec![&font[..]]; + let mut content_attrs = vec![&font[..]]; + + let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + if dark_mode { + graph_attrs.push(r#"bgcolor="black""#); + graph_attrs.push(r#"fontcolor="white""#); + content_attrs.push(r#"color="white""#); + content_attrs.push(r#"fontcolor="white""#); + } + + // Graph label + let mut label = String::from(""); + // FIXME: remove this unwrap + write_graph_label(tcx, body, &mut label).unwrap(); + let g = mir_fn_to_generic_graph(tcx, body); + let settings = GraphvizSettings { + graph_attrs: Some(graph_attrs.join(" ")), + node_attrs: Some(content_attrs.join(" ")), + edge_attrs: Some(content_attrs.join(" ")), + graph_label: Some(label), + }; + g.to_dot(w, &settings, subgraph) +} + +/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that +/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of +/// all the variables and temporaries. +fn write_graph_label<'tcx, W: std::fmt::Write>( + tcx: TyCtxt<'tcx>, + body: &Body<'_>, + w: &mut W, +) -> std::fmt::Result { + let def_id = body.source.def_id(); + + write!(w, "fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?; + + // fn argument types. + for (i, arg) in body.args_iter().enumerate() { + if i > 0 { + write!(w, ", ")?; + } + write!(w, "{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))?; + } + + write!(w, ") -> {}", escape(&body.return_ty()))?; + write!(w, r#"
"#)?; + + for local in body.vars_and_temps_iter() { + let decl = &body.local_decls[local]; + + write!(w, "let ")?; + if decl.mutability == Mutability::Mut { + write!(w, "mut ")?; + } + + write!(w, r#"{:?}: {};
"#, Place::from(local), escape(&decl.ty))?; + } + + for var_debug_info in &body.var_debug_info { + write!( + w, + r#"debug {} => {};
"#, + var_debug_info.name, + escape(&var_debug_info.value), + )?; + } + + Ok(()) +} + +fn escape(t: &T) -> String { + dot::escape_html(&format!("{:?}", t)) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/allocation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/allocation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/allocation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/allocation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1004,13 +1004,13 @@ /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes` /// error which will report the first range of bytes which is uninitialized. fn check_init(&self, range: AllocRange) -> AllocResult { - self.is_init(range).or_else(|idx_range| { - Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess { + self.is_init(range).map_err(|idx_range| { + AllocError::InvalidUninitBytes(Some(UninitBytesAccess { access_offset: range.start, access_size: range.size, uninit_offset: idx_range.start, uninit_size: idx_range.end - idx_range.start, // `Size` subtraction - }))) + })) }) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/error.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/error.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/error.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -287,6 +287,8 @@ target_size: u64, data_size: u64, }, + /// A discriminant of an uninhabited enum variant is written. + UninhabitedEnumVariantWritten, } impl fmt::Display for UndefinedBehaviorInfo<'_> { @@ -391,6 +393,9 @@ "scalar size mismatch: expected {} bytes but got {} bytes instead", target_size, data_size ), + UninhabitedEnumVariantWritten => { + write!(f, "writing discriminant of an uninhabited enum") + } } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/pointer.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/pointer.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/pointer.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/interpret/pointer.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size}; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::fmt; //////////////////////////////////////////////////////////////////////////////// @@ -20,29 +20,27 @@ #[inline] fn machine_usize_max(&self) -> u64 { - let max_usize_plus_1 = 1u128 << self.pointer_size().bits(); - u64::try_from(max_usize_plus_1 - 1).unwrap() + self.pointer_size().unsigned_int_max().try_into().unwrap() } #[inline] fn machine_isize_min(&self) -> i64 { - let max_isize_plus_1 = 1i128 << (self.pointer_size().bits() - 1); - i64::try_from(-max_isize_plus_1).unwrap() + self.pointer_size().signed_int_min().try_into().unwrap() } #[inline] fn machine_isize_max(&self) -> i64 { - let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1); - i64::try_from(max_isize_plus_1 - 1).unwrap() + self.pointer_size().signed_int_max().try_into().unwrap() } #[inline] fn machine_usize_to_isize(&self, val: u64) -> i64 { let val = val as i64; - // Now clamp into the machine_isize range. + // Now wrap-around into the machine_isize range. if val > self.machine_isize_max() { // This can only happen the the ptr size is < 64, so we know max_usize_plus_1 fits into // i64. + debug_assert!(self.pointer_size().bits() < 64); let max_usize_plus_1 = 1u128 << self.pointer_size().bits(); val - i64::try_from(max_usize_plus_1).unwrap() } else { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -40,13 +40,18 @@ use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; -pub mod abstract_const; pub mod coverage; +mod generic_graph; +pub mod generic_graphviz; mod graph_cyclic_cache; +pub mod graphviz; pub mod interpret; pub mod mono; +pub mod patch; mod predecessors; +pub mod pretty; mod query; +pub mod spanview; pub mod tcx; pub mod terminator; pub use terminator::*; @@ -54,6 +59,12 @@ mod type_foldable; pub mod visit; +pub use self::generic_graph::graphviz_safe_def_name; +pub use self::graphviz::write_mir_graphviz; +pub use self::pretty::{ + create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere, +}; + /// Types for locals pub type LocalDecls<'tcx> = IndexVec>; @@ -75,6 +86,22 @@ } } +/// A streamlined trait that you can implement to create a pass; the +/// pass will be named after the type, and it will consist of a main +/// loop that goes over each available MIR and applies `run_pass`. +pub trait MirPass<'tcx> { + fn name(&self) -> Cow<'_, str> { + let name = std::any::type_name::(); + if let Some(tail) = name.rfind(':') { + Cow::from(&name[tail + 1..]) + } else { + Cow::from(name) + } + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); +} + /// The various "big phases" that MIR goes through. /// /// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the @@ -776,8 +803,8 @@ TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } mod binding_form_impl { - use crate::ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + use rustc_query_system::ich::StableHashingContext; impl<'a, 'tcx> HashStable> for super::BindingForm<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { @@ -965,6 +992,9 @@ StaticRef { def_id: DefId, is_thread_local: bool }, /// A temporary created that references the const with the given `DefId` ConstRef { def_id: DefId }, + /// A temporary created during the creation of an aggregate + /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`) + AggregateTemp, } impl<'tcx> LocalDecl<'tcx> { @@ -1142,7 +1172,7 @@ /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg /// [data-flow analyses]: /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis - /// [`CriticalCallEdges`]: ../../rustc_mir/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges + /// [`CriticalCallEdges`]: ../../rustc_const_eval/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ pub struct BasicBlock { derive [HashStable] @@ -1708,7 +1738,7 @@ pub projection: &'tcx List>, } -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Place<'_>, 16); #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -2034,7 +2064,7 @@ Constant(Box>), } -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Operand<'_>, 24); impl<'tcx> Debug for Operand<'tcx> { @@ -2170,9 +2200,15 @@ /// that `Foo` has a destructor. These rvalues can be optimized /// away after type-checking and before lowering. Aggregate(Box>, Vec>), + + /// Transmutes a `*mut u8` into shallow-initialized `Box`. + /// + /// This is different a normal transmute because dataflow analysis will treat the box + /// as initialized but its content as uninitialized. + ShallowInitBox(Operand<'tcx>, Ty<'tcx>), } -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Rvalue<'_>, 40); #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -2198,7 +2234,7 @@ Generator(DefId, SubstsRef<'tcx>, hir::Movability), } -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(AggregateKind<'_>, 48); #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -2250,6 +2286,8 @@ pub enum NullOp { /// Returns the size of a value of that type SizeOf, + /// Returns the minimum alignment of a type + AlignOf, /// Creates a new uninitialized box for a value of that type Box, } @@ -2418,6 +2456,10 @@ }), } } + + ShallowInitBox(ref place, ref ty) => { + write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty) + } } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/mono.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/mono.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/mono.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/mono.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; -use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use rustc_attr::InlineAttr; use rustc_data_structures::base_n; @@ -8,6 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::{HirId, ItemId}; +use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_session::config::OptLevel; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -47,6 +47,14 @@ } impl<'tcx> MonoItem<'tcx> { + /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims). + pub fn is_user_defined(&self) -> bool { + match *self { + MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)), + MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true, + } + } + pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize { match *self { MonoItem::Fn(instance) => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/patch.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/patch.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/patch.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/patch.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,173 @@ +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::*; +use rustc_middle::ty::Ty; +use rustc_span::Span; + +/// This struct represents a patch to MIR, which can add +/// new statements and basic blocks and patch over block +/// terminators. +pub struct MirPatch<'tcx> { + patch_map: IndexVec>>, + new_blocks: Vec>, + new_statements: Vec<(Location, StatementKind<'tcx>)>, + new_locals: Vec>, + resume_block: BasicBlock, + next_local: usize, +} + +impl<'tcx> MirPatch<'tcx> { + pub fn new(body: &Body<'tcx>) -> Self { + let mut result = MirPatch { + patch_map: IndexVec::from_elem(None, body.basic_blocks()), + new_blocks: vec![], + new_statements: vec![], + new_locals: vec![], + next_local: body.local_decls.len(), + resume_block: START_BLOCK, + }; + + // make sure the MIR we create has a resume block. It is + // completely legal to convert jumps to the resume block + // to jumps to None, but we occasionally have to add + // instructions just before that. + + let mut resume_block = None; + let mut resume_stmt_block = None; + for (bb, block) in body.basic_blocks().iter_enumerated() { + if let TerminatorKind::Resume = block.terminator().kind { + if !block.statements.is_empty() { + assert!(resume_stmt_block.is_none()); + resume_stmt_block = Some(bb); + } else { + resume_block = Some(bb); + } + break; + } + } + let resume_block = resume_block.unwrap_or_else(|| { + result.new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(body.span), + kind: TerminatorKind::Resume, + }), + is_cleanup: true, + }) + }); + result.resume_block = resume_block; + if let Some(resume_stmt_block) = resume_stmt_block { + result + .patch_terminator(resume_stmt_block, TerminatorKind::Goto { target: resume_block }); + } + result + } + + pub fn resume_block(&self) -> BasicBlock { + self.resume_block + } + + pub fn is_patched(&self, bb: BasicBlock) -> bool { + self.patch_map[bb].is_some() + } + + pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location { + let offset = match bb.index().checked_sub(body.basic_blocks().len()) { + Some(index) => self.new_blocks[index].statements.len(), + None => body[bb].statements.len(), + }; + Location { block: bb, statement_index: offset } + } + + pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { + let index = self.next_local; + self.next_local += 1; + self.new_locals.push(LocalDecl::new(ty, span)); + Local::new(index as usize) + } + + pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { + let index = self.next_local; + self.next_local += 1; + self.new_locals.push(LocalDecl::new(ty, span).internal()); + Local::new(index as usize) + } + + pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { + let block = BasicBlock::new(self.patch_map.len()); + debug!("MirPatch: new_block: {:?}: {:?}", block, data); + self.new_blocks.push(data); + self.patch_map.push(None); + block + } + + pub fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) { + assert!(self.patch_map[block].is_none()); + debug!("MirPatch: patch_terminator({:?}, {:?})", block, new); + self.patch_map[block] = Some(new); + } + + pub fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) { + debug!("MirPatch: add_statement({:?}, {:?})", loc, stmt); + self.new_statements.push((loc, stmt)); + } + + pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) { + self.add_statement(loc, StatementKind::Assign(Box::new((place, rv)))); + } + + pub fn apply(self, body: &mut Body<'tcx>) { + debug!( + "MirPatch: {:?} new temps, starting from index {}: {:?}", + self.new_locals.len(), + body.local_decls.len(), + self.new_locals + ); + debug!( + "MirPatch: {} new blocks, starting from index {}", + self.new_blocks.len(), + body.basic_blocks().len() + ); + body.basic_blocks_mut().extend(self.new_blocks); + body.local_decls.extend(self.new_locals); + for (src, patch) in self.patch_map.into_iter_enumerated() { + if let Some(patch) = patch { + debug!("MirPatch: patching block {:?}", src); + body[src].terminator_mut().kind = patch; + } + } + + let mut new_statements = self.new_statements; + new_statements.sort_by_key(|s| s.0); + + let mut delta = 0; + let mut last_bb = START_BLOCK; + for (mut loc, stmt) in new_statements { + if loc.block != last_bb { + delta = 0; + last_bb = loc.block; + } + debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); + loc.statement_index += delta; + let source_info = Self::source_info_for_index(&body[loc.block], loc); + body[loc.block] + .statements + .insert(loc.statement_index, Statement { source_info, kind: stmt }); + delta += 1; + } + } + + pub fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo { + match data.statements.get(loc.statement_index) { + Some(stmt) => stmt.source_info, + None => data.terminator().source_info, + } + } + + pub fn source_info_for_location(&self, body: &Body<'_>, loc: Location) -> SourceInfo { + let data = match loc.block.index().checked_sub(body.basic_blocks().len()) { + Some(new) => &self.new_blocks[new], + None => &body[loc.block], + }; + Self::source_info_for_index(data, loc) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/pretty.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/pretty.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/pretty.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/pretty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1046 @@ +use std::collections::BTreeSet; +use std::fmt::Display; +use std::fmt::Write as _; +use std::fs; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; + +use super::graphviz::write_mir_fn_graphviz; +use super::spanview::write_mir_fn_spanview; +use either::Either; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::DefId; +use rustc_index::vec::Idx; +use rustc_middle::mir::interpret::{ + read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, Pointer, Provenance, +}; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::MirSource; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; +use rustc_target::abi::Size; +use std::ops::ControlFlow; + +const INDENT: &str = " "; +/// Alignment for lining up comments following MIR statements +pub(crate) const ALIGN: usize = 40; + +/// An indication of where we are in the control flow graph. Used for printing +/// extra information in `dump_mir` +pub enum PassWhere { + /// We have not started dumping the control flow graph, but we are about to. + BeforeCFG, + + /// We just finished dumping the control flow graph. This is right before EOF + AfterCFG, + + /// We are about to start dumping the given basic block. + BeforeBlock(BasicBlock), + + /// We are just about to dump the given statement or terminator. + BeforeLocation(Location), + + /// We just dumped the given statement or terminator. + AfterLocation(Location), + + /// We just dumped the terminator for a block but not the closing `}`. + AfterTerminator(BasicBlock), +} + +/// If the session is properly configured, dumps a human-readable +/// representation of the mir into: +/// +/// ```text +/// rustc.node... +/// ``` +/// +/// Output from this function is controlled by passing `-Z dump-mir=`, +/// where `` takes the following forms: +/// +/// - `all` -- dump MIR for all fns, all passes, all everything +/// - a filter defined by a set of substrings combined with `&` and `|` +/// (`&` has higher precedence). At least one of the `|`-separated groups +/// must match; an `|`-separated group matches if all of its `&`-separated +/// substrings are matched. +/// +/// Example: +/// +/// - `nll` == match if `nll` appears in the name +/// - `foo & nll` == match if `foo` and `nll` both appear in the name +/// - `foo & nll | typeck` == match if `foo` and `nll` both appear in the name +/// or `typeck` appears in the name. +/// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name +/// or `typeck` and `bar` both appear in the name. +pub fn dump_mir<'tcx, F>( + tcx: TyCtxt<'tcx>, + pass_num: Option<&dyn Display>, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + extra_data: F, +) where + F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, +{ + if !dump_enabled(tcx, pass_name, body.source.def_id()) { + return; + } + + dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, body, extra_data); +} + +pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) -> bool { + let filters = match tcx.sess.opts.debugging_opts.dump_mir { + None => return false, + Some(ref filters) => filters, + }; + let node_path = ty::print::with_forced_impl_filename_line(|| { + // see notes on #41697 below + tcx.def_path_str(def_id) + }); + filters.split('|').any(|or_filter| { + or_filter.split('&').all(|and_filter| { + let and_filter_trimmed = and_filter.trim(); + and_filter_trimmed == "all" + || pass_name.contains(and_filter_trimmed) + || node_path.contains(and_filter_trimmed) + }) + }) +} + +// #41697 -- we use `with_forced_impl_filename_line()` because +// `def_path_str()` would otherwise trigger `type_of`, and this can +// run while we are already attempting to evaluate `type_of`. + +fn dump_matched_mir_node<'tcx, F>( + tcx: TyCtxt<'tcx>, + pass_num: Option<&dyn Display>, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + mut extra_data: F, +) where + F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, +{ + let _: io::Result<()> = try { + let mut file = + create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body.source)?; + let def_path = ty::print::with_forced_impl_filename_line(|| { + // see notes on #41697 above + tcx.def_path_str(body.source.def_id()) + }); + write!(file, "// MIR for `{}", def_path)?; + match body.source.promoted { + None => write!(file, "`")?, + Some(promoted) => write!(file, "::{:?}`", promoted)?, + } + writeln!(file, " {} {}", disambiguator, pass_name)?; + if let Some(ref layout) = body.generator_layout() { + writeln!(file, "/* generator_layout = {:#?} */", layout)?; + } + writeln!(file)?; + extra_data(PassWhere::BeforeCFG, &mut file)?; + write_user_type_annotations(tcx, body, &mut file)?; + write_mir_fn(tcx, body, &mut extra_data, &mut file)?; + extra_data(PassWhere::AfterCFG, &mut file)?; + }; + + if tcx.sess.opts.debugging_opts.dump_mir_graphviz { + let _: io::Result<()> = try { + let mut file = + create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body.source)?; + write_mir_fn_graphviz(tcx, body, false, &mut file)?; + }; + } + + if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview { + let _: io::Result<()> = try { + let file_basename = + dump_file_basename(tcx, pass_num, pass_name, disambiguator, body.source); + let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?; + if body.source.def_id().is_local() { + write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?; + } + }; + } +} + +/// Returns the file basename portion (without extension) of a filename path +/// where we should dump a MIR representation output files. +fn dump_file_basename( + tcx: TyCtxt<'_>, + pass_num: Option<&dyn Display>, + pass_name: &str, + disambiguator: &dyn Display, + source: MirSource<'tcx>, +) -> String { + let promotion_id = match source.promoted { + Some(id) => format!("-{:?}", id), + None => String::new(), + }; + + let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number { + String::new() + } else { + match pass_num { + None => ".-------".to_string(), + Some(pass_num) => format!(".{}", pass_num), + } + }; + + let crate_name = tcx.crate_name(source.def_id().krate); + let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate(); + // All drop shims have the same DefId, so we have to add the type + // to get unique file names. + let shim_disambiguator = match source.instance { + ty::InstanceDef::DropGlue(_, Some(ty)) => { + // Unfortunately, pretty-printed typed are not very filename-friendly. + // We dome some filtering. + let mut s = ".".to_owned(); + s.extend(ty.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + _ => String::new(), + }; + + format!( + "{}.{}{}{}{}.{}.{}", + crate_name, item_name, shim_disambiguator, promotion_id, pass_num, pass_name, disambiguator, + ) +} + +/// Returns the path to the filename where we should dump a given MIR. +/// Also used by other bits of code (e.g., NLL inference) that dump +/// graphviz data or other things. +fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf { + let mut file_path = PathBuf::new(); + file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir)); + + let file_name = format!("{}.{}", basename, extension,); + + file_path.push(&file_name); + + file_path +} + +/// Attempts to open the MIR dump file with the given name and extension. +fn create_dump_file_with_basename( + tcx: TyCtxt<'_>, + file_basename: &str, + extension: &str, +) -> io::Result> { + let file_path = dump_path(tcx, file_basename, extension); + if let Some(parent) = file_path.parent() { + fs::create_dir_all(parent).map_err(|e| { + io::Error::new( + e.kind(), + format!("IO error creating MIR dump directory: {:?}; {}", parent, e), + ) + })?; + } + Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| { + io::Error::new(e.kind(), format!("IO error creating MIR dump file: {:?}; {}", file_path, e)) + })?)) +} + +/// Attempts to open a file where we should dump a given MIR or other +/// bit of MIR-related data. Used by `mir-dump`, but also by other +/// bits of code (e.g., NLL inference) that dump graphviz data or +/// other things, and hence takes the extension as an argument. +pub fn create_dump_file( + tcx: TyCtxt<'_>, + extension: &str, + pass_num: Option<&dyn Display>, + pass_name: &str, + disambiguator: &dyn Display, + source: MirSource<'tcx>, +) -> io::Result> { + create_dump_file_with_basename( + tcx, + &dump_file_basename(tcx, pass_num, pass_name, disambiguator, source), + extension, + ) +} + +/// Write out a human-readable textual representation for the given MIR. +pub fn write_mir_pretty<'tcx>( + tcx: TyCtxt<'tcx>, + single: Option, + w: &mut dyn Write, +) -> io::Result<()> { + writeln!(w, "// WARNING: This output format is intended for human consumers only")?; + writeln!(w, "// and is subject to change without notice. Knock yourself out.")?; + + let mut first = true; + for def_id in dump_mir_def_ids(tcx, single) { + if first { + first = false; + } else { + // Put empty lines between all items + writeln!(w)?; + } + + let render_body = |w: &mut dyn Write, body| -> io::Result<()> { + write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?; + + for body in tcx.promoted_mir(def_id) { + writeln!(w)?; + write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?; + } + Ok(()) + }; + + // For `const fn` we want to render both the optimized MIR and the MIR for ctfe. + if tcx.is_const_fn_raw(def_id) { + render_body(w, tcx.optimized_mir(def_id))?; + writeln!(w)?; + writeln!(w, "// MIR FOR CTFE")?; + // Do not use `render_body`, as that would render the promoteds again, but these + // are shared between mir_for_ctfe and optimized_mir + write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?; + } else { + let instance_mir = + tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id))); + render_body(w, instance_mir)?; + } + } + Ok(()) +} + +/// Write out a human-readable textual representation for the given function. +pub fn write_mir_fn<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + extra_data: &mut F, + w: &mut dyn Write, +) -> io::Result<()> +where + F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, +{ + write_mir_intro(tcx, body, w)?; + for block in body.basic_blocks().indices() { + extra_data(PassWhere::BeforeBlock(block), w)?; + write_basic_block(tcx, block, body, extra_data, w)?; + if block.index() + 1 != body.basic_blocks().len() { + writeln!(w)?; + } + } + + writeln!(w, "}}")?; + + write_allocations(tcx, body, w)?; + + Ok(()) +} + +/// Write out a human-readable textual representation for the given basic block. +pub fn write_basic_block<'tcx, F>( + tcx: TyCtxt<'tcx>, + block: BasicBlock, + body: &Body<'tcx>, + extra_data: &mut F, + w: &mut dyn Write, +) -> io::Result<()> +where + F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, +{ + let data = &body[block]; + + // Basic block label at the top. + let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" }; + writeln!(w, "{}{:?}{}: {{", INDENT, block, cleanup_text)?; + + // List of statements in the middle. + let mut current_location = Location { block, statement_index: 0 }; + for statement in &data.statements { + extra_data(PassWhere::BeforeLocation(current_location), w)?; + let indented_body = format!("{0}{0}{1:?};", INDENT, statement); + writeln!( + w, + "{:A$} // {}{}", + indented_body, + if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, + comment(tcx, statement.source_info), + A = ALIGN, + )?; + + write_extra(tcx, w, |visitor| { + visitor.visit_statement(statement, current_location); + })?; + + extra_data(PassWhere::AfterLocation(current_location), w)?; + + current_location.statement_index += 1; + } + + // Terminator at the bottom. + extra_data(PassWhere::BeforeLocation(current_location), w)?; + let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); + writeln!( + w, + "{:A$} // {}{}", + indented_terminator, + if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, + comment(tcx, data.terminator().source_info), + A = ALIGN, + )?; + + write_extra(tcx, w, |visitor| { + visitor.visit_terminator(data.terminator(), current_location); + })?; + + extra_data(PassWhere::AfterLocation(current_location), w)?; + extra_data(PassWhere::AfterTerminator(block), w)?; + + writeln!(w, "{}}}", INDENT) +} + +/// After we print the main statement, we sometimes dump extra +/// information. There's often a lot of little things "nuzzled up" in +/// a statement. +fn write_extra<'tcx, F>(tcx: TyCtxt<'tcx>, write: &mut dyn Write, mut visit_op: F) -> io::Result<()> +where + F: FnMut(&mut ExtraComments<'tcx>), +{ + let mut extra_comments = ExtraComments { tcx, comments: vec![] }; + visit_op(&mut extra_comments); + for comment in extra_comments.comments { + writeln!(write, "{:A$} // {}", "", comment, A = ALIGN)?; + } + Ok(()) +} + +struct ExtraComments<'tcx> { + tcx: TyCtxt<'tcx>, + comments: Vec, +} + +impl ExtraComments<'tcx> { + fn push(&mut self, lines: &str) { + for line in lines.split('\n') { + self.comments.push(line.to_string()); + } + } +} + +fn use_verbose(ty: &&TyS<'tcx>, fn_def: bool) -> bool { + match ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, + // Unit type + ty::Tuple(g_args) if g_args.is_empty() => false, + ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty(), fn_def)), + ty::Array(ty, _) => use_verbose(ty, fn_def), + ty::FnDef(..) => fn_def, + _ => true, + } +} + +impl Visitor<'tcx> for ExtraComments<'tcx> { + fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + self.super_constant(constant, location); + let Constant { span, user_ty, literal } = constant; + if use_verbose(&literal.ty(), true) { + self.push("mir::Constant"); + self.push(&format!( + "+ span: {}", + self.tcx.sess.source_map().span_to_embeddable_string(*span) + )); + if let Some(user_ty) = user_ty { + self.push(&format!("+ user_ty: {:?}", user_ty)); + } + match literal { + ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)), + ConstantKind::Val(val, ty) => { + // To keep the diffs small, we render this almost like we render ty::Const + self.push(&format!("+ literal: Const {{ ty: {}, val: Value({:?}) }}", ty, val)) + } + } + } + } + + fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { + self.super_const(constant); + let ty::Const { ty, val, .. } = constant; + if use_verbose(ty, false) { + self.push("ty::Const"); + self.push(&format!("+ ty: {:?}", ty)); + let val = match val { + ty::ConstKind::Param(p) => format!("Param({})", p), + ty::ConstKind::Infer(infer) => format!("Infer({:?})", infer), + ty::ConstKind::Bound(idx, var) => format!("Bound({:?}, {:?})", idx, var), + ty::ConstKind::Placeholder(ph) => format!("PlaceHolder({:?})", ph), + ty::ConstKind::Unevaluated(uv) => format!( + "Unevaluated({}, {:?}, {:?})", + self.tcx.def_path_str(uv.def.did), + uv.substs(self.tcx), + uv.promoted + ), + ty::ConstKind::Value(val) => format!("Value({:?})", val), + ty::ConstKind::Error(_) => "Error".to_string(), + }; + self.push(&format!("+ val: {}", val)); + } + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + if let Rvalue::Aggregate(kind, _) = rvalue { + match **kind { + AggregateKind::Closure(def_id, substs) => { + self.push("closure"); + self.push(&format!("+ def_id: {:?}", def_id)); + self.push(&format!("+ substs: {:#?}", substs)); + } + + AggregateKind::Generator(def_id, substs, movability) => { + self.push("generator"); + self.push(&format!("+ def_id: {:?}", def_id)); + self.push(&format!("+ substs: {:#?}", substs)); + self.push(&format!("+ movability: {:?}", movability)); + } + + AggregateKind::Adt(_, _, _, Some(user_ty), _) => { + self.push("adt"); + self.push(&format!("+ user_ty: {:?}", user_ty)); + } + + _ => {} + } + } + } +} + +fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String { + format!("scope {} at {}", scope.index(), tcx.sess.source_map().span_to_embeddable_string(span)) +} + +/// Prints local variables in a scope tree. +fn write_scope_tree( + tcx: TyCtxt<'_>, + body: &Body<'_>, + scope_tree: &FxHashMap>, + w: &mut dyn Write, + parent: SourceScope, + depth: usize, +) -> io::Result<()> { + let indent = depth * INDENT.len(); + + // Local variable debuginfo. + for var_debug_info in &body.var_debug_info { + if var_debug_info.source_info.scope != parent { + // Not declared in this scope. + continue; + } + + let indented_debug_info = format!( + "{0:1$}debug {2} => {3:?};", + INDENT, indent, var_debug_info.name, var_debug_info.value, + ); + + writeln!( + w, + "{0:1$} // in {2}", + indented_debug_info, + ALIGN, + comment(tcx, var_debug_info.source_info), + )?; + } + + // Local variable types. + for (local, local_decl) in body.local_decls.iter_enumerated() { + if (1..body.arg_count + 1).contains(&local.index()) { + // Skip over argument locals, they're printed in the signature. + continue; + } + + if local_decl.source_info.scope != parent { + // Not declared in this scope. + continue; + } + + let mut_str = if local_decl.mutability == Mutability::Mut { "mut " } else { "" }; + + let mut indented_decl = + format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty); + if let Some(user_ty) = &local_decl.user_ty { + for user_ty in user_ty.projections() { + write!(indented_decl, " as {:?}", user_ty).unwrap(); + } + } + indented_decl.push(';'); + + let local_name = + if local == RETURN_PLACE { " return place".to_string() } else { String::new() }; + + writeln!( + w, + "{0:1$} //{2} in {3}", + indented_decl, + ALIGN, + local_name, + comment(tcx, local_decl.source_info), + )?; + } + + let children = match scope_tree.get(&parent) { + Some(children) => children, + None => return Ok(()), + }; + + for &child in children { + let child_data = &body.source_scopes[child]; + assert_eq!(child_data.parent_scope, Some(parent)); + + let (special, span) = if let Some((callee, callsite_span)) = child_data.inlined { + ( + format!( + " (inlined {}{})", + if callee.def.requires_caller_location(tcx) { "#[track_caller] " } else { "" }, + callee + ), + Some(callsite_span), + ) + } else { + (String::new(), None) + }; + + let indented_header = format!("{0:1$}scope {2}{3} {{", "", indent, child.index(), special); + + if let Some(span) = span { + writeln!( + w, + "{0:1$} // at {2}", + indented_header, + ALIGN, + tcx.sess.source_map().span_to_embeddable_string(span), + )?; + } else { + writeln!(w, "{}", indented_header)?; + } + + write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?; + writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?; + } + + Ok(()) +} + +/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its +/// local variables (both user-defined bindings and compiler temporaries). +pub fn write_mir_intro<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'_>, + w: &mut dyn Write, +) -> io::Result<()> { + write_mir_sig(tcx, body, w)?; + writeln!(w, "{{")?; + + // construct a scope tree and write it out + let mut scope_tree: FxHashMap> = Default::default(); + for (index, scope_data) in body.source_scopes.iter().enumerate() { + if let Some(parent) = scope_data.parent_scope { + scope_tree.entry(parent).or_default().push(SourceScope::new(index)); + } else { + // Only the argument scope has no parent, because it's the root. + assert_eq!(index, OUTERMOST_SOURCE_SCOPE.index()); + } + } + + write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?; + + // Add an empty line before the first block is printed. + writeln!(w)?; + + Ok(()) +} + +/// Find all `AllocId`s mentioned (recursively) in the MIR body and print their corresponding +/// allocations. +pub fn write_allocations<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'_>, + w: &mut dyn Write, +) -> io::Result<()> { + fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator + '_ { + alloc.relocations().values().map(|id| *id) + } + fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator + '_ { + match val { + ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _size)) => { + Either::Left(Either::Left(std::iter::once(ptr.provenance))) + } + ConstValue::Scalar(interpret::Scalar::Int { .. }) => { + Either::Left(Either::Right(std::iter::empty())) + } + ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => { + Either::Right(alloc_ids_from_alloc(alloc)) + } + } + } + struct CollectAllocIds(BTreeSet); + impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { + fn tcx_for_anon_const_substs(&self) -> Option> { + // `AllocId`s are only inside of `ConstKind::Value` which + // can't be part of the anon const default substs. + None + } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { + if let ty::ConstKind::Value(val) = c.val { + self.0.extend(alloc_ids_from_const(val)); + } + c.super_visit_with(self) + } + } + let mut visitor = CollectAllocIds(Default::default()); + body.visit_with(&mut visitor); + // `seen` contains all seen allocations, including the ones we have *not* printed yet. + // The protocol is to first `insert` into `seen`, and only if that returns `true` + // then push to `todo`. + let mut seen = visitor.0; + let mut todo: Vec<_> = seen.iter().copied().collect(); + while let Some(id) = todo.pop() { + let mut write_allocation_track_relocs = + |w: &mut dyn Write, alloc: &Allocation| -> io::Result<()> { + // `.rev()` because we are popping them from the back of the `todo` vector. + for id in alloc_ids_from_alloc(alloc).rev() { + if seen.insert(id) { + todo.push(id); + } + } + write!(w, "{}", display_allocation(tcx, alloc)) + }; + write!(w, "\n{}", id)?; + match tcx.get_global_alloc(id) { + // This can't really happen unless there are bugs, but it doesn't cost us anything to + // gracefully handle it and allow buggy rustc to be debugged via allocation printing. + None => write!(w, " (deallocated)")?, + Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?, + Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { + match tcx.eval_static_initializer(did) { + Ok(alloc) => { + write!(w, " (static: {}, ", tcx.def_path_str(did))?; + write_allocation_track_relocs(w, alloc)?; + } + Err(_) => write!( + w, + " (static: {}, error during initializer evaluation)", + tcx.def_path_str(did) + )?, + } + } + Some(GlobalAlloc::Static(did)) => { + write!(w, " (extern static: {})", tcx.def_path_str(did))? + } + Some(GlobalAlloc::Memory(alloc)) => { + write!(w, " (")?; + write_allocation_track_relocs(w, alloc)? + } + } + writeln!(w)?; + } + Ok(()) +} + +/// Dumps the size and metadata and content of an allocation to the given writer. +/// The expectation is that the caller first prints other relevant metadata, so the exact +/// format of this function is (*without* leading or trailing newline): +/// +/// ```text +/// size: {}, align: {}) { +/// +/// } +/// ``` +/// +/// The byte format is similar to how hex editors print bytes. Each line starts with the address of +/// the start of the line, followed by all bytes in hex format (space separated). +/// If the allocation is small enough to fit into a single line, no start address is given. +/// After the hex dump, an ascii dump follows, replacing all unprintable characters (control +/// characters or characters whose value is larger than 127) with a `.` +/// This also prints relocations adequately. +pub fn display_allocation( + tcx: TyCtxt<'tcx>, + alloc: &'a Allocation, +) -> RenderAllocation<'a, 'tcx, Tag, Extra> { + RenderAllocation { tcx, alloc } +} + +#[doc(hidden)] +pub struct RenderAllocation<'a, 'tcx, Tag, Extra> { + tcx: TyCtxt<'tcx>, + alloc: &'a Allocation, +} + +impl std::fmt::Display for RenderAllocation<'a, 'tcx, Tag, Extra> { + fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let RenderAllocation { tcx, alloc } = *self; + write!(w, "size: {}, align: {})", alloc.size().bytes(), alloc.align.bytes())?; + if alloc.size() == Size::ZERO { + // We are done. + return write!(w, " {{}}"); + } + // Write allocation bytes. + writeln!(w, " {{")?; + write_allocation_bytes(tcx, alloc, w, " ")?; + write!(w, "}}")?; + Ok(()) + } +} + +fn write_allocation_endline(w: &mut dyn std::fmt::Write, ascii: &str) -> std::fmt::Result { + for _ in 0..(BYTES_PER_LINE - ascii.chars().count()) { + write!(w, " ")?; + } + writeln!(w, " │ {}", ascii) +} + +/// Number of bytes to print per allocation hex dump line. +const BYTES_PER_LINE: usize = 16; + +/// Prints the line start address and returns the new line start address. +fn write_allocation_newline( + w: &mut dyn std::fmt::Write, + mut line_start: Size, + ascii: &str, + pos_width: usize, + prefix: &str, +) -> Result { + write_allocation_endline(w, ascii)?; + line_start += Size::from_bytes(BYTES_PER_LINE); + write!(w, "{}0x{:02$x} │ ", prefix, line_start.bytes(), pos_width)?; + Ok(line_start) +} + +/// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there +/// is only one line). Note that your prefix should contain a trailing space as the lines are +/// printed directly after it. +fn write_allocation_bytes( + tcx: TyCtxt<'tcx>, + alloc: &Allocation, + w: &mut dyn std::fmt::Write, + prefix: &str, +) -> std::fmt::Result { + let num_lines = alloc.size().bytes_usize().saturating_sub(BYTES_PER_LINE); + // Number of chars needed to represent all line numbers. + let pos_width = hex_number_length(alloc.size().bytes()); + + if num_lines > 0 { + write!(w, "{}0x{:02$x} │ ", prefix, 0, pos_width)?; + } else { + write!(w, "{}", prefix)?; + } + + let mut i = Size::ZERO; + let mut line_start = Size::ZERO; + + let ptr_size = tcx.data_layout.pointer_size; + + let mut ascii = String::new(); + + let oversized_ptr = |target: &mut String, width| { + if target.len() > width { + write!(target, " ({} ptr bytes)", ptr_size.bytes()).unwrap(); + } + }; + + while i < alloc.size() { + // The line start already has a space. While we could remove that space from the line start + // printing and unconditionally print a space here, that would cause the single-line case + // to have a single space before it, which looks weird. + if i != line_start { + write!(w, " ")?; + } + if let Some(&tag) = alloc.relocations().get(&i) { + // Memory with a relocation must be defined + let j = i.bytes_usize(); + let offset = alloc + .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize()); + let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap(); + let offset = Size::from_bytes(offset); + let relocation_width = |bytes| bytes * 3; + let ptr = Pointer::new(tag, offset); + let mut target = format!("{:?}", ptr); + if target.len() > relocation_width(ptr_size.bytes_usize() - 1) { + // This is too long, try to save some space. + target = format!("{:#?}", ptr); + } + if ((i - line_start) + ptr_size).bytes_usize() > BYTES_PER_LINE { + // This branch handles the situation where a relocation starts in the current line + // but ends in the next one. + let remainder = Size::from_bytes(BYTES_PER_LINE) - (i - line_start); + let overflow = ptr_size - remainder; + let remainder_width = relocation_width(remainder.bytes_usize()) - 2; + let overflow_width = relocation_width(overflow.bytes_usize() - 1) + 1; + ascii.push('╾'); + for _ in 0..remainder.bytes() - 1 { + ascii.push('─'); + } + if overflow_width > remainder_width && overflow_width >= target.len() { + // The case where the relocation fits into the part in the next line + write!(w, "╾{0:─^1$}", "", remainder_width)?; + line_start = + write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; + ascii.clear(); + write!(w, "{0:─^1$}╼", target, overflow_width)?; + } else { + oversized_ptr(&mut target, remainder_width); + write!(w, "╾{0:─^1$}", target, remainder_width)?; + line_start = + write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; + write!(w, "{0:─^1$}╼", "", overflow_width)?; + ascii.clear(); + } + for _ in 0..overflow.bytes() - 1 { + ascii.push('─'); + } + ascii.push('╼'); + i += ptr_size; + continue; + } else { + // This branch handles a relocation that starts and ends in the current line. + let relocation_width = relocation_width(ptr_size.bytes_usize() - 1); + oversized_ptr(&mut target, relocation_width); + ascii.push('╾'); + write!(w, "╾{0:─^1$}╼", target, relocation_width)?; + for _ in 0..ptr_size.bytes() - 2 { + ascii.push('─'); + } + ascii.push('╼'); + i += ptr_size; + } + } else if alloc.init_mask().is_range_initialized(i, i + Size::from_bytes(1)).is_ok() { + let j = i.bytes_usize(); + + // Checked definedness (and thus range) and relocations. This access also doesn't + // influence interpreter execution but is only for debugging. + let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0]; + write!(w, "{:02x}", c)?; + if c.is_ascii_control() || c >= 0x80 { + ascii.push('.'); + } else { + ascii.push(char::from(c)); + } + i += Size::from_bytes(1); + } else { + write!(w, "__")?; + ascii.push('░'); + i += Size::from_bytes(1); + } + // Print a new line header if the next line still has some bytes to print. + if i == line_start + Size::from_bytes(BYTES_PER_LINE) && i != alloc.size() { + line_start = write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; + ascii.clear(); + } + } + write_allocation_endline(w, &ascii)?; + + Ok(()) +} + +fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Result<()> { + use rustc_hir::def::DefKind; + + trace!("write_mir_sig: {:?}", body.source.instance); + let def_id = body.source.def_id(); + let kind = tcx.def_kind(def_id); + let is_function = match kind { + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, + _ => tcx.is_closure(def_id), + }; + match (kind, body.source.promoted) { + (_, Some(i)) => write!(w, "{:?} in ", i)?, + (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?, + (DefKind::Static, _) => { + write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })? + } + (_, _) if is_function => write!(w, "fn ")?, + (DefKind::AnonConst, _) => {} // things like anon const, not an item + _ => bug!("Unexpected def kind {:?}", kind), + } + + ty::print::with_forced_impl_filename_line(|| { + // see notes on #41697 elsewhere + write!(w, "{}", tcx.def_path_str(def_id)) + })?; + + if body.source.promoted.is_none() && is_function { + write!(w, "(")?; + + // fn argument types. + for (i, arg) in body.args_iter().enumerate() { + if i != 0 { + write!(w, ", ")?; + } + write!(w, "{:?}: {}", Place::from(arg), body.local_decls[arg].ty)?; + } + + write!(w, ") -> {}", body.return_ty())?; + } else { + assert_eq!(body.arg_count, 0); + write!(w, ": {} =", body.return_ty())?; + } + + if let Some(yield_ty) = body.yield_ty() { + writeln!(w)?; + writeln!(w, "yields {}", yield_ty)?; + } + + write!(w, " ")?; + // Next thing that gets printed is the opening { + + Ok(()) +} + +fn write_user_type_annotations( + tcx: TyCtxt<'_>, + body: &Body<'_>, + w: &mut dyn Write, +) -> io::Result<()> { + if !body.user_type_annotations.is_empty() { + writeln!(w, "| User Type Annotations")?; + } + for (index, annotation) in body.user_type_annotations.iter_enumerated() { + writeln!( + w, + "| {:?}: {:?} at {}", + index.index(), + annotation.user_ty, + tcx.sess.source_map().span_to_embeddable_string(annotation.span) + )?; + } + if !body.user_type_annotations.is_empty() { + writeln!(w, "|")?; + } + Ok(()) +} + +pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { + if let Some(i) = single { + vec![i] + } else { + tcx.mir_keys(()).iter().map(|def_id| def_id.to_def_id()).collect() + } +} + +/// Calc converted u64 decimal into hex and return it's length in chars +/// +/// ```ignore (cannot-test-private-function) +/// assert_eq!(1, hex_number_length(0)); +/// assert_eq!(1, hex_number_length(1)); +/// assert_eq!(2, hex_number_length(16)); +/// ``` +fn hex_number_length(x: u64) -> usize { + if x == 0 { + return 1; + } + let mut length = 0; + let mut x_left = x; + while x_left > 0 { + x_left /= 16; + length += 1; + } + length +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/query.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/query.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/query.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/query.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ //! Values computed by queries that use MIR. -use crate::mir::{abstract_const, Body, Promoted}; +use crate::mir::{Body, Promoted}; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; @@ -219,7 +219,7 @@ /// The result of the `mir_const_qualif` query. /// /// Each field (except `error_occured`) corresponds to an implementer of the `Qualif` trait in -/// `rustc_mir/src/transform/check_consts/qualifs.rs`. See that file for more information on each +/// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each /// `Qualif`. #[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)] pub struct ConstQualifs { @@ -309,11 +309,14 @@ pub category: ConstraintCategory, } +// Make sure this enum doesn't unintentionally grow +rustc_data_structures::static_assert_size!(ConstraintCategory, 12); + /// Outlives-constraints can be categorized to determine whether and why they /// are interesting (for error reporting). Order of variants indicates sort /// order of the category, thereby influencing diagnostic output. /// -/// See also `rustc_mir::borrow_check::constraints`. +/// See also `rustc_const_eval::borrow_check::constraints`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(TyEncodable, TyDecodable, HashStable)] pub enum ConstraintCategory { @@ -332,17 +335,20 @@ CopyBound, SizedBound, Assignment, + /// A constraint that came from a usage of a variable (e.g. in an ADT expression + /// like `Foo { field: my_val }`) + Usage, OpaqueType, ClosureUpvar(hir::HirId), + /// A constraint from a user-written predicate + /// with the provided span, written on the item + /// with the given `DefId` + Predicate(Span), + /// A "boring" constraint (caused by the given location) is one that /// the user probably doesn't want to see described in diagnostics, /// because it is kind of an artifact of the type system setup. - /// Example: `x = Foo { field: y }` technically creates - /// intermediate regions representing the "type of `Foo { field: y - /// }`", and data flows from `y` into those variables, but they - /// are not very interesting. The assignment into `x` on the other - /// hand might be. Boring, // Boring and applicable everywhere. BoringNoLocation, @@ -431,16 +437,4 @@ self.mir_for_ctfe(def.did) } } - - #[inline] - pub fn mir_abstract_const_opt_const_arg( - self, - def: ty::WithOptConstParam, - ) -> Result]>, ErrorReported> { - if let Some((did, param_did)) = def.as_const_arg() { - self.mir_abstract_const_of_const_arg((did, param_did)) - } else { - self.mir_abstract_const(def.did) - } - } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/spanview.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/spanview.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/spanview.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/spanview.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,693 @@ +use rustc_hir::def_id::DefId; +use rustc_middle::hir; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::MirSpanview; +use rustc_span::{BytePos, Pos, Span, SyntaxContext}; + +use std::cmp; +use std::io::{self, Write}; + +pub const TOOLTIP_INDENT: &str = " "; + +const CARET: char = '\u{2038}'; // Unicode `CARET` +const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET +const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` +const NEW_LINE_SPAN: &str = "
\n"; +const HEADER: &str = r#" + +"#; +const START_BODY: &str = r#" +"#; +const FOOTER: &str = r#" +"#; + +const STYLE_SECTION: &str = r#""#; + +/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. +#[derive(Clone, Debug)] +pub struct SpanViewable { + pub bb: BasicBlock, + pub span: Span, + pub id: String, + pub tooltip: String, +} + +/// Write a spanview HTML+CSS file to analyze MIR element spans. +pub fn write_mir_fn_spanview<'tcx, W>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + spanview: MirSpanview, + title: &str, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let def_id = body.source.def_id(); + let hir_body = hir_body(tcx, def_id); + if hir_body.is_none() { + return Ok(()); + } + let body_span = hir_body.unwrap().value.span; + let mut span_viewables = Vec::new(); + for (bb, data) in body.basic_blocks().iter_enumerated() { + match spanview { + MirSpanview::Statement => { + for (i, statement) in data.statements.iter().enumerate() { + if let Some(span_viewable) = + statement_span_viewable(tcx, body_span, bb, i, statement) + { + span_viewables.push(span_viewable); + } + } + if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + MirSpanview::Terminator => { + if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + MirSpanview::Block => { + if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + } + } + write_document(tcx, fn_span(tcx, def_id), span_viewables, title, w)?; + Ok(()) +} + +/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated +/// list `SpanViewable`s. +pub fn write_document<'tcx, W>( + tcx: TyCtxt<'tcx>, + spanview_span: Span, + mut span_viewables: Vec, + title: &str, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let mut from_pos = spanview_span.lo(); + let end_pos = spanview_span.hi(); + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(from_pos); + let indent_to_initial_start_col = " ".repeat(start.col.to_usize()); + debug!( + "spanview_span={:?}; source is:\n{}{}", + spanview_span, + indent_to_initial_start_col, + source_map.span_to_snippet(spanview_span).expect("function should have printable source") + ); + writeln!(w, "{}", HEADER)?; + writeln!(w, "{}", title)?; + writeln!(w, "{}", STYLE_SECTION)?; + writeln!(w, "{}", START_BODY)?; + write!( + w, + r#"
{}"#, + start.line - 1, + indent_to_initial_start_col, + )?; + span_viewables.sort_unstable_by(|a, b| { + let a = a.span; + let b = b.span; + if a.lo() == b.lo() { + // Sort hi() in reverse order so shorter spans are attempted after longer spans. + // This should give shorter spans a higher "layer", so they are not covered by + // the longer spans. + b.hi().partial_cmp(&a.hi()) + } else { + a.lo().partial_cmp(&b.lo()) + } + .unwrap() + }); + let mut ordered_viewables = &span_viewables[..]; + const LOWEST_VIEWABLE_LAYER: usize = 1; + let mut alt = false; + while ordered_viewables.len() > 0 { + debug!( + "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}", + from_pos.to_usize(), + end_pos.to_usize(), + ordered_viewables.len() + ); + let curr_id = &ordered_viewables[0].id; + let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps( + tcx, + from_pos, + end_pos, + ordered_viewables, + alt, + LOWEST_VIEWABLE_LAYER, + w, + )?; + debug!( + "DONE calling write_next_viewable, with new from_pos={}, \ + and remaining viewables len={}", + next_from_pos.to_usize(), + next_ordered_viewables.len() + ); + assert!( + from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(), + "write_next_viewable_with_overlaps() must make a state change" + ); + from_pos = next_from_pos; + if next_ordered_viewables.len() != ordered_viewables.len() { + ordered_viewables = next_ordered_viewables; + if let Some(next_ordered_viewable) = ordered_viewables.first() { + if &next_ordered_viewable.id != curr_id { + alt = !alt; + } + } + } + } + if from_pos < end_pos { + write_coverage_gap(tcx, from_pos, end_pos, w)?; + } + writeln!(w, r#"
"#)?; + writeln!(w, "{}", FOOTER)?; + Ok(()) +} + +/// Format a string showing the start line and column, and end line and column within a file. +pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String { + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(span.lo()); + let end = source_map.lookup_char_pos(span.hi()); + format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1) +} + +pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { + use StatementKind::*; + match statement.kind { + Assign(..) => "Assign", + FakeRead(..) => "FakeRead", + SetDiscriminant { .. } => "SetDiscriminant", + StorageLive(..) => "StorageLive", + StorageDead(..) => "StorageDead", + LlvmInlineAsm(..) => "LlvmInlineAsm", + Retag(..) => "Retag", + AscribeUserType(..) => "AscribeUserType", + Coverage(..) => "Coverage", + CopyNonOverlapping(..) => "CopyNonOverlapping", + Nop => "Nop", + } +} + +pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { + use TerminatorKind::*; + match term.kind { + Goto { .. } => "Goto", + SwitchInt { .. } => "SwitchInt", + Resume => "Resume", + Abort => "Abort", + Return => "Return", + Unreachable => "Unreachable", + Drop { .. } => "Drop", + DropAndReplace { .. } => "DropAndReplace", + Call { .. } => "Call", + Assert { .. } => "Assert", + Yield { .. } => "Yield", + GeneratorDrop => "GeneratorDrop", + FalseEdge { .. } => "FalseEdge", + FalseUnwind { .. } => "FalseUnwind", + InlineAsm { .. } => "InlineAsm", + } +} + +fn statement_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + i: usize, + statement: &Statement<'tcx>, +) -> Option { + let span = statement.source_info.span; + if !body_span.contains(span) { + return None; + } + let id = format!("{}[{}]", bb.index(), i); + let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None); + Some(SpanViewable { bb, span, id, tooltip }) +} + +fn terminator_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + data: &BasicBlockData<'tcx>, +) -> Option { + let term = data.terminator(); + let span = term.source_info.span; + if !body_span.contains(span) { + return None; + } + let id = format!("{}:{}", bb.index(), terminator_kind_name(term)); + let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); + Some(SpanViewable { bb, span, id, tooltip }) +} + +fn block_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + data: &BasicBlockData<'tcx>, +) -> Option { + let span = compute_block_span(data, body_span); + if !body_span.contains(span) { + return None; + } + let id = format!("{}", bb.index()); + let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator); + Some(SpanViewable { bb, span, id, tooltip }) +} + +fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span { + let mut span = data.terminator().source_info.span; + for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { + // Only combine Spans from the root context, and within the function's body_span. + if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) { + span = span.to(statement_span); + } + } + span +} + +/// Recursively process each ordered span. Spans that overlap will have progressively varying +/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will +/// have alternating style choices, to help distinguish between them if, visually adjacent. +/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true +/// and false, for each adjacent non-overlapping span. Source code between the spans (code +/// that is not in any coverage region) has neutral styling. +fn write_next_viewable_with_overlaps<'tcx, 'b, W>( + tcx: TyCtxt<'tcx>, + mut from_pos: BytePos, + mut to_pos: BytePos, + ordered_viewables: &'b [SpanViewable], + alt: bool, + layer: usize, + w: &mut W, +) -> io::Result<(BytePos, &'b [SpanViewable])> +where + W: Write, +{ + let debug_indent = " ".repeat(layer); + let (viewable, mut remaining_viewables) = + ordered_viewables.split_first().expect("ordered_viewables should have some"); + + if from_pos < viewable.span.lo() { + debug!( + "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \ + of {:?}), with to_pos={}", + debug_indent, + from_pos.to_usize(), + viewable.span.lo().to_usize(), + viewable.span, + to_pos.to_usize() + ); + let hi = cmp::min(viewable.span.lo(), to_pos); + write_coverage_gap(tcx, from_pos, hi, w)?; + from_pos = hi; + if from_pos < viewable.span.lo() { + debug!( + "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}", + debug_indent, + from_pos.to_usize() + ); + return Ok((from_pos, ordered_viewables)); + } + } + + if from_pos < viewable.span.hi() { + // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing + // with room to print the tail. + to_pos = cmp::min(viewable.span.hi(), to_pos); + debug!( + "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}", + debug_indent, + viewable.span.hi().to_usize(), + to_pos.to_usize() + ); + } + + let mut subalt = false; + while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) { + let overlapping_viewable = &remaining_viewables[0]; + debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span); + + let span = + trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos)); + let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() { + // `viewable` is not yet fully rendered, so start writing the span, up to either the + // `to_pos` or the next `overlapping_viewable`, whichever comes first. + debug!( + "{}make html_snippet (may not write it if early exit) for partial span {:?} \ + of viewable.span {:?}", + debug_indent, span, viewable.span + ); + from_pos = span.hi(); + make_html_snippet(tcx, span, Some(&viewable)) + } else { + None + }; + + // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans. + // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early + // exit, there should be another opportunity to write the tail marker. + if !span.is_empty() { + if let Some(ref html_snippet) = some_html_snippet { + debug!( + "{}write html_snippet for that partial span of viewable.span {:?}", + debug_indent, viewable.span + ); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + some_html_snippet = None; + } + + if from_pos < overlapping_viewable.span.lo() { + debug!( + "{}EARLY RETURN: from_pos={} has not yet reached the \ + overlapping_viewable.span {:?}", + debug_indent, + from_pos.to_usize(), + overlapping_viewable.span + ); + // must have reached `to_pos` before reaching the start of the + // `overlapping_viewable.span` + return Ok((from_pos, ordered_viewables)); + } + + if from_pos == to_pos + && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty()) + { + debug!( + "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \ + empty, or not from_pos", + debug_indent, + to_pos.to_usize(), + overlapping_viewable.span + ); + // `to_pos` must have occurred before the overlapping viewable. Return + // `ordered_viewables` so we can continue rendering the `viewable`, from after the + // `to_pos`. + return Ok((from_pos, ordered_viewables)); + } + + if let Some(ref html_snippet) = some_html_snippet { + debug!( + "{}write html_snippet for that partial span of viewable.span {:?}", + debug_indent, viewable.span + ); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + + debug!( + "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \ + and viewables len={}", + debug_indent, + from_pos.to_usize(), + to_pos.to_usize(), + remaining_viewables.len() + ); + // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`. + let curr_id = &remaining_viewables[0].id; + let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps( + tcx, + from_pos, + to_pos, + &remaining_viewables, + subalt, + layer + 1, + w, + )?; + debug!( + "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \ + viewables len={}", + debug_indent, + next_from_pos.to_usize(), + next_remaining_viewables.len() + ); + assert!( + from_pos != next_from_pos + || remaining_viewables.len() != next_remaining_viewables.len(), + "write_next_viewable_with_overlaps() must make a state change" + ); + from_pos = next_from_pos; + if next_remaining_viewables.len() != remaining_viewables.len() { + remaining_viewables = next_remaining_viewables; + if let Some(next_ordered_viewable) = remaining_viewables.first() { + if &next_ordered_viewable.id != curr_id { + subalt = !subalt; + } + } + } + } + if from_pos <= viewable.span.hi() { + let span = trim_span(viewable.span, from_pos, to_pos); + debug!( + "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}", + debug_indent, span, viewable.span + ); + if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(&viewable)) { + from_pos = span.hi(); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + } + debug!("{}RETURN: No more overlap", debug_indent); + Ok(( + from_pos, + if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables }, + )) +} + +#[inline(always)] +fn write_coverage_gap<'tcx, W>( + tcx: TyCtxt<'tcx>, + lo: BytePos, + hi: BytePos, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let span = Span::with_root_ctxt(lo, hi); + if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) { + write_span(html_snippet, "", false, 0, w) + } else { + Ok(()) + } +} + +fn write_span( + html_snippet: &str, + tooltip: &str, + alt: bool, + layer: usize, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let maybe_alt_class = if layer > 0 { + if alt { " odd" } else { " even" } + } else { + "" + }; + let maybe_title_attr = if !tooltip.is_empty() { + format!(" title=\"{}\"", escape_attr(tooltip)) + } else { + "".to_owned() + }; + if layer == 1 { + write!(w, "")?; + } + for (i, line) in html_snippet.lines().enumerate() { + if i > 0 { + write!(w, "{}", NEW_LINE_SPAN)?; + } + write!( + w, + r#"{}"#, + maybe_alt_class, layer, maybe_title_attr, line + )?; + } + // Check for and translate trailing newlines, because `str::lines()` ignores them + if html_snippet.ends_with('\n') { + write!(w, "{}", NEW_LINE_SPAN)?; + } + if layer == 1 { + write!(w, "")?; + } + Ok(()) +} + +fn make_html_snippet<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + some_viewable: Option<&SpanViewable>, +) -> Option { + let source_map = tcx.sess.source_map(); + let snippet = source_map + .span_to_snippet(span) + .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); + let html_snippet = if let Some(viewable) = some_viewable { + let is_head = span.lo() == viewable.span.lo(); + let is_tail = span.hi() == viewable.span.hi(); + let mut labeled_snippet = if is_head { + format!(r#"{}{}"#, viewable.id, ANNOTATION_LEFT_BRACKET) + } else { + "".to_owned() + }; + if span.is_empty() { + if is_head && is_tail { + labeled_snippet.push(CARET); + } + } else { + labeled_snippet.push_str(&escape_html(&snippet)); + }; + if is_tail { + labeled_snippet.push_str(&format!( + r#"{}{}"#, + ANNOTATION_RIGHT_BRACKET, viewable.id + )); + } + labeled_snippet + } else { + escape_html(&snippet) + }; + if html_snippet.is_empty() { None } else { Some(html_snippet) } +} + +fn tooltip<'tcx>( + tcx: TyCtxt<'tcx>, + spanview_id: &str, + span: Span, + statements: Vec>, + terminator: &Option>, +) -> String { + let source_map = tcx.sess.source_map(); + let mut text = Vec::new(); + text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span))); + for statement in statements { + let source_range = source_range_no_file(tcx, &statement.source_info.span); + text.push(format!( + "\n{}{}: {}: {}", + TOOLTIP_INDENT, + source_range, + statement_kind_name(&statement), + format!("{:?}", statement) + )); + } + if let Some(term) = terminator { + let source_range = source_range_no_file(tcx, &term.source_info.span); + text.push(format!( + "\n{}{}: {}: {:?}", + TOOLTIP_INDENT, + source_range, + terminator_kind_name(term), + term.kind + )); + } + text.join("") +} + +fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span { + trim_span_hi(trim_span_lo(span, from_pos), to_pos) +} + +fn trim_span_lo(span: Span, from_pos: BytePos) -> Span { + if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) } +} + +fn trim_span_hi(span: Span, to_pos: BytePos) -> Span { + if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) } +} + +fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { + let hir_id = + tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); + let fn_decl_span = tcx.hir().span(hir_id); + if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) { + if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span } + } else { + fn_decl_span + } +} + +fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<&'tcx rustc_hir::Body<'tcx>> { + let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); + hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id)) +} + +fn escape_html(s: &str) -> String { + s.replace("&", "&").replace("<", "<").replace(">", ">") +} + +fn escape_attr(s: &str) -> String { + s.replace("&", "&") + .replace("\"", """) + .replace("'", "'") + .replace("<", "<") + .replace(">", ">") +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/tcx.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/tcx.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/tcx.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/tcx.rs 2021-11-29 19:27:11.000000000 +0000 @@ -196,7 +196,7 @@ Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t), - Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize, + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))), @@ -206,6 +206,7 @@ tcx.mk_generator(did, substs, movability) } }, + Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty), } } @@ -214,7 +215,9 @@ /// whether its only shallowly initialized (`Rvalue::Box`). pub fn initialization_state(&self) -> RvalueInitializationState { match *self { - Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow, + Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => { + RvalueInitializationState::Shallow + } _ => RvalueInitializationState::Deep, } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/type_foldable.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/type_foldable.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/type_foldable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/type_foldable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -210,6 +210,7 @@ }); Aggregate(kind, fields.fold_with(folder)) } + ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)), } } @@ -255,6 +256,10 @@ } fields.visit_with(visitor) } + ShallowInitBox(ref op, ty) => { + op.visit_with(visitor)?; + ty.visit_with(visitor) + } } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/visit.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/visit.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/mir/visit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/mir/visit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -348,7 +348,7 @@ ty::InstanceDef::VtableShim(_def_id) | ty::InstanceDef::ReifyShim(_def_id) | ty::InstanceDef::Virtual(_def_id, _) | - ty::InstanceDef::ClosureOnceShim { call_once: _def_id } | + ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | @@ -753,6 +753,11 @@ self.visit_operand(operand, location); } } + + Rvalue::ShallowInitBox(operand, ty) => { + self.visit_operand(operand, location); + self.visit_ty(ty, TyContext::Location(location)); + } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/query/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/query/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/query/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/query/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -20,6 +20,14 @@ desc { "get the resolver outputs" } } + /// Return the span for a definition. + /// Contrary to `def_span` below, this query returns the full absolute span of the definition. + /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside + /// of rustc_middle::hir::source_map. + query source_span(key: LocalDefId) -> Span { + desc { "get the source span" } + } + /// Represents crate as a whole (as distinct from the top-level crate module). /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), /// we will have to assume that any change means that you need to be recompiled. @@ -44,8 +52,8 @@ /// /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. /// Avoid calling this query directly. - query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems { - eval_always + query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems { + storage(ArenaCacheSelector<'tcx>) desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -295,17 +303,17 @@ } /// Try to build an abstract representation of the given constant. - query mir_abstract_const( + query thir_abstract_const( key: DefId - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for {}", tcx.def_path_str(key), } } /// Try to build an abstract representation of the given constant. - query mir_abstract_const_of_const_arg( + query thir_abstract_const_of_const_arg( key: (LocalDefId, DefId) - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for the const argument {}", @@ -544,14 +552,6 @@ desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } } - /// Returns `true` if this is a const `impl`. **Do not call this function manually.** - /// - /// This query caches the base data for the `is_const_impl` helper function, which also - /// takes into account stability attributes (e.g., `#[rustc_const_unstable]`). - query is_const_impl_raw(key: DefId) -> bool { - desc { |tcx| "checking if item is const impl: `{}`", tcx.def_path_str(key) } - } - query asyncness(key: DefId) -> hir::IsAsync { desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } } @@ -599,7 +599,7 @@ desc { "computing the inferred outlives predicates for items in this crate" } } - /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items. + /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items. query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } } @@ -996,6 +996,12 @@ desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } } + query own_existential_vtable_entries( + key: ty::PolyExistentialTraitRef<'tcx> + ) -> &'tcx [DefId] { + desc { |tcx| "finding all existential vtable entries for trait {}", tcx.def_path_str(key.def_id()) } + } + query vtable_entries(key: ty::PolyTraitRef<'tcx>) -> &'tcx [ty::VtblEntry<'tcx>] { desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) } @@ -1129,6 +1135,27 @@ desc { "computing layout of `{}`", key.value } } + /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. + /// + /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance` + /// instead, where the instance is an `InstanceDef::Virtual`. + query fn_abi_of_fn_ptr( + key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List>)> + ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { + desc { "computing call ABI of `{}` function pointers", key.value.0 } + } + + /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for + /// direct calls to an `fn`. + /// + /// NB: that includes virtual calls, which are represented by "direct calls" + /// to an `InstanceDef::Virtual` instance (of `::fn`). + query fn_abi_of_instance( + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List>)> + ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { + desc { "computing call ABI of `{}`", key.value.0 } + } + query dylib_dependency_formats(_: CrateNum) -> &'tcx [(CrateNum, LinkagePreference)] { desc { "dylib dependency formats of crate" } @@ -1160,6 +1187,10 @@ fatal_cycle desc { "query a crate's configured panic strategy" } } + query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy { + fatal_cycle + desc { "query a crate's configured panic-in-drop strategy" } + } query is_no_builtins(_: CrateNum) -> bool { fatal_cycle desc { "test whether a crate has `#![no_builtins]`" } @@ -1182,7 +1213,7 @@ desc { "traits in scope at a block" } } - query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> { + query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> { desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) } } @@ -1394,7 +1425,7 @@ eval_always desc { "fetching what a crate is named" } } - query item_children(def_id: DefId) -> &'tcx [Export] { + query item_children(def_id: DefId) -> &'tcx [Export] { desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) } } query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option { @@ -1418,7 +1449,7 @@ } /// Returns all diagnostic items defined in all crates. - query all_diagnostic_items(_: ()) -> FxHashMap { + query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems { storage(ArenaCacheSelector<'tcx>) eval_always desc { "calculating the diagnostic items map" } @@ -1430,7 +1461,7 @@ } /// Returns the diagnostic items defined in a crate. - query diagnostic_items(_: CrateNum) -> FxHashMap { + query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems { storage(ArenaCacheSelector<'tcx>) desc { "calculating the diagnostic items map in a crate" } } @@ -1527,11 +1558,11 @@ query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } - query unused_generic_params(key: DefId) -> FiniteBitSet { - cache_on_disk_if { key.is_local() } + query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet { + cache_on_disk_if { key.def_id().is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", - tcx.def_path_str(key) + tcx.def_path_str(key.def_id()) } } query backend_optimization_level(_: ()) -> OptLevel { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/thir/abstract_const.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/thir/abstract_const.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/thir/abstract_const.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/thir/abstract_const.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,61 @@ +//! A subset of a mir body used for const evaluatability checking. +use crate::mir; +use crate::ty::{self, Ty, TyCtxt}; +use rustc_errors::ErrorReported; + +rustc_index::newtype_index! { + /// An index into an `AbstractConst`. + pub struct NodeId { + derive [HashStable] + DEBUG_FORMAT = "n{}", + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum CastKind { + /// thir::ExprKind::As + As, + /// thir::ExprKind::Use + Use, +} + +/// A node of an `AbstractConst`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum Node<'tcx> { + Leaf(&'tcx ty::Const<'tcx>), + Binop(mir::BinOp, NodeId, NodeId), + UnaryOp(mir::UnOp, NodeId), + FunctionCall(NodeId, &'tcx [NodeId]), + Cast(CastKind, NodeId, Ty<'tcx>), +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum NotConstEvaluatable { + Error(ErrorReported), + MentionsInfer, + MentionsParam, +} + +impl From for NotConstEvaluatable { + fn from(e: ErrorReported) -> NotConstEvaluatable { + NotConstEvaluatable::Error(e) + } +} + +TrivialTypeFoldableAndLiftImpls! { + NotConstEvaluatable, +} + +impl<'tcx> TyCtxt<'tcx> { + #[inline] + pub fn thir_abstract_const_opt_const_arg( + self, + def: ty::WithOptConstParam, + ) -> Result]>, ErrorReported> { + if let Some((did, param_did)) = def.as_const_arg() { + self.thir_abstract_const_of_const_arg((did, param_did)) + } else { + self.thir_abstract_const(def.did) + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/thir/visit.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/thir/visit.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/thir/visit.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/thir/visit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,242 @@ +use super::{ + Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, +}; +use rustc_middle::ty::Const; + +pub trait Visitor<'a, 'tcx: 'a>: Sized { + fn thir(&self) -> &'a Thir<'tcx>; + + fn visit_expr(&mut self, expr: &Expr<'tcx>) { + walk_expr(self, expr); + } + + fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { + walk_stmt(self, stmt); + } + + fn visit_block(&mut self, block: &Block) { + walk_block(self, block); + } + + fn visit_arm(&mut self, arm: &Arm<'tcx>) { + walk_arm(self, arm); + } + + fn visit_pat(&mut self, pat: &Pat<'tcx>) { + walk_pat(self, pat); + } + + fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} +} + +pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { + use ExprKind::*; + match expr.kind { + Scope { value, region_scope: _, lint_level: _ } => { + visitor.visit_expr(&visitor.thir()[value]) + } + Box { value } => visitor.visit_expr(&visitor.thir()[value]), + If { cond, then, else_opt, if_then_scope: _ } => { + visitor.visit_expr(&visitor.thir()[cond]); + visitor.visit_expr(&visitor.thir()[then]); + if let Some(else_expr) = else_opt { + visitor.visit_expr(&visitor.thir()[else_expr]); + } + } + Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { + visitor.visit_expr(&visitor.thir()[fun]); + for &arg in &**args { + visitor.visit_expr(&visitor.thir()[arg]); + } + } + Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), + Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Cast { source } => visitor.visit_expr(&visitor.thir()[source]), + Use { source } => visitor.visit_expr(&visitor.thir()[source]), + NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), + Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + Let { expr, .. } => { + visitor.visit_expr(&visitor.thir()[expr]); + } + Loop { body } => visitor.visit_expr(&visitor.thir()[body]), + Match { scrutinee, ref arms } => { + visitor.visit_expr(&visitor.thir()[scrutinee]); + for &arm in &**arms { + visitor.visit_arm(&visitor.thir()[arm]); + } + } + Block { ref body } => visitor.visit_block(body), + Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), + Index { lhs, index } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[index]); + } + VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} + Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), + AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Break { value, label: _ } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + Continue { label: _ } => {} + Return { value } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + ConstBlock { value } => visitor.visit_const(value), + Repeat { value, count } => { + visitor.visit_expr(&visitor.thir()[value]); + visitor.visit_const(count); + } + Array { ref fields } | Tuple { ref fields } => { + for &field in &**fields { + visitor.visit_expr(&visitor.thir()[field]); + } + } + Adt(box crate::thir::Adt { + ref fields, + ref base, + adt_def: _, + variant_index: _, + substs: _, + user_ty: _, + }) => { + for field in &**fields { + visitor.visit_expr(&visitor.thir()[field.expr]); + } + if let Some(base) = base { + visitor.visit_expr(&visitor.thir()[base.base]); + } + } + PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { + visitor.visit_expr(&visitor.thir()[source]) + } + Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} + Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), + StaticRef { literal, def_id: _ } => visitor.visit_const(literal), + InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { + for op in &**operands { + use InlineAsmOperand::*; + match op { + In { expr, reg: _ } + | Out { expr: Some(expr), reg: _, late: _ } + | InOut { expr, reg: _, late: _ } + | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), + SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + visitor.visit_expr(&visitor.thir()[*in_expr]); + if let Some(out_expr) = out_expr { + visitor.visit_expr(&visitor.thir()[*out_expr]); + } + } + Out { expr: None, reg: _, late: _ } + | Const { value: _, span: _ } + | SymStatic { def_id: _ } => {} + } + } + } + ThreadLocalRef(_) => {} + LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { + for &out_expr in &**outputs { + visitor.visit_expr(&visitor.thir()[out_expr]); + } + for &in_expr in &**inputs { + visitor.visit_expr(&visitor.thir()[in_expr]); + } + } + Yield { value } => visitor.visit_expr(&visitor.thir()[value]), + } +} + +pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { + match &stmt.kind { + StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), + StmtKind::Let { + initializer, + remainder_scope: _, + init_scope: _, + ref pattern, + lint_level: _, + } => { + if let Some(init) = initializer { + visitor.visit_expr(&visitor.thir()[*init]); + } + visitor.visit_pat(pattern); + } + } +} + +pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { + for &stmt in &*block.stmts { + visitor.visit_stmt(&visitor.thir()[stmt]); + } + if let Some(expr) = block.expr { + visitor.visit_expr(&visitor.thir()[expr]); + } +} + +pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { + match arm.guard { + Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), + Some(Guard::IfLet(ref pat, expr)) => { + visitor.visit_pat(pat); + visitor.visit_expr(&visitor.thir()[expr]); + } + None => {} + } + visitor.visit_pat(&arm.pattern); + visitor.visit_expr(&visitor.thir()[arm.body]); +} + +pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { + use PatKind::*; + match pat.kind.as_ref() { + AscribeUserType { subpattern, ascription: _ } + | Deref { subpattern } + | Binding { + subpattern: Some(subpattern), + mutability: _, + mode: _, + var: _, + ty: _, + is_primary: _, + name: _, + } => visitor.visit_pat(&subpattern), + Binding { .. } | Wild => {} + Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => { + for subpattern in subpatterns { + visitor.visit_pat(&subpattern.pattern); + } + } + Constant { value } => visitor.visit_const(value), + Range(range) => { + visitor.visit_const(range.lo); + visitor.visit_const(range.hi); + } + Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { + for subpattern in prefix { + visitor.visit_pat(&subpattern); + } + if let Some(pat) = slice { + visitor.visit_pat(pat); + } + for subpattern in suffix { + visitor.visit_pat(&subpattern); + } + } + Or { pats } => { + for pat in pats { + visitor.visit_pat(&pat); + } + } + }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/thir.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/thir.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/thir.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/thir.rs 2021-11-29 19:27:11.000000000 +0000 @@ -33,6 +33,9 @@ use std::fmt; use std::ops::Index; +pub mod abstract_const; +pub mod visit; + newtype_index! { /// An index to an [`Arm`] stored in [`Thir::arms`] #[derive(HashStable)] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ mod structural_impls; use crate::infer::canonical::Canonical; -use crate::mir::abstract_const::NotConstEvaluatable; +use crate::thir::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; use crate::ty::{self, AdtKind, Ty, TyCtxt}; @@ -253,6 +253,15 @@ DerivedObligation(DerivedObligationCause<'tcx>), + FunctionArgumentObligation { + /// The node of the relevant argument in the function call. + arg_hir_id: hir::HirId, + /// The node of the function call. + call_hir_id: hir::HirId, + /// The obligation introduced by this argument. + parent_code: Lrc>, + }, + /// Error derived when matching traits/impls; see ObligationCause for more details CompareImplConstObligation, @@ -340,7 +349,7 @@ WellFormed(Option), /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against. - MatchImpl(Lrc>, DefId), + MatchImpl(ObligationCause<'tcx>, DefId), } /// The 'location' at which we try to perform HIR-based wf checking. @@ -368,11 +377,12 @@ // Return the base obligation, ignoring derived obligations. pub fn peel_derives(&self) -> &Self { let mut base_cause = self; - while let BuiltinDerivedObligation(cause) - | ImplDerivedObligation(cause) - | DerivedObligation(cause) = base_cause + while let BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. }) + | ImplDerivedObligation(DerivedObligationCause { parent_code, .. }) + | DerivedObligation(DerivedObligationCause { parent_code, .. }) + | FunctionArgumentObligation { parent_code, .. } = base_cause { - base_cause = &cause.parent_code; + base_cause = &parent_code; } base_cause } @@ -439,6 +449,7 @@ TraitNotObjectSafe(DefId), NotConstEvaluatable(NotConstEvaluatable), Overflow, + ErrorReporting, } /// When performing resolution, it is typically the case that there @@ -529,6 +540,9 @@ /// ImplSource for a trait alias. TraitAlias(ImplSourceTraitAliasData<'tcx, N>), + + /// ImplSource for a `const Drop` implementation. + ConstDrop(ImplSourceConstDropData), } impl<'tcx, N> ImplSource<'tcx, N> { @@ -543,7 +557,8 @@ ImplSource::Object(d) => d.nested, ImplSource::FnPointer(d) => d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(), + | ImplSource::Pointee(ImplSourcePointeeData) + | ImplSource::ConstDrop(ImplSourceConstDropData) => Vec::new(), ImplSource::TraitAlias(d) => d.nested, ImplSource::TraitUpcasting(d) => d.nested, } @@ -560,7 +575,8 @@ ImplSource::Object(d) => &d.nested[..], ImplSource::FnPointer(d) => &d.nested[..], ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) => &[], + | ImplSource::Pointee(ImplSourcePointeeData) + | ImplSource::ConstDrop(ImplSourceConstDropData) => &[], ImplSource::TraitAlias(d) => &d.nested[..], ImplSource::TraitUpcasting(d) => &d.nested[..], } @@ -621,6 +637,9 @@ nested: d.nested.into_iter().map(f).collect(), }) } + ImplSource::ConstDrop(ImplSourceConstDropData) => { + ImplSource::ConstDrop(ImplSourceConstDropData) + } } } } @@ -712,6 +731,9 @@ #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub struct ImplSourcePointeeData; +#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] +pub struct ImplSourceConstDropData; + #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] pub struct ImplSourceTraitAliasData<'tcx, N> { pub alias_def_id: DefId, @@ -719,7 +741,7 @@ pub nested: Vec, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum ObjectSafetyViolation { /// `Self: Sized` declared on the trait. SizedSelf(SmallVec<[Span; 1]>), @@ -868,7 +890,7 @@ } /// Reasons a method might not be object-safe. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum MethodViolationCode { /// e.g., `fn foo()` StaticMethod(Option<(&'static str, Span)>, Span, bool /* has args */), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/query.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/query.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/query.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/query.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,6 @@ //! The providers for the queries defined here can be found in //! `rustc_traits`. -use crate::ich::StableHashingContext; use crate::infer::canonical::{Canonical, QueryResponse}; use crate::ty::error::TypeError; use crate::ty::subst::GenericArg; @@ -14,6 +13,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; +use rustc_query_system::ich::StableHashingContext; use rustc_span::source_map::Span; use std::iter::FromIterator; use std::mem; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/select.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/select.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/select.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/select.rs 2021-11-29 19:27:11.000000000 +0000 @@ -120,7 +120,9 @@ /// Implementation of a `Fn`-family trait by one of the anonymous /// types generated for a fn pointer type (e.g., `fn(int) -> int`) - FnPointerCandidate, + FnPointerCandidate { + is_const: bool, + }, /// Builtin implementation of `DiscriminantKind`. DiscriminantKindCandidate, @@ -143,6 +145,9 @@ BuiltinObjectCandidate, BuiltinUnsizeCandidate, + + /// Implementation of `const Drop`. + ConstDropCandidate, } /// The result of trait evaluation. The order is important @@ -256,12 +261,18 @@ } } -/// Indicates that trait evaluation caused overflow. +/// Indicates that trait evaluation caused overflow and in which pass. #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] -pub struct OverflowError; +pub enum OverflowError { + Canonical, + ErrorReporting, +} impl<'tcx> From for SelectionError<'tcx> { - fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { - SelectionError::Overflow + fn from(overflow_error: OverflowError) -> SelectionError<'tcx> { + match overflow_error { + OverflowError::Canonical => SelectionError::Overflow, + OverflowError::ErrorReporting => SelectionError::ErrorReporting, + } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/specialization_graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/specialization_graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/specialization_graph.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/specialization_graph.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,7 @@ -use crate::ich::{self, StableHashingContext}; use crate::ty::fast_reject::SimplifiedType; use crate::ty::fold::TypeFoldable; use crate::ty::{self, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorReported; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_span::symbol::Ident; @@ -50,19 +48,19 @@ /// Children of a given impl, grouped into blanket/non-blanket varieties as is /// done in `TraitDef`. -#[derive(Default, TyEncodable, TyDecodable, Debug)] +#[derive(Default, TyEncodable, TyDecodable, Debug, HashStable)] pub struct Children { // Impls of a trait (or specializations of a given impl). To allow for // quicker lookup, the impls are indexed by a simplified version of their // `Self` type: impls with a simplifiable `Self` are stored in - // `nonblanket_impls` keyed by it, while all other impls are stored in + // `non_blanket_impls` keyed by it, while all other impls are stored in // `blanket_impls`. // // A similar division is used within `TraitDef`, but the lists there collect // together *all* the impls for a trait, and are populated prior to building // the specialization graph. /// Impls of the trait. - pub nonblanket_impls: FxHashMap>, + pub non_blanket_impls: FxIndexMap>, /// Blanket impls associated with the trait. pub blanket_impls: Vec, @@ -235,11 +233,3 @@ }) } } - -impl<'a> HashStable> for Children { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Children { ref nonblanket_impls, ref blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/structural_impls.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/structural_impls.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/traits/structural_impls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/traits/structural_impls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -32,6 +32,8 @@ super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d), super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d), + + super::ImplSource::ConstDrop(ref d) => write!(f, "{:?}", d), } } } @@ -125,4 +127,5 @@ super::IfExpressionCause, super::ImplSourceDiscriminantKindData, super::ImplSourcePointeeData, + super::ImplSourceConstDropData, } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/adt.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/adt.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/adt.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/adt.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -use crate::ich::StableHashingContext; use crate::mir::interpret::ErrorHandled; use crate::ty; use crate::ty::util::{Discr, IntTypeExt}; @@ -7,9 +6,11 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorReported; +use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; +use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{self, Encodable, Encoder}; use rustc_session::DataTypeKind; use rustc_span::symbol::sym; @@ -288,6 +289,10 @@ self.destructor(tcx).is_some() } + pub fn has_non_const_dtor(&self, tcx: TyCtxt<'tcx>) -> bool { + matches!(self.destructor(tcx), Some(Destructor { constness: hir::Constness::NotConst, .. })) + } + /// Asserts this is a struct or union and returns its unique variant. pub fn non_enum_variant(&self) -> &VariantDef { assert!(self.is_struct() || self.is_union()); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/codec.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/codec.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/codec.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/codec.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -// This module contains some shared code for encoding and decoding various -// things from the `ty` module, and in particular implements support for -// "shorthands" which allow to have pointers back into the already encoded -// stream instead of re-encoding the same thing twice. -// -// The functionality in here is shared between persisting to crate metadata and -// persisting to incr. comp. caches. +//! This module contains some shared code for encoding and decoding various +//! things from the `ty` module, and in particular implements support for +//! "shorthands" which allow to have pointers back into the already encoded +//! stream instead of re-encoding the same thing twice. +//! +//! The functionality in here is shared between persisting to crate metadata and +//! persisting to incr. comp. caches. use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; @@ -12,6 +12,7 @@ self, interpret::{AllocId, Allocation}, }; +use crate::thir; use crate::ty::subst::SubstsRef; use crate::ty::{self, List, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; @@ -362,7 +363,7 @@ } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().arena.alloc_from_iter( (0..decoder.read_usize()?) @@ -372,7 +373,7 @@ } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().arena.alloc_from_iter( (0..decoder.read_usize()?) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/context.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/context.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/context.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/context.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,11 @@ //! Type context book-keeping. use crate::arena::Arena; -use crate::dep_graph::{DepGraph, DepNode}; +use crate::dep_graph::DepGraph; use crate::hir::place::Place as HirPlace; -use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle; -use crate::middle::cstore::EncodedMetadata; use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault}; use crate::middle::stability; use crate::mir::interpret::{self, Allocation, ConstValue, Scalar}; @@ -27,6 +25,7 @@ use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -45,6 +44,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; +use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; @@ -71,7 +71,7 @@ pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. - fn new(sess: &'tcx Session, data: Vec, start_pos: usize) -> Self + fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self where Self: Sized; @@ -82,23 +82,9 @@ /// 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`. - fn def_path_hash_to_def_id( - &self, - tcx: TyCtxt<'tcx>, - def_path_hash: DefPathHash, - ) -> Option; + fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, def_path_hash: DefPathHash) -> DefId; - /// If the given `dep_node`'s hash still exists in the current compilation, - /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. - /// - /// Normally, `store_foreign_def_id_hash` can be called directly by - /// the dependency graph when we construct a `DepNode`. However, - /// when we re-use a deserialized `DepNode` from the previous compilation - /// session, we only have the `DefPathHash` available. This method is used - /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written - /// out for usage in the next compilation session. - fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode); - fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash); + fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>); fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult; } @@ -115,8 +101,8 @@ /// The arena that types, regions, etc. are allocated from. arena: &'tcx WorkerLocal>, - /// Specifically use a speedy hash algorithm for these hash sets, since - /// they're accessed quite often. + // Specifically use a speedy hash algorithm for these hash sets, since + // they're accessed quite often. type_: InternedSet<'tcx, TyS<'tcx>>, type_list: InternedSet<'tcx, List>>, substs: InternedSet<'tcx, InternalSubsts<'tcx>>, @@ -129,9 +115,9 @@ projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, - /// Const allocations. - allocation: InternedSet<'tcx, Allocation>, + const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List>, + layout: InternedSet<'tcx, Layout>, } impl<'tcx> CtxtInterners<'tcx> { @@ -149,8 +135,9 @@ projs: Default::default(), place_elems: Default::default(), const_: Default::default(), - allocation: Default::default(), + const_allocation: Default::default(), bound_variable_kinds: Default::default(), + layout: Default::default(), } } @@ -1059,8 +1046,6 @@ /// Stores memory for globals (statics/consts). pub(crate) alloc_map: Lock>, - layout_interner: ShardedHashMap<&'tcx Layout, ()>, - output_filenames: Arc, } @@ -1101,13 +1086,6 @@ self.arena.alloc(ty::AdtDef::new(self, did, kind, variants, repr)) } - pub fn intern_const_alloc(self, alloc: Allocation) -> &'tcx Allocation { - self.interners - .allocation - .intern(alloc, |alloc| Interned(self.interners.arena.alloc(alloc))) - .0 - } - /// Allocates a read-only byte or string literal for `mir::interpret`. pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { // Create an allocation that just contains these bytes. @@ -1116,20 +1094,19 @@ self.create_memory_alloc(alloc) } + // FIXME(eddyb) move to `direct_interners!`. pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability { self.stability_interner.intern(stab, |stab| self.arena.alloc(stab)) } + // FIXME(eddyb) move to `direct_interners!`. pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability { self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab)) } - pub fn intern_layout(self, layout: Layout) -> &'tcx Layout { - self.layout_interner.intern(layout, |layout| self.arena.alloc(layout)) - } - /// Returns a range of the start/end indices specified with the /// `rustc_layout_scalar_valid_range` attribute. + // FIXME(eddyb) this is an awkward spot for this method, maybe move it? pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound, Bound) { let attrs = self.get_attrs(def_id); let get = |name| { @@ -1204,7 +1181,6 @@ evaluation_cache: Default::default(), crate_name: Symbol::intern(crate_name), data_layout, - layout_interner: Default::default(), stability_interner: Default::default(), const_stability_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), @@ -1251,12 +1227,17 @@ /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. pub fn get_diagnostic_item(self, name: Symbol) -> Option { - self.all_diagnostic_items(()).get(&name).copied() + self.all_diagnostic_items(()).name_to_id.get(&name).copied() + } + + /// Obtain the diagnostic item's name + pub fn get_diagnostic_name(self, id: DefId) -> Option { + self.diagnostic_items(id.krate).id_to_name.get(&id).copied() } /// Check whether the diagnostic item with the given `name` has the given `DefId`. pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool { - self.diagnostic_items(did.krate).get(&name) == Some(&did) + self.diagnostic_items(did.krate).name_to_id.get(&name) == Some(&did) } pub fn stability(self) -> &'tcx stability::Index<'tcx> { @@ -1309,6 +1290,17 @@ } } + /// Maps a StableCrateId to the corresponding CrateNum. This method assumes + /// that the crate in question has already been loaded by the CrateStore. + #[inline] + pub fn stable_crate_id_to_crate_num(self, stable_crate_id: StableCrateId) -> CrateNum { + if stable_crate_id == self.sess.local_stable_crate_id() { + LOCAL_CRATE + } else { + self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id) + } + } + pub fn def_path_debug_str(self, def_id: DefId) -> String { // We are explicitly not going through queries here in order to get // crate name and stable crate id since this code is called from debug!() @@ -1331,11 +1323,6 @@ ) } - pub fn encode_metadata(self) -> EncodedMetadata { - let _prof_timer = self.prof.verbose_generic_activity("generate_crate_metadata"); - self.untracked_resolutions.cstore.encode_metadata(self) - } - /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries pub fn cstore_untracked(self) -> &'tcx ty::CrateStoreDyn { @@ -1663,7 +1650,7 @@ nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} -nop_lift! {allocation; &'a Allocation => &'tcx Allocation} +nop_lift! {const_allocation; &'a Allocation => &'tcx Allocation} nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} @@ -1955,8 +1942,12 @@ "Const Stability interner: #{}", self.0.const_stability_interner.len() )?; - writeln!(fmt, "Allocation interner: #{}", self.0.interners.allocation.len())?; - writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?; + writeln!( + fmt, + "Const Allocation interner: #{}", + self.0.interners.const_allocation.len() + )?; + writeln!(fmt, "Layout interner: #{}", self.0.interners.layout.len())?; Ok(()) } @@ -2044,38 +2035,6 @@ } } -impl<'tcx> Borrow for Interned<'tcx, RegionKind> { - fn borrow(&self) -> &RegionKind { - &self.0 - } -} - -impl<'tcx> Borrow> for Interned<'tcx, Const<'tcx>> { - fn borrow<'a>(&'a self) -> &'a Const<'tcx> { - &self.0 - } -} - -impl<'tcx> Borrow for Interned<'tcx, Allocation> { - fn borrow<'a>(&'a self) -> &'a Allocation { - &self.0 - } -} - -impl<'tcx> PartialEq for Interned<'tcx, Allocation> { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl<'tcx> Eq for Interned<'tcx, Allocation> {} - -impl<'tcx> Hash for Interned<'tcx, Allocation> { - fn hash(&self, s: &mut H) { - self.0.hash(s) - } -} - macro_rules! direct_interners { ($($name:ident: $method:ident($ty:ty),)+) => { $(impl<'tcx> PartialEq for Interned<'tcx, $ty> { @@ -2092,9 +2051,15 @@ } } + impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> { + fn borrow<'a>(&'a self) -> &'a $ty { + &self.0 + } + } + impl<'tcx> TyCtxt<'tcx> { pub fn $method(self, v: $ty) -> &'tcx $ty { - self.interners.$name.intern_ref(&v, || { + self.interners.$name.intern(v, |v| { Interned(self.interners.arena.alloc(v)) }).0 } @@ -2105,6 +2070,8 @@ direct_interners! { region: mk_region(RegionKind), const_: mk_const(Const<'tcx>), + const_allocation: intern_const_alloc(Allocation), + layout: intern_layout(Layout), } macro_rules! slice_interners { @@ -2150,7 +2117,7 @@ }) } - /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) + /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally) /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used /// to identify which traits may define a given associated type to help avoid cycle errors. /// Returns a `DefId` iterator. @@ -2734,6 +2701,29 @@ pub fn lifetime_scope(self, id: HirId) -> Option { self.lifetime_scope_map(id.owner).and_then(|mut map| map.remove(&id.local_id)) } + + /// Whether the `def_id` counts as const fn in the current crate, considering all active + /// feature gates + pub fn is_const_fn(self, def_id: DefId) -> bool { + if self.is_const_fn_raw(def_id) { + match self.lookup_const_stability(def_id) { + Some(stability) if stability.level.is_unstable() => { + // has a `rustc_const_unstable` attribute, check whether the user enabled the + // corresponding feature gate. + self.features() + .declared_lib_features + .iter() + .any(|&(sym, _)| sym == stability.feature) + } + // functions without const stability are either stable user written + // const fn or the user is using feature gates and we thus don't + // care what they do + _ => true, + } + } else { + false + } + } } impl TyCtxtAt<'tcx> { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/diagnostics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/diagnostics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/diagnostics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/diagnostics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,6 @@ use crate::ty::TyKind::*; use crate::ty::{InferTy, TyCtxt, TyS}; -use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -114,10 +113,8 @@ def_id: Option, ) { // See if there's a `?Sized` bound that can be removed to suggest that. - // First look at the `where` clause because we can have `where T: ?Sized`, but that - // `?Sized` bound is *also* included in the `GenericParam` as a bound, which breaks - // the spans. Hence the somewhat involved logic that follows. - let mut where_unsized_bounds = FxHashSet::default(); + // First look at the `where` clause because we can have `where T: ?Sized`, + // then look at params. for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() { match predicate { WherePredicate::BoundPredicate(WhereBoundPredicate { @@ -140,7 +137,6 @@ }) if segment.ident.as_str() == param_name => { for (pos, bound) in bounds.iter().enumerate() { match bound { - hir::GenericBound::Unsized(_) => {} hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) if poly.trait_ref.trait_def_id() == def_id => {} _ => continue, @@ -173,7 +169,6 @@ // ^^^^^^^^^ (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()), }; - where_unsized_bounds.insert(bound.span()); err.span_suggestion_verbose( sp, "consider removing the `?Sized` bound to make the \ @@ -189,8 +184,7 @@ for (pos, bound) in param.bounds.iter().enumerate() { match bound { hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) - if poly.trait_ref.trait_def_id() == def_id - && !where_unsized_bounds.contains(&bound.span()) => + if poly.trait_ref.trait_def_id() == def_id => { let sp = match (param.bounds.len(), pos) { // T: ?Sized, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/error.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/error.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/error.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -964,7 +964,7 @@ { let (span, sugg) = if has_params { let pos = span.hi() - BytePos(1); - let span = Span::new(pos, pos, span.ctxt()); + let span = Span::new(pos, pos, span.ctxt(), span.parent()); (span, format!(", {} = {}", assoc.ident, ty)) } else { let item_args = self.format_generic_args(assoc_substs); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/fast_reject.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/fast_reject.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/fast_reject.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/fast_reject.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ -use crate::ich::StableHashingContext; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::DefId; +use rustc_query_system::ich::StableHashingContext; use std::fmt::Debug; use std::hash::Hash; use std::mem; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/fold.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/fold.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/fold.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/fold.rs 2021-11-29 19:27:11.000000000 +0000 @@ -79,6 +79,7 @@ == Some(FoundFlags) } + #[instrument(level = "trace")] fn has_type_flags(&self, flags: TypeFlags) -> bool { self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value() == Some(FoundFlags) @@ -476,21 +477,16 @@ t } + #[instrument(skip(self), level = "debug")] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { - debug!( - "RegionFolder.fold_region({:?}) skipped bound region (current index={:?})", - r, self.current_index - ); + debug!(?self.current_index, "skipped bound region"); *self.skipped_regions = true; r } _ => { - debug!( - "RegionFolder.fold_region({:?}) folding free region (current_index={:?})", - r, self.current_index - ); + debug!(?self.current_index, "folding free region"); (self.fold_region_fn)(r, self.current_index) } } @@ -1125,6 +1121,12 @@ flags: ty::TypeFlags, } +impl std::fmt::Debug for HasTypeFlagsVisitor<'tcx> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.flags.fmt(fmt) + } +} + impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { type BreakTy = FoundFlags; fn tcx_for_anon_const_substs(&self) -> Option> { @@ -1132,9 +1134,10 @@ } #[inline] + #[instrument(level = "trace")] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let flags = t.flags(); - debug!("HasTypeFlagsVisitor: t={:?} flags={:?} self.flags={:?}", t, flags, self.flags); + trace!(t.flags=?t.flags()); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1146,9 +1149,10 @@ } #[inline] + #[instrument(skip(self), level = "trace")] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let flags = r.type_flags(); - debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1157,9 +1161,10 @@ } #[inline] + #[instrument(level = "trace")] fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { let flags = FlagComputation::for_const(c); - debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1171,9 +1176,10 @@ } #[inline] + #[instrument(level = "trace")] fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { let flags = FlagComputation::for_unevaluated_const(uv); - debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1185,12 +1191,10 @@ } #[inline] + #[instrument(level = "trace")] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { let flags = predicate.inner.flags; - debug!( - "HasTypeFlagsVisitor: predicate={:?} flags={:?} self.flags={:?}", - predicate, flags, self.flags - ); + trace!(predicate.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/impls_ty.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/impls_ty.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/impls_ty.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/impls_ty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,165 @@ +//! This module contains `HashStable` implementations for various data types +//! from `rustc_middle::ty` in no particular order. + +use crate::middle::region; +use crate::mir; +use crate::ty; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_query_system::ich::StableHashingContext; +use std::cell::RefCell; +use std::mem; + +impl<'a, 'tcx, T> HashStable> for &'tcx ty::List +where + T: HashStable>, +{ + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + thread_local! { + static CACHE: RefCell> = + RefCell::new(Default::default()); + } + + let hash = CACHE.with(|cache| { + let key = (self.as_ptr() as usize, self.len()); + if let Some(&hash) = cache.borrow().get(&key) { + return hash; + } + + let mut hasher = StableHasher::new(); + (&self[..]).hash_stable(hcx, &mut hasher); + + let hash: Fingerprint = hasher.finish(); + cache.borrow_mut().insert(key, hash); + hash + }); + + hash.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx, T> ToStableHashKey> for &'tcx ty::List +where + T: HashStable>, +{ + type KeyType = Fingerprint; + + #[inline] + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint { + let mut hasher = StableHasher::new(); + let mut hcx: StableHashingContext<'a> = hcx.clone(); + self.hash_stable(&mut hcx, &mut hasher); + hasher.finish() + } +} + +impl<'a, 'tcx> HashStable> for ty::subst::GenericArg<'tcx> { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.unpack().hash_stable(hcx, hasher); + } +} + +impl<'a> HashStable> for ty::RegionKind { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ReErased | ty::ReStatic => { + // No variant fields to hash for these ... + } + ty::ReEmpty(universe) => { + universe.hash_stable(hcx, hasher); + } + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => { + db.hash_stable(hcx, hasher); + i.hash_stable(hcx, hasher); + } + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name), .. }) => { + db.hash_stable(hcx, hasher); + def_id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + } + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv, .. }) => { + db.hash_stable(hcx, hasher); + } + ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { + def_id.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + } + ty::ReFree(ref free_region) => { + free_region.hash_stable(hcx, hasher); + } + ty::RePlaceholder(p) => { + p.hash_stable(hcx, hasher); + } + ty::ReVar(..) => { + bug!("StableHasher: unexpected region {:?}", *self) + } + } + } +} + +impl<'a> HashStable> for ty::RegionVid { + #[inline] + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::ConstVid<'tcx> { + #[inline] + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.index.hash_stable(hcx, hasher); + } +} + +impl<'tcx> HashStable> for ty::BoundVar { + #[inline] + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx, T> HashStable> for ty::Binder<'tcx, T> +where + T: HashStable>, +{ + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.as_ref().skip_binder().hash_stable(hcx, hasher); + self.bound_vars().hash_stable(hcx, hasher); + } +} + +// AllocIds get resolved to whatever they point to (to be stable) +impl<'a> HashStable> for mir::interpret::AllocId { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + ty::tls::with_opt(|tcx| { + trace!("hashing {:?}", *self); + let tcx = tcx.expect("can't hash AllocIds during hir lowering"); + tcx.get_global_alloc(*self).hash_stable(hcx, hasher); + }); + } +} + +// `Relocations` with default type parameters is a sorted map. +impl<'a, Tag> HashStable> for mir::interpret::Relocations +where + Tag: HashStable>, +{ + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.len().hash_stable(hcx, hasher); + for reloc in self.iter() { + reloc.hash_stable(hcx, hasher); + } + } +} + +impl<'a> ToStableHashKey> for region::Scope { + type KeyType = region::Scope; + + #[inline] + fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> region::Scope { + *self + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/instance.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/instance.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/instance.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/instance.rs 2021-11-29 19:27:11.000000000 +0000 @@ -77,7 +77,7 @@ /// `<[FnMut closure] as FnOnce>::call_once`. /// /// The `DefId` is the ID of the `call_once` method in `FnOnce`. - ClosureOnceShim { call_once: DefId }, + ClosureOnceShim { call_once: DefId, track_caller: bool }, /// `core::ptr::drop_in_place::`. /// @@ -146,12 +146,28 @@ | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id } + | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) => def_id, } } + /// Returns the `DefId` of instances which might not require codegen locally. + pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option { + match self { + ty::InstanceDef::Item(def) => Some(def.did), + ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), + InstanceDef::VtableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) => None, + } + } + #[inline] pub fn with_opt_param(self) -> ty::WithOptConstParam { match self { @@ -161,7 +177,7 @@ | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id } + | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id), } @@ -231,6 +247,7 @@ | InstanceDef::Virtual(def_id, _) => { tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) } + InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller, _ => false, } } @@ -381,6 +398,8 @@ substs: SubstsRef<'tcx>, ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); + // Use either `resolve_closure` or `resolve_for_vtable` + assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {:?}", def_id); Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { @@ -442,10 +461,20 @@ }) ) { - debug!( - " => vtable fn pointer created for function with #[track_caller]" - ); - resolved.def = InstanceDef::ReifyShim(def.did); + if tcx.is_closure(def.did) { + debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", + def.did, def_id, substs); + + // Create a shim for the `FnOnce/FnMut/Fn` method we are calling + // - unlike functions, invoking a closure always goes through a + // trait. + resolved = Instance { def: InstanceDef::ReifyShim(def_id), substs }; + } else { + debug!( + " => vtable fn pointer created for function with #[track_caller]: {:?}", def.did + ); + resolved.def = InstanceDef::ReifyShim(def.did); + } } } InstanceDef::Virtual(def_id, _) => { @@ -493,7 +522,9 @@ .find(|it| it.kind == ty::AssocKind::Fn) .unwrap() .def_id; - let def = ty::InstanceDef::ClosureOnceShim { call_once }; + let track_caller = + tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); + let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller }; let self_ty = tcx.mk_closure(closure_did, substs); @@ -552,29 +583,26 @@ return self; } - if let InstanceDef::Item(def) = self.def { - let polymorphized_substs = polymorphize(tcx, def.did, self.substs); - debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); - Self { def: self.def, substs: polymorphized_substs } - } else { - self - } + let polymorphized_substs = polymorphize(tcx, self.def, self.substs); + debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); + Self { def: self.def, substs: polymorphized_substs } } } fn polymorphize<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + instance: ty::InstanceDef<'tcx>, substs: SubstsRef<'tcx>, ) -> SubstsRef<'tcx> { - debug!("polymorphize({:?}, {:?})", def_id, substs); - let unused = tcx.unused_generic_params(def_id); + debug!("polymorphize({:?}, {:?})", instance, substs); + let unused = tcx.unused_generic_params(instance); debug!("polymorphize: unused={:?}", unused); // If this is a closure or generator then we need to handle the case where another closure // from the function is captured as an upvar and hasn't been polymorphized. In this case, // the unpolymorphized upvar closure would result in a polymorphized closure producing // multiple mono items (and eventually symbol clashes). + let def_id = instance.def_id(); let upvars_ty = if tcx.is_closure(def_id) { Some(substs.as_closure().tupled_upvars_ty()) } else if tcx.type_of(def_id).is_generator() { @@ -598,7 +626,11 @@ debug!("fold_ty: ty={:?}", ty); match ty.kind { ty::Closure(def_id, substs) => { - let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + let polymorphized_substs = polymorphize( + self.tcx, + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + substs, + ); if substs == polymorphized_substs { ty } else { @@ -606,7 +638,11 @@ } } ty::Generator(def_id, substs, movability) => { - let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + let polymorphized_substs = polymorphize( + self.tcx, + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + substs, + ); if substs == polymorphized_substs { ty } else { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/layout.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/layout.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/layout.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/layout.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,32 +1,36 @@ -use crate::ich::StableHashingContext; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; use crate::ty::subst::Subst; use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; - use rustc_ast as ast; use rustc_attr as attr; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::call::{ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, }; use rustc_target::abi::*; -use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy}; +use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; use std::cmp; use std::fmt; use std::iter; -use std::mem; use std::num::NonZeroUsize; use std::ops::Bound; +use rand::{seq::SliceRandom, SeedableRng}; +use rand_xoshiro::Xoshiro128StarStar; + +pub fn provide(providers: &mut ty::query::Providers) { + *providers = + ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers }; +} + pub trait IntegerExt { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>; fn from_attr(cx: &C, ity: attr::IntType) -> Integer; @@ -191,7 +195,7 @@ /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer. pub const MAX_SIMD_LANES: u64 = 1 << 0xF; -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] pub enum LayoutError<'tcx> { Unknown(Ty<'tcx>), SizeOverflow(Ty<'tcx>), @@ -248,10 +252,6 @@ }) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { layout_of, ..*providers }; -} - pub struct LayoutCx<'tcx, C> { pub tcx: C, pub param_env: ty::ParamEnv<'tcx>, @@ -290,9 +290,9 @@ // HACK(nox): We iter on `b` and then `a` because `max_by_key` // returns the last maximum. - let largest_niche = Niche::from_scalar(dl, b_offset, b.clone()) + let largest_niche = Niche::from_scalar(dl, b_offset, b) .into_iter() - .chain(Niche::from_scalar(dl, Size::ZERO, a.clone())) + .chain(Niche::from_scalar(dl, Size::ZERO, a)) .max_by_key(|niche| niche.available(dl)); Layout { @@ -326,6 +326,10 @@ let mut inverse_memory_index: Vec = (0..fields.len() as u32).collect(); + // `ReprOptions.layout_seed` is a deterministic seed that we can use to + // randomize field ordering with + let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); + let optimize = !repr.inhibit_struct_field_reordering_opt(); if optimize { let end = @@ -334,20 +338,35 @@ let field_align = |f: &TyAndLayout<'_>| { if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi } }; - match kind { - StructKind::AlwaysSized | StructKind::MaybeUnsized => { - optimizing.sort_by_key(|&x| { - // Place ZSTs first to avoid "interesting offsets", - // especially with only one or two non-ZST fields. - let f = &fields[x as usize]; - (!f.is_zst(), cmp::Reverse(field_align(f))) - }); - } - StructKind::Prefixed(..) => { - // Sort in ascending alignment so that the layout stay optimal - // regardless of the prefix - optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); + + // If `-Z randomize-layout` was enabled for the type definition we can shuffle + // the field ordering to try and catch some code making assumptions about layouts + // we don't guarantee + if repr.can_randomize_type_layout() { + // Shuffle the ordering of the fields + optimizing.shuffle(&mut rng); + + // Otherwise we just leave things alone and actually optimize the type's fields + } else { + match kind { + StructKind::AlwaysSized | StructKind::MaybeUnsized => { + optimizing.sort_by_key(|&x| { + // Place ZSTs first to avoid "interesting offsets", + // especially with only one or two non-ZST fields. + let f = &fields[x as usize]; + (!f.is_zst(), cmp::Reverse(field_align(f))) + }); + } + + StructKind::Prefixed(..) => { + // Sort in ascending alignment so that the layout stays optimal + // regardless of the prefix + optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); + } } + + // FIXME(Kixiron): We can always shuffle fields within a given alignment class + // regardless of the status of `-Z randomize-layout` } } @@ -401,7 +420,7 @@ offsets[i as usize] = offset; if !repr.hide_niche() { - if let Some(mut niche) = field.largest_niche.clone() { + if let Some(mut niche) = field.largest_niche { let available = niche.available(dl); if available > largest_niche_available { largest_niche_available = available; @@ -449,12 +468,12 @@ // For plain scalars, or vectors of them, we can't unpack // newtypes for `#[repr(C)]`, as that affects C ABIs. Abi::Scalar(_) | Abi::Vector { .. } if optimize => { - abi = field.abi.clone(); + abi = field.abi; } // But scalar pairs are Rust-specific and get // treated as aggregates by C ABIs anyway. Abi::ScalarPair(..) => { - abi = field.abi.clone(); + abi = field.abi; } _ => {} } @@ -463,14 +482,14 @@ // Two non-ZST fields, and they're both scalars. ( - Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(ref a), .. }, .. })), - Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(ref b), .. }, .. })), + Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(a), .. }, .. })), + Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(b), .. }, .. })), None, ) => { // Order by the memory placement, not source order. let ((i, a), (j, b)) = if offsets[i] < offsets[j] { ((i, a), (j, b)) } else { ((j, b), (i, a)) }; - let pair = self.scalar_pair(a.clone(), b.clone()); + let pair = self.scalar_pair(a, b); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index, &[0, 1]); @@ -512,9 +531,9 @@ let param_env = self.param_env; let dl = self.data_layout(); let scalar_unit = |value: Primitive| { - let bits = value.size(dl).bits(); - assert!(bits <= 128); - Scalar { value, valid_range: WrappingRange { start: 0, end: (!0 >> (128 - bits)) } } + let size = value.size(dl); + assert!(size.bits() <= 128); + Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } } }; let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value))); @@ -609,7 +628,7 @@ Abi::Aggregate { sized: true } }; - let largest_niche = if count != 0 { element.largest_niche.clone() } else { None }; + let largest_niche = if count != 0 { element.largest_niche } else { None }; tcx.intern_layout(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, @@ -768,8 +787,8 @@ // Compute the ABI of the element type: let e_ly = self.layout_of(e_ty)?; - let e_abi = if let Abi::Scalar(ref scalar) = e_ly.abi { - scalar.clone() + let e_abi = if let Abi::Scalar(scalar) = e_ly.abi { + scalar } else { // This error isn't caught in typeck, e.g., if // the element type of the vector is generic. @@ -796,7 +815,7 @@ variants: Variants::Single { index: VariantIdx::new(0) }, fields, abi: Abi::Vector { element: e_abi, count: e_len }, - largest_niche: e_ly.largest_niche.clone(), + largest_niche: e_ly.largest_niche, size, align, }) @@ -843,13 +862,13 @@ // If all non-ZST fields have the same ABI, forward this ABI if optimize && !field.is_zst() { // Normalize scalar_unit to the maximal valid range - let field_abi = match &field.abi { + let field_abi = match field.abi { Abi::Scalar(x) => Abi::Scalar(scalar_unit(x.value)), Abi::ScalarPair(x, y) => { Abi::ScalarPair(scalar_unit(x.value), scalar_unit(y.value)) } Abi::Vector { element: x, count } => { - Abi::Vector { element: scalar_unit(x.value), count: *count } + Abi::Vector { element: scalar_unit(x.value), count } } Abi::Uninhabited | Abi::Aggregate { .. } => { Abi::Aggregate { sized: true } @@ -967,10 +986,10 @@ let niche = if def.repr.hide_niche() { None } else { - Niche::from_scalar(dl, Size::ZERO, scalar.clone()) + Niche::from_scalar(dl, Size::ZERO, *scalar) }; if let Some(niche) = niche { - match &st.largest_niche { + match st.largest_niche { Some(largest_niche) => { // Replace the existing niche even if they're equal, // because this one is at a lower offset. @@ -1045,7 +1064,7 @@ let niche_candidate = variants[i] .iter() .enumerate() - .filter_map(|(j, &field)| Some((j, field.largest_niche.as_ref()?))) + .filter_map(|(j, field)| Some((j, field.largest_niche?))) .max_by_key(|(_, niche)| niche.available(dl)); if let Some((field_index, niche, (niche_start, niche_scalar))) = @@ -1078,31 +1097,24 @@ Abi::Uninhabited } else { match st[i].abi { - Abi::Scalar(_) => Abi::Scalar(niche_scalar.clone()), - Abi::ScalarPair(ref first, ref second) => { + Abi::Scalar(_) => Abi::Scalar(niche_scalar), + Abi::ScalarPair(first, second) => { // We need to use scalar_unit to reset the // valid range to the maximal one for that // primitive, because only the niche is // guaranteed to be initialised, not the // other primitive. if offset.bytes() == 0 { - Abi::ScalarPair( - niche_scalar.clone(), - scalar_unit(second.value), - ) + Abi::ScalarPair(niche_scalar, scalar_unit(second.value)) } else { - Abi::ScalarPair( - scalar_unit(first.value), - niche_scalar.clone(), - ) + Abi::ScalarPair(scalar_unit(first.value), niche_scalar) } } _ => Abi::Aggregate { sized: true }, } }; - let largest_niche = - Niche::from_scalar(dl, offset, niche_scalar.clone()); + let largest_niche = Niche::from_scalar(dl, offset, niche_scalar); niche_filling_layout = Some(Layout { variants: Variants::Multiple { @@ -1273,7 +1285,7 @@ } } - let tag_mask = !0u128 >> (128 - ity.size().bits()); + let tag_mask = ity.size().unsigned_int_max(); let tag = Scalar { value: Int(ity, signed), valid_range: WrappingRange { @@ -1283,7 +1295,7 @@ }; let mut abi = Abi::Aggregate { sized: true }; if tag.value.size(dl) == size { - abi = Abi::Scalar(tag.clone()); + abi = Abi::Scalar(tag); } else { // Try to use a ScalarPair for all tagged enums. let mut common_prim = None; @@ -1303,7 +1315,7 @@ } }; let prim = match field.abi { - Abi::Scalar(ref scalar) => scalar.value, + Abi::Scalar(scalar) => scalar.value, _ => { common_prim = None; break; @@ -1323,7 +1335,7 @@ } } if let Some((prim, offset)) = common_prim { - let pair = self.scalar_pair(tag.clone(), scalar_unit(prim)); + let pair = self.scalar_pair(tag, scalar_unit(prim)); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index, &[0, 1]); @@ -1347,7 +1359,7 @@ abi = Abi::Uninhabited; } - let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone()); + let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); let tagged_layout = Layout { variants: Variants::Multiple { @@ -1372,8 +1384,7 @@ // pick the layout with the larger niche; otherwise, // pick tagged as it has simpler codegen. cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| { - let niche_size = - layout.largest_niche.as_ref().map_or(0, |n| n.available(dl)); + let niche_size = layout.largest_niche.map_or(0, |n| n.available(dl)); (layout.size, cmp::Reverse(niche_size)) }) } @@ -1560,7 +1571,7 @@ value: Primitive::Int(discr_int, false), valid_range: WrappingRange { start: 0, end: max_discr }, }; - let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone())); + let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag)); let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout }; let promoted_layouts = ineligible_locals @@ -1815,8 +1826,11 @@ match layout.variants { Variants::Single { index } => { - debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variants[index].ident); - if !adt_def.variants.is_empty() { + if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive { + debug!( + "print-type-size `{:#?}` variant {}", + layout, adt_def.variants[index].ident + ); let variant_def = &adt_def.variants[index]; let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect(); record( @@ -1832,7 +1846,7 @@ } } - Variants::Multiple { ref tag, ref tag_encoding, .. } => { + Variants::Multiple { tag, ref tag_encoding, .. } => { debug!( "print-type-size `{:#?}` adt general variants def {}", layout.ty, @@ -2023,6 +2037,12 @@ } } +impl<'tcx> HasTargetSpec for TyCtxt<'tcx> { + fn target_spec(&self) -> &Target { + &self.sess.target + } +} + impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { @@ -2037,6 +2057,12 @@ } } +impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> { + fn target_spec(&self) -> &Target { + &self.sess.target + } +} + impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { @@ -2056,35 +2082,125 @@ } } +impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> { + fn target_spec(&self) -> &Target { + self.tcx.target_spec() + } +} + impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx.tcx() } } +pub trait MaybeResult { + type Error; + + fn from(x: Result) -> Self; + fn to_result(self) -> Result; +} + +impl MaybeResult for T { + type Error = !; + + fn from(Ok(x): Result) -> Self { + x + } + fn to_result(self) -> Result { + Ok(self) + } +} + +impl MaybeResult for Result { + type Error = E; + + fn from(x: Result) -> Self { + x + } + fn to_result(self) -> Result { + self + } +} + pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>; -impl LayoutOf<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { - type Ty = Ty<'tcx>; - type TyAndLayout = Result, LayoutError<'tcx>>; +/// Trait for contexts that want to be able to compute layouts of types. +/// This automatically gives access to `LayoutOf`, through a blanket `impl`. +pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> { + /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be + /// returned from `layout_of` (see also `handle_layout_err`). + type LayoutOfResult: MaybeResult>; + + /// `Span` to use for `tcx.at(span)`, from `layout_of`. + // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better? + #[inline] + fn layout_tcx_at_span(&self) -> Span { + DUMMY_SP + } + + /// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a + /// `Self::LayoutOfResult` (which does not need to be a `Result<...>`). + /// + /// Most `impl`s, which propagate `LayoutError`s, should simply return `err`, + /// but this hook allows e.g. codegen to return only `TyAndLayout` from its + /// `cx.layout_of(...)`, without any `Result<...>` around it to deal with + /// (and any `LayoutError`s are turned into fatal errors or ICEs). + fn handle_layout_err( + &self, + err: LayoutError<'tcx>, + span: Span, + ty: Ty<'tcx>, + ) -> >>::Error; +} +/// Blanket extension trait for contexts that can compute layouts of types. +pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> { /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode, and will normalize the input type. #[inline] - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)) + fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { + self.spanned_layout_of(ty, DUMMY_SP) + } + + /// Computes the layout of a type, at `span`. Note that this implicitly + /// executes in "reveal all" mode, and will normalize the input type. + // FIXME(eddyb) avoid passing information like this, and instead add more + // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`. + #[inline] + fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult { + let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() }; + let tcx = self.tcx().at(span); + + MaybeResult::from( + tcx.layout_of(self.param_env().and(ty)) + .map_err(|err| self.handle_layout_err(err, span, ty)), + ) } } -impl LayoutOf<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { - type Ty = Ty<'tcx>; - type TyAndLayout = Result, LayoutError<'tcx>>; +impl> LayoutOf<'tcx> for C {} + +impl LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { + type LayoutOfResult = Result, LayoutError<'tcx>>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> { + err + } +} + +impl LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { + type LayoutOfResult = Result, LayoutError<'tcx>>; - /// Computes the layout of a type. Note that this implicitly - /// executes in "reveal all" mode, and will normalize the input type. #[inline] - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)) + fn layout_tcx_at_span(&self) -> Span { + self.tcx.span + } + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> { + err } } @@ -2156,8 +2272,8 @@ i: usize, ) -> TyMaybeWithLayout<'tcx> { let tcx = cx.tcx(); - let tag_layout = |tag: &Scalar| -> TyAndLayout<'tcx> { - let layout = Layout::scalar(cx, tag.clone()); + let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> { + let layout = Layout::scalar(cx, tag); TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) } }; @@ -2245,7 +2361,7 @@ .nth(i) .unwrap(), ), - Variants::Multiple { ref tag, tag_field, .. } => { + Variants::Multiple { tag, tag_field, .. } => { if i == tag_field { return TyMaybeWithLayout::TyAndLayout(tag_layout(tag)); } @@ -2263,7 +2379,7 @@ } // Discriminant field for enums (where applicable). - Variants::Multiple { ref tag, .. } => { + Variants::Multiple { tag, .. } => { assert_eq!(i, 0); return TyMaybeWithLayout::TyAndLayout(tag_layout(tag)); } @@ -2443,24 +2559,12 @@ } } -impl<'a, 'tcx> HashStable> for LayoutError<'tcx> { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use crate::ty::layout::LayoutError::*; - mem::discriminant(self).hash_stable(hcx, hasher); - - match *self { - Unknown(t) | SizeOverflow(t) => t.hash_stable(hcx, hasher), - } - } -} - impl<'tcx> ty::Instance<'tcx> { // NOTE(eddyb) this is private to avoid using it from outside of - // `FnAbi::of_instance` - any other uses are either too high-level + // `fn_abi_of_instance` - any other uses are either too high-level // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), // or should go through `FnAbi` instead, to avoid losing any - // adjustments `FnAbi::of_instance` might be performing. + // adjustments `fn_abi_of_instance` might be performing. fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function. let ty = self.ty(tcx, ty::ParamEnv::reveal_all()); @@ -2557,38 +2661,6 @@ } } -pub trait FnAbiExt<'tcx, C> -where - C: LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, -{ - /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. - /// - /// NB: this doesn't handle virtual calls - those should use `FnAbi::of_instance` - /// instead, where the instance is an `InstanceDef::Virtual`. - fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; - - /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for - /// direct calls to an `fn`. - /// - /// NB: that includes virtual calls, which are represented by "direct calls" - /// to an `InstanceDef::Virtual` instance (of `::fn`). - fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; - - fn new_internal( - cx: &C, - sig: ty::PolyFnSig<'tcx>, - extra_args: &[Ty<'tcx>], - caller_location: Option>, - codegen_fn_attr_flags: CodegenFnAttrFlags, - make_self_ptr_thin: bool, - ) -> Self; - fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi); -} - /// Calculates whether a function's ABI can unwind or not. /// /// This takes two primary parameters: @@ -2744,52 +2816,175 @@ } } -impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>> -where - C: LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, -{ - fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - call::FnAbi::new_internal(cx, sig, extra_args, None, CodegenFnAttrFlags::empty(), false) +/// Error produced by attempting to compute or adjust a `FnAbi`. +#[derive(Clone, Debug, HashStable)] +pub enum FnAbiError<'tcx> { + /// Error produced by a `layout_of` call, while computing `FnAbi` initially. + Layout(LayoutError<'tcx>), + + /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI. + AdjustForForeignAbi(call::AdjustForForeignAbiError), +} + +impl From> for FnAbiError<'tcx> { + fn from(err: LayoutError<'tcx>) -> Self { + Self::Layout(err) + } +} + +impl From for FnAbiError<'_> { + fn from(err: call::AdjustForForeignAbiError) -> Self { + Self::AdjustForForeignAbi(err) } +} - fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - let sig = instance.fn_sig_for_fn_abi(cx.tcx()); +impl<'tcx> fmt::Display for FnAbiError<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Layout(err) => err.fmt(f), + Self::AdjustForForeignAbi(err) => err.fmt(f), + } + } +} - let caller_location = if instance.def.requires_caller_location(cx.tcx()) { - Some(cx.tcx().caller_location_ty()) - } else { - None - }; +// FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not +// just for error handling. +#[derive(Debug)] +pub enum FnAbiRequest<'tcx> { + OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List> }, + OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List> }, +} - let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags; +/// Trait for contexts that want to be able to compute `FnAbi`s. +/// This automatically gives access to `FnAbiOf`, through a blanket `impl`. +pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> { + /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be + /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`). + type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>; - call::FnAbi::new_internal( - cx, - sig, - extra_args, - caller_location, - attrs, - matches!(instance.def, ty::InstanceDef::Virtual(..)), + /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a + /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`). + /// + /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`, + /// but this hook allows e.g. codegen to return only `&FnAbi` from its + /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with + /// (and any `FnAbiError`s are turned into fatal errors or ICEs). + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> >>>::Error; +} + +/// Blanket extension trait for contexts that can compute `FnAbi`s. +pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { + /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. + /// + /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance` + /// instead, where the instance is an `InstanceDef::Virtual`. + #[inline] + fn fn_abi_of_fn_ptr( + &self, + sig: ty::PolyFnSig<'tcx>, + extra_args: &'tcx ty::List>, + ) -> Self::FnAbiOfResult { + // FIXME(eddyb) get a better `span` here. + let span = self.layout_tcx_at_span(); + let tcx = self.tcx().at(span); + + MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err( + |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }), + )) + } + + /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for + /// direct calls to an `fn`. + /// + /// NB: that includes virtual calls, which are represented by "direct calls" + /// to an `InstanceDef::Virtual` instance (of `::fn`). + #[inline] + fn fn_abi_of_instance( + &self, + instance: ty::Instance<'tcx>, + extra_args: &'tcx ty::List>, + ) -> Self::FnAbiOfResult { + // FIXME(eddyb) get a better `span` here. + let span = self.layout_tcx_at_span(); + let tcx = self.tcx().at(span); + + MaybeResult::from( + tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| { + // HACK(eddyb) at least for definitions of/calls to `Instance`s, + // we can get some kind of span even if one wasn't provided. + // However, we don't do this early in order to avoid calling + // `def_span` unconditionally (which may have a perf penalty). + let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) }; + self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args }) + }), ) } +} - fn new_internal( - cx: &C, +impl> FnAbiOf<'tcx> for C {} + +fn fn_abi_of_fn_ptr<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List>)>, +) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { + let (param_env, (sig, extra_args)) = query.into_parts(); + + LayoutCx { tcx, param_env }.fn_abi_new_uncached( + sig, + extra_args, + None, + CodegenFnAttrFlags::empty(), + false, + ) +} + +fn fn_abi_of_instance<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List>)>, +) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { + let (param_env, (instance, extra_args)) = query.into_parts(); + + let sig = instance.fn_sig_for_fn_abi(tcx); + + let caller_location = if instance.def.requires_caller_location(tcx) { + Some(tcx.caller_location_ty()) + } else { + None + }; + + let attrs = tcx.codegen_fn_attrs(instance.def_id()).flags; + + LayoutCx { tcx, param_env }.fn_abi_new_uncached( + sig, + extra_args, + caller_location, + attrs, + matches!(instance.def, ty::InstanceDef::Virtual(..)), + ) +} + +impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { + // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?) + // arguments of this method, into a separate `struct`. + fn fn_abi_new_uncached( + &self, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>], caller_location: Option>, codegen_fn_attr_flags: CodegenFnAttrFlags, + // FIXME(eddyb) replace this with something typed, like an `enum`. force_thin_self_ptr: bool, - ) -> Self { - debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args); + ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { + debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args); - let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); + let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig); - let conv = conv_from_spec_abi(cx.tcx(), sig.abi); + let conv = conv_from_spec_abi(self.tcx(), sig.abi); let mut inputs = sig.inputs(); let extra_args = if sig.abi == RustCall { @@ -2816,8 +3011,8 @@ extra_args.to_vec() }; - let target = &cx.tcx().sess.target; - let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl"); + let target = &self.tcx.sess.target; + let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc"); let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu"; let linux_s390x_gnu_like = target.os == "linux" && target.arch == "s390x" && target_env_gnu_like; @@ -2830,7 +3025,7 @@ // Handle safe Rust thin and fat pointers. let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: &Scalar, + scalar: Scalar, layout: TyAndLayout<'tcx>, offset: Size, is_return: bool| { @@ -2845,11 +3040,11 @@ return; } - if !scalar.valid_range.contains_zero() { + if !scalar.valid_range.contains(0) { attrs.set(ArgAttribute::NonNull); } - if let Some(pointee) = layout.pointee_info_at(cx, offset) { + if let Some(pointee) = layout.pointee_info_at(self, offset) { if let Some(kind) = pointee.safe { attrs.pointee_align = Some(pointee.align); @@ -2893,20 +3088,20 @@ } }; - let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { + let arg_of = |ty: Ty<'tcx>, arg_idx: Option| -> Result<_, FnAbiError<'tcx>> { let is_return = arg_idx.is_none(); - let layout = cx.layout_of(ty); + let layout = self.layout_of(ty)?; let layout = if force_thin_self_ptr && arg_idx == Some(0) { // Don't pass the vtable, it's not an argument of the virtual fn. // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - make_thin_self_ptr(cx, layout) + make_thin_self_ptr(self, layout) } else { layout }; - let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| { + let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| { let mut attrs = ArgAttributes::new(); adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return); attrs @@ -2915,7 +3110,7 @@ if arg.layout.is_zst() { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. - // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl}. + // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}. if is_return || rust_abi || (!win_x64_gnu @@ -2927,11 +3122,11 @@ } } - arg + Ok(arg) }; let mut fn_abi = FnAbi { - ret: arg_of(sig.output(), None), + ret: arg_of(sig.output(), None)?, args: inputs .iter() .cloned() @@ -2939,20 +3134,24 @@ .chain(caller_location) .enumerate() .map(|(i, ty)| arg_of(ty, Some(i))) - .collect(), + .collect::>()?, c_variadic: sig.c_variadic, fixed_count: inputs.len(), conv, - can_unwind: fn_can_unwind(cx.tcx(), codegen_fn_attr_flags, sig.abi), + can_unwind: fn_can_unwind(self.tcx(), codegen_fn_attr_flags, sig.abi), }; - fn_abi.adjust_for_abi(cx, sig.abi); - debug!("FnAbi::new_internal = {:?}", fn_abi); - fn_abi + self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?; + debug!("fn_abi_new_uncached = {:?}", fn_abi); + Ok(self.tcx.arena.alloc(fn_abi)) } - fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) { + fn fn_abi_adjust_for_abi( + &self, + fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>, + abi: SpecAbi, + ) -> Result<(), FnAbiError<'tcx>> { if abi == SpecAbi::Unadjusted { - return; + return Ok(()); } if abi == SpecAbi::Rust @@ -2989,7 +3188,7 @@ // anyway, we control all calls to it in libstd. Abi::Vector { .. } if abi != SpecAbi::PlatformIntrinsic - && cx.tcx().sess.target.simd_types_indirect => + && self.tcx.sess.target.simd_types_indirect => { arg.make_indirect(); return; @@ -3000,7 +3199,7 @@ // Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`. // LLVM will usually pass these in 2 registers, which is more efficient than by-ref. - let max_by_val_size = Pointer.size(cx) * 2; + let max_by_val_size = Pointer.size(self) * 2; let size = arg.layout.size; if arg.layout.is_unsized() || size > max_by_val_size { @@ -3012,16 +3211,15 @@ arg.cast_to(Reg { kind: RegKind::Integer, size }); } }; - fixup(&mut self.ret); - for arg in &mut self.args { + fixup(&mut fn_abi.ret); + for arg in &mut fn_abi.args { fixup(arg); } - return; + } else { + fn_abi.adjust_for_foreign_abi(self, abi)?; } - if let Err(msg) = self.adjust_for_cabi(cx, abi) { - cx.tcx().sess.fatal(&msg); - } + Ok(()) } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -20,8 +20,6 @@ pub use vtable::*; use crate::hir::exports::ExportMap; -use crate::ich::StableHashingContext; -use crate::middle::cstore::CrateStoreDyn; use crate::mir::{Body, GeneratorLayout}; use crate::traits::{self, Reveal}; use crate::ty; @@ -29,18 +27,18 @@ use crate::ty::util::Discr; use rustc_ast as ast; use rustc_attr as attr; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{self, par_iter, ParallelIterator}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX}; use rustc_hir::Node; use rustc_macros::HashStable; +use rustc_query_system::ich::StableHashingContext; +use rustc_session::cstore::CrateStoreDyn; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::abi::Align; use std::cmp::Ordering; @@ -94,7 +92,6 @@ pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; -pub mod outlives; pub mod print; pub mod query; pub mod relate; @@ -112,6 +109,7 @@ mod diagnostics; mod erase_regions; mod generics; +mod impls_ty; mod instance; mod list; mod structural_impls; @@ -127,7 +125,7 @@ pub extern_crate_map: FxHashMap, pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, - pub export_map: ExportMap, + pub export_map: ExportMap, pub glob_map: FxHashMap>, /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. @@ -137,6 +135,9 @@ /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. pub proc_macros: Vec, + /// Mapping from ident span to path span for paths that don't exist as written, but that + /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. + pub confused_type_with_std_module: FxHashMap, } #[derive(Clone, Copy, Debug)] @@ -598,7 +599,7 @@ // where both `'x` and `'b` would have a DB index of 1. // The substitution from the input trait-ref is therefore going to be // `'a => 'x` (where `'x` has a DB index of 1). - // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an + // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an // early-bound parameter and `'b' is a late-bound parameter with a // DB index of 1. // - If we replace `'a` with `'x` from the input, it too will have @@ -766,12 +767,6 @@ fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; } -impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - ty::Binder::dummy(*self) - } -} - impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { self.map_bound_ref(|trait_pred| trait_pred.trait_ref) @@ -789,23 +784,6 @@ } } -impl ToPredicate<'tcx> for PredicateKind<'tcx> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - tcx.mk_predicate(Binder::dummy(self)) - } -} - -impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Trait(ty::TraitPredicate { - trait_ref: self.value, - constness: self.constness, - }) - .to_predicate(tcx) - } -} - impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.value @@ -1374,6 +1352,8 @@ pub struct Destructor { /// The `DefId` of the destructor method pub did: DefId, + /// The constness of the destructor method + pub constness: hir::Constness, } bitflags! { @@ -1509,6 +1489,9 @@ const IS_LINEAR = 1 << 3; // If true, don't expose any niche to type's context. const HIDE_NICHE = 1 << 4; + // If true, the type's layout can be randomized using + // the seed stored in `ReprOptions.layout_seed` + const RANDOMIZE_LAYOUT = 1 << 5; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | ReprFlags::IS_SIMD.bits | @@ -1523,6 +1506,14 @@ pub align: Option, pub pack: Option, pub flags: ReprFlags, + /// The seed to be used for randomizing a type's layout + /// + /// Note: This could technically be a `[u8; 16]` (a `u128`) which would + /// be the "most accurate" hash as it'd encompass the item and crate + /// hash without loss, but it does pay the price of being larger. + /// Everything's a tradeoff, a `u64` seed should be sufficient for our + /// purposes (primarily `-Z randomize-layout`) + pub field_shuffle_seed: u64, } impl ReprOptions { @@ -1531,6 +1522,11 @@ let mut size = None; let mut max_align: Option = None; let mut min_pack: Option = None; + + // Generate a deterministically-derived seed from the item's path hash + // to allow for cross-crate compilation to actually work + let field_shuffle_seed = tcx.def_path_hash(did).0.to_smaller_hash(); + for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(&tcx.sess, attr) { flags.insert(match r { @@ -1559,33 +1555,45 @@ } } + // If `-Z randomize-layout` was enabled for the type definition then we can + // consider performing layout randomization + if tcx.sess.opts.debugging_opts.randomize_layout { + flags.insert(ReprFlags::RANDOMIZE_LAYOUT); + } + // This is here instead of layout because the choice must make it into metadata. if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.def_path_str(did))) { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, align: max_align, pack: min_pack, flags } + + Self { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } } #[inline] pub fn simd(&self) -> bool { self.flags.contains(ReprFlags::IS_SIMD) } + #[inline] pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) } + #[inline] pub fn packed(&self) -> bool { self.pack.is_some() } + #[inline] pub fn transparent(&self) -> bool { self.flags.contains(ReprFlags::IS_TRANSPARENT) } + #[inline] pub fn linear(&self) -> bool { self.flags.contains(ReprFlags::IS_LINEAR) } + #[inline] pub fn hide_niche(&self) -> bool { self.flags.contains(ReprFlags::HIDE_NICHE) @@ -1612,9 +1620,17 @@ return true; } } + self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some() } + /// Returns `true` if this type is valid for reordering and `-Z randomize-layout` + /// was enabled for its declaration crate + pub fn can_randomize_type_layout(&self) -> bool { + !self.inhibit_struct_field_reordering_opt() + && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT) + } + /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations. pub fn inhibit_union_abi_opt(&self) -> bool { self.c() @@ -1622,8 +1638,8 @@ } impl<'tcx> FieldDef { - /// Returns the type of this field. The `subst` is typically obtained - /// via the second field of `TyKind::AdtDef`. + /// Returns the type of this field. The resulting type is not normalized. The `subst` is + /// typically obtained via the second field of `TyKind::AdtDef`. pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> { tcx.type_of(self.did).subst(tcx, subst) } @@ -1678,18 +1694,6 @@ self.typeck(self.hir().body_owner_def_id(body)) } - /// Returns an iterator of the `DefId`s for all body-owners in this - /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir().krate().body_ids.iter()`. - pub fn body_owners(self) -> impl Iterator + Captures<'tcx> + 'tcx { - self.hir().krate().bodies.keys().map(move |&body_id| self.hir().body_owner_def_id(body_id)) - } - - pub fn par_body_owners(self, f: F) { - par_iter(&self.hir().krate().bodies) - .for_each(|(&body_id, _)| f(self.hir().body_owner_def_id(body_id))); - } - pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator { self.associated_items(id) .in_definition_order() @@ -1895,6 +1899,14 @@ self.sess.contains_name(&self.get_attrs(did), attr) } + /// Determines whether an item is annotated with `doc(hidden)`. + pub fn is_doc_hidden(self, did: DefId) -> bool { + self.get_attrs(did) + .iter() + .filter_map(|attr| if attr.has_name(sym::doc) { attr.meta_item_list() } else { None }) + .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) + } + /// Returns `true` if this is an `auto trait`. pub fn trait_is_auto(self, trait_def_id: DefId) -> bool { self.trait_def(trait_def_id).has_auto_impl @@ -2086,3 +2098,16 @@ fmt::Display::fmt(&self.name, fmt) } } + +#[derive(Debug, Default, Copy, Clone)] +pub struct FoundRelationships { + /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` + /// obligation, where: + /// + /// * `Foo` is not `Sized` + /// * `(): Foo` may be satisfied + pub self_in_trait: bool, + /// This is true if we identified that this Ty (`?T`) is found in a `<_ as + /// _>::AssocType = ?T` + pub output: bool, +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/outlives.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/outlives.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/outlives.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/outlives.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,213 +0,0 @@ -// The outlines relation `T: 'a` or `'a: 'b`. This code frequently -// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that -// RFC for reference. - -use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::sso::SsoHashSet; -use smallvec::SmallVec; - -#[derive(Debug)] -pub enum Component<'tcx> { - Region(ty::Region<'tcx>), - Param(ty::ParamTy), - UnresolvedInferenceVariable(ty::InferTy), - - // Projections like `T::Foo` are tricky because a constraint like - // `T::Foo: 'a` can be satisfied in so many ways. There may be a - // where-clause that says `T::Foo: 'a`, or the defining trait may - // include a bound like `type Foo: 'static`, or -- in the most - // conservative way -- we can prove that `T: 'a` (more generally, - // that all components in the projection outlive `'a`). This code - // is not in a position to judge which is the best technique, so - // we just product the projection as a component and leave it to - // the consumer to decide (but see `EscapingProjection` below). - Projection(ty::ProjectionTy<'tcx>), - - // In the case where a projection has escaping regions -- meaning - // regions bound within the type itself -- we always use - // the most conservative rule, which requires that all components - // outlive the bound. So for example if we had a type like this: - // - // for<'a> Trait1< >::Foo > - // ~~~~~~~~~~~~~~~~~~~~~~~~~ - // - // then the inner projection (underlined) has an escaping region - // `'a`. We consider that outer trait `'c` to meet a bound if `'b` - // outlives `'b: 'c`, and we don't consider whether the trait - // declares that `Foo: 'static` etc. Therefore, we just return the - // free components of such a projection (in this case, `'b`). - // - // However, in the future, we may want to get smarter, and - // actually return a "higher-ranked projection" here. Therefore, - // we mark that these components are part of an escaping - // projection, so that implied bounds code can avoid relying on - // them. This gives us room to improve the regionck reasoning in - // the future without breaking backwards compat. - EscapingProjection(Vec>), -} - -impl<'tcx> TyCtxt<'tcx> { - /// Push onto `out` all the things that must outlive `'a` for the condition - /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. - pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - let mut visited = SsoHashSet::new(); - compute_components(self, ty0, out, &mut visited); - debug!("components({:?}) = {:?}", ty0, out); - } -} - -fn compute_components( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet>, -) { - // Descend through the types, looking for the various "base" - // components and collecting them into `out`. This is not written - // with `collect()` because of the need to sometimes skip subtrees - // in the `subtys` iterator (e.g., when encountering a - // projection). - match *ty.kind() { - ty::FnDef(_, substs) => { - // HACK(eddyb) ignore lifetimes found shallowly in `substs`. - // This is inconsistent with `ty::Adt` (including all substs) - // and with `ty::Closure` (ignoring all substs other than - // upvars, of which a `ty::FnDef` doesn't have any), but - // consistent with previous (accidental) behavior. - // See https://github.com/rust-lang/rust/issues/70917 - // for further background and discussion. - for child in substs { - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(_) => {} - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } - } - - ty::Array(element, _) => { - // Don't look into the len const as it doesn't affect regions - compute_components(tcx, element, out, visited); - } - - ty::Closure(_, ref substs) => { - let tupled_ty = substs.as_closure().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - } - - ty::Generator(_, ref substs, _) => { - // Same as the closure case - let tupled_ty = substs.as_generator().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - - // We ignore regions in the generator interior as we don't - // want these to affect region inference - } - - // All regions are bound inside a witness - ty::GeneratorWitness(..) => (), - - // OutlivesTypeParameterEnv -- the actual checking that `X:'a` - // is implied by the environment is done in regionck. - ty::Param(p) => { - out.push(Component::Param(p)); - } - - // For projections, we prefer to generate an obligation like - // `>::Foo: 'a`, because this gives the - // regionck more ways to prove that it holds. However, - // regionck is not (at least currently) prepared to deal with - // higher-ranked regions that may appear in the - // trait-ref. Therefore, if we see any higher-ranke regions, - // we simply fallback to the most restrictive rule, which - // requires that `Pi: 'a` for all `i`. - ty::Projection(ref data) => { - if !data.has_escaping_bound_vars() { - // best case: no escaping regions, so push the - // projection and skip the subtree (thus generating no - // constraints for Pi). This defers the choice between - // the rules OutlivesProjectionEnv, - // OutlivesProjectionTraitDef, and - // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(*data)); - } else { - // fallback case: hard code - // OutlivesProjectionComponents. Continue walking - // through and constrain Pi. - let mut subcomponents = smallvec![]; - let mut subvisited = SsoHashSet::new(); - compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); - out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); - } - } - - // We assume that inference variables are fully resolved. - // So, if we encounter an inference variable, just record - // the unresolved variable as a component. - ty::Infer(infer_ty) => { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } - - // Most types do not introduce any region binders, nor - // involve any other subtle cases, and so the WF relation - // simply constraints any regions referenced directly by - // the type and then visits the types that are lexically - // contained within. (The comments refer to relevant rules - // from RFC1214.) - ty::Bool | // OutlivesScalar - ty::Char | // OutlivesScalar - ty::Int(..) | // OutlivesScalar - ty::Uint(..) | // OutlivesScalar - ty::Float(..) | // OutlivesScalar - ty::Never | // ... - ty::Adt(..) | // OutlivesNominalType - ty::Opaque(..) | // OutlivesNominalType (ish) - ty::Foreign(..) | // OutlivesNominalType - ty::Str | // OutlivesScalar (ish) - ty::Slice(..) | // ... - ty::RawPtr(..) | // ... - ty::Ref(..) | // OutlivesReference - ty::Tuple(..) | // ... - ty::FnPtr(_) | // OutlivesFunction (*) - ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) - ty::Placeholder(..) | - ty::Bound(..) | - ty::Error(_) => { - // (*) Function pointers and trait objects are both binders. - // In the RFC, this means we would add the bound regions to - // the "bound regions list". In our representation, no such - // list is maintained explicitly, because bound regions - // themselves can be readily identified. - compute_components_recursive(tcx, ty.into(), out, visited); - } - } -} - -fn compute_components_recursive( - tcx: TyCtxt<'tcx>, - parent: GenericArg<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet>, -) { - for child in parent.walk_shallow(tcx, visited) { - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(lt) => { - // Ignore late-bound regions. - if !lt.is_late_bound() { - out.push(Component::Region(lt)); - } - } - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/print/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/print/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/print/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/print/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -98,14 +98,14 @@ // Defaults (should not be overridden): + #[instrument(skip(self), level = "debug")] fn default_print_def_path( self, def_id: DefId, substs: &'tcx [GenericArg<'tcx>], ) -> Result { - debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs); let key = self.tcx().def_key(def_id); - debug!("default_print_def_path: key={:?}", key); + debug!(?key); match key.disambiguated_data.data { DefPathData::CrateRoot => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/print/pretty.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/print/pretty.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/print/pretty.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/print/pretty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -use crate::middle::cstore::{ExternCrate, ExternCrateSource}; use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable}; @@ -11,6 +10,7 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_hir::ItemKind; use rustc_session::config::TrimmedDefPaths; +use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -59,6 +59,7 @@ static SHOULD_PREFIX_WITH_CRATE: Cell = const { Cell::new(false) }; static NO_TRIMMED_PATH: Cell = const { Cell::new(false) }; static NO_QUERIES: Cell = const { Cell::new(false) }; + static NO_VISIBLE_PATH: Cell = const { Cell::new(false) }; } /// Avoids running any queries during any prints that occur @@ -112,6 +113,16 @@ }) } +/// Prevent selection of visible paths. `Display` impl of DefId will prefer visible (public) reexports of types as paths. +pub fn with_no_visible_paths R, R>(f: F) -> R { + NO_VISIBLE_PATH.with(|flag| { + let old = flag.replace(true); + let result = f(); + flag.set(old); + result + }) +} + /// The "region highlights" are used to control region printing during /// specific error messages. When a "region highlight" is enabled, it /// gives an alternate way to print specific regions. For now, we @@ -268,6 +279,10 @@ /// from at least one local module, and returns `true`. If the crate defining `def_id` is /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`. fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), Self::Error> { + if NO_VISIBLE_PATH.with(|flag| flag.get()) { + return Ok((self, false)); + } + let mut callers = Vec::new(); self.try_print_visible_def_path_recur(def_id, &mut callers) } @@ -2018,12 +2033,11 @@ Ok(inner) } + #[instrument(skip(self), level = "debug")] fn prepare_late_bound_region_info(&mut self, value: &ty::Binder<'tcx, T>) where T: TypeFoldable<'tcx>, { - debug!("prepare_late_bound_region_info(value: {:?})", value); - struct LateBoundRegionNameCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, used_region_names: &'a mut FxHashSet, @@ -2037,8 +2051,9 @@ Some(self.tcx) } + #[instrument(skip(self), level = "trace")] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r); + trace!("address: {:p}", r); if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { self.used_region_names.insert(name); } else if let ty::RePlaceholder(ty::PlaceholderRegion { @@ -2053,8 +2068,8 @@ // We collect types in order to prevent really large types from compiling for // a really long time. See issue #83150 for why this is necessary. + #[instrument(skip(self), level = "trace")] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - debug!("LateBoundRegionNameCollector::visit_ty(ty: {:?}", ty); let not_previously_inserted = self.type_collector.insert(ty); if not_previously_inserted { ty.super_visit_with(self) @@ -2156,10 +2171,26 @@ } } +/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only +/// the trait name. That is, it will print `Trait` instead of +/// `>`. +#[derive(Copy, Clone, TypeFoldable, Lift)] +pub struct TraitRefPrintOnlyTraitName<'tcx>(ty::TraitRef<'tcx>); + +impl fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + impl ty::TraitRef<'tcx> { pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> { TraitRefPrintOnlyTraitPath(self) } + + pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> { + TraitRefPrintOnlyTraitName(self) + } } impl ty::Binder<'tcx, ty::TraitRef<'tcx>> { @@ -2179,6 +2210,7 @@ ty::Binder<'tcx, ty::TraitRef<'tcx>>, ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>, ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>, @@ -2241,6 +2273,10 @@ p!(print_def_path(self.0.def_id, self.0.substs)); } + TraitRefPrintOnlyTraitName<'tcx> { + p!(print_def_path(self.0.def_id, &[])); + } + ty::ParamTy { p!(write("{}", self.name)) } @@ -2326,7 +2362,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) { // Iterate all local crate items no matter where they are defined. let hir = tcx.hir(); - for item in hir.krate().items() { + for item in hir.items() { if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) { continue; } @@ -2394,7 +2430,7 @@ /// /// The implementation uses similar import discovery logic to that of 'use' suggestions. fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap { - let mut map = FxHashMap::default(); + let mut map: FxHashMap = FxHashMap::default(); if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths { // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths` @@ -2432,8 +2468,29 @@ }); for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() { + use std::collections::hash_map::Entry::{Occupied, Vacant}; + if let Some(def_id) = opt_def_id { - map.insert(def_id, symbol); + match map.entry(def_id) { + Occupied(mut v) => { + // A single DefId can be known under multiple names (e.g., + // with a `pub use ... as ...;`). We need to ensure that the + // name placed in this map is chosen deterministically, so + // if we find multiple names (`symbol`) resolving to the + // same `def_id`, we prefer the lexicographically smallest + // name. + // + // Any stable ordering would be fine here though. + if *v.get() != symbol { + if v.get().as_str() > symbol.as_str() { + v.insert(symbol); + } + } + } + Vacant(v) => { + v.insert(symbol); + } + } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/query.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/query.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/query.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/query.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::cstore::{CrateDepKind, CrateSource}; -use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::AccessLevels; @@ -46,8 +44,11 @@ use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; +use rustc_session::cstore::{CrateDepKind, CrateSource}; +use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; use rustc_session::utils::NativeLibKind; use rustc_session::Limits; +use rustc_target::abi; use rustc_target::spec::PanicStrategy; use rustc_ast as ast; @@ -110,11 +111,11 @@ ([][$K:ty, $V:ty]) => { >::Cache }; - ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => { + ([(storage $ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => { <$ty as CacheSelector<$K, $V>>::Cache }; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - query_storage!([$($($modifiers)*)*][$($args)*]) + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + query_storage!([$($modifiers)*][$($args)*]) }; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/relate.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/relate.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/relate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/relate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -639,6 +639,15 @@ get_slice_bytes(&tcx, a_val) == get_slice_bytes(&tcx, b_val) } + (ConstValue::ByRef { alloc: alloc_a, .. }, ConstValue::ByRef { alloc: alloc_b, .. }) + if a.ty.is_ref() || b.ty.is_ref() => + { + if a.ty.is_ref() && b.ty.is_ref() { + alloc_a == alloc_b + } else { + false + } + } (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { let a_destructured = tcx.destructure_const(relation.param_env().and(a)); let b_destructured = tcx.destructure_const(relation.param_env().and(b)); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/structural_impls.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/structural_impls.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/structural_impls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/structural_impls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -638,8 +638,8 @@ Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)) } ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)), - ty::InstanceDef::ClosureOnceShim { call_once } => { - Some(ty::InstanceDef::ClosureOnceShim { call_once }) + ty::InstanceDef::ClosureOnceShim { call_once, track_caller } => { + Some(ty::InstanceDef::ClosureOnceShim { call_once, track_caller }) } ty::InstanceDef::DropGlue(def_id, ty) => { Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)) @@ -824,8 +824,8 @@ Intrinsic(did) => Intrinsic(did.fold_with(folder)), FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)), Virtual(did, i) => Virtual(did.fold_with(folder), i), - ClosureOnceShim { call_once } => { - ClosureOnceShim { call_once: call_once.fold_with(folder) } + ClosureOnceShim { call_once, track_caller } => { + ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller } } DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)), CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)), @@ -849,7 +849,7 @@ did.visit_with(visitor)?; ty.visit_with(visitor) } - ClosureOnceShim { call_once } => call_once.visit_with(visitor), + ClosureOnceShim { call_once, track_caller: _ } => call_once.visit_with(visitor), } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/sty.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/sty.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/sty.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/sty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -643,7 +643,7 @@ } /// This returns the types of the MIR locals which had to be stored across suspension points. - /// It is calculated in rustc_mir::transform::generator::StateTransform. + /// It is calculated in rustc_const_eval::transform::generator::StateTransform. /// All the types here must be in the tuple in GeneratorInterior. /// /// The locals are grouped by their variant number. Note that some locals may @@ -844,8 +844,11 @@ /// Returns a `TraitRef` of the form `P0: Foo` where `Pi` /// are the parameters defined on trait. - pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> { - TraitRef { def_id, substs: InternalSubsts::identity_for_item(tcx, def_id) } + pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> { + ty::Binder::dummy(TraitRef { + def_id, + substs: InternalSubsts::identity_for_item(tcx, def_id), + }) } #[inline] @@ -1268,7 +1271,7 @@ /// Representation of regions. Note that the NLL checker uses a distinct /// representation of regions. For this reason, it internally replaces all the /// regions with inference variables -- the index of the variable is then used -/// to index into internal NLL data structures. See `rustc_mir::borrow_check` +/// to index into internal NLL data structures. See `rustc_const_eval::borrow_check` /// module for more information. /// /// ## The Region lattice within a given function @@ -1673,6 +1676,14 @@ } #[inline] + pub fn ty_vid(&self) -> Option { + match self.kind() { + &Infer(TyVar(vid)) => Some(vid), + _ => None, + } + } + + #[inline] pub fn is_ty_infer(&self) -> bool { matches!(self.kind(), Infer(_)) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/trait_def.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/trait_def.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/trait_def.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/trait_def.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -use crate::ich::{self, StableHashingContext}; use crate::traits::specialization_graph; use crate::ty::fast_reject; use crate::ty::fold::TypeFoldable; @@ -7,8 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::definitions::DefPathHash; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorReported; use rustc_macros::HashStable; @@ -66,11 +64,11 @@ AlwaysApplicable, } -#[derive(Default, Debug)] +#[derive(Default, Debug, HashStable)] pub struct TraitImpls { blanket_impls: Vec, /// Impls indexed by their simplified self type, for fast lookup. - non_blanket_impls: FxHashMap>, + non_blanket_impls: FxIndexMap>, } impl TraitImpls { @@ -249,11 +247,3 @@ impls } - -impl<'a> HashStable> for TraitImpls { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let TraitImpls { ref blanket_impls, ref non_blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, non_blanket_impls); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_middle/src/ty/util.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_middle/src/ty/util.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. -use crate::ich::NodeIdHashingMode; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::fold::TypeFolder; use crate::ty::layout::IntegerExt; @@ -18,6 +17,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; +use rustc_query_system::ich::NodeIdHashingMode; use rustc_span::DUMMY_SP; use rustc_target::abi::{Integer, Size, TargetDataLayout}; use smallvec::SmallVec; @@ -45,18 +45,6 @@ } } -fn signed_min(size: Size) -> i128 { - size.sign_extend(1_u128 << (size.bits() - 1)) as i128 -} - -fn signed_max(size: Size) -> i128 { - i128::MAX >> (128 - size.bits()) -} - -fn unsigned_max(size: Size) -> u128 { - u128::MAX >> (128 - size.bits()) -} - fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { let (int, signed) = match *ty.kind() { Int(ity) => (Integer::from_int_ty(&tcx, ity), true), @@ -74,8 +62,8 @@ pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) { let (size, signed) = int_size_and_signed(tcx, self.ty); let (val, oflo) = if signed { - let min = signed_min(size); - let max = signed_max(size); + let min = size.signed_int_min(); + let max = size.signed_int_max(); let val = size.sign_extend(self.val) as i128; assert!(n < (i128::MAX as u128)); let n = n as i128; @@ -86,7 +74,7 @@ let val = size.truncate(val); (val, oflo) } else { - let max = unsigned_max(size); + let max = size.unsigned_int_max(); let val = self.val; let oflo = val > max - n; let val = if oflo { n - (max - val) - 1 } else { val + n }; @@ -336,16 +324,16 @@ self.ensure().coherent_trait(drop_trait); let ty = self.type_of(adt_did); - let dtor_did = self.find_map_relevant_impl(drop_trait, ty, |impl_did| { + let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| { if let Some(item) = self.associated_items(impl_did).in_definition_order().next() { if validate(self, impl_did).is_ok() { - return Some(item.def_id); + return Some((item.def_id, self.impl_constness(impl_did))); } } None - }); + })?; - Some(ty::Destructor { did: dtor_did? }) + Some(ty::Destructor { did, constness }) } /// Returns the set of types that are required to be alive in @@ -528,6 +516,7 @@ } /// Expands the given impl trait type, stopping if the type is recursive. + #[instrument(skip(self), level = "debug")] pub fn try_expand_impl_trait_type( self, def_id: DefId, @@ -544,6 +533,7 @@ }; let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); + trace!(?expanded_type); if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } } @@ -621,7 +611,8 @@ let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); - let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) }; + let val = + if signed { size.signed_int_max() as u128 } else { size.unsigned_int_max() }; Some(val) } ty::Char => Some(std::char::MAX as u128), @@ -640,7 +631,7 @@ let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); - let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 }; + let val = if signed { size.truncate(size.signed_int_min() as u128) } else { 0 }; Some(val) } ty::Char => Some(0), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -[package] -name = "rustc_mir" -version = "0.0.0" -edition = "2018" - -[lib] -doctest = false - -[dependencies] -either = "1.5.0" -rustc_graphviz = { path = "../rustc_graphviz" } -gsgdt = "0.1.2" -itertools = "0.9" -tracing = "0.1" -polonius-engine = "0.13.0" -regex = "1" -rustc_middle = { path = "../rustc_middle" } -rustc_attr = { path = "../rustc_attr" } -rustc_data_structures = { path = "../rustc_data_structures" } -rustc_errors = { path = "../rustc_errors" } -rustc_hir = { path = "../rustc_hir" } -rustc_index = { path = "../rustc_index" } -rustc_infer = { path = "../rustc_infer" } -rustc_lexer = { path = "../rustc_lexer" } -rustc_macros = { path = "../rustc_macros" } -rustc_serialize = { path = "../rustc_serialize" } -rustc_session = { path = "../rustc_session" } -rustc_target = { path = "../rustc_target" } -rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_traits = { path = "../rustc_traits" } -rustc_ast = { path = "../rustc_ast" } -rustc_span = { path = "../rustc_span" } -rustc_apfloat = { path = "../rustc_apfloat" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } - -[dev-dependencies] -coverage_test_macros = { path = "src/transform/coverage/test_macros" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/borrow_set.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/borrow_set.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/borrow_set.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/borrow_set.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,351 +0,0 @@ -use crate::borrow_check::nll::ToRegionVid; -use crate::borrow_check::path_utils::allow_two_phase_borrow; -use crate::borrow_check::place_ext::PlaceExt; -use crate::dataflow::indexes::BorrowIndex; -use crate::dataflow::move_paths::MoveData; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::traversal; -use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, Body, Local, Location}; -use rustc_middle::ty::{RegionVid, TyCtxt}; -use std::fmt; -use std::ops::Index; - -crate struct BorrowSet<'tcx> { - /// The fundamental map relating bitvector indexes to the borrows - /// in the MIR. Each borrow is also uniquely identified in the MIR - /// by the `Location` of the assignment statement in which it - /// appears on the right hand side. Thus the location is the map - /// key, and its position in the map corresponds to `BorrowIndex`. - crate location_map: FxIndexMap>, - - /// Locations which activate borrows. - /// NOTE: a given location may activate more than one borrow in the future - /// when more general two-phase borrow support is introduced, but for now we - /// only need to store one borrow index. - crate activation_map: FxHashMap>, - - /// Map from local to all the borrows on that local. - crate local_map: FxHashMap>, - - crate locals_state_at_exit: LocalsStateAtExit, -} - -impl<'tcx> Index for BorrowSet<'tcx> { - type Output = BorrowData<'tcx>; - - fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> { - &self.location_map[index.as_usize()] - } -} - -/// Location where a two-phase borrow is activated, if a borrow -/// is in fact a two-phase borrow. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -crate enum TwoPhaseActivation { - NotTwoPhase, - NotActivated, - ActivatedAt(Location), -} - -#[derive(Debug, Clone)] -crate struct BorrowData<'tcx> { - /// Location where the borrow reservation starts. - /// In many cases, this will be equal to the activation location but not always. - crate reserve_location: Location, - /// Location where the borrow is activated. - crate activation_location: TwoPhaseActivation, - /// What kind of borrow this is - crate kind: mir::BorrowKind, - /// The region for which this borrow is live - crate region: RegionVid, - /// Place from which we are borrowing - crate borrowed_place: mir::Place<'tcx>, - /// Place to which the borrow was stored - crate assigned_place: mir::Place<'tcx>, -} - -impl<'tcx> fmt::Display for BorrowData<'tcx> { - fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { - let kind = match self.kind { - mir::BorrowKind::Shared => "", - mir::BorrowKind::Shallow => "shallow ", - mir::BorrowKind::Unique => "uniq ", - mir::BorrowKind::Mut { .. } => "mut ", - }; - write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) - } -} - -crate enum LocalsStateAtExit { - AllAreInvalidated, - SomeAreInvalidated { has_storage_dead_or_moved: BitSet }, -} - -impl LocalsStateAtExit { - fn build( - locals_are_invalidated_at_exit: bool, - body: &Body<'tcx>, - move_data: &MoveData<'tcx>, - ) -> Self { - struct HasStorageDead(BitSet); - - impl<'tcx> Visitor<'tcx> for HasStorageDead { - fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { - if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) { - self.0.insert(*local); - } - } - } - - if locals_are_invalidated_at_exit { - LocalsStateAtExit::AllAreInvalidated - } else { - let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body.local_decls.len())); - has_storage_dead.visit_body(&body); - let mut has_storage_dead_or_moved = has_storage_dead.0; - for move_out in &move_data.moves { - if let Some(index) = move_data.base_local(move_out.path) { - has_storage_dead_or_moved.insert(index); - } - } - LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } - } - } -} - -impl<'tcx> BorrowSet<'tcx> { - pub fn build( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - locals_are_invalidated_at_exit: bool, - move_data: &MoveData<'tcx>, - ) -> Self { - let mut visitor = GatherBorrows { - tcx, - body: &body, - location_map: Default::default(), - activation_map: Default::default(), - local_map: Default::default(), - pending_activations: Default::default(), - locals_state_at_exit: LocalsStateAtExit::build( - locals_are_invalidated_at_exit, - body, - move_data, - ), - }; - - for (block, block_data) in traversal::preorder(&body) { - visitor.visit_basic_block_data(block, block_data); - } - - BorrowSet { - location_map: visitor.location_map, - activation_map: visitor.activation_map, - local_map: visitor.local_map, - locals_state_at_exit: visitor.locals_state_at_exit, - } - } - - crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] { - self.activation_map.get(&location).map_or(&[], |activations| &activations[..]) - } - - crate fn len(&self) -> usize { - self.location_map.len() - } - - crate fn indices(&self) -> impl Iterator { - BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len()) - } - - crate fn iter_enumerated(&self) -> impl Iterator)> { - self.indices().zip(self.location_map.values()) - } - - crate fn get_index_of(&self, location: &Location) -> Option { - self.location_map.get_index_of(location).map(BorrowIndex::from) - } - - crate fn contains(&self, location: &Location) -> bool { - self.location_map.contains_key(location) - } -} - -struct GatherBorrows<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - location_map: FxIndexMap>, - activation_map: FxHashMap>, - local_map: FxHashMap>, - - /// When we encounter a 2-phase borrow statement, it will always - /// be assigning into a temporary TEMP: - /// - /// TEMP = &foo - /// - /// We add TEMP into this map with `b`, where `b` is the index of - /// the borrow. When we find a later use of this activation, we - /// remove from the map (and add to the "tombstone" set below). - pending_activations: FxHashMap, - - locals_state_at_exit: LocalsStateAtExit, -} - -impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { - fn visit_assign( - &mut self, - assigned_place: &mir::Place<'tcx>, - rvalue: &mir::Rvalue<'tcx>, - location: mir::Location, - ) { - if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue { - if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) { - debug!("ignoring_borrow of {:?}", borrowed_place); - return; - } - - let region = region.to_region_vid(); - - let borrow = BorrowData { - kind, - region, - reserve_location: location, - activation_location: TwoPhaseActivation::NotTwoPhase, - borrowed_place: *borrowed_place, - assigned_place: *assigned_place, - }; - let (idx, _) = self.location_map.insert_full(location, borrow); - let idx = BorrowIndex::from(idx); - - self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx); - - self.local_map.entry(borrowed_place.local).or_default().insert(idx); - } - - self.super_assign(assigned_place, rvalue, location) - } - - fn visit_local(&mut self, temp: &Local, context: PlaceContext, location: Location) { - if !context.is_use() { - return; - } - - // We found a use of some temporary TMP - // check whether we (earlier) saw a 2-phase borrow like - // - // TMP = &mut place - if let Some(&borrow_index) = self.pending_activations.get(temp) { - let borrow_data = &mut self.location_map[borrow_index.as_usize()]; - - // Watch out: the use of TMP in the borrow itself - // doesn't count as an activation. =) - if borrow_data.reserve_location == location - && context == PlaceContext::MutatingUse(MutatingUseContext::Store) - { - return; - } - - if let TwoPhaseActivation::ActivatedAt(other_location) = borrow_data.activation_location - { - span_bug!( - self.body.source_info(location).span, - "found two uses for 2-phase borrow temporary {:?}: \ - {:?} and {:?}", - temp, - location, - other_location, - ); - } - - // Otherwise, this is the unique later use that we expect. - // Double check: This borrow is indeed a two-phase borrow (that is, - // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and - // we've not found any other activations (checked above). - assert_eq!( - borrow_data.activation_location, - TwoPhaseActivation::NotActivated, - "never found an activation for this borrow!", - ); - self.activation_map.entry(location).or_default().push(borrow_index); - - borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location); - } - } - - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) { - if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue { - // double-check that we already registered a BorrowData for this - - let borrow_data = &self.location_map[&location]; - assert_eq!(borrow_data.reserve_location, location); - assert_eq!(borrow_data.kind, kind); - assert_eq!(borrow_data.region, region.to_region_vid()); - assert_eq!(borrow_data.borrowed_place, *place); - } - - self.super_rvalue(rvalue, location) - } -} - -impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { - /// If this is a two-phase borrow, then we will record it - /// as "pending" until we find the activating use. - fn insert_as_pending_if_two_phase( - &mut self, - start_location: Location, - assigned_place: &mir::Place<'tcx>, - kind: mir::BorrowKind, - borrow_index: BorrowIndex, - ) { - debug!( - "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})", - start_location, assigned_place, borrow_index, - ); - - if !allow_two_phase_borrow(kind) { - debug!(" -> {:?}", start_location); - return; - } - - // When we encounter a 2-phase borrow statement, it will always - // be assigning into a temporary TEMP: - // - // TEMP = &foo - // - // so extract `temp`. - let temp = if let Some(temp) = assigned_place.as_local() { - temp - } else { - span_bug!( - self.body.source_info(start_location).span, - "expected 2-phase borrow to assign to a local, not `{:?}`", - assigned_place, - ); - }; - - // Consider the borrow not activated to start. When we find an activation, we'll update - // this field. - { - let borrow_data = &mut self.location_map[borrow_index.as_usize()]; - borrow_data.activation_location = TwoPhaseActivation::NotActivated; - } - - // Insert `temp` into the list of pending activations. From - // now on, we'll be on the lookout for a use of it. Note that - // we are guaranteed that this use will come after the - // assignment. - let old_value = self.pending_activations.insert(temp, borrow_index); - if let Some(old_index) = old_value { - span_bug!( - self.body.source_info(start_location).span, - "found already pending activation for temp: {:?} \ - at borrow_index: {:?} with associated data {:?}", - temp, - old_index, - self.location_map[old_index.as_usize()] - ); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraint_generation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraint_generation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraint_generation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraint_generation.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,252 +0,0 @@ -use rustc_infer::infer::InferCtxt; -use rustc_middle::mir::visit::TyContext; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, - SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, -}; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, RegionVid, Ty}; - -use crate::borrow_check::{ - borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid, - places_conflict, region_infer::values::LivenessValues, -}; - -pub(super) fn generate_constraints<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, - liveness_constraints: &mut LivenessValues, - all_facts: &mut Option, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) { - let mut cg = ConstraintGeneration { - borrow_set, - infcx, - liveness_constraints, - location_table, - all_facts, - body, - }; - - for (bb, data) in body.basic_blocks().iter_enumerated() { - cg.visit_basic_block_data(bb, data); - } -} - -/// 'cg = the duration of the constraint generation process itself. -struct ConstraintGeneration<'cg, 'cx, 'tcx> { - infcx: &'cg InferCtxt<'cx, 'tcx>, - all_facts: &'cg mut Option, - location_table: &'cg LocationTable, - liveness_constraints: &'cg mut LivenessValues, - borrow_set: &'cg BorrowSet<'tcx>, - body: &'cg Body<'tcx>, -} - -impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { - fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { - self.super_basic_block_data(bb, data); - } - - /// We sometimes have `substs` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_substs(&mut self, substs: &SubstsRef<'tcx>, location: Location) { - self.add_regular_live_constraint(*substs, location); - self.super_substs(substs); - } - - /// We sometimes have `region` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) { - self.add_regular_live_constraint(*region, location); - self.super_region(region); - } - - /// We sometimes have `ty` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) { - match ty_context { - TyContext::ReturnTy(SourceInfo { span, .. }) - | TyContext::YieldTy(SourceInfo { span, .. }) - | TyContext::UserTy(span) - | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => { - span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context); - } - TyContext::Location(location) => { - self.add_regular_live_constraint(ty, location); - } - } - - self.super_ty(ty); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - if let Some(all_facts) = self.all_facts { - let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - all_facts.cfg_edge.push(( - self.location_table.start_index(location), - self.location_table.mid_index(location), - )); - - all_facts.cfg_edge.push(( - self.location_table.mid_index(location), - self.location_table.start_index(location.successor_within_block()), - )); - - // If there are borrows on this now dead local, we need to record them as `killed`. - if let StatementKind::StorageDead(local) = statement.kind { - record_killed_borrows_for_local( - all_facts, - self.borrow_set, - self.location_table, - local, - location, - ); - } - } - - self.super_statement(statement, location); - } - - fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - // When we see `X = ...`, then kill borrows of - // `(*X).foo` and so forth. - self.record_killed_borrows_for_place(*place, location); - - self.super_assign(place, rvalue, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - if let Some(all_facts) = self.all_facts { - let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - all_facts.cfg_edge.push(( - self.location_table.start_index(location), - self.location_table.mid_index(location), - )); - - let successor_blocks = terminator.successors(); - all_facts.cfg_edge.reserve(successor_blocks.size_hint().0); - for successor_block in successor_blocks { - all_facts.cfg_edge.push(( - self.location_table.mid_index(location), - self.location_table.start_index(successor_block.start_location()), - )); - } - } - - // A `Call` terminator's return value can be a local which has borrows, - // so we need to record those as `killed` as well. - if let TerminatorKind::Call { destination, .. } = terminator.kind { - if let Some((place, _)) = destination { - self.record_killed_borrows_for_place(place, location); - } - } - - self.super_terminator(terminator, location); - } - - fn visit_ascribe_user_ty( - &mut self, - _place: &Place<'tcx>, - _variance: &ty::Variance, - _user_ty: &UserTypeProjection, - _location: Location, - ) { - } -} - -impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { - /// Some variable with type `live_ty` is "regular live" at - /// `location` -- i.e., it may be used later. This means that all - /// regions appearing in the type `live_ty` must be live at - /// `location`. - fn add_regular_live_constraint(&mut self, live_ty: T, location: Location) - where - T: TypeFoldable<'tcx>, - { - debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location); - - self.infcx.tcx.for_each_free_region(&live_ty, |live_region| { - let vid = live_region.to_region_vid(); - self.liveness_constraints.add_element(vid, location); - }); - } - - /// When recording facts for Polonius, records the borrows on the specified place - /// as `killed`. For example, when assigning to a local, or on a call's return destination. - fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) { - if let Some(all_facts) = self.all_facts { - let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - - // Depending on the `Place` we're killing: - // - if it's a local, or a single deref of a local, - // we kill all the borrows on the local. - // - if it's a deeper projection, we have to filter which - // of the borrows are killed: the ones whose `borrowed_place` - // conflicts with the `place`. - match place.as_ref() { - PlaceRef { local, projection: &[] } - | PlaceRef { local, projection: &[ProjectionElem::Deref] } => { - debug!( - "Recording `killed` facts for borrows of local={:?} at location={:?}", - local, location - ); - - record_killed_borrows_for_local( - all_facts, - self.borrow_set, - self.location_table, - local, - location, - ); - } - - PlaceRef { local, projection: &[.., _] } => { - // Kill conflicting borrows of the innermost local. - debug!( - "Recording `killed` facts for borrows of \ - innermost projected local={:?} at location={:?}", - local, location - ); - - if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { - for &borrow_index in borrow_indices { - let places_conflict = places_conflict::places_conflict( - self.infcx.tcx, - self.body, - self.borrow_set[borrow_index].borrowed_place, - place, - places_conflict::PlaceConflictBias::NoOverlap, - ); - - if places_conflict { - let location_index = self.location_table.mid_index(location); - all_facts.loan_killed_at.push((borrow_index, location_index)); - } - } - } - } - } - } - } -} - -/// When recording facts for Polonius, records the borrows on the specified local as `killed`. -fn record_killed_borrows_for_local( - all_facts: &mut AllFacts, - borrow_set: &BorrowSet<'_>, - location_table: &LocationTable, - local: Local, - location: Location, -) { - if let Some(borrow_indices) = borrow_set.local_map.get(&local) { - all_facts.loan_killed_at.reserve(borrow_indices.len()); - for &borrow_index in borrow_indices { - let location_index = location_table.mid_index(location); - all_facts.loan_killed_at.push((borrow_index, location_index)); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraints/graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraints/graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraints/graph.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraints/graph.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,233 +0,0 @@ -use rustc_data_structures::graph; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; -use rustc_span::DUMMY_SP; - -use crate::borrow_check::{ - constraints::OutlivesConstraintIndex, - constraints::{OutlivesConstraint, OutlivesConstraintSet}, - type_check::Locations, -}; - -/// The construct graph organizes the constraints by their end-points. -/// It can be used to view a `R1: R2` constraint as either an edge `R1 -/// -> R2` or `R2 -> R1` depending on the direction type `D`. -crate struct ConstraintGraph { - _direction: D, - first_constraints: IndexVec>, - next_constraints: IndexVec>, -} - -crate type NormalConstraintGraph = ConstraintGraph; - -crate type ReverseConstraintGraph = ConstraintGraph; - -/// Marker trait that controls whether a `R1: R2` constraint -/// represents an edge `R1 -> R2` or `R2 -> R1`. -crate trait ConstraintGraphDirecton: Copy + 'static { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid; - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid; - fn is_normal() -> bool; -} - -/// In normal mode, a `R1: R2` constraint results in an edge `R1 -> -/// R2`. This is what we use when constructing the SCCs for -/// inference. This is because we compute the value of R1 by union'ing -/// all the things that it relies on. -#[derive(Copy, Clone, Debug)] -crate struct Normal; - -impl ConstraintGraphDirecton for Normal { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sup - } - - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sub - } - - fn is_normal() -> bool { - true - } -} - -/// In reverse mode, a `R1: R2` constraint results in an edge `R2 -> -/// R1`. We use this for optimizing liveness computation, because then -/// we wish to iterate from a region (e.g., R2) to all the regions -/// that will outlive it (e.g., R1). -#[derive(Copy, Clone, Debug)] -crate struct Reverse; - -impl ConstraintGraphDirecton for Reverse { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sub - } - - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sup - } - - fn is_normal() -> bool { - false - } -} - -impl ConstraintGraph { - /// Creates a "dependency graph" where each region constraint `R1: - /// R2` is treated as an edge `R1 -> R2`. We use this graph to - /// construct SCCs for region inference but also for error - /// reporting. - crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self { - let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars); - let mut next_constraints = IndexVec::from_elem(None, &set.outlives); - - for (idx, constraint) in set.outlives.iter_enumerated().rev() { - let head = &mut first_constraints[D::start_region(constraint)]; - let next = &mut next_constraints[idx]; - debug_assert!(next.is_none()); - *next = *head; - *head = Some(idx); - } - - Self { _direction: direction, first_constraints, next_constraints } - } - - /// Given the constraint set from which this graph was built - /// creates a region graph so that you can iterate over *regions* - /// and not constraints. - crate fn region_graph<'rg, 'tcx>( - &'rg self, - set: &'rg OutlivesConstraintSet<'tcx>, - static_region: RegionVid, - ) -> RegionGraph<'rg, 'tcx, D> { - RegionGraph::new(set, self, static_region) - } - - /// Given a region `R`, iterate over all constraints `R: R1`. - crate fn outgoing_edges<'a, 'tcx>( - &'a self, - region_sup: RegionVid, - constraints: &'a OutlivesConstraintSet<'tcx>, - static_region: RegionVid, - ) -> Edges<'a, 'tcx, D> { - //if this is the `'static` region and the graph's direction is normal, - //then setup the Edges iterator to return all regions #53178 - if region_sup == static_region && D::is_normal() { - Edges { - graph: self, - constraints, - pointer: None, - next_static_idx: Some(0), - static_region, - } - } else { - //otherwise, just setup the iterator as normal - let first = self.first_constraints[region_sup]; - Edges { graph: self, constraints, pointer: first, next_static_idx: None, static_region } - } - } -} - -crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> { - graph: &'s ConstraintGraph, - constraints: &'s OutlivesConstraintSet<'tcx>, - pointer: Option, - next_static_idx: Option, - static_region: RegionVid, -} - -impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> { - type Item = OutlivesConstraint<'tcx>; - - fn next(&mut self) -> Option { - if let Some(p) = self.pointer { - self.pointer = self.graph.next_constraints[p]; - - Some(self.constraints[p].clone()) - } else if let Some(next_static_idx) = self.next_static_idx { - self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) { - None - } else { - Some(next_static_idx + 1) - }; - - Some(OutlivesConstraint { - sup: self.static_region, - sub: next_static_idx.into(), - locations: Locations::All(DUMMY_SP), - category: ConstraintCategory::Internal, - variance_info: VarianceDiagInfo::default(), - }) - } else { - None - } - } -} - -/// This struct brings together a constraint set and a (normal, not -/// reverse) constraint graph. It implements the graph traits and is -/// usd for doing the SCC computation. -crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> { - set: &'s OutlivesConstraintSet<'tcx>, - constraint_graph: &'s ConstraintGraph, - static_region: RegionVid, -} - -impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> { - /// Creates a "dependency graph" where each region constraint `R1: - /// R2` is treated as an edge `R1 -> R2`. We use this graph to - /// construct SCCs for region inference but also for error - /// reporting. - crate fn new( - set: &'s OutlivesConstraintSet<'tcx>, - constraint_graph: &'s ConstraintGraph, - static_region: RegionVid, - ) -> Self { - Self { set, constraint_graph, static_region } - } - - /// Given a region `R`, iterate over all regions `R1` such that - /// there exists a constraint `R: R1`. - crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> { - Successors { - edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), - } - } -} - -crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> { - edges: Edges<'s, 'tcx, D>, -} - -impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> { - type Item = RegionVid; - - fn next(&mut self) -> Option { - self.edges.next().map(|c| D::end_region(&c)) - } -} - -impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { - type Node = RegionVid; -} - -impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> { - fn num_nodes(&self) -> usize { - self.constraint_graph.first_constraints.len() - } -} - -impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { - fn successors(&self, node: Self::Node) -> >::Iter { - self.outgoing_regions(node) - } -} - -impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> - for RegionGraph<'s, 'tcx, D> -{ - type Item = RegionVid; - // FIXME - why can't this be `'graph, 'tcx` - type Iter = Successors<'graph, 'graph, D>; -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraints/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraints/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraints/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/constraints/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -use rustc_data_structures::graph::scc::Sccs; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; -use std::fmt; -use std::ops::Index; - -use crate::borrow_check::type_check::Locations; - -crate mod graph; - -/// A set of NLL region constraints. These include "outlives" -/// constraints of the form `R1: R2`. Each constraint is identified by -/// a unique `OutlivesConstraintIndex` and you can index into the set -/// (`constraint_set[i]`) to access the constraint details. -#[derive(Clone, Default)] -crate struct OutlivesConstraintSet<'tcx> { - outlives: IndexVec>, -} - -impl<'tcx> OutlivesConstraintSet<'tcx> { - crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) { - debug!( - "OutlivesConstraintSet::push({:?}: {:?} @ {:?}", - constraint.sup, constraint.sub, constraint.locations - ); - if constraint.sup == constraint.sub { - // 'a: 'a is pretty uninteresting - return; - } - self.outlives.push(constraint); - } - - /// Constructs a "normal" graph from the constraint set; the graph makes it - /// easy to find the constraints affecting a particular region. - /// - /// N.B., this graph contains a "frozen" view of the current - /// constraints. Any new constraints added to the `OutlivesConstraintSet` - /// after the graph is built will not be present in the graph. - crate fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph { - graph::ConstraintGraph::new(graph::Normal, self, num_region_vars) - } - - /// Like `graph`, but constraints a reverse graph where `R1: R2` - /// represents an edge `R2 -> R1`. - crate fn reverse_graph(&self, num_region_vars: usize) -> graph::ReverseConstraintGraph { - graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars) - } - - /// Computes cycles (SCCs) in the graph of regions. In particular, - /// find all regions R1, R2 such that R1: R2 and R2: R1 and group - /// them into an SCC, and find the relationships between SCCs. - crate fn compute_sccs( - &self, - constraint_graph: &graph::NormalConstraintGraph, - static_region: RegionVid, - ) -> Sccs { - let region_graph = &constraint_graph.region_graph(self, static_region); - Sccs::new(region_graph) - } - - crate fn outlives(&self) -> &IndexVec> { - &self.outlives - } -} - -impl<'tcx> Index for OutlivesConstraintSet<'tcx> { - type Output = OutlivesConstraint<'tcx>; - - fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output { - &self.outlives[i] - } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct OutlivesConstraint<'tcx> { - // NB. The ordering here is not significant for correctness, but - // it is for convenience. Before we dump the constraints in the - // debugging logs, we sort them, and we'd like the "super region" - // to be first, etc. (In particular, span should remain last.) - /// The region SUP must outlive SUB... - pub sup: RegionVid, - - /// Region that must be outlived. - pub sub: RegionVid, - - /// Where did this constraint arise? - pub locations: Locations, - - /// What caused this constraint? - pub category: ConstraintCategory, - - /// Variance diagnostic information - pub variance_info: VarianceDiagInfo<'tcx>, -} - -impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - formatter, - "({:?}: {:?}) due to {:?} ({:?})", - self.sup, self.sub, self.locations, self.variance_info - ) - } -} - -rustc_index::newtype_index! { - pub struct OutlivesConstraintIndex { - DEBUG_FORMAT = "OutlivesConstraintIndex({})" - } -} - -rustc_index::newtype_index! { - pub struct ConstraintSccIndex { - DEBUG_FORMAT = "ConstraintSccIndex({})" - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/consumers.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/consumers.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/consumers.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/consumers.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -//! This file provides API for compiler consumers. - -use rustc_hir::def_id::LocalDefId; -use rustc_index::vec::IndexVec; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::mir::Body; -use rustc_middle::ty::{self, TyCtxt}; - -pub use super::{ - facts::{AllFacts as PoloniusInput, RustcFacts}, - location::{LocationTable, RichLocation}, - nll::PoloniusOutput, - BodyWithBorrowckFacts, -}; - -/// This function computes Polonius facts for the given body. It makes a copy of -/// the body because it needs to regenerate the region identifiers. -/// -/// Note: -/// * This function will panic if the required body was already stolen. This -/// can, for example, happen when requesting a body of a `const` function -/// because they are evaluated during typechecking. The panic can be avoided -/// by overriding the `mir_borrowck` query. You can find a complete example -/// that shows how to do this at `src/test/run-make/obtain-borrowck/`. -/// * This function will also panic if computation of Polonius facts -/// (`-Zpolonius` flag) is not enabled. -/// -/// * Polonius is highly unstable, so expect regular changes in its signature or other details. -pub fn get_body_with_borrowck_facts<'tcx>( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, -) -> BodyWithBorrowckFacts<'tcx> { - let (input_body, promoted) = tcx.mir_promoted(def); - tcx.infer_ctxt().enter(|infcx| { - let input_body: &Body<'_> = &input_body.borrow(); - let promoted: &IndexVec<_, _> = &promoted.borrow(); - *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() - }) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/def_use.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/def_use.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/def_use.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/def_use.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -use rustc_middle::mir::visit::{ - MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, -}; - -#[derive(Eq, PartialEq, Clone)] -pub enum DefUse { - Def, - Use, - Drop, -} - -pub fn categorize(context: PlaceContext) -> Option { - match context { - /////////////////////////////////////////////////////////////////////////// - // DEFS - - PlaceContext::MutatingUse(MutatingUseContext::Store) | - - // This is potentially both a def and a use... - PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | - - // We let Call define the result in both the success and - // unwind cases. This is not really correct, however it - // does not seem to be observable due to the way that we - // generate MIR. To do things properly, we would apply - // the def in call only to the input from the success - // path and not the unwind path. -nmatsakis - PlaceContext::MutatingUse(MutatingUseContext::Call) | - PlaceContext::MutatingUse(MutatingUseContext::Yield) | - - // Storage live and storage dead aren't proper defines, but we can ignore - // values that come before them. - PlaceContext::NonUse(NonUseContext::StorageLive) | - PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def), - - /////////////////////////////////////////////////////////////////////////// - // REGULAR USES - // - // These are uses that occur *outside* of a drop. For the - // purposes of NLL, these are special in that **all** the - // lifetimes appearing in the variable must be live for each regular use. - - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) | - PlaceContext::MutatingUse(MutatingUseContext::Projection) | - - // Borrows only consider their local used at the point of the borrow. - // This won't affect the results since we use this analysis for generators - // and we only care about the result at suspension points. Borrows cannot - // cross suspension points so this behavior is unproblematic. - PlaceContext::MutatingUse(MutatingUseContext::Borrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | - - PlaceContext::MutatingUse(MutatingUseContext::AddressOf) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) | - PlaceContext::NonUse(NonUseContext::AscribeUserTy) | - PlaceContext::MutatingUse(MutatingUseContext::Retag) => - Some(DefUse::Use), - - /////////////////////////////////////////////////////////////////////////// - // DROP USES - // - // These are uses that occur in a DROP (a MIR drop, not a - // call to `std::mem::drop()`). For the purposes of NLL, - // uses in drop are special because `#[may_dangle]` - // attributes can affect whether lifetimes must be live. - - PlaceContext::MutatingUse(MutatingUseContext::Drop) => - Some(DefUse::Drop), - - // Debug info is neither def nor use. - PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,373 +0,0 @@ -use rustc_errors::DiagnosticBuilder; -use rustc_infer::infer::canonical::Canonical; -use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc_infer::infer::region_constraints::Constraint; -use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _}; -use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt}; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_span::Span; -use rustc_trait_selection::traits::query::type_op; -use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _}; -use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span}; - -use std::fmt; -use std::rc::Rc; - -use crate::borrow_check::region_infer::values::RegionElement; -use crate::borrow_check::MirBorrowckCtxt; - -#[derive(Clone)] -crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>); - -/// What operation a universe was created for. -#[derive(Clone)] -enum UniverseInfoInner<'tcx> { - /// Relating two types which have binders. - RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> }, - /// Created from performing a `TypeOp`. - TypeOp(Rc + 'tcx>), - /// Any other reason. - Other, -} - -impl UniverseInfo<'tcx> { - crate fn other() -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::Other) - } - - crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::RelateTys { expected, found }) - } - - crate fn report_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - placeholder: ty::PlaceholderRegion, - error_element: RegionElement, - span: Span, - ) { - match self.0 { - UniverseInfoInner::RelateTys { expected, found } => { - let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id()); - let err = mbcx.infcx.report_mismatched_types( - &ObligationCause::misc(span, body_id), - expected, - found, - TypeError::RegionsPlaceholderMismatch, - ); - err.buffer(&mut mbcx.errors_buffer); - } - UniverseInfoInner::TypeOp(ref type_op_info) => { - type_op_info.report_error(mbcx, placeholder, error_element, span); - } - UniverseInfoInner::Other => { - // FIXME: This error message isn't great, but it doesn't show - // up in the existing UI tests. Consider investigating this - // some more. - mbcx.infcx - .tcx - .sess - .struct_span_err(span, "higher-ranked subtype error") - .buffer(&mut mbcx.errors_buffer); - } - } - } -} - -crate trait ToUniverseInfo<'tcx> { - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>; -} - -impl<'tcx> ToUniverseInfo<'tcx> - for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>> -{ - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery { - canonical_query: self, - base_universe, - }))) - } -} - -impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx> - for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>> -{ - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery { - canonical_query: self, - base_universe, - }))) - } -} - -impl<'tcx> ToUniverseInfo<'tcx> - for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>> -{ - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery { - canonical_query: self, - base_universe, - }))) - } -} - -impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp> { - fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - // We can't rerun custom type ops. - UniverseInfo::other() - } -} - -#[allow(unused_lifetimes)] -trait TypeOpInfo<'tcx> { - /// Returns an error to be reported if rerunning the type op fails to - /// recover the error's cause. - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; - - fn base_universe(&self) -> ty::UniverseIndex; - - fn nice_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option>; - - fn report_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - placeholder: ty::PlaceholderRegion, - error_element: RegionElement, - span: Span, - ) { - let tcx = mbcx.infcx.tcx; - let base_universe = self.base_universe(); - - let adjusted_universe = if let Some(adjusted) = - placeholder.universe.as_u32().checked_sub(base_universe.as_u32()) - { - adjusted - } else { - self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer); - return; - }; - - let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder { - name: placeholder.name, - universe: adjusted_universe.into(), - })); - - let error_region = - if let RegionElement::PlaceholderRegion(error_placeholder) = error_element { - let adjusted_universe = - error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); - adjusted_universe.map(|adjusted| { - tcx.mk_region(ty::RePlaceholder(ty::Placeholder { - name: error_placeholder.name, - universe: adjusted.into(), - })) - }) - } else { - None - }; - - debug!(?placeholder_region); - - let nice_error = self.nice_error(tcx, span, placeholder_region, error_region); - - if let Some(nice_error) = nice_error { - nice_error.buffer(&mut mbcx.errors_buffer); - } else { - self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer); - } - } -} - -struct PredicateQuery<'tcx> { - canonical_query: - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>, - base_universe: ty::UniverseIndex, -} - -impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> { - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); - err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate)); - err - } - - fn base_universe(&self) -> ty::UniverseIndex { - self.base_universe - } - - fn nice_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span)); - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) - } -} - -struct NormalizeQuery<'tcx, T> { - canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>>, - base_universe: ty::UniverseIndex, -} - -impl TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> -where - T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx, -{ - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); - err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value)); - err - } - - fn base_universe(&self) -> ty::UniverseIndex { - self.base_universe - } - - fn nice_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - - let mut selcx = SelectionContext::new(infcx); - - // FIXME(lqd): Unify and de-duplicate the following with the actual - // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the - // `ObligationCause`. The normalization results are currently different between - // `AtExt::normalize` used in the query and `normalize` called below: the former fails - // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check - // after #85499 lands to see if its fixes have erased this difference. - let (param_env, value) = key.into_parts(); - let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( - &mut selcx, - param_env, - ObligationCause::dummy_with_span(span), - value.value, - ); - fulfill_cx.register_predicate_obligations(infcx, obligations); - - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) - } -} - -struct AscribeUserTypeQuery<'tcx> { - canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>, - base_universe: ty::UniverseIndex, -} - -impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, - // and is only the fallback when the nice error fails. Consider improving this some more. - tcx.sess.struct_span_err(span, "higher-ranked lifetime error") - } - - fn base_universe(&self) -> ty::UniverseIndex { - self.base_universe - } - - fn nice_error( - &self, - tcx: TyCtxt<'tcx>, - span: Span, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?; - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) - } -} - -fn try_extract_error_from_fulfill_cx<'tcx>( - mut fulfill_cx: Box + 'tcx>, - infcx: &InferCtxt<'_, 'tcx>, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, -) -> Option> { - let tcx = infcx.tcx; - - // We generally shouldn't have errors here because the query was - // already run, but there's no point using `delay_span_bug` - // when we're going to emit an error here anyway. - let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new); - - let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| { - debug!(?region_constraints); - region_constraints.constraints.iter().find_map(|(constraint, cause)| { - match *constraint { - Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => { - Some((sub, cause.clone())) - } - // FIXME: Should this check the universe of the var? - Constraint::VarSubReg(vid, sup) if sup == placeholder_region => { - Some((tcx.mk_region(ty::ReVar(vid)), cause.clone())) - } - _ => None, - } - }) - })?; - - debug!(?sub_region, ?cause); - let nice_error = match (error_region, sub_region) { - (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new( - infcx, - RegionResolutionError::SubSupConflict( - vid, - infcx.region_var_origin(vid), - cause.clone(), - error_region, - cause.clone(), - placeholder_region, - ), - ), - (Some(error_region), _) => NiceRegionError::new( - infcx, - RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region), - ), - // Note universe here is wrong... - (None, &ty::ReVar(vid)) => NiceRegionError::new( - infcx, - RegionResolutionError::UpperBoundUniverseConflict( - vid, - infcx.region_var_origin(vid), - infcx.universe_of_region(sub_region), - cause.clone(), - placeholder_region, - ), - ), - (None, _) => NiceRegionError::new( - infcx, - RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region), - ), - }; - nice_error.try_report_from_nll().or_else(|| { - if let SubregionOrigin::Subtype(trace) = cause { - Some( - infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch), - ) - } else { - None - } - }) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2292 +0,0 @@ -use either::Either; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; -use rustc_middle::mir::{ - self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, - FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, -}; -use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; -use rustc_span::source_map::DesugaringKind; -use rustc_span::symbol::sym; -use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; -use rustc_trait_selection::infer::InferCtxtExt; - -use crate::dataflow::drop_flag_effects; -use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex}; -use crate::util::borrowck_errors; - -use crate::borrow_check::{ - borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, - InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, -}; - -use super::{ - explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName, - RegionNameSource, UseSpans, -}; - -#[derive(Debug)] -struct MoveSite { - /// Index of the "move out" that we found. The `MoveData` can - /// then tell us where the move occurred. - moi: MoveOutIndex, - - /// `true` if we traversed a back edge while walking from the point - /// of error to the move site. - traversed_back_edge: bool, -} - -/// Which case a StorageDeadOrDrop is for. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum StorageDeadOrDrop<'tcx> { - LocalStorageDead, - BoxedStorageDead, - Destructor(Ty<'tcx>), -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( - &mut self, - location: Location, - desired_action: InitializationRequiringAction, - (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span), - mpi: MovePathIndex, - ) { - debug!( - "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \ - moved_place={:?} used_place={:?} span={:?} mpi={:?}", - location, desired_action, moved_place, used_place, span, mpi - ); - - let use_spans = - self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location)); - let span = use_spans.args_or_use(); - - let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi); - debug!( - "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}", - move_site_vec, use_spans - ); - let move_out_indices: Vec<_> = - move_site_vec.iter().map(|move_site| move_site.moi).collect(); - - if move_out_indices.is_empty() { - let root_place = PlaceRef { projection: &[], ..used_place }; - - if !self.uninitialized_error_reported.insert(root_place) { - debug!( - "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", - root_place - ); - return; - } - - let item_msg = - match self.describe_place_with_options(used_place, IncludingDowncast(true)) { - Some(name) => format!("`{}`", name), - None => "value".to_owned(), - }; - let mut err = self.cannot_act_on_uninitialized_variable( - span, - desired_action.as_noun(), - &self - .describe_place_with_options(moved_place, IncludingDowncast(true)) - .unwrap_or_else(|| "_".to_owned()), - ); - err.span_label(span, format!("use of possibly-uninitialized {}", item_msg)); - - use_spans.var_span_label_path_only( - &mut err, - format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), - ); - - err.buffer(&mut self.errors_buffer); - } else { - if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) { - if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) { - debug!( - "report_use_of_moved_or_uninitialized place: error suppressed \ - mois={:?}", - move_out_indices - ); - return; - } - } - - let is_partial_move = move_site_vec.iter().any(|move_site| { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - // `*(_1)` where `_1` is a `Box` is actually a move out. - let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref] - && self.body.local_decls[moved_place.local].ty.is_box(); - - !is_box_move - && used_place != moved_place.as_ref() - && used_place.is_prefix_of(moved_place.as_ref()) - }); - - let partial_str = if is_partial_move { "partial " } else { "" }; - let partially_str = if is_partial_move { "partially " } else { "" }; - - let mut err = self.cannot_act_on_moved_value( - span, - desired_action.as_noun(), - partially_str, - self.describe_place_with_options(moved_place, IncludingDowncast(true)), - ); - - let reinit_spans = maybe_reinitialized_locations - .iter() - .take(3) - .map(|loc| { - self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc) - .args_or_use() - }) - .collect::>(); - let reinits = maybe_reinitialized_locations.len(); - if reinits == 1 { - err.span_label(reinit_spans[0], "this reinitialization might get skipped"); - } else if reinits > 1 { - err.span_note( - MultiSpan::from_spans(reinit_spans), - &if reinits <= 3 { - format!("these {} reinitializations might get skipped", reinits) - } else { - format!( - "these 3 reinitializations and {} other{} might get skipped", - reinits - 3, - if reinits == 4 { "" } else { "s" } - ) - }, - ); - } - - self.add_moved_or_invoked_closure_note(location, used_place, &mut err); - - let mut is_loop_move = false; - let mut in_pattern = false; - - for move_site in &move_site_vec { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - - let move_spans = self.move_spans(moved_place.as_ref(), move_out.source); - let move_span = move_spans.args_or_use(); - - let move_msg = if move_spans.for_closure() { " into closure" } else { "" }; - - let loop_message = if location == move_out.source || move_site.traversed_back_edge { - ", in previous iteration of loop" - } else { - "" - }; - - if location == move_out.source { - is_loop_move = true; - } - - if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { - let place_name = self - .describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "value".to_owned()); - match kind { - FnSelfUseKind::FnOnceCall => { - err.span_label( - fn_call_span, - &format!( - "{} {}moved due to this call{}", - place_name, partially_str, loop_message - ), - ); - err.span_note( - var_span, - "this value implements `FnOnce`, which causes it to be moved when called", - ); - } - FnSelfUseKind::Operator { self_arg } => { - err.span_label( - fn_call_span, - &format!( - "{} {}moved due to usage in operator{}", - place_name, partially_str, loop_message - ), - ); - if self.fn_self_span_reported.insert(fn_span) { - err.span_note( - self_arg.span, - "calling this operator moves the left-hand side", - ); - } - } - FnSelfUseKind::Normal { - self_arg, - implicit_into_iter, - is_option_or_result, - } => { - if implicit_into_iter { - err.span_label( - fn_call_span, - &format!( - "{} {}moved due to this implicit call to `.into_iter()`{}", - place_name, partially_str, loop_message - ), - ); - } else { - err.span_label( - fn_call_span, - &format!( - "{} {}moved due to this method call{}", - place_name, partially_str, loop_message - ), - ); - } - if is_option_or_result && maybe_reinitialized_locations.is_empty() { - err.span_suggestion_verbose( - fn_call_span.shrink_to_lo(), - "consider calling `.as_ref()` to borrow the type's contents", - "as_ref().".to_string(), - Applicability::MachineApplicable, - ); - } - // Avoid pointing to the same function in multiple different - // error messages. - if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) - { - err.span_note( - self_arg.span, - &format!("this function takes ownership of the receiver `self`, which moves {}", place_name) - ); - } - } - // Deref::deref takes &self, which cannot cause a move - FnSelfUseKind::DerefCoercion { .. } => unreachable!(), - } - } else { - err.span_label( - move_span, - format!("value {}moved{} here{}", partially_str, move_msg, loop_message), - ); - // If the move error occurs due to a loop, don't show - // another message for the same span - if loop_message.is_empty() { - move_spans.var_span_label( - &mut err, - format!( - "variable {}moved due to use{}", - partially_str, - move_spans.describe() - ), - "moved", - ); - } - } - - if let (UseSpans::PatUse(span), []) = - (move_spans, &maybe_reinitialized_locations[..]) - { - if maybe_reinitialized_locations.is_empty() { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "borrow this field in the pattern to avoid moving {}", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "the value".to_string()) - ), - "ref ".to_string(), - Applicability::MachineApplicable, - ); - in_pattern = true; - } - } - - if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() { - let sess = self.infcx.tcx.sess; - let ty = used_place.ty(self.body, self.infcx.tcx).ty; - // If we have a `&mut` ref, we need to reborrow. - if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { - // If we are in a loop this will be suggested later. - if !is_loop_move { - err.span_suggestion_verbose( - move_span.shrink_to_lo(), - &format!( - "consider creating a fresh reborrow of {} here", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "the mutable reference".to_string()), - ), - "&mut *".to_string(), - Applicability::MachineApplicable, - ); - } - } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) { - err.span_suggestion( - move_span, - "consider borrowing to avoid moving into the for loop", - format!("&{}", snippet), - Applicability::MaybeIncorrect, - ); - } - } - } - - use_spans.var_span_label_path_only( - &mut err, - format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), - ); - - if !is_loop_move { - err.span_label( - span, - format!( - "value {} here after {}move", - desired_action.as_verb_in_past_tense(), - partial_str - ), - ); - } - - let ty = used_place.ty(self.body, self.infcx.tcx).ty; - let needs_note = match ty.kind() { - ty::Closure(id, _) => { - let tables = self.infcx.tcx.typeck(id.expect_local()); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local()); - - tables.closure_kind_origins().get(hir_id).is_none() - } - _ => true, - }; - - let mpi = self.move_data.moves[move_out_indices[0]].path; - let place = &self.move_data.move_paths[mpi].place; - let ty = place.ty(self.body, self.infcx.tcx).ty; - - // If we're in pattern, we do nothing in favor of the previous suggestion (#80913). - if is_loop_move & !in_pattern { - if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { - // We have a `&mut` ref, we need to reborrow on each iteration (#62112). - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "consider creating a fresh reborrow of {} here", - self.describe_place(moved_place) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "the mutable reference".to_string()), - ), - "&mut *".to_string(), - Applicability::MachineApplicable, - ); - } - } - - if needs_note { - let opt_name = - self.describe_place_with_options(place.as_ref(), IncludingDowncast(true)); - let note_msg = match opt_name { - Some(ref name) => format!("`{}`", name), - None => "value".to_owned(), - }; - if let ty::Param(param_ty) = ty.kind() { - let tcx = self.infcx.tcx; - let generics = tcx.generics_of(self.mir_def_id()); - let param = generics.type_param(¶m_ty, tcx); - if let Some(generics) = tcx - .hir() - .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id())) - { - suggest_constraining_type_param( - tcx, - generics, - &mut err, - ¶m.name.as_str(), - "Copy", - None, - ); - } - } - let span = if let Some(local) = place.as_local() { - let decl = &self.body.local_decls[local]; - Some(decl.source_info.span) - } else { - None - }; - self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str); - } - - if let UseSpans::FnSelfUse { - kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty }, - .. - } = use_spans - { - err.note(&format!( - "{} occurs due to deref coercion to `{}`", - desired_action.as_noun(), - deref_target_ty - )); - - err.span_note(deref_target, "deref defined here"); - } - - if let Some((_, mut old_err)) = - self.move_error_reported.insert(move_out_indices, (used_place, err)) - { - // Cancel the old error so it doesn't ICE. - old_err.cancel(); - } - } - } - - pub(in crate::borrow_check) fn report_move_out_while_borrowed( - &mut self, - location: Location, - (place, span): (Place<'tcx>, Span), - borrow: &BorrowData<'tcx>, - ) { - debug!( - "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}", - location, place, span, borrow - ); - let value_msg = self.describe_any_place(place.as_ref()); - let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref()); - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.args_or_use(); - - let move_spans = self.move_spans(place.as_ref(), location); - let span = move_spans.args_or_use(); - - let mut err = - self.cannot_move_when_borrowed(span, &self.describe_any_place(place.as_ref())); - err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg)); - err.span_label(span, format!("move out of {} occurs here", value_msg)); - - borrow_spans.var_span_label_path_only( - &mut err, - format!("borrow occurs due to use{}", borrow_spans.describe()), - ); - - move_spans.var_span_label( - &mut err, - format!("move occurs due to use{}", move_spans.describe()), - "moved", - ); - - self.explain_why_borrow_contains_point(location, borrow, None) - .add_explanation_to_diagnostic( - self.infcx.tcx, - &self.body, - &self.local_names, - &mut err, - "", - Some(borrow_span), - None, - ); - err.buffer(&mut self.errors_buffer); - } - - pub(in crate::borrow_check) fn report_use_while_mutably_borrowed( - &mut self, - location: Location, - (place, _span): (Place<'tcx>, Span), - borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx> { - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.args_or_use(); - - // Conflicting borrows are reported separately, so only check for move - // captures. - let use_spans = self.move_spans(place.as_ref(), location); - let span = use_spans.var_or_use(); - - // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use - // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure - let mut err = self.cannot_use_when_mutably_borrowed( - span, - &self.describe_any_place(place.as_ref()), - borrow_span, - &self.describe_any_place(borrow.borrowed_place.as_ref()), - ); - - borrow_spans.var_span_label( - &mut err, - { - let place = &borrow.borrowed_place; - let desc_place = self.describe_any_place(place.as_ref()); - format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe()) - }, - "mutable", - ); - - self.explain_why_borrow_contains_point(location, borrow, None) - .add_explanation_to_diagnostic( - self.infcx.tcx, - &self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - err - } - - pub(in crate::borrow_check) fn report_conflicting_borrow( - &mut self, - location: Location, - (place, span): (Place<'tcx>, Span), - gen_borrow_kind: BorrowKind, - issued_borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx> { - let issued_spans = self.retrieve_borrow_spans(issued_borrow); - let issued_span = issued_spans.args_or_use(); - - let borrow_spans = self.borrow_spans(span, location); - let span = borrow_spans.args_or_use(); - - let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() { - "generator" - } else { - "closure" - }; - - let (desc_place, msg_place, msg_borrow, union_type_name) = - self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place); - - let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None); - let second_borrow_desc = if explanation.is_explained() { "second " } else { "" }; - - // FIXME: supply non-"" `opt_via` when appropriate - let first_borrow_desc; - let mut err = match (gen_borrow_kind, issued_borrow.kind) { - (BorrowKind::Shared, BorrowKind::Mut { .. }) => { - first_borrow_desc = "mutable "; - self.cannot_reborrow_already_borrowed( - span, - &desc_place, - &msg_place, - "immutable", - issued_span, - "it", - "mutable", - &msg_borrow, - None, - ) - } - (BorrowKind::Mut { .. }, BorrowKind::Shared) => { - first_borrow_desc = "immutable "; - self.cannot_reborrow_already_borrowed( - span, - &desc_place, - &msg_place, - "mutable", - issued_span, - "it", - "immutable", - &msg_borrow, - None, - ) - } - - (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { - first_borrow_desc = "first "; - let mut err = self.cannot_mutably_borrow_multiply( - span, - &desc_place, - &msg_place, - issued_span, - &msg_borrow, - None, - ); - self.suggest_split_at_mut_if_applicable( - &mut err, - place, - issued_borrow.borrowed_place, - ); - err - } - - (BorrowKind::Unique, BorrowKind::Unique) => { - first_borrow_desc = "first "; - self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) - } - - (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => { - if let Some(immutable_section_description) = - self.classify_immutable_section(issued_borrow.assigned_place) - { - let mut err = self.cannot_mutate_in_immutable_section( - span, - issued_span, - &desc_place, - immutable_section_description, - "mutably borrow", - ); - borrow_spans.var_span_label( - &mut err, - format!( - "borrow occurs due to use of {}{}", - desc_place, - borrow_spans.describe(), - ), - "immutable", - ); - - return err; - } else { - first_borrow_desc = "immutable "; - self.cannot_reborrow_already_borrowed( - span, - &desc_place, - &msg_place, - "mutable", - issued_span, - "it", - "immutable", - &msg_borrow, - None, - ) - } - } - - (BorrowKind::Unique, _) => { - first_borrow_desc = "first "; - self.cannot_uniquely_borrow_by_one_closure( - span, - container_name, - &desc_place, - "", - issued_span, - "it", - "", - None, - ) - } - - (BorrowKind::Shared, BorrowKind::Unique) => { - first_borrow_desc = "first "; - self.cannot_reborrow_already_uniquely_borrowed( - span, - container_name, - &desc_place, - "", - "immutable", - issued_span, - "", - None, - second_borrow_desc, - ) - } - - (BorrowKind::Mut { .. }, BorrowKind::Unique) => { - first_borrow_desc = "first "; - self.cannot_reborrow_already_uniquely_borrowed( - span, - container_name, - &desc_place, - "", - "mutable", - issued_span, - "", - None, - second_borrow_desc, - ) - } - - (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow) - | ( - BorrowKind::Shallow, - BorrowKind::Mut { .. } - | BorrowKind::Unique - | BorrowKind::Shared - | BorrowKind::Shallow, - ) => unreachable!(), - }; - - if issued_spans == borrow_spans { - borrow_spans.var_span_label( - &mut err, - format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),), - gen_borrow_kind.describe_mutability(), - ); - } else { - let borrow_place = &issued_borrow.borrowed_place; - let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); - issued_spans.var_span_label( - &mut err, - format!( - "first borrow occurs due to use of {}{}", - borrow_place_desc, - issued_spans.describe(), - ), - issued_borrow.kind.describe_mutability(), - ); - - borrow_spans.var_span_label( - &mut err, - format!( - "second borrow occurs due to use of {}{}", - desc_place, - borrow_spans.describe(), - ), - gen_borrow_kind.describe_mutability(), - ); - } - - if union_type_name != "" { - err.note(&format!( - "{} is a field of the union `{}`, so it overlaps the field {}", - msg_place, union_type_name, msg_borrow, - )); - } - - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - &self.body, - &self.local_names, - &mut err, - first_borrow_desc, - None, - Some((issued_span, span)), - ); - - err - } - - fn suggest_split_at_mut_if_applicable( - &self, - err: &mut DiagnosticBuilder<'_>, - place: Place<'tcx>, - borrowed_place: Place<'tcx>, - ) { - if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) = - (&place.projection[..], &borrowed_place.projection[..]) - { - err.help( - "consider using `.split_at_mut(position)` or similar method to obtain \ - two mutable non-overlapping sub-slices", - ); - } - } - - /// Returns the description of the root place for a conflicting borrow and the full - /// descriptions of the places that caused the conflict. - /// - /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is - /// attempted while a shared borrow is live, then this function will return: - /// - /// ("x", "", "") - /// - /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while - /// a shared borrow of another field `x.y`, then this function will return: - /// - /// ("x", "x.z", "x.y") - /// - /// In the more complex union case, where the union is a field of a struct, then if a mutable - /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of - /// another field `x.u.y`, then this function will return: - /// - /// ("x.u", "x.u.z", "x.u.y") - /// - /// This is used when creating error messages like below: - /// - /// ```text - /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as - /// mutable (via `a.u.s.b`) [E0502] - /// ``` - pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow( - &self, - first_borrowed_place: Place<'tcx>, - second_borrowed_place: Place<'tcx>, - ) -> (String, String, String, String) { - // Define a small closure that we can use to check if the type of a place - // is a union. - let union_ty = |place_base| { - // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`; - // using a type annotation in the closure argument instead leads to a lifetime error. - let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty; - ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) - }; - - // Start with an empty tuple, so we can use the functions on `Option` to reduce some - // code duplication (particularly around returning an empty description in the failure - // case). - Some(()) - .filter(|_| { - // If we have a conflicting borrow of the same place, then we don't want to add - // an extraneous "via x.y" to our diagnostics, so filter out this case. - first_borrowed_place != second_borrowed_place - }) - .and_then(|_| { - // We're going to want to traverse the first borrowed place to see if we can find - // field access to a union. If we find that, then we will keep the place of the - // union being accessed and the field that was being accessed so we can check the - // second borrowed place for the same union and an access to a different field. - for (place_base, elem) in first_borrowed_place.iter_projections().rev() { - match elem { - ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => { - return Some((place_base, field)); - } - _ => {} - } - } - None - }) - .and_then(|(target_base, target_field)| { - // With the place of a union and a field access into it, we traverse the second - // borrowed place and look for an access to a different field of the same union. - for (place_base, elem) in second_borrowed_place.iter_projections().rev() { - if let ProjectionElem::Field(field, _) = elem { - if let Some(union_ty) = union_ty(place_base) { - if field != target_field && place_base == target_base { - return Some(( - self.describe_any_place(place_base), - self.describe_any_place(first_borrowed_place.as_ref()), - self.describe_any_place(second_borrowed_place.as_ref()), - union_ty.to_string(), - )); - } - } - } - } - None - }) - .unwrap_or_else(|| { - // If we didn't find a field access into a union, or both places match, then - // only return the description of the first place. - ( - self.describe_any_place(first_borrowed_place.as_ref()), - "".to_string(), - "".to_string(), - "".to_string(), - ) - }) - } - - /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`. - /// - /// This means that some data referenced by `borrow` needs to live - /// past the point where the StorageDeadOrDrop of `place` occurs. - /// This is usually interpreted as meaning that `place` has too - /// short a lifetime. (But sometimes it is more useful to report - /// it as a more direct conflict between the execution of a - /// `Drop::drop` with an aliasing borrow.) - pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough( - &mut self, - location: Location, - borrow: &BorrowData<'tcx>, - place_span: (Place<'tcx>, Span), - kind: Option, - ) { - debug!( - "report_borrowed_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}\ - )", - location, borrow, place_span, kind - ); - - let drop_span = place_span.1; - let root_place = - self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.var_or_use_path_span(); - - assert!(root_place.projection.is_empty()); - let proper_span = self.body.local_decls[root_place.local].source_info.span; - - let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection); - - if self.access_place_error_reported.contains(&( - Place { local: root_place.local, projection: root_place_projection }, - borrow_span, - )) { - debug!( - "suppressing access_place error when borrow doesn't live long enough for {:?}", - borrow_span - ); - return; - } - - self.access_place_error_reported.insert(( - Place { local: root_place.local, projection: root_place_projection }, - borrow_span, - )); - - let borrowed_local = borrow.borrowed_place.local; - if self.body.local_decls[borrowed_local].is_ref_to_thread_local() { - let err = - self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span); - err.buffer(&mut self.errors_buffer); - return; - } - - if let StorageDeadOrDrop::Destructor(dropped_ty) = - self.classify_drop_access_kind(borrow.borrowed_place.as_ref()) - { - // If a borrow of path `B` conflicts with drop of `D` (and - // we're not in the uninteresting case where `B` is a - // prefix of `D`), then report this as a more interesting - // destructor conflict. - if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) { - self.report_borrow_conflicts_with_destructor( - location, borrow, place_span, kind, dropped_ty, - ); - return; - } - } - - let place_desc = self.describe_place(borrow.borrowed_place.as_ref()); - - let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0)); - let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place); - - debug!( - "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})", - place_desc, explanation - ); - let err = match (place_desc, explanation) { - // If the outlives constraint comes from inside the closure, - // for example: - // - // let x = 0; - // let y = &x; - // Box::new(|| y) as Box &'static i32> - // - // then just use the normal error. The closure isn't escaping - // and `move` will not help here. - ( - Some(ref name), - BorrowExplanation::MustBeValidFor { - category: - category - @ - (ConstraintCategory::Return(_) - | ConstraintCategory::CallArgument - | ConstraintCategory::OpaqueType), - from_closure: false, - ref region_name, - span, - .. - }, - ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self - .report_escaping_closure_capture( - borrow_spans, - borrow_span, - region_name, - category, - span, - &format!("`{}`", name), - ), - ( - ref name, - BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Assignment, - from_closure: false, - region_name: - RegionName { - source: - RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name), - .. - }, - span, - .. - }, - ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span), - (Some(name), explanation) => self.report_local_value_does_not_live_long_enough( - location, - &name, - &borrow, - drop_span, - borrow_spans, - explanation, - ), - (None, explanation) => self.report_temporary_value_does_not_live_long_enough( - location, - &borrow, - drop_span, - borrow_spans, - proper_span, - explanation, - ), - }; - - err.buffer(&mut self.errors_buffer); - } - - fn report_local_value_does_not_live_long_enough( - &mut self, - location: Location, - name: &str, - borrow: &BorrowData<'tcx>, - drop_span: Span, - borrow_spans: UseSpans<'tcx>, - explanation: BorrowExplanation, - ) -> DiagnosticBuilder<'cx> { - debug!( - "report_local_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}, {:?}\ - )", - location, name, borrow, drop_span, borrow_spans - ); - - let borrow_span = borrow_spans.var_or_use_path_span(); - if let BorrowExplanation::MustBeValidFor { - category, - span, - ref opt_place_desc, - from_closure: false, - .. - } = explanation - { - if let Some(diag) = self.try_report_cannot_return_reference_to_local( - borrow, - borrow_span, - span, - category, - opt_place_desc.as_ref(), - ) { - return diag; - } - } - - let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name)); - - if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { - let region_name = annotation.emit(self, &mut err); - - err.span_label( - borrow_span, - format!("`{}` would have to be valid for `{}`...", name, region_name), - ); - - let fn_hir_id = self.mir_hir_id(); - err.span_label( - drop_span, - format!( - "...but `{}` will be dropped here, when the {} returns", - name, - self.infcx - .tcx - .hir() - .opt_name(fn_hir_id) - .map(|name| format!("function `{}`", name)) - .unwrap_or_else(|| { - match &self - .infcx - .tcx - .typeck(self.mir_def_id()) - .node_type(fn_hir_id) - .kind() - { - ty::Closure(..) => "enclosing closure", - ty::Generator(..) => "enclosing generator", - kind => bug!("expected closure or generator, found {:?}", kind), - } - .to_string() - }) - ), - ); - - err.note( - "functions cannot return a borrow to data owned within the function's scope, \ - functions can only return borrows to data passed as arguments", - ); - err.note( - "to learn more, visit ", - ); - - if let BorrowExplanation::MustBeValidFor { .. } = explanation { - } else { - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - &self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - } - } else { - err.span_label(borrow_span, "borrowed value does not live long enough"); - err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name)); - - let within = if borrow_spans.for_generator() { " by generator" } else { "" }; - - borrow_spans.args_span_label(&mut err, format!("value captured here{}", within)); - - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - &self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - } - - err - } - - fn report_borrow_conflicts_with_destructor( - &mut self, - location: Location, - borrow: &BorrowData<'tcx>, - (place, drop_span): (Place<'tcx>, Span), - kind: Option, - dropped_ty: Ty<'tcx>, - ) { - debug!( - "report_borrow_conflicts_with_destructor(\ - {:?}, {:?}, ({:?}, {:?}), {:?}\ - )", - location, borrow, place, drop_span, kind, - ); - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.var_or_use(); - - let mut err = self.cannot_borrow_across_destructor(borrow_span); - - let what_was_dropped = match self.describe_place(place.as_ref()) { - Some(name) => format!("`{}`", name), - None => String::from("temporary value"), - }; - - let label = match self.describe_place(borrow.borrowed_place.as_ref()) { - Some(borrowed) => format!( - "here, drop of {D} needs exclusive access to `{B}`, \ - because the type `{T}` implements the `Drop` trait", - D = what_was_dropped, - T = dropped_ty, - B = borrowed - ), - None => format!( - "here is drop of {D}; whose type `{T}` implements the `Drop` trait", - D = what_was_dropped, - T = dropped_ty - ), - }; - err.span_label(drop_span, label); - - // Only give this note and suggestion if they could be relevant. - let explanation = - self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place))); - match explanation { - BorrowExplanation::UsedLater { .. } - | BorrowExplanation::UsedLaterWhenDropped { .. } => { - err.note("consider using a `let` binding to create a longer lived value"); - } - _ => {} - } - - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - &self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - - err.buffer(&mut self.errors_buffer); - } - - fn report_thread_local_value_does_not_live_long_enough( - &mut self, - drop_span: Span, - borrow_span: Span, - ) -> DiagnosticBuilder<'cx> { - debug!( - "report_thread_local_value_does_not_live_long_enough(\ - {:?}, {:?}\ - )", - drop_span, borrow_span - ); - - let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span); - - err.span_label( - borrow_span, - "thread-local variables cannot be borrowed beyond the end of the function", - ); - err.span_label(drop_span, "end of enclosing function is here"); - - err - } - - fn report_temporary_value_does_not_live_long_enough( - &mut self, - location: Location, - borrow: &BorrowData<'tcx>, - drop_span: Span, - borrow_spans: UseSpans<'tcx>, - proper_span: Span, - explanation: BorrowExplanation, - ) -> DiagnosticBuilder<'cx> { - debug!( - "report_temporary_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}\ - )", - location, borrow, drop_span, proper_span - ); - - if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = - explanation - { - if let Some(diag) = self.try_report_cannot_return_reference_to_local( - borrow, - proper_span, - span, - category, - None, - ) { - return diag; - } - } - - let mut err = self.temporary_value_borrowed_for_too_long(proper_span); - err.span_label(proper_span, "creates a temporary which is freed while still in use"); - err.span_label(drop_span, "temporary value is freed at the end of this statement"); - - match explanation { - BorrowExplanation::UsedLater(..) - | BorrowExplanation::UsedLaterInLoop(..) - | BorrowExplanation::UsedLaterWhenDropped { .. } => { - // Only give this note and suggestion if it could be relevant. - err.note("consider using a `let` binding to create a longer lived value"); - } - _ => {} - } - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - &self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - - let within = if borrow_spans.for_generator() { " by generator" } else { "" }; - - borrow_spans.args_span_label(&mut err, format!("value captured here{}", within)); - - err - } - - fn try_report_cannot_return_reference_to_local( - &self, - borrow: &BorrowData<'tcx>, - borrow_span: Span, - return_span: Span, - category: ConstraintCategory, - opt_place_desc: Option<&String>, - ) -> Option> { - let return_kind = match category { - ConstraintCategory::Return(_) => "return", - ConstraintCategory::Yield => "yield", - _ => return None, - }; - - // FIXME use a better heuristic than Spans - let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span { - "reference to" - } else { - "value referencing" - }; - - let (place_desc, note) = if let Some(place_desc) = opt_place_desc { - let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { - match self.body.local_kind(local) { - LocalKind::ReturnPointer | LocalKind::Temp => { - bug!("temporary or return pointer with a name") - } - LocalKind::Var => "local variable ", - LocalKind::Arg - if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL => - { - "variable captured by `move` " - } - LocalKind::Arg => "function parameter ", - } - } else { - "local data " - }; - ( - format!("{}`{}`", local_kind, place_desc), - format!("`{}` is borrowed here", place_desc), - ) - } else { - let root_place = - self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); - let local = root_place.local; - match self.body.local_kind(local) { - LocalKind::ReturnPointer | LocalKind::Temp => { - ("temporary value".to_string(), "temporary value created here".to_string()) - } - LocalKind::Arg => ( - "function parameter".to_string(), - "function parameter borrowed here".to_string(), - ), - LocalKind::Var => { - ("local binding".to_string(), "local binding introduced here".to_string()) - } - } - }; - - let mut err = self.cannot_return_reference_to_local( - return_span, - return_kind, - reference_desc, - &place_desc, - ); - - if return_span != borrow_span { - err.span_label(borrow_span, note); - - let tcx = self.infcx.tcx; - let ty_params = ty::List::empty(); - - let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; - let return_ty = tcx.erase_regions(return_ty); - - // to avoid panics - if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { - if self - .infcx - .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env) - .must_apply_modulo_regions() - { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { - err.span_suggestion_hidden( - return_span, - "use `.collect()` to allocate the iterator", - format!("{}{}", snippet, ".collect::>()"), - Applicability::MaybeIncorrect, - ); - } - } - } - } - - Some(err) - } - - fn report_escaping_closure_capture( - &mut self, - use_span: UseSpans<'tcx>, - var_span: Span, - fr_name: &RegionName, - category: ConstraintCategory, - constraint_span: Span, - captured_var: &str, - ) -> DiagnosticBuilder<'cx> { - let tcx = self.infcx.tcx; - let args_span = use_span.args_or_use(); - - let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) { - Ok(string) => { - if string.starts_with("async ") { - let pos = args_span.lo() + BytePos(6); - (args_span.with_lo(pos).with_hi(pos), "move ".to_string()) - } else if string.starts_with("async|") { - let pos = args_span.lo() + BytePos(5); - (args_span.with_lo(pos).with_hi(pos), " move".to_string()) - } else { - (args_span.shrink_to_lo(), "move ".to_string()) - } - } - Err(_) => (args_span, "move || ".to_string()), - }; - let kind = match use_span.generator_kind() { - Some(generator_kind) => match generator_kind { - GeneratorKind::Async(async_kind) => match async_kind { - AsyncGeneratorKind::Block => "async block", - AsyncGeneratorKind::Closure => "async closure", - _ => bug!("async block/closure expected, but async function found."), - }, - GeneratorKind::Gen => "generator", - }, - None => "closure", - }; - - let mut err = - self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span); - err.span_suggestion_verbose( - sugg_span, - &format!( - "to force the {} to take ownership of {} (and any \ - other referenced variables), use the `move` keyword", - kind, captured_var - ), - suggestion, - Applicability::MachineApplicable, - ); - - match category { - ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => { - let msg = format!("{} is returned here", kind); - err.span_note(constraint_span, &msg); - } - ConstraintCategory::CallArgument => { - fr_name.highlight_region_name(&mut err); - if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) { - err.note( - "async blocks are not executed immediately and must either take a \ - reference or ownership of outside variables they use", - ); - } else { - let msg = format!("function requires argument type to outlive `{}`", fr_name); - err.span_note(constraint_span, &msg); - } - } - _ => bug!( - "report_escaping_closure_capture called with unexpected constraint \ - category: `{:?}`", - category - ), - } - - err - } - - fn report_escaping_data( - &mut self, - borrow_span: Span, - name: &Option, - upvar_span: Span, - upvar_name: &str, - escape_span: Span, - ) -> DiagnosticBuilder<'cx> { - let tcx = self.infcx.tcx; - - let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id()); - - let mut err = - borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from); - - err.span_label( - upvar_span, - format!("`{}` declared here, outside of the {} body", upvar_name, escapes_from), - ); - - err.span_label(borrow_span, format!("borrow is only valid in the {} body", escapes_from)); - - if let Some(name) = name { - err.span_label( - escape_span, - format!("reference to `{}` escapes the {} body here", name, escapes_from), - ); - } else { - err.span_label( - escape_span, - format!("reference escapes the {} body here", escapes_from), - ); - } - - err - } - - fn get_moved_indexes( - &mut self, - location: Location, - mpi: MovePathIndex, - ) -> (Vec, Vec) { - fn predecessor_locations( - body: &'a mir::Body<'tcx>, - location: Location, - ) -> impl Iterator + 'a { - if location.statement_index == 0 { - let predecessors = body.predecessors()[location.block].to_vec(); - Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) - } else { - Either::Right(std::iter::once(Location { - statement_index: location.statement_index - 1, - ..location - })) - } - } - - let mut stack = Vec::new(); - stack.extend(predecessor_locations(self.body, location).map(|predecessor| { - let is_back_edge = location.dominates(predecessor, &self.dominators); - (predecessor, is_back_edge) - })); - - let mut visited = FxHashSet::default(); - let mut move_locations = FxHashSet::default(); - let mut reinits = vec![]; - let mut result = vec![]; - - 'dfs: while let Some((location, is_back_edge)) = stack.pop() { - debug!( - "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})", - location, is_back_edge - ); - - if !visited.insert(location) { - continue; - } - - // check for moves - let stmt_kind = - self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind); - if let Some(StatementKind::StorageDead(..)) = stmt_kind { - // this analysis only tries to find moves explicitly - // written by the user, so we ignore the move-outs - // created by `StorageDead` and at the beginning - // of a function. - } else { - // If we are found a use of a.b.c which was in error, then we want to look for - // moves not only of a.b.c but also a.b and a. - // - // Note that the moves data already includes "parent" paths, so we don't have to - // worry about the other case: that is, if there is a move of a.b.c, it is already - // marked as a move of a.b and a as well, so we will generate the correct errors - // there. - let mut mpis = vec![mpi]; - let move_paths = &self.move_data.move_paths; - mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi)); - - for moi in &self.move_data.loc_map[location] { - debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); - let path = self.move_data.moves[*moi].path; - if mpis.contains(&path) { - debug!( - "report_use_of_moved_or_uninitialized: found {:?}", - move_paths[path].place - ); - result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge }); - move_locations.insert(location); - - // Strictly speaking, we could continue our DFS here. There may be - // other moves that can reach the point of error. But it is kind of - // confusing to highlight them. - // - // Example: - // - // ``` - // let a = vec![]; - // let b = a; - // let c = a; - // drop(a); // <-- current point of error - // ``` - // - // Because we stop the DFS here, we only highlight `let c = a`, - // and not `let b = a`. We will of course also report an error at - // `let c = a` which highlights `let b = a` as the move. - continue 'dfs; - } - } - } - - // check for inits - let mut any_match = false; - drop_flag_effects::for_location_inits( - self.infcx.tcx, - &self.body, - self.move_data, - location, - |m| { - if m == mpi { - any_match = true; - } - }, - ); - if any_match { - reinits.push(location); - continue 'dfs; - } - - stack.extend(predecessor_locations(self.body, location).map(|predecessor| { - let back_edge = location.dominates(predecessor, &self.dominators); - (predecessor, is_back_edge || back_edge) - })); - } - - // Check if we can reach these reinits from a move location. - let reinits_reachable = reinits - .into_iter() - .filter(|reinit| { - let mut visited = FxHashSet::default(); - let mut stack = vec![*reinit]; - while let Some(location) = stack.pop() { - if !visited.insert(location) { - continue; - } - if move_locations.contains(&location) { - return true; - } - stack.extend(predecessor_locations(self.body, location)); - } - false - }) - .collect::>(); - (result, reinits_reachable) - } - - pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed( - &mut self, - location: Location, - (place, span): (Place<'tcx>, Span), - loan: &BorrowData<'tcx>, - ) { - let loan_spans = self.retrieve_borrow_spans(loan); - let loan_span = loan_spans.args_or_use(); - - let descr_place = self.describe_any_place(place.as_ref()); - if loan.kind == BorrowKind::Shallow { - if let Some(section) = self.classify_immutable_section(loan.assigned_place) { - let mut err = self.cannot_mutate_in_immutable_section( - span, - loan_span, - &descr_place, - section, - "assign", - ); - loan_spans.var_span_label( - &mut err, - format!("borrow occurs due to use{}", loan_spans.describe()), - loan.kind.describe_mutability(), - ); - - err.buffer(&mut self.errors_buffer); - - return; - } - } - - let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); - - loan_spans.var_span_label( - &mut err, - format!("borrow occurs due to use{}", loan_spans.describe()), - loan.kind.describe_mutability(), - ); - - self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic( - self.infcx.tcx, - &self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - - self.explain_deref_coercion(loan, &mut err); - - err.buffer(&mut self.errors_buffer); - } - - fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) { - let tcx = self.infcx.tcx; - if let ( - Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }), - Some((method_did, method_substs)), - ) = ( - &self.body[loan.reserve_location.block].terminator, - crate::util::find_self_call( - tcx, - self.body, - loan.assigned_place.local, - loan.reserve_location.block, - ), - ) { - if tcx.is_diagnostic_item(sym::deref_method, method_did) { - let deref_target = - tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, self.param_env, deref_target, method_substs) - .transpose() - }); - if let Some(Ok(instance)) = deref_target { - let deref_target_ty = instance.ty(tcx, self.param_env); - err.note(&format!( - "borrow occurs due to deref coercion to `{}`", - deref_target_ty - )); - err.span_note(tcx.def_span(instance.def_id()), "deref defined here"); - } - } - } - } - - /// Reports an illegal reassignment; for example, an assignment to - /// (part of) a non-`mut` local that occurs potentially after that - /// local has already been initialized. `place` is the path being - /// assigned; `err_place` is a place providing a reason why - /// `place` is not mutable (e.g., the non-`mut` local `x` in an - /// assignment to `x.f`). - pub(in crate::borrow_check) fn report_illegal_reassignment( - &mut self, - _location: Location, - (place, span): (Place<'tcx>, Span), - assigned_span: Span, - err_place: Place<'tcx>, - ) { - let (from_arg, local_decl, local_name) = match err_place.as_local() { - Some(local) => ( - self.body.local_kind(local) == LocalKind::Arg, - Some(&self.body.local_decls[local]), - self.local_names[local], - ), - None => (false, None, None), - }; - - // If root local is initialized immediately (everything apart from let - // PATTERN;) then make the error refer to that local, rather than the - // place being assigned later. - let (place_description, assigned_span) = match local_decl { - Some(LocalDecl { - local_info: - Some(box LocalInfo::User( - ClearCrossCrate::Clear - | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - opt_match_place: None, - .. - })), - )) - | Some(box LocalInfo::StaticRef { .. }) - | None, - .. - }) - | None => (self.describe_any_place(place.as_ref()), assigned_span), - Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span), - }; - - let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg); - let msg = if from_arg { - "cannot assign to immutable argument" - } else { - "cannot assign twice to immutable variable" - }; - if span != assigned_span { - if !from_arg { - err.span_label(assigned_span, format!("first assignment to {}", place_description)); - } - } - if let Some(decl) = local_decl { - if let Some(name) = local_name { - if decl.can_be_made_mutable() { - err.span_suggestion( - decl.source_info.span, - "consider making this binding mutable", - format!("mut {}", name), - Applicability::MachineApplicable, - ); - } - } - } - err.span_label(span, msg); - err.buffer(&mut self.errors_buffer); - } - - fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> { - let tcx = self.infcx.tcx; - match place.last_projection() { - None => StorageDeadOrDrop::LocalStorageDead, - Some((place_base, elem)) => { - // FIXME(spastorino) make this iterate - let base_access = self.classify_drop_access_kind(place_base); - match elem { - ProjectionElem::Deref => match base_access { - StorageDeadOrDrop::LocalStorageDead - | StorageDeadOrDrop::BoxedStorageDead => { - assert!( - place_base.ty(self.body, tcx).ty.is_box(), - "Drop of value behind a reference or raw pointer" - ); - StorageDeadOrDrop::BoxedStorageDead - } - StorageDeadOrDrop::Destructor(_) => base_access, - }, - ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = place_base.ty(self.body, tcx).ty; - match base_ty.kind() { - ty::Adt(def, _) if def.has_dtor(tcx) => { - // Report the outermost adt with a destructor - match base_access { - StorageDeadOrDrop::Destructor(_) => base_access, - StorageDeadOrDrop::LocalStorageDead - | StorageDeadOrDrop::BoxedStorageDead => { - StorageDeadOrDrop::Destructor(base_ty) - } - } - } - _ => base_access, - } - } - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Index(_) => base_access, - } - } - } - } - - /// Describe the reason for the fake borrow that was assigned to `place`. - fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> { - use rustc_middle::mir::visit::Visitor; - struct FakeReadCauseFinder<'tcx> { - place: Place<'tcx>, - cause: Option, - } - impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { - match statement { - Statement { kind: StatementKind::FakeRead(box (cause, place)), .. } - if *place == self.place => - { - self.cause = Some(*cause); - } - _ => (), - } - } - } - let mut visitor = FakeReadCauseFinder { place, cause: None }; - visitor.visit_body(&self.body); - match visitor.cause { - Some(FakeReadCause::ForMatchGuard) => Some("match guard"), - Some(FakeReadCause::ForIndex) => Some("indexing expression"), - _ => None, - } - } - - /// Annotate argument and return type of function and closure with (synthesized) lifetime for - /// borrow of local value that does not live long enough. - fn annotate_argument_and_return_for_borrow( - &self, - borrow: &BorrowData<'tcx>, - ) -> Option> { - // Define a fallback for when we can't match a closure. - let fallback = || { - let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id()); - if is_closure { - None - } else { - let ty = self.infcx.tcx.type_of(self.mir_def_id()); - match ty.kind() { - ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( - self.mir_def_id().to_def_id(), - self.infcx.tcx.fn_sig(self.mir_def_id()), - ), - _ => None, - } - } - }; - - // In order to determine whether we need to annotate, we need to check whether the reserve - // place was an assignment into a temporary. - // - // If it was, we check whether or not that temporary is eventually assigned into the return - // place. If it was, we can add annotations about the function's return type and arguments - // and it'll make sense. - let location = borrow.reserve_location; - debug!("annotate_argument_and_return_for_borrow: location={:?}", location); - if let Some(&Statement { kind: StatementKind::Assign(box (ref reservation, _)), .. }) = - &self.body[location.block].statements.get(location.statement_index) - { - debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation); - // Check that the initial assignment of the reserve location is into a temporary. - let mut target = match reservation.as_local() { - Some(local) if self.body.local_kind(local) == LocalKind::Temp => local, - _ => return None, - }; - - // Next, look through the rest of the block, checking if we are assigning the - // `target` (that is, the place that contains our borrow) to anything. - let mut annotated_closure = None; - for stmt in &self.body[location.block].statements[location.statement_index + 1..] { - debug!( - "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", - target, stmt - ); - if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind { - if let Some(assigned_to) = place.as_local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} \ - rvalue={:?}", - assigned_to, rvalue - ); - // Check if our `target` was captured by a closure. - if let Rvalue::Aggregate( - box AggregateKind::Closure(def_id, substs), - operands, - ) = rvalue - { - for operand in operands { - let assigned_from = match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from - ); - - // Find the local from the operand. - let assigned_from_local = match assigned_from.local_or_deref_local() - { - Some(local) => local, - None => continue, - }; - - if assigned_from_local != target { - continue; - } - - // If a closure captured our `target` and then assigned - // into a place then we should annotate the closure in - // case it ends up being assigned into the return place. - annotated_closure = - self.annotate_fn_sig(*def_id, substs.as_closure().sig()); - debug!( - "annotate_argument_and_return_for_borrow: \ - annotated_closure={:?} assigned_from_local={:?} \ - assigned_to={:?}", - annotated_closure, assigned_from_local, assigned_to - ); - - if assigned_to == mir::RETURN_PLACE { - // If it was assigned directly into the return place, then - // return now. - return annotated_closure; - } else { - // Otherwise, update the target. - target = assigned_to; - } - } - - // If none of our closure's operands matched, then skip to the next - // statement. - continue; - } - - // Otherwise, look at other types of assignment. - let assigned_from = match rvalue { - Rvalue::Ref(_, _, assigned_from) => assigned_from, - Rvalue::Use(operand) => match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }, - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from={:?}", - assigned_from, - ); - - // Find the local from the rvalue. - let assigned_from_local = match assigned_from.local_or_deref_local() { - Some(local) => local, - None => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?}", - assigned_from_local, - ); - - // Check if our local matches the target - if so, we've assigned our - // borrow to a new place. - if assigned_from_local != target { - continue; - } - - // If we assigned our `target` into a new place, then we should - // check if it was the return place. - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?} assigned_to={:?}", - assigned_from_local, assigned_to - ); - if assigned_to == mir::RETURN_PLACE { - // If it was then return the annotated closure if there was one, - // else, annotate this function. - return annotated_closure.or_else(fallback); - } - - // If we didn't assign into the return place, then we just update - // the target. - target = assigned_to; - } - } - } - - // Check the terminator if we didn't find anything in the statements. - let terminator = &self.body[location.block].terminator(); - debug!( - "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}", - target, terminator - ); - if let TerminatorKind::Call { destination: Some((place, _)), args, .. } = - &terminator.kind - { - if let Some(assigned_to) = place.as_local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", - assigned_to, args - ); - for operand in args { - let assigned_from = match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from, - ); - - if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", - assigned_from_local, - ); - - if assigned_to == mir::RETURN_PLACE && assigned_from_local == target { - return annotated_closure.or_else(fallback); - } - } - } - } - } - } - - // If we haven't found an assignment into the return place, then we need not add - // any annotations. - debug!("annotate_argument_and_return_for_borrow: none found"); - None - } - - /// Annotate the first argument and return type of a function signature if they are - /// references. - fn annotate_fn_sig( - &self, - did: DefId, - sig: ty::PolyFnSig<'tcx>, - ) -> Option> { - debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); - let is_closure = self.infcx.tcx.is_closure(did); - let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did.as_local()?); - let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?; - - // We need to work out which arguments to highlight. We do this by looking - // at the return type, where there are three cases: - // - // 1. If there are named arguments, then we should highlight the return type and - // highlight any of the arguments that are also references with that lifetime. - // If there are no arguments that have the same lifetime as the return type, - // then don't highlight anything. - // 2. The return type is a reference with an anonymous lifetime. If this is - // the case, then we can take advantage of (and teach) the lifetime elision - // rules. - // - // We know that an error is being reported. So the arguments and return type - // must satisfy the elision rules. Therefore, if there is a single argument - // then that means the return type and first (and only) argument have the same - // lifetime and the borrow isn't meeting that, we can highlight the argument - // and return type. - // - // If there are multiple arguments then the first argument must be self (else - // it would not satisfy the elision rules), so we can highlight self and the - // return type. - // 3. The return type is not a reference. In this case, we don't highlight - // anything. - let return_ty = sig.output(); - match return_ty.skip_binder().kind() { - ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { - // This is case 1 from above, return type is a named reference so we need to - // search for relevant arguments. - let mut arguments = Vec::new(); - for (index, argument) in sig.inputs().skip_binder().iter().enumerate() { - if let ty::Ref(argument_region, _, _) = argument.kind() { - if argument_region == return_region { - // Need to use the `rustc_middle::ty` types to compare against the - // `return_region`. Then use the `rustc_hir` type to get only - // the lifetime span. - if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind { - // With access to the lifetime, we can get - // the span of it. - arguments.push((*argument, lifetime.span)); - } else { - bug!("ty type is a ref but hir type is not"); - } - } - } - } - - // We need to have arguments. This shouldn't happen, but it's worth checking. - if arguments.is_empty() { - return None; - } - - // We use a mix of the HIR and the Ty types to get information - // as the HIR doesn't have full types for closure arguments. - let return_ty = sig.output().skip_binder(); - let mut return_span = fn_decl.output.span(); - if let hir::FnRetTy::Return(ty) = &fn_decl.output { - if let hir::TyKind::Rptr(lifetime, _) = ty.kind { - return_span = lifetime.span; - } - } - - Some(AnnotatedBorrowFnSignature::NamedFunction { - arguments, - return_ty, - return_span, - }) - } - ty::Ref(_, _, _) if is_closure => { - // This is case 2 from above but only for closures, return type is anonymous - // reference so we select - // the first argument. - let argument_span = fn_decl.inputs.first()?.span; - let argument_ty = sig.inputs().skip_binder().first()?; - - // Closure arguments are wrapped in a tuple, so we need to get the first - // from that. - if let ty::Tuple(elems) = argument_ty.kind() { - let argument_ty = elems.first()?.expect_ty(); - if let ty::Ref(_, _, _) = argument_ty.kind() { - return Some(AnnotatedBorrowFnSignature::Closure { - argument_ty, - argument_span, - }); - } - } - - None - } - ty::Ref(_, _, _) => { - // This is also case 2 from above but for functions, return type is still an - // anonymous reference so we select the first argument. - let argument_span = fn_decl.inputs.first()?.span; - let argument_ty = sig.inputs().skip_binder().first()?; - - let return_span = fn_decl.output.span(); - let return_ty = sig.output().skip_binder(); - - // We expect the first argument to be a reference. - match argument_ty.kind() { - ty::Ref(_, _, _) => {} - _ => return None, - } - - Some(AnnotatedBorrowFnSignature::AnonymousFunction { - argument_ty, - argument_span, - return_ty, - return_span, - }) - } - _ => { - // This is case 3 from above, return type is not a reference so don't highlight - // anything. - None - } - } - } -} - -#[derive(Debug)] -enum AnnotatedBorrowFnSignature<'tcx> { - NamedFunction { - arguments: Vec<(Ty<'tcx>, Span)>, - return_ty: Ty<'tcx>, - return_span: Span, - }, - AnonymousFunction { - argument_ty: Ty<'tcx>, - argument_span: Span, - return_ty: Ty<'tcx>, - return_span: Span, - }, - Closure { - argument_ty: Ty<'tcx>, - argument_span: Span, - }, -} - -impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { - /// Annotate the provided diagnostic with information about borrow from the fn signature that - /// helps explain. - pub(in crate::borrow_check) fn emit( - &self, - cx: &mut MirBorrowckCtxt<'_, 'tcx>, - diag: &mut DiagnosticBuilder<'_>, - ) -> String { - match self { - AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => { - diag.span_label( - *argument_span, - format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)), - ); - - cx.get_region_name_for_ty(argument_ty, 0) - } - AnnotatedBorrowFnSignature::AnonymousFunction { - argument_ty, - argument_span, - return_ty, - return_span, - } => { - let argument_ty_name = cx.get_name_for_ty(argument_ty, 0); - diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name)); - - let return_ty_name = cx.get_name_for_ty(return_ty, 0); - let types_equal = return_ty_name == argument_ty_name; - diag.span_label( - *return_span, - format!( - "{}has type `{}`", - if types_equal { "also " } else { "" }, - return_ty_name, - ), - ); - - diag.note( - "argument and return type have the same lifetime due to lifetime elision rules", - ); - diag.note( - "to learn more, visit ", - ); - - cx.get_region_name_for_ty(return_ty, 0) - } - AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => { - // Region of return type and arguments checked to be the same earlier. - let region_name = cx.get_region_name_for_ty(return_ty, 0); - for (_, argument_span) in arguments { - diag.span_label(*argument_span, format!("has lifetime `{}`", region_name)); - } - - diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,)); - - diag.help(&format!( - "use data from the highlighted arguments which match the `{}` lifetime of \ - the return type", - region_name, - )); - - region_name - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,744 +0,0 @@ -//! Print diagnostics to explain why values are borrowed. - -use std::collections::VecDeque; - -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_index::vec::IndexVec; -use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_middle::mir::{ - Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue, - Statement, StatementKind, TerminatorKind, -}; -use rustc_middle::ty::adjustment::PointerCast; -use rustc_middle::ty::{self, RegionVid, TyCtxt}; -use rustc_span::symbol::Symbol; -use rustc_span::Span; - -use crate::borrow_check::region_infer::BlameConstraint; -use crate::borrow_check::{ - borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt, - WriteKind, -}; - -use super::{find_use, RegionName, UseSpans}; - -#[derive(Debug)] -pub(in crate::borrow_check) enum BorrowExplanation { - UsedLater(LaterUseKind, Span, Option), - UsedLaterInLoop(LaterUseKind, Span, Option), - UsedLaterWhenDropped { - drop_loc: Location, - dropped_local: Local, - should_note_order: bool, - }, - MustBeValidFor { - category: ConstraintCategory, - from_closure: bool, - span: Span, - region_name: RegionName, - opt_place_desc: Option, - }, - Unexplained, -} - -#[derive(Clone, Copy, Debug)] -pub(in crate::borrow_check) enum LaterUseKind { - TraitCapture, - ClosureCapture, - Call, - FakeLetRead, - Other, -} - -impl BorrowExplanation { - pub(in crate::borrow_check) fn is_explained(&self) -> bool { - match self { - BorrowExplanation::Unexplained => false, - _ => true, - } - } - pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - local_names: &IndexVec>, - err: &mut DiagnosticBuilder<'_>, - borrow_desc: &str, - borrow_span: Option, - multiple_borrow_span: Option<(Span, Span)>, - ) { - match *self { - BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { - let message = match later_use_kind { - LaterUseKind::TraitCapture => "captured here by trait object", - LaterUseKind::ClosureCapture => "captured here by closure", - LaterUseKind::Call => "used by call", - LaterUseKind::FakeLetRead => "stored here", - LaterUseKind::Other => "used here", - }; - // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same - if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { - err.span_label( - var_or_use_span, - format!("{}borrow later {}", borrow_desc, message), - ); - } - } else { - // path_span must be `Some` as otherwise the if condition is true - let path_span = path_span.unwrap(); - // path_span is only present in the case of closure capture - assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); - if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { - let path_label = "used here by closure"; - let capture_kind_label = message; - err.span_label( - var_or_use_span, - format!("{}borrow later {}", borrow_desc, capture_kind_label), - ); - err.span_label(path_span, path_label); - } - } - } - BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => { - let message = match later_use_kind { - LaterUseKind::TraitCapture => { - "borrow captured here by trait object, in later iteration of loop" - } - LaterUseKind::ClosureCapture => { - "borrow captured here by closure, in later iteration of loop" - } - LaterUseKind::Call => "borrow used by call, in later iteration of loop", - LaterUseKind::FakeLetRead => "borrow later stored here", - LaterUseKind::Other => "borrow used here, in later iteration of loop", - }; - // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same - if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); - } else { - // path_span must be `Some` as otherwise the if condition is true - let path_span = path_span.unwrap(); - // path_span is only present in the case of closure capture - assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); - if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { - let path_label = "used here by closure"; - let capture_kind_label = message; - err.span_label( - var_or_use_span, - format!("{}borrow later {}", borrow_desc, capture_kind_label), - ); - err.span_label(path_span, path_label); - } - } - } - BorrowExplanation::UsedLaterWhenDropped { - drop_loc, - dropped_local, - should_note_order, - } => { - let local_decl = &body.local_decls[dropped_local]; - let (dtor_desc, type_desc) = match local_decl.ty.kind() { - // If type is an ADT that implements Drop, then - // simplify output by reporting just the ADT name. - ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => { - ("`Drop` code", format!("type `{}`", tcx.def_path_str(adt.did))) - } - - // Otherwise, just report the whole type (and use - // the intentionally fuzzy phrase "destructor") - ty::Closure(..) => ("destructor", "closure".to_owned()), - ty::Generator(..) => ("destructor", "generator".to_owned()), - - _ => ("destructor", format!("type `{}`", local_decl.ty)), - }; - - match local_names[dropped_local] { - Some(local_name) if !local_decl.from_compiler_desugaring() => { - let message = format!( - "{B}borrow might be used here, when `{LOC}` is dropped \ - and runs the {DTOR} for {TYPE}", - B = borrow_desc, - LOC = local_name, - TYPE = type_desc, - DTOR = dtor_desc - ); - err.span_label(body.source_info(drop_loc).span, message); - - if should_note_order { - err.note( - "values in a scope are dropped \ - in the opposite order they are defined", - ); - } - } - _ => { - err.span_label( - local_decl.source_info.span, - format!( - "a temporary with access to the {B}borrow \ - is created here ...", - B = borrow_desc - ), - ); - let message = format!( - "... and the {B}borrow might be used here, \ - when that temporary is dropped \ - and runs the {DTOR} for {TYPE}", - B = borrow_desc, - TYPE = type_desc, - DTOR = dtor_desc - ); - err.span_label(body.source_info(drop_loc).span, message); - - if let Some(info) = &local_decl.is_block_tail { - if info.tail_result_is_ignored { - // #85581: If the first mutable borrow's scope contains - // the second borrow, this suggestion isn't helpful. - if !multiple_borrow_span - .map(|(old, new)| { - old.to(info.span.shrink_to_hi()).contains(new) - }) - .unwrap_or(false) - { - err.span_suggestion_verbose( - info.span.shrink_to_hi(), - "consider adding semicolon after the expression so its \ - temporaries are dropped sooner, before the local variables \ - declared by the block are dropped", - ";".to_string(), - Applicability::MaybeIncorrect, - ); - } - } else { - err.note( - "the temporary is part of an expression at the end of a \ - block;\nconsider forcing this temporary to be dropped sooner, \ - before the block's local variables are dropped", - ); - err.multipart_suggestion( - "for example, you could save the expression's value in a new \ - local variable `x` and then make `x` be the expression at the \ - end of the block", - vec![ - (info.span.shrink_to_lo(), "let x = ".to_string()), - (info.span.shrink_to_hi(), "; x".to_string()), - ], - Applicability::MaybeIncorrect, - ); - }; - } - } - } - } - BorrowExplanation::MustBeValidFor { - category, - span, - ref region_name, - ref opt_place_desc, - from_closure: _, - } => { - region_name.highlight_region_name(err); - - if let Some(desc) = opt_place_desc { - err.span_label( - span, - format!( - "{}requires that `{}` is borrowed for `{}`", - category.description(), - desc, - region_name, - ), - ); - } else { - err.span_label( - span, - format!( - "{}requires that {}borrow lasts for `{}`", - category.description(), - borrow_desc, - region_name, - ), - ); - }; - - self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); - } - _ => {} - } - } - pub(in crate::borrow_check) fn add_lifetime_bound_suggestion_to_diagnostic( - &self, - err: &mut DiagnosticBuilder<'_>, - category: &ConstraintCategory, - span: Span, - region_name: &RegionName, - ) { - if let ConstraintCategory::OpaqueType = category { - let suggestable_name = - if region_name.was_named() { region_name.to_string() } else { "'_".to_string() }; - - let msg = format!( - "you can add a bound to the {}to make it last less than `'static` and match `{}`", - category.description(), - region_name, - ); - - err.span_suggestion_verbose( - span.shrink_to_hi(), - &msg, - format!(" + {}", suggestable_name), - Applicability::Unspecified, - ); - } - } -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - fn free_region_constraint_info( - &self, - borrow_region: RegionVid, - outlived_region: RegionVid, - ) -> (ConstraintCategory, bool, Span, Option) { - let BlameConstraint { category, from_closure, span, variance_info: _ } = - self.regioncx.best_blame_constraint( - &self.body, - borrow_region, - NllRegionVariableOrigin::FreeRegion, - |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), - ); - - let outlived_fr_name = self.give_region_a_name(outlived_region); - - (category, from_closure, span, outlived_fr_name) - } - - /// Returns structured explanation for *why* the borrow contains the - /// point from `location`. This is key for the "3-point errors" - /// [described in the NLL RFC][d]. - /// - /// # Parameters - /// - /// - `borrow`: the borrow in question - /// - `location`: where the borrow occurs - /// - `kind_place`: if Some, this describes the statement that triggered the error. - /// - first half is the kind of write, if any, being performed - /// - second half is the place being accessed - /// - /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points - pub(in crate::borrow_check) fn explain_why_borrow_contains_point( - &self, - location: Location, - borrow: &BorrowData<'tcx>, - kind_place: Option<(WriteKind, Place<'tcx>)>, - ) -> BorrowExplanation { - debug!( - "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})", - location, borrow, kind_place - ); - - let regioncx = &self.regioncx; - let body: &Body<'_> = &self.body; - let tcx = self.infcx.tcx; - - let borrow_region_vid = borrow.region; - debug!("explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid); - - let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location); - debug!("explain_why_borrow_contains_point: region_sub={:?}", region_sub); - - match find_use::find(body, regioncx, tcx, region_sub, location) { - Some(Cause::LiveVar(local, location)) => { - let span = body.source_info(location).span; - let spans = self - .move_spans(Place::from(local).as_ref(), location) - .or_else(|| self.borrow_spans(span, location)); - - let borrow_location = location; - if self.is_use_in_later_iteration_of_loop(borrow_location, location) { - let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2) - } else { - // Check if the location represents a `FakeRead`, and adapt the error - // message to the `FakeReadCause` it is from: in particular, - // the ones inserted in optimized `let var = ` patterns. - let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2) - } - } - - Some(Cause::DropVar(local, location)) => { - let mut should_note_order = false; - if self.local_names[local].is_some() { - if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { - if let Some(borrowed_local) = place.as_local() { - if self.local_names[borrowed_local].is_some() && local != borrowed_local - { - should_note_order = true; - } - } - } - } - - BorrowExplanation::UsedLaterWhenDropped { - drop_loc: location, - dropped_local: local, - should_note_order, - } - } - - None => { - if let Some(region) = self.to_error_region_vid(borrow_region_vid) { - let (category, from_closure, span, region_name) = - self.free_region_constraint_info(borrow_region_vid, region); - if let Some(region_name) = region_name { - let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref()); - BorrowExplanation::MustBeValidFor { - category, - from_closure, - span, - region_name, - opt_place_desc, - } - } else { - debug!( - "explain_why_borrow_contains_point: \ - Could not generate a region name" - ); - BorrowExplanation::Unexplained - } - } else { - debug!( - "explain_why_borrow_contains_point: \ - Could not generate an error region vid" - ); - BorrowExplanation::Unexplained - } - } - } - } - - /// true if `borrow_location` can reach `use_location` by going through a loop and - /// `use_location` is also inside of that loop - fn is_use_in_later_iteration_of_loop( - &self, - borrow_location: Location, - use_location: Location, - ) -> bool { - let back_edge = self.reach_through_backedge(borrow_location, use_location); - back_edge.map_or(false, |back_edge| self.can_reach_head_of_loop(use_location, back_edge)) - } - - /// Returns the outmost back edge if `from` location can reach `to` location passing through - /// that back edge - fn reach_through_backedge(&self, from: Location, to: Location) -> Option { - let mut visited_locations = FxHashSet::default(); - let mut pending_locations = VecDeque::new(); - visited_locations.insert(from); - pending_locations.push_back(from); - debug!("reach_through_backedge: from={:?} to={:?}", from, to,); - - let mut outmost_back_edge = None; - while let Some(location) = pending_locations.pop_front() { - debug!( - "reach_through_backedge: location={:?} outmost_back_edge={:?} - pending_locations={:?} visited_locations={:?}", - location, outmost_back_edge, pending_locations, visited_locations - ); - - if location == to && outmost_back_edge.is_some() { - // We've managed to reach the use location - debug!("reach_through_backedge: found!"); - return outmost_back_edge; - } - - let block = &self.body.basic_blocks()[location.block]; - - if location.statement_index < block.statements.len() { - let successor = location.successor_within_block(); - if visited_locations.insert(successor) { - pending_locations.push_back(successor); - } - } else { - pending_locations.extend( - block - .terminator() - .successors() - .map(|bb| Location { statement_index: 0, block: *bb }) - .filter(|s| visited_locations.insert(*s)) - .map(|s| { - if self.is_back_edge(location, s) { - match outmost_back_edge { - None => { - outmost_back_edge = Some(location); - } - - Some(back_edge) - if location.dominates(back_edge, &self.dominators) => - { - outmost_back_edge = Some(location); - } - - Some(_) => {} - } - } - - s - }), - ); - } - } - - None - } - - /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the - /// intermediate nodes - fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool { - self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default()) - } - - fn find_loop_head_dfs( - &self, - from: Location, - loop_head: Location, - visited_locations: &mut FxHashSet, - ) -> bool { - visited_locations.insert(from); - - if from == loop_head { - return true; - } - - if loop_head.dominates(from, &self.dominators) { - let block = &self.body.basic_blocks()[from.block]; - - if from.statement_index < block.statements.len() { - let successor = from.successor_within_block(); - - if !visited_locations.contains(&successor) - && self.find_loop_head_dfs(successor, loop_head, visited_locations) - { - return true; - } - } else { - for bb in block.terminator().successors() { - let successor = Location { statement_index: 0, block: *bb }; - - if !visited_locations.contains(&successor) - && self.find_loop_head_dfs(successor, loop_head, visited_locations) - { - return true; - } - } - } - } - - false - } - - /// True if an edge `source -> target` is a backedge -- in other words, if the target - /// dominates the source. - fn is_back_edge(&self, source: Location, target: Location) -> bool { - target.dominates(source, &self.dominators) - } - - /// Determine how the borrow was later used. - /// First span returned points to the location of the conflicting use - /// Second span if `Some` is returned in the case of closures and points - /// to the use of the path - fn later_use_kind( - &self, - borrow: &BorrowData<'tcx>, - use_spans: UseSpans<'tcx>, - location: Location, - ) -> (LaterUseKind, Span, Option) { - match use_spans { - UseSpans::ClosureUse { capture_kind_span, path_span, .. } => { - // Used in a closure. - (LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span)) - } - UseSpans::PatUse(span) - | UseSpans::OtherUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } => { - let block = &self.body.basic_blocks()[location.block]; - - let kind = if let Some(&Statement { - kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)), - .. - }) = block.statements.get(location.statement_index) - { - LaterUseKind::FakeLetRead - } else if self.was_captured_by_trait_object(borrow) { - LaterUseKind::TraitCapture - } else if location.statement_index == block.statements.len() { - if let TerminatorKind::Call { ref func, from_hir_call: true, .. } = - block.terminator().kind - { - // Just point to the function, to reduce the chance of overlapping spans. - let function_span = match func { - Operand::Constant(c) => c.span, - Operand::Copy(place) | Operand::Move(place) => { - if let Some(l) = place.as_local() { - let local_decl = &self.body.local_decls[l]; - if self.local_names[l].is_none() { - local_decl.source_info.span - } else { - span - } - } else { - span - } - } - }; - return (LaterUseKind::Call, function_span, None); - } else { - LaterUseKind::Other - } - } else { - LaterUseKind::Other - }; - - (kind, span, None) - } - } - } - - /// Checks if a borrowed value was captured by a trait object. We do this by - /// looking forward in the MIR from the reserve location and checking if we see - /// an unsized cast to a trait object on our data. - fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { - // Start at the reserve location, find the place that we want to see cast to a trait object. - let location = borrow.reserve_location; - let block = &self.body[location.block]; - let stmt = block.statements.get(location.statement_index); - debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt); - - // We make a `queue` vector that has the locations we want to visit. As of writing, this - // will only ever have one item at any given time, but by using a vector, we can pop from - // it which simplifies the termination logic. - let mut queue = vec![location]; - let mut target = if let Some(&Statement { - kind: StatementKind::Assign(box (ref place, _)), - .. - }) = stmt - { - if let Some(local) = place.as_local() { - local - } else { - return false; - } - } else { - return false; - }; - - debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); - while let Some(current_location) = queue.pop() { - debug!("was_captured_by_trait: target={:?}", target); - let block = &self.body[current_location.block]; - // We need to check the current location to find out if it is a terminator. - let is_terminator = current_location.statement_index == block.statements.len(); - if !is_terminator { - let stmt = &block.statements[current_location.statement_index]; - debug!("was_captured_by_trait_object: stmt={:?}", stmt); - - // The only kind of statement that we care about is assignments... - if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind { - let into = match place.local_or_deref_local() { - Some(into) => into, - None => { - // Continue at the next location. - queue.push(current_location.successor_within_block()); - continue; - } - }; - - match rvalue { - // If we see a use, we should check whether it is our data, and if so - // update the place that we're looking for to that new place. - Rvalue::Use(operand) => match operand { - Operand::Copy(place) | Operand::Move(place) => { - if let Some(from) = place.as_local() { - if from == target { - target = into; - } - } - } - _ => {} - }, - // If we see an unsized cast, then if it is our data we should check - // whether it is being cast to a trait object. - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, ty) => { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - if let Some(from) = place.as_local() { - if from == target { - debug!("was_captured_by_trait_object: ty={:?}", ty); - // Check the type for a trait object. - return match ty.kind() { - // `&dyn Trait` - ty::Ref(_, ty, _) if ty.is_trait() => true, - // `Box` - _ if ty.is_box() && ty.boxed_ty().is_trait() => { - true - } - // `dyn Trait` - _ if ty.is_trait() => true, - // Anything else. - _ => false, - }; - } - } - return false; - } - _ => return false, - } - } - _ => {} - } - } - - // Continue at the next location. - queue.push(current_location.successor_within_block()); - } else { - // The only thing we need to do for terminators is progress to the next block. - let terminator = block.terminator(); - debug!("was_captured_by_trait_object: terminator={:?}", terminator); - - if let TerminatorKind::Call { destination: Some((place, block)), args, .. } = - &terminator.kind - { - if let Some(dest) = place.as_local() { - debug!( - "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", - target, dest, args - ); - // Check if one of the arguments to this function is the target place. - let found_target = args.iter().any(|arg| { - if let Operand::Move(place) = arg { - if let Some(potential) = place.as_local() { - potential == target - } else { - false - } - } else { - false - } - }); - - // If it is, follow this to the next block and update the target. - if found_target { - target = dest; - queue.push(block.start_location()); - } - } - } - } - - debug!("was_captured_by_trait: queue={:?}", queue); - } - - // We didn't find anything and ran out of locations to check. - false - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,128 +0,0 @@ -use std::collections::VecDeque; -use std::rc::Rc; - -use crate::borrow_check::{ - def_use::{self, DefUse}, - nll::ToRegionVid, - region_infer::{Cause, RegionInferenceContext}, -}; -use rustc_data_structures::fx::FxHashSet; -use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location}; -use rustc_middle::ty::{RegionVid, TyCtxt}; - -crate fn find<'tcx>( - body: &Body<'tcx>, - regioncx: &Rc>, - tcx: TyCtxt<'tcx>, - region_vid: RegionVid, - start_point: Location, -) -> Option { - let mut uf = UseFinder { body, regioncx, tcx, region_vid, start_point }; - - uf.find() -} - -struct UseFinder<'cx, 'tcx> { - body: &'cx Body<'tcx>, - regioncx: &'cx Rc>, - tcx: TyCtxt<'tcx>, - region_vid: RegionVid, - start_point: Location, -} - -impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { - fn find(&mut self) -> Option { - let mut queue = VecDeque::new(); - let mut visited = FxHashSet::default(); - - queue.push_back(self.start_point); - while let Some(p) = queue.pop_front() { - if !self.regioncx.region_contains(self.region_vid, p) { - continue; - } - - if !visited.insert(p) { - continue; - } - - let block_data = &self.body[p.block]; - - match self.def_use(p, block_data.visitable(p.statement_index)) { - Some(DefUseResult::Def) => {} - - Some(DefUseResult::UseLive { local }) => { - return Some(Cause::LiveVar(local, p)); - } - - Some(DefUseResult::UseDrop { local }) => { - return Some(Cause::DropVar(local, p)); - } - - None => { - if p.statement_index < block_data.statements.len() { - queue.push_back(p.successor_within_block()); - } else { - queue.extend( - block_data - .terminator() - .successors() - .filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind()) - .map(|&bb| Location { statement_index: 0, block: bb }), - ); - } - } - } - } - - None - } - - fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option { - let mut visitor = DefUseVisitor { - body: self.body, - tcx: self.tcx, - region_vid: self.region_vid, - def_use_result: None, - }; - - thing.apply(location, &mut visitor); - - visitor.def_use_result - } -} - -struct DefUseVisitor<'cx, 'tcx> { - body: &'cx Body<'tcx>, - tcx: TyCtxt<'tcx>, - region_vid: RegionVid, - def_use_result: Option, -} - -enum DefUseResult { - Def, - UseLive { local: Local }, - UseDrop { local: Local }, -} - -impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { - let local_ty = self.body.local_decls[local].ty; - - let mut found_it = false; - self.tcx.for_each_free_region(&local_ty, |r| { - if r.to_region_vid() == self.region_vid { - found_it = true; - } - }); - - if found_it { - self.def_use_result = match def_use::categorize(context) { - Some(DefUse::Def) => Some(DefUseResult::Def), - Some(DefUse::Use) => Some(DefUseResult::UseLive { local }), - Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }), - None => None, - }; - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1094 +0,0 @@ -//! Borrow checker diagnostics. - -use rustc_errors::DiagnosticBuilder; -use rustc_hir as hir; -use rustc_hir::def::Namespace; -use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItemGroup; -use rustc_hir::GeneratorKind; -use rustc_middle::mir::{ - AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand, - Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, -}; -use rustc_middle::ty::print::Print; -use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; -use rustc_span::{ - hygiene::{DesugaringKind, ForLoopLoc}, - symbol::sym, - Span, -}; -use rustc_target::abi::VariantIdx; - -use super::borrow_set::BorrowData; -use super::MirBorrowckCtxt; -use crate::dataflow::move_paths::{InitLocation, LookupResult}; - -mod find_use; -mod outlives_suggestion; -mod region_name; -mod var_name; - -mod bound_region_errors; -mod conflict_errors; -mod explain_borrow; -mod move_errors; -mod mutability_errors; -mod region_errors; - -crate use bound_region_errors::{ToUniverseInfo, UniverseInfo}; -crate use mutability_errors::AccessKind; -crate use outlives_suggestion::OutlivesSuggestionBuilder; -crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; -crate use region_name::{RegionName, RegionNameSource}; -use rustc_span::symbol::Ident; - -pub(super) struct IncludingDowncast(pub(super) bool); - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure - /// is moved after being invoked. - /// - /// ```text - /// note: closure cannot be invoked more than once because it moves the variable `dict` out of - /// its environment - /// --> $DIR/issue-42065.rs:16:29 - /// | - /// LL | for (key, value) in dict { - /// | ^^^^ - /// ``` - pub(super) fn add_moved_or_invoked_closure_note( - &self, - location: Location, - place: PlaceRef<'tcx>, - diag: &mut DiagnosticBuilder<'_>, - ) { - debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); - let mut target = place.local_or_deref_local(); - for stmt in &self.body[location.block].statements[location.statement_index..] { - debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target); - if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind { - debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from); - match from { - Operand::Copy(ref place) | Operand::Move(ref place) - if target == place.local_or_deref_local() => - { - target = into.local_or_deref_local() - } - _ => {} - } - } - } - - // Check if we are attempting to call a closure after it has been invoked. - let terminator = self.body[location.block].terminator(); - debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); - if let TerminatorKind::Call { - func: Operand::Constant(box Constant { literal, .. }), - args, - .. - } = &terminator.kind - { - if let ty::FnDef(id, _) = *literal.ty().kind() { - debug!("add_moved_or_invoked_closure_note: id={:?}", id); - if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { - let closure = match args.first() { - Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place)) - if target == place.local_or_deref_local() => - { - place.local_or_deref_local().unwrap() - } - _ => return, - }; - - debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); - if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { - let did = did.expect_local(); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - - if let Some((span, hir_place)) = - self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) - { - diag.span_note( - *span, - &format!( - "closure cannot be invoked more than once because it moves the \ - variable `{}` out of its environment", - ty::place_to_string_for_capture(self.infcx.tcx, hir_place) - ), - ); - return; - } - } - } - } - } - - // Check if we are just moving a closure after it has been invoked. - if let Some(target) = target { - if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { - let did = did.expect_local(); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - - if let Some((span, hir_place)) = - self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) - { - diag.span_note( - *span, - &format!( - "closure cannot be moved more than once as it is not `Copy` due to \ - moving the variable `{}` out of its environment", - ty::place_to_string_for_capture(self.infcx.tcx, hir_place) - ), - ); - } - } - } - } - - /// End-user visible description of `place` if one can be found. - /// If the place is a temporary for instance, `"value"` will be returned. - pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String { - match self.describe_place(place_ref) { - Some(mut descr) => { - // Surround descr with `backticks`. - descr.reserve(2); - descr.insert(0, '`'); - descr.push('`'); - descr - } - None => "value".to_string(), - } - } - - /// End-user visible description of `place` if one can be found. - /// If the place is a temporary for instance, None will be returned. - pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option { - self.describe_place_with_options(place_ref, IncludingDowncast(false)) - } - - /// End-user visible description of `place` if one can be found. If the - /// place is a temporary for instance, None will be returned. - /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is - /// `Downcast` and `IncludingDowncast` is true - pub(super) fn describe_place_with_options( - &self, - place: PlaceRef<'tcx>, - including_downcast: IncludingDowncast, - ) -> Option { - let mut buf = String::new(); - match self.append_place_to_string(place, &mut buf, false, &including_downcast) { - Ok(()) => Some(buf), - Err(()) => None, - } - } - - /// Appends end-user visible description of `place` to `buf`. - fn append_place_to_string( - &self, - place: PlaceRef<'tcx>, - buf: &mut String, - mut autoderef: bool, - including_downcast: &IncludingDowncast, - ) -> Result<(), ()> { - match place { - PlaceRef { local, projection: [] } => { - self.append_local_to_string(local, buf)?; - } - PlaceRef { local, projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_for_guard() => - { - self.append_place_to_string( - PlaceRef { local, projection: &[] }, - buf, - autoderef, - &including_downcast, - )?; - } - PlaceRef { local, projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_to_static() => - { - let local_info = &self.body.local_decls[local].local_info; - if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { - buf.push_str(&self.infcx.tcx.item_name(def_id).as_str()); - } else { - unreachable!(); - } - } - PlaceRef { local, projection: [proj_base @ .., elem] } => { - match elem { - ProjectionElem::Deref => { - let upvar_field_projection = self.is_upvar_field_projection(place); - if let Some(field) = upvar_field_projection { - let var_index = field.index(); - let name = self.upvars[var_index].place.to_string(self.infcx.tcx); - if self.upvars[var_index].by_ref { - buf.push_str(&name); - } else { - buf.push('*'); - buf.push_str(&name); - } - } else { - if autoderef { - // FIXME turn this recursion into iteration - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - } else { - buf.push('*'); - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - } - } - } - ProjectionElem::Downcast(..) => { - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - if including_downcast.0 { - return Err(()); - } - } - ProjectionElem::Field(field, _ty) => { - autoderef = true; - - // FIXME(project-rfc_2229#36): print capture precisely here. - let upvar_field_projection = self.is_upvar_field_projection(place); - if let Some(field) = upvar_field_projection { - let var_index = field.index(); - let name = self.upvars[var_index].place.to_string(self.infcx.tcx); - buf.push_str(&name); - } else { - let field_name = self - .describe_field(PlaceRef { local, projection: proj_base }, *field); - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - buf.push('.'); - buf.push_str(&field_name); - } - } - ProjectionElem::Index(index) => { - autoderef = true; - - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - buf.push('['); - if self.append_local_to_string(*index, buf).is_err() { - buf.push('_'); - } - buf.push(']'); - } - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { - autoderef = true; - // Since it isn't possible to borrow an element on a particular index and - // then use another while the borrow is held, don't output indices details - // to avoid confusing the end-user - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - buf.push_str("[..]"); - } - }; - } - } - - Ok(()) - } - - /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have - /// a name, or its name was generated by the compiler, then `Err` is returned - fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> { - let decl = &self.body.local_decls[local]; - match self.local_names[local] { - Some(name) if !decl.from_compiler_desugaring() => { - buf.push_str(&name.as_str()); - Ok(()) - } - _ => Err(()), - } - } - - /// End-user visible description of the `field`nth field of `base` - fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String { - // FIXME Place2 Make this work iteratively - match place { - PlaceRef { local, projection: [] } => { - let local = &self.body.local_decls[local]; - self.describe_field_from_ty(&local.ty, field, None) - } - PlaceRef { local, projection: [proj_base @ .., elem] } => match elem { - ProjectionElem::Deref => { - self.describe_field(PlaceRef { local, projection: proj_base }, field) - } - ProjectionElem::Downcast(_, variant_index) => { - let base_ty = place.ty(self.body, self.infcx.tcx).ty; - self.describe_field_from_ty(&base_ty, field, Some(*variant_index)) - } - ProjectionElem::Field(_, field_type) => { - self.describe_field_from_ty(&field_type, field, None) - } - ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => { - self.describe_field(PlaceRef { local, projection: proj_base }, field) - } - }, - } - } - - /// End-user visible description of the `field_index`nth field of `ty` - fn describe_field_from_ty( - &self, - ty: Ty<'_>, - field: Field, - variant_index: Option, - ) -> String { - if ty.is_box() { - // If the type is a box, the field is described from the boxed type - self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index) - } else { - match *ty.kind() { - ty::Adt(def, _) => { - let variant = if let Some(idx) = variant_index { - assert!(def.is_enum()); - &def.variants[idx] - } else { - def.non_enum_variant() - }; - variant.fields[field.index()].ident.to_string() - } - ty::Tuple(_) => field.index().to_string(), - ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - self.describe_field_from_ty(&ty, field, variant_index) - } - ty::Array(ty, _) | ty::Slice(ty) => { - self.describe_field_from_ty(&ty, field, variant_index) - } - ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - // We won't be borrowck'ing here if the closure came from another crate, - // so it's safe to call `expect_local`. - // - // We know the field exists so it's safe to call operator[] and `unwrap` here. - let var_id = self - .infcx - .tcx - .typeck(def_id.expect_local()) - .closure_min_captures_flattened(def_id) - .nth(field.index()) - .unwrap() - .get_root_variable(); - - self.infcx.tcx.hir().name(var_id).to_string() - } - _ => { - // Might need a revision when the fields in trait RFC is implemented - // (https://github.com/rust-lang/rfcs/pull/1546) - bug!("End-user description not implemented for field access on `{:?}`", ty); - } - } - } - } - - /// Add a note that a type does not implement `Copy` - pub(super) fn note_type_does_not_implement_copy( - &self, - err: &mut DiagnosticBuilder<'a>, - place_desc: &str, - ty: Ty<'tcx>, - span: Option, - move_prefix: &str, - ) { - let message = format!( - "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait", - move_prefix, place_desc, ty, - ); - if let Some(span) = span { - err.span_label(span, message); - } else { - err.note(&message); - } - } - - pub(super) fn borrowed_content_source( - &self, - deref_base: PlaceRef<'tcx>, - ) -> BorrowedContentSource<'tcx> { - let tcx = self.infcx.tcx; - - // Look up the provided place and work out the move path index for it, - // we'll use this to check whether it was originally from an overloaded - // operator. - match self.move_data.rev_lookup.find(deref_base) { - LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => { - debug!("borrowed_content_source: mpi={:?}", mpi); - - for i in &self.move_data.init_path_map[mpi] { - let init = &self.move_data.inits[*i]; - debug!("borrowed_content_source: init={:?}", init); - // We're only interested in statements that initialized a value, not the - // initializations from arguments. - let loc = match init.location { - InitLocation::Statement(stmt) => stmt, - _ => continue, - }; - - let bbd = &self.body[loc.block]; - let is_terminator = bbd.statements.len() == loc.statement_index; - debug!( - "borrowed_content_source: loc={:?} is_terminator={:?}", - loc, is_terminator, - ); - if !is_terminator { - continue; - } else if let Some(Terminator { - kind: TerminatorKind::Call { ref func, from_hir_call: false, .. }, - .. - }) = bbd.terminator - { - if let Some(source) = - BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx) - { - return source; - } - } - } - } - // Base is a `static` so won't be from an overloaded operator - _ => (), - }; - - // If we didn't find an overloaded deref or index, then assume it's a - // built in deref and check the type of the base. - let base_ty = deref_base.ty(self.body, tcx).ty; - if base_ty.is_unsafe_ptr() { - BorrowedContentSource::DerefRawPointer - } else if base_ty.is_mutable_ptr() { - BorrowedContentSource::DerefMutableRef - } else { - BorrowedContentSource::DerefSharedRef - } - } -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime - /// name where required. - pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); - - // We need to add synthesized lifetimes where appropriate. We do - // this by hooking into the pretty printer and telling it to label the - // lifetimes without names with the value `'0`. - match ty.kind() { - ty::Ref( - ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. }) - | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), - _, - _, - ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter), - _ => {} - } - - let _ = ty.print(printer); - s - } - - /// Returns the name of the provided `Ty` (that must be a reference)'s region with a - /// synthesized lifetime name where required. - pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); - - let region = match ty.kind() { - ty::Ref(region, _, _) => { - match region { - ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. }) - | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { - printer.region_highlight_mode.highlighting_bound_region(*br, counter) - } - _ => {} - } - - region - } - _ => bug!("ty for annotation of borrow region is not a reference"), - }; - - let _ = region.print(printer); - s - } -} - -/// The span(s) associated to a use of a place. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum UseSpans<'tcx> { - /// The access is caused by capturing a variable for a closure. - ClosureUse { - /// This is true if the captured variable was from a generator. - generator_kind: Option, - /// The span of the args of the closure, including the `move` keyword if - /// it's present. - args_span: Span, - /// The span of the use resulting in capture kind - /// Check `ty::CaptureInfo` for more details - capture_kind_span: Span, - /// The span of the use resulting in the captured path - /// Check `ty::CaptureInfo` for more details - path_span: Span, - }, - /// The access is caused by using a variable as the receiver of a method - /// that takes 'self' - FnSelfUse { - /// The span of the variable being moved - var_span: Span, - /// The span of the method call on the variable - fn_call_span: Span, - /// The definition span of the method being called - fn_span: Span, - kind: FnSelfUseKind<'tcx>, - }, - /// This access is caused by a `match` or `if let` pattern. - PatUse(Span), - /// This access has a single span associated to it: common case. - OtherUse(Span), -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum FnSelfUseKind<'tcx> { - /// A normal method call of the form `receiver.foo(a, b, c)` - Normal { - self_arg: Ident, - implicit_into_iter: bool, - /// Whether the self type of the method call has an `.as_ref()` method. - /// Used for better diagnostics. - is_option_or_result: bool, - }, - /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` - FnOnceCall, - /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) - Operator { self_arg: Ident }, - DerefCoercion { - /// The `Span` of the `Target` associated type - /// in the `Deref` impl we are using. - deref_target: Span, - /// The type `T::Deref` we are dereferencing to - deref_target_ty: Ty<'tcx>, - }, -} - -impl UseSpans<'_> { - pub(super) fn args_or_use(self) -> Span { - match self { - UseSpans::ClosureUse { args_span: span, .. } - | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { - fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. - } => fn_call_span, - UseSpans::FnSelfUse { var_span, .. } => var_span, - } - } - - /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span` - pub(super) fn var_or_use_path_span(self) -> Span { - match self { - UseSpans::ClosureUse { path_span: span, .. } - | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { - fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. - } => fn_call_span, - UseSpans::FnSelfUse { var_span, .. } => var_span, - } - } - - /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span` - pub(super) fn var_or_use(self) -> Span { - match self { - UseSpans::ClosureUse { capture_kind_span: span, .. } - | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { - fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. - } => fn_call_span, - UseSpans::FnSelfUse { var_span, .. } => var_span, - } - } - - pub(super) fn generator_kind(self) -> Option { - match self { - UseSpans::ClosureUse { generator_kind, .. } => generator_kind, - _ => None, - } - } - - // Add a span label to the arguments of the closure, if it exists. - pub(super) fn args_span_label( - self, - err: &mut DiagnosticBuilder<'_>, - message: impl Into, - ) { - if let UseSpans::ClosureUse { args_span, .. } = self { - err.span_label(args_span, message); - } - } - - // Add a span label to the use of the captured variable, if it exists. - // only adds label to the `path_span` - pub(super) fn var_span_label_path_only( - self, - err: &mut DiagnosticBuilder<'_>, - message: impl Into, - ) { - if let UseSpans::ClosureUse { path_span, .. } = self { - err.span_label(path_span, message); - } - } - - // Add a span label to the use of the captured variable, if it exists. - pub(super) fn var_span_label( - self, - err: &mut DiagnosticBuilder<'_>, - message: impl Into, - kind_desc: impl Into, - ) { - if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self { - if capture_kind_span == path_span { - err.span_label(capture_kind_span, message); - } else { - let capture_kind_label = - format!("capture is {} because of use here", kind_desc.into()); - let path_label = message; - err.span_label(capture_kind_span, capture_kind_label); - err.span_label(path_span, path_label); - } - } - } - - /// Returns `false` if this place is not used in a closure. - pub(super) fn for_closure(&self) -> bool { - match *self { - UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(), - _ => false, - } - } - - /// Returns `false` if this place is not used in a generator. - pub(super) fn for_generator(&self) -> bool { - match *self { - UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(), - _ => false, - } - } - - /// Describe the span associated with a use of a place. - pub(super) fn describe(&self) -> String { - match *self { - UseSpans::ClosureUse { generator_kind, .. } => { - if generator_kind.is_some() { - " in generator".to_string() - } else { - " in closure".to_string() - } - } - _ => String::new(), - } - } - - pub(super) fn or_else(self, if_other: F) -> Self - where - F: FnOnce() -> Self, - { - match self { - closure @ UseSpans::ClosureUse { .. } => closure, - UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(), - fn_self @ UseSpans::FnSelfUse { .. } => fn_self, - } - } -} - -pub(super) enum BorrowedContentSource<'tcx> { - DerefRawPointer, - DerefMutableRef, - DerefSharedRef, - OverloadedDeref(Ty<'tcx>), - OverloadedIndex(Ty<'tcx>), -} - -impl BorrowedContentSource<'tcx> { - pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String { - match *self { - BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(), - BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(), - BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(), - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { - "an `Rc`".to_string() - } - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { - "an `Arc`".to_string() - } - _ => format!("dereference of `{}`", ty), - }, - BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty), - } - } - - pub(super) fn describe_for_named_place(&self) -> Option<&'static str> { - match *self { - BorrowedContentSource::DerefRawPointer => Some("raw pointer"), - BorrowedContentSource::DerefSharedRef => Some("shared reference"), - BorrowedContentSource::DerefMutableRef => Some("mutable reference"), - // Overloaded deref and index operators should be evaluated into a - // temporary. So we don't need a description here. - BorrowedContentSource::OverloadedDeref(_) - | BorrowedContentSource::OverloadedIndex(_) => None, - } - } - - pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String { - match *self { - BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(), - BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(), - BorrowedContentSource::DerefMutableRef => { - bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") - } - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { - "an `Rc`".to_string() - } - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { - "an `Arc`".to_string() - } - _ => format!("a dereference of `{}`", ty), - }, - BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty), - } - } - - fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option { - match *func.kind() { - ty::FnDef(def_id, substs) => { - let trait_id = tcx.trait_of_item(def_id)?; - - let lang_items = tcx.lang_items(); - if Some(trait_id) == lang_items.deref_trait() - || Some(trait_id) == lang_items.deref_mut_trait() - { - Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0))) - } else if Some(trait_id) == lang_items.index_trait() - || Some(trait_id) == lang_items.index_mut_trait() - { - Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0))) - } else { - None - } - } - _ => None, - } - } -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Finds the spans associated to a move or copy of move_place at location. - pub(super) fn move_spans( - &self, - moved_place: PlaceRef<'tcx>, // Could also be an upvar. - location: Location, - ) -> UseSpans<'tcx> { - use self::UseSpans::*; - - let stmt = match self.body[location.block].statements.get(location.statement_index) { - Some(stmt) => stmt, - None => return OtherUse(self.body.source_info(location).span), - }; - - debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); - if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind { - match kind { - box AggregateKind::Closure(def_id, _) - | box AggregateKind::Generator(def_id, _, _) => { - debug!("move_spans: def_id={:?} places={:?}", def_id, places); - if let Some((args_span, generator_kind, capture_kind_span, path_span)) = - self.closure_span(*def_id, moved_place, places) - { - return ClosureUse { - generator_kind, - args_span, - capture_kind_span, - path_span, - }; - } - } - _ => {} - } - } - - // StatementKind::FakeRead only contains a def_id if they are introduced as a result - // of pattern matching within a closure. - if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind { - match cause { - FakeReadCause::ForMatchedPlace(Some(closure_def_id)) - | FakeReadCause::ForLet(Some(closure_def_id)) => { - debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place); - let places = &[Operand::Move(*place)]; - if let Some((args_span, generator_kind, capture_kind_span, path_span)) = - self.closure_span(closure_def_id, moved_place, places) - { - return ClosureUse { - generator_kind, - args_span, - capture_kind_span, - path_span, - }; - } - } - _ => {} - } - } - - let normal_ret = - if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { - PatUse(stmt.source_info.span) - } else { - OtherUse(stmt.source_info.span) - }; - - // We are trying to find MIR of the form: - // ``` - // _temp = _moved_val; - // ... - // FnSelfCall(_temp, ...) - // ``` - // - // where `_moved_val` is the place we generated the move error for, - // `_temp` is some other local, and `FnSelfCall` is a function - // that has a `self` parameter. - - let target_temp = match stmt.kind { - StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => { - temp.as_local().unwrap() - } - _ => return normal_ret, - }; - - debug!("move_spans: target_temp = {:?}", target_temp); - - if let Some(Terminator { - kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. - }) = &self.body[location.block].terminator - { - let (method_did, method_substs) = if let Some(info) = - crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block) - { - info - } else { - return normal_ret; - }; - - let tcx = self.infcx.tcx; - let parent = tcx.parent(method_did); - let is_fn_once = parent == tcx.lang_items().fn_once_trait(); - let is_operator = !from_hir_call - && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p)); - let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); - let fn_call_span = *fn_span; - - let self_arg = tcx.fn_arg_names(method_did)[0]; - - debug!( - "terminator = {:?} from_hir_call={:?}", - self.body[location.block].terminator, from_hir_call - ); - - // Check for a 'special' use of 'self' - - // an FnOnce call, an operator (e.g. `<<`), or a - // deref coercion. - let kind = if is_fn_once { - Some(FnSelfUseKind::FnOnceCall) - } else if is_operator { - Some(FnSelfUseKind::Operator { self_arg }) - } else if is_deref { - let deref_target = - tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, self.param_env, deref_target, method_substs) - .transpose() - }); - if let Some(Ok(instance)) = deref_target { - let deref_target_ty = instance.ty(tcx, self.param_env); - Some(FnSelfUseKind::DerefCoercion { - deref_target: tcx.def_span(instance.def_id()), - deref_target_ty, - }) - } else { - None - } - } else { - None - }; - - let kind = kind.unwrap_or_else(|| { - // This isn't a 'special' use of `self` - debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); - let implicit_into_iter = matches!( - fn_call_span.desugaring_kind(), - Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) - ); - let parent_self_ty = parent - .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl) - .and_then(|did| match tcx.type_of(did).kind() { - ty::Adt(def, ..) => Some(def.did), - _ => None, - }); - let is_option_or_result = parent_self_ty.map_or(false, |def_id| { - tcx.is_diagnostic_item(sym::option_type, def_id) - || tcx.is_diagnostic_item(sym::result_type, def_id) - }); - FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result } - }); - - return FnSelfUse { - var_span: stmt.source_info.span, - fn_call_span, - fn_span: self - .infcx - .tcx - .sess - .source_map() - .guess_head_span(self.infcx.tcx.def_span(method_did)), - kind, - }; - } - normal_ret - } - - /// Finds the span of arguments of a closure (within `maybe_closure_span`) - /// and its usage of the local assigned at `location`. - /// This is done by searching in statements succeeding `location` - /// and originating from `maybe_closure_span`. - pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> { - use self::UseSpans::*; - debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); - - let target = match self.body[location.block].statements.get(location.statement_index) { - Some(&Statement { kind: StatementKind::Assign(box (ref place, _)), .. }) => { - if let Some(local) = place.as_local() { - local - } else { - return OtherUse(use_span); - } - } - _ => return OtherUse(use_span), - }; - - if self.body.local_kind(target) != LocalKind::Temp { - // operands are always temporaries. - return OtherUse(use_span); - } - - for stmt in &self.body[location.block].statements[location.statement_index + 1..] { - if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = - stmt.kind - { - let (def_id, is_generator) = match kind { - box AggregateKind::Closure(def_id, _) => (def_id, false), - box AggregateKind::Generator(def_id, _, _) => (def_id, true), - _ => continue, - }; - - debug!( - "borrow_spans: def_id={:?} is_generator={:?} places={:?}", - def_id, is_generator, places - ); - if let Some((args_span, generator_kind, capture_kind_span, path_span)) = - self.closure_span(*def_id, Place::from(target).as_ref(), places) - { - return ClosureUse { generator_kind, args_span, capture_kind_span, path_span }; - } else { - return OtherUse(use_span); - } - } - - if use_span != stmt.source_info.span { - break; - } - } - - OtherUse(use_span) - } - - /// Finds the spans of a captured place within a closure or generator. - /// The first span is the location of the use resulting in the capture kind of the capture - /// The second span is the location the use resulting in the captured path of the capture - fn closure_span( - &self, - def_id: DefId, - target_place: PlaceRef<'tcx>, - places: &[Operand<'tcx>], - ) -> Option<(Span, Option, Span, Span)> { - debug!( - "closure_span: def_id={:?} target_place={:?} places={:?}", - def_id, target_place, places - ); - let local_did = def_id.as_local()?; - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did); - let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; - debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); - if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { - for (captured_place, place) in self - .infcx - .tcx - .typeck(def_id.expect_local()) - .closure_min_captures_flattened(def_id) - .zip(places) - { - match place { - Operand::Copy(place) | Operand::Move(place) - if target_place == place.as_ref() => - { - debug!("closure_span: found captured local {:?}", place); - let body = self.infcx.tcx.hir().body(*body_id); - let generator_kind = body.generator_kind(); - - return Some(( - *args_span, - generator_kind, - captured_place.get_capture_kind_span(self.infcx.tcx), - captured_place.get_path_span(self.infcx.tcx), - )); - } - _ => {} - } - } - } - None - } - - /// Helper to retrieve span(s) of given borrow from the current MIR - /// representation - pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> { - let span = self.body.source_info(borrow.reserve_location).span; - self.borrow_spans(span, borrow.reserve_location) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,567 +0,0 @@ -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::mir::*; -use rustc_middle::ty; -use rustc_span::source_map::DesugaringKind; -use rustc_span::{sym, Span, DUMMY_SP}; -use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; - -use crate::borrow_check::diagnostics::UseSpans; -use crate::borrow_check::prefixes::PrefixSet; -use crate::borrow_check::MirBorrowckCtxt; -use crate::dataflow::move_paths::{ - IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex, -}; - -// Often when desugaring a pattern match we may have many individual moves in -// MIR that are all part of one operation from the user's point-of-view. For -// example: -// -// let (x, y) = foo() -// -// would move x from the 0 field of some temporary, and y from the 1 field. We -// group such errors together for cleaner error reporting. -// -// Errors are kept separate if they are from places with different parent move -// paths. For example, this generates two errors: -// -// let (&x, &y) = (&String::new(), &String::new()); -#[derive(Debug)] -enum GroupedMoveError<'tcx> { - // Place expression can't be moved from, - // e.g., match x[0] { s => (), } where x: &[String] - MovesFromPlace { - original_path: Place<'tcx>, - span: Span, - move_from: Place<'tcx>, - kind: IllegalMoveOriginKind<'tcx>, - binds_to: Vec, - }, - // Part of a value expression can't be moved from, - // e.g., match &String::new() { &x => (), } - MovesFromValue { - original_path: Place<'tcx>, - span: Span, - move_from: MovePathIndex, - kind: IllegalMoveOriginKind<'tcx>, - binds_to: Vec, - }, - // Everything that isn't from pattern matching. - OtherIllegalMove { - original_path: Place<'tcx>, - use_spans: UseSpans<'tcx>, - kind: IllegalMoveOriginKind<'tcx>, - }, -} - -impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { - pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) { - let grouped_errors = self.group_move_errors(move_errors); - for error in grouped_errors { - self.report(error); - } - } - - fn group_move_errors( - &self, - errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, - ) -> Vec> { - let mut grouped_errors = Vec::new(); - for (original_path, error) in errors { - self.append_to_grouped_errors(&mut grouped_errors, original_path, error); - } - grouped_errors - } - - fn append_to_grouped_errors( - &self, - grouped_errors: &mut Vec>, - original_path: Place<'tcx>, - error: MoveError<'tcx>, - ) { - match error { - MoveError::UnionMove { .. } => { - unimplemented!("don't know how to report union move errors yet.") - } - MoveError::IllegalMove { cannot_move_out_of: IllegalMoveOrigin { location, kind } } => { - // Note: that the only time we assign a place isn't a temporary - // to a user variable is when initializing it. - // If that ever stops being the case, then the ever initialized - // flow could be used. - if let Some(StatementKind::Assign(box ( - place, - Rvalue::Use(Operand::Move(move_from)), - ))) = self.body.basic_blocks()[location.block] - .statements - .get(location.statement_index) - .map(|stmt| &stmt.kind) - { - if let Some(local) = place.as_local() { - let local_decl = &self.body.local_decls[local]; - // opt_match_place is the - // match_span is the span of the expression being matched on - // match *x.y { ... } match_place is Some(*x.y) - // ^^^^ match_span is the span of *x.y - // - // opt_match_place is None for let [mut] x = ... statements, - // whether or not the right-hand side is a place expression - if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { - opt_match_place: Some((opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - }, - )))) = local_decl.local_info - { - let stmt_source_info = self.body.source_info(location); - self.append_binding_error( - grouped_errors, - kind, - original_path, - *move_from, - local, - opt_match_place, - match_span, - stmt_source_info.span, - ); - return; - } - } - } - - let move_spans = self.move_spans(original_path.as_ref(), location); - grouped_errors.push(GroupedMoveError::OtherIllegalMove { - use_spans: move_spans, - original_path, - kind, - }); - } - } - } - - fn append_binding_error( - &self, - grouped_errors: &mut Vec>, - kind: IllegalMoveOriginKind<'tcx>, - original_path: Place<'tcx>, - move_from: Place<'tcx>, - bind_to: Local, - match_place: Option>, - match_span: Span, - statement_span: Span, - ) { - debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span); - - let from_simple_let = match_place.is_none(); - let match_place = match_place.unwrap_or(move_from); - - match self.move_data.rev_lookup.find(match_place.as_ref()) { - // Error with the match place - LookupResult::Parent(_) => { - for ge in &mut *grouped_errors { - if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge { - if match_span == *span { - debug!("appending local({:?}) to list", bind_to); - if !binds_to.is_empty() { - binds_to.push(bind_to); - } - return; - } - } - } - debug!("found a new move error location"); - - // Don't need to point to x in let x = ... . - let (binds_to, span) = if from_simple_let { - (vec![], statement_span) - } else { - (vec![bind_to], match_span) - }; - grouped_errors.push(GroupedMoveError::MovesFromPlace { - span, - move_from, - original_path, - kind, - binds_to, - }); - } - // Error with the pattern - LookupResult::Exact(_) => { - let mpi = match self.move_data.rev_lookup.find(move_from.as_ref()) { - LookupResult::Parent(Some(mpi)) => mpi, - // move_from should be a projection from match_place. - _ => unreachable!("Probably not unreachable..."), - }; - for ge in &mut *grouped_errors { - if let GroupedMoveError::MovesFromValue { - span, - move_from: other_mpi, - binds_to, - .. - } = ge - { - if match_span == *span && mpi == *other_mpi { - debug!("appending local({:?}) to list", bind_to); - binds_to.push(bind_to); - return; - } - } - } - debug!("found a new move error location"); - grouped_errors.push(GroupedMoveError::MovesFromValue { - span: match_span, - move_from: mpi, - original_path, - kind, - binds_to: vec![bind_to], - }); - } - }; - } - - fn report(&mut self, error: GroupedMoveError<'tcx>) { - let (mut err, err_span) = { - let (span, use_spans, original_path, kind): ( - Span, - Option>, - Place<'tcx>, - &IllegalMoveOriginKind<'_>, - ) = match error { - GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. } - | GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => { - (span, None, original_path, kind) - } - GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => { - (use_spans.args_or_use(), Some(use_spans), original_path, kind) - } - }; - debug!( - "report: original_path={:?} span={:?}, kind={:?} \ - original_path.is_upvar_field_projection={:?}", - original_path, - span, - kind, - self.is_upvar_field_projection(original_path.as_ref()) - ); - ( - match kind { - IllegalMoveOriginKind::BorrowedContent { target_place } => self - .report_cannot_move_from_borrowed_content( - original_path, - *target_place, - span, - use_spans, - ), - IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { - self.cannot_move_out_of_interior_of_drop(span, ty) - } - IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { - self.cannot_move_out_of_interior_noncopy(span, ty, Some(*is_index)) - } - }, - span, - ) - }; - - self.add_move_hints(error, &mut err, err_span); - err.buffer(&mut self.errors_buffer); - } - - fn report_cannot_move_from_static( - &mut self, - place: Place<'tcx>, - span: Span, - ) -> DiagnosticBuilder<'a> { - let description = if place.projection.len() == 1 { - format!("static item {}", self.describe_any_place(place.as_ref())) - } else { - let base_static = PlaceRef { local: place.local, projection: &[ProjectionElem::Deref] }; - - format!( - "{} as {} is a static item", - self.describe_any_place(place.as_ref()), - self.describe_any_place(base_static), - ) - }; - - self.cannot_move_out_of(span, &description) - } - - fn report_cannot_move_from_borrowed_content( - &mut self, - move_place: Place<'tcx>, - deref_target_place: Place<'tcx>, - span: Span, - use_spans: Option>, - ) -> DiagnosticBuilder<'a> { - // Inspect the type of the content behind the - // borrow to provide feedback about why this - // was a move rather than a copy. - let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty; - let upvar_field = self - .prefixes(move_place.as_ref(), PrefixSet::All) - .find_map(|p| self.is_upvar_field_projection(p)); - - let deref_base = match deref_target_place.projection.as_ref() { - [proj_base @ .., ProjectionElem::Deref] => { - PlaceRef { local: deref_target_place.local, projection: &proj_base } - } - _ => bug!("deref_target_place is not a deref projection"), - }; - - if let PlaceRef { local, projection: [] } = deref_base { - let decl = &self.body.local_decls[local]; - if decl.is_ref_for_guard() { - let mut err = self.cannot_move_out_of( - span, - &format!("`{}` in pattern guard", self.local_names[local].unwrap()), - ); - err.note( - "variables bound in patterns cannot be moved from \ - until after the end of the pattern guard", - ); - return err; - } else if decl.is_ref_to_static() { - return self.report_cannot_move_from_static(move_place, span); - } - } - - debug!("report: ty={:?}", ty); - let mut err = match ty.kind() { - ty::Array(..) | ty::Slice(..) => { - self.cannot_move_out_of_interior_noncopy(span, ty, None) - } - ty::Closure(def_id, closure_substs) - if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() => - { - let closure_kind_ty = closure_substs.as_closure().kind_ty(); - let closure_kind = closure_kind_ty.to_opt_closure_kind(); - let capture_description = match closure_kind { - Some(ty::ClosureKind::Fn) => "captured variable in an `Fn` closure", - Some(ty::ClosureKind::FnMut) => "captured variable in an `FnMut` closure", - Some(ty::ClosureKind::FnOnce) => { - bug!("closure kind does not match first argument type") - } - None => bug!("closure kind not inferred by borrowck"), - }; - - let upvar = &self.upvars[upvar_field.unwrap().index()]; - let upvar_hir_id = upvar.place.get_root_variable(); - let upvar_name = upvar.place.to_string(self.infcx.tcx); - let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); - - let place_name = self.describe_any_place(move_place.as_ref()); - - let place_description = - if self.is_upvar_field_projection(move_place.as_ref()).is_some() { - format!("{}, a {}", place_name, capture_description) - } else { - format!("{}, as `{}` is a {}", place_name, upvar_name, capture_description) - }; - - debug!( - "report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}", - closure_kind_ty, closure_kind, place_description, - ); - - let mut diag = self.cannot_move_out_of(span, &place_description); - - diag.span_label(upvar_span, "captured outer variable"); - - diag - } - _ => { - let source = self.borrowed_content_source(deref_base); - match (self.describe_place(move_place.as_ref()), source.describe_for_named_place()) - { - (Some(place_desc), Some(source_desc)) => self.cannot_move_out_of( - span, - &format!("`{}` which is behind a {}", place_desc, source_desc), - ), - (_, _) => self.cannot_move_out_of( - span, - &source.describe_for_unnamed_place(self.infcx.tcx), - ), - } - } - }; - let ty = move_place.ty(self.body, self.infcx.tcx).ty; - let def_id = match *ty.kind() { - ty::Adt(self_def, _) => self_def.did, - ty::Foreign(def_id) - | ty::FnDef(def_id, _) - | ty::Closure(def_id, _) - | ty::Generator(def_id, ..) - | ty::Opaque(def_id, _) => def_id, - _ => return err, - }; - let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id); - let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id); - if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) { - err.span_suggestion_verbose( - span.shrink_to_hi(), - &format!( - "consider borrowing the `{}`'s content", - if is_option { "Option" } else { "Result" } - ), - ".as_ref()".to_string(), - Applicability::MaybeIncorrect, - ); - } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) { - let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { - Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| { - type_known_to_meet_bound_modulo_regions( - &infcx, - self.param_env, - infcx - .tcx - .mk_imm_ref(infcx.tcx.lifetimes.re_erased, infcx.tcx.erase_regions(ty)), - def_id, - DUMMY_SP, - ) - }), - _ => false, - }; - if suggest { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!("consider iterating over a slice of the `{}`'s content", ty), - "&".to_string(), - Applicability::MaybeIncorrect, - ); - } - } - err - } - - fn add_move_hints( - &self, - error: GroupedMoveError<'tcx>, - err: &mut DiagnosticBuilder<'a>, - span: Span, - ) { - match error { - GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { - if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::Unspecified, - ); - } - - if binds_to.is_empty() { - let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; - let place_desc = match self.describe_place(move_from.as_ref()) { - Some(desc) => format!("`{}`", desc), - None => "value".to_string(), - }; - - self.note_type_does_not_implement_copy( - err, - &place_desc, - place_ty, - Some(span), - "", - ); - } else { - binds_to.sort(); - binds_to.dedup(); - - self.add_move_error_details(err, &binds_to); - } - } - GroupedMoveError::MovesFromValue { mut binds_to, .. } => { - binds_to.sort(); - binds_to.dedup(); - self.add_move_error_suggestions(err, &binds_to); - self.add_move_error_details(err, &binds_to); - } - // No binding. Nothing to suggest. - GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { - let span = use_spans.var_or_use(); - let place_ty = original_path.ty(self.body, self.infcx.tcx).ty; - let place_desc = match self.describe_place(original_path.as_ref()) { - Some(desc) => format!("`{}`", desc), - None => "value".to_string(), - }; - self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); - - use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc)); - use_spans.var_span_label( - err, - format!("move occurs due to use{}", use_spans.describe()), - "moved", - ); - } - } - } - - fn add_move_error_suggestions(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) { - let mut suggestions: Vec<(Span, &str, String)> = Vec::new(); - for local in binds_to { - let bind_to = &self.body.local_decls[*local]; - if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { pat_span, .. }, - )))) = bind_to.local_info - { - if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) - { - if let Some(stripped) = pat_snippet.strip_prefix('&') { - let pat_snippet = stripped.trim_start(); - let (suggestion, to_remove) = if pat_snippet.starts_with("mut") - && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace) - { - (pat_snippet["mut".len()..].trim_start(), "&mut") - } else { - (pat_snippet, "&") - }; - suggestions.push((pat_span, to_remove, suggestion.to_owned())); - } - } - } - } - suggestions.sort_unstable_by_key(|&(span, _, _)| span); - suggestions.dedup_by_key(|&mut (span, _, _)| span); - for (span, to_remove, suggestion) in suggestions { - err.span_suggestion( - span, - &format!("consider removing the `{}`", to_remove), - suggestion, - Applicability::MachineApplicable, - ); - } - } - - fn add_move_error_details(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) { - for (j, local) in binds_to.iter().enumerate() { - let bind_to = &self.body.local_decls[*local]; - let binding_span = bind_to.source_info.span; - - if j == 0 { - err.span_label(binding_span, "data moved here"); - } else { - err.span_label(binding_span, "...and here"); - } - - if binds_to.len() == 1 { - self.note_type_does_not_implement_copy( - err, - &format!("`{}`", self.local_names[*local].unwrap()), - bind_to.ty, - Some(binding_span), - "", - ); - } - } - - if binds_to.len() > 1 { - err.note( - "move occurs because these variables have types that \ - don't implement the `Copy` trait", - ); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1098 +0,0 @@ -use rustc_hir as hir; -use rustc_hir::Node; -use rustc_middle::hir::map::Map; -use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::{ - hir::place::PlaceBase, - mir::{ - self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo, - LocalKind, Location, - }, -}; -use rustc_span::source_map::DesugaringKind; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{BytePos, Span}; - -use crate::borrow_check::diagnostics::BorrowedContentSource; -use crate::borrow_check::MirBorrowckCtxt; -use crate::util::collect_writes::FindAssignments; -use rustc_errors::{Applicability, DiagnosticBuilder}; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub(crate) enum AccessKind { - MutableBorrow, - Mutate, -} - -impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { - pub(crate) fn report_mutability_error( - &mut self, - access_place: Place<'tcx>, - span: Span, - the_place_err: PlaceRef<'tcx>, - error_access: AccessKind, - location: Location, - ) { - debug!( - "report_mutability_error(\ - access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\ - )", - access_place, span, the_place_err, error_access, location, - ); - - let mut err; - let item_msg; - let reason; - let mut opt_source = None; - let access_place_desc = self.describe_place(access_place.as_ref()); - debug!("report_mutability_error: access_place_desc={:?}", access_place_desc); - - match the_place_err { - PlaceRef { local, projection: [] } => { - item_msg = format!("`{}`", access_place_desc.unwrap()); - if access_place.as_local().is_some() { - reason = ", as it is not declared as mutable".to_string(); - } else { - let name = self.local_names[local].expect("immutable unnamed local"); - reason = format!(", as `{}` is not declared as mutable", name); - } - } - - PlaceRef { - local, - projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], - } => { - debug_assert!(is_closure_or_generator( - Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty - )); - - let imm_borrow_derefed = self.upvars[upvar_index.index()] - .place - .place - .deref_tys() - .any(|ty| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not))); - - // If the place is immutable then: - // - // - Either we deref an immutable ref to get to our final place. - // - We don't capture derefs of raw ptrs - // - Or the final place is immut because the root variable of the capture - // isn't marked mut and we should suggest that to the user. - if imm_borrow_derefed { - // If we deref an immutable ref then the suggestion here doesn't help. - return; - } else { - item_msg = format!("`{}`", access_place_desc.unwrap()); - if self.is_upvar_field_projection(access_place.as_ref()).is_some() { - reason = ", as it is not declared as mutable".to_string(); - } else { - let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx); - reason = format!(", as `{}` is not declared as mutable", name); - } - } - } - - PlaceRef { local, projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_for_guard() => - { - item_msg = format!("`{}`", access_place_desc.unwrap()); - reason = ", as it is immutable for the pattern guard".to_string(); - } - PlaceRef { local, projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_to_static() => - { - if access_place.projection.len() == 1 { - item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); - reason = String::new(); - } else { - item_msg = format!("`{}`", access_place_desc.unwrap()); - let local_info = &self.body.local_decls[local].local_info; - if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { - let static_name = &self.infcx.tcx.item_name(def_id); - reason = format!(", as `{}` is an immutable static item", static_name); - } else { - bug!("is_ref_to_static return true, but not ref to static?"); - } - } - } - PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => { - if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL - && proj_base.is_empty() - && !self.upvars.is_empty() - { - item_msg = format!("`{}`", access_place_desc.unwrap()); - debug_assert!( - self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr() - ); - debug_assert!(is_closure_or_generator( - Place::ty_from( - the_place_err.local, - the_place_err.projection, - self.body, - self.infcx.tcx - ) - .ty - )); - - reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() { - ", as it is a captured variable in a `Fn` closure".to_string() - } else { - ", as `Fn` closures cannot mutate their captured variables".to_string() - } - } else { - let source = self.borrowed_content_source(PlaceRef { - local: the_place_err.local, - projection: proj_base, - }); - let pointer_type = source.describe_for_immutable_place(self.infcx.tcx); - opt_source = Some(source); - if let Some(desc) = access_place_desc { - item_msg = format!("`{}`", desc); - reason = match error_access { - AccessKind::Mutate => format!(", which is behind {}", pointer_type), - AccessKind::MutableBorrow => { - format!(", as it is behind {}", pointer_type) - } - } - } else { - item_msg = format!("data in {}", pointer_type); - reason = String::new(); - } - } - } - - PlaceRef { - local: _, - projection: - [.., ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..)], - } => bug!("Unexpected immutable place."), - } - - debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason); - - // `act` and `acted_on` are strings that let us abstract over - // the verbs used in some diagnostic messages. - let act; - let acted_on; - - let span = match error_access { - AccessKind::Mutate => { - err = self.cannot_assign(span, &(item_msg + &reason)); - act = "assign"; - acted_on = "written"; - span - } - AccessKind::MutableBorrow => { - act = "borrow as mutable"; - acted_on = "borrowed as mutable"; - - let borrow_spans = self.borrow_spans(span, location); - let borrow_span = borrow_spans.args_or_use(); - err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason); - borrow_spans.var_span_label( - &mut err, - format!( - "mutable borrow occurs due to use of {} in closure", - self.describe_any_place(access_place.as_ref()), - ), - "mutable", - ); - borrow_span - } - }; - - debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on); - - match the_place_err { - // Suggest making an existing shared borrow in a struct definition a mutable borrow. - // - // This is applicable when we have a deref of a field access to a deref of a local - - // something like `*((*_1).0`. The local that we get will be a reference to the - // struct we've got a field access of (it must be a reference since there's a deref - // after the field access). - PlaceRef { - local, - projection: - [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref], - } => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); - - if let Some((span, message)) = annotate_struct_field( - self.infcx.tcx, - Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty, - field, - ) { - err.span_suggestion( - span, - "consider changing this to be mutable", - message, - Applicability::MaybeIncorrect, - ); - } - } - - // Suggest removing a `&mut` from the use of a mutable reference. - PlaceRef { local, projection: [] } - if self - .body - .local_decls - .get(local) - .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) - .unwrap_or(false) => - { - let decl = &self.body.local_decls[local]; - err.span_label(span, format!("cannot {ACT}", ACT = act)); - if let Some(mir::Statement { - source_info, - kind: - mir::StatementKind::Assign(box ( - _, - mir::Rvalue::Ref( - _, - mir::BorrowKind::Mut { allow_two_phase_borrow: false }, - _, - ), - )), - .. - }) = &self.body[location.block].statements.get(location.statement_index) - { - match decl.local_info { - Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), - opt_ty_info: Some(sp), - opt_match_place: _, - pat_span: _, - }, - )))) => { - err.span_note(sp, "the binding is already a mutable borrow"); - } - _ => { - err.span_note( - decl.source_info.span, - "the binding is already a mutable borrow", - ); - } - } - if let Ok(snippet) = - self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span) - { - if snippet.starts_with("&mut ") { - // We don't have access to the HIR to get accurate spans, but we can - // give a best effort structured suggestion. - err.span_suggestion_verbose( - source_info.span.with_hi(source_info.span.lo() + BytePos(5)), - "try removing `&mut` here", - String::new(), - Applicability::MachineApplicable, - ); - } else { - // This can occur with things like `(&mut self).foo()`. - err.span_help(source_info.span, "try removing `&mut` here"); - } - } else { - err.span_help(source_info.span, "try removing `&mut` here"); - } - } else if decl.mutability == Mutability::Not - && !matches!( - decl.local_info, - Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( - ImplicitSelfKind::MutRef - )))) - ) - { - err.span_suggestion_verbose( - decl.source_info.span.shrink_to_lo(), - "consider making the binding mutable", - "mut ".to_string(), - Applicability::MachineApplicable, - ); - } - } - - // We want to suggest users use `let mut` for local (user - // variable) mutations... - PlaceRef { local, projection: [] } - if self.body.local_decls[local].can_be_made_mutable() => - { - // ... but it doesn't make sense to suggest it on - // variables that are `ref x`, `ref mut x`, `&self`, - // or `&mut self` (such variables are simply not - // mutable). - let local_decl = &self.body.local_decls[local]; - assert_eq!(local_decl.mutability, Mutability::Not); - - err.span_label(span, format!("cannot {ACT}", ACT = act)); - err.span_suggestion( - local_decl.source_info.span, - "consider changing this to be mutable", - format!("mut {}", self.local_names[local].unwrap()), - Applicability::MachineApplicable, - ); - let tcx = self.infcx.tcx; - if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() { - self.show_mutating_upvar(tcx, id, the_place_err, &mut err); - } - } - - // Also suggest adding mut for upvars - PlaceRef { - local, - projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], - } => { - debug_assert!(is_closure_or_generator( - Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty - )); - - let captured_place = &self.upvars[upvar_index.index()].place; - - err.span_label(span, format!("cannot {ACT}", ACT = act)); - - let upvar_hir_id = captured_place.get_root_variable(); - - if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) { - if let hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated, - _, - upvar_ident, - _, - ) = pat.kind - { - err.span_suggestion( - upvar_ident.span, - "consider changing this to be mutable", - format!("mut {}", upvar_ident.name), - Applicability::MachineApplicable, - ); - } - } - - let tcx = self.infcx.tcx; - if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind() - { - if let ty::Closure(id, _) = ty.kind() { - self.show_mutating_upvar(tcx, id, the_place_err, &mut err); - } - } - } - - // complete hack to approximate old AST-borrowck - // diagnostic: if the span starts with a mutable borrow of - // a local variable, then just suggest the user remove it. - PlaceRef { local: _, projection: [] } - if { - if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - snippet.starts_with("&mut ") - } else { - false - } - } => - { - err.span_label(span, format!("cannot {ACT}", ACT = act)); - err.span_suggestion( - span, - "try removing `&mut` here", - String::new(), - Applicability::MaybeIncorrect, - ); - } - - PlaceRef { local, projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_for_guard() => - { - err.span_label(span, format!("cannot {ACT}", ACT = act)); - err.note( - "variables bound in patterns are immutable until the end of the pattern guard", - ); - } - - // We want to point out when a `&` can be readily replaced - // with an `&mut`. - // - // FIXME: can this case be generalized to work for an - // arbitrary base for the projection? - PlaceRef { local, projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_user_variable() => - { - let local_decl = &self.body.local_decls[local]; - - let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() { - ("&", "reference") - } else { - ("*const", "pointer") - }; - - match self.local_names[local] { - Some(name) if !local_decl.from_compiler_desugaring() => { - let label = match local_decl.local_info.as_ref().unwrap() { - box LocalInfo::User(ClearCrossCrate::Set( - mir::BindingForm::ImplicitSelf(_), - )) => { - let (span, suggestion) = - suggest_ampmut_self(self.infcx.tcx, local_decl); - Some((true, span, suggestion)) - } - - box LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info, - .. - }, - ))) => { - // check if the RHS is from desugaring - let locations = self.body.find_assignments(local); - let opt_assignment_rhs_span = locations - .first() - .map(|&location| self.body.source_info(location).span); - let opt_desugaring_kind = - opt_assignment_rhs_span.and_then(|span| span.desugaring_kind()); - match opt_desugaring_kind { - // on for loops, RHS points to the iterator part - Some(DesugaringKind::ForLoop(_)) => { - self.suggest_similar_mut_method_for_for_loop(&mut err); - Some(( - false, - opt_assignment_rhs_span.unwrap(), - format!( - "this iterator yields `{SIGIL}` {DESC}s", - SIGIL = pointer_sigil, - DESC = pointer_desc - ), - )) - } - // don't create labels for compiler-generated spans - Some(_) => None, - None => { - let (span, suggestion) = suggest_ampmut( - self.infcx.tcx, - local_decl, - opt_assignment_rhs_span, - *opt_ty_info, - ); - Some((true, span, suggestion)) - } - } - } - - box LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByReference(_), - .. - }, - ))) => { - let pattern_span = local_decl.source_info.span; - suggest_ref_mut(self.infcx.tcx, pattern_span) - .map(|replacement| (true, pattern_span, replacement)) - } - - box LocalInfo::User(ClearCrossCrate::Clear) => { - bug!("saw cleared local state") - } - - _ => unreachable!(), - }; - - match label { - Some((true, err_help_span, suggested_code)) => { - let (is_trait_sig, local_trait) = self.is_error_in_trait(local); - if !is_trait_sig { - err.span_suggestion( - err_help_span, - &format!( - "consider changing this to be a mutable {}", - pointer_desc - ), - suggested_code, - Applicability::MachineApplicable, - ); - } else if let Some(x) = local_trait { - err.span_suggestion( - x, - &format!( - "consider changing that to be a mutable {}", - pointer_desc - ), - suggested_code, - Applicability::MachineApplicable, - ); - } - } - Some((false, err_label_span, message)) => { - err.span_label(err_label_span, &message); - } - None => {} - } - err.span_label( - span, - format!( - "`{NAME}` is a `{SIGIL}` {DESC}, \ - so the data it refers to cannot be {ACTED_ON}", - NAME = name, - SIGIL = pointer_sigil, - DESC = pointer_desc, - ACTED_ON = acted_on - ), - ); - } - _ => { - err.span_label( - span, - format!( - "cannot {ACT} through `{SIGIL}` {DESC}", - ACT = act, - SIGIL = pointer_sigil, - DESC = pointer_desc - ), - ); - } - } - } - - PlaceRef { local, projection: [ProjectionElem::Deref] } - if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() => - { - self.expected_fn_found_fn_mut_call(&mut err, span, act); - } - - PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); - - match opt_source { - Some(BorrowedContentSource::OverloadedDeref(ty)) => { - err.help(&format!( - "trait `DerefMut` is required to modify through a dereference, \ - but it is not implemented for `{}`", - ty, - )); - } - Some(BorrowedContentSource::OverloadedIndex(ty)) => { - err.help(&format!( - "trait `IndexMut` is required to modify indexed content, \ - but it is not implemented for `{}`", - ty, - )); - } - _ => (), - } - } - - _ => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); - } - } - - err.buffer(&mut self.errors_buffer); - } - - /// User cannot make signature of a trait mutable without changing the - /// trait. So we find if this error belongs to a trait and if so we move - /// suggestion to the trait or disable it if it is out of scope of this crate - fn is_error_in_trait(&self, local: Local) -> (bool, Option) { - if self.body.local_kind(local) != LocalKind::Arg { - return (false, None); - } - let hir_map = self.infcx.tcx.hir(); - let my_def = self.body.source.def_id(); - let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap()); - let td = if let Some(a) = - self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x)) - { - a - } else { - return (false, None); - }; - ( - true, - td.as_local().and_then(|tld| { - let h = hir_map.local_def_id_to_hir_id(tld); - match hir_map.find(h) { - Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, _, _, items), - .. - })) => { - let mut f_in_trait_opt = None; - for hir::TraitItemRef { id: fi, kind: k, .. } in *items { - let hi = fi.hir_id(); - if !matches!(k, hir::AssocItemKind::Fn { .. }) { - continue; - } - if hir_map.name(hi) != hir_map.name(my_hir) { - continue; - } - f_in_trait_opt = Some(hi); - break; - } - f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) { - Some(Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn( - hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. }, - _, - ), - .. - })) => { - let hir::Ty { span, .. } = inputs[local.index() - 1]; - Some(span) - } - _ => None, - }) - } - _ => None, - } - }), - ) - } - - // point to span of upvar making closure call require mutable borrow - fn show_mutating_upvar( - &self, - tcx: TyCtxt<'_>, - id: &hir::def_id::DefId, - the_place_err: PlaceRef<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ) { - let closure_local_def_id = id.expect_local(); - let tables = tcx.typeck(closure_local_def_id); - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id); - if let Some((span, closure_kind_origin)) = - &tables.closure_kind_origins().get(closure_hir_id) - { - let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { - let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin); - let root_hir_id = upvar_id.var_path.hir_id; - // we have an origin for this closure kind starting at this root variable so it's safe to unwrap here - let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap(); - - let origin_projection = closure_kind_origin - .projections - .iter() - .map(|proj| proj.kind) - .collect::>(); - let mut capture_reason = String::new(); - for captured_place in captured_places { - let captured_place_kinds = captured_place - .place - .projections - .iter() - .map(|proj| proj.kind) - .collect::>(); - if rustc_middle::ty::is_ancestor_or_same_capture( - &captured_place_kinds, - &origin_projection, - ) { - match captured_place.info.capture_kind { - ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, - .. - }) => { - capture_reason = format!("mutable borrow of `{}`", upvar); - } - ty::UpvarCapture::ByValue(_) => { - capture_reason = format!("possible mutation of `{}`", upvar); - } - _ => bug!("upvar `{}` borrowed, but not mutably", upvar), - } - break; - } - } - if capture_reason.is_empty() { - bug!("upvar `{}` borrowed, but cannot find reason", upvar); - } - capture_reason - } else { - bug!("not an upvar") - }; - err.span_label( - *span, - format!( - "calling `{}` requires mutable binding due to {}", - self.describe_place(the_place_err).unwrap(), - reason - ), - ); - } - } - - // Attempt to search similar mutable associated items for suggestion. - // In the future, attempt in all path but initially for RHS of for_loop - fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) { - use hir::{ - BodyId, Expr, - ExprKind::{Block, Call, DropTemps, Match, MethodCall}, - HirId, ImplItem, ImplItemKind, Item, ItemKind, - }; - - fn maybe_body_id_of_fn(hir_map: &Map<'tcx>, id: HirId) -> Option { - match hir_map.find(id) { - Some(Node::Item(Item { kind: ItemKind::Fn(_, _, body_id), .. })) - | Some(Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })) => { - Some(*body_id) - } - _ => None, - } - } - let hir_map = self.infcx.tcx.hir(); - let mir_body_hir_id = self.mir_hir_id(); - if let Some(fn_body_id) = maybe_body_id_of_fn(&hir_map, mir_body_hir_id) { - if let Block( - hir::Block { - expr: - Some(Expr { - kind: - DropTemps(Expr { - kind: - Match( - Expr { - kind: - Call( - _, - [Expr { - kind: MethodCall(path_segment, ..), - hir_id, - .. - }, ..], - ), - .. - }, - .., - ), - .. - }), - .. - }), - .. - }, - _, - ) = hir_map.body(fn_body_id).value.kind - { - let opt_suggestions = path_segment - .hir_id - .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner)) - .and_then(|typeck| typeck.type_dependent_def_id(*hir_id)) - .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) - .map(|def_id| self.infcx.tcx.associated_items(def_id)) - .map(|assoc_items| { - assoc_items - .in_definition_order() - .map(|assoc_item_def| assoc_item_def.ident) - .filter(|&ident| { - let original_method_ident = path_segment.ident; - original_method_ident != ident - && ident - .as_str() - .starts_with(&original_method_ident.name.to_string()) - }) - .map(|ident| format!("{}()", ident)) - .peekable() - }); - - if let Some(mut suggestions) = opt_suggestions { - if suggestions.peek().is_some() { - err.span_suggestions( - path_segment.ident.span, - "use mutable method", - suggestions, - Applicability::MaybeIncorrect, - ); - } - } - } - }; - } - - /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. - fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) { - err.span_label(sp, format!("cannot {}", act)); - - let hir = self.infcx.tcx.hir(); - let closure_id = self.mir_hir_id(); - let fn_call_id = hir.get_parent_node(closure_id); - let node = hir.get(fn_call_id); - let item_id = hir.enclosing_body_owner(fn_call_id); - let mut look_at_return = true; - // If we can detect the expression to be an `fn` call where the closure was an argument, - // we point at the `fn` definition argument... - if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Call(func, args), .. }) = node { - let arg_pos = args - .iter() - .enumerate() - .filter(|(_, arg)| arg.span == self.body.span) - .map(|(pos, _)| pos) - .next(); - let def_id = hir.local_def_id(item_id); - let tables = self.infcx.tcx.typeck(def_id); - if let Some(ty::FnDef(def_id, _)) = - tables.node_type_opt(func.hir_id).as_ref().map(|ty| ty.kind()) - { - let arg = match hir.get_if_local(*def_id) { - Some( - hir::Node::Item(hir::Item { - ident, kind: hir::ItemKind::Fn(sig, ..), .. - }) - | hir::Node::TraitItem(hir::TraitItem { - ident, - kind: hir::TraitItemKind::Fn(sig, _), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - ident, - kind: hir::ImplItemKind::Fn(sig, _), - .. - }), - ) => Some( - arg_pos - .and_then(|pos| { - sig.decl.inputs.get( - pos + if sig.decl.implicit_self.has_implicit_self() { - 1 - } else { - 0 - }, - ) - }) - .map(|arg| arg.span) - .unwrap_or(ident.span), - ), - _ => None, - }; - if let Some(span) = arg { - err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); - err.span_label(func.span, "expects `Fn` instead of `FnMut`"); - if self.infcx.tcx.sess.source_map().is_multiline(self.body.span) { - err.span_label(self.body.span, "in this closure"); - } - look_at_return = false; - } - } - } - - if look_at_return && hir.get_return_block(closure_id).is_some() { - // ...otherwise we are probably in the tail expression of the function, point at the - // return type. - match hir.get(hir.get_parent_item(fn_call_id)) { - hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) - | hir::Node::TraitItem(hir::TraitItem { - ident, - kind: hir::TraitItemKind::Fn(sig, _), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - ident, - kind: hir::ImplItemKind::Fn(sig, _), - .. - }) => { - err.span_label(ident.span, ""); - err.span_label( - sig.decl.output.span(), - "change this to return `FnMut` instead of `Fn`", - ); - err.span_label(self.body.span, "in this closure"); - } - _ => {} - } - } - } -} - -fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option) -> bool { - debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind()); - - match local_decl.local_info.as_deref() { - // Check if mutably borrowing a mutable reference. - Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), .. - }, - )))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), - Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => { - // Check if the user variable is a `&mut self` and we can therefore - // suggest removing the `&mut`. - // - // Deliberately fall into this case for all implicit self types, - // so that we don't fall in to the next case with them. - *kind == mir::ImplicitSelfKind::MutRef - } - _ if Some(kw::SelfLower) == local_name => { - // Otherwise, check if the name is the `self` keyword - in which case - // we have an explicit self. Do the same thing in this case and check - // for a `self: &mut Self` to suggest removing the `&mut`. - matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)) - } - _ => false, - } -} - -fn suggest_ampmut_self<'tcx>( - tcx: TyCtxt<'tcx>, - local_decl: &mir::LocalDecl<'tcx>, -) -> (Span, String) { - let sp = local_decl.source_info.span; - ( - sp, - match tcx.sess.source_map().span_to_snippet(sp) { - Ok(snippet) => { - let lt_pos = snippet.find('\''); - if let Some(lt_pos) = lt_pos { - format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4]) - } else { - "&mut self".to_string() - } - } - _ => "&mut self".to_string(), - }, - ) -} - -// When we want to suggest a user change a local variable to be a `&mut`, there -// are three potential "obvious" things to highlight: -// -// let ident [: Type] [= RightHandSideExpression]; -// ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ -// (1.) (2.) (3.) -// -// We can always fallback on highlighting the first. But chances are good that -// the user experience will be better if we highlight one of the others if possible; -// for example, if the RHS is present and the Type is not, then the type is going to -// be inferred *from* the RHS, which means we should highlight that (and suggest -// that they borrow the RHS mutably). -// -// This implementation attempts to emulate AST-borrowck prioritization -// by trying (3.), then (2.) and finally falling back on (1.). -fn suggest_ampmut<'tcx>( - tcx: TyCtxt<'tcx>, - local_decl: &mir::LocalDecl<'tcx>, - opt_assignment_rhs_span: Option, - opt_ty_info: Option, -) -> (Span, String) { - if let Some(assignment_rhs_span) = opt_assignment_rhs_span { - if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) { - let is_mutbl = |ty: &str| -> bool { - if ty.starts_with("mut") { - let rest = &ty[3..]; - match rest.chars().next() { - // e.g. `&mut x` - Some(c) if c.is_whitespace() => true, - // e.g. `&mut(x)` - Some('(') => true, - // e.g. `&mut{x}` - Some('{') => true, - // e.g. `&mutablevar` - _ => false, - } - } else { - false - } - }; - if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) { - let lt_name = &src[1..ws_pos]; - let ty = src[ws_pos..].trim_start(); - if !is_mutbl(ty) { - return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty)); - } - } else if let Some(stripped) = src.strip_prefix('&') { - let stripped = stripped.trim_start(); - if !is_mutbl(stripped) { - return (assignment_rhs_span, format!("&mut {}", stripped)); - } - } - } - } - - let highlight_span = match opt_ty_info { - // if this is a variable binding with an explicit type, - // try to highlight that for the suggestion. - Some(ty_span) => ty_span, - - // otherwise, just highlight the span associated with - // the (MIR) LocalDecl. - None => local_decl.source_info.span, - }; - - if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) { - if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) { - let lt_name = &src[1..ws_pos]; - let ty = &src[ws_pos..]; - return (highlight_span, format!("&{} mut{}", lt_name, ty)); - } - } - - let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); - assert_eq!(ty_mut.mutbl, hir::Mutability::Not); - ( - highlight_span, - if local_decl.ty.is_region_ptr() { - format!("&mut {}", ty_mut.ty) - } else { - format!("*mut {}", ty_mut.ty) - }, - ) -} - -fn is_closure_or_generator(ty: Ty<'_>) -> bool { - ty.is_closure() || ty.is_generator() -} - -/// Adds a suggestion to a struct definition given a field access to a local. -/// This function expects the local to be a reference to a struct in order to produce a suggestion. -/// -/// ```text -/// LL | s: &'a String -/// | ---------- use `&'a mut String` here to make mutable -/// ``` -fn annotate_struct_field( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - field: &mir::Field, -) -> Option<(Span, String)> { - // Expect our local to be a reference to a struct of some kind. - if let ty::Ref(_, ty, _) = ty.kind() { - if let ty::Adt(def, _) = ty.kind() { - let field = def.all_fields().nth(field.index())?; - // Use the HIR types to construct the diagnostic message. - let hir_id = tcx.hir().local_def_id_to_hir_id(field.did.as_local()?); - let node = tcx.hir().find(hir_id)?; - // Now we're dealing with the actual struct that we're going to suggest a change to, - // we can expect a field that is an immutable reference to a type. - if let hir::Node::Field(field) = node { - if let hir::TyKind::Rptr( - lifetime, - hir::MutTy { mutbl: hir::Mutability::Not, ref ty }, - ) = field.ty.kind - { - // Get the snippets in two parts - the named lifetime (if there is one) and - // type being referenced, that way we can reconstruct the snippet without loss - // of detail. - let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?; - let lifetime_snippet = if !lifetime.is_elided() { - format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?) - } else { - String::new() - }; - - return Some(( - field.ty.span, - format!("&{}mut {}", lifetime_snippet, &*type_snippet,), - )); - } - } - } - } - - None -} - -/// If possible, suggest replacing `ref` with `ref mut`. -fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option { - let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?; - if hi_src.starts_with("ref") && hi_src["ref".len()..].starts_with(rustc_lexer::is_whitespace) { - let replacement = format!("ref mut{}", &hi_src["ref".len()..]); - Some(replacement) - } else { - None - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,267 +0,0 @@ -//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied -//! outlives constraints. - -use std::collections::BTreeMap; - -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::DiagnosticBuilder; -use rustc_middle::ty::RegionVid; -use tracing::debug; - -use smallvec::SmallVec; - -use crate::borrow_check::MirBorrowckCtxt; - -use super::{ErrorConstraintInfo, RegionName, RegionNameSource}; - -/// The different things we could suggest. -enum SuggestedConstraint { - /// Outlives(a, [b, c, d, ...]) => 'a: 'b + 'c + 'd + ... - Outlives(RegionName, SmallVec<[RegionName; 2]>), - - /// 'a = 'b - Equal(RegionName, RegionName), - - /// 'a: 'static i.e. 'a = 'static and the user should just use 'static - Static(RegionName), -} - -/// Collects information about outlives constraints that needed to be added for a given MIR node -/// corresponding to a function definition. -/// -/// Adds a help note suggesting adding a where clause with the needed constraints. -#[derive(Default)] -pub struct OutlivesSuggestionBuilder { - /// The list of outlives constraints that need to be added. Specifically, we map each free - /// region to all other regions that it must outlive. I will use the shorthand `fr: - /// outlived_frs`. Not all of these regions will already have names necessarily. Some could be - /// implicit free regions that we inferred. These will need to be given names in the final - /// suggestion message. - constraints_to_add: BTreeMap>, -} - -impl OutlivesSuggestionBuilder { - /// Returns `true` iff the `RegionNameSource` is a valid source for an outlives - /// suggestion. - // - // FIXME: Currently, we only report suggestions if the `RegionNameSource` is an early-bound - // region or a named region, avoiding using regions with synthetic names altogether. This - // allows us to avoid giving impossible suggestions (e.g. adding bounds to closure args). - // We can probably be less conservative, since some inferred free regions are namable (e.g. - // the user can explicitly name them. To do this, we would allow some regions whose names - // come from `MatchedAdtAndSegment`, being careful to filter out bad suggestions, such as - // naming the `'self` lifetime in methods, etc. - fn region_name_is_suggestable(name: &RegionName) -> bool { - match name.source { - RegionNameSource::NamedEarlyBoundRegion(..) - | RegionNameSource::NamedFreeRegion(..) - | RegionNameSource::Static => true, - - // Don't give suggestions for upvars, closure return types, or other unnamable - // regions. - RegionNameSource::SynthesizedFreeEnvRegion(..) - | RegionNameSource::AnonRegionFromArgument(..) - | RegionNameSource::AnonRegionFromUpvar(..) - | RegionNameSource::AnonRegionFromOutput(..) - | RegionNameSource::AnonRegionFromYieldTy(..) - | RegionNameSource::AnonRegionFromAsyncFn(..) => { - debug!("Region {:?} is NOT suggestable", name); - false - } - } - } - - /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`. - fn region_vid_to_name( - &self, - mbcx: &MirBorrowckCtxt<'_, '_>, - region: RegionVid, - ) -> Option { - mbcx.give_region_a_name(region).filter(Self::region_name_is_suggestable) - } - - /// Compiles a list of all suggestions to be printed in the final big suggestion. - fn compile_all_suggestions( - &self, - mbcx: &MirBorrowckCtxt<'_, '_>, - ) -> SmallVec<[SuggestedConstraint; 2]> { - let mut suggested = SmallVec::new(); - - // Keep track of variables that we have already suggested unifying so that we don't print - // out silly duplicate messages. - let mut unified_already = FxHashSet::default(); - - for (fr, outlived) in &self.constraints_to_add { - let fr_name = if let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) { - fr_name - } else { - continue; - }; - - let outlived = outlived - .iter() - // if there is a `None`, we will just omit that constraint - .filter_map(|fr| self.region_vid_to_name(mbcx, *fr).map(|rname| (fr, rname))) - .collect::>(); - - // No suggestable outlived lifetimes. - if outlived.is_empty() { - continue; - } - - // There are three types of suggestions we can make: - // 1) Suggest a bound: 'a: 'b - // 2) Suggest replacing 'a with 'static. If any of `outlived` is `'static`, then we - // should just replace 'a with 'static. - // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a - - if outlived - .iter() - .any(|(_, outlived_name)| matches!(outlived_name.source, RegionNameSource::Static)) - { - suggested.push(SuggestedConstraint::Static(fr_name)); - } else { - // We want to isolate out all lifetimes that should be unified and print out - // separate messages for them. - - let (unified, other): (Vec<_>, Vec<_>) = outlived.into_iter().partition( - // Do we have both 'fr: 'r and 'r: 'fr? - |(r, _)| { - self.constraints_to_add - .get(r) - .map(|r_outlived| r_outlived.as_slice().contains(fr)) - .unwrap_or(false) - }, - ); - - for (r, bound) in unified.into_iter() { - if !unified_already.contains(fr) { - suggested.push(SuggestedConstraint::Equal(fr_name.clone(), bound)); - unified_already.insert(r); - } - } - - if !other.is_empty() { - let other = - other.iter().map(|(_, rname)| rname.clone()).collect::>(); - suggested.push(SuggestedConstraint::Outlives(fr_name, other)) - } - } - } - - suggested - } - - /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest. - crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) { - debug!("Collected {:?}: {:?}", fr, outlived_fr); - - // Add to set of constraints for final help note. - self.constraints_to_add.entry(fr).or_default().push(outlived_fr); - } - - /// Emit an intermediate note on the given `Diagnostic` if the involved regions are - /// suggestable. - crate fn intermediate_suggestion( - &mut self, - mbcx: &MirBorrowckCtxt<'_, '_>, - errci: &ErrorConstraintInfo, - diag: &mut DiagnosticBuilder<'_>, - ) { - // Emit an intermediate note. - let fr_name = self.region_vid_to_name(mbcx, errci.fr); - let outlived_fr_name = self.region_vid_to_name(mbcx, errci.outlived_fr); - - if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) { - if let RegionNameSource::Static = outlived_fr_name.source { - diag.help(&format!("consider replacing `{}` with `'static`", fr_name)); - } else { - diag.help(&format!( - "consider adding the following bound: `{}: {}`", - fr_name, outlived_fr_name - )); - } - } - } - - /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final - /// suggestion including all collected constraints. - crate fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) { - // No constraints to add? Done. - if self.constraints_to_add.is_empty() { - debug!("No constraints to suggest."); - return; - } - - // If there is only one constraint to suggest, then we already suggested it in the - // intermediate suggestion above. - if self.constraints_to_add.len() == 1 - && self.constraints_to_add.values().next().unwrap().len() == 1 - { - debug!("Only 1 suggestion. Skipping."); - return; - } - - // Get all suggestable constraints. - let suggested = self.compile_all_suggestions(mbcx); - - // If there are no suggestable constraints... - if suggested.is_empty() { - debug!("Only 1 suggestable constraint. Skipping."); - return; - } - - // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a - // list of diagnostics. - let mut diag = if suggested.len() == 1 { - mbcx.infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() { - SuggestedConstraint::Outlives(a, bs) => { - let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect(); - format!("add bound `{}: {}`", a, bs.join(" + ")) - } - - SuggestedConstraint::Equal(a, b) => { - format!("`{}` and `{}` must be the same: replace one with the other", a, b) - } - SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a), - }) - } else { - // Create a new diagnostic. - let mut diag = mbcx - .infcx - .tcx - .sess - .diagnostic() - .struct_help("the following changes may resolve your lifetime errors"); - - // Add suggestions. - for constraint in suggested { - match constraint { - SuggestedConstraint::Outlives(a, bs) => { - let bs: SmallVec<[String; 2]> = - bs.iter().map(|r| format!("{}", r)).collect(); - diag.help(&format!("add bound `{}: {}`", a, bs.join(" + "))); - } - SuggestedConstraint::Equal(a, b) => { - diag.help(&format!( - "`{}` and `{}` must be the same: replace one with the other", - a, b - )); - } - SuggestedConstraint::Static(a) => { - diag.help(&format!("replace `{}` with `'static`", a)); - } - } - } - - diag - }; - - // We want this message to appear after other messages on the mir def. - let mir_span = mbcx.body.span; - diag.sort_span = mir_span.shrink_to_hi(); - - // Buffer the diagnostic - diag.buffer(&mut mbcx.errors_buffer); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,665 +0,0 @@ -//! Error reporting machinery for lifetime errors. - -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_infer::infer::{ - error_reporting::nice_region_error::NiceRegionError, - error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, -}; -use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; -use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, RegionVid, Ty}; -use rustc_span::symbol::{kw, sym}; -use rustc_span::{BytePos, Span}; - -use crate::util::borrowck_errors; - -use crate::borrow_check::region_infer::BlameConstraint; -use crate::borrow_check::{ - nll::ConstraintDescription, - region_infer::{values::RegionElement, TypeTest}, - universal_regions::DefiningTy, - MirBorrowckCtxt, -}; - -use super::{OutlivesSuggestionBuilder, RegionName}; - -impl ConstraintDescription for ConstraintCategory { - fn description(&self) -> &'static str { - // Must end with a space. Allows for empty names to be provided. - match self { - ConstraintCategory::Assignment => "assignment ", - ConstraintCategory::Return(_) => "returning this value ", - ConstraintCategory::Yield => "yielding this value ", - ConstraintCategory::UseAsConst => "using this value as a constant ", - ConstraintCategory::UseAsStatic => "using this value as a static ", - ConstraintCategory::Cast => "cast ", - ConstraintCategory::CallArgument => "argument ", - ConstraintCategory::TypeAnnotation => "type annotation ", - ConstraintCategory::ClosureBounds => "closure body ", - ConstraintCategory::SizedBound => "proving this value is `Sized` ", - ConstraintCategory::CopyBound => "copying this value ", - ConstraintCategory::OpaqueType => "opaque type ", - ConstraintCategory::ClosureUpvar(_) => "closure capture ", - ConstraintCategory::Boring - | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => "", - } - } -} - -/// A collection of errors encountered during region inference. This is needed to efficiently -/// report errors after borrow checking. -/// -/// Usually we expect this to either be empty or contain a small number of items, so we can avoid -/// allocation most of the time. -crate type RegionErrors<'tcx> = Vec>; - -#[derive(Clone, Debug)] -crate enum RegionErrorKind<'tcx> { - /// A generic bound failure for a type test (`T: 'a`). - TypeTestError { type_test: TypeTest<'tcx> }, - - /// An unexpected hidden region for an opaque type. - UnexpectedHiddenRegion { - /// The span for the member constraint. - span: Span, - /// The hidden type. - hidden_ty: Ty<'tcx>, - /// The unexpected region. - member_region: ty::Region<'tcx>, - }, - - /// Higher-ranked subtyping error. - BoundUniversalRegionError { - /// The placeholder free region. - longer_fr: RegionVid, - /// The region element that erroneously must be outlived by `longer_fr`. - error_element: RegionElement, - /// The placeholder region. - placeholder: ty::PlaceholderRegion, - }, - - /// Any other lifetime error. - RegionError { - /// The origin of the region. - fr_origin: NllRegionVariableOrigin, - /// The region that should outlive `shorter_fr`. - longer_fr: RegionVid, - /// The region that should be shorter, but we can't prove it. - shorter_fr: RegionVid, - /// Indicates whether this is a reported error. We currently only report the first error - /// encountered and leave the rest unreported so as not to overwhelm the user. - is_reported: bool, - }, -} - -/// Information about the various region constraints involved in a borrow checker error. -#[derive(Clone, Debug)] -pub struct ErrorConstraintInfo { - // fr: outlived_fr - pub(super) fr: RegionVid, - pub(super) fr_is_local: bool, - pub(super) outlived_fr: RegionVid, - pub(super) outlived_fr_is_local: bool, - - // Category and span for best blame constraint - pub(super) category: ConstraintCategory, - pub(super) span: Span, -} - -impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { - /// Converts a region inference variable into a `ty::Region` that - /// we can use for error reporting. If `r` is universally bound, - /// then we use the name that we have on record for it. If `r` is - /// existentially bound, then we check its inferred value and try - /// to find a good name from that. Returns `None` if we can't find - /// one (e.g., this is just some random part of the CFG). - pub(super) fn to_error_region(&self, r: RegionVid) -> Option> { - self.to_error_region_vid(r).and_then(|r| self.regioncx.region_definition(r).external_name) - } - - /// Returns the `RegionVid` corresponding to the region returned by - /// `to_error_region`. - pub(super) fn to_error_region_vid(&self, r: RegionVid) -> Option { - if self.regioncx.universal_regions().is_universal_region(r) { - Some(r) - } else { - // We just want something nameable, even if it's not - // actually an upper bound. - let upper_bound = self.regioncx.approx_universal_upper_bound(r); - - if self.regioncx.upper_bound_in_region_scc(r, upper_bound) { - self.to_error_region_vid(upper_bound) - } else { - None - } - } - } - - /// Returns `true` if a closure is inferred to be an `FnMut` closure. - fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { - if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) { - if let ty::BoundRegionKind::BrEnv = free_region.bound_region { - if let DefiningTy::Closure(_, substs) = - self.regioncx.universal_regions().defining_ty - { - return substs.as_closure().kind() == ty::ClosureKind::FnMut; - } - } - } - - false - } - - /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`. - pub(in crate::borrow_check) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) { - // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are - // buffered in the `MirBorrowckCtxt`. - - let mut outlives_suggestion = OutlivesSuggestionBuilder::default(); - - for nll_error in nll_errors.into_iter() { - match nll_error { - RegionErrorKind::TypeTestError { type_test } => { - // Try to convert the lower-bound region into something named we can print for the user. - let lower_bound_region = self.to_error_region(type_test.lower_bound); - - let type_test_span = type_test.locations.span(&self.body); - - if let Some(lower_bound_region) = lower_bound_region { - self.infcx - .construct_generic_bound_failure( - type_test_span, - None, - type_test.generic_kind, - lower_bound_region, - ) - .buffer(&mut self.errors_buffer); - } else { - // FIXME. We should handle this case better. It - // indicates that we have e.g., some region variable - // whose value is like `'a+'b` where `'a` and `'b` are - // distinct unrelated univesal regions that are not - // known to outlive one another. It'd be nice to have - // some examples where this arises to decide how best - // to report it; we could probably handle it by - // iterating over the universal regions and reporting - // an error that multiple bounds are required. - self.infcx - .tcx - .sess - .struct_span_err( - type_test_span, - &format!("`{}` does not live long enough", type_test.generic_kind), - ) - .buffer(&mut self.errors_buffer); - } - } - - RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => { - let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); - let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); - unexpected_hidden_region_diagnostic( - self.infcx.tcx, - span, - named_ty, - named_region, - ) - .buffer(&mut self.errors_buffer); - } - - RegionErrorKind::BoundUniversalRegionError { - longer_fr, - placeholder, - error_element, - } => { - let error_vid = self.regioncx.region_from_element(longer_fr, &error_element); - - // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (_, span) = self.regioncx.find_outlives_blame_span( - &self.body, - longer_fr, - NllRegionVariableOrigin::Placeholder(placeholder), - error_vid, - ); - - let universe = placeholder.universe; - let universe_info = self.regioncx.universe_info(universe); - - universe_info.report_error(self, placeholder, error_element, span); - } - - RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { - if is_reported { - self.report_region_error( - longer_fr, - fr_origin, - shorter_fr, - &mut outlives_suggestion, - ); - } else { - // We only report the first error, so as not to overwhelm the user. See - // `RegRegionErrorKind` docs. - // - // FIXME: currently we do nothing with these, but perhaps we can do better? - // FIXME: try collecting these constraints on the outlives suggestion - // builder. Does it make the suggestions any better? - debug!( - "Unreported region error: can't prove that {:?}: {:?}", - longer_fr, shorter_fr - ); - } - } - } - } - - // Emit one outlives suggestions for each MIR def we borrowck - outlives_suggestion.add_suggestion(self); - } - - /// Report an error because the universal region `fr` was required to outlive - /// `outlived_fr` but it is not known to do so. For example: - /// - /// ``` - /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } - /// ``` - /// - /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. - pub(in crate::borrow_check) fn report_region_error( - &mut self, - fr: RegionVid, - fr_origin: NllRegionVariableOrigin, - outlived_fr: RegionVid, - outlives_suggestion: &mut OutlivesSuggestionBuilder, - ) { - debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - - let BlameConstraint { category, span, variance_info, from_closure: _ } = - self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| { - self.regioncx.provides_universal_region(r, fr, outlived_fr) - }); - - debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info); - // Check if we can use one of the "nice region errors". - if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - let nice = NiceRegionError::new_from_span(self.infcx, span, o, f); - if let Some(diag) = nice.try_report_from_nll() { - diag.buffer(&mut self.errors_buffer); - return; - } - } - - let (fr_is_local, outlived_fr_is_local): (bool, bool) = ( - self.regioncx.universal_regions().is_local_free_region(fr), - self.regioncx.universal_regions().is_local_free_region(outlived_fr), - ); - - debug!( - "report_region_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}", - fr_is_local, outlived_fr_is_local, category - ); - - let errci = ErrorConstraintInfo { - fr, - outlived_fr, - fr_is_local, - outlived_fr_is_local, - category, - span, - }; - - let mut diag = match (category, fr_is_local, outlived_fr_is_local) { - (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => { - self.report_fnmut_error(&errci, kind) - } - (ConstraintCategory::Assignment, true, false) - | (ConstraintCategory::CallArgument, true, false) => { - let mut db = self.report_escaping_data_error(&errci); - - outlives_suggestion.intermediate_suggestion(self, &errci, &mut db); - outlives_suggestion.collect_constraint(fr, outlived_fr); - - db - } - _ => { - let mut db = self.report_general_error(&errci); - - outlives_suggestion.intermediate_suggestion(self, &errci, &mut db); - outlives_suggestion.collect_constraint(fr, outlived_fr); - - db - } - }; - - match variance_info { - ty::VarianceDiagInfo::None => {} - ty::VarianceDiagInfo::Mut { kind, ty } => { - let kind_name = match kind { - ty::VarianceDiagMutKind::Ref => "reference", - ty::VarianceDiagMutKind::RawPtr => "pointer", - }; - diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",)); - diag.note(&format!("mutable {kind_name}s are invariant over their type parameter")); - diag.help("see for more information about variance"); - } - } - - diag.buffer(&mut self.errors_buffer); - } - - /// Report a specialized error when `FnMut` closures return a reference to a captured variable. - /// This function expects `fr` to be local and `outlived_fr` to not be local. - /// - /// ```text - /// error: captured variable cannot escape `FnMut` closure body - /// --> $DIR/issue-53040.rs:15:8 - /// | - /// LL | || &mut v; - /// | -- ^^^^^^ creates a reference to a captured variable which escapes the closure body - /// | | - /// | inferred to be a `FnMut` closure - /// | - /// = note: `FnMut` closures only have access to their captured variables while they are - /// executing... - /// = note: ...therefore, returned references to captured variables will escape the closure - /// ``` - fn report_fnmut_error( - &self, - errci: &ErrorConstraintInfo, - kind: ReturnConstraint, - ) -> DiagnosticBuilder<'tcx> { - let ErrorConstraintInfo { outlived_fr, span, .. } = errci; - - let mut diag = self - .infcx - .tcx - .sess - .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body"); - - let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; - if let ty::Opaque(def_id, _) = *output_ty.kind() { - output_ty = self.infcx.tcx.type_of(def_id) - }; - - debug!("report_fnmut_error: output_ty={:?}", output_ty); - - let message = match output_ty.kind() { - ty::Closure(_, _) => { - "returns a closure that contains a reference to a captured variable, which then \ - escapes the closure body" - } - ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did) => { - "returns an `async` block that contains a reference to a captured variable, which then \ - escapes the closure body" - } - _ => "returns a reference to a captured variable which escapes the closure body", - }; - - diag.span_label(*span, message); - - // FIXME(project-rfc-2229#48): This should store a captured_place not a hir id - if let ReturnConstraint::ClosureUpvar(upvar) = kind { - let def_id = match self.regioncx.universal_regions().defining_ty { - DefiningTy::Closure(def_id, _) => def_id, - ty => bug!("unexpected DefiningTy {:?}", ty), - }; - - let upvar_def_span = self.infcx.tcx.hir().span(upvar); - let upvar_span = self.infcx.tcx.upvars_mentioned(def_id).unwrap()[&upvar].span; - diag.span_label(upvar_def_span, "variable defined here"); - diag.span_label(upvar_span, "variable captured here"); - } - - if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() { - diag.span_label(fr_span, "inferred to be a `FnMut` closure"); - } - - diag.note( - "`FnMut` closures only have access to their captured variables while they are \ - executing...", - ); - diag.note("...therefore, they cannot allow references to captured variables to escape"); - - diag - } - - /// Reports an error specifically for when data is escaping a closure. - /// - /// ```text - /// error: borrowed data escapes outside of function - /// --> $DIR/lifetime-bound-will-change-warning.rs:44:5 - /// | - /// LL | fn test2<'a>(x: &'a Box) { - /// | - `x` is a reference that is only valid in the function body - /// LL | // but ref_obj will not, so warn. - /// LL | ref_obj(x) - /// | ^^^^^^^^^^ `x` escapes the function body here - /// ``` - fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> { - let ErrorConstraintInfo { span, category, .. } = errci; - - let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( - self.infcx.tcx, - &self.body, - &self.local_names, - &self.upvars, - errci.fr, - ); - let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( - self.infcx.tcx, - &self.body, - &self.local_names, - &self.upvars, - errci.outlived_fr, - ); - - let (_, escapes_from) = self - .infcx - .tcx - .article_and_description(self.regioncx.universal_regions().defining_ty.def_id()); - - // Revert to the normal error in these cases. - // Assignments aren't "escapes" in function items. - if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none()) - || (*category == ConstraintCategory::Assignment - && self.regioncx.universal_regions().defining_ty.is_fn_def()) - || self.regioncx.universal_regions().defining_ty.is_const() - { - return self.report_general_error(&ErrorConstraintInfo { - fr_is_local: true, - outlived_fr_is_local: false, - ..*errci - }); - } - - let mut diag = - borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from); - - if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span { - diag.span_label( - outlived_fr_span, - format!( - "`{}` declared here, outside of the {} body", - outlived_fr_name, escapes_from - ), - ); - } - - if let Some((Some(fr_name), fr_span)) = fr_name_and_span { - diag.span_label( - fr_span, - format!( - "`{}` is a reference that is only valid in the {} body", - fr_name, escapes_from - ), - ); - - diag.span_label(*span, format!("`{}` escapes the {} body here", fr_name, escapes_from)); - } - - diag - } - - /// Reports a region inference error for the general case with named/synthesized lifetimes to - /// explain what is happening. - /// - /// ```text - /// error: unsatisfied lifetime constraints - /// --> $DIR/regions-creating-enums3.rs:17:5 - /// | - /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> { - /// | -- -- lifetime `'b` defined here - /// | | - /// | lifetime `'a` defined here - /// LL | ast::add(x, y) - /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it - /// | is returning data with lifetime `'b` - /// ``` - fn report_general_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> { - let ErrorConstraintInfo { - fr, - fr_is_local, - outlived_fr, - outlived_fr_is_local, - span, - category, - .. - } = errci; - - let mut diag = - self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough"); - - let (_, mir_def_name) = - self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id()); - - let fr_name = self.give_region_a_name(*fr).unwrap(); - fr_name.highlight_region_name(&mut diag); - let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap(); - outlived_fr_name.highlight_region_name(&mut diag); - - match (category, outlived_fr_is_local, fr_is_local) { - (ConstraintCategory::Return(_), true, _) => { - diag.span_label( - *span, - format!( - "{} was supposed to return data with lifetime `{}` but it is returning \ - data with lifetime `{}`", - mir_def_name, outlived_fr_name, fr_name - ), - ); - } - _ => { - diag.span_label( - *span, - format!( - "{}requires that `{}` must outlive `{}`", - category.description(), - fr_name, - outlived_fr_name, - ), - ); - } - } - - self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); - - diag - } - - /// Adds a suggestion to errors where an `impl Trait` is returned. - /// - /// ```text - /// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as - /// a constraint - /// | - /// LL | fn iter_values_anon(&self) -> impl Iterator + 'a { - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// ``` - fn add_static_impl_trait_suggestion( - &self, - diag: &mut DiagnosticBuilder<'tcx>, - fr: RegionVid, - // We need to pass `fr_name` - computing it again will label it twice. - fr_name: RegionName, - outlived_fr: RegionVid, - ) { - if let (Some(f), Some(ty::RegionKind::ReStatic)) = - (self.to_error_region(fr), self.to_error_region(outlived_fr)) - { - if let Some(&ty::Opaque(did, substs)) = self - .infcx - .tcx - .is_suitable_region(f) - .map(|r| r.def_id) - .and_then(|id| self.infcx.tcx.return_type_impl_trait(id)) - .map(|(ty, _)| ty.kind()) - { - // Check whether or not the impl trait return type is intended to capture - // data with the static lifetime. - // - // eg. check for `impl Trait + 'static` instead of `impl Trait`. - let has_static_predicate = { - let bounds = self.infcx.tcx.explicit_item_bounds(did); - - let mut found = false; - for (bound, _) in bounds { - if let ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, r)) = - bound.kind().skip_binder() - { - let r = r.subst(self.infcx.tcx, substs); - if let ty::RegionKind::ReStatic = r { - found = true; - break; - } else { - // If there's already a lifetime bound, don't - // suggest anything. - return; - } - } - } - - found - }; - - debug!( - "add_static_impl_trait_suggestion: has_static_predicate={:?}", - has_static_predicate - ); - let static_str = kw::StaticLifetime; - // If there is a static predicate, then the only sensible suggestion is to replace - // fr with `'static`. - if has_static_predicate { - diag.help(&format!("consider replacing `{}` with `{}`", fr_name, static_str)); - } else { - // Otherwise, we should suggest adding a constraint on the return type. - let span = self.infcx.tcx.def_span(did); - if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - let suggestable_fr_name = if fr_name.was_named() { - fr_name.to_string() - } else { - "'_".to_string() - }; - let span = if snippet.ends_with(';') { - // `type X = impl Trait;` - span.with_hi(span.hi() - BytePos(1)) - } else { - span - }; - let suggestion = format!(" + {}", suggestable_fr_name); - let span = span.shrink_to_hi(); - diag.span_suggestion( - span, - &format!( - "to allow this `impl Trait` to capture borrowed data with lifetime \ - `{}`, add `{}` as a bound", - fr_name, suggestable_fr_name, - ), - suggestion, - Applicability::MachineApplicable, - ); - } - } - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,844 +0,0 @@ -use std::fmt::{self, Display}; -use std::iter; - -use rustc_errors::DiagnosticBuilder; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_middle::ty::print::RegionHighlightMode; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, RegionVid, Ty}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; - -use crate::borrow_check::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt}; - -/// A name for a particular region used in emitting diagnostics. This name could be a generated -/// name like `'1`, a name used by the user like `'a`, or a name like `'static`. -#[derive(Debug, Clone)] -crate struct RegionName { - /// The name of the region (interned). - crate name: Symbol, - /// Where the region comes from. - crate source: RegionNameSource, -} - -/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that -/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`. -/// This helps to print the right kinds of diagnostics. -#[derive(Debug, Clone)] -crate enum RegionNameSource { - /// A bound (not free) region that was substituted at the def site (not an HRTB). - NamedEarlyBoundRegion(Span), - /// A free region that the user has a name (`'a`) for. - NamedFreeRegion(Span), - /// The `'static` region. - Static, - /// The free region corresponding to the environment of a closure. - SynthesizedFreeEnvRegion(Span, String), - /// The region corresponding to an argument. - AnonRegionFromArgument(RegionNameHighlight), - /// The region corresponding to a closure upvar. - AnonRegionFromUpvar(Span, String), - /// The region corresponding to the return type of a closure. - AnonRegionFromOutput(RegionNameHighlight, String), - /// The region from a type yielded by a generator. - AnonRegionFromYieldTy(Span, String), - /// An anonymous region from an async fn. - AnonRegionFromAsyncFn(Span), -} - -/// Describes what to highlight to explain to the user that we're giving an anonymous region a -/// synthesized name, and how to highlight it. -#[derive(Debug, Clone)] -crate enum RegionNameHighlight { - /// The anonymous region corresponds to a reference that was found by traversing the type in the HIR. - MatchedHirTy(Span), - /// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union. - MatchedAdtAndSegment(Span), - /// The anonymous region corresponds to a region where the type annotation is completely missing - /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference. - CannotMatchHirTy(Span, String), - /// The anonymous region corresponds to a region where the type annotation is completely missing - /// from the code, and *even if* we print out the full name of the type, the region name won't - /// be included. This currently occurs for opaque types like `impl Future`. - Occluded(Span, String), -} - -impl RegionName { - crate fn was_named(&self) -> bool { - match self.source { - RegionNameSource::NamedEarlyBoundRegion(..) - | RegionNameSource::NamedFreeRegion(..) - | RegionNameSource::Static => true, - RegionNameSource::SynthesizedFreeEnvRegion(..) - | RegionNameSource::AnonRegionFromArgument(..) - | RegionNameSource::AnonRegionFromUpvar(..) - | RegionNameSource::AnonRegionFromOutput(..) - | RegionNameSource::AnonRegionFromYieldTy(..) - | RegionNameSource::AnonRegionFromAsyncFn(..) => false, - } - } - - crate fn span(&self) -> Option { - match self.source { - RegionNameSource::Static => None, - RegionNameSource::NamedEarlyBoundRegion(span) - | RegionNameSource::NamedFreeRegion(span) - | RegionNameSource::SynthesizedFreeEnvRegion(span, _) - | RegionNameSource::AnonRegionFromUpvar(span, _) - | RegionNameSource::AnonRegionFromYieldTy(span, _) - | RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span), - RegionNameSource::AnonRegionFromArgument(ref highlight) - | RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight { - RegionNameHighlight::MatchedHirTy(span) - | RegionNameHighlight::MatchedAdtAndSegment(span) - | RegionNameHighlight::CannotMatchHirTy(span, _) - | RegionNameHighlight::Occluded(span, _) => Some(span), - }, - } - } - - crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) { - match &self.source { - RegionNameSource::NamedFreeRegion(span) - | RegionNameSource::NamedEarlyBoundRegion(span) => { - diag.span_label(*span, format!("lifetime `{}` defined here", self)); - } - RegionNameSource::SynthesizedFreeEnvRegion(span, note) => { - diag.span_label( - *span, - format!("lifetime `{}` represents this closure's body", self), - ); - diag.note(¬e); - } - RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy( - span, - type_name, - )) => { - diag.span_label(*span, format!("has type `{}`", type_name)); - } - RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span)) - | RegionNameSource::AnonRegionFromOutput(RegionNameHighlight::MatchedHirTy(span), _) - | RegionNameSource::AnonRegionFromAsyncFn(span) => { - diag.span_label( - *span, - format!("let's call the lifetime of this reference `{}`", self), - ); - } - RegionNameSource::AnonRegionFromArgument( - RegionNameHighlight::MatchedAdtAndSegment(span), - ) - | RegionNameSource::AnonRegionFromOutput( - RegionNameHighlight::MatchedAdtAndSegment(span), - _, - ) => { - diag.span_label(*span, format!("let's call this `{}`", self)); - } - RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::Occluded( - span, - type_name, - )) => { - diag.span_label( - *span, - format!("lifetime `{}` appears in the type {}", self, type_name), - ); - } - RegionNameSource::AnonRegionFromOutput( - RegionNameHighlight::Occluded(span, type_name), - mir_description, - ) => { - diag.span_label( - *span, - format!( - "return type{} `{}` contains a lifetime `{}`", - mir_description, type_name, self - ), - ); - } - RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => { - diag.span_label( - *span, - format!("lifetime `{}` appears in the type of `{}`", self, upvar_name), - ); - } - RegionNameSource::AnonRegionFromOutput( - RegionNameHighlight::CannotMatchHirTy(span, type_name), - mir_description, - ) => { - diag.span_label(*span, format!("return type{} is {}", mir_description, type_name)); - } - RegionNameSource::AnonRegionFromYieldTy(span, type_name) => { - diag.span_label(*span, format!("yield type is {}", type_name)); - } - RegionNameSource::Static => {} - } - } -} - -impl Display for RegionName { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name) - } -} - -impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { - crate fn mir_def_id(&self) -> hir::def_id::LocalDefId { - self.body.source.def_id().as_local().unwrap() - } - - crate fn mir_hir_id(&self) -> hir::HirId { - self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id()) - } - - /// Generate a synthetic region named `'N`, where `N` is the next value of the counter. Then, - /// increment the counter. - /// - /// This is _not_ idempotent. Call `give_region_a_name` when possible. - fn synthesize_region_name(&self) -> Symbol { - let c = self.next_region_name.replace_with(|counter| *counter + 1); - Symbol::intern(&format!("'{:?}", c)) - } - - /// Maps from an internal MIR region vid to something that we can - /// report to the user. In some cases, the region vids will map - /// directly to lifetimes that the user has a name for (e.g., - /// `'static`). But frequently they will not, in which case we - /// have to find some way to identify the lifetime to the user. To - /// that end, this function takes a "diagnostic" so that it can - /// create auxiliary notes as needed. - /// - /// The names are memoized, so this is both cheap to recompute and idempotent. - /// - /// Example (function arguments): - /// - /// Suppose we are trying to give a name to the lifetime of the - /// reference `x`: - /// - /// ``` - /// fn foo(x: &u32) { .. } - /// ``` - /// - /// This function would create a label like this: - /// - /// ```text - /// | fn foo(x: &u32) { .. } - /// ------- fully elaborated type of `x` is `&'1 u32` - /// ``` - /// - /// and then return the name `'1` for us to use. - crate fn give_region_a_name(&self, fr: RegionVid) -> Option { - debug!( - "give_region_a_name(fr={:?}, counter={:?})", - fr, - self.next_region_name.try_borrow().unwrap() - ); - - assert!(self.regioncx.universal_regions().is_universal_region(fr)); - - if let Some(value) = self.region_names.try_borrow_mut().unwrap().get(&fr) { - return Some(value.clone()); - } - - let value = self - .give_name_from_error_region(fr) - .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)); - - if let Some(ref value) = value { - self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); - } - - debug!("give_region_a_name: gave name {:?}", value); - value - } - - /// Checks for the case where `fr` maps to something that the - /// *user* has a name for. In that case, we'll be able to map - /// `fr` to a `Region<'tcx>`, and that region will be one of - /// named variants. - fn give_name_from_error_region(&self, fr: RegionVid) -> Option { - let error_region = self.to_error_region(fr)?; - - let tcx = self.infcx.tcx; - - debug!("give_region_a_name: error_region = {:?}", error_region); - match error_region { - ty::ReEarlyBound(ebr) => { - if ebr.has_name() { - let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP); - Some(RegionName { - name: ebr.name, - source: RegionNameSource::NamedEarlyBoundRegion(span), - }) - } else { - None - } - } - - ty::ReStatic => { - Some(RegionName { name: kw::StaticLifetime, source: RegionNameSource::Static }) - } - - ty::ReFree(free_region) => match free_region.bound_region { - ty::BoundRegionKind::BrNamed(region_def_id, name) => { - // Get the span to point to, even if we don't use the name. - let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP); - debug!( - "bound region named: {:?}, is_named: {:?}", - name, - free_region.bound_region.is_named() - ); - - if free_region.bound_region.is_named() { - // A named region that is actually named. - Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) - } else { - // If we spuriously thought that the region is named, we should let the - // system generate a true name for error messages. Currently this can - // happen if we have an elided name in an async fn for example: the - // compiler will generate a region named `'_`, but reporting such a name is - // not actually useful, so we synthesize a name for it instead. - let name = self.synthesize_region_name(); - Some(RegionName { - name, - source: RegionNameSource::AnonRegionFromAsyncFn(span), - }) - } - } - - ty::BoundRegionKind::BrEnv => { - let def_ty = self.regioncx.universal_regions().defining_ty; - - if let DefiningTy::Closure(_, substs) = def_ty { - let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) = - tcx.hir().expect_expr(self.mir_hir_id()).kind - { - span - } else { - bug!("Closure is not defined by a closure expr"); - }; - let region_name = self.synthesize_region_name(); - - let closure_kind_ty = substs.as_closure().kind_ty(); - let note = match closure_kind_ty.to_opt_closure_kind() { - Some(ty::ClosureKind::Fn) => { - "closure implements `Fn`, so references to captured variables \ - can't escape the closure" - } - Some(ty::ClosureKind::FnMut) => { - "closure implements `FnMut`, so references to captured variables \ - can't escape the closure" - } - Some(ty::ClosureKind::FnOnce) => { - bug!("BrEnv in a `FnOnce` closure"); - } - None => bug!("Closure kind not inferred in borrow check"), - }; - - Some(RegionName { - name: region_name, - source: RegionNameSource::SynthesizedFreeEnvRegion( - args_span, - note.to_string(), - ), - }) - } else { - // Can't have BrEnv in functions, constants or generators. - bug!("BrEnv outside of closure."); - } - } - - ty::BoundRegionKind::BrAnon(_) => None, - }, - - ty::ReLateBound(..) - | ty::ReVar(..) - | ty::RePlaceholder(..) - | ty::ReEmpty(_) - | ty::ReErased => None, - } - } - - /// Finds an argument that contains `fr` and label it with a fully - /// elaborated type, returning something like `'1`. Result looks - /// like: - /// - /// ```text - /// | fn foo(x: &u32) { .. } - /// ------- fully elaborated type of `x` is `&'1 u32` - /// ``` - fn give_name_if_anonymous_region_appears_in_arguments( - &self, - fr: RegionVid, - ) -> Option { - let implicit_inputs = self.regioncx.universal_regions().defining_ty.implicit_inputs(); - let argument_index = self.regioncx.get_argument_index_for_region(self.infcx.tcx, fr)?; - - let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys - [implicit_inputs + argument_index]; - let (_, span) = self.regioncx.get_argument_name_and_span_for_region( - &self.body, - &self.local_names, - argument_index, - ); - - let highlight = self - .get_argument_hir_ty_for_highlighting(argument_index) - .and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty)) - .unwrap_or_else(|| { - // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to - // the anonymous region. If it succeeds, the `synthesize_region_name` call below - // will increment the counter, "reserving" the number we just used. - let counter = *self.next_region_name.try_borrow().unwrap(); - self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter) - }); - - Some(RegionName { - name: self.synthesize_region_name(), - source: RegionNameSource::AnonRegionFromArgument(highlight), - }) - } - - fn get_argument_hir_ty_for_highlighting( - &self, - argument_index: usize, - ) -> Option<&hir::Ty<'tcx>> { - let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(self.mir_hir_id())?; - let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?; - match argument_hir_ty.kind { - // This indicates a variable with no type annotation, like - // `|x|`... in that case, we can't highlight the type but - // must highlight the variable. - // NOTE(eddyb) this is handled in/by the sole caller - // (`give_name_if_anonymous_region_appears_in_arguments`). - hir::TyKind::Infer => None, - - _ => Some(argument_hir_ty), - } - } - - /// Attempts to highlight the specific part of a type in an argument - /// that has no type annotation. - /// For example, we might produce an annotation like this: - /// - /// ```text - /// | foo(|a, b| b) - /// | - - - /// | | | - /// | | has type `&'1 u32` - /// | has type `&'2 u32` - /// ``` - fn highlight_if_we_cannot_match_hir_ty( - &self, - needle_fr: RegionVid, - ty: Ty<'tcx>, - span: Span, - counter: usize, - ) -> RegionNameHighlight { - let mut highlight = RegionHighlightMode::default(); - highlight.highlighting_region_vid(needle_fr, counter); - let type_name = - self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; - - debug!( - "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", - type_name, needle_fr - ); - if type_name.contains(&format!("'{}", counter)) { - // Only add a label if we can confirm that a region was labelled. - RegionNameHighlight::CannotMatchHirTy(span, type_name) - } else { - RegionNameHighlight::Occluded(span, type_name) - } - } - - /// Attempts to highlight the specific part of a type annotation - /// that contains the anonymous reference we want to give a name - /// to. For example, we might produce an annotation like this: - /// - /// ```text - /// | fn a(items: &[T]) -> Box> { - /// | - let's call the lifetime of this reference `'1` - /// ``` - /// - /// the way this works is that we match up `ty`, which is - /// a `Ty<'tcx>` (the internal form of the type) with - /// `hir_ty`, a `hir::Ty` (the syntax of the type - /// annotation). We are descending through the types stepwise, - /// looking in to find the region `needle_fr` in the internal - /// type. Once we find that, we can use the span of the `hir::Ty` - /// to add the highlight. - /// - /// This is a somewhat imperfect process, so along the way we also - /// keep track of the **closest** type we've found. If we fail to - /// find the exact `&` or `'_` to highlight, then we may fall back - /// to highlighting that closest type instead. - fn highlight_if_we_can_match_hir_ty( - &self, - needle_fr: RegionVid, - ty: Ty<'tcx>, - hir_ty: &hir::Ty<'_>, - ) -> Option { - let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)]; - - while let Some((ty, hir_ty)) = search_stack.pop() { - match (&ty.kind(), &hir_ty.kind) { - // Check if the `ty` is `&'X ..` where `'X` - // is the region we are looking for -- if so, and we have a `&T` - // on the RHS, then we want to highlight the `&` like so: - // - // & - // - let's call the lifetime of this reference `'1` - ( - ty::Ref(region, referent_ty, _), - hir::TyKind::Rptr(_lifetime, referent_hir_ty), - ) => { - if region.to_region_vid() == needle_fr { - // Just grab the first character, the `&`. - let source_map = self.infcx.tcx.sess.source_map(); - let ampersand_span = source_map.start_point(hir_ty.span); - - return Some(RegionNameHighlight::MatchedHirTy(ampersand_span)); - } - - // Otherwise, let's descend into the referent types. - search_stack.push((referent_ty, &referent_hir_ty.ty)); - } - - // Match up something like `Foo<'1>` - ( - ty::Adt(_adt_def, substs), - hir::TyKind::Path(hir::QPath::Resolved(None, path)), - ) => { - match path.res { - // Type parameters of the type alias have no reason to - // be the same as those of the ADT. - // FIXME: We should be able to do something similar to - // match_adt_and_segment in this case. - Res::Def(DefKind::TyAlias, _) => (), - _ => { - if let Some(last_segment) = path.segments.last() { - if let Some(highlight) = self.match_adt_and_segment( - substs, - needle_fr, - last_segment, - search_stack, - ) { - return Some(highlight); - } - } - } - } - } - - // The following cases don't have lifetimes, so we - // just worry about trying to match up the rustc type - // with the HIR types: - (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { - search_stack - .extend(iter::zip(elem_tys.iter().map(|k| k.expect_ty()), *elem_hir_tys)); - } - - (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) - | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => { - search_stack.push((elem_ty, elem_hir_ty)); - } - - (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => { - search_stack.push((mut_ty.ty, &mut_hir_ty.ty)); - } - - _ => { - // FIXME there are other cases that we could trace - } - } - } - - None - } - - /// We've found an enum/struct/union type with the substitutions - /// `substs` and -- in the HIR -- a path type with the final - /// segment `last_segment`. Try to find a `'_` to highlight in - /// the generic args (or, if not, to produce new zipped pairs of - /// types+hir to search through). - fn match_adt_and_segment<'hir>( - &self, - substs: SubstsRef<'tcx>, - needle_fr: RegionVid, - last_segment: &'hir hir::PathSegment<'hir>, - search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, - ) -> Option { - // Did the user give explicit arguments? (e.g., `Foo<..>`) - let args = last_segment.args.as_ref()?; - let lifetime = - self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; - match lifetime.name { - hir::LifetimeName::Param(_) - | hir::LifetimeName::Error - | hir::LifetimeName::Static - | hir::LifetimeName::Underscore => { - let lifetime_span = lifetime.span; - Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) - } - - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => { - // In this case, the user left off the lifetime; so - // they wrote something like: - // - // ``` - // x: Foo - // ``` - // - // where the fully elaborated form is `Foo<'_, '1, - // T>`. We don't consider this a match; instead we let - // the "fully elaborated" type fallback above handle - // it. - None - } - } - } - - /// We've found an enum/struct/union type with the substitutions - /// `substs` and -- in the HIR -- a path with the generic - /// arguments `args`. If `needle_fr` appears in the args, return - /// the `hir::Lifetime` that corresponds to it. If not, push onto - /// `search_stack` the types+hir to search through. - fn try_match_adt_and_generic_args<'hir>( - &self, - substs: SubstsRef<'tcx>, - needle_fr: RegionVid, - args: &'hir hir::GenericArgs<'hir>, - search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, - ) -> Option<&'hir hir::Lifetime> { - for (kind, hir_arg) in iter::zip(substs, args.args) { - match (kind.unpack(), hir_arg) { - (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { - if r.to_region_vid() == needle_fr { - return Some(lt); - } - } - - (GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => { - search_stack.push((ty, hir_ty)); - } - - (GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => { - // Lifetimes cannot be found in consts, so we don't need - // to search anything here. - } - - ( - GenericArgKind::Lifetime(_) - | GenericArgKind::Type(_) - | GenericArgKind::Const(_), - _, - ) => { - // HIR lowering sometimes doesn't catch this in erroneous - // programs, so we need to use delay_span_bug here. See #82126. - self.infcx.tcx.sess.delay_span_bug( - hir_arg.span(), - &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg), - ); - } - } - } - - None - } - - /// Finds a closure upvar that contains `fr` and label it with a - /// fully elaborated type, returning something like `'1`. Result - /// looks like: - /// - /// ```text - /// | let x = Some(&22); - /// - fully elaborated type of `x` is `Option<&'1 u32>` - /// ``` - fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option { - let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; - let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( - self.infcx.tcx, - &self.upvars, - upvar_index, - ); - let region_name = self.synthesize_region_name(); - - Some(RegionName { - name: region_name, - source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()), - }) - } - - /// Checks for arguments appearing in the (closure) return type. It - /// must be a closure since, in a free fn, such an argument would - /// have to either also appear in an argument (if using elision) - /// or be early bound (named, not in argument). - fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option { - let tcx = self.infcx.tcx; - let hir = tcx.hir(); - - let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; - debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty); - if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { - return None; - } - - let mir_hir_id = self.mir_hir_id(); - - let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) { - hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_, return_ty, body_id, span, _), - .. - }) => { - let (mut span, mut hir_ty) = match return_ty.output { - hir::FnRetTy::DefaultReturn(_) => { - (tcx.sess.source_map().end_point(*span), None) - } - hir::FnRetTy::Return(hir_ty) => (return_ty.output.span(), Some(hir_ty)), - }; - let mir_description = match hir.body(*body_id).generator_kind { - Some(hir::GeneratorKind::Async(gen)) => match gen { - hir::AsyncGeneratorKind::Block => " of async block", - hir::AsyncGeneratorKind::Closure => " of async closure", - hir::AsyncGeneratorKind::Fn => { - let parent_item = hir.get(hir.get_parent_item(mir_hir_id)); - let output = &parent_item - .fn_decl() - .expect("generator lowered from async fn should be in fn") - .output; - span = output.span(); - if let hir::FnRetTy::Return(ret) = output { - hir_ty = Some(self.get_future_inner_return_ty(*ret)); - } - " of async function" - } - }, - Some(hir::GeneratorKind::Gen) => " of generator", - None => " of closure", - }; - (span, mir_description, hir_ty) - } - node => match node.fn_decl() { - Some(fn_decl) => { - let hir_ty = match fn_decl.output { - hir::FnRetTy::DefaultReturn(_) => None, - hir::FnRetTy::Return(ty) => Some(ty), - }; - (fn_decl.output.span(), "", hir_ty) - } - None => (self.body.span, "", None), - }, - }; - - let highlight = hir_ty - .and_then(|hir_ty| self.highlight_if_we_can_match_hir_ty(fr, return_ty, hir_ty)) - .unwrap_or_else(|| { - // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to - // the anonymous region. If it succeeds, the `synthesize_region_name` call below - // will increment the counter, "reserving" the number we just used. - let counter = *self.next_region_name.try_borrow().unwrap(); - self.highlight_if_we_cannot_match_hir_ty(fr, return_ty, return_span, counter) - }); - - Some(RegionName { - name: self.synthesize_region_name(), - source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description.to_string()), - }) - } - - /// From the [`hir::Ty`] of an async function's lowered return type, - /// retrieve the `hir::Ty` representing the type the user originally wrote. - /// - /// e.g. given the function: - /// - /// ``` - /// async fn foo() -> i32 {} - /// ``` - /// - /// this function, given the lowered return type of `foo`, an [`OpaqueDef`] that implements `Future`, - /// returns the `i32`. - /// - /// [`OpaqueDef`]: hir::TyKind::OpaqueDef - fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { - let hir = self.infcx.tcx.hir(); - - if let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind { - let opaque_ty = hir.item(id); - if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { - bounds: - [hir::GenericBound::LangItemTrait( - hir::LangItem::Future, - _, - _, - hir::GenericArgs { - bindings: - [hir::TypeBinding { - ident: Ident { name: sym::Output, .. }, - kind: hir::TypeBindingKind::Equality { ty }, - .. - }], - .. - }, - )], - .. - }) = opaque_ty.kind - { - ty - } else { - span_bug!( - hir_ty.span, - "bounds from lowered return type of async fn did not match expected format: {:?}", - opaque_ty - ); - } - } else { - span_bug!( - hir_ty.span, - "lowered return type of async fn is not OpaqueDef: {:?}", - hir_ty - ); - } - } - - fn give_name_if_anonymous_region_appears_in_yield_ty( - &self, - fr: RegionVid, - ) -> Option { - // Note: generators from `async fn` yield `()`, so we don't have to - // worry about them here. - let yield_ty = self.regioncx.universal_regions().yield_ty?; - debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty,); - - let tcx = self.infcx.tcx; - - if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) { - return None; - } - - let mut highlight = RegionHighlightMode::default(); - highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = - self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; - - let yield_span = match tcx.hir().get(self.mir_hir_id()) { - hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_, _, _, span, _), .. - }) => (tcx.sess.source_map().end_point(*span)), - _ => self.body.span, - }; - - debug!( - "give_name_if_anonymous_region_appears_in_yield_ty: \ - type_name = {:?}, yield_span = {:?}", - yield_span, type_name, - ); - - Some(RegionName { - name: self.synthesize_region_name(), - source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), - }) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -use crate::borrow_check::Upvar; -use crate::borrow_check::{nll::ToRegionVid, region_infer::RegionInferenceContext}; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::{Body, Local}; -use rustc_middle::ty::{RegionVid, TyCtxt}; -use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; - -impl<'tcx> RegionInferenceContext<'tcx> { - crate fn get_var_name_and_span_for_region( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - local_names: &IndexVec>, - upvars: &[Upvar<'tcx>], - fr: RegionVid, - ) -> Option<(Option, Span)> { - debug!("get_var_name_and_span_for_region(fr={:?})", fr); - assert!(self.universal_regions().is_universal_region(fr)); - - debug!("get_var_name_and_span_for_region: attempting upvar"); - self.get_upvar_index_for_region(tcx, fr) - .map(|index| { - // FIXME(project-rfc-2229#8): Use place span for diagnostics - let (name, span) = self.get_upvar_name_and_span_for_region(tcx, upvars, index); - (Some(name), span) - }) - .or_else(|| { - debug!("get_var_name_and_span_for_region: attempting argument"); - self.get_argument_index_for_region(tcx, fr).map(|index| { - self.get_argument_name_and_span_for_region(body, local_names, index) - }) - }) - } - - /// Search the upvars (if any) to find one that references fr. Return its index. - crate fn get_upvar_index_for_region(&self, tcx: TyCtxt<'tcx>, fr: RegionVid) -> Option { - let upvar_index = - self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| { - debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty); - tcx.any_free_region_meets(&upvar_ty, |r| { - let r = r.to_region_vid(); - debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr); - r == fr - }) - })?; - - let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index); - - debug!( - "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}", - fr, upvar_index, upvar_ty, - ); - - Some(upvar_index) - } - - /// Given the index of an upvar, finds its name and the span from where it was - /// declared. - crate fn get_upvar_name_and_span_for_region( - &self, - tcx: TyCtxt<'tcx>, - upvars: &[Upvar<'tcx>], - upvar_index: usize, - ) -> (Symbol, Span) { - let upvar_hir_id = upvars[upvar_index].place.get_root_variable(); - debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id); - - let upvar_name = tcx.hir().name(upvar_hir_id); - let upvar_span = tcx.hir().span(upvar_hir_id); - debug!( - "get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}", - upvar_name, upvar_span - ); - - (upvar_name, upvar_span) - } - - /// Search the argument types for one that references fr (which should be a free region). - /// Returns Some(_) with the index of the input if one is found. - /// - /// N.B., in the case of a closure, the index is indexing into the signature as seen by the - /// user - in particular, index 0 is not the implicit self parameter. - crate fn get_argument_index_for_region( - &self, - tcx: TyCtxt<'tcx>, - fr: RegionVid, - ) -> Option { - let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); - let argument_index = - self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position( - |arg_ty| { - debug!("get_argument_index_for_region: arg_ty = {:?}", arg_ty); - tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr) - }, - )?; - - debug!( - "get_argument_index_for_region: found {:?} in argument {} which has type {:?}", - fr, - argument_index, - self.universal_regions().unnormalized_input_tys[argument_index], - ); - - Some(argument_index) - } - - /// Given the index of an argument, finds its name (if any) and the span from where it was - /// declared. - crate fn get_argument_name_and_span_for_region( - &self, - body: &Body<'tcx>, - local_names: &IndexVec>, - argument_index: usize, - ) -> (Option, Span) { - let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); - let argument_local = Local::new(implicit_inputs + argument_index + 1); - debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local); - - let argument_name = local_names[argument_local]; - let argument_span = body.local_decls[argument_local].source_info.span; - debug!( - "get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}", - argument_name, argument_span - ); - - (argument_name, argument_span) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/facts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/facts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/facts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/facts.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,217 +0,0 @@ -use crate::borrow_check::location::{LocationIndex, LocationTable}; -use crate::dataflow::indexes::{BorrowIndex, MovePathIndex}; -use polonius_engine::AllFacts as PoloniusFacts; -use polonius_engine::Atom; -use rustc_index::vec::Idx; -use rustc_middle::mir::Local; -use rustc_middle::ty::{RegionVid, TyCtxt}; -use std::error::Error; -use std::fmt::Debug; -use std::fs::{self, File}; -use std::io::{BufWriter, Write}; -use std::path::Path; - -#[derive(Copy, Clone, Debug)] -pub struct RustcFacts; - -impl polonius_engine::FactTypes for RustcFacts { - type Origin = RegionVid; - type Loan = BorrowIndex; - type Point = LocationIndex; - type Variable = Local; - type Path = MovePathIndex; -} - -pub type AllFacts = PoloniusFacts; - -crate trait AllFactsExt { - /// Returns `true` if there is a need to gather `AllFacts` given the - /// current `-Z` flags. - fn enabled(tcx: TyCtxt<'_>) -> bool; - - fn write_to_dir( - &self, - dir: impl AsRef, - location_table: &LocationTable, - ) -> Result<(), Box>; -} - -impl AllFactsExt for AllFacts { - /// Return - fn enabled(tcx: TyCtxt<'_>) -> bool { - tcx.sess.opts.debugging_opts.nll_facts || tcx.sess.opts.debugging_opts.polonius - } - - fn write_to_dir( - &self, - dir: impl AsRef, - location_table: &LocationTable, - ) -> Result<(), Box> { - let dir: &Path = dir.as_ref(); - fs::create_dir_all(dir)?; - let wr = FactWriter { location_table, dir }; - macro_rules! write_facts_to_path { - ($wr:ident . write_facts_to_path($this:ident . [ - $($field:ident,)* - ])) => { - $( - $wr.write_facts_to_path( - &$this.$field, - &format!("{}.facts", stringify!($field)) - )?; - )* - } - } - write_facts_to_path! { - wr.write_facts_to_path(self.[ - loan_issued_at, - universal_region, - cfg_edge, - loan_killed_at, - subset_base, - loan_invalidated_at, - var_used_at, - var_defined_at, - var_dropped_at, - use_of_var_derefs_origin, - drop_of_var_derefs_origin, - child_path, - path_is_var, - path_assigned_at_base, - path_moved_at_base, - path_accessed_at_base, - known_placeholder_subset, - placeholder, - ]) - } - Ok(()) - } -} - -impl Atom for BorrowIndex { - fn index(self) -> usize { - Idx::index(self) - } -} - -impl Atom for LocationIndex { - fn index(self) -> usize { - Idx::index(self) - } -} - -impl Atom for MovePathIndex { - fn index(self) -> usize { - Idx::index(self) - } -} - -struct FactWriter<'w> { - location_table: &'w LocationTable, - dir: &'w Path, -} - -impl<'w> FactWriter<'w> { - fn write_facts_to_path(&self, rows: &[T], file_name: &str) -> Result<(), Box> - where - T: FactRow, - { - let file = &self.dir.join(file_name); - let mut file = BufWriter::new(File::create(file)?); - for row in rows { - row.write(&mut file, self.location_table)?; - } - Ok(()) - } -} - -trait FactRow { - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box>; -} - -impl FactRow for RegionVid { - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box> { - write_row(out, location_table, &[self]) - } -} - -impl FactRow for (A, B) -where - A: FactCell, - B: FactCell, -{ - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box> { - write_row(out, location_table, &[&self.0, &self.1]) - } -} - -impl FactRow for (A, B, C) -where - A: FactCell, - B: FactCell, - C: FactCell, -{ - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box> { - write_row(out, location_table, &[&self.0, &self.1, &self.2]) - } -} - -impl FactRow for (A, B, C, D) -where - A: FactCell, - B: FactCell, - C: FactCell, - D: FactCell, -{ - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box> { - write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3]) - } -} - -fn write_row( - out: &mut dyn Write, - location_table: &LocationTable, - columns: &[&dyn FactCell], -) -> Result<(), Box> { - for (index, c) in columns.iter().enumerate() { - let tail = if index == columns.len() - 1 { "\n" } else { "\t" }; - write!(out, "{:?}{}", c.to_string(location_table), tail)?; - } - Ok(()) -} - -trait FactCell { - fn to_string(&self, location_table: &LocationTable) -> String; -} - -impl FactCell for A { - default fn to_string(&self, _location_table: &LocationTable) -> String { - format!("{:?}", self) - } -} - -impl FactCell for LocationIndex { - fn to_string(&self, location_table: &LocationTable) -> String { - format!("{:?}", location_table.to_location(*self)) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/invalidation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/invalidation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/invalidation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/invalidation.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,470 +0,0 @@ -use rustc_data_structures::graph::dominators::Dominators; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue}; -use rustc_middle::mir::{BorrowKind, Mutability, Operand}; -use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; -use rustc_middle::mir::{Statement, StatementKind}; -use rustc_middle::ty::TyCtxt; -use std::iter; - -use crate::dataflow::indexes::BorrowIndex; - -use crate::borrow_check::{ - borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth, - Activation, ArtificialField, Deep, JustWrite, LocalMutationIsAllowed, MutateMode, Read, - ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind, -}; - -pub(super) fn generate_invalidates<'tcx>( - tcx: TyCtxt<'tcx>, - all_facts: &mut Option, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) { - if all_facts.is_none() { - // Nothing to do if we don't have any facts - return; - } - - if let Some(all_facts) = all_facts { - let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); - let dominators = body.dominators(); - let mut ig = InvalidationGenerator { - all_facts, - borrow_set, - tcx, - location_table, - body: &body, - dominators, - }; - ig.visit_body(body); - } -} - -struct InvalidationGenerator<'cx, 'tcx> { - tcx: TyCtxt<'tcx>, - all_facts: &'cx mut AllFacts, - location_table: &'cx LocationTable, - body: &'cx Body<'tcx>, - dominators: Dominators, - borrow_set: &'cx BorrowSet<'tcx>, -} - -/// Visits the whole MIR and generates `invalidates()` facts. -/// Most of the code implementing this was stolen from `borrow_check/mod.rs`. -impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - self.check_activations(location); - - match &statement.kind { - StatementKind::Assign(box (lhs, rhs)) => { - self.consume_rvalue(location, rhs); - - self.mutate_place(location, *lhs, Shallow(None), JustWrite); - } - StatementKind::FakeRead(box (_, _)) => { - // Only relevant for initialized/liveness/safety checks. - } - StatementKind::SetDiscriminant { place, variant_index: _ } => { - self.mutate_place(location, **place, Shallow(None), JustWrite); - } - StatementKind::LlvmInlineAsm(asm) => { - for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) { - if o.is_indirect { - // FIXME(eddyb) indirect inline asm outputs should - // be encoded through MIR place derefs instead. - self.access_place( - location, - *output, - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - ); - } else { - self.mutate_place( - location, - *output, - if o.is_rw { Deep } else { Shallow(None) }, - if o.is_rw { WriteAndRead } else { JustWrite }, - ); - } - } - for (_, input) in asm.inputs.iter() { - self.consume_operand(location, input); - } - } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - ref src, - ref dst, - ref count, - }) => { - self.consume_operand(location, src); - self.consume_operand(location, dst); - self.consume_operand(location, count); - } - StatementKind::Nop - | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Retag { .. } - | StatementKind::StorageLive(..) => { - // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant - // to borrow check. - } - StatementKind::StorageDead(local) => { - self.access_place( - location, - Place::from(*local), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - ); - } - } - - self.super_statement(statement, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.check_activations(location); - - match &terminator.kind { - TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => { - self.consume_operand(location, discr); - } - TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => { - self.access_place( - location, - *drop_place, - (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - ); - } - TerminatorKind::DropAndReplace { - place: drop_place, - value: ref new_value, - target: _, - unwind: _, - } => { - self.mutate_place(location, *drop_place, Deep, JustWrite); - self.consume_operand(location, new_value); - } - TerminatorKind::Call { - ref func, - ref args, - destination, - cleanup: _, - from_hir_call: _, - fn_span: _, - } => { - self.consume_operand(location, func); - for arg in args { - self.consume_operand(location, arg); - } - if let Some((dest, _ /*bb*/)) = destination { - self.mutate_place(location, *dest, Deep, JustWrite); - } - } - TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { - self.consume_operand(location, cond); - use rustc_middle::mir::AssertKind; - if let AssertKind::BoundsCheck { ref len, ref index } = *msg { - self.consume_operand(location, len); - self.consume_operand(location, index); - } - } - TerminatorKind::Yield { ref value, resume, resume_arg, drop: _ } => { - self.consume_operand(location, value); - - // Invalidate all borrows of local places - let borrow_set = self.borrow_set; - let resume = self.location_table.start_index(resume.start_location()); - for (i, data) in borrow_set.iter_enumerated() { - if borrow_of_local_data(data.borrowed_place) { - self.all_facts.loan_invalidated_at.push((resume, i)); - } - } - - self.mutate_place(location, *resume_arg, Deep, JustWrite); - } - TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { - // Invalidate all borrows of local places - let borrow_set = self.borrow_set; - let start = self.location_table.start_index(location); - for (i, data) in borrow_set.iter_enumerated() { - if borrow_of_local_data(data.borrowed_place) { - self.all_facts.loan_invalidated_at.push((start, i)); - } - } - } - TerminatorKind::InlineAsm { - template: _, - ref operands, - options: _, - line_spans: _, - destination: _, - } => { - for op in operands { - match *op { - InlineAsmOperand::In { reg: _, ref value } => { - self.consume_operand(location, value); - } - InlineAsmOperand::Out { reg: _, late: _, place, .. } => { - if let Some(place) = place { - self.mutate_place(location, place, Shallow(None), JustWrite); - } - } - InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { - self.consume_operand(location, in_value); - if let Some(out_place) = out_place { - self.mutate_place(location, out_place, Shallow(None), JustWrite); - } - } - InlineAsmOperand::Const { value: _ } - | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } => {} - } - } - } - TerminatorKind::Goto { target: _ } - | TerminatorKind::Abort - | TerminatorKind::Unreachable - | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } - | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { - // no data used, thus irrelevant to borrowck - } - } - - self.super_terminator(terminator, location); - } -} - -impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { - /// Simulates mutation of a place. - fn mutate_place( - &mut self, - location: Location, - place: Place<'tcx>, - kind: AccessDepth, - _mode: MutateMode, - ) { - self.access_place( - location, - place, - (kind, Write(WriteKind::Mutate)), - LocalMutationIsAllowed::ExceptUpvars, - ); - } - - /// Simulates consumption of an operand. - fn consume_operand(&mut self, location: Location, operand: &Operand<'tcx>) { - match *operand { - Operand::Copy(place) => { - self.access_place( - location, - place, - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - ); - } - Operand::Move(place) => { - self.access_place( - location, - place, - (Deep, Write(WriteKind::Move)), - LocalMutationIsAllowed::Yes, - ); - } - Operand::Constant(_) => {} - } - } - - // Simulates consumption of an rvalue - fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) { - match *rvalue { - Rvalue::Ref(_ /*rgn*/, bk, place) => { - let access_kind = match bk { - BorrowKind::Shallow => { - (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) - } - BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { - let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(bk) { - (Deep, Reservation(wk)) - } else { - (Deep, Write(wk)) - } - } - }; - - self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); - } - - Rvalue::AddressOf(mutability, place) => { - let access_kind = match mutability { - Mutability::Mut => ( - Deep, - Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, - })), - ), - Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), - }; - - self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); - } - - Rvalue::ThreadLocalRef(_) => {} - - Rvalue::Use(ref operand) - | Rvalue::Repeat(ref operand, _) - | Rvalue::UnaryOp(_ /*un_op*/, ref operand) - | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { - self.consume_operand(location, operand) - } - - Rvalue::Len(place) | Rvalue::Discriminant(place) => { - let af = match *rvalue { - Rvalue::Len(..) => Some(ArtificialField::ArrayLength), - Rvalue::Discriminant(..) => None, - _ => unreachable!(), - }; - self.access_place( - location, - place, - (Shallow(af), Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - ); - } - - Rvalue::BinaryOp(_bin_op, box (ref operand1, ref operand2)) - | Rvalue::CheckedBinaryOp(_bin_op, box (ref operand1, ref operand2)) => { - self.consume_operand(location, operand1); - self.consume_operand(location, operand2); - } - - Rvalue::NullaryOp(_op, _ty) => {} - - Rvalue::Aggregate(_, ref operands) => { - for operand in operands { - self.consume_operand(location, operand); - } - } - } - } - - /// Simulates an access to a place. - fn access_place( - &mut self, - location: Location, - place: Place<'tcx>, - kind: (AccessDepth, ReadOrWrite), - _is_local_mutation_allowed: LocalMutationIsAllowed, - ) { - let (sd, rw) = kind; - // note: not doing check_access_permissions checks because they don't generate invalidates - self.check_access_for_conflict(location, place, sd, rw); - } - - fn check_access_for_conflict( - &mut self, - location: Location, - place: Place<'tcx>, - sd: AccessDepth, - rw: ReadOrWrite, - ) { - debug!( - "invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \ - rw={:?})", - location, place, sd, rw, - ); - let tcx = self.tcx; - let body = self.body; - let borrow_set = self.borrow_set; - let indices = self.borrow_set.indices(); - each_borrow_involving_path( - self, - tcx, - body, - location, - (sd, place), - borrow_set, - indices, - |this, borrow_index, borrow| { - match (rw, borrow.kind) { - // Obviously an activation is compatible with its own - // reservation (or even prior activating uses of same - // borrow); so don't check if they interfere. - // - // NOTE: *reservations* do conflict with themselves; - // thus aren't injecting unsoundenss w/ this check.) - (Activation(_, activating), _) if activating == borrow_index => { - // Activating a borrow doesn't generate any invalidations, since we - // have already taken the reservation - } - - (Read(_), BorrowKind::Shallow | BorrowKind::Shared) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => { - // Reads don't invalidate shared or shallow borrows - } - - (Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => { - // Reading from mere reservations of mutable-borrows is OK. - if !is_active(&this.dominators, borrow, location) { - // If the borrow isn't active yet, reads don't invalidate it - assert!(allow_two_phase_borrow(borrow.kind)); - return Control::Continue; - } - - // Unique and mutable borrows are invalidated by reads from any - // involved path - this.emit_loan_invalidated_at(borrow_index, location); - } - - (Reservation(_) | Activation(_, _) | Write(_), _) => { - // unique or mutable borrows are invalidated by writes. - // Reservations count as writes since we need to check - // that activating the borrow will be OK - // FIXME(bob_twinkles) is this actually the right thing to do? - this.emit_loan_invalidated_at(borrow_index, location); - } - } - Control::Continue - }, - ); - } - - /// Generates a new `loan_invalidated_at(L, B)` fact. - fn emit_loan_invalidated_at(&mut self, b: BorrowIndex, l: Location) { - let lidx = self.location_table.start_index(l); - self.all_facts.loan_invalidated_at.push((lidx, b)); - } - - fn check_activations(&mut self, location: Location) { - // Two-phase borrow support: For each activation that is newly - // generated at this statement, check if it interferes with - // another borrow. - for &borrow_index in self.borrow_set.activations_at_location(location) { - let borrow = &self.borrow_set[borrow_index]; - - // only mutable borrows should be 2-phase - assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, - }); - - self.access_place( - location, - borrow.borrowed_place, - (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), - LocalMutationIsAllowed::No, - ); - - // We do not need to call `check_if_path_or_subpath_is_moved` - // again, as we already called it when we made the - // initial reservation. - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/location.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/location.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/location.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/location.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::{BasicBlock, Body, Location}; - -/// Maps between a MIR Location, which identifies a particular -/// statement within a basic block, to a "rich location", which -/// identifies at a finer granularity. In particular, we distinguish -/// the *start* of a statement and the *mid-point*. The mid-point is -/// the point *just* before the statement takes effect; in particular, -/// for an assignment `A = B`, it is the point where B is about to be -/// written into A. This mid-point is a kind of hack to work around -/// our inability to track the position information at sufficient -/// granularity through outlives relations; however, the rich location -/// table serves another purpose: it compresses locations from -/// multiple words into a single u32. -pub struct LocationTable { - num_points: usize, - statements_before_block: IndexVec, -} - -rustc_index::newtype_index! { - pub struct LocationIndex { - DEBUG_FORMAT = "LocationIndex({})" - } -} - -#[derive(Copy, Clone, Debug)] -pub enum RichLocation { - Start(Location), - Mid(Location), -} - -impl LocationTable { - crate fn new(body: &Body<'_>) -> Self { - let mut num_points = 0; - let statements_before_block = body - .basic_blocks() - .iter() - .map(|block_data| { - let v = num_points; - num_points += (block_data.statements.len() + 1) * 2; - v - }) - .collect(); - - debug!("LocationTable(statements_before_block={:#?})", statements_before_block); - debug!("LocationTable: num_points={:#?}", num_points); - - Self { num_points, statements_before_block } - } - - pub fn all_points(&self) -> impl Iterator { - (0..self.num_points).map(LocationIndex::new) - } - - pub fn start_index(&self, location: Location) -> LocationIndex { - let Location { block, statement_index } = location; - let start_index = self.statements_before_block[block]; - LocationIndex::new(start_index + statement_index * 2) - } - - pub fn mid_index(&self, location: Location) -> LocationIndex { - let Location { block, statement_index } = location; - let start_index = self.statements_before_block[block]; - LocationIndex::new(start_index + statement_index * 2 + 1) - } - - pub fn to_location(&self, index: LocationIndex) -> RichLocation { - let point_index = index.index(); - - // Find the basic block. We have a vector with the - // starting index of the statement in each block. Imagine - // we have statement #22, and we have a vector like: - // - // [0, 10, 20] - // - // In that case, this represents point_index 2 of - // basic block BB2. We know this because BB0 accounts for - // 0..10, BB1 accounts for 11..20, and BB2 accounts for - // 20... - // - // To compute this, we could do a binary search, but - // because I am lazy we instead iterate through to find - // the last point where the "first index" (0, 10, or 20) - // was less than the statement index (22). In our case, this will - // be (BB2, 20). - let (block, &first_index) = self - .statements_before_block - .iter_enumerated() - .filter(|(_, first_index)| **first_index <= point_index) - .last() - .unwrap(); - - let statement_index = (point_index - first_index) / 2; - if index.is_start() { - RichLocation::Start(Location { block, statement_index }) - } else { - RichLocation::Mid(Location { block, statement_index }) - } - } -} - -impl LocationIndex { - fn is_start(&self) -> bool { - // even indices are start points; odd indices are mid points - (self.index() % 2) == 0 - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/member_constraints.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/member_constraints.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/member_constraints.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/member_constraints.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,224 +0,0 @@ -use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::IndexVec; -use rustc_middle::infer::MemberConstraint; -use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; -use std::hash::Hash; -use std::ops::Index; - -/// Compactly stores a set of `R0 member of [R1...Rn]` constraints, -/// indexed by the region `R0`. -crate struct MemberConstraintSet<'tcx, R> -where - R: Copy + Eq, -{ - /// Stores the first "member" constraint for a given `R0`. This is an - /// index into the `constraints` vector below. - first_constraints: FxHashMap, - - /// Stores the data about each `R0 member of [R1..Rn]` constraint. - /// These are organized into a linked list, so each constraint - /// contains the index of the next constraint with the same `R0`. - constraints: IndexVec>, - - /// Stores the `R1..Rn` regions for *all* sets. For any given - /// constraint, we keep two indices so that we can pull out a - /// slice. - choice_regions: Vec, -} - -/// Represents a `R0 member of [R1..Rn]` constraint -crate struct NllMemberConstraint<'tcx> { - next_constraint: Option, - - /// The span where the hidden type was instantiated. - crate definition_span: Span, - - /// The hidden type in which `R0` appears. (Used in error reporting.) - crate hidden_ty: Ty<'tcx>, - - /// The region `R0`. - crate member_region_vid: ty::RegionVid, - - /// Index of `R1` in `choice_regions` vector from `MemberConstraintSet`. - start_index: usize, - - /// Index of `Rn` in `choice_regions` vector from `MemberConstraintSet`. - end_index: usize, -} - -rustc_index::newtype_index! { - crate struct NllMemberConstraintIndex { - DEBUG_FORMAT = "MemberConstraintIndex({})" - } -} - -impl Default for MemberConstraintSet<'tcx, ty::RegionVid> { - fn default() -> Self { - Self { - first_constraints: Default::default(), - constraints: Default::default(), - choice_regions: Default::default(), - } - } -} - -impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> { - /// Pushes a member constraint into the set. - /// - /// The input member constraint `m_c` is in the form produced by - /// the `rustc_middle::infer` code. - /// - /// The `to_region_vid` callback fn is used to convert the regions - /// within into `RegionVid` format -- it typically consults the - /// `UniversalRegions` data structure that is known to the caller - /// (but which this code is unaware of). - crate fn push_constraint( - &mut self, - m_c: &MemberConstraint<'tcx>, - mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid, - ) { - debug!("push_constraint(m_c={:?})", m_c); - let member_region_vid: ty::RegionVid = to_region_vid(m_c.member_region); - let next_constraint = self.first_constraints.get(&member_region_vid).cloned(); - let start_index = self.choice_regions.len(); - let end_index = start_index + m_c.choice_regions.len(); - debug!("push_constraint: member_region_vid={:?}", member_region_vid); - let constraint_index = self.constraints.push(NllMemberConstraint { - next_constraint, - member_region_vid, - definition_span: m_c.definition_span, - hidden_ty: m_c.hidden_ty, - start_index, - end_index, - }); - self.first_constraints.insert(member_region_vid, constraint_index); - self.choice_regions.extend(m_c.choice_regions.iter().map(|&r| to_region_vid(r))); - } -} - -impl MemberConstraintSet<'tcx, R1> -where - R1: Copy + Hash + Eq, -{ - /// Remap the "member region" key using `map_fn`, producing a new - /// member constraint set. This is used in the NLL code to map from - /// the original `RegionVid` to an scc index. In some cases, we - /// may have multiple `R1` values mapping to the same `R2` key -- that - /// is ok, the two sets will be merged. - crate fn into_mapped( - self, - mut map_fn: impl FnMut(R1) -> R2, - ) -> MemberConstraintSet<'tcx, R2> - where - R2: Copy + Hash + Eq, - { - // We can re-use most of the original data, just tweaking the - // linked list links a bit. - // - // For example if we had two keys `Ra` and `Rb` that both now - // wind up mapped to the same key `S`, we would append the - // linked list for `Ra` onto the end of the linked list for - // `Rb` (or vice versa) -- this basically just requires - // rewriting the final link from one list to point at the other - // other (see `append_list`). - - let MemberConstraintSet { first_constraints, mut constraints, choice_regions } = self; - - let mut first_constraints2 = FxHashMap::default(); - first_constraints2.reserve(first_constraints.len()); - - for (r1, start1) in first_constraints { - let r2 = map_fn(r1); - if let Some(&start2) = first_constraints2.get(&r2) { - append_list(&mut constraints, start1, start2); - } - first_constraints2.insert(r2, start1); - } - - MemberConstraintSet { first_constraints: first_constraints2, constraints, choice_regions } - } -} - -impl MemberConstraintSet<'tcx, R> -where - R: Copy + Hash + Eq, -{ - crate fn all_indices(&self) -> impl Iterator { - self.constraints.indices() - } - - /// Iterate down the constraint indices associated with a given - /// peek-region. You can then use `choice_regions` and other - /// methods to access data. - crate fn indices( - &self, - member_region_vid: R, - ) -> impl Iterator + '_ { - let mut next = self.first_constraints.get(&member_region_vid).cloned(); - std::iter::from_fn(move || -> Option { - if let Some(current) = next { - next = self.constraints[current].next_constraint; - Some(current) - } else { - None - } - }) - } - - /// Returns the "choice regions" for a given member - /// constraint. This is the `R1..Rn` from a constraint like: - /// - /// ``` - /// R0 member of [R1..Rn] - /// ``` - crate fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] { - let NllMemberConstraint { start_index, end_index, .. } = &self.constraints[pci]; - &self.choice_regions[*start_index..*end_index] - } -} - -impl<'tcx, R> Index for MemberConstraintSet<'tcx, R> -where - R: Copy + Eq, -{ - type Output = NllMemberConstraint<'tcx>; - - fn index(&self, i: NllMemberConstraintIndex) -> &NllMemberConstraint<'tcx> { - &self.constraints[i] - } -} - -/// Given a linked list starting at `source_list` and another linked -/// list starting at `target_list`, modify `target_list` so that it is -/// followed by `source_list`. -/// -/// Before: -/// -/// ``` -/// target_list: A -> B -> C -> (None) -/// source_list: D -> E -> F -> (None) -/// ``` -/// -/// After: -/// -/// ``` -/// target_list: A -> B -> C -> D -> E -> F -> (None) -/// ``` -fn append_list( - constraints: &mut IndexVec>, - target_list: NllMemberConstraintIndex, - source_list: NllMemberConstraintIndex, -) { - let mut p = target_list; - loop { - let mut r = &mut constraints[p]; - match r.next_constraint { - Some(q) => p = q, - None => { - r.next_constraint = Some(source_list); - return; - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2368 +0,0 @@ -//! This query borrow-checks the MIR to (further) ensure it is not broken. - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::graph::dominators::Dominators; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; -use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::Node; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::IndexVec; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_middle::mir::{ - traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, - PlaceRef, VarDebugInfoContents, -}; -use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; -use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; -use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt}; -use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT}; -use rustc_span::{Span, Symbol, DUMMY_SP}; - -use either::Either; -use smallvec::SmallVec; -use std::cell::RefCell; -use std::collections::BTreeMap; -use std::iter; -use std::mem; -use std::rc::Rc; - -use crate::dataflow; -use crate::dataflow::impls::{ - Borrows, EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, -}; -use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex}; -use crate::dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveError}; -use crate::dataflow::MoveDataParamEnv; -use crate::dataflow::{Analysis, BorrowckFlowState as Flows, BorrowckResults}; - -use self::diagnostics::{AccessKind, RegionName}; -use self::location::LocationTable; -use self::prefixes::PrefixSet; -use self::MutateMode::{JustWrite, WriteAndRead}; -use facts::AllFacts; - -use self::path_utils::*; - -mod borrow_set; -mod constraint_generation; -mod constraints; -pub mod consumers; -mod def_use; -mod diagnostics; -mod facts; -mod invalidation; -mod location; -mod member_constraints; -mod nll; -mod path_utils; -mod place_ext; -mod places_conflict; -mod prefixes; -mod region_infer; -mod renumber; -mod type_check; -mod universal_regions; -mod used_muts; - -crate use borrow_set::{BorrowData, BorrowSet}; -crate use nll::{PoloniusOutput, ToRegionVid}; -crate use place_ext::PlaceExt; -crate use places_conflict::{places_conflict, PlaceConflictBias}; -crate use region_infer::RegionInferenceContext; - -// FIXME(eddyb) perhaps move this somewhere more centrally. -#[derive(Debug)] -crate struct Upvar<'tcx> { - place: CapturedPlace<'tcx>, - - /// If true, the capture is behind a reference. - by_ref: bool, -} - -const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref]; - -pub fn provide(providers: &mut Providers) { - *providers = Providers { - mir_borrowck: |tcx, did| { - if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { - tcx.mir_borrowck_const_arg(def) - } else { - mir_borrowck(tcx, ty::WithOptConstParam::unknown(did)) - } - }, - mir_borrowck_const_arg: |tcx, (did, param_did)| { - mir_borrowck(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) - }, - ..*providers - }; -} - -fn mir_borrowck<'tcx>( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, -) -> &'tcx BorrowCheckResult<'tcx> { - let (input_body, promoted) = tcx.mir_promoted(def); - debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); - - let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| { - let input_body: &Body<'_> = &input_body.borrow(); - let promoted: &IndexVec<_, _> = &promoted.borrow(); - do_mir_borrowck(&infcx, input_body, promoted, false).0 - }); - debug!("mir_borrowck done"); - - tcx.arena.alloc(opt_closure_req) -} - -/// Perform the actual borrow checking. -/// -/// If `return_body_with_facts` is true, then return the body with non-erased -/// region ids on which the borrow checking was performed together with Polonius -/// facts. -fn do_mir_borrowck<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - input_body: &Body<'tcx>, - input_promoted: &IndexVec>, - return_body_with_facts: bool, -) -> (BorrowCheckResult<'tcx>, Option>>) { - let def = input_body.source.with_opt_param().as_local().unwrap(); - - debug!("do_mir_borrowck(def = {:?})", def); - - assert!( - !return_body_with_facts || infcx.tcx.sess.opts.debugging_opts.polonius, - "borrowck facts can be requested only when Polonius is enabled" - ); - - let tcx = infcx.tcx; - let param_env = tcx.param_env(def.did); - let id = tcx.hir().local_def_id_to_hir_id(def.did); - - let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); - for var_debug_info in &input_body.var_debug_info { - if let VarDebugInfoContents::Place(place) = var_debug_info.value { - if let Some(local) = place.as_local() { - if let Some(prev_name) = local_names[local] { - if var_debug_info.name != prev_name { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); - } - } - local_names[local] = Some(var_debug_info.name); - } - } - } - - // Gather the upvars of a closure, if any. - let tables = tcx.typeck_opt_const_arg(def); - if let Some(ErrorReported) = tables.tainted_by_errors { - infcx.set_tainted_by_errors(); - } - let upvars: Vec<_> = tables - .closure_min_captures_flattened(def.did.to_def_id()) - .map(|captured_place| { - let capture = captured_place.info.capture_kind; - let by_ref = match capture { - ty::UpvarCapture::ByValue(_) => false, - ty::UpvarCapture::ByRef(..) => true, - }; - Upvar { place: captured_place.clone(), by_ref } - }) - .collect(); - - // Replace all regions with fresh inference variables. This - // requires first making our own copy of the MIR. This copy will - // be modified (in place) to contain non-lexical lifetimes. It - // will have a lifetime tied to the inference context. - let mut body_owned = input_body.clone(); - let mut promoted = input_promoted.clone(); - let free_regions = - nll::replace_regions_in_mir(infcx, param_env, &mut body_owned, &mut promoted); - let body = &body_owned; // no further changes - - let location_table_owned = LocationTable::new(body); - let location_table = &location_table_owned; - - let mut errors_buffer = Vec::new(); - let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) = - match MoveData::gather_moves(&body, tcx, param_env) { - Ok(move_data) => (move_data, Vec::new()), - Err((move_data, move_errors)) => (move_data, move_errors), - }; - let promoted_errors = promoted - .iter_enumerated() - .map(|(idx, body)| (idx, MoveData::gather_moves(&body, tcx, param_env))); - - let mdpe = MoveDataParamEnv { move_data, param_env }; - - let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe) - .into_engine(tcx, &body) - .pass_name("borrowck") - .iterate_to_fixpoint() - .into_results_cursor(&body); - - let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure(); - let borrow_set = - Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); - - // Compute non-lexical lifetimes. - let nll::NllOutput { - regioncx, - opaque_type_values, - polonius_input, - polonius_output, - opt_closure_req, - nll_errors, - } = nll::compute_regions( - infcx, - free_regions, - body, - &promoted, - location_table, - param_env, - &mut flow_inits, - &mdpe.move_data, - &borrow_set, - &upvars, - ); - - // Dump MIR results into a file, if that is enabled. This let us - // write unit-tests, as well as helping with debugging. - nll::dump_mir_results(infcx, &body, ®ioncx, &opt_closure_req); - - // We also have a `#[rustc_regions]` annotation that causes us to dump - // information. - nll::dump_annotation( - infcx, - &body, - ®ioncx, - &opt_closure_req, - &opaque_type_values, - &mut errors_buffer, - ); - - // The various `flow_*` structures can be large. We drop `flow_inits` here - // so it doesn't overlap with the others below. This reduces peak memory - // usage significantly on some benchmarks. - drop(flow_inits); - - let regioncx = Rc::new(regioncx); - - let flow_borrows = Borrows::new(tcx, &body, ®ioncx, &borrow_set) - .into_engine(tcx, &body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe) - .into_engine(tcx, &body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe) - .into_engine(tcx, &body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - - let movable_generator = match tcx.hir().get(id) { - Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(.., Some(hir::Movability::Static)), - .. - }) => false, - _ => true, - }; - - for (idx, move_data_results) in promoted_errors { - let promoted_body = &promoted[idx]; - - if let Err((move_data, move_errors)) = move_data_results { - let mut promoted_mbcx = MirBorrowckCtxt { - infcx, - param_env, - body: promoted_body, - move_data: &move_data, - location_table, // no need to create a real one for the promoted, it is not used - movable_generator, - fn_self_span_reported: Default::default(), - locals_are_invalidated_at_exit, - access_place_error_reported: Default::default(), - reservation_error_reported: Default::default(), - reservation_warnings: Default::default(), - move_error_reported: BTreeMap::new(), - uninitialized_error_reported: Default::default(), - errors_buffer, - regioncx: regioncx.clone(), - used_mut: Default::default(), - used_mut_upvars: SmallVec::new(), - borrow_set: Rc::clone(&borrow_set), - dominators: Dominators::dummy(), // not used - upvars: Vec::new(), - local_names: IndexVec::from_elem(None, &promoted_body.local_decls), - region_names: RefCell::default(), - next_region_name: RefCell::new(1), - polonius_output: None, - }; - promoted_mbcx.report_move_errors(move_errors); - errors_buffer = promoted_mbcx.errors_buffer; - }; - } - - let dominators = body.dominators(); - - let mut mbcx = MirBorrowckCtxt { - infcx, - param_env, - body, - move_data: &mdpe.move_data, - location_table, - movable_generator, - locals_are_invalidated_at_exit, - fn_self_span_reported: Default::default(), - access_place_error_reported: Default::default(), - reservation_error_reported: Default::default(), - reservation_warnings: Default::default(), - move_error_reported: BTreeMap::new(), - uninitialized_error_reported: Default::default(), - errors_buffer, - regioncx: Rc::clone(®ioncx), - used_mut: Default::default(), - used_mut_upvars: SmallVec::new(), - borrow_set: Rc::clone(&borrow_set), - dominators, - upvars, - local_names, - region_names: RefCell::default(), - next_region_name: RefCell::new(1), - polonius_output, - }; - - // Compute and report region errors, if any. - mbcx.report_region_errors(nll_errors); - - let results = BorrowckResults { - ever_inits: flow_ever_inits, - uninits: flow_uninits, - borrows: flow_borrows, - }; - - mbcx.report_move_errors(move_errors); - - dataflow::visit_results( - &body, - traversal::reverse_postorder(&body).map(|(bb, _)| bb), - &results, - &mut mbcx, - ); - - // Convert any reservation warnings into lints. - let reservation_warnings = mem::take(&mut mbcx.reservation_warnings); - for (_, (place, span, location, bk, borrow)) in reservation_warnings { - let mut initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow); - - let scope = mbcx.body.source_info(location).scope; - let lint_root = match &mbcx.body.source_scopes[scope].local_data { - ClearCrossCrate::Set(data) => data.lint_root, - _ => id, - }; - - // Span and message don't matter; we overwrite them below anyway - mbcx.infcx.tcx.struct_span_lint_hir( - MUTABLE_BORROW_RESERVATION_CONFLICT, - lint_root, - DUMMY_SP, - |lint| { - let mut diag = lint.build(""); - - diag.message = initial_diag.styled_message().clone(); - diag.span = initial_diag.span.clone(); - - diag.buffer(&mut mbcx.errors_buffer); - }, - ); - initial_diag.cancel(); - } - - // For each non-user used mutable variable, check if it's been assigned from - // a user-declared local. If so, then put that local into the used_mut set. - // Note that this set is expected to be small - only upvars from closures - // would have a chance of erroneously adding non-user-defined mutable vars - // to the set. - let temporary_used_locals: FxHashSet = mbcx - .used_mut - .iter() - .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable()) - .cloned() - .collect(); - // For the remaining unused locals that are marked as mutable, we avoid linting any that - // were never initialized. These locals may have been removed as unreachable code; or will be - // linted as unused variables. - let unused_mut_locals = - mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect(); - mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals); - - debug!("mbcx.used_mut: {:?}", mbcx.used_mut); - let used_mut = mbcx.used_mut; - for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) { - let local_decl = &mbcx.body.local_decls[local]; - let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data { - ClearCrossCrate::Set(data) => data.lint_root, - _ => continue, - }; - - // Skip over locals that begin with an underscore or have no name - match mbcx.local_names[local] { - Some(name) => { - if name.as_str().starts_with('_') { - continue; - } - } - None => continue, - } - - let span = local_decl.source_info.span; - if span.desugaring_kind().is_some() { - // If the `mut` arises as part of a desugaring, we should ignore it. - continue; - } - - tcx.struct_span_lint_hir(UNUSED_MUT, lint_root, span, |lint| { - let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - lint.build("variable does not need to be mutable") - .span_suggestion_short( - mut_span, - "remove this `mut`", - String::new(), - Applicability::MachineApplicable, - ) - .emit(); - }) - } - - // Buffer any move errors that we collected and de-duplicated. - for (_, (_, diag)) in mbcx.move_error_reported { - diag.buffer(&mut mbcx.errors_buffer); - } - - if !mbcx.errors_buffer.is_empty() { - mbcx.errors_buffer.sort_by_key(|diag| diag.sort_span); - - for diag in mbcx.errors_buffer.drain(..) { - mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag); - } - } - - let result = BorrowCheckResult { - concrete_opaque_types: opaque_type_values, - closure_requirements: opt_closure_req, - used_mut_upvars: mbcx.used_mut_upvars, - }; - - let body_with_facts = if return_body_with_facts { - let output_facts = mbcx.polonius_output.expect("Polonius output was not computed"); - Some(Box::new(BodyWithBorrowckFacts { - body: body_owned, - input_facts: *polonius_input.expect("Polonius input facts were not generated"), - output_facts, - location_table: location_table_owned, - })) - } else { - None - }; - - debug!("do_mir_borrowck: result = {:#?}", result); - - (result, body_with_facts) -} - -/// A `Body` with information computed by the borrow checker. This struct is -/// intended to be consumed by compiler consumers. -/// -/// We need to include the MIR body here because the region identifiers must -/// match the ones in the Polonius facts. -pub struct BodyWithBorrowckFacts<'tcx> { - /// A mir body that contains region identifiers. - pub body: Body<'tcx>, - /// Polonius input facts. - pub input_facts: AllFacts, - /// Polonius output facts. - pub output_facts: Rc, - /// The table that maps Polonius points to locations in the table. - pub location_table: LocationTable, -} - -crate struct MirBorrowckCtxt<'cx, 'tcx> { - crate infcx: &'cx InferCtxt<'cx, 'tcx>, - param_env: ParamEnv<'tcx>, - body: &'cx Body<'tcx>, - move_data: &'cx MoveData<'tcx>, - - /// Map from MIR `Location` to `LocationIndex`; created - /// when MIR borrowck begins. - location_table: &'cx LocationTable, - - movable_generator: bool, - /// This keeps track of whether local variables are free-ed when the function - /// exits even without a `StorageDead`, which appears to be the case for - /// constants. - /// - /// I'm not sure this is the right approach - @eddyb could you try and - /// figure this out? - locals_are_invalidated_at_exit: bool, - /// This field keeps track of when borrow errors are reported in the access_place function - /// so that there is no duplicate reporting. This field cannot also be used for the conflicting - /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion - /// of the `Span` type (while required to mute some errors) stops the muting of the reservation - /// errors. - access_place_error_reported: FxHashSet<(Place<'tcx>, Span)>, - /// This field keeps track of when borrow conflict errors are reported - /// for reservations, so that we don't report seemingly duplicate - /// errors for corresponding activations. - // - // FIXME: ideally this would be a set of `BorrowIndex`, not `Place`s, - // but it is currently inconvenient to track down the `BorrowIndex` - // at the time we detect and report a reservation error. - reservation_error_reported: FxHashSet>, - /// This fields keeps track of the `Span`s that we have - /// used to report extra information for `FnSelfUse`, to avoid - /// unnecessarily verbose errors. - fn_self_span_reported: FxHashSet, - /// Migration warnings to be reported for #56254. We delay reporting these - /// so that we can suppress the warning if there's a corresponding error - /// for the activation of the borrow. - reservation_warnings: - FxHashMap, Span, Location, BorrowKind, BorrowData<'tcx>)>, - /// This field keeps track of move errors that are to be reported for given move indices. - /// - /// There are situations where many errors can be reported for a single move out (see #53807) - /// and we want only the best of those errors. - /// - /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the - /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the - /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once - /// all move errors have been reported, any diagnostics in this map are added to the buffer - /// to be emitted. - /// - /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary - /// when errors in the map are being re-added to the error buffer so that errors with the - /// same primary span come out in a consistent order. - move_error_reported: BTreeMap, (PlaceRef<'tcx>, DiagnosticBuilder<'cx>)>, - /// This field keeps track of errors reported in the checking of uninitialized variables, - /// so that we don't report seemingly duplicate errors. - uninitialized_error_reported: FxHashSet>, - /// Errors to be reported buffer - errors_buffer: Vec, - /// This field keeps track of all the local variables that are declared mut and are mutated. - /// Used for the warning issued by an unused mutable local variable. - used_mut: FxHashSet, - /// If the function we're checking is a closure, then we'll need to report back the list of - /// mutable upvars that have been used. This field keeps track of them. - used_mut_upvars: SmallVec<[Field; 8]>, - /// Region inference context. This contains the results from region inference and lets us e.g. - /// find out which CFG points are contained in each borrow region. - regioncx: Rc>, - - /// The set of borrows extracted from the MIR - borrow_set: Rc>, - - /// Dominators for MIR - dominators: Dominators, - - /// Information about upvars not necessarily preserved in types or MIR - upvars: Vec>, - - /// Names of local (user) variables (extracted from `var_debug_info`). - local_names: IndexVec>, - - /// Record the region names generated for each region in the given - /// MIR def so that we can reuse them later in help/error messages. - region_names: RefCell>, - - /// The counter for generating new region names. - next_region_name: RefCell, - - /// Results of Polonius analysis. - polonius_output: Option>, -} - -// Check that: -// 1. assignments are always made to mutable locations (FIXME: does that still really go here?) -// 2. loans made in overlapping scopes do not conflict -// 3. assignments do not affect things loaned out as immutable -// 4. moves do not affect things loaned out in any way -impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> { - type FlowState = Flows<'cx, 'tcx>; - - fn visit_statement_before_primary_effect( - &mut self, - flow_state: &Flows<'cx, 'tcx>, - stmt: &'cx Statement<'tcx>, - location: Location, - ) { - debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, flow_state); - let span = stmt.source_info.span; - - self.check_activations(location, span, flow_state); - - match &stmt.kind { - StatementKind::Assign(box (lhs, ref rhs)) => { - self.consume_rvalue(location, (rhs, span), flow_state); - - self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state); - } - StatementKind::FakeRead(box (_, ref place)) => { - // Read for match doesn't access any memory and is used to - // assert that a place is safe and live. So we don't have to - // do any checks here. - // - // FIXME: Remove check that the place is initialized. This is - // needed for now because matches don't have never patterns yet. - // So this is the only place we prevent - // let x: !; - // match x {}; - // from compiling. - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - StatementKind::SetDiscriminant { place, variant_index: _ } => { - self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state); - } - StatementKind::LlvmInlineAsm(ref asm) => { - for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) { - if o.is_indirect { - // FIXME(eddyb) indirect inline asm outputs should - // be encoded through MIR place derefs instead. - self.access_place( - location, - (*output, o.span), - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - flow_state, - ); - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (output.as_ref(), o.span), - flow_state, - ); - } else { - self.mutate_place( - location, - (*output, o.span), - if o.is_rw { Deep } else { Shallow(None) }, - if o.is_rw { WriteAndRead } else { JustWrite }, - flow_state, - ); - } - } - for (_, input) in asm.inputs.iter() { - self.consume_operand(location, (input, span), flow_state); - } - } - - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - .. - }) => { - span_bug!( - span, - "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", - ) - } - StatementKind::Nop - | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Retag { .. } - | StatementKind::StorageLive(..) => { - // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant - // to borrow check. - } - StatementKind::StorageDead(local) => { - self.access_place( - location, - (Place::from(*local), span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state, - ); - } - } - } - - fn visit_terminator_before_primary_effect( - &mut self, - flow_state: &Flows<'cx, 'tcx>, - term: &'cx Terminator<'tcx>, - loc: Location, - ) { - debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, flow_state); - let span = term.source_info.span; - - self.check_activations(loc, span, flow_state); - - match term.kind { - TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => { - self.consume_operand(loc, (discr, span), flow_state); - } - TerminatorKind::Drop { place, target: _, unwind: _ } => { - debug!( - "visit_terminator_drop \ - loc: {:?} term: {:?} place: {:?} span: {:?}", - loc, term, place, span - ); - - self.access_place( - loc, - (place, span), - (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state, - ); - } - TerminatorKind::DropAndReplace { - place: drop_place, - value: ref new_value, - target: _, - unwind: _, - } => { - self.mutate_place(loc, (drop_place, span), Deep, JustWrite, flow_state); - self.consume_operand(loc, (new_value, span), flow_state); - } - TerminatorKind::Call { - ref func, - ref args, - ref destination, - cleanup: _, - from_hir_call: _, - fn_span: _, - } => { - self.consume_operand(loc, (func, span), flow_state); - for arg in args { - self.consume_operand(loc, (arg, span), flow_state); - } - if let Some((dest, _ /*bb*/)) = *destination { - self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state); - } - } - TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { - self.consume_operand(loc, (cond, span), flow_state); - use rustc_middle::mir::AssertKind; - if let AssertKind::BoundsCheck { ref len, ref index } = *msg { - self.consume_operand(loc, (len, span), flow_state); - self.consume_operand(loc, (index, span), flow_state); - } - } - - TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => { - self.consume_operand(loc, (value, span), flow_state); - self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state); - } - - TerminatorKind::InlineAsm { - template: _, - ref operands, - options: _, - line_spans: _, - destination: _, - } => { - for op in operands { - match *op { - InlineAsmOperand::In { reg: _, ref value } => { - self.consume_operand(loc, (value, span), flow_state); - } - InlineAsmOperand::Out { reg: _, late: _, place, .. } => { - if let Some(place) = place { - self.mutate_place( - loc, - (place, span), - Shallow(None), - JustWrite, - flow_state, - ); - } - } - InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { - self.consume_operand(loc, (in_value, span), flow_state); - if let Some(out_place) = out_place { - self.mutate_place( - loc, - (out_place, span), - Shallow(None), - JustWrite, - flow_state, - ); - } - } - InlineAsmOperand::Const { value: _ } - | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } => {} - } - } - } - - TerminatorKind::Goto { target: _ } - | TerminatorKind::Abort - | TerminatorKind::Unreachable - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::GeneratorDrop - | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } - | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { - // no data used, thus irrelevant to borrowck - } - } - } - - fn visit_terminator_after_primary_effect( - &mut self, - flow_state: &Flows<'cx, 'tcx>, - term: &'cx Terminator<'tcx>, - loc: Location, - ) { - let span = term.source_info.span; - - match term.kind { - TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => { - if self.movable_generator { - // Look for any active borrows to locals - let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { - let borrow = &borrow_set[i]; - self.check_for_local_borrow(borrow, span); - } - } - } - - TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { - // Returning from the function implicitly kills storage for all locals and statics. - // Often, the storage will already have been killed by an explicit - // StorageDead, but we don't always emit those (notably on unwind paths), - // so this "extra check" serves as a kind of backup. - let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { - let borrow = &borrow_set[i]; - self.check_for_invalidation_at_exit(loc, borrow, span); - } - } - - TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } - | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } - | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::InlineAsm { .. } => {} - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum MutateMode { - JustWrite, - WriteAndRead, -} - -use self::AccessDepth::{Deep, Shallow}; -use self::ReadOrWrite::{Activation, Read, Reservation, Write}; - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ArtificialField { - ArrayLength, - ShallowBorrow, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum AccessDepth { - /// From the RFC: "A *shallow* access means that the immediate - /// fields reached at P are accessed, but references or pointers - /// found within are not dereferenced. Right now, the only access - /// that is shallow is an assignment like `x = ...;`, which would - /// be a *shallow write* of `x`." - Shallow(Option), - - /// From the RFC: "A *deep* access means that all data reachable - /// through the given place may be invalidated or accesses by - /// this action." - Deep, - - /// Access is Deep only when there is a Drop implementation that - /// can reach the data behind the reference. - Drop, -} - -/// Kind of access to a value: read or write -/// (For informational purposes only) -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ReadOrWrite { - /// From the RFC: "A *read* means that the existing data may be - /// read, but will not be changed." - Read(ReadKind), - - /// From the RFC: "A *write* means that the data may be mutated to - /// new values or otherwise invalidated (for example, it could be - /// de-initialized, as in a move operation). - Write(WriteKind), - - /// For two-phase borrows, we distinguish a reservation (which is treated - /// like a Read) from an activation (which is treated like a write), and - /// each of those is furthermore distinguished from Reads/Writes above. - Reservation(WriteKind), - Activation(WriteKind, BorrowIndex), -} - -/// Kind of read access to a value -/// (For informational purposes only) -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ReadKind { - Borrow(BorrowKind), - Copy, -} - -/// Kind of write access to a value -/// (For informational purposes only) -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum WriteKind { - StorageDeadOrDrop, - MutableBorrow(BorrowKind), - Mutate, - Move, -} - -/// When checking permissions for a place access, this flag is used to indicate that an immutable -/// local place can be mutated. -// -// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications: -// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`. -// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and -// `is_declared_mutable()`. -// - Take flow state into consideration in `is_assignable()` for local variables. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum LocalMutationIsAllowed { - Yes, - /// We want use of immutable upvars to cause a "write to immutable upvar" - /// error, not an "reassignment" error. - ExceptUpvars, - No, -} - -#[derive(Copy, Clone, Debug)] -enum InitializationRequiringAction { - Update, - Borrow, - MatchOn, - Use, - Assignment, - PartialAssignment, -} - -struct RootPlace<'tcx> { - place_local: Local, - place_projection: &'tcx [PlaceElem<'tcx>], - is_local_mutation_allowed: LocalMutationIsAllowed, -} - -impl InitializationRequiringAction { - fn as_noun(self) -> &'static str { - match self { - InitializationRequiringAction::Update => "update", - InitializationRequiringAction::Borrow => "borrow", - InitializationRequiringAction::MatchOn => "use", // no good noun - InitializationRequiringAction::Use => "use", - InitializationRequiringAction::Assignment => "assign", - InitializationRequiringAction::PartialAssignment => "assign to part", - } - } - - fn as_verb_in_past_tense(self) -> &'static str { - match self { - InitializationRequiringAction::Update => "updated", - InitializationRequiringAction::Borrow => "borrowed", - InitializationRequiringAction::MatchOn => "matched on", - InitializationRequiringAction::Use => "used", - InitializationRequiringAction::Assignment => "assigned", - InitializationRequiringAction::PartialAssignment => "partially assigned", - } - } -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - fn body(&self) -> &'cx Body<'tcx> { - self.body - } - - /// Checks an access to the given place to see if it is allowed. Examines the set of borrows - /// that are in scope, as well as which paths have been initialized, to ensure that (a) the - /// place is initialized and (b) it is not borrowed in some way that would prevent this - /// access. - /// - /// Returns `true` if an error is reported. - fn access_place( - &mut self, - location: Location, - place_span: (Place<'tcx>, Span), - kind: (AccessDepth, ReadOrWrite), - is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'cx, 'tcx>, - ) { - let (sd, rw) = kind; - - if let Activation(_, borrow_index) = rw { - if self.reservation_error_reported.contains(&place_span.0) { - debug!( - "skipping access_place for activation of invalid reservation \ - place: {:?} borrow_index: {:?}", - place_span.0, borrow_index - ); - return; - } - } - - // Check is_empty() first because it's the common case, and doing that - // way we avoid the clone() call. - if !self.access_place_error_reported.is_empty() - && self.access_place_error_reported.contains(&(place_span.0, place_span.1)) - { - debug!( - "access_place: suppressing error place_span=`{:?}` kind=`{:?}`", - place_span, kind - ); - return; - } - - let mutability_error = self.check_access_permissions( - place_span, - rw, - is_local_mutation_allowed, - flow_state, - location, - ); - let conflict_error = - self.check_access_for_conflict(location, place_span, sd, rw, flow_state); - - if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) { - // Suppress this warning when there's an error being emitted for the - // same borrow: fixing the error is likely to fix the warning. - self.reservation_warnings.remove(&borrow_idx); - } - - if conflict_error || mutability_error { - debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind); - - self.access_place_error_reported.insert((place_span.0, place_span.1)); - } - } - - fn check_access_for_conflict( - &mut self, - location: Location, - place_span: (Place<'tcx>, Span), - sd: AccessDepth, - rw: ReadOrWrite, - flow_state: &Flows<'cx, 'tcx>, - ) -> bool { - debug!( - "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})", - location, place_span, sd, rw, - ); - - let mut error_reported = false; - let tcx = self.infcx.tcx; - let body = self.body; - let borrow_set = self.borrow_set.clone(); - - // Use polonius output if it has been enabled. - let polonius_output = self.polonius_output.clone(); - let borrows_in_scope = if let Some(polonius) = &polonius_output { - let location = self.location_table.start_index(location); - Either::Left(polonius.errors_at(location).iter().copied()) - } else { - Either::Right(flow_state.borrows.iter()) - }; - - each_borrow_involving_path( - self, - tcx, - body, - location, - (sd, place_span.0), - &borrow_set, - borrows_in_scope, - |this, borrow_index, borrow| match (rw, borrow.kind) { - // Obviously an activation is compatible with its own - // reservation (or even prior activating uses of same - // borrow); so don't check if they interfere. - // - // NOTE: *reservations* do conflict with themselves; - // thus aren't injecting unsoundenss w/ this check.) - (Activation(_, activating), _) if activating == borrow_index => { - debug!( - "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \ - skipping {:?} b/c activation of same borrow_index", - place_span, - sd, - rw, - (borrow_index, borrow), - ); - Control::Continue - } - - (Read(_), BorrowKind::Shared | BorrowKind::Shallow) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => Control::Continue, - - (Write(WriteKind::Move), BorrowKind::Shallow) => { - // Handled by initialization checks. - Control::Continue - } - - (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => { - // Reading from mere reservations of mutable-borrows is OK. - if !is_active(&this.dominators, borrow, location) { - assert!(allow_two_phase_borrow(borrow.kind)); - return Control::Continue; - } - - error_reported = true; - match kind { - ReadKind::Copy => { - this.report_use_while_mutably_borrowed(location, place_span, borrow) - .buffer(&mut this.errors_buffer); - } - ReadKind::Borrow(bk) => { - this.report_conflicting_borrow(location, place_span, bk, borrow) - .buffer(&mut this.errors_buffer); - } - } - Control::Break - } - - ( - Reservation(WriteKind::MutableBorrow(bk)), - BorrowKind::Shallow | BorrowKind::Shared, - ) if { tcx.migrate_borrowck() && this.borrow_set.contains(&location) } => { - let bi = this.borrow_set.get_index_of(&location).unwrap(); - debug!( - "recording invalid reservation of place: {:?} with \ - borrow index {:?} as warning", - place_span.0, bi, - ); - // rust-lang/rust#56254 - This was previously permitted on - // the 2018 edition so we emit it as a warning. We buffer - // these sepately so that we only emit a warning if borrow - // checking was otherwise successful. - this.reservation_warnings - .insert(bi, (place_span.0, place_span.1, location, bk, borrow.clone())); - - // Don't suppress actual errors. - Control::Continue - } - - (Reservation(kind) | Activation(kind, _) | Write(kind), _) => { - match rw { - Reservation(..) => { - debug!( - "recording invalid reservation of \ - place: {:?}", - place_span.0 - ); - this.reservation_error_reported.insert(place_span.0); - } - Activation(_, activating) => { - debug!( - "observing check_place for activation of \ - borrow_index: {:?}", - activating - ); - } - Read(..) | Write(..) => {} - } - - error_reported = true; - match kind { - WriteKind::MutableBorrow(bk) => { - this.report_conflicting_borrow(location, place_span, bk, borrow) - .buffer(&mut this.errors_buffer); - } - WriteKind::StorageDeadOrDrop => this - .report_borrowed_value_does_not_live_long_enough( - location, - borrow, - place_span, - Some(kind), - ), - WriteKind::Mutate => { - this.report_illegal_mutation_of_borrowed(location, place_span, borrow) - } - WriteKind::Move => { - this.report_move_out_while_borrowed(location, place_span, borrow) - } - } - Control::Break - } - }, - ); - - error_reported - } - - fn mutate_place( - &mut self, - location: Location, - place_span: (Place<'tcx>, Span), - kind: AccessDepth, - mode: MutateMode, - flow_state: &Flows<'cx, 'tcx>, - ) { - // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd. - match mode { - MutateMode::WriteAndRead => { - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Update, - (place_span.0.as_ref(), place_span.1), - flow_state, - ); - } - MutateMode::JustWrite => { - self.check_if_assigned_path_is_moved(location, place_span, flow_state); - } - } - - // Special case: you can assign an immutable local variable - // (e.g., `x = ...`) so long as it has never been initialized - // before (at this point in the flow). - if let Some(local) = place_span.0.as_local() { - if let Mutability::Not = self.body.local_decls[local].mutability { - // check for reassignments to immutable local variables - self.check_if_reassignment_to_immutable_state( - location, local, place_span, flow_state, - ); - return; - } - } - - // Otherwise, use the normal access permission rules. - self.access_place( - location, - place_span, - (kind, Write(WriteKind::Mutate)), - LocalMutationIsAllowed::No, - flow_state, - ); - } - - fn consume_rvalue( - &mut self, - location: Location, - (rvalue, span): (&'cx Rvalue<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - match *rvalue { - Rvalue::Ref(_ /*rgn*/, bk, place) => { - let access_kind = match bk { - BorrowKind::Shallow => { - (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) - } - BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { - let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(bk) { - (Deep, Reservation(wk)) - } else { - (Deep, Write(wk)) - } - } - }; - - self.access_place( - location, - (place, span), - access_kind, - LocalMutationIsAllowed::No, - flow_state, - ); - - let action = if bk == BorrowKind::Shallow { - InitializationRequiringAction::MatchOn - } else { - InitializationRequiringAction::Borrow - }; - - self.check_if_path_or_subpath_is_moved( - location, - action, - (place.as_ref(), span), - flow_state, - ); - } - - Rvalue::AddressOf(mutability, place) => { - let access_kind = match mutability { - Mutability::Mut => ( - Deep, - Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, - })), - ), - Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), - }; - - self.access_place( - location, - (place, span), - access_kind, - LocalMutationIsAllowed::No, - flow_state, - ); - - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Borrow, - (place.as_ref(), span), - flow_state, - ); - } - - Rvalue::ThreadLocalRef(_) => {} - - Rvalue::Use(ref operand) - | Rvalue::Repeat(ref operand, _) - | Rvalue::UnaryOp(_ /*un_op*/, ref operand) - | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { - self.consume_operand(location, (operand, span), flow_state) - } - - Rvalue::Len(place) | Rvalue::Discriminant(place) => { - let af = match *rvalue { - Rvalue::Len(..) => Some(ArtificialField::ArrayLength), - Rvalue::Discriminant(..) => None, - _ => unreachable!(), - }; - self.access_place( - location, - (place, span), - (Shallow(af), Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - flow_state, - ); - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - - Rvalue::BinaryOp(_bin_op, box (ref operand1, ref operand2)) - | Rvalue::CheckedBinaryOp(_bin_op, box (ref operand1, ref operand2)) => { - self.consume_operand(location, (operand1, span), flow_state); - self.consume_operand(location, (operand2, span), flow_state); - } - - Rvalue::NullaryOp(_op, _ty) => { - // nullary ops take no dynamic input; no borrowck effect. - // - // FIXME: is above actually true? Do we want to track - // the fact that uninitialized data can be created via - // `NullOp::Box`? - } - - Rvalue::Aggregate(ref aggregate_kind, ref operands) => { - // We need to report back the list of mutable upvars that were - // moved into the closure and subsequently used by the closure, - // in order to populate our used_mut set. - match **aggregate_kind { - AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) => { - let BorrowCheckResult { used_mut_upvars, .. } = - self.infcx.tcx.mir_borrowck(def_id.expect_local()); - debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); - for field in used_mut_upvars { - self.propagate_closure_used_mut_upvar(&operands[field.index()]); - } - } - AggregateKind::Adt(..) - | AggregateKind::Array(..) - | AggregateKind::Tuple { .. } => (), - } - - for operand in operands { - self.consume_operand(location, (operand, span), flow_state); - } - } - } - } - - fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { - let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| { - // We have three possibilities here: - // a. We are modifying something through a mut-ref - // b. We are modifying something that is local to our parent - // c. Current body is a nested closure, and we are modifying path starting from - // a Place captured by our parent closure. - - // Handle (c), the path being modified is exactly the path captured by our parent - if let Some(field) = this.is_upvar_field_projection(place.as_ref()) { - this.used_mut_upvars.push(field); - return; - } - - for (place_ref, proj) in place.iter_projections().rev() { - // Handle (a) - if proj == ProjectionElem::Deref { - match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() { - // We aren't modifying a variable directly - ty::Ref(_, _, hir::Mutability::Mut) => return, - - _ => {} - } - } - - // Handle (c) - if let Some(field) = this.is_upvar_field_projection(place_ref) { - this.used_mut_upvars.push(field); - return; - } - } - - // Handle(b) - this.used_mut.insert(place.local); - }; - - // This relies on the current way that by-value - // captures of a closure are copied/moved directly - // when generating MIR. - match *operand { - Operand::Move(place) | Operand::Copy(place) => { - match place.as_local() { - Some(local) if !self.body.local_decls[local].is_user_variable() => { - if self.body.local_decls[local].ty.is_mutable_ptr() { - // The variable will be marked as mutable by the borrow. - return; - } - // This is an edge case where we have a `move` closure - // inside a non-move closure, and the inner closure - // contains a mutation: - // - // let mut i = 0; - // || { move || { i += 1; }; }; - // - // In this case our usual strategy of assuming that the - // variable will be captured by mutable reference is - // wrong, since `i` can be copied into the inner - // closure from a shared reference. - // - // As such we have to search for the local that this - // capture comes from and mark it as being used as mut. - - let temp_mpi = self.move_data.rev_lookup.find_local(local); - let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { - &self.move_data.inits[init_index] - } else { - bug!("temporary should be initialized exactly once") - }; - - let loc = match init.location { - InitLocation::Statement(stmt) => stmt, - _ => bug!("temporary initialized in arguments"), - }; - - let body = self.body; - let bbd = &body[loc.block]; - let stmt = &bbd.statements[loc.statement_index]; - debug!("temporary assigned in: stmt={:?}", stmt); - - if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind - { - propagate_closure_used_mut_place(self, source); - } else { - bug!( - "closures should only capture user variables \ - or references to user variables" - ); - } - } - _ => propagate_closure_used_mut_place(self, place), - } - } - Operand::Constant(..) => {} - } - } - - fn consume_operand( - &mut self, - location: Location, - (operand, span): (&'cx Operand<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - match *operand { - Operand::Copy(place) => { - // copy of place: check if this is "copy of frozen path" - // (FIXME: see check_loans.rs) - self.access_place( - location, - (place, span), - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - flow_state, - ); - - // Finally, check if path was already moved. - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - Operand::Move(place) => { - // move of place: check if this is move of already borrowed path - self.access_place( - location, - (place, span), - (Deep, Write(WriteKind::Move)), - LocalMutationIsAllowed::Yes, - flow_state, - ); - - // Finally, check if path was already moved. - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - Operand::Constant(_) => {} - } - } - - /// Checks whether a borrow of this place is invalidated when the function - /// exits - fn check_for_invalidation_at_exit( - &mut self, - location: Location, - borrow: &BorrowData<'tcx>, - span: Span, - ) { - debug!("check_for_invalidation_at_exit({:?})", borrow); - let place = borrow.borrowed_place; - let mut root_place = PlaceRef { local: place.local, projection: &[] }; - - // FIXME(nll-rfc#40): do more precise destructor tracking here. For now - // we just know that all locals are dropped at function exit (otherwise - // we'll have a memory leak) and assume that all statics have a destructor. - // - // FIXME: allow thread-locals to borrow other thread locals? - - let (might_be_alive, will_be_dropped) = - if self.body.local_decls[root_place.local].is_ref_to_thread_local() { - // Thread-locals might be dropped after the function exits - // We have to dereference the outer reference because - // borrows don't conflict behind shared references. - root_place.projection = DEREF_PROJECTION; - (true, true) - } else { - (false, self.locals_are_invalidated_at_exit) - }; - - if !will_be_dropped { - debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place); - return; - } - - let sd = if might_be_alive { Deep } else { Shallow(None) }; - - if places_conflict::borrow_conflicts_with_place( - self.infcx.tcx, - &self.body, - place, - borrow.kind, - root_place, - sd, - places_conflict::PlaceConflictBias::Overlap, - ) { - debug!("check_for_invalidation_at_exit({:?}): INVALID", place); - // FIXME: should be talking about the region lifetime instead - // of just a span here. - let span = self.infcx.tcx.sess.source_map().end_point(span); - self.report_borrowed_value_does_not_live_long_enough( - location, - borrow, - (place, span), - None, - ) - } - } - - /// Reports an error if this is a borrow of local data. - /// This is called for all Yield expressions on movable generators - fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) { - debug!("check_for_local_borrow({:?})", borrow); - - if borrow_of_local_data(borrow.borrowed_place) { - let err = self.cannot_borrow_across_generator_yield( - self.retrieve_borrow_spans(borrow).var_or_use(), - yield_span, - ); - - err.buffer(&mut self.errors_buffer); - } - } - - fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flows<'cx, 'tcx>) { - // Two-phase borrow support: For each activation that is newly - // generated at this statement, check if it interferes with - // another borrow. - let borrow_set = self.borrow_set.clone(); - for &borrow_index in borrow_set.activations_at_location(location) { - let borrow = &borrow_set[borrow_index]; - - // only mutable borrows should be 2-phase - assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, - }); - - self.access_place( - location, - (borrow.borrowed_place, span), - (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), - LocalMutationIsAllowed::No, - flow_state, - ); - // We do not need to call `check_if_path_or_subpath_is_moved` - // again, as we already called it when we made the - // initial reservation. - } - } - - fn check_if_reassignment_to_immutable_state( - &mut self, - location: Location, - local: Local, - place_span: (Place<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - debug!("check_if_reassignment_to_immutable_state({:?})", local); - - // Check if any of the initializiations of `local` have happened yet: - if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) { - // And, if so, report an error. - let init = &self.move_data.inits[init_index]; - let span = init.span(&self.body); - self.report_illegal_reassignment(location, place_span, span, place_span.0); - } - } - - fn check_if_full_path_is_moved( - &mut self, - location: Location, - desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - let maybe_uninits = &flow_state.uninits; - - // Bad scenarios: - // - // 1. Move of `a.b.c`, use of `a.b.c` - // 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`) - // 3. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with - // partial initialization support, one might have `a.x` - // initialized but not `a.b`. - // - // OK scenarios: - // - // 4. Move of `a.b.c`, use of `a.b.d` - // 5. Uninitialized `a.x`, initialized `a.b`, use of `a.b` - // 6. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b` - // must have been initialized for the use to be sound. - // 7. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - - // The dataflow tracks shallow prefixes distinctly (that is, - // field-accesses on P distinctly from P itself), in order to - // track substructure initialization separately from the whole - // structure. - // - // E.g., when looking at (*a.b.c).d, if the closest prefix for - // which we have a MovePath is `a.b`, then that means that the - // initialization state of `a.b` is all we need to inspect to - // know if `a.b.c` is valid (and from that we infer that the - // dereference and `.d` access is also valid, since we assume - // `a.b.c` is assigned a reference to an initialized and - // well-formed record structure.) - - // Therefore, if we seek out the *closest* prefix for which we - // have a MovePath, that should capture the initialization - // state for the place scenario. - // - // This code covers scenarios 1, 2, and 3. - - debug!("check_if_full_path_is_moved place: {:?}", place_span.0); - let (prefix, mpi) = self.move_path_closest_to(place_span.0); - if maybe_uninits.contains(mpi) { - self.report_use_of_moved_or_uninitialized( - location, - desired_action, - (prefix, place_span.0, place_span.1), - mpi, - ); - } // Only query longest prefix with a MovePath, not further - // ancestors; dataflow recurs on children when parents - // move (to support partial (re)inits). - // - // (I.e., querying parents breaks scenario 7; but may want - // to do such a query based on partial-init feature-gate.) - } - - /// Subslices correspond to multiple move paths, so we iterate through the - /// elements of the base array. For each element we check - /// - /// * Does this element overlap with our slice. - /// * Is any part of it uninitialized. - fn check_if_subslice_element_is_moved( - &mut self, - location: Location, - desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'tcx>, Span), - maybe_uninits: &BitSet, - from: u64, - to: u64, - ) { - if let Some(mpi) = self.move_path_for_place(place_span.0) { - let move_paths = &self.move_data.move_paths; - - let root_path = &move_paths[mpi]; - for (child_mpi, child_move_path) in root_path.children(move_paths) { - let last_proj = child_move_path.place.projection.last().unwrap(); - if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj { - debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`."); - - if (from..to).contains(offset) { - let uninit_child = - self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| { - maybe_uninits.contains(mpi) - }); - - if let Some(uninit_child) = uninit_child { - self.report_use_of_moved_or_uninitialized( - location, - desired_action, - (place_span.0, place_span.0, place_span.1), - uninit_child, - ); - return; // don't bother finding other problems. - } - } - } - } - } - } - - fn check_if_path_or_subpath_is_moved( - &mut self, - location: Location, - desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - let maybe_uninits = &flow_state.uninits; - - // Bad scenarios: - // - // 1. Move of `a.b.c`, use of `a` or `a.b` - // partial initialization support, one might have `a.x` - // initialized but not `a.b`. - // 2. All bad scenarios from `check_if_full_path_is_moved` - // - // OK scenarios: - // - // 3. Move of `a.b.c`, use of `a.b.d` - // 4. Uninitialized `a.x`, initialized `a.b`, use of `a.b` - // 5. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b` - // must have been initialized for the use to be sound. - // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - - self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); - - if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) = - place_span.0.last_projection() - { - let place_ty = place_base.ty(self.body(), self.infcx.tcx); - if let ty::Array(..) = place_ty.ty.kind() { - self.check_if_subslice_element_is_moved( - location, - desired_action, - (place_base, place_span.1), - maybe_uninits, - from, - to, - ); - return; - } - } - - // A move of any shallow suffix of `place` also interferes - // with an attempt to use `place`. This is scenario 3 above. - // - // (Distinct from handling of scenarios 1+2+4 above because - // `place` does not interfere with suffixes of its prefixes, - // e.g., `a.b.c` does not interfere with `a.b.d`) - // - // This code covers scenario 1. - - debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0); - if let Some(mpi) = self.move_path_for_place(place_span.0) { - let uninit_mpi = self - .move_data - .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi)); - - if let Some(uninit_mpi) = uninit_mpi { - self.report_use_of_moved_or_uninitialized( - location, - desired_action, - (place_span.0, place_span.0, place_span.1), - uninit_mpi, - ); - return; // don't bother finding other problems. - } - } - } - - /// Currently MoveData does not store entries for all places in - /// the input MIR. For example it will currently filter out - /// places that are Copy; thus we do not track places of shared - /// reference type. This routine will walk up a place along its - /// prefixes, searching for a foundational place that *is* - /// tracked in the MoveData. - /// - /// An Err result includes a tag indicated why the search failed. - /// Currently this can only occur if the place is built off of a - /// static variable, as we do not track those in the MoveData. - fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) { - match self.move_data.rev_lookup.find(place) { - LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => { - (self.move_data.move_paths[mpi].place.as_ref(), mpi) - } - LookupResult::Parent(None) => panic!("should have move path for every Local"), - } - } - - fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option { - // If returns None, then there is no move path corresponding - // to a direct owner of `place` (which means there is nothing - // that borrowck tracks for its analysis). - - match self.move_data.rev_lookup.find(place) { - LookupResult::Parent(_) => None, - LookupResult::Exact(mpi) => Some(mpi), - } - } - - fn check_if_assigned_path_is_moved( - &mut self, - location: Location, - (place, span): (Place<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - debug!("check_if_assigned_path_is_moved place: {:?}", place); - - // None case => assigning to `x` does not require `x` be initialized. - for (place_base, elem) in place.iter_projections().rev() { - match elem { - ProjectionElem::Index(_/*operand*/) | - ProjectionElem::ConstantIndex { .. } | - // assigning to P[i] requires P to be valid. - ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => - // assigning to (P->variant) is okay if assigning to `P` is okay - // - // FIXME: is this true even if P is an adt with a dtor? - { } - - // assigning to (*P) requires P to be initialized - ProjectionElem::Deref => { - self.check_if_full_path_is_moved( - location, InitializationRequiringAction::Use, - (place_base, span), flow_state); - // (base initialized; no need to - // recur further) - break; - } - - ProjectionElem::Subslice { .. } => { - panic!("we don't allow assignments to subslices, location: {:?}", - location); - } - - ProjectionElem::Field(..) => { - // if type of `P` has a dtor, then - // assigning to `P.f` requires `P` itself - // be already initialized - let tcx = self.infcx.tcx; - let base_ty = place_base.ty(self.body(), tcx).ty; - match base_ty.kind() { - ty::Adt(def, _) if def.has_dtor(tcx) => { - self.check_if_path_or_subpath_is_moved( - location, InitializationRequiringAction::Assignment, - (place_base, span), flow_state); - - // (base initialized; no need to - // recur further) - break; - } - - // Once `let s; s.x = V; read(s.x);`, - // is allowed, remove this match arm. - ty::Adt(..) | ty::Tuple(..) => { - check_parent_of_field(self, location, place_base, span, flow_state); - - // rust-lang/rust#21232, #54499, #54986: during period where we reject - // partial initialization, do not complain about unnecessary `mut` on - // an attempt to do a partial initialization. - self.used_mut.insert(place.local); - } - - _ => {} - } - } - } - } - - fn check_parent_of_field<'cx, 'tcx>( - this: &mut MirBorrowckCtxt<'cx, 'tcx>, - location: Location, - base: PlaceRef<'tcx>, - span: Span, - flow_state: &Flows<'cx, 'tcx>, - ) { - // rust-lang/rust#21232: Until Rust allows reads from the - // initialized parts of partially initialized structs, we - // will, starting with the 2018 edition, reject attempts - // to write to structs that are not fully initialized. - // - // In other words, *until* we allow this: - // - // 1. `let mut s; s.x = Val; read(s.x);` - // - // we will for now disallow this: - // - // 2. `let mut s; s.x = Val;` - // - // and also this: - // - // 3. `let mut s = ...; drop(s); s.x=Val;` - // - // This does not use check_if_path_or_subpath_is_moved, - // because we want to *allow* reinitializations of fields: - // e.g., want to allow - // - // `let mut s = ...; drop(s.x); s.x=Val;` - // - // This does not use check_if_full_path_is_moved on - // `base`, because that would report an error about the - // `base` as a whole, but in this scenario we *really* - // want to report an error about the actual thing that was - // moved, which may be some prefix of `base`. - - // Shallow so that we'll stop at any dereference; we'll - // report errors about issues with such bases elsewhere. - let maybe_uninits = &flow_state.uninits; - - // Find the shortest uninitialized prefix you can reach - // without going over a Deref. - let mut shortest_uninit_seen = None; - for prefix in this.prefixes(base, PrefixSet::Shallow) { - let mpi = match this.move_path_for_place(prefix) { - Some(mpi) => mpi, - None => continue, - }; - - if maybe_uninits.contains(mpi) { - debug!( - "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}", - shortest_uninit_seen, - Some((prefix, mpi)) - ); - shortest_uninit_seen = Some((prefix, mpi)); - } else { - debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi)); - } - } - - if let Some((prefix, mpi)) = shortest_uninit_seen { - // Check for a reassignment into an uninitialized field of a union (for example, - // after a move out). In this case, do not report an error here. There is an - // exception, if this is the first assignment into the union (that is, there is - // no move out from an earlier location) then this is an attempt at initialization - // of the union - we should error in that case. - let tcx = this.infcx.tcx; - if base.ty(this.body(), tcx).ty.is_union() { - if this.move_data.path_map[mpi].iter().any(|moi| { - this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) - }) { - return; - } - } - - this.report_use_of_moved_or_uninitialized( - location, - InitializationRequiringAction::PartialAssignment, - (prefix, base, span), - mpi, - ); - } - } - } - - /// Checks the permissions for the given place and read or write kind - /// - /// Returns `true` if an error is reported. - fn check_access_permissions( - &mut self, - (place, span): (Place<'tcx>, Span), - kind: ReadOrWrite, - is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'cx, 'tcx>, - location: Location, - ) -> bool { - debug!( - "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})", - place, kind, is_local_mutation_allowed - ); - - let error_access; - let the_place_err; - - match kind { - Reservation(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) - | Write(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) => { - let is_local_mutation_allowed = match borrow_kind { - BorrowKind::Unique => LocalMutationIsAllowed::Yes, - BorrowKind::Mut { .. } => is_local_mutation_allowed, - BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), - }; - match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { - Ok(root_place) => { - self.add_used_mut(root_place, flow_state); - return false; - } - Err(place_err) => { - error_access = AccessKind::MutableBorrow; - the_place_err = place_err; - } - } - } - Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { - match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { - Ok(root_place) => { - self.add_used_mut(root_place, flow_state); - return false; - } - Err(place_err) => { - error_access = AccessKind::Mutate; - the_place_err = place_err; - } - } - } - - Reservation( - WriteKind::Move - | WriteKind::StorageDeadOrDrop - | WriteKind::MutableBorrow(BorrowKind::Shared) - | WriteKind::MutableBorrow(BorrowKind::Shallow), - ) - | Write( - WriteKind::Move - | WriteKind::StorageDeadOrDrop - | WriteKind::MutableBorrow(BorrowKind::Shared) - | WriteKind::MutableBorrow(BorrowKind::Shallow), - ) => { - if let (Err(_), true) = ( - self.is_mutable(place.as_ref(), is_local_mutation_allowed), - self.errors_buffer.is_empty(), - ) { - // rust-lang/rust#46908: In pure NLL mode this code path should be - // unreachable, but we use `delay_span_bug` because we can hit this when - // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug` - // enabled. We don't want to ICE for that case, as other errors will have - // been emitted (#52262). - self.infcx.tcx.sess.delay_span_bug( - span, - &format!( - "Accessing `{:?}` with the kind `{:?}` shouldn't be possible", - place, kind, - ), - ); - } - return false; - } - Activation(..) => { - // permission checks are done at Reservation point. - return false; - } - Read( - ReadKind::Borrow( - BorrowKind::Unique - | BorrowKind::Mut { .. } - | BorrowKind::Shared - | BorrowKind::Shallow, - ) - | ReadKind::Copy, - ) => { - // Access authorized - return false; - } - } - - // rust-lang/rust#21232, #54986: during period where we reject - // partial initialization, do not complain about mutability - // errors except for actual mutation (as opposed to an attempt - // to do a partial initialization). - let previously_initialized = - self.is_local_ever_initialized(place.local, flow_state).is_some(); - - // at this point, we have set up the error reporting state. - if previously_initialized { - self.report_mutability_error(place, span, the_place_err, error_access, location); - true - } else { - false - } - } - - fn is_local_ever_initialized( - &self, - local: Local, - flow_state: &Flows<'cx, 'tcx>, - ) -> Option { - let mpi = self.move_data.rev_lookup.find_local(local); - let ii = &self.move_data.init_path_map[mpi]; - for &index in ii { - if flow_state.ever_inits.contains(index) { - return Some(index); - } - } - None - } - - /// Adds the place into the used mutable variables set - fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'cx, 'tcx>) { - match root_place { - RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { - // If the local may have been initialized, and it is now currently being - // mutated, then it is justified to be annotated with the `mut` - // keyword, since the mutation may be a possible reassignment. - if is_local_mutation_allowed != LocalMutationIsAllowed::Yes - && self.is_local_ever_initialized(local, flow_state).is_some() - { - self.used_mut.insert(local); - } - } - RootPlace { - place_local: _, - place_projection: _, - is_local_mutation_allowed: LocalMutationIsAllowed::Yes, - } => {} - RootPlace { - place_local, - place_projection: place_projection @ [.., _], - is_local_mutation_allowed: _, - } => { - if let Some(field) = self.is_upvar_field_projection(PlaceRef { - local: place_local, - projection: place_projection, - }) { - self.used_mut_upvars.push(field); - } - } - } - } - - /// Whether this value can be written or borrowed mutably. - /// Returns the root place if the place passed in is a projection. - fn is_mutable( - &self, - place: PlaceRef<'tcx>, - is_local_mutation_allowed: LocalMutationIsAllowed, - ) -> Result, PlaceRef<'tcx>> { - debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed); - match place.last_projection() { - None => { - let local = &self.body.local_decls[place.local]; - match local.mutability { - Mutability::Not => match is_local_mutation_allowed { - LocalMutationIsAllowed::Yes => Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed: LocalMutationIsAllowed::Yes, - }), - LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars, - }), - LocalMutationIsAllowed::No => Err(place), - }, - Mutability::Mut => Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed, - }), - } - } - Some((place_base, elem)) => { - match elem { - ProjectionElem::Deref => { - let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty; - - // Check the kind of deref to decide - match base_ty.kind() { - ty::Ref(_, _, mutbl) => { - match mutbl { - // Shared borrowed data is never mutable - hir::Mutability::Not => Err(place), - // Mutably borrowed data is mutable, but only if we have a - // unique path to the `&mut` - hir::Mutability::Mut => { - let mode = match self.is_upvar_field_projection(place) { - Some(field) if self.upvars[field.index()].by_ref => { - is_local_mutation_allowed - } - _ => LocalMutationIsAllowed::Yes, - }; - - self.is_mutable(place_base, mode) - } - } - } - ty::RawPtr(tnm) => { - match tnm.mutbl { - // `*const` raw pointers are not mutable - hir::Mutability::Not => Err(place), - // `*mut` raw pointers are always mutable, regardless of - // context. The users have to check by themselves. - hir::Mutability::Mut => Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed, - }), - } - } - // `Box` owns its content, so mutable if its location is mutable - _ if base_ty.is_box() => { - self.is_mutable(place_base, is_local_mutation_allowed) - } - // Deref should only be for reference, pointers or boxes - _ => bug!("Deref of unexpected type: {:?}", base_ty), - } - } - // All other projections are owned by their base path, so mutable if - // base path is mutable - ProjectionElem::Field(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..) => { - let upvar_field_projection = self.is_upvar_field_projection(place); - if let Some(field) = upvar_field_projection { - let upvar = &self.upvars[field.index()]; - debug!( - "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \ - place={:?}, place_base={:?}", - upvar, is_local_mutation_allowed, place, place_base - ); - match (upvar.place.mutability, is_local_mutation_allowed) { - ( - Mutability::Not, - LocalMutationIsAllowed::No - | LocalMutationIsAllowed::ExceptUpvars, - ) => Err(place), - (Mutability::Not, LocalMutationIsAllowed::Yes) - | (Mutability::Mut, _) => { - // Subtle: this is an upvar - // reference, so it looks like - // `self.foo` -- we want to double - // check that the location `*self` - // is mutable (i.e., this is not a - // `Fn` closure). But if that - // check succeeds, we want to - // *blame* the mutability on - // `place` (that is, - // `self.foo`). This is used to - // propagate the info about - // whether mutability declarations - // are used outwards, so that we register - // the outer variable as mutable. Otherwise a - // test like this fails to record the `mut` - // as needed: - // - // ``` - // fn foo(_f: F) { } - // fn main() { - // let var = Vec::new(); - // foo(move || { - // var.push(1); - // }); - // } - // ``` - let _ = - self.is_mutable(place_base, is_local_mutation_allowed)?; - Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed, - }) - } - } - } else { - self.is_mutable(place_base, is_local_mutation_allowed) - } - } - } - } - } - } - - /// If `place` is a field projection, and the field is being projected from a closure type, - /// then returns the index of the field being projected. Note that this closure will always - /// be `self` in the current MIR, because that is the only time we directly access the fields - /// of a closure type. - pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option { - path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body()) - } -} - -/// The degree of overlap between 2 places for borrow-checking. -enum Overlap { - /// The places might partially overlap - in this case, we give - /// up and say that they might conflict. This occurs when - /// different fields of a union are borrowed. For example, - /// if `u` is a union, we have no way of telling how disjoint - /// `u.a.x` and `a.b.y` are. - Arbitrary, - /// The places have the same type, and are either completely disjoint - /// or equal - i.e., they can't "partially" overlap as can occur with - /// unions. This is the "base case" on which we recur for extensions - /// of the place. - EqualOrDisjoint, - /// The places are disjoint, so we know all extensions of them - /// will also be disjoint. - Disjoint, -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/nll.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/nll.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/nll.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/nll.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,460 +0,0 @@ -//! The entry point of the NLL borrow checker. - -use rustc_data_structures::vec_map::VecMap; -use rustc_errors::Diagnostic; -use rustc_index::vec::IndexVec; -use rustc_infer::infer::InferCtxt; -use rustc_middle::mir::{ - BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, - Promoted, -}; -use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty}; -use rustc_span::symbol::sym; -use std::env; -use std::fmt::Debug; -use std::io; -use std::path::PathBuf; -use std::rc::Rc; -use std::str::FromStr; - -use self::mir_util::PassWhere; -use polonius_engine::{Algorithm, Output}; - -use crate::dataflow::impls::MaybeInitializedPlaces; -use crate::dataflow::move_paths::{InitKind, InitLocation, MoveData}; -use crate::dataflow::ResultsCursor; -use crate::util as mir_util; -use crate::util::pretty; - -use crate::borrow_check::{ - borrow_set::BorrowSet, - constraint_generation, - diagnostics::RegionErrors, - facts::{AllFacts, AllFactsExt, RustcFacts}, - invalidation, - location::LocationTable, - region_infer::{values::RegionValueElements, RegionInferenceContext}, - renumber, - type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, - universal_regions::UniversalRegions, - Upvar, -}; - -pub type PoloniusOutput = Output; - -/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any -/// closure requirements to propagate, and any generated errors. -crate struct NllOutput<'tcx> { - pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: VecMap, Ty<'tcx>>, - pub polonius_input: Option>, - pub polonius_output: Option>, - pub opt_closure_req: Option>, - pub nll_errors: RegionErrors<'tcx>, -} - -/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal -/// regions (e.g., region parameters) declared on the function. That set will need to be given to -/// `compute_regions`. -pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body: &mut Body<'tcx>, - promoted: &mut IndexVec>, -) -> UniversalRegions<'tcx> { - let def = body.source.with_opt_param().as_local().unwrap(); - - debug!("replace_regions_in_mir(def={:?})", def); - - // Compute named region information. This also renumbers the inputs/outputs. - let universal_regions = UniversalRegions::new(infcx, def, param_env); - - // Replace all remaining regions with fresh inference variables. - renumber::renumber_mir(infcx, body, promoted); - - mir_util::dump_mir(infcx.tcx, None, "renumber", &0, body, |_, _| Ok(())); - - universal_regions -} - -// This function populates an AllFacts instance with base facts related to -// MovePaths and needed for the move analysis. -fn populate_polonius_move_facts( - all_facts: &mut AllFacts, - move_data: &MoveData<'_>, - location_table: &LocationTable, - body: &Body<'_>, -) { - all_facts - .path_is_var - .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (m, v))); - - for (child, move_path) in move_data.move_paths.iter_enumerated() { - if let Some(parent) = move_path.parent { - all_facts.child_path.push((child, parent)); - } - } - - let fn_entry_start = location_table - .start_index(Location { block: BasicBlock::from_u32(0u32), statement_index: 0 }); - - // initialized_at - for init in move_data.inits.iter() { - match init.location { - InitLocation::Statement(location) => { - let block_data = &body[location.block]; - let is_terminator = location.statement_index == block_data.statements.len(); - - if is_terminator && init.kind == InitKind::NonPanicPathOnly { - // We are at the terminator of an init that has a panic path, - // and where the init should not happen on panic - - for &successor in block_data.terminator().successors() { - if body[successor].is_cleanup { - continue; - } - - // The initialization happened in (or rather, when arriving at) - // the successors, but not in the unwind block. - let first_statement = Location { block: successor, statement_index: 0 }; - all_facts - .path_assigned_at_base - .push((init.path, location_table.start_index(first_statement))); - } - } else { - // In all other cases, the initialization just happens at the - // midpoint, like any other effect. - all_facts - .path_assigned_at_base - .push((init.path, location_table.mid_index(location))); - } - } - // Arguments are initialized on function entry - InitLocation::Argument(local) => { - assert!(body.local_kind(local) == LocalKind::Arg); - all_facts.path_assigned_at_base.push((init.path, fn_entry_start)); - } - } - } - - for (local, &path) in move_data.rev_lookup.iter_locals_enumerated() { - if body.local_kind(local) != LocalKind::Arg { - // Non-arguments start out deinitialised; we simulate this with an - // initial move: - all_facts.path_moved_at_base.push((path, fn_entry_start)); - } - } - - // moved_out_at - // deinitialisation is assumed to always happen! - all_facts - .path_moved_at_base - .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source)))); -} - -/// Computes the (non-lexical) regions from the input MIR. -/// -/// This may result in errors being reported. -pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, - universal_regions: UniversalRegions<'tcx>, - body: &Body<'tcx>, - promoted: &IndexVec>, - location_table: &LocationTable, - param_env: ty::ParamEnv<'tcx>, - flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, - move_data: &MoveData<'tcx>, - borrow_set: &BorrowSet<'tcx>, - upvars: &[Upvar<'tcx>], -) -> NllOutput<'tcx> { - let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default()); - - let universal_regions = Rc::new(universal_regions); - - let elements = &Rc::new(RegionValueElements::new(&body)); - - // Run the MIR type-checker. - let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = - type_check::type_check( - infcx, - param_env, - body, - promoted, - &universal_regions, - location_table, - borrow_set, - &mut all_facts, - flow_inits, - move_data, - elements, - upvars, - ); - - if let Some(all_facts) = &mut all_facts { - let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation"); - all_facts.universal_region.extend(universal_regions.universal_regions()); - populate_polonius_move_facts(all_facts, move_data, location_table, &body); - - // Emit universal regions facts, and their relations, for Polonius. - // - // 1: universal regions are modeled in Polonius as a pair: - // - the universal region vid itself. - // - a "placeholder loan" associated to this universal region. Since they don't exist in - // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index - // added to the existing number of loans, as if they succeeded them in the set. - // - let borrow_count = borrow_set.len(); - debug!( - "compute_regions: polonius placeholders, num_universals={}, borrow_count={}", - universal_regions.len(), - borrow_count - ); - - for universal_region in universal_regions.universal_regions() { - let universal_region_idx = universal_region.index(); - let placeholder_loan_idx = borrow_count + universal_region_idx; - all_facts.placeholder.push((universal_region, placeholder_loan_idx.into())); - } - - // 2: the universal region relations `outlives` constraints are emitted as - // `known_placeholder_subset` facts. - for (fr1, fr2) in universal_region_relations.known_outlives() { - if fr1 != fr2 { - debug!( - "compute_regions: emitting polonius `known_placeholder_subset` \ - fr1={:?}, fr2={:?}", - fr1, fr2 - ); - all_facts.known_placeholder_subset.push((*fr1, *fr2)); - } - } - } - - // Create the region inference context, taking ownership of the - // region inference data that was contained in `infcx`, and the - // base constraints generated by the type-check. - let var_origins = infcx.take_region_var_origins(); - let MirTypeckRegionConstraints { - placeholder_indices, - placeholder_index_to_region: _, - mut liveness_constraints, - outlives_constraints, - member_constraints, - closure_bounds_mapping, - universe_causes, - type_tests, - } = constraints; - let placeholder_indices = Rc::new(placeholder_indices); - - constraint_generation::generate_constraints( - infcx, - &mut liveness_constraints, - &mut all_facts, - location_table, - &body, - borrow_set, - ); - - let mut regioncx = RegionInferenceContext::new( - var_origins, - universal_regions, - placeholder_indices, - universal_region_relations, - outlives_constraints, - member_constraints, - closure_bounds_mapping, - universe_causes, - type_tests, - liveness_constraints, - elements, - ); - - // Generate various additional constraints. - invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set); - - let def_id = body.source.def_id(); - - // Dump facts if requested. - let polonius_output = all_facts.as_ref().and_then(|all_facts| { - if infcx.tcx.sess.opts.debugging_opts.nll_facts { - let def_path = infcx.tcx.def_path(def_id); - let dir_path = PathBuf::from(&infcx.tcx.sess.opts.debugging_opts.nll_facts_dir) - .join(def_path.to_filename_friendly_no_crate()); - all_facts.write_to_dir(dir_path, location_table).unwrap(); - } - - if infcx.tcx.sess.opts.debugging_opts.polonius { - let algorithm = - env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid")); - let algorithm = Algorithm::from_str(&algorithm).unwrap(); - debug!("compute_regions: using polonius algorithm {:?}", algorithm); - let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis"); - Some(Rc::new(Output::compute(&all_facts, algorithm, false))) - } else { - None - } - }); - - // Solve the region constraints. - let (closure_region_requirements, nll_errors) = - regioncx.solve(infcx, &body, polonius_output.clone()); - - if !nll_errors.is_empty() { - // Suppress unhelpful extra errors in `infer_opaque_types`. - infcx.set_tainted_by_errors(); - } - - let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span); - - NllOutput { - regioncx, - opaque_type_values: remapped_opaque_tys, - polonius_input: all_facts.map(Box::new), - polonius_output, - opt_closure_req: closure_region_requirements, - nll_errors, - } -} - -pub(super) fn dump_mir_results<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - body: &Body<'tcx>, - regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option>, -) { - if !mir_util::dump_enabled(infcx.tcx, "nll", body.source.def_id()) { - return; - } - - mir_util::dump_mir(infcx.tcx, None, "nll", &0, body, |pass_where, out| { - match pass_where { - // Before the CFG, dump out the values for each region variable. - PassWhere::BeforeCFG => { - regioncx.dump_mir(infcx.tcx, out)?; - writeln!(out, "|")?; - - if let Some(closure_region_requirements) = closure_region_requirements { - writeln!(out, "| Free Region Constraints")?; - for_each_region_constraint(closure_region_requirements, &mut |msg| { - writeln!(out, "| {}", msg) - })?; - writeln!(out, "|")?; - } - } - - PassWhere::BeforeLocation(_) => {} - - PassWhere::AfterTerminator(_) => {} - - PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {} - } - Ok(()) - }); - - // Also dump the inference graph constraints as a graphviz file. - let _: io::Result<()> = try { - let mut file = - pretty::create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, body.source)?; - regioncx.dump_graphviz_raw_constraints(&mut file)?; - }; - - // Also dump the inference graph constraints as a graphviz file. - let _: io::Result<()> = try { - let mut file = - pretty::create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, body.source)?; - regioncx.dump_graphviz_scc_constraints(&mut file)?; - }; -} - -pub(super) fn dump_annotation<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - body: &Body<'tcx>, - regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option>, - opaque_type_values: &VecMap, Ty<'tcx>>, - errors_buffer: &mut Vec, -) { - let tcx = infcx.tcx; - let base_def_id = tcx.closure_base_def_id(body.source.def_id()); - if !tcx.has_attr(base_def_id, sym::rustc_regions) { - return; - } - - // When the enclosing function is tagged with `#[rustc_regions]`, - // we dump out various bits of state as warnings. This is useful - // for verifying that the compiler is behaving as expected. These - // warnings focus on the closure region requirements -- for - // viewing the intraprocedural state, the -Zdump-mir output is - // better. - - let mut err = if let Some(closure_region_requirements) = closure_region_requirements { - let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "external requirements"); - - regioncx.annotate(tcx, &mut err); - - err.note(&format!( - "number of external vids: {}", - closure_region_requirements.num_external_vids - )); - - // Dump the region constraints we are imposing *between* those - // newly created variables. - for_each_region_constraint(closure_region_requirements, &mut |msg| { - err.note(msg); - Ok(()) - }) - .unwrap(); - - err - } else { - let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements"); - regioncx.annotate(tcx, &mut err); - - err - }; - - if !opaque_type_values.is_empty() { - err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values)); - } - - err.buffer(errors_buffer); -} - -fn for_each_region_constraint( - closure_region_requirements: &ClosureRegionRequirements<'_>, - with_msg: &mut dyn FnMut(&str) -> io::Result<()>, -) -> io::Result<()> { - for req in &closure_region_requirements.outlives_requirements { - let subject: &dyn Debug = match &req.subject { - ClosureOutlivesSubject::Region(subject) => subject, - ClosureOutlivesSubject::Ty(ty) => ty, - }; - with_msg(&format!("where {:?}: {:?}", subject, req.outlived_free_region,))?; - } - Ok(()) -} - -/// Right now, we piggy back on the `ReVar` to store our NLL inference -/// regions. These are indexed with `RegionVid`. This method will -/// assert that the region is a `ReVar` and extract its internal index. -/// This is reasonable because in our MIR we replace all universal regions -/// with inference variables. -pub trait ToRegionVid { - fn to_region_vid(self) -> RegionVid; -} - -impl<'tcx> ToRegionVid for &'tcx RegionKind { - fn to_region_vid(self) -> RegionVid { - if let ty::ReVar(vid) = self { *vid } else { bug!("region is not an ReVar: {:?}", self) } - } -} - -impl ToRegionVid for RegionVid { - fn to_region_vid(self) -> RegionVid { - self - } -} - -crate trait ConstraintDescription { - fn description(&self) -> &'static str; -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/path_utils.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/path_utils.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/path_utils.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/path_utils.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ -use crate::borrow_check::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; -use crate::borrow_check::places_conflict; -use crate::borrow_check::AccessDepth; -use crate::borrow_check::Upvar; -use crate::dataflow::indexes::BorrowIndex; -use rustc_data_structures::graph::dominators::Dominators; -use rustc_middle::mir::BorrowKind; -use rustc_middle::mir::{BasicBlock, Body, Field, Location, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::TyCtxt; - -/// Returns `true` if the borrow represented by `kind` is -/// allowed to be split into separate Reservation and -/// Activation phases. -pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool { - kind.allows_two_phase_borrow() -} - -/// Control for the path borrow checking code -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum Control { - Continue, - Break, -} - -/// Encapsulates the idea of iterating over every borrow that involves a particular path -pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( - s: &mut S, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - _location: Location, - access_place: (AccessDepth, Place<'tcx>), - borrow_set: &BorrowSet<'tcx>, - candidates: I, - mut op: F, -) where - F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control, - I: Iterator, -{ - let (access, place) = access_place; - - // FIXME: analogous code in check_loans first maps `place` to - // its base_path. - - // check for loan restricting path P being used. Accounts for - // borrows of P, P.a.b, etc. - for i in candidates { - let borrowed = &borrow_set[i]; - - if places_conflict::borrow_conflicts_with_place( - tcx, - body, - borrowed.borrowed_place, - borrowed.kind, - place.as_ref(), - access, - places_conflict::PlaceConflictBias::Overlap, - ) { - debug!( - "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", - i, borrowed, place, access - ); - let ctrl = op(s, i, borrowed); - if ctrl == Control::Break { - return; - } - } - } -} - -pub(super) fn is_active<'tcx>( - dominators: &Dominators, - borrow_data: &BorrowData<'tcx>, - location: Location, -) -> bool { - debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location); - - let activation_location = match borrow_data.activation_location { - // If this is not a 2-phase borrow, it is always active. - TwoPhaseActivation::NotTwoPhase => return true, - // And if the unique 2-phase use is not an activation, then it is *never* active. - TwoPhaseActivation::NotActivated => return false, - // Otherwise, we derive info from the activation point `loc`: - TwoPhaseActivation::ActivatedAt(loc) => loc, - }; - - // Otherwise, it is active for every location *except* in between - // the reservation and the activation: - // - // X - // / - // R <--+ Except for this - // / \ | diamond - // \ / | - // A <------+ - // | - // Z - // - // Note that we assume that: - // - the reservation R dominates the activation A - // - the activation A post-dominates the reservation R (ignoring unwinding edges). - // - // This means that there can't be an edge that leaves A and - // comes back into that diamond unless it passes through R. - // - // Suboptimal: In some cases, this code walks the dominator - // tree twice when it only has to be walked once. I am - // lazy. -nmatsakis - - // If dominated by the activation A, then it is active. The - // activation occurs upon entering the point A, so this is - // also true if location == activation_location. - if activation_location.dominates(location, dominators) { - return true; - } - - // The reservation starts *on exiting* the reservation block, - // so check if the location is dominated by R.successor. If so, - // this point falls in between the reservation and location. - let reserve_location = borrow_data.reserve_location.successor_within_block(); - if reserve_location.dominates(location, dominators) { - false - } else { - // Otherwise, this point is outside the diamond, so - // consider the borrow active. This could happen for - // example if the borrow remains active around a loop (in - // which case it would be active also for the point R, - // which would generate an error). - true - } -} - -/// Determines if a given borrow is borrowing local data -/// This is called for all Yield expressions on movable generators -pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool { - // Reborrow of already borrowed data is ignored - // Any errors will be caught on the initial borrow - !place.is_indirect() -} - -/// If `place` is a field projection, and the field is being projected from a closure type, -/// then returns the index of the field being projected. Note that this closure will always -/// be `self` in the current MIR, because that is the only time we directly access the fields -/// of a closure type. -pub(crate) fn is_upvar_field_projection( - tcx: TyCtxt<'tcx>, - upvars: &[Upvar<'tcx>], - place_ref: PlaceRef<'tcx>, - body: &Body<'tcx>, -) -> Option { - let mut place_ref = place_ref; - let mut by_ref = false; - - if let Some((place_base, ProjectionElem::Deref)) = place_ref.last_projection() { - place_ref = place_base; - by_ref = true; - } - - match place_ref.last_projection() { - Some((place_base, ProjectionElem::Field(field, _ty))) => { - let base_ty = place_base.ty(body, tcx).ty; - if (base_ty.is_closure() || base_ty.is_generator()) - && (!by_ref || upvars[field.index()].by_ref) - { - Some(field) - } else { - None - } - } - _ => None, - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/place_ext.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/place_ext.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/place_ext.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/place_ext.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -use crate::borrow_check::borrow_set::LocalsStateAtExit; -use rustc_hir as hir; -use rustc_middle::mir::ProjectionElem; -use rustc_middle::mir::{Body, Mutability, Place}; -use rustc_middle::ty::{self, TyCtxt}; - -/// Extension methods for the `Place` type. -crate trait PlaceExt<'tcx> { - /// Returns `true` if we can safely ignore borrows of this place. - /// This is true whenever there is no action that the user can do - /// to the place `self` that would invalidate the borrow. This is true - /// for borrows of raw pointer dereferents as well as shared references. - fn ignore_borrow( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - locals_state_at_exit: &LocalsStateAtExit, - ) -> bool; -} - -impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { - fn ignore_borrow( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - locals_state_at_exit: &LocalsStateAtExit, - ) -> bool { - // If a local variable is immutable, then we only need to track borrows to guard - // against two kinds of errors: - // * The variable being dropped while still borrowed (e.g., because the fn returns - // a reference to a local variable) - // * The variable being moved while still borrowed - // - // In particular, the variable cannot be mutated -- the "access checks" will fail -- - // so we don't have to worry about mutation while borrowed. - if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } = - locals_state_at_exit - { - let ignore = !has_storage_dead_or_moved.contains(self.local) - && body.local_decls[self.local].mutability == Mutability::Not; - debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore); - if ignore { - return true; - } - } - - for (i, elem) in self.projection.iter().enumerate() { - let proj_base = &self.projection[..i]; - - if elem == ProjectionElem::Deref { - let ty = Place::ty_from(self.local, proj_base, body, tcx).ty; - match ty.kind() { - ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { - // For references to thread-local statics, we do need - // to track the borrow. - if body.local_decls[self.local].is_ref_to_thread_local() { - continue; - } - return true; - } - ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Not) => { - // For both derefs of raw pointers and `&T` - // references, the original path is `Copy` and - // therefore not significant. In particular, - // there is nothing the user can do to the - // original path that would invalidate the - // newly created reference -- and if there - // were, then the user could have copied the - // original path into a new variable and - // borrowed *that* one, leaving the original - // path unborrowed. - return true; - } - _ => {} - } - } - } - - false - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/places_conflict.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/places_conflict.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/places_conflict.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/places_conflict.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,539 +0,0 @@ -use crate::borrow_check::ArtificialField; -use crate::borrow_check::Overlap; -use crate::borrow_check::{AccessDepth, Deep, Shallow}; -use rustc_hir as hir; -use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, TyCtxt}; -use std::cmp::max; -use std::iter; - -/// When checking if a place conflicts with another place, this enum is used to influence decisions -/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`. -/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these -/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate -/// being run in the calling context, the conservative choice is to assume the compared indices -/// are disjoint (and therefore, do not overlap). -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -crate enum PlaceConflictBias { - Overlap, - NoOverlap, -} - -/// Helper function for checking if places conflict with a mutable borrow and deep access depth. -/// This is used to check for places conflicting outside of the borrow checking code (such as in -/// dataflow). -crate fn places_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - access_place: Place<'tcx>, - bias: PlaceConflictBias, -) -> bool { - borrow_conflicts_with_place( - tcx, - body, - borrow_place, - BorrowKind::Mut { allow_two_phase_borrow: true }, - access_place.as_ref(), - AccessDepth::Deep, - bias, - ) -} - -/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and -/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime -/// array indices, for example) should be interpreted - this depends on what the caller wants in -/// order to make the conservative choice and preserve soundness. -pub(super) fn borrow_conflicts_with_place<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - borrow_kind: BorrowKind, - access_place: PlaceRef<'tcx>, - access: AccessDepth, - bias: PlaceConflictBias, -) -> bool { - debug!( - "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})", - borrow_place, access_place, access, bias, - ); - - // This Local/Local case is handled by the more general code below, but - // it's so common that it's a speed win to check for it first. - if let Some(l1) = borrow_place.as_local() { - if let Some(l2) = access_place.as_local() { - return l1 == l2; - } - } - - place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias) -} - -fn place_components_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - borrow_kind: BorrowKind, - access_place: PlaceRef<'tcx>, - access: AccessDepth, - bias: PlaceConflictBias, -) -> bool { - // The borrowck rules for proving disjointness are applied from the "root" of the - // borrow forwards, iterating over "similar" projections in lockstep until - // we can prove overlap one way or another. Essentially, we treat `Overlap` as - // a monoid and report a conflict if the product ends up not being `Disjoint`. - // - // At each step, if we didn't run out of borrow or place, we know that our elements - // have the same type, and that they only overlap if they are the identical. - // - // For example, if we are comparing these: - // BORROW: (*x1[2].y).z.a - // ACCESS: (*x1[i].y).w.b - // - // Then our steps are: - // x1 | x1 -- places are the same - // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ) - // x1[2].y | x1[i].y -- equal or disjoint - // *x1[2].y | *x1[i].y -- equal or disjoint - // (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more! - // - // Because `zip` does potentially bad things to the iterator inside, this loop - // also handles the case where the access might be a *prefix* of the borrow, e.g. - // - // BORROW: (*x1[2].y).z.a - // ACCESS: x1[i].y - // - // Then our steps are: - // x1 | x1 -- places are the same - // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ) - // x1[2].y | x1[i].y -- equal or disjoint - // - // -- here we run out of access - the borrow can access a part of it. If this - // is a full deep access, then we *know* the borrow conflicts with it. However, - // if the access is shallow, then we can proceed: - // - // x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we - // are disjoint - // - // Our invariant is, that at each step of the iteration: - // - If we didn't run out of access to match, our borrow and access are comparable - // and either equal or disjoint. - // - If we did run out of access, the borrow can access a part of it. - - let borrow_local = borrow_place.local; - let access_local = access_place.local; - - match place_base_conflict(borrow_local, access_local) { - Overlap::Arbitrary => { - bug!("Two base can't return Arbitrary"); - } - Overlap::EqualOrDisjoint => { - // This is the recursive case - proceed to the next element. - } - Overlap::Disjoint => { - // We have proven the borrow disjoint - further - // projections will remain disjoint. - debug!("borrow_conflicts_with_place: disjoint"); - return false; - } - } - - // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - for (i, (borrow_c, &access_c)) in - iter::zip(borrow_place.projection, access_place.projection).enumerate() - { - debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); - let borrow_proj_base = &borrow_place.projection[..i]; - - debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); - - // Borrow and access path both have more components. - // - // Examples: - // - // - borrow of `a.(...)`, access to `a.(...)` - // - borrow of `a.(...)`, access to `b.(...)` - // - // Here we only see the components we have checked so - // far (in our examples, just the first component). We - // check whether the components being borrowed vs - // accessed are disjoint (as in the second example, - // but not the first). - match place_projection_conflict( - tcx, - body, - borrow_local, - borrow_proj_base, - borrow_c, - access_c, - bias, - ) { - Overlap::Arbitrary => { - // We have encountered different fields of potentially - // the same union - the borrow now partially overlaps. - // - // There is no *easy* way of comparing the fields - // further on, because they might have different types - // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and - // `.y` come from different structs). - // - // We could try to do some things here - e.g., count - // dereferences - but that's probably not a good - // idea, at least for now, so just give up and - // report a conflict. This is unsafe code anyway so - // the user could always use raw pointers. - debug!("borrow_conflicts_with_place: arbitrary -> conflict"); - return true; - } - Overlap::EqualOrDisjoint => { - // This is the recursive case - proceed to the next element. - } - Overlap::Disjoint => { - // We have proven the borrow disjoint - further - // projections will remain disjoint. - debug!("borrow_conflicts_with_place: disjoint"); - return false; - } - } - } - - if borrow_place.projection.len() > access_place.projection.len() { - for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate() - { - // Borrow path is longer than the access path. Examples: - // - // - borrow of `a.b.c`, access to `a.b` - // - // Here, we know that the borrow can access a part of - // our place. This is a conflict if that is a part our - // access cares about. - - let proj_base = &borrow_place.projection[..access_place.projection.len() + i]; - let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty; - - match (elem, &base_ty.kind(), access) { - (_, _, Shallow(Some(ArtificialField::ArrayLength))) - | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { - // The array length is like additional fields on the - // type; it does not overlap any existing data there. - // Furthermore, if cannot actually be a prefix of any - // borrowed place (at least in MIR as it is currently.) - // - // e.g., a (mutable) borrow of `a[5]` while we read the - // array length of `a`. - debug!("borrow_conflicts_with_place: implicit field"); - return false; - } - - (ProjectionElem::Deref, _, Shallow(None)) => { - // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some - // prefix thereof - the shallow access can't touch anything behind - // the pointer. - debug!("borrow_conflicts_with_place: shallow access behind ptr"); - return false; - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Not), _) => { - // Shouldn't be tracked - bug!("Tracking borrow behind shared reference."); - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Mut), AccessDepth::Drop) => { - // Values behind a mutable reference are not access either by dropping a - // value, or by StorageDead - debug!("borrow_conflicts_with_place: drop access behind ptr"); - return false; - } - - (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { - // Drop can read/write arbitrary projections, so places - // conflict regardless of further projections. - if def.has_dtor(tcx) { - return true; - } - } - - (ProjectionElem::Deref, _, Deep) - | (ProjectionElem::Deref, _, AccessDepth::Drop) - | (ProjectionElem::Field { .. }, _, _) - | (ProjectionElem::Index { .. }, _, _) - | (ProjectionElem::ConstantIndex { .. }, _, _) - | (ProjectionElem::Subslice { .. }, _, _) - | (ProjectionElem::Downcast { .. }, _, _) => { - // Recursive case. This can still be disjoint on a - // further iteration if this a shallow access and - // there's a deref later on, e.g., a borrow - // of `*x.y` while accessing `x`. - } - } - } - } - - // Borrow path ran out but access path may not - // have. Examples: - // - // - borrow of `a.b`, access to `a.b.c` - // - borrow of `a.b`, access to `a.b` - // - // In the first example, where we didn't run out of - // access, the borrow can access all of our place, so we - // have a conflict. - // - // If the second example, where we did, then we still know - // that the borrow can access a *part* of our place that - // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Shallow - && borrow_place.projection.len() < access_place.projection.len() - { - debug!("borrow_conflicts_with_place: shallow borrow"); - false - } else { - debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); - true - } -} - -// Given that the bases of `elem1` and `elem2` are always either equal -// or disjoint (and have the same type!), return the overlap situation -// between `elem1` and `elem2`. -fn place_base_conflict(l1: Local, l2: Local) -> Overlap { - if l1 == l2 { - // the same local - base case, equal - debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL"); - Overlap::EqualOrDisjoint - } else { - // different locals - base case, disjoint - debug!("place_element_conflict: DISJOINT-LOCAL"); - Overlap::Disjoint - } -} - -// Given that the bases of `elem1` and `elem2` are always either equal -// or disjoint (and have the same type!), return the overlap situation -// between `elem1` and `elem2`. -fn place_projection_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - pi1_local: Local, - pi1_proj_base: &[PlaceElem<'tcx>], - pi1_elem: PlaceElem<'tcx>, - pi2_elem: PlaceElem<'tcx>, - bias: PlaceConflictBias, -) -> Overlap { - match (pi1_elem, pi2_elem) { - (ProjectionElem::Deref, ProjectionElem::Deref) => { - // derefs (e.g., `*x` vs. `*x`) - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); - Overlap::EqualOrDisjoint - } - (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { - if f1 == f2 { - // same field (e.g., `a.y` vs. `a.y`) - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint - } else { - let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; - if ty.is_union() { - // Different fields of a union, we are basically stuck. - debug!("place_element_conflict: STUCK-UNION"); - Overlap::Arbitrary - } else { - // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } - } - } - (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => { - // different variants are treated as having disjoint fields, - // even if they occupy the same "space", because it's - // impossible for 2 variants of the same enum to exist - // (and therefore, to be borrowed) at the same time. - // - // Note that this is different from unions - we *do* allow - // this code to compile: - // - // ``` - // fn foo(x: &mut Result) { - // let mut v = None; - // if let Ok(ref mut a) = *x { - // v = Some(a); - // } - // // here, you would *think* that the - // // *entirety* of `x` would be borrowed, - // // but in fact only the `Ok` variant is, - // // so the `Err` variant is *entirely free*: - // if let Err(ref mut a) = *x { - // v = Some(a); - // } - // drop(v); - // } - // ``` - if v1 == v2 { - debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } - } - ( - ProjectionElem::Index(..), - ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. }, - ) - | ( - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }, - ProjectionElem::Index(..), - ) => { - // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint - // (if the indexes differ) or equal (if they are the same). - match bias { - PlaceConflictBias::Overlap => { - // If we are biased towards overlapping, then this is the recursive - // case that gives "equal *or* disjoint" its meaning. - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); - Overlap::EqualOrDisjoint - } - PlaceConflictBias::NoOverlap => { - // If we are biased towards no overlapping, then this is disjoint. - debug!("place_element_conflict: DISJOINT-ARRAY-INDEX"); - Overlap::Disjoint - } - } - } - ( - ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false }, - ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false }, - ) - | ( - ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true }, - ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: true }, - ) => { - if o1 == o2 { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { - offset: offset_from_begin, - min_length: min_length1, - from_end: false, - }, - ProjectionElem::ConstantIndex { - offset: offset_from_end, - min_length: min_length2, - from_end: true, - }, - ) - | ( - ProjectionElem::ConstantIndex { - offset: offset_from_end, - min_length: min_length1, - from_end: true, - }, - ProjectionElem::ConstantIndex { - offset: offset_from_begin, - min_length: min_length2, - from_end: false, - }, - ) => { - // both patterns matched so it must be at least the greater of the two - let min_length = max(min_length1, min_length2); - // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last - // element (like -1 in Python) and `min_length` the first. - // Therefore, `min_length - offset_from_end` gives the minimal possible - // offset from the beginning - if offset_from_begin >= min_length - offset_from_end { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ProjectionElem::Subslice { from, to, from_end: false }, - ) - | ( - ProjectionElem::Subslice { from, to, from_end: false }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ) => { - if (from..to).contains(&offset) { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ProjectionElem::Subslice { from, .. }, - ) - | ( - ProjectionElem::Subslice { from, .. }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ) => { - if offset >= from { - debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, - ProjectionElem::Subslice { to, from_end: true, .. }, - ) - | ( - ProjectionElem::Subslice { to, from_end: true, .. }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, - ) => { - if offset > to { - debug!( - "place_element_conflict: \ - DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE" - ); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::Subslice { from: f1, to: t1, from_end: false }, - ProjectionElem::Subslice { from: f2, to: t2, from_end: false }, - ) => { - if f2 >= t1 || f1 >= t2 { - debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES"); - Overlap::Disjoint - } else { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); - Overlap::EqualOrDisjoint - } - } - (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { - debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES"); - Overlap::EqualOrDisjoint - } - ( - ProjectionElem::Deref - | ProjectionElem::Field(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..), - _, - ) => bug!( - "mismatched projections in place_element_conflict: {:?} and {:?}", - pi1_elem, - pi2_elem - ), - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/prefixes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/prefixes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/prefixes.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/prefixes.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -//! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an -//! place are formed by stripping away fields and derefs, except that -//! we stop when we reach the deref of a shared reference. [...] " -//! -//! "Shallow prefixes are found by stripping away fields, but stop at -//! any dereference. So: writing a path like `a` is illegal if `a.b` -//! is borrowed. But: writing `a` is legal if `*a` is borrowed, -//! whether or not `a` is a shared or mutable reference. [...] " - -use super::MirBorrowckCtxt; - -use rustc_hir as hir; -use rustc_middle::mir::{Body, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, TyCtxt}; - -pub trait IsPrefixOf<'tcx> { - fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool; -} - -impl<'tcx> IsPrefixOf<'tcx> for PlaceRef<'tcx> { - fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool { - self.local == other.local - && self.projection.len() <= other.projection.len() - && self.projection == &other.projection[..self.projection.len()] - } -} - -pub(super) struct Prefixes<'cx, 'tcx> { - body: &'cx Body<'tcx>, - tcx: TyCtxt<'tcx>, - kind: PrefixSet, - next: Option>, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum PrefixSet { - /// Doesn't stop until it returns the base case (a Local or - /// Static prefix). - All, - /// Stops at any dereference. - Shallow, - /// Stops at the deref of a shared reference. - Supporting, -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Returns an iterator over the prefixes of `place` - /// (inclusive) from longest to smallest, potentially - /// terminating the iteration early based on `kind`. - pub(super) fn prefixes( - &self, - place_ref: PlaceRef<'tcx>, - kind: PrefixSet, - ) -> Prefixes<'cx, 'tcx> { - Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx } - } -} - -impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { - type Item = PlaceRef<'tcx>; - fn next(&mut self) -> Option { - let mut cursor = self.next?; - - // Post-processing `place`: Enqueue any remaining - // work. Also, `place` may not be a prefix itself, but - // may hold one further down (e.g., we never return - // downcasts here, but may return a base of a downcast). - - 'cursor: loop { - match cursor.last_projection() { - None => { - self.next = None; - return Some(cursor); - } - Some((cursor_base, elem)) => { - match elem { - ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { - // FIXME: add union handling - self.next = Some(cursor_base); - return Some(cursor); - } - ProjectionElem::Downcast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Index(_) => { - cursor = cursor_base; - continue 'cursor; - } - ProjectionElem::Deref => { - // (handled below) - } - } - - assert_eq!(elem, ProjectionElem::Deref); - - match self.kind { - PrefixSet::Shallow => { - // Shallow prefixes are found by stripping away - // fields, but stop at *any* dereference. - // So we can just stop the traversal now. - self.next = None; - return Some(cursor); - } - PrefixSet::All => { - // All prefixes: just blindly enqueue the base - // of the projection. - self.next = Some(cursor_base); - return Some(cursor); - } - PrefixSet::Supporting => { - // Fall through! - } - } - - assert_eq!(self.kind, PrefixSet::Supporting); - // Supporting prefixes: strip away fields and - // derefs, except we stop at the deref of a shared - // reference. - - let ty = cursor_base.ty(self.body, self.tcx).ty; - match ty.kind() { - ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => { - // don't continue traversing over derefs of raw pointers or shared - // borrows. - self.next = None; - return Some(cursor); - } - - ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => { - self.next = Some(cursor_base); - return Some(cursor); - } - - ty::Adt(..) if ty.is_box() => { - self.next = Some(cursor_base); - return Some(cursor); - } - - _ => panic!("unknown type fed to Projection Deref."), - } - } - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -//! As part of generating the regions, if you enable `-Zdump-mir=nll`, -//! we will generate an annotated copy of the MIR that includes the -//! state of region inference. This code handles emitting the region -//! context internal state. - -use super::{OutlivesConstraint, RegionInferenceContext}; -use crate::borrow_check::type_check::Locations; -use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_middle::ty::TyCtxt; -use std::io::{self, Write}; - -// Room for "'_#NNNNr" before things get misaligned. -// Easy enough to fix if this ever doesn't seem like -// enough. -const REGION_WIDTH: usize = 8; - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Write out our state into the `.mir` files. - pub(crate) fn dump_mir(&self, tcx: TyCtxt<'tcx>, out: &mut dyn Write) -> io::Result<()> { - writeln!(out, "| Free Region Mapping")?; - - for region in self.regions() { - if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin { - let classification = self.universal_regions.region_classification(region).unwrap(); - let outlived_by = self.universal_region_relations.regions_outlived_by(region); - writeln!( - out, - "| {r:rw$?} | {c:cw$?} | {ob:?}", - r = region, - rw = REGION_WIDTH, - c = classification, - cw = 8, // "External" at most - ob = outlived_by - )?; - } - } - - writeln!(out, "|")?; - writeln!(out, "| Inferred Region Values")?; - for region in self.regions() { - writeln!( - out, - "| {r:rw$?} | {ui:4?} | {v}", - r = region, - rw = REGION_WIDTH, - ui = self.region_universe(region), - v = self.region_value_str(region), - )?; - } - - writeln!(out, "|")?; - writeln!(out, "| Inference Constraints")?; - self.for_each_constraint(tcx, &mut |msg| writeln!(out, "| {}", msg))?; - - Ok(()) - } - - /// Debugging aid: Invokes the `with_msg` callback repeatedly with - /// our internal region constraints. These are dumped into the - /// -Zdump-mir file so that we can figure out why the region - /// inference resulted in the values that it did when debugging. - fn for_each_constraint( - &self, - tcx: TyCtxt<'tcx>, - with_msg: &mut dyn FnMut(&str) -> io::Result<()>, - ) -> io::Result<()> { - for region in self.definitions.indices() { - let value = self.liveness_constraints.region_value_str(region); - if value != "{}" { - with_msg(&format!("{:?} live at {}", region, value))?; - } - } - - let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); - constraints.sort(); - for constraint in &constraints { - let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint; - let (name, arg) = match locations { - Locations::All(span) => { - ("All", tcx.sess.source_map().span_to_embeddable_string(*span)) - } - Locations::Single(loc) => ("Single", format!("{:?}", loc)), - }; - with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?; - } - - Ok(()) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -//! This module provides linkage between RegionInferenceContext and -//! `rustc_graphviz` traits, specialized to attaching borrowck analysis -//! data to rendered labels. - -use std::borrow::Cow; -use std::io::{self, Write}; - -use super::*; -use crate::borrow_check::constraints::OutlivesConstraint; -use rustc_graphviz as dot; - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Write out the region constraint graph. - crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { - dot::render(&RawConstraints { regioncx: self }, &mut w) - } - - /// Write out the region constraint graph. - crate fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { - let mut nodes_per_scc: IndexVec = - self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect(); - - for region in self.definitions.indices() { - let scc = self.constraint_sccs.scc(region); - nodes_per_scc[scc].push(region); - } - - dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w) - } -} - -struct RawConstraints<'a, 'tcx> { - regioncx: &'a RegionInferenceContext<'tcx>, -} - -impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { - type Node = RegionVid; - type Edge = OutlivesConstraint<'tcx>; - - fn graph_id(&'this self) -> dot::Id<'this> { - dot::Id::new("RegionInferenceContext").unwrap() - } - fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> { - dot::Id::new(format!("r{}", n.index())).unwrap() - } - fn node_shape(&'this self, _node: &RegionVid) -> Option> { - Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) - } - fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { - dot::LabelText::LabelStr(format!("{:?}", n).into()) - } - fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> { - dot::LabelText::LabelStr(format!("{:?}", e.locations).into()) - } -} - -impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { - type Node = RegionVid; - type Edge = OutlivesConstraint<'tcx>; - - fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> { - let vids: Vec = self.regioncx.definitions.indices().collect(); - vids.into() - } - fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> { - (&self.regioncx.constraints.outlives().raw[..]).into() - } - - // Render `a: b` as `a -> b`, indicating the flow - // of data during inference. - - fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { - edge.sup - } - - fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { - edge.sub - } -} - -struct SccConstraints<'a, 'tcx> { - regioncx: &'a RegionInferenceContext<'tcx>, - nodes_per_scc: IndexVec>, -} - -impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { - type Node = ConstraintSccIndex; - type Edge = (ConstraintSccIndex, ConstraintSccIndex); - - fn graph_id(&'this self) -> dot::Id<'this> { - dot::Id::new("RegionInferenceContext".to_string()).unwrap() - } - fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> { - dot::Id::new(format!("r{}", n.index())).unwrap() - } - fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option> { - Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) - } - fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { - let nodes = &self.nodes_per_scc[*n]; - dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into()) - } -} - -impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> { - type Node = ConstraintSccIndex; - type Edge = (ConstraintSccIndex, ConstraintSccIndex); - - fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> { - let vids: Vec = self.regioncx.constraint_sccs.all_sccs().collect(); - vids.into() - } - fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> { - let edges: Vec<_> = self - .regioncx - .constraint_sccs - .all_sccs() - .flat_map(|scc_a| { - self.regioncx - .constraint_sccs - .successors(scc_a) - .iter() - .map(move |&scc_b| (scc_a, scc_b)) - }) - .collect(); - - edges.into() - } - - // Render `a: b` as `a -> b`, indicating the flow - // of data during inference. - - fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { - edge.0 - } - - fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { - edge.1 - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2254 +0,0 @@ -use std::collections::VecDeque; -use std::rc::Rc; - -use rustc_data_structures::binary_search_util; -use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::graph::scc::Sccs; -use rustc_hir::def_id::DefId; -use rustc_index::vec::IndexVec; -use rustc_infer::infer::canonical::QueryOutlivesConstraint; -use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; -use rustc_middle::mir::{ - Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, - ConstraintCategory, Local, Location, ReturnConstraint, -}; -use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; -use rustc_span::Span; - -use crate::borrow_check::{ - constraints::{ - graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet, - }, - diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}, - member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, - nll::{PoloniusOutput, ToRegionVid}, - region_infer::reverse_sccs::ReverseSccGraph, - region_infer::values::{ - LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, - ToElementIndex, - }, - type_check::{free_region_relations::UniversalRegionRelations, Locations}, - universal_regions::UniversalRegions, -}; - -mod dump_mir; -mod graphviz; -mod opaque_types; -mod reverse_sccs; - -pub mod values; - -pub struct RegionInferenceContext<'tcx> { - /// Contains the definition for every region variable. Region - /// variables are identified by their index (`RegionVid`). The - /// definition contains information about where the region came - /// from as well as its final inferred value. - definitions: IndexVec>, - - /// The liveness constraints added to each region. For most - /// regions, these start out empty and steadily grow, though for - /// each universally quantified region R they start out containing - /// the entire CFG and `end(R)`. - liveness_constraints: LivenessValues, - - /// The outlives constraints computed by the type-check. - constraints: Frozen>, - - /// The constraint-set, but in graph form, making it easy to traverse - /// the constraints adjacent to a particular region. Used to construct - /// the SCC (see `constraint_sccs`) and for error reporting. - constraint_graph: Frozen, - - /// The SCC computed from `constraints` and the constraint - /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to - /// compute the values of each region. - constraint_sccs: Rc>, - - /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if - /// `B: A`. This is used to compute the universal regions that are required - /// to outlive a given SCC. Computed lazily. - rev_scc_graph: Option>, - - /// The "R0 member of [R1..Rn]" constraints, indexed by SCC. - member_constraints: Rc>, - - /// Records the member constraints that we applied to each scc. - /// This is useful for error reporting. Once constraint - /// propagation is done, this vector is sorted according to - /// `member_region_scc`. - member_constraints_applied: Vec, - - /// Map closure bounds to a `Span` that should be used for error reporting. - closure_bounds_mapping: - FxHashMap>, - - /// Map universe indexes to information on why we created it. - universe_causes: IndexVec>, - - /// Contains the minimum universe of any variable within the same - /// SCC. We will ensure that no SCC contains values that are not - /// visible from this index. - scc_universes: IndexVec, - - /// Contains a "representative" from each SCC. This will be the - /// minimal RegionVid belonging to that universe. It is used as a - /// kind of hacky way to manage checking outlives relationships, - /// since we can 'canonicalize' each region to the representative - /// of its SCC and be sure that -- if they have the same repr -- - /// they *must* be equal (though not having the same repr does not - /// mean they are unequal). - scc_representatives: IndexVec, - - /// The final inferred values of the region variables; we compute - /// one value per SCC. To get the value for any given *region*, - /// you first find which scc it is a part of. - scc_values: RegionValues, - - /// Type constraints that we check after solving. - type_tests: Vec>, - - /// Information about the universally quantified regions in scope - /// on this function. - universal_regions: Rc>, - - /// Information about how the universally quantified regions in - /// scope on this function relate to one another. - universal_region_relations: Frozen>, -} - -/// Each time that `apply_member_constraint` is successful, it appends -/// one of these structs to the `member_constraints_applied` field. -/// This is used in error reporting to trace out what happened. -/// -/// The way that `apply_member_constraint` works is that it effectively -/// adds a new lower bound to the SCC it is analyzing: so you wind up -/// with `'R: 'O` where `'R` is the pick-region and `'O` is the -/// minimal viable option. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub(crate) struct AppliedMemberConstraint { - /// The SCC that was affected. (The "member region".) - /// - /// The vector if `AppliedMemberConstraint` elements is kept sorted - /// by this field. - pub(in crate::borrow_check) member_region_scc: ConstraintSccIndex, - - /// The "best option" that `apply_member_constraint` found -- this was - /// added as an "ad-hoc" lower-bound to `member_region_scc`. - pub(in crate::borrow_check) min_choice: ty::RegionVid, - - /// The "member constraint index" -- we can find out details about - /// the constraint from - /// `set.member_constraints[member_constraint_index]`. - pub(in crate::borrow_check) member_constraint_index: NllMemberConstraintIndex, -} - -pub(crate) struct RegionDefinition<'tcx> { - /// What kind of variable is this -- a free region? existential - /// variable? etc. (See the `NllRegionVariableOrigin` for more - /// info.) - pub(in crate::borrow_check) origin: NllRegionVariableOrigin, - - /// Which universe is this region variable defined in? This is - /// most often `ty::UniverseIndex::ROOT`, but when we encounter - /// forall-quantifiers like `for<'a> { 'a = 'b }`, we would create - /// the variable for `'a` in a fresh universe that extends ROOT. - pub(in crate::borrow_check) universe: ty::UniverseIndex, - - /// If this is 'static or an early-bound region, then this is - /// `Some(X)` where `X` is the name of the region. - pub(in crate::borrow_check) external_name: Option>, -} - -/// N.B., the variants in `Cause` are intentionally ordered. Lower -/// values are preferred when it comes to error messages. Do not -/// reorder willy nilly. -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] -pub(crate) enum Cause { - /// point inserted because Local was live at the given Location - LiveVar(Local, Location), - - /// point inserted because Local was dropped at the given Location - DropVar(Local, Location), -} - -/// A "type test" corresponds to an outlives constraint between a type -/// and a lifetime, like `T: 'x` or `::Bar: 'x`. They are -/// translated from the `Verify` region constraints in the ordinary -/// inference context. -/// -/// These sorts of constraints are handled differently than ordinary -/// constraints, at least at present. During type checking, the -/// `InferCtxt::process_registered_region_obligations` method will -/// attempt to convert a type test like `T: 'x` into an ordinary -/// outlives constraint when possible (for example, `&'a T: 'b` will -/// be converted into `'a: 'b` and registered as a `Constraint`). -/// -/// In some cases, however, there are outlives relationships that are -/// not converted into a region constraint, but rather into one of -/// these "type tests". The distinction is that a type test does not -/// influence the inference result, but instead just examines the -/// values that we ultimately inferred for each region variable and -/// checks that they meet certain extra criteria. If not, an error -/// can be issued. -/// -/// One reason for this is that these type tests typically boil down -/// to a check like `'a: 'x` where `'a` is a universally quantified -/// region -- and therefore not one whose value is really meant to be -/// *inferred*, precisely (this is not always the case: one can have a -/// type test like `>::Bar: 'x`, where `'?0` is an -/// inference variable). Another reason is that these type tests can -/// involve *disjunction* -- that is, they can be satisfied in more -/// than one way. -/// -/// For more information about this translation, see -/// `InferCtxt::process_registered_region_obligations` and -/// `InferCtxt::type_must_outlive` in `rustc_infer::infer::InferCtxt`. -#[derive(Clone, Debug)] -pub struct TypeTest<'tcx> { - /// The type `T` that must outlive the region. - pub generic_kind: GenericKind<'tcx>, - - /// The region `'x` that the type must outlive. - pub lower_bound: RegionVid, - - /// Where did this constraint arise and why? - pub locations: Locations, - - /// A test which, if met by the region `'x`, proves that this type - /// constraint is satisfied. - pub verify_bound: VerifyBound<'tcx>, -} - -/// When we have an unmet lifetime constraint, we try to propagate it outward (e.g. to a closure -/// environment). If we can't, it is an error. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum RegionRelationCheckResult { - Ok, - Propagated, - Error, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -enum Trace<'tcx> { - StartRegion, - FromOutlivesConstraint(OutlivesConstraint<'tcx>), - NotVisited, -} - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Creates a new region inference context with a total of - /// `num_region_variables` valid inference variables; the first N - /// of those will be constant regions representing the free - /// regions defined in `universal_regions`. - /// - /// The `outlives_constraints` and `type_tests` are an initial set - /// of constraints produced by the MIR type check. - pub(in crate::borrow_check) fn new( - var_infos: VarInfos, - universal_regions: Rc>, - placeholder_indices: Rc, - universal_region_relations: Frozen>, - outlives_constraints: OutlivesConstraintSet<'tcx>, - member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, - closure_bounds_mapping: FxHashMap< - Location, - FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, - >, - universe_causes: IndexVec>, - type_tests: Vec>, - liveness_constraints: LivenessValues, - elements: &Rc, - ) -> Self { - // Create a RegionDefinition for each inference variable. - let definitions: IndexVec<_, _> = var_infos - .into_iter() - .map(|info| RegionDefinition::new(info.universe, info.origin)) - .collect(); - - let constraints = Frozen::freeze(outlives_constraints); - let constraint_graph = Frozen::freeze(constraints.graph(definitions.len())); - let fr_static = universal_regions.fr_static; - let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static)); - - let mut scc_values = - RegionValues::new(elements, universal_regions.len(), &placeholder_indices); - - for region in liveness_constraints.rows() { - let scc = constraint_sccs.scc(region); - scc_values.merge_liveness(scc, region, &liveness_constraints); - } - - let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions); - - let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions); - - let member_constraints = - Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); - - let mut result = Self { - definitions, - liveness_constraints, - constraints, - constraint_graph, - constraint_sccs, - rev_scc_graph: None, - member_constraints, - member_constraints_applied: Vec::new(), - closure_bounds_mapping, - universe_causes, - scc_universes, - scc_representatives, - scc_values, - type_tests, - universal_regions, - universal_region_relations, - }; - - result.init_free_and_bound_regions(); - - result - } - - /// Each SCC is the combination of many region variables which - /// have been equated. Therefore, we can associate a universe with - /// each SCC which is minimum of all the universes of its - /// constituent regions -- this is because whatever value the SCC - /// takes on must be a value that each of the regions within the - /// SCC could have as well. This implies that the SCC must have - /// the minimum, or narrowest, universe. - fn compute_scc_universes( - constraint_sccs: &Sccs, - definitions: &IndexVec>, - ) -> IndexVec { - let num_sccs = constraint_sccs.num_sccs(); - let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs); - - debug!("compute_scc_universes()"); - - // For each region R in universe U, ensure that the universe for the SCC - // that contains R is "no bigger" than U. This effectively sets the universe - // for each SCC to be the minimum of the regions within. - for (region_vid, region_definition) in definitions.iter_enumerated() { - let scc = constraint_sccs.scc(region_vid); - let scc_universe = &mut scc_universes[scc]; - let scc_min = std::cmp::min(region_definition.universe, *scc_universe); - if scc_min != *scc_universe { - *scc_universe = scc_min; - debug!( - "compute_scc_universes: lowered universe of {scc:?} to {scc_min:?} \ - because it contains {region_vid:?} in {region_universe:?}", - scc = scc, - scc_min = scc_min, - region_vid = region_vid, - region_universe = region_definition.universe, - ); - } - } - - // Walk each SCC `A` and `B` such that `A: B` - // and ensure that universe(A) can see universe(B). - // - // This serves to enforce the 'empty/placeholder' hierarchy - // (described in more detail on `RegionKind`): - // - // ``` - // static -----+ - // | | - // empty(U0) placeholder(U1) - // | / - // empty(U1) - // ``` - // - // In particular, imagine we have variables R0 in U0 and R1 - // created in U1, and constraints like this; - // - // ``` - // R1: !1 // R1 outlives the placeholder in U1 - // R1: R0 // R1 outlives R0 - // ``` - // - // Here, we wish for R1 to be `'static`, because it - // cannot outlive `placeholder(U1)` and `empty(U0)` any other way. - // - // Thanks to this loop, what happens is that the `R1: R0` - // constraint lowers the universe of `R1` to `U0`, which in turn - // means that the `R1: !1` constraint will (later) cause - // `R1` to become `'static`. - for scc_a in constraint_sccs.all_sccs() { - for &scc_b in constraint_sccs.successors(scc_a) { - let scc_universe_a = scc_universes[scc_a]; - let scc_universe_b = scc_universes[scc_b]; - let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b); - if scc_universe_a != scc_universe_min { - scc_universes[scc_a] = scc_universe_min; - - debug!( - "compute_scc_universes: lowered universe of {scc_a:?} to {scc_universe_min:?} \ - because {scc_a:?}: {scc_b:?} and {scc_b:?} is in universe {scc_universe_b:?}", - scc_a = scc_a, - scc_b = scc_b, - scc_universe_min = scc_universe_min, - scc_universe_b = scc_universe_b - ); - } - } - } - - debug!("compute_scc_universes: scc_universe = {:#?}", scc_universes); - - scc_universes - } - - /// For each SCC, we compute a unique `RegionVid` (in fact, the - /// minimal one that belongs to the SCC). See - /// `scc_representatives` field of `RegionInferenceContext` for - /// more details. - fn compute_scc_representatives( - constraints_scc: &Sccs, - definitions: &IndexVec>, - ) -> IndexVec { - let num_sccs = constraints_scc.num_sccs(); - let next_region_vid = definitions.next_index(); - let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs); - - for region_vid in definitions.indices() { - let scc = constraints_scc.scc(region_vid); - let prev_min = scc_representatives[scc]; - scc_representatives[scc] = region_vid.min(prev_min); - } - - scc_representatives - } - - /// Initializes the region variables for each universally - /// quantified region (lifetime parameter). The first N variables - /// always correspond to the regions appearing in the function - /// signature (both named and anonymous) and where-clauses. This - /// function iterates over those regions and initializes them with - /// minimum values. - /// - /// For example: - /// - /// fn foo<'a, 'b>(..) where 'a: 'b - /// - /// would initialize two variables like so: - /// - /// R0 = { CFG, R0 } // 'a - /// R1 = { CFG, R0, R1 } // 'b - /// - /// Here, R0 represents `'a`, and it contains (a) the entire CFG - /// and (b) any universally quantified regions that it outlives, - /// which in this case is just itself. R1 (`'b`) in contrast also - /// outlives `'a` and hence contains R0 and R1. - fn init_free_and_bound_regions(&mut self) { - // Update the names (if any) - for (external_name, variable) in self.universal_regions.named_universal_regions() { - debug!( - "init_universal_regions: region {:?} has external name {:?}", - variable, external_name - ); - self.definitions[variable].external_name = Some(external_name); - } - - for variable in self.definitions.indices() { - let scc = self.constraint_sccs.scc(variable); - - match self.definitions[variable].origin { - NllRegionVariableOrigin::FreeRegion => { - // For each free, universally quantified region X: - - // Add all nodes in the CFG to liveness constraints - self.liveness_constraints.add_all_points(variable); - self.scc_values.add_all_points(scc); - - // Add `end(X)` into the set for X. - self.scc_values.add_element(scc, variable); - } - - NllRegionVariableOrigin::Placeholder(placeholder) => { - // Each placeholder region is only visible from - // its universe `ui` and its extensions. So we - // can't just add it into `scc` unless the - // universe of the scc can name this region. - let scc_universe = self.scc_universes[scc]; - if scc_universe.can_name(placeholder.universe) { - self.scc_values.add_element(scc, placeholder); - } else { - debug!( - "init_free_and_bound_regions: placeholder {:?} is \ - not compatible with universe {:?} of its SCC {:?}", - placeholder, scc_universe, scc, - ); - self.add_incompatible_universe(scc); - } - } - - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::Existential { .. } => { - // For existential, regions, nothing to do. - } - } - } - } - - /// Returns an iterator over all the region indices. - pub fn regions(&self) -> impl Iterator { - self.definitions.indices() - } - - /// Given a universal region in scope on the MIR, returns the - /// corresponding index. - /// - /// (Panics if `r` is not a registered universal region.) - pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - self.universal_regions.to_region_vid(r) - } - - /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. - crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut rustc_errors::DiagnosticBuilder<'_>) { - self.universal_regions.annotate(tcx, err) - } - - /// Returns `true` if the region `r` contains the point `p`. - /// - /// Panics if called before `solve()` executes, - crate fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool { - let scc = self.constraint_sccs.scc(r.to_region_vid()); - self.scc_values.contains(scc, p) - } - - /// Returns access to the value of `r` for debugging purposes. - crate fn region_value_str(&self, r: RegionVid) -> String { - let scc = self.constraint_sccs.scc(r.to_region_vid()); - self.scc_values.region_value_str(scc) - } - - /// Returns access to the value of `r` for debugging purposes. - crate fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex { - let scc = self.constraint_sccs.scc(r.to_region_vid()); - self.scc_universes[scc] - } - - /// Once region solving has completed, this function will return - /// the member constraints that were applied to the value of a given - /// region `r`. See `AppliedMemberConstraint`. - pub(in crate::borrow_check) fn applied_member_constraints( - &self, - r: impl ToRegionVid, - ) -> &[AppliedMemberConstraint] { - let scc = self.constraint_sccs.scc(r.to_region_vid()); - binary_search_util::binary_search_slice( - &self.member_constraints_applied, - |applied| applied.member_region_scc, - &scc, - ) - } - - /// Performs region inference and report errors if we see any - /// unsatisfiable constraints. If this is a closure, returns the - /// region requirements to propagate to our creator, if any. - pub(super) fn solve( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - body: &Body<'tcx>, - polonius_output: Option>, - ) -> (Option>, RegionErrors<'tcx>) { - let mir_def_id = body.source.def_id(); - self.propagate_constraints(body); - - let mut errors_buffer = RegionErrors::new(); - - // If this is a closure, we can propagate unsatisfied - // `outlives_requirements` to our creator, so create a vector - // to store those. Otherwise, we'll pass in `None` to the - // functions below, which will trigger them to report errors - // eagerly. - let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new); - - self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer); - - // In Polonius mode, the errors about missing universal region relations are in the output - // and need to be emitted or propagated. Otherwise, we need to check whether the - // constraints were too strong, and if so, emit or propagate those errors. - if infcx.tcx.sess.opts.debugging_opts.polonius { - self.check_polonius_subset_errors( - body, - outlives_requirements.as_mut(), - &mut errors_buffer, - polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), - ); - } else { - self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer); - } - - if errors_buffer.is_empty() { - self.check_member_constraints(infcx, &mut errors_buffer); - } - - let outlives_requirements = outlives_requirements.unwrap_or_default(); - - if outlives_requirements.is_empty() { - (None, errors_buffer) - } else { - let num_external_vids = self.universal_regions.num_global_and_external_regions(); - ( - Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }), - errors_buffer, - ) - } - } - - /// Propagate the region constraints: this will grow the values - /// for each region variable until all the constraints are - /// satisfied. Note that some values may grow **too** large to be - /// feasible, but we check this later. - fn propagate_constraints(&mut self, _body: &Body<'tcx>) { - debug!("propagate_constraints()"); - - debug!("propagate_constraints: constraints={:#?}", { - let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); - constraints.sort(); - constraints - .into_iter() - .map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub))) - .collect::>() - }); - - // To propagate constraints, we walk the DAG induced by the - // SCC. For each SCC, we visit its successors and compute - // their values, then we union all those values to get our - // own. - let constraint_sccs = self.constraint_sccs.clone(); - for scc in constraint_sccs.all_sccs() { - self.compute_value_for_scc(scc); - } - - // Sort the applied member constraints so we can binary search - // through them later. - self.member_constraints_applied.sort_by_key(|applied| applied.member_region_scc); - } - - /// Computes the value of the SCC `scc_a`, which has not yet been - /// computed, by unioning the values of its successors. - /// Assumes that all successors have been computed already - /// (which is assured by iterating over SCCs in dependency order). - fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { - let constraint_sccs = self.constraint_sccs.clone(); - - // Walk each SCC `B` such that `A: B`... - for &scc_b in constraint_sccs.successors(scc_a) { - debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b); - - // ...and add elements from `B` into `A`. One complication - // arises because of universes: If `B` contains something - // that `A` cannot name, then `A` can only contain `B` if - // it outlives static. - if self.universe_compatible(scc_b, scc_a) { - // `A` can name everything that is in `B`, so just - // merge the bits. - self.scc_values.add_region(scc_a, scc_b); - } else { - self.add_incompatible_universe(scc_a); - } - } - - // Now take member constraints into account. - let member_constraints = self.member_constraints.clone(); - for m_c_i in member_constraints.indices(scc_a) { - self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); - } - - debug!( - "propagate_constraint_sccs: scc_a = {:?} has value {:?}", - scc_a, - self.scc_values.region_value_str(scc_a), - ); - } - - /// Invoked for each `R0 member of [R1..Rn]` constraint. - /// - /// `scc` is the SCC containing R0, and `choice_regions` are the - /// `R1..Rn` regions -- they are always known to be universal - /// regions (and if that's not true, we just don't attempt to - /// enforce the constraint). - /// - /// The current value of `scc` at the time the method is invoked - /// is considered a *lower bound*. If possible, we will modify - /// the constraint to set it equal to one of the option regions. - /// If we make any changes, returns true, else false. - fn apply_member_constraint( - &mut self, - scc: ConstraintSccIndex, - member_constraint_index: NllMemberConstraintIndex, - choice_regions: &[ty::RegionVid], - ) -> bool { - debug!("apply_member_constraint(scc={:?}, choice_regions={:#?})", scc, choice_regions,); - - // Create a mutable vector of the options. We'll try to winnow - // them down. - let mut choice_regions: Vec = choice_regions.to_vec(); - - // The 'member region' in a member constraint is part of the - // hidden type, which must be in the root universe. Therefore, - // it cannot have any placeholders in its value. - assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT); - debug_assert!( - self.scc_values.placeholders_contained_in(scc).next().is_none(), - "scc {:?} in a member constraint has placeholder value: {:?}", - scc, - self.scc_values.region_value_str(scc), - ); - - // The existing value for `scc` is a lower-bound. This will - // consist of some set `{P} + {LB}` of points `{P}` and - // lower-bound free regions `{LB}`. As each choice region `O` - // is a free region, it will outlive the points. But we can - // only consider the option `O` if `O: LB`. - choice_regions.retain(|&o_r| { - self.scc_values - .universal_regions_outlived_by(scc) - .all(|lb| self.universal_region_relations.outlives(o_r, lb)) - }); - debug!("apply_member_constraint: after lb, choice_regions={:?}", choice_regions); - - // Now find all the *upper bounds* -- that is, each UB is a - // free region that must outlive the member region `R0` (`UB: - // R0`). Therefore, we need only keep an option `O` if `UB: O` - // for all UB. - let rev_scc_graph = self.reverse_scc_graph(); - let universal_region_relations = &self.universal_region_relations; - for ub in rev_scc_graph.upper_bounds(scc) { - debug!("apply_member_constraint: ub={:?}", ub); - choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); - } - debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions); - - // If we ruled everything out, we're done. - if choice_regions.is_empty() { - return false; - } - - // Otherwise, we need to find the minimum remaining choice, if - // any, and take that. - debug!("apply_member_constraint: choice_regions remaining are {:#?}", choice_regions); - let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option { - let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); - let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); - match (r1_outlives_r2, r2_outlives_r1) { - (true, true) => Some(r1.min(r2)), - (true, false) => Some(r2), - (false, true) => Some(r1), - (false, false) => None, - } - }; - let mut min_choice = choice_regions[0]; - for &other_option in &choice_regions[1..] { - debug!( - "apply_member_constraint: min_choice={:?} other_option={:?}", - min_choice, other_option, - ); - match min(min_choice, other_option) { - Some(m) => min_choice = m, - None => { - debug!( - "apply_member_constraint: {:?} and {:?} are incomparable; no min choice", - min_choice, other_option, - ); - return false; - } - } - } - - let min_choice_scc = self.constraint_sccs.scc(min_choice); - debug!( - "apply_member_constraint: min_choice={:?} best_choice_scc={:?}", - min_choice, min_choice_scc, - ); - if self.scc_values.add_region(scc, min_choice_scc) { - self.member_constraints_applied.push(AppliedMemberConstraint { - member_region_scc: scc, - min_choice, - member_constraint_index, - }); - - true - } else { - false - } - } - - /// Returns `true` if all the elements in the value of `scc_b` are nameable - /// in `scc_a`. Used during constraint propagation, and only once - /// the value of `scc_b` has been computed. - fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { - let universe_a = self.scc_universes[scc_a]; - - // Quick check: if scc_b's declared universe is a subset of - // scc_a's declared univese (typically, both are ROOT), then - // it cannot contain any problematic universe elements. - if universe_a.can_name(self.scc_universes[scc_b]) { - return true; - } - - // Otherwise, we have to iterate over the universe elements in - // B's value, and check whether all of them are nameable - // from universe_a - self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe)) - } - - /// Extend `scc` so that it can outlive some placeholder region - /// from a universe it can't name; at present, the only way for - /// this to be true is if `scc` outlives `'static`. This is - /// actually stricter than necessary: ideally, we'd support bounds - /// like `for<'a: 'b`>` that might then allow us to approximate - /// `'a` with `'b` and not `'static`. But it will have to do for - /// now. - fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) { - debug!("add_incompatible_universe(scc={:?})", scc); - - let fr_static = self.universal_regions.fr_static; - self.scc_values.add_all_points(scc); - self.scc_values.add_element(scc, fr_static); - } - - /// Once regions have been propagated, this method is used to see - /// whether the "type tests" produced by typeck were satisfied; - /// type tests encode type-outlives relationships like `T: - /// 'a`. See `TypeTest` for more details. - fn check_type_tests( - &self, - infcx: &InferCtxt<'_, 'tcx>, - body: &Body<'tcx>, - mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - let tcx = infcx.tcx; - - // Sometimes we register equivalent type-tests that would - // result in basically the exact same error being reported to - // the user. Avoid that. - let mut deduplicate_errors = FxHashSet::default(); - - for type_test in &self.type_tests { - debug!("check_type_test: {:?}", type_test); - - let generic_ty = type_test.generic_kind.to_ty(tcx); - if self.eval_verify_bound( - tcx, - body, - generic_ty, - type_test.lower_bound, - &type_test.verify_bound, - ) { - continue; - } - - if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { - if self.try_promote_type_test( - infcx, - body, - type_test, - propagated_outlives_requirements, - ) { - continue; - } - } - - // Type-test failed. Report the error. - let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind); - - // Skip duplicate-ish errors. - if deduplicate_errors.insert(( - erased_generic_kind, - type_test.lower_bound, - type_test.locations, - )) { - debug!( - "check_type_test: reporting error for erased_generic_kind={:?}, \ - lower_bound_region={:?}, \ - type_test.locations={:?}", - erased_generic_kind, type_test.lower_bound, type_test.locations, - ); - - errors_buffer.push(RegionErrorKind::TypeTestError { type_test: type_test.clone() }); - } - } - } - - /// Invoked when we have some type-test (e.g., `T: 'X`) that we cannot - /// prove to be satisfied. If this is a closure, we will attempt to - /// "promote" this type-test into our `ClosureRegionRequirements` and - /// hence pass it up the creator. To do this, we have to phrase the - /// type-test in terms of external free regions, as local free - /// regions are not nameable by the closure's creator. - /// - /// Promotion works as follows: we first check that the type `T` - /// contains only regions that the creator knows about. If this is - /// true, then -- as a consequence -- we know that all regions in - /// the type `T` are free regions that outlive the closure body. If - /// false, then promotion fails. - /// - /// Once we've promoted T, we have to "promote" `'X` to some region - /// that is "external" to the closure. Generally speaking, a region - /// may be the union of some points in the closure body as well as - /// various free lifetimes. We can ignore the points in the closure - /// body: if the type T can be expressed in terms of external regions, - /// we know it outlives the points in the closure body. That - /// just leaves the free regions. - /// - /// The idea then is to lower the `T: 'X` constraint into multiple - /// bounds -- e.g., if `'X` is the union of two free lifetimes, - /// `'1` and `'2`, then we would create `T: '1` and `T: '2`. - fn try_promote_type_test( - &self, - infcx: &InferCtxt<'_, 'tcx>, - body: &Body<'tcx>, - type_test: &TypeTest<'tcx>, - propagated_outlives_requirements: &mut Vec>, - ) -> bool { - let tcx = infcx.tcx; - - let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test; - - let generic_ty = generic_kind.to_ty(tcx); - let subject = match self.try_promote_type_test_subject(infcx, generic_ty) { - Some(s) => s, - None => return false, - }; - - // For each region outlived by lower_bound find a non-local, - // universal region (it may be the same region) and add it to - // `ClosureOutlivesRequirement`. - let r_scc = self.constraint_sccs.scc(*lower_bound); - for ur in self.scc_values.universal_regions_outlived_by(r_scc) { - // Check whether we can already prove that the "subject" outlives `ur`. - // If so, we don't have to propagate this requirement to our caller. - // - // To continue the example from the function, if we are trying to promote - // a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union - // `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here - // we check whether `T: '1` is something we *can* prove. If so, no need - // to propagate that requirement. - // - // This is needed because -- particularly in the case - // where `ur` is a local bound -- we are sometimes in a - // position to prove things that our caller cannot. See - // #53570 for an example. - if self.eval_verify_bound(tcx, body, generic_ty, ur, &type_test.verify_bound) { - continue; - } - - debug!("try_promote_type_test: ur={:?}", ur); - - let non_local_ub = self.universal_region_relations.non_local_upper_bounds(&ur); - debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub); - - // This is slightly too conservative. To show T: '1, given `'2: '1` - // and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to - // avoid potential non-determinism we approximate this by requiring - // T: '1 and T: '2. - for &upper_bound in non_local_ub { - debug_assert!(self.universal_regions.is_universal_region(upper_bound)); - debug_assert!(!self.universal_regions.is_local_free_region(upper_bound)); - - let requirement = ClosureOutlivesRequirement { - subject, - outlived_free_region: upper_bound, - blame_span: locations.span(body), - category: ConstraintCategory::Boring, - }; - debug!("try_promote_type_test: pushing {:#?}", requirement); - propagated_outlives_requirements.push(requirement); - } - } - true - } - - /// When we promote a type test `T: 'r`, we have to convert the - /// type `T` into something we can store in a query result (so - /// something allocated for `'tcx`). This is problematic if `ty` - /// contains regions. During the course of NLL region checking, we - /// will have replaced all of those regions with fresh inference - /// variables. To create a test subject, we want to replace those - /// inference variables with some region from the closure - /// signature -- this is not always possible, so this is a - /// fallible process. Presuming we do find a suitable region, we - /// will use it's *external name*, which will be a `RegionKind` - /// variant that can be used in query responses such as - /// `ReEarlyBound`. - fn try_promote_type_test_subject( - &self, - infcx: &InferCtxt<'_, 'tcx>, - ty: Ty<'tcx>, - ) -> Option> { - let tcx = infcx.tcx; - - debug!("try_promote_type_test_subject(ty = {:?})", ty); - - let ty = tcx.fold_regions(ty, &mut false, |r, _depth| { - let region_vid = self.to_region_vid(r); - - // The challenge if this. We have some region variable `r` - // whose value is a set of CFG points and universal - // regions. We want to find if that set is *equivalent* to - // any of the named regions found in the closure. - // - // To do so, we compute the - // `non_local_universal_upper_bound`. This will be a - // non-local, universal region that is greater than `r`. - // However, it might not be *contained* within `r`, so - // then we further check whether this bound is contained - // in `r`. If so, we can say that `r` is equivalent to the - // bound. - // - // Let's work through a few examples. For these, imagine - // that we have 3 non-local regions (I'll denote them as - // `'static`, `'a`, and `'b`, though of course in the code - // they would be represented with indices) where: - // - // - `'static: 'a` - // - `'static: 'b` - // - // First, let's assume that `r` is some existential - // variable with an inferred value `{'a, 'static}` (plus - // some CFG nodes). In this case, the non-local upper - // bound is `'static`, since that outlives `'a`. `'static` - // is also a member of `r` and hence we consider `r` - // equivalent to `'static` (and replace it with - // `'static`). - // - // Now let's consider the inferred value `{'a, 'b}`. This - // means `r` is effectively `'a | 'b`. I'm not sure if - // this can come about, actually, but assuming it did, we - // would get a non-local upper bound of `'static`. Since - // `'static` is not contained in `r`, we would fail to - // find an equivalent. - let upper_bound = self.non_local_universal_upper_bound(region_vid); - if self.region_contains(region_vid, upper_bound) { - self.definitions[upper_bound].external_name.unwrap_or(r) - } else { - // In the case of a failure, use a `ReVar` result. This will - // cause the `needs_infer` later on to return `None`. - r - } - }); - - debug!("try_promote_type_test_subject: folded ty = {:?}", ty); - - // `needs_infer` will only be true if we failed to promote some region. - if ty.needs_infer() { - return None; - } - - Some(ClosureOutlivesSubject::Ty(ty)) - } - - /// Given some universal or existential region `r`, finds a - /// non-local, universal region `r+` that outlives `r` at entry to (and - /// exit from) the closure. In the worst case, this will be - /// `'static`. - /// - /// This is used for two purposes. First, if we are propagated - /// some requirement `T: r`, we can use this method to enlarge `r` - /// to something we can encode for our creator (which only knows - /// about non-local, universal regions). It is also used when - /// encoding `T` as part of `try_promote_type_test_subject` (see - /// that fn for details). - /// - /// This is based on the result `'y` of `universal_upper_bound`, - /// except that it converts further takes the non-local upper - /// bound of `'y`, so that the final result is non-local. - fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); - - let lub = self.universal_upper_bound(r); - - // Grow further to get smallest universal region known to - // creator. - let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub); - - debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub); - - non_local_lub - } - - /// Returns a universally quantified region that outlives the - /// value of `r` (`r` may be existentially or universally - /// quantified). - /// - /// Since `r` is (potentially) an existential region, it has some - /// value which may include (a) any number of points in the CFG - /// and (b) any number of `end('x)` elements of universally - /// quantified regions. To convert this into a single universal - /// region we do as follows: - /// - /// - Ignore the CFG points in `'r`. All universally quantified regions - /// include the CFG anyhow. - /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding - /// a result `'y`. - pub(in crate::borrow_check) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); - - // Find the smallest universal region that contains all other - // universal regions within `region`. - let mut lub = self.universal_regions.fr_fn_body; - let r_scc = self.constraint_sccs.scc(r); - for ur in self.scc_values.universal_regions_outlived_by(r_scc) { - lub = self.universal_region_relations.postdom_upper_bound(lub, ur); - } - - debug!("universal_upper_bound: r={:?} lub={:?}", r, lub); - - lub - } - - /// Like `universal_upper_bound`, but returns an approximation more suitable - /// for diagnostics. If `r` contains multiple disjoint universal regions - /// (e.g. 'a and 'b in `fn foo<'a, 'b> { ... }`, we pick the lower-numbered region. - /// This corresponds to picking named regions over unnamed regions - /// (e.g. picking early-bound regions over a closure late-bound region). - /// - /// This means that the returned value may not be a true upper bound, since - /// only 'static is known to outlive disjoint universal regions. - /// Therefore, this method should only be used in diagnostic code, - /// where displaying *some* named universal region is better than - /// falling back to 'static. - pub(in crate::borrow_check) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); - - // Find the smallest universal region that contains all other - // universal regions within `region`. - let mut lub = self.universal_regions.fr_fn_body; - let r_scc = self.constraint_sccs.scc(r); - let static_r = self.universal_regions.fr_static; - for ur in self.scc_values.universal_regions_outlived_by(r_scc) { - let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); - debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub); - // The upper bound of two non-static regions is static: this - // means we know nothing about the relationship between these - // two regions. Pick a 'better' one to use when constructing - // a diagnostic - if ur != static_r && lub != static_r && new_lub == static_r { - // Prefer the region with an `external_name` - this - // indicates that the region is early-bound, so working with - // it can produce a nicer error. - if self.region_definition(ur).external_name.is_some() { - lub = ur; - } else if self.region_definition(lub).external_name.is_some() { - // Leave lub unchanged - } else { - // If we get here, we don't have any reason to prefer - // one region over the other. Just pick the - // one with the lower index for now. - lub = std::cmp::min(ur, lub); - } - } else { - lub = new_lub; - } - } - - debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub); - - lub - } - - /// Tests if `test` is true when applied to `lower_bound` at - /// `point`. - fn eval_verify_bound( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - generic_ty: Ty<'tcx>, - lower_bound: RegionVid, - verify_bound: &VerifyBound<'tcx>, - ) -> bool { - debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound); - - match verify_bound { - VerifyBound::IfEq(test_ty, verify_bound1) => { - self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1) - } - - VerifyBound::IsEmpty => { - let lower_bound_scc = self.constraint_sccs.scc(lower_bound); - self.scc_values.elements_contained_in(lower_bound_scc).next().is_none() - } - - VerifyBound::OutlivedBy(r) => { - let r_vid = self.to_region_vid(r); - self.eval_outlives(r_vid, lower_bound) - } - - VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| { - self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) - }), - - VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| { - self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) - }), - } - } - - fn eval_if_eq( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - generic_ty: Ty<'tcx>, - lower_bound: RegionVid, - test_ty: Ty<'tcx>, - verify_bound: &VerifyBound<'tcx>, - ) -> bool { - let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty); - let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty); - if generic_ty_normalized == test_ty_normalized { - self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound) - } else { - false - } - } - - /// This is a conservative normalization procedure. It takes every - /// free region in `value` and replaces it with the - /// "representative" of its SCC (see `scc_representatives` field). - /// We are guaranteed that if two values normalize to the same - /// thing, then they are equal; this is a conservative check in - /// that they could still be equal even if they normalize to - /// different results. (For example, there might be two regions - /// with the same value that are not in the same SCC). - /// - /// N.B., this is not an ideal approach and I would like to revisit - /// it. However, it works pretty well in practice. In particular, - /// this is needed to deal with projection outlives bounds like - /// - /// ```text - /// >::Item: '1 - /// ``` - /// - /// In particular, this routine winds up being important when - /// there are bounds like `where >::Item: 'b` in the - /// environment. In this case, if we can show that `'0 == 'a`, - /// and that `'b: '1`, then we know that the clause is - /// satisfied. In such cases, particularly due to limitations of - /// the trait solver =), we usually wind up with a where-clause like - /// `T: Foo<'a>` in scope, which thus forces `'0 == 'a` to be added as - /// a constraint, and thus ensures that they are in the same SCC. - /// - /// So why can't we do a more correct routine? Well, we could - /// *almost* use the `relate_tys` code, but the way it is - /// currently setup it creates inference variables to deal with - /// higher-ranked things and so forth, and right now the inference - /// context is not permitted to make more inference variables. So - /// we use this kind of hacky solution. - fn normalize_to_scc_representatives(&self, tcx: TyCtxt<'tcx>, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - tcx.fold_regions(value, &mut false, |r, _db| { - let vid = self.to_region_vid(r); - let scc = self.constraint_sccs.scc(vid); - let repr = self.scc_representatives[scc]; - tcx.mk_region(ty::ReVar(repr)) - }) - } - - // Evaluate whether `sup_region == sub_region`. - fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool { - self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1) - } - - // Evaluate whether `sup_region: sub_region`. - fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { - debug!("eval_outlives({:?}: {:?})", sup_region, sub_region); - - debug!( - "eval_outlives: sup_region's value = {:?} universal={:?}", - self.region_value_str(sup_region), - self.universal_regions.is_universal_region(sup_region), - ); - debug!( - "eval_outlives: sub_region's value = {:?} universal={:?}", - self.region_value_str(sub_region), - self.universal_regions.is_universal_region(sub_region), - ); - - let sub_region_scc = self.constraint_sccs.scc(sub_region); - let sup_region_scc = self.constraint_sccs.scc(sup_region); - - // Both the `sub_region` and `sup_region` consist of the union - // of some number of universal regions (along with the union - // of various points in the CFG; ignore those points for - // now). Therefore, the sup-region outlives the sub-region if, - // for each universal region R1 in the sub-region, there - // exists some region R2 in the sup-region that outlives R1. - let universal_outlives = - self.scc_values.universal_regions_outlived_by(sub_region_scc).all(|r1| { - self.scc_values - .universal_regions_outlived_by(sup_region_scc) - .any(|r2| self.universal_region_relations.outlives(r2, r1)) - }); - - if !universal_outlives { - return false; - } - - // Now we have to compare all the points in the sub region and make - // sure they exist in the sup region. - - if self.universal_regions.is_universal_region(sup_region) { - // Micro-opt: universal regions contain all points. - return true; - } - - self.scc_values.contains_points(sup_region_scc, sub_region_scc) - } - - /// Once regions have been propagated, this method is used to see - /// whether any of the constraints were too strong. In particular, - /// we want to check for a case where a universally quantified - /// region exceeded its bounds. Consider: - /// - /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } - /// - /// In this case, returning `x` requires `&'a u32 <: &'b u32` - /// and hence we establish (transitively) a constraint that - /// `'a: 'b`. The `propagate_constraints` code above will - /// therefore add `end('a)` into the region for `'b` -- but we - /// have no evidence that `'b` outlives `'a`, so we want to report - /// an error. - /// - /// If `propagated_outlives_requirements` is `Some`, then we will - /// push unsatisfied obligations into there. Otherwise, we'll - /// report them as errors. - fn check_universal_regions( - &self, - body: &Body<'tcx>, - mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - for (fr, fr_definition) in self.definitions.iter_enumerated() { - match fr_definition.origin { - NllRegionVariableOrigin::FreeRegion => { - // Go through each of the universal regions `fr` and check that - // they did not grow too large, accumulating any requirements - // for our caller into the `outlives_requirements` vector. - self.check_universal_region( - body, - fr, - &mut propagated_outlives_requirements, - errors_buffer, - ); - } - - NllRegionVariableOrigin::Placeholder(placeholder) => { - self.check_bound_universal_region(fr, placeholder, errors_buffer); - } - - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::Existential { .. } => { - // nothing to check here - } - } - } - } - - /// Checks if Polonius has found any unexpected free region relations. - /// - /// In Polonius terms, a "subset error" (or "illegal subset relation error") is the equivalent - /// of NLL's "checking if any region constraints were too strong": a placeholder origin `'a` - /// was unexpectedly found to be a subset of another placeholder origin `'b`, and means in NLL - /// terms that the "longer free region" `'a` outlived the "shorter free region" `'b`. - /// - /// More details can be found in this blog post by Niko: - /// - /// - /// In the canonical example - /// - /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } - /// - /// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a - /// constraint that `'a: 'b`. It is an error that we have no evidence that this - /// constraint holds. - /// - /// If `propagated_outlives_requirements` is `Some`, then we will - /// push unsatisfied obligations into there. Otherwise, we'll - /// report them as errors. - fn check_polonius_subset_errors( - &self, - body: &Body<'tcx>, - mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - polonius_output: Rc, - ) { - debug!( - "check_polonius_subset_errors: {} subset_errors", - polonius_output.subset_errors.len() - ); - - // Similarly to `check_universal_regions`: a free region relation, which was not explicitly - // declared ("known") was found by Polonius, so emit an error, or propagate the - // requirements for our caller into the `propagated_outlives_requirements` vector. - // - // Polonius doesn't model regions ("origins") as CFG-subsets or durations, but the - // `longer_fr` and `shorter_fr` terminology will still be used here, for consistency with - // the rest of the NLL infrastructure. The "subset origin" is the "longer free region", - // and the "superset origin" is the outlived "shorter free region". - // - // Note: Polonius will produce a subset error at every point where the unexpected - // `longer_fr`'s "placeholder loan" is contained in the `shorter_fr`. This can be helpful - // for diagnostics in the future, e.g. to point more precisely at the key locations - // requiring this constraint to hold. However, the error and diagnostics code downstream - // expects that these errors are not duplicated (and that they are in a certain order). - // Otherwise, diagnostics messages such as the ones giving names like `'1` to elided or - // anonymous lifetimes for example, could give these names differently, while others like - // the outlives suggestions or the debug output from `#[rustc_regions]` would be - // duplicated. The polonius subset errors are deduplicated here, while keeping the - // CFG-location ordering. - let mut subset_errors: Vec<_> = polonius_output - .subset_errors - .iter() - .flat_map(|(_location, subset_errors)| subset_errors.iter()) - .collect(); - subset_errors.sort(); - subset_errors.dedup(); - - for (longer_fr, shorter_fr) in subset_errors.into_iter() { - debug!( - "check_polonius_subset_errors: subset_error longer_fr={:?},\ - shorter_fr={:?}", - longer_fr, shorter_fr - ); - - let propagated = self.try_propagate_universal_region_error( - *longer_fr, - *shorter_fr, - body, - &mut propagated_outlives_requirements, - ); - if propagated == RegionRelationCheckResult::Error { - errors_buffer.push(RegionErrorKind::RegionError { - longer_fr: *longer_fr, - shorter_fr: *shorter_fr, - fr_origin: NllRegionVariableOrigin::FreeRegion, - is_reported: true, - }); - } - } - - // Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has - // a more complete picture on how to separate this responsibility. - for (fr, fr_definition) in self.definitions.iter_enumerated() { - match fr_definition.origin { - NllRegionVariableOrigin::FreeRegion => { - // handled by polonius above - } - - NllRegionVariableOrigin::Placeholder(placeholder) => { - self.check_bound_universal_region(fr, placeholder, errors_buffer); - } - - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::Existential { .. } => { - // nothing to check here - } - } - } - } - - /// Checks the final value for the free region `fr` to see if it - /// grew too large. In particular, examine what `end(X)` points - /// wound up in `fr`'s final value; for each `end(X)` where `X != - /// fr`, we want to check that `fr: X`. If not, that's either an - /// error, or something we have to propagate to our creator. - /// - /// Things that are to be propagated are accumulated into the - /// `outlives_requirements` vector. - fn check_universal_region( - &self, - body: &Body<'tcx>, - longer_fr: RegionVid, - propagated_outlives_requirements: &mut Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - debug!("check_universal_region(fr={:?})", longer_fr); - - let longer_fr_scc = self.constraint_sccs.scc(longer_fr); - - // Because this free region must be in the ROOT universe, we - // know it cannot contain any bound universes. - assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT); - debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none()); - - // Only check all of the relations for the main representative of each - // SCC, otherwise just check that we outlive said representative. This - // reduces the number of redundant relations propagated out of - // closures. - // Note that the representative will be a universal region if there is - // one in this SCC, so we will always check the representative here. - let representative = self.scc_representatives[longer_fr_scc]; - if representative != longer_fr { - if let RegionRelationCheckResult::Error = self.check_universal_region_relation( - longer_fr, - representative, - body, - propagated_outlives_requirements, - ) { - errors_buffer.push(RegionErrorKind::RegionError { - longer_fr, - shorter_fr: representative, - fr_origin: NllRegionVariableOrigin::FreeRegion, - is_reported: true, - }); - } - return; - } - - // Find every region `o` such that `fr: o` - // (because `fr` includes `end(o)`). - let mut error_reported = false; - for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { - if let RegionRelationCheckResult::Error = self.check_universal_region_relation( - longer_fr, - shorter_fr, - body, - propagated_outlives_requirements, - ) { - // We only report the first region error. Subsequent errors are hidden so as - // not to overwhelm the user, but we do record them so as to potentially print - // better diagnostics elsewhere... - errors_buffer.push(RegionErrorKind::RegionError { - longer_fr, - shorter_fr, - fr_origin: NllRegionVariableOrigin::FreeRegion, - is_reported: !error_reported, - }); - - error_reported = true; - } - } - } - - /// Checks that we can prove that `longer_fr: shorter_fr`. If we can't we attempt to propagate - /// the constraint outward (e.g. to a closure environment), but if that fails, there is an - /// error. - fn check_universal_region_relation( - &self, - longer_fr: RegionVid, - shorter_fr: RegionVid, - body: &Body<'tcx>, - propagated_outlives_requirements: &mut Option<&mut Vec>>, - ) -> RegionRelationCheckResult { - // If it is known that `fr: o`, carry on. - if self.universal_region_relations.outlives(longer_fr, shorter_fr) { - RegionRelationCheckResult::Ok - } else { - // If we are not in a context where we can't propagate errors, or we - // could not shrink `fr` to something smaller, then just report an - // error. - // - // Note: in this case, we use the unapproximated regions to report the - // error. This gives better error messages in some cases. - self.try_propagate_universal_region_error( - longer_fr, - shorter_fr, - body, - propagated_outlives_requirements, - ) - } - } - - /// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's - /// creator. If we cannot, then the caller should report an error to the user. - fn try_propagate_universal_region_error( - &self, - longer_fr: RegionVid, - shorter_fr: RegionVid, - body: &Body<'tcx>, - propagated_outlives_requirements: &mut Option<&mut Vec>>, - ) -> RegionRelationCheckResult { - if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { - // Shrink `longer_fr` until we find a non-local region (if we do). - // We'll call it `fr-` -- it's ever so slightly smaller than - // `longer_fr`. - if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) - { - debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); - - let blame_span_category = self.find_outlives_blame_span( - body, - longer_fr, - NllRegionVariableOrigin::FreeRegion, - shorter_fr, - ); - - // Grow `shorter_fr` until we find some non-local regions. (We - // always will.) We'll call them `shorter_fr+` -- they're ever - // so slightly larger than `shorter_fr`. - let shorter_fr_plus = - self.universal_region_relations.non_local_upper_bounds(&shorter_fr); - debug!( - "try_propagate_universal_region_error: shorter_fr_plus={:?}", - shorter_fr_plus - ); - for &&fr in &shorter_fr_plus { - // Push the constraint `fr-: shorter_fr+` - propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject: ClosureOutlivesSubject::Region(fr_minus), - outlived_free_region: fr, - blame_span: blame_span_category.1, - category: blame_span_category.0, - }); - } - return RegionRelationCheckResult::Propagated; - } - } - - RegionRelationCheckResult::Error - } - - fn check_bound_universal_region( - &self, - longer_fr: RegionVid, - placeholder: ty::PlaceholderRegion, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,); - - let longer_fr_scc = self.constraint_sccs.scc(longer_fr); - debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,); - - // If we have some bound universal region `'a`, then the only - // elements it can contain is itself -- we don't know anything - // else about it! - let error_element = match { - self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element { - RegionElement::Location(_) => true, - RegionElement::RootUniversalRegion(_) => true, - RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1, - }) - } { - Some(v) => v, - None => return, - }; - debug!("check_bound_universal_region: error_element = {:?}", error_element); - - // Find the region that introduced this `error_element`. - errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { - longer_fr, - error_element, - placeholder, - }); - } - - fn check_member_constraints( - &self, - infcx: &InferCtxt<'_, 'tcx>, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - let member_constraints = self.member_constraints.clone(); - for m_c_i in member_constraints.all_indices() { - debug!("check_member_constraint(m_c_i={:?})", m_c_i); - let m_c = &member_constraints[m_c_i]; - let member_region_vid = m_c.member_region_vid; - debug!( - "check_member_constraint: member_region_vid={:?} with value {}", - member_region_vid, - self.region_value_str(member_region_vid), - ); - let choice_regions = member_constraints.choice_regions(m_c_i); - debug!("check_member_constraint: choice_regions={:?}", choice_regions); - - // Did the member region wind up equal to any of the option regions? - if let Some(o) = - choice_regions.iter().find(|&&o_r| self.eval_equal(o_r, m_c.member_region_vid)) - { - debug!("check_member_constraint: evaluated as equal to {:?}", o); - continue; - } - - // If not, report an error. - let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid)); - errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { - span: m_c.definition_span, - hidden_ty: m_c.hidden_ty, - member_region, - }); - } - } - - /// We have a constraint `fr1: fr2` that is not satisfied, where - /// `fr2` represents some universal region. Here, `r` is some - /// region where we know that `fr1: r` and this function has the - /// job of determining whether `r` is "to blame" for the fact that - /// `fr1: fr2` is required. - /// - /// This is true under two conditions: - /// - /// - `r == fr2` - /// - `fr2` is `'static` and `r` is some placeholder in a universe - /// that cannot be named by `fr1`; in that case, we will require - /// that `fr1: 'static` because it is the only way to `fr1: r` to - /// be satisfied. (See `add_incompatible_universe`.) - crate fn provides_universal_region( - &self, - r: RegionVid, - fr1: RegionVid, - fr2: RegionVid, - ) -> bool { - debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2); - let result = { - r == fr2 || { - fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r) - } - }; - debug!("provides_universal_region: result = {:?}", result); - result - } - - /// If `r2` represents a placeholder region, then this returns - /// `true` if `r1` cannot name that placeholder in its - /// value; otherwise, returns `false`. - crate fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool { - debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2); - - match self.definitions[r2].origin { - NllRegionVariableOrigin::Placeholder(placeholder) => { - let universe1 = self.definitions[r1].universe; - debug!( - "cannot_name_value_of: universe1={:?} placeholder={:?}", - universe1, placeholder - ); - universe1.cannot_name(placeholder.universe) - } - - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::FreeRegion - | NllRegionVariableOrigin::Existential { .. } => false, - } - } - - crate fn retrieve_closure_constraint_info( - &self, - body: &Body<'tcx>, - constraint: &OutlivesConstraint<'tcx>, - ) -> BlameConstraint<'tcx> { - let loc = match constraint.locations { - Locations::All(span) => { - return BlameConstraint { - category: constraint.category, - from_closure: false, - span, - variance_info: constraint.variance_info.clone(), - }; - } - Locations::Single(loc) => loc, - }; - - let opt_span_category = - self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)); - opt_span_category - .map(|&(category, span)| BlameConstraint { - category, - from_closure: true, - span: span, - variance_info: constraint.variance_info.clone(), - }) - .unwrap_or(BlameConstraint { - category: constraint.category, - from_closure: false, - span: body.source_info(loc).span, - variance_info: constraint.variance_info.clone(), - }) - } - - /// Finds a good span to blame for the fact that `fr1` outlives `fr2`. - crate fn find_outlives_blame_span( - &self, - body: &Body<'tcx>, - fr1: RegionVid, - fr1_origin: NllRegionVariableOrigin, - fr2: RegionVid, - ) -> (ConstraintCategory, Span) { - let BlameConstraint { category, span, .. } = - self.best_blame_constraint(body, fr1, fr1_origin, |r| { - self.provides_universal_region(r, fr1, fr2) - }); - (category, span) - } - - /// Walks the graph of constraints (where `'a: 'b` is considered - /// an edge `'a -> 'b`) to find all paths from `from_region` to - /// `to_region`. The paths are accumulated into the vector - /// `results`. The paths are stored as a series of - /// `ConstraintIndex` values -- in other words, a list of *edges*. - /// - /// Returns: a series of constraints as well as the region `R` - /// that passed the target test. - crate fn find_constraint_paths_between_regions( - &self, - from_region: RegionVid, - target_test: impl Fn(RegionVid) -> bool, - ) -> Option<(Vec>, RegionVid)> { - let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions); - context[from_region] = Trace::StartRegion; - - // Use a deque so that we do a breadth-first search. We will - // stop at the first match, which ought to be the shortest - // path (fewest constraints). - let mut deque = VecDeque::new(); - deque.push_back(from_region); - - while let Some(r) = deque.pop_front() { - debug!( - "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}", - from_region, - r, - self.region_value_str(r), - ); - - // Check if we reached the region we were looking for. If so, - // we can reconstruct the path that led to it and return it. - if target_test(r) { - let mut result = vec![]; - let mut p = r; - loop { - match context[p].clone() { - Trace::NotVisited => { - bug!("found unvisited region {:?} on path to {:?}", p, r) - } - - Trace::FromOutlivesConstraint(c) => { - p = c.sup; - result.push(c); - } - - Trace::StartRegion => { - result.reverse(); - return Some((result, r)); - } - } - } - } - - // Otherwise, walk over the outgoing constraints and - // enqueue any regions we find, keeping track of how we - // reached them. - - // A constraint like `'r: 'x` can come from our constraint - // graph. - let fr_static = self.universal_regions.fr_static; - let outgoing_edges_from_graph = - self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static); - - // Always inline this closure because it can be hot. - let mut handle_constraint = #[inline(always)] - |constraint: OutlivesConstraint<'tcx>| { - debug_assert_eq!(constraint.sup, r); - let sub_region = constraint.sub; - if let Trace::NotVisited = context[sub_region] { - context[sub_region] = Trace::FromOutlivesConstraint(constraint); - deque.push_back(sub_region); - } - }; - - // This loop can be hot. - for constraint in outgoing_edges_from_graph { - handle_constraint(constraint); - } - - // Member constraints can also give rise to `'r: 'x` edges that - // were not part of the graph initially, so watch out for those. - // (But they are extremely rare; this loop is very cold.) - for constraint in self.applied_member_constraints(r) { - let p_c = &self.member_constraints[constraint.member_constraint_index]; - let constraint = OutlivesConstraint { - sup: r, - sub: constraint.min_choice, - locations: Locations::All(p_c.definition_span), - category: ConstraintCategory::OpaqueType, - variance_info: ty::VarianceDiagInfo::default(), - }; - handle_constraint(constraint); - } - } - - None - } - - /// Finds some region R such that `fr1: R` and `R` is live at `elem`. - crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { - debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem); - debug!("find_sub_region_live_at: {:?} is in scc {:?}", fr1, self.constraint_sccs.scc(fr1)); - debug!( - "find_sub_region_live_at: {:?} is in universe {:?}", - fr1, - self.scc_universes[self.constraint_sccs.scc(fr1)] - ); - self.find_constraint_paths_between_regions(fr1, |r| { - // First look for some `r` such that `fr1: r` and `r` is live at `elem` - debug!( - "find_sub_region_live_at: liveness_constraints for {:?} are {:?}", - r, - self.liveness_constraints.region_value_str(r), - ); - self.liveness_constraints.contains(r, elem) - }) - .or_else(|| { - // If we fail to find that, we may find some `r` such that - // `fr1: r` and `r` is a placeholder from some universe - // `fr1` cannot name. This would force `fr1` to be - // `'static`. - self.find_constraint_paths_between_regions(fr1, |r| { - self.cannot_name_placeholder(fr1, r) - }) - }) - .or_else(|| { - // If we fail to find THAT, it may be that `fr1` is a - // placeholder that cannot "fit" into its SCC. In that - // case, there should be some `r` where `fr1: r` and `fr1` is a - // placeholder that `r` cannot name. We can blame that - // edge. - // - // Remember that if `R1: R2`, then the universe of R1 - // must be able to name the universe of R2, because R2 will - // be at least `'empty(Universe(R2))`, and `R1` must be at - // larger than that. - self.find_constraint_paths_between_regions(fr1, |r| { - self.cannot_name_placeholder(r, fr1) - }) - }) - .map(|(_path, r)| r) - .unwrap() - } - - /// Get the region outlived by `longer_fr` and live at `element`. - crate fn region_from_element( - &self, - longer_fr: RegionVid, - element: &RegionElement, - ) -> RegionVid { - match *element { - RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l), - RegionElement::RootUniversalRegion(r) => r, - RegionElement::PlaceholderRegion(error_placeholder) => self - .definitions - .iter_enumerated() - .find_map(|(r, definition)| match definition.origin { - NllRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r), - _ => None, - }) - .unwrap(), - } - } - - /// Get the region definition of `r`. - crate fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> { - &self.definitions[r] - } - - /// Check if the SCC of `r` contains `upper`. - crate fn upper_bound_in_region_scc(&self, r: RegionVid, upper: RegionVid) -> bool { - let r_scc = self.constraint_sccs.scc(r); - self.scc_values.contains(r_scc, upper) - } - - crate fn universal_regions(&self) -> &UniversalRegions<'tcx> { - self.universal_regions.as_ref() - } - - /// Tries to find the best constraint to blame for the fact that - /// `R: from_region`, where `R` is some region that meets - /// `target_test`. This works by following the constraint graph, - /// creating a constraint path that forces `R` to outlive - /// `from_region`, and then finding the best choices within that - /// path to blame. - crate fn best_blame_constraint( - &self, - body: &Body<'tcx>, - from_region: RegionVid, - from_region_origin: NllRegionVariableOrigin, - target_test: impl Fn(RegionVid) -> bool, - ) -> BlameConstraint<'tcx> { - debug!( - "best_blame_constraint(from_region={:?}, from_region_origin={:?})", - from_region, from_region_origin - ); - - // Find all paths - let (path, target_region) = - self.find_constraint_paths_between_regions(from_region, target_test).unwrap(); - debug!( - "best_blame_constraint: path={:#?}", - path.iter() - .map(|c| format!( - "{:?} ({:?}: {:?})", - c, - self.constraint_sccs.scc(c.sup), - self.constraint_sccs.scc(c.sub), - )) - .collect::>() - ); - - // Classify each of the constraints along the path. - let mut categorized_path: Vec> = path - .iter() - .map(|constraint| { - if constraint.category == ConstraintCategory::ClosureBounds { - self.retrieve_closure_constraint_info(body, &constraint) - } else { - BlameConstraint { - category: constraint.category, - from_closure: false, - span: constraint.locations.span(body), - variance_info: constraint.variance_info.clone(), - } - } - }) - .collect(); - debug!("best_blame_constraint: categorized_path={:#?}", categorized_path); - - // To find the best span to cite, we first try to look for the - // final constraint that is interesting and where the `sup` is - // not unified with the ultimate target region. The reason - // for this is that we have a chain of constraints that lead - // from the source to the target region, something like: - // - // '0: '1 ('0 is the source) - // '1: '2 - // '2: '3 - // '3: '4 - // '4: '5 - // '5: '6 ('6 is the target) - // - // Some of those regions are unified with `'6` (in the same - // SCC). We want to screen those out. After that point, the - // "closest" constraint we have to the end is going to be the - // most likely to be the point where the value escapes -- but - // we still want to screen for an "interesting" point to - // highlight (e.g., a call site or something). - let target_scc = self.constraint_sccs.scc(target_region); - let mut range = 0..path.len(); - - // As noted above, when reporting an error, there is typically a chain of constraints - // leading from some "source" region which must outlive some "target" region. - // In most cases, we prefer to "blame" the constraints closer to the target -- - // but there is one exception. When constraints arise from higher-ranked subtyping, - // we generally prefer to blame the source value, - // as the "target" in this case tends to be some type annotation that the user gave. - // Therefore, if we find that the region origin is some instantiation - // of a higher-ranked region, we start our search from the "source" point - // rather than the "target", and we also tweak a few other things. - // - // An example might be this bit of Rust code: - // - // ```rust - // let x: fn(&'static ()) = |_| {}; - // let y: for<'a> fn(&'a ()) = x; - // ``` - // - // In MIR, this will be converted into a combination of assignments and type ascriptions. - // In particular, the 'static is imposed through a type ascription: - // - // ```rust - // x = ...; - // AscribeUserType(x, fn(&'static ()) - // y = x; - // ``` - // - // We wind up ultimately with constraints like - // - // ```rust - // !a: 'temp1 // from the `y = x` statement - // 'temp1: 'temp2 - // 'temp2: 'static // from the AscribeUserType - // ``` - // - // and here we prefer to blame the source (the y = x statement). - let blame_source = match from_region_origin { - NllRegionVariableOrigin::FreeRegion - | NllRegionVariableOrigin::Existential { from_forall: false } => true, - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::Placeholder(_) - | NllRegionVariableOrigin::Existential { from_forall: true } => false, - }; - - let find_region = |i: &usize| { - let constraint = &path[*i]; - - let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup); - - if blame_source { - match categorized_path[*i].category { - ConstraintCategory::OpaqueType - | ConstraintCategory::Boring - | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => false, - ConstraintCategory::TypeAnnotation - | ConstraintCategory::Return(_) - | ConstraintCategory::Yield => true, - _ => constraint_sup_scc != target_scc, - } - } else { - match categorized_path[*i].category { - ConstraintCategory::OpaqueType - | ConstraintCategory::Boring - | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => false, - _ => true, - } - } - }; - - let best_choice = - if blame_source { range.rev().find(find_region) } else { range.find(find_region) }; - - debug!( - "best_blame_constraint: best_choice={:?} blame_source={}", - best_choice, blame_source - ); - - if let Some(i) = best_choice { - if let Some(next) = categorized_path.get(i + 1) { - if matches!(categorized_path[i].category, ConstraintCategory::Return(_)) - && next.category == ConstraintCategory::OpaqueType - { - // The return expression is being influenced by the return type being - // impl Trait, point at the return type and not the return expr. - return next.clone(); - } - } - - if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal) - { - let field = categorized_path.iter().find_map(|p| { - if let ConstraintCategory::ClosureUpvar(f) = p.category { - Some(f) - } else { - None - } - }); - - if let Some(field) = field { - categorized_path[i].category = - ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)); - } - } - - return categorized_path[i].clone(); - } - - // If that search fails, that is.. unusual. Maybe everything - // is in the same SCC or something. In that case, find what - // appears to be the most interesting point to report to the - // user via an even more ad-hoc guess. - categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category)); - debug!("`: sorted_path={:#?}", categorized_path); - - categorized_path.remove(0) - } - - crate fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - self.universe_causes[universe].clone() - } -} - -impl<'tcx> RegionDefinition<'tcx> { - fn new(universe: ty::UniverseIndex, rv_origin: RegionVariableOrigin) -> Self { - // Create a new region definition. Note that, for free - // regions, the `external_name` field gets updated later in - // `init_universal_regions`. - - let origin = match rv_origin { - RegionVariableOrigin::Nll(origin) => origin, - _ => NllRegionVariableOrigin::Existential { from_forall: false }, - }; - - Self { origin, universe, external_name: None } - } -} - -pub trait ClosureRegionRequirementsExt<'tcx> { - fn apply_requirements( - &self, - tcx: TyCtxt<'tcx>, - closure_def_id: DefId, - closure_substs: SubstsRef<'tcx>, - ) -> Vec>; -} - -impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx> { - /// Given an instance T of the closure type, this method - /// instantiates the "extra" requirements that we computed for the - /// closure into the inference context. This has the effect of - /// adding new outlives obligations to existing variables. - /// - /// As described on `ClosureRegionRequirements`, the extra - /// requirements are expressed in terms of regionvids that index - /// into the free regions that appear on the closure type. So, to - /// do this, we first copy those regions out from the type T into - /// a vector. Then we can just index into that vector to extract - /// out the corresponding region from T and apply the - /// requirements. - fn apply_requirements( - &self, - tcx: TyCtxt<'tcx>, - closure_def_id: DefId, - closure_substs: SubstsRef<'tcx>, - ) -> Vec> { - debug!( - "apply_requirements(closure_def_id={:?}, closure_substs={:?})", - closure_def_id, closure_substs - ); - - // Extract the values of the free regions in `closure_substs` - // into a vector. These are the regions that we will be - // relating to one another. - let closure_mapping = &UniversalRegions::closure_mapping( - tcx, - closure_substs, - self.num_external_vids, - tcx.closure_base_def_id(closure_def_id), - ); - debug!("apply_requirements: closure_mapping={:?}", closure_mapping); - - // Create the predicates. - self.outlives_requirements - .iter() - .map(|outlives_requirement| { - let outlived_region = closure_mapping[outlives_requirement.outlived_free_region]; - - match outlives_requirement.subject { - ClosureOutlivesSubject::Region(region) => { - let region = closure_mapping[region]; - debug!( - "apply_requirements: region={:?} \ - outlived_region={:?} \ - outlives_requirement={:?}", - region, outlived_region, outlives_requirement, - ); - ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region)) - } - - ClosureOutlivesSubject::Ty(ty) => { - debug!( - "apply_requirements: ty={:?} \ - outlived_region={:?} \ - outlives_requirement={:?}", - ty, outlived_region, outlives_requirement, - ); - ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)) - } - } - }) - .collect() - } -} - -#[derive(Clone, Debug)] -pub struct BlameConstraint<'tcx> { - pub category: ConstraintCategory, - pub from_closure: bool, - pub span: Span, - pub variance_info: ty::VarianceDiagInfo<'tcx>, -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -use rustc_data_structures::vec_map::VecMap; -use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; -use rustc_span::Span; -use rustc_trait_selection::opaque_types::InferCtxtExt; - -use super::RegionInferenceContext; - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Resolve any opaque types that were encountered while borrow checking - /// this item. This is then used to get the type in the `type_of` query. - /// - /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. - /// This is lowered to give HIR something like - /// - /// type f<'a>::_Return<'_a> = impl Sized + '_a; - /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x } - /// - /// When checking the return type record the type from the return and the - /// type used in the return value. In this case they might be `_Return<'1>` - /// and `&'2 i32` respectively. - /// - /// Once we to this method, we have completed region inference and want to - /// call `infer_opaque_definition_from_instantiation` to get the inferred - /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation` - /// compares lifetimes directly, so we need to map the inference variables - /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`. - /// - /// First we map all the lifetimes in the concrete type to an equal - /// universal region that occurs in the concrete type's substs, in this case - /// this would result in `&'1 i32`. We only consider regions in the substs - /// in case there is an equal region that does not. For example, this should - /// be allowed: - /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` - /// - /// Then we map the regions in both the type and the subst to their - /// `external_name` giving `concrete_type = &'a i32`, - /// `substs = ['static, 'a]`. This will then allow - /// `infer_opaque_definition_from_instantiation` to determine that - /// `_Return<'_a> = &'_a i32`. - /// - /// There's a slight complication around closures. Given - /// `fn f<'a: 'a>() { || {} }` the closure's type is something like - /// `f::<'a>::{{closure}}`. The region parameter from f is essentially - /// ignored by type checking so ends up being inferred to an empty region. - /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, - /// which has no `external_name` in which case we use `'empty` as the - /// region to pass to `infer_opaque_definition_from_instantiation`. - #[instrument(skip(self, infcx))] - pub(in crate::borrow_check) fn infer_opaque_types( - &self, - infcx: &InferCtxt<'_, 'tcx>, - opaque_ty_decls: VecMap, Ty<'tcx>>, - span: Span, - ) -> VecMap, Ty<'tcx>> { - opaque_ty_decls - .into_iter() - .map(|(opaque_type_key, concrete_type)| { - let substs = opaque_type_key.substs; - debug!(?concrete_type, ?substs); - - let mut subst_regions = vec![self.universal_regions.fr_static]; - let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| { - let vid = self.universal_regions.to_region_vid(region); - subst_regions.push(vid); - self.definitions[vid].external_name.unwrap_or_else(|| { - infcx - .tcx - .sess - .delay_span_bug(span, "opaque type with non-universal region substs"); - infcx.tcx.lifetimes.re_static - }) - }); - - subst_regions.sort(); - subst_regions.dedup(); - - let universal_concrete_type = - infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region { - ty::ReVar(vid) => subst_regions - .iter() - .find(|ur_vid| self.eval_equal(vid, **ur_vid)) - .and_then(|ur_vid| self.definitions[*ur_vid].external_name) - .unwrap_or(infcx.tcx.lifetimes.re_root_empty), - _ => region, - }); - - debug!(?universal_concrete_type, ?universal_substs); - - let opaque_type_key = - OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }; - let remapped_type = infcx.infer_opaque_definition_from_instantiation( - opaque_type_key, - universal_concrete_type, - span, - ); - (opaque_type_key, remapped_type) - }) - .collect() - } - - /// Map the regions in the type to named regions. This is similar to what - /// `infer_opaque_types` does, but can infer any universal region, not only - /// ones from the substs for the opaque type. It also doesn't double check - /// that the regions produced are in fact equal to the named region they are - /// replaced with. This is fine because this function is only to improve the - /// region names in error messages. - pub(in crate::borrow_check) fn name_regions(&self, tcx: TyCtxt<'tcx>, ty: T) -> T - where - T: TypeFoldable<'tcx>, - { - tcx.fold_regions(ty, &mut false, |region, _| match *region { - ty::ReVar(vid) => { - // Find something that we can name - let upper_bound = self.approx_universal_upper_bound(vid); - self.definitions[upper_bound].external_name.unwrap_or(region) - } - _ => region, - }) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -use crate::borrow_check::constraints::ConstraintSccIndex; -use crate::borrow_check::RegionInferenceContext; -use itertools::Itertools; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::graph::WithSuccessors; -use rustc_middle::ty::RegionVid; -use std::ops::Range; -use std::rc::Rc; - -crate struct ReverseSccGraph { - graph: VecGraph, - /// For each SCC, the range of `universal_regions` that use that SCC as - /// their value. - scc_regions: FxHashMap>, - /// All of the universal regions, in grouped so that `scc_regions` can - /// index into here. - universal_regions: Vec, -} - -impl ReverseSccGraph { - /// Find all universal regions that are required to outlive the given SCC. - pub(super) fn upper_bounds<'a>( - &'a self, - scc0: ConstraintSccIndex, - ) -> impl Iterator + 'a { - let mut duplicates = FxHashSet::default(); - self.graph - .depth_first_search(scc0) - .flat_map(move |scc1| { - self.scc_regions - .get(&scc1) - .map_or(&[][..], |range| &self.universal_regions[range.clone()]) - }) - .copied() - .filter(move |r| duplicates.insert(*r)) - } -} - -impl RegionInferenceContext<'_> { - /// Compute and return the reverse SCC-based constraint graph (lazily). - pub(super) fn reverse_scc_graph(&mut self) -> Rc { - if let Some(g) = &self.rev_scc_graph { - return g.clone(); - } - - let graph = self.constraint_sccs.reverse(); - let mut paired_scc_regions = self - .universal_regions - .universal_regions() - .map(|region| (self.constraint_sccs.scc(region), region)) - .collect_vec(); - paired_scc_regions.sort(); - let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); - - let mut scc_regions = FxHashMap::default(); - let mut start = 0; - for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) { - let group_size = group.count(); - scc_regions.insert(scc, start..start + group_size); - start += group_size; - } - - let rev_graph = Rc::new(ReverseSccGraph { graph, scc_regions, universal_regions }); - self.rev_scc_graph = Some(rev_graph.clone()); - rev_graph - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/values.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/values.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/values.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/region_infer/values.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,496 +0,0 @@ -use rustc_data_structures::fx::FxIndexSet; -use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; -use rustc_index::vec::Idx; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::{BasicBlock, Body, Location}; -use rustc_middle::ty::{self, RegionVid}; -use std::fmt::Debug; -use std::rc::Rc; - -/// Maps between a `Location` and a `PointIndex` (and vice versa). -crate struct RegionValueElements { - /// For each basic block, how many points are contained within? - statements_before_block: IndexVec, - - /// Map backward from each point to the basic block that it - /// belongs to. - basic_blocks: IndexVec, - - num_points: usize, -} - -impl RegionValueElements { - crate fn new(body: &Body<'_>) -> Self { - let mut num_points = 0; - let statements_before_block: IndexVec = body - .basic_blocks() - .iter() - .map(|block_data| { - let v = num_points; - num_points += block_data.statements.len() + 1; - v - }) - .collect(); - debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block); - debug!("RegionValueElements: num_points={:#?}", num_points); - - let mut basic_blocks = IndexVec::with_capacity(num_points); - for (bb, bb_data) in body.basic_blocks().iter_enumerated() { - basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); - } - - Self { statements_before_block, basic_blocks, num_points } - } - - /// Total number of point indices - crate fn num_points(&self) -> usize { - self.num_points - } - - /// Converts a `Location` into a `PointIndex`. O(1). - crate fn point_from_location(&self, location: Location) -> PointIndex { - let Location { block, statement_index } = location; - let start_index = self.statements_before_block[block]; - PointIndex::new(start_index + statement_index) - } - - /// Converts a `Location` into a `PointIndex`. O(1). - crate fn entry_point(&self, block: BasicBlock) -> PointIndex { - let start_index = self.statements_before_block[block]; - PointIndex::new(start_index) - } - - /// Converts a `PointIndex` back to a location. O(1). - crate fn to_location(&self, index: PointIndex) -> Location { - assert!(index.index() < self.num_points); - let block = self.basic_blocks[index]; - let start_index = self.statements_before_block[block]; - let statement_index = index.index() - start_index; - Location { block, statement_index } - } - - /// Sometimes we get point-indices back from bitsets that may be - /// out of range (because they round up to the nearest 2^N number - /// of bits). Use this function to filter such points out if you - /// like. - crate fn point_in_range(&self, index: PointIndex) -> bool { - index.index() < self.num_points - } - - /// Pushes all predecessors of `index` onto `stack`. - crate fn push_predecessors( - &self, - body: &Body<'_>, - index: PointIndex, - stack: &mut Vec, - ) { - let Location { block, statement_index } = self.to_location(index); - if statement_index == 0 { - // If this is a basic block head, then the predecessors are - // the terminators of other basic blocks - stack.extend( - body.predecessors()[block] - .iter() - .map(|&pred_bb| body.terminator_loc(pred_bb)) - .map(|pred_loc| self.point_from_location(pred_loc)), - ); - } else { - // Otherwise, the pred is just the previous statement - stack.push(PointIndex::new(index.index() - 1)); - } - } -} - -rustc_index::newtype_index! { - /// A single integer representing a `Location` in the MIR control-flow - /// graph. Constructed efficiently from `RegionValueElements`. - pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" } -} - -rustc_index::newtype_index! { - /// A single integer representing a `ty::Placeholder`. - pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" } -} - -/// An individual element in a region value -- the value of a -/// particular region variable consists of a set of these elements. -#[derive(Debug, Clone)] -crate enum RegionElement { - /// A point in the control-flow graph. - Location(Location), - - /// A universally quantified region from the root universe (e.g., - /// a lifetime parameter). - RootUniversalRegion(RegionVid), - - /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)` - /// type). - PlaceholderRegion(ty::PlaceholderRegion), -} - -/// When we initially compute liveness, we use a bit matrix storing -/// points for each region-vid. -crate struct LivenessValues { - elements: Rc, - points: SparseBitMatrix, -} - -impl LivenessValues { - /// Creates a new set of "region values" that tracks causal information. - /// Each of the regions in num_region_variables will be initialized with an - /// empty set of points and no causal information. - crate fn new(elements: Rc) -> Self { - Self { points: SparseBitMatrix::new(elements.num_points), elements } - } - - /// Iterate through each region that has a value in this set. - crate fn rows(&self) -> impl Iterator { - self.points.rows() - } - - /// Adds the given element to the value for the given region. Returns whether - /// the element is newly added (i.e., was not already present). - crate fn add_element(&mut self, row: N, location: Location) -> bool { - debug!("LivenessValues::add(r={:?}, location={:?})", row, location); - let index = self.elements.point_from_location(location); - self.points.insert(row, index) - } - - /// Adds all the elements in the given bit array into the given - /// region. Returns whether any of them are newly added. - crate fn add_elements(&mut self, row: N, locations: &HybridBitSet) -> bool { - debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); - self.points.union_row(row, locations) - } - - /// Adds all the control-flow points to the values for `r`. - crate fn add_all_points(&mut self, row: N) { - self.points.insert_all_into_row(row); - } - - /// Returns `true` if the region `r` contains the given element. - crate fn contains(&self, row: N, location: Location) -> bool { - let index = self.elements.point_from_location(location); - self.points.contains(row, index) - } - - /// Returns a "pretty" string value of the region. Meant for debugging. - crate fn region_value_str(&self, r: N) -> String { - region_value_str( - self.points - .row(r) - .into_iter() - .flat_map(|set| set.iter()) - .take_while(|&p| self.elements.point_in_range(p)) - .map(|p| self.elements.to_location(p)) - .map(RegionElement::Location), - ) - } -} - -/// Maps from `ty::PlaceholderRegion` values that are used in the rest of -/// rustc to the internal `PlaceholderIndex` values that are used in -/// NLL. -#[derive(Default)] -crate struct PlaceholderIndices { - indices: FxIndexSet, -} - -impl PlaceholderIndices { - crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { - let (index, _) = self.indices.insert_full(placeholder); - index.into() - } - - crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { - self.indices.get_index_of(&placeholder).unwrap().into() - } - - crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion { - self.indices[placeholder.index()] - } - - crate fn len(&self) -> usize { - self.indices.len() - } -} - -/// Stores the full values for a set of regions (in contrast to -/// `LivenessValues`, which only stores those points in the where a -/// region is live). The full value for a region may contain points in -/// the CFG, but also free regions as well as bound universe -/// placeholders. -/// -/// Example: -/// -/// ```text -/// fn foo(x: &'a u32) -> &'a u32 { -/// let y: &'0 u32 = x; // let's call this `'0` -/// y -/// } -/// ``` -/// -/// Here, the variable `'0` would contain the free region `'a`, -/// because (since it is returned) it must live for at least `'a`. But -/// it would also contain various points from within the function. -#[derive(Clone)] -crate struct RegionValues { - elements: Rc, - placeholder_indices: Rc, - points: SparseBitMatrix, - free_regions: SparseBitMatrix, - - /// Placeholders represent bound regions -- so something like `'a` - /// in for<'a> fn(&'a u32)`. - placeholders: SparseBitMatrix, -} - -impl RegionValues { - /// Creates a new set of "region values" that tracks causal information. - /// Each of the regions in num_region_variables will be initialized with an - /// empty set of points and no causal information. - crate fn new( - elements: &Rc, - num_universal_regions: usize, - placeholder_indices: &Rc, - ) -> Self { - let num_placeholders = placeholder_indices.len(); - Self { - elements: elements.clone(), - points: SparseBitMatrix::new(elements.num_points), - placeholder_indices: placeholder_indices.clone(), - free_regions: SparseBitMatrix::new(num_universal_regions), - placeholders: SparseBitMatrix::new(num_placeholders), - } - } - - /// Adds the given element to the value for the given region. Returns whether - /// the element is newly added (i.e., was not already present). - crate fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool { - debug!("add(r={:?}, elem={:?})", r, elem); - elem.add_to_row(self, r) - } - - /// Adds all the control-flow points to the values for `r`. - crate fn add_all_points(&mut self, r: N) { - self.points.insert_all_into_row(r); - } - - /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to: - /// r_from`). - crate fn add_region(&mut self, r_to: N, r_from: N) -> bool { - self.points.union_rows(r_from, r_to) - | self.free_regions.union_rows(r_from, r_to) - | self.placeholders.union_rows(r_from, r_to) - } - - /// Returns `true` if the region `r` contains the given element. - crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool { - elem.contained_in_row(self, r) - } - - /// `self[to] |= values[from]`, essentially: that is, take all the - /// elements for the region `from` from `values` and add them to - /// the region `to` in `self`. - crate fn merge_liveness(&mut self, to: N, from: M, values: &LivenessValues) { - if let Some(set) = values.points.row(from) { - self.points.union_row(to, set); - } - } - - /// Returns `true` if `sup_region` contains all the CFG points that - /// `sub_region` contains. Ignores universal regions. - crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool { - if let Some(sub_row) = self.points.row(sub_region) { - if let Some(sup_row) = self.points.row(sup_region) { - sup_row.superset(sub_row) - } else { - // sup row is empty, so sub row must be empty - sub_row.is_empty() - } - } else { - // sub row is empty, always true - true - } - } - - /// Returns the locations contained within a given region `r`. - crate fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator + 'a { - self.points.row(r).into_iter().flat_map(move |set| { - set.iter() - .take_while(move |&p| self.elements.point_in_range(p)) - .map(move |p| self.elements.to_location(p)) - }) - } - - /// Returns just the universal regions that are contained in a given region's value. - crate fn universal_regions_outlived_by<'a>( - &'a self, - r: N, - ) -> impl Iterator + 'a { - self.free_regions.row(r).into_iter().flat_map(|set| set.iter()) - } - - /// Returns all the elements contained in a given region's value. - crate fn placeholders_contained_in<'a>( - &'a self, - r: N, - ) -> impl Iterator + 'a { - self.placeholders - .row(r) - .into_iter() - .flat_map(|set| set.iter()) - .map(move |p| self.placeholder_indices.lookup_placeholder(p)) - } - - /// Returns all the elements contained in a given region's value. - crate fn elements_contained_in<'a>(&'a self, r: N) -> impl Iterator + 'a { - let points_iter = self.locations_outlived_by(r).map(RegionElement::Location); - - let free_regions_iter = - self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion); - - let placeholder_universes_iter = - self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion); - - points_iter.chain(free_regions_iter).chain(placeholder_universes_iter) - } - - /// Returns a "pretty" string value of the region. Meant for debugging. - crate fn region_value_str(&self, r: N) -> String { - region_value_str(self.elements_contained_in(r)) - } -} - -crate trait ToElementIndex: Debug + Copy { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool; - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool; -} - -impl ToElementIndex for Location { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - let index = values.elements.point_from_location(self); - values.points.insert(row, index) - } - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - let index = values.elements.point_from_location(self); - values.points.contains(row, index) - } -} - -impl ToElementIndex for RegionVid { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - values.free_regions.insert(row, self) - } - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - values.free_regions.contains(row, self) - } -} - -impl ToElementIndex for ty::PlaceholderRegion { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - let index = values.placeholder_indices.lookup_index(self); - values.placeholders.insert(row, index) - } - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - let index = values.placeholder_indices.lookup_index(self); - values.placeholders.contains(row, index) - } -} - -crate fn location_set_str( - elements: &RegionValueElements, - points: impl IntoIterator, -) -> String { - region_value_str( - points - .into_iter() - .take_while(|&p| elements.point_in_range(p)) - .map(|p| elements.to_location(p)) - .map(RegionElement::Location), - ) -} - -fn region_value_str(elements: impl IntoIterator) -> String { - let mut result = String::new(); - result.push('{'); - - // Set to Some(l1, l2) when we have observed all the locations - // from l1..=l2 (inclusive) but not yet printed them. This - // gets extended if we then see l3 where l3 is the successor - // to l2. - let mut open_location: Option<(Location, Location)> = None; - - let mut sep = ""; - let mut push_sep = |s: &mut String| { - s.push_str(sep); - sep = ", "; - }; - - for element in elements { - match element { - RegionElement::Location(l) => { - if let Some((location1, location2)) = open_location { - if location2.block == l.block - && location2.statement_index == l.statement_index - 1 - { - open_location = Some((location1, l)); - continue; - } - - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - } - - open_location = Some((l, l)); - } - - RegionElement::RootUniversalRegion(fr) => { - if let Some((location1, location2)) = open_location { - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - open_location = None; - } - - push_sep(&mut result); - result.push_str(&format!("{:?}", fr)); - } - - RegionElement::PlaceholderRegion(placeholder) => { - if let Some((location1, location2)) = open_location { - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - open_location = None; - } - - push_sep(&mut result); - result.push_str(&format!("{:?}", placeholder)); - } - } - } - - if let Some((location1, location2)) = open_location { - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - } - - result.push('}'); - - return result; - - fn push_location_range(str: &mut String, location1: Location, location2: Location) { - if location1 == location2 { - str.push_str(&format!("{:?}", location1)); - } else { - assert_eq!(location1.block, location2.block); - str.push_str(&format!( - "{:?}[{}..={}]", - location1.block, location1.statement_index, location2.statement_index - )); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/renumber.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/renumber.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/renumber.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/renumber.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -use rustc_index::vec::IndexVec; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; -use rustc_middle::mir::visit::{MutVisitor, TyContext}; -use rustc_middle::mir::{Body, Location, PlaceElem, Promoted}; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; - -/// Replaces all free regions appearing in the MIR with fresh -/// inference variables, returning the number of variables created. -pub fn renumber_mir<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, - body: &mut Body<'tcx>, - promoted: &mut IndexVec>, -) { - debug!("renumber_mir()"); - debug!("renumber_mir: body.arg_count={:?}", body.arg_count); - - let mut visitor = NllVisitor { infcx }; - - for body in promoted.iter_mut() { - visitor.visit_body(body); - } - - visitor.visit_body(body); -} - -/// Replaces all regions appearing in `value` with fresh inference -/// variables. -pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("renumber_regions(value={:?})", value); - - infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { - let origin = NllRegionVariableOrigin::Existential { from_forall: false }; - infcx.next_nll_region_var(origin) - }) -} - -struct NllVisitor<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, -} - -impl<'a, 'tcx> NllVisitor<'a, 'tcx> { - fn renumber_regions(&mut self, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - renumber_regions(self.infcx, value) - } -} - -impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { - debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context); - - *ty = self.renumber_regions(ty); - - debug!("visit_ty: ty={:?}", ty); - } - - fn process_projection_elem( - &mut self, - elem: PlaceElem<'tcx>, - _: Location, - ) -> Option> { - if let PlaceElem::Field(field, ty) = elem { - let new_ty = self.renumber_regions(ty); - - if new_ty != ty { - return Some(PlaceElem::Field(field, new_ty)); - } - } - - None - } - - fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { - debug!("visit_substs(substs={:?}, location={:?})", substs, location); - - *substs = self.renumber_regions(*substs); - - debug!("visit_substs: substs={:?}", substs); - } - - fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) { - debug!("visit_region(region={:?}, location={:?})", region, location); - - let old_region = *region; - *region = self.renumber_regions(&old_region); - - debug!("visit_region: region={:?}", region); - } - - fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) { - *constant = self.renumber_regions(&*constant); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -use std::fmt; - -use rustc_infer::infer::canonical::Canonical; -use rustc_infer::traits::query::NoSolution; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{self, ToPredicate, TypeFoldable}; -use rustc_span::Span; -use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; -use rustc_trait_selection::traits::query::Fallible; - -use crate::borrow_check::diagnostics::{ToUniverseInfo, UniverseInfo}; - -use super::{Locations, NormalizeLocation, TypeChecker}; - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - /// Given some operation `op` that manipulates types, proves - /// predicates, or otherwise uses the inference context, executes - /// `op` and then executes all the further obligations that `op` - /// returns. This will yield a set of outlives constraints amongst - /// regions which are extracted and stored as having occurred at - /// `locations`. - /// - /// **Any `rustc_infer::infer` operations that might generate region - /// constraints should occur within this method so that those - /// constraints can be properly localized!** - pub(super) fn fully_perform_op( - &mut self, - locations: Locations, - category: ConstraintCategory, - op: Op, - ) -> Fallible - where - Op: type_op::TypeOp<'tcx, Output = R>, - Canonical<'tcx, Op>: ToUniverseInfo<'tcx>, - { - let old_universe = self.infcx.universe(); - - let TypeOpOutput { output, constraints, canonicalized_query } = - op.fully_perform(self.infcx)?; - - if let Some(data) = &constraints { - self.push_region_constraints(locations, category, data); - } - - let universe = self.infcx.universe(); - - if old_universe != universe { - let universe_info = match canonicalized_query { - Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe), - None => UniverseInfo::other(), - }; - for u in old_universe..universe { - let info_universe = - self.borrowck_context.constraints.universe_causes.push(universe_info.clone()); - assert_eq!(u.as_u32() + 1, info_universe.as_u32()); - } - } - - Ok(output) - } - - pub(super) fn instantiate_canonical_with_fresh_inference_vars( - &mut self, - span: Span, - canonical: &Canonical<'tcx, T>, - ) -> T - where - T: TypeFoldable<'tcx>, - { - let (instantiated, _) = - self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); - - for _ in 0..canonical.max_universe.as_u32() { - let info = UniverseInfo::other(); - self.borrowck_context.constraints.universe_causes.push(info); - } - - instantiated - } - - pub(super) fn prove_trait_ref( - &mut self, - trait_ref: ty::TraitRef<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) { - self.prove_predicates( - Some(ty::PredicateKind::Trait(ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - })), - locations, - category, - ); - } - - pub(super) fn normalize_and_prove_instantiated_predicates( - &mut self, - instantiated_predicates: ty::InstantiatedPredicates<'tcx>, - locations: Locations, - ) { - for predicate in instantiated_predicates.predicates { - let predicate = self.normalize(predicate, locations); - self.prove_predicate(predicate, locations, ConstraintCategory::Boring); - } - } - - pub(super) fn prove_predicates( - &mut self, - predicates: impl IntoIterator>, - locations: Locations, - category: ConstraintCategory, - ) { - for predicate in predicates { - let predicate = predicate.to_predicate(self.tcx()); - debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,); - - self.prove_predicate(predicate, locations, category); - } - } - - pub(super) fn prove_predicate( - &mut self, - predicate: ty::Predicate<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) { - debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,); - - let param_env = self.param_env; - self.fully_perform_op( - locations, - category, - param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)), - ) - .unwrap_or_else(|NoSolution| { - span_mirbug!(self, NoSolution, "could not prove {:?}", predicate); - }) - } - - pub(super) fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T - where - T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, - { - debug!("normalize(value={:?}, location={:?})", value, location); - let param_env = self.param_env; - self.fully_perform_op( - location.to_locations(), - ConstraintCategory::Boring, - param_env.and(type_op::normalize::Normalize::new(value)), - ) - .unwrap_or_else(|NoSolution| { - span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value); - value - }) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,178 +0,0 @@ -use rustc_infer::infer::canonical::QueryOutlivesConstraint; -use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::outlives::env::RegionBoundPairs; -use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; -use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; -use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::DUMMY_SP; - -use crate::borrow_check::{ - constraints::OutlivesConstraint, - nll::ToRegionVid, - region_infer::TypeTest, - type_check::{Locations, MirTypeckRegionConstraints}, - universal_regions::UniversalRegions, -}; - -crate struct ConstraintConversion<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - tcx: TyCtxt<'tcx>, - universal_regions: &'a UniversalRegions<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: Option>, - param_env: ty::ParamEnv<'tcx>, - locations: Locations, - category: ConstraintCategory, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, -} - -impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { - crate fn new( - infcx: &'a InferCtxt<'a, 'tcx>, - universal_regions: &'a UniversalRegions<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: Option>, - param_env: ty::ParamEnv<'tcx>, - locations: Locations, - category: ConstraintCategory, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - ) -> Self { - Self { - infcx, - tcx: infcx.tcx, - universal_regions, - region_bound_pairs, - implicit_region_bound, - param_env, - locations, - category, - constraints, - } - } - - pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { - debug!("convert_all(query_constraints={:#?})", query_constraints); - - let QueryRegionConstraints { outlives, member_constraints } = query_constraints; - - // Annoying: to invoke `self.to_region_vid`, we need access to - // `self.constraints`, but we also want to be mutating - // `self.member_constraints`. For now, just swap out the value - // we want and replace at the end. - let mut tmp = std::mem::take(&mut self.constraints.member_constraints); - for member_constraint in member_constraints { - tmp.push_constraint(member_constraint, |r| self.to_region_vid(r)); - } - self.constraints.member_constraints = tmp; - - for query_constraint in outlives { - self.convert(query_constraint); - } - } - - pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { - debug!("generate: constraints at: {:#?}", self.locations); - - // Extract out various useful fields we'll need below. - let ConstraintConversion { - tcx, region_bound_pairs, implicit_region_bound, param_env, .. - } = *self; - - // At the moment, we never generate any "higher-ranked" - // region constraints like `for<'a> 'a: 'b`. At some point - // when we move to universes, we will, and this assertion - // will start to fail. - let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound vars", query_constraint,); - }); - - match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - let r1_vid = self.to_region_vid(r1); - let r2_vid = self.to_region_vid(r2); - self.add_outlives(r1_vid, r2_vid); - } - - GenericArgKind::Type(t1) => { - // we don't actually use this for anything, but - // the `TypeOutlives` code needs an origin. - let origin = infer::RelateParamBound(DUMMY_SP, t1, None); - - TypeOutlives::new( - &mut *self, - tcx, - region_bound_pairs, - implicit_region_bound, - param_env, - ) - .type_must_outlive(origin, t1, r2); - } - - GenericArgKind::Const(_) => { - // Consts cannot outlive one another, so we - // don't need to handle any relations here. - } - } - } - - fn verify_to_type_test( - &mut self, - generic_kind: GenericKind<'tcx>, - region: ty::Region<'tcx>, - verify_bound: VerifyBound<'tcx>, - ) -> TypeTest<'tcx> { - let lower_bound = self.to_region_vid(region); - - TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound } - } - - fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid { - if let ty::RePlaceholder(placeholder) = r { - self.constraints.placeholder_region(self.infcx, *placeholder).to_region_vid() - } else { - self.universal_regions.to_region_vid(r) - } - } - - fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { - self.constraints.outlives_constraints.push(OutlivesConstraint { - locations: self.locations, - category: self.category, - sub, - sup, - variance_info: ty::VarianceDiagInfo::default(), - }); - } - - fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { - debug!("add_type_test(type_test={:?})", type_test); - self.constraints.type_tests.push(type_test); - } -} - -impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { - fn push_sub_region_constraint( - &mut self, - _origin: SubregionOrigin<'tcx>, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) { - let b = self.to_region_vid(b); - let a = self.to_region_vid(a); - self.add_outlives(b, a); - } - - fn push_verify( - &mut self, - _origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - a: ty::Region<'tcx>, - bound: VerifyBound<'tcx>, - ) { - let type_test = self.verify_to_type_test(kind, a, bound); - self.add_type_test(type_test); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,402 +0,0 @@ -use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::transitive_relation::TransitiveRelation; -use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::free_regions::FreeRegionRelations; -use rustc_infer::infer::outlives; -use rustc_infer::infer::region_constraints::GenericKind; -use rustc_infer::infer::InferCtxt; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; -use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; -use std::rc::Rc; -use type_op::TypeOpOutput; - -use crate::borrow_check::{ - nll::ToRegionVid, - type_check::constraint_conversion, - type_check::{Locations, MirTypeckRegionConstraints}, - universal_regions::UniversalRegions, -}; - -#[derive(Debug)] -crate struct UniversalRegionRelations<'tcx> { - universal_regions: Rc>, - - /// Stores the outlives relations that are known to hold from the - /// implied bounds, in-scope where-clauses, and that sort of - /// thing. - outlives: TransitiveRelation, - - /// This is the `<=` relation; that is, if `a: b`, then `b <= a`, - /// and we store that here. This is useful when figuring out how - /// to express some local region in terms of external regions our - /// caller will understand. - inverse_outlives: TransitiveRelation, -} - -/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to -/// be true. These encode relationships like `T: 'a` that are -/// added via implicit bounds. -/// -/// Each region here is guaranteed to be a key in the `indices` -/// map. We use the "original" regions (i.e., the keys from the -/// map, and not the values) because the code in -/// `process_registered_region_obligations` has some special-cased -/// logic expecting to see (e.g.) `ReStatic`, and if we supplied -/// our special inference variable there, we would mess that up. -type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; - -/// As part of computing the free region relations, we also have to -/// normalize the input-output types, which we then need later. So we -/// return those. This vector consists of first the input types and -/// then the output type as the last element. -type NormalizedInputsAndOutput<'tcx> = Vec>; - -crate struct CreateResult<'tcx> { - pub(in crate::borrow_check) universal_region_relations: Frozen>, - crate region_bound_pairs: RegionBoundPairs<'tcx>, - crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, -} - -crate fn create( - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - implicit_region_bound: Option>, - universal_regions: &Rc>, - constraints: &mut MirTypeckRegionConstraints<'tcx>, -) -> CreateResult<'tcx> { - UniversalRegionRelationsBuilder { - infcx, - param_env, - implicit_region_bound, - constraints, - universal_regions: universal_regions.clone(), - region_bound_pairs: Vec::new(), - relations: UniversalRegionRelations { - universal_regions: universal_regions.clone(), - outlives: Default::default(), - inverse_outlives: Default::default(), - }, - } - .create() -} - -impl UniversalRegionRelations<'tcx> { - /// Records in the `outlives_relation` (and - /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the - /// builder below. - fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { - debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b); - self.outlives.add(fr_a, fr_b); - self.inverse_outlives.add(fr_b, fr_a); - } - - /// Given two universal regions, returns the postdominating - /// upper-bound (effectively the least upper bound). - /// - /// (See `TransitiveRelation::postdom_upper_bound` for details on - /// the postdominating upper bound in general.) - crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { - assert!(self.universal_regions.is_universal_region(fr1)); - assert!(self.universal_regions.is_universal_region(fr2)); - *self - .inverse_outlives - .postdom_upper_bound(&fr1, &fr2) - .unwrap_or(&self.universal_regions.fr_static) - } - - /// Finds an "upper bound" for `fr` that is not local. In other - /// words, returns the smallest (*) known region `fr1` that (a) - /// outlives `fr` and (b) is not local. - /// - /// (*) If there are multiple competing choices, we return all of them. - crate fn non_local_upper_bounds(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> { - debug!("non_local_upper_bound(fr={:?})", fr); - let res = self.non_local_bounds(&self.inverse_outlives, fr); - assert!(!res.is_empty(), "can't find an upper bound!?"); - res - } - - /// Returns the "postdominating" bound of the set of - /// `non_local_upper_bounds` for the given region. - crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { - let upper_bounds = self.non_local_upper_bounds(&fr); - - // In case we find more than one, reduce to one for - // convenience. This is to prevent us from generating more - // complex constraints, but it will cause spurious errors. - let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds); - - debug!("non_local_bound: post_dom={:?}", post_dom); - - post_dom - .and_then(|&post_dom| { - // If the mutual immediate postdom is not local, then - // there is no non-local result we can return. - if !self.universal_regions.is_local_free_region(post_dom) { - Some(post_dom) - } else { - None - } - }) - .unwrap_or(self.universal_regions.fr_static) - } - - /// Finds a "lower bound" for `fr` that is not local. In other - /// words, returns the largest (*) known region `fr1` that (a) is - /// outlived by `fr` and (b) is not local. - /// - /// (*) If there are multiple competing choices, we pick the "postdominating" - /// one. See `TransitiveRelation::postdom_upper_bound` for details. - crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option { - debug!("non_local_lower_bound(fr={:?})", fr); - let lower_bounds = self.non_local_bounds(&self.outlives, &fr); - - // In case we find more than one, reduce to one for - // convenience. This is to prevent us from generating more - // complex constraints, but it will cause spurious errors. - let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds); - - debug!("non_local_bound: post_dom={:?}", post_dom); - - post_dom.and_then(|&post_dom| { - // If the mutual immediate postdom is not local, then - // there is no non-local result we can return. - if !self.universal_regions.is_local_free_region(post_dom) { - Some(post_dom) - } else { - None - } - }) - } - - /// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`. - /// Repeatedly invokes `postdom_parent` until we find something that is not - /// local. Returns `None` if we never do so. - fn non_local_bounds<'a>( - &self, - relation: &'a TransitiveRelation, - fr0: &'a RegionVid, - ) -> Vec<&'a RegionVid> { - // This method assumes that `fr0` is one of the universally - // quantified region variables. - assert!(self.universal_regions.is_universal_region(*fr0)); - - let mut external_parents = vec![]; - let mut queue = vec![fr0]; - - // Keep expanding `fr` into its parents until we reach - // non-local regions. - while let Some(fr) = queue.pop() { - if !self.universal_regions.is_local_free_region(*fr) { - external_parents.push(fr); - continue; - } - - queue.extend(relation.parents(fr)); - } - - debug!("non_local_bound: external_parents={:?}", external_parents); - - external_parents - } - - /// Returns `true` if fr1 is known to outlive fr2. - /// - /// This will only ever be true for universally quantified regions. - crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { - self.outlives.contains(&fr1, &fr2) - } - - /// Returns a vector of free regions `x` such that `fr1: x` is - /// known to hold. - crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> { - self.outlives.reachable_from(&fr1) - } - - /// Returns the _non-transitive_ set of known `outlives` constraints between free regions. - crate fn known_outlives(&self) -> impl Iterator { - self.outlives.base_edges() - } -} - -struct UniversalRegionRelationsBuilder<'this, 'tcx> { - infcx: &'this InferCtxt<'this, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - universal_regions: Rc>, - implicit_region_bound: Option>, - constraints: &'this mut MirTypeckRegionConstraints<'tcx>, - - // outputs: - relations: UniversalRegionRelations<'tcx>, - region_bound_pairs: RegionBoundPairs<'tcx>, -} - -impl UniversalRegionRelationsBuilder<'cx, 'tcx> { - crate fn create(mut self) -> CreateResult<'tcx> { - let unnormalized_input_output_tys = self - .universal_regions - .unnormalized_input_tys - .iter() - .cloned() - .chain(Some(self.universal_regions.unnormalized_output_ty)); - - // For each of the input/output types: - // - Normalize the type. This will create some region - // constraints, which we buffer up because we are - // not ready to process them yet. - // - Then compute the implied bounds. This will adjust - // the `region_bound_pairs` and so forth. - // - After this is done, we'll process the constraints, once - // the `relations` is built. - let mut normalized_inputs_and_output = - Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); - let constraint_sets: Vec<_> = unnormalized_input_output_tys - .flat_map(|ty| { - debug!("build: input_or_output={:?}", ty); - // We add implied bounds from both the unnormalized and normalized ty - // See issue #87748 - let constraints_implied_1 = self.add_implied_bounds(ty); - let TypeOpOutput { output: ty, constraints: constraints1, .. } = self - .param_env - .and(type_op::normalize::Normalize::new(ty)) - .fully_perform(self.infcx) - .unwrap_or_else(|_| { - self.infcx - .tcx - .sess - .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty)); - TypeOpOutput { - output: self.infcx.tcx.ty_error(), - constraints: None, - canonicalized_query: None, - } - }); - // Note: we need this in examples like - // ``` - // trait Foo { - // type Bar; - // fn foo(&self) -> &Self::Bar; - // } - // impl Foo for () { - // type Bar = (); - // fn foo(&self) ->&() {} - // } - // ``` - // Both &Self::Bar and &() are WF - let constraints_implied_2 = self.add_implied_bounds(ty); - normalized_inputs_and_output.push(ty); - constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2) - }) - .collect(); - - // Insert the facts we know from the predicates. Why? Why not. - let param_env = self.param_env; - self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); - - // Finally: - // - outlives is reflexive, so `'r: 'r` for every region `'r` - // - `'static: 'r` for every region `'r` - // - `'r: 'fn_body` for every (other) universally quantified - // region `'r`, all of which are provided by our caller - let fr_static = self.universal_regions.fr_static; - let fr_fn_body = self.universal_regions.fr_fn_body; - for fr in self.universal_regions.universal_regions() { - debug!("build: relating free region {:?} to itself and to 'static", fr); - self.relations.relate_universal_regions(fr, fr); - self.relations.relate_universal_regions(fr_static, fr); - self.relations.relate_universal_regions(fr, fr_fn_body); - } - - for data in &constraint_sets { - constraint_conversion::ConstraintConversion::new( - self.infcx, - &self.universal_regions, - &self.region_bound_pairs, - self.implicit_region_bound, - self.param_env, - Locations::All(DUMMY_SP), - ConstraintCategory::Internal, - &mut self.constraints, - ) - .convert_all(data); - } - - CreateResult { - universal_region_relations: Frozen::freeze(self.relations), - region_bound_pairs: self.region_bound_pairs, - normalized_inputs_and_output, - } - } - - /// Update the type of a single local, which should represent - /// either the return type of the MIR or one of its arguments. At - /// the same time, compute and add any implied bounds that come - /// from this local. - fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option>> { - debug!("add_implied_bounds(ty={:?})", ty); - let TypeOpOutput { output: bounds, constraints, .. } = self - .param_env - .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) - .fully_perform(self.infcx) - .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty)); - self.add_outlives_bounds(bounds); - constraints - } - - /// Registers the `OutlivesBound` items from `outlives_bounds` in - /// the outlives relation as well as the region-bound pairs - /// listing. - fn add_outlives_bounds(&mut self, outlives_bounds: I) - where - I: IntoIterator>, - { - for outlives_bound in outlives_bounds { - debug!("add_outlives_bounds(bound={:?})", outlives_bound); - - match outlives_bound { - OutlivesBound::RegionSubRegion(r1, r2) => { - // `where Type:` is lowered to `where Type: 'empty` so that - // we check `Type` is well formed, but there's no use for - // this bound here. - if let ty::ReEmpty(_) = r1 { - return; - } - - // The bound says that `r1 <= r2`; we store `r2: r1`. - let r1 = self.universal_regions.to_region_vid(r1); - let r2 = self.universal_regions.to_region_vid(r2); - self.relations.relate_universal_regions(r2, r1); - } - - OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); - } - - OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); - } - } - } - } -} - -/// This trait is used by the `impl-trait` constraint code to abstract -/// over the `FreeRegionMap` from lexical regions and -/// `UniversalRegions` (from NLL)`. -impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> { - fn sub_free_regions( - &self, - _tcx: TyCtxt<'tcx>, - shorter: ty::Region<'tcx>, - longer: ty::Region<'tcx>, - ) -> bool { - let shorter = shorter.to_region_vid(); - assert!(self.universal_regions.is_universal_region(shorter)); - let longer = longer.to_region_vid(); - assert!(self.universal_regions.is_universal_region(longer)); - self.outlives(longer, shorter) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -//! This module contains code to equate the input/output types appearing -//! in the MIR with the expected input/output types from the function -//! signature. This requires a bit of processing, as the expected types -//! are supplied to us before normalization and may contain opaque -//! `impl Trait` instances. In contrast, the input/output types found in -//! the MIR (specifically, in the special local variables for the -//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and -//! contain revealed `impl Trait` values). - -use rustc_infer::infer::LateBoundRegionConversionTime; -use rustc_middle::mir::*; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, Ty}; -use rustc_trait_selection::traits::query::normalize::AtExt; - -use rustc_index::vec::Idx; -use rustc_span::Span; - -use crate::borrow_check::universal_regions::UniversalRegions; - -use super::{Locations, TypeChecker}; - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - pub(super) fn equate_inputs_and_outputs( - &mut self, - body: &Body<'tcx>, - universal_regions: &UniversalRegions<'tcx>, - normalized_inputs_and_output: &[Ty<'tcx>], - ) { - let (&normalized_output_ty, normalized_input_tys) = - normalized_inputs_and_output.split_last().unwrap(); - - let mir_def_id = body.source.def_id().expect_local(); - - // If the user explicitly annotated the input types, extract - // those. - // - // e.g., `|x: FxHashMap<_, &'static u32>| ...` - let user_provided_sig; - if !self.tcx().is_closure(mir_def_id.to_def_id()) { - user_provided_sig = None; - } else { - let typeck_results = self.tcx().typeck(mir_def_id); - user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map( - |user_provided_poly_sig| { - // Instantiate the canonicalized variables from - // user-provided signature (e.g., the `_` in the code - // above) with fresh variables. - let poly_sig = self.instantiate_canonical_with_fresh_inference_vars( - body.span, - &user_provided_poly_sig, - ); - - // Replace the bound items in the fn sig with fresh - // variables, so that they represent the view from - // "inside" the closure. - self.infcx - .replace_bound_vars_with_fresh_vars( - body.span, - LateBoundRegionConversionTime::FnCall, - poly_sig, - ) - .0 - }, - ); - } - - debug!( - "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}", - normalized_input_tys, body.local_decls - ); - - // Equate expected input tys with those in the MIR. - for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { - if argument_index + 1 >= body.local_decls.len() { - self.tcx() - .sess - .delay_span_bug(body.span, "found more normalized_input_ty than local_decls"); - break; - } - // In MIR, argument N is stored in local N+1. - let local = Local::new(argument_index + 1); - - let mir_input_ty = body.local_decls[local].ty; - let mir_input_span = body.local_decls[local].source_info.span; - self.equate_normalized_input_or_output( - normalized_input_ty, - mir_input_ty, - mir_input_span, - ); - } - - if let Some(user_provided_sig) = user_provided_sig { - for (argument_index, &user_provided_input_ty) in - user_provided_sig.inputs().iter().enumerate() - { - // In MIR, closures begin an implicit `self`, so - // argument N is stored in local N+2. - let local = Local::new(argument_index + 2); - let mir_input_ty = body.local_decls[local].ty; - let mir_input_span = body.local_decls[local].source_info.span; - - // If the user explicitly annotated the input types, enforce those. - let user_provided_input_ty = - self.normalize(user_provided_input_ty, Locations::All(mir_input_span)); - self.equate_normalized_input_or_output( - user_provided_input_ty, - mir_input_ty, - mir_input_span, - ); - } - } - - assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some()); - if let Some(mir_yield_ty) = body.yield_ty() { - let ur_yield_ty = universal_regions.yield_ty.unwrap(); - let yield_span = body.local_decls[RETURN_PLACE].source_info.span; - self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span); - } - - // Return types are a bit more complex. They may contain opaque `impl Trait` types. - let mir_output_ty = body.local_decls[RETURN_PLACE].ty; - let output_span = body.local_decls[RETURN_PLACE].source_info.span; - if let Err(terr) = self.eq_opaque_type_and_type( - mir_output_ty, - normalized_output_ty, - Locations::All(output_span), - ConstraintCategory::BoringNoLocation, - ) { - span_mirbug!( - self, - Location::START, - "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", - normalized_output_ty, - mir_output_ty, - terr - ); - }; - - // If the user explicitly annotated the output types, enforce those. - // Note that this only happens for closures. - if let Some(user_provided_sig) = user_provided_sig { - let user_provided_output_ty = user_provided_sig.output(); - let user_provided_output_ty = - self.normalize(user_provided_output_ty, Locations::All(output_span)); - if let Err(err) = self.eq_opaque_type_and_type( - mir_output_ty, - user_provided_output_ty, - Locations::All(output_span), - ConstraintCategory::BoringNoLocation, - ) { - span_mirbug!( - self, - Location::START, - "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", - mir_output_ty, - user_provided_output_ty, - err - ); - } - } - } - - fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { - debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b); - - if let Err(_) = - self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) - { - // FIXME(jackh726): This is a hack. It's somewhat like - // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd - // like to normalize *before* inserting into `local_decls`, but - // doing so ends up causing some other trouble. - let b = match self - .infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .normalize(b) - { - Ok(n) => { - debug!("equate_inputs_and_outputs: {:?}", n); - if n.obligations.iter().all(|o| { - matches!( - o.predicate.kind().skip_binder(), - ty::PredicateKind::RegionOutlives(_) - | ty::PredicateKind::TypeOutlives(_) - ) - }) { - n.value - } else { - b - } - } - Err(_) => { - debug!("equate_inputs_and_outputs: NoSolution"); - b - } - }; - if let Err(terr) = - self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) - { - span_mirbug!( - self, - Location::START, - "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`", - a, - b, - terr - ); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -use rustc_data_structures::vec_linked_list as vll; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location}; - -use crate::borrow_check::def_use::{self, DefUse}; -use crate::borrow_check::region_infer::values::{PointIndex, RegionValueElements}; - -/// A map that cross references each local with the locations where it -/// is defined (assigned), used, or dropped. Used during liveness -/// computation. -/// -/// We keep track only of `Local`s we'll do the liveness analysis later, -/// this means that our internal `IndexVec`s will only be sparsely populated. -/// In the time-memory trade-off between keeping compact vectors with new -/// indexes (and needing to continuously map the `Local` index to its compact -/// counterpart) and having `IndexVec`s that we only use a fraction of, time -/// (and code simplicity) was favored. The rationale is that we only keep -/// a small number of `IndexVec`s throughout the entire analysis while, in -/// contrast, we're accessing each `Local` *many* times. -crate struct LocalUseMap { - /// Head of a linked list of **definitions** of each variable -- - /// definition in this context means assignment, e.g., `x` is - /// defined in `x = y` but not `y`; that first def is the head of - /// a linked list that lets you enumerate all places the variable - /// is assigned. - first_def_at: IndexVec>, - - /// Head of a linked list of **uses** of each variable -- use in - /// this context means that the existing value of the variable is - /// read or modified. e.g., `y` is used in `x = y` but not `x`. - /// Note that `DROP(x)` terminators are excluded from this list. - first_use_at: IndexVec>, - - /// Head of a linked list of **drops** of each variable -- these - /// are a special category of uses corresponding to the drop that - /// we add for each local variable. - first_drop_at: IndexVec>, - - appearances: IndexVec, -} - -struct Appearance { - point_index: PointIndex, - next: Option, -} - -rustc_index::newtype_index! { - pub struct AppearanceIndex { .. } -} - -impl vll::LinkElem for Appearance { - type LinkIndex = AppearanceIndex; - - fn next(elem: &Self) -> Option { - elem.next - } -} - -impl LocalUseMap { - crate fn build(live_locals: &[Local], elements: &RegionValueElements, body: &Body<'_>) -> Self { - let nones = IndexVec::from_elem_n(None, body.local_decls.len()); - let mut local_use_map = LocalUseMap { - first_def_at: nones.clone(), - first_use_at: nones.clone(), - first_drop_at: nones, - appearances: IndexVec::new(), - }; - - if live_locals.is_empty() { - return local_use_map; - } - - let mut locals_with_use_data: IndexVec = - IndexVec::from_elem_n(false, body.local_decls.len()); - live_locals.iter().for_each(|&local| locals_with_use_data[local] = true); - - LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data } - .visit_body(&body); - - local_use_map - } - - crate fn defs(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_def_at[local], &self.appearances) - .map(move |aa| self.appearances[aa].point_index) - } - - crate fn uses(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_use_at[local], &self.appearances) - .map(move |aa| self.appearances[aa].point_index) - } - - crate fn drops(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_drop_at[local], &self.appearances) - .map(move |aa| self.appearances[aa].point_index) - } -} - -struct LocalUseMapBuild<'me> { - local_use_map: &'me mut LocalUseMap, - elements: &'me RegionValueElements, - - // Vector used in `visit_local` to signal which `Local`s do we need - // def/use/drop information on, constructed from `live_locals` (that - // contains the variables we'll do the liveness analysis for). - // This vector serves optimization purposes only: we could have - // obtained the same information from `live_locals` but we want to - // avoid repeatedly calling `Vec::contains()` (see `LocalUseMap` for - // the rationale on the time-memory trade-off we're favoring here). - locals_with_use_data: IndexVec, -} - -impl LocalUseMapBuild<'_> { - fn insert_def(&mut self, local: Local, location: Location) { - Self::insert( - self.elements, - &mut self.local_use_map.first_def_at[local], - &mut self.local_use_map.appearances, - location, - ); - } - - fn insert_use(&mut self, local: Local, location: Location) { - Self::insert( - self.elements, - &mut self.local_use_map.first_use_at[local], - &mut self.local_use_map.appearances, - location, - ); - } - - fn insert_drop(&mut self, local: Local, location: Location) { - Self::insert( - self.elements, - &mut self.local_use_map.first_drop_at[local], - &mut self.local_use_map.appearances, - location, - ); - } - - fn insert( - elements: &RegionValueElements, - first_appearance: &mut Option, - appearances: &mut IndexVec, - location: Location, - ) { - let point_index = elements.point_from_location(location); - let appearance_index = - appearances.push(Appearance { point_index, next: *first_appearance }); - *first_appearance = Some(appearance_index); - } -} - -impl Visitor<'tcx> for LocalUseMapBuild<'_> { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { - if self.locals_with_use_data[local] { - match def_use::categorize(context) { - Some(DefUse::Def) => self.insert_def(local, location), - Some(DefUse::Use) => self.insert_use(local, location), - Some(DefUse::Drop) => self.insert_drop(local, location), - _ => (), - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -use rustc_data_structures::fx::FxHashSet; -use rustc_middle::mir::{Body, Local}; -use rustc_middle::ty::{RegionVid, TyCtxt}; -use std::rc::Rc; - -use crate::dataflow::impls::MaybeInitializedPlaces; -use crate::dataflow::move_paths::MoveData; -use crate::dataflow::ResultsCursor; - -use crate::borrow_check::{ - constraints::OutlivesConstraintSet, - facts::{AllFacts, AllFactsExt}, - location::LocationTable, - nll::ToRegionVid, - region_infer::values::RegionValueElements, - universal_regions::UniversalRegions, -}; - -use super::TypeChecker; - -mod local_use_map; -mod polonius; -mod trace; - -/// Combines liveness analysis with initialization analysis to -/// determine which variables are live at which points, both due to -/// ordinary uses and drops. Returns a set of (ty, location) pairs -/// that indicate which types must be live at which point in the CFG. -/// This vector is consumed by `constraint_generation`. -/// -/// N.B., this computation requires normalization; therefore, it must be -/// performed before -pub(super) fn generate<'mir, 'tcx>( - typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, - elements: &Rc, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, - move_data: &MoveData<'tcx>, - location_table: &LocationTable, -) { - debug!("liveness::generate"); - - let free_regions = regions_that_outlive_free_regions( - typeck.infcx.num_region_vars(), - &typeck.borrowck_context.universal_regions, - &typeck.borrowck_context.constraints.outlives_constraints, - ); - let live_locals = compute_live_locals(typeck.tcx(), &free_regions, &body); - let facts_enabled = AllFacts::enabled(typeck.tcx()); - - let polonius_drop_used = if facts_enabled { - let mut drop_used = Vec::new(); - polonius::populate_access_facts(typeck, body, location_table, move_data, &mut drop_used); - Some(drop_used) - } else { - None - }; - - if !live_locals.is_empty() || facts_enabled { - trace::trace( - typeck, - body, - elements, - flow_inits, - move_data, - live_locals, - polonius_drop_used, - ); - } -} - -// The purpose of `compute_live_locals` is to define the subset of `Local` -// variables for which we need to do a liveness computation. We only need -// to compute whether a variable `X` is live if that variable contains -// some region `R` in its type where `R` is not known to outlive a free -// region (i.e., where `R` may be valid for just a subset of the fn body). -fn compute_live_locals( - tcx: TyCtxt<'tcx>, - free_regions: &FxHashSet, - body: &Body<'tcx>, -) -> Vec { - let live_locals: Vec = body - .local_decls - .iter_enumerated() - .filter_map(|(local, local_decl)| { - if tcx.all_free_regions_meet(&local_decl.ty, |r| { - free_regions.contains(&r.to_region_vid()) - }) { - None - } else { - Some(local) - } - }) - .collect(); - - debug!("{} total variables", body.local_decls.len()); - debug!("{} variables need liveness", live_locals.len()); - debug!("{} regions outlive free regions", free_regions.len()); - - live_locals -} - -/// Computes all regions that are (currently) known to outlive free -/// regions. For these regions, we do not need to compute -/// liveness, since the outlives constraints will ensure that they -/// are live over the whole fn body anyhow. -fn regions_that_outlive_free_regions( - num_region_vars: usize, - universal_regions: &UniversalRegions<'tcx>, - constraint_set: &OutlivesConstraintSet<'tcx>, -) -> FxHashSet { - // Build a graph of the outlives constraints thus far. This is - // a reverse graph, so for each constraint `R1: R2` we have an - // edge `R2 -> R1`. Therefore, if we find all regions - // reachable from each free region, we will have all the - // regions that are forced to outlive some free region. - let rev_constraint_graph = constraint_set.reverse_graph(num_region_vars); - let fr_static = universal_regions.fr_static; - let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static); - - // Stack for the depth-first search. Start out with all the free regions. - let mut stack: Vec<_> = universal_regions.universal_regions().collect(); - - // Set of all free regions, plus anything that outlives them. Initially - // just contains the free regions. - let mut outlives_free_region: FxHashSet<_> = stack.iter().cloned().collect(); - - // Do the DFS -- for each thing in the stack, find all things - // that outlive it and add them to the set. If they are not, - // push them onto the stack for later. - while let Some(sub_region) = stack.pop() { - stack.extend( - rev_region_graph - .outgoing_regions(sub_region) - .filter(|&r| outlives_free_region.insert(r)), - ); - } - - // Return the final set of things we visited. - outlives_free_region -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -use crate::borrow_check::def_use::{self, DefUse}; -use crate::borrow_check::location::{LocationIndex, LocationTable}; -use crate::dataflow::indexes::MovePathIndex; -use crate::dataflow::move_paths::{LookupResult, MoveData}; -use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location, Place}; -use rustc_middle::ty::subst::GenericArg; - -use super::TypeChecker; - -type VarPointRelation = Vec<(Local, LocationIndex)>; -type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>; - -struct UseFactsExtractor<'me> { - var_defined_at: &'me mut VarPointRelation, - var_used_at: &'me mut VarPointRelation, - location_table: &'me LocationTable, - var_dropped_at: &'me mut VarPointRelation, - move_data: &'me MoveData<'me>, - path_accessed_at_base: &'me mut PathPointRelation, -} - -// A Visitor to walk through the MIR and extract point-wise facts -impl UseFactsExtractor<'_> { - fn location_to_index(&self, location: Location) -> LocationIndex { - self.location_table.mid_index(location) - } - - fn insert_def(&mut self, local: Local, location: Location) { - debug!("UseFactsExtractor::insert_def()"); - self.var_defined_at.push((local, self.location_to_index(location))); - } - - fn insert_use(&mut self, local: Local, location: Location) { - debug!("UseFactsExtractor::insert_use()"); - self.var_used_at.push((local, self.location_to_index(location))); - } - - fn insert_drop_use(&mut self, local: Local, location: Location) { - debug!("UseFactsExtractor::insert_drop_use()"); - self.var_dropped_at.push((local, self.location_to_index(location))); - } - - fn insert_path_access(&mut self, path: MovePathIndex, location: Location) { - debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location); - self.path_accessed_at_base.push((path, self.location_to_index(location))); - } - - fn place_to_mpi(&self, place: &Place<'_>) -> Option { - match self.move_data.rev_lookup.find(place.as_ref()) { - LookupResult::Exact(mpi) => Some(mpi), - LookupResult::Parent(mmpi) => mmpi, - } - } -} - -impl Visitor<'tcx> for UseFactsExtractor<'_> { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { - match def_use::categorize(context) { - Some(DefUse::Def) => self.insert_def(local, location), - Some(DefUse::Use) => self.insert_use(local, location), - Some(DefUse::Drop) => self.insert_drop_use(local, location), - _ => (), - } - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - self.super_place(place, context, location); - match context { - PlaceContext::NonMutatingUse(_) => { - if let Some(mpi) = self.place_to_mpi(place) { - self.insert_path_access(mpi, location); - } - } - - PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { - if let Some(mpi) = self.place_to_mpi(place) { - self.insert_path_access(mpi, location); - } - } - _ => (), - } - } -} - -pub(super) fn populate_access_facts( - typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, - location_table: &LocationTable, - move_data: &MoveData<'_>, - dropped_at: &mut Vec<(Local, Location)>, -) { - debug!("populate_access_facts()"); - - if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { - let mut extractor = UseFactsExtractor { - var_defined_at: &mut facts.var_defined_at, - var_used_at: &mut facts.var_used_at, - var_dropped_at: &mut facts.var_dropped_at, - path_accessed_at_base: &mut facts.path_accessed_at_base, - location_table, - move_data, - }; - extractor.visit_body(&body); - - facts.var_dropped_at.extend( - dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))), - ); - - for (local, local_decl) in body.local_decls.iter_enumerated() { - debug!( - "add use_of_var_derefs_origin facts - local={:?}, type={:?}", - local, local_decl.ty - ); - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let universal_regions = &typeck.borrowck_context.universal_regions; - typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| { - let region_vid = universal_regions.to_region_vid(region); - facts.use_of_var_derefs_origin.push((local, region_vid)); - }); - } - } -} - -// For every potentially drop()-touched region `region` in `local`'s type -// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact. -pub(super) fn add_drop_of_var_derefs_origin( - typeck: &mut TypeChecker<'_, 'tcx>, - local: Local, - kind: &GenericArg<'tcx>, -) { - debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind); - if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let universal_regions = &typeck.borrowck_context.universal_regions; - typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| { - let region_vid = universal_regions.to_region_vid(drop_live_region); - facts.drop_of_var_derefs_origin.push((local, region_vid)); - }); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,527 +0,0 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_index::bit_set::HybridBitSet; -use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; -use rustc_middle::ty::{Ty, TypeFoldable}; -use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; -use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; -use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; -use std::rc::Rc; - -use crate::dataflow::impls::MaybeInitializedPlaces; -use crate::dataflow::indexes::MovePathIndex; -use crate::dataflow::move_paths::{HasMoveData, MoveData}; -use crate::dataflow::ResultsCursor; - -use crate::borrow_check::{ - region_infer::values::{self, PointIndex, RegionValueElements}, - type_check::liveness::local_use_map::LocalUseMap, - type_check::liveness::polonius, - type_check::NormalizeLocation, - type_check::TypeChecker, -}; - -/// This is the heart of the liveness computation. For each variable X -/// that requires a liveness computation, it walks over all the uses -/// of X and does a reverse depth-first search ("trace") through the -/// MIR. This search stops when we find a definition of that variable. -/// The points visited in this search is the USE-LIVE set for the variable; -/// of those points is added to all the regions that appear in the variable's -/// type. -/// -/// We then also walks through each *drop* of those variables and does -/// another search, stopping when we reach a use or definition. This -/// is the DROP-LIVE set of points. Each of the points in the -/// DROP-LIVE set are to the liveness sets for regions found in the -/// `dropck_outlives` result of the variable's type (in particular, -/// this respects `#[may_dangle]` annotations). -pub(super) fn trace( - typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, - elements: &Rc, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, - move_data: &MoveData<'tcx>, - live_locals: Vec, - polonius_drop_used: Option>, -) { - debug!("trace()"); - - let local_use_map = &LocalUseMap::build(&live_locals, elements, body); - - let cx = LivenessContext { - typeck, - body, - flow_inits, - elements, - local_use_map, - move_data, - drop_data: FxHashMap::default(), - }; - - let mut results = LivenessResults::new(cx); - - if let Some(drop_used) = polonius_drop_used { - results.add_extra_drop_facts(drop_used, live_locals.iter().copied().collect()) - } - - results.compute_for_all_locals(live_locals); -} - -/// Contextual state for the type-liveness generator. -struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { - /// Current type-checker, giving us our inference context etc. - typeck: &'me mut TypeChecker<'typeck, 'tcx>, - - /// Defines the `PointIndex` mapping - elements: &'me RegionValueElements, - - /// MIR we are analyzing. - body: &'me Body<'tcx>, - - /// Mapping to/from the various indices used for initialization tracking. - move_data: &'me MoveData<'tcx>, - - /// Cache for the results of `dropck_outlives` query. - drop_data: FxHashMap, DropData<'tcx>>, - - /// Results of dataflow tracking which variables (and paths) have been - /// initialized. - flow_inits: &'me mut ResultsCursor<'flow, 'tcx, MaybeInitializedPlaces<'flow, 'tcx>>, - - /// Index indicating where each variable is assigned, used, or - /// dropped. - local_use_map: &'me LocalUseMap, -} - -struct DropData<'tcx> { - dropck_result: DropckOutlivesResult<'tcx>, - region_constraint_data: Option>>, -} - -struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { - cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>, - - /// Set of points that define the current local. - defs: HybridBitSet, - - /// Points where the current variable is "use live" -- meaning - /// that there is a future "full use" that may use its value. - use_live_at: HybridBitSet, - - /// Points where the current variable is "drop live" -- meaning - /// that there is no future "full use" that may use its value, but - /// there is a future drop. - drop_live_at: HybridBitSet, - - /// Locations where drops may occur. - drop_locations: Vec, - - /// Stack used when doing (reverse) DFS. - stack: Vec, -} - -impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { - fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self { - let num_points = cx.elements.num_points(); - LivenessResults { - cx, - defs: HybridBitSet::new_empty(num_points), - use_live_at: HybridBitSet::new_empty(num_points), - drop_live_at: HybridBitSet::new_empty(num_points), - drop_locations: vec![], - stack: vec![], - } - } - - fn compute_for_all_locals(&mut self, live_locals: Vec) { - for local in live_locals { - self.reset_local_state(); - self.add_defs_for(local); - self.compute_use_live_points_for(local); - self.compute_drop_live_points_for(local); - - let local_ty = self.cx.body.local_decls[local].ty; - - if !self.use_live_at.is_empty() { - self.cx.add_use_live_facts_for(local_ty, &self.use_live_at); - } - - if !self.drop_live_at.is_empty() { - self.cx.add_drop_live_facts_for( - local, - local_ty, - &self.drop_locations, - &self.drop_live_at, - ); - } - } - } - - /// Add extra drop facts needed for Polonius. - /// - /// Add facts for all locals with free regions, since regions may outlive - /// the function body only at certain nodes in the CFG. - fn add_extra_drop_facts( - &mut self, - drop_used: Vec<(Local, Location)>, - live_locals: FxHashSet, - ) { - let locations = HybridBitSet::new_empty(self.cx.elements.num_points()); - - for (local, location) in drop_used { - if !live_locals.contains(&local) { - let local_ty = self.cx.body.local_decls[local].ty; - if local_ty.has_free_regions(self.cx.typeck.tcx()) { - self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); - } - } - } - } - - /// Clear the value of fields that are "per local variable". - fn reset_local_state(&mut self) { - self.defs.clear(); - self.use_live_at.clear(); - self.drop_live_at.clear(); - self.drop_locations.clear(); - assert!(self.stack.is_empty()); - } - - /// Adds the definitions of `local` into `self.defs`. - fn add_defs_for(&mut self, local: Local) { - for def in self.cx.local_use_map.defs(local) { - debug!("- defined at {:?}", def); - self.defs.insert(def); - } - } - - /// Computes all points where local is "use live" -- meaning its - /// current value may be used later (except by a drop). This is - /// done by walking backwards from each use of `local` until we - /// find a `def` of local. - /// - /// Requires `add_defs_for(local)` to have been executed. - fn compute_use_live_points_for(&mut self, local: Local) { - debug!("compute_use_live_points_for(local={:?})", local); - - self.stack.extend(self.cx.local_use_map.uses(local)); - while let Some(p) = self.stack.pop() { - if self.defs.contains(p) { - continue; - } - - if self.use_live_at.insert(p) { - self.cx.elements.push_predecessors(self.cx.body, p, &mut self.stack) - } - } - } - - /// Computes all points where local is "drop live" -- meaning its - /// current value may be dropped later (but not used). This is - /// done by iterating over the drops of `local` where `local` (or - /// some subpart of `local`) is initialized. For each such drop, - /// we walk backwards until we find a point where `local` is - /// either defined or use-live. - /// - /// Requires `compute_use_live_points_for` and `add_defs_for` to - /// have been executed. - fn compute_drop_live_points_for(&mut self, local: Local) { - debug!("compute_drop_live_points_for(local={:?})", local); - - let mpi = self.cx.move_data.rev_lookup.find_local(local); - debug!("compute_drop_live_points_for: mpi = {:?}", mpi); - - // Find the drops where `local` is initialized. - for drop_point in self.cx.local_use_map.drops(local) { - let location = self.cx.elements.to_location(drop_point); - debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); - - if self.cx.initialized_at_terminator(location.block, mpi) { - if self.drop_live_at.insert(drop_point) { - self.drop_locations.push(location); - self.stack.push(drop_point); - } - } - } - - debug!("compute_drop_live_points_for: drop_locations={:?}", self.drop_locations); - - // Reverse DFS. But for drops, we do it a bit differently. - // The stack only ever stores *terminators of blocks*. Within - // a block, we walk back the statements in an inner loop. - while let Some(term_point) = self.stack.pop() { - self.compute_drop_live_points_for_block(mpi, term_point); - } - } - - /// Executes one iteration of the drop-live analysis loop. - /// - /// The parameter `mpi` is the `MovePathIndex` of the local variable - /// we are currently analyzing. - /// - /// The point `term_point` represents some terminator in the MIR, - /// where the local `mpi` is drop-live on entry to that terminator. - /// - /// This method adds all drop-live points within the block and -- - /// where applicable -- pushes the terminators of preceding blocks - /// onto `self.stack`. - fn compute_drop_live_points_for_block(&mut self, mpi: MovePathIndex, term_point: PointIndex) { - debug!( - "compute_drop_live_points_for_block(mpi={:?}, term_point={:?})", - self.cx.move_data.move_paths[mpi].place, - self.cx.elements.to_location(term_point), - ); - - // We are only invoked with terminators where `mpi` is - // drop-live on entry. - debug_assert!(self.drop_live_at.contains(term_point)); - - // Otherwise, scan backwards through the statements in the - // block. One of them may be either a definition or use - // live point. - let term_location = self.cx.elements.to_location(term_point); - debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,); - let block = term_location.block; - let entry_point = self.cx.elements.entry_point(term_location.block); - for p in (entry_point..term_point).rev() { - debug!("compute_drop_live_points_for_block: p = {:?}", self.cx.elements.to_location(p)); - - if self.defs.contains(p) { - debug!("compute_drop_live_points_for_block: def site"); - return; - } - - if self.use_live_at.contains(p) { - debug!("compute_drop_live_points_for_block: use-live at {:?}", p); - return; - } - - if !self.drop_live_at.insert(p) { - debug!("compute_drop_live_points_for_block: already drop-live"); - return; - } - } - - let body = self.cx.body; - for &pred_block in body.predecessors()[block].iter() { - debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,); - - // Check whether the variable is (at least partially) - // initialized at the exit of this predecessor. If so, we - // want to enqueue it on our list. If not, go check the - // next block. - // - // Note that we only need to check whether `live_local` - // became de-initialized at basic block boundaries. If it - // were to become de-initialized within the block, that - // would have been a "use-live" transition in the earlier - // loop, and we'd have returned already. - // - // NB. It's possible that the pred-block ends in a call - // which stores to the variable; in that case, the - // variable may be uninitialized "at exit" because this - // call only considers the *unconditional effects* of the - // terminator. *But*, in that case, the terminator is also - // a *definition* of the variable, in which case we want - // to stop the search anyhow. (But see Note 1 below.) - if !self.cx.initialized_at_exit(pred_block, mpi) { - debug!("compute_drop_live_points_for_block: not initialized"); - continue; - } - - let pred_term_loc = self.cx.body.terminator_loc(pred_block); - let pred_term_point = self.cx.elements.point_from_location(pred_term_loc); - - // If the terminator of this predecessor either *assigns* - // our value or is a "normal use", then stop. - if self.defs.contains(pred_term_point) { - debug!("compute_drop_live_points_for_block: defined at {:?}", pred_term_loc); - continue; - } - - if self.use_live_at.contains(pred_term_point) { - debug!("compute_drop_live_points_for_block: use-live at {:?}", pred_term_loc); - continue; - } - - // Otherwise, we are drop-live on entry to the terminator, - // so walk it. - if self.drop_live_at.insert(pred_term_point) { - debug!("compute_drop_live_points_for_block: pushed to stack"); - self.stack.push(pred_term_point); - } - } - - // Note 1. There is a weird scenario that you might imagine - // being problematic here, but which actually cannot happen. - // The problem would be if we had a variable that *is* initialized - // (but dead) on entry to the terminator, and where the current value - // will be dropped in the case of unwind. In that case, we ought to - // consider `X` to be drop-live in between the last use and call. - // Here is the example: - // - // ``` - // BB0 { - // X = ... - // use(X); // last use - // ... // <-- X ought to be drop-live here - // X = call() goto BB1 unwind BB2 - // } - // - // BB1 { - // DROP(X) - // } - // - // BB2 { - // DROP(X) - // } - // ``` - // - // However, the current code would, when walking back from BB2, - // simply stop and never explore BB0. This seems bad! But it turns - // out this code is flawed anyway -- note that the existing value of - // `X` would leak in the case where unwinding did *not* occur. - // - // What we *actually* generate is a store to a temporary - // for the call (`TMP = call()...`) and then a - // `DropAndReplace` to swap that with `X` - // (`DropAndReplace` has very particular semantics). - } -} - -impl LivenessContext<'_, '_, '_, 'tcx> { - /// Returns `true` if the local variable (or some part of it) is initialized at the current - /// cursor position. Callers should call one of the `seek` methods immediately before to point - /// the cursor to the desired location. - fn initialized_at_curr_loc(&self, mpi: MovePathIndex) -> bool { - let state = self.flow_inits.get(); - if state.contains(mpi) { - return true; - } - - let move_paths = &self.flow_inits.analysis().move_data().move_paths; - move_paths[mpi].find_descendant(&move_paths, |mpi| state.contains(mpi)).is_some() - } - - /// Returns `true` if the local variable (or some part of it) is initialized in - /// the terminator of `block`. We need to check this to determine if a - /// DROP of some local variable will have an effect -- note that - /// drops, as they may unwind, are always terminators. - fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { - self.flow_inits.seek_before_primary_effect(self.body.terminator_loc(block)); - self.initialized_at_curr_loc(mpi) - } - - /// Returns `true` if the path `mpi` (or some part of it) is initialized at - /// the exit of `block`. - /// - /// **Warning:** Does not account for the result of `Call` - /// instructions. - fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { - self.flow_inits.seek_after_primary_effect(self.body.terminator_loc(block)); - self.initialized_at_curr_loc(mpi) - } - - /// Stores the result that all regions in `value` are live for the - /// points `live_at`. - fn add_use_live_facts_for( - &mut self, - value: impl TypeFoldable<'tcx>, - live_at: &HybridBitSet, - ) { - debug!("add_use_live_facts_for(value={:?})", value); - - Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at) - } - - /// Some variable with type `live_ty` is "drop live" at `location` - /// -- i.e., it may be dropped later. This means that *some* of - /// the regions in its type must be live at `location`. The - /// precise set will depend on the dropck constraints, and in - /// particular this takes `#[may_dangle]` into account. - fn add_drop_live_facts_for( - &mut self, - dropped_local: Local, - dropped_ty: Ty<'tcx>, - drop_locations: &[Location], - live_at: &HybridBitSet, - ) { - debug!( - "add_drop_live_constraint(\ - dropped_local={:?}, \ - dropped_ty={:?}, \ - drop_locations={:?}, \ - live_at={:?})", - dropped_local, - dropped_ty, - drop_locations, - values::location_set_str(self.elements, live_at.iter()), - ); - - let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({ - let typeck = &mut self.typeck; - move || Self::compute_drop_data(typeck, dropped_ty) - }); - - if let Some(data) = &drop_data.region_constraint_data { - for &drop_location in drop_locations { - self.typeck.push_region_constraints( - drop_location.to_locations(), - ConstraintCategory::Boring, - data, - ); - } - } - - drop_data.dropck_result.report_overflows( - self.typeck.infcx.tcx, - self.body.source_info(*drop_locations.first().unwrap()).span, - dropped_ty, - ); - - // All things in the `outlives` array may be touched by - // the destructor and must be live at this point. - for &kind in &drop_data.dropck_result.kinds { - Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at); - - polonius::add_drop_of_var_derefs_origin(&mut self.typeck, dropped_local, &kind); - } - } - - fn make_all_regions_live( - elements: &RegionValueElements, - typeck: &mut TypeChecker<'_, 'tcx>, - value: impl TypeFoldable<'tcx>, - live_at: &HybridBitSet, - ) { - debug!("make_all_regions_live(value={:?})", value); - debug!( - "make_all_regions_live: live_at={}", - values::location_set_str(elements, live_at.iter()), - ); - - let tcx = typeck.tcx(); - tcx.for_each_free_region(&value, |live_region| { - let live_region_vid = - typeck.borrowck_context.universal_regions.to_region_vid(live_region); - typeck - .borrowck_context - .constraints - .liveness_constraints - .add_elements(live_region_vid, live_at); - }); - } - - fn compute_drop_data( - typeck: &mut TypeChecker<'_, 'tcx>, - dropped_ty: Ty<'tcx>, - ) -> DropData<'tcx> { - debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); - - let param_env = typeck.param_env; - let TypeOpOutput { output, constraints, .. } = - param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap(); - - DropData { dropck_result: output, region_constraint_data: constraints } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2723 +0,0 @@ -//! This pass type-checks the MIR to ensure it is not broken. - -use std::rc::Rc; -use std::{fmt, iter, mem}; - -use either::Either; - -use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::vec_map::VecMap; -use rustc_errors::struct_span_err; -use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::lang_items::LangItem; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::outlives::env::RegionBoundPairs; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{ - InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin, -}; -use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::AssertKind; -use rustc_middle::mir::*; -use rustc_middle::ty::adjustment::PointerCast; -use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; -use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, - ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, -}; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::VariantIdx; -use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt}; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::query::type_op; -use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; -use rustc_trait_selection::traits::query::Fallible; -use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}; - -use crate::dataflow::impls::MaybeInitializedPlaces; -use crate::dataflow::move_paths::MoveData; -use crate::dataflow::ResultsCursor; -use crate::transform::{ - check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression, -}; - -use crate::borrow_check::{ - borrow_set::BorrowSet, - constraints::{OutlivesConstraint, OutlivesConstraintSet}, - diagnostics::UniverseInfo, - facts::AllFacts, - location::LocationTable, - member_constraints::MemberConstraintSet, - nll::ToRegionVid, - path_utils, - region_infer::values::{ - LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, - }, - region_infer::{ClosureRegionRequirementsExt, TypeTest}, - type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, - universal_regions::{DefiningTy, UniversalRegions}, - Upvar, -}; - -macro_rules! span_mirbug { - ($context:expr, $elem:expr, $($message:tt)*) => ({ - $crate::borrow_check::type_check::mirbug( - $context.tcx(), - $context.last_span, - &format!( - "broken MIR in {:?} ({:?}): {}", - $context.body.source.def_id(), - $elem, - format_args!($($message)*), - ), - ) - }) -} - -macro_rules! span_mirbug_and_err { - ($context:expr, $elem:expr, $($message:tt)*) => ({ - { - span_mirbug!($context, $elem, $($message)*); - $context.error() - } - }) -} - -mod canonical; -mod constraint_conversion; -pub mod free_region_relations; -mod input_output; -crate mod liveness; -mod relate_tys; - -/// Type checks the given `mir` in the context of the inference -/// context `infcx`. Returns any region constraints that have yet to -/// be proven. This result includes liveness constraints that -/// ensure that regions appearing in the types of all local variables -/// are live at all points where that local variable may later be -/// used. -/// -/// This phase of type-check ought to be infallible -- this is because -/// the original, HIR-based type-check succeeded. So if any errors -/// occur here, we will get a `bug!` reported. -/// -/// # Parameters -/// -/// - `infcx` -- inference context to use -/// - `param_env` -- parameter environment to use for trait solving -/// - `body` -- MIR body to type-check -/// - `promoted` -- map of promoted constants within `body` -/// - `universal_regions` -- the universal regions from `body`s function signature -/// - `location_table` -- MIR location map of `body` -/// - `borrow_set` -- information about borrows occurring in `body` -/// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts -/// - `flow_inits` -- results of a maybe-init dataflow analysis -/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis -/// - `elements` -- MIR region map -pub(crate) fn type_check<'mir, 'tcx>( - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body: &Body<'tcx>, - promoted: &IndexVec>, - universal_regions: &Rc>, - location_table: &LocationTable, - borrow_set: &BorrowSet<'tcx>, - all_facts: &mut Option, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, - move_data: &MoveData<'tcx>, - elements: &Rc, - upvars: &[Upvar<'tcx>], -) -> MirTypeckResults<'tcx> { - let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); - let mut constraints = MirTypeckRegionConstraints { - placeholder_indices: PlaceholderIndices::default(), - placeholder_index_to_region: IndexVec::default(), - liveness_constraints: LivenessValues::new(elements.clone()), - outlives_constraints: OutlivesConstraintSet::default(), - member_constraints: MemberConstraintSet::default(), - closure_bounds_mapping: Default::default(), - type_tests: Vec::default(), - universe_causes: IndexVec::from_elem_n(UniverseInfo::other(), 1), - }; - - let CreateResult { - universal_region_relations, - region_bound_pairs, - normalized_inputs_and_output, - } = free_region_relations::create( - infcx, - param_env, - Some(implicit_region_bound), - universal_regions, - &mut constraints, - ); - - for _ in ty::UniverseIndex::ROOT..infcx.universe() { - let info = UniverseInfo::other(); - constraints.universe_causes.push(info); - } - - let mut borrowck_context = BorrowCheckContext { - universal_regions, - location_table, - borrow_set, - all_facts, - constraints: &mut constraints, - upvars, - }; - - let opaque_type_values = type_check_internal( - infcx, - param_env, - body, - promoted, - ®ion_bound_pairs, - implicit_region_bound, - &mut borrowck_context, - &universal_region_relations, - |mut cx| { - cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); - liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); - - translate_outlives_facts(&mut cx); - let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types); - - opaque_type_values - .into_iter() - .filter_map(|(opaque_type_key, decl)| { - let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); - if revealed_ty.has_infer_types_or_consts() { - infcx.tcx.sess.delay_span_bug( - body.span, - &format!("could not resolve {:#?}", revealed_ty.kind()), - ); - revealed_ty = infcx.tcx.ty_error(); - } - let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() { - *def_id == opaque_type_key.def_id - } else { - false - }; - - if concrete_is_opaque { - // We're using an opaque `impl Trait` type without - // 'revealing' it. For example, code like this: - // - // type Foo = impl Debug; - // fn foo1() -> Foo { ... } - // fn foo2() -> Foo { foo1() } - // - // In `foo2`, we're not revealing the type of `Foo` - we're - // just treating it as the opaque type. - // - // When this occurs, we do *not* want to try to equate - // the concrete type with the underlying defining type - // of the opaque type - this will always fail, since - // the defining type of an opaque type is always - // some other type (e.g. not itself) - // Essentially, none of the normal obligations apply here - - // we're just passing around some unknown opaque type, - // without actually looking at the underlying type it - // gets 'revealed' into - debug!( - "eq_opaque_type_and_type: non-defining use of {:?}", - opaque_type_key.def_id, - ); - None - } else { - Some((opaque_type_key, revealed_ty)) - } - }) - .collect() - }, - ); - - MirTypeckResults { constraints, universal_region_relations, opaque_type_values } -} - -fn type_check_internal<'a, 'tcx, R>( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body: &'a Body<'tcx>, - promoted: &'a IndexVec>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, - borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - universal_region_relations: &'a UniversalRegionRelations<'tcx>, - extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, -) -> R { - let mut checker = TypeChecker::new( - infcx, - body, - param_env, - region_bound_pairs, - implicit_region_bound, - borrowck_context, - universal_region_relations, - ); - let errors_reported = { - let mut verifier = TypeVerifier::new(&mut checker, body, promoted); - verifier.visit_body(&body); - verifier.errors_reported - }; - - if !errors_reported { - // if verifier failed, don't do further checks to avoid ICEs - checker.typeck_mir(body); - } - - extra(checker) -} - -fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { - let cx = &mut typeck.borrowck_context; - if let Some(facts) = cx.all_facts { - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let location_table = cx.location_table; - facts.subset_base.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map( - |constraint: &OutlivesConstraint<'_>| { - if let Some(from_location) = constraint.locations.from_location() { - Either::Left(iter::once(( - constraint.sup, - constraint.sub, - location_table.mid_index(from_location), - ))) - } else { - Either::Right( - location_table - .all_points() - .map(move |location| (constraint.sup, constraint.sub, location)), - ) - } - }, - )); - } -} - -fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) { - // We sometimes see MIR failures (notably predicate failures) due to - // the fact that we check rvalue sized predicates here. So use `delay_span_bug` - // to avoid reporting bugs in those cases. - tcx.sess.diagnostic().delay_span_bug(span, msg); -} - -enum FieldAccessError { - OutOfRange { field_count: usize }, -} - -/// Verifies that MIR types are sane to not crash further checks. -/// -/// The sanitize_XYZ methods here take an MIR object and compute its -/// type, calling `span_mirbug` and returning an error type if there -/// is a problem. -struct TypeVerifier<'a, 'b, 'tcx> { - cx: &'a mut TypeChecker<'b, 'tcx>, - body: &'b Body<'tcx>, - promoted: &'b IndexVec>, - last_span: Span, - errors_reported: bool, -} - -impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { - fn visit_span(&mut self, span: &Span) { - if !span.is_dummy() { - self.last_span = *span; - } - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - self.sanitize_place(place, location, context); - } - - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { - self.super_constant(constant, location); - let ty = self.sanitize_type(constant, constant.literal.ty()); - - self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { - let live_region_vid = - self.cx.borrowck_context.universal_regions.to_region_vid(live_region); - self.cx - .borrowck_context - .constraints - .liveness_constraints - .add_element(live_region_vid, location); - }); - - if let Some(annotation_index) = constant.user_ty { - if let Err(terr) = self.cx.relate_type_and_user_type( - constant.literal.ty(), - ty::Variance::Invariant, - &UserTypeProjection { base: annotation_index, projs: vec![] }, - location.to_locations(), - ConstraintCategory::Boring, - ) { - let annotation = &self.cx.user_type_annotations[annotation_index]; - span_mirbug!( - self, - constant, - "bad constant user type {:?} vs {:?}: {:?}", - annotation, - constant.literal.ty(), - terr, - ); - } - } else { - let tcx = self.tcx(); - let maybe_uneval = match constant.literal { - ConstantKind::Ty(ct) => match ct.val { - ty::ConstKind::Unevaluated(uv) => Some(uv), - _ => None, - }, - _ => None, - }; - if let Some(uv) = maybe_uneval { - if let Some(promoted) = uv.promoted { - let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, - promoted: &Body<'tcx>, - ty, - san_ty| { - if let Err(terr) = verifier.cx.eq_types( - ty, - san_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - verifier, - promoted, - "bad promoted type ({:?}: {:?}): {:?}", - ty, - san_ty, - terr - ); - }; - }; - - if !self.errors_reported { - let promoted_body = &self.promoted[promoted]; - self.sanitize_promoted(promoted_body, location); - - let promoted_ty = promoted_body.return_ty(); - check_err(self, promoted_body, ty, promoted_ty); - } - } else { - if let Err(terr) = self.cx.fully_perform_op( - location.to_locations(), - ConstraintCategory::Boring, - self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - constant.literal.ty(), - uv.def.did, - UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None }, - )), - ) { - span_mirbug!( - self, - constant, - "bad constant type {:?} ({:?})", - constant, - terr - ); - } - } - } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { - let unnormalized_ty = tcx.type_of(static_def_id); - let locations = location.to_locations(); - let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; - - if let Err(terr) = self.cx.eq_types( - literal_ty, - normalized_ty, - locations, - ConstraintCategory::Boring, - ) { - span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); - } - } - - if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - self.cx.normalize_and_prove_instantiated_predicates( - instantiated_predicates, - location.to_locations(), - ); - } - } - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - let rval_ty = rvalue.ty(self.body, self.tcx()); - self.sanitize_type(rvalue, rval_ty); - } - - fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { - self.super_local_decl(local, local_decl); - self.sanitize_type(local_decl, local_decl.ty); - - if let Some(user_ty) = &local_decl.user_ty { - for (user_ty, span) in user_ty.projections_and_spans() { - let ty = if !local_decl.is_nonref_binding() { - // If we have a binding of the form `let ref x: T = ..` - // then remove the outermost reference so we can check the - // type annotation for the remaining type. - if let ty::Ref(_, rty, _) = local_decl.ty.kind() { - rty - } else { - bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); - } - } else { - local_decl.ty - }; - - if let Err(terr) = self.cx.relate_type_and_user_type( - ty, - ty::Variance::Invariant, - user_ty, - Locations::All(*span), - ConstraintCategory::TypeAnnotation, - ) { - span_mirbug!( - self, - local, - "bad user type on variable {:?}: {:?} != {:?} ({:?})", - local, - local_decl.ty, - local_decl.user_ty, - terr, - ); - } - } - } - } - - fn visit_body(&mut self, body: &Body<'tcx>) { - self.sanitize_type(&"return type", body.return_ty()); - for local_decl in &body.local_decls { - self.sanitize_type(local_decl, local_decl.ty); - } - if self.errors_reported { - return; - } - self.super_body(body); - } -} - -impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { - fn new( - cx: &'a mut TypeChecker<'b, 'tcx>, - body: &'b Body<'tcx>, - promoted: &'b IndexVec>, - ) -> Self { - TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false } - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.cx.infcx.tcx - } - - fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_bound_vars() || ty.references_error() { - span_mirbug_and_err!(self, parent, "bad type {:?}", ty) - } else { - ty - } - } - - /// Checks that the types internal to the `place` match up with - /// what would be expected. - fn sanitize_place( - &mut self, - place: &Place<'tcx>, - location: Location, - context: PlaceContext, - ) -> PlaceTy<'tcx> { - debug!("sanitize_place: {:?}", place); - - let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); - - for elem in place.projection.iter() { - if place_ty.variant_index.is_none() { - if place_ty.ty.references_error() { - assert!(self.errors_reported); - return PlaceTy::from_ty(self.tcx().ty_error()); - } - } - place_ty = self.sanitize_projection(place_ty, elem, place, location); - } - - if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let tcx = self.tcx(); - let trait_ref = ty::TraitRef { - def_id: tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), - substs: tcx.mk_substs_trait(place_ty.ty, &[]), - }; - - // To have a `Copy` operand, the type `T` of the - // value must be `Copy`. Note that we prove that `T: Copy`, - // rather than using the `is_copy_modulo_regions` - // test. This is important because - // `is_copy_modulo_regions` ignores the resulting region - // obligations and assumes they pass. This can result in - // bounds from `Copy` impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use `Copy` before knowing - // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement `Copy`, then - // it must. - self.cx.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::CopyBound, - ); - } - - place_ty - } - - fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { - // Determine the constraints from the promoted MIR by running the type - // checker on the promoted MIR, then transfer the constraints back to - // the main MIR, changing the locations to the provided location. - - let parent_body = mem::replace(&mut self.body, promoted_body); - - // Use new sets of constraints and closure bounds so that we can - // modify their locations. - let all_facts = &mut None; - let mut constraints = Default::default(); - let mut closure_bounds = Default::default(); - let mut liveness_constraints = - LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body))); - // Don't try to add borrow_region facts for the promoted MIR - - let mut swap_constraints = |this: &mut Self| { - mem::swap(this.cx.borrowck_context.all_facts, all_facts); - mem::swap( - &mut this.cx.borrowck_context.constraints.outlives_constraints, - &mut constraints, - ); - mem::swap( - &mut this.cx.borrowck_context.constraints.closure_bounds_mapping, - &mut closure_bounds, - ); - mem::swap( - &mut this.cx.borrowck_context.constraints.liveness_constraints, - &mut liveness_constraints, - ); - }; - - swap_constraints(self); - - self.visit_body(&promoted_body); - - if !self.errors_reported { - // if verifier failed, don't do further checks to avoid ICEs - self.cx.typeck_mir(promoted_body); - } - - self.body = parent_body; - // Merge the outlives constraints back in, at the given location. - swap_constraints(self); - - let locations = location.to_locations(); - for constraint in constraints.outlives().iter() { - let mut constraint = constraint.clone(); - constraint.locations = locations; - if let ConstraintCategory::Return(_) - | ConstraintCategory::UseAsConst - | ConstraintCategory::UseAsStatic = constraint.category - { - // "Returning" from a promoted is an assignment to a - // temporary from the user's point of view. - constraint.category = ConstraintCategory::Boring; - } - self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) - } - for live_region in liveness_constraints.rows() { - self.cx - .borrowck_context - .constraints - .liveness_constraints - .add_element(live_region, location); - } - - if !closure_bounds.is_empty() { - let combined_bounds_mapping = - closure_bounds.into_iter().flat_map(|(_, value)| value).collect(); - let existing = self - .cx - .borrowck_context - .constraints - .closure_bounds_mapping - .insert(location, combined_bounds_mapping); - assert!(existing.is_none(), "Multiple promoteds/closures at the same location."); - } - } - - fn sanitize_projection( - &mut self, - base: PlaceTy<'tcx>, - pi: PlaceElem<'tcx>, - place: &Place<'tcx>, - location: Location, - ) -> PlaceTy<'tcx> { - debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); - let tcx = self.tcx(); - let base_ty = base.ty; - match pi { - ProjectionElem::Deref => { - let deref_ty = base_ty.builtin_deref(true); - PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| { - span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) - })) - } - ProjectionElem::Index(i) => { - let index_ty = Place::from(i).ty(self.body, tcx).ty; - if index_ty != tcx.types.usize { - PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)) - } else { - PlaceTy::from_ty(base_ty.builtin_index().unwrap_or_else(|| { - span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) - })) - } - } - ProjectionElem::ConstantIndex { .. } => { - // consider verifying in-bounds - PlaceTy::from_ty(base_ty.builtin_index().unwrap_or_else(|| { - span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) - })) - } - ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match base_ty.kind() { - ty::Array(inner, _) => { - assert!(!from_end, "array subslices should not use from_end"); - tcx.mk_array(inner, to - from) - } - ty::Slice(..) => { - assert!(from_end, "slice subslices should use from_end"); - base_ty - } - _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), - }) - } - ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind() { - ty::Adt(adt_def, _substs) if adt_def.is_enum() => { - if index.as_usize() >= adt_def.variants.len() { - PlaceTy::from_ty(span_mirbug_and_err!( - self, - place, - "cast to variant #{:?} but enum only has {:?}", - index, - adt_def.variants.len() - )) - } else { - PlaceTy { ty: base_ty, variant_index: Some(index) } - } - } - // We do not need to handle generators here, because this runs - // before the generator transform stage. - _ => { - let ty = if let Some(name) = maybe_name { - span_mirbug_and_err!( - self, - place, - "can't downcast {:?} as {:?}", - base_ty, - name - ) - } else { - span_mirbug_and_err!(self, place, "can't downcast {:?}", base_ty) - }; - PlaceTy::from_ty(ty) - } - }, - ProjectionElem::Field(field, fty) => { - let fty = self.sanitize_type(place, fty); - match self.field_ty(place, base, field, location) { - Ok(ty) => { - let ty = self.cx.normalize(ty, location); - if let Err(terr) = self.cx.eq_types( - ty, - fty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - place, - "bad field access ({:?}: {:?}): {:?}", - ty, - fty, - terr - ); - } - } - Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!( - self, - place, - "accessed field #{} but variant only has {}", - field.index(), - field_count - ), - } - PlaceTy::from_ty(fty) - } - } - } - - fn error(&mut self) -> Ty<'tcx> { - self.errors_reported = true; - self.tcx().ty_error() - } - - fn field_ty( - &mut self, - parent: &dyn fmt::Debug, - base_ty: PlaceTy<'tcx>, - field: Field, - location: Location, - ) -> Result, FieldAccessError> { - let tcx = self.tcx(); - - let (variant, substs) = match base_ty { - PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() { - ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs), - ty::Generator(def_id, substs, _) => { - let mut variants = substs.as_generator().state_tys(def_id, tcx); - let mut variant = match variants.nth(variant_index.into()) { - Some(v) => v, - None => bug!( - "variant_index of generator out of range: {:?}/{:?}", - variant_index, - substs.as_generator().state_tys(def_id, tcx).count() - ), - }; - return match variant.nth(field.index()) { - Some(ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { field_count: variant.count() }), - }; - } - _ => bug!("can't have downcast of non-adt non-generator type"), - }, - PlaceTy { ty, variant_index: None } => match *ty.kind() { - ty::Adt(adt_def, substs) if !adt_def.is_enum() => { - (&adt_def.variants[VariantIdx::new(0)], substs) - } - ty::Closure(_, substs) => { - return match substs - .as_closure() - .tupled_upvars_ty() - .tuple_element_ty(field.index()) - { - Some(ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { - field_count: substs.as_closure().upvar_tys().count(), - }), - }; - } - ty::Generator(_, substs, _) => { - // Only prefix fields (upvars and current state) are - // accessible without a variant index. - return match substs.as_generator().prefix_tys().nth(field.index()) { - Some(ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { - field_count: substs.as_generator().prefix_tys().count(), - }), - }; - } - ty::Tuple(tys) => { - return match tys.get(field.index()) { - Some(&ty) => Ok(ty.expect_ty()), - None => Err(FieldAccessError::OutOfRange { field_count: tys.len() }), - }; - } - _ => { - return Ok(span_mirbug_and_err!( - self, - parent, - "can't project out of {:?}", - base_ty - )); - } - }, - }; - - if let Some(field) = variant.fields.get(field.index()) { - Ok(self.cx.normalize(field.ty(tcx, substs), location)) - } else { - Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) - } - } -} - -/// The MIR type checker. Visits the MIR and enforces all the -/// constraints needed for it to be valid and well-typed. Along the -/// way, it accrues region constraints -- these can later be used by -/// NLL region checking. -struct TypeChecker<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - last_span: Span, - body: &'a Body<'tcx>, - /// User type annotations are shared between the main MIR and the MIR of - /// all of the promoted items. - user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, - reported_errors: FxHashSet<(Ty<'tcx>, Span)>, - borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - universal_region_relations: &'a UniversalRegionRelations<'tcx>, -} - -struct BorrowCheckContext<'a, 'tcx> { - universal_regions: &'a UniversalRegions<'tcx>, - location_table: &'a LocationTable, - all_facts: &'a mut Option, - borrow_set: &'a BorrowSet<'tcx>, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - upvars: &'a [Upvar<'tcx>], -} - -crate struct MirTypeckResults<'tcx> { - crate constraints: MirTypeckRegionConstraints<'tcx>, - pub(in crate::borrow_check) universal_region_relations: Frozen>, - crate opaque_type_values: VecMap, Ty<'tcx>>, -} - -/// A collection of region constraints that must be satisfied for the -/// program to be considered well-typed. -crate struct MirTypeckRegionConstraints<'tcx> { - /// Maps from a `ty::Placeholder` to the corresponding - /// `PlaceholderIndex` bit that we will use for it. - /// - /// To keep everything in sync, do not insert this set - /// directly. Instead, use the `placeholder_region` helper. - crate placeholder_indices: PlaceholderIndices, - - /// Each time we add a placeholder to `placeholder_indices`, we - /// also create a corresponding "representative" region vid for - /// that wraps it. This vector tracks those. This way, when we - /// convert the same `ty::RePlaceholder(p)` twice, we can map to - /// the same underlying `RegionVid`. - crate placeholder_index_to_region: IndexVec>, - - /// In general, the type-checker is not responsible for enforcing - /// liveness constraints; this job falls to the region inferencer, - /// which performs a liveness analysis. However, in some limited - /// cases, the MIR type-checker creates temporary regions that do - /// not otherwise appear in the MIR -- in particular, the - /// late-bound regions that it instantiates at call-sites -- and - /// hence it must report on their liveness constraints. - crate liveness_constraints: LivenessValues, - - crate outlives_constraints: OutlivesConstraintSet<'tcx>, - - crate member_constraints: MemberConstraintSet<'tcx, RegionVid>, - - crate closure_bounds_mapping: - FxHashMap>, - - crate universe_causes: IndexVec>, - - crate type_tests: Vec>, -} - -impl MirTypeckRegionConstraints<'tcx> { - fn placeholder_region( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - placeholder: ty::PlaceholderRegion, - ) -> ty::Region<'tcx> { - let placeholder_index = self.placeholder_indices.insert(placeholder); - match self.placeholder_index_to_region.get(placeholder_index) { - Some(&v) => v, - None => { - let origin = NllRegionVariableOrigin::Placeholder(placeholder); - let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe); - self.placeholder_index_to_region.push(region); - region - } - } - } -} - -/// The `Locations` type summarizes *where* region constraints are -/// required to hold. Normally, this is at a particular point which -/// created the obligation, but for constraints that the user gave, we -/// want the constraint to hold at all points. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Locations { - /// Indicates that a type constraint should always be true. This - /// is particularly important in the new borrowck analysis for - /// things like the type of the return slot. Consider this - /// example: - /// - /// ``` - /// fn foo<'a>(x: &'a u32) -> &'a u32 { - /// let y = 22; - /// return &y; // error - /// } - /// ``` - /// - /// Here, we wind up with the signature from the return type being - /// something like `&'1 u32` where `'1` is a universal region. But - /// the type of the return slot `_0` is something like `&'2 u32` - /// where `'2` is an existential region variable. The type checker - /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the - /// older NLL analysis, we required this only at the entry point - /// to the function. By the nature of the constraints, this wound - /// up propagating to all points reachable from start (because - /// `'1` -- as a universal region -- is live everywhere). In the - /// newer analysis, though, this doesn't work: `_0` is considered - /// dead at the start (it has no usable value) and hence this type - /// equality is basically a no-op. Then, later on, when we do `_0 - /// = &'3 y`, that region `'3` never winds up related to the - /// universal region `'1` and hence no error occurs. Therefore, we - /// use Locations::All instead, which ensures that the `'1` and - /// `'2` are equal everything. We also use this for other - /// user-given type annotations; e.g., if the user wrote `let mut - /// x: &'static u32 = ...`, we would ensure that all values - /// assigned to `x` are of `'static` lifetime. - /// - /// The span points to the place the constraint arose. For example, - /// it points to the type in a user-given type annotation. If - /// there's no sensible span then it's DUMMY_SP. - All(Span), - - /// An outlives constraint that only has to hold at a single location, - /// usually it represents a point where references flow from one spot to - /// another (e.g., `x = y`) - Single(Location), -} - -impl Locations { - pub fn from_location(&self) -> Option { - match self { - Locations::All(_) => None, - Locations::Single(from_location) => Some(*from_location), - } - } - - /// Gets a span representing the location. - pub fn span(&self, body: &Body<'_>) -> Span { - match self { - Locations::All(span) => *span, - Locations::Single(l) => body.source_info(*l).span, - } - } -} - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - fn new( - infcx: &'a InferCtxt<'a, 'tcx>, - body: &'a Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, - borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - universal_region_relations: &'a UniversalRegionRelations<'tcx>, - ) -> Self { - let mut checker = Self { - infcx, - last_span: DUMMY_SP, - body, - user_type_annotations: &body.user_type_annotations, - param_env, - region_bound_pairs, - implicit_region_bound, - borrowck_context, - reported_errors: Default::default(), - universal_region_relations, - }; - checker.check_user_type_annotations(); - checker - } - - fn unsized_feature_enabled(&self) -> bool { - let features = self.tcx().features(); - features.unsized_locals || features.unsized_fn_params - } - - /// Equate the inferred type and the annotated type for user type annotations - fn check_user_type_annotations(&mut self) { - debug!( - "check_user_type_annotations: user_type_annotations={:?}", - self.user_type_annotations - ); - for user_annotation in self.user_type_annotations { - let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; - let inferred_ty = self.normalize(inferred_ty, Locations::All(span)); - let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); - match annotation { - UserType::Ty(mut ty) => { - ty = self.normalize(ty, Locations::All(span)); - - if let Err(terr) = self.eq_types( - ty, - inferred_ty, - Locations::All(span), - ConstraintCategory::BoringNoLocation, - ) { - span_mirbug!( - self, - user_annotation, - "bad user type ({:?} = {:?}): {:?}", - ty, - inferred_ty, - terr - ); - } - - self.prove_predicate( - ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()), - Locations::All(span), - ConstraintCategory::TypeAnnotation, - ); - } - UserType::TypeOf(def_id, user_substs) => { - if let Err(terr) = self.fully_perform_op( - Locations::All(span), - ConstraintCategory::BoringNoLocation, - self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - inferred_ty, - def_id, - user_substs, - )), - ) { - span_mirbug!( - self, - user_annotation, - "bad user type AscribeUserType({:?}, {:?} {:?}, type_of={:?}): {:?}", - inferred_ty, - def_id, - user_substs, - self.tcx().type_of(def_id), - terr, - ); - } - } - } - } - } - - fn push_region_constraints( - &mut self, - locations: Locations, - category: ConstraintCategory, - data: &QueryRegionConstraints<'tcx>, - ) { - debug!("push_region_constraints: constraints generated at {:?} are {:#?}", locations, data); - - constraint_conversion::ConstraintConversion::new( - self.infcx, - self.borrowck_context.universal_regions, - self.region_bound_pairs, - Some(self.implicit_region_bound), - self.param_env, - locations, - category, - &mut self.borrowck_context.constraints, - ) - .convert_all(data); - } - - /// Convenient wrapper around `relate_tys::relate_types` -- see - /// that fn for docs. - fn relate_types( - &mut self, - a: Ty<'tcx>, - v: ty::Variance, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) -> Fallible<()> { - relate_tys::relate_types( - self.infcx, - self.param_env, - a, - v, - b, - locations, - category, - self.borrowck_context, - ) - } - - /// Try to relate `sub <: sup` - fn sub_types( - &mut self, - sub: Ty<'tcx>, - sup: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) -> Fallible<()> { - // Use this order of parameters because the sup type is usually the - // "expected" type in diagnostics. - self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) - } - - fn eq_types( - &mut self, - expected: Ty<'tcx>, - found: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) -> Fallible<()> { - self.relate_types(expected, ty::Variance::Invariant, found, locations, category) - } - - fn relate_type_and_user_type( - &mut self, - a: Ty<'tcx>, - v: ty::Variance, - user_ty: &UserTypeProjection, - locations: Locations, - category: ConstraintCategory, - ) -> Fallible<()> { - debug!( - "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})", - a, v, user_ty, locations, - ); - - let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; - let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); - - let tcx = self.infcx.tcx; - - for proj in &user_ty.projs { - let projected_ty = curr_projected_ty.projection_ty_core( - tcx, - self.param_env, - proj, - |this, field, &()| { - let ty = this.field_ty(tcx, field); - self.normalize(ty, locations) - }, - ); - curr_projected_ty = projected_ty; - } - debug!( - "user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}", - user_ty.base, annotated_type, user_ty.projs, curr_projected_ty - ); - - let ty = curr_projected_ty.ty; - self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?; - - Ok(()) - } - - /// Equates a type `anon_ty` that may contain opaque types whose - /// values are to be inferred by the MIR. - /// - /// The type `revealed_ty` contains the same type as `anon_ty`, but with the - /// hidden types for impl traits revealed. - /// - /// # Example - /// - /// Consider a piece of code like - /// - /// ```rust - /// type Foo = impl Debug; - /// - /// fn foo(t: T) -> Box> { - /// Box::new((t, 22_u32)) - /// } - /// ``` - /// - /// Here, the function signature would be something like - /// `fn(T) -> Box`. The MIR return slot would have - /// the type with the opaque type revealed, so `Box<(T, u32)>`. - /// - /// In terms of our function parameters: - /// - /// * `anon_ty` would be `Box>` where `Foo` is an opaque type - /// scoped to this function (note that it is parameterized by the - /// generics of `foo`). Note that `anon_ty` is not just the opaque type, - /// but the entire return type (which may contain opaque types within it). - /// * `revealed_ty` would be `Box<(T, u32)>` - fn eq_opaque_type_and_type( - &mut self, - revealed_ty: Ty<'tcx>, - anon_ty: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) -> Fallible<()> { - debug!( - "eq_opaque_type_and_type( \ - revealed_ty={:?}, \ - anon_ty={:?})", - revealed_ty, anon_ty - ); - - // Fast path for the common case. - if !anon_ty.has_opaque_types() { - if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) { - span_mirbug!( - self, - locations, - "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`", - revealed_ty, - anon_ty, - terr - ); - } - return Ok(()); - } - - let param_env = self.param_env; - let body = self.body; - let mir_def_id = body.source.def_id().expect_local(); - - debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id); - self.fully_perform_op( - locations, - category, - CustomTypeOp::new( - |infcx| { - let mut obligations = ObligationAccumulator::default(); - - let dummy_body_id = hir::CRATE_HIR_ID; - - // Replace the opaque types defined by this function with - // inference variables, creating a map. In our example above, - // this would transform the type `Box>` (where `Foo` is an opaque type) - // to `Box`, returning an `opaque_type_map` mapping `{Foo -> ?T}`. - // (Note that the key of the map is both the def-id of `Foo` along with - // any generic parameters.) - let output_ty = obligations.add(infcx.instantiate_opaque_types( - dummy_body_id, - param_env, - anon_ty, - locations.span(body), - )); - debug!( - "eq_opaque_type_and_type: \ - instantiated output_ty={:?} \ - revealed_ty={:?}", - output_ty, revealed_ty - ); - - // Make sure that the inferred types are well-formed. I'm - // not entirely sure this is needed (the HIR type check - // didn't do this) but it seems sensible to prevent opaque - // types hiding ill-formed types. - obligations.obligations.push(traits::Obligation::new( - ObligationCause::dummy(), - param_env, - ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx), - )); - obligations.add( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(output_ty, revealed_ty)?, - ); - - debug!("eq_opaque_type_and_type: equated"); - - Ok(InferOk { value: (), obligations: obligations.into_vec() }) - }, - || "input_output".to_string(), - ), - )?; - - let universal_region_relations = self.universal_region_relations; - - // Finally, if we instantiated the anon types successfully, we - // have to solve any bounds (e.g., `-> impl Iterator` needs to - // prove that `T: Iterator` where `T` is the type we - // instantiated it with). - let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone(); - for (opaque_type_key, opaque_decl) in opaque_type_map { - self.fully_perform_op( - locations, - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |infcx| { - infcx.constrain_opaque_type( - opaque_type_key, - &opaque_decl, - GenerateMemberConstraints::IfNoStaticBound, - universal_region_relations, - ); - Ok(InferOk { value: (), obligations: vec![] }) - }, - || "opaque_type_map".to_string(), - ), - )?; - } - Ok(()) - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { - debug!("check_stmt: {:?}", stmt); - let tcx = self.tcx(); - match stmt.kind { - StatementKind::Assign(box (ref place, ref rv)) => { - // Assignments to temporaries are not "interesting"; - // they are not caused by the user, but rather artifacts - // of lowering. Assignments to other sorts of places *are* interesting - // though. - let category = match place.as_local() { - Some(RETURN_PLACE) => { - if let BorrowCheckContext { - universal_regions: - UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, - .. - } = self.borrowck_context - { - if tcx.is_static(*def_id) { - ConstraintCategory::UseAsStatic - } else { - ConstraintCategory::UseAsConst - } - } else { - ConstraintCategory::Return(ReturnConstraint::Normal) - } - } - Some(l) if !body.local_decls[l].is_user_variable() => { - ConstraintCategory::Boring - } - _ => ConstraintCategory::Assignment, - }; - - let place_ty = place.ty(body, tcx).ty; - let place_ty = self.normalize(place_ty, location); - let rv_ty = rv.ty(body, tcx); - let rv_ty = self.normalize(rv_ty, location); - if let Err(terr) = - self.sub_types(rv_ty, place_ty, location.to_locations(), category) - { - span_mirbug!( - self, - stmt, - "bad assignment ({:?} = {:?}): {:?}", - place_ty, - rv_ty, - terr - ); - } - - if let Some(annotation_index) = self.rvalue_user_ty(rv) { - if let Err(terr) = self.relate_type_and_user_type( - rv_ty, - ty::Variance::Invariant, - &UserTypeProjection { base: annotation_index, projs: vec![] }, - location.to_locations(), - ConstraintCategory::Boring, - ) { - let annotation = &self.user_type_annotations[annotation_index]; - span_mirbug!( - self, - stmt, - "bad user type on rvalue ({:?} = {:?}): {:?}", - annotation, - rv_ty, - terr - ); - } - } - - self.check_rvalue(body, rv, location); - if !self.unsized_feature_enabled() { - let trait_ref = ty::TraitRef { - def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), - substs: tcx.mk_substs_trait(place_ty, &[]), - }; - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::SizedBound, - ); - } - } - StatementKind::SetDiscriminant { ref place, variant_index } => { - let place_type = place.ty(body, tcx).ty; - let adt = match place_type.kind() { - ty::Adt(adt, _) if adt.is_enum() => adt, - _ => { - span_bug!( - stmt.source_info.span, - "bad set discriminant ({:?} = {:?}): lhs is not an enum", - place, - variant_index - ); - } - }; - if variant_index.as_usize() >= adt.variants.len() { - span_bug!( - stmt.source_info.span, - "bad set discriminant ({:?} = {:?}): value of of range", - place, - variant_index - ); - }; - } - StatementKind::AscribeUserType(box (ref place, ref projection), variance) => { - let place_ty = place.ty(body, tcx).ty; - if let Err(terr) = self.relate_type_and_user_type( - place_ty, - variance, - projection, - Locations::All(stmt.source_info.span), - ConstraintCategory::TypeAnnotation, - ) { - let annotation = &self.user_type_annotations[projection.base]; - span_mirbug!( - self, - stmt, - "bad type assert ({:?} <: {:?} with projections {:?}): {:?}", - place_ty, - annotation, - projection.projs, - terr - ); - } - } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - .. - }) => span_bug!( - stmt.source_info.span, - "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics", - ), - StatementKind::FakeRead(..) - | StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::LlvmInlineAsm { .. } - | StatementKind::Retag { .. } - | StatementKind::Coverage(..) - | StatementKind::Nop => {} - } - } - - fn check_terminator( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - term_location: Location, - ) { - debug!("check_terminator: {:?}", term); - let tcx = self.tcx(); - match term.kind { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::GeneratorDrop - | TerminatorKind::Unreachable - | TerminatorKind::Drop { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => { - // no checks needed for these - } - - TerminatorKind::DropAndReplace { ref place, ref value, target: _, unwind: _ } => { - let place_ty = place.ty(body, tcx).ty; - let rv_ty = value.ty(body, tcx); - - let locations = term_location.to_locations(); - if let Err(terr) = - self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment) - { - span_mirbug!( - self, - term, - "bad DropAndReplace ({:?} = {:?}): {:?}", - place_ty, - rv_ty, - terr - ); - } - } - TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { - let discr_ty = discr.ty(body, tcx); - if let Err(terr) = self.sub_types( - discr_ty, - switch_ty, - term_location.to_locations(), - ConstraintCategory::Assignment, - ) { - span_mirbug!( - self, - term, - "bad SwitchInt ({:?} on {:?}): {:?}", - switch_ty, - discr_ty, - terr - ); - } - if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() { - span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty); - } - // FIXME: check the values - } - TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { - let func_ty = func.ty(body, tcx); - debug!("check_terminator: call, func_ty={:?}", func_ty); - let sig = match func_ty.kind() { - ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx), - _ => { - span_mirbug!(self, term, "call to non-function {:?}", func_ty); - return; - } - }; - let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars( - term.source_info.span, - LateBoundRegionConversionTime::FnCall, - sig, - ); - let sig = self.normalize(sig, term_location); - self.check_call_dest(body, term, &sig, destination, term_location); - - self.prove_predicates( - sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())), - term_location.to_locations(), - ConstraintCategory::Boring, - ); - - // The ordinary liveness rules will ensure that all - // regions in the type of the callee are live here. We - // then further constrain the late-bound regions that - // were instantiated at the call site to be live as - // well. The resulting is that all the input (and - // output) types in the signature must be live, since - // all the inputs that fed into it were live. - for &late_bound_region in map.values() { - let region_vid = - self.borrowck_context.universal_regions.to_region_vid(late_bound_region); - self.borrowck_context - .constraints - .liveness_constraints - .add_element(region_vid, term_location); - } - - self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call); - } - TerminatorKind::Assert { ref cond, ref msg, .. } => { - let cond_ty = cond.ty(body, tcx); - if cond_ty != tcx.types.bool { - span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); - } - - if let AssertKind::BoundsCheck { ref len, ref index } = *msg { - if len.ty(body, tcx) != tcx.types.usize { - span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) - } - if index.ty(body, tcx) != tcx.types.usize { - span_mirbug!(self, index, "bounds-check index non-usize {:?}", index) - } - } - } - TerminatorKind::Yield { ref value, .. } => { - let value_ty = value.ty(body, tcx); - match body.yield_ty() { - None => span_mirbug!(self, term, "yield in non-generator"), - Some(ty) => { - if let Err(terr) = self.sub_types( - value_ty, - ty, - term_location.to_locations(), - ConstraintCategory::Yield, - ) { - span_mirbug!( - self, - term, - "type of yield value is {:?}, but the yield type is {:?}: {:?}", - value_ty, - ty, - terr - ); - } - } - } - } - } - } - - fn check_call_dest( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - sig: &ty::FnSig<'tcx>, - destination: &Option<(Place<'tcx>, BasicBlock)>, - term_location: Location, - ) { - let tcx = self.tcx(); - match *destination { - Some((ref dest, _target_block)) => { - let dest_ty = dest.ty(body, tcx).ty; - let dest_ty = self.normalize(dest_ty, term_location); - let category = match dest.as_local() { - Some(RETURN_PLACE) => { - if let BorrowCheckContext { - universal_regions: - UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, - .. - } = self.borrowck_context - { - if tcx.is_static(*def_id) { - ConstraintCategory::UseAsStatic - } else { - ConstraintCategory::UseAsConst - } - } else { - ConstraintCategory::Return(ReturnConstraint::Normal) - } - } - Some(l) if !body.local_decls[l].is_user_variable() => { - ConstraintCategory::Boring - } - _ => ConstraintCategory::Assignment, - }; - - let locations = term_location.to_locations(); - - if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { - span_mirbug!( - self, - term, - "call dest mismatch ({:?} <- {:?}): {:?}", - dest_ty, - sig.output(), - terr - ); - } - - // When `unsized_fn_params` and `unsized_locals` are both not enabled, - // this check is done at `check_local`. - if self.unsized_feature_enabled() { - let span = term.source_info.span; - self.ensure_place_sized(dest_ty, span); - } - } - None => { - if !self - .tcx() - .conservative_is_privately_uninhabited(self.param_env.and(sig.output())) - { - span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); - } - } - } - } - - fn check_call_inputs( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - sig: &ty::FnSig<'tcx>, - args: &[Operand<'tcx>], - term_location: Location, - from_hir_call: bool, - ) { - debug!("check_call_inputs({:?}, {:?})", sig, args); - if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { - span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); - } - for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { - let op_arg_ty = op_arg.ty(body, self.tcx()); - let op_arg_ty = self.normalize(op_arg_ty, term_location); - let category = if from_hir_call { - ConstraintCategory::CallArgument - } else { - ConstraintCategory::Boring - }; - if let Err(terr) = - self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category) - { - span_mirbug!( - self, - term, - "bad arg #{:?} ({:?} <- {:?}): {:?}", - n, - fn_arg, - op_arg_ty, - terr - ); - } - } - } - - fn check_iscleanup(&mut self, body: &Body<'tcx>, block_data: &BasicBlockData<'tcx>) { - let is_cleanup = block_data.is_cleanup; - self.last_span = block_data.terminator().source_info.span; - match block_data.terminator().kind { - TerminatorKind::Goto { target } => { - self.assert_iscleanup(body, block_data, target, is_cleanup) - } - TerminatorKind::SwitchInt { ref targets, .. } => { - for target in targets.all_targets() { - self.assert_iscleanup(body, block_data, *target, is_cleanup); - } - } - TerminatorKind::Resume => { - if !is_cleanup { - span_mirbug!(self, block_data, "resume on non-cleanup block!") - } - } - TerminatorKind::Abort => { - if !is_cleanup { - span_mirbug!(self, block_data, "abort on non-cleanup block!") - } - } - TerminatorKind::Return => { - if is_cleanup { - span_mirbug!(self, block_data, "return on cleanup block") - } - } - TerminatorKind::GeneratorDrop { .. } => { - if is_cleanup { - span_mirbug!(self, block_data, "generator_drop in cleanup block") - } - } - TerminatorKind::Yield { resume, drop, .. } => { - if is_cleanup { - span_mirbug!(self, block_data, "yield in cleanup block") - } - self.assert_iscleanup(body, block_data, resume, is_cleanup); - if let Some(drop) = drop { - self.assert_iscleanup(body, block_data, drop, is_cleanup); - } - } - TerminatorKind::Unreachable => {} - TerminatorKind::Drop { target, unwind, .. } - | TerminatorKind::DropAndReplace { target, unwind, .. } - | TerminatorKind::Assert { target, cleanup: unwind, .. } => { - self.assert_iscleanup(body, block_data, target, is_cleanup); - if let Some(unwind) = unwind { - if is_cleanup { - span_mirbug!(self, block_data, "unwind on cleanup block") - } - self.assert_iscleanup(body, block_data, unwind, true); - } - } - TerminatorKind::Call { ref destination, cleanup, .. } => { - if let &Some((_, target)) = destination { - self.assert_iscleanup(body, block_data, target, is_cleanup); - } - if let Some(cleanup) = cleanup { - if is_cleanup { - span_mirbug!(self, block_data, "cleanup on cleanup block") - } - self.assert_iscleanup(body, block_data, cleanup, true); - } - } - TerminatorKind::FalseEdge { real_target, imaginary_target } => { - self.assert_iscleanup(body, block_data, real_target, is_cleanup); - self.assert_iscleanup(body, block_data, imaginary_target, is_cleanup); - } - TerminatorKind::FalseUnwind { real_target, unwind } => { - self.assert_iscleanup(body, block_data, real_target, is_cleanup); - if let Some(unwind) = unwind { - if is_cleanup { - span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind"); - } - self.assert_iscleanup(body, block_data, unwind, true); - } - } - TerminatorKind::InlineAsm { destination, .. } => { - if let Some(target) = destination { - self.assert_iscleanup(body, block_data, target, is_cleanup); - } - } - } - } - - fn assert_iscleanup( - &mut self, - body: &Body<'tcx>, - ctxt: &dyn fmt::Debug, - bb: BasicBlock, - iscleanuppad: bool, - ) { - if body[bb].is_cleanup != iscleanuppad { - span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}", bb, iscleanuppad); - } - } - - fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { - match body.local_kind(local) { - LocalKind::ReturnPointer | LocalKind::Arg => { - // return values of normal functions are required to be - // sized by typeck, but return values of ADT constructors are - // not because we don't include a `Self: Sized` bounds on them. - // - // Unbound parts of arguments were never required to be Sized - // - maybe we should make that a warning. - return; - } - LocalKind::Var | LocalKind::Temp => {} - } - - // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls - // and nullary ops are checked in `check_call_dest`. - if !self.unsized_feature_enabled() { - let span = local_decl.source_info.span; - let ty = local_decl.ty; - self.ensure_place_sized(ty, span); - } - } - - fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) { - let tcx = self.tcx(); - - // Erase the regions from `ty` to get a global type. The - // `Sized` bound in no way depends on precise regions, so this - // shouldn't affect `is_sized`. - let erased_ty = tcx.erase_regions(ty); - if !erased_ty.is_sized(tcx.at(span), self.param_env) { - // in current MIR construction, all non-control-flow rvalue - // expressions evaluate through `as_temp` or `into` a return - // slot or local, so to find all unsized rvalues it is enough - // to check all temps, return slots and locals. - if self.reported_errors.replace((ty, span)).is_none() { - let mut diag = struct_span_err!( - self.tcx().sess, - span, - E0161, - "cannot move a value of type {0}: the size of {0} \ - cannot be statically determined", - ty - ); - - // While this is located in `nll::typeck` this error is not - // an NLL error, it's a required check to prevent creation - // of unsized rvalues in a call expression. - diag.emit(); - } - } - } - - fn aggregate_field_ty( - &mut self, - ak: &AggregateKind<'tcx>, - field_index: usize, - location: Location, - ) -> Result, FieldAccessError> { - let tcx = self.tcx(); - - match *ak { - AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => { - let variant = &def.variants[variant_index]; - let adj_field_index = active_field_index.unwrap_or(field_index); - if let Some(field) = variant.fields.get(adj_field_index) { - Ok(self.normalize(field.ty(tcx, substs), location)) - } else { - Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) - } - } - AggregateKind::Closure(_, substs) => { - match substs.as_closure().upvar_tys().nth(field_index) { - Some(ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { - field_count: substs.as_closure().upvar_tys().count(), - }), - } - } - AggregateKind::Generator(_, substs, _) => { - // It doesn't make sense to look at a field beyond the prefix; - // these require a variant index, and are not initialized in - // aggregate rvalues. - match substs.as_generator().prefix_tys().nth(field_index) { - Some(ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { - field_count: substs.as_generator().prefix_tys().count(), - }), - } - } - AggregateKind::Array(ty) => Ok(ty), - AggregateKind::Tuple => { - unreachable!("This should have been covered in check_rvalues"); - } - } - } - - fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - let tcx = self.tcx(); - - match rvalue { - Rvalue::Aggregate(ak, ops) => { - self.check_aggregate_rvalue(&body, rvalue, ak, ops, location) - } - - Rvalue::Repeat(operand, len) => { - // If the length cannot be evaluated we must assume that the length can be larger - // than 1. - // If the length is larger than 1, the repeat expression will need to copy the - // element, so we require the `Copy` trait. - if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { - match operand { - Operand::Copy(..) | Operand::Constant(..) => { - // These are always okay: direct use of a const, or a value that can evidently be copied. - } - Operand::Move(place) => { - // Make sure that repeated elements implement `Copy`. - let span = body.source_info(location).span; - let ty = operand.ty(body, tcx); - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { - let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); - let is_const_fn = - is_const_fn_in_array_repeat_expression(&ccx, &place, &body); - - debug!("check_rvalue: is_const_fn={:?}", is_const_fn); - - let def_id = body.source.def_id().expect_local(); - let obligation = traits::Obligation::new( - ObligationCause::new( - span, - self.tcx().hir().local_def_id_to_hir_id(def_id), - traits::ObligationCauseCode::RepeatVec(is_const_fn), - ), - self.param_env, - ty::Binder::dummy(ty::TraitRef::new( - self.tcx().require_lang_item( - LangItem::Copy, - Some(self.last_span), - ), - tcx.mk_substs_trait(ty, &[]), - )) - .without_const() - .to_predicate(self.tcx()), - ); - self.infcx.report_selection_error( - obligation.clone(), - &obligation, - &traits::SelectionError::Unimplemented, - false, - false, - ); - } - } - } - } - } - - Rvalue::NullaryOp(_, ty) => { - // Even with unsized locals cannot box an unsized value. - if self.unsized_feature_enabled() { - let span = body.source_info(location).span; - self.ensure_place_sized(ty, span); - } - - let trait_ref = ty::TraitRef { - def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), - substs: tcx.mk_substs_trait(ty, &[]), - }; - - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::SizedBound, - ); - } - - Rvalue::Cast(cast_kind, op, ty) => { - match cast_kind { - CastKind::Pointer(PointerCast::ReifyFnPointer) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); - - // The type that we see in the fcx is like - // `foo::<'a, 'b>`, where `foo` is the path to a - // function definition. When we extract the - // signature, it comes from the `fn_sig` query, - // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); - - let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); - - if let Err(terr) = self.eq_types( - ty, - ty_fn_ptr_from, - location.to_locations(), - ConstraintCategory::Cast, - ) { - span_mirbug!( - self, - rvalue, - "equating {:?} with {:?} yields {:?}", - ty_fn_ptr_from, - ty, - terr - ); - } - } - - CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { - let sig = match op.ty(body, tcx).kind() { - ty::Closure(_, substs) => substs.as_closure().sig(), - _ => bug!(), - }; - let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety)); - - if let Err(terr) = self.eq_types( - ty, - ty_fn_ptr_from, - location.to_locations(), - ConstraintCategory::Cast, - ) { - span_mirbug!( - self, - rvalue, - "equating {:?} with {:?} yields {:?}", - ty_fn_ptr_from, - ty, - terr - ); - } - } - - CastKind::Pointer(PointerCast::UnsafeFnPointer) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); - - // The type that we see in the fcx is like - // `foo::<'a, 'b>`, where `foo` is the path to a - // function definition. When we extract the - // signature, it comes from the `fn_sig` query, - // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); - - let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); - - if let Err(terr) = self.eq_types( - ty, - ty_fn_ptr_from, - location.to_locations(), - ConstraintCategory::Cast, - ) { - span_mirbug!( - self, - rvalue, - "equating {:?} with {:?} yields {:?}", - ty_fn_ptr_from, - ty, - terr - ); - } - } - - CastKind::Pointer(PointerCast::Unsize) => { - let &ty = ty; - let trait_ref = ty::TraitRef { - def_id: tcx - .require_lang_item(LangItem::CoerceUnsized, Some(self.last_span)), - substs: tcx.mk_substs_trait(op.ty(body, tcx), &[ty.into()]), - }; - - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::Cast, - ); - } - - CastKind::Pointer(PointerCast::MutToConstPointer) => { - let ty_from = match op.ty(body, tcx).kind() { - ty::RawPtr(ty::TypeAndMut { - ty: ty_from, - mutbl: hir::Mutability::Mut, - }) => ty_from, - _ => { - span_mirbug!( - self, - rvalue, - "unexpected base type for cast {:?}", - ty, - ); - return; - } - }; - let ty_to = match ty.kind() { - ty::RawPtr(ty::TypeAndMut { - ty: ty_to, - mutbl: hir::Mutability::Not, - }) => ty_to, - _ => { - span_mirbug!( - self, - rvalue, - "unexpected target type for cast {:?}", - ty, - ); - return; - } - }; - if let Err(terr) = self.sub_types( - ty_from, - ty_to, - location.to_locations(), - ConstraintCategory::Cast, - ) { - span_mirbug!( - self, - rvalue, - "relating {:?} with {:?} yields {:?}", - ty_from, - ty_to, - terr - ); - } - } - - CastKind::Pointer(PointerCast::ArrayToPointer) => { - let ty_from = op.ty(body, tcx); - - let opt_ty_elem_mut = match ty_from.kind() { - ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => { - match array_ty.kind() { - ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)), - _ => None, - } - } - _ => None, - }; - - let (ty_elem, ty_mut) = match opt_ty_elem_mut { - Some(ty_elem_mut) => ty_elem_mut, - None => { - span_mirbug!( - self, - rvalue, - "ArrayToPointer cast from unexpected type {:?}", - ty_from, - ); - return; - } - }; - - let (ty_to, ty_to_mut) = match ty.kind() { - ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => { - (ty_to, *ty_to_mut) - } - _ => { - span_mirbug!( - self, - rvalue, - "ArrayToPointer cast to unexpected type {:?}", - ty, - ); - return; - } - }; - - if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not { - span_mirbug!( - self, - rvalue, - "ArrayToPointer cast from const {:?} to mut {:?}", - ty, - ty_to - ); - return; - } - - if let Err(terr) = self.sub_types( - ty_elem, - ty_to, - location.to_locations(), - ConstraintCategory::Cast, - ) { - span_mirbug!( - self, - rvalue, - "relating {:?} with {:?} yields {:?}", - ty_elem, - ty_to, - terr - ) - } - } - - CastKind::Misc => { - let ty_from = op.ty(body, tcx); - let cast_ty_from = CastTy::from_ty(ty_from); - let cast_ty_to = CastTy::from_ty(ty); - match (cast_ty_from, cast_ty_to) { - (None, _) - | (_, None | Some(CastTy::FnPtr)) - | (Some(CastTy::Float), Some(CastTy::Ptr(_))) - | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => { - span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,) - } - ( - Some(CastTy::Int(_)), - Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)), - ) - | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float)) - | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_))) - | (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (), - } - } - } - } - - Rvalue::Ref(region, _borrow_kind, borrowed_place) => { - self.add_reborrow_constraint(&body, location, region, borrowed_place); - } - - Rvalue::BinaryOp( - BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, - box (left, right), - ) => { - let ty_left = left.ty(body, tcx); - match ty_left.kind() { - // Types with regions are comparable if they have a common super-type. - ty::RawPtr(_) | ty::FnPtr(_) => { - let ty_right = right.ty(body, tcx); - let common_ty = self.infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: body.source_info(location).span, - }); - self.sub_types( - ty_left, - common_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) - .unwrap_or_else(|err| { - bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) - }); - if let Err(terr) = self.sub_types( - ty_right, - common_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - rvalue, - "unexpected comparison types {:?} and {:?} yields {:?}", - ty_left, - ty_right, - terr - ) - } - } - // For types with no regions we can just check that the - // both operands have the same type. - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) - if ty_left == right.ty(body, tcx) => {} - // Other types are compared by trait methods, not by - // `Rvalue::BinaryOp`. - _ => span_mirbug!( - self, - rvalue, - "unexpected comparison types {:?} and {:?}", - ty_left, - right.ty(body, tcx) - ), - } - } - - Rvalue::AddressOf(..) - | Rvalue::ThreadLocalRef(..) - | Rvalue::Use(..) - | Rvalue::Len(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) => {} - } - } - - /// If this rvalue supports a user-given type annotation, then - /// extract and return it. This represents the final type of the - /// rvalue and will be unified with the inferred type. - fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option { - match rvalue { - Rvalue::Use(_) - | Rvalue::ThreadLocalRef(_) - | Rvalue::Repeat(..) - | Rvalue::Ref(..) - | Rvalue::AddressOf(..) - | Rvalue::Len(..) - | Rvalue::Cast(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::NullaryOp(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) => None, - - Rvalue::Aggregate(aggregate, _) => match **aggregate { - AggregateKind::Adt(_, _, _, user_ty, _) => user_ty, - AggregateKind::Array(_) => None, - AggregateKind::Tuple => None, - AggregateKind::Closure(_, _) => None, - AggregateKind::Generator(_, _, _) => None, - }, - } - } - - fn check_aggregate_rvalue( - &mut self, - body: &Body<'tcx>, - rvalue: &Rvalue<'tcx>, - aggregate_kind: &AggregateKind<'tcx>, - operands: &[Operand<'tcx>], - location: Location, - ) { - let tcx = self.tcx(); - - self.prove_aggregate_predicates(aggregate_kind, location); - - if *aggregate_kind == AggregateKind::Tuple { - // tuple rvalue field type is always the type of the op. Nothing to check here. - return; - } - - for (i, operand) in operands.iter().enumerate() { - let field_ty = match self.aggregate_field_ty(aggregate_kind, i, location) { - Ok(field_ty) => field_ty, - Err(FieldAccessError::OutOfRange { field_count }) => { - span_mirbug!( - self, - rvalue, - "accessed field #{} but variant only has {}", - i, - field_count - ); - continue; - } - }; - let operand_ty = operand.ty(body, tcx); - let operand_ty = self.normalize(operand_ty, location); - - if let Err(terr) = self.sub_types( - operand_ty, - field_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - rvalue, - "{:?} is not a subtype of {:?}: {:?}", - operand_ty, - field_ty, - terr - ); - } - } - } - - /// Adds the constraints that arise from a borrow expression `&'a P` at the location `L`. - /// - /// # Parameters - /// - /// - `location`: the location `L` where the borrow expression occurs - /// - `borrow_region`: the region `'a` associated with the borrow - /// - `borrowed_place`: the place `P` being borrowed - fn add_reborrow_constraint( - &mut self, - body: &Body<'tcx>, - location: Location, - borrow_region: ty::Region<'tcx>, - borrowed_place: &Place<'tcx>, - ) { - // These constraints are only meaningful during borrowck: - let BorrowCheckContext { borrow_set, location_table, all_facts, constraints, .. } = - self.borrowck_context; - - // In Polonius mode, we also push a `loan_issued_at` fact - // linking the loan to the region (in some cases, though, - // there is no loan associated with this borrow expression -- - // that occurs when we are borrowing an unsafe place, for - // example). - if let Some(all_facts) = all_facts { - let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - if let Some(borrow_index) = borrow_set.get_index_of(&location) { - let region_vid = borrow_region.to_region_vid(); - all_facts.loan_issued_at.push(( - region_vid, - borrow_index, - location_table.mid_index(location), - )); - } - } - - // If we are reborrowing the referent of another reference, we - // need to add outlives relationships. In a case like `&mut - // *p`, where the `p` has type `&'b mut Foo`, for example, we - // need to ensure that `'b: 'a`. - - debug!( - "add_reborrow_constraint({:?}, {:?}, {:?})", - location, borrow_region, borrowed_place - ); - - let mut cursor = borrowed_place.projection.as_ref(); - let tcx = self.infcx.tcx; - let field = path_utils::is_upvar_field_projection( - tcx, - &self.borrowck_context.upvars, - borrowed_place.as_ref(), - body, - ); - let category = if let Some(field) = field { - let var_hir_id = self.borrowck_context.upvars[field.index()].place.get_root_variable(); - // FIXME(project-rfc-2229#8): Use Place for better diagnostics - ConstraintCategory::ClosureUpvar(var_hir_id) - } else { - ConstraintCategory::Boring - }; - - while let [proj_base @ .., elem] = cursor { - cursor = proj_base; - - debug!("add_reborrow_constraint - iteration {:?}", elem); - - match elem { - ProjectionElem::Deref => { - let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty; - - debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); - match base_ty.kind() { - ty::Ref(ref_region, _, mutbl) => { - constraints.outlives_constraints.push(OutlivesConstraint { - sup: ref_region.to_region_vid(), - sub: borrow_region.to_region_vid(), - locations: location.to_locations(), - category, - variance_info: ty::VarianceDiagInfo::default(), - }); - - match mutbl { - hir::Mutability::Not => { - // Immutable reference. We don't need the base - // to be valid for the entire lifetime of - // the borrow. - break; - } - hir::Mutability::Mut => { - // Mutable reference. We *do* need the base - // to be valid, because after the base becomes - // invalid, someone else can use our mutable deref. - - // This is in order to make the following function - // illegal: - // ``` - // fn unsafe_deref<'a, 'b>(x: &'a &'b mut T) -> &'b mut T { - // &mut *x - // } - // ``` - // - // As otherwise you could clone `&mut T` using the - // following function: - // ``` - // fn bad(x: &mut T) -> (&mut T, &mut T) { - // let my_clone = unsafe_deref(&'a x); - // ENDREGION 'a; - // (my_clone, x) - // } - // ``` - } - } - } - ty::RawPtr(..) => { - // deref of raw pointer, guaranteed to be valid - break; - } - ty::Adt(def, _) if def.is_box() => { - // deref of `Box`, need the base to be valid - propagate - } - _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place), - } - } - ProjectionElem::Field(..) - | ProjectionElem::Downcast(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => { - // other field access - } - } - } - } - - fn prove_aggregate_predicates( - &mut self, - aggregate_kind: &AggregateKind<'tcx>, - location: Location, - ) { - let tcx = self.tcx(); - - debug!( - "prove_aggregate_predicates(aggregate_kind={:?}, location={:?})", - aggregate_kind, location - ); - - let instantiated_predicates = match aggregate_kind { - AggregateKind::Adt(def, _, substs, _, _) => { - tcx.predicates_of(def.did).instantiate(tcx, substs) - } - - // For closures, we have some **extra requirements** we - // - // have to check. In particular, in their upvars and - // signatures, closures often reference various regions - // from the surrounding function -- we call those the - // closure's free regions. When we borrow-check (and hence - // region-check) closures, we may find that the closure - // requires certain relationships between those free - // regions. However, because those free regions refer to - // portions of the CFG of their caller, the closure is not - // in a position to verify those relationships. In that - // case, the requirements get "propagated" to us, and so - // we have to solve them here where we instantiate the - // closure. - // - // Despite the opacity of the previous parapgrah, this is - // actually relatively easy to understand in terms of the - // desugaring. A closure gets desugared to a struct, and - // these extra requirements are basically like where - // clauses on the struct. - AggregateKind::Closure(def_id, substs) - | AggregateKind::Generator(def_id, substs, _) => { - self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location) - } - - AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), - }; - - self.normalize_and_prove_instantiated_predicates( - instantiated_predicates, - location.to_locations(), - ); - } - - fn prove_closure_bounds( - &mut self, - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - substs: SubstsRef<'tcx>, - location: Location, - ) -> ty::InstantiatedPredicates<'tcx> { - if let Some(ref closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements - { - let closure_constraints = QueryRegionConstraints { - outlives: closure_region_requirements.apply_requirements( - tcx, - def_id.to_def_id(), - substs, - ), - - // Presently, closures never propagate member - // constraints to their parents -- they are enforced - // locally. This is largely a non-issue as member - // constraints only come from `-> impl Trait` and - // friends which don't appear (thus far...) in - // closures. - member_constraints: vec![], - }; - - let bounds_mapping = closure_constraints - .outlives - .iter() - .enumerate() - .filter_map(|(idx, constraint)| { - let ty::OutlivesPredicate(k1, r2) = - constraint.no_bound_vars().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound vars", constraint,); - }); - - match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - // constraint is r1: r2 - let r1_vid = self.borrowck_context.universal_regions.to_region_vid(r1); - let r2_vid = self.borrowck_context.universal_regions.to_region_vid(r2); - let outlives_requirements = - &closure_region_requirements.outlives_requirements[idx]; - Some(( - (r1_vid, r2_vid), - (outlives_requirements.category, outlives_requirements.blame_span), - )) - } - GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, - } - }) - .collect(); - - let existing = self - .borrowck_context - .constraints - .closure_bounds_mapping - .insert(location, bounds_mapping); - assert!(existing.is_none(), "Multiple closures at the same location."); - - self.push_region_constraints( - location.to_locations(), - ConstraintCategory::ClosureBounds, - &closure_constraints, - ); - } - - tcx.predicates_of(def_id).instantiate(tcx, substs) - } - - fn typeck_mir(&mut self, body: &Body<'tcx>) { - self.last_span = body.span; - debug!("run_on_mir: {:?}", body.span); - - for (local, local_decl) in body.local_decls.iter_enumerated() { - self.check_local(&body, local, local_decl); - } - - for (block, block_data) in body.basic_blocks().iter_enumerated() { - let mut location = Location { block, statement_index: 0 }; - for stmt in &block_data.statements { - if !stmt.source_info.span.is_dummy() { - self.last_span = stmt.source_info.span; - } - self.check_stmt(body, stmt, location); - location.statement_index += 1; - } - - self.check_terminator(&body, block_data.terminator(), location); - self.check_iscleanup(&body, block_data); - } - } -} - -trait NormalizeLocation: fmt::Debug + Copy { - fn to_locations(self) -> Locations; -} - -impl NormalizeLocation for Locations { - fn to_locations(self) -> Locations { - self - } -} - -impl NormalizeLocation for Location { - fn to_locations(self) -> Locations { - Locations::Single(self) - } -} - -#[derive(Debug, Default)] -struct ObligationAccumulator<'tcx> { - obligations: PredicateObligations<'tcx>, -} - -impl<'tcx> ObligationAccumulator<'tcx> { - fn add(&mut self, value: InferOk<'tcx, T>) -> T { - let InferOk { value, obligations } = value; - self.obligations.extend(obligations); - value - } - - fn into_vec(self) -> PredicateObligations<'tcx> { - self.obligations - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, Const, Ty}; -use rustc_trait_selection::traits::query::Fallible; - -use crate::borrow_check::constraints::OutlivesConstraint; -use crate::borrow_check::diagnostics::UniverseInfo; -use crate::borrow_check::type_check::{BorrowCheckContext, Locations}; - -/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: -/// -/// - "Covariant" `a <: b` -/// - "Invariant" `a == b` -/// - "Contravariant" `a :> b` -/// -/// N.B., the type `a` is permitted to have unresolved inference -/// variables, but not the type `b`. -pub(super) fn relate_types<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: Ty<'tcx>, - v: ty::Variance, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - borrowck_context: &mut BorrowCheckContext<'_, 'tcx>, -) -> Fallible<()> { - debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations); - TypeRelating::new( - infcx, - NllTypeRelatingDelegate::new( - infcx, - borrowck_context, - param_env, - locations, - category, - UniverseInfo::relate(a, b), - ), - v, - ) - .relate(a, b)?; - Ok(()) -} - -struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { - infcx: &'me InferCtxt<'me, 'tcx>, - borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>, - - param_env: ty::ParamEnv<'tcx>, - - /// Where (and why) is this relation taking place? - locations: Locations, - - /// What category do we assign the resulting `'a: 'b` relationships? - category: ConstraintCategory, - - /// Information so that error reporting knows what types we are relating - /// when reporting a bound region error. - universe_info: UniverseInfo<'tcx>, -} - -impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { - fn new( - infcx: &'me InferCtxt<'me, 'tcx>, - borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - locations: Locations, - category: ConstraintCategory, - universe_info: UniverseInfo<'tcx>, - ) -> Self { - Self { infcx, borrowck_context, param_env, locations, category, universe_info } - } -} - -impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn create_next_universe(&mut self) -> ty::UniverseIndex { - let info_universe = - self.borrowck_context.constraints.universe_causes.push(self.universe_info.clone()); - let universe = self.infcx.create_next_universe(); - assert_eq!(info_universe, universe); - universe - } - - fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { - let origin = NllRegionVariableOrigin::Existential { from_forall }; - self.infcx.next_nll_region_var(origin) - } - - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder) - } - - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - self.infcx.next_nll_region_var_in_universe( - NllRegionVariableOrigin::Existential { from_forall: false }, - universe, - ) - } - - fn push_outlives( - &mut self, - sup: ty::Region<'tcx>, - sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, - ) { - let sub = self.borrowck_context.universal_regions.to_region_vid(sub); - let sup = self.borrowck_context.universal_regions.to_region_vid(sup); - self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint { - sup, - sub, - locations: self.locations, - category: self.category, - variance_info: info, - }); - } - - // We don't have to worry about the equality of consts during borrow checking - // as consts always have a static lifetime. - fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {} - - fn normalization() -> NormalizationStrategy { - NormalizationStrategy::Eager - } - - fn forbid_inference_vars() -> bool { - true - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/universal_regions.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/universal_regions.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/universal_regions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/universal_regions.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,817 +0,0 @@ -//! Code to extract the universally quantified regions declared on a -//! function and the relationships between them. For example: -//! -//! ``` -//! fn foo<'a, 'b, 'c: 'b>() { } -//! ``` -//! -//! here we would return a map assigning each of `{'a, 'b, 'c}` -//! to an index, as well as the `FreeRegionMap` which can compute -//! relationships between them. -//! -//! The code in this file doesn't *do anything* with those results; it -//! just returns them for other code to use. - -use either::Either; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::DiagnosticBuilder; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::lang_items::LangItem; -use rustc_hir::{BodyOwnerKind, HirId}; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; -use std::iter; - -use crate::borrow_check::nll::ToRegionVid; - -#[derive(Debug)] -pub struct UniversalRegions<'tcx> { - indices: UniversalRegionIndices<'tcx>, - - /// The vid assigned to `'static` - pub fr_static: RegionVid, - - /// A special region vid created to represent the current MIR fn - /// body. It will outlive the entire CFG but it will not outlive - /// any other universal regions. - pub fr_fn_body: RegionVid, - - /// We create region variables such that they are ordered by their - /// `RegionClassification`. The first block are globals, then - /// externals, then locals. So, things from: - /// - `FIRST_GLOBAL_INDEX..first_extern_index` are global, - /// - `first_extern_index..first_local_index` are external, - /// - `first_local_index..num_universals` are local. - first_extern_index: usize, - - /// See `first_extern_index`. - first_local_index: usize, - - /// The total number of universal region variables instantiated. - num_universals: usize, - - /// A special region variable created for the `'empty(U0)` region. - /// Note that this is **not** a "universal" region, as it doesn't - /// represent a universally bound placeholder or any such thing. - /// But we do create it here in this type because it's a useful region - /// to have around in a few limited cases. - pub root_empty: RegionVid, - - /// The "defining" type for this function, with all universal - /// regions instantiated. For a closure or generator, this is the - /// closure type, but for a top-level function it's the `FnDef`. - pub defining_ty: DefiningTy<'tcx>, - - /// The return type of this function, with all regions replaced by - /// their universal `RegionVid` equivalents. - /// - /// N.B., associated types in this type have not been normalized, - /// as the name suggests. =) - pub unnormalized_output_ty: Ty<'tcx>, - - /// The fully liberated input types of this function, with all - /// regions replaced by their universal `RegionVid` equivalents. - /// - /// N.B., associated types in these types have not been normalized, - /// as the name suggests. =) - pub unnormalized_input_tys: &'tcx [Ty<'tcx>], - - pub yield_ty: Option>, -} - -/// The "defining type" for this MIR. The key feature of the "defining -/// type" is that it contains the information needed to derive all the -/// universal regions that are in scope as well as the types of the -/// inputs/output from the MIR. In general, early-bound universal -/// regions appear free in the defining type and late-bound regions -/// appear bound in the signature. -#[derive(Copy, Clone, Debug)] -pub enum DefiningTy<'tcx> { - /// The MIR is a closure. The signature is found via - /// `ClosureSubsts::closure_sig_ty`. - Closure(DefId, SubstsRef<'tcx>), - - /// The MIR is a generator. The signature is that generators take - /// no parameters and return the result of - /// `ClosureSubsts::generator_return_ty`. - Generator(DefId, SubstsRef<'tcx>, hir::Movability), - - /// The MIR is a fn item with the given `DefId` and substs. The signature - /// of the function can be bound then with the `fn_sig` query. - FnDef(DefId, SubstsRef<'tcx>), - - /// The MIR represents some form of constant. The signature then - /// is that it has no inputs and a single return value, which is - /// the value of the constant. - Const(DefId, SubstsRef<'tcx>), -} - -impl<'tcx> DefiningTy<'tcx> { - /// Returns a list of all the upvar types for this MIR. If this is - /// not a closure or generator, there are no upvars, and hence it - /// will be an empty list. The order of types in this list will - /// match up with the upvar order in the HIR, typesystem, and MIR. - pub fn upvar_tys(self) -> impl Iterator> + 'tcx { - match self { - DefiningTy::Closure(_, substs) => Either::Left(substs.as_closure().upvar_tys()), - DefiningTy::Generator(_, substs, _) => { - Either::Right(Either::Left(substs.as_generator().upvar_tys())) - } - DefiningTy::FnDef(..) | DefiningTy::Const(..) => { - Either::Right(Either::Right(iter::empty())) - } - } - } - - /// Number of implicit inputs -- notably the "environment" - /// parameter for closures -- that appear in MIR but not in the - /// user's code. - pub fn implicit_inputs(self) -> usize { - match self { - DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1, - DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0, - } - } - - pub fn is_fn_def(&self) -> bool { - match *self { - DefiningTy::FnDef(..) => true, - _ => false, - } - } - - pub fn is_const(&self) -> bool { - match *self { - DefiningTy::Const(..) => true, - _ => false, - } - } - - pub fn def_id(&self) -> DefId { - match *self { - DefiningTy::Closure(def_id, ..) - | DefiningTy::Generator(def_id, ..) - | DefiningTy::FnDef(def_id, ..) - | DefiningTy::Const(def_id, ..) => def_id, - } - } -} - -#[derive(Debug)] -struct UniversalRegionIndices<'tcx> { - /// For those regions that may appear in the parameter environment - /// ('static and early-bound regions), we maintain a map from the - /// `ty::Region` to the internal `RegionVid` we are using. This is - /// used because trait matching and type-checking will feed us - /// region constraints that reference those regions and we need to - /// be able to map them our internal `RegionVid`. This is - /// basically equivalent to an `InternalSubsts`, except that it also - /// contains an entry for `ReStatic` -- it might be nice to just - /// use a substs, and then handle `ReStatic` another way. - indices: FxHashMap, RegionVid>, -} - -#[derive(Debug, PartialEq)] -pub enum RegionClassification { - /// A **global** region is one that can be named from - /// anywhere. There is only one, `'static`. - Global, - - /// An **external** region is only relevant for closures. In that - /// case, it refers to regions that are free in the closure type - /// -- basically, something bound in the surrounding context. - /// - /// Consider this example: - /// - /// ``` - /// fn foo<'a, 'b>(a: &'a u32, b: &'b u32, c: &'static u32) { - /// let closure = for<'x> |x: &'x u32| { .. }; - /// ^^^^^^^ pretend this were legal syntax - /// for declaring a late-bound region in - /// a closure signature - /// } - /// ``` - /// - /// Here, the lifetimes `'a` and `'b` would be **external** to the - /// closure. - /// - /// If we are not analyzing a closure, there are no external - /// lifetimes. - External, - - /// A **local** lifetime is one about which we know the full set - /// of relevant constraints (that is, relationships to other named - /// regions). For a closure, this includes any region bound in - /// the closure's signature. For a fn item, this includes all - /// regions other than global ones. - /// - /// Continuing with the example from `External`, if we were - /// analyzing the closure, then `'x` would be local (and `'a` and - /// `'b` are external). If we are analyzing the function item - /// `foo`, then `'a` and `'b` are local (and `'x` is not in - /// scope). - Local, -} - -const FIRST_GLOBAL_INDEX: usize = 0; - -impl<'tcx> UniversalRegions<'tcx> { - /// Creates a new and fully initialized `UniversalRegions` that - /// contains indices for all the free regions found in the given - /// MIR -- that is, all the regions that appear in the function's - /// signature. This will also compute the relationships that are - /// known between those regions. - pub fn new( - infcx: &InferCtxt<'_, 'tcx>, - mir_def: ty::WithOptConstParam, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - let tcx = infcx.tcx; - let mir_hir_id = tcx.hir().local_def_id_to_hir_id(mir_def.did); - UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build() - } - - /// Given a reference to a closure type, extracts all the values - /// from its free regions and returns a vector with them. This is - /// used when the closure's creator checks that the - /// `ClosureRegionRequirements` are met. The requirements from - /// `ClosureRegionRequirements` are expressed in terms of - /// `RegionVid` entries that map into the returned vector `V`: so - /// if the `ClosureRegionRequirements` contains something like - /// `'1: '2`, then the caller would impose the constraint that - /// `V[1]: V[2]`. - pub fn closure_mapping( - tcx: TyCtxt<'tcx>, - closure_substs: SubstsRef<'tcx>, - expected_num_vars: usize, - closure_base_def_id: DefId, - ) -> IndexVec> { - let mut region_mapping = IndexVec::with_capacity(expected_num_vars); - region_mapping.push(tcx.lifetimes.re_static); - tcx.for_each_free_region(&closure_substs, |fr| { - region_mapping.push(fr); - }); - - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { - region_mapping.push(r); - }); - - assert_eq!( - region_mapping.len(), - expected_num_vars, - "index vec had unexpected number of variables" - ); - - region_mapping - } - - /// Returns `true` if `r` is a member of this set of universal regions. - pub fn is_universal_region(&self, r: RegionVid) -> bool { - (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index()) - } - - /// Classifies `r` as a universal region, returning `None` if this - /// is not a member of this set of universal regions. - pub fn region_classification(&self, r: RegionVid) -> Option { - let index = r.index(); - if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index) { - Some(RegionClassification::Global) - } else if (self.first_extern_index..self.first_local_index).contains(&index) { - Some(RegionClassification::External) - } else if (self.first_local_index..self.num_universals).contains(&index) { - Some(RegionClassification::Local) - } else { - None - } - } - - /// Returns an iterator over all the RegionVids corresponding to - /// universally quantified free regions. - pub fn universal_regions(&self) -> impl Iterator { - (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new) - } - - /// Returns `true` if `r` is classified as an local region. - pub fn is_local_free_region(&self, r: RegionVid) -> bool { - self.region_classification(r) == Some(RegionClassification::Local) - } - - /// Returns the number of universal regions created in any category. - pub fn len(&self) -> usize { - self.num_universals - } - - /// Returns the number of global plus external universal regions. - /// For closures, these are the regions that appear free in the - /// closure type (versus those bound in the closure - /// signature). They are therefore the regions between which the - /// closure may impose constraints that its creator must verify. - pub fn num_global_and_external_regions(&self) -> usize { - self.first_local_index - } - - /// Gets an iterator over all the early-bound regions that have names. - pub fn named_universal_regions<'s>( - &'s self, - ) -> impl Iterator, ty::RegionVid)> + 's { - self.indices.indices.iter().map(|(&r, &v)| (r, v)) - } - - /// See `UniversalRegionIndices::to_region_vid`. - pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - if let ty::ReEmpty(ty::UniverseIndex::ROOT) = r { - self.root_empty - } else { - self.indices.to_region_vid(r) - } - } - - /// As part of the NLL unit tests, you can annotate a function with - /// `#[rustc_regions]`, and we will emit information about the region - /// inference context and -- in particular -- the external constraints - /// that this region imposes on others. The methods in this file - /// handle the part about dumping the inference context internal - /// state. - crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) { - match self.defining_ty { - DefiningTy::Closure(def_id, substs) => { - err.note(&format!( - "defining type: {} with closure substs {:#?}", - tcx.def_path_str_with_substs(def_id, substs), - &substs[tcx.generics_of(def_id).parent_count..], - )); - - // FIXME: It'd be nice to print the late-bound regions - // here, but unfortunately these wind up stored into - // tests, and the resulting print-outs include def-ids - // and other things that are not stable across tests! - // So we just include the region-vid. Annoying. - let closure_base_def_id = tcx.closure_base_def_id(def_id); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { - err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); - }); - } - DefiningTy::Generator(def_id, substs, _) => { - err.note(&format!( - "defining type: {} with generator substs {:#?}", - tcx.def_path_str_with_substs(def_id, substs), - &substs[tcx.generics_of(def_id).parent_count..], - )); - - // FIXME: As above, we'd like to print out the region - // `r` but doing so is not stable across architectures - // and so forth. - let closure_base_def_id = tcx.closure_base_def_id(def_id); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { - err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); - }); - } - DefiningTy::FnDef(def_id, substs) => { - err.note(&format!( - "defining type: {}", - tcx.def_path_str_with_substs(def_id, substs), - )); - } - DefiningTy::Const(def_id, substs) => { - err.note(&format!( - "defining constant type: {}", - tcx.def_path_str_with_substs(def_id, substs), - )); - } - } - } -} - -struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - mir_def: ty::WithOptConstParam, - mir_hir_id: HirId, - param_env: ty::ParamEnv<'tcx>, -} - -const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion; - -impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { - fn build(self) -> UniversalRegions<'tcx> { - debug!("build(mir_def={:?})", self.mir_def); - - let param_env = self.param_env; - debug!("build: param_env={:?}", param_env); - - assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); - - // Create the "global" region that is always free in all contexts: 'static. - let fr_static = self.infcx.next_nll_region_var(FR).to_region_vid(); - - // We've now added all the global regions. The next ones we - // add will be external. - let first_extern_index = self.infcx.num_region_vars(); - - let defining_ty = self.defining_ty(); - debug!("build: defining_ty={:?}", defining_ty); - - let mut indices = self.compute_indices(fr_static, defining_ty); - debug!("build: indices={:?}", indices); - - let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id()); - - // If this is a closure or generator, then the late-bound regions from the enclosing - // function are actually external regions to us. For example, here, 'a is not local - // to the closure c (although it is local to the fn foo): - // fn foo<'a>() { - // let c = || { let x: &'a u32 = ...; } - // } - if self.mir_def.did.to_def_id() != closure_base_def_id { - self.infcx - .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices) - } - - let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); - - // "Liberate" the late-bound regions. These correspond to - // "local" free regions. - let first_local_index = self.infcx.num_region_vars(); - let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( - FR, - self.mir_def.did, - bound_inputs_and_output, - &mut indices, - ); - // Converse of above, if this is a function then the late-bound regions declared on its - // signature are local to the fn. - if self.mir_def.did.to_def_id() == closure_base_def_id { - self.infcx - .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices); - } - - let (unnormalized_output_ty, mut unnormalized_input_tys) = - inputs_and_output.split_last().unwrap(); - - // C-variadic fns also have a `VaList` input that's not listed in the signature - // (as it's created inside the body itself, not passed in from outside). - if let DefiningTy::FnDef(def_id, _) = defining_ty { - if self.infcx.tcx.fn_sig(def_id).c_variadic() { - let va_list_did = self.infcx.tcx.require_lang_item( - LangItem::VaList, - Some(self.infcx.tcx.def_span(self.mir_def.did)), - ); - let region = self - .infcx - .tcx - .mk_region(ty::ReVar(self.infcx.next_nll_region_var(FR).to_region_vid())); - let va_list_ty = - self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]); - - unnormalized_input_tys = self.infcx.tcx.mk_type_list( - unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)), - ); - } - } - - let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid(); - let num_universals = self.infcx.num_region_vars(); - - debug!("build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index); - debug!("build: extern regions = {}..{}", first_extern_index, first_local_index); - debug!("build: local regions = {}..{}", first_local_index, num_universals); - - let yield_ty = match defining_ty { - DefiningTy::Generator(_, substs, _) => Some(substs.as_generator().yield_ty()), - _ => None, - }; - - let root_empty = self - .infcx - .next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion) - .to_region_vid(); - - UniversalRegions { - indices, - fr_static, - fr_fn_body, - root_empty, - first_extern_index, - first_local_index, - num_universals, - defining_ty, - unnormalized_output_ty, - unnormalized_input_tys, - yield_ty, - } - } - - /// Returns the "defining type" of the current MIR; - /// see `DefiningTy` for details. - fn defining_ty(&self) -> DefiningTy<'tcx> { - let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); - - match tcx.hir().body_owner_kind(self.mir_hir_id) { - BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id { - tcx.type_of(closure_base_def_id) - } else { - let tables = tcx.typeck(self.mir_def.did); - tables.node_type(self.mir_hir_id) - }; - - debug!("defining_ty (pre-replacement): {:?}", defining_ty); - - let defining_ty = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, defining_ty); - - match *defining_ty.kind() { - ty::Closure(def_id, substs) => DefiningTy::Closure(def_id, substs), - ty::Generator(def_id, substs, movability) => { - DefiningTy::Generator(def_id, substs, movability) - } - ty::FnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs), - _ => span_bug!( - tcx.def_span(self.mir_def.did), - "expected defining type for `{:?}`: `{:?}`", - self.mir_def.did, - defining_ty - ), - } - } - - BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { - assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id); - let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); - let substs = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); - DefiningTy::Const(self.mir_def.did.to_def_id(), substs) - } - } - } - - /// Builds a hashmap that maps from the universal regions that are - /// in scope (as a `ty::Region<'tcx>`) to their indices (as a - /// `RegionVid`). The map returned by this function contains only - /// the early-bound regions. - fn compute_indices( - &self, - fr_static: RegionVid, - defining_ty: DefiningTy<'tcx>, - ) -> UniversalRegionIndices<'tcx> { - let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); - let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); - let fr_substs = match defining_ty { - DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => { - // In the case of closures, we rely on the fact that - // the first N elements in the ClosureSubsts are - // inherited from the `closure_base_def_id`. - // Therefore, when we zip together (below) with - // `identity_substs`, we will get only those regions - // that correspond to early-bound regions declared on - // the `closure_base_def_id`. - assert!(substs.len() >= identity_substs.len()); - assert_eq!(substs.regions().count(), identity_substs.regions().count()); - substs - } - - DefiningTy::FnDef(_, substs) | DefiningTy::Const(_, substs) => substs, - }; - - let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); - let subst_mapping = - iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid())); - - UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect() } - } - - fn compute_inputs_and_output( - &self, - indices: &UniversalRegionIndices<'tcx>, - defining_ty: DefiningTy<'tcx>, - ) -> ty::Binder<'tcx, &'tcx ty::List>> { - let tcx = self.infcx.tcx; - match defining_ty { - DefiningTy::Closure(def_id, substs) => { - assert_eq!(self.mir_def.did.to_def_id(), def_id); - let closure_sig = substs.as_closure().sig(); - let inputs_and_output = closure_sig.inputs_and_output(); - let bound_vars = tcx.mk_bound_variable_kinds( - inputs_and_output - .bound_vars() - .iter() - .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), - ); - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind: ty::BrEnv, - }; - let env_region = ty::ReLateBound(ty::INNERMOST, br); - let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); - - // The "inputs" of the closure in the - // signature appear as a tuple. The MIR side - // flattens this tuple. - let (&output, tuplized_inputs) = - inputs_and_output.skip_binder().split_last().unwrap(); - assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); - let inputs = match tuplized_inputs[0].kind() { - ty::Tuple(inputs) => inputs, - _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]), - }; - - ty::Binder::bind_with_vars( - tcx.mk_type_list( - iter::once(closure_ty) - .chain(inputs.iter().map(|k| k.expect_ty())) - .chain(iter::once(output)), - ), - bound_vars, - ) - } - - DefiningTy::Generator(def_id, substs, movability) => { - assert_eq!(self.mir_def.did.to_def_id(), def_id); - let resume_ty = substs.as_generator().resume_ty(); - let output = substs.as_generator().return_ty(); - let generator_ty = tcx.mk_generator(def_id, substs, movability); - let inputs_and_output = - self.infcx.tcx.intern_type_list(&[generator_ty, resume_ty, output]); - ty::Binder::dummy(inputs_and_output) - } - - DefiningTy::FnDef(def_id, _) => { - let sig = tcx.fn_sig(def_id); - let sig = indices.fold_to_region_vids(tcx, sig); - sig.inputs_and_output() - } - - DefiningTy::Const(def_id, _) => { - // For a constant body, there are no inputs, and one - // "output" (the type of the constant). - assert_eq!(self.mir_def.did.to_def_id(), def_id); - let ty = tcx.type_of(self.mir_def.def_id_for_type_of()); - let ty = indices.fold_to_region_vids(tcx, ty); - ty::Binder::dummy(tcx.intern_type_list(&[ty])) - } - } - } -} - -trait InferCtxtExt<'tcx> { - fn replace_free_regions_with_nll_infer_vars( - &self, - origin: NllRegionVariableOrigin, - value: T, - ) -> T - where - T: TypeFoldable<'tcx>; - - fn replace_bound_regions_with_nll_infer_vars( - &self, - origin: NllRegionVariableOrigin, - all_outlive_scope: LocalDefId, - value: ty::Binder<'tcx, T>, - indices: &mut UniversalRegionIndices<'tcx>, - ) -> T - where - T: TypeFoldable<'tcx>; - - fn replace_late_bound_regions_with_nll_infer_vars( - &self, - mir_def_id: LocalDefId, - indices: &mut UniversalRegionIndices<'tcx>, - ); -} - -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { - fn replace_free_regions_with_nll_infer_vars( - &self, - origin: NllRegionVariableOrigin, - value: T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin)) - } - - fn replace_bound_regions_with_nll_infer_vars( - &self, - origin: NllRegionVariableOrigin, - all_outlive_scope: LocalDefId, - value: ty::Binder<'tcx, T>, - indices: &mut UniversalRegionIndices<'tcx>, - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!( - "replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})", - value, all_outlive_scope, - ); - let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { - debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br); - let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope: all_outlive_scope.to_def_id(), - bound_region: br.kind, - })); - let region_vid = self.next_nll_region_var(origin); - indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); - debug!( - "replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}", - liberated_region, region_vid - ); - region_vid - }); - value - } - - /// Finds late-bound regions that do not appear in the parameter listing and adds them to the - /// indices vector. Typically, we identify late-bound regions as we process the inputs and - /// outputs of the closure/function. However, sometimes there are late-bound regions which do - /// not appear in the fn parameters but which are nonetheless in scope. The simplest case of - /// this are unused functions, like fn foo<'a>() { } (see e.g., #51351). Despite not being used, - /// users can still reference these regions (e.g., let x: &'a u32 = &22;), so we need to create - /// entries for them and store them in the indices map. This code iterates over the complete - /// set of late-bound regions and checks for any that we have not yet seen, adding them to the - /// inputs vector. - fn replace_late_bound_regions_with_nll_infer_vars( - &self, - mir_def_id: LocalDefId, - indices: &mut UniversalRegionIndices<'tcx>, - ) { - debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); - let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id()); - for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| { - debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); - if !indices.indices.contains_key(&r) { - let region_vid = self.next_nll_region_var(FR); - indices.insert_late_bound_region(r, region_vid.to_region_vid()); - } - }); - } -} - -impl<'tcx> UniversalRegionIndices<'tcx> { - /// Initially, the `UniversalRegionIndices` map contains only the - /// early-bound regions in scope. Once that is all setup, we come - /// in later and instantiate the late-bound regions, and then we - /// insert the `ReFree` version of those into the map as - /// well. These are used for error reporting. - fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) { - debug!("insert_late_bound_region({:?}, {:?})", r, vid); - self.indices.insert(r, vid); - } - - /// Converts `r` into a local inference variable: `r` can either - /// by a `ReVar` (i.e., already a reference to an inference - /// variable) or it can be `'static` or some early-bound - /// region. This is useful when taking the results from - /// type-checking and trait-matching, which may sometimes - /// reference those regions from the `ParamEnv`. It is also used - /// during initialization. Relies on the `indices` map having been - /// fully initialized. - pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - if let ty::ReVar(..) = r { - r.to_region_vid() - } else { - *self - .indices - .get(&r) - .unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r)) - } - } - - /// Replaces all free regions in `value` with region vids, as - /// returned by `to_region_vid`. - pub fn fold_to_region_vids(&self, tcx: TyCtxt<'tcx>, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - tcx.fold_regions(value, &mut false, |region, _| { - tcx.mk_region(ty::ReVar(self.to_region_vid(region))) - }) - } -} - -/// Iterates over the late-bound regions defined on fn_def_id and -/// invokes `f` with the liberated form of each one. -fn for_each_late_bound_region_defined_on<'tcx>( - tcx: TyCtxt<'tcx>, - fn_def_id: DefId, - mut f: impl FnMut(ty::Region<'tcx>), -) { - if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) { - for &late_bound in late_bounds.iter() { - let hir_id = HirId { owner, local_id: late_bound }; - let name = tcx.hir().name(hir_id); - let region_def_id = tcx.hir().local_def_id(hir_id); - let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope: owner.to_def_id(), - bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name), - })); - f(liberated_region); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/used_muts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/used_muts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/used_muts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/borrow_check/used_muts.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{ - Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind, -}; - -use rustc_data_structures::fx::FxHashSet; - -use crate::borrow_check::MirBorrowckCtxt; - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes - /// of the `unused_mut` lint. - /// - /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and - /// used from borrow checking. This function looks for assignments into these locals from - /// user-declared locals and adds those user-defined locals to the `used_mut` set. This can - /// occur due to a rare case involving upvars in closures. - /// - /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals - /// (not arguments) that have not already been marked as being used. - /// This function then looks for assignments from statements or the terminator into the locals - /// from this set and removes them from the set. This leaves only those locals that have not - /// been assigned to - this set is used as a proxy for locals that were not initialized due to - /// unreachable code. These locals are then considered "used" to silence the lint for them. - /// See #55344 for context. - crate fn gather_used_muts( - &mut self, - temporary_used_locals: FxHashSet, - mut never_initialized_mut_locals: FxHashSet, - ) { - { - let mut visitor = GatherUsedMutsVisitor { - temporary_used_locals, - never_initialized_mut_locals: &mut never_initialized_mut_locals, - mbcx: self, - }; - visitor.visit_body(&visitor.mbcx.body); - } - - // Take the union of the existed `used_mut` set with those variables we've found were - // never initialized. - debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals); - self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect(); - } -} - -/// MIR visitor for collecting used mutable variables. -/// The 'visit lifetime represents the duration of the MIR walk. -struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { - temporary_used_locals: FxHashSet, - never_initialized_mut_locals: &'visit mut FxHashSet, - mbcx: &'visit mut MirBorrowckCtxt<'cx, 'tcx>, -} - -impl GatherUsedMutsVisitor<'_, '_, '_> { - fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) { - // Remove any locals that we found were initialized from the - // `never_initialized_mut_locals` set. At the end, the only remaining locals will - // be those that were never initialized - we will consider those as being used as - // they will either have been removed by unreachable code optimizations; or linted - // as unused variables. - self.never_initialized_mut_locals.remove(&into.local); - } -} - -impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - debug!("visit_terminator: terminator={:?}", terminator); - match &terminator.kind { - TerminatorKind::Call { destination: Some((into, _)), .. } => { - self.remove_never_initialized_mut_locals(*into); - } - TerminatorKind::DropAndReplace { place, .. } => { - self.remove_never_initialized_mut_locals(*place); - } - _ => {} - } - - self.super_terminator(terminator, location); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - if let StatementKind::Assign(box (into, _)) = &statement.kind { - debug!( - "visit_statement: statement={:?} local={:?} \ - never_initialized_mut_locals={:?}", - statement, into.local, self.never_initialized_mut_locals - ); - self.remove_never_initialized_mut_locals(*into); - } - - self.super_statement(statement, location); - } - - fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) { - if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) { - // Propagate the Local assigned at this Location as a used mutable local variable - for moi in &self.mbcx.move_data.loc_map[location] { - let mpi = &self.mbcx.move_data.moves[*moi].path; - let path = &self.mbcx.move_data.move_paths[*mpi]; - debug!( - "assignment of {:?} to {:?}, adding {:?} to used mutable set", - path.place, local, path.place - ); - if let Some(user_local) = path.place.as_local() { - self.mbcx.used_mut.insert(user_local); - } - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/error.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/error.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/error.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/error.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,210 +0,0 @@ -use std::error::Error; -use std::fmt; - -use rustc_errors::{DiagnosticBuilder, ErrorReported}; -use rustc_hir as hir; -use rustc_middle::mir::AssertKind; -use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt}; -use rustc_span::{Span, Symbol}; - -use super::InterpCx; -use crate::interpret::{ - struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, -}; - -/// The CTFE machine has some custom error kinds. -#[derive(Clone, Debug)] -pub enum ConstEvalErrKind { - NeedsRfc(String), - ConstAccessesStatic, - ModifiedGlobal, - AssertFailure(AssertKind), - Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, - Abort(String), -} - -impl MachineStopType for ConstEvalErrKind { - fn is_hard_err(&self) -> bool { - match self { - Self::Panic { .. } => true, - _ => false, - } - } -} - -// The errors become `MachineStop` with plain strings when being raised. -// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to -// handle these. -impl<'tcx> Into> for ConstEvalErrKind { - fn into(self) -> InterpErrorInfo<'tcx> { - err_machine_stop!(self).into() - } -} - -impl fmt::Display for ConstEvalErrKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::ConstEvalErrKind::*; - match *self { - NeedsRfc(ref msg) => { - write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg) - } - ConstAccessesStatic => write!(f, "constant accesses static"), - ModifiedGlobal => { - write!(f, "modifying a static's initial value from another static's initializer") - } - AssertFailure(ref msg) => write!(f, "{:?}", msg), - Panic { msg, line, col, file } => { - write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) - } - Abort(ref msg) => write!(f, "{}", msg), - } - } -} - -impl Error for ConstEvalErrKind {} - -/// When const-evaluation errors, this type is constructed with the resulting information, -/// and then used to emit the error as a lint or hard error. -#[derive(Debug)] -pub struct ConstEvalErr<'tcx> { - pub span: Span, - pub error: InterpError<'tcx>, - pub stacktrace: Vec>, -} - -impl<'tcx> ConstEvalErr<'tcx> { - /// Turn an interpreter error into something to report to the user. - /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. - /// Should be called only if the error is actually going to to be reported! - pub fn new<'mir, M: Machine<'mir, 'tcx>>( - ecx: &InterpCx<'mir, 'tcx, M>, - error: InterpErrorInfo<'tcx>, - span: Option, - ) -> ConstEvalErr<'tcx> - where - 'tcx: 'mir, - { - error.print_backtrace(); - let stacktrace = ecx.generate_stacktrace(); - ConstEvalErr { - error: error.into_kind(), - stacktrace, - span: span.unwrap_or_else(|| ecx.cur_span()), - } - } - - pub fn struct_error( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - emit: impl FnOnce(DiagnosticBuilder<'_>), - ) -> ErrorHandled { - self.struct_generic(tcx, message, emit, None) - } - - pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled { - self.struct_error(tcx, message, |mut e| e.emit()) - } - - pub fn report_as_lint( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - lint_root: hir::HirId, - span: Option, - ) -> ErrorHandled { - self.struct_generic( - tcx, - message, - |mut lint: DiagnosticBuilder<'_>| { - // Apply the span. - if let Some(span) = span { - let primary_spans = lint.span.primary_spans().to_vec(); - // point at the actual error as the primary span - lint.replace_span_with(span); - // point to the `const` statement as a secondary span - // they don't have any label - for sp in primary_spans { - if sp != span { - lint.span_label(sp, ""); - } - } - } - lint.emit(); - }, - Some(lint_root), - ) - } - - /// Create a diagnostic for this const eval error. - /// - /// Sets the message passed in via `message` and adds span labels with detailed error - /// information before handing control back to `emit` to do any final processing. - /// It's the caller's responsibility to call emit(), stash(), etc. within the `emit` - /// function to dispose of the diagnostic properly. - /// - /// If `lint_root.is_some()` report it as a lint, else report it as a hard error. - /// (Except that for some errors, we ignore all that -- see `must_error` below.) - fn struct_generic( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - emit: impl FnOnce(DiagnosticBuilder<'_>), - lint_root: Option, - ) -> ErrorHandled { - let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option| { - trace!("reporting const eval failure at {:?}", self.span); - if let Some(span_msg) = span_msg { - err.span_label(self.span, span_msg); - } - // Add spans for the stacktrace. Don't print a single-line backtrace though. - if self.stacktrace.len() > 1 { - for frame_info in &self.stacktrace { - err.span_label(frame_info.span, frame_info.to_string()); - } - } - // Let the caller finish the job. - emit(err) - }; - - // Special handling for certain errors - match &self.error { - // Don't emit a new diagnostic for these errors - err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { - return ErrorHandled::TooGeneric; - } - err_inval!(AlreadyReported(error_reported)) => { - return ErrorHandled::Reported(*error_reported); - } - err_inval!(Layout(LayoutError::SizeOverflow(_))) => { - // We must *always* hard error on these, even if the caller wants just a lint. - // The `message` makes little sense here, this is a more serious error than the - // caller thinks anyway. - // See . - finish(struct_error(tcx, &self.error.to_string()), None); - return ErrorHandled::Reported(ErrorReported); - } - _ => {} - }; - - let err_msg = self.error.to_string(); - - // Regular case - emit a lint. - if let Some(lint_root) = lint_root { - // Report as lint. - let hir_id = - self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root); - tcx.struct_span_lint_hir( - rustc_session::lint::builtin::CONST_ERR, - hir_id, - tcx.span, - |lint| finish(lint.build(message), Some(err_msg)), - ); - ErrorHandled::Linted - } else { - // Report as hard error. - finish(struct_error(tcx, message), Some(err_msg)); - ErrorHandled::Reported(ErrorReported) - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/eval_queries.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/eval_queries.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/eval_queries.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/eval_queries.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,398 +0,0 @@ -use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; -use crate::interpret::eval_nullary_intrinsic; -use crate::interpret::{ - intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, - Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, - ScalarMaybeUninit, StackPopCleanup, -}; -use crate::util::pretty::display_allocation; - -use rustc_errors::ErrorReported; -use rustc_hir::def::DefKind; -use rustc_middle::mir; -use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::traits::Reveal; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, subst::Subst, TyCtxt}; -use rustc_span::source_map::Span; -use rustc_target::abi::{Abi, LayoutOf}; -use std::borrow::Cow; -use std::convert::TryInto; - -pub fn note_on_undefined_behavior_error() -> &'static str { - "The rules on what exactly is undefined behavior aren't clear, \ - so this check might be overzealous. Please open an issue on the rustc \ - repository if you believe it should not be considered undefined behavior." -} - -// Returns a pointer to where the result lives -fn eval_body_using_ecx<'mir, 'tcx>( - ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, - cid: GlobalId<'tcx>, - body: &'mir mir::Body<'tcx>, -) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); - let tcx = *ecx.tcx; - assert!( - cid.promoted.is_some() - || matches!( - ecx.tcx.def_kind(cid.instance.def_id()), - DefKind::Const - | DefKind::Static - | DefKind::ConstParam - | DefKind::AnonConst - | DefKind::AssocConst - ), - "Unexpected DefKind: {:?}", - ecx.tcx.def_kind(cid.instance.def_id()) - ); - let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; - assert!(!layout.is_unsized()); - let ret = ecx.allocate(layout, MemoryKind::Stack)?; - - let name = - with_no_trimmed_paths(|| ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()))); - let prom = cid.promoted.map_or_else(String::new, |p| format!("::promoted[{:?}]", p)); - trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); - - ecx.push_stack_frame( - cid.instance, - body, - Some(&ret.into()), - StackPopCleanup::None { cleanup: false }, - )?; - - // The main interpreter loop. - ecx.run()?; - - // Intern the result - let intern_kind = if cid.promoted.is_some() { - InternKind::Promoted - } else { - match tcx.static_mutability(cid.instance.def_id()) { - Some(m) => InternKind::Static(m), - None => InternKind::Constant, - } - }; - intern_const_alloc_recursive(ecx, intern_kind, &ret)?; - - debug!("eval_body_using_ecx done: {:?}", *ret); - Ok(ret) -} - -/// The `InterpCx` is only meant to be used to do field and index projections into constants for -/// `simd_shuffle` and const patterns in match arms. -/// -/// The function containing the `match` that is currently being analyzed may have generic bounds -/// that inform us about the generic bounds of the constant. E.g., using an associated constant -/// of a function's generic parameter will require knowledge about the bounds on the generic -/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(super) fn mk_eval_cx<'mir, 'tcx>( - tcx: TyCtxt<'tcx>, - root_span: Span, - param_env: ty::ParamEnv<'tcx>, - can_access_statics: bool, -) -> CompileTimeEvalContext<'mir, 'tcx> { - debug!("mk_eval_cx: {:?}", param_env); - InterpCx::new( - tcx, - root_span, - param_env, - CompileTimeInterpreter::new(tcx.const_eval_limit()), - MemoryExtra { can_access_statics }, - ) -} - -/// This function converts an interpreter value into a constant that is meant for use in the -/// type system. -pub(super) fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'_, 'tcx>, - op: &OpTy<'tcx>, -) -> ConstValue<'tcx> { - // We do not have value optimizations for everything. - // Only scalars and slices, since they are very common. - // Note that further down we turn scalars of uninitialized bits back to `ByRef`. These can result - // from scalar unions that are initialized with one of their zero sized variants. We could - // instead allow `ConstValue::Scalar` to store `ScalarMaybeUninit`, but that would affect all - // the usual cases of extracting e.g. a `usize`, without there being a real use case for the - // `Undef` situation. - let try_as_immediate = match op.layout.abi { - Abi::Scalar(..) => true, - Abi::ScalarPair(..) => match op.layout.ty.kind() { - ty::Ref(_, inner, _) => match *inner.kind() { - ty::Slice(elem) => elem == ecx.tcx.types.u8, - ty::Str => true, - _ => false, - }, - _ => false, - }, - _ => false, - }; - let immediate = if try_as_immediate { - Err(ecx.read_immediate(op).expect("normalization works on validated constants")) - } else { - // It is guaranteed that any non-slice scalar pair is actually ByRef here. - // When we come back from raw const eval, we are always by-ref. The only way our op here is - // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we - // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or - // structs containing such. - op.try_as_mplace() - }; - - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let to_const_value = |mplace: &MPlaceTy<'_>| match mplace.ptr.into_parts() { - (Some(alloc_id), offset) => { - let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory(); - ConstValue::ByRef { alloc, offset } - } - (None, offset) => { - assert!(mplace.layout.is_zst()); - assert_eq!( - offset.bytes() % mplace.layout.align.abi.bytes(), - 0, - "this MPlaceTy must come from a validated constant, thus we can assume the \ - alignment is correct", - ); - ConstValue::Scalar(Scalar::ZST) - } - }; - match immediate { - Ok(ref mplace) => to_const_value(mplace), - // see comment on `let try_as_immediate` above - Err(imm) => match *imm { - Immediate::Scalar(x) => match x { - ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place()), - }, - Immediate::ScalarPair(a, b) => { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (data, start) = match ecx.scalar_to_ptr(a.check_init().unwrap()).into_parts() { - (Some(alloc_id), offset) => { - (ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes()) - } - (None, _offset) => ( - ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable( - b"" as &[u8], - )), - 0, - ), - }; - let len = b.to_machine_usize(ecx).unwrap(); - let start = start.try_into().unwrap(); - let len: usize = len.try_into().unwrap(); - ConstValue::Slice { data, start, end: start + len } - } - }, - } -} - -fn turn_into_const_value<'tcx>( - tcx: TyCtxt<'tcx>, - constant: ConstAlloc<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ConstValue<'tcx> { - let cid = key.value; - let def_id = cid.instance.def.def_id(); - let is_static = tcx.is_static(def_id); - let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); - - let mplace = ecx.raw_const_to_mplace(constant).expect( - "can only fail if layout computation failed, \ - which should have given a good error before ever invoking this function", - ); - assert!( - !is_static || cid.promoted.is_some(), - "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" - ); - // Turn this into a proper constant. - op_to_const(&ecx, &mplace.into()) -} - -pub fn eval_to_const_value_raw_provider<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - // see comment in eval_to_allocation_raw_provider for what we're doing here - if key.param_env.reveal() == Reveal::All { - let mut key = key; - key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_const_value_raw(key) { - // try again with reveal all as requested - Err(ErrorHandled::TooGeneric) => {} - // deduplicate calls - other => return other, - } - } - - // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. - // Catch such calls and evaluate them instead of trying to load a constant's MIR. - if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty(tcx, key.param_env); - let substs = match ty.kind() { - ty::FnDef(_, substs) => substs, - _ => bug!("intrinsic with type {:?}", ty), - }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { - let span = tcx.def_span(def_id); - let error = ConstEvalErr { error: error.into_kind(), stacktrace: vec![], span }; - error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") - }); - } - - tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) -} - -pub fn eval_to_allocation_raw_provider<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - // Because the constant is computed twice (once per value of `Reveal`), we are at risk of - // reporting the same error twice here. To resolve this, we check whether we can evaluate the - // constant in the more restrictive `Reveal::UserFacing`, which most likely already was - // computed. For a large percentage of constants that will already have succeeded. Only - // associated constants of generic functions will fail due to not enough monomorphization - // information being available. - - // In case we fail in the `UserFacing` variant, we just do the real computation. - if key.param_env.reveal() == Reveal::All { - let mut key = key; - key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_allocation_raw(key) { - // try again with reveal all as requested - Err(ErrorHandled::TooGeneric) => {} - // deduplicate calls - other => return other, - } - } - if cfg!(debug_assertions) { - // Make sure we format the instance even if we do not print it. - // This serves as a regression test against an ICE on printing. - // The next two lines concatenated contain some discussion: - // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ - // subject/anon_const_instance_printing/near/135980032 - let instance = with_no_trimmed_paths(|| key.value.instance.to_string()); - trace!("const eval: {:?} ({})", key, instance); - } - - let cid = key.value; - let def = cid.instance.def.with_opt_param(); - - if let Some(def) = def.as_local() { - if tcx.has_typeck_results(def.did) { - if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors { - return Err(ErrorHandled::Reported(error_reported)); - } - } - if !tcx.is_mir_available(def.did) { - tcx.sess.delay_span_bug( - tcx.def_span(def.did), - &format!("no MIR body is available for {:?}", def.did), - ); - return Err(ErrorHandled::Reported(ErrorReported {})); - } - if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured { - return Err(ErrorHandled::Reported(error_reported)); - } - } - - let is_static = tcx.is_static(def.did); - - let mut ecx = InterpCx::new( - tcx, - tcx.def_span(def.did), - key.param_env, - CompileTimeInterpreter::new(tcx.const_eval_limit()), - // Statics (and promoteds inside statics) may access other statics, because unlike consts - // they do not have to behave "as if" they were evaluated at runtime. - MemoryExtra { can_access_statics: is_static }, - ); - - let res = ecx.load_mir(cid.instance.def, cid.promoted); - match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { - Err(error) => { - let err = ConstEvalErr::new(&ecx, error, None); - // Some CTFE errors raise just a lint, not a hard error; see - // . - let is_hard_err = if let Some(def) = def.as_local() { - // (Associated) consts only emit a lint, since they might be unused. - !matches!(tcx.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst) - // check if the inner InterpError is hard - || err.error.is_hard_err() - } else { - // use of broken constant from other crate: always an error - true - }; - - if is_hard_err { - let msg = if is_static { - Cow::from("could not evaluate static initializer") - } else { - // If the current item has generics, we'd like to enrich the message with the - // instance and its substs: to show the actual compile-time values, in addition to - // the expression, leading to the const eval error. - let instance = &key.value.instance; - if !instance.substs.is_empty() { - let instance = with_no_trimmed_paths(|| instance.to_string()); - let msg = format!("evaluation of `{}` failed", instance); - Cow::from(msg) - } else { - Cow::from("evaluation of constant value failed") - } - }; - - Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg)) - } else { - let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did); - Err(err.report_as_lint( - tcx.at(tcx.def_span(def.did)), - "any use of this value will cause an error", - hir_id, - Some(err.span), - )) - } - } - Ok(mplace) => { - // Since evaluation had no errors, validate the resulting constant. - // This is a separate `try` block to provide more targeted error reporting. - let validation = try { - let mut ref_tracking = RefTracking::new(mplace); - let mut inner = false; - while let Some((mplace, path)) = ref_tracking.todo.pop() { - let mode = match tcx.static_mutability(cid.instance.def_id()) { - Some(_) if cid.promoted.is_some() => { - // Promoteds in statics are allowed to point to statics. - CtfeValidationMode::Const { inner, allow_static_ptrs: true } - } - Some(_) => CtfeValidationMode::Regular, // a `static` - None => CtfeValidationMode::Const { inner, allow_static_ptrs: false }, - }; - ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?; - inner = true; - } - }; - let alloc_id = mplace.ptr.provenance.unwrap(); - if let Err(error) = validation { - // Validation failed, report an error. This is always a hard error. - let err = ConstEvalErr::new(&ecx, error, None); - Err(err.struct_error( - ecx.tcx, - "it is undefined behavior to use this value", - |mut diag| { - diag.note(note_on_undefined_behavior_error()); - diag.note(&format!( - "the raw bytes of the constant ({}", - display_allocation( - *ecx.tcx, - ecx.tcx.global_alloc(alloc_id).unwrap_memory() - ) - )); - diag.emit(); - }, - )) - } else { - // Convert to raw constant - Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty }) - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/fn_queries.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/fn_queries.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/fn_queries.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/fn_queries.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::Symbol; -use rustc_target::spec::abi::Abi; - -/// Whether the `def_id` counts as const fn in your current crate, considering all active -/// feature gates -pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - tcx.is_const_fn_raw(def_id) - && match is_unstable_const_fn(tcx, def_id) { - Some(feature_name) => { - // has a `rustc_const_unstable` attribute, check whether the user enabled the - // corresponding feature gate. - tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name) - } - // functions without const stability are either stable user written - // const fn or the user is using feature gates and we thus don't - // care what they do - None => true, - } -} - -/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it -pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - if tcx.is_const_fn_raw(def_id) { - let const_stab = tcx.lookup_const_stability(def_id)?; - if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None } - } else { - None - } -} - -pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { - let parent_id = tcx.hir().get_parent_did(hir_id); - if !parent_id.is_top_level_module() { is_const_impl_raw(tcx, parent_id) } else { false } -} - -/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether -/// said intrinsic has a `rustc_const_{un,}stable` attribute. -fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - - let node = tcx.hir().get(hir_id); - - if let hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) = - node - { - // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other - // foreign items cannot be evaluated at compile-time. - if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = tcx.hir().get_foreign_abi(hir_id) { - tcx.lookup_const_stability(def_id).is_some() - } else { - false - } - } else if let Some(fn_like) = FnLikeNode::from_node(node) { - if fn_like.constness() == hir::Constness::Const { - return true; - } - - // If the function itself is not annotated with `const`, it may still be a `const fn` - // if it resides in a const trait impl. - is_parent_const_impl_raw(tcx, hir_id) - } else if let hir::Node::Ctor(_) = node { - true - } else { - false - } -} - -/// Checks whether the given item is an `impl` that has a `const` modifier. -fn is_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let node = tcx.hir().get(hir_id); - matches!( - node, - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }), - .. - }) - ) -} - -fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - is_const_fn(tcx, def_id) - && match tcx.lookup_const_stability(def_id) { - Some(stab) => { - if cfg!(debug_assertions) && stab.promotable { - let sig = tcx.fn_sig(def_id); - assert_eq!( - sig.unsafety(), - hir::Unsafety::Normal, - "don't mark const unsafe fns as promotable", - // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682 - ); - } - stab.promotable - } - None => false, - } -} - -pub fn provide(providers: &mut Providers) { - *providers = Providers { - is_const_fn_raw, - is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()), - is_promotable_const_fn, - ..*providers - }; -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/machine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/machine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/machine.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/machine.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,474 +0,0 @@ -use rustc_middle::mir; -use rustc_middle::ty::{self, Ty}; -use std::borrow::Borrow; -use std::collections::hash_map::Entry; -use std::hash::Hash; - -use rustc_data_structures::fx::FxHashMap; -use std::fmt; - -use rustc_ast::Mutability; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::AssertMessage; -use rustc_session::Limit; -use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{Align, Size}; -use rustc_target::spec::abi::Abi; - -use crate::interpret::{ - self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, OpTy, - PlaceTy, Scalar, StackPopUnwind, -}; - -use super::error::*; - -impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { - /// "Intercept" a function call to a panic-related function - /// because we have something special to do for it. - /// If this returns successfully (`Ok`), the function should just be evaluated normally. - fn hook_panic_fn( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - ) -> InterpResult<'tcx, Option>> { - // The list of functions we handle here must be in sync with - // `is_lang_panic_fn` in `transform/check_consts/mod.rs`. - let def_id = instance.def_id(); - if Some(def_id) == self.tcx.lang_items().panic_fn() - || Some(def_id) == self.tcx.lang_items().panic_str() - || Some(def_id) == self.tcx.lang_items().begin_panic_fn() - { - // &str - assert!(args.len() == 1); - - let msg_place = self.deref_operand(&args[0])?; - let msg = Symbol::intern(self.read_str(&msg_place)?); - let span = self.find_closest_untracked_caller_location(); - let (file, line, col) = self.location_triple_for_span(span); - return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); - } else if Some(def_id) == self.tcx.lang_items().panic_fmt() - || Some(def_id) == self.tcx.lang_items().begin_panic_fmt() - { - // For panic_fmt, call const_panic_fmt instead. - if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() { - return Ok(Some( - ty::Instance::resolve( - *self.tcx, - ty::ParamEnv::reveal_all(), - const_panic_fmt, - self.tcx.intern_substs(&[]), - ) - .unwrap() - .unwrap(), - )); - } - } - Ok(None) - } -} - -/// Extra machine state for CTFE, and the Machine instance -pub struct CompileTimeInterpreter<'mir, 'tcx> { - /// For now, the number of terminators that can be evaluated before we throw a resource - /// exhaustion error. - /// - /// Setting this to `0` disables the limit and allows the interpreter to run forever. - pub steps_remaining: usize, - - /// The virtual call stack. - pub(crate) stack: Vec>, -} - -#[derive(Copy, Clone, Debug)] -pub struct MemoryExtra { - /// We need to make sure consts never point to anything mutable, even recursively. That is - /// relied on for pattern matching on consts with references. - /// To achieve this, two pieces have to work together: - /// * Interning makes everything outside of statics immutable. - /// * Pointers to allocations inside of statics can never leak outside, to a non-static global. - /// This boolean here controls the second part. - pub(super) can_access_statics: bool, -} - -impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(super) fn new(const_eval_limit: Limit) -> Self { - CompileTimeInterpreter { steps_remaining: const_eval_limit.0, stack: Vec::new() } - } -} - -impl interpret::AllocMap for FxHashMap { - #[inline(always)] - fn contains_key(&mut self, k: &Q) -> bool - where - K: Borrow, - { - FxHashMap::contains_key(self, k) - } - - #[inline(always)] - fn insert(&mut self, k: K, v: V) -> Option { - FxHashMap::insert(self, k, v) - } - - #[inline(always)] - fn remove(&mut self, k: &Q) -> Option - where - K: Borrow, - { - FxHashMap::remove(self, k) - } - - #[inline(always)] - fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { - self.iter().filter_map(move |(k, v)| f(k, &*v)).collect() - } - - #[inline(always)] - fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E> { - match self.get(&k) { - Some(v) => Ok(v), - None => { - vacant()?; - bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading") - } - } - } - - #[inline(always)] - fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E> { - match self.entry(k) { - Entry::Occupied(e) => Ok(e.into_mut()), - Entry::Vacant(e) => { - let v = vacant()?; - Ok(e.insert(v)) - } - } - } -} - -crate type CompileTimeEvalContext<'mir, 'tcx> = - InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum MemoryKind { - Heap, -} - -impl fmt::Display for MemoryKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - MemoryKind::Heap => write!(f, "heap allocation"), - } - } -} - -impl interpret::MayLeak for MemoryKind { - #[inline(always)] - fn may_leak(self) -> bool { - match self { - MemoryKind::Heap => false, - } - } -} - -impl interpret::MayLeak for ! { - #[inline(always)] - fn may_leak(self) -> bool { - // `self` is uninhabited - self - } -} - -impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { - fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { - // Comparisons between integers are always known. - (Scalar::Int { .. }, Scalar::Int { .. }) => a == b, - // Equality with integers can never be known for sure. - (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => false, - // FIXME: return `true` for when both sides are the same pointer, *except* that - // some things (like functions and vtables) do not have stable addresses - // so we need to be careful around them (see e.g. #73722). - (Scalar::Ptr(..), Scalar::Ptr(..)) => false, - } - } - - fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { - // Comparisons between integers are always known. - (Scalar::Int(_), Scalar::Int(_)) => a != b, - // Comparisons of abstract pointers with null pointers are known if the pointer - // is in bounds, because if they are in bounds, the pointer can't be null. - // Inequality with integers other than null can never be known for sure. - (Scalar::Int(int), Scalar::Ptr(ptr, _)) | (Scalar::Ptr(ptr, _), Scalar::Int(int)) => { - int.is_null() && !self.memory.ptr_may_be_null(ptr.into()) - } - // FIXME: return `true` for at least some comparisons where we can reliably - // determine the result of runtime inequality tests at compile-time. - // Examples include comparison of addresses in different static items. - (Scalar::Ptr(..), Scalar::Ptr(..)) => false, - } - } -} - -impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { - compile_time_machine!(<'mir, 'tcx>); - - type MemoryKind = MemoryKind; - - type MemoryExtra = MemoryExtra; - - const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error - - fn load_mir( - ecx: &InterpCx<'mir, 'tcx, Self>, - instance: ty::InstanceDef<'tcx>, - ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - match instance { - ty::InstanceDef::Item(def) => { - if ecx.tcx.is_ctfe_mir_available(def.did) { - Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def)) - } else { - let path = ecx.tcx.def_path_str(def.did); - Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path)) - .into()) - } - } - _ => Ok(ecx.tcx.instance_mir(instance)), - } - } - - fn find_mir_or_eval_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - _abi: Abi, - args: &[OpTy<'tcx>], - _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, - _unwind: StackPopUnwind, // unwinding is not supported in consts - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - debug!("find_mir_or_eval_fn: {:?}", instance); - - // Only check non-glue functions - if let ty::InstanceDef::Item(def) = instance.def { - // Execution might have wandered off into other crates, so we cannot do a stability- - // sensitive check here. But we can at least rule out functions that are not const - // at all. - if !ecx.tcx.is_const_fn_raw(def.did) { - // allow calling functions marked with #[default_method_body_is_const]. - if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) { - // Some functions we support even if they are non-const -- but avoid testing - // that for const fn! - if let Some(new_instance) = ecx.hook_panic_fn(instance, args)? { - // We call another const fn instead. - return Self::find_mir_or_eval_fn( - ecx, - new_instance, - _abi, - args, - _ret, - _unwind, - ); - } else { - // We certainly do *not* want to actually call the fn - // though, so be sure we return here. - throw_unsup_format!("calling non-const function `{}`", instance) - } - } - } - } - // This is a const fn. Call it. - Ok(Some(ecx.load_mir(instance.def, None)?)) - } - - fn call_intrinsic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, - _unwind: StackPopUnwind, - ) -> InterpResult<'tcx> { - // Shared intrinsics. - if ecx.emulate_intrinsic(instance, args, ret)? { - return Ok(()); - } - let intrinsic_name = ecx.tcx.item_name(instance.def_id()); - - // CTFE-specific intrinsics. - let (dest, ret) = match ret { - None => { - return Err(ConstEvalErrKind::NeedsRfc(format!( - "calling intrinsic `{}`", - intrinsic_name - )) - .into()); - } - Some(p) => p, - }; - match intrinsic_name { - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = ecx.read_immediate(&args[0])?.to_scalar()?; - let b = ecx.read_immediate(&args[1])?.to_scalar()?; - let cmp = if intrinsic_name == sym::ptr_guaranteed_eq { - ecx.guaranteed_eq(a, b) - } else { - ecx.guaranteed_ne(a, b) - }; - ecx.write_scalar(Scalar::from_bool(cmp), dest)?; - } - sym::const_allocate => { - let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?; - let align = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?; - - let align = match Align::from_bytes(align) { - Ok(a) => a, - Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), - }; - - let ptr = ecx.memory.allocate( - Size::from_bytes(size as u64), - align, - interpret::MemoryKind::Machine(MemoryKind::Heap), - )?; - ecx.write_pointer(ptr, dest)?; - } - _ => { - return Err(ConstEvalErrKind::NeedsRfc(format!( - "calling intrinsic `{}`", - intrinsic_name - )) - .into()); - } - } - - ecx.go_to_block(ret); - Ok(()) - } - - fn assert_panic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - msg: &AssertMessage<'tcx>, - _unwind: Option, - ) -> InterpResult<'tcx> { - use rustc_middle::mir::AssertKind::*; - // Convert `AssertKind` to `AssertKind`. - let eval_to_int = - |op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int()); - let err = match msg { - BoundsCheck { ref len, ref index } => { - let len = eval_to_int(len)?; - let index = eval_to_int(index)?; - BoundsCheck { len, index } - } - Overflow(op, l, r) => Overflow(*op, eval_to_int(l)?, eval_to_int(r)?), - OverflowNeg(op) => OverflowNeg(eval_to_int(op)?), - DivisionByZero(op) => DivisionByZero(eval_to_int(op)?), - RemainderByZero(op) => RemainderByZero(eval_to_int(op)?), - ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind), - ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind), - }; - Err(ConstEvalErrKind::AssertFailure(err).into()) - } - - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { - Err(ConstEvalErrKind::Abort(msg).into()) - } - - fn binary_ptr_op( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _bin_op: mir::BinOp, - _left: &ImmTy<'tcx>, - _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into()) - } - - fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _dest: &PlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into()) - } - - fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - // The step limit has already been hit in a previous call to `before_terminator`. - if ecx.machine.steps_remaining == 0 { - return Ok(()); - } - - ecx.machine.steps_remaining -= 1; - if ecx.machine.steps_remaining == 0 { - throw_exhaust!(StepLimitReached) - } - - Ok(()) - } - - #[inline(always)] - fn init_frame_extra( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { - // Enforce stack size limit. Add 1 because this is run before the new frame is pushed. - if !ecx.recursion_limit.value_within_limit(ecx.stack().len() + 1) { - throw_exhaust!(StackFrameLimitReached) - } else { - Ok(frame) - } - } - - #[inline(always)] - fn stack( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } - - fn before_access_global( - memory_extra: &MemoryExtra, - alloc_id: AllocId, - allocation: &Allocation, - static_def_id: Option, - is_write: bool, - ) -> InterpResult<'tcx> { - if is_write { - // Write access. These are never allowed, but we give a targeted error message. - if allocation.mutability == Mutability::Not { - Err(err_ub!(WriteToReadOnly(alloc_id)).into()) - } else { - Err(ConstEvalErrKind::ModifiedGlobal.into()) - } - } else { - // Read access. These are usually allowed, with some exceptions. - if memory_extra.can_access_statics { - // Machine configuration allows us read from anything (e.g., `static` initializer). - Ok(()) - } else if static_def_id.is_some() { - // Machine configuration does not allow us to read statics - // (e.g., `const` initializer). - // See const_eval::machine::MemoryExtra::can_access_statics for why - // this check is so important: if we could read statics, we could read pointers - // to mutable allocations *inside* statics. These allocations are not themselves - // statics, so pointers to them can get around the check in `validity.rs`. - Err(ConstEvalErrKind::ConstAccessesStatic.into()) - } else { - // Immutable global, this read is fine. - // But make sure we never accept a read from something mutable, that would be - // unsound. The reason is that as the content of this allocation may be different - // now and at run-time, so if we permit reading now we might return the wrong value. - assert_eq!(allocation.mutability, Mutability::Not); - Ok(()) - } - } - } -} - -// Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups -// so we can end up having a file with just that impl, but for now, let's keep the impl discoverable -// at the bottom of this file. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/const_eval/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,207 +0,0 @@ -// Not in interpret to make sure we do not use private implementation details - -use std::convert::TryFrom; - -use rustc_hir::Mutability; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_middle::{ - mir::{self, interpret::ConstAlloc}, - ty::ScalarInt, -}; -use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; - -use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar, -}; - -mod error; -mod eval_queries; -mod fn_queries; -mod machine; - -pub use error::*; -pub use eval_queries::*; -pub use fn_queries::*; -pub use machine::*; - -pub(crate) fn const_caller_location( - tcx: TyCtxt<'tcx>, - (file, line, col): (Symbol, u32, u32), -) -> ConstValue<'tcx> { - trace!("const_caller_location: {}:{}:{}", file, line, col); - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); - - let loc_place = ecx.alloc_caller_location(file, line, col); - if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { - bug!("intern_const_alloc_recursive should not error in this case") - } - ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx)) -} - -/// Convert an evaluated constant to a type level constant -pub(crate) fn const_to_valtree<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - raw: ConstAlloc<'tcx>, -) -> Option> { - let ecx = mk_eval_cx( - tcx, DUMMY_SP, param_env, - // It is absolutely crucial for soundness that - // we do not read from static items or other mutable memory. - false, - ); - let place = ecx.raw_const_to_mplace(raw).unwrap(); - const_to_valtree_inner(&ecx, &place) -} - -fn const_to_valtree_inner<'tcx>( - ecx: &CompileTimeEvalContext<'tcx, 'tcx>, - place: &MPlaceTy<'tcx>, -) -> Option> { - let branches = |n, variant| { - let place = match variant { - Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(), - None => *place, - }; - let variant = - variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32())))); - let fields = (0..n).map(|i| { - let field = ecx.mplace_field(&place, i).unwrap(); - const_to_valtree_inner(ecx, &field) - }); - // For enums, we preped their variant index before the variant's fields so we can figure out - // the variant again when just seeing a valtree. - let branches = variant.into_iter().chain(fields); - Some(ty::ValTree::Branch( - ecx.tcx.arena.alloc_from_iter(branches.collect::>>()?), - )) - }; - match place.layout.ty.kind() { - ty::FnDef(..) => Some(ty::ValTree::zst()), - ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let val = ecx.read_immediate(&place.into()).unwrap(); - let val = val.to_scalar().unwrap(); - Some(ty::ValTree::Leaf(val.assert_int())) - } - - // Raw pointers are not allowed in type level constants, as we cannot properly test them for - // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`). - // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to - // agree with runtime equality tests. - ty::FnPtr(_) | ty::RawPtr(_) => None, - ty::Ref(..) => unimplemented!("need to use deref_const"), - - // Trait objects are not allowed in type level constants, as we have no concept for - // resolving their backing type, even if we can do that at const eval time. We may - // hypothetically be able to allow `dyn StructuralEq` trait objects in the future, - // but it is unclear if this is useful. - ty::Dynamic(..) => None, - - ty::Slice(_) | ty::Str => { - unimplemented!("need to find the backing data of the slice/str and recurse on that") - } - ty::Tuple(substs) => branches(substs.len(), None), - ty::Array(_, len) => branches(usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), None), - - ty::Adt(def, _) => { - if def.variants.is_empty() { - bug!("uninhabited types should have errored and never gotten converted to valtree") - } - - let variant = ecx.read_discriminant(&place.into()).unwrap().1; - - branches(def.variants[variant].fields.len(), def.is_enum().then_some(variant)) - } - - ty::Never - | ty::Error(_) - | ty::Foreign(..) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Projection(..) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - // FIXME(oli-obk): we could look behind opaque types - | ty::Opaque(..) - | ty::Infer(_) - // FIXME(oli-obk): we can probably encode closures just like structs - | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) => None, - } -} - -/// This function uses `unwrap` copiously, because an already validated constant -/// must have valid fields and can thus never fail outside of compiler bugs. However, it is -/// invoked from the pretty printer, where it can receive enums with no variants and e.g. -/// `read_discriminant` needs to be able to handle that. -pub(crate) fn destructure_const<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - val: &'tcx ty::Const<'tcx>, -) -> mir::DestructuredConst<'tcx> { - trace!("destructure_const: {:?}", val); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - let op = ecx.const_to_op(val, None).unwrap(); - - // We go to `usize` as we cannot allocate anything bigger anyway. - let (field_count, variant, down) = match val.ty.kind() { - ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), - ty::Adt(def, _) if def.variants.is_empty() => { - return mir::DestructuredConst { variant: None, fields: &[] }; - } - ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op).unwrap().1; - let down = ecx.operand_downcast(&op, variant).unwrap(); - (def.variants[variant].fields.len(), Some(variant), down) - } - ty::Tuple(substs) => (substs.len(), None, op), - _ => bug!("cannot destructure constant {:?}", val), - }; - - let fields_iter = (0..field_count).map(|i| { - let field_op = ecx.operand_field(&down, i).unwrap(); - let val = op_to_const(&ecx, &field_op); - ty::Const::from_value(tcx, val, field_op.layout.ty) - }); - let fields = tcx.arena.alloc_from_iter(fields_iter); - - mir::DestructuredConst { variant, fields } -} - -pub(crate) fn deref_const<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - val: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> { - trace!("deref_const: {:?}", val); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - let op = ecx.const_to_op(val, None).unwrap(); - let mplace = ecx.deref_operand(&op).unwrap(); - if let Some(alloc_id) = mplace.ptr.provenance { - assert_eq!( - tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().mutability, - Mutability::Not, - "deref_const cannot be used with mutable allocations as \ - that could allow pattern matching to observe mutable statics", - ); - } - - let ty = match mplace.meta { - MemPlaceMeta::None => mplace.layout.ty, - MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), - // In case of unsized types, figure out the real type behind. - MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { - ty::Str => bug!("there's no sized equivalent of a `str`"), - ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()), - _ => bug!( - "type {} should not have metadata, but had {:?}", - mplace.layout.ty, - mplace.meta - ), - }, - }; - - tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty }) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,270 +0,0 @@ -use crate::util::elaborate_drops::DropFlagState; -use rustc_middle::mir::{self, Body, Location}; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::abi::VariantIdx; - -use super::indexes::MovePathIndex; -use super::move_paths::{InitKind, LookupResult, MoveData}; -use super::MoveDataParamEnv; - -pub fn move_path_children_matching<'tcx, F>( - move_data: &MoveData<'tcx>, - path: MovePathIndex, - mut cond: F, -) -> Option -where - F: FnMut(mir::PlaceElem<'tcx>) -> bool, -{ - let mut next_child = move_data.move_paths[path].first_child; - while let Some(child_index) = next_child { - let move_path_children = &move_data.move_paths[child_index]; - if let Some(&elem) = move_path_children.place.projection.last() { - if cond(elem) { - return Some(child_index); - } - } - next_child = move_path_children.next_sibling; - } - - None -} - -/// When enumerating the child fragments of a path, don't recurse into -/// paths (1.) past arrays, slices, and pointers, nor (2.) into a type -/// that implements `Drop`. -/// -/// Places behind references or arrays are not tracked by elaboration -/// and are always assumed to be initialized when accessible. As -/// references and indexes can be reseated, trying to track them can -/// only lead to trouble. -/// -/// Places behind ADT's with a Drop impl are not tracked by -/// elaboration since they can never have a drop-flag state that -/// differs from that of the parent with the Drop impl. -/// -/// In both cases, the contents can only be accessed if and only if -/// their parents are initialized. This implies for example that there -/// is no need to maintain separate drop flags to track such state. -// -// FIXME: we have to do something for moving slice patterns. -fn place_contents_drop_state_cannot_differ<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - place: mir::Place<'tcx>, -) -> bool { - let ty = place.ty(body, tcx).ty; - match ty.kind() { - ty::Array(..) => { - debug!( - "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", - place, ty - ); - false - } - ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => { - debug!( - "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true", - place, ty - ); - true - } - ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => { - debug!( - "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true", - place, ty - ); - true - } - _ => false, - } -} - -pub(crate) fn on_lookup_result_bits<'tcx, F>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - move_data: &MoveData<'tcx>, - lookup_result: LookupResult, - each_child: F, -) where - F: FnMut(MovePathIndex), -{ - match lookup_result { - LookupResult::Parent(..) => { - // access to untracked value - do not touch children - } - LookupResult::Exact(e) => on_all_children_bits(tcx, body, move_data, e, each_child), - } -} - -pub(crate) fn on_all_children_bits<'tcx, F>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - move_data: &MoveData<'tcx>, - move_path_index: MovePathIndex, - mut each_child: F, -) where - F: FnMut(MovePathIndex), -{ - fn is_terminal_path<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - move_data: &MoveData<'tcx>, - path: MovePathIndex, - ) -> bool { - place_contents_drop_state_cannot_differ(tcx, body, move_data.move_paths[path].place) - } - - fn on_all_children_bits<'tcx, F>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - move_data: &MoveData<'tcx>, - move_path_index: MovePathIndex, - each_child: &mut F, - ) where - F: FnMut(MovePathIndex), - { - each_child(move_path_index); - - if is_terminal_path(tcx, body, move_data, move_path_index) { - return; - } - - let mut next_child_index = move_data.move_paths[move_path_index].first_child; - while let Some(child_index) = next_child_index { - on_all_children_bits(tcx, body, move_data, child_index, each_child); - next_child_index = move_data.move_paths[child_index].next_sibling; - } - } - on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child); -} - -pub(crate) fn on_all_drop_children_bits<'tcx, F>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - ctxt: &MoveDataParamEnv<'tcx>, - path: MovePathIndex, - mut each_child: F, -) where - F: FnMut(MovePathIndex), -{ - on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| { - let place = &ctxt.move_data.move_paths[path].place; - let ty = place.ty(body, tcx).ty; - debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); - - let erased_ty = tcx.erase_regions(ty); - if erased_ty.needs_drop(tcx, ctxt.param_env) { - each_child(child); - } else { - debug!("on_all_drop_children_bits - skipping") - } - }) -} - -pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - ctxt: &MoveDataParamEnv<'tcx>, - mut callback: F, -) where - F: FnMut(MovePathIndex, DropFlagState), -{ - let move_data = &ctxt.move_data; - for arg in body.args_iter() { - let place = mir::Place::from(arg); - let lookup_result = move_data.rev_lookup.find(place.as_ref()); - on_lookup_result_bits(tcx, body, move_data, lookup_result, |mpi| { - callback(mpi, DropFlagState::Present) - }); - } -} - -pub(crate) fn drop_flag_effects_for_location<'tcx, F>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - ctxt: &MoveDataParamEnv<'tcx>, - loc: Location, - mut callback: F, -) where - F: FnMut(MovePathIndex, DropFlagState), -{ - let move_data = &ctxt.move_data; - debug!("drop_flag_effects_for_location({:?})", loc); - - // first, move out of the RHS - for mi in &move_data.loc_map[loc] { - let path = mi.move_path_index(move_data); - debug!("moving out of path {:?}", move_data.move_paths[path]); - - on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent)) - } - - debug!("drop_flag_effects: assignment for location({:?})", loc); - - for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present)); -} - -pub(crate) fn for_location_inits<'tcx, F>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - move_data: &MoveData<'tcx>, - loc: Location, - mut callback: F, -) where - F: FnMut(MovePathIndex), -{ - for ii in &move_data.init_loc_map[loc] { - let init = move_data.inits[*ii]; - match init.kind { - InitKind::Deep => { - let path = init.path; - - on_all_children_bits(tcx, body, move_data, path, &mut callback) - } - InitKind::Shallow => { - let mpi = init.path; - callback(mpi); - } - InitKind::NonPanicPathOnly => (), - } - } -} - -/// Calls `handle_inactive_variant` for each descendant move path of `enum_place` that contains a -/// `Downcast` to a variant besides the `active_variant`. -/// -/// NOTE: If there are no move paths corresponding to an inactive variant, -/// `handle_inactive_variant` will not be called for that variant. -pub(crate) fn on_all_inactive_variants<'tcx>( - tcx: TyCtxt<'tcx>, - body: &mir::Body<'tcx>, - move_data: &MoveData<'tcx>, - enum_place: mir::Place<'tcx>, - active_variant: VariantIdx, - mut handle_inactive_variant: impl FnMut(MovePathIndex), -) { - let enum_mpi = match move_data.rev_lookup.find(enum_place.as_ref()) { - LookupResult::Exact(mpi) => mpi, - LookupResult::Parent(_) => return, - }; - - let enum_path = &move_data.move_paths[enum_mpi]; - for (variant_mpi, variant_path) in enum_path.children(&move_data.move_paths) { - // Because of the way we build the `MoveData` tree, each child should have exactly one more - // projection than `enum_place`. This additional projection must be a downcast since the - // base is an enum. - let (downcast, base_proj) = variant_path.place.projection.split_last().unwrap(); - assert_eq!(enum_place.projection.len(), base_proj.len()); - - let variant_idx = match *downcast { - mir::ProjectionElem::Downcast(_, idx) => idx, - _ => unreachable!(), - }; - - if variant_idx != active_variant { - on_all_children_bits(tcx, body, move_data, variant_mpi, |mpi| { - handle_inactive_variant(mpi) - }); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/cursor.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/cursor.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/cursor.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/cursor.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ -//! Random access inspection of the results of a dataflow analysis. - -use std::borrow::Borrow; -use std::cmp::Ordering; - -use rustc_index::bit_set::BitSet; -use rustc_index::vec::Idx; -use rustc_middle::mir::{self, BasicBlock, Location}; - -use super::{Analysis, Direction, Effect, EffectIndex, Results}; - -/// A `ResultsCursor` that borrows the underlying `Results`. -pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>; - -/// Allows random access inspection of the results of a dataflow analysis. -/// -/// This cursor only has linear performance within a basic block when its statements are visited in -/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are -/// visited in *reverse* order—performance will be quadratic in the number of statements in the -/// block. The order in which basic blocks are inspected has no impact on performance. -/// -/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The -/// type of ownership is determined by `R` (see `ResultsRefCursor` above). -pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>> -where - A: Analysis<'tcx>, -{ - body: &'mir mir::Body<'tcx>, - results: R, - state: A::Domain, - - pos: CursorPosition, - - /// Indicates that `state` has been modified with a custom effect. - /// - /// When this flag is set, we need to reset to an entry set before doing a seek. - state_needs_reset: bool, - - #[cfg(debug_assertions)] - reachable_blocks: BitSet, -} - -impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> -where - A: Analysis<'tcx>, - R: Borrow>, -{ - /// Returns a new cursor that can inspect `results`. - pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self { - let bottom_value = results.borrow().analysis.bottom_value(body); - ResultsCursor { - body, - results, - - // Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that - // it needs to reset to block entry before the first seek. The cursor position is - // immaterial. - state_needs_reset: true, - state: bottom_value, - pos: CursorPosition::block_entry(mir::START_BLOCK), - - #[cfg(debug_assertions)] - reachable_blocks: mir::traversal::reachable_as_bitset(body), - } - } - - /// Returns the underlying `Results`. - pub fn results(&self) -> &Results<'tcx, A> { - &self.results.borrow() - } - - /// Returns the `Analysis` used to generate the underlying `Results`. - pub fn analysis(&self) -> &A { - &self.results.borrow().analysis - } - - /// Returns the dataflow state at the current location. - pub fn get(&self) -> &A::Domain { - &self.state - } - - /// Resets the cursor to hold the entry set for the given basic block. - /// - /// For forward dataflow analyses, this is the dataflow state prior to the first statement. - /// - /// For backward dataflow analyses, this is the dataflow state after the terminator. - pub(super) fn seek_to_block_entry(&mut self, block: BasicBlock) { - #[cfg(debug_assertions)] - assert!(self.reachable_blocks.contains(block)); - - self.state.clone_from(&self.results.borrow().entry_set_for_block(block)); - self.pos = CursorPosition::block_entry(block); - self.state_needs_reset = false; - } - - /// Resets the cursor to hold the state prior to the first statement in a basic block. - /// - /// For forward analyses, this is the entry set for the given block. - /// - /// For backward analyses, this is the state that will be propagated to its - /// predecessors (ignoring edge-specific effects). - pub fn seek_to_block_start(&mut self, block: BasicBlock) { - if A::Direction::is_forward() { - self.seek_to_block_entry(block) - } else { - self.seek_after(Location { block, statement_index: 0 }, Effect::Primary) - } - } - - /// Resets the cursor to hold the state after the terminator in a basic block. - /// - /// For backward analyses, this is the entry set for the given block. - /// - /// For forward analyses, this is the state that will be propagated to its - /// successors (ignoring edge-specific effects). - pub fn seek_to_block_end(&mut self, block: BasicBlock) { - if A::Direction::is_backward() { - self.seek_to_block_entry(block) - } else { - self.seek_after(self.body.terminator_loc(block), Effect::Primary) - } - } - - /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is - /// applied. - /// - /// The "before" effect at the target location *will be* applied. - pub fn seek_before_primary_effect(&mut self, target: Location) { - self.seek_after(target, Effect::Before) - } - - /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is - /// applied. - /// - /// The "before" effect at the target location will be applied as well. - pub fn seek_after_primary_effect(&mut self, target: Location) { - self.seek_after(target, Effect::Primary) - } - - fn seek_after(&mut self, target: Location, effect: Effect) { - assert!(target <= self.body.terminator_loc(target.block)); - - // Reset to the entry of the target block if any of the following are true: - // - A custom effect has been applied to the cursor state. - // - We are in a different block than the target. - // - We are in the same block but have advanced past the target effect. - if self.state_needs_reset || self.pos.block != target.block { - self.seek_to_block_entry(target.block); - } else if let Some(curr_effect) = self.pos.curr_effect_index { - let mut ord = curr_effect.statement_index.cmp(&target.statement_index); - if A::Direction::is_backward() { - ord = ord.reverse() - } - - match ord.then_with(|| curr_effect.effect.cmp(&effect)) { - Ordering::Equal => return, - Ordering::Greater => self.seek_to_block_entry(target.block), - Ordering::Less => {} - } - } - - // At this point, the cursor is in the same block as the target location at an earlier - // statement. - debug_assert_eq!(target.block, self.pos.block); - - let block_data = &self.body[target.block]; - let next_effect = if A::Direction::is_forward() { - #[rustfmt::skip] - self.pos.curr_effect_index.map_or_else( - || Effect::Before.at_index(0), - EffectIndex::next_in_forward_order, - ) - } else { - self.pos.curr_effect_index.map_or_else( - || Effect::Before.at_index(block_data.statements.len()), - EffectIndex::next_in_backward_order, - ) - }; - - let analysis = &self.results.borrow().analysis; - let target_effect_index = effect.at_index(target.statement_index); - - A::Direction::apply_effects_in_range( - analysis, - &mut self.state, - target.block, - block_data, - next_effect..=target_effect_index, - ); - - self.pos = - CursorPosition { block: target.block, curr_effect_index: Some(target_effect_index) }; - } - - /// Applies `f` to the cursor's internal state. - /// - /// This can be used, e.g., to apply the call return effect directly to the cursor without - /// creating an extra copy of the dataflow state. - pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) { - f(&self.results.borrow().analysis, &mut self.state); - self.state_needs_reset = true; - } -} - -impl<'mir, 'tcx, A, R, T> ResultsCursor<'mir, 'tcx, A, R> -where - A: Analysis<'tcx, Domain = BitSet>, - T: Idx, - R: Borrow>, -{ - pub fn contains(&self, elem: T) -> bool { - self.get().contains(elem) - } -} - -#[derive(Clone, Copy, Debug)] -struct CursorPosition { - block: BasicBlock, - curr_effect_index: Option, -} - -impl CursorPosition { - fn block_entry(block: BasicBlock) -> CursorPosition { - CursorPosition { block, curr_effect_index: None } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/direction.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/direction.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/direction.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/direction.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,564 +0,0 @@ -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets}; -use rustc_middle::ty::TyCtxt; -use std::ops::RangeInclusive; - -use super::visitor::{ResultsVisitable, ResultsVisitor}; -use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget}; - -pub trait Direction { - fn is_forward() -> bool; - - fn is_backward() -> bool { - !Self::is_forward() - } - - /// Applies all effects between the given `EffectIndex`s. - /// - /// `effects.start()` must precede or equal `effects.end()` in this direction. - fn apply_effects_in_range( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - effects: RangeInclusive, - ) where - A: Analysis<'tcx>; - - fn apply_effects_in_block( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: Analysis<'tcx>; - - fn gen_kill_effects_in_block( - analysis: &A, - trans: &mut GenKillSet, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: GenKillAnalysis<'tcx>; - - fn visit_results_in_block( - state: &mut F, - block: BasicBlock, - block_data: &'mir mir::BasicBlockData<'tcx>, - results: &R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, - ) where - R: ResultsVisitable<'tcx, FlowState = F>; - - fn join_state_into_successors_of( - analysis: &A, - tcx: TyCtxt<'tcx>, - body: &mir::Body<'tcx>, - dead_unwinds: Option<&BitSet>, - exit_state: &mut A::Domain, - block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - propagate: impl FnMut(BasicBlock, &A::Domain), - ) where - A: Analysis<'tcx>; -} - -/// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement). -pub struct Backward; - -impl Direction for Backward { - fn is_forward() -> bool { - false - } - - fn apply_effects_in_block( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: Analysis<'tcx>, - { - let terminator = block_data.terminator(); - let location = Location { block, statement_index: block_data.statements.len() }; - analysis.apply_before_terminator_effect(state, terminator, location); - analysis.apply_terminator_effect(state, terminator, location); - - for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { - let location = Location { block, statement_index }; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); - } - } - - fn gen_kill_effects_in_block( - analysis: &A, - trans: &mut GenKillSet, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: GenKillAnalysis<'tcx>, - { - let terminator = block_data.terminator(); - let location = Location { block, statement_index: block_data.statements.len() }; - analysis.before_terminator_effect(trans, terminator, location); - analysis.terminator_effect(trans, terminator, location); - - for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { - let location = Location { block, statement_index }; - analysis.before_statement_effect(trans, statement, location); - analysis.statement_effect(trans, statement, location); - } - } - - fn apply_effects_in_range( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - effects: RangeInclusive, - ) where - A: Analysis<'tcx>, - { - let (from, to) = (*effects.start(), *effects.end()); - let terminator_index = block_data.statements.len(); - - assert!(from.statement_index <= terminator_index); - assert!(!to.precedes_in_backward_order(from)); - - // Handle the statement (or terminator) at `from`. - - let next_effect = match from.effect { - // If we need to apply the terminator effect in all or in part, do so now. - _ if from.statement_index == terminator_index => { - let location = Location { block, statement_index: from.statement_index }; - let terminator = block_data.terminator(); - - if from.effect == Effect::Before { - analysis.apply_before_terminator_effect(state, terminator, location); - if to == Effect::Before.at_index(terminator_index) { - return; - } - } - - analysis.apply_terminator_effect(state, terminator, location); - if to == Effect::Primary.at_index(terminator_index) { - return; - } - - // If `from.statement_index` is `0`, we will have hit one of the earlier comparisons - // with `to`. - from.statement_index - 1 - } - - Effect::Primary => { - let location = Location { block, statement_index: from.statement_index }; - let statement = &block_data.statements[from.statement_index]; - - analysis.apply_statement_effect(state, statement, location); - if to == Effect::Primary.at_index(from.statement_index) { - return; - } - - from.statement_index - 1 - } - - Effect::Before => from.statement_index, - }; - - // Handle all statements between `first_unapplied_idx` and `to.statement_index`. - - for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) { - let location = Location { block, statement_index }; - let statement = &block_data.statements[statement_index]; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); - } - - // Handle the statement at `to`. - - let location = Location { block, statement_index: to.statement_index }; - let statement = &block_data.statements[to.statement_index]; - analysis.apply_before_statement_effect(state, statement, location); - - if to.effect == Effect::Before { - return; - } - - analysis.apply_statement_effect(state, statement, location); - } - - fn visit_results_in_block( - state: &mut F, - block: BasicBlock, - block_data: &'mir mir::BasicBlockData<'tcx>, - results: &R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, - ) where - R: ResultsVisitable<'tcx, FlowState = F>, - { - results.reset_to_block_entry(state, block); - - vis.visit_block_end(&state, block_data, block); - - // Terminator - let loc = Location { block, statement_index: block_data.statements.len() }; - let term = block_data.terminator(); - results.reconstruct_before_terminator_effect(state, term, loc); - vis.visit_terminator_before_primary_effect(state, term, loc); - results.reconstruct_terminator_effect(state, term, loc); - vis.visit_terminator_after_primary_effect(state, term, loc); - - for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { - let loc = Location { block, statement_index }; - results.reconstruct_before_statement_effect(state, stmt, loc); - vis.visit_statement_before_primary_effect(state, stmt, loc); - results.reconstruct_statement_effect(state, stmt, loc); - vis.visit_statement_after_primary_effect(state, stmt, loc); - } - - vis.visit_block_start(state, block_data, block); - } - - fn join_state_into_successors_of( - analysis: &A, - _tcx: TyCtxt<'tcx>, - body: &mir::Body<'tcx>, - dead_unwinds: Option<&BitSet>, - exit_state: &mut A::Domain, - (bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - mut propagate: impl FnMut(BasicBlock, &A::Domain), - ) where - A: Analysis<'tcx>, - { - for pred in body.predecessors()[bb].iter().copied() { - match body[pred].terminator().kind { - // Apply terminator-specific edge effects. - // - // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally. - mir::TerminatorKind::Call { - destination: Some((return_place, dest)), - ref func, - ref args, - .. - } if dest == bb => { - let mut tmp = exit_state.clone(); - analysis.apply_call_return_effect(&mut tmp, pred, func, args, return_place); - propagate(pred, &tmp); - } - - mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => { - let mut tmp = exit_state.clone(); - analysis.apply_yield_resume_effect(&mut tmp, resume, resume_arg); - propagate(pred, &tmp); - } - - // Ignore dead unwinds. - mir::TerminatorKind::Call { cleanup: Some(unwind), .. } - | mir::TerminatorKind::Assert { cleanup: Some(unwind), .. } - | mir::TerminatorKind::Drop { unwind: Some(unwind), .. } - | mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. } - | mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. } - if unwind == bb => - { - if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { - propagate(pred, exit_state); - } - } - - _ => propagate(pred, exit_state), - } - } - } -} - -/// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator). -pub struct Forward; - -impl Direction for Forward { - fn is_forward() -> bool { - true - } - - fn apply_effects_in_block( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: Analysis<'tcx>, - { - for (statement_index, statement) in block_data.statements.iter().enumerate() { - let location = Location { block, statement_index }; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); - } - - let terminator = block_data.terminator(); - let location = Location { block, statement_index: block_data.statements.len() }; - analysis.apply_before_terminator_effect(state, terminator, location); - analysis.apply_terminator_effect(state, terminator, location); - } - - fn gen_kill_effects_in_block( - analysis: &A, - trans: &mut GenKillSet, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: GenKillAnalysis<'tcx>, - { - for (statement_index, statement) in block_data.statements.iter().enumerate() { - let location = Location { block, statement_index }; - analysis.before_statement_effect(trans, statement, location); - analysis.statement_effect(trans, statement, location); - } - - let terminator = block_data.terminator(); - let location = Location { block, statement_index: block_data.statements.len() }; - analysis.before_terminator_effect(trans, terminator, location); - analysis.terminator_effect(trans, terminator, location); - } - - fn apply_effects_in_range( - analysis: &A, - state: &mut A::Domain, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - effects: RangeInclusive, - ) where - A: Analysis<'tcx>, - { - let (from, to) = (*effects.start(), *effects.end()); - let terminator_index = block_data.statements.len(); - - assert!(to.statement_index <= terminator_index); - assert!(!to.precedes_in_forward_order(from)); - - // If we have applied the before affect of the statement or terminator at `from` but not its - // after effect, do so now and start the loop below from the next statement. - - let first_unapplied_index = match from.effect { - Effect::Before => from.statement_index, - - Effect::Primary if from.statement_index == terminator_index => { - debug_assert_eq!(from, to); - - let location = Location { block, statement_index: terminator_index }; - let terminator = block_data.terminator(); - analysis.apply_terminator_effect(state, terminator, location); - return; - } - - Effect::Primary => { - let location = Location { block, statement_index: from.statement_index }; - let statement = &block_data.statements[from.statement_index]; - analysis.apply_statement_effect(state, statement, location); - - // If we only needed to apply the after effect of the statement at `idx`, we are done. - if from == to { - return; - } - - from.statement_index + 1 - } - }; - - // Handle all statements between `from` and `to` whose effects must be applied in full. - - for statement_index in first_unapplied_index..to.statement_index { - let location = Location { block, statement_index }; - let statement = &block_data.statements[statement_index]; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); - } - - // Handle the statement or terminator at `to`. - - let location = Location { block, statement_index: to.statement_index }; - if to.statement_index == terminator_index { - let terminator = block_data.terminator(); - analysis.apply_before_terminator_effect(state, terminator, location); - - if to.effect == Effect::Primary { - analysis.apply_terminator_effect(state, terminator, location); - } - } else { - let statement = &block_data.statements[to.statement_index]; - analysis.apply_before_statement_effect(state, statement, location); - - if to.effect == Effect::Primary { - analysis.apply_statement_effect(state, statement, location); - } - } - } - - fn visit_results_in_block( - state: &mut F, - block: BasicBlock, - block_data: &'mir mir::BasicBlockData<'tcx>, - results: &R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, - ) where - R: ResultsVisitable<'tcx, FlowState = F>, - { - results.reset_to_block_entry(state, block); - - vis.visit_block_start(state, block_data, block); - - for (statement_index, stmt) in block_data.statements.iter().enumerate() { - let loc = Location { block, statement_index }; - results.reconstruct_before_statement_effect(state, stmt, loc); - vis.visit_statement_before_primary_effect(state, stmt, loc); - results.reconstruct_statement_effect(state, stmt, loc); - vis.visit_statement_after_primary_effect(state, stmt, loc); - } - - let loc = Location { block, statement_index: block_data.statements.len() }; - let term = block_data.terminator(); - results.reconstruct_before_terminator_effect(state, term, loc); - vis.visit_terminator_before_primary_effect(state, term, loc); - results.reconstruct_terminator_effect(state, term, loc); - vis.visit_terminator_after_primary_effect(state, term, loc); - - vis.visit_block_end(state, block_data, block); - } - - fn join_state_into_successors_of( - analysis: &A, - _tcx: TyCtxt<'tcx>, - _body: &mir::Body<'tcx>, - dead_unwinds: Option<&BitSet>, - exit_state: &mut A::Domain, - (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - mut propagate: impl FnMut(BasicBlock, &A::Domain), - ) where - A: Analysis<'tcx>, - { - use mir::TerminatorKind::*; - match bb_data.terminator().kind { - Return | Resume | Abort | GeneratorDrop | Unreachable => {} - - Goto { target } => propagate(target, exit_state), - - Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ } - | Drop { target, unwind, place: _ } - | DropAndReplace { target, unwind, value: _, place: _ } - | FalseUnwind { real_target: target, unwind } => { - if let Some(unwind) = unwind { - if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { - propagate(unwind, exit_state); - } - } - - propagate(target, exit_state); - } - - FalseEdge { real_target, imaginary_target } => { - propagate(real_target, exit_state); - propagate(imaginary_target, exit_state); - } - - Yield { resume: target, drop, resume_arg, value: _ } => { - if let Some(drop) = drop { - propagate(drop, exit_state); - } - - analysis.apply_yield_resume_effect(exit_state, target, resume_arg); - propagate(target, exit_state); - } - - Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => { - if let Some(unwind) = cleanup { - if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { - propagate(unwind, exit_state); - } - } - - if let Some((dest_place, target)) = destination { - // N.B.: This must be done *last*, otherwise the unwind path will see the call - // return effect. - analysis.apply_call_return_effect(exit_state, bb, func, args, dest_place); - propagate(target, exit_state); - } - } - - InlineAsm { template: _, operands: _, options: _, line_spans: _, destination } => { - if let Some(target) = destination { - propagate(target, exit_state); - } - } - - SwitchInt { ref targets, ref discr, switch_ty: _ } => { - let mut applier = SwitchIntEdgeEffectApplier { - exit_state, - targets, - propagate, - effects_applied: false, - }; - - analysis.apply_switch_int_edge_effects(bb, discr, &mut applier); - - let SwitchIntEdgeEffectApplier { - exit_state, mut propagate, effects_applied, .. - } = applier; - - if !effects_applied { - for target in targets.all_targets() { - propagate(*target, exit_state); - } - } - } - } - } -} - -struct SwitchIntEdgeEffectApplier<'a, D, F> { - exit_state: &'a mut D, - targets: &'a SwitchTargets, - propagate: F, - - effects_applied: bool, -} - -impl super::SwitchIntEdgeEffects for SwitchIntEdgeEffectApplier<'_, D, F> -where - D: Clone, - F: FnMut(BasicBlock, &D), -{ - fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { - assert!(!self.effects_applied); - - let mut tmp = None; - for (value, target) in self.targets.iter() { - let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); - apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target }); - (self.propagate)(target, tmp); - } - - // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`, - // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state. - let otherwise = self.targets.otherwise(); - apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise }); - (self.propagate)(otherwise, self.exit_state); - - self.effects_applied = true; - } -} - -/// An analogue of `Option::get_or_insert_with` that stores a clone of `val` into `opt`, but uses -/// the more efficient `clone_from` if `opt` was `Some`. -/// -/// Returns a mutable reference to the new clone that resides in `opt`. -// -// FIXME: Figure out how to express this using `Option::clone_from`, or maybe lift it into the -// standard library? -fn opt_clone_from_or_clone(opt: &'a mut Option, val: &T) -> &'a mut T { - if opt.is_some() { - let ret = opt.as_mut().unwrap(); - ret.clone_from(val); - ret - } else { - *opt = Some(val.clone()); - opt.as_mut().unwrap() - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/engine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/engine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/engine.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/engine.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,414 +0,0 @@ -//! A solver for dataflow problems. - -use std::borrow::BorrowMut; -use std::ffi::OsString; -use std::path::PathBuf; - -use rustc_ast as ast; -use rustc_data_structures::work_queue::WorkQueue; -use rustc_graphviz as dot; -use rustc_hir::def_id::DefId; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::{self, traversal, BasicBlock}; -use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::{sym, Symbol}; - -use super::fmt::DebugWithContext; -use super::graphviz; -use super::{ - visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice, - ResultsCursor, ResultsVisitor, -}; -use crate::util::pretty::{create_dump_file, dump_enabled}; - -/// A dataflow analysis that has converged to fixpoint. -pub struct Results<'tcx, A> -where - A: Analysis<'tcx>, -{ - pub analysis: A, - pub(super) entry_sets: IndexVec, -} - -impl Results<'tcx, A> -where - A: Analysis<'tcx>, -{ - /// Creates a `ResultsCursor` that can inspect these `Results`. - pub fn into_results_cursor(self, body: &'mir mir::Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> { - ResultsCursor::new(body, self) - } - - /// Gets the dataflow state for the given block. - pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { - &self.entry_sets[block] - } - - pub fn visit_with( - &self, - body: &'mir mir::Body<'tcx>, - blocks: impl IntoIterator, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, - ) { - visit_results(body, blocks, self, vis) - } - - pub fn visit_reachable_with( - &self, - body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, - ) { - let blocks = mir::traversal::reachable(body); - visit_results(body, blocks.map(|(bb, _)| bb), self, vis) - } -} - -/// A solver for dataflow problems. -pub struct Engine<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, - dead_unwinds: Option<&'a BitSet>, - entry_sets: IndexVec, - pass_name: Option<&'static str>, - analysis: A, - - /// Cached, cumulative transfer functions for each block. - // - // FIXME(ecstaticmorse): This boxed `Fn` trait object is invoked inside a tight loop for - // gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade - // performance in practice. I've tried a few ways to avoid this, but they have downsides. See - // the message for the commit that added this FIXME for more information. - apply_trans_for_block: Option>, -} - -impl Engine<'a, 'tcx, A> -where - A: GenKillAnalysis<'tcx, Idx = T, Domain = D>, - D: Clone + JoinSemiLattice + GenKill + BorrowMut>, - T: Idx, -{ - /// Creates a new `Engine` to solve a gen-kill dataflow problem. - pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self { - // If there are no back-edges in the control-flow graph, we only ever need to apply the - // transfer function for each block exactly once (assuming that we process blocks in RPO). - // - // In this case, there's no need to compute the block transfer functions ahead of time. - if !body.is_cfg_cyclic() { - return Self::new(tcx, body, analysis, None); - } - - // Otherwise, compute and store the cumulative transfer function for each block. - - let identity = GenKillSet::identity(analysis.bottom_value(body).borrow().domain_size()); - let mut trans_for_block = IndexVec::from_elem(identity, body.basic_blocks()); - - for (block, block_data) in body.basic_blocks().iter_enumerated() { - let trans = &mut trans_for_block[block]; - A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data); - } - - let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| { - trans_for_block[bb].apply(state.borrow_mut()); - }); - - Self::new(tcx, body, analysis, Some(apply_trans as Box<_>)) - } -} - -impl Engine<'a, 'tcx, A> -where - A: Analysis<'tcx, Domain = D>, - D: Clone + JoinSemiLattice, -{ - /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer - /// function. - /// - /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for - /// better performance. - pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self { - Self::new(tcx, body, analysis, None) - } - - fn new( - tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, - analysis: A, - apply_trans_for_block: Option>, - ) -> Self { - let bottom_value = analysis.bottom_value(body); - let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), body.basic_blocks()); - analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); - - if A::Direction::is_backward() && entry_sets[mir::START_BLOCK] != bottom_value { - bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); - } - - Engine { - analysis, - tcx, - body, - dead_unwinds: None, - pass_name: None, - entry_sets, - apply_trans_for_block, - } - } - - /// Signals that we do not want dataflow state to propagate across unwind edges for these - /// `BasicBlock`s. - /// - /// You must take care that `dead_unwinds` does not contain a `BasicBlock` that *can* actually - /// unwind during execution. Otherwise, your dataflow results will not be correct. - pub fn dead_unwinds(mut self, dead_unwinds: &'a BitSet) -> Self { - self.dead_unwinds = Some(dead_unwinds); - self - } - - /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. - /// - /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name` - /// to differentiate them. Otherwise, only the results for the latest run will be saved. - pub fn pass_name(mut self, name: &'static str) -> Self { - self.pass_name = Some(name); - self - } - - /// Computes the fixpoint for this dataflow problem and returns it. - pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> - where - A::Domain: DebugWithContext, - { - let Engine { - analysis, - body, - dead_unwinds, - mut entry_sets, - tcx, - apply_trans_for_block, - pass_name, - .. - } = self; - - let mut dirty_queue: WorkQueue = - WorkQueue::with_none(body.basic_blocks().len()); - - if A::Direction::is_forward() { - for (bb, _) in traversal::reverse_postorder(body) { - dirty_queue.insert(bb); - } - } else { - // Reverse post-order on the reverse CFG may generate a better iteration order for - // backward dataflow analyses, but probably not enough to matter. - for (bb, _) in traversal::postorder(body) { - dirty_queue.insert(bb); - } - } - - // `state` is not actually used between iterations; - // this is just an optimization to avoid reallocating - // every iteration. - let mut state = analysis.bottom_value(body); - while let Some(bb) = dirty_queue.pop() { - let bb_data = &body[bb]; - - // Set the state to the entry state of the block. - // This is equivalent to `state = entry_sets[bb].clone()`, - // but it saves an allocation, thus improving compile times. - state.clone_from(&entry_sets[bb]); - - // Apply the block transfer function, using the cached one if it exists. - match &apply_trans_for_block { - Some(apply) => apply(bb, &mut state), - None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data), - } - - A::Direction::join_state_into_successors_of( - &analysis, - tcx, - body, - dead_unwinds, - &mut state, - (bb, bb_data), - |target: BasicBlock, state: &A::Domain| { - let set_changed = entry_sets[target].join(state); - if set_changed { - dirty_queue.insert(target); - } - }, - ); - } - - let results = Results { analysis, entry_sets }; - - let res = write_graphviz_results(tcx, &body, &results, pass_name); - if let Err(e) = res { - error!("Failed to write graphviz dataflow results: {}", e); - } - - results - } -} - -// Graphviz - -/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via -/// `rustc_mir` attributes. -fn write_graphviz_results( - tcx: TyCtxt<'tcx>, - body: &mir::Body<'tcx>, - results: &Results<'tcx, A>, - pass_name: Option<&'static str>, -) -> std::io::Result<()> -where - A: Analysis<'tcx>, - A::Domain: DebugWithContext, -{ - use std::fs; - use std::io::{self, Write}; - - let def_id = body.source.def_id(); - let attrs = match RustcMirAttrs::parse(tcx, def_id) { - Ok(attrs) => attrs, - - // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse` - Err(()) => return Ok(()), - }; - - let mut file = match attrs.output_path(A::NAME) { - Some(path) => { - debug!("printing dataflow results for {:?} to {}", def_id, path.display()); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent)?; - } - io::BufWriter::new(fs::File::create(&path)?) - } - - None if tcx.sess.opts.debugging_opts.dump_mir_dataflow - && dump_enabled(tcx, A::NAME, def_id) => - { - create_dump_file( - tcx, - ".dot", - None, - A::NAME, - &pass_name.unwrap_or("-----"), - body.source, - )? - } - - _ => return Ok(()), - }; - - let style = match attrs.formatter { - Some(sym::two_phase) => graphviz::OutputStyle::BeforeAndAfter, - _ => graphviz::OutputStyle::AfterOnly, - }; - - let mut buf = Vec::new(); - - let graphviz = graphviz::Formatter::new(body, results, style); - let mut render_opts = - vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())]; - if tcx.sess.opts.debugging_opts.graphviz_dark_mode { - render_opts.push(dot::RenderOption::DarkTheme); - } - dot::render_opts(&graphviz, &mut buf, &render_opts)?; - - file.write_all(&buf)?; - - Ok(()) -} - -#[derive(Default)] -struct RustcMirAttrs { - basename_and_suffix: Option, - formatter: Option, -} - -impl RustcMirAttrs { - fn parse(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result { - let attrs = tcx.get_attrs(def_id); - - let mut result = Ok(()); - let mut ret = RustcMirAttrs::default(); - - let rustc_mir_attrs = attrs - .iter() - .filter(|attr| attr.has_name(sym::rustc_mir)) - .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); - - for attr in rustc_mir_attrs { - let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) { - Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| { - let path = PathBuf::from(s.to_string()); - match path.file_name() { - Some(_) => Ok(path), - None => { - tcx.sess.span_err(attr.span(), "path must end in a filename"); - Err(()) - } - } - }) - } else if attr.has_name(sym::borrowck_graphviz_format) { - Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s { - sym::gen_kill | sym::two_phase => Ok(s), - _ => { - tcx.sess.span_err(attr.span(), "unknown formatter"); - Err(()) - } - }) - } else { - Ok(()) - }; - - result = result.and(attr_result); - } - - result.map(|()| ret) - } - - fn set_field( - field: &mut Option, - tcx: TyCtxt<'tcx>, - attr: &ast::NestedMetaItem, - mapper: impl FnOnce(Symbol) -> Result, - ) -> Result<(), ()> { - if field.is_some() { - tcx.sess - .span_err(attr.span(), &format!("duplicate values for `{}`", attr.name_or_empty())); - - return Err(()); - } - - if let Some(s) = attr.value_str() { - *field = Some(mapper(s)?); - Ok(()) - } else { - tcx.sess - .span_err(attr.span(), &format!("`{}` requires an argument", attr.name_or_empty())); - Err(()) - } - } - - /// Returns the path where dataflow results should be written, or `None` - /// `borrowck_graphviz_postflow` was not specified. - /// - /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`: - /// - /// "path/suffix.dot" -> "path/analysis_name_suffix.dot" - fn output_path(&self, analysis_name: &str) -> Option { - let mut ret = self.basename_and_suffix.as_ref().cloned()?; - let suffix = ret.file_name().unwrap(); // Checked when parsing attrs - - let mut file_name: OsString = analysis_name.into(); - file_name.push("_"); - file_name.push(suffix); - ret.set_file_name(file_name); - - Some(ret) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/fmt.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/fmt.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/fmt.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/fmt.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,172 +0,0 @@ -//! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow -//! analysis. - -use rustc_index::bit_set::{BitSet, HybridBitSet}; -use rustc_index::vec::Idx; -use std::fmt; - -/// An extension to `fmt::Debug` for data that can be better printed with some auxiliary data `C`. -pub trait DebugWithContext: Eq + fmt::Debug { - fn fmt_with(&self, _ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self, f) - } - - /// Print the difference between `self` and `old`. - /// - /// This should print nothing if `self == old`. - /// - /// `+` and `-` are typically used to indicate differences. However, these characters are - /// fairly common and may be needed to print a types representation. If using them to indicate - /// a diff, prefix them with the "Unit Separator" control character (⟠U+001F). - fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self == old { - return Ok(()); - } - - write!(f, "\u{001f}+")?; - self.fmt_with(ctxt, f)?; - - if f.alternate() { - write!(f, "\n")?; - } else { - write!(f, "\t")?; - } - - write!(f, "\u{001f}-")?; - old.fmt_with(ctxt, f) - } -} - -/// Implements `fmt::Debug` by deferring to `>::fmt_with`. -pub struct DebugWithAdapter<'a, T, C> { - pub this: T, - pub ctxt: &'a C, -} - -impl fmt::Debug for DebugWithAdapter<'_, T, C> -where - T: DebugWithContext, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.this.fmt_with(self.ctxt, f) - } -} - -/// Implements `fmt::Debug` by deferring to `>::fmt_diff_with`. -pub struct DebugDiffWithAdapter<'a, T, C> { - pub new: T, - pub old: T, - pub ctxt: &'a C, -} - -impl fmt::Debug for DebugDiffWithAdapter<'_, T, C> -where - T: DebugWithContext, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.new.fmt_diff_with(&self.old, self.ctxt, f) - } -} - -// Impls - -impl DebugWithContext for BitSet -where - T: Idx + DebugWithContext, -{ - fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_set().entries(self.iter().map(|i| DebugWithAdapter { this: i, ctxt })).finish() - } - - fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let size = self.domain_size(); - assert_eq!(size, old.domain_size()); - - let mut set_in_self = HybridBitSet::new_empty(size); - let mut cleared_in_self = HybridBitSet::new_empty(size); - - for i in (0..size).map(T::new) { - match (self.contains(i), old.contains(i)) { - (true, false) => set_in_self.insert(i), - (false, true) => cleared_in_self.insert(i), - _ => continue, - }; - } - - let mut first = true; - for idx in set_in_self.iter() { - let delim = if first { - "\u{001f}+" - } else if f.alternate() { - "\n\u{001f}+" - } else { - ", " - }; - - write!(f, "{}", delim)?; - idx.fmt_with(ctxt, f)?; - first = false; - } - - if !f.alternate() { - first = true; - if !set_in_self.is_empty() && !cleared_in_self.is_empty() { - write!(f, "\t")?; - } - } - - for idx in cleared_in_self.iter() { - let delim = if first { - "\u{001f}-" - } else if f.alternate() { - "\n\u{001f}-" - } else { - ", " - }; - - write!(f, "{}", delim)?; - idx.fmt_with(ctxt, f)?; - first = false; - } - - Ok(()) - } -} - -impl DebugWithContext for &'_ T -where - T: DebugWithContext, -{ - fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (*self).fmt_with(ctxt, f) - } - - fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (*self).fmt_diff_with(*old, ctxt, f) - } -} - -impl DebugWithContext for rustc_middle::mir::Local {} -impl DebugWithContext for crate::dataflow::move_paths::InitIndex {} - -impl<'tcx, C> DebugWithContext for crate::dataflow::move_paths::MovePathIndex -where - C: crate::dataflow::move_paths::HasMoveData<'tcx>, -{ - fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", ctxt.move_data().move_paths[*self]) - } -} - -impl DebugWithContext for crate::dataflow::lattice::Dual -where - T: DebugWithContext, -{ - fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (self.0).fmt_with(ctxt, f) - } - - fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (self.0).fmt_diff_with(&old.0, ctxt, f) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/graphviz.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/graphviz.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/graphviz.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/graphviz.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,644 +0,0 @@ -//! A helpful diagram for debugging dataflow problems. - -use std::borrow::Cow; -use std::lazy::SyncOnceCell; -use std::{io, ops, str}; - -use regex::Regex; -use rustc_graphviz as dot; -use rustc_middle::mir::{self, BasicBlock, Body, Location}; - -use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext}; -use super::{Analysis, Direction, Results, ResultsRefCursor, ResultsVisitor}; -use crate::util::graphviz_safe_def_name; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum OutputStyle { - AfterOnly, - BeforeAndAfter, -} - -impl OutputStyle { - fn num_state_columns(&self) -> usize { - match self { - Self::AfterOnly => 1, - Self::BeforeAndAfter => 2, - } - } -} - -pub struct Formatter<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - body: &'a Body<'tcx>, - results: &'a Results<'tcx, A>, - style: OutputStyle, -} - -impl Formatter<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self { - Formatter { body, results, style } - } -} - -/// A pair of a basic block and an index into that basic blocks `successors`. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct CfgEdge { - source: BasicBlock, - index: usize, -} - -fn dataflow_successors(body: &Body<'tcx>, bb: BasicBlock) -> Vec { - body[bb] - .terminator() - .successors() - .enumerate() - .map(|(index, _)| CfgEdge { source: bb, index }) - .collect() -} - -impl dot::Labeller<'_> for Formatter<'a, 'tcx, A> -where - A: Analysis<'tcx>, - A::Domain: DebugWithContext, -{ - type Node = BasicBlock; - type Edge = CfgEdge; - - fn graph_id(&self) -> dot::Id<'_> { - let name = graphviz_safe_def_name(self.body.source.def_id()); - dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap() - } - - fn node_id(&self, n: &Self::Node) -> dot::Id<'_> { - dot::Id::new(format!("bb_{}", n.index())).unwrap() - } - - fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let mut label = Vec::new(); - let mut fmt = BlockFormatter { - results: ResultsRefCursor::new(self.body, self.results), - style: self.style, - bg: Background::Light, - }; - - fmt.write_node_label(&mut label, self.body, *block).unwrap(); - dot::LabelText::html(String::from_utf8(label).unwrap()) - } - - fn node_shape(&self, _n: &Self::Node) -> Option> { - Some(dot::LabelText::label("none")) - } - - fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { - let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index]; - dot::LabelText::label(label.clone()) - } -} - -impl dot::GraphWalk<'a> for Formatter<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - type Node = BasicBlock; - type Edge = CfgEdge; - - fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - self.body.basic_blocks().indices().collect::>().into() - } - - fn edges(&self) -> dot::Edges<'_, Self::Edge> { - self.body - .basic_blocks() - .indices() - .flat_map(|bb| dataflow_successors(self.body, bb)) - .collect::>() - .into() - } - - fn source(&self, edge: &Self::Edge) -> Self::Node { - edge.source - } - - fn target(&self, edge: &Self::Edge) -> Self::Node { - self.body[edge.source].terminator().successors().nth(edge.index).copied().unwrap() - } -} - -struct BlockFormatter<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - results: ResultsRefCursor<'a, 'a, 'tcx, A>, - bg: Background, - style: OutputStyle, -} - -impl BlockFormatter<'a, 'tcx, A> -where - A: Analysis<'tcx>, - A::Domain: DebugWithContext, -{ - const HEADER_COLOR: &'static str = "#a0a0a0"; - - fn toggle_background(&mut self) -> Background { - let bg = self.bg; - self.bg = !bg; - bg - } - - fn write_node_label( - &mut self, - w: &mut impl io::Write, - body: &'a Body<'tcx>, - block: BasicBlock, - ) -> io::Result<()> { - // Sample output: - // +-+-----------------------------------------------+ - // A | bb4 | - // +-+----------------------------------+------------+ - // B | MIR | STATE | - // +-+----------------------------------+------------+ - // C | | (on entry) | {_0,_2,_3} | - // +-+----------------------------------+------------+ - // D |0| StorageLive(_7) | | - // +-+----------------------------------+------------+ - // |1| StorageLive(_8) | | - // +-+----------------------------------+------------+ - // |2| _8 = &mut _1 | +_8 | - // +-+----------------------------------+------------+ - // E |T| _4 = const Foo::twiddle(move _2) | -_2 | - // +-+----------------------------------+------------+ - // F | | (on unwind) | {_0,_3,_8} | - // +-+----------------------------------+------------+ - // | | (on successful return) | +_4 | - // +-+----------------------------------+------------+ - - // N.B., Some attributes (`align`, `balign`) are repeated on parent elements and their - // children. This is because `xdot` seemed to have a hard time correctly propagating - // attributes. Make sure to test the output before trying to remove the redundancy. - // Notably, `align` was found to have no effect when applied only to . - - let table_fmt = concat!( - " border=\"1\"", - " cellborder=\"1\"", - " cellspacing=\"0\"", - " cellpadding=\"3\"", - " sides=\"rb\"", - ); - write!(w, r#""#, fmt = table_fmt)?; - - // A + B: Block header - match self.style { - OutputStyle::AfterOnly => self.write_block_header_simple(w, block)?, - OutputStyle::BeforeAndAfter => { - self.write_block_header_with_state_columns(w, block, &["BEFORE", "AFTER"])? - } - } - - // C: State at start of block - self.bg = Background::Light; - self.results.seek_to_block_start(block); - let block_start_state = self.results.get().clone(); - self.write_row_with_full_state(w, "", "(on start)")?; - - // D + E: Statement and terminator transfer functions - self.write_statements_and_terminator(w, body, block)?; - - // F: State at end of block - - let terminator = body[block].terminator(); - - // Write the full dataflow state immediately after the terminator if it differs from the - // state at block entry. - self.results.seek_to_block_end(block); - if self.results.get() != &block_start_state || A::Direction::is_backward() { - let after_terminator_name = match terminator.kind { - mir::TerminatorKind::Call { destination: Some(_), .. } => "(on unwind)", - _ => "(on end)", - }; - - self.write_row_with_full_state(w, "", after_terminator_name)?; - } - - // Write any changes caused by terminator-specific effects. - // - // FIXME: These should really be printed as part of each outgoing edge rather than the node - // for the basic block itself. That way, we could display terminator-specific effects for - // backward dataflow analyses as well as effects for `SwitchInt` terminators. - match terminator.kind { - mir::TerminatorKind::Call { - destination: Some((return_place, _)), - ref func, - ref args, - .. - } => { - self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { - analysis.apply_call_return_effect(state, block, func, args, return_place); - }); - - write!( - w, - r#""#, - colspan = this.style.num_state_columns(), - fmt = fmt, - diff = diff_pretty( - this.results.get(), - &state_on_unwind, - this.results.analysis() - ), - ) - })?; - } - - mir::TerminatorKind::Yield { resume, resume_arg, .. } => { - self.write_row(w, "", "(on yield resume)", |this, w, fmt| { - let state_on_generator_drop = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { - analysis.apply_yield_resume_effect(state, resume, resume_arg); - }); - - write!( - w, - r#""#, - colspan = this.style.num_state_columns(), - fmt = fmt, - diff = diff_pretty( - this.results.get(), - &state_on_generator_drop, - this.results.analysis() - ), - ) - })?; - } - - _ => {} - }; - - write!(w, "
{diff}{diff}
") - } - - fn write_block_header_simple( - &mut self, - w: &mut impl io::Write, - block: BasicBlock, - ) -> io::Result<()> { - // +-------------------------------------------------+ - // A | bb4 | - // +-----------------------------------+-------------+ - // B | MIR | STATE | - // +-+---------------------------------+-------------+ - // | | ... | | - - // A - write!( - w, - concat!("", r#"bb{block_id}"#, "",), - block_id = block.index(), - )?; - - // B - write!( - w, - concat!( - "", - r#"MIR"#, - r#"STATE"#, - "", - ), - fmt = format!("bgcolor=\"{}\" sides=\"tl\"", Self::HEADER_COLOR), - ) - } - - fn write_block_header_with_state_columns( - &mut self, - w: &mut impl io::Write, - block: BasicBlock, - state_column_names: &[&str], - ) -> io::Result<()> { - // +------------------------------------+-------------+ - // A | bb4 | STATE | - // +------------------------------------+------+------+ - // B | MIR | GEN | KILL | - // +-+----------------------------------+------+------+ - // | | ... | | | - - // A - write!( - w, - concat!( - "", - r#"bb{block_id}"#, - r#"STATE"#, - "", - ), - fmt = "sides=\"tl\"", - num_state_cols = state_column_names.len(), - block_id = block.index(), - )?; - - // B - let fmt = format!("bgcolor=\"{}\" sides=\"tl\"", Self::HEADER_COLOR); - write!(w, concat!("", r#"MIR"#,), fmt = fmt,)?; - - for name in state_column_names { - write!(w, "{name}", fmt = fmt, name = name)?; - } - - write!(w, "") - } - - fn write_statements_and_terminator( - &mut self, - w: &mut impl io::Write, - body: &'a Body<'tcx>, - block: BasicBlock, - ) -> io::Result<()> { - let diffs = StateDiffCollector::run(body, block, self.results.results(), self.style); - - let mut befores = diffs.before.map(|v| v.into_iter()); - let mut afters = diffs.after.into_iter(); - - let next_in_dataflow_order = |it: &mut std::vec::IntoIter<_>| { - if A::Direction::is_forward() { it.next().unwrap() } else { it.next_back().unwrap() } - }; - - for (i, statement) in body[block].statements.iter().enumerate() { - let statement_str = format!("{:?}", statement); - let index_str = format!("{}", i); - - let after = next_in_dataflow_order(&mut afters); - let before = befores.as_mut().map(next_in_dataflow_order); - - self.write_row(w, &index_str, &statement_str, |_this, w, fmt| { - if let Some(before) = before { - write!(w, r#"{diff}"#, fmt = fmt, diff = before)?; - } - - write!(w, r#"{diff}"#, fmt = fmt, diff = after) - })?; - } - - let after = next_in_dataflow_order(&mut afters); - let before = befores.as_mut().map(next_in_dataflow_order); - - assert!(afters.is_empty()); - assert!(befores.as_ref().map_or(true, ExactSizeIterator::is_empty)); - - let terminator = body[block].terminator(); - let mut terminator_str = String::new(); - terminator.kind.fmt_head(&mut terminator_str).unwrap(); - - self.write_row(w, "T", &terminator_str, |_this, w, fmt| { - if let Some(before) = before { - write!(w, r#"{diff}"#, fmt = fmt, diff = before)?; - } - - write!(w, r#"{diff}"#, fmt = fmt, diff = after) - }) - } - - /// Write a row with the given index and MIR, using the function argument to fill in the - /// "STATE" column(s). - fn write_row( - &mut self, - w: &mut W, - i: &str, - mir: &str, - f: impl FnOnce(&mut Self, &mut W, &str) -> io::Result<()>, - ) -> io::Result<()> { - let bg = self.toggle_background(); - let valign = if mir.starts_with("(on ") && mir != "(on entry)" { "bottom" } else { "top" }; - - let fmt = format!("valign=\"{}\" sides=\"tl\" {}", valign, bg.attr()); - - write!( - w, - concat!( - "", - r#"{i}"#, - r#"{mir}"#, - ), - i = i, - fmt = fmt, - mir = dot::escape_html(mir), - )?; - - f(self, w, &fmt)?; - write!(w, "") - } - - fn write_row_with_full_state( - &mut self, - w: &mut impl io::Write, - i: &str, - mir: &str, - ) -> io::Result<()> { - self.write_row(w, i, mir, |this, w, fmt| { - let state = this.results.get(); - let analysis = this.results.analysis(); - - // FIXME: The full state vector can be quite long. It would be nice to split on commas - // and use some text wrapping algorithm. - write!( - w, - r#"{state}"#, - colspan = this.style.num_state_columns(), - fmt = fmt, - state = format!("{:?}", DebugWithAdapter { this: state, ctxt: analysis }), - ) - }) - } -} - -struct StateDiffCollector<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - analysis: &'a A, - prev_state: A::Domain, - before: Option>, - after: Vec, -} - -impl
StateDiffCollector<'a, 'tcx, A> -where - A: Analysis<'tcx>, - A::Domain: DebugWithContext, -{ - fn run( - body: &'a mir::Body<'tcx>, - block: BasicBlock, - results: &'a Results<'tcx, A>, - style: OutputStyle, - ) -> Self { - let mut collector = StateDiffCollector { - analysis: &results.analysis, - prev_state: results.analysis.bottom_value(body), - after: vec![], - before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), - }; - - results.visit_with(body, std::iter::once(block), &mut collector); - collector - } -} - -impl ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A> -where - A: Analysis<'tcx>, - A::Domain: DebugWithContext, -{ - type FlowState = A::Domain; - - fn visit_block_start( - &mut self, - state: &Self::FlowState, - _block_data: &'mir mir::BasicBlockData<'tcx>, - _block: BasicBlock, - ) { - if A::Direction::is_forward() { - self.prev_state.clone_from(state); - } - } - - fn visit_block_end( - &mut self, - state: &Self::FlowState, - _block_data: &'mir mir::BasicBlockData<'tcx>, - _block: BasicBlock, - ) { - if A::Direction::is_backward() { - self.prev_state.clone_from(state); - } - } - - fn visit_statement_before_primary_effect( - &mut self, - state: &Self::FlowState, - _statement: &'mir mir::Statement<'tcx>, - _location: Location, - ) { - if let Some(before) = self.before.as_mut() { - before.push(diff_pretty(state, &self.prev_state, self.analysis)); - self.prev_state.clone_from(state) - } - } - - fn visit_statement_after_primary_effect( - &mut self, - state: &Self::FlowState, - _statement: &'mir mir::Statement<'tcx>, - _location: Location, - ) { - self.after.push(diff_pretty(state, &self.prev_state, self.analysis)); - self.prev_state.clone_from(state) - } - - fn visit_terminator_before_primary_effect( - &mut self, - state: &Self::FlowState, - _terminator: &'mir mir::Terminator<'tcx>, - _location: Location, - ) { - if let Some(before) = self.before.as_mut() { - before.push(diff_pretty(state, &self.prev_state, self.analysis)); - self.prev_state.clone_from(state) - } - } - - fn visit_terminator_after_primary_effect( - &mut self, - state: &Self::FlowState, - _terminator: &'mir mir::Terminator<'tcx>, - _location: Location, - ) { - self.after.push(diff_pretty(state, &self.prev_state, self.analysis)); - self.prev_state.clone_from(state) - } -} - -macro_rules! regex { - ($re:literal $(,)?) => {{ - static RE: SyncOnceCell = SyncOnceCell::new(); - RE.get_or_init(|| Regex::new($re).unwrap()) - }}; -} - -fn diff_pretty(new: T, old: T, ctxt: &C) -> String -where - T: DebugWithContext, -{ - if new == old { - return String::new(); - } - - let re = regex!("\t?\u{001f}([+-])"); - - let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt }); - - // Replace newlines in the `Debug` output with `
` - let raw_diff = raw_diff.replace('\n', r#"
"#); - - let mut inside_font_tag = false; - let html_diff = re.replace_all(&raw_diff, |captures: ®ex::Captures<'_>| { - let mut ret = String::new(); - if inside_font_tag { - ret.push_str(r#""#); - } - - let tag = match &captures[1] { - "+" => r#"+"#, - "-" => r#"-"#, - _ => unreachable!(), - }; - - inside_font_tag = true; - ret.push_str(tag); - ret - }); - - let mut html_diff = match html_diff { - Cow::Borrowed(_) => return raw_diff, - Cow::Owned(s) => s, - }; - - if inside_font_tag { - html_diff.push_str(""); - } - - html_diff -} - -/// The background color used for zebra-striping the table. -#[derive(Clone, Copy)] -enum Background { - Light, - Dark, -} - -impl Background { - fn attr(self) -> &'static str { - match self { - Self::Dark => "bgcolor=\"#f0f0f0\"", - Self::Light => "", - } - } -} - -impl ops::Not for Background { - type Output = Self; - - fn not(self) -> Self { - match self { - Self::Light => Self::Dark, - Self::Dark => Self::Light, - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/lattice.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/lattice.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/lattice.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/lattice.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,231 +0,0 @@ -//! Traits used to represent [lattices] for use as the domain of a dataflow analysis. -//! -//! # Overview -//! -//! The most common lattice is a powerset of some set `S`, ordered by [set inclusion]. The [Hasse -//! diagram] for the powerset of a set with two elements (`X` and `Y`) is shown below. Note that -//! distinct elements at the same height in a Hasse diagram (e.g. `{X}` and `{Y}`) are -//! *incomparable*, not equal. -//! -//! ```text -//! {X, Y} <- top -//! / \ -//! {X} {Y} -//! \ / -//! {} <- bottom -//! -//! ``` -//! -//! The defining characteristic of a lattice—the one that differentiates it from a [partially -//! ordered set][poset]—is the existence of a *unique* least upper and greatest lower bound for -//! every pair of elements. The lattice join operator (`∨`) returns the least upper bound, and the -//! lattice meet operator (`∧`) returns the greatest lower bound. Types that implement one operator -//! but not the other are known as semilattices. Dataflow analysis only uses the join operator and -//! will work with any join-semilattice, but both should be specified when possible. -//! -//! ## `PartialOrd` -//! -//! Given that they represent partially ordered sets, you may be surprised that [`JoinSemiLattice`] -//! and [`MeetSemiLattice`] do not have [`PartialOrd`][std::cmp::PartialOrd] as a supertrait. This -//! is because most standard library types use lexicographic ordering instead of set inclusion for -//! their `PartialOrd` impl. Since we do not actually need to compare lattice elements to run a -//! dataflow analysis, there's no need for a newtype wrapper with a custom `PartialOrd` impl. The -//! only benefit would be the ability to check that the least upper (or greatest lower) bound -//! returned by the lattice join (or meet) operator was in fact greater (or lower) than the inputs. -//! -//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) -//! [set inclusion]: https://en.wikipedia.org/wiki/Subset -//! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram -//! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set - -use rustc_index::bit_set::BitSet; -use rustc_index::vec::{Idx, IndexVec}; -use std::iter; - -/// A [partially ordered set][poset] that has a [least upper bound][lub] for any pair of elements -/// in the set. -/// -/// [lub]: https://en.wikipedia.org/wiki/Infimum_and_supremum -/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set -pub trait JoinSemiLattice: Eq { - /// Computes the least upper bound of two elements, storing the result in `self` and returning - /// `true` if `self` has changed. - /// - /// The lattice join operator is abbreviated as `∨`. - fn join(&mut self, other: &Self) -> bool; -} - -/// A [partially ordered set][poset] that has a [greatest lower bound][glb] for any pair of -/// elements in the set. -/// -/// Dataflow analyses only require that their domains implement [`JoinSemiLattice`], not -/// `MeetSemiLattice`. However, types that will be used as dataflow domains should implement both -/// so that they can be used with [`Dual`]. -/// -/// [glb]: https://en.wikipedia.org/wiki/Infimum_and_supremum -/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set -pub trait MeetSemiLattice: Eq { - /// Computes the greatest lower bound of two elements, storing the result in `self` and - /// returning `true` if `self` has changed. - /// - /// The lattice meet operator is abbreviated as `∧`. - fn meet(&mut self, other: &Self) -> bool; -} - -/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom: -/// -/// ```text -/// true -/// | -/// false -/// ``` -impl JoinSemiLattice for bool { - fn join(&mut self, other: &Self) -> bool { - if let (false, true) = (*self, *other) { - *self = true; - return true; - } - - false - } -} - -impl MeetSemiLattice for bool { - fn meet(&mut self, other: &Self) -> bool { - if let (true, false) = (*self, *other) { - *self = false; - return true; - } - - false - } -} - -/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation -/// of the least upper bounds of each element of the tuple (or list). -/// -/// In other words: -/// (Aâ‚€, Aâ‚, ..., Aâ‚™) ∨ (Bâ‚€, Bâ‚, ..., Bâ‚™) = (A₀∨Bâ‚€, Aâ‚∨Bâ‚, ..., Aₙ∨Bâ‚™) -impl JoinSemiLattice for IndexVec { - fn join(&mut self, other: &Self) -> bool { - assert_eq!(self.len(), other.len()); - - let mut changed = false; - for (a, b) in iter::zip(self, other) { - changed |= a.join(b); - } - changed - } -} - -impl MeetSemiLattice for IndexVec { - fn meet(&mut self, other: &Self) -> bool { - assert_eq!(self.len(), other.len()); - - let mut changed = false; - for (a, b) in iter::zip(self, other) { - changed |= a.meet(b); - } - changed - } -} - -/// A `BitSet` represents the lattice formed by the powerset of all possible values of -/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices, -/// one for each possible value of `T`. -impl JoinSemiLattice for BitSet { - fn join(&mut self, other: &Self) -> bool { - self.union(other) - } -} - -impl MeetSemiLattice for BitSet { - fn meet(&mut self, other: &Self) -> bool { - self.intersect(other) - } -} - -/// The counterpart of a given semilattice `T` using the [inverse order]. -/// -/// The dual of a join-semilattice is a meet-semilattice and vice versa. For example, the dual of a -/// powerset has the empty set as its top element and the full set as its bottom element and uses -/// set *intersection* as its join operator. -/// -/// [inverse order]: https://en.wikipedia.org/wiki/Duality_(order_theory) -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Dual(pub T); - -impl std::borrow::Borrow for Dual { - fn borrow(&self) -> &T { - &self.0 - } -} - -impl std::borrow::BorrowMut for Dual { - fn borrow_mut(&mut self) -> &mut T { - &mut self.0 - } -} - -impl JoinSemiLattice for Dual { - fn join(&mut self, other: &Self) -> bool { - self.0.meet(&other.0) - } -} - -impl MeetSemiLattice for Dual { - fn meet(&mut self, other: &Self) -> bool { - self.0.join(&other.0) - } -} - -/// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no -/// value of `T` is comparable with any other. A flat set has the following [Hasse diagram]: -/// -/// ```text -/// top -/// / / \ \ -/// all possible values of `T` -/// \ \ / / -/// bottom -/// ``` -/// -/// [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum FlatSet { - Bottom, - Elem(T), - Top, -} - -impl JoinSemiLattice for FlatSet { - fn join(&mut self, other: &Self) -> bool { - let result = match (&*self, other) { - (Self::Top, _) | (_, Self::Bottom) => return false, - (Self::Elem(a), Self::Elem(b)) if a == b => return false, - - (Self::Bottom, Self::Elem(x)) => Self::Elem(x.clone()), - - _ => Self::Top, - }; - - *self = result; - true - } -} - -impl MeetSemiLattice for FlatSet { - fn meet(&mut self, other: &Self) -> bool { - let result = match (&*self, other) { - (Self::Bottom, _) | (_, Self::Top) => return false, - (Self::Elem(ref a), Self::Elem(ref b)) if a == b => return false, - - (Self::Top, Self::Elem(ref x)) => Self::Elem(x.clone()), - - _ => Self::Bottom, - }; - - *self = result; - true - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,547 +0,0 @@ -//! A framework that can express both [gen-kill] and generic dataflow problems. -//! -//! To actually use this framework, you must implement either the `Analysis` or the -//! `GenKillAnalysis` trait. If your transfer function can be expressed with only gen/kill -//! operations, prefer `GenKillAnalysis` since it will run faster while iterating to fixpoint. The -//! `impls` module contains several examples of gen/kill dataflow analyses. -//! -//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait, -//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the -//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use -//! `visit_results`. The following example uses the `ResultsCursor` approach. -//! -//! ```ignore (cross-crate-imports) -//! use rustc_mir::dataflow::Analysis; // Makes `into_engine` available. -//! -//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { -//! let analysis = MyAnalysis::new() -//! .into_engine(tcx, body) -//! .iterate_to_fixpoint() -//! .into_results_cursor(body); -//! -//! // Print the dataflow state *after* each statement in the start block. -//! for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() { -//! cursor.seek_after(Location { block: START_BLOCK, statement_index }); -//! let state = cursor.get(); -//! println!("{:?}", state); -//! } -//! } -//! ``` -//! -//! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems - -use std::borrow::BorrowMut; -use std::cmp::Ordering; - -use rustc_index::bit_set::{BitSet, HybridBitSet}; -use rustc_index::vec::Idx; -use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::TyCtxt; - -mod cursor; -mod direction; -mod engine; -pub mod fmt; -pub mod graphviz; -pub mod lattice; -mod visitor; - -pub use self::cursor::{ResultsCursor, ResultsRefCursor}; -pub use self::direction::{Backward, Direction, Forward}; -pub use self::engine::{Engine, Results}; -pub use self::lattice::{JoinSemiLattice, MeetSemiLattice}; -pub use self::visitor::{visit_results, ResultsVisitor}; -pub use self::visitor::{BorrowckFlowState, BorrowckResults}; - -/// Define the domain of a dataflow problem. -/// -/// This trait specifies the lattice on which this analysis operates (the domain) as well as its -/// initial value at the entry point of each basic block. -pub trait AnalysisDomain<'tcx> { - /// The type that holds the dataflow state at any given point in the program. - type Domain: Clone + JoinSemiLattice; - - /// The direction of this analysis. Either `Forward` or `Backward`. - type Direction: Direction = Forward; - - /// A descriptive name for this analysis. Used only for debugging. - /// - /// This name should be brief and contain no spaces, periods or other characters that are not - /// suitable as part of a filename. - const NAME: &'static str; - - /// The initial value of the dataflow state upon entry to each basic block. - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; - - /// Mutates the initial value of the dataflow state upon entry to the `START_BLOCK`. - /// - /// For backward analyses, initial state besides the bottom value is not yet supported. Trying - /// to mutate the initial state will result in a panic. - // - // FIXME: For backward dataflow analyses, the initial state should be applied to every basic - // block where control flow could exit the MIR body (e.g., those terminated with `return` or - // `resume`). It's not obvious how to handle `yield` points in generators, however. - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain); -} - -/// A dataflow problem with an arbitrarily complex transfer function. -/// -/// # Convergence -/// -/// When implementing this trait directly (not via [`GenKillAnalysis`]), it's possible to choose a -/// transfer function such that the analysis does not reach fixpoint. To guarantee convergence, -/// your transfer functions must maintain the following invariant: -/// -/// > If the dataflow state **before** some point in the program changes to be greater -/// than the prior state **before** that point, the dataflow state **after** that point must -/// also change to be greater than the prior state **after** that point. -/// -/// This invariant guarantees that the dataflow state at a given point in the program increases -/// monotonically until fixpoint is reached. Note that this monotonicity requirement only applies -/// to the same point in the program at different points in time. The dataflow state at a given -/// point in the program may or may not be greater than the state at any preceding point. -pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { - /// Updates the current dataflow state with the effect of evaluating a statement. - fn apply_statement_effect( - &self, - state: &mut Self::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ); - - /// Updates the current dataflow state with an effect that occurs immediately *before* the - /// given statement. - /// - /// This method is useful if the consumer of the results of this analysis needs only to observe - /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule, - /// analyses should not implement this without implementing `apply_statement_effect`. - fn apply_before_statement_effect( - &self, - _state: &mut Self::Domain, - _statement: &mir::Statement<'tcx>, - _location: Location, - ) { - } - - /// Updates the current dataflow state with the effect of evaluating a terminator. - /// - /// The effect of a successful return from a `Call` terminator should **not** be accounted for - /// in this function. That should go in `apply_call_return_effect`. For example, in the - /// `InitializedPlaces` analyses, the return place for a function call is not marked as - /// initialized here. - fn apply_terminator_effect( - &self, - state: &mut Self::Domain, - terminator: &mir::Terminator<'tcx>, - location: Location, - ); - - /// Updates the current dataflow state with an effect that occurs immediately *before* the - /// given terminator. - /// - /// This method is useful if the consumer of the results of this analysis needs only to observe - /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule, - /// analyses should not implement this without implementing `apply_terminator_effect`. - fn apply_before_terminator_effect( - &self, - _state: &mut Self::Domain, - _terminator: &mir::Terminator<'tcx>, - _location: Location, - ) { - } - - /* Edge-specific effects */ - - /// Updates the current dataflow state with the effect of a successful return from a `Call` - /// terminator. - /// - /// This is separate from `apply_terminator_effect` to properly track state across unwind - /// edges. - fn apply_call_return_effect( - &self, - state: &mut Self::Domain, - block: BasicBlock, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, - ); - - /// Updates the current dataflow state with the effect of resuming from a `Yield` terminator. - /// - /// This is similar to `apply_call_return_effect` in that it only takes place after the - /// generator is resumed, not when it is dropped. - /// - /// By default, no effects happen. - fn apply_yield_resume_effect( - &self, - _state: &mut Self::Domain, - _resume_block: BasicBlock, - _resume_place: mir::Place<'tcx>, - ) { - } - - /// Updates the current dataflow state with the effect of taking a particular branch in a - /// `SwitchInt` terminator. - /// - /// Unlike the other edge-specific effects, which are allowed to mutate `Self::Domain` - /// directly, overriders of this method must pass a callback to - /// `SwitchIntEdgeEffects::apply`. The callback will be run once for each outgoing edge and - /// will have access to the dataflow state that will be propagated along that edge. - /// - /// This interface is somewhat more complex than the other visitor-like "effect" methods. - /// However, it is both more ergonomic—callers don't need to recompute or cache information - /// about a given `SwitchInt` terminator for each one of its edges—and more efficient—the - /// engine doesn't need to clone the exit state for a block unless - /// `SwitchIntEdgeEffects::apply` is actually called. - /// - /// FIXME: This class of effects is not supported for backward dataflow analyses. - fn apply_switch_int_edge_effects( - &self, - _block: BasicBlock, - _discr: &mir::Operand<'tcx>, - _apply_edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - } - - /* Extension methods */ - - /// Creates an `Engine` to find the fixpoint for this dataflow problem. - /// - /// You shouldn't need to override this outside this module, since the combination of the - /// default impl and the one for all `A: GenKillAnalysis` will do the right thing. - /// Its purpose is to enable method chaining like so: - /// - /// ```ignore (cross-crate-imports) - /// let results = MyAnalysis::new(tcx, body) - /// .into_engine(tcx, body, def_id) - /// .iterate_to_fixpoint() - /// .into_results_cursor(body); - /// ``` - fn into_engine(self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Engine<'mir, 'tcx, Self> - where - Self: Sized, - { - Engine::new_generic(tcx, body, self) - } -} - -/// A gen/kill dataflow problem. -/// -/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only -/// allow modification of the dataflow state via "gen" and "kill" operations. By defining transfer -/// functions for each statement in this way, the transfer function for an entire basic block can -/// be computed efficiently. -/// -/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis`. -pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { - type Idx: Idx; - - /// See `Analysis::apply_statement_effect`. - fn statement_effect( - &self, - trans: &mut impl GenKill, - statement: &mir::Statement<'tcx>, - location: Location, - ); - - /// See `Analysis::apply_before_statement_effect`. - fn before_statement_effect( - &self, - _trans: &mut impl GenKill, - _statement: &mir::Statement<'tcx>, - _location: Location, - ) { - } - - /// See `Analysis::apply_terminator_effect`. - fn terminator_effect( - &self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, - location: Location, - ); - - /// See `Analysis::apply_before_terminator_effect`. - fn before_terminator_effect( - &self, - _trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - _location: Location, - ) { - } - - /* Edge-specific effects */ - - /// See `Analysis::apply_call_return_effect`. - fn call_return_effect( - &self, - trans: &mut impl GenKill, - block: BasicBlock, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, - ); - - /// See `Analysis::apply_yield_resume_effect`. - fn yield_resume_effect( - &self, - _trans: &mut impl GenKill, - _resume_block: BasicBlock, - _resume_place: mir::Place<'tcx>, - ) { - } - - /// See `Analysis::apply_switch_int_edge_effects`. - fn switch_int_edge_effects>( - &self, - _block: BasicBlock, - _discr: &mir::Operand<'tcx>, - _edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - } -} - -impl
Analysis<'tcx> for A -where - A: GenKillAnalysis<'tcx>, - A::Domain: GenKill + BorrowMut>, -{ - fn apply_statement_effect( - &self, - state: &mut A::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.statement_effect(state, statement, location); - } - - fn apply_before_statement_effect( - &self, - state: &mut A::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.before_statement_effect(state, statement, location); - } - - fn apply_terminator_effect( - &self, - state: &mut A::Domain, - terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - self.terminator_effect(state, terminator, location); - } - - fn apply_before_terminator_effect( - &self, - state: &mut A::Domain, - terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - self.before_terminator_effect(state, terminator, location); - } - - /* Edge-specific effects */ - - fn apply_call_return_effect( - &self, - state: &mut A::Domain, - block: BasicBlock, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, - ) { - self.call_return_effect(state, block, func, args, return_place); - } - - fn apply_yield_resume_effect( - &self, - state: &mut A::Domain, - resume_block: BasicBlock, - resume_place: mir::Place<'tcx>, - ) { - self.yield_resume_effect(state, resume_block, resume_place); - } - - fn apply_switch_int_edge_effects( - &self, - block: BasicBlock, - discr: &mir::Operand<'tcx>, - edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - self.switch_int_edge_effects(block, discr, edge_effects); - } - - /* Extension methods */ - - fn into_engine(self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Engine<'mir, 'tcx, Self> - where - Self: Sized, - { - Engine::new_gen_kill(tcx, body, self) - } -} - -/// The legal operations for a transfer function in a gen/kill problem. -/// -/// This abstraction exists because there are two different contexts in which we call the methods in -/// `GenKillAnalysis`. Sometimes we need to store a single transfer function that can be efficiently -/// applied multiple times, such as when computing the cumulative transfer function for each block. -/// These cases require a `GenKillSet`, which in turn requires two `BitSet`s of storage. Oftentimes, -/// however, we only need to apply an effect once. In *these* cases, it is more efficient to pass the -/// `BitSet` representing the state vector directly into the `*_effect` methods as opposed to -/// building up a `GenKillSet` and then throwing it away. -pub trait GenKill { - /// Inserts `elem` into the state vector. - fn gen(&mut self, elem: T); - - /// Removes `elem` from the state vector. - fn kill(&mut self, elem: T); - - /// Calls `gen` for each element in `elems`. - fn gen_all(&mut self, elems: impl IntoIterator) { - for elem in elems { - self.gen(elem); - } - } - - /// Calls `kill` for each element in `elems`. - fn kill_all(&mut self, elems: impl IntoIterator) { - for elem in elems { - self.kill(elem); - } - } -} - -/// Stores a transfer function for a gen/kill problem. -/// -/// Calling `gen`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be -/// applied multiple times efficiently. When there are multiple calls to `gen` and/or `kill` for -/// the same element, the most recent one takes precedence. -#[derive(Clone)] -pub struct GenKillSet { - gen: HybridBitSet, - kill: HybridBitSet, -} - -impl GenKillSet { - /// Creates a new transfer function that will leave the dataflow state unchanged. - pub fn identity(universe: usize) -> Self { - GenKillSet { - gen: HybridBitSet::new_empty(universe), - kill: HybridBitSet::new_empty(universe), - } - } - - pub fn apply(&self, state: &mut BitSet) { - state.union(&self.gen); - state.subtract(&self.kill); - } -} - -impl GenKill for GenKillSet { - fn gen(&mut self, elem: T) { - self.gen.insert(elem); - self.kill.remove(elem); - } - - fn kill(&mut self, elem: T) { - self.kill.insert(elem); - self.gen.remove(elem); - } -} - -impl GenKill for BitSet { - fn gen(&mut self, elem: T) { - self.insert(elem); - } - - fn kill(&mut self, elem: T) { - self.remove(elem); - } -} - -impl GenKill for lattice::Dual> { - fn gen(&mut self, elem: T) { - self.0.insert(elem); - } - - fn kill(&mut self, elem: T) { - self.0.remove(elem); - } -} - -// NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum Effect { - /// The "before" effect (e.g., `apply_before_statement_effect`) for a statement (or - /// terminator). - Before, - - /// The "primary" effect (e.g., `apply_statement_effect`) for a statement (or terminator). - Primary, -} - -impl Effect { - pub const fn at_index(self, statement_index: usize) -> EffectIndex { - EffectIndex { effect: self, statement_index } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct EffectIndex { - statement_index: usize, - effect: Effect, -} - -impl EffectIndex { - fn next_in_forward_order(self) -> Self { - match self.effect { - Effect::Before => Effect::Primary.at_index(self.statement_index), - Effect::Primary => Effect::Before.at_index(self.statement_index + 1), - } - } - - fn next_in_backward_order(self) -> Self { - match self.effect { - Effect::Before => Effect::Primary.at_index(self.statement_index), - Effect::Primary => Effect::Before.at_index(self.statement_index - 1), - } - } - - /// Returns `true` if the effect at `self` should be applied earlier than the effect at `other` - /// in forward order. - fn precedes_in_forward_order(self, other: Self) -> bool { - let ord = self - .statement_index - .cmp(&other.statement_index) - .then_with(|| self.effect.cmp(&other.effect)); - ord == Ordering::Less - } - - /// Returns `true` if the effect at `self` should be applied earlier than the effect at `other` - /// in backward order. - fn precedes_in_backward_order(self, other: Self) -> bool { - let ord = other - .statement_index - .cmp(&self.statement_index) - .then_with(|| self.effect.cmp(&other.effect)); - ord == Ordering::Less - } -} - -pub struct SwitchIntTarget { - pub value: Option, - pub target: BasicBlock, -} - -/// A type that records the edge-specific effects for a `SwitchInt` terminator. -pub trait SwitchIntEdgeEffects { - /// Calls `apply_edge_effect` for each outgoing edge from a `SwitchInt` terminator and - /// records the results. - fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)); -} - -#[cfg(test)] -mod tests; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/tests.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,320 +0,0 @@ -//! A test for the logic that updates the state in a `ResultsCursor` during seek. - -use std::marker::PhantomData; - -use rustc_index::bit_set::BitSet; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty; -use rustc_span::DUMMY_SP; - -use super::*; - -/// Creates a `mir::Body` with a few disconnected basic blocks. -/// -/// This is the `Body` that will be used by the `MockAnalysis` below. The shape of its CFG is not -/// important. -fn mock_body() -> mir::Body<'static> { - let source_info = mir::SourceInfo::outermost(DUMMY_SP); - - let mut blocks = IndexVec::new(); - let mut block = |n, kind| { - let nop = mir::Statement { source_info, kind: mir::StatementKind::Nop }; - - blocks.push(mir::BasicBlockData { - statements: std::iter::repeat(&nop).cloned().take(n).collect(), - terminator: Some(mir::Terminator { source_info, kind }), - is_cleanup: false, - }) - }; - - let dummy_place = mir::Place { local: mir::RETURN_PLACE, projection: ty::List::empty() }; - - block(4, mir::TerminatorKind::Return); - block(1, mir::TerminatorKind::Return); - block( - 2, - mir::TerminatorKind::Call { - func: mir::Operand::Copy(dummy_place.clone()), - args: vec![], - destination: Some((dummy_place.clone(), mir::START_BLOCK)), - cleanup: None, - from_hir_call: false, - fn_span: DUMMY_SP, - }, - ); - block(3, mir::TerminatorKind::Return); - block(0, mir::TerminatorKind::Return); - block( - 4, - mir::TerminatorKind::Call { - func: mir::Operand::Copy(dummy_place.clone()), - args: vec![], - destination: Some((dummy_place.clone(), mir::START_BLOCK)), - cleanup: None, - from_hir_call: false, - fn_span: DUMMY_SP, - }, - ); - - mir::Body::new_cfg_only(blocks) -} - -/// A dataflow analysis whose state is unique at every possible `SeekTarget`. -/// -/// Uniqueness is achieved by having a *locally* unique effect before and after each statement and -/// terminator (see `effect_at_target`) while ensuring that the entry set for each block is -/// *globally* unique (see `mock_entry_set`). -/// -/// For example, a `BasicBlock` with ID `2` and a `Call` terminator has the following state at each -/// location ("+x" indicates that "x" is added to the state). -/// -/// | Location | Before | After | -/// |------------------------|-------------------|--------| -/// | (on_entry) | {102} || -/// | statement 0 | +0 | +1 | -/// | statement 1 | +2 | +3 | -/// | `Call` terminator | +4 | +5 | -/// | (on unwind) | {102,0,1,2,3,4,5} || -/// -/// The `102` in the block's entry set is derived from the basic block index and ensures that the -/// expected state is unique across all basic blocks. Remember, it is generated by -/// `mock_entry_sets`, not from actually running `MockAnalysis` to fixpoint. -struct MockAnalysis<'tcx, D> { - body: &'tcx mir::Body<'tcx>, - dir: PhantomData, -} - -impl MockAnalysis<'tcx, D> { - const BASIC_BLOCK_OFFSET: usize = 100; - - /// The entry set for each `BasicBlock` is the ID of that block offset by a fixed amount to - /// avoid colliding with the statement/terminator effects. - fn mock_entry_set(&self, bb: BasicBlock) -> BitSet { - let mut ret = self.bottom_value(self.body); - ret.insert(Self::BASIC_BLOCK_OFFSET + bb.index()); - ret - } - - fn mock_entry_sets(&self) -> IndexVec> { - let empty = self.bottom_value(self.body); - let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks()); - - for (bb, _) in self.body.basic_blocks().iter_enumerated() { - ret[bb] = self.mock_entry_set(bb); - } - - ret - } - - /// Returns the index that should be added to the dataflow state at the given target. - fn effect(&self, loc: EffectIndex) -> usize { - let idx = match loc.effect { - Effect::Before => loc.statement_index * 2, - Effect::Primary => loc.statement_index * 2 + 1, - }; - - assert!(idx < Self::BASIC_BLOCK_OFFSET, "Too many statements in basic block"); - idx - } - - /// Returns the expected state at the given `SeekTarget`. - /// - /// This is the union of index of the target basic block, the index assigned to the - /// target statement or terminator, and the indices of all preceding statements in the target - /// basic block. - /// - /// For example, the expected state when calling - /// `seek_before_primary_effect(Location { block: 2, statement_index: 2 })` - /// would be `[102, 0, 1, 2, 3, 4]`. - fn expected_state_at_target(&self, target: SeekTarget) -> BitSet { - let block = target.block(); - let mut ret = self.bottom_value(self.body); - ret.insert(Self::BASIC_BLOCK_OFFSET + block.index()); - - let target = match target { - SeekTarget::BlockEntry { .. } => return ret, - SeekTarget::Before(loc) => Effect::Before.at_index(loc.statement_index), - SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index), - }; - - let mut pos = if D::is_forward() { - Effect::Before.at_index(0) - } else { - Effect::Before.at_index(self.body[block].statements.len()) - }; - - loop { - ret.insert(self.effect(pos)); - - if pos == target { - return ret; - } - - if D::is_forward() { - pos = pos.next_in_forward_order(); - } else { - pos = pos.next_in_backward_order(); - } - } - } -} - -impl AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { - type Domain = BitSet; - type Direction = D; - - const NAME: &'static str = "mock"; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - BitSet::new_empty(Self::BASIC_BLOCK_OFFSET + body.basic_blocks().len()) - } - - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { - unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint"); - } -} - -impl Analysis<'tcx> for MockAnalysis<'tcx, D> { - fn apply_statement_effect( - &self, - state: &mut Self::Domain, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - let idx = self.effect(Effect::Primary.at_index(location.statement_index)); - assert!(state.insert(idx)); - } - - fn apply_before_statement_effect( - &self, - state: &mut Self::Domain, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - let idx = self.effect(Effect::Before.at_index(location.statement_index)); - assert!(state.insert(idx)); - } - - fn apply_terminator_effect( - &self, - state: &mut Self::Domain, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - let idx = self.effect(Effect::Primary.at_index(location.statement_index)); - assert!(state.insert(idx)); - } - - fn apply_before_terminator_effect( - &self, - state: &mut Self::Domain, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - let idx = self.effect(Effect::Before.at_index(location.statement_index)); - assert!(state.insert(idx)); - } - - fn apply_call_return_effect( - &self, - _state: &mut Self::Domain, - _block: BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - _return_place: mir::Place<'tcx>, - ) { - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum SeekTarget { - BlockEntry(BasicBlock), - Before(Location), - After(Location), -} - -impl SeekTarget { - fn block(&self) -> BasicBlock { - use SeekTarget::*; - - match *self { - BlockEntry(block) => block, - Before(loc) | After(loc) => loc.block, - } - } - - /// An iterator over all possible `SeekTarget`s in a given block in order, starting with - /// `BlockEntry`. - fn iter_in_block(body: &mir::Body<'_>, block: BasicBlock) -> impl Iterator { - let statements_and_terminator = (0..=body[block].statements.len()) - .flat_map(|i| (0..2).map(move |j| (i, j))) - .map(move |(i, kind)| { - let loc = Location { block, statement_index: i }; - match kind { - 0 => SeekTarget::Before(loc), - 1 => SeekTarget::After(loc), - _ => unreachable!(), - } - }); - - std::iter::once(SeekTarget::BlockEntry(block)).chain(statements_and_terminator) - } -} - -fn test_cursor(analysis: MockAnalysis<'tcx, D>) { - let body = analysis.body; - - let mut cursor = - Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body); - - let every_target = || { - body.basic_blocks() - .iter_enumerated() - .flat_map(|(bb, _)| SeekTarget::iter_in_block(body, bb)) - }; - - let mut seek_to_target = |targ| { - use SeekTarget::*; - - match targ { - BlockEntry(block) => cursor.seek_to_block_entry(block), - Before(loc) => cursor.seek_before_primary_effect(loc), - After(loc) => cursor.seek_after_primary_effect(loc), - } - - assert_eq!(cursor.get(), &cursor.analysis().expected_state_at_target(targ)); - }; - - // Seek *to* every possible `SeekTarget` *from* every possible `SeekTarget`. - // - // By resetting the cursor to `from` each time it changes, we end up checking some edges twice. - // What we really want is an Eulerian cycle for the complete digraph over all possible - // `SeekTarget`s, but it's not worth spending the time to compute it. - for from in every_target() { - seek_to_target(from); - - for to in every_target() { - dbg!(from); - dbg!(to); - seek_to_target(to); - seek_to_target(from); - } - } -} - -#[test] -fn backward_cursor() { - let body = mock_body(); - let body = &body; - let analysis = MockAnalysis { body, dir: PhantomData:: }; - test_cursor(analysis) -} - -#[test] -fn forward_cursor() { - let body = mock_body(); - let body = &body; - let analysis = MockAnalysis { body, dir: PhantomData:: }; - test_cursor(analysis) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/visitor.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/visitor.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/visitor.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/framework/visitor.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +0,0 @@ -use rustc_middle::mir::{self, BasicBlock, Location}; - -use super::{Analysis, Direction, Results}; -use crate::dataflow::impls::{borrows::Borrows, EverInitializedPlaces, MaybeUninitializedPlaces}; - -/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the -/// dataflow state at that location. -pub fn visit_results( - body: &'mir mir::Body<'tcx>, - blocks: impl IntoIterator, - results: &V, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, -) where - V: ResultsVisitable<'tcx, FlowState = F>, -{ - let mut state = results.new_flow_state(body); - - #[cfg(debug_assertions)] - let reachable_blocks = mir::traversal::reachable_as_bitset(body); - - for block in blocks { - #[cfg(debug_assertions)] - assert!(reachable_blocks.contains(block)); - - let block_data = &body[block]; - V::Direction::visit_results_in_block(&mut state, block, block_data, results, vis); - } -} - -pub trait ResultsVisitor<'mir, 'tcx> { - type FlowState; - - fn visit_block_start( - &mut self, - _state: &Self::FlowState, - _block_data: &'mir mir::BasicBlockData<'tcx>, - _block: BasicBlock, - ) { - } - - /// Called with the `before_statement_effect` of the given statement applied to `state` but not - /// its `statement_effect`. - fn visit_statement_before_primary_effect( - &mut self, - _state: &Self::FlowState, - _statement: &'mir mir::Statement<'tcx>, - _location: Location, - ) { - } - - /// Called with both the `before_statement_effect` and the `statement_effect` of the given - /// statement applied to `state`. - fn visit_statement_after_primary_effect( - &mut self, - _state: &Self::FlowState, - _statement: &'mir mir::Statement<'tcx>, - _location: Location, - ) { - } - - /// Called with the `before_terminator_effect` of the given terminator applied to `state` but not - /// its `terminator_effect`. - fn visit_terminator_before_primary_effect( - &mut self, - _state: &Self::FlowState, - _terminator: &'mir mir::Terminator<'tcx>, - _location: Location, - ) { - } - - /// Called with both the `before_terminator_effect` and the `terminator_effect` of the given - /// terminator applied to `state`. - /// - /// The `call_return_effect` (if one exists) will *not* be applied to `state`. - fn visit_terminator_after_primary_effect( - &mut self, - _state: &Self::FlowState, - _terminator: &'mir mir::Terminator<'tcx>, - _location: Location, - ) { - } - - fn visit_block_end( - &mut self, - _state: &Self::FlowState, - _block_data: &'mir mir::BasicBlockData<'tcx>, - _block: BasicBlock, - ) { - } -} - -/// Things that can be visited by a `ResultsVisitor`. -/// -/// This trait exists so that we can visit the results of multiple dataflow analyses simultaneously. -/// DO NOT IMPLEMENT MANUALLY. Instead, use the `impl_visitable` macro below. -pub trait ResultsVisitable<'tcx> { - type Direction: Direction; - type FlowState; - - /// Creates an empty `FlowState` to hold the transient state for these dataflow results. - /// - /// The value of the newly created `FlowState` will be overwritten by `reset_to_block_entry` - /// before it can be observed by a `ResultsVisitor`. - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState; - - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock); - - fn reconstruct_before_statement_effect( - &self, - state: &mut Self::FlowState, - statement: &mir::Statement<'tcx>, - location: Location, - ); - - fn reconstruct_statement_effect( - &self, - state: &mut Self::FlowState, - statement: &mir::Statement<'tcx>, - location: Location, - ); - - fn reconstruct_before_terminator_effect( - &self, - state: &mut Self::FlowState, - terminator: &mir::Terminator<'tcx>, - location: Location, - ); - - fn reconstruct_terminator_effect( - &self, - state: &mut Self::FlowState, - terminator: &mir::Terminator<'tcx>, - location: Location, - ); -} - -impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> -where - A: Analysis<'tcx>, -{ - type FlowState = A::Domain; - - type Direction = A::Direction; - - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { - self.analysis.bottom_value(body) - } - - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { - state.clone_from(&self.entry_set_for_block(block)); - } - - fn reconstruct_before_statement_effect( - &self, - state: &mut Self::FlowState, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - self.analysis.apply_before_statement_effect(state, stmt, loc); - } - - fn reconstruct_statement_effect( - &self, - state: &mut Self::FlowState, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - self.analysis.apply_statement_effect(state, stmt, loc); - } - - fn reconstruct_before_terminator_effect( - &self, - state: &mut Self::FlowState, - term: &mir::Terminator<'tcx>, - loc: Location, - ) { - self.analysis.apply_before_terminator_effect(state, term, loc); - } - - fn reconstruct_terminator_effect( - &self, - state: &mut Self::FlowState, - term: &mir::Terminator<'tcx>, - loc: Location, - ) { - self.analysis.apply_terminator_effect(state, term, loc); - } -} - -/// A tuple with named fields that can hold either the results or the transient state of the -/// dataflow analyses used by the borrow checker. -#[derive(Debug)] -pub struct BorrowckAnalyses { - pub borrows: B, - pub uninits: U, - pub ever_inits: E, -} - -/// The results of the dataflow analyses used by the borrow checker. -pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses< - Results<'tcx, Borrows<'mir, 'tcx>>, - Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, - Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>, ->; - -/// The transient state of the dataflow analyses used by the borrow checker. -pub type BorrowckFlowState<'mir, 'tcx> = - as ResultsVisitable<'tcx>>::FlowState; - -macro_rules! impl_visitable { - ( $( - $T:ident { $( $field:ident : $A:ident ),* $(,)? } - )* ) => { $( - impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*> - where - $( $A: Analysis<'tcx, Direction = D>, )* - { - type Direction = D; - type FlowState = $T<$( $A::Domain ),*>; - - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { - $T { - $( $field: self.$field.analysis.bottom_value(body) ),* - } - } - - fn reset_to_block_entry( - &self, - state: &mut Self::FlowState, - block: BasicBlock, - ) { - $( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )* - } - - fn reconstruct_before_statement_effect( - &self, - state: &mut Self::FlowState, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - $( self.$field.analysis - .apply_before_statement_effect(&mut state.$field, stmt, loc); )* - } - - fn reconstruct_statement_effect( - &self, - state: &mut Self::FlowState, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - $( self.$field.analysis - .apply_statement_effect(&mut state.$field, stmt, loc); )* - } - - fn reconstruct_before_terminator_effect( - &self, - state: &mut Self::FlowState, - term: &mir::Terminator<'tcx>, - loc: Location, - ) { - $( self.$field.analysis - .apply_before_terminator_effect(&mut state.$field, term, loc); )* - } - - fn reconstruct_terminator_effect( - &self, - state: &mut Self::FlowState, - term: &mir::Terminator<'tcx>, - loc: Location, - ) { - $( self.$field.analysis - .apply_terminator_effect(&mut state.$field, term, loc); )* - } - } - )* } -} - -impl_visitable! { - BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,273 +0,0 @@ -pub use super::*; - -use crate::dataflow::{AnalysisDomain, GenKill, GenKillAnalysis}; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::*; -use rustc_middle::ty::{ParamEnv, TyCtxt}; -use rustc_span::DUMMY_SP; - -pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals>; - -/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points -/// to a given local. -/// -/// The `K` parameter determines what kind of borrows are tracked. By default, -/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows -/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead. -/// -/// At present, this is used as a very limited form of alias analysis. For example, -/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for -/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a -/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a -/// function call or inline assembly. -pub struct MaybeBorrowedLocals { - kind: K, - ignore_borrow_on_drop: bool, -} - -impl MaybeBorrowedLocals { - /// A dataflow analysis that records whether a pointer or reference exists that may alias the - /// given local. - pub fn all_borrows() -> Self { - MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false } - } -} - -impl MaybeMutBorrowedLocals<'mir, 'tcx> { - /// A dataflow analysis that records whether a pointer or reference exists that may *mutably* - /// alias the given local. - /// - /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of - /// types with interior mutability. - pub fn mut_borrows_only( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Self { - MaybeBorrowedLocals { - kind: MutBorrow { body, tcx, param_env }, - ignore_borrow_on_drop: false, - } - } -} - -impl MaybeBorrowedLocals { - /// During dataflow analysis, ignore the borrow that may occur when a place is dropped. - /// - /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a - /// parameter. In the general case, a drop impl could launder that reference into the - /// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the - /// dropped local. We are not yet willing to declare this particular case UB, so we must treat - /// all dropped locals as mutably borrowed for now. See discussion on [#61069]. - /// - /// In some contexts, we know that this borrow will never occur. For example, during - /// const-eval, custom drop glue cannot be run. Code that calls this should document the - /// assumptions that justify ignoring `Drop` terminators in this way. - /// - /// [#61069]: https://github.com/rust-lang/rust/pull/61069 - pub fn unsound_ignore_borrow_on_drop(self) -> Self { - MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self } - } - - fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> { - TransferFunction { - kind: &self.kind, - trans, - ignore_borrow_on_drop: self.ignore_borrow_on_drop, - } - } -} - -impl AnalysisDomain<'tcx> for MaybeBorrowedLocals -where - K: BorrowAnalysisKind<'tcx>, -{ - type Domain = BitSet; - const NAME: &'static str = K::ANALYSIS_NAME; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - // bottom = unborrowed - BitSet::new_empty(body.local_decls().len()) - } - - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { - // No locals are aliased on function entry - } -} - -impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals -where - K: BorrowAnalysisKind<'tcx>, -{ - type Idx = Local; - - fn statement_effect( - &self, - trans: &mut impl GenKill, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.transfer_function(trans).visit_statement(statement, location); - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - self.transfer_function(trans).visit_terminator(terminator, location); - } - - fn call_return_effect( - &self, - _trans: &mut impl GenKill, - _block: mir::BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - _dest_place: mir::Place<'tcx>, - ) { - } -} - -/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. -struct TransferFunction<'a, T, K> { - trans: &'a mut T, - kind: &'a K, - ignore_borrow_on_drop: bool, -} - -impl Visitor<'tcx> for TransferFunction<'a, T, K> -where - T: GenKill, - K: BorrowAnalysisKind<'tcx>, -{ - fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) { - self.super_statement(stmt, location); - - // When we reach a `StorageDead` statement, we can assume that any pointers to this memory - // are now invalid. - if let StatementKind::StorageDead(local) = stmt.kind { - self.trans.kill(local); - } - } - - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - - match rvalue { - mir::Rvalue::AddressOf(mt, borrowed_place) => { - if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) { - self.trans.gen(borrowed_place.local); - } - } - - mir::Rvalue::Ref(_, kind, borrowed_place) => { - if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) { - self.trans.gen(borrowed_place.local); - } - } - - mir::Rvalue::Cast(..) - | mir::Rvalue::Use(..) - | mir::Rvalue::ThreadLocalRef(..) - | mir::Rvalue::Repeat(..) - | mir::Rvalue::Len(..) - | mir::Rvalue::BinaryOp(..) - | mir::Rvalue::CheckedBinaryOp(..) - | mir::Rvalue::NullaryOp(..) - | mir::Rvalue::UnaryOp(..) - | mir::Rvalue::Discriminant(..) - | mir::Rvalue::Aggregate(..) => {} - } - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); - - match terminator.kind { - mir::TerminatorKind::Drop { place: dropped_place, .. } - | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => { - // See documentation for `unsound_ignore_borrow_on_drop` for an explanation. - if !self.ignore_borrow_on_drop { - self.trans.gen(dropped_place.local); - } - } - - TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::InlineAsm { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } => {} - } - } -} - -pub struct AnyBorrow; - -pub struct MutBorrow<'mir, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, - param_env: ParamEnv<'tcx>, -} - -impl MutBorrow<'mir, 'tcx> { - /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`. - /// - /// This assumes that it is UB to take the address of a struct field whose type is - /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of - /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will - /// have to check the type of the borrowed **local** instead of the borrowed **place** - /// below. See [rust-lang/unsafe-code-guidelines#134]. - /// - /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 - fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool { - !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) - } -} - -pub trait BorrowAnalysisKind<'tcx> { - const ANALYSIS_NAME: &'static str; - - fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool; - fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool; -} - -impl BorrowAnalysisKind<'tcx> for AnyBorrow { - const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals"; - - fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool { - true - } - fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool { - true - } -} - -impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> { - const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals"; - - fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool { - match kind { - mir::BorrowKind::Mut { .. } => true, - mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => { - self.shared_borrow_allows_mutation(place) - } - } - } - - fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool { - match mt { - Mutability::Mut => true, - Mutability::Not => self.shared_borrow_allows_mutation(place), - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/borrows.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/borrows.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/borrows.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/borrows.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,355 +0,0 @@ -use rustc_middle::mir::{self, Body, Location, Place}; -use rustc_middle::ty::RegionVid; -use rustc_middle::ty::TyCtxt; - -use rustc_data_structures::fx::FxHashMap; -use rustc_index::bit_set::BitSet; - -use crate::borrow_check::{ - places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, -}; -use crate::dataflow::{self, fmt::DebugWithContext, GenKill}; - -use std::fmt; -use std::iter; - -rustc_index::newtype_index! { - pub struct BorrowIndex { - DEBUG_FORMAT = "bw{}" - } -} - -/// `Borrows` stores the data used in the analyses that track the flow -/// of borrows. -/// -/// It uniquely identifies every borrow (`Rvalue::Ref`) by a -/// `BorrowIndex`, and maps each such index to a `BorrowData` -/// describing the borrow. These indexes are used for representing the -/// borrows in compact bitvectors. -pub struct Borrows<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - - borrow_set: &'a BorrowSet<'tcx>, - borrows_out_of_scope_at_location: FxHashMap>, -} - -struct StackEntry { - bb: mir::BasicBlock, - lo: usize, - hi: usize, -} - -struct OutOfScopePrecomputer<'a, 'tcx> { - visited: BitSet, - visit_stack: Vec, - body: &'a Body<'tcx>, - regioncx: &'a RegionInferenceContext<'tcx>, - borrows_out_of_scope_at_location: FxHashMap>, -} - -impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> { - fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self { - OutOfScopePrecomputer { - visited: BitSet::new_empty(body.basic_blocks().len()), - visit_stack: vec![], - body, - regioncx, - borrows_out_of_scope_at_location: FxHashMap::default(), - } - } -} - -impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { - fn precompute_borrows_out_of_scope( - &mut self, - borrow_index: BorrowIndex, - borrow_region: RegionVid, - location: Location, - ) { - // We visit one BB at a time. The complication is that we may start in the - // middle of the first BB visited (the one containing `location`), in which - // case we may have to later on process the first part of that BB if there - // is a path back to its start. - - // For visited BBs, we record the index of the first statement processed. - // (In fully processed BBs this index is 0.) Note also that we add BBs to - // `visited` once they are added to `stack`, before they are actually - // processed, because this avoids the need to look them up again on - // completion. - self.visited.insert(location.block); - - let mut first_lo = location.statement_index; - let first_hi = self.body[location.block].statements.len(); - - self.visit_stack.push(StackEntry { bb: location.block, lo: first_lo, hi: first_hi }); - - while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() { - // If we process the first part of the first basic block (i.e. we encounter that block - // for the second time), we no longer have to visit its successors again. - let mut finished_early = bb == location.block && hi != first_hi; - for i in lo..=hi { - let location = Location { block: bb, statement_index: i }; - // If region does not contain a point at the location, then add to list and skip - // successor locations. - if !self.regioncx.region_contains(borrow_region, location) { - debug!("borrow {:?} gets killed at {:?}", borrow_index, location); - self.borrows_out_of_scope_at_location - .entry(location) - .or_default() - .push(borrow_index); - finished_early = true; - break; - } - } - - if !finished_early { - // Add successor BBs to the work list, if necessary. - let bb_data = &self.body[bb]; - debug_assert!(hi == bb_data.statements.len()); - for &succ_bb in bb_data.terminator().successors() { - if self.visited.insert(succ_bb) == false { - if succ_bb == location.block && first_lo > 0 { - // `succ_bb` has been seen before. If it wasn't - // fully processed, add its first part to `stack` - // for processing. - self.visit_stack.push(StackEntry { - bb: succ_bb, - lo: 0, - hi: first_lo - 1, - }); - - // And update this entry with 0, to represent the - // whole BB being processed. - first_lo = 0; - } - } else { - // succ_bb hasn't been seen before. Add it to - // `stack` for processing. - self.visit_stack.push(StackEntry { - bb: succ_bb, - lo: 0, - hi: self.body[succ_bb].statements.len(), - }); - } - } - } - } - - self.visited.clear(); - } -} - -impl<'a, 'tcx> Borrows<'a, 'tcx> { - crate fn new( - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - nonlexical_regioncx: &'a RegionInferenceContext<'tcx>, - borrow_set: &'a BorrowSet<'tcx>, - ) -> Self { - let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx); - for (borrow_index, borrow_data) in borrow_set.iter_enumerated() { - let borrow_region = borrow_data.region.to_region_vid(); - let location = borrow_data.reserve_location; - - prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location); - } - - Borrows { - tcx, - body, - borrow_set, - borrows_out_of_scope_at_location: prec.borrows_out_of_scope_at_location, - } - } - - pub fn location(&self, idx: BorrowIndex) -> &Location { - &self.borrow_set[idx].reserve_location - } - - /// Add all borrows to the kill set, if those borrows are out of scope at `location`. - /// That means they went out of a nonlexical scope - fn kill_loans_out_of_scope_at_location( - &self, - trans: &mut impl GenKill, - location: Location, - ) { - // NOTE: The state associated with a given `location` - // reflects the dataflow on entry to the statement. - // Iterate over each of the borrows that we've precomputed - // to have went out of scope at this location and kill them. - // - // We are careful always to call this function *before* we - // set up the gen-bits for the statement or - // terminator. That way, if the effect of the statement or - // terminator *does* introduce a new loan of the same - // region, then setting that gen-bit will override any - // potential kill introduced here. - if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { - trans.kill_all(indices.iter().copied()); - } - } - - /// Kill any borrows that conflict with `place`. - fn kill_borrows_on_place(&self, trans: &mut impl GenKill, place: Place<'tcx>) { - debug!("kill_borrows_on_place: place={:?}", place); - - let other_borrows_of_local = self - .borrow_set - .local_map - .get(&place.local) - .into_iter() - .flat_map(|bs| bs.iter()) - .copied(); - - // If the borrowed place is a local with no projections, all other borrows of this - // local must conflict. This is purely an optimization so we don't have to call - // `places_conflict` for every borrow. - if place.projection.is_empty() { - if !self.body.local_decls[place.local].is_ref_to_static() { - trans.kill_all(other_borrows_of_local); - } - return; - } - - // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given - // pair of array indices are unequal, so that when `places_conflict` returns true, we - // will be assured that two places being compared definitely denotes the same sets of - // locations. - let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { - places_conflict( - self.tcx, - self.body, - self.borrow_set[i].borrowed_place, - place, - PlaceConflictBias::NoOverlap, - ) - }); - - trans.kill_all(definitely_conflicting_borrows); - } -} - -impl<'tcx> dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { - type Domain = BitSet; - - const NAME: &'static str = "borrows"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = nothing is reserved or activated yet; - BitSet::new_empty(self.borrow_set.len() * 2) - } - - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { - // no borrows of code region_scopes have been taken prior to - // function execution, so this method has no effect. - } -} - -impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { - type Idx = BorrowIndex; - - fn before_statement_effect( - &self, - trans: &mut impl GenKill, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.kill_loans_out_of_scope_at_location(trans, location); - } - - fn statement_effect( - &self, - trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, - location: Location, - ) { - match stmt.kind { - mir::StatementKind::Assign(box (lhs, ref rhs)) => { - if let mir::Rvalue::Ref(_, _, place) = *rhs { - if place.ignore_borrow( - self.tcx, - self.body, - &self.borrow_set.locals_state_at_exit, - ) { - return; - } - let index = self.borrow_set.get_index_of(&location).unwrap_or_else(|| { - panic!("could not find BorrowIndex for location {:?}", location); - }); - - trans.gen(index); - } - - // Make sure there are no remaining borrows for variables - // that are assigned over. - self.kill_borrows_on_place(trans, lhs); - } - - mir::StatementKind::StorageDead(local) => { - // Make sure there are no remaining borrows for locals that - // are gone out of scope. - self.kill_borrows_on_place(trans, Place::from(local)); - } - - mir::StatementKind::LlvmInlineAsm(ref asm) => { - for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) { - if !kind.is_indirect && !kind.is_rw { - self.kill_borrows_on_place(trans, *output); - } - } - } - - mir::StatementKind::FakeRead(..) - | mir::StatementKind::SetDiscriminant { .. } - | mir::StatementKind::StorageLive(..) - | mir::StatementKind::Retag { .. } - | mir::StatementKind::AscribeUserType(..) - | mir::StatementKind::Coverage(..) - | mir::StatementKind::CopyNonOverlapping(..) - | mir::StatementKind::Nop => {} - } - } - - fn before_terminator_effect( - &self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - self.kill_loans_out_of_scope_at_location(trans, location); - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - teminator: &mir::Terminator<'tcx>, - _location: Location, - ) { - if let mir::TerminatorKind::InlineAsm { operands, .. } = &teminator.kind { - for op in operands { - if let mir::InlineAsmOperand::Out { place: Some(place), .. } - | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op - { - self.kill_borrows_on_place(trans, place); - } - } - } - } - - fn call_return_effect( - &self, - _trans: &mut impl GenKill, - _block: mir::BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - _dest_place: mir::Place<'tcx>, - ) { - } -} - -impl DebugWithContext> for BorrowIndex { - fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", ctxt.location(*self)) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/init_locals.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/init_locals.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/init_locals.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/init_locals.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -//! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals. -//! -//! A local will be maybe initialized if *any* projections of that local might be initialized. - -use crate::dataflow::{self, GenKill}; - -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{self, BasicBlock, Local, Location}; - -pub struct MaybeInitializedLocals; - -impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { - type Domain = BitSet; - - const NAME: &'static str = "maybe_init_locals"; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - // bottom = uninit - BitSet::new_empty(body.local_decls.len()) - } - - fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut Self::Domain) { - // Function arguments are initialized to begin with. - for arg in body.args_iter() { - entry_set.insert(arg); - } - } -} - -impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals { - type Idx = Local; - - fn statement_effect( - &self, - trans: &mut impl GenKill, - statement: &mir::Statement<'tcx>, - loc: Location, - ) { - TransferFunction { trans }.visit_statement(statement, loc) - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, - loc: Location, - ) { - TransferFunction { trans }.visit_terminator(terminator, loc) - } - - fn call_return_effect( - &self, - trans: &mut impl GenKill, - _block: BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, - ) { - trans.gen(return_place.local) - } - - /// See `Analysis::apply_yield_resume_effect`. - fn yield_resume_effect( - &self, - trans: &mut impl GenKill, - _resume_block: BasicBlock, - resume_place: mir::Place<'tcx>, - ) { - trans.gen(resume_place.local) - } -} - -struct TransferFunction<'a, T> { - trans: &'a mut T, -} - -impl Visitor<'tcx> for TransferFunction<'a, T> -where - T: GenKill, -{ - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { - use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext}; - match context { - // These are handled specially in `call_return_effect` and `yield_resume_effect`. - PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {} - - // Otherwise, when a place is mutated, we must consider it possibly initialized. - PlaceContext::MutatingUse(_) => self.trans.gen(local), - - // If the local is moved out of, or if it gets marked `StorageDead`, consider it no - // longer initialized. - PlaceContext::NonUse(NonUseContext::StorageDead) - | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => self.trans.kill(local), - - // All other uses do not affect this analysis. - PlaceContext::NonUse( - NonUseContext::StorageLive - | NonUseContext::AscribeUserTy - | NonUseContext::VarDebugInfo, - ) - | PlaceContext::NonMutatingUse( - NonMutatingUseContext::Inspect - | NonMutatingUseContext::Copy - | NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::UniqueBorrow - | NonMutatingUseContext::AddressOf - | NonMutatingUseContext::Projection, - ) => {} - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/liveness.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/liveness.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/liveness.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/liveness.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, Local, Location}; - -use crate::dataflow::{AnalysisDomain, Backward, GenKill, GenKillAnalysis}; - -/// A [live-variable dataflow analysis][liveness]. -/// -/// This analysis considers references as being used only at the point of the -/// borrow. In other words, this analysis does not track uses because of references that already -/// exist. See [this `mir-dataflow` test][flow-test] for an example. You almost never want to use -/// this analysis without also looking at the results of [`MaybeBorrowedLocals`]. -/// -/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals -/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs -/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis -pub struct MaybeLiveLocals; - -impl MaybeLiveLocals { - fn transfer_function(&self, trans: &'a mut T) -> TransferFunction<'a, T> { - TransferFunction(trans) - } -} - -impl AnalysisDomain<'tcx> for MaybeLiveLocals { - type Domain = BitSet; - type Direction = Backward; - - const NAME: &'static str = "liveness"; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - // bottom = not live - BitSet::new_empty(body.local_decls.len()) - } - - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { - // No variables are live until we observe a use - } -} - -impl GenKillAnalysis<'tcx> for MaybeLiveLocals { - type Idx = Local; - - fn statement_effect( - &self, - trans: &mut impl GenKill, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.transfer_function(trans).visit_statement(statement, location); - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - self.transfer_function(trans).visit_terminator(terminator, location); - } - - fn call_return_effect( - &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - dest_place: mir::Place<'tcx>, - ) { - if let Some(local) = dest_place.as_local() { - trans.kill(local); - } - } - - fn yield_resume_effect( - &self, - trans: &mut impl GenKill, - _resume_block: mir::BasicBlock, - resume_place: mir::Place<'tcx>, - ) { - if let Some(local) = resume_place.as_local() { - trans.kill(local); - } - } -} - -struct TransferFunction<'a, T>(&'a mut T); - -impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T> -where - T: GenKill, -{ - fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { - let mir::Place { projection, local } = *place; - - // We purposefully do not call `super_place` here to avoid calling `visit_local` for this - // place with one of the `Projection` variants of `PlaceContext`. - self.visit_projection(place.as_ref(), context, location); - - match DefUse::for_place(context) { - // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use. - Some(_) if place.is_indirect() => self.0.gen(local), - - Some(DefUse::Def) if projection.is_empty() => self.0.kill(local), - Some(DefUse::Use) => self.0.gen(local), - _ => {} - } - } - - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { - // Because we do not call `super_place` above, `visit_local` is only called for locals that - // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use - // of the return place in a `Return` terminator or the index in an `Index` projection. - match DefUse::for_place(context) { - Some(DefUse::Def) => self.0.kill(local), - Some(DefUse::Use) => self.0.gen(local), - _ => {} - } - } -} - -#[derive(Eq, PartialEq, Clone)] -enum DefUse { - Def, - Use, -} - -impl DefUse { - fn for_place(context: PlaceContext) -> Option { - match context { - PlaceContext::NonUse(_) => None, - - PlaceContext::MutatingUse(MutatingUseContext::Store) => Some(DefUse::Def), - - // `MutatingUseContext::Call` and `MutatingUseContext::Yield` indicate that this is the - // destination place for a `Call` return or `Yield` resume respectively. Since this is - // only a `Def` when the function returns successfully, we handle this case separately - // in `call_return_effect` above. - PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => None, - - // All other contexts are uses... - PlaceContext::MutatingUse( - MutatingUseContext::AddressOf - | MutatingUseContext::AsmOutput - | MutatingUseContext::Borrow - | MutatingUseContext::Drop - | MutatingUseContext::Retag, - ) - | PlaceContext::NonMutatingUse( - NonMutatingUseContext::AddressOf - | NonMutatingUseContext::Copy - | NonMutatingUseContext::Inspect - | NonMutatingUseContext::Move - | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::UniqueBorrow, - ) => Some(DefUse::Use), - - PlaceContext::MutatingUse(MutatingUseContext::Projection) - | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => { - unreachable!("A projection could be a def or a use and must be handled separately") - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,717 +0,0 @@ -//! Dataflow analyses are built upon some interpretation of the -//! bitvectors attached to each basic block, represented via a -//! zero-sized structure. - -use rustc_index::bit_set::BitSet; -use rustc_index::vec::Idx; -use rustc_middle::mir::{self, Body, Location}; -use rustc_middle::ty::{self, TyCtxt}; - -use super::MoveDataParamEnv; - -use crate::util::elaborate_drops::DropFlagState; - -use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex}; -use super::{lattice, AnalysisDomain, GenKill, GenKillAnalysis}; - -use super::drop_flag_effects_for_function_entry; -use super::drop_flag_effects_for_location; -use super::on_lookup_result_bits; -use crate::dataflow::drop_flag_effects; -use crate::dataflow::framework::SwitchIntEdgeEffects; - -mod borrowed_locals; -pub(super) mod borrows; -mod init_locals; -mod liveness; -mod storage_liveness; - -pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; -pub use self::borrows::Borrows; -pub use self::init_locals::MaybeInitializedLocals; -pub use self::liveness::MaybeLiveLocals; -pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; - -/// `MaybeInitializedPlaces` tracks all places that might be -/// initialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // maybe-init: -/// // {} -/// let a = S; let b = S; let c; let d; // {a, b} -/// -/// if pred { -/// drop(a); // { b} -/// b = S; // { b} -/// -/// } else { -/// drop(b); // {a} -/// d = S; // {a, d} -/// -/// } // {a, b, d} -/// -/// c = S; // {a, b, c, d} -/// } -/// ``` -/// -/// To determine whether a place *must* be initialized at a -/// particular control-flow point, one can take the set-difference -/// between this data and the data from `MaybeUninitializedPlaces` at the -/// corresponding control-flow point. -/// -/// Similarly, at a given `drop` statement, the set-intersection -/// between this data and `MaybeUninitializedPlaces` yields the set of -/// places that would require a dynamic drop-flag at that statement. -pub struct MaybeInitializedPlaces<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, -} - -impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - MaybeInitializedPlaces { tcx, body, mdpe } - } -} - -impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { - &self.mdpe.move_data - } -} - -/// `MaybeUninitializedPlaces` tracks all places that might be -/// uninitialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // maybe-uninit: -/// // {a, b, c, d} -/// let a = S; let b = S; let c; let d; // { c, d} -/// -/// if pred { -/// drop(a); // {a, c, d} -/// b = S; // {a, c, d} -/// -/// } else { -/// drop(b); // { b, c, d} -/// d = S; // { b, c } -/// -/// } // {a, b, c, d} -/// -/// c = S; // {a, b, d} -/// } -/// ``` -/// -/// To determine whether a place *must* be uninitialized at a -/// particular control-flow point, one can take the set-difference -/// between this data and the data from `MaybeInitializedPlaces` at the -/// corresponding control-flow point. -/// -/// Similarly, at a given `drop` statement, the set-intersection -/// between this data and `MaybeInitializedPlaces` yields the set of -/// places that would require a dynamic drop-flag at that statement. -pub struct MaybeUninitializedPlaces<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, - - mark_inactive_variants_as_uninit: bool, -} - -impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit: false } - } - - /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an - /// enum discriminant. - /// - /// This is correct in a vacuum but is not the default because it causes problems in the borrow - /// checker, where this information gets propagated along `FakeEdge`s. - pub fn mark_inactive_variants_as_uninit(mut self) -> Self { - self.mark_inactive_variants_as_uninit = true; - self - } -} - -impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { - &self.mdpe.move_data - } -} - -/// `DefinitelyInitializedPlaces` tracks all places that are definitely -/// initialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // definite-init: -/// // { } -/// let a = S; let b = S; let c; let d; // {a, b } -/// -/// if pred { -/// drop(a); // { b, } -/// b = S; // { b, } -/// -/// } else { -/// drop(b); // {a, } -/// d = S; // {a, d} -/// -/// } // { } -/// -/// c = S; // { c } -/// } -/// ``` -/// -/// To determine whether a place *may* be uninitialized at a -/// particular control-flow point, one can take the set-complement -/// of this data. -/// -/// Similarly, at a given `drop` statement, the set-difference between -/// this data and `MaybeInitializedPlaces` yields the set of places -/// that would require a dynamic drop-flag at that statement. -pub struct DefinitelyInitializedPlaces<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, -} - -impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - DefinitelyInitializedPlaces { tcx, body, mdpe } - } -} - -impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { - &self.mdpe.move_data - } -} - -/// `EverInitializedPlaces` tracks all places that might have ever been -/// initialized upon reaching a particular point in the control flow -/// for a function, without an intervening `StorageDead`. -/// -/// This dataflow is used to determine if an immutable local variable may -/// be assigned to. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // ever-init: -/// // { } -/// let a = S; let b = S; let c; let d; // {a, b } -/// -/// if pred { -/// drop(a); // {a, b, } -/// b = S; // {a, b, } -/// -/// } else { -/// drop(b); // {a, b, } -/// d = S; // {a, b, d } -/// -/// } // {a, b, d } -/// -/// c = S; // {a, b, c, d } -/// } -/// ``` -pub struct EverInitializedPlaces<'a, 'tcx> { - #[allow(dead_code)] - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, -} - -impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - EverInitializedPlaces { tcx, body, mdpe } - } -} - -impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { - &self.mdpe.move_data - } -} - -impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { - fn update_bits( - trans: &mut impl GenKill, - path: MovePathIndex, - state: DropFlagState, - ) { - match state { - DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen(path), - } - } -} - -impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { - fn update_bits( - trans: &mut impl GenKill, - path: MovePathIndex, - state: DropFlagState, - ) { - match state { - DropFlagState::Absent => trans.gen(path), - DropFlagState::Present => trans.kill(path), - } - } -} - -impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { - fn update_bits( - trans: &mut impl GenKill, - path: MovePathIndex, - state: DropFlagState, - ) { - match state { - DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen(path), - } - } -} - -impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Domain = BitSet; - const NAME: &'static str = "maybe_init"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = uninitialized - BitSet::new_empty(self.move_data().move_paths.len()) - } - - fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { - drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { - assert!(s == DropFlagState::Present); - state.insert(path); - }); - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn statement_effect( - &self, - trans: &mut impl GenKill, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn call_return_effect( - &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - dest_place: mir::Place<'tcx>, - ) { - // when a call returns successfully, that means we need to set - // the bits for that dest_place to 1 (initialized). - on_lookup_result_bits( - self.tcx, - self.body, - self.move_data(), - self.move_data().rev_lookup.find(dest_place.as_ref()), - |mpi| { - trans.gen(mpi); - }, - ); - } - - fn switch_int_edge_effects>( - &self, - block: mir::BasicBlock, - discr: &mir::Operand<'tcx>, - edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { - return; - } - - let enum_ = discr.place().and_then(|discr| { - switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) - }); - - let (enum_place, enum_def) = match enum_ { - Some(x) => x, - None => return, - }; - - let mut discriminants = enum_def.discriminants(self.tcx); - edge_effects.apply(|trans, edge| { - let value = match edge.value { - Some(x) => x, - None => return, - }; - - // MIR building adds discriminants to the `values` array in the same order as they - // are yielded by `AdtDef::discriminants`. We rely on this to match each - // discriminant in `values` to its corresponding variant in linear time. - let (variant, _) = discriminants - .find(|&(_, discr)| discr.val == value) - .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); - - // Kill all move paths that correspond to variants we know to be inactive along this - // particular outgoing edge of a `SwitchInt`. - drop_flag_effects::on_all_inactive_variants( - self.tcx, - self.body, - self.move_data(), - enum_place, - variant, - |mpi| trans.kill(mpi), - ); - }); - } -} - -impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { - type Domain = BitSet; - - const NAME: &'static str = "maybe_uninit"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = initialized (start_block_effect counters this at outset) - BitSet::new_empty(self.move_data().move_paths.len()) - } - - // sets on_entry bits for Arg places - fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { - // set all bits to 1 (uninit) before gathering counterevidence - state.insert_all(); - - drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { - assert!(s == DropFlagState::Present); - state.remove(path); - }); - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn statement_effect( - &self, - trans: &mut impl GenKill, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn call_return_effect( - &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - dest_place: mir::Place<'tcx>, - ) { - // when a call returns successfully, that means we need to set - // the bits for that dest_place to 0 (initialized). - on_lookup_result_bits( - self.tcx, - self.body, - self.move_data(), - self.move_data().rev_lookup.find(dest_place.as_ref()), - |mpi| { - trans.kill(mpi); - }, - ); - } - - fn switch_int_edge_effects>( - &self, - block: mir::BasicBlock, - discr: &mir::Operand<'tcx>, - edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { - return; - } - - if !self.mark_inactive_variants_as_uninit { - return; - } - - let enum_ = discr.place().and_then(|discr| { - switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) - }); - - let (enum_place, enum_def) = match enum_ { - Some(x) => x, - None => return, - }; - - let mut discriminants = enum_def.discriminants(self.tcx); - edge_effects.apply(|trans, edge| { - let value = match edge.value { - Some(x) => x, - None => return, - }; - - // MIR building adds discriminants to the `values` array in the same order as they - // are yielded by `AdtDef::discriminants`. We rely on this to match each - // discriminant in `values` to its corresponding variant in linear time. - let (variant, _) = discriminants - .find(|&(_, discr)| discr.val == value) - .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); - - // Mark all move paths that correspond to variants other than this one as maybe - // uninitialized (in reality, they are *definitely* uninitialized). - drop_flag_effects::on_all_inactive_variants( - self.tcx, - self.body, - self.move_data(), - enum_place, - variant, - |mpi| trans.gen(mpi), - ); - }); - } -} - -impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { - /// Use set intersection as the join operator. - type Domain = lattice::Dual>; - - const NAME: &'static str = "definite_init"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = initialized (start_block_effect counters this at outset) - lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len())) - } - - // sets on_entry bits for Arg places - fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { - state.0.clear(); - - drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { - assert!(s == DropFlagState::Present); - state.0.insert(path); - }); - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn statement_effect( - &self, - trans: &mut impl GenKill, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn call_return_effect( - &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - dest_place: mir::Place<'tcx>, - ) { - // when a call returns successfully, that means we need to set - // the bits for that dest_place to 1 (initialized). - on_lookup_result_bits( - self.tcx, - self.body, - self.move_data(), - self.move_data().rev_lookup.find(dest_place.as_ref()), - |mpi| { - trans.gen(mpi); - }, - ); - } -} - -impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { - type Domain = BitSet; - - const NAME: &'static str = "ever_init"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = no initialized variables by default - BitSet::new_empty(self.move_data().inits.len()) - } - - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { - for arg_init in 0..body.arg_count { - state.insert(InitIndex::new(arg_init)); - } - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { - type Idx = InitIndex; - - fn statement_effect( - &self, - trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, - location: Location, - ) { - let move_data = self.move_data(); - let init_path_map = &move_data.init_path_map; - let init_loc_map = &move_data.init_loc_map; - let rev_lookup = &move_data.rev_lookup; - - debug!( - "statement {:?} at loc {:?} initializes move_indexes {:?}", - stmt, location, &init_loc_map[location] - ); - trans.gen_all(init_loc_map[location].iter().copied()); - - if let mir::StatementKind::StorageDead(local) = stmt.kind { - // End inits for StorageDead, so that an immutable variable can - // be reinitialized on the next iteration of the loop. - let move_path_index = rev_lookup.find_local(local); - debug!( - "stmt {:?} at loc {:?} clears the ever initialized status of {:?}", - stmt, location, &init_path_map[move_path_index] - ); - trans.kill_all(init_path_map[move_path_index].iter().copied()); - } - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - let (body, move_data) = (self.body, self.move_data()); - let term = body[location.block].terminator(); - let init_loc_map = &move_data.init_loc_map; - debug!( - "terminator {:?} at loc {:?} initializes move_indexes {:?}", - term, location, &init_loc_map[location] - ); - trans.gen_all( - init_loc_map[location] - .iter() - .filter(|init_index| { - move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly - }) - .copied(), - ); - } - - fn call_return_effect( - &self, - trans: &mut impl GenKill, - block: mir::BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - _dest_place: mir::Place<'tcx>, - ) { - let move_data = self.move_data(); - let init_loc_map = &move_data.init_loc_map; - - let call_loc = self.body.terminator_loc(block); - for init_index in &init_loc_map[call_loc] { - trans.gen(*init_index); - } - } -} - -/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is -/// an enum discriminant. -/// -/// We expect such blocks to have a call to `discriminant` as their last statement like so: -/// -/// ```text -/// ... -/// _42 = discriminant(_1) -/// SwitchInt(_42, ..) -/// ``` -/// -/// If the basic block matches this pattern, this function returns the place corresponding to the -/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. -fn switch_on_enum_discriminant( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - block: &'mir mir::BasicBlockData<'tcx>, - switch_on: mir::Place<'tcx>, -) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> { - match block.statements.last().map(|stmt| &stmt.kind) { - Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))) - if *lhs == switch_on => - { - match &discriminated.ty(body, tcx).ty.kind() { - ty::Adt(def, _) => Some((*discriminated, def)), - - // `Rvalue::Discriminant` is also used to get the active yield point for a - // generator, but we do not need edge-specific effects in that case. This may - // change in the future. - ty::Generator(..) => None, - - t => bug!("`discriminant` called on unexpected type {:?}", t), - } - } - - _ => None, - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,307 +0,0 @@ -pub use super::*; - -use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; -use crate::util::storage::AlwaysLiveLocals; -use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use std::cell::RefCell; - -#[derive(Clone)] -pub struct MaybeStorageLive { - always_live_locals: AlwaysLiveLocals, -} - -impl MaybeStorageLive { - pub fn new(always_live_locals: AlwaysLiveLocals) -> Self { - MaybeStorageLive { always_live_locals } - } -} - -impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive { - type Domain = BitSet; - - const NAME: &'static str = "maybe_storage_live"; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - // bottom = dead - BitSet::new_empty(body.local_decls.len()) - } - - fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { - assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size()); - for local in self.always_live_locals.iter() { - on_entry.insert(local); - } - - for arg in body.args_iter() { - on_entry.insert(arg); - } - } -} - -impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive { - type Idx = Local; - - fn statement_effect( - &self, - trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, - _: Location, - ) { - match stmt.kind { - StatementKind::StorageLive(l) => trans.gen(l), - StatementKind::StorageDead(l) => trans.kill(l), - _ => (), - } - } - - fn terminator_effect( - &self, - _trans: &mut impl GenKill, - _: &mir::Terminator<'tcx>, - _: Location, - ) { - // Terminators have no effect - } - - fn call_return_effect( - &self, - _trans: &mut impl GenKill, - _block: BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - _return_place: mir::Place<'tcx>, - ) { - // Nothing to do when a call returns successfully - } -} - -type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; - -/// Dataflow analysis that determines whether each local requires storage at a -/// given location; i.e. whether its storage can go away without being observed. -pub struct MaybeRequiresStorage<'mir, 'tcx> { - body: &'mir Body<'tcx>, - borrowed_locals: RefCell>, -} - -impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { - pub fn new( - body: &'mir Body<'tcx>, - borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>, - ) -> Self { - MaybeRequiresStorage { - body, - borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)), - } - } -} - -impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { - type Domain = BitSet; - - const NAME: &'static str = "requires_storage"; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - // bottom = dead - BitSet::new_empty(body.local_decls.len()) - } - - fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { - // The resume argument is live on function entry (we don't care about - // the `self` argument) - for arg in body.args_iter().skip(1) { - on_entry.insert(arg); - } - } -} - -impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { - type Idx = Local; - - fn before_statement_effect( - &self, - trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - // If a place is borrowed in a statement, it needs storage for that statement. - self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc); - - match &stmt.kind { - StatementKind::StorageDead(l) => trans.kill(*l), - - // If a place is assigned to in a statement, it needs storage for that statement. - StatementKind::Assign(box (place, _)) - | StatementKind::SetDiscriminant { box place, .. } => { - trans.gen(place.local); - } - StatementKind::LlvmInlineAsm(asm) => { - for place in &*asm.outputs { - trans.gen(place.local); - } - } - - // Nothing to do for these. Match exhaustively so this fails to compile when new - // variants are added. - StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::FakeRead(..) - | StatementKind::Nop - | StatementKind::Retag(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::StorageLive(..) => {} - } - } - - fn statement_effect( - &self, - trans: &mut impl GenKill, - _: &mir::Statement<'tcx>, - loc: Location, - ) { - // If we move from a place then only stops needing storage *after* - // that statement. - self.check_for_move(trans, loc); - } - - fn before_terminator_effect( - &self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, - loc: Location, - ) { - // If a place is borrowed in a terminator, it needs storage for that terminator. - self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc); - - match &terminator.kind { - TerminatorKind::Call { destination: Some((place, _)), .. } => { - trans.gen(place.local); - } - - // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for - // that is that a `yield` will return from the function, and `resume_arg` is written - // only when the generator is later resumed. Unlike `Call`, this doesn't require the - // place to have storage *before* the yield, only after. - TerminatorKind::Yield { .. } => {} - - TerminatorKind::InlineAsm { operands, .. } => { - for op in operands { - match op { - InlineAsmOperand::Out { place, .. } - | InlineAsmOperand::InOut { out_place: place, .. } => { - if let Some(place) = place { - trans.gen(place.local); - } - } - InlineAsmOperand::In { .. } - | InlineAsmOperand::Const { .. } - | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } => {} - } - } - } - - // Nothing to do for these. Match exhaustively so this fails to compile when new - // variants are added. - TerminatorKind::Call { destination: None, .. } - | TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} - } - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, - loc: Location, - ) { - match &terminator.kind { - // For call terminators the destination requires storage for the call - // and after the call returns successfully, but not after a panic. - // Since `propagate_call_unwind` doesn't exist, we have to kill the - // destination here, and then gen it again in `call_return_effect`. - TerminatorKind::Call { destination: Some((place, _)), .. } => { - trans.kill(place.local); - } - - // Nothing to do for these. Match exhaustively so this fails to compile when new - // variants are added. - TerminatorKind::Call { destination: None, .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::InlineAsm { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} - } - - self.check_for_move(trans, loc); - } - - fn call_return_effect( - &self, - trans: &mut impl GenKill, - _block: BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, - ) { - trans.gen(return_place.local); - } - - fn yield_resume_effect( - &self, - trans: &mut impl GenKill, - _resume_block: BasicBlock, - resume_place: mir::Place<'tcx>, - ) { - trans.gen(resume_place.local); - } -} - -impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { - /// Kill locals that are fully moved and have not been borrowed. - fn check_for_move(&self, trans: &mut impl GenKill, loc: Location) { - let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals }; - visitor.visit_location(&self.body, loc); - } -} - -struct MoveVisitor<'a, 'mir, 'tcx, T> { - borrowed_locals: &'a RefCell>, - trans: &'a mut T, -} - -impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> -where - T: GenKill, -{ - fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { - if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { - let mut borrowed_locals = self.borrowed_locals.borrow_mut(); - borrowed_locals.seek_before_primary_effect(loc); - if !borrowed_locals.contains(*local) { - self.trans.kill(*local); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -use rustc_ast::{self as ast, MetaItem}; -use rustc_middle::ty; -use rustc_session::Session; -use rustc_span::symbol::{sym, Symbol}; - -pub(crate) use self::drop_flag_effects::*; -pub use self::framework::{ - fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState, - BorrowckResults, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, - ResultsCursor, ResultsRefCursor, ResultsVisitor, SwitchIntEdgeEffects, -}; - -use self::move_paths::MoveData; - -pub mod drop_flag_effects; -mod framework; -pub mod impls; -pub mod move_paths; - -pub(crate) mod indexes { - pub(crate) use super::{ - impls::borrows::BorrowIndex, - move_paths::{InitIndex, MoveOutIndex, MovePathIndex}, - }; -} - -pub struct MoveDataParamEnv<'tcx> { - pub(crate) move_data: MoveData<'tcx>, - pub(crate) param_env: ty::ParamEnv<'tcx>, -} - -pub(crate) fn has_rustc_mir_with( - _sess: &Session, - attrs: &[ast::Attribute], - name: Symbol, -) -> Option { - for attr in attrs { - if attr.has_name(sym::rustc_mir) { - let items = attr.meta_item_list(); - for item in items.iter().flat_map(|l| l.iter()) { - match item.meta_item() { - Some(mi) if mi.has_name(name) => return Some(mi.clone()), - _ => continue, - } - } - } - } - None -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -//! The move-analysis portion of borrowck needs to work in an abstract -//! domain of lifted `Place`s. Most of the `Place` variants fall into a -//! one-to-one mapping between the concrete and abstract (e.g., a -//! field-deref on a local variable, `x.field`, has the same meaning -//! in both domains). Indexed projections are the exception: `a[x]` -//! needs to be treated as mapping to the same move path as `a[y]` as -//! well as `a[13]`, etc. -//! -//! (In theory, the analysis could be extended to work with sets of -//! paths, so that `a[0]` and `a[13]` could be kept distinct, while -//! `a[x]` would still overlap them both. But that is not this -//! representation does today.) - -use rustc_middle::mir::{Local, Operand, PlaceElem, ProjectionElem}; -use rustc_middle::ty::Ty; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct AbstractOperand; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct AbstractType; -pub type AbstractElem = ProjectionElem; - -pub trait Lift { - type Abstract; - fn lift(&self) -> Self::Abstract; -} -impl<'tcx> Lift for Operand<'tcx> { - type Abstract = AbstractOperand; - fn lift(&self) -> Self::Abstract { - AbstractOperand - } -} -impl Lift for Local { - type Abstract = AbstractOperand; - fn lift(&self) -> Self::Abstract { - AbstractOperand - } -} -impl<'tcx> Lift for Ty<'tcx> { - type Abstract = AbstractType; - fn lift(&self) -> Self::Abstract { - AbstractType - } -} -impl<'tcx> Lift for PlaceElem<'tcx> { - type Abstract = AbstractElem; - fn lift(&self) -> Self::Abstract { - match *self { - ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()), - ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } - } - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - ProjectionElem::ConstantIndex { offset, min_length, from_end } - } - ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u), - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/builder.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/builder.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/builder.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/builder.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,543 +0,0 @@ -use rustc_index::vec::IndexVec; -use rustc_middle::mir::tcx::RvalueInitializationState; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; -use smallvec::{smallvec, SmallVec}; - -use std::iter; -use std::mem; - -use super::abs_domain::Lift; -use super::IllegalMoveOriginKind::*; -use super::{Init, InitIndex, InitKind, InitLocation, LookupResult, MoveError}; -use super::{ - LocationMap, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup, -}; - -struct MoveDataBuilder<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - data: MoveData<'tcx>, - errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, -} - -impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { - fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { - let mut move_paths = IndexVec::new(); - let mut path_map = IndexVec::new(); - let mut init_path_map = IndexVec::new(); - - MoveDataBuilder { - body, - tcx, - param_env, - errors: Vec::new(), - data: MoveData { - moves: IndexVec::new(), - loc_map: LocationMap::new(body), - rev_lookup: MovePathLookup { - locals: body - .local_decls - .indices() - .map(|i| { - Self::new_move_path( - &mut move_paths, - &mut path_map, - &mut init_path_map, - None, - Place::from(i), - ) - }) - .collect(), - projections: Default::default(), - }, - move_paths, - path_map, - inits: IndexVec::new(), - init_loc_map: LocationMap::new(body), - init_path_map, - }, - } - } - - fn new_move_path( - move_paths: &mut IndexVec>, - path_map: &mut IndexVec>, - init_path_map: &mut IndexVec>, - parent: Option, - place: Place<'tcx>, - ) -> MovePathIndex { - let move_path = - move_paths.push(MovePath { next_sibling: None, first_child: None, parent, place }); - - if let Some(parent) = parent { - let next_sibling = mem::replace(&mut move_paths[parent].first_child, Some(move_path)); - move_paths[move_path].next_sibling = next_sibling; - } - - let path_map_ent = path_map.push(smallvec![]); - assert_eq!(path_map_ent, move_path); - - let init_path_map_ent = init_path_map.push(smallvec![]); - assert_eq!(init_path_map_ent, move_path); - - move_path - } -} - -impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { - /// This creates a MovePath for a given place, returning an `MovePathError` - /// if that place can't be moved from. - /// - /// NOTE: places behind references *do not* get a move path, which is - /// problematic for borrowck. - /// - /// Maybe we should have separate "borrowck" and "moveck" modes. - fn move_path_for(&mut self, place: Place<'tcx>) -> Result> { - debug!("lookup({:?})", place); - let mut base = self.builder.data.rev_lookup.locals[place.local]; - - // The move path index of the first union that we find. Once this is - // some we stop creating child move paths, since moves from unions - // move the whole thing. - // We continue looking for other move errors though so that moving - // from `*(u.f: &_)` isn't allowed. - let mut union_path = None; - - for (i, elem) in place.projection.iter().enumerate() { - let proj_base = &place.projection[..i]; - let body = self.builder.body; - let tcx = self.builder.tcx; - let place_ty = Place::ty_from(place.local, proj_base, body, tcx).ty; - match place_ty.kind() { - ty::Ref(..) | ty::RawPtr(..) => { - let proj = &place.projection[..i + 1]; - return Err(MoveError::cannot_move_out_of( - self.loc, - BorrowedContent { - target_place: Place { - local: place.local, - projection: tcx.intern_place_elems(proj), - }, - }, - )); - } - ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => { - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfTypeWithDestructor { container_ty: place_ty }, - )); - } - ty::Adt(adt, _) if adt.is_union() => { - union_path.get_or_insert(base); - } - ty::Slice(_) => { - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfSliceOrArray { - ty: place_ty, - is_index: matches!(elem, ProjectionElem::Index(..)), - }, - )); - } - - ty::Array(..) => { - if let ProjectionElem::Index(..) = elem { - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfSliceOrArray { ty: place_ty, is_index: true }, - )); - } - } - - _ => {} - }; - - if union_path.is_none() { - base = self.add_move_path(base, elem, |tcx| Place { - local: place.local, - projection: tcx.intern_place_elems(&place.projection[..i + 1]), - }); - } - } - - if let Some(base) = union_path { - // Move out of union - always move the entire union. - Err(MoveError::UnionMove { path: base }) - } else { - Ok(base) - } - } - - fn add_move_path( - &mut self, - base: MovePathIndex, - elem: PlaceElem<'tcx>, - mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>, - ) -> MovePathIndex { - let MoveDataBuilder { - data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. }, - tcx, - .. - } = self.builder; - *rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || { - MoveDataBuilder::new_move_path( - move_paths, - path_map, - init_path_map, - Some(base), - mk_place(*tcx), - ) - }) - } - - fn create_move_path(&mut self, place: Place<'tcx>) { - // This is an non-moving access (such as an overwrite or - // drop), so this not being a valid move path is OK. - let _ = self.move_path_for(place); - } -} - -impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { - fn finalize( - self, - ) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { - debug!("{}", { - debug!("moves for {:?}:", self.body.span); - for (j, mo) in self.data.moves.iter_enumerated() { - debug!(" {:?} = {:?}", j, mo); - } - debug!("move paths for {:?}:", self.body.span); - for (j, path) in self.data.move_paths.iter_enumerated() { - debug!(" {:?} = {:?}", j, path); - } - "done dumping moves" - }); - - if !self.errors.is_empty() { Err((self.data, self.errors)) } else { Ok(self.data) } - } -} - -pub(super) fn gather_moves<'tcx>( - body: &Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { - let mut builder = MoveDataBuilder::new(body, tcx, param_env); - - builder.gather_args(); - - for (bb, block) in body.basic_blocks().iter_enumerated() { - for (i, stmt) in block.statements.iter().enumerate() { - let source = Location { block: bb, statement_index: i }; - builder.gather_statement(source, stmt); - } - - let terminator_loc = Location { block: bb, statement_index: block.statements.len() }; - builder.gather_terminator(terminator_loc, block.terminator()); - } - - builder.finalize() -} - -impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { - fn gather_args(&mut self) { - for arg in self.body.args_iter() { - let path = self.data.rev_lookup.locals[arg]; - - let init = self.data.inits.push(Init { - path, - kind: InitKind::Deep, - location: InitLocation::Argument(arg), - }); - - debug!("gather_args: adding init {:?} of {:?} for argument {:?}", init, path, arg); - - self.data.init_path_map[path].push(init); - } - } - - fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { - debug!("gather_statement({:?}, {:?})", loc, stmt); - (Gatherer { builder: self, loc }).gather_statement(stmt); - } - - fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) { - debug!("gather_terminator({:?}, {:?})", loc, term); - (Gatherer { builder: self, loc }).gather_terminator(term); - } -} - -struct Gatherer<'b, 'a, 'tcx> { - builder: &'b mut MoveDataBuilder<'a, 'tcx>, - loc: Location, -} - -impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { - fn gather_statement(&mut self, stmt: &Statement<'tcx>) { - match &stmt.kind { - StatementKind::Assign(box (place, rval)) => { - self.create_move_path(*place); - if let RvalueInitializationState::Shallow = rval.initialization_state() { - // Box starts out uninitialized - need to create a separate - // move-path for the interior so it will be separate from - // the exterior. - self.create_move_path(self.builder.tcx.mk_place_deref(*place)); - self.gather_init(place.as_ref(), InitKind::Shallow); - } else { - self.gather_init(place.as_ref(), InitKind::Deep); - } - self.gather_rvalue(rval); - } - StatementKind::FakeRead(box (_, place)) => { - self.create_move_path(*place); - } - StatementKind::LlvmInlineAsm(ref asm) => { - for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) { - if !kind.is_indirect { - self.gather_init(output.as_ref(), InitKind::Deep); - } - } - for (_, input) in asm.inputs.iter() { - self.gather_operand(input); - } - } - StatementKind::StorageLive(_) => {} - StatementKind::StorageDead(local) => { - self.gather_move(Place::from(*local)); - } - StatementKind::SetDiscriminant { .. } => { - span_bug!( - stmt.source_info.span, - "SetDiscriminant should not exist during borrowck" - ); - } - StatementKind::Retag { .. } - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Nop => {} - } - } - - fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { - match *rvalue { - Rvalue::ThreadLocalRef(_) => {} // not-a-move - Rvalue::Use(ref operand) - | Rvalue::Repeat(ref operand, _) - | Rvalue::Cast(_, ref operand, _) - | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), - Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) - | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => { - self.gather_operand(lhs); - self.gather_operand(rhs); - } - Rvalue::Aggregate(ref _kind, ref operands) => { - for operand in operands { - self.gather_operand(operand); - } - } - Rvalue::Ref(..) - | Rvalue::AddressOf(..) - | Rvalue::Discriminant(..) - | Rvalue::Len(..) - | Rvalue::NullaryOp(NullOp::SizeOf, _) - | Rvalue::NullaryOp(NullOp::Box, _) => { - // This returns an rvalue with uninitialized contents. We can't - // move out of it here because it is an rvalue - assignments always - // completely initialize their place. - // - // However, this does not matter - MIR building is careful to - // only emit a shallow free for the partially-initialized - // temporary. - // - // In any case, if we want to fix this, we have to register a - // special move and change the `statement_effect` functions. - } - } - } - - fn gather_terminator(&mut self, term: &Terminator<'tcx>) { - match term.kind { - TerminatorKind::Goto { target: _ } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - // In some sense returning moves the return place into the current - // call's destination, however, since there are no statements after - // this that could possibly access the return place, this doesn't - // need recording. - | TerminatorKind::Return - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::GeneratorDrop - | TerminatorKind::Unreachable => {} - - TerminatorKind::Assert { ref cond, .. } => { - self.gather_operand(cond); - } - - TerminatorKind::SwitchInt { ref discr, .. } => { - self.gather_operand(discr); - } - - TerminatorKind::Yield { ref value, resume_arg: place, .. } => { - self.gather_operand(value); - self.create_move_path(place); - self.gather_init(place.as_ref(), InitKind::Deep); - } - - TerminatorKind::Drop { place, target: _, unwind: _ } => { - self.gather_move(place); - } - TerminatorKind::DropAndReplace { place, ref value, .. } => { - self.create_move_path(place); - self.gather_operand(value); - self.gather_init(place.as_ref(), InitKind::Deep); - } - TerminatorKind::Call { - ref func, - ref args, - ref destination, - cleanup: _, - from_hir_call: _, - fn_span: _, - } => { - self.gather_operand(func); - for arg in args { - self.gather_operand(arg); - } - if let Some((destination, _bb)) = *destination { - self.create_move_path(destination); - self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly); - } - } - TerminatorKind::InlineAsm { - template: _, - ref operands, - options: _, - line_spans: _, - destination: _, - } => { - for op in operands { - match *op { - InlineAsmOperand::In { reg: _, ref value } - => { - self.gather_operand(value); - } - InlineAsmOperand::Out { reg: _, late: _, place, .. } => { - if let Some(place) = place { - self.create_move_path(place); - self.gather_init(place.as_ref(), InitKind::Deep); - } - } - InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { - self.gather_operand(in_value); - if let Some(out_place) = out_place { - self.create_move_path(out_place); - self.gather_init(out_place.as_ref(), InitKind::Deep); - } - } - InlineAsmOperand::Const { value: _ } - | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } => {} - } - } - } - } - } - - fn gather_operand(&mut self, operand: &Operand<'tcx>) { - match *operand { - Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move - Operand::Move(place) => { - // a move - self.gather_move(place); - } - } - } - - fn gather_move(&mut self, place: Place<'tcx>) { - debug!("gather_move({:?}, {:?})", self.loc, place); - - if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] = - **place.projection - { - // Split `Subslice` patterns into the corresponding list of - // `ConstIndex` patterns. This is done to ensure that all move paths - // are disjoint, which is expected by drop elaboration. - let base_place = - Place { local: place.local, projection: self.builder.tcx.intern_place_elems(base) }; - let base_path = match self.move_path_for(base_place) { - Ok(path) => path, - Err(MoveError::UnionMove { path }) => { - self.record_move(place, path); - return; - } - Err(error @ MoveError::IllegalMove { .. }) => { - self.builder.errors.push((base_place, error)); - return; - } - }; - let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; - let len: u64 = match base_ty.kind() { - ty::Array(_, size) => size.eval_usize(self.builder.tcx, self.builder.param_env), - _ => bug!("from_end: false slice pattern of non-array type"), - }; - for offset in from..to { - let elem = - ProjectionElem::ConstantIndex { offset, min_length: len, from_end: false }; - let path = - self.add_move_path(base_path, elem, |tcx| tcx.mk_place_elem(base_place, elem)); - self.record_move(place, path); - } - } else { - match self.move_path_for(place) { - Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path), - Err(error @ MoveError::IllegalMove { .. }) => { - self.builder.errors.push((place, error)); - } - }; - } - } - - fn record_move(&mut self, place: Place<'tcx>, path: MovePathIndex) { - let move_out = self.builder.data.moves.push(MoveOut { path, source: self.loc }); - debug!( - "gather_move({:?}, {:?}): adding move {:?} of {:?}", - self.loc, place, move_out, path - ); - self.builder.data.path_map[path].push(move_out); - self.builder.data.loc_map[self.loc].push(move_out); - } - - fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) { - debug!("gather_init({:?}, {:?})", self.loc, place); - - let mut place = place; - - // Check if we are assigning into a field of a union, if so, lookup the place - // of the union so it is marked as initialized again. - if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() { - if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() { - place = place_base; - } - } - - if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) { - let init = self.builder.data.inits.push(Init { - location: InitLocation::Statement(self.loc), - path, - kind, - }); - - debug!( - "gather_init({:?}, {:?}): adding init {:?} of {:?}", - self.loc, place, init, path - ); - - self.builder.data.init_path_map[path].push(init); - self.builder.data.init_loc_map[self.loc].push(init); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/dataflow/move_paths/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,414 +0,0 @@ -use core::slice::Iter; -use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::{Enumerated, IndexVec}; -use rustc_middle::mir::*; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; -use rustc_span::Span; -use smallvec::SmallVec; - -use std::fmt; -use std::ops::{Index, IndexMut}; - -use self::abs_domain::{AbstractElem, Lift}; - -mod abs_domain; - -rustc_index::newtype_index! { - pub struct MovePathIndex { - DEBUG_FORMAT = "mp{}" - } -} - -rustc_index::newtype_index! { - pub struct MoveOutIndex { - DEBUG_FORMAT = "mo{}" - } -} - -rustc_index::newtype_index! { - pub struct InitIndex { - DEBUG_FORMAT = "in{}" - } -} - -impl MoveOutIndex { - pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex { - move_data.moves[*self].path - } -} - -/// `MovePath` is a canonicalized representation of a path that is -/// moved or assigned to. -/// -/// It follows a tree structure. -/// -/// Given `struct X { m: M, n: N }` and `x: X`, moves like `drop x.m;` -/// move *out* of the place `x.m`. -/// -/// The MovePaths representing `x.m` and `x.n` are siblings (that is, -/// one of them will link to the other via the `next_sibling` field, -/// and the other will have no entry in its `next_sibling` field), and -/// they both have the MovePath representing `x` as their parent. -#[derive(Clone)] -pub struct MovePath<'tcx> { - pub next_sibling: Option, - pub first_child: Option, - pub parent: Option, - pub place: Place<'tcx>, -} - -impl<'tcx> MovePath<'tcx> { - /// Returns an iterator over the parents of `self`. - pub fn parents<'a>( - &self, - move_paths: &'a IndexVec>, - ) -> impl 'a + Iterator)> { - let first = self.parent.map(|mpi| (mpi, &move_paths[mpi])); - MovePathLinearIter { - next: first, - fetch_next: move |_, parent: &MovePath<'_>| { - parent.parent.map(|mpi| (mpi, &move_paths[mpi])) - }, - } - } - - /// Returns an iterator over the immediate children of `self`. - pub fn children<'a>( - &self, - move_paths: &'a IndexVec>, - ) -> impl 'a + Iterator)> { - let first = self.first_child.map(|mpi| (mpi, &move_paths[mpi])); - MovePathLinearIter { - next: first, - fetch_next: move |_, child: &MovePath<'_>| { - child.next_sibling.map(|mpi| (mpi, &move_paths[mpi])) - }, - } - } - - /// Finds the closest descendant of `self` for which `f` returns `true` using a breadth-first - /// search. - /// - /// `f` will **not** be called on `self`. - pub fn find_descendant( - &self, - move_paths: &IndexVec>, - f: impl Fn(MovePathIndex) -> bool, - ) -> Option { - let mut todo = if let Some(child) = self.first_child { - vec![child] - } else { - return None; - }; - - while let Some(mpi) = todo.pop() { - if f(mpi) { - return Some(mpi); - } - - let move_path = &move_paths[mpi]; - if let Some(child) = move_path.first_child { - todo.push(child); - } - - // After we've processed the original `mpi`, we should always - // traverse the siblings of any of its children. - if let Some(sibling) = move_path.next_sibling { - todo.push(sibling); - } - } - - None - } -} - -impl<'tcx> fmt::Debug for MovePath<'tcx> { - fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(w, "MovePath {{")?; - if let Some(parent) = self.parent { - write!(w, " parent: {:?},", parent)?; - } - if let Some(first_child) = self.first_child { - write!(w, " first_child: {:?},", first_child)?; - } - if let Some(next_sibling) = self.next_sibling { - write!(w, " next_sibling: {:?}", next_sibling)?; - } - write!(w, " place: {:?} }}", self.place) - } -} - -impl<'tcx> fmt::Display for MovePath<'tcx> { - fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(w, "{:?}", self.place) - } -} - -struct MovePathLinearIter<'a, 'tcx, F> { - next: Option<(MovePathIndex, &'a MovePath<'tcx>)>, - fetch_next: F, -} - -impl<'a, 'tcx, F> Iterator for MovePathLinearIter<'a, 'tcx, F> -where - F: FnMut(MovePathIndex, &'a MovePath<'tcx>) -> Option<(MovePathIndex, &'a MovePath<'tcx>)>, -{ - type Item = (MovePathIndex, &'a MovePath<'tcx>); - - fn next(&mut self) -> Option { - let ret = self.next.take()?; - self.next = (self.fetch_next)(ret.0, ret.1); - Some(ret) - } -} - -#[derive(Debug)] -pub struct MoveData<'tcx> { - pub move_paths: IndexVec>, - pub moves: IndexVec, - /// Each Location `l` is mapped to the MoveOut's that are effects - /// of executing the code at `l`. (There can be multiple MoveOut's - /// for a given `l` because each MoveOut is associated with one - /// particular path being moved.) - pub loc_map: LocationMap>, - pub path_map: IndexVec>, - pub rev_lookup: MovePathLookup, - pub inits: IndexVec, - /// Each Location `l` is mapped to the Inits that are effects - /// of executing the code at `l`. - pub init_loc_map: LocationMap>, - pub init_path_map: IndexVec>, -} - -pub trait HasMoveData<'tcx> { - fn move_data(&self) -> &MoveData<'tcx>; -} - -#[derive(Debug)] -pub struct LocationMap { - /// Location-indexed (BasicBlock for outer index, index within BB - /// for inner index) map. - pub(crate) map: IndexVec>, -} - -impl Index for LocationMap { - type Output = T; - fn index(&self, index: Location) -> &Self::Output { - &self.map[index.block][index.statement_index] - } -} - -impl IndexMut for LocationMap { - fn index_mut(&mut self, index: Location) -> &mut Self::Output { - &mut self.map[index.block][index.statement_index] - } -} - -impl LocationMap -where - T: Default + Clone, -{ - fn new(body: &Body<'_>) -> Self { - LocationMap { - map: body - .basic_blocks() - .iter() - .map(|block| vec![T::default(); block.statements.len() + 1]) - .collect(), - } - } -} - -/// `MoveOut` represents a point in a program that moves out of some -/// L-value; i.e., "creates" uninitialized memory. -/// -/// With respect to dataflow analysis: -/// - Generated by moves and declaration of uninitialized variables. -/// - Killed by assignments to the memory. -#[derive(Copy, Clone)] -pub struct MoveOut { - /// path being moved - pub path: MovePathIndex, - /// location of move - pub source: Location, -} - -impl fmt::Debug for MoveOut { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{:?}@{:?}", self.path, self.source) - } -} - -/// `Init` represents a point in a program that initializes some L-value; -#[derive(Copy, Clone)] -pub struct Init { - /// path being initialized - pub path: MovePathIndex, - /// location of initialization - pub location: InitLocation, - /// Extra information about this initialization - pub kind: InitKind, -} - -/// Initializations can be from an argument or from a statement. Arguments -/// do not have locations, in those cases the `Local` is kept.. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum InitLocation { - Argument(Local), - Statement(Location), -} - -/// Additional information about the initialization. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum InitKind { - /// Deep init, even on panic - Deep, - /// Only does a shallow init - Shallow, - /// This doesn't initialize the variable on panic (and a panic is possible). - NonPanicPathOnly, -} - -impl fmt::Debug for Init { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{:?}@{:?} ({:?})", self.path, self.location, self.kind) - } -} - -impl Init { - crate fn span<'tcx>(&self, body: &Body<'tcx>) -> Span { - match self.location { - InitLocation::Argument(local) => body.local_decls[local].source_info.span, - InitLocation::Statement(location) => body.source_info(location).span, - } - } -} - -/// Tables mapping from a place to its MovePathIndex. -#[derive(Debug)] -pub struct MovePathLookup { - locals: IndexVec, - - /// projections are made from a base-place and a projection - /// elem. The base-place will have a unique MovePathIndex; we use - /// the latter as the index into the outer vector (narrowing - /// subsequent search so that it is solely relative to that - /// base-place). For the remaining lookup, we map the projection - /// elem to the associated MovePathIndex. - projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>, -} - -mod builder; - -#[derive(Copy, Clone, Debug)] -pub enum LookupResult { - Exact(MovePathIndex), - Parent(Option), -} - -impl MovePathLookup { - // Unlike the builder `fn move_path_for` below, this lookup - // alternative will *not* create a MovePath on the fly for an - // unknown place, but will rather return the nearest available - // parent. - pub fn find(&self, place: PlaceRef<'_>) -> LookupResult { - let mut result = self.locals[place.local]; - - for elem in place.projection.iter() { - if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { - result = subpath; - } else { - return LookupResult::Parent(Some(result)); - } - } - - LookupResult::Exact(result) - } - - pub fn find_local(&self, local: Local) -> MovePathIndex { - self.locals[local] - } - - /// An enumerated iterator of `local`s and their associated - /// `MovePathIndex`es. - pub fn iter_locals_enumerated(&self) -> Enumerated> { - self.locals.iter_enumerated() - } -} - -#[derive(Debug)] -pub struct IllegalMoveOrigin<'tcx> { - pub(crate) location: Location, - pub(crate) kind: IllegalMoveOriginKind<'tcx>, -} - -#[derive(Debug)] -pub(crate) enum IllegalMoveOriginKind<'tcx> { - /// Illegal move due to attempt to move from behind a reference. - BorrowedContent { - /// The place the reference refers to: if erroneous code was trying to - /// move from `(*x).f` this will be `*x`. - target_place: Place<'tcx>, - }, - - /// Illegal move due to attempt to move from field of an ADT that - /// implements `Drop`. Rust maintains invariant that all `Drop` - /// ADT's remain fully-initialized so that user-defined destructor - /// can safely read from all of the ADT's fields. - InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> }, - - /// Illegal move due to attempt to move out of a slice or array. - InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool }, -} - -#[derive(Debug)] -pub enum MoveError<'tcx> { - IllegalMove { cannot_move_out_of: IllegalMoveOrigin<'tcx> }, - UnionMove { path: MovePathIndex }, -} - -impl<'tcx> MoveError<'tcx> { - fn cannot_move_out_of(location: Location, kind: IllegalMoveOriginKind<'tcx>) -> Self { - let origin = IllegalMoveOrigin { location, kind }; - MoveError::IllegalMove { cannot_move_out_of: origin } - } -} - -impl<'tcx> MoveData<'tcx> { - pub fn gather_moves( - body: &Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Result, MoveError<'tcx>)>)> { - builder::gather_moves(body, tcx, param_env) - } - - /// For the move path `mpi`, returns the root local variable (if any) that starts the path. - /// (e.g., for a path like `a.b.c` returns `Some(a)`) - pub fn base_local(&self, mut mpi: MovePathIndex) -> Option { - loop { - let path = &self.move_paths[mpi]; - if let Some(l) = path.place.as_local() { - return Some(l); - } - if let Some(parent) = path.parent { - mpi = parent; - continue; - } else { - return None; - } - } - } - - pub fn find_in_move_path_or_its_descendants( - &self, - root: MovePathIndex, - pred: impl Fn(MovePathIndex) -> bool, - ) -> Option { - if pred(root) { - return Some(root); - } - - self.move_paths[root].find_descendant(&self.move_paths, pred) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/cast.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/cast.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/cast.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/cast.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,365 +0,0 @@ -use std::convert::TryFrom; - -use rustc_apfloat::ieee::{Double, Single}; -use rustc_apfloat::{Float, FloatConvert}; -use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; -use rustc_middle::mir::CastKind; -use rustc_middle::ty::adjustment::PointerCast; -use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; -use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut}; -use rustc_target::abi::{Integer, LayoutOf, Variants}; - -use super::{ - util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, -}; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn cast( - &mut self, - src: &OpTy<'tcx, M::PointerTag>, - cast_kind: CastKind, - cast_ty: Ty<'tcx>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - use rustc_middle::mir::CastKind::*; - // FIXME: In which cases should we trigger UB when the source is uninit? - match cast_kind { - Pointer(PointerCast::Unsize) => { - let cast_ty = self.layout_of(cast_ty)?; - self.unsize_into(src, cast_ty, dest)?; - } - - Misc => { - let src = self.read_immediate(src)?; - let res = self.misc_cast(&src, cast_ty)?; - self.write_immediate(res, dest)?; - } - - Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer) => { - // These are NOPs, but can be wide pointers. - let v = self.read_immediate(src)?; - self.write_immediate(*v, dest)?; - } - - Pointer(PointerCast::ReifyFnPointer) => { - // The src operand does not matter, just its type - match *src.layout.ty.kind() { - ty::FnDef(def_id, substs) => { - // All reifications must be monomorphic, bail out otherwise. - ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; - - let instance = ty::Instance::resolve_for_fn_ptr( - *self.tcx, - self.param_env, - def_id, - substs, - ) - .ok_or_else(|| err_inval!(TooGeneric))?; - - let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); - self.write_pointer(fn_ptr, dest)?; - } - _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty), - } - } - - Pointer(PointerCast::UnsafeFnPointer) => { - let src = self.read_immediate(src)?; - match cast_ty.kind() { - ty::FnPtr(_) => { - // No change to value - self.write_immediate(*src, dest)?; - } - _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty), - } - } - - Pointer(PointerCast::ClosureFnPointer(_)) => { - // The src operand does not matter, just its type - match *src.layout.ty.kind() { - ty::Closure(def_id, substs) => { - // All reifications must be monomorphic, bail out otherwise. - ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; - - let instance = ty::Instance::resolve_closure( - *self.tcx, - def_id, - substs, - ty::ClosureKind::FnOnce, - ); - let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); - self.write_pointer(fn_ptr, dest)?; - } - _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), - } - } - } - Ok(()) - } - - fn misc_cast( - &self, - src: &ImmTy<'tcx, M::PointerTag>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { - use rustc_middle::ty::TyKind::*; - trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); - - match src.layout.ty.kind() { - // Floating point - Float(FloatTy::F32) => { - return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into()); - } - Float(FloatTy::F64) => { - return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into()); - } - // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that - // are represented as integers. - _ => assert!( - src.layout.ty.is_bool() - || src.layout.ty.is_char() - || src.layout.ty.is_enum() - || src.layout.ty.is_integral() - || src.layout.ty.is_any_ptr(), - "Unexpected cast from type {:?}", - src.layout.ty - ), - } - - // # First handle non-scalar source values. - - // Handle cast from a ZST enum (0 or 1 variants). - match src.layout.variants { - Variants::Single { index } => { - if src.layout.abi.is_uninhabited() { - // This is dead code, because an uninhabited enum is UB to - // instantiate. - throw_ub!(Unreachable); - } - if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) { - assert!(src.layout.is_zst()); - let discr_layout = self.layout_of(discr.ty)?; - return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into()); - } - } - Variants::Multiple { .. } => {} - } - - // Handle casting any ptr to raw ptr (might be a fat ptr). - if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() { - let dest_layout = self.layout_of(cast_ty)?; - if dest_layout.size == src.layout.size { - // Thin or fat pointer that just hast the ptr kind of target type changed. - return Ok(**src); - } else { - // Casting the metadata away from a fat ptr. - assert_eq!(src.layout.size, 2 * self.memory.pointer_size()); - assert_eq!(dest_layout.size, self.memory.pointer_size()); - assert!(src.layout.ty.is_unsafe_ptr()); - return match **src { - Immediate::ScalarPair(data, _) => Ok(data.into()), - Immediate::Scalar(..) => span_bug!( - self.cur_span(), - "{:?} input to a fat-to-thin cast ({:?} -> {:?})", - *src, - src.layout.ty, - cast_ty - ), - }; - } - } - - // # The remaining source values are scalar. - - // For all remaining casts, we either - // (a) cast a raw ptr to usize, or - // (b) cast from an integer-like (including bool, char, enums). - // In both cases we want the bits. - let bits = src.to_scalar()?.to_bits(src.layout.size)?; - Ok(self.cast_from_scalar(bits, src.layout, cast_ty).into()) - } - - pub(super) fn cast_from_scalar( - &self, - v: u128, // raw bits (there is no ScalarTy so we separate data+layout) - src_layout: TyAndLayout<'tcx>, - cast_ty: Ty<'tcx>, - ) -> Scalar { - // Let's make sure v is sign-extended *if* it has a signed type. - let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. - let v = if signed { self.sign_extend(v, src_layout) } else { v }; - trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty); - use rustc_middle::ty::TyKind::*; - match *cast_ty.kind() { - Int(_) | Uint(_) | RawPtr(_) => { - let size = match *cast_ty.kind() { - Int(t) => Integer::from_int_ty(self, t).size(), - Uint(t) => Integer::from_uint_ty(self, t).size(), - RawPtr(_) => self.pointer_size(), - _ => bug!(), - }; - let v = size.truncate(v); - Scalar::from_uint(v, size) - } - - Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value), - Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value), - Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value), - Float(FloatTy::F64) => Scalar::from_f64(Double::from_u128(v).value), - - Char => { - // `u8` to `char` cast - Scalar::from_u32(u8::try_from(v).unwrap().into()) - } - - // Casts to bool are not permitted by rustc, no need to handle them here. - _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty), - } - } - - fn cast_from_float(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar - where - F: Float + Into> + FloatConvert + FloatConvert, - { - use rustc_middle::ty::TyKind::*; - match *dest_ty.kind() { - // float -> uint - Uint(t) => { - let size = Integer::from_uint_ty(self, t).size(); - // `to_u128` is a saturating cast, which is what we need - // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). - let v = f.to_u128(size.bits_usize()).value; - // This should already fit the bit width - Scalar::from_uint(v, size) - } - // float -> int - Int(t) => { - let size = Integer::from_int_ty(self, t).size(); - // `to_i128` is a saturating cast, which is what we need - // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). - let v = f.to_i128(size.bits_usize()).value; - Scalar::from_int(v, size) - } - // float -> f32 - Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value), - // float -> f64 - Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value), - // That's it. - _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty), - } - } - - fn unsize_into_ptr( - &mut self, - src: &OpTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, - // The pointee types - source_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx> { - // A -> A conversion - let (src_pointee_ty, dest_pointee_ty) = - self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env); - - match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { - (&ty::Array(_, length), &ty::Slice(_)) => { - let ptr = self.read_immediate(src)?.to_scalar()?; - // u64 cast is from usize to u64, which is always good - let val = - Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self); - self.write_immediate(val, dest) - } - (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - let val = self.read_immediate(src)?; - if data_a.principal_def_id() == data_b.principal_def_id() { - return self.write_immediate(*val, dest); - } - // trait upcasting coercion - let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( - src_pointee_ty, - dest_pointee_ty, - )); - - if let Some(entry_idx) = vptr_entry_idx { - let entry_idx = u64::try_from(entry_idx).unwrap(); - let (old_data, old_vptr) = val.to_scalar_pair()?; - let old_vptr = self.scalar_to_ptr(old_vptr); - let new_vptr = self - .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?; - self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) - } else { - self.write_immediate(*val, dest) - } - } - (_, &ty::Dynamic(ref data, _)) => { - // Initial cast from sized to dyn trait - let vtable = self.get_vtable(src_pointee_ty, data.principal())?; - let ptr = self.read_immediate(src)?.to_scalar()?; - let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); - self.write_immediate(val, dest) - } - - _ => { - span_bug!(self.cur_span(), "invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty) - } - } - } - - fn unsize_into( - &mut self, - src: &OpTy<'tcx, M::PointerTag>, - cast_ty: TyAndLayout<'tcx>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty); - match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { - (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. })) - | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => { - self.unsize_into_ptr(src, dest, s, c) - } - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { - assert_eq!(def_a, def_b); - if def_a.is_box() || def_b.is_box() { - if !def_a.is_box() || !def_b.is_box() { - span_bug!( - self.cur_span(), - "invalid unsizing between {:?} -> {:?}", - src.layout.ty, - cast_ty.ty - ); - } - return self.unsize_into_ptr( - src, - dest, - src.layout.ty.boxed_ty(), - cast_ty.ty.boxed_ty(), - ); - } - - // unsizing of generic struct with pointer fields - // Example: `Arc` -> `Arc` - // here we need to increase the size of every &T thin ptr field to a fat ptr - for i in 0..src.layout.fields.count() { - let cast_ty_field = cast_ty.field(self, i); - if cast_ty_field.is_zst() { - continue; - } - let src_field = self.operand_field(src, i)?; - let dst_field = self.place_field(dest, i)?; - if src_field.layout.ty == cast_ty_field.ty { - self.copy_op(&src_field, &dst_field)?; - } else { - self.unsize_into(&src_field, cast_ty_field, &dst_field)?; - } - } - Ok(()) - } - _ => span_bug!( - self.cur_span(), - "unsize_into: invalid conversion: {:?} -> {:?}", - src.layout, - dest.layout - ), - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/eval_context.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/eval_context.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/eval_context.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/eval_context.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1042 +0,0 @@ -use std::cell::Cell; -use std::fmt; -use std::mem; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; -use rustc_index::vec::IndexVec; -use rustc_macros::HashStable; -use rustc_middle::ich::StableHashingContext; -use rustc_middle::mir; -use rustc_middle::ty::layout::{self, TyAndLayout}; -use rustc_middle::ty::{ - self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, -}; -use rustc_session::Limit; -use rustc_span::{Pos, Span}; -use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; - -use super::{ - AllocId, GlobalId, Immediate, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, - MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar, ScalarMaybeUninit, - StackPopJump, -}; -use crate::transform::validate::equal_up_to_regions; -use crate::util::storage::AlwaysLiveLocals; - -pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { - /// Stores the `Machine` instance. - /// - /// Note: the stack is provided by the machine. - pub machine: M, - - /// The results of the type checker, from rustc. - /// The span in this is the "root" of the evaluation, i.e., the const - /// we are evaluating (if this is CTFE). - pub tcx: TyCtxtAt<'tcx>, - - /// Bounds in scope for polymorphic evaluations. - pub(crate) param_env: ty::ParamEnv<'tcx>, - - /// The virtual memory system. - pub memory: Memory<'mir, 'tcx, M>, - - /// The recursion limit (cached from `tcx.recursion_limit(())`) - pub recursion_limit: Limit, -} - -// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread -// boundary and dropped in the other thread, it would exit the span in the other thread. -struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>); - -impl SpanGuard { - /// By default a `SpanGuard` does nothing. - fn new() -> Self { - Self(tracing::Span::none(), std::marker::PhantomData) - } - - /// If a span is entered, we exit the previous span (if any, normally none) and enter the - /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of - /// `Frame` by creating a dummy span to being with and then entering it once the frame has - /// been pushed. - fn enter(&mut self, span: tracing::Span) { - // This executes the destructor on the previous instance of `SpanGuard`, ensuring that - // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we - // can't protect the tracing stack, but that'll just lead to weird logging, no actual - // problems. - *self = Self(span, std::marker::PhantomData); - self.0.with_subscriber(|(id, dispatch)| { - dispatch.enter(id); - }); - } -} - -impl Drop for SpanGuard { - fn drop(&mut self) { - self.0.with_subscriber(|(id, dispatch)| { - dispatch.exit(id); - }); - } -} - -/// A stack frame. -pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { - //////////////////////////////////////////////////////////////////////////////// - // Function and callsite information - //////////////////////////////////////////////////////////////////////////////// - /// The MIR for the function called on this frame. - pub body: &'mir mir::Body<'tcx>, - - /// The def_id and substs of the current function. - pub instance: ty::Instance<'tcx>, - - /// Extra data for the machine. - pub extra: Extra, - - //////////////////////////////////////////////////////////////////////////////// - // Return place and locals - //////////////////////////////////////////////////////////////////////////////// - /// Work to perform when returning from this function. - pub return_to_block: StackPopCleanup, - - /// The location where the result of the current stack frame should be written to, - /// and its layout in the caller. - pub return_place: Option>, - - /// The list of locals for this stack frame, stored in order as - /// `[return_ptr, arguments..., variables..., temporaries...]`. - /// The locals are stored as `Option`s. - /// `None` represents a local that is currently dead, while a live local - /// can either directly contain `Scalar` or refer to some part of an `Allocation`. - pub locals: IndexVec>, - - /// The span of the `tracing` crate is stored here. - /// When the guard is dropped, the span is exited. This gives us - /// a full stack trace on all tracing statements. - tracing_span: SpanGuard, - - //////////////////////////////////////////////////////////////////////////////// - // Current position within the function - //////////////////////////////////////////////////////////////////////////////// - /// If this is `Err`, we are not currently executing any particular statement in - /// this frame (can happen e.g. during frame initialization, and during unwinding on - /// frames without cleanup code). - /// We basically abuse `Result` as `Either`. - pub(super) loc: Result, -} - -/// What we store about a frame in an interpreter backtrace. -#[derive(Debug)] -pub struct FrameInfo<'tcx> { - pub instance: ty::Instance<'tcx>, - pub span: Span, - pub lint_root: Option, -} - -/// Unwind information. -#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] -pub enum StackPopUnwind { - /// The cleanup block. - Cleanup(mir::BasicBlock), - /// No cleanup needs to be done. - Skip, - /// Unwinding is not allowed (UB). - NotAllowed, -} - -#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these -pub enum StackPopCleanup { - /// Jump to the next block in the caller, or cause UB if None (that's a function - /// that may never return). Also store layout of return place so - /// we can validate it at that layout. - /// `ret` stores the block we jump to on a normal return, while `unwind` - /// stores the block used for cleanup during unwinding. - Goto { ret: Option, unwind: StackPopUnwind }, - /// Just do nothing: Used by Main and for the `box_alloc` hook in miri. - /// `cleanup` says whether locals are deallocated. Static computation - /// wants them leaked to intern what they need (and just throw away - /// the entire `ecx` when it is done). - None { cleanup: bool }, -} - -/// State of a local variable including a memoized layout -#[derive(Clone, PartialEq, Eq, HashStable)] -pub struct LocalState<'tcx, Tag: Provenance = AllocId> { - pub value: LocalValue, - /// Don't modify if `Some`, this is only used to prevent computing the layout twice - #[stable_hasher(ignore)] - pub layout: Cell>>, -} - -/// Current value of a local variable -#[derive(Copy, Clone, PartialEq, Eq, HashStable, Debug)] // Miri debug-prints these -pub enum LocalValue { - /// This local is not currently alive, and cannot be used at all. - Dead, - /// This local is alive but not yet initialized. It can be written to - /// but not read from or its address taken. Locals get initialized on - /// first write because for unsized locals, we do not know their size - /// before that. - Uninitialized, - /// A normal, live local. - /// Mostly for convenience, we re-use the `Operand` type here. - /// This is an optimization over just always having a pointer here; - /// we can thus avoid doing an allocation when the local just stores - /// immediate values *and* never has its address taken. - Live(Operand), -} - -impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> { - /// Read the local's value or error if the local is not yet live or not live anymore. - /// - /// Note: This may only be invoked from the `Machine::access_local` hook and not from - /// anywhere else. You may be invalidating machine invariants if you do! - pub fn access(&self) -> InterpResult<'tcx, Operand> { - match self.value { - LocalValue::Dead => throw_ub!(DeadLocal), - LocalValue::Uninitialized => { - bug!("The type checker should prevent reading from a never-written local") - } - LocalValue::Live(val) => Ok(val), - } - } - - /// Overwrite the local. If the local can be overwritten in place, return a reference - /// to do so; otherwise return the `MemPlace` to consult instead. - /// - /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from - /// anywhere else. You may be invalidating machine invariants if you do! - pub fn access_mut( - &mut self, - ) -> InterpResult<'tcx, Result<&mut LocalValue, MemPlace>> { - match self.value { - LocalValue::Dead => throw_ub!(DeadLocal), - LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)), - ref mut - local @ (LocalValue::Live(Operand::Immediate(_)) | LocalValue::Uninitialized) => { - Ok(Ok(local)) - } - } - } -} - -impl<'mir, 'tcx, Tag: Provenance> Frame<'mir, 'tcx, Tag> { - pub fn with_extra(self, extra: Extra) -> Frame<'mir, 'tcx, Tag, Extra> { - Frame { - body: self.body, - instance: self.instance, - return_to_block: self.return_to_block, - return_place: self.return_place, - locals: self.locals, - loc: self.loc, - extra, - tracing_span: self.tracing_span, - } - } -} - -impl<'mir, 'tcx, Tag: Provenance, Extra> Frame<'mir, 'tcx, Tag, Extra> { - /// Get the current location within the Frame. - /// - /// If this is `Err`, we are not currently executing any particular statement in - /// this frame (can happen e.g. during frame initialization, and during unwinding on - /// frames without cleanup code). - /// We basically abuse `Result` as `Either`. - /// - /// Used by priroda. - pub fn current_loc(&self) -> Result { - self.loc - } - - /// Return the `SourceInfo` of the current instruction. - pub fn current_source_info(&self) -> Option<&mir::SourceInfo> { - self.loc.ok().map(|loc| self.body.source_info(loc)) - } - - pub fn current_span(&self) -> Span { - match self.loc { - Ok(loc) => self.body.source_info(loc).span, - Err(span) => span, - } - } -} - -impl<'tcx> fmt::Display for FrameInfo<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - if tcx.def_key(self.instance.def_id()).disambiguated_data.data - == DefPathData::ClosureExpr - { - write!(f, "inside closure")?; - } else { - write!(f, "inside `{}`", self.instance)?; - } - if !self.span.is_dummy() { - let sm = tcx.sess.source_map(); - let lo = sm.lookup_char_pos(self.span.lo()); - write!( - f, - " at {}:{}:{}", - sm.filename_for_diagnostics(&lo.file.name), - lo.line, - lo.col.to_usize() + 1 - )?; - } - Ok(()) - }) - } -} - -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - &self.tcx.data_layout - } -} - -impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'mir, 'tcx, M> -where - M: Machine<'mir, 'tcx>, -{ - #[inline] - fn tcx(&self) -> TyCtxt<'tcx> { - *self.tcx - } -} - -impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M> -where - M: Machine<'mir, 'tcx>, -{ - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf<'tcx> for InterpCx<'mir, 'tcx, M> { - type Ty = Ty<'tcx>; - type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>; - - #[inline] - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx - .layout_of(self.param_env.and(ty)) - .map_err(|layout| err_inval!(Layout(layout)).into()) - } -} - -/// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. -/// This test should be symmetric, as it is primarily about layout compatibility. -pub(super) fn mir_assign_valid_types<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - src: TyAndLayout<'tcx>, - dest: TyAndLayout<'tcx>, -) -> bool { - // Type-changing assignments can happen when subtyping is used. While - // all normal lifetimes are erased, higher-ranked types with their - // late-bound lifetimes are still around and can lead to type - // differences. So we compare ignoring lifetimes. - if equal_up_to_regions(tcx, param_env, src.ty, dest.ty) { - // Make sure the layout is equal, too -- just to be safe. Miri really - // needs layout equality. For performance reason we skip this check when - // the types are equal. Equal types *can* have different layouts when - // enum downcast is involved (as enum variants carry the type of the - // enum), but those should never occur in assignments. - if cfg!(debug_assertions) || src.ty != dest.ty { - assert_eq!(src.layout, dest.layout); - } - true - } else { - false - } -} - -/// Use the already known layout if given (but sanity check in debug mode), -/// or compute the layout. -#[cfg_attr(not(debug_assertions), inline(always))] -pub(super) fn from_known_layout<'tcx>( - tcx: TyCtxtAt<'tcx>, - param_env: ParamEnv<'tcx>, - known_layout: Option>, - compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, -) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - match known_layout { - None => compute(), - Some(known_layout) => { - if cfg!(debug_assertions) { - let check_layout = compute()?; - if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) { - span_bug!( - tcx.span, - "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}", - known_layout.ty, - check_layout.ty, - ); - } - } - Ok(known_layout) - } - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn new( - tcx: TyCtxt<'tcx>, - root_span: Span, - param_env: ty::ParamEnv<'tcx>, - machine: M, - memory_extra: M::MemoryExtra, - ) -> Self { - InterpCx { - machine, - tcx: tcx.at(root_span), - param_env, - memory: Memory::new(tcx, memory_extra), - recursion_limit: tcx.recursion_limit(), - } - } - - #[inline(always)] - pub fn cur_span(&self) -> Span { - self.stack() - .iter() - .rev() - .find(|frame| !frame.instance.def.requires_caller_location(*self.tcx)) - .map_or(self.tcx.span, |f| f.current_span()) - } - - #[inline(always)] - pub fn scalar_to_ptr(&self, scalar: Scalar) -> Pointer> { - self.memory.scalar_to_ptr(scalar) - } - - /// Call this to turn untagged "global" pointers (obtained via `tcx`) into - /// the machine pointer to the allocation. Must never be used - /// for any other pointers, nor for TLS statics. - /// - /// Using the resulting pointer represents a *direct* access to that memory - /// (e.g. by directly using a `static`), - /// as opposed to access through a pointer that was created by the program. - /// - /// This function can fail only if `ptr` points to an `extern static`. - #[inline(always)] - pub fn global_base_pointer(&self, ptr: Pointer) -> InterpResult<'tcx, Pointer> { - self.memory.global_base_pointer(ptr) - } - - #[inline(always)] - pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] { - M::stack(self) - } - - #[inline(always)] - pub(crate) fn stack_mut( - &mut self, - ) -> &mut Vec> { - M::stack_mut(self) - } - - #[inline(always)] - pub fn frame_idx(&self) -> usize { - let stack = self.stack(); - assert!(!stack.is_empty()); - stack.len() - 1 - } - - #[inline(always)] - pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { - self.stack().last().expect("no call frames exist") - } - - #[inline(always)] - pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { - self.stack_mut().last_mut().expect("no call frames exist") - } - - #[inline(always)] - pub(super) fn body(&self) -> &'mir mir::Body<'tcx> { - self.frame().body - } - - #[inline(always)] - pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { - assert!(ty.abi.is_signed()); - ty.size.sign_extend(value) - } - - #[inline(always)] - pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { - ty.size.truncate(value) - } - - #[inline] - pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx, self.param_env) - } - - pub fn load_mir( - &self, - instance: ty::InstanceDef<'tcx>, - promoted: Option, - ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - // do not continue if typeck errors occurred (can only occur in local crate) - let def = instance.with_opt_param(); - if let Some(def) = def.as_local() { - if self.tcx.has_typeck_results(def.did) { - if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors { - throw_inval!(AlreadyReported(error_reported)) - } - } - } - trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); - if let Some(promoted) = promoted { - return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]); - } - M::load_mir(self, instance) - } - - /// Call this on things you got out of the MIR (so it is as generic as the current - /// stack frame), to bring it into the proper environment for this interpreter. - pub(super) fn subst_from_current_frame_and_normalize_erasing_regions>( - &self, - value: T, - ) -> T { - self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value) - } - - /// Call this on things you got out of the MIR (so it is as generic as the provided - /// stack frame), to bring it into the proper environment for this interpreter. - pub(super) fn subst_from_frame_and_normalize_erasing_regions>( - &self, - frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, - value: T, - ) -> T { - frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) - } - - /// The `substs` are assumed to already be in our interpreter "universe" (param_env). - pub(super) fn resolve( - &self, - def: ty::WithOptConstParam, - substs: SubstsRef<'tcx>, - ) -> InterpResult<'tcx, ty::Instance<'tcx>> { - trace!("resolve: {:?}, {:#?}", def, substs); - trace!("param_env: {:#?}", self.param_env); - trace!("substs: {:#?}", substs); - match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) { - Ok(Some(instance)) => Ok(instance), - Ok(None) => throw_inval!(TooGeneric), - - // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. - Err(error_reported) => throw_inval!(AlreadyReported(error_reported)), - } - } - - #[inline(always)] - pub fn layout_of_local( - &self, - frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, - local: mir::Local, - layout: Option>, - ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - // `const_prop` runs into this with an invalid (empty) frame, so we - // have to support that case (mostly by skipping all caching). - match frame.locals.get(local).and_then(|state| state.layout.get()) { - None => { - let layout = from_known_layout(self.tcx, self.param_env, layout, || { - let local_ty = frame.body.local_decls[local].ty; - let local_ty = - self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty); - self.layout_of(local_ty) - })?; - if let Some(state) = frame.locals.get(local) { - // Layouts of locals are requested a lot, so we cache them. - state.layout.set(Some(layout)); - } - Ok(layout) - } - Some(layout) => Ok(layout), - } - } - - /// Returns the actual dynamic size and alignment of the place at the given type. - /// Only the "meta" (metadata) part of the place matters. - /// This can fail to provide an answer for extern types. - pub(super) fn size_and_align_of( - &self, - metadata: &MemPlaceMeta, - layout: &TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, Option<(Size, Align)>> { - if !layout.is_unsized() { - return Ok(Some((layout.size, layout.align.abi))); - } - match layout.ty.kind() { - ty::Adt(..) | ty::Tuple(..) => { - // First get the size of all statically known fields. - // Don't use type_of::sizing_type_of because that expects t to be sized, - // and it also rounds up to alignment, which we want to avoid, - // as the unsized field's alignment could be smaller. - assert!(!layout.ty.is_simd()); - assert!(layout.fields.count() > 0); - trace!("DST layout: {:?}", layout); - - let sized_size = layout.fields.offset(layout.fields.count() - 1); - let sized_align = layout.align.abi; - trace!( - "DST {} statically sized prefix size: {:?} align: {:?}", - layout.ty, - sized_size, - sized_align - ); - - // Recurse to get the size of the dynamically sized field (must be - // the last field). Can't have foreign types here, how would we - // adjust alignment and size for them? - let field = layout.field(self, layout.fields.count() - 1); - let (unsized_size, unsized_align) = - match self.size_and_align_of(metadata, &field)? { - Some(size_and_align) => size_and_align, - None => { - // A field with extern type. If this field is at offset 0, we behave - // like the underlying extern type. - // FIXME: Once we have made decisions for how to handle size and alignment - // of `extern type`, this should be adapted. It is just a temporary hack - // to get some code to work that probably ought to work. - if sized_size == Size::ZERO { - return Ok(None); - } else { - span_bug!( - self.cur_span(), - "Fields cannot be extern types, unless they are at offset 0" - ) - } - } - }; - - // FIXME (#26403, #27023): We should be adding padding - // to `sized_size` (to accommodate the `unsized_align` - // required of the unsized field that follows) before - // summing it with `sized_size`. (Note that since #26403 - // is unfixed, we do not yet add the necessary padding - // here. But this is where the add would go.) - - // Return the sum of sizes and max of aligns. - let size = sized_size + unsized_size; // `Size` addition - - // Choose max of two known alignments (combined value must - // be aligned according to more restrictive of the two). - let align = sized_align.max(unsized_align); - - // Issue #27023: must add any necessary padding to `size` - // (to make it a multiple of `align`) before returning it. - let size = size.align_to(align); - - // Check if this brought us over the size limit. - if size.bytes() >= self.tcx.data_layout.obj_size_bound() { - throw_ub!(InvalidMeta("total size is bigger than largest supported object")); - } - Ok(Some((size, align))) - } - ty::Dynamic(..) => { - let vtable = self.scalar_to_ptr(metadata.unwrap_meta()); - // Read size and align from vtable (already checks size). - Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) - } - - ty::Slice(_) | ty::Str => { - let len = metadata.unwrap_meta().to_machine_usize(self)?; - let elem = layout.field(self, 0); - - // Make sure the slice is not too big. - let size = elem.size.checked_mul(len, self).ok_or_else(|| { - err_ub!(InvalidMeta("slice is bigger than largest supported object")) - })?; - Ok(Some((size, elem.align.abi))) - } - - ty::Foreign(_) => Ok(None), - - _ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty), - } - } - #[inline] - pub fn size_and_align_of_mplace( - &self, - mplace: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Option<(Size, Align)>> { - self.size_and_align_of(&mplace.meta, &mplace.layout) - } - - pub fn push_stack_frame( - &mut self, - instance: ty::Instance<'tcx>, - body: &'mir mir::Body<'tcx>, - return_place: Option<&PlaceTy<'tcx, M::PointerTag>>, - return_to_block: StackPopCleanup, - ) -> InterpResult<'tcx> { - // first push a stack frame so we have access to the local substs - let pre_frame = Frame { - body, - loc: Err(body.span), // Span used for errors caused during preamble. - return_to_block, - return_place: return_place.copied(), - // empty local array, we fill it in below, after we are inside the stack frame and - // all methods actually know about the frame - locals: IndexVec::new(), - instance, - tracing_span: SpanGuard::new(), - extra: (), - }; - let frame = M::init_frame_extra(self, pre_frame)?; - self.stack_mut().push(frame); - - // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). - for const_ in &body.required_consts { - let span = const_.span; - let const_ = - self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal); - self.mir_const_to_op(&const_, None).map_err(|err| { - // If there was an error, set the span of the current frame to this constant. - // Avoiding doing this when evaluation succeeds. - self.frame_mut().loc = Err(span); - err - })?; - } - - // Locals are initially uninitialized. - let dummy = LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) }; - let mut locals = IndexVec::from_elem(dummy, &body.local_decls); - - // Now mark those locals as dead that we do not want to initialize - // Mark locals that use `Storage*` annotations as dead on function entry. - let always_live = AlwaysLiveLocals::new(self.body()); - for local in locals.indices() { - if !always_live.contains(local) { - locals[local].value = LocalValue::Dead; - } - } - // done - self.frame_mut().locals = locals; - M::after_stack_push(self)?; - self.frame_mut().loc = Ok(mir::Location::START); - - let span = info_span!("frame", "{}", instance); - self.frame_mut().tracing_span.enter(span); - - Ok(()) - } - - /// Jump to the given block. - #[inline] - pub fn go_to_block(&mut self, target: mir::BasicBlock) { - self.frame_mut().loc = Ok(mir::Location { block: target, statement_index: 0 }); - } - - /// *Return* to the given `target` basic block. - /// Do *not* use for unwinding! Use `unwind_to_block` instead. - /// - /// If `target` is `None`, that indicates the function cannot return, so we raise UB. - pub fn return_to_block(&mut self, target: Option) -> InterpResult<'tcx> { - if let Some(target) = target { - self.go_to_block(target); - Ok(()) - } else { - throw_ub!(Unreachable) - } - } - - /// *Unwind* to the given `target` basic block. - /// Do *not* use for returning! Use `return_to_block` instead. - /// - /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup - /// during unwinding, and we will just keep propagating that upwards. - /// - /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow - /// unwinding, and doing so is UB. - pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> { - self.frame_mut().loc = match target { - StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }), - StackPopUnwind::Skip => Err(self.frame_mut().body.span), - StackPopUnwind::NotAllowed => { - throw_ub_format!("unwinding past a stack frame that does not allow unwinding") - } - }; - Ok(()) - } - - /// Pops the current frame from the stack, deallocating the - /// memory for allocated locals. - /// - /// If `unwinding` is `false`, then we are performing a normal return - /// from a function. In this case, we jump back into the frame of the caller, - /// and continue execution as normal. - /// - /// If `unwinding` is `true`, then we are in the middle of a panic, - /// and need to unwind this frame. In this case, we jump to the - /// `cleanup` block for the function, which is responsible for running - /// `Drop` impls for any locals that have been initialized at this point. - /// The cleanup block ends with a special `Resume` terminator, which will - /// cause us to continue unwinding. - pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> { - info!( - "popping stack frame ({})", - if unwinding { "during unwinding" } else { "returning from function" } - ); - - // Sanity check `unwinding`. - assert_eq!( - unwinding, - match self.frame().loc { - Ok(loc) => self.body().basic_blocks()[loc.block].is_cleanup, - Err(_) => true, - } - ); - - if unwinding && self.frame_idx() == 0 { - throw_ub_format!("unwinding past the topmost frame of the stack"); - } - - let frame = - self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); - - if !unwinding { - // Copy the return value to the caller's stack frame. - if let Some(ref return_place) = frame.return_place { - let op = self.access_local(&frame, mir::RETURN_PLACE, None)?; - self.copy_op_transmute(&op, return_place)?; - trace!("{:?}", self.dump_place(**return_place)); - } else { - throw_ub!(Unreachable); - } - } - - let return_to_block = frame.return_to_block; - - // Now where do we jump next? - - // Usually we want to clean up (deallocate locals), but in a few rare cases we don't. - // In that case, we return early. We also avoid validation in that case, - // because this is CTFE and the final value will be thoroughly validated anyway. - let cleanup = match return_to_block { - StackPopCleanup::Goto { .. } => true, - StackPopCleanup::None { cleanup, .. } => cleanup, - }; - - if !cleanup { - assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); - assert!(!unwinding, "tried to skip cleanup during unwinding"); - // Leak the locals, skip validation, skip machine hook. - return Ok(()); - } - - // Cleanup: deallocate all locals that are backed by an allocation. - for local in &frame.locals { - self.deallocate_local(local.value)?; - } - - if M::after_stack_pop(self, frame, unwinding)? == StackPopJump::NoJump { - // The hook already did everything. - // We want to skip the `info!` below, hence early return. - return Ok(()); - } - // Normal return, figure out where to jump. - if unwinding { - // Follow the unwind edge. - let unwind = match return_to_block { - StackPopCleanup::Goto { unwind, .. } => unwind, - StackPopCleanup::None { .. } => { - panic!("Encountered StackPopCleanup::None when unwinding!") - } - }; - self.unwind_to_block(unwind) - } else { - // Follow the normal return edge. - match return_to_block { - StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret), - StackPopCleanup::None { .. } => Ok(()), - } - } - } - - /// Mark a storage as live, killing the previous content. - pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> { - assert!(local != mir::RETURN_PLACE, "Cannot make return place live"); - trace!("{:?} is now live", local); - - let local_val = LocalValue::Uninitialized; - // StorageLive expects the local to be dead, and marks it live. - let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); - if !matches!(old, LocalValue::Dead) { - throw_ub_format!("StorageLive on a local that was already live"); - } - Ok(()) - } - - pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> { - assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); - trace!("{:?} is now dead", local); - - // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR) - let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); - self.deallocate_local(old)?; - Ok(()) - } - - fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { - if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { - // All locals have a backing allocation, even if the allocation is empty - // due to the local having ZST type. Hence we can `unwrap`. - trace!( - "deallocating local {:?}: {:?}", - local, - self.memory.dump_alloc(ptr.provenance.unwrap().get_alloc_id()) - ); - self.memory.deallocate(ptr, None, MemoryKind::Stack)?; - }; - Ok(()) - } - - pub fn eval_to_allocation( - &self, - gid: GlobalId<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics - // and thus don't care about the parameter environment. While we could just use - // `self.param_env`, that would mean we invoke the query to evaluate the static - // with different parameter environments, thus causing the static to be evaluated - // multiple times. - let param_env = if self.tcx.is_static(gid.instance.def_id()) { - ty::ParamEnv::reveal_all() - } else { - self.param_env - }; - let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?; - self.raw_const_to_mplace(val) - } - - #[must_use] - pub fn dump_place(&'a self, place: Place) -> PlacePrinter<'a, 'mir, 'tcx, M> { - PlacePrinter { ecx: self, place } - } - - #[must_use] - pub fn generate_stacktrace(&self) -> Vec> { - let mut frames = Vec::new(); - for frame in self - .stack() - .iter() - .rev() - .skip_while(|frame| frame.instance.def.requires_caller_location(*self.tcx)) - { - let lint_root = frame.current_source_info().and_then(|source_info| { - match &frame.body.source_scopes[source_info.scope].local_data { - mir::ClearCrossCrate::Set(data) => Some(data.lint_root), - mir::ClearCrossCrate::Clear => None, - } - }); - let span = frame.current_span(); - - frames.push(FrameInfo { span, instance: frame.instance, lint_root }); - } - trace!("generate stacktrace: {:#?}", frames); - frames - } -} - -#[doc(hidden)] -/// Helper struct for the `dump_place` function. -pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { - ecx: &'a InterpCx<'mir, 'tcx, M>, - place: Place, -} - -impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug - for PlacePrinter<'a, 'mir, 'tcx, M> -{ - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.place { - Place::Local { frame, local } => { - let mut allocs = Vec::new(); - write!(fmt, "{:?}", local)?; - if frame != self.ecx.frame_idx() { - write!(fmt, " ({} frames up)", self.ecx.frame_idx() - frame)?; - } - write!(fmt, ":")?; - - match self.ecx.stack()[frame].locals[local].value { - LocalValue::Dead => write!(fmt, " is dead")?, - LocalValue::Uninitialized => write!(fmt, " is uninitialized")?, - LocalValue::Live(Operand::Indirect(mplace)) => { - write!( - fmt, - " by align({}){} ref {:?}:", - mplace.align.bytes(), - match mplace.meta { - MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), - MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), - }, - mplace.ptr, - )?; - allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id)); - } - LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { - write!(fmt, " {:?}", val)?; - if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val { - allocs.push(ptr.provenance.get_alloc_id()); - } - } - LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { - write!(fmt, " ({:?}, {:?})", val1, val2)?; - if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val1 { - allocs.push(ptr.provenance.get_alloc_id()); - } - if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val2 { - allocs.push(ptr.provenance.get_alloc_id()); - } - } - } - - write!(fmt, ": {:?}", self.ecx.memory.dump_allocs(allocs)) - } - Place::Ptr(mplace) => match mplace.ptr.provenance.map(Provenance::get_alloc_id) { - Some(alloc_id) => write!( - fmt, - "by align({}) ref {:?}: {:?}", - mplace.align.bytes(), - mplace.ptr, - self.ecx.memory.dump_alloc(alloc_id) - ), - ptr => write!(fmt, " integral by ref: {:?}", ptr), - }, - } - } -} - -impl<'ctx, 'mir, 'tcx, Tag: Provenance, Extra> HashStable> - for Frame<'mir, 'tcx, Tag, Extra> -where - Extra: HashStable>, - Tag: HashStable>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) { - // Exhaustive match on fields to make sure we forget no field. - let Frame { - body, - instance, - return_to_block, - return_place, - locals, - loc, - extra, - tracing_span: _, - } = self; - body.hash_stable(hcx, hasher); - instance.hash_stable(hcx, hasher); - return_to_block.hash_stable(hcx, hasher); - return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher); - locals.hash_stable(hcx, hasher); - loc.hash_stable(hcx, hasher); - extra.hash_stable(hcx, hasher); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intern.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intern.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intern.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intern.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,437 +0,0 @@ -//! This module specifies the type based interner for constants. -//! -//! After a const evaluation has computed a value, before we destroy the const evaluator's session -//! memory, we need to extract all memory allocations to the global memory pool so they stay around. -//! -//! In principle, this is not very complicated: we recursively walk the final value, follow all the -//! pointers, and move all reachable allocations to the global `tcx` memory. The only complication -//! is picking the right mutability for the allocations in a `static` initializer: we want to make -//! as many allocations as possible immutable so LLVM can put them into read-only memory. At the -//! same time, we need to make memory that could be mutated by the program mutable to avoid -//! incorrect compilations. To achieve this, we do a type-based traversal of the final value, -//! tracking mutable and shared references and `UnsafeCell` to determine the current mutability. -//! (In principle, we could skip this type-based part for `const` and promoteds, as they need to be -//! always immutable. At least for `const` however we use this opportunity to reject any `const` -//! that contains allocations whose mutability we cannot identify.) - -use super::validity::RefTracking; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::ErrorReported; -use rustc_hir as hir; -use rustc_middle::mir::interpret::InterpResult; -use rustc_middle::ty::{self, layout::TyAndLayout, Ty}; - -use rustc_ast::Mutability; - -use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, ValueVisitor}; -use crate::const_eval; - -pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< - 'mir, - 'tcx, - MemoryKind = T, - PointerTag = AllocId, - ExtraFnVal = !, - FrameExtra = (), - AllocExtra = (), - MemoryMap = FxHashMap, Allocation)>, ->; - -struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> { - /// The ectx from which we intern. - ecx: &'rt mut InterpCx<'mir, 'tcx, M>, - /// Previously encountered safe references. - ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, InternMode)>, - /// A list of all encountered allocations. After type-based interning, we traverse this list to - /// also intern allocations that are only referenced by a raw pointer or inside a union. - leftover_allocations: &'rt mut FxHashSet, - /// The root kind of the value that we're looking at. This field is never mutated for a - /// particular allocation. It is primarily used to make as many allocations as possible - /// read-only so LLVM can place them in const memory. - mode: InternMode, - /// This field stores whether we are *currently* inside an `UnsafeCell`. This can affect - /// the intern mode of references we encounter. - inside_unsafe_cell: bool, -} - -#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] -enum InternMode { - /// A static and its current mutability. Below shared references inside a `static mut`, - /// this is *immutable*, and below mutable references inside an `UnsafeCell`, this - /// is *mutable*. - Static(hir::Mutability), - /// A `const`. - Const, -} - -/// Signalling data structure to ensure we don't recurse -/// into the memory of other constants or statics -struct IsStaticOrFn; - -/// Intern an allocation without looking at its children. -/// `mode` is the mode of the environment where we found this pointer. -/// `mutablity` is the mutability of the place to be interned; even if that says -/// `immutable` things might become mutable if `ty` is not frozen. -/// `ty` can be `None` if there is no potential interior mutability -/// to account for (e.g. for vtables). -fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>( - ecx: &'rt mut InterpCx<'mir, 'tcx, M>, - leftover_allocations: &'rt mut FxHashSet, - alloc_id: AllocId, - mode: InternMode, - ty: Option>, -) -> Option { - trace!("intern_shallow {:?} with {:?}", alloc_id, mode); - // remove allocation - let tcx = ecx.tcx; - let (kind, mut alloc) = match ecx.memory.alloc_map.remove(&alloc_id) { - Some(entry) => entry, - None => { - // Pointer not found in local memory map. It is either a pointer to the global - // map, or dangling. - // If the pointer is dangling (neither in local nor global memory), we leave it - // to validation to error -- it has the much better error messages, pointing out where - // in the value the dangling reference lies. - // The `delay_span_bug` ensures that we don't forget such a check in validation. - if tcx.get_global_alloc(alloc_id).is_none() { - tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer"); - } - // treat dangling pointers like other statics - // just to stop trying to recurse into them - return Some(IsStaticOrFn); - } - }; - // This match is just a canary for future changes to `MemoryKind`, which most likely need - // changes in this function. - match kind { - MemoryKind::Stack - | MemoryKind::Machine(const_eval::MemoryKind::Heap) - | MemoryKind::CallerLocation => {} - } - // Set allocation mutability as appropriate. This is used by LLVM to put things into - // read-only memory, and also by Miri when evaluating other globals that - // access this one. - if let InternMode::Static(mutability) = mode { - // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume - // no interior mutability. - let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env)); - // For statics, allocation mutability is the combination of place mutability and - // type mutability. - // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere. - let immutable = mutability == Mutability::Not && frozen; - if immutable { - alloc.mutability = Mutability::Not; - } else { - // Just making sure we are not "upgrading" an immutable allocation to mutable. - assert_eq!(alloc.mutability, Mutability::Mut); - } - } else { - // No matter what, *constants are never mutable*. Mutating them is UB. - // See const_eval::machine::MemoryExtra::can_access_statics for why - // immutability is so important. - - // Validation will ensure that there is no `UnsafeCell` on an immutable allocation. - alloc.mutability = Mutability::Not; - }; - // link the alloc id to the actual allocation - let alloc = tcx.intern_const_alloc(alloc); - leftover_allocations.extend(alloc.relocations().iter().map(|&(_, alloc_id)| alloc_id)); - tcx.set_alloc_id_memory(alloc_id, alloc); - None -} - -impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> - InternVisitor<'rt, 'mir, 'tcx, M> -{ - fn intern_shallow( - &mut self, - alloc_id: AllocId, - mode: InternMode, - ty: Option>, - ) -> Option { - intern_shallow(self.ecx, self.leftover_allocations, alloc_id, mode, ty) - } -} - -impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> - ValueVisitor<'mir, 'tcx, M> for InternVisitor<'rt, 'mir, 'tcx, M> -{ - type V = MPlaceTy<'tcx>; - - #[inline(always)] - fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { - &self.ecx - } - - fn visit_aggregate( - &mut self, - mplace: &MPlaceTy<'tcx>, - fields: impl Iterator>, - ) -> InterpResult<'tcx> { - // ZSTs cannot contain pointers, so we can skip them. - if mplace.layout.is_zst() { - return Ok(()); - } - - if let Some(def) = mplace.layout.ty.ty_adt_def() { - if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() { - // We are crossing over an `UnsafeCell`, we can mutate again. This means that - // References we encounter inside here are interned as pointing to mutable - // allocations. - // Remember the `old` value to handle nested `UnsafeCell`. - let old = std::mem::replace(&mut self.inside_unsafe_cell, true); - let walked = self.walk_aggregate(mplace, fields); - self.inside_unsafe_cell = old; - return walked; - } - } - - self.walk_aggregate(mplace, fields) - } - - fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { - // Handle Reference types, as these are the only relocations supported by const eval. - // Raw pointers (and boxes) are handled by the `leftover_relocations` logic. - let tcx = self.ecx.tcx; - let ty = mplace.layout.ty; - if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() { - let value = self.ecx.read_immediate(&(*mplace).into())?; - let mplace = self.ecx.ref_to_mplace(&value)?; - assert_eq!(mplace.layout.ty, referenced_ty); - // Handle trait object vtables. - if let ty::Dynamic(..) = - tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() - { - let ptr = self.ecx.scalar_to_ptr(mplace.meta.unwrap_meta()); - if let Some(alloc_id) = ptr.provenance { - // Explicitly choose const mode here, since vtables are immutable, even - // if the reference of the fat pointer is mutable. - self.intern_shallow(alloc_id, InternMode::Const, None); - } else { - // Validation will error (with a better message) on an invalid vtable pointer. - // Let validation show the error message, but make sure it *does* error. - tcx.sess - .delay_span_bug(tcx.span, "vtables pointers cannot be integer pointers"); - } - } - // Check if we have encountered this pointer+layout combination before. - // Only recurse for allocation-backed pointers. - if let Some(alloc_id) = mplace.ptr.provenance { - // Compute the mode with which we intern this. Our goal here is to make as many - // statics as we can immutable so they can be placed in read-only memory by LLVM. - let ref_mode = match self.mode { - InternMode::Static(mutbl) => { - // In statics, merge outer mutability with reference mutability and - // take into account whether we are in an `UnsafeCell`. - - // The only way a mutable reference actually works as a mutable reference is - // by being in a `static mut` directly or behind another mutable reference. - // If there's an immutable reference or we are inside a `static`, then our - // mutable reference is equivalent to an immutable one. As an example: - // `&&mut Foo` is semantically equivalent to `&&Foo` - match ref_mutability { - _ if self.inside_unsafe_cell => { - // Inside an `UnsafeCell` is like inside a `static mut`, the "outer" - // mutability does not matter. - InternMode::Static(ref_mutability) - } - Mutability::Not => { - // A shared reference, things become immutable. - // We do *not* consider `freeze` here: `intern_shallow` considers - // `freeze` for the actual mutability of this allocation; the intern - // mode for references contained in this allocation is tracked more - // precisely when traversing the referenced data (by tracking - // `UnsafeCell`). This makes sure that `&(&i32, &Cell)` still - // has the left inner reference interned into a read-only - // allocation. - InternMode::Static(Mutability::Not) - } - Mutability::Mut => { - // Mutable reference. - InternMode::Static(mutbl) - } - } - } - InternMode::Const => { - // Ignore `UnsafeCell`, everything is immutable. Validity does some sanity - // checking for mutable references that we encounter -- they must all be - // ZST. - InternMode::Const - } - }; - match self.intern_shallow(alloc_id, ref_mode, Some(referenced_ty)) { - // No need to recurse, these are interned already and statics may have - // cycles, so we don't want to recurse there - Some(IsStaticOrFn) => {} - // intern everything referenced by this value. The mutability is taken from the - // reference. It is checked above that mutable references only happen in - // `static mut` - None => self.ref_tracking.track((mplace, ref_mode), || ()), - } - } - Ok(()) - } else { - // Not a reference -- proceed recursively. - self.walk_value(mplace) - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] -pub enum InternKind { - /// The `mutability` of the static, ignoring the type which may have interior mutability. - Static(hir::Mutability), - Constant, - Promoted, -} - -/// Intern `ret` and everything it references. -/// -/// This *cannot raise an interpreter error*. Doing so is left to validation, which -/// tracks where in the value we are and thus can show much better error messages. -/// Any errors here would anyway be turned into `const_err` lints, whereas validation failures -/// are hard errors. -#[tracing::instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_recursive>( - ecx: &mut InterpCx<'mir, 'tcx, M>, - intern_kind: InternKind, - ret: &MPlaceTy<'tcx>, -) -> Result<(), ErrorReported> -where - 'tcx: 'mir, -{ - let tcx = ecx.tcx; - let base_intern_mode = match intern_kind { - InternKind::Static(mutbl) => InternMode::Static(mutbl), - // `Constant` includes array lengths. - InternKind::Constant | InternKind::Promoted => InternMode::Const, - }; - - // Type based interning. - // `ref_tracking` tracks typed references we have already interned and still need to crawl for - // more typed information inside them. - // `leftover_allocations` collects *all* allocations we see, because some might not - // be available in a typed way. They get interned at the end. - let mut ref_tracking = RefTracking::empty(); - let leftover_allocations = &mut FxHashSet::default(); - - // start with the outermost allocation - intern_shallow( - ecx, - leftover_allocations, - // The outermost allocation must exist, because we allocated it with - // `Memory::allocate`. - ret.ptr.provenance.unwrap(), - base_intern_mode, - Some(ret.layout.ty), - ); - - ref_tracking.track((*ret, base_intern_mode), || ()); - - while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() { - let res = InternVisitor { - ref_tracking: &mut ref_tracking, - ecx, - mode, - leftover_allocations, - inside_unsafe_cell: false, - } - .visit_value(&mplace); - // We deliberately *ignore* interpreter errors here. When there is a problem, the remaining - // references are "leftover"-interned, and later validation will show a proper error - // and point at the right part of the value causing the problem. - match res { - Ok(()) => {} - Err(error) => { - ecx.tcx.sess.delay_span_bug( - ecx.tcx.span, - &format!( - "error during interning should later cause validation failure: {}", - error - ), - ); - } - } - } - - // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw - // pointers, ... So we can't intern them according to their type rules - - let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect(); - while let Some(alloc_id) = todo.pop() { - if let Some((_, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) { - // We can't call the `intern_shallow` method here, as its logic is tailored to safe - // references and a `leftover_allocations` set (where we only have a todo-list here). - // So we hand-roll the interning logic here again. - match intern_kind { - // Statics may contain mutable allocations even behind relocations. - // Even for immutable statics it would be ok to have mutable allocations behind - // raw pointers, e.g. for `static FOO: *const AtomicUsize = &AtomicUsize::new(42)`. - InternKind::Static(_) => {} - // Raw pointers in promoteds may only point to immutable things so we mark - // everything as immutable. - // It is UB to mutate through a raw pointer obtained via an immutable reference: - // Since all references and pointers inside a promoted must by their very definition - // be created from an immutable reference (and promotion also excludes interior - // mutability), mutating through them would be UB. - // There's no way we can check whether the user is using raw pointers correctly, - // so all we can do is mark this as immutable here. - InternKind::Promoted => { - // See const_eval::machine::MemoryExtra::can_access_statics for why - // immutability is so important. - alloc.mutability = Mutability::Not; - } - InternKind::Constant => { - // If it's a constant, we should not have any "leftovers" as everything - // is tracked by const-checking. - // FIXME: downgrade this to a warning? It rejects some legitimate consts, - // such as `const CONST_RAW: *const Vec = &Vec::new() as *const _;`. - ecx.tcx - .sess - .span_err(ecx.tcx.span, "untyped pointers are not allowed in constant"); - // For better errors later, mark the allocation as immutable. - alloc.mutability = Mutability::Not; - } - } - let alloc = tcx.intern_const_alloc(alloc); - tcx.set_alloc_id_memory(alloc_id, alloc); - for &(_, alloc_id) in alloc.relocations().iter() { - if leftover_allocations.insert(alloc_id) { - todo.push(alloc_id); - } - } - } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) { - // Codegen does not like dangling pointers, and generally `tcx` assumes that - // all allocations referenced anywhere actually exist. So, make sure we error here. - ecx.tcx.sess.span_err(ecx.tcx.span, "encountered dangling pointer in final constant"); - return Err(ErrorReported); - } else if ecx.tcx.get_global_alloc(alloc_id).is_none() { - // We have hit an `AllocId` that is neither in local or global memory and isn't - // marked as dangling by local memory. That should be impossible. - span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id); - } - } - Ok(()) -} - -impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> - InterpCx<'mir, 'tcx, M> -{ - /// A helper function that allocates memory for the layout given and gives you access to mutate - /// it. Once your own mutation code is done, the backing `Allocation` is removed from the - /// current `Memory` and returned. - pub(crate) fn intern_with_temp_alloc( - &mut self, - layout: TyAndLayout<'tcx>, - f: impl FnOnce( - &mut InterpCx<'mir, 'tcx, M>, - &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ()>, - ) -> InterpResult<'tcx, &'tcx Allocation> { - let dest = self.allocate(layout, MemoryKind::Stack)?; - f(self, &dest.into())?; - let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1; - alloc.mutability = Mutability::Not; - Ok(self.tcx.intern_const_alloc(alloc)) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -use std::convert::TryFrom; - -use rustc_ast::Mutability; -use rustc_hir::lang_items::LangItem; -use rustc_middle::mir::TerminatorKind; -use rustc_middle::ty::subst::Subst; -use rustc_span::{Span, Symbol}; -use rustc_target::abi::LayoutOf; - -use crate::interpret::{ - intrinsics::{InterpCx, Machine}, - MPlaceTy, MemoryKind, Scalar, -}; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a - /// frame which is not `#[track_caller]`. - crate fn find_closest_untracked_caller_location(&self) -> Span { - for frame in self.stack().iter().rev() { - debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance); - - // Assert that the frame we look at is actually executing code currently - // (`loc` is `Err` when we are unwinding and the frame does not require cleanup). - let loc = frame.loc.unwrap(); - - // This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all - // (such as `box`). Use the normal span by default. - let mut source_info = *frame.body.source_info(loc); - - // If this is a `Call` terminator, use the `fn_span` instead. - let block = &frame.body.basic_blocks()[loc.block]; - if loc.statement_index == block.statements.len() { - debug!( - "find_closest_untracked_caller_location: got terminator {:?} ({:?})", - block.terminator(), - block.terminator().kind - ); - if let TerminatorKind::Call { fn_span, .. } = block.terminator().kind { - source_info.span = fn_span; - } - } - - // Walk up the `SourceScope`s, in case some of them are from MIR inlining. - // If so, the starting `source_info.span` is in the innermost inlined - // function, and will be replaced with outer callsite spans as long - // as the inlined functions were `#[track_caller]`. - loop { - let scope_data = &frame.body.source_scopes[source_info.scope]; - - if let Some((callee, callsite_span)) = scope_data.inlined { - // Stop inside the most nested non-`#[track_caller]` function, - // before ever reaching its caller (which is irrelevant). - if !callee.def.requires_caller_location(*self.tcx) { - return source_info.span; - } - source_info.span = callsite_span; - } - - // Skip past all of the parents with `inlined: None`. - match scope_data.inlined_parent_scope { - Some(parent) => source_info.scope = parent, - None => break, - } - } - - // Stop inside the most nested non-`#[track_caller]` function, - // before ever reaching its caller (which is irrelevant). - if !frame.instance.def.requires_caller_location(*self.tcx) { - return source_info.span; - } - } - - bug!("no non-`#[track_caller]` frame found") - } - - /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. - crate fn alloc_caller_location( - &mut self, - filename: Symbol, - line: u32, - col: u32, - ) -> MPlaceTy<'tcx, M::PointerTag> { - let file = - self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not); - let line = Scalar::from_u32(line); - let col = Scalar::from_u32(col); - - // Allocate memory for `CallerLocation` struct. - let loc_ty = self - .tcx - .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None)) - .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter())); - let loc_layout = self.layout_of(loc_ty).unwrap(); - // This can fail if rustc runs out of memory right here. Trying to emit an error would be - // pointless, since that would require allocating more memory than a Location. - let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); - - // Initialize fields. - self.write_immediate(file.to_ref(self), &self.mplace_field(&location, 0).unwrap().into()) - .expect("writing to memory we just allocated cannot fail"); - self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into()) - .expect("writing to memory we just allocated cannot fail"); - self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into()) - .expect("writing to memory we just allocated cannot fail"); - - location - } - - crate fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { - let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); - let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); - ( - Symbol::intern(&caller.file.name.prefer_remapped().to_string_lossy()), - u32::try_from(caller.line).unwrap(), - u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(), - ) - } - - pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> { - let (file, line, column) = self.location_triple_for_span(span); - self.alloc_caller_location(file, line, column) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,197 +0,0 @@ -use rustc_hir::def_id::CrateNum; -use rustc_hir::definitions::DisambiguatedDefPathData; -use rustc_middle::mir::interpret::Allocation; -use rustc_middle::ty::{ - self, - print::{PrettyPrinter, Print, Printer}, - subst::{GenericArg, GenericArgKind}, - Ty, TyCtxt, -}; -use std::fmt::Write; - -struct AbsolutePathPrinter<'tcx> { - tcx: TyCtxt<'tcx>, - path: String, -} - -impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { - type Error = std::fmt::Error; - - type Path = Self; - type Region = Self; - type Type = Self; - type DynExistential = Self; - type Const = Self; - - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn print_region(self, _region: ty::Region<'_>) -> Result { - Ok(self) - } - - fn print_type(mut self, ty: Ty<'tcx>) -> Result { - match *ty.kind() { - // Types without identity. - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_) - | ty::Ref(_, _, _) - | ty::FnPtr(_) - | ty::Never - | ty::Tuple(_) - | ty::Dynamic(_, _) => self.pretty_print_type(ty), - - // Placeholders (all printed as `_` to uniformize them). - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { - write!(self, "_")?; - Ok(self) - } - - // Types with identity (print the module path). - ty::Adt(&ty::AdtDef { did: def_id, .. }, substs) - | ty::FnDef(def_id, substs) - | ty::Opaque(def_id, substs) - | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) - | ty::Closure(def_id, substs) - | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), - ty::Foreign(def_id) => self.print_def_path(def_id, &[]), - - ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), - } - } - - fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result { - self.pretty_print_const(ct, false) - } - - fn print_dyn_existential( - mut self, - predicates: &'tcx ty::List>>, - ) -> Result { - let mut first = true; - for p in predicates { - if !first { - write!(self, "+")?; - } - first = false; - self = p.print(self)?; - } - Ok(self) - } - - fn path_crate(mut self, cnum: CrateNum) -> Result { - self.path.push_str(&self.tcx.crate_name(cnum).as_str()); - Ok(self) - } - - fn path_qualified( - self, - self_ty: Ty<'tcx>, - trait_ref: Option>, - ) -> Result { - self.pretty_path_qualified(self_ty, trait_ref) - } - - fn path_append_impl( - self, - print_prefix: impl FnOnce(Self) -> Result, - _disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option>, - ) -> Result { - self.pretty_path_append_impl( - |mut cx| { - cx = print_prefix(cx)?; - - cx.path.push_str("::"); - - Ok(cx) - }, - self_ty, - trait_ref, - ) - } - - fn path_append( - mut self, - print_prefix: impl FnOnce(Self) -> Result, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result { - self = print_prefix(self)?; - - write!(self.path, "::{}", disambiguated_data.data).unwrap(); - - Ok(self) - } - - fn path_generic_args( - mut self, - print_prefix: impl FnOnce(Self) -> Result, - args: &[GenericArg<'tcx>], - ) -> Result { - self = print_prefix(self)?; - let args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => false, - _ => true, - }); - if args.clone().next().is_some() { - self.generic_delimiters(|cx| cx.comma_sep(args)) - } else { - Ok(self) - } - } -} - -impl PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { - fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool { - false - } - fn comma_sep(mut self, mut elems: impl Iterator) -> Result - where - T: Print<'tcx, Self, Output = Self, Error = Self::Error>, - { - if let Some(first) = elems.next() { - self = first.print(self)?; - for elem in elems { - self.path.push_str(", "); - self = elem.print(self)?; - } - } - Ok(self) - } - - fn generic_delimiters( - mut self, - f: impl FnOnce(Self) -> Result, - ) -> Result { - write!(self, "<")?; - - self = f(self)?; - - write!(self, ">")?; - - Ok(self) - } -} - -impl Write for AbsolutePathPrinter<'_> { - fn write_str(&mut self, s: &str) -> std::fmt::Result { - self.path.push_str(s); - Ok(()) - } -} - -/// Directly returns an `Allocation` containing an absolute path representation of the given type. -crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation { - let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; - let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); - tcx.intern_const_alloc(alloc) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/intrinsics.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,584 +0,0 @@ -//! Intrinsics and other functions that the miri engine executes without -//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE -//! and miri. - -use std::convert::TryFrom; - -use rustc_hir::def_id::DefId; -use rustc_middle::mir::{ - self, - interpret::{ConstValue, GlobalId, InterpResult, Scalar}, - BinOp, -}; -use rustc_middle::ty; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{Abi, Align, LayoutOf as _, Primitive, Size}; - -use super::{ - util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy, - Pointer, -}; - -mod caller_location; -mod type_name; - -fn numeric_intrinsic(name: Symbol, bits: u128, kind: Primitive) -> Scalar { - let size = match kind { - Primitive::Int(integer, _) => integer.size(), - _ => bug!("invalid `{}` argument: {:?}", name, bits), - }; - let extra = 128 - u128::from(size.bits()); - let bits_out = match name { - sym::ctpop => u128::from(bits.count_ones()), - sym::ctlz => u128::from(bits.leading_zeros()) - extra, - sym::cttz => u128::from((bits << extra).trailing_zeros()) - extra, - sym::bswap => (bits << extra).swap_bytes(), - sym::bitreverse => (bits << extra).reverse_bits(), - _ => bug!("not a numeric intrinsic: {}", name), - }; - Scalar::from_uint(bits_out, size) -} - -/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated -/// inside an `InterpCx` and instead have their value computed directly from rustc internal info. -crate fn eval_nullary_intrinsic<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, -) -> InterpResult<'tcx, ConstValue<'tcx>> { - let tp_ty = substs.type_at(0); - let name = tcx.item_name(def_id); - Ok(match name { - sym::type_name => { - ensure_monomorphic_enough(tcx, tp_ty)?; - let alloc = type_name::alloc_type_name(tcx, tp_ty); - ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } - } - sym::needs_drop => { - ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)) - } - sym::min_align_of | sym::pref_align_of => { - // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. - let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; - let n = match name { - sym::pref_align_of => layout.align.pref.bytes(), - sym::min_align_of => layout.align.abi.bytes(), - _ => bug!(), - }; - ConstValue::from_machine_usize(n, &tcx) - } - sym::type_id => { - ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_u64(tcx.type_id_hash(tp_ty)) - } - sym::variant_count => match tp_ty.kind() { - // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. - ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx), - ty::Projection(_) - | ty::Opaque(_, _) - | ty::Param(_) - | ty::Bound(_, _) - | ty::Placeholder(_) - | ty::Infer(_) => throw_inval!(TooGeneric), - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(_, _) - | ty::Closure(_, _) - | ty::Generator(_, _, _) - | ty::GeneratorWitness(_) - | ty::Never - | ty::Tuple(_) - | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx), - }, - other => bug!("`{}` is not a zero arg intrinsic", other), - }) -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Returns `true` if emulation happened. - /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own - /// intrinsic handling. - pub fn emulate_intrinsic( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, M::PointerTag>], - ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, - ) -> InterpResult<'tcx, bool> { - let substs = instance.substs; - let intrinsic_name = self.tcx.item_name(instance.def_id()); - - // First handle intrinsics without return place. - let (dest, ret) = match ret { - None => match intrinsic_name { - sym::transmute => throw_ub_format!("transmuting to uninhabited type"), - sym::abort => M::abort(self, "the program aborted execution".to_owned())?, - // Unsupported diverging intrinsic. - _ => return Ok(false), - }, - Some(p) => p, - }; - - // Keep the patterns in this match ordered the same as the list in - // `src/librustc_middle/ty/constness.rs` - match intrinsic_name { - sym::caller_location => { - let span = self.find_closest_untracked_caller_location(); - let location = self.alloc_caller_location_for_span(span); - self.write_immediate(location.to_ref(self), dest)?; - } - - sym::min_align_of_val | sym::size_of_val => { - // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be - // dereferencable! - let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?; - let (size, align) = self - .size_and_align_of_mplace(&place)? - .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?; - - let result = match intrinsic_name { - sym::min_align_of_val => align.bytes(), - sym::size_of_val => size.bytes(), - _ => bug!(), - }; - - self.write_scalar(Scalar::from_machine_usize(result, self), dest)?; - } - - sym::min_align_of - | sym::pref_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { - let gid = GlobalId { instance, promoted: None }; - let ty = match intrinsic_name { - sym::min_align_of | sym::pref_align_of | sym::variant_count => { - self.tcx.types.usize - } - sym::needs_drop => self.tcx.types.bool, - sym::type_id => self.tcx.types.u64, - sym::type_name => self.tcx.mk_static_str(), - _ => bug!("already checked for nullary intrinsics"), - }; - let val = - self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?; - let val = self.const_val_to_op(val, ty, Some(dest.layout))?; - self.copy_op(&val, dest)?; - } - - sym::ctpop - | sym::cttz - | sym::cttz_nonzero - | sym::ctlz - | sym::ctlz_nonzero - | sym::bswap - | sym::bitreverse => { - let ty = substs.type_at(0); - let layout_of = self.layout_of(ty)?; - let val = self.read_scalar(&args[0])?.check_init()?; - let bits = val.to_bits(layout_of.size)?; - let kind = match layout_of.abi { - Abi::Scalar(ref scalar) => scalar.value, - _ => span_bug!( - self.cur_span(), - "{} called on invalid type {:?}", - intrinsic_name, - ty - ), - }; - let (nonzero, intrinsic_name) = match intrinsic_name { - sym::cttz_nonzero => (true, sym::cttz), - sym::ctlz_nonzero => (true, sym::ctlz), - other => (false, other), - }; - if nonzero && bits == 0 { - throw_ub_format!("`{}_nonzero` called on 0", intrinsic_name); - } - let out_val = numeric_intrinsic(intrinsic_name, bits, kind); - self.write_scalar(out_val, dest)?; - } - sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { - let lhs = self.read_immediate(&args[0])?; - let rhs = self.read_immediate(&args[1])?; - let bin_op = match intrinsic_name { - sym::add_with_overflow => BinOp::Add, - sym::sub_with_overflow => BinOp::Sub, - sym::mul_with_overflow => BinOp::Mul, - _ => bug!("Already checked for int ops"), - }; - self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?; - } - sym::saturating_add | sym::saturating_sub => { - let l = self.read_immediate(&args[0])?; - let r = self.read_immediate(&args[1])?; - let is_add = intrinsic_name == sym::saturating_add; - let (val, overflowed, _ty) = self.overflowing_binary_op( - if is_add { BinOp::Add } else { BinOp::Sub }, - &l, - &r, - )?; - let val = if overflowed { - let num_bits = l.layout.size.bits(); - if l.layout.abi.is_signed() { - // For signed ints the saturated value depends on the sign of the first - // term since the sign of the second term can be inferred from this and - // the fact that the operation has overflowed (if either is 0 no - // overflow can occur) - let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; - let first_term_positive = first_term & (1 << (num_bits - 1)) == 0; - if first_term_positive { - // Negative overflow not possible since the positive first term - // can only increase an (in range) negative term for addition - // or corresponding negated positive term for subtraction - Scalar::from_uint( - (1u128 << (num_bits - 1)) - 1, // max positive - Size::from_bits(num_bits), - ) - } else { - // Positive overflow not possible for similar reason - // max negative - Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits)) - } - } else { - // unsigned - if is_add { - // max unsigned - Scalar::from_uint( - u128::MAX >> (128 - num_bits), - Size::from_bits(num_bits), - ) - } else { - // underflow to 0 - Scalar::from_uint(0u128, Size::from_bits(num_bits)) - } - } - } else { - val - }; - self.write_scalar(val, dest)?; - } - sym::discriminant_value => { - let place = self.deref_operand(&args[0])?; - let discr_val = self.read_discriminant(&place.into())?.0; - self.write_scalar(discr_val, dest)?; - } - sym::unchecked_shl - | sym::unchecked_shr - | sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul - | sym::unchecked_div - | sym::unchecked_rem => { - let l = self.read_immediate(&args[0])?; - let r = self.read_immediate(&args[1])?; - let bin_op = match intrinsic_name { - sym::unchecked_shl => BinOp::Shl, - sym::unchecked_shr => BinOp::Shr, - sym::unchecked_add => BinOp::Add, - sym::unchecked_sub => BinOp::Sub, - sym::unchecked_mul => BinOp::Mul, - sym::unchecked_div => BinOp::Div, - sym::unchecked_rem => BinOp::Rem, - _ => bug!("Already checked for int ops"), - }; - let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?; - if overflowed { - let layout = self.layout_of(substs.type_at(0))?; - let r_val = r.to_scalar()?.to_bits(layout.size)?; - if let sym::unchecked_shl | sym::unchecked_shr = intrinsic_name { - throw_ub_format!("overflowing shift by {} in `{}`", r_val, intrinsic_name); - } else { - throw_ub_format!("overflow executing `{}`", intrinsic_name); - } - } - self.write_scalar(val, dest)?; - } - sym::rotate_left | sym::rotate_right => { - // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) - // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) - let layout = self.layout_of(substs.type_at(0))?; - let val = self.read_scalar(&args[0])?.check_init()?; - let val_bits = val.to_bits(layout.size)?; - let raw_shift = self.read_scalar(&args[1])?.check_init()?; - let raw_shift_bits = raw_shift.to_bits(layout.size)?; - let width_bits = u128::from(layout.size.bits()); - let shift_bits = raw_shift_bits % width_bits; - let inv_shift_bits = (width_bits - shift_bits) % width_bits; - let result_bits = if intrinsic_name == sym::rotate_left { - (val_bits << shift_bits) | (val_bits >> inv_shift_bits) - } else { - (val_bits >> shift_bits) | (val_bits << inv_shift_bits) - }; - let truncated_bits = self.truncate(result_bits, layout); - let result = Scalar::from_uint(truncated_bits, layout.size); - self.write_scalar(result, dest)?; - } - sym::copy => { - self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?; - } - sym::offset => { - let ptr = self.read_pointer(&args[0])?; - let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?; - let pointee_ty = substs.type_at(0); - - let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; - self.write_pointer(offset_ptr, dest)?; - } - sym::arith_offset => { - let ptr = self.read_pointer(&args[0])?; - let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?; - let pointee_ty = substs.type_at(0); - - let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset_bytes = offset_count.wrapping_mul(pointee_size); - let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, self); - self.write_pointer(offset_ptr, dest)?; - } - sym::ptr_offset_from => { - let a = self.read_immediate(&args[0])?.to_scalar()?; - let b = self.read_immediate(&args[1])?.to_scalar()?; - - // Special case: if both scalars are *equal integers* - // and not null, we pretend there is an allocation of size 0 right there, - // and their offset is 0. (There's never a valid object at null, making it an - // exception from the exception.) - // This is the dual to the special exception for offset-by-0 - // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`). - // - // Control flow is weird because we cannot early-return (to reach the - // `go_to_block` at the end). - let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) { - let a = a.try_to_machine_usize(*self.tcx).unwrap(); - let b = b.try_to_machine_usize(*self.tcx).unwrap(); - if a == b && a != 0 { - self.write_scalar(Scalar::from_machine_isize(0, self), dest)?; - true - } else { - false - } - } else { - false - }; - - if !done { - // General case: we need two pointers. - let a = self.scalar_to_ptr(a); - let b = self.scalar_to_ptr(b); - let (a_alloc_id, a_offset, _) = self.memory.ptr_get_alloc(a)?; - let (b_alloc_id, b_offset, _) = self.memory.ptr_get_alloc(b)?; - if a_alloc_id != b_alloc_id { - throw_ub_format!( - "ptr_offset_from cannot compute offset of pointers into different \ - allocations.", - ); - } - let usize_layout = self.layout_of(self.tcx.types.usize)?; - let isize_layout = self.layout_of(self.tcx.types.isize)?; - let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout); - let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout); - let (val, _overflowed, _ty) = - self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?; - let pointee_layout = self.layout_of(substs.type_at(0))?; - let val = ImmTy::from_scalar(val, isize_layout); - let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout); - self.exact_div(&val, &size, dest)?; - } - } - - sym::transmute => { - self.copy_op_transmute(&args[0], dest)?; - } - sym::assert_inhabited => { - let ty = instance.substs.type_at(0); - let layout = self.layout_of(ty)?; - - if layout.abi.is_uninhabited() { - // The run-time intrinsic panics just to get a good backtrace; here we abort - // since there is no problem showing a backtrace even for aborts. - M::abort( - self, - format!( - "aborted execution: attempted to instantiate uninhabited type `{}`", - ty - ), - )?; - } - } - sym::simd_insert => { - let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); - let elem = &args[2]; - let input = &args[0]; - let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx); - assert!( - index < len, - "Index `{}` must be in bounds of vector type `{}`: `[0, {})`", - index, - e_ty, - len - ); - assert_eq!( - input.layout, dest.layout, - "Return type `{}` must match vector type `{}`", - dest.layout.ty, input.layout.ty - ); - assert_eq!( - elem.layout.ty, e_ty, - "Scalar element type `{}` must match vector element type `{}`", - elem.layout.ty, e_ty - ); - - for i in 0..len { - let place = self.place_index(dest, i)?; - let value = if i == index { *elem } else { self.operand_index(input, i)? }; - self.copy_op(&value, &place)?; - } - } - sym::simd_extract => { - let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); - let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx); - assert!( - index < len, - "index `{}` is out-of-bounds of vector type `{}` with length `{}`", - index, - e_ty, - len - ); - assert_eq!( - e_ty, dest.layout.ty, - "Return type `{}` must match vector element type `{}`", - dest.layout.ty, e_ty - ); - self.copy_op(&self.operand_index(&args[0], index)?, dest)?; - } - sym::likely | sym::unlikely | sym::black_box => { - // These just return their argument - self.copy_op(&args[0], dest)?; - } - sym::assume => { - let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?; - if !cond { - throw_ub_format!("`assume` intrinsic called with `false`"); - } - } - sym::raw_eq => { - let result = self.raw_eq_intrinsic(&args[0], &args[1])?; - self.write_scalar(result, dest)?; - } - _ => return Ok(false), - } - - trace!("{:?}", self.dump_place(**dest)); - self.go_to_block(ret); - Ok(true) - } - - pub fn exact_div( - &mut self, - a: &ImmTy<'tcx, M::PointerTag>, - b: &ImmTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - // Performs an exact division, resulting in undefined behavior where - // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. - // First, check x % y != 0 (or if that computation overflows). - let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?; - if overflow || res.assert_bits(a.layout.size) != 0 { - // Then, check if `b` is -1, which is the "MIN / -1" case. - let minus1 = Scalar::from_int(-1, dest.layout.size); - let b_scalar = b.to_scalar().unwrap(); - if b_scalar == minus1 { - throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") - } else { - throw_ub_format!("exact_div: {} cannot be divided by {} without remainder", a, b,) - } - } - // `Rem` says this is all right, so we can let `Div` do its job. - self.binop_ignore_overflow(BinOp::Div, &a, &b, dest) - } - - /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its - /// allocation. For integer pointers, we consider each of them their own tiny allocation of size - /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value. - pub fn ptr_offset_inbounds( - &self, - ptr: Pointer>, - pointee_ty: Ty<'tcx>, - offset_count: i64, - ) -> InterpResult<'tcx, Pointer>> { - // We cannot overflow i64 as a type's size must be <= isize::MAX. - let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - // The computed offset, in bytes, cannot overflow an isize. - let offset_bytes = - offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?; - // The offset being in bounds cannot rely on "wrapping around" the address space. - // So, first rule out overflows in the pointer arithmetic. - let offset_ptr = ptr.signed_offset(offset_bytes, self)?; - // ptr and offset_ptr must be in bounds of the same allocated object. This means all of the - // memory between these pointers must be accessible. Note that we do not require the - // pointers to be properly aligned (unlike a read/write operation). - let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; - let size = offset_bytes.unsigned_abs(); - // This call handles checking for integer/null pointers. - self.memory.check_ptr_access_align( - min_ptr, - Size::from_bytes(size), - Align::ONE, - CheckInAllocMsg::PointerArithmeticTest, - )?; - Ok(offset_ptr) - } - - /// Copy `count*size_of::()` many bytes from `*src` to `*dst`. - pub(crate) fn copy_intrinsic( - &mut self, - src: &OpTy<'tcx, >::PointerTag>, - dst: &OpTy<'tcx, >::PointerTag>, - count: &OpTy<'tcx, >::PointerTag>, - nonoverlapping: bool, - ) -> InterpResult<'tcx> { - let count = self.read_scalar(&count)?.to_machine_usize(self)?; - let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?; - let (size, align) = (layout.size, layout.align.abi); - let size = size.checked_mul(count, self).ok_or_else(|| { - err_ub_format!( - "overflow computing total size of `{}`", - if nonoverlapping { "copy_nonoverlapping" } else { "copy" } - ) - })?; - - let src = self.read_pointer(&src)?; - let dst = self.read_pointer(&dst)?; - - self.memory.copy(src, align, dst, align, size, nonoverlapping) - } - - pub(crate) fn raw_eq_intrinsic( - &mut self, - lhs: &OpTy<'tcx, >::PointerTag>, - rhs: &OpTy<'tcx, >::PointerTag>, - ) -> InterpResult<'tcx, Scalar> { - let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; - assert!(!layout.is_unsized()); - - let lhs = self.read_pointer(lhs)?; - let rhs = self.read_pointer(rhs)?; - let lhs_bytes = self.memory.read_bytes(lhs, layout.size)?; - let rhs_bytes = self.memory.read_bytes(rhs, layout.size)?; - Ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/machine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/machine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/machine.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/machine.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,479 +0,0 @@ -//! This module contains everything needed to instantiate an interpreter. -//! This separation exists to ensure that no fancy miri features like -//! interpreting common C functions leak into CTFE. - -use std::borrow::{Borrow, Cow}; -use std::fmt::Debug; -use std::hash::Hash; - -use rustc_middle::mir; -use rustc_middle::ty::{self, Ty}; -use rustc_span::def_id::DefId; -use rustc_target::abi::Size; -use rustc_target::spec::abi::Abi; - -use super::{ - AllocId, AllocRange, Allocation, Frame, ImmTy, InterpCx, InterpResult, LocalValue, MemPlace, - Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, -}; - -/// Data returned by Machine::stack_pop, -/// to provide further control over the popping of the stack frame -#[derive(Eq, PartialEq, Debug, Copy, Clone)] -pub enum StackPopJump { - /// Indicates that no special handling should be - /// done - we'll either return normally or unwind - /// based on the terminator for the function - /// we're leaving. - Normal, - - /// Indicates that we should *not* jump to the return/unwind address, as the callback already - /// took care of everything. - NoJump, -} - -/// Whether this kind of memory is allowed to leak -pub trait MayLeak: Copy { - fn may_leak(self) -> bool; -} - -/// The functionality needed by memory to manage its allocations -pub trait AllocMap { - /// Tests if the map contains the given key. - /// Deliberately takes `&mut` because that is sufficient, and some implementations - /// can be more efficient then (using `RefCell::get_mut`). - fn contains_key(&mut self, k: &Q) -> bool - where - K: Borrow; - - /// Inserts a new entry into the map. - fn insert(&mut self, k: K, v: V) -> Option; - - /// Removes an entry from the map. - fn remove(&mut self, k: &Q) -> Option - where - K: Borrow; - - /// Returns data based on the keys and values in the map. - fn filter_map_collect(&self, f: impl FnMut(&K, &V) -> Option) -> Vec; - - /// Returns a reference to entry `k`. If no such entry exists, call - /// `vacant` and either forward its error, or add its result to the map - /// and return a reference to *that*. - fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E>; - - /// Returns a mutable reference to entry `k`. If no such entry exists, call - /// `vacant` and either forward its error, or add its result to the map - /// and return a reference to *that*. - fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E>; - - /// Read-only lookup. - fn get(&self, k: K) -> Option<&V> { - self.get_or(k, || Err(())).ok() - } - - /// Mutable lookup. - fn get_mut(&mut self, k: K) -> Option<&mut V> { - self.get_mut_or(k, || Err(())).ok() - } -} - -/// Methods of this trait signifies a point where CTFE evaluation would fail -/// and some use case dependent behaviour can instead be applied. -pub trait Machine<'mir, 'tcx>: Sized { - /// Additional memory kinds a machine wishes to distinguish from the builtin ones - type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static; - - /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. - type PointerTag: Provenance + Eq + Hash + 'static; - - /// Machines can define extra (non-instance) things that represent values of function pointers. - /// For example, Miri uses this to return a function pointer from `dlsym` - /// that can later be called to execute the right thing. - type ExtraFnVal: Debug + Copy; - - /// Extra data stored in every call frame. - type FrameExtra; - - /// Extra data stored in memory. A reference to this is available when `AllocExtra` - /// gets initialized, so you can e.g., have an `Rc` here if there is global state you - /// need access to in the `AllocExtra` hooks. - type MemoryExtra; - - /// Extra data stored in every allocation. - type AllocExtra: Debug + Clone + 'static; - - /// Memory's allocation map - type MemoryMap: AllocMap< - AllocId, - (MemoryKind, Allocation), - > + Default - + Clone; - - /// The memory kind to use for copied global memory (held in `tcx`) -- - /// or None if such memory should not be mutated and thus any such attempt will cause - /// a `ModifiedStatic` error to be raised. - /// Statics are copied under two circumstances: When they are mutated, and when - /// `tag_allocation` (see below) returns an owned allocation - /// that is added to the memory so that the work is not done twice. - const GLOBAL_KIND: Option; - - /// Should the machine panic on allocation failures? - const PANIC_ON_ALLOC_FAIL: bool; - - /// Whether memory accesses should be alignment-checked. - fn enforce_alignment(memory_extra: &Self::MemoryExtra) -> bool; - - /// Whether, when checking alignment, we should `force_int` and thus support - /// custom alignment logic based on whatever the integer address happens to be. - fn force_int_for_alignment_check(memory_extra: &Self::MemoryExtra) -> bool; - - /// Whether to enforce the validity invariant - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - - /// Whether function calls should be [ABI](Abi)-checked. - fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - true - } - - /// Entry point for obtaining the MIR of anything that should get evaluated. - /// So not just functions and shims, but also const/static initializers, anonymous - /// constants, ... - fn load_mir( - ecx: &InterpCx<'mir, 'tcx, Self>, - instance: ty::InstanceDef<'tcx>, - ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - Ok(ecx.tcx.instance_mir(instance)) - } - - /// Entry point to all function calls. - /// - /// Returns either the mir to use for the call, or `None` if execution should - /// just proceed (which usually means this hook did all the work that the - /// called function should usually have done). In the latter case, it is - /// this hook's responsibility to advance the instruction pointer! - /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR - /// nor just jump to `ret`, but instead push their own stack frame.) - /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them - /// was used. - fn find_mir_or_eval_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - abi: Abi, - args: &[OpTy<'tcx, Self::PointerTag>], - ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, - unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>; - - /// Execute `fn_val`. It is the hook's responsibility to advance the instruction - /// pointer as appropriate. - fn call_extra_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - fn_val: Self::ExtraFnVal, - abi: Abi, - args: &[OpTy<'tcx, Self::PointerTag>], - ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, - unwind: StackPopUnwind, - ) -> InterpResult<'tcx>; - - /// Directly process an intrinsic without pushing a stack frame. It is the hook's - /// responsibility to advance the instruction pointer as appropriate. - fn call_intrinsic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Self::PointerTag>], - ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, - unwind: StackPopUnwind, - ) -> InterpResult<'tcx>; - - /// Called to evaluate `Assert` MIR terminators that trigger a panic. - fn assert_panic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - msg: &mir::AssertMessage<'tcx>, - unwind: Option, - ) -> InterpResult<'tcx>; - - /// Called to evaluate `Abort` MIR terminator. - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> { - throw_unsup_format!("aborting execution is not supported") - } - - /// Called for all binary operations where the LHS has pointer type. - /// - /// Returns a (value, overflowed) pair if the operation succeeded - fn binary_ptr_op( - ecx: &InterpCx<'mir, 'tcx, Self>, - bin_op: mir::BinOp, - left: &ImmTy<'tcx, Self::PointerTag>, - right: &ImmTy<'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - - /// Heap allocations via the `box` keyword. - fn box_alloc( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - dest: &PlaceTy<'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx>; - - /// Called to read the specified `local` from the `frame`. - /// Since reading a ZST is not actually accessing memory or locals, this is never invoked - /// for ZST reads. - #[inline] - fn access_local( - _ecx: &InterpCx<'mir, 'tcx, Self>, - frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, - local: mir::Local, - ) -> InterpResult<'tcx, Operand> { - frame.locals[local].access() - } - - /// Called to write the specified `local` from the `frame`. - /// Since writing a ZST is not actually accessing memory or locals, this is never invoked - /// for ZST reads. - #[inline] - fn access_local_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - frame: usize, - local: mir::Local, - ) -> InterpResult<'tcx, Result<&'a mut LocalValue, MemPlace>> - where - 'tcx: 'mir, - { - ecx.stack_mut()[frame].locals[local].access_mut() - } - - /// Called before a basic block terminator is executed. - /// You can use this to detect endlessly running programs. - #[inline] - fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called before a global allocation is accessed. - /// `def_id` is `Some` if this is the "lazy" allocation of a static. - #[inline] - fn before_access_global( - _memory_extra: &Self::MemoryExtra, - _alloc_id: AllocId, - _allocation: &Allocation, - _static_def_id: Option, - _is_write: bool, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Return the `AllocId` for the given thread-local static in the current thread. - fn thread_local_static_base_pointer( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { - throw_unsup!(ThreadLocalStatic(def_id)) - } - - /// Return the root pointer for the given `extern static`. - fn extern_static_base_pointer( - mem: &Memory<'mir, 'tcx, Self>, - def_id: DefId, - ) -> InterpResult<'tcx, Pointer>; - - /// Return a "base" pointer for the given allocation: the one that is used for direct - /// accesses to this static/const/fn allocation, or the one returned from the heap allocator. - /// - /// Not called on `extern` or thread-local statics (those use the methods above). - fn tag_alloc_base_pointer( - mem: &Memory<'mir, 'tcx, Self>, - ptr: Pointer, - ) -> Pointer; - - /// "Int-to-pointer cast" - fn ptr_from_addr( - mem: &Memory<'mir, 'tcx, Self>, - addr: u64, - ) -> Pointer>; - - /// Convert a pointer with provenance into an allocation-offset pair. - fn ptr_get_alloc( - mem: &Memory<'mir, 'tcx, Self>, - ptr: Pointer, - ) -> (AllocId, Size); - - /// Called to initialize the "extra" state of an allocation and make the pointers - /// it contains (in relocations) tagged. The way we construct allocations is - /// to always first construct it without extra and then add the extra. - /// This keeps uniform code paths for handling both allocations created by CTFE - /// for globals, and allocations created by Miri during evaluation. - /// - /// `kind` is the kind of the allocation being tagged; it can be `None` when - /// it's a global and `GLOBAL_KIND` is `None`. - /// - /// This should avoid copying if no work has to be done! If this returns an owned - /// allocation (because a copy had to be done to add tags or metadata), machine memory will - /// cache the result. (This relies on `AllocMap::get_or` being able to add the - /// owned allocation to the map even when the map is shared.) - fn init_allocation_extra<'b>( - mem: &Memory<'mir, 'tcx, Self>, - id: AllocId, - alloc: Cow<'b, Allocation>, - kind: Option>, - ) -> Cow<'b, Allocation>; - - /// Hook for performing extra checks on a memory read access. - /// - /// Takes read-only access to the allocation so we can keep all the memory read - /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you - /// need to mutate. - #[inline(always)] - fn memory_read( - _memory_extra: &Self::MemoryExtra, - _alloc_extra: &Self::AllocExtra, - _tag: Self::PointerTag, - _range: AllocRange, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Hook for performing extra checks on a memory write access. - #[inline(always)] - fn memory_written( - _memory_extra: &mut Self::MemoryExtra, - _alloc_extra: &mut Self::AllocExtra, - _tag: Self::PointerTag, - _range: AllocRange, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Hook for performing extra operations on a memory deallocation. - #[inline(always)] - fn memory_deallocated( - _memory_extra: &mut Self::MemoryExtra, - _alloc_extra: &mut Self::AllocExtra, - _tag: Self::PointerTag, - _range: AllocRange, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Executes a retagging operation. - #[inline] - fn retag( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _kind: mir::RetagKind, - _place: &PlaceTy<'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called immediately before a new stack frame gets pushed. - fn init_frame_extra( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>; - - /// Borrow the current thread's stack. - fn stack( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>]; - - /// Mutably borrow the current thread's stack. - fn stack_mut( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec>; - - /// Called immediately after a stack frame got pushed and its locals got initialized. - fn after_stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called immediately after a stack frame got popped, but before jumping back to the caller. - fn after_stack_pop( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _frame: Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, - _unwinding: bool, - ) -> InterpResult<'tcx, StackPopJump> { - // By default, we do not support unwinding from panics - Ok(StackPopJump::Normal) - } -} - -// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines -// (CTFE and ConstProp) use the same instance. Here, we share that code. -pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { - type PointerTag = AllocId; - type ExtraFnVal = !; - - type MemoryMap = - rustc_data_structures::fx::FxHashMap, Allocation)>; - const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory - - type AllocExtra = (); - type FrameExtra = (); - - #[inline(always)] - fn enforce_alignment(_memory_extra: &Self::MemoryExtra) -> bool { - // We do not check for alignment to avoid having to carry an `Align` - // in `ConstValue::ByRef`. - false - } - - #[inline(always)] - fn force_int_for_alignment_check(_memory_extra: &Self::MemoryExtra) -> bool { - // We do not support `force_int`. - false - } - - #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - false // for now, we don't enforce validity - } - - #[inline(always)] - fn call_extra_fn( - _ecx: &mut InterpCx<$mir, $tcx, Self>, - fn_val: !, - _abi: Abi, - _args: &[OpTy<$tcx>], - _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>, - _unwind: StackPopUnwind, - ) -> InterpResult<$tcx> { - match fn_val {} - } - - #[inline(always)] - fn init_allocation_extra<'b>( - _mem: &Memory<$mir, $tcx, Self>, - _id: AllocId, - alloc: Cow<'b, Allocation>, - _kind: Option>, - ) -> Cow<'b, Allocation> { - // We do not use a tag so we can just cheaply forward the allocation - alloc - } - - fn extern_static_base_pointer( - mem: &Memory<$mir, $tcx, Self>, - def_id: DefId, - ) -> InterpResult<$tcx, Pointer> { - // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail. - Ok(Pointer::new(mem.tcx.create_static_alloc(def_id), Size::ZERO)) - } - - #[inline(always)] - fn tag_alloc_base_pointer( - _mem: &Memory<$mir, $tcx, Self>, - ptr: Pointer, - ) -> Pointer { - ptr - } - - #[inline(always)] - fn ptr_from_addr(_mem: &Memory<$mir, $tcx, Self>, addr: u64) -> Pointer> { - Pointer::new(None, Size::from_bytes(addr)) - } - - #[inline(always)] - fn ptr_get_alloc(_mem: &Memory<$mir, $tcx, Self>, ptr: Pointer) -> (AllocId, Size) { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (alloc_id, offset) = ptr.into_parts(); - (alloc_id, offset) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/memory.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/memory.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/memory.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/memory.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1186 +0,0 @@ -//! The memory subsystem. -//! -//! Generally, we use `Pointer` to denote memory addresses. However, some operations -//! have a "size"-like parameter, and they take `Scalar` for the address because -//! if the size is 0, then the pointer can also be a (properly aligned, non-null) -//! integer. It is crucial that these operations call `check_align` *before* -//! short-circuiting the empty case! - -use std::assert_matches::assert_matches; -use std::borrow::Cow; -use std::collections::VecDeque; -use std::convert::TryFrom; -use std::fmt; -use std::ptr; - -use rustc_ast::Mutability; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_middle::ty::{Instance, ParamEnv, TyCtxt}; -use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; - -use super::{ - alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, - InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar, - ScalarMaybeUninit, -}; -use crate::util::pretty; - -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum MemoryKind { - /// Stack memory. Error if deallocated except during a stack pop. - Stack, - /// Memory allocated by `caller_location` intrinsic. Error if ever deallocated. - CallerLocation, - /// Additional memory kinds a machine wishes to distinguish from the builtin ones. - Machine(T), -} - -impl MayLeak for MemoryKind { - #[inline] - fn may_leak(self) -> bool { - match self { - MemoryKind::Stack => false, - MemoryKind::CallerLocation => true, - MemoryKind::Machine(k) => k.may_leak(), - } - } -} - -impl fmt::Display for MemoryKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - MemoryKind::Stack => write!(f, "stack variable"), - MemoryKind::CallerLocation => write!(f, "caller location"), - MemoryKind::Machine(m) => write!(f, "{}", m), - } - } -} - -/// Used by `get_size_and_align` to indicate whether the allocation needs to be live. -#[derive(Debug, Copy, Clone)] -pub enum AllocCheck { - /// Allocation must be live and not a function pointer. - Dereferenceable, - /// Allocations needs to be live, but may be a function pointer. - Live, - /// Allocation may be dead. - MaybeDead, -} - -/// The value of a function pointer. -#[derive(Debug, Copy, Clone)] -pub enum FnVal<'tcx, Other> { - Instance(Instance<'tcx>), - Other(Other), -} - -impl<'tcx, Other> FnVal<'tcx, Other> { - pub fn as_instance(self) -> InterpResult<'tcx, Instance<'tcx>> { - match self { - FnVal::Instance(instance) => Ok(instance), - FnVal::Other(_) => { - throw_unsup_format!("'foreign' function pointers are not supported in this context") - } - } - } -} - -// `Memory` has to depend on the `Machine` because some of its operations -// (e.g., `get`) call a `Machine` hook. -pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { - /// Allocations local to this instance of the miri engine. The kind - /// helps ensure that the same mechanism is used for allocation and - /// deallocation. When an allocation is not found here, it is a - /// global and looked up in the `tcx` for read access. Some machines may - /// have to mutate this map even on a read-only access to a global (because - /// they do pointer provenance tracking and the allocations in `tcx` have - /// the wrong type), so we let the machine override this type. - /// Either way, if the machine allows writing to a global, doing so will - /// create a copy of the global allocation here. - // FIXME: this should not be public, but interning currently needs access to it - pub(super) alloc_map: M::MemoryMap, - - /// Map for "extra" function pointers. - extra_fn_ptr_map: FxHashMap, - - /// To be able to compare pointers with null, and to check alignment for accesses - /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations - /// that do not exist any more. - // FIXME: this should not be public, but interning currently needs access to it - pub(super) dead_alloc_map: FxHashMap, - - /// Extra data added by the machine. - pub extra: M::MemoryExtra, - - /// Lets us implement `HasDataLayout`, which is awfully convenient. - pub tcx: TyCtxt<'tcx>, -} - -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - &self.tcx.data_layout - } -} - -/// A reference to some allocation that was already bounds-checked for the given region -/// and had the on-access machine hooks run. -#[derive(Copy, Clone)] -pub struct AllocRef<'a, 'tcx, Tag, Extra> { - alloc: &'a Allocation, - range: AllocRange, - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, -} -/// A reference to some allocation that was already bounds-checked for the given region -/// and had the on-access machine hooks run. -pub struct AllocRefMut<'a, 'tcx, Tag, Extra> { - alloc: &'a mut Allocation, - range: AllocRange, - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, -} - -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { - pub fn new(tcx: TyCtxt<'tcx>, extra: M::MemoryExtra) -> Self { - Memory { - alloc_map: M::MemoryMap::default(), - extra_fn_ptr_map: FxHashMap::default(), - dead_alloc_map: FxHashMap::default(), - extra, - tcx, - } - } - - /// Call this to turn untagged "global" pointers (obtained via `tcx`) into - /// the machine pointer to the allocation. Must never be used - /// for any other pointers, nor for TLS statics. - /// - /// Using the resulting pointer represents a *direct* access to that memory - /// (e.g. by directly using a `static`), - /// as opposed to access through a pointer that was created by the program. - /// - /// This function can fail only if `ptr` points to an `extern static`. - #[inline] - pub fn global_base_pointer( - &self, - ptr: Pointer, - ) -> InterpResult<'tcx, Pointer> { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (alloc_id, offset) = ptr.into_parts(); - // We need to handle `extern static`. - match self.tcx.get_global_alloc(alloc_id) { - Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => { - bug!("global memory cannot point to thread-local static") - } - Some(GlobalAlloc::Static(def_id)) if self.tcx.is_foreign_item(def_id) => { - return M::extern_static_base_pointer(self, def_id); - } - _ => {} - } - // And we need to get the tag. - Ok(M::tag_alloc_base_pointer(self, Pointer::new(alloc_id, offset))) - } - - pub fn create_fn_alloc( - &mut self, - fn_val: FnVal<'tcx, M::ExtraFnVal>, - ) -> Pointer { - let id = match fn_val { - FnVal::Instance(instance) => self.tcx.create_fn_alloc(instance), - FnVal::Other(extra) => { - // FIXME(RalfJung): Should we have a cache here? - let id = self.tcx.reserve_alloc_id(); - let old = self.extra_fn_ptr_map.insert(id, extra); - assert!(old.is_none()); - id - } - }; - // Functions are global allocations, so make sure we get the right base pointer. - // We know this is not an `extern static` so this cannot fail. - self.global_base_pointer(Pointer::from(id)).unwrap() - } - - pub fn allocate( - &mut self, - size: Size, - align: Align, - kind: MemoryKind, - ) -> InterpResult<'static, Pointer> { - let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?; - Ok(self.allocate_with(alloc, kind)) - } - - pub fn allocate_bytes( - &mut self, - bytes: &[u8], - align: Align, - kind: MemoryKind, - mutability: Mutability, - ) -> Pointer { - let alloc = Allocation::from_bytes(bytes, align, mutability); - self.allocate_with(alloc, kind) - } - - pub fn allocate_with( - &mut self, - alloc: Allocation, - kind: MemoryKind, - ) -> Pointer { - let id = self.tcx.reserve_alloc_id(); - debug_assert_ne!( - Some(kind), - M::GLOBAL_KIND.map(MemoryKind::Machine), - "dynamically allocating global memory" - ); - let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind)); - self.alloc_map.insert(id, (kind, alloc.into_owned())); - M::tag_alloc_base_pointer(self, Pointer::from(id)) - } - - pub fn reallocate( - &mut self, - ptr: Pointer>, - old_size_and_align: Option<(Size, Align)>, - new_size: Size, - new_align: Align, - kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { - let (alloc_id, offset, ptr) = self.ptr_get_alloc(ptr)?; - if offset.bytes() != 0 { - throw_ub_format!( - "reallocating {:?} which does not point to the beginning of an object", - ptr - ); - } - - // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc". - // This happens so rarely, the perf advantage is outweighed by the maintenance cost. - let new_ptr = self.allocate(new_size, new_align, kind)?; - let old_size = match old_size_and_align { - Some((size, _align)) => size, - None => self.get_raw(alloc_id)?.size(), - }; - // This will also call the access hooks. - self.copy( - ptr.into(), - Align::ONE, - new_ptr.into(), - Align::ONE, - old_size.min(new_size), - /*nonoverlapping*/ true, - )?; - self.deallocate(ptr.into(), old_size_and_align, kind)?; - - Ok(new_ptr) - } - - pub fn deallocate( - &mut self, - ptr: Pointer>, - old_size_and_align: Option<(Size, Align)>, - kind: MemoryKind, - ) -> InterpResult<'tcx> { - let (alloc_id, offset, ptr) = self.ptr_get_alloc(ptr)?; - trace!("deallocating: {}", alloc_id); - - if offset.bytes() != 0 { - throw_ub_format!( - "deallocating {:?} which does not point to the beginning of an object", - ptr - ); - } - - let (alloc_kind, mut alloc) = match self.alloc_map.remove(&alloc_id) { - Some(alloc) => alloc, - None => { - // Deallocating global memory -- always an error - return Err(match self.tcx.get_global_alloc(alloc_id) { - Some(GlobalAlloc::Function(..)) => { - err_ub_format!("deallocating {}, which is a function", alloc_id) - } - Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { - err_ub_format!("deallocating {}, which is static memory", alloc_id) - } - None => err_ub!(PointerUseAfterFree(alloc_id)), - } - .into()); - } - }; - - if alloc.mutability == Mutability::Not { - throw_ub_format!("deallocating immutable allocation {}", alloc_id); - } - if alloc_kind != kind { - throw_ub_format!( - "deallocating {}, which is {} memory, using {} deallocation operation", - alloc_id, - alloc_kind, - kind - ); - } - if let Some((size, align)) = old_size_and_align { - if size != alloc.size() || align != alloc.align { - throw_ub_format!( - "incorrect layout on deallocation: {} has size {} and alignment {}, but gave size {} and alignment {}", - alloc_id, - alloc.size().bytes(), - alloc.align.bytes(), - size.bytes(), - align.bytes(), - ) - } - } - - // Let the machine take some extra action - let size = alloc.size(); - M::memory_deallocated( - &mut self.extra, - &mut alloc.extra, - ptr.provenance, - alloc_range(Size::ZERO, size), - )?; - - // Don't forget to remember size and align of this now-dead allocation - let old = self.dead_alloc_map.insert(alloc_id, (size, alloc.align)); - if old.is_some() { - bug!("Nothing can be deallocated twice"); - } - - Ok(()) - } - - /// Internal helper function to determine the allocation and offset of a pointer (if any). - #[inline(always)] - fn get_ptr_access( - &self, - ptr: Pointer>, - size: Size, - align: Align, - ) -> InterpResult<'tcx, Option<(AllocId, Size, Pointer)>> { - let align = M::enforce_alignment(&self.extra).then_some(align); - self.check_and_deref_ptr( - ptr, - size, - align, - CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, ptr| { - let (size, align) = - self.get_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; - Ok((size, align, (alloc_id, offset, ptr))) - }, - ) - } - - /// Check if the given pointer points to live memory of given `size` and `align` - /// (ignoring `M::enforce_alignment`). The caller can control the error message for the - /// out-of-bounds case. - #[inline(always)] - pub fn check_ptr_access_align( - &self, - ptr: Pointer>, - size: Size, - align: Align, - msg: CheckInAllocMsg, - ) -> InterpResult<'tcx> { - self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| { - let check = match msg { - CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => { - AllocCheck::Dereferenceable - } - CheckInAllocMsg::PointerArithmeticTest | CheckInAllocMsg::InboundsTest => { - AllocCheck::Live - } - }; - let (size, align) = self.get_size_and_align(alloc_id, check)?; - Ok((size, align, ())) - })?; - Ok(()) - } - - /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference - /// to the allocation it points to. Supports both shared and mutable references, as the actual - /// checking is offloaded to a helper closure. `align` defines whether and which alignment check - /// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned. - fn check_and_deref_ptr( - &self, - ptr: Pointer>, - size: Size, - align: Option, - msg: CheckInAllocMsg, - alloc_size: impl FnOnce( - AllocId, - Size, - Pointer, - ) -> InterpResult<'tcx, (Size, Align, T)>, - ) -> InterpResult<'tcx, Option> { - fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> { - if offset % align.bytes() == 0 { - Ok(()) - } else { - // The biggest power of two through which `offset` is divisible. - let offset_pow2 = 1 << offset.trailing_zeros(); - throw_ub!(AlignmentCheckFailed { - has: Align::from_bytes(offset_pow2).unwrap(), - required: align, - }) - } - } - - // Extract from the pointer an `Option` and an offset, which is relative to the - // allocation or (if that is `None`) an absolute address. - let ptr_or_addr = if size.bytes() == 0 { - // Let's see what we can do, but don't throw errors if there's nothing there. - self.ptr_try_get_alloc(ptr) - } else { - // A "real" access, we insist on getting an `AllocId`. - Ok(self.ptr_get_alloc(ptr)?) - }; - Ok(match ptr_or_addr { - Err(addr) => { - // No memory is actually being accessed. - debug_assert!(size.bytes() == 0); - // Must be non-null. - if addr == 0 { - throw_ub!(DanglingIntPointer(0, msg)) - } - // Must be aligned. - if let Some(align) = align { - check_offset_align(addr, align)?; - } - None - } - Ok((alloc_id, offset, ptr)) => { - let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, ptr)?; - // Test bounds. This also ensures non-null. - // It is sufficient to check this for the end pointer. Also check for overflow! - if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { - throw_ub!(PointerOutOfBounds { - alloc_id, - alloc_size, - ptr_offset: self.machine_usize_to_isize(offset.bytes()), - ptr_size: size, - msg, - }) - } - // Test align. Check this last; if both bounds and alignment are violated - // we want the error to be about the bounds. - if let Some(align) = align { - if M::force_int_for_alignment_check(&self.extra) { - let addr = Scalar::from_pointer(ptr, &self.tcx) - .to_machine_usize(&self.tcx) - .expect("ptr-to-int cast for align check should never fail"); - check_offset_align(addr, align)?; - } else { - // Check allocation alignment and offset alignment. - if alloc_align.bytes() < align.bytes() { - throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align }); - } - check_offset_align(offset.bytes(), align)?; - } - } - - // We can still be zero-sized in this branch, in which case we have to - // return `None`. - if size.bytes() == 0 { None } else { Some(ret_val) } - } - }) - } - - /// Test if the pointer might be null. - pub fn ptr_may_be_null(&self, ptr: Pointer>) -> bool { - match self.ptr_try_get_alloc(ptr) { - Ok((alloc_id, offset, _)) => { - let (size, _align) = self - .get_size_and_align(alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail"); - // If the pointer is out-of-bounds, it may be null. - // Note that one-past-the-end (offset == size) is still inbounds, and never null. - offset > size - } - Err(offset) => offset == 0, - } - } -} - -/// Allocation accessors -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { - /// Helper function to obtain a global (tcx) allocation. - /// This attempts to return a reference to an existing allocation if - /// one can be found in `tcx`. That, however, is only possible if `tcx` and - /// this machine use the same pointer tag, so it is indirected through - /// `M::tag_allocation`. - fn get_global_alloc( - &self, - id: AllocId, - is_write: bool, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - let (alloc, def_id) = match self.tcx.get_global_alloc(id) { - Some(GlobalAlloc::Memory(mem)) => { - // Memory of a constant or promoted or anonymous memory referenced by a static. - (mem, None) - } - Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), - None => throw_ub!(PointerUseAfterFree(id)), - Some(GlobalAlloc::Static(def_id)) => { - assert!(self.tcx.is_static(def_id)); - assert!(!self.tcx.is_thread_local_static(def_id)); - // Notice that every static has two `AllocId` that will resolve to the same - // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID, - // and the other one is maps to `GlobalAlloc::Memory`, this is returned by - // `eval_static_initializer` and it is the "resolved" ID. - // The resolved ID is never used by the interpreted program, it is hidden. - // This is relied upon for soundness of const-patterns; a pointer to the resolved - // ID would "sidestep" the checks that make sure consts do not point to statics! - // The `GlobalAlloc::Memory` branch here is still reachable though; when a static - // contains a reference to memory that was created during its evaluation (i.e., not - // to another static), those inner references only exist in "resolved" form. - if self.tcx.is_foreign_item(def_id) { - throw_unsup!(ReadExternStatic(def_id)); - } - - (self.tcx.eval_static_initializer(def_id)?, Some(def_id)) - } - }; - M::before_access_global(&self.extra, id, alloc, def_id, is_write)?; - let alloc = Cow::Borrowed(alloc); - // We got tcx memory. Let the machine initialize its "extra" stuff. - let alloc = M::init_allocation_extra( - self, - id, // always use the ID we got as input, not the "hidden" one. - alloc, - M::GLOBAL_KIND.map(MemoryKind::Machine), - ); - Ok(alloc) - } - - /// Gives raw access to the `Allocation`, without bounds or alignment checks. - /// The caller is responsible for calling the access hooks! - fn get_raw( - &self, - id: AllocId, - ) -> InterpResult<'tcx, &Allocation> { - // The error type of the inner closure here is somewhat funny. We have two - // ways of "erroring": An actual error, or because we got a reference from - // `get_global_alloc` that we can actually use directly without inserting anything anywhere. - // So the error type is `InterpResult<'tcx, &Allocation>`. - let a = self.alloc_map.get_or(id, || { - let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?; - match alloc { - Cow::Borrowed(alloc) => { - // We got a ref, cheaply return that as an "error" so that the - // map does not get mutated. - Err(Ok(alloc)) - } - Cow::Owned(alloc) => { - // Need to put it into the map and return a ref to that - let kind = M::GLOBAL_KIND.expect( - "I got a global allocation that I have to copy but the machine does \ - not expect that to happen", - ); - Ok((MemoryKind::Machine(kind), alloc)) - } - } - }); - // Now unpack that funny error type - match a { - Ok(a) => Ok(&a.1), - Err(a) => a, - } - } - - /// "Safe" (bounds and align-checked) allocation access. - pub fn get<'a>( - &'a self, - ptr: Pointer>, - size: Size, - align: Align, - ) -> InterpResult<'tcx, Option>> { - let align = M::enforce_alignment(&self.extra).then_some(align); - let ptr_and_alloc = self.check_and_deref_ptr( - ptr, - size, - align, - CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, ptr| { - let alloc = self.get_raw(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, ptr, alloc))) - }, - )?; - if let Some((alloc_id, offset, ptr, alloc)) = ptr_and_alloc { - let range = alloc_range(offset, size); - M::memory_read(&self.extra, &alloc.extra, ptr.provenance, range)?; - Ok(Some(AllocRef { alloc, range, tcx: self.tcx, alloc_id })) - } else { - // Even in this branch we have to be sure that we actually access the allocation, in - // order to ensure that `static FOO: Type = FOO;` causes a cycle error instead of - // magically pulling *any* ZST value from the ether. However, the `get_raw` above is - // always called when `ptr` has an `AllocId`. - Ok(None) - } - } - - /// Return the `extra` field of the given allocation. - pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> { - Ok(&self.get_raw(id)?.extra) - } - - /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. - /// The caller is responsible for calling the access hooks! - /// - /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the - /// allocation. - fn get_raw_mut( - &mut self, - id: AllocId, - ) -> InterpResult<'tcx, (&mut Allocation, &mut M::MemoryExtra)> - { - // We have "NLL problem case #3" here, which cannot be worked around without loss of - // efficiency even for the common case where the key is in the map. - // - // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.) - if self.alloc_map.get_mut(id).is_none() { - // Slow path. - // Allocation not found locally, go look global. - let alloc = self.get_global_alloc(id, /*is_write*/ true)?; - let kind = M::GLOBAL_KIND.expect( - "I got a global allocation that I have to copy but the machine does \ - not expect that to happen", - ); - self.alloc_map.insert(id, (MemoryKind::Machine(kind), alloc.into_owned())); - } - - let (_kind, alloc) = self.alloc_map.get_mut(id).unwrap(); - if alloc.mutability == Mutability::Not { - throw_ub!(WriteToReadOnly(id)) - } - Ok((alloc, &mut self.extra)) - } - - /// "Safe" (bounds and align-checked) allocation access. - pub fn get_mut<'a>( - &'a mut self, - ptr: Pointer>, - size: Size, - align: Align, - ) -> InterpResult<'tcx, Option>> { - let parts = self.get_ptr_access(ptr, size, align)?; - if let Some((alloc_id, offset, ptr)) = parts { - let tcx = self.tcx; - // FIXME: can we somehow avoid looking up the allocation twice here? - // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. - let (alloc, extra) = self.get_raw_mut(alloc_id)?; - let range = alloc_range(offset, size); - M::memory_written(extra, &mut alloc.extra, ptr.provenance, range)?; - Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id })) - } else { - Ok(None) - } - } - - /// Return the `extra` field of the given allocation. - pub fn get_alloc_extra_mut<'a>( - &'a mut self, - id: AllocId, - ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M::MemoryExtra)> { - let (alloc, memory_extra) = self.get_raw_mut(id)?; - Ok((&mut alloc.extra, memory_extra)) - } - - /// Obtain the size and alignment of an allocation, even if that allocation has - /// been deallocated. - /// - /// If `liveness` is `AllocCheck::MaybeDead`, this function always returns `Ok`. - pub fn get_size_and_align( - &self, - id: AllocId, - liveness: AllocCheck, - ) -> InterpResult<'static, (Size, Align)> { - // # Regular allocations - // Don't use `self.get_raw` here as that will - // a) cause cycles in case `id` refers to a static - // b) duplicate a global's allocation in miri - if let Some((_, alloc)) = self.alloc_map.get(id) { - return Ok((alloc.size(), alloc.align)); - } - - // # Function pointers - // (both global from `alloc_map` and local from `extra_fn_ptr_map`) - if self.get_fn_alloc(id).is_some() { - return if let AllocCheck::Dereferenceable = liveness { - // The caller requested no function pointers. - throw_ub!(DerefFunctionPointer(id)) - } else { - Ok((Size::ZERO, Align::ONE)) - }; - } - - // # Statics - // Can't do this in the match argument, we may get cycle errors since the lock would - // be held throughout the match. - match self.tcx.get_global_alloc(id) { - Some(GlobalAlloc::Static(did)) => { - assert!(!self.tcx.is_thread_local_static(did)); - // Use size and align of the type. - let ty = self.tcx.type_of(did); - let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); - Ok((layout.size, layout.align.abi)) - } - Some(GlobalAlloc::Memory(alloc)) => { - // Need to duplicate the logic here, because the global allocations have - // different associated types than the interpreter-local ones. - Ok((alloc.size(), alloc.align)) - } - Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), - // The rest must be dead. - None => { - if let AllocCheck::MaybeDead = liveness { - // Deallocated pointers are allowed, we should be able to find - // them in the map. - Ok(*self - .dead_alloc_map - .get(&id) - .expect("deallocated pointers should all be recorded in `dead_alloc_map`")) - } else { - throw_ub!(PointerUseAfterFree(id)) - } - } - } - } - - fn get_fn_alloc(&self, id: AllocId) -> Option> { - if let Some(extra) = self.extra_fn_ptr_map.get(&id) { - Some(FnVal::Other(*extra)) - } else { - match self.tcx.get_global_alloc(id) { - Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), - _ => None, - } - } - } - - pub fn get_fn( - &self, - ptr: Pointer>, - ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { - trace!("get_fn({:?})", ptr); - let (alloc_id, offset, _ptr) = self.ptr_get_alloc(ptr)?; - if offset.bytes() != 0 { - throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) - } - self.get_fn_alloc(alloc_id) - .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) - } - - pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { - self.get_raw_mut(id)?.0.mutability = Mutability::Not; - Ok(()) - } - - /// Create a lazy debug printer that prints the given allocation and all allocations it points - /// to, recursively. - #[must_use] - pub fn dump_alloc<'a>(&'a self, id: AllocId) -> DumpAllocs<'a, 'mir, 'tcx, M> { - self.dump_allocs(vec![id]) - } - - /// Create a lazy debug printer for a list of allocations and all allocations they point to, - /// recursively. - #[must_use] - pub fn dump_allocs<'a>(&'a self, mut allocs: Vec) -> DumpAllocs<'a, 'mir, 'tcx, M> { - allocs.sort(); - allocs.dedup(); - DumpAllocs { mem: self, allocs } - } - - /// Print leaked memory. Allocations reachable from `static_roots` or a `Global` allocation - /// are not considered leaked. Leaks whose kind `may_leak()` returns true are not reported. - pub fn leak_report(&self, static_roots: &[AllocId]) -> usize { - // Collect the set of allocations that are *reachable* from `Global` allocations. - let reachable = { - let mut reachable = FxHashSet::default(); - let global_kind = M::GLOBAL_KIND.map(MemoryKind::Machine); - let mut todo: Vec<_> = self.alloc_map.filter_map_collect(move |&id, &(kind, _)| { - if Some(kind) == global_kind { Some(id) } else { None } - }); - todo.extend(static_roots); - while let Some(id) = todo.pop() { - if reachable.insert(id) { - // This is a new allocation, add its relocations to `todo`. - if let Some((_, alloc)) = self.alloc_map.get(id) { - todo.extend(alloc.relocations().values().map(|tag| tag.get_alloc_id())); - } - } - } - reachable - }; - - // All allocations that are *not* `reachable` and *not* `may_leak` are considered leaking. - let leaks: Vec<_> = self.alloc_map.filter_map_collect(|&id, &(kind, _)| { - if kind.may_leak() || reachable.contains(&id) { None } else { Some(id) } - }); - let n = leaks.len(); - if n > 0 { - eprintln!("The following memory was leaked: {:?}", self.dump_allocs(leaks)); - } - n - } - - /// This is used by [priroda](https://github.com/oli-obk/priroda) - pub fn alloc_map(&self) -> &M::MemoryMap { - &self.alloc_map - } -} - -#[doc(hidden)] -/// There's no way to use this directly, it's just a helper struct for the `dump_alloc(s)` methods. -pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { - mem: &'a Memory<'mir, 'tcx, M>, - allocs: Vec, -} - -impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Cannot be a closure because it is generic in `Tag`, `Extra`. - fn write_allocation_track_relocs<'tcx, Tag: Provenance, Extra>( - fmt: &mut std::fmt::Formatter<'_>, - tcx: TyCtxt<'tcx>, - allocs_to_print: &mut VecDeque, - alloc: &Allocation, - ) -> std::fmt::Result { - for alloc_id in alloc.relocations().values().map(|tag| tag.get_alloc_id()) { - allocs_to_print.push_back(alloc_id); - } - write!(fmt, "{}", pretty::display_allocation(tcx, alloc)) - } - - let mut allocs_to_print: VecDeque<_> = self.allocs.iter().copied().collect(); - // `allocs_printed` contains all allocations that we have already printed. - let mut allocs_printed = FxHashSet::default(); - - while let Some(id) = allocs_to_print.pop_front() { - if !allocs_printed.insert(id) { - // Already printed, so skip this. - continue; - } - - write!(fmt, "{}", id)?; - match self.mem.alloc_map.get(id) { - Some(&(kind, ref alloc)) => { - // normal alloc - write!(fmt, " ({}, ", kind)?; - write_allocation_track_relocs( - &mut *fmt, - self.mem.tcx, - &mut allocs_to_print, - alloc, - )?; - } - None => { - // global alloc - match self.mem.tcx.get_global_alloc(id) { - Some(GlobalAlloc::Memory(alloc)) => { - write!(fmt, " (unchanged global, ")?; - write_allocation_track_relocs( - &mut *fmt, - self.mem.tcx, - &mut allocs_to_print, - alloc, - )?; - } - Some(GlobalAlloc::Function(func)) => { - write!(fmt, " (fn: {})", func)?; - } - Some(GlobalAlloc::Static(did)) => { - write!(fmt, " (static: {})", self.mem.tcx.def_path_str(did))?; - } - None => { - write!(fmt, " (deallocated)")?; - } - } - } - } - writeln!(fmt)?; - } - Ok(()) - } -} - -/// Reading and writing. -impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { - pub fn write_scalar( - &mut self, - range: AllocRange, - val: ScalarMaybeUninit, - ) -> InterpResult<'tcx> { - Ok(self - .alloc - .write_scalar(&self.tcx, self.range.subrange(range), val) - .map_err(|e| e.to_interp_error(self.alloc_id))?) - } - - pub fn write_ptr_sized( - &mut self, - offset: Size, - val: ScalarMaybeUninit, - ) -> InterpResult<'tcx> { - self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) - } -} - -impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { - pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit> { - Ok(self - .alloc - .read_scalar(&self.tcx, self.range.subrange(range)) - .map_err(|e| e.to_interp_error(self.alloc_id))?) - } - - pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit> { - self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size)) - } - - pub fn check_bytes(&self, range: AllocRange, allow_uninit_and_ptr: bool) -> InterpResult<'tcx> { - Ok(self - .alloc - .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit_and_ptr) - .map_err(|e| e.to_interp_error(self.alloc_id))?) - } -} - -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { - /// Reads the given number of bytes from memory. Returns them as a slice. - /// - /// Performs appropriate bounds checks. - pub fn read_bytes( - &self, - ptr: Pointer>, - size: Size, - ) -> InterpResult<'tcx, &[u8]> { - let alloc_ref = match self.get(ptr, size, Align::ONE)? { - Some(a) => a, - None => return Ok(&[]), // zero-sized access - }; - // Side-step AllocRef and directly access the underlying bytes more efficiently. - // (We are staying inside the bounds here so all is good.) - Ok(alloc_ref - .alloc - .get_bytes(&alloc_ref.tcx, alloc_ref.range) - .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?) - } - - /// Writes the given stream of bytes into memory. - /// - /// Performs appropriate bounds checks. - pub fn write_bytes( - &mut self, - ptr: Pointer>, - src: impl IntoIterator, - ) -> InterpResult<'tcx> { - let mut src = src.into_iter(); - let (lower, upper) = src.size_hint(); - let len = upper.expect("can only write bounded iterators"); - assert_eq!(lower, len, "can only write iterators with a precise length"); - - let size = Size::from_bytes(len); - let alloc_ref = match self.get_mut(ptr, size, Align::ONE)? { - Some(alloc_ref) => alloc_ref, - None => { - // zero-sized access - assert_matches!( - src.next(), - None, - "iterator said it was empty but returned an element" - ); - return Ok(()); - } - }; - - // Side-step AllocRef and directly access the underlying bytes more efficiently. - // (We are staying inside the bounds here so all is good.) - let alloc_id = alloc_ref.alloc_id; - let bytes = alloc_ref - .alloc - .get_bytes_mut(&alloc_ref.tcx, alloc_ref.range) - .map_err(move |e| e.to_interp_error(alloc_id))?; - // `zip` would stop when the first iterator ends; we want to definitely - // cover all of `bytes`. - for dest in bytes { - *dest = src.next().expect("iterator was shorter than it said it would be"); - } - assert_matches!(src.next(), None, "iterator was longer than it said it would be"); - Ok(()) - } - - pub fn copy( - &mut self, - src: Pointer>, - src_align: Align, - dest: Pointer>, - dest_align: Align, - size: Size, - nonoverlapping: bool, - ) -> InterpResult<'tcx> { - self.copy_repeatedly(src, src_align, dest, dest_align, size, 1, nonoverlapping) - } - - pub fn copy_repeatedly( - &mut self, - src: Pointer>, - src_align: Align, - dest: Pointer>, - dest_align: Align, - size: Size, - num_copies: u64, - nonoverlapping: bool, - ) -> InterpResult<'tcx> { - let tcx = self.tcx; - // We need to do our own bounds-checks. - let src_parts = self.get_ptr_access(src, size, src_align)?; - let dest_parts = self.get_ptr_access(dest, size * num_copies, dest_align)?; // `Size` multiplication - - // FIXME: we look up both allocations twice here, once ebfore for the `check_ptr_access` - // and once below to get the underlying `&[mut] Allocation`. - - // Source alloc preparations and access hooks. - let (src_alloc_id, src_offset, src) = match src_parts { - None => return Ok(()), // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do. - Some(src_ptr) => src_ptr, - }; - let src_alloc = self.get_raw(src_alloc_id)?; - let src_range = alloc_range(src_offset, size); - M::memory_read(&self.extra, &src_alloc.extra, src.provenance, src_range)?; - // We need the `dest` ptr for the next operation, so we get it now. - // We already did the source checks and called the hooks so we are good to return early. - let (dest_alloc_id, dest_offset, dest) = match dest_parts { - None => return Ok(()), // Zero-sized *destiantion*. - Some(dest_ptr) => dest_ptr, - }; - - // first copy the relocations to a temporary buffer, because - // `get_bytes_mut` will clear the relocations, which is correct, - // since we don't want to keep any relocations at the target. - // (`get_bytes_with_uninit_and_ptr` below checks that there are no - // relocations overlapping the edges; those would not be handled correctly). - let relocations = - src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies); - // Prepare a copy of the initialization mask. - let compressed = src_alloc.compress_uninit_range(src_range); - // This checks relocation edges on the src. - let src_bytes = src_alloc - .get_bytes_with_uninit_and_ptr(&tcx, src_range) - .map_err(|e| e.to_interp_error(src_alloc_id))? - .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation - - // Destination alloc preparations and access hooks. - let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?; - let dest_range = alloc_range(dest_offset, size * num_copies); - M::memory_written(extra, &mut dest_alloc.extra, dest.provenance, dest_range)?; - let dest_bytes = dest_alloc - .get_bytes_mut_ptr(&tcx, dest_range) - .map_err(|e| e.to_interp_error(dest_alloc_id))? - .as_mut_ptr(); - - if compressed.no_bytes_init() { - // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range - // is marked as uninitialized but we otherwise omit changing the byte representation which may - // be arbitrary for uninitialized bytes. - // This also avoids writing to the target bytes so that the backing allocation is never - // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary - // operating system this can avoid physically allocating the page. - dest_alloc.mark_init(dest_range, false); // `Size` multiplication - dest_alloc.mark_relocation_range(relocations); - return Ok(()); - } - - // SAFE: The above indexing would have panicked if there weren't at least `size` bytes - // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and - // `dest` could possibly overlap. - // The pointers above remain valid even if the `HashMap` table is moved around because they - // point into the `Vec` storing the bytes. - unsafe { - if src_alloc_id == dest_alloc_id { - if nonoverlapping { - // `Size` additions - if (src_offset <= dest_offset && src_offset + size > dest_offset) - || (dest_offset <= src_offset && dest_offset + size > src_offset) - { - throw_ub_format!("copy_nonoverlapping called on overlapping ranges") - } - } - - for i in 0..num_copies { - ptr::copy( - src_bytes, - dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication - size.bytes_usize(), - ); - } - } else { - for i in 0..num_copies { - ptr::copy_nonoverlapping( - src_bytes, - dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication - size.bytes_usize(), - ); - } - } - } - - // now fill in all the "init" data - dest_alloc.mark_compressed_init_range( - &compressed, - alloc_range(dest_offset, size), // just a single copy (i.e., not full `dest_range`) - num_copies, - ); - // copy the relocations to the destination - dest_alloc.mark_relocation_range(relocations); - - Ok(()) - } -} - -/// Machine pointer introspection. -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { - pub fn scalar_to_ptr(&self, scalar: Scalar) -> Pointer> { - // We use `to_bits_or_ptr_internal` since we are just implementing the method people need to - // call to force getting out a pointer. - match scalar.to_bits_or_ptr_internal(self.pointer_size()) { - Err(ptr) => ptr.into(), - Ok(bits) => { - let addr = u64::try_from(bits).unwrap(); - let ptr = M::ptr_from_addr(&self, addr); - if addr == 0 { - assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId"); - } - ptr - } - } - } - - /// Turning a "maybe pointer" into a proper pointer (and some information - /// about where it points), or an absolute address. - pub fn ptr_try_get_alloc( - &self, - ptr: Pointer>, - ) -> Result<(AllocId, Size, Pointer), u64> { - match ptr.into_pointer_or_addr() { - Ok(ptr) => { - let (alloc_id, offset) = M::ptr_get_alloc(self, ptr); - Ok((alloc_id, offset, ptr)) - } - Err(addr) => Err(addr.bytes()), - } - } - - /// Turning a "maybe pointer" into a proper pointer (and some information about where it points). - #[inline(always)] - pub fn ptr_get_alloc( - &self, - ptr: Pointer>, - ) -> InterpResult<'tcx, (AllocId, Size, Pointer)> { - self.ptr_try_get_alloc(ptr).map_err(|offset| { - err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into() - }) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -//! An interpreter for MIR used in CTFE and by miri - -mod cast; -mod eval_context; -mod intern; -mod intrinsics; -mod machine; -mod memory; -mod operand; -mod operator; -mod place; -mod step; -mod terminator; -mod traits; -mod util; -mod validity; -mod visitor; - -pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here - -pub use self::eval_context::{ - Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind, -}; -pub use self::intern::{intern_const_alloc_recursive, InternKind}; -pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; -pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; -pub use self::operand::{ImmTy, Immediate, OpTy, Operand}; -pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; -pub use self::validity::{CtfeValidationMode, RefTracking}; -pub use self::visitor::{MutValueVisitor, ValueVisitor}; - -crate use self::intrinsics::eval_nullary_intrinsic; -use eval_context::{from_known_layout, mir_assign_valid_types}; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/operand.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/operand.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/operand.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/operand.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,762 +0,0 @@ -//! Functions concerning immediate values and operands, and reading from operands. -//! All high-level functions to read from memory work on operands as sources. - -use std::convert::TryFrom; -use std::fmt::Write; - -use rustc_errors::ErrorReported; -use rustc_hir::def::Namespace; -use rustc_macros::HashStable; -use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; -use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; -use rustc_middle::ty::{ConstInt, Ty}; -use rustc_middle::{mir, ty}; -use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding}; -use rustc_target::abi::{VariantIdx, Variants}; - -use super::{ - alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId, - InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Provenance, - Scalar, ScalarMaybeUninit, -}; - -/// An `Immediate` represents a single immediate self-contained Rust value. -/// -/// For optimization of a few very common cases, there is also a representation for a pair of -/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary -/// operations and wide pointers. This idea was taken from rustc's codegen. -/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely -/// defined on `Immediate`, and do not have to work with a `Place`. -#[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)] -pub enum Immediate { - Scalar(ScalarMaybeUninit), - ScalarPair(ScalarMaybeUninit, ScalarMaybeUninit), -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Immediate, 56); - -impl From> for Immediate { - #[inline(always)] - fn from(val: ScalarMaybeUninit) -> Self { - Immediate::Scalar(val) - } -} - -impl From> for Immediate { - #[inline(always)] - fn from(val: Scalar) -> Self { - Immediate::Scalar(val.into()) - } -} - -impl<'tcx, Tag: Provenance> Immediate { - pub fn from_pointer(p: Pointer, cx: &impl HasDataLayout) -> Self { - Immediate::Scalar(ScalarMaybeUninit::from_pointer(p, cx)) - } - - pub fn from_maybe_pointer(p: Pointer>, cx: &impl HasDataLayout) -> Self { - Immediate::Scalar(ScalarMaybeUninit::from_maybe_pointer(p, cx)) - } - - pub fn new_slice(val: Scalar, len: u64, cx: &impl HasDataLayout) -> Self { - Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into()) - } - - pub fn new_dyn_trait( - val: Scalar, - vtable: Pointer>, - cx: &impl HasDataLayout, - ) -> Self { - Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx)) - } - - #[inline] - pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit { - match self { - Immediate::Scalar(val) => val, - Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"), - } - } - - #[inline] - pub fn to_scalar(self) -> InterpResult<'tcx, Scalar> { - self.to_scalar_or_uninit().check_init() - } - - #[inline] - pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { - match self { - Immediate::ScalarPair(val1, val2) => Ok((val1.check_init()?, val2.check_init()?)), - Immediate::Scalar(..) => { - bug!("Got a scalar where a scalar pair was expected") - } - } - } -} - -// ScalarPair needs a type to interpret, so we often have an immediate and a type together -// as input for binary and cast operations. -#[derive(Copy, Clone, Debug)] -pub struct ImmTy<'tcx, Tag: Provenance = AllocId> { - imm: Immediate, - pub layout: TyAndLayout<'tcx>, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(ImmTy<'_>, 72); - -impl std::fmt::Display for ImmTy<'tcx, Tag> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// Helper function for printing a scalar to a FmtPrinter - fn p<'a, 'tcx, F: std::fmt::Write, Tag: Provenance>( - cx: FmtPrinter<'a, 'tcx, F>, - s: ScalarMaybeUninit, - ty: Ty<'tcx>, - ) -> Result, std::fmt::Error> { - match s { - ScalarMaybeUninit::Scalar(Scalar::Int(int)) => { - cx.pretty_print_const_scalar_int(int, ty, true) - } - ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _sz)) => { - // Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to - // print what is points to, which would fail since it has no access to the local - // memory. - cx.pretty_print_const_pointer(ptr, ty, true) - } - ScalarMaybeUninit::Uninit => cx.typed_value( - |mut this| { - this.write_str("uninit ")?; - Ok(this) - }, - |this| this.print_type(ty), - " ", - ), - } - } - ty::tls::with(|tcx| { - match self.imm { - Immediate::Scalar(s) => { - if let Some(ty) = tcx.lift(self.layout.ty) { - let cx = FmtPrinter::new(tcx, f, Namespace::ValueNS); - p(cx, s, ty)?; - return Ok(()); - } - write!(f, "{}: {}", s, self.layout.ty) - } - Immediate::ScalarPair(a, b) => { - // FIXME(oli-obk): at least print tuples and slices nicely - write!(f, "({}, {}): {}", a, b, self.layout.ty,) - } - } - }) - } -} - -impl<'tcx, Tag: Provenance> std::ops::Deref for ImmTy<'tcx, Tag> { - type Target = Immediate; - #[inline(always)] - fn deref(&self) -> &Immediate { - &self.imm - } -} - -/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate, -/// or still in memory. The latter is an optimization, to delay reading that chunk of -/// memory and to avoid having to store arbitrary-sized data here. -#[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)] -pub enum Operand { - Immediate(Immediate), - Indirect(MemPlace), -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct OpTy<'tcx, Tag: Provenance = AllocId> { - op: Operand, // Keep this private; it helps enforce invariants. - pub layout: TyAndLayout<'tcx>, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(OpTy<'_>, 80); - -impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> { - type Target = Operand; - #[inline(always)] - fn deref(&self) -> &Operand { - &self.op - } -} - -impl<'tcx, Tag: Provenance> From> for OpTy<'tcx, Tag> { - #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { - OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout } - } -} - -impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { - #[inline(always)] - fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { - OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout } - } -} - -impl<'tcx, Tag: Provenance> From> for OpTy<'tcx, Tag> { - #[inline(always)] - fn from(val: ImmTy<'tcx, Tag>) -> Self { - OpTy { op: Operand::Immediate(val.imm), layout: val.layout } - } -} - -impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { - #[inline] - pub fn from_scalar(val: Scalar, layout: TyAndLayout<'tcx>) -> Self { - ImmTy { imm: val.into(), layout } - } - - #[inline] - pub fn from_immediate(imm: Immediate, layout: TyAndLayout<'tcx>) -> Self { - ImmTy { imm, layout } - } - - #[inline] - pub fn try_from_uint(i: impl Into, layout: TyAndLayout<'tcx>) -> Option { - Some(Self::from_scalar(Scalar::try_from_uint(i, layout.size)?, layout)) - } - #[inline] - pub fn from_uint(i: impl Into, layout: TyAndLayout<'tcx>) -> Self { - Self::from_scalar(Scalar::from_uint(i, layout.size), layout) - } - - #[inline] - pub fn try_from_int(i: impl Into, layout: TyAndLayout<'tcx>) -> Option { - Some(Self::from_scalar(Scalar::try_from_int(i, layout.size)?, layout)) - } - - #[inline] - pub fn from_int(i: impl Into, layout: TyAndLayout<'tcx>) -> Self { - Self::from_scalar(Scalar::from_int(i, layout.size), layout) - } - - #[inline] - pub fn to_const_int(self) -> ConstInt { - assert!(self.layout.ty.is_integral()); - let int = self.to_scalar().expect("to_const_int doesn't work on scalar pairs").assert_int(); - ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral()) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. - /// Returns `None` if the layout does not permit loading this as a value. - fn try_read_immediate_from_mplace( - &self, - mplace: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Option>> { - if mplace.layout.is_unsized() { - // Don't touch unsized - return Ok(None); - } - - let alloc = match self.get_alloc(mplace)? { - Some(ptr) => ptr, - None => { - return Ok(Some(ImmTy { - // zero-sized type - imm: Scalar::ZST.into(), - layout: mplace.layout, - })); - } - }; - - match mplace.layout.abi { - Abi::Scalar(..) => { - let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?; - Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })) - } - Abi::ScalarPair(ref a, ref b) => { - // We checked `ptr_align` above, so all fields will have the alignment they need. - // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, - // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. - let (a, b) = (&a.value, &b.value); - let (a_size, b_size) = (a.size(self), b.size(self)); - let b_offset = a_size.align_to(b.align(self).abi); - assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields - let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?; - let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?; - Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })) - } - _ => Ok(None), - } - } - - /// Try returning an immediate for the operand. - /// If the layout does not permit loading this as an immediate, return where in memory - /// we can find the data. - /// Note that for a given layout, this operation will either always fail or always - /// succeed! Whether it succeeds depends on whether the layout can be represented - /// in an `Immediate`, not on which data is stored there currently. - pub(crate) fn try_read_immediate( - &self, - src: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::PointerTag>>> { - Ok(match src.try_as_mplace() { - Ok(ref mplace) => { - if let Some(val) = self.try_read_immediate_from_mplace(mplace)? { - Ok(val) - } else { - Err(*mplace) - } - } - Err(val) => Ok(val), - }) - } - - /// Read an immediate from a place, asserting that that is possible with the given layout. - #[inline(always)] - pub fn read_immediate( - &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { - if let Ok(imm) = self.try_read_immediate(op)? { - Ok(imm) - } else { - span_bug!(self.cur_span(), "primitive read failed for type: {:?}", op.layout.ty); - } - } - - /// Read a scalar from a place - pub fn read_scalar( - &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - Ok(self.read_immediate(op)?.to_scalar_or_uninit()) - } - - /// Read a pointer from a place. - pub fn read_pointer( - &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Pointer>> { - Ok(self.scalar_to_ptr(self.read_scalar(op)?.check_init()?)) - } - - // Turn the wide MPlace into a string (must already be dereferenced!) - pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { - let len = mplace.len(self)?; - let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?; - let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; - Ok(str) - } - - /// Projection functions - pub fn operand_field( - &self, - op: &OpTy<'tcx, M::PointerTag>, - field: usize, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let base = match op.try_as_mplace() { - Ok(ref mplace) => { - // We can reuse the mplace field computation logic for indirect operands. - let field = self.mplace_field(mplace, field)?; - return Ok(field.into()); - } - Err(value) => value, - }; - - let field_layout = op.layout.field(self, field); - if field_layout.is_zst() { - let immediate = Scalar::ZST.into(); - return Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout }); - } - let offset = op.layout.fields.offset(field); - let immediate = match *base { - // the field covers the entire type - _ if offset.bytes() == 0 && field_layout.size == op.layout.size => *base, - // extract fields from types with `ScalarPair` ABI - Immediate::ScalarPair(a, b) => { - let val = if offset.bytes() == 0 { a } else { b }; - Immediate::from(val) - } - Immediate::Scalar(val) => span_bug!( - self.cur_span(), - "field access on non aggregate {:#?}, {:#?}", - val, - op.layout - ), - }; - Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout }) - } - - pub fn operand_index( - &self, - op: &OpTy<'tcx, M::PointerTag>, - index: u64, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - if let Ok(index) = usize::try_from(index) { - // We can just treat this as a field. - self.operand_field(op, index) - } else { - // Indexing into a big array. This must be an mplace. - let mplace = op.assert_mem_place(); - Ok(self.mplace_index(&mplace, index)?.into()) - } - } - - pub fn operand_downcast( - &self, - op: &OpTy<'tcx, M::PointerTag>, - variant: VariantIdx, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - // Downcasts only change the layout - Ok(match op.try_as_mplace() { - Ok(ref mplace) => self.mplace_downcast(mplace, variant)?.into(), - Err(..) => { - let layout = op.layout.for_variant(self, variant); - OpTy { layout, ..*op } - } - }) - } - - pub fn operand_projection( - &self, - base: &OpTy<'tcx, M::PointerTag>, - proj_elem: mir::PlaceElem<'tcx>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { - Field(field, _) => self.operand_field(base, field.index())?, - Downcast(_, variant) => self.operand_downcast(base, variant)?, - Deref => self.deref_operand(base)?.into(), - Subslice { .. } | ConstantIndex { .. } | Index(_) => { - // The rest should only occur as mplace, we do not use Immediates for types - // allowing such operations. This matches place_projection forcing an allocation. - let mplace = base.assert_mem_place(); - self.mplace_projection(&mplace, proj_elem)?.into() - } - }) - } - - /// Read from a local. Will not actually access the local if reading from a ZST. - /// Will not access memory, instead an indirect `Operand` is returned. - /// - /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an - /// OpTy from a local - pub fn access_local( - &self, - frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, - local: mir::Local, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let layout = self.layout_of_local(frame, local, layout)?; - let op = if layout.is_zst() { - // Do not read from ZST, they might not be initialized - Operand::Immediate(Scalar::ZST.into()) - } else { - M::access_local(&self, frame, local)? - }; - Ok(OpTy { op, layout }) - } - - /// Every place can be read from, so we can turn them into an operand. - /// This will definitely return `Indirect` if the place is a `Ptr`, i.e., this - /// will never actually read from memory. - #[inline(always)] - pub fn place_to_op( - &self, - place: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let op = match **place { - Place::Ptr(mplace) => Operand::Indirect(mplace), - Place::Local { frame, local } => { - *self.access_local(&self.stack()[frame], local, None)? - } - }; - Ok(OpTy { op, layout: place.layout }) - } - - // Evaluate a place with the goal of reading from it. This lets us sometimes - // avoid allocations. - pub fn eval_place_to_op( - &self, - place: mir::Place<'tcx>, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - // Do not use the layout passed in as argument if the base we are looking at - // here is not the entire place. - let layout = if place.projection.is_empty() { layout } else { None }; - - let base_op = self.access_local(self.frame(), place.local, layout)?; - - let op = place - .projection - .iter() - .try_fold(base_op, |op, elem| self.operand_projection(&op, elem))?; - - trace!("eval_place_to_op: got {:?}", *op); - // Sanity-check the type we ended up with. - debug_assert!(mir_assign_valid_types( - *self.tcx, - self.param_env, - self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( - place.ty(&self.frame().body.local_decls, *self.tcx).ty - ))?, - op.layout, - )); - Ok(op) - } - - /// Evaluate the operand, returning a place where you can then find the data. - /// If you already know the layout, you can save two table lookups - /// by passing it in here. - #[inline] - pub fn eval_operand( - &self, - mir_op: &mir::Operand<'tcx>, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - use rustc_middle::mir::Operand::*; - let op = match *mir_op { - // FIXME: do some more logic on `move` to invalidate the old location - Copy(place) | Move(place) => self.eval_place_to_op(place, layout)?, - - Constant(ref constant) => { - let val = - self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal); - // This can still fail: - // * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all - // checked yet. - // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail. - - self.mir_const_to_op(&val, layout)? - } - }; - trace!("{:?}: {:?}", mir_op, *op); - Ok(op) - } - - /// Evaluate a bunch of operands at once - pub(super) fn eval_operands( - &self, - ops: &[mir::Operand<'tcx>], - ) -> InterpResult<'tcx, Vec>> { - ops.iter().map(|op| self.eval_operand(op, None)).collect() - } - - // Used when the miri-engine runs into a constant and for extracting information from constants - // in patterns via the `const_eval` module - /// The `val` and `layout` are assumed to already be in our interpreter - /// "universe" (param_env). - crate fn const_to_op( - &self, - val: &ty::Const<'tcx>, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - match val.val { - ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), - ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), - ty::ConstKind::Unevaluated(uv) => { - let instance = self.resolve(uv.def, uv.substs(*self.tcx))?; - Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into()) - } - ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { - span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) - } - ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty, layout), - } - } - - crate fn mir_const_to_op( - &self, - val: &mir::ConstantKind<'tcx>, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - match val { - mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout), - mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, layout), - } - } - - crate fn const_val_to_op( - &self, - val_val: ConstValue<'tcx>, - ty: Ty<'tcx>, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - // Other cases need layout. - let tag_scalar = |scalar| -> InterpResult<'tcx, _> { - Ok(match scalar { - Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size), - Scalar::Int(int) => Scalar::Int(int), - }) - }; - let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; - let op = match val_val { - ConstValue::ByRef { alloc, offset } => { - let id = self.tcx.create_memory_alloc(alloc); - // We rely on mutability being set correctly in that allocation to prevent writes - // where none should happen. - let ptr = self.global_base_pointer(Pointer::new(id, offset))?; - Operand::Indirect(MemPlace::from_ptr(ptr.into(), layout.align.abi)) - } - ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()), - ConstValue::Slice { data, start, end } => { - // We rely on mutability being set correctly in `data` to prevent writes - // where none should happen. - let ptr = Pointer::new( - self.tcx.create_memory_alloc(data), - Size::from_bytes(start), // offset: `start` - ); - Operand::Immediate(Immediate::new_slice( - Scalar::from_pointer(self.global_base_pointer(ptr)?, &*self.tcx), - u64::try_from(end.checked_sub(start).unwrap()).unwrap(), // len: `end - start` - self, - )) - } - }; - Ok(OpTy { op, layout }) - } - - /// Read discriminant, return the runtime value as well as the variant index. - pub fn read_discriminant( - &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { - trace!("read_discriminant_value {:#?}", op.layout); - // Get type and layout of the discriminant. - let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?; - trace!("discriminant type: {:?}", discr_layout.ty); - - // We use "discriminant" to refer to the value associated with a particular enum variant. - // This is not to be confused with its "variant index", which is just determining its position in the - // declared list of variants -- they can differ with explicitly assigned discriminants. - // We use "tag" to refer to how the discriminant is encoded in memory, which can be either - // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`). - let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants { - Variants::Single { index } => { - let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) { - Some(discr) => { - // This type actually has discriminants. - assert_eq!(discr.ty, discr_layout.ty); - Scalar::from_uint(discr.val, discr_layout.size) - } - None => { - // On a type without actual discriminants, variant is 0. - assert_eq!(index.as_u32(), 0); - Scalar::from_uint(index.as_u32(), discr_layout.size) - } - }; - return Ok((discr, index)); - } - Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => { - (tag, tag_encoding, tag_field) - } - }; - - // There are *three* layouts that come into play here: - // - The discriminant has a type for typechecking. This is `discr_layout`, and is used for - // the `Scalar` we return. - // - The tag (encoded discriminant) has layout `tag_layout`. This is always an integer type, - // and used to interpret the value we read from the tag field. - // For the return value, a cast to `discr_layout` is performed. - // - The field storing the tag has a layout, which is very similar to `tag_layout` but - // may be a pointer. This is `tag_val.layout`; we just use it for sanity checks. - - // Get layout for tag. - let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?; - - // Read tag and sanity-check `tag_layout`. - let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?; - assert_eq!(tag_layout.size, tag_val.layout.size); - assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); - let tag_val = tag_val.to_scalar()?; - trace!("tag value: {:?}", tag_val); - - // Figure out which discriminant and variant this corresponds to. - Ok(match *tag_encoding { - TagEncoding::Direct => { - let tag_bits = tag_val - .try_to_int() - .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))? - .assert_bits(tag_layout.size); - // Cast bits from tag layout to discriminant layout. - let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); - let discr_bits = discr_val.assert_bits(discr_layout.size); - // Convert discriminant to variant index, and catch invalid discriminants. - let index = match *op.layout.ty.kind() { - ty::Adt(adt, _) => { - adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits) - } - ty::Generator(def_id, substs, _) => { - let substs = substs.as_generator(); - substs - .discriminants(def_id, *self.tcx) - .find(|(_, var)| var.val == discr_bits) - } - _ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"), - } - .ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?; - // Return the cast value, and the index. - (discr_val, index.0) - } - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { - // Compute the variant this niche value/"tag" corresponds to. With niche layout, - // discriminant (encoded in niche/tag) and variant index are the same. - let variants_start = niche_variants.start().as_u32(); - let variants_end = niche_variants.end().as_u32(); - let variant = match tag_val.try_to_int() { - Err(dbg_val) => { - // So this is a pointer then, and casting to an int failed. - // Can only happen during CTFE. - let ptr = self.scalar_to_ptr(tag_val); - // The niche must be just 0, and the ptr not null, then we know this is - // okay. Everything else, we conservatively reject. - let ptr_valid = niche_start == 0 - && variants_start == variants_end - && !self.memory.ptr_may_be_null(ptr); - if !ptr_valid { - throw_ub!(InvalidTag(dbg_val)) - } - dataful_variant - } - Ok(tag_bits) => { - let tag_bits = tag_bits.assert_bits(tag_layout.size); - // We need to use machine arithmetic to get the relative variant idx: - // variant_index_relative = tag_val - niche_start_val - let tag_val = ImmTy::from_uint(tag_bits, tag_layout); - let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); - let variant_index_relative_val = - self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?; - let variant_index_relative = variant_index_relative_val - .to_scalar()? - .assert_bits(tag_val.layout.size); - // Check if this is in the range that indicates an actual discriminant. - if variant_index_relative <= u128::from(variants_end - variants_start) { - let variant_index_relative = u32::try_from(variant_index_relative) - .expect("we checked that this fits into a u32"); - // Then computing the absolute variant idx should not overflow any more. - let variant_index = variants_start - .checked_add(variant_index_relative) - .expect("overflow computing absolute variant idx"); - let variants_len = op - .layout - .ty - .ty_adt_def() - .expect("tagged layout for non adt") - .variants - .len(); - assert!(usize::try_from(variant_index).unwrap() < variants_len); - VariantIdx::from_u32(variant_index) - } else { - dataful_variant - } - } - }; - // Compute the size of the scalar we need to return. - // No need to cast, because the variant index directly serves as discriminant and is - // encoded in the tag. - (Scalar::from_uint(variant.as_u32(), discr_layout.size), variant) - } - }) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/operator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/operator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/operator.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/operator.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,417 +0,0 @@ -use std::convert::TryFrom; - -use rustc_apfloat::Float; -use rustc_middle::mir; -use rustc_middle::mir::interpret::{InterpResult, Scalar}; -use rustc_middle::ty::{self, layout::TyAndLayout, FloatTy, Ty}; -use rustc_target::abi::LayoutOf; - -use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy}; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Applies the binary operation `op` to the two operands and writes a tuple of the result - /// and a boolean signifying the potential overflow to the destination. - pub fn binop_with_overflow( - &mut self, - op: mir::BinOp, - left: &ImmTy<'tcx, M::PointerTag>, - right: &ImmTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?; - debug_assert_eq!( - self.tcx.intern_tup(&[ty, self.tcx.types.bool]), - dest.layout.ty, - "type mismatch for result of {:?}", - op, - ); - let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into()); - self.write_immediate(val, dest) - } - - /// Applies the binary operation `op` to the arguments and writes the result to the - /// destination. - pub fn binop_ignore_overflow( - &mut self, - op: mir::BinOp, - left: &ImmTy<'tcx, M::PointerTag>, - right: &ImmTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?; - assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op); - self.write_scalar(val, dest) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - fn binary_char_op( - &self, - bin_op: mir::BinOp, - l: char, - r: char, - ) -> (Scalar, bool, Ty<'tcx>) { - use rustc_middle::mir::BinOp::*; - - let res = match bin_op { - Eq => l == r, - Ne => l != r, - Lt => l < r, - Le => l <= r, - Gt => l > r, - Ge => l >= r, - _ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op), - }; - (Scalar::from_bool(res), false, self.tcx.types.bool) - } - - fn binary_bool_op( - &self, - bin_op: mir::BinOp, - l: bool, - r: bool, - ) -> (Scalar, bool, Ty<'tcx>) { - use rustc_middle::mir::BinOp::*; - - let res = match bin_op { - Eq => l == r, - Ne => l != r, - Lt => l < r, - Le => l <= r, - Gt => l > r, - Ge => l >= r, - BitAnd => l & r, - BitOr => l | r, - BitXor => l ^ r, - _ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op), - }; - (Scalar::from_bool(res), false, self.tcx.types.bool) - } - - fn binary_float_op>>( - &self, - bin_op: mir::BinOp, - ty: Ty<'tcx>, - l: F, - r: F, - ) -> (Scalar, bool, Ty<'tcx>) { - use rustc_middle::mir::BinOp::*; - - let (val, ty) = match bin_op { - Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), - Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), - Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), - Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), - Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), - Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), - Add => ((l + r).value.into(), ty), - Sub => ((l - r).value.into(), ty), - Mul => ((l * r).value.into(), ty), - Div => ((l / r).value.into(), ty), - Rem => ((l % r).value.into(), ty), - _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op), - }; - (val, false, ty) - } - - fn binary_int_op( - &self, - bin_op: mir::BinOp, - // passing in raw bits - l: u128, - left_layout: TyAndLayout<'tcx>, - r: u128, - right_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - use rustc_middle::mir::BinOp::*; - - // Shift ops can have an RHS with a different numeric type. - if bin_op == Shl || bin_op == Shr { - let signed = left_layout.abi.is_signed(); - let size = u128::from(left_layout.size.bits()); - let overflow = r >= size; - let r = r % size; // mask to type size - let r = u32::try_from(r).unwrap(); // we masked so this will always fit - let result = if signed { - let l = self.sign_extend(l, left_layout) as i128; - let result = match bin_op { - Shl => l.checked_shl(r).unwrap(), - Shr => l.checked_shr(r).unwrap(), - _ => bug!("it has already been checked that this is a shift op"), - }; - result as u128 - } else { - match bin_op { - Shl => l.checked_shl(r).unwrap(), - Shr => l.checked_shr(r).unwrap(), - _ => bug!("it has already been checked that this is a shift op"), - } - }; - let truncated = self.truncate(result, left_layout); - return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty)); - } - - // For the remaining ops, the types must be the same on both sides - if left_layout.ty != right_layout.ty { - span_bug!( - self.cur_span(), - "invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})", - bin_op, - l, - left_layout.ty, - r, - right_layout.ty, - ) - } - - let size = left_layout.size; - - // Operations that need special treatment for signed integers - if left_layout.abi.is_signed() { - let op: Option bool> = match bin_op { - Lt => Some(i128::lt), - Le => Some(i128::le), - Gt => Some(i128::gt), - Ge => Some(i128::ge), - _ => None, - }; - if let Some(op) = op { - let l = self.sign_extend(l, left_layout) as i128; - let r = self.sign_extend(r, right_layout) as i128; - return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool)); - } - let op: Option (i128, bool)> = match bin_op { - Div if r == 0 => throw_ub!(DivisionByZero), - Rem if r == 0 => throw_ub!(RemainderByZero), - Div => Some(i128::overflowing_div), - Rem => Some(i128::overflowing_rem), - Add => Some(i128::overflowing_add), - Sub => Some(i128::overflowing_sub), - Mul => Some(i128::overflowing_mul), - _ => None, - }; - if let Some(op) = op { - let r = self.sign_extend(r, right_layout) as i128; - // We need a special check for overflowing remainder: - // "int_min % -1" overflows and returns 0, but after casting things to a larger int - // type it does *not* overflow nor give an unrepresentable result! - if bin_op == Rem { - if r == -1 && l == (1 << (size.bits() - 1)) { - return Ok((Scalar::from_int(0, size), true, left_layout.ty)); - } - } - let l = self.sign_extend(l, left_layout) as i128; - - let (result, oflo) = op(l, r); - // This may be out-of-bounds for the result type, so we have to truncate ourselves. - // If that truncation loses any information, we have an overflow. - let result = result as u128; - let truncated = self.truncate(result, left_layout); - return Ok(( - Scalar::from_uint(truncated, size), - oflo || self.sign_extend(truncated, left_layout) != result, - left_layout.ty, - )); - } - } - - let (val, ty) = match bin_op { - Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), - Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), - - Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), - Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), - Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), - Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), - - BitOr => (Scalar::from_uint(l | r, size), left_layout.ty), - BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty), - BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty), - - Add | Sub | Mul | Rem | Div => { - assert!(!left_layout.abi.is_signed()); - let op: fn(u128, u128) -> (u128, bool) = match bin_op { - Add => u128::overflowing_add, - Sub => u128::overflowing_sub, - Mul => u128::overflowing_mul, - Div if r == 0 => throw_ub!(DivisionByZero), - Rem if r == 0 => throw_ub!(RemainderByZero), - Div => u128::overflowing_div, - Rem => u128::overflowing_rem, - _ => bug!(), - }; - let (result, oflo) = op(l, r); - // Truncate to target type. - // If that truncation loses any information, we have an overflow. - let truncated = self.truncate(result, left_layout); - return Ok(( - Scalar::from_uint(truncated, size), - oflo || truncated != result, - left_layout.ty, - )); - } - - _ => span_bug!( - self.cur_span(), - "invalid binary op {:?}: {:?}, {:?} (both {:?})", - bin_op, - l, - r, - right_layout.ty, - ), - }; - - Ok((val, false, ty)) - } - - /// Returns the result of the specified operation, whether it overflowed, and - /// the result type. - pub fn overflowing_binary_op( - &self, - bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::PointerTag>, - right: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - trace!( - "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", - bin_op, - *left, - left.layout.ty, - *right, - right.layout.ty - ); - - match left.layout.ty.kind() { - ty::Char => { - assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_scalar()?; - let right = right.to_scalar()?; - Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) - } - ty::Bool => { - assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_scalar()?; - let right = right.to_scalar()?; - Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) - } - ty::Float(fty) => { - assert_eq!(left.layout.ty, right.layout.ty); - let ty = left.layout.ty; - let left = left.to_scalar()?; - let right = right.to_scalar()?; - Ok(match fty { - FloatTy::F32 => { - self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?) - } - FloatTy::F64 => { - self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?) - } - }) - } - _ if left.layout.ty.is_integral() => { - // the RHS type can be different, e.g. for shifts -- but it has to be integral, too - assert!( - right.layout.ty.is_integral(), - "Unexpected types for BinOp: {:?} {:?} {:?}", - left.layout.ty, - bin_op, - right.layout.ty - ); - - let l = left.to_scalar()?.to_bits(left.layout.size)?; - let r = right.to_scalar()?.to_bits(right.layout.size)?; - self.binary_int_op(bin_op, l, left.layout, r, right.layout) - } - _ if left.layout.ty.is_any_ptr() => { - // The RHS type must be the same *or an integer type* (for `Offset`). - assert!( - right.layout.ty == left.layout.ty || right.layout.ty.is_integral(), - "Unexpected types for BinOp: {:?} {:?} {:?}", - left.layout.ty, - bin_op, - right.layout.ty - ); - - M::binary_ptr_op(self, bin_op, left, right) - } - _ => span_bug!( - self.cur_span(), - "Invalid MIR: bad LHS type for binop: {:?}", - left.layout.ty - ), - } - } - - /// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows. - #[inline] - pub fn binary_op( - &self, - bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::PointerTag>, - right: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { - let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?; - Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) - } - - /// Returns the result of the specified operation, whether it overflowed, and - /// the result type. - pub fn overflowing_unary_op( - &self, - un_op: mir::UnOp, - val: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - use rustc_middle::mir::UnOp::*; - - let layout = val.layout; - let val = val.to_scalar()?; - trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); - - match layout.ty.kind() { - ty::Bool => { - let val = val.to_bool()?; - let res = match un_op { - Not => !val, - _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op), - }; - Ok((Scalar::from_bool(res), false, self.tcx.types.bool)) - } - ty::Float(fty) => { - let res = match (un_op, fty) { - (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), - (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), - _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), - }; - Ok((res, false, layout.ty)) - } - _ => { - assert!(layout.ty.is_integral()); - let val = val.to_bits(layout.size)?; - let (res, overflow) = match un_op { - Not => (self.truncate(!val, layout), false), // bitwise negation, then truncate - Neg => { - // arithmetic negation - assert!(layout.abi.is_signed()); - let val = self.sign_extend(val, layout) as i128; - let (res, overflow) = val.overflowing_neg(); - let res = res as u128; - // Truncate to target type. - // If that truncation loses any information, we have an overflow. - let truncated = self.truncate(res, layout); - (truncated, overflow || self.sign_extend(truncated, layout) != res) - } - }; - Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty)) - } - } - } - - pub fn unary_op( - &self, - un_op: mir::UnOp, - val: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { - let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?; - Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/place.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/place.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/place.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/place.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1091 +0,0 @@ -//! Computations on places -- field projections, going from mir::Place, and writing -//! into a place. -//! All high-level functions to write to memory work on places as destinations. - -use std::convert::TryFrom; -use std::hash::Hash; - -use rustc_ast::Mutability; -use rustc_macros::HashStable; -use rustc_middle::mir; -use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; -use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; - -use super::{ - alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg, - ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, - Operand, Pointer, PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, -}; - -#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] -/// Information required for the sound usage of a `MemPlace`. -pub enum MemPlaceMeta { - /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). - Meta(Scalar), - /// `Sized` types or unsized `extern type` - None, - /// The address of this place may not be taken. This protects the `MemPlace` from coming from - /// a ZST Operand without a backing allocation and being converted to an integer address. This - /// should be impossible, because you can't take the address of an operand, but this is a second - /// protection layer ensuring that we don't mess up. - Poison, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(MemPlaceMeta, 24); - -impl MemPlaceMeta { - pub fn unwrap_meta(self) -> Scalar { - match self { - Self::Meta(s) => s, - Self::None | Self::Poison => { - bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") - } - } - } - fn has_meta(self) -> bool { - match self { - Self::Meta(_) => true, - Self::None | Self::Poison => false, - } - } -} - -#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] -pub struct MemPlace { - /// The pointer can be a pure integer, with the `None` tag. - pub ptr: Pointer>, - pub align: Align, - /// Metadata for unsized places. Interpretation is up to the type. - /// Must not be present for sized types, but can be missing for unsized types - /// (e.g., `extern type`). - pub meta: MemPlaceMeta, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(MemPlace, 48); - -#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] -pub enum Place { - /// A place referring to a value allocated in the `Memory` system. - Ptr(MemPlace), - - /// To support alloc-free locals, we are able to write directly to a local. - /// (Without that optimization, we'd just always be a `MemPlace`.) - Local { frame: usize, local: mir::Local }, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Place, 56); - -#[derive(Copy, Clone, Debug)] -pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> { - place: Place, // Keep this private; it helps enforce invariants. - pub layout: TyAndLayout<'tcx>, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72); - -impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> { - type Target = Place; - #[inline(always)] - fn deref(&self) -> &Place { - &self.place - } -} - -/// A MemPlace with its layout. Constructing it is only possible in this module. -#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] -pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> { - mplace: MemPlace, - pub layout: TyAndLayout<'tcx>, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64); - -impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> { - type Target = MemPlace; - #[inline(always)] - fn deref(&self) -> &MemPlace { - &self.mplace - } -} - -impl<'tcx, Tag: Provenance> From> for PlaceTy<'tcx, Tag> { - #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { - PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout } - } -} - -impl MemPlace { - #[inline(always)] - pub fn from_ptr(ptr: Pointer>, align: Align) -> Self { - MemPlace { ptr, align, meta: MemPlaceMeta::None } - } - - /// Adjust the provenance of the main pointer (metadata is unaffected). - pub fn map_provenance(self, f: impl FnOnce(Option) -> Option) -> Self { - MemPlace { ptr: self.ptr.map_provenance(f), ..self } - } - - /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. - /// This is the inverse of `ref_to_mplace`. - #[inline(always)] - pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { - match self.meta { - MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)), - MemPlaceMeta::Meta(meta) => { - Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx).into(), meta.into()) - } - MemPlaceMeta::Poison => bug!( - "MPlaceTy::dangling may never be used to produce a \ - place that will have the address of its pointee taken" - ), - } - } - - #[inline] - pub fn offset( - self, - offset: Size, - meta: MemPlaceMeta, - cx: &impl HasDataLayout, - ) -> InterpResult<'tcx, Self> { - Ok(MemPlace { - ptr: self.ptr.offset(offset, cx)?, - align: self.align.restrict_for_offset(offset), - meta, - }) - } -} - -impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { - /// Produces a MemPlace that works for ZST but nothing else - #[inline] - pub fn dangling(layout: TyAndLayout<'tcx>) -> Self { - let align = layout.align.abi; - let ptr = Pointer::new(None, Size::from_bytes(align.bytes())); // no provenance, absolute address - // `Poison` this to make sure that the pointer value `ptr` is never observable by the program. - MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout } - } - - #[inline] - pub fn offset( - &self, - offset: Size, - meta: MemPlaceMeta, - layout: TyAndLayout<'tcx>, - cx: &impl HasDataLayout, - ) -> InterpResult<'tcx, Self> { - Ok(MPlaceTy { mplace: self.mplace.offset(offset, meta, cx)?, layout }) - } - - #[inline] - pub fn from_aligned_ptr(ptr: Pointer>, layout: TyAndLayout<'tcx>) -> Self { - MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout } - } - - #[inline] - pub(super) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { - if self.layout.is_unsized() { - // We need to consult `meta` metadata - match self.layout.ty.kind() { - ty::Slice(..) | ty::Str => self.mplace.meta.unwrap_meta().to_machine_usize(cx), - _ => bug!("len not supported on unsized type {:?}", self.layout.ty), - } - } else { - // Go through the layout. There are lots of types that support a length, - // e.g., SIMD types. - match self.layout.fields { - FieldsShape::Array { count, .. } => Ok(count), - _ => bug!("len not supported on sized type {:?}", self.layout.ty), - } - } - } - - #[inline] - pub(super) fn vtable(&self) -> Scalar { - match self.layout.ty.kind() { - ty::Dynamic(..) => self.mplace.meta.unwrap_meta(), - _ => bug!("vtable not supported on type {:?}", self.layout.ty), - } - } -} - -// These are defined here because they produce a place. -impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { - #[inline(always)] - /// Note: do not call `as_ref` on the resulting place. This function should only be used to - /// read from the resulting mplace, not to get its address back. - pub fn try_as_mplace(&self) -> Result, ImmTy<'tcx, Tag>> { - match **self { - Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), - Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout)), - Operand::Immediate(imm) => Err(ImmTy::from_immediate(imm, self.layout)), - } - } - - #[inline(always)] - /// Note: do not call `as_ref` on the resulting place. This function should only be used to - /// read from the resulting mplace, not to get its address back. - pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Tag> { - self.try_as_mplace().unwrap() - } -} - -impl Place { - #[inline] - pub fn assert_mem_place(self) -> MemPlace { - match self { - Place::Ptr(mplace) => mplace, - _ => bug!("assert_mem_place: expected Place::Ptr, got {:?}", self), - } - } -} - -impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> { - #[inline] - pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { - MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout } - } -} - -// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385 -impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> -where - // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 - Tag: Provenance + Eq + Hash + 'static, - M: Machine<'mir, 'tcx, PointerTag = Tag>, -{ - /// Take a value, which represents a (thin or wide) reference, and make it a place. - /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. - /// - /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not - /// want to ever use the place for memory access! - /// Generally prefer `deref_operand`. - pub fn ref_to_mplace( - &self, - val: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let pointee_type = - val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; - let layout = self.layout_of(pointee_type)?; - let (ptr, meta) = match **val { - Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None), - Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta.check_init()?)), - }; - - let mplace = MemPlace { - ptr: self.scalar_to_ptr(ptr.check_init()?), - // We could use the run-time alignment here. For now, we do not, because - // the point of tracking the alignment here is to make sure that the *static* - // alignment information emitted with the loads is correct. The run-time - // alignment can only be more restrictive. - align: layout.align.abi, - meta, - }; - Ok(MPlaceTy { mplace, layout }) - } - - /// Take an operand, representing a pointer, and dereference it to a place -- that - /// will always be a MemPlace. Lives in `place.rs` because it creates a place. - pub fn deref_operand( - &self, - src: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let val = self.read_immediate(src)?; - trace!("deref to {} on {:?}", val.layout.ty, *val); - let mplace = self.ref_to_mplace(&val)?; - self.check_mplace_access(mplace, CheckInAllocMsg::DerefTest)?; - Ok(mplace) - } - - #[inline] - pub(super) fn get_alloc( - &self, - place: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Option>> { - assert!(!place.layout.is_unsized()); - assert!(!place.meta.has_meta()); - let size = place.layout.size; - self.memory.get(place.ptr, size, place.align) - } - - #[inline] - pub(super) fn get_alloc_mut( - &mut self, - place: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Option>> { - assert!(!place.layout.is_unsized()); - assert!(!place.meta.has_meta()); - let size = place.layout.size; - self.memory.get_mut(place.ptr, size, place.align) - } - - /// Check if this mplace is dereferencable and sufficiently aligned. - fn check_mplace_access( - &self, - mplace: MPlaceTy<'tcx, M::PointerTag>, - msg: CheckInAllocMsg, - ) -> InterpResult<'tcx> { - let (size, align) = self - .size_and_align_of_mplace(&mplace)? - .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - assert!(mplace.mplace.align <= align, "dynamic alignment less strict than static one?"); - let align = M::enforce_alignment(&self.memory.extra).then_some(align); - self.memory.check_ptr_access_align(mplace.ptr, size, align.unwrap_or(Align::ONE), msg)?; - Ok(()) - } - - /// Offset a pointer to project to a field of a struct/union. Unlike `place_field`, this is - /// always possible without allocating, so it can take `&self`. Also return the field's layout. - /// This supports both struct and array fields. - /// - /// This also works for arrays, but then the `usize` index type is restricting. - /// For indexing into arrays, use `mplace_index`. - #[inline(always)] - pub fn mplace_field( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - field: usize, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let offset = base.layout.fields.offset(field); - let field_layout = base.layout.field(self, field); - - // Offset may need adjustment for unsized fields. - let (meta, offset) = if field_layout.is_unsized() { - // Re-use parent metadata to determine dynamic field layout. - // With custom DSTS, this *will* execute user-defined code, but the same - // happens at run-time so that's okay. - let align = match self.size_and_align_of(&base.meta, &field_layout)? { - Some((_, align)) => align, - None if offset == Size::ZERO => { - // An extern type at offset 0, we fall back to its static alignment. - // FIXME: Once we have made decisions for how to handle size and alignment - // of `extern type`, this should be adapted. It is just a temporary hack - // to get some code to work that probably ought to work. - field_layout.align.abi - } - None => span_bug!( - self.cur_span(), - "cannot compute offset for extern type field at non-0 offset" - ), - }; - (base.meta, offset.align_to(align)) - } else { - // base.meta could be present; we might be accessing a sized field of an unsized - // struct. - (MemPlaceMeta::None, offset) - }; - - // We do not look at `base.layout.align` nor `field_layout.align`, unlike - // codegen -- mostly to see if we can get away with that - base.offset(offset, meta, field_layout, self) - } - - /// Index into an array. - #[inline(always)] - pub fn mplace_index( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - index: u64, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - // Not using the layout method because we want to compute on u64 - match base.layout.fields { - FieldsShape::Array { stride, .. } => { - let len = base.len(self)?; - if index >= len { - // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len, index }); - } - let offset = stride * index; // `Size` multiplication - // All fields have the same layout. - let field_layout = base.layout.field(self, 0); - - assert!(!field_layout.is_unsized()); - base.offset(offset, MemPlaceMeta::None, field_layout, self) - } - _ => span_bug!( - self.cur_span(), - "`mplace_index` called on non-array type {:?}", - base.layout.ty - ), - } - } - - // Iterates over all fields of an array. Much more efficient than doing the - // same by repeatedly calling `mplace_array`. - pub(super) fn mplace_array_fields( - &self, - base: &'a MPlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx, impl Iterator>> + 'a> - { - let len = base.len(self)?; // also asserts that we have a type where this makes sense - let stride = match base.layout.fields { - FieldsShape::Array { stride, .. } => stride, - _ => span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout"), - }; - let layout = base.layout.field(self, 0); - let dl = &self.tcx.data_layout; - // `Size` multiplication - Ok((0..len).map(move |i| base.offset(stride * i, MemPlaceMeta::None, layout, dl))) - } - - fn mplace_subslice( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - from: u64, - to: u64, - from_end: bool, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let len = base.len(self)?; // also asserts that we have a type where this makes sense - let actual_to = if from_end { - if from.checked_add(to).map_or(true, |to| to > len) { - // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len: len, index: from.saturating_add(to) }); - } - len.checked_sub(to).unwrap() - } else { - to - }; - - // Not using layout method because that works with usize, and does not work with slices - // (that have count 0 in their layout). - let from_offset = match base.layout.fields { - FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked - _ => { - span_bug!(self.cur_span(), "unexpected layout of index access: {:#?}", base.layout) - } - }; - - // Compute meta and new layout - let inner_len = actual_to.checked_sub(from).unwrap(); - let (meta, ty) = match base.layout.ty.kind() { - // It is not nice to match on the type, but that seems to be the only way to - // implement this. - ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)), - ty::Slice(..) => { - let len = Scalar::from_machine_usize(inner_len, self); - (MemPlaceMeta::Meta(len), base.layout.ty) - } - _ => { - span_bug!(self.cur_span(), "cannot subslice non-array type: `{:?}`", base.layout.ty) - } - }; - let layout = self.layout_of(ty)?; - base.offset(from_offset, meta, layout, self) - } - - pub(crate) fn mplace_downcast( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - variant: VariantIdx, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - // Downcasts only change the layout - assert!(!base.meta.has_meta()); - Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..*base }) - } - - /// Project into an mplace - pub(super) fn mplace_projection( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - proj_elem: mir::PlaceElem<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { - Field(field, _) => self.mplace_field(base, field.index())?, - Downcast(_, variant) => self.mplace_downcast(base, variant)?, - Deref => self.deref_operand(&base.into())?, - - Index(local) => { - let layout = self.layout_of(self.tcx.types.usize)?; - let n = self.access_local(self.frame(), local, Some(layout))?; - let n = self.read_scalar(&n)?; - let n = n.to_machine_usize(self)?; - self.mplace_index(base, n)? - } - - ConstantIndex { offset, min_length, from_end } => { - let n = base.len(self)?; - if n < min_length { - // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len: min_length, index: n }); - } - - let index = if from_end { - assert!(0 < offset && offset <= min_length); - n.checked_sub(offset).unwrap() - } else { - assert!(offset < min_length); - offset - }; - - self.mplace_index(base, index)? - } - - Subslice { from, to, from_end } => self.mplace_subslice(base, from, to, from_end)?, - }) - } - - /// Gets the place of a field inside the place, and also the field's type. - /// Just a convenience function, but used quite a bit. - /// This is the only projection that might have a side-effect: We cannot project - /// into the field of a local `ScalarPair`, we have to first allocate it. - pub fn place_field( - &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, - field: usize, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - // FIXME: We could try to be smarter and avoid allocation for fields that span the - // entire place. - let mplace = self.force_allocation(base)?; - Ok(self.mplace_field(&mplace, field)?.into()) - } - - pub fn place_index( - &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, - index: u64, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - let mplace = self.force_allocation(base)?; - Ok(self.mplace_index(&mplace, index)?.into()) - } - - pub fn place_downcast( - &self, - base: &PlaceTy<'tcx, M::PointerTag>, - variant: VariantIdx, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - // Downcast just changes the layout - Ok(match base.place { - Place::Ptr(mplace) => { - self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into() - } - Place::Local { .. } => { - let layout = base.layout.for_variant(self, variant); - PlaceTy { layout, ..*base } - } - }) - } - - /// Projects into a place. - pub fn place_projection( - &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, - &proj_elem: &mir::ProjectionElem>, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { - Field(field, _) => self.place_field(base, field.index())?, - Downcast(_, variant) => self.place_downcast(base, variant)?, - Deref => self.deref_operand(&self.place_to_op(base)?)?.into(), - // For the other variants, we have to force an allocation. - // This matches `operand_projection`. - Subslice { .. } | ConstantIndex { .. } | Index(_) => { - let mplace = self.force_allocation(base)?; - self.mplace_projection(&mplace, proj_elem)?.into() - } - }) - } - - /// Computes a place. You should only use this if you intend to write into this - /// place; for reading, a more efficient alternative is `eval_place_for_read`. - pub fn eval_place( - &mut self, - place: mir::Place<'tcx>, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - let mut place_ty = PlaceTy { - // This works even for dead/uninitialized locals; we check further when writing - place: Place::Local { frame: self.frame_idx(), local: place.local }, - layout: self.layout_of_local(self.frame(), place.local, None)?, - }; - - for elem in place.projection.iter() { - place_ty = self.place_projection(&place_ty, &elem)? - } - - trace!("{:?}", self.dump_place(place_ty.place)); - // Sanity-check the type we ended up with. - debug_assert!(mir_assign_valid_types( - *self.tcx, - self.param_env, - self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( - place.ty(&self.frame().body.local_decls, *self.tcx).ty - ))?, - place_ty.layout, - )); - Ok(place_ty) - } - - /// Write an immediate to a place - #[inline(always)] - pub fn write_immediate( - &mut self, - src: Immediate, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - self.write_immediate_no_validate(src, dest)?; - - if M::enforce_validity(self) { - // Data got changed, better make sure it matches the type! - self.validate_operand(&self.place_to_op(dest)?)?; - } - - Ok(()) - } - - /// Write a scalar to a place - #[inline(always)] - pub fn write_scalar( - &mut self, - val: impl Into>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - self.write_immediate(Immediate::Scalar(val.into()), dest) - } - - /// Write a pointer to a place - #[inline(always)] - pub fn write_pointer( - &mut self, - ptr: impl Into>>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest) - } - - /// Write an immediate to a place. - /// If you use this you are responsible for validating that things got copied at the - /// right type. - fn write_immediate_no_validate( - &mut self, - src: Immediate, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - if cfg!(debug_assertions) { - // This is a very common path, avoid some checks in release mode - assert!(!dest.layout.is_unsized(), "Cannot write unsized data"); - match src { - Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Ptr(..))) => assert_eq!( - self.pointer_size(), - dest.layout.size, - "Size mismatch when writing pointer" - ), - Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Int(int))) => { - assert_eq!(int.size(), dest.layout.size, "Size mismatch when writing bits") - } - Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // uninit can have any size - Immediate::ScalarPair(_, _) => { - // FIXME: Can we check anything here? - } - } - } - trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); - - // See if we can avoid an allocation. This is the counterpart to `try_read_immediate`, - // but not factored as a separate function. - let mplace = match dest.place { - Place::Local { frame, local } => { - match M::access_local_mut(self, frame, local)? { - Ok(local) => { - // Local can be updated in-place. - *local = LocalValue::Live(Operand::Immediate(src)); - return Ok(()); - } - Err(mplace) => { - // The local is in memory, go on below. - mplace - } - } - } - Place::Ptr(mplace) => mplace, // already referring to memory - }; - let dest = MPlaceTy { mplace, layout: dest.layout }; - - // This is already in memory, write there. - self.write_immediate_to_mplace_no_validate(src, &dest) - } - - /// Write an immediate to memory. - /// If you use this you are responsible for validating that things got copied at the - /// right type. - fn write_immediate_to_mplace_no_validate( - &mut self, - value: Immediate, - dest: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - // Note that it is really important that the type here is the right one, and matches the - // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here - // to handle padding properly, which is only correct if we never look at this data with the - // wrong type. - - // Invalid places are a thing: the return place of a diverging function - let tcx = *self.tcx; - let mut alloc = match self.get_alloc_mut(dest)? { - Some(a) => a, - None => return Ok(()), // zero-sized access - }; - - // FIXME: We should check that there are dest.layout.size many bytes available in - // memory. The code below is not sufficient, with enough padding it might not - // cover all the bytes! - match value { - Immediate::Scalar(scalar) => { - match dest.layout.abi { - Abi::Scalar(_) => {} // fine - _ => span_bug!( - self.cur_span(), - "write_immediate_to_mplace: invalid Scalar layout: {:#?}", - dest.layout - ), - } - alloc.write_scalar(alloc_range(Size::ZERO, dest.layout.size), scalar) - } - Immediate::ScalarPair(a_val, b_val) => { - // We checked `ptr_align` above, so all fields will have the alignment they need. - // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, - // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. - let (a, b) = match dest.layout.abi { - Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value), - _ => span_bug!( - self.cur_span(), - "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", - dest.layout - ), - }; - let (a_size, b_size) = (a.size(&tcx), b.size(&tcx)); - let b_offset = a_size.align_to(b.align(&tcx).abi); - - // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, - // but that does not work: We could be a newtype around a pair, then the - // fields do not match the `ScalarPair` components. - - alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?; - alloc.write_scalar(alloc_range(b_offset, b_size), b_val) - } - } - } - - /// Copies the data from an operand to a place. This does not support transmuting! - /// Use `copy_op_transmute` if the layouts could disagree. - #[inline(always)] - pub fn copy_op( - &mut self, - src: &OpTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - self.copy_op_no_validate(src, dest)?; - - if M::enforce_validity(self) { - // Data got changed, better make sure it matches the type! - self.validate_operand(&self.place_to_op(dest)?)?; - } - - Ok(()) - } - - /// Copies the data from an operand to a place. This does not support transmuting! - /// Use `copy_op_transmute` if the layouts could disagree. - /// Also, if you use this you are responsible for validating that things get copied at the - /// right type. - fn copy_op_no_validate( - &mut self, - src: &OpTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - // We do NOT compare the types for equality, because well-typed code can - // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - if !mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) { - span_bug!( - self.cur_span(), - "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", - src.layout.ty, - dest.layout.ty, - ); - } - - // Let us see if the layout is simple so we take a shortcut, avoid force_allocation. - let src = match self.try_read_immediate(src)? { - Ok(src_val) => { - assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); - // Yay, we got a value that we can write directly. - // FIXME: Add a check to make sure that if `src` is indirect, - // it does not overlap with `dest`. - return self.write_immediate_no_validate(*src_val, dest); - } - Err(mplace) => mplace, - }; - // Slow path, this does not fit into an immediate. Just memcpy. - trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); - - // This interprets `src.meta` with the `dest` local's layout, if an unsized local - // is being initialized! - let (dest, size) = self.force_allocation_maybe_sized(dest, src.meta)?; - let size = size.unwrap_or_else(|| { - assert!( - !dest.layout.is_unsized(), - "Cannot copy into already initialized unsized place" - ); - dest.layout.size - }); - assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances"); - - self.memory - .copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ true) - } - - /// Copies the data from an operand to a place. The layouts may disagree, but they must - /// have the same size. - pub fn copy_op_transmute( - &mut self, - src: &OpTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) { - // Fast path: Just use normal `copy_op` - return self.copy_op(src, dest); - } - // We still require the sizes to match. - if src.layout.size != dest.layout.size { - // FIXME: This should be an assert instead of an error, but if we transmute within an - // array length computation, `typeck` may not have yet been run and errored out. In fact - // most likey we *are* running `typeck` right now. Investigate whether we can bail out - // on `typeck_results().has_errors` at all const eval entry points. - debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); - self.tcx.sess.delay_span_bug( - self.cur_span(), - "size-changing transmute, should have been caught by transmute checking", - ); - throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); - } - // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want - // to avoid that here. - assert!( - !src.layout.is_unsized() && !dest.layout.is_unsized(), - "Cannot transmute unsized data" - ); - - // The hard case is `ScalarPair`. `src` is already read from memory in this case, - // using `src.layout` to figure out which bytes to use for the 1st and 2nd field. - // We have to write them to `dest` at the offsets they were *read at*, which is - // not necessarily the same as the offsets in `dest.layout`! - // Hence we do the copy with the source layout on both sides. We also make sure to write - // into memory, because if `dest` is a local we would not even have a way to write - // at the `src` offsets; the fact that we came from a different layout would - // just be lost. - let dest = self.force_allocation(dest)?; - self.copy_op_no_validate( - src, - &PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }), - )?; - - if M::enforce_validity(self) { - // Data got changed, better make sure it matches the type! - self.validate_operand(&dest.into())?; - } - - Ok(()) - } - - /// Ensures that a place is in memory, and returns where it is. - /// If the place currently refers to a local that doesn't yet have a matching allocation, - /// create such an allocation. - /// This is essentially `force_to_memplace`. - /// - /// This supports unsized types and returns the computed size to avoid some - /// redundant computation when copying; use `force_allocation` for a simpler, sized-only - /// version. - pub fn force_allocation_maybe_sized( - &mut self, - place: &PlaceTy<'tcx, M::PointerTag>, - meta: MemPlaceMeta, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option)> { - let (mplace, size) = match place.place { - Place::Local { frame, local } => { - match M::access_local_mut(self, frame, local)? { - Ok(&mut local_val) => { - // We need to make an allocation. - - // We need the layout of the local. We can NOT use the layout we got, - // that might e.g., be an inner field of a struct with `Scalar` layout, - // that has different alignment than the outer field. - let local_layout = - self.layout_of_local(&self.stack()[frame], local, None)?; - // We also need to support unsized types, and hence cannot use `allocate`. - let (size, align) = self - .size_and_align_of(&meta, &local_layout)? - .expect("Cannot allocate for non-dyn-sized type"); - let ptr = self.memory.allocate(size, align, MemoryKind::Stack)?; - let mplace = MemPlace { ptr: ptr.into(), align, meta }; - if let LocalValue::Live(Operand::Immediate(value)) = local_val { - // Preserve old value. - // We don't have to validate as we can assume the local - // was already valid for its type. - let mplace = MPlaceTy { mplace, layout: local_layout }; - self.write_immediate_to_mplace_no_validate(value, &mplace)?; - } - // Now we can call `access_mut` again, asserting it goes well, - // and actually overwrite things. - *M::access_local_mut(self, frame, local).unwrap().unwrap() = - LocalValue::Live(Operand::Indirect(mplace)); - (mplace, Some(size)) - } - Err(mplace) => (mplace, None), // this already was an indirect local - } - } - Place::Ptr(mplace) => (mplace, None), - }; - // Return with the original layout, so that the caller can go on - Ok((MPlaceTy { mplace, layout: place.layout }, size)) - } - - #[inline(always)] - pub fn force_allocation( - &mut self, - place: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0) - } - - pub fn allocate( - &mut self, - layout: TyAndLayout<'tcx>, - kind: MemoryKind, - ) -> InterpResult<'static, MPlaceTy<'tcx, M::PointerTag>> { - let ptr = self.memory.allocate(layout.size, layout.align.abi, kind)?; - Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) - } - - /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation. - pub fn allocate_str( - &mut self, - str: &str, - kind: MemoryKind, - mutbl: Mutability, - ) -> MPlaceTy<'tcx, M::PointerTag> { - let ptr = self.memory.allocate_bytes(str.as_bytes(), Align::ONE, kind, mutbl); - let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self); - let mplace = - MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) }; - - let ty = self.tcx.mk_ref( - self.tcx.lifetimes.re_static, - ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, - ); - let layout = self.layout_of(ty).unwrap(); - MPlaceTy { mplace, layout } - } - - /// Writes the discriminant of the given variant. - pub fn write_discriminant( - &mut self, - variant_index: VariantIdx, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - // Layout computation excludes uninhabited variants from consideration - // therefore there's no way to represent those variants in the given layout. - if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() { - throw_ub!(Unreachable); - } - - match dest.layout.variants { - Variants::Single { index } => { - assert_eq!(index, variant_index); - } - Variants::Multiple { - tag_encoding: TagEncoding::Direct, - tag: ref tag_layout, - tag_field, - .. - } => { - // No need to validate that the discriminant here because the - // `TyAndLayout::for_variant()` call earlier already checks the variant is valid. - - let discr_val = - dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val; - - // raw discriminants for enums are isize or bigger during - // their computation, but the in-memory tag is the smallest possible - // representation - let size = tag_layout.value.size(self); - let tag_val = size.truncate(discr_val); - - let tag_dest = self.place_field(dest, tag_field)?; - self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?; - } - Variants::Multiple { - tag_encoding: - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, - tag: ref tag_layout, - tag_field, - .. - } => { - // No need to validate that the discriminant here because the - // `TyAndLayout::for_variant()` call earlier already checks the variant is valid. - - if variant_index != dataful_variant { - let variants_start = niche_variants.start().as_u32(); - let variant_index_relative = variant_index - .as_u32() - .checked_sub(variants_start) - .expect("overflow computing relative variant idx"); - // We need to use machine arithmetic when taking into account `niche_start`: - // tag_val = variant_index_relative + niche_start_val - let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?; - let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); - let variant_index_relative_val = - ImmTy::from_uint(variant_index_relative, tag_layout); - let tag_val = self.binary_op( - mir::BinOp::Add, - &variant_index_relative_val, - &niche_start_val, - )?; - // Write result. - let niche_dest = self.place_field(dest, tag_field)?; - self.write_immediate(*tag_val, &niche_dest)?; - } - } - } - - Ok(()) - } - - pub fn raw_const_to_mplace( - &self, - raw: ConstAlloc<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - // This must be an allocation in `tcx` - let _ = self.tcx.global_alloc(raw.alloc_id); - let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; - let layout = self.layout_of(raw.ty)?; - Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) - } - - /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. - /// Also return some more information so drop doesn't have to run the same code twice. - pub(super) fn unpack_dyn_trait( - &self, - mplace: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> { - let vtable = self.scalar_to_ptr(mplace.vtable()); // also sanity checks the type - let (instance, ty) = self.read_drop_type_from_vtable(vtable)?; - let layout = self.layout_of(ty)?; - - // More sanity checks - if cfg!(debug_assertions) { - let (size, align) = self.read_size_and_align_from_vtable(vtable)?; - assert_eq!(size, layout.size); - // only ABI alignment is preserved - assert_eq!(align, layout.align.abi); - } - - let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout }; - Ok((instance, mplace)) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/step.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/step.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/step.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/step.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,316 +0,0 @@ -//! This module contains the `InterpCx` methods for executing a single step of the interpreter. -//! -//! The main entry point is the `step` method. - -use rustc_middle::mir; -use rustc_middle::mir::interpret::{InterpResult, Scalar}; -use rustc_target::abi::LayoutOf; - -use super::{InterpCx, Machine}; - -/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the -/// same type as the result. -#[inline] -fn binop_left_homogeneous(op: mir::BinOp) -> bool { - use rustc_middle::mir::BinOp::*; - match op { - Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Offset | Shl | Shr => true, - Eq | Ne | Lt | Le | Gt | Ge => false, - } -} -/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the -/// same type as the LHS. -#[inline] -fn binop_right_homogeneous(op: mir::BinOp) -> bool { - use rustc_middle::mir::BinOp::*; - match op { - Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true, - Offset | Shl | Shr => false, - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn run(&mut self) -> InterpResult<'tcx> { - while self.step()? {} - Ok(()) - } - - /// Returns `true` as long as there are more things to do. - /// - /// This is used by [priroda](https://github.com/oli-obk/priroda) - /// - /// This is marked `#inline(always)` to work around adverserial codegen when `opt-level = 3` - #[inline(always)] - pub fn step(&mut self) -> InterpResult<'tcx, bool> { - if self.stack().is_empty() { - return Ok(false); - } - - let loc = match self.frame().loc { - Ok(loc) => loc, - Err(_) => { - // We are unwinding and this fn has no cleanup code. - // Just go on unwinding. - trace!("unwinding: skipping frame"); - self.pop_stack_frame(/* unwinding */ true)?; - return Ok(true); - } - }; - let basic_block = &self.body().basic_blocks()[loc.block]; - - let old_frames = self.frame_idx(); - - if let Some(stmt) = basic_block.statements.get(loc.statement_index) { - assert_eq!(old_frames, self.frame_idx()); - self.statement(stmt)?; - return Ok(true); - } - - M::before_terminator(self)?; - - let terminator = basic_block.terminator(); - assert_eq!(old_frames, self.frame_idx()); - self.terminator(terminator)?; - Ok(true) - } - - /// Runs the interpretation logic for the given `mir::Statement` at the current frame and - /// statement counter. This also moves the statement counter forward. - crate fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { - info!("{:?}", stmt); - - use rustc_middle::mir::StatementKind::*; - - // Some statements (e.g., box) push new stack frames. - // We have to record the stack frame number *before* executing the statement. - let frame_idx = self.frame_idx(); - - match &stmt.kind { - Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?, - - SetDiscriminant { place, variant_index } => { - let dest = self.eval_place(**place)?; - self.write_discriminant(*variant_index, &dest)?; - } - - // Mark locals as alive - StorageLive(local) => { - self.storage_live(*local)?; - } - - // Mark locals as dead - StorageDead(local) => { - self.storage_dead(*local)?; - } - - // No dynamic semantics attached to `FakeRead`; MIR - // interpreter is solely intended for borrowck'ed code. - FakeRead(..) => {} - - // Stacked Borrows. - Retag(kind, place) => { - let dest = self.eval_place(**place)?; - M::retag(self, *kind, &dest)?; - } - - // Call CopyNonOverlapping - CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => { - let src = self.eval_operand(src, None)?; - let dst = self.eval_operand(dst, None)?; - let count = self.eval_operand(count, None)?; - self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?; - } - - // Statements we do not track. - AscribeUserType(..) => {} - - // Currently, Miri discards Coverage statements. Coverage statements are only injected - // via an optional compile time MIR pass and have no side effects. Since Coverage - // statements don't exist at the source level, it is safe for Miri to ignore them, even - // for undefined behavior (UB) checks. - // - // A coverage counter inside a const expression (for example, a counter injected in a - // const function) is discarded when the const is evaluated at compile time. Whether - // this should change, and/or how to implement a const eval counter, is a subject of the - // following issue: - // - // FIXME(#73156): Handle source code coverage in const eval - Coverage(..) => {} - - // Defined to do nothing. These are added by optimization passes, to avoid changing the - // size of MIR constantly. - Nop => {} - - LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), - } - - self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1; - Ok(()) - } - - /// Evaluate an assignment statement. - /// - /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue - /// type writes its results directly into the memory specified by the place. - pub fn eval_rvalue_into_place( - &mut self, - rvalue: &mir::Rvalue<'tcx>, - place: mir::Place<'tcx>, - ) -> InterpResult<'tcx> { - let dest = self.eval_place(place)?; - - use rustc_middle::mir::Rvalue::*; - match *rvalue { - ThreadLocalRef(did) => { - let ptr = M::thread_local_static_base_pointer(self, did)?; - self.write_pointer(ptr, &dest)?; - } - - Use(ref operand) => { - // Avoid recomputing the layout - let op = self.eval_operand(operand, Some(dest.layout))?; - self.copy_op(&op, &dest)?; - } - - BinaryOp(bin_op, box (ref left, ref right)) => { - let layout = binop_left_homogeneous(bin_op).then_some(dest.layout); - let left = self.read_immediate(&self.eval_operand(left, layout)?)?; - let layout = binop_right_homogeneous(bin_op).then_some(left.layout); - let right = self.read_immediate(&self.eval_operand(right, layout)?)?; - self.binop_ignore_overflow(bin_op, &left, &right, &dest)?; - } - - CheckedBinaryOp(bin_op, box (ref left, ref right)) => { - // Due to the extra boolean in the result, we can never reuse the `dest.layout`. - let left = self.read_immediate(&self.eval_operand(left, None)?)?; - let layout = binop_right_homogeneous(bin_op).then_some(left.layout); - let right = self.read_immediate(&self.eval_operand(right, layout)?)?; - self.binop_with_overflow(bin_op, &left, &right, &dest)?; - } - - UnaryOp(un_op, ref operand) => { - // The operand always has the same type as the result. - let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?; - let val = self.unary_op(un_op, &val)?; - assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op); - self.write_immediate(*val, &dest)?; - } - - Aggregate(ref kind, ref operands) => { - let (dest, active_field_index) = match **kind { - mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { - self.write_discriminant(variant_index, &dest)?; - if adt_def.is_enum() { - (self.place_downcast(&dest, variant_index)?, active_field_index) - } else { - (dest, active_field_index) - } - } - _ => (dest, None), - }; - - for (i, operand) in operands.iter().enumerate() { - let op = self.eval_operand(operand, None)?; - // Ignore zero-sized fields. - if !op.layout.is_zst() { - let field_index = active_field_index.unwrap_or(i); - let field_dest = self.place_field(&dest, field_index)?; - self.copy_op(&op, &field_dest)?; - } - } - } - - Repeat(ref operand, _) => { - let src = self.eval_operand(operand, None)?; - assert!(!src.layout.is_unsized()); - let dest = self.force_allocation(&dest)?; - let length = dest.len(self)?; - - if length == 0 { - // Nothing to copy... but let's still make sure that `dest` as a place is valid. - self.get_alloc_mut(&dest)?; - } else { - // Write the src to the first element. - let first = self.mplace_field(&dest, 0)?; - self.copy_op(&src, &first.into())?; - - // This is performance-sensitive code for big static/const arrays! So we - // avoid writing each operand individually and instead just make many copies - // of the first element. - let elem_size = first.layout.size; - let first_ptr = first.ptr; - let rest_ptr = first_ptr.offset(elem_size, self)?; - self.memory.copy_repeatedly( - first_ptr, - first.align, - rest_ptr, - first.align, - elem_size, - length - 1, - /*nonoverlapping:*/ true, - )?; - } - } - - Len(place) => { - // FIXME(CTFE): don't allow computing the length of arrays in const eval - let src = self.eval_place(place)?; - let mplace = self.force_allocation(&src)?; - let len = mplace.len(self)?; - self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?; - } - - AddressOf(_, place) | Ref(_, _, place) => { - let src = self.eval_place(place)?; - let place = self.force_allocation(&src)?; - self.write_immediate(place.to_ref(self), &dest)?; - } - - NullaryOp(mir::NullOp::Box, _) => { - M::box_alloc(self, &dest)?; - } - - NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty); - let layout = self.layout_of(ty)?; - if layout.is_unsized() { - // FIXME: This should be a span_bug (#80742) - self.tcx.sess.delay_span_bug( - self.frame().current_span(), - &format!("SizeOf nullary MIR operator called for unsized type {}", ty), - ); - throw_inval!(SizeOfUnsizedType(ty)); - } - self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), &dest)?; - } - - Cast(cast_kind, ref operand, cast_ty) => { - let src = self.eval_operand(operand, None)?; - let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty); - self.cast(&src, cast_kind, cast_ty, &dest)?; - } - - Discriminant(place) => { - let op = self.eval_place_to_op(place, None)?; - let discr_val = self.read_discriminant(&op)?.0; - self.write_scalar(discr_val, &dest)?; - } - } - - trace!("{:?}", self.dump_place(*dest)); - - Ok(()) - } - - fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { - info!("{:?}", terminator.kind); - - self.eval_terminator(terminator)?; - if !self.stack().is_empty() { - if let Ok(loc) = self.frame().loc { - info!("// executing {:?}", loc.block); - } - } - Ok(()) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/terminator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/terminator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/terminator.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/terminator.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,517 +0,0 @@ -use std::borrow::Cow; -use std::convert::TryFrom; - -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::ty::layout::{self, TyAndLayout}; -use rustc_middle::ty::Instance; -use rustc_middle::{ - mir, - ty::{self, Ty}, -}; -use rustc_target::abi::{self, LayoutOf as _}; -use rustc_target::spec::abi::Abi; - -use super::{ - FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Scalar, - StackPopCleanup, StackPopUnwind, -}; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool { - layout::fn_can_unwind(*self.tcx, attrs, abi) - } - - pub(super) fn eval_terminator( - &mut self, - terminator: &mir::Terminator<'tcx>, - ) -> InterpResult<'tcx> { - use rustc_middle::mir::TerminatorKind::*; - match terminator.kind { - Return => { - self.pop_stack_frame(/* unwinding */ false)? - } - - Goto { target } => self.go_to_block(target), - - SwitchInt { ref discr, ref targets, switch_ty } => { - let discr = self.read_immediate(&self.eval_operand(discr, None)?)?; - trace!("SwitchInt({:?})", *discr); - assert_eq!(discr.layout.ty, switch_ty); - - // Branch to the `otherwise` case by default, if no match is found. - assert!(!targets.iter().is_empty()); - let mut target_block = targets.otherwise(); - - for (const_int, target) in targets.iter() { - // Compare using binary_op, to also support pointer values - let res = self - .overflowing_binary_op( - mir::BinOp::Eq, - &discr, - &ImmTy::from_uint(const_int, discr.layout), - )? - .0; - if res.to_bool()? { - target_block = target; - break; - } - } - - self.go_to_block(target_block); - } - - Call { ref func, ref args, destination, ref cleanup, from_hir_call: _, fn_span: _ } => { - let old_stack = self.frame_idx(); - let old_loc = self.frame().loc; - let func = self.eval_operand(func, None)?; - let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() { - ty::FnPtr(sig) => { - let caller_abi = sig.abi(); - let fn_ptr = self.read_pointer(&func)?; - let fn_val = self.memory.get_fn(fn_ptr)?; - ( - fn_val, - caller_abi, - self.fn_can_unwind(CodegenFnAttrFlags::empty(), caller_abi), - ) - } - ty::FnDef(def_id, substs) => { - let sig = func.layout.ty.fn_sig(*self.tcx); - ( - FnVal::Instance( - self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?, - ), - sig.abi(), - self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()), - ) - } - _ => span_bug!( - terminator.source_info.span, - "invalid callee of type {:?}", - func.layout.ty - ), - }; - let args = self.eval_operands(args)?; - let dest_place; - let ret = match destination { - Some((dest, ret)) => { - dest_place = self.eval_place(dest)?; - Some((&dest_place, ret)) - } - None => None, - }; - self.eval_fn_call( - fn_val, - abi, - &args[..], - ret, - match (cleanup, caller_can_unwind) { - (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), - (None, true) => StackPopUnwind::Skip, - (_, false) => StackPopUnwind::NotAllowed, - }, - )?; - // Sanity-check that `eval_fn_call` either pushed a new frame or - // did a jump to another block. - if self.frame_idx() == old_stack && self.frame().loc == old_loc { - span_bug!(terminator.source_info.span, "evaluating this call made no progress"); - } - } - - Drop { place, target, unwind } => { - let place = self.eval_place(place)?; - let ty = place.layout.ty; - trace!("TerminatorKind::drop: {:?}, type {}", place, ty); - - let instance = Instance::resolve_drop_in_place(*self.tcx, ty); - self.drop_in_place(&place, instance, target, unwind)?; - } - - Assert { ref cond, expected, ref msg, target, cleanup } => { - let cond_val = - self.read_immediate(&self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?; - if expected == cond_val { - self.go_to_block(target); - } else { - M::assert_panic(self, msg, cleanup)?; - } - } - - Abort => { - M::abort(self, "the program aborted execution".to_owned())?; - } - - // When we encounter Resume, we've finished unwinding - // cleanup for the current stack frame. We pop it in order - // to continue unwinding the next frame - Resume => { - trace!("unwinding: resuming from cleanup"); - // By definition, a Resume terminator means - // that we're unwinding - self.pop_stack_frame(/* unwinding */ true)?; - return Ok(()); - } - - // It is UB to ever encounter this. - Unreachable => throw_ub!(Unreachable), - - // These should never occur for MIR we actually run. - DropAndReplace { .. } - | FalseEdge { .. } - | FalseUnwind { .. } - | Yield { .. } - | GeneratorDrop => span_bug!( - terminator.source_info.span, - "{:#?} should have been eliminated by MIR pass", - terminator.kind - ), - - // Inline assembly can't be interpreted. - InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), - } - - Ok(()) - } - - fn check_argument_compat( - rust_abi: bool, - caller: TyAndLayout<'tcx>, - callee: TyAndLayout<'tcx>, - ) -> bool { - if caller.ty == callee.ty { - // No question - return true; - } - if !rust_abi { - // Don't risk anything - return false; - } - // Compare layout - match (&caller.abi, &callee.abi) { - // Different valid ranges are okay (once we enforce validity, - // that will take care to make it UB to leave the range, just - // like for transmute). - (abi::Abi::Scalar(ref caller), abi::Abi::Scalar(ref callee)) => { - caller.value == callee.value - } - ( - abi::Abi::ScalarPair(ref caller1, ref caller2), - abi::Abi::ScalarPair(ref callee1, ref callee2), - ) => caller1.value == callee1.value && caller2.value == callee2.value, - // Be conservative - _ => false, - } - } - - /// Pass a single argument, checking the types for compatibility. - fn pass_argument( - &mut self, - rust_abi: bool, - caller_arg: &mut impl Iterator>, - callee_arg: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - if rust_abi && callee_arg.layout.is_zst() { - // Nothing to do. - trace!("Skipping callee ZST"); - return Ok(()); - } - let caller_arg = caller_arg.next().ok_or_else(|| { - err_ub_format!("calling a function with fewer arguments than it requires") - })?; - if rust_abi { - assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); - } - // Now, check - if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) { - throw_ub_format!( - "calling a function with argument of type {:?} passing data of type {:?}", - callee_arg.layout.ty, - caller_arg.layout.ty - ) - } - // We allow some transmutes here - self.copy_op_transmute(&caller_arg, callee_arg) - } - - /// Call this function -- pushing the stack frame and initializing the arguments. - fn eval_fn_call( - &mut self, - fn_val: FnVal<'tcx, M::ExtraFnVal>, - caller_abi: Abi, - args: &[OpTy<'tcx, M::PointerTag>], - ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, - mut unwind: StackPopUnwind, - ) -> InterpResult<'tcx> { - trace!("eval_fn_call: {:#?}", fn_val); - - let instance = match fn_val { - FnVal::Instance(instance) => instance, - FnVal::Other(extra) => { - return M::call_extra_fn(self, extra, caller_abi, args, ret, unwind); - } - }; - - let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() { - ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(), - ty::Closure(..) => Abi::RustCall, - ty::Generator(..) => Abi::Rust, - _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty), - }; - - // ABI check - let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> { - let normalize_abi = |abi| match abi { - Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic => - // These are all the same ABI, really. - { - Abi::Rust - } - abi => abi, - }; - if normalize_abi(caller_abi) != normalize_abi(callee_abi) { - throw_ub_format!( - "calling a function with ABI {} using caller ABI {}", - callee_abi.name(), - caller_abi.name() - ) - } - Ok(()) - }; - - match instance.def { - ty::InstanceDef::Intrinsic(..) => { - if M::enforce_abi(self) { - check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?; - } - assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic); - M::call_intrinsic(self, instance, args, ret, unwind) - } - ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::Item(_) => { - // We need MIR for this fn - let body = - match M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? { - Some(body) => body, - None => return Ok(()), - }; - - // Check against the ABI of the MIR body we are calling (not the ABI of `instance`; - // these can differ when `find_mir_or_eval_fn` does something clever like resolve - // exported symbol names). - let callee_def_id = body.source.def_id(); - let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id)); - - if M::enforce_abi(self) { - check_abi(callee_abi)?; - } - - if !matches!(unwind, StackPopUnwind::NotAllowed) - && !self - .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi) - { - // The callee cannot unwind. - unwind = StackPopUnwind::NotAllowed; - } - - self.push_stack_frame( - instance, - body, - ret.map(|p| p.0), - StackPopCleanup::Goto { ret: ret.map(|p| p.1), unwind }, - )?; - - // If an error is raised here, pop the frame again to get an accurate backtrace. - // To this end, we wrap it all in a `try` block. - let res: InterpResult<'tcx> = try { - trace!( - "caller ABI: {:?}, args: {:#?}", - caller_abi, - args.iter() - .map(|arg| (arg.layout.ty, format!("{:?}", **arg))) - .collect::>() - ); - trace!( - "spread_arg: {:?}, locals: {:#?}", - body.spread_arg, - body.args_iter() - .map(|local| ( - local, - self.layout_of_local(self.frame(), local, None).unwrap().ty - )) - .collect::>() - ); - - // Figure out how to pass which arguments. - // The Rust ABI is special: ZST get skipped. - let rust_abi = match caller_abi { - Abi::Rust | Abi::RustCall => true, - _ => false, - }; - // We have two iterators: Where the arguments come from, - // and where they go to. - - // For where they come from: If the ABI is RustCall, we untuple the - // last incoming argument. These two iterators do not have the same type, - // so to keep the code paths uniform we accept an allocation - // (for RustCall ABI only). - let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> = - if caller_abi == Abi::RustCall && !args.is_empty() { - // Untuple - let (untuple_arg, args) = args.split_last().unwrap(); - trace!("eval_fn_call: Will pass last argument by untupling"); - Cow::from( - args.iter() - .map(|&a| Ok(a)) - .chain( - (0..untuple_arg.layout.fields.count()) - .map(|i| self.operand_field(untuple_arg, i)), - ) - .collect::>>>( - )?, - ) - } else { - // Plain arg passing - Cow::from(args) - }; - // Skip ZSTs - let mut caller_iter = - caller_args.iter().filter(|op| !rust_abi || !op.layout.is_zst()).copied(); - - // Now we have to spread them out across the callee's locals, - // taking into account the `spread_arg`. If we could write - // this is a single iterator (that handles `spread_arg`), then - // `pass_argument` would be the loop body. It takes care to - // not advance `caller_iter` for ZSTs. - for local in body.args_iter() { - let dest = self.eval_place(mir::Place::from(local))?; - if Some(local) == body.spread_arg { - // Must be a tuple - for i in 0..dest.layout.fields.count() { - let dest = self.place_field(&dest, i)?; - self.pass_argument(rust_abi, &mut caller_iter, &dest)?; - } - } else { - // Normal argument - self.pass_argument(rust_abi, &mut caller_iter, &dest)?; - } - } - // Now we should have no more caller args - if caller_iter.next().is_some() { - throw_ub_format!("calling a function with more arguments than it expected") - } - // Don't forget to check the return type! - if let Some((caller_ret, _)) = ret { - let callee_ret = self.eval_place(mir::Place::return_place())?; - if !Self::check_argument_compat( - rust_abi, - caller_ret.layout, - callee_ret.layout, - ) { - throw_ub_format!( - "calling a function with return type {:?} passing \ - return place of type {:?}", - callee_ret.layout.ty, - caller_ret.layout.ty - ) - } - } else { - let local = mir::RETURN_PLACE; - let callee_layout = self.layout_of_local(self.frame(), local, None)?; - if !callee_layout.abi.is_uninhabited() { - throw_ub_format!("calling a returning function without a return place") - } - } - }; - match res { - Err(err) => { - self.stack_mut().pop(); - Err(err) - } - Ok(()) => Ok(()), - } - } - // cannot use the shim here, because that will only result in infinite recursion - ty::InstanceDef::Virtual(_, idx) => { - let mut args = args.to_vec(); - // We have to implement all "object safe receivers". Currently we - // support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do - // not yet support custom self types. - // Also see `compiler/rustc_codegen_llvm/src/abi.rs` and `compiler/rustc_codegen_ssa/src/mir/block.rs`. - let receiver_place = match args[0].layout.ty.builtin_deref(true) { - Some(_) => { - // Built-in pointer. - self.deref_operand(&args[0])? - } - None => { - // Unsized self. - args[0].assert_mem_place() - } - }; - // Find and consult vtable - let vtable = self.scalar_to_ptr(receiver_place.vtable()); - let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; - - // `*mut receiver_place.layout.ty` is almost the layout that we - // want for args[0]: We have to project to field 0 because we want - // a thin pointer. - assert!(receiver_place.layout.is_unsized()); - let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty); - let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0); - // Adjust receiver argument. - args[0] = OpTy::from(ImmTy::from_immediate( - Scalar::from_maybe_pointer(receiver_place.ptr, self).into(), - this_receiver_ptr, - )); - trace!("Patched self operand to {:#?}", args[0]); - // recurse with concrete function - self.eval_fn_call(fn_val, caller_abi, &args, ret, unwind) - } - } - } - - fn drop_in_place( - &mut self, - place: &PlaceTy<'tcx, M::PointerTag>, - instance: ty::Instance<'tcx>, - target: mir::BasicBlock, - unwind: Option, - ) -> InterpResult<'tcx> { - trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance); - // We take the address of the object. This may well be unaligned, which is fine - // for us here. However, unaligned accesses will probably make the actual drop - // implementation fail -- a problem shared by rustc. - let place = self.force_allocation(place)?; - - let (instance, place) = match place.layout.ty.kind() { - ty::Dynamic(..) => { - // Dropping a trait object. - self.unpack_dyn_trait(&place)? - } - _ => (instance, place), - }; - - let arg = ImmTy::from_immediate( - place.to_ref(self), - self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?, - ); - - let ty = self.tcx.mk_unit(); // return type is () - let dest = MPlaceTy::dangling(self.layout_of(ty)?); - - self.eval_fn_call( - FnVal::Instance(instance), - Abi::Rust, - &[arg.into()], - Some((&dest.into(), target)), - match unwind { - Some(cleanup) => StackPopUnwind::Cleanup(cleanup), - None => StackPopUnwind::Skip, - }, - ) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/traits.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/traits.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/traits.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/traits.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -use std::convert::TryFrom; - -use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic}; -use rustc_middle::ty::{ - self, Ty, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN, - COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE, -}; -use rustc_target::abi::{Align, Size}; - -use super::util::ensure_monomorphic_enough; -use super::{FnVal, InterpCx, Machine}; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Creates a dynamic vtable for the given type and vtable origin. This is used only for - /// objects. - /// - /// The `trait_ref` encodes the erased self type. Hence, if we are - /// making an object `Foo` from a value of type `Foo`, then - /// `trait_ref` would map `T: Trait`. - pub fn get_vtable( - &mut self, - ty: Ty<'tcx>, - poly_trait_ref: Option>, - ) -> InterpResult<'tcx, Pointer>> { - trace!("get_vtable(trait_ref={:?})", poly_trait_ref); - - let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); - - // All vtables must be monomorphic, bail out otherwise. - ensure_monomorphic_enough(*self.tcx, ty)?; - ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; - - let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref)); - - let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_allocation))?; - - Ok(vtable_ptr.into()) - } - - /// Resolves the function at the specified slot in the provided - /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`) - /// corresponds to the first method declared in the trait of the provided vtable. - pub fn get_vtable_slot( - &self, - vtable: Pointer>, - idx: u64, - ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { - let ptr_size = self.pointer_size(); - let vtable_slot = vtable.offset(ptr_size * idx, self)?; - let vtable_slot = self - .memory - .get(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? - .expect("cannot be a ZST"); - let fn_ptr = self.scalar_to_ptr(vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?); - self.memory.get_fn(fn_ptr) - } - - /// Returns the drop fn instance as well as the actual dynamic type. - pub fn read_drop_type_from_vtable( - &self, - vtable: Pointer>, - ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> { - let pointer_size = self.pointer_size(); - // We don't care about the pointee type; we just want a pointer. - let vtable = self - .memory - .get( - vtable, - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(), - self.tcx.data_layout.pointer_align.abi, - )? - .expect("cannot be a ZST"); - let drop_fn = vtable - .read_ptr_sized( - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap(), - )? - .check_init()?; - // We *need* an instance here, no other kind of function value, to be able - // to determine the type. - let drop_instance = self.memory.get_fn(self.scalar_to_ptr(drop_fn))?.as_instance()?; - trace!("Found drop fn: {:?}", drop_instance); - let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); - let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig); - // The drop function takes `*mut T` where `T` is the type being dropped, so get that. - let args = fn_sig.inputs(); - if args.len() != 1 { - throw_ub!(InvalidVtableDropFn(fn_sig)); - } - let ty = - args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty; - Ok((drop_instance, ty)) - } - - pub fn read_size_and_align_from_vtable( - &self, - vtable: Pointer>, - ) -> InterpResult<'tcx, (Size, Align)> { - let pointer_size = self.pointer_size(); - // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here), - // the size, and the align (which we read below). - let vtable = self - .memory - .get( - vtable, - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(), - self.tcx.data_layout.pointer_align.abi, - )? - .expect("cannot be a ZST"); - let size = vtable - .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())? - .check_init()?; - let size = size.to_machine_usize(self)?; - let align = vtable - .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())? - .check_init()?; - let align = align.to_machine_usize(self)?; - let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?; - - if size >= self.tcx.data_layout.obj_size_bound() { - throw_ub!(InvalidVtableSize); - } - Ok((Size::from_bytes(size), align)) - } - - pub fn read_new_vtable_after_trait_upcasting_from_vtable( - &self, - vtable: Pointer>, - idx: u64, - ) -> InterpResult<'tcx, Pointer>> { - let pointer_size = self.pointer_size(); - - let vtable_slot = vtable.offset(pointer_size * idx, self)?; - let new_vtable = self - .memory - .get(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)? - .expect("cannot be a ZST"); - - let new_vtable = self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?); - - Ok(new_vtable) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/util.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/util.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -use rustc_middle::mir::interpret::InterpResult; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor}; -use std::convert::TryInto; -use std::ops::ControlFlow; - -/// Returns `true` if a used generic parameter requires substitution. -crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx> -where - T: TypeFoldable<'tcx>, -{ - debug!("ensure_monomorphic_enough: ty={:?}", ty); - if !ty.potentially_needs_subst() { - return Ok(()); - } - - struct FoundParam; - struct UsedParamsNeedSubstVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { - type BreakTy = FoundParam; - - fn tcx_for_anon_const_substs(&self) -> Option> { - Some(self.tcx) - } - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.potentially_needs_subst() { - return ControlFlow::CONTINUE; - } - - match *ty.kind() { - ty::Param(_) => ControlFlow::Break(FoundParam), - ty::Closure(def_id, substs) - | ty::Generator(def_id, substs, ..) - | ty::FnDef(def_id, substs) => { - let unused_params = self.tcx.unused_generic_params(def_id); - for (index, subst) in substs.into_iter().enumerate() { - let index = index - .try_into() - .expect("more generic parameters than can fit into a `u32`"); - let is_used = unused_params.contains(index).map_or(true, |unused| !unused); - // Only recurse when generic parameters in fns, closures and generators - // are used and require substitution. - match (is_used, subst.definitely_needs_subst(self.tcx)) { - // Just in case there are closures or generators within this subst, - // recurse. - (true, true) => return subst.super_visit_with(self), - // Confirm that polymorphization replaced the parameter with - // `ty::Param`/`ty::ConstKind::Param`. - (false, true) if cfg!(debug_assertions) => match subst.unpack() { - ty::subst::GenericArgKind::Type(ty) => { - assert!(matches!(ty.kind(), ty::Param(_))) - } - ty::subst::GenericArgKind::Const(ct) => { - assert!(matches!(ct.val, ty::ConstKind::Param(_))) - } - ty::subst::GenericArgKind::Lifetime(..) => (), - }, - _ => {} - } - } - ControlFlow::CONTINUE - } - _ => ty.super_visit_with(self), - } - } - - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { - match c.val { - ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), - _ => c.super_visit_with(self), - } - } - } - - let mut vis = UsedParamsNeedSubstVisitor { tcx }; - if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { - throw_inval!(TooGeneric); - } else { - Ok(()) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/validity.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/validity.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/validity.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/validity.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,967 +0,0 @@ -//! Check the validity invariant of a given value, and tell the user -//! where in the value it got violated. -//! In const context, this goes even further and tries to approximate const safety. -//! That's useful because it means other passes (e.g. promotion) can rely on `const`s -//! to be const-safe. - -use std::convert::TryFrom; -use std::fmt::Write; -use std::num::NonZeroUsize; - -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_middle::mir::interpret::InterpError; -use rustc_middle::ty; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{ - Abi, LayoutOf, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, -}; - -use std::hash::Hash; - -use super::{ - alloc_range, CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, - MemPlaceMeta, OpTy, ScalarMaybeUninit, ValueVisitor, -}; - -macro_rules! throw_validation_failure { - ($where:expr, { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )?) => {{ - let mut msg = String::new(); - msg.push_str("encountered "); - write!(&mut msg, $($what_fmt),+).unwrap(); - $( - msg.push_str(", but expected "); - write!(&mut msg, $($expected_fmt),+).unwrap(); - )? - let path = rustc_middle::ty::print::with_no_trimmed_paths(|| { - let where_ = &$where; - if !where_.is_empty() { - let mut path = String::new(); - write_path(&mut path, where_); - Some(path) - } else { - None - } - }); - throw_ub!(ValidationFailure { path, msg }) - }}; -} - -/// If $e throws an error matching the pattern, throw a validation failure. -/// Other errors are passed back to the caller, unchanged -- and if they reach the root of -/// the visitor, we make sure only validation errors and `InvalidProgram` errors are left. -/// This lets you use the patterns as a kind of validation list, asserting which errors -/// can possibly happen: -/// -/// ``` -/// let v = try_validation!(some_fn(), some_path, { -/// Foo | Bar | Baz => { "some failure" }, -/// }); -/// ``` -/// -/// An additional expected parameter can also be added to the failure message: -/// -/// ``` -/// let v = try_validation!(some_fn(), some_path, { -/// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" }, -/// }); -/// ``` -/// -/// An additional nicety is that both parameters actually take format args, so you can just write -/// the format string in directly: -/// -/// ``` -/// let v = try_validation!(some_fn(), some_path, { -/// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value }, -/// }); -/// ``` -/// -macro_rules! try_validation { - ($e:expr, $where:expr, - $( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)? - ) => {{ - match $e { - Ok(x) => x, - // We catch the error and turn it into a validation failure. We are okay with - // allocation here as this can only slow down builds that fail anyway. - Err(e) => match e.kind() { - $( - $($p)|+ => - throw_validation_failure!( - $where, - { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )? - ) - ),+, - #[allow(unreachable_patterns)] - _ => Err::(e)?, - } - } - }}; -} - -/// We want to show a nice path to the invalid field for diagnostics, -/// but avoid string operations in the happy case where no error happens. -/// So we track a `Vec` where `PathElem` contains all the data we -/// need to later print something for the user. -#[derive(Copy, Clone, Debug)] -pub enum PathElem { - Field(Symbol), - Variant(Symbol), - GeneratorState(VariantIdx), - CapturedVar(Symbol), - ArrayElem(usize), - TupleElem(usize), - Deref, - EnumTag, - GeneratorTag, - DynDowncast, -} - -/// Extra things to check for during validation of CTFE results. -pub enum CtfeValidationMode { - /// Regular validation, nothing special happening. - Regular, - /// Validation of a `const`. - /// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const - /// allocation). Being an inner allocation makes a difference because the top-level allocation - /// of a `const` is copied for each use, but the inner allocations are implicitly shared. - /// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics). - Const { inner: bool, allow_static_ptrs: bool }, -} - -/// State for tracking recursive validation of references -pub struct RefTracking { - pub seen: FxHashSet, - pub todo: Vec<(T, PATH)>, -} - -impl RefTracking { - pub fn empty() -> Self { - RefTracking { seen: FxHashSet::default(), todo: vec![] } - } - pub fn new(op: T) -> Self { - let mut ref_tracking_for_consts = - RefTracking { seen: FxHashSet::default(), todo: vec![(op, PATH::default())] }; - ref_tracking_for_consts.seen.insert(op); - ref_tracking_for_consts - } - - pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { - if self.seen.insert(op) { - trace!("Recursing below ptr {:#?}", op); - let path = path(); - // Remember to come back to this later. - self.todo.push((op, path)); - } - } -} - -/// Format a path -fn write_path(out: &mut String, path: &[PathElem]) { - use self::PathElem::*; - - for elem in path.iter() { - match elem { - Field(name) => write!(out, ".{}", name), - EnumTag => write!(out, "."), - Variant(name) => write!(out, ".", name), - GeneratorTag => write!(out, "."), - GeneratorState(idx) => write!(out, ".", idx.index()), - CapturedVar(name) => write!(out, ".", name), - TupleElem(idx) => write!(out, ".{}", idx), - ArrayElem(idx) => write!(out, "[{}]", idx), - // `.` does not match Rust syntax, but it is more readable for long paths -- and - // some of the other items here also are not Rust syntax. Actually we can't - // even use the usual syntax because we are just showing the projections, - // not the root. - Deref => write!(out, "."), - DynDowncast => write!(out, "."), - } - .unwrap() - } -} - -// Formats such that a sentence like "expected something {}" to mean -// "expected something " makes sense. -fn wrapping_range_format(r: WrappingRange, max_hi: u128) -> String { - let WrappingRange { start: lo, end: hi } = r; - assert!(hi <= max_hi); - if lo > hi { - format!("less or equal to {}, or greater or equal to {}", hi, lo) - } else if lo == hi { - format!("equal to {}", lo) - } else if lo == 0 { - assert!(hi < max_hi, "should not be printing if the range covers everything"); - format!("less or equal to {}", hi) - } else if hi == max_hi { - assert!(lo > 0, "should not be printing if the range covers everything"); - format!("greater or equal to {}", lo) - } else { - format!("in the range {:?}", r) - } -} - -struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { - /// The `path` may be pushed to, but the part that is present when a function - /// starts must not be changed! `visit_fields` and `visit_array` rely on - /// this stack discipline. - path: Vec, - ref_tracking: Option<&'rt mut RefTracking, Vec>>, - /// `None` indicates this is not validating for CTFE (but for runtime). - ctfe_mode: Option, - ecx: &'rt InterpCx<'mir, 'tcx, M>, -} - -impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> { - fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem { - // First, check if we are projecting to a variant. - match layout.variants { - Variants::Multiple { tag_field, .. } => { - if tag_field == field { - return match layout.ty.kind() { - ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, - ty::Generator(..) => PathElem::GeneratorTag, - _ => bug!("non-variant type {:?}", layout.ty), - }; - } - } - Variants::Single { .. } => {} - } - - // Now we know we are projecting to a field, so figure out which one. - match layout.ty.kind() { - // generators and closures. - ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - let mut name = None; - // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar - // https://github.com/rust-lang/project-rfc-2229/issues/46 - if let Some(local_def_id) = def_id.as_local() { - let tables = self.ecx.tcx.typeck(local_def_id); - if let Some(captured_place) = - tables.closure_min_captures_flattened(*def_id).nth(field) - { - // Sometimes the index is beyond the number of upvars (seen - // for a generator). - let var_hir_id = captured_place.get_root_variable(); - let node = self.ecx.tcx.hir().get(var_hir_id); - if let hir::Node::Binding(pat) = node { - if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { - name = Some(ident.name); - } - } - } - } - - PathElem::CapturedVar(name.unwrap_or_else(|| { - // Fall back to showing the field index. - sym::integer(field) - })) - } - - // tuples - ty::Tuple(_) => PathElem::TupleElem(field), - - // enums - ty::Adt(def, ..) if def.is_enum() => { - // we might be projecting *to* a variant, or to a field *in* a variant. - match layout.variants { - Variants::Single { index } => { - // Inside a variant - PathElem::Field(def.variants[index].fields[field].ident.name) - } - Variants::Multiple { .. } => bug!("we handled variants above"), - } - } - - // other ADTs - ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name), - - // arrays/slices - ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field), - - // dyn traits - ty::Dynamic(..) => PathElem::DynDowncast, - - // nothing else has an aggregate layout - _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", layout.ty), - } - } - - fn with_elem( - &mut self, - elem: PathElem, - f: impl FnOnce(&mut Self) -> InterpResult<'tcx, R>, - ) -> InterpResult<'tcx, R> { - // Remember the old state - let path_len = self.path.len(); - // Record new element - self.path.push(elem); - // Perform operation - let r = f(self)?; - // Undo changes - self.path.truncate(path_len); - // Done - Ok(r) - } - - fn check_wide_ptr_meta( - &mut self, - meta: MemPlaceMeta, - pointee: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx> { - let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); - match tail.kind() { - ty::Dynamic(..) => { - let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta()); - // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. - try_validation!( - self.ecx.memory.check_ptr_access_align( - vtable, - 3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align - self.ecx.tcx.data_layout.pointer_align.abi, - CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message - ), - self.path, - err_ub!(DanglingIntPointer(..)) | - err_ub!(PointerUseAfterFree(..)) => - { "dangling vtable pointer in wide pointer" }, - err_ub!(AlignmentCheckFailed { .. }) => - { "unaligned vtable pointer in wide pointer" }, - err_ub!(PointerOutOfBounds { .. }) => - { "too small vtable" }, - ); - try_validation!( - self.ecx.read_drop_type_from_vtable(vtable), - self.path, - err_ub!(DanglingIntPointer(..)) | - err_ub!(InvalidFunctionPointer(..)) => - { "invalid drop function pointer in vtable (not pointing to a function)" }, - err_ub!(InvalidVtableDropFn(..)) => - { "invalid drop function pointer in vtable (function has incompatible signature)" }, - ); - try_validation!( - self.ecx.read_size_and_align_from_vtable(vtable), - self.path, - err_ub!(InvalidVtableSize) => - { "invalid vtable: size is bigger than largest supported object" }, - err_ub!(InvalidVtableAlignment(msg)) => - { "invalid vtable: alignment {}", msg }, - err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, - ); - // FIXME: More checks for the vtable. - } - ty::Slice(..) | ty::Str => { - let _len = try_validation!( - meta.unwrap_meta().to_machine_usize(self.ecx), - self.path, - err_unsup!(ReadPointerAsBytes) => { "non-integer slice length in wide pointer" }, - ); - // We do not check that `len * elem_size <= isize::MAX`: - // that is only required for references, and there it falls out of the - // "dereferenceable" check performed by Stacked Borrows. - } - ty::Foreign(..) => { - // Unsized, but not wide. - } - _ => bug!("Unexpected unsized type tail: {:?}", tail), - } - - Ok(()) - } - - /// Check a reference or `Box`. - fn check_safe_pointer( - &mut self, - value: &OpTy<'tcx, M::PointerTag>, - kind: &str, - ) -> InterpResult<'tcx> { - let value = try_validation!( - self.ecx.read_immediate(value), - self.path, - err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" }, - ); - // Handle wide pointers. - // Check metadata early, for better diagnostics - let place = try_validation!( - self.ecx.ref_to_mplace(&value), - self.path, - err_ub!(InvalidUninitBytes(None)) => { "uninitialized {}", kind }, - ); - if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta, place.layout)?; - } - // Make sure this is dereferenceable and all. - let size_and_align = try_validation!( - self.ecx.size_and_align_of_mplace(&place), - self.path, - err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg }, - ); - let (size, align) = size_and_align - // for the purpose of validity, consider foreign types to have - // alignment and size determined by the layout (size will be 0, - // alignment should take attributes into account). - .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); - // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. - try_validation!( - self.ecx.memory.check_ptr_access_align( - place.ptr, - size, - align, - CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message - ), - self.path, - err_ub!(AlignmentCheckFailed { required, has }) => - { - "an unaligned {} (required {} byte alignment but found {})", - kind, - required.bytes(), - has.bytes() - }, - err_ub!(DanglingIntPointer(0, _)) => - { "a null {}", kind }, - err_ub!(DanglingIntPointer(i, _)) => - { "a dangling {} (address 0x{:x} is unallocated)", kind, i }, - err_ub!(PointerOutOfBounds { .. }) => - { "a dangling {} (going beyond the bounds of its allocation)", kind }, - // This cannot happen during const-eval (because interning already detects - // dangling pointers), but it can happen in Miri. - err_ub!(PointerUseAfterFree(..)) => - { "a dangling {} (use-after-free)", kind }, - ); - // Recursive checking - if let Some(ref mut ref_tracking) = self.ref_tracking { - // Proceed recursively even for ZST, no reason to skip them! - // `!` is a ZST and we want to validate it. - // Skip validation entirely for some external statics - if let Ok((alloc_id, _offset, _ptr)) = self.ecx.memory.ptr_try_get_alloc(place.ptr) { - // not a ZST - let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id); - if let Some(GlobalAlloc::Static(did)) = alloc_kind { - assert!(!self.ecx.tcx.is_thread_local_static(did)); - assert!(self.ecx.tcx.is_static(did)); - if matches!( - self.ctfe_mode, - Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) - ) { - // See const_eval::machine::MemoryExtra::can_access_statics for why - // this check is so important. - // This check is reachable when the const just referenced the static, - // but never read it (so we never entered `before_access_global`). - throw_validation_failure!(self.path, - { "a {} pointing to a static variable", kind } - ); - } - // We skip checking other statics. These statics must be sound by - // themselves, and the only way to get broken statics here is by using - // unsafe code. - // The reasons we don't check other statics is twofold. For one, in all - // sound cases, the static was already validated on its own, and second, we - // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us. - // We might miss const-invalid data, - // but things are still sound otherwise (in particular re: consts - // referring to statics). - return Ok(()); - } - } - let path = &self.path; - ref_tracking.track(place, || { - // We need to clone the path anyway, make sure it gets created - // with enough space for the additional `Deref`. - let mut new_path = Vec::with_capacity(path.len() + 1); - new_path.clone_from(path); - new_path.push(PathElem::Deref); - new_path - }); - } - Ok(()) - } - - fn read_scalar( - &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - Ok(try_validation!( - self.ecx.read_scalar(op), - self.path, - err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "plain (non-pointer) bytes" }, - )) - } - - /// Check if this is a value of primitive type, and if yes check the validity of the value - /// at that type. Return `true` if the type is indeed primitive. - fn try_visit_primitive( - &mut self, - value: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, bool> { - // Go over all the primitive types - let ty = value.layout.ty; - match ty.kind() { - ty::Bool => { - let value = self.read_scalar(value)?; - try_validation!( - value.to_bool(), - self.path, - err_ub!(InvalidBool(..)) | err_ub!(InvalidUninitBytes(None)) => - { "{}", value } expected { "a boolean" }, - ); - Ok(true) - } - ty::Char => { - let value = self.read_scalar(value)?; - try_validation!( - value.to_char(), - self.path, - err_ub!(InvalidChar(..)) | err_ub!(InvalidUninitBytes(None)) => - { "{}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" }, - ); - Ok(true) - } - ty::Float(_) | ty::Int(_) | ty::Uint(_) => { - let value = self.read_scalar(value)?; - // NOTE: Keep this in sync with the array optimization for int/float - // types below! - if self.ctfe_mode.is_some() { - // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous - let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok()); - if !is_bits { - throw_validation_failure!(self.path, - { "{}", value } expected { "initialized plain (non-pointer) bytes" } - ) - } - } else { - // At run-time, for now, we accept *anything* for these types, including - // uninit. We should fix that, but let's start low. - } - Ok(true) - } - ty::RawPtr(..) => { - // We are conservative with uninit for integers, but try to - // actually enforce the strict rules for raw pointers (mostly because - // that lets us re-use `ref_to_mplace`). - let place = try_validation!( - self.ecx.read_immediate(value).and_then(|ref i| self.ecx.ref_to_mplace(i)), - self.path, - err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" }, - err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" }, - ); - if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta, place.layout)?; - } - Ok(true) - } - ty::Ref(_, ty, mutbl) => { - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) - && *mutbl == hir::Mutability::Mut - { - // A mutable reference inside a const? That does not seem right (except if it is - // a ZST). - let layout = self.ecx.layout_of(ty)?; - if !layout.is_zst() { - throw_validation_failure!(self.path, { "mutable reference in a `const`" }); - } - } - self.check_safe_pointer(value, "reference")?; - Ok(true) - } - ty::Adt(def, ..) if def.is_box() => { - self.check_safe_pointer(value, "box")?; - Ok(true) - } - ty::FnPtr(_sig) => { - let value = try_validation!( - self.ecx.read_immediate(value), - self.path, - err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" }, - ); - // Make sure we print a `ScalarMaybeUninit` (and not an `ImmTy`) in the error - // message below. - let value = value.to_scalar_or_uninit(); - let _fn = try_validation!( - value.check_init().and_then(|ptr| self.ecx.memory.get_fn(self.ecx.scalar_to_ptr(ptr))), - self.path, - err_ub!(DanglingIntPointer(..)) | - err_ub!(InvalidFunctionPointer(..)) | - err_ub!(InvalidUninitBytes(None)) => - { "{}", value } expected { "a function pointer" }, - ); - // FIXME: Check if the signature matches - Ok(true) - } - ty::Never => throw_validation_failure!(self.path, { "a value of the never type `!`" }), - ty::Foreign(..) | ty::FnDef(..) => { - // Nothing to check. - Ok(true) - } - // The above should be all the primitive types. The rest is compound, we - // check them by visiting their fields/variants. - ty::Adt(..) - | ty::Tuple(..) - | ty::Array(..) - | ty::Slice(..) - | ty::Str - | ty::Dynamic(..) - | ty::Closure(..) - | ty::Generator(..) => Ok(false), - // Some types only occur during typechecking, they have no layout. - // We should not see them here and we could not check them anyway. - ty::Error(_) - | ty::Infer(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Param(..) - | ty::Opaque(..) - | ty::Projection(..) - | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty), - } - } - - fn visit_scalar( - &mut self, - op: &OpTy<'tcx, M::PointerTag>, - scalar_layout: &ScalarAbi, - ) -> InterpResult<'tcx> { - let value = self.read_scalar(op)?; - let valid_range = scalar_layout.valid_range.clone(); - let WrappingRange { start: lo, end: hi } = valid_range; - // Determine the allowed range - // `max_hi` is as big as the size fits - let max_hi = u128::MAX >> (128 - op.layout.size.bits()); - assert!(hi <= max_hi); - // We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128` - if (lo == 0 && hi == max_hi) || (hi + 1 == lo) { - // Nothing to check - return Ok(()); - } - // At least one value is excluded. Get the bits. - let value = try_validation!( - value.check_init(), - self.path, - err_ub!(InvalidUninitBytes(None)) => { "{}", value } - expected { "something {}", wrapping_range_format(valid_range, max_hi) }, - ); - let bits = match value.try_to_int() { - Err(_) => { - // So this is a pointer then, and casting to an int failed. - // Can only happen during CTFE. - let ptr = self.ecx.scalar_to_ptr(value); - if lo == 1 && hi == max_hi { - // Only null is the niche. So make sure the ptr is NOT null. - if self.ecx.memory.ptr_may_be_null(ptr) { - throw_validation_failure!(self.path, - { "a potentially null pointer" } - expected { - "something that cannot possibly fail to be {}", - wrapping_range_format(valid_range, max_hi) - } - ) - } - return Ok(()); - } else { - // Conservatively, we reject, because the pointer *could* have a bad - // value. - throw_validation_failure!(self.path, - { "a pointer" } - expected { - "something that cannot possibly fail to be {}", - wrapping_range_format(valid_range, max_hi) - } - ) - } - } - Ok(int) => int.assert_bits(op.layout.size), - }; - // Now compare. This is slightly subtle because this is a special "wrap-around" range. - if valid_range.contains(bits) { - Ok(()) - } else { - throw_validation_failure!(self.path, - { "{}", bits } - expected { "something {}", wrapping_range_format(valid_range, max_hi) } - ) - } - } -} - -impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for ValidityVisitor<'rt, 'mir, 'tcx, M> -{ - type V = OpTy<'tcx, M::PointerTag>; - - #[inline(always)] - fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { - &self.ecx - } - - fn read_discriminant( - &mut self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, VariantIdx> { - self.with_elem(PathElem::EnumTag, move |this| { - Ok(try_validation!( - this.ecx.read_discriminant(op), - this.path, - err_ub!(InvalidTag(val)) => - { "{}", val } expected { "a valid enum tag" }, - err_ub!(InvalidUninitBytes(None)) => - { "uninitialized bytes" } expected { "a valid enum tag" }, - err_unsup!(ReadPointerAsBytes) => - { "a pointer" } expected { "a valid enum tag" }, - ) - .1) - }) - } - - #[inline] - fn visit_field( - &mut self, - old_op: &OpTy<'tcx, M::PointerTag>, - field: usize, - new_op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - let elem = self.aggregate_field_path_elem(old_op.layout, field); - self.with_elem(elem, move |this| this.visit_value(new_op)) - } - - #[inline] - fn visit_variant( - &mut self, - old_op: &OpTy<'tcx, M::PointerTag>, - variant_id: VariantIdx, - new_op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - let name = match old_op.layout.ty.kind() { - ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name), - // Generators also have variants - ty::Generator(..) => PathElem::GeneratorState(variant_id), - _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty), - }; - self.with_elem(name, move |this| this.visit_value(new_op)) - } - - #[inline(always)] - fn visit_union( - &mut self, - _op: &OpTy<'tcx, M::PointerTag>, - _fields: NonZeroUsize, - ) -> InterpResult<'tcx> { - Ok(()) - } - - #[inline] - fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { - trace!("visit_value: {:?}, {:?}", *op, op.layout); - - // Check primitive types -- the leafs of our recursive descend. - if self.try_visit_primitive(op)? { - return Ok(()); - } - // Sanity check: `builtin_deref` does not know any pointers that are not primitive. - assert!(op.layout.ty.builtin_deref(true).is_none()); - - // Special check preventing `UnsafeCell` in the inner part of constants - if let Some(def) = op.layout.ty.ty_adt_def() { - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) - && Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() - { - throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); - } - } - - // Recursively walk the value at its type. - self.walk_value(op)?; - - // *After* all of this, check the ABI. We need to check the ABI to handle - // types like `NonNull` where the `Scalar` info is more restrictive than what - // the fields say (`rustc_layout_scalar_valid_range_start`). - // But in most cases, this will just propagate what the fields say, - // and then we want the error to point at the field -- so, first recurse, - // then check ABI. - // - // FIXME: We could avoid some redundant checks here. For newtypes wrapping - // scalars, we do the same check on every "level" (e.g., first we check - // MyNewtype and then the scalar in there). - match op.layout.abi { - Abi::Uninhabited => { - throw_validation_failure!(self.path, - { "a value of uninhabited type {:?}", op.layout.ty } - ); - } - Abi::Scalar(ref scalar_layout) => { - self.visit_scalar(op, scalar_layout)?; - } - Abi::ScalarPair { .. } | Abi::Vector { .. } => { - // These have fields that we already visited above, so we already checked - // all their scalar-level restrictions. - // There is also no equivalent to `rustc_layout_scalar_valid_range_start` - // that would make skipping them here an issue. - } - Abi::Aggregate { .. } => { - // Nothing to do. - } - } - - Ok(()) - } - - fn visit_aggregate( - &mut self, - op: &OpTy<'tcx, M::PointerTag>, - fields: impl Iterator>, - ) -> InterpResult<'tcx> { - match op.layout.ty.kind() { - ty::Str => { - let mplace = op.assert_mem_place(); // strings are never immediate - let len = mplace.len(self.ecx)?; - try_validation!( - self.ecx.memory.read_bytes(mplace.ptr, Size::from_bytes(len)), - self.path, - err_ub!(InvalidUninitBytes(..)) => { "uninitialized data in `str`" }, - err_unsup!(ReadPointerAsBytes) => { "a pointer in `str`" }, - ); - } - ty::Array(tys, ..) | ty::Slice(tys) - // This optimization applies for types that can hold arbitrary bytes (such as - // integer and floating point types) or for structs or tuples with no fields. - // FIXME(wesleywiser) This logic could be extended further to arbitrary structs - // or tuples made up of integer/floating point types or inhabited ZSTs with no - // padding. - if matches!(tys.kind(), ty::Int(..) | ty::Uint(..) | ty::Float(..)) - => - { - // Optimized handling for arrays of integer/float type. - - // Arrays cannot be immediate, slices are never immediate. - let mplace = op.assert_mem_place(); - // This is the length of the array/slice. - let len = mplace.len(self.ecx)?; - // This is the element type size. - let layout = self.ecx.layout_of(tys)?; - // This is the size in bytes of the whole array. (This checks for overflow.) - let size = layout.size * len; - - // Optimization: we just check the entire range at once. - // NOTE: Keep this in sync with the handling of integer and float - // types above, in `visit_primitive`. - // In run-time mode, we accept pointers in here. This is actually more - // permissive than a per-element check would be, e.g., we accept - // a &[u8] that contains a pointer even though bytewise checking would - // reject it. However, that's good: We don't inherently want - // to reject those pointers, we just do not have the machinery to - // talk about parts of a pointer. - // We also accept uninit, for consistency with the slow path. - let alloc = match self.ecx.memory.get(mplace.ptr, size, mplace.align)? { - Some(a) => a, - None => { - // Size 0, nothing more to check. - return Ok(()); - } - }; - - match alloc.check_bytes( - alloc_range(Size::ZERO, size), - /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(), - ) { - // In the happy case, we needn't check anything else. - Ok(()) => {} - // Some error happened, try to provide a more detailed description. - Err(err) => { - // For some errors we might be able to provide extra information. - // (This custom logic does not fit the `try_validation!` macro.) - match err.kind() { - err_ub!(InvalidUninitBytes(Some((_alloc_id, access)))) => { - // Some byte was uninitialized, determine which - // element that byte belongs to so we can - // provide an index. - let i = usize::try_from( - access.uninit_offset.bytes() / layout.size.bytes(), - ) - .unwrap(); - self.path.push(PathElem::ArrayElem(i)); - - throw_validation_failure!(self.path, { "uninitialized bytes" }) - } - err_unsup!(ReadPointerAsBytes) => { - throw_validation_failure!(self.path, { "a pointer" } expected { "plain (non-pointer) bytes" }) - } - - // Propagate upwards (that will also check for unexpected errors). - _ => return Err(err), - } - } - } - } - // Fast path for arrays and slices of ZSTs. We only need to check a single ZST element - // of an array and not all of them, because there's only a single value of a specific - // ZST type, so either validation fails for all elements or none. - ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(tys)?.is_zst() => { - // Validate just the first element (if any). - self.walk_aggregate(op, fields.take(1))? - } - _ => { - self.walk_aggregate(op, fields)? // default handler - } - } - Ok(()) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - fn validate_operand_internal( - &self, - op: &OpTy<'tcx, M::PointerTag>, - path: Vec, - ref_tracking: Option<&mut RefTracking, Vec>>, - ctfe_mode: Option, - ) -> InterpResult<'tcx> { - trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); - - // Construct a visitor - let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self }; - - // Run it. - match visitor.visit_value(&op) { - Ok(()) => Ok(()), - // Pass through validation failures. - Err(err) if matches!(err.kind(), err_ub!(ValidationFailure { .. })) => Err(err), - // Also pass through InvalidProgram, those just indicate that we could not - // validate and each caller will know best what to do with them. - Err(err) if matches!(err.kind(), InterpError::InvalidProgram(_)) => Err(err), - // Avoid other errors as those do not show *where* in the value the issue lies. - Err(err) => { - err.print_backtrace(); - bug!("Unexpected error during validation: {}", err); - } - } - } - - /// This function checks the data at `op` to be const-valid. - /// `op` is assumed to cover valid memory if it is an indirect operand. - /// It will error if the bits at the destination do not match the ones described by the layout. - /// - /// `ref_tracking` is used to record references that we encounter so that they - /// can be checked recursively by an outside driving loop. - /// - /// `constant` controls whether this must satisfy the rules for constants: - /// - no pointers to statics. - /// - no `UnsafeCell` or non-ZST `&mut`. - #[inline(always)] - pub fn const_validate_operand( - &self, - op: &OpTy<'tcx, M::PointerTag>, - path: Vec, - ref_tracking: &mut RefTracking, Vec>, - ctfe_mode: CtfeValidationMode, - ) -> InterpResult<'tcx> { - self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode)) - } - - /// This function checks the data at `op` to be runtime-valid. - /// `op` is assumed to cover valid memory if it is an indirect operand. - /// It will error if the bits at the destination do not match the ones described by the layout. - #[inline(always)] - pub fn validate_operand(&self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { - self.validate_operand_internal(op, vec![], None, None) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/visitor.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/visitor.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/visitor.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/interpret/visitor.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,278 +0,0 @@ -//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound -//! types until we arrive at the leaves, with custom handling for primitive types. - -use rustc_middle::mir::interpret::InterpResult; -use rustc_middle::ty; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_target::abi::{FieldsShape, VariantIdx, Variants}; - -use std::num::NonZeroUsize; - -use super::{InterpCx, MPlaceTy, Machine, OpTy}; - -// A thing that we can project into, and that has a layout. -// This wouldn't have to depend on `Machine` but with the current type inference, -// that's just more convenient to work with (avoids repeating all the `Machine` bounds). -pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { - /// Gets this value's layout. - fn layout(&self) -> TyAndLayout<'tcx>; - - /// Makes this into an `OpTy`. - fn to_op(&self, ecx: &InterpCx<'mir, 'tcx, M>) - -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; - - /// Creates this from an `MPlaceTy`. - fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self; - - /// Projects to the given enum variant. - fn project_downcast( - &self, - ecx: &InterpCx<'mir, 'tcx, M>, - variant: VariantIdx, - ) -> InterpResult<'tcx, Self>; - - /// Projects to the n-th field. - fn project_field( - &self, - ecx: &InterpCx<'mir, 'tcx, M>, - field: usize, - ) -> InterpResult<'tcx, Self>; -} - -// Operands and memory-places are both values. -// Places in general are not due to `place_field` having to do `force_allocation`. -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> { - #[inline(always)] - fn layout(&self) -> TyAndLayout<'tcx> { - self.layout - } - - #[inline(always)] - fn to_op( - &self, - _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - Ok(*self) - } - - #[inline(always)] - fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self { - mplace.into() - } - - #[inline(always)] - fn project_downcast( - &self, - ecx: &InterpCx<'mir, 'tcx, M>, - variant: VariantIdx, - ) -> InterpResult<'tcx, Self> { - ecx.operand_downcast(self, variant) - } - - #[inline(always)] - fn project_field( - &self, - ecx: &InterpCx<'mir, 'tcx, M>, - field: usize, - ) -> InterpResult<'tcx, Self> { - ecx.operand_field(self, field) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> - for MPlaceTy<'tcx, M::PointerTag> -{ - #[inline(always)] - fn layout(&self) -> TyAndLayout<'tcx> { - self.layout - } - - #[inline(always)] - fn to_op( - &self, - _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - Ok((*self).into()) - } - - #[inline(always)] - fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self { - mplace - } - - #[inline(always)] - fn project_downcast( - &self, - ecx: &InterpCx<'mir, 'tcx, M>, - variant: VariantIdx, - ) -> InterpResult<'tcx, Self> { - ecx.mplace_downcast(self, variant) - } - - #[inline(always)] - fn project_field( - &self, - ecx: &InterpCx<'mir, 'tcx, M>, - field: usize, - ) -> InterpResult<'tcx, Self> { - ecx.mplace_field(self, field) - } -} - -macro_rules! make_value_visitor { - ($visitor_trait_name:ident, $($mutability:ident)?) => { - // How to traverse a value and what to do when we are at the leaves. - pub trait $visitor_trait_name<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { - type V: Value<'mir, 'tcx, M>; - - /// The visitor must have an `InterpCx` in it. - fn ecx(&$($mutability)? self) - -> &$($mutability)? InterpCx<'mir, 'tcx, M>; - - /// `read_discriminant` can be hooked for better error messages. - #[inline(always)] - fn read_discriminant( - &mut self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, VariantIdx> { - Ok(self.ecx().read_discriminant(op)?.1) - } - - // Recursive actions, ready to be overloaded. - /// Visits the given value, dispatching as appropriate to more specialized visitors. - #[inline(always)] - fn visit_value(&mut self, v: &Self::V) -> InterpResult<'tcx> - { - self.walk_value(v) - } - /// Visits the given value as a union. No automatic recursion can happen here. - #[inline(always)] - fn visit_union(&mut self, _v: &Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx> - { - Ok(()) - } - /// Visits this value as an aggregate, you are getting an iterator yielding - /// all the fields (still in an `InterpResult`, you have to do error handling yourself). - /// Recurses into the fields. - #[inline(always)] - fn visit_aggregate( - &mut self, - v: &Self::V, - fields: impl Iterator>, - ) -> InterpResult<'tcx> { - self.walk_aggregate(v, fields) - } - - /// Called each time we recurse down to a field of a "product-like" aggregate - /// (structs, tuples, arrays and the like, but not enums), passing in old (outer) - /// and new (inner) value. - /// This gives the visitor the chance to track the stack of nested fields that - /// we are descending through. - #[inline(always)] - fn visit_field( - &mut self, - _old_val: &Self::V, - _field: usize, - new_val: &Self::V, - ) -> InterpResult<'tcx> { - self.visit_value(new_val) - } - /// Called when recursing into an enum variant. - /// This gives the visitor the chance to track the stack of nested fields that - /// we are descending through. - #[inline(always)] - fn visit_variant( - &mut self, - _old_val: &Self::V, - _variant: VariantIdx, - new_val: &Self::V, - ) -> InterpResult<'tcx> { - self.visit_value(new_val) - } - - // Default recursors. Not meant to be overloaded. - fn walk_aggregate( - &mut self, - v: &Self::V, - fields: impl Iterator>, - ) -> InterpResult<'tcx> { - // Now iterate over it. - for (idx, field_val) in fields.enumerate() { - self.visit_field(v, idx, &field_val?)?; - } - Ok(()) - } - fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx> - { - trace!("walk_value: type: {}", v.layout().ty); - - // Special treatment for special types, where the (static) layout is not sufficient. - match *v.layout().ty.kind() { - // If it is a trait object, switch to the real type that was used to create it. - ty::Dynamic(..) => { - // immediate trait objects are not a thing - let op = v.to_op(self.ecx())?; - let dest = op.assert_mem_place(); - let inner = self.ecx().unpack_dyn_trait(&dest)?.1; - trace!("walk_value: dyn object layout: {:#?}", inner.layout); - // recurse with the inner type - return self.visit_field(&v, 0, &Value::from_mem_place(inner)); - }, - // Slices do not need special handling here: they have `Array` field - // placement with length 0, so we enter the `Array` case below which - // indirectly uses the metadata to determine the actual length. - _ => {}, - }; - - // Visit the fields of this value. - match v.layout().fields { - FieldsShape::Primitive => {}, - FieldsShape::Union(fields) => { - self.visit_union(v, fields)?; - }, - FieldsShape::Arbitrary { ref offsets, .. } => { - // FIXME: We collect in a vec because otherwise there are lifetime - // errors: Projecting to a field needs access to `ecx`. - let fields: Vec> = - (0..offsets.len()).map(|i| { - v.project_field(self.ecx(), i) - }) - .collect(); - self.visit_aggregate(v, fields.into_iter())?; - }, - FieldsShape::Array { .. } => { - // Let's get an mplace first. - let op = v.to_op(self.ecx())?; - let mplace = op.assert_mem_place(); - // Now we can go over all the fields. - // This uses the *run-time length*, i.e., if we are a slice, - // the dynamic info from the metadata is used. - let iter = self.ecx().mplace_array_fields(&mplace)? - .map(|f| f.and_then(|f| { - Ok(Value::from_mem_place(f)) - })); - self.visit_aggregate(v, iter)?; - } - } - - match v.layout().variants { - // If this is a multi-variant layout, find the right variant and proceed - // with *its* fields. - Variants::Multiple { .. } => { - let op = v.to_op(self.ecx())?; - let idx = self.read_discriminant(&op)?; - let inner = v.project_downcast(self.ecx(), idx)?; - trace!("walk_value: variant layout: {:#?}", inner.layout()); - // recurse with the inner type - self.visit_variant(v, idx, &inner) - } - // For single-variant layouts, we already did anything there is to do. - Variants::Single { .. } => Ok(()) - } - } - } - } -} - -make_value_visitor!(ValueVisitor,); -make_value_visitor!(MutValueVisitor, mut); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/*! - -Rust MIR: a lowered representation of Rust. - -*/ - -#![feature(nll)] -#![feature(in_band_lifetimes)] -#![feature(array_windows)] -#![feature(assert_matches)] -#![cfg_attr(bootstrap, feature(bindings_after_at))] -#![feature(bool_to_option)] -#![feature(box_patterns)] -#![feature(crate_visibility_modifier)] -#![feature(decl_macro)] -#![feature(exact_size_is_empty)] -#![feature(format_args_capture)] -#![feature(iter_zip)] -#![feature(never_type)] -#![feature(map_try_insert)] -#![feature(min_specialization)] -#![feature(slice_ptr_get)] -#![feature(trusted_len)] -#![feature(try_blocks)] -#![feature(associated_type_defaults)] -#![feature(stmt_expr_attributes)] -#![feature(trait_alias)] -#![feature(option_get_or_insert_default)] -#![feature(once_cell)] -#![feature(control_flow_enum)] -#![feature(try_reserve)] -#![feature(try_reserve_kind)] -#![recursion_limit = "256"] - -#[macro_use] -extern crate tracing; -#[macro_use] -extern crate rustc_middle; - -mod borrow_check; -pub mod const_eval; -pub mod dataflow; -pub mod interpret; -pub mod monomorphize; -mod shim; -pub mod transform; -pub mod util; - -// A public API provided for the Rust compiler consumers. -pub use self::borrow_check::consumers; - -use rustc_middle::ty::query::Providers; - -pub fn provide(providers: &mut Providers) { - borrow_check::provide(providers); - const_eval::provide(providers); - shim::provide(providers); - transform::provide(providers); - monomorphize::partitioning::provide(providers); - monomorphize::polymorphize::provide(providers); - providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; - providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; - providers.const_caller_location = const_eval::const_caller_location; - providers.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable; - providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees; - providers.destructure_const = |tcx, param_env_and_value| { - let (param_env, value) = param_env_and_value.into_parts(); - const_eval::destructure_const(tcx, param_env, value) - }; - providers.const_to_valtree = |tcx, param_env_and_value| { - let (param_env, raw) = param_env_and_value.into_parts(); - const_eval::const_to_valtree(tcx, param_env, raw) - }; - providers.deref_const = |tcx, param_env_and_value| { - let (param_env, value) = param_env_and_value.into_parts(); - const_eval::deref_const(tcx, param_env, value) - }; -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/collector.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/collector.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/collector.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/collector.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1414 +0,0 @@ -//! Mono Item Collection -//! ==================== -//! -//! This module is responsible for discovering all items that will contribute -//! to code generation of the crate. The important part here is that it not only -//! needs to find syntax-level items (functions, structs, etc) but also all -//! their monomorphized instantiations. Every non-generic, non-const function -//! maps to one LLVM artifact. Every generic function can produce -//! from zero to N artifacts, depending on the sets of type arguments it -//! is instantiated with. -//! This also applies to generic items from other crates: A generic definition -//! in crate X might produce monomorphizations that are compiled into crate Y. -//! We also have to collect these here. -//! -//! The following kinds of "mono items" are handled here: -//! -//! - Functions -//! - Methods -//! - Closures -//! - Statics -//! - Drop glue -//! -//! The following things also result in LLVM artifacts, but are not collected -//! here, since we instantiate them locally on demand when needed in a given -//! codegen unit: -//! -//! - Constants -//! - Vtables -//! - Object Shims -//! -//! -//! General Algorithm -//! ----------------- -//! Let's define some terms first: -//! -//! - A "mono item" is something that results in a function or global in -//! the LLVM IR of a codegen unit. Mono items do not stand on their -//! own, they can reference other mono items. For example, if function -//! `foo()` calls function `bar()` then the mono item for `foo()` -//! references the mono item for function `bar()`. In general, the -//! definition for mono item A referencing a mono item B is that -//! the LLVM artifact produced for A references the LLVM artifact produced -//! for B. -//! -//! - Mono items and the references between them form a directed graph, -//! where the mono items are the nodes and references form the edges. -//! Let's call this graph the "mono item graph". -//! -//! - The mono item graph for a program contains all mono items -//! that are needed in order to produce the complete LLVM IR of the program. -//! -//! The purpose of the algorithm implemented in this module is to build the -//! mono item graph for the current crate. It runs in two phases: -//! -//! 1. Discover the roots of the graph by traversing the HIR of the crate. -//! 2. Starting from the roots, find neighboring nodes by inspecting the MIR -//! representation of the item corresponding to a given node, until no more -//! new nodes are found. -//! -//! ### Discovering roots -//! -//! The roots of the mono item graph correspond to the public non-generic -//! syntactic items in the source code. We find them by walking the HIR of the -//! crate, and whenever we hit upon a public function, method, or static item, -//! we create a mono item consisting of the items DefId and, since we only -//! consider non-generic items, an empty type-substitution set. (In eager -//! collection mode, during incremental compilation, all non-generic functions -//! are considered as roots, as well as when the `-Clink-dead-code` option is -//! specified. Functions marked `#[no_mangle]` and functions called by inlinable -//! functions also always act as roots.) -//! -//! ### Finding neighbor nodes -//! Given a mono item node, we can discover neighbors by inspecting its -//! MIR. We walk the MIR and any time we hit upon something that signifies a -//! reference to another mono item, we have found a neighbor. Since the -//! mono item we are currently at is always monomorphic, we also know the -//! concrete type arguments of its neighbors, and so all neighbors again will be -//! monomorphic. The specific forms a reference to a neighboring node can take -//! in MIR are quite diverse. Here is an overview: -//! -//! #### Calling Functions/Methods -//! The most obvious form of one mono item referencing another is a -//! function or method call (represented by a CALL terminator in MIR). But -//! calls are not the only thing that might introduce a reference between two -//! function mono items, and as we will see below, they are just a -//! specialization of the form described next, and consequently will not get any -//! special treatment in the algorithm. -//! -//! #### Taking a reference to a function or method -//! A function does not need to actually be called in order to be a neighbor of -//! another function. It suffices to just take a reference in order to introduce -//! an edge. Consider the following example: -//! -//! ```rust -//! fn print_val(x: T) { -//! println!("{}", x); -//! } -//! -//! fn call_fn(f: &Fn(i32), x: i32) { -//! f(x); -//! } -//! -//! fn main() { -//! let print_i32 = print_val::; -//! call_fn(&print_i32, 0); -//! } -//! ``` -//! The MIR of none of these functions will contain an explicit call to -//! `print_val::`. Nonetheless, in order to mono this program, we need -//! an instance of this function. Thus, whenever we encounter a function or -//! method in operand position, we treat it as a neighbor of the current -//! mono item. Calls are just a special case of that. -//! -//! #### Closures -//! In a way, closures are a simple case. Since every closure object needs to be -//! constructed somewhere, we can reliably discover them by observing -//! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also -//! true for closures inlined from other crates. -//! -//! #### Drop glue -//! Drop glue mono items are introduced by MIR drop-statements. The -//! generated mono item will again have drop-glue item neighbors if the -//! type to be dropped contains nested values that also need to be dropped. It -//! might also have a function item neighbor for the explicit `Drop::drop` -//! implementation of its type. -//! -//! #### Unsizing Casts -//! A subtle way of introducing neighbor edges is by casting to a trait object. -//! Since the resulting fat-pointer contains a reference to a vtable, we need to -//! instantiate all object-save methods of the trait, as we need to store -//! pointers to these functions even if they never get called anywhere. This can -//! be seen as a special case of taking a function reference. -//! -//! #### Boxes -//! Since `Box` expression have special compiler support, no explicit calls to -//! `exchange_malloc()` and `box_free()` may show up in MIR, even if the -//! compiler will generate them. We have to observe `Rvalue::Box` expressions -//! and Box-typed drop-statements for that purpose. -//! -//! -//! Interaction with Cross-Crate Inlining -//! ------------------------------------- -//! The binary of a crate will not only contain machine code for the items -//! defined in the source code of that crate. It will also contain monomorphic -//! instantiations of any extern generic functions and of functions marked with -//! `#[inline]`. -//! The collection algorithm handles this more or less mono. If it is -//! about to create a mono item for something with an external `DefId`, -//! it will take a look if the MIR for that item is available, and if so just -//! proceed normally. If the MIR is not available, it assumes that the item is -//! just linked to and no node is created; which is exactly what we want, since -//! no machine code should be generated in the current crate for such an item. -//! -//! Eager and Lazy Collection Mode -//! ------------------------------ -//! Mono item collection can be performed in one of two modes: -//! -//! - Lazy mode means that items will only be instantiated when actually -//! referenced. The goal is to produce the least amount of machine code -//! possible. -//! -//! - Eager mode is meant to be used in conjunction with incremental compilation -//! where a stable set of mono items is more important than a minimal -//! one. Thus, eager mode will instantiate drop-glue for every drop-able type -//! in the crate, even if no drop call for that type exists (yet). It will -//! also instantiate default implementations of trait methods, something that -//! otherwise is only done on demand. -//! -//! -//! Open Issues -//! ----------- -//! Some things are not yet fully implemented in the current version of this -//! module. -//! -//! ### Const Fns -//! Ideally, no mono item should be generated for const fns unless there -//! is a call to them that cannot be evaluated at compile time. At the moment -//! this is not implemented however: a mono item will be produced -//! regardless of whether it is actually needed or not. - -use crate::monomorphize; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; -use rustc_errors::{ErrorReported, FatalError}; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::GrowableBitSet; -use rustc_middle::mir::interpret::{AllocId, ConstValue}; -use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; -use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; -use rustc_middle::mir::visit::Visitor as MirVisitor; -use rustc_middle::mir::{self, Local, Location}; -use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; -use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, VtblEntry}; -use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; -use rustc_session::config::EntryFnType; -use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; -use rustc_session::Limit; -use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; -use rustc_target::abi::Size; -use smallvec::SmallVec; -use std::iter; -use std::ops::Range; -use std::path::PathBuf; - -#[derive(PartialEq)] -pub enum MonoItemCollectionMode { - Eager, - Lazy, -} - -/// Maps every mono item to all mono items it references in its -/// body. -pub struct InliningMap<'tcx> { - // Maps a source mono item to the range of mono items - // accessed by it. - // The range selects elements within the `targets` vecs. - index: FxHashMap, Range>, - targets: Vec>, - - // Contains one bit per mono item in the `targets` field. That bit - // is true if that mono item needs to be inlined into every CGU. - inlines: GrowableBitSet, -} - -impl<'tcx> InliningMap<'tcx> { - fn new() -> InliningMap<'tcx> { - InliningMap { - index: FxHashMap::default(), - targets: Vec::new(), - inlines: GrowableBitSet::with_capacity(1024), - } - } - - fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) { - let start_index = self.targets.len(); - let new_items_count = new_targets.len(); - let new_items_count_total = new_items_count + self.targets.len(); - - self.targets.reserve(new_items_count); - self.inlines.ensure(new_items_count_total); - - for (i, (target, inline)) in new_targets.iter().enumerate() { - self.targets.push(*target); - if *inline { - self.inlines.insert(i + start_index); - } - } - - let end_index = self.targets.len(); - assert!(self.index.insert(source, start_index..end_index).is_none()); - } - - // Internally iterate over all items referenced by `source` which will be - // made available for inlining. - pub fn with_inlining_candidates(&self, source: MonoItem<'tcx>, mut f: F) - where - F: FnMut(MonoItem<'tcx>), - { - if let Some(range) = self.index.get(&source) { - for (i, candidate) in self.targets[range.clone()].iter().enumerate() { - if self.inlines.contains(range.start + i) { - f(*candidate); - } - } - } - } - - // Internally iterate over all items and the things each accesses. - pub fn iter_accesses(&self, mut f: F) - where - F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]), - { - for (&accessor, range) in &self.index { - f(accessor, &self.targets[range.clone()]) - } - } -} - -pub fn collect_crate_mono_items( - tcx: TyCtxt<'_>, - mode: MonoItemCollectionMode, -) -> (FxHashSet>, InliningMap<'_>) { - let _prof_timer = tcx.prof.generic_activity("monomorphization_collector"); - - let roots = - tcx.sess.time("monomorphization_collector_root_collections", || collect_roots(tcx, mode)); - - debug!("building mono item graph, beginning at roots"); - - let mut visited = MTLock::new(FxHashSet::default()); - let mut inlining_map = MTLock::new(InliningMap::new()); - let recursion_limit = tcx.recursion_limit(); - - { - let visited: MTRef<'_, _> = &mut visited; - let inlining_map: MTRef<'_, _> = &mut inlining_map; - - tcx.sess.time("monomorphization_collector_graph_walk", || { - par_iter(roots).for_each(|root| { - let mut recursion_depths = DefIdMap::default(); - collect_items_rec( - tcx, - dummy_spanned(root), - visited, - &mut recursion_depths, - recursion_limit, - inlining_map, - ); - }); - }); - } - - (visited.into_inner(), inlining_map.into_inner()) -} - -// Find all non-generic items by walking the HIR. These items serve as roots to -// start monomorphizing from. -fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec> { - debug!("collecting roots"); - let mut roots = Vec::new(); - - { - let entry_fn = tcx.entry_fn(()); - - debug!("collect_roots: entry_fn = {:?}", entry_fn); - - let mut visitor = RootCollector { tcx, mode, entry_fn, output: &mut roots }; - - tcx.hir().krate().visit_all_item_likes(&mut visitor); - - visitor.push_extra_entry_roots(); - } - - // We can only codegen items that are instantiable - items all of - // whose predicates hold. Luckily, items that aren't instantiable - // can't actually be used, so we can just skip codegenning them. - roots - .into_iter() - .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node)) - .collect() -} - -/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a -/// post-monorphization error is encountered during a collection step. -fn collect_items_rec<'tcx>( - tcx: TyCtxt<'tcx>, - starting_point: Spanned>, - visited: MTRef<'_, MTLock>>>, - recursion_depths: &mut DefIdMap, - recursion_limit: Limit, - inlining_map: MTRef<'_, MTLock>>, -) { - if !visited.lock_mut().insert(starting_point.node) { - // We've been here already, no need to search again. - return; - } - debug!("BEGIN collect_items_rec({})", starting_point.node); - - let mut neighbors = Vec::new(); - let recursion_depth_reset; - - // - // Post-monomorphization errors MVP - // - // We can encounter errors while monomorphizing an item, but we don't have a good way of - // showing a complete stack of spans ultimately leading to collecting the erroneous one yet. - // (It's also currently unclear exactly which diagnostics and information would be interesting - // to report in such cases) - // - // This leads to suboptimal error reporting: a post-monomorphization error (PME) will be - // shown with just a spanned piece of code causing the error, without information on where - // it was called from. This is especially obscure if the erroneous mono item is in a - // dependency. See for example issue #85155, where, before minimization, a PME happened two - // crates downstream from libcore's stdarch, without a way to know which dependency was the - // cause. - // - // If such an error occurs in the current crate, its span will be enough to locate the - // source. If the cause is in another crate, the goal here is to quickly locate which mono - // item in the current crate is ultimately responsible for causing the error. - // - // To give at least _some_ context to the user: while collecting mono items, we check the - // error count. If it has changed, a PME occurred, and we trigger some diagnostics about the - // current step of mono items collection. - // - let error_count = tcx.sess.diagnostic().err_count(); - - match starting_point.node { - MonoItem::Static(def_id) => { - let instance = Instance::mono(tcx, def_id); - - // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, &instance)); - - let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); - visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors); - - recursion_depth_reset = None; - - if let Ok(alloc) = tcx.eval_static_initializer(def_id) { - for &id in alloc.relocations().values() { - collect_miri(tcx, id, &mut neighbors); - } - } - } - MonoItem::Fn(instance) => { - // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, &instance)); - - // Keep track of the monomorphization recursion depth - recursion_depth_reset = Some(check_recursion_limit( - tcx, - instance, - starting_point.span, - recursion_depths, - recursion_limit, - )); - check_type_length_limit(tcx, instance); - - rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_neighbours(tcx, instance, &mut neighbors); - }); - } - MonoItem::GlobalAsm(item_id) => { - recursion_depth_reset = None; - - let item = tcx.hir().item(item_id); - if let hir::ItemKind::GlobalAsm(asm) = item.kind { - for (op, op_sp) in asm.operands { - match op { - hir::InlineAsmOperand::Const { .. } => { - // Only constants which resolve to a plain integer - // are supported. Therefore the value should not - // depend on any other items. - } - _ => span_bug!(*op_sp, "invalid operand type for global_asm!"), - } - } - } else { - span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") - } - } - } - - // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the - // mono item graph where the PME diagnostics are currently the most problematic (e.g. ones - // involving a dependency, and the lack of context is confusing) in this MVP, we focus on - // diagnostics on edges crossing a crate boundary: the collected mono items which are not - // defined in the local crate. - if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE - { - let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string()); - tcx.sess.span_note_without_error( - starting_point.span, - &format!("the above error was encountered while instantiating `{}`", formatted_item), - ); - } - - record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); - - for neighbour in neighbors { - collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map); - } - - if let Some((def_id, depth)) = recursion_depth_reset { - recursion_depths.insert(def_id, depth); - } - - debug!("END collect_items_rec({})", starting_point.node); -} - -fn record_accesses<'a, 'tcx: 'a>( - tcx: TyCtxt<'tcx>, - caller: MonoItem<'tcx>, - callees: impl Iterator>, - inlining_map: MTRef<'_, MTLock>>, -) { - let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| { - mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy - }; - - // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock. - // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec` - // instead to avoid creating this `SmallVec`. - let accesses: SmallVec<[_; 128]> = - callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect(); - - inlining_map.lock_mut().record_accesses(caller, &accesses); -} - -/// Format instance name that is already known to be too long for rustc. -/// Show only the first and last 32 characters to avoid blasting -/// the user's terminal with thousands of lines of type-name. -/// -/// If the type name is longer than before+after, it will be written to a file. -fn shrunk_instance_name( - tcx: TyCtxt<'tcx>, - instance: &Instance<'tcx>, - before: usize, - after: usize, -) -> (String, Option) { - let s = instance.to_string(); - - // Only use the shrunk version if it's really shorter. - // This also avoids the case where before and after slices overlap. - if s.chars().nth(before + after + 1).is_some() { - // An iterator of all byte positions including the end of the string. - let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); - - let shrunk = format!( - "{before}...{after}", - before = &s[..positions().nth(before).unwrap_or(s.len())], - after = &s[positions().rev().nth(after).unwrap_or(0)..], - ); - - let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None); - let written_to_path = std::fs::write(&path, s).ok().map(|_| path); - - (shrunk, written_to_path) - } else { - (s, None) - } -} - -fn check_recursion_limit<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - span: Span, - recursion_depths: &mut DefIdMap, - recursion_limit: Limit, -) -> (DefId, usize) { - let def_id = instance.def_id(); - let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); - debug!(" => recursion depth={}", recursion_depth); - - let adjusted_recursion_depth = if Some(def_id) == tcx.lang_items().drop_in_place_fn() { - // HACK: drop_in_place creates tight monomorphization loops. Give - // it more margin. - recursion_depth / 4 - } else { - recursion_depth - }; - - // Code that needs to instantiate the same function recursively - // more than the recursion limit is assumed to be causing an - // infinite expansion. - if !recursion_limit.value_within_limit(adjusted_recursion_depth) { - let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); - let error = format!("reached the recursion limit while instantiating `{}`", shrunk); - let mut err = tcx.sess.struct_span_fatal(span, &error); - err.span_note( - tcx.def_span(def_id), - &format!("`{}` defined here", tcx.def_path_str(def_id)), - ); - if let Some(path) = written_to_path { - err.note(&format!("the full type name has been written to '{}'", path.display())); - } - err.emit(); - FatalError.raise(); - } - - recursion_depths.insert(def_id, recursion_depth + 1); - - (def_id, recursion_depth) -} - -fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { - let type_length = instance - .substs - .iter() - .flat_map(|arg| arg.walk(tcx)) - .filter(|arg| match arg.unpack() { - GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, - GenericArgKind::Lifetime(_) => false, - }) - .count(); - debug!(" => type length={}", type_length); - - // Rust code can easily create exponentially-long types using only a - // polynomial recursion depth. Even with the default recursion - // depth, you can easily get cases that take >2^60 steps to run, - // which means that rustc basically hangs. - // - // Bail out in these cases to avoid that bad user experience. - if !tcx.type_length_limit().value_within_limit(type_length) { - let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); - let msg = format!("reached the type-length limit while instantiating `{}`", shrunk); - let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); - if let Some(path) = written_to_path { - diag.note(&format!("the full type name has been written to '{}'", path.display())); - } - diag.help(&format!( - "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", - type_length - )); - diag.emit(); - tcx.sess.abort_if_errors(); - } -} - -struct MirNeighborCollector<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, - output: &'a mut Vec>>, - instance: Instance<'tcx>, -} - -impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { - pub fn monomorphize(&self, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - debug!("monomorphize: self.instance={:?}", self.instance); - self.instance.subst_mir_and_normalize_erasing_regions( - self.tcx, - ty::ParamEnv::reveal_all(), - value, - ) - } -} - -impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { - debug!("visiting rvalue {:?}", *rvalue); - - let span = self.body.source_info(location).span; - - match *rvalue { - // When doing an cast from a regular pointer to a fat pointer, we - // have to instantiate all methods of the trait being cast to, so we - // can build the appropriate vtable. - mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::Unsize), - ref operand, - target_ty, - ) => { - let target_ty = self.monomorphize(target_ty); - let source_ty = operand.ty(self.body, self.tcx); - let source_ty = self.monomorphize(source_ty); - let (source_ty, target_ty) = - find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty); - // This could also be a different Unsize instruction, like - // from a fixed sized array to a slice. But we are only - // interested in things that produce a vtable. - if target_ty.is_trait() && !source_ty.is_trait() { - create_mono_items_for_vtable_methods( - self.tcx, - target_ty, - source_ty, - span, - self.output, - ); - } - } - mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::ReifyFnPointer), - ref operand, - _, - ) => { - let fn_ty = operand.ty(self.body, self.tcx); - let fn_ty = self.monomorphize(fn_ty); - visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output); - } - mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)), - ref operand, - _, - ) => { - let source_ty = operand.ty(self.body, self.tcx); - let source_ty = self.monomorphize(source_ty); - match *source_ty.kind() { - ty::Closure(def_id, substs) => { - let instance = Instance::resolve_closure( - self.tcx, - def_id, - substs, - ty::ClosureKind::FnOnce, - ); - if should_codegen_locally(self.tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); - } - } - _ => bug!(), - } - } - mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { - let tcx = self.tcx; - let exchange_malloc_fn_def_id = - tcx.require_lang_item(LangItem::ExchangeMalloc, None); - let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); - if should_codegen_locally(tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); - } - } - mir::Rvalue::ThreadLocalRef(def_id) => { - assert!(self.tcx.is_thread_local_static(def_id)); - let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, &instance) { - trace!("collecting thread-local static {:?}", def_id); - self.output.push(respan(span, MonoItem::Static(def_id))); - } - } - _ => { /* not interesting */ } - } - - self.super_rvalue(rvalue, location); - } - - /// This does not walk the constant, as it has been handled entirely here and trying - /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily - /// work, as some constants cannot be represented in the type system. - fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { - let literal = self.monomorphize(constant.literal); - let val = match literal { - mir::ConstantKind::Val(val, _) => val, - mir::ConstantKind::Ty(ct) => match ct.val { - ty::ConstKind::Value(val) => val, - ty::ConstKind::Unevaluated(ct) => { - let param_env = ty::ParamEnv::reveal_all(); - match self.tcx.const_eval_resolve(param_env, ct, None) { - // The `monomorphize` call should have evaluated that constant already. - Ok(val) => val, - Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => return, - Err(ErrorHandled::TooGeneric) => span_bug!( - self.body.source_info(location).span, - "collection encountered polymorphic constant: {:?}", - literal - ), - } - } - _ => return, - }, - }; - collect_const_value(self.tcx, val, self.output); - self.visit_ty(literal.ty(), TyContext::Location(location)); - } - - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { - debug!("visiting const {:?} @ {:?}", *constant, location); - - let substituted_constant = self.monomorphize(*constant); - let param_env = ty::ParamEnv::reveal_all(); - - match substituted_constant.val { - ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), - ty::ConstKind::Unevaluated(unevaluated) => { - match self.tcx.const_eval_resolve(param_env, unevaluated, None) { - // The `monomorphize` call should have evaluated that constant already. - Ok(val) => span_bug!( - self.body.source_info(location).span, - "collection encountered the unevaluated constant {} which evaluated to {:?}", - substituted_constant, - val - ), - Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {} - Err(ErrorHandled::TooGeneric) => span_bug!( - self.body.source_info(location).span, - "collection encountered polymorphic constant: {}", - substituted_constant - ), - } - } - _ => {} - } - - self.super_const(constant); - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - debug!("visiting terminator {:?} @ {:?}", terminator, location); - let source = self.body.source_info(location).span; - - let tcx = self.tcx; - match terminator.kind { - mir::TerminatorKind::Call { ref func, .. } => { - let callee_ty = func.ty(self.body, tcx); - let callee_ty = self.monomorphize(callee_ty); - visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output); - } - mir::TerminatorKind::Drop { ref place, .. } - | mir::TerminatorKind::DropAndReplace { ref place, .. } => { - let ty = place.ty(self.body, self.tcx).ty; - let ty = self.monomorphize(ty); - visit_drop_use(self.tcx, ty, true, source, self.output); - } - mir::TerminatorKind::InlineAsm { ref operands, .. } => { - for op in operands { - match *op { - mir::InlineAsmOperand::SymFn { ref value } => { - let fn_ty = self.monomorphize(value.literal.ty()); - visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); - } - mir::InlineAsmOperand::SymStatic { def_id } => { - let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, &instance) { - trace!("collecting asm sym static {:?}", def_id); - self.output.push(respan(source, MonoItem::Static(def_id))); - } - } - _ => {} - } - } - } - mir::TerminatorKind::Goto { .. } - | mir::TerminatorKind::SwitchInt { .. } - | mir::TerminatorKind::Resume - | mir::TerminatorKind::Abort - | mir::TerminatorKind::Return - | mir::TerminatorKind::Unreachable - | mir::TerminatorKind::Assert { .. } => {} - mir::TerminatorKind::GeneratorDrop - | mir::TerminatorKind::Yield { .. } - | mir::TerminatorKind::FalseEdge { .. } - | mir::TerminatorKind::FalseUnwind { .. } => bug!(), - } - - self.super_terminator(terminator, location); - } - - fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { - self.super_operand(operand, location); - let limit = self.tcx.move_size_limit().0; - if limit == 0 { - return; - } - let limit = Size::from_bytes(limit); - let ty = operand.ty(self.body, self.tcx); - let ty = self.monomorphize(ty); - let layout = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)); - if let Ok(layout) = layout { - if layout.size > limit { - debug!(?layout); - let source_info = self.body.source_info(location); - debug!(?source_info); - let lint_root = source_info.scope.lint_root(&self.body.source_scopes); - debug!(?lint_root); - let lint_root = match lint_root { - Some(lint_root) => lint_root, - // This happens when the issue is in a function from a foreign crate that - // we monomorphized in the current crate. We can't get a `HirId` for things - // in other crates. - // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root - // but correct span? This would make the lint at least accept crate-level lint attributes. - None => return, - }; - self.tcx.struct_span_lint_hir( - LARGE_ASSIGNMENTS, - lint_root, - source_info.span, - |lint| { - let mut err = lint.build(&format!("moving {} bytes", layout.size.bytes())); - err.span_label(source_info.span, "value moved from here"); - err.emit() - }, - ); - } - } - } - - fn visit_local( - &mut self, - _place_local: &Local, - _context: mir::visit::PlaceContext, - _location: Location, - ) { - } -} - -fn visit_drop_use<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - is_direct_call: bool, - source: Span, - output: &mut Vec>>, -) { - let instance = Instance::resolve_drop_in_place(tcx, ty); - visit_instance_use(tcx, instance, is_direct_call, source, output); -} - -fn visit_fn_use<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - is_direct_call: bool, - source: Span, - output: &mut Vec>>, -) { - if let ty::FnDef(def_id, substs) = *ty.kind() { - let instance = if is_direct_call { - ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap() - } else { - ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs) - .unwrap() - }; - visit_instance_use(tcx, instance, is_direct_call, source, output); - } -} - -fn visit_instance_use<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::Instance<'tcx>, - is_direct_call: bool, - source: Span, - output: &mut Vec>>, -) { - debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); - if !should_codegen_locally(tcx, &instance) { - return; - } - - match instance.def { - ty::InstanceDef::Virtual(..) | ty::InstanceDef::Intrinsic(_) => { - if !is_direct_call { - bug!("{:?} being reified", instance); - } - } - ty::InstanceDef::DropGlue(_, None) => { - // Don't need to emit noop drop glue if we are calling directly. - if !is_direct_call { - output.push(create_fn_mono_item(tcx, instance, source)); - } - } - ty::InstanceDef::DropGlue(_, Some(_)) - | ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Item(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::CloneShim(..) => { - output.push(create_fn_mono_item(tcx, instance, source)); - } - } -} - -// Returns `true` if we should codegen an instance in the local crate. -// Returns `false` if we can just link to the upstream crate and therefore don't -// need a mono item. -fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { - let def_id = match instance.def { - ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id, - ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Intrinsic(_) - | ty::InstanceDef::CloneShim(..) => return true, - }; - - if tcx.is_foreign_item(def_id) { - // Foreign items are always linked against, there's no way of instantiating them. - return false; - } - - if def_id.is_local() { - // Local items cannot be referred to locally without monomorphizing them locally. - return true; - } - - if tcx.is_reachable_non_generic(def_id) - || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() - { - // We can link to the item in question, no instance needed in this crate. - return false; - } - - if !tcx.is_mir_available(def_id) { - bug!("no MIR available for {:?}", def_id); - } - - true -} - -/// For a given pair of source and target type that occur in an unsizing coercion, -/// this function finds the pair of types that determines the vtable linking -/// them. -/// -/// For example, the source type might be `&SomeStruct` and the target type\ -/// might be `&SomeTrait` in a cast like: -/// -/// let src: &SomeStruct = ...; -/// let target = src as &SomeTrait; -/// -/// Then the output of this function would be (SomeStruct, SomeTrait) since for -/// constructing the `target` fat-pointer we need the vtable for that pair. -/// -/// Things can get more complicated though because there's also the case where -/// the unsized type occurs as a field: -/// -/// ```rust -/// struct ComplexStruct { -/// a: u32, -/// b: f64, -/// c: T -/// } -/// ``` -/// -/// In this case, if `T` is sized, `&ComplexStruct` is a thin pointer. If `T` -/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is -/// for the pair of `T` (which is a trait) and the concrete type that `T` was -/// originally coerced from: -/// -/// let src: &ComplexStruct = ...; -/// let target = src as &ComplexStruct; -/// -/// Again, we want this `find_vtable_types_for_unsizing()` to provide the pair -/// `(SomeStruct, SomeTrait)`. -/// -/// Finally, there is also the case of custom unsizing coercions, e.g., for -/// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'tcx>( - tcx: TyCtxt<'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>, -) -> (Ty<'tcx>, Ty<'tcx>) { - let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - let param_env = ty::ParamEnv::reveal_all(); - let type_has_metadata = |ty: Ty<'tcx>| -> bool { - if ty.is_sized(tcx.at(DUMMY_SP), param_env) { - return false; - } - let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); - match tail.kind() { - ty::Foreign(..) => false, - ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail), - } - }; - if type_has_metadata(inner_source) { - (inner_source, inner_target) - } else { - tcx.struct_lockstep_tails_erasing_lifetimes(inner_source, inner_target, param_env) - } - }; - - match (&source_ty.kind(), &target_ty.kind()) { - (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) - | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { - ptr_vtable(a, b) - } - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) - } - - (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { - assert_eq!(source_adt_def, target_adt_def); - - let CustomCoerceUnsized::Struct(coerce_index) = - monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty); - - let source_fields = &source_adt_def.non_enum_variant().fields; - let target_fields = &target_adt_def.non_enum_variant().fields; - - assert!( - coerce_index < source_fields.len() && source_fields.len() == target_fields.len() - ); - - find_vtable_types_for_unsizing( - tcx, - source_fields[coerce_index].ty(tcx, source_substs), - target_fields[coerce_index].ty(tcx, target_substs), - ) - } - _ => bug!( - "find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", - source_ty, - target_ty - ), - } -} - -fn create_fn_mono_item<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - source: Span, -) -> Spanned> { - debug!("create_fn_mono_item(instance={})", instance); - - let def_id = instance.def_id(); - if tcx.sess.opts.debugging_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) - { - monomorphize::util::dump_closure_profile(tcx, instance); - } - - respan(source, MonoItem::Fn(instance.polymorphize(tcx))) -} - -/// Creates a `MonoItem` for each method that is referenced by the vtable for -/// the given trait/impl pair. -fn create_mono_items_for_vtable_methods<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ty: Ty<'tcx>, - impl_ty: Ty<'tcx>, - source: Span, - output: &mut Vec>>, -) { - assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars()); - - if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind() { - if let Some(principal) = trait_ty.principal() { - let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); - assert!(!poly_trait_ref.has_escaping_bound_vars()); - - // Walk all methods of the trait, including those of its supertraits - let entries = tcx.vtable_entries(poly_trait_ref); - let methods = entries - .iter() - .filter_map(|entry| match entry { - VtblEntry::MetadataDropInPlace - | VtblEntry::MetadataSize - | VtblEntry::MetadataAlign - | VtblEntry::Vacant => None, - VtblEntry::TraitVPtr(_) => { - // all super trait items already covered, so skip them. - None - } - VtblEntry::Method(instance) => { - Some(*instance).filter(|instance| should_codegen_locally(tcx, instance)) - } - }) - .map(|item| create_fn_mono_item(tcx, item, source)); - output.extend(methods); - } - - // Also add the destructor. - visit_drop_use(tcx, impl_ty, false, source, output); - } -} - -//=----------------------------------------------------------------------------- -// Root Collection -//=----------------------------------------------------------------------------- - -struct RootCollector<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - mode: MonoItemCollectionMode, - output: &'a mut Vec>>, - entry_fn: Option<(DefId, EntryFnType)>, -} - -impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { - fn visit_item(&mut self, item: &'v hir::Item<'v>) { - match item.kind { - hir::ItemKind::ExternCrate(..) - | hir::ItemKind::Use(..) - | hir::ItemKind::Macro(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::Mod(..) => { - // Nothing to do, just keep recursing. - } - - hir::ItemKind::Impl { .. } => { - if self.mode == MonoItemCollectionMode::Eager { - create_mono_items_for_default_impls(self.tcx, item, self.output); - } - } - - hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) => { - if generics.params.is_empty() { - if self.mode == MonoItemCollectionMode::Eager { - debug!( - "RootCollector: ADT drop-glue for {}", - self.tcx.def_path_str(item.def_id.to_def_id()) - ); - - let ty = Instance::new(item.def_id.to_def_id(), InternalSubsts::empty()) - .ty(self.tcx, ty::ParamEnv::reveal_all()); - visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output); - } - } - } - hir::ItemKind::GlobalAsm(..) => { - debug!( - "RootCollector: ItemKind::GlobalAsm({})", - self.tcx.def_path_str(item.def_id.to_def_id()) - ); - self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.item_id()))); - } - hir::ItemKind::Static(..) => { - debug!( - "RootCollector: ItemKind::Static({})", - self.tcx.def_path_str(item.def_id.to_def_id()) - ); - self.output.push(dummy_spanned(MonoItem::Static(item.def_id.to_def_id()))); - } - hir::ItemKind::Const(..) => { - // const items only generate mono items if they are - // actually used somewhere. Just declaring them is insufficient. - - // but even just declaring them must collect the items they refer to - if let Ok(val) = self.tcx.const_eval_poly(item.def_id.to_def_id()) { - collect_const_value(self.tcx, val, &mut self.output); - } - } - hir::ItemKind::Fn(..) => { - self.push_if_root(item.def_id); - } - } - } - - fn visit_trait_item(&mut self, _: &'v hir::TraitItem<'v>) { - // Even if there's a default body with no explicit generics, - // it's still generic over some `Self: Trait`, so not a root. - } - - fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { - if let hir::ImplItemKind::Fn(hir::FnSig { .. }, _) = ii.kind { - self.push_if_root(ii.def_id); - } - } - - fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {} -} - -impl RootCollector<'_, 'v> { - fn is_root(&self, def_id: LocalDefId) -> bool { - !item_requires_monomorphization(self.tcx, def_id) - && match self.mode { - MonoItemCollectionMode::Eager => true, - MonoItemCollectionMode::Lazy => { - self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) - || self.tcx.is_reachable_non_generic(def_id) - || self - .tcx - .codegen_fn_attrs(def_id) - .flags - .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) - } - } - } - - /// If `def_id` represents a root, pushes it onto the list of - /// outputs. (Note that all roots must be monomorphic.) - fn push_if_root(&mut self, def_id: LocalDefId) { - if self.is_root(def_id) { - debug!("RootCollector::push_if_root: found root def_id={:?}", def_id); - - let instance = Instance::mono(self.tcx, def_id.to_def_id()); - self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP)); - } - } - - /// As a special case, when/if we encounter the - /// `main()` function, we also have to generate a - /// monomorphized copy of the start lang item based on - /// the return type of `main`. This is not needed when - /// the user writes their own `start` manually. - fn push_extra_entry_roots(&mut self) { - let main_def_id = match self.entry_fn { - Some((def_id, EntryFnType::Main)) => def_id, - _ => return, - }; - - let start_def_id = match self.tcx.lang_items().require(LangItem::Start) { - Ok(s) => s, - Err(err) => self.tcx.sess.fatal(&err), - }; - let main_ret_ty = self.tcx.fn_sig(main_def_id).output(); - - // Given that `main()` has no arguments, - // then its return type cannot have - // late-bound regions, since late-bound - // regions must appear in the argument - // listing. - let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); - - let start_instance = Instance::resolve( - self.tcx, - ty::ParamEnv::reveal_all(), - start_def_id, - self.tcx.intern_substs(&[main_ret_ty.into()]), - ) - .unwrap() - .unwrap(); - - self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); - } -} - -fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - let generics = tcx.generics_of(def_id); - generics.requires_monomorphization(tcx) -} - -fn create_mono_items_for_default_impls<'tcx>( - tcx: TyCtxt<'tcx>, - item: &'tcx hir::Item<'tcx>, - output: &mut Vec>>, -) { - match item.kind { - hir::ItemKind::Impl(ref impl_) => { - for param in impl_.generics.params { - match param.kind { - hir::GenericParamKind::Lifetime { .. } => {} - hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => { - return; - } - } - } - - debug!( - "create_mono_items_for_default_impls(item={})", - tcx.def_path_str(item.def_id.to_def_id()) - ); - - if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) { - let param_env = ty::ParamEnv::reveal_all(); - let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); - let overridden_methods: FxHashSet<_> = - impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect(); - for method in tcx.provided_trait_methods(trait_ref.def_id) { - if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) { - continue; - } - - if tcx.generics_of(method.def_id).own_requires_monomorphization() { - continue; - } - - let substs = - InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } - | GenericParamDefKind::Const { .. } => { - trait_ref.substs[param.index as usize] - } - }); - let instance = ty::Instance::resolve(tcx, param_env, method.def_id, substs) - .unwrap() - .unwrap(); - - let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); - if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance) - { - output.push(mono_item); - } - } - } - } - _ => bug!(), - } -} - -/// Scans the miri alloc in order to find function calls, closures, and drop-glue. -fn collect_miri<'tcx>( - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, - output: &mut Vec>>, -) { - match tcx.global_alloc(alloc_id) { - GlobalAlloc::Static(def_id) => { - assert!(!tcx.is_thread_local_static(def_id)); - let instance = Instance::mono(tcx, def_id); - if should_codegen_locally(tcx, &instance) { - trace!("collecting static {:?}", def_id); - output.push(dummy_spanned(MonoItem::Static(def_id))); - } - } - GlobalAlloc::Memory(alloc) => { - trace!("collecting {:?} with {:#?}", alloc_id, alloc); - for &inner in alloc.relocations().values() { - rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_miri(tcx, inner, output); - }); - } - } - GlobalAlloc::Function(fn_instance) => { - if should_codegen_locally(tcx, &fn_instance) { - trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); - output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); - } - } - } -} - -/// Scans the MIR in order to find function calls, closures, and drop-glue. -fn collect_neighbours<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - output: &mut Vec>>, -) { - debug!("collect_neighbours: {:?}", instance.def_id()); - let body = tcx.instance_mir(instance.def); - - MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); -} - -fn collect_const_value<'tcx>( - tcx: TyCtxt<'tcx>, - value: ConstValue<'tcx>, - output: &mut Vec>>, -) { - match value { - ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output), - ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { - for &id in alloc.relocations().values() { - collect_miri(tcx, id, output); - } - } - _ => {} - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -use rustc_middle::traits; -use rustc_middle::ty::adjustment::CustomCoerceUnsized; -use rustc_middle::ty::{self, Ty, TyCtxt}; - -use rustc_hir::lang_items::LangItem; - -pub mod collector; -pub mod partitioning; -pub mod polymorphize; -pub mod util; - -fn custom_coerce_unsize_info<'tcx>( - tcx: TyCtxt<'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>, -) -> CustomCoerceUnsized { - let def_id = tcx.require_lang_item(LangItem::CoerceUnsized, None); - - let trait_ref = ty::Binder::dummy(ty::TraitRef { - def_id, - substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]), - }); - - match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { - Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { - impl_def_id, - .. - })) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(), - impl_source => { - bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/default.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/default.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/default.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/default.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,557 +0,0 @@ -use std::collections::hash_map::Entry; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::DefPathDataName; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::exported_symbols::SymbolExportLevel; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; -use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; -use rustc_middle::ty::print::characteristic_def_id_of_type; -use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt}; -use rustc_span::symbol::Symbol; - -use super::PartitioningCx; -use crate::monomorphize::collector::InliningMap; -use crate::monomorphize::partitioning::merging; -use crate::monomorphize::partitioning::{ - MonoItemPlacement, Partitioner, PostInliningPartitioning, PreInliningPartitioning, -}; - -pub struct DefaultPartitioning; - -impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { - fn place_root_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut dyn Iterator>, - ) -> PreInliningPartitioning<'tcx> { - let mut roots = FxHashSet::default(); - let mut codegen_units = FxHashMap::default(); - let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); - let mut internalization_candidates = FxHashSet::default(); - - // Determine if monomorphizations instantiated in this crate will be made - // available to downstream crates. This depends on whether we are in - // share-generics mode and whether the current crate can even have - // downstream crates. - let export_generics = - cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - let cgu_name_cache = &mut FxHashMap::default(); - - for mono_item in mono_items { - match mono_item.instantiation_mode(cx.tcx) { - InstantiationMode::GloballyShared { .. } => {} - InstantiationMode::LocalCopy => continue, - } - - let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); - let is_volatile = is_incremental_build && mono_item.is_generic_fn(); - - let codegen_unit_name = match characteristic_def_id { - Some(def_id) => compute_codegen_unit_name( - cx.tcx, - cgu_name_builder, - def_id, - is_volatile, - cgu_name_cache, - ), - None => fallback_cgu_name(cgu_name_builder), - }; - - let codegen_unit = codegen_units - .entry(codegen_unit_name) - .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); - - let mut can_be_internalized = true; - let (linkage, visibility) = mono_item_linkage_and_visibility( - cx.tcx, - &mono_item, - &mut can_be_internalized, - export_generics, - ); - if visibility == Visibility::Hidden && can_be_internalized { - internalization_candidates.insert(mono_item); - } - - codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); - roots.insert(mono_item); - } - - // Always ensure we have at least one CGU; otherwise, if we have a - // crate with just types (for example), we could wind up with no CGU. - if codegen_units.is_empty() { - let codegen_unit_name = fallback_cgu_name(cgu_name_builder); - codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); - } - - PreInliningPartitioning { - codegen_units: codegen_units - .into_iter() - .map(|(_, codegen_unit)| codegen_unit) - .collect(), - roots, - internalization_candidates, - } - } - - fn merge_codegen_units( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, - ) { - merging::merge_codegen_units(cx, initial_partitioning); - } - - fn place_inlined_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: PreInliningPartitioning<'tcx>, - ) -> PostInliningPartitioning<'tcx> { - let mut new_partitioning = Vec::new(); - let mut mono_item_placements = FxHashMap::default(); - - let PreInliningPartitioning { - codegen_units: initial_cgus, - roots, - internalization_candidates, - } = initial_partitioning; - - let single_codegen_unit = initial_cgus.len() == 1; - - for old_codegen_unit in initial_cgus { - // Collect all items that need to be available in this codegen unit. - let mut reachable = FxHashSet::default(); - for root in old_codegen_unit.items().keys() { - follow_inlining(*root, cx.inlining_map, &mut reachable); - } - - let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); - - // Add all monomorphizations that are not already there. - for mono_item in reachable { - if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { - // This is a root, just copy it over. - new_codegen_unit.items_mut().insert(mono_item, *linkage); - } else { - if roots.contains(&mono_item) { - bug!( - "GloballyShared mono-item inlined into other CGU: \ - {:?}", - mono_item - ); - } - - // This is a CGU-private copy. - new_codegen_unit - .items_mut() - .insert(mono_item, (Linkage::Internal, Visibility::Default)); - } - - if !single_codegen_unit { - // If there is more than one codegen unit, we need to keep track - // in which codegen units each monomorphization is placed. - match mono_item_placements.entry(mono_item) { - Entry::Occupied(e) => { - let placement = e.into_mut(); - debug_assert!(match *placement { - MonoItemPlacement::SingleCgu { cgu_name } => { - cgu_name != new_codegen_unit.name() - } - MonoItemPlacement::MultipleCgus => true, - }); - *placement = MonoItemPlacement::MultipleCgus; - } - Entry::Vacant(e) => { - e.insert(MonoItemPlacement::SingleCgu { - cgu_name: new_codegen_unit.name(), - }); - } - } - } - } - - new_partitioning.push(new_codegen_unit); - } - - return PostInliningPartitioning { - codegen_units: new_partitioning, - mono_item_placements, - internalization_candidates, - }; - - fn follow_inlining<'tcx>( - mono_item: MonoItem<'tcx>, - inlining_map: &InliningMap<'tcx>, - visited: &mut FxHashSet>, - ) { - if !visited.insert(mono_item) { - return; - } - - inlining_map.with_inlining_candidates(mono_item, |target| { - follow_inlining(target, inlining_map, visited); - }); - } - } - - fn internalize_symbols( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - partitioning: &mut PostInliningPartitioning<'tcx>, - ) { - if partitioning.codegen_units.len() == 1 { - // Fast path for when there is only one codegen unit. In this case we - // can internalize all candidates, since there is nowhere else they - // could be accessed from. - for cgu in &mut partitioning.codegen_units { - for candidate in &partitioning.internalization_candidates { - cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); - } - } - - return; - } - - // Build a map from every monomorphization to all the monomorphizations that - // reference it. - let mut accessor_map: FxHashMap, Vec>> = Default::default(); - cx.inlining_map.iter_accesses(|accessor, accessees| { - for accessee in accessees { - accessor_map.entry(*accessee).or_default().push(accessor); - } - }); - - let mono_item_placements = &partitioning.mono_item_placements; - - // For each internalization candidates in each codegen unit, check if it is - // accessed from outside its defining codegen unit. - for cgu in &mut partitioning.codegen_units { - let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; - - for (accessee, linkage_and_visibility) in cgu.items_mut() { - if !partitioning.internalization_candidates.contains(accessee) { - // This item is no candidate for internalizing, so skip it. - continue; - } - debug_assert_eq!(mono_item_placements[accessee], home_cgu); - - if let Some(accessors) = accessor_map.get(accessee) { - if accessors - .iter() - .filter_map(|accessor| { - // Some accessors might not have been - // instantiated. We can safely ignore those. - mono_item_placements.get(accessor) - }) - .any(|placement| *placement != home_cgu) - { - // Found an accessor from another CGU, so skip to the next - // item without marking this one as internal. - continue; - } - } - - // If we got here, we did not find any accesses from other CGUs, - // so it's fine to make this monomorphization internal. - *linkage_and_visibility = (Linkage::Internal, Visibility::Default); - } - } - } -} - -fn characteristic_def_id_of_mono_item<'tcx>( - tcx: TyCtxt<'tcx>, - mono_item: MonoItem<'tcx>, -) -> Option { - match mono_item { - MonoItem::Fn(instance) => { - let def_id = match instance.def { - ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::CloneShim(..) => return None, - }; - - // If this is a method, we want to put it into the same module as - // its self-type. If the self-type does not provide a characteristic - // DefId, we use the location of the impl after all. - - if tcx.trait_of_item(def_id).is_some() { - let self_ty = instance.substs.type_at(0); - // This is a default implementation of a trait method. - return characteristic_def_id_of_type(self_ty).or(Some(def_id)); - } - - if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - if tcx.sess.opts.incremental.is_some() - && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() - { - // Put `Drop::drop` into the same cgu as `drop_in_place` - // since `drop_in_place` is the only thing that can - // call it. - return None; - } - // This is a method within an impl, find out what the self-type is: - let impl_self_ty = tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - tcx.type_of(impl_def_id), - ); - if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { - return Some(def_id); - } - } - - Some(def_id) - } - MonoItem::Static(def_id) => Some(def_id), - MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.to_def_id()), - } -} - -fn compute_codegen_unit_name( - tcx: TyCtxt<'_>, - name_builder: &mut CodegenUnitNameBuilder<'_>, - def_id: DefId, - volatile: bool, - cache: &mut CguNameCache, -) -> Symbol { - // Find the innermost module that is not nested within a function. - let mut current_def_id = def_id; - let mut cgu_def_id = None; - // Walk backwards from the item we want to find the module for. - loop { - if current_def_id.index == CRATE_DEF_INDEX { - if cgu_def_id.is_none() { - // If we have not found a module yet, take the crate root. - cgu_def_id = Some(DefId { krate: def_id.krate, index: CRATE_DEF_INDEX }); - } - break; - } else if tcx.def_kind(current_def_id) == DefKind::Mod { - if cgu_def_id.is_none() { - cgu_def_id = Some(current_def_id); - } - } else { - // If we encounter something that is not a module, throw away - // any module that we've found so far because we now know that - // it is nested within something else. - cgu_def_id = None; - } - - current_def_id = tcx.parent(current_def_id).unwrap(); - } - - let cgu_def_id = cgu_def_id.unwrap(); - - *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { - let def_path = tcx.def_path(cgu_def_id); - - let components = def_path.data.iter().map(|part| match part.data.name() { - DefPathDataName::Named(name) => name, - DefPathDataName::Anon { .. } => unreachable!(), - }); - - let volatile_suffix = volatile.then_some("volatile"); - - name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) - }) -} - -// Anything we can't find a proper codegen unit for goes into this. -fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { - name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) -} - -fn mono_item_linkage_and_visibility( - tcx: TyCtxt<'tcx>, - mono_item: &MonoItem<'tcx>, - can_be_internalized: &mut bool, - export_generics: bool, -) -> (Linkage, Visibility) { - if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { - return (explicit_linkage, Visibility::Default); - } - let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); - (Linkage::External, vis) -} - -type CguNameCache = FxHashMap<(DefId, bool), Symbol>; - -fn mono_item_visibility( - tcx: TyCtxt<'tcx>, - mono_item: &MonoItem<'tcx>, - can_be_internalized: &mut bool, - export_generics: bool, -) -> Visibility { - let instance = match mono_item { - // This is pretty complicated; see below. - MonoItem::Fn(instance) => instance, - - // Misc handling for generics and such, but otherwise: - MonoItem::Static(def_id) => { - return if tcx.is_reachable_non_generic(*def_id) { - *can_be_internalized = false; - default_visibility(tcx, *def_id, false) - } else { - Visibility::Hidden - }; - } - MonoItem::GlobalAsm(item_id) => { - return if tcx.is_reachable_non_generic(item_id.def_id) { - *can_be_internalized = false; - default_visibility(tcx, item_id.def_id.to_def_id(), false) - } else { - Visibility::Hidden - }; - } - }; - - let def_id = match instance.def { - InstanceDef::Item(def) => def.did, - InstanceDef::DropGlue(def_id, Some(_)) => def_id, - - // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VtableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) => return Visibility::Hidden, - }; - - // The `start_fn` lang item is actually a monomorphized instance of a - // function in the standard library, used for the `main` function. We don't - // want to export it so we tag it with `Hidden` visibility but this symbol - // is only referenced from the actual `main` symbol which we unfortunately - // don't know anything about during partitioning/collection. As a result we - // forcibly keep this symbol out of the `internalization_candidates` set. - // - // FIXME: eventually we don't want to always force this symbol to have - // hidden visibility, it should indeed be a candidate for - // internalization, but we have to understand that it's referenced - // from the `main` symbol we'll generate later. - // - // This may be fixable with a new `InstanceDef` perhaps? Unsure! - if tcx.lang_items().start_fn() == Some(def_id) { - *can_be_internalized = false; - return Visibility::Hidden; - } - - let is_generic = instance.substs.non_erasable_generics().next().is_some(); - - // Upstream `DefId` instances get different handling than local ones. - let def_id = if let Some(def_id) = def_id.as_local() { - def_id - } else { - return if export_generics && is_generic { - // If it is an upstream monomorphization and we export generics, we must make - // it available to downstream crates. - *can_be_internalized = false; - default_visibility(tcx, def_id, true) - } else { - Visibility::Hidden - }; - }; - - if is_generic { - if export_generics { - if tcx.is_unreachable_local_definition(def_id) { - // This instance cannot be used from another crate. - Visibility::Hidden - } else { - // This instance might be useful in a downstream crate. - *can_be_internalized = false; - default_visibility(tcx, def_id.to_def_id(), true) - } - } else { - // We are not exporting generics or the definition is not reachable - // for downstream crates, we can internalize its instantiations. - Visibility::Hidden - } - } else { - // If this isn't a generic function then we mark this a `Default` if - // this is a reachable item, meaning that it's a symbol other crates may - // access when they link to us. - if tcx.is_reachable_non_generic(def_id.to_def_id()) { - *can_be_internalized = false; - debug_assert!(!is_generic); - return default_visibility(tcx, def_id.to_def_id(), false); - } - - // If this isn't reachable then we're gonna tag this with `Hidden` - // visibility. In some situations though we'll want to prevent this - // symbol from being internalized. - // - // There's two categories of items here: - // - // * First is weak lang items. These are basically mechanisms for - // libcore to forward-reference symbols defined later in crates like - // the standard library or `#[panic_handler]` definitions. The - // definition of these weak lang items needs to be referenceable by - // libcore, so we're no longer a candidate for internalization. - // Removal of these functions can't be done by LLVM but rather must be - // done by the linker as it's a non-local decision. - // - // * Second is "std internal symbols". Currently this is primarily used - // for allocator symbols. Allocators are a little weird in their - // implementation, but the idea is that the compiler, at the last - // minute, defines an allocator with an injected object file. The - // `alloc` crate references these symbols (`__rust_alloc`) and the - // definition doesn't get hooked up until a linked crate artifact is - // generated. - // - // The symbols synthesized by the compiler (`__rust_alloc`) are thin - // veneers around the actual implementation, some other symbol which - // implements the same ABI. These symbols (things like `__rg_alloc`, - // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std - // internal symbols". - // - // The std-internal symbols here **should not show up in a dll as an - // exported interface**, so they return `false` from - // `is_reachable_non_generic` above and we'll give them `Hidden` - // visibility below. Like the weak lang items, though, we can't let - // LLVM internalize them as this decision is left up to the linker to - // omit them, so prevent them from being internalized. - let attrs = tcx.codegen_fn_attrs(def_id); - if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { - *can_be_internalized = false; - } - - Visibility::Hidden - } -} - -fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { - if !tcx.sess.target.default_hidden_visibility { - return Visibility::Default; - } - - // Generic functions never have export-level C. - if is_generic { - return Visibility::Hidden; - } - - // Things with export level C don't get instantiated in - // downstream crates. - if !id.is_local() { - return Visibility::Hidden; - } - - // C-export level items remain at `Default`, all other internal - // items become `Hidden`. - match tcx.reachable_non_generics(id.krate).get(&id) { - Some(SymbolExportLevel::C) => Visibility::Default, - _ => Visibility::Hidden, - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -use std::cmp; - -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder}; -use rustc_span::symbol::{Symbol, SymbolStr}; - -use super::PartitioningCx; -use crate::monomorphize::partitioning::PreInliningPartitioning; - -pub fn merge_codegen_units<'tcx>( - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, -) { - assert!(cx.target_cgu_count >= 1); - let codegen_units = &mut initial_partitioning.codegen_units; - - // Note that at this point in time the `codegen_units` here may not be in a - // deterministic order (but we know they're deterministically the same set). - // We want this merging to produce a deterministic ordering of codegen units - // from the input. - // - // Due to basically how we've implemented the merging below (merge the two - // smallest into each other) we're sure to start off with a deterministic - // order (sorted by name). This'll mean that if two cgus have the same size - // the stable sort below will keep everything nice and deterministic. - codegen_units.sort_by_cached_key(|cgu| cgu.name().as_str()); - - // This map keeps track of what got merged into what. - let mut cgu_contents: FxHashMap> = - codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect(); - - // Merge the two smallest codegen units until the target size is reached. - while codegen_units.len() > cx.target_cgu_count { - // Sort small cgus to the back - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); - let mut smallest = codegen_units.pop().unwrap(); - let second_smallest = codegen_units.last_mut().unwrap(); - - // Move the mono-items from `smallest` to `second_smallest` - second_smallest.modify_size_estimate(smallest.size_estimate()); - for (k, v) in smallest.items_mut().drain() { - second_smallest.items_mut().insert(k, v); - } - - // Record that `second_smallest` now contains all the stuff that was in - // `smallest` before. - let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); - cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); - - debug!( - "CodegenUnit {} merged into CodegenUnit {}", - smallest.name(), - second_smallest.name() - ); - } - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - - if cx.tcx.sess.opts.incremental.is_some() { - // If we are doing incremental compilation, we want CGU names to - // reflect the path of the source level module they correspond to. - // For CGUs that contain the code of multiple modules because of the - // merging done above, we use a concatenation of the names of - // all contained CGUs. - let new_cgu_names: FxHashMap = cgu_contents - .into_iter() - // This `filter` makes sure we only update the name of CGUs that - // were actually modified by merging. - .filter(|(_, cgu_contents)| cgu_contents.len() > 1) - .map(|(current_cgu_name, cgu_contents)| { - let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| &s[..]).collect(); - - // Sort the names, so things are deterministic and easy to - // predict. - - // We are sorting primitive &strs here so we can use unstable sort - cgu_contents.sort_unstable(); - - (current_cgu_name, cgu_contents.join("--")) - }) - .collect(); - - for cgu in codegen_units.iter_mut() { - if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names { - cgu.set_name(Symbol::intern(&new_cgu_name)); - } else { - // If we don't require CGU names to be human-readable, we - // use a fixed length hash of the composite CGU name - // instead. - let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); - cgu.set_name(Symbol::intern(&new_cgu_name)); - } - } - } - } else { - // If we are compiling non-incrementally we just generate simple CGU - // names containing an index. - for (index, cgu) in codegen_units.iter_mut().enumerate() { - cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index)); - } - } -} - -fn numbered_codegen_unit_name( - name_builder: &mut CodegenUnitNameBuilder<'_>, - index: usize, -) -> Symbol { - name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,466 +0,0 @@ -//! Partitioning Codegen Units for Incremental Compilation -//! ====================================================== -//! -//! The task of this module is to take the complete set of monomorphizations of -//! a crate and produce a set of codegen units from it, where a codegen unit -//! is a named set of (mono-item, linkage) pairs. That is, this module -//! decides which monomorphization appears in which codegen units with which -//! linkage. The following paragraphs describe some of the background on the -//! partitioning scheme. -//! -//! The most important opportunity for saving on compilation time with -//! incremental compilation is to avoid re-codegenning and re-optimizing code. -//! Since the unit of codegen and optimization for LLVM is "modules" or, how -//! we call them "codegen units", the particulars of how much time can be saved -//! by incremental compilation are tightly linked to how the output program is -//! partitioned into these codegen units prior to passing it to LLVM -- -//! especially because we have to treat codegen units as opaque entities once -//! they are created: There is no way for us to incrementally update an existing -//! LLVM module and so we have to build any such module from scratch if it was -//! affected by some change in the source code. -//! -//! From that point of view it would make sense to maximize the number of -//! codegen units by, for example, putting each function into its own module. -//! That way only those modules would have to be re-compiled that were actually -//! affected by some change, minimizing the number of functions that could have -//! been re-used but just happened to be located in a module that is -//! re-compiled. -//! -//! However, since LLVM optimization does not work across module boundaries, -//! using such a highly granular partitioning would lead to very slow runtime -//! code since it would effectively prohibit inlining and other inter-procedure -//! optimizations. We want to avoid that as much as possible. -//! -//! Thus we end up with a trade-off: The bigger the codegen units, the better -//! LLVM's optimizer can do its work, but also the smaller the compilation time -//! reduction we get from incremental compilation. -//! -//! Ideally, we would create a partitioning such that there are few big codegen -//! units with few interdependencies between them. For now though, we use the -//! following heuristic to determine the partitioning: -//! -//! - There are two codegen units for every source-level module: -//! - One for "stable", that is non-generic, code -//! - One for more "volatile" code, i.e., monomorphized instances of functions -//! defined in that module -//! -//! In order to see why this heuristic makes sense, let's take a look at when a -//! codegen unit can get invalidated: -//! -//! 1. The most straightforward case is when the BODY of a function or global -//! changes. Then any codegen unit containing the code for that item has to be -//! re-compiled. Note that this includes all codegen units where the function -//! has been inlined. -//! -//! 2. The next case is when the SIGNATURE of a function or global changes. In -//! this case, all codegen units containing a REFERENCE to that item have to be -//! re-compiled. This is a superset of case 1. -//! -//! 3. The final and most subtle case is when a REFERENCE to a generic function -//! is added or removed somewhere. Even though the definition of the function -//! might be unchanged, a new REFERENCE might introduce a new monomorphized -//! instance of this function which has to be placed and compiled somewhere. -//! Conversely, when removing a REFERENCE, it might have been the last one with -//! that particular set of generic arguments and thus we have to remove it. -//! -//! From the above we see that just using one codegen unit per source-level -//! module is not such a good idea, since just adding a REFERENCE to some -//! generic item somewhere else would invalidate everything within the module -//! containing the generic item. The heuristic above reduces this detrimental -//! side-effect of references a little by at least not touching the non-generic -//! code of the module. -//! -//! A Note on Inlining -//! ------------------ -//! As briefly mentioned above, in order for LLVM to be able to inline a -//! function call, the body of the function has to be available in the LLVM -//! module where the call is made. This has a few consequences for partitioning: -//! -//! - The partitioning algorithm has to take care of placing functions into all -//! codegen units where they should be available for inlining. It also has to -//! decide on the correct linkage for these functions. -//! -//! - The partitioning algorithm has to know which functions are likely to get -//! inlined, so it can distribute function instantiations accordingly. Since -//! there is no way of knowing for sure which functions LLVM will decide to -//! inline in the end, we apply a heuristic here: Only functions marked with -//! `#[inline]` are considered for inlining by the partitioner. The current -//! implementation will not try to determine if a function is likely to be -//! inlined by looking at the functions definition. -//! -//! Note though that as a side-effect of creating a codegen units per -//! source-level module, functions from the same module will be available for -//! inlining, even when they are not marked `#[inline]`. - -mod default; -mod merging; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync; -use rustc_hir::def_id::DefIdSet; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::mir::mono::{CodegenUnit, Linkage}; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::Symbol; - -use crate::monomorphize::collector::InliningMap; -use crate::monomorphize::collector::{self, MonoItemCollectionMode}; - -pub struct PartitioningCx<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - target_cgu_count: usize, - inlining_map: &'a InliningMap<'tcx>, -} - -trait Partitioner<'tcx> { - fn place_root_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut dyn Iterator>, - ) -> PreInliningPartitioning<'tcx>; - - fn merge_codegen_units( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, - ); - - fn place_inlined_mono_items( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: PreInliningPartitioning<'tcx>, - ) -> PostInliningPartitioning<'tcx>; - - fn internalize_symbols( - &mut self, - cx: &PartitioningCx<'_, 'tcx>, - partitioning: &mut PostInliningPartitioning<'tcx>, - ); -} - -fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box> { - let strategy = match &tcx.sess.opts.debugging_opts.cgu_partitioning_strategy { - None => "default", - Some(s) => &s[..], - }; - - match strategy { - "default" => Box::new(default::DefaultPartitioning), - _ => tcx.sess.fatal("unknown partitioning strategy"), - } -} - -pub fn partition<'tcx>( - tcx: TyCtxt<'tcx>, - mono_items: &mut dyn Iterator>, - max_cgu_count: usize, - inlining_map: &InliningMap<'tcx>, -) -> Vec> { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); - - let mut partitioner = get_partitioner(tcx); - let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; - // In the first step, we place all regular monomorphizations into their - // respective 'home' codegen unit. Regular monomorphizations are all - // functions and statics defined in the local crate. - let mut initial_partitioning = { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - partitioner.place_root_mono_items(cx, mono_items) - }; - - initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); - - debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); - - // Merge until we have at most `max_cgu_count` codegen units. - { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - partitioner.merge_codegen_units(cx, &mut initial_partitioning); - debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); - } - - // In the next step, we use the inlining map to determine which additional - // monomorphizations have to go into each codegen unit. These additional - // monomorphizations can be drop-glue, functions from external crates, and - // local functions the definition of which is marked with `#[inline]`. - let mut post_inlining = { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - partitioner.place_inlined_mono_items(cx, initial_partitioning) - }; - - post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); - - debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); - - // Next we try to make as many symbols "internal" as possible, so LLVM has - // more freedom to optimize. - if !tcx.sess.link_dead_code() { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - partitioner.internalize_symbols(cx, &mut post_inlining); - } - - // Finally, sort by codegen unit name, so that we get deterministic results. - let PostInliningPartitioning { - codegen_units: mut result, - mono_item_placements: _, - internalization_candidates: _, - } = post_inlining; - - result.sort_by_cached_key(|cgu| cgu.name().as_str()); - - result -} - -pub struct PreInliningPartitioning<'tcx> { - codegen_units: Vec>, - roots: FxHashSet>, - internalization_candidates: FxHashSet>, -} - -/// For symbol internalization, we need to know whether a symbol/mono-item is -/// accessed from outside the codegen unit it is defined in. This type is used -/// to keep track of that. -#[derive(Clone, PartialEq, Eq, Debug)] -enum MonoItemPlacement { - SingleCgu { cgu_name: Symbol }, - MultipleCgus, -} - -struct PostInliningPartitioning<'tcx> { - codegen_units: Vec>, - mono_item_placements: FxHashMap, MonoItemPlacement>, - internalization_candidates: FxHashSet>, -} - -fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I) -where - I: Iterator>, - 'tcx: 'a, -{ - let dump = move || { - use std::fmt::Write; - - let s = &mut String::new(); - let _ = writeln!(s, "{}", label); - for cgu in cgus { - let _ = - writeln!(s, "CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate()); - - for (mono_item, linkage) in cgu.items() { - let symbol_name = mono_item.symbol_name(tcx).name; - let symbol_hash_start = symbol_name.rfind('h'); - let symbol_hash = symbol_hash_start.map_or("", |i| &symbol_name[i..]); - - let _ = writeln!( - s, - " - {} [{:?}] [{}] estimated size {}", - mono_item, - linkage, - symbol_hash, - mono_item.size_estimate(tcx) - ); - } - - let _ = writeln!(s, ""); - } - - std::mem::take(s) - }; - - debug!("{}", dump()); -} - -#[inline(never)] // give this a place in the profiler -fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -where - I: Iterator>, - 'tcx: 'a, -{ - let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct"); - - let mut symbols: Vec<_> = - mono_items.map(|mono_item| (mono_item, mono_item.symbol_name(tcx))).collect(); - - symbols.sort_by_key(|sym| sym.1); - - for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() { - if sym1 == sym2 { - let span1 = mono_item1.local_span(tcx); - let span2 = mono_item2.local_span(tcx); - - // Deterministically select one of the spans for error reporting - let span = match (span1, span2) { - (Some(span1), Some(span2)) => { - Some(if span1.lo().0 > span2.lo().0 { span1 } else { span2 }) - } - (span1, span2) => span1.or(span2), - }; - - let error_message = format!("symbol `{}` is already defined", sym1); - - if let Some(span) = span { - tcx.sess.span_fatal(span, &error_message) - } else { - tcx.sess.fatal(&error_message) - } - } - } -} - -fn collect_and_partition_mono_items<'tcx>( - tcx: TyCtxt<'tcx>, - (): (), -) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { - let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { - Some(ref s) => { - let mode_string = s.to_lowercase(); - let mode_string = mode_string.trim(); - if mode_string == "eager" { - MonoItemCollectionMode::Eager - } else { - if mode_string != "lazy" { - let message = format!( - "Unknown codegen-item collection mode '{}'. \ - Falling back to 'lazy' mode.", - mode_string - ); - tcx.sess.warn(&message); - } - - MonoItemCollectionMode::Lazy - } - } - None => { - if tcx.sess.link_dead_code() { - MonoItemCollectionMode::Eager - } else { - MonoItemCollectionMode::Lazy - } - } - }; - - let (items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode); - - tcx.sess.abort_if_errors(); - - let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || { - sync::join( - || { - let mut codegen_units = partition( - tcx, - &mut items.iter().cloned(), - tcx.sess.codegen_units(), - &inlining_map, - ); - codegen_units[0].make_primary(); - &*tcx.arena.alloc_from_iter(codegen_units) - }, - || assert_symbols_are_distinct(tcx, items.iter()), - ) - }); - - let mono_items: DefIdSet = items - .iter() - .filter_map(|mono_item| match *mono_item { - MonoItem::Fn(ref instance) => Some(instance.def_id()), - MonoItem::Static(def_id) => Some(def_id), - _ => None, - }) - .collect(); - - if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { - let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); - - for cgu in codegen_units { - for (&mono_item, &linkage) in cgu.items() { - item_to_cgus.entry(mono_item).or_default().push((cgu.name(), linkage)); - } - } - - let mut item_keys: Vec<_> = items - .iter() - .map(|i| { - let mut output = with_no_trimmed_paths(|| i.to_string()); - output.push_str(" @@"); - let mut empty = Vec::new(); - let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); - cgus.sort_by_key(|(name, _)| *name); - cgus.dedup(); - for &(ref cgu_name, (linkage, _)) in cgus.iter() { - output.push(' '); - output.push_str(&cgu_name.as_str()); - - let linkage_abbrev = match linkage { - Linkage::External => "External", - Linkage::AvailableExternally => "Available", - Linkage::LinkOnceAny => "OnceAny", - Linkage::LinkOnceODR => "OnceODR", - Linkage::WeakAny => "WeakAny", - Linkage::WeakODR => "WeakODR", - Linkage::Appending => "Appending", - Linkage::Internal => "Internal", - Linkage::Private => "Private", - Linkage::ExternalWeak => "ExternalWeak", - Linkage::Common => "Common", - }; - - output.push('['); - output.push_str(linkage_abbrev); - output.push(']'); - } - output - }) - .collect(); - - item_keys.sort(); - - for item in item_keys { - println!("MONO_ITEM {}", item); - } - } - - (tcx.arena.alloc(mono_items), codegen_units) -} - -fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSet { - let (items, cgus) = tcx.collect_and_partition_mono_items(()); - let mut visited = DefIdSet::default(); - let mut result = items.clone(); - - for cgu in cgus { - for (item, _) in cgu.items() { - if let MonoItem::Fn(ref instance) = item { - let did = instance.def_id(); - if !visited.insert(did) { - continue; - } - for scope in &tcx.instance_mir(instance.def).source_scopes { - if let Some((ref inlined, _)) = scope.inlined { - result.insert(inlined.def_id()); - } - } - } - } - } - - tcx.arena.alloc(result) -} - -pub fn provide(providers: &mut Providers) { - providers.collect_and_partition_mono_items = collect_and_partition_mono_items; - providers.codegened_and_inlined_items = codegened_and_inlined_items; - - providers.is_codegened_item = |tcx, def_id| { - let (all_mono_items, _) = tcx.collect_and_partition_mono_items(()); - all_mono_items.contains(&def_id) - }; - - providers.codegen_unit = |tcx, name| { - let (_, all) = tcx.collect_and_partition_mono_items(()); - all.iter() - .find(|cgu| cgu.name() == name) - .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name)) - }; -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/polymorphize.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/polymorphize.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/polymorphize.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/polymorphize.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,399 +0,0 @@ -//! Polymorphization Analysis -//! ========================= -//! -//! This module implements an analysis of functions, methods and closures to determine which -//! generic parameters are unused (and eventually, in what ways generic parameters are used - only -//! for their size, offset of a field, etc.). - -use rustc_hir::{def::DefKind, def_id::DefId, ConstContext}; -use rustc_index::bit_set::FiniteBitSet; -use rustc_middle::mir::{ - visit::{TyContext, Visitor}, - Local, LocalDecl, Location, -}; -use rustc_middle::ty::{ - self, - fold::{TypeFoldable, TypeVisitor}, - query::Providers, - subst::SubstsRef, - Const, Ty, TyCtxt, -}; -use rustc_span::symbol::sym; -use std::convert::TryInto; -use std::ops::ControlFlow; - -/// Provide implementations of queries relating to polymorphization analysis. -pub fn provide(providers: &mut Providers) { - providers.unused_generic_params = unused_generic_params; -} - -/// Determine which generic parameters are used by the function/method/closure represented by -/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty` -/// indicates all parameters are used). -#[instrument(skip(tcx))] -fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { - if !tcx.sess.opts.debugging_opts.polymorphize { - // If polymorphization disabled, then all parameters are used. - return FiniteBitSet::new_empty(); - } - - // Polymorphization results are stored in cross-crate metadata only when there are unused - // parameters, so assume that non-local items must have only used parameters (else this query - // would not be invoked, and the cross-crate metadata used instead). - if !def_id.is_local() { - return FiniteBitSet::new_empty(); - } - - let generics = tcx.generics_of(def_id); - debug!(?generics); - - // Exit early when there are no parameters to be unused. - if generics.count() == 0 { - return FiniteBitSet::new_empty(); - } - - // Exit early when there is no MIR available. - let context = tcx.hir().body_const_context(def_id.expect_local()); - match context { - Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => { - debug!("no mir available"); - return FiniteBitSet::new_empty(); - } - Some(_) if !tcx.is_ctfe_mir_available(def_id) => { - debug!("no ctfe mir available"); - return FiniteBitSet::new_empty(); - } - _ => {} - } - - // Create a bitset with N rightmost ones for each parameter. - let generics_count: u32 = - generics.count().try_into().expect("more generic parameters than can fit into a `u32`"); - let mut unused_parameters = FiniteBitSet::::new_empty(); - unused_parameters.set_range(0..generics_count); - debug!(?unused_parameters, "(start)"); - mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); - debug!(?unused_parameters, "(after default)"); - - // Visit MIR and accumululate used generic parameters. - let body = match context { - // Const functions are actually called and should thus be considered for polymorphization - // via their runtime MIR - Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id), - Some(_) => tcx.mir_for_ctfe(def_id), - }; - let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters }; - vis.visit_body(body); - debug!(?unused_parameters, "(after visitor)"); - - mark_used_by_predicates(tcx, def_id, &mut unused_parameters); - debug!(?unused_parameters, "(end)"); - - // Emit errors for debugging and testing if enabled. - if !unused_parameters.is_empty() { - emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters); - } - - unused_parameters -} - -/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy -/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should -/// be `true` if the item that `unused_generic_params` was invoked on is a closure. -#[instrument(skip(tcx, def_id, generics, unused_parameters))] -fn mark_used_by_default_parameters<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - generics: &'tcx ty::Generics, - unused_parameters: &mut FiniteBitSet, -) { - match tcx.def_kind(def_id) { - DefKind::Closure | DefKind::Generator => { - for param in &generics.params { - debug!(?param, "(closure/gen)"); - unused_parameters.clear(param.index); - } - } - DefKind::Mod - | DefKind::Struct - | DefKind::Union - | DefKind::Enum - | DefKind::Variant - | DefKind::Trait - | DefKind::TyAlias - | DefKind::ForeignTy - | DefKind::TraitAlias - | DefKind::AssocTy - | DefKind::TyParam - | DefKind::Fn - | DefKind::Const - | DefKind::ConstParam - | DefKind::Static - | DefKind::Ctor(_, _) - | DefKind::AssocFn - | DefKind::AssocConst - | DefKind::Macro(_) - | DefKind::ExternCrate - | DefKind::Use - | DefKind::ForeignMod - | DefKind::AnonConst - | DefKind::OpaqueTy - | DefKind::Field - | DefKind::LifetimeParam - | DefKind::GlobalAsm - | DefKind::Impl => { - for param in &generics.params { - debug!(?param, "(other)"); - if let ty::GenericParamDefKind::Lifetime = param.kind { - unused_parameters.clear(param.index); - } - } - } - } - - if let Some(parent) = generics.parent { - mark_used_by_default_parameters(tcx, parent, tcx.generics_of(parent), unused_parameters); - } -} - -/// Search the predicates on used generic parameters for any unused generic parameters, and mark -/// those as used. -#[instrument(skip(tcx, def_id))] -fn mark_used_by_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - unused_parameters: &mut FiniteBitSet, -) { - let def_id = tcx.closure_base_def_id(def_id); - let predicates = tcx.explicit_predicates_of(def_id); - - let mut current_unused_parameters = FiniteBitSet::new_empty(); - // Run to a fixed point to support `where T: Trait, U: Trait`, starting with an empty - // bit set so that this is skipped if all parameters are already used. - while current_unused_parameters != *unused_parameters { - debug!(?current_unused_parameters, ?unused_parameters); - current_unused_parameters = *unused_parameters; - - for (predicate, _) in predicates.predicates { - // Consider all generic params in a predicate as used if any other parameter in the - // predicate is used. - let any_param_used = { - let mut vis = HasUsedGenericParams { tcx, unused_parameters }; - predicate.visit_with(&mut vis).is_break() - }; - - if any_param_used { - let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters }; - predicate.visit_with(&mut vis); - } - } - } - - if let Some(parent) = predicates.parent { - mark_used_by_predicates(tcx, parent, unused_parameters); - } -} - -/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic -/// parameter which was unused. -#[instrument(skip(tcx, generics))] -fn emit_unused_generic_params_error<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - generics: &'tcx ty::Generics, - unused_parameters: &FiniteBitSet, -) { - let base_def_id = tcx.closure_base_def_id(def_id); - if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) { - return; - } - - let fn_span = match tcx.opt_item_name(def_id) { - Some(ident) => ident.span, - _ => tcx.def_span(def_id), - }; - - let mut err = tcx.sess.struct_span_err(fn_span, "item has unused generic parameters"); - - let mut next_generics = Some(generics); - while let Some(generics) = next_generics { - for param in &generics.params { - if unused_parameters.contains(param.index).unwrap_or(false) { - debug!(?param); - let def_span = tcx.def_span(param.def_id); - err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name)); - } - } - - next_generics = generics.parent.map(|did| tcx.generics_of(did)); - } - - err.emit(); -} - -/// Visitor used to aggregate generic parameter uses. -struct MarkUsedGenericParams<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - def_id: DefId, - unused_parameters: &'a mut FiniteBitSet, -} - -impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { - /// Invoke `unused_generic_params` on a body contained within the current item (e.g. - /// a closure, generator or constant). - #[instrument(skip(self, def_id, substs))] - fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) { - let unused = self.tcx.unused_generic_params(def_id); - debug!(?self.unused_parameters, ?unused); - for (i, arg) in substs.iter().enumerate() { - let i = i.try_into().unwrap(); - if !unused.contains(i).unwrap_or(false) { - arg.visit_with(self); - } - } - debug!(?self.unused_parameters); - } -} - -impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { - #[instrument(skip(self, local))] - fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { - if local == Local::from_usize(1) { - let def_kind = self.tcx.def_kind(self.def_id); - if matches!(def_kind, DefKind::Closure | DefKind::Generator) { - // Skip visiting the closure/generator that is currently being processed. This only - // happens because the first argument to the closure is a reference to itself and - // that will call `visit_substs`, resulting in each generic parameter captured being - // considered used by default. - debug!("skipping closure substs"); - return; - } - } - - self.super_local_decl(local, local_decl); - } - - fn visit_const(&mut self, c: &&'tcx Const<'tcx>, _: Location) { - c.visit_with(self); - } - - fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) { - ty.visit_with(self); - } -} - -impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { - fn tcx_for_anon_const_substs(&self) -> Option> { - Some(self.tcx) - } - #[instrument(skip(self))] - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { - if !c.potentially_has_param_types_or_consts() { - return ControlFlow::CONTINUE; - } - - match c.val { - ty::ConstKind::Param(param) => { - debug!(?param); - self.unused_parameters.clear(param.index); - ControlFlow::CONTINUE - } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: Some(p)}) - // Avoid considering `T` unused when constants are of the form: - // `>::foo::promoted[p]` - if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self => - { - // If there is a promoted, don't look at the substs - since it will always contain - // the generic parameters, instead, traverse the promoted MIR. - let promoted = self.tcx.promoted_mir(def.did); - self.visit_body(&promoted[p]); - ControlFlow::CONTINUE - } - ty::ConstKind::Unevaluated(uv) - if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst => - { - self.visit_child_body(uv.def.did, uv.substs(self.tcx)); - ControlFlow::CONTINUE - } - _ => c.super_visit_with(self), - } - } - - #[instrument(skip(self))] - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.potentially_has_param_types_or_consts() { - return ControlFlow::CONTINUE; - } - - match *ty.kind() { - ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => { - debug!(?def_id); - // Avoid cycle errors with generators. - if def_id == self.def_id { - return ControlFlow::CONTINUE; - } - - // Consider any generic parameters used by any closures/generators as used in the - // parent. - self.visit_child_body(def_id, substs); - ControlFlow::CONTINUE - } - ty::Param(param) => { - debug!(?param); - self.unused_parameters.clear(param.index); - ControlFlow::CONTINUE - } - _ => ty.super_visit_with(self), - } - } -} - -/// Visitor used to check if a generic parameter is used. -struct HasUsedGenericParams<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - unused_parameters: &'a FiniteBitSet, -} - -impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { - type BreakTy = (); - - fn tcx_for_anon_const_substs(&self) -> Option> { - Some(self.tcx) - } - - #[instrument(skip(self))] - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { - if !c.potentially_has_param_types_or_consts() { - return ControlFlow::CONTINUE; - } - - match c.val { - ty::ConstKind::Param(param) => { - if self.unused_parameters.contains(param.index).unwrap_or(false) { - ControlFlow::CONTINUE - } else { - ControlFlow::BREAK - } - } - _ => c.super_visit_with(self), - } - } - - #[instrument(skip(self))] - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if !ty.potentially_has_param_types_or_consts() { - return ControlFlow::CONTINUE; - } - - match ty.kind() { - ty::Param(param) => { - if self.unused_parameters.contains(param.index).unwrap_or(false) { - ControlFlow::CONTINUE - } else { - ControlFlow::BREAK - } - } - _ => ty.super_visit_with(self), - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/util.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/monomorphize/util.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -use rustc_middle::ty::{self, ClosureSizeProfileData, Instance, TyCtxt}; -use std::fs::OpenOptions; -use std::io::prelude::*; - -/// For a given closure, writes out the data for the profiling the impact of RFC 2229 on -/// closure size into a CSV. -/// -/// During the same compile all closures dump the information in the same file -/// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked. -crate fn dump_closure_profile(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) { - let mut file = if let Ok(file) = OpenOptions::new() - .create(true) - .append(true) - .open(&format!("closure_profile_{}.csv", std::process::id())) - { - file - } else { - eprintln!("Cound't open file for writing closure profile"); - return; - }; - - let closure_def_id = closure_instance.def_id(); - let typeck_results = tcx.typeck(closure_def_id.expect_local()); - - if typeck_results.closure_size_eval.contains_key(&closure_def_id) { - let param_env = ty::ParamEnv::reveal_all(); - - let ClosureSizeProfileData { before_feature_tys, after_feature_tys } = - typeck_results.closure_size_eval[&closure_def_id]; - - let before_feature_tys = tcx.subst_and_normalize_erasing_regions( - closure_instance.substs, - param_env, - before_feature_tys, - ); - let after_feature_tys = tcx.subst_and_normalize_erasing_regions( - closure_instance.substs, - param_env, - after_feature_tys, - ); - - let new_size = tcx - .layout_of(param_env.and(after_feature_tys)) - .map(|l| format!("{:?}", l.size.bytes())) - .unwrap_or_else(|e| format!("Failed {:?}", e)); - - let old_size = tcx - .layout_of(param_env.and(before_feature_tys)) - .map(|l| format!("{:?}", l.size.bytes())) - .unwrap_or_else(|e| format!("Failed {:?}", e)); - - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); - let closure_span = tcx.hir().span(closure_hir_id); - let src_file = tcx.sess.source_map().span_to_filename(closure_span); - let line_nos = tcx - .sess - .source_map() - .span_to_lines(closure_span) - .map(|l| format!("{:?} {:?}", l.lines.first(), l.lines.last())) - .unwrap_or_else(|e| format!("{:?}", e)); - - if let Err(e) = writeln!( - file, - "{}, {}, {}, {:?}", - old_size, - new_size, - src_file.prefer_local(), - line_nos - ) { - eprintln!("Error writting to file {}", e.to_string()) - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/shim.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/shim.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/shim.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/shim.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,946 +0,0 @@ -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItem; -use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_target::abi::VariantIdx; - -use rustc_index::vec::{Idx, IndexVec}; - -use rustc_span::Span; -use rustc_target::spec::abi::Abi; - -use std::fmt; -use std::iter; - -use crate::transform::{ - abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads, - run_passes, simplify, -}; -use crate::util::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle}; -use crate::util::expand_aggregate; -use crate::util::patch::MirPatch; - -pub fn provide(providers: &mut Providers) { - providers.mir_shims = make_shim; -} - -fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> { - debug!("make_shim({:?})", instance); - - let mut result = match instance { - ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::VtableShim(def_id) => { - build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id)) - } - ty::InstanceDef::FnPtrShim(def_id, ty) => { - let trait_ = tcx.trait_of_item(def_id).unwrap(); - let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) { - Some(ty::ClosureKind::FnOnce) => Adjustment::Identity, - Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref, - None => bug!("fn pointer {:?} is not an fn", ty), - }; - - build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty)) - } - // We are generating a call back to our def-id, which the - // codegen backend knows to turn to an actual call, be it - // a virtual call, or a direct call to a function for which - // indirect calls must be codegen'd differently than direct ones - // (such as `#[track_caller]`). - ty::InstanceDef::ReifyShim(def_id) => { - build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) - } - ty::InstanceDef::ClosureOnceShim { call_once: _ } => { - let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); - let call_mut = tcx - .associated_items(fn_mut) - .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) - .unwrap() - .def_id; - - build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) - } - ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty), - ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), - ty::InstanceDef::Virtual(..) => { - bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) - } - ty::InstanceDef::Intrinsic(_) => { - bug!("creating shims from intrinsics ({:?}) is unsupported", instance) - } - }; - debug!("make_shim({:?}) = untransformed {:?}", instance, result); - - run_passes( - tcx, - &mut result, - MirPhase::Const, - &[&[ - &add_moves_for_packed_drops::AddMovesForPackedDrops, - &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("make_shim"), - &add_call_guards::CriticalCallEdges, - &abort_unwinding_calls::AbortUnwindingCalls, - ]], - ); - - debug!("make_shim({:?}) = {:?}", instance, result); - - result -} - -#[derive(Copy, Clone, Debug, PartialEq)] -enum Adjustment { - /// Pass the receiver as-is. - Identity, - - /// We get passed `&[mut] self` and call the target with `*self`. - /// - /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it - /// (for `VtableShim`, which effectively is passed `&own Self`). - Deref, - - /// We get passed `self: Self` and call the target with `&mut self`. - /// - /// In this case we need to ensure that the `Self` is dropped after the call, as the callee - /// won't do it for us. - RefMut, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -enum CallKind<'tcx> { - /// Call the `FnPtr` that was passed as the receiver. - Indirect(Ty<'tcx>), - - /// Call a known `FnDef`. - Direct(DefId), -} - -fn local_decls_for_sig<'tcx>( - sig: &ty::FnSig<'tcx>, - span: Span, -) -> IndexVec> { - iter::once(LocalDecl::new(sig.output(), span)) - .chain(sig.inputs().iter().map(|ity| LocalDecl::new(ity, span).immutable())) - .collect() -} - -fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) -> Body<'tcx> { - debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); - - // Check if this is a generator, if so, return the drop glue for it - if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) { - let body = tcx.optimized_mir(gen_def_id).generator_drop().unwrap(); - return body.clone().subst(tcx, substs); - } - - let substs = if let Some(ty) = ty { - tcx.intern_substs(&[ty.into()]) - } else { - InternalSubsts::identity_for_item(tcx, def_id) - }; - let sig = tcx.fn_sig(def_id).subst(tcx, substs); - let sig = tcx.erase_late_bound_regions(sig); - let span = tcx.def_span(def_id); - - let source_info = SourceInfo::outermost(span); - - let return_block = BasicBlock::new(1); - let mut blocks = IndexVec::with_capacity(2); - let block = |blocks: &mut IndexVec<_, _>, kind| { - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info, kind }), - is_cleanup: false, - }) - }; - block(&mut blocks, TerminatorKind::Goto { target: return_block }); - block(&mut blocks, TerminatorKind::Return); - - let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty)); - let mut body = - new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); - - if ty.is_some() { - // The first argument (index 0), but add 1 for the return value. - let dropee_ptr = Place::from(Local::new(1 + 0)); - if tcx.sess.opts.debugging_opts.mir_emit_retag { - // Function arguments should be retagged, and we make this one raw. - body.basic_blocks_mut()[START_BLOCK].statements.insert( - 0, - Statement { - source_info, - kind: StatementKind::Retag(RetagKind::Raw, Box::new(dropee_ptr)), - }, - ); - } - let patch = { - let param_env = tcx.param_env_reveal_all_normalized(def_id); - let mut elaborator = - DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env }; - let dropee = tcx.mk_place_deref(dropee_ptr); - let resume_block = elaborator.patch.resume_block(); - elaborate_drops::elaborate_drop( - &mut elaborator, - source_info, - dropee, - (), - return_block, - elaborate_drops::Unwind::To(resume_block), - START_BLOCK, - ); - elaborator.patch - }; - patch.apply(&mut body); - } - - body -} - -fn new_body<'tcx>( - tcx: TyCtxt<'tcx>, - source: MirSource<'tcx>, - basic_blocks: IndexVec>, - local_decls: IndexVec>, - arg_count: usize, - span: Span, -) -> Body<'tcx> { - Body::new( - tcx, - source, - basic_blocks, - IndexVec::from_elem_n( - SourceScopeData { - span, - parent_scope: None, - inlined: None, - inlined_parent_scope: None, - local_data: ClearCrossCrate::Clear, - }, - 1, - ), - local_decls, - IndexVec::new(), - arg_count, - vec![], - span, - None, - ) -} - -pub struct DropShimElaborator<'a, 'tcx> { - pub body: &'a Body<'tcx>, - pub patch: MirPatch<'tcx>, - pub tcx: TyCtxt<'tcx>, - pub param_env: ty::ParamEnv<'tcx>, -} - -impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - Ok(()) - } -} - -impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { - type Path = (); - - fn patch(&mut self) -> &mut MirPatch<'tcx> { - &mut self.patch - } - fn body(&self) -> &'a Body<'tcx> { - self.body - } - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle { - match mode { - DropFlagMode::Shallow => { - // Drops for the contained fields are "shallow" and "static" - they will simply call - // the field's own drop glue. - DropStyle::Static - } - DropFlagMode::Deep => { - // The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder - // dropping each field contained in the value. - DropStyle::Open - } - } - } - - fn get_drop_flag(&mut self, _path: Self::Path) -> Option> { - None - } - - fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {} - - fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option { - None - } - fn deref_subpath(&self, _path: Self::Path) -> Option { - None - } - fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option { - Some(()) - } - fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option { - None - } -} - -/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`. -fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> { - debug!("build_clone_shim(def_id={:?})", def_id); - - let param_env = tcx.param_env(def_id); - - let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty); - let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env); - - let dest = Place::return_place(); - let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0))); - - match self_ty.kind() { - _ if is_copy => builder.copy_shim(), - ty::Array(ty, len) => builder.array_shim(dest, src, ty, len), - ty::Closure(_, substs) => { - builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys()) - } - ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()), - _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty), - }; - - builder.into_mir() -} - -struct CloneShimBuilder<'tcx> { - tcx: TyCtxt<'tcx>, - def_id: DefId, - local_decls: IndexVec>, - blocks: IndexVec>, - span: Span, - sig: ty::FnSig<'tcx>, -} - -impl CloneShimBuilder<'tcx> { - fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self { - // we must subst the self_ty because it's - // otherwise going to be TySelf and we can't index - // or access fields of a Place of type TySelf. - let substs = tcx.mk_substs_trait(self_ty, &[]); - let sig = tcx.fn_sig(def_id).subst(tcx, substs); - let sig = tcx.erase_late_bound_regions(sig); - let span = tcx.def_span(def_id); - - CloneShimBuilder { - tcx, - def_id, - local_decls: local_decls_for_sig(&sig, span), - blocks: IndexVec::new(), - span, - sig, - } - } - - fn into_mir(self) -> Body<'tcx> { - let source = MirSource::from_instance(ty::InstanceDef::CloneShim( - self.def_id, - self.sig.inputs_and_output[0], - )); - new_body( - self.tcx, - source, - self.blocks, - self.local_decls, - self.sig.inputs().len(), - self.span, - ) - } - - fn source_info(&self) -> SourceInfo { - SourceInfo::outermost(self.span) - } - - fn block( - &mut self, - statements: Vec>, - kind: TerminatorKind<'tcx>, - is_cleanup: bool, - ) -> BasicBlock { - let source_info = self.source_info(); - self.blocks.push(BasicBlockData { - statements, - terminator: Some(Terminator { source_info, kind }), - is_cleanup, - }) - } - - /// Gives the index of an upcoming BasicBlock, with an offset. - /// offset=0 will give you the index of the next BasicBlock, - /// offset=1 will give the index of the next-to-next block, - /// offset=-1 will give you the index of the last-created block - fn block_index_offset(&mut self, offset: usize) -> BasicBlock { - BasicBlock::new(self.blocks.len() + offset) - } - - fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> { - Statement { source_info: self.source_info(), kind } - } - - fn copy_shim(&mut self) { - let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1 + 0))); - let ret_statement = self.make_statement(StatementKind::Assign(Box::new(( - Place::return_place(), - Rvalue::Use(Operand::Copy(rcvr)), - )))); - self.block(vec![ret_statement], TerminatorKind::Return, false); - } - - fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> { - let span = self.span; - let mut local = LocalDecl::new(ty, span); - if mutability == Mutability::Not { - local = local.immutable(); - } - Place::from(self.local_decls.push(local)) - } - - fn make_clone_call( - &mut self, - dest: Place<'tcx>, - src: Place<'tcx>, - ty: Ty<'tcx>, - next: BasicBlock, - cleanup: BasicBlock, - ) { - let tcx = self.tcx; - - let substs = tcx.mk_substs_trait(ty, &[]); - - // `func == Clone::clone(&ty) -> ty` - let func_ty = tcx.mk_fn_def(self.def_id, substs); - let func = Operand::Constant(Box::new(Constant { - span: self.span, - user_ty: None, - literal: ty::Const::zero_sized(tcx, func_ty).into(), - })); - - let ref_loc = self.make_place( - Mutability::Not, - tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }), - ); - - // `let ref_loc: &ty = &src;` - let statement = self.make_statement(StatementKind::Assign(Box::new(( - ref_loc, - Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src), - )))); - - // `let loc = Clone::clone(ref_loc);` - self.block( - vec![statement], - TerminatorKind::Call { - func, - args: vec![Operand::Move(ref_loc)], - destination: Some((dest, next)), - cleanup: Some(cleanup), - from_hir_call: true, - fn_span: self.span, - }, - false, - ); - } - - fn loop_header( - &mut self, - beg: Place<'tcx>, - end: Place<'tcx>, - loop_body: BasicBlock, - loop_end: BasicBlock, - is_cleanup: bool, - ) { - let tcx = self.tcx; - - let cond = self.make_place(Mutability::Mut, tcx.types.bool); - let compute_cond = self.make_statement(StatementKind::Assign(Box::new(( - cond, - Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))), - )))); - - // `if end != beg { goto loop_body; } else { goto loop_end; }` - self.block( - vec![compute_cond], - TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end), - is_cleanup, - ); - } - - fn make_usize(&self, value: u64) -> Box> { - Box::new(Constant { - span: self.span, - user_ty: None, - literal: ty::Const::from_usize(self.tcx, value).into(), - }) - } - - fn array_shim( - &mut self, - dest: Place<'tcx>, - src: Place<'tcx>, - ty: Ty<'tcx>, - len: &'tcx ty::Const<'tcx>, - ) { - let tcx = self.tcx; - let span = self.span; - - let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span)); - let end = self.make_place(Mutability::Not, tcx.types.usize); - - // BB #0 - // `let mut beg = 0;` - // `let end = len;` - // `goto #1;` - let inits = vec![ - self.make_statement(StatementKind::Assign(Box::new(( - Place::from(beg), - Rvalue::Use(Operand::Constant(self.make_usize(0))), - )))), - self.make_statement(StatementKind::Assign(Box::new(( - end, - Rvalue::Use(Operand::Constant(Box::new(Constant { - span: self.span, - user_ty: None, - literal: len.into(), - }))), - )))), - ]; - self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false); - - // BB #1: loop { - // BB #2; - // BB #3; - // } - // BB #4; - self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false); - - // BB #2 - // `dest[i] = Clone::clone(src[beg])`; - // Goto #3 if ok, #5 if unwinding happens. - let dest_field = self.tcx.mk_place_index(dest, beg); - let src_field = self.tcx.mk_place_index(src, beg); - self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5)); - - // BB #3 - // `beg = beg + 1;` - // `goto #1`; - let statements = vec![self.make_statement(StatementKind::Assign(Box::new(( - Place::from(beg), - Rvalue::BinaryOp( - BinOp::Add, - Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))), - ), - ))))]; - self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false); - - // BB #4 - // `return dest;` - self.block(vec![], TerminatorKind::Return, false); - - // BB #5 (cleanup) - // `let end = beg;` - // `let mut beg = 0;` - // goto #6; - let end = beg; - let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span)); - let init = self.make_statement(StatementKind::Assign(Box::new(( - Place::from(beg), - Rvalue::Use(Operand::Constant(self.make_usize(0))), - )))); - self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); - - // BB #6 (cleanup): loop { - // BB #7; - // BB #8; - // } - // BB #9; - self.loop_header( - Place::from(beg), - Place::from(end), - BasicBlock::new(7), - BasicBlock::new(9), - true, - ); - - // BB #7 (cleanup) - // `drop(dest[beg])`; - self.block( - vec![], - TerminatorKind::Drop { - place: self.tcx.mk_place_index(dest, beg), - target: BasicBlock::new(8), - unwind: None, - }, - true, - ); - - // BB #8 (cleanup) - // `beg = beg + 1;` - // `goto #6;` - let statement = self.make_statement(StatementKind::Assign(Box::new(( - Place::from(beg), - Rvalue::BinaryOp( - BinOp::Add, - Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))), - ), - )))); - self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); - - // BB #9 (resume) - self.block(vec![], TerminatorKind::Resume, true); - } - - fn tuple_like_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I) - where - I: Iterator>, - { - let mut previous_field = None; - for (i, ity) in tys.enumerate() { - let field = Field::new(i); - let src_field = self.tcx.mk_place_field(src, field, ity); - - let dest_field = self.tcx.mk_place_field(dest, field, ity); - - // #(2i + 1) is the cleanup block for the previous clone operation - let cleanup_block = self.block_index_offset(1); - // #(2i + 2) is the next cloning block - // (or the Return terminator if this is the last block) - let next_block = self.block_index_offset(2); - - // BB #(2i) - // `dest.i = Clone::clone(&src.i);` - // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens. - self.make_clone_call(dest_field, src_field, ity, next_block, cleanup_block); - - // BB #(2i + 1) (cleanup) - if let Some((previous_field, previous_cleanup)) = previous_field.take() { - // Drop previous field and goto previous cleanup block. - self.block( - vec![], - TerminatorKind::Drop { - place: previous_field, - target: previous_cleanup, - unwind: None, - }, - true, - ); - } else { - // Nothing to drop, just resume. - self.block(vec![], TerminatorKind::Resume, true); - } - - previous_field = Some((dest_field, cleanup_block)); - } - - self.block(vec![], TerminatorKind::Return, false); - } -} - -/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`, -/// first adjusting its first argument according to `rcvr_adjustment`. -fn build_call_shim<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, - rcvr_adjustment: Option, - call_kind: CallKind<'tcx>, -) -> Body<'tcx> { - debug!( - "build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})", - instance, rcvr_adjustment, call_kind - ); - - // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used - // to substitute into the signature of the shim. It is not necessary for users of this - // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`). - let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { - let sig = tcx.erase_late_bound_regions(ty.fn_sig(tcx)); - - let untuple_args = sig.inputs(); - - // Create substitutions for the `Self` and `Args` generic parameters of the shim body. - let arg_tup = tcx.mk_tup(untuple_args.iter()); - let sig_substs = tcx.mk_substs_trait(ty, &[ty::subst::GenericArg::from(arg_tup)]); - - (Some(sig_substs), Some(untuple_args)) - } else { - (None, None) - }; - - let def_id = instance.def_id(); - let sig = tcx.fn_sig(def_id); - let mut sig = tcx.erase_late_bound_regions(sig); - - assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); - if let Some(sig_substs) = sig_substs { - sig = sig.subst(tcx, sig_substs); - } - - if let CallKind::Indirect(fnty) = call_kind { - // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This - // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from - // the implemented `FnX` trait. - - // Apply the opposite adjustment to the MIR input. - let mut inputs_and_output = sig.inputs_and_output.to_vec(); - - // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the - // fn arguments. `Self` may be passed via (im)mutable reference or by-value. - assert_eq!(inputs_and_output.len(), 3); - - // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for - // `FnDef` and `FnPtr` callees, not the `Self` type param. - let self_arg = &mut inputs_and_output[0]; - *self_arg = match rcvr_adjustment.unwrap() { - Adjustment::Identity => fnty, - Adjustment::Deref => tcx.mk_imm_ptr(fnty), - Adjustment::RefMut => tcx.mk_mut_ptr(fnty), - }; - sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); - } - - // FIXME(eddyb) avoid having this snippet both here and in - // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). - if let ty::InstanceDef::VtableShim(..) = instance { - // Modify fn(self, ...) to fn(self: *mut Self, ...) - let mut inputs_and_output = sig.inputs_and_output.to_vec(); - let self_arg = &mut inputs_and_output[0]; - debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param); - *self_arg = tcx.mk_mut_ptr(*self_arg); - sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); - } - - let span = tcx.def_span(def_id); - - debug!("build_call_shim: sig={:?}", sig); - - let mut local_decls = local_decls_for_sig(&sig, span); - let source_info = SourceInfo::outermost(span); - - let rcvr_place = || { - assert!(rcvr_adjustment.is_some()); - Place::from(Local::new(1 + 0)) - }; - let mut statements = vec![]; - - let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment { - Adjustment::Identity => Operand::Move(rcvr_place()), - Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), - Adjustment::RefMut => { - // let rcvr = &mut rcvr; - let ref_rcvr = local_decls.push( - LocalDecl::new( - tcx.mk_ref( - tcx.lifetimes.re_erased, - ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut }, - ), - span, - ) - .immutable(), - ); - let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false }; - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(ref_rcvr), - Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()), - ))), - }); - Operand::Move(Place::from(ref_rcvr)) - } - }); - - let (callee, mut args) = match call_kind { - // `FnPtr` call has no receiver. Args are untupled below. - CallKind::Indirect(_) => (rcvr.unwrap(), vec![]), - - // `FnDef` call with optional receiver. - CallKind::Direct(def_id) => { - let ty = tcx.type_of(def_id); - ( - Operand::Constant(Box::new(Constant { - span, - user_ty: None, - literal: ty::Const::zero_sized(tcx, ty).into(), - })), - rcvr.into_iter().collect::>(), - ) - } - }; - - let mut arg_range = 0..sig.inputs().len(); - - // Take the `self` ("receiver") argument out of the range (it's adjusted above). - if rcvr_adjustment.is_some() { - arg_range.start += 1; - } - - // Take the last argument, if we need to untuple it (handled below). - if untuple_args.is_some() { - arg_range.end -= 1; - } - - // Pass all of the non-special arguments directly. - args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i))))); - - // Untuple the last argument, if we have to. - if let Some(untuple_args) = untuple_args { - let tuple_arg = Local::new(1 + (sig.inputs().len() - 1)); - args.extend(untuple_args.iter().enumerate().map(|(i, ity)| { - Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), Field::new(i), *ity)) - })); - } - - let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 }; - let mut blocks = IndexVec::with_capacity(n_blocks); - let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { - blocks.push(BasicBlockData { - statements, - terminator: Some(Terminator { source_info, kind }), - is_cleanup, - }) - }; - - // BB #0 - block( - &mut blocks, - statements, - TerminatorKind::Call { - func: callee, - args, - destination: Some((Place::return_place(), BasicBlock::new(1))), - cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment { - Some(BasicBlock::new(3)) - } else { - None - }, - from_hir_call: true, - fn_span: span, - }, - false, - ); - - if let Some(Adjustment::RefMut) = rcvr_adjustment { - // BB #1 - drop for Self - block( - &mut blocks, - vec![], - TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None }, - false, - ); - } - // BB #1/#2 - return - block(&mut blocks, vec![], TerminatorKind::Return, false); - if let Some(Adjustment::RefMut) = rcvr_adjustment { - // BB #3 - drop if closure panics - block( - &mut blocks, - vec![], - TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None }, - true, - ); - - // BB #4 - resume - block(&mut blocks, vec![], TerminatorKind::Resume, true); - } - - let mut body = new_body( - tcx, - MirSource::from_instance(instance), - blocks, - local_decls, - sig.inputs().len(), - span, - ); - - if let Abi::RustCall = sig.abi { - body.spread_arg = Some(Local::new(sig.inputs().len())); - } - - body -} - -pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { - debug_assert!(tcx.is_constructor(ctor_id)); - - let span = - tcx.hir().span_if_local(ctor_id).unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id)); - - let param_env = tcx.param_env(ctor_id); - - // Normalize the sig. - let sig = tcx.fn_sig(ctor_id).no_bound_vars().expect("LBR in ADT constructor signature"); - let sig = tcx.normalize_erasing_regions(param_env, sig); - - let (adt_def, substs) = match sig.output().kind() { - ty::Adt(adt_def, substs) => (adt_def, substs), - _ => bug!("unexpected type for ADT ctor {:?}", sig.output()), - }; - - debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig); - - let local_decls = local_decls_for_sig(&sig, span); - - let source_info = SourceInfo::outermost(span); - - let variant_index = if adt_def.is_enum() { - adt_def.variant_index_with_ctor_id(ctor_id) - } else { - VariantIdx::new(0) - }; - - // Generate the following MIR: - // - // (return as Variant).field0 = arg0; - // (return as Variant).field1 = arg1; - // - // return; - debug!("build_ctor: variant_index={:?}", variant_index); - - let statements = expand_aggregate( - Place::return_place(), - adt_def.variants[variant_index].fields.iter().enumerate().map(|(idx, field_def)| { - (Operand::Move(Place::from(Local::new(idx + 1))), field_def.ty(tcx, substs)) - }), - AggregateKind::Adt(adt_def, variant_index, substs, None, None), - source_info, - tcx, - ) - .collect(); - - let start_block = BasicBlockData { - statements, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }; - - let source = MirSource::item(ctor_id); - let body = new_body( - tcx, - source, - IndexVec::from_elem_n(start_block, 1), - local_decls, - sig.inputs().len(), - span, - ); - - crate::util::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); - - body -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -use crate::transform::MirPass; -use rustc_hir::def::DefKind; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::*; -use rustc_middle::ty::layout; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::spec::abi::Abi; - -/// A pass that runs which is targeted at ensuring that codegen guarantees about -/// unwinding are upheld for compilations of panic=abort programs. -/// -/// When compiling with panic=abort codegen backends generally want to assume -/// that all Rust-defined functions do not unwind, and it's UB if they actually -/// do unwind. Foreign functions, however, can be declared as "may unwind" via -/// their ABI (e.g. `extern "C-unwind"`). To uphold the guarantees that -/// Rust-defined functions never unwind a well-behaved Rust program needs to -/// catch unwinding from foreign functions and force them to abort. -/// -/// This pass walks over all functions calls which may possibly unwind, -/// and if any are found sets their cleanup to a block that aborts the process. -/// This forces all unwinds, in panic=abort mode happening in foreign code, to -/// trigger a process abort. -#[derive(PartialEq)] -pub struct AbortUnwindingCalls; - -impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let def_id = body.source.def_id(); - let kind = tcx.def_kind(def_id); - - // We don't simplify the MIR of constants at this time because that - // namely results in a cyclic query when we call `tcx.type_of` below. - let is_function = match kind { - DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, - _ => tcx.is_closure(def_id), - }; - if !is_function { - return; - } - - // This pass only runs on functions which themselves cannot unwind, - // forcibly changing the body of the function to structurally provide - // this guarantee by aborting on an unwind. If this function can unwind, - // then there's nothing to do because it already should work correctly. - // - // Here we test for this function itself whether its ABI allows - // unwinding or not. - let body_flags = tcx.codegen_fn_attrs(def_id).flags; - let body_ty = tcx.type_of(def_id); - let body_abi = match body_ty.kind() { - ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), - ty::Closure(..) => Abi::RustCall, - ty::Generator(..) => Abi::Rust, - _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), - }; - let body_can_unwind = layout::fn_can_unwind(tcx, body_flags, body_abi); - - // Look in this function body for any basic blocks which are terminated - // with a function call, and whose function we're calling may unwind. - // This will filter to functions with `extern "C-unwind"` ABIs, for - // example. - let mut calls_to_terminate = Vec::new(); - let mut cleanups_to_remove = Vec::new(); - for (id, block) in body.basic_blocks().iter_enumerated() { - if block.is_cleanup { - continue; - } - let terminator = match &block.terminator { - Some(terminator) => terminator, - None => continue, - }; - let span = terminator.source_info.span; - - let call_can_unwind = match &terminator.kind { - TerminatorKind::Call { func, .. } => { - let ty = func.ty(body, tcx); - let sig = ty.fn_sig(tcx); - let flags = match ty.kind() { - ty::FnPtr(_) => CodegenFnAttrFlags::empty(), - ty::FnDef(def_id, _) => tcx.codegen_fn_attrs(*def_id).flags, - _ => span_bug!(span, "invalid callee of type {:?}", ty), - }; - layout::fn_can_unwind(tcx, flags, sig.abi()) - } - TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::FalseUnwind { .. } => { - layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust) - } - _ => continue, - }; - - // If this function call can't unwind, then there's no need for it - // to have a landing pad. This means that we can remove any cleanup - // registered for it. - if !call_can_unwind { - cleanups_to_remove.push(id); - continue; - } - - // Otherwise if this function can unwind, then if the outer function - // can also unwind there's nothing to do. If the outer function - // can't unwind, however, we need to change the landing pad for this - // function call to one that aborts. - if !body_can_unwind { - calls_to_terminate.push(id); - } - } - - // For call instructions which need to be terminated, we insert a - // singular basic block which simply terminates, and then configure the - // `cleanup` attribute for all calls we found to this basic block we - // insert which means that any unwinding that happens in the functions - // will force an abort of the process. - if !calls_to_terminate.is_empty() { - let bb = BasicBlockData { - statements: Vec::new(), - is_cleanup: true, - terminator: Some(Terminator { - source_info: SourceInfo::outermost(body.span), - kind: TerminatorKind::Abort, - }), - }; - let abort_bb = body.basic_blocks_mut().push(bb); - - for bb in calls_to_terminate { - let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap(); - *cleanup = Some(abort_bb); - } - } - - for id in cleanups_to_remove { - let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap(); - *cleanup = None; - } - - // We may have invalidated some `cleanup` blocks so clean those up now. - super::simplify::remove_dead_blocks(tcx, body); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_call_guards.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_call_guards.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_call_guards.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_call_guards.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -use crate::transform::MirPass; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -#[derive(PartialEq)] -pub enum AddCallGuards { - AllCallEdges, - CriticalCallEdges, -} -pub use self::AddCallGuards::*; - -/** - * Breaks outgoing critical edges for call terminators in the MIR. - * - * Critical edges are edges that are neither the only edge leaving a - * block, nor the only edge entering one. - * - * When you want something to happen "along" an edge, you can either - * do at the end of the predecessor block, or at the start of the - * successor block. Critical edges have to be broken in order to prevent - * "edge actions" from affecting other edges. We need this for calls that are - * codegened to LLVM invoke instructions, because invoke is a block terminator - * in LLVM so we can't insert any code to handle the call's result into the - * block that performs the call. - * - * This function will break those edges by inserting new blocks along them. - * - * NOTE: Simplify CFG will happily undo most of the work this pass does. - * - */ - -impl<'tcx> MirPass<'tcx> for AddCallGuards { - fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - self.add_call_guards(body); - } -} - -impl AddCallGuards { - pub fn add_call_guards(&self, body: &mut Body<'_>) { - let mut pred_count: IndexVec<_, _> = - body.predecessors().iter().map(|ps| ps.len()).collect(); - pred_count[START_BLOCK] += 1; - - // We need a place to store the new blocks generated - let mut new_blocks = Vec::new(); - - let cur_len = body.basic_blocks().len(); - - for block in body.basic_blocks_mut() { - match block.terminator { - Some(Terminator { - kind: - TerminatorKind::Call { - destination: Some((_, ref mut destination)), - cleanup, - .. - }, - source_info, - }) if pred_count[*destination] > 1 - && (cleanup.is_some() || self == &AllCallEdges) => - { - // It's a critical edge, break it - let call_guard = BasicBlockData { - statements: vec![], - is_cleanup: block.is_cleanup, - terminator: Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target: *destination }, - }), - }; - - // Get the index it will be when inserted into the MIR - let idx = cur_len + new_blocks.len(); - new_blocks.push(call_guard); - *destination = BasicBlock::new(idx); - } - _ => {} - } - } - - debug!("Broke {} N edges", new_blocks.len()); - - body.basic_blocks_mut().extend(new_blocks); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -use crate::transform::MirPass; -use crate::util; -use crate::util::patch::MirPatch; - -// This pass moves values being dropped that are within a packed -// struct to a separate local before dropping them, to ensure that -// they are dropped from an aligned address. -// -// For example, if we have something like -// ```Rust -// #[repr(packed)] -// struct Foo { -// dealign: u8, -// data: Vec -// } -// -// let foo = ...; -// ``` -// -// We want to call `drop_in_place::>` on `data` from an aligned -// address. This means we can't simply drop `foo.data` directly, because -// its address is not aligned. -// -// Instead, we move `foo.data` to a local and drop that: -// ``` -// storage.live(drop_temp) -// drop_temp = foo.data; -// drop(drop_temp) -> next -// next: -// storage.dead(drop_temp) -// ``` -// -// The storage instructions are required to avoid stack space -// blowup. - -pub struct AddMovesForPackedDrops; - -impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span); - add_moves_for_packed_drops(tcx, body); - } -} - -pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let patch = add_moves_for_packed_drops_patch(tcx, body); - patch.apply(body); -} - -fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> MirPatch<'tcx> { - let def_id = body.source.def_id(); - let mut patch = MirPatch::new(body); - let param_env = tcx.param_env(def_id); - - for (bb, data) in body.basic_blocks().iter_enumerated() { - let loc = Location { block: bb, statement_index: data.statements.len() }; - let terminator = data.terminator(); - - match terminator.kind { - TerminatorKind::Drop { place, .. } - if util::is_disaligned(tcx, body, param_env, place) => - { - add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup); - } - TerminatorKind::DropAndReplace { .. } => { - span_bug!(terminator.source_info.span, "replace in AddMovesForPackedDrops"); - } - _ => {} - } - } - - patch -} - -fn add_move_for_packed_drop<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - patch: &mut MirPatch<'tcx>, - terminator: &Terminator<'tcx>, - loc: Location, - is_cleanup: bool, -) { - debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc); - let (place, target, unwind) = match terminator.kind { - TerminatorKind::Drop { ref place, target, unwind } => (place, target, unwind), - _ => unreachable!(), - }; - - let source_info = terminator.source_info; - let ty = place.ty(body, tcx).ty; - let temp = patch.new_temp(ty, terminator.source_info.span); - - let storage_dead_block = patch.new_block(BasicBlockData { - statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), - is_cleanup, - }); - - patch.add_statement(loc, StatementKind::StorageLive(temp)); - patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); - patch.patch_terminator( - loc.block, - TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind }, - ); -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_retag.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_retag.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_retag.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/add_retag.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,186 +0,0 @@ -//! This pass adds validation calls (AcquireValid, ReleaseValid) where appropriate. -//! It has to be run really early, before transformations like inlining, because -//! introducing these calls *adds* UB -- so, conceptually, this pass is actually part -//! of MIR building, and only after this pass we think of the program has having the -//! normal MIR semantics. - -use crate::transform::MirPass; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, Ty, TyCtxt}; - -pub struct AddRetag; - -/// Determines whether this place is "stable": Whether, if we evaluate it again -/// after the assignment, we can be sure to obtain the same place value. -/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic -/// copies. Data races are UB.) -fn is_stable(place: PlaceRef<'_>) -> bool { - place.projection.iter().all(|elem| { - match elem { - // Which place this evaluates to can change with any memory write, - // so cannot assume this to be stable. - ProjectionElem::Deref => false, - // Array indices are interesting, but MIR building generates a *fresh* - // temporary for every array access, so the index cannot be changed as - // a side-effect. - ProjectionElem::Index { .. } | - // The rest is completely boring, they just offset by a constant. - ProjectionElem::Field { .. } | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Subslice { .. } | - ProjectionElem::Downcast { .. } => true, - } - }) -} - -/// Determine whether this type may be a reference (or box), and thus needs retagging. -fn may_be_reference(ty: Ty<'tcx>) -> bool { - match ty.kind() { - // Primitive types that are not references - ty::Bool - | ty::Char - | ty::Float(_) - | ty::Int(_) - | ty::Uint(_) - | ty::RawPtr(..) - | ty::FnPtr(..) - | ty::Str - | ty::FnDef(..) - | ty::Never => false, - // References - ty::Ref(..) => true, - ty::Adt(..) if ty.is_box() => true, - // Compound types are not references - ty::Array(..) | ty::Slice(..) | ty::Tuple(..) | ty::Adt(..) => false, - // Conservative fallback - _ => true, - } -} - -impl<'tcx> MirPass<'tcx> for AddRetag { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if !tcx.sess.opts.debugging_opts.mir_emit_retag { - return; - } - - // We need an `AllCallEdges` pass before we can do any work. - super::add_call_guards::AllCallEdges.run_pass(tcx, body); - - let (span, arg_count) = (body.span, body.arg_count); - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - let needs_retag = |place: &Place<'tcx>| { - // FIXME: Instead of giving up for unstable places, we should introduce - // a temporary and retag on that. - is_stable(place.as_ref()) && may_be_reference(place.ty(&*local_decls, tcx).ty) - }; - let place_base_raw = |place: &Place<'tcx>| { - // If this is a `Deref`, get the type of what we are deref'ing. - let deref_base = - place.projection.iter().rposition(|p| matches!(p, ProjectionElem::Deref)); - if let Some(deref_base) = deref_base { - let base_proj = &place.projection[..deref_base]; - let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty; - ty.is_unsafe_ptr() - } else { - // Not a deref, and thus not raw. - false - } - }; - - // PART 1 - // Retag arguments at the beginning of the start block. - { - // FIXME: Consider using just the span covering the function - // argument declaration. - let source_info = SourceInfo::outermost(span); - // Gather all arguments, skip return value. - let places = local_decls - .iter_enumerated() - .skip(1) - .take(arg_count) - .map(|(local, _)| Place::from(local)) - .filter(needs_retag); - // Emit their retags. - basic_blocks[START_BLOCK].statements.splice( - 0..0, - places.map(|place| Statement { - source_info, - kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)), - }), - ); - } - - // PART 2 - // Retag return values of functions. Also escape-to-raw the argument of `drop`. - // We collect the return destinations because we cannot mutate while iterating. - let returns = basic_blocks - .iter_mut() - .filter_map(|block_data| { - match block_data.terminator().kind { - TerminatorKind::Call { destination: Some(ref destination), .. } - if needs_retag(&destination.0) => - { - // Remember the return destination for later - Some((block_data.terminator().source_info, destination.0, destination.1)) - } - - // `Drop` is also a call, but it doesn't return anything so we are good. - TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => None, - // Not a block ending in a Call -> ignore. - _ => None, - } - }) - .collect::>(); - // Now we go over the returns we collected to retag the return values. - for (source_info, dest_place, dest_block) in returns { - basic_blocks[dest_block].statements.insert( - 0, - Statement { - source_info, - kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)), - }, - ); - } - - // PART 3 - // Add retag after assignment. - for block_data in basic_blocks { - // We want to insert statements as we iterate. To this end, we - // iterate backwards using indices. - for i in (0..block_data.statements.len()).rev() { - let (retag_kind, place) = match block_data.statements[i].kind { - // Retag-as-raw after escaping to a raw pointer, if the referent - // is not already a raw pointer. - StatementKind::Assign(box (lplace, Rvalue::AddressOf(_, ref rplace))) - if !place_base_raw(rplace) => - { - (RetagKind::Raw, lplace) - } - // Retag after assignments of reference type. - StatementKind::Assign(box (ref place, ref rvalue)) if needs_retag(place) => { - let kind = match rvalue { - Rvalue::Ref(_, borrow_kind, _) - if borrow_kind.allows_two_phase_borrow() => - { - RetagKind::TwoPhase - } - _ => RetagKind::Default, - }; - (kind, *place) - } - // Do nothing for the rest - _ => continue, - }; - // Insert a retag after the statement. - let source_info = block_data.statements[i].source_info; - block_data.statements.insert( - i + 1, - Statement { - source_info, - kind: StatementKind::Retag(retag_kind, Box::new(place)), - }, - ); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_const_item_mutation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_const_item_mutation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_const_item_mutation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_const_item_mutation.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -use rustc_errors::DiagnosticBuilder; -use rustc_middle::lint::LintDiagnosticBuilder; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; -use rustc_session::lint::builtin::CONST_ITEM_MUTATION; -use rustc_span::def_id::DefId; - -use crate::transform::MirPass; - -pub struct CheckConstItemMutation; - -impl<'tcx> MirPass<'tcx> for CheckConstItemMutation { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mut checker = ConstMutationChecker { body, tcx, target_local: None }; - checker.visit_body(&body); - } -} - -struct ConstMutationChecker<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, - target_local: Option, -} - -impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { - fn is_const_item(&self, local: Local) -> Option { - if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info { - Some(def_id) - } else { - None - } - } - - fn is_const_item_without_destructor(&self, local: Local) -> Option { - let def_id = self.is_const_item(local)?; - - // We avoid linting mutation of a const item if the const's type has a - // Drop impl. The Drop logic observes the mutation which was performed. - // - // pub struct Log { msg: &'static str } - // pub const LOG: Log = Log { msg: "" }; - // impl Drop for Log { - // fn drop(&mut self) { println!("{}", self.msg); } - // } - // - // LOG.msg = "wow"; // prints "wow" - // - // FIXME(https://github.com/rust-lang/rust/issues/77425): - // Drop this exception once there is a stable attribute to suppress the - // const item mutation lint for a single specific const only. Something - // equivalent to: - // - // #[const_mutation_allowed] - // pub const LOG: Log = Log { msg: "" }; - match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) { - Some(_) => None, - None => Some(def_id), - } - } - - fn lint_const_item_usage( - &self, - place: &Place<'tcx>, - const_item: DefId, - location: Location, - decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>, - ) { - // Don't lint on borrowing/assigning when a dereference is involved. - // If we 'leave' the temporary via a dereference, we must - // be modifying something else - // - // `unsafe { *FOO = 0; *BAR.field = 1; }` - // `unsafe { &mut *FOO }` - // `unsafe { (*ARRAY)[0] = val; } - if !place.projection.iter().any(|p| matches!(p, PlaceElem::Deref)) { - let source_info = self.body.source_info(location); - let lint_root = self.body.source_scopes[source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; - - self.tcx.struct_span_lint_hir( - CONST_ITEM_MUTATION, - lint_root, - source_info.span, - |lint| { - decorate(lint) - .span_note(self.tcx.def_span(const_item), "`const` item defined here") - .emit() - }, - ); - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { - fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) { - if let StatementKind::Assign(box (lhs, _)) = &stmt.kind { - // Check for assignment to fields of a constant - // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error, - // so emitting a lint would be redundant. - if !lhs.projection.is_empty() { - if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) { - self.lint_const_item_usage(&lhs, def_id, loc, |lint| { - let mut lint = lint.build("attempting to modify a `const` item"); - lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified"); - lint - }) - } - } - // We are looking for MIR of the form: - // - // ``` - // _1 = const FOO; - // _2 = &mut _1; - // method_call(_2, ..) - // ``` - // - // Record our current LHS, so that we can detect this - // pattern in `visit_rvalue` - self.target_local = lhs.as_local(); - } - self.super_statement(stmt, loc); - self.target_local = None; - } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { - if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue { - let local = place.local; - if let Some(def_id) = self.is_const_item(local) { - // If this Rvalue is being used as the right-hand side of a - // `StatementKind::Assign`, see if it ends up getting used as - // the `self` parameter of a method call (as the terminator of our current - // BasicBlock). If so, we emit a more specific lint. - let method_did = self.target_local.and_then(|target_local| { - crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block) - }); - let lint_loc = - if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc }; - self.lint_const_item_usage(place, def_id, lint_loc, |lint| { - let mut lint = lint.build("taking a mutable reference to a `const` item"); - lint - .note("each usage of a `const` item creates a new temporary") - .note("the mutable reference will refer to this temporary, not the original `const` item"); - - if let Some((method_did, _substs)) = method_did { - lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method"); - } - - lint - }); - } - } - self.super_rvalue(rvalue, loc); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/check.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/check.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/check.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/check.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1110 +0,0 @@ -//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. - -use rustc_errors::{Applicability, Diagnostic, ErrorReported}; -use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, HirId, LangItem}; -use rustc_index::bit_set::BitSet; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; -use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; -use rustc_middle::ty::{Binder, TraitPredicate, TraitRef}; -use rustc_span::{sym, Span, Symbol}; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt; -use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine}; - -use std::mem; -use std::ops::Deref; - -use super::ops::{self, NonConstOp, Status}; -use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop}; -use super::resolver::FlowSensitiveAnalysis; -use super::{is_lang_panic_fn, ConstCx, Qualif}; -use crate::const_eval::is_unstable_const_fn; -use crate::dataflow::impls::MaybeMutBorrowedLocals; -use crate::dataflow::{self, Analysis}; - -// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated -// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals` -// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`. -type IndirectlyMutableResults<'mir, 'tcx> = - dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>; - -type QualifResults<'mir, 'tcx, Q> = - dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; - -#[derive(Default)] -pub struct Qualifs<'mir, 'tcx> { - has_mut_interior: Option>, - needs_drop: Option>, - indirectly_mutable: Option>, -} - -impl Qualifs<'mir, 'tcx> { - pub fn indirectly_mutable( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| { - let ConstCx { tcx, body, param_env, .. } = *ccx; - - // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not - // allowed in a const. - // - // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this - // without breaking stable code? - MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env) - .unsound_ignore_borrow_on_drop() - .into_engine(tcx, &body) - .pass_name("const_qualification") - .iterate_to_fixpoint() - .into_results_cursor(&body) - }); - - indirectly_mutable.seek_before_primary_effect(location); - indirectly_mutable.get().contains(local) - } - - /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary - pub fn needs_drop( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - if !NeedsDrop::in_any_value_of_ty(ccx, ty) { - return false; - } - - let needs_drop = self.needs_drop.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(NeedsDrop, ccx) - .into_engine(tcx, &body) - .iterate_to_fixpoint() - .into_results_cursor(&body) - }); - - needs_drop.seek_before_primary_effect(location); - needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location) - } - - /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary. - pub fn has_mut_interior( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - if !HasMutInterior::in_any_value_of_ty(ccx, ty) { - return false; - } - - let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(HasMutInterior, ccx) - .into_engine(tcx, &body) - .iterate_to_fixpoint() - .into_results_cursor(&body) - }); - - has_mut_interior.seek_before_primary_effect(location); - has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location) - } - - fn in_return_place( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - error_occured: Option, - ) -> ConstQualifs { - // Find the `Return` terminator if one exists. - // - // If no `Return` terminator exists, this MIR is divergent. Just return the conservative - // qualifs for the return type. - let return_block = ccx - .body - .basic_blocks() - .iter_enumerated() - .find(|(_, block)| match block.terminator().kind { - TerminatorKind::Return => true, - _ => false, - }) - .map(|(bb, _)| bb); - - let return_block = match return_block { - None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured), - Some(bb) => bb, - }; - - let return_loc = ccx.body.terminator_loc(return_block); - - let custom_eq = match ccx.const_kind() { - // We don't care whether a `const fn` returns a value that is not structurally - // matchable. Functions calls are opaque and always use type-based qualification, so - // this value should never be used. - hir::ConstContext::ConstFn => true, - - // If we know that all values of the return type are structurally matchable, there's no - // need to run dataflow. - _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false, - - hir::ConstContext::Const | hir::ConstContext::Static(_) => { - let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) - .into_engine(ccx.tcx, &ccx.body) - .iterate_to_fixpoint() - .into_results_cursor(&ccx.body); - - cursor.seek_after_primary_effect(return_loc); - cursor.contains(RETURN_PLACE) - } - }; - - ConstQualifs { - needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), - has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), - custom_eq, - error_occured, - } - } -} - -pub struct Checker<'mir, 'tcx> { - ccx: &'mir ConstCx<'mir, 'tcx>, - qualifs: Qualifs<'mir, 'tcx>, - - /// The span of the current statement. - span: Span, - - /// A set that stores for each local whether it has a `StorageDead` for it somewhere. - local_has_storage_dead: Option>, - - error_emitted: Option, - secondary_errors: Vec, -} - -impl Deref for Checker<'mir, 'tcx> { - type Target = ConstCx<'mir, 'tcx>; - - fn deref(&self) -> &Self::Target { - &self.ccx - } -} - -impl Checker<'mir, 'tcx> { - pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { - Checker { - span: ccx.body.span, - ccx, - qualifs: Default::default(), - local_has_storage_dead: None, - error_emitted: None, - secondary_errors: Vec::new(), - } - } - - pub fn check_body(&mut self) { - let ConstCx { tcx, body, .. } = *self.ccx; - let def_id = self.ccx.def_id(); - - // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's - // no need to emit duplicate errors here. - if is_async_fn(self.ccx) || body.generator.is_some() { - tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`"); - return; - } - - // The local type and predicate checks are not free and only relevant for `const fn`s. - if self.const_kind() == hir::ConstContext::ConstFn { - // Prevent const trait methods from being annotated as `stable`. - // FIXME: Do this as part of stability checking. - if self.is_const_stable_const_fn() { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { - self.ccx - .tcx - .sess - .struct_span_err(self.span, "trait methods cannot be stable const fn") - .emit(); - } - } - - self.check_item_predicates(); - - for (idx, local) in body.local_decls.iter_enumerated() { - // Handle the return place below. - if idx == RETURN_PLACE || local.internal { - continue; - } - - self.span = local.source_info.span; - self.check_local_or_return_ty(local.ty, idx); - } - - // impl trait is gone in MIR, so check the return type of a const fn by its signature - // instead of the type of the return place. - self.span = body.local_decls[RETURN_PLACE].source_info.span; - let return_ty = tcx.fn_sig(def_id).output(); - self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); - } - - self.visit_body(&body); - - // Ensure that the end result is `Sync` in a non-thread local `static`. - let should_check_for_sync = self.const_kind() - == hir::ConstContext::Static(hir::Mutability::Not) - && !tcx.is_thread_local_static(def_id.to_def_id()); - - if should_check_for_sync { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - check_return_ty_is_sync(tcx, &body, hir_id); - } - - // If we got through const-checking without emitting any "primary" errors, emit any - // "secondary" errors if they occurred. - let secondary_errors = mem::take(&mut self.secondary_errors); - if self.error_emitted.is_none() { - for error in secondary_errors { - self.tcx.sess.diagnostic().emit_diagnostic(&error); - } - } else { - assert!(self.tcx.sess.has_errors()); - } - } - - fn local_has_storage_dead(&mut self, local: Local) -> bool { - let ccx = self.ccx; - self.local_has_storage_dead - .get_or_insert_with(|| { - struct StorageDeads { - locals: BitSet, - } - impl Visitor<'tcx> for StorageDeads { - fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) { - if let StatementKind::StorageDead(l) = stmt.kind { - self.locals.insert(l); - } - } - } - let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) }; - v.visit_body(ccx.body); - v.locals - }) - .contains(local) - } - - pub fn qualifs_in_return_place(&mut self) -> ConstQualifs { - self.qualifs.in_return_place(self.ccx, self.error_emitted) - } - - /// Emits an error if an expression cannot be evaluated in the current context. - pub fn check_op(&mut self, op: impl NonConstOp) { - self.check_op_spanned(op, self.span); - } - - /// Emits an error at the given `span` if an expression cannot be evaluated in the current - /// context. - pub fn check_op_spanned(&mut self, op: O, span: Span) { - let gate = match op.status_in_item(self.ccx) { - Status::Allowed => return, - - Status::Unstable(gate) if self.tcx.features().enabled(gate) => { - let unstable_in_stable = self.ccx.is_const_stable_const_fn() - && !super::rustc_allow_const_fn_unstable( - self.tcx, - self.def_id().to_def_id(), - gate, - ); - if unstable_in_stable { - emit_unstable_in_stable_error(self.ccx, span, gate); - } - - return; - } - - Status::Unstable(gate) => Some(gate), - Status::Forbidden => None, - }; - - if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - self.tcx.sess.miri_unleashed_feature(span, gate); - return; - } - - let mut err = op.build_error(self.ccx, span); - assert!(err.is_error()); - - match op.importance() { - ops::DiagnosticImportance::Primary => { - self.error_emitted = Some(ErrorReported); - err.emit(); - } - - ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors), - } - } - - fn check_static(&mut self, def_id: DefId, span: Span) { - if self.tcx.is_thread_local_static(def_id) { - self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef"); - } - self.check_op_spanned(ops::StaticAccess, span) - } - - fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { - let kind = self.body.local_kind(local); - - for ty in ty.walk(self.tcx) { - let ty = match ty.unpack() { - GenericArgKind::Type(ty) => ty, - - // No constraints on lifetimes or constants, except potentially - // constants' types, but `walk` will get to them as well. - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, - }; - - match *ty.kind() { - ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)), - ty::Opaque(..) => self.check_op(ops::ty::ImplTrait), - ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)), - - ty::Dynamic(preds, _) => { - for pred in preds.iter() { - match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) - | ty::ExistentialPredicate::Projection(_) => { - self.check_op(ops::ty::TraitBound(kind)) - } - ty::ExistentialPredicate::Trait(trait_ref) => { - if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() { - self.check_op(ops::ty::TraitBound(kind)) - } - } - } - } - } - _ => {} - } - } - } - - fn check_item_predicates(&mut self) { - let ConstCx { tcx, .. } = *self.ccx; - - let mut current = self.def_id().to_def_id(); - loop { - let predicates = tcx.predicates_of(current); - for (predicate, _) in predicates.predicates { - match predicate.kind().skip_binder() { - ty::PredicateKind::RegionOutlives(_) - | ty::PredicateKind::TypeOutlives(_) - | ty::PredicateKind::WellFormed(_) - | ty::PredicateKind::Projection(_) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::ObjectSafe(_) => { - bug!("object safe predicate on function: {:#?}", predicate) - } - ty::PredicateKind::ClosureKind(..) => { - bug!("closure kind predicate on function: {:#?}", predicate) - } - ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => { - bug!("subtype/coerce predicate on function: {:#?}", predicate) - } - ty::PredicateKind::Trait(pred) => { - if Some(pred.def_id()) == tcx.lang_items().sized_trait() { - continue; - } - match pred.self_ty().kind() { - ty::Param(p) => { - let generics = tcx.generics_of(current); - let def = generics.type_param(p, tcx); - let span = tcx.def_span(def.def_id); - - // These are part of the function signature, so treat them like - // arguments when determining importance. - let kind = LocalKind::Arg; - - self.check_op_spanned(ops::ty::TraitBound(kind), span); - } - // other kinds of bounds are either tautologies - // or cause errors in other passes - _ => continue, - } - } - } - } - match predicates.parent { - Some(parent) => current = parent, - None => break, - } - } - } - - fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) { - match self.const_kind() { - // In a const fn all borrows are transient or point to the places given via - // references in the arguments (so we already checked them with - // TransientMutBorrow/MutBorrow as appropriate). - // The borrow checker guarantees that no new non-transient borrows are created. - // NOTE: Once we have heap allocations during CTFE we need to figure out - // how to prevent `const fn` to create long-lived allocations that point - // to mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)), - _ => { - // Locals with StorageDead do not live beyond the evaluation and can - // thus safely be borrowed without being able to be leaked to the final - // value of the constant. - if self.local_has_storage_dead(local) { - self.check_op(ops::TransientMutBorrow(kind)); - } else { - self.check_op(ops::MutBorrow(kind)); - } - } - } - } -} - -impl Visitor<'tcx> for Checker<'mir, 'tcx> { - fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) { - trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup); - - // We don't const-check basic blocks on the cleanup path since we never unwind during - // const-eval: a panic causes an immediate compile error. In other words, cleanup blocks - // are unreachable during const-eval. - // - // We can't be more conservative (e.g., by const-checking cleanup blocks anyways) because - // locals that would never be dropped during normal execution are sometimes dropped during - // unwinding, which means backwards-incompatible live-drop errors. - if block.is_cleanup { - return; - } - - self.super_basic_block_data(bb, block); - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); - - // Special-case reborrows to be more like a copy of a reference. - match *rvalue { - Rvalue::Ref(_, kind, place) => { - if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { - let ctx = match kind { - BorrowKind::Shared => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) - } - BorrowKind::Shallow => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) - } - BorrowKind::Unique => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) - } - BorrowKind::Mut { .. } => { - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - } - }; - self.visit_local(&reborrowed_place_ref.local, ctx, location); - self.visit_projection(reborrowed_place_ref, ctx, location); - return; - } - } - Rvalue::AddressOf(mutbl, place) => { - if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { - let ctx = match mutbl { - Mutability::Not => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) - } - Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), - }; - self.visit_local(&reborrowed_place_ref.local, ctx, location); - self.visit_projection(reborrowed_place_ref, ctx, location); - return; - } - } - _ => {} - } - - self.super_rvalue(rvalue, location); - - match *rvalue { - Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess), - - Rvalue::Use(_) - | Rvalue::Repeat(..) - | Rvalue::Discriminant(..) - | Rvalue::Len(_) - | Rvalue::Aggregate(..) => {} - - Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place) - | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => { - let ty = place.ty(self.body, self.tcx).ty; - let is_allowed = match ty.kind() { - // Inside a `static mut`, `&mut [...]` is allowed. - ty::Array(..) | ty::Slice(_) - if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) => - { - true - } - - // FIXME(ecstaticmorse): We could allow `&mut []` inside a const context given - // that this is merely a ZST and it is already eligible for promotion. - // This may require an RFC? - /* - ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0) - => true, - */ - _ => false, - }; - - if !is_allowed { - if let BorrowKind::Mut { .. } = kind { - self.check_mut_borrow(place.local, hir::BorrowKind::Ref) - } else { - self.check_op(ops::CellBorrow); - } - } - } - - Rvalue::AddressOf(Mutability::Mut, ref place) => { - self.check_mut_borrow(place.local, hir::BorrowKind::Raw) - } - - Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place) - | Rvalue::AddressOf(Mutability::Not, ref place) => { - let borrowed_place_has_mut_interior = qualifs::in_place::( - &self.ccx, - &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location), - place.as_ref(), - ); - - if borrowed_place_has_mut_interior { - match self.const_kind() { - // In a const fn all borrows are transient or point to the places given via - // references in the arguments (so we already checked them with - // TransientCellBorrow/CellBorrow as appropriate). - // The borrow checker guarantees that no new non-transient borrows are created. - // NOTE: Once we have heap allocations during CTFE we need to figure out - // how to prevent `const fn` to create long-lived allocations that point - // to (interior) mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow), - _ => { - // Locals with StorageDead are definitely not part of the final constant value, and - // it is thus inherently safe to permit such locals to have their - // address taken as we can't end up with a reference to them in the - // final value. - // Note: This is only sound if every local that has a `StorageDead` has a - // `StorageDead` in every control flow path leading to a `return` terminator. - if self.local_has_storage_dead(place.local) { - self.check_op(ops::TransientCellBorrow); - } else { - self.check_op(ops::CellBorrow); - } - } - } - } - } - - Rvalue::Cast( - CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), - _, - _, - ) => {} - - Rvalue::Cast( - CastKind::Pointer( - PointerCast::UnsafeFnPointer - | PointerCast::ClosureFnPointer(_) - | PointerCast::ReifyFnPointer, - ), - _, - _, - ) => self.check_op(ops::FnPtrCast), - - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => { - // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur - // in the type of any local, which also excludes casts). - } - - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.body, self.tcx); - let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - - if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { - self.check_op(ops::RawPtrToIntCast); - } - } - - Rvalue::NullaryOp(NullOp::SizeOf, _) => {} - Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), - - Rvalue::UnaryOp(_, ref operand) => { - let ty = operand.ty(self.body, self.tcx); - if is_int_bool_or_char(ty) { - // Int, bool, and char operations are fine. - } else if ty.is_floating_point() { - self.check_op(ops::FloatingPointOp); - } else { - span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); - } - } - - Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) - | Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => { - let lhs_ty = lhs.ty(self.body, self.tcx); - let rhs_ty = rhs.ty(self.body, self.tcx); - - if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) { - // Int, bool, and char operations are fine. - } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { - assert_eq!(lhs_ty, rhs_ty); - assert!( - op == BinOp::Eq - || op == BinOp::Ne - || op == BinOp::Le - || op == BinOp::Lt - || op == BinOp::Ge - || op == BinOp::Gt - || op == BinOp::Offset - ); - - self.check_op(ops::RawPtrComparison); - } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { - self.check_op(ops::FloatingPointOp); - } else { - span_bug!( - self.span, - "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}", - lhs_ty, - rhs_ty - ); - } - } - } - } - - fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { - self.super_operand(op, location); - if let Operand::Constant(c) = op { - if let Some(def_id) = c.check_static_ptr(self.tcx) { - self.check_static(def_id, self.span); - } - } - } - fn visit_projection_elem( - &mut self, - place_local: Local, - proj_base: &[PlaceElem<'tcx>], - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - trace!( - "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \ - context={:?} location={:?}", - place_local, - proj_base, - elem, - context, - location, - ); - - self.super_projection_elem(place_local, proj_base, elem, context, location); - - match elem { - ProjectionElem::Deref => { - let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty; - if let ty::RawPtr(_) = base_ty.kind() { - if proj_base.is_empty() { - let decl = &self.body.local_decls[place_local]; - if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { - let span = decl.source_info.span; - self.check_static(def_id, span); - return; - } - } - self.check_op(ops::RawPtrDeref); - } - - if context.is_mutating_use() { - self.check_op(ops::MutDeref); - } - } - - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Downcast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::Field(..) - | ProjectionElem::Index(_) => {} - } - } - - fn visit_source_info(&mut self, source_info: &SourceInfo) { - trace!("visit_source_info: source_info={:?}", source_info); - self.span = source_info.span; - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - trace!("visit_statement: statement={:?} location={:?}", statement, location); - - self.super_statement(statement, location); - - match statement.kind { - StatementKind::LlvmInlineAsm { .. } => { - self.check_op(ops::InlineAsm); - } - - StatementKind::Assign(..) - | StatementKind::SetDiscriminant { .. } - | StatementKind::FakeRead(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag { .. } - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Nop => {} - } - } - - #[instrument(level = "debug", skip(self))] - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - use rustc_target::spec::abi::Abi::RustIntrinsic; - - self.super_terminator(terminator, location); - - match &terminator.kind { - TerminatorKind::Call { func, args, .. } => { - let ConstCx { tcx, body, param_env, .. } = *self.ccx; - let caller = self.def_id().to_def_id(); - - let fn_ty = func.ty(body, tcx); - - let (mut callee, mut substs) = match *fn_ty.kind() { - ty::FnDef(def_id, substs) => (def_id, substs), - - ty::FnPtr(_) => { - self.check_op(ops::FnCallIndirect); - return; - } - _ => { - span_bug!(terminator.source_info.span, "invalid callee of type {:?}", fn_ty) - } - }; - - let mut nonconst_call_permission = false; - - // Attempting to call a trait method? - if let Some(trait_id) = tcx.trait_of_item(callee) { - trace!("attempting to call a trait method"); - if !self.tcx.features().const_trait_impl { - self.check_op(ops::FnCallNonConst); - return; - } - - let trait_ref = TraitRef::from_method(tcx, trait_id, substs); - let obligation = Obligation::new( - ObligationCause::dummy(), - param_env, - Binder::dummy(TraitPredicate { - trait_ref, - constness: ty::BoundConstness::ConstIfConst, - }), - ); - - let implsrc = tcx.infer_ctxt().enter(|infcx| { - let mut selcx = - SelectionContext::with_constness(&infcx, hir::Constness::Const); - selcx.select(&obligation) - }); - - match implsrc { - Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => { - debug!( - "const_trait_impl: provided {:?} via where-clause in {:?}", - trait_ref, param_env - ); - return; - } - Ok(Some(ImplSource::UserDefined(data))) => { - let callee_name = tcx.item_name(callee); - if let Some(&did) = tcx - .associated_item_def_ids(data.impl_def_id) - .iter() - .find(|did| tcx.item_name(**did) == callee_name) - { - // using internal substs is ok here, since this is only - // used for the `resolve` call below - substs = InternalSubsts::identity_for_item(tcx, did); - callee = did; - } - } - _ if !tcx.is_const_fn_raw(callee) => { - // At this point, it is only legal when the caller is marked with - // #[default_method_body_is_const], and the callee is in the same - // trait. - let callee_trait = tcx.trait_of_item(callee); - if callee_trait.is_some() { - if tcx.has_attr(caller, sym::default_method_body_is_const) { - if tcx.trait_of_item(caller) == callee_trait { - nonconst_call_permission = true; - } - } - } - - if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst); - return; - } - } - _ => {} - } - - // Resolve a trait method call to its concrete implementation, which may be in a - // `const` trait impl. - let instance = Instance::resolve(tcx, param_env, callee, substs); - debug!("Resolving ({:?}) -> {:?}", callee, instance); - if let Ok(Some(func)) = instance { - if let InstanceDef::Item(def) = func.def { - callee = def.did; - } - } - } - - // At this point, we are calling a function, `callee`, whose `DefId` is known... - if is_lang_panic_fn(tcx, callee) { - self.check_op(ops::Panic); - - // const-eval of the `begin_panic` fn assumes the argument is `&str` - if Some(callee) == tcx.lang_items().begin_panic_fn() { - match args[0].ty(&self.ccx.body.local_decls, tcx).kind() { - ty::Ref(_, ty, _) if ty.is_str() => (), - _ => self.check_op(ops::PanicNonStr), - } - } - - return; - } - - // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`. - let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn(); - if is_async_block { - let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block); - self.check_op(ops::Generator(kind)); - return; - } - - let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic; - - if !tcx.is_const_fn_raw(callee) { - if tcx.trait_of_item(callee).is_some() { - if tcx.has_attr(callee, sym::default_method_body_is_const) { - // To get to here we must have already found a const impl for the - // trait, but for it to still be non-const can be that the impl is - // using default method bodies. - nonconst_call_permission = true; - } - } - - if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst); - return; - } - } - - // If the `const fn` we are trying to call is not const-stable, ensure that we have - // the proper feature gate enabled. - if let Some(gate) = is_unstable_const_fn(tcx, callee) { - trace!(?gate, "calling unstable const fn"); - if self.span.allows_unstable(gate) { - return; - } - - // Calling an unstable function *always* requires that the corresponding gate - // be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`. - if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) { - self.check_op(ops::FnCallUnstable(callee, Some(gate))); - return; - } - - // If this crate is not using stability attributes, or the caller is not claiming to be a - // stable `const fn`, that is all that is required. - if !self.ccx.is_const_stable_const_fn() { - trace!("crate not using stability attributes or caller not stably const"); - return; - } - - // Otherwise, we are something const-stable calling a const-unstable fn. - - if super::rustc_allow_const_fn_unstable(tcx, caller, gate) { - trace!("rustc_allow_const_fn_unstable gate active"); - return; - } - - self.check_op(ops::FnCallUnstable(callee, Some(gate))); - return; - } - - // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that - // have no `rustc_const_stable` attributes to be const-unstable as well. This - // should be fixed later. - let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() - && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable()); - if callee_is_unstable_unmarked { - trace!("callee_is_unstable_unmarked"); - // We do not use `const` modifiers for intrinsic "functions", as intrinsics are - // `extern` funtions, and these have no way to get marked `const`. So instead we - // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const` - if self.ccx.is_const_stable_const_fn() || is_intrinsic { - self.check_op(ops::FnCallUnstable(callee, None)); - return; - } - } - trace!("permitting call"); - } - - // Forbid all `Drop` terminators unless the place being dropped is a local with no - // projections that cannot be `NeedsDrop`. - TerminatorKind::Drop { place: dropped_place, .. } - | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { - // If we are checking live drops after drop-elaboration, don't emit duplicate - // errors here. - if super::post_drop_elaboration::checking_enabled(self.ccx) { - return; - } - - let mut err_span = self.span; - - // Check to see if the type of this place can ever have a drop impl. If not, this - // `Drop` terminator is frivolous. - let ty_needs_drop = - dropped_place.ty(self.body, self.tcx).ty.needs_drop(self.tcx, self.param_env); - - if !ty_needs_drop { - return; - } - - let needs_drop = if let Some(local) = dropped_place.as_local() { - // Use the span where the local was declared as the span of the drop error. - err_span = self.body.local_decls[local].source_info.span; - self.qualifs.needs_drop(self.ccx, local, location) - } else { - true - }; - - if needs_drop { - self.check_op_spanned( - ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, - err_span, - ); - } - } - - TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), - - TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { - self.check_op(ops::Generator(hir::GeneratorKind::Gen)) - } - - TerminatorKind::Abort => { - // Cleanup blocks are skipped for const checking (see `visit_basic_block_data`). - span_bug!(self.span, "`Abort` terminator outside of cleanup block") - } - - TerminatorKind::Assert { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} - } - } -} - -fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) { - let ty = body.return_ty(); - tcx.infer_ctxt().enter(|infcx| { - let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic); - let mut fulfillment_cx = traits::FulfillmentContext::new(); - let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span)); - fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause); - if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&err, None, false); - } - }); -} - -fn place_as_reborrow( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - place: Place<'tcx>, -) -> Option> { - match place.as_ref().last_projection() { - Some((place_base, ProjectionElem::Deref)) => { - // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` - // that points to the allocation for the static. Don't treat these as reborrows. - if body.local_decls[place_base.local].is_ref_to_static() { - None - } else { - // Ensure the type being derefed is a reference and not a raw pointer. - // This is sufficient to prevent an access to a `static mut` from being marked as a - // reborrow, even if the check above were to disappear. - let inner_ty = place_base.ty(body, tcx).ty; - - if let ty::Ref(..) = inner_ty.kind() { - return Some(place_base); - } else { - return None; - } - } - } - _ => None, - } -} - -fn is_int_bool_or_char(ty: Ty<'_>) -> bool { - ty.is_bool() || ty.is_integral() || ty.is_char() -} - -fn is_async_fn(ccx: &ConstCx<'_, '_>) -> bool { - ccx.fn_sig().map_or(false, |sig| sig.header.asyncness == hir::IsAsync::Async) -} - -fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) { - let attr_span = ccx.fn_sig().map_or(ccx.body.span, |sig| sig.span.shrink_to_lo()); - - ccx.tcx - .sess - .struct_span_err( - span, - &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()), - ) - .span_suggestion( - attr_span, - "if it is not part of the public API, make this function unstably const", - concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(), - Applicability::HasPlaceholders, - ) - .span_suggestion( - attr_span, - "otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks", - format!("#[rustc_allow_const_fn_unstable({})]\n", gate), - Applicability::MaybeIncorrect, - ) - .emit(); -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -//! Check the bodies of `const`s, `static`s and `const fn`s for illegal operations. -//! -//! This module will eventually replace the parts of `qualify_consts.rs` that check whether a local -//! has interior mutability or needs to be dropped, as well as the visitor that emits errors when -//! it finds operations that are invalid in a certain context. - -use rustc_attr as attr; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::mir; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::{sym, Symbol}; - -pub use self::qualifs::Qualif; - -pub mod check; -mod ops; -pub mod post_drop_elaboration; -pub mod qualifs; -mod resolver; - -/// Information about the item currently being const-checked, as well as a reference to the global -/// context. -pub struct ConstCx<'mir, 'tcx> { - pub body: &'mir mir::Body<'tcx>, - pub tcx: TyCtxt<'tcx>, - pub param_env: ty::ParamEnv<'tcx>, - pub const_kind: Option, -} - -impl ConstCx<'mir, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self { - let def_id = body.source.def_id().expect_local(); - let param_env = tcx.param_env(def_id); - Self::new_with_param_env(tcx, body, param_env) - } - - pub fn new_with_param_env( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local()); - ConstCx { body, tcx, param_env, const_kind } - } - - pub fn def_id(&self) -> LocalDefId { - self.body.source.def_id().expect_local() - } - - /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.). - /// - /// Panics if this `Item` is not const. - pub fn const_kind(&self) -> hir::ConstContext { - self.const_kind.expect("`const_kind` must not be called on a non-const fn") - } - - pub fn is_const_stable_const_fn(&self) -> bool { - self.const_kind == Some(hir::ConstContext::ConstFn) - && self.tcx.features().staged_api - && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id()) - } - - /// Returns the function signature of the item being const-checked if it is a `fn` or `const fn`. - pub fn fn_sig(&self) -> Option<&'tcx hir::FnSig<'tcx>> { - // Get this from the HIR map instead of a query to avoid cycle errors. - // - // FIXME: Is this still an issue? - let hir_map = self.tcx.hir(); - let hir_id = hir_map.local_def_id_to_hir_id(self.def_id()); - hir_map.fn_sig_by_hir_id(hir_id) - } -} - -/// Returns `true` if this `DefId` points to one of the official `panic` lang items. -pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - // We can allow calls to these functions because `hook_panic_fn` in - // `const_eval/machine.rs` ensures the calls are handled specially. - // Keep in sync with what that function handles! - Some(def_id) == tcx.lang_items().panic_fn() - || Some(def_id) == tcx.lang_items().panic_str() - || Some(def_id) == tcx.lang_items().begin_panic_fn() - || Some(def_id) == tcx.lang_items().panic_fmt() - || Some(def_id) == tcx.lang_items().begin_panic_fmt() -} - -pub fn rustc_allow_const_fn_unstable( - tcx: TyCtxt<'tcx>, - def_id: DefId, - feature_gate: Symbol, -) -> bool { - let attrs = tcx.get_attrs(def_id); - attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate) -} - -// Returns `true` if the given `const fn` is "const-stable". -// -// Panics if the given `DefId` does not refer to a `const fn`. -// -// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" -// functions can be called in a const-context by users of the stable compiler. "const-stable" -// functions are subject to more stringent restrictions than "const-unstable" functions: They -// cannot use unstable features and can only call other "const-stable" functions. -pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - use attr::{ConstStability, Stability, StabilityLevel}; - - // A default body marked const is not const-stable because const - // trait fns currently cannot be const-stable. We shouldn't - // restrict default bodies to only call const-stable functions. - if tcx.has_attr(def_id, sym::default_method_body_is_const) { - return false; - } - - // Const-stability is only relevant for `const fn`. - assert!(tcx.is_const_fn_raw(def_id)); - - // Functions with `#[rustc_const_unstable]` are const-unstable. - match tcx.lookup_const_stability(def_id) { - Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false, - Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true, - None => {} - } - - // Functions with `#[unstable]` are const-unstable. - // - // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability - // attributes. `#[unstable]` should be irrelevant. - if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) = - tcx.lookup_stability(def_id) - { - return false; - } - - true -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/ops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/ops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/ops.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/ops.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,628 +0,0 @@ -//! Concrete error types for all operations which may be invalid in a certain const context. - -use rustc_errors::{struct_span_err, DiagnosticBuilder}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_middle::mir; -use rustc_session::parse::feature_err; -use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol}; - -use super::ConstCx; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Status { - Allowed, - Unstable(Symbol), - Forbidden, -} - -#[derive(Clone, Copy)] -pub enum DiagnosticImportance { - /// An operation that must be removed for const-checking to pass. - Primary, - - /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere. - Secondary, -} - -/// An operation that is not *always* allowed in a const context. -pub trait NonConstOp: std::fmt::Debug { - /// Returns an enum indicating whether this operation is allowed within the given item. - fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { - Status::Forbidden - } - - fn importance(&self) -> DiagnosticImportance { - DiagnosticImportance::Primary - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; -} - -#[derive(Debug)] -pub struct FloatingPointOp; -impl NonConstOp for FloatingPointOp { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - if ccx.const_kind() == hir::ConstContext::ConstFn { - Status::Unstable(sym::const_fn_floating_point_arithmetic) - } else { - Status::Allowed - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_fn_floating_point_arithmetic, - span, - &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()), - ) - } -} - -/// A function call where the callee is a pointer. -#[derive(Debug)] -pub struct FnCallIndirect; -impl NonConstOp for FnCallIndirect { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn") - } -} - -/// A function call where the callee is not marked as `const`. -#[derive(Debug)] -pub struct FnCallNonConst; -impl NonConstOp for FnCallNonConst { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - ccx.const_kind(), - ) - } -} - -/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function. -/// -/// Contains the name of the feature that would allow the use of this function. -#[derive(Debug)] -pub struct FnCallUnstable(pub DefId, pub Option); - -impl NonConstOp for FnCallUnstable { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let FnCallUnstable(def_id, feature) = *self; - - let mut err = ccx.tcx.sess.struct_span_err( - span, - &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)), - ); - - if ccx.is_const_stable_const_fn() { - err.help("Const-stable functions can only call other const-stable functions"); - } else if ccx.tcx.sess.is_nightly_build() { - if let Some(feature) = feature { - err.help(&format!( - "add `#![feature({})]` to the crate attributes to enable", - feature - )); - } - } - - err - } -} - -#[derive(Debug)] -pub struct FnPtrCast; -impl NonConstOp for FnPtrCast { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - if ccx.const_kind() != hir::ConstContext::ConstFn { - Status::Allowed - } else { - Status::Unstable(sym::const_fn_fn_ptr_basics) - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_fn_fn_ptr_basics, - span, - &format!("function pointer casts are not allowed in {}s", ccx.const_kind()), - ) - } -} - -#[derive(Debug)] -pub struct Generator(pub hir::GeneratorKind); -impl NonConstOp for Generator { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { - Status::Unstable(sym::const_async_blocks) - } else { - Status::Forbidden - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); - if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { - feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg) - } else { - ccx.tcx.sess.struct_span_err(span, &msg) - } - } -} - -#[derive(Debug)] -pub struct HeapAllocation; -impl NonConstOp for HeapAllocation { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0010, - "allocations are not allowed in {}s", - ccx.const_kind() - ); - err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind())); - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "The value of statics and constants must be known at compile time, \ - and they live for the entire lifetime of a program. Creating a boxed \ - value allocates memory on the heap at runtime, and therefore cannot \ - be done at compile time.", - ); - } - err - } -} - -#[derive(Debug)] -pub struct InlineAsm; -impl NonConstOp for InlineAsm { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "inline assembly is not allowed in {}s", - ccx.const_kind() - ) - } -} - -#[derive(Debug)] -pub struct LiveDrop { - pub dropped_at: Option, -} -impl NonConstOp for LiveDrop { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0493, - "destructors cannot be evaluated at compile-time" - ); - err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); - if let Some(span) = self.dropped_at { - err.span_label(span, "value is dropped here"); - } - err - } -} - -#[derive(Debug)] -/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to -/// the final value of the constant. -pub struct TransientCellBorrow; -impl NonConstOp for TransientCellBorrow { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_refs_to_cell) - } - fn importance(&self) -> DiagnosticImportance { - // The cases that cannot possibly work will already emit a `CellBorrow`, so we should - // not additionally emit a feature gate error if activating the feature gate won't work. - DiagnosticImportance::Secondary - } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_refs_to_cell, - span, - "cannot borrow here, since the borrowed element may contain interior mutability", - ) - } -} - -#[derive(Debug)] -/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to -/// the final value of the constant, and thus we cannot allow this (for now). We may allow -/// it in the future for static items. -pub struct CellBorrow; -impl NonConstOp for CellBorrow { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0492, - "{}s cannot refer to interior mutable data", - ccx.const_kind(), - ); - err.span_label( - span, - "this borrow of an interior mutable value may end up in the final value", - ); - if let hir::ConstContext::Static(_) = ccx.const_kind() { - err.help( - "to fix this, the value can be extracted to a separate \ - `static` item and then referenced", - ); - } - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "A constant containing interior mutable data behind a reference can allow you - to modify that data. This would make multiple uses of a constant to be able to - see different values and allow circumventing the `Send` and `Sync` requirements - for shared mutable data, which is unsound.", - ); - } - err - } -} - -#[derive(Debug)] -/// This op is for `&mut` borrows in the trailing expression of a constant -/// which uses the "enclosing scopes rule" to leak its locals into anonymous -/// static or const items. -pub struct MutBorrow(pub hir::BorrowKind); - -impl NonConstOp for MutBorrow { - fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { - Status::Forbidden - } - - fn importance(&self) -> DiagnosticImportance { - // If there were primary errors (like non-const function calls), do not emit further - // errors about mutable references. - DiagnosticImportance::Secondary - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let raw = match self.0 { - hir::BorrowKind::Raw => "raw ", - hir::BorrowKind::Ref => "", - }; - - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0764, - "{}mutable references are not allowed in the final value of {}s", - raw, - ccx.const_kind(), - ); - - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "References in statics and constants may only refer \ - to immutable values.\n\n\ - Statics are shared everywhere, and if they refer to \ - mutable data one might violate memory safety since \ - holding multiple mutable references to shared data \ - is not allowed.\n\n\ - If you really want global mutable state, try using \ - static mut or a global UnsafeCell.", - ); - } - err - } -} - -#[derive(Debug)] -pub struct TransientMutBorrow(pub hir::BorrowKind); - -impl NonConstOp for TransientMutBorrow { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let raw = match self.0 { - hir::BorrowKind::Raw => "raw ", - hir::BorrowKind::Ref => "", - }; - - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()), - ) - } -} - -#[derive(Debug)] -pub struct MutDeref; -impl NonConstOp for MutDeref { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn importance(&self) -> DiagnosticImportance { - // Usually a side-effect of a `TransientMutBorrow` somewhere. - DiagnosticImportance::Secondary - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("mutation through a reference is not allowed in {}s", ccx.const_kind()), - ) - } -} - -#[derive(Debug)] -pub struct Panic; -impl NonConstOp for Panic { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_panic) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_panic, - span, - &format!("panicking in {}s is unstable", ccx.const_kind()), - ) - } -} - -/// A call to a `panic()` lang item where the first argument is _not_ a `&str`. -#[derive(Debug)] -pub struct PanicNonStr; -impl NonConstOp for PanicNonStr { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - ccx.tcx.sess.struct_span_err( - span, - "argument to `panic!()` in a const context must have type `&str`", - ) - } -} - -/// Comparing raw pointers for equality. -/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on -/// allocation base addresses that are not known at compile-time. -#[derive(Debug)] -pub struct RawPtrComparison; -impl NonConstOp for RawPtrComparison { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = ccx - .tcx - .sess - .struct_span_err(span, "pointers cannot be reliably compared during const eval."); - err.note( - "see issue #53020 \ - for more information", - ); - err - } -} - -#[derive(Debug)] -pub struct RawPtrDeref; -impl NonConstOp for RawPtrDeref { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_raw_ptr_deref) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_raw_ptr_deref, - span, - &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),), - ) - } -} - -/// Casting raw pointer or function pointer to an integer. -/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on -/// allocation base addresses that are not known at compile-time. -#[derive(Debug)] -pub struct RawPtrToIntCast; -impl NonConstOp for RawPtrToIntCast { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = ccx - .tcx - .sess - .struct_span_err(span, "pointers cannot be cast to integers during const eval."); - err.note("at compile-time, pointers do not have an integer value"); - err.note( - "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior", - ); - err - } -} - -/// An access to a (non-thread-local) `static`. -#[derive(Debug)] -pub struct StaticAccess; -impl NonConstOp for StaticAccess { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - if let hir::ConstContext::Static(_) = ccx.const_kind() { - Status::Allowed - } else { - Status::Forbidden - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0013, - "{}s cannot refer to statics", - ccx.const_kind() - ); - err.help( - "consider extracting the value of the `static` to a `const`, and referring to that", - ); - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "`static` and `const` variables can refer to other `const` variables. \ - A `const` variable, however, cannot refer to a `static` variable.", - ); - err.help("To fix this, the value can be extracted to a `const` and then used."); - } - err - } -} - -/// An access to a thread-local `static`. -#[derive(Debug)] -pub struct ThreadLocalAccess; -impl NonConstOp for ThreadLocalAccess { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - struct_span_err!( - ccx.tcx.sess, - span, - E0625, - "thread-local statics cannot be \ - accessed at compile-time" - ) - } -} - -// Types that cannot appear in the signature or locals of a `const fn`. -pub mod ty { - use super::*; - - #[derive(Debug)] - pub struct MutRef(pub mir::LocalKind); - impl NonConstOp for MutRef { - fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn importance(&self) -> DiagnosticImportance { - match self.0 { - mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, - mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { - DiagnosticImportance::Primary - } - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("mutable references are not allowed in {}s", ccx.const_kind()), - ) - } - } - - #[derive(Debug)] - pub struct FnPtr(pub mir::LocalKind); - impl NonConstOp for FnPtr { - fn importance(&self) -> DiagnosticImportance { - match self.0 { - mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, - mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { - DiagnosticImportance::Primary - } - } - } - - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - if ccx.const_kind() != hir::ConstContext::ConstFn { - Status::Allowed - } else { - Status::Unstable(sym::const_fn_fn_ptr_basics) - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_fn_fn_ptr_basics, - span, - &format!("function pointers cannot appear in {}s", ccx.const_kind()), - ) - } - } - - #[derive(Debug)] - pub struct ImplTrait; - impl NonConstOp for ImplTrait { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_impl_trait) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_impl_trait, - span, - &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()), - ) - } - } - - #[derive(Debug)] - pub struct TraitBound(pub mir::LocalKind); - impl NonConstOp for TraitBound { - fn importance(&self) -> DiagnosticImportance { - match self.0 { - mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, - mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { - DiagnosticImportance::Primary - } - } - } - - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - if ccx.const_kind() != hir::ConstContext::ConstFn { - Status::Allowed - } else { - Status::Unstable(sym::const_fn_trait_bound) - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_fn_trait_bound, - span, - "trait bounds other than `Sized` on const fn parameters are unstable", - ) - } - } - - /// A trait bound with the `?const Trait` opt-out - #[derive(Debug)] - pub struct TraitBoundNotConst; - impl NonConstOp for TraitBoundNotConst { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_trait_bound_opt_out) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_trait_bound_opt_out, - span, - "`?const Trait` syntax is unstable", - ) - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::TyCtxt; -use rustc_span::Span; - -use super::check::Qualifs; -use super::ops::{self, NonConstOp}; -use super::qualifs::{NeedsDrop, Qualif}; -use super::ConstCx; - -/// Returns `true` if we should use the more precise live drop checker that runs after drop -/// elaboration. -pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { - // Const-stable functions must always use the stable live drop checker. - if ccx.is_const_stable_const_fn() { - return false; - } - - ccx.tcx.features().const_precise_live_drops -} - -/// Look for live drops in a const context. -/// -/// This is separate from the rest of the const checking logic because it must run after drop -/// elaboration. -pub fn check_live_drops(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); - let const_kind = tcx.hir().body_const_context(def_id); - if const_kind.is_none() { - return; - } - - let ccx = ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def_id) }; - if !checking_enabled(&ccx) { - return; - } - - let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() }; - - visitor.visit_body(body); -} - -struct CheckLiveDrops<'mir, 'tcx> { - ccx: &'mir ConstCx<'mir, 'tcx>, - qualifs: Qualifs<'mir, 'tcx>, -} - -// So we can access `body` and `tcx`. -impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { - type Target = ConstCx<'mir, 'tcx>; - - fn deref(&self) -> &Self::Target { - &self.ccx - } -} - -impl CheckLiveDrops<'mir, 'tcx> { - fn check_live_drop(&self, span: Span) { - ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit(); - } -} - -impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> { - fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &mir::BasicBlockData<'tcx>) { - trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup); - - // Ignore drop terminators in cleanup blocks. - if block.is_cleanup { - return; - } - - self.super_basic_block_data(bb, block); - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); - - match &terminator.kind { - mir::TerminatorKind::Drop { place: dropped_place, .. } => { - let dropped_ty = dropped_place.ty(self.body, self.tcx).ty; - if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) { - bug!( - "Drop elaboration left behind a Drop for a type that does not need dropping" - ); - } - - if dropped_place.is_indirect() { - self.check_live_drop(terminator.source_info.span); - return; - } - - // Drop elaboration is not precise enough to accept code like - // `src/test/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option>` is - // initialized with `None` and never changed, it still emits drop glue. - // Hence we additionally check the qualifs here to allow more code to pass. - if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) { - // Use the span where the dropped local was declared for the error. - let span = self.body.local_decls[dropped_place.local].source_info.span; - self.check_live_drop(span); - } - } - - mir::TerminatorKind::DropAndReplace { .. } => span_bug!( - terminator.source_info.span, - "`DropAndReplace` should be removed by drop elaboration", - ), - - mir::TerminatorKind::Abort - | mir::TerminatorKind::Call { .. } - | mir::TerminatorKind::Assert { .. } - | mir::TerminatorKind::FalseEdge { .. } - | mir::TerminatorKind::FalseUnwind { .. } - | mir::TerminatorKind::GeneratorDrop - | mir::TerminatorKind::Goto { .. } - | mir::TerminatorKind::InlineAsm { .. } - | mir::TerminatorKind::Resume - | mir::TerminatorKind::Return - | mir::TerminatorKind::SwitchInt { .. } - | mir::TerminatorKind::Unreachable - | mir::TerminatorKind::Yield { .. } => {} - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/qualifs.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/qualifs.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/qualifs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/qualifs.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,272 +0,0 @@ -//! Structural const qualification. -//! -//! See the `Qualif` trait for more info. - -use rustc_errors::ErrorReported; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; -use rustc_span::DUMMY_SP; -use rustc_trait_selection::traits; - -use super::ConstCx; - -pub fn in_any_value_of_ty( - cx: &ConstCx<'_, 'tcx>, - ty: Ty<'tcx>, - error_occured: Option, -) -> ConstQualifs { - ConstQualifs { - has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), - needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), - custom_eq: CustomEq::in_any_value_of_ty(cx, ty), - error_occured, - } -} - -/// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some -/// code for promotion or prevent it from evaluating at compile time. -/// -/// Normally, we would determine what qualifications apply to each type and error when an illegal -/// operation is performed on such a type. However, this was found to be too imprecise, especially -/// in the presence of `enum`s. If only a single variant of an enum has a certain qualification, we -/// needn't reject code unless it actually constructs and operates on the qualified variant. -/// -/// To accomplish this, const-checking and promotion use a value-based analysis (as opposed to a -/// type-based one). Qualifications propagate structurally across variables: If a local (or a -/// projection of a local) is assigned a qualified value, that local itself becomes qualified. -pub trait Qualif { - /// The name of the file used to debug the dataflow analysis that computes this qualif. - const ANALYSIS_NAME: &'static str; - - /// Whether this `Qualif` is cleared when a local is moved from. - const IS_CLEARED_ON_MOVE: bool = false; - - /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`. - fn in_qualifs(qualifs: &ConstQualifs) -> bool; - - /// Returns `true` if *any* value of the given type could possibly have this `Qualif`. - /// - /// This function determines `Qualif`s when we cannot do a value-based analysis. Since qualif - /// propagation is context-insenstive, this includes function arguments and values returned - /// from a call to another function. - /// - /// It also determines the `Qualif`s for primitive types. - fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool; - - /// Returns `true` if this `Qualif` is inherent to the given struct or enum. - /// - /// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes - /// qualified if part of it is assigned a value with that `Qualif`. However, some ADTs *always* - /// have a certain `Qualif`, regardless of whether their fields have it. For example, a type - /// with a custom `Drop` impl is inherently `NeedsDrop`. - /// - /// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound. - fn in_adt_inherently( - cx: &ConstCx<'_, 'tcx>, - adt: &'tcx AdtDef, - substs: SubstsRef<'tcx>, - ) -> bool; -} - -/// Constant containing interior mutability (`UnsafeCell`). -/// This must be ruled out to make sure that evaluating the constant at compile-time -/// and at *any point* during the run-time would produce the same result. In particular, -/// promotion of temporaries must not change program behavior; if the promoted could be -/// written to, that would be a problem. -pub struct HasMutInterior; - -impl Qualif for HasMutInterior { - const ANALYSIS_NAME: &'static str = "flow_has_mut_interior"; - - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.has_mut_interior - } - - fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) - } - - fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { - // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. - // It arises structurally for all other types. - Some(adt.did) == cx.tcx.lang_items().unsafe_cell_type() - } -} - -/// Constant containing an ADT that implements `Drop`. -/// This must be ruled out (a) because we cannot run `Drop` during compile-time -/// as that might not be a `const fn`, and (b) because implicit promotion would -/// remove side-effects that occur as part of dropping that value. -pub struct NeedsDrop; - -impl Qualif for NeedsDrop { - const ANALYSIS_NAME: &'static str = "flow_needs_drop"; - const IS_CLEARED_ON_MOVE: bool = true; - - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.needs_drop - } - - fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.needs_drop(cx.tcx, cx.param_env) - } - - fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { - adt.has_dtor(cx.tcx) - } -} - -/// A constant that cannot be used as part of a pattern in a `match` expression. -pub struct CustomEq; - -impl Qualif for CustomEq { - const ANALYSIS_NAME: &'static str = "flow_custom_eq"; - - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.custom_eq - } - - fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`, - // we know that at least some values of that type are not structural-match. I say "some" - // because that component may be part of an enum variant (e.g., - // `Option::::Some`), in which case some values of this type may be - // structural-match (`Option::None`). - let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id()); - traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some() - } - - fn in_adt_inherently( - cx: &ConstCx<'_, 'tcx>, - adt: &'tcx AdtDef, - substs: SubstsRef<'tcx>, - ) -> bool { - let ty = cx.tcx.mk_ty(ty::Adt(adt, substs)); - !ty.is_structural_eq_shallow(cx.tcx) - } -} - -// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. - -/// Returns `true` if this `Rvalue` contains qualif `Q`. -pub fn in_rvalue(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, rvalue: &Rvalue<'tcx>) -> bool -where - Q: Qualif, - F: FnMut(Local) -> bool, -{ - match rvalue { - Rvalue::ThreadLocalRef(_) | Rvalue::NullaryOp(..) => { - Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) - } - - Rvalue::Discriminant(place) | Rvalue::Len(place) => { - in_place::(cx, in_local, place.as_ref()) - } - - Rvalue::Use(operand) - | Rvalue::Repeat(operand, _) - | Rvalue::UnaryOp(_, operand) - | Rvalue::Cast(_, operand, _) => in_operand::(cx, in_local, operand), - - Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { - in_operand::(cx, in_local, lhs) || in_operand::(cx, in_local, rhs) - } - - Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - // Special-case reborrows to be more like a copy of the reference. - if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() { - let base_ty = place_base.ty(cx.body, cx.tcx).ty; - if let ty::Ref(..) = base_ty.kind() { - return in_place::(cx, in_local, place_base); - } - } - - in_place::(cx, in_local, place.as_ref()) - } - - Rvalue::Aggregate(kind, operands) => { - // Return early if we know that the struct or enum being constructed is always - // qualified. - if let AggregateKind::Adt(def, _, substs, ..) = **kind { - if Q::in_adt_inherently(cx, def, substs) { - return true; - } - } - - // Otherwise, proceed structurally... - operands.iter().any(|o| in_operand::(cx, in_local, o)) - } - } -} - -/// Returns `true` if this `Place` contains qualif `Q`. -pub fn in_place(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, place: PlaceRef<'tcx>) -> bool -where - Q: Qualif, - F: FnMut(Local) -> bool, -{ - let mut place = place; - while let Some((place_base, elem)) = place.last_projection() { - match elem { - ProjectionElem::Index(index) if in_local(index) => return true, - - ProjectionElem::Deref - | ProjectionElem::Field(_, _) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(_, _) - | ProjectionElem::Index(_) => {} - } - - let base_ty = place_base.ty(cx.body, cx.tcx); - let proj_ty = base_ty.projection_ty(cx.tcx, elem).ty; - if !Q::in_any_value_of_ty(cx, proj_ty) { - return false; - } - - place = place_base; - } - - assert!(place.projection.is_empty()); - in_local(place.local) -} - -/// Returns `true` if this `Operand` contains qualif `Q`. -pub fn in_operand(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, operand: &Operand<'tcx>) -> bool -where - Q: Qualif, - F: FnMut(Local) -> bool, -{ - let constant = match operand { - Operand::Copy(place) | Operand::Move(place) => { - return in_place::(cx, in_local, place.as_ref()); - } - - Operand::Constant(c) => c, - }; - - // Check the qualifs of the value of `const` items. - if let Some(ct) = constant.literal.const_for_ty() { - if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val { - assert!(promoted.is_none()); - // Don't peek inside trait associated constants. - if cx.tcx.trait_of_item(def.did).is_none() { - let qualifs = if let Some((did, param_did)) = def.as_const_arg() { - cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) - } else { - cx.tcx.at(constant.span).mir_const_qualif(def.did) - }; - - if !Q::in_qualifs(&qualifs) { - return false; - } - - // Just in case the type is more specific than - // the definition, e.g., impl associated const - // with type parameters, take it into account. - } - } - } - // Otherwise use the qualifs of the type. - Q::in_any_value_of_ty(cx, constant.literal.ty()) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/resolver.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/resolver.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/resolver.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_consts/resolver.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,217 +0,0 @@ -//! Propagate `Qualif`s between locals and query the results. -//! -//! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs. - -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Local, Location}; - -use std::marker::PhantomData; - -use super::{qualifs, ConstCx, Qualif}; -use crate::dataflow; - -/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of -/// `FlowSensitiveAnalysis`. -/// -/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on -/// the `MaybeMutBorrowedLocals` dataflow pass to see if a `Local` may have become qualified via -/// an indirect assignment or function call. -struct TransferFunction<'a, 'mir, 'tcx, Q> { - ccx: &'a ConstCx<'mir, 'tcx>, - qualifs_per_local: &'a mut BitSet, - - _qualif: PhantomData, -} - -impl TransferFunction<'a, 'mir, 'tcx, Q> -where - Q: Qualif, -{ - fn new(ccx: &'a ConstCx<'mir, 'tcx>, qualifs_per_local: &'a mut BitSet) -> Self { - TransferFunction { ccx, qualifs_per_local, _qualif: PhantomData } - } - - fn initialize_state(&mut self) { - self.qualifs_per_local.clear(); - - for arg in self.ccx.body.args_iter() { - let arg_ty = self.ccx.body.local_decls[arg].ty; - if Q::in_any_value_of_ty(self.ccx, arg_ty) { - self.qualifs_per_local.insert(arg); - } - } - } - - fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) { - debug_assert!(!place.is_indirect()); - - match (value, place.as_ref()) { - (true, mir::PlaceRef { local, .. }) => { - self.qualifs_per_local.insert(local); - } - - // For now, we do not clear the qualif if a local is overwritten in full by - // an unqualified rvalue (e.g. `y = 5`). This is to be consistent - // with aggregates where we overwrite all fields with assignments, which would not - // get this feature. - (false, mir::PlaceRef { local: _, projection: &[] }) => { - // self.qualifs_per_local.remove(*local); - } - - _ => {} - } - } - - fn apply_call_return_effect( - &mut self, - _block: BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, - ) { - // We cannot reason about another function's internals, so use conservative type-based - // qualification for the result of a function call. - let return_ty = return_place.ty(self.ccx.body, self.ccx.tcx).ty; - let qualif = Q::in_any_value_of_ty(self.ccx, return_ty); - - if !return_place.is_indirect() { - self.assign_qualif_direct(&return_place, qualif); - } - } -} - -impl Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q> -where - Q: Qualif, -{ - fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { - self.super_operand(operand, location); - - if !Q::IS_CLEARED_ON_MOVE { - return; - } - - // If a local with no projections is moved from (e.g. `x` in `y = x`), record that - // it no longer needs to be dropped. - if let mir::Operand::Move(place) = operand { - if let Some(local) = place.as_local() { - self.qualifs_per_local.remove(local); - } - } - } - - fn visit_assign( - &mut self, - place: &mir::Place<'tcx>, - rvalue: &mir::Rvalue<'tcx>, - location: Location, - ) { - let qualif = qualifs::in_rvalue::( - self.ccx, - &mut |l| self.qualifs_per_local.contains(l), - rvalue, - ); - if !place.is_indirect() { - self.assign_qualif_direct(place, qualif); - } - - // We need to assign qualifs to the left-hand side before visiting `rvalue` since - // qualifs can be cleared on move. - self.super_assign(place, rvalue, location); - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - // The effect of assignment to the return place in `TerminatorKind::Call` is not applied - // here; that occurs in `apply_call_return_effect`. - - if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind { - let qualif = qualifs::in_operand::( - self.ccx, - &mut |l| self.qualifs_per_local.contains(l), - value, - ); - - if !place.is_indirect() { - self.assign_qualif_direct(place, qualif); - } - } - - // We need to assign qualifs to the dropped location before visiting the operand that - // replaces it since qualifs can be cleared on move. - self.super_terminator(terminator, location); - } -} - -/// The dataflow analysis used to propagate qualifs on arbitrary CFGs. -pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> { - ccx: &'a ConstCx<'mir, 'tcx>, - _qualif: PhantomData, -} - -impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> -where - Q: Qualif, -{ - pub(super) fn new(_: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self { - FlowSensitiveAnalysis { ccx, _qualif: PhantomData } - } - - fn transfer_function( - &self, - state: &'a mut BitSet, - ) -> TransferFunction<'a, 'mir, 'tcx, Q> { - TransferFunction::::new(self.ccx, state) - } -} - -impl dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> -where - Q: Qualif, -{ - type Domain = BitSet; - - const NAME: &'static str = Q::ANALYSIS_NAME; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - BitSet::new_empty(body.local_decls.len()) - } - - fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) { - self.transfer_function(state).initialize_state(); - } -} - -impl dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> -where - Q: Qualif, -{ - fn apply_statement_effect( - &self, - state: &mut Self::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.transfer_function(state).visit_statement(statement, location); - } - - fn apply_terminator_effect( - &self, - state: &mut Self::Domain, - terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - self.transfer_function(state).visit_terminator(terminator, location); - } - - fn apply_call_return_effect( - &self, - state: &mut Self::Domain, - block: BasicBlock, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, - ) { - self.transfer_function(state).apply_call_return_effect(block, func, args, return_place) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_packed_ref.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_packed_ref.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_packed_ref.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_packed_ref.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::UNALIGNED_REFERENCES; -use rustc_span::symbol::sym; - -use crate::transform::MirPass; -use crate::util; - -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { unsafe_derive_on_repr_packed, ..*providers }; -} - -pub struct CheckPackedRef; - -impl<'tcx> MirPass<'tcx> for CheckPackedRef { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env(body.source.def_id()); - let source_info = SourceInfo::outermost(body.span); - let mut checker = PackedRefChecker { body, tcx, param_env, source_info }; - checker.visit_body(&body); - } -} - -struct PackedRefChecker<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - source_info: SourceInfo, -} - -fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - - tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| { - // FIXME: when we make this a hard error, this should have its - // own error code. - let message = if tcx.generics_of(def_id).own_requires_monomorphization() { - "`#[derive]` can't be used on a `#[repr(packed)]` struct with \ - type or const parameters (error E0133)" - .to_string() - } else { - "`#[derive]` can't be used on a `#[repr(packed)]` struct that \ - does not derive Copy (error E0133)" - .to_string() - }; - lint.build(&message).emit() - }); -} - -fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - debug!("builtin_derive_def_id({:?})", def_id); - if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - if tcx.has_attr(impl_def_id, sym::automatically_derived) { - debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id); - Some(impl_def_id) - } else { - debug!("builtin_derive_def_id({:?}) - not automatically derived", def_id); - None - } - } else { - debug!("builtin_derive_def_id({:?}) - not a method", def_id); - None - } -} - -impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> { - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - // Make sure we know where in the MIR we are. - self.source_info = terminator.source_info; - self.super_terminator(terminator, location); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - // Make sure we know where in the MIR we are. - self.source_info = statement.source_info; - self.super_statement(statement, location); - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - if context.is_borrow() { - if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { - let def_id = self.body.source.instance.def_id(); - if let Some(impl_def_id) = builtin_derive_def_id(self.tcx, def_id) { - // If a method is defined in the local crate, - // the impl containing that method should also be. - self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); - } else { - let source_info = self.source_info; - let lint_root = self.body.source_scopes[source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; - self.tcx.struct_span_lint_hir( - UNALIGNED_REFERENCES, - lint_root, - source_info.span, - |lint| { - lint.build("reference to packed field is unaligned") - .note( - "fields of packed structs are not properly aligned, and creating \ - a misaligned reference is undefined behavior (even if that \ - reference is never dereferenced)", - ) - .emit() - }, - ); - } - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_unsafety.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_unsafety.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_unsafety.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/check_unsafety.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,574 +0,0 @@ -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::hir_id::HirId; -use rustc_hir::intravisit; -use rustc_hir::Node; -use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; -use rustc_session::lint::Level; - -use std::ops::Bound; - -pub struct UnsafetyChecker<'a, 'tcx> { - body: &'a Body<'tcx>, - body_did: LocalDefId, - violations: Vec, - source_info: SourceInfo, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - /// Mark an `unsafe` block as used, so we don't lint it. - used_unsafe: FxHashSet, - inherited_blocks: Vec<(hir::HirId, bool)>, -} - -impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { - fn new( - body: &'a Body<'tcx>, - body_did: LocalDefId, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - Self { - body, - body_did, - violations: vec![], - source_info: SourceInfo::outermost(body.span), - tcx, - param_env, - used_unsafe: Default::default(), - inherited_blocks: vec![], - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.source_info = terminator.source_info; - match terminator.kind { - TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { - // safe (at least as emitted during MIR construction) - } - - TerminatorKind::Call { ref func, .. } => { - let func_ty = func.ty(self.body, self.tcx); - let sig = func_ty.fn_sig(self.tcx); - if let hir::Unsafety::Unsafe = sig.unsafety() { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::CallToUnsafeFunction, - ) - } - - if let ty::FnDef(func_id, _) = func_ty.kind() { - self.check_target_features(*func_id); - } - } - - TerminatorKind::InlineAsm { .. } => self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfInlineAssembly, - ), - } - self.super_terminator(terminator, location); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - self.source_info = statement.source_info; - match statement.kind { - StatementKind::Assign(..) - | StatementKind::FakeRead(..) - | StatementKind::SetDiscriminant { .. } - | StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::Retag { .. } - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::Nop => { - // safe (at least as emitted during MIR construction) - } - - StatementKind::LlvmInlineAsm { .. } => self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfInlineAssembly, - ), - StatementKind::CopyNonOverlapping(..) => unreachable!(), - } - self.super_statement(statement, location); - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - match rvalue { - Rvalue::Aggregate(box ref aggregate, _) => match aggregate { - &AggregateKind::Array(..) | &AggregateKind::Tuple => {} - &AggregateKind::Adt(ref def, ..) => { - match self.tcx.layout_scalar_valid_range(def.did) { - (Bound::Unbounded, Bound::Unbounded) => {} - _ => self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::InitializingTypeWith, - ), - } - } - &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => { - let UnsafetyCheckResult { violations, unsafe_blocks } = - self.tcx.unsafety_check_result(def_id.expect_local()); - self.register_violations(&violations, &unsafe_blocks); - } - }, - _ => {} - } - self.super_rvalue(rvalue, location); - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - // On types with `scalar_valid_range`, prevent - // * `&mut x.field` - // * `x.field = y;` - // * `&x.field` if `field`'s type has interior mutability - // because either of these would allow modifying the layout constrained field and - // insert values that violate the layout constraints. - if context.is_mutating_use() || context.is_borrow() { - self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use()); - } - - // Some checks below need the extra metainfo of the local declaration. - let decl = &self.body.local_decls[place.local]; - - // Check the base local: it might be an unsafe-to-access static. We only check derefs of the - // temporary holding the static pointer to avoid duplicate errors - // . - if decl.internal && place.projection.first() == Some(&ProjectionElem::Deref) { - // If the projection root is an artifical local that we introduced when - // desugaring `static`, give a more specific error message - // (avoid the general "raw pointer" clause below, that would only be confusing). - if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { - if self.tcx.is_mutable_static(def_id) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfMutableStatic, - ); - return; - } else if self.tcx.is_foreign_item(def_id) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfExternStatic, - ); - return; - } - } - } - - // Check for raw pointer `Deref`. - for (base, proj) in place.iter_projections() { - if proj == ProjectionElem::Deref { - let base_ty = base.ty(self.body, self.tcx).ty; - if base_ty.is_unsafe_ptr() { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::DerefOfRawPointer, - ) - } - } - } - - // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes - // whether we *read* the union field or potentially *write* to it (if this place is being assigned to). - let mut saw_deref = false; - for (base, proj) in place.iter_projections().rev() { - if proj == ProjectionElem::Deref { - saw_deref = true; - continue; - } - - let base_ty = base.ty(self.body, self.tcx).ty; - if base_ty.is_union() { - // If we did not hit a `Deref` yet and the overall place use is an assignment, the - // rules are different. - let assign_to_field = !saw_deref - && matches!( - context, - PlaceContext::MutatingUse( - MutatingUseContext::Store - | MutatingUseContext::Drop - | MutatingUseContext::AsmOutput - ) - ); - // If this is just an assignment, determine if the assigned type needs dropping. - if assign_to_field { - // We have to check the actual type of the assignment, as that determines if the - // old value is being dropped. - let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; - // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. - let manually_drop = assigned_ty - .ty_adt_def() - .map_or(false, |adt_def| adt_def.is_manually_drop()); - let nodrop = manually_drop - || assigned_ty.is_copy_modulo_regions( - self.tcx.at(self.source_info.span), - self.param_env, - ); - if !nodrop { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::AssignToDroppingUnionField, - ); - } else { - // write to non-drop union field, safe - } - } else { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::AccessToUnionField, - ) - } - } - } - } -} - -impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { - fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) { - // Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such. - assert_ne!(kind, UnsafetyViolationKind::UnsafeFn); - - let source_info = self.source_info; - let lint_root = self.body.source_scopes[self.source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; - self.register_violations( - &[UnsafetyViolation { source_info, lint_root, kind, details }], - &[], - ); - } - - fn register_violations( - &mut self, - violations: &[UnsafetyViolation], - unsafe_blocks: &[(hir::HirId, bool)], - ) { - let safety = self.body.source_scopes[self.source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .safety; - let within_unsafe = match safety { - // `unsafe` blocks are required in safe code - Safety::Safe => { - for violation in violations { - match violation.kind { - UnsafetyViolationKind::General => {} - UnsafetyViolationKind::UnsafeFn => { - bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") - } - } - if !self.violations.contains(violation) { - self.violations.push(*violation) - } - } - false - } - // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s - Safety::FnUnsafe => { - for violation in violations { - let mut violation = *violation; - - violation.kind = UnsafetyViolationKind::UnsafeFn; - if !self.violations.contains(&violation) { - self.violations.push(violation) - } - } - false - } - Safety::BuiltinUnsafe => true, - Safety::ExplicitUnsafe(hir_id) => { - // mark unsafe block as used if there are any unsafe operations inside - if !violations.is_empty() { - self.used_unsafe.insert(hir_id); - } - true - } - }; - self.inherited_blocks.extend( - unsafe_blocks.iter().map(|&(hir_id, is_used)| (hir_id, is_used && !within_unsafe)), - ); - } - fn check_mut_borrowing_layout_constrained_field( - &mut self, - place: Place<'tcx>, - is_mut_use: bool, - ) { - for (place_base, elem) in place.iter_projections().rev() { - match elem { - // Modifications behind a dereference don't affect the value of - // the pointer. - ProjectionElem::Deref => return, - ProjectionElem::Field(..) => { - let ty = place_base.ty(&self.body.local_decls, self.tcx).ty; - if let ty::Adt(def, _) = ty.kind() { - if self.tcx.layout_scalar_valid_range(def.did) - != (Bound::Unbounded, Bound::Unbounded) - { - let details = if is_mut_use { - UnsafetyViolationDetails::MutationOfLayoutConstrainedField - - // Check `is_freeze` as late as possible to avoid cycle errors - // with opaque types. - } else if !place - .ty(self.body, self.tcx) - .ty - .is_freeze(self.tcx.at(self.source_info.span), self.param_env) - { - UnsafetyViolationDetails::BorrowOfLayoutConstrainedField - } else { - continue; - }; - self.require_unsafe(UnsafetyViolationKind::General, details); - } - } - } - _ => {} - } - } - } - - /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether - /// the called function has target features the calling function hasn't. - fn check_target_features(&mut self, func_did: DefId) { - // Unsafety isn't required on wasm targets. For more information see - // the corresponding check in typeck/src/collect.rs - if self.tcx.sess.target.options.is_like_wasm { - return; - } - - let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; - let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features; - - // Is `callee_features` a subset of `calling_features`? - if !callee_features.iter().all(|feature| self_features.contains(feature)) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::CallToFunctionWith, - ) - } - } -} - -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { - unsafety_check_result: |tcx, def_id| { - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.unsafety_check_result_for_const_arg(def) - } else { - unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id)) - } - }, - unsafety_check_result_for_const_arg: |tcx, (did, param_did)| { - unsafety_check_result( - tcx, - ty::WithOptConstParam { did, const_param_did: Some(param_did) }, - ) - }, - ..*providers - }; -} - -struct UnusedUnsafeVisitor<'a> { - used_unsafe: &'a FxHashSet, - unsafe_blocks: &'a mut Vec<(hir::HirId, bool)>, -} - -impl<'a, 'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { - intravisit::walk_block(self, block); - - if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules { - self.unsafe_blocks.push((block.hir_id, self.used_unsafe.contains(&block.hir_id))); - } - } -} - -fn check_unused_unsafe( - tcx: TyCtxt<'_>, - def_id: LocalDefId, - used_unsafe: &FxHashSet, - unsafe_blocks: &mut Vec<(hir::HirId, bool)>, -) { - let body_id = tcx.hir().maybe_body_owned_by(tcx.hir().local_def_id_to_hir_id(def_id)); - - let body_id = match body_id { - Some(body) => body, - None => { - debug!("check_unused_unsafe({:?}) - no body found", def_id); - return; - } - }; - let body = tcx.hir().body(body_id); - debug!("check_unused_unsafe({:?}, body={:?}, used_unsafe={:?})", def_id, body, used_unsafe); - - let mut visitor = UnusedUnsafeVisitor { used_unsafe, unsafe_blocks }; - intravisit::Visitor::visit_body(&mut visitor, body); -} - -fn unsafety_check_result<'tcx>( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, -) -> &'tcx UnsafetyCheckResult { - debug!("unsafety_violations({:?})", def); - - // N.B., this borrow is valid because all the consumers of - // `mir_built` force this. - let body = &tcx.mir_built(def).borrow(); - - let param_env = tcx.param_env(def.did); - - let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env); - checker.visit_body(&body); - - check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks); - - tcx.arena.alloc(UnsafetyCheckResult { - violations: checker.violations.into(), - unsafe_blocks: checker.inherited_blocks.into(), - }) -} - -/// Returns the `HirId` for an enclosing scope that is also `unsafe`. -fn is_enclosed( - tcx: TyCtxt<'_>, - used_unsafe: &FxHashSet, - id: hir::HirId, - unsafe_op_in_unsafe_fn_allowed: bool, -) -> Option<(&'static str, hir::HirId)> { - let parent_id = tcx.hir().get_parent_node(id); - if parent_id != id { - if used_unsafe.contains(&parent_id) { - Some(("block", parent_id)) - } else if let Some(Node::Item(&hir::Item { - kind: hir::ItemKind::Fn(ref sig, _, _), .. - })) = tcx.hir().find(parent_id) - { - if sig.header.unsafety == hir::Unsafety::Unsafe && unsafe_op_in_unsafe_fn_allowed { - Some(("fn", parent_id)) - } else { - None - } - } else { - is_enclosed(tcx, used_unsafe, parent_id, unsafe_op_in_unsafe_fn_allowed) - } - } else { - None - } -} - -fn report_unused_unsafe(tcx: TyCtxt<'_>, used_unsafe: &FxHashSet, id: hir::HirId) { - let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id)); - tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, |lint| { - let msg = "unnecessary `unsafe` block"; - let mut db = lint.build(msg); - db.span_label(span, msg); - if let Some((kind, id)) = - is_enclosed(tcx, used_unsafe, id, unsafe_op_in_unsafe_fn_allowed(tcx, id)) - { - db.span_label( - tcx.sess.source_map().guess_head_span(tcx.hir().span(id)), - format!("because it's nested under this `unsafe` {}", kind), - ); - } - db.emit(); - }); -} - -pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug!("check_unsafety({:?})", def_id); - - // closures are handled by their parent fn. - if tcx.is_closure(def_id.to_def_id()) { - return; - } - - let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id); - - for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() { - let (description, note) = details.description_and_note(); - - // Report an error. - let unsafe_fn_msg = - if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" }; - - match kind { - UnsafetyViolationKind::General => { - // once - struct_span_err!( - tcx.sess, - source_info.span, - E0133, - "{} is unsafe and requires unsafe{} block", - description, - unsafe_fn_msg, - ) - .span_label(source_info.span, description) - .note(note) - .emit(); - } - UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir( - UNSAFE_OP_IN_UNSAFE_FN, - lint_root, - source_info.span, - |lint| { - lint.build(&format!( - "{} is unsafe and requires unsafe block (error E0133)", - description, - )) - .span_label(source_info.span, description) - .note(note) - .emit(); - }, - ), - } - } - - let (mut unsafe_used, mut unsafe_unused): (FxHashSet<_>, Vec<_>) = Default::default(); - for &(block_id, is_used) in unsafe_blocks.iter() { - if is_used { - unsafe_used.insert(block_id); - } else { - unsafe_unused.push(block_id); - } - } - // The unused unsafe blocks might not be in source order; sort them so that the unused unsafe - // error messages are properly aligned and the issue-45107 and lint-unused-unsafe tests pass. - unsafe_unused.sort_by_cached_key(|hir_id| tcx.hir().span(*hir_id)); - - for &block_id in &unsafe_unused { - report_unused_unsafe(tcx, &unsafe_used, block_id); - } -} - -fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool { - tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -//! This module provides a pass to replacing the following statements with -//! [`Nop`]s -//! -//! - [`AscribeUserType`] -//! - [`FakeRead`] -//! - [`Assign`] statements with a [`Shallow`] borrow -//! -//! The `CleanFakeReadsAndBorrows` "pass" is actually implemented as two -//! traversals (aka visits) of the input MIR. The first traversal, -//! `DeleteAndRecordFakeReads`, deletes the fake reads and finds the -//! temporaries read by [`ForMatchGuard`] reads, and `DeleteFakeBorrows` -//! deletes the initialization of those temporaries. -//! -//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType -//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow -//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead -//! [`Assign`]: rustc_middle::mir::StatementKind::Assign -//! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard -//! [`Nop`]: rustc_middle::mir::StatementKind::Nop - -use crate::transform::MirPass; -use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue}; -use rustc_middle::mir::{Statement, StatementKind}; -use rustc_middle::ty::TyCtxt; - -pub struct CleanupNonCodegenStatements; - -pub struct DeleteNonCodegenStatements<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mut delete = DeleteNonCodegenStatements { tcx }; - delete.visit_body(body); - body.user_type_annotations.raw.clear(); - - for decl in &mut body.local_decls { - decl.user_ty = None; - } - } -} - -impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { - match statement.kind { - StatementKind::AscribeUserType(..) - | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _))) - | StatementKind::FakeRead(..) => statement.make_nop(), - _ => (), - } - self.super_statement(statement, location); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_debuginfo.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_debuginfo.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_debuginfo.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_debuginfo.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -//! Finds locals which are assigned once to a const and unused except for debuginfo and converts -//! their debuginfo to use the const directly, allowing the local to be removed. - -use rustc_middle::{ - mir::{ - visit::{PlaceContext, Visitor}, - Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, - }, - ty::TyCtxt, -}; - -use crate::transform::MirPass; -use rustc_index::{bit_set::BitSet, vec::IndexVec}; - -pub struct ConstDebugInfo; - -impl<'tcx> MirPass<'tcx> for ConstDebugInfo { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { - return; - } - - trace!("running ConstDebugInfo on {:?}", body.source); - - for (local, constant) in find_optimization_oportunities(body) { - for debuginfo in &mut body.var_debug_info { - if let VarDebugInfoContents::Place(p) = debuginfo.value { - if p.local == local && p.projection.is_empty() { - trace!( - "changing debug info for {:?} from place {:?} to constant {:?}", - debuginfo.name, - p, - constant - ); - debuginfo.value = VarDebugInfoContents::Const(constant); - } - } - } - } - } -} - -struct LocalUseVisitor { - local_mutating_uses: IndexVec, - local_assignment_locations: IndexVec>, -} - -fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> { - let mut visitor = LocalUseVisitor { - local_mutating_uses: IndexVec::from_elem(0, &body.local_decls), - local_assignment_locations: IndexVec::from_elem(None, &body.local_decls), - }; - - visitor.visit_body(body); - - let mut locals_to_debuginfo = BitSet::new_empty(body.local_decls.len()); - for debuginfo in &body.var_debug_info { - if let VarDebugInfoContents::Place(p) = debuginfo.value { - if let Some(l) = p.as_local() { - locals_to_debuginfo.insert(l); - } - } - } - - let mut eligable_locals = Vec::new(); - for (local, mutating_uses) in visitor.local_mutating_uses.drain_enumerated(..) { - if mutating_uses != 1 || !locals_to_debuginfo.contains(local) { - continue; - } - - if let Some(location) = visitor.local_assignment_locations[local] { - let bb = &body[location.block]; - - // The value is assigned as the result of a call, not a constant - if bb.statements.len() == location.statement_index { - continue; - } - - if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(box c)))) = - &bb.statements[location.statement_index].kind - { - if let Some(local) = p.as_local() { - eligable_locals.push((local, *c)); - } - } - } - } - - eligable_locals -} - -impl<'tcx> Visitor<'tcx> for LocalUseVisitor { - fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { - if context.is_mutating_use() { - self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1); - - if context.is_place_assignment() { - self.local_assignment_locations[*local] = Some(location); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_goto.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_goto.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_goto.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_goto.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -//! This pass optimizes the following sequence -//! ```rust,ignore (example) -//! bb2: { -//! _2 = const true; -//! goto -> bb3; -//! } -//! -//! bb3: { -//! switchInt(_2) -> [false: bb4, otherwise: bb5]; -//! } -//! ``` -//! into -//! ```rust,ignore (example) -//! bb2: { -//! _2 = const true; -//! goto -> bb5; -//! } -//! ``` - -use crate::transform::MirPass; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; -use rustc_middle::{mir::visit::Visitor, ty::ParamEnv}; - -use super::simplify::{simplify_cfg, simplify_locals}; - -pub struct ConstGoto; - -impl<'tcx> MirPass<'tcx> for ConstGoto { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } - trace!("Running ConstGoto on {:?}", body.source); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let mut opt_finder = - ConstGotoOptimizationFinder { tcx, body, optimizations: vec![], param_env }; - opt_finder.visit_body(body); - let should_simplify = !opt_finder.optimizations.is_empty(); - for opt in opt_finder.optimizations { - let terminator = body.basic_blocks_mut()[opt.bb_with_goto].terminator_mut(); - let new_goto = TerminatorKind::Goto { target: opt.target_to_use_in_goto }; - debug!("SUCCESS: replacing `{:?}` with `{:?}`", terminator.kind, new_goto); - terminator.kind = new_goto; - } - - // if we applied optimizations, we potentially have some cfg to cleanup to - // make it easier for further passes - if should_simplify { - simplify_cfg(tcx, body); - simplify_locals(body, tcx); - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'a, 'tcx> { - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - let _: Option<_> = try { - let target = terminator.kind.as_goto()?; - // We only apply this optimization if the last statement is a const assignment - let last_statement = self.body.basic_blocks()[location.block].statements.last()?; - - if let (place, Rvalue::Use(Operand::Constant(_const))) = - last_statement.kind.as_assign()? - { - // We found a constant being assigned to `place`. - // Now check that the target of this Goto switches on this place. - let target_bb = &self.body.basic_blocks()[target]; - - // FIXME(simonvandel): We are conservative here when we don't allow - // any statements in the target basic block. - // This could probably be relaxed to allow `StorageDead`s which could be - // copied to the predecessor of this block. - if !target_bb.statements.is_empty() { - None? - } - - let target_bb_terminator = target_bb.terminator(); - let (discr, switch_ty, targets) = target_bb_terminator.kind.as_switch()?; - if discr.place() == Some(*place) { - // We now know that the Switch matches on the const place, and it is statementless - // Now find which value in the Switch matches the const value. - let const_value = - _const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?; - let found_value_idx_option = targets - .iter() - .enumerate() - .find(|(_, (value, _))| const_value == *value) - .map(|(idx, _)| idx); - - let target_to_use_in_goto = - if let Some(found_value_idx) = found_value_idx_option { - targets.iter().nth(found_value_idx).unwrap().1 - } else { - // If we did not find the const value in values, it must be the otherwise case - targets.otherwise() - }; - - self.optimizations.push(OptimizationToApply { - bb_with_goto: location.block, - target_to_use_in_goto, - }); - } - } - Some(()) - }; - - self.super_terminator(terminator, location); - } -} - -struct OptimizationToApply { - bb_with_goto: BasicBlock, - target_to_use_in_goto: BasicBlock, -} - -pub struct ConstGotoOptimizationFinder<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - param_env: ParamEnv<'tcx>, - optimizations: Vec, -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_prop.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_prop.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_prop.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/const_prop.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1312 +0,0 @@ -//! Propagates constants for early reporting of statically known -//! assertion failures - -use std::cell::Cell; - -use rustc_ast::Mutability; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def::DefKind; -use rustc_hir::HirId; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::visit::{ - MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, -}; -use rustc_middle::mir::{ - AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind, - Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, - StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, -}; -use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{ - self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable, -}; -use rustc_session::lint; -use rustc_span::{def_id::DefId, Span}; -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout}; -use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits; - -use crate::const_eval::ConstEvalErr; -use crate::interpret::{ - self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy, - Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy, - Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind, -}; -use crate::transform::MirPass; - -/// The maximum number of bytes that we'll allocate space for a local or the return value. -/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just -/// Severely regress performance. -const MAX_ALLOC_LIMIT: u64 = 1024; - -/// Macro for machine-specific `InterpError` without allocation. -/// (These will never be shown to the user, but they help diagnose ICEs.) -macro_rules! throw_machine_stop_str { - ($($tt:tt)*) => {{ - // We make a new local type for it. The type itself does not carry any information, - // but its vtable (for the `MachineStopType` trait) does. - struct Zst; - // Printing this type shows the desired string. - impl std::fmt::Display for Zst { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, $($tt)*) - } - } - impl rustc_middle::mir::interpret::MachineStopType for Zst {} - throw_machine_stop!(Zst) - }}; -} - -pub struct ConstProp; - -impl<'tcx> MirPass<'tcx> for ConstProp { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // will be evaluated by miri and produce its errors there - if body.source.promoted.is_some() { - return; - } - - use rustc_middle::hir::map::blocks::FnLikeNode; - let def_id = body.source.def_id().expect_local(); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); - let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst; - - // Only run const prop on functions, methods, closures and associated constants - if !is_fn_like && !is_assoc_const { - // skip anon_const/statics/consts because they'll be evaluated by miri anyway - trace!("ConstProp skipped for {:?}", def_id); - return; - } - - let is_generator = tcx.type_of(def_id.to_def_id()).is_generator(); - // FIXME(welseywiser) const prop doesn't work on generators because of query cycles - // computing their layout. - if is_generator { - trace!("ConstProp skipped for generator {:?}", def_id); - return; - } - - // Check if it's even possible to satisfy the 'where' clauses - // for this item. - // This branch will never be taken for any normal function. - // However, it's possible to `#!feature(trivial_bounds)]` to write - // a function with impossible to satisfy clauses, e.g.: - // `fn foo() where String: Copy {}` - // - // We don't usually need to worry about this kind of case, - // since we would get a compilation error if the user tried - // to call it. However, since we can do const propagation - // even without any calls to the function, we need to make - // sure that it even makes sense to try to evaluate the body. - // If there are unsatisfiable where clauses, then all bets are - // off, and we just give up. - // - // We manually filter the predicates, skipping anything that's not - // "global". We are in a potentially generic context - // (e.g. we are evaluating a function without substituting generic - // parameters, so this filtering serves two purposes: - // - // 1. We skip evaluating any predicates that we would - // never be able prove are unsatisfiable (e.g. `` - // 2. We avoid trying to normalize predicates involving generic - // parameters (e.g. `::MyItem`). This can confuse - // the normalization code (leading to cycle errors), since - // it's usually never invoked in this way. - let predicates = tcx - .predicates_of(def_id.to_def_id()) - .predicates - .iter() - .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None }); - if traits::impossible_predicates( - tcx, - traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(), - ) { - trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id); - return; - } - - trace!("ConstProp starting for {:?}", def_id); - - let dummy_body = &Body::new( - tcx, - body.source, - body.basic_blocks().clone(), - body.source_scopes.clone(), - body.local_decls.clone(), - Default::default(), - body.arg_count, - Default::default(), - body.span, - body.generator_kind(), - ); - - // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold - // constants, instead of just checking for const-folding succeeding. - // That would require a uniform one-def no-mutation analysis - // and RPO (or recursing when needing the value of a local). - let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx); - optimization_finder.visit_body(body); - - trace!("ConstProp done for {:?}", def_id); - } -} - -struct ConstPropMachine<'mir, 'tcx> { - /// The virtual call stack. - stack: Vec>, - /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end. - written_only_inside_own_block_locals: FxHashSet, - /// Locals that need to be cleared after every block terminates. - only_propagate_inside_block_locals: BitSet, - can_const_prop: IndexVec, -} - -impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { - fn new( - only_propagate_inside_block_locals: BitSet, - can_const_prop: IndexVec, - ) -> Self { - Self { - stack: Vec::new(), - written_only_inside_own_block_locals: Default::default(), - only_propagate_inside_block_locals, - can_const_prop, - } - } -} - -impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { - compile_time_machine!(<'mir, 'tcx>); - const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`) - - type MemoryKind = !; - - type MemoryExtra = (); - - fn load_mir( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _instance: ty::InstanceDef<'tcx>, - ) -> InterpResult<'tcx, &'tcx Body<'tcx>> { - throw_machine_stop_str!("calling functions isn't supported in ConstProp") - } - - fn find_mir_or_eval_fn( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _abi: Abi, - _args: &[OpTy<'tcx>], - _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, - _unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> { - Ok(None) - } - - fn call_intrinsic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _args: &[OpTy<'tcx>], - _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, - _unwind: StackPopUnwind, - ) -> InterpResult<'tcx> { - throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") - } - - fn assert_panic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _msg: &rustc_middle::mir::AssertMessage<'tcx>, - _unwind: Option, - ) -> InterpResult<'tcx> { - bug!("panics terminators are not evaluated in ConstProp") - } - - fn binary_ptr_op( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _bin_op: BinOp, - _left: &ImmTy<'tcx>, - _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - // We can't do this because aliasing of memory can differ between const eval and llvm - throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") - } - - fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _dest: &PlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - throw_machine_stop_str!("can't const prop heap allocations") - } - - fn access_local( - _ecx: &InterpCx<'mir, 'tcx, Self>, - frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, - local: Local, - ) -> InterpResult<'tcx, InterpOperand> { - let l = &frame.locals[local]; - - if l.value == LocalValue::Uninitialized { - throw_machine_stop_str!("tried to access an uninitialized local") - } - - l.access() - } - - fn access_local_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - frame: usize, - local: Local, - ) -> InterpResult<'tcx, Result<&'a mut LocalValue, MemPlace>> - { - if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { - throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") - } - if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) { - trace!( - "mutating local {:?} which is restricted to its block. \ - Will remove it from const-prop after block is finished.", - local - ); - ecx.machine.written_only_inside_own_block_locals.insert(local); - } - ecx.machine.stack[frame].locals[local].access_mut() - } - - fn before_access_global( - _memory_extra: &(), - _alloc_id: AllocId, - allocation: &Allocation, - _static_def_id: Option, - is_write: bool, - ) -> InterpResult<'tcx> { - if is_write { - throw_machine_stop_str!("can't write to global"); - } - // If the static allocation is mutable, then we can't const prop it as its content - // might be different at runtime. - if allocation.mutability == Mutability::Mut { - throw_machine_stop_str!("can't access mutable globals in ConstProp"); - } - - Ok(()) - } - - #[inline(always)] - fn init_frame_extra( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { - Ok(frame) - } - - #[inline(always)] - fn stack( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } -} - -/// Finds optimization opportunities on the MIR. -struct ConstPropagator<'mir, 'tcx> { - ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - // FIXME(eddyb) avoid cloning these two fields more than once, - // by accessing them through `ecx` instead. - source_scopes: IndexVec>, - local_decls: IndexVec>, - // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store - // the last known `SourceInfo` here and just keep revisiting it. - source_info: Option, -} - -impl<'mir, 'tcx> LayoutOf<'tcx> for ConstPropagator<'mir, 'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = Result, LayoutError<'tcx>>; - - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)) - } -} - -impl<'mir, 'tcx> HasDataLayout for ConstPropagator<'mir, 'tcx> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - &self.tcx.data_layout - } -} - -impl<'mir, 'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> { - #[inline] - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } -} - -impl<'mir, 'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'mir, 'tcx> { - #[inline] - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } -} - -impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { - fn new( - body: &Body<'tcx>, - dummy_body: &'mir Body<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> ConstPropagator<'mir, 'tcx> { - let def_id = body.source.def_id(); - let substs = &InternalSubsts::identity_for_item(tcx, def_id); - let param_env = tcx.param_env_reveal_all_normalized(def_id); - - let span = tcx.def_span(def_id); - // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts - // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in - // `layout_of` query invocations. - let can_const_prop = CanConstProp::check(tcx, param_env, body); - let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len()); - for (l, mode) in can_const_prop.iter_enumerated() { - if *mode == ConstPropMode::OnlyInsideOwnBlock { - only_propagate_inside_block_locals.insert(l); - } - } - let mut ecx = InterpCx::new( - tcx, - span, - param_env, - ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop), - (), - ); - - let ret = ecx - .layout_of(body.return_ty().subst(tcx, substs)) - .ok() - // Don't bother allocating memory for ZST types which have no values - // or for large values. - .filter(|ret_layout| { - !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) - }) - .map(|ret_layout| { - ecx.allocate(ret_layout, MemoryKind::Stack) - .expect("couldn't perform small allocation") - .into() - }); - - ecx.push_stack_frame( - Instance::new(def_id, substs), - dummy_body, - ret.as_ref(), - StackPopCleanup::None { cleanup: false }, - ) - .expect("failed to push initial stack frame"); - - ConstPropagator { - ecx, - tcx, - param_env, - // FIXME(eddyb) avoid cloning these two fields more than once, - // by accessing them through `ecx` instead. - source_scopes: body.source_scopes.clone(), - //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it - local_decls: body.local_decls.clone(), - source_info: None, - } - } - - fn get_const(&self, place: Place<'tcx>) -> Option> { - let op = match self.ecx.eval_place_to_op(place, None) { - Ok(op) => op, - Err(e) => { - trace!("get_const failed: {}", e); - return None; - } - }; - - // Try to read the local as an immediate so that if it is representable as a scalar, we can - // handle it as such, but otherwise, just return the value as is. - Some(match self.ecx.try_read_immediate(&op) { - Ok(Ok(imm)) => imm.into(), - _ => op, - }) - } - - /// Remove `local` from the pool of `Locals`. Allows writing to them, - /// but not reading from them anymore. - fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { - ecx.frame_mut().locals[local] = - LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) }; - } - - fn lint_root(&self, source_info: SourceInfo) -> Option { - source_info.scope.lint_root(&self.source_scopes) - } - - fn use_ecx(&mut self, f: F) -> Option - where - F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, - { - match f(self) { - Ok(val) => Some(val), - Err(error) => { - trace!("InterpCx operation failed: {:?}", error); - // Some errors shouldn't come up because creating them causes - // an allocation, which we should avoid. When that happens, - // dedicated error variants should be introduced instead. - assert!( - !error.kind().formatted_string(), - "const-prop encountered formatting error: {}", - error - ); - None - } - } - } - - /// Returns the value, if any, of evaluating `c`. - fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option> { - // FIXME we need to revisit this for #67176 - if c.definitely_needs_subst(self.tcx) { - return None; - } - - match self.ecx.mir_const_to_op(&c.literal, None) { - Ok(op) => Some(op), - Err(error) => { - let tcx = self.ecx.tcx.at(c.span); - let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); - if let Some(lint_root) = self.lint_root(source_info) { - let lint_only = match c.literal { - ConstantKind::Ty(ct) => match ct.val { - // Promoteds must lint and not error as the user didn't ask for them - ConstKind::Unevaluated(ty::Unevaluated { - def: _, - substs_: _, - promoted: Some(_), - }) => true, - // Out of backwards compatibility we cannot report hard errors in unused - // generic functions using associated constants of the generic parameters. - _ => c.literal.definitely_needs_subst(*tcx), - }, - ConstantKind::Val(_, ty) => ty.definitely_needs_subst(*tcx), - }; - if lint_only { - // Out of backwards compatibility we cannot report hard errors in unused - // generic functions using associated constants of the generic parameters. - err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span)); - } else { - err.report_as_error(tcx, "erroneous constant used"); - } - } else { - err.report_as_error(tcx, "erroneous constant used"); - } - None - } - } - } - - /// Returns the value, if any, of evaluating `place`. - fn eval_place(&mut self, place: Place<'tcx>) -> Option> { - trace!("eval_place(place={:?})", place); - self.use_ecx(|this| this.ecx.eval_place_to_op(place, None)) - } - - /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant` - /// or `eval_place`, depending on the variant of `Operand` used. - fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { - match *op { - Operand::Constant(ref c) => self.eval_constant(c, source_info), - Operand::Move(place) | Operand::Copy(place) => self.eval_place(place), - } - } - - fn report_assert_as_lint( - &self, - lint: &'static lint::Lint, - source_info: SourceInfo, - message: &'static str, - panic: AssertKind, - ) { - if let Some(lint_root) = self.lint_root(source_info) { - self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| { - let mut err = lint.build(message); - err.span_label(source_info.span, format!("{:?}", panic)); - err.emit() - }); - } - } - - fn check_unary_op( - &mut self, - op: UnOp, - arg: &Operand<'tcx>, - source_info: SourceInfo, - ) -> Option<()> { - if let (val, true) = self.use_ecx(|this| { - let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?; - let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?; - Ok((val, overflow)) - })? { - // `AssertKind` only has an `OverflowNeg` variant, so make sure that is - // appropriate to use. - assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); - self.report_assert_as_lint( - lint::builtin::ARITHMETIC_OVERFLOW, - source_info, - "this arithmetic operation will overflow", - AssertKind::OverflowNeg(val.to_const_int()), - ); - return None; - } - - Some(()) - } - - fn check_binary_op( - &mut self, - op: BinOp, - left: &Operand<'tcx>, - right: &Operand<'tcx>, - source_info: SourceInfo, - ) -> Option<()> { - let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?)); - let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?)); - // Check for exceeding shifts *even if* we cannot evaluate the LHS. - if op == BinOp::Shr || op == BinOp::Shl { - let r = r?; - // We need the type of the LHS. We cannot use `place_layout` as that is the type - // of the result, which for checked binops is not the same! - let left_ty = left.ty(&self.local_decls, self.tcx); - let left_size = self.ecx.layout_of(left_ty).ok()?.size; - let right_size = r.layout.size; - let r_bits = r.to_scalar().ok(); - let r_bits = r_bits.and_then(|r| r.to_bits(right_size).ok()); - if r_bits.map_or(false, |b| b >= left_size.bits() as u128) { - debug!("check_binary_op: reporting assert for {:?}", source_info); - self.report_assert_as_lint( - lint::builtin::ARITHMETIC_OVERFLOW, - source_info, - "this arithmetic operation will overflow", - AssertKind::Overflow( - op, - match l { - Some(l) => l.to_const_int(), - // Invent a dummy value, the diagnostic ignores it anyway - None => ConstInt::new( - ScalarInt::try_from_uint(1_u8, left_size).unwrap(), - left_ty.is_signed(), - left_ty.is_ptr_sized_integral(), - ), - }, - r.to_const_int(), - ), - ); - return None; - } - } - - if let (Some(l), Some(r)) = (&l, &r) { - // The remaining operators are handled through `overflowing_binary_op`. - if self.use_ecx(|this| { - let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?; - Ok(overflow) - })? { - self.report_assert_as_lint( - lint::builtin::ARITHMETIC_OVERFLOW, - source_info, - "this arithmetic operation will overflow", - AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), - ); - return None; - } - } - Some(()) - } - - fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) { - match *operand { - Operand::Copy(l) | Operand::Move(l) => { - if let Some(value) = self.get_const(l) { - if self.should_const_prop(&value) { - // FIXME(felix91gr): this code only handles `Scalar` cases. - // For now, we're not handling `ScalarPair` cases because - // doing so here would require a lot of code duplication. - // We should hopefully generalize `Operand` handling into a fn, - // and use it to do const-prop here and everywhere else - // where it makes sense. - if let interpret::Operand::Immediate(interpret::Immediate::Scalar( - ScalarMaybeUninit::Scalar(scalar), - )) = *value - { - *operand = self.operand_from_scalar( - scalar, - value.layout.ty, - self.source_info.unwrap().span, - ); - } - } - } - } - Operand::Constant(_) => (), - } - } - - fn const_prop( - &mut self, - rvalue: &Rvalue<'tcx>, - source_info: SourceInfo, - place: Place<'tcx>, - ) -> Option<()> { - // Perform any special handling for specific Rvalue types. - // Generally, checks here fall into one of two categories: - // 1. Additional checking to provide useful lints to the user - // - In this case, we will do some validation and then fall through to the - // end of the function which evals the assignment. - // 2. Working around bugs in other parts of the compiler - // - In this case, we'll return `None` from this function to stop evaluation. - match rvalue { - // Additional checking: give lints to the user if an overflow would occur. - // We do this here and not in the `Assert` terminator as that terminator is - // only sometimes emitted (overflow checks can be disabled), but we want to always - // lint. - Rvalue::UnaryOp(op, arg) => { - trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); - self.check_unary_op(*op, arg, source_info)?; - } - Rvalue::BinaryOp(op, box (left, right)) => { - trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); - self.check_binary_op(*op, left, right, source_info)?; - } - Rvalue::CheckedBinaryOp(op, box (left, right)) => { - trace!( - "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})", - op, - left, - right - ); - self.check_binary_op(*op, left, right, source_info)?; - } - - // Do not try creating references (#67862) - Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => { - trace!("skipping AddressOf | Ref for {:?}", place); - - // This may be creating mutable references or immutable references to cells. - // If that happens, the pointed to value could be mutated via that reference. - // Since we aren't tracking references, the const propagator loses track of what - // value the local has right now. - // Thus, all locals that have their reference taken - // must not take part in propagation. - Self::remove_const(&mut self.ecx, place.local); - - return None; - } - Rvalue::ThreadLocalRef(def_id) => { - trace!("skipping ThreadLocalRef({:?})", def_id); - - return None; - } - - // There's no other checking to do at this time. - Rvalue::Aggregate(..) - | Rvalue::Use(..) - | Rvalue::Repeat(..) - | Rvalue::Len(..) - | Rvalue::Cast(..) - | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(..) => {} - } - - // FIXME we need to revisit this for #67176 - if rvalue.definitely_needs_subst(self.tcx) { - return None; - } - - if self.tcx.sess.mir_opt_level() >= 4 { - self.eval_rvalue_with_identities(rvalue, place) - } else { - self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place)) - } - } - - // Attempt to use albegraic identities to eliminate constant expressions - fn eval_rvalue_with_identities( - &mut self, - rvalue: &Rvalue<'tcx>, - place: Place<'tcx>, - ) -> Option<()> { - self.use_ecx(|this| { - match rvalue { - Rvalue::BinaryOp(op, box (left, right)) - | Rvalue::CheckedBinaryOp(op, box (left, right)) => { - let l = this.ecx.eval_operand(left, None); - let r = this.ecx.eval_operand(right, None); - - let const_arg = match (l, r) { - (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?, - (Err(e), Err(_)) => return Err(e), - (Ok(_), Ok(_)) => { - this.ecx.eval_rvalue_into_place(rvalue, place)?; - return Ok(()); - } - }; - - let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?; - let dest = this.ecx.eval_place(place)?; - - match op { - BinOp::BitAnd => { - if arg_value == 0 { - this.ecx.write_immediate(*const_arg, &dest)?; - } - } - BinOp::BitOr => { - if arg_value == const_arg.layout.size.truncate(u128::MAX) - || (const_arg.layout.ty.is_bool() && arg_value == 1) - { - this.ecx.write_immediate(*const_arg, &dest)?; - } - } - BinOp::Mul => { - if const_arg.layout.ty.is_integral() && arg_value == 0 { - if let Rvalue::CheckedBinaryOp(_, _) = rvalue { - let val = Immediate::ScalarPair( - const_arg.to_scalar()?.into(), - Scalar::from_bool(false).into(), - ); - this.ecx.write_immediate(val, &dest)?; - } else { - this.ecx.write_immediate(*const_arg, &dest)?; - } - } - } - _ => { - this.ecx.eval_rvalue_into_place(rvalue, place)?; - } - } - } - _ => { - this.ecx.eval_rvalue_into_place(rvalue, place)?; - } - } - - Ok(()) - }) - } - - /// Creates a new `Operand::Constant` from a `Scalar` value - fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> { - Operand::Constant(Box::new(Constant { - span, - user_ty: None, - literal: ty::Const::from_scalar(self.tcx, scalar, ty).into(), - })) - } - - fn replace_with_const( - &mut self, - rval: &mut Rvalue<'tcx>, - value: &OpTy<'tcx>, - source_info: SourceInfo, - ) { - if let Rvalue::Use(Operand::Constant(c)) = rval { - match c.literal { - ConstantKind::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {} - _ => { - trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); - return; - } - } - } - - trace!("attempting to replace {:?} with {:?}", rval, value); - if let Err(e) = self.ecx.const_validate_operand( - value, - vec![], - // FIXME: is ref tracking too expensive? - // FIXME: what is the point of ref tracking if we do not even check the tracked refs? - &mut interpret::RefTracking::empty(), - CtfeValidationMode::Regular, - ) { - trace!("validation error, attempt failed: {:?}", e); - return; - } - - // FIXME> figure out what to do when try_read_immediate fails - let imm = self.use_ecx(|this| this.ecx.try_read_immediate(value)); - - if let Some(Ok(imm)) = imm { - match *imm { - interpret::Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar)) => { - *rval = Rvalue::Use(self.operand_from_scalar( - scalar, - value.layout.ty, - source_info.span, - )); - } - Immediate::ScalarPair( - ScalarMaybeUninit::Scalar(_), - ScalarMaybeUninit::Scalar(_), - ) => { - // Found a value represented as a pair. For now only do const-prop if the type - // of `rvalue` is also a tuple with two scalars. - // FIXME: enable the general case stated above ^. - let ty = &value.layout.ty; - // Only do it for tuples - if let ty::Tuple(substs) = ty.kind() { - // Only do it if tuple is also a pair with two scalars - if substs.len() == 2 { - let alloc = self.use_ecx(|this| { - let ty1 = substs[0].expect_ty(); - let ty2 = substs[1].expect_ty(); - let ty_is_scalar = |ty| { - this.ecx.layout_of(ty).ok().map(|layout| layout.abi.is_scalar()) - == Some(true) - }; - if ty_is_scalar(ty1) && ty_is_scalar(ty2) { - let alloc = this - .ecx - .intern_with_temp_alloc(value.layout, |ecx, dest| { - ecx.write_immediate(*imm, dest) - }) - .unwrap(); - Ok(Some(alloc)) - } else { - Ok(None) - } - }); - - if let Some(Some(alloc)) = alloc { - // Assign entire constant in a single statement. - // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`. - *rval = Rvalue::Use(Operand::Constant(Box::new(Constant { - span: source_info.span, - user_ty: None, - literal: self - .ecx - .tcx - .mk_const(ty::Const { - ty, - val: ty::ConstKind::Value(ConstValue::ByRef { - alloc, - offset: Size::ZERO, - }), - }) - .into(), - }))); - } - } - } - } - // Scalars or scalar pairs that contain undef values are assumed to not have - // successfully evaluated and are thus not propagated. - _ => {} - } - } - } - - /// Returns `true` if and only if this `op` should be const-propagated into. - fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool { - let mir_opt_level = self.tcx.sess.mir_opt_level(); - - if mir_opt_level == 0 { - return false; - } - - if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - OpTy: {:?}", op)) { - return false; - } - - match **op { - interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => { - s.try_to_int().is_ok() - } - interpret::Operand::Immediate(Immediate::ScalarPair( - ScalarMaybeUninit::Scalar(l), - ScalarMaybeUninit::Scalar(r), - )) => l.try_to_int().is_ok() && r.try_to_int().is_ok(), - _ => false, - } - } -} - -/// The mode that `ConstProp` is allowed to run in for a given `Local`. -#[derive(Clone, Copy, Debug, PartialEq)] -enum ConstPropMode { - /// The `Local` can be propagated into and reads of this `Local` can also be propagated. - FullConstProp, - /// The `Local` can only be propagated into and from its own block. - OnlyInsideOwnBlock, - /// The `Local` can be propagated into but reads cannot be propagated. - OnlyPropagateInto, - /// The `Local` cannot be part of propagation at all. Any statement - /// referencing it either for reading or writing will not get propagated. - NoPropagation, -} - -struct CanConstProp { - can_const_prop: IndexVec, - // False at the beginning. Once set, no more assignments are allowed to that local. - found_assignment: BitSet, - // Cache of locals' information - local_kinds: IndexVec, -} - -impl CanConstProp { - /// Returns true if `local` can be propagated - fn check( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - body: &Body<'tcx>, - ) -> IndexVec { - let mut cpv = CanConstProp { - can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls), - found_assignment: BitSet::new_empty(body.local_decls.len()), - local_kinds: IndexVec::from_fn_n( - |local| body.local_kind(local), - body.local_decls.len(), - ), - }; - for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { - let ty = body.local_decls[local].ty; - match tcx.layout_of(param_env.and(ty)) { - Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} - // Either the layout fails to compute, then we can't use this local anyway - // or the local is too large, then we don't want to. - _ => { - *val = ConstPropMode::NoPropagation; - continue; - } - } - // Cannot use args at all - // Cannot use locals because if x < y { y - x } else { x - y } would - // lint for x != y - // FIXME(oli-obk): lint variables until they are used in a condition - // FIXME(oli-obk): lint if return value is constant - if cpv.local_kinds[local] == LocalKind::Arg { - *val = ConstPropMode::OnlyPropagateInto; - trace!( - "local {:?} can't be const propagated because it's a function argument", - local - ); - } else if cpv.local_kinds[local] == LocalKind::Var { - *val = ConstPropMode::OnlyInsideOwnBlock; - trace!( - "local {:?} will only be propagated inside its block, because it's a user variable", - local - ); - } - } - cpv.visit_body(&body); - cpv.can_const_prop - } -} - -impl<'tcx> Visitor<'tcx> for CanConstProp { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { - use rustc_middle::mir::visit::PlaceContext::*; - match context { - // Projections are fine, because `&mut foo.x` will be caught by - // `MutatingUseContext::Borrow` elsewhere. - MutatingUse(MutatingUseContext::Projection) - // These are just stores, where the storing is not propagatable, but there may be later - // mutations of the same local via `Store` - | MutatingUse(MutatingUseContext::Call) - // Actual store that can possibly even propagate a value - | MutatingUse(MutatingUseContext::Store) => { - if !self.found_assignment.insert(local) { - match &mut self.can_const_prop[local] { - // If the local can only get propagated in its own block, then we don't have - // to worry about multiple assignments, as we'll nuke the const state at the - // end of the block anyway, and inside the block we overwrite previous - // states as applicable. - ConstPropMode::OnlyInsideOwnBlock => {} - ConstPropMode::NoPropagation => {} - ConstPropMode::OnlyPropagateInto => {} - other @ ConstPropMode::FullConstProp => { - trace!( - "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}", - local, other, - ); - *other = ConstPropMode::OnlyInsideOwnBlock; - } - } - } - } - // Reading constants is allowed an arbitrary number of times - NonMutatingUse(NonMutatingUseContext::Copy) - | NonMutatingUse(NonMutatingUseContext::Move) - | NonMutatingUse(NonMutatingUseContext::Inspect) - | NonMutatingUse(NonMutatingUseContext::Projection) - | NonUse(_) => {} - - // These could be propagated with a smarter analysis or just some careful thinking about - // whether they'd be fine right now. - MutatingUse(MutatingUseContext::AsmOutput) - | MutatingUse(MutatingUseContext::Yield) - | MutatingUse(MutatingUseContext::Drop) - | MutatingUse(MutatingUseContext::Retag) - // These can't ever be propagated under any scheme, as we can't reason about indirect - // mutation. - | NonMutatingUse(NonMutatingUseContext::SharedBorrow) - | NonMutatingUse(NonMutatingUseContext::ShallowBorrow) - | NonMutatingUse(NonMutatingUseContext::UniqueBorrow) - | NonMutatingUse(NonMutatingUseContext::AddressOf) - | MutatingUse(MutatingUseContext::Borrow) - | MutatingUse(MutatingUseContext::AddressOf) => { - trace!("local {:?} can't be propagaged because it's used: {:?}", local, context); - self.can_const_prop[local] = ConstPropMode::NoPropagation; - } - } - } -} - -impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_body(&mut self, body: &mut Body<'tcx>) { - for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() { - self.visit_basic_block_data(bb, data); - } - } - - fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { - self.super_operand(operand, location); - - // Only const prop copies and moves on `mir_opt_level=3` as doing so - // currently slightly increases compile time in some cases. - if self.tcx.sess.mir_opt_level() >= 3 { - self.propagate_operand(operand) - } - } - - fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { - trace!("visit_constant: {:?}", constant); - self.super_constant(constant, location); - self.eval_constant(constant, self.source_info.unwrap()); - } - - fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { - trace!("visit_statement: {:?}", statement); - let source_info = statement.source_info; - self.source_info = Some(source_info); - if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind { - let can_const_prop = self.ecx.machine.can_const_prop[place.local]; - if let Some(()) = self.const_prop(rval, source_info, place) { - // This will return None if the above `const_prop` invocation only "wrote" a - // type whose creation requires no write. E.g. a generator whose initial state - // consists solely of uninitialized memory (so it doesn't capture any locals). - if let Some(ref value) = self.get_const(place) { - if self.should_const_prop(value) { - trace!("replacing {:?} with {:?}", rval, value); - self.replace_with_const(rval, value, source_info); - if can_const_prop == ConstPropMode::FullConstProp - || can_const_prop == ConstPropMode::OnlyInsideOwnBlock - { - trace!("propagated into {:?}", place); - } - } - } - match can_const_prop { - ConstPropMode::OnlyInsideOwnBlock => { - trace!( - "found local restricted to its block. \ - Will remove it from const-prop after block is finished. Local: {:?}", - place.local - ); - } - ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => { - trace!("can't propagate into {:?}", place); - if place.local != RETURN_PLACE { - Self::remove_const(&mut self.ecx, place.local); - } - } - ConstPropMode::FullConstProp => {} - } - } else { - // Const prop failed, so erase the destination, ensuring that whatever happens - // from here on, does not know about the previous value. - // This is important in case we have - // ```rust - // let mut x = 42; - // x = SOME_MUTABLE_STATIC; - // // x must now be uninit - // ``` - // FIXME: we overzealously erase the entire local, because that's easier to - // implement. - trace!( - "propagation into {:?} failed. - Nuking the entire site from orbit, it's the only way to be sure", - place, - ); - Self::remove_const(&mut self.ecx, place.local); - } - } else { - match statement.kind { - StatementKind::SetDiscriminant { ref place, .. } => { - match self.ecx.machine.can_const_prop[place.local] { - ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => { - if self.use_ecx(|this| this.ecx.statement(statement)).is_some() { - trace!("propped discriminant into {:?}", place); - } else { - Self::remove_const(&mut self.ecx, place.local); - } - } - ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => { - Self::remove_const(&mut self.ecx, place.local); - } - } - } - StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { - let frame = self.ecx.frame_mut(); - frame.locals[local].value = - if let StatementKind::StorageLive(_) = statement.kind { - LocalValue::Uninitialized - } else { - LocalValue::Dead - }; - } - _ => {} - } - } - - self.super_statement(statement, location); - } - - fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - let source_info = terminator.source_info; - self.source_info = Some(source_info); - self.super_terminator(terminator, location); - match &mut terminator.kind { - TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => { - if let Some(ref value) = self.eval_operand(&cond, source_info) { - trace!("assertion on {:?} should be {:?}", value, expected); - let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected)); - let value_const = self.ecx.read_scalar(&value).unwrap(); - if expected != value_const { - enum DbgVal { - Val(T), - Underscore, - } - impl std::fmt::Debug for DbgVal { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Val(val) => val.fmt(fmt), - Self::Underscore => fmt.write_str("_"), - } - } - } - let mut eval_to_int = |op| { - // This can be `None` if the lhs wasn't const propagated and we just - // triggered the assert on the value of the rhs. - self.eval_operand(op, source_info).map_or(DbgVal::Underscore, |op| { - DbgVal::Val(self.ecx.read_immediate(&op).unwrap().to_const_int()) - }) - }; - let msg = match msg { - AssertKind::DivisionByZero(op) => { - Some(AssertKind::DivisionByZero(eval_to_int(op))) - } - AssertKind::RemainderByZero(op) => { - Some(AssertKind::RemainderByZero(eval_to_int(op))) - } - AssertKind::BoundsCheck { ref len, ref index } => { - let len = eval_to_int(len); - let index = eval_to_int(index); - Some(AssertKind::BoundsCheck { len, index }) - } - // Overflow is are already covered by checks on the binary operators. - AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => None, - // Need proper const propagator for these. - _ => None, - }; - // Poison all places this operand references so that further code - // doesn't use the invalid value - match cond { - Operand::Move(ref place) | Operand::Copy(ref place) => { - Self::remove_const(&mut self.ecx, place.local); - } - Operand::Constant(_) => {} - } - if let Some(msg) = msg { - self.report_assert_as_lint( - lint::builtin::UNCONDITIONAL_PANIC, - source_info, - "this operation will panic at runtime", - msg, - ); - } - } else { - if self.should_const_prop(value) { - if let ScalarMaybeUninit::Scalar(scalar) = value_const { - *cond = self.operand_from_scalar( - scalar, - self.tcx.types.bool, - source_info.span, - ); - } - } - } - } - } - TerminatorKind::SwitchInt { ref mut discr, .. } => { - // FIXME: This is currently redundant with `visit_operand`, but sadly - // always visiting operands currently causes a perf regression in LLVM codegen, so - // `visit_operand` currently only runs for propagates places for `mir_opt_level=4`. - self.propagate_operand(discr) - } - // None of these have Operands to const-propagate. - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => {} - // Every argument in our function calls have already been propagated in `visit_operand`. - // - // NOTE: because LLVM codegen gives slight performance regressions with it, so this is - // gated on `mir_opt_level=3`. - TerminatorKind::Call { .. } => {} - } - - // We remove all Locals which are restricted in propagation to their containing blocks and - // which were modified in the current block. - // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. - let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); - for &local in locals.iter() { - Self::remove_const(&mut self.ecx, local); - } - locals.clear(); - // Put it back so we reuse the heap of the storage - self.ecx.machine.written_only_inside_own_block_locals = locals; - if cfg!(debug_assertions) { - // Ensure we are correctly erasing locals with the non-debug-assert logic. - for local in self.ecx.machine.only_propagate_inside_block_locals.iter() { - assert!( - self.get_const(local.into()).is_none() - || self - .layout_of(self.local_decls[local].ty) - .map_or(true, |layout| layout.is_zst()) - ) - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/counters.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/counters.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/counters.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/counters.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,614 +0,0 @@ -use super::Error; - -use super::debug; -use super::graph; -use super::spans; - -use debug::{DebugCounters, NESTED_INDENT}; -use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops}; -use spans::CoverageSpan; - -use rustc_data_structures::graph::WithNumNodes; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::coverage::*; - -/// Manages the counter and expression indexes/IDs to generate `CoverageKind` components for MIR -/// `Coverage` statements. -pub(super) struct CoverageCounters { - function_source_hash: u64, - next_counter_id: u32, - num_expressions: u32, - pub debug_counters: DebugCounters, -} - -impl CoverageCounters { - pub fn new(function_source_hash: u64) -> Self { - Self { - function_source_hash, - next_counter_id: CounterValueReference::START.as_u32(), - num_expressions: 0, - debug_counters: DebugCounters::new(), - } - } - - /// Activate the `DebugCounters` data structures, to provide additional debug formatting - /// features when formatting `CoverageKind` (counter) values. - pub fn enable_debug(&mut self) { - self.debug_counters.enable(); - } - - /// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or - /// indirectly associated with `CoverageSpans`, and returns additional `Expression`s - /// representing intermediate values. - pub fn make_bcb_counters( - &mut self, - basic_coverage_blocks: &mut CoverageGraph, - coverage_spans: &Vec, - ) -> Result, Error> { - let mut bcb_counters = BcbCounters::new(self, basic_coverage_blocks); - bcb_counters.make_bcb_counters(coverage_spans) - } - - fn make_counter(&mut self, debug_block_label_fn: F) -> CoverageKind - where - F: Fn() -> Option, - { - let counter = CoverageKind::Counter { - function_source_hash: self.function_source_hash, - id: self.next_counter(), - }; - if self.debug_counters.is_enabled() { - self.debug_counters.add_counter(&counter, (debug_block_label_fn)()); - } - counter - } - - fn make_expression( - &mut self, - lhs: ExpressionOperandId, - op: Op, - rhs: ExpressionOperandId, - debug_block_label_fn: F, - ) -> CoverageKind - where - F: Fn() -> Option, - { - let id = self.next_expression(); - let expression = CoverageKind::Expression { id, lhs, op, rhs }; - if self.debug_counters.is_enabled() { - self.debug_counters.add_counter(&expression, (debug_block_label_fn)()); - } - expression - } - - pub fn make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind { - let some_debug_block_label = if self.debug_counters.is_enabled() { - self.debug_counters.some_block_label(counter_operand).cloned() - } else { - None - }; - self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO, || { - some_debug_block_label.clone() - }) - } - - /// Counter IDs start from one and go up. - fn next_counter(&mut self) -> CounterValueReference { - assert!(self.next_counter_id < u32::MAX - self.num_expressions); - let next = self.next_counter_id; - self.next_counter_id += 1; - CounterValueReference::from(next) - } - - /// Expression IDs start from u32::MAX and go down because an Expression can reference - /// (add or subtract counts) of both Counter regions and Expression regions. The counter - /// expression operand IDs must be unique across both types. - fn next_expression(&mut self) -> InjectedExpressionId { - assert!(self.next_counter_id < u32::MAX - self.num_expressions); - let next = u32::MAX - self.num_expressions; - self.num_expressions += 1; - InjectedExpressionId::from(next) - } -} - -/// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be -/// injected with `CoverageSpan`s. `Expressions` have no runtime overhead, so if a viable expression -/// (adding or subtracting two other counters or expressions) can compute the same result as an -/// embedded counter, an `Expression` should be used. -struct BcbCounters<'a> { - coverage_counters: &'a mut CoverageCounters, - basic_coverage_blocks: &'a mut CoverageGraph, -} - -impl<'a> BcbCounters<'a> { - fn new( - coverage_counters: &'a mut CoverageCounters, - basic_coverage_blocks: &'a mut CoverageGraph, - ) -> Self { - Self { coverage_counters, basic_coverage_blocks } - } - - /// If two `BasicCoverageBlock`s branch from another `BasicCoverageBlock`, one of the branches - /// can be counted by `Expression` by subtracting the other branch from the branching - /// block. Otherwise, the `BasicCoverageBlock` executed the least should have the `Counter`. - /// One way to predict which branch executes the least is by considering loops. A loop is exited - /// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost - /// always executed less than the branch that does not exit the loop. - /// - /// Returns any non-code-span expressions created to represent intermediate values (such as to - /// add two counters so the result can be subtracted from another counter), or an Error with - /// message for subsequent debugging. - fn make_bcb_counters( - &mut self, - coverage_spans: &[CoverageSpan], - ) -> Result, Error> { - debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock"); - let num_bcbs = self.basic_coverage_blocks.num_nodes(); - let mut collect_intermediate_expressions = Vec::with_capacity(num_bcbs); - - let mut bcbs_with_coverage = BitSet::new_empty(num_bcbs); - for covspan in coverage_spans { - bcbs_with_coverage.insert(covspan.bcb); - } - - // Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated - // `CoverageSpan`, add a counter. If the `BasicCoverageBlock` branches, add a counter or - // expression to each branch `BasicCoverageBlock` (if the branch BCB has only one incoming - // edge) or edge from the branching BCB to the branch BCB (if the branch BCB has multiple - // incoming edges). - // - // The `TraverseCoverageGraphWithLoops` traversal ensures that, when a loop is encountered, - // all `BasicCoverageBlock` nodes in the loop are visited before visiting any node outside - // the loop. The `traversal` state includes a `context_stack`, providing a way to know if - // the current BCB is in one or more nested loops or not. - let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks); - while let Some(bcb) = traversal.next(self.basic_coverage_blocks) { - if bcbs_with_coverage.contains(bcb) { - debug!("{:?} has at least one `CoverageSpan`. Get or make its counter", bcb); - let branching_counter_operand = - self.get_or_make_counter_operand(bcb, &mut collect_intermediate_expressions)?; - - if self.bcb_needs_branch_counters(bcb) { - self.make_branch_counters( - &mut traversal, - bcb, - branching_counter_operand, - &mut collect_intermediate_expressions, - )?; - } - } else { - debug!( - "{:?} does not have any `CoverageSpan`s. A counter will only be added if \ - and when a covered BCB has an expression dependency.", - bcb, - ); - } - } - - if traversal.is_complete() { - Ok(collect_intermediate_expressions) - } else { - Error::from_string(format!( - "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}", - traversal.unvisited(), - )) - } - } - - fn make_branch_counters( - &mut self, - traversal: &mut TraverseCoverageGraphWithLoops, - branching_bcb: BasicCoverageBlock, - branching_counter_operand: ExpressionOperandId, - collect_intermediate_expressions: &mut Vec, - ) -> Result<(), Error> { - let branches = self.bcb_branches(branching_bcb); - debug!( - "{:?} has some branch(es) without counters:\n {}", - branching_bcb, - branches - .iter() - .map(|branch| { - format!("{:?}: {:?}", branch, branch.counter(&self.basic_coverage_blocks)) - }) - .collect::>() - .join("\n "), - ); - - // Use the `traversal` state to decide if a subset of the branches exit a loop, making it - // likely that branch is executed less than branches that do not exit the same loop. In this - // case, any branch that does not exit the loop (and has not already been assigned a - // counter) should be counted by expression, if possible. (If a preferred expression branch - // is not selected based on the loop context, select any branch without an existing - // counter.) - let expression_branch = self.choose_preferred_expression_branch(traversal, &branches); - - // Assign a Counter or Expression to each branch, plus additional `Expression`s, as needed, - // to sum up intermediate results. - let mut some_sumup_counter_operand = None; - for branch in branches { - // Skip the selected `expression_branch`, if any. It's expression will be assigned after - // all others. - if branch != expression_branch { - let branch_counter_operand = if branch.is_only_path_to_target() { - debug!( - " {:?} has only one incoming edge (from {:?}), so adding a \ - counter", - branch, branching_bcb - ); - self.get_or_make_counter_operand( - branch.target_bcb, - collect_intermediate_expressions, - )? - } else { - debug!(" {:?} has multiple incoming edges, so adding an edge counter", branch); - self.get_or_make_edge_counter_operand( - branching_bcb, - branch.target_bcb, - collect_intermediate_expressions, - )? - }; - if let Some(sumup_counter_operand) = - some_sumup_counter_operand.replace(branch_counter_operand) - { - let intermediate_expression = self.coverage_counters.make_expression( - branch_counter_operand, - Op::Add, - sumup_counter_operand, - || None, - ); - debug!( - " [new intermediate expression: {}]", - self.format_counter(&intermediate_expression) - ); - let intermediate_expression_operand = intermediate_expression.as_operand_id(); - collect_intermediate_expressions.push(intermediate_expression); - some_sumup_counter_operand.replace(intermediate_expression_operand); - } - } - } - - // Assign the final expression to the `expression_branch` by subtracting the total of all - // other branches from the counter of the branching BCB. - let sumup_counter_operand = - some_sumup_counter_operand.expect("sumup_counter_operand should have a value"); - debug!( - "Making an expression for the selected expression_branch: {:?} \ - (expression_branch predecessors: {:?})", - expression_branch, - self.bcb_predecessors(expression_branch.target_bcb), - ); - let expression = self.coverage_counters.make_expression( - branching_counter_operand, - Op::Subtract, - sumup_counter_operand, - || Some(format!("{:?}", expression_branch)), - ); - debug!("{:?} gets an expression: {}", expression_branch, self.format_counter(&expression)); - let bcb = expression_branch.target_bcb; - if expression_branch.is_only_path_to_target() { - self.basic_coverage_blocks[bcb].set_counter(expression)?; - } else { - self.basic_coverage_blocks[bcb].set_edge_counter_from(branching_bcb, expression)?; - } - Ok(()) - } - - fn get_or_make_counter_operand( - &mut self, - bcb: BasicCoverageBlock, - collect_intermediate_expressions: &mut Vec, - ) -> Result { - self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1) - } - - fn recursive_get_or_make_counter_operand( - &mut self, - bcb: BasicCoverageBlock, - collect_intermediate_expressions: &mut Vec, - debug_indent_level: usize, - ) -> Result { - // If the BCB already has a counter, return it. - if let Some(counter_kind) = self.basic_coverage_blocks[bcb].counter() { - debug!( - "{}{:?} already has a counter: {}", - NESTED_INDENT.repeat(debug_indent_level), - bcb, - self.format_counter(counter_kind), - ); - return Ok(counter_kind.as_operand_id()); - } - - // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`). - // Also, a BCB that loops back to itself gets a simple `Counter`. This may indicate the - // program results in a tight infinite loop, but it should still compile. - let one_path_to_target = self.bcb_has_one_path_to_target(bcb); - if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) { - let counter_kind = self.coverage_counters.make_counter(|| Some(format!("{:?}", bcb))); - if one_path_to_target { - debug!( - "{}{:?} gets a new counter: {}", - NESTED_INDENT.repeat(debug_indent_level), - bcb, - self.format_counter(&counter_kind), - ); - } else { - debug!( - "{}{:?} has itself as its own predecessor. It can't be part of its own \ - Expression sum, so it will get its own new counter: {}. (Note, the compiled \ - code will generate an infinite loop.)", - NESTED_INDENT.repeat(debug_indent_level), - bcb, - self.format_counter(&counter_kind), - ); - } - return self.basic_coverage_blocks[bcb].set_counter(counter_kind); - } - - // A BCB with multiple incoming edges can compute its count by `Expression`, summing up the - // counters and/or expressions of its incoming edges. This will recursively get or create - // counters for those incoming edges first, then call `make_expression()` to sum them up, - // with additional intermediate expressions as needed. - let mut predecessors = self.bcb_predecessors(bcb).clone().into_iter(); - debug!( - "{}{:?} has multiple incoming edges and will get an expression that sums them up...", - NESTED_INDENT.repeat(debug_indent_level), - bcb, - ); - let first_edge_counter_operand = self.recursive_get_or_make_edge_counter_operand( - predecessors.next().unwrap(), - bcb, - collect_intermediate_expressions, - debug_indent_level + 1, - )?; - let mut some_sumup_edge_counter_operand = None; - for predecessor in predecessors { - let edge_counter_operand = self.recursive_get_or_make_edge_counter_operand( - predecessor, - bcb, - collect_intermediate_expressions, - debug_indent_level + 1, - )?; - if let Some(sumup_edge_counter_operand) = - some_sumup_edge_counter_operand.replace(edge_counter_operand) - { - let intermediate_expression = self.coverage_counters.make_expression( - sumup_edge_counter_operand, - Op::Add, - edge_counter_operand, - || None, - ); - debug!( - "{}new intermediate expression: {}", - NESTED_INDENT.repeat(debug_indent_level), - self.format_counter(&intermediate_expression) - ); - let intermediate_expression_operand = intermediate_expression.as_operand_id(); - collect_intermediate_expressions.push(intermediate_expression); - some_sumup_edge_counter_operand.replace(intermediate_expression_operand); - } - } - let counter_kind = self.coverage_counters.make_expression( - first_edge_counter_operand, - Op::Add, - some_sumup_edge_counter_operand.unwrap(), - || Some(format!("{:?}", bcb)), - ); - debug!( - "{}{:?} gets a new counter (sum of predecessor counters): {}", - NESTED_INDENT.repeat(debug_indent_level), - bcb, - self.format_counter(&counter_kind) - ); - self.basic_coverage_blocks[bcb].set_counter(counter_kind) - } - - fn get_or_make_edge_counter_operand( - &mut self, - from_bcb: BasicCoverageBlock, - to_bcb: BasicCoverageBlock, - collect_intermediate_expressions: &mut Vec, - ) -> Result { - self.recursive_get_or_make_edge_counter_operand( - from_bcb, - to_bcb, - collect_intermediate_expressions, - 1, - ) - } - - fn recursive_get_or_make_edge_counter_operand( - &mut self, - from_bcb: BasicCoverageBlock, - to_bcb: BasicCoverageBlock, - collect_intermediate_expressions: &mut Vec, - debug_indent_level: usize, - ) -> Result { - // If the source BCB has only one successor (assumed to be the given target), an edge - // counter is unnecessary. Just get or make a counter for the source BCB. - let successors = self.bcb_successors(from_bcb).iter(); - if successors.len() == 1 { - return self.recursive_get_or_make_counter_operand( - from_bcb, - collect_intermediate_expressions, - debug_indent_level + 1, - ); - } - - // If the edge already has a counter, return it. - if let Some(counter_kind) = self.basic_coverage_blocks[to_bcb].edge_counter_from(from_bcb) { - debug!( - "{}Edge {:?}->{:?} already has a counter: {}", - NESTED_INDENT.repeat(debug_indent_level), - from_bcb, - to_bcb, - self.format_counter(counter_kind) - ); - return Ok(counter_kind.as_operand_id()); - } - - // Make a new counter to count this edge. - let counter_kind = - self.coverage_counters.make_counter(|| Some(format!("{:?}->{:?}", from_bcb, to_bcb))); - debug!( - "{}Edge {:?}->{:?} gets a new counter: {}", - NESTED_INDENT.repeat(debug_indent_level), - from_bcb, - to_bcb, - self.format_counter(&counter_kind) - ); - self.basic_coverage_blocks[to_bcb].set_edge_counter_from(from_bcb, counter_kind) - } - - /// Select a branch for the expression, either the recommended `reloop_branch`, or if none was - /// found, select any branch. - fn choose_preferred_expression_branch( - &self, - traversal: &TraverseCoverageGraphWithLoops, - branches: &[BcbBranch], - ) -> BcbBranch { - let branch_needs_a_counter = - |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); - - let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches); - if let Some(reloop_branch_without_counter) = - some_reloop_branch.filter(branch_needs_a_counter) - { - debug!( - "Selecting reloop_branch={:?} that still needs a counter, to get the \ - `Expression`", - reloop_branch_without_counter - ); - reloop_branch_without_counter - } else { - let &branch_without_counter = branches - .iter() - .find(|&&branch| branch.counter(&self.basic_coverage_blocks).is_none()) - .expect( - "needs_branch_counters was `true` so there should be at least one \ - branch", - ); - debug!( - "Selecting any branch={:?} that still needs a counter, to get the \ - `Expression` because there was no `reloop_branch`, or it already had a \ - counter", - branch_without_counter - ); - branch_without_counter - } - } - - /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has - /// multiple incoming edges) can have a counter computed by expression. - /// - /// If at least one of the branches leads outside of a loop (`found_loop_exit` is - /// true), and at least one other branch does not exit the loop (the first of which - /// is captured in `some_reloop_branch`), it's likely any reloop branch will be - /// executed far more often than loop exit branch, making the reloop branch a better - /// candidate for an expression. - fn find_some_reloop_branch( - &self, - traversal: &TraverseCoverageGraphWithLoops, - branches: &[BcbBranch], - ) -> Option { - let branch_needs_a_counter = - |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); - - let mut some_reloop_branch: Option = None; - for context in traversal.context_stack.iter().rev() { - if let Some((backedge_from_bcbs, _)) = &context.loop_backedges { - let mut found_loop_exit = false; - for &branch in branches.iter() { - if backedge_from_bcbs.iter().any(|&backedge_from_bcb| { - self.bcb_is_dominated_by(backedge_from_bcb, branch.target_bcb) - }) { - if let Some(reloop_branch) = some_reloop_branch { - if reloop_branch.counter(&self.basic_coverage_blocks).is_none() { - // we already found a candidate reloop_branch that still - // needs a counter - continue; - } - } - // The path from branch leads back to the top of the loop. Set this - // branch as the `reloop_branch`. If this branch already has a - // counter, and we find another reloop branch that doesn't have a - // counter yet, that branch will be selected as the `reloop_branch` - // instead. - some_reloop_branch = Some(branch); - } else { - // The path from branch leads outside this loop - found_loop_exit = true; - } - if found_loop_exit - && some_reloop_branch.filter(branch_needs_a_counter).is_some() - { - // Found both a branch that exits the loop and a branch that returns - // to the top of the loop (`reloop_branch`), and the `reloop_branch` - // doesn't already have a counter. - break; - } - } - if !found_loop_exit { - debug!( - "No branches exit the loop, so any branch without an existing \ - counter can have the `Expression`." - ); - break; - } - if some_reloop_branch.is_some() { - debug!( - "Found a branch that exits the loop and a branch the loops back to \ - the top of the loop (`reloop_branch`). The `reloop_branch` will \ - get the `Expression`, as long as it still needs a counter." - ); - break; - } - // else all branches exited this loop context, so run the same checks with - // the outer loop(s) - } - } - some_reloop_branch - } - - #[inline] - fn bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &Vec { - &self.basic_coverage_blocks.predecessors[bcb] - } - - #[inline] - fn bcb_successors(&self, bcb: BasicCoverageBlock) -> &Vec { - &self.basic_coverage_blocks.successors[bcb] - } - - #[inline] - fn bcb_branches(&self, from_bcb: BasicCoverageBlock) -> Vec { - self.bcb_successors(from_bcb) - .iter() - .map(|&to_bcb| BcbBranch::from_to(from_bcb, to_bcb, &self.basic_coverage_blocks)) - .collect::>() - } - - fn bcb_needs_branch_counters(&self, bcb: BasicCoverageBlock) -> bool { - let branch_needs_a_counter = - |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); - let branches = self.bcb_branches(bcb); - branches.len() > 1 && branches.iter().any(branch_needs_a_counter) - } - - /// Returns true if the BasicCoverageBlock has zero or one incoming edge. (If zero, it should be - /// the entry point for the function.) - #[inline] - fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool { - self.bcb_predecessors(bcb).len() <= 1 - } - - #[inline] - fn bcb_is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool { - self.basic_coverage_blocks.is_dominated_by(node, dom) - } - - #[inline] - fn format_counter(&self, counter_kind: &CoverageKind) -> String { - self.coverage_counters.debug_counters.format_counter(counter_kind) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/debug.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/debug.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/debug.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/debug.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,840 +0,0 @@ -//! The `InstrumentCoverage` MIR pass implementation includes debugging tools and options -//! to help developers understand and/or improve the analysis and instrumentation of a MIR. -//! -//! To enable coverage, include the rustc command line option: -//! -//! * `-Z instrument-coverage` -//! -//! MIR Dump Files, with additional `CoverageGraph` graphviz and `CoverageSpan` spanview -//! ------------------------------------------------------------------------------------ -//! -//! Additional debugging options include: -//! -//! * `-Z dump-mir=InstrumentCoverage` - Generate `.mir` files showing the state of the MIR, -//! before and after the `InstrumentCoverage` pass, for each compiled function. -//! -//! * `-Z dump-mir-graphviz` - If `-Z dump-mir` is also enabled for the current MIR node path, -//! each MIR dump is accompanied by a before-and-after graphical view of the MIR, in Graphviz -//! `.dot` file format (which can be visually rendered as a graph using any of a number of free -//! Graphviz viewers and IDE extensions). -//! -//! For the `InstrumentCoverage` pass, this option also enables generation of an additional -//! Graphviz `.dot` file for each function, rendering the `CoverageGraph`: the control flow -//! graph (CFG) of `BasicCoverageBlocks` (BCBs), as nodes, internally labeled to show the -//! `CoverageSpan`-based MIR elements each BCB represents (`BasicBlock`s, `Statement`s and -//! `Terminator`s), assigned coverage counters and/or expressions, and edge counters, as needed. -//! -//! (Note the additional option, `-Z graphviz-dark-mode`, can be added, to change the rendered -//! output from its default black-on-white background to a dark color theme, if desired.) -//! -//! * `-Z dump-mir-spanview` - If `-Z dump-mir` is also enabled for the current MIR node path, -//! each MIR dump is accompanied by a before-and-after `.html` document showing the function's -//! original source code, highlighted by it's MIR spans, at the `statement`-level (by default), -//! `terminator` only, or encompassing span for the `Terminator` plus all `Statement`s, in each -//! `block` (`BasicBlock`). -//! -//! For the `InstrumentCoverage` pass, this option also enables generation of an additional -//! spanview `.html` file for each function, showing the aggregated `CoverageSpan`s that will -//! require counters (or counter expressions) for accurate coverage analysis. -//! -//! Debug Logging -//! ------------- -//! -//! The `InstrumentCoverage` pass includes debug logging messages at various phases and decision -//! points, which can be enabled via environment variable: -//! -//! ```shell -//! RUSTC_LOG=rustc_mir::transform::coverage=debug -//! ``` -//! -//! Other module paths with coverage-related debug logs may also be of interest, particularly for -//! debugging the coverage map data, injected as global variables in the LLVM IR (during rustc's -//! code generation pass). For example: -//! -//! ```shell -//! RUSTC_LOG=rustc_mir::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug -//! ``` -//! -//! Coverage Debug Options -//! --------------------------------- -//! -//! Additional debugging options can be enabled using the environment variable: -//! -//! ```shell -//! RUSTC_COVERAGE_DEBUG_OPTIONS= -//! ``` -//! -//! These options are comma-separated, and specified in the format `option-name=value`. For example: -//! -//! ```shell -//! $ RUSTC_COVERAGE_DEBUG_OPTIONS=counter-format=id+operation,allow-unused-expressions=yes cargo build -//! ``` -//! -//! Coverage debug options include: -//! -//! * `allow-unused-expressions=yes` or `no` (default: `no`) -//! -//! The `InstrumentCoverage` algorithms _should_ only create and assign expressions to a -//! `BasicCoverageBlock`, or an incoming edge, if that expression is either (a) required to -//! count a `CoverageSpan`, or (b) a dependency of some other required counter expression. -//! -//! If an expression is generated that does not map to a `CoverageSpan` or dependency, this -//! probably indicates there was a bug in the algorithm that creates and assigns counters -//! and expressions. -//! -//! When this kind of bug is encountered, the rustc compiler will panic by default. Setting: -//! `allow-unused-expressions=yes` will log a warning message instead of panicking (effectively -//! ignoring the unused expressions), which may be helpful when debugging the root cause of -//! the problem. -//! -//! * `counter-format=`, where `` can be any plus-separated combination of `id`, -//! `block`, and/or `operation` (default: `block+operation`) -//! -//! This option effects both the `CoverageGraph` (graphviz `.dot` files) and debug logging, when -//! generating labels for counters and expressions. -//! -//! Depending on the values and combinations, counters can be labeled by: -//! -//! * `id` - counter or expression ID (ascending counter IDs, starting at 1, or descending -//! expression IDs, starting at `u32:MAX`) -//! * `block` - the `BasicCoverageBlock` label (for example, `bcb0`) or edge label (for -//! example `bcb0->bcb1`), for counters or expressions assigned to count a -//! `BasicCoverageBlock` or edge. Intermediate expressions (not directly associated with -//! a BCB or edge) will be labeled by their expression ID, unless `operation` is also -//! specified. -//! * `operation` - applied to expressions only, labels include the left-hand-side counter -//! or expression label (lhs operand), the operator (`+` or `-`), and the right-hand-side -//! counter or expression (rhs operand). Expression operand labels are generated -//! recursively, generating labels with nested operations, enclosed in parentheses -//! (for example: `bcb2 + (bcb0 - bcb1)`). - -use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; -use super::spans::CoverageSpan; - -use crate::util::generic_graphviz::GraphvizWriter; -use crate::util::pretty; -use crate::util::spanview::{self, SpanViewable}; - -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir::coverage::*; -use rustc_middle::mir::{self, BasicBlock, TerminatorKind}; -use rustc_middle::ty::TyCtxt; -use rustc_span::Span; - -use std::iter; -use std::lazy::SyncOnceCell; - -pub const NESTED_INDENT: &str = " "; - -const RUSTC_COVERAGE_DEBUG_OPTIONS: &str = "RUSTC_COVERAGE_DEBUG_OPTIONS"; - -pub(super) fn debug_options<'a>() -> &'a DebugOptions { - static DEBUG_OPTIONS: SyncOnceCell = SyncOnceCell::new(); - - &DEBUG_OPTIONS.get_or_init(DebugOptions::from_env) -} - -/// Parses and maintains coverage-specific debug options captured from the environment variable -/// "RUSTC_COVERAGE_DEBUG_OPTIONS", if set. -#[derive(Debug, Clone)] -pub(super) struct DebugOptions { - pub allow_unused_expressions: bool, - counter_format: ExpressionFormat, -} - -impl DebugOptions { - fn from_env() -> Self { - let mut allow_unused_expressions = true; - let mut counter_format = ExpressionFormat::default(); - - if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) { - for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') { - let (option, value) = match setting_str.split_once('=') { - None => (setting_str, None), - Some((k, v)) => (k, Some(v)), - }; - match option { - "allow_unused_expressions" => { - allow_unused_expressions = bool_option_val(option, value); - debug!( - "{} env option `allow_unused_expressions` is set to {}", - RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions - ); - } - "counter_format" => { - match value { - None => { - bug!( - "`{}` option in environment variable {} requires one or more \ - plus-separated choices (a non-empty subset of \ - `id+block+operation`)", - option, - RUSTC_COVERAGE_DEBUG_OPTIONS - ); - } - Some(val) => { - counter_format = counter_format_option_val(val); - debug!( - "{} env option `counter_format` is set to {:?}", - RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format - ); - } - }; - } - _ => { - bug!( - "Unsupported setting `{}` in environment variable {}", - option, - RUSTC_COVERAGE_DEBUG_OPTIONS - ) - } - }; - } - } - - Self { allow_unused_expressions, counter_format } - } -} - -fn bool_option_val(option: &str, some_strval: Option<&str>) -> bool { - if let Some(val) = some_strval { - if vec!["yes", "y", "on", "true"].contains(&val) { - true - } else if vec!["no", "n", "off", "false"].contains(&val) { - false - } else { - bug!( - "Unsupported value `{}` for option `{}` in environment variable {}", - option, - val, - RUSTC_COVERAGE_DEBUG_OPTIONS - ) - } - } else { - true - } -} - -fn counter_format_option_val(strval: &str) -> ExpressionFormat { - let mut counter_format = ExpressionFormat { id: false, block: false, operation: false }; - let components = strval.splitn(3, '+'); - for component in components { - match component { - "id" => counter_format.id = true, - "block" => counter_format.block = true, - "operation" => counter_format.operation = true, - _ => bug!( - "Unsupported counter_format choice `{}` in environment variable {}", - component, - RUSTC_COVERAGE_DEBUG_OPTIONS - ), - } - } - counter_format -} - -#[derive(Debug, Clone)] -struct ExpressionFormat { - id: bool, - block: bool, - operation: bool, -} - -impl Default for ExpressionFormat { - fn default() -> Self { - Self { id: false, block: true, operation: true } - } -} - -/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `ExpressionOperandId`) to -/// the `CoverageKind` data and optional label (normally, the counter's associated -/// `BasicCoverageBlock` format string, if any). -/// -/// Use `format_counter` to convert one of these `CoverageKind` counters to a debug output string, -/// as directed by the `DebugOptions`. This allows the format of counter labels in logs and dump -/// files (including the `CoverageGraph` graphviz file) to be changed at runtime, via environment -/// variable. -/// -/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be -/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`. -pub(super) struct DebugCounters { - some_counters: Option>, -} - -impl DebugCounters { - pub fn new() -> Self { - Self { some_counters: None } - } - - pub fn enable(&mut self) { - debug_assert!(!self.is_enabled()); - self.some_counters.replace(FxHashMap::default()); - } - - pub fn is_enabled(&self) -> bool { - self.some_counters.is_some() - } - - pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option) { - if let Some(counters) = &mut self.some_counters { - let id: ExpressionOperandId = match *counter_kind { - CoverageKind::Counter { id, .. } => id.into(), - CoverageKind::Expression { id, .. } => id.into(), - _ => bug!( - "the given `CoverageKind` is not an counter or expression: {:?}", - counter_kind - ), - }; - counters - .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label)) - .expect("attempt to add the same counter_kind to DebugCounters more than once"); - } - } - - pub fn some_block_label(&self, operand: ExpressionOperandId) -> Option<&String> { - self.some_counters.as_ref().map_or(None, |counters| { - counters - .get(&operand) - .map_or(None, |debug_counter| debug_counter.some_block_label.as_ref()) - }) - } - - pub fn format_counter(&self, counter_kind: &CoverageKind) -> String { - match *counter_kind { - CoverageKind::Counter { .. } => { - format!("Counter({})", self.format_counter_kind(counter_kind)) - } - CoverageKind::Expression { .. } => { - format!("Expression({})", self.format_counter_kind(counter_kind)) - } - CoverageKind::Unreachable { .. } => "Unreachable".to_owned(), - } - } - - fn format_counter_kind(&self, counter_kind: &CoverageKind) -> String { - let counter_format = &debug_options().counter_format; - if let CoverageKind::Expression { id, lhs, op, rhs } = *counter_kind { - if counter_format.operation { - return format!( - "{}{} {} {}", - if counter_format.id || self.some_counters.is_none() { - format!("#{} = ", id.index()) - } else { - String::new() - }, - self.format_operand(lhs), - if op == Op::Add { "+" } else { "-" }, - self.format_operand(rhs), - ); - } - } - - let id: ExpressionOperandId = match *counter_kind { - CoverageKind::Counter { id, .. } => id.into(), - CoverageKind::Expression { id, .. } => id.into(), - _ => { - bug!("the given `CoverageKind` is not an counter or expression: {:?}", counter_kind) - } - }; - if self.some_counters.is_some() && (counter_format.block || !counter_format.id) { - let counters = self.some_counters.as_ref().unwrap(); - if let Some(DebugCounter { some_block_label: Some(block_label), .. }) = - counters.get(&id) - { - return if counter_format.id { - format!("{}#{}", block_label, id.index()) - } else { - block_label.to_string() - }; - } - } - format!("#{}", id.index()) - } - - fn format_operand(&self, operand: ExpressionOperandId) -> String { - if operand.index() == 0 { - return String::from("0"); - } - if let Some(counters) = &self.some_counters { - if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) { - if let CoverageKind::Expression { .. } = counter_kind { - if let Some(block_label) = some_block_label { - if debug_options().counter_format.block { - return format!( - "{}:({})", - block_label, - self.format_counter_kind(counter_kind) - ); - } - } - return format!("({})", self.format_counter_kind(counter_kind)); - } - return self.format_counter_kind(counter_kind); - } - } - format!("#{}", operand.index()) - } -} - -/// A non-public support class to `DebugCounters`. -#[derive(Debug)] -struct DebugCounter { - counter_kind: CoverageKind, - some_block_label: Option, -} - -impl DebugCounter { - fn new(counter_kind: CoverageKind, some_block_label: Option) -> Self { - Self { counter_kind, some_block_label } - } -} - -/// If enabled, this data structure captures additional debugging information used when generating -/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes. -pub(super) struct GraphvizData { - some_bcb_to_coverage_spans_with_counters: - Option>>, - some_bcb_to_dependency_counters: Option>>, - some_edge_to_counter: Option>, -} - -impl GraphvizData { - pub fn new() -> Self { - Self { - some_bcb_to_coverage_spans_with_counters: None, - some_bcb_to_dependency_counters: None, - some_edge_to_counter: None, - } - } - - pub fn enable(&mut self) { - debug_assert!(!self.is_enabled()); - self.some_bcb_to_coverage_spans_with_counters = Some(FxHashMap::default()); - self.some_bcb_to_dependency_counters = Some(FxHashMap::default()); - self.some_edge_to_counter = Some(FxHashMap::default()); - } - - pub fn is_enabled(&self) -> bool { - self.some_bcb_to_coverage_spans_with_counters.is_some() - } - - pub fn add_bcb_coverage_span_with_counter( - &mut self, - bcb: BasicCoverageBlock, - coverage_span: &CoverageSpan, - counter_kind: &CoverageKind, - ) { - if let Some(bcb_to_coverage_spans_with_counters) = - self.some_bcb_to_coverage_spans_with_counters.as_mut() - { - bcb_to_coverage_spans_with_counters - .entry(bcb) - .or_insert_with(Vec::new) - .push((coverage_span.clone(), counter_kind.clone())); - } - } - - pub fn get_bcb_coverage_spans_with_counters( - &self, - bcb: BasicCoverageBlock, - ) -> Option<&Vec<(CoverageSpan, CoverageKind)>> { - if let Some(bcb_to_coverage_spans_with_counters) = - self.some_bcb_to_coverage_spans_with_counters.as_ref() - { - bcb_to_coverage_spans_with_counters.get(&bcb) - } else { - None - } - } - - pub fn add_bcb_dependency_counter( - &mut self, - bcb: BasicCoverageBlock, - counter_kind: &CoverageKind, - ) { - if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() { - bcb_to_dependency_counters - .entry(bcb) - .or_insert_with(Vec::new) - .push(counter_kind.clone()); - } - } - - pub fn get_bcb_dependency_counters( - &self, - bcb: BasicCoverageBlock, - ) -> Option<&Vec> { - if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() { - bcb_to_dependency_counters.get(&bcb) - } else { - None - } - } - - pub fn set_edge_counter( - &mut self, - from_bcb: BasicCoverageBlock, - to_bb: BasicBlock, - counter_kind: &CoverageKind, - ) { - if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() { - edge_to_counter - .try_insert((from_bcb, to_bb), counter_kind.clone()) - .expect("invalid attempt to insert more than one edge counter for the same edge"); - } - } - - pub fn get_edge_counter( - &self, - from_bcb: BasicCoverageBlock, - to_bb: BasicBlock, - ) -> Option<&CoverageKind> { - if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() { - edge_to_counter.get(&(from_bcb, to_bb)) - } else { - None - } - } -} - -/// If enabled, this struct captures additional data used to track whether expressions were used, -/// directly or indirectly, to compute the coverage counts for all `CoverageSpan`s, and any that are -/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs -/// and/or a `CoverageGraph` graphviz output). -pub(super) struct UsedExpressions { - some_used_expression_operands: - Option>>, - some_unused_expressions: - Option, BasicCoverageBlock)>>, -} - -impl UsedExpressions { - pub fn new() -> Self { - Self { some_used_expression_operands: None, some_unused_expressions: None } - } - - pub fn enable(&mut self) { - debug_assert!(!self.is_enabled()); - self.some_used_expression_operands = Some(FxHashMap::default()); - self.some_unused_expressions = Some(Vec::new()); - } - - pub fn is_enabled(&self) -> bool { - self.some_used_expression_operands.is_some() - } - - pub fn add_expression_operands(&mut self, expression: &CoverageKind) { - if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() { - if let CoverageKind::Expression { id, lhs, rhs, .. } = *expression { - used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id); - used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id); - } - } - } - - pub fn expression_is_used(&self, expression: &CoverageKind) -> bool { - if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() { - used_expression_operands.contains_key(&expression.as_operand_id()) - } else { - false - } - } - - pub fn add_unused_expression_if_not_found( - &mut self, - expression: &CoverageKind, - edge_from_bcb: Option, - target_bcb: BasicCoverageBlock, - ) { - if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() { - if !used_expression_operands.contains_key(&expression.as_operand_id()) { - self.some_unused_expressions.as_mut().unwrap().push(( - expression.clone(), - edge_from_bcb, - target_bcb, - )); - } - } - } - - /// Return the list of unused counters (if any) as a tuple with the counter (`CoverageKind`), - /// optional `from_bcb` (if it was an edge counter), and `target_bcb`. - pub fn get_unused_expressions( - &self, - ) -> Vec<(CoverageKind, Option, BasicCoverageBlock)> { - if let Some(unused_expressions) = self.some_unused_expressions.as_ref() { - unused_expressions.clone() - } else { - Vec::new() - } - } - - /// If enabled, validate that every BCB or edge counter not directly associated with a coverage - /// span is at least indirectly associated (it is a dependency of a BCB counter that _is_ - /// associated with a coverage span). - pub fn validate( - &mut self, - bcb_counters_without_direct_coverage_spans: &Vec<( - Option, - BasicCoverageBlock, - CoverageKind, - )>, - ) { - if self.is_enabled() { - let mut not_validated = bcb_counters_without_direct_coverage_spans - .iter() - .map(|(_, _, counter_kind)| counter_kind) - .collect::>(); - let mut validating_count = 0; - while not_validated.len() != validating_count { - let to_validate = not_validated.split_off(0); - validating_count = to_validate.len(); - for counter_kind in to_validate { - if self.expression_is_used(counter_kind) { - self.add_expression_operands(counter_kind); - } else { - not_validated.push(counter_kind); - } - } - } - } - } - - pub fn alert_on_unused_expressions(&self, debug_counters: &DebugCounters) { - if let Some(unused_expressions) = self.some_unused_expressions.as_ref() { - for (counter_kind, edge_from_bcb, target_bcb) in unused_expressions { - let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() { - format!( - "non-coverage edge counter found without a dependent expression, in \ - {:?}->{:?}; counter={}", - from_bcb, - target_bcb, - debug_counters.format_counter(&counter_kind), - ) - } else { - format!( - "non-coverage counter found without a dependent expression, in {:?}; \ - counter={}", - target_bcb, - debug_counters.format_counter(&counter_kind), - ) - }; - - if debug_options().allow_unused_expressions { - debug!("WARNING: {}", unused_counter_message); - } else { - bug!("{}", unused_counter_message); - } - } - } - } -} - -/// Generates the MIR pass `CoverageSpan`-specific spanview dump file. -pub(super) fn dump_coverage_spanview( - tcx: TyCtxt<'tcx>, - mir_body: &mir::Body<'tcx>, - basic_coverage_blocks: &CoverageGraph, - pass_name: &str, - body_span: Span, - coverage_spans: &Vec, -) { - let mir_source = mir_body.source; - let def_id = mir_source.def_id(); - - let span_viewables = span_viewables(tcx, mir_body, basic_coverage_blocks, &coverage_spans); - let mut file = pretty::create_dump_file(tcx, "html", None, pass_name, &0, mir_source) - .expect("Unexpected error creating MIR spanview HTML file"); - let crate_name = tcx.crate_name(def_id.krate); - let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate(); - let title = format!("{}.{} - Coverage Spans", crate_name, item_name); - spanview::write_document(tcx, body_span, span_viewables, &title, &mut file) - .expect("Unexpected IO error dumping coverage spans as HTML"); -} - -/// Converts the computed `BasicCoverageBlockData`s into `SpanViewable`s. -fn span_viewables( - tcx: TyCtxt<'tcx>, - mir_body: &mir::Body<'tcx>, - basic_coverage_blocks: &CoverageGraph, - coverage_spans: &Vec, -) -> Vec { - let mut span_viewables = Vec::new(); - for coverage_span in coverage_spans { - let tooltip = coverage_span.format_coverage_statements(tcx, mir_body); - let CoverageSpan { span, bcb, .. } = coverage_span; - let bcb_data = &basic_coverage_blocks[*bcb]; - let id = bcb_data.id(); - let leader_bb = bcb_data.leader_bb(); - span_viewables.push(SpanViewable { bb: leader_bb, span: *span, id, tooltip }); - } - span_viewables -} - -/// Generates the MIR pass coverage-specific graphviz dump file. -pub(super) fn dump_coverage_graphviz( - tcx: TyCtxt<'tcx>, - mir_body: &mir::Body<'tcx>, - pass_name: &str, - basic_coverage_blocks: &CoverageGraph, - debug_counters: &DebugCounters, - graphviz_data: &GraphvizData, - intermediate_expressions: &Vec, - debug_used_expressions: &UsedExpressions, -) { - let mir_source = mir_body.source; - let def_id = mir_source.def_id(); - let node_content = |bcb| { - bcb_to_string_sections( - tcx, - mir_body, - debug_counters, - &basic_coverage_blocks[bcb], - graphviz_data.get_bcb_coverage_spans_with_counters(bcb), - graphviz_data.get_bcb_dependency_counters(bcb), - // intermediate_expressions are injected into the mir::START_BLOCK, so - // include them in the first BCB. - if bcb.index() == 0 { Some(&intermediate_expressions) } else { None }, - ) - }; - let edge_labels = |from_bcb| { - let from_bcb_data = &basic_coverage_blocks[from_bcb]; - let from_terminator = from_bcb_data.terminator(mir_body); - let mut edge_labels = from_terminator.kind.fmt_successor_labels(); - edge_labels.retain(|label| label != "unreachable"); - let edge_counters = from_terminator - .successors() - .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb)); - iter::zip(&edge_labels, edge_counters) - .map(|(label, some_counter)| { - if let Some(counter) = some_counter { - format!("{}\n{}", label, debug_counters.format_counter(counter)) - } else { - label.to_string() - } - }) - .collect::>() - }; - let graphviz_name = format!("Cov_{}_{}", def_id.krate.index(), def_id.index.index()); - let mut graphviz_writer = - GraphvizWriter::new(basic_coverage_blocks, &graphviz_name, node_content, edge_labels); - let unused_expressions = debug_used_expressions.get_unused_expressions(); - if unused_expressions.len() > 0 { - graphviz_writer.set_graph_label(&format!( - "Unused expressions:\n {}", - unused_expressions - .as_slice() - .iter() - .map(|(counter_kind, edge_from_bcb, target_bcb)| { - if let Some(from_bcb) = edge_from_bcb.as_ref() { - format!( - "{:?}->{:?}: {}", - from_bcb, - target_bcb, - debug_counters.format_counter(&counter_kind), - ) - } else { - format!( - "{:?}: {}", - target_bcb, - debug_counters.format_counter(&counter_kind), - ) - } - }) - .collect::>() - .join("\n ") - )); - } - let mut file = pretty::create_dump_file(tcx, "dot", None, pass_name, &0, mir_source) - .expect("Unexpected error creating BasicCoverageBlock graphviz DOT file"); - graphviz_writer - .write_graphviz(tcx, &mut file) - .expect("Unexpected error writing BasicCoverageBlock graphviz DOT file"); -} - -fn bcb_to_string_sections( - tcx: TyCtxt<'tcx>, - mir_body: &mir::Body<'tcx>, - debug_counters: &DebugCounters, - bcb_data: &BasicCoverageBlockData, - some_coverage_spans_with_counters: Option<&Vec<(CoverageSpan, CoverageKind)>>, - some_dependency_counters: Option<&Vec>, - some_intermediate_expressions: Option<&Vec>, -) -> Vec { - let len = bcb_data.basic_blocks.len(); - let mut sections = Vec::new(); - if let Some(collect_intermediate_expressions) = some_intermediate_expressions { - sections.push( - collect_intermediate_expressions - .iter() - .map(|expression| { - format!("Intermediate {}", debug_counters.format_counter(expression)) - }) - .collect::>() - .join("\n"), - ); - } - if let Some(coverage_spans_with_counters) = some_coverage_spans_with_counters { - sections.push( - coverage_spans_with_counters - .iter() - .map(|(covspan, counter)| { - format!( - "{} at {}", - debug_counters.format_counter(counter), - covspan.format(tcx, mir_body) - ) - }) - .collect::>() - .join("\n"), - ); - } - if let Some(dependency_counters) = some_dependency_counters { - sections.push(format!( - "Non-coverage counters:\n {}", - dependency_counters - .iter() - .map(|counter| debug_counters.format_counter(counter)) - .collect::>() - .join(" \n"), - )); - } - if let Some(counter_kind) = &bcb_data.counter_kind { - sections.push(format!("{:?}", counter_kind)); - } - let non_term_blocks = bcb_data.basic_blocks[0..len - 1] - .iter() - .map(|&bb| format!("{:?}: {}", bb, term_type(&mir_body[bb].terminator().kind))) - .collect::>(); - if non_term_blocks.len() > 0 { - sections.push(non_term_blocks.join("\n")); - } - sections.push(format!( - "{:?}: {}", - bcb_data.basic_blocks.last().unwrap(), - term_type(&bcb_data.terminator(mir_body).kind) - )); - sections -} - -/// Returns a simple string representation of a `TerminatorKind` variant, independent of any -/// values it might hold. -pub(super) fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str { - match kind { - TerminatorKind::Goto { .. } => "Goto", - TerminatorKind::SwitchInt { .. } => "SwitchInt", - TerminatorKind::Resume => "Resume", - TerminatorKind::Abort => "Abort", - TerminatorKind::Return => "Return", - TerminatorKind::Unreachable => "Unreachable", - TerminatorKind::Drop { .. } => "Drop", - TerminatorKind::DropAndReplace { .. } => "DropAndReplace", - TerminatorKind::Call { .. } => "Call", - TerminatorKind::Assert { .. } => "Assert", - TerminatorKind::Yield { .. } => "Yield", - TerminatorKind::GeneratorDrop => "GeneratorDrop", - TerminatorKind::FalseEdge { .. } => "FalseEdge", - TerminatorKind::FalseUnwind { .. } => "FalseUnwind", - TerminatorKind::InlineAsm { .. } => "InlineAsm", - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/graph.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/graph.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,769 +0,0 @@ -use super::Error; - -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::dominators::{self, Dominators}; -use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode}; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::coverage::*; -use rustc_middle::mir::{self, BasicBlock, BasicBlockData, Terminator, TerminatorKind}; - -use std::ops::{Index, IndexMut}; - -const ID_SEPARATOR: &str = ","; - -/// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s -/// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s, plus a -/// `CoverageKind` counter (to be added by `CoverageCounters::make_bcb_counters`), and an optional -/// set of additional counters--if needed--to count incoming edges, if there are more than one. -/// (These "edge counters" are eventually converted into new MIR `BasicBlock`s.) -#[derive(Debug)] -pub(super) struct CoverageGraph { - bcbs: IndexVec, - bb_to_bcb: IndexVec>, - pub successors: IndexVec>, - pub predecessors: IndexVec>, - dominators: Option>, -} - -impl CoverageGraph { - pub fn from_mir(mir_body: &mir::Body<'tcx>) -> Self { - let (bcbs, bb_to_bcb) = Self::compute_basic_coverage_blocks(mir_body); - - // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock - // equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the - // each predecessor of a BCB leader_bb should be in a unique BCB. It is possible for a - // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so - // de-duplication is required. This is done without reordering the successors. - - let bcbs_len = bcbs.len(); - let mut seen = IndexVec::from_elem_n(false, bcbs_len); - let successors = IndexVec::from_fn_n( - |bcb| { - for b in seen.iter_mut() { - *b = false; - } - let bcb_data = &bcbs[bcb]; - let mut bcb_successors = Vec::new(); - for successor in - bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind) - .filter_map(|&successor_bb| bb_to_bcb[successor_bb]) - { - if !seen[successor] { - seen[successor] = true; - bcb_successors.push(successor); - } - } - bcb_successors - }, - bcbs.len(), - ); - - let mut predecessors = IndexVec::from_elem_n(Vec::new(), bcbs.len()); - for (bcb, bcb_successors) in successors.iter_enumerated() { - for &successor in bcb_successors { - predecessors[successor].push(bcb); - } - } - - let mut basic_coverage_blocks = - Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None }; - let dominators = dominators::dominators(&basic_coverage_blocks); - basic_coverage_blocks.dominators = Some(dominators); - basic_coverage_blocks - } - - fn compute_basic_coverage_blocks( - mir_body: &mir::Body<'tcx>, - ) -> ( - IndexVec, - IndexVec>, - ) { - let num_basic_blocks = mir_body.num_nodes(); - let mut bcbs = IndexVec::with_capacity(num_basic_blocks); - let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks); - - // Walk the MIR CFG using a Preorder traversal, which starts from `START_BLOCK` and follows - // each block terminator's `successors()`. Coverage spans must map to actual source code, - // so compiler generated blocks and paths can be ignored. To that end, the CFG traversal - // intentionally omits unwind paths. - // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and - // `catch_unwind()` handlers. - let mir_cfg_without_unwind = ShortCircuitPreorder::new(&mir_body, bcb_filtered_successors); - - let mut basic_blocks = Vec::new(); - for (bb, data) in mir_cfg_without_unwind { - if let Some(last) = basic_blocks.last() { - let predecessors = &mir_body.predecessors()[bb]; - if predecessors.len() > 1 || !predecessors.contains(last) { - // The `bb` has more than one _incoming_ edge, and should start its own - // `BasicCoverageBlockData`. (Note, the `basic_blocks` vector does not yet - // include `bb`; it contains a sequence of one or more sequential basic_blocks - // with no intermediate branches in or out. Save these as a new - // `BasicCoverageBlockData` before starting the new one.) - Self::add_basic_coverage_block( - &mut bcbs, - &mut bb_to_bcb, - basic_blocks.split_off(0), - ); - debug!( - " because {}", - if predecessors.len() > 1 { - "predecessors.len() > 1".to_owned() - } else { - format!("bb {} is not in precessors: {:?}", bb.index(), predecessors) - } - ); - } - } - basic_blocks.push(bb); - - let term = data.terminator(); - - match term.kind { - TerminatorKind::Return { .. } - | TerminatorKind::Abort - | TerminatorKind::Yield { .. } - | TerminatorKind::SwitchInt { .. } => { - // The `bb` has more than one _outgoing_ edge, or exits the function. Save the - // current sequence of `basic_blocks` gathered to this point, as a new - // `BasicCoverageBlockData`. - Self::add_basic_coverage_block( - &mut bcbs, - &mut bb_to_bcb, - basic_blocks.split_off(0), - ); - debug!(" because term.kind = {:?}", term.kind); - // Note that this condition is based on `TerminatorKind`, even though it - // theoretically boils down to `successors().len() != 1`; that is, either zero - // (e.g., `Return`, `Abort`) or multiple successors (e.g., `SwitchInt`), but - // since the BCB CFG ignores things like unwind branches (which exist in the - // `Terminator`s `successors()` list) checking the number of successors won't - // work. - } - - // The following `TerminatorKind`s are either not expected outside an unwind branch, - // or they should not (under normal circumstances) branch. Coverage graphs are - // simplified by assuring coverage results are accurate for program executions that - // don't panic. - // - // Programs that panic and unwind may record slightly inaccurate coverage results - // for a coverage region containing the `Terminator` that began the panic. This - // is as intended. (See Issue #78544 for a possible future option to support - // coverage in test programs that panic.) - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Unreachable - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Assert { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => {} - } - } - - if !basic_blocks.is_empty() { - // process any remaining basic_blocks into a final `BasicCoverageBlockData` - Self::add_basic_coverage_block(&mut bcbs, &mut bb_to_bcb, basic_blocks.split_off(0)); - debug!(" because the end of the MIR CFG was reached while traversing"); - } - - (bcbs, bb_to_bcb) - } - - fn add_basic_coverage_block( - bcbs: &mut IndexVec, - bb_to_bcb: &mut IndexVec>, - basic_blocks: Vec, - ) { - let bcb = BasicCoverageBlock::from_usize(bcbs.len()); - for &bb in basic_blocks.iter() { - bb_to_bcb[bb] = Some(bcb); - } - let bcb_data = BasicCoverageBlockData::from(basic_blocks); - debug!("adding bcb{}: {:?}", bcb.index(), bcb_data); - bcbs.push(bcb_data); - } - - #[inline(always)] - pub fn iter_enumerated( - &self, - ) -> impl Iterator { - self.bcbs.iter_enumerated() - } - - #[inline(always)] - pub fn iter_enumerated_mut( - &mut self, - ) -> impl Iterator { - self.bcbs.iter_enumerated_mut() - } - - #[inline(always)] - pub fn bcb_from_bb(&self, bb: BasicBlock) -> Option { - if bb.index() < self.bb_to_bcb.len() { self.bb_to_bcb[bb] } else { None } - } - - #[inline(always)] - pub fn is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool { - self.dominators.as_ref().unwrap().is_dominated_by(node, dom) - } - - #[inline(always)] - pub fn dominators(&self) -> &Dominators { - self.dominators.as_ref().unwrap() - } -} - -impl Index for CoverageGraph { - type Output = BasicCoverageBlockData; - - #[inline] - fn index(&self, index: BasicCoverageBlock) -> &BasicCoverageBlockData { - &self.bcbs[index] - } -} - -impl IndexMut for CoverageGraph { - #[inline] - fn index_mut(&mut self, index: BasicCoverageBlock) -> &mut BasicCoverageBlockData { - &mut self.bcbs[index] - } -} - -impl graph::DirectedGraph for CoverageGraph { - type Node = BasicCoverageBlock; -} - -impl graph::WithNumNodes for CoverageGraph { - #[inline] - fn num_nodes(&self) -> usize { - self.bcbs.len() - } -} - -impl graph::WithStartNode for CoverageGraph { - #[inline] - fn start_node(&self) -> Self::Node { - self.bcb_from_bb(mir::START_BLOCK) - .expect("mir::START_BLOCK should be in a BasicCoverageBlock") - } -} - -type BcbSuccessors<'graph> = std::slice::Iter<'graph, BasicCoverageBlock>; - -impl<'graph> graph::GraphSuccessors<'graph> for CoverageGraph { - type Item = BasicCoverageBlock; - type Iter = std::iter::Cloned>; -} - -impl graph::WithSuccessors for CoverageGraph { - #[inline] - fn successors(&self, node: Self::Node) -> >::Iter { - self.successors[node].iter().cloned() - } -} - -impl graph::GraphPredecessors<'graph> for CoverageGraph { - type Item = BasicCoverageBlock; - type Iter = std::iter::Copied>; -} - -impl graph::WithPredecessors for CoverageGraph { - #[inline] - fn predecessors(&self, node: Self::Node) -> >::Iter { - self.predecessors[node].iter().copied() - } -} - -rustc_index::newtype_index! { - /// A node in the [control-flow graph][CFG] of CoverageGraph. - pub(super) struct BasicCoverageBlock { - DEBUG_FORMAT = "bcb{}", - const START_BCB = 0, - } -} - -/// `BasicCoverageBlockData` holds the data indexed by a `BasicCoverageBlock`. -/// -/// A `BasicCoverageBlock` (BCB) represents the maximal-length sequence of MIR `BasicBlock`s without -/// conditional branches, and form a new, simplified, coverage-specific Control Flow Graph, without -/// altering the original MIR CFG. -/// -/// Note that running the MIR `SimplifyCfg` transform is not sufficient (and therefore not -/// necessary). The BCB-based CFG is a more aggressive simplification. For example: -/// -/// * The BCB CFG ignores (trims) branches not relevant to coverage, such as unwind-related code, -/// that is injected by the Rust compiler but has no physical source code to count. This also -/// means a BasicBlock with a `Call` terminator can be merged into its primary successor target -/// block, in the same BCB. (But, note: Issue #78544: "MIR InstrumentCoverage: Improve coverage -/// of `#[should_panic]` tests and `catch_unwind()` handlers") -/// * Some BasicBlock terminators support Rust-specific concerns--like borrow-checking--that are -/// not relevant to coverage analysis. `FalseUnwind`, for example, can be treated the same as -/// a `Goto`, and merged with its successor into the same BCB. -/// -/// Each BCB with at least one computed `CoverageSpan` will have no more than one `Counter`. -/// In some cases, a BCB's execution count can be computed by `Expression`. Additional -/// disjoint `CoverageSpan`s in a BCB can also be counted by `Expression` (by adding `ZERO` -/// to the BCB's primary counter or expression). -/// -/// The BCB CFG is critical to simplifying the coverage analysis by ensuring graph path-based -/// queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch (control flow) -/// significance. -#[derive(Debug, Clone)] -pub(super) struct BasicCoverageBlockData { - pub basic_blocks: Vec, - pub counter_kind: Option, - edge_from_bcbs: Option>, -} - -impl BasicCoverageBlockData { - pub fn from(basic_blocks: Vec) -> Self { - assert!(basic_blocks.len() > 0); - Self { basic_blocks, counter_kind: None, edge_from_bcbs: None } - } - - #[inline(always)] - pub fn leader_bb(&self) -> BasicBlock { - self.basic_blocks[0] - } - - #[inline(always)] - pub fn last_bb(&self) -> BasicBlock { - *self.basic_blocks.last().unwrap() - } - - #[inline(always)] - pub fn terminator<'a, 'tcx>(&self, mir_body: &'a mir::Body<'tcx>) -> &'a Terminator<'tcx> { - &mir_body[self.last_bb()].terminator() - } - - pub fn set_counter( - &mut self, - counter_kind: CoverageKind, - ) -> Result { - debug_assert!( - // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also - // have an expression (to be injected into an existing `BasicBlock` represented by this - // `BasicCoverageBlock`). - self.edge_from_bcbs.is_none() || counter_kind.is_expression(), - "attempt to add a `Counter` to a BCB target with existing incoming edge counters" - ); - let operand = counter_kind.as_operand_id(); - if let Some(replaced) = self.counter_kind.replace(counter_kind) { - Error::from_string(format!( - "attempt to set a BasicCoverageBlock coverage counter more than once; \ - {:?} already had counter {:?}", - self, replaced, - )) - } else { - Ok(operand) - } - } - - #[inline(always)] - pub fn counter(&self) -> Option<&CoverageKind> { - self.counter_kind.as_ref() - } - - #[inline(always)] - pub fn take_counter(&mut self) -> Option { - self.counter_kind.take() - } - - pub fn set_edge_counter_from( - &mut self, - from_bcb: BasicCoverageBlock, - counter_kind: CoverageKind, - ) -> Result { - if level_enabled!(tracing::Level::DEBUG) { - // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also - // have an expression (to be injected into an existing `BasicBlock` represented by this - // `BasicCoverageBlock`). - if !self.counter_kind.as_ref().map_or(true, |c| c.is_expression()) { - return Error::from_string(format!( - "attempt to add an incoming edge counter from {:?} when the target BCB already \ - has a `Counter`", - from_bcb - )); - } - } - let operand = counter_kind.as_operand_id(); - if let Some(replaced) = - self.edge_from_bcbs.get_or_insert_default().insert(from_bcb, counter_kind) - { - Error::from_string(format!( - "attempt to set an edge counter more than once; from_bcb: \ - {:?} already had counter {:?}", - from_bcb, replaced, - )) - } else { - Ok(operand) - } - } - - #[inline] - pub fn edge_counter_from(&self, from_bcb: BasicCoverageBlock) -> Option<&CoverageKind> { - if let Some(edge_from_bcbs) = &self.edge_from_bcbs { - edge_from_bcbs.get(&from_bcb) - } else { - None - } - } - - #[inline] - pub fn take_edge_counters( - &mut self, - ) -> Option> { - self.edge_from_bcbs.take().map_or(None, |m| Some(m.into_iter())) - } - - pub fn id(&self) -> String { - format!( - "@{}", - self.basic_blocks - .iter() - .map(|bb| bb.index().to_string()) - .collect::>() - .join(ID_SEPARATOR) - ) - } -} - -/// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`) -/// as either the successor BCB itself, if it has only one incoming edge, or the successor _plus_ -/// the specific branching BCB, representing the edge between the two. The latter case -/// distinguishes this incoming edge from other incoming edges to the same `target_bcb`. -#[derive(Clone, Copy, PartialEq, Eq)] -pub(super) struct BcbBranch { - pub edge_from_bcb: Option, - pub target_bcb: BasicCoverageBlock, -} - -impl BcbBranch { - pub fn from_to( - from_bcb: BasicCoverageBlock, - to_bcb: BasicCoverageBlock, - basic_coverage_blocks: &CoverageGraph, - ) -> Self { - let edge_from_bcb = if basic_coverage_blocks.predecessors[to_bcb].len() > 1 { - Some(from_bcb) - } else { - None - }; - Self { edge_from_bcb, target_bcb: to_bcb } - } - - pub fn counter<'a>( - &self, - basic_coverage_blocks: &'a CoverageGraph, - ) -> Option<&'a CoverageKind> { - if let Some(from_bcb) = self.edge_from_bcb { - basic_coverage_blocks[self.target_bcb].edge_counter_from(from_bcb) - } else { - basic_coverage_blocks[self.target_bcb].counter() - } - } - - pub fn is_only_path_to_target(&self) -> bool { - self.edge_from_bcb.is_none() - } -} - -impl std::fmt::Debug for BcbBranch { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(from_bcb) = self.edge_from_bcb { - write!(fmt, "{:?}->{:?}", from_bcb, self.target_bcb) - } else { - write!(fmt, "{:?}", self.target_bcb) - } - } -} - -// Returns the `Terminator`s non-unwind successors. -// FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and -// `catch_unwind()` handlers. -fn bcb_filtered_successors<'a, 'tcx>( - body: &'tcx &'a mir::Body<'tcx>, - term_kind: &'tcx TerminatorKind<'tcx>, -) -> Box + 'a> { - let mut successors = term_kind.successors(); - Box::new( - match &term_kind { - // SwitchInt successors are never unwind, and all of them should be traversed. - TerminatorKind::SwitchInt { .. } => successors, - // For all other kinds, return only the first successor, if any, and ignore unwinds. - // NOTE: `chain(&[])` is required to coerce the `option::iter` (from - // `next().into_iter()`) into the `mir::Successors` aliased type. - _ => successors.next().into_iter().chain(&[]), - } - .filter(move |&&successor| { - body[successor].terminator().kind != TerminatorKind::Unreachable - }), - ) -} - -/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the -/// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that -/// ensures a loop is completely traversed before processing Blocks after the end of the loop. -#[derive(Debug)] -pub(super) struct TraversalContext { - /// From one or more backedges returning to a loop header. - pub loop_backedges: Option<(Vec, BasicCoverageBlock)>, - - /// worklist, to be traversed, of CoverageGraph in the loop with the given loop - /// backedges, such that the loop is the inner inner-most loop containing these - /// CoverageGraph - pub worklist: Vec, -} - -pub(super) struct TraverseCoverageGraphWithLoops { - pub backedges: IndexVec>, - pub context_stack: Vec, - visited: BitSet, -} - -impl TraverseCoverageGraphWithLoops { - pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self { - let start_bcb = basic_coverage_blocks.start_node(); - let backedges = find_loop_backedges(basic_coverage_blocks); - let context_stack = - vec![TraversalContext { loop_backedges: None, worklist: vec![start_bcb] }]; - // `context_stack` starts with a `TraversalContext` for the main function context (beginning - // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top - // of the stack as loops are entered, and popped off of the stack when a loop's worklist is - // exhausted. - let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - Self { backedges, context_stack, visited } - } - - pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option { - debug!( - "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", - self.context_stack.iter().rev().collect::>() - ); - while let Some(next_bcb) = { - // Strip contexts with empty worklists from the top of the stack - while self.context_stack.last().map_or(false, |context| context.worklist.is_empty()) { - self.context_stack.pop(); - } - // Pop the next bcb off of the current context_stack. If none, all BCBs were visited. - self.context_stack.last_mut().map_or(None, |context| context.worklist.pop()) - } { - if !self.visited.insert(next_bcb) { - debug!("Already visited: {:?}", next_bcb); - continue; - } - debug!("Visiting {:?}", next_bcb); - if self.backedges[next_bcb].len() > 0 { - debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb); - self.context_stack.push(TraversalContext { - loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)), - worklist: Vec::new(), - }); - } - self.extend_worklist(basic_coverage_blocks, next_bcb); - return Some(next_bcb); - } - None - } - - pub fn extend_worklist( - &mut self, - basic_coverage_blocks: &CoverageGraph, - bcb: BasicCoverageBlock, - ) { - let successors = &basic_coverage_blocks.successors[bcb]; - debug!("{:?} has {} successors:", bcb, successors.len()); - for &successor in successors { - if successor == bcb { - debug!( - "{:?} has itself as its own successor. (Note, the compiled code will \ - generate an infinite loop.)", - bcb - ); - // Don't re-add this successor to the worklist. We are already processing it. - break; - } - for context in self.context_stack.iter_mut().rev() { - // Add successors of the current BCB to the appropriate context. Successors that - // stay within a loop are added to the BCBs context worklist. Successors that - // exit the loop (they are not dominated by the loop header) must be reachable - // from other BCBs outside the loop, and they will be added to a different - // worklist. - // - // Branching blocks (with more than one successor) must be processed before - // blocks with only one successor, to prevent unnecessarily complicating - // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the - // branching block would have given an `Expression` (or vice versa). - let (some_successor_to_add, some_loop_header) = - if let Some((_, loop_header)) = context.loop_backedges { - if basic_coverage_blocks.is_dominated_by(successor, loop_header) { - (Some(successor), Some(loop_header)) - } else { - (None, None) - } - } else { - (Some(successor), None) - }; - if let Some(successor_to_add) = some_successor_to_add { - if basic_coverage_blocks.successors[successor_to_add].len() > 1 { - debug!( - "{:?} successor is branching. Prioritize it at the beginning of \ - the {}", - successor_to_add, - if let Some(loop_header) = some_loop_header { - format!("worklist for the loop headed by {:?}", loop_header) - } else { - String::from("non-loop worklist") - }, - ); - context.worklist.insert(0, successor_to_add); - } else { - debug!( - "{:?} successor is non-branching. Defer it to the end of the {}", - successor_to_add, - if let Some(loop_header) = some_loop_header { - format!("worklist for the loop headed by {:?}", loop_header) - } else { - String::from("non-loop worklist") - }, - ); - context.worklist.push(successor_to_add); - } - break; - } - } - } - } - - pub fn is_complete(&self) -> bool { - self.visited.count() == self.visited.domain_size() - } - - pub fn unvisited(&self) -> Vec { - let mut unvisited_set: BitSet = - BitSet::new_filled(self.visited.domain_size()); - unvisited_set.subtract(&self.visited); - unvisited_set.iter().collect::>() - } -} - -pub(super) fn find_loop_backedges( - basic_coverage_blocks: &CoverageGraph, -) -> IndexVec> { - let num_bcbs = basic_coverage_blocks.num_nodes(); - let mut backedges = IndexVec::from_elem_n(Vec::::new(), num_bcbs); - - // Identify loops by their backedges. - // - // The computational complexity is bounded by: n(s) x d where `n` is the number of - // `BasicCoverageBlock` nodes (the simplified/reduced representation of the CFG derived from the - // MIR); `s` is the average number of successors per node (which is most likely less than 2, and - // independent of the size of the function, so it can be treated as a constant); - // and `d` is the average number of dominators per node. - // - // The average number of dominators depends on the size and complexity of the function, and - // nodes near the start of the function's control flow graph typically have less dominators - // than nodes near the end of the CFG. Without doing a detailed mathematical analysis, I - // think the resulting complexity has the characteristics of O(n log n). - // - // The overall complexity appears to be comparable to many other MIR transform algorithms, and I - // don't expect that this function is creating a performance hot spot, but if this becomes an - // issue, there may be ways to optimize the `is_dominated_by` algorithm (as indicated by an - // existing `FIXME` comment in that code), or possibly ways to optimize it's usage here, perhaps - // by keeping track of results for visited `BasicCoverageBlock`s if they can be used to short - // circuit downstream `is_dominated_by` checks. - // - // For now, that kind of optimization seems unnecessarily complicated. - for (bcb, _) in basic_coverage_blocks.iter_enumerated() { - for &successor in &basic_coverage_blocks.successors[bcb] { - if basic_coverage_blocks.is_dominated_by(bcb, successor) { - let loop_header = successor; - let backedge_from_bcb = bcb; - debug!( - "Found BCB backedge: {:?} -> loop_header: {:?}", - backedge_from_bcb, loop_header - ); - backedges[loop_header].push(backedge_from_bcb); - } - } - } - backedges -} - -pub struct ShortCircuitPreorder< - 'a, - 'tcx, - F: Fn( - &'tcx &'a mir::Body<'tcx>, - &'tcx TerminatorKind<'tcx>, - ) -> Box + 'a>, -> { - body: &'tcx &'a mir::Body<'tcx>, - visited: BitSet, - worklist: Vec, - filtered_successors: F, -} - -impl< - 'a, - 'tcx, - F: Fn( - &'tcx &'a mir::Body<'tcx>, - &'tcx TerminatorKind<'tcx>, - ) -> Box + 'a>, -> ShortCircuitPreorder<'a, 'tcx, F> -{ - pub fn new( - body: &'tcx &'a mir::Body<'tcx>, - filtered_successors: F, - ) -> ShortCircuitPreorder<'a, 'tcx, F> { - let worklist = vec![mir::START_BLOCK]; - - ShortCircuitPreorder { - body, - visited: BitSet::new_empty(body.basic_blocks().len()), - worklist, - filtered_successors, - } - } -} - -impl< - 'a: 'tcx, - 'tcx, - F: Fn( - &'tcx &'a mir::Body<'tcx>, - &'tcx TerminatorKind<'tcx>, - ) -> Box + 'a>, -> Iterator for ShortCircuitPreorder<'a, 'tcx, F> -{ - type Item = (BasicBlock, &'a BasicBlockData<'tcx>); - - fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { - while let Some(idx) = self.worklist.pop() { - if !self.visited.insert(idx) { - continue; - } - - let data = &self.body[idx]; - - if let Some(ref term) = data.terminator { - self.worklist.extend((self.filtered_successors)(&self.body, &term.kind)); - } - - return Some((idx, data)); - } - - None - } - - fn size_hint(&self) -> (usize, Option) { - let size = self.body.basic_blocks().len() - self.visited.count(); - (size, Some(size)) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,588 +0,0 @@ -pub mod query; - -mod counters; -mod debug; -mod graph; -mod spans; - -#[cfg(test)] -mod tests; - -use counters::CoverageCounters; -use graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; -use spans::{CoverageSpan, CoverageSpans}; - -use crate::transform::MirPass; -use crate::util::pretty; - -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::graph::WithNumNodes; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lrc; -use rustc_index::vec::IndexVec; -use rustc_middle::hir; -use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::ich::StableHashingContext; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::coverage::*; -use rustc_middle::mir::{ - self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator, - TerminatorKind, -}; -use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::DefId; -use rustc_span::source_map::SourceMap; -use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol}; - -/// A simple error message wrapper for `coverage::Error`s. -#[derive(Debug)] -struct Error { - message: String, -} - -impl Error { - pub fn from_string(message: String) -> Result { - Err(Self { message }) - } -} - -/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected -/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen -/// to construct the coverage map. -pub struct InstrumentCoverage; - -impl<'tcx> MirPass<'tcx> for InstrumentCoverage { - fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { - let mir_source = mir_body.source; - - // If the InstrumentCoverage pass is called on promoted MIRs, skip them. - // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601 - if mir_source.promoted.is_some() { - trace!( - "InstrumentCoverage skipped for {:?} (already promoted for Miri evaluation)", - mir_source.def_id() - ); - return; - } - - let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local()); - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); - - // Only instrument functions, methods, and closures (not constants since they are evaluated - // at compile time by Miri). - // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const - // expressions get coverage spans, we will probably have to "carve out" space for const - // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might - // be tricky if const expressions have no corresponding statements in the enclosing MIR. - // Closures are carved out by their initial `Assign` statement.) - if !is_fn_like { - trace!("InstrumentCoverage skipped for {:?} (not an FnLikeNode)", mir_source.def_id()); - return; - } - - match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind { - TerminatorKind::Unreachable => { - trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`"); - return; - } - _ => {} - } - - let codegen_fn_attrs = tcx.codegen_fn_attrs(mir_source.def_id()); - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { - return; - } - - trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); - Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); - trace!("InstrumentCoverage done for {:?}", mir_source.def_id()); - } -} - -struct Instrumentor<'a, 'tcx> { - pass_name: &'a str, - tcx: TyCtxt<'tcx>, - mir_body: &'a mut mir::Body<'tcx>, - source_file: Lrc, - fn_sig_span: Span, - body_span: Span, - basic_coverage_blocks: CoverageGraph, - coverage_counters: CoverageCounters, -} - -impl<'a, 'tcx> Instrumentor<'a, 'tcx> { - fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { - let source_map = tcx.sess.source_map(); - let def_id = mir_body.source.def_id(); - let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id); - - let body_span = get_body_span(tcx, hir_body, mir_body); - - let source_file = source_map.lookup_source_file(body_span.lo()); - let fn_sig_span = match some_fn_sig.filter(|fn_sig| { - fn_sig.span.ctxt() == body_span.ctxt() - && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo())) - }) { - Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), - None => body_span.shrink_to_lo(), - }; - - debug!( - "instrumenting {}: {:?}, fn sig span: {:?}, body span: {:?}", - if tcx.is_closure(def_id) { "closure" } else { "function" }, - def_id, - fn_sig_span, - body_span - ); - - let function_source_hash = hash_mir_source(tcx, hir_body); - let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); - Self { - pass_name, - tcx, - mir_body, - source_file, - fn_sig_span, - body_span, - basic_coverage_blocks, - coverage_counters: CoverageCounters::new(function_source_hash), - } - } - - fn inject_counters(&'a mut self) { - let tcx = self.tcx; - let mir_source = self.mir_body.source; - let def_id = mir_source.def_id(); - let fn_sig_span = self.fn_sig_span; - let body_span = self.body_span; - - let mut graphviz_data = debug::GraphvizData::new(); - let mut debug_used_expressions = debug::UsedExpressions::new(); - - let dump_mir = pretty::dump_enabled(tcx, self.pass_name, def_id); - let dump_graphviz = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_graphviz; - let dump_spanview = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_spanview.is_some(); - - if dump_graphviz { - graphviz_data.enable(); - self.coverage_counters.enable_debug(); - } - - if dump_graphviz || level_enabled!(tracing::Level::DEBUG) { - debug_used_expressions.enable(); - } - - //////////////////////////////////////////////////// - // Compute `CoverageSpan`s from the `CoverageGraph`. - let coverage_spans = CoverageSpans::generate_coverage_spans( - &self.mir_body, - fn_sig_span, - body_span, - &self.basic_coverage_blocks, - ); - - if dump_spanview { - debug::dump_coverage_spanview( - tcx, - self.mir_body, - &self.basic_coverage_blocks, - self.pass_name, - body_span, - &coverage_spans, - ); - } - - //////////////////////////////////////////////////// - // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure - // every `CoverageSpan` has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` - // and all `Expression` dependencies (operands) are also generated, for any other - // `BasicCoverageBlock`s not already associated with a `CoverageSpan`. - // - // Intermediate expressions (used to compute other `Expression` values), which have no - // direct associate to any `BasicCoverageBlock`, are returned in the method `Result`. - let intermediate_expressions_or_error = self - .coverage_counters - .make_bcb_counters(&mut self.basic_coverage_blocks, &coverage_spans); - - let (result, intermediate_expressions) = match intermediate_expressions_or_error { - Ok(intermediate_expressions) => { - // If debugging, add any intermediate expressions (which are not associated with any - // BCB) to the `debug_used_expressions` map. - if debug_used_expressions.is_enabled() { - for intermediate_expression in &intermediate_expressions { - debug_used_expressions.add_expression_operands(intermediate_expression); - } - } - - //////////////////////////////////////////////////// - // Remove the counter or edge counter from of each `CoverageSpan`s associated - // `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR. - // - // `Coverage` statements injected from `CoverageSpan`s will include the code regions - // (source code start and end positions) to be counted by the associated counter. - // - // These `CoverageSpan`-associated counters are removed from their associated - // `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph` - // are indirect counters (to be injected next, without associated code regions). - self.inject_coverage_span_counters( - coverage_spans, - &mut graphviz_data, - &mut debug_used_expressions, - ); - - //////////////////////////////////////////////////// - // For any remaining `BasicCoverageBlock` counters (that were not associated with - // any `CoverageSpan`), inject `Coverage` statements (_without_ code region `Span`s) - // to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on - // are in fact counted, even though they don't directly contribute to counting - // their own independent code region's coverage. - self.inject_indirect_counters(&mut graphviz_data, &mut debug_used_expressions); - - // Intermediate expressions will be injected as the final step, after generating - // debug output, if any. - //////////////////////////////////////////////////// - - (Ok(()), intermediate_expressions) - } - Err(e) => (Err(e), Vec::new()), - }; - - if graphviz_data.is_enabled() { - // Even if there was an error, a partial CoverageGraph can still generate a useful - // graphviz output. - debug::dump_coverage_graphviz( - tcx, - self.mir_body, - self.pass_name, - &self.basic_coverage_blocks, - &self.coverage_counters.debug_counters, - &graphviz_data, - &intermediate_expressions, - &debug_used_expressions, - ); - } - - if let Err(e) = result { - bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e) - }; - - // Depending on current `debug_options()`, `alert_on_unused_expressions()` could panic, so - // this check is performed as late as possible, to allow other debug output (logs and dump - // files), which might be helpful in analyzing unused expressions, to still be generated. - debug_used_expressions.alert_on_unused_expressions(&self.coverage_counters.debug_counters); - - //////////////////////////////////////////////////// - // Finally, inject the intermediate expressions collected along the way. - for intermediate_expression in intermediate_expressions { - inject_intermediate_expression(self.mir_body, intermediate_expression); - } - } - - /// Inject a counter for each `CoverageSpan`. There can be multiple `CoverageSpan`s for a given - /// BCB, but only one actual counter needs to be incremented per BCB. `bb_counters` maps each - /// `bcb` to its `Counter`, when injected. Subsequent `CoverageSpan`s for a BCB that already has - /// a `Counter` will inject an `Expression` instead, and compute its value by adding `ZERO` to - /// the BCB `Counter` value. - /// - /// If debugging, add every BCB `Expression` associated with a `CoverageSpan`s to the - /// `used_expression_operands` map. - fn inject_coverage_span_counters( - &mut self, - coverage_spans: Vec, - graphviz_data: &mut debug::GraphvizData, - debug_used_expressions: &mut debug::UsedExpressions, - ) { - let tcx = self.tcx; - let source_map = tcx.sess.source_map(); - let body_span = self.body_span; - let file_name = Symbol::intern(&self.source_file.name.prefer_remapped().to_string_lossy()); - - let mut bcb_counters = IndexVec::from_elem_n(None, self.basic_coverage_blocks.num_nodes()); - for covspan in coverage_spans { - let bcb = covspan.bcb; - let span = covspan.span; - let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() { - self.coverage_counters.make_identity_counter(counter_operand) - } else if let Some(counter_kind) = self.bcb_data_mut(bcb).take_counter() { - bcb_counters[bcb] = Some(counter_kind.as_operand_id()); - debug_used_expressions.add_expression_operands(&counter_kind); - counter_kind - } else { - bug!("Every BasicCoverageBlock should have a Counter or Expression"); - }; - graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind); - - debug!( - "Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})", - file_name, - self.source_file, - source_map.span_to_diagnostic_string(span), - source_map.span_to_diagnostic_string(body_span) - ); - - inject_statement( - self.mir_body, - counter_kind, - self.bcb_leader_bb(bcb), - Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)), - ); - } - } - - /// `inject_coverage_span_counters()` looped through the `CoverageSpan`s and injected the - /// counter from the `CoverageSpan`s `BasicCoverageBlock`, removing it from the BCB in the - /// process (via `take_counter()`). - /// - /// Any other counter associated with a `BasicCoverageBlock`, or its incoming edge, but not - /// associated with a `CoverageSpan`, should only exist if the counter is an `Expression` - /// dependency (one of the expression operands). Collect them, and inject the additional - /// counters into the MIR, without a reportable coverage span. - fn inject_indirect_counters( - &mut self, - graphviz_data: &mut debug::GraphvizData, - debug_used_expressions: &mut debug::UsedExpressions, - ) { - let mut bcb_counters_without_direct_coverage_spans = Vec::new(); - for (target_bcb, target_bcb_data) in self.basic_coverage_blocks.iter_enumerated_mut() { - if let Some(counter_kind) = target_bcb_data.take_counter() { - bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind)); - } - if let Some(edge_counters) = target_bcb_data.take_edge_counters() { - for (from_bcb, counter_kind) in edge_counters { - bcb_counters_without_direct_coverage_spans.push(( - Some(from_bcb), - target_bcb, - counter_kind, - )); - } - } - } - - // If debug is enabled, validate that every BCB or edge counter not directly associated - // with a coverage span is at least indirectly associated (it is a dependency of a BCB - // counter that _is_ associated with a coverage span). - debug_used_expressions.validate(&bcb_counters_without_direct_coverage_spans); - - for (edge_from_bcb, target_bcb, counter_kind) in bcb_counters_without_direct_coverage_spans - { - debug_used_expressions.add_unused_expression_if_not_found( - &counter_kind, - edge_from_bcb, - target_bcb, - ); - - match counter_kind { - CoverageKind::Counter { .. } => { - let inject_to_bb = if let Some(from_bcb) = edge_from_bcb { - // The MIR edge starts `from_bb` (the outgoing / last BasicBlock in - // `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the - // `target_bcb`; also called the `leader_bb`). - let from_bb = self.bcb_last_bb(from_bcb); - let to_bb = self.bcb_leader_bb(target_bcb); - - let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); - graphviz_data.set_edge_counter(from_bcb, new_bb, &counter_kind); - debug!( - "Edge {:?} (last {:?}) -> {:?} (leader {:?}) requires a new MIR \ - BasicBlock {:?}, for unclaimed edge counter {}", - edge_from_bcb, - from_bb, - target_bcb, - to_bb, - new_bb, - self.format_counter(&counter_kind), - ); - new_bb - } else { - let target_bb = self.bcb_last_bb(target_bcb); - graphviz_data.add_bcb_dependency_counter(target_bcb, &counter_kind); - debug!( - "{:?} ({:?}) gets a new Coverage statement for unclaimed counter {}", - target_bcb, - target_bb, - self.format_counter(&counter_kind), - ); - target_bb - }; - - inject_statement(self.mir_body, counter_kind, inject_to_bb, None); - } - CoverageKind::Expression { .. } => { - inject_intermediate_expression(self.mir_body, counter_kind) - } - _ => bug!("CoverageKind should be a counter"), - } - } - } - - #[inline] - fn bcb_leader_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock { - self.bcb_data(bcb).leader_bb() - } - - #[inline] - fn bcb_last_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock { - self.bcb_data(bcb).last_bb() - } - - #[inline] - fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData { - &self.basic_coverage_blocks[bcb] - } - - #[inline] - fn bcb_data_mut(&mut self, bcb: BasicCoverageBlock) -> &mut BasicCoverageBlockData { - &mut self.basic_coverage_blocks[bcb] - } - - #[inline] - fn format_counter(&self, counter_kind: &CoverageKind) -> String { - self.coverage_counters.debug_counters.format_counter(counter_kind) - } -} - -fn inject_edge_counter_basic_block( - mir_body: &mut mir::Body<'tcx>, - from_bb: BasicBlock, - to_bb: BasicBlock, -) -> BasicBlock { - let span = mir_body[from_bb].terminator().source_info.span.shrink_to_hi(); - let new_bb = mir_body.basic_blocks_mut().push(BasicBlockData { - statements: vec![], // counter will be injected here - terminator: Some(Terminator { - source_info: SourceInfo::outermost(span), - kind: TerminatorKind::Goto { target: to_bb }, - }), - is_cleanup: false, - }); - let edge_ref = mir_body[from_bb] - .terminator_mut() - .successors_mut() - .find(|successor| **successor == to_bb) - .expect("from_bb should have a successor for to_bb"); - *edge_ref = new_bb; - new_bb -} - -fn inject_statement( - mir_body: &mut mir::Body<'tcx>, - counter_kind: CoverageKind, - bb: BasicBlock, - some_code_region: Option, -) { - debug!( - " injecting statement {:?} for {:?} at code region: {:?}", - counter_kind, bb, some_code_region - ); - let data = &mut mir_body[bb]; - let source_info = data.terminator().source_info; - let statement = Statement { - source_info, - kind: StatementKind::Coverage(Box::new(Coverage { - kind: counter_kind, - code_region: some_code_region, - })), - }; - data.statements.insert(0, statement); -} - -// Non-code expressions are injected into the coverage map, without generating executable code. -fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: CoverageKind) { - debug_assert!(if let CoverageKind::Expression { .. } = expression { true } else { false }); - debug!(" injecting non-code expression {:?}", expression); - let inject_in_bb = mir::START_BLOCK; - let data = &mut mir_body[inject_in_bb]; - let source_info = data.terminator().source_info; - let statement = Statement { - source_info, - kind: StatementKind::Coverage(Box::new(Coverage { kind: expression, code_region: None })), - }; - data.statements.push(statement); -} - -/// Convert the Span into its file name, start line and column, and end line and column -fn make_code_region( - source_map: &SourceMap, - file_name: Symbol, - source_file: &Lrc, - span: Span, - body_span: Span, -) -> CodeRegion { - let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo()); - let (end_line, end_col) = if span.hi() == span.lo() { - let (end_line, mut end_col) = (start_line, start_col); - // Extend an empty span by one character so the region will be counted. - let CharPos(char_pos) = start_col; - if span.hi() == body_span.hi() { - start_col = CharPos(char_pos - 1); - } else { - end_col = CharPos(char_pos + 1); - } - (end_line, end_col) - } else { - source_file.lookup_file_pos(span.hi()) - }; - let start_line = source_map.doctest_offset_line(&source_file.name, start_line); - let end_line = source_map.doctest_offset_line(&source_file.name, end_line); - CodeRegion { - file_name, - start_line: start_line as u32, - start_col: start_col.to_u32() + 1, - end_line: end_line as u32, - end_col: end_col.to_u32() + 1, - } -} - -fn fn_sig_and_body<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, -) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) { - // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back - // to HIR for it. - let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); - (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id)) -} - -fn get_body_span<'tcx>( - tcx: TyCtxt<'tcx>, - hir_body: &rustc_hir::Body<'tcx>, - mir_body: &mut mir::Body<'tcx>, -) -> Span { - let mut body_span = hir_body.value.span; - let def_id = mir_body.source.def_id(); - - if tcx.is_closure(def_id) { - // If the MIR function is a closure, and if the closure body span - // starts from a macro, but it's content is not in that macro, try - // to find a non-macro callsite, and instrument the spans there - // instead. - loop { - let expn_data = body_span.ctxt().outer_expn_data(); - if expn_data.is_root() { - break; - } - if let ExpnKind::Macro { .. } = expn_data.kind { - body_span = expn_data.call_site; - } else { - break; - } - } - } - - body_span -} - -fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { - let mut hcx = tcx.create_no_span_stable_hashing_context(); - hash(&mut hcx, &hir_body.value).to_smaller_hash() -} - -fn hash( - hcx: &mut StableHashingContext<'tcx>, - node: &impl HashStable>, -) -> Fingerprint { - let mut stable_hasher = StableHasher::new(); - node.hash_stable(hcx, &mut stable_hasher); - stable_hasher.finish() -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/query.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/query.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/query.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/query.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -use super::*; - -use rustc_middle::mir::coverage::*; -use rustc_middle::mir::{self, Body, Coverage, CoverageInfo}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::def_id::DefId; - -/// A `query` provider for retrieving coverage information injected into MIR. -pub(crate) fn provide(providers: &mut Providers) { - providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id); - providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id); - providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id); -} - -/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in -/// other words, the number of counter value references injected into the MIR (plus 1 for the -/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected -/// counters have a counter ID from `1..num_counters-1`. -/// -/// `num_expressions` is the number of counter expressions added to the MIR body. -/// -/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend -/// code generate, to lookup counters and expressions by simple u32 indexes. -/// -/// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code -/// including injected counters. (It is OK if some counters are optimized out, but those counters -/// are still included in the total `num_counters` or `num_expressions`.) Simply counting the -/// calls may not work; but computing the number of counters or expressions by adding `1` to the -/// highest ID (for a given instrumented function) is valid. -/// -/// This visitor runs twice, first with `add_missing_operands` set to `false`, to find the maximum -/// counter ID and maximum expression ID based on their enum variant `id` fields; then, as a -/// safeguard, with `add_missing_operands` set to `true`, to find any other counter or expression -/// IDs referenced by expression operands, if not already seen. -/// -/// Ideally, each operand ID in a MIR `CoverageKind::Expression` will have a separate MIR `Coverage` -/// statement for the `Counter` or `Expression` with the referenced ID. but since current or future -/// MIR optimizations can theoretically optimize out segments of a MIR, it may not be possible to -/// guarantee this, so the second pass ensures the `CoverageInfo` counts include all referenced IDs. -struct CoverageVisitor { - info: CoverageInfo, - add_missing_operands: bool, -} - -impl CoverageVisitor { - /// Updates `num_counters` to the maximum encountered zero-based counter_id plus 1. Note the - /// final computed number of counters should be the number of all `CoverageKind::Counter` - /// statements in the MIR *plus one* for the implicit `ZERO` counter. - #[inline(always)] - fn update_num_counters(&mut self, counter_id: u32) { - self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); - } - - /// Computes an expression index for each expression ID, and updates `num_expressions` to the - /// maximum encountered index plus 1. - #[inline(always)] - fn update_num_expressions(&mut self, expression_id: u32) { - let expression_index = u32::MAX - expression_id; - self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1); - } - - fn update_from_expression_operand(&mut self, operand_id: u32) { - if operand_id >= self.info.num_counters { - let operand_as_expression_index = u32::MAX - operand_id; - if operand_as_expression_index >= self.info.num_expressions { - // The operand ID is outside the known range of counter IDs and also outside the - // known range of expression IDs. In either case, the result of a missing operand - // (if and when used in an expression) will be zero, so from a computation - // perspective, it doesn't matter whether it is interepretted as a counter or an - // expression. - // - // However, the `num_counters` and `num_expressions` query results are used to - // allocate arrays when generating the coverage map (during codegen), so choose - // the type that grows either `num_counters` or `num_expressions` the least. - if operand_id - self.info.num_counters - < operand_as_expression_index - self.info.num_expressions - { - self.update_num_counters(operand_id) - } else { - self.update_num_expressions(operand_id) - } - } - } - } - - fn visit_body(&mut self, body: &Body<'_>) { - for bb_data in body.basic_blocks().iter() { - for statement in bb_data.statements.iter() { - if let StatementKind::Coverage(box ref coverage) = statement.kind { - if is_inlined(body, statement) { - continue; - } - self.visit_coverage(coverage); - } - } - } - } - - fn visit_coverage(&mut self, coverage: &Coverage) { - if self.add_missing_operands { - match coverage.kind { - CoverageKind::Expression { lhs, rhs, .. } => { - self.update_from_expression_operand(u32::from(lhs)); - self.update_from_expression_operand(u32::from(rhs)); - } - _ => {} - } - } else { - match coverage.kind { - CoverageKind::Counter { id, .. } => { - self.update_num_counters(u32::from(id)); - } - CoverageKind::Expression { id, .. } => { - self.update_num_expressions(u32::from(id)); - } - _ => {} - } - } - } -} - -fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> CoverageInfo { - let mir_body = tcx.instance_mir(instance_def); - - let mut coverage_visitor = CoverageVisitor { - // num_counters always has at least the `ZERO` counter. - info: CoverageInfo { num_counters: 1, num_expressions: 0 }, - add_missing_operands: false, - }; - - coverage_visitor.visit_body(mir_body); - - coverage_visitor.add_missing_operands = true; - coverage_visitor.visit_body(mir_body); - - coverage_visitor.info -} - -fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { - if tcx.is_mir_available(def_id) { - let body = mir_body(tcx, def_id); - for bb_data in body.basic_blocks().iter() { - for statement in bb_data.statements.iter() { - if let StatementKind::Coverage(box ref coverage) = statement.kind { - if let Some(code_region) = coverage.code_region.as_ref() { - if is_inlined(body, statement) { - continue; - } - return Some(code_region.file_name); - } - } - } - } - } - return None; -} - -fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> { - let body = mir_body(tcx, def_id); - body.basic_blocks() - .iter() - .map(|data| { - data.statements.iter().filter_map(|statement| match statement.kind { - StatementKind::Coverage(box ref coverage) => { - if is_inlined(body, statement) { - None - } else { - coverage.code_region.as_ref() // may be None - } - } - _ => None, - }) - }) - .flatten() - .collect() -} - -fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { - let scope_data = &body.source_scopes[statement.source_info.scope]; - scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some() -} - -/// This function ensures we obtain the correct MIR for the given item irrespective of -/// whether that means const mir or runtime mir. For `const fn` this opts for runtime -/// mir. -fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> { - let id = ty::WithOptConstParam::unknown(def_id); - let def = ty::InstanceDef::Item(id); - tcx.instance_mir(def) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/spans.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/spans.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/spans.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/spans.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,900 +0,0 @@ -use super::debug::term_type; -use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; - -use crate::util::spanview::source_range_no_file; - -use rustc_data_structures::graph::WithNumNodes; -use rustc_middle::mir::{ - self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, -}; -use rustc_middle::ty::TyCtxt; - -use rustc_span::source_map::original_sp; -use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol}; - -use std::cell::RefCell; -use std::cmp::Ordering; - -#[derive(Debug, Copy, Clone)] -pub(super) enum CoverageStatement { - Statement(BasicBlock, Span, usize), - Terminator(BasicBlock, Span), -} - -impl CoverageStatement { - pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String { - match *self { - Self::Statement(bb, span, stmt_index) => { - let stmt = &mir_body[bb].statements[stmt_index]; - format!( - "{}: @{}[{}]: {:?}", - source_range_no_file(tcx, &span), - bb.index(), - stmt_index, - stmt - ) - } - Self::Terminator(bb, span) => { - let term = mir_body[bb].terminator(); - format!( - "{}: @{}.{}: {:?}", - source_range_no_file(tcx, &span), - bb.index(), - term_type(&term.kind), - term.kind - ) - } - } - } - - pub fn span(&self) -> &Span { - match self { - Self::Statement(_, span, _) | Self::Terminator(_, span) => span, - } - } -} - -/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that -/// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s. -/// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent -/// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the -/// `CoverageStatement` vectors, and the `Span`s to cover the extent of the combined `Span`s. -/// -/// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that -/// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches -/// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock` -/// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`. -#[derive(Debug, Clone)] -pub(super) struct CoverageSpan { - pub span: Span, - pub expn_span: Span, - pub current_macro_or_none: RefCell>>, - pub bcb: BasicCoverageBlock, - pub coverage_statements: Vec, - pub is_closure: bool, -} - -impl CoverageSpan { - pub fn for_fn_sig(fn_sig_span: Span) -> Self { - Self { - span: fn_sig_span, - expn_span: fn_sig_span, - current_macro_or_none: Default::default(), - bcb: START_BCB, - coverage_statements: vec![], - is_closure: false, - } - } - - pub fn for_statement( - statement: &Statement<'tcx>, - span: Span, - expn_span: Span, - bcb: BasicCoverageBlock, - bb: BasicBlock, - stmt_index: usize, - ) -> Self { - let is_closure = match statement.kind { - StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind { - AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true, - _ => false, - }, - _ => false, - }; - - Self { - span, - expn_span, - current_macro_or_none: Default::default(), - bcb, - coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)], - is_closure, - } - } - - pub fn for_terminator( - span: Span, - expn_span: Span, - bcb: BasicCoverageBlock, - bb: BasicBlock, - ) -> Self { - Self { - span, - expn_span, - current_macro_or_none: Default::default(), - bcb, - coverage_statements: vec![CoverageStatement::Terminator(bb, span)], - is_closure: false, - } - } - - pub fn merge_from(&mut self, mut other: CoverageSpan) { - debug_assert!(self.is_mergeable(&other)); - self.span = self.span.to(other.span); - self.coverage_statements.append(&mut other.coverage_statements); - } - - pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) { - self.coverage_statements.retain(|covstmt| covstmt.span().hi() <= cutoff_pos); - if let Some(highest_covstmt) = - self.coverage_statements.iter().max_by_key(|covstmt| covstmt.span().hi()) - { - self.span = self.span.with_hi(highest_covstmt.span().hi()); - } - } - - #[inline] - pub fn is_mergeable(&self, other: &Self) -> bool { - self.is_in_same_bcb(other) && !(self.is_closure || other.is_closure) - } - - #[inline] - pub fn is_in_same_bcb(&self, other: &Self) -> bool { - self.bcb == other.bcb - } - - pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String { - format!( - "{}\n {}", - source_range_no_file(tcx, &self.span), - self.format_coverage_statements(tcx, mir_body).replace("\n", "\n "), - ) - } - - pub fn format_coverage_statements( - &self, - tcx: TyCtxt<'tcx>, - mir_body: &'a mir::Body<'tcx>, - ) -> String { - let mut sorted_coverage_statements = self.coverage_statements.clone(); - sorted_coverage_statements.sort_unstable_by_key(|covstmt| match *covstmt { - CoverageStatement::Statement(bb, _, index) => (bb, index), - CoverageStatement::Terminator(bb, _) => (bb, usize::MAX), - }); - sorted_coverage_statements - .iter() - .map(|covstmt| covstmt.format(tcx, mir_body)) - .collect::>() - .join("\n") - } - - /// If the span is part of a macro, returns the macro name symbol. - pub fn current_macro(&self) -> Option { - self.current_macro_or_none - .borrow_mut() - .get_or_insert_with(|| { - if let ExpnKind::Macro(MacroKind::Bang, current_macro) = - self.expn_span.ctxt().outer_expn_data().kind - { - return Some(current_macro); - } - None - }) - .map(|symbol| symbol) - } - - /// If the span is part of a macro, and the macro is visible (expands directly to the given - /// body_span), returns the macro name symbol. - pub fn visible_macro(&self, body_span: Span) -> Option { - if let Some(current_macro) = self.current_macro() { - if self.expn_span.parent().unwrap_or_else(|| bug!("macro must have a parent")).ctxt() - == body_span.ctxt() - { - return Some(current_macro); - } - } - None - } - - pub fn is_macro_expansion(&self) -> bool { - self.current_macro().is_some() - } -} - -/// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a -/// minimal set of `CoverageSpan`s, using the BCB CFG to determine where it is safe and useful to: -/// -/// * Remove duplicate source code coverage regions -/// * Merge spans that represent continuous (both in source code and control flow), non-branching -/// execution -/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) -pub struct CoverageSpans<'a, 'tcx> { - /// The MIR, used to look up `BasicBlockData`. - mir_body: &'a mir::Body<'tcx>, - - /// A `Span` covering the signature of function for the MIR. - fn_sig_span: Span, - - /// A `Span` covering the function body of the MIR (typically from left curly brace to right - /// curly brace). - body_span: Span, - - /// The BasicCoverageBlock Control Flow Graph (BCB CFG). - basic_coverage_blocks: &'a CoverageGraph, - - /// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative - /// dominance between the `BasicCoverageBlock`s of equal `Span`s. - sorted_spans_iter: Option>, - - /// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the - /// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to - /// `pending_dups`). If `curr` is not discarded or merged, it becomes `prev` for the next - /// iteration. - some_curr: Option, - - /// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span` - /// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()` - /// is mutated. - curr_original_span: Span, - - /// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`. - /// If that `curr` was discarded, `prev` retains its value from the previous iteration. - some_prev: Option, - - /// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span` - /// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()` - /// is mutated. - prev_original_span: Span, - - /// A copy of the expn_span from the prior iteration. - prev_expn_span: Option, - - /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and - /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list. - /// If a new `curr` span also fits this criteria (compared to an existing list of - /// `pending_dups`), that `curr` `CoverageSpan` moves to `prev` before possibly being added to - /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups` - /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev` - /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a - /// `prev` with a matching `Span`) - pending_dups: Vec, - - /// The final `CoverageSpan`s to add to the coverage map. A `Counter` or `Expression` - /// will also be injected into the MIR for each `CoverageSpan`. - refined_spans: Vec, -} - -impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { - /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be - /// counted. - /// - /// The basic steps are: - /// - /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each - /// `BasicCoverageBlockData`. - /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position - /// are sorted with longer spans before shorter spans; and equal spans are sorted - /// (deterministically) based on "dominator" relationship (if any). - /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, - /// if another span or spans are already counting the same code region), or should be merged - /// into a broader combined span (because it represents a contiguous, non-branching, and - /// uninterrupted region of source code). - /// - /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since - /// closures have their own MIR, their `Span` in their enclosing function should be left - /// "uncovered". - /// - /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need - /// to be). - pub(super) fn generate_coverage_spans( - mir_body: &'a mir::Body<'tcx>, - fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span` - body_span: Span, - basic_coverage_blocks: &'a CoverageGraph, - ) -> Vec { - let mut coverage_spans = CoverageSpans { - mir_body, - fn_sig_span, - body_span, - basic_coverage_blocks, - sorted_spans_iter: None, - refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), - some_curr: None, - curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), - some_prev: None, - prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), - prev_expn_span: None, - pending_dups: Vec::new(), - }; - - let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans(); - - coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter()); - - coverage_spans.to_refined_spans() - } - - fn mir_to_initial_sorted_coverage_spans(&self) -> Vec { - let mut initial_spans = Vec::::with_capacity(self.mir_body.num_nodes() * 2); - for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() { - for coverage_span in self.bcb_to_initial_coverage_spans(bcb, bcb_data) { - initial_spans.push(coverage_span); - } - } - - if initial_spans.is_empty() { - // This can happen if, for example, the function is unreachable (contains only a - // `BasicBlock`(s) with an `Unreachable` terminator). - return initial_spans; - } - - initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span)); - - initial_spans.sort_unstable_by(|a, b| { - if a.span.lo() == b.span.lo() { - if a.span.hi() == b.span.hi() { - if a.is_in_same_bcb(b) { - Some(Ordering::Equal) - } else { - // Sort equal spans by dominator relationship, in reverse order (so - // dominators always come after the dominated equal spans). When later - // comparing two spans in order, the first will either dominate the second, - // or they will have no dominator relationship. - self.basic_coverage_blocks.dominators().rank_partial_cmp(b.bcb, a.bcb) - } - } else { - // Sort hi() in reverse order so shorter spans are attempted after longer spans. - // This guarantees that, if a `prev` span overlaps, and is not equal to, a - // `curr` span, the prev span either extends further left of the curr span, or - // they start at the same position and the prev span extends further right of - // the end of the curr span. - b.span.hi().partial_cmp(&a.span.hi()) - } - } else { - a.span.lo().partial_cmp(&b.span.lo()) - } - .unwrap() - }); - - initial_spans - } - - /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and - /// de-duplicated `CoverageSpan`s. - fn to_refined_spans(mut self) -> Vec { - while self.next_coverage_span() { - if self.some_prev.is_none() { - debug!(" initial span"); - self.check_invoked_macro_name_span(); - } else if self.curr().is_mergeable(self.prev()) { - debug!(" same bcb (and neither is a closure), merge with prev={:?}", self.prev()); - let prev = self.take_prev(); - self.curr_mut().merge_from(prev); - self.check_invoked_macro_name_span(); - // Note that curr.span may now differ from curr_original_span - } else if self.prev_ends_before_curr() { - debug!( - " different bcbs and disjoint spans, so keep curr for next iter, and add \ - prev={:?}", - self.prev() - ); - let prev = self.take_prev(); - self.push_refined_span(prev); - self.check_invoked_macro_name_span(); - } else if self.prev().is_closure { - // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the - // next iter - debug!( - " curr overlaps a closure (prev). Drop curr and keep prev for next iter. \ - prev={:?}", - self.prev() - ); - self.take_curr(); - } else if self.curr().is_closure { - self.carve_out_span_for_closure(); - } else if self.prev_original_span == self.curr().span { - // Note that this compares the new (`curr`) span to `prev_original_span`. - // In this branch, the actual span byte range of `prev_original_span` is not - // important. What is important is knowing whether the new `curr` span was - // **originally** the same as the original span of `prev()`. The original spans - // reflect their original sort order, and for equal spans, conveys a partial - // ordering based on CFG dominator priority. - if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() { - // Macros that expand to include branching (such as - // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or - // `trace!()) typically generate callee spans with identical - // ranges (typically the full span of the macro) for all - // `BasicBlocks`. This makes it impossible to distinguish - // the condition (`if val1 != val2`) from the optional - // branched statements (such as the call to `panic!()` on - // assert failure). In this case it is better (or less - // worse) to drop the optional branch bcbs and keep the - // non-conditional statements, to count when reached. - debug!( - " curr and prev are part of a macro expansion, and curr has the same span \ - as prev, but is in a different bcb. Drop curr and keep prev for next iter. \ - prev={:?}", - self.prev() - ); - self.take_curr(); - } else { - self.hold_pending_dups_unless_dominated(); - } - } else { - self.cutoff_prev_at_overlapping_curr(); - self.check_invoked_macro_name_span(); - } - } - - debug!(" AT END, adding last prev={:?}", self.prev()); - let prev = self.take_prev(); - let pending_dups = self.pending_dups.split_off(0); - for dup in pending_dups { - debug!(" ...adding at least one pending dup={:?}", dup); - self.push_refined_span(dup); - } - - // Async functions wrap a closure that implements the body to be executed. The enclosing - // function is called and returns an `impl Future` without initially executing any of the - // body. To avoid showing the return from the enclosing function as a "covered" return from - // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is - // excluded. The closure's `Return` is the only one that will be counted. This provides - // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace - // of the function body.) - let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() { - last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi() - } else { - false - }; - - if !body_ends_with_closure { - self.push_refined_span(prev); - } - - // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage - // regions for the current function leave room for the closure's own coverage regions - // (injected separately, from the closure's own MIR). - self.refined_spans.retain(|covspan| !covspan.is_closure); - self.refined_spans - } - - fn push_refined_span(&mut self, covspan: CoverageSpan) { - let len = self.refined_spans.len(); - if len > 0 { - let last = &mut self.refined_spans[len - 1]; - if last.is_mergeable(&covspan) { - debug!( - "merging new refined span with last refined span, last={:?}, covspan={:?}", - last, covspan - ); - last.merge_from(covspan); - return; - } - } - self.refined_spans.push(covspan) - } - - fn check_invoked_macro_name_span(&mut self) { - if let Some(visible_macro) = self.curr().visible_macro(self.body_span) { - if self.prev_expn_span.map_or(true, |prev_expn_span| { - self.curr().expn_span.ctxt() != prev_expn_span.ctxt() - }) { - let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo(); - let after_macro_bang = - merged_prefix_len + BytePos(visible_macro.as_str().bytes().count() as u32 + 1); - let mut macro_name_cov = self.curr().clone(); - self.curr_mut().span = - self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang); - macro_name_cov.span = - macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang); - debug!( - " and curr starts a new macro expansion, so add a new span just for \ - the macro `{}!`, new span={:?}", - visible_macro, macro_name_cov - ); - self.push_refined_span(macro_name_cov); - } - } - } - - // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of - // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated - // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will - // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple - // `Statement`s and/or `Terminator`s.) - fn bcb_to_initial_coverage_spans( - &self, - bcb: BasicCoverageBlock, - bcb_data: &'a BasicCoverageBlockData, - ) -> Vec { - bcb_data - .basic_blocks - .iter() - .flat_map(|&bb| { - let data = &self.mir_body[bb]; - data.statements - .iter() - .enumerate() - .filter_map(move |(index, statement)| { - filtered_statement_span(statement).map(|span| { - CoverageSpan::for_statement( - statement, - function_source_span(span, self.body_span), - span, - bcb, - bb, - index, - ) - }) - }) - .chain(filtered_terminator_span(data.terminator()).map(|span| { - CoverageSpan::for_terminator( - function_source_span(span, self.body_span), - span, - bcb, - bb, - ) - })) - }) - .collect() - } - - fn curr(&self) -> &CoverageSpan { - self.some_curr - .as_ref() - .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) - } - - fn curr_mut(&mut self) -> &mut CoverageSpan { - self.some_curr - .as_mut() - .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) - } - - fn prev(&self) -> &CoverageSpan { - self.some_prev - .as_ref() - .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) - } - - fn prev_mut(&mut self) -> &mut CoverageSpan { - self.some_prev - .as_mut() - .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) - } - - fn take_prev(&mut self) -> CoverageSpan { - self.some_prev.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) - } - - /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the - /// `pending_dups` spans), then one of the following two things happened during the previous - /// iteration: - /// * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups - /// (in which case there should be at least two spans in `pending_dups`); or - /// * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case - /// `pending_dups` could have as few as one span) - /// In either case, no more spans will match the span of `pending_dups`, so - /// add the `pending_dups` if they don't overlap `curr`, and clear the list. - fn check_pending_dups(&mut self) { - if let Some(dup) = self.pending_dups.last() { - if dup.span != self.prev().span { - debug!( - " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \ - previous iteration, or prev started a new disjoint span" - ); - if dup.span.hi() <= self.curr().span.lo() { - let pending_dups = self.pending_dups.split_off(0); - for dup in pending_dups.into_iter() { - debug!(" ...adding at least one pending={:?}", dup); - self.push_refined_span(dup); - } - } else { - self.pending_dups.clear(); - } - } - } - } - - /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order. - fn next_coverage_span(&mut self) -> bool { - if let Some(curr) = self.some_curr.take() { - self.prev_expn_span = Some(curr.expn_span); - self.some_prev = Some(curr); - self.prev_original_span = self.curr_original_span; - } - while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() { - debug!("FOR curr={:?}", curr); - if self.some_prev.is_some() && self.prev_starts_after_next(&curr) { - debug!( - " prev.span starts after curr.span, so curr will be dropped (skipping past \ - closure?); prev={:?}", - self.prev() - ); - } else { - // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed - // by `self.curr_mut().merge_from(prev)`. - self.curr_original_span = curr.span; - self.some_curr.replace(curr); - self.check_pending_dups(); - return true; - } - } - false - } - - /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the - /// `curr` coverage span. - fn take_curr(&mut self) -> CoverageSpan { - self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) - } - - /// Returns true if the curr span should be skipped because prev has already advanced beyond the - /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region - /// of code, such as skipping past a closure. - fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool { - self.prev().span.lo() > next_curr.span.lo() - } - - /// Returns true if the curr span starts past the end of the prev span, which means they don't - /// overlap, so we now know the prev can be added to the refined coverage spans. - fn prev_ends_before_curr(&self) -> bool { - self.prev().span.hi() <= self.curr().span.lo() - } - - /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from - /// `prev`'s span. (The closure's coverage counters will be injected when processing the - /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span - /// extends to the right of the closure, update `prev` to that portion of the span. For any - /// `pending_dups`, repeat the same process. - fn carve_out_span_for_closure(&mut self) { - let curr_span = self.curr().span; - let left_cutoff = curr_span.lo(); - let right_cutoff = curr_span.hi(); - let has_pre_closure_span = self.prev().span.lo() < right_cutoff; - let has_post_closure_span = self.prev().span.hi() > right_cutoff; - let mut pending_dups = self.pending_dups.split_off(0); - if has_pre_closure_span { - let mut pre_closure = self.prev().clone(); - pre_closure.span = pre_closure.span.with_hi(left_cutoff); - debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure); - if !pending_dups.is_empty() { - for mut dup in pending_dups.iter().cloned() { - dup.span = dup.span.with_hi(left_cutoff); - debug!(" ...and at least one pre_closure dup={:?}", dup); - self.push_refined_span(dup); - } - } - self.push_refined_span(pre_closure); - } - if has_post_closure_span { - // Mutate `prev.span()` to start after the closure (and discard curr). - // (**NEVER** update `prev_original_span` because it affects the assumptions - // about how the `CoverageSpan`s are ordered.) - self.prev_mut().span = self.prev().span.with_lo(right_cutoff); - debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev()); - for dup in pending_dups.iter_mut() { - debug!(" ...and at least one overlapping dup={:?}", dup); - dup.span = dup.span.with_lo(right_cutoff); - } - self.pending_dups.append(&mut pending_dups); - let closure_covspan = self.take_curr(); - self.push_refined_span(closure_covspan); // since self.prev() was already updated - } else { - pending_dups.clear(); - } - } - - /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all - /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed. - /// If prev.span() was merged into other spans (with matching BCB, for instance), - /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`. - /// If prev.span() was split off to the right of a closure, prev.span().lo() will be - /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is - /// not as important as knowing that `prev()` **used to have the same span** as `curr(), - /// which means their sort order is still meaningful for determinating the dominator - /// relationship. - /// - /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if - /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held, - /// until their disposition is determined. In this latter case, the `prev` dup is moved into - /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration. - fn hold_pending_dups_unless_dominated(&mut self) { - // Equal coverage spans are ordered by dominators before dominated (if any), so it should be - // impossible for `curr` to dominate any previous `CoverageSpan`. - debug_assert!(!self.span_bcb_is_dominated_by(self.prev(), self.curr())); - - let initial_pending_count = self.pending_dups.len(); - if initial_pending_count > 0 { - let mut pending_dups = self.pending_dups.split_off(0); - pending_dups.retain(|dup| !self.span_bcb_is_dominated_by(self.curr(), dup)); - self.pending_dups.append(&mut pending_dups); - if self.pending_dups.len() < initial_pending_count { - debug!( - " discarded {} of {} pending_dups that dominated curr", - initial_pending_count - self.pending_dups.len(), - initial_pending_count - ); - } - } - - if self.span_bcb_is_dominated_by(self.curr(), self.prev()) { - debug!( - " different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}", - self.prev() - ); - self.cutoff_prev_at_overlapping_curr(); - // If one span dominates the other, assocate the span with the code from the dominated - // block only (`curr`), and discard the overlapping portion of the `prev` span. (Note - // that if `prev.span` is wider than `prev_original_span`, a `CoverageSpan` will still - // be created for `prev`s block, for the non-overlapping portion, left of `curr.span`.) - // - // For example: - // match somenum { - // x if x < 1 => { ... } - // }... - // - // The span for the first `x` is referenced by both the pattern block (every time it is - // evaluated) and the arm code (only when matched). The counter will be applied only to - // the dominated block. This allows coverage to track and highlight things like the - // assignment of `x` above, if the branch is matched, making `x` available to the arm - // code; and to track and highlight the question mark `?` "try" operator at the end of - // a function call returning a `Result`, so the `?` is covered when the function returns - // an `Err`, and not counted as covered if the function always returns `Ok`. - } else { - // Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.) - // If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as - // well; but if `curr` is added to refined_spans, the `pending_dups` will also be added. - debug!( - " different bcbs but SAME spans, and neither dominates, so keep curr for \ - next iter, and, pending upcoming spans (unless overlapping) add prev={:?}", - self.prev() - ); - let prev = self.take_prev(); - self.pending_dups.push(prev); - } - } - - /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_ - /// statements that end before `curr.lo()` (if any), and add the portion of the - /// combined span for those statements. Any other statements have overlapping spans - /// that can be ignored because `curr` and/or other upcoming statements/spans inside - /// the overlap area will produce their own counters. This disambiguation process - /// avoids injecting multiple counters for overlapping spans, and the potential for - /// double-counting. - fn cutoff_prev_at_overlapping_curr(&mut self) { - debug!( - " different bcbs, overlapping spans, so ignore/drop pending and only add prev \ - if it has statements that end before curr; prev={:?}", - self.prev() - ); - if self.pending_dups.is_empty() { - let curr_span = self.curr().span; - self.prev_mut().cutoff_statements_at(curr_span.lo()); - if self.prev().coverage_statements.is_empty() { - debug!(" ... no non-overlapping statements to add"); - } else { - debug!(" ... adding modified prev={:?}", self.prev()); - let prev = self.take_prev(); - self.push_refined_span(prev); - } - } else { - // with `pending_dups`, `prev` cannot have any statements that don't overlap - self.pending_dups.clear(); - } - } - - fn span_bcb_is_dominated_by(&self, covspan: &CoverageSpan, dom_covspan: &CoverageSpan) -> bool { - self.basic_coverage_blocks.is_dominated_by(covspan.bcb, dom_covspan.bcb) - } -} - -/// If the MIR `Statement` has a span contributive to computing coverage spans, -/// return it; otherwise return `None`. -pub(super) fn filtered_statement_span(statement: &'a Statement<'tcx>) -> Option { - match statement.kind { - // These statements have spans that are often outside the scope of the executed source code - // for their parent `BasicBlock`. - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - // Coverage should not be encountered, but don't inject coverage coverage - | StatementKind::Coverage(_) - // Ignore `Nop`s - | StatementKind::Nop => None, - - // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead` - // statements be more consistent? - // - // FakeReadCause::ForGuardBinding, in this example: - // match somenum { - // x if x < 1 => { ... } - // }... - // The BasicBlock within the match arm code included one of these statements, but the span - // for it covered the `1` in this source. The actual statements have nothing to do with that - // source span: - // FakeRead(ForGuardBinding, _4); - // where `_4` is: - // _4 = &_1; (at the span for the first `x`) - // and `_1` is the `Place` for `somenum`. - // - // If and when the Issue is resolved, remove this special case match pattern: - StatementKind::FakeRead(box (cause, _)) if cause == FakeReadCause::ForGuardBinding => None, - - // Retain spans from all other statements - StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assign(_) - | StatementKind::SetDiscriminant { .. } - | StatementKind::LlvmInlineAsm(_) - | StatementKind::Retag(_, _) - | StatementKind::AscribeUserType(_, _) => { - Some(statement.source_info.span) - } - } -} - -/// If the MIR `Terminator` has a span contributive to computing coverage spans, -/// return it; otherwise return `None`. -pub(super) fn filtered_terminator_span(terminator: &'a Terminator<'tcx>) -> Option { - match terminator.kind { - // These terminators have spans that don't positively contribute to computing a reasonable - // span of actually executed source code. (For example, SwitchInt terminators extracted from - // an `if condition { block }` has a span that includes the executed block, if true, - // but for coverage, the code region executed, up to *and* through the SwitchInt, - // actually stops before the if's block.) - TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG - | TerminatorKind::Assert { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::SwitchInt { .. } - // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::Goto { .. } => None, - - // Call `func` operand can have a more specific span when part of a chain of calls - | TerminatorKind::Call { ref func, .. } => { - let mut span = terminator.source_info.span; - if let mir::Operand::Constant(box constant) = func { - if constant.span.lo() > span.lo() { - span = span.with_lo(constant.span.lo()); - } - } - Some(span) - } - - // Retain spans from all other terminators - TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Yield { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => { - Some(terminator.source_info.span) - } - } -} - -/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range -/// within the function's body source. This span is guaranteed to be contained -/// within, or equal to, the `body_span`. If the extrapolated span is not -/// contained within the `body_span`, the `body_span` is returned. -/// -/// [^1]Expansions result from Rust syntax including macros, syntactic sugar, -/// etc.). -#[inline] -pub(super) fn function_source_span(span: Span, body_span: Span) -> Span { - let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt()); - if body_span.contains(original_span) { original_span } else { body_span } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -[package] -name = "coverage_test_macros" -version = "0.0.0" -edition = "2018" - -[lib] -proc-macro = true -doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -use proc_macro::TokenStream; - -#[proc_macro] -pub fn let_bcb(item: TokenStream) -> TokenStream { - format!("let bcb{} = graph::BasicCoverageBlock::from_usize({});", item, item).parse().unwrap() -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/coverage/tests.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,721 +0,0 @@ -//! This crate hosts a selection of "unit tests" for components of the `InstrumentCoverage` MIR -//! pass. -//! -//! ```shell -//! ./x.py test --keep-stage 1 compiler/rustc_mir --test-args '--show-output coverage' -//! ``` -//! -//! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage` -//! functions and algorithms. Mocked objects include instances of `mir::Body`; including -//! `Terminator`s of various `kind`s, and `Span` objects. Some functions used by or used on -//! real, runtime versions of these mocked-up objects have constraints (such as cross-thread -//! limitations) and deep dependencies on other elements of the full Rust compiler (which is -//! *not* constructed or mocked for these tests). -//! -//! Of particular note, attempting to simply print elements of the `mir::Body` with default -//! `Debug` formatting can fail because some `Debug` format implementations require the -//! `TyCtxt`, obtained via a static global variable that is *not* set for these tests. -//! Initializing the global type context is prohibitively complex for the scope and scale of these -//! tests (essentially requiring initializing the entire compiler). -//! -//! Also note, some basic features of `Span` also rely on the `Span`s own "session globals", which -//! are unrelated to the `TyCtxt` global. Without initializing the `Span` session globals, some -//! basic, coverage-specific features would be impossible to test, but thankfully initializing these -//! globals is comparatively simpler. The easiest way is to wrap the test in a closure argument -//! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`. - -use super::counters; -use super::debug; -use super::graph; -use super::spans; - -use coverage_test_macros::let_bcb; - -use rustc_data_structures::graph::WithNumNodes; -use rustc_data_structures::graph::WithSuccessors; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::coverage::CoverageKind; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, DebruijnIndex, TyS, TypeFlags}; -use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP}; - -// All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`. -const TEMP_BLOCK: BasicBlock = BasicBlock::MAX; - -fn dummy_ty() -> &'static TyS<'static> { - thread_local! { - static DUMMY_TYS: &'static TyS<'static> = Box::leak(Box::new(TyS::make_for_test( - ty::Bool, - TypeFlags::empty(), - DebruijnIndex::from_usize(0), - ))); - } - - &DUMMY_TYS.with(|tys| *tys) -} - -struct MockBlocks<'tcx> { - blocks: IndexVec>, - dummy_place: Place<'tcx>, - next_local: usize, -} - -impl<'tcx> MockBlocks<'tcx> { - fn new() -> Self { - Self { - blocks: IndexVec::new(), - dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() }, - next_local: 0, - } - } - - fn new_temp(&mut self) -> Local { - let index = self.next_local; - self.next_local += 1; - Local::new(index) - } - - fn push(&mut self, kind: TerminatorKind<'tcx>) -> BasicBlock { - let next_lo = if let Some(last) = self.blocks.last() { - self.blocks[last].terminator().source_info.span.hi() - } else { - BytePos(1) - }; - let next_hi = next_lo + BytePos(1); - self.blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)), - kind, - }), - is_cleanup: false, - }) - } - - fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) { - match self.blocks[from_block].terminator_mut().kind { - TerminatorKind::Assert { ref mut target, .. } - | TerminatorKind::Call { destination: Some((_, ref mut target)), .. } - | TerminatorKind::Drop { ref mut target, .. } - | TerminatorKind::DropAndReplace { ref mut target, .. } - | TerminatorKind::FalseEdge { real_target: ref mut target, .. } - | TerminatorKind::FalseUnwind { real_target: ref mut target, .. } - | TerminatorKind::Goto { ref mut target } - | TerminatorKind::InlineAsm { destination: Some(ref mut target), .. } - | TerminatorKind::Yield { resume: ref mut target, .. } => *target = to_block, - ref invalid => bug!("Invalid from_block: {:?}", invalid), - } - } - - fn add_block_from( - &mut self, - some_from_block: Option, - to_kind: TerminatorKind<'tcx>, - ) -> BasicBlock { - let new_block = self.push(to_kind); - if let Some(from_block) = some_from_block { - self.link(from_block, new_block); - } - new_block - } - - fn set_branch(&mut self, switchint: BasicBlock, branch_index: usize, to_block: BasicBlock) { - match self.blocks[switchint].terminator_mut().kind { - TerminatorKind::SwitchInt { ref mut targets, .. } => { - let mut branches = targets.iter().collect::>(); - let otherwise = if branch_index == branches.len() { - to_block - } else { - let old_otherwise = targets.otherwise(); - if branch_index > branches.len() { - branches.push((branches.len() as u128, old_otherwise)); - while branches.len() < branch_index { - branches.push((branches.len() as u128, TEMP_BLOCK)); - } - to_block - } else { - branches[branch_index] = (branch_index as u128, to_block); - old_otherwise - } - }; - *targets = SwitchTargets::new(branches.into_iter(), otherwise); - } - ref invalid => bug!("Invalid BasicBlock kind or no to_block: {:?}", invalid), - } - } - - fn call(&mut self, some_from_block: Option) -> BasicBlock { - self.add_block_from( - some_from_block, - TerminatorKind::Call { - func: Operand::Copy(self.dummy_place.clone()), - args: vec![], - destination: Some((self.dummy_place.clone(), TEMP_BLOCK)), - cleanup: None, - from_hir_call: false, - fn_span: DUMMY_SP, - }, - ) - } - - fn goto(&mut self, some_from_block: Option) -> BasicBlock { - self.add_block_from(some_from_block, TerminatorKind::Goto { target: TEMP_BLOCK }) - } - - fn switchint(&mut self, some_from_block: Option) -> BasicBlock { - let switchint_kind = TerminatorKind::SwitchInt { - discr: Operand::Move(Place::from(self.new_temp())), - switch_ty: dummy_ty(), - targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK), - }; - self.add_block_from(some_from_block, switchint_kind) - } - - fn return_(&mut self, some_from_block: Option) -> BasicBlock { - self.add_block_from(some_from_block, TerminatorKind::Return) - } - - fn to_body(self) -> Body<'tcx> { - Body::new_cfg_only(self.blocks) - } -} - -fn debug_basic_blocks(mir_body: &Body<'tcx>) -> String { - format!( - "{:?}", - mir_body - .basic_blocks() - .iter_enumerated() - .map(|(bb, data)| { - let term = &data.terminator(); - let kind = &term.kind; - let span = term.source_info.span; - let sp = format!("(span:{},{})", span.lo().to_u32(), span.hi().to_u32()); - match kind { - TerminatorKind::Assert { target, .. } - | TerminatorKind::Call { destination: Some((_, target)), .. } - | TerminatorKind::Drop { target, .. } - | TerminatorKind::DropAndReplace { target, .. } - | TerminatorKind::FalseEdge { real_target: target, .. } - | TerminatorKind::FalseUnwind { real_target: target, .. } - | TerminatorKind::Goto { target } - | TerminatorKind::InlineAsm { destination: Some(target), .. } - | TerminatorKind::Yield { resume: target, .. } => { - format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), target) - } - TerminatorKind::SwitchInt { targets, .. } => { - format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), targets) - } - _ => format!("{}{:?}:{}", sp, bb, debug::term_type(kind)), - } - }) - .collect::>() - ) -} - -static PRINT_GRAPHS: bool = false; - -fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { - if PRINT_GRAPHS { - println!( - "digraph {} {{\n{}\n}}", - name, - mir_body - .basic_blocks() - .iter_enumerated() - .map(|(bb, data)| { - format!( - " {:?} [label=\"{:?}: {}\"];\n{}", - bb, - bb, - debug::term_type(&data.terminator().kind), - mir_body - .successors(bb) - .map(|successor| { format!(" {:?} -> {:?};", bb, successor) }) - .collect::>() - .join("\n") - ) - }) - .collect::>() - .join("\n") - ); - } -} - -fn print_coverage_graphviz( - name: &str, - mir_body: &Body<'_>, - basic_coverage_blocks: &graph::CoverageGraph, -) { - if PRINT_GRAPHS { - println!( - "digraph {} {{\n{}\n}}", - name, - basic_coverage_blocks - .iter_enumerated() - .map(|(bcb, bcb_data)| { - format!( - " {:?} [label=\"{:?}: {}\"];\n{}", - bcb, - bcb, - debug::term_type(&bcb_data.terminator(mir_body).kind), - basic_coverage_blocks - .successors(bcb) - .map(|successor| { format!(" {:?} -> {:?};", bcb, successor) }) - .collect::>() - .join("\n") - ) - }) - .collect::>() - .join("\n") - ); - } -} - -/// Create a mock `Body` with a simple flow. -fn goto_switchint() -> Body<'a> { - let mut blocks = MockBlocks::new(); - let start = blocks.call(None); - let goto = blocks.goto(Some(start)); - let switchint = blocks.switchint(Some(goto)); - let then_call = blocks.call(None); - let else_call = blocks.call(None); - blocks.set_branch(switchint, 0, then_call); - blocks.set_branch(switchint, 1, else_call); - blocks.return_(Some(then_call)); - blocks.return_(Some(else_call)); - - let mir_body = blocks.to_body(); - print_mir_graphviz("mir_goto_switchint", &mir_body); - /* Graphviz character plots created using: `graph-easy --as=boxart`: - ┌────────────────┠- │ bb0: Call │ - └────────────────┘ - │ - │ - ▼ - ┌────────────────┠- │ bb1: Goto │ - └────────────────┘ - │ - │ - ▼ - ┌─────────────┠┌────────────────┠- │ bb4: Call │ ◀── │ bb2: SwitchInt │ - └─────────────┘ └────────────────┘ - │ │ - │ │ - ▼ ▼ - ┌─────────────┠┌────────────────┠- │ bb6: Return │ │ bb3: Call │ - └─────────────┘ └────────────────┘ - │ - │ - ▼ - ┌────────────────┠- │ bb5: Return │ - └────────────────┘ - */ - mir_body -} - -macro_rules! assert_successors { - ($basic_coverage_blocks:ident, $i:ident, [$($successor:ident),*]) => { - let mut successors = $basic_coverage_blocks.successors[$i].clone(); - successors.sort_unstable(); - assert_eq!(successors, vec![$($successor),*]); - } -} - -#[test] -fn test_covgraph_goto_switchint() { - let mir_body = goto_switchint(); - if false { - eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body)); - } - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks); - /* - ┌──────────────┠┌─────────────────┠- │ bcb2: Return │ ◀── │ bcb0: SwitchInt │ - └──────────────┘ └─────────────────┘ - │ - │ - ▼ - ┌─────────────────┠- │ bcb1: Return │ - └─────────────────┘ - */ - assert_eq!( - basic_coverage_blocks.num_nodes(), - 3, - "basic_coverage_blocks: {:?}", - basic_coverage_blocks.iter_enumerated().collect::>() - ); - - let_bcb!(0); - let_bcb!(1); - let_bcb!(2); - - assert_successors!(basic_coverage_blocks, bcb0, [bcb1, bcb2]); - assert_successors!(basic_coverage_blocks, bcb1, []); - assert_successors!(basic_coverage_blocks, bcb2, []); -} - -/// Create a mock `Body` with a loop. -fn switchint_then_loop_else_return() -> Body<'a> { - let mut blocks = MockBlocks::new(); - let start = blocks.call(None); - let switchint = blocks.switchint(Some(start)); - let then_call = blocks.call(None); - blocks.set_branch(switchint, 0, then_call); - let backedge_goto = blocks.goto(Some(then_call)); - blocks.link(backedge_goto, switchint); - let else_return = blocks.return_(None); - blocks.set_branch(switchint, 1, else_return); - - let mir_body = blocks.to_body(); - print_mir_graphviz("mir_switchint_then_loop_else_return", &mir_body); - /* - ┌────────────────┠- │ bb0: Call │ - └────────────────┘ - │ - │ - ▼ - ┌─────────────┠┌────────────────┠- │ bb4: Return │ ◀── │ bb1: SwitchInt │ ◀┠- └─────────────┘ └────────────────┘ │ - │ │ - │ │ - ▼ │ - ┌────────────────┠│ - │ bb2: Call │ │ - └────────────────┘ │ - │ │ - │ │ - ▼ │ - ┌────────────────┠│ - │ bb3: Goto │ ─┘ - └────────────────┘ - */ - mir_body -} - -#[test] -fn test_covgraph_switchint_then_loop_else_return() { - let mir_body = switchint_then_loop_else_return(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - print_coverage_graphviz( - "covgraph_switchint_then_loop_else_return", - &mir_body, - &basic_coverage_blocks, - ); - /* - ┌─────────────────┠- │ bcb0: Call │ - └─────────────────┘ - │ - │ - ▼ - ┌────────────┠┌─────────────────┠- │ bcb3: Goto │ ◀── │ bcb1: SwitchInt │ ◀┠- └────────────┘ └─────────────────┘ │ - │ │ │ - │ │ │ - │ ▼ │ - │ ┌─────────────────┠│ - │ │ bcb2: Return │ │ - │ └─────────────────┘ │ - │ │ - └─────────────────────────────────────┘ - */ - assert_eq!( - basic_coverage_blocks.num_nodes(), - 4, - "basic_coverage_blocks: {:?}", - basic_coverage_blocks.iter_enumerated().collect::>() - ); - - let_bcb!(0); - let_bcb!(1); - let_bcb!(2); - let_bcb!(3); - - assert_successors!(basic_coverage_blocks, bcb0, [bcb1]); - assert_successors!(basic_coverage_blocks, bcb1, [bcb2, bcb3]); - assert_successors!(basic_coverage_blocks, bcb2, []); - assert_successors!(basic_coverage_blocks, bcb3, [bcb1]); -} - -/// Create a mock `Body` with nested loops. -fn switchint_loop_then_inner_loop_else_break() -> Body<'a> { - let mut blocks = MockBlocks::new(); - let start = blocks.call(None); - let switchint = blocks.switchint(Some(start)); - let then_call = blocks.call(None); - blocks.set_branch(switchint, 0, then_call); - let else_return = blocks.return_(None); - blocks.set_branch(switchint, 1, else_return); - - let inner_start = blocks.call(Some(then_call)); - let inner_switchint = blocks.switchint(Some(inner_start)); - let inner_then_call = blocks.call(None); - blocks.set_branch(inner_switchint, 0, inner_then_call); - let inner_backedge_goto = blocks.goto(Some(inner_then_call)); - blocks.link(inner_backedge_goto, inner_switchint); - let inner_else_break_goto = blocks.goto(None); - blocks.set_branch(inner_switchint, 1, inner_else_break_goto); - - let backedge_goto = blocks.goto(Some(inner_else_break_goto)); - blocks.link(backedge_goto, switchint); - - let mir_body = blocks.to_body(); - print_mir_graphviz("mir_switchint_loop_then_inner_loop_else_break", &mir_body); - /* - ┌────────────────┠- │ bb0: Call │ - └────────────────┘ - │ - │ - ▼ - ┌─────────────┠┌────────────────┠- │ bb3: Return │ ◀── │ bb1: SwitchInt │ ◀─────┠- └─────────────┘ └────────────────┘ │ - │ │ - │ │ - ▼ │ - ┌────────────────┠│ - │ bb2: Call │ │ - └────────────────┘ │ - │ │ - │ │ - ▼ │ - ┌────────────────┠│ - │ bb4: Call │ │ - └────────────────┘ │ - │ │ - │ │ - ▼ │ - ┌─────────────┠┌────────────────┠│ - │ bb8: Goto │ ◀── │ bb5: SwitchInt │ ◀┠│ - └─────────────┘ └────────────────┘ │ │ - │ │ │ │ - │ │ │ │ - ▼ ▼ │ │ - ┌─────────────┠┌────────────────┠│ │ - │ bb9: Goto │ ─┠│ bb6: Call │ │ │ - └─────────────┘ │ └────────────────┘ │ │ - │ │ │ │ - │ │ │ │ - │ ▼ │ │ - │ ┌────────────────┠│ │ - │ │ bb7: Goto │ ─┘ │ - │ └────────────────┘ │ - │ │ - └───────────────────────────┘ - */ - mir_body -} - -#[test] -fn test_covgraph_switchint_loop_then_inner_loop_else_break() { - let mir_body = switchint_loop_then_inner_loop_else_break(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - print_coverage_graphviz( - "covgraph_switchint_loop_then_inner_loop_else_break", - &mir_body, - &basic_coverage_blocks, - ); - /* - ┌─────────────────┠- │ bcb0: Call │ - └─────────────────┘ - │ - │ - ▼ - ┌──────────────┠┌─────────────────┠- │ bcb2: Return │ ◀── │ bcb1: SwitchInt │ ◀┠- └──────────────┘ └─────────────────┘ │ - │ │ - │ │ - ▼ │ - ┌─────────────────┠│ - │ bcb3: Call │ │ - └─────────────────┘ │ - │ │ - │ │ - ▼ │ - ┌──────────────┠┌─────────────────┠│ - │ bcb6: Goto │ ◀── │ bcb4: SwitchInt │ ◀┼────┠- └──────────────┘ └─────────────────┘ │ │ - │ │ │ │ - │ │ │ │ - │ ▼ │ │ - │ ┌─────────────────┠│ │ - │ │ bcb5: Goto │ ─┘ │ - │ └─────────────────┘ │ - │ │ - └────────────────────────────────────────────┘ - */ - assert_eq!( - basic_coverage_blocks.num_nodes(), - 7, - "basic_coverage_blocks: {:?}", - basic_coverage_blocks.iter_enumerated().collect::>() - ); - - let_bcb!(0); - let_bcb!(1); - let_bcb!(2); - let_bcb!(3); - let_bcb!(4); - let_bcb!(5); - let_bcb!(6); - - assert_successors!(basic_coverage_blocks, bcb0, [bcb1]); - assert_successors!(basic_coverage_blocks, bcb1, [bcb2, bcb3]); - assert_successors!(basic_coverage_blocks, bcb2, []); - assert_successors!(basic_coverage_blocks, bcb3, [bcb4]); - assert_successors!(basic_coverage_blocks, bcb4, [bcb5, bcb6]); - assert_successors!(basic_coverage_blocks, bcb5, [bcb1]); - assert_successors!(basic_coverage_blocks, bcb6, [bcb4]); -} - -#[test] -fn test_find_loop_backedges_none() { - let mir_body = goto_switchint(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - if false { - eprintln!( - "basic_coverage_blocks = {:?}", - basic_coverage_blocks.iter_enumerated().collect::>() - ); - eprintln!("successors = {:?}", basic_coverage_blocks.successors); - } - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), - 0, - "backedges: {:?}", - backedges - ); -} - -#[test] -fn test_find_loop_backedges_one() { - let mir_body = switchint_then_loop_else_return(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), - 1, - "backedges: {:?}", - backedges - ); - - let_bcb!(1); - let_bcb!(3); - - assert_eq!(backedges[bcb1], vec![bcb3]); -} - -#[test] -fn test_find_loop_backedges_two() { - let mir_body = switchint_loop_then_inner_loop_else_break(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), - 2, - "backedges: {:?}", - backedges - ); - - let_bcb!(1); - let_bcb!(4); - let_bcb!(5); - let_bcb!(6); - - assert_eq!(backedges[bcb1], vec![bcb5]); - assert_eq!(backedges[bcb4], vec![bcb6]); -} - -#[test] -fn test_traverse_coverage_with_loops() { - let mir_body = switchint_loop_then_inner_loop_else_break(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let mut traversed_in_order = Vec::new(); - let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks); - while let Some(bcb) = traversal.next(&basic_coverage_blocks) { - traversed_in_order.push(bcb); - } - - let_bcb!(6); - - // bcb0 is visited first. Then bcb1 starts the first loop, and all remaining nodes, *except* - // bcb6 are inside the first loop. - assert_eq!( - *traversed_in_order.last().expect("should have elements"), - bcb6, - "bcb6 should not be visited until all nodes inside the first loop have been visited" - ); -} - -fn synthesize_body_span_from_terminators(mir_body: &Body<'_>) -> Span { - let mut some_span: Option = None; - for (_, data) in mir_body.basic_blocks().iter_enumerated() { - let term_span = data.terminator().source_info.span; - if let Some(span) = some_span.as_mut() { - *span = span.to(term_span); - } else { - some_span = Some(term_span) - } - } - some_span.expect("body must have at least one BasicBlock") -} - -#[test] -fn test_make_bcb_counters() { - rustc_span::create_default_session_globals_then(|| { - let mir_body = goto_switchint(); - let body_span = synthesize_body_span_from_terminators(&mir_body); - let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let mut coverage_spans = Vec::new(); - for (bcb, data) in basic_coverage_blocks.iter_enumerated() { - if let Some(span) = spans::filtered_terminator_span(data.terminator(&mir_body)) { - coverage_spans.push(spans::CoverageSpan::for_terminator( - spans::function_source_span(span, body_span), - span, - bcb, - data.last_bb(), - )); - } - } - let mut coverage_counters = counters::CoverageCounters::new(0); - let intermediate_expressions = coverage_counters - .make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans) - .expect("should be Ok"); - assert_eq!(intermediate_expressions.len(), 0); - - let_bcb!(1); - assert_eq!( - 1, // coincidentally, bcb1 has a `Counter` with id = 1 - match basic_coverage_blocks[bcb1].counter().expect("should have a counter") { - CoverageKind::Counter { id, .. } => id, - _ => panic!("expected a Counter"), - } - .as_u32() - ); - - let_bcb!(2); - assert_eq!( - 2, // coincidentally, bcb2 has a `Counter` with id = 2 - match basic_coverage_blocks[bcb2].counter().expect("should have a counter") { - CoverageKind::Counter { id, .. } => id, - _ => panic!("expected a Counter"), - } - .as_u32() - ); - }); -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/deaggregator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/deaggregator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/deaggregator.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/deaggregator.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -use crate::transform::MirPass; -use crate::util::expand_aggregate; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -pub struct Deaggregator; - -impl<'tcx> MirPass<'tcx> for Deaggregator { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - let local_decls = &*local_decls; - for bb in basic_blocks { - bb.expand_statements(|stmt| { - // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL). - match stmt.kind { - // FIXME(#48193) Deaggregate arrays when it's cheaper to do so. - StatementKind::Assign(box ( - _, - Rvalue::Aggregate(box AggregateKind::Array(_), _), - )) => { - return None; - } - StatementKind::Assign(box (_, Rvalue::Aggregate(_, _))) => {} - _ => return None, - } - - let stmt = stmt.replace_nop(); - let source_info = stmt.source_info; - let (lhs, kind, operands) = match stmt.kind { - StatementKind::Assign(box (lhs, Rvalue::Aggregate(kind, operands))) => { - (lhs, kind, operands) - } - _ => bug!(), - }; - - Some(expand_aggregate( - lhs, - operands.into_iter().map(|op| { - let ty = op.ty(local_decls, tcx); - (op, ty) - }), - *kind, - source_info, - tcx, - )) - }); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/deduplicate_blocks.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/deduplicate_blocks.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/deduplicate_blocks.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/deduplicate_blocks.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,189 +0,0 @@ -//! This pass finds basic blocks that are completely equal, -//! and replaces all uses with just one of them. - -use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher, iter}; - -use crate::transform::MirPass; - -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -use super::simplify::simplify_cfg; - -pub struct DeduplicateBlocks; - -impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } - debug!("Running DeduplicateBlocks on `{:?}`", body.source); - let duplicates = find_duplicates(body); - let has_opts_to_apply = !duplicates.is_empty(); - - if has_opts_to_apply { - let mut opt_applier = OptApplier { tcx, duplicates }; - opt_applier.visit_body(body); - simplify_cfg(tcx, body); - } - } -} - -struct OptApplier<'tcx> { - tcx: TyCtxt<'tcx>, - duplicates: FxHashMap, -} - -impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - for target in terminator.successors_mut() { - if let Some(replacement) = self.duplicates.get(target) { - debug!("SUCCESS: Replacing: `{:?}` with `{:?}`", target, replacement); - *target = *replacement; - } - } - - self.super_terminator(terminator, location); - } -} - -fn find_duplicates<'a, 'tcx>(body: &'a Body<'tcx>) -> FxHashMap { - let mut duplicates = FxHashMap::default(); - - let bbs_to_go_through = - body.basic_blocks().iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count(); - - let mut same_hashes = - FxHashMap::with_capacity_and_hasher(bbs_to_go_through, Default::default()); - - // Go through the basic blocks backwards. This means that in case of duplicates, - // we can use the basic block with the highest index as the replacement for all lower ones. - // For example, if bb1, bb2 and bb3 are duplicates, we will first insert bb3 in same_hashes. - // Then we will see that bb2 is a duplicate of bb3, - // and insert bb2 with the replacement bb3 in the duplicates list. - // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the duplicates list - // with replacement bb3. - // When the duplicates are removed, we will end up with only bb3. - for (bb, bbd) in body.basic_blocks().iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup) - { - // Basic blocks can get really big, so to avoid checking for duplicates in basic blocks - // that are unlikely to have duplicates, we stop early. The early bail number has been - // found experimentally by eprintln while compiling the crates in the rustc-perf suite. - if bbd.statements.len() > 10 { - continue; - } - - let to_hash = BasicBlockHashable { basic_block_data: bbd }; - let entry = same_hashes.entry(to_hash); - match entry { - Entry::Occupied(occupied) => { - // The basic block was already in the hashmap, which means we have a duplicate - let value = *occupied.get(); - debug!("Inserting {:?} -> {:?}", bb, value); - duplicates.try_insert(bb, value).expect("key was already inserted"); - } - Entry::Vacant(vacant) => { - vacant.insert(bb); - } - } - } - - duplicates -} - -struct BasicBlockHashable<'tcx, 'a> { - basic_block_data: &'a BasicBlockData<'tcx>, -} - -impl<'tcx, 'a> Hash for BasicBlockHashable<'tcx, 'a> { - fn hash(&self, state: &mut H) { - hash_statements(state, self.basic_block_data.statements.iter()); - // Note that since we only hash the kind, we lose span information if we deduplicate the blocks - self.basic_block_data.terminator().kind.hash(state); - } -} - -impl<'tcx, 'a> Eq for BasicBlockHashable<'tcx, 'a> {} - -impl<'tcx, 'a> PartialEq for BasicBlockHashable<'tcx, 'a> { - fn eq(&self, other: &Self) -> bool { - self.basic_block_data.statements.len() == other.basic_block_data.statements.len() - && &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind - && iter::zip(&self.basic_block_data.statements, &other.basic_block_data.statements) - .all(|(x, y)| statement_eq(&x.kind, &y.kind)) - } -} - -fn hash_statements<'a, 'tcx, H: Hasher>( - hasher: &mut H, - iter: impl Iterator>, -) where - 'tcx: 'a, -{ - for stmt in iter { - statement_hash(hasher, &stmt.kind); - } -} - -fn statement_hash<'tcx, H: Hasher>(hasher: &mut H, stmt: &StatementKind<'tcx>) { - match stmt { - StatementKind::Assign(box (place, rvalue)) => { - place.hash(hasher); - rvalue_hash(hasher, rvalue) - } - x => x.hash(hasher), - }; -} - -fn rvalue_hash(hasher: &mut H, rvalue: &Rvalue<'tcx>) { - match rvalue { - Rvalue::Use(op) => operand_hash(hasher, op), - x => x.hash(hasher), - }; -} - -fn operand_hash(hasher: &mut H, operand: &Operand<'tcx>) { - match operand { - Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher), - x => x.hash(hasher), - }; -} - -fn statement_eq<'tcx>(lhs: &StatementKind<'tcx>, rhs: &StatementKind<'tcx>) -> bool { - let res = match (lhs, rhs) { - ( - StatementKind::Assign(box (place, rvalue)), - StatementKind::Assign(box (place2, rvalue2)), - ) => place == place2 && rvalue_eq(rvalue, rvalue2), - (x, y) => x == y, - }; - debug!("statement_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); - res -} - -fn rvalue_eq(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool { - let res = match (lhs, rhs) { - (Rvalue::Use(op1), Rvalue::Use(op2)) => operand_eq(op1, op2), - (x, y) => x == y, - }; - debug!("rvalue_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); - res -} - -fn operand_eq(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool { - let res = match (lhs, rhs) { - ( - Operand::Constant(box Constant { user_ty: _, literal, span: _ }), - Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }), - ) => literal == literal2, - (x, y) => x == y, - }; - debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); - res -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/dest_prop.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/dest_prop.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/dest_prop.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/dest_prop.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1039 +0,0 @@ -//! Propagates assignment destinations backwards in the CFG to eliminate redundant assignments. -//! -//! # Motivation -//! -//! MIR building can insert a lot of redundant copies, and Rust code in general often tends to move -//! values around a lot. The result is a lot of assignments of the form `dest = {move} src;` in MIR. -//! MIR building for constants in particular tends to create additional locals that are only used -//! inside a single block to shuffle a value around unnecessarily. -//! -//! LLVM by itself is not good enough at eliminating these redundant copies (eg. see -//! ), so this leaves some performance on the table -//! that we can regain by implementing an optimization for removing these assign statements in rustc -//! itself. When this optimization runs fast enough, it can also speed up the constant evaluation -//! and code generation phases of rustc due to the reduced number of statements and locals. -//! -//! # The Optimization -//! -//! Conceptually, this optimization is "destination propagation". It is similar to the Named Return -//! Value Optimization, or NRVO, known from the C++ world, except that it isn't limited to return -//! values or the return place `_0`. On a very high level, independent of the actual implementation -//! details, it does the following: -//! -//! 1) Identify `dest = src;` statements that can be soundly eliminated. -//! 2) Replace all mentions of `src` with `dest` ("unifying" them and propagating the destination -//! backwards). -//! 3) Delete the `dest = src;` statement (by making it a `nop`). -//! -//! Step 1) is by far the hardest, so it is explained in more detail below. -//! -//! ## Soundness -//! -//! Given an `Assign` statement `dest = src;`, where `dest` is a `Place` and `src` is an `Rvalue`, -//! there are a few requirements that must hold for the optimization to be sound: -//! -//! * `dest` must not contain any *indirection* through a pointer. It must access part of the base -//! local. Otherwise it might point to arbitrary memory that is hard to track. -//! -//! It must also not contain any indexing projections, since those take an arbitrary `Local` as -//! the index, and that local might only be initialized shortly before `dest` is used. -//! -//! Subtle case: If `dest` is a, or projects through a union, then we have to make sure that there -//! remains an assignment to it, since that sets the "active field" of the union. But if `src` is -//! a ZST, it might not be initialized, so there might not be any use of it before the assignment, -//! and performing the optimization would simply delete the assignment, leaving `dest` -//! uninitialized. -//! -//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Is this a -//! fundamental restriction or just current impl state?). It can be copied or moved by the -//! assignment. -//! -//! * The `dest` and `src` locals must never be [*live*][liveness] at the same time. If they are, it -//! means that they both hold a (potentially different) value that is needed by a future use of -//! the locals. Unifying them would overwrite one of the values. -//! -//! Note that computing liveness of locals that have had their address taken is more difficult: -//! Short of doing full escape analysis on the address/pointer/reference, the pass would need to -//! assume that any operation that can potentially involve opaque user code (such as function -//! calls, destructors, and inline assembly) may access any local that had its address taken -//! before that point. -//! -//! Here, the first two conditions are simple structural requirements on the `Assign` statements -//! that can be trivially checked. The liveness requirement however is more difficult and costly to -//! check. -//! -//! ## Previous Work -//! -//! A [previous attempt] at implementing an optimization like this turned out to be a significant -//! regression in compiler performance. Fixing the regressions introduced a lot of undesirable -//! complexity to the implementation. -//! -//! A [subsequent approach] tried to avoid the costly computation by limiting itself to acyclic -//! CFGs, but still turned out to be far too costly to run due to suboptimal performance within -//! individual basic blocks, requiring a walk across the entire block for every assignment found -//! within the block. For the `tuple-stress` benchmark, which has 458745 statements in a single -//! block, this proved to be far too costly. -//! -//! Since the first attempt at this, the compiler has improved dramatically, and new analysis -//! frameworks have been added that should make this approach viable without requiring a limited -//! approach that only works for some classes of CFGs: -//! - rustc now has a powerful dataflow analysis framework that can handle forwards and backwards -//! analyses efficiently. -//! - Layout optimizations for generators have been added to improve code generation for -//! async/await, which are very similar in spirit to what this optimization does. Both walk the -//! MIR and record conflicting uses of locals in a `BitMatrix`. -//! -//! Also, rustc now has a simple NRVO pass (see `nrvo.rs`), which handles a subset of the cases that -//! this destination propagation pass handles, proving that similar optimizations can be performed -//! on MIR. -//! -//! ## Pre/Post Optimization -//! -//! It is recommended to run `SimplifyCfg` and then `SimplifyLocals` some time after this pass, as -//! it replaces the eliminated assign statements with `nop`s and leaves unused locals behind. -//! -//! [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis -//! [previous attempt]: https://github.com/rust-lang/rust/pull/47954 -//! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003 - -use crate::dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals}; -use crate::dataflow::Analysis; -use crate::{ - transform::MirPass, - util::{dump_mir, PassWhere}, -}; -use itertools::Itertools; -use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey}; -use rustc_index::{ - bit_set::{BitMatrix, BitSet}, - vec::IndexVec, -}; -use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; -use rustc_middle::mir::{ - traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem, - Rvalue, Statement, StatementKind, Terminator, TerminatorKind, -}; -use rustc_middle::ty::TyCtxt; - -// Empirical measurements have resulted in some observations: -// - Running on a body with a single block and 500 locals takes barely any time -// - Running on a body with ~400 blocks and ~300 relevant locals takes "too long" -// ...so we just limit both to somewhat reasonable-ish looking values. -const MAX_LOCALS: usize = 500; -const MAX_BLOCKS: usize = 250; - -pub struct DestinationPropagation; - -impl<'tcx> MirPass<'tcx> for DestinationPropagation { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // FIXME(#79191, #82678) - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { - return; - } - - // Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove - // storage statements at the moment). - if tcx.sess.mir_opt_level() < 3 { - return; - } - - let def_id = body.source.def_id(); - - let candidates = find_candidates(tcx, body); - if candidates.is_empty() { - debug!("{:?}: no dest prop candidates, done", def_id); - return; - } - - // Collect all locals we care about. We only compute conflicts for these to save time. - let mut relevant_locals = BitSet::new_empty(body.local_decls.len()); - for CandidateAssignment { dest, src, loc: _ } in &candidates { - relevant_locals.insert(dest.local); - relevant_locals.insert(*src); - } - - // This pass unfortunately has `O(l² * s)` performance, where `l` is the number of locals - // and `s` is the number of statements and terminators in the function. - // To prevent blowing up compile times too much, we bail out when there are too many locals. - let relevant = relevant_locals.count(); - debug!( - "{:?}: {} locals ({} relevant), {} blocks", - def_id, - body.local_decls.len(), - relevant, - body.basic_blocks().len() - ); - if relevant > MAX_LOCALS { - warn!( - "too many candidate locals in {:?} ({}, max is {}), not optimizing", - def_id, relevant, MAX_LOCALS - ); - return; - } - if body.basic_blocks().len() > MAX_BLOCKS { - warn!( - "too many blocks in {:?} ({}, max is {}), not optimizing", - def_id, - body.basic_blocks().len(), - MAX_BLOCKS - ); - return; - } - - let mut conflicts = Conflicts::build(tcx, body, &relevant_locals); - - let mut replacements = Replacements::new(body.local_decls.len()); - for candidate @ CandidateAssignment { dest, src, loc } in candidates { - // Merge locals that don't conflict. - if !conflicts.can_unify(dest.local, src) { - debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src); - continue; - } - - if replacements.for_src(candidate.src).is_some() { - debug!("src {:?} already has replacement", candidate.src); - continue; - } - - if !tcx.consider_optimizing(|| { - format!("DestinationPropagation {:?} {:?}", def_id, candidate) - }) { - break; - } - - replacements.push(candidate); - conflicts.unify(candidate.src, candidate.dest.local); - } - - replacements.flatten(tcx); - - debug!("replacements {:?}", replacements.map); - - Replacer { tcx, replacements, place_elem_cache: Vec::new() }.visit_body(body); - - // FIXME fix debug info - } -} - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -struct UnifyLocal(Local); - -impl From for UnifyLocal { - fn from(l: Local) -> Self { - Self(l) - } -} - -impl UnifyKey for UnifyLocal { - type Value = (); - fn index(&self) -> u32 { - self.0.as_u32() - } - fn from_index(u: u32) -> Self { - Self(Local::from_u32(u)) - } - fn tag() -> &'static str { - "UnifyLocal" - } -} - -struct Replacements<'tcx> { - /// Maps locals to their replacement. - map: IndexVec>>, - - /// Whose locals' live ranges to kill. - kill: BitSet, -} - -impl Replacements<'tcx> { - fn new(locals: usize) -> Self { - Self { map: IndexVec::from_elem_n(None, locals), kill: BitSet::new_empty(locals) } - } - - fn push(&mut self, candidate: CandidateAssignment<'tcx>) { - trace!("Replacements::push({:?})", candidate); - let entry = &mut self.map[candidate.src]; - assert!(entry.is_none()); - - *entry = Some(candidate.dest); - self.kill.insert(candidate.src); - self.kill.insert(candidate.dest.local); - } - - /// Applies the stored replacements to all replacements, until no replacements would result in - /// locals that need further replacements when applied. - fn flatten(&mut self, tcx: TyCtxt<'tcx>) { - // Note: This assumes that there are no cycles in the replacements, which is enforced via - // `self.unified_locals`. Otherwise this can cause an infinite loop. - - for local in self.map.indices() { - if let Some(replacement) = self.map[local] { - // Substitute the base local of `replacement` until fixpoint. - let mut base = replacement.local; - let mut reversed_projection_slices = Vec::with_capacity(1); - while let Some(replacement_for_replacement) = self.map[base] { - base = replacement_for_replacement.local; - reversed_projection_slices.push(replacement_for_replacement.projection); - } - - let projection: Vec<_> = reversed_projection_slices - .iter() - .rev() - .flat_map(|projs| projs.iter()) - .chain(replacement.projection.iter()) - .collect(); - let projection = tcx.intern_place_elems(&projection); - - // Replace with the final `Place`. - self.map[local] = Some(Place { local: base, projection }); - } - } - } - - fn for_src(&self, src: Local) -> Option> { - self.map[src] - } -} - -struct Replacer<'tcx> { - tcx: TyCtxt<'tcx>, - replacements: Replacements<'tcx>, - place_elem_cache: Vec>, -} - -impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, context: PlaceContext, location: Location) { - if context.is_use() && self.replacements.for_src(*local).is_some() { - bug!( - "use of local {:?} should have been replaced by visit_place; context={:?}, loc={:?}", - local, - context, - location, - ); - } - } - - fn process_projection_elem( - &mut self, - elem: PlaceElem<'tcx>, - _: Location, - ) -> Option> { - match elem { - PlaceElem::Index(local) => { - if let Some(replacement) = self.replacements.for_src(local) { - bug!( - "cannot replace {:?} with {:?} in index projection {:?}", - local, - replacement, - elem, - ); - } else { - None - } - } - _ => None, - } - } - - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if let Some(replacement) = self.replacements.for_src(place.local) { - // Rebase `place`s projections onto `replacement`'s. - self.place_elem_cache.clear(); - self.place_elem_cache.extend(replacement.projection.iter().chain(place.projection)); - let projection = self.tcx.intern_place_elems(&self.place_elem_cache); - let new_place = Place { local: replacement.local, projection }; - - debug!("Replacer: {:?} -> {:?}", place, new_place); - *place = new_place; - } - - self.super_place(place, context, location); - } - - fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { - self.super_statement(statement, location); - - match &statement.kind { - // FIXME: Don't delete storage statements, merge the live ranges instead - StatementKind::StorageDead(local) | StatementKind::StorageLive(local) - if self.replacements.kill.contains(*local) => - { - statement.make_nop() - } - - StatementKind::Assign(box (dest, rvalue)) => { - match rvalue { - Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { - // These might've been turned into self-assignments by the replacement - // (this includes the original statement we wanted to eliminate). - if dest == place { - debug!("{:?} turned into self-assignment, deleting", location); - statement.make_nop(); - } - } - _ => {} - } - } - - _ => {} - } - } -} - -struct Conflicts<'a> { - relevant_locals: &'a BitSet, - - /// The conflict matrix. It is always symmetric and the adjacency matrix of the corresponding - /// conflict graph. - matrix: BitMatrix, - - /// Preallocated `BitSet` used by `unify`. - unify_cache: BitSet, - - /// Tracks locals that have been merged together to prevent cycles and propagate conflicts. - unified_locals: InPlaceUnificationTable, -} - -impl Conflicts<'a> { - fn build<'tcx>( - tcx: TyCtxt<'tcx>, - body: &'_ Body<'tcx>, - relevant_locals: &'a BitSet, - ) -> Self { - // We don't have to look out for locals that have their address taken, since - // `find_candidates` already takes care of that. - - let conflicts = BitMatrix::from_row_n( - &BitSet::new_empty(body.local_decls.len()), - body.local_decls.len(), - ); - - let mut init = MaybeInitializedLocals - .into_engine(tcx, body) - .iterate_to_fixpoint() - .into_results_cursor(body); - let mut live = - MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint().into_results_cursor(body); - - let mut reachable = None; - dump_mir(tcx, None, "DestinationPropagation-dataflow", &"", body, |pass_where, w| { - let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body)); - - match pass_where { - PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => { - init.seek_before_primary_effect(loc); - live.seek_after_primary_effect(loc); - - writeln!(w, " // init: {:?}", init.get())?; - writeln!(w, " // live: {:?}", live.get())?; - } - PassWhere::AfterTerminator(bb) if reachable.contains(bb) => { - let loc = body.terminator_loc(bb); - init.seek_after_primary_effect(loc); - live.seek_before_primary_effect(loc); - - writeln!(w, " // init: {:?}", init.get())?; - writeln!(w, " // live: {:?}", live.get())?; - } - - PassWhere::BeforeBlock(bb) if reachable.contains(bb) => { - init.seek_to_block_start(bb); - live.seek_to_block_start(bb); - - writeln!(w, " // init: {:?}", init.get())?; - writeln!(w, " // live: {:?}", live.get())?; - } - - PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {} - - PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => { - writeln!(w, " // init: ")?; - writeln!(w, " // live: ")?; - } - - PassWhere::BeforeBlock(_) => { - writeln!(w, " // init: ")?; - writeln!(w, " // live: ")?; - } - } - - Ok(()) - }); - - let mut this = Self { - relevant_locals, - matrix: conflicts, - unify_cache: BitSet::new_empty(body.local_decls.len()), - unified_locals: { - let mut table = InPlaceUnificationTable::new(); - // Pre-fill table with all locals (this creates N nodes / "connected" components, - // "graph"-ically speaking). - for local in 0..body.local_decls.len() { - assert_eq!(table.new_key(()), UnifyLocal(Local::from_usize(local))); - } - table - }, - }; - - let mut live_and_init_locals = Vec::new(); - - // Visit only reachable basic blocks. The exact order is not important. - for (block, data) in traversal::preorder(body) { - // We need to observe the dataflow state *before* all possible locations (statement or - // terminator) in each basic block, and then observe the state *after* the terminator - // effect is applied. As long as neither `init` nor `borrowed` has a "before" effect, - // we will observe all possible dataflow states. - - // Since liveness is a backwards analysis, we need to walk the results backwards. To do - // that, we first collect in the `MaybeInitializedLocals` results in a forwards - // traversal. - - live_and_init_locals.resize_with(data.statements.len() + 1, || { - BitSet::new_empty(body.local_decls.len()) - }); - - // First, go forwards for `MaybeInitializedLocals` and apply intra-statement/terminator - // conflicts. - for (i, statement) in data.statements.iter().enumerate() { - this.record_statement_conflicts(statement); - - let loc = Location { block, statement_index: i }; - init.seek_before_primary_effect(loc); - - live_and_init_locals[i].clone_from(init.get()); - } - - this.record_terminator_conflicts(data.terminator()); - let term_loc = Location { block, statement_index: data.statements.len() }; - init.seek_before_primary_effect(term_loc); - live_and_init_locals[term_loc.statement_index].clone_from(init.get()); - - // Now, go backwards and union with the liveness results. - for statement_index in (0..=data.statements.len()).rev() { - let loc = Location { block, statement_index }; - live.seek_after_primary_effect(loc); - - live_and_init_locals[statement_index].intersect(live.get()); - - trace!("record conflicts at {:?}", loc); - - this.record_dataflow_conflicts(&mut live_and_init_locals[statement_index]); - } - - init.seek_to_block_end(block); - live.seek_to_block_end(block); - let mut conflicts = init.get().clone(); - conflicts.intersect(live.get()); - trace!("record conflicts at end of {:?}", block); - - this.record_dataflow_conflicts(&mut conflicts); - } - - this - } - - fn record_dataflow_conflicts(&mut self, new_conflicts: &mut BitSet) { - // Remove all locals that are not candidates. - new_conflicts.intersect(self.relevant_locals); - - for local in new_conflicts.iter() { - self.matrix.union_row_with(&new_conflicts, local); - } - } - - fn record_local_conflict(&mut self, a: Local, b: Local, why: &str) { - trace!("conflict {:?} <-> {:?} due to {}", a, b, why); - self.matrix.insert(a, b); - self.matrix.insert(b, a); - } - - /// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict - /// and must not be merged. - fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) { - match &stmt.kind { - // While the left and right sides of an assignment must not overlap, we do not mark - // conflicts here as that would make this optimization useless. When we optimize, we - // eliminate the resulting self-assignments automatically. - StatementKind::Assign(_) => {} - - StatementKind::LlvmInlineAsm(asm) => { - // Inputs and outputs must not overlap. - for (_, input) in &*asm.inputs { - if let Some(in_place) = input.place() { - if !in_place.is_indirect() { - for out_place in &*asm.outputs { - if !out_place.is_indirect() && !in_place.is_indirect() { - self.record_local_conflict( - in_place.local, - out_place.local, - "aliasing llvm_asm! operands", - ); - } - } - } - } - } - } - - StatementKind::SetDiscriminant { .. } - | StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::Retag(..) - | StatementKind::FakeRead(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Nop => {} - } - } - - fn record_terminator_conflicts(&mut self, term: &Terminator<'_>) { - match &term.kind { - TerminatorKind::DropAndReplace { - place: dropped_place, - value, - target: _, - unwind: _, - } => { - if let Some(place) = value.place() { - if !place.is_indirect() && !dropped_place.is_indirect() { - self.record_local_conflict( - place.local, - dropped_place.local, - "DropAndReplace operand overlap", - ); - } - } - } - TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { - if let Some(place) = value.place() { - if !place.is_indirect() && !resume_arg.is_indirect() { - self.record_local_conflict( - place.local, - resume_arg.local, - "Yield operand overlap", - ); - } - } - } - TerminatorKind::Call { - func, - args, - destination: Some((dest_place, _)), - cleanup: _, - from_hir_call: _, - fn_span: _, - } => { - // No arguments may overlap with the destination. - for arg in args.iter().chain(Some(func)) { - if let Some(place) = arg.place() { - if !place.is_indirect() && !dest_place.is_indirect() { - self.record_local_conflict( - dest_place.local, - place.local, - "call dest/arg overlap", - ); - } - } - } - } - TerminatorKind::InlineAsm { - template: _, - operands, - options: _, - line_spans: _, - destination: _, - } => { - // The intended semantics here aren't documented, we just assume that nothing that - // could be written to by the assembly may overlap with any other operands. - for op in operands { - match op { - InlineAsmOperand::Out { reg: _, late: _, place: Some(dest_place) } - | InlineAsmOperand::InOut { - reg: _, - late: _, - in_value: _, - out_place: Some(dest_place), - } => { - // For output place `place`, add all places accessed by the inline asm. - for op in operands { - match op { - InlineAsmOperand::In { reg: _, value } => { - if let Some(p) = value.place() { - if !p.is_indirect() && !dest_place.is_indirect() { - self.record_local_conflict( - p.local, - dest_place.local, - "asm! operand overlap", - ); - } - } - } - InlineAsmOperand::Out { - reg: _, - late: _, - place: Some(place), - } => { - if !place.is_indirect() && !dest_place.is_indirect() { - self.record_local_conflict( - place.local, - dest_place.local, - "asm! operand overlap", - ); - } - } - InlineAsmOperand::InOut { - reg: _, - late: _, - in_value, - out_place, - } => { - if let Some(place) = in_value.place() { - if !place.is_indirect() && !dest_place.is_indirect() { - self.record_local_conflict( - place.local, - dest_place.local, - "asm! operand overlap", - ); - } - } - - if let Some(place) = out_place { - if !place.is_indirect() && !dest_place.is_indirect() { - self.record_local_conflict( - place.local, - dest_place.local, - "asm! operand overlap", - ); - } - } - } - InlineAsmOperand::Out { reg: _, late: _, place: None } - | InlineAsmOperand::Const { value: _ } - | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } => {} - } - } - } - InlineAsmOperand::InOut { - reg: _, - late: _, - in_value: _, - out_place: None, - } - | InlineAsmOperand::In { reg: _, value: _ } - | InlineAsmOperand::Out { reg: _, late: _, place: None } - | InlineAsmOperand::Const { value: _ } - | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } => {} - } - } - } - - TerminatorKind::Goto { .. } - | TerminatorKind::Call { destination: None, .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::Drop { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => {} - } - } - - /// Checks whether `a` and `b` may be merged. Returns `false` if there's a conflict. - fn can_unify(&mut self, a: Local, b: Local) -> bool { - // After some locals have been unified, their conflicts are only tracked in the root key, - // so look that up. - let a = self.unified_locals.find(a).0; - let b = self.unified_locals.find(b).0; - - if a == b { - // Already merged (part of the same connected component). - return false; - } - - if self.matrix.contains(a, b) { - // Conflict (derived via dataflow, intra-statement conflicts, or inherited from another - // local during unification). - return false; - } - - true - } - - /// Merges the conflicts of `a` and `b`, so that each one inherits all conflicts of the other. - /// - /// `can_unify` must have returned `true` for the same locals, or this may panic or lead to - /// miscompiles. - /// - /// This is called when the pass makes the decision to unify `a` and `b` (or parts of `a` and - /// `b`) and is needed to ensure that future unification decisions take potentially newly - /// introduced conflicts into account. - /// - /// For an example, assume we have locals `_0`, `_1`, `_2`, and `_3`. There are these conflicts: - /// - /// * `_0` <-> `_1` - /// * `_1` <-> `_2` - /// * `_3` <-> `_0` - /// - /// We then decide to merge `_2` with `_3` since they don't conflict. Then we decide to merge - /// `_2` with `_0`, which also doesn't have a conflict in the above list. However `_2` is now - /// `_3`, which does conflict with `_0`. - fn unify(&mut self, a: Local, b: Local) { - trace!("unify({:?}, {:?})", a, b); - - // Get the root local of the connected components. The root local stores the conflicts of - // all locals in the connected component (and *is stored* as the conflicting local of other - // locals). - let a = self.unified_locals.find(a).0; - let b = self.unified_locals.find(b).0; - assert_ne!(a, b); - - trace!("roots: a={:?}, b={:?}", a, b); - trace!("{:?} conflicts: {:?}", a, self.matrix.iter(a).format(", ")); - trace!("{:?} conflicts: {:?}", b, self.matrix.iter(b).format(", ")); - - self.unified_locals.union(a, b); - - let root = self.unified_locals.find(a).0; - assert!(root == a || root == b); - - // Make all locals that conflict with `a` also conflict with `b`, and vice versa. - self.unify_cache.clear(); - for conflicts_with_a in self.matrix.iter(a) { - self.unify_cache.insert(conflicts_with_a); - } - for conflicts_with_b in self.matrix.iter(b) { - self.unify_cache.insert(conflicts_with_b); - } - for conflicts_with_a_or_b in self.unify_cache.iter() { - // Set both `a` and `b` for this local's row. - self.matrix.insert(conflicts_with_a_or_b, a); - self.matrix.insert(conflicts_with_a_or_b, b); - } - - // Write the locals `a` conflicts with to `b`'s row. - self.matrix.union_rows(a, b); - // Write the locals `b` conflicts with to `a`'s row. - self.matrix.union_rows(b, a); - } -} - -/// A `dest = {move} src;` statement at `loc`. -/// -/// We want to consider merging `dest` and `src` due to this assignment. -#[derive(Debug, Copy, Clone)] -struct CandidateAssignment<'tcx> { - /// Does not contain indirection or indexing (so the only local it contains is the place base). - dest: Place<'tcx>, - src: Local, - loc: Location, -} - -/// Scans the MIR for assignments between locals that we might want to consider merging. -/// -/// This will filter out assignments that do not match the right form (as described in the top-level -/// comment) and also throw out assignments that involve a local that has its address taken or is -/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate -/// arbitrary places into array indices). -fn find_candidates<'a, 'tcx>( - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, -) -> Vec> { - let mut visitor = FindAssignments { - tcx, - body, - candidates: Vec::new(), - ever_borrowed_locals: ever_borrowed_locals(body), - locals_used_as_array_index: locals_used_as_array_index(body), - }; - visitor.visit_body(body); - visitor.candidates -} - -struct FindAssignments<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - candidates: Vec>, - ever_borrowed_locals: BitSet, - locals_used_as_array_index: BitSet, -} - -impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - if let StatementKind::Assign(box ( - dest, - Rvalue::Use(Operand::Copy(src) | Operand::Move(src)), - )) = &statement.kind - { - // `dest` must not have pointer indirection. - if dest.is_indirect() { - return; - } - - // `src` must be a plain local. - if !src.projection.is_empty() { - return; - } - - // Since we want to replace `src` with `dest`, `src` must not be required. - if is_local_required(src.local, self.body) { - return; - } - - // Can't optimize if both locals ever have their address taken (can introduce - // aliasing). - // FIXME: This can be smarter and take `StorageDead` into account (which - // invalidates borrows). - if self.ever_borrowed_locals.contains(dest.local) - || self.ever_borrowed_locals.contains(src.local) - { - return; - } - - assert_ne!(dest.local, src.local, "self-assignments are UB"); - - // We can't replace locals occurring in `PlaceElem::Index` for now. - if self.locals_used_as_array_index.contains(src.local) { - return; - } - - // Handle the "subtle case" described above by rejecting any `dest` that is or - // projects through a union. - let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); - if place_ty.ty.is_union() { - return; - } - for elem in dest.projection { - if let PlaceElem::Index(_) = elem { - // `dest` contains an indexing projection. - return; - } - - place_ty = place_ty.projection_ty(self.tcx, elem); - if place_ty.ty.is_union() { - return; - } - } - - self.candidates.push(CandidateAssignment { - dest: *dest, - src: src.local, - loc: location, - }); - } - } -} - -/// Some locals are part of the function's interface and can not be removed. -/// -/// Note that these locals *can* still be merged with non-required locals by removing that other -/// local. -fn is_local_required(local: Local, body: &Body<'_>) -> bool { - match body.local_kind(local) { - LocalKind::Arg | LocalKind::ReturnPointer => true, - LocalKind::Var | LocalKind::Temp => false, - } -} - -/// Walks MIR to find all locals that have their address taken anywhere. -fn ever_borrowed_locals(body: &Body<'_>) -> BitSet { - let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) }; - visitor.visit_body(body); - visitor.locals -} - -struct BorrowCollector { - locals: BitSet, -} - -impl<'tcx> Visitor<'tcx> for BorrowCollector { - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - - match rvalue { - Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { - if !borrowed_place.is_indirect() { - self.locals.insert(borrowed_place.local); - } - } - - Rvalue::Cast(..) - | Rvalue::Use(..) - | Rvalue::Repeat(..) - | Rvalue::Len(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::NullaryOp(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) - | Rvalue::Aggregate(..) - | Rvalue::ThreadLocalRef(..) => {} - } - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); - - match terminator.kind { - TerminatorKind::Drop { place: dropped_place, .. } - | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { - self.locals.insert(dropped_place.local); - } - - TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } - | TerminatorKind::InlineAsm { .. } => {} - } - } -} - -/// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`. -/// -/// Collect locals used as indices so we don't generate candidates that are impossible to apply -/// later. -fn locals_used_as_array_index(body: &Body<'_>) -> BitSet { - let mut visitor = IndexCollector { locals: BitSet::new_empty(body.local_decls.len()) }; - visitor.visit_body(body); - visitor.locals -} - -struct IndexCollector { - locals: BitSet, -} - -impl<'tcx> Visitor<'tcx> for IndexCollector { - fn visit_projection_elem( - &mut self, - local: Local, - proj_base: &[PlaceElem<'tcx>], - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - if let PlaceElem::Index(i) = elem { - self.locals.insert(i); - } - self.super_projection_elem(local, proj_base, elem, context, location); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/dump_mir.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/dump_mir.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/dump_mir.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/dump_mir.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -//! This pass just dumps MIR at a specified point. - -use std::borrow::Cow; -use std::fmt; -use std::fs::File; -use std::io; - -use crate::transform::MirPass; -use crate::util as mir_util; -use rustc_middle::mir::Body; -use rustc_middle::ty::TyCtxt; -use rustc_session::config::{OutputFilenames, OutputType}; - -pub struct Marker(pub &'static str); - -impl<'tcx> MirPass<'tcx> for Marker { - fn name(&self) -> Cow<'_, str> { - Cow::Borrowed(self.0) - } - - fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {} -} - -pub struct Disambiguator { - is_after: bool, -} - -impl fmt::Display for Disambiguator { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - let title = if self.is_after { "after" } else { "before" }; - write!(formatter, "{}", title) - } -} - -pub fn on_mir_pass<'tcx>( - tcx: TyCtxt<'tcx>, - pass_num: &dyn fmt::Display, - pass_name: &str, - body: &Body<'tcx>, - is_after: bool, -) { - if mir_util::dump_enabled(tcx, pass_name, body.source.def_id()) { - mir_util::dump_mir( - tcx, - Some(pass_num), - pass_name, - &Disambiguator { is_after }, - body, - |_, _| Ok(()), - ); - } -} - -pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> { - let path = outputs.path(OutputType::Mir); - let mut f = io::BufWriter::new(File::create(&path)?); - mir_util::write_mir_pretty(tcx, None, &mut f)?; - Ok(()) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/early_otherwise_branch.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/early_otherwise_branch.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/early_otherwise_branch.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/early_otherwise_branch.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,369 +0,0 @@ -use crate::{transform::MirPass, util::patch::MirPatch}; -use rustc_middle::mir::*; -use rustc_middle::ty::{Ty, TyCtxt}; -use std::fmt::Debug; - -use super::simplify::simplify_cfg; - -/// This pass optimizes something like -/// ```text -/// let x: Option<()>; -/// let y: Option<()>; -/// match (x,y) { -/// (Some(_), Some(_)) => {0}, -/// _ => {1} -/// } -/// ``` -/// into something like -/// ```text -/// let x: Option<()>; -/// let y: Option<()>; -/// let discriminant_x = // get discriminant of x -/// let discriminant_y = // get discriminant of y -/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0} -/// ``` -pub struct EarlyOtherwiseBranch; - -impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // FIXME(#78496) - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { - return; - } - - if tcx.sess.mir_opt_level() < 3 { - return; - } - trace!("running EarlyOtherwiseBranch on {:?}", body.source); - // we are only interested in this bb if the terminator is a switchInt - let bbs_with_switch = - body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator())); - - let opts_to_apply: Vec> = bbs_with_switch - .flat_map(|(bb_idx, bb)| { - let switch = bb.terminator(); - let helper = Helper { body, tcx }; - let infos = helper.go(bb, switch)?; - Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx }) - }) - .collect(); - - let should_cleanup = !opts_to_apply.is_empty(); - - for opt_to_apply in opts_to_apply { - if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) { - break; - } - - trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); - - let statements_before = - body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len(); - let end_of_block_location = Location { - block: opt_to_apply.basic_block_first_switch, - statement_index: statements_before, - }; - - let mut patch = MirPatch::new(body); - - // create temp to store second discriminant in - let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty; - let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span; - let second_discriminant_temp = patch.new_temp(discr_type, discr_span); - - patch.add_statement( - end_of_block_location, - StatementKind::StorageLive(second_discriminant_temp), - ); - - // create assignment of discriminant - let place_of_adt_to_get_discriminant_of = - opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read; - patch.add_assign( - end_of_block_location, - Place::from(second_discriminant_temp), - Rvalue::Discriminant(place_of_adt_to_get_discriminant_of), - ); - - // create temp to store NotEqual comparison between the two discriminants - let not_equal = BinOp::Ne; - let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type); - let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span); - patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp)); - - // create NotEqual comparison between the two discriminants - let first_descriminant_place = - opt_to_apply.infos[0].first_switch_info.discr_used_in_switch; - let not_equal_rvalue = Rvalue::BinaryOp( - not_equal, - Box::new(( - Operand::Copy(Place::from(second_discriminant_temp)), - Operand::Copy(first_descriminant_place), - )), - ); - patch.add_statement( - end_of_block_location, - StatementKind::Assign(Box::new((Place::from(not_equal_temp), not_equal_rvalue))), - ); - - let new_targets = opt_to_apply - .infos - .iter() - .flat_map(|x| x.second_switch_info.targets_with_values.iter()) - .cloned(); - - let targets = SwitchTargets::new( - new_targets, - opt_to_apply.infos[0].first_switch_info.otherwise_bb, - ); - - // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal - let new_switch_data = BasicBlockData::new(Some(Terminator { - source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info, - kind: TerminatorKind::SwitchInt { - // the first and second discriminants are equal, so just pick one - discr: Operand::Copy(first_descriminant_place), - switch_ty: discr_type, - targets, - }, - })); - - let new_switch_bb = patch.new_block(new_switch_data); - - // switch on the NotEqual. If true, then jump to the `otherwise` case. - // If false, then jump to a basic block that then jumps to the correct disciminant case - let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb; - let false_case = new_switch_bb; - patch.patch_terminator( - opt_to_apply.basic_block_first_switch, - TerminatorKind::if_( - tcx, - Operand::Move(Place::from(not_equal_temp)), - true_case, - false_case, - ), - ); - - // generate StorageDead for the second_discriminant_temp not in use anymore - patch.add_statement( - end_of_block_location, - StatementKind::StorageDead(second_discriminant_temp), - ); - - // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch - for bb in [false_case, true_case].iter() { - patch.add_statement( - Location { block: *bb, statement_index: 0 }, - StatementKind::StorageDead(not_equal_temp), - ); - } - - patch.apply(body); - } - - // Since this optimization adds new basic blocks and invalidates others, - // clean up the cfg to make it nicer for other passes - if should_cleanup { - simplify_cfg(tcx, body); - } - } -} - -fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool { - matches!(terminator.kind, TerminatorKind::SwitchInt { .. }) -} - -struct Helper<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, -} - -#[derive(Debug, Clone)] -struct SwitchDiscriminantInfo<'tcx> { - /// Type of the discriminant being switched on - discr_ty: Ty<'tcx>, - /// The basic block that the otherwise branch points to - otherwise_bb: BasicBlock, - /// Target along with the value being branched from. Otherwise is not included - targets_with_values: Vec<(u128, BasicBlock)>, - discr_source_info: SourceInfo, - /// The place of the discriminant used in the switch - discr_used_in_switch: Place<'tcx>, - /// The place of the adt that has its discriminant read - place_of_adt_discr_read: Place<'tcx>, - /// The type of the adt that has its discriminant read - type_adt_matched_on: Ty<'tcx>, -} - -#[derive(Debug)] -struct OptimizationToApply<'tcx> { - infos: Vec>, - /// Basic block of the original first switch - basic_block_first_switch: BasicBlock, -} - -#[derive(Debug)] -struct OptimizationInfo<'tcx> { - /// Info about the first switch and discriminant - first_switch_info: SwitchDiscriminantInfo<'tcx>, - /// Info about the second switch and discriminant - second_switch_info: SwitchDiscriminantInfo<'tcx>, -} - -impl<'a, 'tcx> Helper<'a, 'tcx> { - pub fn go( - &self, - bb: &BasicBlockData<'tcx>, - switch: &Terminator<'tcx>, - ) -> Option>> { - // try to find the statement that defines the discriminant that is used for the switch - let discr = self.find_switch_discriminant_info(bb, switch)?; - - // go through each target, finding a discriminant read, and a switch - let results = discr - .targets_with_values - .iter() - .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value)); - - // if the optimization did not apply for one of the targets, then abort - if results.clone().any(|x| x.is_none()) || results.len() == 0 { - trace!("NO: not all of the targets matched the pattern for optimization"); - return None; - } - - Some(results.flatten().collect()) - } - - fn find_discriminant_switch_pairing( - &self, - discr_info: &SwitchDiscriminantInfo<'tcx>, - target: BasicBlock, - value: u128, - ) -> Option> { - let bb = &self.body.basic_blocks()[target]; - // find switch - let terminator = bb.terminator(); - if is_switch(terminator) { - let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?; - - // the types of the two adts matched on have to be equalfor this optimization to apply - if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on { - trace!( - "NO: types do not match. LHS: {:?}, RHS: {:?}", - discr_info.type_adt_matched_on, - this_bb_discr_info.type_adt_matched_on - ); - return None; - } - - // the otherwise branch of the two switches have to point to the same bb - if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb { - trace!("NO: otherwise target is not the same"); - return None; - } - - // check that the value being matched on is the same. The - if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() { - trace!("NO: values being matched on are not the same"); - return None; - } - - // only allow optimization if the left and right of the tuple being matched are the same variants. - // so the following should not optimize - // ```rust - // let x: Option<()>; - // let y: Option<()>; - // match (x,y) { - // (Some(_), None) => {}, - // _ => {} - // } - // ``` - // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch - if !(this_bb_discr_info.targets_with_values.len() == 1 - && this_bb_discr_info.targets_with_values[0].0 == value) - { - trace!( - "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here" - ); - return None; - } - - // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially. - // for example, this should not be optimized: - // - // ```rust - // enum E<'a> { Empty, Some(&'a E<'a>), } - // let Some(Some(_)) = e; - // ``` - // - // ```mir - // bb0: { - // _2 = discriminant(*_1) - // switchInt(_2) -> [...] - // } - // bb1: { - // _3 = discriminant(*(((*_1) as Some).0: &E)) - // switchInt(_3) -> [...] - // } - // ``` - let discr_place = discr_info.place_of_adt_discr_read; - let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; - if discr_place.local == this_discr_place.local - && this_discr_place.projection.starts_with(discr_place.projection) - { - trace!("NO: one target is the projection of another"); - return None; - } - - // if we reach this point, the optimization applies, and we should be able to optimize this case - // store the info that is needed to apply the optimization - - Some(OptimizationInfo { - first_switch_info: discr_info.clone(), - second_switch_info: this_bb_discr_info, - }) - } else { - None - } - } - - fn find_switch_discriminant_info( - &self, - bb: &BasicBlockData<'tcx>, - switch: &Terminator<'tcx>, - ) -> Option> { - match &switch.kind { - TerminatorKind::SwitchInt { discr, targets, .. } => { - let discr_local = discr.place()?.as_local()?; - // the declaration of the discriminant read. Place of this read is being used in the switch - let discr_decl = &self.body.local_decls()[discr_local]; - let discr_ty = discr_decl.ty; - // the otherwise target lies as the last element - let otherwise_bb = targets.otherwise(); - let targets_with_values = targets.iter().collect(); - - // find the place of the adt where the discriminant is being read from - // assume this is the last statement of the block - let place_of_adt_discr_read = match bb.statements.last()?.kind { - StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => { - Some(adt_place) - } - _ => None, - }?; - - let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty; - - Some(SwitchDiscriminantInfo { - discr_used_in_switch: discr.place()?, - discr_ty, - otherwise_bb, - targets_with_values, - discr_source_info: discr_decl.source_info, - place_of_adt_discr_read, - type_adt_matched_on, - }) - } - _ => unreachable!("must only be passed terminator that is a switch"), - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/elaborate_drops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/elaborate_drops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/elaborate_drops.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/elaborate_drops.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,589 +0,0 @@ -use crate::dataflow; -use crate::dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; -use crate::dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; -use crate::dataflow::on_lookup_result_bits; -use crate::dataflow::MoveDataParamEnv; -use crate::dataflow::{on_all_children_bits, on_all_drop_children_bits}; -use crate::dataflow::{Analysis, ResultsCursor}; -use crate::transform::MirPass; -use crate::util::elaborate_drops::{elaborate_drop, DropFlagState, Unwind}; -use crate::util::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle}; -use crate::util::patch::MirPatch; -use rustc_data_structures::fx::FxHashMap; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::Span; -use rustc_target::abi::VariantIdx; -use std::fmt; - -pub struct ElaborateDrops; - -impl<'tcx> MirPass<'tcx> for ElaborateDrops { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); - - let def_id = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); - let move_data = match MoveData::gather_moves(body, tcx, param_env) { - Ok(move_data) => move_data, - Err((move_data, _)) => { - tcx.sess.delay_span_bug( - body.span, - "No `move_errors` should be allowed in MIR borrowck", - ); - move_data - } - }; - let elaborate_patch = { - let body = &*body; - let env = MoveDataParamEnv { move_data, param_env }; - let dead_unwinds = find_dead_unwinds(tcx, body, &env); - - let inits = MaybeInitializedPlaces::new(tcx, body, &env) - .into_engine(tcx, body) - .dead_unwinds(&dead_unwinds) - .pass_name("elaborate_drops") - .iterate_to_fixpoint() - .into_results_cursor(body); - - let uninits = MaybeUninitializedPlaces::new(tcx, body, &env) - .mark_inactive_variants_as_uninit() - .into_engine(tcx, body) - .dead_unwinds(&dead_unwinds) - .pass_name("elaborate_drops") - .iterate_to_fixpoint() - .into_results_cursor(body); - - ElaborateDropsCtxt { - tcx, - body, - env: &env, - init_data: InitializationData { inits, uninits }, - drop_flags: Default::default(), - patch: MirPatch::new(body), - } - .elaborate() - }; - elaborate_patch.apply(body); - } -} - -/// Returns the set of basic blocks whose unwind edges are known -/// to not be reachable, because they are `drop` terminators -/// that can't drop anything. -fn find_dead_unwinds<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - env: &MoveDataParamEnv<'tcx>, -) -> BitSet { - debug!("find_dead_unwinds({:?})", body.span); - // We only need to do this pass once, because unwind edges can only - // reach cleanup blocks, which can't have unwind edges themselves. - let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); - let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) - .into_engine(tcx, body) - .pass_name("find_dead_unwinds") - .iterate_to_fixpoint() - .into_results_cursor(body); - for (bb, bb_data) in body.basic_blocks().iter_enumerated() { - let place = match bb_data.terminator().kind { - TerminatorKind::Drop { ref place, unwind: Some(_), .. } - | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place, - _ => continue, - }; - - debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data); - - let path = match env.move_data.rev_lookup.find(place.as_ref()) { - LookupResult::Exact(e) => e, - LookupResult::Parent(..) => { - debug!("find_dead_unwinds: has parent; skipping"); - continue; - } - }; - - flow_inits.seek_before_primary_effect(body.terminator_loc(bb)); - debug!( - "find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}", - bb, - place, - path, - flow_inits.get() - ); - - let mut maybe_live = false; - on_all_drop_children_bits(tcx, body, &env, path, |child| { - maybe_live |= flow_inits.contains(child); - }); - - debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); - if !maybe_live { - dead_unwinds.insert(bb); - } - } - - dead_unwinds -} - -struct InitializationData<'mir, 'tcx> { - inits: ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, - uninits: ResultsCursor<'mir, 'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, -} - -impl InitializationData<'_, '_> { - fn seek_before(&mut self, loc: Location) { - self.inits.seek_before_primary_effect(loc); - self.uninits.seek_before_primary_effect(loc); - } - - fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) { - (self.inits.contains(path), self.uninits.contains(path)) - } -} - -struct Elaborator<'a, 'b, 'tcx> { - ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>, -} - -impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { - type Path = MovePathIndex; - - fn patch(&mut self) -> &mut MirPatch<'tcx> { - &mut self.ctxt.patch - } - - fn body(&self) -> &'a Body<'tcx> { - self.ctxt.body - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.ctxt.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.ctxt.param_env() - } - - fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { - let ((maybe_live, maybe_dead), multipart) = match mode { - DropFlagMode::Shallow => (self.ctxt.init_data.maybe_live_dead(path), false), - DropFlagMode::Deep => { - let mut some_live = false; - let mut some_dead = false; - let mut children_count = 0; - on_all_drop_children_bits(self.tcx(), self.body(), self.ctxt.env, path, |child| { - let (live, dead) = self.ctxt.init_data.maybe_live_dead(child); - debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); - some_live |= live; - some_dead |= dead; - children_count += 1; - }); - ((some_live, some_dead), children_count != 1) - } - }; - match (maybe_live, maybe_dead, multipart) { - (false, _, _) => DropStyle::Dead, - (true, false, _) => DropStyle::Static, - (true, true, false) => DropStyle::Conditional, - (true, true, true) => DropStyle::Open, - } - } - - fn clear_drop_flag(&mut self, loc: Location, path: Self::Path, mode: DropFlagMode) { - match mode { - DropFlagMode::Shallow => { - self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent); - } - DropFlagMode::Deep => { - on_all_children_bits( - self.tcx(), - self.body(), - self.ctxt.move_data(), - path, - |child| self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent), - ); - } - } - } - - fn field_subpath(&self, path: Self::Path, field: Field) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { - ProjectionElem::Field(idx, _) => idx == field, - _ => false, - }) - } - - fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - debug_assert!(size == min_length, "min_length should be exact for arrays"); - assert!(!from_end, "from_end should not be used for array element ConstantIndex"); - offset == index - } - _ => false, - }) - } - - fn deref_subpath(&self, path: Self::Path) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| { - e == ProjectionElem::Deref - }) - } - - fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { - ProjectionElem::Downcast(_, idx) => idx == variant, - _ => false, - }) - } - - fn get_drop_flag(&mut self, path: Self::Path) -> Option> { - self.ctxt.drop_flag(path).map(Operand::Copy) - } -} - -struct ElaborateDropsCtxt<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - env: &'a MoveDataParamEnv<'tcx>, - init_data: InitializationData<'a, 'tcx>, - drop_flags: FxHashMap, - patch: MirPatch<'tcx>, -} - -impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { - fn move_data(&self) -> &'b MoveData<'tcx> { - &self.env.move_data - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.env.param_env - } - - fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { - let tcx = self.tcx; - let patch = &mut self.patch; - debug!("create_drop_flag({:?})", self.body.span); - self.drop_flags.entry(index).or_insert_with(|| patch.new_internal(tcx.types.bool, span)); - } - - fn drop_flag(&mut self, index: MovePathIndex) -> Option> { - self.drop_flags.get(&index).map(|t| Place::from(*t)) - } - - /// create a patch that elaborates all drops in the input - /// MIR. - fn elaborate(mut self) -> MirPatch<'tcx> { - self.collect_drop_flags(); - - self.elaborate_drops(); - - self.drop_flags_on_init(); - self.drop_flags_for_fn_rets(); - self.drop_flags_for_args(); - self.drop_flags_for_locs(); - - self.patch - } - - fn collect_drop_flags(&mut self) { - for (bb, data) in self.body.basic_blocks().iter_enumerated() { - let terminator = data.terminator(); - let place = match terminator.kind { - TerminatorKind::Drop { ref place, .. } - | TerminatorKind::DropAndReplace { ref place, .. } => place, - _ => continue, - }; - - self.init_data.seek_before(self.body.terminator_loc(bb)); - - let path = self.move_data().rev_lookup.find(place.as_ref()); - debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, place, path); - - let path = match path { - LookupResult::Exact(e) => e, - LookupResult::Parent(None) => continue, - LookupResult::Parent(Some(parent)) => { - let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); - if maybe_dead { - span_bug!( - terminator.source_info.span, - "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", - bb, - place, - path - ); - } - continue; - } - }; - - on_all_drop_children_bits(self.tcx, self.body, self.env, path, |child| { - let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child); - debug!( - "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", - child, - place, - path, - (maybe_live, maybe_dead) - ); - if maybe_live && maybe_dead { - self.create_drop_flag(child, terminator.source_info.span) - } - }); - } - } - - fn elaborate_drops(&mut self) { - for (bb, data) in self.body.basic_blocks().iter_enumerated() { - let loc = Location { block: bb, statement_index: data.statements.len() }; - let terminator = data.terminator(); - - let resume_block = self.patch.resume_block(); - match terminator.kind { - TerminatorKind::Drop { place, target, unwind } => { - self.init_data.seek_before(loc); - match self.move_data().rev_lookup.find(place.as_ref()) { - LookupResult::Exact(path) => elaborate_drop( - &mut Elaborator { ctxt: self }, - terminator.source_info, - place, - path, - target, - if data.is_cleanup { - Unwind::InCleanup - } else { - Unwind::To(Option::unwrap_or(unwind, resume_block)) - }, - bb, - ), - LookupResult::Parent(..) => { - span_bug!( - terminator.source_info.span, - "drop of untracked value {:?}", - bb - ); - } - } - } - TerminatorKind::DropAndReplace { place, ref value, target, unwind } => { - assert!(!data.is_cleanup); - - self.elaborate_replace(loc, place, value, target, unwind); - } - _ => continue, - } - } - } - - /// Elaborate a MIR `replace` terminator. This instruction - /// is not directly handled by codegen, and therefore - /// must be desugared. - /// - /// The desugaring drops the location if needed, and then writes - /// the value (including setting the drop flag) over it in *both* arms. - /// - /// The `replace` terminator can also be called on places that - /// are not tracked by elaboration (for example, - /// `replace x[i] <- tmp0`). The borrow checker requires that - /// these locations are initialized before the assignment, - /// so we just generate an unconditional drop. - fn elaborate_replace( - &mut self, - loc: Location, - place: Place<'tcx>, - value: &Operand<'tcx>, - target: BasicBlock, - unwind: Option, - ) { - let bb = loc.block; - let data = &self.body[bb]; - let terminator = data.terminator(); - assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); - - let assign = Statement { - kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value.clone())))), - source_info: terminator.source_info, - }; - - let unwind = unwind.unwrap_or_else(|| self.patch.resume_block()); - let unwind = self.patch.new_block(BasicBlockData { - statements: vec![assign.clone()], - terminator: Some(Terminator { - kind: TerminatorKind::Goto { target: unwind }, - ..*terminator - }), - is_cleanup: true, - }); - - let target = self.patch.new_block(BasicBlockData { - statements: vec![assign], - terminator: Some(Terminator { kind: TerminatorKind::Goto { target }, ..*terminator }), - is_cleanup: false, - }); - - match self.move_data().rev_lookup.find(place.as_ref()) { - LookupResult::Exact(path) => { - debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); - self.init_data.seek_before(loc); - elaborate_drop( - &mut Elaborator { ctxt: self }, - terminator.source_info, - place, - path, - target, - Unwind::To(unwind), - bb, - ); - on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| { - self.set_drop_flag( - Location { block: target, statement_index: 0 }, - child, - DropFlagState::Present, - ); - self.set_drop_flag( - Location { block: unwind, statement_index: 0 }, - child, - DropFlagState::Present, - ); - }); - } - LookupResult::Parent(parent) => { - // drop and replace behind a pointer/array/whatever. The location - // must be initialized. - debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent); - self.patch.patch_terminator( - bb, - TerminatorKind::Drop { place, target, unwind: Some(unwind) }, - ); - } - } - } - - fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> { - Rvalue::Use(Operand::Constant(Box::new(Constant { - span, - user_ty: None, - literal: ty::Const::from_bool(self.tcx, val).into(), - }))) - } - - fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) { - if let Some(&flag) = self.drop_flags.get(&path) { - let span = self.patch.source_info_for_location(self.body, loc).span; - let val = self.constant_bool(span, val.value()); - self.patch.add_assign(loc, Place::from(flag), val); - } - } - - fn drop_flags_on_init(&mut self) { - let loc = Location::START; - let span = self.patch.source_info_for_location(self.body, loc).span; - let false_ = self.constant_bool(span, false); - for flag in self.drop_flags.values() { - self.patch.add_assign(loc, Place::from(*flag), false_.clone()); - } - } - - fn drop_flags_for_fn_rets(&mut self) { - for (bb, data) in self.body.basic_blocks().iter_enumerated() { - if let TerminatorKind::Call { - destination: Some((ref place, tgt)), - cleanup: Some(_), - .. - } = data.terminator().kind - { - assert!(!self.patch.is_patched(bb)); - - let loc = Location { block: tgt, statement_index: 0 }; - let path = self.move_data().rev_lookup.find(place.as_ref()); - on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| { - self.set_drop_flag(loc, child, DropFlagState::Present) - }); - } - } - } - - fn drop_flags_for_args(&mut self) { - let loc = Location::START; - dataflow::drop_flag_effects_for_function_entry(self.tcx, self.body, self.env, |path, ds| { - self.set_drop_flag(loc, path, ds); - }) - } - - fn drop_flags_for_locs(&mut self) { - // We intentionally iterate only over the *old* basic blocks. - // - // Basic blocks created by drop elaboration update their - // drop flags by themselves, to avoid the drop flags being - // clobbered before they are read. - - for (bb, data) in self.body.basic_blocks().iter_enumerated() { - debug!("drop_flags_for_locs({:?})", data); - for i in 0..(data.statements.len() + 1) { - debug!("drop_flag_for_locs: stmt {}", i); - let mut allow_initializations = true; - if i == data.statements.len() { - match data.terminator().kind { - TerminatorKind::Drop { .. } => { - // drop elaboration should handle that by itself - continue; - } - TerminatorKind::DropAndReplace { .. } => { - // this contains the move of the source and - // the initialization of the destination. We - // only want the former - the latter is handled - // by the elaboration code and must be done - // *after* the destination is dropped. - assert!(self.patch.is_patched(bb)); - allow_initializations = false; - } - TerminatorKind::Resume => { - // It is possible for `Resume` to be patched - // (in particular it can be patched to be replaced with - // a Goto; see `MirPatch::new`). - } - _ => { - assert!(!self.patch.is_patched(bb)); - } - } - } - let loc = Location { block: bb, statement_index: i }; - dataflow::drop_flag_effects_for_location( - self.tcx, - self.body, - self.env, - loc, - |path, ds| { - if ds == DropFlagState::Absent || allow_initializations { - self.set_drop_flag(loc, path, ds) - } - }, - ) - } - - // There may be a critical edge after this call, - // so mark the return as initialized *before* the - // call. - if let TerminatorKind::Call { - destination: Some((ref place, _)), cleanup: None, .. - } = data.terminator().kind - { - assert!(!self.patch.is_patched(bb)); - - let loc = Location { block: bb, statement_index: data.statements.len() }; - let path = self.move_data().rev_lookup.find(place.as_ref()); - on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| { - self.set_drop_flag(loc, child, DropFlagState::Present) - }); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/function_item_references.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/function_item_references.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/function_item_references.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/function_item_references.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,223 +0,0 @@ -use rustc_errors::Applicability; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::*; -use rustc_middle::ty::{ - self, - subst::{GenericArgKind, Subst, SubstsRef}, - PredicateKind, Ty, TyCtxt, TyS, -}; -use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; -use rustc_span::{symbol::sym, Span}; -use rustc_target::spec::abi::Abi; - -use crate::transform::MirPass; - -pub struct FunctionItemReferences; - -impl<'tcx> MirPass<'tcx> for FunctionItemReferences { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mut checker = FunctionItemRefChecker { tcx, body }; - checker.visit_body(&body); - } -} - -struct FunctionItemRefChecker<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> { - /// Emits a lint for function reference arguments bound by `fmt::Pointer` or passed to - /// `transmute`. This only handles arguments in calls outside macro expansions to avoid double - /// counting function references formatted as pointers by macros. - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - if let TerminatorKind::Call { - func, - args, - destination: _, - cleanup: _, - from_hir_call: _, - fn_span: _, - } = &terminator.kind - { - let source_info = *self.body.source_info(location); - // Only handle function calls outside macros - if !source_info.span.from_expansion() { - let func_ty = func.ty(self.body, self.tcx); - if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() { - // Handle calls to `transmute` - if self.tcx.is_diagnostic_item(sym::transmute, def_id) { - let arg_ty = args[0].ty(self.body, self.tcx); - for generic_inner_ty in arg_ty.walk(self.tcx) { - if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { - if let Some((fn_id, fn_substs)) = - FunctionItemRefChecker::is_fn_ref(inner_ty) - { - let span = self.nth_arg_span(&args, 0); - self.emit_lint(fn_id, fn_substs, source_info, span); - } - } - } - } else { - self.check_bound_args(def_id, substs_ref, &args, source_info); - } - } - } - } - self.super_terminator(terminator, location); - } - - /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These - /// cases are handled as operands instead of call terminators to avoid any dependence on - /// unstable, internal formatting details like whether `fmt` is called directly or not. - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - let source_info = *self.body.source_info(location); - if source_info.span.from_expansion() { - let op_ty = operand.ty(self.body, self.tcx); - if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() { - if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) { - let param_ty = substs_ref.type_at(0); - if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(param_ty) { - // The operand's ctxt wouldn't display the lint since it's inside a macro so - // we have to use the callsite's ctxt. - let callsite_ctxt = source_info.span.source_callsite().ctxt(); - let span = source_info.span.with_ctxt(callsite_ctxt); - self.emit_lint(fn_id, fn_substs, source_info, span); - } - } - } - } - self.super_operand(operand, location); - } -} - -impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { - /// Emits a lint for function reference arguments bound by `fmt::Pointer` in calls to the - /// function defined by `def_id` with the substitutions `substs_ref`. - fn check_bound_args( - &self, - def_id: DefId, - substs_ref: SubstsRef<'tcx>, - args: &[Operand<'tcx>], - source_info: SourceInfo, - ) { - let param_env = self.tcx.param_env(def_id); - let bounds = param_env.caller_bounds(); - for bound in bounds { - if let Some(bound_ty) = self.is_pointer_trait(&bound.kind().skip_binder()) { - // Get the argument types as they appear in the function signature. - let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs(); - for (arg_num, arg_def) in arg_defs.iter().enumerate() { - // For all types reachable from the argument type in the fn sig - for generic_inner_ty in arg_def.walk(self.tcx) { - if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { - // If the inner type matches the type bound by `Pointer` - if TyS::same_type(inner_ty, bound_ty) { - // Do a substitution using the parameters from the callsite - let subst_ty = inner_ty.subst(self.tcx, substs_ref); - if let Some((fn_id, fn_substs)) = - FunctionItemRefChecker::is_fn_ref(subst_ty) - { - let span = self.nth_arg_span(args, arg_num); - self.emit_lint(fn_id, fn_substs, source_info, span); - } - } - } - } - } - } - } - } - - /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type. - fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option> { - if let ty::PredicateKind::Trait(predicate) = bound { - if self.tcx.is_diagnostic_item(sym::pointer_trait, predicate.def_id()) { - Some(predicate.trait_ref.self_ty()) - } else { - None - } - } else { - None - } - } - - /// If a type is a reference or raw pointer to the anonymous type of a function definition, - /// returns that function's `DefId` and `SubstsRef`. - fn is_fn_ref(ty: Ty<'tcx>) -> Option<(DefId, SubstsRef<'tcx>)> { - let referent_ty = match ty.kind() { - ty::Ref(_, referent_ty, _) => Some(referent_ty), - ty::RawPtr(ty_and_mut) => Some(&ty_and_mut.ty), - _ => None, - }; - referent_ty - .map(|ref_ty| { - if let ty::FnDef(def_id, substs_ref) = *ref_ty.kind() { - Some((def_id, substs_ref)) - } else { - None - } - }) - .unwrap_or(None) - } - - fn nth_arg_span(&self, args: &[Operand<'tcx>], n: usize) -> Span { - match &args[n] { - Operand::Copy(place) | Operand::Move(place) => { - self.body.local_decls[place.local].source_info.span - } - Operand::Constant(constant) => constant.span, - } - } - - fn emit_lint( - &self, - fn_id: DefId, - fn_substs: SubstsRef<'tcx>, - source_info: SourceInfo, - span: Span, - ) { - let lint_root = self.body.source_scopes[source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; - let fn_sig = self.tcx.fn_sig(fn_id); - let unsafety = fn_sig.unsafety().prefix_str(); - let abi = match fn_sig.abi() { - Abi::Rust => String::from(""), - other_abi => { - let mut s = String::from("extern \""); - s.push_str(other_abi.name()); - s.push_str("\" "); - s - } - }; - let ident = self.tcx.item_name(fn_id).to_ident_string(); - let ty_params = fn_substs.types().map(|ty| format!("{}", ty)); - let const_params = fn_substs.consts().map(|c| format!("{}", c)); - let params = ty_params.chain(const_params).collect::>().join(", "); - let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); - let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; - let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; - self.tcx.struct_span_lint_hir(FUNCTION_ITEM_REFERENCES, lint_root, span, |lint| { - lint.build("taking a reference to a function item does not give a function pointer") - .span_suggestion( - span, - &format!("cast `{}` to obtain a function pointer", ident), - format!( - "{} as {}{}fn({}{}){}", - if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) }, - unsafety, - abi, - vec!["_"; num_args].join(", "), - variadic, - ret, - ), - Applicability::Unspecified, - ) - .emit(); - }); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/generator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/generator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/generator.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/generator.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1500 +0,0 @@ -//! This is the implementation of the pass which transforms generators into state machines. -//! -//! MIR generation for generators creates a function which has a self argument which -//! passes by value. This argument is effectively a generator type which only contains upvars and -//! is only used for this argument inside the MIR for the generator. -//! It is passed by value to enable upvars to be moved out of it. Drop elaboration runs on that -//! MIR before this pass and creates drop flags for MIR locals. -//! It will also drop the generator argument (which only consists of upvars) if any of the upvars -//! are moved out of. This pass elaborates the drops of upvars / generator argument in the case -//! that none of the upvars were moved out of. This is because we cannot have any drops of this -//! generator in the MIR, since it is used to create the drop glue for the generator. We'd get -//! infinite recursion otherwise. -//! -//! This pass creates the implementation for the Generator::resume function and the drop shim -//! for the generator based on the MIR input. It converts the generator argument from Self to -//! &mut Self adding derefs in the MIR as needed. It computes the final layout of the generator -//! struct which looks like this: -//! First upvars are stored -//! It is followed by the generator state field. -//! Then finally the MIR locals which are live across a suspension point are stored. -//! -//! struct Generator { -//! upvars..., -//! state: u32, -//! mir_locals..., -//! } -//! -//! This pass computes the meaning of the state field and the MIR locals which are live -//! across a suspension point. There are however three hardcoded generator states: -//! 0 - Generator have not been resumed yet -//! 1 - Generator has returned / is completed -//! 2 - Generator has been poisoned -//! -//! It also rewrites `return x` and `yield y` as setting a new generator state and returning -//! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively. -//! MIR locals which are live across a suspension point are moved to the generator struct -//! with references to them being updated with references to the generator struct. -//! -//! The pass creates two functions which have a switch on the generator state giving -//! the action to take. -//! -//! One of them is the implementation of Generator::resume. -//! For generators with state 0 (unresumed) it starts the execution of the generator. -//! For generators with state 1 (returned) and state 2 (poisoned) it panics. -//! Otherwise it continues the execution from the last suspension point. -//! -//! The other function is the drop glue for the generator. -//! For generators with state 0 (unresumed) it drops the upvars of the generator. -//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing. -//! Otherwise it drops all the values in scope at the last suspension point. - -use crate::dataflow::impls::{ - MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, -}; -use crate::dataflow::{self, Analysis}; -use crate::transform::simplify; -use crate::transform::MirPass; -use crate::util::dump_mir; -use crate::util::expand_aggregate; -use crate::util::storage; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; -use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::{BitMatrix, BitSet}; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::subst::{Subst, SubstsRef}; -use rustc_middle::ty::GeneratorSubsts; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; -use rustc_target::abi::VariantIdx; -use rustc_target::spec::PanicStrategy; -use std::{iter, ops}; - -pub struct StateTransform; - -struct RenameLocalVisitor<'tcx> { - from: Local, - to: Local, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - if *local == self.from { - *local = self.to; - } - } - - fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - match terminator.kind { - TerminatorKind::Return => { - // Do not replace the implicit `_0` access here, as that's not possible. The - // transform already handles `return` correctly. - } - _ => self.super_terminator(terminator, location), - } - } -} - -struct DerefArgVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - assert_ne!(*local, SELF_ARG); - } - - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.local == SELF_ARG { - replace_base( - place, - Place { - local: SELF_ARG, - projection: self.tcx().intern_place_elems(&[ProjectionElem::Deref]), - }, - self.tcx, - ); - } else { - self.visit_local(&mut place.local, context, location); - - for elem in place.projection.iter() { - if let PlaceElem::Index(local) = elem { - assert_ne!(local, SELF_ARG); - } - } - } - } -} - -struct PinArgVisitor<'tcx> { - ref_gen_ty: Ty<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - assert_ne!(*local, SELF_ARG); - } - - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.local == SELF_ARG { - replace_base( - place, - Place { - local: SELF_ARG, - projection: self.tcx().intern_place_elems(&[ProjectionElem::Field( - Field::new(0), - self.ref_gen_ty, - )]), - }, - self.tcx, - ); - } else { - self.visit_local(&mut place.local, context, location); - - for elem in place.projection.iter() { - if let PlaceElem::Index(local) = elem { - assert_ne!(local, SELF_ARG); - } - } - } - } -} - -fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) { - place.local = new_base.local; - - let mut new_projection = new_base.projection.to_vec(); - new_projection.append(&mut place.projection.to_vec()); - - place.projection = tcx.intern_place_elems(&new_projection); -} - -const SELF_ARG: Local = Local::from_u32(1); - -/// Generator has not been resumed yet. -const UNRESUMED: usize = GeneratorSubsts::UNRESUMED; -/// Generator has returned / is completed. -const RETURNED: usize = GeneratorSubsts::RETURNED; -/// Generator has panicked and is poisoned. -const POISONED: usize = GeneratorSubsts::POISONED; - -/// A `yield` point in the generator. -struct SuspensionPoint<'tcx> { - /// State discriminant used when suspending or resuming at this point. - state: usize, - /// The block to jump to after resumption. - resume: BasicBlock, - /// Where to move the resume argument after resumption. - resume_arg: Place<'tcx>, - /// Which block to jump to if the generator is dropped in this state. - drop: Option, - /// Set of locals that have live storage while at this suspension point. - storage_liveness: BitSet, -} - -struct TransformVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - state_adt_ref: &'tcx AdtDef, - state_substs: SubstsRef<'tcx>, - - // The type of the discriminant in the generator struct - discr_ty: Ty<'tcx>, - - // Mapping from Local to (type of local, generator struct index) - // FIXME(eddyb) This should use `IndexVec>`. - remap: FxHashMap, VariantIdx, usize)>, - - // A map from a suspension point in a block to the locals which have live storage at that point - storage_liveness: IndexVec>>, - - // A list of suspension points, generated during the transform - suspension_points: Vec>, - - // The set of locals that have no `StorageLive`/`StorageDead` annotations. - always_live_locals: storage::AlwaysLiveLocals, - - // The original RETURN_PLACE local - new_ret_local: Local, -} - -impl TransformVisitor<'tcx> { - // Make a GeneratorState variant assignment. `core::ops::GeneratorState` only has single - // element tuple variants, so we can just write to the downcasted first field and then set the - // discriminant to the appropriate variant. - fn make_state( - &self, - idx: VariantIdx, - val: Operand<'tcx>, - source_info: SourceInfo, - ) -> impl Iterator> { - let kind = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None); - assert_eq!(self.state_adt_ref.variants[idx].fields.len(), 1); - let ty = self - .tcx - .type_of(self.state_adt_ref.variants[idx].fields[0].did) - .subst(self.tcx, self.state_substs); - expand_aggregate( - Place::return_place(), - std::iter::once((val, ty)), - kind, - source_info, - self.tcx, - ) - } - - // Create a Place referencing a generator struct field - fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { - let self_place = Place::from(SELF_ARG); - let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index); - let mut projection = base.projection.to_vec(); - projection.push(ProjectionElem::Field(Field::new(idx), ty)); - - Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) } - } - - // Create a statement which changes the discriminant - fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> { - let self_place = Place::from(SELF_ARG); - Statement { - source_info, - kind: StatementKind::SetDiscriminant { - place: Box::new(self_place), - variant_index: state_disc, - }, - } - } - - // Create a statement which reads the discriminant into a temporary - fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) { - let temp_decl = LocalDecl::new(self.discr_ty, body.span).internal(); - let local_decls_len = body.local_decls.push(temp_decl); - let temp = Place::from(local_decls_len); - - let self_place = Place::from(SELF_ARG); - let assign = Statement { - source_info: SourceInfo::outermost(body.span), - kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))), - }; - (assign, temp) - } -} - -impl MutVisitor<'tcx> for TransformVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - assert_eq!(self.remap.get(local), None); - } - - fn visit_place( - &mut self, - place: &mut Place<'tcx>, - _context: PlaceContext, - _location: Location, - ) { - // Replace an Local in the remap with a generator struct access - if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) { - replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); - } - } - - fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { - // Remove StorageLive and StorageDead statements for remapped locals - data.retain_statements(|s| match s.kind { - StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { - !self.remap.contains_key(&l) - } - _ => true, - }); - - let ret_val = match data.terminator().kind { - TerminatorKind::Return => Some(( - VariantIdx::new(1), - None, - Operand::Move(Place::from(self.new_ret_local)), - None, - )), - TerminatorKind::Yield { ref value, resume, resume_arg, drop } => { - Some((VariantIdx::new(0), Some((resume, resume_arg)), value.clone(), drop)) - } - _ => None, - }; - - if let Some((state_idx, resume, v, drop)) = ret_val { - let source_info = data.terminator().source_info; - // We must assign the value first in case it gets declared dead below - data.statements.extend(self.make_state(state_idx, v, source_info)); - let state = if let Some((resume, resume_arg)) = resume { - // Yield - let state = 3 + self.suspension_points.len(); - - // The resume arg target location might itself be remapped if its base local is - // live across a yield. - let resume_arg = - if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) { - self.make_field(variant, idx, ty) - } else { - resume_arg - }; - - self.suspension_points.push(SuspensionPoint { - state, - resume, - resume_arg, - drop, - storage_liveness: self.storage_liveness[block].clone().unwrap(), - }); - - VariantIdx::new(state) - } else { - // Return - VariantIdx::new(RETURNED) // state for returned - }; - data.statements.push(self.set_discr(state, source_info)); - data.terminator_mut().kind = TerminatorKind::Return; - } - - self.super_basic_block_data(block, data); - } -} - -fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let gen_ty = body.local_decls.raw[1].ty; - - let ref_gen_ty = - tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut }); - - // Replace the by value generator argument - body.local_decls.raw[1].ty = ref_gen_ty; - - // Add a deref to accesses of the generator state - DerefArgVisitor { tcx }.visit_body(body); -} - -fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let ref_gen_ty = body.local_decls.raw[1].ty; - - let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span)); - let pin_adt_ref = tcx.adt_def(pin_did); - let substs = tcx.intern_substs(&[ref_gen_ty.into()]); - let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs); - - // Replace the by ref generator argument - body.local_decls.raw[1].ty = pin_ref_gen_ty; - - // Add the Pin field access to accesses of the generator state - PinArgVisitor { ref_gen_ty, tcx }.visit_body(body); -} - -/// Allocates a new local and replaces all references of `local` with it. Returns the new local. -/// -/// `local` will be changed to a new local decl with type `ty`. -/// -/// Note that the new local will be uninitialized. It is the caller's responsibility to assign some -/// valid value to it before its first use. -fn replace_local<'tcx>( - local: Local, - ty: Ty<'tcx>, - body: &mut Body<'tcx>, - tcx: TyCtxt<'tcx>, -) -> Local { - let new_decl = LocalDecl::new(ty, body.span); - let new_local = body.local_decls.push(new_decl); - body.local_decls.swap(local, new_local); - - RenameLocalVisitor { from: local, to: new_local, tcx }.visit_body(body); - - new_local -} - -struct LivenessInfo { - /// Which locals are live across any suspension point. - saved_locals: GeneratorSavedLocals, - - /// The set of saved locals live at each suspension point. - live_locals_at_suspension_points: Vec>, - - /// Parallel vec to the above with SourceInfo for each yield terminator. - source_info_at_suspension_points: Vec, - - /// For every saved local, the set of other saved locals that are - /// storage-live at the same time as this local. We cannot overlap locals in - /// the layout which have conflicting storage. - storage_conflicts: BitMatrix, - - /// For every suspending block, the locals which are storage-live across - /// that suspension point. - storage_liveness: IndexVec>>, -} - -fn locals_live_across_suspend_points( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - always_live_locals: &storage::AlwaysLiveLocals, - movable: bool, -) -> LivenessInfo { - let body_ref: &Body<'_> = &body; - - // Calculate when MIR locals have live storage. This gives us an upper bound of their - // lifetimes. - let mut storage_live = MaybeStorageLive::new(always_live_locals.clone()) - .into_engine(tcx, body_ref) - .iterate_to_fixpoint() - .into_results_cursor(body_ref); - - // Calculate the MIR locals which have been previously - // borrowed (even if they are still active). - let borrowed_locals_results = MaybeBorrowedLocals::all_borrows() - .into_engine(tcx, body_ref) - .pass_name("generator") - .iterate_to_fixpoint(); - - let mut borrowed_locals_cursor = - dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results); - - // Calculate the MIR locals that we actually need to keep storage around - // for. - let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results) - .into_engine(tcx, body_ref) - .iterate_to_fixpoint(); - let mut requires_storage_cursor = - dataflow::ResultsCursor::new(body_ref, &requires_storage_results); - - // Calculate the liveness of MIR locals ignoring borrows. - let mut liveness = MaybeLiveLocals - .into_engine(tcx, body_ref) - .pass_name("generator") - .iterate_to_fixpoint() - .into_results_cursor(body_ref); - - let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks()); - let mut live_locals_at_suspension_points = Vec::new(); - let mut source_info_at_suspension_points = Vec::new(); - let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len()); - - for (block, data) in body.basic_blocks().iter_enumerated() { - if let TerminatorKind::Yield { .. } = data.terminator().kind { - let loc = Location { block, statement_index: data.statements.len() }; - - liveness.seek_to_block_end(block); - let mut live_locals = liveness.get().clone(); - - if !movable { - // The `liveness` variable contains the liveness of MIR locals ignoring borrows. - // This is correct for movable generators since borrows cannot live across - // suspension points. However for immovable generators we need to account for - // borrows, so we conseratively assume that all borrowed locals are live until - // we find a StorageDead statement referencing the locals. - // To do this we just union our `liveness` result with `borrowed_locals`, which - // contains all the locals which has been borrowed before this suspension point. - // If a borrow is converted to a raw reference, we must also assume that it lives - // forever. Note that the final liveness is still bounded by the storage liveness - // of the local, which happens using the `intersect` operation below. - borrowed_locals_cursor.seek_before_primary_effect(loc); - live_locals.union(borrowed_locals_cursor.get()); - } - - // Store the storage liveness for later use so we can restore the state - // after a suspension point - storage_live.seek_before_primary_effect(loc); - storage_liveness_map[block] = Some(storage_live.get().clone()); - - // Locals live are live at this point only if they are used across - // suspension points (the `liveness` variable) - // and their storage is required (the `storage_required` variable) - requires_storage_cursor.seek_before_primary_effect(loc); - live_locals.intersect(requires_storage_cursor.get()); - - // The generator argument is ignored. - live_locals.remove(SELF_ARG); - - debug!("loc = {:?}, live_locals = {:?}", loc, live_locals); - - // Add the locals live at this suspension point to the set of locals which live across - // any suspension points - live_locals_at_any_suspension_point.union(&live_locals); - - live_locals_at_suspension_points.push(live_locals); - source_info_at_suspension_points.push(data.terminator().source_info); - } - } - - debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point); - let saved_locals = GeneratorSavedLocals(live_locals_at_any_suspension_point); - - // Renumber our liveness_map bitsets to include only the locals we are - // saving. - let live_locals_at_suspension_points = live_locals_at_suspension_points - .iter() - .map(|live_here| saved_locals.renumber_bitset(&live_here)) - .collect(); - - let storage_conflicts = compute_storage_conflicts( - body_ref, - &saved_locals, - always_live_locals.clone(), - requires_storage_results, - ); - - LivenessInfo { - saved_locals, - live_locals_at_suspension_points, - source_info_at_suspension_points, - storage_conflicts, - storage_liveness: storage_liveness_map, - } -} - -/// The set of `Local`s that must be saved across yield points. -/// -/// `GeneratorSavedLocal` is indexed in terms of the elements in this set; -/// i.e. `GeneratorSavedLocal::new(1)` corresponds to the second local -/// included in this set. -struct GeneratorSavedLocals(BitSet); - -impl GeneratorSavedLocals { - /// Returns an iterator over each `GeneratorSavedLocal` along with the `Local` it corresponds - /// to. - fn iter_enumerated(&self) -> impl '_ + Iterator { - self.iter().enumerate().map(|(i, l)| (GeneratorSavedLocal::from(i), l)) - } - - /// Transforms a `BitSet` that contains only locals saved across yield points to the - /// equivalent `BitSet`. - fn renumber_bitset(&self, input: &BitSet) -> BitSet { - assert!(self.superset(&input), "{:?} not a superset of {:?}", self.0, input); - let mut out = BitSet::new_empty(self.count()); - for (saved_local, local) in self.iter_enumerated() { - if input.contains(local) { - out.insert(saved_local); - } - } - out - } - - fn get(&self, local: Local) -> Option { - if !self.contains(local) { - return None; - } - - let idx = self.iter().take_while(|&l| l < local).count(); - Some(GeneratorSavedLocal::new(idx)) - } -} - -impl ops::Deref for GeneratorSavedLocals { - type Target = BitSet; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -/// For every saved local, looks for which locals are StorageLive at the same -/// time. Generates a bitset for every local of all the other locals that may be -/// StorageLive simultaneously with that local. This is used in the layout -/// computation; see `GeneratorLayout` for more. -fn compute_storage_conflicts( - body: &'mir Body<'tcx>, - saved_locals: &GeneratorSavedLocals, - always_live_locals: storage::AlwaysLiveLocals, - requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, -) -> BitMatrix { - assert_eq!(body.local_decls.len(), saved_locals.domain_size()); - - debug!("compute_storage_conflicts({:?})", body.span); - debug!("always_live = {:?}", always_live_locals); - - // Locals that are always live or ones that need to be stored across - // suspension points are not eligible for overlap. - let mut ineligible_locals = always_live_locals.into_inner(); - ineligible_locals.intersect(&**saved_locals); - - // Compute the storage conflicts for all eligible locals. - let mut visitor = StorageConflictVisitor { - body, - saved_locals: &saved_locals, - local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), - }; - - requires_storage.visit_reachable_with(body, &mut visitor); - - let local_conflicts = visitor.local_conflicts; - - // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal). - // - // NOTE: Today we store a full conflict bitset for every local. Technically - // this is twice as many bits as we need, since the relation is symmetric. - // However, in practice these bitsets are not usually large. The layout code - // also needs to keep track of how many conflicts each local has, so it's - // simpler to keep it this way for now. - let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count()); - for (saved_local_a, local_a) in saved_locals.iter_enumerated() { - if ineligible_locals.contains(local_a) { - // Conflicts with everything. - storage_conflicts.insert_all_into_row(saved_local_a); - } else { - // Keep overlap information only for stored locals. - for (saved_local_b, local_b) in saved_locals.iter_enumerated() { - if local_conflicts.contains(local_a, local_b) { - storage_conflicts.insert(saved_local_a, saved_local_b); - } - } - } - } - storage_conflicts -} - -struct StorageConflictVisitor<'mir, 'tcx, 's> { - body: &'mir Body<'tcx>, - saved_locals: &'s GeneratorSavedLocals, - // FIXME(tmandry): Consider using sparse bitsets here once we have good - // benchmarks for generators. - local_conflicts: BitMatrix, -} - -impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> { - type FlowState = BitSet; - - fn visit_statement_before_primary_effect( - &mut self, - state: &Self::FlowState, - _statement: &'mir Statement<'tcx>, - loc: Location, - ) { - self.apply_state(state, loc); - } - - fn visit_terminator_before_primary_effect( - &mut self, - state: &Self::FlowState, - _terminator: &'mir Terminator<'tcx>, - loc: Location, - ) { - self.apply_state(state, loc); - } -} - -impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> { - fn apply_state(&mut self, flow_state: &BitSet, loc: Location) { - // Ignore unreachable blocks. - if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable { - return; - } - - let mut eligible_storage_live = flow_state.clone(); - eligible_storage_live.intersect(&**self.saved_locals); - - for local in eligible_storage_live.iter() { - self.local_conflicts.union_row_with(&eligible_storage_live, local); - } - - if eligible_storage_live.count() > 1 { - trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live); - } - } -} - -/// Validates the typeck view of the generator against the actual set of types saved between -/// yield points. -fn sanitize_witness<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - witness: Ty<'tcx>, - upvars: Vec>, - saved_locals: &GeneratorSavedLocals, -) { - let did = body.source.def_id(); - let allowed_upvars = tcx.erase_regions(upvars); - let allowed = match witness.kind() { - &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s), - _ => { - tcx.sess.delay_span_bug( - body.span, - &format!("unexpected generator witness type {:?}", witness.kind()), - ); - return; - } - }; - - let param_env = tcx.param_env(did); - - for (local, decl) in body.local_decls.iter_enumerated() { - // Ignore locals which are internal or not saved between yields. - if !saved_locals.contains(local) || decl.internal { - continue; - } - let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty); - - // Sanity check that typeck knows about the type of locals which are - // live across a suspension point - if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) { - span_bug!( - body.span, - "Broken MIR: generator contains type {} in MIR, \ - but typeck only knows about {} and {:?}", - decl_ty, - allowed, - allowed_upvars - ); - } - } -} - -fn compute_layout<'tcx>( - liveness: LivenessInfo, - body: &mut Body<'tcx>, -) -> ( - FxHashMap, VariantIdx, usize)>, - GeneratorLayout<'tcx>, - IndexVec>>, -) { - let LivenessInfo { - saved_locals, - live_locals_at_suspension_points, - source_info_at_suspension_points, - storage_conflicts, - storage_liveness, - } = liveness; - - // Gather live local types and their indices. - let mut locals = IndexVec::::new(); - let mut tys = IndexVec::::new(); - for (saved_local, local) in saved_locals.iter_enumerated() { - locals.push(local); - tys.push(body.local_decls[local].ty); - debug!("generator saved local {:?} => {:?}", saved_local, local); - } - - // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. - // In debuginfo, these will correspond to the beginning (UNRESUMED) or end - // (RETURNED, POISONED) of the function. - const RESERVED_VARIANTS: usize = 3; - let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span; - let mut variant_source_info: IndexVec = [ - SourceInfo::outermost(body_span.shrink_to_lo()), - SourceInfo::outermost(body_span.shrink_to_hi()), - SourceInfo::outermost(body_span.shrink_to_hi()), - ] - .iter() - .copied() - .collect(); - - // Build the generator variant field list. - // Create a map from local indices to generator struct indices. - let mut variant_fields: IndexVec> = - iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect(); - let mut remap = FxHashMap::default(); - for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() { - let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx); - let mut fields = IndexVec::new(); - for (idx, saved_local) in live_locals.iter().enumerate() { - fields.push(saved_local); - // Note that if a field is included in multiple variants, we will - // just use the first one here. That's fine; fields do not move - // around inside generators, so it doesn't matter which variant - // index we access them by. - remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx)); - } - variant_fields.push(fields); - variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]); - } - debug!("generator variant_fields = {:?}", variant_fields); - debug!("generator storage_conflicts = {:#?}", storage_conflicts); - - let layout = - GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; - - (remap, layout, storage_liveness) -} - -/// Replaces the entry point of `body` with a block that switches on the generator discriminant and -/// dispatches to blocks according to `cases`. -/// -/// After this function, the former entry point of the function will be bb1. -fn insert_switch<'tcx>( - body: &mut Body<'tcx>, - cases: Vec<(usize, BasicBlock)>, - transform: &TransformVisitor<'tcx>, - default: TerminatorKind<'tcx>, -) { - let default_block = insert_term_block(body, default); - let (assign, discr) = transform.get_discr(body); - let switch_targets = - SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block); - let switch = TerminatorKind::SwitchInt { - discr: Operand::Move(discr), - switch_ty: transform.discr_ty, - targets: switch_targets, - }; - - let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().raw.insert( - 0, - BasicBlockData { - statements: vec![assign], - terminator: Some(Terminator { source_info, kind: switch }), - is_cleanup: false, - }, - ); - - let blocks = body.basic_blocks_mut().iter_mut(); - - for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { - *target = BasicBlock::new(target.index() + 1); - } -} - -fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - use crate::shim::DropShimElaborator; - use crate::util::elaborate_drops::{elaborate_drop, Unwind}; - use crate::util::patch::MirPatch; - - // Note that `elaborate_drops` only drops the upvars of a generator, and - // this is ok because `open_drop` can only be reached within that own - // generator's resume function. - - let def_id = body.source.def_id(); - let param_env = tcx.param_env(def_id); - - let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env }; - - for (block, block_data) in body.basic_blocks().iter_enumerated() { - let (target, unwind, source_info) = match block_data.terminator() { - Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => { - if let Some(local) = place.as_local() { - if local == SELF_ARG { - (target, unwind, source_info) - } else { - continue; - } - } else { - continue; - } - } - _ => continue, - }; - let unwind = if block_data.is_cleanup { - Unwind::InCleanup - } else { - Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block())) - }; - elaborate_drop( - &mut elaborator, - *source_info, - Place::from(SELF_ARG), - (), - *target, - unwind, - block, - ); - } - elaborator.patch.apply(body); -} - -fn create_generator_drop_shim<'tcx>( - tcx: TyCtxt<'tcx>, - transform: &TransformVisitor<'tcx>, - gen_ty: Ty<'tcx>, - body: &mut Body<'tcx>, - drop_clean: BasicBlock, -) -> Body<'tcx> { - let mut body = body.clone(); - body.arg_count = 1; // make sure the resume argument is not included here - - let source_info = SourceInfo::outermost(body.span); - - let mut cases = create_cases(&mut body, transform, Operation::Drop); - - cases.insert(0, (UNRESUMED, drop_clean)); - - // The returned state and the poisoned state fall through to the default - // case which is just to return - - insert_switch(&mut body, cases, &transform, TerminatorKind::Return); - - for block in body.basic_blocks_mut() { - let kind = &mut block.terminator_mut().kind; - if let TerminatorKind::GeneratorDrop = *kind { - *kind = TerminatorKind::Return; - } - } - - // Replace the return variable - body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(tcx.mk_unit(), source_info); - - make_generator_state_argument_indirect(tcx, &mut body); - - // Change the generator argument from &mut to *mut - body.local_decls[SELF_ARG] = LocalDecl::with_source_info( - tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }), - source_info, - ); - if tcx.sess.opts.debugging_opts.mir_emit_retag { - // Alias tracking must know we changed the type - body.basic_blocks_mut()[START_BLOCK].statements.insert( - 0, - Statement { - source_info, - kind: StatementKind::Retag(RetagKind::Raw, Box::new(Place::from(SELF_ARG))), - }, - ) - } - - // Make sure we remove dead blocks to remove - // unrelated code from the resume part of the function - simplify::remove_dead_blocks(tcx, &mut body); - - dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(())); - - body -} - -fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock { - let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { source_info, kind }), - is_cleanup: false, - }) -} - -fn insert_panic_block<'tcx>( - tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, - message: AssertMessage<'tcx>, -) -> BasicBlock { - let assert_block = BasicBlock::new(body.basic_blocks().len()); - let term = TerminatorKind::Assert { - cond: Operand::Constant(Box::new(Constant { - span: body.span, - user_ty: None, - literal: ty::Const::from_bool(tcx, false).into(), - })), - expected: true, - msg: message, - target: assert_block, - cleanup: None, - }; - - let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { source_info, kind: term }), - is_cleanup: false, - }); - - assert_block -} - -fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - // Returning from a function with an uninhabited return type is undefined behavior. - if tcx.conservative_is_privately_uninhabited(param_env.and(body.return_ty())) { - return false; - } - - // If there's a return terminator the function may return. - for block in body.basic_blocks() { - if let TerminatorKind::Return = block.terminator().kind { - return true; - } - } - - // Otherwise the function can't return. - false -} - -fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { - // Nothing can unwind when landing pads are off. - if tcx.sess.panic_strategy() == PanicStrategy::Abort { - return false; - } - - // Unwinds can only start at certain terminators. - for block in body.basic_blocks() { - match block.terminator().kind { - // These never unwind. - TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::GeneratorDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => {} - - // Resume will *continue* unwinding, but if there's no other unwinding terminator it - // will never be reached. - TerminatorKind::Resume => {} - - TerminatorKind::Yield { .. } => { - unreachable!("`can_unwind` called before generator transform") - } - - // These may unwind. - TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::Assert { .. } => return true, - } - } - - // If we didn't find an unwinding terminator, the function cannot unwind. - false -} - -fn create_generator_resume_function<'tcx>( - tcx: TyCtxt<'tcx>, - transform: TransformVisitor<'tcx>, - body: &mut Body<'tcx>, - can_return: bool, -) { - let can_unwind = can_unwind(tcx, body); - - // Poison the generator when it unwinds - if can_unwind { - let source_info = SourceInfo::outermost(body.span); - let poison_block = body.basic_blocks_mut().push(BasicBlockData { - statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }), - is_cleanup: true, - }); - - for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() { - let source_info = block.terminator().source_info; - - if let TerminatorKind::Resume = block.terminator().kind { - // An existing `Resume` terminator is redirected to jump to our dedicated - // "poisoning block" above. - if idx != poison_block { - *block.terminator_mut() = Terminator { - source_info, - kind: TerminatorKind::Goto { target: poison_block }, - }; - } - } else if !block.is_cleanup { - // Any terminators that *can* unwind but don't have an unwind target set are also - // pointed at our poisoning block (unless they're part of the cleanup path). - if let Some(unwind @ None) = block.terminator_mut().unwind_mut() { - *unwind = Some(poison_block); - } - } - } - } - - let mut cases = create_cases(body, &transform, Operation::Resume); - - use rustc_middle::mir::AssertKind::{ResumedAfterPanic, ResumedAfterReturn}; - - // Jump to the entry point on the unresumed - cases.insert(0, (UNRESUMED, BasicBlock::new(0))); - - // Panic when resumed on the returned or poisoned state - let generator_kind = body.generator_kind().unwrap(); - - if can_unwind { - cases.insert( - 1, - (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind))), - ); - } - - if can_return { - cases.insert( - 1, - (RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(generator_kind))), - ); - } - - insert_switch(body, cases, &transform, TerminatorKind::Unreachable); - - make_generator_state_argument_indirect(tcx, body); - make_generator_state_argument_pinned(tcx, body); - - // Make sure we remove dead blocks to remove - // unrelated code from the drop part of the function - simplify::remove_dead_blocks(tcx, body); - - dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(())); -} - -fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { - let return_block = insert_term_block(body, TerminatorKind::Return); - - let term = - TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None }; - let source_info = SourceInfo::outermost(body.span); - - // Create a block to destroy an unresumed generators. This can only destroy upvars. - body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { source_info, kind: term }), - is_cleanup: false, - }) -} - -/// An operation that can be performed on a generator. -#[derive(PartialEq, Copy, Clone)] -enum Operation { - Resume, - Drop, -} - -impl Operation { - fn target_block(self, point: &SuspensionPoint<'_>) -> Option { - match self { - Operation::Resume => Some(point.resume), - Operation::Drop => point.drop, - } - } -} - -fn create_cases<'tcx>( - body: &mut Body<'tcx>, - transform: &TransformVisitor<'tcx>, - operation: Operation, -) -> Vec<(usize, BasicBlock)> { - let source_info = SourceInfo::outermost(body.span); - - transform - .suspension_points - .iter() - .filter_map(|point| { - // Find the target for this suspension point, if applicable - operation.target_block(point).map(|target| { - let mut statements = Vec::new(); - - // Create StorageLive instructions for locals with live storage - for i in 0..(body.local_decls.len()) { - if i == 2 { - // The resume argument is live on function entry. Don't insert a - // `StorageLive`, or the following `Assign` will read from uninitialized - // memory. - continue; - } - - let l = Local::new(i); - let needs_storage_live = point.storage_liveness.contains(l) - && !transform.remap.contains_key(&l) - && !transform.always_live_locals.contains(l); - if needs_storage_live { - statements - .push(Statement { source_info, kind: StatementKind::StorageLive(l) }); - } - } - - if operation == Operation::Resume { - // Move the resume argument to the destination place of the `Yield` terminator - let resume_arg = Local::new(2); // 0 = return, 1 = self - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - point.resume_arg, - Rvalue::Use(Operand::Move(resume_arg.into())), - ))), - }); - } - - // Then jump to the real target - let block = body.basic_blocks_mut().push(BasicBlockData { - statements, - terminator: Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target }, - }), - is_cleanup: false, - }); - - (point.state, block) - }) - }) - .collect() -} - -impl<'tcx> MirPass<'tcx> for StateTransform { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let yield_ty = if let Some(yield_ty) = body.yield_ty() { - yield_ty - } else { - // This only applies to generators - return; - }; - - assert!(body.generator_drop().is_none()); - - // The first argument is the generator type passed by value - let gen_ty = body.local_decls.raw[1].ty; - - // Get the interior types and substs which typeck computed - let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() { - ty::Generator(_, substs, movability) => { - let substs = substs.as_generator(); - ( - substs.upvar_tys().collect(), - substs.witness(), - substs.discr_ty(tcx), - movability == hir::Movability::Movable, - ) - } - _ => { - tcx.sess - .delay_span_bug(body.span, &format!("unexpected generator type {}", gen_ty)); - return; - } - }; - - // Compute GeneratorState - let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]); - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); - - // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local - // RETURN_PLACE then is a fresh unused local with type ret_ty. - let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx); - - // We also replace the resume argument and insert an `Assign`. - // This is needed because the resume argument `_2` might be live across a `yield`, in which - // case there is no `Assign` to it that the transform can turn into a store to the generator - // state. After the yield the slot in the generator state would then be uninitialized. - let resume_local = Local::new(2); - let new_resume_local = - replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx); - - // When first entering the generator, move the resume argument into its new local. - let source_info = SourceInfo::outermost(body.span); - let stmts = &mut body.basic_blocks_mut()[BasicBlock::new(0)].statements; - stmts.insert( - 0, - Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - new_resume_local.into(), - Rvalue::Use(Operand::Move(resume_local.into())), - ))), - }, - ); - - let always_live_locals = storage::AlwaysLiveLocals::new(&body); - - let liveness_info = - locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); - - sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals); - - if tcx.sess.opts.debugging_opts.validate_mir { - let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias { - assigned_local: None, - saved_locals: &liveness_info.saved_locals, - storage_conflicts: &liveness_info.storage_conflicts, - }; - - vis.visit_body(body); - } - - // Extract locals which are live across suspension point into `layout` - // `remap` gives a mapping from local indices onto generator struct indices - // `storage_liveness` tells us which locals have live storage at suspension points - let (remap, layout, storage_liveness) = compute_layout(liveness_info, body); - - let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id())); - - // Run the transformation which converts Places from Local to generator struct - // accesses for locals in `remap`. - // It also rewrites `return x` and `yield y` as writing a new generator state and returning - // GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively. - let mut transform = TransformVisitor { - tcx, - state_adt_ref, - state_substs, - remap, - storage_liveness, - always_live_locals, - suspension_points: Vec::new(), - new_ret_local, - discr_ty, - }; - transform.visit_body(body); - - // Update our MIR struct to reflect the changes we've made - body.arg_count = 2; // self, resume arg - body.spread_arg = None; - - body.generator.as_mut().unwrap().yield_ty = None; - body.generator.as_mut().unwrap().generator_layout = Some(layout); - - // Insert `drop(generator_struct)` which is used to drop upvars for generators in - // the unresumed state. - // This is expanded to a drop ladder in `elaborate_generator_drops`. - let drop_clean = insert_clean_drop(body); - - dump_mir(tcx, None, "generator_pre-elab", &0, body, |_, _| Ok(())); - - // Expand `drop(generator_struct)` to a drop ladder which destroys upvars. - // If any upvars are moved out of, drop elaboration will handle upvar destruction. - // However we need to also elaborate the code generated by `insert_clean_drop`. - elaborate_generator_drops(tcx, body); - - dump_mir(tcx, None, "generator_post-transform", &0, body, |_, _| Ok(())); - - // Create a copy of our MIR and use it to create the drop shim for the generator - let drop_shim = create_generator_drop_shim(tcx, &transform, gen_ty, body, drop_clean); - - body.generator.as_mut().unwrap().generator_drop = Some(drop_shim); - - // Create the Generator::resume function - create_generator_resume_function(tcx, transform, body, can_return); - } -} - -/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields -/// in the generator state machine but whose storage is not marked as conflicting -/// -/// Validation needs to happen immediately *before* `TransformVisitor` is invoked, not after. -/// -/// This condition would arise when the assignment is the last use of `_5` but the initial -/// definition of `_4` if we weren't extra careful to mark all locals used inside a statement as -/// conflicting. Non-conflicting generator saved locals may be stored at the same location within -/// the generator state machine, which would result in ill-formed MIR: the left-hand and right-hand -/// sides of an assignment may not alias. This caused a miscompilation in [#73137]. -/// -/// [#73137]: https://github.com/rust-lang/rust/issues/73137 -struct EnsureGeneratorFieldAssignmentsNeverAlias<'a> { - saved_locals: &'a GeneratorSavedLocals, - storage_conflicts: &'a BitMatrix, - assigned_local: Option, -} - -impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> { - fn saved_local_for_direct_place(&self, place: Place<'_>) -> Option { - if place.is_indirect() { - return None; - } - - self.saved_locals.get(place.local) - } - - fn check_assigned_place(&mut self, place: Place<'tcx>, f: impl FnOnce(&mut Self)) { - if let Some(assigned_local) = self.saved_local_for_direct_place(place) { - assert!(self.assigned_local.is_none(), "`check_assigned_place` must not recurse"); - - self.assigned_local = Some(assigned_local); - f(self); - self.assigned_local = None; - } - } -} - -impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - let lhs = match self.assigned_local { - Some(l) => l, - None => { - // This visitor only invokes `visit_place` for the right-hand side of an assignment - // and only after setting `self.assigned_local`. However, the default impl of - // `Visitor::super_body` may call `visit_place` with a `NonUseContext` for places - // with debuginfo. Ignore them here. - assert!(!context.is_use()); - return; - } - }; - - let rhs = match self.saved_local_for_direct_place(*place) { - Some(l) => l, - None => return, - }; - - if !self.storage_conflicts.contains(lhs, rhs) { - bug!( - "Assignment between generator saved locals whose storage is not \ - marked as conflicting: {:?}: {:?} = {:?}", - location, - lhs, - rhs, - ); - } - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - match &statement.kind { - StatementKind::Assign(box (lhs, rhs)) => { - self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location)); - } - - // FIXME: Does `llvm_asm!` have any aliasing requirements? - StatementKind::LlvmInlineAsm(_) => {} - - StatementKind::FakeRead(..) - | StatementKind::SetDiscriminant { .. } - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Nop => {} - } - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - // Checking for aliasing in terminators is probably overkill, but until we have actual - // semantics, we should be conservative here. - match &terminator.kind { - TerminatorKind::Call { - func, - args, - destination: Some((dest, _)), - cleanup: _, - from_hir_call: _, - fn_span: _, - } => { - self.check_assigned_place(*dest, |this| { - this.visit_operand(func, location); - for arg in args { - this.visit_operand(arg, location); - } - }); - } - - TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { - self.check_assigned_place(*resume_arg, |this| this.visit_operand(value, location)); - } - - // FIXME: Does `asm!` have any aliasing requirements? - TerminatorKind::InlineAsm { .. } => {} - - TerminatorKind::Call { .. } - | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => {} - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/inline/cycle.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/inline/cycle.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/inline/cycle.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/inline/cycle.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sso::SsoHashSet; -use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::mir::TerminatorKind; -use rustc_middle::ty::TypeFoldable; -use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt}; -use rustc_session::Limit; - -// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking -// this query riddiculously often. -#[instrument(level = "debug", skip(tcx, root, target))] -crate fn mir_callgraph_reachable( - tcx: TyCtxt<'tcx>, - (root, target): (ty::Instance<'tcx>, LocalDefId), -) -> bool { - trace!(%root, target = %tcx.def_path_str(target.to_def_id())); - let param_env = tcx.param_env_reveal_all_normalized(target); - assert_ne!( - root.def_id().expect_local(), - target, - "you should not call `mir_callgraph_reachable` on immediate self recursion" - ); - assert!( - matches!(root.def, InstanceDef::Item(_)), - "you should not call `mir_callgraph_reachable` on shims" - ); - assert!( - !tcx.is_constructor(root.def_id()), - "you should not call `mir_callgraph_reachable` on enum/struct constructor functions" - ); - #[instrument( - level = "debug", - skip(tcx, param_env, target, stack, seen, recursion_limiter, caller, recursion_limit) - )] - fn process( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - caller: ty::Instance<'tcx>, - target: LocalDefId, - stack: &mut Vec>, - seen: &mut FxHashSet>, - recursion_limiter: &mut FxHashMap, - recursion_limit: Limit, - ) -> bool { - trace!(%caller); - for &(callee, substs) in tcx.mir_inliner_callees(caller.def) { - let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs); - let callee = match ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() { - Some(callee) => callee, - None => { - trace!(?callee, "cannot resolve, skipping"); - continue; - } - }; - - // Found a path. - if callee.def_id() == target.to_def_id() { - return true; - } - - if tcx.is_constructor(callee.def_id()) { - trace!("constructors always have MIR"); - // Constructor functions cannot cause a query cycle. - continue; - } - - match callee.def { - InstanceDef::Item(_) => { - // If there is no MIR available (either because it was not in metadata or - // because it has no MIR because it's an extern function), then the inliner - // won't cause cycles on this. - if !tcx.is_mir_available(callee.def_id()) { - trace!(?callee, "no mir available, skipping"); - continue; - } - } - // These have no own callable MIR. - InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue, - // These have MIR and if that MIR is inlined, substituted and then inlining is run - // again, a function item can end up getting inlined. Thus we'll be able to cause - // a cycle that way - InstanceDef::VtableShim(_) - | InstanceDef::ReifyShim(_) - | InstanceDef::FnPtrShim(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::CloneShim(..) => {} - InstanceDef::DropGlue(..) => { - // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to - // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this - // needs some more analysis. - if callee.definitely_needs_subst(tcx) { - continue; - } - } - } - - if seen.insert(callee) { - let recursion = recursion_limiter.entry(callee.def_id()).or_default(); - trace!(?callee, recursion = *recursion); - if recursion_limit.value_within_limit(*recursion) { - *recursion += 1; - stack.push(callee); - let found_recursion = ensure_sufficient_stack(|| { - process( - tcx, - param_env, - callee, - target, - stack, - seen, - recursion_limiter, - recursion_limit, - ) - }); - if found_recursion { - return true; - } - stack.pop(); - } else { - // Pessimistically assume that there could be recursion. - return true; - } - } - } - false - } - process( - tcx, - param_env, - root, - target, - &mut Vec::new(), - &mut FxHashSet::default(), - &mut FxHashMap::default(), - tcx.recursion_limit(), - ) -} - -crate fn mir_inliner_callees<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, -) -> &'tcx [(DefId, SubstsRef<'tcx>)] { - let steal; - let guard; - let body = match (instance, instance.def_id().as_local()) { - (InstanceDef::Item(_), Some(def_id)) => { - let def = ty::WithOptConstParam::unknown(def_id); - steal = tcx.mir_promoted(def).0; - guard = steal.borrow(); - &*guard - } - // Functions from other crates and MIR shims - _ => tcx.instance_mir(instance), - }; - let mut calls = SsoHashSet::new(); - for bb_data in body.basic_blocks() { - let terminator = bb_data.terminator(); - if let TerminatorKind::Call { func, .. } = &terminator.kind { - let ty = func.ty(&body.local_decls, tcx); - let call = match ty.kind() { - ty::FnDef(def_id, substs) => (*def_id, *substs), - _ => continue, - }; - calls.insert(call); - } - } - tcx.arena.alloc_from_iter(calls.iter().copied()) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/inline.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/inline.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/inline.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/inline.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,966 +0,0 @@ -//! Inlining pass for MIR functions - -use rustc_attr::InlineAttr; -use rustc_hir as hir; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::Idx; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; -use rustc_middle::mir::visit::*; -use rustc_middle::mir::*; -use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; -use rustc_span::{hygiene::ExpnKind, ExpnData, Span}; -use rustc_target::spec::abi::Abi; - -use super::simplify::{remove_dead_blocks, CfgSimplifier}; -use crate::transform::MirPass; -use std::iter; -use std::ops::{Range, RangeFrom}; - -crate mod cycle; - -const INSTR_COST: usize = 5; -const CALL_PENALTY: usize = 25; -const LANDINGPAD_PENALTY: usize = 50; -const RESUME_PENALTY: usize = 45; - -const UNKNOWN_SIZE_COST: usize = 10; - -pub struct Inline; - -#[derive(Copy, Clone, Debug)] -struct CallSite<'tcx> { - callee: Instance<'tcx>, - fn_sig: ty::PolyFnSig<'tcx>, - block: BasicBlock, - target: Option, - source_info: SourceInfo, -} - -/// Returns true if MIR inlining is enabled in the current compilation session. -crate fn is_enabled(tcx: TyCtxt<'_>) -> bool { - if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir { - return enabled; - } - - tcx.sess.mir_opt_level() >= 3 -} - -impl<'tcx> MirPass<'tcx> for Inline { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if !is_enabled(tcx) { - return; - } - - let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id())); - let _guard = span.enter(); - if inline(tcx, body) { - debug!("running simplify cfg on {:?}", body.source); - CfgSimplifier::new(body).simplify(); - remove_dead_blocks(tcx, body); - } - } -} - -fn inline(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { - let def_id = body.source.def_id(); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - - // Only do inlining into fn bodies. - if !tcx.hir().body_owner_kind(hir_id).is_fn_or_closure() { - return false; - } - if body.source.promoted.is_some() { - return false; - } - - let mut this = Inliner { - tcx, - param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()), - codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()), - hir_id, - history: Vec::new(), - changed: false, - }; - let blocks = BasicBlock::new(0)..body.basic_blocks().next_index(); - this.process_blocks(body, blocks); - this.changed -} - -struct Inliner<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - /// Caller codegen attributes. - codegen_fn_attrs: &'tcx CodegenFnAttrs, - /// Caller HirID. - hir_id: hir::HirId, - /// Stack of inlined Instances. - history: Vec>, - /// Indicates that the caller body has been modified. - changed: bool, -} - -impl Inliner<'tcx> { - fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range) { - for bb in blocks { - let bb_data = &caller_body[bb]; - if bb_data.is_cleanup { - continue; - } - - let callsite = match self.resolve_callsite(caller_body, bb, bb_data) { - None => continue, - Some(it) => it, - }; - - let span = trace_span!("process_blocks", %callsite.callee, ?bb); - let _guard = span.enter(); - - match self.try_inlining(caller_body, &callsite) { - Err(reason) => { - debug!("not-inlined {} [{}]", callsite.callee, reason); - continue; - } - Ok(new_blocks) => { - debug!("inlined {}", callsite.callee); - self.changed = true; - self.history.push(callsite.callee); - self.process_blocks(caller_body, new_blocks); - self.history.pop(); - } - } - } - } - - /// Attempts to inline a callsite into the caller body. When successful returns basic blocks - /// containing the inlined body. Otherwise returns an error describing why inlining didn't take - /// place. - fn try_inlining( - &self, - caller_body: &mut Body<'tcx>, - callsite: &CallSite<'tcx>, - ) -> Result, &'static str> { - let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); - self.check_codegen_attributes(callsite, callee_attrs)?; - self.check_mir_is_available(caller_body, &callsite.callee)?; - let callee_body = self.tcx.instance_mir(callsite.callee.def); - self.check_mir_body(callsite, callee_body, callee_attrs)?; - - if !self.tcx.consider_optimizing(|| { - format!("Inline {:?} into {}", callee_body.span, callsite.callee) - }) { - return Err("optimization fuel exhausted"); - } - - let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions( - self.tcx, - self.param_env, - callee_body.clone(), - ); - - let old_blocks = caller_body.basic_blocks().next_index(); - self.inline_call(caller_body, &callsite, callee_body); - let new_blocks = old_blocks..caller_body.basic_blocks().next_index(); - - Ok(new_blocks) - } - - fn check_mir_is_available( - &self, - caller_body: &Body<'tcx>, - callee: &Instance<'tcx>, - ) -> Result<(), &'static str> { - if callee.def_id() == caller_body.source.def_id() { - return Err("self-recursion"); - } - - match callee.def { - InstanceDef::Item(_) => { - // If there is no MIR available (either because it was not in metadata or - // because it has no MIR because it's an extern function), then the inliner - // won't cause cycles on this. - if !self.tcx.is_mir_available(callee.def_id()) { - return Err("item MIR unavailable"); - } - } - // These have no own callable MIR. - InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => { - return Err("instance without MIR (intrinsic / virtual)"); - } - // This cannot result in an immediate cycle since the callee MIR is a shim, which does - // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we - // do not need to catch this here, we can wait until the inliner decides to continue - // inlining a second time. - InstanceDef::VtableShim(_) - | InstanceDef::ReifyShim(_) - | InstanceDef::FnPtrShim(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) => return Ok(()), - } - - if self.tcx.is_constructor(callee.def_id()) { - trace!("constructors always have MIR"); - // Constructor functions cannot cause a query cycle. - return Ok(()); - } - - if let Some(callee_def_id) = callee.def_id().as_local() { - let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id); - // Avoid inlining into generators, - // since their `optimized_mir` is used for layout computation, which can - // create a cycle, even when no attempt is made to inline the function - // in the other direction. - if caller_body.generator.is_some() { - return Err("local generator (query cycle avoidance)"); - } - - // Avoid a cycle here by only using `instance_mir` only if we have - // a lower `HirId` than the callee. This ensures that the callee will - // not inline us. This trick only works without incremental compilation. - // So don't do it if that is enabled. - if !self.tcx.dep_graph.is_fully_enabled() && self.hir_id < callee_hir_id { - return Ok(()); - } - - // If we know for sure that the function we're calling will itself try to - // call us, then we avoid inlining that function. - if self - .tcx - .mir_callgraph_reachable((*callee, caller_body.source.def_id().expect_local())) - { - return Err("caller might be reachable from callee (query cycle avoidance)"); - } - - Ok(()) - } else { - // This cannot result in an immediate cycle since the callee MIR is from another crate - // and is already optimized. Any subsequent inlining may cause cycles, but we do - // not need to catch this here, we can wait until the inliner decides to continue - // inlining a second time. - trace!("functions from other crates always have MIR"); - Ok(()) - } - } - - fn resolve_callsite( - &self, - caller_body: &Body<'tcx>, - bb: BasicBlock, - bb_data: &BasicBlockData<'tcx>, - ) -> Option> { - // Only consider direct calls to functions - let terminator = bb_data.terminator(); - if let TerminatorKind::Call { ref func, ref destination, .. } = terminator.kind { - let func_ty = func.ty(caller_body, self.tcx); - if let ty::FnDef(def_id, substs) = *func_ty.kind() { - // To resolve an instance its substs have to be fully normalized. - let substs = self.tcx.normalize_erasing_regions(self.param_env, substs); - let callee = - Instance::resolve(self.tcx, self.param_env, def_id, substs).ok().flatten()?; - - if let InstanceDef::Virtual(..) | InstanceDef::Intrinsic(_) = callee.def { - return None; - } - - let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); - - return Some(CallSite { - callee, - fn_sig, - block: bb, - target: destination.map(|(_, target)| target), - source_info: terminator.source_info, - }); - } - } - - None - } - - /// Returns an error if inlining is not possible based on codegen attributes alone. A success - /// indicates that inlining decision should be based on other criteria. - fn check_codegen_attributes( - &self, - callsite: &CallSite<'tcx>, - callee_attrs: &CodegenFnAttrs, - ) -> Result<(), &'static str> { - if let InlineAttr::Never = callee_attrs.inline { - return Err("never inline hint"); - } - - // Only inline local functions if they would be eligible for cross-crate - // inlining. This is to ensure that the final crate doesn't have MIR that - // reference unexported symbols - if callsite.callee.def_id().is_local() { - let is_generic = callsite.callee.substs.non_erasable_generics().next().is_some(); - if !is_generic && !callee_attrs.requests_inline() { - return Err("not exported"); - } - } - - if callsite.fn_sig.c_variadic() { - return Err("C variadic"); - } - - if callee_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - return Err("naked"); - } - - if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) { - return Err("cold"); - } - - if callee_attrs.no_sanitize != self.codegen_fn_attrs.no_sanitize { - return Err("incompatible sanitizer set"); - } - - if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set { - return Err("incompatible instruction set"); - } - - for feature in &callee_attrs.target_features { - if !self.codegen_fn_attrs.target_features.contains(feature) { - return Err("incompatible target feature"); - } - } - - Ok(()) - } - - /// Returns inlining decision that is based on the examination of callee MIR body. - /// Assumes that codegen attributes have been checked for compatibility already. - #[instrument(level = "debug", skip(self, callee_body))] - fn check_mir_body( - &self, - callsite: &CallSite<'tcx>, - callee_body: &Body<'tcx>, - callee_attrs: &CodegenFnAttrs, - ) -> Result<(), &'static str> { - let tcx = self.tcx; - - let mut threshold = if callee_attrs.requests_inline() { - self.tcx.sess.opts.debugging_opts.inline_mir_hint_threshold.unwrap_or(100) - } else { - self.tcx.sess.opts.debugging_opts.inline_mir_threshold.unwrap_or(50) - }; - - // Give a bonus functions with a small number of blocks, - // We normally have two or three blocks for even - // very small functions. - if callee_body.basic_blocks().len() <= 3 { - threshold += threshold / 4; - } - debug!(" final inline threshold = {}", threshold); - - // FIXME: Give a bonus to functions with only a single caller - let mut first_block = true; - let mut cost = 0; - - // Traverse the MIR manually so we can account for the effects of - // inlining on the CFG. - let mut work_list = vec![START_BLOCK]; - let mut visited = BitSet::new_empty(callee_body.basic_blocks().len()); - while let Some(bb) = work_list.pop() { - if !visited.insert(bb.index()) { - continue; - } - let blk = &callee_body.basic_blocks()[bb]; - - for stmt in &blk.statements { - // Don't count StorageLive/StorageDead in the inlining cost. - match stmt.kind { - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Nop => {} - _ => cost += INSTR_COST, - } - } - let term = blk.terminator(); - let mut is_drop = false; - match term.kind { - TerminatorKind::Drop { ref place, target, unwind } - | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } => { - is_drop = true; - work_list.push(target); - // If the place doesn't actually need dropping, treat it like - // a regular goto. - let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty); - if ty.needs_drop(tcx, self.param_env) { - cost += CALL_PENALTY; - if let Some(unwind) = unwind { - cost += LANDINGPAD_PENALTY; - work_list.push(unwind); - } - } else { - cost += INSTR_COST; - } - } - - TerminatorKind::Unreachable | TerminatorKind::Call { destination: None, .. } - if first_block => - { - // If the function always diverges, don't inline - // unless the cost is zero - threshold = 0; - } - - TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { - if let ty::FnDef(def_id, substs) = - *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind() - { - let substs = self.tcx.normalize_erasing_regions(self.param_env, substs); - if let Ok(Some(instance)) = - Instance::resolve(self.tcx, self.param_env, def_id, substs) - { - if callsite.callee.def_id() == instance.def_id() { - return Err("self-recursion"); - } else if self.history.contains(&instance) { - return Err("already inlined"); - } - } - // Don't give intrinsics the extra penalty for calls - let f = tcx.fn_sig(def_id); - if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { - cost += INSTR_COST; - } else { - cost += CALL_PENALTY; - } - } else { - cost += CALL_PENALTY; - } - if cleanup.is_some() { - cost += LANDINGPAD_PENALTY; - } - } - TerminatorKind::Assert { cleanup, .. } => { - cost += CALL_PENALTY; - - if cleanup.is_some() { - cost += LANDINGPAD_PENALTY; - } - } - TerminatorKind::Resume => cost += RESUME_PENALTY, - _ => cost += INSTR_COST, - } - - if !is_drop { - for &succ in term.successors() { - work_list.push(succ); - } - } - - first_block = false; - } - - // Count up the cost of local variables and temps, if we know the size - // use that, otherwise we use a moderately-large dummy cost. - - let ptr_size = tcx.data_layout.pointer_size.bytes(); - - for v in callee_body.vars_and_temps_iter() { - let ty = callsite.callee.subst_mir(self.tcx, &callee_body.local_decls[v].ty); - // Cost of the var is the size in machine-words, if we know - // it. - if let Some(size) = type_size_of(tcx, self.param_env, ty) { - cost += ((size + ptr_size - 1) / ptr_size) as usize; - } else { - cost += UNKNOWN_SIZE_COST; - } - } - - if let InlineAttr::Always = callee_attrs.inline { - debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost); - Ok(()) - } else { - if cost <= threshold { - debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold); - Ok(()) - } else { - debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold); - Err("cost above threshold") - } - } - } - - fn inline_call( - &self, - caller_body: &mut Body<'tcx>, - callsite: &CallSite<'tcx>, - mut callee_body: Body<'tcx>, - ) { - let terminator = caller_body[callsite.block].terminator.take().unwrap(); - match terminator.kind { - TerminatorKind::Call { args, destination, cleanup, .. } => { - // If the call is something like `a[*i] = f(i)`, where - // `i : &mut usize`, then just duplicating the `a[*i]` - // Place could result in two different locations if `f` - // writes to `i`. To prevent this we need to create a temporary - // borrow of the place and pass the destination as `*temp` instead. - fn dest_needs_borrow(place: Place<'_>) -> bool { - for elem in place.projection.iter() { - match elem { - ProjectionElem::Deref | ProjectionElem::Index(_) => return true, - _ => {} - } - } - - false - } - - let dest = if let Some((destination_place, _)) = destination { - if dest_needs_borrow(destination_place) { - trace!("creating temp for return destination"); - let dest = Rvalue::Ref( - self.tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, - destination_place, - ); - let dest_ty = dest.ty(caller_body, self.tcx); - let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty)); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((temp, dest))), - }); - self.tcx.mk_place_deref(temp) - } else { - destination_place - } - } else { - trace!("creating temp for return place"); - Place::from(self.new_call_temp(caller_body, &callsite, callee_body.return_ty())) - }; - - // Copy the arguments if needed. - let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body); - - let mut integrator = Integrator { - args: &args, - new_locals: Local::new(caller_body.local_decls.len()).., - new_scopes: SourceScope::new(caller_body.source_scopes.len()).., - new_blocks: BasicBlock::new(caller_body.basic_blocks().len()).., - destination: dest, - return_block: callsite.target, - cleanup_block: cleanup, - in_cleanup_block: false, - tcx: self.tcx, - callsite_span: callsite.source_info.span, - body_span: callee_body.span, - always_live_locals: BitSet::new_filled(callee_body.local_decls.len()), - }; - - // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones - // (or existing ones, in a few special cases) in the caller. - integrator.visit_body(&mut callee_body); - - for scope in &mut callee_body.source_scopes { - // FIXME(eddyb) move this into a `fn visit_scope_data` in `Integrator`. - if scope.parent_scope.is_none() { - let callsite_scope = &caller_body.source_scopes[callsite.source_info.scope]; - - // Attach the outermost callee scope as a child of the callsite - // scope, via the `parent_scope` and `inlined_parent_scope` chains. - scope.parent_scope = Some(callsite.source_info.scope); - assert_eq!(scope.inlined_parent_scope, None); - scope.inlined_parent_scope = if callsite_scope.inlined.is_some() { - Some(callsite.source_info.scope) - } else { - callsite_scope.inlined_parent_scope - }; - - // Mark the outermost callee scope as an inlined one. - assert_eq!(scope.inlined, None); - scope.inlined = Some((callsite.callee, callsite.source_info.span)); - } else if scope.inlined_parent_scope.is_none() { - // Make it easy to find the scope with `inlined` set above. - scope.inlined_parent_scope = - Some(integrator.map_scope(OUTERMOST_SOURCE_SCOPE)); - } - } - - // If there are any locals without storage markers, give them storage only for the - // duration of the call. - for local in callee_body.vars_and_temps_iter() { - if integrator.always_live_locals.contains(local) { - let new_local = integrator.map_local(local); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageLive(new_local), - }); - } - } - if let Some(block) = callsite.target { - // To avoid repeated O(n) insert, push any new statements to the end and rotate - // the slice once. - let mut n = 0; - for local in callee_body.vars_and_temps_iter().rev() { - if integrator.always_live_locals.contains(local) { - let new_local = integrator.map_local(local); - caller_body[block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageDead(new_local), - }); - n += 1; - } - } - caller_body[block].statements.rotate_right(n); - } - - // Insert all of the (mapped) parts of the callee body into the caller. - caller_body.local_decls.extend(callee_body.drain_vars_and_temps()); - caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..)); - caller_body.var_debug_info.append(&mut callee_body.var_debug_info); - caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..)); - - caller_body[callsite.block].terminator = Some(Terminator { - source_info: callsite.source_info, - kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) }, - }); - - // Copy only unevaluated constants from the callee_body into the caller_body. - // Although we are only pushing `ConstKind::Unevaluated` consts to - // `required_consts`, here we may not only have `ConstKind::Unevaluated` - // because we are calling `subst_and_normalize_erasing_regions`. - caller_body.required_consts.extend( - callee_body.required_consts.iter().copied().filter(|&ct| { - match ct.literal.const_for_ty() { - Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_)), - None => true, - } - }), - ); - } - kind => bug!("unexpected terminator kind {:?}", kind), - } - } - - fn make_call_args( - &self, - args: Vec>, - callsite: &CallSite<'tcx>, - caller_body: &mut Body<'tcx>, - callee_body: &Body<'tcx>, - ) -> Vec { - let tcx = self.tcx; - - // There is a bit of a mismatch between the *caller* of a closure and the *callee*. - // The caller provides the arguments wrapped up in a tuple: - // - // tuple_tmp = (a, b, c) - // Fn::call(closure_ref, tuple_tmp) - // - // meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`) - // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, codegen has - // the job of unpacking this tuple. But here, we are codegen. =) So we want to create - // a vector like - // - // [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2] - // - // Except for one tiny wrinkle: we don't actually want `tuple_tmp.0`. It's more convenient - // if we "spill" that into *another* temporary, so that we can map the argument - // variable in the callee MIR directly to an argument variable on our side. - // So we introduce temporaries like: - // - // tmp0 = tuple_tmp.0 - // tmp1 = tuple_tmp.1 - // tmp2 = tuple_tmp.2 - // - // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. - if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() { - let mut args = args.into_iter(); - let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); - let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); - assert!(args.next().is_none()); - - let tuple = Place::from(tuple); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind() { - s - } else { - bug!("Closure arguments are not passed as a tuple"); - }; - - // The `closure_ref` in our example above. - let closure_ref_arg = iter::once(self_); - - // The `tmp0`, `tmp1`, and `tmp2` in our example abonve. - let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| { - // This is e.g., `tuple_tmp.0` in our example above. - let tuple_field = - Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty())); - - // Spill to a local to make e.g., `tmp0`. - self.create_temp_if_necessary(tuple_field, callsite, caller_body) - }); - - closure_ref_arg.chain(tuple_tmp_args).collect() - } else { - args.into_iter() - .map(|a| self.create_temp_if_necessary(a, callsite, caller_body)) - .collect() - } - } - - /// If `arg` is already a temporary, returns it. Otherwise, introduces a fresh - /// temporary `T` and an instruction `T = arg`, and returns `T`. - fn create_temp_if_necessary( - &self, - arg: Operand<'tcx>, - callsite: &CallSite<'tcx>, - caller_body: &mut Body<'tcx>, - ) -> Local { - // Reuse the operand if it is a moved temporary. - if let Operand::Move(place) = &arg { - if let Some(local) = place.as_local() { - if caller_body.local_kind(local) == LocalKind::Temp { - return local; - } - } - } - - // Otherwise, create a temporary for the argument. - trace!("creating temp for argument {:?}", arg); - let arg_ty = arg.ty(caller_body, self.tcx); - let local = self.new_call_temp(caller_body, callsite, arg_ty); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))), - }); - local - } - - /// Introduces a new temporary into the caller body that is live for the duration of the call. - fn new_call_temp( - &self, - caller_body: &mut Body<'tcx>, - callsite: &CallSite<'tcx>, - ty: Ty<'tcx>, - ) -> Local { - let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span)); - - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageLive(local), - }); - - if let Some(block) = callsite.target { - caller_body[block].statements.insert( - 0, - Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageDead(local), - }, - ); - } - - local - } -} - -fn type_size_of<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> Option { - tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) -} - -/** - * Integrator. - * - * Integrates blocks from the callee function into the calling function. - * Updates block indices, references to locals and other control flow - * stuff. -*/ -struct Integrator<'a, 'tcx> { - args: &'a [Local], - new_locals: RangeFrom, - new_scopes: RangeFrom, - new_blocks: RangeFrom, - destination: Place<'tcx>, - return_block: Option, - cleanup_block: Option, - in_cleanup_block: bool, - tcx: TyCtxt<'tcx>, - callsite_span: Span, - body_span: Span, - always_live_locals: BitSet, -} - -impl<'a, 'tcx> Integrator<'a, 'tcx> { - fn map_local(&self, local: Local) -> Local { - let new = if local == RETURN_PLACE { - self.destination.local - } else { - let idx = local.index() - 1; - if idx < self.args.len() { - self.args[idx] - } else { - Local::new(self.new_locals.start.index() + (idx - self.args.len())) - } - }; - trace!("mapping local `{:?}` to `{:?}`", local, new); - new - } - - fn map_scope(&self, scope: SourceScope) -> SourceScope { - let new = SourceScope::new(self.new_scopes.start.index() + scope.index()); - trace!("mapping scope `{:?}` to `{:?}`", scope, new); - new - } - - fn map_block(&self, block: BasicBlock) -> BasicBlock { - let new = BasicBlock::new(self.new_blocks.start.index() + block.index()); - trace!("mapping block `{:?}` to `{:?}`", block, new); - new - } -} - -impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, _ctxt: PlaceContext, _location: Location) { - *local = self.map_local(*local); - } - - fn visit_source_scope(&mut self, scope: &mut SourceScope) { - *scope = self.map_scope(*scope); - } - - fn visit_span(&mut self, span: &mut Span) { - let mut expn_data = - ExpnData::default(ExpnKind::Inlined, *span, self.tcx.sess.edition(), None, None); - expn_data.def_site = self.body_span; - // Make sure that all spans track the fact that they were inlined. - *span = - self.callsite_span.fresh_expansion(expn_data, self.tcx.create_stable_hashing_context()); - } - - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - for elem in place.projection { - // FIXME: Make sure that return place is not used in an indexing projection, since it - // won't be rebased as it is supposed to be. - assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem); - } - - // If this is the `RETURN_PLACE`, we need to rebase any projections onto it. - let dest_proj_len = self.destination.projection.len(); - if place.local == RETURN_PLACE && dest_proj_len > 0 { - let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len()); - projs.extend(self.destination.projection); - projs.extend(place.projection); - - place.projection = self.tcx.intern_place_elems(&*projs); - } - // Handles integrating any locals that occur in the base - // or projections - self.super_place(place, context, location) - } - - fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { - self.in_cleanup_block = data.is_cleanup; - self.super_basic_block_data(block, data); - self.in_cleanup_block = false; - } - - fn visit_retag(&mut self, kind: &mut RetagKind, place: &mut Place<'tcx>, loc: Location) { - self.super_retag(kind, place, loc); - - // We have to patch all inlined retags to be aware that they are no longer - // happening on function entry. - if *kind == RetagKind::FnEntry { - *kind = RetagKind::Default; - } - } - - fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { - if let StatementKind::StorageLive(local) | StatementKind::StorageDead(local) = - statement.kind - { - self.always_live_locals.remove(local); - } - self.super_statement(statement, location); - } - - fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) { - // Don't try to modify the implicit `_0` access on return (`return` terminators are - // replaced down below anyways). - if !matches!(terminator.kind, TerminatorKind::Return) { - self.super_terminator(terminator, loc); - } - - match terminator.kind { - TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => bug!(), - TerminatorKind::Goto { ref mut target } => { - *target = self.map_block(*target); - } - TerminatorKind::SwitchInt { ref mut targets, .. } => { - for tgt in targets.all_targets_mut() { - *tgt = self.map_block(*tgt); - } - } - TerminatorKind::Drop { ref mut target, ref mut unwind, .. } - | TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => { - *target = self.map_block(*target); - if let Some(tgt) = *unwind { - *unwind = Some(self.map_block(tgt)); - } else if !self.in_cleanup_block { - // Unless this drop is in a cleanup block, add an unwind edge to - // the original call's cleanup block - *unwind = self.cleanup_block; - } - } - TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => { - if let Some((_, ref mut tgt)) = *destination { - *tgt = self.map_block(*tgt); - } - if let Some(tgt) = *cleanup { - *cleanup = Some(self.map_block(tgt)); - } else if !self.in_cleanup_block { - // Unless this call is in a cleanup block, add an unwind edge to - // the original call's cleanup block - *cleanup = self.cleanup_block; - } - } - TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => { - *target = self.map_block(*target); - if let Some(tgt) = *cleanup { - *cleanup = Some(self.map_block(tgt)); - } else if !self.in_cleanup_block { - // Unless this assert is in a cleanup block, add an unwind edge to - // the original call's cleanup block - *cleanup = self.cleanup_block; - } - } - TerminatorKind::Return => { - terminator.kind = if let Some(tgt) = self.return_block { - TerminatorKind::Goto { target: tgt } - } else { - TerminatorKind::Unreachable - } - } - TerminatorKind::Resume => { - if let Some(tgt) = self.cleanup_block { - terminator.kind = TerminatorKind::Goto { target: tgt } - } - } - TerminatorKind::Abort => {} - TerminatorKind::Unreachable => {} - TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => { - *real_target = self.map_block(*real_target); - *imaginary_target = self.map_block(*imaginary_target); - } - TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => - // see the ordering of passes in the optimized_mir query. - { - bug!("False unwinds should have been removed before inlining") - } - TerminatorKind::InlineAsm { ref mut destination, .. } => { - if let Some(ref mut tgt) = *destination { - *tgt = self.map_block(*tgt); - } - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/instcombine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/instcombine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/instcombine.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/instcombine.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -//! Performs various peephole optimizations. - -use crate::transform::MirPass; -use rustc_hir::Mutability; -use rustc_middle::mir::{ - BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, - StatementKind, UnOp, -}; -use rustc_middle::ty::{self, TyCtxt}; - -pub struct InstCombine; - -impl<'tcx> MirPass<'tcx> for InstCombine { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - let ctx = InstCombineContext { tcx, local_decls }; - for block in basic_blocks.iter_mut() { - for statement in block.statements.iter_mut() { - match statement.kind { - StatementKind::Assign(box (_place, ref mut rvalue)) => { - ctx.combine_bool_cmp(&statement.source_info, rvalue); - ctx.combine_ref_deref(&statement.source_info, rvalue); - ctx.combine_len(&statement.source_info, rvalue); - } - _ => {} - } - } - } - } -} - -struct InstCombineContext<'tcx, 'a> { - tcx: TyCtxt<'tcx>, - local_decls: &'a LocalDecls<'tcx>, -} - -impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { - fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool { - self.tcx.consider_optimizing(|| { - format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info) - }) - } - - /// Transform boolean comparisons into logical operations. - fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { - match rvalue { - Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => { - let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) { - // Transform "Eq(a, true)" ==> "a" - (BinOp::Eq, _, Some(true)) => Some(Rvalue::Use(a.clone())), - - // Transform "Ne(a, false)" ==> "a" - (BinOp::Ne, _, Some(false)) => Some(Rvalue::Use(a.clone())), - - // Transform "Eq(true, b)" ==> "b" - (BinOp::Eq, Some(true), _) => Some(Rvalue::Use(b.clone())), - - // Transform "Ne(false, b)" ==> "b" - (BinOp::Ne, Some(false), _) => Some(Rvalue::Use(b.clone())), - - // Transform "Eq(false, b)" ==> "Not(b)" - (BinOp::Eq, Some(false), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())), - - // Transform "Ne(true, b)" ==> "Not(b)" - (BinOp::Ne, Some(true), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())), - - // Transform "Eq(a, false)" ==> "Not(a)" - (BinOp::Eq, _, Some(false)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())), - - // Transform "Ne(a, true)" ==> "Not(a)" - (BinOp::Ne, _, Some(true)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())), - - _ => None, - }; - - if let Some(new) = new { - if self.should_combine(source_info, rvalue) { - *rvalue = new; - } - } - } - - _ => {} - } - } - - fn try_eval_bool(&self, a: &Operand<'_>) -> Option { - let a = a.constant()?; - if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None } - } - - /// Transform "&(*a)" ==> "a". - fn combine_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { - if let Rvalue::Ref(_, _, place) = rvalue { - if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() { - if let ty::Ref(_, _, Mutability::Not) = - base.ty(self.local_decls, self.tcx).ty.kind() - { - // The dereferenced place must have type `&_`, so that we don't copy `&mut _`. - } else { - return; - } - - if !self.should_combine(source_info, rvalue) { - return; - } - - *rvalue = Rvalue::Use(Operand::Copy(Place { - local: base.local, - projection: self.tcx.intern_place_elems(base.projection), - })); - } - } - } - - /// Transform "Len([_; N])" ==> "N". - fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { - if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(self.local_decls, self.tcx).ty; - if let ty::Array(_, len) = *place_ty.kind() { - if !self.should_combine(source_info, rvalue) { - return; - } - - let constant = - Constant { span: source_info.span, literal: len.into(), user_ty: None }; - *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/lower_intrinsics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/lower_intrinsics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/lower_intrinsics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/lower_intrinsics.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -//! Lowers intrinsic calls - -use crate::transform::MirPass; -use rustc_middle::mir::*; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use rustc_target::spec::abi::Abi; - -pub struct LowerIntrinsics; - -impl<'tcx> MirPass<'tcx> for LowerIntrinsics { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks { - let terminator = block.terminator.as_mut().unwrap(); - if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind { - let func_ty = func.ty(local_decls, tcx); - let (intrinsic_name, substs) = match resolve_rust_intrinsic(tcx, func_ty) { - None => continue, - Some(it) => it, - }; - match intrinsic_name { - sym::unreachable => { - terminator.kind = TerminatorKind::Unreachable; - } - sym::forget => { - if let Some((destination, target)) = *destination { - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - destination, - Rvalue::Use(Operand::Constant(Box::new(Constant { - span: terminator.source_info.span, - user_ty: None, - literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(), - }))), - ))), - }); - terminator.kind = TerminatorKind::Goto { target }; - } - } - sym::copy_nonoverlapping => { - let target = destination.unwrap().1; - let mut args = args.drain(..); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::CopyNonOverlapping(Box::new( - rustc_middle::mir::CopyNonOverlapping { - src: args.next().unwrap(), - dst: args.next().unwrap(), - count: args.next().unwrap(), - }, - )), - }); - assert_eq!( - args.next(), - None, - "Extra argument for copy_non_overlapping intrinsic" - ); - drop(args); - terminator.kind = TerminatorKind::Goto { target }; - } - sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { - if let Some((destination, target)) = *destination { - let lhs; - let rhs; - { - let mut args = args.drain(..); - lhs = args.next().unwrap(); - rhs = args.next().unwrap(); - } - let bin_op = match intrinsic_name { - sym::wrapping_add => BinOp::Add, - sym::wrapping_sub => BinOp::Sub, - sym::wrapping_mul => BinOp::Mul, - _ => bug!("unexpected intrinsic"), - }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - destination, - Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))), - ))), - }); - terminator.kind = TerminatorKind::Goto { target }; - } - } - sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { - // The checked binary operations are not suitable target for lowering here, - // since their semantics depend on the value of overflow-checks flag used - // during codegen. Issue #35310. - } - sym::size_of => { - if let Some((destination, target)) = *destination { - let tp_ty = substs.type_at(0); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - destination, - Rvalue::NullaryOp(NullOp::SizeOf, tp_ty), - ))), - }); - terminator.kind = TerminatorKind::Goto { target }; - } - } - sym::discriminant_value => { - if let (Some((destination, target)), Some(arg)) = - (*destination, args[0].place()) - { - let arg = tcx.mk_place_deref(arg); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - destination, - Rvalue::Discriminant(arg), - ))), - }); - terminator.kind = TerminatorKind::Goto { target }; - } - } - _ if intrinsic_name.as_str().starts_with("simd_shuffle") => { - validate_simd_shuffle(tcx, args, terminator.source_info.span); - } - _ => {} - } - } - } - } -} - -fn resolve_rust_intrinsic( - tcx: TyCtxt<'tcx>, - func_ty: Ty<'tcx>, -) -> Option<(Symbol, SubstsRef<'tcx>)> { - if let ty::FnDef(def_id, substs) = *func_ty.kind() { - let fn_sig = func_ty.fn_sig(tcx); - if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() { - return Some((tcx.item_name(def_id), substs)); - } - } - None -} - -fn validate_simd_shuffle(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) { - match &args[2] { - Operand::Constant(_) => {} // all good - _ => { - let msg = "last argument of `simd_shuffle` is required to be a `const` item"; - tcx.sess.span_err(span, msg); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/lower_slice_len.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/lower_slice_len.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/lower_slice_len.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/lower_slice_len.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -//! This pass lowers calls to core::slice::len to just Len op. -//! It should run before inlining! - -use crate::transform::MirPass; -use rustc_hir::def_id::DefId; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; - -pub struct LowerSliceLenCalls; - -impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - lower_slice_len_calls(tcx, body) - } -} - -pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let language_items = tcx.lang_items(); - let slice_len_fn_item_def_id = if let Some(slice_len_fn_item) = language_items.slice_len_fn() { - slice_len_fn_item - } else { - // there is no language item to compare to :) - return; - }; - - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - - for block in basic_blocks { - // lower `<[_]>::len` calls - lower_slice_len_call(tcx, block, &*local_decls, slice_len_fn_item_def_id); - } -} - -struct SliceLenPatchInformation<'tcx> { - add_statement: Statement<'tcx>, - new_terminator_kind: TerminatorKind<'tcx>, -} - -fn lower_slice_len_call<'tcx>( - tcx: TyCtxt<'tcx>, - block: &mut BasicBlockData<'tcx>, - local_decls: &IndexVec>, - slice_len_fn_item_def_id: DefId, -) { - let mut patch_found: Option> = None; - - let terminator = block.terminator(); - match &terminator.kind { - TerminatorKind::Call { - func, - args, - destination: Some((dest, bb)), - cleanup: None, - from_hir_call: true, - .. - } => { - // some heuristics for fast rejection - if args.len() != 1 { - return; - } - let arg = match args[0].place() { - Some(arg) => arg, - None => return, - }; - let func_ty = func.ty(local_decls, tcx); - match func_ty.kind() { - ty::FnDef(fn_def_id, _) if fn_def_id == &slice_len_fn_item_def_id => { - // perform modifications - // from something like `_5 = core::slice::::len(move _6) -> bb1` - // into `_5 = Len(*_6) - // goto bb1 - - // make new RValue for Len - let deref_arg = tcx.mk_place_deref(arg); - let r_value = Rvalue::Len(deref_arg); - let len_statement_kind = StatementKind::Assign(Box::new((*dest, r_value))); - let add_statement = Statement { - kind: len_statement_kind, - source_info: terminator.source_info.clone(), - }; - - // modify terminator into simple Goto - let new_terminator_kind = TerminatorKind::Goto { target: bb.clone() }; - - let patch = SliceLenPatchInformation { add_statement, new_terminator_kind }; - - patch_found = Some(patch); - } - _ => {} - } - } - _ => {} - } - - if let Some(SliceLenPatchInformation { add_statement, new_terminator_kind }) = patch_found { - block.statements.push(add_statement); - block.terminator_mut().kind = new_terminator_kind; - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/match_branches.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/match_branches.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/match_branches.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/match_branches.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,176 +0,0 @@ -use crate::transform::MirPass; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; -use std::iter; - -use super::simplify::simplify_cfg; - -pub struct MatchBranchSimplification; - -/// 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, -/// using Eq / Ne comparison with switch value where const bools value differ. -/// -/// For example: -/// -/// ```rust -/// bb0: { -/// switchInt(move _3) -> [42_isize: bb1, otherwise: bb2]; -/// } -/// -/// bb1: { -/// _2 = const true; -/// goto -> bb3; -/// } -/// -/// bb2: { -/// _2 = const false; -/// goto -> bb3; -/// } -/// ``` -/// -/// into: -/// -/// ```rust -/// bb0: { -/// _2 = Eq(move _3, const 42_isize); -/// goto -> bb3; -/// } -/// ``` - -impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 3 { - return; - } - - let def_id = body.source.def_id(); - let param_env = tcx.param_env(def_id); - - let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut(); - let mut should_cleanup = false; - 'outer: for bb_idx in bbs.indices() { - if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) { - continue; - } - - let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind { - TerminatorKind::SwitchInt { - discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)), - switch_ty, - ref targets, - .. - } if targets.iter().len() == 1 => { - let (value, target) = targets.iter().next().unwrap(); - if target == targets.otherwise() { - continue; - } - (discr, value, switch_ty, 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; - } - - // 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 => {} - - // 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.literal.ty().is_bool() - && s_c.literal.ty().is_bool() - && f_c.literal.try_eval_bool(tcx, param_env).is_some() - && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {} - - // Otherwise we cannot optimize. Try another block. - _ => continue 'outer, - } - } - // 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[bb_idx].terminator().source_info; - let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span)); - - // 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); - - 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(), - - ( - 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.literal.try_eval_bool(tcx, param_env).unwrap(); - let s_b = s_c.literal.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(switch_ty)).unwrap().size; - let const_cmp = Operand::const_from_scalar( - tcx, - switch_ty, - crate::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))), - } - } - } - - _ => unreachable!(), - } - }); - - 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; - } - - if should_cleanup { - simplify_cfg(tcx, body); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,627 +0,0 @@ -use crate::{shim, util}; -use required_consts::RequiredConstsVisitor; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::steal::Steal; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_index::vec::IndexVec; -use rustc_middle::mir::visit::Visitor as _; -use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; -use rustc_span::{Span, Symbol}; -use std::borrow::Cow; - -pub mod abort_unwinding_calls; -pub mod add_call_guards; -pub mod add_moves_for_packed_drops; -pub mod add_retag; -pub mod check_const_item_mutation; -pub mod check_consts; -pub mod check_packed_ref; -pub mod check_unsafety; -pub mod cleanup_post_borrowck; -pub mod const_debuginfo; -pub mod const_goto; -pub mod const_prop; -pub mod coverage; -pub mod deaggregator; -pub mod deduplicate_blocks; -pub mod dest_prop; -pub mod dump_mir; -pub mod early_otherwise_branch; -pub mod elaborate_drops; -pub mod function_item_references; -pub mod generator; -pub mod inline; -pub mod instcombine; -pub mod lower_intrinsics; -pub mod lower_slice_len; -pub mod match_branches; -pub mod multiple_return_terminators; -pub mod nrvo; -pub mod promote_consts; -pub mod remove_noop_landing_pads; -pub mod remove_storage_markers; -pub mod remove_unneeded_drops; -pub mod remove_zsts; -pub mod required_consts; -pub mod rustc_peek; -pub mod separate_const_switch; -pub mod simplify; -pub mod simplify_branches; -pub mod simplify_comparison_integral; -pub mod simplify_try; -pub mod uninhabited_enum_branching; -pub mod unreachable_prop; -pub mod validate; - -pub use rustc_middle::mir::MirSource; - -pub(crate) fn provide(providers: &mut Providers) { - self::check_unsafety::provide(providers); - self::check_packed_ref::provide(providers); - *providers = Providers { - mir_keys, - mir_const, - mir_const_qualif: |tcx, def_id| { - let def_id = def_id.expect_local(); - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.mir_const_qualif_const_arg(def) - } else { - mir_const_qualif(tcx, ty::WithOptConstParam::unknown(def_id)) - } - }, - mir_const_qualif_const_arg: |tcx, (did, param_did)| { - mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) - }, - mir_promoted, - mir_drops_elaborated_and_const_checked, - mir_for_ctfe, - mir_for_ctfe_of_const_arg, - optimized_mir, - is_mir_available, - is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did), - promoted_mir: |tcx, def_id| { - let def_id = def_id.expect_local(); - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.promoted_mir_of_const_arg(def) - } else { - promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id)) - } - }, - promoted_mir_of_const_arg: |tcx, (did, param_did)| { - promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) - }, - ..*providers - }; - coverage::query::provide(providers); -} - -fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let def_id = def_id.expect_local(); - tcx.mir_keys(()).contains(&def_id) -} - -/// Finds the full set of `DefId`s within the current crate that have -/// MIR associated with them. -fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet { - let mut set = FxHashSet::default(); - - // All body-owners have MIR associated with them. - set.extend(tcx.body_owners()); - - // Additionally, tuple struct/variant constructors have MIR, but - // they don't have a BodyId, so we need to build them separately. - struct GatherCtors<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - set: &'a mut FxHashSet, - } - impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> { - fn visit_variant_data( - &mut self, - v: &'tcx hir::VariantData<'tcx>, - _: Symbol, - _: &'tcx hir::Generics<'tcx>, - _: hir::HirId, - _: Span, - ) { - if let hir::VariantData::Tuple(_, hir_id) = *v { - self.set.insert(self.tcx.hir().local_def_id(hir_id)); - } - intravisit::walk_struct_def(self, v) - } - type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } - } - tcx.hir() - .krate() - .visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor()); - - set -} - -/// Generates a default name for the pass based on the name of the -/// type `T`. -pub fn default_name() -> Cow<'static, str> { - let name = std::any::type_name::(); - if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) } -} - -/// A streamlined trait that you can implement to create a pass; the -/// pass will be named after the type, and it will consist of a main -/// loop that goes over each available MIR and applies `run_pass`. -pub trait MirPass<'tcx> { - fn name(&self) -> Cow<'_, str> { - default_name::() - } - - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); -} - -pub fn run_passes( - tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, - mir_phase: MirPhase, - passes: &[&[&dyn MirPass<'tcx>]], -) { - let phase_index = mir_phase.phase_index(); - let validate = tcx.sess.opts.debugging_opts.validate_mir; - - if body.phase >= mir_phase { - return; - } - - if validate { - validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase } - .run_pass(tcx, body); - } - - let mut index = 0; - let mut run_pass = |pass: &dyn MirPass<'tcx>| { - let run_hooks = |body: &_, index, is_after| { - dump_mir::on_mir_pass( - tcx, - &format_args!("{:03}-{:03}", phase_index, index), - &pass.name(), - body, - is_after, - ); - }; - run_hooks(body, index, false); - pass.run_pass(tcx, body); - run_hooks(body, index, true); - - if validate { - validate::Validator { - when: format!("after {} in phase {:?}", pass.name(), mir_phase), - mir_phase, - } - .run_pass(tcx, body); - } - - index += 1; - }; - - for pass_group in passes { - for pass in *pass_group { - run_pass(*pass); - } - } - - body.phase = mir_phase; - - if mir_phase == MirPhase::Optimization { - validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase } - .run_pass(tcx, body); - } -} - -fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> ConstQualifs { - let const_kind = tcx.hir().body_const_context(def.did); - - // No need to const-check a non-const `fn`. - if const_kind.is_none() { - return Default::default(); - } - - // N.B., this `borrow()` is guaranteed to be valid (i.e., the value - // cannot yet be stolen), because `mir_promoted()`, which steals - // from `mir_const(), forces this query to execute before - // performing the steal. - let body = &tcx.mir_const(def).borrow(); - - if body.return_ty().references_error() { - tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors"); - return Default::default(); - } - - let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def.did) }; - - let mut validator = check_consts::check::Checker::new(&ccx); - validator.check_body(); - - // We return the qualifs in the return place for every MIR body, even though it is only used - // when deciding to promote a reference to a `const` for now. - validator.qualifs_in_return_place() -} - -/// Make MIR ready for const evaluation. This is run on all MIR, not just on consts! -fn mir_const<'tcx>( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, -) -> &'tcx Steal> { - if let Some(def) = def.try_upgrade(tcx) { - return tcx.mir_const(def); - } - - // Unsafety check uses the raw mir, so make sure it is run. - if !tcx.sess.opts.debugging_opts.thir_unsafeck { - if let Some(param_did) = def.const_param_did { - tcx.ensure().unsafety_check_result_for_const_arg((def.did, param_did)); - } else { - tcx.ensure().unsafety_check_result(def.did); - } - } - - let mut body = tcx.mir_built(def).steal(); - - util::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); - - run_passes( - tcx, - &mut body, - MirPhase::Const, - &[&[ - // MIR-level lints. - &check_packed_ref::CheckPackedRef, - &check_const_item_mutation::CheckConstItemMutation, - &function_item_references::FunctionItemReferences, - // What we need to do constant evaluation. - &simplify::SimplifyCfg::new("initial"), - &rustc_peek::SanityCheck, - ]], - ); - tcx.alloc_steal_mir(body) -} - -/// Compute the main MIR body and the list of MIR bodies of the promoteds. -fn mir_promoted( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, -) -> (&'tcx Steal>, &'tcx Steal>>) { - if let Some(def) = def.try_upgrade(tcx) { - return tcx.mir_promoted(def); - } - - // Ensure that we compute the `mir_const_qualif` for constants at - // this point, before we steal the mir-const result. - // Also this means promotion can rely on all const checks having been done. - let _ = tcx.mir_const_qualif_opt_const_arg(def); - let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global()); - let mut body = tcx.mir_const(def).steal(); - - let mut required_consts = Vec::new(); - let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts); - for (bb, bb_data) in traversal::reverse_postorder(&body) { - required_consts_visitor.visit_basic_block_data(bb, bb_data); - } - body.required_consts = required_consts; - - let promote_pass = promote_consts::PromoteTemps::default(); - let promote: &[&dyn MirPass<'tcx>] = &[ - // What we need to run borrowck etc. - &promote_pass, - &simplify::SimplifyCfg::new("promote-consts"), - ]; - - let opt_coverage: &[&dyn MirPass<'tcx>] = - if tcx.sess.instrument_coverage() { &[&coverage::InstrumentCoverage] } else { &[] }; - - run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]); - - let promoted = promote_pass.promoted_fragments.into_inner(); - (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) -} - -/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it) -fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> { - let did = def_id.expect_local(); - if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { - tcx.mir_for_ctfe_of_const_arg(def) - } else { - tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did))) - } -} - -/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter. -/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that -/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck -/// the const parameter while type checking the main body, which in turn would try -/// to type check the main body again. -fn mir_for_ctfe_of_const_arg<'tcx>( - tcx: TyCtxt<'tcx>, - (did, param_did): (LocalDefId, DefId), -) -> &'tcx Body<'tcx> { - tcx.arena.alloc(inner_mir_for_ctfe( - tcx, - ty::WithOptConstParam { did, const_param_did: Some(param_did) }, - )) -} - -fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { - // FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries - if tcx.is_constructor(def.did.to_def_id()) { - // There's no reason to run all of the MIR passes on constructors when - // we can just output the MIR we want directly. This also saves const - // qualification and borrow checking the trouble of special casing - // constructors. - return shim::build_adt_ctor(tcx, def.did.to_def_id()); - } - - let context = tcx - .hir() - .body_const_context(def.did) - .expect("mir_for_ctfe should not be used for runtime functions"); - - let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); - - match context { - // Do not const prop functions, either they get executed at runtime or exported to metadata, - // so we run const prop on them, or they don't, in which case we const evaluate some control - // flow paths of the function and any errors in those paths will get emitted as const eval - // errors. - hir::ConstContext::ConstFn => {} - // Static items always get evaluated, so we can just let const eval see if any erroneous - // control flow paths get executed. - hir::ConstContext::Static(_) => {} - // Associated constants get const prop run so we detect common failure situations in the - // crate that defined the constant. - // Technically we want to not run on regular const items, but oli-obk doesn't know how to - // conveniently detect that at this point without looking at the HIR. - hir::ConstContext::Const => { - #[rustfmt::skip] - let optimizations: &[&dyn MirPass<'_>] = &[ - &const_prop::ConstProp, - ]; - - #[rustfmt::skip] - run_passes( - tcx, - &mut body, - MirPhase::Optimization, - &[ - optimizations, - ], - ); - } - } - - debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE"); - - body -} - -/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs -/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't -/// end up missing the source MIR due to stealing happening. -fn mir_drops_elaborated_and_const_checked<'tcx>( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, -) -> &'tcx Steal> { - if let Some(def) = def.try_upgrade(tcx) { - return tcx.mir_drops_elaborated_and_const_checked(def); - } - - // (Mir-)Borrowck uses `mir_promoted`, so we have to force it to - // execute before we can steal. - if let Some(param_did) = def.const_param_did { - tcx.ensure().mir_borrowck_const_arg((def.did, param_did)); - } else { - tcx.ensure().mir_borrowck(def.did); - } - - let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - use rustc_middle::hir::map::blocks::FnLikeNode; - let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); - if is_fn_like { - let did = def.did.to_def_id(); - let def = ty::WithOptConstParam::unknown(did); - - // Do not compute the mir call graph without said call graph actually being used. - if inline::is_enabled(tcx) { - let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def)); - } - } - - let (body, _) = tcx.mir_promoted(def); - let mut body = body.steal(); - - run_post_borrowck_cleanup_passes(tcx, &mut body); - check_consts::post_drop_elaboration::check_live_drops(tcx, &body); - tcx.alloc_steal_mir(body) -} - -/// After this series of passes, no lifetime analysis based on borrowing can be done. -fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("post_borrowck_cleanup({:?})", body.source.def_id()); - - let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[ - // Remove all things only needed by analysis - &simplify_branches::SimplifyBranches::new("initial"), - &remove_noop_landing_pads::RemoveNoopLandingPads, - &cleanup_post_borrowck::CleanupNonCodegenStatements, - &simplify::SimplifyCfg::new("early-opt"), - // These next passes must be executed together - &add_call_guards::CriticalCallEdges, - &elaborate_drops::ElaborateDrops, - // This will remove extraneous landing pads which are no longer - // necessary as well as well as forcing any call in a non-unwinding - // function calling a possibly-unwinding function to abort the process. - &abort_unwinding_calls::AbortUnwindingCalls, - // AddMovesForPackedDrops needs to run after drop - // elaboration. - &add_moves_for_packed_drops::AddMovesForPackedDrops, - // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late, - // but before optimizations begin. - &add_retag::AddRetag, - &lower_intrinsics::LowerIntrinsics, - &simplify::SimplifyCfg::new("elaborate-drops"), - // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening - // and it can help optimizations. - &deaggregator::Deaggregator, - ]; - - run_passes(tcx, body, MirPhase::DropLowering, &[post_borrowck_cleanup]); -} - -fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mir_opt_level = tcx.sess.mir_opt_level(); - - // Lowering generator control-flow and variables has to happen before we do anything else - // to them. We run some optimizations before that, because they may be harder to do on the state - // machine than on MIR with async primitives. - let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[ - &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first - &unreachable_prop::UnreachablePropagation, - &uninhabited_enum_branching::UninhabitedEnumBranching, - &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"), - &inline::Inline, - &generator::StateTransform, - ]; - - // Even if we don't do optimizations, we still have to lower generators for codegen. - let no_optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[&generator::StateTransform]; - - // The main optimizations that we do on MIR. - let optimizations: &[&dyn MirPass<'tcx>] = &[ - &remove_storage_markers::RemoveStorageMarkers, - &remove_zsts::RemoveZsts, - &const_goto::ConstGoto, - &remove_unneeded_drops::RemoveUnneededDrops, - &match_branches::MatchBranchSimplification, - // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) - &multiple_return_terminators::MultipleReturnTerminators, - &instcombine::InstCombine, - &separate_const_switch::SeparateConstSwitch, - &const_prop::ConstProp, - &simplify_branches::SimplifyBranches::new("after-const-prop"), - &early_otherwise_branch::EarlyOtherwiseBranch, - &simplify_comparison_integral::SimplifyComparisonIntegral, - &simplify_try::SimplifyArmIdentity, - &simplify_try::SimplifyBranchSame, - &dest_prop::DestinationPropagation, - &simplify_branches::SimplifyBranches::new("final"), - &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("final"), - &nrvo::RenameReturnPlace, - &const_debuginfo::ConstDebugInfo, - &simplify::SimplifyLocals, - &multiple_return_terminators::MultipleReturnTerminators, - &deduplicate_blocks::DeduplicateBlocks, - ]; - - // Optimizations to run even if mir optimizations have been disabled. - let no_optimizations: &[&dyn MirPass<'tcx>] = &[ - // FIXME(#70073): This pass is responsible for both optimization as well as some lints. - &const_prop::ConstProp, - ]; - - // Some cleanup necessary at least for LLVM and potentially other codegen backends. - let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[ - &add_call_guards::CriticalCallEdges, - // Dump the end result for testing and debugging purposes. - &dump_mir::Marker("PreCodegen"), - ]; - - // End of pass declarations, now actually run the passes. - // Generator Lowering - #[rustfmt::skip] - run_passes( - tcx, - body, - MirPhase::GeneratorLowering, - &[ - if mir_opt_level > 0 { - optimizations_with_generators - } else { - no_optimizations_with_generators - } - ], - ); - - // Main optimization passes - #[rustfmt::skip] - run_passes( - tcx, - body, - MirPhase::Optimization, - &[ - if mir_opt_level > 0 { optimizations } else { no_optimizations }, - pre_codegen_cleanup, - ], - ); -} - -/// Optimize the MIR and prepare it for codegen. -fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> { - let did = did.expect_local(); - assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None); - tcx.arena.alloc(inner_optimized_mir(tcx, did)) -} - -fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { - if tcx.is_constructor(did.to_def_id()) { - // There's no reason to run all of the MIR passes on constructors when - // we can just output the MIR we want directly. This also saves const - // qualification and borrow checking the trouble of special casing - // constructors. - return shim::build_adt_ctor(tcx, did.to_def_id()); - } - - match tcx.hir().body_const_context(did) { - // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked` - // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it - // computes and caches its result. - Some(hir::ConstContext::ConstFn) => tcx.ensure().mir_for_ctfe(did), - None => {} - Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other), - } - let mut body = - tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); - run_optimization_passes(tcx, &mut body); - - debug_assert!(!body.has_free_regions(tcx), "Free regions in optimized MIR"); - - body -} - -/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for -/// constant evaluation once all substitutions become known. -fn promoted_mir<'tcx>( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam, -) -> &'tcx IndexVec> { - if tcx.is_constructor(def.did.to_def_id()) { - return tcx.arena.alloc(IndexVec::new()); - } - - if let Some(param_did) = def.const_param_did { - tcx.ensure().mir_borrowck_const_arg((def.did, param_did)); - } else { - tcx.ensure().mir_borrowck(def.did); - } - let (_, promoted) = tcx.mir_promoted(def); - let mut promoted = promoted.steal(); - - for body in &mut promoted { - run_post_borrowck_cleanup_passes(tcx, body); - } - - debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR"); - - tcx.arena.alloc(promoted) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/multiple_return_terminators.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/multiple_return_terminators.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/multiple_return_terminators.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/multiple_return_terminators.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -//! This pass removes jumps to basic blocks containing only a return, and replaces them with a -//! return instead. - -use crate::transform::{simplify, MirPass}; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -pub struct MultipleReturnTerminators; - -impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } - - // find basic blocks with no statement and a return terminator - let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len()); - let def_id = body.source.def_id(); - let bbs = body.basic_blocks_mut(); - for idx in bbs.indices() { - if bbs[idx].statements.is_empty() - && bbs[idx].terminator().kind == TerminatorKind::Return - { - bbs_simple_returns.insert(idx); - } - } - - for bb in bbs { - if !tcx.consider_optimizing(|| format!("MultipleReturnTerminators {:?} ", def_id)) { - break; - } - - if let TerminatorKind::Goto { target } = bb.terminator().kind { - if bbs_simple_returns.contains(target) { - bb.terminator_mut().kind = TerminatorKind::Return; - } - } - } - - simplify::remove_dead_blocks(tcx, body) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/nrvo.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/nrvo.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/nrvo.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/nrvo.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,239 +0,0 @@ -//! See the docs for [`RenameReturnPlace`]. - -use rustc_hir::Mutability; -use rustc_index::bit_set::HybridBitSet; -use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, BasicBlock, Local, Location}; -use rustc_middle::ty::TyCtxt; - -use crate::transform::MirPass; - -/// This pass looks for MIR that always copies the same local into the return place and eliminates -/// the copy by renaming all uses of that local to `_0`. -/// -/// This allows LLVM to perform an optimization similar to the named return value optimization -/// (NRVO) that is guaranteed in C++. This avoids a stack allocation and `memcpy` for the -/// relatively common pattern of allocating a buffer on the stack, mutating it, and returning it by -/// value like so: -/// -/// ```rust -/// fn foo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { -/// let mut buf = [0; 1024]; -/// init(&mut buf); -/// buf -/// } -/// ``` -/// -/// For now, this pass is very simple and only capable of eliminating a single copy. A more general -/// version of copy propagation, such as the one based on non-overlapping live ranges in [#47954] and -/// [#71003], could yield even more benefits. -/// -/// [#47954]: https://github.com/rust-lang/rust/pull/47954 -/// [#71003]: https://github.com/rust-lang/rust/pull/71003 -pub struct RenameReturnPlace; - -impl<'tcx> MirPass<'tcx> for RenameReturnPlace { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { - if tcx.sess.mir_opt_level() == 0 { - return; - } - - let def_id = body.source.def_id(); - let returned_local = match local_eligible_for_nrvo(body) { - Some(l) => l, - None => { - debug!("`{:?}` was ineligible for NRVO", def_id); - return; - } - }; - - if !tcx.consider_optimizing(|| format!("RenameReturnPlace {:?}", def_id)) { - return; - } - - debug!( - "`{:?}` was eligible for NRVO, making {:?} the return place", - def_id, returned_local - ); - - RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body); - - // Clean up the `NOP`s we inserted for statements made useless by our renaming. - for block_data in body.basic_blocks_mut() { - block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop); - } - - // Overwrite the debuginfo of `_0` with that of the renamed local. - let (renamed_decl, ret_decl) = - body.local_decls.pick2_mut(returned_local, mir::RETURN_PLACE); - - // Sometimes, the return place is assigned a local of a different but coercable type, for - // example `&mut T` instead of `&T`. Overwriting the `LocalInfo` for the return place means - // its type may no longer match the return type of its function. This doesn't cause a - // problem in codegen because these two types are layout-compatible, but may be unexpected. - debug!("_0: {:?} = {:?}: {:?}", ret_decl.ty, returned_local, renamed_decl.ty); - ret_decl.clone_from(renamed_decl); - - // The return place is always mutable. - ret_decl.mutability = Mutability::Mut; - } -} - -/// MIR that is eligible for the NRVO must fulfill two conditions: -/// 1. The return place must not be read prior to the `Return` terminator. -/// 2. A simple assignment of a whole local to the return place (e.g., `_0 = _1`) must be the -/// only definition of the return place reaching the `Return` terminator. -/// -/// If the MIR fulfills both these conditions, this function returns the `Local` that is assigned -/// to the return place along all possible paths through the control-flow graph. -fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option { - if IsReturnPlaceRead::run(body) { - return None; - } - - let mut copied_to_return_place = None; - for block in body.basic_blocks().indices() { - // Look for blocks with a `Return` terminator. - if !matches!(body[block].terminator().kind, mir::TerminatorKind::Return) { - continue; - } - - // Look for an assignment of a single local to the return place prior to the `Return`. - let returned_local = find_local_assigned_to_return_place(block, body)?; - match body.local_kind(returned_local) { - // FIXME: Can we do this for arguments as well? - mir::LocalKind::Arg => return None, - - mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"), - mir::LocalKind::Var | mir::LocalKind::Temp => {} - } - - // If multiple different locals are copied to the return place. We can't pick a - // single one to rename. - if copied_to_return_place.map_or(false, |old| old != returned_local) { - return None; - } - - copied_to_return_place = Some(returned_local); - } - - copied_to_return_place -} - -fn find_local_assigned_to_return_place( - start: BasicBlock, - body: &mut mir::Body<'_>, -) -> Option { - let mut block = start; - let mut seen = HybridBitSet::new_empty(body.basic_blocks().len()); - - // Iterate as long as `block` has exactly one predecessor that we have not yet visited. - while seen.insert(block) { - trace!("Looking for assignments to `_0` in {:?}", block); - - let local = body[block].statements.iter().rev().find_map(as_local_assigned_to_return_place); - if local.is_some() { - return local; - } - - match body.predecessors()[block].as_slice() { - &[pred] => block = pred, - _ => return None, - } - } - - None -} - -// If this statement is an assignment of an unprojected local to the return place, -// return that local. -fn as_local_assigned_to_return_place(stmt: &mir::Statement<'_>) -> Option { - if let mir::StatementKind::Assign(box (lhs, rhs)) = &stmt.kind { - if lhs.as_local() == Some(mir::RETURN_PLACE) { - if let mir::Rvalue::Use(mir::Operand::Copy(rhs) | mir::Operand::Move(rhs)) = rhs { - return rhs.as_local(); - } - } - } - - None -} - -struct RenameToReturnPlace<'tcx> { - to_rename: Local, - tcx: TyCtxt<'tcx>, -} - -/// Replaces all uses of `self.to_rename` with `_0`. -impl MutVisitor<'tcx> for RenameToReturnPlace<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_statement(&mut self, stmt: &mut mir::Statement<'tcx>, loc: Location) { - // Remove assignments of the local being replaced to the return place, since it is now the - // return place: - // _0 = _1 - if as_local_assigned_to_return_place(stmt) == Some(self.to_rename) { - stmt.kind = mir::StatementKind::Nop; - return; - } - - // Remove storage annotations for the local being replaced: - // StorageLive(_1) - if let mir::StatementKind::StorageLive(local) | mir::StatementKind::StorageDead(local) = - stmt.kind - { - if local == self.to_rename { - stmt.kind = mir::StatementKind::Nop; - return; - } - } - - self.super_statement(stmt, loc) - } - - fn visit_terminator(&mut self, terminator: &mut mir::Terminator<'tcx>, loc: Location) { - // Ignore the implicit "use" of the return place in a `Return` statement. - if let mir::TerminatorKind::Return = terminator.kind { - return; - } - - self.super_terminator(terminator, loc); - } - - fn visit_local(&mut self, l: &mut Local, ctxt: PlaceContext, _: Location) { - if *l == mir::RETURN_PLACE { - assert_eq!(ctxt, PlaceContext::NonUse(NonUseContext::VarDebugInfo)); - } else if *l == self.to_rename { - *l = mir::RETURN_PLACE; - } - } -} - -struct IsReturnPlaceRead(bool); - -impl IsReturnPlaceRead { - fn run(body: &mir::Body<'_>) -> bool { - let mut vis = IsReturnPlaceRead(false); - vis.visit_body(body); - vis.0 - } -} - -impl Visitor<'tcx> for IsReturnPlaceRead { - fn visit_local(&mut self, &l: &Local, ctxt: PlaceContext, _: Location) { - if l == mir::RETURN_PLACE && ctxt.is_use() && !ctxt.is_place_assignment() { - self.0 = true; - } - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, loc: Location) { - // Ignore the implicit "use" of the return place in a `Return` statement. - if let mir::TerminatorKind::Return = terminator.kind { - return; - } - - self.super_terminator(terminator, loc); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/promote_consts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/promote_consts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/promote_consts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/promote_consts.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1092 +0,0 @@ -//! A pass that promotes borrows of constant rvalues. -//! -//! The rvalues considered constant are trees of temps, -//! each with exactly one initialization, and holding -//! a constant value with no interior mutability. -//! They are placed into a new MIR constant body in -//! `promoted` and the borrow rvalue is replaced with -//! a `Literal::Promoted` using the index into `promoted` -//! of that constant MIR. -//! -//! This pass assumes that every use is dominated by an -//! initialization and can otherwise silence errors, if -//! move analysis runs after promotion on broken MIR. - -use rustc_hir as hir; -use rustc_middle::mir::traversal::ReversePostorder; -use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable}; -use rustc_span::Span; - -use rustc_index::vec::{Idx, IndexVec}; - -use std::cell::Cell; -use std::{cmp, iter, mem}; - -use crate::const_eval::{is_const_fn, is_unstable_const_fn}; -use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx}; -use crate::transform::MirPass; - -/// A `MirPass` for promotion. -/// -/// Promotion is the extraction of promotable temps into separate MIR bodies so they can have -/// `'static` lifetime. -/// -/// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each -/// newly created `Constant`. -#[derive(Default)] -pub struct PromoteTemps<'tcx> { - pub promoted_fragments: Cell>>, -} - -impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // There's not really any point in promoting errorful MIR. - // - // This does not include MIR that failed const-checking, which we still try to promote. - if body.return_ty().references_error() { - tcx.sess.delay_span_bug(body.span, "PromoteTemps: MIR had errors"); - return; - } - - if body.source.promoted.is_some() { - return; - } - - let mut rpo = traversal::reverse_postorder(body); - let ccx = ConstCx::new(tcx, body); - let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo); - - let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates); - - let promoted = promote_candidates(body, tcx, temps, promotable_candidates); - self.promoted_fragments.set(promoted); - } -} - -/// State of a temporary during collection and promotion. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TempState { - /// No references to this temp. - Undefined, - /// One direct assignment and any number of direct uses. - /// A borrow of this temp is promotable if the assigned - /// value is qualified as constant. - Defined { location: Location, uses: usize }, - /// Any other combination of assignments/uses. - Unpromotable, - /// This temp was part of an rvalue which got extracted - /// during promotion and needs cleanup. - PromotedOut, -} - -impl TempState { - pub fn is_promotable(&self) -> bool { - debug!("is_promotable: self={:?}", self); - matches!(self, TempState::Defined { .. }) - } -} - -/// A "root candidate" for promotion, which will become the -/// returned value in a promoted MIR, unless it's a subset -/// of a larger candidate. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Candidate { - /// Borrow of a constant temporary, candidate for lifetime extension. - Ref(Location), -} - -impl Candidate { - fn source_info(&self, body: &Body<'_>) -> SourceInfo { - match self { - Candidate::Ref(location) => *body.source_info(*location), - } - } -} - -struct Collector<'a, 'tcx> { - ccx: &'a ConstCx<'a, 'tcx>, - temps: IndexVec, - candidates: Vec, -} - -impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { - fn visit_local(&mut self, &index: &Local, context: PlaceContext, location: Location) { - debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); - // We're only interested in temporaries and the return place - match self.ccx.body.local_kind(index) { - LocalKind::Temp | LocalKind::ReturnPointer => {} - LocalKind::Arg | LocalKind::Var => return, - } - - // Ignore drops, if the temp gets promoted, - // then it's constant and thus drop is noop. - // Non-uses are also irrelevant. - if context.is_drop() || !context.is_use() { - debug!( - "visit_local: context.is_drop={:?} context.is_use={:?}", - context.is_drop(), - context.is_use(), - ); - return; - } - - let temp = &mut self.temps[index]; - debug!("visit_local: temp={:?}", temp); - if *temp == TempState::Undefined { - match context { - PlaceContext::MutatingUse(MutatingUseContext::Store) - | PlaceContext::MutatingUse(MutatingUseContext::Call) => { - *temp = TempState::Defined { location, uses: 0 }; - return; - } - _ => { /* mark as unpromotable below */ } - } - } else if let TempState::Defined { ref mut uses, .. } = *temp { - // We always allow borrows, even mutable ones, as we need - // to promote mutable borrows of some ZSTs e.g., `&mut []`. - let allowed_use = match context { - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - | PlaceContext::NonMutatingUse(_) => true, - PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, - }; - debug!("visit_local: allowed_use={:?}", allowed_use); - if allowed_use { - *uses += 1; - return; - } - /* mark as unpromotable below */ - } - *temp = TempState::Unpromotable; - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - - match *rvalue { - Rvalue::Ref(..) => { - self.candidates.push(Candidate::Ref(location)); - } - _ => {} - } - } -} - -pub fn collect_temps_and_candidates( - ccx: &ConstCx<'mir, 'tcx>, - rpo: &mut ReversePostorder<'_, 'tcx>, -) -> (IndexVec, Vec) { - let mut collector = Collector { - temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls), - candidates: vec![], - ccx, - }; - for (bb, data) in rpo { - collector.visit_basic_block_data(bb, data); - } - (collector.temps, collector.candidates) -} - -/// Checks whether locals that appear in a promotion context (`Candidate`) are actually promotable. -/// -/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion. -struct Validator<'a, 'tcx> { - ccx: &'a ConstCx<'a, 'tcx>, - temps: &'a IndexVec, -} - -impl std::ops::Deref for Validator<'a, 'tcx> { - type Target = ConstCx<'a, 'tcx>; - - fn deref(&self) -> &Self::Target { - &self.ccx - } -} - -struct Unpromotable; - -impl<'tcx> Validator<'_, 'tcx> { - fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { - match candidate { - Candidate::Ref(loc) => { - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => { - // We can only promote interior borrows of promotable temps (non-temps - // don't get promoted anyway). - self.validate_local(place.local)?; - - // The reference operation itself must be promotable. - // (Needs to come after `validate_local` to avoid ICEs.) - self.validate_ref(*kind, place)?; - - // We do not check all the projections (they do not get promoted anyway), - // but we do stay away from promoting anything involving a dereference. - if place.projection.contains(&ProjectionElem::Deref) { - return Err(Unpromotable); - } - - // We cannot promote things that need dropping, since the promoted value - // would not get dropped. - if self.qualif_local::(place.local) { - return Err(Unpromotable); - } - - Ok(()) - } - _ => bug!(), - } - } - } - } - - // FIXME(eddyb) maybe cache this? - fn qualif_local(&self, local: Local) -> bool { - if let TempState::Defined { location: loc, .. } = self.temps[local] { - let num_stmts = self.body[loc.block].statements.len(); - - if loc.statement_index < num_stmts { - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, rhs)) => qualifs::in_rvalue::( - &self.ccx, - &mut |l| self.qualif_local::(l), - rhs, - ), - _ => { - span_bug!( - statement.source_info.span, - "{:?} is not an assignment", - statement - ); - } - } - } else { - let terminator = self.body[loc.block].terminator(); - match &terminator.kind { - TerminatorKind::Call { .. } => { - let return_ty = self.body.local_decls[local].ty; - Q::in_any_value_of_ty(&self.ccx, return_ty) - } - kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); - } - } - } - } else { - let span = self.body.local_decls[local].source_info.span; - span_bug!(span, "{:?} not promotable, qualif_local shouldn't have been called", local); - } - } - - // FIXME(eddyb) maybe cache this? - fn validate_local(&self, local: Local) -> Result<(), Unpromotable> { - if let TempState::Defined { location: loc, .. } = self.temps[local] { - let block = &self.body[loc.block]; - let num_stmts = block.statements.len(); - - if loc.statement_index < num_stmts { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs), - _ => { - span_bug!( - statement.source_info.span, - "{:?} is not an assignment", - statement - ); - } - } - } else { - let terminator = block.terminator(); - match &terminator.kind { - TerminatorKind::Call { func, args, .. } => self.validate_call(func, args), - TerminatorKind::Yield { .. } => Err(Unpromotable), - kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); - } - } - } - } else { - Err(Unpromotable) - } - } - - fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> { - match place.last_projection() { - None => self.validate_local(place.local), - Some((place_base, elem)) => { - // Validate topmost projection, then recurse. - match elem { - ProjectionElem::Deref => { - let mut promotable = false; - // We need to make sure this is a `Deref` of a local with no further projections. - // Discussion can be found at - // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 - if let Some(local) = place_base.as_local() { - // This is a special treatment for cases like *&STATIC where STATIC is a - // global static variable. - // This pattern is generated only when global static variables are directly - // accessed and is qualified for promotion safely. - if let TempState::Defined { location, .. } = self.temps[local] { - let def_stmt = self.body[location.block] - .statements - .get(location.statement_index); - if let Some(Statement { - kind: - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )), - .. - }) = def_stmt - { - if let Some(did) = c.check_static_ptr(self.tcx) { - // Evaluating a promoted may not read statics except if it got - // promoted from a static (this is a CTFE check). So we - // can only promote static accesses inside statics. - if let Some(hir::ConstContext::Static(..)) = self.const_kind - { - if !self.tcx.is_thread_local_static(did) { - promotable = true; - } - } - } - } - } - } - if !promotable { - return Err(Unpromotable); - } - } - ProjectionElem::Downcast(..) => { - return Err(Unpromotable); - } - - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} - - ProjectionElem::Index(local) => { - let mut promotable = false; - // Only accept if we can predict the index and are indexing an array. - let val = - if let TempState::Defined { location: loc, .. } = self.temps[local] { - let block = &self.body[loc.block]; - if loc.statement_index < block.statements.len() { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )) => c.literal.try_eval_usize(self.tcx, self.param_env), - _ => None, - } - } else { - None - } - } else { - None - }; - if let Some(idx) = val { - // Determine the type of the thing we are indexing. - let ty = place_base.ty(self.body, self.tcx).ty; - match ty.kind() { - ty::Array(_, len) => { - // It's an array; determine its length. - if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) - { - // If the index is in-bounds, go ahead. - if idx < len { - promotable = true; - } - } - } - _ => {} - } - } - if !promotable { - return Err(Unpromotable); - } - - self.validate_local(local)?; - } - - ProjectionElem::Field(..) => { - let base_ty = place_base.ty(self.body, self.tcx).ty; - if base_ty.is_union() { - // No promotion of union field accesses. - return Err(Unpromotable); - } - } - } - - self.validate_place(place_base) - } - } - } - - fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> { - match operand { - Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()), - - // The qualifs for a constant (e.g. `HasMutInterior`) are checked in - // `validate_rvalue` upon access. - Operand::Constant(c) => { - if let Some(def_id) = c.check_static_ptr(self.tcx) { - // Only allow statics (not consts) to refer to other statics. - // FIXME(eddyb) does this matter at all for promotion? - // FIXME(RalfJung) it makes little sense to not promote this in `fn`/`const fn`, - // and in `const` this cannot occur anyway. The only concern is that we might - // promote even `let x = &STATIC` which would be useless, but this applies to - // promotion inside statics as well. - let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_))); - if !is_static { - return Err(Unpromotable); - } - - let is_thread_local = self.tcx.is_thread_local_static(def_id); - if is_thread_local { - return Err(Unpromotable); - } - } - - Ok(()) - } - } - } - - fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> { - match kind { - // Reject these borrow types just to be safe. - // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. - BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), - - BorrowKind::Shared => { - let has_mut_interior = self.qualif_local::(place.local); - if has_mut_interior { - return Err(Unpromotable); - } - } - - BorrowKind::Mut { .. } => { - let ty = place.ty(self.body, self.tcx).ty; - - // In theory, any zero-sized value could be borrowed - // mutably without consequences. However, only &mut [] - // is allowed right now. - if let ty::Array(_, len) = ty.kind() { - match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) => {} - _ => return Err(Unpromotable), - } - } else { - return Err(Unpromotable); - } - } - } - - Ok(()) - } - - fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { - match rvalue { - Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => { - self.validate_operand(operand)?; - } - - Rvalue::Discriminant(place) | Rvalue::Len(place) => { - self.validate_place(place.as_ref())? - } - - Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), - - Rvalue::Cast(kind, operand, cast_ty) => { - if matches!(kind, CastKind::Misc) { - let operand_ty = operand.ty(self.body, self.tcx); - let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { - // ptr-to-int casts are not possible in consts and thus not promotable - return Err(Unpromotable); - } - // int-to-ptr casts are fine, they just use the integer value at pointer type. - } - - self.validate_operand(operand)?; - } - - Rvalue::NullaryOp(op, _) => match op { - NullOp::Box => return Err(Unpromotable), - NullOp::SizeOf => {} - }, - - Rvalue::UnaryOp(op, operand) => { - match op { - // These operations can never fail. - UnOp::Neg | UnOp::Not => {} - } - - self.validate_operand(operand)?; - } - - Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => { - let op = *op; - let lhs_ty = lhs.ty(self.body, self.tcx); - - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() { - // Raw and fn pointer operations are not allowed inside consts and thus not promotable. - assert!(matches!( - op, - BinOp::Eq - | BinOp::Ne - | BinOp::Le - | BinOp::Lt - | BinOp::Ge - | BinOp::Gt - | BinOp::Offset - )); - return Err(Unpromotable); - } - - match op { - BinOp::Div | BinOp::Rem => { - if lhs_ty.is_integral() { - // Integer division: the RHS must be a non-zero const. - let const_val = match rhs { - Operand::Constant(c) => { - c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty) - } - _ => None, - }; - match const_val { - Some(x) if x != 0 => {} // okay - _ => return Err(Unpromotable), // value not known or 0 -- not okay - } - } - } - // The remaining operations can never fail. - BinOp::Eq - | BinOp::Ne - | BinOp::Le - | BinOp::Lt - | BinOp::Ge - | BinOp::Gt - | BinOp::Offset - | BinOp::Add - | BinOp::Sub - | BinOp::Mul - | BinOp::BitXor - | BinOp::BitAnd - | BinOp::BitOr - | BinOp::Shl - | BinOp::Shr => {} - } - - self.validate_operand(lhs)?; - self.validate_operand(rhs)?; - } - - Rvalue::AddressOf(_, place) => { - // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is - // no problem, only using it is. - if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() - { - let base_ty = place_base.ty(self.body, self.tcx).ty; - if let ty::Ref(..) = base_ty.kind() { - return self.validate_place(place_base); - } - } - return Err(Unpromotable); - } - - Rvalue::Ref(_, kind, place) => { - // Special-case reborrows to be more like a copy of the reference. - let mut place_simplified = place.as_ref(); - if let Some((place_base, ProjectionElem::Deref)) = - place_simplified.last_projection() - { - let base_ty = place_base.ty(self.body, self.tcx).ty; - if let ty::Ref(..) = base_ty.kind() { - place_simplified = place_base; - } - } - - self.validate_place(place_simplified)?; - - // Check that the reference is fine (using the original place!). - // (Needs to come after `validate_place` to avoid ICEs.) - self.validate_ref(*kind, place)?; - } - - Rvalue::Aggregate(_, operands) => { - for o in operands { - self.validate_operand(o)?; - } - } - } - - Ok(()) - } - - fn validate_call( - &self, - callee: &Operand<'tcx>, - args: &[Operand<'tcx>], - ) -> Result<(), Unpromotable> { - let fn_ty = callee.ty(self.body, self.tcx); - - // Inside const/static items, we promote all (eligible) function calls. - // Everywhere else, we require `#[rustc_promotable]` on the callee. - let promote_all_const_fn = matches!( - self.const_kind, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) - ); - if !promote_all_const_fn { - if let ty::FnDef(def_id, _) = *fn_ty.kind() { - // Never promote runtime `const fn` calls of - // functions without `#[rustc_promotable]`. - if !self.tcx.is_promotable_const_fn(def_id) { - return Err(Unpromotable); - } - } - } - - let is_const_fn = match *fn_ty.kind() { - ty::FnDef(def_id, _) => { - is_const_fn(self.tcx, def_id) - || is_unstable_const_fn(self.tcx, def_id).is_some() - || is_lang_panic_fn(self.tcx, def_id) - } - _ => false, - }; - if !is_const_fn { - return Err(Unpromotable); - } - - self.validate_operand(callee)?; - for arg in args { - self.validate_operand(arg)?; - } - - Ok(()) - } -} - -// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`. -pub fn validate_candidates( - ccx: &ConstCx<'_, '_>, - temps: &IndexVec, - candidates: &[Candidate], -) -> Vec { - let validator = Validator { ccx, temps }; - - candidates - .iter() - .copied() - .filter(|&candidate| validator.validate_candidate(candidate).is_ok()) - .collect() -} - -struct Promoter<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - source: &'a mut Body<'tcx>, - promoted: Body<'tcx>, - temps: &'a mut IndexVec, - extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>, - - /// If true, all nested temps are also kept in the - /// source MIR, not moved to the promoted MIR. - keep_original: bool, -} - -impl<'a, 'tcx> Promoter<'a, 'tcx> { - fn new_block(&mut self) -> BasicBlock { - let span = self.promoted.span; - self.promoted.basic_blocks_mut().push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: SourceInfo::outermost(span), - kind: TerminatorKind::Return, - }), - is_cleanup: false, - }) - } - - fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { - let last = self.promoted.basic_blocks().last().unwrap(); - let data = &mut self.promoted[last]; - data.statements.push(Statement { - source_info: SourceInfo::outermost(span), - kind: StatementKind::Assign(Box::new((Place::from(dest), rvalue))), - }); - } - - fn is_temp_kind(&self, local: Local) -> bool { - self.source.local_kind(local) == LocalKind::Temp - } - - /// Copies the initialization of this temp to the - /// promoted MIR, recursing through temps. - fn promote_temp(&mut self, temp: Local) -> Local { - let old_keep_original = self.keep_original; - let loc = match self.temps[temp] { - TempState::Defined { location, uses } if uses > 0 => { - if uses > 1 { - self.keep_original = true; - } - location - } - state => { - span_bug!(self.promoted.span, "{:?} not promotable: {:?}", temp, state); - } - }; - if !self.keep_original { - self.temps[temp] = TempState::PromotedOut; - } - - let num_stmts = self.source[loc.block].statements.len(); - let new_temp = self.promoted.local_decls.push(LocalDecl::new( - self.source.local_decls[temp].ty, - self.source.local_decls[temp].source_info.span, - )); - - debug!("promote({:?} @ {:?}/{:?}, {:?})", temp, loc, num_stmts, self.keep_original); - - // First, take the Rvalue or Call out of the source MIR, - // or duplicate it, depending on keep_original. - if loc.statement_index < num_stmts { - let (mut rvalue, source_info) = { - let statement = &mut self.source[loc.block].statements[loc.statement_index]; - let rhs = match statement.kind { - StatementKind::Assign(box (_, ref mut rhs)) => rhs, - _ => { - span_bug!( - statement.source_info.span, - "{:?} is not an assignment", - statement - ); - } - }; - - ( - if self.keep_original { - rhs.clone() - } else { - let unit = Rvalue::Use(Operand::Constant(Box::new(Constant { - span: statement.source_info.span, - user_ty: None, - literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit).into(), - }))); - mem::replace(rhs, unit) - }, - statement.source_info, - ) - }; - - self.visit_rvalue(&mut rvalue, loc); - self.assign(new_temp, rvalue, source_info.span); - } else { - let terminator = if self.keep_original { - self.source[loc.block].terminator().clone() - } else { - let terminator = self.source[loc.block].terminator_mut(); - let target = match terminator.kind { - TerminatorKind::Call { destination: Some((_, target)), .. } => target, - ref kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); - } - }; - Terminator { - source_info: terminator.source_info, - kind: mem::replace(&mut terminator.kind, TerminatorKind::Goto { target }), - } - }; - - match terminator.kind { - TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => { - self.visit_operand(&mut func, loc); - for arg in &mut args { - self.visit_operand(arg, loc); - } - - let last = self.promoted.basic_blocks().last().unwrap(); - let new_target = self.new_block(); - - *self.promoted[last].terminator_mut() = Terminator { - kind: TerminatorKind::Call { - func, - args, - cleanup: None, - destination: Some((Place::from(new_temp), new_target)), - from_hir_call, - fn_span, - }, - source_info: SourceInfo::outermost(terminator.source_info.span), - ..terminator - }; - } - ref kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); - } - }; - }; - - self.keep_original = old_keep_original; - new_temp - } - - fn promote_candidate( - mut self, - candidate: Candidate, - next_promoted_id: usize, - ) -> Option> { - let def = self.source.source.with_opt_param(); - let mut rvalue = { - let promoted = &mut self.promoted; - let promoted_id = Promoted::new(next_promoted_id); - let tcx = self.tcx; - let mut promoted_operand = |ty, span| { - promoted.span = span; - promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); - - Operand::Constant(Box::new(Constant { - span, - user_ty: None, - literal: tcx - .mk_const(ty::Const { - ty, - val: ty::ConstKind::Unevaluated(ty::Unevaluated { - def, - substs_: Some(InternalSubsts::for_item( - tcx, - def.did, - |param, _| { - if let ty::GenericParamDefKind::Lifetime = param.kind { - tcx.lifetimes.re_erased.into() - } else { - tcx.mk_param_from_def(param) - } - }, - )), - promoted: Some(promoted_id), - }), - }) - .into(), - })) - }; - let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); - match candidate { - Candidate::Ref(loc) => { - let statement = &mut blocks[loc.block].statements[loc.statement_index]; - match statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Ref(ref mut region, borrow_kind, ref mut place), - )) => { - // Use the underlying local for this (necessarily interior) borrow. - let ty = local_decls.local_decls()[place.local].ty; - let span = statement.source_info.span; - - let ref_ty = tcx.mk_ref( - tcx.lifetimes.re_erased, - ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() }, - ); - - *region = tcx.lifetimes.re_erased; - - let mut projection = vec![PlaceElem::Deref]; - projection.extend(place.projection); - place.projection = tcx.intern_place_elems(&projection); - - // Create a temp to hold the promoted reference. - // This is because `*r` requires `r` to be a local, - // otherwise we would use the `promoted` directly. - let mut promoted_ref = LocalDecl::new(ref_ty, span); - promoted_ref.source_info = statement.source_info; - let promoted_ref = local_decls.push(promoted_ref); - assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref); - - let promoted_ref_statement = Statement { - source_info: statement.source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(promoted_ref), - Rvalue::Use(promoted_operand(ref_ty, span)), - ))), - }; - self.extra_statements.push((loc, promoted_ref_statement)); - - Rvalue::Ref( - tcx.lifetimes.re_erased, - borrow_kind, - Place { - local: mem::replace(&mut place.local, promoted_ref), - projection: List::empty(), - }, - ) - } - _ => bug!(), - } - } - } - }; - - assert_eq!(self.new_block(), START_BLOCK); - self.visit_rvalue( - &mut rvalue, - Location { block: BasicBlock::new(0), statement_index: usize::MAX }, - ); - - let span = self.promoted.span; - self.assign(RETURN_PLACE, rvalue, span); - Some(self.promoted) - } -} - -/// Replaces all temporaries with their promoted counterparts. -impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - if self.is_temp_kind(*local) { - *local = self.promote_temp(*local); - } - } -} - -pub fn promote_candidates<'tcx>( - body: &mut Body<'tcx>, - tcx: TyCtxt<'tcx>, - mut temps: IndexVec, - candidates: Vec, -) -> IndexVec> { - // Visit candidates in reverse, in case they're nested. - debug!("promote_candidates({:?})", candidates); - - let mut promotions = IndexVec::new(); - - let mut extra_statements = vec![]; - for candidate in candidates.into_iter().rev() { - match candidate { - Candidate::Ref(Location { block, statement_index }) => { - if let StatementKind::Assign(box (place, _)) = - &body[block].statements[statement_index].kind - { - if let Some(local) = place.as_local() { - if temps[local] == TempState::PromotedOut { - // Already promoted. - continue; - } - } - } - } - } - - // Declare return place local so that `mir::Body::new` doesn't complain. - let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect(); - - let mut scope = body.source_scopes[candidate.source_info(body).scope].clone(); - scope.parent_scope = None; - - let promoted = Body::new( - tcx, - body.source, // `promoted` gets filled in below - IndexVec::new(), - IndexVec::from_elem_n(scope, 1), - initial_locals, - IndexVec::new(), - 0, - vec![], - body.span, - body.generator_kind(), - ); - - let promoter = Promoter { - promoted, - tcx, - source: body, - temps: &mut temps, - extra_statements: &mut extra_statements, - keep_original: false, - }; - - //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice - if let Some(mut promoted) = promoter.promote_candidate(candidate, promotions.len()) { - promoted.source.promoted = Some(promotions.next_index()); - promotions.push(promoted); - } - } - - // Insert each of `extra_statements` before its indicated location, which - // has to be done in reverse location order, to not invalidate the rest. - extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc)); - for (loc, statement) in extra_statements { - body[loc.block].statements.insert(loc.statement_index, statement); - } - - // Eliminate assignments to, and drops of promoted temps. - let promoted = |index: Local| temps[index] == TempState::PromotedOut; - for block in body.basic_blocks_mut() { - block.statements.retain(|statement| match &statement.kind { - StatementKind::Assign(box (place, _)) => { - if let Some(index) = place.as_local() { - !promoted(index) - } else { - true - } - } - StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { - !promoted(*index) - } - _ => true, - }); - let terminator = block.terminator_mut(); - if let TerminatorKind::Drop { place, target, .. } = &terminator.kind { - if let Some(index) = place.as_local() { - if promoted(index) { - terminator.kind = TerminatorKind::Goto { target: *target }; - } - } - } - } - - promotions -} - -/// This function returns `true` if the function being called in the array -/// repeat expression is a `const` function. -crate fn is_const_fn_in_array_repeat_expression<'tcx>( - ccx: &ConstCx<'_, 'tcx>, - place: &Place<'tcx>, - body: &Body<'tcx>, -) -> bool { - match place.as_local() { - // rule out cases such as: `let my_var = some_fn(); [my_var; N]` - Some(local) if body.local_decls[local].is_user_variable() => return false, - None => return false, - _ => {} - } - - for block in body.basic_blocks() { - if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = - &block.terminator - { - if let Operand::Constant(box Constant { literal, .. }) = func { - if let ty::FnDef(def_id, _) = *literal.ty().kind() { - if let Some((destination_place, _)) = destination { - if destination_place == place { - if is_const_fn(ccx.tcx, def_id) { - return true; - } - } - } - } - } - } - } - - false -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -use crate::transform::MirPass; -use crate::util::patch::MirPatch; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; -use rustc_target::spec::PanicStrategy; - -/// A pass that removes noop landing pads and replaces jumps to them with -/// `None`. This is important because otherwise LLVM generates terrible -/// code for these. -pub struct RemoveNoopLandingPads; - -pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.panic_strategy() == PanicStrategy::Abort { - return; - } - debug!("remove_noop_landing_pads({:?})", body); - - RemoveNoopLandingPads.remove_nop_landing_pads(body) -} - -impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - remove_noop_landing_pads(tcx, body); - } -} - -impl RemoveNoopLandingPads { - fn is_nop_landing_pad( - &self, - bb: BasicBlock, - body: &Body<'_>, - nop_landing_pads: &BitSet, - ) -> bool { - for stmt in &body[bb].statements { - match &stmt.kind { - StatementKind::FakeRead(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::Nop => { - // These are all nops in a landing pad - } - - StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => { - if place.as_local().is_some() { - // Writing to a local (e.g., a drop flag) does not - // turn a landing pad to a non-nop - } else { - return false; - } - } - - StatementKind::Assign { .. } - | StatementKind::SetDiscriminant { .. } - | StatementKind::LlvmInlineAsm { .. } - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Retag { .. } => { - return false; - } - } - } - - let terminator = body[bb].terminator(); - match terminator.kind { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { - terminator.successors().all(|&succ| nop_landing_pads.contains(succ)) - } - TerminatorKind::GeneratorDrop - | TerminatorKind::Yield { .. } - | TerminatorKind::Return - | TerminatorKind::Abort - | TerminatorKind::Unreachable - | TerminatorKind::Call { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::InlineAsm { .. } => false, - } - } - - fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { - // make sure there's a single resume block - let resume_block = { - let patch = MirPatch::new(body); - let resume_block = patch.resume_block(); - patch.apply(body); - resume_block - }; - debug!("remove_noop_landing_pads: resume block is {:?}", resume_block); - - let mut jumps_folded = 0; - let mut landing_pads_removed = 0; - let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len()); - - // This is a post-order traversal, so that if A post-dominates B - // then A will be visited before B. - let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); - for bb in postorder { - debug!(" processing {:?}", bb); - if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { - if let Some(unwind_bb) = *unwind { - if nop_landing_pads.contains(unwind_bb) { - debug!(" removing noop landing pad"); - landing_pads_removed += 1; - *unwind = None; - } - } - } - - for target in body[bb].terminator_mut().successors_mut() { - if *target != resume_block && nop_landing_pads.contains(*target) { - debug!(" folding noop jump to {:?} to resume block", target); - *target = resume_block; - jumps_folded += 1; - } - } - - let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); - if is_nop_landing_pad { - nop_landing_pads.insert(bb); - } - debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad); - } - - debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_storage_markers.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_storage_markers.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_storage_markers.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_storage_markers.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -//! This pass removes storage markers if they won't be emitted during codegen. - -use crate::transform::MirPass; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -pub struct RemoveStorageMarkers; - -impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.emit_lifetime_markers() { - return; - } - - trace!("Running RemoveStorageMarkers on {:?}", body.source); - for data in body.basic_blocks_mut() { - data.statements.retain(|statement| match statement.kind { - StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::Nop => false, - _ => true, - }) - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -//! This pass replaces a drop of a type that does not need dropping, with a goto - -use crate::transform::MirPass; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -use super::simplify::simplify_cfg; - -pub struct RemoveUnneededDrops; - -impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - trace!("Running RemoveUnneededDrops on {:?}", body.source); - - let did = body.source.def_id(); - let param_env = tcx.param_env(did); - let mut should_simplify = false; - - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks { - let terminator = block.terminator_mut(); - if let TerminatorKind::Drop { place, target, .. } = terminator.kind { - let ty = place.ty(local_decls, tcx); - if ty.ty.needs_drop(tcx, param_env) { - continue; - } - if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", did)) { - continue; - } - debug!("SUCCESS: replacing `drop` with goto({:?})", target); - terminator.kind = TerminatorKind::Goto { target }; - should_simplify = true; - } - } - - // if we applied optimizations, we potentially have some cfg to cleanup to - // make it easier for further passes - if should_simplify { - simplify_cfg(tcx, body); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_zsts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_zsts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_zsts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/remove_zsts.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -//! Removes assignments to ZST places. - -use crate::transform::MirPass; -use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind}; -use rustc_middle::ty::{self, Ty, TyCtxt}; - -pub struct RemoveZsts; - -impl<'tcx> MirPass<'tcx> for RemoveZsts { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // Avoid query cycles (generators require optimized MIR for layout). - if tcx.type_of(body.source.def_id()).is_generator() { - return; - } - let param_env = tcx.param_env(body.source.def_id()); - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks.iter_mut() { - for statement in block.statements.iter_mut() { - if let StatementKind::Assign(box (place, _)) = statement.kind { - let place_ty = place.ty(local_decls, tcx).ty; - if !maybe_zst(place_ty) { - continue; - } - let layout = match tcx.layout_of(param_env.and(place_ty)) { - Ok(layout) => layout, - Err(_) => continue, - }; - if !layout.is_zst() { - continue; - } - if involves_a_union(place, local_decls, tcx) { - continue; - } - if tcx.consider_optimizing(|| { - format!( - "RemoveZsts - Place: {:?} SourceInfo: {:?}", - place, statement.source_info - ) - }) { - statement.make_nop(); - } - } - } - } - } -} - -/// A cheap, approximate check to avoid unnecessary `layout_of` calls. -fn maybe_zst(ty: Ty<'_>) -> bool { - match ty.kind() { - // maybe ZST (could be more precise) - ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true, - // definitely ZST - ty::FnDef(..) | ty::Never => true, - // unreachable or can't be ZST - _ => false, - } -} - -/// Miri lazily allocates memory for locals on assignment, -/// so we must preserve writes to unions and union fields, -/// or it will ICE on reads of those fields. -fn involves_a_union<'tcx>( - place: Place<'tcx>, - local_decls: &LocalDecls<'tcx>, - tcx: TyCtxt<'tcx>, -) -> bool { - let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty); - if place_ty.ty.is_union() { - return true; - } - for elem in place.projection { - place_ty = place_ty.projection_ty(tcx, elem); - if place_ty.ty.is_union() { - return true; - } - } - return false; -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/required_consts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/required_consts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/required_consts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/required_consts.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Constant, Location}; -use rustc_middle::ty::ConstKind; - -pub struct RequiredConstsVisitor<'a, 'tcx> { - required_consts: &'a mut Vec>, -} - -impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { - pub fn new(required_consts: &'a mut Vec>) -> Self { - RequiredConstsVisitor { required_consts } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for RequiredConstsVisitor<'a, 'tcx> { - fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) { - if let Some(ct) = constant.literal.const_for_ty() { - if let ConstKind::Unevaluated(_) = ct.val { - self.required_consts.push(*constant); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/rustc_peek.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/rustc_peek.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/rustc_peek.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/rustc_peek.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,326 +0,0 @@ -use std::borrow::Borrow; - -use rustc_ast::ast; -use rustc_span::symbol::sym; -use rustc_span::Span; -use rustc_target::spec::abi::Abi; - -use crate::transform::MirPass; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, Body, Local, Location}; -use rustc_middle::ty::{self, Ty, TyCtxt}; - -use crate::dataflow::impls::{ - DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals, - MaybeUninitializedPlaces, -}; -use crate::dataflow::move_paths::{HasMoveData, MoveData}; -use crate::dataflow::move_paths::{LookupResult, MovePathIndex}; -use crate::dataflow::MoveDataParamEnv; -use crate::dataflow::{Analysis, JoinSemiLattice, Results, ResultsCursor}; - -pub struct SanityCheck; - -impl<'tcx> MirPass<'tcx> for SanityCheck { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - use crate::dataflow::has_rustc_mir_with; - let def_id = body.source.def_id(); - if !tcx.has_attr(def_id, sym::rustc_mir) { - debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); - return; - } else { - debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); - } - - let attributes = tcx.get_attrs(def_id); - let param_env = tcx.param_env(def_id); - let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap(); - let mdpe = MoveDataParamEnv { move_data, param_env }; - let sess = &tcx.sess; - - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_init).is_some() { - let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe) - .into_engine(tcx, body) - .iterate_to_fixpoint(); - - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_inits); - } - - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_uninit).is_some() { - let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe) - .into_engine(tcx, body) - .iterate_to_fixpoint(); - - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_uninits); - } - - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_definite_init).is_some() { - let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe) - .into_engine(tcx, body) - .iterate_to_fixpoint(); - - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits); - } - - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() { - let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env) - .into_engine(tcx, body) - .iterate_to_fixpoint(); - - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed); - } - - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() { - let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); - - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_liveness); - } - - if has_rustc_mir_with(sess, &attributes, sym::stop_after_dataflow).is_some() { - tcx.sess.fatal("stop_after_dataflow ended compilation"); - } - } -} - -/// This function scans `mir` for all calls to the intrinsic -/// `rustc_peek` that have the expression form `rustc_peek(&expr)`. -/// -/// For each such call, determines what the dataflow bit-state is for -/// the L-value corresponding to `expr`; if the bit-state is a 1, then -/// that call to `rustc_peek` is ignored by the sanity check. If the -/// bit-state is a 0, then this pass emits an error message saying -/// "rustc_peek: bit not set". -/// -/// The intention is that one can write unit tests for dataflow by -/// putting code into a UI test and using `rustc_peek` to -/// make observations about the results of dataflow static analyses. -/// -/// (If there are any calls to `rustc_peek` that do not match the -/// expression form above, then that emits an error as well, but those -/// errors are not intended to be used for unit tests.) -pub fn sanity_check_via_rustc_peek<'tcx, A>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - _attributes: &[ast::Attribute], - results: &Results<'tcx, A>, -) where - A: RustcPeekAt<'tcx>, -{ - let def_id = body.source.def_id(); - debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id); - - let mut cursor = ResultsCursor::new(body, results); - - let peek_calls = body.basic_blocks().iter_enumerated().filter_map(|(bb, block_data)| { - PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call)) - }); - - for (bb, block_data, call) in peek_calls { - // Look for a sequence like the following to indicate that we should be peeking at `_1`: - // _2 = &_1; - // rustc_peek(_2); - // - // /* or */ - // - // _2 = _1; - // rustc_peek(_2); - let (statement_index, peek_rval) = block_data - .statements - .iter() - .enumerate() - .find_map(|(i, stmt)| value_assigned_to_local(stmt, call.arg).map(|rval| (i, rval))) - .expect( - "call to rustc_peek should be preceded by \ - assignment to temporary holding its argument", - ); - - match (call.kind, peek_rval) { - (PeekCallKind::ByRef, mir::Rvalue::Ref(_, _, place)) - | ( - PeekCallKind::ByVal, - mir::Rvalue::Use(mir::Operand::Move(place) | mir::Operand::Copy(place)), - ) => { - let loc = Location { block: bb, statement_index }; - cursor.seek_before_primary_effect(loc); - let state = cursor.get(); - results.analysis.peek_at(tcx, *place, state, call); - } - - _ => { - let msg = "rustc_peek: argument expression \ - must be either `place` or `&place`"; - tcx.sess.span_err(call.span, msg); - } - } - } -} - -/// If `stmt` is an assignment where the LHS is the given local (with no projections), returns the -/// RHS of the assignment. -fn value_assigned_to_local<'a, 'tcx>( - stmt: &'a mir::Statement<'tcx>, - local: Local, -) -> Option<&'a mir::Rvalue<'tcx>> { - if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind { - if let Some(l) = place.as_local() { - if local == l { - return Some(&*rvalue); - } - } - } - - None -} - -#[derive(Clone, Copy, Debug)] -enum PeekCallKind { - ByVal, - ByRef, -} - -impl PeekCallKind { - fn from_arg_ty(arg: Ty<'_>) -> Self { - match arg.kind() { - ty::Ref(_, _, _) => PeekCallKind::ByRef, - _ => PeekCallKind::ByVal, - } - } -} - -#[derive(Clone, Copy, Debug)] -pub struct PeekCall { - arg: Local, - kind: PeekCallKind, - span: Span, -} - -impl PeekCall { - fn from_terminator<'tcx>( - tcx: TyCtxt<'tcx>, - terminator: &mir::Terminator<'tcx>, - ) -> Option { - use mir::Operand; - - let span = terminator.source_info.span; - if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = - &terminator.kind - { - if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() { - let sig = tcx.fn_sig(def_id); - let name = tcx.item_name(def_id); - if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek { - return None; - } - - assert_eq!(args.len(), 1); - let kind = PeekCallKind::from_arg_ty(substs.type_at(0)); - let arg = match &args[0] { - Operand::Copy(place) | Operand::Move(place) => { - if let Some(local) = place.as_local() { - local - } else { - tcx.sess.diagnostic().span_err( - span, - "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", - ); - return None; - } - } - _ => { - tcx.sess.diagnostic().span_err( - span, - "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", - ); - return None; - } - }; - - return Some(PeekCall { arg, kind, span }); - } - } - - None - } -} - -pub trait RustcPeekAt<'tcx>: Analysis<'tcx> { - fn peek_at( - &self, - tcx: TyCtxt<'tcx>, - place: mir::Place<'tcx>, - flow_state: &Self::Domain, - call: PeekCall, - ); -} - -impl<'tcx, A, D> RustcPeekAt<'tcx> for A -where - A: Analysis<'tcx, Domain = D> + HasMoveData<'tcx>, - D: JoinSemiLattice + Clone + Borrow>, -{ - fn peek_at( - &self, - tcx: TyCtxt<'tcx>, - place: mir::Place<'tcx>, - flow_state: &Self::Domain, - call: PeekCall, - ) { - match self.move_data().rev_lookup.find(place.as_ref()) { - LookupResult::Exact(peek_mpi) => { - let bit_state = flow_state.borrow().contains(peek_mpi); - debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state); - if !bit_state { - tcx.sess.span_err(call.span, "rustc_peek: bit not set"); - } - } - - LookupResult::Parent(..) => { - tcx.sess.span_err(call.span, "rustc_peek: argument untracked"); - } - } - } -} - -impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> { - fn peek_at( - &self, - tcx: TyCtxt<'tcx>, - place: mir::Place<'tcx>, - flow_state: &BitSet, - call: PeekCall, - ) { - warn!("peek_at: place={:?}", place); - let local = if let Some(l) = place.as_local() { - l - } else { - tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); - return; - }; - - if !flow_state.contains(local) { - tcx.sess.span_err(call.span, "rustc_peek: bit not set"); - } - } -} - -impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { - fn peek_at( - &self, - tcx: TyCtxt<'tcx>, - place: mir::Place<'tcx>, - flow_state: &BitSet, - call: PeekCall, - ) { - warn!("peek_at: place={:?}", place); - let local = if let Some(l) = place.as_local() { - l - } else { - tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); - return; - }; - - if !flow_state.contains(local) { - tcx.sess.span_err(call.span, "rustc_peek: bit not set"); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/separate_const_switch.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/separate_const_switch.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/separate_const_switch.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/separate_const_switch.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,343 +0,0 @@ -//! A pass that duplicates switch-terminated blocks -//! into a new copy for each predecessor, provided -//! the predecessor sets the value being switched -//! over to a constant. -//! -//! The purpose of this pass is to help constant -//! propagation passes to simplify the switch terminator -//! of the copied blocks into gotos when some predecessors -//! statically determine the output of switches. -//! -//! ```text -//! x = 12 --- ---> something -//! \ / 12 -//! --> switch x -//! / \ otherwise -//! x = y --- ---> something else -//! ``` -//! becomes -//! ```text -//! x = 12 ---> switch x ------> something -//! \ / 12 -//! X -//! / \ otherwise -//! x = y ---> switch x ------> something else -//! ``` -//! so it can hopefully later be turned by another pass into -//! ```text -//! x = 12 --------------------> something -//! / 12 -//! / -//! / otherwise -//! x = y ---- switch x ------> something else -//! ``` -//! -//! This optimization is meant to cover simple cases -//! like `?` desugaring. For now, it thus focuses on -//! simplicity rather than completeness (it notably -//! sometimes duplicates abusively). - -use crate::transform::MirPass; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; -use smallvec::SmallVec; - -pub struct SeparateConstSwitch; - -impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - return; - } - - // If execution did something, applying a simplification layer - // helps later passes optimize the copy away. - if separate_const_switch(body) > 0 { - super::simplify::simplify_cfg(tcx, body); - } - } -} - -/// Returns the amount of blocks that were duplicated -pub fn separate_const_switch<'tcx>(body: &mut Body<'tcx>) -> usize { - let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new(); - let predecessors = body.predecessors(); - 'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() { - if let TerminatorKind::SwitchInt { - discr: Operand::Copy(switch_place) | Operand::Move(switch_place), - .. - } = block.terminator().kind - { - // If the block is on an unwind path, do not - // apply the optimization as unwind paths - // rely on a unique parent invariant - if block.is_cleanup { - continue 'block_iter; - } - - // If the block has fewer than 2 predecessors, ignore it - // we could maybe chain blocks that have exactly one - // predecessor, but for now we ignore that - if predecessors[block_id].len() < 2 { - continue 'block_iter; - } - - // First, let's find a non-const place - // that determines the result of the switch - if let Some(switch_place) = find_determining_place(switch_place, block) { - // We now have an input place for which it would - // be interesting if predecessors assigned it from a const - - let mut predecessors_left = predecessors[block_id].len(); - 'predec_iter: for predecessor_id in predecessors[block_id].iter().copied() { - let predecessor = &body.basic_blocks()[predecessor_id]; - - // First we make sure the predecessor jumps - // in a reasonable way - match &predecessor.terminator().kind { - // The following terminators are - // unconditionally valid - TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } => {} - - TerminatorKind::FalseEdge { real_target, .. } => { - if *real_target != block_id { - continue 'predec_iter; - } - } - - // The following terminators are not allowed - TerminatorKind::Resume - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::InlineAsm { .. } - | TerminatorKind::GeneratorDrop => { - continue 'predec_iter; - } - } - - if is_likely_const(switch_place, predecessor) { - new_blocks.push((predecessor_id, block_id)); - predecessors_left -= 1; - if predecessors_left < 2 { - // If the original block only has one predecessor left, - // we have nothing left to do - break 'predec_iter; - } - } - } - } - } - } - - // Once the analysis is done, perform the duplication - let body_span = body.span; - let copied_blocks = new_blocks.len(); - let blocks = body.basic_blocks_mut(); - for (pred_id, target_id) in new_blocks { - let new_block = blocks[target_id].clone(); - let new_block_id = blocks.push(new_block); - let terminator = blocks[pred_id].terminator_mut(); - - match terminator.kind { - TerminatorKind::Goto { ref mut target } => { - *target = new_block_id; - } - - TerminatorKind::FalseEdge { ref mut real_target, .. } => { - if *real_target == target_id { - *real_target = new_block_id; - } - } - - TerminatorKind::SwitchInt { ref mut targets, .. } => { - targets.all_targets_mut().iter_mut().for_each(|x| { - if *x == target_id { - *x = new_block_id; - } - }); - } - - TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::GeneratorDrop - | TerminatorKind::Assert { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::InlineAsm { .. } - | TerminatorKind::Yield { .. } => { - span_bug!( - body_span, - "basic block terminator had unexpected kind {:?}", - &terminator.kind - ) - } - } - } - - copied_blocks -} - -/// This function describes a rough heuristic guessing -/// whether a place is last set with a const within the block. -/// Notably, it will be overly pessimistic in cases that are already -/// not handled by `separate_const_switch`. -fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<'tcx>) -> bool { - for statement in block.statements.iter().rev() { - match &statement.kind { - StatementKind::Assign(assign) => { - if assign.0 == tracked_place { - match assign.1 { - // These rvalues are definitely constant - Rvalue::Use(Operand::Constant(_)) - | Rvalue::Ref(_, _, _) - | Rvalue::AddressOf(_, _) - | Rvalue::Cast(_, Operand::Constant(_), _) - | Rvalue::NullaryOp(_, _) - | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true, - - // These rvalues make things ambiguous - Rvalue::Repeat(_, _) - | Rvalue::ThreadLocalRef(_) - | Rvalue::Len(_) - | Rvalue::BinaryOp(_, _) - | Rvalue::CheckedBinaryOp(_, _) - | Rvalue::Aggregate(_, _) => return false, - - // These rvalues move the place to track - Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _) - | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) - | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place)) - | Rvalue::Discriminant(place) => tracked_place = place, - } - } - } - - // If the discriminant is set, it is always set - // as a constant, so the job is done. - // As we are **ignoring projections**, if the place - // we are tracking sees its discriminant be set, - // that means we had to be tracking the discriminant - // specifically (as it is impossible to switch over - // an enum directly, and if we were switching over - // its content, we would have had to at least cast it to - // some variant first) - StatementKind::SetDiscriminant { place, .. } => { - if **place == tracked_place { - return true; - } - } - - // If inline assembly is found, we probably should - // not try to analyze the code - StatementKind::LlvmInlineAsm(_) => return false, - - // These statements have no influence on the place - // we are interested in - StatementKind::FakeRead(_) - | StatementKind::StorageLive(_) - | StatementKind::Retag(_, _) - | StatementKind::AscribeUserType(_, _) - | StatementKind::Coverage(_) - | StatementKind::StorageDead(_) - | StatementKind::CopyNonOverlapping(_) - | StatementKind::Nop => {} - } - } - - // If no good reason for the place to be const is found, - // give up. We could maybe go up predecessors, but in - // most cases giving up now should be sufficient. - false -} - -/// Finds a unique place that entirely determines the value -/// of `switch_place`, if it exists. This is only a heuristic. -/// Ideally we would like to track multiple determining places -/// for some edge cases, but one is enough for a lot of situations. -fn find_determining_place<'tcx>( - mut switch_place: Place<'tcx>, - block: &BasicBlockData<'tcx>, -) -> Option> { - for statement in block.statements.iter().rev() { - match &statement.kind { - StatementKind::Assign(op) => { - if op.0 != switch_place { - continue; - } - - match op.1 { - // The following rvalues move the place - // that may be const in the predecessor - Rvalue::Use(Operand::Move(new) | Operand::Copy(new)) - | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new)) - | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _) - | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _) - | Rvalue::Discriminant(new) - => switch_place = new, - - // The following rvalues might still make the block - // be valid but for now we reject them - Rvalue::Len(_) - | Rvalue::Ref(_, _, _) - | Rvalue::BinaryOp(_, _) - | Rvalue::CheckedBinaryOp(_, _) - | Rvalue::Aggregate(_, _) - - // The following rvalues definitely mean we cannot - // or should not apply this optimization - | Rvalue::Use(Operand::Constant(_)) - | Rvalue::Repeat(Operand::Constant(_), _) - | Rvalue::ThreadLocalRef(_) - | Rvalue::AddressOf(_, _) - | Rvalue::NullaryOp(_, _) - | Rvalue::UnaryOp(_, Operand::Constant(_)) - | Rvalue::Cast(_, Operand::Constant(_), _) - => return None, - } - } - - // These statements have no influence on the place - // we are interested in - StatementKind::FakeRead(_) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag(_, _) - | StatementKind::AscribeUserType(_, _) - | StatementKind::Coverage(_) - | StatementKind::CopyNonOverlapping(_) - | StatementKind::Nop => {} - - // If inline assembly is found, we probably should - // not try to analyze the code - StatementKind::LlvmInlineAsm(_) => return None, - - // If the discriminant is set, it is always set - // as a constant, so the job is already done. - // As we are **ignoring projections**, if the place - // we are tracking sees its discriminant be set, - // that means we had to be tracking the discriminant - // specifically (as it is impossible to switch over - // an enum directly, and if we were switching over - // its content, we would have had to at least cast it to - // some variant first) - StatementKind::SetDiscriminant { place, .. } => { - if **place == switch_place { - return None; - } - } - } - } - - Some(switch_place) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_branches.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_branches.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_branches.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_branches.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -//! A pass that simplifies branches when their condition is known. - -use crate::transform::MirPass; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -use std::borrow::Cow; - -pub struct SimplifyBranches { - label: String, -} - -impl SimplifyBranches { - pub fn new(label: &str) -> Self { - SimplifyBranches { label: format!("SimplifyBranches-{}", label) } - } -} - -impl<'tcx> MirPass<'tcx> for SimplifyBranches { - fn name(&self) -> Cow<'_, str> { - Cow::Borrowed(&self.label) - } - - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env(body.source.def_id()); - for block in body.basic_blocks_mut() { - let terminator = block.terminator_mut(); - terminator.kind = match terminator.kind { - TerminatorKind::SwitchInt { - discr: Operand::Constant(ref c), - switch_ty, - ref targets, - .. - } => { - let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty); - if let Some(constant) = constant { - let otherwise = targets.otherwise(); - let mut ret = TerminatorKind::Goto { target: otherwise }; - for (v, t) in targets.iter() { - if v == constant { - ret = TerminatorKind::Goto { target: t }; - break; - } - } - ret - } else { - continue; - } - } - TerminatorKind::Assert { - target, cond: Operand::Constant(ref c), expected, .. - } => match c.literal.try_eval_bool(tcx, param_env) { - Some(v) if v == expected => TerminatorKind::Goto { target }, - _ => continue, - }, - TerminatorKind::FalseEdge { real_target, .. } => { - TerminatorKind::Goto { target: real_target } - } - TerminatorKind::FalseUnwind { real_target, .. } => { - TerminatorKind::Goto { target: real_target } - } - _ => continue, - }; - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,238 +0,0 @@ -use std::iter; - -use super::MirPass; -use rustc_middle::{ - mir::{ - interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, - StatementKind, SwitchTargets, TerminatorKind, - }, - ty::{Ty, TyCtxt}, -}; - -/// Pass to convert `if` conditions on integrals into switches on the integral. -/// For an example, it turns something like -/// -/// ``` -/// _3 = Eq(move _4, const 43i32); -/// StorageDead(_4); -/// switchInt(_3) -> [false: bb2, otherwise: bb3]; -/// ``` -/// -/// into: -/// -/// ``` -/// switchInt(_4) -> [43i32: bb3, otherwise: bb2]; -/// ``` -pub struct SimplifyComparisonIntegral; - -impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - trace!("Running SimplifyComparisonIntegral on {:?}", body.source); - - let helper = OptimizationFinder { body }; - let opts = helper.find_optimizations(); - let mut storage_deads_to_insert = vec![]; - let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![]; - let param_env = tcx.param_env(body.source.def_id()); - for opt in opts { - trace!("SUCCESS: Applying {:?}", opt); - // replace terminator with a switchInt that switches on the integer directly - let bbs = &mut body.basic_blocks_mut(); - let bb = &mut bbs[opt.bb_idx]; - let new_value = match opt.branch_value_scalar { - Scalar::Int(int) => { - let layout = tcx - .layout_of(param_env.and(opt.branch_value_ty)) - .expect("if we have an evaluated constant we must know the layout"); - int.assert_bits(layout.size) - } - Scalar::Ptr(..) => continue, - }; - const FALSE: u128 = 0; - - let mut new_targets = opt.targets; - let first_value = new_targets.iter().next().unwrap().0; - let first_is_false_target = first_value == FALSE; - match opt.op { - BinOp::Eq => { - // if the assignment was Eq we want the true case to be first - if first_is_false_target { - new_targets.all_targets_mut().swap(0, 1); - } - } - BinOp::Ne => { - // if the assignment was Ne we want the false case to be first - if !first_is_false_target { - new_targets.all_targets_mut().swap(0, 1); - } - } - _ => unreachable!(), - } - - // delete comparison statement if it the value being switched on was moved, which means it can not be user later on - if opt.can_remove_bin_op_stmt { - bb.statements[opt.bin_op_stmt_idx].make_nop(); - } else { - // if the integer being compared to a const integral is being moved into the comparison, - // e.g `_2 = Eq(move _3, const 'x');` - // we want to avoid making a double move later on in the switchInt on _3. - // So to avoid `switchInt(move _3) -> ['x': bb2, otherwise: bb1];`, - // we convert the move in the comparison statement to a copy. - - // unwrap is safe as we know this statement is an assign - let (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap(); - - use Operand::*; - match rhs { - Rvalue::BinaryOp(_, box (ref mut left @ Move(_), Constant(_))) => { - *left = Copy(opt.to_switch_on); - } - Rvalue::BinaryOp(_, box (Constant(_), ref mut right @ Move(_))) => { - *right = Copy(opt.to_switch_on); - } - _ => (), - } - } - - let terminator = bb.terminator(); - - // remove StorageDead (if it exists) being used in the assign of the comparison - for (stmt_idx, stmt) in bb.statements.iter().enumerate() { - if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local) - { - continue; - } - storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); - // if we have StorageDeads to remove then make sure to insert them at the top of each target - for bb_idx in new_targets.all_targets() { - storage_deads_to_insert.push(( - *bb_idx, - Statement { - source_info: terminator.source_info, - kind: StatementKind::StorageDead(opt.to_switch_on.local), - }, - )); - } - } - - let [bb_cond, bb_otherwise] = match new_targets.all_targets() { - [a, b] => [*a, *b], - e => bug!("expected 2 switch targets, got: {:?}", e), - }; - - let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise); - - let terminator = bb.terminator_mut(); - terminator.kind = TerminatorKind::SwitchInt { - discr: Operand::Move(opt.to_switch_on), - switch_ty: opt.branch_value_ty, - targets, - }; - } - - for (idx, bb_idx) in storage_deads_to_remove { - body.basic_blocks_mut()[bb_idx].statements[idx].make_nop(); - } - - for (idx, stmt) in storage_deads_to_insert { - body.basic_blocks_mut()[idx].statements.insert(0, stmt); - } - } -} - -struct OptimizationFinder<'a, 'tcx> { - body: &'a Body<'tcx>, -} - -impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> { - fn find_optimizations(&self) -> Vec> { - self.body - .basic_blocks() - .iter_enumerated() - .filter_map(|(bb_idx, bb)| { - // find switch - let (place_switched_on, targets, place_switched_on_moved) = - match &bb.terminator().kind { - rustc_middle::mir::TerminatorKind::SwitchInt { discr, targets, .. } => { - Some((discr.place()?, targets, discr.is_move())) - } - _ => None, - }?; - - // find the statement that assigns the place being switched on - bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| { - match &stmt.kind { - rustc_middle::mir::StatementKind::Assign(box (lhs, rhs)) - if *lhs == place_switched_on => - { - match rhs { - Rvalue::BinaryOp( - op @ (BinOp::Eq | BinOp::Ne), - box (left, right), - ) => { - let (branch_value_scalar, branch_value_ty, to_switch_on) = - find_branch_value_info(left, right)?; - - Some(OptimizationInfo { - bin_op_stmt_idx: stmt_idx, - bb_idx, - can_remove_bin_op_stmt: place_switched_on_moved, - to_switch_on, - branch_value_scalar, - branch_value_ty, - op: *op, - targets: targets.clone(), - }) - } - _ => None, - } - } - _ => None, - } - }) - }) - .collect() - } -} - -fn find_branch_value_info<'tcx>( - left: &Operand<'tcx>, - right: &Operand<'tcx>, -) -> Option<(Scalar, Ty<'tcx>, Place<'tcx>)> { - // check that either left or right is a constant. - // if any are, we can use the other to switch on, and the constant as a value in a switch - use Operand::*; - match (left, right) { - (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) - | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { - let branch_value_ty = branch_value.literal.ty(); - // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats - if !branch_value_ty.is_integral() && !branch_value_ty.is_char() { - return None; - }; - let branch_value_scalar = branch_value.literal.try_to_scalar()?; - Some((branch_value_scalar, branch_value_ty, *to_switch_on)) - } - _ => None, - } -} - -#[derive(Debug)] -struct OptimizationInfo<'tcx> { - /// Basic block to apply the optimization - bb_idx: BasicBlock, - /// Statement index of Eq/Ne assignment that can be removed. None if the assignment can not be removed - i.e the statement is used later on - bin_op_stmt_idx: usize, - /// Can remove Eq/Ne assignment - can_remove_bin_op_stmt: bool, - /// Place that needs to be switched on. This place is of type integral - to_switch_on: Place<'tcx>, - /// Constant to use in switch target value - branch_value_scalar: Scalar, - /// Type of the constant value - branch_value_ty: Ty<'tcx>, - /// Either Eq or Ne - op: BinOp, - /// Current targets used in the switch - targets: SwitchTargets, -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,592 +0,0 @@ -//! A number of passes which remove various redundancies in the CFG. -//! -//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals` -//! gets rid of all the unnecessary local variable declarations. -//! -//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often. -//! Most of the passes should not care or be impacted in meaningful ways due to extra locals -//! either, so running the pass once, right before codegen, should suffice. -//! -//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus -//! one should run it after every pass which may modify CFG in significant ways. This pass must -//! also be run before any analysis passes because it removes dead blocks, and some of these can be -//! ill-typed. -//! -//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have -//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's -//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A -//! standard example of the situation is: -//! -//! ```rust -//! fn example() { -//! let _a: char = { return; }; -//! } -//! ``` -//! -//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we -//! naively generate still contains the `_a = ()` write in the unreachable block "after" the -//! return. - -use crate::transform::MirPass; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::coverage::*; -use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; -use smallvec::SmallVec; -use std::borrow::Cow; -use std::convert::TryInto; - -pub struct SimplifyCfg { - label: String, -} - -impl SimplifyCfg { - pub fn new(label: &str) -> Self { - SimplifyCfg { label: format!("SimplifyCfg-{}", label) } - } -} - -pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { - CfgSimplifier::new(body).simplify(); - remove_dead_blocks(tcx, body); - - // FIXME: Should probably be moved into some kind of pass manager - body.basic_blocks_mut().raw.shrink_to_fit(); -} - -impl<'tcx> MirPass<'tcx> for SimplifyCfg { - fn name(&self) -> Cow<'_, str> { - Cow::Borrowed(&self.label) - } - - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source); - simplify_cfg(tcx, body); - } -} - -pub struct CfgSimplifier<'a, 'tcx> { - basic_blocks: &'a mut IndexVec>, - pred_count: IndexVec, -} - -impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { - pub fn new(body: &'a mut Body<'tcx>) -> Self { - let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks()); - - // we can't use mir.predecessors() here because that counts - // dead blocks, which we don't want to. - pred_count[START_BLOCK] = 1; - - for (_, data) in traversal::preorder(body) { - if let Some(ref term) = data.terminator { - for &tgt in term.successors() { - pred_count[tgt] += 1; - } - } - } - - let basic_blocks = body.basic_blocks_mut(); - - CfgSimplifier { basic_blocks, pred_count } - } - - pub fn simplify(mut self) { - self.strip_nops(); - - let mut start = START_BLOCK; - - // Vec of the blocks that should be merged. We store the indices here, instead of the - // statements itself to avoid moving the (relatively) large statements twice. - // We do not push the statements directly into the target block (`bb`) as that is slower - // due to additional reallocations - let mut merged_blocks = Vec::new(); - loop { - let mut changed = false; - - self.collapse_goto_chain(&mut start, &mut changed); - - for bb in self.basic_blocks.indices() { - if self.pred_count[bb] == 0 { - continue; - } - - debug!("simplifying {:?}", bb); - - let mut terminator = - self.basic_blocks[bb].terminator.take().expect("invalid terminator state"); - - for successor in terminator.successors_mut() { - self.collapse_goto_chain(successor, &mut changed); - } - - let mut inner_changed = true; - merged_blocks.clear(); - while inner_changed { - inner_changed = false; - inner_changed |= self.simplify_branch(&mut terminator); - inner_changed |= self.merge_successor(&mut merged_blocks, &mut terminator); - changed |= inner_changed; - } - - let statements_to_merge = - merged_blocks.iter().map(|&i| self.basic_blocks[i].statements.len()).sum(); - - if statements_to_merge > 0 { - let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements); - statements.reserve(statements_to_merge); - for &from in &merged_blocks { - statements.append(&mut self.basic_blocks[from].statements); - } - self.basic_blocks[bb].statements = statements; - } - - self.basic_blocks[bb].terminator = Some(terminator); - } - - if !changed { - break; - } - } - - if start != START_BLOCK { - debug_assert!(self.pred_count[START_BLOCK] == 0); - self.basic_blocks.swap(START_BLOCK, start); - self.pred_count.swap(START_BLOCK, start); - - // pred_count == 1 if the start block has no predecessor _blocks_. - if self.pred_count[START_BLOCK] > 1 { - for (bb, data) in self.basic_blocks.iter_enumerated_mut() { - if self.pred_count[bb] == 0 { - continue; - } - - for target in data.terminator_mut().successors_mut() { - if *target == start { - *target = START_BLOCK; - } - } - } - } - } - } - - /// This function will return `None` if - /// * the block has statements - /// * the block has a terminator other than `goto` - /// * the block has no terminator (meaning some other part of the current optimization stole it) - fn take_terminator_if_simple_goto(&mut self, bb: BasicBlock) -> Option> { - match self.basic_blocks[bb] { - BasicBlockData { - ref statements, - terminator: - ref mut terminator @ Some(Terminator { kind: TerminatorKind::Goto { .. }, .. }), - .. - } if statements.is_empty() => terminator.take(), - // if `terminator` is None, this means we are in a loop. In that - // case, let all the loop collapse to its entry. - _ => None, - } - } - - /// Collapse a goto chain starting from `start` - fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) { - // Using `SmallVec` here, because in some logs on libcore oli-obk saw many single-element - // goto chains. We should probably benchmark different sizes. - let mut terminators: SmallVec<[_; 1]> = Default::default(); - let mut current = *start; - while let Some(terminator) = self.take_terminator_if_simple_goto(current) { - let target = match terminator { - Terminator { kind: TerminatorKind::Goto { target }, .. } => target, - _ => unreachable!(), - }; - terminators.push((current, terminator)); - current = target; - } - let last = current; - *start = last; - while let Some((current, mut terminator)) = terminators.pop() { - let target = match terminator { - Terminator { kind: TerminatorKind::Goto { ref mut target }, .. } => target, - _ => unreachable!(), - }; - *changed |= *target != last; - *target = last; - debug!("collapsing goto chain from {:?} to {:?}", current, target); - - if self.pred_count[current] == 1 { - // This is the last reference to current, so the pred-count to - // to target is moved into the current block. - self.pred_count[current] = 0; - } else { - self.pred_count[*target] += 1; - self.pred_count[current] -= 1; - } - self.basic_blocks[current].terminator = Some(terminator); - } - } - - // merge a block with 1 `goto` predecessor to its parent - fn merge_successor( - &mut self, - merged_blocks: &mut Vec, - terminator: &mut Terminator<'tcx>, - ) -> bool { - let target = match terminator.kind { - TerminatorKind::Goto { target } if self.pred_count[target] == 1 => target, - _ => return false, - }; - - debug!("merging block {:?} into {:?}", target, terminator); - *terminator = match self.basic_blocks[target].terminator.take() { - Some(terminator) => terminator, - None => { - // unreachable loop - this should not be possible, as we - // don't strand blocks, but handle it correctly. - return false; - } - }; - - merged_blocks.push(target); - self.pred_count[target] = 0; - - true - } - - // turn a branch with all successors identical to a goto - fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool { - match terminator.kind { - TerminatorKind::SwitchInt { .. } => {} - _ => return false, - }; - - let first_succ = { - if let Some(&first_succ) = terminator.successors().next() { - if terminator.successors().all(|s| *s == first_succ) { - let count = terminator.successors().count(); - self.pred_count[first_succ] -= (count - 1) as u32; - first_succ - } else { - return false; - } - } else { - return false; - } - }; - - debug!("simplifying branch {:?}", terminator); - terminator.kind = TerminatorKind::Goto { target: first_succ }; - true - } - - fn strip_nops(&mut self) { - for blk in self.basic_blocks.iter_mut() { - blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop)) - } - } -} - -pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { - let reachable = traversal::reachable_as_bitset(body); - let num_blocks = body.basic_blocks().len(); - if num_blocks == reachable.count() { - return; - } - - let basic_blocks = body.basic_blocks_mut(); - let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); - let mut used_blocks = 0; - for alive_index in reachable.iter() { - let alive_index = alive_index.index(); - replacements[alive_index] = BasicBlock::new(used_blocks); - if alive_index != used_blocks { - // Swap the next alive block data with the current available slot. Since - // alive_index is non-decreasing this is a valid operation. - basic_blocks.raw.swap(alive_index, used_blocks); - } - used_blocks += 1; - } - - if tcx.sess.instrument_coverage() { - save_unreachable_coverage(basic_blocks, used_blocks); - } - - basic_blocks.raw.truncate(used_blocks); - - for block in basic_blocks { - for target in block.terminator_mut().successors_mut() { - *target = replacements[target.index()]; - } - } -} - -/// Some MIR transforms can determine at compile time that a sequences of -/// statements will never be executed, so they can be dropped from the MIR. -/// For example, an `if` or `else` block that is guaranteed to never be executed -/// because its condition can be evaluated at compile time, such as by const -/// evaluation: `if false { ... }`. -/// -/// Those statements are bypassed by redirecting paths in the CFG around the -/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually -/// include `Coverage` statements representing the Rust source code regions to -/// be counted at runtime. Without these `Coverage` statements, the regions are -/// lost, and the Rust source code will show no coverage information. -/// -/// What we want to show in a coverage report is the dead code with coverage -/// counts of `0`. To do this, we need to save the code regions, by injecting -/// `Unreachable` coverage statements. These are non-executable statements whose -/// code regions are still recorded in the coverage map, representing regions -/// with `0` executions. -fn save_unreachable_coverage( - basic_blocks: &mut IndexVec>, - first_dead_block: usize, -) { - let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| { - live_block.statements.iter().any(|statement| { - if let StatementKind::Coverage(coverage) = &statement.kind { - matches!(coverage.kind, CoverageKind::Counter { .. }) - } else { - false - } - }) - }); - if !has_live_counters { - // If there are no live `Counter` `Coverage` statements anymore, don't - // move dead coverage to the `START_BLOCK`. Just allow the dead - // `Coverage` statements to be dropped with the dead blocks. - // - // The `generator::StateTransform` MIR pass can create atypical - // conditions, where all live `Counter`s are dropped from the MIR. - // - // At least one Counter per function is required by LLVM (and necessary, - // to add the `function_hash` to the counter's call to the LLVM - // intrinsic `instrprof.increment()`). - return; - } - - // Retain coverage info for dead blocks, so coverage reports will still - // report `0` executions for the uncovered code regions. - let mut dropped_coverage = Vec::new(); - for dead_block in basic_blocks.raw[first_dead_block..].iter() { - for statement in dead_block.statements.iter() { - if let StatementKind::Coverage(coverage) = &statement.kind { - if let Some(code_region) = &coverage.code_region { - dropped_coverage.push((statement.source_info, code_region.clone())); - } - } - } - } - - let start_block = &mut basic_blocks[START_BLOCK]; - for (source_info, code_region) in dropped_coverage { - start_block.statements.push(Statement { - source_info, - kind: StatementKind::Coverage(Box::new(Coverage { - kind: CoverageKind::Unreachable, - code_region: Some(code_region), - })), - }) - } -} - -pub struct SimplifyLocals; - -impl<'tcx> MirPass<'tcx> for SimplifyLocals { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - trace!("running SimplifyLocals on {:?}", body.source); - simplify_locals(body, tcx); - } -} - -pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { - // First, we're going to get a count of *actual* uses for every `Local`. - let mut used_locals = UsedLocals::new(body); - - // Next, we're going to remove any `Local` with zero actual uses. When we remove those - // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` - // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from - // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a - // fixedpoint where there are no more unused locals. - remove_unused_definitions(&mut used_locals, body); - - // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. - let map = make_local_map(&mut body.local_decls, &used_locals); - - // Only bother running the `LocalUpdater` if we actually found locals to remove. - if map.iter().any(Option::is_none) { - // Update references to all vars and tmps now - let mut updater = LocalUpdater { map, tcx }; - updater.visit_body(body); - - body.local_decls.shrink_to_fit(); - } -} - -/// Construct the mapping while swapping out unused stuff out from the `vec`. -fn make_local_map( - local_decls: &mut IndexVec, - used_locals: &UsedLocals, -) -> IndexVec> { - let mut map: IndexVec> = IndexVec::from_elem(None, &*local_decls); - let mut used = Local::new(0); - - for alive_index in local_decls.indices() { - // `is_used` treats the `RETURN_PLACE` and arguments as used. - if !used_locals.is_used(alive_index) { - continue; - } - - map[alive_index] = Some(used); - if alive_index != used { - local_decls.swap(alive_index, used); - } - used.increment_by(1); - } - local_decls.truncate(used.index()); - map -} - -/// Keeps track of used & unused locals. -struct UsedLocals { - increment: bool, - arg_count: u32, - use_count: IndexVec, -} - -impl UsedLocals { - /// Determines which locals are used & unused in the given body. - fn new(body: &Body<'_>) -> Self { - let mut this = Self { - increment: true, - arg_count: body.arg_count.try_into().unwrap(), - use_count: IndexVec::from_elem(0, &body.local_decls), - }; - this.visit_body(body); - this - } - - /// Checks if local is used. - /// - /// Return place and arguments are always considered used. - fn is_used(&self, local: Local) -> bool { - trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]); - local.as_u32() <= self.arg_count || self.use_count[local] != 0 - } - - /// Updates the use counts to reflect the removal of given statement. - fn statement_removed(&mut self, statement: &Statement<'tcx>) { - self.increment = false; - - // The location of the statement is irrelevant. - let location = Location { block: START_BLOCK, statement_index: 0 }; - self.visit_statement(statement, location); - } - - /// Visits a left-hand side of an assignment. - fn visit_lhs(&mut self, place: &Place<'tcx>, location: Location) { - if place.is_indirect() { - // A use, not a definition. - self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location); - } else { - // A definition. The base local itself is not visited, so this occurrence is not counted - // toward its use count. There might be other locals still, used in an indexing - // projection. - self.super_projection( - place.as_ref(), - PlaceContext::MutatingUse(MutatingUseContext::Projection), - location, - ); - } - } -} - -impl Visitor<'_> for UsedLocals { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - match statement.kind { - StatementKind::LlvmInlineAsm(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Retag(..) - | StatementKind::Coverage(..) - | StatementKind::FakeRead(..) - | StatementKind::AscribeUserType(..) => { - self.super_statement(statement, location); - } - - StatementKind::Nop => {} - - StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {} - - StatementKind::Assign(box (ref place, ref rvalue)) => { - self.visit_lhs(place, location); - self.visit_rvalue(rvalue, location); - } - - StatementKind::SetDiscriminant { ref place, variant_index: _ } => { - self.visit_lhs(place, location); - } - } - } - - fn visit_local(&mut self, local: &Local, _ctx: PlaceContext, _location: Location) { - if self.increment { - self.use_count[*local] += 1; - } else { - assert_ne!(self.use_count[*local], 0); - self.use_count[*local] -= 1; - } - } -} - -/// Removes unused definitions. Updates the used locals to reflect the changes made. -fn remove_unused_definitions<'a, 'tcx>(used_locals: &'a mut UsedLocals, body: &mut Body<'tcx>) { - // The use counts are updated as we remove the statements. A local might become unused - // during the retain operation, leading to a temporary inconsistency (storage statements or - // definitions referencing the local might remain). For correctness it is crucial that this - // computation reaches a fixed point. - - let mut modified = true; - while modified { - modified = false; - - for data in body.basic_blocks_mut() { - // Remove unnecessary StorageLive and StorageDead annotations. - data.statements.retain(|statement| { - let keep = match &statement.kind { - StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { - used_locals.is_used(*local) - } - StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local), - - StatementKind::SetDiscriminant { ref place, .. } => { - used_locals.is_used(place.local) - } - _ => true, - }; - - if !keep { - trace!("removing statement {:?}", statement); - modified = true; - used_locals.statement_removed(statement); - } - - keep - }); - } - } -} - -struct LocalUpdater<'tcx> { - map: IndexVec>, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { - *l = self.map[*l].unwrap(); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_try.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_try.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_try.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/simplify_try.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,821 +0,0 @@ -//! The general point of the optimizations provided here is to simplify something like: -//! -//! ```rust -//! match x { -//! Ok(x) => Ok(x), -//! Err(x) => Err(x) -//! } -//! ``` -//! -//! into just `x`. - -use crate::transform::{simplify, MirPass}; -use itertools::Itertools as _; -use rustc_index::{bit_set::BitSet, vec::IndexVec}; -use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, List, Ty, TyCtxt}; -use rustc_target::abi::VariantIdx; -use std::iter::{once, Enumerate, Peekable}; -use std::slice::Iter; - -/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move. -/// -/// This is done by transforming basic blocks where the statements match: -/// -/// ```rust -/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY ); -/// _TMP_2 = _LOCAL_TMP; -/// ((_LOCAL_0 as Variant).FIELD: TY) = move _TMP_2; -/// discriminant(_LOCAL_0) = VAR_IDX; -/// ``` -/// -/// into: -/// -/// ```rust -/// _LOCAL_0 = move _LOCAL_1 -/// ``` -pub struct SimplifyArmIdentity; - -#[derive(Debug)] -struct ArmIdentityInfo<'tcx> { - /// Storage location for the variant's field - local_temp_0: Local, - /// Storage location holding the variant being read from - local_1: Local, - /// The variant field being read from - vf_s0: VarField<'tcx>, - /// Index of the statement which loads the variant being read - get_variant_field_stmt: usize, - - /// Tracks each assignment to a temporary of the variant's field - field_tmp_assignments: Vec<(Local, Local)>, - - /// Storage location holding the variant's field that was read from - local_tmp_s1: Local, - /// Storage location holding the enum that we are writing to - local_0: Local, - /// The variant field being written to - vf_s1: VarField<'tcx>, - - /// Storage location that the discriminant is being written to - set_discr_local: Local, - /// The variant being written - set_discr_var_idx: VariantIdx, - - /// Index of the statement that should be overwritten as a move - stmt_to_overwrite: usize, - /// SourceInfo for the new move - source_info: SourceInfo, - - /// Indices of matching Storage{Live,Dead} statements encountered. - /// (StorageLive index,, StorageDead index, Local) - storage_stmts: Vec<(usize, usize, Local)>, - - /// The statements that should be removed (turned into nops) - stmts_to_remove: Vec, - - /// Indices of debug variables that need to be adjusted to point to - // `{local_0}.{dbg_projection}`. - dbg_info_to_adjust: Vec, - - /// The projection used to rewrite debug info. - dbg_projection: &'tcx List>, -} - -fn get_arm_identity_info<'a, 'tcx>( - stmts: &'a [Statement<'tcx>], - locals_count: usize, - debug_info: &'a [VarDebugInfo<'tcx>], -) -> Option> { - // This can't possibly match unless there are at least 3 statements in the block - // so fail fast on tiny blocks. - if stmts.len() < 3 { - return None; - } - - let mut tmp_assigns = Vec::new(); - let mut nop_stmts = Vec::new(); - let mut storage_stmts = Vec::new(); - let mut storage_live_stmts = Vec::new(); - let mut storage_dead_stmts = Vec::new(); - - type StmtIter<'a, 'tcx> = Peekable>>>; - - fn is_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool { - matches!(stmt.kind, StatementKind::StorageLive(_) | StatementKind::StorageDead(_)) - } - - /// Eats consecutive Statements which match `test`, performing the specified `action` for each. - /// The iterator `stmt_iter` is not advanced if none were matched. - fn try_eat<'a, 'tcx>( - stmt_iter: &mut StmtIter<'a, 'tcx>, - test: impl Fn(&'a Statement<'tcx>) -> bool, - mut action: impl FnMut(usize, &'a Statement<'tcx>), - ) { - while stmt_iter.peek().map_or(false, |(_, stmt)| test(stmt)) { - let (idx, stmt) = stmt_iter.next().unwrap(); - - action(idx, stmt); - } - } - - /// Eats consecutive `StorageLive` and `StorageDead` Statements. - /// The iterator `stmt_iter` is not advanced if none were found. - fn try_eat_storage_stmts<'a, 'tcx>( - stmt_iter: &mut StmtIter<'a, 'tcx>, - storage_live_stmts: &mut Vec<(usize, Local)>, - storage_dead_stmts: &mut Vec<(usize, Local)>, - ) { - try_eat(stmt_iter, is_storage_stmt, |idx, stmt| { - if let StatementKind::StorageLive(l) = stmt.kind { - storage_live_stmts.push((idx, l)); - } else if let StatementKind::StorageDead(l) = stmt.kind { - storage_dead_stmts.push((idx, l)); - } - }) - } - - fn is_tmp_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool { - use rustc_middle::mir::StatementKind::Assign; - if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = &stmt.kind { - place.as_local().is_some() && p.as_local().is_some() - } else { - false - } - } - - /// Eats consecutive `Assign` Statements. - // The iterator `stmt_iter` is not advanced if none were found. - fn try_eat_assign_tmp_stmts<'a, 'tcx>( - stmt_iter: &mut StmtIter<'a, 'tcx>, - tmp_assigns: &mut Vec<(Local, Local)>, - nop_stmts: &mut Vec, - ) { - try_eat(stmt_iter, is_tmp_storage_stmt, |idx, stmt| { - use rustc_middle::mir::StatementKind::Assign; - if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = - &stmt.kind - { - tmp_assigns.push((place.as_local().unwrap(), p.as_local().unwrap())); - nop_stmts.push(idx); - } - }) - } - - fn find_storage_live_dead_stmts_for_local<'tcx>( - local: Local, - stmts: &[Statement<'tcx>], - ) -> Option<(usize, usize)> { - trace!("looking for {:?}", local); - let mut storage_live_stmt = None; - let mut storage_dead_stmt = None; - for (idx, stmt) in stmts.iter().enumerate() { - if stmt.kind == StatementKind::StorageLive(local) { - storage_live_stmt = Some(idx); - } else if stmt.kind == StatementKind::StorageDead(local) { - storage_dead_stmt = Some(idx); - } - } - - Some((storage_live_stmt?, storage_dead_stmt.unwrap_or(usize::MAX))) - } - - // Try to match the expected MIR structure with the basic block we're processing. - // We want to see something that looks like: - // ``` - // (StorageLive(_) | StorageDead(_));* - // _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY); - // (StorageLive(_) | StorageDead(_));* - // (tmp_n+1 = tmp_n);* - // (StorageLive(_) | StorageDead(_));* - // (tmp_n+1 = tmp_n);* - // ((LOCAL_FROM as Variant).FIELD: TY) = move tmp; - // discriminant(LOCAL_FROM) = VariantIdx; - // (StorageLive(_) | StorageDead(_));* - // ``` - let mut stmt_iter = stmts.iter().enumerate().peekable(); - - try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); - - let (get_variant_field_stmt, stmt) = stmt_iter.next()?; - let (local_tmp_s0, local_1, vf_s0, dbg_projection) = match_get_variant_field(stmt)?; - - try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); - - try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts); - - try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); - - try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts); - - let (idx, stmt) = stmt_iter.next()?; - let (local_tmp_s1, local_0, vf_s1) = match_set_variant_field(stmt)?; - nop_stmts.push(idx); - - let (idx, stmt) = stmt_iter.next()?; - let (set_discr_local, set_discr_var_idx) = match_set_discr(stmt)?; - let discr_stmt_source_info = stmt.source_info; - nop_stmts.push(idx); - - try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); - - for (live_idx, live_local) in storage_live_stmts { - if let Some(i) = storage_dead_stmts.iter().rposition(|(_, l)| *l == live_local) { - let (dead_idx, _) = storage_dead_stmts.swap_remove(i); - storage_stmts.push((live_idx, dead_idx, live_local)); - - if live_local == local_tmp_s0 { - nop_stmts.push(get_variant_field_stmt); - } - } - } - // We sort primitive usize here so we can use unstable sort - nop_stmts.sort_unstable(); - - // Use one of the statements we're going to discard between the point - // where the storage location for the variant field becomes live and - // is killed. - let (live_idx, dead_idx) = find_storage_live_dead_stmts_for_local(local_tmp_s0, stmts)?; - let stmt_to_overwrite = - nop_stmts.iter().find(|stmt_idx| live_idx < **stmt_idx && **stmt_idx < dead_idx); - - let mut tmp_assigned_vars = BitSet::new_empty(locals_count); - for (l, r) in &tmp_assigns { - tmp_assigned_vars.insert(*l); - tmp_assigned_vars.insert(*r); - } - - let dbg_info_to_adjust: Vec<_> = debug_info - .iter() - .enumerate() - .filter_map(|(i, var_info)| { - if let VarDebugInfoContents::Place(p) = var_info.value { - if tmp_assigned_vars.contains(p.local) { - return Some(i); - } - } - - None - }) - .collect(); - - Some(ArmIdentityInfo { - local_temp_0: local_tmp_s0, - local_1, - vf_s0, - get_variant_field_stmt, - field_tmp_assignments: tmp_assigns, - local_tmp_s1, - local_0, - vf_s1, - set_discr_local, - set_discr_var_idx, - stmt_to_overwrite: *stmt_to_overwrite?, - source_info: discr_stmt_source_info, - storage_stmts, - stmts_to_remove: nop_stmts, - dbg_info_to_adjust, - dbg_projection, - }) -} - -fn optimization_applies<'tcx>( - opt_info: &ArmIdentityInfo<'tcx>, - local_decls: &IndexVec>, - local_uses: &IndexVec, - var_debug_info: &[VarDebugInfo<'tcx>], -) -> bool { - trace!("testing if optimization applies..."); - - // FIXME(wesleywiser): possibly relax this restriction? - if opt_info.local_0 == opt_info.local_1 { - trace!("NO: moving into ourselves"); - return false; - } else if opt_info.vf_s0 != opt_info.vf_s1 { - trace!("NO: the field-and-variant information do not match"); - return false; - } else if local_decls[opt_info.local_0].ty != local_decls[opt_info.local_1].ty { - // FIXME(Centril,oli-obk): possibly relax to same layout? - trace!("NO: source and target locals have different types"); - return false; - } else if (opt_info.local_0, opt_info.vf_s0.var_idx) - != (opt_info.set_discr_local, opt_info.set_discr_var_idx) - { - trace!("NO: the discriminants do not match"); - return false; - } - - // Verify the assignment chain consists of the form b = a; c = b; d = c; etc... - if opt_info.field_tmp_assignments.is_empty() { - trace!("NO: no assignments found"); - return false; - } - let mut last_assigned_to = opt_info.field_tmp_assignments[0].1; - let source_local = last_assigned_to; - for (l, r) in &opt_info.field_tmp_assignments { - if *r != last_assigned_to { - trace!("NO: found unexpected assignment {:?} = {:?}", l, r); - return false; - } - - last_assigned_to = *l; - } - - // Check that the first and last used locals are only used twice - // since they are of the form: - // - // ``` - // _first = ((_x as Variant).n: ty); - // _n = _first; - // ... - // ((_y as Variant).n: ty) = _n; - // discriminant(_y) = z; - // ``` - for (l, r) in &opt_info.field_tmp_assignments { - if local_uses[*l] != 2 { - warn!("NO: FAILED assignment chain local {:?} was used more than twice", l); - return false; - } else if local_uses[*r] != 2 { - warn!("NO: FAILED assignment chain local {:?} was used more than twice", r); - return false; - } - } - - // Check that debug info only points to full Locals and not projections. - for dbg_idx in &opt_info.dbg_info_to_adjust { - let dbg_info = &var_debug_info[*dbg_idx]; - if let VarDebugInfoContents::Place(p) = dbg_info.value { - if !p.projection.is_empty() { - trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, p); - return false; - } - } - } - - if source_local != opt_info.local_temp_0 { - trace!( - "NO: start of assignment chain does not match enum variant temp: {:?} != {:?}", - source_local, - opt_info.local_temp_0 - ); - return false; - } else if last_assigned_to != opt_info.local_tmp_s1 { - trace!( - "NO: end of assignemnt chain does not match written enum temp: {:?} != {:?}", - last_assigned_to, - opt_info.local_tmp_s1 - ); - return false; - } - - trace!("SUCCESS: optimization applies!"); - true -} - -impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // FIXME(77359): This optimization can result in unsoundness. - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { - return; - } - - let source = body.source; - trace!("running SimplifyArmIdentity on {:?}", source); - - let local_uses = LocalUseCounter::get_local_uses(body); - let (basic_blocks, local_decls, debug_info) = - body.basic_blocks_local_decls_mut_and_var_debug_info(); - for bb in basic_blocks { - if let Some(opt_info) = - get_arm_identity_info(&bb.statements, local_decls.len(), debug_info) - { - trace!("got opt_info = {:#?}", opt_info); - if !optimization_applies(&opt_info, local_decls, &local_uses, &debug_info) { - debug!("optimization skipped for {:?}", source); - continue; - } - - // Also remove unused Storage{Live,Dead} statements which correspond - // to temps used previously. - for (live_idx, dead_idx, local) in &opt_info.storage_stmts { - // The temporary that we've read the variant field into is scoped to this block, - // so we can remove the assignment. - if *local == opt_info.local_temp_0 { - bb.statements[opt_info.get_variant_field_stmt].make_nop(); - } - - for (left, right) in &opt_info.field_tmp_assignments { - if local == left || local == right { - bb.statements[*live_idx].make_nop(); - bb.statements[*dead_idx].make_nop(); - } - } - } - - // Right shape; transform - for stmt_idx in opt_info.stmts_to_remove { - bb.statements[stmt_idx].make_nop(); - } - - let stmt = &mut bb.statements[opt_info.stmt_to_overwrite]; - stmt.source_info = opt_info.source_info; - stmt.kind = StatementKind::Assign(Box::new(( - opt_info.local_0.into(), - Rvalue::Use(Operand::Move(opt_info.local_1.into())), - ))); - - bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop); - - // Fix the debug info to point to the right local - for dbg_index in opt_info.dbg_info_to_adjust { - let dbg_info = &mut debug_info[dbg_index]; - assert!( - matches!(dbg_info.value, VarDebugInfoContents::Place(_)), - "value was not a Place" - ); - if let VarDebugInfoContents::Place(p) = &mut dbg_info.value { - assert!(p.projection.is_empty()); - p.local = opt_info.local_0; - p.projection = opt_info.dbg_projection; - } - } - - trace!("block is now {:?}", bb.statements); - } - } - } -} - -struct LocalUseCounter { - local_uses: IndexVec, -} - -impl LocalUseCounter { - fn get_local_uses<'tcx>(body: &Body<'tcx>) -> IndexVec { - let mut counter = LocalUseCounter { local_uses: IndexVec::from_elem(0, &body.local_decls) }; - counter.visit_body(body); - counter.local_uses - } -} - -impl<'tcx> Visitor<'tcx> for LocalUseCounter { - fn visit_local(&mut self, local: &Local, context: PlaceContext, _location: Location) { - if context.is_storage_marker() - || context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) - { - return; - } - - self.local_uses[*local] += 1; - } -} - -/// Match on: -/// ```rust -/// _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY); -/// ``` -fn match_get_variant_field<'tcx>( - stmt: &Statement<'tcx>, -) -> Option<(Local, Local, VarField<'tcx>, &'tcx List>)> { - match &stmt.kind { - StatementKind::Assign(box ( - place_into, - Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)), - )) => { - let local_into = place_into.as_local()?; - let (local_from, vf) = match_variant_field_place(*pf)?; - Some((local_into, local_from, vf, pf.projection)) - } - _ => None, - } -} - -/// Match on: -/// ```rust -/// ((_LOCAL_FROM as Variant).FIELD: TY) = move _LOCAL_INTO; -/// ``` -fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> { - match &stmt.kind { - StatementKind::Assign(box (place_from, Rvalue::Use(Operand::Move(place_into)))) => { - let local_into = place_into.as_local()?; - let (local_from, vf) = match_variant_field_place(*place_from)?; - Some((local_into, local_from, vf)) - } - _ => None, - } -} - -/// Match on: -/// ```rust -/// discriminant(_LOCAL_TO_SET) = VAR_IDX; -/// ``` -fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)> { - match &stmt.kind { - StatementKind::SetDiscriminant { place, variant_index } => { - Some((place.as_local()?, *variant_index)) - } - _ => None, - } -} - -#[derive(PartialEq, Debug)] -struct VarField<'tcx> { - field: Field, - field_ty: Ty<'tcx>, - var_idx: VariantIdx, -} - -/// Match on `((_LOCAL as Variant).FIELD: TY)`. -fn match_variant_field_place<'tcx>(place: Place<'tcx>) -> Option<(Local, VarField<'tcx>)> { - match place.as_ref() { - PlaceRef { - local, - projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)], - } => Some((local, VarField { field, field_ty: ty, var_idx })), - _ => None, - } -} - -/// Simplifies `SwitchInt(_) -> [targets]`, -/// where all the `targets` have the same form, -/// into `goto -> target_first`. -pub struct SimplifyBranchSame; - -impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // This optimization is disabled by default for now due to - // soundness concerns; see issue #89485 and PR #89489. - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { - return; - } - - trace!("Running SimplifyBranchSame on {:?}", body.source); - let finder = SimplifyBranchSameOptimizationFinder { body, tcx }; - let opts = finder.find(); - - let did_remove_blocks = opts.len() > 0; - for opt in opts.iter() { - trace!("SUCCESS: Applying optimization {:?}", opt); - // Replace `SwitchInt(..) -> [bb_first, ..];` with a `goto -> bb_first;`. - body.basic_blocks_mut()[opt.bb_to_opt_terminator].terminator_mut().kind = - TerminatorKind::Goto { target: opt.bb_to_goto }; - } - - if did_remove_blocks { - // We have dead blocks now, so remove those. - simplify::remove_dead_blocks(tcx, body); - } - } -} - -#[derive(Debug)] -struct SimplifyBranchSameOptimization { - /// All basic blocks are equal so go to this one - bb_to_goto: BasicBlock, - /// Basic block where the terminator can be simplified to a goto - bb_to_opt_terminator: BasicBlock, -} - -struct SwitchTargetAndValue { - target: BasicBlock, - // None in case of the `otherwise` case - value: Option, -} - -struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { - fn find(&self) -> Vec { - self.body - .basic_blocks() - .iter_enumerated() - .filter_map(|(bb_idx, bb)| { - let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { - TerminatorKind::SwitchInt { targets, discr, .. } => { - let targets_and_values: Vec<_> = targets.iter() - .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) }) - .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None })) - .collect(); - (discr, targets_and_values) - }, - _ => return None, - }; - - // find the adt that has its discriminant read - // assuming this must be the last statement of the block - let adt_matched_on = match &bb.statements.last()?.kind { - StatementKind::Assign(box (place, rhs)) - if Some(*place) == discr_switched_on.place() => - { - match rhs { - Rvalue::Discriminant(adt_place) if adt_place.ty(self.body, self.tcx).ty.is_enum() => adt_place, - _ => { - trace!("NO: expected a discriminant read of an enum instead of: {:?}", rhs); - return None; - } - } - } - other => { - trace!("NO: expected an assignment of a discriminant read to a place. Found: {:?}", other); - return None - }, - }; - - let mut iter_bbs_reachable = targets_and_values - .iter() - .map(|target_and_value| (target_and_value, &self.body.basic_blocks()[target_and_value.target])) - .filter(|(_, bb)| { - // Reaching `unreachable` is UB so assume it doesn't happen. - bb.terminator().kind != TerminatorKind::Unreachable - // But `asm!(...)` could abort the program, - // so we cannot assume that the `unreachable` terminator itself is reachable. - // FIXME(Centril): use a normalization pass instead of a check. - || bb.statements.iter().any(|stmt| matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))) - }) - .peekable(); - - let bb_first = iter_bbs_reachable.peek().map_or(&targets_and_values[0], |(idx, _)| *idx); - let mut all_successors_equivalent = StatementEquality::TrivialEqual; - - // All successor basic blocks must be equal or contain statements that are pairwise considered equal. - for ((target_and_value_l,bb_l), (target_and_value_r,bb_r)) in iter_bbs_reachable.tuple_windows() { - let trivial_checks = bb_l.is_cleanup == bb_r.is_cleanup - && bb_l.terminator().kind == bb_r.terminator().kind - && bb_l.statements.len() == bb_r.statements.len(); - let statement_check = || { - bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| { - let stmt_equality = self.statement_equality(*adt_matched_on, &l, target_and_value_l, &r, target_and_value_r); - if matches!(stmt_equality, StatementEquality::NotEqual) { - // short circuit - None - } else { - Some(acc.combine(&stmt_equality)) - } - }) - .unwrap_or(StatementEquality::NotEqual) - }; - if !trivial_checks { - all_successors_equivalent = StatementEquality::NotEqual; - break; - } - all_successors_equivalent = all_successors_equivalent.combine(&statement_check()); - }; - - match all_successors_equivalent{ - StatementEquality::TrivialEqual => { - // statements are trivially equal, so just take first - trace!("Statements are trivially equal"); - Some(SimplifyBranchSameOptimization { - bb_to_goto: bb_first.target, - bb_to_opt_terminator: bb_idx, - }) - } - StatementEquality::ConsideredEqual(bb_to_choose) => { - trace!("Statements are considered equal"); - Some(SimplifyBranchSameOptimization { - bb_to_goto: bb_to_choose, - bb_to_opt_terminator: bb_idx, - }) - } - StatementEquality::NotEqual => { - trace!("NO: not all successors of basic block {:?} were equivalent", bb_idx); - None - } - } - }) - .collect() - } - - /// Tests if two statements can be considered equal - /// - /// Statements can be trivially equal if the kinds match. - /// But they can also be considered equal in the following case A: - /// ``` - /// discriminant(_0) = 0; // bb1 - /// _0 = move _1; // bb2 - /// ``` - /// In this case the two statements are equal iff - /// - `_0` is an enum where the variant index 0 is fieldless, and - /// - bb1 was targeted by a switch where the discriminant of `_1` was switched on - fn statement_equality( - &self, - adt_matched_on: Place<'tcx>, - x: &Statement<'tcx>, - x_target_and_value: &SwitchTargetAndValue, - y: &Statement<'tcx>, - y_target_and_value: &SwitchTargetAndValue, - ) -> StatementEquality { - let helper = |rhs: &Rvalue<'tcx>, - place: &Place<'tcx>, - variant_index: &VariantIdx, - switch_value: u128, - side_to_choose| { - let place_type = place.ty(self.body, self.tcx).ty; - let adt = match *place_type.kind() { - ty::Adt(adt, _) if adt.is_enum() => adt, - _ => return StatementEquality::NotEqual, - }; - // We need to make sure that the switch value that targets the bb with - // SetDiscriminant is the same as the variant discriminant. - let variant_discr = adt.discriminant_for_variant(self.tcx, *variant_index).val; - if variant_discr != switch_value { - trace!( - "NO: variant discriminant {} does not equal switch value {}", - variant_discr, - switch_value - ); - return StatementEquality::NotEqual; - } - let variant_is_fieldless = adt.variants[*variant_index].fields.is_empty(); - if !variant_is_fieldless { - trace!("NO: variant {:?} was not fieldless", variant_index); - return StatementEquality::NotEqual; - } - - match rhs { - Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => { - StatementEquality::ConsideredEqual(side_to_choose) - } - _ => { - trace!( - "NO: RHS of assignment was {:?}, but expected it to match the adt being matched on in the switch, which is {:?}", - rhs, - adt_matched_on - ); - StatementEquality::NotEqual - } - } - }; - match (&x.kind, &y.kind) { - // trivial case - (x, y) if x == y => StatementEquality::TrivialEqual, - - // check for case A - ( - StatementKind::Assign(box (_, rhs)), - StatementKind::SetDiscriminant { place, variant_index }, - ) if y_target_and_value.value.is_some() => { - // choose basic block of x, as that has the assign - helper( - rhs, - place, - variant_index, - y_target_and_value.value.unwrap(), - x_target_and_value.target, - ) - } - ( - StatementKind::SetDiscriminant { place, variant_index }, - StatementKind::Assign(box (_, rhs)), - ) if x_target_and_value.value.is_some() => { - // choose basic block of y, as that has the assign - helper( - rhs, - place, - variant_index, - x_target_and_value.value.unwrap(), - y_target_and_value.target, - ) - } - _ => { - trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y); - StatementEquality::NotEqual - } - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq)] -enum StatementEquality { - /// The two statements are trivially equal; same kind - TrivialEqual, - /// The two statements are considered equal, but may be of different kinds. The BasicBlock field is the basic block to jump to when performing the branch-same optimization. - /// For example, `_0 = _1` and `discriminant(_0) = discriminant(0)` are considered equal if 0 is a fieldless variant of an enum. But we don't want to jump to the basic block with the SetDiscriminant, as that is not legal if _1 is not the 0 variant index - ConsideredEqual(BasicBlock), - /// The two statements are not equal - NotEqual, -} - -impl StatementEquality { - fn combine(&self, other: &StatementEquality) -> StatementEquality { - use StatementEquality::*; - match (self, other) { - (TrivialEqual, TrivialEqual) => TrivialEqual, - (TrivialEqual, ConsideredEqual(b)) | (ConsideredEqual(b), TrivialEqual) => { - ConsideredEqual(*b) - } - (ConsideredEqual(b1), ConsideredEqual(b2)) => { - if b1 == b2 { - ConsideredEqual(*b1) - } else { - NotEqual - } - } - (_, NotEqual) | (NotEqual, _) => NotEqual, - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -//! A pass that eliminates branches on uninhabited enum variants. - -use crate::transform::MirPass; -use rustc_data_structures::stable_set::FxHashSet; -use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, - TerminatorKind, -}; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_target::abi::{Abi, Variants}; - -pub struct UninhabitedEnumBranching; - -fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option { - if let TerminatorKind::SwitchInt { discr: Operand::Move(p), .. } = terminator { - p.as_local() - } else { - None - } -} - -/// If the basic block terminates by switching on a discriminant, this returns the `Ty` the -/// discriminant is read from. Otherwise, returns None. -fn get_switched_on_type<'tcx>( - block_data: &BasicBlockData<'tcx>, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, -) -> Option> { - let terminator = block_data.terminator(); - - // Only bother checking blocks which terminate by switching on a local. - if let Some(local) = get_discriminant_local(&terminator.kind) { - let stmt_before_term = (!block_data.statements.is_empty()) - .then(|| &block_data.statements[block_data.statements.len() - 1].kind); - - if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term - { - if l.as_local() == Some(local) { - let ty = place.ty(body, tcx).ty; - if ty.is_enum() { - return Some(ty); - } - } - } - } - - None -} - -fn variant_discriminants<'tcx>( - layout: &TyAndLayout<'tcx>, - ty: Ty<'tcx>, - tcx: TyCtxt<'tcx>, -) -> FxHashSet { - match &layout.variants { - Variants::Single { index } => { - let mut res = FxHashSet::default(); - res.insert(index.as_u32() as u128); - res - } - Variants::Multiple { variants, .. } => variants - .iter_enumerated() - .filter_map(|(idx, layout)| { - (layout.abi != Abi::Uninhabited) - .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val) - }) - .collect(), - } -} - -impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if body.source.promoted.is_some() { - return; - } - - trace!("UninhabitedEnumBranching starting for {:?}", body.source); - - let basic_block_count = body.basic_blocks().len(); - - for bb in 0..basic_block_count { - let bb = BasicBlock::from_usize(bb); - trace!("processing block {:?}", bb); - - let discriminant_ty = - if let Some(ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) { - ty - } else { - continue; - }; - - let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty)); - - let allowed_variants = if let Ok(layout) = layout { - variant_discriminants(&layout, discriminant_ty, tcx) - } else { - continue; - }; - - trace!("allowed_variants = {:?}", allowed_variants); - - if let TerminatorKind::SwitchInt { targets, .. } = - &mut body.basic_blocks_mut()[bb].terminator_mut().kind - { - let new_targets = SwitchTargets::new( - targets.iter().filter(|(val, _)| allowed_variants.contains(val)), - targets.otherwise(), - ); - - *targets = new_targets; - } else { - unreachable!() - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/unreachable_prop.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/unreachable_prop.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/unreachable_prop.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/unreachable_prop.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -//! A pass that propagates the unreachable terminator of a block to its predecessors -//! when all of their successors are unreachable. This is achieved through a -//! post-order traversal of the blocks. - -use crate::transform::simplify; -use crate::transform::MirPass; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -pub struct UnreachablePropagation; - -impl MirPass<'_> for UnreachablePropagation { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.mir_opt_level() < 4 { - // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt - // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code. - return; - } - - let mut unreachable_blocks = FxHashSet::default(); - let mut replacements = FxHashMap::default(); - - for (bb, bb_data) in traversal::postorder(body) { - let terminator = bb_data.terminator(); - // HACK: If the block contains any asm statement it is not regarded as unreachable. - // This is a temporary solution that handles possibly diverging asm statements. - // Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs - let asm_stmt_in_block = || { - bb_data.statements.iter().any(|stmt: &Statement<'_>| match stmt.kind { - StatementKind::LlvmInlineAsm(..) => true, - _ => false, - }) - }; - - if terminator.kind == TerminatorKind::Unreachable && !asm_stmt_in_block() { - unreachable_blocks.insert(bb); - } else { - let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ); - let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable); - - if let Some(terminator_kind) = terminator_kind_opt { - if terminator_kind == TerminatorKind::Unreachable && !asm_stmt_in_block() { - unreachable_blocks.insert(bb); - } - replacements.insert(bb, terminator_kind); - } - } - } - - let replaced = !replacements.is_empty(); - for (bb, terminator_kind) in replacements { - if !tcx.consider_optimizing(|| { - format!("UnreachablePropagation {:?} ", body.source.def_id()) - }) { - break; - } - - body.basic_blocks_mut()[bb].terminator_mut().kind = terminator_kind; - } - - if replaced { - simplify::remove_dead_blocks(tcx, body); - } - } -} - -fn remove_successors( - terminator_kind: &TerminatorKind<'tcx>, - predicate: F, -) -> Option> -where - F: Fn(BasicBlock) -> bool, -{ - let terminator = match *terminator_kind { - TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable, - TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => { - let otherwise = targets.otherwise(); - - let original_targets_len = targets.iter().len() + 1; - let (mut values, mut targets): (Vec<_>, Vec<_>) = - targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip(); - - if !predicate(otherwise) { - targets.push(otherwise); - } else { - values.pop(); - } - - let retained_targets_len = targets.len(); - - if targets.is_empty() { - TerminatorKind::Unreachable - } else if targets.len() == 1 { - TerminatorKind::Goto { target: targets[0] } - } else if original_targets_len != retained_targets_len { - TerminatorKind::SwitchInt { - discr: discr.clone(), - switch_ty, - targets: SwitchTargets::new( - values.iter().copied().zip(targets.iter().copied()), - *targets.last().unwrap(), - ), - } - } else { - return None; - } - } - _ => return None, - }; - Some(terminator) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/validate.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/validate.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/transform/validate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/transform/validate.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,524 +0,0 @@ -//! Validates the MIR to ensure that invariants are upheld. - -use crate::dataflow::impls::MaybeStorageLive; -use crate::dataflow::{Analysis, ResultsCursor}; -use crate::util::storage::AlwaysLiveLocals; - -use super::MirPass; -use rustc_index::bit_set::BitSet; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::mir::interpret::Scalar; -use rustc_middle::mir::traversal; -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{ - AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem, - PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator, - TerminatorKind, -}; -use rustc_middle::ty::fold::BottomUpFolder; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable}; -use rustc_target::abi::Size; - -#[derive(Copy, Clone, Debug)] -enum EdgeKind { - Unwind, - Normal, -} - -pub struct Validator { - /// Describes at which point in the pipeline this validation is happening. - pub when: String, - /// The phase for which we are upholding the dialect. If the given phase forbids a specific - /// element, this validator will now emit errors if that specific element is encountered. - /// Note that phases that change the dialect cause all *following* phases to check the - /// invariants of the new dialect. A phase that changes dialects never checks the new invariants - /// itself. - pub mir_phase: MirPhase, -} - -impl<'tcx> MirPass<'tcx> for Validator { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let def_id = body.source.def_id(); - let param_env = tcx.param_env(def_id); - let mir_phase = self.mir_phase; - - let always_live_locals = AlwaysLiveLocals::new(body); - let storage_liveness = MaybeStorageLive::new(always_live_locals) - .into_engine(tcx, body) - .iterate_to_fixpoint() - .into_results_cursor(body); - - TypeChecker { - when: &self.when, - body, - tcx, - param_env, - mir_phase, - reachable_blocks: traversal::reachable_as_bitset(body), - storage_liveness, - place_cache: Vec::new(), - } - .visit_body(body); - } -} - -/// Returns whether the two types are equal up to lifetimes. -/// All lifetimes, including higher-ranked ones, get ignored for this comparison. -/// (This is unlike the `erasing_regions` methods, which keep higher-ranked lifetimes for soundness reasons.) -/// -/// The point of this function is to approximate "equal up to subtyping". However, -/// the approximation is incorrect as variance is ignored. -pub fn equal_up_to_regions( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - src: Ty<'tcx>, - dest: Ty<'tcx>, -) -> bool { - // Fast path. - if src == dest { - return true; - } - - // Normalize lifetimes away on both sides, then compare. - let param_env = param_env.with_reveal_all_normalized(tcx); - let normalize = |ty: Ty<'tcx>| { - tcx.normalize_erasing_regions( - param_env, - ty.fold_with(&mut BottomUpFolder { - tcx, - // FIXME: We erase all late-bound lifetimes, but this is not fully correct. - // If you have a type like ` fn(&'a u32) as SomeTrait>::Assoc`, - // this is not necessarily equivalent to `::Assoc`, - // since one may have an `impl SomeTrait for fn(&32)` and - // `impl SomeTrait for fn(&'static u32)` at the same time which - // specify distinct values for Assoc. (See also #56105) - lt_op: |_| tcx.lifetimes.re_erased, - // Leave consts and types unchanged. - ct_op: |ct| ct, - ty_op: |ty| ty, - }), - ) - }; - tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok()) -} - -struct TypeChecker<'a, 'tcx> { - when: &'a str, - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - mir_phase: MirPhase, - reachable_blocks: BitSet, - storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>, - place_cache: Vec>, -} - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - fn fail(&self, location: Location, msg: impl AsRef) { - let span = self.body.source_info(location).span; - // We use `delay_span_bug` as we might see broken MIR when other errors have already - // occurred. - self.tcx.sess.diagnostic().delay_span_bug( - span, - &format!( - "broken MIR in {:?} ({}) at {:?}:\n{}", - self.body.source.instance, - self.when, - location, - msg.as_ref() - ), - ); - } - - fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) { - if let Some(bb) = self.body.basic_blocks().get(bb) { - let src = self.body.basic_blocks().get(location.block).unwrap(); - match (src.is_cleanup, bb.is_cleanup, edge_kind) { - // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges - (false, false, EdgeKind::Normal) - // Non-cleanup blocks can jump to cleanup blocks along unwind edges - | (false, true, EdgeKind::Unwind) - // Cleanup blocks can jump to cleanup blocks along non-unwind edges - | (true, true, EdgeKind::Normal) => {} - // All other jumps are invalid - _ => { - self.fail( - location, - format!( - "{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})", - edge_kind, - bb, - src.is_cleanup, - bb.is_cleanup, - ) - ) - } - } - } else { - self.fail(location, format!("encountered jump to invalid basic block {:?}", bb)) - } - } - - /// Check if src can be assigned into dest. - /// This is not precise, it will accept some incorrect assignments. - fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { - // Fast path before we normalize. - if src == dest { - // Equal types, all is good. - return true; - } - // Normalize projections and things like that. - // FIXME: We need to reveal_all, as some optimizations change types in ways - // that require unfolding opaque types. - let param_env = self.param_env.with_reveal_all_normalized(self.tcx); - let src = self.tcx.normalize_erasing_regions(param_env, src); - let dest = self.tcx.normalize_erasing_regions(param_env, dest); - - // Type-changing assignments can happen when subtyping is used. While - // all normal lifetimes are erased, higher-ranked types with their - // late-bound lifetimes are still around and can lead to type - // differences. So we compare ignoring lifetimes. - equal_up_to_regions(self.tcx, param_env, src, dest) - } -} - -impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { - fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { - if self.body.local_decls.get(*local).is_none() { - self.fail( - location, - format!("local {:?} has no corresponding declaration in `body.local_decls`", local), - ); - } - - if self.reachable_blocks.contains(location.block) && context.is_use() { - // Uses of locals must occur while the local's storage is allocated. - self.storage_liveness.seek_after_primary_effect(location); - let locals_with_storage = self.storage_liveness.get(); - if !locals_with_storage.contains(*local) { - self.fail(location, format!("use of local {:?}, which has no storage here", local)); - } - } - } - - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. - if self.tcx.sess.opts.debugging_opts.validate_mir { - // `Operand::Copy` is only supposed to be used with `Copy` types. - if let Operand::Copy(place) = operand { - let ty = place.ty(&self.body.local_decls, self.tcx).ty; - let span = self.body.source_info(location).span; - - if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) { - self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty)); - } - } - } - - self.super_operand(operand, location); - } - - fn visit_projection_elem( - &mut self, - local: Local, - proj_base: &[PlaceElem<'tcx>], - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - if let ProjectionElem::Index(index) = elem { - let index_ty = self.body.local_decls[index].ty; - if index_ty != self.tcx.types.usize { - self.fail(location, format!("bad index ({:?} != usize)", index_ty)) - } - } - self.super_projection_elem(local, proj_base, elem, context, location); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - match &statement.kind { - StatementKind::Assign(box (dest, rvalue)) => { - // LHS and RHS of the assignment must have the same type. - let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty; - let right_ty = rvalue.ty(&self.body.local_decls, self.tcx); - if !self.mir_assign_valid_types(right_ty, left_ty) { - self.fail( - location, - format!( - "encountered `{:?}` with incompatible types:\n\ - left-hand side has type: {}\n\ - right-hand side has type: {}", - statement.kind, left_ty, right_ty, - ), - ); - } - match rvalue { - // The sides of an assignment must not alias. Currently this just checks whether the places - // are identical. - Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => { - if dest == src { - self.fail( - location, - "encountered `Assign` statement with overlapping memory", - ); - } - } - // The deaggregator currently does not deaggreagate arrays. - // So for now, we ignore them here. - Rvalue::Aggregate(box AggregateKind::Array { .. }, _) => {} - // All other aggregates must be gone after some phases. - Rvalue::Aggregate(box kind, _) => { - if self.mir_phase > MirPhase::DropLowering - && !matches!(kind, AggregateKind::Generator(..)) - { - // Generators persist until the state machine transformation, but all - // other aggregates must have been lowered. - self.fail( - location, - format!("{:?} have been lowered to field assignments", rvalue), - ) - } else if self.mir_phase > MirPhase::GeneratorLowering { - // No more aggregates after drop and generator lowering. - self.fail( - location, - format!("{:?} have been lowered to field assignments", rvalue), - ) - } - } - Rvalue::Ref(_, BorrowKind::Shallow, _) => { - if self.mir_phase > MirPhase::DropLowering { - self.fail( - location, - "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase", - ); - } - } - _ => {} - } - } - StatementKind::AscribeUserType(..) => { - if self.mir_phase > MirPhase::DropLowering { - self.fail( - location, - "`AscribeUserType` should have been removed after drop lowering phase", - ); - } - } - StatementKind::FakeRead(..) => { - if self.mir_phase > MirPhase::DropLowering { - self.fail( - location, - "`FakeRead` should have been removed after drop lowering phase", - ); - } - } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - ref src, - ref dst, - ref count, - }) => { - let src_ty = src.ty(&self.body.local_decls, self.tcx); - let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { - src_deref.ty - } else { - self.fail( - location, - format!("Expected src to be ptr in copy_nonoverlapping, got: {}", src_ty), - ); - return; - }; - let dst_ty = dst.ty(&self.body.local_decls, self.tcx); - let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { - dst_deref.ty - } else { - self.fail( - location, - format!("Expected dst to be ptr in copy_nonoverlapping, got: {}", dst_ty), - ); - return; - }; - // since CopyNonOverlapping is parametrized by 1 type, - // we only need to check that they are equal and not keep an extra parameter. - if op_src_ty != op_dst_ty { - self.fail(location, format!("bad arg ({:?} != {:?})", op_src_ty, op_dst_ty)); - } - - let op_cnt_ty = count.ty(&self.body.local_decls, self.tcx); - if op_cnt_ty != self.tcx.types.usize { - self.fail(location, format!("bad arg ({:?} != usize)", op_cnt_ty)) - } - } - StatementKind::SetDiscriminant { .. } - | StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::LlvmInlineAsm(..) - | StatementKind::Retag(_, _) - | StatementKind::Coverage(_) - | StatementKind::Nop => {} - } - - self.super_statement(statement, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - match &terminator.kind { - TerminatorKind::Goto { target } => { - self.check_edge(location, *target, EdgeKind::Normal); - } - TerminatorKind::SwitchInt { targets, switch_ty, discr } => { - let ty = discr.ty(&self.body.local_decls, self.tcx); - if ty != *switch_ty { - self.fail( - location, - format!( - "encountered `SwitchInt` terminator with type mismatch: {:?} != {:?}", - ty, switch_ty, - ), - ); - } - - let target_width = self.tcx.sess.target.pointer_width; - - let size = Size::from_bits(match switch_ty.kind() { - ty::Uint(uint) => uint.normalize(target_width).bit_width().unwrap(), - ty::Int(int) => int.normalize(target_width).bit_width().unwrap(), - ty::Char => 32, - ty::Bool => 1, - other => bug!("unhandled type: {:?}", other), - }); - - for (value, target) in targets.iter() { - if Scalar::<()>::try_from_uint(value, size).is_none() { - self.fail( - location, - format!("the value {:#x} is not a proper {:?}", value, switch_ty), - ) - } - - self.check_edge(location, target, EdgeKind::Normal); - } - self.check_edge(location, targets.otherwise(), EdgeKind::Normal); - } - TerminatorKind::Drop { target, unwind, .. } => { - self.check_edge(location, *target, EdgeKind::Normal); - if let Some(unwind) = unwind { - self.check_edge(location, *unwind, EdgeKind::Unwind); - } - } - TerminatorKind::DropAndReplace { target, unwind, .. } => { - if self.mir_phase > MirPhase::DropLowering { - self.fail( - location, - "`DropAndReplace` is not permitted to exist after drop elaboration", - ); - } - self.check_edge(location, *target, EdgeKind::Normal); - if let Some(unwind) = unwind { - self.check_edge(location, *unwind, EdgeKind::Unwind); - } - } - TerminatorKind::Call { func, args, destination, cleanup, .. } => { - let func_ty = func.ty(&self.body.local_decls, self.tcx); - match func_ty.kind() { - ty::FnPtr(..) | ty::FnDef(..) => {} - _ => self.fail( - location, - format!("encountered non-callable type {} in `Call` terminator", func_ty), - ), - } - if let Some((_, target)) = destination { - self.check_edge(location, *target, EdgeKind::Normal); - } - if let Some(cleanup) = cleanup { - self.check_edge(location, *cleanup, EdgeKind::Unwind); - } - - // The call destination place and Operand::Move place used as an argument might be - // passed by a reference to the callee. Consequently they must be non-overlapping. - // Currently this simply checks for duplicate places. - self.place_cache.clear(); - if let Some((destination, _)) = destination { - self.place_cache.push(destination.as_ref()); - } - for arg in args { - if let Operand::Move(place) = arg { - self.place_cache.push(place.as_ref()); - } - } - let all_len = self.place_cache.len(); - self.place_cache.sort_unstable(); - self.place_cache.dedup(); - let has_duplicates = all_len != self.place_cache.len(); - if has_duplicates { - self.fail( - location, - format!( - "encountered overlapping memory in `Call` terminator: {:?}", - terminator.kind, - ), - ); - } - } - TerminatorKind::Assert { cond, target, cleanup, .. } => { - let cond_ty = cond.ty(&self.body.local_decls, self.tcx); - if cond_ty != self.tcx.types.bool { - self.fail( - location, - format!( - "encountered non-boolean condition of type {} in `Assert` terminator", - cond_ty - ), - ); - } - self.check_edge(location, *target, EdgeKind::Normal); - if let Some(cleanup) = cleanup { - self.check_edge(location, *cleanup, EdgeKind::Unwind); - } - } - TerminatorKind::Yield { resume, drop, .. } => { - if self.mir_phase > MirPhase::GeneratorLowering { - self.fail(location, "`Yield` should have been replaced by generator lowering"); - } - self.check_edge(location, *resume, EdgeKind::Normal); - if let Some(drop) = drop { - self.check_edge(location, *drop, EdgeKind::Normal); - } - } - TerminatorKind::FalseEdge { real_target, imaginary_target } => { - self.check_edge(location, *real_target, EdgeKind::Normal); - self.check_edge(location, *imaginary_target, EdgeKind::Normal); - } - TerminatorKind::FalseUnwind { real_target, unwind } => { - self.check_edge(location, *real_target, EdgeKind::Normal); - if let Some(unwind) = unwind { - self.check_edge(location, *unwind, EdgeKind::Unwind); - } - } - TerminatorKind::InlineAsm { destination, .. } => { - if let Some(destination) = destination { - self.check_edge(location, *destination, EdgeKind::Normal); - } - } - // Nothing to validate for these. - TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::GeneratorDrop => {} - } - - self.super_terminator(terminator, location); - } - - fn visit_source_scope(&mut self, scope: &SourceScope) { - if self.body.source_scopes.get(*scope).is_none() { - self.tcx.sess.diagnostic().delay_span_bug( - self.body.span, - &format!( - "broken MIR in {:?} ({}):\ninvalid source scope {:?}", - self.body.source.instance, self.when, scope, - ), - ); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/aggregate.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/aggregate.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/aggregate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/aggregate.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -use rustc_index::vec::Idx; -use rustc_middle::mir::*; -use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_target::abi::VariantIdx; - -use std::convert::TryFrom; -use std::iter::TrustedLen; - -/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields. -/// -/// Produces something like -/// -/// (lhs as Variant).field0 = arg0; // We only have a downcast if this is an enum -/// (lhs as Variant).field1 = arg1; -/// discriminant(lhs) = variant_index; // If lhs is an enum or generator. -pub fn expand_aggregate<'tcx>( - mut lhs: Place<'tcx>, - operands: impl Iterator, Ty<'tcx>)> + TrustedLen, - kind: AggregateKind<'tcx>, - source_info: SourceInfo, - tcx: TyCtxt<'tcx>, -) -> impl Iterator> + TrustedLen { - let mut set_discriminant = None; - let active_field_index = match kind { - AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { - if adt_def.is_enum() { - set_discriminant = Some(Statement { - kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index }, - source_info, - }); - lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index); - } - active_field_index - } - AggregateKind::Generator(..) => { - // Right now we only support initializing generators to - // variant 0 (Unresumed). - let variant_index = VariantIdx::new(0); - set_discriminant = Some(Statement { - kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index }, - source_info, - }); - - // Operands are upvars stored on the base place, so no - // downcast is necessary. - - None - } - _ => None, - }; - - operands - .enumerate() - .map(move |(i, (op, ty))| { - let lhs_field = if let AggregateKind::Array(_) = kind { - let offset = u64::try_from(i).unwrap(); - tcx.mk_place_elem( - lhs, - ProjectionElem::ConstantIndex { - offset, - min_length: offset + 1, - from_end: false, - }, - ) - } else { - let field = Field::new(active_field_index.unwrap_or(i)); - tcx.mk_place_field(lhs, field, ty) - }; - Statement { - source_info, - kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))), - } - }) - .chain(set_discriminant) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/alignment.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/alignment.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/alignment.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/alignment.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::abi::Align; - -/// Returns `true` if this place is allowed to be less aligned -/// than its containing struct (because it is within a packed -/// struct). -pub fn is_disaligned<'tcx, L>( - tcx: TyCtxt<'tcx>, - local_decls: &L, - param_env: ty::ParamEnv<'tcx>, - place: Place<'tcx>, -) -> bool -where - L: HasLocalDecls<'tcx>, -{ - debug!("is_disaligned({:?})", place); - let pack = match is_within_packed(tcx, local_decls, place) { - None => { - debug!("is_disaligned({:?}) - not within packed", place); - return false; - } - Some(pack) => pack, - }; - - let ty = place.ty(local_decls, tcx).ty; - match tcx.layout_of(param_env.and(ty)) { - Ok(layout) if layout.align.abi <= pack => { - // If the packed alignment is greater or equal to the field alignment, the type won't be - // further disaligned. - debug!( - "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", - place, - layout.align.abi.bytes(), - pack.bytes() - ); - false - } - _ => { - debug!("is_disaligned({:?}) - true", place); - true - } - } -} - -fn is_within_packed<'tcx, L>( - tcx: TyCtxt<'tcx>, - local_decls: &L, - place: Place<'tcx>, -) -> Option -where - L: HasLocalDecls<'tcx>, -{ - for (place_base, elem) in place.iter_projections().rev() { - match elem { - // encountered a Deref, which is ABI-aligned - ProjectionElem::Deref => break, - ProjectionElem::Field(..) => { - let ty = place_base.ty(local_decls, tcx).ty; - match ty.kind() { - ty::Adt(def, _) => return def.repr.pack, - _ => {} - } - } - _ => {} - } - } - - None -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/borrowck_errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/borrowck_errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/borrowck_errors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/borrowck_errors.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,487 +0,0 @@ -use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId}; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::{MultiSpan, Span}; - -impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { - crate fn cannot_move_when_borrowed(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> { - struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,) - } - - crate fn cannot_use_when_mutably_borrowed( - &self, - span: Span, - desc: &str, - borrow_span: Span, - borrow_desc: &str, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - span, - E0503, - "cannot use {} because it was mutably borrowed", - desc, - ); - - err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_desc)); - err.span_label(span, format!("use of borrowed {}", borrow_desc)); - err - } - - crate fn cannot_act_on_uninitialized_variable( - &self, - span: Span, - verb: &str, - desc: &str, - ) -> DiagnosticBuilder<'cx> { - struct_span_err!( - self, - span, - E0381, - "{} of possibly-uninitialized variable: `{}`", - verb, - desc, - ) - } - - crate fn cannot_mutably_borrow_multiply( - &self, - new_loan_span: Span, - desc: &str, - opt_via: &str, - old_loan_span: Span, - old_opt_via: &str, - old_load_end_span: Option, - ) -> DiagnosticBuilder<'cx> { - let via = - |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; - let mut err = struct_span_err!( - self, - new_loan_span, - E0499, - "cannot borrow {}{} as mutable more than once at a time", - desc, - via(opt_via), - ); - if old_loan_span == new_loan_span { - // Both borrows are happening in the same place - // Meaning the borrow is occurring in a loop - err.span_label( - new_loan_span, - format!( - "{}{} was mutably borrowed here in the previous iteration of the loop{}", - desc, - via(opt_via), - opt_via, - ), - ); - if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, "mutable borrow ends here"); - } - } else { - err.span_label( - old_loan_span, - format!("first mutable borrow occurs here{}", via(old_opt_via)), - ); - err.span_label( - new_loan_span, - format!("second mutable borrow occurs here{}", via(opt_via)), - ); - if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, "first borrow ends here"); - } - } - err - } - - crate fn cannot_uniquely_borrow_by_two_closures( - &self, - new_loan_span: Span, - desc: &str, - old_loan_span: Span, - old_load_end_span: Option, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - new_loan_span, - E0524, - "two closures require unique access to {} at the same time", - desc, - ); - if old_loan_span == new_loan_span { - err.span_label( - old_loan_span, - "closures are constructed here in different iterations of loop", - ); - } else { - err.span_label(old_loan_span, "first closure is constructed here"); - err.span_label(new_loan_span, "second closure is constructed here"); - } - if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, "borrow from first closure ends here"); - } - err - } - - crate fn cannot_uniquely_borrow_by_one_closure( - &self, - new_loan_span: Span, - container_name: &str, - desc_new: &str, - opt_via: &str, - old_loan_span: Span, - noun_old: &str, - old_opt_via: &str, - previous_end_span: Option, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - new_loan_span, - E0500, - "closure requires unique access to {} but {} is already borrowed{}", - desc_new, - noun_old, - old_opt_via, - ); - err.span_label( - new_loan_span, - format!("{} construction occurs here{}", container_name, opt_via), - ); - err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via)); - if let Some(previous_end_span) = previous_end_span { - err.span_label(previous_end_span, "borrow ends here"); - } - err - } - - crate fn cannot_reborrow_already_uniquely_borrowed( - &self, - new_loan_span: Span, - container_name: &str, - desc_new: &str, - opt_via: &str, - kind_new: &str, - old_loan_span: Span, - old_opt_via: &str, - previous_end_span: Option, - second_borrow_desc: &str, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - new_loan_span, - E0501, - "cannot borrow {}{} as {} because previous closure \ - requires unique access", - desc_new, - opt_via, - kind_new, - ); - err.span_label( - new_loan_span, - format!("{}borrow occurs here{}", second_borrow_desc, opt_via), - ); - err.span_label( - old_loan_span, - format!("{} construction occurs here{}", container_name, old_opt_via), - ); - if let Some(previous_end_span) = previous_end_span { - err.span_label(previous_end_span, "borrow from closure ends here"); - } - err - } - - crate fn cannot_reborrow_already_borrowed( - &self, - span: Span, - desc_new: &str, - msg_new: &str, - kind_new: &str, - old_span: Span, - noun_old: &str, - kind_old: &str, - msg_old: &str, - old_load_end_span: Option, - ) -> DiagnosticBuilder<'cx> { - let via = - |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; - let mut err = struct_span_err!( - self, - span, - E0502, - "cannot borrow {}{} as {} because {} is also borrowed as {}{}", - desc_new, - via(msg_new), - kind_new, - noun_old, - kind_old, - via(msg_old), - ); - - if msg_new == "" { - // If `msg_new` is empty, then this isn't a borrow of a union field. - err.span_label(span, format!("{} borrow occurs here", kind_new)); - err.span_label(old_span, format!("{} borrow occurs here", kind_old)); - } else { - // If `msg_new` isn't empty, then this a borrow of a union field. - err.span_label( - span, - format!( - "{} borrow of {} -- which overlaps with {} -- occurs here", - kind_new, msg_new, msg_old, - ), - ); - err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, via(msg_old))); - } - - if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old)); - } - err - } - - crate fn cannot_assign_to_borrowed( - &self, - span: Span, - borrow_span: Span, - desc: &str, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - span, - E0506, - "cannot assign to {} because it is borrowed", - desc, - ); - - err.span_label(borrow_span, format!("borrow of {} occurs here", desc)); - err.span_label(span, format!("assignment to borrowed {} occurs here", desc)); - err - } - - crate fn cannot_reassign_immutable( - &self, - span: Span, - desc: &str, - is_arg: bool, - ) -> DiagnosticBuilder<'cx> { - let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; - struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc) - } - - crate fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> { - struct_span_err!(self, span, E0594, "cannot assign to {}", desc) - } - - crate fn cannot_move_out_of( - &self, - move_from_span: Span, - move_from_desc: &str, - ) -> DiagnosticBuilder<'cx> { - struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,) - } - - /// Signal an error due to an attempt to move out of the interior - /// of an array or slice. `is_index` is None when error origin - /// didn't capture whether there was an indexing operation or not. - crate fn cannot_move_out_of_interior_noncopy( - &self, - move_from_span: Span, - ty: Ty<'_>, - is_index: Option, - ) -> DiagnosticBuilder<'cx> { - let type_name = match (&ty.kind(), is_index) { - (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", - (&ty::Slice(_), _) => "slice", - _ => span_bug!(move_from_span, "this path should not cause illegal move"), - }; - let mut err = struct_span_err!( - self, - move_from_span, - E0508, - "cannot move out of type `{}`, a non-copy {}", - ty, - type_name, - ); - err.span_label(move_from_span, "cannot move out of here"); - err - } - - crate fn cannot_move_out_of_interior_of_drop( - &self, - move_from_span: Span, - container_ty: Ty<'_>, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - move_from_span, - E0509, - "cannot move out of type `{}`, which implements the `Drop` trait", - container_ty, - ); - err.span_label(move_from_span, "cannot move out of here"); - err - } - - crate fn cannot_act_on_moved_value( - &self, - use_span: Span, - verb: &str, - optional_adverb_for_moved: &str, - moved_path: Option, - ) -> DiagnosticBuilder<'cx> { - let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default(); - - struct_span_err!( - self, - use_span, - E0382, - "{} of {}moved value{}", - verb, - optional_adverb_for_moved, - moved_path, - ) - } - - crate fn cannot_borrow_path_as_mutable_because( - &self, - span: Span, - path: &str, - reason: &str, - ) -> DiagnosticBuilder<'cx> { - struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,) - } - - crate fn cannot_mutate_in_immutable_section( - &self, - mutate_span: Span, - immutable_span: Span, - immutable_place: &str, - immutable_section: &str, - action: &str, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - mutate_span, - E0510, - "cannot {} {} in {}", - action, - immutable_place, - immutable_section, - ); - err.span_label(mutate_span, format!("cannot {}", action)); - err.span_label(immutable_span, format!("value is immutable in {}", immutable_section)); - err - } - - crate fn cannot_borrow_across_generator_yield( - &self, - span: Span, - yield_span: Span, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - span, - E0626, - "borrow may still be in use when generator yields", - ); - err.span_label(yield_span, "possible yield occurs here"); - err - } - - crate fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> DiagnosticBuilder<'cx> { - struct_span_err!( - self, - borrow_span, - E0713, - "borrow may still be in use when destructor runs", - ) - } - - crate fn path_does_not_live_long_enough( - &self, - span: Span, - path: &str, - ) -> DiagnosticBuilder<'cx> { - struct_span_err!(self, span, E0597, "{} does not live long enough", path,) - } - - crate fn cannot_return_reference_to_local( - &self, - span: Span, - return_kind: &str, - reference_desc: &str, - path_desc: &str, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - span, - E0515, - "cannot {RETURN} {REFERENCE} {LOCAL}", - RETURN = return_kind, - REFERENCE = reference_desc, - LOCAL = path_desc, - ); - - err.span_label( - span, - format!("{}s a {} data owned by the current function", return_kind, reference_desc), - ); - - err - } - - crate fn cannot_capture_in_long_lived_closure( - &self, - closure_span: Span, - closure_kind: &str, - borrowed_path: &str, - capture_span: Span, - ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( - self, - closure_span, - E0373, - "{} may outlive the current function, \ - but it borrows {}, \ - which is owned by the current function", - closure_kind, - borrowed_path, - ); - err.span_label(capture_span, format!("{} is borrowed here", borrowed_path)) - .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path)); - err - } - - crate fn thread_local_value_does_not_live_long_enough( - &self, - span: Span, - ) -> DiagnosticBuilder<'cx> { - struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",) - } - - crate fn temporary_value_borrowed_for_too_long(&self, span: Span) -> DiagnosticBuilder<'cx> { - struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",) - } - - fn struct_span_err_with_code>( - &self, - sp: S, - msg: &str, - code: DiagnosticId, - ) -> DiagnosticBuilder<'tcx> { - self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code) - } -} - -crate fn borrowed_data_escapes_closure<'tcx>( - tcx: TyCtxt<'tcx>, - escape_span: Span, - escapes_from: &str, -) -> DiagnosticBuilder<'tcx> { - struct_span_err!( - tcx.sess, - escape_span, - E0521, - "borrowed data escapes outside of {}", - escapes_from, - ) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/collect_writes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/collect_writes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/collect_writes.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/collect_writes.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -use rustc_middle::mir::visit::PlaceContext; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Body, Local, Location}; - -crate trait FindAssignments { - // Finds all statements that assign directly to local (i.e., X = ...) - // and returns their locations. - fn find_assignments(&self, local: Local) -> Vec; -} - -impl<'tcx> FindAssignments for Body<'tcx> { - fn find_assignments(&self, local: Local) -> Vec { - let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] }; - visitor.visit_body(self); - visitor.locations - } -} - -// The Visitor walks the MIR to return the assignment statements corresponding -// to a Local. -struct FindLocalAssignmentVisitor { - needle: Local, - locations: Vec, -} - -impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { - fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) { - if self.needle != *local { - return; - } - - if place_context.is_place_assignment() { - self.locations.push(location); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/elaborate_drops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/elaborate_drops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/elaborate_drops.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/elaborate_drops.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1051 +0,0 @@ -use crate::util::patch::MirPatch; -use rustc_hir as hir; -use rustc_hir::lang_items::LangItem; -use rustc_index::vec::Idx; -use rustc_middle::mir::*; -use rustc_middle::traits::Reveal; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_target::abi::VariantIdx; -use std::fmt; - -/// The value of an inserted drop flag. -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum DropFlagState { - /// The tracked value is initialized and needs to be dropped when leaving its scope. - Present, - - /// The tracked value is uninitialized or was moved out of and does not need to be dropped when - /// leaving its scope. - Absent, -} - -impl DropFlagState { - pub fn value(self) -> bool { - match self { - DropFlagState::Present => true, - DropFlagState::Absent => false, - } - } -} - -/// Describes how/if a value should be dropped. -#[derive(Debug)] -pub enum DropStyle { - /// The value is already dead at the drop location, no drop will be executed. - Dead, - - /// The value is known to always be initialized at the drop location, drop will always be - /// executed. - Static, - - /// Whether the value needs to be dropped depends on its drop flag. - Conditional, - - /// An "open" drop is one where only the fields of a value are dropped. - /// - /// For example, this happens when moving out of a struct field: The rest of the struct will be - /// dropped in such an "open" drop. It is also used to generate drop glue for the individual - /// components of a value, for example for dropping array elements. - Open, -} - -/// Which drop flags to affect/check with an operation. -#[derive(Debug)] -pub enum DropFlagMode { - /// Only affect the top-level drop flag, not that of any contained fields. - Shallow, - /// Affect all nested drop flags in addition to the top-level one. - Deep, -} - -/// Describes if unwinding is necessary and where to unwind to if a panic occurs. -#[derive(Copy, Clone, Debug)] -pub enum Unwind { - /// Unwind to this block. - To(BasicBlock), - /// Already in an unwind path, any panic will cause an abort. - InCleanup, -} - -impl Unwind { - fn is_cleanup(self) -> bool { - match self { - Unwind::To(..) => false, - Unwind::InCleanup => true, - } - } - - fn into_option(self) -> Option { - match self { - Unwind::To(bb) => Some(bb), - Unwind::InCleanup => None, - } - } - - fn map(self, f: F) -> Self - where - F: FnOnce(BasicBlock) -> BasicBlock, - { - match self { - Unwind::To(bb) => Unwind::To(f(bb)), - Unwind::InCleanup => Unwind::InCleanup, - } - } -} - -pub trait DropElaborator<'a, 'tcx>: fmt::Debug { - /// The type representing paths that can be moved out of. - /// - /// Users can move out of individual fields of a struct, such as `a.b.c`. This type is used to - /// represent such move paths. Sometimes tracking individual move paths is not necessary, in - /// which case this may be set to (for example) `()`. - type Path: Copy + fmt::Debug; - - // Accessors - - fn patch(&mut self) -> &mut MirPatch<'tcx>; - fn body(&self) -> &'a Body<'tcx>; - fn tcx(&self) -> TyCtxt<'tcx>; - fn param_env(&self) -> ty::ParamEnv<'tcx>; - - // Drop logic - - /// Returns how `path` should be dropped, given `mode`. - fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle; - - /// Returns the drop flag of `path` as a MIR `Operand` (or `None` if `path` has no drop flag). - fn get_drop_flag(&mut self, path: Self::Path) -> Option>; - - /// Modifies the MIR patch so that the drop flag of `path` (if any) is cleared at `location`. - /// - /// If `mode` is deep, drop flags of all child paths should also be cleared by inserting - /// additional statements. - fn clear_drop_flag(&mut self, location: Location, path: Self::Path, mode: DropFlagMode); - - // Subpaths - - /// Returns the subpath of a field of `path` (or `None` if there is no dedicated subpath). - /// - /// If this returns `None`, `field` will not get a dedicated drop flag. - fn field_subpath(&self, path: Self::Path, field: Field) -> Option; - - /// Returns the subpath of a dereference of `path` (or `None` if there is no dedicated subpath). - /// - /// If this returns `None`, `*path` will not get a dedicated drop flag. - /// - /// This is only relevant for `Box`, where the contained `T` can be moved out of the box. - fn deref_subpath(&self, path: Self::Path) -> Option; - - /// Returns the subpath of downcasting `path` to one of its variants. - /// - /// If this returns `None`, the downcast of `path` will not get a dedicated drop flag. - fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option; - - /// Returns the subpath of indexing a fixed-size array `path`. - /// - /// If this returns `None`, elements of `path` will not get a dedicated drop flag. - /// - /// This is only relevant for array patterns, which can move out of individual array elements. - fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option; -} - -#[derive(Debug)] -struct DropCtxt<'l, 'b, 'tcx, D> -where - D: DropElaborator<'b, 'tcx>, -{ - elaborator: &'l mut D, - - source_info: SourceInfo, - - place: Place<'tcx>, - path: D::Path, - succ: BasicBlock, - unwind: Unwind, -} - -/// "Elaborates" a drop of `place`/`path` and patches `bb`'s terminator to execute it. -/// -/// The passed `elaborator` is used to determine what should happen at the drop terminator. It -/// decides whether the drop can be statically determined or whether it needs a dynamic drop flag, -/// and whether the drop is "open", ie. should be expanded to drop all subfields of the dropped -/// value. -/// -/// When this returns, the MIR patch in the `elaborator` contains the necessary changes. -pub fn elaborate_drop<'b, 'tcx, D>( - elaborator: &mut D, - source_info: SourceInfo, - place: Place<'tcx>, - path: D::Path, - succ: BasicBlock, - unwind: Unwind, - bb: BasicBlock, -) where - D: DropElaborator<'b, 'tcx>, - 'tcx: 'b, -{ - DropCtxt { elaborator, source_info, place, path, succ, unwind }.elaborate_drop(bb) -} - -impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> -where - D: DropElaborator<'b, 'tcx>, - 'tcx: 'b, -{ - fn place_ty(&self, place: Place<'tcx>) -> Ty<'tcx> { - place.ty(self.elaborator.body(), self.tcx()).ty - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.elaborator.tcx() - } - - /// This elaborates a single drop instruction, located at `bb`, and - /// patches over it. - /// - /// The elaborated drop checks the drop flags to only drop what - /// is initialized. - /// - /// In addition, the relevant drop flags also need to be cleared - /// to avoid double-drops. However, in the middle of a complex - /// drop, one must avoid clearing some of the flags before they - /// are read, as that would cause a memory leak. - /// - /// In particular, when dropping an ADT, multiple fields may be - /// joined together under the `rest` subpath. They are all controlled - /// by the primary drop flag, but only the last rest-field dropped - /// should clear it (and it must also not clear anything else). - // - // FIXME: I think we should just control the flags externally, - // and then we do not need this machinery. - pub fn elaborate_drop(&mut self, bb: BasicBlock) { - debug!("elaborate_drop({:?}, {:?})", bb, self); - let style = self.elaborator.drop_style(self.path, DropFlagMode::Deep); - debug!("elaborate_drop({:?}, {:?}): live - {:?}", bb, self, style); - match style { - DropStyle::Dead => { - self.elaborator - .patch() - .patch_terminator(bb, TerminatorKind::Goto { target: self.succ }); - } - DropStyle::Static => { - self.elaborator.patch().patch_terminator( - bb, - TerminatorKind::Drop { - place: self.place, - target: self.succ, - unwind: self.unwind.into_option(), - }, - ); - } - DropStyle::Conditional => { - let drop_bb = self.complete_drop(self.succ, self.unwind); - self.elaborator - .patch() - .patch_terminator(bb, TerminatorKind::Goto { target: drop_bb }); - } - DropStyle::Open => { - let drop_bb = self.open_drop(); - self.elaborator - .patch() - .patch_terminator(bb, TerminatorKind::Goto { target: drop_bb }); - } - } - } - - /// Returns the place and move path for each field of `variant`, - /// (the move path is `None` if the field is a rest field). - fn move_paths_for_fields( - &self, - base_place: Place<'tcx>, - variant_path: D::Path, - variant: &'tcx ty::VariantDef, - substs: SubstsRef<'tcx>, - ) -> Vec<(Place<'tcx>, Option)> { - variant - .fields - .iter() - .enumerate() - .map(|(i, f)| { - let field = Field::new(i); - let subpath = self.elaborator.field_subpath(variant_path, field); - let tcx = self.tcx(); - - assert_eq!(self.elaborator.param_env().reveal(), Reveal::All); - let field_ty = - tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs)); - (tcx.mk_place_field(base_place, field, field_ty), subpath) - }) - .collect() - } - - fn drop_subpath( - &mut self, - place: Place<'tcx>, - path: Option, - succ: BasicBlock, - unwind: Unwind, - ) -> BasicBlock { - if let Some(path) = path { - debug!("drop_subpath: for std field {:?}", place); - - DropCtxt { - elaborator: self.elaborator, - source_info: self.source_info, - path, - place, - succ, - unwind, - } - .elaborated_drop_block() - } else { - debug!("drop_subpath: for rest field {:?}", place); - - DropCtxt { - elaborator: self.elaborator, - source_info: self.source_info, - place, - succ, - unwind, - // Using `self.path` here to condition the drop on - // our own drop flag. - path: self.path, - } - .complete_drop(succ, unwind) - } - } - - /// Creates one-half of the drop ladder for a list of fields, and return - /// the list of steps in it in reverse order, with the first step - /// dropping 0 fields and so on. - /// - /// `unwind_ladder` is such a list of steps in reverse order, - /// which is called if the matching step of the drop glue panics. - fn drop_halfladder( - &mut self, - unwind_ladder: &[Unwind], - mut succ: BasicBlock, - fields: &[(Place<'tcx>, Option)], - ) -> Vec { - Some(succ) - .into_iter() - .chain(fields.iter().rev().zip(unwind_ladder).map(|(&(place, path), &unwind_succ)| { - succ = self.drop_subpath(place, path, succ, unwind_succ); - succ - })) - .collect() - } - - fn drop_ladder_bottom(&mut self) -> (BasicBlock, Unwind) { - // Clear the "master" drop flag at the end. This is needed - // because the "master" drop protects the ADT's discriminant, - // which is invalidated after the ADT is dropped. - (self.drop_flag_reset_block(DropFlagMode::Shallow, self.succ, self.unwind), self.unwind) - } - - /// Creates a full drop ladder, consisting of 2 connected half-drop-ladders - /// - /// For example, with 3 fields, the drop ladder is - /// - /// .d0: - /// ELAB(drop location.0 [target=.d1, unwind=.c1]) - /// .d1: - /// ELAB(drop location.1 [target=.d2, unwind=.c2]) - /// .d2: - /// ELAB(drop location.2 [target=`self.succ`, unwind=`self.unwind`]) - /// .c1: - /// ELAB(drop location.1 [target=.c2]) - /// .c2: - /// ELAB(drop location.2 [target=`self.unwind`]) - /// - /// NOTE: this does not clear the master drop flag, so you need - /// to point succ/unwind on a `drop_ladder_bottom`. - fn drop_ladder( - &mut self, - fields: Vec<(Place<'tcx>, Option)>, - succ: BasicBlock, - unwind: Unwind, - ) -> (BasicBlock, Unwind) { - debug!("drop_ladder({:?}, {:?})", self, fields); - - let mut fields = fields; - fields.retain(|&(place, _)| { - self.place_ty(place).needs_drop(self.tcx(), self.elaborator.param_env()) - }); - - debug!("drop_ladder - fields needing drop: {:?}", fields); - - let unwind_ladder = vec![Unwind::InCleanup; fields.len() + 1]; - let unwind_ladder: Vec<_> = if let Unwind::To(target) = unwind { - let halfladder = self.drop_halfladder(&unwind_ladder, target, &fields); - halfladder.into_iter().map(Unwind::To).collect() - } else { - unwind_ladder - }; - - let normal_ladder = self.drop_halfladder(&unwind_ladder, succ, &fields); - - (*normal_ladder.last().unwrap(), *unwind_ladder.last().unwrap()) - } - - fn open_drop_for_tuple(&mut self, tys: &[Ty<'tcx>]) -> BasicBlock { - debug!("open_drop_for_tuple({:?}, {:?})", self, tys); - - let fields = tys - .iter() - .enumerate() - .map(|(i, &ty)| { - ( - self.tcx().mk_place_field(self.place, Field::new(i), ty), - self.elaborator.field_subpath(self.path, Field::new(i)), - ) - }) - .collect(); - - let (succ, unwind) = self.drop_ladder_bottom(); - self.drop_ladder(fields, succ, unwind).0 - } - - fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { - debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs); - - let interior = self.tcx().mk_place_deref(self.place); - let interior_path = self.elaborator.deref_subpath(self.path); - - let succ = self.box_free_block(adt, substs, self.succ, self.unwind); - let unwind_succ = - self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup)); - - self.drop_subpath(interior, interior_path, succ, unwind_succ) - } - - fn open_drop_for_adt(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { - debug!("open_drop_for_adt({:?}, {:?}, {:?})", self, adt, substs); - if adt.variants.is_empty() { - return self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Unreachable, - }), - is_cleanup: self.unwind.is_cleanup(), - }); - } - - let skip_contents = - adt.is_union() || Some(adt.did) == self.tcx().lang_items().manually_drop(); - let contents_drop = if skip_contents { - (self.succ, self.unwind) - } else { - self.open_drop_for_adt_contents(adt, substs) - }; - - if adt.has_dtor(self.tcx()) { - self.destructor_call_block(contents_drop) - } else { - contents_drop.0 - } - } - - fn open_drop_for_adt_contents( - &mut self, - adt: &'tcx ty::AdtDef, - substs: SubstsRef<'tcx>, - ) -> (BasicBlock, Unwind) { - let (succ, unwind) = self.drop_ladder_bottom(); - if !adt.is_enum() { - let fields = self.move_paths_for_fields( - self.place, - self.path, - &adt.variants[VariantIdx::new(0)], - substs, - ); - self.drop_ladder(fields, succ, unwind) - } else { - self.open_drop_for_multivariant(adt, substs, succ, unwind) - } - } - - fn open_drop_for_multivariant( - &mut self, - adt: &'tcx ty::AdtDef, - substs: SubstsRef<'tcx>, - succ: BasicBlock, - unwind: Unwind, - ) -> (BasicBlock, Unwind) { - let mut values = Vec::with_capacity(adt.variants.len()); - let mut normal_blocks = Vec::with_capacity(adt.variants.len()); - let mut unwind_blocks = - if unwind.is_cleanup() { None } else { Some(Vec::with_capacity(adt.variants.len())) }; - - let mut have_otherwise_with_drop_glue = false; - let mut have_otherwise = false; - let tcx = self.tcx(); - - for (variant_index, discr) in adt.discriminants(tcx) { - let variant = &adt.variants[variant_index]; - let subpath = self.elaborator.downcast_subpath(self.path, variant_index); - - if let Some(variant_path) = subpath { - let base_place = tcx.mk_place_elem( - self.place, - ProjectionElem::Downcast(Some(variant.ident.name), variant_index), - ); - let fields = self.move_paths_for_fields(base_place, variant_path, &variant, substs); - values.push(discr.val); - if let Unwind::To(unwind) = unwind { - // We can't use the half-ladder from the original - // drop ladder, because this breaks the - // "funclet can't have 2 successor funclets" - // requirement from MSVC: - // - // switch unwind-switch - // / \ / \ - // v1.0 v2.0 v2.0-unwind v1.0-unwind - // | | / | - // v1.1-unwind v2.1-unwind | - // ^ | - // \-------------------------------/ - // - // Create a duplicate half-ladder to avoid that. We - // could technically only do this on MSVC, but I - // I want to minimize the divergence between MSVC - // and non-MSVC. - - let unwind_blocks = unwind_blocks.as_mut().unwrap(); - let unwind_ladder = vec![Unwind::InCleanup; fields.len() + 1]; - let halfladder = self.drop_halfladder(&unwind_ladder, unwind, &fields); - unwind_blocks.push(halfladder.last().cloned().unwrap()); - } - let (normal, _) = self.drop_ladder(fields, succ, unwind); - normal_blocks.push(normal); - } else { - have_otherwise = true; - - let param_env = self.elaborator.param_env(); - let have_field_with_drop_glue = variant - .fields - .iter() - .any(|field| field.ty(tcx, substs).needs_drop(tcx, param_env)); - if have_field_with_drop_glue { - have_otherwise_with_drop_glue = true; - } - } - } - - if !have_otherwise { - values.pop(); - } else if !have_otherwise_with_drop_glue { - normal_blocks.push(self.goto_block(succ, unwind)); - if let Unwind::To(unwind) = unwind { - unwind_blocks.as_mut().unwrap().push(self.goto_block(unwind, Unwind::InCleanup)); - } - } else { - normal_blocks.push(self.drop_block(succ, unwind)); - if let Unwind::To(unwind) = unwind { - unwind_blocks.as_mut().unwrap().push(self.drop_block(unwind, Unwind::InCleanup)); - } - } - - ( - self.adt_switch_block(adt, normal_blocks, &values, succ, unwind), - unwind.map(|unwind| { - self.adt_switch_block( - adt, - unwind_blocks.unwrap(), - &values, - unwind, - Unwind::InCleanup, - ) - }), - ) - } - - fn adt_switch_block( - &mut self, - adt: &'tcx ty::AdtDef, - blocks: Vec, - values: &[u128], - succ: BasicBlock, - unwind: Unwind, - ) -> BasicBlock { - // If there are multiple variants, then if something - // is present within the enum the discriminant, tracked - // by the rest path, must be initialized. - // - // Additionally, we do not want to switch on the - // discriminant after it is free-ed, because that - // way lies only trouble. - let discr_ty = adt.repr.discr_type().to_ty(self.tcx()); - let discr = Place::from(self.new_temp(discr_ty)); - let discr_rv = Rvalue::Discriminant(self.place); - let switch_block = BasicBlockData { - statements: vec![self.assign(discr, discr_rv)], - terminator: Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::SwitchInt { - discr: Operand::Move(discr), - switch_ty: discr_ty, - targets: SwitchTargets::new( - values.iter().copied().zip(blocks.iter().copied()), - *blocks.last().unwrap(), - ), - }, - }), - is_cleanup: unwind.is_cleanup(), - }; - let switch_block = self.elaborator.patch().new_block(switch_block); - self.drop_flag_test_block(switch_block, succ, unwind) - } - - fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { - debug!("destructor_call_block({:?}, {:?})", self, succ); - let tcx = self.tcx(); - let drop_trait = tcx.require_lang_item(LangItem::Drop, None); - let drop_fn = tcx.associated_items(drop_trait).in_definition_order().next().unwrap(); - let ty = self.place_ty(self.place); - let substs = tcx.mk_substs_trait(ty, &[]); - - let ref_ty = - tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }); - let ref_place = self.new_temp(ref_ty); - let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); - - let result = BasicBlockData { - statements: vec![self.assign( - Place::from(ref_place), - Rvalue::Ref( - tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, - self.place, - ), - )], - terminator: Some(Terminator { - kind: TerminatorKind::Call { - func: Operand::function_handle( - tcx, - drop_fn.def_id, - substs, - self.source_info.span, - ), - args: vec![Operand::Move(Place::from(ref_place))], - destination: Some((unit_temp, succ)), - cleanup: unwind.into_option(), - from_hir_call: true, - fn_span: self.source_info.span, - }, - source_info: self.source_info, - }), - is_cleanup: unwind.is_cleanup(), - }; - self.elaborator.patch().new_block(result) - } - - /// Create a loop that drops an array: - /// - /// ```text - /// loop-block: - /// can_go = cur == length_or_end - /// if can_go then succ else drop-block - /// drop-block: - /// if ptr_based { - /// ptr = cur - /// cur = cur.offset(1) - /// } else { - /// ptr = &raw mut P[cur] - /// cur = cur + 1 - /// } - /// drop(ptr) - /// ``` - fn drop_loop( - &mut self, - succ: BasicBlock, - cur: Local, - length_or_end: Place<'tcx>, - ety: Ty<'tcx>, - unwind: Unwind, - ptr_based: bool, - ) -> BasicBlock { - let copy = |place: Place<'tcx>| Operand::Copy(place); - let move_ = |place: Place<'tcx>| Operand::Move(place); - let tcx = self.tcx(); - - let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut }); - let ptr = Place::from(self.new_temp(ptr_ty)); - let can_go = Place::from(self.new_temp(tcx.types.bool)); - - let one = self.constant_usize(1); - let (ptr_next, cur_next) = if ptr_based { - ( - Rvalue::Use(copy(cur.into())), - Rvalue::BinaryOp(BinOp::Offset, Box::new((move_(cur.into()), one))), - ) - } else { - ( - Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)), - Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), - ) - }; - - let drop_block = BasicBlockData { - statements: vec![self.assign(ptr, ptr_next), self.assign(Place::from(cur), cur_next)], - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { - source_info: self.source_info, - // this gets overwritten by drop elaboration. - kind: TerminatorKind::Unreachable, - }), - }; - let drop_block = self.elaborator.patch().new_block(drop_block); - - let loop_block = BasicBlockData { - statements: vec![self.assign( - can_go, - Rvalue::BinaryOp( - BinOp::Eq, - Box::new((copy(Place::from(cur)), copy(length_or_end))), - ), - )], - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::if_(tcx, move_(can_go), succ, drop_block), - }), - }; - let loop_block = self.elaborator.patch().new_block(loop_block); - - self.elaborator.patch().patch_terminator( - drop_block, - TerminatorKind::Drop { - place: tcx.mk_place_deref(ptr), - target: loop_block, - unwind: unwind.into_option(), - }, - ); - - loop_block - } - - fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option) -> BasicBlock { - debug!("open_drop_for_array({:?}, {:?})", ety, opt_size); - - // if size_of::() == 0 { - // index_based_loop - // } else { - // ptr_based_loop - // } - - let tcx = self.tcx(); - - if let Some(size) = opt_size { - let fields: Vec<(Place<'tcx>, Option)> = (0..size) - .map(|i| { - ( - tcx.mk_place_elem( - self.place, - ProjectionElem::ConstantIndex { - offset: i, - min_length: size, - from_end: false, - }, - ), - self.elaborator.array_subpath(self.path, i, size), - ) - }) - .collect(); - - if fields.iter().any(|(_, path)| path.is_some()) { - let (succ, unwind) = self.drop_ladder_bottom(); - return self.drop_ladder(fields, succ, unwind).0; - } - } - - let move_ = |place: Place<'tcx>| Operand::Move(place); - let elem_size = Place::from(self.new_temp(tcx.types.usize)); - let len = Place::from(self.new_temp(tcx.types.usize)); - - let base_block = BasicBlockData { - statements: vec![ - self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), - self.assign(len, Rvalue::Len(self.place)), - ], - is_cleanup: self.unwind.is_cleanup(), - terminator: Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::SwitchInt { - discr: move_(elem_size), - switch_ty: tcx.types.usize, - targets: SwitchTargets::static_if( - 0, - self.drop_loop_pair(ety, false, len), - self.drop_loop_pair(ety, true, len), - ), - }, - }), - }; - self.elaborator.patch().new_block(base_block) - } - - /// Creates a pair of drop-loops of `place`, which drops its contents, even - /// in the case of 1 panic. If `ptr_based`, creates a pointer loop, - /// otherwise create an index loop. - fn drop_loop_pair( - &mut self, - ety: Ty<'tcx>, - ptr_based: bool, - length: Place<'tcx>, - ) -> BasicBlock { - debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based); - let tcx = self.tcx(); - let iter_ty = if ptr_based { tcx.mk_mut_ptr(ety) } else { tcx.types.usize }; - - let cur = self.new_temp(iter_ty); - let length_or_end = if ptr_based { Place::from(self.new_temp(iter_ty)) } else { length }; - - let unwind = self.unwind.map(|unwind| { - self.drop_loop(unwind, cur, length_or_end, ety, Unwind::InCleanup, ptr_based) - }); - - let loop_block = self.drop_loop(self.succ, cur, length_or_end, ety, unwind, ptr_based); - - let cur = Place::from(cur); - let drop_block_stmts = if ptr_based { - let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place)); - let tmp = Place::from(self.new_temp(tmp_ty)); - // tmp = &raw mut P; - // cur = tmp as *mut T; - // end = Offset(cur, len); - vec![ - self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)), - self.assign(cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)), - self.assign( - length_or_end, - Rvalue::BinaryOp( - BinOp::Offset, - Box::new((Operand::Copy(cur), Operand::Move(length))), - ), - ), - ] - } else { - // cur = 0 (length already pushed) - let zero = self.constant_usize(0); - vec![self.assign(cur, Rvalue::Use(zero))] - }; - let drop_block = self.elaborator.patch().new_block(BasicBlockData { - statements: drop_block_stmts, - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Goto { target: loop_block }, - }), - }); - - // FIXME(#34708): handle partially-dropped array/slice elements. - let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); - self.drop_flag_test_block(reset_block, self.succ, unwind) - } - - /// The slow-path - create an "open", elaborated drop for a type - /// which is moved-out-of only partially, and patch `bb` to a jump - /// to it. This must not be called on ADTs with a destructor, - /// as these can't be moved-out-of, except for `Box`, which is - /// special-cased. - /// - /// This creates a "drop ladder" that drops the needed fields of the - /// ADT, both in the success case or if one of the destructors fail. - fn open_drop(&mut self) -> BasicBlock { - let ty = self.place_ty(self.place); - match ty.kind() { - ty::Closure(_, substs) => { - let tys: Vec<_> = substs.as_closure().upvar_tys().collect(); - self.open_drop_for_tuple(&tys) - } - // Note that `elaborate_drops` only drops the upvars of a generator, - // and this is ok because `open_drop` here can only be reached - // within that own generator's resume function. - // This should only happen for the self argument on the resume function. - // It effetively only contains upvars until the generator transformation runs. - // See librustc_body/transform/generator.rs for more details. - ty::Generator(_, substs, _) => { - let tys: Vec<_> = substs.as_generator().upvar_tys().collect(); - self.open_drop_for_tuple(&tys) - } - ty::Tuple(..) => { - let tys: Vec<_> = ty.tuple_fields().collect(); - self.open_drop_for_tuple(&tys) - } - ty::Adt(def, substs) => { - if def.is_box() { - self.open_drop_for_box(def, substs) - } else { - self.open_drop_for_adt(def, substs) - } - } - ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind), - ty::Array(ety, size) => { - let size = size.try_eval_usize(self.tcx(), self.elaborator.param_env()); - self.open_drop_for_array(ety, size) - } - ty::Slice(ety) => self.open_drop_for_array(ety, None), - - _ => bug!("open drop from non-ADT `{:?}`", ty), - } - } - - fn complete_drop(&mut self, succ: BasicBlock, unwind: Unwind) -> BasicBlock { - debug!("complete_drop(succ={:?}, unwind={:?})", succ, unwind); - - let drop_block = self.drop_block(succ, unwind); - - self.drop_flag_test_block(drop_block, succ, unwind) - } - - /// Creates a block that resets the drop flag. If `mode` is deep, all children drop flags will - /// also be cleared. - fn drop_flag_reset_block( - &mut self, - mode: DropFlagMode, - succ: BasicBlock, - unwind: Unwind, - ) -> BasicBlock { - debug!("drop_flag_reset_block({:?},{:?})", self, mode); - - if unwind.is_cleanup() { - // The drop flag isn't read again on the unwind path, so don't - // bother setting it. - return succ; - } - let block = self.new_block(unwind, TerminatorKind::Goto { target: succ }); - let block_start = Location { block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, mode); - block - } - - fn elaborated_drop_block(&mut self) -> BasicBlock { - debug!("elaborated_drop_block({:?})", self); - let blk = self.drop_block(self.succ, self.unwind); - self.elaborate_drop(blk); - blk - } - - /// Creates a block that frees the backing memory of a `Box` if its drop is required (either - /// statically or by checking its drop flag). - /// - /// The contained value will not be dropped. - fn box_free_block( - &mut self, - adt: &'tcx ty::AdtDef, - substs: SubstsRef<'tcx>, - target: BasicBlock, - unwind: Unwind, - ) -> BasicBlock { - let block = self.unelaborated_free_block(adt, substs, target, unwind); - self.drop_flag_test_block(block, target, unwind) - } - - /// Creates a block that frees the backing memory of a `Box` (without dropping the contained - /// value). - fn unelaborated_free_block( - &mut self, - adt: &'tcx ty::AdtDef, - substs: SubstsRef<'tcx>, - target: BasicBlock, - unwind: Unwind, - ) -> BasicBlock { - let tcx = self.tcx(); - let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); - let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span)); - let args = adt.variants[VariantIdx::new(0)] - .fields - .iter() - .enumerate() - .map(|(i, f)| { - let field = Field::new(i); - let field_ty = f.ty(tcx, substs); - Operand::Move(tcx.mk_place_field(self.place, field, field_ty)) - }) - .collect(); - - let call = TerminatorKind::Call { - func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), - args, - destination: Some((unit_temp, target)), - cleanup: None, - from_hir_call: false, - fn_span: self.source_info.span, - }; // FIXME(#43234) - let free_block = self.new_block(unwind, call); - - let block_start = Location { block: free_block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); - free_block - } - - fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { - let block = - TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_option() }; - self.new_block(unwind, block) - } - - fn goto_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { - let block = TerminatorKind::Goto { target }; - self.new_block(unwind, block) - } - - /// Returns the block to jump to in order to test the drop flag and execute the drop. - /// - /// Depending on the required `DropStyle`, this might be a generated block with an `if` - /// terminator (for dynamic/open drops), or it might be `on_set` or `on_unset` itself, in case - /// the drop can be statically determined. - fn drop_flag_test_block( - &mut self, - on_set: BasicBlock, - on_unset: BasicBlock, - unwind: Unwind, - ) -> BasicBlock { - let style = self.elaborator.drop_style(self.path, DropFlagMode::Shallow); - debug!( - "drop_flag_test_block({:?},{:?},{:?},{:?}) - {:?}", - self, on_set, on_unset, unwind, style - ); - - match style { - DropStyle::Dead => on_unset, - DropStyle::Static => on_set, - DropStyle::Conditional | DropStyle::Open => { - let flag = self.elaborator.get_drop_flag(self.path).unwrap(); - let term = TerminatorKind::if_(self.tcx(), flag, on_set, on_unset); - self.new_block(unwind, term) - } - } - } - - fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock { - self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info: self.source_info, kind: k }), - is_cleanup: unwind.is_cleanup(), - }) - } - - fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { - self.elaborator.patch().new_temp(ty, self.source_info.span) - } - - fn constant_usize(&self, val: u16) -> Operand<'tcx> { - Operand::Constant(Box::new(Constant { - span: self.source_info.span, - user_ty: None, - literal: ty::Const::from_usize(self.tcx(), val.into()).into(), - })) - } - - fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { - Statement { - source_info: self.source_info, - kind: StatementKind::Assign(Box::new((lhs, rhs))), - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/find_self_call.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/find_self_call.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/find_self_call.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/find_self_call.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -use rustc_middle::mir::*; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::def_id::DefId; - -/// Checks if the specified `local` is used as the `self` parameter of a method call -/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is -/// returned. -pub fn find_self_call<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - local: Local, - block: BasicBlock, -) -> Option<(DefId, SubstsRef<'tcx>)> { - debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator); - if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = - &body[block].terminator - { - debug!("find_self_call: func={:?}", func); - if let Operand::Constant(box Constant { literal, .. }) = func { - if let ty::FnDef(def_id, substs) = *literal.ty().kind() { - if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = - tcx.opt_associated_item(def_id) - { - debug!("find_self_call: args={:?}", args); - if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args { - if self_place.as_local() == Some(local) { - return Some((def_id, substs)); - } - } - } - } - } - } - None -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/generic_graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/generic_graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/generic_graph.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/generic_graph.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -use gsgdt::{Edge, Graph, Node, NodeStyle}; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; - -/// Convert an MIR function into a gsgdt Graph -pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph { - let def_id = body.source.def_id(); - let def_name = graphviz_safe_def_name(def_id); - let graph_name = format!("Mir_{}", def_name); - let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; - - // Nodes - let nodes: Vec = body - .basic_blocks() - .iter_enumerated() - .map(|(block, _)| bb_to_graph_node(block, body, dark_mode)) - .collect(); - - // Edges - let mut edges = Vec::new(); - for (source, _) in body.basic_blocks().iter_enumerated() { - let def_id = body.source.def_id(); - let terminator = body[source].terminator(); - let labels = terminator.kind.fmt_successor_labels(); - - for (&target, label) in terminator.successors().zip(labels) { - let src = node(def_id, source); - let trg = node(def_id, target); - edges.push(Edge::new(src, trg, label.to_string())); - } - } - - Graph::new(graph_name, nodes, edges) -} - -fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node { - let def_id = body.source.def_id(); - let data = &body[block]; - let label = node(def_id, block); - - let (title, bgcolor) = if data.is_cleanup { - let color = if dark_mode { "royalblue" } else { "lightblue" }; - (format!("{} (cleanup)", block.index()), color) - } else { - let color = if dark_mode { "dimgray" } else { "gray" }; - (format!("{}", block.index()), color) - }; - - let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() }; - let mut stmts: Vec = data.statements.iter().map(|x| format!("{:?}", x)).collect(); - - // add the terminator to the stmts, gsgdt can print it out seperately - let mut terminator_head = String::new(); - data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); - stmts.push(terminator_head); - - Node::new(stmts, label, title, style) -} - -// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so -// it does not have to be user friendly. -pub fn graphviz_safe_def_name(def_id: DefId) -> String { - format!("{}_{}", def_id.krate.index(), def_id.index.index(),) -} - -fn node(def_id: DefId, block: BasicBlock) -> String { - format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id)) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/generic_graphviz.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/generic_graphviz.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/generic_graphviz.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/generic_graphviz.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,173 +0,0 @@ -use rustc_data_structures::graph::{self, iterate}; -use rustc_graphviz as dot; -use rustc_middle::ty::TyCtxt; -use std::io::{self, Write}; - -pub struct GraphvizWriter< - 'a, - G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes, - NodeContentFn: Fn(::Node) -> Vec, - EdgeLabelsFn: Fn(::Node) -> Vec, -> { - graph: &'a G, - is_subgraph: bool, - graphviz_name: String, - graph_label: Option, - node_content_fn: NodeContentFn, - edge_labels_fn: EdgeLabelsFn, -} - -impl< - 'a, - G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes, - NodeContentFn: Fn(::Node) -> Vec, - EdgeLabelsFn: Fn(::Node) -> Vec, -> GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn> -{ - pub fn new( - graph: &'a G, - graphviz_name: &str, - node_content_fn: NodeContentFn, - edge_labels_fn: EdgeLabelsFn, - ) -> Self { - Self { - graph, - is_subgraph: false, - graphviz_name: graphviz_name.to_owned(), - graph_label: None, - node_content_fn, - edge_labels_fn, - } - } - - pub fn set_graph_label(&mut self, graph_label: &str) { - self.graph_label = Some(graph_label.to_owned()); - } - - /// Write a graphviz DOT of the graph - pub fn write_graphviz<'tcx, W>(&self, tcx: TyCtxt<'tcx>, w: &mut W) -> io::Result<()> - where - W: Write, - { - let kind = if self.is_subgraph { "subgraph" } else { "digraph" }; - let cluster = if self.is_subgraph { "cluster_" } else { "" }; // Print border around graph - // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation, - // prepend "Mir_" to the graphviz_safe_def_name(def_id) - writeln!(w, "{} {}{} {{", kind, cluster, self.graphviz_name)?; - - // Global graph properties - let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); - let mut graph_attrs = vec![&font[..]]; - let mut content_attrs = vec![&font[..]]; - - let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; - if dark_mode { - graph_attrs.push(r#"bgcolor="black""#); - graph_attrs.push(r#"fontcolor="white""#); - content_attrs.push(r#"color="white""#); - content_attrs.push(r#"fontcolor="white""#); - } - - writeln!(w, r#" graph [{}];"#, graph_attrs.join(" "))?; - let content_attrs_str = content_attrs.join(" "); - writeln!(w, r#" node [{}];"#, content_attrs_str)?; - writeln!(w, r#" edge [{}];"#, content_attrs_str)?; - - // Graph label - if let Some(graph_label) = &self.graph_label { - self.write_graph_label(graph_label, w)?; - } - - // Nodes - for node in iterate::post_order_from(self.graph, self.graph.start_node()) { - self.write_node(node, dark_mode, w)?; - } - - // Edges - for source in iterate::post_order_from(self.graph, self.graph.start_node()) { - self.write_edges(source, w)?; - } - writeln!(w, "}}") - } - - /// Write a graphviz DOT node for the given node. - pub fn write_node(&self, node: G::Node, dark_mode: bool, w: &mut W) -> io::Result<()> - where - W: Write, - { - // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables. - write!(w, r#" {} [shape="none", label=<"#, self.node(node))?; - - write!(w, r#""#)?; - - // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation, - // we need generic way to know if node header should have a different color. For example, - // for MIR: - // - // let (blk, bgcolor) = if data.is_cleanup { - // let color = if dark_mode { "royalblue" } else { "lightblue" }; - // (format!("{:?} (cleanup)", node), color) - // } else { - // let color = if dark_mode { "dimgray" } else { "gray" }; - // (format!("{:?}", node), color) - // }; - let color = if dark_mode { "dimgray" } else { "gray" }; - let (blk, bgcolor) = (format!("{:?}", node), color); - write!( - w, - r#""#, - attrs = r#"align="center""#, - colspan = 1, - blk = blk, - bgcolor = bgcolor - )?; - - for section in (self.node_content_fn)(node) { - write!( - w, - r#""#, - dot::escape_html(§ion).replace("\n", "
") - )?; - } - - // Close the table - write!(w, "
{blk}
{}
")?; - - // Close the node label and the node itself. - writeln!(w, ">];") - } - - /// Write graphviz DOT edges with labels between the given node and all of its successors. - fn write_edges(&self, source: G::Node, w: &mut W) -> io::Result<()> - where - W: Write, - { - let edge_labels = (self.edge_labels_fn)(source); - for (index, target) in self.graph.successors(source).enumerate() { - let src = self.node(source); - let trg = self.node(target); - let escaped_edge_label = if let Some(edge_label) = edge_labels.get(index) { - dot::escape_html(edge_label).replace("\n", r#"
"#) - } else { - "".to_owned() - }; - writeln!(w, r#" {} -> {} [label=<{}>];"#, src, trg, escaped_edge_label)?; - } - Ok(()) - } - - /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that - /// will appear below the graph. - fn write_graph_label(&self, label: &str, w: &mut W) -> io::Result<()> - where - W: Write, - { - let lines = label.split('\n').map(|s| dot::escape_html(s)).collect::>(); - let escaped_label = lines.join(r#"
"#); - writeln!(w, r#" label=<

{}



>;"#, escaped_label) - } - - fn node(&self, node: G::Node) -> String { - format!("{:?}__{}", node, self.graphviz_name) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/graphviz.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/graphviz.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/graphviz.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/graphviz.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -use gsgdt::GraphvizSettings; -use rustc_graphviz as dot; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; -use std::fmt::Debug; -use std::io::{self, Write}; - -use super::generic_graph::mir_fn_to_generic_graph; -use super::pretty::dump_mir_def_ids; - -/// Write a graphviz DOT graph of a list of MIRs. -pub fn write_mir_graphviz(tcx: TyCtxt<'_>, single: Option, w: &mut W) -> io::Result<()> -where - W: Write, -{ - let def_ids = dump_mir_def_ids(tcx, single); - - let mirs = - def_ids - .iter() - .flat_map(|def_id| { - if tcx.is_const_fn_raw(*def_id) { - vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] - } else { - vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown( - *def_id, - )))] - } - }) - .collect::>(); - - let use_subgraphs = mirs.len() > 1; - if use_subgraphs { - writeln!(w, "digraph __crate__ {{")?; - } - - for mir in mirs { - write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?; - } - - if use_subgraphs { - writeln!(w, "}}")?; - } - - Ok(()) -} - -/// Write a graphviz DOT graph of the MIR. -pub fn write_mir_fn_graphviz<'tcx, W>( - tcx: TyCtxt<'tcx>, - body: &Body<'_>, - subgraph: bool, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - // Global graph properties - let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); - let mut graph_attrs = vec![&font[..]]; - let mut content_attrs = vec![&font[..]]; - - let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; - if dark_mode { - graph_attrs.push(r#"bgcolor="black""#); - graph_attrs.push(r#"fontcolor="white""#); - content_attrs.push(r#"color="white""#); - content_attrs.push(r#"fontcolor="white""#); - } - - // Graph label - let mut label = String::from(""); - // FIXME: remove this unwrap - write_graph_label(tcx, body, &mut label).unwrap(); - let g = mir_fn_to_generic_graph(tcx, body); - let settings = GraphvizSettings { - graph_attrs: Some(graph_attrs.join(" ")), - node_attrs: Some(content_attrs.join(" ")), - edge_attrs: Some(content_attrs.join(" ")), - graph_label: Some(label), - }; - g.to_dot(w, &settings, subgraph) -} - -/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that -/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of -/// all the variables and temporaries. -fn write_graph_label<'tcx, W: std::fmt::Write>( - tcx: TyCtxt<'tcx>, - body: &Body<'_>, - w: &mut W, -) -> std::fmt::Result { - let def_id = body.source.def_id(); - - write!(w, "fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?; - - // fn argument types. - for (i, arg) in body.args_iter().enumerate() { - if i > 0 { - write!(w, ", ")?; - } - write!(w, "{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))?; - } - - write!(w, ") -> {}", escape(&body.return_ty()))?; - write!(w, r#"
"#)?; - - for local in body.vars_and_temps_iter() { - let decl = &body.local_decls[local]; - - write!(w, "let ")?; - if decl.mutability == Mutability::Mut { - write!(w, "mut ")?; - } - - write!(w, r#"{:?}: {};
"#, Place::from(local), escape(&decl.ty))?; - } - - for var_debug_info in &body.var_debug_info { - write!( - w, - r#"debug {} => {};
"#, - var_debug_info.name, - escape(&var_debug_info.value), - )?; - } - - Ok(()) -} - -fn escape(t: &T) -> String { - dot::escape_html(&format!("{:?}", t)) -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -pub mod aggregate; -pub mod borrowck_errors; -pub mod elaborate_drops; -pub mod patch; -pub mod storage; - -mod alignment; -pub mod collect_writes; -mod find_self_call; -mod generic_graph; -pub(crate) mod generic_graphviz; -mod graphviz; -pub(crate) mod pretty; -pub(crate) mod spanview; - -pub use self::aggregate::expand_aggregate; -pub use self::alignment::is_disaligned; -pub use self::find_self_call::find_self_call; -pub use self::generic_graph::graphviz_safe_def_name; -pub use self::graphviz::write_mir_graphviz; -pub use self::pretty::{dump_enabled, dump_mir, write_mir_fn, write_mir_pretty, PassWhere}; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/patch.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/patch.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/patch.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/patch.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,173 +0,0 @@ -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::*; -use rustc_middle::ty::Ty; -use rustc_span::Span; - -/// This struct represents a patch to MIR, which can add -/// new statements and basic blocks and patch over block -/// terminators. -pub struct MirPatch<'tcx> { - patch_map: IndexVec>>, - new_blocks: Vec>, - new_statements: Vec<(Location, StatementKind<'tcx>)>, - new_locals: Vec>, - resume_block: BasicBlock, - next_local: usize, -} - -impl<'tcx> MirPatch<'tcx> { - pub fn new(body: &Body<'tcx>) -> Self { - let mut result = MirPatch { - patch_map: IndexVec::from_elem(None, body.basic_blocks()), - new_blocks: vec![], - new_statements: vec![], - new_locals: vec![], - next_local: body.local_decls.len(), - resume_block: START_BLOCK, - }; - - // make sure the MIR we create has a resume block. It is - // completely legal to convert jumps to the resume block - // to jumps to None, but we occasionally have to add - // instructions just before that. - - let mut resume_block = None; - let mut resume_stmt_block = None; - for (bb, block) in body.basic_blocks().iter_enumerated() { - if let TerminatorKind::Resume = block.terminator().kind { - if !block.statements.is_empty() { - assert!(resume_stmt_block.is_none()); - resume_stmt_block = Some(bb); - } else { - resume_block = Some(bb); - } - break; - } - } - let resume_block = resume_block.unwrap_or_else(|| { - result.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: SourceInfo::outermost(body.span), - kind: TerminatorKind::Resume, - }), - is_cleanup: true, - }) - }); - result.resume_block = resume_block; - if let Some(resume_stmt_block) = resume_stmt_block { - result - .patch_terminator(resume_stmt_block, TerminatorKind::Goto { target: resume_block }); - } - result - } - - pub fn resume_block(&self) -> BasicBlock { - self.resume_block - } - - pub fn is_patched(&self, bb: BasicBlock) -> bool { - self.patch_map[bb].is_some() - } - - pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location { - let offset = match bb.index().checked_sub(body.basic_blocks().len()) { - Some(index) => self.new_blocks[index].statements.len(), - None => body[bb].statements.len(), - }; - Location { block: bb, statement_index: offset } - } - - pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { - let index = self.next_local; - self.next_local += 1; - self.new_locals.push(LocalDecl::new(ty, span)); - Local::new(index as usize) - } - - pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { - let index = self.next_local; - self.next_local += 1; - self.new_locals.push(LocalDecl::new(ty, span).internal()); - Local::new(index as usize) - } - - pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { - let block = BasicBlock::new(self.patch_map.len()); - debug!("MirPatch: new_block: {:?}: {:?}", block, data); - self.new_blocks.push(data); - self.patch_map.push(None); - block - } - - pub fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) { - assert!(self.patch_map[block].is_none()); - debug!("MirPatch: patch_terminator({:?}, {:?})", block, new); - self.patch_map[block] = Some(new); - } - - pub fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) { - debug!("MirPatch: add_statement({:?}, {:?})", loc, stmt); - self.new_statements.push((loc, stmt)); - } - - pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) { - self.add_statement(loc, StatementKind::Assign(Box::new((place, rv)))); - } - - pub fn apply(self, body: &mut Body<'tcx>) { - debug!( - "MirPatch: {:?} new temps, starting from index {}: {:?}", - self.new_locals.len(), - body.local_decls.len(), - self.new_locals - ); - debug!( - "MirPatch: {} new blocks, starting from index {}", - self.new_blocks.len(), - body.basic_blocks().len() - ); - body.basic_blocks_mut().extend(self.new_blocks); - body.local_decls.extend(self.new_locals); - for (src, patch) in self.patch_map.into_iter_enumerated() { - if let Some(patch) = patch { - debug!("MirPatch: patching block {:?}", src); - body[src].terminator_mut().kind = patch; - } - } - - let mut new_statements = self.new_statements; - new_statements.sort_by_key(|s| s.0); - - let mut delta = 0; - let mut last_bb = START_BLOCK; - for (mut loc, stmt) in new_statements { - if loc.block != last_bb { - delta = 0; - last_bb = loc.block; - } - debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); - loc.statement_index += delta; - let source_info = Self::source_info_for_index(&body[loc.block], loc); - body[loc.block] - .statements - .insert(loc.statement_index, Statement { source_info, kind: stmt }); - delta += 1; - } - } - - pub fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo { - match data.statements.get(loc.statement_index) { - Some(stmt) => stmt.source_info, - None => data.terminator().source_info, - } - } - - pub fn source_info_for_location(&self, body: &Body<'_>, loc: Location) -> SourceInfo { - let data = match loc.block.index().checked_sub(body.basic_blocks().len()) { - Some(new) => &self.new_blocks[new], - None => &body[loc.block], - }; - Self::source_info_for_index(data, loc) - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/pretty.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/pretty.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/pretty.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/pretty.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1046 +0,0 @@ -use std::collections::BTreeSet; -use std::fmt::Display; -use std::fmt::Write as _; -use std::fs; -use std::io::{self, Write}; -use std::path::{Path, PathBuf}; - -use super::graphviz::write_mir_fn_graphviz; -use super::spanview::write_mir_fn_spanview; -use crate::transform::MirSource; -use either::Either; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefId; -use rustc_index::vec::Idx; -use rustc_middle::mir::interpret::{ - read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, Pointer, Provenance, -}; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; -use rustc_target::abi::Size; -use std::ops::ControlFlow; - -const INDENT: &str = " "; -/// Alignment for lining up comments following MIR statements -pub(crate) const ALIGN: usize = 40; - -/// An indication of where we are in the control flow graph. Used for printing -/// extra information in `dump_mir` -pub enum PassWhere { - /// We have not started dumping the control flow graph, but we are about to. - BeforeCFG, - - /// We just finished dumping the control flow graph. This is right before EOF - AfterCFG, - - /// We are about to start dumping the given basic block. - BeforeBlock(BasicBlock), - - /// We are just about to dump the given statement or terminator. - BeforeLocation(Location), - - /// We just dumped the given statement or terminator. - AfterLocation(Location), - - /// We just dumped the terminator for a block but not the closing `}`. - AfterTerminator(BasicBlock), -} - -/// If the session is properly configured, dumps a human-readable -/// representation of the mir into: -/// -/// ```text -/// rustc.node... -/// ``` -/// -/// Output from this function is controlled by passing `-Z dump-mir=`, -/// where `` takes the following forms: -/// -/// - `all` -- dump MIR for all fns, all passes, all everything -/// - a filter defined by a set of substrings combined with `&` and `|` -/// (`&` has higher precedence). At least one of the `|`-separated groups -/// must match; an `|`-separated group matches if all of its `&`-separated -/// substrings are matched. -/// -/// Example: -/// -/// - `nll` == match if `nll` appears in the name -/// - `foo & nll` == match if `foo` and `nll` both appear in the name -/// - `foo & nll | typeck` == match if `foo` and `nll` both appear in the name -/// or `typeck` appears in the name. -/// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name -/// or `typeck` and `bar` both appear in the name. -pub fn dump_mir<'tcx, F>( - tcx: TyCtxt<'tcx>, - pass_num: Option<&dyn Display>, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - extra_data: F, -) where - F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, -{ - if !dump_enabled(tcx, pass_name, body.source.def_id()) { - return; - } - - dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, body, extra_data); -} - -pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) -> bool { - let filters = match tcx.sess.opts.debugging_opts.dump_mir { - None => return false, - Some(ref filters) => filters, - }; - let node_path = ty::print::with_forced_impl_filename_line(|| { - // see notes on #41697 below - tcx.def_path_str(def_id) - }); - filters.split('|').any(|or_filter| { - or_filter.split('&').all(|and_filter| { - let and_filter_trimmed = and_filter.trim(); - and_filter_trimmed == "all" - || pass_name.contains(and_filter_trimmed) - || node_path.contains(and_filter_trimmed) - }) - }) -} - -// #41697 -- we use `with_forced_impl_filename_line()` because -// `def_path_str()` would otherwise trigger `type_of`, and this can -// run while we are already attempting to evaluate `type_of`. - -fn dump_matched_mir_node<'tcx, F>( - tcx: TyCtxt<'tcx>, - pass_num: Option<&dyn Display>, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - mut extra_data: F, -) where - F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, -{ - let _: io::Result<()> = try { - let mut file = - create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body.source)?; - let def_path = ty::print::with_forced_impl_filename_line(|| { - // see notes on #41697 above - tcx.def_path_str(body.source.def_id()) - }); - write!(file, "// MIR for `{}", def_path)?; - match body.source.promoted { - None => write!(file, "`")?, - Some(promoted) => write!(file, "::{:?}`", promoted)?, - } - writeln!(file, " {} {}", disambiguator, pass_name)?; - if let Some(ref layout) = body.generator_layout() { - writeln!(file, "/* generator_layout = {:#?} */", layout)?; - } - writeln!(file)?; - extra_data(PassWhere::BeforeCFG, &mut file)?; - write_user_type_annotations(tcx, body, &mut file)?; - write_mir_fn(tcx, body, &mut extra_data, &mut file)?; - extra_data(PassWhere::AfterCFG, &mut file)?; - }; - - if tcx.sess.opts.debugging_opts.dump_mir_graphviz { - let _: io::Result<()> = try { - let mut file = - create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body.source)?; - write_mir_fn_graphviz(tcx, body, false, &mut file)?; - }; - } - - if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview { - let _: io::Result<()> = try { - let file_basename = - dump_file_basename(tcx, pass_num, pass_name, disambiguator, body.source); - let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?; - if body.source.def_id().is_local() { - write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?; - } - }; - } -} - -/// Returns the file basename portion (without extension) of a filename path -/// where we should dump a MIR representation output files. -fn dump_file_basename( - tcx: TyCtxt<'_>, - pass_num: Option<&dyn Display>, - pass_name: &str, - disambiguator: &dyn Display, - source: MirSource<'tcx>, -) -> String { - let promotion_id = match source.promoted { - Some(id) => format!("-{:?}", id), - None => String::new(), - }; - - let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number { - String::new() - } else { - match pass_num { - None => ".-------".to_string(), - Some(pass_num) => format!(".{}", pass_num), - } - }; - - let crate_name = tcx.crate_name(source.def_id().krate); - let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate(); - // All drop shims have the same DefId, so we have to add the type - // to get unique file names. - let shim_disambiguator = match source.instance { - ty::InstanceDef::DropGlue(_, Some(ty)) => { - // Unfortunately, pretty-printed typed are not very filename-friendly. - // We dome some filtering. - let mut s = ".".to_owned(); - s.extend(ty.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s - } - _ => String::new(), - }; - - format!( - "{}.{}{}{}{}.{}.{}", - crate_name, item_name, shim_disambiguator, promotion_id, pass_num, pass_name, disambiguator, - ) -} - -/// Returns the path to the filename where we should dump a given MIR. -/// Also used by other bits of code (e.g., NLL inference) that dump -/// graphviz data or other things. -fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf { - let mut file_path = PathBuf::new(); - file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir)); - - let file_name = format!("{}.{}", basename, extension,); - - file_path.push(&file_name); - - file_path -} - -/// Attempts to open the MIR dump file with the given name and extension. -fn create_dump_file_with_basename( - tcx: TyCtxt<'_>, - file_basename: &str, - extension: &str, -) -> io::Result> { - let file_path = dump_path(tcx, file_basename, extension); - if let Some(parent) = file_path.parent() { - fs::create_dir_all(parent).map_err(|e| { - io::Error::new( - e.kind(), - format!("IO error creating MIR dump directory: {:?}; {}", parent, e), - ) - })?; - } - Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| { - io::Error::new(e.kind(), format!("IO error creating MIR dump file: {:?}; {}", file_path, e)) - })?)) -} - -/// Attempts to open a file where we should dump a given MIR or other -/// bit of MIR-related data. Used by `mir-dump`, but also by other -/// bits of code (e.g., NLL inference) that dump graphviz data or -/// other things, and hence takes the extension as an argument. -pub(crate) fn create_dump_file( - tcx: TyCtxt<'_>, - extension: &str, - pass_num: Option<&dyn Display>, - pass_name: &str, - disambiguator: &dyn Display, - source: MirSource<'tcx>, -) -> io::Result> { - create_dump_file_with_basename( - tcx, - &dump_file_basename(tcx, pass_num, pass_name, disambiguator, source), - extension, - ) -} - -/// Write out a human-readable textual representation for the given MIR. -pub fn write_mir_pretty<'tcx>( - tcx: TyCtxt<'tcx>, - single: Option, - w: &mut dyn Write, -) -> io::Result<()> { - writeln!(w, "// WARNING: This output format is intended for human consumers only")?; - writeln!(w, "// and is subject to change without notice. Knock yourself out.")?; - - let mut first = true; - for def_id in dump_mir_def_ids(tcx, single) { - if first { - first = false; - } else { - // Put empty lines between all items - writeln!(w)?; - } - - let render_body = |w: &mut dyn Write, body| -> io::Result<()> { - write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?; - - for body in tcx.promoted_mir(def_id) { - writeln!(w)?; - write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?; - } - Ok(()) - }; - - // For `const fn` we want to render both the optimized MIR and the MIR for ctfe. - if tcx.is_const_fn_raw(def_id) { - render_body(w, tcx.optimized_mir(def_id))?; - writeln!(w)?; - writeln!(w, "// MIR FOR CTFE")?; - // Do not use `render_body`, as that would render the promoteds again, but these - // are shared between mir_for_ctfe and optimized_mir - write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?; - } else { - let instance_mir = - tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id))); - render_body(w, instance_mir)?; - } - } - Ok(()) -} - -/// Write out a human-readable textual representation for the given function. -pub fn write_mir_fn<'tcx, F>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - extra_data: &mut F, - w: &mut dyn Write, -) -> io::Result<()> -where - F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, -{ - write_mir_intro(tcx, body, w)?; - for block in body.basic_blocks().indices() { - extra_data(PassWhere::BeforeBlock(block), w)?; - write_basic_block(tcx, block, body, extra_data, w)?; - if block.index() + 1 != body.basic_blocks().len() { - writeln!(w)?; - } - } - - writeln!(w, "}}")?; - - write_allocations(tcx, body, w)?; - - Ok(()) -} - -/// Write out a human-readable textual representation for the given basic block. -pub fn write_basic_block<'tcx, F>( - tcx: TyCtxt<'tcx>, - block: BasicBlock, - body: &Body<'tcx>, - extra_data: &mut F, - w: &mut dyn Write, -) -> io::Result<()> -where - F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, -{ - let data = &body[block]; - - // Basic block label at the top. - let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" }; - writeln!(w, "{}{:?}{}: {{", INDENT, block, cleanup_text)?; - - // List of statements in the middle. - let mut current_location = Location { block, statement_index: 0 }; - for statement in &data.statements { - extra_data(PassWhere::BeforeLocation(current_location), w)?; - let indented_body = format!("{0}{0}{1:?};", INDENT, statement); - writeln!( - w, - "{:A$} // {}{}", - indented_body, - if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, - comment(tcx, statement.source_info), - A = ALIGN, - )?; - - write_extra(tcx, w, |visitor| { - visitor.visit_statement(statement, current_location); - })?; - - extra_data(PassWhere::AfterLocation(current_location), w)?; - - current_location.statement_index += 1; - } - - // Terminator at the bottom. - extra_data(PassWhere::BeforeLocation(current_location), w)?; - let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); - writeln!( - w, - "{:A$} // {}{}", - indented_terminator, - if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, - comment(tcx, data.terminator().source_info), - A = ALIGN, - )?; - - write_extra(tcx, w, |visitor| { - visitor.visit_terminator(data.terminator(), current_location); - })?; - - extra_data(PassWhere::AfterLocation(current_location), w)?; - extra_data(PassWhere::AfterTerminator(block), w)?; - - writeln!(w, "{}}}", INDENT) -} - -/// After we print the main statement, we sometimes dump extra -/// information. There's often a lot of little things "nuzzled up" in -/// a statement. -fn write_extra<'tcx, F>(tcx: TyCtxt<'tcx>, write: &mut dyn Write, mut visit_op: F) -> io::Result<()> -where - F: FnMut(&mut ExtraComments<'tcx>), -{ - let mut extra_comments = ExtraComments { tcx, comments: vec![] }; - visit_op(&mut extra_comments); - for comment in extra_comments.comments { - writeln!(write, "{:A$} // {}", "", comment, A = ALIGN)?; - } - Ok(()) -} - -struct ExtraComments<'tcx> { - tcx: TyCtxt<'tcx>, - comments: Vec, -} - -impl ExtraComments<'tcx> { - fn push(&mut self, lines: &str) { - for line in lines.split('\n') { - self.comments.push(line.to_string()); - } - } -} - -fn use_verbose(ty: &&TyS<'tcx>, fn_def: bool) -> bool { - match ty.kind() { - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, - // Unit type - ty::Tuple(g_args) if g_args.is_empty() => false, - ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty(), fn_def)), - ty::Array(ty, _) => use_verbose(ty, fn_def), - ty::FnDef(..) => fn_def, - _ => true, - } -} - -impl Visitor<'tcx> for ExtraComments<'tcx> { - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { - self.super_constant(constant, location); - let Constant { span, user_ty, literal } = constant; - if use_verbose(&literal.ty(), true) { - self.push("mir::Constant"); - self.push(&format!( - "+ span: {}", - self.tcx.sess.source_map().span_to_embeddable_string(*span) - )); - if let Some(user_ty) = user_ty { - self.push(&format!("+ user_ty: {:?}", user_ty)); - } - match literal { - ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)), - ConstantKind::Val(val, ty) => { - // To keep the diffs small, we render this almost like we render ty::Const - self.push(&format!("+ literal: Const {{ ty: {}, val: Value({:?}) }}", ty, val)) - } - } - } - } - - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { - self.super_const(constant); - let ty::Const { ty, val, .. } = constant; - if use_verbose(ty, false) { - self.push("ty::Const"); - self.push(&format!("+ ty: {:?}", ty)); - let val = match val { - ty::ConstKind::Param(p) => format!("Param({})", p), - ty::ConstKind::Infer(infer) => format!("Infer({:?})", infer), - ty::ConstKind::Bound(idx, var) => format!("Bound({:?}, {:?})", idx, var), - ty::ConstKind::Placeholder(ph) => format!("PlaceHolder({:?})", ph), - ty::ConstKind::Unevaluated(uv) => format!( - "Unevaluated({}, {:?}, {:?})", - self.tcx.def_path_str(uv.def.did), - uv.substs(self.tcx), - uv.promoted - ), - ty::ConstKind::Value(val) => format!("Value({:?})", val), - ty::ConstKind::Error(_) => "Error".to_string(), - }; - self.push(&format!("+ val: {}", val)); - } - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - if let Rvalue::Aggregate(kind, _) = rvalue { - match **kind { - AggregateKind::Closure(def_id, substs) => { - self.push("closure"); - self.push(&format!("+ def_id: {:?}", def_id)); - self.push(&format!("+ substs: {:#?}", substs)); - } - - AggregateKind::Generator(def_id, substs, movability) => { - self.push("generator"); - self.push(&format!("+ def_id: {:?}", def_id)); - self.push(&format!("+ substs: {:#?}", substs)); - self.push(&format!("+ movability: {:?}", movability)); - } - - AggregateKind::Adt(_, _, _, Some(user_ty), _) => { - self.push("adt"); - self.push(&format!("+ user_ty: {:?}", user_ty)); - } - - _ => {} - } - } - } -} - -fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String { - format!("scope {} at {}", scope.index(), tcx.sess.source_map().span_to_embeddable_string(span)) -} - -/// Prints local variables in a scope tree. -fn write_scope_tree( - tcx: TyCtxt<'_>, - body: &Body<'_>, - scope_tree: &FxHashMap>, - w: &mut dyn Write, - parent: SourceScope, - depth: usize, -) -> io::Result<()> { - let indent = depth * INDENT.len(); - - // Local variable debuginfo. - for var_debug_info in &body.var_debug_info { - if var_debug_info.source_info.scope != parent { - // Not declared in this scope. - continue; - } - - let indented_debug_info = format!( - "{0:1$}debug {2} => {3:?};", - INDENT, indent, var_debug_info.name, var_debug_info.value, - ); - - writeln!( - w, - "{0:1$} // in {2}", - indented_debug_info, - ALIGN, - comment(tcx, var_debug_info.source_info), - )?; - } - - // Local variable types. - for (local, local_decl) in body.local_decls.iter_enumerated() { - if (1..body.arg_count + 1).contains(&local.index()) { - // Skip over argument locals, they're printed in the signature. - continue; - } - - if local_decl.source_info.scope != parent { - // Not declared in this scope. - continue; - } - - let mut_str = if local_decl.mutability == Mutability::Mut { "mut " } else { "" }; - - let mut indented_decl = - format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty); - if let Some(user_ty) = &local_decl.user_ty { - for user_ty in user_ty.projections() { - write!(indented_decl, " as {:?}", user_ty).unwrap(); - } - } - indented_decl.push(';'); - - let local_name = - if local == RETURN_PLACE { " return place".to_string() } else { String::new() }; - - writeln!( - w, - "{0:1$} //{2} in {3}", - indented_decl, - ALIGN, - local_name, - comment(tcx, local_decl.source_info), - )?; - } - - let children = match scope_tree.get(&parent) { - Some(children) => children, - None => return Ok(()), - }; - - for &child in children { - let child_data = &body.source_scopes[child]; - assert_eq!(child_data.parent_scope, Some(parent)); - - let (special, span) = if let Some((callee, callsite_span)) = child_data.inlined { - ( - format!( - " (inlined {}{})", - if callee.def.requires_caller_location(tcx) { "#[track_caller] " } else { "" }, - callee - ), - Some(callsite_span), - ) - } else { - (String::new(), None) - }; - - let indented_header = format!("{0:1$}scope {2}{3} {{", "", indent, child.index(), special); - - if let Some(span) = span { - writeln!( - w, - "{0:1$} // at {2}", - indented_header, - ALIGN, - tcx.sess.source_map().span_to_embeddable_string(span), - )?; - } else { - writeln!(w, "{}", indented_header)?; - } - - write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?; - writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?; - } - - Ok(()) -} - -/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its -/// local variables (both user-defined bindings and compiler temporaries). -pub fn write_mir_intro<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'_>, - w: &mut dyn Write, -) -> io::Result<()> { - write_mir_sig(tcx, body, w)?; - writeln!(w, "{{")?; - - // construct a scope tree and write it out - let mut scope_tree: FxHashMap> = Default::default(); - for (index, scope_data) in body.source_scopes.iter().enumerate() { - if let Some(parent) = scope_data.parent_scope { - scope_tree.entry(parent).or_default().push(SourceScope::new(index)); - } else { - // Only the argument scope has no parent, because it's the root. - assert_eq!(index, OUTERMOST_SOURCE_SCOPE.index()); - } - } - - write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?; - - // Add an empty line before the first block is printed. - writeln!(w)?; - - Ok(()) -} - -/// Find all `AllocId`s mentioned (recursively) in the MIR body and print their corresponding -/// allocations. -pub fn write_allocations<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'_>, - w: &mut dyn Write, -) -> io::Result<()> { - fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator + '_ { - alloc.relocations().values().map(|id| *id) - } - fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator + '_ { - match val { - ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _size)) => { - Either::Left(Either::Left(std::iter::once(ptr.provenance))) - } - ConstValue::Scalar(interpret::Scalar::Int { .. }) => { - Either::Left(Either::Right(std::iter::empty())) - } - ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => { - Either::Right(alloc_ids_from_alloc(alloc)) - } - } - } - struct CollectAllocIds(BTreeSet); - impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { - fn tcx_for_anon_const_substs(&self) -> Option> { - // `AllocId`s are only inside of `ConstKind::Value` which - // can't be part of the anon const default substs. - None - } - - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { - if let ty::ConstKind::Value(val) = c.val { - self.0.extend(alloc_ids_from_const(val)); - } - c.super_visit_with(self) - } - } - let mut visitor = CollectAllocIds(Default::default()); - body.visit_with(&mut visitor); - // `seen` contains all seen allocations, including the ones we have *not* printed yet. - // The protocol is to first `insert` into `seen`, and only if that returns `true` - // then push to `todo`. - let mut seen = visitor.0; - let mut todo: Vec<_> = seen.iter().copied().collect(); - while let Some(id) = todo.pop() { - let mut write_allocation_track_relocs = - |w: &mut dyn Write, alloc: &Allocation| -> io::Result<()> { - // `.rev()` because we are popping them from the back of the `todo` vector. - for id in alloc_ids_from_alloc(alloc).rev() { - if seen.insert(id) { - todo.push(id); - } - } - write!(w, "{}", display_allocation(tcx, alloc)) - }; - write!(w, "\n{}", id)?; - match tcx.get_global_alloc(id) { - // This can't really happen unless there are bugs, but it doesn't cost us anything to - // gracefully handle it and allow buggy rustc to be debugged via allocation printing. - None => write!(w, " (deallocated)")?, - Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?, - Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { - match tcx.eval_static_initializer(did) { - Ok(alloc) => { - write!(w, " (static: {}, ", tcx.def_path_str(did))?; - write_allocation_track_relocs(w, alloc)?; - } - Err(_) => write!( - w, - " (static: {}, error during initializer evaluation)", - tcx.def_path_str(did) - )?, - } - } - Some(GlobalAlloc::Static(did)) => { - write!(w, " (extern static: {})", tcx.def_path_str(did))? - } - Some(GlobalAlloc::Memory(alloc)) => { - write!(w, " (")?; - write_allocation_track_relocs(w, alloc)? - } - } - writeln!(w)?; - } - Ok(()) -} - -/// Dumps the size and metadata and content of an allocation to the given writer. -/// The expectation is that the caller first prints other relevant metadata, so the exact -/// format of this function is (*without* leading or trailing newline): -/// -/// ```text -/// size: {}, align: {}) { -/// -/// } -/// ``` -/// -/// The byte format is similar to how hex editors print bytes. Each line starts with the address of -/// the start of the line, followed by all bytes in hex format (space separated). -/// If the allocation is small enough to fit into a single line, no start address is given. -/// After the hex dump, an ascii dump follows, replacing all unprintable characters (control -/// characters or characters whose value is larger than 127) with a `.` -/// This also prints relocations adequately. -pub fn display_allocation( - tcx: TyCtxt<'tcx>, - alloc: &'a Allocation, -) -> RenderAllocation<'a, 'tcx, Tag, Extra> { - RenderAllocation { tcx, alloc } -} - -#[doc(hidden)] -pub struct RenderAllocation<'a, 'tcx, Tag, Extra> { - tcx: TyCtxt<'tcx>, - alloc: &'a Allocation, -} - -impl std::fmt::Display for RenderAllocation<'a, 'tcx, Tag, Extra> { - fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let RenderAllocation { tcx, alloc } = *self; - write!(w, "size: {}, align: {})", alloc.size().bytes(), alloc.align.bytes())?; - if alloc.size() == Size::ZERO { - // We are done. - return write!(w, " {{}}"); - } - // Write allocation bytes. - writeln!(w, " {{")?; - write_allocation_bytes(tcx, alloc, w, " ")?; - write!(w, "}}")?; - Ok(()) - } -} - -fn write_allocation_endline(w: &mut dyn std::fmt::Write, ascii: &str) -> std::fmt::Result { - for _ in 0..(BYTES_PER_LINE - ascii.chars().count()) { - write!(w, " ")?; - } - writeln!(w, " │ {}", ascii) -} - -/// Number of bytes to print per allocation hex dump line. -const BYTES_PER_LINE: usize = 16; - -/// Prints the line start address and returns the new line start address. -fn write_allocation_newline( - w: &mut dyn std::fmt::Write, - mut line_start: Size, - ascii: &str, - pos_width: usize, - prefix: &str, -) -> Result { - write_allocation_endline(w, ascii)?; - line_start += Size::from_bytes(BYTES_PER_LINE); - write!(w, "{}0x{:02$x} │ ", prefix, line_start.bytes(), pos_width)?; - Ok(line_start) -} - -/// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there -/// is only one line). Note that your prefix should contain a trailing space as the lines are -/// printed directly after it. -fn write_allocation_bytes( - tcx: TyCtxt<'tcx>, - alloc: &Allocation, - w: &mut dyn std::fmt::Write, - prefix: &str, -) -> std::fmt::Result { - let num_lines = alloc.size().bytes_usize().saturating_sub(BYTES_PER_LINE); - // Number of chars needed to represent all line numbers. - let pos_width = hex_number_length(alloc.size().bytes()); - - if num_lines > 0 { - write!(w, "{}0x{:02$x} │ ", prefix, 0, pos_width)?; - } else { - write!(w, "{}", prefix)?; - } - - let mut i = Size::ZERO; - let mut line_start = Size::ZERO; - - let ptr_size = tcx.data_layout.pointer_size; - - let mut ascii = String::new(); - - let oversized_ptr = |target: &mut String, width| { - if target.len() > width { - write!(target, " ({} ptr bytes)", ptr_size.bytes()).unwrap(); - } - }; - - while i < alloc.size() { - // The line start already has a space. While we could remove that space from the line start - // printing and unconditionally print a space here, that would cause the single-line case - // to have a single space before it, which looks weird. - if i != line_start { - write!(w, " ")?; - } - if let Some(&tag) = alloc.relocations().get(&i) { - // Memory with a relocation must be defined - let j = i.bytes_usize(); - let offset = alloc - .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize()); - let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap(); - let offset = Size::from_bytes(offset); - let relocation_width = |bytes| bytes * 3; - let ptr = Pointer::new(tag, offset); - let mut target = format!("{:?}", ptr); - if target.len() > relocation_width(ptr_size.bytes_usize() - 1) { - // This is too long, try to save some space. - target = format!("{:#?}", ptr); - } - if ((i - line_start) + ptr_size).bytes_usize() > BYTES_PER_LINE { - // This branch handles the situation where a relocation starts in the current line - // but ends in the next one. - let remainder = Size::from_bytes(BYTES_PER_LINE) - (i - line_start); - let overflow = ptr_size - remainder; - let remainder_width = relocation_width(remainder.bytes_usize()) - 2; - let overflow_width = relocation_width(overflow.bytes_usize() - 1) + 1; - ascii.push('╾'); - for _ in 0..remainder.bytes() - 1 { - ascii.push('─'); - } - if overflow_width > remainder_width && overflow_width >= target.len() { - // The case where the relocation fits into the part in the next line - write!(w, "╾{0:─^1$}", "", remainder_width)?; - line_start = - write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; - ascii.clear(); - write!(w, "{0:─^1$}╼", target, overflow_width)?; - } else { - oversized_ptr(&mut target, remainder_width); - write!(w, "╾{0:─^1$}", target, remainder_width)?; - line_start = - write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; - write!(w, "{0:─^1$}╼", "", overflow_width)?; - ascii.clear(); - } - for _ in 0..overflow.bytes() - 1 { - ascii.push('─'); - } - ascii.push('╼'); - i += ptr_size; - continue; - } else { - // This branch handles a relocation that starts and ends in the current line. - let relocation_width = relocation_width(ptr_size.bytes_usize() - 1); - oversized_ptr(&mut target, relocation_width); - ascii.push('╾'); - write!(w, "╾{0:─^1$}╼", target, relocation_width)?; - for _ in 0..ptr_size.bytes() - 2 { - ascii.push('─'); - } - ascii.push('╼'); - i += ptr_size; - } - } else if alloc.init_mask().is_range_initialized(i, i + Size::from_bytes(1)).is_ok() { - let j = i.bytes_usize(); - - // Checked definedness (and thus range) and relocations. This access also doesn't - // influence interpreter execution but is only for debugging. - let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0]; - write!(w, "{:02x}", c)?; - if c.is_ascii_control() || c >= 0x80 { - ascii.push('.'); - } else { - ascii.push(char::from(c)); - } - i += Size::from_bytes(1); - } else { - write!(w, "__")?; - ascii.push('░'); - i += Size::from_bytes(1); - } - // Print a new line header if the next line still has some bytes to print. - if i == line_start + Size::from_bytes(BYTES_PER_LINE) && i != alloc.size() { - line_start = write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; - ascii.clear(); - } - } - write_allocation_endline(w, &ascii)?; - - Ok(()) -} - -fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Result<()> { - use rustc_hir::def::DefKind; - - trace!("write_mir_sig: {:?}", body.source.instance); - let def_id = body.source.def_id(); - let kind = tcx.def_kind(def_id); - let is_function = match kind { - DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, - _ => tcx.is_closure(def_id), - }; - match (kind, body.source.promoted) { - (_, Some(i)) => write!(w, "{:?} in ", i)?, - (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?, - (DefKind::Static, _) => { - write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })? - } - (_, _) if is_function => write!(w, "fn ")?, - (DefKind::AnonConst, _) => {} // things like anon const, not an item - _ => bug!("Unexpected def kind {:?}", kind), - } - - ty::print::with_forced_impl_filename_line(|| { - // see notes on #41697 elsewhere - write!(w, "{}", tcx.def_path_str(def_id)) - })?; - - if body.source.promoted.is_none() && is_function { - write!(w, "(")?; - - // fn argument types. - for (i, arg) in body.args_iter().enumerate() { - if i != 0 { - write!(w, ", ")?; - } - write!(w, "{:?}: {}", Place::from(arg), body.local_decls[arg].ty)?; - } - - write!(w, ") -> {}", body.return_ty())?; - } else { - assert_eq!(body.arg_count, 0); - write!(w, ": {} =", body.return_ty())?; - } - - if let Some(yield_ty) = body.yield_ty() { - writeln!(w)?; - writeln!(w, "yields {}", yield_ty)?; - } - - write!(w, " ")?; - // Next thing that gets printed is the opening { - - Ok(()) -} - -fn write_user_type_annotations( - tcx: TyCtxt<'_>, - body: &Body<'_>, - w: &mut dyn Write, -) -> io::Result<()> { - if !body.user_type_annotations.is_empty() { - writeln!(w, "| User Type Annotations")?; - } - for (index, annotation) in body.user_type_annotations.iter_enumerated() { - writeln!( - w, - "| {:?}: {:?} at {}", - index.index(), - annotation.user_ty, - tcx.sess.source_map().span_to_embeddable_string(annotation.span) - )?; - } - if !body.user_type_annotations.is_empty() { - writeln!(w, "|")?; - } - Ok(()) -} - -pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { - if let Some(i) = single { - vec![i] - } else { - tcx.mir_keys(()).iter().map(|def_id| def_id.to_def_id()).collect() - } -} - -/// Calc converted u64 decimal into hex and return it's length in chars -/// -/// ```ignore (cannot-test-private-function) -/// assert_eq!(1, hex_number_length(0)); -/// assert_eq!(1, hex_number_length(1)); -/// assert_eq!(2, hex_number_length(16)); -/// ``` -fn hex_number_length(x: u64) -> usize { - if x == 0 { - return 1; - } - let mut length = 0; - let mut x_left = x; - while x_left > 0 { - x_left /= 16; - length += 1; - } - length -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/spanview.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/spanview.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/spanview.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/spanview.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,693 +0,0 @@ -use rustc_hir::def_id::DefId; -use rustc_middle::hir; -use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; -use rustc_session::config::MirSpanview; -use rustc_span::{BytePos, Pos, Span, SyntaxContext}; - -use std::cmp; -use std::io::{self, Write}; - -pub const TOOLTIP_INDENT: &str = " "; - -const CARET: char = '\u{2038}'; // Unicode `CARET` -const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET -const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` -const NEW_LINE_SPAN: &str = "
\n"; -const HEADER: &str = r#" - -"#; -const START_BODY: &str = r#" -"#; -const FOOTER: &str = r#" -"#; - -const STYLE_SECTION: &str = r#""#; - -/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. -#[derive(Clone, Debug)] -pub struct SpanViewable { - pub bb: BasicBlock, - pub span: Span, - pub id: String, - pub tooltip: String, -} - -/// Write a spanview HTML+CSS file to analyze MIR element spans. -pub fn write_mir_fn_spanview<'tcx, W>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - spanview: MirSpanview, - title: &str, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let def_id = body.source.def_id(); - let hir_body = hir_body(tcx, def_id); - if hir_body.is_none() { - return Ok(()); - } - let body_span = hir_body.unwrap().value.span; - let mut span_viewables = Vec::new(); - for (bb, data) in body.basic_blocks().iter_enumerated() { - match spanview { - MirSpanview::Statement => { - for (i, statement) in data.statements.iter().enumerate() { - if let Some(span_viewable) = - statement_span_viewable(tcx, body_span, bb, i, statement) - { - span_viewables.push(span_viewable); - } - } - if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - MirSpanview::Terminator => { - if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - MirSpanview::Block => { - if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - } - } - write_document(tcx, fn_span(tcx, def_id), span_viewables, title, w)?; - Ok(()) -} - -/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated -/// list `SpanViewable`s. -pub fn write_document<'tcx, W>( - tcx: TyCtxt<'tcx>, - spanview_span: Span, - mut span_viewables: Vec, - title: &str, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let mut from_pos = spanview_span.lo(); - let end_pos = spanview_span.hi(); - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(from_pos); - let indent_to_initial_start_col = " ".repeat(start.col.to_usize()); - debug!( - "spanview_span={:?}; source is:\n{}{}", - spanview_span, - indent_to_initial_start_col, - source_map.span_to_snippet(spanview_span).expect("function should have printable source") - ); - writeln!(w, "{}", HEADER)?; - writeln!(w, "{}", title)?; - writeln!(w, "{}", STYLE_SECTION)?; - writeln!(w, "{}", START_BODY)?; - write!( - w, - r#"
{}"#, - start.line - 1, - indent_to_initial_start_col, - )?; - span_viewables.sort_unstable_by(|a, b| { - let a = a.span; - let b = b.span; - if a.lo() == b.lo() { - // Sort hi() in reverse order so shorter spans are attempted after longer spans. - // This should give shorter spans a higher "layer", so they are not covered by - // the longer spans. - b.hi().partial_cmp(&a.hi()) - } else { - a.lo().partial_cmp(&b.lo()) - } - .unwrap() - }); - let mut ordered_viewables = &span_viewables[..]; - const LOWEST_VIEWABLE_LAYER: usize = 1; - let mut alt = false; - while ordered_viewables.len() > 0 { - debug!( - "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}", - from_pos.to_usize(), - end_pos.to_usize(), - ordered_viewables.len() - ); - let curr_id = &ordered_viewables[0].id; - let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps( - tcx, - from_pos, - end_pos, - ordered_viewables, - alt, - LOWEST_VIEWABLE_LAYER, - w, - )?; - debug!( - "DONE calling write_next_viewable, with new from_pos={}, \ - and remaining viewables len={}", - next_from_pos.to_usize(), - next_ordered_viewables.len() - ); - assert!( - from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(), - "write_next_viewable_with_overlaps() must make a state change" - ); - from_pos = next_from_pos; - if next_ordered_viewables.len() != ordered_viewables.len() { - ordered_viewables = next_ordered_viewables; - if let Some(next_ordered_viewable) = ordered_viewables.first() { - if &next_ordered_viewable.id != curr_id { - alt = !alt; - } - } - } - } - if from_pos < end_pos { - write_coverage_gap(tcx, from_pos, end_pos, w)?; - } - writeln!(w, r#"
"#)?; - writeln!(w, "{}", FOOTER)?; - Ok(()) -} - -/// Format a string showing the start line and column, and end line and column within a file. -pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String { - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(span.lo()); - let end = source_map.lookup_char_pos(span.hi()); - format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1) -} - -pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { - use StatementKind::*; - match statement.kind { - Assign(..) => "Assign", - FakeRead(..) => "FakeRead", - SetDiscriminant { .. } => "SetDiscriminant", - StorageLive(..) => "StorageLive", - StorageDead(..) => "StorageDead", - LlvmInlineAsm(..) => "LlvmInlineAsm", - Retag(..) => "Retag", - AscribeUserType(..) => "AscribeUserType", - Coverage(..) => "Coverage", - CopyNonOverlapping(..) => "CopyNonOverlapping", - Nop => "Nop", - } -} - -pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { - use TerminatorKind::*; - match term.kind { - Goto { .. } => "Goto", - SwitchInt { .. } => "SwitchInt", - Resume => "Resume", - Abort => "Abort", - Return => "Return", - Unreachable => "Unreachable", - Drop { .. } => "Drop", - DropAndReplace { .. } => "DropAndReplace", - Call { .. } => "Call", - Assert { .. } => "Assert", - Yield { .. } => "Yield", - GeneratorDrop => "GeneratorDrop", - FalseEdge { .. } => "FalseEdge", - FalseUnwind { .. } => "FalseUnwind", - InlineAsm { .. } => "InlineAsm", - } -} - -fn statement_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - i: usize, - statement: &Statement<'tcx>, -) -> Option { - let span = statement.source_info.span; - if !body_span.contains(span) { - return None; - } - let id = format!("{}[{}]", bb.index(), i); - let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn terminator_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - data: &BasicBlockData<'tcx>, -) -> Option { - let term = data.terminator(); - let span = term.source_info.span; - if !body_span.contains(span) { - return None; - } - let id = format!("{}:{}", bb.index(), terminator_kind_name(term)); - let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn block_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - data: &BasicBlockData<'tcx>, -) -> Option { - let span = compute_block_span(data, body_span); - if !body_span.contains(span) { - return None; - } - let id = format!("{}", bb.index()); - let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span { - let mut span = data.terminator().source_info.span; - for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { - // Only combine Spans from the root context, and within the function's body_span. - if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) { - span = span.to(statement_span); - } - } - span -} - -/// Recursively process each ordered span. Spans that overlap will have progressively varying -/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will -/// have alternating style choices, to help distinguish between them if, visually adjacent. -/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true -/// and false, for each adjacent non-overlapping span. Source code between the spans (code -/// that is not in any coverage region) has neutral styling. -fn write_next_viewable_with_overlaps<'tcx, 'b, W>( - tcx: TyCtxt<'tcx>, - mut from_pos: BytePos, - mut to_pos: BytePos, - ordered_viewables: &'b [SpanViewable], - alt: bool, - layer: usize, - w: &mut W, -) -> io::Result<(BytePos, &'b [SpanViewable])> -where - W: Write, -{ - let debug_indent = " ".repeat(layer); - let (viewable, mut remaining_viewables) = - ordered_viewables.split_first().expect("ordered_viewables should have some"); - - if from_pos < viewable.span.lo() { - debug!( - "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \ - of {:?}), with to_pos={}", - debug_indent, - from_pos.to_usize(), - viewable.span.lo().to_usize(), - viewable.span, - to_pos.to_usize() - ); - let hi = cmp::min(viewable.span.lo(), to_pos); - write_coverage_gap(tcx, from_pos, hi, w)?; - from_pos = hi; - if from_pos < viewable.span.lo() { - debug!( - "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}", - debug_indent, - from_pos.to_usize() - ); - return Ok((from_pos, ordered_viewables)); - } - } - - if from_pos < viewable.span.hi() { - // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing - // with room to print the tail. - to_pos = cmp::min(viewable.span.hi(), to_pos); - debug!( - "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}", - debug_indent, - viewable.span.hi().to_usize(), - to_pos.to_usize() - ); - } - - let mut subalt = false; - while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) { - let overlapping_viewable = &remaining_viewables[0]; - debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span); - - let span = - trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos)); - let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() { - // `viewable` is not yet fully rendered, so start writing the span, up to either the - // `to_pos` or the next `overlapping_viewable`, whichever comes first. - debug!( - "{}make html_snippet (may not write it if early exit) for partial span {:?} \ - of viewable.span {:?}", - debug_indent, span, viewable.span - ); - from_pos = span.hi(); - make_html_snippet(tcx, span, Some(&viewable)) - } else { - None - }; - - // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans. - // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early - // exit, there should be another opportunity to write the tail marker. - if !span.is_empty() { - if let Some(ref html_snippet) = some_html_snippet { - debug!( - "{}write html_snippet for that partial span of viewable.span {:?}", - debug_indent, viewable.span - ); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - some_html_snippet = None; - } - - if from_pos < overlapping_viewable.span.lo() { - debug!( - "{}EARLY RETURN: from_pos={} has not yet reached the \ - overlapping_viewable.span {:?}", - debug_indent, - from_pos.to_usize(), - overlapping_viewable.span - ); - // must have reached `to_pos` before reaching the start of the - // `overlapping_viewable.span` - return Ok((from_pos, ordered_viewables)); - } - - if from_pos == to_pos - && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty()) - { - debug!( - "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \ - empty, or not from_pos", - debug_indent, - to_pos.to_usize(), - overlapping_viewable.span - ); - // `to_pos` must have occurred before the overlapping viewable. Return - // `ordered_viewables` so we can continue rendering the `viewable`, from after the - // `to_pos`. - return Ok((from_pos, ordered_viewables)); - } - - if let Some(ref html_snippet) = some_html_snippet { - debug!( - "{}write html_snippet for that partial span of viewable.span {:?}", - debug_indent, viewable.span - ); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - - debug!( - "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \ - and viewables len={}", - debug_indent, - from_pos.to_usize(), - to_pos.to_usize(), - remaining_viewables.len() - ); - // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`. - let curr_id = &remaining_viewables[0].id; - let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps( - tcx, - from_pos, - to_pos, - &remaining_viewables, - subalt, - layer + 1, - w, - )?; - debug!( - "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \ - viewables len={}", - debug_indent, - next_from_pos.to_usize(), - next_remaining_viewables.len() - ); - assert!( - from_pos != next_from_pos - || remaining_viewables.len() != next_remaining_viewables.len(), - "write_next_viewable_with_overlaps() must make a state change" - ); - from_pos = next_from_pos; - if next_remaining_viewables.len() != remaining_viewables.len() { - remaining_viewables = next_remaining_viewables; - if let Some(next_ordered_viewable) = remaining_viewables.first() { - if &next_ordered_viewable.id != curr_id { - subalt = !subalt; - } - } - } - } - if from_pos <= viewable.span.hi() { - let span = trim_span(viewable.span, from_pos, to_pos); - debug!( - "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}", - debug_indent, span, viewable.span - ); - if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(&viewable)) { - from_pos = span.hi(); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - } - debug!("{}RETURN: No more overlap", debug_indent); - Ok(( - from_pos, - if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables }, - )) -} - -#[inline(always)] -fn write_coverage_gap<'tcx, W>( - tcx: TyCtxt<'tcx>, - lo: BytePos, - hi: BytePos, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let span = Span::with_root_ctxt(lo, hi); - if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) { - write_span(html_snippet, "", false, 0, w) - } else { - Ok(()) - } -} - -fn write_span( - html_snippet: &str, - tooltip: &str, - alt: bool, - layer: usize, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let maybe_alt_class = if layer > 0 { - if alt { " odd" } else { " even" } - } else { - "" - }; - let maybe_title_attr = if !tooltip.is_empty() { - format!(" title=\"{}\"", escape_attr(tooltip)) - } else { - "".to_owned() - }; - if layer == 1 { - write!(w, "")?; - } - for (i, line) in html_snippet.lines().enumerate() { - if i > 0 { - write!(w, "{}", NEW_LINE_SPAN)?; - } - write!( - w, - r#"{}"#, - maybe_alt_class, layer, maybe_title_attr, line - )?; - } - // Check for and translate trailing newlines, because `str::lines()` ignores them - if html_snippet.ends_with('\n') { - write!(w, "{}", NEW_LINE_SPAN)?; - } - if layer == 1 { - write!(w, "")?; - } - Ok(()) -} - -fn make_html_snippet<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - some_viewable: Option<&SpanViewable>, -) -> Option { - let source_map = tcx.sess.source_map(); - let snippet = source_map - .span_to_snippet(span) - .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); - let html_snippet = if let Some(viewable) = some_viewable { - let is_head = span.lo() == viewable.span.lo(); - let is_tail = span.hi() == viewable.span.hi(); - let mut labeled_snippet = if is_head { - format!(r#"{}{}"#, viewable.id, ANNOTATION_LEFT_BRACKET) - } else { - "".to_owned() - }; - if span.is_empty() { - if is_head && is_tail { - labeled_snippet.push(CARET); - } - } else { - labeled_snippet.push_str(&escape_html(&snippet)); - }; - if is_tail { - labeled_snippet.push_str(&format!( - r#"{}{}"#, - ANNOTATION_RIGHT_BRACKET, viewable.id - )); - } - labeled_snippet - } else { - escape_html(&snippet) - }; - if html_snippet.is_empty() { None } else { Some(html_snippet) } -} - -fn tooltip<'tcx>( - tcx: TyCtxt<'tcx>, - spanview_id: &str, - span: Span, - statements: Vec>, - terminator: &Option>, -) -> String { - let source_map = tcx.sess.source_map(); - let mut text = Vec::new(); - text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span))); - for statement in statements { - let source_range = source_range_no_file(tcx, &statement.source_info.span); - text.push(format!( - "\n{}{}: {}: {}", - TOOLTIP_INDENT, - source_range, - statement_kind_name(&statement), - format!("{:?}", statement) - )); - } - if let Some(term) = terminator { - let source_range = source_range_no_file(tcx, &term.source_info.span); - text.push(format!( - "\n{}{}: {}: {:?}", - TOOLTIP_INDENT, - source_range, - terminator_kind_name(term), - term.kind - )); - } - text.join("") -} - -fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span { - trim_span_hi(trim_span_lo(span, from_pos), to_pos) -} - -fn trim_span_lo(span: Span, from_pos: BytePos) -> Span { - if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) } -} - -fn trim_span_hi(span: Span, to_pos: BytePos) -> Span { - if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) } -} - -fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { - let hir_id = - tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); - let fn_decl_span = tcx.hir().span(hir_id); - if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) { - if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span } - } else { - fn_decl_span - } -} - -fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<&'tcx rustc_hir::Body<'tcx>> { - let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id)) -} - -fn escape_html(s: &str) -> String { - s.replace("&", "&").replace("<", "<").replace(">", ">") -} - -fn escape_attr(s: &str) -> String { - s.replace("&", "&") - .replace("\"", """) - .replace("'", "'") - .replace("<", "<") - .replace(">", ">") -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/storage.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/storage.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir/src/util/storage.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir/src/util/storage.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, Local}; - -/// The set of locals in a MIR body that do not have `StorageLive`/`StorageDead` annotations. -/// -/// These locals have fixed storage for the duration of the body. -// -// FIXME: Currently, we need to traverse the entire MIR to compute this. We should instead store it -// as a field in the `LocalDecl` for each `Local`. -#[derive(Debug, Clone)] -pub struct AlwaysLiveLocals(BitSet); - -impl AlwaysLiveLocals { - pub fn new(body: &mir::Body<'tcx>) -> Self { - let mut always_live_locals = AlwaysLiveLocals(BitSet::new_filled(body.local_decls.len())); - - for block in body.basic_blocks() { - for statement in &block.statements { - use mir::StatementKind::{StorageDead, StorageLive}; - if let StorageLive(l) | StorageDead(l) = statement.kind { - always_live_locals.0.remove(l); - } - } - } - - always_live_locals - } - - pub fn into_inner(self) -> BitSet { - self.0 - } -} - -impl std::ops::Deref for AlwaysLiveLocals { - type Target = BitSet; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_mir_build" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/as_operand.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/as_operand.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/as_operand.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/as_operand.rs 2021-11-29 19:27:11.000000000 +0000 @@ -20,7 +20,7 @@ expr: &Expr<'tcx>, ) -> BlockAnd> { let local_scope = self.local_scope(); - self.as_operand(block, Some(local_scope), expr) + self.as_operand(block, Some(local_scope), expr, None) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -85,6 +85,11 @@ /// temporary `tmp = x`, so that we capture the value of `x` at /// this time. /// + /// If we end up needing to create a temporary, then we will use + /// `local_info` as its `LocalInfo`, unless `as_temporary` + /// has already assigned it a non-`None` `LocalInfo`. + /// Normally, you should use `None` for `local_info` + /// /// The operand is known to be live until the end of `scope`. /// /// Like `as_local_call_operand`, except that the argument will @@ -94,15 +99,16 @@ mut block: BasicBlock, scope: Option, expr: &Expr<'tcx>, + local_info: Option>>, ) -> BlockAnd> { - debug!("as_operand(block={:?}, expr={:?})", block, expr); + debug!("as_operand(block={:?}, expr={:?} local_info={:?})", block, expr, local_info); let this = self; if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { - this.as_operand(block, scope, &this.thir[value]) + this.as_operand(block, scope, &this.thir[value], local_info) }); } @@ -115,6 +121,9 @@ } Category::Place | Category::Rvalue(..) => { let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut)); + if this.local_decls[operand].local_info.is_none() { + this.local_decls[operand].local_info = local_info; + } block.and(Operand::Move(Place::from(operand))) } } @@ -167,6 +176,6 @@ } } - this.as_operand(block, scope, expr) + this.as_operand(block, scope, expr, None) } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,6 +5,7 @@ use crate::build::expr::as_place::PlaceBase; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use rustc_hir::lang_items::LangItem; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind; use rustc_middle::mir::Place; @@ -52,16 +53,16 @@ } ExprKind::Repeat { value, count } => { let value_operand = - unpack!(block = this.as_operand(block, scope, &this.thir[value])); + unpack!(block = this.as_operand(block, scope, &this.thir[value], None)); block.and(Rvalue::Repeat(value_operand, count)) } ExprKind::Binary { op, lhs, rhs } => { - let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs])); - let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs])); + let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs], None)); + let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs], None)); this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs) } ExprKind::Unary { op, arg } => { - let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg])); + let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg], None)); // Check for -MIN on signed integers if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() { let bool_ty = this.tcx.types.bool; @@ -88,6 +89,56 @@ } ExprKind::Box { value } => { let value = &this.thir[value]; + let tcx = this.tcx; + + // `exchange_malloc` is unsafe but box is safe, so need a new scope. + let synth_scope = this.new_source_scope( + expr_span, + LintLevel::Inherited, + Some(Safety::BuiltinUnsafe), + ); + let synth_info = SourceInfo { span: expr_span, scope: synth_scope }; + + let size = this.temp(tcx.types.usize, expr_span); + this.cfg.push_assign( + block, + synth_info, + size, + Rvalue::NullaryOp(NullOp::SizeOf, value.ty), + ); + + let align = this.temp(tcx.types.usize, expr_span); + this.cfg.push_assign( + block, + synth_info, + align, + Rvalue::NullaryOp(NullOp::AlignOf, value.ty), + ); + + // malloc some memory of suitable size and align: + let exchange_malloc = Operand::function_handle( + tcx, + tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)), + ty::List::empty(), + expr_span, + ); + let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span); + let success = this.cfg.start_new_block(); + this.cfg.terminate( + block, + synth_info, + TerminatorKind::Call { + func: exchange_malloc, + args: vec![Operand::Move(size), Operand::Move(align)], + destination: Some((storage, success)), + cleanup: None, + from_hir_call: false, + fn_span: expr_span, + }, + ); + this.diverge_from(block); + block = success; + // The `Box` temporary created here is not a part of the HIR, // and therefore is not considered during generator auto-trait // determination. See the comment about `box` at `yield_in_scope`. @@ -101,8 +152,8 @@ this.schedule_drop_storage_and_value(expr_span, scope, result); } - // malloc some memory of suitable type (thus far, uninitialized): - let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); + // Transmute `*mut u8` to the box (thus far, uninitialized): + let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value.ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); // initialize the box contents: @@ -116,11 +167,13 @@ block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { - let source = unpack!(block = this.as_operand(block, scope, &this.thir[source])); + let source = + unpack!(block = this.as_operand(block, scope, &this.thir[source], None)); block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) } ExprKind::Pointer { cast, source } => { - let source = unpack!(block = this.as_operand(block, scope, &this.thir[source])); + let source = + unpack!(block = this.as_operand(block, scope, &this.thir[source], None)); block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) } ExprKind::Array { ref fields } => { @@ -155,7 +208,7 @@ let fields: Vec<_> = fields .into_iter() .copied() - .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f]))) + .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f], None))) .collect(); block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(el_ty)), fields)) @@ -166,7 +219,7 @@ let fields: Vec<_> = fields .into_iter() .copied() - .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f]))) + .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f], None))) .collect(); block.and(Rvalue::Aggregate(Box::new(AggregateKind::Tuple), fields)) @@ -242,7 +295,9 @@ &this.thir[arg], ) ), - _ => unpack!(block = this.as_operand(block, scope, upvar)), + _ => { + unpack!(block = this.as_operand(block, scope, upvar, None)) + } } } } @@ -304,7 +359,7 @@ Category::of(&expr.kind), Some(Category::Rvalue(RvalueFunc::AsRvalue)) )); - let operand = unpack!(block = this.as_operand(block, scope, expr)); + let operand = unpack!(block = this.as_operand(block, scope, expr, None)); block.and(Rvalue::Use(operand)) } } @@ -494,9 +549,8 @@ // Helper to get a `-1` value of the appropriate type fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let param_ty = ty::ParamEnv::empty().and(ty); - let bits = self.tcx.layout_of(param_ty).unwrap().size.bits(); - let n = (!0u128) >> (128 - bits); - let literal = ty::Const::from_bits(self.tcx, n, param_ty); + let size = self.tcx.layout_of(param_ty).unwrap().size; + let literal = ty::Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty); self.literal_operand(span, literal) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/into.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/into.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/into.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/expr/into.rs 2021-11-29 19:27:11.000000000 +0000 @@ -326,10 +326,16 @@ let fields_map: FxHashMap<_, _> = fields .into_iter() .map(|f| { + let local_info = Box::new(LocalInfo::AggregateTemp); ( f.name, unpack!( - block = this.as_operand(block, Some(scope), &this.thir[f.expr]) + block = this.as_operand( + block, + Some(scope), + &this.thir[f.expr], + Some(local_info) + ) ), ) }) @@ -443,8 +449,11 @@ }) .collect(); - let destination = this.cfg.start_new_block(); + if !options.contains(InlineAsmOptions::NORETURN) { + this.cfg.push_assign_unit(block, source_info, destination, this.tcx); + } + let destination_block = this.cfg.start_new_block(); this.cfg.terminate( block, source_info, @@ -456,11 +465,11 @@ destination: if options.contains(InlineAsmOptions::NORETURN) { None } else { - Some(destination) + Some(destination_block) }, }, ); - destination.unit() + destination_block.unit() } // These cases don't actually need a destination @@ -508,7 +517,8 @@ ExprKind::Yield { value } => { let scope = this.local_scope(); - let value = unpack!(block = this.as_operand(block, Some(scope), &this.thir[value])); + let value = + unpack!(block = this.as_operand(block, Some(scope), &this.thir[value], None)); let resume = this.cfg.start_new_block(); this.cfg.terminate( block, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/matches/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/matches/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/matches/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/matches/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -900,10 +900,7 @@ struct Binding<'tcx> { span: Span, source: Place<'tcx>, - name: Symbol, var_id: HirId, - var_ty: Ty<'tcx>, - mutability: Mutability, binding_mode: BindingMode, } @@ -2063,7 +2060,7 @@ source_info.span, ascription.source, ascription.user_ty, ); - let user_ty = ascription.user_ty.clone().user_ty( + let user_ty = ascription.user_ty.user_ty( &mut self.canonical_user_type_annotations, ascription.source.ty(&self.local_decls, self.tcx).ty, source_info.span, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/matches/simplify.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/matches/simplify.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/matches/simplify.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/matches/simplify.rs 2021-11-29 19:27:11.000000000 +0000 @@ -176,17 +176,22 @@ Ok(()) } - PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => { + PatKind::Binding { + name: _, + mutability: _, + mode, + var, + ty: _, + ref subpattern, + is_primary: _, + } => { if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) { candidate.bindings.push(Binding { - name, - mutability, span: match_pair.pattern.span, source: place_resolved.into_place(self.tcx, self.typeck_results), var_id: var, - var_ty: ty, binding_mode: mode, }); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -44,13 +44,18 @@ let body_owner_kind = tcx.hir().body_owner_kind(id); let typeck_results = tcx.typeck_opt_const_arg(def); - // Ensure unsafeck is ran before we steal the THIR. + // Ensure unsafeck and abstract const building is ran before we steal the THIR. + // We can't use `ensure()` for `thir_abstract_const` as it doesn't compute the query + // if inputs are green. This can cause ICEs when calling `thir_abstract_const` after + // THIR has been stolen if we haven't computed this query yet. match def { ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { - tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)) + tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)); + drop(tcx.thir_abstract_const_of_const_arg((did, const_param_did))); } ty::WithOptConstParam { did, const_param_did: None } => { - tcx.ensure().thir_check_unsafety(did) + tcx.ensure().thir_check_unsafety(did); + drop(tcx.thir_abstract_const(did)); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/scope.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/scope.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/scope.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/build/scope.rs 2021-11-29 19:27:11.000000000 +0000 @@ -118,9 +118,6 @@ /// the region span of this scope within source code. region_scope: region::Scope, - /// the span of that region_scope - region_scope_span: Span, - /// set of places to drop when exiting this scope. This starts /// out empty but grows as variables are declared during the /// building process. This is a stack, so we always drop from the @@ -420,7 +417,6 @@ self.scopes.push(Scope { source_scope: vis_scope, region_scope: region_scope.0, - region_scope_span: region_scope.1.span, drops: vec![], moved_locals: vec![], cached_unwind_block: None, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/check_unsafety.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/check_unsafety.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/check_unsafety.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/check_unsafety.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ use crate::build::ExprCategory; -use crate::thir::visit::{self, Visitor}; +use rustc_middle::thir::visit::{self, Visitor}; use rustc_errors::struct_span_err; use rustc_hir as hir; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/cx/expr.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/cx/expr.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/cx/expr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/cx/expr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -39,10 +39,17 @@ let mut expr = self.make_mirror_unadjusted(hir_expr); + let adjustment_span = match self.adjustment_span { + Some((hir_id, span)) if hir_id == hir_expr.hir_id => Some(span), + _ => None, + }; + // Now apply adjustments, if any. for adjustment in self.typeck_results.expr_adjustments(hir_expr) { debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment); - expr = self.apply_adjustment(hir_expr, expr, adjustment); + let span = expr.span; + expr = + self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span)); } // Next, wrap this up in the expr's scope. @@ -82,8 +89,9 @@ hir_expr: &'tcx hir::Expr<'tcx>, mut expr: Expr<'tcx>, adjustment: &Adjustment<'tcx>, + mut span: Span, ) -> Expr<'tcx> { - let Expr { temp_lifetime, mut span, .. } = expr; + let Expr { temp_lifetime, .. } = expr; // Adjust the span from the block, to the last expression of the // block. This is a better span when returning a mutable reference @@ -150,6 +158,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let expr_ty = self.typeck_results().expr_ty(expr); + let expr_span = expr.span; let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); let kind = match expr.kind { @@ -157,7 +166,13 @@ hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) let expr = self.method_callee(expr, method_span, None); + // When we apply adjustments to the receiver, use the span of + // the overall method call for better diagnostics. args[0] + // is guaranteed to exist, since a method call always has a receiver. + let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span)); + tracing::info!("Using method span: {:?}", expr.span); let args = self.mirror_exprs(args); + self.adjustment_span = old_adjustment_span; ExprKind::Call { ty: expr.ty, fun: self.thir.exprs.push(expr), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/cx/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/cx/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/cx/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/cx/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,7 @@ use rustc_data_structures::steal::Steal; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::HirId; use rustc_hir::Node; use rustc_middle::middle::region; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; @@ -46,6 +47,14 @@ crate region_scope_tree: &'tcx region::ScopeTree, crate typeck_results: &'tcx ty::TypeckResults<'tcx>, + /// When applying adjustments to the expression + /// with the given `HirId`, use the given `Span`, + /// instead of the usual span. This is used to + /// assign the span of an overall method call + /// (e.g. `my_val.foo()`) to the adjustment expressions + /// for the receiver. + adjustment_span: Option<(HirId, Span)>, + /// The `DefId` of the owner of this body. body_owner: DefId, } @@ -60,6 +69,7 @@ region_scope_tree: tcx.region_scope_tree(def.did), typeck_results, body_owner: def.did.to_def_id(), + adjustment_span: None, } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,4 +11,3 @@ crate mod pattern; mod util; -pub mod visit; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/check_match.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/check_match.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/check_match.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/check_match.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ +use super::deconstruct_pat::{Constructor, DeconstructedPat}; use super::usefulness::{ - compute_match_usefulness, expand_pattern, is_wildcard, MatchArm, MatchCheckCtxt, Reachability, - UsefulnessReport, + compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport, }; use super::{PatCtxt, PatternError}; @@ -12,13 +12,12 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{HirId, Pat}; -use rustc_middle::thir::PatKind; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME; -use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_session::lint::builtin::{ + BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, +}; use rustc_session::Session; use rustc_span::{DesugaringKind, ExpnKind, Span}; -use std::slice; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match def_id.as_local() { @@ -26,11 +25,12 @@ Some(id) => tcx.hir().body_owned_by(tcx.hir().local_def_id_to_hir_id(id)), }; + let pattern_arena = TypedArena::default(); let mut visitor = MatchVisitor { tcx, typeck_results: tcx.typeck_body(body_id), param_env: tcx.param_env(def_id), - pattern_arena: TypedArena::default(), + pattern_arena: &pattern_arena, }; visitor.visit_body(tcx.hir().body(body_id)); } @@ -39,14 +39,21 @@ struct_span_err!(sess, sp, E0004, "{}", &error_message) } -struct MatchVisitor<'a, 'tcx> { +#[derive(PartialEq)] +enum RefutableFlag { + Irrefutable, + Refutable, +} +use RefutableFlag::*; + +struct MatchVisitor<'a, 'p, 'tcx> { tcx: TyCtxt<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - pattern_arena: TypedArena>, + pattern_arena: &'p TypedArena>, } -impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { +impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { type Map = intravisit::ErasedMap<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { @@ -73,13 +80,13 @@ hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None), }; self.check_irrefutable(&loc.pat, msg, sp); - self.check_patterns(&loc.pat); + self.check_patterns(&loc.pat, Irrefutable); } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { intravisit::walk_param(self, param); self.check_irrefutable(¶m.pat, "function argument", None); - self.check_patterns(¶m.pat); + self.check_patterns(¶m.pat, Irrefutable); } } @@ -112,31 +119,30 @@ } } -impl<'tcx> MatchVisitor<'_, 'tcx> { - fn check_patterns(&self, pat: &Pat<'_>) { +impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { + fn check_patterns(&self, pat: &Pat<'_>, rf: RefutableFlag) { pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); - check_for_bindings_named_same_as_variants(self, pat); + check_for_bindings_named_same_as_variants(self, pat, rf); } - fn lower_pattern<'p>( + fn lower_pattern( &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat: &'tcx hir::Pat<'tcx>, have_errors: &mut bool, - ) -> (&'p super::Pat<'tcx>, Ty<'tcx>) { + ) -> &'p DeconstructedPat<'p, 'tcx> { let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.typeck_results); patcx.include_lint_checks(); let pattern = patcx.lower_pattern(pat); - let pattern_ty = pattern.ty; - let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(pattern)); + let pattern: &_ = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)); if !patcx.errors.is_empty() { *have_errors = true; patcx.report_inlining_errors(); } - (pattern, pattern_ty) + pattern } - fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'_, 'tcx> { + fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'p, 'tcx> { MatchCheckCtxt { tcx: self.tcx, param_env: self.param_env, @@ -146,10 +152,10 @@ } fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, expr: &hir::Expr<'_>, span: Span) { - self.check_patterns(pat); + self.check_patterns(pat, Refutable); let mut cx = self.new_cx(expr.hir_id); - let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; - check_let_reachability(&mut cx, pat.hir_id, &tpat, span); + let tpat = self.lower_pattern(&mut cx, pat, &mut false); + check_let_reachability(&mut cx, pat.hir_id, tpat, span); } fn check_match( @@ -162,11 +168,11 @@ for arm in arms { // Check the arm for some things unrelated to exhaustiveness. - self.check_patterns(&arm.pat); + self.check_patterns(&arm.pat, Refutable); if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { - self.check_patterns(pat); - let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; - check_let_reachability(&mut cx, pat.hir_id, &tpat, tpat.span); + self.check_patterns(pat, Refutable); + let tpat = self.lower_pattern(&mut cx, pat, &mut false); + check_let_reachability(&mut cx, pat.hir_id, tpat, tpat.span()); } } @@ -175,7 +181,7 @@ let arms: Vec<_> = arms .iter() .map(|hir::Arm { pat, guard, .. }| MatchArm { - pat: self.lower_pattern(&mut cx, pat, &mut have_errors).0, + pat: self.lower_pattern(&mut cx, pat, &mut have_errors), hir_id: pat.hir_id, has_guard: guard.is_some(), }) @@ -189,20 +195,16 @@ let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty); - report_arm_reachability(&cx, &report, |_, arm_span, arm_hir_id, catchall| { - match source { - hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - unreachable_pattern(cx.tcx, arm_span, arm_hir_id, catchall); - } - // Unreachable patterns in try and await expressions occur when one of - // the arms are an uninhabited type. Which is OK. - hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} - } - }); + match source { + hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { + report_arm_reachability(&cx, &report) + } + // Unreachable patterns in try and await expressions occur when one of + // the arms are an uninhabited type. Which is OK. + hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} + } // Check if the match is exhaustive. - // Note: An empty match isn't the same as an empty matrix for diagnostics purposes, - // since an empty matrix can occur when there are arms, if those arms all have guards. let is_empty_match = arms.is_empty(); let witnesses = report.non_exhaustiveness_witnesses; if !witnesses.is_empty() { @@ -213,7 +215,8 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option) { let mut cx = self.new_cx(pat.hir_id); - let (pattern, pattern_ty) = self.lower_pattern(&mut cx, pat, &mut false); + let pattern = self.lower_pattern(&mut cx, pat, &mut false); + let pattern_ty = pattern.ty(); let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }]; let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty); @@ -225,7 +228,7 @@ return; } - let joined_patterns = joined_uncovered_patterns(&witnesses); + let joined_patterns = joined_uncovered_patterns(&cx, &witnesses); let mut err = struct_span_err!( self.tcx.sess, pat.span, @@ -301,7 +304,11 @@ } } -fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) { +fn check_for_bindings_named_same_as_variants( + cx: &MatchVisitor<'_, '_, '_>, + pat: &Pat<'_>, + rf: RefutableFlag, +) { pat.walk_always(|p| { if let hir::PatKind::Binding(_, _, ident, None) = p.kind { if let Some(ty::BindByValue(hir::Mutability::Not)) = @@ -314,25 +321,31 @@ variant.ident == ident && variant.ctor_kind == CtorKind::Const }) { + let variant_count = edef.variants.len(); cx.tcx.struct_span_lint_hir( BINDINGS_WITH_VARIANT_NAME, p.hir_id, p.span, |lint| { let ty_path = cx.tcx.def_path_str(edef.did); - lint.build(&format!( + let mut err = lint.build(&format!( "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", + of the variants of the type `{}`", ident, ty_path - )) - .code(error_code!(E0170)) - .span_suggestion( - p.span, - "to match on the variant, qualify the path", - format!("{}::{}", ty_path, ident), - Applicability::MachineApplicable, - ) - .emit(); + )); + err.code(error_code!(E0170)); + // If this is an irrefutable pattern, and there's > 1 variant, + // then we can't actually match on this. Applying the below + // suggestion would produce code that breaks on `check_irrefutable`. + if rf == Refutable || variant_count == 1 { + err.span_suggestion( + p.span, + "to match on the variant, qualify the path", + format!("{}::{}", ty_path, ident), + Applicability::MachineApplicable, + ); + } + err.emit(); }, ) } @@ -343,12 +356,11 @@ } /// Checks for common cases of "catchall" patterns that may not be intended as such. -fn pat_is_catchall(pat: &super::Pat<'_>) -> bool { - use PatKind::*; - match &*pat.kind { - Binding { subpattern: None, .. } => true, - Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s), - Leaf { subpatterns: s } => s.iter().all(|p| pat_is_catchall(&p.pattern)), +fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { + use Constructor::*; + match pat.ctor() { + Wildcard => true, + Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)), _ => false, } } @@ -427,29 +439,16 @@ fn check_let_reachability<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId, - pat: &'p super::Pat<'tcx>, + pat: &'p DeconstructedPat<'p, 'tcx>, span: Span, ) { let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; - let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty); + let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty()); - report_arm_reachability(&cx, &report, |arm_index, arm_span, arm_hir_id, _| { - match let_source(cx.tcx, pat_id) { - LetSource::IfLet | LetSource::WhileLet => { - match arm_index { - // The arm with the user-specified pattern. - 0 => unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None), - // The arm with the wildcard pattern. - 1 => irrefutable_let_pattern(cx.tcx, pat_id, arm_span), - _ => bug!(), - } - } - LetSource::IfLetGuard if arm_index == 0 => { - unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None); - } - _ => {} - } - }); + // Report if the pattern is unreachable, which can only occur when the type is uninhabited. + // This also reports unreachable sub-patterns though, so we can't just replace it with an + // `is_uninhabited` check. + report_arm_reachability(&cx, &report); if report.non_exhaustiveness_witnesses.is_empty() { // The match is exhaustive, i.e. the `if let` pattern is irrefutable. @@ -458,18 +457,15 @@ } /// Report unreachable arms, if any. -fn report_arm_reachability<'p, 'tcx, F>( +fn report_arm_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>, - unreachable: F, -) where - F: Fn(usize, Span, HirId, Option), -{ +) { use Reachability::*; let mut catchall = None; - for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() { + for (arm, is_useful) in report.arm_usefulness.iter() { match is_useful { - Unreachable => unreachable(arm_index, arm.pat.span, arm.hir_id, catchall), + Unreachable => unreachable_pattern(cx.tcx, arm.pat.span(), arm.hir_id, catchall), Reachable(unreachables) if unreachables.is_empty() => {} // The arm is reachable, but contains unreachable subpatterns (from or-patterns). Reachable(unreachables) => { @@ -482,7 +478,7 @@ } } if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) { - catchall = Some(arm.pat.span); + catchall = Some(arm.pat.span()); } } } @@ -492,7 +488,7 @@ cx: &MatchCheckCtxt<'p, 'tcx>, scrut_ty: Ty<'tcx>, sp: Span, - witnesses: Vec>, + witnesses: Vec>, is_empty_match: bool, ) { let non_empty_enum = match scrut_ty.kind() { @@ -509,7 +505,7 @@ format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty), ); } else { - let joined_patterns = joined_uncovered_patterns(&witnesses); + let joined_patterns = joined_uncovered_patterns(cx, &witnesses); err = create_e0004( cx.tcx.sess, sp, @@ -536,7 +532,7 @@ if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize) && !is_empty_match && witnesses.len() == 1 - && is_wildcard(&witnesses[0]) + && matches!(witnesses[0].ctor(), Constructor::NonExhaustive) { err.note(&format!( "`{}` does not have a fixed maximum value, \ @@ -559,33 +555,40 @@ err.emit(); } -fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String { +crate fn joined_uncovered_patterns<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + witnesses: &[DeconstructedPat<'p, 'tcx>], +) -> String { const LIMIT: usize = 3; + let pat_to_str = |pat: &DeconstructedPat<'p, 'tcx>| pat.to_pat(cx).to_string(); match witnesses { [] => bug!(), - [witness] => format!("`{}`", witness), + [witness] => format!("`{}`", witness.to_pat(cx)), [head @ .., tail] if head.len() < LIMIT => { - let head: Vec<_> = head.iter().map(<_>::to_string).collect(); - format!("`{}` and `{}`", head.join("`, `"), tail) + let head: Vec<_> = head.iter().map(pat_to_str).collect(); + format!("`{}` and `{}`", head.join("`, `"), tail.to_pat(cx)) } _ => { let (head, tail) = witnesses.split_at(LIMIT); - let head: Vec<_> = head.iter().map(<_>::to_string).collect(); + let head: Vec<_> = head.iter().map(pat_to_str).collect(); format!("`{}` and {} more", head.join("`, `"), tail.len()) } } } -fn pattern_not_covered_label(witnesses: &[super::Pat<'_>], joined_patterns: &str) -> String { +crate fn pattern_not_covered_label( + witnesses: &[DeconstructedPat<'_, '_>], + joined_patterns: &str, +) -> String { format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns) } /// Point at the definition of non-covered `enum` variants. -fn adt_defined_here( - cx: &MatchCheckCtxt<'_, '_>, +fn adt_defined_here<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, err: &mut DiagnosticBuilder<'_>, - ty: Ty<'_>, - witnesses: &[super::Pat<'_>], + ty: Ty<'tcx>, + witnesses: &[DeconstructedPat<'p, 'tcx>], ) { let ty = ty.peel_refs(); if let ty::Adt(def, _) = ty.kind() { @@ -594,57 +597,42 @@ } if witnesses.len() < 4 { - for sp in maybe_point_at_variant(ty, &witnesses) { + for sp in maybe_point_at_variant(cx, def, witnesses.iter()) { err.span_label(sp, "not covered"); } } } } -fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec { +fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( + cx: &MatchCheckCtxt<'p, 'tcx>, + def: &AdtDef, + patterns: impl Iterator>, +) -> Vec { + use Constructor::*; let mut covered = vec![]; - if let ty::Adt(def, _) = ty.kind() { - // Don't point at variants that have already been covered due to other patterns to avoid - // visual clutter. - for pattern in patterns { - use PatKind::{AscribeUserType, Deref, Leaf, Or, Variant}; - match &*pattern.kind { - AscribeUserType { subpattern, .. } | Deref { subpattern } => { - covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern))); - } - Variant { adt_def, variant_index, subpatterns, .. } if adt_def.did == def.did => { - let sp = def.variants[*variant_index].ident.span; - if covered.contains(&sp) { - continue; - } - covered.push(sp); - - let pats = subpatterns - .iter() - .map(|field_pattern| field_pattern.pattern.clone()) - .collect::>(); - covered.extend(maybe_point_at_variant(ty, &pats)); - } - Leaf { subpatterns } => { - let pats = subpatterns - .iter() - .map(|field_pattern| field_pattern.pattern.clone()) - .collect::>(); - covered.extend(maybe_point_at_variant(ty, &pats)); - } - Or { pats } => { - let pats = pats.iter().cloned().collect::>(); - covered.extend(maybe_point_at_variant(ty, &pats)); - } - _ => {} + for pattern in patterns { + if let Variant(variant_index) = pattern.ctor() { + if let ty::Adt(this_def, _) = pattern.ty().kind() { + if this_def.did != def.did { + continue; + } + } + let sp = def.variants[*variant_index].ident.span; + if covered.contains(&sp) { + // Don't point at variants that have already been covered due to other patterns to avoid + // visual clutter. + continue; } + covered.push(sp); } + covered.extend(maybe_point_at_variant(cx, def, pattern.iter_fields())); } covered } /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. -fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> bool { +fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool { !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env) } @@ -658,7 +646,7 @@ /// - `x @ Some(ref mut? y)`. /// /// This analysis is *not* subsumed by NLL. -fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) { +fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pat<'_>) { // Extract `sub` in `binding @ sub`. let (name, sub) = match &pat.kind { hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs 2021-11-29 19:27:11.000000000 +0000 @@ -322,16 +322,18 @@ && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - cv.ty, cv.ty, - ); tcx.struct_span_lint_hir( lint::builtin::INDIRECT_STRUCTURAL_MATCH, id, span, - |lint| lint.build(&msg).emit(), + |lint| { + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + cv.ty, cv.ty, + ); + lint.build(&msg).emit() + }, ); } // Since we are behind a reference, we can just bubble the error up so we get a diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs 2021-11-29 19:27:11.000000000 +0000 @@ -46,26 +46,45 @@ use self::SliceKind::*; use super::compare_const_vals; -use super::usefulness::{is_wildcard, MatchCheckCtxt, PatCtxt}; +use super::usefulness::{MatchCheckCtxt, PatCtxt}; use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_hir::{HirId, RangeEnd}; -use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::Field; use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt, VariantDef}; +use rustc_middle::{middle::stability::EvalResult, mir::interpret::ConstValue}; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; use smallvec::{smallvec, SmallVec}; +use std::cell::Cell; use std::cmp::{self, max, min, Ordering}; +use std::fmt; use std::iter::{once, IntoIterator}; use std::ops::RangeInclusive; +/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. +fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { + fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { + if let PatKind::Or { pats } = pat.kind.as_ref() { + for pat in pats { + expand(pat, vec); + } + } else { + vec.push(pat) + } + } + + let mut pats = Vec::new(); + expand(pat, &mut pats); + pats +} + /// An inclusive interval, used for precise integer exhaustiveness checking. /// `IntRange`s always store a contiguous range. This means that values are /// encoded such that `0` encodes the minimum value for the integer, @@ -76,9 +95,13 @@ /// /// `IntRange` is never used to encode an empty range or a "range" that wraps /// around the (offset) space: i.e., `range.lo <= range.hi`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub(super) struct IntRange { range: RangeInclusive, + /// Keeps the bias used for encoding the range. It depends on the type of the range and + /// possibly the pointer size of the current architecture. The algorithm ensures we never + /// compare `IntRange`s with different types/architectures. + bias: u128, } impl IntRange { @@ -131,7 +154,7 @@ value.try_eval_bits(tcx, param_env, ty) })()?; let val = val ^ bias; - Some(IntRange { range: val..=val }) + Some(IntRange { range: val..=val, bias }) } else { None } @@ -155,7 +178,7 @@ // This should have been caught earlier by E0030. bug!("malformed range pattern: {}..={}", lo, (hi - offset)); } - Some(IntRange { range: lo..=(hi - offset) }) + Some(IntRange { range: lo..=(hi - offset), bias }) } else { None } @@ -180,7 +203,7 @@ let (lo, hi) = self.boundaries(); let (other_lo, other_hi) = other.boundaries(); if lo <= other_hi && other_lo <= hi { - Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) }) + Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), bias: self.bias }) } else { None } @@ -203,10 +226,11 @@ (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton() } + /// Only used for displaying the range properly. fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { let (lo, hi) = self.boundaries(); - let bias = IntRange::signed_bias(tcx, ty); + let bias = self.bias; let (lo, hi) = (lo ^ bias, hi ^ bias); let env = ty::ParamEnv::empty().and(ty); @@ -223,10 +247,10 @@ } /// Lint on likely incorrect range patterns (#63987) - pub(super) fn lint_overlapping_range_endpoints<'a, 'tcx: 'a>( + pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>( &self, - pcx: PatCtxt<'_, '_, 'tcx>, - ctors: impl Iterator, Span)>, + pcx: PatCtxt<'_, 'p, 'tcx>, + pats: impl Iterator>, column_count: usize, hir_id: HirId, ) { @@ -248,8 +272,8 @@ return; } - let overlaps: Vec<_> = ctors - .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))) + let overlaps: Vec<_> = pats + .filter_map(|pat| Some((pat.ctor().as_int_range()?, pat.span()))) .filter(|(range, _)| self.suspicious_intersection(range)) .map(|(range, span)| (self.intersection(&range).unwrap(), span)) .collect(); @@ -291,6 +315,19 @@ } } +/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and +/// would be displayed as such. To render properly, convert to a pattern first. +impl fmt::Debug for IntRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (lo, hi) = self.boundaries(); + let bias = self.bias; + let (lo, hi) = (lo ^ bias, hi ^ bias); + write!(f, "{}", lo)?; + write!(f, "{}", RangeEnd::Included)?; + write!(f, "{}", hi) + } +} + /// Represents a border between 2 integers. Because the intervals spanning borders must be able to /// cover every integer, we need to be able to represent 2^128 + 1 such borders. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -375,13 +412,13 @@ // Skip duplicates. .filter(|(prev_border, border)| prev_border != border) // Finally, convert to ranges. - .map(|(prev_border, border)| { + .map(move |(prev_border, border)| { let range = match (prev_border, border) { (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), (JustBefore(n), AfterMax) => n..=u128::MAX, _ => unreachable!(), // Ruled out by the sorting and filtering we did }; - IntRange { range } + IntRange { range, bias: self.range.bias } }) } } @@ -389,17 +426,17 @@ #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum SliceKind { /// Patterns of length `n` (`[x, y]`). - FixedLen(u64), + FixedLen(usize), /// Patterns using the `..` notation (`[x, .., y]`). /// Captures any array constructor of `length >= i + j`. /// In the case where `array_len` is `Some(_)`, /// this indicates that we only care about the first `i` and the last `j` values of the array, /// and everything in between is a wildcard `_`. - VarLen(u64, u64), + VarLen(usize, usize), } impl SliceKind { - fn arity(self) -> u64 { + fn arity(self) -> usize { match self { FixedLen(length) => length, VarLen(prefix, suffix) => prefix + suffix, @@ -407,7 +444,7 @@ } /// Whether this pattern includes patterns of length `other_len`. - fn covers_length(self, other_len: u64) -> bool { + fn covers_length(self, other_len: usize) -> bool { match self { FixedLen(len) => len == other_len, VarLen(prefix, suffix) => prefix + suffix <= other_len, @@ -419,13 +456,13 @@ #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(super) struct Slice { /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`. - array_len: Option, + array_len: Option, /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`. kind: SliceKind, } impl Slice { - fn new(array_len: Option, kind: SliceKind) -> Self { + fn new(array_len: Option, kind: SliceKind) -> Self { let kind = match (array_len, kind) { // If the middle `..` is empty, we effectively have a fixed-length pattern. (Some(len), VarLen(prefix, suffix)) if prefix + suffix >= len => FixedLen(len), @@ -434,7 +471,7 @@ Slice { array_len, kind } } - fn arity(self) -> u64 { + fn arity(self) -> usize { self.kind.arity() } @@ -508,16 +545,16 @@ #[derive(Debug)] struct SplitVarLenSlice { /// If the type is an array, this is its size. - array_len: Option, + array_len: Option, /// The arity of the input slice. - arity: u64, + arity: usize, /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L` /// described above. max_slice: SliceKind, } impl SplitVarLenSlice { - fn new(prefix: u64, suffix: u64, array_len: Option) -> Self { + fn new(prefix: usize, suffix: usize, array_len: Option) -> Self { SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) } } @@ -606,10 +643,13 @@ /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. NonExhaustive, /// Stands for constructors that are not seen in the matrix, as explained in the documentation - /// for [`SplitWildcard`]. - Missing, + /// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns` + /// lint. + Missing { nonexhaustive_enum_missing_real_variants: bool }, /// Wildcard pattern. Wildcard, + /// Or-pattern. + Or, } impl<'tcx> Constructor<'tcx> { @@ -617,6 +657,10 @@ matches!(self, Wildcard) } + pub(super) fn is_non_exhaustive(&self) -> bool { + matches!(self, NonExhaustive) + } + fn as_int_range(&self) -> Option<&IntRange> { match self { IntRange(range) => Some(range), @@ -631,6 +675,36 @@ } } + /// Checks if the `Constructor` is a variant and `TyCtxt::eval_stability` returns + /// `EvalResult::Deny { .. }`. + /// + /// This means that the variant has a stdlib unstable feature marking it. + pub(super) fn is_unstable_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool { + if let Constructor::Variant(idx) = self { + if let ty::Adt(adt, _) = pcx.ty.kind() { + let variant_def_id = adt.variants[*idx].def_id; + // Filter variants that depend on a disabled unstable feature. + return matches!( + pcx.cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None), + EvalResult::Deny { .. } + ); + } + } + false + } + + /// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]` + /// attribute. + pub(super) fn is_doc_hidden_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool { + if let Constructor::Variant(idx) = self { + if let ty::Adt(adt, _) = pcx.ty.kind() { + let variant_def_id = adt.variants[*idx].def_id; + return pcx.cx.tcx.is_doc_hidden(variant_def_id); + } + } + false + } + fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx { match *self { Variant(idx) => idx, @@ -642,60 +716,34 @@ } } - /// Determines the constructor that the given pattern can be specialized to. - pub(super) fn from_pat<'p>(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>) -> Self { - match pat.kind.as_ref() { - PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` - PatKind::Binding { .. } | PatKind::Wild => Wildcard, - PatKind::Leaf { .. } | PatKind::Deref { .. } => Single, - &PatKind::Variant { variant_index, .. } => Variant(variant_index), - PatKind::Constant { value } => { - if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) { - IntRange(int_range) - } else { - match pat.ty.kind() { - ty::Float(_) => FloatRange(value, value, RangeEnd::Included), - // In `expand_pattern`, we convert string literals to `&CONST` patterns with - // `CONST` a pattern of type `str`. In truth this contains a constant of type - // `&str`. - ty::Str => Str(value), - // All constants that can be structurally matched have already been expanded - // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are - // opaque. - _ => Opaque, + /// The number of fields for this constructor. This must be kept in sync with + /// `Fields::wildcards`. + pub(super) fn arity(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> usize { + match self { + Single | Variant(_) => match pcx.ty.kind() { + ty::Tuple(fs) => fs.len(), + ty::Ref(..) => 1, + ty::Adt(adt, ..) => { + if adt.is_box() { + // The only legal patterns of type `Box` (outside `std`) are `_` and box + // patterns. If we're here we can assume this is a box pattern. + 1 + } else { + let variant = &adt.variants[self.variant_index_for_adt(adt)]; + Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant).count() } } - } - &PatKind::Range(PatRange { lo, hi, end }) => { - let ty = lo.ty; - if let Some(int_range) = IntRange::from_range( - cx.tcx, - lo.eval_bits(cx.tcx, cx.param_env, lo.ty), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty), - ty, - &end, - ) { - IntRange(int_range) - } else { - FloatRange(lo, hi, end) - } - } - PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { - let array_len = match pat.ty.kind() { - ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env)), - ty::Slice(_) => None, - _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), - }; - let prefix = prefix.len() as u64; - let suffix = suffix.len() as u64; - let kind = if slice.is_some() { - VarLen(prefix, suffix) - } else { - FixedLen(prefix + suffix) - }; - Slice(Slice::new(array_len, kind)) - } - PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), + _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty), + }, + Slice(slice) => slice.arity(), + Str(..) + | FloatRange(..) + | IntRange(..) + | NonExhaustive + | Opaque + | Missing { .. } + | Wildcard => 0, + Or => bug!("The `Or` constructor doesn't have a fixed arity"), } } @@ -756,7 +804,7 @@ // Wildcards cover anything (_, Wildcard) => true, // The missing ctors are not covered by anything in the matrix except wildcards. - (Missing | Wildcard, _) => false, + (Missing { .. } | Wildcard, _) => false, (Single, Single) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, @@ -818,7 +866,7 @@ match self { // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s. Single => !used_ctors.is_empty(), - Variant(_) => used_ctors.iter().any(|c| c == self), + Variant(vid) => used_ctors.iter().any(|c| matches!(c, Variant(i) if i == vid)), IntRange(range) => used_ctors .iter() .filter_map(|c| c.as_int_range()) @@ -829,7 +877,7 @@ .any(|other| slice.is_covered_by(other)), // This constructor is never covered by anything else NonExhaustive => false, - Str(..) | FloatRange(..) | Opaque | Missing | Wildcard => { + Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => { span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self) } } @@ -880,7 +928,7 @@ let all_ctors = match pcx.ty.kind() { ty::Bool => smallvec![make_range(0, 1)], ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { - let len = len.eval_usize(cx.tcx, cx.param_env); + let len = len.eval_usize(cx.tcx, cx.param_env) as usize; if len != 0 && cx.is_uninhabited(sub_ty) { smallvec![] } else { @@ -911,30 +959,33 @@ // witness. let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); + let is_exhaustive_pat_feature = cx.tcx.features().exhaustive_patterns; + // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it // as though it had an "unknown" constructor to avoid exposing its emptiness. The // exception is if the pattern is at the top level, because we want empty matches to be // considered exhaustive. - let is_secretly_empty = def.variants.is_empty() - && !cx.tcx.features().exhaustive_patterns - && !pcx.is_top_level; + let is_secretly_empty = + def.variants.is_empty() && !is_exhaustive_pat_feature && !pcx.is_top_level; + + let mut ctors: SmallVec<[_; 1]> = def + .variants + .iter_enumerated() + .filter(|(_, v)| { + // If `exhaustive_patterns` is enabled, we exclude variants known to be + // uninhabited. + let is_uninhabited = is_exhaustive_pat_feature + && v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) + .contains(cx.tcx, cx.module); + !is_uninhabited + }) + .map(|(idx, _)| Variant(idx)) + .collect(); if is_secretly_empty || is_declared_nonexhaustive { - smallvec![NonExhaustive] - } else if cx.tcx.features().exhaustive_patterns { - // If `exhaustive_patterns` is enabled, we exclude variants known to be - // uninhabited. - def.variants - .iter_enumerated() - .filter(|(_, v)| { - !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) - .contains(cx.tcx, cx.module) - }) - .map(|(idx, _)| Variant(idx)) - .collect() - } else { - def.variants.indices().map(|idx| Variant(idx)).collect() + ctors.push(NonExhaustive); } + ctors } ty::Char => { smallvec![ @@ -975,6 +1026,7 @@ // This type is one for which we cannot list constructors, like `str` or `f64`. _ => smallvec![NonExhaustive], }; + SplitWildcard { matrix_ctors: Vec::new(), all_ctors } } @@ -1039,7 +1091,15 @@ // sometimes prefer reporting the list of constructors instead of just `_`. let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing { - Missing + if pcx.is_non_exhaustive { + Missing { + nonexhaustive_enum_missing_real_variants: self + .iter_missing(pcx) + .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))), + } + } else { + Missing { nonexhaustive_enum_missing_real_variants: false } + } } else { Wildcard }; @@ -1051,120 +1111,108 @@ } } -/// Some fields need to be explicitly hidden away in certain cases; see the comment above the -/// `Fields` struct. This struct represents such a potentially-hidden field. -#[derive(Debug, Copy, Clone)] -pub(super) enum FilteredField<'p, 'tcx> { - Kept(&'p Pat<'tcx>), - Hidden, -} - -impl<'p, 'tcx> FilteredField<'p, 'tcx> { - fn kept(self) -> Option<&'p Pat<'tcx>> { - match self { - FilteredField::Kept(p) => Some(p), - FilteredField::Hidden => None, - } - } -} - /// A value can be decomposed into a constructor applied to some fields. This struct represents /// those fields, generalized to allow patterns in each field. See also `Constructor`. -/// This is constructed from a constructor using [`Fields::wildcards()`]. /// -/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is -/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically -/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used, -/// so we avoid it when possible to preserve performance. -#[derive(Debug, Clone)] -pub(super) enum Fields<'p, 'tcx> { - /// Lists of patterns that don't contain any filtered fields. - /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and - /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril) - /// have not measured if it really made a difference. - Slice(&'p [Pat<'tcx>]), - Vec(SmallVec<[&'p Pat<'tcx>; 2]>), - /// Patterns where some of the fields need to be hidden. For all intents and purposes we only - /// care about the non-hidden fields. We need to keep the real field index for those fields; - /// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient. - /// `len` counts the number of non-hidden fields - Filtered { - fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>, - len: usize, - }, +/// This is constructed for a constructor using [`Fields::wildcards()`]. The idea is that +/// [`Fields::wildcards()`] constructs a list of fields where all entries are wildcards, and then +/// given a pattern we fill some of the fields with its subpatterns. +/// In the following example `Fields::wildcards` returns `[_, _, _, _]`. Then in +/// `extract_pattern_arguments` we fill some of the entries, and the result is +/// `[Some(0), _, _, _]`. +/// ```rust +/// let x: [Option; 4] = foo(); +/// match x { +/// [Some(0), ..] => {} +/// } +/// ``` +/// +/// Note that the number of fields of a constructor may not match the fields declared in the +/// original struct/variant. This happens if a private or `non_exhaustive` field is uninhabited, +/// because the code mustn't observe that it is uninhabited. In that case that field is not +/// included in `fields`. For that reason, when you have a `mir::Field` you must use +/// `index_with_declared_idx`. +#[derive(Debug, Clone, Copy)] +pub(super) struct Fields<'p, 'tcx> { + fields: &'p [DeconstructedPat<'p, 'tcx>], } impl<'p, 'tcx> Fields<'p, 'tcx> { - /// Internal use. Use `Fields::wildcards()` instead. - /// Must not be used if the pattern is a field of a struct/tuple/variant. - fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self { - Fields::Slice(std::slice::from_ref(pat)) + fn empty() -> Self { + Fields { fields: &[] } + } + + fn singleton(cx: &MatchCheckCtxt<'p, 'tcx>, field: DeconstructedPat<'p, 'tcx>) -> Self { + let field: &_ = cx.pattern_arena.alloc(field); + Fields { fields: std::slice::from_ref(field) } + } + + pub(super) fn from_iter( + cx: &MatchCheckCtxt<'p, 'tcx>, + fields: impl IntoIterator>, + ) -> Self { + let fields: &[_] = cx.pattern_arena.alloc_from_iter(fields); + Fields { fields } } - /// Convenience; internal use. fn wildcards_from_tys( cx: &MatchCheckCtxt<'p, 'tcx>, tys: impl IntoIterator>, ) -> Self { - let wilds = tys.into_iter().map(Pat::wildcard_from_ty); - let pats = cx.pattern_arena.alloc_from_iter(wilds); - Fields::Slice(pats) + Fields::from_iter(cx, tys.into_iter().map(DeconstructedPat::wildcard)) } - /// Creates a new list of wildcard fields for a given constructor. - pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { - let ty = pcx.ty; - let cx = pcx.cx; - let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); + // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide + // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. + // This lists the fields we keep along with their types. + fn list_variant_nonhidden_fields<'a>( + cx: &'a MatchCheckCtxt<'p, 'tcx>, + ty: Ty<'tcx>, + variant: &'a VariantDef, + ) -> impl Iterator)> + Captures<'a> + Captures<'p> { + let (adt, substs) = match ty.kind() { + ty::Adt(adt, substs) => (adt, substs), + _ => bug!(), + }; + // Whether we must not match the fields of this variant exhaustively. + let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local(); + variant.fields.iter().enumerate().filter_map(move |(i, field)| { + let ty = field.ty(cx.tcx, substs); + // `field.ty()` doesn't normalize after substituting. + let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(ty); + + if is_uninhabited && (!is_visible || is_non_exhaustive) { + None + } else { + Some((Field::new(i), ty)) + } + }) + } + + /// Creates a new list of wildcard fields for a given constructor. The result must have a + /// length of `constructor.arity()`. + pub(super) fn wildcards( + cx: &MatchCheckCtxt<'p, 'tcx>, + ty: Ty<'tcx>, + constructor: &Constructor<'tcx>, + ) -> Self { let ret = match constructor { Single | Variant(_) => match ty.kind() { - ty::Tuple(ref fs) => { - Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty())) - } - ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)), + ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter().map(|ty| ty.expect_ty())), + ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)), ty::Adt(adt, substs) => { if adt.is_box() { - // Use T as the sub pattern type of Box. - Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0))) + // The only legal patterns of type `Box` (outside `std`) are `_` and box + // patterns. If we're here we can assume this is a box pattern. + Fields::wildcards_from_tys(cx, once(substs.type_at(0))) } else { let variant = &adt.variants[constructor.variant_index_for_adt(adt)]; - // Whether we must not match the fields of this variant exhaustively. - let is_non_exhaustive = - variant.is_field_list_non_exhaustive() && !adt.did.is_local(); - let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs)); - // In the following cases, we don't need to filter out any fields. This is - // the vast majority of real cases, since uninhabited fields are uncommon. - let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive) - || !field_tys.clone().any(|ty| cx.is_uninhabited(ty)); - - if has_no_hidden_fields { - Fields::wildcards_from_tys(cx, field_tys) - } else { - let mut len = 0; - let fields = variant - .fields - .iter() - .map(|field| { - let ty = field.ty(cx.tcx, substs); - let is_visible = adt.is_enum() - || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(ty); - - // In the cases of either a `#[non_exhaustive]` field list - // or a non-public field, we hide uninhabited fields in - // order not to reveal the uninhabitedness of the whole - // variant. - if is_uninhabited && (!is_visible || is_non_exhaustive) { - FilteredField::Hidden - } else { - len += 1; - FilteredField::Kept(wildcard_from_ty(ty)) - } - }) - .collect(); - Fields::Filtered { fields, len } - } + let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant) + .map(|(_, ty)| ty); + Fields::wildcards_from_tys(cx, tys) } } _ => bug!("Unexpected type for `Single` constructor: {:?}", ty), @@ -1176,52 +1224,249 @@ } _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), }, - Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing - | Wildcard => Fields::Slice(&[]), + Str(..) + | FloatRange(..) + | IntRange(..) + | NonExhaustive + | Opaque + | Missing { .. } + | Wildcard => Fields::empty(), + Or => { + bug!("called `Fields::wildcards` on an `Or` ctor") + } }; debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); ret } - /// Apply a constructor to a list of patterns, yielding a new pattern. `self` - /// must have as many elements as this constructor's arity. - /// - /// This is roughly the inverse of `specialize_constructor`. - /// - /// Examples: - /// `ctor`: `Constructor::Single` - /// `ty`: `Foo(u32, u32, u32)` - /// `self`: `[10, 20, _]` - /// returns `Foo(10, 20, _)` - /// - /// `ctor`: `Constructor::Variant(Option::Some)` - /// `ty`: `Option` - /// `self`: `[false]` - /// returns `Some(false)` - pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> { - let subpatterns_and_indices = self.patterns_and_indices(); - let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned(); + /// Returns the list of patterns. + pub(super) fn iter_patterns<'a>( + &'a self, + ) -> impl Iterator> + Captures<'a> { + self.fields.iter() + } +} - let pat = match ctor { - Single | Variant(_) => match pcx.ty.kind() { - ty::Adt(..) | ty::Tuple(..) => { - // We want the real indices here. - let subpatterns = subpatterns_and_indices - .iter() - .map(|&(field, p)| FieldPat { field, pattern: p.clone() }) - .collect(); +/// Values and patterns can be represented as a constructor applied to some fields. This represents +/// a pattern in this form. +/// This also keeps track of whether the pattern has been found reachable during analysis. For this +/// reason we should be careful not to clone patterns for which we care about that. Use +/// `clone_and_forget_reachability` if you're sure. +pub(crate) struct DeconstructedPat<'p, 'tcx> { + ctor: Constructor<'tcx>, + fields: Fields<'p, 'tcx>, + ty: Ty<'tcx>, + span: Span, + reachable: Cell, +} - if let ty::Adt(adt, substs) = pcx.ty.kind() { - if adt.is_enum() { - PatKind::Variant { - adt_def: adt, - substs, - variant_index: ctor.variant_index_for_adt(adt), - subpatterns, - } +impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { + pub(super) fn wildcard(ty: Ty<'tcx>) -> Self { + Self::new(Wildcard, Fields::empty(), ty, DUMMY_SP) + } + + pub(super) fn new( + ctor: Constructor<'tcx>, + fields: Fields<'p, 'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> Self { + DeconstructedPat { ctor, fields, ty, span, reachable: Cell::new(false) } + } + + /// Construct a pattern that matches everything that starts with this constructor. + /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern + /// `Some(_)`. + pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self { + let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor); + DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP) + } + + /// Clone this value. This method emphasizes that cloning loses reachability information and + /// should be done carefully. + pub(super) fn clone_and_forget_reachability(&self) -> Self { + DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty, self.span) + } + + pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self { + let mkpat = |pat| DeconstructedPat::from_pat(cx, pat); + let ctor; + let fields; + match pat.kind.as_ref() { + PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern), + PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat), + PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { + ctor = Wildcard; + fields = Fields::empty(); + } + PatKind::Deref { subpattern } => { + ctor = Single; + fields = Fields::singleton(cx, mkpat(subpattern)); + } + PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { + match pat.ty.kind() { + ty::Tuple(fs) => { + ctor = Single; + let mut wilds: SmallVec<[_; 2]> = fs + .iter() + .map(|ty| ty.expect_ty()) + .map(DeconstructedPat::wildcard) + .collect(); + for pat in subpatterns { + wilds[pat.field.index()] = mkpat(&pat.pattern); + } + fields = Fields::from_iter(cx, wilds); + } + ty::Adt(adt, substs) if adt.is_box() => { + // The only legal patterns of type `Box` (outside `std`) are `_` and box + // patterns. If we're here we can assume this is a box pattern. + // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, + // _)` or a box pattern. As a hack to avoid an ICE with the former, we + // ignore other fields than the first one. This will trigger an error later + // anyway. + // See https://github.com/rust-lang/rust/issues/82772 , + // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977 + // The problem is that we can't know from the type whether we'll match + // normally or through box-patterns. We'll have to figure out a proper + // solution when we introduce generalized deref patterns. Also need to + // prevent mixing of those two options. + let pat = subpatterns.into_iter().find(|pat| pat.field.index() == 0); + let pat = if let Some(pat) = pat { + mkpat(&pat.pattern) } else { - PatKind::Leaf { subpatterns } + DeconstructedPat::wildcard(substs.type_at(0)) + }; + ctor = Single; + fields = Fields::singleton(cx, pat); + } + ty::Adt(adt, _) => { + ctor = match pat.kind.as_ref() { + PatKind::Leaf { .. } => Single, + PatKind::Variant { variant_index, .. } => Variant(*variant_index), + _ => bug!(), + }; + let variant = &adt.variants[ctor.variant_index_for_adt(adt)]; + // For each field in the variant, we store the relevant index into `self.fields` if any. + let mut field_id_to_id: Vec> = + (0..variant.fields.len()).map(|_| None).collect(); + let tys = Fields::list_variant_nonhidden_fields(cx, pat.ty, variant) + .enumerate() + .map(|(i, (field, ty))| { + field_id_to_id[field.index()] = Some(i); + ty + }); + let mut wilds: SmallVec<[_; 2]> = + tys.map(DeconstructedPat::wildcard).collect(); + for pat in subpatterns { + if let Some(i) = field_id_to_id[pat.field.index()] { + wilds[i] = mkpat(&pat.pattern); + } + } + fields = Fields::from_iter(cx, wilds); + } + _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, pat.ty), + } + } + PatKind::Constant { value } => { + if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) { + ctor = IntRange(int_range); + fields = Fields::empty(); + } else { + match pat.ty.kind() { + ty::Float(_) => { + ctor = FloatRange(value, value, RangeEnd::Included); + fields = Fields::empty(); + } + ty::Ref(_, t, _) if t.is_str() => { + // We want a `&str` constant to behave like a `Deref` pattern, to be compatible + // with other `Deref` patterns. This could have been done in `const_to_pat`, + // but that causes issues with the rest of the matching code. + // So here, the constructor for a `"foo"` pattern is `&` (represented by + // `Single`), and has one field. That field has constructor `Str(value)` and no + // fields. + // Note: `t` is `str`, not `&str`. + let subpattern = + DeconstructedPat::new(Str(value), Fields::empty(), t, pat.span); + ctor = Single; + fields = Fields::singleton(cx, subpattern) } + // All constants that can be structurally matched have already been expanded + // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are + // opaque. + _ => { + ctor = Opaque; + fields = Fields::empty(); + } + } + } + } + &PatKind::Range(PatRange { lo, hi, end }) => { + let ty = lo.ty; + ctor = if let Some(int_range) = IntRange::from_range( + cx.tcx, + lo.eval_bits(cx.tcx, cx.param_env, lo.ty), + hi.eval_bits(cx.tcx, cx.param_env, hi.ty), + ty, + &end, + ) { + IntRange(int_range) + } else { + FloatRange(lo, hi, end) + }; + fields = Fields::empty(); + } + PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { + let array_len = match pat.ty.kind() { + ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env) as usize), + ty::Slice(_) => None, + _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), + }; + let kind = if slice.is_some() { + VarLen(prefix.len(), suffix.len()) + } else { + FixedLen(prefix.len() + suffix.len()) + }; + ctor = Slice(Slice::new(array_len, kind)); + fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat)); + } + PatKind::Or { .. } => { + ctor = Or; + let pats = expand_or_pat(pat); + fields = Fields::from_iter(cx, pats.into_iter().map(mkpat)); + } + } + DeconstructedPat::new(ctor, fields, pat.ty, pat.span) + } + + pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> { + let is_wildcard = |pat: &Pat<'_>| { + matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) + }; + let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx)); + let pat = match &self.ctor { + Single | Variant(_) => match self.ty.kind() { + ty::Tuple(..) => PatKind::Leaf { + subpatterns: subpatterns + .enumerate() + .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + .collect(), + }, + ty::Adt(adt_def, _) if adt_def.is_box() => { + // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside + // of `std`). So this branch is only reachable when the feature is enabled and + // the pattern is a box pattern. + PatKind::Deref { subpattern: subpatterns.next().unwrap() } + } + ty::Adt(adt_def, substs) => { + let variant_index = self.ctor.variant_index_for_adt(adt_def); + let variant = &adt_def.variants[variant_index]; + let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty, variant) + .zip(subpatterns) + .map(|((field, _ty), pattern)| FieldPat { field, pattern }) + .collect(); + + if adt_def.is_enum() { + PatKind::Variant { adt_def, substs, variant_index, subpatterns } } else { PatKind::Leaf { subpatterns } } @@ -1229,195 +1474,239 @@ // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should // be careful to reconstruct the correct constant pattern here. However a string // literal pattern will never be reported as a non-exhaustiveness witness, so we - // can ignore this issue. + // ignore this issue. ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, - ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", ctor, pcx.ty), - _ => PatKind::Wild, + _ => bug!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty), }, - Slice(slice) => match slice.kind { - FixedLen(_) => { - PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] } - } - VarLen(prefix, _) => { - let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect(); - if slice.array_len.is_some() { - // Improves diagnostics a bit: if the type is a known-size array, instead - // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. - // This is incorrect if the size is not known, since `[_, ..]` captures - // arrays of lengths `>= 1` whereas `[..]` captures any length. - while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) { - prefix.pop(); + Slice(slice) => { + match slice.kind { + FixedLen(_) => PatKind::Slice { + prefix: subpatterns.collect(), + slice: None, + suffix: vec![], + }, + VarLen(prefix, _) => { + let mut subpatterns = subpatterns.peekable(); + let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect(); + if slice.array_len.is_some() { + // Improves diagnostics a bit: if the type is a known-size array, instead + // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. + // This is incorrect if the size is not known, since `[_, ..]` captures + // arrays of lengths `>= 1` whereas `[..]` captures any length. + while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) { + prefix.pop(); + } + while subpatterns.peek().is_some() + && is_wildcard(subpatterns.peek().unwrap()) + { + subpatterns.next(); + } } + let suffix: Vec<_> = subpatterns.collect(); + let wild = Pat::wildcard_from_ty(self.ty); + PatKind::Slice { prefix, slice: Some(wild), suffix } } - let suffix: Vec<_> = if slice.array_len.is_some() { - // Same as above. - subpatterns.skip_while(is_wildcard).collect() - } else { - subpatterns.collect() - }; - let wild = Pat::wildcard_from_ty(pcx.ty); - PatKind::Slice { prefix, slice: Some(wild), suffix } } - }, + } &Str(value) => PatKind::Constant { value }, &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), - IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty), - NonExhaustive => PatKind::Wild, - Wildcard => return Pat::wildcard_from_ty(pcx.ty), - Opaque => bug!("we should not try to apply an opaque constructor"), - Missing => bug!( - "trying to apply the `Missing` constructor; this should have been done in `apply_constructors`" + IntRange(range) => return range.to_pat(cx.tcx, self.ty), + Wildcard | NonExhaustive => PatKind::Wild, + Missing { .. } => bug!( + "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, + `Missing` should have been processed in `apply_constructors`" ), + Opaque | Or => { + bug!("can't convert to pattern: {:?}", self) + } }; - Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) } + Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) } } - /// Returns the number of patterns. This is the same as the arity of the constructor used to - /// construct `self`. - pub(super) fn len(&self) -> usize { - match self { - Fields::Slice(pats) => pats.len(), - Fields::Vec(pats) => pats.len(), - Fields::Filtered { len, .. } => *len, - } + pub(super) fn is_or_pat(&self) -> bool { + matches!(self.ctor, Or) } - /// Returns the list of patterns along with the corresponding field indices. - fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> { - match self { - Fields::Slice(pats) => { - pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect() - } - Fields::Vec(pats) => { - pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect() - } - Fields::Filtered { fields, .. } => { - // Indices must be relative to the full list of patterns - fields - .iter() - .enumerate() - .filter_map(|(i, p)| Some((Field::new(i), p.kept()?))) - .collect() - } - } + pub(super) fn ctor(&self) -> &Constructor<'tcx> { + &self.ctor } - - /// Returns the list of patterns. - pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> { - match self { - Fields::Slice(pats) => pats.iter().collect(), - Fields::Vec(pats) => pats, - Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(), - } + pub(super) fn ty(&self) -> Ty<'tcx> { + self.ty } - - /// Overrides some of the fields with the provided patterns. Exactly like - /// `replace_fields_indexed`, except that it takes `FieldPat`s as input. - fn replace_with_fieldpats( - &self, - new_pats: impl IntoIterator>, - ) -> Self { - self.replace_fields_indexed( - new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)), - ) + pub(super) fn span(&self) -> Span { + self.span } - /// Overrides some of the fields with the provided patterns. This is used when a pattern - /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start - /// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the - /// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice - /// patterns for the same reason. - fn replace_fields_indexed( - &self, - new_pats: impl IntoIterator)>, - ) -> Self { - let mut fields = self.clone(); - if let Fields::Slice(pats) = fields { - fields = Fields::Vec(pats.iter().collect()); - } + pub(super) fn iter_fields<'a>( + &'a self, + ) -> impl Iterator> + Captures<'a> { + self.fields.iter_patterns() + } - match &mut fields { - Fields::Vec(pats) => { - for (i, pat) in new_pats { - if let Some(p) = pats.get_mut(i) { - *p = pat; - } - } + /// Specialize this pattern with a constructor. + /// `other_ctor` can be different from `self.ctor`, but must be covered by it. + pub(super) fn specialize<'a>( + &'a self, + cx: &MatchCheckCtxt<'p, 'tcx>, + other_ctor: &Constructor<'tcx>, + ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> { + match (&self.ctor, other_ctor) { + (Wildcard, _) => { + // We return a wildcard for each field of `other_ctor`. + Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect() } - Fields::Filtered { fields, .. } => { - for (i, pat) in new_pats { - if let FilteredField::Kept(p) = &mut fields[i] { - *p = pat + (Slice(self_slice), Slice(other_slice)) + if self_slice.arity() != other_slice.arity() => + { + // The only tricky case: two slices of different arity. Since `self_slice` covers + // `other_slice`, `self_slice` must be `VarLen`, i.e. of the form + // `[prefix, .., suffix]`. Moreover `other_slice` is guaranteed to have a larger + // arity. So we fill the middle part with enough wildcards to reach the length of + // the new, larger slice. + match self_slice.kind { + FixedLen(_) => bug!("{:?} doesn't cover {:?}", self_slice, other_slice), + VarLen(prefix, suffix) => { + let inner_ty = match *self.ty.kind() { + ty::Slice(ty) | ty::Array(ty, _) => ty, + _ => bug!("bad slice pattern {:?} {:?}", self.ctor, self.ty), + }; + let prefix = &self.fields.fields[..prefix]; + let suffix = &self.fields.fields[self_slice.arity() - suffix..]; + let wildcard: &_ = + cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); + let extra_wildcards = other_slice.arity() - self_slice.arity(); + let extra_wildcards = (0..extra_wildcards).map(|_| wildcard); + prefix.iter().chain(extra_wildcards).chain(suffix).collect() } } } - Fields::Slice(_) => unreachable!(), + _ => self.fields.iter_patterns().collect(), } - fields } - /// Replaces contained fields with the given list of patterns. There must be `len()` patterns - /// in `pats`. - pub(super) fn replace_fields( - &self, - cx: &MatchCheckCtxt<'p, 'tcx>, - pats: impl IntoIterator>, - ) -> Self { - let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); + /// We keep track for each pattern if it was ever reachable during the analysis. This is used + /// with `unreachable_spans` to report unreachable subpatterns arising from or patterns. + pub(super) fn set_reachable(&self) { + self.reachable.set(true) + } + pub(super) fn is_reachable(&self) -> bool { + self.reachable.get() + } - match self { - Fields::Filtered { fields, len } => { - let mut pats = pats.iter(); - let mut fields = fields.clone(); - for f in &mut fields { - if let FilteredField::Kept(p) = f { - // We take one input pattern for each `Kept` field, in order. - *p = pats.next().unwrap(); - } - } - Fields::Filtered { fields, len: *len } + /// Report the spans of subpatterns that were not reachable, if any. + pub(super) fn unreachable_spans(&self) -> Vec { + let mut spans = Vec::new(); + self.collect_unreachable_spans(&mut spans); + spans + } + + fn collect_unreachable_spans(&self, spans: &mut Vec) { + // We don't look at subpatterns if we already reported the whole pattern as unreachable. + if !self.is_reachable() { + spans.push(self.span); + } else { + for p in self.iter_fields() { + p.collect_unreachable_spans(spans); } - _ => Fields::Slice(pats), } } +} - /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern - /// that is compatible with the constructor used to build `self`. - /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that - /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern - /// provided to this function fills some of the fields with non-wildcards. - /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call - /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _, - /// _, _]`. - /// ```rust - /// let x: [Option; 4] = foo(); - /// match x { - /// [Some(0), ..] => {} - /// } - /// ``` - /// This is guaranteed to preserve the number of patterns in `self`. - pub(super) fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self { - match pat.kind.as_ref() { - PatKind::Deref { subpattern } => { - assert_eq!(self.len(), 1); - Fields::from_single_pattern(subpattern) +/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a +/// `Display` impl. +impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Printing lists is a chore. + let mut first = true; + let mut start_or_continue = |s| { + if first { + first = false; + "" + } else { + s } - PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { - self.replace_with_fieldpats(subpatterns) + }; + let mut start_or_comma = || start_or_continue(", "); + + match &self.ctor { + Single | Variant(_) => match self.ty.kind() { + ty::Adt(def, _) if def.is_box() => { + // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside + // of `std`). So this branch is only reachable when the feature is enabled and + // the pattern is a box pattern. + let subpattern = self.iter_fields().next().unwrap(); + write!(f, "box {:?}", subpattern) + } + ty::Adt(..) | ty::Tuple(..) => { + let variant = match self.ty.kind() { + ty::Adt(adt, _) => { + Some(&adt.variants[self.ctor.variant_index_for_adt(adt)]) + } + ty::Tuple(_) => None, + _ => unreachable!(), + }; + + if let Some(variant) = variant { + write!(f, "{}", variant.ident)?; + } + + // Without `cx`, we can't know which field corresponds to which, so we can't + // get the names of the fields. Instead we just display everything as a suple + // struct, which should be good enough. + write!(f, "(")?; + for p in self.iter_fields() { + write!(f, "{}", start_or_comma())?; + write!(f, "{:?}", p)?; + } + write!(f, ")") + } + // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should + // be careful to detect strings here. However a string literal pattern will never + // be reported as a non-exhaustiveness witness, so we can ignore this issue. + ty::Ref(_, _, mutbl) => { + let subpattern = self.iter_fields().next().unwrap(); + write!(f, "&{}{:?}", mutbl.prefix_str(), subpattern) + } + _ => write!(f, "_"), + }, + Slice(slice) => { + let mut subpatterns = self.fields.iter_patterns(); + write!(f, "[")?; + match slice.kind { + FixedLen(_) => { + for p in subpatterns { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + } + VarLen(prefix_len, _) => { + for p in subpatterns.by_ref().take(prefix_len) { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + write!(f, "{}", start_or_comma())?; + write!(f, "..")?; + for p in subpatterns { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + } + } + write!(f, "]") } - PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => { - // Number of subpatterns for the constructor - let ctor_arity = self.len(); - - // Replace the prefix and the suffix with the given patterns, leaving wildcards in - // the middle if there was a subslice pattern `..`. - let prefix = prefix.iter().enumerate(); - let suffix = - suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p)); - self.replace_fields_indexed(prefix.chain(suffix)) + &FloatRange(lo, hi, end) => { + write!(f, "{}", lo)?; + write!(f, "{}", end)?; + write!(f, "{}", hi) + } + IntRange(range) => write!(f, "{:?}", range), // Best-effort, will render e.g. `false` as `0..=0` + Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty), + Or => { + for pat in self.iter_fields() { + write!(f, "{}{:?}", start_or_continue(" | "), pat)?; + } + Ok(()) } - _ => self.clone(), + Str(value) => write!(f, "{}", value), + Opaque => write!(f, ""), } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs 2021-11-29 19:27:11.000000000 +0000 @@ -280,28 +280,26 @@ //! The details are not necessary to understand this file, so we explain them in //! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function. +use self::ArmType::*; use self::Usefulness::*; -use self::WitnessPreference::*; -use super::deconstruct_pat::{Constructor, Fields, SplitWildcard}; -use super::{PatternFoldable, PatternFolder}; +use super::check_match::{joined_uncovered_patterns, pattern_not_covered_label}; +use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashMap; use rustc_arena::TypedArena; use rustc_hir::def_id::DefId; use rustc_hir::HirId; -use rustc_middle::thir::{Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; +use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::fmt; -use std::iter::{FromIterator, IntoIterator}; -use std::lazy::OnceCell; +use std::iter::once; -crate struct MatchCheckCtxt<'a, 'tcx> { +crate struct MatchCheckCtxt<'p, 'tcx> { crate tcx: TyCtxt<'tcx>, /// The module in which the match occurs. This is necessary for /// checking inhabited-ness of types because whether a type is (visibly) @@ -310,7 +308,7 @@ /// outside its module and should not be matchable with an empty match statement. crate module: DefId, crate param_env: ty::ParamEnv<'tcx>, - crate pattern_arena: &'a TypedArena>, + crate pattern_arena: &'p TypedArena>, } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { @@ -343,6 +341,8 @@ /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a /// subpattern. pub(super) is_top_level: bool, + /// Wether the current pattern is from a `non_exhaustive` enum. + pub(super) is_non_exhaustive: bool, } impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { @@ -351,78 +351,20 @@ } } -crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> { - LiteralExpander.fold_pattern(&pat) -} - -struct LiteralExpander; - -impl<'tcx> PatternFolder<'tcx> for LiteralExpander { - fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { - debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); - match (pat.ty.kind(), pat.kind.as_ref()) { - (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self), - (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self), - (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => { - // Treat string literal patterns as deref patterns to a `str` constant, i.e. - // `&CONST`. This expands them like other const patterns. This could have been done - // in `const_to_pat`, but that causes issues with the rest of the matching code. - let mut new_pat = pat.super_fold_with(self); - // Make a fake const pattern of type `str` (instead of `&str`). That the carried - // constant value still knows it is of type `&str`. - new_pat.ty = t; - Pat { - kind: Box::new(PatKind::Deref { subpattern: new_pat }), - span: pat.span, - ty: pat.ty, - } - } - _ => pat.super_fold_with(self), - } - } -} - -pub(super) fn is_wildcard(pat: &Pat<'_>) -> bool { - matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) -} - -fn is_or_pat(pat: &Pat<'_>) -> bool { - matches!(*pat.kind, PatKind::Or { .. }) -} - -/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. -fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { - fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { - if let PatKind::Or { pats } = pat.kind.as_ref() { - for pat in pats { - expand(pat, vec); - } - } else { - vec.push(pat) - } - } - - let mut pats = Vec::new(); - expand(pat, &mut pats); - pats -} - /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` /// works well. #[derive(Clone)] struct PatStack<'p, 'tcx> { - pats: SmallVec<[&'p Pat<'tcx>; 2]>, - /// Cache for the constructor of the head - head_ctor: OnceCell>, + pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, } impl<'p, 'tcx> PatStack<'p, 'tcx> { - fn from_pattern(pat: &'p Pat<'tcx>) -> Self { + fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>) -> Self { Self::from_vec(smallvec![pat]) } - fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self { - PatStack { pats: vec, head_ctor: OnceCell::new() } + fn from_vec(vec: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>) -> Self { + PatStack { pats: vec } } fn is_empty(&self) -> bool { @@ -433,79 +375,56 @@ self.pats.len() } - fn head(&self) -> &'p Pat<'tcx> { + fn head(&self) -> &'p DeconstructedPat<'p, 'tcx> { self.pats[0] } - #[inline] - fn head_ctor<'a>(&'a self, cx: &MatchCheckCtxt<'p, 'tcx>) -> &'a Constructor<'tcx> { - self.head_ctor.get_or_init(|| Constructor::from_pat(cx, self.head())) - } - - fn iter(&self) -> impl Iterator> { + fn iter(&self) -> impl Iterator> { self.pats.iter().copied() } // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an // or-pattern. Panics if `self` is empty. fn expand_or_pat<'a>(&'a self) -> impl Iterator> + Captures<'a> { - expand_or_pat(self.head()).into_iter().map(move |pat| { + self.head().iter_fields().map(move |pat| { let mut new_patstack = PatStack::from_pattern(pat); new_patstack.pats.extend_from_slice(&self.pats[1..]); new_patstack }) } - /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations. + /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations. /// /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing /// fields filled with wild patterns. /// /// This is roughly the inverse of `Constructor::apply`. - fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatStack<'p, 'tcx> { + fn pop_head_constructor( + &self, + cx: &MatchCheckCtxt<'p, 'tcx>, + ctor: &Constructor<'tcx>, + ) -> PatStack<'p, 'tcx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. - let mut new_fields = - ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns(); + let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor); new_fields.extend_from_slice(&self.pats[1..]); PatStack::from_vec(new_fields) } } -impl<'p, 'tcx> Default for PatStack<'p, 'tcx> { - fn default() -> Self { - Self::from_vec(smallvec![]) - } -} - -impl<'p, 'tcx> PartialEq for PatStack<'p, 'tcx> { - fn eq(&self, other: &Self) -> bool { - self.pats == other.pats - } -} - -impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { - fn from_iter(iter: T) -> Self - where - T: IntoIterator>, - { - Self::from_vec(iter.into_iter().collect()) - } -} - /// Pretty-printing for matrix row. impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "+")?; for pat in self.iter() { - write!(f, " {} +", pat)?; + write!(f, " {:?} +", pat)?; } Ok(()) } } /// A 2D matrix. -#[derive(Clone, PartialEq)] +#[derive(Clone)] pub(super) struct Matrix<'p, 'tcx> { patterns: Vec>, } @@ -523,7 +442,7 @@ /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively /// expands it. fn push(&mut self, row: PatStack<'p, 'tcx>) { - if !row.is_empty() && is_or_pat(row.head()) { + if !row.is_empty() && row.head().is_or_pat() { for row in row.expand_or_pat() { self.patterns.push(row); } @@ -533,24 +452,10 @@ } /// Iterate over the first component of each row - fn heads<'a>(&'a self) -> impl Iterator> + Captures<'p> { - self.patterns.iter().map(|r| r.head()) - } - - /// Iterate over the first constructor of each row. - pub(super) fn head_ctors<'a>( - &'a self, - cx: &'a MatchCheckCtxt<'p, 'tcx>, - ) -> impl Iterator> + Captures<'p> + Clone { - self.patterns.iter().map(move |r| r.head_ctor(cx)) - } - - /// Iterate over the first constructor and the corresponding span of each row. - pub(super) fn head_ctors_and_spans<'a>( + fn heads<'a>( &'a self, - cx: &'a MatchCheckCtxt<'p, 'tcx>, - ) -> impl Iterator, Span)> + Captures<'p> { - self.patterns.iter().map(move |r| (r.head_ctor(cx), r.head().span)) + ) -> impl Iterator> + Clone + Captures<'a> { + self.patterns.iter().map(|r| r.head()) } /// This computes `S(constructor, self)`. See top of the file for explanations. @@ -558,13 +463,15 @@ &self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Matrix<'p, 'tcx> { - self.patterns - .iter() - .filter(|r| ctor.is_covered_by(pcx, r.head_ctor(pcx.cx))) - .map(|r| r.pop_head_constructor(ctor_wild_subpatterns)) - .collect() + let mut matrix = Matrix::empty(); + for row in &self.patterns { + if ctor.is_covered_by(pcx, row.head().ctor()) { + let new_row = row.pop_head_constructor(pcx.cx, ctor); + matrix.push(new_row); + } + } + matrix } } @@ -583,7 +490,7 @@ let Matrix { patterns: m, .. } = self; let pretty_printed_matrix: Vec> = - m.iter().map(|row| row.iter().map(|pat| format!("{}", pat)).collect()).collect(); + m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); let column_count = m.iter().map(|row| row.len()).next().unwrap_or(0); assert!(m.iter().all(|row| row.len() == column_count)); @@ -604,289 +511,41 @@ } } -impl<'p, 'tcx> FromIterator> for Matrix<'p, 'tcx> { - fn from_iter(iter: T) -> Self - where - T: IntoIterator>, - { - let mut matrix = Matrix::empty(); - for x in iter { - // Using `push` ensures we correctly expand or-patterns. - matrix.push(x); - } - matrix - } -} - -/// Given a pattern or a pattern-stack, this struct captures a set of its subpatterns. We use that -/// to track reachable sub-patterns arising from or-patterns. In the absence of or-patterns this -/// will always be either `Empty` (the whole pattern is unreachable) or `Full` (the whole pattern -/// is reachable). When there are or-patterns, some subpatterns may be reachable while others -/// aren't. In this case the whole pattern still counts as reachable, but we will lint the -/// unreachable subpatterns. -/// -/// This supports a limited set of operations, so not all possible sets of subpatterns can be -/// represented. That's ok, we only want the ones that make sense for our usage. -/// -/// What we're doing is illustrated by this: -/// ``` -/// match (true, 0) { -/// (true, 0) => {} -/// (_, 1) => {} -/// (true | false, 0 | 1) => {} -/// } -/// ``` -/// When we try the alternatives of the `true | false` or-pattern, the last `0` is reachable in the -/// `false` alternative but not the `true`. So overall it is reachable. By contrast, the last `1` -/// is not reachable in either alternative, so we want to signal this to the user. -/// Therefore we take the union of sets of reachable patterns coming from different alternatives in -/// order to figure out which subpatterns are overall reachable. -/// -/// Invariant: we try to construct the smallest representation we can. In particular if -/// `self.is_empty()` we ensure that `self` is `Empty`, and same with `Full`. This is not important -/// for correctness currently. -#[derive(Debug, Clone)] -enum SubPatSet<'p, 'tcx> { - /// The empty set. This means the pattern is unreachable. - Empty, - /// The set containing the full pattern. - Full, - /// If the pattern is a pattern with a constructor or a pattern-stack, we store a set for each - /// of its subpatterns. Missing entries in the map are implicitly full, because that's the - /// common case. - Seq { subpats: FxHashMap> }, - /// If the pattern is an or-pattern, we store a set for each of its alternatives. Missing - /// entries in the map are implicitly empty. Note: we always flatten nested or-patterns. - Alt { - subpats: FxHashMap>, - /// Counts the total number of alternatives in the pattern - alt_count: usize, - /// We keep the pattern around to retrieve spans. - pat: &'p Pat<'tcx>, - }, -} - -impl<'p, 'tcx> SubPatSet<'p, 'tcx> { - fn full() -> Self { - SubPatSet::Full - } - fn empty() -> Self { - SubPatSet::Empty - } - - fn is_empty(&self) -> bool { - match self { - SubPatSet::Empty => true, - SubPatSet::Full => false, - // If any subpattern in a sequence is unreachable, the whole pattern is unreachable. - SubPatSet::Seq { subpats } => subpats.values().any(|set| set.is_empty()), - // An or-pattern is reachable if any of its alternatives is. - SubPatSet::Alt { subpats, .. } => subpats.values().all(|set| set.is_empty()), - } - } - - fn is_full(&self) -> bool { - match self { - SubPatSet::Empty => false, - SubPatSet::Full => true, - // The whole pattern is reachable only when all its alternatives are. - SubPatSet::Seq { subpats } => subpats.values().all(|sub_set| sub_set.is_full()), - // The whole or-pattern is reachable only when all its alternatives are. - SubPatSet::Alt { subpats, alt_count, .. } => { - subpats.len() == *alt_count && subpats.values().all(|set| set.is_full()) - } - } - } - - /// Union `self` with `other`, mutating `self`. - fn union(&mut self, other: Self) { - use SubPatSet::*; - // Union with full stays full; union with empty changes nothing. - if self.is_full() || other.is_empty() { - return; - } else if self.is_empty() { - *self = other; - return; - } else if other.is_full() { - *self = Full; - return; - } - - match (&mut *self, other) { - (Seq { subpats: s_set }, Seq { subpats: mut o_set }) => { - s_set.retain(|i, s_sub_set| { - // Missing entries count as full. - let o_sub_set = o_set.remove(&i).unwrap_or(Full); - s_sub_set.union(o_sub_set); - // We drop full entries. - !s_sub_set.is_full() - }); - // Everything left in `o_set` is missing from `s_set`, i.e. counts as full. Since - // unioning with full returns full, we can drop those entries. - } - (Alt { subpats: s_set, .. }, Alt { subpats: mut o_set, .. }) => { - s_set.retain(|i, s_sub_set| { - // Missing entries count as empty. - let o_sub_set = o_set.remove(&i).unwrap_or(Empty); - s_sub_set.union(o_sub_set); - // We drop empty entries. - !s_sub_set.is_empty() - }); - // Everything left in `o_set` is missing from `s_set`, i.e. counts as empty. Since - // unioning with empty changes nothing, we can take those entries as is. - s_set.extend(o_set); - } - _ => bug!(), - } - - if self.is_full() { - *self = Full; - } - } - - /// Returns a list of the spans of the unreachable subpatterns. If `self` is empty (i.e. the - /// whole pattern is unreachable) we return `None`. - fn list_unreachable_spans(&self) -> Option> { - /// Panics if `set.is_empty()`. - fn fill_spans(set: &SubPatSet<'_, '_>, spans: &mut Vec) { - match set { - SubPatSet::Empty => bug!(), - SubPatSet::Full => {} - SubPatSet::Seq { subpats } => { - for (_, sub_set) in subpats { - fill_spans(sub_set, spans); - } - } - SubPatSet::Alt { subpats, pat, alt_count, .. } => { - let expanded = expand_or_pat(pat); - for i in 0..*alt_count { - let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty); - if sub_set.is_empty() { - // Found an unreachable subpattern. - spans.push(expanded[i].span); - } else { - fill_spans(sub_set, spans); - } - } - } - } - } - - if self.is_empty() { - return None; - } - if self.is_full() { - // No subpatterns are unreachable. - return Some(Vec::new()); - } - let mut spans = Vec::new(); - fill_spans(self, &mut spans); - Some(spans) - } - - /// When `self` refers to a patstack that was obtained from specialization, after running - /// `unspecialize` it will refer to the original patstack before specialization. - fn unspecialize(self, arity: usize) -> Self { - use SubPatSet::*; - match self { - Full => Full, - Empty => Empty, - Seq { subpats } => { - // We gather the first `arity` subpatterns together and shift the remaining ones. - let mut new_subpats = FxHashMap::default(); - let mut new_subpats_first_col = FxHashMap::default(); - for (i, sub_set) in subpats { - if i < arity { - // The first `arity` indices are now part of the pattern in the first - // column. - new_subpats_first_col.insert(i, sub_set); - } else { - // Indices after `arity` are simply shifted - new_subpats.insert(i - arity + 1, sub_set); - } - } - // If `new_subpats_first_col` has no entries it counts as full, so we can omit it. - if !new_subpats_first_col.is_empty() { - new_subpats.insert(0, Seq { subpats: new_subpats_first_col }); - } - Seq { subpats: new_subpats } - } - Alt { .. } => bug!(), // `self` is a patstack - } - } - - /// When `self` refers to a patstack that was obtained from splitting an or-pattern, after - /// running `unspecialize` it will refer to the original patstack before splitting. - /// - /// For example: - /// ``` - /// match Some(true) { - /// Some(true) => {} - /// None | Some(true | false) => {} - /// } - /// ``` - /// Here `None` would return the full set and `Some(true | false)` would return the set - /// containing `false`. After `unsplit_or_pat`, we want the set to contain `None` and `false`. - /// This is what this function does. - fn unsplit_or_pat(mut self, alt_id: usize, alt_count: usize, pat: &'p Pat<'tcx>) -> Self { - use SubPatSet::*; - if self.is_empty() { - return Empty; - } - - // Subpatterns coming from inside the or-pattern alternative itself, e.g. in `None | Some(0 - // | 1)`. - let set_first_col = match &mut self { - Full => Full, - Seq { subpats } => subpats.remove(&0).unwrap_or(Full), - Empty => unreachable!(), - Alt { .. } => bug!(), // `self` is a patstack - }; - let mut subpats_first_col = FxHashMap::default(); - subpats_first_col.insert(alt_id, set_first_col); - let set_first_col = Alt { subpats: subpats_first_col, pat, alt_count }; - - let mut subpats = match self { - Full => FxHashMap::default(), - Seq { subpats } => subpats, - Empty => unreachable!(), - Alt { .. } => bug!(), // `self` is a patstack - }; - subpats.insert(0, set_first_col); - Seq { subpats } - } -} - /// This carries the results of computing usefulness, as described at the top of the file. When /// checking usefulness of a match branch, we use the `NoWitnesses` variant, which also keeps track /// of potential unreachable sub-patterns (in the presence of or-patterns). When checking /// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of /// witnesses of non-exhaustiveness when there are any. -/// Which variant to use is dictated by `WitnessPreference`. -#[derive(Clone, Debug)] +/// Which variant to use is dictated by `ArmType`. +#[derive(Debug)] enum Usefulness<'p, 'tcx> { - /// Carries a set of subpatterns that have been found to be reachable. If empty, this indicates - /// the whole pattern is unreachable. If not, this indicates that the pattern is reachable but - /// that some sub-patterns may be unreachable (due to or-patterns). In the absence of - /// or-patterns this will always be either `Empty` (the whole pattern is unreachable) or `Full` - /// (the whole pattern is reachable). - NoWitnesses(SubPatSet<'p, 'tcx>), + /// If we don't care about witnesses, simply remember if the pattern was useful. + NoWitnesses { useful: bool }, /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole /// pattern is unreachable. - WithWitnesses(Vec>), + WithWitnesses(Vec>), } impl<'p, 'tcx> Usefulness<'p, 'tcx> { - fn new_useful(preference: WitnessPreference) -> Self { + fn new_useful(preference: ArmType) -> Self { match preference { - ConstructWitness => WithWitnesses(vec![Witness(vec![])]), - LeaveOutWitness => NoWitnesses(SubPatSet::full()), + // A single (empty) witness of reachability. + FakeExtraWildcard => WithWitnesses(vec![Witness(vec![])]), + RealArm => NoWitnesses { useful: true }, } } - fn new_not_useful(preference: WitnessPreference) -> Self { + + fn new_not_useful(preference: ArmType) -> Self { match preference { - ConstructWitness => WithWitnesses(vec![]), - LeaveOutWitness => NoWitnesses(SubPatSet::empty()), + FakeExtraWildcard => WithWitnesses(vec![]), + RealArm => NoWitnesses { useful: false }, + } + } + + fn is_useful(&self) -> bool { + match self { + Usefulness::NoWitnesses { useful } => *useful, + Usefulness::WithWitnesses(witnesses) => !witnesses.is_empty(), } } @@ -896,37 +555,14 @@ (WithWitnesses(_), WithWitnesses(o)) if o.is_empty() => {} (WithWitnesses(s), WithWitnesses(o)) if s.is_empty() => *self = WithWitnesses(o), (WithWitnesses(s), WithWitnesses(o)) => s.extend(o), - (NoWitnesses(s), NoWitnesses(o)) => s.union(o), - _ => unreachable!(), - } - } - - /// When trying several branches and each returns a `Usefulness`, we need to combine the - /// results together. - fn merge(pref: WitnessPreference, usefulnesses: impl Iterator) -> Self { - let mut ret = Self::new_not_useful(pref); - for u in usefulnesses { - ret.extend(u); - if let NoWitnesses(subpats) = &ret { - if subpats.is_full() { - // Once we reach the full set, more unions won't change the result. - return ret; - } + (NoWitnesses { useful: s_useful }, NoWitnesses { useful: o_useful }) => { + *s_useful = *s_useful || o_useful } - } - ret - } - - /// After calculating the usefulness for a branch of an or-pattern, call this to make this - /// usefulness mergeable with those from the other branches. - fn unsplit_or_pat(self, alt_id: usize, alt_count: usize, pat: &'p Pat<'tcx>) -> Self { - match self { - NoWitnesses(subpats) => NoWitnesses(subpats.unsplit_or_pat(alt_id, alt_count, pat)), - WithWitnesses(_) => bug!(), + _ => unreachable!(), } } - /// After calculating usefulness after a specialization, call this to recontruct a usefulness + /// After calculating usefulness after a specialization, call this to reconstruct a usefulness /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged /// with the results of specializing with the other constructors. fn apply_constructor( @@ -934,51 +570,81 @@ pcx: PatCtxt<'_, 'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Self { match self { - WithWitnesses(witnesses) if witnesses.is_empty() => WithWitnesses(witnesses), + NoWitnesses { .. } => self, + WithWitnesses(ref witnesses) if witnesses.is_empty() => self, WithWitnesses(witnesses) => { - let new_witnesses = if matches!(ctor, Constructor::Missing) { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.head_ctors(pcx.cx)); - // Construct for each missing constructor a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, we get the pattern `Some(_)`. - let new_patterns: Vec<_> = split_wildcard - .iter_missing(pcx) - .map(|missing_ctor| { - Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor) - }) - .collect(); + let new_witnesses = if let Constructor::Missing { .. } = ctor { + // We got the special `Missing` constructor, so each of the missing constructors + // gives a new pattern that is not caught by the match. We list those patterns. + let new_patterns = if pcx.is_non_exhaustive { + // Here we don't want the user to try to list all variants, we want them to add + // a wildcard, so we only suggest that. + vec![DeconstructedPat::wildcard(pcx.ty)] + } else { + let mut split_wildcard = SplitWildcard::new(pcx); + split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); + + // This lets us know if we skipped any variants because they are marked + // `doc(hidden)` or they are unstable feature gate (only stdlib types). + let mut hide_variant_show_wild = false; + // Construct for each missing constructor a "wild" version of this + // constructor, that matches everything that can be built with + // it. For example, if `ctor` is a `Constructor::Variant` for + // `Option::Some`, we get the pattern `Some(_)`. + let mut new: Vec> = split_wildcard + .iter_missing(pcx) + .filter_map(|missing_ctor| { + // Check if this variant is marked `doc(hidden)` + if missing_ctor.is_doc_hidden_variant(pcx) + || missing_ctor.is_unstable_variant(pcx) + { + hide_variant_show_wild = true; + return None; + } + Some(DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone())) + }) + .collect(); + + if hide_variant_show_wild { + new.push(DeconstructedPat::wildcard(pcx.ty)); + } + + new + }; + witnesses .into_iter() .flat_map(|witness| { new_patterns.iter().map(move |pat| { - let mut witness = witness.clone(); - witness.0.push(pat.clone()); - witness + Witness( + witness + .0 + .iter() + .chain(once(pat)) + .map(DeconstructedPat::clone_and_forget_reachability) + .collect(), + ) }) }) .collect() } else { witnesses .into_iter() - .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns)) + .map(|witness| witness.apply_constructor(pcx, &ctor)) .collect() }; WithWitnesses(new_witnesses) } - NoWitnesses(subpats) => NoWitnesses(subpats.unspecialize(ctor_wild_subpatterns.len())), } } } #[derive(Copy, Clone, Debug)] -enum WitnessPreference { - ConstructWitness, - LeaveOutWitness, +enum ArmType { + FakeExtraWildcard, + RealArm, } /// A witness of non-exhaustiveness for error reporting, represented @@ -1014,12 +680,12 @@ /// `Witness(vec![Pair(Some(_), true)])` /// /// The final `Pair(Some(_), true)` is then the resulting witness. -#[derive(Clone, Debug)] -crate struct Witness<'tcx>(Vec>); +#[derive(Debug)] +crate struct Witness<'p, 'tcx>(Vec>); -impl<'tcx> Witness<'tcx> { +impl<'p, 'tcx> Witness<'p, 'tcx> { /// Asserts that the witness contains a single pattern, and returns it. - fn single_pattern(self) -> Pat<'tcx> { + fn single_pattern(self) -> DeconstructedPat<'p, 'tcx> { assert_eq!(self.0.len(), 1); self.0.into_iter().next().unwrap() } @@ -1037,17 +703,13 @@ /// /// left_ty: struct X { a: (bool, &'static str), b: usize} /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } - fn apply_constructor<'p>( - mut self, - pcx: PatCtxt<'_, 'p, 'tcx>, - ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, - ) -> Self { + fn apply_constructor(mut self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self { let pat = { let len = self.0.len(); - let arity = ctor_wild_subpatterns.len(); + let arity = ctor.arity(pcx); let pats = self.0.drain((len - arity)..).rev(); - ctor_wild_subpatterns.replace_fields(pcx.cx, pats).apply(pcx, ctor) + let fields = Fields::from_iter(pcx.cx, pats); + DeconstructedPat::new(ctor.clone(), fields, pcx.ty, DUMMY_SP) }; self.0.push(pat); @@ -1056,6 +718,32 @@ } } +/// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` +/// is not exhaustive enough. +/// +/// NB: The partner lint for structs lives in `compiler/rustc_typeck/src/check/pat.rs`. +fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + scrut_ty: Ty<'tcx>, + sp: Span, + hir_id: HirId, + witnesses: Vec>, +) { + let joined_patterns = joined_uncovered_patterns(cx, &witnesses); + cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| { + let mut lint = build.build("some variants are not matched explicitly"); + lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); + lint.help( + "ensure that all variants are matched explicitly by adding the suggested match arms", + ); + lint.note(&format!( + "the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found", + scrut_ty, + )); + lint.emit(); + }); +} + /// Algorithm from . /// The algorithm from the paper has been modified to correctly handle empty /// types. The changes are: @@ -1086,7 +774,7 @@ cx: &MatchCheckCtxt<'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, v: &PatStack<'p, 'tcx>, - witness_preference: WitnessPreference, + witness_preference: ArmType, hir_id: HirId, is_under_guard: bool, is_top_level: bool, @@ -1111,59 +799,96 @@ assert!(rows.iter().all(|r| r.len() == v.len())); - // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). - let ty = matrix.heads().next().map_or(v.head().ty, |r| r.ty); - let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level }; + let ty = v.head().ty(); + let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); + let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; // If the first pattern is an or-pattern, expand it. - let ret = if is_or_pat(v.head()) { + let mut ret = Usefulness::new_not_useful(witness_preference); + if v.head().is_or_pat() { debug!("expanding or-pattern"); - let v_head = v.head(); - let vs: Vec<_> = v.expand_or_pat().collect(); - let alt_count = vs.len(); // We try each or-pattern branch in turn. let mut matrix = matrix.clone(); - let usefulnesses = vs.into_iter().enumerate().map(|(i, v)| { + for v in v.expand_or_pat() { let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); + ret.extend(usefulness); // If pattern has a guard don't add it to the matrix. if !is_under_guard { // We push the already-seen patterns into the matrix in order to detect redundant // branches like `Some(_) | Some(0)`. matrix.push(v); } - usefulness.unsplit_or_pat(i, alt_count, v_head) - }); - Usefulness::merge(witness_preference, usefulnesses) + } } else { - let v_ctor = v.head_ctor(cx); + let v_ctor = v.head().ctor(); if let Constructor::IntRange(ctor_range) = &v_ctor { // Lint on likely incorrect range patterns (#63987) ctor_range.lint_overlapping_range_endpoints( pcx, - matrix.head_ctors_and_spans(cx), + matrix.heads(), matrix.column_count().unwrap_or(0), hir_id, ) } // We split the head constructor of `v`. - let split_ctors = v_ctor.split(pcx, matrix.head_ctors(cx)); + let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); + let is_non_exhaustive_and_wild = is_non_exhaustive && v_ctor.is_wildcard(); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. let start_matrix = &matrix; - let usefulnesses = split_ctors.into_iter().map(|ctor| { + for ctor in split_ctors { debug!("specialize({:?})", ctor); // We cache the result of `Fields::wildcards` because it is used a lot. - let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); - let spec_matrix = - start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); - let v = v.pop_head_constructor(&ctor_wild_subpatterns); + let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); + let v = v.pop_head_constructor(cx, &ctor); let usefulness = is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false); - usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns) - }); - Usefulness::merge(witness_preference, usefulnesses) - }; + let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); + + // When all the conditions are met we have a match with a `non_exhaustive` enum + // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint. + // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors` + if is_non_exhaustive_and_wild + // We check that the match has a wildcard pattern and that that wildcard is useful, + // meaning there are variants that are covered by the wildcard. Without the check + // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}` + && usefulness.is_useful() && matches!(witness_preference, RealArm) + && matches!( + &ctor, + Constructor::Missing { nonexhaustive_enum_missing_real_variants: true } + ) + { + let patterns = { + let mut split_wildcard = SplitWildcard::new(pcx); + split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); + // Construct for each missing constructor a "wild" version of this + // constructor, that matches everything that can be built with + // it. For example, if `ctor` is a `Constructor::Variant` for + // `Option::Some`, we get the pattern `Some(_)`. + split_wildcard + .iter_missing(pcx) + // Filter out the `NonExhaustive` because we want to list only real + // variants. Also remove any unstable feature gated variants. + // Because of how we computed `nonexhaustive_enum_missing_real_variants`, + // this will not return an empty `Vec`. + .filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))) + .cloned() + .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) + .collect::>() + }; + + lint_non_exhaustive_omitted_patterns(pcx.cx, pcx.ty, pcx.span, hir_id, patterns); + } + + ret.extend(usefulness); + } + } + + if ret.is_useful() { + v.head().set_reachable(); + } + debug!(?ret); ret } @@ -1172,7 +897,7 @@ #[derive(Clone, Copy)] crate struct MatchArm<'p, 'tcx> { /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`. - crate pat: &'p Pat<'tcx>, + crate pat: &'p DeconstructedPat<'p, 'tcx>, crate hir_id: HirId, crate has_guard: bool, } @@ -1194,7 +919,7 @@ crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>, /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of /// exhaustiveness. - crate non_exhaustiveness_witnesses: Vec>, + crate non_exhaustiveness_witnesses: Vec>, } /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which @@ -1214,28 +939,25 @@ .copied() .map(|arm| { let v = PatStack::from_pattern(arm.pat); - let usefulness = - is_useful(cx, &matrix, &v, LeaveOutWitness, arm.hir_id, arm.has_guard, true); + is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true); if !arm.has_guard { matrix.push(v); } - let reachability = match usefulness { - NoWitnesses(subpats) if subpats.is_empty() => Reachability::Unreachable, - NoWitnesses(subpats) => { - Reachability::Reachable(subpats.list_unreachable_spans().unwrap()) - } - WithWitnesses(..) => bug!(), + let reachability = if arm.pat.is_reachable() { + Reachability::Reachable(arm.pat.unreachable_spans()) + } else { + Reachability::Unreachable }; (arm, reachability) }) .collect(); - let wild_pattern = cx.pattern_arena.alloc(Pat::wildcard_from_ty(scrut_ty)); + let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty)); let v = PatStack::from_pattern(wild_pattern); - let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true); + let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, scrut_hir_id, false, true); let non_exhaustiveness_witnesses = match usefulness { WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(), - NoWitnesses(_) => bug!(), + NoWitnesses { .. } => bug!(), }; UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/visit.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/visit.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/visit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_build/src/thir/visit.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,240 +0,0 @@ -use rustc_middle::thir::{self, *}; -use rustc_middle::ty::Const; - -pub trait Visitor<'a, 'tcx: 'a>: Sized { - fn thir(&self) -> &'a Thir<'tcx>; - - fn visit_expr(&mut self, expr: &Expr<'tcx>) { - walk_expr(self, expr); - } - - fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { - walk_stmt(self, stmt); - } - - fn visit_block(&mut self, block: &Block) { - walk_block(self, block); - } - - fn visit_arm(&mut self, arm: &Arm<'tcx>) { - walk_arm(self, arm); - } - - fn visit_pat(&mut self, pat: &Pat<'tcx>) { - walk_pat(self, pat); - } - - fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} -} - -pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { - use ExprKind::*; - match expr.kind { - Scope { value, region_scope: _, lint_level: _ } => { - visitor.visit_expr(&visitor.thir()[value]) - } - Box { value } => visitor.visit_expr(&visitor.thir()[value]), - If { cond, then, else_opt, if_then_scope: _ } => { - visitor.visit_expr(&visitor.thir()[cond]); - visitor.visit_expr(&visitor.thir()[then]); - if let Some(else_expr) = else_opt { - visitor.visit_expr(&visitor.thir()[else_expr]); - } - } - Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { - visitor.visit_expr(&visitor.thir()[fun]); - for &arg in &**args { - visitor.visit_expr(&visitor.thir()[arg]); - } - } - Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), - Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Cast { source } => visitor.visit_expr(&visitor.thir()[source]), - Use { source } => visitor.visit_expr(&visitor.thir()[source]), - NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), - Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), - Let { expr, .. } => { - visitor.visit_expr(&visitor.thir()[expr]); - } - Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - Match { scrutinee, ref arms } => { - visitor.visit_expr(&visitor.thir()[scrutinee]); - for &arm in &**arms { - visitor.visit_arm(&visitor.thir()[arm]); - } - } - Block { ref body } => visitor.visit_block(body), - Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), - Index { lhs, index } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[index]); - } - VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} - Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), - AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Break { value, label: _ } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - Continue { label: _ } => {} - Return { value } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - ConstBlock { value } => visitor.visit_const(value), - Repeat { value, count } => { - visitor.visit_expr(&visitor.thir()[value]); - visitor.visit_const(count); - } - Array { ref fields } | Tuple { ref fields } => { - for &field in &**fields { - visitor.visit_expr(&visitor.thir()[field]); - } - } - Adt(box thir::Adt { - ref fields, - ref base, - adt_def: _, - variant_index: _, - substs: _, - user_ty: _, - }) => { - for field in &**fields { - visitor.visit_expr(&visitor.thir()[field.expr]); - } - if let Some(base) = base { - visitor.visit_expr(&visitor.thir()[base.base]); - } - } - PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { - visitor.visit_expr(&visitor.thir()[source]) - } - Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} - Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), - StaticRef { literal, def_id: _ } => visitor.visit_const(literal), - InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { - for op in &**operands { - use InlineAsmOperand::*; - match op { - In { expr, reg: _ } - | Out { expr: Some(expr), reg: _, late: _ } - | InOut { expr, reg: _, late: _ } - | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), - SplitInOut { in_expr, out_expr, reg: _, late: _ } => { - visitor.visit_expr(&visitor.thir()[*in_expr]); - if let Some(out_expr) = out_expr { - visitor.visit_expr(&visitor.thir()[*out_expr]); - } - } - Out { expr: None, reg: _, late: _ } - | Const { value: _, span: _ } - | SymStatic { def_id: _ } => {} - } - } - } - ThreadLocalRef(_) => {} - LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { - for &out_expr in &**outputs { - visitor.visit_expr(&visitor.thir()[out_expr]); - } - for &in_expr in &**inputs { - visitor.visit_expr(&visitor.thir()[in_expr]); - } - } - Yield { value } => visitor.visit_expr(&visitor.thir()[value]), - } -} - -pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { - match &stmt.kind { - StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), - StmtKind::Let { - initializer, - remainder_scope: _, - init_scope: _, - ref pattern, - lint_level: _, - } => { - if let Some(init) = initializer { - visitor.visit_expr(&visitor.thir()[*init]); - } - visitor.visit_pat(pattern); - } - } -} - -pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { - for &stmt in &*block.stmts { - visitor.visit_stmt(&visitor.thir()[stmt]); - } - if let Some(expr) = block.expr { - visitor.visit_expr(&visitor.thir()[expr]); - } -} - -pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { - match arm.guard { - Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), - Some(Guard::IfLet(ref pat, expr)) => { - visitor.visit_pat(pat); - visitor.visit_expr(&visitor.thir()[expr]); - } - None => {} - } - visitor.visit_pat(&arm.pattern); - visitor.visit_expr(&visitor.thir()[arm.body]); -} - -pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { - use PatKind::*; - match pat.kind.as_ref() { - AscribeUserType { subpattern, ascription: _ } - | Deref { subpattern } - | Binding { - subpattern: Some(subpattern), - mutability: _, - mode: _, - var: _, - ty: _, - is_primary: _, - name: _, - } => visitor.visit_pat(&subpattern), - Binding { .. } | Wild => {} - Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => { - for subpattern in subpatterns { - visitor.visit_pat(&subpattern.pattern); - } - } - Constant { value } => visitor.visit_const(value), - Range(range) => { - visitor.visit_const(range.lo); - visitor.visit_const(range.hi); - } - Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { - for subpattern in prefix { - visitor.visit_pat(&subpattern); - } - if let Some(pat) = slice { - visitor.visit_pat(pat); - } - for subpattern in suffix { - visitor.visit_pat(&subpattern); - } - } - Or { pats } => { - for pat in pats { - visitor.visit_pat(&pat); - } - } - }; -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +[package] +name = "rustc_mir_dataflow" +version = "0.0.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +polonius-engine = "0.13.0" +regex = "1" +smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_graphviz = { path = "../rustc_graphviz" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_middle = { path = "../rustc_middle" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_span = { path = "../rustc_span" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,270 @@ +use crate::elaborate_drops::DropFlagState; +use rustc_middle::mir::{self, Body, Location}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_target::abi::VariantIdx; + +use super::indexes::MovePathIndex; +use super::move_paths::{InitKind, LookupResult, MoveData}; +use super::MoveDataParamEnv; + +pub fn move_path_children_matching<'tcx, F>( + move_data: &MoveData<'tcx>, + path: MovePathIndex, + mut cond: F, +) -> Option +where + F: FnMut(mir::PlaceElem<'tcx>) -> bool, +{ + let mut next_child = move_data.move_paths[path].first_child; + while let Some(child_index) = next_child { + let move_path_children = &move_data.move_paths[child_index]; + if let Some(&elem) = move_path_children.place.projection.last() { + if cond(elem) { + return Some(child_index); + } + } + next_child = move_path_children.next_sibling; + } + + None +} + +/// When enumerating the child fragments of a path, don't recurse into +/// paths (1.) past arrays, slices, and pointers, nor (2.) into a type +/// that implements `Drop`. +/// +/// Places behind references or arrays are not tracked by elaboration +/// and are always assumed to be initialized when accessible. As +/// references and indexes can be reseated, trying to track them can +/// only lead to trouble. +/// +/// Places behind ADT's with a Drop impl are not tracked by +/// elaboration since they can never have a drop-flag state that +/// differs from that of the parent with the Drop impl. +/// +/// In both cases, the contents can only be accessed if and only if +/// their parents are initialized. This implies for example that there +/// is no need to maintain separate drop flags to track such state. +// +// FIXME: we have to do something for moving slice patterns. +fn place_contents_drop_state_cannot_differ<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + place: mir::Place<'tcx>, +) -> bool { + let ty = place.ty(body, tcx).ty; + match ty.kind() { + ty::Array(..) => { + debug!( + "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", + place, ty + ); + false + } + ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => { + debug!( + "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true", + place, ty + ); + true + } + ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => { + debug!( + "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true", + place, ty + ); + true + } + _ => false, + } +} + +pub fn on_lookup_result_bits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + move_data: &MoveData<'tcx>, + lookup_result: LookupResult, + each_child: F, +) where + F: FnMut(MovePathIndex), +{ + match lookup_result { + LookupResult::Parent(..) => { + // access to untracked value - do not touch children + } + LookupResult::Exact(e) => on_all_children_bits(tcx, body, move_data, e, each_child), + } +} + +pub fn on_all_children_bits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + move_data: &MoveData<'tcx>, + move_path_index: MovePathIndex, + mut each_child: F, +) where + F: FnMut(MovePathIndex), +{ + fn is_terminal_path<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + move_data: &MoveData<'tcx>, + path: MovePathIndex, + ) -> bool { + place_contents_drop_state_cannot_differ(tcx, body, move_data.move_paths[path].place) + } + + fn on_all_children_bits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + move_data: &MoveData<'tcx>, + move_path_index: MovePathIndex, + each_child: &mut F, + ) where + F: FnMut(MovePathIndex), + { + each_child(move_path_index); + + if is_terminal_path(tcx, body, move_data, move_path_index) { + return; + } + + let mut next_child_index = move_data.move_paths[move_path_index].first_child; + while let Some(child_index) = next_child_index { + on_all_children_bits(tcx, body, move_data, child_index, each_child); + next_child_index = move_data.move_paths[child_index].next_sibling; + } + } + on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child); +} + +pub fn on_all_drop_children_bits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, + path: MovePathIndex, + mut each_child: F, +) where + F: FnMut(MovePathIndex), +{ + on_all_children_bits(tcx, body, &ctxt.move_data, path, |child| { + let place = &ctxt.move_data.move_paths[path].place; + let ty = place.ty(body, tcx).ty; + debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); + + let erased_ty = tcx.erase_regions(ty); + if erased_ty.needs_drop(tcx, ctxt.param_env) { + each_child(child); + } else { + debug!("on_all_drop_children_bits - skipping") + } + }) +} + +pub fn drop_flag_effects_for_function_entry<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, + mut callback: F, +) where + F: FnMut(MovePathIndex, DropFlagState), +{ + let move_data = &ctxt.move_data; + for arg in body.args_iter() { + let place = mir::Place::from(arg); + let lookup_result = move_data.rev_lookup.find(place.as_ref()); + on_lookup_result_bits(tcx, body, move_data, lookup_result, |mpi| { + callback(mpi, DropFlagState::Present) + }); + } +} + +pub fn drop_flag_effects_for_location<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, + loc: Location, + mut callback: F, +) where + F: FnMut(MovePathIndex, DropFlagState), +{ + let move_data = &ctxt.move_data; + debug!("drop_flag_effects_for_location({:?})", loc); + + // first, move out of the RHS + for mi in &move_data.loc_map[loc] { + let path = mi.move_path_index(move_data); + debug!("moving out of path {:?}", move_data.move_paths[path]); + + on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent)) + } + + debug!("drop_flag_effects: assignment for location({:?})", loc); + + for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present)); +} + +pub fn for_location_inits<'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + move_data: &MoveData<'tcx>, + loc: Location, + mut callback: F, +) where + F: FnMut(MovePathIndex), +{ + for ii in &move_data.init_loc_map[loc] { + let init = move_data.inits[*ii]; + match init.kind { + InitKind::Deep => { + let path = init.path; + + on_all_children_bits(tcx, body, move_data, path, &mut callback) + } + InitKind::Shallow => { + let mpi = init.path; + callback(mpi); + } + InitKind::NonPanicPathOnly => (), + } + } +} + +/// Calls `handle_inactive_variant` for each descendant move path of `enum_place` that contains a +/// `Downcast` to a variant besides the `active_variant`. +/// +/// NOTE: If there are no move paths corresponding to an inactive variant, +/// `handle_inactive_variant` will not be called for that variant. +pub(crate) fn on_all_inactive_variants<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mir::Body<'tcx>, + move_data: &MoveData<'tcx>, + enum_place: mir::Place<'tcx>, + active_variant: VariantIdx, + mut handle_inactive_variant: impl FnMut(MovePathIndex), +) { + let enum_mpi = match move_data.rev_lookup.find(enum_place.as_ref()) { + LookupResult::Exact(mpi) => mpi, + LookupResult::Parent(_) => return, + }; + + let enum_path = &move_data.move_paths[enum_mpi]; + for (variant_mpi, variant_path) in enum_path.children(&move_data.move_paths) { + // Because of the way we build the `MoveData` tree, each child should have exactly one more + // projection than `enum_place`. This additional projection must be a downcast since the + // base is an enum. + let (downcast, base_proj) = variant_path.place.projection.split_last().unwrap(); + assert_eq!(enum_place.projection.len(), base_proj.len()); + + let variant_idx = match *downcast { + mir::ProjectionElem::Downcast(_, idx) => idx, + _ => unreachable!(), + }; + + if variant_idx != active_variant { + on_all_children_bits(tcx, body, move_data, variant_mpi, |mpi| { + handle_inactive_variant(mpi) + }); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/elaborate_drops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/elaborate_drops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/elaborate_drops.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/elaborate_drops.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1051 @@ +use rustc_hir as hir; +use rustc_hir::lang_items::LangItem; +use rustc_index::vec::Idx; +use rustc_middle::mir::patch::MirPatch; +use rustc_middle::mir::*; +use rustc_middle::traits::Reveal; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::util::IntTypeExt; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_target::abi::VariantIdx; +use std::fmt; + +/// The value of an inserted drop flag. +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum DropFlagState { + /// The tracked value is initialized and needs to be dropped when leaving its scope. + Present, + + /// The tracked value is uninitialized or was moved out of and does not need to be dropped when + /// leaving its scope. + Absent, +} + +impl DropFlagState { + pub fn value(self) -> bool { + match self { + DropFlagState::Present => true, + DropFlagState::Absent => false, + } + } +} + +/// Describes how/if a value should be dropped. +#[derive(Debug)] +pub enum DropStyle { + /// The value is already dead at the drop location, no drop will be executed. + Dead, + + /// The value is known to always be initialized at the drop location, drop will always be + /// executed. + Static, + + /// Whether the value needs to be dropped depends on its drop flag. + Conditional, + + /// An "open" drop is one where only the fields of a value are dropped. + /// + /// For example, this happens when moving out of a struct field: The rest of the struct will be + /// dropped in such an "open" drop. It is also used to generate drop glue for the individual + /// components of a value, for example for dropping array elements. + Open, +} + +/// Which drop flags to affect/check with an operation. +#[derive(Debug)] +pub enum DropFlagMode { + /// Only affect the top-level drop flag, not that of any contained fields. + Shallow, + /// Affect all nested drop flags in addition to the top-level one. + Deep, +} + +/// Describes if unwinding is necessary and where to unwind to if a panic occurs. +#[derive(Copy, Clone, Debug)] +pub enum Unwind { + /// Unwind to this block. + To(BasicBlock), + /// Already in an unwind path, any panic will cause an abort. + InCleanup, +} + +impl Unwind { + fn is_cleanup(self) -> bool { + match self { + Unwind::To(..) => false, + Unwind::InCleanup => true, + } + } + + fn into_option(self) -> Option { + match self { + Unwind::To(bb) => Some(bb), + Unwind::InCleanup => None, + } + } + + fn map(self, f: F) -> Self + where + F: FnOnce(BasicBlock) -> BasicBlock, + { + match self { + Unwind::To(bb) => Unwind::To(f(bb)), + Unwind::InCleanup => Unwind::InCleanup, + } + } +} + +pub trait DropElaborator<'a, 'tcx>: fmt::Debug { + /// The type representing paths that can be moved out of. + /// + /// Users can move out of individual fields of a struct, such as `a.b.c`. This type is used to + /// represent such move paths. Sometimes tracking individual move paths is not necessary, in + /// which case this may be set to (for example) `()`. + type Path: Copy + fmt::Debug; + + // Accessors + + fn patch(&mut self) -> &mut MirPatch<'tcx>; + fn body(&self) -> &'a Body<'tcx>; + fn tcx(&self) -> TyCtxt<'tcx>; + fn param_env(&self) -> ty::ParamEnv<'tcx>; + + // Drop logic + + /// Returns how `path` should be dropped, given `mode`. + fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle; + + /// Returns the drop flag of `path` as a MIR `Operand` (or `None` if `path` has no drop flag). + fn get_drop_flag(&mut self, path: Self::Path) -> Option>; + + /// Modifies the MIR patch so that the drop flag of `path` (if any) is cleared at `location`. + /// + /// If `mode` is deep, drop flags of all child paths should also be cleared by inserting + /// additional statements. + fn clear_drop_flag(&mut self, location: Location, path: Self::Path, mode: DropFlagMode); + + // Subpaths + + /// Returns the subpath of a field of `path` (or `None` if there is no dedicated subpath). + /// + /// If this returns `None`, `field` will not get a dedicated drop flag. + fn field_subpath(&self, path: Self::Path, field: Field) -> Option; + + /// Returns the subpath of a dereference of `path` (or `None` if there is no dedicated subpath). + /// + /// If this returns `None`, `*path` will not get a dedicated drop flag. + /// + /// This is only relevant for `Box`, where the contained `T` can be moved out of the box. + fn deref_subpath(&self, path: Self::Path) -> Option; + + /// Returns the subpath of downcasting `path` to one of its variants. + /// + /// If this returns `None`, the downcast of `path` will not get a dedicated drop flag. + fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option; + + /// Returns the subpath of indexing a fixed-size array `path`. + /// + /// If this returns `None`, elements of `path` will not get a dedicated drop flag. + /// + /// This is only relevant for array patterns, which can move out of individual array elements. + fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option; +} + +#[derive(Debug)] +struct DropCtxt<'l, 'b, 'tcx, D> +where + D: DropElaborator<'b, 'tcx>, +{ + elaborator: &'l mut D, + + source_info: SourceInfo, + + place: Place<'tcx>, + path: D::Path, + succ: BasicBlock, + unwind: Unwind, +} + +/// "Elaborates" a drop of `place`/`path` and patches `bb`'s terminator to execute it. +/// +/// The passed `elaborator` is used to determine what should happen at the drop terminator. It +/// decides whether the drop can be statically determined or whether it needs a dynamic drop flag, +/// and whether the drop is "open", ie. should be expanded to drop all subfields of the dropped +/// value. +/// +/// When this returns, the MIR patch in the `elaborator` contains the necessary changes. +pub fn elaborate_drop<'b, 'tcx, D>( + elaborator: &mut D, + source_info: SourceInfo, + place: Place<'tcx>, + path: D::Path, + succ: BasicBlock, + unwind: Unwind, + bb: BasicBlock, +) where + D: DropElaborator<'b, 'tcx>, + 'tcx: 'b, +{ + DropCtxt { elaborator, source_info, place, path, succ, unwind }.elaborate_drop(bb) +} + +impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> +where + D: DropElaborator<'b, 'tcx>, + 'tcx: 'b, +{ + fn place_ty(&self, place: Place<'tcx>) -> Ty<'tcx> { + place.ty(self.elaborator.body(), self.tcx()).ty + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.elaborator.tcx() + } + + /// This elaborates a single drop instruction, located at `bb`, and + /// patches over it. + /// + /// The elaborated drop checks the drop flags to only drop what + /// is initialized. + /// + /// In addition, the relevant drop flags also need to be cleared + /// to avoid double-drops. However, in the middle of a complex + /// drop, one must avoid clearing some of the flags before they + /// are read, as that would cause a memory leak. + /// + /// In particular, when dropping an ADT, multiple fields may be + /// joined together under the `rest` subpath. They are all controlled + /// by the primary drop flag, but only the last rest-field dropped + /// should clear it (and it must also not clear anything else). + // + // FIXME: I think we should just control the flags externally, + // and then we do not need this machinery. + pub fn elaborate_drop(&mut self, bb: BasicBlock) { + debug!("elaborate_drop({:?}, {:?})", bb, self); + let style = self.elaborator.drop_style(self.path, DropFlagMode::Deep); + debug!("elaborate_drop({:?}, {:?}): live - {:?}", bb, self, style); + match style { + DropStyle::Dead => { + self.elaborator + .patch() + .patch_terminator(bb, TerminatorKind::Goto { target: self.succ }); + } + DropStyle::Static => { + self.elaborator.patch().patch_terminator( + bb, + TerminatorKind::Drop { + place: self.place, + target: self.succ, + unwind: self.unwind.into_option(), + }, + ); + } + DropStyle::Conditional => { + let drop_bb = self.complete_drop(self.succ, self.unwind); + self.elaborator + .patch() + .patch_terminator(bb, TerminatorKind::Goto { target: drop_bb }); + } + DropStyle::Open => { + let drop_bb = self.open_drop(); + self.elaborator + .patch() + .patch_terminator(bb, TerminatorKind::Goto { target: drop_bb }); + } + } + } + + /// Returns the place and move path for each field of `variant`, + /// (the move path is `None` if the field is a rest field). + fn move_paths_for_fields( + &self, + base_place: Place<'tcx>, + variant_path: D::Path, + variant: &'tcx ty::VariantDef, + substs: SubstsRef<'tcx>, + ) -> Vec<(Place<'tcx>, Option)> { + variant + .fields + .iter() + .enumerate() + .map(|(i, f)| { + let field = Field::new(i); + let subpath = self.elaborator.field_subpath(variant_path, field); + let tcx = self.tcx(); + + assert_eq!(self.elaborator.param_env().reveal(), Reveal::All); + let field_ty = + tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs)); + (tcx.mk_place_field(base_place, field, field_ty), subpath) + }) + .collect() + } + + fn drop_subpath( + &mut self, + place: Place<'tcx>, + path: Option, + succ: BasicBlock, + unwind: Unwind, + ) -> BasicBlock { + if let Some(path) = path { + debug!("drop_subpath: for std field {:?}", place); + + DropCtxt { + elaborator: self.elaborator, + source_info: self.source_info, + path, + place, + succ, + unwind, + } + .elaborated_drop_block() + } else { + debug!("drop_subpath: for rest field {:?}", place); + + DropCtxt { + elaborator: self.elaborator, + source_info: self.source_info, + place, + succ, + unwind, + // Using `self.path` here to condition the drop on + // our own drop flag. + path: self.path, + } + .complete_drop(succ, unwind) + } + } + + /// Creates one-half of the drop ladder for a list of fields, and return + /// the list of steps in it in reverse order, with the first step + /// dropping 0 fields and so on. + /// + /// `unwind_ladder` is such a list of steps in reverse order, + /// which is called if the matching step of the drop glue panics. + fn drop_halfladder( + &mut self, + unwind_ladder: &[Unwind], + mut succ: BasicBlock, + fields: &[(Place<'tcx>, Option)], + ) -> Vec { + Some(succ) + .into_iter() + .chain(fields.iter().rev().zip(unwind_ladder).map(|(&(place, path), &unwind_succ)| { + succ = self.drop_subpath(place, path, succ, unwind_succ); + succ + })) + .collect() + } + + fn drop_ladder_bottom(&mut self) -> (BasicBlock, Unwind) { + // Clear the "master" drop flag at the end. This is needed + // because the "master" drop protects the ADT's discriminant, + // which is invalidated after the ADT is dropped. + (self.drop_flag_reset_block(DropFlagMode::Shallow, self.succ, self.unwind), self.unwind) + } + + /// Creates a full drop ladder, consisting of 2 connected half-drop-ladders + /// + /// For example, with 3 fields, the drop ladder is + /// + /// .d0: + /// ELAB(drop location.0 [target=.d1, unwind=.c1]) + /// .d1: + /// ELAB(drop location.1 [target=.d2, unwind=.c2]) + /// .d2: + /// ELAB(drop location.2 [target=`self.succ`, unwind=`self.unwind`]) + /// .c1: + /// ELAB(drop location.1 [target=.c2]) + /// .c2: + /// ELAB(drop location.2 [target=`self.unwind`]) + /// + /// NOTE: this does not clear the master drop flag, so you need + /// to point succ/unwind on a `drop_ladder_bottom`. + fn drop_ladder( + &mut self, + fields: Vec<(Place<'tcx>, Option)>, + succ: BasicBlock, + unwind: Unwind, + ) -> (BasicBlock, Unwind) { + debug!("drop_ladder({:?}, {:?})", self, fields); + + let mut fields = fields; + fields.retain(|&(place, _)| { + self.place_ty(place).needs_drop(self.tcx(), self.elaborator.param_env()) + }); + + debug!("drop_ladder - fields needing drop: {:?}", fields); + + let unwind_ladder = vec![Unwind::InCleanup; fields.len() + 1]; + let unwind_ladder: Vec<_> = if let Unwind::To(target) = unwind { + let halfladder = self.drop_halfladder(&unwind_ladder, target, &fields); + halfladder.into_iter().map(Unwind::To).collect() + } else { + unwind_ladder + }; + + let normal_ladder = self.drop_halfladder(&unwind_ladder, succ, &fields); + + (*normal_ladder.last().unwrap(), *unwind_ladder.last().unwrap()) + } + + fn open_drop_for_tuple(&mut self, tys: &[Ty<'tcx>]) -> BasicBlock { + debug!("open_drop_for_tuple({:?}, {:?})", self, tys); + + let fields = tys + .iter() + .enumerate() + .map(|(i, &ty)| { + ( + self.tcx().mk_place_field(self.place, Field::new(i), ty), + self.elaborator.field_subpath(self.path, Field::new(i)), + ) + }) + .collect(); + + let (succ, unwind) = self.drop_ladder_bottom(); + self.drop_ladder(fields, succ, unwind).0 + } + + fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { + debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs); + + let interior = self.tcx().mk_place_deref(self.place); + let interior_path = self.elaborator.deref_subpath(self.path); + + let succ = self.box_free_block(adt, substs, self.succ, self.unwind); + let unwind_succ = + self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup)); + + self.drop_subpath(interior, interior_path, succ, unwind_succ) + } + + fn open_drop_for_adt(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { + debug!("open_drop_for_adt({:?}, {:?}, {:?})", self, adt, substs); + if adt.variants.is_empty() { + return self.elaborator.patch().new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::Unreachable, + }), + is_cleanup: self.unwind.is_cleanup(), + }); + } + + let skip_contents = + adt.is_union() || Some(adt.did) == self.tcx().lang_items().manually_drop(); + let contents_drop = if skip_contents { + (self.succ, self.unwind) + } else { + self.open_drop_for_adt_contents(adt, substs) + }; + + if adt.has_dtor(self.tcx()) { + self.destructor_call_block(contents_drop) + } else { + contents_drop.0 + } + } + + fn open_drop_for_adt_contents( + &mut self, + adt: &'tcx ty::AdtDef, + substs: SubstsRef<'tcx>, + ) -> (BasicBlock, Unwind) { + let (succ, unwind) = self.drop_ladder_bottom(); + if !adt.is_enum() { + let fields = self.move_paths_for_fields( + self.place, + self.path, + &adt.variants[VariantIdx::new(0)], + substs, + ); + self.drop_ladder(fields, succ, unwind) + } else { + self.open_drop_for_multivariant(adt, substs, succ, unwind) + } + } + + fn open_drop_for_multivariant( + &mut self, + adt: &'tcx ty::AdtDef, + substs: SubstsRef<'tcx>, + succ: BasicBlock, + unwind: Unwind, + ) -> (BasicBlock, Unwind) { + let mut values = Vec::with_capacity(adt.variants.len()); + let mut normal_blocks = Vec::with_capacity(adt.variants.len()); + let mut unwind_blocks = + if unwind.is_cleanup() { None } else { Some(Vec::with_capacity(adt.variants.len())) }; + + let mut have_otherwise_with_drop_glue = false; + let mut have_otherwise = false; + let tcx = self.tcx(); + + for (variant_index, discr) in adt.discriminants(tcx) { + let variant = &adt.variants[variant_index]; + let subpath = self.elaborator.downcast_subpath(self.path, variant_index); + + if let Some(variant_path) = subpath { + let base_place = tcx.mk_place_elem( + self.place, + ProjectionElem::Downcast(Some(variant.ident.name), variant_index), + ); + let fields = self.move_paths_for_fields(base_place, variant_path, &variant, substs); + values.push(discr.val); + if let Unwind::To(unwind) = unwind { + // We can't use the half-ladder from the original + // drop ladder, because this breaks the + // "funclet can't have 2 successor funclets" + // requirement from MSVC: + // + // switch unwind-switch + // / \ / \ + // v1.0 v2.0 v2.0-unwind v1.0-unwind + // | | / | + // v1.1-unwind v2.1-unwind | + // ^ | + // \-------------------------------/ + // + // Create a duplicate half-ladder to avoid that. We + // could technically only do this on MSVC, but I + // I want to minimize the divergence between MSVC + // and non-MSVC. + + let unwind_blocks = unwind_blocks.as_mut().unwrap(); + let unwind_ladder = vec![Unwind::InCleanup; fields.len() + 1]; + let halfladder = self.drop_halfladder(&unwind_ladder, unwind, &fields); + unwind_blocks.push(halfladder.last().cloned().unwrap()); + } + let (normal, _) = self.drop_ladder(fields, succ, unwind); + normal_blocks.push(normal); + } else { + have_otherwise = true; + + let param_env = self.elaborator.param_env(); + let have_field_with_drop_glue = variant + .fields + .iter() + .any(|field| field.ty(tcx, substs).needs_drop(tcx, param_env)); + if have_field_with_drop_glue { + have_otherwise_with_drop_glue = true; + } + } + } + + if !have_otherwise { + values.pop(); + } else if !have_otherwise_with_drop_glue { + normal_blocks.push(self.goto_block(succ, unwind)); + if let Unwind::To(unwind) = unwind { + unwind_blocks.as_mut().unwrap().push(self.goto_block(unwind, Unwind::InCleanup)); + } + } else { + normal_blocks.push(self.drop_block(succ, unwind)); + if let Unwind::To(unwind) = unwind { + unwind_blocks.as_mut().unwrap().push(self.drop_block(unwind, Unwind::InCleanup)); + } + } + + ( + self.adt_switch_block(adt, normal_blocks, &values, succ, unwind), + unwind.map(|unwind| { + self.adt_switch_block( + adt, + unwind_blocks.unwrap(), + &values, + unwind, + Unwind::InCleanup, + ) + }), + ) + } + + fn adt_switch_block( + &mut self, + adt: &'tcx ty::AdtDef, + blocks: Vec, + values: &[u128], + succ: BasicBlock, + unwind: Unwind, + ) -> BasicBlock { + // If there are multiple variants, then if something + // is present within the enum the discriminant, tracked + // by the rest path, must be initialized. + // + // Additionally, we do not want to switch on the + // discriminant after it is free-ed, because that + // way lies only trouble. + let discr_ty = adt.repr.discr_type().to_ty(self.tcx()); + let discr = Place::from(self.new_temp(discr_ty)); + let discr_rv = Rvalue::Discriminant(self.place); + let switch_block = BasicBlockData { + statements: vec![self.assign(discr, discr_rv)], + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::SwitchInt { + discr: Operand::Move(discr), + switch_ty: discr_ty, + targets: SwitchTargets::new( + values.iter().copied().zip(blocks.iter().copied()), + *blocks.last().unwrap(), + ), + }, + }), + is_cleanup: unwind.is_cleanup(), + }; + let switch_block = self.elaborator.patch().new_block(switch_block); + self.drop_flag_test_block(switch_block, succ, unwind) + } + + fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { + debug!("destructor_call_block({:?}, {:?})", self, succ); + let tcx = self.tcx(); + let drop_trait = tcx.require_lang_item(LangItem::Drop, None); + let drop_fn = tcx.associated_items(drop_trait).in_definition_order().next().unwrap(); + let ty = self.place_ty(self.place); + let substs = tcx.mk_substs_trait(ty, &[]); + + let ref_ty = + tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }); + let ref_place = self.new_temp(ref_ty); + let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); + + let result = BasicBlockData { + statements: vec![self.assign( + Place::from(ref_place), + Rvalue::Ref( + tcx.lifetimes.re_erased, + BorrowKind::Mut { allow_two_phase_borrow: false }, + self.place, + ), + )], + terminator: Some(Terminator { + kind: TerminatorKind::Call { + func: Operand::function_handle( + tcx, + drop_fn.def_id, + substs, + self.source_info.span, + ), + args: vec![Operand::Move(Place::from(ref_place))], + destination: Some((unit_temp, succ)), + cleanup: unwind.into_option(), + from_hir_call: true, + fn_span: self.source_info.span, + }, + source_info: self.source_info, + }), + is_cleanup: unwind.is_cleanup(), + }; + self.elaborator.patch().new_block(result) + } + + /// Create a loop that drops an array: + /// + /// ```text + /// loop-block: + /// can_go = cur == length_or_end + /// if can_go then succ else drop-block + /// drop-block: + /// if ptr_based { + /// ptr = cur + /// cur = cur.offset(1) + /// } else { + /// ptr = &raw mut P[cur] + /// cur = cur + 1 + /// } + /// drop(ptr) + /// ``` + fn drop_loop( + &mut self, + succ: BasicBlock, + cur: Local, + length_or_end: Place<'tcx>, + ety: Ty<'tcx>, + unwind: Unwind, + ptr_based: bool, + ) -> BasicBlock { + let copy = |place: Place<'tcx>| Operand::Copy(place); + let move_ = |place: Place<'tcx>| Operand::Move(place); + let tcx = self.tcx(); + + let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut }); + let ptr = Place::from(self.new_temp(ptr_ty)); + let can_go = Place::from(self.new_temp(tcx.types.bool)); + + let one = self.constant_usize(1); + let (ptr_next, cur_next) = if ptr_based { + ( + Rvalue::Use(copy(cur.into())), + Rvalue::BinaryOp(BinOp::Offset, Box::new((move_(cur.into()), one))), + ) + } else { + ( + Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)), + Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), + ) + }; + + let drop_block = BasicBlockData { + statements: vec![self.assign(ptr, ptr_next), self.assign(Place::from(cur), cur_next)], + is_cleanup: unwind.is_cleanup(), + terminator: Some(Terminator { + source_info: self.source_info, + // this gets overwritten by drop elaboration. + kind: TerminatorKind::Unreachable, + }), + }; + let drop_block = self.elaborator.patch().new_block(drop_block); + + let loop_block = BasicBlockData { + statements: vec![self.assign( + can_go, + Rvalue::BinaryOp( + BinOp::Eq, + Box::new((copy(Place::from(cur)), copy(length_or_end))), + ), + )], + is_cleanup: unwind.is_cleanup(), + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::if_(tcx, move_(can_go), succ, drop_block), + }), + }; + let loop_block = self.elaborator.patch().new_block(loop_block); + + self.elaborator.patch().patch_terminator( + drop_block, + TerminatorKind::Drop { + place: tcx.mk_place_deref(ptr), + target: loop_block, + unwind: unwind.into_option(), + }, + ); + + loop_block + } + + fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option) -> BasicBlock { + debug!("open_drop_for_array({:?}, {:?})", ety, opt_size); + + // if size_of::() == 0 { + // index_based_loop + // } else { + // ptr_based_loop + // } + + let tcx = self.tcx(); + + if let Some(size) = opt_size { + let fields: Vec<(Place<'tcx>, Option)> = (0..size) + .map(|i| { + ( + tcx.mk_place_elem( + self.place, + ProjectionElem::ConstantIndex { + offset: i, + min_length: size, + from_end: false, + }, + ), + self.elaborator.array_subpath(self.path, i, size), + ) + }) + .collect(); + + if fields.iter().any(|(_, path)| path.is_some()) { + let (succ, unwind) = self.drop_ladder_bottom(); + return self.drop_ladder(fields, succ, unwind).0; + } + } + + let move_ = |place: Place<'tcx>| Operand::Move(place); + let elem_size = Place::from(self.new_temp(tcx.types.usize)); + let len = Place::from(self.new_temp(tcx.types.usize)); + + let base_block = BasicBlockData { + statements: vec![ + self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), + self.assign(len, Rvalue::Len(self.place)), + ], + is_cleanup: self.unwind.is_cleanup(), + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::SwitchInt { + discr: move_(elem_size), + switch_ty: tcx.types.usize, + targets: SwitchTargets::static_if( + 0, + self.drop_loop_pair(ety, false, len), + self.drop_loop_pair(ety, true, len), + ), + }, + }), + }; + self.elaborator.patch().new_block(base_block) + } + + /// Creates a pair of drop-loops of `place`, which drops its contents, even + /// in the case of 1 panic. If `ptr_based`, creates a pointer loop, + /// otherwise create an index loop. + fn drop_loop_pair( + &mut self, + ety: Ty<'tcx>, + ptr_based: bool, + length: Place<'tcx>, + ) -> BasicBlock { + debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based); + let tcx = self.tcx(); + let iter_ty = if ptr_based { tcx.mk_mut_ptr(ety) } else { tcx.types.usize }; + + let cur = self.new_temp(iter_ty); + let length_or_end = if ptr_based { Place::from(self.new_temp(iter_ty)) } else { length }; + + let unwind = self.unwind.map(|unwind| { + self.drop_loop(unwind, cur, length_or_end, ety, Unwind::InCleanup, ptr_based) + }); + + let loop_block = self.drop_loop(self.succ, cur, length_or_end, ety, unwind, ptr_based); + + let cur = Place::from(cur); + let drop_block_stmts = if ptr_based { + let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place)); + let tmp = Place::from(self.new_temp(tmp_ty)); + // tmp = &raw mut P; + // cur = tmp as *mut T; + // end = Offset(cur, len); + vec![ + self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)), + self.assign(cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)), + self.assign( + length_or_end, + Rvalue::BinaryOp( + BinOp::Offset, + Box::new((Operand::Copy(cur), Operand::Move(length))), + ), + ), + ] + } else { + // cur = 0 (length already pushed) + let zero = self.constant_usize(0); + vec![self.assign(cur, Rvalue::Use(zero))] + }; + let drop_block = self.elaborator.patch().new_block(BasicBlockData { + statements: drop_block_stmts, + is_cleanup: unwind.is_cleanup(), + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::Goto { target: loop_block }, + }), + }); + + // FIXME(#34708): handle partially-dropped array/slice elements. + let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); + self.drop_flag_test_block(reset_block, self.succ, unwind) + } + + /// The slow-path - create an "open", elaborated drop for a type + /// which is moved-out-of only partially, and patch `bb` to a jump + /// to it. This must not be called on ADTs with a destructor, + /// as these can't be moved-out-of, except for `Box`, which is + /// special-cased. + /// + /// This creates a "drop ladder" that drops the needed fields of the + /// ADT, both in the success case or if one of the destructors fail. + fn open_drop(&mut self) -> BasicBlock { + let ty = self.place_ty(self.place); + match ty.kind() { + ty::Closure(_, substs) => { + let tys: Vec<_> = substs.as_closure().upvar_tys().collect(); + self.open_drop_for_tuple(&tys) + } + // Note that `elaborate_drops` only drops the upvars of a generator, + // and this is ok because `open_drop` here can only be reached + // within that own generator's resume function. + // This should only happen for the self argument on the resume function. + // It effetively only contains upvars until the generator transformation runs. + // See librustc_body/transform/generator.rs for more details. + ty::Generator(_, substs, _) => { + let tys: Vec<_> = substs.as_generator().upvar_tys().collect(); + self.open_drop_for_tuple(&tys) + } + ty::Tuple(..) => { + let tys: Vec<_> = ty.tuple_fields().collect(); + self.open_drop_for_tuple(&tys) + } + ty::Adt(def, substs) => { + if def.is_box() { + self.open_drop_for_box(def, substs) + } else { + self.open_drop_for_adt(def, substs) + } + } + ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind), + ty::Array(ety, size) => { + let size = size.try_eval_usize(self.tcx(), self.elaborator.param_env()); + self.open_drop_for_array(ety, size) + } + ty::Slice(ety) => self.open_drop_for_array(ety, None), + + _ => bug!("open drop from non-ADT `{:?}`", ty), + } + } + + fn complete_drop(&mut self, succ: BasicBlock, unwind: Unwind) -> BasicBlock { + debug!("complete_drop(succ={:?}, unwind={:?})", succ, unwind); + + let drop_block = self.drop_block(succ, unwind); + + self.drop_flag_test_block(drop_block, succ, unwind) + } + + /// Creates a block that resets the drop flag. If `mode` is deep, all children drop flags will + /// also be cleared. + fn drop_flag_reset_block( + &mut self, + mode: DropFlagMode, + succ: BasicBlock, + unwind: Unwind, + ) -> BasicBlock { + debug!("drop_flag_reset_block({:?},{:?})", self, mode); + + if unwind.is_cleanup() { + // The drop flag isn't read again on the unwind path, so don't + // bother setting it. + return succ; + } + let block = self.new_block(unwind, TerminatorKind::Goto { target: succ }); + let block_start = Location { block, statement_index: 0 }; + self.elaborator.clear_drop_flag(block_start, self.path, mode); + block + } + + fn elaborated_drop_block(&mut self) -> BasicBlock { + debug!("elaborated_drop_block({:?})", self); + let blk = self.drop_block(self.succ, self.unwind); + self.elaborate_drop(blk); + blk + } + + /// Creates a block that frees the backing memory of a `Box` if its drop is required (either + /// statically or by checking its drop flag). + /// + /// The contained value will not be dropped. + fn box_free_block( + &mut self, + adt: &'tcx ty::AdtDef, + substs: SubstsRef<'tcx>, + target: BasicBlock, + unwind: Unwind, + ) -> BasicBlock { + let block = self.unelaborated_free_block(adt, substs, target, unwind); + self.drop_flag_test_block(block, target, unwind) + } + + /// Creates a block that frees the backing memory of a `Box` (without dropping the contained + /// value). + fn unelaborated_free_block( + &mut self, + adt: &'tcx ty::AdtDef, + substs: SubstsRef<'tcx>, + target: BasicBlock, + unwind: Unwind, + ) -> BasicBlock { + let tcx = self.tcx(); + let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); + let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span)); + let args = adt.variants[VariantIdx::new(0)] + .fields + .iter() + .enumerate() + .map(|(i, f)| { + let field = Field::new(i); + let field_ty = f.ty(tcx, substs); + Operand::Move(tcx.mk_place_field(self.place, field, field_ty)) + }) + .collect(); + + let call = TerminatorKind::Call { + func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), + args, + destination: Some((unit_temp, target)), + cleanup: None, + from_hir_call: false, + fn_span: self.source_info.span, + }; // FIXME(#43234) + let free_block = self.new_block(unwind, call); + + let block_start = Location { block: free_block, statement_index: 0 }; + self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); + free_block + } + + fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { + let block = + TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_option() }; + self.new_block(unwind, block) + } + + fn goto_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { + let block = TerminatorKind::Goto { target }; + self.new_block(unwind, block) + } + + /// Returns the block to jump to in order to test the drop flag and execute the drop. + /// + /// Depending on the required `DropStyle`, this might be a generated block with an `if` + /// terminator (for dynamic/open drops), or it might be `on_set` or `on_unset` itself, in case + /// the drop can be statically determined. + fn drop_flag_test_block( + &mut self, + on_set: BasicBlock, + on_unset: BasicBlock, + unwind: Unwind, + ) -> BasicBlock { + let style = self.elaborator.drop_style(self.path, DropFlagMode::Shallow); + debug!( + "drop_flag_test_block({:?},{:?},{:?},{:?}) - {:?}", + self, on_set, on_unset, unwind, style + ); + + match style { + DropStyle::Dead => on_unset, + DropStyle::Static => on_set, + DropStyle::Conditional | DropStyle::Open => { + let flag = self.elaborator.get_drop_flag(self.path).unwrap(); + let term = TerminatorKind::if_(self.tcx(), flag, on_set, on_unset); + self.new_block(unwind, term) + } + } + } + + fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock { + self.elaborator.patch().new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { source_info: self.source_info, kind: k }), + is_cleanup: unwind.is_cleanup(), + }) + } + + fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { + self.elaborator.patch().new_temp(ty, self.source_info.span) + } + + fn constant_usize(&self, val: u16) -> Operand<'tcx> { + Operand::Constant(Box::new(Constant { + span: self.source_info.span, + user_ty: None, + literal: ty::Const::from_usize(self.tcx(), val.into()).into(), + })) + } + + fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { + Statement { + source_info: self.source_info, + kind: StatementKind::Assign(Box::new((lhs, rhs))), + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/cursor.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/cursor.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/cursor.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/cursor.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,226 @@ +//! Random access inspection of the results of a dataflow analysis. + +use std::borrow::Borrow; +use std::cmp::Ordering; + +use rustc_index::bit_set::BitSet; +use rustc_index::vec::Idx; +use rustc_middle::mir::{self, BasicBlock, Location}; + +use super::{Analysis, Direction, Effect, EffectIndex, Results}; + +/// A `ResultsCursor` that borrows the underlying `Results`. +pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>; + +/// Allows random access inspection of the results of a dataflow analysis. +/// +/// This cursor only has linear performance within a basic block when its statements are visited in +/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are +/// visited in *reverse* order—performance will be quadratic in the number of statements in the +/// block. The order in which basic blocks are inspected has no impact on performance. +/// +/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The +/// type of ownership is determined by `R` (see `ResultsRefCursor` above). +pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>> +where + A: Analysis<'tcx>, +{ + body: &'mir mir::Body<'tcx>, + results: R, + state: A::Domain, + + pos: CursorPosition, + + /// Indicates that `state` has been modified with a custom effect. + /// + /// When this flag is set, we need to reset to an entry set before doing a seek. + state_needs_reset: bool, + + #[cfg(debug_assertions)] + reachable_blocks: BitSet, +} + +impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> +where + A: Analysis<'tcx>, + R: Borrow>, +{ + /// Returns a new cursor that can inspect `results`. + pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self { + let bottom_value = results.borrow().analysis.bottom_value(body); + ResultsCursor { + body, + results, + + // Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that + // it needs to reset to block entry before the first seek. The cursor position is + // immaterial. + state_needs_reset: true, + state: bottom_value, + pos: CursorPosition::block_entry(mir::START_BLOCK), + + #[cfg(debug_assertions)] + reachable_blocks: mir::traversal::reachable_as_bitset(body), + } + } + + /// Returns the underlying `Results`. + pub fn results(&self) -> &Results<'tcx, A> { + &self.results.borrow() + } + + /// Returns the `Analysis` used to generate the underlying `Results`. + pub fn analysis(&self) -> &A { + &self.results.borrow().analysis + } + + /// Returns the dataflow state at the current location. + pub fn get(&self) -> &A::Domain { + &self.state + } + + /// Resets the cursor to hold the entry set for the given basic block. + /// + /// For forward dataflow analyses, this is the dataflow state prior to the first statement. + /// + /// For backward dataflow analyses, this is the dataflow state after the terminator. + pub(super) fn seek_to_block_entry(&mut self, block: BasicBlock) { + #[cfg(debug_assertions)] + assert!(self.reachable_blocks.contains(block)); + + self.state.clone_from(&self.results.borrow().entry_set_for_block(block)); + self.pos = CursorPosition::block_entry(block); + self.state_needs_reset = false; + } + + /// Resets the cursor to hold the state prior to the first statement in a basic block. + /// + /// For forward analyses, this is the entry set for the given block. + /// + /// For backward analyses, this is the state that will be propagated to its + /// predecessors (ignoring edge-specific effects). + pub fn seek_to_block_start(&mut self, block: BasicBlock) { + if A::Direction::is_forward() { + self.seek_to_block_entry(block) + } else { + self.seek_after(Location { block, statement_index: 0 }, Effect::Primary) + } + } + + /// Resets the cursor to hold the state after the terminator in a basic block. + /// + /// For backward analyses, this is the entry set for the given block. + /// + /// For forward analyses, this is the state that will be propagated to its + /// successors (ignoring edge-specific effects). + pub fn seek_to_block_end(&mut self, block: BasicBlock) { + if A::Direction::is_backward() { + self.seek_to_block_entry(block) + } else { + self.seek_after(self.body.terminator_loc(block), Effect::Primary) + } + } + + /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is + /// applied. + /// + /// The "before" effect at the target location *will be* applied. + pub fn seek_before_primary_effect(&mut self, target: Location) { + self.seek_after(target, Effect::Before) + } + + /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is + /// applied. + /// + /// The "before" effect at the target location will be applied as well. + pub fn seek_after_primary_effect(&mut self, target: Location) { + self.seek_after(target, Effect::Primary) + } + + fn seek_after(&mut self, target: Location, effect: Effect) { + assert!(target <= self.body.terminator_loc(target.block)); + + // Reset to the entry of the target block if any of the following are true: + // - A custom effect has been applied to the cursor state. + // - We are in a different block than the target. + // - We are in the same block but have advanced past the target effect. + if self.state_needs_reset || self.pos.block != target.block { + self.seek_to_block_entry(target.block); + } else if let Some(curr_effect) = self.pos.curr_effect_index { + let mut ord = curr_effect.statement_index.cmp(&target.statement_index); + if A::Direction::is_backward() { + ord = ord.reverse() + } + + match ord.then_with(|| curr_effect.effect.cmp(&effect)) { + Ordering::Equal => return, + Ordering::Greater => self.seek_to_block_entry(target.block), + Ordering::Less => {} + } + } + + // At this point, the cursor is in the same block as the target location at an earlier + // statement. + debug_assert_eq!(target.block, self.pos.block); + + let block_data = &self.body[target.block]; + let next_effect = if A::Direction::is_forward() { + #[rustfmt::skip] + self.pos.curr_effect_index.map_or_else( + || Effect::Before.at_index(0), + EffectIndex::next_in_forward_order, + ) + } else { + self.pos.curr_effect_index.map_or_else( + || Effect::Before.at_index(block_data.statements.len()), + EffectIndex::next_in_backward_order, + ) + }; + + let analysis = &self.results.borrow().analysis; + let target_effect_index = effect.at_index(target.statement_index); + + A::Direction::apply_effects_in_range( + analysis, + &mut self.state, + target.block, + block_data, + next_effect..=target_effect_index, + ); + + self.pos = + CursorPosition { block: target.block, curr_effect_index: Some(target_effect_index) }; + } + + /// Applies `f` to the cursor's internal state. + /// + /// This can be used, e.g., to apply the call return effect directly to the cursor without + /// creating an extra copy of the dataflow state. + pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) { + f(&self.results.borrow().analysis, &mut self.state); + self.state_needs_reset = true; + } +} + +impl<'mir, 'tcx, A, R, T> ResultsCursor<'mir, 'tcx, A, R> +where + A: Analysis<'tcx, Domain = BitSet>, + T: Idx, + R: Borrow>, +{ + pub fn contains(&self, elem: T) -> bool { + self.get().contains(elem) + } +} + +#[derive(Clone, Copy, Debug)] +struct CursorPosition { + block: BasicBlock, + curr_effect_index: Option, +} + +impl CursorPosition { + fn block_entry(block: BasicBlock) -> CursorPosition { + CursorPosition { block, curr_effect_index: None } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/direction.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/direction.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/direction.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/direction.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,564 @@ +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets}; +use rustc_middle::ty::TyCtxt; +use std::ops::RangeInclusive; + +use super::visitor::{ResultsVisitable, ResultsVisitor}; +use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget}; + +pub trait Direction { + fn is_forward() -> bool; + + fn is_backward() -> bool { + !Self::is_forward() + } + + /// Applies all effects between the given `EffectIndex`s. + /// + /// `effects.start()` must precede or equal `effects.end()` in this direction. + fn apply_effects_in_range
( + analysis: &A, + state: &mut A::Domain, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + effects: RangeInclusive, + ) where + A: Analysis<'tcx>; + + fn apply_effects_in_block( + analysis: &A, + state: &mut A::Domain, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + ) where + A: Analysis<'tcx>; + + fn gen_kill_effects_in_block( + analysis: &A, + trans: &mut GenKillSet, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + ) where + A: GenKillAnalysis<'tcx>; + + fn visit_results_in_block( + state: &mut F, + block: BasicBlock, + block_data: &'mir mir::BasicBlockData<'tcx>, + results: &R, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, + ) where + R: ResultsVisitable<'tcx, FlowState = F>; + + fn join_state_into_successors_of( + analysis: &A, + tcx: TyCtxt<'tcx>, + body: &mir::Body<'tcx>, + dead_unwinds: Option<&BitSet>, + exit_state: &mut A::Domain, + block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>), + propagate: impl FnMut(BasicBlock, &A::Domain), + ) where + A: Analysis<'tcx>; +} + +/// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement). +pub struct Backward; + +impl Direction for Backward { + fn is_forward() -> bool { + false + } + + fn apply_effects_in_block( + analysis: &A, + state: &mut A::Domain, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + ) where + A: Analysis<'tcx>, + { + let terminator = block_data.terminator(); + let location = Location { block, statement_index: block_data.statements.len() }; + analysis.apply_before_terminator_effect(state, terminator, location); + analysis.apply_terminator_effect(state, terminator, location); + + for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { + let location = Location { block, statement_index }; + analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_statement_effect(state, statement, location); + } + } + + fn gen_kill_effects_in_block( + analysis: &A, + trans: &mut GenKillSet, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + ) where + A: GenKillAnalysis<'tcx>, + { + let terminator = block_data.terminator(); + let location = Location { block, statement_index: block_data.statements.len() }; + analysis.before_terminator_effect(trans, terminator, location); + analysis.terminator_effect(trans, terminator, location); + + for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { + let location = Location { block, statement_index }; + analysis.before_statement_effect(trans, statement, location); + analysis.statement_effect(trans, statement, location); + } + } + + fn apply_effects_in_range( + analysis: &A, + state: &mut A::Domain, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + effects: RangeInclusive, + ) where + A: Analysis<'tcx>, + { + let (from, to) = (*effects.start(), *effects.end()); + let terminator_index = block_data.statements.len(); + + assert!(from.statement_index <= terminator_index); + assert!(!to.precedes_in_backward_order(from)); + + // Handle the statement (or terminator) at `from`. + + let next_effect = match from.effect { + // If we need to apply the terminator effect in all or in part, do so now. + _ if from.statement_index == terminator_index => { + let location = Location { block, statement_index: from.statement_index }; + let terminator = block_data.terminator(); + + if from.effect == Effect::Before { + analysis.apply_before_terminator_effect(state, terminator, location); + if to == Effect::Before.at_index(terminator_index) { + return; + } + } + + analysis.apply_terminator_effect(state, terminator, location); + if to == Effect::Primary.at_index(terminator_index) { + return; + } + + // If `from.statement_index` is `0`, we will have hit one of the earlier comparisons + // with `to`. + from.statement_index - 1 + } + + Effect::Primary => { + let location = Location { block, statement_index: from.statement_index }; + let statement = &block_data.statements[from.statement_index]; + + analysis.apply_statement_effect(state, statement, location); + if to == Effect::Primary.at_index(from.statement_index) { + return; + } + + from.statement_index - 1 + } + + Effect::Before => from.statement_index, + }; + + // Handle all statements between `first_unapplied_idx` and `to.statement_index`. + + for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) { + let location = Location { block, statement_index }; + let statement = &block_data.statements[statement_index]; + analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_statement_effect(state, statement, location); + } + + // Handle the statement at `to`. + + let location = Location { block, statement_index: to.statement_index }; + let statement = &block_data.statements[to.statement_index]; + analysis.apply_before_statement_effect(state, statement, location); + + if to.effect == Effect::Before { + return; + } + + analysis.apply_statement_effect(state, statement, location); + } + + fn visit_results_in_block( + state: &mut F, + block: BasicBlock, + block_data: &'mir mir::BasicBlockData<'tcx>, + results: &R, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, + ) where + R: ResultsVisitable<'tcx, FlowState = F>, + { + results.reset_to_block_entry(state, block); + + vis.visit_block_end(&state, block_data, block); + + // Terminator + let loc = Location { block, statement_index: block_data.statements.len() }; + let term = block_data.terminator(); + results.reconstruct_before_terminator_effect(state, term, loc); + vis.visit_terminator_before_primary_effect(state, term, loc); + results.reconstruct_terminator_effect(state, term, loc); + vis.visit_terminator_after_primary_effect(state, term, loc); + + for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { + let loc = Location { block, statement_index }; + results.reconstruct_before_statement_effect(state, stmt, loc); + vis.visit_statement_before_primary_effect(state, stmt, loc); + results.reconstruct_statement_effect(state, stmt, loc); + vis.visit_statement_after_primary_effect(state, stmt, loc); + } + + vis.visit_block_start(state, block_data, block); + } + + fn join_state_into_successors_of( + analysis: &A, + _tcx: TyCtxt<'tcx>, + body: &mir::Body<'tcx>, + dead_unwinds: Option<&BitSet>, + exit_state: &mut A::Domain, + (bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), + mut propagate: impl FnMut(BasicBlock, &A::Domain), + ) where + A: Analysis<'tcx>, + { + for pred in body.predecessors()[bb].iter().copied() { + match body[pred].terminator().kind { + // Apply terminator-specific edge effects. + // + // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally. + mir::TerminatorKind::Call { + destination: Some((return_place, dest)), + ref func, + ref args, + .. + } if dest == bb => { + let mut tmp = exit_state.clone(); + analysis.apply_call_return_effect(&mut tmp, pred, func, args, return_place); + propagate(pred, &tmp); + } + + mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => { + let mut tmp = exit_state.clone(); + analysis.apply_yield_resume_effect(&mut tmp, resume, resume_arg); + propagate(pred, &tmp); + } + + // Ignore dead unwinds. + mir::TerminatorKind::Call { cleanup: Some(unwind), .. } + | mir::TerminatorKind::Assert { cleanup: Some(unwind), .. } + | mir::TerminatorKind::Drop { unwind: Some(unwind), .. } + | mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. } + | mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. } + if unwind == bb => + { + if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { + propagate(pred, exit_state); + } + } + + _ => propagate(pred, exit_state), + } + } + } +} + +/// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator). +pub struct Forward; + +impl Direction for Forward { + fn is_forward() -> bool { + true + } + + fn apply_effects_in_block( + analysis: &A, + state: &mut A::Domain, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + ) where + A: Analysis<'tcx>, + { + for (statement_index, statement) in block_data.statements.iter().enumerate() { + let location = Location { block, statement_index }; + analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_statement_effect(state, statement, location); + } + + let terminator = block_data.terminator(); + let location = Location { block, statement_index: block_data.statements.len() }; + analysis.apply_before_terminator_effect(state, terminator, location); + analysis.apply_terminator_effect(state, terminator, location); + } + + fn gen_kill_effects_in_block( + analysis: &A, + trans: &mut GenKillSet, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + ) where + A: GenKillAnalysis<'tcx>, + { + for (statement_index, statement) in block_data.statements.iter().enumerate() { + let location = Location { block, statement_index }; + analysis.before_statement_effect(trans, statement, location); + analysis.statement_effect(trans, statement, location); + } + + let terminator = block_data.terminator(); + let location = Location { block, statement_index: block_data.statements.len() }; + analysis.before_terminator_effect(trans, terminator, location); + analysis.terminator_effect(trans, terminator, location); + } + + fn apply_effects_in_range( + analysis: &A, + state: &mut A::Domain, + block: BasicBlock, + block_data: &mir::BasicBlockData<'tcx>, + effects: RangeInclusive, + ) where + A: Analysis<'tcx>, + { + let (from, to) = (*effects.start(), *effects.end()); + let terminator_index = block_data.statements.len(); + + assert!(to.statement_index <= terminator_index); + assert!(!to.precedes_in_forward_order(from)); + + // If we have applied the before affect of the statement or terminator at `from` but not its + // after effect, do so now and start the loop below from the next statement. + + let first_unapplied_index = match from.effect { + Effect::Before => from.statement_index, + + Effect::Primary if from.statement_index == terminator_index => { + debug_assert_eq!(from, to); + + let location = Location { block, statement_index: terminator_index }; + let terminator = block_data.terminator(); + analysis.apply_terminator_effect(state, terminator, location); + return; + } + + Effect::Primary => { + let location = Location { block, statement_index: from.statement_index }; + let statement = &block_data.statements[from.statement_index]; + analysis.apply_statement_effect(state, statement, location); + + // If we only needed to apply the after effect of the statement at `idx`, we are done. + if from == to { + return; + } + + from.statement_index + 1 + } + }; + + // Handle all statements between `from` and `to` whose effects must be applied in full. + + for statement_index in first_unapplied_index..to.statement_index { + let location = Location { block, statement_index }; + let statement = &block_data.statements[statement_index]; + analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_statement_effect(state, statement, location); + } + + // Handle the statement or terminator at `to`. + + let location = Location { block, statement_index: to.statement_index }; + if to.statement_index == terminator_index { + let terminator = block_data.terminator(); + analysis.apply_before_terminator_effect(state, terminator, location); + + if to.effect == Effect::Primary { + analysis.apply_terminator_effect(state, terminator, location); + } + } else { + let statement = &block_data.statements[to.statement_index]; + analysis.apply_before_statement_effect(state, statement, location); + + if to.effect == Effect::Primary { + analysis.apply_statement_effect(state, statement, location); + } + } + } + + fn visit_results_in_block( + state: &mut F, + block: BasicBlock, + block_data: &'mir mir::BasicBlockData<'tcx>, + results: &R, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, + ) where + R: ResultsVisitable<'tcx, FlowState = F>, + { + results.reset_to_block_entry(state, block); + + vis.visit_block_start(state, block_data, block); + + for (statement_index, stmt) in block_data.statements.iter().enumerate() { + let loc = Location { block, statement_index }; + results.reconstruct_before_statement_effect(state, stmt, loc); + vis.visit_statement_before_primary_effect(state, stmt, loc); + results.reconstruct_statement_effect(state, stmt, loc); + vis.visit_statement_after_primary_effect(state, stmt, loc); + } + + let loc = Location { block, statement_index: block_data.statements.len() }; + let term = block_data.terminator(); + results.reconstruct_before_terminator_effect(state, term, loc); + vis.visit_terminator_before_primary_effect(state, term, loc); + results.reconstruct_terminator_effect(state, term, loc); + vis.visit_terminator_after_primary_effect(state, term, loc); + + vis.visit_block_end(state, block_data, block); + } + + fn join_state_into_successors_of( + analysis: &A, + _tcx: TyCtxt<'tcx>, + _body: &mir::Body<'tcx>, + dead_unwinds: Option<&BitSet>, + exit_state: &mut A::Domain, + (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), + mut propagate: impl FnMut(BasicBlock, &A::Domain), + ) where + A: Analysis<'tcx>, + { + use mir::TerminatorKind::*; + match bb_data.terminator().kind { + Return | Resume | Abort | GeneratorDrop | Unreachable => {} + + Goto { target } => propagate(target, exit_state), + + Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ } + | Drop { target, unwind, place: _ } + | DropAndReplace { target, unwind, value: _, place: _ } + | FalseUnwind { real_target: target, unwind } => { + if let Some(unwind) = unwind { + if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { + propagate(unwind, exit_state); + } + } + + propagate(target, exit_state); + } + + FalseEdge { real_target, imaginary_target } => { + propagate(real_target, exit_state); + propagate(imaginary_target, exit_state); + } + + Yield { resume: target, drop, resume_arg, value: _ } => { + if let Some(drop) = drop { + propagate(drop, exit_state); + } + + analysis.apply_yield_resume_effect(exit_state, target, resume_arg); + propagate(target, exit_state); + } + + Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => { + if let Some(unwind) = cleanup { + if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { + propagate(unwind, exit_state); + } + } + + if let Some((dest_place, target)) = destination { + // N.B.: This must be done *last*, otherwise the unwind path will see the call + // return effect. + analysis.apply_call_return_effect(exit_state, bb, func, args, dest_place); + propagate(target, exit_state); + } + } + + InlineAsm { template: _, operands: _, options: _, line_spans: _, destination } => { + if let Some(target) = destination { + propagate(target, exit_state); + } + } + + SwitchInt { ref targets, ref discr, switch_ty: _ } => { + let mut applier = SwitchIntEdgeEffectApplier { + exit_state, + targets, + propagate, + effects_applied: false, + }; + + analysis.apply_switch_int_edge_effects(bb, discr, &mut applier); + + let SwitchIntEdgeEffectApplier { + exit_state, mut propagate, effects_applied, .. + } = applier; + + if !effects_applied { + for target in targets.all_targets() { + propagate(*target, exit_state); + } + } + } + } + } +} + +struct SwitchIntEdgeEffectApplier<'a, D, F> { + exit_state: &'a mut D, + targets: &'a SwitchTargets, + propagate: F, + + effects_applied: bool, +} + +impl super::SwitchIntEdgeEffects for SwitchIntEdgeEffectApplier<'_, D, F> +where + D: Clone, + F: FnMut(BasicBlock, &D), +{ + fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { + assert!(!self.effects_applied); + + let mut tmp = None; + for (value, target) in self.targets.iter() { + let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); + apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target }); + (self.propagate)(target, tmp); + } + + // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`, + // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state. + let otherwise = self.targets.otherwise(); + apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise }); + (self.propagate)(otherwise, self.exit_state); + + self.effects_applied = true; + } +} + +/// An analogue of `Option::get_or_insert_with` that stores a clone of `val` into `opt`, but uses +/// the more efficient `clone_from` if `opt` was `Some`. +/// +/// Returns a mutable reference to the new clone that resides in `opt`. +// +// FIXME: Figure out how to express this using `Option::clone_from`, or maybe lift it into the +// standard library? +fn opt_clone_from_or_clone(opt: &'a mut Option, val: &T) -> &'a mut T { + if opt.is_some() { + let ret = opt.as_mut().unwrap(); + ret.clone_from(val); + ret + } else { + *opt = Some(val.clone()); + opt.as_mut().unwrap() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/engine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/engine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/engine.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/engine.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,414 @@ +//! A solver for dataflow problems. + +use std::borrow::BorrowMut; +use std::ffi::OsString; +use std::path::PathBuf; + +use rustc_ast as ast; +use rustc_data_structures::work_queue::WorkQueue; +use rustc_graphviz as dot; +use rustc_hir::def_id::DefId; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::{self, traversal, BasicBlock}; +use rustc_middle::mir::{create_dump_file, dump_enabled}; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::{sym, Symbol}; + +use super::fmt::DebugWithContext; +use super::graphviz; +use super::{ + visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice, + ResultsCursor, ResultsVisitor, +}; + +/// A dataflow analysis that has converged to fixpoint. +pub struct Results<'tcx, A> +where + A: Analysis<'tcx>, +{ + pub analysis: A, + pub(super) entry_sets: IndexVec, +} + +impl Results<'tcx, A> +where + A: Analysis<'tcx>, +{ + /// Creates a `ResultsCursor` that can inspect these `Results`. + pub fn into_results_cursor(self, body: &'mir mir::Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> { + ResultsCursor::new(body, self) + } + + /// Gets the dataflow state for the given block. + pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { + &self.entry_sets[block] + } + + pub fn visit_with( + &self, + body: &'mir mir::Body<'tcx>, + blocks: impl IntoIterator, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, + ) { + visit_results(body, blocks, self, vis) + } + + pub fn visit_reachable_with( + &self, + body: &'mir mir::Body<'tcx>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, + ) { + let blocks = mir::traversal::reachable(body); + visit_results(body, blocks.map(|(bb, _)| bb), self, vis) + } +} + +/// A solver for dataflow problems. +pub struct Engine<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + dead_unwinds: Option<&'a BitSet>, + entry_sets: IndexVec, + pass_name: Option<&'static str>, + analysis: A, + + /// Cached, cumulative transfer functions for each block. + // + // FIXME(ecstaticmorse): This boxed `Fn` trait object is invoked inside a tight loop for + // gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade + // performance in practice. I've tried a few ways to avoid this, but they have downsides. See + // the message for the commit that added this FIXME for more information. + apply_trans_for_block: Option>, +} + +impl Engine<'a, 'tcx, A> +where + A: GenKillAnalysis<'tcx, Idx = T, Domain = D>, + D: Clone + JoinSemiLattice + GenKill + BorrowMut>, + T: Idx, +{ + /// Creates a new `Engine` to solve a gen-kill dataflow problem. + pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self { + // If there are no back-edges in the control-flow graph, we only ever need to apply the + // transfer function for each block exactly once (assuming that we process blocks in RPO). + // + // In this case, there's no need to compute the block transfer functions ahead of time. + if !body.is_cfg_cyclic() { + return Self::new(tcx, body, analysis, None); + } + + // Otherwise, compute and store the cumulative transfer function for each block. + + let identity = GenKillSet::identity(analysis.bottom_value(body).borrow().domain_size()); + let mut trans_for_block = IndexVec::from_elem(identity, body.basic_blocks()); + + for (block, block_data) in body.basic_blocks().iter_enumerated() { + let trans = &mut trans_for_block[block]; + A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data); + } + + let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| { + trans_for_block[bb].apply(state.borrow_mut()); + }); + + Self::new(tcx, body, analysis, Some(apply_trans as Box<_>)) + } +} + +impl Engine<'a, 'tcx, A> +where + A: Analysis<'tcx, Domain = D>, + D: Clone + JoinSemiLattice, +{ + /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer + /// function. + /// + /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for + /// better performance. + pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self { + Self::new(tcx, body, analysis, None) + } + + fn new( + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + analysis: A, + apply_trans_for_block: Option>, + ) -> Self { + let bottom_value = analysis.bottom_value(body); + let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), body.basic_blocks()); + analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); + + if A::Direction::is_backward() && entry_sets[mir::START_BLOCK] != bottom_value { + bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); + } + + Engine { + analysis, + tcx, + body, + dead_unwinds: None, + pass_name: None, + entry_sets, + apply_trans_for_block, + } + } + + /// Signals that we do not want dataflow state to propagate across unwind edges for these + /// `BasicBlock`s. + /// + /// You must take care that `dead_unwinds` does not contain a `BasicBlock` that *can* actually + /// unwind during execution. Otherwise, your dataflow results will not be correct. + pub fn dead_unwinds(mut self, dead_unwinds: &'a BitSet) -> Self { + self.dead_unwinds = Some(dead_unwinds); + self + } + + /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. + /// + /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name` + /// to differentiate them. Otherwise, only the results for the latest run will be saved. + pub fn pass_name(mut self, name: &'static str) -> Self { + self.pass_name = Some(name); + self + } + + /// Computes the fixpoint for this dataflow problem and returns it. + pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> + where + A::Domain: DebugWithContext, + { + let Engine { + analysis, + body, + dead_unwinds, + mut entry_sets, + tcx, + apply_trans_for_block, + pass_name, + .. + } = self; + + let mut dirty_queue: WorkQueue = + WorkQueue::with_none(body.basic_blocks().len()); + + if A::Direction::is_forward() { + for (bb, _) in traversal::reverse_postorder(body) { + dirty_queue.insert(bb); + } + } else { + // Reverse post-order on the reverse CFG may generate a better iteration order for + // backward dataflow analyses, but probably not enough to matter. + for (bb, _) in traversal::postorder(body) { + dirty_queue.insert(bb); + } + } + + // `state` is not actually used between iterations; + // this is just an optimization to avoid reallocating + // every iteration. + let mut state = analysis.bottom_value(body); + while let Some(bb) = dirty_queue.pop() { + let bb_data = &body[bb]; + + // Set the state to the entry state of the block. + // This is equivalent to `state = entry_sets[bb].clone()`, + // but it saves an allocation, thus improving compile times. + state.clone_from(&entry_sets[bb]); + + // Apply the block transfer function, using the cached one if it exists. + match &apply_trans_for_block { + Some(apply) => apply(bb, &mut state), + None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data), + } + + A::Direction::join_state_into_successors_of( + &analysis, + tcx, + body, + dead_unwinds, + &mut state, + (bb, bb_data), + |target: BasicBlock, state: &A::Domain| { + let set_changed = entry_sets[target].join(state); + if set_changed { + dirty_queue.insert(target); + } + }, + ); + } + + let results = Results { analysis, entry_sets }; + + let res = write_graphviz_results(tcx, &body, &results, pass_name); + if let Err(e) = res { + error!("Failed to write graphviz dataflow results: {}", e); + } + + results + } +} + +// Graphviz + +/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via +/// `rustc_mir` attributes. +fn write_graphviz_results( + tcx: TyCtxt<'tcx>, + body: &mir::Body<'tcx>, + results: &Results<'tcx, A>, + pass_name: Option<&'static str>, +) -> std::io::Result<()> +where + A: Analysis<'tcx>, + A::Domain: DebugWithContext, +{ + use std::fs; + use std::io::{self, Write}; + + let def_id = body.source.def_id(); + let attrs = match RustcMirAttrs::parse(tcx, def_id) { + Ok(attrs) => attrs, + + // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse` + Err(()) => return Ok(()), + }; + + let mut file = match attrs.output_path(A::NAME) { + Some(path) => { + debug!("printing dataflow results for {:?} to {}", def_id, path.display()); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + io::BufWriter::new(fs::File::create(&path)?) + } + + None if tcx.sess.opts.debugging_opts.dump_mir_dataflow + && dump_enabled(tcx, A::NAME, def_id) => + { + create_dump_file( + tcx, + ".dot", + None, + A::NAME, + &pass_name.unwrap_or("-----"), + body.source, + )? + } + + _ => return Ok(()), + }; + + let style = match attrs.formatter { + Some(sym::two_phase) => graphviz::OutputStyle::BeforeAndAfter, + _ => graphviz::OutputStyle::AfterOnly, + }; + + let mut buf = Vec::new(); + + let graphviz = graphviz::Formatter::new(body, results, style); + let mut render_opts = + vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())]; + if tcx.sess.opts.debugging_opts.graphviz_dark_mode { + render_opts.push(dot::RenderOption::DarkTheme); + } + dot::render_opts(&graphviz, &mut buf, &render_opts)?; + + file.write_all(&buf)?; + + Ok(()) +} + +#[derive(Default)] +struct RustcMirAttrs { + basename_and_suffix: Option, + formatter: Option, +} + +impl RustcMirAttrs { + fn parse(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result { + let attrs = tcx.get_attrs(def_id); + + let mut result = Ok(()); + let mut ret = RustcMirAttrs::default(); + + let rustc_mir_attrs = attrs + .iter() + .filter(|attr| attr.has_name(sym::rustc_mir)) + .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); + + for attr in rustc_mir_attrs { + let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) { + Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| { + let path = PathBuf::from(s.to_string()); + match path.file_name() { + Some(_) => Ok(path), + None => { + tcx.sess.span_err(attr.span(), "path must end in a filename"); + Err(()) + } + } + }) + } else if attr.has_name(sym::borrowck_graphviz_format) { + Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s { + sym::gen_kill | sym::two_phase => Ok(s), + _ => { + tcx.sess.span_err(attr.span(), "unknown formatter"); + Err(()) + } + }) + } else { + Ok(()) + }; + + result = result.and(attr_result); + } + + result.map(|()| ret) + } + + fn set_field( + field: &mut Option, + tcx: TyCtxt<'tcx>, + attr: &ast::NestedMetaItem, + mapper: impl FnOnce(Symbol) -> Result, + ) -> Result<(), ()> { + if field.is_some() { + tcx.sess + .span_err(attr.span(), &format!("duplicate values for `{}`", attr.name_or_empty())); + + return Err(()); + } + + if let Some(s) = attr.value_str() { + *field = Some(mapper(s)?); + Ok(()) + } else { + tcx.sess + .span_err(attr.span(), &format!("`{}` requires an argument", attr.name_or_empty())); + Err(()) + } + } + + /// Returns the path where dataflow results should be written, or `None` + /// `borrowck_graphviz_postflow` was not specified. + /// + /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`: + /// + /// "path/suffix.dot" -> "path/analysis_name_suffix.dot" + fn output_path(&self, analysis_name: &str) -> Option { + let mut ret = self.basename_and_suffix.as_ref().cloned()?; + let suffix = ret.file_name().unwrap(); // Checked when parsing attrs + + let mut file_name: OsString = analysis_name.into(); + file_name.push("_"); + file_name.push(suffix); + ret.set_file_name(file_name); + + Some(ret) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/fmt.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/fmt.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/fmt.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/fmt.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,172 @@ +//! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow +//! analysis. + +use rustc_index::bit_set::{BitSet, HybridBitSet}; +use rustc_index::vec::Idx; +use std::fmt; + +/// An extension to `fmt::Debug` for data that can be better printed with some auxiliary data `C`. +pub trait DebugWithContext: Eq + fmt::Debug { + fn fmt_with(&self, _ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } + + /// Print the difference between `self` and `old`. + /// + /// This should print nothing if `self == old`. + /// + /// `+` and `-` are typically used to indicate differences. However, these characters are + /// fairly common and may be needed to print a types representation. If using them to indicate + /// a diff, prefix them with the "Unit Separator" control character (⟠U+001F). + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self == old { + return Ok(()); + } + + write!(f, "\u{001f}+")?; + self.fmt_with(ctxt, f)?; + + if f.alternate() { + write!(f, "\n")?; + } else { + write!(f, "\t")?; + } + + write!(f, "\u{001f}-")?; + old.fmt_with(ctxt, f) + } +} + +/// Implements `fmt::Debug` by deferring to `>::fmt_with`. +pub struct DebugWithAdapter<'a, T, C> { + pub this: T, + pub ctxt: &'a C, +} + +impl fmt::Debug for DebugWithAdapter<'_, T, C> +where + T: DebugWithContext, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.this.fmt_with(self.ctxt, f) + } +} + +/// Implements `fmt::Debug` by deferring to `>::fmt_diff_with`. +pub struct DebugDiffWithAdapter<'a, T, C> { + pub new: T, + pub old: T, + pub ctxt: &'a C, +} + +impl fmt::Debug for DebugDiffWithAdapter<'_, T, C> +where + T: DebugWithContext, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.new.fmt_diff_with(&self.old, self.ctxt, f) + } +} + +// Impls + +impl DebugWithContext for BitSet +where + T: Idx + DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter().map(|i| DebugWithAdapter { this: i, ctxt })).finish() + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let size = self.domain_size(); + assert_eq!(size, old.domain_size()); + + let mut set_in_self = HybridBitSet::new_empty(size); + let mut cleared_in_self = HybridBitSet::new_empty(size); + + for i in (0..size).map(T::new) { + match (self.contains(i), old.contains(i)) { + (true, false) => set_in_self.insert(i), + (false, true) => cleared_in_self.insert(i), + _ => continue, + }; + } + + let mut first = true; + for idx in set_in_self.iter() { + let delim = if first { + "\u{001f}+" + } else if f.alternate() { + "\n\u{001f}+" + } else { + ", " + }; + + write!(f, "{}", delim)?; + idx.fmt_with(ctxt, f)?; + first = false; + } + + if !f.alternate() { + first = true; + if !set_in_self.is_empty() && !cleared_in_self.is_empty() { + write!(f, "\t")?; + } + } + + for idx in cleared_in_self.iter() { + let delim = if first { + "\u{001f}-" + } else if f.alternate() { + "\n\u{001f}-" + } else { + ", " + }; + + write!(f, "{}", delim)?; + idx.fmt_with(ctxt, f)?; + first = false; + } + + Ok(()) + } +} + +impl DebugWithContext for &'_ T +where + T: DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (*self).fmt_with(ctxt, f) + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (*self).fmt_diff_with(*old, ctxt, f) + } +} + +impl DebugWithContext for rustc_middle::mir::Local {} +impl DebugWithContext for crate::move_paths::InitIndex {} + +impl<'tcx, C> DebugWithContext for crate::move_paths::MovePathIndex +where + C: crate::move_paths::HasMoveData<'tcx>, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", ctxt.move_data().move_paths[*self]) + } +} + +impl DebugWithContext for crate::lattice::Dual +where + T: DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self.0).fmt_with(ctxt, f) + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self.0).fmt_diff_with(&old.0, ctxt, f) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/graphviz.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/graphviz.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/graphviz.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/graphviz.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,644 @@ +//! A helpful diagram for debugging dataflow problems. + +use std::borrow::Cow; +use std::lazy::SyncOnceCell; +use std::{io, ops, str}; + +use regex::Regex; +use rustc_graphviz as dot; +use rustc_middle::mir::graphviz_safe_def_name; +use rustc_middle::mir::{self, BasicBlock, Body, Location}; + +use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext}; +use super::{Analysis, Direction, Results, ResultsRefCursor, ResultsVisitor}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum OutputStyle { + AfterOnly, + BeforeAndAfter, +} + +impl OutputStyle { + fn num_state_columns(&self) -> usize { + match self { + Self::AfterOnly => 1, + Self::BeforeAndAfter => 2, + } + } +} + +pub struct Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + body: &'a Body<'tcx>, + results: &'a Results<'tcx, A>, + style: OutputStyle, +} + +impl Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self { + Formatter { body, results, style } + } +} + +/// A pair of a basic block and an index into that basic blocks `successors`. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct CfgEdge { + source: BasicBlock, + index: usize, +} + +fn dataflow_successors(body: &Body<'tcx>, bb: BasicBlock) -> Vec { + body[bb] + .terminator() + .successors() + .enumerate() + .map(|(index, _)| CfgEdge { source: bb, index }) + .collect() +} + +impl dot::Labeller<'_> for Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, + A::Domain: DebugWithContext, +{ + type Node = BasicBlock; + type Edge = CfgEdge; + + fn graph_id(&self) -> dot::Id<'_> { + let name = graphviz_safe_def_name(self.body.source.def_id()); + dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap() + } + + fn node_id(&self, n: &Self::Node) -> dot::Id<'_> { + dot::Id::new(format!("bb_{}", n.index())).unwrap() + } + + fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { + let mut label = Vec::new(); + let mut fmt = BlockFormatter { + results: ResultsRefCursor::new(self.body, self.results), + style: self.style, + bg: Background::Light, + }; + + fmt.write_node_label(&mut label, self.body, *block).unwrap(); + dot::LabelText::html(String::from_utf8(label).unwrap()) + } + + fn node_shape(&self, _n: &Self::Node) -> Option> { + Some(dot::LabelText::label("none")) + } + + fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { + let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index]; + dot::LabelText::label(label.clone()) + } +} + +impl dot::GraphWalk<'a> for Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + type Node = BasicBlock; + type Edge = CfgEdge; + + fn nodes(&self) -> dot::Nodes<'_, Self::Node> { + self.body.basic_blocks().indices().collect::>().into() + } + + fn edges(&self) -> dot::Edges<'_, Self::Edge> { + self.body + .basic_blocks() + .indices() + .flat_map(|bb| dataflow_successors(self.body, bb)) + .collect::>() + .into() + } + + fn source(&self, edge: &Self::Edge) -> Self::Node { + edge.source + } + + fn target(&self, edge: &Self::Edge) -> Self::Node { + self.body[edge.source].terminator().successors().nth(edge.index).copied().unwrap() + } +} + +struct BlockFormatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + results: ResultsRefCursor<'a, 'a, 'tcx, A>, + bg: Background, + style: OutputStyle, +} + +impl BlockFormatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, + A::Domain: DebugWithContext, +{ + const HEADER_COLOR: &'static str = "#a0a0a0"; + + fn toggle_background(&mut self) -> Background { + let bg = self.bg; + self.bg = !bg; + bg + } + + fn write_node_label( + &mut self, + w: &mut impl io::Write, + body: &'a Body<'tcx>, + block: BasicBlock, + ) -> io::Result<()> { + // Sample output: + // +-+-----------------------------------------------+ + // A | bb4 | + // +-+----------------------------------+------------+ + // B | MIR | STATE | + // +-+----------------------------------+------------+ + // C | | (on entry) | {_0,_2,_3} | + // +-+----------------------------------+------------+ + // D |0| StorageLive(_7) | | + // +-+----------------------------------+------------+ + // |1| StorageLive(_8) | | + // +-+----------------------------------+------------+ + // |2| _8 = &mut _1 | +_8 | + // +-+----------------------------------+------------+ + // E |T| _4 = const Foo::twiddle(move _2) | -_2 | + // +-+----------------------------------+------------+ + // F | | (on unwind) | {_0,_3,_8} | + // +-+----------------------------------+------------+ + // | | (on successful return) | +_4 | + // +-+----------------------------------+------------+ + + // N.B., Some attributes (`align`, `balign`) are repeated on parent elements and their + // children. This is because `xdot` seemed to have a hard time correctly propagating + // attributes. Make sure to test the output before trying to remove the redundancy. + // Notably, `align` was found to have no effect when applied only to . + + let table_fmt = concat!( + " border=\"1\"", + " cellborder=\"1\"", + " cellspacing=\"0\"", + " cellpadding=\"3\"", + " sides=\"rb\"", + ); + write!(w, r#""#, fmt = table_fmt)?; + + // A + B: Block header + match self.style { + OutputStyle::AfterOnly => self.write_block_header_simple(w, block)?, + OutputStyle::BeforeAndAfter => { + self.write_block_header_with_state_columns(w, block, &["BEFORE", "AFTER"])? + } + } + + // C: State at start of block + self.bg = Background::Light; + self.results.seek_to_block_start(block); + let block_start_state = self.results.get().clone(); + self.write_row_with_full_state(w, "", "(on start)")?; + + // D + E: Statement and terminator transfer functions + self.write_statements_and_terminator(w, body, block)?; + + // F: State at end of block + + let terminator = body[block].terminator(); + + // Write the full dataflow state immediately after the terminator if it differs from the + // state at block entry. + self.results.seek_to_block_end(block); + if self.results.get() != &block_start_state || A::Direction::is_backward() { + let after_terminator_name = match terminator.kind { + mir::TerminatorKind::Call { destination: Some(_), .. } => "(on unwind)", + _ => "(on end)", + }; + + self.write_row_with_full_state(w, "", after_terminator_name)?; + } + + // Write any changes caused by terminator-specific effects. + // + // FIXME: These should really be printed as part of each outgoing edge rather than the node + // for the basic block itself. That way, we could display terminator-specific effects for + // backward dataflow analyses as well as effects for `SwitchInt` terminators. + match terminator.kind { + mir::TerminatorKind::Call { + destination: Some((return_place, _)), + ref func, + ref args, + .. + } => { + self.write_row(w, "", "(on successful return)", |this, w, fmt| { + let state_on_unwind = this.results.get().clone(); + this.results.apply_custom_effect(|analysis, state| { + analysis.apply_call_return_effect(state, block, func, args, return_place); + }); + + write!( + w, + r#""#, + colspan = this.style.num_state_columns(), + fmt = fmt, + diff = diff_pretty( + this.results.get(), + &state_on_unwind, + this.results.analysis() + ), + ) + })?; + } + + mir::TerminatorKind::Yield { resume, resume_arg, .. } => { + self.write_row(w, "", "(on yield resume)", |this, w, fmt| { + let state_on_generator_drop = this.results.get().clone(); + this.results.apply_custom_effect(|analysis, state| { + analysis.apply_yield_resume_effect(state, resume, resume_arg); + }); + + write!( + w, + r#""#, + colspan = this.style.num_state_columns(), + fmt = fmt, + diff = diff_pretty( + this.results.get(), + &state_on_generator_drop, + this.results.analysis() + ), + ) + })?; + } + + _ => {} + }; + + write!(w, "
{diff}{diff}
") + } + + fn write_block_header_simple( + &mut self, + w: &mut impl io::Write, + block: BasicBlock, + ) -> io::Result<()> { + // +-------------------------------------------------+ + // A | bb4 | + // +-----------------------------------+-------------+ + // B | MIR | STATE | + // +-+---------------------------------+-------------+ + // | | ... | | + + // A + write!( + w, + concat!("", r#"bb{block_id}"#, "",), + block_id = block.index(), + )?; + + // B + write!( + w, + concat!( + "", + r#"MIR"#, + r#"STATE"#, + "", + ), + fmt = format!("bgcolor=\"{}\" sides=\"tl\"", Self::HEADER_COLOR), + ) + } + + fn write_block_header_with_state_columns( + &mut self, + w: &mut impl io::Write, + block: BasicBlock, + state_column_names: &[&str], + ) -> io::Result<()> { + // +------------------------------------+-------------+ + // A | bb4 | STATE | + // +------------------------------------+------+------+ + // B | MIR | GEN | KILL | + // +-+----------------------------------+------+------+ + // | | ... | | | + + // A + write!( + w, + concat!( + "", + r#"bb{block_id}"#, + r#"STATE"#, + "", + ), + fmt = "sides=\"tl\"", + num_state_cols = state_column_names.len(), + block_id = block.index(), + )?; + + // B + let fmt = format!("bgcolor=\"{}\" sides=\"tl\"", Self::HEADER_COLOR); + write!(w, concat!("", r#"MIR"#,), fmt = fmt,)?; + + for name in state_column_names { + write!(w, "{name}", fmt = fmt, name = name)?; + } + + write!(w, "") + } + + fn write_statements_and_terminator( + &mut self, + w: &mut impl io::Write, + body: &'a Body<'tcx>, + block: BasicBlock, + ) -> io::Result<()> { + let diffs = StateDiffCollector::run(body, block, self.results.results(), self.style); + + let mut befores = diffs.before.map(|v| v.into_iter()); + let mut afters = diffs.after.into_iter(); + + let next_in_dataflow_order = |it: &mut std::vec::IntoIter<_>| { + if A::Direction::is_forward() { it.next().unwrap() } else { it.next_back().unwrap() } + }; + + for (i, statement) in body[block].statements.iter().enumerate() { + let statement_str = format!("{:?}", statement); + let index_str = format!("{}", i); + + let after = next_in_dataflow_order(&mut afters); + let before = befores.as_mut().map(next_in_dataflow_order); + + self.write_row(w, &index_str, &statement_str, |_this, w, fmt| { + if let Some(before) = before { + write!(w, r#"{diff}"#, fmt = fmt, diff = before)?; + } + + write!(w, r#"{diff}"#, fmt = fmt, diff = after) + })?; + } + + let after = next_in_dataflow_order(&mut afters); + let before = befores.as_mut().map(next_in_dataflow_order); + + assert!(afters.is_empty()); + assert!(befores.as_ref().map_or(true, ExactSizeIterator::is_empty)); + + let terminator = body[block].terminator(); + let mut terminator_str = String::new(); + terminator.kind.fmt_head(&mut terminator_str).unwrap(); + + self.write_row(w, "T", &terminator_str, |_this, w, fmt| { + if let Some(before) = before { + write!(w, r#"{diff}"#, fmt = fmt, diff = before)?; + } + + write!(w, r#"{diff}"#, fmt = fmt, diff = after) + }) + } + + /// Write a row with the given index and MIR, using the function argument to fill in the + /// "STATE" column(s). + fn write_row( + &mut self, + w: &mut W, + i: &str, + mir: &str, + f: impl FnOnce(&mut Self, &mut W, &str) -> io::Result<()>, + ) -> io::Result<()> { + let bg = self.toggle_background(); + let valign = if mir.starts_with("(on ") && mir != "(on entry)" { "bottom" } else { "top" }; + + let fmt = format!("valign=\"{}\" sides=\"tl\" {}", valign, bg.attr()); + + write!( + w, + concat!( + "", + r#"{i}"#, + r#"{mir}"#, + ), + i = i, + fmt = fmt, + mir = dot::escape_html(mir), + )?; + + f(self, w, &fmt)?; + write!(w, "") + } + + fn write_row_with_full_state( + &mut self, + w: &mut impl io::Write, + i: &str, + mir: &str, + ) -> io::Result<()> { + self.write_row(w, i, mir, |this, w, fmt| { + let state = this.results.get(); + let analysis = this.results.analysis(); + + // FIXME: The full state vector can be quite long. It would be nice to split on commas + // and use some text wrapping algorithm. + write!( + w, + r#"{state}"#, + colspan = this.style.num_state_columns(), + fmt = fmt, + state = format!("{:?}", DebugWithAdapter { this: state, ctxt: analysis }), + ) + }) + } +} + +struct StateDiffCollector<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + analysis: &'a A, + prev_state: A::Domain, + before: Option>, + after: Vec, +} + +impl
StateDiffCollector<'a, 'tcx, A> +where + A: Analysis<'tcx>, + A::Domain: DebugWithContext, +{ + fn run( + body: &'a mir::Body<'tcx>, + block: BasicBlock, + results: &'a Results<'tcx, A>, + style: OutputStyle, + ) -> Self { + let mut collector = StateDiffCollector { + analysis: &results.analysis, + prev_state: results.analysis.bottom_value(body), + after: vec![], + before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), + }; + + results.visit_with(body, std::iter::once(block), &mut collector); + collector + } +} + +impl ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A> +where + A: Analysis<'tcx>, + A::Domain: DebugWithContext, +{ + type FlowState = A::Domain; + + fn visit_block_start( + &mut self, + state: &Self::FlowState, + _block_data: &'mir mir::BasicBlockData<'tcx>, + _block: BasicBlock, + ) { + if A::Direction::is_forward() { + self.prev_state.clone_from(state); + } + } + + fn visit_block_end( + &mut self, + state: &Self::FlowState, + _block_data: &'mir mir::BasicBlockData<'tcx>, + _block: BasicBlock, + ) { + if A::Direction::is_backward() { + self.prev_state.clone_from(state); + } + } + + fn visit_statement_before_primary_effect( + &mut self, + state: &Self::FlowState, + _statement: &'mir mir::Statement<'tcx>, + _location: Location, + ) { + if let Some(before) = self.before.as_mut() { + before.push(diff_pretty(state, &self.prev_state, self.analysis)); + self.prev_state.clone_from(state) + } + } + + fn visit_statement_after_primary_effect( + &mut self, + state: &Self::FlowState, + _statement: &'mir mir::Statement<'tcx>, + _location: Location, + ) { + self.after.push(diff_pretty(state, &self.prev_state, self.analysis)); + self.prev_state.clone_from(state) + } + + fn visit_terminator_before_primary_effect( + &mut self, + state: &Self::FlowState, + _terminator: &'mir mir::Terminator<'tcx>, + _location: Location, + ) { + if let Some(before) = self.before.as_mut() { + before.push(diff_pretty(state, &self.prev_state, self.analysis)); + self.prev_state.clone_from(state) + } + } + + fn visit_terminator_after_primary_effect( + &mut self, + state: &Self::FlowState, + _terminator: &'mir mir::Terminator<'tcx>, + _location: Location, + ) { + self.after.push(diff_pretty(state, &self.prev_state, self.analysis)); + self.prev_state.clone_from(state) + } +} + +macro_rules! regex { + ($re:literal $(,)?) => {{ + static RE: SyncOnceCell = SyncOnceCell::new(); + RE.get_or_init(|| Regex::new($re).unwrap()) + }}; +} + +fn diff_pretty(new: T, old: T, ctxt: &C) -> String +where + T: DebugWithContext, +{ + if new == old { + return String::new(); + } + + let re = regex!("\t?\u{001f}([+-])"); + + let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt }); + + // Replace newlines in the `Debug` output with `
` + let raw_diff = raw_diff.replace('\n', r#"
"#); + + let mut inside_font_tag = false; + let html_diff = re.replace_all(&raw_diff, |captures: ®ex::Captures<'_>| { + let mut ret = String::new(); + if inside_font_tag { + ret.push_str(r#"
"#); + } + + let tag = match &captures[1] { + "+" => r#"+"#, + "-" => r#"-"#, + _ => unreachable!(), + }; + + inside_font_tag = true; + ret.push_str(tag); + ret + }); + + let mut html_diff = match html_diff { + Cow::Borrowed(_) => return raw_diff, + Cow::Owned(s) => s, + }; + + if inside_font_tag { + html_diff.push_str(""); + } + + html_diff +} + +/// The background color used for zebra-striping the table. +#[derive(Clone, Copy)] +enum Background { + Light, + Dark, +} + +impl Background { + fn attr(self) -> &'static str { + match self { + Self::Dark => "bgcolor=\"#f0f0f0\"", + Self::Light => "", + } + } +} + +impl ops::Not for Background { + type Output = Self; + + fn not(self) -> Self { + match self { + Self::Light => Self::Dark, + Self::Dark => Self::Light, + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/lattice.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/lattice.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/lattice.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/lattice.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,231 @@ +//! Traits used to represent [lattices] for use as the domain of a dataflow analysis. +//! +//! # Overview +//! +//! The most common lattice is a powerset of some set `S`, ordered by [set inclusion]. The [Hasse +//! diagram] for the powerset of a set with two elements (`X` and `Y`) is shown below. Note that +//! distinct elements at the same height in a Hasse diagram (e.g. `{X}` and `{Y}`) are +//! *incomparable*, not equal. +//! +//! ```text +//! {X, Y} <- top +//! / \ +//! {X} {Y} +//! \ / +//! {} <- bottom +//! +//! ``` +//! +//! The defining characteristic of a lattice—the one that differentiates it from a [partially +//! ordered set][poset]—is the existence of a *unique* least upper and greatest lower bound for +//! every pair of elements. The lattice join operator (`∨`) returns the least upper bound, and the +//! lattice meet operator (`∧`) returns the greatest lower bound. Types that implement one operator +//! but not the other are known as semilattices. Dataflow analysis only uses the join operator and +//! will work with any join-semilattice, but both should be specified when possible. +//! +//! ## `PartialOrd` +//! +//! Given that they represent partially ordered sets, you may be surprised that [`JoinSemiLattice`] +//! and [`MeetSemiLattice`] do not have [`PartialOrd`][std::cmp::PartialOrd] as a supertrait. This +//! is because most standard library types use lexicographic ordering instead of set inclusion for +//! their `PartialOrd` impl. Since we do not actually need to compare lattice elements to run a +//! dataflow analysis, there's no need for a newtype wrapper with a custom `PartialOrd` impl. The +//! only benefit would be the ability to check that the least upper (or greatest lower) bound +//! returned by the lattice join (or meet) operator was in fact greater (or lower) than the inputs. +//! +//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) +//! [set inclusion]: https://en.wikipedia.org/wiki/Subset +//! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram +//! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set + +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; +use std::iter; + +/// A [partially ordered set][poset] that has a [least upper bound][lub] for any pair of elements +/// in the set. +/// +/// [lub]: https://en.wikipedia.org/wiki/Infimum_and_supremum +/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set +pub trait JoinSemiLattice: Eq { + /// Computes the least upper bound of two elements, storing the result in `self` and returning + /// `true` if `self` has changed. + /// + /// The lattice join operator is abbreviated as `∨`. + fn join(&mut self, other: &Self) -> bool; +} + +/// A [partially ordered set][poset] that has a [greatest lower bound][glb] for any pair of +/// elements in the set. +/// +/// Dataflow analyses only require that their domains implement [`JoinSemiLattice`], not +/// `MeetSemiLattice`. However, types that will be used as dataflow domains should implement both +/// so that they can be used with [`Dual`]. +/// +/// [glb]: https://en.wikipedia.org/wiki/Infimum_and_supremum +/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set +pub trait MeetSemiLattice: Eq { + /// Computes the greatest lower bound of two elements, storing the result in `self` and + /// returning `true` if `self` has changed. + /// + /// The lattice meet operator is abbreviated as `∧`. + fn meet(&mut self, other: &Self) -> bool; +} + +/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom: +/// +/// ```text +/// true +/// | +/// false +/// ``` +impl JoinSemiLattice for bool { + fn join(&mut self, other: &Self) -> bool { + if let (false, true) = (*self, *other) { + *self = true; + return true; + } + + false + } +} + +impl MeetSemiLattice for bool { + fn meet(&mut self, other: &Self) -> bool { + if let (true, false) = (*self, *other) { + *self = false; + return true; + } + + false + } +} + +/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation +/// of the least upper bounds of each element of the tuple (or list). +/// +/// In other words: +/// (Aâ‚€, Aâ‚, ..., Aâ‚™) ∨ (Bâ‚€, Bâ‚, ..., Bâ‚™) = (A₀∨Bâ‚€, Aâ‚∨Bâ‚, ..., Aₙ∨Bâ‚™) +impl JoinSemiLattice for IndexVec { + fn join(&mut self, other: &Self) -> bool { + assert_eq!(self.len(), other.len()); + + let mut changed = false; + for (a, b) in iter::zip(self, other) { + changed |= a.join(b); + } + changed + } +} + +impl MeetSemiLattice for IndexVec { + fn meet(&mut self, other: &Self) -> bool { + assert_eq!(self.len(), other.len()); + + let mut changed = false; + for (a, b) in iter::zip(self, other) { + changed |= a.meet(b); + } + changed + } +} + +/// A `BitSet` represents the lattice formed by the powerset of all possible values of +/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices, +/// one for each possible value of `T`. +impl JoinSemiLattice for BitSet { + fn join(&mut self, other: &Self) -> bool { + self.union(other) + } +} + +impl MeetSemiLattice for BitSet { + fn meet(&mut self, other: &Self) -> bool { + self.intersect(other) + } +} + +/// The counterpart of a given semilattice `T` using the [inverse order]. +/// +/// The dual of a join-semilattice is a meet-semilattice and vice versa. For example, the dual of a +/// powerset has the empty set as its top element and the full set as its bottom element and uses +/// set *intersection* as its join operator. +/// +/// [inverse order]: https://en.wikipedia.org/wiki/Duality_(order_theory) +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Dual(pub T); + +impl std::borrow::Borrow for Dual { + fn borrow(&self) -> &T { + &self.0 + } +} + +impl std::borrow::BorrowMut for Dual { + fn borrow_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl JoinSemiLattice for Dual { + fn join(&mut self, other: &Self) -> bool { + self.0.meet(&other.0) + } +} + +impl MeetSemiLattice for Dual { + fn meet(&mut self, other: &Self) -> bool { + self.0.join(&other.0) + } +} + +/// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no +/// value of `T` is comparable with any other. A flat set has the following [Hasse diagram]: +/// +/// ```text +/// top +/// / / \ \ +/// all possible values of `T` +/// \ \ / / +/// bottom +/// ``` +/// +/// [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FlatSet { + Bottom, + Elem(T), + Top, +} + +impl JoinSemiLattice for FlatSet { + fn join(&mut self, other: &Self) -> bool { + let result = match (&*self, other) { + (Self::Top, _) | (_, Self::Bottom) => return false, + (Self::Elem(a), Self::Elem(b)) if a == b => return false, + + (Self::Bottom, Self::Elem(x)) => Self::Elem(x.clone()), + + _ => Self::Top, + }; + + *self = result; + true + } +} + +impl MeetSemiLattice for FlatSet { + fn meet(&mut self, other: &Self) -> bool { + let result = match (&*self, other) { + (Self::Bottom, _) | (_, Self::Top) => return false, + (Self::Elem(ref a), Self::Elem(ref b)) if a == b => return false, + + (Self::Top, Self::Elem(ref x)) => Self::Elem(x.clone()), + + _ => Self::Bottom, + }; + + *self = result; + true + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,546 @@ +//! A framework that can express both [gen-kill] and generic dataflow problems. +//! +//! To actually use this framework, you must implement either the `Analysis` or the +//! `GenKillAnalysis` trait. If your transfer function can be expressed with only gen/kill +//! operations, prefer `GenKillAnalysis` since it will run faster while iterating to fixpoint. The +//! `impls` module contains several examples of gen/kill dataflow analyses. +//! +//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait, +//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the +//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use +//! `visit_results`. The following example uses the `ResultsCursor` approach. +//! +//! ```ignore (cross-crate-imports) +//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available. +//! +//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { +//! let analysis = MyAnalysis::new() +//! .into_engine(tcx, body) +//! .iterate_to_fixpoint() +//! .into_results_cursor(body); +//! +//! // Print the dataflow state *after* each statement in the start block. +//! for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() { +//! cursor.seek_after(Location { block: START_BLOCK, statement_index }); +//! let state = cursor.get(); +//! println!("{:?}", state); +//! } +//! } +//! ``` +//! +//! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems + +use std::borrow::BorrowMut; +use std::cmp::Ordering; + +use rustc_index::bit_set::{BitSet, HybridBitSet}; +use rustc_index::vec::Idx; +use rustc_middle::mir::{self, BasicBlock, Location}; +use rustc_middle::ty::TyCtxt; + +mod cursor; +mod direction; +mod engine; +pub mod fmt; +pub mod graphviz; +pub mod lattice; +mod visitor; + +pub use self::cursor::{ResultsCursor, ResultsRefCursor}; +pub use self::direction::{Backward, Direction, Forward}; +pub use self::engine::{Engine, Results}; +pub use self::lattice::{JoinSemiLattice, MeetSemiLattice}; +pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor}; + +/// Define the domain of a dataflow problem. +/// +/// This trait specifies the lattice on which this analysis operates (the domain) as well as its +/// initial value at the entry point of each basic block. +pub trait AnalysisDomain<'tcx> { + /// The type that holds the dataflow state at any given point in the program. + type Domain: Clone + JoinSemiLattice; + + /// The direction of this analysis. Either `Forward` or `Backward`. + type Direction: Direction = Forward; + + /// A descriptive name for this analysis. Used only for debugging. + /// + /// This name should be brief and contain no spaces, periods or other characters that are not + /// suitable as part of a filename. + const NAME: &'static str; + + /// The initial value of the dataflow state upon entry to each basic block. + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; + + /// Mutates the initial value of the dataflow state upon entry to the `START_BLOCK`. + /// + /// For backward analyses, initial state besides the bottom value is not yet supported. Trying + /// to mutate the initial state will result in a panic. + // + // FIXME: For backward dataflow analyses, the initial state should be applied to every basic + // block where control flow could exit the MIR body (e.g., those terminated with `return` or + // `resume`). It's not obvious how to handle `yield` points in generators, however. + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain); +} + +/// A dataflow problem with an arbitrarily complex transfer function. +/// +/// # Convergence +/// +/// When implementing this trait directly (not via [`GenKillAnalysis`]), it's possible to choose a +/// transfer function such that the analysis does not reach fixpoint. To guarantee convergence, +/// your transfer functions must maintain the following invariant: +/// +/// > If the dataflow state **before** some point in the program changes to be greater +/// than the prior state **before** that point, the dataflow state **after** that point must +/// also change to be greater than the prior state **after** that point. +/// +/// This invariant guarantees that the dataflow state at a given point in the program increases +/// monotonically until fixpoint is reached. Note that this monotonicity requirement only applies +/// to the same point in the program at different points in time. The dataflow state at a given +/// point in the program may or may not be greater than the state at any preceding point. +pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { + /// Updates the current dataflow state with the effect of evaluating a statement. + fn apply_statement_effect( + &self, + state: &mut Self::Domain, + statement: &mir::Statement<'tcx>, + location: Location, + ); + + /// Updates the current dataflow state with an effect that occurs immediately *before* the + /// given statement. + /// + /// This method is useful if the consumer of the results of this analysis needs only to observe + /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule, + /// analyses should not implement this without implementing `apply_statement_effect`. + fn apply_before_statement_effect( + &self, + _state: &mut Self::Domain, + _statement: &mir::Statement<'tcx>, + _location: Location, + ) { + } + + /// Updates the current dataflow state with the effect of evaluating a terminator. + /// + /// The effect of a successful return from a `Call` terminator should **not** be accounted for + /// in this function. That should go in `apply_call_return_effect`. For example, in the + /// `InitializedPlaces` analyses, the return place for a function call is not marked as + /// initialized here. + fn apply_terminator_effect( + &self, + state: &mut Self::Domain, + terminator: &mir::Terminator<'tcx>, + location: Location, + ); + + /// Updates the current dataflow state with an effect that occurs immediately *before* the + /// given terminator. + /// + /// This method is useful if the consumer of the results of this analysis needs only to observe + /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule, + /// analyses should not implement this without implementing `apply_terminator_effect`. + fn apply_before_terminator_effect( + &self, + _state: &mut Self::Domain, + _terminator: &mir::Terminator<'tcx>, + _location: Location, + ) { + } + + /* Edge-specific effects */ + + /// Updates the current dataflow state with the effect of a successful return from a `Call` + /// terminator. + /// + /// This is separate from `apply_terminator_effect` to properly track state across unwind + /// edges. + fn apply_call_return_effect( + &self, + state: &mut Self::Domain, + block: BasicBlock, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ); + + /// Updates the current dataflow state with the effect of resuming from a `Yield` terminator. + /// + /// This is similar to `apply_call_return_effect` in that it only takes place after the + /// generator is resumed, not when it is dropped. + /// + /// By default, no effects happen. + fn apply_yield_resume_effect( + &self, + _state: &mut Self::Domain, + _resume_block: BasicBlock, + _resume_place: mir::Place<'tcx>, + ) { + } + + /// Updates the current dataflow state with the effect of taking a particular branch in a + /// `SwitchInt` terminator. + /// + /// Unlike the other edge-specific effects, which are allowed to mutate `Self::Domain` + /// directly, overriders of this method must pass a callback to + /// `SwitchIntEdgeEffects::apply`. The callback will be run once for each outgoing edge and + /// will have access to the dataflow state that will be propagated along that edge. + /// + /// This interface is somewhat more complex than the other visitor-like "effect" methods. + /// However, it is both more ergonomic—callers don't need to recompute or cache information + /// about a given `SwitchInt` terminator for each one of its edges—and more efficient—the + /// engine doesn't need to clone the exit state for a block unless + /// `SwitchIntEdgeEffects::apply` is actually called. + /// + /// FIXME: This class of effects is not supported for backward dataflow analyses. + fn apply_switch_int_edge_effects( + &self, + _block: BasicBlock, + _discr: &mir::Operand<'tcx>, + _apply_edge_effects: &mut impl SwitchIntEdgeEffects, + ) { + } + + /* Extension methods */ + + /// Creates an `Engine` to find the fixpoint for this dataflow problem. + /// + /// You shouldn't need to override this outside this module, since the combination of the + /// default impl and the one for all `A: GenKillAnalysis` will do the right thing. + /// Its purpose is to enable method chaining like so: + /// + /// ```ignore (cross-crate-imports) + /// let results = MyAnalysis::new(tcx, body) + /// .into_engine(tcx, body, def_id) + /// .iterate_to_fixpoint() + /// .into_results_cursor(body); + /// ``` + fn into_engine(self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Engine<'mir, 'tcx, Self> + where + Self: Sized, + { + Engine::new_generic(tcx, body, self) + } +} + +/// A gen/kill dataflow problem. +/// +/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only +/// allow modification of the dataflow state via "gen" and "kill" operations. By defining transfer +/// functions for each statement in this way, the transfer function for an entire basic block can +/// be computed efficiently. +/// +/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis`. +pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { + type Idx: Idx; + + /// See `Analysis::apply_statement_effect`. + fn statement_effect( + &self, + trans: &mut impl GenKill, + statement: &mir::Statement<'tcx>, + location: Location, + ); + + /// See `Analysis::apply_before_statement_effect`. + fn before_statement_effect( + &self, + _trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + _location: Location, + ) { + } + + /// See `Analysis::apply_terminator_effect`. + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + location: Location, + ); + + /// See `Analysis::apply_before_terminator_effect`. + fn before_terminator_effect( + &self, + _trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + _location: Location, + ) { + } + + /* Edge-specific effects */ + + /// See `Analysis::apply_call_return_effect`. + fn call_return_effect( + &self, + trans: &mut impl GenKill, + block: BasicBlock, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ); + + /// See `Analysis::apply_yield_resume_effect`. + fn yield_resume_effect( + &self, + _trans: &mut impl GenKill, + _resume_block: BasicBlock, + _resume_place: mir::Place<'tcx>, + ) { + } + + /// See `Analysis::apply_switch_int_edge_effects`. + fn switch_int_edge_effects>( + &self, + _block: BasicBlock, + _discr: &mir::Operand<'tcx>, + _edge_effects: &mut impl SwitchIntEdgeEffects, + ) { + } +} + +impl Analysis<'tcx> for A +where + A: GenKillAnalysis<'tcx>, + A::Domain: GenKill + BorrowMut>, +{ + fn apply_statement_effect( + &self, + state: &mut A::Domain, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.statement_effect(state, statement, location); + } + + fn apply_before_statement_effect( + &self, + state: &mut A::Domain, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.before_statement_effect(state, statement, location); + } + + fn apply_terminator_effect( + &self, + state: &mut A::Domain, + terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + self.terminator_effect(state, terminator, location); + } + + fn apply_before_terminator_effect( + &self, + state: &mut A::Domain, + terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + self.before_terminator_effect(state, terminator, location); + } + + /* Edge-specific effects */ + + fn apply_call_return_effect( + &self, + state: &mut A::Domain, + block: BasicBlock, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ) { + self.call_return_effect(state, block, func, args, return_place); + } + + fn apply_yield_resume_effect( + &self, + state: &mut A::Domain, + resume_block: BasicBlock, + resume_place: mir::Place<'tcx>, + ) { + self.yield_resume_effect(state, resume_block, resume_place); + } + + fn apply_switch_int_edge_effects( + &self, + block: BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, + ) { + self.switch_int_edge_effects(block, discr, edge_effects); + } + + /* Extension methods */ + + fn into_engine(self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Engine<'mir, 'tcx, Self> + where + Self: Sized, + { + Engine::new_gen_kill(tcx, body, self) + } +} + +/// The legal operations for a transfer function in a gen/kill problem. +/// +/// This abstraction exists because there are two different contexts in which we call the methods in +/// `GenKillAnalysis`. Sometimes we need to store a single transfer function that can be efficiently +/// applied multiple times, such as when computing the cumulative transfer function for each block. +/// These cases require a `GenKillSet`, which in turn requires two `BitSet`s of storage. Oftentimes, +/// however, we only need to apply an effect once. In *these* cases, it is more efficient to pass the +/// `BitSet` representing the state vector directly into the `*_effect` methods as opposed to +/// building up a `GenKillSet` and then throwing it away. +pub trait GenKill { + /// Inserts `elem` into the state vector. + fn gen(&mut self, elem: T); + + /// Removes `elem` from the state vector. + fn kill(&mut self, elem: T); + + /// Calls `gen` for each element in `elems`. + fn gen_all(&mut self, elems: impl IntoIterator) { + for elem in elems { + self.gen(elem); + } + } + + /// Calls `kill` for each element in `elems`. + fn kill_all(&mut self, elems: impl IntoIterator) { + for elem in elems { + self.kill(elem); + } + } +} + +/// Stores a transfer function for a gen/kill problem. +/// +/// Calling `gen`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be +/// applied multiple times efficiently. When there are multiple calls to `gen` and/or `kill` for +/// the same element, the most recent one takes precedence. +#[derive(Clone)] +pub struct GenKillSet { + gen: HybridBitSet, + kill: HybridBitSet, +} + +impl GenKillSet { + /// Creates a new transfer function that will leave the dataflow state unchanged. + pub fn identity(universe: usize) -> Self { + GenKillSet { + gen: HybridBitSet::new_empty(universe), + kill: HybridBitSet::new_empty(universe), + } + } + + pub fn apply(&self, state: &mut BitSet) { + state.union(&self.gen); + state.subtract(&self.kill); + } +} + +impl GenKill for GenKillSet { + fn gen(&mut self, elem: T) { + self.gen.insert(elem); + self.kill.remove(elem); + } + + fn kill(&mut self, elem: T) { + self.kill.insert(elem); + self.gen.remove(elem); + } +} + +impl GenKill for BitSet { + fn gen(&mut self, elem: T) { + self.insert(elem); + } + + fn kill(&mut self, elem: T) { + self.remove(elem); + } +} + +impl GenKill for lattice::Dual> { + fn gen(&mut self, elem: T) { + self.0.insert(elem); + } + + fn kill(&mut self, elem: T) { + self.0.remove(elem); + } +} + +// NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Effect { + /// The "before" effect (e.g., `apply_before_statement_effect`) for a statement (or + /// terminator). + Before, + + /// The "primary" effect (e.g., `apply_statement_effect`) for a statement (or terminator). + Primary, +} + +impl Effect { + pub const fn at_index(self, statement_index: usize) -> EffectIndex { + EffectIndex { effect: self, statement_index } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct EffectIndex { + statement_index: usize, + effect: Effect, +} + +impl EffectIndex { + fn next_in_forward_order(self) -> Self { + match self.effect { + Effect::Before => Effect::Primary.at_index(self.statement_index), + Effect::Primary => Effect::Before.at_index(self.statement_index + 1), + } + } + + fn next_in_backward_order(self) -> Self { + match self.effect { + Effect::Before => Effect::Primary.at_index(self.statement_index), + Effect::Primary => Effect::Before.at_index(self.statement_index - 1), + } + } + + /// Returns `true` if the effect at `self` should be applied earlier than the effect at `other` + /// in forward order. + fn precedes_in_forward_order(self, other: Self) -> bool { + let ord = self + .statement_index + .cmp(&other.statement_index) + .then_with(|| self.effect.cmp(&other.effect)); + ord == Ordering::Less + } + + /// Returns `true` if the effect at `self` should be applied earlier than the effect at `other` + /// in backward order. + fn precedes_in_backward_order(self, other: Self) -> bool { + let ord = other + .statement_index + .cmp(&self.statement_index) + .then_with(|| self.effect.cmp(&other.effect)); + ord == Ordering::Less + } +} + +pub struct SwitchIntTarget { + pub value: Option, + pub target: BasicBlock, +} + +/// A type that records the edge-specific effects for a `SwitchInt` terminator. +pub trait SwitchIntEdgeEffects { + /// Calls `apply_edge_effect` for each outgoing edge from a `SwitchInt` terminator and + /// records the results. + fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)); +} + +#[cfg(test)] +mod tests; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/tests.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,320 @@ +//! A test for the logic that updates the state in a `ResultsCursor` during seek. + +use std::marker::PhantomData; + +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::{self, BasicBlock, Location}; +use rustc_middle::ty; +use rustc_span::DUMMY_SP; + +use super::*; + +/// Creates a `mir::Body` with a few disconnected basic blocks. +/// +/// This is the `Body` that will be used by the `MockAnalysis` below. The shape of its CFG is not +/// important. +fn mock_body() -> mir::Body<'static> { + let source_info = mir::SourceInfo::outermost(DUMMY_SP); + + let mut blocks = IndexVec::new(); + let mut block = |n, kind| { + let nop = mir::Statement { source_info, kind: mir::StatementKind::Nop }; + + blocks.push(mir::BasicBlockData { + statements: std::iter::repeat(&nop).cloned().take(n).collect(), + terminator: Some(mir::Terminator { source_info, kind }), + is_cleanup: false, + }) + }; + + let dummy_place = mir::Place { local: mir::RETURN_PLACE, projection: ty::List::empty() }; + + block(4, mir::TerminatorKind::Return); + block(1, mir::TerminatorKind::Return); + block( + 2, + mir::TerminatorKind::Call { + func: mir::Operand::Copy(dummy_place.clone()), + args: vec![], + destination: Some((dummy_place.clone(), mir::START_BLOCK)), + cleanup: None, + from_hir_call: false, + fn_span: DUMMY_SP, + }, + ); + block(3, mir::TerminatorKind::Return); + block(0, mir::TerminatorKind::Return); + block( + 4, + mir::TerminatorKind::Call { + func: mir::Operand::Copy(dummy_place.clone()), + args: vec![], + destination: Some((dummy_place.clone(), mir::START_BLOCK)), + cleanup: None, + from_hir_call: false, + fn_span: DUMMY_SP, + }, + ); + + mir::Body::new_cfg_only(blocks) +} + +/// A dataflow analysis whose state is unique at every possible `SeekTarget`. +/// +/// Uniqueness is achieved by having a *locally* unique effect before and after each statement and +/// terminator (see `effect_at_target`) while ensuring that the entry set for each block is +/// *globally* unique (see `mock_entry_set`). +/// +/// For example, a `BasicBlock` with ID `2` and a `Call` terminator has the following state at each +/// location ("+x" indicates that "x" is added to the state). +/// +/// | Location | Before | After | +/// |------------------------|-------------------|--------| +/// | (on_entry) | {102} || +/// | statement 0 | +0 | +1 | +/// | statement 1 | +2 | +3 | +/// | `Call` terminator | +4 | +5 | +/// | (on unwind) | {102,0,1,2,3,4,5} || +/// +/// The `102` in the block's entry set is derived from the basic block index and ensures that the +/// expected state is unique across all basic blocks. Remember, it is generated by +/// `mock_entry_sets`, not from actually running `MockAnalysis` to fixpoint. +struct MockAnalysis<'tcx, D> { + body: &'tcx mir::Body<'tcx>, + dir: PhantomData, +} + +impl MockAnalysis<'tcx, D> { + const BASIC_BLOCK_OFFSET: usize = 100; + + /// The entry set for each `BasicBlock` is the ID of that block offset by a fixed amount to + /// avoid colliding with the statement/terminator effects. + fn mock_entry_set(&self, bb: BasicBlock) -> BitSet { + let mut ret = self.bottom_value(self.body); + ret.insert(Self::BASIC_BLOCK_OFFSET + bb.index()); + ret + } + + fn mock_entry_sets(&self) -> IndexVec> { + let empty = self.bottom_value(self.body); + let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks()); + + for (bb, _) in self.body.basic_blocks().iter_enumerated() { + ret[bb] = self.mock_entry_set(bb); + } + + ret + } + + /// Returns the index that should be added to the dataflow state at the given target. + fn effect(&self, loc: EffectIndex) -> usize { + let idx = match loc.effect { + Effect::Before => loc.statement_index * 2, + Effect::Primary => loc.statement_index * 2 + 1, + }; + + assert!(idx < Self::BASIC_BLOCK_OFFSET, "Too many statements in basic block"); + idx + } + + /// Returns the expected state at the given `SeekTarget`. + /// + /// This is the union of index of the target basic block, the index assigned to the + /// target statement or terminator, and the indices of all preceding statements in the target + /// basic block. + /// + /// For example, the expected state when calling + /// `seek_before_primary_effect(Location { block: 2, statement_index: 2 })` + /// would be `[102, 0, 1, 2, 3, 4]`. + fn expected_state_at_target(&self, target: SeekTarget) -> BitSet { + let block = target.block(); + let mut ret = self.bottom_value(self.body); + ret.insert(Self::BASIC_BLOCK_OFFSET + block.index()); + + let target = match target { + SeekTarget::BlockEntry { .. } => return ret, + SeekTarget::Before(loc) => Effect::Before.at_index(loc.statement_index), + SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index), + }; + + let mut pos = if D::is_forward() { + Effect::Before.at_index(0) + } else { + Effect::Before.at_index(self.body[block].statements.len()) + }; + + loop { + ret.insert(self.effect(pos)); + + if pos == target { + return ret; + } + + if D::is_forward() { + pos = pos.next_in_forward_order(); + } else { + pos = pos.next_in_backward_order(); + } + } + } +} + +impl AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { + type Domain = BitSet; + type Direction = D; + + const NAME: &'static str = "mock"; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + BitSet::new_empty(Self::BASIC_BLOCK_OFFSET + body.basic_blocks().len()) + } + + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { + unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint"); + } +} + +impl Analysis<'tcx> for MockAnalysis<'tcx, D> { + fn apply_statement_effect( + &self, + state: &mut Self::Domain, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + let idx = self.effect(Effect::Primary.at_index(location.statement_index)); + assert!(state.insert(idx)); + } + + fn apply_before_statement_effect( + &self, + state: &mut Self::Domain, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + let idx = self.effect(Effect::Before.at_index(location.statement_index)); + assert!(state.insert(idx)); + } + + fn apply_terminator_effect( + &self, + state: &mut Self::Domain, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + let idx = self.effect(Effect::Primary.at_index(location.statement_index)); + assert!(state.insert(idx)); + } + + fn apply_before_terminator_effect( + &self, + state: &mut Self::Domain, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + let idx = self.effect(Effect::Before.at_index(location.statement_index)); + assert!(state.insert(idx)); + } + + fn apply_call_return_effect( + &self, + _state: &mut Self::Domain, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + _return_place: mir::Place<'tcx>, + ) { + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum SeekTarget { + BlockEntry(BasicBlock), + Before(Location), + After(Location), +} + +impl SeekTarget { + fn block(&self) -> BasicBlock { + use SeekTarget::*; + + match *self { + BlockEntry(block) => block, + Before(loc) | After(loc) => loc.block, + } + } + + /// An iterator over all possible `SeekTarget`s in a given block in order, starting with + /// `BlockEntry`. + fn iter_in_block(body: &mir::Body<'_>, block: BasicBlock) -> impl Iterator { + let statements_and_terminator = (0..=body[block].statements.len()) + .flat_map(|i| (0..2).map(move |j| (i, j))) + .map(move |(i, kind)| { + let loc = Location { block, statement_index: i }; + match kind { + 0 => SeekTarget::Before(loc), + 1 => SeekTarget::After(loc), + _ => unreachable!(), + } + }); + + std::iter::once(SeekTarget::BlockEntry(block)).chain(statements_and_terminator) + } +} + +fn test_cursor(analysis: MockAnalysis<'tcx, D>) { + let body = analysis.body; + + let mut cursor = + Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body); + + let every_target = || { + body.basic_blocks() + .iter_enumerated() + .flat_map(|(bb, _)| SeekTarget::iter_in_block(body, bb)) + }; + + let mut seek_to_target = |targ| { + use SeekTarget::*; + + match targ { + BlockEntry(block) => cursor.seek_to_block_entry(block), + Before(loc) => cursor.seek_before_primary_effect(loc), + After(loc) => cursor.seek_after_primary_effect(loc), + } + + assert_eq!(cursor.get(), &cursor.analysis().expected_state_at_target(targ)); + }; + + // Seek *to* every possible `SeekTarget` *from* every possible `SeekTarget`. + // + // By resetting the cursor to `from` each time it changes, we end up checking some edges twice. + // What we really want is an Eulerian cycle for the complete digraph over all possible + // `SeekTarget`s, but it's not worth spending the time to compute it. + for from in every_target() { + seek_to_target(from); + + for to in every_target() { + dbg!(from); + dbg!(to); + seek_to_target(to); + seek_to_target(from); + } + } +} + +#[test] +fn backward_cursor() { + let body = mock_body(); + let body = &body; + let analysis = MockAnalysis { body, dir: PhantomData:: }; + test_cursor(analysis) +} + +#[test] +fn forward_cursor() { + let body = mock_body(); + let body = &body; + let analysis = MockAnalysis { body, dir: PhantomData:: }; + test_cursor(analysis) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/visitor.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/visitor.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/visitor.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/framework/visitor.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,187 @@ +use rustc_middle::mir::{self, BasicBlock, Location}; + +use super::{Analysis, Direction, Results}; + +/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the +/// dataflow state at that location. +pub fn visit_results( + body: &'mir mir::Body<'tcx>, + blocks: impl IntoIterator, + results: &V, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, +) where + V: ResultsVisitable<'tcx, FlowState = F>, +{ + let mut state = results.new_flow_state(body); + + #[cfg(debug_assertions)] + let reachable_blocks = mir::traversal::reachable_as_bitset(body); + + for block in blocks { + #[cfg(debug_assertions)] + assert!(reachable_blocks.contains(block)); + + let block_data = &body[block]; + V::Direction::visit_results_in_block(&mut state, block, block_data, results, vis); + } +} + +pub trait ResultsVisitor<'mir, 'tcx> { + type FlowState; + + fn visit_block_start( + &mut self, + _state: &Self::FlowState, + _block_data: &'mir mir::BasicBlockData<'tcx>, + _block: BasicBlock, + ) { + } + + /// Called with the `before_statement_effect` of the given statement applied to `state` but not + /// its `statement_effect`. + fn visit_statement_before_primary_effect( + &mut self, + _state: &Self::FlowState, + _statement: &'mir mir::Statement<'tcx>, + _location: Location, + ) { + } + + /// Called with both the `before_statement_effect` and the `statement_effect` of the given + /// statement applied to `state`. + fn visit_statement_after_primary_effect( + &mut self, + _state: &Self::FlowState, + _statement: &'mir mir::Statement<'tcx>, + _location: Location, + ) { + } + + /// Called with the `before_terminator_effect` of the given terminator applied to `state` but not + /// its `terminator_effect`. + fn visit_terminator_before_primary_effect( + &mut self, + _state: &Self::FlowState, + _terminator: &'mir mir::Terminator<'tcx>, + _location: Location, + ) { + } + + /// Called with both the `before_terminator_effect` and the `terminator_effect` of the given + /// terminator applied to `state`. + /// + /// The `call_return_effect` (if one exists) will *not* be applied to `state`. + fn visit_terminator_after_primary_effect( + &mut self, + _state: &Self::FlowState, + _terminator: &'mir mir::Terminator<'tcx>, + _location: Location, + ) { + } + + fn visit_block_end( + &mut self, + _state: &Self::FlowState, + _block_data: &'mir mir::BasicBlockData<'tcx>, + _block: BasicBlock, + ) { + } +} + +/// Things that can be visited by a `ResultsVisitor`. +/// +/// This trait exists so that we can visit the results of multiple dataflow analyses simultaneously. +/// DO NOT IMPLEMENT MANUALLY. Instead, use the `impl_visitable` macro below. +pub trait ResultsVisitable<'tcx> { + type Direction: Direction; + type FlowState; + + /// Creates an empty `FlowState` to hold the transient state for these dataflow results. + /// + /// The value of the newly created `FlowState` will be overwritten by `reset_to_block_entry` + /// before it can be observed by a `ResultsVisitor`. + fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState; + + fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock); + + fn reconstruct_before_statement_effect( + &self, + state: &mut Self::FlowState, + statement: &mir::Statement<'tcx>, + location: Location, + ); + + fn reconstruct_statement_effect( + &self, + state: &mut Self::FlowState, + statement: &mir::Statement<'tcx>, + location: Location, + ); + + fn reconstruct_before_terminator_effect( + &self, + state: &mut Self::FlowState, + terminator: &mir::Terminator<'tcx>, + location: Location, + ); + + fn reconstruct_terminator_effect( + &self, + state: &mut Self::FlowState, + terminator: &mir::Terminator<'tcx>, + location: Location, + ); +} + +impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> +where + A: Analysis<'tcx>, +{ + type FlowState = A::Domain; + + type Direction = A::Direction; + + fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { + self.analysis.bottom_value(body) + } + + fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { + state.clone_from(&self.entry_set_for_block(block)); + } + + fn reconstruct_before_statement_effect( + &self, + state: &mut Self::FlowState, + stmt: &mir::Statement<'tcx>, + loc: Location, + ) { + self.analysis.apply_before_statement_effect(state, stmt, loc); + } + + fn reconstruct_statement_effect( + &self, + state: &mut Self::FlowState, + stmt: &mir::Statement<'tcx>, + loc: Location, + ) { + self.analysis.apply_statement_effect(state, stmt, loc); + } + + fn reconstruct_before_terminator_effect( + &self, + state: &mut Self::FlowState, + term: &mir::Terminator<'tcx>, + loc: Location, + ) { + self.analysis.apply_before_terminator_effect(state, term, loc); + } + + fn reconstruct_terminator_effect( + &self, + state: &mut Self::FlowState, + term: &mir::Terminator<'tcx>, + loc: Location, + ) { + self.analysis.apply_terminator_effect(state, term, loc); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,274 @@ +use super::*; + +use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::{ParamEnv, TyCtxt}; +use rustc_span::DUMMY_SP; + +pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals>; + +/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points +/// to a given local. +/// +/// The `K` parameter determines what kind of borrows are tracked. By default, +/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows +/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead. +/// +/// At present, this is used as a very limited form of alias analysis. For example, +/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for +/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a +/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a +/// function call or inline assembly. +pub struct MaybeBorrowedLocals { + kind: K, + ignore_borrow_on_drop: bool, +} + +impl MaybeBorrowedLocals { + /// A dataflow analysis that records whether a pointer or reference exists that may alias the + /// given local. + pub fn all_borrows() -> Self { + MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false } + } +} + +impl MaybeMutBorrowedLocals<'mir, 'tcx> { + /// A dataflow analysis that records whether a pointer or reference exists that may *mutably* + /// alias the given local. + /// + /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of + /// types with interior mutability. + pub fn mut_borrows_only( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Self { + MaybeBorrowedLocals { + kind: MutBorrow { body, tcx, param_env }, + ignore_borrow_on_drop: false, + } + } +} + +impl MaybeBorrowedLocals { + /// During dataflow analysis, ignore the borrow that may occur when a place is dropped. + /// + /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a + /// parameter. In the general case, a drop impl could launder that reference into the + /// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the + /// dropped local. We are not yet willing to declare this particular case UB, so we must treat + /// all dropped locals as mutably borrowed for now. See discussion on [#61069]. + /// + /// In some contexts, we know that this borrow will never occur. For example, during + /// const-eval, custom drop glue cannot be run. Code that calls this should document the + /// assumptions that justify ignoring `Drop` terminators in this way. + /// + /// [#61069]: https://github.com/rust-lang/rust/pull/61069 + pub fn unsound_ignore_borrow_on_drop(self) -> Self { + MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self } + } + + fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> { + TransferFunction { + kind: &self.kind, + trans, + ignore_borrow_on_drop: self.ignore_borrow_on_drop, + } + } +} + +impl AnalysisDomain<'tcx> for MaybeBorrowedLocals +where + K: BorrowAnalysisKind<'tcx>, +{ + type Domain = BitSet; + const NAME: &'static str = K::ANALYSIS_NAME; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = unborrowed + BitSet::new_empty(body.local_decls().len()) + } + + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { + // No locals are aliased on function entry + } +} + +impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals +where + K: BorrowAnalysisKind<'tcx>, +{ + type Idx = Local; + + fn statement_effect( + &self, + trans: &mut impl GenKill, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.transfer_function(trans).visit_statement(statement, location); + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + self.transfer_function(trans).visit_terminator(terminator, location); + } + + fn call_return_effect( + &self, + _trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + _dest_place: mir::Place<'tcx>, + ) { + } +} + +/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. +struct TransferFunction<'a, T, K> { + trans: &'a mut T, + kind: &'a K, + ignore_borrow_on_drop: bool, +} + +impl Visitor<'tcx> for TransferFunction<'a, T, K> +where + T: GenKill, + K: BorrowAnalysisKind<'tcx>, +{ + fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) { + self.super_statement(stmt, location); + + // When we reach a `StorageDead` statement, we can assume that any pointers to this memory + // are now invalid. + if let StatementKind::StorageDead(local) = stmt.kind { + self.trans.kill(local); + } + } + + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + + match rvalue { + mir::Rvalue::AddressOf(mt, borrowed_place) => { + if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) { + self.trans.gen(borrowed_place.local); + } + } + + mir::Rvalue::Ref(_, kind, borrowed_place) => { + if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) { + self.trans.gen(borrowed_place.local); + } + } + + mir::Rvalue::Cast(..) + | mir::Rvalue::ShallowInitBox(..) + | mir::Rvalue::Use(..) + | mir::Rvalue::ThreadLocalRef(..) + | mir::Rvalue::Repeat(..) + | mir::Rvalue::Len(..) + | mir::Rvalue::BinaryOp(..) + | mir::Rvalue::CheckedBinaryOp(..) + | mir::Rvalue::NullaryOp(..) + | mir::Rvalue::UnaryOp(..) + | mir::Rvalue::Discriminant(..) + | mir::Rvalue::Aggregate(..) => {} + } + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + + match terminator.kind { + mir::TerminatorKind::Drop { place: dropped_place, .. } + | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => { + // See documentation for `unsound_ignore_borrow_on_drop` for an explanation. + if !self.ignore_borrow_on_drop { + self.trans.gen(dropped_place.local); + } + } + + TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable + | TerminatorKind::Yield { .. } => {} + } + } +} + +pub struct AnyBorrow; + +pub struct MutBorrow<'mir, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'mir Body<'tcx>, + param_env: ParamEnv<'tcx>, +} + +impl MutBorrow<'mir, 'tcx> { + /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`. + /// + /// This assumes that it is UB to take the address of a struct field whose type is + /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of + /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will + /// have to check the type of the borrowed **local** instead of the borrowed **place** + /// below. See [rust-lang/unsafe-code-guidelines#134]. + /// + /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 + fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool { + !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) + } +} + +pub trait BorrowAnalysisKind<'tcx> { + const ANALYSIS_NAME: &'static str; + + fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool; + fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool; +} + +impl BorrowAnalysisKind<'tcx> for AnyBorrow { + const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals"; + + fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool { + true + } + fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool { + true + } +} + +impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> { + const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals"; + + fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool { + match kind { + mir::BorrowKind::Mut { .. } => true, + mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => { + self.shared_borrow_allows_mutation(place) + } + } + } + + fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool { + match mt { + Mutability::Mut => true, + Mutability::Not => self.shared_borrow_allows_mutation(place), + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/init_locals.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/init_locals.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/init_locals.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/init_locals.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,113 @@ +//! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals. +//! +//! A local will be maybe initialized if *any* projections of that local might be initialized. + +use crate::GenKill; + +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{self, BasicBlock, Local, Location}; + +pub struct MaybeInitializedLocals; + +impl crate::AnalysisDomain<'tcx> for MaybeInitializedLocals { + type Domain = BitSet; + + const NAME: &'static str = "maybe_init_locals"; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = uninit + BitSet::new_empty(body.local_decls.len()) + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut Self::Domain) { + // Function arguments are initialized to begin with. + for arg in body.args_iter() { + entry_set.insert(arg); + } + } +} + +impl crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals { + type Idx = Local; + + fn statement_effect( + &self, + trans: &mut impl GenKill, + statement: &mir::Statement<'tcx>, + loc: Location, + ) { + TransferFunction { trans }.visit_statement(statement, loc) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + TransferFunction { trans }.visit_terminator(terminator, loc) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ) { + trans.gen(return_place.local) + } + + /// See `Analysis::apply_yield_resume_effect`. + fn yield_resume_effect( + &self, + trans: &mut impl GenKill, + _resume_block: BasicBlock, + resume_place: mir::Place<'tcx>, + ) { + trans.gen(resume_place.local) + } +} + +struct TransferFunction<'a, T> { + trans: &'a mut T, +} + +impl Visitor<'tcx> for TransferFunction<'a, T> +where + T: GenKill, +{ + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext}; + match context { + // These are handled specially in `call_return_effect` and `yield_resume_effect`. + PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {} + + // Otherwise, when a place is mutated, we must consider it possibly initialized. + PlaceContext::MutatingUse(_) => self.trans.gen(local), + + // If the local is moved out of, or if it gets marked `StorageDead`, consider it no + // longer initialized. + PlaceContext::NonUse(NonUseContext::StorageDead) + | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => self.trans.kill(local), + + // All other uses do not affect this analysis. + PlaceContext::NonUse( + NonUseContext::StorageLive + | NonUseContext::AscribeUserTy + | NonUseContext::VarDebugInfo, + ) + | PlaceContext::NonMutatingUse( + NonMutatingUseContext::Inspect + | NonMutatingUseContext::Copy + | NonMutatingUseContext::SharedBorrow + | NonMutatingUseContext::ShallowBorrow + | NonMutatingUseContext::UniqueBorrow + | NonMutatingUseContext::AddressOf + | NonMutatingUseContext::Projection, + ) => {} + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/liveness.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/liveness.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/liveness.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/liveness.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,196 @@ +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::{self, Local, Location}; + +use crate::{AnalysisDomain, Backward, GenKill, GenKillAnalysis}; + +/// A [live-variable dataflow analysis][liveness]. +/// +/// This analysis considers references as being used only at the point of the +/// borrow. In other words, this analysis does not track uses because of references that already +/// exist. See [this `mir-dataflow` test][flow-test] for an example. You almost never want to use +/// this analysis without also looking at the results of [`MaybeBorrowedLocals`]. +/// +/// ## Field-(in)sensitivity +/// +/// As the name suggests, this analysis is field insensitive. If a projection of a variable `x` is +/// assigned to (e.g. `x.0 = 42`), it does not "define" `x` as far as liveness is concerned. In fact, +/// such an assignment is currently marked as a "use" of `x` in an attempt to be maximally +/// conservative. +/// +/// ## Enums and `SetDiscriminant` +/// +/// Assigning a literal value to an `enum` (e.g. `Option`), does not result in a simple +/// assignment of the form `_1 = /*...*/` in the MIR. For example, the following assignment to `x`: +/// +/// ``` +/// x = Some(4); +/// ``` +/// +/// compiles to this MIR +/// +/// ``` +/// ((_1 as Some).0: i32) = const 4_i32; +/// discriminant(_1) = 1; +/// ``` +/// +/// However, `MaybeLiveLocals` **does** mark `x` (`_1`) as "killed" after a statement like this. +/// That's because it treats the `SetDiscriminant` operation as a definition of `x`, even though +/// the writes that actually initialized the locals happened earlier. +/// +/// This makes `MaybeLiveLocals` unsuitable for certain classes of optimization normally associated +/// with a live variables analysis, notably dead-store elimination. It's a dirty hack, but it works +/// okay for the generator state transform (currently the main consumuer of this analysis). +/// +/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals +/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs +/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis +pub struct MaybeLiveLocals; + +impl MaybeLiveLocals { + fn transfer_function(&self, trans: &'a mut T) -> TransferFunction<'a, T> { + TransferFunction(trans) + } +} + +impl AnalysisDomain<'tcx> for MaybeLiveLocals { + type Domain = BitSet; + type Direction = Backward; + + const NAME: &'static str = "liveness"; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = not live + BitSet::new_empty(body.local_decls.len()) + } + + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { + // No variables are live until we observe a use + } +} + +impl GenKillAnalysis<'tcx> for MaybeLiveLocals { + type Idx = Local; + + fn statement_effect( + &self, + trans: &mut impl GenKill, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.transfer_function(trans).visit_statement(statement, location); + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + self.transfer_function(trans).visit_terminator(terminator, location); + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + dest_place: mir::Place<'tcx>, + ) { + if let Some(local) = dest_place.as_local() { + trans.kill(local); + } + } + + fn yield_resume_effect( + &self, + trans: &mut impl GenKill, + _resume_block: mir::BasicBlock, + resume_place: mir::Place<'tcx>, + ) { + if let Some(local) = resume_place.as_local() { + trans.kill(local); + } + } +} + +struct TransferFunction<'a, T>(&'a mut T); + +impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T> +where + T: GenKill, +{ + fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { + let mir::Place { projection, local } = *place; + + // We purposefully do not call `super_place` here to avoid calling `visit_local` for this + // place with one of the `Projection` variants of `PlaceContext`. + self.visit_projection(place.as_ref(), context, location); + + match DefUse::for_place(context) { + // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use. + Some(_) if place.is_indirect() => self.0.gen(local), + + Some(DefUse::Def) if projection.is_empty() => self.0.kill(local), + Some(DefUse::Use) => self.0.gen(local), + _ => {} + } + } + + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + // Because we do not call `super_place` above, `visit_local` is only called for locals that + // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use + // of the return place in a `Return` terminator or the index in an `Index` projection. + match DefUse::for_place(context) { + Some(DefUse::Def) => self.0.kill(local), + Some(DefUse::Use) => self.0.gen(local), + _ => {} + } + } +} + +#[derive(Eq, PartialEq, Clone)] +enum DefUse { + Def, + Use, +} + +impl DefUse { + fn for_place(context: PlaceContext) -> Option { + match context { + PlaceContext::NonUse(_) => None, + + PlaceContext::MutatingUse(MutatingUseContext::Store) => Some(DefUse::Def), + + // `MutatingUseContext::Call` and `MutatingUseContext::Yield` indicate that this is the + // destination place for a `Call` return or `Yield` resume respectively. Since this is + // only a `Def` when the function returns successfully, we handle this case separately + // in `call_return_effect` above. + PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => None, + + // All other contexts are uses... + PlaceContext::MutatingUse( + MutatingUseContext::AddressOf + | MutatingUseContext::AsmOutput + | MutatingUseContext::Borrow + | MutatingUseContext::Drop + | MutatingUseContext::Retag, + ) + | PlaceContext::NonMutatingUse( + NonMutatingUseContext::AddressOf + | NonMutatingUseContext::Copy + | NonMutatingUseContext::Inspect + | NonMutatingUseContext::Move + | NonMutatingUseContext::ShallowBorrow + | NonMutatingUseContext::SharedBorrow + | NonMutatingUseContext::UniqueBorrow, + ) => Some(DefUse::Use), + + PlaceContext::MutatingUse(MutatingUseContext::Projection) + | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => { + unreachable!("A projection could be a def or a use and must be handled separately") + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,706 @@ +//! Dataflow analyses are built upon some interpretation of the +//! bitvectors attached to each basic block, represented via a +//! zero-sized structure. + +use rustc_index::bit_set::BitSet; +use rustc_index::vec::Idx; +use rustc_middle::mir::{self, Body, Location}; +use rustc_middle::ty::{self, TyCtxt}; + +use crate::drop_flag_effects; +use crate::drop_flag_effects_for_function_entry; +use crate::drop_flag_effects_for_location; +use crate::elaborate_drops::DropFlagState; +use crate::framework::SwitchIntEdgeEffects; +use crate::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex}; +use crate::on_lookup_result_bits; +use crate::MoveDataParamEnv; +use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis}; + +mod borrowed_locals; +mod init_locals; +mod liveness; +mod storage_liveness; + +pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; +pub use self::init_locals::MaybeInitializedLocals; +pub use self::liveness::MaybeLiveLocals; +pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; + +/// `MaybeInitializedPlaces` tracks all places that might be +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-init: +/// // {} +/// let a = S; let b = S; let c; let d; // {a, b} +/// +/// if pred { +/// drop(a); // { b} +/// b = S; // { b} +/// +/// } else { +/// drop(b); // {a} +/// d = S; // {a, d} +/// +/// } // {a, b, d} +/// +/// c = S; // {a, b, c, d} +/// } +/// ``` +/// +/// To determine whether a place *must* be initialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeUninitializedPlaces` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeUninitializedPlaces` yields the set of +/// places that would require a dynamic drop-flag at that statement. +pub struct MaybeInitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, +} + +impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + MaybeInitializedPlaces { tcx, body, mdpe } + } +} + +impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { + &self.mdpe.move_data + } +} + +/// `MaybeUninitializedPlaces` tracks all places that might be +/// uninitialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-uninit: +/// // {a, b, c, d} +/// let a = S; let b = S; let c; let d; // { c, d} +/// +/// if pred { +/// drop(a); // {a, c, d} +/// b = S; // {a, c, d} +/// +/// } else { +/// drop(b); // { b, c, d} +/// d = S; // { b, c } +/// +/// } // {a, b, c, d} +/// +/// c = S; // {a, b, d} +/// } +/// ``` +/// +/// To determine whether a place *must* be uninitialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeInitializedPlaces` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeInitializedPlaces` yields the set of +/// places that would require a dynamic drop-flag at that statement. +pub struct MaybeUninitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, + + mark_inactive_variants_as_uninit: bool, +} + +impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit: false } + } + + /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an + /// enum discriminant. + /// + /// This is correct in a vacuum but is not the default because it causes problems in the borrow + /// checker, where this information gets propagated along `FakeEdge`s. + pub fn mark_inactive_variants_as_uninit(mut self) -> Self { + self.mark_inactive_variants_as_uninit = true; + self + } +} + +impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { + &self.mdpe.move_data + } +} + +/// `DefinitelyInitializedPlaces` tracks all places that are definitely +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // definite-init: +/// // { } +/// let a = S; let b = S; let c; let d; // {a, b } +/// +/// if pred { +/// drop(a); // { b, } +/// b = S; // { b, } +/// +/// } else { +/// drop(b); // {a, } +/// d = S; // {a, d} +/// +/// } // { } +/// +/// c = S; // { c } +/// } +/// ``` +/// +/// To determine whether a place *may* be uninitialized at a +/// particular control-flow point, one can take the set-complement +/// of this data. +/// +/// Similarly, at a given `drop` statement, the set-difference between +/// this data and `MaybeInitializedPlaces` yields the set of places +/// that would require a dynamic drop-flag at that statement. +pub struct DefinitelyInitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, +} + +impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + DefinitelyInitializedPlaces { tcx, body, mdpe } + } +} + +impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { + &self.mdpe.move_data + } +} + +/// `EverInitializedPlaces` tracks all places that might have ever been +/// initialized upon reaching a particular point in the control flow +/// for a function, without an intervening `StorageDead`. +/// +/// This dataflow is used to determine if an immutable local variable may +/// be assigned to. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // ever-init: +/// // { } +/// let a = S; let b = S; let c; let d; // {a, b } +/// +/// if pred { +/// drop(a); // {a, b, } +/// b = S; // {a, b, } +/// +/// } else { +/// drop(b); // {a, b, } +/// d = S; // {a, b, d } +/// +/// } // {a, b, d } +/// +/// c = S; // {a, b, c, d } +/// } +/// ``` +pub struct EverInitializedPlaces<'a, 'tcx> { + #[allow(dead_code)] + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, +} + +impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + EverInitializedPlaces { tcx, body, mdpe } + } +} + +impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { + &self.mdpe.move_data + } +} + +impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { + fn update_bits( + trans: &mut impl GenKill, + path: MovePathIndex, + state: DropFlagState, + ) { + match state { + DropFlagState::Absent => trans.kill(path), + DropFlagState::Present => trans.gen(path), + } + } +} + +impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { + fn update_bits( + trans: &mut impl GenKill, + path: MovePathIndex, + state: DropFlagState, + ) { + match state { + DropFlagState::Absent => trans.gen(path), + DropFlagState::Present => trans.kill(path), + } + } +} + +impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { + fn update_bits( + trans: &mut impl GenKill, + path: MovePathIndex, + state: DropFlagState, + ) { + match state { + DropFlagState::Absent => trans.kill(path), + DropFlagState::Present => trans.gen(path), + } + } +} + +impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + type Domain = BitSet; + const NAME: &'static str = "maybe_init"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = uninitialized + BitSet::new_empty(self.move_data().move_paths.len()) + } + + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { + drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { + assert!(s == DropFlagState::Present); + state.insert(path); + }); + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + + fn statement_effect( + &self, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + dest_place: mir::Place<'tcx>, + ) { + // when a call returns successfully, that means we need to set + // the bits for that dest_place to 1 (initialized). + on_lookup_result_bits( + self.tcx, + self.body, + self.move_data(), + self.move_data().rev_lookup.find(dest_place.as_ref()), + |mpi| { + trans.gen(mpi); + }, + ); + } + + fn switch_int_edge_effects>( + &self, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, + ) { + if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { + return; + } + + let enum_ = discr.place().and_then(|discr| { + switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) + }); + + let (enum_place, enum_def) = match enum_ { + Some(x) => x, + None => return, + }; + + let mut discriminants = enum_def.discriminants(self.tcx); + edge_effects.apply(|trans, edge| { + let value = match edge.value { + Some(x) => x, + None => return, + }; + + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let (variant, _) = discriminants + .find(|&(_, discr)| discr.val == value) + .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); + + // Kill all move paths that correspond to variants we know to be inactive along this + // particular outgoing edge of a `SwitchInt`. + drop_flag_effects::on_all_inactive_variants( + self.tcx, + self.body, + self.move_data(), + enum_place, + variant, + |mpi| trans.kill(mpi), + ); + }); + } +} + +impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + type Domain = BitSet; + + const NAME: &'static str = "maybe_uninit"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = initialized (start_block_effect counters this at outset) + BitSet::new_empty(self.move_data().move_paths.len()) + } + + // sets on_entry bits for Arg places + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { + // set all bits to 1 (uninit) before gathering counterevidence + state.insert_all(); + + drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { + assert!(s == DropFlagState::Present); + state.remove(path); + }); + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + + fn statement_effect( + &self, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + dest_place: mir::Place<'tcx>, + ) { + // when a call returns successfully, that means we need to set + // the bits for that dest_place to 0 (initialized). + on_lookup_result_bits( + self.tcx, + self.body, + self.move_data(), + self.move_data().rev_lookup.find(dest_place.as_ref()), + |mpi| { + trans.kill(mpi); + }, + ); + } + + fn switch_int_edge_effects>( + &self, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, + ) { + if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { + return; + } + + if !self.mark_inactive_variants_as_uninit { + return; + } + + let enum_ = discr.place().and_then(|discr| { + switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) + }); + + let (enum_place, enum_def) = match enum_ { + Some(x) => x, + None => return, + }; + + let mut discriminants = enum_def.discriminants(self.tcx); + edge_effects.apply(|trans, edge| { + let value = match edge.value { + Some(x) => x, + None => return, + }; + + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let (variant, _) = discriminants + .find(|&(_, discr)| discr.val == value) + .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); + + // Mark all move paths that correspond to variants other than this one as maybe + // uninitialized (in reality, they are *definitely* uninitialized). + drop_flag_effects::on_all_inactive_variants( + self.tcx, + self.body, + self.move_data(), + enum_place, + variant, + |mpi| trans.gen(mpi), + ); + }); + } +} + +impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { + /// Use set intersection as the join operator. + type Domain = lattice::Dual>; + + const NAME: &'static str = "definite_init"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = initialized (start_block_effect counters this at outset) + lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len())) + } + + // sets on_entry bits for Arg places + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { + state.0.clear(); + + drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { + assert!(s == DropFlagState::Present); + state.0.insert(path); + }); + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + + fn statement_effect( + &self, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + dest_place: mir::Place<'tcx>, + ) { + // when a call returns successfully, that means we need to set + // the bits for that dest_place to 1 (initialized). + on_lookup_result_bits( + self.tcx, + self.body, + self.move_data(), + self.move_data().rev_lookup.find(dest_place.as_ref()), + |mpi| { + trans.gen(mpi); + }, + ); + } +} + +impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { + type Domain = BitSet; + + const NAME: &'static str = "ever_init"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = no initialized variables by default + BitSet::new_empty(self.move_data().inits.len()) + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { + for arg_init in 0..body.arg_count { + state.insert(InitIndex::new(arg_init)); + } + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { + type Idx = InitIndex; + + #[instrument(skip(self, trans), level = "debug")] + fn statement_effect( + &self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + location: Location, + ) { + let move_data = self.move_data(); + let init_path_map = &move_data.init_path_map; + let init_loc_map = &move_data.init_loc_map; + let rev_lookup = &move_data.rev_lookup; + + debug!("initializes move_indexes {:?}", &init_loc_map[location]); + trans.gen_all(init_loc_map[location].iter().copied()); + + if let mir::StatementKind::StorageDead(local) = stmt.kind { + // End inits for StorageDead, so that an immutable variable can + // be reinitialized on the next iteration of the loop. + let move_path_index = rev_lookup.find_local(local); + debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]); + trans.kill_all(init_path_map[move_path_index].iter().copied()); + } + } + + #[instrument(skip(self, trans, _terminator), level = "debug")] + fn terminator_effect( + &self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + let (body, move_data) = (self.body, self.move_data()); + let term = body[location.block].terminator(); + let init_loc_map = &move_data.init_loc_map; + debug!(?term); + debug!("initializes move_indexes {:?}", init_loc_map[location]); + trans.gen_all( + init_loc_map[location] + .iter() + .filter(|init_index| { + move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly + }) + .copied(), + ); + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + _dest_place: mir::Place<'tcx>, + ) { + let move_data = self.move_data(); + let init_loc_map = &move_data.init_loc_map; + + let call_loc = self.body.terminator_loc(block); + for init_index in &init_loc_map[call_loc] { + trans.gen(*init_index); + } + } +} + +/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is +/// an enum discriminant. +/// +/// We expect such blocks to have a call to `discriminant` as their last statement like so: +/// +/// ```text +/// ... +/// _42 = discriminant(_1) +/// SwitchInt(_42, ..) +/// ``` +/// +/// If the basic block matches this pattern, this function returns the place corresponding to the +/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. +fn switch_on_enum_discriminant( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + block: &'mir mir::BasicBlockData<'tcx>, + switch_on: mir::Place<'tcx>, +) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> { + match block.statements.last().map(|stmt| &stmt.kind) { + Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))) + if *lhs == switch_on => + { + match &discriminated.ty(body, tcx).ty.kind() { + ty::Adt(def, _) => Some((*discriminated, def)), + + // `Rvalue::Discriminant` is also used to get the active yield point for a + // generator, but we do not need edge-specific effects in that case. This may + // change in the future. + ty::Generator(..) => None, + + t => bug!("`discriminant` called on unexpected type {:?}", t), + } + } + + _ => None, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,307 @@ +pub use super::*; + +use crate::storage::AlwaysLiveLocals; +use crate::{GenKill, Results, ResultsRefCursor}; +use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use std::cell::RefCell; + +#[derive(Clone)] +pub struct MaybeStorageLive { + always_live_locals: AlwaysLiveLocals, +} + +impl MaybeStorageLive { + pub fn new(always_live_locals: AlwaysLiveLocals) -> Self { + MaybeStorageLive { always_live_locals } + } +} + +impl crate::AnalysisDomain<'tcx> for MaybeStorageLive { + type Domain = BitSet; + + const NAME: &'static str = "maybe_storage_live"; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = dead + BitSet::new_empty(body.local_decls.len()) + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { + assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size()); + for local in self.always_live_locals.iter() { + on_entry.insert(local); + } + + for arg in body.args_iter() { + on_entry.insert(arg); + } + } +} + +impl crate::GenKillAnalysis<'tcx> for MaybeStorageLive { + type Idx = Local; + + fn statement_effect( + &self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + _: Location, + ) { + match stmt.kind { + StatementKind::StorageLive(l) => trans.gen(l), + StatementKind::StorageDead(l) => trans.kill(l), + _ => (), + } + } + + fn terminator_effect( + &self, + _trans: &mut impl GenKill, + _: &mir::Terminator<'tcx>, + _: Location, + ) { + // Terminators have no effect + } + + fn call_return_effect( + &self, + _trans: &mut impl GenKill, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + _return_place: mir::Place<'tcx>, + ) { + // Nothing to do when a call returns successfully + } +} + +type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; + +/// Dataflow analysis that determines whether each local requires storage at a +/// given location; i.e. whether its storage can go away without being observed. +pub struct MaybeRequiresStorage<'mir, 'tcx> { + body: &'mir Body<'tcx>, + borrowed_locals: RefCell>, +} + +impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { + pub fn new( + body: &'mir Body<'tcx>, + borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>, + ) -> Self { + MaybeRequiresStorage { + body, + borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)), + } + } +} + +impl<'mir, 'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { + type Domain = BitSet; + + const NAME: &'static str = "requires_storage"; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = dead + BitSet::new_empty(body.local_decls.len()) + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { + // The resume argument is live on function entry (we don't care about + // the `self` argument) + for arg in body.args_iter().skip(1) { + on_entry.insert(arg); + } + } +} + +impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { + type Idx = Local; + + fn before_statement_effect( + &self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + loc: Location, + ) { + // If a place is borrowed in a statement, it needs storage for that statement. + self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc); + + match &stmt.kind { + StatementKind::StorageDead(l) => trans.kill(*l), + + // If a place is assigned to in a statement, it needs storage for that statement. + StatementKind::Assign(box (place, _)) + | StatementKind::SetDiscriminant { box place, .. } => { + trans.gen(place.local); + } + StatementKind::LlvmInlineAsm(asm) => { + for place in &*asm.outputs { + trans.gen(place.local); + } + } + + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::FakeRead(..) + | StatementKind::Nop + | StatementKind::Retag(..) + | StatementKind::CopyNonOverlapping(..) + | StatementKind::StorageLive(..) => {} + } + } + + fn statement_effect( + &self, + trans: &mut impl GenKill, + _: &mir::Statement<'tcx>, + loc: Location, + ) { + // If we move from a place then only stops needing storage *after* + // that statement. + self.check_for_move(trans, loc); + } + + fn before_terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + // If a place is borrowed in a terminator, it needs storage for that terminator. + self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc); + + match &terminator.kind { + TerminatorKind::Call { destination: Some((place, _)), .. } => { + trans.gen(place.local); + } + + // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for + // that is that a `yield` will return from the function, and `resume_arg` is written + // only when the generator is later resumed. Unlike `Call`, this doesn't require the + // place to have storage *before* the yield, only after. + TerminatorKind::Yield { .. } => {} + + TerminatorKind::InlineAsm { operands, .. } => { + for op in operands { + match op { + InlineAsmOperand::Out { place, .. } + | InlineAsmOperand::InOut { out_place: place, .. } => { + if let Some(place) = place { + trans.gen(place.local); + } + } + InlineAsmOperand::In { .. } + | InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::SymStatic { .. } => {} + } + } + } + + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + TerminatorKind::Call { destination: None, .. } + | TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable => {} + } + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + match &terminator.kind { + // For call terminators the destination requires storage for the call + // and after the call returns successfully, but not after a panic. + // Since `propagate_call_unwind` doesn't exist, we have to kill the + // destination here, and then gen it again in `call_return_effect`. + TerminatorKind::Call { destination: Some((place, _)), .. } => { + trans.kill(place.local); + } + + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + TerminatorKind::Call { destination: None, .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable => {} + } + + self.check_for_move(trans, loc); + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ) { + trans.gen(return_place.local); + } + + fn yield_resume_effect( + &self, + trans: &mut impl GenKill, + _resume_block: BasicBlock, + resume_place: mir::Place<'tcx>, + ) { + trans.gen(resume_place.local); + } +} + +impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { + /// Kill locals that are fully moved and have not been borrowed. + fn check_for_move(&self, trans: &mut impl GenKill, loc: Location) { + let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals }; + visitor.visit_location(&self.body, loc); + } +} + +struct MoveVisitor<'a, 'mir, 'tcx, T> { + borrowed_locals: &'a RefCell>, + trans: &'a mut T, +} + +impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> +where + T: GenKill, +{ + fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { + if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { + let mut borrowed_locals = self.borrowed_locals.borrow_mut(); + borrowed_locals.seek_before_primary_effect(loc); + if !borrowed_locals.contains(*local) { + self.trans.kill(*local); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,72 @@ +#![feature(associated_type_defaults)] +#![feature(bool_to_option)] +#![feature(box_patterns)] +#![feature(box_syntax)] +#![cfg_attr(bootstrap, feature(const_panic))] +#![feature(exact_size_is_empty)] +#![feature(in_band_lifetimes)] +#![feature(iter_zip)] +#![feature(min_specialization)] +#![feature(once_cell)] +#![feature(stmt_expr_attributes)] +#![feature(trusted_step)] +#![recursion_limit = "256"] + +#[macro_use] +extern crate tracing; +#[macro_use] +extern crate rustc_middle; + +use rustc_ast::{self as ast, MetaItem}; +use rustc_middle::ty; +use rustc_session::Session; +use rustc_span::symbol::{sym, Symbol}; + +pub use self::drop_flag_effects::{ + drop_flag_effects_for_function_entry, drop_flag_effects_for_location, + move_path_children_matching, on_all_children_bits, on_all_drop_children_bits, + on_lookup_result_bits, +}; +pub use self::framework::{ + fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine, + Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor, ResultsRefCursor, + ResultsVisitable, ResultsVisitor, +}; + +use self::move_paths::MoveData; + +pub mod drop_flag_effects; +pub mod elaborate_drops; +mod framework; +pub mod impls; +pub mod move_paths; +pub mod rustc_peek; +pub mod storage; + +pub(crate) mod indexes { + pub(crate) use super::move_paths::MovePathIndex; +} + +pub struct MoveDataParamEnv<'tcx> { + pub move_data: MoveData<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, +} + +pub fn has_rustc_mir_with( + _sess: &Session, + attrs: &[ast::Attribute], + name: Symbol, +) -> Option { + for attr in attrs { + if attr.has_name(sym::rustc_mir) { + let items = attr.meta_item_list(); + for item in items.iter().flat_map(|l| l.iter()) { + match item.meta_item() { + Some(mi) if mi.has_name(name) => return Some(mi.clone()), + _ => continue, + } + } + } + } + None +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,61 @@ +//! The move-analysis portion of borrowck needs to work in an abstract +//! domain of lifted `Place`s. Most of the `Place` variants fall into a +//! one-to-one mapping between the concrete and abstract (e.g., a +//! field-deref on a local variable, `x.field`, has the same meaning +//! in both domains). Indexed projections are the exception: `a[x]` +//! needs to be treated as mapping to the same move path as `a[y]` as +//! well as `a[13]`, etc. +//! +//! (In theory, the analysis could be extended to work with sets of +//! paths, so that `a[0]` and `a[13]` could be kept distinct, while +//! `a[x]` would still overlap them both. But that is not this +//! representation does today.) + +use rustc_middle::mir::{Local, Operand, PlaceElem, ProjectionElem}; +use rustc_middle::ty::Ty; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct AbstractOperand; +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct AbstractType; +pub type AbstractElem = ProjectionElem; + +pub trait Lift { + type Abstract; + fn lift(&self) -> Self::Abstract; +} +impl<'tcx> Lift for Operand<'tcx> { + type Abstract = AbstractOperand; + fn lift(&self) -> Self::Abstract { + AbstractOperand + } +} +impl Lift for Local { + type Abstract = AbstractOperand; + fn lift(&self) -> Self::Abstract { + AbstractOperand + } +} +impl<'tcx> Lift for Ty<'tcx> { + type Abstract = AbstractType; + fn lift(&self) -> Self::Abstract { + AbstractType + } +} +impl<'tcx> Lift for PlaceElem<'tcx> { + type Abstract = AbstractElem; + fn lift(&self) -> Self::Abstract { + match *self { + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()), + ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), + ProjectionElem::Subslice { from, to, from_end } => { + ProjectionElem::Subslice { from, to, from_end } + } + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + ProjectionElem::ConstantIndex { offset, min_length, from_end } + } + ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u), + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/builder.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/builder.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/builder.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/builder.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,544 @@ +use rustc_index::vec::IndexVec; +use rustc_middle::mir::tcx::RvalueInitializationState; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; +use smallvec::{smallvec, SmallVec}; + +use std::iter; +use std::mem; + +use super::abs_domain::Lift; +use super::IllegalMoveOriginKind::*; +use super::{Init, InitIndex, InitKind, InitLocation, LookupResult, MoveError}; +use super::{ + LocationMap, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup, +}; + +struct MoveDataBuilder<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + data: MoveData<'tcx>, + errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, +} + +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { + fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { + let mut move_paths = IndexVec::new(); + let mut path_map = IndexVec::new(); + let mut init_path_map = IndexVec::new(); + + MoveDataBuilder { + body, + tcx, + param_env, + errors: Vec::new(), + data: MoveData { + moves: IndexVec::new(), + loc_map: LocationMap::new(body), + rev_lookup: MovePathLookup { + locals: body + .local_decls + .indices() + .map(|i| { + Self::new_move_path( + &mut move_paths, + &mut path_map, + &mut init_path_map, + None, + Place::from(i), + ) + }) + .collect(), + projections: Default::default(), + }, + move_paths, + path_map, + inits: IndexVec::new(), + init_loc_map: LocationMap::new(body), + init_path_map, + }, + } + } + + fn new_move_path( + move_paths: &mut IndexVec>, + path_map: &mut IndexVec>, + init_path_map: &mut IndexVec>, + parent: Option, + place: Place<'tcx>, + ) -> MovePathIndex { + let move_path = + move_paths.push(MovePath { next_sibling: None, first_child: None, parent, place }); + + if let Some(parent) = parent { + let next_sibling = mem::replace(&mut move_paths[parent].first_child, Some(move_path)); + move_paths[move_path].next_sibling = next_sibling; + } + + let path_map_ent = path_map.push(smallvec![]); + assert_eq!(path_map_ent, move_path); + + let init_path_map_ent = init_path_map.push(smallvec![]); + assert_eq!(init_path_map_ent, move_path); + + move_path + } +} + +impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { + /// This creates a MovePath for a given place, returning an `MovePathError` + /// if that place can't be moved from. + /// + /// NOTE: places behind references *do not* get a move path, which is + /// problematic for borrowck. + /// + /// Maybe we should have separate "borrowck" and "moveck" modes. + fn move_path_for(&mut self, place: Place<'tcx>) -> Result> { + debug!("lookup({:?})", place); + let mut base = self.builder.data.rev_lookup.locals[place.local]; + + // The move path index of the first union that we find. Once this is + // some we stop creating child move paths, since moves from unions + // move the whole thing. + // We continue looking for other move errors though so that moving + // from `*(u.f: &_)` isn't allowed. + let mut union_path = None; + + for (i, elem) in place.projection.iter().enumerate() { + let proj_base = &place.projection[..i]; + let body = self.builder.body; + let tcx = self.builder.tcx; + let place_ty = Place::ty_from(place.local, proj_base, body, tcx).ty; + match place_ty.kind() { + ty::Ref(..) | ty::RawPtr(..) => { + let proj = &place.projection[..i + 1]; + return Err(MoveError::cannot_move_out_of( + self.loc, + BorrowedContent { + target_place: Place { + local: place.local, + projection: tcx.intern_place_elems(proj), + }, + }, + )); + } + ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfTypeWithDestructor { container_ty: place_ty }, + )); + } + ty::Adt(adt, _) if adt.is_union() => { + union_path.get_or_insert(base); + } + ty::Slice(_) => { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfSliceOrArray { + ty: place_ty, + is_index: matches!(elem, ProjectionElem::Index(..)), + }, + )); + } + + ty::Array(..) => { + if let ProjectionElem::Index(..) = elem { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfSliceOrArray { ty: place_ty, is_index: true }, + )); + } + } + + _ => {} + }; + + if union_path.is_none() { + base = self.add_move_path(base, elem, |tcx| Place { + local: place.local, + projection: tcx.intern_place_elems(&place.projection[..i + 1]), + }); + } + } + + if let Some(base) = union_path { + // Move out of union - always move the entire union. + Err(MoveError::UnionMove { path: base }) + } else { + Ok(base) + } + } + + fn add_move_path( + &mut self, + base: MovePathIndex, + elem: PlaceElem<'tcx>, + mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>, + ) -> MovePathIndex { + let MoveDataBuilder { + data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. }, + tcx, + .. + } = self.builder; + *rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || { + MoveDataBuilder::new_move_path( + move_paths, + path_map, + init_path_map, + Some(base), + mk_place(*tcx), + ) + }) + } + + fn create_move_path(&mut self, place: Place<'tcx>) { + // This is an non-moving access (such as an overwrite or + // drop), so this not being a valid move path is OK. + let _ = self.move_path_for(place); + } +} + +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { + fn finalize( + self, + ) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { + debug!("{}", { + debug!("moves for {:?}:", self.body.span); + for (j, mo) in self.data.moves.iter_enumerated() { + debug!(" {:?} = {:?}", j, mo); + } + debug!("move paths for {:?}:", self.body.span); + for (j, path) in self.data.move_paths.iter_enumerated() { + debug!(" {:?} = {:?}", j, path); + } + "done dumping moves" + }); + + if !self.errors.is_empty() { Err((self.data, self.errors)) } else { Ok(self.data) } + } +} + +pub(super) fn gather_moves<'tcx>( + body: &Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { + let mut builder = MoveDataBuilder::new(body, tcx, param_env); + + builder.gather_args(); + + for (bb, block) in body.basic_blocks().iter_enumerated() { + for (i, stmt) in block.statements.iter().enumerate() { + let source = Location { block: bb, statement_index: i }; + builder.gather_statement(source, stmt); + } + + let terminator_loc = Location { block: bb, statement_index: block.statements.len() }; + builder.gather_terminator(terminator_loc, block.terminator()); + } + + builder.finalize() +} + +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { + fn gather_args(&mut self) { + for arg in self.body.args_iter() { + let path = self.data.rev_lookup.locals[arg]; + + let init = self.data.inits.push(Init { + path, + kind: InitKind::Deep, + location: InitLocation::Argument(arg), + }); + + debug!("gather_args: adding init {:?} of {:?} for argument {:?}", init, path, arg); + + self.data.init_path_map[path].push(init); + } + } + + fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { + debug!("gather_statement({:?}, {:?})", loc, stmt); + (Gatherer { builder: self, loc }).gather_statement(stmt); + } + + fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) { + debug!("gather_terminator({:?}, {:?})", loc, term); + (Gatherer { builder: self, loc }).gather_terminator(term); + } +} + +struct Gatherer<'b, 'a, 'tcx> { + builder: &'b mut MoveDataBuilder<'a, 'tcx>, + loc: Location, +} + +impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { + fn gather_statement(&mut self, stmt: &Statement<'tcx>) { + match &stmt.kind { + StatementKind::Assign(box (place, rval)) => { + self.create_move_path(*place); + if let RvalueInitializationState::Shallow = rval.initialization_state() { + // Box starts out uninitialized - need to create a separate + // move-path for the interior so it will be separate from + // the exterior. + self.create_move_path(self.builder.tcx.mk_place_deref(*place)); + self.gather_init(place.as_ref(), InitKind::Shallow); + } else { + self.gather_init(place.as_ref(), InitKind::Deep); + } + self.gather_rvalue(rval); + } + StatementKind::FakeRead(box (_, place)) => { + self.create_move_path(*place); + } + StatementKind::LlvmInlineAsm(ref asm) => { + for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) { + if !kind.is_indirect { + self.gather_init(output.as_ref(), InitKind::Deep); + } + } + for (_, input) in asm.inputs.iter() { + self.gather_operand(input); + } + } + StatementKind::StorageLive(_) => {} + StatementKind::StorageDead(local) => { + self.gather_move(Place::from(*local)); + } + StatementKind::SetDiscriminant { .. } => { + span_bug!( + stmt.source_info.span, + "SetDiscriminant should not exist during borrowck" + ); + } + StatementKind::Retag { .. } + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::CopyNonOverlapping(..) + | StatementKind::Nop => {} + } + } + + fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { + match *rvalue { + Rvalue::ThreadLocalRef(_) => {} // not-a-move + Rvalue::Use(ref operand) + | Rvalue::Repeat(ref operand, _) + | Rvalue::Cast(_, ref operand, _) + | Rvalue::ShallowInitBox(ref operand, _) + | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), + Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) + | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => { + self.gather_operand(lhs); + self.gather_operand(rhs); + } + Rvalue::Aggregate(ref _kind, ref operands) => { + for operand in operands { + self.gather_operand(operand); + } + } + Rvalue::Ref(..) + | Rvalue::AddressOf(..) + | Rvalue::Discriminant(..) + | Rvalue::Len(..) + | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) + | Rvalue::NullaryOp(NullOp::Box, _) => { + // This returns an rvalue with uninitialized contents. We can't + // move out of it here because it is an rvalue - assignments always + // completely initialize their place. + // + // However, this does not matter - MIR building is careful to + // only emit a shallow free for the partially-initialized + // temporary. + // + // In any case, if we want to fix this, we have to register a + // special move and change the `statement_effect` functions. + } + } + } + + fn gather_terminator(&mut self, term: &Terminator<'tcx>) { + match term.kind { + TerminatorKind::Goto { target: _ } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + // In some sense returning moves the return place into the current + // call's destination, however, since there are no statements after + // this that could possibly access the return place, this doesn't + // need recording. + | TerminatorKind::Return + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::GeneratorDrop + | TerminatorKind::Unreachable => {} + + TerminatorKind::Assert { ref cond, .. } => { + self.gather_operand(cond); + } + + TerminatorKind::SwitchInt { ref discr, .. } => { + self.gather_operand(discr); + } + + TerminatorKind::Yield { ref value, resume_arg: place, .. } => { + self.gather_operand(value); + self.create_move_path(place); + self.gather_init(place.as_ref(), InitKind::Deep); + } + + TerminatorKind::Drop { place, target: _, unwind: _ } => { + self.gather_move(place); + } + TerminatorKind::DropAndReplace { place, ref value, .. } => { + self.create_move_path(place); + self.gather_operand(value); + self.gather_init(place.as_ref(), InitKind::Deep); + } + TerminatorKind::Call { + ref func, + ref args, + ref destination, + cleanup: _, + from_hir_call: _, + fn_span: _, + } => { + self.gather_operand(func); + for arg in args { + self.gather_operand(arg); + } + if let Some((destination, _bb)) = *destination { + self.create_move_path(destination); + self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly); + } + } + TerminatorKind::InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination: _, + } => { + for op in operands { + match *op { + InlineAsmOperand::In { reg: _, ref value } + => { + self.gather_operand(value); + } + InlineAsmOperand::Out { reg: _, late: _, place, .. } => { + if let Some(place) = place { + self.create_move_path(place); + self.gather_init(place.as_ref(), InitKind::Deep); + } + } + InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { + self.gather_operand(in_value); + if let Some(out_place) = out_place { + self.create_move_path(out_place); + self.gather_init(out_place.as_ref(), InitKind::Deep); + } + } + InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { def_id: _ } => {} + } + } + } + } + } + + fn gather_operand(&mut self, operand: &Operand<'tcx>) { + match *operand { + Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move + Operand::Move(place) => { + // a move + self.gather_move(place); + } + } + } + + fn gather_move(&mut self, place: Place<'tcx>) { + debug!("gather_move({:?}, {:?})", self.loc, place); + + if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] = + **place.projection + { + // Split `Subslice` patterns into the corresponding list of + // `ConstIndex` patterns. This is done to ensure that all move paths + // are disjoint, which is expected by drop elaboration. + let base_place = + Place { local: place.local, projection: self.builder.tcx.intern_place_elems(base) }; + let base_path = match self.move_path_for(base_place) { + Ok(path) => path, + Err(MoveError::UnionMove { path }) => { + self.record_move(place, path); + return; + } + Err(error @ MoveError::IllegalMove { .. }) => { + self.builder.errors.push((base_place, error)); + return; + } + }; + let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; + let len: u64 = match base_ty.kind() { + ty::Array(_, size) => size.eval_usize(self.builder.tcx, self.builder.param_env), + _ => bug!("from_end: false slice pattern of non-array type"), + }; + for offset in from..to { + let elem = + ProjectionElem::ConstantIndex { offset, min_length: len, from_end: false }; + let path = + self.add_move_path(base_path, elem, |tcx| tcx.mk_place_elem(base_place, elem)); + self.record_move(place, path); + } + } else { + match self.move_path_for(place) { + Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path), + Err(error @ MoveError::IllegalMove { .. }) => { + self.builder.errors.push((place, error)); + } + }; + } + } + + fn record_move(&mut self, place: Place<'tcx>, path: MovePathIndex) { + let move_out = self.builder.data.moves.push(MoveOut { path, source: self.loc }); + debug!( + "gather_move({:?}, {:?}): adding move {:?} of {:?}", + self.loc, place, move_out, path + ); + self.builder.data.path_map[path].push(move_out); + self.builder.data.loc_map[self.loc].push(move_out); + } + + fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) { + debug!("gather_init({:?}, {:?})", self.loc, place); + + let mut place = place; + + // Check if we are assigning into a field of a union, if so, lookup the place + // of the union so it is marked as initialized again. + if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() { + if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() { + place = place_base; + } + } + + if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) { + let init = self.builder.data.inits.push(Init { + location: InitLocation::Statement(self.loc), + path, + kind, + }); + + debug!( + "gather_init({:?}, {:?}): adding init {:?} of {:?}", + self.loc, place, init, path + ); + + self.builder.data.init_path_map[path].push(init); + self.builder.data.init_loc_map[self.loc].push(init); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/move_paths/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,421 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::*; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_span::Span; +use smallvec::SmallVec; + +use std::fmt; +use std::ops::{Index, IndexMut}; + +use self::abs_domain::{AbstractElem, Lift}; + +mod abs_domain; + +rustc_index::newtype_index! { + pub struct MovePathIndex { + DEBUG_FORMAT = "mp{}" + } +} + +impl polonius_engine::Atom for MovePathIndex { + fn index(self) -> usize { + rustc_index::vec::Idx::index(self) + } +} + +rustc_index::newtype_index! { + pub struct MoveOutIndex { + DEBUG_FORMAT = "mo{}" + } +} + +rustc_index::newtype_index! { + pub struct InitIndex { + DEBUG_FORMAT = "in{}" + } +} + +impl MoveOutIndex { + pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex { + move_data.moves[*self].path + } +} + +/// `MovePath` is a canonicalized representation of a path that is +/// moved or assigned to. +/// +/// It follows a tree structure. +/// +/// Given `struct X { m: M, n: N }` and `x: X`, moves like `drop x.m;` +/// move *out* of the place `x.m`. +/// +/// The MovePaths representing `x.m` and `x.n` are siblings (that is, +/// one of them will link to the other via the `next_sibling` field, +/// and the other will have no entry in its `next_sibling` field), and +/// they both have the MovePath representing `x` as their parent. +#[derive(Clone)] +pub struct MovePath<'tcx> { + pub next_sibling: Option, + pub first_child: Option, + pub parent: Option, + pub place: Place<'tcx>, +} + +impl<'tcx> MovePath<'tcx> { + /// Returns an iterator over the parents of `self`. + pub fn parents<'a>( + &self, + move_paths: &'a IndexVec>, + ) -> impl 'a + Iterator)> { + let first = self.parent.map(|mpi| (mpi, &move_paths[mpi])); + MovePathLinearIter { + next: first, + fetch_next: move |_, parent: &MovePath<'_>| { + parent.parent.map(|mpi| (mpi, &move_paths[mpi])) + }, + } + } + + /// Returns an iterator over the immediate children of `self`. + pub fn children<'a>( + &self, + move_paths: &'a IndexVec>, + ) -> impl 'a + Iterator)> { + let first = self.first_child.map(|mpi| (mpi, &move_paths[mpi])); + MovePathLinearIter { + next: first, + fetch_next: move |_, child: &MovePath<'_>| { + child.next_sibling.map(|mpi| (mpi, &move_paths[mpi])) + }, + } + } + + /// Finds the closest descendant of `self` for which `f` returns `true` using a breadth-first + /// search. + /// + /// `f` will **not** be called on `self`. + pub fn find_descendant( + &self, + move_paths: &IndexVec>, + f: impl Fn(MovePathIndex) -> bool, + ) -> Option { + let mut todo = if let Some(child) = self.first_child { + vec![child] + } else { + return None; + }; + + while let Some(mpi) = todo.pop() { + if f(mpi) { + return Some(mpi); + } + + let move_path = &move_paths[mpi]; + if let Some(child) = move_path.first_child { + todo.push(child); + } + + // After we've processed the original `mpi`, we should always + // traverse the siblings of any of its children. + if let Some(sibling) = move_path.next_sibling { + todo.push(sibling); + } + } + + None + } +} + +impl<'tcx> fmt::Debug for MovePath<'tcx> { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(w, "MovePath {{")?; + if let Some(parent) = self.parent { + write!(w, " parent: {:?},", parent)?; + } + if let Some(first_child) = self.first_child { + write!(w, " first_child: {:?},", first_child)?; + } + if let Some(next_sibling) = self.next_sibling { + write!(w, " next_sibling: {:?}", next_sibling)?; + } + write!(w, " place: {:?} }}", self.place) + } +} + +impl<'tcx> fmt::Display for MovePath<'tcx> { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(w, "{:?}", self.place) + } +} + +struct MovePathLinearIter<'a, 'tcx, F> { + next: Option<(MovePathIndex, &'a MovePath<'tcx>)>, + fetch_next: F, +} + +impl<'a, 'tcx, F> Iterator for MovePathLinearIter<'a, 'tcx, F> +where + F: FnMut(MovePathIndex, &'a MovePath<'tcx>) -> Option<(MovePathIndex, &'a MovePath<'tcx>)>, +{ + type Item = (MovePathIndex, &'a MovePath<'tcx>); + + fn next(&mut self) -> Option { + let ret = self.next.take()?; + self.next = (self.fetch_next)(ret.0, ret.1); + Some(ret) + } +} + +#[derive(Debug)] +pub struct MoveData<'tcx> { + pub move_paths: IndexVec>, + pub moves: IndexVec, + /// Each Location `l` is mapped to the MoveOut's that are effects + /// of executing the code at `l`. (There can be multiple MoveOut's + /// for a given `l` because each MoveOut is associated with one + /// particular path being moved.) + pub loc_map: LocationMap>, + pub path_map: IndexVec>, + pub rev_lookup: MovePathLookup, + pub inits: IndexVec, + /// Each Location `l` is mapped to the Inits that are effects + /// of executing the code at `l`. + pub init_loc_map: LocationMap>, + pub init_path_map: IndexVec>, +} + +pub trait HasMoveData<'tcx> { + fn move_data(&self) -> &MoveData<'tcx>; +} + +#[derive(Debug)] +pub struct LocationMap { + /// Location-indexed (BasicBlock for outer index, index within BB + /// for inner index) map. + pub(crate) map: IndexVec>, +} + +impl Index for LocationMap { + type Output = T; + fn index(&self, index: Location) -> &Self::Output { + &self.map[index.block][index.statement_index] + } +} + +impl IndexMut for LocationMap { + fn index_mut(&mut self, index: Location) -> &mut Self::Output { + &mut self.map[index.block][index.statement_index] + } +} + +impl LocationMap +where + T: Default + Clone, +{ + fn new(body: &Body<'_>) -> Self { + LocationMap { + map: body + .basic_blocks() + .iter() + .map(|block| vec![T::default(); block.statements.len() + 1]) + .collect(), + } + } +} + +/// `MoveOut` represents a point in a program that moves out of some +/// L-value; i.e., "creates" uninitialized memory. +/// +/// With respect to dataflow analysis: +/// - Generated by moves and declaration of uninitialized variables. +/// - Killed by assignments to the memory. +#[derive(Copy, Clone)] +pub struct MoveOut { + /// path being moved + pub path: MovePathIndex, + /// location of move + pub source: Location, +} + +impl fmt::Debug for MoveOut { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{:?}@{:?}", self.path, self.source) + } +} + +/// `Init` represents a point in a program that initializes some L-value; +#[derive(Copy, Clone)] +pub struct Init { + /// path being initialized + pub path: MovePathIndex, + /// location of initialization + pub location: InitLocation, + /// Extra information about this initialization + pub kind: InitKind, +} + +/// Initializations can be from an argument or from a statement. Arguments +/// do not have locations, in those cases the `Local` is kept.. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum InitLocation { + Argument(Local), + Statement(Location), +} + +/// Additional information about the initialization. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum InitKind { + /// Deep init, even on panic + Deep, + /// Only does a shallow init + Shallow, + /// This doesn't initialize the variable on panic (and a panic is possible). + NonPanicPathOnly, +} + +impl fmt::Debug for Init { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{:?}@{:?} ({:?})", self.path, self.location, self.kind) + } +} + +impl Init { + pub fn span<'tcx>(&self, body: &Body<'tcx>) -> Span { + match self.location { + InitLocation::Argument(local) => body.local_decls[local].source_info.span, + InitLocation::Statement(location) => body.source_info(location).span, + } + } +} + +/// Tables mapping from a place to its MovePathIndex. +#[derive(Debug)] +pub struct MovePathLookup { + locals: IndexVec, + + /// projections are made from a base-place and a projection + /// elem. The base-place will have a unique MovePathIndex; we use + /// the latter as the index into the outer vector (narrowing + /// subsequent search so that it is solely relative to that + /// base-place). For the remaining lookup, we map the projection + /// elem to the associated MovePathIndex. + projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>, +} + +mod builder; + +#[derive(Copy, Clone, Debug)] +pub enum LookupResult { + Exact(MovePathIndex), + Parent(Option), +} + +impl MovePathLookup { + // Unlike the builder `fn move_path_for` below, this lookup + // alternative will *not* create a MovePath on the fly for an + // unknown place, but will rather return the nearest available + // parent. + pub fn find(&self, place: PlaceRef<'_>) -> LookupResult { + let mut result = self.locals[place.local]; + + for elem in place.projection.iter() { + if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { + result = subpath; + } else { + return LookupResult::Parent(Some(result)); + } + } + + LookupResult::Exact(result) + } + + pub fn find_local(&self, local: Local) -> MovePathIndex { + self.locals[local] + } + + /// An enumerated iterator of `local`s and their associated + /// `MovePathIndex`es. + pub fn iter_locals_enumerated( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator { + self.locals.iter_enumerated() + } +} + +#[derive(Debug)] +pub struct IllegalMoveOrigin<'tcx> { + pub location: Location, + pub kind: IllegalMoveOriginKind<'tcx>, +} + +#[derive(Debug)] +pub enum IllegalMoveOriginKind<'tcx> { + /// Illegal move due to attempt to move from behind a reference. + BorrowedContent { + /// The place the reference refers to: if erroneous code was trying to + /// move from `(*x).f` this will be `*x`. + target_place: Place<'tcx>, + }, + + /// Illegal move due to attempt to move from field of an ADT that + /// implements `Drop`. Rust maintains invariant that all `Drop` + /// ADT's remain fully-initialized so that user-defined destructor + /// can safely read from all of the ADT's fields. + InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> }, + + /// Illegal move due to attempt to move out of a slice or array. + InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool }, +} + +#[derive(Debug)] +pub enum MoveError<'tcx> { + IllegalMove { cannot_move_out_of: IllegalMoveOrigin<'tcx> }, + UnionMove { path: MovePathIndex }, +} + +impl<'tcx> MoveError<'tcx> { + fn cannot_move_out_of(location: Location, kind: IllegalMoveOriginKind<'tcx>) -> Self { + let origin = IllegalMoveOrigin { location, kind }; + MoveError::IllegalMove { cannot_move_out_of: origin } + } +} + +impl<'tcx> MoveData<'tcx> { + pub fn gather_moves( + body: &Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Result, MoveError<'tcx>)>)> { + builder::gather_moves(body, tcx, param_env) + } + + /// For the move path `mpi`, returns the root local variable (if any) that starts the path. + /// (e.g., for a path like `a.b.c` returns `Some(a)`) + pub fn base_local(&self, mut mpi: MovePathIndex) -> Option { + loop { + let path = &self.move_paths[mpi]; + if let Some(l) = path.place.as_local() { + return Some(l); + } + if let Some(parent) = path.parent { + mpi = parent; + continue; + } else { + return None; + } + } + } + + pub fn find_in_move_path_or_its_descendants( + &self, + root: MovePathIndex, + pred: impl Fn(MovePathIndex) -> bool, + ) -> Option { + if pred(root) { + return Some(root); + } + + self.move_paths[root].find_descendant(&self.move_paths, pred) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/rustc_peek.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/rustc_peek.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/rustc_peek.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/rustc_peek.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,326 @@ +use std::borrow::Borrow; + +use rustc_ast::ast; +use rustc_span::symbol::sym; +use rustc_span::Span; +use rustc_target::spec::abi::Abi; + +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::MirPass; +use rustc_middle::mir::{self, Body, Local, Location}; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +use crate::impls::{ + DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals, + MaybeUninitializedPlaces, +}; +use crate::move_paths::{HasMoveData, MoveData}; +use crate::move_paths::{LookupResult, MovePathIndex}; +use crate::MoveDataParamEnv; +use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor}; + +pub struct SanityCheck; + +impl<'tcx> MirPass<'tcx> for SanityCheck { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + use crate::has_rustc_mir_with; + let def_id = body.source.def_id(); + if !tcx.has_attr(def_id, sym::rustc_mir) { + debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); + return; + } else { + debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); + } + + let attributes = tcx.get_attrs(def_id); + let param_env = tcx.param_env(def_id); + let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap(); + let mdpe = MoveDataParamEnv { move_data, param_env }; + let sess = &tcx.sess; + + if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_init).is_some() { + let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe) + .into_engine(tcx, body) + .iterate_to_fixpoint(); + + sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_inits); + } + + if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_uninit).is_some() { + let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe) + .into_engine(tcx, body) + .iterate_to_fixpoint(); + + sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_uninits); + } + + if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_definite_init).is_some() { + let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe) + .into_engine(tcx, body) + .iterate_to_fixpoint(); + + sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits); + } + + if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() { + let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env) + .into_engine(tcx, body) + .iterate_to_fixpoint(); + + sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed); + } + + if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() { + let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); + + sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_liveness); + } + + if has_rustc_mir_with(sess, &attributes, sym::stop_after_dataflow).is_some() { + tcx.sess.fatal("stop_after_dataflow ended compilation"); + } + } +} + +/// This function scans `mir` for all calls to the intrinsic +/// `rustc_peek` that have the expression form `rustc_peek(&expr)`. +/// +/// For each such call, determines what the dataflow bit-state is for +/// the L-value corresponding to `expr`; if the bit-state is a 1, then +/// that call to `rustc_peek` is ignored by the sanity check. If the +/// bit-state is a 0, then this pass emits an error message saying +/// "rustc_peek: bit not set". +/// +/// The intention is that one can write unit tests for dataflow by +/// putting code into a UI test and using `rustc_peek` to +/// make observations about the results of dataflow static analyses. +/// +/// (If there are any calls to `rustc_peek` that do not match the +/// expression form above, then that emits an error as well, but those +/// errors are not intended to be used for unit tests.) +pub fn sanity_check_via_rustc_peek<'tcx, A>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + _attributes: &[ast::Attribute], + results: &Results<'tcx, A>, +) where + A: RustcPeekAt<'tcx>, +{ + let def_id = body.source.def_id(); + debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id); + + let mut cursor = ResultsCursor::new(body, results); + + let peek_calls = body.basic_blocks().iter_enumerated().filter_map(|(bb, block_data)| { + PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call)) + }); + + for (bb, block_data, call) in peek_calls { + // Look for a sequence like the following to indicate that we should be peeking at `_1`: + // _2 = &_1; + // rustc_peek(_2); + // + // /* or */ + // + // _2 = _1; + // rustc_peek(_2); + let (statement_index, peek_rval) = block_data + .statements + .iter() + .enumerate() + .find_map(|(i, stmt)| value_assigned_to_local(stmt, call.arg).map(|rval| (i, rval))) + .expect( + "call to rustc_peek should be preceded by \ + assignment to temporary holding its argument", + ); + + match (call.kind, peek_rval) { + (PeekCallKind::ByRef, mir::Rvalue::Ref(_, _, place)) + | ( + PeekCallKind::ByVal, + mir::Rvalue::Use(mir::Operand::Move(place) | mir::Operand::Copy(place)), + ) => { + let loc = Location { block: bb, statement_index }; + cursor.seek_before_primary_effect(loc); + let state = cursor.get(); + results.analysis.peek_at(tcx, *place, state, call); + } + + _ => { + let msg = "rustc_peek: argument expression \ + must be either `place` or `&place`"; + tcx.sess.span_err(call.span, msg); + } + } + } +} + +/// If `stmt` is an assignment where the LHS is the given local (with no projections), returns the +/// RHS of the assignment. +fn value_assigned_to_local<'a, 'tcx>( + stmt: &'a mir::Statement<'tcx>, + local: Local, +) -> Option<&'a mir::Rvalue<'tcx>> { + if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind { + if let Some(l) = place.as_local() { + if local == l { + return Some(&*rvalue); + } + } + } + + None +} + +#[derive(Clone, Copy, Debug)] +enum PeekCallKind { + ByVal, + ByRef, +} + +impl PeekCallKind { + fn from_arg_ty(arg: Ty<'_>) -> Self { + match arg.kind() { + ty::Ref(_, _, _) => PeekCallKind::ByRef, + _ => PeekCallKind::ByVal, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct PeekCall { + arg: Local, + kind: PeekCallKind, + span: Span, +} + +impl PeekCall { + fn from_terminator<'tcx>( + tcx: TyCtxt<'tcx>, + terminator: &mir::Terminator<'tcx>, + ) -> Option { + use mir::Operand; + + let span = terminator.source_info.span; + if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = + &terminator.kind + { + if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() { + let sig = tcx.fn_sig(def_id); + let name = tcx.item_name(def_id); + if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek { + return None; + } + + assert_eq!(args.len(), 1); + let kind = PeekCallKind::from_arg_ty(substs.type_at(0)); + let arg = match &args[0] { + Operand::Copy(place) | Operand::Move(place) => { + if let Some(local) = place.as_local() { + local + } else { + tcx.sess.diagnostic().span_err( + span, + "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", + ); + return None; + } + } + _ => { + tcx.sess.diagnostic().span_err( + span, + "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", + ); + return None; + } + }; + + return Some(PeekCall { arg, kind, span }); + } + } + + None + } +} + +pub trait RustcPeekAt<'tcx>: Analysis<'tcx> { + fn peek_at( + &self, + tcx: TyCtxt<'tcx>, + place: mir::Place<'tcx>, + flow_state: &Self::Domain, + call: PeekCall, + ); +} + +impl<'tcx, A, D> RustcPeekAt<'tcx> for A +where + A: Analysis<'tcx, Domain = D> + HasMoveData<'tcx>, + D: JoinSemiLattice + Clone + Borrow>, +{ + fn peek_at( + &self, + tcx: TyCtxt<'tcx>, + place: mir::Place<'tcx>, + flow_state: &Self::Domain, + call: PeekCall, + ) { + match self.move_data().rev_lookup.find(place.as_ref()) { + LookupResult::Exact(peek_mpi) => { + let bit_state = flow_state.borrow().contains(peek_mpi); + debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state); + if !bit_state { + tcx.sess.span_err(call.span, "rustc_peek: bit not set"); + } + } + + LookupResult::Parent(..) => { + tcx.sess.span_err(call.span, "rustc_peek: argument untracked"); + } + } + } +} + +impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> { + fn peek_at( + &self, + tcx: TyCtxt<'tcx>, + place: mir::Place<'tcx>, + flow_state: &BitSet, + call: PeekCall, + ) { + info!(?place, "peek_at"); + let local = if let Some(l) = place.as_local() { + l + } else { + tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); + return; + }; + + if !flow_state.contains(local) { + tcx.sess.span_err(call.span, "rustc_peek: bit not set"); + } + } +} + +impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { + fn peek_at( + &self, + tcx: TyCtxt<'tcx>, + place: mir::Place<'tcx>, + flow_state: &BitSet, + call: PeekCall, + ) { + info!(?place, "peek_at"); + let local = if let Some(l) = place.as_local() { + l + } else { + tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); + return; + }; + + if !flow_state.contains(local) { + tcx.sess.span_err(call.span, "rustc_peek: bit not set"); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/storage.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/storage.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/storage.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_dataflow/src/storage.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,41 @@ +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::{self, Local}; + +/// The set of locals in a MIR body that do not have `StorageLive`/`StorageDead` annotations. +/// +/// These locals have fixed storage for the duration of the body. +// +// FIXME: Currently, we need to traverse the entire MIR to compute this. We should instead store it +// as a field in the `LocalDecl` for each `Local`. +#[derive(Debug, Clone)] +pub struct AlwaysLiveLocals(BitSet); + +impl AlwaysLiveLocals { + pub fn new(body: &mir::Body<'tcx>) -> Self { + let mut always_live_locals = AlwaysLiveLocals(BitSet::new_filled(body.local_decls.len())); + + for block in body.basic_blocks() { + for statement in &block.statements { + use mir::StatementKind::{StorageDead, StorageLive}; + if let StorageLive(l) | StorageDead(l) = statement.kind { + always_live_locals.0.remove(l); + } + } + } + + always_live_locals + } + + pub fn into_inner(self) -> BitSet { + self.0 + } +} + +impl std::ops::Deref for AlwaysLiveLocals { + type Target = BitSet; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +[package] +name = "rustc_mir_transform" +version = "0.0.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +itertools = "0.9" +smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_middle = { path = "../rustc_middle" } +rustc_const_eval = { path = "../rustc_const_eval" } +rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } +rustc_query_system = { path = "../rustc_query_system" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_span = { path = "../rustc_span" } + +[dev-dependencies] +coverage_test_macros = { path = "src/coverage/test_macros" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,143 @@ +use crate::MirPass; +use rustc_hir::def::DefKind; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::*; +use rustc_middle::ty::layout; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_target::spec::abi::Abi; +use rustc_target::spec::PanicStrategy; + +/// A pass that runs which is targeted at ensuring that codegen guarantees about +/// unwinding are upheld for compilations of panic=abort programs. +/// +/// When compiling with panic=abort codegen backends generally want to assume +/// that all Rust-defined functions do not unwind, and it's UB if they actually +/// do unwind. Foreign functions, however, can be declared as "may unwind" via +/// their ABI (e.g. `extern "C-unwind"`). To uphold the guarantees that +/// Rust-defined functions never unwind a well-behaved Rust program needs to +/// catch unwinding from foreign functions and force them to abort. +/// +/// This pass walks over all functions calls which may possibly unwind, +/// and if any are found sets their cleanup to a block that aborts the process. +/// This forces all unwinds, in panic=abort mode happening in foreign code, to +/// trigger a process abort. +#[derive(PartialEq)] +pub struct AbortUnwindingCalls; + +impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let def_id = body.source.def_id(); + let kind = tcx.def_kind(def_id); + + // We don't simplify the MIR of constants at this time because that + // namely results in a cyclic query when we call `tcx.type_of` below. + let is_function = match kind { + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, + _ => tcx.is_closure(def_id), + }; + if !is_function { + return; + } + + // This pass only runs on functions which themselves cannot unwind, + // forcibly changing the body of the function to structurally provide + // this guarantee by aborting on an unwind. If this function can unwind, + // then there's nothing to do because it already should work correctly. + // + // Here we test for this function itself whether its ABI allows + // unwinding or not. + let body_flags = tcx.codegen_fn_attrs(def_id).flags; + let body_ty = tcx.type_of(def_id); + let body_abi = match body_ty.kind() { + ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), + ty::Closure(..) => Abi::RustCall, + ty::Generator(..) => Abi::Rust, + _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), + }; + let body_can_unwind = layout::fn_can_unwind(tcx, body_flags, body_abi); + + // Look in this function body for any basic blocks which are terminated + // with a function call, and whose function we're calling may unwind. + // This will filter to functions with `extern "C-unwind"` ABIs, for + // example. + let mut calls_to_terminate = Vec::new(); + let mut cleanups_to_remove = Vec::new(); + for (id, block) in body.basic_blocks().iter_enumerated() { + if block.is_cleanup { + continue; + } + let terminator = match &block.terminator { + Some(terminator) => terminator, + None => continue, + }; + let span = terminator.source_info.span; + + let call_can_unwind = match &terminator.kind { + TerminatorKind::Call { func, .. } => { + let ty = func.ty(body, tcx); + let sig = ty.fn_sig(tcx); + let flags = match ty.kind() { + ty::FnPtr(_) => CodegenFnAttrFlags::empty(), + ty::FnDef(def_id, _) => tcx.codegen_fn_attrs(*def_id).flags, + _ => span_bug!(span, "invalid callee of type {:?}", ty), + }; + layout::fn_can_unwind(tcx, flags, sig.abi()) + } + TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => { + tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Unwind + && layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust) + } + TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => { + layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust) + } + _ => continue, + }; + + // If this function call can't unwind, then there's no need for it + // to have a landing pad. This means that we can remove any cleanup + // registered for it. + if !call_can_unwind { + cleanups_to_remove.push(id); + continue; + } + + // Otherwise if this function can unwind, then if the outer function + // can also unwind there's nothing to do. If the outer function + // can't unwind, however, we need to change the landing pad for this + // function call to one that aborts. + if !body_can_unwind { + calls_to_terminate.push(id); + } + } + + // For call instructions which need to be terminated, we insert a + // singular basic block which simply terminates, and then configure the + // `cleanup` attribute for all calls we found to this basic block we + // insert which means that any unwinding that happens in the functions + // will force an abort of the process. + if !calls_to_terminate.is_empty() { + let bb = BasicBlockData { + statements: Vec::new(), + is_cleanup: true, + terminator: Some(Terminator { + source_info: SourceInfo::outermost(body.span), + kind: TerminatorKind::Abort, + }), + }; + let abort_bb = body.basic_blocks_mut().push(bb); + + for bb in calls_to_terminate { + let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap(); + *cleanup = Some(abort_bb); + } + } + + for id in cleanups_to_remove { + let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap(); + *cleanup = None; + } + + // We may have invalidated some `cleanup` blocks so clean those up now. + super::simplify::remove_dead_blocks(tcx, body); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_call_guards.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_call_guards.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_call_guards.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_call_guards.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,86 @@ +use crate::MirPass; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +#[derive(PartialEq)] +pub enum AddCallGuards { + AllCallEdges, + CriticalCallEdges, +} +pub use self::AddCallGuards::*; + +/** + * Breaks outgoing critical edges for call terminators in the MIR. + * + * Critical edges are edges that are neither the only edge leaving a + * block, nor the only edge entering one. + * + * When you want something to happen "along" an edge, you can either + * do at the end of the predecessor block, or at the start of the + * successor block. Critical edges have to be broken in order to prevent + * "edge actions" from affecting other edges. We need this for calls that are + * codegened to LLVM invoke instructions, because invoke is a block terminator + * in LLVM so we can't insert any code to handle the call's result into the + * block that performs the call. + * + * This function will break those edges by inserting new blocks along them. + * + * NOTE: Simplify CFG will happily undo most of the work this pass does. + * + */ + +impl<'tcx> MirPass<'tcx> for AddCallGuards { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + self.add_call_guards(body); + } +} + +impl AddCallGuards { + pub fn add_call_guards(&self, body: &mut Body<'_>) { + let mut pred_count: IndexVec<_, _> = + body.predecessors().iter().map(|ps| ps.len()).collect(); + pred_count[START_BLOCK] += 1; + + // We need a place to store the new blocks generated + let mut new_blocks = Vec::new(); + + let cur_len = body.basic_blocks().len(); + + for block in body.basic_blocks_mut() { + match block.terminator { + Some(Terminator { + kind: + TerminatorKind::Call { + destination: Some((_, ref mut destination)), + cleanup, + .. + }, + source_info, + }) if pred_count[*destination] > 1 + && (cleanup.is_some() || self == &AllCallEdges) => + { + // It's a critical edge, break it + let call_guard = BasicBlockData { + statements: vec![], + is_cleanup: block.is_cleanup, + terminator: Some(Terminator { + source_info, + kind: TerminatorKind::Goto { target: *destination }, + }), + }; + + // Get the index it will be when inserted into the MIR + let idx = cur_len + new_blocks.len(); + new_blocks.push(call_guard); + *destination = BasicBlock::new(idx); + } + _ => {} + } + } + + debug!("Broke {} N edges", new_blocks.len()); + + body.basic_blocks_mut().extend(new_blocks); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,108 @@ +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +use crate::util; +use crate::MirPass; +use rustc_middle::mir::patch::MirPatch; + +// This pass moves values being dropped that are within a packed +// struct to a separate local before dropping them, to ensure that +// they are dropped from an aligned address. +// +// For example, if we have something like +// ```Rust +// #[repr(packed)] +// struct Foo { +// dealign: u8, +// data: Vec +// } +// +// let foo = ...; +// ``` +// +// We want to call `drop_in_place::>` on `data` from an aligned +// address. This means we can't simply drop `foo.data` directly, because +// its address is not aligned. +// +// Instead, we move `foo.data` to a local and drop that: +// ``` +// storage.live(drop_temp) +// drop_temp = foo.data; +// drop(drop_temp) -> next +// next: +// storage.dead(drop_temp) +// ``` +// +// The storage instructions are required to avoid stack space +// blowup. + +pub struct AddMovesForPackedDrops; + +impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span); + add_moves_for_packed_drops(tcx, body); + } +} + +pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let patch = add_moves_for_packed_drops_patch(tcx, body); + patch.apply(body); +} + +fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> MirPatch<'tcx> { + let def_id = body.source.def_id(); + let mut patch = MirPatch::new(body); + let param_env = tcx.param_env(def_id); + + for (bb, data) in body.basic_blocks().iter_enumerated() { + let loc = Location { block: bb, statement_index: data.statements.len() }; + let terminator = data.terminator(); + + match terminator.kind { + TerminatorKind::Drop { place, .. } + if util::is_disaligned(tcx, body, param_env, place) => + { + add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup); + } + TerminatorKind::DropAndReplace { .. } => { + span_bug!(terminator.source_info.span, "replace in AddMovesForPackedDrops"); + } + _ => {} + } + } + + patch +} + +fn add_move_for_packed_drop<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + patch: &mut MirPatch<'tcx>, + terminator: &Terminator<'tcx>, + loc: Location, + is_cleanup: bool, +) { + debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc); + let (place, target, unwind) = match terminator.kind { + TerminatorKind::Drop { ref place, target, unwind } => (place, target, unwind), + _ => unreachable!(), + }; + + let source_info = terminator.source_info; + let ty = place.ty(body, tcx).ty; + let temp = patch.new_temp(ty, terminator.source_info.span); + + let storage_dead_block = patch.new_block(BasicBlockData { + statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }], + terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), + is_cleanup, + }); + + patch.add_statement(loc, StatementKind::StorageLive(temp)); + patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); + patch.patch_terminator( + loc.block, + TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind }, + ); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_retag.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_retag.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_retag.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/add_retag.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,186 @@ +//! This pass adds validation calls (AcquireValid, ReleaseValid) where appropriate. +//! It has to be run really early, before transformations like inlining, because +//! introducing these calls *adds* UB -- so, conceptually, this pass is actually part +//! of MIR building, and only after this pass we think of the program has having the +//! normal MIR semantics. + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub struct AddRetag; + +/// Determines whether this place is "stable": Whether, if we evaluate it again +/// after the assignment, we can be sure to obtain the same place value. +/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic +/// copies. Data races are UB.) +fn is_stable(place: PlaceRef<'_>) -> bool { + place.projection.iter().all(|elem| { + match elem { + // Which place this evaluates to can change with any memory write, + // so cannot assume this to be stable. + ProjectionElem::Deref => false, + // Array indices are interesting, but MIR building generates a *fresh* + // temporary for every array access, so the index cannot be changed as + // a side-effect. + ProjectionElem::Index { .. } | + // The rest is completely boring, they just offset by a constant. + ProjectionElem::Field { .. } | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Subslice { .. } | + ProjectionElem::Downcast { .. } => true, + } + }) +} + +/// Determine whether this type may be a reference (or box), and thus needs retagging. +fn may_be_reference(ty: Ty<'tcx>) -> bool { + match ty.kind() { + // Primitive types that are not references + ty::Bool + | ty::Char + | ty::Float(_) + | ty::Int(_) + | ty::Uint(_) + | ty::RawPtr(..) + | ty::FnPtr(..) + | ty::Str + | ty::FnDef(..) + | ty::Never => false, + // References + ty::Ref(..) => true, + ty::Adt(..) if ty.is_box() => true, + // Compound types are not references + ty::Array(..) | ty::Slice(..) | ty::Tuple(..) | ty::Adt(..) => false, + // Conservative fallback + _ => true, + } +} + +impl<'tcx> MirPass<'tcx> for AddRetag { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if !tcx.sess.opts.debugging_opts.mir_emit_retag { + return; + } + + // We need an `AllCallEdges` pass before we can do any work. + super::add_call_guards::AllCallEdges.run_pass(tcx, body); + + let (span, arg_count) = (body.span, body.arg_count); + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + let needs_retag = |place: &Place<'tcx>| { + // FIXME: Instead of giving up for unstable places, we should introduce + // a temporary and retag on that. + is_stable(place.as_ref()) && may_be_reference(place.ty(&*local_decls, tcx).ty) + }; + let place_base_raw = |place: &Place<'tcx>| { + // If this is a `Deref`, get the type of what we are deref'ing. + let deref_base = + place.projection.iter().rposition(|p| matches!(p, ProjectionElem::Deref)); + if let Some(deref_base) = deref_base { + let base_proj = &place.projection[..deref_base]; + let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty; + ty.is_unsafe_ptr() + } else { + // Not a deref, and thus not raw. + false + } + }; + + // PART 1 + // Retag arguments at the beginning of the start block. + { + // FIXME: Consider using just the span covering the function + // argument declaration. + let source_info = SourceInfo::outermost(span); + // Gather all arguments, skip return value. + let places = local_decls + .iter_enumerated() + .skip(1) + .take(arg_count) + .map(|(local, _)| Place::from(local)) + .filter(needs_retag); + // Emit their retags. + basic_blocks[START_BLOCK].statements.splice( + 0..0, + places.map(|place| Statement { + source_info, + kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)), + }), + ); + } + + // PART 2 + // Retag return values of functions. Also escape-to-raw the argument of `drop`. + // We collect the return destinations because we cannot mutate while iterating. + let returns = basic_blocks + .iter_mut() + .filter_map(|block_data| { + match block_data.terminator().kind { + TerminatorKind::Call { destination: Some(ref destination), .. } + if needs_retag(&destination.0) => + { + // Remember the return destination for later + Some((block_data.terminator().source_info, destination.0, destination.1)) + } + + // `Drop` is also a call, but it doesn't return anything so we are good. + TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => None, + // Not a block ending in a Call -> ignore. + _ => None, + } + }) + .collect::>(); + // Now we go over the returns we collected to retag the return values. + for (source_info, dest_place, dest_block) in returns { + basic_blocks[dest_block].statements.insert( + 0, + Statement { + source_info, + kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)), + }, + ); + } + + // PART 3 + // Add retag after assignment. + for block_data in basic_blocks { + // We want to insert statements as we iterate. To this end, we + // iterate backwards using indices. + for i in (0..block_data.statements.len()).rev() { + let (retag_kind, place) = match block_data.statements[i].kind { + // Retag-as-raw after escaping to a raw pointer, if the referent + // is not already a raw pointer. + StatementKind::Assign(box (lplace, Rvalue::AddressOf(_, ref rplace))) + if !place_base_raw(rplace) => + { + (RetagKind::Raw, lplace) + } + // Retag after assignments of reference type. + StatementKind::Assign(box (ref place, ref rvalue)) if needs_retag(place) => { + let kind = match rvalue { + Rvalue::Ref(_, borrow_kind, _) + if borrow_kind.allows_two_phase_borrow() => + { + RetagKind::TwoPhase + } + _ => RetagKind::Default, + }; + (kind, *place) + } + // Do nothing for the rest + _ => continue, + }; + // Insert a retag after the statement. + let source_info = block_data.statements[i].source_info; + block_data.statements.insert( + i + 1, + Statement { + source_info, + kind: StatementKind::Retag(retag_kind, Box::new(place)), + }, + ); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_const_item_mutation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_const_item_mutation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_const_item_mutation.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_const_item_mutation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,157 @@ +use rustc_errors::DiagnosticBuilder; +use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::lint::builtin::CONST_ITEM_MUTATION; +use rustc_span::def_id::DefId; + +use crate::MirPass; + +pub struct CheckConstItemMutation; + +impl<'tcx> MirPass<'tcx> for CheckConstItemMutation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut checker = ConstMutationChecker { body, tcx, target_local: None }; + checker.visit_body(&body); + } +} + +struct ConstMutationChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + target_local: Option, +} + +impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { + fn is_const_item(&self, local: Local) -> Option { + if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info { + Some(def_id) + } else { + None + } + } + + fn is_const_item_without_destructor(&self, local: Local) -> Option { + let def_id = self.is_const_item(local)?; + + // We avoid linting mutation of a const item if the const's type has a + // Drop impl. The Drop logic observes the mutation which was performed. + // + // pub struct Log { msg: &'static str } + // pub const LOG: Log = Log { msg: "" }; + // impl Drop for Log { + // fn drop(&mut self) { println!("{}", self.msg); } + // } + // + // LOG.msg = "wow"; // prints "wow" + // + // FIXME(https://github.com/rust-lang/rust/issues/77425): + // Drop this exception once there is a stable attribute to suppress the + // const item mutation lint for a single specific const only. Something + // equivalent to: + // + // #[const_mutation_allowed] + // pub const LOG: Log = Log { msg: "" }; + match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) { + Some(_) => None, + None => Some(def_id), + } + } + + fn lint_const_item_usage( + &self, + place: &Place<'tcx>, + const_item: DefId, + location: Location, + decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>, + ) { + // Don't lint on borrowing/assigning when a dereference is involved. + // If we 'leave' the temporary via a dereference, we must + // be modifying something else + // + // `unsafe { *FOO = 0; *BAR.field = 1; }` + // `unsafe { &mut *FOO }` + // `unsafe { (*ARRAY)[0] = val; } + if !place.projection.iter().any(|p| matches!(p, PlaceElem::Deref)) { + let source_info = self.body.source_info(location); + let lint_root = self.body.source_scopes[source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + + self.tcx.struct_span_lint_hir( + CONST_ITEM_MUTATION, + lint_root, + source_info.span, + |lint| { + decorate(lint) + .span_note(self.tcx.def_span(const_item), "`const` item defined here") + .emit() + }, + ); + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { + fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) { + if let StatementKind::Assign(box (lhs, _)) = &stmt.kind { + // Check for assignment to fields of a constant + // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error, + // so emitting a lint would be redundant. + if !lhs.projection.is_empty() { + if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) { + self.lint_const_item_usage(&lhs, def_id, loc, |lint| { + let mut lint = lint.build("attempting to modify a `const` item"); + lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified"); + lint + }) + } + } + // We are looking for MIR of the form: + // + // ``` + // _1 = const FOO; + // _2 = &mut _1; + // method_call(_2, ..) + // ``` + // + // Record our current LHS, so that we can detect this + // pattern in `visit_rvalue` + self.target_local = lhs.as_local(); + } + self.super_statement(stmt, loc); + self.target_local = None; + } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { + if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue { + let local = place.local; + if let Some(def_id) = self.is_const_item(local) { + // If this Rvalue is being used as the right-hand side of a + // `StatementKind::Assign`, see if it ends up getting used as + // the `self` parameter of a method call (as the terminator of our current + // BasicBlock). If so, we emit a more specific lint. + let method_did = self.target_local.and_then(|target_local| { + crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block) + }); + let lint_loc = + if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc }; + self.lint_const_item_usage(place, def_id, lint_loc, |lint| { + let mut lint = lint.build("taking a mutable reference to a `const` item"); + lint + .note("each usage of a `const` item creates a new temporary") + .note("the mutable reference will refer to this temporary, not the original `const` item"); + + if let Some((method_did, _substs)) = method_did { + lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method"); + } + + lint + }); + } + } + self.super_rvalue(rvalue, loc); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_packed_ref.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_packed_ref.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_packed_ref.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_packed_ref.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,115 @@ +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::lint::builtin::UNALIGNED_REFERENCES; +use rustc_span::symbol::sym; + +use crate::util; +use crate::MirPass; + +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { unsafe_derive_on_repr_packed, ..*providers }; +} + +pub struct CheckPackedRef; + +impl<'tcx> MirPass<'tcx> for CheckPackedRef { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let param_env = tcx.param_env(body.source.def_id()); + let source_info = SourceInfo::outermost(body.span); + let mut checker = PackedRefChecker { body, tcx, param_env, source_info }; + checker.visit_body(&body); + } +} + +struct PackedRefChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + source_info: SourceInfo, +} + +fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + + tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| { + // FIXME: when we make this a hard error, this should have its + // own error code. + let message = if tcx.generics_of(def_id).own_requires_monomorphization() { + "`#[derive]` can't be used on a `#[repr(packed)]` struct with \ + type or const parameters (error E0133)" + .to_string() + } else { + "`#[derive]` can't be used on a `#[repr(packed)]` struct that \ + does not derive Copy (error E0133)" + .to_string() + }; + lint.build(&message).emit() + }); +} + +fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + debug!("builtin_derive_def_id({:?})", def_id); + if let Some(impl_def_id) = tcx.impl_of_method(def_id) { + if tcx.has_attr(impl_def_id, sym::automatically_derived) { + debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id); + Some(impl_def_id) + } else { + debug!("builtin_derive_def_id({:?}) - not automatically derived", def_id); + None + } + } else { + debug!("builtin_derive_def_id({:?}) - not a method", def_id); + None + } +} + +impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + // Make sure we know where in the MIR we are. + self.source_info = terminator.source_info; + self.super_terminator(terminator, location); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + // Make sure we know where in the MIR we are. + self.source_info = statement.source_info; + self.super_statement(statement, location); + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + if context.is_borrow() { + if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { + let def_id = self.body.source.instance.def_id(); + if let Some(impl_def_id) = builtin_derive_def_id(self.tcx, def_id) { + // If a method is defined in the local crate, + // the impl containing that method should also be. + self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); + } else { + let source_info = self.source_info; + let lint_root = self.body.source_scopes[source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + self.tcx.struct_span_lint_hir( + UNALIGNED_REFERENCES, + lint_root, + source_info.span, + |lint| { + lint.build("reference to packed field is unaligned") + .note( + "fields of packed structs are not properly aligned, and creating \ + a misaligned reference is undefined behavior (even if that \ + reference is never dereferenced)", + ) + .emit() + }, + ); + } + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_unsafety.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_unsafety.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_unsafety.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/check_unsafety.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,574 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::hir_id::HirId; +use rustc_hir::intravisit; +use rustc_hir::Node; +use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; +use rustc_session::lint::Level; + +use std::ops::Bound; + +pub struct UnsafetyChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + body_did: LocalDefId, + violations: Vec, + source_info: SourceInfo, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + /// Mark an `unsafe` block as used, so we don't lint it. + used_unsafe: FxHashSet, + inherited_blocks: Vec<(hir::HirId, bool)>, +} + +impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { + fn new( + body: &'a Body<'tcx>, + body_did: LocalDefId, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Self { + Self { + body, + body_did, + violations: vec![], + source_info: SourceInfo::outermost(body.span), + tcx, + param_env, + used_unsafe: Default::default(), + inherited_blocks: vec![], + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.source_info = terminator.source_info; + match terminator.kind { + TerminatorKind::Goto { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => { + // safe (at least as emitted during MIR construction) + } + + TerminatorKind::Call { ref func, .. } => { + let func_ty = func.ty(self.body, self.tcx); + let sig = func_ty.fn_sig(self.tcx); + if let hir::Unsafety::Unsafe = sig.unsafety() { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::CallToUnsafeFunction, + ) + } + + if let ty::FnDef(func_id, _) = func_ty.kind() { + self.check_target_features(*func_id); + } + } + + TerminatorKind::InlineAsm { .. } => self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::UseOfInlineAssembly, + ), + } + self.super_terminator(terminator, location); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + self.source_info = statement.source_info; + match statement.kind { + StatementKind::Assign(..) + | StatementKind::FakeRead(..) + | StatementKind::SetDiscriminant { .. } + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::Retag { .. } + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::Nop => { + // safe (at least as emitted during MIR construction) + } + + StatementKind::LlvmInlineAsm { .. } => self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::UseOfInlineAssembly, + ), + StatementKind::CopyNonOverlapping(..) => unreachable!(), + } + self.super_statement(statement, location); + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + match rvalue { + Rvalue::Aggregate(box ref aggregate, _) => match aggregate { + &AggregateKind::Array(..) | &AggregateKind::Tuple => {} + &AggregateKind::Adt(ref def, ..) => { + match self.tcx.layout_scalar_valid_range(def.did) { + (Bound::Unbounded, Bound::Unbounded) => {} + _ => self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::InitializingTypeWith, + ), + } + } + &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => { + let UnsafetyCheckResult { violations, unsafe_blocks } = + self.tcx.unsafety_check_result(def_id.expect_local()); + self.register_violations(&violations, &unsafe_blocks); + } + }, + _ => {} + } + self.super_rvalue(rvalue, location); + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + // On types with `scalar_valid_range`, prevent + // * `&mut x.field` + // * `x.field = y;` + // * `&x.field` if `field`'s type has interior mutability + // because either of these would allow modifying the layout constrained field and + // insert values that violate the layout constraints. + if context.is_mutating_use() || context.is_borrow() { + self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use()); + } + + // Some checks below need the extra metainfo of the local declaration. + let decl = &self.body.local_decls[place.local]; + + // Check the base local: it might be an unsafe-to-access static. We only check derefs of the + // temporary holding the static pointer to avoid duplicate errors + // . + if decl.internal && place.projection.first() == Some(&ProjectionElem::Deref) { + // If the projection root is an artifical local that we introduced when + // desugaring `static`, give a more specific error message + // (avoid the general "raw pointer" clause below, that would only be confusing). + if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { + if self.tcx.is_mutable_static(def_id) { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::UseOfMutableStatic, + ); + return; + } else if self.tcx.is_foreign_item(def_id) { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::UseOfExternStatic, + ); + return; + } + } + } + + // Check for raw pointer `Deref`. + for (base, proj) in place.iter_projections() { + if proj == ProjectionElem::Deref { + let base_ty = base.ty(self.body, self.tcx).ty; + if base_ty.is_unsafe_ptr() { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::DerefOfRawPointer, + ) + } + } + } + + // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes + // whether we *read* the union field or potentially *write* to it (if this place is being assigned to). + let mut saw_deref = false; + for (base, proj) in place.iter_projections().rev() { + if proj == ProjectionElem::Deref { + saw_deref = true; + continue; + } + + let base_ty = base.ty(self.body, self.tcx).ty; + if base_ty.is_union() { + // If we did not hit a `Deref` yet and the overall place use is an assignment, the + // rules are different. + let assign_to_field = !saw_deref + && matches!( + context, + PlaceContext::MutatingUse( + MutatingUseContext::Store + | MutatingUseContext::Drop + | MutatingUseContext::AsmOutput + ) + ); + // If this is just an assignment, determine if the assigned type needs dropping. + if assign_to_field { + // We have to check the actual type of the assignment, as that determines if the + // old value is being dropped. + let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; + // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. + let manually_drop = assigned_ty + .ty_adt_def() + .map_or(false, |adt_def| adt_def.is_manually_drop()); + let nodrop = manually_drop + || assigned_ty.is_copy_modulo_regions( + self.tcx.at(self.source_info.span), + self.param_env, + ); + if !nodrop { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::AssignToDroppingUnionField, + ); + } else { + // write to non-drop union field, safe + } + } else { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::AccessToUnionField, + ) + } + } + } + } +} + +impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { + fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) { + // Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such. + assert_ne!(kind, UnsafetyViolationKind::UnsafeFn); + + let source_info = self.source_info; + let lint_root = self.body.source_scopes[self.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + self.register_violations( + &[UnsafetyViolation { source_info, lint_root, kind, details }], + &[], + ); + } + + fn register_violations( + &mut self, + violations: &[UnsafetyViolation], + unsafe_blocks: &[(hir::HirId, bool)], + ) { + let safety = self.body.source_scopes[self.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .safety; + let within_unsafe = match safety { + // `unsafe` blocks are required in safe code + Safety::Safe => { + for violation in violations { + match violation.kind { + UnsafetyViolationKind::General => {} + UnsafetyViolationKind::UnsafeFn => { + bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") + } + } + if !self.violations.contains(violation) { + self.violations.push(*violation) + } + } + false + } + // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s + Safety::FnUnsafe => { + for violation in violations { + let mut violation = *violation; + + violation.kind = UnsafetyViolationKind::UnsafeFn; + if !self.violations.contains(&violation) { + self.violations.push(violation) + } + } + false + } + Safety::BuiltinUnsafe => true, + Safety::ExplicitUnsafe(hir_id) => { + // mark unsafe block as used if there are any unsafe operations inside + if !violations.is_empty() { + self.used_unsafe.insert(hir_id); + } + true + } + }; + self.inherited_blocks.extend( + unsafe_blocks.iter().map(|&(hir_id, is_used)| (hir_id, is_used && !within_unsafe)), + ); + } + fn check_mut_borrowing_layout_constrained_field( + &mut self, + place: Place<'tcx>, + is_mut_use: bool, + ) { + for (place_base, elem) in place.iter_projections().rev() { + match elem { + // Modifications behind a dereference don't affect the value of + // the pointer. + ProjectionElem::Deref => return, + ProjectionElem::Field(..) => { + let ty = place_base.ty(&self.body.local_decls, self.tcx).ty; + if let ty::Adt(def, _) = ty.kind() { + if self.tcx.layout_scalar_valid_range(def.did) + != (Bound::Unbounded, Bound::Unbounded) + { + let details = if is_mut_use { + UnsafetyViolationDetails::MutationOfLayoutConstrainedField + + // Check `is_freeze` as late as possible to avoid cycle errors + // with opaque types. + } else if !place + .ty(self.body, self.tcx) + .ty + .is_freeze(self.tcx.at(self.source_info.span), self.param_env) + { + UnsafetyViolationDetails::BorrowOfLayoutConstrainedField + } else { + continue; + }; + self.require_unsafe(UnsafetyViolationKind::General, details); + } + } + } + _ => {} + } + } + } + + /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether + /// the called function has target features the calling function hasn't. + fn check_target_features(&mut self, func_did: DefId) { + // Unsafety isn't required on wasm targets. For more information see + // the corresponding check in typeck/src/collect.rs + if self.tcx.sess.target.options.is_like_wasm { + return; + } + + let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; + let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features; + + // Is `callee_features` a subset of `calling_features`? + if !callee_features.iter().all(|feature| self_features.contains(feature)) { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::CallToFunctionWith, + ) + } + } +} + +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { + unsafety_check_result: |tcx, def_id| { + if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { + tcx.unsafety_check_result_for_const_arg(def) + } else { + unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id)) + } + }, + unsafety_check_result_for_const_arg: |tcx, (did, param_did)| { + unsafety_check_result( + tcx, + ty::WithOptConstParam { did, const_param_did: Some(param_did) }, + ) + }, + ..*providers + }; +} + +struct UnusedUnsafeVisitor<'a> { + used_unsafe: &'a FxHashSet, + unsafe_blocks: &'a mut Vec<(hir::HirId, bool)>, +} + +impl<'a, 'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a> { + type Map = intravisit::ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { + intravisit::walk_block(self, block); + + if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules { + self.unsafe_blocks.push((block.hir_id, self.used_unsafe.contains(&block.hir_id))); + } + } +} + +fn check_unused_unsafe( + tcx: TyCtxt<'_>, + def_id: LocalDefId, + used_unsafe: &FxHashSet, + unsafe_blocks: &mut Vec<(hir::HirId, bool)>, +) { + let body_id = tcx.hir().maybe_body_owned_by(tcx.hir().local_def_id_to_hir_id(def_id)); + + let body_id = match body_id { + Some(body) => body, + None => { + debug!("check_unused_unsafe({:?}) - no body found", def_id); + return; + } + }; + let body = tcx.hir().body(body_id); + debug!("check_unused_unsafe({:?}, body={:?}, used_unsafe={:?})", def_id, body, used_unsafe); + + let mut visitor = UnusedUnsafeVisitor { used_unsafe, unsafe_blocks }; + intravisit::Visitor::visit_body(&mut visitor, body); +} + +fn unsafety_check_result<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> &'tcx UnsafetyCheckResult { + debug!("unsafety_violations({:?})", def); + + // N.B., this borrow is valid because all the consumers of + // `mir_built` force this. + let body = &tcx.mir_built(def).borrow(); + + let param_env = tcx.param_env(def.did); + + let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env); + checker.visit_body(&body); + + check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks); + + tcx.arena.alloc(UnsafetyCheckResult { + violations: checker.violations.into(), + unsafe_blocks: checker.inherited_blocks.into(), + }) +} + +/// Returns the `HirId` for an enclosing scope that is also `unsafe`. +fn is_enclosed( + tcx: TyCtxt<'_>, + used_unsafe: &FxHashSet, + id: hir::HirId, + unsafe_op_in_unsafe_fn_allowed: bool, +) -> Option<(&'static str, hir::HirId)> { + let parent_id = tcx.hir().get_parent_node(id); + if parent_id != id { + if used_unsafe.contains(&parent_id) { + Some(("block", parent_id)) + } else if let Some(Node::Item(&hir::Item { + kind: hir::ItemKind::Fn(ref sig, _, _), .. + })) = tcx.hir().find(parent_id) + { + if sig.header.unsafety == hir::Unsafety::Unsafe && unsafe_op_in_unsafe_fn_allowed { + Some(("fn", parent_id)) + } else { + None + } + } else { + is_enclosed(tcx, used_unsafe, parent_id, unsafe_op_in_unsafe_fn_allowed) + } + } else { + None + } +} + +fn report_unused_unsafe(tcx: TyCtxt<'_>, used_unsafe: &FxHashSet, id: hir::HirId) { + let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id)); + tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, |lint| { + let msg = "unnecessary `unsafe` block"; + let mut db = lint.build(msg); + db.span_label(span, msg); + if let Some((kind, id)) = + is_enclosed(tcx, used_unsafe, id, unsafe_op_in_unsafe_fn_allowed(tcx, id)) + { + db.span_label( + tcx.sess.source_map().guess_head_span(tcx.hir().span(id)), + format!("because it's nested under this `unsafe` {}", kind), + ); + } + db.emit(); + }); +} + +pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { + debug!("check_unsafety({:?})", def_id); + + // closures are handled by their parent fn. + if tcx.is_closure(def_id.to_def_id()) { + return; + } + + let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id); + + for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() { + let (description, note) = details.description_and_note(); + + // Report an error. + let unsafe_fn_msg = + if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" }; + + match kind { + UnsafetyViolationKind::General => { + // once + struct_span_err!( + tcx.sess, + source_info.span, + E0133, + "{} is unsafe and requires unsafe{} block", + description, + unsafe_fn_msg, + ) + .span_label(source_info.span, description) + .note(note) + .emit(); + } + UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir( + UNSAFE_OP_IN_UNSAFE_FN, + lint_root, + source_info.span, + |lint| { + lint.build(&format!( + "{} is unsafe and requires unsafe block (error E0133)", + description, + )) + .span_label(source_info.span, description) + .note(note) + .emit(); + }, + ), + } + } + + let (mut unsafe_used, mut unsafe_unused): (FxHashSet<_>, Vec<_>) = Default::default(); + for &(block_id, is_used) in unsafe_blocks.iter() { + if is_used { + unsafe_used.insert(block_id); + } else { + unsafe_unused.push(block_id); + } + } + // The unused unsafe blocks might not be in source order; sort them so that the unused unsafe + // error messages are properly aligned and the issue-45107 and lint-unused-unsafe tests pass. + unsafe_unused.sort_by_cached_key(|hir_id| tcx.hir().span(*hir_id)); + + for &block_id in &unsafe_unused { + report_unused_unsafe(tcx, &unsafe_used, block_id); + } +} + +fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool { + tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,59 @@ +//! This module provides a pass to replacing the following statements with +//! [`Nop`]s +//! +//! - [`AscribeUserType`] +//! - [`FakeRead`] +//! - [`Assign`] statements with a [`Shallow`] borrow +//! +//! The `CleanFakeReadsAndBorrows` "pass" is actually implemented as two +//! traversals (aka visits) of the input MIR. The first traversal, +//! `DeleteAndRecordFakeReads`, deletes the fake reads and finds the +//! temporaries read by [`ForMatchGuard`] reads, and `DeleteFakeBorrows` +//! deletes the initialization of those temporaries. +//! +//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType +//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow +//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead +//! [`Assign`]: rustc_middle::mir::StatementKind::Assign +//! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard +//! [`Nop`]: rustc_middle::mir::StatementKind::Nop + +use crate::MirPass; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue}; +use rustc_middle::mir::{Statement, StatementKind}; +use rustc_middle::ty::TyCtxt; + +pub struct CleanupNonCodegenStatements; + +pub struct DeleteNonCodegenStatements<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut delete = DeleteNonCodegenStatements { tcx }; + delete.visit_body(body); + body.user_type_annotations.raw.clear(); + + for decl in &mut body.local_decls { + decl.user_ty = None; + } + } +} + +impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + match statement.kind { + StatementKind::AscribeUserType(..) + | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _))) + | StatementKind::FakeRead(..) => statement.make_nop(), + _ => (), + } + self.super_statement(statement, location); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_debuginfo.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_debuginfo.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_debuginfo.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_debuginfo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,102 @@ +//! Finds locals which are assigned once to a const and unused except for debuginfo and converts +//! their debuginfo to use the const directly, allowing the local to be removed. + +use rustc_middle::{ + mir::{ + visit::{PlaceContext, Visitor}, + Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, + }, + ty::TyCtxt, +}; + +use crate::MirPass; +use rustc_index::{bit_set::BitSet, vec::IndexVec}; + +pub struct ConstDebugInfo; + +impl<'tcx> MirPass<'tcx> for ConstDebugInfo { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + + trace!("running ConstDebugInfo on {:?}", body.source); + + for (local, constant) in find_optimization_oportunities(body) { + for debuginfo in &mut body.var_debug_info { + if let VarDebugInfoContents::Place(p) = debuginfo.value { + if p.local == local && p.projection.is_empty() { + trace!( + "changing debug info for {:?} from place {:?} to constant {:?}", + debuginfo.name, + p, + constant + ); + debuginfo.value = VarDebugInfoContents::Const(constant); + } + } + } + } + } +} + +struct LocalUseVisitor { + local_mutating_uses: IndexVec, + local_assignment_locations: IndexVec>, +} + +fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> { + let mut visitor = LocalUseVisitor { + local_mutating_uses: IndexVec::from_elem(0, &body.local_decls), + local_assignment_locations: IndexVec::from_elem(None, &body.local_decls), + }; + + visitor.visit_body(body); + + let mut locals_to_debuginfo = BitSet::new_empty(body.local_decls.len()); + for debuginfo in &body.var_debug_info { + if let VarDebugInfoContents::Place(p) = debuginfo.value { + if let Some(l) = p.as_local() { + locals_to_debuginfo.insert(l); + } + } + } + + let mut eligable_locals = Vec::new(); + for (local, mutating_uses) in visitor.local_mutating_uses.drain_enumerated(..) { + if mutating_uses != 1 || !locals_to_debuginfo.contains(local) { + continue; + } + + if let Some(location) = visitor.local_assignment_locations[local] { + let bb = &body[location.block]; + + // The value is assigned as the result of a call, not a constant + if bb.statements.len() == location.statement_index { + continue; + } + + if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(box c)))) = + &bb.statements[location.statement_index].kind + { + if let Some(local) = p.as_local() { + eligable_locals.push((local, *c)); + } + } + } + } + + eligable_locals +} + +impl<'tcx> Visitor<'tcx> for LocalUseVisitor { + fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + if context.is_mutating_use() { + self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1); + + if context.is_place_assignment() { + self.local_assignment_locations[*local] = Some(location); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_goto.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_goto.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_goto.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_goto.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,122 @@ +//! This pass optimizes the following sequence +//! ```rust,ignore (example) +//! bb2: { +//! _2 = const true; +//! goto -> bb3; +//! } +//! +//! bb3: { +//! switchInt(_2) -> [false: bb4, otherwise: bb5]; +//! } +//! ``` +//! into +//! ```rust,ignore (example) +//! bb2: { +//! _2 = const true; +//! goto -> bb5; +//! } +//! ``` + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_middle::{mir::visit::Visitor, ty::ParamEnv}; + +use super::simplify::{simplify_cfg, simplify_locals}; + +pub struct ConstGoto; + +impl<'tcx> MirPass<'tcx> for ConstGoto { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.mir_opt_level() < 4 { + return; + } + trace!("Running ConstGoto on {:?}", body.source); + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let mut opt_finder = + ConstGotoOptimizationFinder { tcx, body, optimizations: vec![], param_env }; + opt_finder.visit_body(body); + let should_simplify = !opt_finder.optimizations.is_empty(); + for opt in opt_finder.optimizations { + let terminator = body.basic_blocks_mut()[opt.bb_with_goto].terminator_mut(); + let new_goto = TerminatorKind::Goto { target: opt.target_to_use_in_goto }; + debug!("SUCCESS: replacing `{:?}` with `{:?}`", terminator.kind, new_goto); + terminator.kind = new_goto; + } + + // if we applied optimizations, we potentially have some cfg to cleanup to + // make it easier for further passes + if should_simplify { + simplify_cfg(tcx, body); + simplify_locals(body, tcx); + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + let _: Option<_> = try { + let target = terminator.kind.as_goto()?; + // We only apply this optimization if the last statement is a const assignment + let last_statement = self.body.basic_blocks()[location.block].statements.last()?; + + if let (place, Rvalue::Use(Operand::Constant(_const))) = + last_statement.kind.as_assign()? + { + // We found a constant being assigned to `place`. + // Now check that the target of this Goto switches on this place. + let target_bb = &self.body.basic_blocks()[target]; + + // FIXME(simonvandel): We are conservative here when we don't allow + // any statements in the target basic block. + // This could probably be relaxed to allow `StorageDead`s which could be + // copied to the predecessor of this block. + if !target_bb.statements.is_empty() { + None? + } + + let target_bb_terminator = target_bb.terminator(); + let (discr, switch_ty, targets) = target_bb_terminator.kind.as_switch()?; + if discr.place() == Some(*place) { + // We now know that the Switch matches on the const place, and it is statementless + // Now find which value in the Switch matches the const value. + let const_value = + _const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?; + let found_value_idx_option = targets + .iter() + .enumerate() + .find(|(_, (value, _))| const_value == *value) + .map(|(idx, _)| idx); + + let target_to_use_in_goto = + if let Some(found_value_idx) = found_value_idx_option { + targets.iter().nth(found_value_idx).unwrap().1 + } else { + // If we did not find the const value in values, it must be the otherwise case + targets.otherwise() + }; + + self.optimizations.push(OptimizationToApply { + bb_with_goto: location.block, + target_to_use_in_goto, + }); + } + } + Some(()) + }; + + self.super_terminator(terminator, location); + } +} + +struct OptimizationToApply { + bb_with_goto: BasicBlock, + target_to_use_in_goto: BasicBlock, +} + +pub struct ConstGotoOptimizationFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + param_env: ParamEnv<'tcx>, + optimizations: Vec, +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_prop.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_prop.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_prop.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/const_prop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1313 @@ +//! Propagates constants for early reporting of statically known +//! assertion failures + +use std::cell::Cell; + +use rustc_ast::Mutability; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def::DefKind; +use rustc_hir::HirId; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::{ + MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, +}; +use rustc_middle::mir::{ + AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind, + Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, + StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, +}; +use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::{ + self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable, +}; +use rustc_session::lint; +use rustc_span::{def_id::DefId, Span}; +use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; +use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits; + +use crate::MirPass; +use rustc_const_eval::const_eval::ConstEvalErr; +use rustc_const_eval::interpret::{ + self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy, + Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy, + Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind, +}; + +/// The maximum number of bytes that we'll allocate space for a local or the return value. +/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just +/// Severely regress performance. +const MAX_ALLOC_LIMIT: u64 = 1024; + +/// Macro for machine-specific `InterpError` without allocation. +/// (These will never be shown to the user, but they help diagnose ICEs.) +macro_rules! throw_machine_stop_str { + ($($tt:tt)*) => {{ + // We make a new local type for it. The type itself does not carry any information, + // but its vtable (for the `MachineStopType` trait) does. + struct Zst; + // Printing this type shows the desired string. + impl std::fmt::Display for Zst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, $($tt)*) + } + } + impl rustc_middle::mir::interpret::MachineStopType for Zst {} + throw_machine_stop!(Zst) + }}; +} + +pub struct ConstProp; + +impl<'tcx> MirPass<'tcx> for ConstProp { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // will be evaluated by miri and produce its errors there + if body.source.promoted.is_some() { + return; + } + + use rustc_middle::hir::map::blocks::FnLikeNode; + let def_id = body.source.def_id().expect_local(); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + + let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst; + + // Only run const prop on functions, methods, closures and associated constants + if !is_fn_like && !is_assoc_const { + // skip anon_const/statics/consts because they'll be evaluated by miri anyway + trace!("ConstProp skipped for {:?}", def_id); + return; + } + + let is_generator = tcx.type_of(def_id.to_def_id()).is_generator(); + // FIXME(welseywiser) const prop doesn't work on generators because of query cycles + // computing their layout. + if is_generator { + trace!("ConstProp skipped for generator {:?}", def_id); + return; + } + + // Check if it's even possible to satisfy the 'where' clauses + // for this item. + // This branch will never be taken for any normal function. + // However, it's possible to `#!feature(trivial_bounds)]` to write + // a function with impossible to satisfy clauses, e.g.: + // `fn foo() where String: Copy {}` + // + // We don't usually need to worry about this kind of case, + // since we would get a compilation error if the user tried + // to call it. However, since we can do const propagation + // even without any calls to the function, we need to make + // sure that it even makes sense to try to evaluate the body. + // If there are unsatisfiable where clauses, then all bets are + // off, and we just give up. + // + // We manually filter the predicates, skipping anything that's not + // "global". We are in a potentially generic context + // (e.g. we are evaluating a function without substituting generic + // parameters, so this filtering serves two purposes: + // + // 1. We skip evaluating any predicates that we would + // never be able prove are unsatisfiable (e.g. `` + // 2. We avoid trying to normalize predicates involving generic + // parameters (e.g. `::MyItem`). This can confuse + // the normalization code (leading to cycle errors), since + // it's usually never invoked in this way. + let predicates = tcx + .predicates_of(def_id.to_def_id()) + .predicates + .iter() + .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None }); + if traits::impossible_predicates( + tcx, + traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(), + ) { + trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id); + return; + } + + trace!("ConstProp starting for {:?}", def_id); + + let dummy_body = &Body::new( + tcx, + body.source, + body.basic_blocks().clone(), + body.source_scopes.clone(), + body.local_decls.clone(), + Default::default(), + body.arg_count, + Default::default(), + body.span, + body.generator_kind(), + ); + + // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold + // constants, instead of just checking for const-folding succeeding. + // That would require a uniform one-def no-mutation analysis + // and RPO (or recursing when needing the value of a local). + let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx); + optimization_finder.visit_body(body); + + trace!("ConstProp done for {:?}", def_id); + } +} + +struct ConstPropMachine<'mir, 'tcx> { + /// The virtual call stack. + stack: Vec>, + /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end. + written_only_inside_own_block_locals: FxHashSet, + /// Locals that need to be cleared after every block terminates. + only_propagate_inside_block_locals: BitSet, + can_const_prop: IndexVec, +} + +impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { + fn new( + only_propagate_inside_block_locals: BitSet, + can_const_prop: IndexVec, + ) -> Self { + Self { + stack: Vec::new(), + written_only_inside_own_block_locals: Default::default(), + only_propagate_inside_block_locals, + can_const_prop, + } + } +} + +impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { + compile_time_machine!(<'mir, 'tcx>); + const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`) + + type MemoryKind = !; + + type MemoryExtra = (); + + fn load_mir( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _instance: ty::InstanceDef<'tcx>, + ) -> InterpResult<'tcx, &'tcx Body<'tcx>> { + throw_machine_stop_str!("calling functions isn't supported in ConstProp") + } + + fn find_mir_or_eval_fn( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _abi: Abi, + _args: &[OpTy<'tcx>], + _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, + _unwind: StackPopUnwind, + ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> { + Ok(None) + } + + fn call_intrinsic( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _args: &[OpTy<'tcx>], + _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, + _unwind: StackPopUnwind, + ) -> InterpResult<'tcx> { + throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") + } + + fn assert_panic( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _msg: &rustc_middle::mir::AssertMessage<'tcx>, + _unwind: Option, + ) -> InterpResult<'tcx> { + bug!("panics terminators are not evaluated in ConstProp") + } + + fn binary_ptr_op( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _bin_op: BinOp, + _left: &ImmTy<'tcx>, + _right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + // We can't do this because aliasing of memory can differ between const eval and llvm + throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") + } + + fn box_alloc( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _dest: &PlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + throw_machine_stop_str!("can't const prop heap allocations") + } + + fn access_local( + _ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: Local, + ) -> InterpResult<'tcx, InterpOperand> { + let l = &frame.locals[local]; + + if l.value == LocalValue::Uninitialized { + throw_machine_stop_str!("tried to access an uninitialized local") + } + + l.access() + } + + fn access_local_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + frame: usize, + local: Local, + ) -> InterpResult<'tcx, Result<&'a mut LocalValue, MemPlace>> + { + if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { + throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") + } + if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) { + trace!( + "mutating local {:?} which is restricted to its block. \ + Will remove it from const-prop after block is finished.", + local + ); + ecx.machine.written_only_inside_own_block_locals.insert(local); + } + ecx.machine.stack[frame].locals[local].access_mut() + } + + fn before_access_global( + _memory_extra: &(), + _alloc_id: AllocId, + allocation: &Allocation, + _static_def_id: Option, + is_write: bool, + ) -> InterpResult<'tcx> { + if is_write { + throw_machine_stop_str!("can't write to global"); + } + // If the static allocation is mutable, then we can't const prop it as its content + // might be different at runtime. + if allocation.mutability == Mutability::Mut { + throw_machine_stop_str!("can't access mutable globals in ConstProp"); + } + + Ok(()) + } + + #[inline(always)] + fn init_frame_extra( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + frame: Frame<'mir, 'tcx>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { + Ok(frame) + } + + #[inline(always)] + fn stack( + ecx: &'a InterpCx<'mir, 'tcx, Self>, + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + &ecx.machine.stack + } + + #[inline(always)] + fn stack_mut( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + ) -> &'a mut Vec> { + &mut ecx.machine.stack + } +} + +/// Finds optimization opportunities on the MIR. +struct ConstPropagator<'mir, 'tcx> { + ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + // FIXME(eddyb) avoid cloning these two fields more than once, + // by accessing them through `ecx` instead. + source_scopes: IndexVec>, + local_decls: IndexVec>, + // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store + // the last known `SourceInfo` here and just keep revisiting it. + source_info: Option, +} + +impl<'mir, 'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'mir, 'tcx> { + type LayoutOfResult = Result, LayoutError<'tcx>>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> { + err + } +} + +impl<'mir, 'tcx> HasDataLayout for ConstPropagator<'mir, 'tcx> { + #[inline] + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'mir, 'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> { + #[inline] + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl<'mir, 'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'mir, 'tcx> { + #[inline] + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } +} + +impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { + fn new( + body: &Body<'tcx>, + dummy_body: &'mir Body<'tcx>, + tcx: TyCtxt<'tcx>, + ) -> ConstPropagator<'mir, 'tcx> { + let def_id = body.source.def_id(); + let substs = &InternalSubsts::identity_for_item(tcx, def_id); + let param_env = tcx.param_env_reveal_all_normalized(def_id); + + let span = tcx.def_span(def_id); + // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts + // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in + // `layout_of` query invocations. + let can_const_prop = CanConstProp::check(tcx, param_env, body); + let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len()); + for (l, mode) in can_const_prop.iter_enumerated() { + if *mode == ConstPropMode::OnlyInsideOwnBlock { + only_propagate_inside_block_locals.insert(l); + } + } + let mut ecx = InterpCx::new( + tcx, + span, + param_env, + ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop), + (), + ); + + let ret = ecx + .layout_of(body.return_ty().subst(tcx, substs)) + .ok() + // Don't bother allocating memory for ZST types which have no values + // or for large values. + .filter(|ret_layout| { + !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) + }) + .map(|ret_layout| { + ecx.allocate(ret_layout, MemoryKind::Stack) + .expect("couldn't perform small allocation") + .into() + }); + + ecx.push_stack_frame( + Instance::new(def_id, substs), + dummy_body, + ret.as_ref(), + StackPopCleanup::None { cleanup: false }, + ) + .expect("failed to push initial stack frame"); + + ConstPropagator { + ecx, + tcx, + param_env, + // FIXME(eddyb) avoid cloning these two fields more than once, + // by accessing them through `ecx` instead. + source_scopes: body.source_scopes.clone(), + //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it + local_decls: body.local_decls.clone(), + source_info: None, + } + } + + fn get_const(&self, place: Place<'tcx>) -> Option> { + let op = match self.ecx.eval_place_to_op(place, None) { + Ok(op) => op, + Err(e) => { + trace!("get_const failed: {}", e); + return None; + } + }; + + // Try to read the local as an immediate so that if it is representable as a scalar, we can + // handle it as such, but otherwise, just return the value as is. + Some(match self.ecx.try_read_immediate(&op) { + Ok(Ok(imm)) => imm.into(), + _ => op, + }) + } + + /// Remove `local` from the pool of `Locals`. Allows writing to them, + /// but not reading from them anymore. + fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { + ecx.frame_mut().locals[local] = + LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) }; + } + + fn lint_root(&self, source_info: SourceInfo) -> Option { + source_info.scope.lint_root(&self.source_scopes) + } + + fn use_ecx(&mut self, f: F) -> Option + where + F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, + { + match f(self) { + Ok(val) => Some(val), + Err(error) => { + trace!("InterpCx operation failed: {:?}", error); + // Some errors shouldn't come up because creating them causes + // an allocation, which we should avoid. When that happens, + // dedicated error variants should be introduced instead. + assert!( + !error.kind().formatted_string(), + "const-prop encountered formatting error: {}", + error + ); + None + } + } + } + + /// Returns the value, if any, of evaluating `c`. + fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option> { + // FIXME we need to revisit this for #67176 + if c.definitely_needs_subst(self.tcx) { + return None; + } + + match self.ecx.mir_const_to_op(&c.literal, None) { + Ok(op) => Some(op), + Err(error) => { + let tcx = self.ecx.tcx.at(c.span); + let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); + if let Some(lint_root) = self.lint_root(source_info) { + let lint_only = match c.literal { + ConstantKind::Ty(ct) => match ct.val { + // Promoteds must lint and not error as the user didn't ask for them + ConstKind::Unevaluated(ty::Unevaluated { + def: _, + substs_: _, + promoted: Some(_), + }) => true, + // Out of backwards compatibility we cannot report hard errors in unused + // generic functions using associated constants of the generic parameters. + _ => c.literal.definitely_needs_subst(*tcx), + }, + ConstantKind::Val(_, ty) => ty.definitely_needs_subst(*tcx), + }; + if lint_only { + // Out of backwards compatibility we cannot report hard errors in unused + // generic functions using associated constants of the generic parameters. + err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span)); + } else { + err.report_as_error(tcx, "erroneous constant used"); + } + } else { + err.report_as_error(tcx, "erroneous constant used"); + } + None + } + } + } + + /// Returns the value, if any, of evaluating `place`. + fn eval_place(&mut self, place: Place<'tcx>) -> Option> { + trace!("eval_place(place={:?})", place); + self.use_ecx(|this| this.ecx.eval_place_to_op(place, None)) + } + + /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant` + /// or `eval_place`, depending on the variant of `Operand` used. + fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { + match *op { + Operand::Constant(ref c) => self.eval_constant(c, source_info), + Operand::Move(place) | Operand::Copy(place) => self.eval_place(place), + } + } + + fn report_assert_as_lint( + &self, + lint: &'static lint::Lint, + source_info: SourceInfo, + message: &'static str, + panic: AssertKind, + ) { + if let Some(lint_root) = self.lint_root(source_info) { + self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| { + let mut err = lint.build(message); + err.span_label(source_info.span, format!("{:?}", panic)); + err.emit() + }); + } + } + + fn check_unary_op( + &mut self, + op: UnOp, + arg: &Operand<'tcx>, + source_info: SourceInfo, + ) -> Option<()> { + if let (val, true) = self.use_ecx(|this| { + let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?; + let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?; + Ok((val, overflow)) + })? { + // `AssertKind` only has an `OverflowNeg` variant, so make sure that is + // appropriate to use. + assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::OverflowNeg(val.to_const_int()), + ); + return None; + } + + Some(()) + } + + fn check_binary_op( + &mut self, + op: BinOp, + left: &Operand<'tcx>, + right: &Operand<'tcx>, + source_info: SourceInfo, + ) -> Option<()> { + let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?)); + let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?)); + // Check for exceeding shifts *even if* we cannot evaluate the LHS. + if op == BinOp::Shr || op == BinOp::Shl { + let r = r?; + // We need the type of the LHS. We cannot use `place_layout` as that is the type + // of the result, which for checked binops is not the same! + let left_ty = left.ty(&self.local_decls, self.tcx); + let left_size = self.ecx.layout_of(left_ty).ok()?.size; + let right_size = r.layout.size; + let r_bits = r.to_scalar().ok(); + let r_bits = r_bits.and_then(|r| r.to_bits(right_size).ok()); + if r_bits.map_or(false, |b| b >= left_size.bits() as u128) { + debug!("check_binary_op: reporting assert for {:?}", source_info); + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::Overflow( + op, + match l { + Some(l) => l.to_const_int(), + // Invent a dummy value, the diagnostic ignores it anyway + None => ConstInt::new( + ScalarInt::try_from_uint(1_u8, left_size).unwrap(), + left_ty.is_signed(), + left_ty.is_ptr_sized_integral(), + ), + }, + r.to_const_int(), + ), + ); + return None; + } + } + + if let (Some(l), Some(r)) = (&l, &r) { + // The remaining operators are handled through `overflowing_binary_op`. + if self.use_ecx(|this| { + let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?; + Ok(overflow) + })? { + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), + ); + return None; + } + } + Some(()) + } + + fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) { + match *operand { + Operand::Copy(l) | Operand::Move(l) => { + if let Some(value) = self.get_const(l) { + if self.should_const_prop(&value) { + // FIXME(felix91gr): this code only handles `Scalar` cases. + // For now, we're not handling `ScalarPair` cases because + // doing so here would require a lot of code duplication. + // We should hopefully generalize `Operand` handling into a fn, + // and use it to do const-prop here and everywhere else + // where it makes sense. + if let interpret::Operand::Immediate(interpret::Immediate::Scalar( + ScalarMaybeUninit::Scalar(scalar), + )) = *value + { + *operand = self.operand_from_scalar( + scalar, + value.layout.ty, + self.source_info.unwrap().span, + ); + } + } + } + } + Operand::Constant(_) => (), + } + } + + fn const_prop( + &mut self, + rvalue: &Rvalue<'tcx>, + source_info: SourceInfo, + place: Place<'tcx>, + ) -> Option<()> { + // Perform any special handling for specific Rvalue types. + // Generally, checks here fall into one of two categories: + // 1. Additional checking to provide useful lints to the user + // - In this case, we will do some validation and then fall through to the + // end of the function which evals the assignment. + // 2. Working around bugs in other parts of the compiler + // - In this case, we'll return `None` from this function to stop evaluation. + match rvalue { + // Additional checking: give lints to the user if an overflow would occur. + // We do this here and not in the `Assert` terminator as that terminator is + // only sometimes emitted (overflow checks can be disabled), but we want to always + // lint. + Rvalue::UnaryOp(op, arg) => { + trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); + self.check_unary_op(*op, arg, source_info)?; + } + Rvalue::BinaryOp(op, box (left, right)) => { + trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); + self.check_binary_op(*op, left, right, source_info)?; + } + Rvalue::CheckedBinaryOp(op, box (left, right)) => { + trace!( + "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})", + op, + left, + right + ); + self.check_binary_op(*op, left, right, source_info)?; + } + + // Do not try creating references (#67862) + Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => { + trace!("skipping AddressOf | Ref for {:?}", place); + + // This may be creating mutable references or immutable references to cells. + // If that happens, the pointed to value could be mutated via that reference. + // Since we aren't tracking references, the const propagator loses track of what + // value the local has right now. + // Thus, all locals that have their reference taken + // must not take part in propagation. + Self::remove_const(&mut self.ecx, place.local); + + return None; + } + Rvalue::ThreadLocalRef(def_id) => { + trace!("skipping ThreadLocalRef({:?})", def_id); + + return None; + } + + // There's no other checking to do at this time. + Rvalue::Aggregate(..) + | Rvalue::Use(..) + | Rvalue::Repeat(..) + | Rvalue::Len(..) + | Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) + | Rvalue::Discriminant(..) + | Rvalue::NullaryOp(..) => {} + } + + // FIXME we need to revisit this for #67176 + if rvalue.definitely_needs_subst(self.tcx) { + return None; + } + + if self.tcx.sess.mir_opt_level() >= 4 { + self.eval_rvalue_with_identities(rvalue, place) + } else { + self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place)) + } + } + + // Attempt to use albegraic identities to eliminate constant expressions + fn eval_rvalue_with_identities( + &mut self, + rvalue: &Rvalue<'tcx>, + place: Place<'tcx>, + ) -> Option<()> { + self.use_ecx(|this| { + match rvalue { + Rvalue::BinaryOp(op, box (left, right)) + | Rvalue::CheckedBinaryOp(op, box (left, right)) => { + let l = this.ecx.eval_operand(left, None); + let r = this.ecx.eval_operand(right, None); + + let const_arg = match (l, r) { + (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?, + (Err(e), Err(_)) => return Err(e), + (Ok(_), Ok(_)) => { + this.ecx.eval_rvalue_into_place(rvalue, place)?; + return Ok(()); + } + }; + + let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?; + let dest = this.ecx.eval_place(place)?; + + match op { + BinOp::BitAnd => { + if arg_value == 0 { + this.ecx.write_immediate(*const_arg, &dest)?; + } + } + BinOp::BitOr => { + if arg_value == const_arg.layout.size.truncate(u128::MAX) + || (const_arg.layout.ty.is_bool() && arg_value == 1) + { + this.ecx.write_immediate(*const_arg, &dest)?; + } + } + BinOp::Mul => { + if const_arg.layout.ty.is_integral() && arg_value == 0 { + if let Rvalue::CheckedBinaryOp(_, _) = rvalue { + let val = Immediate::ScalarPair( + const_arg.to_scalar()?.into(), + Scalar::from_bool(false).into(), + ); + this.ecx.write_immediate(val, &dest)?; + } else { + this.ecx.write_immediate(*const_arg, &dest)?; + } + } + } + _ => { + this.ecx.eval_rvalue_into_place(rvalue, place)?; + } + } + } + _ => { + this.ecx.eval_rvalue_into_place(rvalue, place)?; + } + } + + Ok(()) + }) + } + + /// Creates a new `Operand::Constant` from a `Scalar` value + fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> { + Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: ty::Const::from_scalar(self.tcx, scalar, ty).into(), + })) + } + + fn replace_with_const( + &mut self, + rval: &mut Rvalue<'tcx>, + value: &OpTy<'tcx>, + source_info: SourceInfo, + ) { + if let Rvalue::Use(Operand::Constant(c)) = rval { + match c.literal { + ConstantKind::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {} + _ => { + trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); + return; + } + } + } + + trace!("attempting to replace {:?} with {:?}", rval, value); + if let Err(e) = self.ecx.const_validate_operand( + value, + vec![], + // FIXME: is ref tracking too expensive? + // FIXME: what is the point of ref tracking if we do not even check the tracked refs? + &mut interpret::RefTracking::empty(), + CtfeValidationMode::Regular, + ) { + trace!("validation error, attempt failed: {:?}", e); + return; + } + + // FIXME> figure out what to do when try_read_immediate fails + let imm = self.use_ecx(|this| this.ecx.try_read_immediate(value)); + + if let Some(Ok(imm)) = imm { + match *imm { + interpret::Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar)) => { + *rval = Rvalue::Use(self.operand_from_scalar( + scalar, + value.layout.ty, + source_info.span, + )); + } + Immediate::ScalarPair( + ScalarMaybeUninit::Scalar(_), + ScalarMaybeUninit::Scalar(_), + ) => { + // Found a value represented as a pair. For now only do const-prop if the type + // of `rvalue` is also a tuple with two scalars. + // FIXME: enable the general case stated above ^. + let ty = &value.layout.ty; + // Only do it for tuples + if let ty::Tuple(substs) = ty.kind() { + // Only do it if tuple is also a pair with two scalars + if substs.len() == 2 { + let alloc = self.use_ecx(|this| { + let ty1 = substs[0].expect_ty(); + let ty2 = substs[1].expect_ty(); + let ty_is_scalar = |ty| { + this.ecx.layout_of(ty).ok().map(|layout| layout.abi.is_scalar()) + == Some(true) + }; + if ty_is_scalar(ty1) && ty_is_scalar(ty2) { + let alloc = this + .ecx + .intern_with_temp_alloc(value.layout, |ecx, dest| { + ecx.write_immediate(*imm, dest) + }) + .unwrap(); + Ok(Some(alloc)) + } else { + Ok(None) + } + }); + + if let Some(Some(alloc)) = alloc { + // Assign entire constant in a single statement. + // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`. + *rval = Rvalue::Use(Operand::Constant(Box::new(Constant { + span: source_info.span, + user_ty: None, + literal: self + .ecx + .tcx + .mk_const(ty::Const { + ty, + val: ty::ConstKind::Value(ConstValue::ByRef { + alloc, + offset: Size::ZERO, + }), + }) + .into(), + }))); + } + } + } + } + // Scalars or scalar pairs that contain undef values are assumed to not have + // successfully evaluated and are thus not propagated. + _ => {} + } + } + } + + /// Returns `true` if and only if this `op` should be const-propagated into. + fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool { + let mir_opt_level = self.tcx.sess.mir_opt_level(); + + if mir_opt_level == 0 { + return false; + } + + if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - OpTy: {:?}", op)) { + return false; + } + + match **op { + interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => { + s.try_to_int().is_ok() + } + interpret::Operand::Immediate(Immediate::ScalarPair( + ScalarMaybeUninit::Scalar(l), + ScalarMaybeUninit::Scalar(r), + )) => l.try_to_int().is_ok() && r.try_to_int().is_ok(), + _ => false, + } + } +} + +/// The mode that `ConstProp` is allowed to run in for a given `Local`. +#[derive(Clone, Copy, Debug, PartialEq)] +enum ConstPropMode { + /// The `Local` can be propagated into and reads of this `Local` can also be propagated. + FullConstProp, + /// The `Local` can only be propagated into and from its own block. + OnlyInsideOwnBlock, + /// The `Local` can be propagated into but reads cannot be propagated. + OnlyPropagateInto, + /// The `Local` cannot be part of propagation at all. Any statement + /// referencing it either for reading or writing will not get propagated. + NoPropagation, +} + +struct CanConstProp { + can_const_prop: IndexVec, + // False at the beginning. Once set, no more assignments are allowed to that local. + found_assignment: BitSet, + // Cache of locals' information + local_kinds: IndexVec, +} + +impl CanConstProp { + /// Returns true if `local` can be propagated + fn check( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + body: &Body<'tcx>, + ) -> IndexVec { + let mut cpv = CanConstProp { + can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls), + found_assignment: BitSet::new_empty(body.local_decls.len()), + local_kinds: IndexVec::from_fn_n( + |local| body.local_kind(local), + body.local_decls.len(), + ), + }; + for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { + let ty = body.local_decls[local].ty; + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} + // Either the layout fails to compute, then we can't use this local anyway + // or the local is too large, then we don't want to. + _ => { + *val = ConstPropMode::NoPropagation; + continue; + } + } + // Cannot use args at all + // Cannot use locals because if x < y { y - x } else { x - y } would + // lint for x != y + // FIXME(oli-obk): lint variables until they are used in a condition + // FIXME(oli-obk): lint if return value is constant + if cpv.local_kinds[local] == LocalKind::Arg { + *val = ConstPropMode::OnlyPropagateInto; + trace!( + "local {:?} can't be const propagated because it's a function argument", + local + ); + } else if cpv.local_kinds[local] == LocalKind::Var { + *val = ConstPropMode::OnlyInsideOwnBlock; + trace!( + "local {:?} will only be propagated inside its block, because it's a user variable", + local + ); + } + } + cpv.visit_body(&body); + cpv.can_const_prop + } +} + +impl<'tcx> Visitor<'tcx> for CanConstProp { + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + use rustc_middle::mir::visit::PlaceContext::*; + match context { + // Projections are fine, because `&mut foo.x` will be caught by + // `MutatingUseContext::Borrow` elsewhere. + MutatingUse(MutatingUseContext::Projection) + // These are just stores, where the storing is not propagatable, but there may be later + // mutations of the same local via `Store` + | MutatingUse(MutatingUseContext::Call) + // Actual store that can possibly even propagate a value + | MutatingUse(MutatingUseContext::Store) => { + if !self.found_assignment.insert(local) { + match &mut self.can_const_prop[local] { + // If the local can only get propagated in its own block, then we don't have + // to worry about multiple assignments, as we'll nuke the const state at the + // end of the block anyway, and inside the block we overwrite previous + // states as applicable. + ConstPropMode::OnlyInsideOwnBlock => {} + ConstPropMode::NoPropagation => {} + ConstPropMode::OnlyPropagateInto => {} + other @ ConstPropMode::FullConstProp => { + trace!( + "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}", + local, other, + ); + *other = ConstPropMode::OnlyInsideOwnBlock; + } + } + } + } + // Reading constants is allowed an arbitrary number of times + NonMutatingUse(NonMutatingUseContext::Copy) + | NonMutatingUse(NonMutatingUseContext::Move) + | NonMutatingUse(NonMutatingUseContext::Inspect) + | NonMutatingUse(NonMutatingUseContext::Projection) + | NonUse(_) => {} + + // These could be propagated with a smarter analysis or just some careful thinking about + // whether they'd be fine right now. + MutatingUse(MutatingUseContext::AsmOutput) + | MutatingUse(MutatingUseContext::Yield) + | MutatingUse(MutatingUseContext::Drop) + | MutatingUse(MutatingUseContext::Retag) + // These can't ever be propagated under any scheme, as we can't reason about indirect + // mutation. + | NonMutatingUse(NonMutatingUseContext::SharedBorrow) + | NonMutatingUse(NonMutatingUseContext::ShallowBorrow) + | NonMutatingUse(NonMutatingUseContext::UniqueBorrow) + | NonMutatingUse(NonMutatingUseContext::AddressOf) + | MutatingUse(MutatingUseContext::Borrow) + | MutatingUse(MutatingUseContext::AddressOf) => { + trace!("local {:?} can't be propagaged because it's used: {:?}", local, context); + self.can_const_prop[local] = ConstPropMode::NoPropagation; + } + } + } +} + +impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_body(&mut self, body: &mut Body<'tcx>) { + for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() { + self.visit_basic_block_data(bb, data); + } + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { + self.super_operand(operand, location); + + // Only const prop copies and moves on `mir_opt_level=3` as doing so + // currently slightly increases compile time in some cases. + if self.tcx.sess.mir_opt_level() >= 3 { + self.propagate_operand(operand) + } + } + + fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { + trace!("visit_constant: {:?}", constant); + self.super_constant(constant, location); + self.eval_constant(constant, self.source_info.unwrap()); + } + + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + trace!("visit_statement: {:?}", statement); + let source_info = statement.source_info; + self.source_info = Some(source_info); + if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind { + let can_const_prop = self.ecx.machine.can_const_prop[place.local]; + if let Some(()) = self.const_prop(rval, source_info, place) { + // This will return None if the above `const_prop` invocation only "wrote" a + // type whose creation requires no write. E.g. a generator whose initial state + // consists solely of uninitialized memory (so it doesn't capture any locals). + if let Some(ref value) = self.get_const(place) { + if self.should_const_prop(value) { + trace!("replacing {:?} with {:?}", rval, value); + self.replace_with_const(rval, value, source_info); + if can_const_prop == ConstPropMode::FullConstProp + || can_const_prop == ConstPropMode::OnlyInsideOwnBlock + { + trace!("propagated into {:?}", place); + } + } + } + match can_const_prop { + ConstPropMode::OnlyInsideOwnBlock => { + trace!( + "found local restricted to its block. \ + Will remove it from const-prop after block is finished. Local: {:?}", + place.local + ); + } + ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => { + trace!("can't propagate into {:?}", place); + if place.local != RETURN_PLACE { + Self::remove_const(&mut self.ecx, place.local); + } + } + ConstPropMode::FullConstProp => {} + } + } else { + // Const prop failed, so erase the destination, ensuring that whatever happens + // from here on, does not know about the previous value. + // This is important in case we have + // ```rust + // let mut x = 42; + // x = SOME_MUTABLE_STATIC; + // // x must now be uninit + // ``` + // FIXME: we overzealously erase the entire local, because that's easier to + // implement. + trace!( + "propagation into {:?} failed. + Nuking the entire site from orbit, it's the only way to be sure", + place, + ); + Self::remove_const(&mut self.ecx, place.local); + } + } else { + match statement.kind { + StatementKind::SetDiscriminant { ref place, .. } => { + match self.ecx.machine.can_const_prop[place.local] { + ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => { + if self.use_ecx(|this| this.ecx.statement(statement)).is_some() { + trace!("propped discriminant into {:?}", place); + } else { + Self::remove_const(&mut self.ecx, place.local); + } + } + ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => { + Self::remove_const(&mut self.ecx, place.local); + } + } + } + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + let frame = self.ecx.frame_mut(); + frame.locals[local].value = + if let StatementKind::StorageLive(_) = statement.kind { + LocalValue::Uninitialized + } else { + LocalValue::Dead + }; + } + _ => {} + } + } + + self.super_statement(statement, location); + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + let source_info = terminator.source_info; + self.source_info = Some(source_info); + self.super_terminator(terminator, location); + match &mut terminator.kind { + TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => { + if let Some(ref value) = self.eval_operand(&cond, source_info) { + trace!("assertion on {:?} should be {:?}", value, expected); + let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected)); + let value_const = self.ecx.read_scalar(&value).unwrap(); + if expected != value_const { + enum DbgVal { + Val(T), + Underscore, + } + impl std::fmt::Debug for DbgVal { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Val(val) => val.fmt(fmt), + Self::Underscore => fmt.write_str("_"), + } + } + } + let mut eval_to_int = |op| { + // This can be `None` if the lhs wasn't const propagated and we just + // triggered the assert on the value of the rhs. + self.eval_operand(op, source_info).map_or(DbgVal::Underscore, |op| { + DbgVal::Val(self.ecx.read_immediate(&op).unwrap().to_const_int()) + }) + }; + let msg = match msg { + AssertKind::DivisionByZero(op) => { + Some(AssertKind::DivisionByZero(eval_to_int(op))) + } + AssertKind::RemainderByZero(op) => { + Some(AssertKind::RemainderByZero(eval_to_int(op))) + } + AssertKind::BoundsCheck { ref len, ref index } => { + let len = eval_to_int(len); + let index = eval_to_int(index); + Some(AssertKind::BoundsCheck { len, index }) + } + // Overflow is are already covered by checks on the binary operators. + AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => None, + // Need proper const propagator for these. + _ => None, + }; + // Poison all places this operand references so that further code + // doesn't use the invalid value + match cond { + Operand::Move(ref place) | Operand::Copy(ref place) => { + Self::remove_const(&mut self.ecx, place.local); + } + Operand::Constant(_) => {} + } + if let Some(msg) = msg { + self.report_assert_as_lint( + lint::builtin::UNCONDITIONAL_PANIC, + source_info, + "this operation will panic at runtime", + msg, + ); + } + } else { + if self.should_const_prop(value) { + if let ScalarMaybeUninit::Scalar(scalar) = value_const { + *cond = self.operand_from_scalar( + scalar, + self.tcx.types.bool, + source_info.span, + ); + } + } + } + } + } + TerminatorKind::SwitchInt { ref mut discr, .. } => { + // FIXME: This is currently redundant with `visit_operand`, but sadly + // always visiting operands currently causes a perf regression in LLVM codegen, so + // `visit_operand` currently only runs for propagates places for `mir_opt_level=4`. + self.propagate_operand(discr) + } + // None of these have Operands to const-propagate. + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => {} + // Every argument in our function calls have already been propagated in `visit_operand`. + // + // NOTE: because LLVM codegen gives slight performance regressions with it, so this is + // gated on `mir_opt_level=3`. + TerminatorKind::Call { .. } => {} + } + + // We remove all Locals which are restricted in propagation to their containing blocks and + // which were modified in the current block. + // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. + let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); + for &local in locals.iter() { + Self::remove_const(&mut self.ecx, local); + } + locals.clear(); + // Put it back so we reuse the heap of the storage + self.ecx.machine.written_only_inside_own_block_locals = locals; + if cfg!(debug_assertions) { + // Ensure we are correctly erasing locals with the non-debug-assert logic. + for local in self.ecx.machine.only_propagate_inside_block_locals.iter() { + assert!( + self.get_const(local.into()).is_none() + || self + .layout_of(self.local_decls[local].ty) + .map_or(true, |layout| layout.is_zst()) + ) + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/counters.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/counters.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/counters.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/counters.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,614 @@ +use super::Error; + +use super::debug; +use super::graph; +use super::spans; + +use debug::{DebugCounters, NESTED_INDENT}; +use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops}; +use spans::CoverageSpan; + +use rustc_data_structures::graph::WithNumNodes; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::coverage::*; + +/// Manages the counter and expression indexes/IDs to generate `CoverageKind` components for MIR +/// `Coverage` statements. +pub(super) struct CoverageCounters { + function_source_hash: u64, + next_counter_id: u32, + num_expressions: u32, + pub debug_counters: DebugCounters, +} + +impl CoverageCounters { + pub fn new(function_source_hash: u64) -> Self { + Self { + function_source_hash, + next_counter_id: CounterValueReference::START.as_u32(), + num_expressions: 0, + debug_counters: DebugCounters::new(), + } + } + + /// Activate the `DebugCounters` data structures, to provide additional debug formatting + /// features when formatting `CoverageKind` (counter) values. + pub fn enable_debug(&mut self) { + self.debug_counters.enable(); + } + + /// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or + /// indirectly associated with `CoverageSpans`, and returns additional `Expression`s + /// representing intermediate values. + pub fn make_bcb_counters( + &mut self, + basic_coverage_blocks: &mut CoverageGraph, + coverage_spans: &Vec, + ) -> Result, Error> { + let mut bcb_counters = BcbCounters::new(self, basic_coverage_blocks); + bcb_counters.make_bcb_counters(coverage_spans) + } + + fn make_counter(&mut self, debug_block_label_fn: F) -> CoverageKind + where + F: Fn() -> Option, + { + let counter = CoverageKind::Counter { + function_source_hash: self.function_source_hash, + id: self.next_counter(), + }; + if self.debug_counters.is_enabled() { + self.debug_counters.add_counter(&counter, (debug_block_label_fn)()); + } + counter + } + + fn make_expression( + &mut self, + lhs: ExpressionOperandId, + op: Op, + rhs: ExpressionOperandId, + debug_block_label_fn: F, + ) -> CoverageKind + where + F: Fn() -> Option, + { + let id = self.next_expression(); + let expression = CoverageKind::Expression { id, lhs, op, rhs }; + if self.debug_counters.is_enabled() { + self.debug_counters.add_counter(&expression, (debug_block_label_fn)()); + } + expression + } + + pub fn make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind { + let some_debug_block_label = if self.debug_counters.is_enabled() { + self.debug_counters.some_block_label(counter_operand).cloned() + } else { + None + }; + self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO, || { + some_debug_block_label.clone() + }) + } + + /// Counter IDs start from one and go up. + fn next_counter(&mut self) -> CounterValueReference { + assert!(self.next_counter_id < u32::MAX - self.num_expressions); + let next = self.next_counter_id; + self.next_counter_id += 1; + CounterValueReference::from(next) + } + + /// Expression IDs start from u32::MAX and go down because an Expression can reference + /// (add or subtract counts) of both Counter regions and Expression regions. The counter + /// expression operand IDs must be unique across both types. + fn next_expression(&mut self) -> InjectedExpressionId { + assert!(self.next_counter_id < u32::MAX - self.num_expressions); + let next = u32::MAX - self.num_expressions; + self.num_expressions += 1; + InjectedExpressionId::from(next) + } +} + +/// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be +/// injected with `CoverageSpan`s. `Expressions` have no runtime overhead, so if a viable expression +/// (adding or subtracting two other counters or expressions) can compute the same result as an +/// embedded counter, an `Expression` should be used. +struct BcbCounters<'a> { + coverage_counters: &'a mut CoverageCounters, + basic_coverage_blocks: &'a mut CoverageGraph, +} + +impl<'a> BcbCounters<'a> { + fn new( + coverage_counters: &'a mut CoverageCounters, + basic_coverage_blocks: &'a mut CoverageGraph, + ) -> Self { + Self { coverage_counters, basic_coverage_blocks } + } + + /// If two `BasicCoverageBlock`s branch from another `BasicCoverageBlock`, one of the branches + /// can be counted by `Expression` by subtracting the other branch from the branching + /// block. Otherwise, the `BasicCoverageBlock` executed the least should have the `Counter`. + /// One way to predict which branch executes the least is by considering loops. A loop is exited + /// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost + /// always executed less than the branch that does not exit the loop. + /// + /// Returns any non-code-span expressions created to represent intermediate values (such as to + /// add two counters so the result can be subtracted from another counter), or an Error with + /// message for subsequent debugging. + fn make_bcb_counters( + &mut self, + coverage_spans: &[CoverageSpan], + ) -> Result, Error> { + debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock"); + let num_bcbs = self.basic_coverage_blocks.num_nodes(); + let mut collect_intermediate_expressions = Vec::with_capacity(num_bcbs); + + let mut bcbs_with_coverage = BitSet::new_empty(num_bcbs); + for covspan in coverage_spans { + bcbs_with_coverage.insert(covspan.bcb); + } + + // Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated + // `CoverageSpan`, add a counter. If the `BasicCoverageBlock` branches, add a counter or + // expression to each branch `BasicCoverageBlock` (if the branch BCB has only one incoming + // edge) or edge from the branching BCB to the branch BCB (if the branch BCB has multiple + // incoming edges). + // + // The `TraverseCoverageGraphWithLoops` traversal ensures that, when a loop is encountered, + // all `BasicCoverageBlock` nodes in the loop are visited before visiting any node outside + // the loop. The `traversal` state includes a `context_stack`, providing a way to know if + // the current BCB is in one or more nested loops or not. + let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks); + while let Some(bcb) = traversal.next(self.basic_coverage_blocks) { + if bcbs_with_coverage.contains(bcb) { + debug!("{:?} has at least one `CoverageSpan`. Get or make its counter", bcb); + let branching_counter_operand = + self.get_or_make_counter_operand(bcb, &mut collect_intermediate_expressions)?; + + if self.bcb_needs_branch_counters(bcb) { + self.make_branch_counters( + &mut traversal, + bcb, + branching_counter_operand, + &mut collect_intermediate_expressions, + )?; + } + } else { + debug!( + "{:?} does not have any `CoverageSpan`s. A counter will only be added if \ + and when a covered BCB has an expression dependency.", + bcb, + ); + } + } + + if traversal.is_complete() { + Ok(collect_intermediate_expressions) + } else { + Error::from_string(format!( + "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}", + traversal.unvisited(), + )) + } + } + + fn make_branch_counters( + &mut self, + traversal: &mut TraverseCoverageGraphWithLoops, + branching_bcb: BasicCoverageBlock, + branching_counter_operand: ExpressionOperandId, + collect_intermediate_expressions: &mut Vec, + ) -> Result<(), Error> { + let branches = self.bcb_branches(branching_bcb); + debug!( + "{:?} has some branch(es) without counters:\n {}", + branching_bcb, + branches + .iter() + .map(|branch| { + format!("{:?}: {:?}", branch, branch.counter(&self.basic_coverage_blocks)) + }) + .collect::>() + .join("\n "), + ); + + // Use the `traversal` state to decide if a subset of the branches exit a loop, making it + // likely that branch is executed less than branches that do not exit the same loop. In this + // case, any branch that does not exit the loop (and has not already been assigned a + // counter) should be counted by expression, if possible. (If a preferred expression branch + // is not selected based on the loop context, select any branch without an existing + // counter.) + let expression_branch = self.choose_preferred_expression_branch(traversal, &branches); + + // Assign a Counter or Expression to each branch, plus additional `Expression`s, as needed, + // to sum up intermediate results. + let mut some_sumup_counter_operand = None; + for branch in branches { + // Skip the selected `expression_branch`, if any. It's expression will be assigned after + // all others. + if branch != expression_branch { + let branch_counter_operand = if branch.is_only_path_to_target() { + debug!( + " {:?} has only one incoming edge (from {:?}), so adding a \ + counter", + branch, branching_bcb + ); + self.get_or_make_counter_operand( + branch.target_bcb, + collect_intermediate_expressions, + )? + } else { + debug!(" {:?} has multiple incoming edges, so adding an edge counter", branch); + self.get_or_make_edge_counter_operand( + branching_bcb, + branch.target_bcb, + collect_intermediate_expressions, + )? + }; + if let Some(sumup_counter_operand) = + some_sumup_counter_operand.replace(branch_counter_operand) + { + let intermediate_expression = self.coverage_counters.make_expression( + branch_counter_operand, + Op::Add, + sumup_counter_operand, + || None, + ); + debug!( + " [new intermediate expression: {}]", + self.format_counter(&intermediate_expression) + ); + let intermediate_expression_operand = intermediate_expression.as_operand_id(); + collect_intermediate_expressions.push(intermediate_expression); + some_sumup_counter_operand.replace(intermediate_expression_operand); + } + } + } + + // Assign the final expression to the `expression_branch` by subtracting the total of all + // other branches from the counter of the branching BCB. + let sumup_counter_operand = + some_sumup_counter_operand.expect("sumup_counter_operand should have a value"); + debug!( + "Making an expression for the selected expression_branch: {:?} \ + (expression_branch predecessors: {:?})", + expression_branch, + self.bcb_predecessors(expression_branch.target_bcb), + ); + let expression = self.coverage_counters.make_expression( + branching_counter_operand, + Op::Subtract, + sumup_counter_operand, + || Some(format!("{:?}", expression_branch)), + ); + debug!("{:?} gets an expression: {}", expression_branch, self.format_counter(&expression)); + let bcb = expression_branch.target_bcb; + if expression_branch.is_only_path_to_target() { + self.basic_coverage_blocks[bcb].set_counter(expression)?; + } else { + self.basic_coverage_blocks[bcb].set_edge_counter_from(branching_bcb, expression)?; + } + Ok(()) + } + + fn get_or_make_counter_operand( + &mut self, + bcb: BasicCoverageBlock, + collect_intermediate_expressions: &mut Vec, + ) -> Result { + self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1) + } + + fn recursive_get_or_make_counter_operand( + &mut self, + bcb: BasicCoverageBlock, + collect_intermediate_expressions: &mut Vec, + debug_indent_level: usize, + ) -> Result { + // If the BCB already has a counter, return it. + if let Some(counter_kind) = self.basic_coverage_blocks[bcb].counter() { + debug!( + "{}{:?} already has a counter: {}", + NESTED_INDENT.repeat(debug_indent_level), + bcb, + self.format_counter(counter_kind), + ); + return Ok(counter_kind.as_operand_id()); + } + + // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`). + // Also, a BCB that loops back to itself gets a simple `Counter`. This may indicate the + // program results in a tight infinite loop, but it should still compile. + let one_path_to_target = self.bcb_has_one_path_to_target(bcb); + if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) { + let counter_kind = self.coverage_counters.make_counter(|| Some(format!("{:?}", bcb))); + if one_path_to_target { + debug!( + "{}{:?} gets a new counter: {}", + NESTED_INDENT.repeat(debug_indent_level), + bcb, + self.format_counter(&counter_kind), + ); + } else { + debug!( + "{}{:?} has itself as its own predecessor. It can't be part of its own \ + Expression sum, so it will get its own new counter: {}. (Note, the compiled \ + code will generate an infinite loop.)", + NESTED_INDENT.repeat(debug_indent_level), + bcb, + self.format_counter(&counter_kind), + ); + } + return self.basic_coverage_blocks[bcb].set_counter(counter_kind); + } + + // A BCB with multiple incoming edges can compute its count by `Expression`, summing up the + // counters and/or expressions of its incoming edges. This will recursively get or create + // counters for those incoming edges first, then call `make_expression()` to sum them up, + // with additional intermediate expressions as needed. + let mut predecessors = self.bcb_predecessors(bcb).clone().into_iter(); + debug!( + "{}{:?} has multiple incoming edges and will get an expression that sums them up...", + NESTED_INDENT.repeat(debug_indent_level), + bcb, + ); + let first_edge_counter_operand = self.recursive_get_or_make_edge_counter_operand( + predecessors.next().unwrap(), + bcb, + collect_intermediate_expressions, + debug_indent_level + 1, + )?; + let mut some_sumup_edge_counter_operand = None; + for predecessor in predecessors { + let edge_counter_operand = self.recursive_get_or_make_edge_counter_operand( + predecessor, + bcb, + collect_intermediate_expressions, + debug_indent_level + 1, + )?; + if let Some(sumup_edge_counter_operand) = + some_sumup_edge_counter_operand.replace(edge_counter_operand) + { + let intermediate_expression = self.coverage_counters.make_expression( + sumup_edge_counter_operand, + Op::Add, + edge_counter_operand, + || None, + ); + debug!( + "{}new intermediate expression: {}", + NESTED_INDENT.repeat(debug_indent_level), + self.format_counter(&intermediate_expression) + ); + let intermediate_expression_operand = intermediate_expression.as_operand_id(); + collect_intermediate_expressions.push(intermediate_expression); + some_sumup_edge_counter_operand.replace(intermediate_expression_operand); + } + } + let counter_kind = self.coverage_counters.make_expression( + first_edge_counter_operand, + Op::Add, + some_sumup_edge_counter_operand.unwrap(), + || Some(format!("{:?}", bcb)), + ); + debug!( + "{}{:?} gets a new counter (sum of predecessor counters): {}", + NESTED_INDENT.repeat(debug_indent_level), + bcb, + self.format_counter(&counter_kind) + ); + self.basic_coverage_blocks[bcb].set_counter(counter_kind) + } + + fn get_or_make_edge_counter_operand( + &mut self, + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, + collect_intermediate_expressions: &mut Vec, + ) -> Result { + self.recursive_get_or_make_edge_counter_operand( + from_bcb, + to_bcb, + collect_intermediate_expressions, + 1, + ) + } + + fn recursive_get_or_make_edge_counter_operand( + &mut self, + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, + collect_intermediate_expressions: &mut Vec, + debug_indent_level: usize, + ) -> Result { + // If the source BCB has only one successor (assumed to be the given target), an edge + // counter is unnecessary. Just get or make a counter for the source BCB. + let successors = self.bcb_successors(from_bcb).iter(); + if successors.len() == 1 { + return self.recursive_get_or_make_counter_operand( + from_bcb, + collect_intermediate_expressions, + debug_indent_level + 1, + ); + } + + // If the edge already has a counter, return it. + if let Some(counter_kind) = self.basic_coverage_blocks[to_bcb].edge_counter_from(from_bcb) { + debug!( + "{}Edge {:?}->{:?} already has a counter: {}", + NESTED_INDENT.repeat(debug_indent_level), + from_bcb, + to_bcb, + self.format_counter(counter_kind) + ); + return Ok(counter_kind.as_operand_id()); + } + + // Make a new counter to count this edge. + let counter_kind = + self.coverage_counters.make_counter(|| Some(format!("{:?}->{:?}", from_bcb, to_bcb))); + debug!( + "{}Edge {:?}->{:?} gets a new counter: {}", + NESTED_INDENT.repeat(debug_indent_level), + from_bcb, + to_bcb, + self.format_counter(&counter_kind) + ); + self.basic_coverage_blocks[to_bcb].set_edge_counter_from(from_bcb, counter_kind) + } + + /// Select a branch for the expression, either the recommended `reloop_branch`, or if none was + /// found, select any branch. + fn choose_preferred_expression_branch( + &self, + traversal: &TraverseCoverageGraphWithLoops, + branches: &[BcbBranch], + ) -> BcbBranch { + let branch_needs_a_counter = + |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); + + let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches); + if let Some(reloop_branch_without_counter) = + some_reloop_branch.filter(branch_needs_a_counter) + { + debug!( + "Selecting reloop_branch={:?} that still needs a counter, to get the \ + `Expression`", + reloop_branch_without_counter + ); + reloop_branch_without_counter + } else { + let &branch_without_counter = branches + .iter() + .find(|&&branch| branch.counter(&self.basic_coverage_blocks).is_none()) + .expect( + "needs_branch_counters was `true` so there should be at least one \ + branch", + ); + debug!( + "Selecting any branch={:?} that still needs a counter, to get the \ + `Expression` because there was no `reloop_branch`, or it already had a \ + counter", + branch_without_counter + ); + branch_without_counter + } + } + + /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has + /// multiple incoming edges) can have a counter computed by expression. + /// + /// If at least one of the branches leads outside of a loop (`found_loop_exit` is + /// true), and at least one other branch does not exit the loop (the first of which + /// is captured in `some_reloop_branch`), it's likely any reloop branch will be + /// executed far more often than loop exit branch, making the reloop branch a better + /// candidate for an expression. + fn find_some_reloop_branch( + &self, + traversal: &TraverseCoverageGraphWithLoops, + branches: &[BcbBranch], + ) -> Option { + let branch_needs_a_counter = + |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); + + let mut some_reloop_branch: Option = None; + for context in traversal.context_stack.iter().rev() { + if let Some((backedge_from_bcbs, _)) = &context.loop_backedges { + let mut found_loop_exit = false; + for &branch in branches.iter() { + if backedge_from_bcbs.iter().any(|&backedge_from_bcb| { + self.bcb_is_dominated_by(backedge_from_bcb, branch.target_bcb) + }) { + if let Some(reloop_branch) = some_reloop_branch { + if reloop_branch.counter(&self.basic_coverage_blocks).is_none() { + // we already found a candidate reloop_branch that still + // needs a counter + continue; + } + } + // The path from branch leads back to the top of the loop. Set this + // branch as the `reloop_branch`. If this branch already has a + // counter, and we find another reloop branch that doesn't have a + // counter yet, that branch will be selected as the `reloop_branch` + // instead. + some_reloop_branch = Some(branch); + } else { + // The path from branch leads outside this loop + found_loop_exit = true; + } + if found_loop_exit + && some_reloop_branch.filter(branch_needs_a_counter).is_some() + { + // Found both a branch that exits the loop and a branch that returns + // to the top of the loop (`reloop_branch`), and the `reloop_branch` + // doesn't already have a counter. + break; + } + } + if !found_loop_exit { + debug!( + "No branches exit the loop, so any branch without an existing \ + counter can have the `Expression`." + ); + break; + } + if some_reloop_branch.is_some() { + debug!( + "Found a branch that exits the loop and a branch the loops back to \ + the top of the loop (`reloop_branch`). The `reloop_branch` will \ + get the `Expression`, as long as it still needs a counter." + ); + break; + } + // else all branches exited this loop context, so run the same checks with + // the outer loop(s) + } + } + some_reloop_branch + } + + #[inline] + fn bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &Vec { + &self.basic_coverage_blocks.predecessors[bcb] + } + + #[inline] + fn bcb_successors(&self, bcb: BasicCoverageBlock) -> &Vec { + &self.basic_coverage_blocks.successors[bcb] + } + + #[inline] + fn bcb_branches(&self, from_bcb: BasicCoverageBlock) -> Vec { + self.bcb_successors(from_bcb) + .iter() + .map(|&to_bcb| BcbBranch::from_to(from_bcb, to_bcb, &self.basic_coverage_blocks)) + .collect::>() + } + + fn bcb_needs_branch_counters(&self, bcb: BasicCoverageBlock) -> bool { + let branch_needs_a_counter = + |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none(); + let branches = self.bcb_branches(bcb); + branches.len() > 1 && branches.iter().any(branch_needs_a_counter) + } + + /// Returns true if the BasicCoverageBlock has zero or one incoming edge. (If zero, it should be + /// the entry point for the function.) + #[inline] + fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool { + self.bcb_predecessors(bcb).len() <= 1 + } + + #[inline] + fn bcb_is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool { + self.basic_coverage_blocks.is_dominated_by(node, dom) + } + + #[inline] + fn format_counter(&self, counter_kind: &CoverageKind) -> String { + self.coverage_counters.debug_counters.format_counter(counter_kind) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/debug.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/debug.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/debug.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/debug.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,838 @@ +//! The `InstrumentCoverage` MIR pass implementation includes debugging tools and options +//! to help developers understand and/or improve the analysis and instrumentation of a MIR. +//! +//! To enable coverage, include the rustc command line option: +//! +//! * `-Z instrument-coverage` +//! +//! MIR Dump Files, with additional `CoverageGraph` graphviz and `CoverageSpan` spanview +//! ------------------------------------------------------------------------------------ +//! +//! Additional debugging options include: +//! +//! * `-Z dump-mir=InstrumentCoverage` - Generate `.mir` files showing the state of the MIR, +//! before and after the `InstrumentCoverage` pass, for each compiled function. +//! +//! * `-Z dump-mir-graphviz` - If `-Z dump-mir` is also enabled for the current MIR node path, +//! each MIR dump is accompanied by a before-and-after graphical view of the MIR, in Graphviz +//! `.dot` file format (which can be visually rendered as a graph using any of a number of free +//! Graphviz viewers and IDE extensions). +//! +//! For the `InstrumentCoverage` pass, this option also enables generation of an additional +//! Graphviz `.dot` file for each function, rendering the `CoverageGraph`: the control flow +//! graph (CFG) of `BasicCoverageBlocks` (BCBs), as nodes, internally labeled to show the +//! `CoverageSpan`-based MIR elements each BCB represents (`BasicBlock`s, `Statement`s and +//! `Terminator`s), assigned coverage counters and/or expressions, and edge counters, as needed. +//! +//! (Note the additional option, `-Z graphviz-dark-mode`, can be added, to change the rendered +//! output from its default black-on-white background to a dark color theme, if desired.) +//! +//! * `-Z dump-mir-spanview` - If `-Z dump-mir` is also enabled for the current MIR node path, +//! each MIR dump is accompanied by a before-and-after `.html` document showing the function's +//! original source code, highlighted by it's MIR spans, at the `statement`-level (by default), +//! `terminator` only, or encompassing span for the `Terminator` plus all `Statement`s, in each +//! `block` (`BasicBlock`). +//! +//! For the `InstrumentCoverage` pass, this option also enables generation of an additional +//! spanview `.html` file for each function, showing the aggregated `CoverageSpan`s that will +//! require counters (or counter expressions) for accurate coverage analysis. +//! +//! Debug Logging +//! ------------- +//! +//! The `InstrumentCoverage` pass includes debug logging messages at various phases and decision +//! points, which can be enabled via environment variable: +//! +//! ```shell +//! RUSTC_LOG=rustc_mir_transform::transform::coverage=debug +//! ``` +//! +//! Other module paths with coverage-related debug logs may also be of interest, particularly for +//! debugging the coverage map data, injected as global variables in the LLVM IR (during rustc's +//! code generation pass). For example: +//! +//! ```shell +//! RUSTC_LOG=rustc_mir_transform::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug +//! ``` +//! +//! Coverage Debug Options +//! --------------------------------- +//! +//! Additional debugging options can be enabled using the environment variable: +//! +//! ```shell +//! RUSTC_COVERAGE_DEBUG_OPTIONS= +//! ``` +//! +//! These options are comma-separated, and specified in the format `option-name=value`. For example: +//! +//! ```shell +//! $ RUSTC_COVERAGE_DEBUG_OPTIONS=counter-format=id+operation,allow-unused-expressions=yes cargo build +//! ``` +//! +//! Coverage debug options include: +//! +//! * `allow-unused-expressions=yes` or `no` (default: `no`) +//! +//! The `InstrumentCoverage` algorithms _should_ only create and assign expressions to a +//! `BasicCoverageBlock`, or an incoming edge, if that expression is either (a) required to +//! count a `CoverageSpan`, or (b) a dependency of some other required counter expression. +//! +//! If an expression is generated that does not map to a `CoverageSpan` or dependency, this +//! probably indicates there was a bug in the algorithm that creates and assigns counters +//! and expressions. +//! +//! When this kind of bug is encountered, the rustc compiler will panic by default. Setting: +//! `allow-unused-expressions=yes` will log a warning message instead of panicking (effectively +//! ignoring the unused expressions), which may be helpful when debugging the root cause of +//! the problem. +//! +//! * `counter-format=`, where `` can be any plus-separated combination of `id`, +//! `block`, and/or `operation` (default: `block+operation`) +//! +//! This option effects both the `CoverageGraph` (graphviz `.dot` files) and debug logging, when +//! generating labels for counters and expressions. +//! +//! Depending on the values and combinations, counters can be labeled by: +//! +//! * `id` - counter or expression ID (ascending counter IDs, starting at 1, or descending +//! expression IDs, starting at `u32:MAX`) +//! * `block` - the `BasicCoverageBlock` label (for example, `bcb0`) or edge label (for +//! example `bcb0->bcb1`), for counters or expressions assigned to count a +//! `BasicCoverageBlock` or edge. Intermediate expressions (not directly associated with +//! a BCB or edge) will be labeled by their expression ID, unless `operation` is also +//! specified. +//! * `operation` - applied to expressions only, labels include the left-hand-side counter +//! or expression label (lhs operand), the operator (`+` or `-`), and the right-hand-side +//! counter or expression (rhs operand). Expression operand labels are generated +//! recursively, generating labels with nested operations, enclosed in parentheses +//! (for example: `bcb2 + (bcb0 - bcb1)`). + +use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use super::spans::CoverageSpan; + +use rustc_middle::mir::create_dump_file; +use rustc_middle::mir::generic_graphviz::GraphvizWriter; +use rustc_middle::mir::spanview::{self, SpanViewable}; + +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::mir::coverage::*; +use rustc_middle::mir::{self, BasicBlock, TerminatorKind}; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; + +use std::iter; +use std::lazy::SyncOnceCell; + +pub const NESTED_INDENT: &str = " "; + +const RUSTC_COVERAGE_DEBUG_OPTIONS: &str = "RUSTC_COVERAGE_DEBUG_OPTIONS"; + +pub(super) fn debug_options<'a>() -> &'a DebugOptions { + static DEBUG_OPTIONS: SyncOnceCell = SyncOnceCell::new(); + + &DEBUG_OPTIONS.get_or_init(DebugOptions::from_env) +} + +/// Parses and maintains coverage-specific debug options captured from the environment variable +/// "RUSTC_COVERAGE_DEBUG_OPTIONS", if set. +#[derive(Debug, Clone)] +pub(super) struct DebugOptions { + pub allow_unused_expressions: bool, + counter_format: ExpressionFormat, +} + +impl DebugOptions { + fn from_env() -> Self { + let mut allow_unused_expressions = true; + let mut counter_format = ExpressionFormat::default(); + + if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) { + for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') { + let (option, value) = match setting_str.split_once('=') { + None => (setting_str, None), + Some((k, v)) => (k, Some(v)), + }; + match option { + "allow_unused_expressions" => { + allow_unused_expressions = bool_option_val(option, value); + debug!( + "{} env option `allow_unused_expressions` is set to {}", + RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions + ); + } + "counter_format" => { + match value { + None => { + bug!( + "`{}` option in environment variable {} requires one or more \ + plus-separated choices (a non-empty subset of \ + `id+block+operation`)", + option, + RUSTC_COVERAGE_DEBUG_OPTIONS + ); + } + Some(val) => { + counter_format = counter_format_option_val(val); + debug!( + "{} env option `counter_format` is set to {:?}", + RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format + ); + } + }; + } + _ => bug!( + "Unsupported setting `{}` in environment variable {}", + option, + RUSTC_COVERAGE_DEBUG_OPTIONS + ), + }; + } + } + + Self { allow_unused_expressions, counter_format } + } +} + +fn bool_option_val(option: &str, some_strval: Option<&str>) -> bool { + if let Some(val) = some_strval { + if vec!["yes", "y", "on", "true"].contains(&val) { + true + } else if vec!["no", "n", "off", "false"].contains(&val) { + false + } else { + bug!( + "Unsupported value `{}` for option `{}` in environment variable {}", + option, + val, + RUSTC_COVERAGE_DEBUG_OPTIONS + ) + } + } else { + true + } +} + +fn counter_format_option_val(strval: &str) -> ExpressionFormat { + let mut counter_format = ExpressionFormat { id: false, block: false, operation: false }; + let components = strval.splitn(3, '+'); + for component in components { + match component { + "id" => counter_format.id = true, + "block" => counter_format.block = true, + "operation" => counter_format.operation = true, + _ => bug!( + "Unsupported counter_format choice `{}` in environment variable {}", + component, + RUSTC_COVERAGE_DEBUG_OPTIONS + ), + } + } + counter_format +} + +#[derive(Debug, Clone)] +struct ExpressionFormat { + id: bool, + block: bool, + operation: bool, +} + +impl Default for ExpressionFormat { + fn default() -> Self { + Self { id: false, block: true, operation: true } + } +} + +/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `ExpressionOperandId`) to +/// the `CoverageKind` data and optional label (normally, the counter's associated +/// `BasicCoverageBlock` format string, if any). +/// +/// Use `format_counter` to convert one of these `CoverageKind` counters to a debug output string, +/// as directed by the `DebugOptions`. This allows the format of counter labels in logs and dump +/// files (including the `CoverageGraph` graphviz file) to be changed at runtime, via environment +/// variable. +/// +/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be +/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`. +pub(super) struct DebugCounters { + some_counters: Option>, +} + +impl DebugCounters { + pub fn new() -> Self { + Self { some_counters: None } + } + + pub fn enable(&mut self) { + debug_assert!(!self.is_enabled()); + self.some_counters.replace(FxHashMap::default()); + } + + pub fn is_enabled(&self) -> bool { + self.some_counters.is_some() + } + + pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option) { + if let Some(counters) = &mut self.some_counters { + let id: ExpressionOperandId = match *counter_kind { + CoverageKind::Counter { id, .. } => id.into(), + CoverageKind::Expression { id, .. } => id.into(), + _ => bug!( + "the given `CoverageKind` is not an counter or expression: {:?}", + counter_kind + ), + }; + counters + .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label)) + .expect("attempt to add the same counter_kind to DebugCounters more than once"); + } + } + + pub fn some_block_label(&self, operand: ExpressionOperandId) -> Option<&String> { + self.some_counters.as_ref().map_or(None, |counters| { + counters + .get(&operand) + .map_or(None, |debug_counter| debug_counter.some_block_label.as_ref()) + }) + } + + pub fn format_counter(&self, counter_kind: &CoverageKind) -> String { + match *counter_kind { + CoverageKind::Counter { .. } => { + format!("Counter({})", self.format_counter_kind(counter_kind)) + } + CoverageKind::Expression { .. } => { + format!("Expression({})", self.format_counter_kind(counter_kind)) + } + CoverageKind::Unreachable { .. } => "Unreachable".to_owned(), + } + } + + fn format_counter_kind(&self, counter_kind: &CoverageKind) -> String { + let counter_format = &debug_options().counter_format; + if let CoverageKind::Expression { id, lhs, op, rhs } = *counter_kind { + if counter_format.operation { + return format!( + "{}{} {} {}", + if counter_format.id || self.some_counters.is_none() { + format!("#{} = ", id.index()) + } else { + String::new() + }, + self.format_operand(lhs), + if op == Op::Add { "+" } else { "-" }, + self.format_operand(rhs), + ); + } + } + + let id: ExpressionOperandId = match *counter_kind { + CoverageKind::Counter { id, .. } => id.into(), + CoverageKind::Expression { id, .. } => id.into(), + _ => { + bug!("the given `CoverageKind` is not an counter or expression: {:?}", counter_kind) + } + }; + if self.some_counters.is_some() && (counter_format.block || !counter_format.id) { + let counters = self.some_counters.as_ref().unwrap(); + if let Some(DebugCounter { some_block_label: Some(block_label), .. }) = + counters.get(&id) + { + return if counter_format.id { + format!("{}#{}", block_label, id.index()) + } else { + block_label.to_string() + }; + } + } + format!("#{}", id.index()) + } + + fn format_operand(&self, operand: ExpressionOperandId) -> String { + if operand.index() == 0 { + return String::from("0"); + } + if let Some(counters) = &self.some_counters { + if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) { + if let CoverageKind::Expression { .. } = counter_kind { + if let Some(block_label) = some_block_label { + if debug_options().counter_format.block { + return format!( + "{}:({})", + block_label, + self.format_counter_kind(counter_kind) + ); + } + } + return format!("({})", self.format_counter_kind(counter_kind)); + } + return self.format_counter_kind(counter_kind); + } + } + format!("#{}", operand.index()) + } +} + +/// A non-public support class to `DebugCounters`. +#[derive(Debug)] +struct DebugCounter { + counter_kind: CoverageKind, + some_block_label: Option, +} + +impl DebugCounter { + fn new(counter_kind: CoverageKind, some_block_label: Option) -> Self { + Self { counter_kind, some_block_label } + } +} + +/// If enabled, this data structure captures additional debugging information used when generating +/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes. +pub(super) struct GraphvizData { + some_bcb_to_coverage_spans_with_counters: + Option>>, + some_bcb_to_dependency_counters: Option>>, + some_edge_to_counter: Option>, +} + +impl GraphvizData { + pub fn new() -> Self { + Self { + some_bcb_to_coverage_spans_with_counters: None, + some_bcb_to_dependency_counters: None, + some_edge_to_counter: None, + } + } + + pub fn enable(&mut self) { + debug_assert!(!self.is_enabled()); + self.some_bcb_to_coverage_spans_with_counters = Some(FxHashMap::default()); + self.some_bcb_to_dependency_counters = Some(FxHashMap::default()); + self.some_edge_to_counter = Some(FxHashMap::default()); + } + + pub fn is_enabled(&self) -> bool { + self.some_bcb_to_coverage_spans_with_counters.is_some() + } + + pub fn add_bcb_coverage_span_with_counter( + &mut self, + bcb: BasicCoverageBlock, + coverage_span: &CoverageSpan, + counter_kind: &CoverageKind, + ) { + if let Some(bcb_to_coverage_spans_with_counters) = + self.some_bcb_to_coverage_spans_with_counters.as_mut() + { + bcb_to_coverage_spans_with_counters + .entry(bcb) + .or_insert_with(Vec::new) + .push((coverage_span.clone(), counter_kind.clone())); + } + } + + pub fn get_bcb_coverage_spans_with_counters( + &self, + bcb: BasicCoverageBlock, + ) -> Option<&Vec<(CoverageSpan, CoverageKind)>> { + if let Some(bcb_to_coverage_spans_with_counters) = + self.some_bcb_to_coverage_spans_with_counters.as_ref() + { + bcb_to_coverage_spans_with_counters.get(&bcb) + } else { + None + } + } + + pub fn add_bcb_dependency_counter( + &mut self, + bcb: BasicCoverageBlock, + counter_kind: &CoverageKind, + ) { + if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() { + bcb_to_dependency_counters + .entry(bcb) + .or_insert_with(Vec::new) + .push(counter_kind.clone()); + } + } + + pub fn get_bcb_dependency_counters( + &self, + bcb: BasicCoverageBlock, + ) -> Option<&Vec> { + if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() { + bcb_to_dependency_counters.get(&bcb) + } else { + None + } + } + + pub fn set_edge_counter( + &mut self, + from_bcb: BasicCoverageBlock, + to_bb: BasicBlock, + counter_kind: &CoverageKind, + ) { + if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() { + edge_to_counter + .try_insert((from_bcb, to_bb), counter_kind.clone()) + .expect("invalid attempt to insert more than one edge counter for the same edge"); + } + } + + pub fn get_edge_counter( + &self, + from_bcb: BasicCoverageBlock, + to_bb: BasicBlock, + ) -> Option<&CoverageKind> { + if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() { + edge_to_counter.get(&(from_bcb, to_bb)) + } else { + None + } + } +} + +/// If enabled, this struct captures additional data used to track whether expressions were used, +/// directly or indirectly, to compute the coverage counts for all `CoverageSpan`s, and any that are +/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs +/// and/or a `CoverageGraph` graphviz output). +pub(super) struct UsedExpressions { + some_used_expression_operands: + Option>>, + some_unused_expressions: + Option, BasicCoverageBlock)>>, +} + +impl UsedExpressions { + pub fn new() -> Self { + Self { some_used_expression_operands: None, some_unused_expressions: None } + } + + pub fn enable(&mut self) { + debug_assert!(!self.is_enabled()); + self.some_used_expression_operands = Some(FxHashMap::default()); + self.some_unused_expressions = Some(Vec::new()); + } + + pub fn is_enabled(&self) -> bool { + self.some_used_expression_operands.is_some() + } + + pub fn add_expression_operands(&mut self, expression: &CoverageKind) { + if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() { + if let CoverageKind::Expression { id, lhs, rhs, .. } = *expression { + used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id); + used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id); + } + } + } + + pub fn expression_is_used(&self, expression: &CoverageKind) -> bool { + if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() { + used_expression_operands.contains_key(&expression.as_operand_id()) + } else { + false + } + } + + pub fn add_unused_expression_if_not_found( + &mut self, + expression: &CoverageKind, + edge_from_bcb: Option, + target_bcb: BasicCoverageBlock, + ) { + if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() { + if !used_expression_operands.contains_key(&expression.as_operand_id()) { + self.some_unused_expressions.as_mut().unwrap().push(( + expression.clone(), + edge_from_bcb, + target_bcb, + )); + } + } + } + + /// Return the list of unused counters (if any) as a tuple with the counter (`CoverageKind`), + /// optional `from_bcb` (if it was an edge counter), and `target_bcb`. + pub fn get_unused_expressions( + &self, + ) -> Vec<(CoverageKind, Option, BasicCoverageBlock)> { + if let Some(unused_expressions) = self.some_unused_expressions.as_ref() { + unused_expressions.clone() + } else { + Vec::new() + } + } + + /// If enabled, validate that every BCB or edge counter not directly associated with a coverage + /// span is at least indirectly associated (it is a dependency of a BCB counter that _is_ + /// associated with a coverage span). + pub fn validate( + &mut self, + bcb_counters_without_direct_coverage_spans: &Vec<( + Option, + BasicCoverageBlock, + CoverageKind, + )>, + ) { + if self.is_enabled() { + let mut not_validated = bcb_counters_without_direct_coverage_spans + .iter() + .map(|(_, _, counter_kind)| counter_kind) + .collect::>(); + let mut validating_count = 0; + while not_validated.len() != validating_count { + let to_validate = not_validated.split_off(0); + validating_count = to_validate.len(); + for counter_kind in to_validate { + if self.expression_is_used(counter_kind) { + self.add_expression_operands(counter_kind); + } else { + not_validated.push(counter_kind); + } + } + } + } + } + + pub fn alert_on_unused_expressions(&self, debug_counters: &DebugCounters) { + if let Some(unused_expressions) = self.some_unused_expressions.as_ref() { + for (counter_kind, edge_from_bcb, target_bcb) in unused_expressions { + let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() { + format!( + "non-coverage edge counter found without a dependent expression, in \ + {:?}->{:?}; counter={}", + from_bcb, + target_bcb, + debug_counters.format_counter(&counter_kind), + ) + } else { + format!( + "non-coverage counter found without a dependent expression, in {:?}; \ + counter={}", + target_bcb, + debug_counters.format_counter(&counter_kind), + ) + }; + + if debug_options().allow_unused_expressions { + debug!("WARNING: {}", unused_counter_message); + } else { + bug!("{}", unused_counter_message); + } + } + } + } +} + +/// Generates the MIR pass `CoverageSpan`-specific spanview dump file. +pub(super) fn dump_coverage_spanview( + tcx: TyCtxt<'tcx>, + mir_body: &mir::Body<'tcx>, + basic_coverage_blocks: &CoverageGraph, + pass_name: &str, + body_span: Span, + coverage_spans: &Vec, +) { + let mir_source = mir_body.source; + let def_id = mir_source.def_id(); + + let span_viewables = span_viewables(tcx, mir_body, basic_coverage_blocks, &coverage_spans); + let mut file = create_dump_file(tcx, "html", None, pass_name, &0, mir_source) + .expect("Unexpected error creating MIR spanview HTML file"); + let crate_name = tcx.crate_name(def_id.krate); + let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate(); + let title = format!("{}.{} - Coverage Spans", crate_name, item_name); + spanview::write_document(tcx, body_span, span_viewables, &title, &mut file) + .expect("Unexpected IO error dumping coverage spans as HTML"); +} + +/// Converts the computed `BasicCoverageBlockData`s into `SpanViewable`s. +fn span_viewables( + tcx: TyCtxt<'tcx>, + mir_body: &mir::Body<'tcx>, + basic_coverage_blocks: &CoverageGraph, + coverage_spans: &Vec, +) -> Vec { + let mut span_viewables = Vec::new(); + for coverage_span in coverage_spans { + let tooltip = coverage_span.format_coverage_statements(tcx, mir_body); + let CoverageSpan { span, bcb, .. } = coverage_span; + let bcb_data = &basic_coverage_blocks[*bcb]; + let id = bcb_data.id(); + let leader_bb = bcb_data.leader_bb(); + span_viewables.push(SpanViewable { bb: leader_bb, span: *span, id, tooltip }); + } + span_viewables +} + +/// Generates the MIR pass coverage-specific graphviz dump file. +pub(super) fn dump_coverage_graphviz( + tcx: TyCtxt<'tcx>, + mir_body: &mir::Body<'tcx>, + pass_name: &str, + basic_coverage_blocks: &CoverageGraph, + debug_counters: &DebugCounters, + graphviz_data: &GraphvizData, + intermediate_expressions: &Vec, + debug_used_expressions: &UsedExpressions, +) { + let mir_source = mir_body.source; + let def_id = mir_source.def_id(); + let node_content = |bcb| { + bcb_to_string_sections( + tcx, + mir_body, + debug_counters, + &basic_coverage_blocks[bcb], + graphviz_data.get_bcb_coverage_spans_with_counters(bcb), + graphviz_data.get_bcb_dependency_counters(bcb), + // intermediate_expressions are injected into the mir::START_BLOCK, so + // include them in the first BCB. + if bcb.index() == 0 { Some(&intermediate_expressions) } else { None }, + ) + }; + let edge_labels = |from_bcb| { + let from_bcb_data = &basic_coverage_blocks[from_bcb]; + let from_terminator = from_bcb_data.terminator(mir_body); + let mut edge_labels = from_terminator.kind.fmt_successor_labels(); + edge_labels.retain(|label| label != "unreachable"); + let edge_counters = from_terminator + .successors() + .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb)); + iter::zip(&edge_labels, edge_counters) + .map(|(label, some_counter)| { + if let Some(counter) = some_counter { + format!("{}\n{}", label, debug_counters.format_counter(counter)) + } else { + label.to_string() + } + }) + .collect::>() + }; + let graphviz_name = format!("Cov_{}_{}", def_id.krate.index(), def_id.index.index()); + let mut graphviz_writer = + GraphvizWriter::new(basic_coverage_blocks, &graphviz_name, node_content, edge_labels); + let unused_expressions = debug_used_expressions.get_unused_expressions(); + if unused_expressions.len() > 0 { + graphviz_writer.set_graph_label(&format!( + "Unused expressions:\n {}", + unused_expressions + .as_slice() + .iter() + .map(|(counter_kind, edge_from_bcb, target_bcb)| { + if let Some(from_bcb) = edge_from_bcb.as_ref() { + format!( + "{:?}->{:?}: {}", + from_bcb, + target_bcb, + debug_counters.format_counter(&counter_kind), + ) + } else { + format!( + "{:?}: {}", + target_bcb, + debug_counters.format_counter(&counter_kind), + ) + } + }) + .collect::>() + .join("\n ") + )); + } + let mut file = create_dump_file(tcx, "dot", None, pass_name, &0, mir_source) + .expect("Unexpected error creating BasicCoverageBlock graphviz DOT file"); + graphviz_writer + .write_graphviz(tcx, &mut file) + .expect("Unexpected error writing BasicCoverageBlock graphviz DOT file"); +} + +fn bcb_to_string_sections( + tcx: TyCtxt<'tcx>, + mir_body: &mir::Body<'tcx>, + debug_counters: &DebugCounters, + bcb_data: &BasicCoverageBlockData, + some_coverage_spans_with_counters: Option<&Vec<(CoverageSpan, CoverageKind)>>, + some_dependency_counters: Option<&Vec>, + some_intermediate_expressions: Option<&Vec>, +) -> Vec { + let len = bcb_data.basic_blocks.len(); + let mut sections = Vec::new(); + if let Some(collect_intermediate_expressions) = some_intermediate_expressions { + sections.push( + collect_intermediate_expressions + .iter() + .map(|expression| { + format!("Intermediate {}", debug_counters.format_counter(expression)) + }) + .collect::>() + .join("\n"), + ); + } + if let Some(coverage_spans_with_counters) = some_coverage_spans_with_counters { + sections.push( + coverage_spans_with_counters + .iter() + .map(|(covspan, counter)| { + format!( + "{} at {}", + debug_counters.format_counter(counter), + covspan.format(tcx, mir_body) + ) + }) + .collect::>() + .join("\n"), + ); + } + if let Some(dependency_counters) = some_dependency_counters { + sections.push(format!( + "Non-coverage counters:\n {}", + dependency_counters + .iter() + .map(|counter| debug_counters.format_counter(counter)) + .collect::>() + .join(" \n"), + )); + } + if let Some(counter_kind) = &bcb_data.counter_kind { + sections.push(format!("{:?}", counter_kind)); + } + let non_term_blocks = bcb_data.basic_blocks[0..len - 1] + .iter() + .map(|&bb| format!("{:?}: {}", bb, term_type(&mir_body[bb].terminator().kind))) + .collect::>(); + if non_term_blocks.len() > 0 { + sections.push(non_term_blocks.join("\n")); + } + sections.push(format!( + "{:?}: {}", + bcb_data.basic_blocks.last().unwrap(), + term_type(&bcb_data.terminator(mir_body).kind) + )); + sections +} + +/// Returns a simple string representation of a `TerminatorKind` variant, independent of any +/// values it might hold. +pub(super) fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str { + match kind { + TerminatorKind::Goto { .. } => "Goto", + TerminatorKind::SwitchInt { .. } => "SwitchInt", + TerminatorKind::Resume => "Resume", + TerminatorKind::Abort => "Abort", + TerminatorKind::Return => "Return", + TerminatorKind::Unreachable => "Unreachable", + TerminatorKind::Drop { .. } => "Drop", + TerminatorKind::DropAndReplace { .. } => "DropAndReplace", + TerminatorKind::Call { .. } => "Call", + TerminatorKind::Assert { .. } => "Assert", + TerminatorKind::Yield { .. } => "Yield", + TerminatorKind::GeneratorDrop => "GeneratorDrop", + TerminatorKind::FalseEdge { .. } => "FalseEdge", + TerminatorKind::FalseUnwind { .. } => "FalseUnwind", + TerminatorKind::InlineAsm { .. } => "InlineAsm", + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/graph.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/graph.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,769 @@ +use super::Error; + +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::graph::dominators::{self, Dominators}; +use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode}; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::coverage::*; +use rustc_middle::mir::{self, BasicBlock, BasicBlockData, Terminator, TerminatorKind}; + +use std::ops::{Index, IndexMut}; + +const ID_SEPARATOR: &str = ","; + +/// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s +/// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s, plus a +/// `CoverageKind` counter (to be added by `CoverageCounters::make_bcb_counters`), and an optional +/// set of additional counters--if needed--to count incoming edges, if there are more than one. +/// (These "edge counters" are eventually converted into new MIR `BasicBlock`s.) +#[derive(Debug)] +pub(super) struct CoverageGraph { + bcbs: IndexVec, + bb_to_bcb: IndexVec>, + pub successors: IndexVec>, + pub predecessors: IndexVec>, + dominators: Option>, +} + +impl CoverageGraph { + pub fn from_mir(mir_body: &mir::Body<'tcx>) -> Self { + let (bcbs, bb_to_bcb) = Self::compute_basic_coverage_blocks(mir_body); + + // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock + // equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the + // each predecessor of a BCB leader_bb should be in a unique BCB. It is possible for a + // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so + // de-duplication is required. This is done without reordering the successors. + + let bcbs_len = bcbs.len(); + let mut seen = IndexVec::from_elem_n(false, bcbs_len); + let successors = IndexVec::from_fn_n( + |bcb| { + for b in seen.iter_mut() { + *b = false; + } + let bcb_data = &bcbs[bcb]; + let mut bcb_successors = Vec::new(); + for successor in + bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind) + .filter_map(|&successor_bb| bb_to_bcb[successor_bb]) + { + if !seen[successor] { + seen[successor] = true; + bcb_successors.push(successor); + } + } + bcb_successors + }, + bcbs.len(), + ); + + let mut predecessors = IndexVec::from_elem_n(Vec::new(), bcbs.len()); + for (bcb, bcb_successors) in successors.iter_enumerated() { + for &successor in bcb_successors { + predecessors[successor].push(bcb); + } + } + + let mut basic_coverage_blocks = + Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None }; + let dominators = dominators::dominators(&basic_coverage_blocks); + basic_coverage_blocks.dominators = Some(dominators); + basic_coverage_blocks + } + + fn compute_basic_coverage_blocks( + mir_body: &mir::Body<'tcx>, + ) -> ( + IndexVec, + IndexVec>, + ) { + let num_basic_blocks = mir_body.num_nodes(); + let mut bcbs = IndexVec::with_capacity(num_basic_blocks); + let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks); + + // Walk the MIR CFG using a Preorder traversal, which starts from `START_BLOCK` and follows + // each block terminator's `successors()`. Coverage spans must map to actual source code, + // so compiler generated blocks and paths can be ignored. To that end, the CFG traversal + // intentionally omits unwind paths. + // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and + // `catch_unwind()` handlers. + let mir_cfg_without_unwind = ShortCircuitPreorder::new(&mir_body, bcb_filtered_successors); + + let mut basic_blocks = Vec::new(); + for (bb, data) in mir_cfg_without_unwind { + if let Some(last) = basic_blocks.last() { + let predecessors = &mir_body.predecessors()[bb]; + if predecessors.len() > 1 || !predecessors.contains(last) { + // The `bb` has more than one _incoming_ edge, and should start its own + // `BasicCoverageBlockData`. (Note, the `basic_blocks` vector does not yet + // include `bb`; it contains a sequence of one or more sequential basic_blocks + // with no intermediate branches in or out. Save these as a new + // `BasicCoverageBlockData` before starting the new one.) + Self::add_basic_coverage_block( + &mut bcbs, + &mut bb_to_bcb, + basic_blocks.split_off(0), + ); + debug!( + " because {}", + if predecessors.len() > 1 { + "predecessors.len() > 1".to_owned() + } else { + format!("bb {} is not in precessors: {:?}", bb.index(), predecessors) + } + ); + } + } + basic_blocks.push(bb); + + let term = data.terminator(); + + match term.kind { + TerminatorKind::Return { .. } + | TerminatorKind::Abort + | TerminatorKind::Yield { .. } + | TerminatorKind::SwitchInt { .. } => { + // The `bb` has more than one _outgoing_ edge, or exits the function. Save the + // current sequence of `basic_blocks` gathered to this point, as a new + // `BasicCoverageBlockData`. + Self::add_basic_coverage_block( + &mut bcbs, + &mut bb_to_bcb, + basic_blocks.split_off(0), + ); + debug!(" because term.kind = {:?}", term.kind); + // Note that this condition is based on `TerminatorKind`, even though it + // theoretically boils down to `successors().len() != 1`; that is, either zero + // (e.g., `Return`, `Abort`) or multiple successors (e.g., `SwitchInt`), but + // since the BCB CFG ignores things like unwind branches (which exist in the + // `Terminator`s `successors()` list) checking the number of successors won't + // work. + } + + // The following `TerminatorKind`s are either not expected outside an unwind branch, + // or they should not (under normal circumstances) branch. Coverage graphs are + // simplified by assuring coverage results are accurate for program executions that + // don't panic. + // + // Programs that panic and unwind may record slightly inaccurate coverage results + // for a coverage region containing the `Terminator` that began the panic. This + // is as intended. (See Issue #78544 for a possible future option to support + // coverage in test programs that panic.) + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Assert { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => {} + } + } + + if !basic_blocks.is_empty() { + // process any remaining basic_blocks into a final `BasicCoverageBlockData` + Self::add_basic_coverage_block(&mut bcbs, &mut bb_to_bcb, basic_blocks.split_off(0)); + debug!(" because the end of the MIR CFG was reached while traversing"); + } + + (bcbs, bb_to_bcb) + } + + fn add_basic_coverage_block( + bcbs: &mut IndexVec, + bb_to_bcb: &mut IndexVec>, + basic_blocks: Vec, + ) { + let bcb = BasicCoverageBlock::from_usize(bcbs.len()); + for &bb in basic_blocks.iter() { + bb_to_bcb[bb] = Some(bcb); + } + let bcb_data = BasicCoverageBlockData::from(basic_blocks); + debug!("adding bcb{}: {:?}", bcb.index(), bcb_data); + bcbs.push(bcb_data); + } + + #[inline(always)] + pub fn iter_enumerated( + &self, + ) -> impl Iterator { + self.bcbs.iter_enumerated() + } + + #[inline(always)] + pub fn iter_enumerated_mut( + &mut self, + ) -> impl Iterator { + self.bcbs.iter_enumerated_mut() + } + + #[inline(always)] + pub fn bcb_from_bb(&self, bb: BasicBlock) -> Option { + if bb.index() < self.bb_to_bcb.len() { self.bb_to_bcb[bb] } else { None } + } + + #[inline(always)] + pub fn is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool { + self.dominators.as_ref().unwrap().is_dominated_by(node, dom) + } + + #[inline(always)] + pub fn dominators(&self) -> &Dominators { + self.dominators.as_ref().unwrap() + } +} + +impl Index for CoverageGraph { + type Output = BasicCoverageBlockData; + + #[inline] + fn index(&self, index: BasicCoverageBlock) -> &BasicCoverageBlockData { + &self.bcbs[index] + } +} + +impl IndexMut for CoverageGraph { + #[inline] + fn index_mut(&mut self, index: BasicCoverageBlock) -> &mut BasicCoverageBlockData { + &mut self.bcbs[index] + } +} + +impl graph::DirectedGraph for CoverageGraph { + type Node = BasicCoverageBlock; +} + +impl graph::WithNumNodes for CoverageGraph { + #[inline] + fn num_nodes(&self) -> usize { + self.bcbs.len() + } +} + +impl graph::WithStartNode for CoverageGraph { + #[inline] + fn start_node(&self) -> Self::Node { + self.bcb_from_bb(mir::START_BLOCK) + .expect("mir::START_BLOCK should be in a BasicCoverageBlock") + } +} + +type BcbSuccessors<'graph> = std::slice::Iter<'graph, BasicCoverageBlock>; + +impl<'graph> graph::GraphSuccessors<'graph> for CoverageGraph { + type Item = BasicCoverageBlock; + type Iter = std::iter::Cloned>; +} + +impl graph::WithSuccessors for CoverageGraph { + #[inline] + fn successors(&self, node: Self::Node) -> >::Iter { + self.successors[node].iter().cloned() + } +} + +impl graph::GraphPredecessors<'graph> for CoverageGraph { + type Item = BasicCoverageBlock; + type Iter = std::iter::Copied>; +} + +impl graph::WithPredecessors for CoverageGraph { + #[inline] + fn predecessors(&self, node: Self::Node) -> >::Iter { + self.predecessors[node].iter().copied() + } +} + +rustc_index::newtype_index! { + /// A node in the [control-flow graph][CFG] of CoverageGraph. + pub(super) struct BasicCoverageBlock { + DEBUG_FORMAT = "bcb{}", + const START_BCB = 0, + } +} + +/// `BasicCoverageBlockData` holds the data indexed by a `BasicCoverageBlock`. +/// +/// A `BasicCoverageBlock` (BCB) represents the maximal-length sequence of MIR `BasicBlock`s without +/// conditional branches, and form a new, simplified, coverage-specific Control Flow Graph, without +/// altering the original MIR CFG. +/// +/// Note that running the MIR `SimplifyCfg` transform is not sufficient (and therefore not +/// necessary). The BCB-based CFG is a more aggressive simplification. For example: +/// +/// * The BCB CFG ignores (trims) branches not relevant to coverage, such as unwind-related code, +/// that is injected by the Rust compiler but has no physical source code to count. This also +/// means a BasicBlock with a `Call` terminator can be merged into its primary successor target +/// block, in the same BCB. (But, note: Issue #78544: "MIR InstrumentCoverage: Improve coverage +/// of `#[should_panic]` tests and `catch_unwind()` handlers") +/// * Some BasicBlock terminators support Rust-specific concerns--like borrow-checking--that are +/// not relevant to coverage analysis. `FalseUnwind`, for example, can be treated the same as +/// a `Goto`, and merged with its successor into the same BCB. +/// +/// Each BCB with at least one computed `CoverageSpan` will have no more than one `Counter`. +/// In some cases, a BCB's execution count can be computed by `Expression`. Additional +/// disjoint `CoverageSpan`s in a BCB can also be counted by `Expression` (by adding `ZERO` +/// to the BCB's primary counter or expression). +/// +/// The BCB CFG is critical to simplifying the coverage analysis by ensuring graph path-based +/// queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch (control flow) +/// significance. +#[derive(Debug, Clone)] +pub(super) struct BasicCoverageBlockData { + pub basic_blocks: Vec, + pub counter_kind: Option, + edge_from_bcbs: Option>, +} + +impl BasicCoverageBlockData { + pub fn from(basic_blocks: Vec) -> Self { + assert!(basic_blocks.len() > 0); + Self { basic_blocks, counter_kind: None, edge_from_bcbs: None } + } + + #[inline(always)] + pub fn leader_bb(&self) -> BasicBlock { + self.basic_blocks[0] + } + + #[inline(always)] + pub fn last_bb(&self) -> BasicBlock { + *self.basic_blocks.last().unwrap() + } + + #[inline(always)] + pub fn terminator<'a, 'tcx>(&self, mir_body: &'a mir::Body<'tcx>) -> &'a Terminator<'tcx> { + &mir_body[self.last_bb()].terminator() + } + + pub fn set_counter( + &mut self, + counter_kind: CoverageKind, + ) -> Result { + debug_assert!( + // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also + // have an expression (to be injected into an existing `BasicBlock` represented by this + // `BasicCoverageBlock`). + self.edge_from_bcbs.is_none() || counter_kind.is_expression(), + "attempt to add a `Counter` to a BCB target with existing incoming edge counters" + ); + let operand = counter_kind.as_operand_id(); + if let Some(replaced) = self.counter_kind.replace(counter_kind) { + Error::from_string(format!( + "attempt to set a BasicCoverageBlock coverage counter more than once; \ + {:?} already had counter {:?}", + self, replaced, + )) + } else { + Ok(operand) + } + } + + #[inline(always)] + pub fn counter(&self) -> Option<&CoverageKind> { + self.counter_kind.as_ref() + } + + #[inline(always)] + pub fn take_counter(&mut self) -> Option { + self.counter_kind.take() + } + + pub fn set_edge_counter_from( + &mut self, + from_bcb: BasicCoverageBlock, + counter_kind: CoverageKind, + ) -> Result { + if level_enabled!(tracing::Level::DEBUG) { + // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also + // have an expression (to be injected into an existing `BasicBlock` represented by this + // `BasicCoverageBlock`). + if !self.counter_kind.as_ref().map_or(true, |c| c.is_expression()) { + return Error::from_string(format!( + "attempt to add an incoming edge counter from {:?} when the target BCB already \ + has a `Counter`", + from_bcb + )); + } + } + let operand = counter_kind.as_operand_id(); + if let Some(replaced) = + self.edge_from_bcbs.get_or_insert_default().insert(from_bcb, counter_kind) + { + Error::from_string(format!( + "attempt to set an edge counter more than once; from_bcb: \ + {:?} already had counter {:?}", + from_bcb, replaced, + )) + } else { + Ok(operand) + } + } + + #[inline] + pub fn edge_counter_from(&self, from_bcb: BasicCoverageBlock) -> Option<&CoverageKind> { + if let Some(edge_from_bcbs) = &self.edge_from_bcbs { + edge_from_bcbs.get(&from_bcb) + } else { + None + } + } + + #[inline] + pub fn take_edge_counters( + &mut self, + ) -> Option> { + self.edge_from_bcbs.take().map_or(None, |m| Some(m.into_iter())) + } + + pub fn id(&self) -> String { + format!( + "@{}", + self.basic_blocks + .iter() + .map(|bb| bb.index().to_string()) + .collect::>() + .join(ID_SEPARATOR) + ) + } +} + +/// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`) +/// as either the successor BCB itself, if it has only one incoming edge, or the successor _plus_ +/// the specific branching BCB, representing the edge between the two. The latter case +/// distinguishes this incoming edge from other incoming edges to the same `target_bcb`. +#[derive(Clone, Copy, PartialEq, Eq)] +pub(super) struct BcbBranch { + pub edge_from_bcb: Option, + pub target_bcb: BasicCoverageBlock, +} + +impl BcbBranch { + pub fn from_to( + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, + basic_coverage_blocks: &CoverageGraph, + ) -> Self { + let edge_from_bcb = if basic_coverage_blocks.predecessors[to_bcb].len() > 1 { + Some(from_bcb) + } else { + None + }; + Self { edge_from_bcb, target_bcb: to_bcb } + } + + pub fn counter<'a>( + &self, + basic_coverage_blocks: &'a CoverageGraph, + ) -> Option<&'a CoverageKind> { + if let Some(from_bcb) = self.edge_from_bcb { + basic_coverage_blocks[self.target_bcb].edge_counter_from(from_bcb) + } else { + basic_coverage_blocks[self.target_bcb].counter() + } + } + + pub fn is_only_path_to_target(&self) -> bool { + self.edge_from_bcb.is_none() + } +} + +impl std::fmt::Debug for BcbBranch { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(from_bcb) = self.edge_from_bcb { + write!(fmt, "{:?}->{:?}", from_bcb, self.target_bcb) + } else { + write!(fmt, "{:?}", self.target_bcb) + } + } +} + +// Returns the `Terminator`s non-unwind successors. +// FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and +// `catch_unwind()` handlers. +fn bcb_filtered_successors<'a, 'tcx>( + body: &'tcx &'a mir::Body<'tcx>, + term_kind: &'tcx TerminatorKind<'tcx>, +) -> Box + 'a> { + let mut successors = term_kind.successors(); + Box::new( + match &term_kind { + // SwitchInt successors are never unwind, and all of them should be traversed. + TerminatorKind::SwitchInt { .. } => successors, + // For all other kinds, return only the first successor, if any, and ignore unwinds. + // NOTE: `chain(&[])` is required to coerce the `option::iter` (from + // `next().into_iter()`) into the `mir::Successors` aliased type. + _ => successors.next().into_iter().chain(&[]), + } + .filter(move |&&successor| { + body[successor].terminator().kind != TerminatorKind::Unreachable + }), + ) +} + +/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the +/// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that +/// ensures a loop is completely traversed before processing Blocks after the end of the loop. +#[derive(Debug)] +pub(super) struct TraversalContext { + /// From one or more backedges returning to a loop header. + pub loop_backedges: Option<(Vec, BasicCoverageBlock)>, + + /// worklist, to be traversed, of CoverageGraph in the loop with the given loop + /// backedges, such that the loop is the inner inner-most loop containing these + /// CoverageGraph + pub worklist: Vec, +} + +pub(super) struct TraverseCoverageGraphWithLoops { + pub backedges: IndexVec>, + pub context_stack: Vec, + visited: BitSet, +} + +impl TraverseCoverageGraphWithLoops { + pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self { + let start_bcb = basic_coverage_blocks.start_node(); + let backedges = find_loop_backedges(basic_coverage_blocks); + let context_stack = + vec![TraversalContext { loop_backedges: None, worklist: vec![start_bcb] }]; + // `context_stack` starts with a `TraversalContext` for the main function context (beginning + // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top + // of the stack as loops are entered, and popped off of the stack when a loop's worklist is + // exhausted. + let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes()); + Self { backedges, context_stack, visited } + } + + pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option { + debug!( + "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", + self.context_stack.iter().rev().collect::>() + ); + while let Some(next_bcb) = { + // Strip contexts with empty worklists from the top of the stack + while self.context_stack.last().map_or(false, |context| context.worklist.is_empty()) { + self.context_stack.pop(); + } + // Pop the next bcb off of the current context_stack. If none, all BCBs were visited. + self.context_stack.last_mut().map_or(None, |context| context.worklist.pop()) + } { + if !self.visited.insert(next_bcb) { + debug!("Already visited: {:?}", next_bcb); + continue; + } + debug!("Visiting {:?}", next_bcb); + if self.backedges[next_bcb].len() > 0 { + debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb); + self.context_stack.push(TraversalContext { + loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)), + worklist: Vec::new(), + }); + } + self.extend_worklist(basic_coverage_blocks, next_bcb); + return Some(next_bcb); + } + None + } + + pub fn extend_worklist( + &mut self, + basic_coverage_blocks: &CoverageGraph, + bcb: BasicCoverageBlock, + ) { + let successors = &basic_coverage_blocks.successors[bcb]; + debug!("{:?} has {} successors:", bcb, successors.len()); + for &successor in successors { + if successor == bcb { + debug!( + "{:?} has itself as its own successor. (Note, the compiled code will \ + generate an infinite loop.)", + bcb + ); + // Don't re-add this successor to the worklist. We are already processing it. + break; + } + for context in self.context_stack.iter_mut().rev() { + // Add successors of the current BCB to the appropriate context. Successors that + // stay within a loop are added to the BCBs context worklist. Successors that + // exit the loop (they are not dominated by the loop header) must be reachable + // from other BCBs outside the loop, and they will be added to a different + // worklist. + // + // Branching blocks (with more than one successor) must be processed before + // blocks with only one successor, to prevent unnecessarily complicating + // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the + // branching block would have given an `Expression` (or vice versa). + let (some_successor_to_add, some_loop_header) = + if let Some((_, loop_header)) = context.loop_backedges { + if basic_coverage_blocks.is_dominated_by(successor, loop_header) { + (Some(successor), Some(loop_header)) + } else { + (None, None) + } + } else { + (Some(successor), None) + }; + if let Some(successor_to_add) = some_successor_to_add { + if basic_coverage_blocks.successors[successor_to_add].len() > 1 { + debug!( + "{:?} successor is branching. Prioritize it at the beginning of \ + the {}", + successor_to_add, + if let Some(loop_header) = some_loop_header { + format!("worklist for the loop headed by {:?}", loop_header) + } else { + String::from("non-loop worklist") + }, + ); + context.worklist.insert(0, successor_to_add); + } else { + debug!( + "{:?} successor is non-branching. Defer it to the end of the {}", + successor_to_add, + if let Some(loop_header) = some_loop_header { + format!("worklist for the loop headed by {:?}", loop_header) + } else { + String::from("non-loop worklist") + }, + ); + context.worklist.push(successor_to_add); + } + break; + } + } + } + } + + pub fn is_complete(&self) -> bool { + self.visited.count() == self.visited.domain_size() + } + + pub fn unvisited(&self) -> Vec { + let mut unvisited_set: BitSet = + BitSet::new_filled(self.visited.domain_size()); + unvisited_set.subtract(&self.visited); + unvisited_set.iter().collect::>() + } +} + +pub(super) fn find_loop_backedges( + basic_coverage_blocks: &CoverageGraph, +) -> IndexVec> { + let num_bcbs = basic_coverage_blocks.num_nodes(); + let mut backedges = IndexVec::from_elem_n(Vec::::new(), num_bcbs); + + // Identify loops by their backedges. + // + // The computational complexity is bounded by: n(s) x d where `n` is the number of + // `BasicCoverageBlock` nodes (the simplified/reduced representation of the CFG derived from the + // MIR); `s` is the average number of successors per node (which is most likely less than 2, and + // independent of the size of the function, so it can be treated as a constant); + // and `d` is the average number of dominators per node. + // + // The average number of dominators depends on the size and complexity of the function, and + // nodes near the start of the function's control flow graph typically have less dominators + // than nodes near the end of the CFG. Without doing a detailed mathematical analysis, I + // think the resulting complexity has the characteristics of O(n log n). + // + // The overall complexity appears to be comparable to many other MIR transform algorithms, and I + // don't expect that this function is creating a performance hot spot, but if this becomes an + // issue, there may be ways to optimize the `is_dominated_by` algorithm (as indicated by an + // existing `FIXME` comment in that code), or possibly ways to optimize it's usage here, perhaps + // by keeping track of results for visited `BasicCoverageBlock`s if they can be used to short + // circuit downstream `is_dominated_by` checks. + // + // For now, that kind of optimization seems unnecessarily complicated. + for (bcb, _) in basic_coverage_blocks.iter_enumerated() { + for &successor in &basic_coverage_blocks.successors[bcb] { + if basic_coverage_blocks.is_dominated_by(bcb, successor) { + let loop_header = successor; + let backedge_from_bcb = bcb; + debug!( + "Found BCB backedge: {:?} -> loop_header: {:?}", + backedge_from_bcb, loop_header + ); + backedges[loop_header].push(backedge_from_bcb); + } + } + } + backedges +} + +pub struct ShortCircuitPreorder< + 'a, + 'tcx, + F: Fn( + &'tcx &'a mir::Body<'tcx>, + &'tcx TerminatorKind<'tcx>, + ) -> Box + 'a>, +> { + body: &'tcx &'a mir::Body<'tcx>, + visited: BitSet, + worklist: Vec, + filtered_successors: F, +} + +impl< + 'a, + 'tcx, + F: Fn( + &'tcx &'a mir::Body<'tcx>, + &'tcx TerminatorKind<'tcx>, + ) -> Box + 'a>, +> ShortCircuitPreorder<'a, 'tcx, F> +{ + pub fn new( + body: &'tcx &'a mir::Body<'tcx>, + filtered_successors: F, + ) -> ShortCircuitPreorder<'a, 'tcx, F> { + let worklist = vec![mir::START_BLOCK]; + + ShortCircuitPreorder { + body, + visited: BitSet::new_empty(body.basic_blocks().len()), + worklist, + filtered_successors, + } + } +} + +impl< + 'a: 'tcx, + 'tcx, + F: Fn( + &'tcx &'a mir::Body<'tcx>, + &'tcx TerminatorKind<'tcx>, + ) -> Box + 'a>, +> Iterator for ShortCircuitPreorder<'a, 'tcx, F> +{ + type Item = (BasicBlock, &'a BasicBlockData<'tcx>); + + fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { + while let Some(idx) = self.worklist.pop() { + if !self.visited.insert(idx) { + continue; + } + + let data = &self.body[idx]; + + if let Some(ref term) = data.terminator { + self.worklist.extend((self.filtered_successors)(&self.body, &term.kind)); + } + + return Some((idx, data)); + } + + None + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.body.basic_blocks().len() - self.visited.count(); + (size, Some(size)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,588 @@ +pub mod query; + +mod counters; +mod debug; +mod graph; +mod spans; + +#[cfg(test)] +mod tests; + +use counters::CoverageCounters; +use graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use spans::{CoverageSpan, CoverageSpans}; + +use crate::MirPass; + +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::graph::WithNumNodes; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::Lrc; +use rustc_index::vec::IndexVec; +use rustc_middle::hir; +use rustc_middle::hir::map::blocks::FnLikeNode; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::coverage::*; +use rustc_middle::mir::dump_enabled; +use rustc_middle::mir::{ + self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator, + TerminatorKind, +}; +use rustc_middle::ty::TyCtxt; +use rustc_query_system::ich::StableHashingContext; +use rustc_span::def_id::DefId; +use rustc_span::source_map::SourceMap; +use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol}; + +/// A simple error message wrapper for `coverage::Error`s. +#[derive(Debug)] +struct Error { + message: String, +} + +impl Error { + pub fn from_string(message: String) -> Result { + Err(Self { message }) + } +} + +/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected +/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen +/// to construct the coverage map. +pub struct InstrumentCoverage; + +impl<'tcx> MirPass<'tcx> for InstrumentCoverage { + fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { + let mir_source = mir_body.source; + + // If the InstrumentCoverage pass is called on promoted MIRs, skip them. + // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601 + if mir_source.promoted.is_some() { + trace!( + "InstrumentCoverage skipped for {:?} (already promoted for Miri evaluation)", + mir_source.def_id() + ); + return; + } + + let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local()); + let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + + // Only instrument functions, methods, and closures (not constants since they are evaluated + // at compile time by Miri). + // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const + // expressions get coverage spans, we will probably have to "carve out" space for const + // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might + // be tricky if const expressions have no corresponding statements in the enclosing MIR. + // Closures are carved out by their initial `Assign` statement.) + if !is_fn_like { + trace!("InstrumentCoverage skipped for {:?} (not an FnLikeNode)", mir_source.def_id()); + return; + } + + match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind { + TerminatorKind::Unreachable => { + trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`"); + return; + } + _ => {} + } + + let codegen_fn_attrs = tcx.codegen_fn_attrs(mir_source.def_id()); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + return; + } + + trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); + Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); + trace!("InstrumentCoverage done for {:?}", mir_source.def_id()); + } +} + +struct Instrumentor<'a, 'tcx> { + pass_name: &'a str, + tcx: TyCtxt<'tcx>, + mir_body: &'a mut mir::Body<'tcx>, + source_file: Lrc, + fn_sig_span: Span, + body_span: Span, + basic_coverage_blocks: CoverageGraph, + coverage_counters: CoverageCounters, +} + +impl<'a, 'tcx> Instrumentor<'a, 'tcx> { + fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { + let source_map = tcx.sess.source_map(); + let def_id = mir_body.source.def_id(); + let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id); + + let body_span = get_body_span(tcx, hir_body, mir_body); + + let source_file = source_map.lookup_source_file(body_span.lo()); + let fn_sig_span = match some_fn_sig.filter(|fn_sig| { + fn_sig.span.ctxt() == body_span.ctxt() + && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo())) + }) { + Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), + None => body_span.shrink_to_lo(), + }; + + debug!( + "instrumenting {}: {:?}, fn sig span: {:?}, body span: {:?}", + if tcx.is_closure(def_id) { "closure" } else { "function" }, + def_id, + fn_sig_span, + body_span + ); + + let function_source_hash = hash_mir_source(tcx, hir_body); + let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); + Self { + pass_name, + tcx, + mir_body, + source_file, + fn_sig_span, + body_span, + basic_coverage_blocks, + coverage_counters: CoverageCounters::new(function_source_hash), + } + } + + fn inject_counters(&'a mut self) { + let tcx = self.tcx; + let mir_source = self.mir_body.source; + let def_id = mir_source.def_id(); + let fn_sig_span = self.fn_sig_span; + let body_span = self.body_span; + + let mut graphviz_data = debug::GraphvizData::new(); + let mut debug_used_expressions = debug::UsedExpressions::new(); + + let dump_mir = dump_enabled(tcx, self.pass_name, def_id); + let dump_graphviz = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_graphviz; + let dump_spanview = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_spanview.is_some(); + + if dump_graphviz { + graphviz_data.enable(); + self.coverage_counters.enable_debug(); + } + + if dump_graphviz || level_enabled!(tracing::Level::DEBUG) { + debug_used_expressions.enable(); + } + + //////////////////////////////////////////////////// + // Compute `CoverageSpan`s from the `CoverageGraph`. + let coverage_spans = CoverageSpans::generate_coverage_spans( + &self.mir_body, + fn_sig_span, + body_span, + &self.basic_coverage_blocks, + ); + + if dump_spanview { + debug::dump_coverage_spanview( + tcx, + self.mir_body, + &self.basic_coverage_blocks, + self.pass_name, + body_span, + &coverage_spans, + ); + } + + //////////////////////////////////////////////////// + // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure + // every `CoverageSpan` has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` + // and all `Expression` dependencies (operands) are also generated, for any other + // `BasicCoverageBlock`s not already associated with a `CoverageSpan`. + // + // Intermediate expressions (used to compute other `Expression` values), which have no + // direct associate to any `BasicCoverageBlock`, are returned in the method `Result`. + let intermediate_expressions_or_error = self + .coverage_counters + .make_bcb_counters(&mut self.basic_coverage_blocks, &coverage_spans); + + let (result, intermediate_expressions) = match intermediate_expressions_or_error { + Ok(intermediate_expressions) => { + // If debugging, add any intermediate expressions (which are not associated with any + // BCB) to the `debug_used_expressions` map. + if debug_used_expressions.is_enabled() { + for intermediate_expression in &intermediate_expressions { + debug_used_expressions.add_expression_operands(intermediate_expression); + } + } + + //////////////////////////////////////////////////// + // Remove the counter or edge counter from of each `CoverageSpan`s associated + // `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR. + // + // `Coverage` statements injected from `CoverageSpan`s will include the code regions + // (source code start and end positions) to be counted by the associated counter. + // + // These `CoverageSpan`-associated counters are removed from their associated + // `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph` + // are indirect counters (to be injected next, without associated code regions). + self.inject_coverage_span_counters( + coverage_spans, + &mut graphviz_data, + &mut debug_used_expressions, + ); + + //////////////////////////////////////////////////// + // For any remaining `BasicCoverageBlock` counters (that were not associated with + // any `CoverageSpan`), inject `Coverage` statements (_without_ code region `Span`s) + // to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on + // are in fact counted, even though they don't directly contribute to counting + // their own independent code region's coverage. + self.inject_indirect_counters(&mut graphviz_data, &mut debug_used_expressions); + + // Intermediate expressions will be injected as the final step, after generating + // debug output, if any. + //////////////////////////////////////////////////// + + (Ok(()), intermediate_expressions) + } + Err(e) => (Err(e), Vec::new()), + }; + + if graphviz_data.is_enabled() { + // Even if there was an error, a partial CoverageGraph can still generate a useful + // graphviz output. + debug::dump_coverage_graphviz( + tcx, + self.mir_body, + self.pass_name, + &self.basic_coverage_blocks, + &self.coverage_counters.debug_counters, + &graphviz_data, + &intermediate_expressions, + &debug_used_expressions, + ); + } + + if let Err(e) = result { + bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message) + }; + + // Depending on current `debug_options()`, `alert_on_unused_expressions()` could panic, so + // this check is performed as late as possible, to allow other debug output (logs and dump + // files), which might be helpful in analyzing unused expressions, to still be generated. + debug_used_expressions.alert_on_unused_expressions(&self.coverage_counters.debug_counters); + + //////////////////////////////////////////////////// + // Finally, inject the intermediate expressions collected along the way. + for intermediate_expression in intermediate_expressions { + inject_intermediate_expression(self.mir_body, intermediate_expression); + } + } + + /// Inject a counter for each `CoverageSpan`. There can be multiple `CoverageSpan`s for a given + /// BCB, but only one actual counter needs to be incremented per BCB. `bb_counters` maps each + /// `bcb` to its `Counter`, when injected. Subsequent `CoverageSpan`s for a BCB that already has + /// a `Counter` will inject an `Expression` instead, and compute its value by adding `ZERO` to + /// the BCB `Counter` value. + /// + /// If debugging, add every BCB `Expression` associated with a `CoverageSpan`s to the + /// `used_expression_operands` map. + fn inject_coverage_span_counters( + &mut self, + coverage_spans: Vec, + graphviz_data: &mut debug::GraphvizData, + debug_used_expressions: &mut debug::UsedExpressions, + ) { + let tcx = self.tcx; + let source_map = tcx.sess.source_map(); + let body_span = self.body_span; + let file_name = Symbol::intern(&self.source_file.name.prefer_remapped().to_string_lossy()); + + let mut bcb_counters = IndexVec::from_elem_n(None, self.basic_coverage_blocks.num_nodes()); + for covspan in coverage_spans { + let bcb = covspan.bcb; + let span = covspan.span; + let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() { + self.coverage_counters.make_identity_counter(counter_operand) + } else if let Some(counter_kind) = self.bcb_data_mut(bcb).take_counter() { + bcb_counters[bcb] = Some(counter_kind.as_operand_id()); + debug_used_expressions.add_expression_operands(&counter_kind); + counter_kind + } else { + bug!("Every BasicCoverageBlock should have a Counter or Expression"); + }; + graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind); + + debug!( + "Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})", + file_name, + self.source_file, + source_map.span_to_diagnostic_string(span), + source_map.span_to_diagnostic_string(body_span) + ); + + inject_statement( + self.mir_body, + counter_kind, + self.bcb_leader_bb(bcb), + Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)), + ); + } + } + + /// `inject_coverage_span_counters()` looped through the `CoverageSpan`s and injected the + /// counter from the `CoverageSpan`s `BasicCoverageBlock`, removing it from the BCB in the + /// process (via `take_counter()`). + /// + /// Any other counter associated with a `BasicCoverageBlock`, or its incoming edge, but not + /// associated with a `CoverageSpan`, should only exist if the counter is an `Expression` + /// dependency (one of the expression operands). Collect them, and inject the additional + /// counters into the MIR, without a reportable coverage span. + fn inject_indirect_counters( + &mut self, + graphviz_data: &mut debug::GraphvizData, + debug_used_expressions: &mut debug::UsedExpressions, + ) { + let mut bcb_counters_without_direct_coverage_spans = Vec::new(); + for (target_bcb, target_bcb_data) in self.basic_coverage_blocks.iter_enumerated_mut() { + if let Some(counter_kind) = target_bcb_data.take_counter() { + bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind)); + } + if let Some(edge_counters) = target_bcb_data.take_edge_counters() { + for (from_bcb, counter_kind) in edge_counters { + bcb_counters_without_direct_coverage_spans.push(( + Some(from_bcb), + target_bcb, + counter_kind, + )); + } + } + } + + // If debug is enabled, validate that every BCB or edge counter not directly associated + // with a coverage span is at least indirectly associated (it is a dependency of a BCB + // counter that _is_ associated with a coverage span). + debug_used_expressions.validate(&bcb_counters_without_direct_coverage_spans); + + for (edge_from_bcb, target_bcb, counter_kind) in bcb_counters_without_direct_coverage_spans + { + debug_used_expressions.add_unused_expression_if_not_found( + &counter_kind, + edge_from_bcb, + target_bcb, + ); + + match counter_kind { + CoverageKind::Counter { .. } => { + let inject_to_bb = if let Some(from_bcb) = edge_from_bcb { + // The MIR edge starts `from_bb` (the outgoing / last BasicBlock in + // `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the + // `target_bcb`; also called the `leader_bb`). + let from_bb = self.bcb_last_bb(from_bcb); + let to_bb = self.bcb_leader_bb(target_bcb); + + let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); + graphviz_data.set_edge_counter(from_bcb, new_bb, &counter_kind); + debug!( + "Edge {:?} (last {:?}) -> {:?} (leader {:?}) requires a new MIR \ + BasicBlock {:?}, for unclaimed edge counter {}", + edge_from_bcb, + from_bb, + target_bcb, + to_bb, + new_bb, + self.format_counter(&counter_kind), + ); + new_bb + } else { + let target_bb = self.bcb_last_bb(target_bcb); + graphviz_data.add_bcb_dependency_counter(target_bcb, &counter_kind); + debug!( + "{:?} ({:?}) gets a new Coverage statement for unclaimed counter {}", + target_bcb, + target_bb, + self.format_counter(&counter_kind), + ); + target_bb + }; + + inject_statement(self.mir_body, counter_kind, inject_to_bb, None); + } + CoverageKind::Expression { .. } => { + inject_intermediate_expression(self.mir_body, counter_kind) + } + _ => bug!("CoverageKind should be a counter"), + } + } + } + + #[inline] + fn bcb_leader_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock { + self.bcb_data(bcb).leader_bb() + } + + #[inline] + fn bcb_last_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock { + self.bcb_data(bcb).last_bb() + } + + #[inline] + fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData { + &self.basic_coverage_blocks[bcb] + } + + #[inline] + fn bcb_data_mut(&mut self, bcb: BasicCoverageBlock) -> &mut BasicCoverageBlockData { + &mut self.basic_coverage_blocks[bcb] + } + + #[inline] + fn format_counter(&self, counter_kind: &CoverageKind) -> String { + self.coverage_counters.debug_counters.format_counter(counter_kind) + } +} + +fn inject_edge_counter_basic_block( + mir_body: &mut mir::Body<'tcx>, + from_bb: BasicBlock, + to_bb: BasicBlock, +) -> BasicBlock { + let span = mir_body[from_bb].terminator().source_info.span.shrink_to_hi(); + let new_bb = mir_body.basic_blocks_mut().push(BasicBlockData { + statements: vec![], // counter will be injected here + terminator: Some(Terminator { + source_info: SourceInfo::outermost(span), + kind: TerminatorKind::Goto { target: to_bb }, + }), + is_cleanup: false, + }); + let edge_ref = mir_body[from_bb] + .terminator_mut() + .successors_mut() + .find(|successor| **successor == to_bb) + .expect("from_bb should have a successor for to_bb"); + *edge_ref = new_bb; + new_bb +} + +fn inject_statement( + mir_body: &mut mir::Body<'tcx>, + counter_kind: CoverageKind, + bb: BasicBlock, + some_code_region: Option, +) { + debug!( + " injecting statement {:?} for {:?} at code region: {:?}", + counter_kind, bb, some_code_region + ); + let data = &mut mir_body[bb]; + let source_info = data.terminator().source_info; + let statement = Statement { + source_info, + kind: StatementKind::Coverage(Box::new(Coverage { + kind: counter_kind, + code_region: some_code_region, + })), + }; + data.statements.insert(0, statement); +} + +// Non-code expressions are injected into the coverage map, without generating executable code. +fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: CoverageKind) { + debug_assert!(if let CoverageKind::Expression { .. } = expression { true } else { false }); + debug!(" injecting non-code expression {:?}", expression); + let inject_in_bb = mir::START_BLOCK; + let data = &mut mir_body[inject_in_bb]; + let source_info = data.terminator().source_info; + let statement = Statement { + source_info, + kind: StatementKind::Coverage(Box::new(Coverage { kind: expression, code_region: None })), + }; + data.statements.push(statement); +} + +/// Convert the Span into its file name, start line and column, and end line and column +fn make_code_region( + source_map: &SourceMap, + file_name: Symbol, + source_file: &Lrc, + span: Span, + body_span: Span, +) -> CodeRegion { + let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo()); + let (end_line, end_col) = if span.hi() == span.lo() { + let (end_line, mut end_col) = (start_line, start_col); + // Extend an empty span by one character so the region will be counted. + let CharPos(char_pos) = start_col; + if span.hi() == body_span.hi() { + start_col = CharPos(char_pos - 1); + } else { + end_col = CharPos(char_pos + 1); + } + (end_line, end_col) + } else { + source_file.lookup_file_pos(span.hi()) + }; + let start_line = source_map.doctest_offset_line(&source_file.name, start_line); + let end_line = source_map.doctest_offset_line(&source_file.name, end_line); + CodeRegion { + file_name, + start_line: start_line as u32, + start_col: start_col.to_u32() + 1, + end_line: end_line as u32, + end_col: end_col.to_u32() + 1, + } +} + +fn fn_sig_and_body<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) { + // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back + // to HIR for it. + let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); + let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id)) +} + +fn get_body_span<'tcx>( + tcx: TyCtxt<'tcx>, + hir_body: &rustc_hir::Body<'tcx>, + mir_body: &mut mir::Body<'tcx>, +) -> Span { + let mut body_span = hir_body.value.span; + let def_id = mir_body.source.def_id(); + + if tcx.is_closure(def_id) { + // If the MIR function is a closure, and if the closure body span + // starts from a macro, but it's content is not in that macro, try + // to find a non-macro callsite, and instrument the spans there + // instead. + loop { + let expn_data = body_span.ctxt().outer_expn_data(); + if expn_data.is_root() { + break; + } + if let ExpnKind::Macro { .. } = expn_data.kind { + body_span = expn_data.call_site; + } else { + break; + } + } + } + + body_span +} + +fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { + let mut hcx = tcx.create_no_span_stable_hashing_context(); + hash(&mut hcx, &hir_body.value).to_smaller_hash() +} + +fn hash( + hcx: &mut StableHashingContext<'tcx>, + node: &impl HashStable>, +) -> Fingerprint { + let mut stable_hasher = StableHasher::new(); + node.hash_stable(hcx, &mut stable_hasher); + stable_hasher.finish() +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/query.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/query.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/query.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/query.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,191 @@ +use super::*; + +use rustc_middle::mir::coverage::*; +use rustc_middle::mir::{self, Body, Coverage, CoverageInfo}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::DefId; + +/// A `query` provider for retrieving coverage information injected into MIR. +pub(crate) fn provide(providers: &mut Providers) { + providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id); + providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id); + providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id); +} + +/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in +/// other words, the number of counter value references injected into the MIR (plus 1 for the +/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected +/// counters have a counter ID from `1..num_counters-1`. +/// +/// `num_expressions` is the number of counter expressions added to the MIR body. +/// +/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend +/// code generate, to lookup counters and expressions by simple u32 indexes. +/// +/// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code +/// including injected counters. (It is OK if some counters are optimized out, but those counters +/// are still included in the total `num_counters` or `num_expressions`.) Simply counting the +/// calls may not work; but computing the number of counters or expressions by adding `1` to the +/// highest ID (for a given instrumented function) is valid. +/// +/// This visitor runs twice, first with `add_missing_operands` set to `false`, to find the maximum +/// counter ID and maximum expression ID based on their enum variant `id` fields; then, as a +/// safeguard, with `add_missing_operands` set to `true`, to find any other counter or expression +/// IDs referenced by expression operands, if not already seen. +/// +/// Ideally, each operand ID in a MIR `CoverageKind::Expression` will have a separate MIR `Coverage` +/// statement for the `Counter` or `Expression` with the referenced ID. but since current or future +/// MIR optimizations can theoretically optimize out segments of a MIR, it may not be possible to +/// guarantee this, so the second pass ensures the `CoverageInfo` counts include all referenced IDs. +struct CoverageVisitor { + info: CoverageInfo, + add_missing_operands: bool, +} + +impl CoverageVisitor { + /// Updates `num_counters` to the maximum encountered zero-based counter_id plus 1. Note the + /// final computed number of counters should be the number of all `CoverageKind::Counter` + /// statements in the MIR *plus one* for the implicit `ZERO` counter. + #[inline(always)] + fn update_num_counters(&mut self, counter_id: u32) { + self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); + } + + /// Computes an expression index for each expression ID, and updates `num_expressions` to the + /// maximum encountered index plus 1. + #[inline(always)] + fn update_num_expressions(&mut self, expression_id: u32) { + let expression_index = u32::MAX - expression_id; + self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1); + } + + fn update_from_expression_operand(&mut self, operand_id: u32) { + if operand_id >= self.info.num_counters { + let operand_as_expression_index = u32::MAX - operand_id; + if operand_as_expression_index >= self.info.num_expressions { + // The operand ID is outside the known range of counter IDs and also outside the + // known range of expression IDs. In either case, the result of a missing operand + // (if and when used in an expression) will be zero, so from a computation + // perspective, it doesn't matter whether it is interepretted as a counter or an + // expression. + // + // However, the `num_counters` and `num_expressions` query results are used to + // allocate arrays when generating the coverage map (during codegen), so choose + // the type that grows either `num_counters` or `num_expressions` the least. + if operand_id - self.info.num_counters + < operand_as_expression_index - self.info.num_expressions + { + self.update_num_counters(operand_id) + } else { + self.update_num_expressions(operand_id) + } + } + } + } + + fn visit_body(&mut self, body: &Body<'_>) { + for bb_data in body.basic_blocks().iter() { + for statement in bb_data.statements.iter() { + if let StatementKind::Coverage(box ref coverage) = statement.kind { + if is_inlined(body, statement) { + continue; + } + self.visit_coverage(coverage); + } + } + } + } + + fn visit_coverage(&mut self, coverage: &Coverage) { + if self.add_missing_operands { + match coverage.kind { + CoverageKind::Expression { lhs, rhs, .. } => { + self.update_from_expression_operand(u32::from(lhs)); + self.update_from_expression_operand(u32::from(rhs)); + } + _ => {} + } + } else { + match coverage.kind { + CoverageKind::Counter { id, .. } => { + self.update_num_counters(u32::from(id)); + } + CoverageKind::Expression { id, .. } => { + self.update_num_expressions(u32::from(id)); + } + _ => {} + } + } + } +} + +fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> CoverageInfo { + let mir_body = tcx.instance_mir(instance_def); + + let mut coverage_visitor = CoverageVisitor { + // num_counters always has at least the `ZERO` counter. + info: CoverageInfo { num_counters: 1, num_expressions: 0 }, + add_missing_operands: false, + }; + + coverage_visitor.visit_body(mir_body); + + coverage_visitor.add_missing_operands = true; + coverage_visitor.visit_body(mir_body); + + coverage_visitor.info +} + +fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { + if tcx.is_mir_available(def_id) { + let body = mir_body(tcx, def_id); + for bb_data in body.basic_blocks().iter() { + for statement in bb_data.statements.iter() { + if let StatementKind::Coverage(box ref coverage) = statement.kind { + if let Some(code_region) = coverage.code_region.as_ref() { + if is_inlined(body, statement) { + continue; + } + return Some(code_region.file_name); + } + } + } + } + } + return None; +} + +fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> { + let body = mir_body(tcx, def_id); + body.basic_blocks() + .iter() + .map(|data| { + data.statements.iter().filter_map(|statement| match statement.kind { + StatementKind::Coverage(box ref coverage) => { + if is_inlined(body, statement) { + None + } else { + coverage.code_region.as_ref() // may be None + } + } + _ => None, + }) + }) + .flatten() + .collect() +} + +fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { + let scope_data = &body.source_scopes[statement.source_info.scope]; + scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some() +} + +/// This function ensures we obtain the correct MIR for the given item irrespective of +/// whether that means const mir or runtime mir. For `const fn` this opts for runtime +/// mir. +fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> { + let id = ty::WithOptConstParam::unknown(def_id); + let def = ty::InstanceDef::Item(id); + tcx.instance_mir(def) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/spans.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/spans.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/spans.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/spans.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,902 @@ +use super::debug::term_type; +use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; + +use rustc_data_structures::graph::WithNumNodes; +use rustc_middle::mir::spanview::source_range_no_file; +use rustc_middle::mir::{ + self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, +}; +use rustc_middle::ty::TyCtxt; +use rustc_span::source_map::original_sp; +use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol}; + +use std::cell::RefCell; +use std::cmp::Ordering; + +#[derive(Debug, Copy, Clone)] +pub(super) enum CoverageStatement { + Statement(BasicBlock, Span, usize), + Terminator(BasicBlock, Span), +} + +impl CoverageStatement { + pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String { + match *self { + Self::Statement(bb, span, stmt_index) => { + let stmt = &mir_body[bb].statements[stmt_index]; + format!( + "{}: @{}[{}]: {:?}", + source_range_no_file(tcx, &span), + bb.index(), + stmt_index, + stmt + ) + } + Self::Terminator(bb, span) => { + let term = mir_body[bb].terminator(); + format!( + "{}: @{}.{}: {:?}", + source_range_no_file(tcx, &span), + bb.index(), + term_type(&term.kind), + term.kind + ) + } + } + } + + pub fn span(&self) -> &Span { + match self { + Self::Statement(_, span, _) | Self::Terminator(_, span) => span, + } + } +} + +/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that +/// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s. +/// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent +/// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the +/// `CoverageStatement` vectors, and the `Span`s to cover the extent of the combined `Span`s. +/// +/// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that +/// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches +/// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock` +/// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`. +#[derive(Debug, Clone)] +pub(super) struct CoverageSpan { + pub span: Span, + pub expn_span: Span, + pub current_macro_or_none: RefCell>>, + pub bcb: BasicCoverageBlock, + pub coverage_statements: Vec, + pub is_closure: bool, +} + +impl CoverageSpan { + pub fn for_fn_sig(fn_sig_span: Span) -> Self { + Self { + span: fn_sig_span, + expn_span: fn_sig_span, + current_macro_or_none: Default::default(), + bcb: START_BCB, + coverage_statements: vec![], + is_closure: false, + } + } + + pub fn for_statement( + statement: &Statement<'tcx>, + span: Span, + expn_span: Span, + bcb: BasicCoverageBlock, + bb: BasicBlock, + stmt_index: usize, + ) -> Self { + let is_closure = match statement.kind { + StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind { + AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true, + _ => false, + }, + _ => false, + }; + + Self { + span, + expn_span, + current_macro_or_none: Default::default(), + bcb, + coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)], + is_closure, + } + } + + pub fn for_terminator( + span: Span, + expn_span: Span, + bcb: BasicCoverageBlock, + bb: BasicBlock, + ) -> Self { + Self { + span, + expn_span, + current_macro_or_none: Default::default(), + bcb, + coverage_statements: vec![CoverageStatement::Terminator(bb, span)], + is_closure: false, + } + } + + pub fn merge_from(&mut self, mut other: CoverageSpan) { + debug_assert!(self.is_mergeable(&other)); + self.span = self.span.to(other.span); + self.coverage_statements.append(&mut other.coverage_statements); + } + + pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) { + self.coverage_statements.retain(|covstmt| covstmt.span().hi() <= cutoff_pos); + if let Some(highest_covstmt) = + self.coverage_statements.iter().max_by_key(|covstmt| covstmt.span().hi()) + { + self.span = self.span.with_hi(highest_covstmt.span().hi()); + } + } + + #[inline] + pub fn is_mergeable(&self, other: &Self) -> bool { + self.is_in_same_bcb(other) && !(self.is_closure || other.is_closure) + } + + #[inline] + pub fn is_in_same_bcb(&self, other: &Self) -> bool { + self.bcb == other.bcb + } + + pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String { + format!( + "{}\n {}", + source_range_no_file(tcx, &self.span), + self.format_coverage_statements(tcx, mir_body).replace("\n", "\n "), + ) + } + + pub fn format_coverage_statements( + &self, + tcx: TyCtxt<'tcx>, + mir_body: &'a mir::Body<'tcx>, + ) -> String { + let mut sorted_coverage_statements = self.coverage_statements.clone(); + sorted_coverage_statements.sort_unstable_by_key(|covstmt| match *covstmt { + CoverageStatement::Statement(bb, _, index) => (bb, index), + CoverageStatement::Terminator(bb, _) => (bb, usize::MAX), + }); + sorted_coverage_statements + .iter() + .map(|covstmt| covstmt.format(tcx, mir_body)) + .collect::>() + .join("\n") + } + + /// If the span is part of a macro, returns the macro name symbol. + pub fn current_macro(&self) -> Option { + self.current_macro_or_none + .borrow_mut() + .get_or_insert_with(|| { + if let ExpnKind::Macro(MacroKind::Bang, current_macro) = + self.expn_span.ctxt().outer_expn_data().kind + { + return Some(current_macro); + } + None + }) + .map(|symbol| symbol) + } + + /// If the span is part of a macro, and the macro is visible (expands directly to the given + /// body_span), returns the macro name symbol. + pub fn visible_macro(&self, body_span: Span) -> Option { + if let Some(current_macro) = self.current_macro() { + if self + .expn_span + .parent_callsite() + .unwrap_or_else(|| bug!("macro must have a parent")) + .ctxt() + == body_span.ctxt() + { + return Some(current_macro); + } + } + None + } + + pub fn is_macro_expansion(&self) -> bool { + self.current_macro().is_some() + } +} + +/// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a +/// minimal set of `CoverageSpan`s, using the BCB CFG to determine where it is safe and useful to: +/// +/// * Remove duplicate source code coverage regions +/// * Merge spans that represent continuous (both in source code and control flow), non-branching +/// execution +/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) +pub struct CoverageSpans<'a, 'tcx> { + /// The MIR, used to look up `BasicBlockData`. + mir_body: &'a mir::Body<'tcx>, + + /// A `Span` covering the signature of function for the MIR. + fn_sig_span: Span, + + /// A `Span` covering the function body of the MIR (typically from left curly brace to right + /// curly brace). + body_span: Span, + + /// The BasicCoverageBlock Control Flow Graph (BCB CFG). + basic_coverage_blocks: &'a CoverageGraph, + + /// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative + /// dominance between the `BasicCoverageBlock`s of equal `Span`s. + sorted_spans_iter: Option>, + + /// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the + /// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to + /// `pending_dups`). If `curr` is not discarded or merged, it becomes `prev` for the next + /// iteration. + some_curr: Option, + + /// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span` + /// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()` + /// is mutated. + curr_original_span: Span, + + /// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`. + /// If that `curr` was discarded, `prev` retains its value from the previous iteration. + some_prev: Option, + + /// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span` + /// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()` + /// is mutated. + prev_original_span: Span, + + /// A copy of the expn_span from the prior iteration. + prev_expn_span: Option, + + /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and + /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list. + /// If a new `curr` span also fits this criteria (compared to an existing list of + /// `pending_dups`), that `curr` `CoverageSpan` moves to `prev` before possibly being added to + /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups` + /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev` + /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a + /// `prev` with a matching `Span`) + pending_dups: Vec, + + /// The final `CoverageSpan`s to add to the coverage map. A `Counter` or `Expression` + /// will also be injected into the MIR for each `CoverageSpan`. + refined_spans: Vec, +} + +impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { + /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be + /// counted. + /// + /// The basic steps are: + /// + /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each + /// `BasicCoverageBlockData`. + /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position + /// are sorted with longer spans before shorter spans; and equal spans are sorted + /// (deterministically) based on "dominator" relationship (if any). + /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, + /// if another span or spans are already counting the same code region), or should be merged + /// into a broader combined span (because it represents a contiguous, non-branching, and + /// uninterrupted region of source code). + /// + /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since + /// closures have their own MIR, their `Span` in their enclosing function should be left + /// "uncovered". + /// + /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need + /// to be). + pub(super) fn generate_coverage_spans( + mir_body: &'a mir::Body<'tcx>, + fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span` + body_span: Span, + basic_coverage_blocks: &'a CoverageGraph, + ) -> Vec { + let mut coverage_spans = CoverageSpans { + mir_body, + fn_sig_span, + body_span, + basic_coverage_blocks, + sorted_spans_iter: None, + refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), + some_curr: None, + curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), + some_prev: None, + prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), + prev_expn_span: None, + pending_dups: Vec::new(), + }; + + let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans(); + + coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter()); + + coverage_spans.to_refined_spans() + } + + fn mir_to_initial_sorted_coverage_spans(&self) -> Vec { + let mut initial_spans = Vec::::with_capacity(self.mir_body.num_nodes() * 2); + for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() { + for coverage_span in self.bcb_to_initial_coverage_spans(bcb, bcb_data) { + initial_spans.push(coverage_span); + } + } + + if initial_spans.is_empty() { + // This can happen if, for example, the function is unreachable (contains only a + // `BasicBlock`(s) with an `Unreachable` terminator). + return initial_spans; + } + + initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span)); + + initial_spans.sort_unstable_by(|a, b| { + if a.span.lo() == b.span.lo() { + if a.span.hi() == b.span.hi() { + if a.is_in_same_bcb(b) { + Some(Ordering::Equal) + } else { + // Sort equal spans by dominator relationship, in reverse order (so + // dominators always come after the dominated equal spans). When later + // comparing two spans in order, the first will either dominate the second, + // or they will have no dominator relationship. + self.basic_coverage_blocks.dominators().rank_partial_cmp(b.bcb, a.bcb) + } + } else { + // Sort hi() in reverse order so shorter spans are attempted after longer spans. + // This guarantees that, if a `prev` span overlaps, and is not equal to, a + // `curr` span, the prev span either extends further left of the curr span, or + // they start at the same position and the prev span extends further right of + // the end of the curr span. + b.span.hi().partial_cmp(&a.span.hi()) + } + } else { + a.span.lo().partial_cmp(&b.span.lo()) + } + .unwrap() + }); + + initial_spans + } + + /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and + /// de-duplicated `CoverageSpan`s. + fn to_refined_spans(mut self) -> Vec { + while self.next_coverage_span() { + if self.some_prev.is_none() { + debug!(" initial span"); + self.check_invoked_macro_name_span(); + } else if self.curr().is_mergeable(self.prev()) { + debug!(" same bcb (and neither is a closure), merge with prev={:?}", self.prev()); + let prev = self.take_prev(); + self.curr_mut().merge_from(prev); + self.check_invoked_macro_name_span(); + // Note that curr.span may now differ from curr_original_span + } else if self.prev_ends_before_curr() { + debug!( + " different bcbs and disjoint spans, so keep curr for next iter, and add \ + prev={:?}", + self.prev() + ); + let prev = self.take_prev(); + self.push_refined_span(prev); + self.check_invoked_macro_name_span(); + } else if self.prev().is_closure { + // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the + // next iter + debug!( + " curr overlaps a closure (prev). Drop curr and keep prev for next iter. \ + prev={:?}", + self.prev() + ); + self.take_curr(); + } else if self.curr().is_closure { + self.carve_out_span_for_closure(); + } else if self.prev_original_span == self.curr().span { + // Note that this compares the new (`curr`) span to `prev_original_span`. + // In this branch, the actual span byte range of `prev_original_span` is not + // important. What is important is knowing whether the new `curr` span was + // **originally** the same as the original span of `prev()`. The original spans + // reflect their original sort order, and for equal spans, conveys a partial + // ordering based on CFG dominator priority. + if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() { + // Macros that expand to include branching (such as + // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or + // `trace!()) typically generate callee spans with identical + // ranges (typically the full span of the macro) for all + // `BasicBlocks`. This makes it impossible to distinguish + // the condition (`if val1 != val2`) from the optional + // branched statements (such as the call to `panic!()` on + // assert failure). In this case it is better (or less + // worse) to drop the optional branch bcbs and keep the + // non-conditional statements, to count when reached. + debug!( + " curr and prev are part of a macro expansion, and curr has the same span \ + as prev, but is in a different bcb. Drop curr and keep prev for next iter. \ + prev={:?}", + self.prev() + ); + self.take_curr(); + } else { + self.hold_pending_dups_unless_dominated(); + } + } else { + self.cutoff_prev_at_overlapping_curr(); + self.check_invoked_macro_name_span(); + } + } + + debug!(" AT END, adding last prev={:?}", self.prev()); + let prev = self.take_prev(); + let pending_dups = self.pending_dups.split_off(0); + for dup in pending_dups { + debug!(" ...adding at least one pending dup={:?}", dup); + self.push_refined_span(dup); + } + + // Async functions wrap a closure that implements the body to be executed. The enclosing + // function is called and returns an `impl Future` without initially executing any of the + // body. To avoid showing the return from the enclosing function as a "covered" return from + // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is + // excluded. The closure's `Return` is the only one that will be counted. This provides + // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace + // of the function body.) + let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() { + last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi() + } else { + false + }; + + if !body_ends_with_closure { + self.push_refined_span(prev); + } + + // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage + // regions for the current function leave room for the closure's own coverage regions + // (injected separately, from the closure's own MIR). + self.refined_spans.retain(|covspan| !covspan.is_closure); + self.refined_spans + } + + fn push_refined_span(&mut self, covspan: CoverageSpan) { + let len = self.refined_spans.len(); + if len > 0 { + let last = &mut self.refined_spans[len - 1]; + if last.is_mergeable(&covspan) { + debug!( + "merging new refined span with last refined span, last={:?}, covspan={:?}", + last, covspan + ); + last.merge_from(covspan); + return; + } + } + self.refined_spans.push(covspan) + } + + fn check_invoked_macro_name_span(&mut self) { + if let Some(visible_macro) = self.curr().visible_macro(self.body_span) { + if self.prev_expn_span.map_or(true, |prev_expn_span| { + self.curr().expn_span.ctxt() != prev_expn_span.ctxt() + }) { + let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo(); + let after_macro_bang = + merged_prefix_len + BytePos(visible_macro.as_str().bytes().count() as u32 + 1); + let mut macro_name_cov = self.curr().clone(); + self.curr_mut().span = + self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang); + macro_name_cov.span = + macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang); + debug!( + " and curr starts a new macro expansion, so add a new span just for \ + the macro `{}!`, new span={:?}", + visible_macro, macro_name_cov + ); + self.push_refined_span(macro_name_cov); + } + } + } + + // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of + // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated + // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will + // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple + // `Statement`s and/or `Terminator`s.) + fn bcb_to_initial_coverage_spans( + &self, + bcb: BasicCoverageBlock, + bcb_data: &'a BasicCoverageBlockData, + ) -> Vec { + bcb_data + .basic_blocks + .iter() + .flat_map(|&bb| { + let data = &self.mir_body[bb]; + data.statements + .iter() + .enumerate() + .filter_map(move |(index, statement)| { + filtered_statement_span(statement).map(|span| { + CoverageSpan::for_statement( + statement, + function_source_span(span, self.body_span), + span, + bcb, + bb, + index, + ) + }) + }) + .chain(filtered_terminator_span(data.terminator()).map(|span| { + CoverageSpan::for_terminator( + function_source_span(span, self.body_span), + span, + bcb, + bb, + ) + })) + }) + .collect() + } + + fn curr(&self) -> &CoverageSpan { + self.some_curr + .as_ref() + .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) + } + + fn curr_mut(&mut self) -> &mut CoverageSpan { + self.some_curr + .as_mut() + .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) + } + + fn prev(&self) -> &CoverageSpan { + self.some_prev + .as_ref() + .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) + } + + fn prev_mut(&mut self) -> &mut CoverageSpan { + self.some_prev + .as_mut() + .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) + } + + fn take_prev(&mut self) -> CoverageSpan { + self.some_prev.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev")) + } + + /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the + /// `pending_dups` spans), then one of the following two things happened during the previous + /// iteration: + /// * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups + /// (in which case there should be at least two spans in `pending_dups`); or + /// * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case + /// `pending_dups` could have as few as one span) + /// In either case, no more spans will match the span of `pending_dups`, so + /// add the `pending_dups` if they don't overlap `curr`, and clear the list. + fn check_pending_dups(&mut self) { + if let Some(dup) = self.pending_dups.last() { + if dup.span != self.prev().span { + debug!( + " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \ + previous iteration, or prev started a new disjoint span" + ); + if dup.span.hi() <= self.curr().span.lo() { + let pending_dups = self.pending_dups.split_off(0); + for dup in pending_dups.into_iter() { + debug!(" ...adding at least one pending={:?}", dup); + self.push_refined_span(dup); + } + } else { + self.pending_dups.clear(); + } + } + } + } + + /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order. + fn next_coverage_span(&mut self) -> bool { + if let Some(curr) = self.some_curr.take() { + self.prev_expn_span = Some(curr.expn_span); + self.some_prev = Some(curr); + self.prev_original_span = self.curr_original_span; + } + while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() { + debug!("FOR curr={:?}", curr); + if self.some_prev.is_some() && self.prev_starts_after_next(&curr) { + debug!( + " prev.span starts after curr.span, so curr will be dropped (skipping past \ + closure?); prev={:?}", + self.prev() + ); + } else { + // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed + // by `self.curr_mut().merge_from(prev)`. + self.curr_original_span = curr.span; + self.some_curr.replace(curr); + self.check_pending_dups(); + return true; + } + } + false + } + + /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the + /// `curr` coverage span. + fn take_curr(&mut self) -> CoverageSpan { + self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) + } + + /// Returns true if the curr span should be skipped because prev has already advanced beyond the + /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region + /// of code, such as skipping past a closure. + fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool { + self.prev().span.lo() > next_curr.span.lo() + } + + /// Returns true if the curr span starts past the end of the prev span, which means they don't + /// overlap, so we now know the prev can be added to the refined coverage spans. + fn prev_ends_before_curr(&self) -> bool { + self.prev().span.hi() <= self.curr().span.lo() + } + + /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from + /// `prev`'s span. (The closure's coverage counters will be injected when processing the + /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span + /// extends to the right of the closure, update `prev` to that portion of the span. For any + /// `pending_dups`, repeat the same process. + fn carve_out_span_for_closure(&mut self) { + let curr_span = self.curr().span; + let left_cutoff = curr_span.lo(); + let right_cutoff = curr_span.hi(); + let has_pre_closure_span = self.prev().span.lo() < right_cutoff; + let has_post_closure_span = self.prev().span.hi() > right_cutoff; + let mut pending_dups = self.pending_dups.split_off(0); + if has_pre_closure_span { + let mut pre_closure = self.prev().clone(); + pre_closure.span = pre_closure.span.with_hi(left_cutoff); + debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure); + if !pending_dups.is_empty() { + for mut dup in pending_dups.iter().cloned() { + dup.span = dup.span.with_hi(left_cutoff); + debug!(" ...and at least one pre_closure dup={:?}", dup); + self.push_refined_span(dup); + } + } + self.push_refined_span(pre_closure); + } + if has_post_closure_span { + // Mutate `prev.span()` to start after the closure (and discard curr). + // (**NEVER** update `prev_original_span` because it affects the assumptions + // about how the `CoverageSpan`s are ordered.) + self.prev_mut().span = self.prev().span.with_lo(right_cutoff); + debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev()); + for dup in pending_dups.iter_mut() { + debug!(" ...and at least one overlapping dup={:?}", dup); + dup.span = dup.span.with_lo(right_cutoff); + } + self.pending_dups.append(&mut pending_dups); + let closure_covspan = self.take_curr(); + self.push_refined_span(closure_covspan); // since self.prev() was already updated + } else { + pending_dups.clear(); + } + } + + /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all + /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed. + /// If prev.span() was merged into other spans (with matching BCB, for instance), + /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`. + /// If prev.span() was split off to the right of a closure, prev.span().lo() will be + /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is + /// not as important as knowing that `prev()` **used to have the same span** as `curr(), + /// which means their sort order is still meaningful for determinating the dominator + /// relationship. + /// + /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if + /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held, + /// until their disposition is determined. In this latter case, the `prev` dup is moved into + /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration. + fn hold_pending_dups_unless_dominated(&mut self) { + // Equal coverage spans are ordered by dominators before dominated (if any), so it should be + // impossible for `curr` to dominate any previous `CoverageSpan`. + debug_assert!(!self.span_bcb_is_dominated_by(self.prev(), self.curr())); + + let initial_pending_count = self.pending_dups.len(); + if initial_pending_count > 0 { + let mut pending_dups = self.pending_dups.split_off(0); + pending_dups.retain(|dup| !self.span_bcb_is_dominated_by(self.curr(), dup)); + self.pending_dups.append(&mut pending_dups); + if self.pending_dups.len() < initial_pending_count { + debug!( + " discarded {} of {} pending_dups that dominated curr", + initial_pending_count - self.pending_dups.len(), + initial_pending_count + ); + } + } + + if self.span_bcb_is_dominated_by(self.curr(), self.prev()) { + debug!( + " different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}", + self.prev() + ); + self.cutoff_prev_at_overlapping_curr(); + // If one span dominates the other, assocate the span with the code from the dominated + // block only (`curr`), and discard the overlapping portion of the `prev` span. (Note + // that if `prev.span` is wider than `prev_original_span`, a `CoverageSpan` will still + // be created for `prev`s block, for the non-overlapping portion, left of `curr.span`.) + // + // For example: + // match somenum { + // x if x < 1 => { ... } + // }... + // + // The span for the first `x` is referenced by both the pattern block (every time it is + // evaluated) and the arm code (only when matched). The counter will be applied only to + // the dominated block. This allows coverage to track and highlight things like the + // assignment of `x` above, if the branch is matched, making `x` available to the arm + // code; and to track and highlight the question mark `?` "try" operator at the end of + // a function call returning a `Result`, so the `?` is covered when the function returns + // an `Err`, and not counted as covered if the function always returns `Ok`. + } else { + // Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.) + // If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as + // well; but if `curr` is added to refined_spans, the `pending_dups` will also be added. + debug!( + " different bcbs but SAME spans, and neither dominates, so keep curr for \ + next iter, and, pending upcoming spans (unless overlapping) add prev={:?}", + self.prev() + ); + let prev = self.take_prev(); + self.pending_dups.push(prev); + } + } + + /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_ + /// statements that end before `curr.lo()` (if any), and add the portion of the + /// combined span for those statements. Any other statements have overlapping spans + /// that can be ignored because `curr` and/or other upcoming statements/spans inside + /// the overlap area will produce their own counters. This disambiguation process + /// avoids injecting multiple counters for overlapping spans, and the potential for + /// double-counting. + fn cutoff_prev_at_overlapping_curr(&mut self) { + debug!( + " different bcbs, overlapping spans, so ignore/drop pending and only add prev \ + if it has statements that end before curr; prev={:?}", + self.prev() + ); + if self.pending_dups.is_empty() { + let curr_span = self.curr().span; + self.prev_mut().cutoff_statements_at(curr_span.lo()); + if self.prev().coverage_statements.is_empty() { + debug!(" ... no non-overlapping statements to add"); + } else { + debug!(" ... adding modified prev={:?}", self.prev()); + let prev = self.take_prev(); + self.push_refined_span(prev); + } + } else { + // with `pending_dups`, `prev` cannot have any statements that don't overlap + self.pending_dups.clear(); + } + } + + fn span_bcb_is_dominated_by(&self, covspan: &CoverageSpan, dom_covspan: &CoverageSpan) -> bool { + self.basic_coverage_blocks.is_dominated_by(covspan.bcb, dom_covspan.bcb) + } +} + +/// If the MIR `Statement` has a span contributive to computing coverage spans, +/// return it; otherwise return `None`. +pub(super) fn filtered_statement_span(statement: &'a Statement<'tcx>) -> Option { + match statement.kind { + // These statements have spans that are often outside the scope of the executed source code + // for their parent `BasicBlock`. + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + // Coverage should not be encountered, but don't inject coverage coverage + | StatementKind::Coverage(_) + // Ignore `Nop`s + | StatementKind::Nop => None, + + // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead` + // statements be more consistent? + // + // FakeReadCause::ForGuardBinding, in this example: + // match somenum { + // x if x < 1 => { ... } + // }... + // The BasicBlock within the match arm code included one of these statements, but the span + // for it covered the `1` in this source. The actual statements have nothing to do with that + // source span: + // FakeRead(ForGuardBinding, _4); + // where `_4` is: + // _4 = &_1; (at the span for the first `x`) + // and `_1` is the `Place` for `somenum`. + // + // If and when the Issue is resolved, remove this special case match pattern: + StatementKind::FakeRead(box (cause, _)) if cause == FakeReadCause::ForGuardBinding => None, + + // Retain spans from all other statements + StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` + | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assign(_) + | StatementKind::SetDiscriminant { .. } + | StatementKind::LlvmInlineAsm(_) + | StatementKind::Retag(_, _) + | StatementKind::AscribeUserType(_, _) => { + Some(statement.source_info.span) + } + } +} + +/// If the MIR `Terminator` has a span contributive to computing coverage spans, +/// return it; otherwise return `None`. +pub(super) fn filtered_terminator_span(terminator: &'a Terminator<'tcx>) -> Option { + match terminator.kind { + // These terminators have spans that don't positively contribute to computing a reasonable + // span of actually executed source code. (For example, SwitchInt terminators extracted from + // an `if condition { block }` has a span that includes the executed block, if true, + // but for coverage, the code region executed, up to *and* through the SwitchInt, + // actually stops before the if's block.) + TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::SwitchInt { .. } + // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::Goto { .. } => None, + + // Call `func` operand can have a more specific span when part of a chain of calls + | TerminatorKind::Call { ref func, .. } => { + let mut span = terminator.source_info.span; + if let mir::Operand::Constant(box constant) = func { + if constant.span.lo() > span.lo() { + span = span.with_lo(constant.span.lo()); + } + } + Some(span) + } + + // Retain spans from all other terminators + TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Yield { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => { + Some(terminator.source_info.span) + } + } +} + +/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range +/// within the function's body source. This span is guaranteed to be contained +/// within, or equal to, the `body_span`. If the extrapolated span is not +/// contained within the `body_span`, the `body_span` is returned. +/// +/// [^1]Expansions result from Rust syntax including macros, syntactic sugar, +/// etc.). +#[inline] +pub(super) fn function_source_span(span: Span, body_span: Span) -> Span { + let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt()); + if body_span.contains(original_span) { original_span } else { body_span } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +[package] +name = "coverage_test_macros" +version = "0.0.0" +edition = "2021" + +[lib] +proc-macro = true +doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +use proc_macro::TokenStream; + +#[proc_macro] +pub fn let_bcb(item: TokenStream) -> TokenStream { + format!("let bcb{} = graph::BasicCoverageBlock::from_usize({});", item, item).parse().unwrap() +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/tests.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/coverage/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,721 @@ +//! This crate hosts a selection of "unit tests" for components of the `InstrumentCoverage` MIR +//! pass. +//! +//! ```shell +//! ./x.py test --keep-stage 1 compiler/rustc_mir --test-args '--show-output coverage' +//! ``` +//! +//! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage` +//! functions and algorithms. Mocked objects include instances of `mir::Body`; including +//! `Terminator`s of various `kind`s, and `Span` objects. Some functions used by or used on +//! real, runtime versions of these mocked-up objects have constraints (such as cross-thread +//! limitations) and deep dependencies on other elements of the full Rust compiler (which is +//! *not* constructed or mocked for these tests). +//! +//! Of particular note, attempting to simply print elements of the `mir::Body` with default +//! `Debug` formatting can fail because some `Debug` format implementations require the +//! `TyCtxt`, obtained via a static global variable that is *not* set for these tests. +//! Initializing the global type context is prohibitively complex for the scope and scale of these +//! tests (essentially requiring initializing the entire compiler). +//! +//! Also note, some basic features of `Span` also rely on the `Span`s own "session globals", which +//! are unrelated to the `TyCtxt` global. Without initializing the `Span` session globals, some +//! basic, coverage-specific features would be impossible to test, but thankfully initializing these +//! globals is comparatively simpler. The easiest way is to wrap the test in a closure argument +//! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`. + +use super::counters; +use super::debug; +use super::graph; +use super::spans; + +use coverage_test_macros::let_bcb; + +use rustc_data_structures::graph::WithNumNodes; +use rustc_data_structures::graph::WithSuccessors; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::coverage::CoverageKind; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, DebruijnIndex, TyS, TypeFlags}; +use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP}; + +// All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`. +const TEMP_BLOCK: BasicBlock = BasicBlock::MAX; + +fn dummy_ty() -> &'static TyS<'static> { + thread_local! { + static DUMMY_TYS: &'static TyS<'static> = Box::leak(Box::new(TyS::make_for_test( + ty::Bool, + TypeFlags::empty(), + DebruijnIndex::from_usize(0), + ))); + } + + &DUMMY_TYS.with(|tys| *tys) +} + +struct MockBlocks<'tcx> { + blocks: IndexVec>, + dummy_place: Place<'tcx>, + next_local: usize, +} + +impl<'tcx> MockBlocks<'tcx> { + fn new() -> Self { + Self { + blocks: IndexVec::new(), + dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() }, + next_local: 0, + } + } + + fn new_temp(&mut self) -> Local { + let index = self.next_local; + self.next_local += 1; + Local::new(index) + } + + fn push(&mut self, kind: TerminatorKind<'tcx>) -> BasicBlock { + let next_lo = if let Some(last) = self.blocks.last() { + self.blocks[last].terminator().source_info.span.hi() + } else { + BytePos(1) + }; + let next_hi = next_lo + BytePos(1); + self.blocks.push(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)), + kind, + }), + is_cleanup: false, + }) + } + + fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) { + match self.blocks[from_block].terminator_mut().kind { + TerminatorKind::Assert { ref mut target, .. } + | TerminatorKind::Call { destination: Some((_, ref mut target)), .. } + | TerminatorKind::Drop { ref mut target, .. } + | TerminatorKind::DropAndReplace { ref mut target, .. } + | TerminatorKind::FalseEdge { real_target: ref mut target, .. } + | TerminatorKind::FalseUnwind { real_target: ref mut target, .. } + | TerminatorKind::Goto { ref mut target } + | TerminatorKind::InlineAsm { destination: Some(ref mut target), .. } + | TerminatorKind::Yield { resume: ref mut target, .. } => *target = to_block, + ref invalid => bug!("Invalid from_block: {:?}", invalid), + } + } + + fn add_block_from( + &mut self, + some_from_block: Option, + to_kind: TerminatorKind<'tcx>, + ) -> BasicBlock { + let new_block = self.push(to_kind); + if let Some(from_block) = some_from_block { + self.link(from_block, new_block); + } + new_block + } + + fn set_branch(&mut self, switchint: BasicBlock, branch_index: usize, to_block: BasicBlock) { + match self.blocks[switchint].terminator_mut().kind { + TerminatorKind::SwitchInt { ref mut targets, .. } => { + let mut branches = targets.iter().collect::>(); + let otherwise = if branch_index == branches.len() { + to_block + } else { + let old_otherwise = targets.otherwise(); + if branch_index > branches.len() { + branches.push((branches.len() as u128, old_otherwise)); + while branches.len() < branch_index { + branches.push((branches.len() as u128, TEMP_BLOCK)); + } + to_block + } else { + branches[branch_index] = (branch_index as u128, to_block); + old_otherwise + } + }; + *targets = SwitchTargets::new(branches.into_iter(), otherwise); + } + ref invalid => bug!("Invalid BasicBlock kind or no to_block: {:?}", invalid), + } + } + + fn call(&mut self, some_from_block: Option) -> BasicBlock { + self.add_block_from( + some_from_block, + TerminatorKind::Call { + func: Operand::Copy(self.dummy_place.clone()), + args: vec![], + destination: Some((self.dummy_place.clone(), TEMP_BLOCK)), + cleanup: None, + from_hir_call: false, + fn_span: DUMMY_SP, + }, + ) + } + + fn goto(&mut self, some_from_block: Option) -> BasicBlock { + self.add_block_from(some_from_block, TerminatorKind::Goto { target: TEMP_BLOCK }) + } + + fn switchint(&mut self, some_from_block: Option) -> BasicBlock { + let switchint_kind = TerminatorKind::SwitchInt { + discr: Operand::Move(Place::from(self.new_temp())), + switch_ty: dummy_ty(), + targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK), + }; + self.add_block_from(some_from_block, switchint_kind) + } + + fn return_(&mut self, some_from_block: Option) -> BasicBlock { + self.add_block_from(some_from_block, TerminatorKind::Return) + } + + fn to_body(self) -> Body<'tcx> { + Body::new_cfg_only(self.blocks) + } +} + +fn debug_basic_blocks(mir_body: &Body<'tcx>) -> String { + format!( + "{:?}", + mir_body + .basic_blocks() + .iter_enumerated() + .map(|(bb, data)| { + let term = &data.terminator(); + let kind = &term.kind; + let span = term.source_info.span; + let sp = format!("(span:{},{})", span.lo().to_u32(), span.hi().to_u32()); + match kind { + TerminatorKind::Assert { target, .. } + | TerminatorKind::Call { destination: Some((_, target)), .. } + | TerminatorKind::Drop { target, .. } + | TerminatorKind::DropAndReplace { target, .. } + | TerminatorKind::FalseEdge { real_target: target, .. } + | TerminatorKind::FalseUnwind { real_target: target, .. } + | TerminatorKind::Goto { target } + | TerminatorKind::InlineAsm { destination: Some(target), .. } + | TerminatorKind::Yield { resume: target, .. } => { + format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), target) + } + TerminatorKind::SwitchInt { targets, .. } => { + format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), targets) + } + _ => format!("{}{:?}:{}", sp, bb, debug::term_type(kind)), + } + }) + .collect::>() + ) +} + +static PRINT_GRAPHS: bool = false; + +fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { + if PRINT_GRAPHS { + println!( + "digraph {} {{\n{}\n}}", + name, + mir_body + .basic_blocks() + .iter_enumerated() + .map(|(bb, data)| { + format!( + " {:?} [label=\"{:?}: {}\"];\n{}", + bb, + bb, + debug::term_type(&data.terminator().kind), + mir_body + .successors(bb) + .map(|successor| { format!(" {:?} -> {:?};", bb, successor) }) + .collect::>() + .join("\n") + ) + }) + .collect::>() + .join("\n") + ); + } +} + +fn print_coverage_graphviz( + name: &str, + mir_body: &Body<'_>, + basic_coverage_blocks: &graph::CoverageGraph, +) { + if PRINT_GRAPHS { + println!( + "digraph {} {{\n{}\n}}", + name, + basic_coverage_blocks + .iter_enumerated() + .map(|(bcb, bcb_data)| { + format!( + " {:?} [label=\"{:?}: {}\"];\n{}", + bcb, + bcb, + debug::term_type(&bcb_data.terminator(mir_body).kind), + basic_coverage_blocks + .successors(bcb) + .map(|successor| { format!(" {:?} -> {:?};", bcb, successor) }) + .collect::>() + .join("\n") + ) + }) + .collect::>() + .join("\n") + ); + } +} + +/// Create a mock `Body` with a simple flow. +fn goto_switchint() -> Body<'a> { + let mut blocks = MockBlocks::new(); + let start = blocks.call(None); + let goto = blocks.goto(Some(start)); + let switchint = blocks.switchint(Some(goto)); + let then_call = blocks.call(None); + let else_call = blocks.call(None); + blocks.set_branch(switchint, 0, then_call); + blocks.set_branch(switchint, 1, else_call); + blocks.return_(Some(then_call)); + blocks.return_(Some(else_call)); + + let mir_body = blocks.to_body(); + print_mir_graphviz("mir_goto_switchint", &mir_body); + /* Graphviz character plots created using: `graph-easy --as=boxart`: + ┌────────────────┠+ │ bb0: Call │ + └────────────────┘ + │ + │ + â–¼ + ┌────────────────┠+ │ bb1: Goto │ + └────────────────┘ + │ + │ + â–¼ + ┌─────────────┠┌────────────────┠+ │ bb4: Call │ ◀── │ bb2: SwitchInt │ + └─────────────┘ └────────────────┘ + │ │ + │ │ + â–¼ â–¼ + ┌─────────────┠┌────────────────┠+ │ bb6: Return │ │ bb3: Call │ + └─────────────┘ └────────────────┘ + │ + │ + â–¼ + ┌────────────────┠+ │ bb5: Return │ + └────────────────┘ + */ + mir_body +} + +macro_rules! assert_successors { + ($basic_coverage_blocks:ident, $i:ident, [$($successor:ident),*]) => { + let mut successors = $basic_coverage_blocks.successors[$i].clone(); + successors.sort_unstable(); + assert_eq!(successors, vec![$($successor),*]); + } +} + +#[test] +fn test_covgraph_goto_switchint() { + let mir_body = goto_switchint(); + if false { + eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body)); + } + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks); + /* + ┌──────────────┠┌─────────────────┠+ │ bcb2: Return │ ◀── │ bcb0: SwitchInt │ + └──────────────┘ └─────────────────┘ + │ + │ + â–¼ + ┌─────────────────┠+ │ bcb1: Return │ + └─────────────────┘ + */ + assert_eq!( + basic_coverage_blocks.num_nodes(), + 3, + "basic_coverage_blocks: {:?}", + basic_coverage_blocks.iter_enumerated().collect::>() + ); + + let_bcb!(0); + let_bcb!(1); + let_bcb!(2); + + assert_successors!(basic_coverage_blocks, bcb0, [bcb1, bcb2]); + assert_successors!(basic_coverage_blocks, bcb1, []); + assert_successors!(basic_coverage_blocks, bcb2, []); +} + +/// Create a mock `Body` with a loop. +fn switchint_then_loop_else_return() -> Body<'a> { + let mut blocks = MockBlocks::new(); + let start = blocks.call(None); + let switchint = blocks.switchint(Some(start)); + let then_call = blocks.call(None); + blocks.set_branch(switchint, 0, then_call); + let backedge_goto = blocks.goto(Some(then_call)); + blocks.link(backedge_goto, switchint); + let else_return = blocks.return_(None); + blocks.set_branch(switchint, 1, else_return); + + let mir_body = blocks.to_body(); + print_mir_graphviz("mir_switchint_then_loop_else_return", &mir_body); + /* + ┌────────────────┠+ │ bb0: Call │ + └────────────────┘ + │ + │ + â–¼ + ┌─────────────┠┌────────────────┠+ │ bb4: Return │ ◀── │ bb1: SwitchInt │ ◀┠+ └─────────────┘ └────────────────┘ │ + │ │ + │ │ + â–¼ │ + ┌────────────────┠│ + │ bb2: Call │ │ + └────────────────┘ │ + │ │ + │ │ + â–¼ │ + ┌────────────────┠│ + │ bb3: Goto │ ─┘ + └────────────────┘ + */ + mir_body +} + +#[test] +fn test_covgraph_switchint_then_loop_else_return() { + let mir_body = switchint_then_loop_else_return(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + print_coverage_graphviz( + "covgraph_switchint_then_loop_else_return", + &mir_body, + &basic_coverage_blocks, + ); + /* + ┌─────────────────┠+ │ bcb0: Call │ + └─────────────────┘ + │ + │ + â–¼ + ┌────────────┠┌─────────────────┠+ │ bcb3: Goto │ ◀── │ bcb1: SwitchInt │ ◀┠+ └────────────┘ └─────────────────┘ │ + │ │ │ + │ │ │ + │ â–¼ │ + │ ┌─────────────────┠│ + │ │ bcb2: Return │ │ + │ └─────────────────┘ │ + │ │ + └─────────────────────────────────────┘ + */ + assert_eq!( + basic_coverage_blocks.num_nodes(), + 4, + "basic_coverage_blocks: {:?}", + basic_coverage_blocks.iter_enumerated().collect::>() + ); + + let_bcb!(0); + let_bcb!(1); + let_bcb!(2); + let_bcb!(3); + + assert_successors!(basic_coverage_blocks, bcb0, [bcb1]); + assert_successors!(basic_coverage_blocks, bcb1, [bcb2, bcb3]); + assert_successors!(basic_coverage_blocks, bcb2, []); + assert_successors!(basic_coverage_blocks, bcb3, [bcb1]); +} + +/// Create a mock `Body` with nested loops. +fn switchint_loop_then_inner_loop_else_break() -> Body<'a> { + let mut blocks = MockBlocks::new(); + let start = blocks.call(None); + let switchint = blocks.switchint(Some(start)); + let then_call = blocks.call(None); + blocks.set_branch(switchint, 0, then_call); + let else_return = blocks.return_(None); + blocks.set_branch(switchint, 1, else_return); + + let inner_start = blocks.call(Some(then_call)); + let inner_switchint = blocks.switchint(Some(inner_start)); + let inner_then_call = blocks.call(None); + blocks.set_branch(inner_switchint, 0, inner_then_call); + let inner_backedge_goto = blocks.goto(Some(inner_then_call)); + blocks.link(inner_backedge_goto, inner_switchint); + let inner_else_break_goto = blocks.goto(None); + blocks.set_branch(inner_switchint, 1, inner_else_break_goto); + + let backedge_goto = blocks.goto(Some(inner_else_break_goto)); + blocks.link(backedge_goto, switchint); + + let mir_body = blocks.to_body(); + print_mir_graphviz("mir_switchint_loop_then_inner_loop_else_break", &mir_body); + /* + ┌────────────────┠+ │ bb0: Call │ + └────────────────┘ + │ + │ + â–¼ + ┌─────────────┠┌────────────────┠+ │ bb3: Return │ ◀── │ bb1: SwitchInt │ ◀─────┠+ └─────────────┘ └────────────────┘ │ + │ │ + │ │ + â–¼ │ + ┌────────────────┠│ + │ bb2: Call │ │ + └────────────────┘ │ + │ │ + │ │ + â–¼ │ + ┌────────────────┠│ + │ bb4: Call │ │ + └────────────────┘ │ + │ │ + │ │ + â–¼ │ + ┌─────────────┠┌────────────────┠│ + │ bb8: Goto │ ◀── │ bb5: SwitchInt │ ◀┠│ + └─────────────┘ └────────────────┘ │ │ + │ │ │ │ + │ │ │ │ + â–¼ â–¼ │ │ + ┌─────────────┠┌────────────────┠│ │ + │ bb9: Goto │ ─┠│ bb6: Call │ │ │ + └─────────────┘ │ └────────────────┘ │ │ + │ │ │ │ + │ │ │ │ + │ â–¼ │ │ + │ ┌────────────────┠│ │ + │ │ bb7: Goto │ ─┘ │ + │ └────────────────┘ │ + │ │ + └───────────────────────────┘ + */ + mir_body +} + +#[test] +fn test_covgraph_switchint_loop_then_inner_loop_else_break() { + let mir_body = switchint_loop_then_inner_loop_else_break(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + print_coverage_graphviz( + "covgraph_switchint_loop_then_inner_loop_else_break", + &mir_body, + &basic_coverage_blocks, + ); + /* + ┌─────────────────┠+ │ bcb0: Call │ + └─────────────────┘ + │ + │ + â–¼ + ┌──────────────┠┌─────────────────┠+ │ bcb2: Return │ ◀── │ bcb1: SwitchInt │ ◀┠+ └──────────────┘ └─────────────────┘ │ + │ │ + │ │ + â–¼ │ + ┌─────────────────┠│ + │ bcb3: Call │ │ + └─────────────────┘ │ + │ │ + │ │ + â–¼ │ + ┌──────────────┠┌─────────────────┠│ + │ bcb6: Goto │ ◀── │ bcb4: SwitchInt │ ◀┼────┠+ └──────────────┘ └─────────────────┘ │ │ + │ │ │ │ + │ │ │ │ + │ â–¼ │ │ + │ ┌─────────────────┠│ │ + │ │ bcb5: Goto │ ─┘ │ + │ └─────────────────┘ │ + │ │ + └────────────────────────────────────────────┘ + */ + assert_eq!( + basic_coverage_blocks.num_nodes(), + 7, + "basic_coverage_blocks: {:?}", + basic_coverage_blocks.iter_enumerated().collect::>() + ); + + let_bcb!(0); + let_bcb!(1); + let_bcb!(2); + let_bcb!(3); + let_bcb!(4); + let_bcb!(5); + let_bcb!(6); + + assert_successors!(basic_coverage_blocks, bcb0, [bcb1]); + assert_successors!(basic_coverage_blocks, bcb1, [bcb2, bcb3]); + assert_successors!(basic_coverage_blocks, bcb2, []); + assert_successors!(basic_coverage_blocks, bcb3, [bcb4]); + assert_successors!(basic_coverage_blocks, bcb4, [bcb5, bcb6]); + assert_successors!(basic_coverage_blocks, bcb5, [bcb1]); + assert_successors!(basic_coverage_blocks, bcb6, [bcb4]); +} + +#[test] +fn test_find_loop_backedges_none() { + let mir_body = goto_switchint(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + if false { + eprintln!( + "basic_coverage_blocks = {:?}", + basic_coverage_blocks.iter_enumerated().collect::>() + ); + eprintln!("successors = {:?}", basic_coverage_blocks.successors); + } + let backedges = graph::find_loop_backedges(&basic_coverage_blocks); + assert_eq!( + backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), + 0, + "backedges: {:?}", + backedges + ); +} + +#[test] +fn test_find_loop_backedges_one() { + let mir_body = switchint_then_loop_else_return(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + let backedges = graph::find_loop_backedges(&basic_coverage_blocks); + assert_eq!( + backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), + 1, + "backedges: {:?}", + backedges + ); + + let_bcb!(1); + let_bcb!(3); + + assert_eq!(backedges[bcb1], vec![bcb3]); +} + +#[test] +fn test_find_loop_backedges_two() { + let mir_body = switchint_loop_then_inner_loop_else_break(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + let backedges = graph::find_loop_backedges(&basic_coverage_blocks); + assert_eq!( + backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), + 2, + "backedges: {:?}", + backedges + ); + + let_bcb!(1); + let_bcb!(4); + let_bcb!(5); + let_bcb!(6); + + assert_eq!(backedges[bcb1], vec![bcb5]); + assert_eq!(backedges[bcb4], vec![bcb6]); +} + +#[test] +fn test_traverse_coverage_with_loops() { + let mir_body = switchint_loop_then_inner_loop_else_break(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + let mut traversed_in_order = Vec::new(); + let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks); + while let Some(bcb) = traversal.next(&basic_coverage_blocks) { + traversed_in_order.push(bcb); + } + + let_bcb!(6); + + // bcb0 is visited first. Then bcb1 starts the first loop, and all remaining nodes, *except* + // bcb6 are inside the first loop. + assert_eq!( + *traversed_in_order.last().expect("should have elements"), + bcb6, + "bcb6 should not be visited until all nodes inside the first loop have been visited" + ); +} + +fn synthesize_body_span_from_terminators(mir_body: &Body<'_>) -> Span { + let mut some_span: Option = None; + for (_, data) in mir_body.basic_blocks().iter_enumerated() { + let term_span = data.terminator().source_info.span; + if let Some(span) = some_span.as_mut() { + *span = span.to(term_span); + } else { + some_span = Some(term_span) + } + } + some_span.expect("body must have at least one BasicBlock") +} + +#[test] +fn test_make_bcb_counters() { + rustc_span::create_default_session_globals_then(|| { + let mir_body = goto_switchint(); + let body_span = synthesize_body_span_from_terminators(&mir_body); + let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + let mut coverage_spans = Vec::new(); + for (bcb, data) in basic_coverage_blocks.iter_enumerated() { + if let Some(span) = spans::filtered_terminator_span(data.terminator(&mir_body)) { + coverage_spans.push(spans::CoverageSpan::for_terminator( + spans::function_source_span(span, body_span), + span, + bcb, + data.last_bb(), + )); + } + } + let mut coverage_counters = counters::CoverageCounters::new(0); + let intermediate_expressions = coverage_counters + .make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans) + .expect("should be Ok"); + assert_eq!(intermediate_expressions.len(), 0); + + let_bcb!(1); + assert_eq!( + 1, // coincidentally, bcb1 has a `Counter` with id = 1 + match basic_coverage_blocks[bcb1].counter().expect("should have a counter") { + CoverageKind::Counter { id, .. } => id, + _ => panic!("expected a Counter"), + } + .as_u32() + ); + + let_bcb!(2); + assert_eq!( + 2, // coincidentally, bcb2 has a `Counter` with id = 2 + match basic_coverage_blocks[bcb2].counter().expect("should have a counter") { + CoverageKind::Counter { id, .. } => id, + _ => panic!("expected a Counter"), + } + .as_u32() + ); + }); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/deaggregator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/deaggregator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/deaggregator.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/deaggregator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,49 @@ +use crate::util::expand_aggregate; +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct Deaggregator; + +impl<'tcx> MirPass<'tcx> for Deaggregator { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + let local_decls = &*local_decls; + for bb in basic_blocks { + bb.expand_statements(|stmt| { + // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL). + match stmt.kind { + // FIXME(#48193) Deaggregate arrays when it's cheaper to do so. + StatementKind::Assign(box ( + _, + Rvalue::Aggregate(box AggregateKind::Array(_), _), + )) => { + return None; + } + StatementKind::Assign(box (_, Rvalue::Aggregate(_, _))) => {} + _ => return None, + } + + let stmt = stmt.replace_nop(); + let source_info = stmt.source_info; + let (lhs, kind, operands) = match stmt.kind { + StatementKind::Assign(box (lhs, Rvalue::Aggregate(kind, operands))) => { + (lhs, kind, operands) + } + _ => bug!(), + }; + + Some(expand_aggregate( + lhs, + operands.into_iter().map(|op| { + let ty = op.ty(local_decls, tcx); + (op, ty) + }), + *kind, + source_info, + tcx, + )) + }); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/deduplicate_blocks.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/deduplicate_blocks.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/deduplicate_blocks.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/deduplicate_blocks.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,189 @@ +//! This pass finds basic blocks that are completely equal, +//! and replaces all uses with just one of them. + +use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher, iter}; + +use crate::MirPass; + +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +use super::simplify::simplify_cfg; + +pub struct DeduplicateBlocks; + +impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.mir_opt_level() < 4 { + return; + } + debug!("Running DeduplicateBlocks on `{:?}`", body.source); + let duplicates = find_duplicates(body); + let has_opts_to_apply = !duplicates.is_empty(); + + if has_opts_to_apply { + let mut opt_applier = OptApplier { tcx, duplicates }; + opt_applier.visit_body(body); + simplify_cfg(tcx, body); + } + } +} + +struct OptApplier<'tcx> { + tcx: TyCtxt<'tcx>, + duplicates: FxHashMap, +} + +impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + for target in terminator.successors_mut() { + if let Some(replacement) = self.duplicates.get(target) { + debug!("SUCCESS: Replacing: `{:?}` with `{:?}`", target, replacement); + *target = *replacement; + } + } + + self.super_terminator(terminator, location); + } +} + +fn find_duplicates<'a, 'tcx>(body: &'a Body<'tcx>) -> FxHashMap { + let mut duplicates = FxHashMap::default(); + + let bbs_to_go_through = + body.basic_blocks().iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count(); + + let mut same_hashes = + FxHashMap::with_capacity_and_hasher(bbs_to_go_through, Default::default()); + + // Go through the basic blocks backwards. This means that in case of duplicates, + // we can use the basic block with the highest index as the replacement for all lower ones. + // For example, if bb1, bb2 and bb3 are duplicates, we will first insert bb3 in same_hashes. + // Then we will see that bb2 is a duplicate of bb3, + // and insert bb2 with the replacement bb3 in the duplicates list. + // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the duplicates list + // with replacement bb3. + // When the duplicates are removed, we will end up with only bb3. + for (bb, bbd) in body.basic_blocks().iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup) + { + // Basic blocks can get really big, so to avoid checking for duplicates in basic blocks + // that are unlikely to have duplicates, we stop early. The early bail number has been + // found experimentally by eprintln while compiling the crates in the rustc-perf suite. + if bbd.statements.len() > 10 { + continue; + } + + let to_hash = BasicBlockHashable { basic_block_data: bbd }; + let entry = same_hashes.entry(to_hash); + match entry { + Entry::Occupied(occupied) => { + // The basic block was already in the hashmap, which means we have a duplicate + let value = *occupied.get(); + debug!("Inserting {:?} -> {:?}", bb, value); + duplicates.try_insert(bb, value).expect("key was already inserted"); + } + Entry::Vacant(vacant) => { + vacant.insert(bb); + } + } + } + + duplicates +} + +struct BasicBlockHashable<'tcx, 'a> { + basic_block_data: &'a BasicBlockData<'tcx>, +} + +impl<'tcx, 'a> Hash for BasicBlockHashable<'tcx, 'a> { + fn hash(&self, state: &mut H) { + hash_statements(state, self.basic_block_data.statements.iter()); + // Note that since we only hash the kind, we lose span information if we deduplicate the blocks + self.basic_block_data.terminator().kind.hash(state); + } +} + +impl<'tcx, 'a> Eq for BasicBlockHashable<'tcx, 'a> {} + +impl<'tcx, 'a> PartialEq for BasicBlockHashable<'tcx, 'a> { + fn eq(&self, other: &Self) -> bool { + self.basic_block_data.statements.len() == other.basic_block_data.statements.len() + && &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind + && iter::zip(&self.basic_block_data.statements, &other.basic_block_data.statements) + .all(|(x, y)| statement_eq(&x.kind, &y.kind)) + } +} + +fn hash_statements<'a, 'tcx, H: Hasher>( + hasher: &mut H, + iter: impl Iterator>, +) where + 'tcx: 'a, +{ + for stmt in iter { + statement_hash(hasher, &stmt.kind); + } +} + +fn statement_hash<'tcx, H: Hasher>(hasher: &mut H, stmt: &StatementKind<'tcx>) { + match stmt { + StatementKind::Assign(box (place, rvalue)) => { + place.hash(hasher); + rvalue_hash(hasher, rvalue) + } + x => x.hash(hasher), + }; +} + +fn rvalue_hash(hasher: &mut H, rvalue: &Rvalue<'tcx>) { + match rvalue { + Rvalue::Use(op) => operand_hash(hasher, op), + x => x.hash(hasher), + }; +} + +fn operand_hash(hasher: &mut H, operand: &Operand<'tcx>) { + match operand { + Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher), + x => x.hash(hasher), + }; +} + +fn statement_eq<'tcx>(lhs: &StatementKind<'tcx>, rhs: &StatementKind<'tcx>) -> bool { + let res = match (lhs, rhs) { + ( + StatementKind::Assign(box (place, rvalue)), + StatementKind::Assign(box (place2, rvalue2)), + ) => place == place2 && rvalue_eq(rvalue, rvalue2), + (x, y) => x == y, + }; + debug!("statement_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); + res +} + +fn rvalue_eq(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool { + let res = match (lhs, rhs) { + (Rvalue::Use(op1), Rvalue::Use(op2)) => operand_eq(op1, op2), + (x, y) => x == y, + }; + debug!("rvalue_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); + res +} + +fn operand_eq(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool { + let res = match (lhs, rhs) { + ( + Operand::Constant(box Constant { user_ty: _, literal, span: _ }), + Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }), + ) => literal == literal2, + (x, y) => x == y, + }; + debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); + res +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/dest_prop.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/dest_prop.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/dest_prop.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/dest_prop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1038 @@ +//! Propagates assignment destinations backwards in the CFG to eliminate redundant assignments. +//! +//! # Motivation +//! +//! MIR building can insert a lot of redundant copies, and Rust code in general often tends to move +//! values around a lot. The result is a lot of assignments of the form `dest = {move} src;` in MIR. +//! MIR building for constants in particular tends to create additional locals that are only used +//! inside a single block to shuffle a value around unnecessarily. +//! +//! LLVM by itself is not good enough at eliminating these redundant copies (eg. see +//! ), so this leaves some performance on the table +//! that we can regain by implementing an optimization for removing these assign statements in rustc +//! itself. When this optimization runs fast enough, it can also speed up the constant evaluation +//! and code generation phases of rustc due to the reduced number of statements and locals. +//! +//! # The Optimization +//! +//! Conceptually, this optimization is "destination propagation". It is similar to the Named Return +//! Value Optimization, or NRVO, known from the C++ world, except that it isn't limited to return +//! values or the return place `_0`. On a very high level, independent of the actual implementation +//! details, it does the following: +//! +//! 1) Identify `dest = src;` statements that can be soundly eliminated. +//! 2) Replace all mentions of `src` with `dest` ("unifying" them and propagating the destination +//! backwards). +//! 3) Delete the `dest = src;` statement (by making it a `nop`). +//! +//! Step 1) is by far the hardest, so it is explained in more detail below. +//! +//! ## Soundness +//! +//! Given an `Assign` statement `dest = src;`, where `dest` is a `Place` and `src` is an `Rvalue`, +//! there are a few requirements that must hold for the optimization to be sound: +//! +//! * `dest` must not contain any *indirection* through a pointer. It must access part of the base +//! local. Otherwise it might point to arbitrary memory that is hard to track. +//! +//! It must also not contain any indexing projections, since those take an arbitrary `Local` as +//! the index, and that local might only be initialized shortly before `dest` is used. +//! +//! Subtle case: If `dest` is a, or projects through a union, then we have to make sure that there +//! remains an assignment to it, since that sets the "active field" of the union. But if `src` is +//! a ZST, it might not be initialized, so there might not be any use of it before the assignment, +//! and performing the optimization would simply delete the assignment, leaving `dest` +//! uninitialized. +//! +//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Is this a +//! fundamental restriction or just current impl state?). It can be copied or moved by the +//! assignment. +//! +//! * The `dest` and `src` locals must never be [*live*][liveness] at the same time. If they are, it +//! means that they both hold a (potentially different) value that is needed by a future use of +//! the locals. Unifying them would overwrite one of the values. +//! +//! Note that computing liveness of locals that have had their address taken is more difficult: +//! Short of doing full escape analysis on the address/pointer/reference, the pass would need to +//! assume that any operation that can potentially involve opaque user code (such as function +//! calls, destructors, and inline assembly) may access any local that had its address taken +//! before that point. +//! +//! Here, the first two conditions are simple structural requirements on the `Assign` statements +//! that can be trivially checked. The liveness requirement however is more difficult and costly to +//! check. +//! +//! ## Previous Work +//! +//! A [previous attempt] at implementing an optimization like this turned out to be a significant +//! regression in compiler performance. Fixing the regressions introduced a lot of undesirable +//! complexity to the implementation. +//! +//! A [subsequent approach] tried to avoid the costly computation by limiting itself to acyclic +//! CFGs, but still turned out to be far too costly to run due to suboptimal performance within +//! individual basic blocks, requiring a walk across the entire block for every assignment found +//! within the block. For the `tuple-stress` benchmark, which has 458745 statements in a single +//! block, this proved to be far too costly. +//! +//! Since the first attempt at this, the compiler has improved dramatically, and new analysis +//! frameworks have been added that should make this approach viable without requiring a limited +//! approach that only works for some classes of CFGs: +//! - rustc now has a powerful dataflow analysis framework that can handle forwards and backwards +//! analyses efficiently. +//! - Layout optimizations for generators have been added to improve code generation for +//! async/await, which are very similar in spirit to what this optimization does. Both walk the +//! MIR and record conflicting uses of locals in a `BitMatrix`. +//! +//! Also, rustc now has a simple NRVO pass (see `nrvo.rs`), which handles a subset of the cases that +//! this destination propagation pass handles, proving that similar optimizations can be performed +//! on MIR. +//! +//! ## Pre/Post Optimization +//! +//! It is recommended to run `SimplifyCfg` and then `SimplifyLocals` some time after this pass, as +//! it replaces the eliminated assign statements with `nop`s and leaves unused locals behind. +//! +//! [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis +//! [previous attempt]: https://github.com/rust-lang/rust/pull/47954 +//! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003 + +use crate::MirPass; +use itertools::Itertools; +use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey}; +use rustc_index::{ + bit_set::{BitMatrix, BitSet}, + vec::IndexVec, +}; +use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::{dump_mir, PassWhere}; +use rustc_middle::mir::{ + traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem, + Rvalue, Statement, StatementKind, Terminator, TerminatorKind, +}; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals}; +use rustc_mir_dataflow::Analysis; + +// Empirical measurements have resulted in some observations: +// - Running on a body with a single block and 500 locals takes barely any time +// - Running on a body with ~400 blocks and ~300 relevant locals takes "too long" +// ...so we just limit both to somewhat reasonable-ish looking values. +const MAX_LOCALS: usize = 500; +const MAX_BLOCKS: usize = 250; + +pub struct DestinationPropagation; + +impl<'tcx> MirPass<'tcx> for DestinationPropagation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // FIXME(#79191, #82678) + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + + // Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove + // storage statements at the moment). + if tcx.sess.mir_opt_level() < 3 { + return; + } + + let def_id = body.source.def_id(); + + let candidates = find_candidates(tcx, body); + if candidates.is_empty() { + debug!("{:?}: no dest prop candidates, done", def_id); + return; + } + + // Collect all locals we care about. We only compute conflicts for these to save time. + let mut relevant_locals = BitSet::new_empty(body.local_decls.len()); + for CandidateAssignment { dest, src, loc: _ } in &candidates { + relevant_locals.insert(dest.local); + relevant_locals.insert(*src); + } + + // This pass unfortunately has `O(l² * s)` performance, where `l` is the number of locals + // and `s` is the number of statements and terminators in the function. + // To prevent blowing up compile times too much, we bail out when there are too many locals. + let relevant = relevant_locals.count(); + debug!( + "{:?}: {} locals ({} relevant), {} blocks", + def_id, + body.local_decls.len(), + relevant, + body.basic_blocks().len() + ); + if relevant > MAX_LOCALS { + warn!( + "too many candidate locals in {:?} ({}, max is {}), not optimizing", + def_id, relevant, MAX_LOCALS + ); + return; + } + if body.basic_blocks().len() > MAX_BLOCKS { + warn!( + "too many blocks in {:?} ({}, max is {}), not optimizing", + def_id, + body.basic_blocks().len(), + MAX_BLOCKS + ); + return; + } + + let mut conflicts = Conflicts::build(tcx, body, &relevant_locals); + + let mut replacements = Replacements::new(body.local_decls.len()); + for candidate @ CandidateAssignment { dest, src, loc } in candidates { + // Merge locals that don't conflict. + if !conflicts.can_unify(dest.local, src) { + debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src); + continue; + } + + if replacements.for_src(candidate.src).is_some() { + debug!("src {:?} already has replacement", candidate.src); + continue; + } + + if !tcx.consider_optimizing(|| { + format!("DestinationPropagation {:?} {:?}", def_id, candidate) + }) { + break; + } + + replacements.push(candidate); + conflicts.unify(candidate.src, candidate.dest.local); + } + + replacements.flatten(tcx); + + debug!("replacements {:?}", replacements.map); + + Replacer { tcx, replacements, place_elem_cache: Vec::new() }.visit_body(body); + + // FIXME fix debug info + } +} + +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +struct UnifyLocal(Local); + +impl From for UnifyLocal { + fn from(l: Local) -> Self { + Self(l) + } +} + +impl UnifyKey for UnifyLocal { + type Value = (); + fn index(&self) -> u32 { + self.0.as_u32() + } + fn from_index(u: u32) -> Self { + Self(Local::from_u32(u)) + } + fn tag() -> &'static str { + "UnifyLocal" + } +} + +struct Replacements<'tcx> { + /// Maps locals to their replacement. + map: IndexVec>>, + + /// Whose locals' live ranges to kill. + kill: BitSet, +} + +impl Replacements<'tcx> { + fn new(locals: usize) -> Self { + Self { map: IndexVec::from_elem_n(None, locals), kill: BitSet::new_empty(locals) } + } + + fn push(&mut self, candidate: CandidateAssignment<'tcx>) { + trace!("Replacements::push({:?})", candidate); + let entry = &mut self.map[candidate.src]; + assert!(entry.is_none()); + + *entry = Some(candidate.dest); + self.kill.insert(candidate.src); + self.kill.insert(candidate.dest.local); + } + + /// Applies the stored replacements to all replacements, until no replacements would result in + /// locals that need further replacements when applied. + fn flatten(&mut self, tcx: TyCtxt<'tcx>) { + // Note: This assumes that there are no cycles in the replacements, which is enforced via + // `self.unified_locals`. Otherwise this can cause an infinite loop. + + for local in self.map.indices() { + if let Some(replacement) = self.map[local] { + // Substitute the base local of `replacement` until fixpoint. + let mut base = replacement.local; + let mut reversed_projection_slices = Vec::with_capacity(1); + while let Some(replacement_for_replacement) = self.map[base] { + base = replacement_for_replacement.local; + reversed_projection_slices.push(replacement_for_replacement.projection); + } + + let projection: Vec<_> = reversed_projection_slices + .iter() + .rev() + .flat_map(|projs| projs.iter()) + .chain(replacement.projection.iter()) + .collect(); + let projection = tcx.intern_place_elems(&projection); + + // Replace with the final `Place`. + self.map[local] = Some(Place { local: base, projection }); + } + } + } + + fn for_src(&self, src: Local) -> Option> { + self.map[src] + } +} + +struct Replacer<'tcx> { + tcx: TyCtxt<'tcx>, + replacements: Replacements<'tcx>, + place_elem_cache: Vec>, +} + +impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, context: PlaceContext, location: Location) { + if context.is_use() && self.replacements.for_src(*local).is_some() { + bug!( + "use of local {:?} should have been replaced by visit_place; context={:?}, loc={:?}", + local, + context, + location, + ); + } + } + + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + _: Location, + ) -> Option> { + match elem { + PlaceElem::Index(local) => { + if let Some(replacement) = self.replacements.for_src(local) { + bug!( + "cannot replace {:?} with {:?} in index projection {:?}", + local, + replacement, + elem, + ); + } else { + None + } + } + _ => None, + } + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + if let Some(replacement) = self.replacements.for_src(place.local) { + // Rebase `place`s projections onto `replacement`'s. + self.place_elem_cache.clear(); + self.place_elem_cache.extend(replacement.projection.iter().chain(place.projection)); + let projection = self.tcx.intern_place_elems(&self.place_elem_cache); + let new_place = Place { local: replacement.local, projection }; + + debug!("Replacer: {:?} -> {:?}", place, new_place); + *place = new_place; + } + + self.super_place(place, context, location); + } + + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + self.super_statement(statement, location); + + match &statement.kind { + // FIXME: Don't delete storage statements, merge the live ranges instead + StatementKind::StorageDead(local) | StatementKind::StorageLive(local) + if self.replacements.kill.contains(*local) => + { + statement.make_nop() + } + + StatementKind::Assign(box (dest, rvalue)) => { + match rvalue { + Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { + // These might've been turned into self-assignments by the replacement + // (this includes the original statement we wanted to eliminate). + if dest == place { + debug!("{:?} turned into self-assignment, deleting", location); + statement.make_nop(); + } + } + _ => {} + } + } + + _ => {} + } + } +} + +struct Conflicts<'a> { + relevant_locals: &'a BitSet, + + /// The conflict matrix. It is always symmetric and the adjacency matrix of the corresponding + /// conflict graph. + matrix: BitMatrix, + + /// Preallocated `BitSet` used by `unify`. + unify_cache: BitSet, + + /// Tracks locals that have been merged together to prevent cycles and propagate conflicts. + unified_locals: InPlaceUnificationTable, +} + +impl Conflicts<'a> { + fn build<'tcx>( + tcx: TyCtxt<'tcx>, + body: &'_ Body<'tcx>, + relevant_locals: &'a BitSet, + ) -> Self { + // We don't have to look out for locals that have their address taken, since + // `find_candidates` already takes care of that. + + let conflicts = BitMatrix::from_row_n( + &BitSet::new_empty(body.local_decls.len()), + body.local_decls.len(), + ); + + let mut init = MaybeInitializedLocals + .into_engine(tcx, body) + .iterate_to_fixpoint() + .into_results_cursor(body); + let mut live = + MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint().into_results_cursor(body); + + let mut reachable = None; + dump_mir(tcx, None, "DestinationPropagation-dataflow", &"", body, |pass_where, w| { + let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body)); + + match pass_where { + PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => { + init.seek_before_primary_effect(loc); + live.seek_after_primary_effect(loc); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + PassWhere::AfterTerminator(bb) if reachable.contains(bb) => { + let loc = body.terminator_loc(bb); + init.seek_after_primary_effect(loc); + live.seek_before_primary_effect(loc); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + + PassWhere::BeforeBlock(bb) if reachable.contains(bb) => { + init.seek_to_block_start(bb); + live.seek_to_block_start(bb); + + writeln!(w, " // init: {:?}", init.get())?; + writeln!(w, " // live: {:?}", live.get())?; + } + + PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {} + + PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => { + writeln!(w, " // init: ")?; + writeln!(w, " // live: ")?; + } + + PassWhere::BeforeBlock(_) => { + writeln!(w, " // init: ")?; + writeln!(w, " // live: ")?; + } + } + + Ok(()) + }); + + let mut this = Self { + relevant_locals, + matrix: conflicts, + unify_cache: BitSet::new_empty(body.local_decls.len()), + unified_locals: { + let mut table = InPlaceUnificationTable::new(); + // Pre-fill table with all locals (this creates N nodes / "connected" components, + // "graph"-ically speaking). + for local in 0..body.local_decls.len() { + assert_eq!(table.new_key(()), UnifyLocal(Local::from_usize(local))); + } + table + }, + }; + + let mut live_and_init_locals = Vec::new(); + + // Visit only reachable basic blocks. The exact order is not important. + for (block, data) in traversal::preorder(body) { + // We need to observe the dataflow state *before* all possible locations (statement or + // terminator) in each basic block, and then observe the state *after* the terminator + // effect is applied. As long as neither `init` nor `borrowed` has a "before" effect, + // we will observe all possible dataflow states. + + // Since liveness is a backwards analysis, we need to walk the results backwards. To do + // that, we first collect in the `MaybeInitializedLocals` results in a forwards + // traversal. + + live_and_init_locals.resize_with(data.statements.len() + 1, || { + BitSet::new_empty(body.local_decls.len()) + }); + + // First, go forwards for `MaybeInitializedLocals` and apply intra-statement/terminator + // conflicts. + for (i, statement) in data.statements.iter().enumerate() { + this.record_statement_conflicts(statement); + + let loc = Location { block, statement_index: i }; + init.seek_before_primary_effect(loc); + + live_and_init_locals[i].clone_from(init.get()); + } + + this.record_terminator_conflicts(data.terminator()); + let term_loc = Location { block, statement_index: data.statements.len() }; + init.seek_before_primary_effect(term_loc); + live_and_init_locals[term_loc.statement_index].clone_from(init.get()); + + // Now, go backwards and union with the liveness results. + for statement_index in (0..=data.statements.len()).rev() { + let loc = Location { block, statement_index }; + live.seek_after_primary_effect(loc); + + live_and_init_locals[statement_index].intersect(live.get()); + + trace!("record conflicts at {:?}", loc); + + this.record_dataflow_conflicts(&mut live_and_init_locals[statement_index]); + } + + init.seek_to_block_end(block); + live.seek_to_block_end(block); + let mut conflicts = init.get().clone(); + conflicts.intersect(live.get()); + trace!("record conflicts at end of {:?}", block); + + this.record_dataflow_conflicts(&mut conflicts); + } + + this + } + + fn record_dataflow_conflicts(&mut self, new_conflicts: &mut BitSet) { + // Remove all locals that are not candidates. + new_conflicts.intersect(self.relevant_locals); + + for local in new_conflicts.iter() { + self.matrix.union_row_with(&new_conflicts, local); + } + } + + fn record_local_conflict(&mut self, a: Local, b: Local, why: &str) { + trace!("conflict {:?} <-> {:?} due to {}", a, b, why); + self.matrix.insert(a, b); + self.matrix.insert(b, a); + } + + /// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict + /// and must not be merged. + fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) { + match &stmt.kind { + // While the left and right sides of an assignment must not overlap, we do not mark + // conflicts here as that would make this optimization useless. When we optimize, we + // eliminate the resulting self-assignments automatically. + StatementKind::Assign(_) => {} + + StatementKind::LlvmInlineAsm(asm) => { + // Inputs and outputs must not overlap. + for (_, input) in &*asm.inputs { + if let Some(in_place) = input.place() { + if !in_place.is_indirect() { + for out_place in &*asm.outputs { + if !out_place.is_indirect() && !in_place.is_indirect() { + self.record_local_conflict( + in_place.local, + out_place.local, + "aliasing llvm_asm! operands", + ); + } + } + } + } + } + } + + StatementKind::SetDiscriminant { .. } + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::Retag(..) + | StatementKind::FakeRead(..) + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::CopyNonOverlapping(..) + | StatementKind::Nop => {} + } + } + + fn record_terminator_conflicts(&mut self, term: &Terminator<'_>) { + match &term.kind { + TerminatorKind::DropAndReplace { + place: dropped_place, + value, + target: _, + unwind: _, + } => { + if let Some(place) = value.place() { + if !place.is_indirect() && !dropped_place.is_indirect() { + self.record_local_conflict( + place.local, + dropped_place.local, + "DropAndReplace operand overlap", + ); + } + } + } + TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { + if let Some(place) = value.place() { + if !place.is_indirect() && !resume_arg.is_indirect() { + self.record_local_conflict( + place.local, + resume_arg.local, + "Yield operand overlap", + ); + } + } + } + TerminatorKind::Call { + func, + args, + destination: Some((dest_place, _)), + cleanup: _, + from_hir_call: _, + fn_span: _, + } => { + // No arguments may overlap with the destination. + for arg in args.iter().chain(Some(func)) { + if let Some(place) = arg.place() { + if !place.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + dest_place.local, + place.local, + "call dest/arg overlap", + ); + } + } + } + } + TerminatorKind::InlineAsm { + template: _, + operands, + options: _, + line_spans: _, + destination: _, + } => { + // The intended semantics here aren't documented, we just assume that nothing that + // could be written to by the assembly may overlap with any other operands. + for op in operands { + match op { + InlineAsmOperand::Out { reg: _, late: _, place: Some(dest_place) } + | InlineAsmOperand::InOut { + reg: _, + late: _, + in_value: _, + out_place: Some(dest_place), + } => { + // For output place `place`, add all places accessed by the inline asm. + for op in operands { + match op { + InlineAsmOperand::In { reg: _, value } => { + if let Some(p) = value.place() { + if !p.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + p.local, + dest_place.local, + "asm! operand overlap", + ); + } + } + } + InlineAsmOperand::Out { + reg: _, + late: _, + place: Some(place), + } => { + if !place.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); + } + } + InlineAsmOperand::InOut { + reg: _, + late: _, + in_value, + out_place, + } => { + if let Some(place) = in_value.place() { + if !place.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); + } + } + + if let Some(place) = out_place { + if !place.is_indirect() && !dest_place.is_indirect() { + self.record_local_conflict( + place.local, + dest_place.local, + "asm! operand overlap", + ); + } + } + } + InlineAsmOperand::Out { reg: _, late: _, place: None } + | InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { def_id: _ } => {} + } + } + } + InlineAsmOperand::InOut { + reg: _, + late: _, + in_value: _, + out_place: None, + } + | InlineAsmOperand::In { reg: _, value: _ } + | InlineAsmOperand::Out { reg: _, late: _, place: None } + | InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::SymFn { value: _ } + | InlineAsmOperand::SymStatic { def_id: _ } => {} + } + } + } + + TerminatorKind::Goto { .. } + | TerminatorKind::Call { destination: None, .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => {} + } + } + + /// Checks whether `a` and `b` may be merged. Returns `false` if there's a conflict. + fn can_unify(&mut self, a: Local, b: Local) -> bool { + // After some locals have been unified, their conflicts are only tracked in the root key, + // so look that up. + let a = self.unified_locals.find(a).0; + let b = self.unified_locals.find(b).0; + + if a == b { + // Already merged (part of the same connected component). + return false; + } + + if self.matrix.contains(a, b) { + // Conflict (derived via dataflow, intra-statement conflicts, or inherited from another + // local during unification). + return false; + } + + true + } + + /// Merges the conflicts of `a` and `b`, so that each one inherits all conflicts of the other. + /// + /// `can_unify` must have returned `true` for the same locals, or this may panic or lead to + /// miscompiles. + /// + /// This is called when the pass makes the decision to unify `a` and `b` (or parts of `a` and + /// `b`) and is needed to ensure that future unification decisions take potentially newly + /// introduced conflicts into account. + /// + /// For an example, assume we have locals `_0`, `_1`, `_2`, and `_3`. There are these conflicts: + /// + /// * `_0` <-> `_1` + /// * `_1` <-> `_2` + /// * `_3` <-> `_0` + /// + /// We then decide to merge `_2` with `_3` since they don't conflict. Then we decide to merge + /// `_2` with `_0`, which also doesn't have a conflict in the above list. However `_2` is now + /// `_3`, which does conflict with `_0`. + fn unify(&mut self, a: Local, b: Local) { + trace!("unify({:?}, {:?})", a, b); + + // Get the root local of the connected components. The root local stores the conflicts of + // all locals in the connected component (and *is stored* as the conflicting local of other + // locals). + let a = self.unified_locals.find(a).0; + let b = self.unified_locals.find(b).0; + assert_ne!(a, b); + + trace!("roots: a={:?}, b={:?}", a, b); + trace!("{:?} conflicts: {:?}", a, self.matrix.iter(a).format(", ")); + trace!("{:?} conflicts: {:?}", b, self.matrix.iter(b).format(", ")); + + self.unified_locals.union(a, b); + + let root = self.unified_locals.find(a).0; + assert!(root == a || root == b); + + // Make all locals that conflict with `a` also conflict with `b`, and vice versa. + self.unify_cache.clear(); + for conflicts_with_a in self.matrix.iter(a) { + self.unify_cache.insert(conflicts_with_a); + } + for conflicts_with_b in self.matrix.iter(b) { + self.unify_cache.insert(conflicts_with_b); + } + for conflicts_with_a_or_b in self.unify_cache.iter() { + // Set both `a` and `b` for this local's row. + self.matrix.insert(conflicts_with_a_or_b, a); + self.matrix.insert(conflicts_with_a_or_b, b); + } + + // Write the locals `a` conflicts with to `b`'s row. + self.matrix.union_rows(a, b); + // Write the locals `b` conflicts with to `a`'s row. + self.matrix.union_rows(b, a); + } +} + +/// A `dest = {move} src;` statement at `loc`. +/// +/// We want to consider merging `dest` and `src` due to this assignment. +#[derive(Debug, Copy, Clone)] +struct CandidateAssignment<'tcx> { + /// Does not contain indirection or indexing (so the only local it contains is the place base). + dest: Place<'tcx>, + src: Local, + loc: Location, +} + +/// Scans the MIR for assignments between locals that we might want to consider merging. +/// +/// This will filter out assignments that do not match the right form (as described in the top-level +/// comment) and also throw out assignments that involve a local that has its address taken or is +/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate +/// arbitrary places into array indices). +fn find_candidates<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, +) -> Vec> { + let mut visitor = FindAssignments { + tcx, + body, + candidates: Vec::new(), + ever_borrowed_locals: ever_borrowed_locals(body), + locals_used_as_array_index: locals_used_as_array_index(body), + }; + visitor.visit_body(body); + visitor.candidates +} + +struct FindAssignments<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + candidates: Vec>, + ever_borrowed_locals: BitSet, + locals_used_as_array_index: BitSet, +} + +impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + if let StatementKind::Assign(box ( + dest, + Rvalue::Use(Operand::Copy(src) | Operand::Move(src)), + )) = &statement.kind + { + // `dest` must not have pointer indirection. + if dest.is_indirect() { + return; + } + + // `src` must be a plain local. + if !src.projection.is_empty() { + return; + } + + // Since we want to replace `src` with `dest`, `src` must not be required. + if is_local_required(src.local, self.body) { + return; + } + + // Can't optimize if both locals ever have their address taken (can introduce + // aliasing). + // FIXME: This can be smarter and take `StorageDead` into account (which + // invalidates borrows). + if self.ever_borrowed_locals.contains(dest.local) + || self.ever_borrowed_locals.contains(src.local) + { + return; + } + + assert_ne!(dest.local, src.local, "self-assignments are UB"); + + // We can't replace locals occurring in `PlaceElem::Index` for now. + if self.locals_used_as_array_index.contains(src.local) { + return; + } + + // Handle the "subtle case" described above by rejecting any `dest` that is or + // projects through a union. + let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); + if place_ty.ty.is_union() { + return; + } + for elem in dest.projection { + if let PlaceElem::Index(_) = elem { + // `dest` contains an indexing projection. + return; + } + + place_ty = place_ty.projection_ty(self.tcx, elem); + if place_ty.ty.is_union() { + return; + } + } + + self.candidates.push(CandidateAssignment { + dest: *dest, + src: src.local, + loc: location, + }); + } + } +} + +/// Some locals are part of the function's interface and can not be removed. +/// +/// Note that these locals *can* still be merged with non-required locals by removing that other +/// local. +fn is_local_required(local: Local, body: &Body<'_>) -> bool { + match body.local_kind(local) { + LocalKind::Arg | LocalKind::ReturnPointer => true, + LocalKind::Var | LocalKind::Temp => false, + } +} + +/// Walks MIR to find all locals that have their address taken anywhere. +fn ever_borrowed_locals(body: &Body<'_>) -> BitSet { + let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) }; + visitor.visit_body(body); + visitor.locals +} + +struct BorrowCollector { + locals: BitSet, +} + +impl<'tcx> Visitor<'tcx> for BorrowCollector { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + + match rvalue { + Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { + if !borrowed_place.is_indirect() { + self.locals.insert(borrowed_place.local); + } + } + + Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) + | Rvalue::Use(..) + | Rvalue::Repeat(..) + | Rvalue::Len(..) + | Rvalue::BinaryOp(..) + | Rvalue::CheckedBinaryOp(..) + | Rvalue::NullaryOp(..) + | Rvalue::UnaryOp(..) + | Rvalue::Discriminant(..) + | Rvalue::Aggregate(..) + | Rvalue::ThreadLocalRef(..) => {} + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + + match terminator.kind { + TerminatorKind::Drop { place: dropped_place, .. } + | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { + self.locals.insert(dropped_place.local); + } + + TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable + | TerminatorKind::Yield { .. } + | TerminatorKind::InlineAsm { .. } => {} + } + } +} + +/// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`. +/// +/// Collect locals used as indices so we don't generate candidates that are impossible to apply +/// later. +fn locals_used_as_array_index(body: &Body<'_>) -> BitSet { + let mut visitor = IndexCollector { locals: BitSet::new_empty(body.local_decls.len()) }; + visitor.visit_body(body); + visitor.locals +} + +struct IndexCollector { + locals: BitSet, +} + +impl<'tcx> Visitor<'tcx> for IndexCollector { + fn visit_projection_elem( + &mut self, + local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + if let PlaceElem::Index(i) = elem { + self.locals.insert(i); + } + self.super_projection_elem(local, proj_base, elem, context, location); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/dump_mir.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/dump_mir.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/dump_mir.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/dump_mir.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,52 @@ +//! This pass just dumps MIR at a specified point. + +use std::borrow::Cow; +use std::fmt; +use std::fs::File; +use std::io; + +use crate::MirPass; +use rustc_middle::mir::Body; +use rustc_middle::mir::{dump_enabled, dump_mir, write_mir_pretty}; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::{OutputFilenames, OutputType}; + +pub struct Marker(pub &'static str); + +impl<'tcx> MirPass<'tcx> for Marker { + fn name(&self) -> Cow<'_, str> { + Cow::Borrowed(self.0) + } + + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {} +} + +pub struct Disambiguator { + is_after: bool, +} + +impl fmt::Display for Disambiguator { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let title = if self.is_after { "after" } else { "before" }; + write!(formatter, "{}", title) + } +} + +pub fn on_mir_pass<'tcx>( + tcx: TyCtxt<'tcx>, + pass_num: &dyn fmt::Display, + pass_name: &str, + body: &Body<'tcx>, + is_after: bool, +) { + if dump_enabled(tcx, pass_name, body.source.def_id()) { + dump_mir(tcx, Some(pass_num), pass_name, &Disambiguator { is_after }, body, |_, _| Ok(())); + } +} + +pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> { + let path = outputs.path(OutputType::Mir); + let mut f = io::BufWriter::new(File::create(&path)?); + write_mir_pretty(tcx, None, &mut f)?; + Ok(()) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/early_otherwise_branch.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/early_otherwise_branch.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/early_otherwise_branch.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/early_otherwise_branch.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,369 @@ +use rustc_middle::mir::patch::MirPatch; +use rustc_middle::mir::*; +use rustc_middle::ty::{Ty, TyCtxt}; +use std::fmt::Debug; + +use super::simplify::simplify_cfg; + +/// This pass optimizes something like +/// ```text +/// let x: Option<()>; +/// let y: Option<()>; +/// match (x,y) { +/// (Some(_), Some(_)) => {0}, +/// _ => {1} +/// } +/// ``` +/// into something like +/// ```text +/// let x: Option<()>; +/// let y: Option<()>; +/// let discriminant_x = // get discriminant of x +/// let discriminant_y = // get discriminant of y +/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0} +/// ``` +pub struct EarlyOtherwiseBranch; + +impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // FIXME(#78496) + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + + if tcx.sess.mir_opt_level() < 3 { + return; + } + trace!("running EarlyOtherwiseBranch on {:?}", body.source); + // we are only interested in this bb if the terminator is a switchInt + let bbs_with_switch = + body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator())); + + let opts_to_apply: Vec> = bbs_with_switch + .flat_map(|(bb_idx, bb)| { + let switch = bb.terminator(); + let helper = Helper { body, tcx }; + let infos = helper.go(bb, switch)?; + Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx }) + }) + .collect(); + + let should_cleanup = !opts_to_apply.is_empty(); + + for opt_to_apply in opts_to_apply { + if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) { + break; + } + + trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); + + let statements_before = + body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len(); + let end_of_block_location = Location { + block: opt_to_apply.basic_block_first_switch, + statement_index: statements_before, + }; + + let mut patch = MirPatch::new(body); + + // create temp to store second discriminant in + let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty; + let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span; + let second_discriminant_temp = patch.new_temp(discr_type, discr_span); + + patch.add_statement( + end_of_block_location, + StatementKind::StorageLive(second_discriminant_temp), + ); + + // create assignment of discriminant + let place_of_adt_to_get_discriminant_of = + opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read; + patch.add_assign( + end_of_block_location, + Place::from(second_discriminant_temp), + Rvalue::Discriminant(place_of_adt_to_get_discriminant_of), + ); + + // create temp to store NotEqual comparison between the two discriminants + let not_equal = BinOp::Ne; + let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type); + let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span); + patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp)); + + // create NotEqual comparison between the two discriminants + let first_descriminant_place = + opt_to_apply.infos[0].first_switch_info.discr_used_in_switch; + let not_equal_rvalue = Rvalue::BinaryOp( + not_equal, + Box::new(( + Operand::Copy(Place::from(second_discriminant_temp)), + Operand::Copy(first_descriminant_place), + )), + ); + patch.add_statement( + end_of_block_location, + StatementKind::Assign(Box::new((Place::from(not_equal_temp), not_equal_rvalue))), + ); + + let new_targets = opt_to_apply + .infos + .iter() + .flat_map(|x| x.second_switch_info.targets_with_values.iter()) + .cloned(); + + let targets = SwitchTargets::new( + new_targets, + opt_to_apply.infos[0].first_switch_info.otherwise_bb, + ); + + // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal + let new_switch_data = BasicBlockData::new(Some(Terminator { + source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info, + kind: TerminatorKind::SwitchInt { + // the first and second discriminants are equal, so just pick one + discr: Operand::Copy(first_descriminant_place), + switch_ty: discr_type, + targets, + }, + })); + + let new_switch_bb = patch.new_block(new_switch_data); + + // switch on the NotEqual. If true, then jump to the `otherwise` case. + // If false, then jump to a basic block that then jumps to the correct disciminant case + let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb; + let false_case = new_switch_bb; + patch.patch_terminator( + opt_to_apply.basic_block_first_switch, + TerminatorKind::if_( + tcx, + Operand::Move(Place::from(not_equal_temp)), + true_case, + false_case, + ), + ); + + // generate StorageDead for the second_discriminant_temp not in use anymore + patch.add_statement( + end_of_block_location, + StatementKind::StorageDead(second_discriminant_temp), + ); + + // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch + for bb in [false_case, true_case].iter() { + patch.add_statement( + Location { block: *bb, statement_index: 0 }, + StatementKind::StorageDead(not_equal_temp), + ); + } + + patch.apply(body); + } + + // Since this optimization adds new basic blocks and invalidates others, + // clean up the cfg to make it nicer for other passes + if should_cleanup { + simplify_cfg(tcx, body); + } + } +} + +fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool { + matches!(terminator.kind, TerminatorKind::SwitchInt { .. }) +} + +struct Helper<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, +} + +#[derive(Debug, Clone)] +struct SwitchDiscriminantInfo<'tcx> { + /// Type of the discriminant being switched on + discr_ty: Ty<'tcx>, + /// The basic block that the otherwise branch points to + otherwise_bb: BasicBlock, + /// Target along with the value being branched from. Otherwise is not included + targets_with_values: Vec<(u128, BasicBlock)>, + discr_source_info: SourceInfo, + /// The place of the discriminant used in the switch + discr_used_in_switch: Place<'tcx>, + /// The place of the adt that has its discriminant read + place_of_adt_discr_read: Place<'tcx>, + /// The type of the adt that has its discriminant read + type_adt_matched_on: Ty<'tcx>, +} + +#[derive(Debug)] +struct OptimizationToApply<'tcx> { + infos: Vec>, + /// Basic block of the original first switch + basic_block_first_switch: BasicBlock, +} + +#[derive(Debug)] +struct OptimizationInfo<'tcx> { + /// Info about the first switch and discriminant + first_switch_info: SwitchDiscriminantInfo<'tcx>, + /// Info about the second switch and discriminant + second_switch_info: SwitchDiscriminantInfo<'tcx>, +} + +impl<'a, 'tcx> Helper<'a, 'tcx> { + pub fn go( + &self, + bb: &BasicBlockData<'tcx>, + switch: &Terminator<'tcx>, + ) -> Option>> { + // try to find the statement that defines the discriminant that is used for the switch + let discr = self.find_switch_discriminant_info(bb, switch)?; + + // go through each target, finding a discriminant read, and a switch + let results = discr + .targets_with_values + .iter() + .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value)); + + // if the optimization did not apply for one of the targets, then abort + if results.clone().any(|x| x.is_none()) || results.len() == 0 { + trace!("NO: not all of the targets matched the pattern for optimization"); + return None; + } + + Some(results.flatten().collect()) + } + + fn find_discriminant_switch_pairing( + &self, + discr_info: &SwitchDiscriminantInfo<'tcx>, + target: BasicBlock, + value: u128, + ) -> Option> { + let bb = &self.body.basic_blocks()[target]; + // find switch + let terminator = bb.terminator(); + if is_switch(terminator) { + let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?; + + // the types of the two adts matched on have to be equalfor this optimization to apply + if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on { + trace!( + "NO: types do not match. LHS: {:?}, RHS: {:?}", + discr_info.type_adt_matched_on, + this_bb_discr_info.type_adt_matched_on + ); + return None; + } + + // the otherwise branch of the two switches have to point to the same bb + if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb { + trace!("NO: otherwise target is not the same"); + return None; + } + + // check that the value being matched on is the same. The + if !this_bb_discr_info.targets_with_values.iter().any(|x| x.0 == value) { + trace!("NO: values being matched on are not the same"); + return None; + } + + // only allow optimization if the left and right of the tuple being matched are the same variants. + // so the following should not optimize + // ```rust + // let x: Option<()>; + // let y: Option<()>; + // match (x,y) { + // (Some(_), None) => {}, + // _ => {} + // } + // ``` + // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch + if !(this_bb_discr_info.targets_with_values.len() == 1 + && this_bb_discr_info.targets_with_values[0].0 == value) + { + trace!( + "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here" + ); + return None; + } + + // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially. + // for example, this should not be optimized: + // + // ```rust + // enum E<'a> { Empty, Some(&'a E<'a>), } + // let Some(Some(_)) = e; + // ``` + // + // ```mir + // bb0: { + // _2 = discriminant(*_1) + // switchInt(_2) -> [...] + // } + // bb1: { + // _3 = discriminant(*(((*_1) as Some).0: &E)) + // switchInt(_3) -> [...] + // } + // ``` + let discr_place = discr_info.place_of_adt_discr_read; + let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; + if discr_place.local == this_discr_place.local + && this_discr_place.projection.starts_with(discr_place.projection) + { + trace!("NO: one target is the projection of another"); + return None; + } + + // if we reach this point, the optimization applies, and we should be able to optimize this case + // store the info that is needed to apply the optimization + + Some(OptimizationInfo { + first_switch_info: discr_info.clone(), + second_switch_info: this_bb_discr_info, + }) + } else { + None + } + } + + fn find_switch_discriminant_info( + &self, + bb: &BasicBlockData<'tcx>, + switch: &Terminator<'tcx>, + ) -> Option> { + match &switch.kind { + TerminatorKind::SwitchInt { discr, targets, .. } => { + let discr_local = discr.place()?.as_local()?; + // the declaration of the discriminant read. Place of this read is being used in the switch + let discr_decl = &self.body.local_decls()[discr_local]; + let discr_ty = discr_decl.ty; + // the otherwise target lies as the last element + let otherwise_bb = targets.otherwise(); + let targets_with_values = targets.iter().collect(); + + // find the place of the adt where the discriminant is being read from + // assume this is the last statement of the block + let place_of_adt_discr_read = match bb.statements.last()?.kind { + StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => { + Some(adt_place) + } + _ => None, + }?; + + let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty; + + Some(SwitchDiscriminantInfo { + discr_used_in_switch: discr.place()?, + discr_ty, + otherwise_bb, + targets_with_values, + discr_source_info: discr_decl.source_info, + place_of_adt_discr_read, + type_adt_matched_on, + }) + } + _ => unreachable!("must only be passed terminator that is a switch"), + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/elaborate_drops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/elaborate_drops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/elaborate_drops.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/elaborate_drops.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,593 @@ +use crate::MirPass; +use rustc_data_structures::fx::FxHashMap; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::patch::MirPatch; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, DropFlagState, Unwind}; +use rustc_mir_dataflow::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle}; +use rustc_mir_dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; +use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; +use rustc_mir_dataflow::on_lookup_result_bits; +use rustc_mir_dataflow::MoveDataParamEnv; +use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits}; +use rustc_mir_dataflow::{Analysis, ResultsCursor}; +use rustc_span::Span; +use rustc_target::abi::VariantIdx; +use std::fmt; + +pub struct ElaborateDrops; + +impl<'tcx> MirPass<'tcx> for ElaborateDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); + + let def_id = body.source.def_id(); + let param_env = tcx.param_env_reveal_all_normalized(def_id); + let move_data = match MoveData::gather_moves(body, tcx, param_env) { + Ok(move_data) => move_data, + Err((move_data, _)) => { + tcx.sess.delay_span_bug( + body.span, + "No `move_errors` should be allowed in MIR borrowck", + ); + move_data + } + }; + let elaborate_patch = { + let body = &*body; + let env = MoveDataParamEnv { move_data, param_env }; + let dead_unwinds = find_dead_unwinds(tcx, body, &env); + + let inits = MaybeInitializedPlaces::new(tcx, body, &env) + .into_engine(tcx, body) + .dead_unwinds(&dead_unwinds) + .pass_name("elaborate_drops") + .iterate_to_fixpoint() + .into_results_cursor(body); + + let uninits = MaybeUninitializedPlaces::new(tcx, body, &env) + .mark_inactive_variants_as_uninit() + .into_engine(tcx, body) + .dead_unwinds(&dead_unwinds) + .pass_name("elaborate_drops") + .iterate_to_fixpoint() + .into_results_cursor(body); + + ElaborateDropsCtxt { + tcx, + body, + env: &env, + init_data: InitializationData { inits, uninits }, + drop_flags: Default::default(), + patch: MirPatch::new(body), + } + .elaborate() + }; + elaborate_patch.apply(body); + } +} + +/// Returns the set of basic blocks whose unwind edges are known +/// to not be reachable, because they are `drop` terminators +/// that can't drop anything. +fn find_dead_unwinds<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + env: &MoveDataParamEnv<'tcx>, +) -> BitSet { + debug!("find_dead_unwinds({:?})", body.span); + // We only need to do this pass once, because unwind edges can only + // reach cleanup blocks, which can't have unwind edges themselves. + let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); + let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) + .into_engine(tcx, body) + .pass_name("find_dead_unwinds") + .iterate_to_fixpoint() + .into_results_cursor(body); + for (bb, bb_data) in body.basic_blocks().iter_enumerated() { + let place = match bb_data.terminator().kind { + TerminatorKind::Drop { ref place, unwind: Some(_), .. } + | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place, + _ => continue, + }; + + debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data); + + let path = match env.move_data.rev_lookup.find(place.as_ref()) { + LookupResult::Exact(e) => e, + LookupResult::Parent(..) => { + debug!("find_dead_unwinds: has parent; skipping"); + continue; + } + }; + + flow_inits.seek_before_primary_effect(body.terminator_loc(bb)); + debug!( + "find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}", + bb, + place, + path, + flow_inits.get() + ); + + let mut maybe_live = false; + on_all_drop_children_bits(tcx, body, &env, path, |child| { + maybe_live |= flow_inits.contains(child); + }); + + debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); + if !maybe_live { + dead_unwinds.insert(bb); + } + } + + dead_unwinds +} + +struct InitializationData<'mir, 'tcx> { + inits: ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + uninits: ResultsCursor<'mir, 'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, +} + +impl InitializationData<'_, '_> { + fn seek_before(&mut self, loc: Location) { + self.inits.seek_before_primary_effect(loc); + self.uninits.seek_before_primary_effect(loc); + } + + fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) { + (self.inits.contains(path), self.uninits.contains(path)) + } +} + +struct Elaborator<'a, 'b, 'tcx> { + ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>, +} + +impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { + type Path = MovePathIndex; + + fn patch(&mut self) -> &mut MirPatch<'tcx> { + &mut self.ctxt.patch + } + + fn body(&self) -> &'a Body<'tcx> { + self.ctxt.body + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.ctxt.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.ctxt.param_env() + } + + fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { + let ((maybe_live, maybe_dead), multipart) = match mode { + DropFlagMode::Shallow => (self.ctxt.init_data.maybe_live_dead(path), false), + DropFlagMode::Deep => { + let mut some_live = false; + let mut some_dead = false; + let mut children_count = 0; + on_all_drop_children_bits(self.tcx(), self.body(), self.ctxt.env, path, |child| { + let (live, dead) = self.ctxt.init_data.maybe_live_dead(child); + debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); + some_live |= live; + some_dead |= dead; + children_count += 1; + }); + ((some_live, some_dead), children_count != 1) + } + }; + match (maybe_live, maybe_dead, multipart) { + (false, _, _) => DropStyle::Dead, + (true, false, _) => DropStyle::Static, + (true, true, false) => DropStyle::Conditional, + (true, true, true) => DropStyle::Open, + } + } + + fn clear_drop_flag(&mut self, loc: Location, path: Self::Path, mode: DropFlagMode) { + match mode { + DropFlagMode::Shallow => { + self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent); + } + DropFlagMode::Deep => { + on_all_children_bits( + self.tcx(), + self.body(), + self.ctxt.move_data(), + path, + |child| self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent), + ); + } + } + } + + fn field_subpath(&self, path: Self::Path, field: Field) -> Option { + rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::Field(idx, _) => idx == field, + _ => false, + }) + } + + fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option { + rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + debug_assert!(size == min_length, "min_length should be exact for arrays"); + assert!(!from_end, "from_end should not be used for array element ConstantIndex"); + offset == index + } + _ => false, + }) + } + + fn deref_subpath(&self, path: Self::Path) -> Option { + rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| { + e == ProjectionElem::Deref + }) + } + + fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option { + rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::Downcast(_, idx) => idx == variant, + _ => false, + }) + } + + fn get_drop_flag(&mut self, path: Self::Path) -> Option> { + self.ctxt.drop_flag(path).map(Operand::Copy) + } +} + +struct ElaborateDropsCtxt<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + env: &'a MoveDataParamEnv<'tcx>, + init_data: InitializationData<'a, 'tcx>, + drop_flags: FxHashMap, + patch: MirPatch<'tcx>, +} + +impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { + fn move_data(&self) -> &'b MoveData<'tcx> { + &self.env.move_data + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.env.param_env + } + + fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { + let tcx = self.tcx; + let patch = &mut self.patch; + debug!("create_drop_flag({:?})", self.body.span); + self.drop_flags.entry(index).or_insert_with(|| patch.new_internal(tcx.types.bool, span)); + } + + fn drop_flag(&mut self, index: MovePathIndex) -> Option> { + self.drop_flags.get(&index).map(|t| Place::from(*t)) + } + + /// create a patch that elaborates all drops in the input + /// MIR. + fn elaborate(mut self) -> MirPatch<'tcx> { + self.collect_drop_flags(); + + self.elaborate_drops(); + + self.drop_flags_on_init(); + self.drop_flags_for_fn_rets(); + self.drop_flags_for_args(); + self.drop_flags_for_locs(); + + self.patch + } + + fn collect_drop_flags(&mut self) { + for (bb, data) in self.body.basic_blocks().iter_enumerated() { + let terminator = data.terminator(); + let place = match terminator.kind { + TerminatorKind::Drop { ref place, .. } + | TerminatorKind::DropAndReplace { ref place, .. } => place, + _ => continue, + }; + + self.init_data.seek_before(self.body.terminator_loc(bb)); + + let path = self.move_data().rev_lookup.find(place.as_ref()); + debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, place, path); + + let path = match path { + LookupResult::Exact(e) => e, + LookupResult::Parent(None) => continue, + LookupResult::Parent(Some(parent)) => { + let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); + if maybe_dead { + span_bug!( + terminator.source_info.span, + "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", + bb, + place, + path + ); + } + continue; + } + }; + + on_all_drop_children_bits(self.tcx, self.body, self.env, path, |child| { + let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child); + debug!( + "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", + child, + place, + path, + (maybe_live, maybe_dead) + ); + if maybe_live && maybe_dead { + self.create_drop_flag(child, terminator.source_info.span) + } + }); + } + } + + fn elaborate_drops(&mut self) { + for (bb, data) in self.body.basic_blocks().iter_enumerated() { + let loc = Location { block: bb, statement_index: data.statements.len() }; + let terminator = data.terminator(); + + let resume_block = self.patch.resume_block(); + match terminator.kind { + TerminatorKind::Drop { place, target, unwind } => { + self.init_data.seek_before(loc); + match self.move_data().rev_lookup.find(place.as_ref()) { + LookupResult::Exact(path) => elaborate_drop( + &mut Elaborator { ctxt: self }, + terminator.source_info, + place, + path, + target, + if data.is_cleanup { + Unwind::InCleanup + } else { + Unwind::To(Option::unwrap_or(unwind, resume_block)) + }, + bb, + ), + LookupResult::Parent(..) => { + span_bug!( + terminator.source_info.span, + "drop of untracked value {:?}", + bb + ); + } + } + } + TerminatorKind::DropAndReplace { place, ref value, target, unwind } => { + assert!(!data.is_cleanup); + + self.elaborate_replace(loc, place, value, target, unwind); + } + _ => continue, + } + } + } + + /// Elaborate a MIR `replace` terminator. This instruction + /// is not directly handled by codegen, and therefore + /// must be desugared. + /// + /// The desugaring drops the location if needed, and then writes + /// the value (including setting the drop flag) over it in *both* arms. + /// + /// The `replace` terminator can also be called on places that + /// are not tracked by elaboration (for example, + /// `replace x[i] <- tmp0`). The borrow checker requires that + /// these locations are initialized before the assignment, + /// so we just generate an unconditional drop. + fn elaborate_replace( + &mut self, + loc: Location, + place: Place<'tcx>, + value: &Operand<'tcx>, + target: BasicBlock, + unwind: Option, + ) { + let bb = loc.block; + let data = &self.body[bb]; + let terminator = data.terminator(); + assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); + + let assign = Statement { + kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value.clone())))), + source_info: terminator.source_info, + }; + + let unwind = unwind.unwrap_or_else(|| self.patch.resume_block()); + let unwind = self.patch.new_block(BasicBlockData { + statements: vec![assign.clone()], + terminator: Some(Terminator { + kind: TerminatorKind::Goto { target: unwind }, + ..*terminator + }), + is_cleanup: true, + }); + + let target = self.patch.new_block(BasicBlockData { + statements: vec![assign], + terminator: Some(Terminator { kind: TerminatorKind::Goto { target }, ..*terminator }), + is_cleanup: false, + }); + + match self.move_data().rev_lookup.find(place.as_ref()) { + LookupResult::Exact(path) => { + debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); + self.init_data.seek_before(loc); + elaborate_drop( + &mut Elaborator { ctxt: self }, + terminator.source_info, + place, + path, + target, + Unwind::To(unwind), + bb, + ); + on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| { + self.set_drop_flag( + Location { block: target, statement_index: 0 }, + child, + DropFlagState::Present, + ); + self.set_drop_flag( + Location { block: unwind, statement_index: 0 }, + child, + DropFlagState::Present, + ); + }); + } + LookupResult::Parent(parent) => { + // drop and replace behind a pointer/array/whatever. The location + // must be initialized. + debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent); + self.patch.patch_terminator( + bb, + TerminatorKind::Drop { place, target, unwind: Some(unwind) }, + ); + } + } + } + + fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> { + Rvalue::Use(Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: ty::Const::from_bool(self.tcx, val).into(), + }))) + } + + fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) { + if let Some(&flag) = self.drop_flags.get(&path) { + let span = self.patch.source_info_for_location(self.body, loc).span; + let val = self.constant_bool(span, val.value()); + self.patch.add_assign(loc, Place::from(flag), val); + } + } + + fn drop_flags_on_init(&mut self) { + let loc = Location::START; + let span = self.patch.source_info_for_location(self.body, loc).span; + let false_ = self.constant_bool(span, false); + for flag in self.drop_flags.values() { + self.patch.add_assign(loc, Place::from(*flag), false_.clone()); + } + } + + fn drop_flags_for_fn_rets(&mut self) { + for (bb, data) in self.body.basic_blocks().iter_enumerated() { + if let TerminatorKind::Call { + destination: Some((ref place, tgt)), + cleanup: Some(_), + .. + } = data.terminator().kind + { + assert!(!self.patch.is_patched(bb)); + + let loc = Location { block: tgt, statement_index: 0 }; + let path = self.move_data().rev_lookup.find(place.as_ref()); + on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| { + self.set_drop_flag(loc, child, DropFlagState::Present) + }); + } + } + } + + fn drop_flags_for_args(&mut self) { + let loc = Location::START; + rustc_mir_dataflow::drop_flag_effects_for_function_entry( + self.tcx, + self.body, + self.env, + |path, ds| { + self.set_drop_flag(loc, path, ds); + }, + ) + } + + fn drop_flags_for_locs(&mut self) { + // We intentionally iterate only over the *old* basic blocks. + // + // Basic blocks created by drop elaboration update their + // drop flags by themselves, to avoid the drop flags being + // clobbered before they are read. + + for (bb, data) in self.body.basic_blocks().iter_enumerated() { + debug!("drop_flags_for_locs({:?})", data); + for i in 0..(data.statements.len() + 1) { + debug!("drop_flag_for_locs: stmt {}", i); + let mut allow_initializations = true; + if i == data.statements.len() { + match data.terminator().kind { + TerminatorKind::Drop { .. } => { + // drop elaboration should handle that by itself + continue; + } + TerminatorKind::DropAndReplace { .. } => { + // this contains the move of the source and + // the initialization of the destination. We + // only want the former - the latter is handled + // by the elaboration code and must be done + // *after* the destination is dropped. + assert!(self.patch.is_patched(bb)); + allow_initializations = false; + } + TerminatorKind::Resume => { + // It is possible for `Resume` to be patched + // (in particular it can be patched to be replaced with + // a Goto; see `MirPatch::new`). + } + _ => { + assert!(!self.patch.is_patched(bb)); + } + } + } + let loc = Location { block: bb, statement_index: i }; + rustc_mir_dataflow::drop_flag_effects_for_location( + self.tcx, + self.body, + self.env, + loc, + |path, ds| { + if ds == DropFlagState::Absent || allow_initializations { + self.set_drop_flag(loc, path, ds) + } + }, + ) + } + + // There may be a critical edge after this call, + // so mark the return as initialized *before* the + // call. + if let TerminatorKind::Call { + destination: Some((ref place, _)), cleanup: None, .. + } = data.terminator().kind + { + assert!(!self.patch.is_patched(bb)); + + let loc = Location { block: bb, statement_index: data.statements.len() }; + let path = self.move_data().rev_lookup.find(place.as_ref()); + on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| { + self.set_drop_flag(loc, child, DropFlagState::Present) + }); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/function_item_references.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/function_item_references.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/function_item_references.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/function_item_references.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,223 @@ +use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::{ + self, + subst::{GenericArgKind, Subst, SubstsRef}, + PredicateKind, Ty, TyCtxt, TyS, +}; +use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; +use rustc_span::{symbol::sym, Span}; +use rustc_target::spec::abi::Abi; + +use crate::MirPass; + +pub struct FunctionItemReferences; + +impl<'tcx> MirPass<'tcx> for FunctionItemReferences { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut checker = FunctionItemRefChecker { tcx, body }; + checker.visit_body(&body); + } +} + +struct FunctionItemRefChecker<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, +} + +impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> { + /// Emits a lint for function reference arguments bound by `fmt::Pointer` or passed to + /// `transmute`. This only handles arguments in calls outside macro expansions to avoid double + /// counting function references formatted as pointers by macros. + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + if let TerminatorKind::Call { + func, + args, + destination: _, + cleanup: _, + from_hir_call: _, + fn_span: _, + } = &terminator.kind + { + let source_info = *self.body.source_info(location); + // Only handle function calls outside macros + if !source_info.span.from_expansion() { + let func_ty = func.ty(self.body, self.tcx); + if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() { + // Handle calls to `transmute` + if self.tcx.is_diagnostic_item(sym::transmute, def_id) { + let arg_ty = args[0].ty(self.body, self.tcx); + for generic_inner_ty in arg_ty.walk(self.tcx) { + if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { + if let Some((fn_id, fn_substs)) = + FunctionItemRefChecker::is_fn_ref(inner_ty) + { + let span = self.nth_arg_span(&args, 0); + self.emit_lint(fn_id, fn_substs, source_info, span); + } + } + } + } else { + self.check_bound_args(def_id, substs_ref, &args, source_info); + } + } + } + } + self.super_terminator(terminator, location); + } + + /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These + /// cases are handled as operands instead of call terminators to avoid any dependence on + /// unstable, internal formatting details like whether `fmt` is called directly or not. + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { + let source_info = *self.body.source_info(location); + if source_info.span.from_expansion() { + let op_ty = operand.ty(self.body, self.tcx); + if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() { + if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) { + let param_ty = substs_ref.type_at(0); + if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(param_ty) { + // The operand's ctxt wouldn't display the lint since it's inside a macro so + // we have to use the callsite's ctxt. + let callsite_ctxt = source_info.span.source_callsite().ctxt(); + let span = source_info.span.with_ctxt(callsite_ctxt); + self.emit_lint(fn_id, fn_substs, source_info, span); + } + } + } + } + self.super_operand(operand, location); + } +} + +impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { + /// Emits a lint for function reference arguments bound by `fmt::Pointer` in calls to the + /// function defined by `def_id` with the substitutions `substs_ref`. + fn check_bound_args( + &self, + def_id: DefId, + substs_ref: SubstsRef<'tcx>, + args: &[Operand<'tcx>], + source_info: SourceInfo, + ) { + let param_env = self.tcx.param_env(def_id); + let bounds = param_env.caller_bounds(); + for bound in bounds { + if let Some(bound_ty) = self.is_pointer_trait(&bound.kind().skip_binder()) { + // Get the argument types as they appear in the function signature. + let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs(); + for (arg_num, arg_def) in arg_defs.iter().enumerate() { + // For all types reachable from the argument type in the fn sig + for generic_inner_ty in arg_def.walk(self.tcx) { + if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { + // If the inner type matches the type bound by `Pointer` + if TyS::same_type(inner_ty, bound_ty) { + // Do a substitution using the parameters from the callsite + let subst_ty = inner_ty.subst(self.tcx, substs_ref); + if let Some((fn_id, fn_substs)) = + FunctionItemRefChecker::is_fn_ref(subst_ty) + { + let span = self.nth_arg_span(args, arg_num); + self.emit_lint(fn_id, fn_substs, source_info, span); + } + } + } + } + } + } + } + } + + /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type. + fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option> { + if let ty::PredicateKind::Trait(predicate) = bound { + if self.tcx.is_diagnostic_item(sym::Pointer, predicate.def_id()) { + Some(predicate.trait_ref.self_ty()) + } else { + None + } + } else { + None + } + } + + /// If a type is a reference or raw pointer to the anonymous type of a function definition, + /// returns that function's `DefId` and `SubstsRef`. + fn is_fn_ref(ty: Ty<'tcx>) -> Option<(DefId, SubstsRef<'tcx>)> { + let referent_ty = match ty.kind() { + ty::Ref(_, referent_ty, _) => Some(referent_ty), + ty::RawPtr(ty_and_mut) => Some(&ty_and_mut.ty), + _ => None, + }; + referent_ty + .map(|ref_ty| { + if let ty::FnDef(def_id, substs_ref) = *ref_ty.kind() { + Some((def_id, substs_ref)) + } else { + None + } + }) + .unwrap_or(None) + } + + fn nth_arg_span(&self, args: &[Operand<'tcx>], n: usize) -> Span { + match &args[n] { + Operand::Copy(place) | Operand::Move(place) => { + self.body.local_decls[place.local].source_info.span + } + Operand::Constant(constant) => constant.span, + } + } + + fn emit_lint( + &self, + fn_id: DefId, + fn_substs: SubstsRef<'tcx>, + source_info: SourceInfo, + span: Span, + ) { + let lint_root = self.body.source_scopes[source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + let fn_sig = self.tcx.fn_sig(fn_id); + let unsafety = fn_sig.unsafety().prefix_str(); + let abi = match fn_sig.abi() { + Abi::Rust => String::from(""), + other_abi => { + let mut s = String::from("extern \""); + s.push_str(other_abi.name()); + s.push_str("\" "); + s + } + }; + let ident = self.tcx.item_name(fn_id).to_ident_string(); + let ty_params = fn_substs.types().map(|ty| format!("{}", ty)); + let const_params = fn_substs.consts().map(|c| format!("{}", c)); + let params = ty_params.chain(const_params).collect::>().join(", "); + let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); + let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; + let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; + self.tcx.struct_span_lint_hir(FUNCTION_ITEM_REFERENCES, lint_root, span, |lint| { + lint.build("taking a reference to a function item does not give a function pointer") + .span_suggestion( + span, + &format!("cast `{}` to obtain a function pointer", ident), + format!( + "{} as {}{}fn({}{}){}", + if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) }, + unsafety, + abi, + vec!["_"; num_args].join(", "), + variadic, + ret, + ), + Applicability::Unspecified, + ) + .emit(); + }); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/generator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/generator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/generator.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/generator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1501 @@ +//! This is the implementation of the pass which transforms generators into state machines. +//! +//! MIR generation for generators creates a function which has a self argument which +//! passes by value. This argument is effectively a generator type which only contains upvars and +//! is only used for this argument inside the MIR for the generator. +//! It is passed by value to enable upvars to be moved out of it. Drop elaboration runs on that +//! MIR before this pass and creates drop flags for MIR locals. +//! It will also drop the generator argument (which only consists of upvars) if any of the upvars +//! are moved out of. This pass elaborates the drops of upvars / generator argument in the case +//! that none of the upvars were moved out of. This is because we cannot have any drops of this +//! generator in the MIR, since it is used to create the drop glue for the generator. We'd get +//! infinite recursion otherwise. +//! +//! This pass creates the implementation for the Generator::resume function and the drop shim +//! for the generator based on the MIR input. It converts the generator argument from Self to +//! &mut Self adding derefs in the MIR as needed. It computes the final layout of the generator +//! struct which looks like this: +//! First upvars are stored +//! It is followed by the generator state field. +//! Then finally the MIR locals which are live across a suspension point are stored. +//! +//! struct Generator { +//! upvars..., +//! state: u32, +//! mir_locals..., +//! } +//! +//! This pass computes the meaning of the state field and the MIR locals which are live +//! across a suspension point. There are however three hardcoded generator states: +//! 0 - Generator have not been resumed yet +//! 1 - Generator has returned / is completed +//! 2 - Generator has been poisoned +//! +//! It also rewrites `return x` and `yield y` as setting a new generator state and returning +//! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively. +//! MIR locals which are live across a suspension point are moved to the generator struct +//! with references to them being updated with references to the generator struct. +//! +//! The pass creates two functions which have a switch on the generator state giving +//! the action to take. +//! +//! One of them is the implementation of Generator::resume. +//! For generators with state 0 (unresumed) it starts the execution of the generator. +//! For generators with state 1 (returned) and state 2 (poisoned) it panics. +//! Otherwise it continues the execution from the last suspension point. +//! +//! The other function is the drop glue for the generator. +//! For generators with state 0 (unresumed) it drops the upvars of the generator. +//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing. +//! Otherwise it drops all the values in scope at the last suspension point. + +use crate::simplify; +use crate::util::expand_aggregate; +use crate::MirPass; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir as hir; +use rustc_hir::lang_items::LangItem; +use rustc_index::bit_set::{BitMatrix, BitSet}; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::dump_mir; +use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::GeneratorSubsts; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_mir_dataflow::impls::{ + MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, +}; +use rustc_mir_dataflow::storage; +use rustc_mir_dataflow::{self, Analysis}; +use rustc_target::abi::VariantIdx; +use rustc_target::spec::PanicStrategy; +use std::{iter, ops}; + +pub struct StateTransform; + +struct RenameLocalVisitor<'tcx> { + from: Local, + to: Local, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { + if *local == self.from { + *local = self.to; + } + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + match terminator.kind { + TerminatorKind::Return => { + // Do not replace the implicit `_0` access here, as that's not possible. The + // transform already handles `return` correctly. + } + _ => self.super_terminator(terminator, location), + } + } +} + +struct DerefArgVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { + assert_ne!(*local, SELF_ARG); + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + if place.local == SELF_ARG { + replace_base( + place, + Place { + local: SELF_ARG, + projection: self.tcx().intern_place_elems(&[ProjectionElem::Deref]), + }, + self.tcx, + ); + } else { + self.visit_local(&mut place.local, context, location); + + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(local, SELF_ARG); + } + } + } + } +} + +struct PinArgVisitor<'tcx> { + ref_gen_ty: Ty<'tcx>, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { + assert_ne!(*local, SELF_ARG); + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + if place.local == SELF_ARG { + replace_base( + place, + Place { + local: SELF_ARG, + projection: self.tcx().intern_place_elems(&[ProjectionElem::Field( + Field::new(0), + self.ref_gen_ty, + )]), + }, + self.tcx, + ); + } else { + self.visit_local(&mut place.local, context, location); + + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(local, SELF_ARG); + } + } + } + } +} + +fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) { + place.local = new_base.local; + + let mut new_projection = new_base.projection.to_vec(); + new_projection.append(&mut place.projection.to_vec()); + + place.projection = tcx.intern_place_elems(&new_projection); +} + +const SELF_ARG: Local = Local::from_u32(1); + +/// Generator has not been resumed yet. +const UNRESUMED: usize = GeneratorSubsts::UNRESUMED; +/// Generator has returned / is completed. +const RETURNED: usize = GeneratorSubsts::RETURNED; +/// Generator has panicked and is poisoned. +const POISONED: usize = GeneratorSubsts::POISONED; + +/// A `yield` point in the generator. +struct SuspensionPoint<'tcx> { + /// State discriminant used when suspending or resuming at this point. + state: usize, + /// The block to jump to after resumption. + resume: BasicBlock, + /// Where to move the resume argument after resumption. + resume_arg: Place<'tcx>, + /// Which block to jump to if the generator is dropped in this state. + drop: Option, + /// Set of locals that have live storage while at this suspension point. + storage_liveness: BitSet, +} + +struct TransformVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + state_adt_ref: &'tcx AdtDef, + state_substs: SubstsRef<'tcx>, + + // The type of the discriminant in the generator struct + discr_ty: Ty<'tcx>, + + // Mapping from Local to (type of local, generator struct index) + // FIXME(eddyb) This should use `IndexVec>`. + remap: FxHashMap, VariantIdx, usize)>, + + // A map from a suspension point in a block to the locals which have live storage at that point + storage_liveness: IndexVec>>, + + // A list of suspension points, generated during the transform + suspension_points: Vec>, + + // The set of locals that have no `StorageLive`/`StorageDead` annotations. + always_live_locals: storage::AlwaysLiveLocals, + + // The original RETURN_PLACE local + new_ret_local: Local, +} + +impl TransformVisitor<'tcx> { + // Make a GeneratorState variant assignment. `core::ops::GeneratorState` only has single + // element tuple variants, so we can just write to the downcasted first field and then set the + // discriminant to the appropriate variant. + fn make_state( + &self, + idx: VariantIdx, + val: Operand<'tcx>, + source_info: SourceInfo, + ) -> impl Iterator> { + let kind = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None); + assert_eq!(self.state_adt_ref.variants[idx].fields.len(), 1); + let ty = self + .tcx + .type_of(self.state_adt_ref.variants[idx].fields[0].did) + .subst(self.tcx, self.state_substs); + expand_aggregate( + Place::return_place(), + std::iter::once((val, ty)), + kind, + source_info, + self.tcx, + ) + } + + // Create a Place referencing a generator struct field + fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { + let self_place = Place::from(SELF_ARG); + let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index); + let mut projection = base.projection.to_vec(); + projection.push(ProjectionElem::Field(Field::new(idx), ty)); + + Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) } + } + + // Create a statement which changes the discriminant + fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> { + let self_place = Place::from(SELF_ARG); + Statement { + source_info, + kind: StatementKind::SetDiscriminant { + place: Box::new(self_place), + variant_index: state_disc, + }, + } + } + + // Create a statement which reads the discriminant into a temporary + fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) { + let temp_decl = LocalDecl::new(self.discr_ty, body.span).internal(); + let local_decls_len = body.local_decls.push(temp_decl); + let temp = Place::from(local_decls_len); + + let self_place = Place::from(SELF_ARG); + let assign = Statement { + source_info: SourceInfo::outermost(body.span), + kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))), + }; + (assign, temp) + } +} + +impl MutVisitor<'tcx> for TransformVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { + assert_eq!(self.remap.get(local), None); + } + + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + _context: PlaceContext, + _location: Location, + ) { + // Replace an Local in the remap with a generator struct access + if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) { + replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); + } + } + + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { + // Remove StorageLive and StorageDead statements for remapped locals + data.retain_statements(|s| match s.kind { + StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { + !self.remap.contains_key(&l) + } + _ => true, + }); + + let ret_val = match data.terminator().kind { + TerminatorKind::Return => Some(( + VariantIdx::new(1), + None, + Operand::Move(Place::from(self.new_ret_local)), + None, + )), + TerminatorKind::Yield { ref value, resume, resume_arg, drop } => { + Some((VariantIdx::new(0), Some((resume, resume_arg)), value.clone(), drop)) + } + _ => None, + }; + + if let Some((state_idx, resume, v, drop)) = ret_val { + let source_info = data.terminator().source_info; + // We must assign the value first in case it gets declared dead below + data.statements.extend(self.make_state(state_idx, v, source_info)); + let state = if let Some((resume, mut resume_arg)) = resume { + // Yield + let state = 3 + self.suspension_points.len(); + + // The resume arg target location might itself be remapped if its base local is + // live across a yield. + let resume_arg = + if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) { + replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx); + resume_arg + } else { + resume_arg + }; + + self.suspension_points.push(SuspensionPoint { + state, + resume, + resume_arg, + drop, + storage_liveness: self.storage_liveness[block].clone().unwrap(), + }); + + VariantIdx::new(state) + } else { + // Return + VariantIdx::new(RETURNED) // state for returned + }; + data.statements.push(self.set_discr(state, source_info)); + data.terminator_mut().kind = TerminatorKind::Return; + } + + self.super_basic_block_data(block, data); + } +} + +fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let gen_ty = body.local_decls.raw[1].ty; + + let ref_gen_ty = + tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut }); + + // Replace the by value generator argument + body.local_decls.raw[1].ty = ref_gen_ty; + + // Add a deref to accesses of the generator state + DerefArgVisitor { tcx }.visit_body(body); +} + +fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let ref_gen_ty = body.local_decls.raw[1].ty; + + let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span)); + let pin_adt_ref = tcx.adt_def(pin_did); + let substs = tcx.intern_substs(&[ref_gen_ty.into()]); + let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs); + + // Replace the by ref generator argument + body.local_decls.raw[1].ty = pin_ref_gen_ty; + + // Add the Pin field access to accesses of the generator state + PinArgVisitor { ref_gen_ty, tcx }.visit_body(body); +} + +/// Allocates a new local and replaces all references of `local` with it. Returns the new local. +/// +/// `local` will be changed to a new local decl with type `ty`. +/// +/// Note that the new local will be uninitialized. It is the caller's responsibility to assign some +/// valid value to it before its first use. +fn replace_local<'tcx>( + local: Local, + ty: Ty<'tcx>, + body: &mut Body<'tcx>, + tcx: TyCtxt<'tcx>, +) -> Local { + let new_decl = LocalDecl::new(ty, body.span); + let new_local = body.local_decls.push(new_decl); + body.local_decls.swap(local, new_local); + + RenameLocalVisitor { from: local, to: new_local, tcx }.visit_body(body); + + new_local +} + +struct LivenessInfo { + /// Which locals are live across any suspension point. + saved_locals: GeneratorSavedLocals, + + /// The set of saved locals live at each suspension point. + live_locals_at_suspension_points: Vec>, + + /// Parallel vec to the above with SourceInfo for each yield terminator. + source_info_at_suspension_points: Vec, + + /// For every saved local, the set of other saved locals that are + /// storage-live at the same time as this local. We cannot overlap locals in + /// the layout which have conflicting storage. + storage_conflicts: BitMatrix, + + /// For every suspending block, the locals which are storage-live across + /// that suspension point. + storage_liveness: IndexVec>>, +} + +fn locals_live_across_suspend_points( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + always_live_locals: &storage::AlwaysLiveLocals, + movable: bool, +) -> LivenessInfo { + let body_ref: &Body<'_> = &body; + + // Calculate when MIR locals have live storage. This gives us an upper bound of their + // lifetimes. + let mut storage_live = MaybeStorageLive::new(always_live_locals.clone()) + .into_engine(tcx, body_ref) + .iterate_to_fixpoint() + .into_results_cursor(body_ref); + + // Calculate the MIR locals which have been previously + // borrowed (even if they are still active). + let borrowed_locals_results = MaybeBorrowedLocals::all_borrows() + .into_engine(tcx, body_ref) + .pass_name("generator") + .iterate_to_fixpoint(); + + let mut borrowed_locals_cursor = + rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results); + + // Calculate the MIR locals that we actually need to keep storage around + // for. + let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results) + .into_engine(tcx, body_ref) + .iterate_to_fixpoint(); + let mut requires_storage_cursor = + rustc_mir_dataflow::ResultsCursor::new(body_ref, &requires_storage_results); + + // Calculate the liveness of MIR locals ignoring borrows. + let mut liveness = MaybeLiveLocals + .into_engine(tcx, body_ref) + .pass_name("generator") + .iterate_to_fixpoint() + .into_results_cursor(body_ref); + + let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks()); + let mut live_locals_at_suspension_points = Vec::new(); + let mut source_info_at_suspension_points = Vec::new(); + let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len()); + + for (block, data) in body.basic_blocks().iter_enumerated() { + if let TerminatorKind::Yield { .. } = data.terminator().kind { + let loc = Location { block, statement_index: data.statements.len() }; + + liveness.seek_to_block_end(block); + let mut live_locals = liveness.get().clone(); + + if !movable { + // The `liveness` variable contains the liveness of MIR locals ignoring borrows. + // This is correct for movable generators since borrows cannot live across + // suspension points. However for immovable generators we need to account for + // borrows, so we conseratively assume that all borrowed locals are live until + // we find a StorageDead statement referencing the locals. + // To do this we just union our `liveness` result with `borrowed_locals`, which + // contains all the locals which has been borrowed before this suspension point. + // If a borrow is converted to a raw reference, we must also assume that it lives + // forever. Note that the final liveness is still bounded by the storage liveness + // of the local, which happens using the `intersect` operation below. + borrowed_locals_cursor.seek_before_primary_effect(loc); + live_locals.union(borrowed_locals_cursor.get()); + } + + // Store the storage liveness for later use so we can restore the state + // after a suspension point + storage_live.seek_before_primary_effect(loc); + storage_liveness_map[block] = Some(storage_live.get().clone()); + + // Locals live are live at this point only if they are used across + // suspension points (the `liveness` variable) + // and their storage is required (the `storage_required` variable) + requires_storage_cursor.seek_before_primary_effect(loc); + live_locals.intersect(requires_storage_cursor.get()); + + // The generator argument is ignored. + live_locals.remove(SELF_ARG); + + debug!("loc = {:?}, live_locals = {:?}", loc, live_locals); + + // Add the locals live at this suspension point to the set of locals which live across + // any suspension points + live_locals_at_any_suspension_point.union(&live_locals); + + live_locals_at_suspension_points.push(live_locals); + source_info_at_suspension_points.push(data.terminator().source_info); + } + } + + debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point); + let saved_locals = GeneratorSavedLocals(live_locals_at_any_suspension_point); + + // Renumber our liveness_map bitsets to include only the locals we are + // saving. + let live_locals_at_suspension_points = live_locals_at_suspension_points + .iter() + .map(|live_here| saved_locals.renumber_bitset(&live_here)) + .collect(); + + let storage_conflicts = compute_storage_conflicts( + body_ref, + &saved_locals, + always_live_locals.clone(), + requires_storage_results, + ); + + LivenessInfo { + saved_locals, + live_locals_at_suspension_points, + source_info_at_suspension_points, + storage_conflicts, + storage_liveness: storage_liveness_map, + } +} + +/// The set of `Local`s that must be saved across yield points. +/// +/// `GeneratorSavedLocal` is indexed in terms of the elements in this set; +/// i.e. `GeneratorSavedLocal::new(1)` corresponds to the second local +/// included in this set. +struct GeneratorSavedLocals(BitSet); + +impl GeneratorSavedLocals { + /// Returns an iterator over each `GeneratorSavedLocal` along with the `Local` it corresponds + /// to. + fn iter_enumerated(&self) -> impl '_ + Iterator { + self.iter().enumerate().map(|(i, l)| (GeneratorSavedLocal::from(i), l)) + } + + /// Transforms a `BitSet` that contains only locals saved across yield points to the + /// equivalent `BitSet`. + fn renumber_bitset(&self, input: &BitSet) -> BitSet { + assert!(self.superset(&input), "{:?} not a superset of {:?}", self.0, input); + let mut out = BitSet::new_empty(self.count()); + for (saved_local, local) in self.iter_enumerated() { + if input.contains(local) { + out.insert(saved_local); + } + } + out + } + + fn get(&self, local: Local) -> Option { + if !self.contains(local) { + return None; + } + + let idx = self.iter().take_while(|&l| l < local).count(); + Some(GeneratorSavedLocal::new(idx)) + } +} + +impl ops::Deref for GeneratorSavedLocals { + type Target = BitSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// For every saved local, looks for which locals are StorageLive at the same +/// time. Generates a bitset for every local of all the other locals that may be +/// StorageLive simultaneously with that local. This is used in the layout +/// computation; see `GeneratorLayout` for more. +fn compute_storage_conflicts( + body: &'mir Body<'tcx>, + saved_locals: &GeneratorSavedLocals, + always_live_locals: storage::AlwaysLiveLocals, + requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, +) -> BitMatrix { + assert_eq!(body.local_decls.len(), saved_locals.domain_size()); + + debug!("compute_storage_conflicts({:?})", body.span); + debug!("always_live = {:?}", always_live_locals); + + // Locals that are always live or ones that need to be stored across + // suspension points are not eligible for overlap. + let mut ineligible_locals = always_live_locals.into_inner(); + ineligible_locals.intersect(&**saved_locals); + + // Compute the storage conflicts for all eligible locals. + let mut visitor = StorageConflictVisitor { + body, + saved_locals: &saved_locals, + local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), + }; + + requires_storage.visit_reachable_with(body, &mut visitor); + + let local_conflicts = visitor.local_conflicts; + + // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal). + // + // NOTE: Today we store a full conflict bitset for every local. Technically + // this is twice as many bits as we need, since the relation is symmetric. + // However, in practice these bitsets are not usually large. The layout code + // also needs to keep track of how many conflicts each local has, so it's + // simpler to keep it this way for now. + let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count()); + for (saved_local_a, local_a) in saved_locals.iter_enumerated() { + if ineligible_locals.contains(local_a) { + // Conflicts with everything. + storage_conflicts.insert_all_into_row(saved_local_a); + } else { + // Keep overlap information only for stored locals. + for (saved_local_b, local_b) in saved_locals.iter_enumerated() { + if local_conflicts.contains(local_a, local_b) { + storage_conflicts.insert(saved_local_a, saved_local_b); + } + } + } + } + storage_conflicts +} + +struct StorageConflictVisitor<'mir, 'tcx, 's> { + body: &'mir Body<'tcx>, + saved_locals: &'s GeneratorSavedLocals, + // FIXME(tmandry): Consider using sparse bitsets here once we have good + // benchmarks for generators. + local_conflicts: BitMatrix, +} + +impl rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> { + type FlowState = BitSet; + + fn visit_statement_before_primary_effect( + &mut self, + state: &Self::FlowState, + _statement: &'mir Statement<'tcx>, + loc: Location, + ) { + self.apply_state(state, loc); + } + + fn visit_terminator_before_primary_effect( + &mut self, + state: &Self::FlowState, + _terminator: &'mir Terminator<'tcx>, + loc: Location, + ) { + self.apply_state(state, loc); + } +} + +impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> { + fn apply_state(&mut self, flow_state: &BitSet, loc: Location) { + // Ignore unreachable blocks. + if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable { + return; + } + + let mut eligible_storage_live = flow_state.clone(); + eligible_storage_live.intersect(&**self.saved_locals); + + for local in eligible_storage_live.iter() { + self.local_conflicts.union_row_with(&eligible_storage_live, local); + } + + if eligible_storage_live.count() > 1 { + trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live); + } + } +} + +/// Validates the typeck view of the generator against the actual set of types saved between +/// yield points. +fn sanitize_witness<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + witness: Ty<'tcx>, + upvars: Vec>, + saved_locals: &GeneratorSavedLocals, +) { + let did = body.source.def_id(); + let allowed_upvars = tcx.erase_regions(upvars); + let allowed = match witness.kind() { + &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s), + _ => { + tcx.sess.delay_span_bug( + body.span, + &format!("unexpected generator witness type {:?}", witness.kind()), + ); + return; + } + }; + + let param_env = tcx.param_env(did); + + for (local, decl) in body.local_decls.iter_enumerated() { + // Ignore locals which are internal or not saved between yields. + if !saved_locals.contains(local) || decl.internal { + continue; + } + let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty); + + // Sanity check that typeck knows about the type of locals which are + // live across a suspension point + if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) { + span_bug!( + body.span, + "Broken MIR: generator contains type {} in MIR, \ + but typeck only knows about {} and {:?}", + decl_ty, + allowed, + allowed_upvars + ); + } + } +} + +fn compute_layout<'tcx>( + liveness: LivenessInfo, + body: &mut Body<'tcx>, +) -> ( + FxHashMap, VariantIdx, usize)>, + GeneratorLayout<'tcx>, + IndexVec>>, +) { + let LivenessInfo { + saved_locals, + live_locals_at_suspension_points, + source_info_at_suspension_points, + storage_conflicts, + storage_liveness, + } = liveness; + + // Gather live local types and their indices. + let mut locals = IndexVec::::new(); + let mut tys = IndexVec::::new(); + for (saved_local, local) in saved_locals.iter_enumerated() { + locals.push(local); + tys.push(body.local_decls[local].ty); + debug!("generator saved local {:?} => {:?}", saved_local, local); + } + + // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. + // In debuginfo, these will correspond to the beginning (UNRESUMED) or end + // (RETURNED, POISONED) of the function. + const RESERVED_VARIANTS: usize = 3; + let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span; + let mut variant_source_info: IndexVec = [ + SourceInfo::outermost(body_span.shrink_to_lo()), + SourceInfo::outermost(body_span.shrink_to_hi()), + SourceInfo::outermost(body_span.shrink_to_hi()), + ] + .iter() + .copied() + .collect(); + + // Build the generator variant field list. + // Create a map from local indices to generator struct indices. + let mut variant_fields: IndexVec> = + iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect(); + let mut remap = FxHashMap::default(); + for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() { + let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx); + let mut fields = IndexVec::new(); + for (idx, saved_local) in live_locals.iter().enumerate() { + fields.push(saved_local); + // Note that if a field is included in multiple variants, we will + // just use the first one here. That's fine; fields do not move + // around inside generators, so it doesn't matter which variant + // index we access them by. + remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx)); + } + variant_fields.push(fields); + variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]); + } + debug!("generator variant_fields = {:?}", variant_fields); + debug!("generator storage_conflicts = {:#?}", storage_conflicts); + + let layout = + GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; + + (remap, layout, storage_liveness) +} + +/// Replaces the entry point of `body` with a block that switches on the generator discriminant and +/// dispatches to blocks according to `cases`. +/// +/// After this function, the former entry point of the function will be bb1. +fn insert_switch<'tcx>( + body: &mut Body<'tcx>, + cases: Vec<(usize, BasicBlock)>, + transform: &TransformVisitor<'tcx>, + default: TerminatorKind<'tcx>, +) { + let default_block = insert_term_block(body, default); + let (assign, discr) = transform.get_discr(body); + let switch_targets = + SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block); + let switch = TerminatorKind::SwitchInt { + discr: Operand::Move(discr), + switch_ty: transform.discr_ty, + targets: switch_targets, + }; + + let source_info = SourceInfo::outermost(body.span); + body.basic_blocks_mut().raw.insert( + 0, + BasicBlockData { + statements: vec![assign], + terminator: Some(Terminator { source_info, kind: switch }), + is_cleanup: false, + }, + ); + + let blocks = body.basic_blocks_mut().iter_mut(); + + for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { + *target = BasicBlock::new(target.index() + 1); + } +} + +fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + use crate::shim::DropShimElaborator; + use rustc_middle::mir::patch::MirPatch; + use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, Unwind}; + + // Note that `elaborate_drops` only drops the upvars of a generator, and + // this is ok because `open_drop` can only be reached within that own + // generator's resume function. + + let def_id = body.source.def_id(); + let param_env = tcx.param_env(def_id); + + let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env }; + + for (block, block_data) in body.basic_blocks().iter_enumerated() { + let (target, unwind, source_info) = match block_data.terminator() { + Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => { + if let Some(local) = place.as_local() { + if local == SELF_ARG { + (target, unwind, source_info) + } else { + continue; + } + } else { + continue; + } + } + _ => continue, + }; + let unwind = if block_data.is_cleanup { + Unwind::InCleanup + } else { + Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block())) + }; + elaborate_drop( + &mut elaborator, + *source_info, + Place::from(SELF_ARG), + (), + *target, + unwind, + block, + ); + } + elaborator.patch.apply(body); +} + +fn create_generator_drop_shim<'tcx>( + tcx: TyCtxt<'tcx>, + transform: &TransformVisitor<'tcx>, + gen_ty: Ty<'tcx>, + body: &mut Body<'tcx>, + drop_clean: BasicBlock, +) -> Body<'tcx> { + let mut body = body.clone(); + body.arg_count = 1; // make sure the resume argument is not included here + + let source_info = SourceInfo::outermost(body.span); + + let mut cases = create_cases(&mut body, transform, Operation::Drop); + + cases.insert(0, (UNRESUMED, drop_clean)); + + // The returned state and the poisoned state fall through to the default + // case which is just to return + + insert_switch(&mut body, cases, &transform, TerminatorKind::Return); + + for block in body.basic_blocks_mut() { + let kind = &mut block.terminator_mut().kind; + if let TerminatorKind::GeneratorDrop = *kind { + *kind = TerminatorKind::Return; + } + } + + // Replace the return variable + body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(tcx.mk_unit(), source_info); + + make_generator_state_argument_indirect(tcx, &mut body); + + // Change the generator argument from &mut to *mut + body.local_decls[SELF_ARG] = LocalDecl::with_source_info( + tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }), + source_info, + ); + if tcx.sess.opts.debugging_opts.mir_emit_retag { + // Alias tracking must know we changed the type + body.basic_blocks_mut()[START_BLOCK].statements.insert( + 0, + Statement { + source_info, + kind: StatementKind::Retag(RetagKind::Raw, Box::new(Place::from(SELF_ARG))), + }, + ) + } + + // Make sure we remove dead blocks to remove + // unrelated code from the resume part of the function + simplify::remove_dead_blocks(tcx, &mut body); + + dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(())); + + body +} + +fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock { + let source_info = SourceInfo::outermost(body.span); + body.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { source_info, kind }), + is_cleanup: false, + }) +} + +fn insert_panic_block<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + message: AssertMessage<'tcx>, +) -> BasicBlock { + let assert_block = BasicBlock::new(body.basic_blocks().len()); + let term = TerminatorKind::Assert { + cond: Operand::Constant(Box::new(Constant { + span: body.span, + user_ty: None, + literal: ty::Const::from_bool(tcx, false).into(), + })), + expected: true, + msg: message, + target: assert_block, + cleanup: None, + }; + + let source_info = SourceInfo::outermost(body.span); + body.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { source_info, kind: term }), + is_cleanup: false, + }); + + assert_block +} + +fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + // Returning from a function with an uninhabited return type is undefined behavior. + if tcx.conservative_is_privately_uninhabited(param_env.and(body.return_ty())) { + return false; + } + + // If there's a return terminator the function may return. + for block in body.basic_blocks() { + if let TerminatorKind::Return = block.terminator().kind { + return true; + } + } + + // Otherwise the function can't return. + false +} + +fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { + // Nothing can unwind when landing pads are off. + if tcx.sess.panic_strategy() == PanicStrategy::Abort { + return false; + } + + // Unwinds can only start at certain terminators. + for block in body.basic_blocks() { + match block.terminator().kind { + // These never unwind. + TerminatorKind::Goto { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => {} + + // Resume will *continue* unwinding, but if there's no other unwinding terminator it + // will never be reached. + TerminatorKind::Resume => {} + + TerminatorKind::Yield { .. } => { + unreachable!("`can_unwind` called before generator transform") + } + + // These may unwind. + TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::Assert { .. } => return true, + } + } + + // If we didn't find an unwinding terminator, the function cannot unwind. + false +} + +fn create_generator_resume_function<'tcx>( + tcx: TyCtxt<'tcx>, + transform: TransformVisitor<'tcx>, + body: &mut Body<'tcx>, + can_return: bool, +) { + let can_unwind = can_unwind(tcx, body); + + // Poison the generator when it unwinds + if can_unwind { + let source_info = SourceInfo::outermost(body.span); + let poison_block = body.basic_blocks_mut().push(BasicBlockData { + statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)], + terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }), + is_cleanup: true, + }); + + for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() { + let source_info = block.terminator().source_info; + + if let TerminatorKind::Resume = block.terminator().kind { + // An existing `Resume` terminator is redirected to jump to our dedicated + // "poisoning block" above. + if idx != poison_block { + *block.terminator_mut() = Terminator { + source_info, + kind: TerminatorKind::Goto { target: poison_block }, + }; + } + } else if !block.is_cleanup { + // Any terminators that *can* unwind but don't have an unwind target set are also + // pointed at our poisoning block (unless they're part of the cleanup path). + if let Some(unwind @ None) = block.terminator_mut().unwind_mut() { + *unwind = Some(poison_block); + } + } + } + } + + let mut cases = create_cases(body, &transform, Operation::Resume); + + use rustc_middle::mir::AssertKind::{ResumedAfterPanic, ResumedAfterReturn}; + + // Jump to the entry point on the unresumed + cases.insert(0, (UNRESUMED, BasicBlock::new(0))); + + // Panic when resumed on the returned or poisoned state + let generator_kind = body.generator_kind().unwrap(); + + if can_unwind { + cases.insert( + 1, + (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind))), + ); + } + + if can_return { + cases.insert( + 1, + (RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(generator_kind))), + ); + } + + insert_switch(body, cases, &transform, TerminatorKind::Unreachable); + + make_generator_state_argument_indirect(tcx, body); + make_generator_state_argument_pinned(tcx, body); + + // Make sure we remove dead blocks to remove + // unrelated code from the drop part of the function + simplify::remove_dead_blocks(tcx, body); + + dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(())); +} + +fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { + let return_block = insert_term_block(body, TerminatorKind::Return); + + let term = + TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None }; + let source_info = SourceInfo::outermost(body.span); + + // Create a block to destroy an unresumed generators. This can only destroy upvars. + body.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { source_info, kind: term }), + is_cleanup: false, + }) +} + +/// An operation that can be performed on a generator. +#[derive(PartialEq, Copy, Clone)] +enum Operation { + Resume, + Drop, +} + +impl Operation { + fn target_block(self, point: &SuspensionPoint<'_>) -> Option { + match self { + Operation::Resume => Some(point.resume), + Operation::Drop => point.drop, + } + } +} + +fn create_cases<'tcx>( + body: &mut Body<'tcx>, + transform: &TransformVisitor<'tcx>, + operation: Operation, +) -> Vec<(usize, BasicBlock)> { + let source_info = SourceInfo::outermost(body.span); + + transform + .suspension_points + .iter() + .filter_map(|point| { + // Find the target for this suspension point, if applicable + operation.target_block(point).map(|target| { + let mut statements = Vec::new(); + + // Create StorageLive instructions for locals with live storage + for i in 0..(body.local_decls.len()) { + if i == 2 { + // The resume argument is live on function entry. Don't insert a + // `StorageLive`, or the following `Assign` will read from uninitialized + // memory. + continue; + } + + let l = Local::new(i); + let needs_storage_live = point.storage_liveness.contains(l) + && !transform.remap.contains_key(&l) + && !transform.always_live_locals.contains(l); + if needs_storage_live { + statements + .push(Statement { source_info, kind: StatementKind::StorageLive(l) }); + } + } + + if operation == Operation::Resume { + // Move the resume argument to the destination place of the `Yield` terminator + let resume_arg = Local::new(2); // 0 = return, 1 = self + statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + point.resume_arg, + Rvalue::Use(Operand::Move(resume_arg.into())), + ))), + }); + } + + // Then jump to the real target + let block = body.basic_blocks_mut().push(BasicBlockData { + statements, + terminator: Some(Terminator { + source_info, + kind: TerminatorKind::Goto { target }, + }), + is_cleanup: false, + }); + + (point.state, block) + }) + }) + .collect() +} + +impl<'tcx> MirPass<'tcx> for StateTransform { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let yield_ty = if let Some(yield_ty) = body.yield_ty() { + yield_ty + } else { + // This only applies to generators + return; + }; + + assert!(body.generator_drop().is_none()); + + // The first argument is the generator type passed by value + let gen_ty = body.local_decls.raw[1].ty; + + // Get the interior types and substs which typeck computed + let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() { + ty::Generator(_, substs, movability) => { + let substs = substs.as_generator(); + ( + substs.upvar_tys().collect(), + substs.witness(), + substs.discr_ty(tcx), + movability == hir::Movability::Movable, + ) + } + _ => { + tcx.sess + .delay_span_bug(body.span, &format!("unexpected generator type {}", gen_ty)); + return; + } + }; + + // Compute GeneratorState + let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]); + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + + // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local + // RETURN_PLACE then is a fresh unused local with type ret_ty. + let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx); + + // We also replace the resume argument and insert an `Assign`. + // This is needed because the resume argument `_2` might be live across a `yield`, in which + // case there is no `Assign` to it that the transform can turn into a store to the generator + // state. After the yield the slot in the generator state would then be uninitialized. + let resume_local = Local::new(2); + let new_resume_local = + replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx); + + // When first entering the generator, move the resume argument into its new local. + let source_info = SourceInfo::outermost(body.span); + let stmts = &mut body.basic_blocks_mut()[BasicBlock::new(0)].statements; + stmts.insert( + 0, + Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + new_resume_local.into(), + Rvalue::Use(Operand::Move(resume_local.into())), + ))), + }, + ); + + let always_live_locals = storage::AlwaysLiveLocals::new(&body); + + let liveness_info = + locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); + + sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals); + + if tcx.sess.opts.debugging_opts.validate_mir { + let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias { + assigned_local: None, + saved_locals: &liveness_info.saved_locals, + storage_conflicts: &liveness_info.storage_conflicts, + }; + + vis.visit_body(body); + } + + // Extract locals which are live across suspension point into `layout` + // `remap` gives a mapping from local indices onto generator struct indices + // `storage_liveness` tells us which locals have live storage at suspension points + let (remap, layout, storage_liveness) = compute_layout(liveness_info, body); + + let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id())); + + // Run the transformation which converts Places from Local to generator struct + // accesses for locals in `remap`. + // It also rewrites `return x` and `yield y` as writing a new generator state and returning + // GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively. + let mut transform = TransformVisitor { + tcx, + state_adt_ref, + state_substs, + remap, + storage_liveness, + always_live_locals, + suspension_points: Vec::new(), + new_ret_local, + discr_ty, + }; + transform.visit_body(body); + + // Update our MIR struct to reflect the changes we've made + body.arg_count = 2; // self, resume arg + body.spread_arg = None; + + body.generator.as_mut().unwrap().yield_ty = None; + body.generator.as_mut().unwrap().generator_layout = Some(layout); + + // Insert `drop(generator_struct)` which is used to drop upvars for generators in + // the unresumed state. + // This is expanded to a drop ladder in `elaborate_generator_drops`. + let drop_clean = insert_clean_drop(body); + + dump_mir(tcx, None, "generator_pre-elab", &0, body, |_, _| Ok(())); + + // Expand `drop(generator_struct)` to a drop ladder which destroys upvars. + // If any upvars are moved out of, drop elaboration will handle upvar destruction. + // However we need to also elaborate the code generated by `insert_clean_drop`. + elaborate_generator_drops(tcx, body); + + dump_mir(tcx, None, "generator_post-transform", &0, body, |_, _| Ok(())); + + // Create a copy of our MIR and use it to create the drop shim for the generator + let drop_shim = create_generator_drop_shim(tcx, &transform, gen_ty, body, drop_clean); + + body.generator.as_mut().unwrap().generator_drop = Some(drop_shim); + + // Create the Generator::resume function + create_generator_resume_function(tcx, transform, body, can_return); + } +} + +/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields +/// in the generator state machine but whose storage is not marked as conflicting +/// +/// Validation needs to happen immediately *before* `TransformVisitor` is invoked, not after. +/// +/// This condition would arise when the assignment is the last use of `_5` but the initial +/// definition of `_4` if we weren't extra careful to mark all locals used inside a statement as +/// conflicting. Non-conflicting generator saved locals may be stored at the same location within +/// the generator state machine, which would result in ill-formed MIR: the left-hand and right-hand +/// sides of an assignment may not alias. This caused a miscompilation in [#73137]. +/// +/// [#73137]: https://github.com/rust-lang/rust/issues/73137 +struct EnsureGeneratorFieldAssignmentsNeverAlias<'a> { + saved_locals: &'a GeneratorSavedLocals, + storage_conflicts: &'a BitMatrix, + assigned_local: Option, +} + +impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> { + fn saved_local_for_direct_place(&self, place: Place<'_>) -> Option { + if place.is_indirect() { + return None; + } + + self.saved_locals.get(place.local) + } + + fn check_assigned_place(&mut self, place: Place<'tcx>, f: impl FnOnce(&mut Self)) { + if let Some(assigned_local) = self.saved_local_for_direct_place(place) { + assert!(self.assigned_local.is_none(), "`check_assigned_place` must not recurse"); + + self.assigned_local = Some(assigned_local); + f(self); + self.assigned_local = None; + } + } +} + +impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + let lhs = match self.assigned_local { + Some(l) => l, + None => { + // This visitor only invokes `visit_place` for the right-hand side of an assignment + // and only after setting `self.assigned_local`. However, the default impl of + // `Visitor::super_body` may call `visit_place` with a `NonUseContext` for places + // with debuginfo. Ignore them here. + assert!(!context.is_use()); + return; + } + }; + + let rhs = match self.saved_local_for_direct_place(*place) { + Some(l) => l, + None => return, + }; + + if !self.storage_conflicts.contains(lhs, rhs) { + bug!( + "Assignment between generator saved locals whose storage is not \ + marked as conflicting: {:?}: {:?} = {:?}", + location, + lhs, + rhs, + ); + } + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + match &statement.kind { + StatementKind::Assign(box (lhs, rhs)) => { + self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location)); + } + + // FIXME: Does `llvm_asm!` have any aliasing requirements? + StatementKind::LlvmInlineAsm(_) => {} + + StatementKind::FakeRead(..) + | StatementKind::SetDiscriminant { .. } + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Retag(..) + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::CopyNonOverlapping(..) + | StatementKind::Nop => {} + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + // Checking for aliasing in terminators is probably overkill, but until we have actual + // semantics, we should be conservative here. + match &terminator.kind { + TerminatorKind::Call { + func, + args, + destination: Some((dest, _)), + cleanup: _, + from_hir_call: _, + fn_span: _, + } => { + self.check_assigned_place(*dest, |this| { + this.visit_operand(func, location); + for arg in args { + this.visit_operand(arg, location); + } + }); + } + + TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { + self.check_assigned_place(*resume_arg, |this| this.visit_operand(value, location)); + } + + // FIXME: Does `asm!` have any aliasing requirements? + TerminatorKind::InlineAsm { .. } => {} + + TerminatorKind::Call { .. } + | TerminatorKind::Goto { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => {} + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/inline/cycle.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/inline/cycle.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/inline/cycle.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/inline/cycle.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,169 @@ +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sso::SsoHashSet; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::mir::TerminatorKind; +use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt}; +use rustc_session::Limit; + +// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking +// this query riddiculously often. +#[instrument(level = "debug", skip(tcx, root, target))] +crate fn mir_callgraph_reachable( + tcx: TyCtxt<'tcx>, + (root, target): (ty::Instance<'tcx>, LocalDefId), +) -> bool { + trace!(%root, target = %tcx.def_path_str(target.to_def_id())); + let param_env = tcx.param_env_reveal_all_normalized(target); + assert_ne!( + root.def_id().expect_local(), + target, + "you should not call `mir_callgraph_reachable` on immediate self recursion" + ); + assert!( + matches!(root.def, InstanceDef::Item(_)), + "you should not call `mir_callgraph_reachable` on shims" + ); + assert!( + !tcx.is_constructor(root.def_id()), + "you should not call `mir_callgraph_reachable` on enum/struct constructor functions" + ); + #[instrument( + level = "debug", + skip(tcx, param_env, target, stack, seen, recursion_limiter, caller, recursion_limit) + )] + fn process( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + caller: ty::Instance<'tcx>, + target: LocalDefId, + stack: &mut Vec>, + seen: &mut FxHashSet>, + recursion_limiter: &mut FxHashMap, + recursion_limit: Limit, + ) -> bool { + trace!(%caller); + for &(callee, substs) in tcx.mir_inliner_callees(caller.def) { + let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs); + let callee = match ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() { + Some(callee) => callee, + None => { + trace!(?callee, "cannot resolve, skipping"); + continue; + } + }; + + // Found a path. + if callee.def_id() == target.to_def_id() { + return true; + } + + if tcx.is_constructor(callee.def_id()) { + trace!("constructors always have MIR"); + // Constructor functions cannot cause a query cycle. + continue; + } + + match callee.def { + InstanceDef::Item(_) => { + // If there is no MIR available (either because it was not in metadata or + // because it has no MIR because it's an extern function), then the inliner + // won't cause cycles on this. + if !tcx.is_mir_available(callee.def_id()) { + trace!(?callee, "no mir available, skipping"); + continue; + } + } + // These have no own callable MIR. + InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue, + // These have MIR and if that MIR is inlined, substituted and then inlining is run + // again, a function item can end up getting inlined. Thus we'll be able to cause + // a cycle that way + InstanceDef::VtableShim(_) + | InstanceDef::ReifyShim(_) + | InstanceDef::FnPtrShim(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::CloneShim(..) => {} + InstanceDef::DropGlue(..) => { + // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to + // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this + // needs some more analysis. + if callee.definitely_needs_subst(tcx) { + continue; + } + } + } + + if seen.insert(callee) { + let recursion = recursion_limiter.entry(callee.def_id()).or_default(); + trace!(?callee, recursion = *recursion); + if recursion_limit.value_within_limit(*recursion) { + *recursion += 1; + stack.push(callee); + let found_recursion = ensure_sufficient_stack(|| { + process( + tcx, + param_env, + callee, + target, + stack, + seen, + recursion_limiter, + recursion_limit, + ) + }); + if found_recursion { + return true; + } + stack.pop(); + } else { + // Pessimistically assume that there could be recursion. + return true; + } + } + } + false + } + process( + tcx, + param_env, + root, + target, + &mut Vec::new(), + &mut FxHashSet::default(), + &mut FxHashMap::default(), + tcx.recursion_limit(), + ) +} + +crate fn mir_inliner_callees<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, +) -> &'tcx [(DefId, SubstsRef<'tcx>)] { + let steal; + let guard; + let body = match (instance, instance.def_id().as_local()) { + (InstanceDef::Item(_), Some(def_id)) => { + let def = ty::WithOptConstParam::unknown(def_id); + steal = tcx.mir_promoted(def).0; + guard = steal.borrow(); + &*guard + } + // Functions from other crates and MIR shims + _ => tcx.instance_mir(instance), + }; + let mut calls = SsoHashSet::new(); + for bb_data in body.basic_blocks() { + let terminator = bb_data.terminator(); + if let TerminatorKind::Call { func, .. } = &terminator.kind { + let ty = func.ty(&body.local_decls, tcx); + let call = match ty.kind() { + ty::FnDef(def_id, substs) => (*def_id, *substs), + _ => continue, + }; + calls.insert(call); + } + } + tcx.arena.alloc_from_iter(calls.iter().copied()) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/inline.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/inline.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/inline.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/inline.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,966 @@ +//! Inlining pass for MIR functions + +use rustc_attr::InlineAttr; +use rustc_hir as hir; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::Idx; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::mir::visit::*; +use rustc_middle::mir::*; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_span::{hygiene::ExpnKind, ExpnData, Span}; +use rustc_target::spec::abi::Abi; + +use super::simplify::{remove_dead_blocks, CfgSimplifier}; +use crate::MirPass; +use std::iter; +use std::ops::{Range, RangeFrom}; + +crate mod cycle; + +const INSTR_COST: usize = 5; +const CALL_PENALTY: usize = 25; +const LANDINGPAD_PENALTY: usize = 50; +const RESUME_PENALTY: usize = 45; + +const UNKNOWN_SIZE_COST: usize = 10; + +pub struct Inline; + +#[derive(Copy, Clone, Debug)] +struct CallSite<'tcx> { + callee: Instance<'tcx>, + fn_sig: ty::PolyFnSig<'tcx>, + block: BasicBlock, + target: Option, + source_info: SourceInfo, +} + +/// Returns true if MIR inlining is enabled in the current compilation session. +crate fn is_enabled(tcx: TyCtxt<'_>) -> bool { + if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir { + return enabled; + } + + tcx.sess.mir_opt_level() >= 3 +} + +impl<'tcx> MirPass<'tcx> for Inline { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if !is_enabled(tcx) { + return; + } + + let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id())); + let _guard = span.enter(); + if inline(tcx, body) { + debug!("running simplify cfg on {:?}", body.source); + CfgSimplifier::new(body).simplify(); + remove_dead_blocks(tcx, body); + } + } +} + +fn inline(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { + let def_id = body.source.def_id(); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + + // Only do inlining into fn bodies. + if !tcx.hir().body_owner_kind(hir_id).is_fn_or_closure() { + return false; + } + if body.source.promoted.is_some() { + return false; + } + + let mut this = Inliner { + tcx, + param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()), + codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()), + hir_id, + history: Vec::new(), + changed: false, + }; + let blocks = BasicBlock::new(0)..body.basic_blocks().next_index(); + this.process_blocks(body, blocks); + this.changed +} + +struct Inliner<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + /// Caller codegen attributes. + codegen_fn_attrs: &'tcx CodegenFnAttrs, + /// Caller HirID. + hir_id: hir::HirId, + /// Stack of inlined Instances. + history: Vec>, + /// Indicates that the caller body has been modified. + changed: bool, +} + +impl Inliner<'tcx> { + fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range) { + for bb in blocks { + let bb_data = &caller_body[bb]; + if bb_data.is_cleanup { + continue; + } + + let callsite = match self.resolve_callsite(caller_body, bb, bb_data) { + None => continue, + Some(it) => it, + }; + + let span = trace_span!("process_blocks", %callsite.callee, ?bb); + let _guard = span.enter(); + + match self.try_inlining(caller_body, &callsite) { + Err(reason) => { + debug!("not-inlined {} [{}]", callsite.callee, reason); + continue; + } + Ok(new_blocks) => { + debug!("inlined {}", callsite.callee); + self.changed = true; + self.history.push(callsite.callee); + self.process_blocks(caller_body, new_blocks); + self.history.pop(); + } + } + } + } + + /// Attempts to inline a callsite into the caller body. When successful returns basic blocks + /// containing the inlined body. Otherwise returns an error describing why inlining didn't take + /// place. + fn try_inlining( + &self, + caller_body: &mut Body<'tcx>, + callsite: &CallSite<'tcx>, + ) -> Result, &'static str> { + let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); + self.check_codegen_attributes(callsite, callee_attrs)?; + self.check_mir_is_available(caller_body, &callsite.callee)?; + let callee_body = self.tcx.instance_mir(callsite.callee.def); + self.check_mir_body(callsite, callee_body, callee_attrs)?; + + if !self.tcx.consider_optimizing(|| { + format!("Inline {:?} into {:?}", callsite.callee, caller_body.source) + }) { + return Err("optimization fuel exhausted"); + } + + let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions( + self.tcx, + self.param_env, + callee_body.clone(), + ); + + let old_blocks = caller_body.basic_blocks().next_index(); + self.inline_call(caller_body, &callsite, callee_body); + let new_blocks = old_blocks..caller_body.basic_blocks().next_index(); + + Ok(new_blocks) + } + + fn check_mir_is_available( + &self, + caller_body: &Body<'tcx>, + callee: &Instance<'tcx>, + ) -> Result<(), &'static str> { + if callee.def_id() == caller_body.source.def_id() { + return Err("self-recursion"); + } + + match callee.def { + InstanceDef::Item(_) => { + // If there is no MIR available (either because it was not in metadata or + // because it has no MIR because it's an extern function), then the inliner + // won't cause cycles on this. + if !self.tcx.is_mir_available(callee.def_id()) { + return Err("item MIR unavailable"); + } + } + // These have no own callable MIR. + InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => { + return Err("instance without MIR (intrinsic / virtual)"); + } + // This cannot result in an immediate cycle since the callee MIR is a shim, which does + // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we + // do not need to catch this here, we can wait until the inliner decides to continue + // inlining a second time. + InstanceDef::VtableShim(_) + | InstanceDef::ReifyShim(_) + | InstanceDef::FnPtrShim(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) => return Ok(()), + } + + if self.tcx.is_constructor(callee.def_id()) { + trace!("constructors always have MIR"); + // Constructor functions cannot cause a query cycle. + return Ok(()); + } + + if let Some(callee_def_id) = callee.def_id().as_local() { + let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id); + // Avoid inlining into generators, + // since their `optimized_mir` is used for layout computation, which can + // create a cycle, even when no attempt is made to inline the function + // in the other direction. + if caller_body.generator.is_some() { + return Err("local generator (query cycle avoidance)"); + } + + // Avoid a cycle here by only using `instance_mir` only if we have + // a lower `HirId` than the callee. This ensures that the callee will + // not inline us. This trick only works without incremental compilation. + // So don't do it if that is enabled. + if !self.tcx.dep_graph.is_fully_enabled() && self.hir_id < callee_hir_id { + return Ok(()); + } + + // If we know for sure that the function we're calling will itself try to + // call us, then we avoid inlining that function. + if self + .tcx + .mir_callgraph_reachable((*callee, caller_body.source.def_id().expect_local())) + { + return Err("caller might be reachable from callee (query cycle avoidance)"); + } + + Ok(()) + } else { + // This cannot result in an immediate cycle since the callee MIR is from another crate + // and is already optimized. Any subsequent inlining may cause cycles, but we do + // not need to catch this here, we can wait until the inliner decides to continue + // inlining a second time. + trace!("functions from other crates always have MIR"); + Ok(()) + } + } + + fn resolve_callsite( + &self, + caller_body: &Body<'tcx>, + bb: BasicBlock, + bb_data: &BasicBlockData<'tcx>, + ) -> Option> { + // Only consider direct calls to functions + let terminator = bb_data.terminator(); + if let TerminatorKind::Call { ref func, ref destination, .. } = terminator.kind { + let func_ty = func.ty(caller_body, self.tcx); + if let ty::FnDef(def_id, substs) = *func_ty.kind() { + // To resolve an instance its substs have to be fully normalized. + let substs = self.tcx.normalize_erasing_regions(self.param_env, substs); + let callee = + Instance::resolve(self.tcx, self.param_env, def_id, substs).ok().flatten()?; + + if let InstanceDef::Virtual(..) | InstanceDef::Intrinsic(_) = callee.def { + return None; + } + + let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); + + return Some(CallSite { + callee, + fn_sig, + block: bb, + target: destination.map(|(_, target)| target), + source_info: terminator.source_info, + }); + } + } + + None + } + + /// Returns an error if inlining is not possible based on codegen attributes alone. A success + /// indicates that inlining decision should be based on other criteria. + fn check_codegen_attributes( + &self, + callsite: &CallSite<'tcx>, + callee_attrs: &CodegenFnAttrs, + ) -> Result<(), &'static str> { + if let InlineAttr::Never = callee_attrs.inline { + return Err("never inline hint"); + } + + // Only inline local functions if they would be eligible for cross-crate + // inlining. This is to ensure that the final crate doesn't have MIR that + // reference unexported symbols + if callsite.callee.def_id().is_local() { + let is_generic = callsite.callee.substs.non_erasable_generics().next().is_some(); + if !is_generic && !callee_attrs.requests_inline() { + return Err("not exported"); + } + } + + if callsite.fn_sig.c_variadic() { + return Err("C variadic"); + } + + if callee_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + return Err("naked"); + } + + if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) { + return Err("cold"); + } + + if callee_attrs.no_sanitize != self.codegen_fn_attrs.no_sanitize { + return Err("incompatible sanitizer set"); + } + + if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set { + return Err("incompatible instruction set"); + } + + for feature in &callee_attrs.target_features { + if !self.codegen_fn_attrs.target_features.contains(feature) { + return Err("incompatible target feature"); + } + } + + Ok(()) + } + + /// Returns inlining decision that is based on the examination of callee MIR body. + /// Assumes that codegen attributes have been checked for compatibility already. + #[instrument(level = "debug", skip(self, callee_body))] + fn check_mir_body( + &self, + callsite: &CallSite<'tcx>, + callee_body: &Body<'tcx>, + callee_attrs: &CodegenFnAttrs, + ) -> Result<(), &'static str> { + let tcx = self.tcx; + + let mut threshold = if callee_attrs.requests_inline() { + self.tcx.sess.opts.debugging_opts.inline_mir_hint_threshold.unwrap_or(100) + } else { + self.tcx.sess.opts.debugging_opts.inline_mir_threshold.unwrap_or(50) + }; + + // Give a bonus functions with a small number of blocks, + // We normally have two or three blocks for even + // very small functions. + if callee_body.basic_blocks().len() <= 3 { + threshold += threshold / 4; + } + debug!(" final inline threshold = {}", threshold); + + // FIXME: Give a bonus to functions with only a single caller + let mut first_block = true; + let mut cost = 0; + + // Traverse the MIR manually so we can account for the effects of + // inlining on the CFG. + let mut work_list = vec![START_BLOCK]; + let mut visited = BitSet::new_empty(callee_body.basic_blocks().len()); + while let Some(bb) = work_list.pop() { + if !visited.insert(bb.index()) { + continue; + } + let blk = &callee_body.basic_blocks()[bb]; + + for stmt in &blk.statements { + // Don't count StorageLive/StorageDead in the inlining cost. + match stmt.kind { + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Nop => {} + _ => cost += INSTR_COST, + } + } + let term = blk.terminator(); + let mut is_drop = false; + match term.kind { + TerminatorKind::Drop { ref place, target, unwind } + | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } => { + is_drop = true; + work_list.push(target); + // If the place doesn't actually need dropping, treat it like + // a regular goto. + let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty); + if ty.needs_drop(tcx, self.param_env) { + cost += CALL_PENALTY; + if let Some(unwind) = unwind { + cost += LANDINGPAD_PENALTY; + work_list.push(unwind); + } + } else { + cost += INSTR_COST; + } + } + + TerminatorKind::Unreachable | TerminatorKind::Call { destination: None, .. } + if first_block => + { + // If the function always diverges, don't inline + // unless the cost is zero + threshold = 0; + } + + TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { + if let ty::FnDef(def_id, substs) = + *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind() + { + let substs = self.tcx.normalize_erasing_regions(self.param_env, substs); + if let Ok(Some(instance)) = + Instance::resolve(self.tcx, self.param_env, def_id, substs) + { + if callsite.callee.def_id() == instance.def_id() { + return Err("self-recursion"); + } else if self.history.contains(&instance) { + return Err("already inlined"); + } + } + // Don't give intrinsics the extra penalty for calls + let f = tcx.fn_sig(def_id); + if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { + cost += INSTR_COST; + } else { + cost += CALL_PENALTY; + } + } else { + cost += CALL_PENALTY; + } + if cleanup.is_some() { + cost += LANDINGPAD_PENALTY; + } + } + TerminatorKind::Assert { cleanup, .. } => { + cost += CALL_PENALTY; + + if cleanup.is_some() { + cost += LANDINGPAD_PENALTY; + } + } + TerminatorKind::Resume => cost += RESUME_PENALTY, + _ => cost += INSTR_COST, + } + + if !is_drop { + for &succ in term.successors() { + work_list.push(succ); + } + } + + first_block = false; + } + + // Count up the cost of local variables and temps, if we know the size + // use that, otherwise we use a moderately-large dummy cost. + + let ptr_size = tcx.data_layout.pointer_size.bytes(); + + for v in callee_body.vars_and_temps_iter() { + let ty = callsite.callee.subst_mir(self.tcx, &callee_body.local_decls[v].ty); + // Cost of the var is the size in machine-words, if we know + // it. + if let Some(size) = type_size_of(tcx, self.param_env, ty) { + cost += ((size + ptr_size - 1) / ptr_size) as usize; + } else { + cost += UNKNOWN_SIZE_COST; + } + } + + if let InlineAttr::Always = callee_attrs.inline { + debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost); + Ok(()) + } else { + if cost <= threshold { + debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold); + Ok(()) + } else { + debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold); + Err("cost above threshold") + } + } + } + + fn inline_call( + &self, + caller_body: &mut Body<'tcx>, + callsite: &CallSite<'tcx>, + mut callee_body: Body<'tcx>, + ) { + let terminator = caller_body[callsite.block].terminator.take().unwrap(); + match terminator.kind { + TerminatorKind::Call { args, destination, cleanup, .. } => { + // If the call is something like `a[*i] = f(i)`, where + // `i : &mut usize`, then just duplicating the `a[*i]` + // Place could result in two different locations if `f` + // writes to `i`. To prevent this we need to create a temporary + // borrow of the place and pass the destination as `*temp` instead. + fn dest_needs_borrow(place: Place<'_>) -> bool { + for elem in place.projection.iter() { + match elem { + ProjectionElem::Deref | ProjectionElem::Index(_) => return true, + _ => {} + } + } + + false + } + + let dest = if let Some((destination_place, _)) = destination { + if dest_needs_borrow(destination_place) { + trace!("creating temp for return destination"); + let dest = Rvalue::Ref( + self.tcx.lifetimes.re_erased, + BorrowKind::Mut { allow_two_phase_borrow: false }, + destination_place, + ); + let dest_ty = dest.ty(caller_body, self.tcx); + let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty)); + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::Assign(Box::new((temp, dest))), + }); + self.tcx.mk_place_deref(temp) + } else { + destination_place + } + } else { + trace!("creating temp for return place"); + Place::from(self.new_call_temp(caller_body, &callsite, callee_body.return_ty())) + }; + + // Copy the arguments if needed. + let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body); + + let mut integrator = Integrator { + args: &args, + new_locals: Local::new(caller_body.local_decls.len()).., + new_scopes: SourceScope::new(caller_body.source_scopes.len()).., + new_blocks: BasicBlock::new(caller_body.basic_blocks().len()).., + destination: dest, + return_block: callsite.target, + cleanup_block: cleanup, + in_cleanup_block: false, + tcx: self.tcx, + callsite_span: callsite.source_info.span, + body_span: callee_body.span, + always_live_locals: BitSet::new_filled(callee_body.local_decls.len()), + }; + + // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones + // (or existing ones, in a few special cases) in the caller. + integrator.visit_body(&mut callee_body); + + for scope in &mut callee_body.source_scopes { + // FIXME(eddyb) move this into a `fn visit_scope_data` in `Integrator`. + if scope.parent_scope.is_none() { + let callsite_scope = &caller_body.source_scopes[callsite.source_info.scope]; + + // Attach the outermost callee scope as a child of the callsite + // scope, via the `parent_scope` and `inlined_parent_scope` chains. + scope.parent_scope = Some(callsite.source_info.scope); + assert_eq!(scope.inlined_parent_scope, None); + scope.inlined_parent_scope = if callsite_scope.inlined.is_some() { + Some(callsite.source_info.scope) + } else { + callsite_scope.inlined_parent_scope + }; + + // Mark the outermost callee scope as an inlined one. + assert_eq!(scope.inlined, None); + scope.inlined = Some((callsite.callee, callsite.source_info.span)); + } else if scope.inlined_parent_scope.is_none() { + // Make it easy to find the scope with `inlined` set above. + scope.inlined_parent_scope = + Some(integrator.map_scope(OUTERMOST_SOURCE_SCOPE)); + } + } + + // If there are any locals without storage markers, give them storage only for the + // duration of the call. + for local in callee_body.vars_and_temps_iter() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageLive(new_local), + }); + } + } + if let Some(block) = callsite.target { + // To avoid repeated O(n) insert, push any new statements to the end and rotate + // the slice once. + let mut n = 0; + for local in callee_body.vars_and_temps_iter().rev() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageDead(new_local), + }); + n += 1; + } + } + caller_body[block].statements.rotate_right(n); + } + + // Insert all of the (mapped) parts of the callee body into the caller. + caller_body.local_decls.extend(callee_body.drain_vars_and_temps()); + caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..)); + caller_body.var_debug_info.append(&mut callee_body.var_debug_info); + caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..)); + + caller_body[callsite.block].terminator = Some(Terminator { + source_info: callsite.source_info, + kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) }, + }); + + // Copy only unevaluated constants from the callee_body into the caller_body. + // Although we are only pushing `ConstKind::Unevaluated` consts to + // `required_consts`, here we may not only have `ConstKind::Unevaluated` + // because we are calling `subst_and_normalize_erasing_regions`. + caller_body.required_consts.extend( + callee_body.required_consts.iter().copied().filter(|&ct| { + match ct.literal.const_for_ty() { + Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_)), + None => true, + } + }), + ); + } + kind => bug!("unexpected terminator kind {:?}", kind), + } + } + + fn make_call_args( + &self, + args: Vec>, + callsite: &CallSite<'tcx>, + caller_body: &mut Body<'tcx>, + callee_body: &Body<'tcx>, + ) -> Vec { + let tcx = self.tcx; + + // There is a bit of a mismatch between the *caller* of a closure and the *callee*. + // The caller provides the arguments wrapped up in a tuple: + // + // tuple_tmp = (a, b, c) + // Fn::call(closure_ref, tuple_tmp) + // + // meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`) + // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, codegen has + // the job of unpacking this tuple. But here, we are codegen. =) So we want to create + // a vector like + // + // [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2] + // + // Except for one tiny wrinkle: we don't actually want `tuple_tmp.0`. It's more convenient + // if we "spill" that into *another* temporary, so that we can map the argument + // variable in the callee MIR directly to an argument variable on our side. + // So we introduce temporaries like: + // + // tmp0 = tuple_tmp.0 + // tmp1 = tuple_tmp.1 + // tmp2 = tuple_tmp.2 + // + // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. + if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() { + let mut args = args.into_iter(); + let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); + let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); + assert!(args.next().is_none()); + + let tuple = Place::from(tuple); + let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind() { + s + } else { + bug!("Closure arguments are not passed as a tuple"); + }; + + // The `closure_ref` in our example above. + let closure_ref_arg = iter::once(self_); + + // The `tmp0`, `tmp1`, and `tmp2` in our example abonve. + let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| { + // This is e.g., `tuple_tmp.0` in our example above. + let tuple_field = + Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty())); + + // Spill to a local to make e.g., `tmp0`. + self.create_temp_if_necessary(tuple_field, callsite, caller_body) + }); + + closure_ref_arg.chain(tuple_tmp_args).collect() + } else { + args.into_iter() + .map(|a| self.create_temp_if_necessary(a, callsite, caller_body)) + .collect() + } + } + + /// If `arg` is already a temporary, returns it. Otherwise, introduces a fresh + /// temporary `T` and an instruction `T = arg`, and returns `T`. + fn create_temp_if_necessary( + &self, + arg: Operand<'tcx>, + callsite: &CallSite<'tcx>, + caller_body: &mut Body<'tcx>, + ) -> Local { + // Reuse the operand if it is a moved temporary. + if let Operand::Move(place) = &arg { + if let Some(local) = place.as_local() { + if caller_body.local_kind(local) == LocalKind::Temp { + return local; + } + } + } + + // Otherwise, create a temporary for the argument. + trace!("creating temp for argument {:?}", arg); + let arg_ty = arg.ty(caller_body, self.tcx); + let local = self.new_call_temp(caller_body, callsite, arg_ty); + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))), + }); + local + } + + /// Introduces a new temporary into the caller body that is live for the duration of the call. + fn new_call_temp( + &self, + caller_body: &mut Body<'tcx>, + callsite: &CallSite<'tcx>, + ty: Ty<'tcx>, + ) -> Local { + let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span)); + + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageLive(local), + }); + + if let Some(block) = callsite.target { + caller_body[block].statements.insert( + 0, + Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageDead(local), + }, + ); + } + + local + } +} + +fn type_size_of<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Option { + tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) +} + +/** + * Integrator. + * + * Integrates blocks from the callee function into the calling function. + * Updates block indices, references to locals and other control flow + * stuff. +*/ +struct Integrator<'a, 'tcx> { + args: &'a [Local], + new_locals: RangeFrom, + new_scopes: RangeFrom, + new_blocks: RangeFrom, + destination: Place<'tcx>, + return_block: Option, + cleanup_block: Option, + in_cleanup_block: bool, + tcx: TyCtxt<'tcx>, + callsite_span: Span, + body_span: Span, + always_live_locals: BitSet, +} + +impl<'a, 'tcx> Integrator<'a, 'tcx> { + fn map_local(&self, local: Local) -> Local { + let new = if local == RETURN_PLACE { + self.destination.local + } else { + let idx = local.index() - 1; + if idx < self.args.len() { + self.args[idx] + } else { + Local::new(self.new_locals.start.index() + (idx - self.args.len())) + } + }; + trace!("mapping local `{:?}` to `{:?}`", local, new); + new + } + + fn map_scope(&self, scope: SourceScope) -> SourceScope { + let new = SourceScope::new(self.new_scopes.start.index() + scope.index()); + trace!("mapping scope `{:?}` to `{:?}`", scope, new); + new + } + + fn map_block(&self, block: BasicBlock) -> BasicBlock { + let new = BasicBlock::new(self.new_blocks.start.index() + block.index()); + trace!("mapping block `{:?}` to `{:?}`", block, new); + new + } +} + +impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, _ctxt: PlaceContext, _location: Location) { + *local = self.map_local(*local); + } + + fn visit_source_scope(&mut self, scope: &mut SourceScope) { + *scope = self.map_scope(*scope); + } + + fn visit_span(&mut self, span: &mut Span) { + let mut expn_data = + ExpnData::default(ExpnKind::Inlined, *span, self.tcx.sess.edition(), None, None); + expn_data.def_site = self.body_span; + // Make sure that all spans track the fact that they were inlined. + *span = + self.callsite_span.fresh_expansion(expn_data, self.tcx.create_stable_hashing_context()); + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + for elem in place.projection { + // FIXME: Make sure that return place is not used in an indexing projection, since it + // won't be rebased as it is supposed to be. + assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem); + } + + // If this is the `RETURN_PLACE`, we need to rebase any projections onto it. + let dest_proj_len = self.destination.projection.len(); + if place.local == RETURN_PLACE && dest_proj_len > 0 { + let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len()); + projs.extend(self.destination.projection); + projs.extend(place.projection); + + place.projection = self.tcx.intern_place_elems(&*projs); + } + // Handles integrating any locals that occur in the base + // or projections + self.super_place(place, context, location) + } + + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { + self.in_cleanup_block = data.is_cleanup; + self.super_basic_block_data(block, data); + self.in_cleanup_block = false; + } + + fn visit_retag(&mut self, kind: &mut RetagKind, place: &mut Place<'tcx>, loc: Location) { + self.super_retag(kind, place, loc); + + // We have to patch all inlined retags to be aware that they are no longer + // happening on function entry. + if *kind == RetagKind::FnEntry { + *kind = RetagKind::Default; + } + } + + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + if let StatementKind::StorageLive(local) | StatementKind::StorageDead(local) = + statement.kind + { + self.always_live_locals.remove(local); + } + self.super_statement(statement, location); + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) { + // Don't try to modify the implicit `_0` access on return (`return` terminators are + // replaced down below anyways). + if !matches!(terminator.kind, TerminatorKind::Return) { + self.super_terminator(terminator, loc); + } + + match terminator.kind { + TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => bug!(), + TerminatorKind::Goto { ref mut target } => { + *target = self.map_block(*target); + } + TerminatorKind::SwitchInt { ref mut targets, .. } => { + for tgt in targets.all_targets_mut() { + *tgt = self.map_block(*tgt); + } + } + TerminatorKind::Drop { ref mut target, ref mut unwind, .. } + | TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => { + *target = self.map_block(*target); + if let Some(tgt) = *unwind { + *unwind = Some(self.map_block(tgt)); + } else if !self.in_cleanup_block { + // Unless this drop is in a cleanup block, add an unwind edge to + // the original call's cleanup block + *unwind = self.cleanup_block; + } + } + TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => { + if let Some((_, ref mut tgt)) = *destination { + *tgt = self.map_block(*tgt); + } + if let Some(tgt) = *cleanup { + *cleanup = Some(self.map_block(tgt)); + } else if !self.in_cleanup_block { + // Unless this call is in a cleanup block, add an unwind edge to + // the original call's cleanup block + *cleanup = self.cleanup_block; + } + } + TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => { + *target = self.map_block(*target); + if let Some(tgt) = *cleanup { + *cleanup = Some(self.map_block(tgt)); + } else if !self.in_cleanup_block { + // Unless this assert is in a cleanup block, add an unwind edge to + // the original call's cleanup block + *cleanup = self.cleanup_block; + } + } + TerminatorKind::Return => { + terminator.kind = if let Some(tgt) = self.return_block { + TerminatorKind::Goto { target: tgt } + } else { + TerminatorKind::Unreachable + } + } + TerminatorKind::Resume => { + if let Some(tgt) = self.cleanup_block { + terminator.kind = TerminatorKind::Goto { target: tgt } + } + } + TerminatorKind::Abort => {} + TerminatorKind::Unreachable => {} + TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => { + *real_target = self.map_block(*real_target); + *imaginary_target = self.map_block(*imaginary_target); + } + TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => + // see the ordering of passes in the optimized_mir query. + { + bug!("False unwinds should have been removed before inlining") + } + TerminatorKind::InlineAsm { ref mut destination, .. } => { + if let Some(ref mut tgt) = *destination { + *tgt = self.map_block(*tgt); + } + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/instcombine.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/instcombine.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/instcombine.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/instcombine.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,131 @@ +//! Performs various peephole optimizations. + +use crate::MirPass; +use rustc_hir::Mutability; +use rustc_middle::mir::{ + BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, + StatementKind, UnOp, +}; +use rustc_middle::ty::{self, TyCtxt}; + +pub struct InstCombine; + +impl<'tcx> MirPass<'tcx> for InstCombine { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + let ctx = InstCombineContext { tcx, local_decls }; + for block in basic_blocks.iter_mut() { + for statement in block.statements.iter_mut() { + match statement.kind { + StatementKind::Assign(box (_place, ref mut rvalue)) => { + ctx.combine_bool_cmp(&statement.source_info, rvalue); + ctx.combine_ref_deref(&statement.source_info, rvalue); + ctx.combine_len(&statement.source_info, rvalue); + } + _ => {} + } + } + } + } +} + +struct InstCombineContext<'tcx, 'a> { + tcx: TyCtxt<'tcx>, + local_decls: &'a LocalDecls<'tcx>, +} + +impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { + fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool { + self.tcx.consider_optimizing(|| { + format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info) + }) + } + + /// Transform boolean comparisons into logical operations. + fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { + match rvalue { + Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => { + let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) { + // Transform "Eq(a, true)" ==> "a" + (BinOp::Eq, _, Some(true)) => Some(Rvalue::Use(a.clone())), + + // Transform "Ne(a, false)" ==> "a" + (BinOp::Ne, _, Some(false)) => Some(Rvalue::Use(a.clone())), + + // Transform "Eq(true, b)" ==> "b" + (BinOp::Eq, Some(true), _) => Some(Rvalue::Use(b.clone())), + + // Transform "Ne(false, b)" ==> "b" + (BinOp::Ne, Some(false), _) => Some(Rvalue::Use(b.clone())), + + // Transform "Eq(false, b)" ==> "Not(b)" + (BinOp::Eq, Some(false), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())), + + // Transform "Ne(true, b)" ==> "Not(b)" + (BinOp::Ne, Some(true), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())), + + // Transform "Eq(a, false)" ==> "Not(a)" + (BinOp::Eq, _, Some(false)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())), + + // Transform "Ne(a, true)" ==> "Not(a)" + (BinOp::Ne, _, Some(true)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())), + + _ => None, + }; + + if let Some(new) = new { + if self.should_combine(source_info, rvalue) { + *rvalue = new; + } + } + } + + _ => {} + } + } + + fn try_eval_bool(&self, a: &Operand<'_>) -> Option { + let a = a.constant()?; + if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None } + } + + /// Transform "&(*a)" ==> "a". + fn combine_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { + if let Rvalue::Ref(_, _, place) = rvalue { + if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() { + if let ty::Ref(_, _, Mutability::Not) = + base.ty(self.local_decls, self.tcx).ty.kind() + { + // The dereferenced place must have type `&_`, so that we don't copy `&mut _`. + } else { + return; + } + + if !self.should_combine(source_info, rvalue) { + return; + } + + *rvalue = Rvalue::Use(Operand::Copy(Place { + local: base.local, + projection: self.tcx.intern_place_elems(base.projection), + })); + } + } + } + + /// Transform "Len([_; N])" ==> "N". + fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { + if let Rvalue::Len(ref place) = *rvalue { + let place_ty = place.ty(self.local_decls, self.tcx).ty; + if let ty::Array(_, len) = *place_ty.kind() { + if !self.should_combine(source_info, rvalue) { + return; + } + + let constant = + Constant { span: source_info.span, literal: len.into(), user_ty: None }; + *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,631 @@ +#![feature(box_patterns)] +#![feature(box_syntax)] +#![feature(crate_visibility_modifier)] +#![cfg_attr(bootstrap, feature(const_panic))] +#![feature(in_band_lifetimes)] +#![feature(iter_zip)] +#![feature(map_try_insert)] +#![feature(min_specialization)] +#![feature(option_get_or_insert_default)] +#![feature(once_cell)] +#![feature(never_type)] +#![feature(trusted_step)] +#![feature(try_blocks)] +#![recursion_limit = "256"] + +#[macro_use] +extern crate tracing; +#[macro_use] +extern crate rustc_middle; + +use required_consts::RequiredConstsVisitor; +use rustc_const_eval::util; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::steal::Steal; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::Visitor as _; +use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_span::{Span, Symbol}; + +mod abort_unwinding_calls; +mod add_call_guards; +mod add_moves_for_packed_drops; +mod add_retag; +mod check_const_item_mutation; +mod check_packed_ref; +pub mod check_unsafety; +mod cleanup_post_borrowck; +mod const_debuginfo; +mod const_goto; +mod const_prop; +mod coverage; +mod deaggregator; +mod deduplicate_blocks; +mod dest_prop; +pub mod dump_mir; +mod early_otherwise_branch; +mod elaborate_drops; +mod function_item_references; +mod generator; +mod inline; +mod instcombine; +mod lower_intrinsics; +mod lower_slice_len; +mod match_branches; +mod multiple_return_terminators; +mod normalize_array_len; +mod nrvo; +mod remove_noop_landing_pads; +mod remove_storage_markers; +mod remove_unneeded_drops; +mod remove_zsts; +mod required_consts; +mod separate_const_switch; +mod shim; +mod simplify; +mod simplify_branches; +mod simplify_comparison_integral; +mod simplify_try; +mod uninhabited_enum_branching; +mod unreachable_prop; + +use rustc_const_eval::transform::check_consts; +use rustc_const_eval::transform::promote_consts; +use rustc_const_eval::transform::validate; +pub use rustc_const_eval::transform::MirPass; +use rustc_mir_dataflow::rustc_peek; + +pub fn provide(providers: &mut Providers) { + check_unsafety::provide(providers); + check_packed_ref::provide(providers); + coverage::query::provide(providers); + shim::provide(providers); + *providers = Providers { + mir_keys, + mir_const, + mir_const_qualif: |tcx, def_id| { + let def_id = def_id.expect_local(); + if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { + tcx.mir_const_qualif_const_arg(def) + } else { + mir_const_qualif(tcx, ty::WithOptConstParam::unknown(def_id)) + } + }, + mir_const_qualif_const_arg: |tcx, (did, param_did)| { + mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) + }, + mir_promoted, + mir_drops_elaborated_and_const_checked, + mir_for_ctfe, + mir_for_ctfe_of_const_arg, + optimized_mir, + is_mir_available, + is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did), + mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable, + mir_inliner_callees: inline::cycle::mir_inliner_callees, + promoted_mir: |tcx, def_id| { + let def_id = def_id.expect_local(); + if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { + tcx.promoted_mir_of_const_arg(def) + } else { + promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id)) + } + }, + promoted_mir_of_const_arg: |tcx, (did, param_did)| { + promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) + }, + ..*providers + }; +} + +fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let def_id = def_id.expect_local(); + tcx.mir_keys(()).contains(&def_id) +} + +/// Finds the full set of `DefId`s within the current crate that have +/// MIR associated with them. +fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet { + let mut set = FxHashSet::default(); + + // All body-owners have MIR associated with them. + set.extend(tcx.hir().body_owners()); + + // Additionally, tuple struct/variant constructors have MIR, but + // they don't have a BodyId, so we need to build them separately. + struct GatherCtors<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + set: &'a mut FxHashSet, + } + impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> { + fn visit_variant_data( + &mut self, + v: &'tcx hir::VariantData<'tcx>, + _: Symbol, + _: &'tcx hir::Generics<'tcx>, + _: hir::HirId, + _: Span, + ) { + if let hir::VariantData::Tuple(_, hir_id) = *v { + self.set.insert(self.tcx.hir().local_def_id(hir_id)); + } + intravisit::walk_struct_def(self, v) + } + type Map = intravisit::ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + } + tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor()); + + set +} + +fn run_passes( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + mir_phase: MirPhase, + passes: &[&[&dyn MirPass<'tcx>]], +) { + let phase_index = mir_phase.phase_index(); + let validate = tcx.sess.opts.debugging_opts.validate_mir; + + if body.phase >= mir_phase { + return; + } + + if validate { + validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase } + .run_pass(tcx, body); + } + + let mut index = 0; + let mut run_pass = |pass: &dyn MirPass<'tcx>| { + let run_hooks = |body: &_, index, is_after| { + dump_mir::on_mir_pass( + tcx, + &format_args!("{:03}-{:03}", phase_index, index), + &pass.name(), + body, + is_after, + ); + }; + run_hooks(body, index, false); + pass.run_pass(tcx, body); + run_hooks(body, index, true); + + if validate { + validate::Validator { + when: format!("after {} in phase {:?}", pass.name(), mir_phase), + mir_phase, + } + .run_pass(tcx, body); + } + + index += 1; + }; + + for pass_group in passes { + for pass in *pass_group { + run_pass(*pass); + } + } + + body.phase = mir_phase; + + if mir_phase == MirPhase::Optimization { + validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase } + .run_pass(tcx, body); + } +} + +fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> ConstQualifs { + let const_kind = tcx.hir().body_const_context(def.did); + + // No need to const-check a non-const `fn`. + if const_kind.is_none() { + return Default::default(); + } + + // N.B., this `borrow()` is guaranteed to be valid (i.e., the value + // cannot yet be stolen), because `mir_promoted()`, which steals + // from `mir_const(), forces this query to execute before + // performing the steal. + let body = &tcx.mir_const(def).borrow(); + + if body.return_ty().references_error() { + tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors"); + return Default::default(); + } + + let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def.did) }; + + let mut validator = check_consts::check::Checker::new(&ccx); + validator.check_body(); + + // We return the qualifs in the return place for every MIR body, even though it is only used + // when deciding to promote a reference to a `const` for now. + validator.qualifs_in_return_place() +} + +/// Make MIR ready for const evaluation. This is run on all MIR, not just on consts! +fn mir_const<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> &'tcx Steal> { + if let Some(def) = def.try_upgrade(tcx) { + return tcx.mir_const(def); + } + + // Unsafety check uses the raw mir, so make sure it is run. + if !tcx.sess.opts.debugging_opts.thir_unsafeck { + if let Some(param_did) = def.const_param_did { + tcx.ensure().unsafety_check_result_for_const_arg((def.did, param_did)); + } else { + tcx.ensure().unsafety_check_result(def.did); + } + } + + let mut body = tcx.mir_built(def).steal(); + + rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); + + run_passes( + tcx, + &mut body, + MirPhase::Const, + &[&[ + // MIR-level lints. + &check_packed_ref::CheckPackedRef, + &check_const_item_mutation::CheckConstItemMutation, + &function_item_references::FunctionItemReferences, + // What we need to do constant evaluation. + &simplify::SimplifyCfg::new("initial"), + &rustc_peek::SanityCheck, + ]], + ); + tcx.alloc_steal_mir(body) +} + +/// Compute the main MIR body and the list of MIR bodies of the promoteds. +fn mir_promoted( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> (&'tcx Steal>, &'tcx Steal>>) { + if let Some(def) = def.try_upgrade(tcx) { + return tcx.mir_promoted(def); + } + + // Ensure that we compute the `mir_const_qualif` for constants at + // this point, before we steal the mir-const result. + // Also this means promotion can rely on all const checks having been done. + let _ = tcx.mir_const_qualif_opt_const_arg(def); + let mut body = tcx.mir_const(def).steal(); + + let mut required_consts = Vec::new(); + let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts); + for (bb, bb_data) in traversal::reverse_postorder(&body) { + required_consts_visitor.visit_basic_block_data(bb, bb_data); + } + body.required_consts = required_consts; + + let promote_pass = promote_consts::PromoteTemps::default(); + let promote: &[&dyn MirPass<'tcx>] = &[ + // What we need to run borrowck etc. + &promote_pass, + &simplify::SimplifyCfg::new("promote-consts"), + ]; + + let opt_coverage: &[&dyn MirPass<'tcx>] = + if tcx.sess.instrument_coverage() { &[&coverage::InstrumentCoverage] } else { &[] }; + + run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]); + + let promoted = promote_pass.promoted_fragments.into_inner(); + (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) +} + +/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it) +fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> { + let did = def_id.expect_local(); + if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { + tcx.mir_for_ctfe_of_const_arg(def) + } else { + tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did))) + } +} + +/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter. +/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that +/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck +/// the const parameter while type checking the main body, which in turn would try +/// to type check the main body again. +fn mir_for_ctfe_of_const_arg<'tcx>( + tcx: TyCtxt<'tcx>, + (did, param_did): (LocalDefId, DefId), +) -> &'tcx Body<'tcx> { + tcx.arena.alloc(inner_mir_for_ctfe( + tcx, + ty::WithOptConstParam { did, const_param_did: Some(param_did) }, + )) +} + +fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { + // FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries + if tcx.is_constructor(def.did.to_def_id()) { + // There's no reason to run all of the MIR passes on constructors when + // we can just output the MIR we want directly. This also saves const + // qualification and borrow checking the trouble of special casing + // constructors. + return shim::build_adt_ctor(tcx, def.did.to_def_id()); + } + + let context = tcx + .hir() + .body_const_context(def.did) + .expect("mir_for_ctfe should not be used for runtime functions"); + + let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); + + match context { + // Do not const prop functions, either they get executed at runtime or exported to metadata, + // so we run const prop on them, or they don't, in which case we const evaluate some control + // flow paths of the function and any errors in those paths will get emitted as const eval + // errors. + hir::ConstContext::ConstFn => {} + // Static items always get evaluated, so we can just let const eval see if any erroneous + // control flow paths get executed. + hir::ConstContext::Static(_) => {} + // Associated constants get const prop run so we detect common failure situations in the + // crate that defined the constant. + // Technically we want to not run on regular const items, but oli-obk doesn't know how to + // conveniently detect that at this point without looking at the HIR. + hir::ConstContext::Const => { + #[rustfmt::skip] + let optimizations: &[&dyn MirPass<'_>] = &[ + &const_prop::ConstProp, + ]; + + #[rustfmt::skip] + run_passes( + tcx, + &mut body, + MirPhase::Optimization, + &[ + optimizations, + ], + ); + } + } + + debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE"); + + body +} + +/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs +/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't +/// end up missing the source MIR due to stealing happening. +fn mir_drops_elaborated_and_const_checked<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> &'tcx Steal> { + if let Some(def) = def.try_upgrade(tcx) { + return tcx.mir_drops_elaborated_and_const_checked(def); + } + + // (Mir-)Borrowck uses `mir_promoted`, so we have to force it to + // execute before we can steal. + if let Some(param_did) = def.const_param_did { + tcx.ensure().mir_borrowck_const_arg((def.did, param_did)); + } else { + tcx.ensure().mir_borrowck(def.did); + } + + let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + use rustc_middle::hir::map::blocks::FnLikeNode; + let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some(); + if is_fn_like { + let did = def.did.to_def_id(); + let def = ty::WithOptConstParam::unknown(did); + + // Do not compute the mir call graph without said call graph actually being used. + if inline::is_enabled(tcx) { + let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def)); + } + } + + let (body, _) = tcx.mir_promoted(def); + let mut body = body.steal(); + + run_post_borrowck_cleanup_passes(tcx, &mut body); + check_consts::post_drop_elaboration::check_live_drops(tcx, &body); + tcx.alloc_steal_mir(body) +} + +/// After this series of passes, no lifetime analysis based on borrowing can be done. +fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!("post_borrowck_cleanup({:?})", body.source.def_id()); + + let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[ + // Remove all things only needed by analysis + &simplify_branches::SimplifyBranches::new("initial"), + &remove_noop_landing_pads::RemoveNoopLandingPads, + &cleanup_post_borrowck::CleanupNonCodegenStatements, + &simplify::SimplifyCfg::new("early-opt"), + // These next passes must be executed together + &add_call_guards::CriticalCallEdges, + &elaborate_drops::ElaborateDrops, + // This will remove extraneous landing pads which are no longer + // necessary as well as well as forcing any call in a non-unwinding + // function calling a possibly-unwinding function to abort the process. + &abort_unwinding_calls::AbortUnwindingCalls, + // AddMovesForPackedDrops needs to run after drop + // elaboration. + &add_moves_for_packed_drops::AddMovesForPackedDrops, + // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late, + // but before optimizations begin. + &add_retag::AddRetag, + &lower_intrinsics::LowerIntrinsics, + &simplify::SimplifyCfg::new("elaborate-drops"), + // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening + // and it can help optimizations. + &deaggregator::Deaggregator, + ]; + + run_passes(tcx, body, MirPhase::DropLowering, &[post_borrowck_cleanup]); +} + +fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mir_opt_level = tcx.sess.mir_opt_level(); + + // Lowering generator control-flow and variables has to happen before we do anything else + // to them. We run some optimizations before that, because they may be harder to do on the state + // machine than on MIR with async primitives. + let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[ + &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first + &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering + &unreachable_prop::UnreachablePropagation, + &uninhabited_enum_branching::UninhabitedEnumBranching, + &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"), + &inline::Inline, + &generator::StateTransform, + ]; + + // Even if we don't do optimizations, we still have to lower generators for codegen. + let no_optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[&generator::StateTransform]; + + // The main optimizations that we do on MIR. + let optimizations: &[&dyn MirPass<'tcx>] = &[ + &remove_storage_markers::RemoveStorageMarkers, + &remove_zsts::RemoveZsts, + &const_goto::ConstGoto, + &remove_unneeded_drops::RemoveUnneededDrops, + &match_branches::MatchBranchSimplification, + // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) + &multiple_return_terminators::MultipleReturnTerminators, + &instcombine::InstCombine, + &separate_const_switch::SeparateConstSwitch, + &const_prop::ConstProp, + &simplify_branches::SimplifyBranches::new("after-const-prop"), + &early_otherwise_branch::EarlyOtherwiseBranch, + &simplify_comparison_integral::SimplifyComparisonIntegral, + &simplify_try::SimplifyArmIdentity, + &simplify_try::SimplifyBranchSame, + &dest_prop::DestinationPropagation, + &simplify_branches::SimplifyBranches::new("final"), + &remove_noop_landing_pads::RemoveNoopLandingPads, + &simplify::SimplifyCfg::new("final"), + &nrvo::RenameReturnPlace, + &const_debuginfo::ConstDebugInfo, + &simplify::SimplifyLocals, + &multiple_return_terminators::MultipleReturnTerminators, + &deduplicate_blocks::DeduplicateBlocks, + ]; + + // Optimizations to run even if mir optimizations have been disabled. + let no_optimizations: &[&dyn MirPass<'tcx>] = &[ + // FIXME(#70073): This pass is responsible for both optimization as well as some lints. + &const_prop::ConstProp, + ]; + + // Some cleanup necessary at least for LLVM and potentially other codegen backends. + let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[ + &add_call_guards::CriticalCallEdges, + // Dump the end result for testing and debugging purposes. + &dump_mir::Marker("PreCodegen"), + ]; + + // End of pass declarations, now actually run the passes. + // Generator Lowering + #[rustfmt::skip] + run_passes( + tcx, + body, + MirPhase::GeneratorLowering, + &[ + if mir_opt_level > 0 { + optimizations_with_generators + } else { + no_optimizations_with_generators + } + ], + ); + + // Main optimization passes + #[rustfmt::skip] + run_passes( + tcx, + body, + MirPhase::Optimization, + &[ + if mir_opt_level > 0 { optimizations } else { no_optimizations }, + pre_codegen_cleanup, + ], + ); +} + +/// Optimize the MIR and prepare it for codegen. +fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> { + let did = did.expect_local(); + assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None); + tcx.arena.alloc(inner_optimized_mir(tcx, did)) +} + +fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { + if tcx.is_constructor(did.to_def_id()) { + // There's no reason to run all of the MIR passes on constructors when + // we can just output the MIR we want directly. This also saves const + // qualification and borrow checking the trouble of special casing + // constructors. + return shim::build_adt_ctor(tcx, did.to_def_id()); + } + + match tcx.hir().body_const_context(did) { + // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked` + // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it + // computes and caches its result. + Some(hir::ConstContext::ConstFn) => tcx.ensure().mir_for_ctfe(did), + None => {} + Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other), + } + let mut body = + tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); + run_optimization_passes(tcx, &mut body); + + debug_assert!(!body.has_free_regions(tcx), "Free regions in optimized MIR"); + + body +} + +/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for +/// constant evaluation once all substitutions become known. +fn promoted_mir<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> &'tcx IndexVec> { + if tcx.is_constructor(def.did.to_def_id()) { + return tcx.arena.alloc(IndexVec::new()); + } + + if let Some(param_did) = def.const_param_did { + tcx.ensure().mir_borrowck_const_arg((def.did, param_did)); + } else { + tcx.ensure().mir_borrowck(def.did); + } + let (_, promoted) = tcx.mir_promoted(def); + let mut promoted = promoted.steal(); + + for body in &mut promoted { + run_post_borrowck_cleanup_passes(tcx, body); + } + + debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR"); + + tcx.arena.alloc(promoted) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lower_intrinsics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lower_intrinsics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lower_intrinsics.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lower_intrinsics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,159 @@ +//! Lowers intrinsic calls + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Span; +use rustc_target::spec::abi::Abi; + +pub struct LowerIntrinsics; + +impl<'tcx> MirPass<'tcx> for LowerIntrinsics { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + for block in basic_blocks { + let terminator = block.terminator.as_mut().unwrap(); + if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind { + let func_ty = func.ty(local_decls, tcx); + let (intrinsic_name, substs) = match resolve_rust_intrinsic(tcx, func_ty) { + None => continue, + Some(it) => it, + }; + match intrinsic_name { + sym::unreachable => { + terminator.kind = TerminatorKind::Unreachable; + } + sym::forget => { + if let Some((destination, target)) = *destination { + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + destination, + Rvalue::Use(Operand::Constant(Box::new(Constant { + span: terminator.source_info.span, + user_ty: None, + literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(), + }))), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + sym::copy_nonoverlapping => { + let target = destination.unwrap().1; + let mut args = args.drain(..); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::CopyNonOverlapping(Box::new( + rustc_middle::mir::CopyNonOverlapping { + src: args.next().unwrap(), + dst: args.next().unwrap(), + count: args.next().unwrap(), + }, + )), + }); + assert_eq!( + args.next(), + None, + "Extra argument for copy_non_overlapping intrinsic" + ); + drop(args); + terminator.kind = TerminatorKind::Goto { target }; + } + sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { + if let Some((destination, target)) = *destination { + let lhs; + let rhs; + { + let mut args = args.drain(..); + lhs = args.next().unwrap(); + rhs = args.next().unwrap(); + } + let bin_op = match intrinsic_name { + sym::wrapping_add => BinOp::Add, + sym::wrapping_sub => BinOp::Sub, + sym::wrapping_mul => BinOp::Mul, + _ => bug!("unexpected intrinsic"), + }; + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + destination, + Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { + // The checked binary operations are not suitable target for lowering here, + // since their semantics depend on the value of overflow-checks flag used + // during codegen. Issue #35310. + } + sym::size_of | sym::min_align_of => { + if let Some((destination, target)) = *destination { + let tp_ty = substs.type_at(0); + let null_op = match intrinsic_name { + sym::size_of => NullOp::SizeOf, + sym::min_align_of => NullOp::AlignOf, + _ => bug!("unexpected intrinsic"), + }; + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + destination, + Rvalue::NullaryOp(null_op, tp_ty), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + sym::discriminant_value => { + if let (Some((destination, target)), Some(arg)) = + (*destination, args[0].place()) + { + let arg = tcx.mk_place_deref(arg); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + destination, + Rvalue::Discriminant(arg), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + _ if intrinsic_name.as_str().starts_with("simd_shuffle") => { + validate_simd_shuffle(tcx, args, terminator.source_info.span); + } + _ => {} + } + } + } + } +} + +fn resolve_rust_intrinsic( + tcx: TyCtxt<'tcx>, + func_ty: Ty<'tcx>, +) -> Option<(Symbol, SubstsRef<'tcx>)> { + if let ty::FnDef(def_id, substs) = *func_ty.kind() { + let fn_sig = func_ty.fn_sig(tcx); + if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() { + return Some((tcx.item_name(def_id), substs)); + } + } + None +} + +fn validate_simd_shuffle(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) { + match &args[2] { + Operand::Constant(_) => {} // all good + _ => { + let msg = "last argument of `simd_shuffle` is required to be a `const` item"; + tcx.sess.span_err(span, msg); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lower_slice_len.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lower_slice_len.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lower_slice_len.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/lower_slice_len.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,98 @@ +//! This pass lowers calls to core::slice::len to just Len op. +//! It should run before inlining! + +use crate::MirPass; +use rustc_hir::def_id::DefId; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; + +pub struct LowerSliceLenCalls; + +impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + lower_slice_len_calls(tcx, body) + } +} + +pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let language_items = tcx.lang_items(); + let slice_len_fn_item_def_id = if let Some(slice_len_fn_item) = language_items.slice_len_fn() { + slice_len_fn_item + } else { + // there is no language item to compare to :) + return; + }; + + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + + for block in basic_blocks { + // lower `<[_]>::len` calls + lower_slice_len_call(tcx, block, &*local_decls, slice_len_fn_item_def_id); + } +} + +struct SliceLenPatchInformation<'tcx> { + add_statement: Statement<'tcx>, + new_terminator_kind: TerminatorKind<'tcx>, +} + +fn lower_slice_len_call<'tcx>( + tcx: TyCtxt<'tcx>, + block: &mut BasicBlockData<'tcx>, + local_decls: &IndexVec>, + slice_len_fn_item_def_id: DefId, +) { + let mut patch_found: Option> = None; + + let terminator = block.terminator(); + match &terminator.kind { + TerminatorKind::Call { + func, + args, + destination: Some((dest, bb)), + cleanup: None, + from_hir_call: true, + .. + } => { + // some heuristics for fast rejection + if args.len() != 1 { + return; + } + let arg = match args[0].place() { + Some(arg) => arg, + None => return, + }; + let func_ty = func.ty(local_decls, tcx); + match func_ty.kind() { + ty::FnDef(fn_def_id, _) if fn_def_id == &slice_len_fn_item_def_id => { + // perform modifications + // from something like `_5 = core::slice::::len(move _6) -> bb1` + // into `_5 = Len(*_6) + // goto bb1 + + // make new RValue for Len + let deref_arg = tcx.mk_place_deref(arg); + let r_value = Rvalue::Len(deref_arg); + let len_statement_kind = StatementKind::Assign(Box::new((*dest, r_value))); + let add_statement = + Statement { kind: len_statement_kind, source_info: terminator.source_info }; + + // modify terminator into simple Goto + let new_terminator_kind = TerminatorKind::Goto { target: *bb }; + + let patch = SliceLenPatchInformation { add_statement, new_terminator_kind }; + + patch_found = Some(patch); + } + _ => {} + } + } + _ => {} + } + + if let Some(SliceLenPatchInformation { add_statement, new_terminator_kind }) = patch_found { + block.statements.push(add_statement); + block.terminator_mut().kind = new_terminator_kind; + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/match_branches.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/match_branches.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/match_branches.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/match_branches.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,176 @@ +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use std::iter; + +use super::simplify::simplify_cfg; + +pub struct MatchBranchSimplification; + +/// 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, +/// using Eq / Ne comparison with switch value where const bools value differ. +/// +/// For example: +/// +/// ```rust +/// bb0: { +/// switchInt(move _3) -> [42_isize: bb1, otherwise: bb2]; +/// } +/// +/// bb1: { +/// _2 = const true; +/// goto -> bb3; +/// } +/// +/// bb2: { +/// _2 = const false; +/// goto -> bb3; +/// } +/// ``` +/// +/// into: +/// +/// ```rust +/// bb0: { +/// _2 = Eq(move _3, const 42_isize); +/// goto -> bb3; +/// } +/// ``` + +impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.mir_opt_level() < 3 { + return; + } + + let def_id = body.source.def_id(); + let param_env = tcx.param_env(def_id); + + let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut(); + let mut should_cleanup = false; + 'outer: for bb_idx in bbs.indices() { + if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) { + continue; + } + + let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind { + TerminatorKind::SwitchInt { + discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)), + switch_ty, + ref targets, + .. + } if targets.iter().len() == 1 => { + let (value, target) = targets.iter().next().unwrap(); + if target == targets.otherwise() { + continue; + } + (discr, value, switch_ty, 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; + } + + // 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 => {} + + // 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.literal.ty().is_bool() + && s_c.literal.ty().is_bool() + && f_c.literal.try_eval_bool(tcx, param_env).is_some() + && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {} + + // Otherwise we cannot optimize. Try another block. + _ => continue 'outer, + } + } + // 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[bb_idx].terminator().source_info; + let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span)); + + // 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); + + 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(), + + ( + 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.literal.try_eval_bool(tcx, param_env).unwrap(); + let s_b = s_c.literal.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(switch_ty)).unwrap().size; + let const_cmp = Operand::const_from_scalar( + tcx, + switch_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))), + } + } + } + + _ => unreachable!(), + } + }); + + 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; + } + + if should_cleanup { + simplify_cfg(tcx, body); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/multiple_return_terminators.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/multiple_return_terminators.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/multiple_return_terminators.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/multiple_return_terminators.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,43 @@ +//! This pass removes jumps to basic blocks containing only a return, and replaces them with a +//! return instead. + +use crate::{simplify, MirPass}; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct MultipleReturnTerminators; + +impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.mir_opt_level() < 4 { + return; + } + + // find basic blocks with no statement and a return terminator + let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len()); + let def_id = body.source.def_id(); + let bbs = body.basic_blocks_mut(); + for idx in bbs.indices() { + if bbs[idx].statements.is_empty() + && bbs[idx].terminator().kind == TerminatorKind::Return + { + bbs_simple_returns.insert(idx); + } + } + + for bb in bbs { + if !tcx.consider_optimizing(|| format!("MultipleReturnTerminators {:?} ", def_id)) { + break; + } + + if let TerminatorKind::Goto { target } = bb.terminator().kind { + if bbs_simple_returns.contains(target) { + bb.terminator_mut().kind = TerminatorKind::Return; + } + } + } + + simplify::remove_dead_blocks(tcx, body) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/normalize_array_len.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/normalize_array_len.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/normalize_array_len.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/normalize_array_len.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,286 @@ +//! This pass eliminates casting of arrays into slices when their length +//! is taken using `.len()` method. Handy to preserve information in MIR for const prop + +use crate::MirPass; +use rustc_data_structures::fx::FxIndexMap; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; + +const MAX_NUM_BLOCKS: usize = 800; +const MAX_NUM_LOCALS: usize = 3000; + +pub struct NormalizeArrayLen; + +impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.mir_opt_level() < 4 { + return; + } + + // early returns for edge cases of highly unrolled functions + if body.basic_blocks().len() > MAX_NUM_BLOCKS { + return; + } + if body.local_decls().len() > MAX_NUM_LOCALS { + return; + } + normalize_array_len_calls(tcx, body) + } +} + +pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + + // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]` + let mut interesting_locals = BitSet::new_empty(local_decls.len()); + for (local, decl) in local_decls.iter_enumerated() { + match decl.ty.kind() { + ty::Array(..) => { + interesting_locals.insert(local); + } + ty::Ref(.., ty, Mutability::Not) => match ty.kind() { + ty::Array(..) => { + interesting_locals.insert(local); + } + _ => {} + }, + _ => {} + } + } + if interesting_locals.is_empty() { + // we have found nothing to analyze + return; + } + let num_intesting_locals = interesting_locals.count(); + let mut state = FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); + let mut patches_scratchpad = + FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); + let mut replacements_scratchpad = + FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); + for block in basic_blocks { + // make length calls for arrays [T; N] not to decay into length calls for &[T] + // that forbids constant propagation + normalize_array_len_call( + tcx, + block, + local_decls, + &interesting_locals, + &mut state, + &mut patches_scratchpad, + &mut replacements_scratchpad, + ); + state.clear(); + patches_scratchpad.clear(); + replacements_scratchpad.clear(); + } +} + +struct Patcher<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + patches_scratchpad: &'a FxIndexMap, + replacements_scratchpad: &'a mut FxIndexMap, + local_decls: &'a mut IndexVec>, + statement_idx: usize, +} + +impl<'a, 'tcx> Patcher<'a, 'tcx> { + fn patch_expand_statement( + &mut self, + statement: &mut Statement<'tcx>, + ) -> Option>> { + let idx = self.statement_idx; + if let Some(len_statemnt_idx) = self.patches_scratchpad.get(&idx).copied() { + let mut statements = Vec::with_capacity(2); + + // we are at statement that performs a cast. The only sound way is + // to create another local that performs a similar copy without a cast and then + // use this copy in the Len operation + + match &statement.kind { + StatementKind::Assign(box ( + .., + Rvalue::Cast( + CastKind::Pointer(ty::adjustment::PointerCast::Unsize), + operand, + _, + ), + )) => { + match operand { + Operand::Copy(place) | Operand::Move(place) => { + // create new local + let ty = operand.ty(self.local_decls, self.tcx); + let local_decl = LocalDecl::with_source_info(ty, statement.source_info); + let local = self.local_decls.push(local_decl); + // make it live + let mut make_live_statement = statement.clone(); + make_live_statement.kind = StatementKind::StorageLive(local); + statements.push(make_live_statement); + // copy into it + + let operand = Operand::Copy(*place); + let mut make_copy_statement = statement.clone(); + let assign_to = Place::from(local); + let rvalue = Rvalue::Use(operand); + make_copy_statement.kind = + StatementKind::Assign(box (assign_to, rvalue)); + statements.push(make_copy_statement); + + // to reorder we have to copy and make NOP + statements.push(statement.clone()); + statement.make_nop(); + + self.replacements_scratchpad.insert(len_statemnt_idx, local); + } + _ => { + unreachable!("it's a bug in the implementation") + } + } + } + _ => { + unreachable!("it's a bug in the implementation") + } + } + + self.statement_idx += 1; + + Some(statements.into_iter()) + } else if let Some(local) = self.replacements_scratchpad.get(&idx).copied() { + let mut statements = Vec::with_capacity(2); + + match &statement.kind { + StatementKind::Assign(box (into, Rvalue::Len(place))) => { + let add_deref = if let Some(..) = place.as_local() { + false + } else if let Some(..) = place.local_or_deref_local() { + true + } else { + unreachable!("it's a bug in the implementation") + }; + // replace len statement + let mut len_statement = statement.clone(); + let mut place = Place::from(local); + if add_deref { + place = self.tcx.mk_place_deref(place); + } + len_statement.kind = StatementKind::Assign(box (*into, Rvalue::Len(place))); + statements.push(len_statement); + + // make temporary dead + let mut make_dead_statement = statement.clone(); + make_dead_statement.kind = StatementKind::StorageDead(local); + statements.push(make_dead_statement); + + // make original statement NOP + statement.make_nop(); + } + _ => { + unreachable!("it's a bug in the implementation") + } + } + + self.statement_idx += 1; + + Some(statements.into_iter()) + } else { + self.statement_idx += 1; + None + } + } +} + +fn normalize_array_len_call<'tcx>( + tcx: TyCtxt<'tcx>, + block: &mut BasicBlockData<'tcx>, + local_decls: &mut IndexVec>, + interesting_locals: &BitSet, + state: &mut FxIndexMap, + patches_scratchpad: &mut FxIndexMap, + replacements_scratchpad: &mut FxIndexMap, +) { + for (statement_idx, statement) in block.statements.iter_mut().enumerate() { + match &mut statement.kind { + StatementKind::Assign(box (place, rvalue)) => { + match rvalue { + Rvalue::Cast( + CastKind::Pointer(ty::adjustment::PointerCast::Unsize), + operand, + cast_ty, + ) => { + let local = if let Some(local) = place.as_local() { local } else { return }; + match operand { + Operand::Copy(place) | Operand::Move(place) => { + let operand_local = + if let Some(local) = place.local_or_deref_local() { + local + } else { + return; + }; + if !interesting_locals.contains(operand_local) { + return; + } + let operand_ty = local_decls[operand_local].ty; + match (operand_ty.kind(), cast_ty.kind()) { + (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => { + if of_ty_src == of_ty_dst { + // this is a cast from [T; N] into [T], so we are good + state.insert(local, statement_idx); + } + } + // current way of patching doesn't allow to work with `mut` + ( + ty::Ref( + ty::RegionKind::ReErased, + operand_ty, + Mutability::Not, + ), + ty::Ref(ty::RegionKind::ReErased, cast_ty, Mutability::Not), + ) => { + match (operand_ty.kind(), cast_ty.kind()) { + // current way of patching doesn't allow to work with `mut` + (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => { + if of_ty_src == of_ty_dst { + // this is a cast from [T; N] into [T], so we are good + state.insert(local, statement_idx); + } + } + _ => {} + } + } + _ => {} + } + } + _ => {} + } + } + Rvalue::Len(place) => { + let local = if let Some(local) = place.local_or_deref_local() { + local + } else { + return; + }; + if let Some(cast_statement_idx) = state.get(&local).copied() { + patches_scratchpad.insert(cast_statement_idx, statement_idx); + } + } + _ => { + // invalidate + state.remove(&place.local); + } + } + } + _ => {} + } + } + + let mut patcher = Patcher { + tcx, + patches_scratchpad: &*patches_scratchpad, + replacements_scratchpad, + local_decls, + statement_idx: 0, + }; + + block.expand_statements(|st| patcher.patch_expand_statement(st)); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/nrvo.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/nrvo.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/nrvo.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/nrvo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,239 @@ +//! See the docs for [`RenameReturnPlace`]. + +use rustc_hir::Mutability; +use rustc_index::bit_set::HybridBitSet; +use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::{self, BasicBlock, Local, Location}; +use rustc_middle::ty::TyCtxt; + +use crate::MirPass; + +/// This pass looks for MIR that always copies the same local into the return place and eliminates +/// the copy by renaming all uses of that local to `_0`. +/// +/// This allows LLVM to perform an optimization similar to the named return value optimization +/// (NRVO) that is guaranteed in C++. This avoids a stack allocation and `memcpy` for the +/// relatively common pattern of allocating a buffer on the stack, mutating it, and returning it by +/// value like so: +/// +/// ```rust +/// fn foo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { +/// let mut buf = [0; 1024]; +/// init(&mut buf); +/// buf +/// } +/// ``` +/// +/// For now, this pass is very simple and only capable of eliminating a single copy. A more general +/// version of copy propagation, such as the one based on non-overlapping live ranges in [#47954] and +/// [#71003], could yield even more benefits. +/// +/// [#47954]: https://github.com/rust-lang/rust/pull/47954 +/// [#71003]: https://github.com/rust-lang/rust/pull/71003 +pub struct RenameReturnPlace; + +impl<'tcx> MirPass<'tcx> for RenameReturnPlace { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { + if tcx.sess.mir_opt_level() == 0 { + return; + } + + let def_id = body.source.def_id(); + let returned_local = match local_eligible_for_nrvo(body) { + Some(l) => l, + None => { + debug!("`{:?}` was ineligible for NRVO", def_id); + return; + } + }; + + if !tcx.consider_optimizing(|| format!("RenameReturnPlace {:?}", def_id)) { + return; + } + + debug!( + "`{:?}` was eligible for NRVO, making {:?} the return place", + def_id, returned_local + ); + + RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body); + + // Clean up the `NOP`s we inserted for statements made useless by our renaming. + for block_data in body.basic_blocks_mut() { + block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop); + } + + // Overwrite the debuginfo of `_0` with that of the renamed local. + let (renamed_decl, ret_decl) = + body.local_decls.pick2_mut(returned_local, mir::RETURN_PLACE); + + // Sometimes, the return place is assigned a local of a different but coercable type, for + // example `&mut T` instead of `&T`. Overwriting the `LocalInfo` for the return place means + // its type may no longer match the return type of its function. This doesn't cause a + // problem in codegen because these two types are layout-compatible, but may be unexpected. + debug!("_0: {:?} = {:?}: {:?}", ret_decl.ty, returned_local, renamed_decl.ty); + ret_decl.clone_from(renamed_decl); + + // The return place is always mutable. + ret_decl.mutability = Mutability::Mut; + } +} + +/// MIR that is eligible for the NRVO must fulfill two conditions: +/// 1. The return place must not be read prior to the `Return` terminator. +/// 2. A simple assignment of a whole local to the return place (e.g., `_0 = _1`) must be the +/// only definition of the return place reaching the `Return` terminator. +/// +/// If the MIR fulfills both these conditions, this function returns the `Local` that is assigned +/// to the return place along all possible paths through the control-flow graph. +fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option { + if IsReturnPlaceRead::run(body) { + return None; + } + + let mut copied_to_return_place = None; + for block in body.basic_blocks().indices() { + // Look for blocks with a `Return` terminator. + if !matches!(body[block].terminator().kind, mir::TerminatorKind::Return) { + continue; + } + + // Look for an assignment of a single local to the return place prior to the `Return`. + let returned_local = find_local_assigned_to_return_place(block, body)?; + match body.local_kind(returned_local) { + // FIXME: Can we do this for arguments as well? + mir::LocalKind::Arg => return None, + + mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"), + mir::LocalKind::Var | mir::LocalKind::Temp => {} + } + + // If multiple different locals are copied to the return place. We can't pick a + // single one to rename. + if copied_to_return_place.map_or(false, |old| old != returned_local) { + return None; + } + + copied_to_return_place = Some(returned_local); + } + + copied_to_return_place +} + +fn find_local_assigned_to_return_place( + start: BasicBlock, + body: &mut mir::Body<'_>, +) -> Option { + let mut block = start; + let mut seen = HybridBitSet::new_empty(body.basic_blocks().len()); + + // Iterate as long as `block` has exactly one predecessor that we have not yet visited. + while seen.insert(block) { + trace!("Looking for assignments to `_0` in {:?}", block); + + let local = body[block].statements.iter().rev().find_map(as_local_assigned_to_return_place); + if local.is_some() { + return local; + } + + match body.predecessors()[block].as_slice() { + &[pred] => block = pred, + _ => return None, + } + } + + None +} + +// If this statement is an assignment of an unprojected local to the return place, +// return that local. +fn as_local_assigned_to_return_place(stmt: &mir::Statement<'_>) -> Option { + if let mir::StatementKind::Assign(box (lhs, rhs)) = &stmt.kind { + if lhs.as_local() == Some(mir::RETURN_PLACE) { + if let mir::Rvalue::Use(mir::Operand::Copy(rhs) | mir::Operand::Move(rhs)) = rhs { + return rhs.as_local(); + } + } + } + + None +} + +struct RenameToReturnPlace<'tcx> { + to_rename: Local, + tcx: TyCtxt<'tcx>, +} + +/// Replaces all uses of `self.to_rename` with `_0`. +impl MutVisitor<'tcx> for RenameToReturnPlace<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_statement(&mut self, stmt: &mut mir::Statement<'tcx>, loc: Location) { + // Remove assignments of the local being replaced to the return place, since it is now the + // return place: + // _0 = _1 + if as_local_assigned_to_return_place(stmt) == Some(self.to_rename) { + stmt.kind = mir::StatementKind::Nop; + return; + } + + // Remove storage annotations for the local being replaced: + // StorageLive(_1) + if let mir::StatementKind::StorageLive(local) | mir::StatementKind::StorageDead(local) = + stmt.kind + { + if local == self.to_rename { + stmt.kind = mir::StatementKind::Nop; + return; + } + } + + self.super_statement(stmt, loc) + } + + fn visit_terminator(&mut self, terminator: &mut mir::Terminator<'tcx>, loc: Location) { + // Ignore the implicit "use" of the return place in a `Return` statement. + if let mir::TerminatorKind::Return = terminator.kind { + return; + } + + self.super_terminator(terminator, loc); + } + + fn visit_local(&mut self, l: &mut Local, ctxt: PlaceContext, _: Location) { + if *l == mir::RETURN_PLACE { + assert_eq!(ctxt, PlaceContext::NonUse(NonUseContext::VarDebugInfo)); + } else if *l == self.to_rename { + *l = mir::RETURN_PLACE; + } + } +} + +struct IsReturnPlaceRead(bool); + +impl IsReturnPlaceRead { + fn run(body: &mir::Body<'_>) -> bool { + let mut vis = IsReturnPlaceRead(false); + vis.visit_body(body); + vis.0 + } +} + +impl Visitor<'tcx> for IsReturnPlaceRead { + fn visit_local(&mut self, &l: &Local, ctxt: PlaceContext, _: Location) { + if l == mir::RETURN_PLACE && ctxt.is_use() && !ctxt.is_place_assignment() { + self.0 = true; + } + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, loc: Location) { + // Ignore the implicit "use" of the return place in a `Return` statement. + if let mir::TerminatorKind::Return = terminator.kind { + return; + } + + self.super_terminator(terminator, loc); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,133 @@ +use crate::MirPass; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::patch::MirPatch; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_target::spec::PanicStrategy; + +/// A pass that removes noop landing pads and replaces jumps to them with +/// `None`. This is important because otherwise LLVM generates terrible +/// code for these. +pub struct RemoveNoopLandingPads; + +pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.panic_strategy() == PanicStrategy::Abort { + return; + } + debug!("remove_noop_landing_pads({:?})", body); + + RemoveNoopLandingPads.remove_nop_landing_pads(body) +} + +impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + remove_noop_landing_pads(tcx, body); + } +} + +impl RemoveNoopLandingPads { + fn is_nop_landing_pad( + &self, + bb: BasicBlock, + body: &Body<'_>, + nop_landing_pads: &BitSet, + ) -> bool { + for stmt in &body[bb].statements { + match &stmt.kind { + StatementKind::FakeRead(..) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::Nop => { + // These are all nops in a landing pad + } + + StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => { + if place.as_local().is_some() { + // Writing to a local (e.g., a drop flag) does not + // turn a landing pad to a non-nop + } else { + return false; + } + } + + StatementKind::Assign { .. } + | StatementKind::SetDiscriminant { .. } + | StatementKind::LlvmInlineAsm { .. } + | StatementKind::CopyNonOverlapping(..) + | StatementKind::Retag { .. } => { + return false; + } + } + } + + let terminator = body[bb].terminator(); + match terminator.kind { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => { + terminator.successors().all(|&succ| nop_landing_pads.contains(succ)) + } + TerminatorKind::GeneratorDrop + | TerminatorKind::Yield { .. } + | TerminatorKind::Return + | TerminatorKind::Abort + | TerminatorKind::Unreachable + | TerminatorKind::Call { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::InlineAsm { .. } => false, + } + } + + fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { + // make sure there's a single resume block + let resume_block = { + let patch = MirPatch::new(body); + let resume_block = patch.resume_block(); + patch.apply(body); + resume_block + }; + debug!("remove_noop_landing_pads: resume block is {:?}", resume_block); + + let mut jumps_folded = 0; + let mut landing_pads_removed = 0; + let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len()); + + // This is a post-order traversal, so that if A post-dominates B + // then A will be visited before B. + let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); + for bb in postorder { + debug!(" processing {:?}", bb); + if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { + if let Some(unwind_bb) = *unwind { + if nop_landing_pads.contains(unwind_bb) { + debug!(" removing noop landing pad"); + landing_pads_removed += 1; + *unwind = None; + } + } + } + + for target in body[bb].terminator_mut().successors_mut() { + if *target != resume_block && nop_landing_pads.contains(*target) { + debug!(" folding noop jump to {:?} to resume block", target); + *target = resume_block; + jumps_folded += 1; + } + } + + let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); + if is_nop_landing_pad { + nop_landing_pads.insert(bb); + } + debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad); + } + + debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_storage_markers.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_storage_markers.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_storage_markers.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_storage_markers.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,25 @@ +//! This pass removes storage markers if they won't be emitted during codegen. + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct RemoveStorageMarkers; + +impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.emit_lifetime_markers() { + return; + } + + trace!("Running RemoveStorageMarkers on {:?}", body.source); + for data in body.basic_blocks_mut() { + data.statements.retain(|statement| match statement.kind { + StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::Nop => false, + _ => true, + }) + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,42 @@ +//! This pass replaces a drop of a type that does not need dropping, with a goto + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +use super::simplify::simplify_cfg; + +pub struct RemoveUnneededDrops; + +impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("Running RemoveUnneededDrops on {:?}", body.source); + + let did = body.source.def_id(); + let param_env = tcx.param_env(did); + let mut should_simplify = false; + + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + for block in basic_blocks { + let terminator = block.terminator_mut(); + if let TerminatorKind::Drop { place, target, .. } = terminator.kind { + let ty = place.ty(local_decls, tcx); + if ty.ty.needs_drop(tcx, param_env) { + continue; + } + if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", did)) { + continue; + } + debug!("SUCCESS: replacing `drop` with goto({:?})", target); + terminator.kind = TerminatorKind::Goto { target }; + should_simplify = true; + } + } + + // if we applied optimizations, we potentially have some cfg to cleanup to + // make it easier for further passes + if should_simplify { + simplify_cfg(tcx, body); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_zsts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_zsts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_zsts.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/remove_zsts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,80 @@ +//! Removes assignments to ZST places. + +use crate::MirPass; +use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind}; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub struct RemoveZsts; + +impl<'tcx> MirPass<'tcx> for RemoveZsts { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // Avoid query cycles (generators require optimized MIR for layout). + if tcx.type_of(body.source.def_id()).is_generator() { + return; + } + let param_env = tcx.param_env(body.source.def_id()); + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + for block in basic_blocks.iter_mut() { + for statement in block.statements.iter_mut() { + if let StatementKind::Assign(box (place, _)) = statement.kind { + let place_ty = place.ty(local_decls, tcx).ty; + if !maybe_zst(place_ty) { + continue; + } + let layout = match tcx.layout_of(param_env.and(place_ty)) { + Ok(layout) => layout, + Err(_) => continue, + }; + if !layout.is_zst() { + continue; + } + if involves_a_union(place, local_decls, tcx) { + continue; + } + if tcx.consider_optimizing(|| { + format!( + "RemoveZsts - Place: {:?} SourceInfo: {:?}", + place, statement.source_info + ) + }) { + statement.make_nop(); + } + } + } + } + } +} + +/// A cheap, approximate check to avoid unnecessary `layout_of` calls. +fn maybe_zst(ty: Ty<'_>) -> bool { + match ty.kind() { + // maybe ZST (could be more precise) + ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true, + // definitely ZST + ty::FnDef(..) | ty::Never => true, + // unreachable or can't be ZST + _ => false, + } +} + +/// Miri lazily allocates memory for locals on assignment, +/// so we must preserve writes to unions and union fields, +/// or it will ICE on reads of those fields. +fn involves_a_union<'tcx>( + place: Place<'tcx>, + local_decls: &LocalDecls<'tcx>, + tcx: TyCtxt<'tcx>, +) -> bool { + let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty); + if place_ty.ty.is_union() { + return true; + } + for elem in place.projection { + place_ty = place_ty.projection_ty(tcx, elem); + if place_ty.ty.is_union() { + return true; + } + } + return false; +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/required_consts.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/required_consts.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/required_consts.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/required_consts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{Constant, Location}; +use rustc_middle::ty::ConstKind; + +pub struct RequiredConstsVisitor<'a, 'tcx> { + required_consts: &'a mut Vec>, +} + +impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { + pub fn new(required_consts: &'a mut Vec>) -> Self { + RequiredConstsVisitor { required_consts } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for RequiredConstsVisitor<'a, 'tcx> { + fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) { + if let Some(ct) = constant.literal.const_for_ty() { + if let ConstKind::Unevaluated(_) = ct.val { + self.required_consts.push(*constant); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/separate_const_switch.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/separate_const_switch.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/separate_const_switch.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/separate_const_switch.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,345 @@ +//! A pass that duplicates switch-terminated blocks +//! into a new copy for each predecessor, provided +//! the predecessor sets the value being switched +//! over to a constant. +//! +//! The purpose of this pass is to help constant +//! propagation passes to simplify the switch terminator +//! of the copied blocks into gotos when some predecessors +//! statically determine the output of switches. +//! +//! ```text +//! x = 12 --- ---> something +//! \ / 12 +//! --> switch x +//! / \ otherwise +//! x = y --- ---> something else +//! ``` +//! becomes +//! ```text +//! x = 12 ---> switch x ------> something +//! \ / 12 +//! X +//! / \ otherwise +//! x = y ---> switch x ------> something else +//! ``` +//! so it can hopefully later be turned by another pass into +//! ```text +//! x = 12 --------------------> something +//! / 12 +//! / +//! / otherwise +//! x = y ---- switch x ------> something else +//! ``` +//! +//! This optimization is meant to cover simple cases +//! like `?` desugaring. For now, it thus focuses on +//! simplicity rather than completeness (it notably +//! sometimes duplicates abusively). + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use smallvec::SmallVec; + +pub struct SeparateConstSwitch; + +impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.mir_opt_level() < 4 { + return; + } + + // If execution did something, applying a simplification layer + // helps later passes optimize the copy away. + if separate_const_switch(body) > 0 { + super::simplify::simplify_cfg(tcx, body); + } + } +} + +/// Returns the amount of blocks that were duplicated +pub fn separate_const_switch<'tcx>(body: &mut Body<'tcx>) -> usize { + let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new(); + let predecessors = body.predecessors(); + 'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() { + if let TerminatorKind::SwitchInt { + discr: Operand::Copy(switch_place) | Operand::Move(switch_place), + .. + } = block.terminator().kind + { + // If the block is on an unwind path, do not + // apply the optimization as unwind paths + // rely on a unique parent invariant + if block.is_cleanup { + continue 'block_iter; + } + + // If the block has fewer than 2 predecessors, ignore it + // we could maybe chain blocks that have exactly one + // predecessor, but for now we ignore that + if predecessors[block_id].len() < 2 { + continue 'block_iter; + } + + // First, let's find a non-const place + // that determines the result of the switch + if let Some(switch_place) = find_determining_place(switch_place, block) { + // We now have an input place for which it would + // be interesting if predecessors assigned it from a const + + let mut predecessors_left = predecessors[block_id].len(); + 'predec_iter: for predecessor_id in predecessors[block_id].iter().copied() { + let predecessor = &body.basic_blocks()[predecessor_id]; + + // First we make sure the predecessor jumps + // in a reasonable way + match &predecessor.terminator().kind { + // The following terminators are + // unconditionally valid + TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } => {} + + TerminatorKind::FalseEdge { real_target, .. } => { + if *real_target != block_id { + continue 'predec_iter; + } + } + + // The following terminators are not allowed + TerminatorKind::Resume + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::GeneratorDrop => { + continue 'predec_iter; + } + } + + if is_likely_const(switch_place, predecessor) { + new_blocks.push((predecessor_id, block_id)); + predecessors_left -= 1; + if predecessors_left < 2 { + // If the original block only has one predecessor left, + // we have nothing left to do + break 'predec_iter; + } + } + } + } + } + } + + // Once the analysis is done, perform the duplication + let body_span = body.span; + let copied_blocks = new_blocks.len(); + let blocks = body.basic_blocks_mut(); + for (pred_id, target_id) in new_blocks { + let new_block = blocks[target_id].clone(); + let new_block_id = blocks.push(new_block); + let terminator = blocks[pred_id].terminator_mut(); + + match terminator.kind { + TerminatorKind::Goto { ref mut target } => { + *target = new_block_id; + } + + TerminatorKind::FalseEdge { ref mut real_target, .. } => { + if *real_target == target_id { + *real_target = new_block_id; + } + } + + TerminatorKind::SwitchInt { ref mut targets, .. } => { + targets.all_targets_mut().iter_mut().for_each(|x| { + if *x == target_id { + *x = new_block_id; + } + }); + } + + TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop + | TerminatorKind::Assert { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::Yield { .. } => { + span_bug!( + body_span, + "basic block terminator had unexpected kind {:?}", + &terminator.kind + ) + } + } + } + + copied_blocks +} + +/// This function describes a rough heuristic guessing +/// whether a place is last set with a const within the block. +/// Notably, it will be overly pessimistic in cases that are already +/// not handled by `separate_const_switch`. +fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<'tcx>) -> bool { + for statement in block.statements.iter().rev() { + match &statement.kind { + StatementKind::Assign(assign) => { + if assign.0 == tracked_place { + match assign.1 { + // These rvalues are definitely constant + Rvalue::Use(Operand::Constant(_)) + | Rvalue::Ref(_, _, _) + | Rvalue::AddressOf(_, _) + | Rvalue::Cast(_, Operand::Constant(_), _) + | Rvalue::NullaryOp(_, _) + | Rvalue::ShallowInitBox(_, _) + | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true, + + // These rvalues make things ambiguous + Rvalue::Repeat(_, _) + | Rvalue::ThreadLocalRef(_) + | Rvalue::Len(_) + | Rvalue::BinaryOp(_, _) + | Rvalue::CheckedBinaryOp(_, _) + | Rvalue::Aggregate(_, _) => return false, + + // These rvalues move the place to track + Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _) + | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) + | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place)) + | Rvalue::Discriminant(place) => tracked_place = place, + } + } + } + + // If the discriminant is set, it is always set + // as a constant, so the job is done. + // As we are **ignoring projections**, if the place + // we are tracking sees its discriminant be set, + // that means we had to be tracking the discriminant + // specifically (as it is impossible to switch over + // an enum directly, and if we were switching over + // its content, we would have had to at least cast it to + // some variant first) + StatementKind::SetDiscriminant { place, .. } => { + if **place == tracked_place { + return true; + } + } + + // If inline assembly is found, we probably should + // not try to analyze the code + StatementKind::LlvmInlineAsm(_) => return false, + + // These statements have no influence on the place + // we are interested in + StatementKind::FakeRead(_) + | StatementKind::StorageLive(_) + | StatementKind::Retag(_, _) + | StatementKind::AscribeUserType(_, _) + | StatementKind::Coverage(_) + | StatementKind::StorageDead(_) + | StatementKind::CopyNonOverlapping(_) + | StatementKind::Nop => {} + } + } + + // If no good reason for the place to be const is found, + // give up. We could maybe go up predecessors, but in + // most cases giving up now should be sufficient. + false +} + +/// Finds a unique place that entirely determines the value +/// of `switch_place`, if it exists. This is only a heuristic. +/// Ideally we would like to track multiple determining places +/// for some edge cases, but one is enough for a lot of situations. +fn find_determining_place<'tcx>( + mut switch_place: Place<'tcx>, + block: &BasicBlockData<'tcx>, +) -> Option> { + for statement in block.statements.iter().rev() { + match &statement.kind { + StatementKind::Assign(op) => { + if op.0 != switch_place { + continue; + } + + match op.1 { + // The following rvalues move the place + // that may be const in the predecessor + Rvalue::Use(Operand::Move(new) | Operand::Copy(new)) + | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new)) + | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _) + | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _) + | Rvalue::Discriminant(new) + => switch_place = new, + + // The following rvalues might still make the block + // be valid but for now we reject them + Rvalue::Len(_) + | Rvalue::Ref(_, _, _) + | Rvalue::BinaryOp(_, _) + | Rvalue::CheckedBinaryOp(_, _) + | Rvalue::Aggregate(_, _) + + // The following rvalues definitely mean we cannot + // or should not apply this optimization + | Rvalue::Use(Operand::Constant(_)) + | Rvalue::Repeat(Operand::Constant(_), _) + | Rvalue::ThreadLocalRef(_) + | Rvalue::AddressOf(_, _) + | Rvalue::NullaryOp(_, _) + | Rvalue::ShallowInitBox(_, _) + | Rvalue::UnaryOp(_, Operand::Constant(_)) + | Rvalue::Cast(_, Operand::Constant(_), _) + => return None, + } + } + + // These statements have no influence on the place + // we are interested in + StatementKind::FakeRead(_) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Retag(_, _) + | StatementKind::AscribeUserType(_, _) + | StatementKind::Coverage(_) + | StatementKind::CopyNonOverlapping(_) + | StatementKind::Nop => {} + + // If inline assembly is found, we probably should + // not try to analyze the code + StatementKind::LlvmInlineAsm(_) => return None, + + // If the discriminant is set, it is always set + // as a constant, so the job is already done. + // As we are **ignoring projections**, if the place + // we are tracking sees its discriminant be set, + // that means we had to be tracking the discriminant + // specifically (as it is impossible to switch over + // an enum directly, and if we were switching over + // its content, we would have had to at least cast it to + // some variant first) + StatementKind::SetDiscriminant { place, .. } => { + if **place == switch_place { + return None; + } + } + } + } + + Some(switch_place) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/shim.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/shim.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/shim.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/shim.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,946 @@ +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_middle::mir::*; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_target::abi::VariantIdx; + +use rustc_index::vec::{Idx, IndexVec}; + +use rustc_span::Span; +use rustc_target::spec::abi::Abi; + +use std::fmt; +use std::iter; + +use crate::util::expand_aggregate; +use crate::{ + abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads, + run_passes, simplify, +}; +use rustc_middle::mir::patch::MirPatch; +use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle}; + +pub fn provide(providers: &mut Providers) { + providers.mir_shims = make_shim; +} + +fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> { + debug!("make_shim({:?})", instance); + + let mut result = match instance { + ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), + ty::InstanceDef::VtableShim(def_id) => { + build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id)) + } + ty::InstanceDef::FnPtrShim(def_id, ty) => { + let trait_ = tcx.trait_of_item(def_id).unwrap(); + let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) { + Some(ty::ClosureKind::FnOnce) => Adjustment::Identity, + Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref, + None => bug!("fn pointer {:?} is not an fn", ty), + }; + + build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty)) + } + // We are generating a call back to our def-id, which the + // codegen backend knows to turn to an actual call, be it + // a virtual call, or a direct call to a function for which + // indirect calls must be codegen'd differently than direct ones + // (such as `#[track_caller]`). + ty::InstanceDef::ReifyShim(def_id) => { + build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) + } + ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => { + let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); + let call_mut = tcx + .associated_items(fn_mut) + .in_definition_order() + .find(|it| it.kind == ty::AssocKind::Fn) + .unwrap() + .def_id; + + build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) + } + ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty), + ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), + ty::InstanceDef::Virtual(..) => { + bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) + } + ty::InstanceDef::Intrinsic(_) => { + bug!("creating shims from intrinsics ({:?}) is unsupported", instance) + } + }; + debug!("make_shim({:?}) = untransformed {:?}", instance, result); + + run_passes( + tcx, + &mut result, + MirPhase::Const, + &[&[ + &add_moves_for_packed_drops::AddMovesForPackedDrops, + &remove_noop_landing_pads::RemoveNoopLandingPads, + &simplify::SimplifyCfg::new("make_shim"), + &add_call_guards::CriticalCallEdges, + &abort_unwinding_calls::AbortUnwindingCalls, + ]], + ); + + debug!("make_shim({:?}) = {:?}", instance, result); + + result +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum Adjustment { + /// Pass the receiver as-is. + Identity, + + /// We get passed `&[mut] self` and call the target with `*self`. + /// + /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it + /// (for `VtableShim`, which effectively is passed `&own Self`). + Deref, + + /// We get passed `self: Self` and call the target with `&mut self`. + /// + /// In this case we need to ensure that the `Self` is dropped after the call, as the callee + /// won't do it for us. + RefMut, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum CallKind<'tcx> { + /// Call the `FnPtr` that was passed as the receiver. + Indirect(Ty<'tcx>), + + /// Call a known `FnDef`. + Direct(DefId), +} + +fn local_decls_for_sig<'tcx>( + sig: &ty::FnSig<'tcx>, + span: Span, +) -> IndexVec> { + iter::once(LocalDecl::new(sig.output(), span)) + .chain(sig.inputs().iter().map(|ity| LocalDecl::new(ity, span).immutable())) + .collect() +} + +fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) -> Body<'tcx> { + debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); + + // Check if this is a generator, if so, return the drop glue for it + if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) { + let body = tcx.optimized_mir(gen_def_id).generator_drop().unwrap(); + return body.clone().subst(tcx, substs); + } + + let substs = if let Some(ty) = ty { + tcx.intern_substs(&[ty.into()]) + } else { + InternalSubsts::identity_for_item(tcx, def_id) + }; + let sig = tcx.fn_sig(def_id).subst(tcx, substs); + let sig = tcx.erase_late_bound_regions(sig); + let span = tcx.def_span(def_id); + + let source_info = SourceInfo::outermost(span); + + let return_block = BasicBlock::new(1); + let mut blocks = IndexVec::with_capacity(2); + let block = |blocks: &mut IndexVec<_, _>, kind| { + blocks.push(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { source_info, kind }), + is_cleanup: false, + }) + }; + block(&mut blocks, TerminatorKind::Goto { target: return_block }); + block(&mut blocks, TerminatorKind::Return); + + let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty)); + let mut body = + new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); + + if ty.is_some() { + // The first argument (index 0), but add 1 for the return value. + let dropee_ptr = Place::from(Local::new(1 + 0)); + if tcx.sess.opts.debugging_opts.mir_emit_retag { + // Function arguments should be retagged, and we make this one raw. + body.basic_blocks_mut()[START_BLOCK].statements.insert( + 0, + Statement { + source_info, + kind: StatementKind::Retag(RetagKind::Raw, Box::new(dropee_ptr)), + }, + ); + } + let patch = { + let param_env = tcx.param_env_reveal_all_normalized(def_id); + let mut elaborator = + DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env }; + let dropee = tcx.mk_place_deref(dropee_ptr); + let resume_block = elaborator.patch.resume_block(); + elaborate_drops::elaborate_drop( + &mut elaborator, + source_info, + dropee, + (), + return_block, + elaborate_drops::Unwind::To(resume_block), + START_BLOCK, + ); + elaborator.patch + }; + patch.apply(&mut body); + } + + body +} + +fn new_body<'tcx>( + tcx: TyCtxt<'tcx>, + source: MirSource<'tcx>, + basic_blocks: IndexVec>, + local_decls: IndexVec>, + arg_count: usize, + span: Span, +) -> Body<'tcx> { + Body::new( + tcx, + source, + basic_blocks, + IndexVec::from_elem_n( + SourceScopeData { + span, + parent_scope: None, + inlined: None, + inlined_parent_scope: None, + local_data: ClearCrossCrate::Clear, + }, + 1, + ), + local_decls, + IndexVec::new(), + arg_count, + vec![], + span, + None, + ) +} + +pub struct DropShimElaborator<'a, 'tcx> { + pub body: &'a Body<'tcx>, + pub patch: MirPatch<'tcx>, + pub tcx: TyCtxt<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, +} + +impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + Ok(()) + } +} + +impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { + type Path = (); + + fn patch(&mut self) -> &mut MirPatch<'tcx> { + &mut self.patch + } + fn body(&self) -> &'a Body<'tcx> { + self.body + } + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle { + match mode { + DropFlagMode::Shallow => { + // Drops for the contained fields are "shallow" and "static" - they will simply call + // the field's own drop glue. + DropStyle::Static + } + DropFlagMode::Deep => { + // The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder + // dropping each field contained in the value. + DropStyle::Open + } + } + } + + fn get_drop_flag(&mut self, _path: Self::Path) -> Option> { + None + } + + fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {} + + fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option { + None + } + fn deref_subpath(&self, _path: Self::Path) -> Option { + None + } + fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option { + Some(()) + } + fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option { + None + } +} + +/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`. +fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> { + debug!("build_clone_shim(def_id={:?})", def_id); + + let param_env = tcx.param_env(def_id); + + let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty); + let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env); + + let dest = Place::return_place(); + let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0))); + + match self_ty.kind() { + _ if is_copy => builder.copy_shim(), + ty::Array(ty, len) => builder.array_shim(dest, src, ty, len), + ty::Closure(_, substs) => { + builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys()) + } + ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()), + _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty), + }; + + builder.into_mir() +} + +struct CloneShimBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + def_id: DefId, + local_decls: IndexVec>, + blocks: IndexVec>, + span: Span, + sig: ty::FnSig<'tcx>, +} + +impl CloneShimBuilder<'tcx> { + fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self { + // we must subst the self_ty because it's + // otherwise going to be TySelf and we can't index + // or access fields of a Place of type TySelf. + let substs = tcx.mk_substs_trait(self_ty, &[]); + let sig = tcx.fn_sig(def_id).subst(tcx, substs); + let sig = tcx.erase_late_bound_regions(sig); + let span = tcx.def_span(def_id); + + CloneShimBuilder { + tcx, + def_id, + local_decls: local_decls_for_sig(&sig, span), + blocks: IndexVec::new(), + span, + sig, + } + } + + fn into_mir(self) -> Body<'tcx> { + let source = MirSource::from_instance(ty::InstanceDef::CloneShim( + self.def_id, + self.sig.inputs_and_output[0], + )); + new_body( + self.tcx, + source, + self.blocks, + self.local_decls, + self.sig.inputs().len(), + self.span, + ) + } + + fn source_info(&self) -> SourceInfo { + SourceInfo::outermost(self.span) + } + + fn block( + &mut self, + statements: Vec>, + kind: TerminatorKind<'tcx>, + is_cleanup: bool, + ) -> BasicBlock { + let source_info = self.source_info(); + self.blocks.push(BasicBlockData { + statements, + terminator: Some(Terminator { source_info, kind }), + is_cleanup, + }) + } + + /// Gives the index of an upcoming BasicBlock, with an offset. + /// offset=0 will give you the index of the next BasicBlock, + /// offset=1 will give the index of the next-to-next block, + /// offset=-1 will give you the index of the last-created block + fn block_index_offset(&mut self, offset: usize) -> BasicBlock { + BasicBlock::new(self.blocks.len() + offset) + } + + fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> { + Statement { source_info: self.source_info(), kind } + } + + fn copy_shim(&mut self) { + let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1 + 0))); + let ret_statement = self.make_statement(StatementKind::Assign(Box::new(( + Place::return_place(), + Rvalue::Use(Operand::Copy(rcvr)), + )))); + self.block(vec![ret_statement], TerminatorKind::Return, false); + } + + fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> { + let span = self.span; + let mut local = LocalDecl::new(ty, span); + if mutability == Mutability::Not { + local = local.immutable(); + } + Place::from(self.local_decls.push(local)) + } + + fn make_clone_call( + &mut self, + dest: Place<'tcx>, + src: Place<'tcx>, + ty: Ty<'tcx>, + next: BasicBlock, + cleanup: BasicBlock, + ) { + let tcx = self.tcx; + + let substs = tcx.mk_substs_trait(ty, &[]); + + // `func == Clone::clone(&ty) -> ty` + let func_ty = tcx.mk_fn_def(self.def_id, substs); + let func = Operand::Constant(Box::new(Constant { + span: self.span, + user_ty: None, + literal: ty::Const::zero_sized(tcx, func_ty).into(), + })); + + let ref_loc = self.make_place( + Mutability::Not, + tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }), + ); + + // `let ref_loc: &ty = &src;` + let statement = self.make_statement(StatementKind::Assign(Box::new(( + ref_loc, + Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src), + )))); + + // `let loc = Clone::clone(ref_loc);` + self.block( + vec![statement], + TerminatorKind::Call { + func, + args: vec![Operand::Move(ref_loc)], + destination: Some((dest, next)), + cleanup: Some(cleanup), + from_hir_call: true, + fn_span: self.span, + }, + false, + ); + } + + fn loop_header( + &mut self, + beg: Place<'tcx>, + end: Place<'tcx>, + loop_body: BasicBlock, + loop_end: BasicBlock, + is_cleanup: bool, + ) { + let tcx = self.tcx; + + let cond = self.make_place(Mutability::Mut, tcx.types.bool); + let compute_cond = self.make_statement(StatementKind::Assign(Box::new(( + cond, + Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))), + )))); + + // `if end != beg { goto loop_body; } else { goto loop_end; }` + self.block( + vec![compute_cond], + TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end), + is_cleanup, + ); + } + + fn make_usize(&self, value: u64) -> Box> { + Box::new(Constant { + span: self.span, + user_ty: None, + literal: ty::Const::from_usize(self.tcx, value).into(), + }) + } + + fn array_shim( + &mut self, + dest: Place<'tcx>, + src: Place<'tcx>, + ty: Ty<'tcx>, + len: &'tcx ty::Const<'tcx>, + ) { + let tcx = self.tcx; + let span = self.span; + + let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span)); + let end = self.make_place(Mutability::Not, tcx.types.usize); + + // BB #0 + // `let mut beg = 0;` + // `let end = len;` + // `goto #1;` + let inits = vec![ + self.make_statement(StatementKind::Assign(Box::new(( + Place::from(beg), + Rvalue::Use(Operand::Constant(self.make_usize(0))), + )))), + self.make_statement(StatementKind::Assign(Box::new(( + end, + Rvalue::Use(Operand::Constant(Box::new(Constant { + span: self.span, + user_ty: None, + literal: len.into(), + }))), + )))), + ]; + self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false); + + // BB #1: loop { + // BB #2; + // BB #3; + // } + // BB #4; + self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false); + + // BB #2 + // `dest[i] = Clone::clone(src[beg])`; + // Goto #3 if ok, #5 if unwinding happens. + let dest_field = self.tcx.mk_place_index(dest, beg); + let src_field = self.tcx.mk_place_index(src, beg); + self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5)); + + // BB #3 + // `beg = beg + 1;` + // `goto #1`; + let statements = vec![self.make_statement(StatementKind::Assign(Box::new(( + Place::from(beg), + Rvalue::BinaryOp( + BinOp::Add, + Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))), + ), + ))))]; + self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false); + + // BB #4 + // `return dest;` + self.block(vec![], TerminatorKind::Return, false); + + // BB #5 (cleanup) + // `let end = beg;` + // `let mut beg = 0;` + // goto #6; + let end = beg; + let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span)); + let init = self.make_statement(StatementKind::Assign(Box::new(( + Place::from(beg), + Rvalue::Use(Operand::Constant(self.make_usize(0))), + )))); + self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); + + // BB #6 (cleanup): loop { + // BB #7; + // BB #8; + // } + // BB #9; + self.loop_header( + Place::from(beg), + Place::from(end), + BasicBlock::new(7), + BasicBlock::new(9), + true, + ); + + // BB #7 (cleanup) + // `drop(dest[beg])`; + self.block( + vec![], + TerminatorKind::Drop { + place: self.tcx.mk_place_index(dest, beg), + target: BasicBlock::new(8), + unwind: None, + }, + true, + ); + + // BB #8 (cleanup) + // `beg = beg + 1;` + // `goto #6;` + let statement = self.make_statement(StatementKind::Assign(Box::new(( + Place::from(beg), + Rvalue::BinaryOp( + BinOp::Add, + Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))), + ), + )))); + self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); + + // BB #9 (resume) + self.block(vec![], TerminatorKind::Resume, true); + } + + fn tuple_like_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I) + where + I: Iterator>, + { + let mut previous_field = None; + for (i, ity) in tys.enumerate() { + let field = Field::new(i); + let src_field = self.tcx.mk_place_field(src, field, ity); + + let dest_field = self.tcx.mk_place_field(dest, field, ity); + + // #(2i + 1) is the cleanup block for the previous clone operation + let cleanup_block = self.block_index_offset(1); + // #(2i + 2) is the next cloning block + // (or the Return terminator if this is the last block) + let next_block = self.block_index_offset(2); + + // BB #(2i) + // `dest.i = Clone::clone(&src.i);` + // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens. + self.make_clone_call(dest_field, src_field, ity, next_block, cleanup_block); + + // BB #(2i + 1) (cleanup) + if let Some((previous_field, previous_cleanup)) = previous_field.take() { + // Drop previous field and goto previous cleanup block. + self.block( + vec![], + TerminatorKind::Drop { + place: previous_field, + target: previous_cleanup, + unwind: None, + }, + true, + ); + } else { + // Nothing to drop, just resume. + self.block(vec![], TerminatorKind::Resume, true); + } + + previous_field = Some((dest_field, cleanup_block)); + } + + self.block(vec![], TerminatorKind::Return, false); + } +} + +/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`, +/// first adjusting its first argument according to `rcvr_adjustment`. +fn build_call_shim<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, + rcvr_adjustment: Option, + call_kind: CallKind<'tcx>, +) -> Body<'tcx> { + debug!( + "build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})", + instance, rcvr_adjustment, call_kind + ); + + // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used + // to substitute into the signature of the shim. It is not necessary for users of this + // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`). + let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { + let sig = tcx.erase_late_bound_regions(ty.fn_sig(tcx)); + + let untuple_args = sig.inputs(); + + // Create substitutions for the `Self` and `Args` generic parameters of the shim body. + let arg_tup = tcx.mk_tup(untuple_args.iter()); + let sig_substs = tcx.mk_substs_trait(ty, &[ty::subst::GenericArg::from(arg_tup)]); + + (Some(sig_substs), Some(untuple_args)) + } else { + (None, None) + }; + + let def_id = instance.def_id(); + let sig = tcx.fn_sig(def_id); + let mut sig = tcx.erase_late_bound_regions(sig); + + assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); + if let Some(sig_substs) = sig_substs { + sig = sig.subst(tcx, sig_substs); + } + + if let CallKind::Indirect(fnty) = call_kind { + // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This + // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from + // the implemented `FnX` trait. + + // Apply the opposite adjustment to the MIR input. + let mut inputs_and_output = sig.inputs_and_output.to_vec(); + + // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the + // fn arguments. `Self` may be passed via (im)mutable reference or by-value. + assert_eq!(inputs_and_output.len(), 3); + + // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for + // `FnDef` and `FnPtr` callees, not the `Self` type param. + let self_arg = &mut inputs_and_output[0]; + *self_arg = match rcvr_adjustment.unwrap() { + Adjustment::Identity => fnty, + Adjustment::Deref => tcx.mk_imm_ptr(fnty), + Adjustment::RefMut => tcx.mk_mut_ptr(fnty), + }; + sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); + } + + // FIXME(eddyb) avoid having this snippet both here and in + // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). + if let ty::InstanceDef::VtableShim(..) = instance { + // Modify fn(self, ...) to fn(self: *mut Self, ...) + let mut inputs_and_output = sig.inputs_and_output.to_vec(); + let self_arg = &mut inputs_and_output[0]; + debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param); + *self_arg = tcx.mk_mut_ptr(*self_arg); + sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); + } + + let span = tcx.def_span(def_id); + + debug!("build_call_shim: sig={:?}", sig); + + let mut local_decls = local_decls_for_sig(&sig, span); + let source_info = SourceInfo::outermost(span); + + let rcvr_place = || { + assert!(rcvr_adjustment.is_some()); + Place::from(Local::new(1 + 0)) + }; + let mut statements = vec![]; + + let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment { + Adjustment::Identity => Operand::Move(rcvr_place()), + Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), + Adjustment::RefMut => { + // let rcvr = &mut rcvr; + let ref_rcvr = local_decls.push( + LocalDecl::new( + tcx.mk_ref( + tcx.lifetimes.re_erased, + ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut }, + ), + span, + ) + .immutable(), + ); + let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false }; + statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + Place::from(ref_rcvr), + Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()), + ))), + }); + Operand::Move(Place::from(ref_rcvr)) + } + }); + + let (callee, mut args) = match call_kind { + // `FnPtr` call has no receiver. Args are untupled below. + CallKind::Indirect(_) => (rcvr.unwrap(), vec![]), + + // `FnDef` call with optional receiver. + CallKind::Direct(def_id) => { + let ty = tcx.type_of(def_id); + ( + Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: ty::Const::zero_sized(tcx, ty).into(), + })), + rcvr.into_iter().collect::>(), + ) + } + }; + + let mut arg_range = 0..sig.inputs().len(); + + // Take the `self` ("receiver") argument out of the range (it's adjusted above). + if rcvr_adjustment.is_some() { + arg_range.start += 1; + } + + // Take the last argument, if we need to untuple it (handled below). + if untuple_args.is_some() { + arg_range.end -= 1; + } + + // Pass all of the non-special arguments directly. + args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i))))); + + // Untuple the last argument, if we have to. + if let Some(untuple_args) = untuple_args { + let tuple_arg = Local::new(1 + (sig.inputs().len() - 1)); + args.extend(untuple_args.iter().enumerate().map(|(i, ity)| { + Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), Field::new(i), *ity)) + })); + } + + let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 }; + let mut blocks = IndexVec::with_capacity(n_blocks); + let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { + blocks.push(BasicBlockData { + statements, + terminator: Some(Terminator { source_info, kind }), + is_cleanup, + }) + }; + + // BB #0 + block( + &mut blocks, + statements, + TerminatorKind::Call { + func: callee, + args, + destination: Some((Place::return_place(), BasicBlock::new(1))), + cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment { + Some(BasicBlock::new(3)) + } else { + None + }, + from_hir_call: true, + fn_span: span, + }, + false, + ); + + if let Some(Adjustment::RefMut) = rcvr_adjustment { + // BB #1 - drop for Self + block( + &mut blocks, + vec![], + TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None }, + false, + ); + } + // BB #1/#2 - return + block(&mut blocks, vec![], TerminatorKind::Return, false); + if let Some(Adjustment::RefMut) = rcvr_adjustment { + // BB #3 - drop if closure panics + block( + &mut blocks, + vec![], + TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None }, + true, + ); + + // BB #4 - resume + block(&mut blocks, vec![], TerminatorKind::Resume, true); + } + + let mut body = new_body( + tcx, + MirSource::from_instance(instance), + blocks, + local_decls, + sig.inputs().len(), + span, + ); + + if let Abi::RustCall = sig.abi { + body.spread_arg = Some(Local::new(sig.inputs().len())); + } + + body +} + +pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { + debug_assert!(tcx.is_constructor(ctor_id)); + + let span = + tcx.hir().span_if_local(ctor_id).unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id)); + + let param_env = tcx.param_env(ctor_id); + + // Normalize the sig. + let sig = tcx.fn_sig(ctor_id).no_bound_vars().expect("LBR in ADT constructor signature"); + let sig = tcx.normalize_erasing_regions(param_env, sig); + + let (adt_def, substs) = match sig.output().kind() { + ty::Adt(adt_def, substs) => (adt_def, substs), + _ => bug!("unexpected type for ADT ctor {:?}", sig.output()), + }; + + debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig); + + let local_decls = local_decls_for_sig(&sig, span); + + let source_info = SourceInfo::outermost(span); + + let variant_index = if adt_def.is_enum() { + adt_def.variant_index_with_ctor_id(ctor_id) + } else { + VariantIdx::new(0) + }; + + // Generate the following MIR: + // + // (return as Variant).field0 = arg0; + // (return as Variant).field1 = arg1; + // + // return; + debug!("build_ctor: variant_index={:?}", variant_index); + + let statements = expand_aggregate( + Place::return_place(), + adt_def.variants[variant_index].fields.iter().enumerate().map(|(idx, field_def)| { + (Operand::Move(Place::from(Local::new(idx + 1))), field_def.ty(tcx, substs)) + }), + AggregateKind::Adt(adt_def, variant_index, substs, None, None), + source_info, + tcx, + ) + .collect(); + + let start_block = BasicBlockData { + statements, + terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), + is_cleanup: false, + }; + + let source = MirSource::item(ctor_id); + let body = new_body( + tcx, + source, + IndexVec::from_elem_n(start_block, 1), + local_decls, + sig.inputs().len(), + span, + ); + + rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); + + body +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_branches.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_branches.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_branches.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_branches.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,66 @@ +//! A pass that simplifies branches when their condition is known. + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +use std::borrow::Cow; + +pub struct SimplifyBranches { + label: String, +} + +impl SimplifyBranches { + pub fn new(label: &str) -> Self { + SimplifyBranches { label: format!("SimplifyBranches-{}", label) } + } +} + +impl<'tcx> MirPass<'tcx> for SimplifyBranches { + fn name(&self) -> Cow<'_, str> { + Cow::Borrowed(&self.label) + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let param_env = tcx.param_env(body.source.def_id()); + for block in body.basic_blocks_mut() { + let terminator = block.terminator_mut(); + terminator.kind = match terminator.kind { + TerminatorKind::SwitchInt { + discr: Operand::Constant(ref c), + switch_ty, + ref targets, + .. + } => { + let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty); + if let Some(constant) = constant { + let otherwise = targets.otherwise(); + let mut ret = TerminatorKind::Goto { target: otherwise }; + for (v, t) in targets.iter() { + if v == constant { + ret = TerminatorKind::Goto { target: t }; + break; + } + } + ret + } else { + continue; + } + } + TerminatorKind::Assert { + target, cond: Operand::Constant(ref c), expected, .. + } => match c.literal.try_eval_bool(tcx, param_env) { + Some(v) if v == expected => TerminatorKind::Goto { target }, + _ => continue, + }, + TerminatorKind::FalseEdge { real_target, .. } => { + TerminatorKind::Goto { target: real_target } + } + TerminatorKind::FalseUnwind { real_target, .. } => { + TerminatorKind::Goto { target: real_target } + } + _ => continue, + }; + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,238 @@ +use std::iter; + +use super::MirPass; +use rustc_middle::{ + mir::{ + interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, + StatementKind, SwitchTargets, TerminatorKind, + }, + ty::{Ty, TyCtxt}, +}; + +/// Pass to convert `if` conditions on integrals into switches on the integral. +/// For an example, it turns something like +/// +/// ``` +/// _3 = Eq(move _4, const 43i32); +/// StorageDead(_4); +/// switchInt(_3) -> [false: bb2, otherwise: bb3]; +/// ``` +/// +/// into: +/// +/// ``` +/// switchInt(_4) -> [43i32: bb3, otherwise: bb2]; +/// ``` +pub struct SimplifyComparisonIntegral; + +impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("Running SimplifyComparisonIntegral on {:?}", body.source); + + let helper = OptimizationFinder { body }; + let opts = helper.find_optimizations(); + let mut storage_deads_to_insert = vec![]; + let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![]; + let param_env = tcx.param_env(body.source.def_id()); + for opt in opts { + trace!("SUCCESS: Applying {:?}", opt); + // replace terminator with a switchInt that switches on the integer directly + let bbs = &mut body.basic_blocks_mut(); + let bb = &mut bbs[opt.bb_idx]; + let new_value = match opt.branch_value_scalar { + Scalar::Int(int) => { + let layout = tcx + .layout_of(param_env.and(opt.branch_value_ty)) + .expect("if we have an evaluated constant we must know the layout"); + int.assert_bits(layout.size) + } + Scalar::Ptr(..) => continue, + }; + const FALSE: u128 = 0; + + let mut new_targets = opt.targets; + let first_value = new_targets.iter().next().unwrap().0; + let first_is_false_target = first_value == FALSE; + match opt.op { + BinOp::Eq => { + // if the assignment was Eq we want the true case to be first + if first_is_false_target { + new_targets.all_targets_mut().swap(0, 1); + } + } + BinOp::Ne => { + // if the assignment was Ne we want the false case to be first + if !first_is_false_target { + new_targets.all_targets_mut().swap(0, 1); + } + } + _ => unreachable!(), + } + + // delete comparison statement if it the value being switched on was moved, which means it can not be user later on + if opt.can_remove_bin_op_stmt { + bb.statements[opt.bin_op_stmt_idx].make_nop(); + } else { + // if the integer being compared to a const integral is being moved into the comparison, + // e.g `_2 = Eq(move _3, const 'x');` + // we want to avoid making a double move later on in the switchInt on _3. + // So to avoid `switchInt(move _3) -> ['x': bb2, otherwise: bb1];`, + // we convert the move in the comparison statement to a copy. + + // unwrap is safe as we know this statement is an assign + let (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap(); + + use Operand::*; + match rhs { + Rvalue::BinaryOp(_, box (ref mut left @ Move(_), Constant(_))) => { + *left = Copy(opt.to_switch_on); + } + Rvalue::BinaryOp(_, box (Constant(_), ref mut right @ Move(_))) => { + *right = Copy(opt.to_switch_on); + } + _ => (), + } + } + + let terminator = bb.terminator(); + + // remove StorageDead (if it exists) being used in the assign of the comparison + for (stmt_idx, stmt) in bb.statements.iter().enumerate() { + if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local) + { + continue; + } + storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); + // if we have StorageDeads to remove then make sure to insert them at the top of each target + for bb_idx in new_targets.all_targets() { + storage_deads_to_insert.push(( + *bb_idx, + Statement { + source_info: terminator.source_info, + kind: StatementKind::StorageDead(opt.to_switch_on.local), + }, + )); + } + } + + let [bb_cond, bb_otherwise] = match new_targets.all_targets() { + [a, b] => [*a, *b], + e => bug!("expected 2 switch targets, got: {:?}", e), + }; + + let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise); + + let terminator = bb.terminator_mut(); + terminator.kind = TerminatorKind::SwitchInt { + discr: Operand::Move(opt.to_switch_on), + switch_ty: opt.branch_value_ty, + targets, + }; + } + + for (idx, bb_idx) in storage_deads_to_remove { + body.basic_blocks_mut()[bb_idx].statements[idx].make_nop(); + } + + for (idx, stmt) in storage_deads_to_insert { + body.basic_blocks_mut()[idx].statements.insert(0, stmt); + } + } +} + +struct OptimizationFinder<'a, 'tcx> { + body: &'a Body<'tcx>, +} + +impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> { + fn find_optimizations(&self) -> Vec> { + self.body + .basic_blocks() + .iter_enumerated() + .filter_map(|(bb_idx, bb)| { + // find switch + let (place_switched_on, targets, place_switched_on_moved) = + match &bb.terminator().kind { + rustc_middle::mir::TerminatorKind::SwitchInt { discr, targets, .. } => { + Some((discr.place()?, targets, discr.is_move())) + } + _ => None, + }?; + + // find the statement that assigns the place being switched on + bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| { + match &stmt.kind { + rustc_middle::mir::StatementKind::Assign(box (lhs, rhs)) + if *lhs == place_switched_on => + { + match rhs { + Rvalue::BinaryOp( + op @ (BinOp::Eq | BinOp::Ne), + box (left, right), + ) => { + let (branch_value_scalar, branch_value_ty, to_switch_on) = + find_branch_value_info(left, right)?; + + Some(OptimizationInfo { + bin_op_stmt_idx: stmt_idx, + bb_idx, + can_remove_bin_op_stmt: place_switched_on_moved, + to_switch_on, + branch_value_scalar, + branch_value_ty, + op: *op, + targets: targets.clone(), + }) + } + _ => None, + } + } + _ => None, + } + }) + }) + .collect() + } +} + +fn find_branch_value_info<'tcx>( + left: &Operand<'tcx>, + right: &Operand<'tcx>, +) -> Option<(Scalar, Ty<'tcx>, Place<'tcx>)> { + // check that either left or right is a constant. + // if any are, we can use the other to switch on, and the constant as a value in a switch + use Operand::*; + match (left, right) { + (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) + | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { + let branch_value_ty = branch_value.literal.ty(); + // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats + if !branch_value_ty.is_integral() && !branch_value_ty.is_char() { + return None; + }; + let branch_value_scalar = branch_value.literal.try_to_scalar()?; + Some((branch_value_scalar, branch_value_ty, *to_switch_on)) + } + _ => None, + } +} + +#[derive(Debug)] +struct OptimizationInfo<'tcx> { + /// Basic block to apply the optimization + bb_idx: BasicBlock, + /// Statement index of Eq/Ne assignment that can be removed. None if the assignment can not be removed - i.e the statement is used later on + bin_op_stmt_idx: usize, + /// Can remove Eq/Ne assignment + can_remove_bin_op_stmt: bool, + /// Place that needs to be switched on. This place is of type integral + to_switch_on: Place<'tcx>, + /// Constant to use in switch target value + branch_value_scalar: Scalar, + /// Type of the constant value + branch_value_ty: Ty<'tcx>, + /// Either Eq or Ne + op: BinOp, + /// Current targets used in the switch + targets: SwitchTargets, +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,567 @@ +//! A number of passes which remove various redundancies in the CFG. +//! +//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals` +//! gets rid of all the unnecessary local variable declarations. +//! +//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often. +//! Most of the passes should not care or be impacted in meaningful ways due to extra locals +//! either, so running the pass once, right before codegen, should suffice. +//! +//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus +//! one should run it after every pass which may modify CFG in significant ways. This pass must +//! also be run before any analysis passes because it removes dead blocks, and some of these can be +//! ill-typed. +//! +//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have +//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's +//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A +//! standard example of the situation is: +//! +//! ```rust +//! fn example() { +//! let _a: char = { return; }; +//! } +//! ``` +//! +//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we +//! naively generate still contains the `_a = ()` write in the unreachable block "after" the +//! return. + +use crate::MirPass; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::coverage::*; +use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use smallvec::SmallVec; +use std::borrow::Cow; +use std::convert::TryInto; + +pub struct SimplifyCfg { + label: String, +} + +impl SimplifyCfg { + pub fn new(label: &str) -> Self { + SimplifyCfg { label: format!("SimplifyCfg-{}", label) } + } +} + +pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { + CfgSimplifier::new(body).simplify(); + remove_dead_blocks(tcx, body); + + // FIXME: Should probably be moved into some kind of pass manager + body.basic_blocks_mut().raw.shrink_to_fit(); +} + +impl<'tcx> MirPass<'tcx> for SimplifyCfg { + fn name(&self) -> Cow<'_, str> { + Cow::Borrowed(&self.label) + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source); + simplify_cfg(tcx, body); + } +} + +pub struct CfgSimplifier<'a, 'tcx> { + basic_blocks: &'a mut IndexVec>, + pred_count: IndexVec, +} + +impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { + pub fn new(body: &'a mut Body<'tcx>) -> Self { + let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks()); + + // we can't use mir.predecessors() here because that counts + // dead blocks, which we don't want to. + pred_count[START_BLOCK] = 1; + + for (_, data) in traversal::preorder(body) { + if let Some(ref term) = data.terminator { + for &tgt in term.successors() { + pred_count[tgt] += 1; + } + } + } + + let basic_blocks = body.basic_blocks_mut(); + + CfgSimplifier { basic_blocks, pred_count } + } + + pub fn simplify(mut self) { + self.strip_nops(); + + // Vec of the blocks that should be merged. We store the indices here, instead of the + // statements itself to avoid moving the (relatively) large statements twice. + // We do not push the statements directly into the target block (`bb`) as that is slower + // due to additional reallocations + let mut merged_blocks = Vec::new(); + loop { + let mut changed = false; + + for bb in self.basic_blocks.indices() { + if self.pred_count[bb] == 0 { + continue; + } + + debug!("simplifying {:?}", bb); + + let mut terminator = + self.basic_blocks[bb].terminator.take().expect("invalid terminator state"); + + for successor in terminator.successors_mut() { + self.collapse_goto_chain(successor, &mut changed); + } + + let mut inner_changed = true; + merged_blocks.clear(); + while inner_changed { + inner_changed = false; + inner_changed |= self.simplify_branch(&mut terminator); + inner_changed |= self.merge_successor(&mut merged_blocks, &mut terminator); + changed |= inner_changed; + } + + let statements_to_merge = + merged_blocks.iter().map(|&i| self.basic_blocks[i].statements.len()).sum(); + + if statements_to_merge > 0 { + let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements); + statements.reserve(statements_to_merge); + for &from in &merged_blocks { + statements.append(&mut self.basic_blocks[from].statements); + } + self.basic_blocks[bb].statements = statements; + } + + self.basic_blocks[bb].terminator = Some(terminator); + } + + if !changed { + break; + } + } + } + + /// This function will return `None` if + /// * the block has statements + /// * the block has a terminator other than `goto` + /// * the block has no terminator (meaning some other part of the current optimization stole it) + fn take_terminator_if_simple_goto(&mut self, bb: BasicBlock) -> Option> { + match self.basic_blocks[bb] { + BasicBlockData { + ref statements, + terminator: + ref mut terminator @ Some(Terminator { kind: TerminatorKind::Goto { .. }, .. }), + .. + } if statements.is_empty() => terminator.take(), + // if `terminator` is None, this means we are in a loop. In that + // case, let all the loop collapse to its entry. + _ => None, + } + } + + /// Collapse a goto chain starting from `start` + fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) { + // Using `SmallVec` here, because in some logs on libcore oli-obk saw many single-element + // goto chains. We should probably benchmark different sizes. + let mut terminators: SmallVec<[_; 1]> = Default::default(); + let mut current = *start; + while let Some(terminator) = self.take_terminator_if_simple_goto(current) { + let target = match terminator { + Terminator { kind: TerminatorKind::Goto { target }, .. } => target, + _ => unreachable!(), + }; + terminators.push((current, terminator)); + current = target; + } + let last = current; + *start = last; + while let Some((current, mut terminator)) = terminators.pop() { + let target = match terminator { + Terminator { kind: TerminatorKind::Goto { ref mut target }, .. } => target, + _ => unreachable!(), + }; + *changed |= *target != last; + *target = last; + debug!("collapsing goto chain from {:?} to {:?}", current, target); + + if self.pred_count[current] == 1 { + // This is the last reference to current, so the pred-count to + // to target is moved into the current block. + self.pred_count[current] = 0; + } else { + self.pred_count[*target] += 1; + self.pred_count[current] -= 1; + } + self.basic_blocks[current].terminator = Some(terminator); + } + } + + // merge a block with 1 `goto` predecessor to its parent + fn merge_successor( + &mut self, + merged_blocks: &mut Vec, + terminator: &mut Terminator<'tcx>, + ) -> bool { + let target = match terminator.kind { + TerminatorKind::Goto { target } if self.pred_count[target] == 1 => target, + _ => return false, + }; + + debug!("merging block {:?} into {:?}", target, terminator); + *terminator = match self.basic_blocks[target].terminator.take() { + Some(terminator) => terminator, + None => { + // unreachable loop - this should not be possible, as we + // don't strand blocks, but handle it correctly. + return false; + } + }; + + merged_blocks.push(target); + self.pred_count[target] = 0; + + true + } + + // turn a branch with all successors identical to a goto + fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool { + match terminator.kind { + TerminatorKind::SwitchInt { .. } => {} + _ => return false, + }; + + let first_succ = { + if let Some(&first_succ) = terminator.successors().next() { + if terminator.successors().all(|s| *s == first_succ) { + let count = terminator.successors().count(); + self.pred_count[first_succ] -= (count - 1) as u32; + first_succ + } else { + return false; + } + } else { + return false; + } + }; + + debug!("simplifying branch {:?}", terminator); + terminator.kind = TerminatorKind::Goto { target: first_succ }; + true + } + + fn strip_nops(&mut self) { + for blk in self.basic_blocks.iter_mut() { + blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop)) + } + } +} + +pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { + let reachable = traversal::reachable_as_bitset(body); + let num_blocks = body.basic_blocks().len(); + if num_blocks == reachable.count() { + return; + } + + let basic_blocks = body.basic_blocks_mut(); + let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); + let mut used_blocks = 0; + for alive_index in reachable.iter() { + let alive_index = alive_index.index(); + replacements[alive_index] = BasicBlock::new(used_blocks); + if alive_index != used_blocks { + // Swap the next alive block data with the current available slot. Since + // alive_index is non-decreasing this is a valid operation. + basic_blocks.raw.swap(alive_index, used_blocks); + } + used_blocks += 1; + } + + if tcx.sess.instrument_coverage() { + save_unreachable_coverage(basic_blocks, used_blocks); + } + + basic_blocks.raw.truncate(used_blocks); + + for block in basic_blocks { + for target in block.terminator_mut().successors_mut() { + *target = replacements[target.index()]; + } + } +} + +/// Some MIR transforms can determine at compile time that a sequences of +/// statements will never be executed, so they can be dropped from the MIR. +/// For example, an `if` or `else` block that is guaranteed to never be executed +/// because its condition can be evaluated at compile time, such as by const +/// evaluation: `if false { ... }`. +/// +/// Those statements are bypassed by redirecting paths in the CFG around the +/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually +/// include `Coverage` statements representing the Rust source code regions to +/// be counted at runtime. Without these `Coverage` statements, the regions are +/// lost, and the Rust source code will show no coverage information. +/// +/// What we want to show in a coverage report is the dead code with coverage +/// counts of `0`. To do this, we need to save the code regions, by injecting +/// `Unreachable` coverage statements. These are non-executable statements whose +/// code regions are still recorded in the coverage map, representing regions +/// with `0` executions. +fn save_unreachable_coverage( + basic_blocks: &mut IndexVec>, + first_dead_block: usize, +) { + let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| { + live_block.statements.iter().any(|statement| { + if let StatementKind::Coverage(coverage) = &statement.kind { + matches!(coverage.kind, CoverageKind::Counter { .. }) + } else { + false + } + }) + }); + if !has_live_counters { + // If there are no live `Counter` `Coverage` statements anymore, don't + // move dead coverage to the `START_BLOCK`. Just allow the dead + // `Coverage` statements to be dropped with the dead blocks. + // + // The `generator::StateTransform` MIR pass can create atypical + // conditions, where all live `Counter`s are dropped from the MIR. + // + // At least one Counter per function is required by LLVM (and necessary, + // to add the `function_hash` to the counter's call to the LLVM + // intrinsic `instrprof.increment()`). + return; + } + + // Retain coverage info for dead blocks, so coverage reports will still + // report `0` executions for the uncovered code regions. + let mut dropped_coverage = Vec::new(); + for dead_block in basic_blocks.raw[first_dead_block..].iter() { + for statement in dead_block.statements.iter() { + if let StatementKind::Coverage(coverage) = &statement.kind { + if let Some(code_region) = &coverage.code_region { + dropped_coverage.push((statement.source_info, code_region.clone())); + } + } + } + } + + let start_block = &mut basic_blocks[START_BLOCK]; + for (source_info, code_region) in dropped_coverage { + start_block.statements.push(Statement { + source_info, + kind: StatementKind::Coverage(Box::new(Coverage { + kind: CoverageKind::Unreachable, + code_region: Some(code_region), + })), + }) + } +} + +pub struct SimplifyLocals; + +impl<'tcx> MirPass<'tcx> for SimplifyLocals { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("running SimplifyLocals on {:?}", body.source); + simplify_locals(body, tcx); + } +} + +pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { + // First, we're going to get a count of *actual* uses for every `Local`. + let mut used_locals = UsedLocals::new(body); + + // Next, we're going to remove any `Local` with zero actual uses. When we remove those + // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` + // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from + // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a + // fixedpoint where there are no more unused locals. + remove_unused_definitions(&mut used_locals, body); + + // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. + let map = make_local_map(&mut body.local_decls, &used_locals); + + // Only bother running the `LocalUpdater` if we actually found locals to remove. + if map.iter().any(Option::is_none) { + // Update references to all vars and tmps now + let mut updater = LocalUpdater { map, tcx }; + updater.visit_body(body); + + body.local_decls.shrink_to_fit(); + } +} + +/// Construct the mapping while swapping out unused stuff out from the `vec`. +fn make_local_map( + local_decls: &mut IndexVec, + used_locals: &UsedLocals, +) -> IndexVec> { + let mut map: IndexVec> = IndexVec::from_elem(None, &*local_decls); + let mut used = Local::new(0); + + for alive_index in local_decls.indices() { + // `is_used` treats the `RETURN_PLACE` and arguments as used. + if !used_locals.is_used(alive_index) { + continue; + } + + map[alive_index] = Some(used); + if alive_index != used { + local_decls.swap(alive_index, used); + } + used.increment_by(1); + } + local_decls.truncate(used.index()); + map +} + +/// Keeps track of used & unused locals. +struct UsedLocals { + increment: bool, + arg_count: u32, + use_count: IndexVec, +} + +impl UsedLocals { + /// Determines which locals are used & unused in the given body. + fn new(body: &Body<'_>) -> Self { + let mut this = Self { + increment: true, + arg_count: body.arg_count.try_into().unwrap(), + use_count: IndexVec::from_elem(0, &body.local_decls), + }; + this.visit_body(body); + this + } + + /// Checks if local is used. + /// + /// Return place and arguments are always considered used. + fn is_used(&self, local: Local) -> bool { + trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]); + local.as_u32() <= self.arg_count || self.use_count[local] != 0 + } + + /// Updates the use counts to reflect the removal of given statement. + fn statement_removed(&mut self, statement: &Statement<'tcx>) { + self.increment = false; + + // The location of the statement is irrelevant. + let location = Location { block: START_BLOCK, statement_index: 0 }; + self.visit_statement(statement, location); + } + + /// Visits a left-hand side of an assignment. + fn visit_lhs(&mut self, place: &Place<'tcx>, location: Location) { + if place.is_indirect() { + // A use, not a definition. + self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location); + } else { + // A definition. The base local itself is not visited, so this occurrence is not counted + // toward its use count. There might be other locals still, used in an indexing + // projection. + self.super_projection( + place.as_ref(), + PlaceContext::MutatingUse(MutatingUseContext::Projection), + location, + ); + } + } +} + +impl Visitor<'_> for UsedLocals { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + match statement.kind { + StatementKind::LlvmInlineAsm(..) + | StatementKind::CopyNonOverlapping(..) + | StatementKind::Retag(..) + | StatementKind::Coverage(..) + | StatementKind::FakeRead(..) + | StatementKind::AscribeUserType(..) => { + self.super_statement(statement, location); + } + + StatementKind::Nop => {} + + StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {} + + StatementKind::Assign(box (ref place, ref rvalue)) => { + self.visit_lhs(place, location); + self.visit_rvalue(rvalue, location); + } + + StatementKind::SetDiscriminant { ref place, variant_index: _ } => { + self.visit_lhs(place, location); + } + } + } + + fn visit_local(&mut self, local: &Local, _ctx: PlaceContext, _location: Location) { + if self.increment { + self.use_count[*local] += 1; + } else { + assert_ne!(self.use_count[*local], 0); + self.use_count[*local] -= 1; + } + } +} + +/// Removes unused definitions. Updates the used locals to reflect the changes made. +fn remove_unused_definitions<'a, 'tcx>(used_locals: &'a mut UsedLocals, body: &mut Body<'tcx>) { + // The use counts are updated as we remove the statements. A local might become unused + // during the retain operation, leading to a temporary inconsistency (storage statements or + // definitions referencing the local might remain). For correctness it is crucial that this + // computation reaches a fixed point. + + let mut modified = true; + while modified { + modified = false; + + for data in body.basic_blocks_mut() { + // Remove unnecessary StorageLive and StorageDead annotations. + data.statements.retain(|statement| { + let keep = match &statement.kind { + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + used_locals.is_used(*local) + } + StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local), + + StatementKind::SetDiscriminant { ref place, .. } => { + used_locals.is_used(place.local) + } + _ => true, + }; + + if !keep { + trace!("removing statement {:?}", statement); + modified = true; + used_locals.statement_removed(statement); + } + + keep + }); + } + } +} + +struct LocalUpdater<'tcx> { + map: IndexVec>, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { + *l = self.map[*l].unwrap(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_try.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_try.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_try.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/simplify_try.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,821 @@ +//! The general point of the optimizations provided here is to simplify something like: +//! +//! ```rust +//! match x { +//! Ok(x) => Ok(x), +//! Err(x) => Err(x) +//! } +//! ``` +//! +//! into just `x`. + +use crate::{simplify, MirPass}; +use itertools::Itertools as _; +use rustc_index::{bit_set::BitSet, vec::IndexVec}; +use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, List, Ty, TyCtxt}; +use rustc_target::abi::VariantIdx; +use std::iter::{once, Enumerate, Peekable}; +use std::slice::Iter; + +/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move. +/// +/// This is done by transforming basic blocks where the statements match: +/// +/// ```rust +/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY ); +/// _TMP_2 = _LOCAL_TMP; +/// ((_LOCAL_0 as Variant).FIELD: TY) = move _TMP_2; +/// discriminant(_LOCAL_0) = VAR_IDX; +/// ``` +/// +/// into: +/// +/// ```rust +/// _LOCAL_0 = move _LOCAL_1 +/// ``` +pub struct SimplifyArmIdentity; + +#[derive(Debug)] +struct ArmIdentityInfo<'tcx> { + /// Storage location for the variant's field + local_temp_0: Local, + /// Storage location holding the variant being read from + local_1: Local, + /// The variant field being read from + vf_s0: VarField<'tcx>, + /// Index of the statement which loads the variant being read + get_variant_field_stmt: usize, + + /// Tracks each assignment to a temporary of the variant's field + field_tmp_assignments: Vec<(Local, Local)>, + + /// Storage location holding the variant's field that was read from + local_tmp_s1: Local, + /// Storage location holding the enum that we are writing to + local_0: Local, + /// The variant field being written to + vf_s1: VarField<'tcx>, + + /// Storage location that the discriminant is being written to + set_discr_local: Local, + /// The variant being written + set_discr_var_idx: VariantIdx, + + /// Index of the statement that should be overwritten as a move + stmt_to_overwrite: usize, + /// SourceInfo for the new move + source_info: SourceInfo, + + /// Indices of matching Storage{Live,Dead} statements encountered. + /// (StorageLive index,, StorageDead index, Local) + storage_stmts: Vec<(usize, usize, Local)>, + + /// The statements that should be removed (turned into nops) + stmts_to_remove: Vec, + + /// Indices of debug variables that need to be adjusted to point to + // `{local_0}.{dbg_projection}`. + dbg_info_to_adjust: Vec, + + /// The projection used to rewrite debug info. + dbg_projection: &'tcx List>, +} + +fn get_arm_identity_info<'a, 'tcx>( + stmts: &'a [Statement<'tcx>], + locals_count: usize, + debug_info: &'a [VarDebugInfo<'tcx>], +) -> Option> { + // This can't possibly match unless there are at least 3 statements in the block + // so fail fast on tiny blocks. + if stmts.len() < 3 { + return None; + } + + let mut tmp_assigns = Vec::new(); + let mut nop_stmts = Vec::new(); + let mut storage_stmts = Vec::new(); + let mut storage_live_stmts = Vec::new(); + let mut storage_dead_stmts = Vec::new(); + + type StmtIter<'a, 'tcx> = Peekable>>>; + + fn is_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool { + matches!(stmt.kind, StatementKind::StorageLive(_) | StatementKind::StorageDead(_)) + } + + /// Eats consecutive Statements which match `test`, performing the specified `action` for each. + /// The iterator `stmt_iter` is not advanced if none were matched. + fn try_eat<'a, 'tcx>( + stmt_iter: &mut StmtIter<'a, 'tcx>, + test: impl Fn(&'a Statement<'tcx>) -> bool, + mut action: impl FnMut(usize, &'a Statement<'tcx>), + ) { + while stmt_iter.peek().map_or(false, |(_, stmt)| test(stmt)) { + let (idx, stmt) = stmt_iter.next().unwrap(); + + action(idx, stmt); + } + } + + /// Eats consecutive `StorageLive` and `StorageDead` Statements. + /// The iterator `stmt_iter` is not advanced if none were found. + fn try_eat_storage_stmts<'a, 'tcx>( + stmt_iter: &mut StmtIter<'a, 'tcx>, + storage_live_stmts: &mut Vec<(usize, Local)>, + storage_dead_stmts: &mut Vec<(usize, Local)>, + ) { + try_eat(stmt_iter, is_storage_stmt, |idx, stmt| { + if let StatementKind::StorageLive(l) = stmt.kind { + storage_live_stmts.push((idx, l)); + } else if let StatementKind::StorageDead(l) = stmt.kind { + storage_dead_stmts.push((idx, l)); + } + }) + } + + fn is_tmp_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool { + use rustc_middle::mir::StatementKind::Assign; + if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = &stmt.kind { + place.as_local().is_some() && p.as_local().is_some() + } else { + false + } + } + + /// Eats consecutive `Assign` Statements. + // The iterator `stmt_iter` is not advanced if none were found. + fn try_eat_assign_tmp_stmts<'a, 'tcx>( + stmt_iter: &mut StmtIter<'a, 'tcx>, + tmp_assigns: &mut Vec<(Local, Local)>, + nop_stmts: &mut Vec, + ) { + try_eat(stmt_iter, is_tmp_storage_stmt, |idx, stmt| { + use rustc_middle::mir::StatementKind::Assign; + if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = + &stmt.kind + { + tmp_assigns.push((place.as_local().unwrap(), p.as_local().unwrap())); + nop_stmts.push(idx); + } + }) + } + + fn find_storage_live_dead_stmts_for_local<'tcx>( + local: Local, + stmts: &[Statement<'tcx>], + ) -> Option<(usize, usize)> { + trace!("looking for {:?}", local); + let mut storage_live_stmt = None; + let mut storage_dead_stmt = None; + for (idx, stmt) in stmts.iter().enumerate() { + if stmt.kind == StatementKind::StorageLive(local) { + storage_live_stmt = Some(idx); + } else if stmt.kind == StatementKind::StorageDead(local) { + storage_dead_stmt = Some(idx); + } + } + + Some((storage_live_stmt?, storage_dead_stmt.unwrap_or(usize::MAX))) + } + + // Try to match the expected MIR structure with the basic block we're processing. + // We want to see something that looks like: + // ``` + // (StorageLive(_) | StorageDead(_));* + // _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY); + // (StorageLive(_) | StorageDead(_));* + // (tmp_n+1 = tmp_n);* + // (StorageLive(_) | StorageDead(_));* + // (tmp_n+1 = tmp_n);* + // ((LOCAL_FROM as Variant).FIELD: TY) = move tmp; + // discriminant(LOCAL_FROM) = VariantIdx; + // (StorageLive(_) | StorageDead(_));* + // ``` + let mut stmt_iter = stmts.iter().enumerate().peekable(); + + try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); + + let (get_variant_field_stmt, stmt) = stmt_iter.next()?; + let (local_tmp_s0, local_1, vf_s0, dbg_projection) = match_get_variant_field(stmt)?; + + try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); + + try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts); + + try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); + + try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts); + + let (idx, stmt) = stmt_iter.next()?; + let (local_tmp_s1, local_0, vf_s1) = match_set_variant_field(stmt)?; + nop_stmts.push(idx); + + let (idx, stmt) = stmt_iter.next()?; + let (set_discr_local, set_discr_var_idx) = match_set_discr(stmt)?; + let discr_stmt_source_info = stmt.source_info; + nop_stmts.push(idx); + + try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); + + for (live_idx, live_local) in storage_live_stmts { + if let Some(i) = storage_dead_stmts.iter().rposition(|(_, l)| *l == live_local) { + let (dead_idx, _) = storage_dead_stmts.swap_remove(i); + storage_stmts.push((live_idx, dead_idx, live_local)); + + if live_local == local_tmp_s0 { + nop_stmts.push(get_variant_field_stmt); + } + } + } + // We sort primitive usize here so we can use unstable sort + nop_stmts.sort_unstable(); + + // Use one of the statements we're going to discard between the point + // where the storage location for the variant field becomes live and + // is killed. + let (live_idx, dead_idx) = find_storage_live_dead_stmts_for_local(local_tmp_s0, stmts)?; + let stmt_to_overwrite = + nop_stmts.iter().find(|stmt_idx| live_idx < **stmt_idx && **stmt_idx < dead_idx); + + let mut tmp_assigned_vars = BitSet::new_empty(locals_count); + for (l, r) in &tmp_assigns { + tmp_assigned_vars.insert(*l); + tmp_assigned_vars.insert(*r); + } + + let dbg_info_to_adjust: Vec<_> = debug_info + .iter() + .enumerate() + .filter_map(|(i, var_info)| { + if let VarDebugInfoContents::Place(p) = var_info.value { + if tmp_assigned_vars.contains(p.local) { + return Some(i); + } + } + + None + }) + .collect(); + + Some(ArmIdentityInfo { + local_temp_0: local_tmp_s0, + local_1, + vf_s0, + get_variant_field_stmt, + field_tmp_assignments: tmp_assigns, + local_tmp_s1, + local_0, + vf_s1, + set_discr_local, + set_discr_var_idx, + stmt_to_overwrite: *stmt_to_overwrite?, + source_info: discr_stmt_source_info, + storage_stmts, + stmts_to_remove: nop_stmts, + dbg_info_to_adjust, + dbg_projection, + }) +} + +fn optimization_applies<'tcx>( + opt_info: &ArmIdentityInfo<'tcx>, + local_decls: &IndexVec>, + local_uses: &IndexVec, + var_debug_info: &[VarDebugInfo<'tcx>], +) -> bool { + trace!("testing if optimization applies..."); + + // FIXME(wesleywiser): possibly relax this restriction? + if opt_info.local_0 == opt_info.local_1 { + trace!("NO: moving into ourselves"); + return false; + } else if opt_info.vf_s0 != opt_info.vf_s1 { + trace!("NO: the field-and-variant information do not match"); + return false; + } else if local_decls[opt_info.local_0].ty != local_decls[opt_info.local_1].ty { + // FIXME(Centril,oli-obk): possibly relax to same layout? + trace!("NO: source and target locals have different types"); + return false; + } else if (opt_info.local_0, opt_info.vf_s0.var_idx) + != (opt_info.set_discr_local, opt_info.set_discr_var_idx) + { + trace!("NO: the discriminants do not match"); + return false; + } + + // Verify the assignment chain consists of the form b = a; c = b; d = c; etc... + if opt_info.field_tmp_assignments.is_empty() { + trace!("NO: no assignments found"); + return false; + } + let mut last_assigned_to = opt_info.field_tmp_assignments[0].1; + let source_local = last_assigned_to; + for (l, r) in &opt_info.field_tmp_assignments { + if *r != last_assigned_to { + trace!("NO: found unexpected assignment {:?} = {:?}", l, r); + return false; + } + + last_assigned_to = *l; + } + + // Check that the first and last used locals are only used twice + // since they are of the form: + // + // ``` + // _first = ((_x as Variant).n: ty); + // _n = _first; + // ... + // ((_y as Variant).n: ty) = _n; + // discriminant(_y) = z; + // ``` + for (l, r) in &opt_info.field_tmp_assignments { + if local_uses[*l] != 2 { + warn!("NO: FAILED assignment chain local {:?} was used more than twice", l); + return false; + } else if local_uses[*r] != 2 { + warn!("NO: FAILED assignment chain local {:?} was used more than twice", r); + return false; + } + } + + // Check that debug info only points to full Locals and not projections. + for dbg_idx in &opt_info.dbg_info_to_adjust { + let dbg_info = &var_debug_info[*dbg_idx]; + if let VarDebugInfoContents::Place(p) = dbg_info.value { + if !p.projection.is_empty() { + trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, p); + return false; + } + } + } + + if source_local != opt_info.local_temp_0 { + trace!( + "NO: start of assignment chain does not match enum variant temp: {:?} != {:?}", + source_local, + opt_info.local_temp_0 + ); + return false; + } else if last_assigned_to != opt_info.local_tmp_s1 { + trace!( + "NO: end of assignemnt chain does not match written enum temp: {:?} != {:?}", + last_assigned_to, + opt_info.local_tmp_s1 + ); + return false; + } + + trace!("SUCCESS: optimization applies!"); + true +} + +impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // FIXME(77359): This optimization can result in unsoundness. + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + + let source = body.source; + trace!("running SimplifyArmIdentity on {:?}", source); + + let local_uses = LocalUseCounter::get_local_uses(body); + let (basic_blocks, local_decls, debug_info) = + body.basic_blocks_local_decls_mut_and_var_debug_info(); + for bb in basic_blocks { + if let Some(opt_info) = + get_arm_identity_info(&bb.statements, local_decls.len(), debug_info) + { + trace!("got opt_info = {:#?}", opt_info); + if !optimization_applies(&opt_info, local_decls, &local_uses, &debug_info) { + debug!("optimization skipped for {:?}", source); + continue; + } + + // Also remove unused Storage{Live,Dead} statements which correspond + // to temps used previously. + for (live_idx, dead_idx, local) in &opt_info.storage_stmts { + // The temporary that we've read the variant field into is scoped to this block, + // so we can remove the assignment. + if *local == opt_info.local_temp_0 { + bb.statements[opt_info.get_variant_field_stmt].make_nop(); + } + + for (left, right) in &opt_info.field_tmp_assignments { + if local == left || local == right { + bb.statements[*live_idx].make_nop(); + bb.statements[*dead_idx].make_nop(); + } + } + } + + // Right shape; transform + for stmt_idx in opt_info.stmts_to_remove { + bb.statements[stmt_idx].make_nop(); + } + + let stmt = &mut bb.statements[opt_info.stmt_to_overwrite]; + stmt.source_info = opt_info.source_info; + stmt.kind = StatementKind::Assign(Box::new(( + opt_info.local_0.into(), + Rvalue::Use(Operand::Move(opt_info.local_1.into())), + ))); + + bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop); + + // Fix the debug info to point to the right local + for dbg_index in opt_info.dbg_info_to_adjust { + let dbg_info = &mut debug_info[dbg_index]; + assert!( + matches!(dbg_info.value, VarDebugInfoContents::Place(_)), + "value was not a Place" + ); + if let VarDebugInfoContents::Place(p) = &mut dbg_info.value { + assert!(p.projection.is_empty()); + p.local = opt_info.local_0; + p.projection = opt_info.dbg_projection; + } + } + + trace!("block is now {:?}", bb.statements); + } + } + } +} + +struct LocalUseCounter { + local_uses: IndexVec, +} + +impl LocalUseCounter { + fn get_local_uses<'tcx>(body: &Body<'tcx>) -> IndexVec { + let mut counter = LocalUseCounter { local_uses: IndexVec::from_elem(0, &body.local_decls) }; + counter.visit_body(body); + counter.local_uses + } +} + +impl<'tcx> Visitor<'tcx> for LocalUseCounter { + fn visit_local(&mut self, local: &Local, context: PlaceContext, _location: Location) { + if context.is_storage_marker() + || context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) + { + return; + } + + self.local_uses[*local] += 1; + } +} + +/// Match on: +/// ```rust +/// _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY); +/// ``` +fn match_get_variant_field<'tcx>( + stmt: &Statement<'tcx>, +) -> Option<(Local, Local, VarField<'tcx>, &'tcx List>)> { + match &stmt.kind { + StatementKind::Assign(box ( + place_into, + Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)), + )) => { + let local_into = place_into.as_local()?; + let (local_from, vf) = match_variant_field_place(*pf)?; + Some((local_into, local_from, vf, pf.projection)) + } + _ => None, + } +} + +/// Match on: +/// ```rust +/// ((_LOCAL_FROM as Variant).FIELD: TY) = move _LOCAL_INTO; +/// ``` +fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> { + match &stmt.kind { + StatementKind::Assign(box (place_from, Rvalue::Use(Operand::Move(place_into)))) => { + let local_into = place_into.as_local()?; + let (local_from, vf) = match_variant_field_place(*place_from)?; + Some((local_into, local_from, vf)) + } + _ => None, + } +} + +/// Match on: +/// ```rust +/// discriminant(_LOCAL_TO_SET) = VAR_IDX; +/// ``` +fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)> { + match &stmt.kind { + StatementKind::SetDiscriminant { place, variant_index } => { + Some((place.as_local()?, *variant_index)) + } + _ => None, + } +} + +#[derive(PartialEq, Debug)] +struct VarField<'tcx> { + field: Field, + field_ty: Ty<'tcx>, + var_idx: VariantIdx, +} + +/// Match on `((_LOCAL as Variant).FIELD: TY)`. +fn match_variant_field_place<'tcx>(place: Place<'tcx>) -> Option<(Local, VarField<'tcx>)> { + match place.as_ref() { + PlaceRef { + local, + projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)], + } => Some((local, VarField { field, field_ty: ty, var_idx })), + _ => None, + } +} + +/// Simplifies `SwitchInt(_) -> [targets]`, +/// where all the `targets` have the same form, +/// into `goto -> target_first`. +pub struct SimplifyBranchSame; + +impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // This optimization is disabled by default for now due to + // soundness concerns; see issue #89485 and PR #89489. + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + + trace!("Running SimplifyBranchSame on {:?}", body.source); + let finder = SimplifyBranchSameOptimizationFinder { body, tcx }; + let opts = finder.find(); + + let did_remove_blocks = opts.len() > 0; + for opt in opts.iter() { + trace!("SUCCESS: Applying optimization {:?}", opt); + // Replace `SwitchInt(..) -> [bb_first, ..];` with a `goto -> bb_first;`. + body.basic_blocks_mut()[opt.bb_to_opt_terminator].terminator_mut().kind = + TerminatorKind::Goto { target: opt.bb_to_goto }; + } + + if did_remove_blocks { + // We have dead blocks now, so remove those. + simplify::remove_dead_blocks(tcx, body); + } + } +} + +#[derive(Debug)] +struct SimplifyBranchSameOptimization { + /// All basic blocks are equal so go to this one + bb_to_goto: BasicBlock, + /// Basic block where the terminator can be simplified to a goto + bb_to_opt_terminator: BasicBlock, +} + +struct SwitchTargetAndValue { + target: BasicBlock, + // None in case of the `otherwise` case + value: Option, +} + +struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, +} + +impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { + fn find(&self) -> Vec { + self.body + .basic_blocks() + .iter_enumerated() + .filter_map(|(bb_idx, bb)| { + let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { + TerminatorKind::SwitchInt { targets, discr, .. } => { + let targets_and_values: Vec<_> = targets.iter() + .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) }) + .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None })) + .collect(); + (discr, targets_and_values) + }, + _ => return None, + }; + + // find the adt that has its discriminant read + // assuming this must be the last statement of the block + let adt_matched_on = match &bb.statements.last()?.kind { + StatementKind::Assign(box (place, rhs)) + if Some(*place) == discr_switched_on.place() => + { + match rhs { + Rvalue::Discriminant(adt_place) if adt_place.ty(self.body, self.tcx).ty.is_enum() => adt_place, + _ => { + trace!("NO: expected a discriminant read of an enum instead of: {:?}", rhs); + return None; + } + } + } + other => { + trace!("NO: expected an assignment of a discriminant read to a place. Found: {:?}", other); + return None + }, + }; + + let mut iter_bbs_reachable = targets_and_values + .iter() + .map(|target_and_value| (target_and_value, &self.body.basic_blocks()[target_and_value.target])) + .filter(|(_, bb)| { + // Reaching `unreachable` is UB so assume it doesn't happen. + bb.terminator().kind != TerminatorKind::Unreachable + // But `asm!(...)` could abort the program, + // so we cannot assume that the `unreachable` terminator itself is reachable. + // FIXME(Centril): use a normalization pass instead of a check. + || bb.statements.iter().any(|stmt| matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))) + }) + .peekable(); + + let bb_first = iter_bbs_reachable.peek().map_or(&targets_and_values[0], |(idx, _)| *idx); + let mut all_successors_equivalent = StatementEquality::TrivialEqual; + + // All successor basic blocks must be equal or contain statements that are pairwise considered equal. + for ((target_and_value_l,bb_l), (target_and_value_r,bb_r)) in iter_bbs_reachable.tuple_windows() { + let trivial_checks = bb_l.is_cleanup == bb_r.is_cleanup + && bb_l.terminator().kind == bb_r.terminator().kind + && bb_l.statements.len() == bb_r.statements.len(); + let statement_check = || { + bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| { + let stmt_equality = self.statement_equality(*adt_matched_on, &l, target_and_value_l, &r, target_and_value_r); + if matches!(stmt_equality, StatementEquality::NotEqual) { + // short circuit + None + } else { + Some(acc.combine(&stmt_equality)) + } + }) + .unwrap_or(StatementEquality::NotEqual) + }; + if !trivial_checks { + all_successors_equivalent = StatementEquality::NotEqual; + break; + } + all_successors_equivalent = all_successors_equivalent.combine(&statement_check()); + }; + + match all_successors_equivalent{ + StatementEquality::TrivialEqual => { + // statements are trivially equal, so just take first + trace!("Statements are trivially equal"); + Some(SimplifyBranchSameOptimization { + bb_to_goto: bb_first.target, + bb_to_opt_terminator: bb_idx, + }) + } + StatementEquality::ConsideredEqual(bb_to_choose) => { + trace!("Statements are considered equal"); + Some(SimplifyBranchSameOptimization { + bb_to_goto: bb_to_choose, + bb_to_opt_terminator: bb_idx, + }) + } + StatementEquality::NotEqual => { + trace!("NO: not all successors of basic block {:?} were equivalent", bb_idx); + None + } + } + }) + .collect() + } + + /// Tests if two statements can be considered equal + /// + /// Statements can be trivially equal if the kinds match. + /// But they can also be considered equal in the following case A: + /// ``` + /// discriminant(_0) = 0; // bb1 + /// _0 = move _1; // bb2 + /// ``` + /// In this case the two statements are equal iff + /// - `_0` is an enum where the variant index 0 is fieldless, and + /// - bb1 was targeted by a switch where the discriminant of `_1` was switched on + fn statement_equality( + &self, + adt_matched_on: Place<'tcx>, + x: &Statement<'tcx>, + x_target_and_value: &SwitchTargetAndValue, + y: &Statement<'tcx>, + y_target_and_value: &SwitchTargetAndValue, + ) -> StatementEquality { + let helper = |rhs: &Rvalue<'tcx>, + place: &Place<'tcx>, + variant_index: &VariantIdx, + switch_value: u128, + side_to_choose| { + let place_type = place.ty(self.body, self.tcx).ty; + let adt = match *place_type.kind() { + ty::Adt(adt, _) if adt.is_enum() => adt, + _ => return StatementEquality::NotEqual, + }; + // We need to make sure that the switch value that targets the bb with + // SetDiscriminant is the same as the variant discriminant. + let variant_discr = adt.discriminant_for_variant(self.tcx, *variant_index).val; + if variant_discr != switch_value { + trace!( + "NO: variant discriminant {} does not equal switch value {}", + variant_discr, + switch_value + ); + return StatementEquality::NotEqual; + } + let variant_is_fieldless = adt.variants[*variant_index].fields.is_empty(); + if !variant_is_fieldless { + trace!("NO: variant {:?} was not fieldless", variant_index); + return StatementEquality::NotEqual; + } + + match rhs { + Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => { + StatementEquality::ConsideredEqual(side_to_choose) + } + _ => { + trace!( + "NO: RHS of assignment was {:?}, but expected it to match the adt being matched on in the switch, which is {:?}", + rhs, + adt_matched_on + ); + StatementEquality::NotEqual + } + } + }; + match (&x.kind, &y.kind) { + // trivial case + (x, y) if x == y => StatementEquality::TrivialEqual, + + // check for case A + ( + StatementKind::Assign(box (_, rhs)), + StatementKind::SetDiscriminant { place, variant_index }, + ) if y_target_and_value.value.is_some() => { + // choose basic block of x, as that has the assign + helper( + rhs, + place, + variant_index, + y_target_and_value.value.unwrap(), + x_target_and_value.target, + ) + } + ( + StatementKind::SetDiscriminant { place, variant_index }, + StatementKind::Assign(box (_, rhs)), + ) if x_target_and_value.value.is_some() => { + // choose basic block of y, as that has the assign + helper( + rhs, + place, + variant_index, + x_target_and_value.value.unwrap(), + y_target_and_value.target, + ) + } + _ => { + trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y); + StatementEquality::NotEqual + } + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +enum StatementEquality { + /// The two statements are trivially equal; same kind + TrivialEqual, + /// The two statements are considered equal, but may be of different kinds. The BasicBlock field is the basic block to jump to when performing the branch-same optimization. + /// For example, `_0 = _1` and `discriminant(_0) = discriminant(0)` are considered equal if 0 is a fieldless variant of an enum. But we don't want to jump to the basic block with the SetDiscriminant, as that is not legal if _1 is not the 0 variant index + ConsideredEqual(BasicBlock), + /// The two statements are not equal + NotEqual, +} + +impl StatementEquality { + fn combine(&self, other: &StatementEquality) -> StatementEquality { + use StatementEquality::*; + match (self, other) { + (TrivialEqual, TrivialEqual) => TrivialEqual, + (TrivialEqual, ConsideredEqual(b)) | (ConsideredEqual(b), TrivialEqual) => { + ConsideredEqual(*b) + } + (ConsideredEqual(b1), ConsideredEqual(b2)) => { + if b1 == b2 { + ConsideredEqual(*b1) + } else { + NotEqual + } + } + (_, NotEqual) | (NotEqual, _) => NotEqual, + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,117 @@ +//! A pass that eliminates branches on uninhabited enum variants. + +use crate::MirPass; +use rustc_data_structures::stable_set::FxHashSet; +use rustc_middle::mir::{ + BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, + TerminatorKind, +}; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_target::abi::{Abi, Variants}; + +pub struct UninhabitedEnumBranching; + +fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option { + if let TerminatorKind::SwitchInt { discr: Operand::Move(p), .. } = terminator { + p.as_local() + } else { + None + } +} + +/// If the basic block terminates by switching on a discriminant, this returns the `Ty` the +/// discriminant is read from. Otherwise, returns None. +fn get_switched_on_type<'tcx>( + block_data: &BasicBlockData<'tcx>, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, +) -> Option> { + let terminator = block_data.terminator(); + + // Only bother checking blocks which terminate by switching on a local. + if let Some(local) = get_discriminant_local(&terminator.kind) { + let stmt_before_term = (!block_data.statements.is_empty()) + .then(|| &block_data.statements[block_data.statements.len() - 1].kind); + + if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term + { + if l.as_local() == Some(local) { + let ty = place.ty(body, tcx).ty; + if ty.is_enum() { + return Some(ty); + } + } + } + } + + None +} + +fn variant_discriminants<'tcx>( + layout: &TyAndLayout<'tcx>, + ty: Ty<'tcx>, + tcx: TyCtxt<'tcx>, +) -> FxHashSet { + match &layout.variants { + Variants::Single { index } => { + let mut res = FxHashSet::default(); + res.insert(index.as_u32() as u128); + res + } + Variants::Multiple { variants, .. } => variants + .iter_enumerated() + .filter_map(|(idx, layout)| { + (layout.abi != Abi::Uninhabited) + .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val) + }) + .collect(), + } +} + +impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if body.source.promoted.is_some() { + return; + } + + trace!("UninhabitedEnumBranching starting for {:?}", body.source); + + let basic_block_count = body.basic_blocks().len(); + + for bb in 0..basic_block_count { + let bb = BasicBlock::from_usize(bb); + trace!("processing block {:?}", bb); + + let discriminant_ty = + if let Some(ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) { + ty + } else { + continue; + }; + + let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty)); + + let allowed_variants = if let Ok(layout) = layout { + variant_discriminants(&layout, discriminant_ty, tcx) + } else { + continue; + }; + + trace!("allowed_variants = {:?}", allowed_variants); + + if let TerminatorKind::SwitchInt { targets, .. } = + &mut body.basic_blocks_mut()[bb].terminator_mut().kind + { + let new_targets = SwitchTargets::new( + targets.iter().filter(|(val, _)| allowed_variants.contains(val)), + targets.otherwise(), + ); + + *targets = new_targets; + } else { + unreachable!() + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/unreachable_prop.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/unreachable_prop.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_mir_transform/src/unreachable_prop.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_mir_transform/src/unreachable_prop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,112 @@ +//! A pass that propagates the unreachable terminator of a block to its predecessors +//! when all of their successors are unreachable. This is achieved through a +//! post-order traversal of the blocks. + +use crate::simplify; +use crate::MirPass; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct UnreachablePropagation; + +impl MirPass<'_> for UnreachablePropagation { + fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.mir_opt_level() < 4 { + // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt + // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code. + return; + } + + let mut unreachable_blocks = FxHashSet::default(); + let mut replacements = FxHashMap::default(); + + for (bb, bb_data) in traversal::postorder(body) { + let terminator = bb_data.terminator(); + // HACK: If the block contains any asm statement it is not regarded as unreachable. + // This is a temporary solution that handles possibly diverging asm statements. + // Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs + let asm_stmt_in_block = || { + bb_data.statements.iter().any(|stmt: &Statement<'_>| match stmt.kind { + StatementKind::LlvmInlineAsm(..) => true, + _ => false, + }) + }; + + if terminator.kind == TerminatorKind::Unreachable && !asm_stmt_in_block() { + unreachable_blocks.insert(bb); + } else { + let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ); + let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable); + + if let Some(terminator_kind) = terminator_kind_opt { + if terminator_kind == TerminatorKind::Unreachable && !asm_stmt_in_block() { + unreachable_blocks.insert(bb); + } + replacements.insert(bb, terminator_kind); + } + } + } + + let replaced = !replacements.is_empty(); + for (bb, terminator_kind) in replacements { + if !tcx.consider_optimizing(|| { + format!("UnreachablePropagation {:?} ", body.source.def_id()) + }) { + break; + } + + body.basic_blocks_mut()[bb].terminator_mut().kind = terminator_kind; + } + + if replaced { + simplify::remove_dead_blocks(tcx, body); + } + } +} + +fn remove_successors( + terminator_kind: &TerminatorKind<'tcx>, + predicate: F, +) -> Option> +where + F: Fn(BasicBlock) -> bool, +{ + let terminator = match *terminator_kind { + TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable, + TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => { + let otherwise = targets.otherwise(); + + let original_targets_len = targets.iter().len() + 1; + let (mut values, mut targets): (Vec<_>, Vec<_>) = + targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip(); + + if !predicate(otherwise) { + targets.push(otherwise); + } else { + values.pop(); + } + + let retained_targets_len = targets.len(); + + if targets.is_empty() { + TerminatorKind::Unreachable + } else if targets.len() == 1 { + TerminatorKind::Goto { target: targets[0] } + } else if original_targets_len != retained_targets_len { + TerminatorKind::SwitchInt { + discr: discr.clone(), + switch_ty, + targets: SwitchTargets::new( + values.iter().copied().zip(targets.iter().copied()), + *targets.last().unwrap(), + ), + } + } else { + return None; + } + } + _ => return None, + }; + Some(terminator) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +[package] +name = "rustc_monomorphize" +version = "0.0.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +tracing = "0.1" +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_middle = { path = "../rustc_middle" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/collector.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/collector.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/collector.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/collector.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1406 @@ +//! Mono Item Collection +//! ==================== +//! +//! This module is responsible for discovering all items that will contribute +//! to code generation of the crate. The important part here is that it not only +//! needs to find syntax-level items (functions, structs, etc) but also all +//! their monomorphized instantiations. Every non-generic, non-const function +//! maps to one LLVM artifact. Every generic function can produce +//! from zero to N artifacts, depending on the sets of type arguments it +//! is instantiated with. +//! This also applies to generic items from other crates: A generic definition +//! in crate X might produce monomorphizations that are compiled into crate Y. +//! We also have to collect these here. +//! +//! The following kinds of "mono items" are handled here: +//! +//! - Functions +//! - Methods +//! - Closures +//! - Statics +//! - Drop glue +//! +//! The following things also result in LLVM artifacts, but are not collected +//! here, since we instantiate them locally on demand when needed in a given +//! codegen unit: +//! +//! - Constants +//! - Vtables +//! - Object Shims +//! +//! +//! General Algorithm +//! ----------------- +//! Let's define some terms first: +//! +//! - A "mono item" is something that results in a function or global in +//! the LLVM IR of a codegen unit. Mono items do not stand on their +//! own, they can reference other mono items. For example, if function +//! `foo()` calls function `bar()` then the mono item for `foo()` +//! references the mono item for function `bar()`. In general, the +//! definition for mono item A referencing a mono item B is that +//! the LLVM artifact produced for A references the LLVM artifact produced +//! for B. +//! +//! - Mono items and the references between them form a directed graph, +//! where the mono items are the nodes and references form the edges. +//! Let's call this graph the "mono item graph". +//! +//! - The mono item graph for a program contains all mono items +//! that are needed in order to produce the complete LLVM IR of the program. +//! +//! The purpose of the algorithm implemented in this module is to build the +//! mono item graph for the current crate. It runs in two phases: +//! +//! 1. Discover the roots of the graph by traversing the HIR of the crate. +//! 2. Starting from the roots, find neighboring nodes by inspecting the MIR +//! representation of the item corresponding to a given node, until no more +//! new nodes are found. +//! +//! ### Discovering roots +//! +//! The roots of the mono item graph correspond to the public non-generic +//! syntactic items in the source code. We find them by walking the HIR of the +//! crate, and whenever we hit upon a public function, method, or static item, +//! we create a mono item consisting of the items DefId and, since we only +//! consider non-generic items, an empty type-substitution set. (In eager +//! collection mode, during incremental compilation, all non-generic functions +//! are considered as roots, as well as when the `-Clink-dead-code` option is +//! specified. Functions marked `#[no_mangle]` and functions called by inlinable +//! functions also always act as roots.) +//! +//! ### Finding neighbor nodes +//! Given a mono item node, we can discover neighbors by inspecting its +//! MIR. We walk the MIR and any time we hit upon something that signifies a +//! reference to another mono item, we have found a neighbor. Since the +//! mono item we are currently at is always monomorphic, we also know the +//! concrete type arguments of its neighbors, and so all neighbors again will be +//! monomorphic. The specific forms a reference to a neighboring node can take +//! in MIR are quite diverse. Here is an overview: +//! +//! #### Calling Functions/Methods +//! The most obvious form of one mono item referencing another is a +//! function or method call (represented by a CALL terminator in MIR). But +//! calls are not the only thing that might introduce a reference between two +//! function mono items, and as we will see below, they are just a +//! specialization of the form described next, and consequently will not get any +//! special treatment in the algorithm. +//! +//! #### Taking a reference to a function or method +//! A function does not need to actually be called in order to be a neighbor of +//! another function. It suffices to just take a reference in order to introduce +//! an edge. Consider the following example: +//! +//! ```rust +//! fn print_val(x: T) { +//! println!("{}", x); +//! } +//! +//! fn call_fn(f: &Fn(i32), x: i32) { +//! f(x); +//! } +//! +//! fn main() { +//! let print_i32 = print_val::; +//! call_fn(&print_i32, 0); +//! } +//! ``` +//! The MIR of none of these functions will contain an explicit call to +//! `print_val::`. Nonetheless, in order to mono this program, we need +//! an instance of this function. Thus, whenever we encounter a function or +//! method in operand position, we treat it as a neighbor of the current +//! mono item. Calls are just a special case of that. +//! +//! #### Closures +//! In a way, closures are a simple case. Since every closure object needs to be +//! constructed somewhere, we can reliably discover them by observing +//! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also +//! true for closures inlined from other crates. +//! +//! #### Drop glue +//! Drop glue mono items are introduced by MIR drop-statements. The +//! generated mono item will again have drop-glue item neighbors if the +//! type to be dropped contains nested values that also need to be dropped. It +//! might also have a function item neighbor for the explicit `Drop::drop` +//! implementation of its type. +//! +//! #### Unsizing Casts +//! A subtle way of introducing neighbor edges is by casting to a trait object. +//! Since the resulting fat-pointer contains a reference to a vtable, we need to +//! instantiate all object-save methods of the trait, as we need to store +//! pointers to these functions even if they never get called anywhere. This can +//! be seen as a special case of taking a function reference. +//! +//! #### Boxes +//! Since `Box` expression have special compiler support, no explicit calls to +//! `exchange_malloc()` and `box_free()` may show up in MIR, even if the +//! compiler will generate them. We have to observe `Rvalue::Box` expressions +//! and Box-typed drop-statements for that purpose. +//! +//! +//! Interaction with Cross-Crate Inlining +//! ------------------------------------- +//! The binary of a crate will not only contain machine code for the items +//! defined in the source code of that crate. It will also contain monomorphic +//! instantiations of any extern generic functions and of functions marked with +//! `#[inline]`. +//! The collection algorithm handles this more or less mono. If it is +//! about to create a mono item for something with an external `DefId`, +//! it will take a look if the MIR for that item is available, and if so just +//! proceed normally. If the MIR is not available, it assumes that the item is +//! just linked to and no node is created; which is exactly what we want, since +//! no machine code should be generated in the current crate for such an item. +//! +//! Eager and Lazy Collection Mode +//! ------------------------------ +//! Mono item collection can be performed in one of two modes: +//! +//! - Lazy mode means that items will only be instantiated when actually +//! referenced. The goal is to produce the least amount of machine code +//! possible. +//! +//! - Eager mode is meant to be used in conjunction with incremental compilation +//! where a stable set of mono items is more important than a minimal +//! one. Thus, eager mode will instantiate drop-glue for every drop-able type +//! in the crate, even if no drop call for that type exists (yet). It will +//! also instantiate default implementations of trait methods, something that +//! otherwise is only done on demand. +//! +//! +//! Open Issues +//! ----------- +//! Some things are not yet fully implemented in the current version of this +//! module. +//! +//! ### Const Fns +//! Ideally, no mono item should be generated for const fns unless there +//! is a call to them that cannot be evaluated at compile time. At the moment +//! this is not implemented however: a mono item will be produced +//! regardless of whether it is actually needed or not. + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; +use rustc_errors::{ErrorReported, FatalError}; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_hir::lang_items::LangItem; +use rustc_index::bit_set::GrowableBitSet; +use rustc_middle::mir::interpret::{AllocId, ConstValue}; +use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; +use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; +use rustc_middle::mir::visit::Visitor as MirVisitor; +use rustc_middle::mir::{self, Local, Location}; +use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; +use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, VtblEntry}; +use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; +use rustc_session::config::EntryFnType; +use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; +use rustc_session::Limit; +use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; +use rustc_target::abi::Size; +use smallvec::SmallVec; +use std::iter; +use std::ops::Range; +use std::path::PathBuf; + +#[derive(PartialEq)] +pub enum MonoItemCollectionMode { + Eager, + Lazy, +} + +/// Maps every mono item to all mono items it references in its +/// body. +pub struct InliningMap<'tcx> { + // Maps a source mono item to the range of mono items + // accessed by it. + // The range selects elements within the `targets` vecs. + index: FxHashMap, Range>, + targets: Vec>, + + // Contains one bit per mono item in the `targets` field. That bit + // is true if that mono item needs to be inlined into every CGU. + inlines: GrowableBitSet, +} + +impl<'tcx> InliningMap<'tcx> { + fn new() -> InliningMap<'tcx> { + InliningMap { + index: FxHashMap::default(), + targets: Vec::new(), + inlines: GrowableBitSet::with_capacity(1024), + } + } + + fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) { + let start_index = self.targets.len(); + let new_items_count = new_targets.len(); + let new_items_count_total = new_items_count + self.targets.len(); + + self.targets.reserve(new_items_count); + self.inlines.ensure(new_items_count_total); + + for (i, (target, inline)) in new_targets.iter().enumerate() { + self.targets.push(*target); + if *inline { + self.inlines.insert(i + start_index); + } + } + + let end_index = self.targets.len(); + assert!(self.index.insert(source, start_index..end_index).is_none()); + } + + // Internally iterate over all items referenced by `source` which will be + // made available for inlining. + pub fn with_inlining_candidates(&self, source: MonoItem<'tcx>, mut f: F) + where + F: FnMut(MonoItem<'tcx>), + { + if let Some(range) = self.index.get(&source) { + for (i, candidate) in self.targets[range.clone()].iter().enumerate() { + if self.inlines.contains(range.start + i) { + f(*candidate); + } + } + } + } + + // Internally iterate over all items and the things each accesses. + pub fn iter_accesses(&self, mut f: F) + where + F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]), + { + for (&accessor, range) in &self.index { + f(accessor, &self.targets[range.clone()]) + } + } +} + +pub fn collect_crate_mono_items( + tcx: TyCtxt<'_>, + mode: MonoItemCollectionMode, +) -> (FxHashSet>, InliningMap<'_>) { + let _prof_timer = tcx.prof.generic_activity("monomorphization_collector"); + + let roots = + tcx.sess.time("monomorphization_collector_root_collections", || collect_roots(tcx, mode)); + + debug!("building mono item graph, beginning at roots"); + + let mut visited = MTLock::new(FxHashSet::default()); + let mut inlining_map = MTLock::new(InliningMap::new()); + let recursion_limit = tcx.recursion_limit(); + + { + let visited: MTRef<'_, _> = &mut visited; + let inlining_map: MTRef<'_, _> = &mut inlining_map; + + tcx.sess.time("monomorphization_collector_graph_walk", || { + par_iter(roots).for_each(|root| { + let mut recursion_depths = DefIdMap::default(); + collect_items_rec( + tcx, + dummy_spanned(root), + visited, + &mut recursion_depths, + recursion_limit, + inlining_map, + ); + }); + }); + } + + (visited.into_inner(), inlining_map.into_inner()) +} + +// Find all non-generic items by walking the HIR. These items serve as roots to +// start monomorphizing from. +fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec> { + debug!("collecting roots"); + let mut roots = Vec::new(); + + { + let entry_fn = tcx.entry_fn(()); + + debug!("collect_roots: entry_fn = {:?}", entry_fn); + + let mut visitor = RootCollector { tcx, mode, entry_fn, output: &mut roots }; + + tcx.hir().visit_all_item_likes(&mut visitor); + + visitor.push_extra_entry_roots(); + } + + // We can only codegen items that are instantiable - items all of + // whose predicates hold. Luckily, items that aren't instantiable + // can't actually be used, so we can just skip codegenning them. + roots + .into_iter() + .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node)) + .collect() +} + +/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a +/// post-monorphization error is encountered during a collection step. +fn collect_items_rec<'tcx>( + tcx: TyCtxt<'tcx>, + starting_point: Spanned>, + visited: MTRef<'_, MTLock>>>, + recursion_depths: &mut DefIdMap, + recursion_limit: Limit, + inlining_map: MTRef<'_, MTLock>>, +) { + if !visited.lock_mut().insert(starting_point.node) { + // We've been here already, no need to search again. + return; + } + debug!("BEGIN collect_items_rec({})", starting_point.node); + + let mut neighbors = Vec::new(); + let recursion_depth_reset; + + // + // Post-monomorphization errors MVP + // + // We can encounter errors while monomorphizing an item, but we don't have a good way of + // showing a complete stack of spans ultimately leading to collecting the erroneous one yet. + // (It's also currently unclear exactly which diagnostics and information would be interesting + // to report in such cases) + // + // This leads to suboptimal error reporting: a post-monomorphization error (PME) will be + // shown with just a spanned piece of code causing the error, without information on where + // it was called from. This is especially obscure if the erroneous mono item is in a + // dependency. See for example issue #85155, where, before minimization, a PME happened two + // crates downstream from libcore's stdarch, without a way to know which dependency was the + // cause. + // + // If such an error occurs in the current crate, its span will be enough to locate the + // source. If the cause is in another crate, the goal here is to quickly locate which mono + // item in the current crate is ultimately responsible for causing the error. + // + // To give at least _some_ context to the user: while collecting mono items, we check the + // error count. If it has changed, a PME occurred, and we trigger some diagnostics about the + // current step of mono items collection. + // + let error_count = tcx.sess.diagnostic().err_count(); + + match starting_point.node { + MonoItem::Static(def_id) => { + let instance = Instance::mono(tcx, def_id); + + // Sanity check whether this ended up being collected accidentally + debug_assert!(should_codegen_locally(tcx, &instance)); + + let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors); + + recursion_depth_reset = None; + + if let Ok(alloc) = tcx.eval_static_initializer(def_id) { + for &id in alloc.relocations().values() { + collect_miri(tcx, id, &mut neighbors); + } + } + } + MonoItem::Fn(instance) => { + // Sanity check whether this ended up being collected accidentally + debug_assert!(should_codegen_locally(tcx, &instance)); + + // Keep track of the monomorphization recursion depth + recursion_depth_reset = Some(check_recursion_limit( + tcx, + instance, + starting_point.span, + recursion_depths, + recursion_limit, + )); + check_type_length_limit(tcx, instance); + + rustc_data_structures::stack::ensure_sufficient_stack(|| { + collect_neighbours(tcx, instance, &mut neighbors); + }); + } + MonoItem::GlobalAsm(item_id) => { + recursion_depth_reset = None; + + let item = tcx.hir().item(item_id); + if let hir::ItemKind::GlobalAsm(asm) = item.kind { + for (op, op_sp) in asm.operands { + match op { + hir::InlineAsmOperand::Const { .. } => { + // Only constants which resolve to a plain integer + // are supported. Therefore the value should not + // depend on any other items. + } + _ => span_bug!(*op_sp, "invalid operand type for global_asm!"), + } + } + } else { + span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") + } + } + } + + // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the + // mono item graph where the PME diagnostics are currently the most problematic (e.g. ones + // involving a dependency, and the lack of context is confusing) in this MVP, we focus on + // diagnostics on edges crossing a crate boundary: the collected mono items which are not + // defined in the local crate. + if tcx.sess.diagnostic().err_count() > error_count + && starting_point.node.krate() != LOCAL_CRATE + && starting_point.node.is_user_defined() + { + let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string()); + tcx.sess.span_note_without_error( + starting_point.span, + &format!("the above error was encountered while instantiating `{}`", formatted_item), + ); + } + + record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); + + for neighbour in neighbors { + collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map); + } + + if let Some((def_id, depth)) = recursion_depth_reset { + recursion_depths.insert(def_id, depth); + } + + debug!("END collect_items_rec({})", starting_point.node); +} + +fn record_accesses<'a, 'tcx: 'a>( + tcx: TyCtxt<'tcx>, + caller: MonoItem<'tcx>, + callees: impl Iterator>, + inlining_map: MTRef<'_, MTLock>>, +) { + let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| { + mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy + }; + + // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock. + // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec` + // instead to avoid creating this `SmallVec`. + let accesses: SmallVec<[_; 128]> = + callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect(); + + inlining_map.lock_mut().record_accesses(caller, &accesses); +} + +/// Format instance name that is already known to be too long for rustc. +/// Show only the first and last 32 characters to avoid blasting +/// the user's terminal with thousands of lines of type-name. +/// +/// If the type name is longer than before+after, it will be written to a file. +fn shrunk_instance_name( + tcx: TyCtxt<'tcx>, + instance: &Instance<'tcx>, + before: usize, + after: usize, +) -> (String, Option) { + let s = instance.to_string(); + + // Only use the shrunk version if it's really shorter. + // This also avoids the case where before and after slices overlap. + if s.chars().nth(before + after + 1).is_some() { + // An iterator of all byte positions including the end of the string. + let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); + + let shrunk = format!( + "{before}...{after}", + before = &s[..positions().nth(before).unwrap_or(s.len())], + after = &s[positions().rev().nth(after).unwrap_or(0)..], + ); + + let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None); + let written_to_path = std::fs::write(&path, s).ok().map(|_| path); + + (shrunk, written_to_path) + } else { + (s, None) + } +} + +fn check_recursion_limit<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + span: Span, + recursion_depths: &mut DefIdMap, + recursion_limit: Limit, +) -> (DefId, usize) { + let def_id = instance.def_id(); + let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); + debug!(" => recursion depth={}", recursion_depth); + + let adjusted_recursion_depth = if Some(def_id) == tcx.lang_items().drop_in_place_fn() { + // HACK: drop_in_place creates tight monomorphization loops. Give + // it more margin. + recursion_depth / 4 + } else { + recursion_depth + }; + + // Code that needs to instantiate the same function recursively + // more than the recursion limit is assumed to be causing an + // infinite expansion. + if !recursion_limit.value_within_limit(adjusted_recursion_depth) { + let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); + let error = format!("reached the recursion limit while instantiating `{}`", shrunk); + let mut err = tcx.sess.struct_span_fatal(span, &error); + err.span_note( + tcx.def_span(def_id), + &format!("`{}` defined here", tcx.def_path_str(def_id)), + ); + if let Some(path) = written_to_path { + err.note(&format!("the full type name has been written to '{}'", path.display())); + } + err.emit(); + FatalError.raise(); + } + + recursion_depths.insert(def_id, recursion_depth + 1); + + (def_id, recursion_depth) +} + +fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { + let type_length = instance + .substs + .iter() + .flat_map(|arg| arg.walk(tcx)) + .filter(|arg| match arg.unpack() { + GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, + GenericArgKind::Lifetime(_) => false, + }) + .count(); + debug!(" => type length={}", type_length); + + // Rust code can easily create exponentially-long types using only a + // polynomial recursion depth. Even with the default recursion + // depth, you can easily get cases that take >2^60 steps to run, + // which means that rustc basically hangs. + // + // Bail out in these cases to avoid that bad user experience. + if !tcx.type_length_limit().value_within_limit(type_length) { + let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); + let msg = format!("reached the type-length limit while instantiating `{}`", shrunk); + let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); + if let Some(path) = written_to_path { + diag.note(&format!("the full type name has been written to '{}'", path.display())); + } + diag.help(&format!( + "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", + type_length + )); + diag.emit(); + tcx.sess.abort_if_errors(); + } +} + +struct MirNeighborCollector<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + output: &'a mut Vec>>, + instance: Instance<'tcx>, +} + +impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { + pub fn monomorphize(&self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + debug!("monomorphize: self.instance={:?}", self.instance); + self.instance.subst_mir_and_normalize_erasing_regions( + self.tcx, + ty::ParamEnv::reveal_all(), + value, + ) + } +} + +impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { + debug!("visiting rvalue {:?}", *rvalue); + + let span = self.body.source_info(location).span; + + match *rvalue { + // When doing an cast from a regular pointer to a fat pointer, we + // have to instantiate all methods of the trait being cast to, so we + // can build the appropriate vtable. + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::Unsize), + ref operand, + target_ty, + ) => { + let target_ty = self.monomorphize(target_ty); + let source_ty = operand.ty(self.body, self.tcx); + let source_ty = self.monomorphize(source_ty); + let (source_ty, target_ty) = + find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty); + // This could also be a different Unsize instruction, like + // from a fixed sized array to a slice. But we are only + // interested in things that produce a vtable. + if target_ty.is_trait() && !source_ty.is_trait() { + create_mono_items_for_vtable_methods( + self.tcx, + target_ty, + source_ty, + span, + self.output, + ); + } + } + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::ReifyFnPointer), + ref operand, + _, + ) => { + let fn_ty = operand.ty(self.body, self.tcx); + let fn_ty = self.monomorphize(fn_ty); + visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output); + } + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)), + ref operand, + _, + ) => { + let source_ty = operand.ty(self.body, self.tcx); + let source_ty = self.monomorphize(source_ty); + match *source_ty.kind() { + ty::Closure(def_id, substs) => { + let instance = Instance::resolve_closure( + self.tcx, + def_id, + substs, + ty::ClosureKind::FnOnce, + ); + if should_codegen_locally(self.tcx, &instance) { + self.output.push(create_fn_mono_item(self.tcx, instance, span)); + } + } + _ => bug!(), + } + } + mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { + let tcx = self.tcx; + let exchange_malloc_fn_def_id = + tcx.require_lang_item(LangItem::ExchangeMalloc, None); + let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); + if should_codegen_locally(tcx, &instance) { + self.output.push(create_fn_mono_item(self.tcx, instance, span)); + } + } + mir::Rvalue::ThreadLocalRef(def_id) => { + assert!(self.tcx.is_thread_local_static(def_id)); + let instance = Instance::mono(self.tcx, def_id); + if should_codegen_locally(self.tcx, &instance) { + trace!("collecting thread-local static {:?}", def_id); + self.output.push(respan(span, MonoItem::Static(def_id))); + } + } + _ => { /* not interesting */ } + } + + self.super_rvalue(rvalue, location); + } + + /// This does not walk the constant, as it has been handled entirely here and trying + /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily + /// work, as some constants cannot be represented in the type system. + fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { + let literal = self.monomorphize(constant.literal); + let val = match literal { + mir::ConstantKind::Val(val, _) => val, + mir::ConstantKind::Ty(ct) => match ct.val { + ty::ConstKind::Value(val) => val, + ty::ConstKind::Unevaluated(ct) => { + let param_env = ty::ParamEnv::reveal_all(); + match self.tcx.const_eval_resolve(param_env, ct, None) { + // The `monomorphize` call should have evaluated that constant already. + Ok(val) => val, + Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => return, + Err(ErrorHandled::TooGeneric) => span_bug!( + self.body.source_info(location).span, + "collection encountered polymorphic constant: {:?}", + literal + ), + } + } + _ => return, + }, + }; + collect_const_value(self.tcx, val, self.output); + self.visit_ty(literal.ty(), TyContext::Location(location)); + } + + fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { + debug!("visiting const {:?} @ {:?}", *constant, location); + + let substituted_constant = self.monomorphize(*constant); + let param_env = ty::ParamEnv::reveal_all(); + + match substituted_constant.val { + ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), + ty::ConstKind::Unevaluated(unevaluated) => { + match self.tcx.const_eval_resolve(param_env, unevaluated, None) { + // The `monomorphize` call should have evaluated that constant already. + Ok(val) => span_bug!( + self.body.source_info(location).span, + "collection encountered the unevaluated constant {} which evaluated to {:?}", + substituted_constant, + val + ), + Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {} + Err(ErrorHandled::TooGeneric) => span_bug!( + self.body.source_info(location).span, + "collection encountered polymorphic constant: {}", + substituted_constant + ), + } + } + _ => {} + } + + self.super_const(constant); + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + debug!("visiting terminator {:?} @ {:?}", terminator, location); + let source = self.body.source_info(location).span; + + let tcx = self.tcx; + match terminator.kind { + mir::TerminatorKind::Call { ref func, .. } => { + let callee_ty = func.ty(self.body, tcx); + let callee_ty = self.monomorphize(callee_ty); + visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output); + } + mir::TerminatorKind::Drop { ref place, .. } + | mir::TerminatorKind::DropAndReplace { ref place, .. } => { + let ty = place.ty(self.body, self.tcx).ty; + let ty = self.monomorphize(ty); + visit_drop_use(self.tcx, ty, true, source, self.output); + } + mir::TerminatorKind::InlineAsm { ref operands, .. } => { + for op in operands { + match *op { + mir::InlineAsmOperand::SymFn { ref value } => { + let fn_ty = self.monomorphize(value.literal.ty()); + visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); + } + mir::InlineAsmOperand::SymStatic { def_id } => { + let instance = Instance::mono(self.tcx, def_id); + if should_codegen_locally(self.tcx, &instance) { + trace!("collecting asm sym static {:?}", def_id); + self.output.push(respan(source, MonoItem::Static(def_id))); + } + } + _ => {} + } + } + } + mir::TerminatorKind::Goto { .. } + | mir::TerminatorKind::SwitchInt { .. } + | mir::TerminatorKind::Resume + | mir::TerminatorKind::Abort + | mir::TerminatorKind::Return + | mir::TerminatorKind::Unreachable + | mir::TerminatorKind::Assert { .. } => {} + mir::TerminatorKind::GeneratorDrop + | mir::TerminatorKind::Yield { .. } + | mir::TerminatorKind::FalseEdge { .. } + | mir::TerminatorKind::FalseUnwind { .. } => bug!(), + } + + self.super_terminator(terminator, location); + } + + fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { + self.super_operand(operand, location); + let limit = self.tcx.move_size_limit().0; + if limit == 0 { + return; + } + let limit = Size::from_bytes(limit); + let ty = operand.ty(self.body, self.tcx); + let ty = self.monomorphize(ty); + let layout = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)); + if let Ok(layout) = layout { + if layout.size > limit { + debug!(?layout); + let source_info = self.body.source_info(location); + debug!(?source_info); + let lint_root = source_info.scope.lint_root(&self.body.source_scopes); + debug!(?lint_root); + let lint_root = match lint_root { + Some(lint_root) => lint_root, + // This happens when the issue is in a function from a foreign crate that + // we monomorphized in the current crate. We can't get a `HirId` for things + // in other crates. + // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root + // but correct span? This would make the lint at least accept crate-level lint attributes. + None => return, + }; + self.tcx.struct_span_lint_hir( + LARGE_ASSIGNMENTS, + lint_root, + source_info.span, + |lint| { + let mut err = lint.build(&format!("moving {} bytes", layout.size.bytes())); + err.span_label(source_info.span, "value moved from here"); + err.emit() + }, + ); + } + } + } + + fn visit_local( + &mut self, + _place_local: &Local, + _context: mir::visit::PlaceContext, + _location: Location, + ) { + } +} + +fn visit_drop_use<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + is_direct_call: bool, + source: Span, + output: &mut Vec>>, +) { + let instance = Instance::resolve_drop_in_place(tcx, ty); + visit_instance_use(tcx, instance, is_direct_call, source, output); +} + +fn visit_fn_use<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + is_direct_call: bool, + source: Span, + output: &mut Vec>>, +) { + if let ty::FnDef(def_id, substs) = *ty.kind() { + let instance = if is_direct_call { + ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap() + } else { + ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs) + .unwrap() + }; + visit_instance_use(tcx, instance, is_direct_call, source, output); + } +} + +fn visit_instance_use<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, + is_direct_call: bool, + source: Span, + output: &mut Vec>>, +) { + debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); + if !should_codegen_locally(tcx, &instance) { + return; + } + + match instance.def { + ty::InstanceDef::Virtual(..) | ty::InstanceDef::Intrinsic(_) => { + if !is_direct_call { + bug!("{:?} being reified", instance); + } + } + ty::InstanceDef::DropGlue(_, None) => { + // Don't need to emit noop drop glue if we are calling directly. + if !is_direct_call { + output.push(create_fn_mono_item(tcx, instance, source)); + } + } + ty::InstanceDef::DropGlue(_, Some(_)) + | ty::InstanceDef::VtableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::Item(..) + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::CloneShim(..) => { + output.push(create_fn_mono_item(tcx, instance, source)); + } + } +} + +/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we +/// can just link to the upstream crate and therefore don't need a mono item. +fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { + let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() { + def_id + } else { + return true; + }; + + if tcx.is_foreign_item(def_id) { + // Foreign items are always linked against, there's no way of instantiating them. + return false; + } + + if def_id.is_local() { + // Local items cannot be referred to locally without monomorphizing them locally. + return true; + } + + if tcx.is_reachable_non_generic(def_id) + || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() + { + // We can link to the item in question, no instance needed in this crate. + return false; + } + + if !tcx.is_mir_available(def_id) { + bug!("no MIR available for {:?}", def_id); + } + + true +} + +/// For a given pair of source and target type that occur in an unsizing coercion, +/// this function finds the pair of types that determines the vtable linking +/// them. +/// +/// For example, the source type might be `&SomeStruct` and the target type\ +/// might be `&SomeTrait` in a cast like: +/// +/// let src: &SomeStruct = ...; +/// let target = src as &SomeTrait; +/// +/// Then the output of this function would be (SomeStruct, SomeTrait) since for +/// constructing the `target` fat-pointer we need the vtable for that pair. +/// +/// Things can get more complicated though because there's also the case where +/// the unsized type occurs as a field: +/// +/// ```rust +/// struct ComplexStruct { +/// a: u32, +/// b: f64, +/// c: T +/// } +/// ``` +/// +/// In this case, if `T` is sized, `&ComplexStruct` is a thin pointer. If `T` +/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is +/// for the pair of `T` (which is a trait) and the concrete type that `T` was +/// originally coerced from: +/// +/// let src: &ComplexStruct = ...; +/// let target = src as &ComplexStruct; +/// +/// Again, we want this `find_vtable_types_for_unsizing()` to provide the pair +/// `(SomeStruct, SomeTrait)`. +/// +/// Finally, there is also the case of custom unsizing coercions, e.g., for +/// smart pointers such as `Rc` and `Arc`. +fn find_vtable_types_for_unsizing<'tcx>( + tcx: TyCtxt<'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>, +) -> (Ty<'tcx>, Ty<'tcx>) { + let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { + let param_env = ty::ParamEnv::reveal_all(); + let type_has_metadata = |ty: Ty<'tcx>| -> bool { + if ty.is_sized(tcx.at(DUMMY_SP), param_env) { + return false; + } + let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); + match tail.kind() { + ty::Foreign(..) => false, + ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, + _ => bug!("unexpected unsized tail: {:?}", tail), + } + }; + if type_has_metadata(inner_source) { + (inner_source, inner_target) + } else { + tcx.struct_lockstep_tails_erasing_lifetimes(inner_source, inner_target, param_env) + } + }; + + match (&source_ty.kind(), &target_ty.kind()) { + (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) + | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { + ptr_vtable(a, b) + } + (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) + } + + (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { + assert_eq!(source_adt_def, target_adt_def); + + let CustomCoerceUnsized::Struct(coerce_index) = + crate::custom_coerce_unsize_info(tcx, source_ty, target_ty); + + let source_fields = &source_adt_def.non_enum_variant().fields; + let target_fields = &target_adt_def.non_enum_variant().fields; + + assert!( + coerce_index < source_fields.len() && source_fields.len() == target_fields.len() + ); + + find_vtable_types_for_unsizing( + tcx, + source_fields[coerce_index].ty(tcx, source_substs), + target_fields[coerce_index].ty(tcx, target_substs), + ) + } + _ => bug!( + "find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", + source_ty, + target_ty + ), + } +} + +fn create_fn_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + source: Span, +) -> Spanned> { + debug!("create_fn_mono_item(instance={})", instance); + + let def_id = instance.def_id(); + if tcx.sess.opts.debugging_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) + { + crate::util::dump_closure_profile(tcx, instance); + } + + respan(source, MonoItem::Fn(instance.polymorphize(tcx))) +} + +/// Creates a `MonoItem` for each method that is referenced by the vtable for +/// the given trait/impl pair. +fn create_mono_items_for_vtable_methods<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ty: Ty<'tcx>, + impl_ty: Ty<'tcx>, + source: Span, + output: &mut Vec>>, +) { + assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars()); + + if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind() { + if let Some(principal) = trait_ty.principal() { + let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); + assert!(!poly_trait_ref.has_escaping_bound_vars()); + + // Walk all methods of the trait, including those of its supertraits + let entries = tcx.vtable_entries(poly_trait_ref); + let methods = entries + .iter() + .filter_map(|entry| match entry { + VtblEntry::MetadataDropInPlace + | VtblEntry::MetadataSize + | VtblEntry::MetadataAlign + | VtblEntry::Vacant => None, + VtblEntry::TraitVPtr(_) => { + // all super trait items already covered, so skip them. + None + } + VtblEntry::Method(instance) => { + Some(*instance).filter(|instance| should_codegen_locally(tcx, instance)) + } + }) + .map(|item| create_fn_mono_item(tcx, item, source)); + output.extend(methods); + } + + // Also add the destructor. + visit_drop_use(tcx, impl_ty, false, source, output); + } +} + +//=----------------------------------------------------------------------------- +// Root Collection +//=----------------------------------------------------------------------------- + +struct RootCollector<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + mode: MonoItemCollectionMode, + output: &'a mut Vec>>, + entry_fn: Option<(DefId, EntryFnType)>, +} + +impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { + fn visit_item(&mut self, item: &'v hir::Item<'v>) { + match item.kind { + hir::ItemKind::ExternCrate(..) + | hir::ItemKind::Use(..) + | hir::ItemKind::Macro(..) + | hir::ItemKind::ForeignMod { .. } + | hir::ItemKind::TyAlias(..) + | hir::ItemKind::Trait(..) + | hir::ItemKind::TraitAlias(..) + | hir::ItemKind::OpaqueTy(..) + | hir::ItemKind::Mod(..) => { + // Nothing to do, just keep recursing. + } + + hir::ItemKind::Impl { .. } => { + if self.mode == MonoItemCollectionMode::Eager { + create_mono_items_for_default_impls(self.tcx, item, self.output); + } + } + + hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) => { + if generics.params.is_empty() { + if self.mode == MonoItemCollectionMode::Eager { + debug!( + "RootCollector: ADT drop-glue for {}", + self.tcx.def_path_str(item.def_id.to_def_id()) + ); + + let ty = Instance::new(item.def_id.to_def_id(), InternalSubsts::empty()) + .ty(self.tcx, ty::ParamEnv::reveal_all()); + visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output); + } + } + } + hir::ItemKind::GlobalAsm(..) => { + debug!( + "RootCollector: ItemKind::GlobalAsm({})", + self.tcx.def_path_str(item.def_id.to_def_id()) + ); + self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.item_id()))); + } + hir::ItemKind::Static(..) => { + debug!( + "RootCollector: ItemKind::Static({})", + self.tcx.def_path_str(item.def_id.to_def_id()) + ); + self.output.push(dummy_spanned(MonoItem::Static(item.def_id.to_def_id()))); + } + hir::ItemKind::Const(..) => { + // const items only generate mono items if they are + // actually used somewhere. Just declaring them is insufficient. + + // but even just declaring them must collect the items they refer to + if let Ok(val) = self.tcx.const_eval_poly(item.def_id.to_def_id()) { + collect_const_value(self.tcx, val, &mut self.output); + } + } + hir::ItemKind::Fn(..) => { + self.push_if_root(item.def_id); + } + } + } + + fn visit_trait_item(&mut self, _: &'v hir::TraitItem<'v>) { + // Even if there's a default body with no explicit generics, + // it's still generic over some `Self: Trait`, so not a root. + } + + fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { + if let hir::ImplItemKind::Fn(hir::FnSig { .. }, _) = ii.kind { + self.push_if_root(ii.def_id); + } + } + + fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {} +} + +impl RootCollector<'_, 'v> { + fn is_root(&self, def_id: LocalDefId) -> bool { + !item_requires_monomorphization(self.tcx, def_id) + && match self.mode { + MonoItemCollectionMode::Eager => true, + MonoItemCollectionMode::Lazy => { + self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) + || self.tcx.is_reachable_non_generic(def_id) + || self + .tcx + .codegen_fn_attrs(def_id) + .flags + .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + } + } + } + + /// If `def_id` represents a root, pushes it onto the list of + /// outputs. (Note that all roots must be monomorphic.) + fn push_if_root(&mut self, def_id: LocalDefId) { + if self.is_root(def_id) { + debug!("RootCollector::push_if_root: found root def_id={:?}", def_id); + + let instance = Instance::mono(self.tcx, def_id.to_def_id()); + self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP)); + } + } + + /// As a special case, when/if we encounter the + /// `main()` function, we also have to generate a + /// monomorphized copy of the start lang item based on + /// the return type of `main`. This is not needed when + /// the user writes their own `start` manually. + fn push_extra_entry_roots(&mut self) { + let main_def_id = match self.entry_fn { + Some((def_id, EntryFnType::Main)) => def_id, + _ => return, + }; + + let start_def_id = match self.tcx.lang_items().require(LangItem::Start) { + Ok(s) => s, + Err(err) => self.tcx.sess.fatal(&err), + }; + let main_ret_ty = self.tcx.fn_sig(main_def_id).output(); + + // Given that `main()` has no arguments, + // then its return type cannot have + // late-bound regions, since late-bound + // regions must appear in the argument + // listing. + let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); + + let start_instance = Instance::resolve( + self.tcx, + ty::ParamEnv::reveal_all(), + start_def_id, + self.tcx.intern_substs(&[main_ret_ty.into()]), + ) + .unwrap() + .unwrap(); + + self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); + } +} + +fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let generics = tcx.generics_of(def_id); + generics.requires_monomorphization(tcx) +} + +fn create_mono_items_for_default_impls<'tcx>( + tcx: TyCtxt<'tcx>, + item: &'tcx hir::Item<'tcx>, + output: &mut Vec>>, +) { + match item.kind { + hir::ItemKind::Impl(ref impl_) => { + for param in impl_.generics.params { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => {} + hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => { + return; + } + } + } + + debug!( + "create_mono_items_for_default_impls(item={})", + tcx.def_path_str(item.def_id.to_def_id()) + ); + + if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) { + let param_env = ty::ParamEnv::reveal_all(); + let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); + let overridden_methods: FxHashSet<_> = + impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect(); + for method in tcx.provided_trait_methods(trait_ref.def_id) { + if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) { + continue; + } + + if tcx.generics_of(method.def_id).own_requires_monomorphization() { + continue; + } + + let substs = + InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind { + GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const { .. } => { + trait_ref.substs[param.index as usize] + } + }); + let instance = ty::Instance::resolve(tcx, param_env, method.def_id, substs) + .unwrap() + .unwrap(); + + let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); + if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance) + { + output.push(mono_item); + } + } + } + } + _ => bug!(), + } +} + +/// Scans the miri alloc in order to find function calls, closures, and drop-glue. +fn collect_miri<'tcx>( + tcx: TyCtxt<'tcx>, + alloc_id: AllocId, + output: &mut Vec>>, +) { + match tcx.global_alloc(alloc_id) { + GlobalAlloc::Static(def_id) => { + assert!(!tcx.is_thread_local_static(def_id)); + let instance = Instance::mono(tcx, def_id); + if should_codegen_locally(tcx, &instance) { + trace!("collecting static {:?}", def_id); + output.push(dummy_spanned(MonoItem::Static(def_id))); + } + } + GlobalAlloc::Memory(alloc) => { + trace!("collecting {:?} with {:#?}", alloc_id, alloc); + for &inner in alloc.relocations().values() { + rustc_data_structures::stack::ensure_sufficient_stack(|| { + collect_miri(tcx, inner, output); + }); + } + } + GlobalAlloc::Function(fn_instance) => { + if should_codegen_locally(tcx, &fn_instance) { + trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); + output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); + } + } + } +} + +/// Scans the MIR in order to find function calls, closures, and drop-glue. +fn collect_neighbours<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + output: &mut Vec>>, +) { + debug!("collect_neighbours: {:?}", instance.def_id()); + let body = tcx.instance_mir(instance.def); + + MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); +} + +fn collect_const_value<'tcx>( + tcx: TyCtxt<'tcx>, + value: ConstValue<'tcx>, + output: &mut Vec>>, +) { + match value { + ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output), + ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { + for &id in alloc.relocations().values() { + collect_miri(tcx, id, output); + } + } + _ => {} + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,50 @@ +#![feature(array_windows)] +#![feature(bool_to_option)] +#![feature(crate_visibility_modifier)] +#![feature(control_flow_enum)] +#![feature(in_band_lifetimes)] +#![recursion_limit = "256"] + +#[macro_use] +extern crate tracing; +#[macro_use] +extern crate rustc_middle; + +use rustc_hir::lang_items::LangItem; +use rustc_middle::traits; +use rustc_middle::ty::adjustment::CustomCoerceUnsized; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +mod collector; +mod partitioning; +mod polymorphize; +mod util; + +fn custom_coerce_unsize_info<'tcx>( + tcx: TyCtxt<'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>, +) -> CustomCoerceUnsized { + let def_id = tcx.require_lang_item(LangItem::CoerceUnsized, None); + + let trait_ref = ty::Binder::dummy(ty::TraitRef { + def_id, + substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]), + }); + + match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { + Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { + impl_def_id, + .. + })) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(), + impl_source => { + bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source); + } + } +} + +pub fn provide(providers: &mut Providers) { + partitioning::provide(providers); + polymorphize::provide(providers); +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/default.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/default.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/default.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/default.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,564 @@ +use std::collections::hash_map::Entry; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::definitions::DefPathDataName; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::exported_symbols::SymbolExportLevel; +use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; +use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; +use rustc_middle::ty::print::characteristic_def_id_of_type; +use rustc_middle::ty::{self, fold::TypeFoldable, DefIdTree, InstanceDef, TyCtxt}; +use rustc_span::symbol::Symbol; + +use super::PartitioningCx; +use crate::collector::InliningMap; +use crate::partitioning::merging; +use crate::partitioning::{ + MonoItemPlacement, Partitioner, PostInliningPartitioning, PreInliningPartitioning, +}; + +pub struct DefaultPartitioning; + +impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { + fn place_root_mono_items( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + mono_items: &mut dyn Iterator>, + ) -> PreInliningPartitioning<'tcx> { + let mut roots = FxHashSet::default(); + let mut codegen_units = FxHashMap::default(); + let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); + let mut internalization_candidates = FxHashSet::default(); + + // Determine if monomorphizations instantiated in this crate will be made + // available to downstream crates. This depends on whether we are in + // share-generics mode and whether the current crate can even have + // downstream crates. + let export_generics = + cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + let cgu_name_cache = &mut FxHashMap::default(); + + for mono_item in mono_items { + match mono_item.instantiation_mode(cx.tcx) { + InstantiationMode::GloballyShared { .. } => {} + InstantiationMode::LocalCopy => continue, + } + + let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); + let is_volatile = is_incremental_build && mono_item.is_generic_fn(); + + let codegen_unit_name = match characteristic_def_id { + Some(def_id) => compute_codegen_unit_name( + cx.tcx, + cgu_name_builder, + def_id, + is_volatile, + cgu_name_cache, + ), + None => fallback_cgu_name(cgu_name_builder), + }; + + let codegen_unit = codegen_units + .entry(codegen_unit_name) + .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); + + let mut can_be_internalized = true; + let (linkage, visibility) = mono_item_linkage_and_visibility( + cx.tcx, + &mono_item, + &mut can_be_internalized, + export_generics, + ); + if visibility == Visibility::Hidden && can_be_internalized { + internalization_candidates.insert(mono_item); + } + + codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); + roots.insert(mono_item); + } + + // Always ensure we have at least one CGU; otherwise, if we have a + // crate with just types (for example), we could wind up with no CGU. + if codegen_units.is_empty() { + let codegen_unit_name = fallback_cgu_name(cgu_name_builder); + codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); + } + + PreInliningPartitioning { + codegen_units: codegen_units + .into_iter() + .map(|(_, codegen_unit)| codegen_unit) + .collect(), + roots, + internalization_candidates, + } + } + + fn merge_codegen_units( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, + ) { + merging::merge_codegen_units(cx, initial_partitioning); + } + + fn place_inlined_mono_items( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + initial_partitioning: PreInliningPartitioning<'tcx>, + ) -> PostInliningPartitioning<'tcx> { + let mut new_partitioning = Vec::new(); + let mut mono_item_placements = FxHashMap::default(); + + let PreInliningPartitioning { + codegen_units: initial_cgus, + roots, + internalization_candidates, + } = initial_partitioning; + + let single_codegen_unit = initial_cgus.len() == 1; + + for old_codegen_unit in initial_cgus { + // Collect all items that need to be available in this codegen unit. + let mut reachable = FxHashSet::default(); + for root in old_codegen_unit.items().keys() { + follow_inlining(*root, cx.inlining_map, &mut reachable); + } + + let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); + + // Add all monomorphizations that are not already there. + for mono_item in reachable { + if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { + // This is a root, just copy it over. + new_codegen_unit.items_mut().insert(mono_item, *linkage); + } else { + if roots.contains(&mono_item) { + bug!( + "GloballyShared mono-item inlined into other CGU: \ + {:?}", + mono_item + ); + } + + // This is a CGU-private copy. + new_codegen_unit + .items_mut() + .insert(mono_item, (Linkage::Internal, Visibility::Default)); + } + + if !single_codegen_unit { + // If there is more than one codegen unit, we need to keep track + // in which codegen units each monomorphization is placed. + match mono_item_placements.entry(mono_item) { + Entry::Occupied(e) => { + let placement = e.into_mut(); + debug_assert!(match *placement { + MonoItemPlacement::SingleCgu { cgu_name } => { + cgu_name != new_codegen_unit.name() + } + MonoItemPlacement::MultipleCgus => true, + }); + *placement = MonoItemPlacement::MultipleCgus; + } + Entry::Vacant(e) => { + e.insert(MonoItemPlacement::SingleCgu { + cgu_name: new_codegen_unit.name(), + }); + } + } + } + } + + new_partitioning.push(new_codegen_unit); + } + + return PostInliningPartitioning { + codegen_units: new_partitioning, + mono_item_placements, + internalization_candidates, + }; + + fn follow_inlining<'tcx>( + mono_item: MonoItem<'tcx>, + inlining_map: &InliningMap<'tcx>, + visited: &mut FxHashSet>, + ) { + if !visited.insert(mono_item) { + return; + } + + inlining_map.with_inlining_candidates(mono_item, |target| { + follow_inlining(target, inlining_map, visited); + }); + } + } + + fn internalize_symbols( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + partitioning: &mut PostInliningPartitioning<'tcx>, + ) { + if partitioning.codegen_units.len() == 1 { + // Fast path for when there is only one codegen unit. In this case we + // can internalize all candidates, since there is nowhere else they + // could be accessed from. + for cgu in &mut partitioning.codegen_units { + for candidate in &partitioning.internalization_candidates { + cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); + } + } + + return; + } + + // Build a map from every monomorphization to all the monomorphizations that + // reference it. + let mut accessor_map: FxHashMap, Vec>> = Default::default(); + cx.inlining_map.iter_accesses(|accessor, accessees| { + for accessee in accessees { + accessor_map.entry(*accessee).or_default().push(accessor); + } + }); + + let mono_item_placements = &partitioning.mono_item_placements; + + // For each internalization candidates in each codegen unit, check if it is + // accessed from outside its defining codegen unit. + for cgu in &mut partitioning.codegen_units { + let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; + + for (accessee, linkage_and_visibility) in cgu.items_mut() { + if !partitioning.internalization_candidates.contains(accessee) { + // This item is no candidate for internalizing, so skip it. + continue; + } + debug_assert_eq!(mono_item_placements[accessee], home_cgu); + + if let Some(accessors) = accessor_map.get(accessee) { + if accessors + .iter() + .filter_map(|accessor| { + // Some accessors might not have been + // instantiated. We can safely ignore those. + mono_item_placements.get(accessor) + }) + .any(|placement| *placement != home_cgu) + { + // Found an accessor from another CGU, so skip to the next + // item without marking this one as internal. + continue; + } + } + + // If we got here, we did not find any accesses from other CGUs, + // so it's fine to make this monomorphization internal. + *linkage_and_visibility = (Linkage::Internal, Visibility::Default); + } + } + } +} + +fn characteristic_def_id_of_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: MonoItem<'tcx>, +) -> Option { + match mono_item { + MonoItem::Fn(instance) => { + let def_id = match instance.def { + ty::InstanceDef::Item(def) => def.did, + ty::InstanceDef::VtableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::Intrinsic(..) + | ty::InstanceDef::DropGlue(..) + | ty::InstanceDef::Virtual(..) + | ty::InstanceDef::CloneShim(..) => return None, + }; + + // If this is a method, we want to put it into the same module as + // its self-type. If the self-type does not provide a characteristic + // DefId, we use the location of the impl after all. + + if tcx.trait_of_item(def_id).is_some() { + let self_ty = instance.substs.type_at(0); + // This is a default implementation of a trait method. + return characteristic_def_id_of_type(self_ty).or(Some(def_id)); + } + + if let Some(impl_def_id) = tcx.impl_of_method(def_id) { + if tcx.sess.opts.incremental.is_some() + && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() + { + // Put `Drop::drop` into the same cgu as `drop_in_place` + // since `drop_in_place` is the only thing that can + // call it. + return None; + } + + // When polymorphization is enabled, methods which do not depend on their generic + // parameters, but the self-type of their impl block do will fail to normalize. + if !tcx.sess.opts.debugging_opts.polymorphize + || !instance.definitely_needs_subst(tcx) + { + // This is a method within an impl, find out what the self-type is: + let impl_self_ty = tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + tcx.type_of(impl_def_id), + ); + if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { + return Some(def_id); + } + } + } + + Some(def_id) + } + MonoItem::Static(def_id) => Some(def_id), + MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.to_def_id()), + } +} + +fn compute_codegen_unit_name( + tcx: TyCtxt<'_>, + name_builder: &mut CodegenUnitNameBuilder<'_>, + def_id: DefId, + volatile: bool, + cache: &mut CguNameCache, +) -> Symbol { + // Find the innermost module that is not nested within a function. + let mut current_def_id = def_id; + let mut cgu_def_id = None; + // Walk backwards from the item we want to find the module for. + loop { + if current_def_id.index == CRATE_DEF_INDEX { + if cgu_def_id.is_none() { + // If we have not found a module yet, take the crate root. + cgu_def_id = Some(DefId { krate: def_id.krate, index: CRATE_DEF_INDEX }); + } + break; + } else if tcx.def_kind(current_def_id) == DefKind::Mod { + if cgu_def_id.is_none() { + cgu_def_id = Some(current_def_id); + } + } else { + // If we encounter something that is not a module, throw away + // any module that we've found so far because we now know that + // it is nested within something else. + cgu_def_id = None; + } + + current_def_id = tcx.parent(current_def_id).unwrap(); + } + + let cgu_def_id = cgu_def_id.unwrap(); + + *cache.entry((cgu_def_id, volatile)).or_insert_with(|| { + let def_path = tcx.def_path(cgu_def_id); + + let components = def_path.data.iter().map(|part| match part.data.name() { + DefPathDataName::Named(name) => name, + DefPathDataName::Anon { .. } => unreachable!(), + }); + + let volatile_suffix = volatile.then_some("volatile"); + + name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) + }) +} + +// Anything we can't find a proper codegen unit for goes into this. +fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol { + name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu")) +} + +fn mono_item_linkage_and_visibility( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, + can_be_internalized: &mut bool, + export_generics: bool, +) -> (Linkage, Visibility) { + if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) { + return (explicit_linkage, Visibility::Default); + } + let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics); + (Linkage::External, vis) +} + +type CguNameCache = FxHashMap<(DefId, bool), Symbol>; + +fn mono_item_visibility( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, + can_be_internalized: &mut bool, + export_generics: bool, +) -> Visibility { + let instance = match mono_item { + // This is pretty complicated; see below. + MonoItem::Fn(instance) => instance, + + // Misc handling for generics and such, but otherwise: + MonoItem::Static(def_id) => { + return if tcx.is_reachable_non_generic(*def_id) { + *can_be_internalized = false; + default_visibility(tcx, *def_id, false) + } else { + Visibility::Hidden + }; + } + MonoItem::GlobalAsm(item_id) => { + return if tcx.is_reachable_non_generic(item_id.def_id) { + *can_be_internalized = false; + default_visibility(tcx, item_id.def_id.to_def_id(), false) + } else { + Visibility::Hidden + }; + } + }; + + let def_id = match instance.def { + InstanceDef::Item(def) => def.did, + InstanceDef::DropGlue(def_id, Some(_)) => def_id, + + // These are all compiler glue and such, never exported, always hidden. + InstanceDef::VtableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) => return Visibility::Hidden, + }; + + // The `start_fn` lang item is actually a monomorphized instance of a + // function in the standard library, used for the `main` function. We don't + // want to export it so we tag it with `Hidden` visibility but this symbol + // is only referenced from the actual `main` symbol which we unfortunately + // don't know anything about during partitioning/collection. As a result we + // forcibly keep this symbol out of the `internalization_candidates` set. + // + // FIXME: eventually we don't want to always force this symbol to have + // hidden visibility, it should indeed be a candidate for + // internalization, but we have to understand that it's referenced + // from the `main` symbol we'll generate later. + // + // This may be fixable with a new `InstanceDef` perhaps? Unsure! + if tcx.lang_items().start_fn() == Some(def_id) { + *can_be_internalized = false; + return Visibility::Hidden; + } + + let is_generic = instance.substs.non_erasable_generics().next().is_some(); + + // Upstream `DefId` instances get different handling than local ones. + let def_id = if let Some(def_id) = def_id.as_local() { + def_id + } else { + return if export_generics && is_generic { + // If it is an upstream monomorphization and we export generics, we must make + // it available to downstream crates. + *can_be_internalized = false; + default_visibility(tcx, def_id, true) + } else { + Visibility::Hidden + }; + }; + + if is_generic { + if export_generics { + if tcx.is_unreachable_local_definition(def_id) { + // This instance cannot be used from another crate. + Visibility::Hidden + } else { + // This instance might be useful in a downstream crate. + *can_be_internalized = false; + default_visibility(tcx, def_id.to_def_id(), true) + } + } else { + // We are not exporting generics or the definition is not reachable + // for downstream crates, we can internalize its instantiations. + Visibility::Hidden + } + } else { + // If this isn't a generic function then we mark this a `Default` if + // this is a reachable item, meaning that it's a symbol other crates may + // access when they link to us. + if tcx.is_reachable_non_generic(def_id.to_def_id()) { + *can_be_internalized = false; + debug_assert!(!is_generic); + return default_visibility(tcx, def_id.to_def_id(), false); + } + + // If this isn't reachable then we're gonna tag this with `Hidden` + // visibility. In some situations though we'll want to prevent this + // symbol from being internalized. + // + // There's two categories of items here: + // + // * First is weak lang items. These are basically mechanisms for + // libcore to forward-reference symbols defined later in crates like + // the standard library or `#[panic_handler]` definitions. The + // definition of these weak lang items needs to be referenceable by + // libcore, so we're no longer a candidate for internalization. + // Removal of these functions can't be done by LLVM but rather must be + // done by the linker as it's a non-local decision. + // + // * Second is "std internal symbols". Currently this is primarily used + // for allocator symbols. Allocators are a little weird in their + // implementation, but the idea is that the compiler, at the last + // minute, defines an allocator with an injected object file. The + // `alloc` crate references these symbols (`__rust_alloc`) and the + // definition doesn't get hooked up until a linked crate artifact is + // generated. + // + // The symbols synthesized by the compiler (`__rust_alloc`) are thin + // veneers around the actual implementation, some other symbol which + // implements the same ABI. These symbols (things like `__rg_alloc`, + // `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std + // internal symbols". + // + // The std-internal symbols here **should not show up in a dll as an + // exported interface**, so they return `false` from + // `is_reachable_non_generic` above and we'll give them `Hidden` + // visibility below. Like the weak lang items, though, we can't let + // LLVM internalize them as this decision is left up to the linker to + // omit them, so prevent them from being internalized. + let attrs = tcx.codegen_fn_attrs(def_id); + if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { + *can_be_internalized = false; + } + + Visibility::Hidden + } +} + +fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { + if !tcx.sess.target.default_hidden_visibility { + return Visibility::Default; + } + + // Generic functions never have export-level C. + if is_generic { + return Visibility::Hidden; + } + + // Things with export level C don't get instantiated in + // downstream crates. + if !id.is_local() { + return Visibility::Hidden; + } + + // C-export level items remain at `Default`, all other internal + // items become `Hidden`. + match tcx.reachable_non_generics(id.krate).get(&id) { + Some(SymbolExportLevel::C) => Visibility::Default, + _ => Visibility::Hidden, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/merging.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/merging.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/merging.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/merging.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,111 @@ +use std::cmp; + +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder}; +use rustc_span::symbol::{Symbol, SymbolStr}; + +use super::PartitioningCx; +use crate::partitioning::PreInliningPartitioning; + +pub fn merge_codegen_units<'tcx>( + cx: &PartitioningCx<'_, 'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, +) { + assert!(cx.target_cgu_count >= 1); + let codegen_units = &mut initial_partitioning.codegen_units; + + // Note that at this point in time the `codegen_units` here may not be in a + // deterministic order (but we know they're deterministically the same set). + // We want this merging to produce a deterministic ordering of codegen units + // from the input. + // + // Due to basically how we've implemented the merging below (merge the two + // smallest into each other) we're sure to start off with a deterministic + // order (sorted by name). This'll mean that if two cgus have the same size + // the stable sort below will keep everything nice and deterministic. + codegen_units.sort_by_cached_key(|cgu| cgu.name().as_str()); + + // This map keeps track of what got merged into what. + let mut cgu_contents: FxHashMap> = + codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect(); + + // Merge the two smallest codegen units until the target size is reached. + while codegen_units.len() > cx.target_cgu_count { + // Sort small cgus to the back + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + let mut smallest = codegen_units.pop().unwrap(); + let second_smallest = codegen_units.last_mut().unwrap(); + + // Move the mono-items from `smallest` to `second_smallest` + second_smallest.modify_size_estimate(smallest.size_estimate()); + for (k, v) in smallest.items_mut().drain() { + second_smallest.items_mut().insert(k, v); + } + + // Record that `second_smallest` now contains all the stuff that was in + // `smallest` before. + let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); + cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); + + debug!( + "CodegenUnit {} merged into CodegenUnit {}", + smallest.name(), + second_smallest.name() + ); + } + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + + if cx.tcx.sess.opts.incremental.is_some() { + // If we are doing incremental compilation, we want CGU names to + // reflect the path of the source level module they correspond to. + // For CGUs that contain the code of multiple modules because of the + // merging done above, we use a concatenation of the names of + // all contained CGUs. + let new_cgu_names: FxHashMap = cgu_contents + .into_iter() + // This `filter` makes sure we only update the name of CGUs that + // were actually modified by merging. + .filter(|(_, cgu_contents)| cgu_contents.len() > 1) + .map(|(current_cgu_name, cgu_contents)| { + let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| &s[..]).collect(); + + // Sort the names, so things are deterministic and easy to + // predict. + + // We are sorting primitive &strs here so we can use unstable sort + cgu_contents.sort_unstable(); + + (current_cgu_name, cgu_contents.join("--")) + }) + .collect(); + + for cgu in codegen_units.iter_mut() { + if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { + if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names { + cgu.set_name(Symbol::intern(&new_cgu_name)); + } else { + // If we don't require CGU names to be human-readable, we + // use a fixed length hash of the composite CGU name + // instead. + let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); + cgu.set_name(Symbol::intern(&new_cgu_name)); + } + } + } + } else { + // If we are compiling non-incrementally we just generate simple CGU + // names containing an index. + for (index, cgu) in codegen_units.iter_mut().enumerate() { + cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index)); + } + } +} + +fn numbered_codegen_unit_name( + name_builder: &mut CodegenUnitNameBuilder<'_>, + index: usize, +) -> Symbol { + name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)) +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/partitioning/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,466 @@ +//! Partitioning Codegen Units for Incremental Compilation +//! ====================================================== +//! +//! The task of this module is to take the complete set of monomorphizations of +//! a crate and produce a set of codegen units from it, where a codegen unit +//! is a named set of (mono-item, linkage) pairs. That is, this module +//! decides which monomorphization appears in which codegen units with which +//! linkage. The following paragraphs describe some of the background on the +//! partitioning scheme. +//! +//! The most important opportunity for saving on compilation time with +//! incremental compilation is to avoid re-codegenning and re-optimizing code. +//! Since the unit of codegen and optimization for LLVM is "modules" or, how +//! we call them "codegen units", the particulars of how much time can be saved +//! by incremental compilation are tightly linked to how the output program is +//! partitioned into these codegen units prior to passing it to LLVM -- +//! especially because we have to treat codegen units as opaque entities once +//! they are created: There is no way for us to incrementally update an existing +//! LLVM module and so we have to build any such module from scratch if it was +//! affected by some change in the source code. +//! +//! From that point of view it would make sense to maximize the number of +//! codegen units by, for example, putting each function into its own module. +//! That way only those modules would have to be re-compiled that were actually +//! affected by some change, minimizing the number of functions that could have +//! been re-used but just happened to be located in a module that is +//! re-compiled. +//! +//! However, since LLVM optimization does not work across module boundaries, +//! using such a highly granular partitioning would lead to very slow runtime +//! code since it would effectively prohibit inlining and other inter-procedure +//! optimizations. We want to avoid that as much as possible. +//! +//! Thus we end up with a trade-off: The bigger the codegen units, the better +//! LLVM's optimizer can do its work, but also the smaller the compilation time +//! reduction we get from incremental compilation. +//! +//! Ideally, we would create a partitioning such that there are few big codegen +//! units with few interdependencies between them. For now though, we use the +//! following heuristic to determine the partitioning: +//! +//! - There are two codegen units for every source-level module: +//! - One for "stable", that is non-generic, code +//! - One for more "volatile" code, i.e., monomorphized instances of functions +//! defined in that module +//! +//! In order to see why this heuristic makes sense, let's take a look at when a +//! codegen unit can get invalidated: +//! +//! 1. The most straightforward case is when the BODY of a function or global +//! changes. Then any codegen unit containing the code for that item has to be +//! re-compiled. Note that this includes all codegen units where the function +//! has been inlined. +//! +//! 2. The next case is when the SIGNATURE of a function or global changes. In +//! this case, all codegen units containing a REFERENCE to that item have to be +//! re-compiled. This is a superset of case 1. +//! +//! 3. The final and most subtle case is when a REFERENCE to a generic function +//! is added or removed somewhere. Even though the definition of the function +//! might be unchanged, a new REFERENCE might introduce a new monomorphized +//! instance of this function which has to be placed and compiled somewhere. +//! Conversely, when removing a REFERENCE, it might have been the last one with +//! that particular set of generic arguments and thus we have to remove it. +//! +//! From the above we see that just using one codegen unit per source-level +//! module is not such a good idea, since just adding a REFERENCE to some +//! generic item somewhere else would invalidate everything within the module +//! containing the generic item. The heuristic above reduces this detrimental +//! side-effect of references a little by at least not touching the non-generic +//! code of the module. +//! +//! A Note on Inlining +//! ------------------ +//! As briefly mentioned above, in order for LLVM to be able to inline a +//! function call, the body of the function has to be available in the LLVM +//! module where the call is made. This has a few consequences for partitioning: +//! +//! - The partitioning algorithm has to take care of placing functions into all +//! codegen units where they should be available for inlining. It also has to +//! decide on the correct linkage for these functions. +//! +//! - The partitioning algorithm has to know which functions are likely to get +//! inlined, so it can distribute function instantiations accordingly. Since +//! there is no way of knowing for sure which functions LLVM will decide to +//! inline in the end, we apply a heuristic here: Only functions marked with +//! `#[inline]` are considered for inlining by the partitioner. The current +//! implementation will not try to determine if a function is likely to be +//! inlined by looking at the functions definition. +//! +//! Note though that as a side-effect of creating a codegen units per +//! source-level module, functions from the same module will be available for +//! inlining, even when they are not marked `#[inline]`. + +mod default; +mod merging; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync; +use rustc_hir::def_id::DefIdSet; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::mir::mono::{CodegenUnit, Linkage}; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::Symbol; + +use crate::collector::InliningMap; +use crate::collector::{self, MonoItemCollectionMode}; + +pub struct PartitioningCx<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + target_cgu_count: usize, + inlining_map: &'a InliningMap<'tcx>, +} + +trait Partitioner<'tcx> { + fn place_root_mono_items( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + mono_items: &mut dyn Iterator>, + ) -> PreInliningPartitioning<'tcx>; + + fn merge_codegen_units( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, + ); + + fn place_inlined_mono_items( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + initial_partitioning: PreInliningPartitioning<'tcx>, + ) -> PostInliningPartitioning<'tcx>; + + fn internalize_symbols( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + partitioning: &mut PostInliningPartitioning<'tcx>, + ); +} + +fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box> { + let strategy = match &tcx.sess.opts.debugging_opts.cgu_partitioning_strategy { + None => "default", + Some(s) => &s[..], + }; + + match strategy { + "default" => Box::new(default::DefaultPartitioning), + _ => tcx.sess.fatal("unknown partitioning strategy"), + } +} + +pub fn partition<'tcx>( + tcx: TyCtxt<'tcx>, + mono_items: &mut dyn Iterator>, + max_cgu_count: usize, + inlining_map: &InliningMap<'tcx>, +) -> Vec> { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); + + let mut partitioner = get_partitioner(tcx); + let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; + // In the first step, we place all regular monomorphizations into their + // respective 'home' codegen unit. Regular monomorphizations are all + // functions and statics defined in the local crate. + let mut initial_partitioning = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); + partitioner.place_root_mono_items(cx, mono_items) + }; + + initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + + debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); + + // Merge until we have at most `max_cgu_count` codegen units. + { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); + partitioner.merge_codegen_units(cx, &mut initial_partitioning); + debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); + } + + // In the next step, we use the inlining map to determine which additional + // monomorphizations have to go into each codegen unit. These additional + // monomorphizations can be drop-glue, functions from external crates, and + // local functions the definition of which is marked with `#[inline]`. + let mut post_inlining = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); + partitioner.place_inlined_mono_items(cx, initial_partitioning) + }; + + post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + + debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); + + // Next we try to make as many symbols "internal" as possible, so LLVM has + // more freedom to optimize. + if !tcx.sess.link_dead_code() { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); + partitioner.internalize_symbols(cx, &mut post_inlining); + } + + // Finally, sort by codegen unit name, so that we get deterministic results. + let PostInliningPartitioning { + codegen_units: mut result, + mono_item_placements: _, + internalization_candidates: _, + } = post_inlining; + + result.sort_by_cached_key(|cgu| cgu.name().as_str()); + + result +} + +pub struct PreInliningPartitioning<'tcx> { + codegen_units: Vec>, + roots: FxHashSet>, + internalization_candidates: FxHashSet>, +} + +/// For symbol internalization, we need to know whether a symbol/mono-item is +/// accessed from outside the codegen unit it is defined in. This type is used +/// to keep track of that. +#[derive(Clone, PartialEq, Eq, Debug)] +enum MonoItemPlacement { + SingleCgu { cgu_name: Symbol }, + MultipleCgus, +} + +struct PostInliningPartitioning<'tcx> { + codegen_units: Vec>, + mono_item_placements: FxHashMap, MonoItemPlacement>, + internalization_candidates: FxHashSet>, +} + +fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I) +where + I: Iterator>, + 'tcx: 'a, +{ + let dump = move || { + use std::fmt::Write; + + let s = &mut String::new(); + let _ = writeln!(s, "{}", label); + for cgu in cgus { + let _ = + writeln!(s, "CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate()); + + for (mono_item, linkage) in cgu.items() { + let symbol_name = mono_item.symbol_name(tcx).name; + let symbol_hash_start = symbol_name.rfind('h'); + let symbol_hash = symbol_hash_start.map_or("", |i| &symbol_name[i..]); + + let _ = writeln!( + s, + " - {} [{:?}] [{}] estimated size {}", + mono_item, + linkage, + symbol_hash, + mono_item.size_estimate(tcx) + ); + } + + let _ = writeln!(s, ""); + } + + std::mem::take(s) + }; + + debug!("{}", dump()); +} + +#[inline(never)] // give this a place in the profiler +fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) +where + I: Iterator>, + 'tcx: 'a, +{ + let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct"); + + let mut symbols: Vec<_> = + mono_items.map(|mono_item| (mono_item, mono_item.symbol_name(tcx))).collect(); + + symbols.sort_by_key(|sym| sym.1); + + for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() { + if sym1 == sym2 { + let span1 = mono_item1.local_span(tcx); + let span2 = mono_item2.local_span(tcx); + + // Deterministically select one of the spans for error reporting + let span = match (span1, span2) { + (Some(span1), Some(span2)) => { + Some(if span1.lo().0 > span2.lo().0 { span1 } else { span2 }) + } + (span1, span2) => span1.or(span2), + }; + + let error_message = format!("symbol `{}` is already defined", sym1); + + if let Some(span) = span { + tcx.sess.span_fatal(span, &error_message) + } else { + tcx.sess.fatal(&error_message) + } + } + } +} + +fn collect_and_partition_mono_items<'tcx>( + tcx: TyCtxt<'tcx>, + (): (), +) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { + let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { + Some(ref s) => { + let mode_string = s.to_lowercase(); + let mode_string = mode_string.trim(); + if mode_string == "eager" { + MonoItemCollectionMode::Eager + } else { + if mode_string != "lazy" { + let message = format!( + "Unknown codegen-item collection mode '{}'. \ + Falling back to 'lazy' mode.", + mode_string + ); + tcx.sess.warn(&message); + } + + MonoItemCollectionMode::Lazy + } + } + None => { + if tcx.sess.link_dead_code() { + MonoItemCollectionMode::Eager + } else { + MonoItemCollectionMode::Lazy + } + } + }; + + let (items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode); + + tcx.sess.abort_if_errors(); + + let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || { + sync::join( + || { + let mut codegen_units = partition( + tcx, + &mut items.iter().cloned(), + tcx.sess.codegen_units(), + &inlining_map, + ); + codegen_units[0].make_primary(); + &*tcx.arena.alloc_from_iter(codegen_units) + }, + || assert_symbols_are_distinct(tcx, items.iter()), + ) + }); + + let mono_items: DefIdSet = items + .iter() + .filter_map(|mono_item| match *mono_item { + MonoItem::Fn(ref instance) => Some(instance.def_id()), + MonoItem::Static(def_id) => Some(def_id), + _ => None, + }) + .collect(); + + if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { + let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); + + for cgu in codegen_units { + for (&mono_item, &linkage) in cgu.items() { + item_to_cgus.entry(mono_item).or_default().push((cgu.name(), linkage)); + } + } + + let mut item_keys: Vec<_> = items + .iter() + .map(|i| { + let mut output = with_no_trimmed_paths(|| i.to_string()); + output.push_str(" @@"); + let mut empty = Vec::new(); + let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); + cgus.sort_by_key(|(name, _)| *name); + cgus.dedup(); + for &(ref cgu_name, (linkage, _)) in cgus.iter() { + output.push(' '); + output.push_str(&cgu_name.as_str()); + + let linkage_abbrev = match linkage { + Linkage::External => "External", + Linkage::AvailableExternally => "Available", + Linkage::LinkOnceAny => "OnceAny", + Linkage::LinkOnceODR => "OnceODR", + Linkage::WeakAny => "WeakAny", + Linkage::WeakODR => "WeakODR", + Linkage::Appending => "Appending", + Linkage::Internal => "Internal", + Linkage::Private => "Private", + Linkage::ExternalWeak => "ExternalWeak", + Linkage::Common => "Common", + }; + + output.push('['); + output.push_str(linkage_abbrev); + output.push(']'); + } + output + }) + .collect(); + + item_keys.sort(); + + for item in item_keys { + println!("MONO_ITEM {}", item); + } + } + + (tcx.arena.alloc(mono_items), codegen_units) +} + +fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSet { + let (items, cgus) = tcx.collect_and_partition_mono_items(()); + let mut visited = DefIdSet::default(); + let mut result = items.clone(); + + for cgu in cgus { + for (item, _) in cgu.items() { + if let MonoItem::Fn(ref instance) = item { + let did = instance.def_id(); + if !visited.insert(did) { + continue; + } + for scope in &tcx.instance_mir(instance.def).source_scopes { + if let Some((ref inlined, _)) = scope.inlined { + result.insert(inlined.def_id()); + } + } + } + } + } + + tcx.arena.alloc(result) +} + +pub fn provide(providers: &mut Providers) { + providers.collect_and_partition_mono_items = collect_and_partition_mono_items; + providers.codegened_and_inlined_items = codegened_and_inlined_items; + + providers.is_codegened_item = |tcx, def_id| { + let (all_mono_items, _) = tcx.collect_and_partition_mono_items(()); + all_mono_items.contains(&def_id) + }; + + providers.codegen_unit = |tcx, name| { + let (_, all) = tcx.collect_and_partition_mono_items(()); + all.iter() + .find(|cgu| cgu.name() == name) + .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name)) + }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/polymorphize.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/polymorphize.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/polymorphize.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/polymorphize.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,392 @@ +//! Polymorphization Analysis +//! ========================= +//! +//! This module implements an analysis of functions, methods and closures to determine which +//! generic parameters are unused (and eventually, in what ways generic parameters are used - only +//! for their size, offset of a field, etc.). + +use rustc_hir::{def::DefKind, def_id::DefId, ConstContext}; +use rustc_index::bit_set::FiniteBitSet; +use rustc_middle::mir::{ + visit::{TyContext, Visitor}, + Local, LocalDecl, Location, +}; +use rustc_middle::ty::{ + self, + fold::{TypeFoldable, TypeVisitor}, + query::Providers, + subst::SubstsRef, + Const, Ty, TyCtxt, +}; +use rustc_span::symbol::sym; +use std::convert::TryInto; +use std::ops::ControlFlow; + +/// Provide implementations of queries relating to polymorphization analysis. +pub fn provide(providers: &mut Providers) { + providers.unused_generic_params = unused_generic_params; +} + +/// Determine which generic parameters are used by the instance. +/// +/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all +/// parameters are used). +#[instrument(level = "debug", skip(tcx))] +fn unused_generic_params<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, +) -> FiniteBitSet { + if !tcx.sess.opts.debugging_opts.polymorphize { + // If polymorphization disabled, then all parameters are used. + return FiniteBitSet::new_empty(); + } + + let def_id = instance.def_id(); + // Exit early if this instance should not be polymorphized. + if !should_polymorphize(tcx, def_id, instance) { + return FiniteBitSet::new_empty(); + } + + let generics = tcx.generics_of(def_id); + debug!(?generics); + + // Exit early when there are no parameters to be unused. + if generics.count() == 0 { + return FiniteBitSet::new_empty(); + } + + // Create a bitset with N rightmost ones for each parameter. + let generics_count: u32 = + generics.count().try_into().expect("more generic parameters than can fit into a `u32`"); + let mut unused_parameters = FiniteBitSet::::new_empty(); + unused_parameters.set_range(0..generics_count); + debug!(?unused_parameters, "(start)"); + + mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); + debug!(?unused_parameters, "(after default)"); + + // Visit MIR and accumululate used generic parameters. + let body = match tcx.hir().body_const_context(def_id.expect_local()) { + // Const functions are actually called and should thus be considered for polymorphization + // via their runtime MIR. + Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id), + Some(_) => tcx.mir_for_ctfe(def_id), + }; + let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters }; + vis.visit_body(body); + debug!(?unused_parameters, "(end)"); + + // Emit errors for debugging and testing if enabled. + if !unused_parameters.is_empty() { + emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters); + } + + unused_parameters +} + +/// Returns `true` if the instance should be polymorphized. +fn should_polymorphize<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + instance: ty::InstanceDef<'tcx>, +) -> bool { + // If an instance's MIR body is not polymorphic then the modified substitutions that are + // derived from polymorphization's result won't make any difference. + if !instance.has_polymorphic_mir_body() { + return false; + } + + // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic. + if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) { + return false; + } + + // Polymorphization results are stored in cross-crate metadata only when there are unused + // parameters, so assume that non-local items must have only used parameters (else this query + // would not be invoked, and the cross-crate metadata used instead). + if !def_id.is_local() { + return false; + } + + // Foreign items have no bodies to analyze. + if tcx.is_foreign_item(def_id) { + return false; + } + + // Make sure there is MIR available. + match tcx.hir().body_const_context(def_id.expect_local()) { + Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => { + debug!("no mir available"); + return false; + } + Some(_) if !tcx.is_ctfe_mir_available(def_id) => { + debug!("no ctfe mir available"); + return false; + } + _ => true, + } +} + +/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy +/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should +/// be `true` if the item that `unused_generic_params` was invoked on is a closure. +#[instrument(level = "debug", skip(tcx, def_id, generics, unused_parameters))] +fn mark_used_by_default_parameters<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + generics: &'tcx ty::Generics, + unused_parameters: &mut FiniteBitSet, +) { + match tcx.def_kind(def_id) { + DefKind::Closure | DefKind::Generator => { + for param in &generics.params { + debug!(?param, "(closure/gen)"); + unused_parameters.clear(param.index); + } + } + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Fn + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static + | DefKind::Ctor(_, _) + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::OpaqueTy + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Impl => { + for param in &generics.params { + debug!(?param, "(other)"); + if let ty::GenericParamDefKind::Lifetime = param.kind { + unused_parameters.clear(param.index); + } + } + } + } + + if let Some(parent) = generics.parent { + mark_used_by_default_parameters(tcx, parent, tcx.generics_of(parent), unused_parameters); + } +} + +/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic +/// parameter which was unused. +#[instrument(level = "debug", skip(tcx, generics))] +fn emit_unused_generic_params_error<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + generics: &'tcx ty::Generics, + unused_parameters: &FiniteBitSet, +) { + let base_def_id = tcx.closure_base_def_id(def_id); + if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) { + return; + } + + let fn_span = match tcx.opt_item_name(def_id) { + Some(ident) => ident.span, + _ => tcx.def_span(def_id), + }; + + let mut err = tcx.sess.struct_span_err(fn_span, "item has unused generic parameters"); + + let mut next_generics = Some(generics); + while let Some(generics) = next_generics { + for param in &generics.params { + if unused_parameters.contains(param.index).unwrap_or(false) { + debug!(?param); + let def_span = tcx.def_span(param.def_id); + err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name)); + } + } + + next_generics = generics.parent.map(|did| tcx.generics_of(did)); + } + + err.emit(); +} + +/// Visitor used to aggregate generic parameter uses. +struct MarkUsedGenericParams<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + def_id: DefId, + unused_parameters: &'a mut FiniteBitSet, +} + +impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { + /// Invoke `unused_generic_params` on a body contained within the current item (e.g. + /// a closure, generator or constant). + #[instrument(level = "debug", skip(self, def_id, substs))] + fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) { + let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let unused = self.tcx.unused_generic_params(instance); + debug!(?self.unused_parameters, ?unused); + for (i, arg) in substs.iter().enumerate() { + let i = i.try_into().unwrap(); + if !unused.contains(i).unwrap_or(false) { + arg.visit_with(self); + } + } + debug!(?self.unused_parameters); + } +} + +impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { + #[instrument(level = "debug", skip(self, local))] + fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { + if local == Local::from_usize(1) { + let def_kind = self.tcx.def_kind(self.def_id); + if matches!(def_kind, DefKind::Closure | DefKind::Generator) { + // Skip visiting the closure/generator that is currently being processed. This only + // happens because the first argument to the closure is a reference to itself and + // that will call `visit_substs`, resulting in each generic parameter captured being + // considered used by default. + debug!("skipping closure substs"); + return; + } + } + + self.super_local_decl(local, local_decl); + } + + fn visit_const(&mut self, c: &&'tcx Const<'tcx>, _: Location) { + c.visit_with(self); + } + + fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) { + ty.visit_with(self); + } +} + +impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + #[instrument(level = "debug", skip(self))] + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { + if !c.potentially_has_param_types_or_consts() { + return ControlFlow::CONTINUE; + } + + match c.val { + ty::ConstKind::Param(param) => { + debug!(?param); + self.unused_parameters.clear(param.index); + ControlFlow::CONTINUE + } + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: Some(p)}) + // Avoid considering `T` unused when constants are of the form: + // `>::foo::promoted[p]` + if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self => + { + // If there is a promoted, don't look at the substs - since it will always contain + // the generic parameters, instead, traverse the promoted MIR. + let promoted = self.tcx.promoted_mir(def.did); + self.visit_body(&promoted[p]); + ControlFlow::CONTINUE + } + ty::ConstKind::Unevaluated(uv) + if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst => + { + self.visit_child_body(uv.def.did, uv.substs(self.tcx)); + ControlFlow::CONTINUE + } + _ => c.super_visit_with(self), + } + } + + #[instrument(level = "debug", skip(self))] + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + if !ty.potentially_has_param_types_or_consts() { + return ControlFlow::CONTINUE; + } + + match *ty.kind() { + ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => { + debug!(?def_id); + // Avoid cycle errors with generators. + if def_id == self.def_id { + return ControlFlow::CONTINUE; + } + + // Consider any generic parameters used by any closures/generators as used in the + // parent. + self.visit_child_body(def_id, substs); + ControlFlow::CONTINUE + } + ty::Param(param) => { + debug!(?param); + self.unused_parameters.clear(param.index); + ControlFlow::CONTINUE + } + _ => ty.super_visit_with(self), + } + } +} + +/// Visitor used to check if a generic parameter is used. +struct HasUsedGenericParams<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + unused_parameters: &'a FiniteBitSet, +} + +impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { + type BreakTy = (); + + fn tcx_for_anon_const_substs(&self) -> Option> { + Some(self.tcx) + } + + #[instrument(level = "debug", skip(self))] + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { + if !c.potentially_has_param_types_or_consts() { + return ControlFlow::CONTINUE; + } + + match c.val { + ty::ConstKind::Param(param) => { + if self.unused_parameters.contains(param.index).unwrap_or(false) { + ControlFlow::CONTINUE + } else { + ControlFlow::BREAK + } + } + _ => c.super_visit_with(self), + } + } + + #[instrument(level = "debug", skip(self))] + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + if !ty.potentially_has_param_types_or_consts() { + return ControlFlow::CONTINUE; + } + + match ty.kind() { + ty::Param(param) => { + if self.unused_parameters.contains(param.index).unwrap_or(false) { + ControlFlow::CONTINUE + } else { + ControlFlow::BREAK + } + } + _ => ty.super_visit_with(self), + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_monomorphize/src/util.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_monomorphize/src/util.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,73 @@ +use rustc_middle::ty::{self, ClosureSizeProfileData, Instance, TyCtxt}; +use std::fs::OpenOptions; +use std::io::prelude::*; + +/// For a given closure, writes out the data for the profiling the impact of RFC 2229 on +/// closure size into a CSV. +/// +/// During the same compile all closures dump the information in the same file +/// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked. +crate fn dump_closure_profile(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) { + let mut file = if let Ok(file) = OpenOptions::new() + .create(true) + .append(true) + .open(&format!("closure_profile_{}.csv", std::process::id())) + { + file + } else { + eprintln!("Cound't open file for writing closure profile"); + return; + }; + + let closure_def_id = closure_instance.def_id(); + let typeck_results = tcx.typeck(closure_def_id.expect_local()); + + if typeck_results.closure_size_eval.contains_key(&closure_def_id) { + let param_env = ty::ParamEnv::reveal_all(); + + let ClosureSizeProfileData { before_feature_tys, after_feature_tys } = + typeck_results.closure_size_eval[&closure_def_id]; + + let before_feature_tys = tcx.subst_and_normalize_erasing_regions( + closure_instance.substs, + param_env, + before_feature_tys, + ); + let after_feature_tys = tcx.subst_and_normalize_erasing_regions( + closure_instance.substs, + param_env, + after_feature_tys, + ); + + let new_size = tcx + .layout_of(param_env.and(after_feature_tys)) + .map(|l| format!("{:?}", l.size.bytes())) + .unwrap_or_else(|e| format!("Failed {:?}", e)); + + let old_size = tcx + .layout_of(param_env.and(before_feature_tys)) + .map(|l| format!("{:?}", l.size.bytes())) + .unwrap_or_else(|e| format!("Failed {:?}", e)); + + let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + let closure_span = tcx.hir().span(closure_hir_id); + let src_file = tcx.sess.source_map().span_to_filename(closure_span); + let line_nos = tcx + .sess + .source_map() + .span_to_lines(closure_span) + .map(|l| format!("{:?} {:?}", l.lines.first(), l.lines.last())) + .unwrap_or_else(|e| format!("{:?}", e)); + + if let Err(e) = writeln!( + file, + "{}, {}, {}, {:?}", + old_size, + new_size, + src_file.prefer_local(), + line_nos + ) { + eprintln!("Error writting to file {}", e.to_string()) + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_parse" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false @@ -18,3 +18,4 @@ rustc_span = { path = "../rustc_span" } rustc_ast = { path = "../rustc_ast" } unicode-normalization = "0.1.11" +unicode-width = "0.1.4" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/lexer/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/lexer/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/lexer/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/lexer/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,9 @@ use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; -use rustc_session::lint::builtin::RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX; +use rustc_session::lint::builtin::{ + TEXT_DIRECTION_CODEPOINT_IN_COMMENT, RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, +}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; @@ -129,6 +131,28 @@ .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c))) } + /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly + /// complain about it. + fn lint_unicode_text_flow(&self, start: BytePos) { + // Opening delimiter of the length 2 is not included into the comment text. + let content_start = start + BytePos(2); + let content = self.str_from(content_start); + let span = self.mk_sp(start, self.pos); + const UNICODE_TEXT_FLOW_CHARS: &[char] = &[ + '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', + '\u{202C}', '\u{2069}', + ]; + if content.contains(UNICODE_TEXT_FLOW_CHARS) { + self.sess.buffer_lint_with_diagnostic( + &TEXT_DIRECTION_CODEPOINT_IN_COMMENT, + span, + ast::CRATE_NODE_ID, + "unicode codepoint changing visible direction of text present in comment", + BuiltinLintDiagnostics::UnicodeTextFlow(span, content.to_string()), + ); + } + } + /// Turns simple `rustc_lexer::TokenKind` enum into a rich /// `rustc_ast::TokenKind`. This turns strings into interned /// symbols and runs additional validation. @@ -136,7 +160,12 @@ Some(match token { rustc_lexer::TokenKind::LineComment { doc_style } => { // Skip non-doc comments - let doc_style = doc_style?; + let doc_style = if let Some(doc_style) = doc_style { + doc_style + } else { + self.lint_unicode_text_flow(start); + return None; + }; // Opening delimiter of the length 3 is not included into the symbol. let content_start = start + BytePos(3); @@ -158,7 +187,12 @@ } // Skip non-doc comments - let doc_style = doc_style?; + let doc_style = if let Some(doc_style) = doc_style { + doc_style + } else { + self.lint_unicode_text_flow(start); + return None; + }; // Opening delimiter of the length 3 and closing delimiter of the length 2 // are not included into the symbol. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ use std::iter::once; use std::ops::Range; -use rustc_errors::{Applicability, Handler}; +use rustc_errors::{pluralize, Applicability, Handler}; use rustc_lexer::unescape::{EscapeError, Mode}; use rustc_span::{BytePos, Span}; @@ -49,24 +49,57 @@ .emit(); } EscapeError::MoreThanOneChar => { - let (prefix, msg) = if mode.is_bytes() { - ("b", "if you meant to write a byte string literal, use double quotes") - } else { - ("", "if you meant to write a `str` literal, use double quotes") - }; + use unicode_normalization::{char::is_combining_mark, UnicodeNormalization}; - handler - .struct_span_err( - span_with_quotes, - "character literal may only contain one codepoint", - ) - .span_suggestion( + let mut has_help = false; + let mut handler = handler.struct_span_err( + span_with_quotes, + "character literal may only contain one codepoint", + ); + + if lit.chars().skip(1).all(|c| is_combining_mark(c)) { + let escaped_marks = + lit.chars().skip(1).map(|c| c.escape_default().to_string()).collect::>(); + handler.span_note( + span, + &format!( + "this `{}` is followed by the combining mark{} `{}`", + lit.chars().next().unwrap(), + pluralize!(escaped_marks.len()), + escaped_marks.join(""), + ), + ); + let normalized = lit.nfc().to_string(); + if normalized.chars().count() == 1 { + has_help = true; + handler.span_suggestion( + span, + &format!( + "consider using the normalized form `{}` of this character", + normalized.chars().next().unwrap().escape_default() + ), + normalized, + Applicability::MachineApplicable, + ); + } + } + + if !has_help { + let (prefix, msg) = if mode.is_bytes() { + ("b", "if you meant to write a byte string literal, use double quotes") + } else { + ("", "if you meant to write a `str` literal, use double quotes") + }; + + handler.span_suggestion( span_with_quotes, msg, format!("{}\"{}\"", prefix, lit), Applicability::MachineApplicable, - ) - .emit(); + ); + } + + handler.emit(); } EscapeError::EscapeOnlyChar => { let (c, char_span) = last_char(); @@ -154,12 +187,17 @@ assert!(mode.is_bytes()); let (c, span) = last_char(); let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant"); - err.span_label(span, "byte constant must be ASCII"); + let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 { + format!(" but is {:?}", c) + } else { + String::new() + }; + err.span_label(span, &format!("byte constant must be ASCII{}", postfix)); if (c as u32) <= 0xFF { err.span_suggestion( span, &format!( - "if you meant to use the unicode code point for '{}', use a \\xHH escape", + "if you meant to use the unicode code point for {:?}, use a \\xHH escape", c ), format!("\\x{:X}", c as u32), @@ -173,7 +211,7 @@ err.span_suggestion( span, &format!( - "if you meant to use the UTF-8 encoding of '{}', use \\xHH escapes", + "if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes", c ), utf8.as_bytes() @@ -187,10 +225,15 @@ } EscapeError::NonAsciiCharInByteString => { assert!(mode.is_bytes()); - let (_c, span) = last_char(); + let (c, span) = last_char(); + let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 { + format!(" but is {:?}", c) + } else { + String::new() + }; handler .struct_span_err(span, "raw byte string must be ASCII") - .span_label(span, "must be ASCII") + .span_label(span, &format!("must be ASCII{}", postfix)) .emit(); } EscapeError::OutOfRangeHexEscape => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,11 +3,12 @@ #![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] -#![cfg_attr(bootstrap, feature(bindings_after_at))] #![feature(box_patterns)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard #![recursion_limit = "256"] +#[macro_use] +extern crate tracing; + use rustc_ast as ast; use rustc_ast::token::{self, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{self, AttributesData, CanSynthesizeMissingTokens, LazyTokenStream}; @@ -133,7 +134,7 @@ let mut parser = stream_to_parser(sess, stream, None); parser.unclosed_delims = unclosed_delims; if parser.token == token::Eof { - parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); + parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); } Ok(parser) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/attr.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/attr.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/attr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/attr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -use super::{AttrWrapper, Capturing, Parser, PathStyle}; +use super::{AttrWrapper, Capturing, ForceCollect, Parser, PathStyle}; use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Nonterminal}; use rustc_ast_pretty::pprust; -use rustc_errors::{error_code, PResult}; -use rustc_span::{sym, Span}; +use rustc_errors::{error_code, DiagnosticBuilder, PResult}; +use rustc_span::{sym, BytePos, Span}; use std::convert::TryInto; use tracing::debug; @@ -25,6 +25,12 @@ prev_attr_sp: None, }; +enum OuterAttributeType { + DocComment, + DocBlockComment, + Attribute, +} + impl<'a> Parser<'a> { /// Parses attributes that appear before an item. pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { @@ -49,18 +55,32 @@ Some(self.parse_attribute(inner_parse_policy)?) } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { if attr_style != ast::AttrStyle::Outer { - self.sess - .span_diagnostic - .struct_span_err_with_code( - self.token.span, - "expected outer doc comment", - error_code!(E0753), - ) - .note( - "inner doc comments like this (starting with \ - `//!` or `/*!`) can only appear before items", - ) - .emit(); + let span = self.token.span; + let mut err = self.sess.span_diagnostic.struct_span_err_with_code( + span, + "expected outer doc comment", + error_code!(E0753), + ); + if let Some(replacement_span) = self.annotate_following_item_if_applicable( + &mut err, + span, + match comment_kind { + token::CommentKind::Line => OuterAttributeType::DocComment, + token::CommentKind::Block => OuterAttributeType::DocBlockComment, + }, + ) { + err.note( + "inner doc comments like this (starting with `//!` or `/*!`) can \ + only appear before items", + ); + err.span_suggestion_verbose( + replacement_span, + "you might have meant to write a regular comment", + String::new(), + rustc_errors::Applicability::MachineApplicable, + ); + } + err.emit(); } self.bump(); just_parsed_doc_comment = true; @@ -97,7 +117,7 @@ inner_parse_policy, self.token ); let lo = self.token.span; - // Attributse can't have attributes of their own + // Attributes can't have attributes of their own [Editor's note: not with that attitude] self.collect_tokens_no_attrs(|this| { if this.eat(&token::Pound) { let style = if this.eat(&token::Not) { @@ -125,6 +145,75 @@ }) } + fn annotate_following_item_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + attr_type: OuterAttributeType, + ) -> Option { + let mut snapshot = self.clone(); + let lo = span.lo() + + BytePos(match attr_type { + OuterAttributeType::Attribute => 1, + _ => 2, + }); + let hi = lo + BytePos(1); + let replacement_span = span.with_lo(lo).with_hi(hi); + if let OuterAttributeType::DocBlockComment | OuterAttributeType::DocComment = attr_type { + snapshot.bump(); + } + loop { + // skip any other attributes, we want the item + if snapshot.token.kind == token::Pound { + if let Err(mut err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) { + err.cancel(); + return Some(replacement_span); + } + } else { + break; + } + } + match snapshot.parse_item_common( + AttrWrapper::empty(), + true, + false, + |_| true, + ForceCollect::No, + ) { + Ok(Some(item)) => { + let attr_name = match attr_type { + OuterAttributeType::Attribute => "attribute", + _ => "doc comment", + }; + err.span_label( + item.span, + &format!("the inner {} doesn't annotate this {}", attr_name, item.kind.descr()), + ); + err.span_suggestion_verbose( + replacement_span, + &format!( + "to annotate the {}, change the {} from inner to outer style", + item.kind.descr(), + attr_name + ), + (match attr_type { + OuterAttributeType::Attribute => "", + OuterAttributeType::DocBlockComment => "*", + OuterAttributeType::DocComment => "/", + }) + .to_string(), + rustc_errors::Applicability::MachineApplicable, + ); + return None; + } + Err(mut item_err) => { + item_err.cancel(); + } + Ok(None) => {} + } + Some(replacement_span) + } + pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) { if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy { let prev_attr_note = @@ -138,11 +227,20 @@ } diag.note( - "inner attributes, like `#![no_std]`, annotate the item enclosing them, \ - and are usually found at the beginning of source files. \ - Outer attributes, like `#[test]`, annotate the item following them.", - ) - .emit(); + "inner attributes, like `#![no_std]`, annotate the item enclosing them, and \ + are usually found at the beginning of source files", + ); + if self + .annotate_following_item_if_applicable( + &mut diag, + attr_sp, + OuterAttributeType::Attribute, + ) + .is_some() + { + diag.note("outer attributes, like `#[test]`, annotate the item following them"); + }; + diag.emit(); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/attr_wrapper.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/attr_wrapper.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/attr_wrapper.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/attr_wrapper.rs 2021-11-29 19:27:11.000000000 +0000 @@ -34,7 +34,7 @@ // This struct is passed around very frequently, // so make sure it doesn't accidentally get larger -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(AttrWrapper, 16); impl AttrWrapper { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/diagnostics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/diagnostics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/diagnostics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/diagnostics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -277,7 +277,7 @@ self.struct_span_err(sp, &msg) .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl) .emit(); - return Ok(false); + return Ok(true); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(token::Brace) || ( @@ -295,7 +295,7 @@ .span_label(self.token.span, "unexpected token") .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) .emit(); - return Ok(false); + return Ok(true); } } @@ -1334,30 +1334,25 @@ pub(super) fn recover_parens_around_for_head( &mut self, pat: P, - expr: &Expr, begin_paren: Option, ) -> P { match (&self.token.kind, begin_paren) { (token::CloseDelim(token::Paren), Some(begin_par_sp)) => { self.bump(); - let pat_str = self - // Remove the `(` from the span of the pattern: - .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) - .unwrap_or_else(|_| pprust::pat_to_string(&pat)); - - self.struct_span_err(self.prev_token.span, "unexpected closing `)`") - .span_label(begin_par_sp, "opening `(`") - .span_suggestion( - begin_par_sp.to(self.prev_token.span), - "remove parenthesis in `for` loop", - format!("{} in {}", pat_str, pprust::expr_to_string(&expr)), - // With e.g. `for (x) in y)` this would replace `(x) in y)` - // with `x) in y)` which is syntactically invalid. - // However, this is prevented before we get here. - Applicability::MachineApplicable, - ) - .emit(); + self.struct_span_err( + MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]), + "unexpected parenthesis surrounding `for` loop head", + ) + .multipart_suggestion( + "remove parenthesis in `for` loop", + vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())], + // With e.g. `for (x) in y)` this would replace `(x) in y)` + // with `x) in y)` which is syntactically invalid. + // However, this is prevented before we get here. + Applicability::MachineApplicable, + ) + .emit(); // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. pat.and_then(|pat| match pat.kind { @@ -1633,50 +1628,57 @@ { let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)"; - let (ident, self_sugg, param_sugg, type_sugg) = match pat.kind { - PatKind::Ident(_, ident, _) => ( - ident, - format!("self: {}", ident), - format!("{}: TypeName", ident), - format!("_: {}", ident), - ), - // Also catches `fn foo(&a)`. - PatKind::Ref(ref pat, mutab) - if matches!(pat.clone().into_inner().kind, PatKind::Ident(..)) => - { - match pat.clone().into_inner().kind { - PatKind::Ident(_, ident, _) => { - let mutab = mutab.prefix_str(); - ( - ident, - format!("self: &{}{}", mutab, ident), - format!("{}: &{}TypeName", ident, mutab), - format!("_: &{}{}", mutab, ident), - ) + let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span) = + match pat.kind { + PatKind::Ident(_, ident, _) => ( + ident, + "self: ".to_string(), + ": TypeName".to_string(), + "_: ".to_string(), + pat.span.shrink_to_lo(), + pat.span.shrink_to_hi(), + pat.span.shrink_to_lo(), + ), + // Also catches `fn foo(&a)`. + PatKind::Ref(ref inner_pat, mutab) + if matches!(inner_pat.clone().into_inner().kind, PatKind::Ident(..)) => + { + match inner_pat.clone().into_inner().kind { + PatKind::Ident(_, ident, _) => { + let mutab = mutab.prefix_str(); + ( + ident, + "self: ".to_string(), + format!("{}: &{}TypeName", ident, mutab), + "_: ".to_string(), + pat.span.shrink_to_lo(), + pat.span, + pat.span.shrink_to_lo(), + ) + } + _ => unreachable!(), } - _ => unreachable!(), - } - } - _ => { - // Otherwise, try to get a type and emit a suggestion. - if let Some(ty) = pat.to_ty() { - err.span_suggestion_verbose( - pat.span, - "explicitly ignore the parameter name", - format!("_: {}", pprust::ty_to_string(&ty)), - Applicability::MachineApplicable, - ); - err.note(rfc_note); } + _ => { + // Otherwise, try to get a type and emit a suggestion. + if let Some(ty) = pat.to_ty() { + err.span_suggestion_verbose( + pat.span, + "explicitly ignore the parameter name", + format!("_: {}", pprust::ty_to_string(&ty)), + Applicability::MachineApplicable, + ); + err.note(rfc_note); + } - return None; - } - }; + return None; + } + }; // `fn foo(a, b) {}`, `fn foo(a, b) {}` or `fn foo(usize, usize) {}` if first_param { err.span_suggestion( - pat.span, + self_span, "if this is a `self` type, give it a parameter name", self_sugg, Applicability::MaybeIncorrect, @@ -1686,14 +1688,14 @@ // `fn foo(HashMap: TypeName)`. if self.token != token::Lt { err.span_suggestion( - pat.span, + param_span, "if this is a parameter name, give it a type", param_sugg, Applicability::HasPlaceholders, ); } err.span_suggestion( - pat.span, + type_span, "if this is a type, explicitly ignore the parameter name", type_sugg, Applicability::MachineApplicable, @@ -1948,7 +1950,19 @@ } match self.parse_expr_res(Restrictions::CONST_EXPR, None) { Ok(expr) => { - if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() { + // Find a mistake like `MyTrait`. + if token::EqEq == snapshot.token.kind { + err.span_suggestion( + snapshot.token.span, + "if you meant to use an associated type binding, replace `==` with `=`", + "=".to_string(), + Applicability::MaybeIncorrect, + ); + let value = self.mk_expr_err(start.to(expr.span)); + err.emit(); + return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); + } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() + { // Avoid the following output by checking that we consumed a full const arg: // help: expressions must be enclosed in braces to be used as const generic // arguments diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/expr.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/expr.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/expr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/expr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,12 @@ use super::pat::{RecoverColon, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; -use super::{AttrWrapper, BlockMode, ForceCollect, Parser, PathStyle, Restrictions, TokenType}; +use super::{ + AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, TokenType, +}; use super::{SemiColonMode, SeqSep, TokenExpectType, TrailingToken}; use crate::maybe_recover_from_interpolated_ty_qpath; +use ast::token::DelimToken; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::Spacing; @@ -91,6 +94,8 @@ /// Parses an expression. #[inline] pub fn parse_expr(&mut self) -> PResult<'a, P> { + self.current_closure.take(); + self.parse_expr_res(Restrictions::empty(), None) } @@ -516,6 +521,26 @@ token::BinOp(token::And) | token::AndAnd => { make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo)) } + token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => { + let mut err = this.struct_span_err(lo, "leading `+` is not supported"); + err.span_label(lo, "unexpected `+`"); + + // a block on the LHS might have been intended to be an expression instead + if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) { + this.sess.expr_parentheses_needed(&mut err, *sp); + } else { + err.span_suggestion_verbose( + lo, + "try removing the `+`", + "".to_string(), + Applicability::MachineApplicable, + ); + } + err.emit(); + + this.bump(); + this.parse_prefix_expr(None) + } // `+expr` token::Ident(..) if this.token.is_keyword(kw::Box) => { make_it!(this, attrs, |this, _| this.parse_box_expr(lo)) } @@ -882,6 +907,12 @@ } } + fn look_ahead_type_ascription_as_field(&mut self) -> bool { + self.look_ahead(1, |t| t.is_ident()) + && self.look_ahead(2, |t| t == &token::Colon) + && self.look_ahead(3, |t| t.can_begin_expr()) + } + fn parse_dot_suffix_expr(&mut self, lo: Span, base: P) -> PResult<'a, P> { match self.token.uninterpolate().kind { token::Ident(..) => self.parse_dot_suffix(base, lo), @@ -1031,12 +1062,77 @@ /// Parse a function call expression, `expr(...)`. fn parse_fn_call_expr(&mut self, lo: Span, fun: P) -> P { - let seq = self.parse_paren_expr_seq().map(|args| { + let snapshot = if self.token.kind == token::OpenDelim(token::Paren) + && self.look_ahead_type_ascription_as_field() + { + Some((self.clone(), fun.kind.clone())) + } else { + None + }; + let open_paren = self.token.span; + + let mut seq = self.parse_paren_expr_seq().map(|args| { self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args), AttrVec::new()) }); + if let Some(expr) = + self.maybe_recover_struct_lit_bad_delims(lo, open_paren, &mut seq, snapshot) + { + return expr; + } self.recover_seq_parse_error(token::Paren, lo, seq) } + /// If we encounter a parser state that looks like the user has written a `struct` literal with + /// parentheses instead of braces, recover the parser state and provide suggestions. + #[instrument(skip(self, seq, snapshot), level = "trace")] + fn maybe_recover_struct_lit_bad_delims( + &mut self, + lo: Span, + open_paren: Span, + seq: &mut PResult<'a, P>, + snapshot: Option<(Self, ExprKind)>, + ) -> Option> { + match (seq.as_mut(), snapshot) { + (Err(ref mut err), Some((mut snapshot, ExprKind::Path(None, path)))) => { + let name = pprust::path_to_string(&path); + snapshot.bump(); // `(` + match snapshot.parse_struct_fields(path, false, token::Paren) { + Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => { + // We have are certain we have `Enum::Foo(a: 3, b: 4)`, suggest + // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`. + *self = snapshot; + let close_paren = self.prev_token.span; + let span = lo.to(self.prev_token.span); + err.cancel(); + self.struct_span_err( + span, + "invalid `struct` delimiters or `fn` call arguments", + ) + .multipart_suggestion( + &format!("if `{}` is a struct, use braces as delimiters", name), + vec![(open_paren, " { ".to_string()), (close_paren, " }".to_string())], + Applicability::MaybeIncorrect, + ) + .multipart_suggestion( + &format!("if `{}` is a function, use the arguments directly", name), + fields + .into_iter() + .map(|field| (field.span.until(field.expr.span), String::new())) + .collect(), + Applicability::MaybeIncorrect, + ) + .emit(); + return Some(self.mk_expr_err(span)); + } + Ok(_) => {} + Err(mut err) => err.emit(), + } + } + _ => {} + } + None + } + /// Parse an indexing expression `expr[...]`. fn parse_index_expr(&mut self, lo: Span, base: P) -> PResult<'a, P> { self.bump(); // `[` @@ -1109,7 +1205,7 @@ } else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) { self.parse_closure_expr(attrs) } else if self.check(&token::OpenDelim(token::Bracket)) { - self.parse_array_or_repeat_expr(attrs) + self.parse_array_or_repeat_expr(attrs, token::Bracket) } else if self.check_path() { self.parse_path_start_expr(attrs) } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { @@ -1227,11 +1323,15 @@ self.maybe_recover_from_bad_qpath(expr, true) } - fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn parse_array_or_repeat_expr( + &mut self, + attrs: AttrVec, + close_delim: token::DelimToken, + ) -> PResult<'a, P> { let lo = self.token.span; - self.bump(); // `[` + self.bump(); // `[` or other open delim - let close = &token::CloseDelim(token::Bracket); + let close = &token::CloseDelim(close_delim); let kind = if self.eat(close) { // Empty vector ExprKind::Array(Vec::new()) @@ -1468,6 +1568,20 @@ pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { self.parse_opt_lit().ok_or_else(|| { + if let token::Interpolated(inner) = &self.token.kind { + let expr = match inner.as_ref() { + token::NtExpr(expr) => Some(expr), + token::NtLiteral(expr) => Some(expr), + _ => None, + }; + if let Some(expr) = expr { + if matches!(expr.kind, ExprKind::Err) { + self.diagnostic() + .delay_span_bug(self.token.span, &"invalid interpolated expression"); + return self.diagnostic().struct_dummy(); + } + } + } let msg = format!("unexpected token: {}", super::token_descr(&self.token)); self.struct_span_err(self.token.span, &msg) }) @@ -1657,6 +1771,46 @@ } } + fn is_array_like_block(&mut self) -> bool { + self.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_))) + && self.look_ahead(2, |t| t == &token::Comma) + && self.look_ahead(3, |t| t.can_begin_expr()) + } + + /// Emits a suggestion if it looks like the user meant an array but + /// accidentally used braces, causing the code to be interpreted as a block + /// expression. + fn maybe_suggest_brackets_instead_of_braces( + &mut self, + lo: Span, + attrs: AttrVec, + ) -> Option> { + let mut snapshot = self.clone(); + match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) { + Ok(arr) => { + let hi = snapshot.prev_token.span; + self.struct_span_err( + arr.span, + "this code is interpreted as a block expression, not an array", + ) + .multipart_suggestion( + "try using [] instead of {}", + vec![(lo, "[".to_owned()), (hi, "]".to_owned())], + Applicability::MaybeIncorrect, + ) + .note("to define an array, one would use square brackets instead of curly braces") + .emit(); + + *self = snapshot; + Some(self.mk_expr_err(arr.span)) + } + Err(mut e) => { + e.cancel(); + None + } + } + } + /// Parses a block or unsafe block. pub(super) fn parse_block_expr( &mut self, @@ -1665,6 +1819,12 @@ blk_mode: BlockCheckMode, mut attrs: AttrVec, ) -> PResult<'a, P> { + if self.is_array_like_block() { + if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo, attrs.clone()) { + return Ok(arr); + } + } + if let Some(label) = opt_label { self.sess.gated_spans.gate(sym::label_break_value, label.ident.span); } @@ -1716,7 +1876,7 @@ let capture_clause = self.parse_capture_clause()?; let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; - let body = match decl.output { + let mut body = match decl.output { FnRetTy::Default(_) => { let restrictions = self.restrictions - Restrictions::STMT_EXPR; self.parse_expr_res(restrictions, None)? @@ -1733,11 +1893,28 @@ self.sess.gated_spans.gate(sym::async_closure, span); } - Ok(self.mk_expr( + if self.token.kind == TokenKind::Semi && self.token_cursor.frame.delim == DelimToken::Paren + { + // It is likely that the closure body is a block but where the + // braces have been removed. We will recover and eat the next + // statements later in the parsing process. + body = self.mk_expr_err(body.span); + } + + let body_span = body.span; + + let closure = self.mk_expr( lo.to(body.span), ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)), attrs, - )) + ); + + // Disable recovery for closure body + let spans = + ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span }; + self.current_closure = Some(spans); + + Ok(closure) } /// Parses an optional `move` prefix to a closure-like construct. @@ -1930,7 +2107,7 @@ self.check_for_for_in_in_typo(self.prev_token.span); let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; - let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren); + let pat = self.recover_parens_around_for_head(pat, begin_paren); let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); @@ -2145,7 +2322,24 @@ None }; let arrow_span = this.token.span; - this.expect(&token::FatArrow)?; + if let Err(mut err) = this.expect(&token::FatArrow) { + // We might have a `=>` -> `=` or `->` typo (issue #89396). + if TokenKind::FatArrow + .similar_tokens() + .map_or(false, |similar_tokens| similar_tokens.contains(&this.token.kind)) + { + err.span_suggestion( + this.token.span, + "try using a fat arrow here", + "=>".to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + this.bump(); + } else { + return Err(err); + } + } let arm_start_span = this.token.span; let expr = this.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| { @@ -2332,14 +2526,12 @@ .emit(); } - /// Precondition: already parsed the '{'. - pub(super) fn parse_struct_expr( + pub(super) fn parse_struct_fields( &mut self, - qself: Option, pth: ast::Path, - attrs: AttrVec, recover: bool, - ) -> PResult<'a, P> { + close_delim: token::DelimToken, + ) -> PResult<'a, (Vec, ast::StructRest, bool)> { let mut fields = Vec::new(); let mut base = ast::StructRest::None; let mut recover_async = false; @@ -2351,11 +2543,11 @@ e.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); }; - while self.token != token::CloseDelim(token::Brace) { + while self.token != token::CloseDelim(close_delim) { if self.eat(&token::DotDot) { let exp_span = self.prev_token.span; // We permit `.. }` on the left-hand side of a destructuring assignment. - if self.check(&token::CloseDelim(token::Brace)) { + if self.check(&token::CloseDelim(close_delim)) { self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span); base = ast::StructRest::Rest(self.prev_token.span.shrink_to_hi()); break; @@ -2396,7 +2588,7 @@ } }; - match self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]) { + match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) { Ok(_) => { if let Some(f) = parsed_field.or(recovery_field) { // Only include the field if there's no parse error for the field name. @@ -2427,8 +2619,21 @@ } } } + Ok((fields, base, recover_async)) + } - let span = pth.span.to(self.token.span); + /// Precondition: already parsed the '{'. + pub(super) fn parse_struct_expr( + &mut self, + qself: Option, + pth: ast::Path, + attrs: AttrVec, + recover: bool, + ) -> PResult<'a, P> { + let lo = pth.span; + let (fields, base, recover_async) = + self.parse_struct_fields(pth.clone(), recover, token::Brace)?; + let span = lo.to(self.token.span); self.expect(&token::CloseDelim(token::Brace))?; let expr = if recover_async { ExprKind::Err diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/item.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/item.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/item.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/item.rs 2021-11-29 19:27:11.000000000 +0000 @@ -493,7 +493,20 @@ let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt) { let span = self.prev_token.span.between(self.token.span); - self.struct_span_err(span, "missing trait in a trait impl").emit(); + self.struct_span_err(span, "missing trait in a trait impl") + .span_suggestion( + span, + "add a trait here", + " Trait ".into(), + Applicability::HasPlaceholders, + ) + .span_suggestion( + span.to(self.token.span), + "for an inherent impl, drop this `for`", + "".into(), + Applicability::MaybeIncorrect, + ) + .emit(); P(Ty { kind: TyKind::Path(None, err_path(span)), span, @@ -1534,6 +1547,20 @@ self.expect(&token::Not)?; // `!` let ident = self.parse_ident()?; + + if self.eat(&token::Not) { + // Handle macro_rules! foo! + let span = self.prev_token.span; + self.struct_span_err(span, "macro names aren't followed by a `!`") + .span_suggestion( + span, + "remove the `!`", + "".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); + } + let body = self.parse_mac_args()?; self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -142,6 +142,17 @@ /// If present, this `Parser` is not parsing Rust code but rather a macro call. subparser_name: Option<&'static str>, capture_state: CaptureState, + /// This allows us to recover when the user forget to add braces around + /// multiple statements in the closure body. + pub current_closure: Option, +} + +/// Stores span informations about a closure. +#[derive(Clone)] +pub struct ClosureSpans { + pub whole_closure: Span, + pub closing_pipe: Span, + pub body: Span, } /// Indicates a range of tokens that should be replaced by @@ -440,6 +451,7 @@ replace_ranges: Vec::new(), inner_attr_ranges: Default::default(), }, + current_closure: None, }; // Make parser point to the first token. @@ -761,8 +773,11 @@ first = false; } else { match self.expect(t) { - Ok(false) => {} + Ok(false) => { + self.current_closure.take(); + } Ok(true) => { + self.current_closure.take(); recovered = true; break; } @@ -770,10 +785,29 @@ let sp = self.prev_token.span.shrink_to_hi(); let token_str = pprust::token_kind_to_string(t); - // Attempt to keep parsing if it was a similar separator. - if let Some(ref tokens) = t.similar_tokens() { - if tokens.contains(&self.token.kind) && !unclosed_delims { - self.bump(); + match self.current_closure.take() { + Some(closure_spans) if self.token.kind == TokenKind::Semi => { + // Finding a semicolon instead of a comma + // after a closure body indicates that the + // closure body may be a block but the user + // forgot to put braces around its + // statements. + + self.recover_missing_braces_around_closure_body( + closure_spans, + expect_err, + )?; + + continue; + } + + _ => { + // Attempt to keep parsing if it was a similar separator. + if let Some(ref tokens) = t.similar_tokens() { + if tokens.contains(&self.token.kind) && !unclosed_delims { + self.bump(); + } + } } } @@ -839,6 +873,65 @@ Ok((v, trailing, recovered)) } + fn recover_missing_braces_around_closure_body( + &mut self, + closure_spans: ClosureSpans, + mut expect_err: DiagnosticBuilder<'_>, + ) -> PResult<'a, ()> { + let initial_semicolon = self.token.span; + + while self.eat(&TokenKind::Semi) { + let _ = self.parse_stmt(ForceCollect::Yes)?; + } + + expect_err.set_primary_message( + "closure bodies that contain statements must be surrounded by braces", + ); + + let preceding_pipe_span = closure_spans.closing_pipe; + let following_token_span = self.token.span; + + let mut first_note = MultiSpan::from(vec![initial_semicolon]); + first_note.push_span_label( + initial_semicolon, + "this `;` turns the preceding closure into a statement".to_string(), + ); + first_note.push_span_label( + closure_spans.body, + "this expression is a statement because of the trailing semicolon".to_string(), + ); + expect_err.span_note(first_note, "statement found outside of a block"); + + let mut second_note = MultiSpan::from(vec![closure_spans.whole_closure]); + second_note.push_span_label( + closure_spans.whole_closure, + "this is the parsed closure...".to_string(), + ); + second_note.push_span_label( + following_token_span, + "...but likely you meant the closure to end here".to_string(), + ); + expect_err.span_note(second_note, "the closure body may be incorrectly delimited"); + + expect_err.set_span(vec![preceding_pipe_span, following_token_span]); + + let opening_suggestion_str = " {".to_string(); + let closing_suggestion_str = "}".to_string(); + + expect_err.multipart_suggestion( + "try adding braces", + vec![ + (preceding_pipe_span.shrink_to_hi(), opening_suggestion_str), + (following_token_span.shrink_to_lo(), closing_suggestion_str), + ], + Applicability::MaybeIncorrect, + ); + + expect_err.emit(); + + Ok(()) + } + /// Parses a sequence, not including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/path.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/path.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/path.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/path.rs 2021-11-29 19:27:11.000000000 +0000 @@ -495,20 +495,28 @@ None => { let after_eq = eq.shrink_to_hi(); let before_next = self.token.span.shrink_to_lo(); - self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`") - .span_suggestion( + let mut err = self + .struct_span_err(after_eq.to(before_next), "missing type to the right of `=`"); + if matches!(self.token.kind, token::Comma | token::Gt) { + err.span_suggestion( self.sess.source_map().next_point(eq).to(before_next), "to constrain the associated type, add a type after `=`", " TheType".to_string(), Applicability::HasPlaceholders, - ) - .span_suggestion( + ); + err.span_suggestion( eq.to(before_next), &format!("remove the `=` if `{}` is a type", ident), String::new(), Applicability::MaybeIncorrect, ) - .emit(); + } else { + err.span_label( + self.token.span, + &format!("expected type, found {}", super::token_descr(&self.token)), + ) + }; + return Err(err); } } Ok(self.mk_ty(span, ast::TyKind::Err)) @@ -572,6 +580,25 @@ return self.recover_const_arg(start, err).map(Some); } } + } else if self.eat_keyword_noexpect(kw::Const) { + // Detect and recover from the old, pre-RFC2000 syntax for const generics. + let mut err = self.struct_span_err( + start, + "expected lifetime, type, or constant, found keyword `const`", + ); + if self.check_const_arg() { + err.span_suggestion_verbose( + start.until(self.token.span), + "the `const` keyword is only needed in the definition of the type", + String::new(), + Applicability::MaybeIncorrect, + ); + err.emit(); + GenericArg::Const(self.parse_const_arg()?) + } else { + let after_kw_const = self.token.span; + return self.recover_const_arg(after_kw_const, err).map(Some); + } } else { return Ok(None); }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/stmt.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/stmt.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/parser/stmt.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/parser/stmt.rs 2021-11-29 19:27:11.000000000 +0000 @@ -155,17 +155,20 @@ let mac = MacCall { path, args, prior_type_ascription: self.last_type_ascription }; - let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof - { - StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) - } else { - // Since none of the above applied, this is an expression statement macro. - let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); - let e = self.maybe_recover_from_bad_qpath(e, true)?; - let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; - StmtKind::Expr(e) - }; + let kind = + if (delim == token::Brace && self.token != token::Dot && self.token != token::Question) + || self.token == token::Semi + || self.token == token::Eof + { + StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) + } else { + // Since none of the above applied, this is an expression statement macro. + let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); + let e = self.maybe_recover_from_bad_qpath(e, true)?; + let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; + StmtKind::Expr(e) + }; Ok(self.mk_stmt(lo.to(hi), kind)) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/validate_attr.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/validate_attr.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse/src/validate_attr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse/src/validate_attr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenTree}; use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; @@ -91,69 +91,11 @@ // Some special attributes like `cfg` must be checked // before the generic check, so we skip them here. let should_skip = |name| name == sym::cfg; - // Some of previously accepted forms were used in practice, - // report them as warnings for now. - let should_warn = |name| { - name == sym::doc - || name == sym::ignore - || name == sym::inline - || name == sym::link - || name == sym::test - || name == sym::bench - }; match parse_meta(sess, attr) { Ok(meta) => { if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { - let error_msg = format!("malformed `{}` attribute input", name); - let mut msg = "attribute must be of the form ".to_owned(); - let mut suggestions = vec![]; - let mut first = true; - if template.word { - first = false; - let code = format!("#[{}]", name); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.list { - if !first { - msg.push_str(" or "); - } - first = false; - let code = format!("#[{}({})]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.name_value_str { - if !first { - msg.push_str(" or "); - } - let code = format!("#[{} = \"{}\"]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if should_warn(name) { - sess.buffer_lint( - &ILL_FORMED_ATTRIBUTE_INPUT, - meta.span, - ast::CRATE_NODE_ID, - &msg, - ); - } else { - sess.span_diagnostic - .struct_span_err(meta.span, &error_msg) - .span_suggestions( - meta.span, - if suggestions.len() == 1 { - "must be of the form" - } else { - "the following are the possible correct uses" - }, - suggestions.into_iter(), - Applicability::HasPlaceholders, - ) - .emit(); - } + emit_malformed_attribute(sess, attr, name, template); } } Err(mut err) => { @@ -161,3 +103,74 @@ } } } + +fn emit_malformed_attribute( + sess: &ParseSess, + attr: &Attribute, + name: Symbol, + template: AttributeTemplate, +) { + // Some of previously accepted forms were used in practice, + // report them as warnings for now. + let should_warn = |name| { + matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench) + }; + + let error_msg = format!("malformed `{}` attribute input", name); + let mut msg = "attribute must be of the form ".to_owned(); + let mut suggestions = vec![]; + let mut first = true; + let inner = if attr.style == ast::AttrStyle::Inner { "!" } else { "" }; + if template.word { + first = false; + let code = format!("#{}[{}]", inner, name); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.list { + if !first { + msg.push_str(" or "); + } + first = false; + let code = format!("#{}[{}({})]", inner, name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.name_value_str { + if !first { + msg.push_str(" or "); + } + let code = format!("#{}[{} = \"{}\"]", inner, name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if should_warn(name) { + sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, attr.span, ast::CRATE_NODE_ID, &msg); + } else { + sess.span_diagnostic + .struct_span_err(attr.span, &error_msg) + .span_suggestions( + attr.span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are the possible correct uses" + }, + suggestions.into_iter(), + Applicability::HasPlaceholders, + ) + .emit(); + } +} + +pub fn emit_fatal_malformed_builtin_attribute( + sess: &ParseSess, + attr: &Attribute, + name: Symbol, +) -> ! { + let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2; + emit_malformed_attribute(sess, attr, name, template); + // This is fatal, otherwise it will likely cause a cascade of other errors + // (and an error here is expected to be very rare). + FatalError.raise() +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse_format/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse_format/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_parse_format/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_parse_format/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_parse_format" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustc_span = { path = "../rustc_span" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_passes" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] tracing = "0.1" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/check_attr.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/check_attr.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/check_attr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/check_attr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ use rustc_middle::ty::TyCtxt; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; @@ -66,6 +66,7 @@ target: Target, item: Option>, ) { + let mut doc_aliases = FxHashMap::default(); let mut is_valid = true; let mut specified_inline = None; let mut seen = FxHashSet::default(); @@ -79,7 +80,13 @@ sym::track_caller => { self.check_track_caller(hir_id, &attr.span, attrs, span, target) } - sym::doc => self.check_doc_attrs(attr, hir_id, target, &mut specified_inline), + sym::doc => self.check_doc_attrs( + attr, + hir_id, + target, + &mut specified_inline, + &mut doc_aliases, + ), sym::no_link => self.check_no_link(hir_id, &attr, span, target), sym::export_name => self.check_export_name(hir_id, &attr, span, target), sym::rustc_layout_scalar_valid_range_start @@ -104,6 +111,7 @@ sym::default_method_body_is_const => { self.check_default_method_body_is_const(attr, span, target) } + sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), sym::rustc_const_unstable | sym::rustc_const_stable | sym::unstable @@ -511,6 +519,7 @@ hir_id: HirId, target: Target, is_list: bool, + aliases: &mut FxHashMap, ) -> bool { let tcx = self.tcx; let err_fn = move |span: Span, msg: &str| { @@ -581,17 +590,38 @@ if &*item_name.as_str() == doc_alias { return err_fn(meta.span(), "is the same as the item's name"); } + let span = meta.span(); + if let Err(entry) = aliases.try_insert(doc_alias.to_owned(), span) { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| { + lint.build("doc alias is duplicated") + .span_label(*entry.entry.get(), "first defined here") + .emit(); + }); + } true } - fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool { + fn check_doc_alias( + &self, + meta: &NestedMetaItem, + hir_id: HirId, + target: Target, + aliases: &mut FxHashMap, + ) -> bool { if let Some(values) = meta.meta_item_list() { let mut errors = 0; for v in values { match v.literal() { Some(l) => match l.kind { LitKind::Str(s, _) => { - if !self.check_doc_alias_value(v, &s.as_str(), hir_id, target, true) { + if !self.check_doc_alias_value( + v, + &s.as_str(), + hir_id, + target, + true, + aliases, + ) { errors += 1; } } @@ -620,7 +650,7 @@ } errors == 0 } else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) { - self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false) + self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false, aliases) } else { self.tcx .sess @@ -857,6 +887,7 @@ hir_id: HirId, target: Target, specified_inline: &mut Option<(bool, Span)>, + aliases: &mut FxHashMap, ) -> bool { let mut is_valid = true; @@ -866,7 +897,7 @@ match i_meta.name_or_empty() { sym::alias if !self.check_attr_not_crate_level(&meta, hir_id, "alias") - || !self.check_doc_alias(&meta, hir_id, target) => + || !self.check_doc_alias(&meta, hir_id, target, aliases) => { is_valid = false } @@ -907,6 +938,7 @@ // plugins: removed, but rustdoc warns about it itself sym::alias | sym::cfg + | sym::cfg_hide | sym::hidden | sym::html_favicon_url | sym::html_logo_url @@ -1014,6 +1046,21 @@ is_valid } + /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid. + fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Struct | Target::Enum | Target::Union | Target::Trait => true, + _ => { + self.tcx + .sess + .struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait") + .span_label(*span, "is not a struct, enum, or trait") + .emit(); + false + } + } + } + /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid. fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { match target { @@ -1720,8 +1767,7 @@ fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { if target != Target::MacroDef { self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!("`#[macro_export]` only has an effect on macro definitions")) - .emit(); + lint.build("`#[macro_export]` only has an effect on macro definitions").emit(); }); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/check_const.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/check_const.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/check_const.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/check_const.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,6 @@ //! through, but errors for structured control flow in a `const` should be emitted here. use rustc_attr as attr; -use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -83,30 +82,39 @@ let _: Option<_> = try { if let hir::ItemKind::Impl(ref imp) = item.kind { if let hir::Constness::Const = imp.constness { - let did = imp.of_trait.as_ref()?.trait_def_id()?; - let mut to_implement = FxHashSet::default(); + let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?; + let ancestors = self + .tcx + .trait_def(trait_def_id) + .ancestors(self.tcx, item.def_id.to_def_id()) + .ok()?; + let mut to_implement = Vec::new(); - for did in self.tcx.associated_item_def_ids(did) { + for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order() + { if let ty::AssocItem { kind: ty::AssocKind::Fn, ident, defaultness, .. - } = self.tcx.associated_item(*did) + } = trait_item { // we can ignore functions that do not have default bodies: // if those are unimplemented it will be catched by typeck. - if defaultness.has_value() - && !self.tcx.has_attr(*did, sym::default_method_body_is_const) + if !defaultness.has_value() + || self + .tcx + .has_attr(trait_item.def_id, sym::default_method_body_is_const) { - to_implement.insert(ident); + continue; } - } - } - for it in imp - .items - .iter() - .filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. })) - { - to_implement.remove(&it.ident); + let is_implemented = ancestors + .leaf_def(self.tcx, trait_item.ident, trait_item.kind) + .map(|node_item| !node_item.defining_node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented { + to_implement.push(ident.to_string()); + } + } } // all nonconst trait functions (not marked with #[default_method_body_is_const]) @@ -118,7 +126,7 @@ item.span, "const trait implementations may not use non-const default functions", ) - .note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::>().join("`, `"))) + .note(&format!("`{}` not implemented", to_implement.join("`, `"))) .emit(); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/dead.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/dead.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/dead.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/dead.rs 2021-11-29 19:27:11.000000000 +0000 @@ -239,7 +239,35 @@ } } + /// Automatically generated items marked with `rustc_trivial_field_reads` + /// will be ignored for the purposes of dead code analysis (see PR #85200 + /// for discussion). + fn should_ignore_item(&self, def_id: DefId) -> bool { + if let Some(impl_of) = self.tcx.impl_of_method(def_id) { + if !self.tcx.has_attr(impl_of, sym::automatically_derived) { + return false; + } + + if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) { + if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { + return true; + } + } + } + + return false; + } + fn visit_node(&mut self, node: Node<'tcx>) { + if let Some(item_def_id) = match node { + Node::ImplItem(hir::ImplItem { def_id, .. }) => Some(def_id.to_def_id()), + _ => None, + } { + if self.should_ignore_item(item_def_id) { + return; + } + } + let had_repr_c = self.repr_has_repr_c; let had_inherited_pub_visibility = self.inherited_pub_visibility; let had_pub_visibility = self.pub_visibility; @@ -448,15 +476,14 @@ // or // 2) We are not sure to be live or not // * Implementations of traits and trait methods -struct LifeSeeder<'k, 'tcx> { +struct LifeSeeder<'tcx> { worklist: Vec, - krate: &'k hir::Crate<'k>, tcx: TyCtxt<'tcx>, // see `MarkSymbolVisitor::struct_constructors` struct_constructors: FxHashMap, } -impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { +impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> { fn visit_item(&mut self, item: &hir::Item<'_>) { let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id()); if allow_dead_code { @@ -483,7 +510,7 @@ self.worklist.push(item.def_id); } for impl_item_ref in items { - let impl_item = self.krate.impl_item(impl_item_ref.id); + let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); if of_trait.is_some() || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id()) { @@ -527,7 +554,6 @@ fn create_and_seed_worklist<'tcx>( tcx: TyCtxt<'tcx>, access_levels: &privacy::AccessLevels, - krate: &hir::Crate<'_>, ) -> (Vec, FxHashMap) { let worklist = access_levels .map @@ -542,9 +568,8 @@ .collect::>(); // Seed implemented trait items - let mut life_seeder = - LifeSeeder { worklist, krate, tcx, struct_constructors: Default::default() }; - krate.visit_all_item_likes(&mut life_seeder); + let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() }; + tcx.hir().visit_all_item_likes(&mut life_seeder); (life_seeder.worklist, life_seeder.struct_constructors) } @@ -552,9 +577,8 @@ fn find_live<'tcx>( tcx: TyCtxt<'tcx>, access_levels: &privacy::AccessLevels, - krate: &hir::Crate<'_>, ) -> FxHashSet { - let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate); + let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels); let mut symbol_visitor = MarkSymbolVisitor { worklist, tcx, @@ -772,8 +796,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let access_levels = &tcx.privacy_access_levels(()); - let krate = tcx.hir().krate(); - let live_symbols = find_live(tcx, access_levels, krate); + let live_symbols = find_live(tcx, access_levels); let mut visitor = DeadVisitor { tcx, live_symbols }; - intravisit::walk_crate(&mut visitor, krate); + tcx.hir().walk_toplevel_module(&mut visitor); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/diagnostic_items.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/diagnostic_items.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/diagnostic_items.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/diagnostic_items.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,8 +10,8 @@ //! * Compiler internal types like `Ty` and `TyCtxt` use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -19,9 +19,8 @@ use rustc_span::symbol::{sym, Symbol}; struct DiagnosticItemCollector<'tcx> { - // items from this crate - items: FxHashMap, tcx: TyCtxt<'tcx>, + diagnostic_items: DiagnosticItems, } impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { @@ -44,7 +43,7 @@ impl<'tcx> DiagnosticItemCollector<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> { - DiagnosticItemCollector { tcx, items: Default::default() } + DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() } } fn observe_item(&mut self, def_id: LocalDefId) { @@ -52,19 +51,14 @@ let attrs = self.tcx.hir().attrs(hir_id); if let Some(name) = extract(attrs) { // insert into our table - collect_item(self.tcx, &mut self.items, name, def_id.to_def_id()); + collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id()); } } } -fn collect_item( - tcx: TyCtxt<'_>, - items: &mut FxHashMap, - name: Symbol, - item_def_id: DefId, -) { - // Check for duplicates. - if let Some(original_def_id) = items.insert(name, item_def_id) { +fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item_def_id: DefId) { + items.id_to_name.insert(item_def_id, name); + if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) { if original_def_id != item_def_id { let mut err = match tcx.hir().span_if_local(item_def_id) { Some(span) => tcx.sess.struct_span_err( @@ -98,31 +92,31 @@ } /// Traverse and collect the diagnostic items in the current -fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap { +fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems { assert_eq!(cnum, LOCAL_CRATE); // Initialize the collector. let mut collector = DiagnosticItemCollector::new(tcx); // Collect diagnostic items in this crate. - tcx.hir().krate().visit_all_item_likes(&mut collector); + tcx.hir().visit_all_item_likes(&mut collector); - collector.items + collector.diagnostic_items } /// Traverse and collect all the diagnostic items in all crates. -fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashMap { +fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> DiagnosticItems { // Initialize the collector. - let mut collector = FxHashMap::default(); + let mut items = DiagnosticItems::default(); // Collect diagnostic items in other crates. for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { - for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() { - collect_item(tcx, &mut collector, name, def_id); + for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id { + collect_item(tcx, &mut items, name, def_id); } } - collector + items } pub fn provide(providers: &mut Providers) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/entry.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/entry.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/entry.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/entry.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ use rustc_ast::entry::EntryPointType; use rustc_errors::struct_span_err; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID}; use rustc_middle::hir::map::Map; @@ -68,7 +68,7 @@ non_main_fns: Vec::new(), }; - tcx.hir().krate().visit_all_item_likes(&mut ctxt); + tcx.hir().visit_all_item_likes(&mut ctxt); configure_main(tcx, &ctxt) } @@ -183,7 +183,7 @@ } fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { - let sp = tcx.hir().krate().module().inner; + let sp = tcx.def_span(CRATE_DEF_ID); if *tcx.sess.parse_sess.reached_eof.borrow() { // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about // the missing `fn main()` then as it might have been hidden inside an unclosed block. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/hir_id_validator.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/hir_id_validator.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/hir_id_validator.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/hir_id_validator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator}; +use rustc_data_structures::sync::Lock; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::intravisit; @@ -11,12 +11,16 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.dep_graph.assert_ignored(); + if tcx.sess.opts.debugging_opts.hir_stats { + crate::hir_stats::print_hir_stats(tcx); + } + let errors = Lock::new(Vec::new()); let hir_map = tcx.hir(); - par_iter(&hir_map.krate().modules).for_each(|(&module_id, _)| { + hir_map.par_for_each_module(|module_id| { hir_map - .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors }); + .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors }) }); let errors = errors.into_inner(); @@ -159,14 +163,14 @@ self.hir_ids_seen.insert(hir_id.local_id); } - fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef<'hir>) { + fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) { // Explicitly do nothing here. ImplItemRefs contain hir::Visibility // values that actually belong to an ImplItem instead of the ItemKind::Impl // we are currently in. So for those it's correct that they have a // different owner. } - fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef<'hir>) { + fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef) { // Explicitly do nothing here. ForeignItemRefs contain hir::Visibility // values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod // we are currently in. So for those it's correct that they have a diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/hir_stats.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/hir_stats.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/hir_stats.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/hir_stats.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,7 @@ use rustc_hir::intravisit as hir_visit; use rustc_hir::HirId; use rustc_middle::hir::map::Map; +use rustc_middle::ty::TyCtxt; use rustc_middle::util::common::to_readable_str; use rustc_span::Span; @@ -25,18 +26,19 @@ } struct StatCollector<'k> { - krate: Option<&'k hir::Crate<'k>>, + krate: Option>, data: FxHashMap<&'static str, NodeData>, seen: FxHashSet, } -pub fn print_hir_stats(krate: &hir::Crate<'_>) { +pub fn print_hir_stats(tcx: TyCtxt<'_>) { let mut collector = StatCollector { - krate: Some(krate), + krate: Some(tcx.hir()), data: FxHashMap::default(), seen: FxHashSet::default(), }; - hir_visit::walk_crate(&mut collector, krate); + tcx.hir().walk_toplevel_module(&mut collector); + tcx.hir().walk_attributes(&mut collector); collector.print("HIR STATS"); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/intrinsicck.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/intrinsicck.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/intrinsicck.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/intrinsicck.rs 2021-11-29 19:27:11.000000000 +0000 @@ -141,6 +141,7 @@ template: &[InlineAsmTemplatePiece], is_input: bool, tied_input: Option<(&hir::Expr<'tcx>, Option)>, + target_features: &[Symbol], ) -> Option { // Check the type against the allowed types for inline asm. let ty = self.typeck_results.expr_ty_adjusted(expr); @@ -283,17 +284,20 @@ }; // Check whether the selected type requires a target feature. Note that - // this is different from the feature check we did earlier in AST - // lowering. While AST lowering checked that this register class is - // usable at all with the currently enabled features, some types may - // only be usable with a register class when a certain feature is - // enabled. We check this here since it depends on the results of typeck. + // this is different from the feature check we did earlier. While the + // previous check checked that this register class is usable at all + // with the currently enabled features, some types may only be usable + // with a register class when a certain feature is enabled. We check + // this here since it depends on the results of typeck. // // Also note that this check isn't run when the operand type is never - // (!). In that case we still need the earlier check in AST lowering to - // verify that the register class is usable at all. + // (!). In that case we still need the earlier check to verify that the + // register class is usable at all. if let Some(feature) = feature { - if !self.tcx.sess.target_features.contains(&Symbol::intern(feature)) { + let feat_sym = Symbol::intern(feature); + if !self.tcx.sess.target_features.contains(&feat_sym) + && !target_features.contains(&feat_sym) + { let msg = &format!("`{}` target feature is not enabled", feature); let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note(&format!( @@ -349,23 +353,122 @@ Some(asm_ty) } - fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) { - for (idx, (op, _)) in asm.operands.iter().enumerate() { + fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) { + let hir = self.tcx.hir(); + let enclosing_id = hir.enclosing_body_owner(hir_id); + let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id(); + let attrs = self.tcx.codegen_fn_attrs(enclosing_def_id); + for (idx, (op, op_sp)) in asm.operands.iter().enumerate() { + // Validate register classes against currently enabled target + // features. We check that at least one type is available for + // the enabled features. + // + // We ignore target feature requirements for clobbers: if the + // feature is disabled then the compiler doesn't care what we + // do with the registers. + // + // Note that this is only possible for explicit register + // operands, which cannot be used in the asm string. + if let Some(reg) = op.reg() { + if !op.is_clobber() { + let mut missing_required_features = vec![]; + let reg_class = reg.reg_class(); + for &(_, feature) in reg_class.supported_types(self.tcx.sess.asm_arch.unwrap()) + { + match feature { + Some(feature) => { + let feat_sym = Symbol::intern(feature); + if self.tcx.sess.target_features.contains(&feat_sym) + || attrs.target_features.contains(&feat_sym) + { + missing_required_features.clear(); + break; + } else { + missing_required_features.push(feature); + } + } + None => { + missing_required_features.clear(); + break; + } + } + } + + // We are sorting primitive strs here and can use unstable sort here + missing_required_features.sort_unstable(); + missing_required_features.dedup(); + match &missing_required_features[..] { + [] => {} + [feature] => { + let msg = format!( + "register class `{}` requires the `{}` target feature", + reg_class.name(), + feature + ); + self.tcx.sess.struct_span_err(*op_sp, &msg).emit(); + // register isn't enabled, don't do more checks + continue; + } + features => { + let msg = format!( + "register class `{}` requires at least one of the following target features: {}", + reg_class.name(), + features.join(", ") + ); + self.tcx.sess.struct_span_err(*op_sp, &msg).emit(); + // register isn't enabled, don't do more checks + continue; + } + } + } + } + match *op { hir::InlineAsmOperand::In { reg, ref expr } => { - self.check_asm_operand_type(idx, reg, expr, asm.template, true, None); + self.check_asm_operand_type( + idx, + reg, + expr, + asm.template, + true, + None, + &attrs.target_features, + ); } hir::InlineAsmOperand::Out { reg, late: _, ref expr } => { if let Some(expr) = expr { - self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); + self.check_asm_operand_type( + idx, + reg, + expr, + asm.template, + false, + None, + &attrs.target_features, + ); } } hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => { - self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); + self.check_asm_operand_type( + idx, + reg, + expr, + asm.template, + false, + None, + &attrs.target_features, + ); } hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => { - let in_ty = - self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None); + let in_ty = self.check_asm_operand_type( + idx, + reg, + in_expr, + asm.template, + true, + None, + &attrs.target_features, + ); if let Some(out_expr) = out_expr { self.check_asm_operand_type( idx, @@ -374,6 +477,7 @@ asm.template, false, Some((in_expr, in_ty)), + &attrs.target_features, ); } } @@ -422,7 +526,7 @@ } } - hir::ExprKind::InlineAsm(asm) => self.check_asm(asm), + hir::ExprKind::InlineAsm(asm) => self.check_asm(asm, expr.hir_id), _ => {} } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/lang_items.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/lang_items.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/lang_items.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/lang_items.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,9 +10,6 @@ use crate::check_attr::target_from_impl_item; use crate::weak_lang_items; -use rustc_middle::middle::cstore::ExternCrate; -use rustc_middle::ty::TyCtxt; - use rustc_ast::Attribute; use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; @@ -20,6 +17,8 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS}; use rustc_hir::{HirId, LangItem, LanguageItems, Target}; +use rustc_middle::ty::TyCtxt; +use rustc_session::cstore::ExternCrate; use rustc_span::Span; use rustc_middle::ty::query::Providers; @@ -262,7 +261,7 @@ } // Collect lang items in this crate. - tcx.hir().krate().visit_all_item_likes(&mut collector); + tcx.hir().visit_all_item_likes(&mut collector); // Extract out the found lang items. let LanguageItemCollector { mut items, .. } = collector; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/layout_test.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/layout_test.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/layout_test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/layout_test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,15 +3,16 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::ItemKind; -use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::sym; -use rustc_target::abi::{HasDataLayout, LayoutOf, TargetDataLayout}; +use rustc_span::Span; +use rustc_target::abi::{HasDataLayout, TargetDataLayout}; pub fn test_layout(tcx: TyCtxt<'_>) { if tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout - tcx.hir().krate().visit_all_item_likes(&mut LayoutTest { tcx }); + tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx }); } } @@ -113,12 +114,16 @@ param_env: ParamEnv<'tcx>, } -impl LayoutOf<'tcx> for UnwrapLayoutCx<'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; +impl LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)).unwrap() + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + span_bug!( + span, + "`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`", + ty, + err + ); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/lib_features.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/lib_features.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/lib_features.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/lib_features.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ use rustc_ast::{Attribute, MetaItem, MetaItemKind}; use rustc_errors::struct_span_err; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_middle::hir::map::Map; use rustc_middle::middle::lib_features::LibFeatures; use rustc_middle::ty::query::Providers; @@ -126,9 +126,7 @@ fn get_lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures { let mut collector = LibFeatureCollector::new(tcx); - let krate = tcx.hir().krate(); - - intravisit::walk_crate(&mut collector, krate); + tcx.hir().walk_attributes(&mut collector); collector.lib_features } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,8 +9,9 @@ #![feature(in_band_lifetimes)] #![feature(format_args_capture)] #![feature(iter_zip)] -#![feature(nll)] +#![feature(map_try_insert)] #![feature(min_specialization)] +#![feature(nll)] #![feature(try_blocks)] #![recursion_limit = "256"] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/liveness.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/liveness.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/liveness.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/liveness.rs 2021-11-29 19:27:11.000000000 +0000 @@ -265,12 +265,13 @@ self.capture_info_map.insert(hir_id, Rc::new(cs)); } - fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { + fn collect_shorthand_field_ids(&self, pat: &hir::Pat<'tcx>) -> HirIdSet { // For struct patterns, take note of which fields used shorthand // (`x` rather than `x: x`). let mut shorthand_field_ids = HirIdSet::default(); let mut pats = VecDeque::new(); pats.push_back(pat); + while let Some(pat) = pats.pop_front() { use rustc_hir::PatKind::*; match &pat.kind { @@ -278,8 +279,10 @@ pats.extend(inner_pat.iter()); } Struct(_, fields, _) => { - let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id); - shorthand_field_ids.extend(ids); + let (short, not_short): (Vec<&_>, Vec<&_>) = + fields.iter().partition(|f| f.is_shorthand); + shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id)); + pats.extend(not_short.iter().map(|f| f.pat)); } Ref(inner_pat, _) | Box(inner_pat) => { pats.push_back(inner_pat); @@ -296,6 +299,12 @@ } } + return shorthand_field_ids; + } + + fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { + let shorthand_field_ids = self.collect_shorthand_field_ids(pat); + pat.each_binding(|_, hir_id, _, ident| { self.add_live_node_for_node(hir_id, VarDefNode(ident.span, hir_id)); self.add_variable(Local(LocalInfo { @@ -373,15 +382,13 @@ } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + let shorthand_field_ids = self.collect_shorthand_field_ids(param.pat); param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = match param.pat.kind { - rustc_hir::PatKind::Struct(_, fields, _) => Local(LocalInfo { + rustc_hir::PatKind::Struct(..) => Local(LocalInfo { id: hir_id, name: ident.name, - is_shorthand: fields - .iter() - .find(|f| f.ident == ident) - .map_or(false, |f| f.is_shorthand), + is_shorthand: shorthand_field_ids.contains(&hir_id), }), _ => Param(hir_id, ident.name), }; @@ -775,7 +782,7 @@ if blk.targeted_by_break { self.break_ln.insert(blk.hir_id, succ); } - let succ = self.propagate_through_opt_expr(blk.expr.as_deref(), succ); + let succ = self.propagate_through_opt_expr(blk.expr, succ); blk.stmts.iter().rev().fold(succ, |succ, stmt| self.propagate_through_stmt(stmt, succ)) } @@ -796,7 +803,7 @@ // initialization, which is mildly more complex than checking // once at the func header but otherwise equivalent. - let succ = self.propagate_through_opt_expr(local.init.as_deref(), succ); + let succ = self.propagate_through_opt_expr(local.init, succ); self.define_bindings_in_pat(&local.pat, succ) } hir::StmtKind::Item(..) => succ, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/reachable.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/reachable.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/reachable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/reachable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -427,7 +427,7 @@ access_levels, worklist: &mut reachable_context.worklist, }; - tcx.hir().krate().visit_all_item_likes(&mut collect_private_impl_items); + tcx.hir().visit_all_item_likes(&mut collect_private_impl_items); } // Step 2: Mark all symbols that the symbols on the worklist touch. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/region.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/region.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/region.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/region.rs 2021-11-29 19:27:11.000000000 +0000 @@ -812,7 +812,7 @@ resolve_expr(self, ex); } fn visit_local(&mut self, l: &'tcx Local<'tcx>) { - resolve_local(self, Some(&l.pat), l.init.as_deref()); + resolve_local(self, Some(&l.pat), l.init); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/stability.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/stability.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/stability.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/stability.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,6 +8,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::map::Map; @@ -678,7 +679,6 @@ .collect(); { - let krate = tcx.hir().krate(); let mut annotator = Annotator { tcx, index: &mut index, @@ -711,13 +711,13 @@ annotator.annotate( CRATE_DEF_ID, - krate.module().inner, + tcx.hir().span(CRATE_HIR_ID), None, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, - |v| intravisit::walk_crate(v, krate), + |v| tcx.hir().walk_toplevel_module(v), ); } index @@ -906,11 +906,10 @@ let access_levels = &tcx.privacy_access_levels(()); if tcx.stability().staged_api[&LOCAL_CRATE] { - let krate = tcx.hir().krate(); let mut missing = MissingStabilityAnnotations { tcx, access_levels }; - missing.check_missing_stability(CRATE_DEF_ID, krate.module().inner); - intravisit::walk_crate(&mut missing, krate); - krate.visit_all_item_likes(&mut missing.as_deep_visitor()); + missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID)); + tcx.hir().walk_toplevel_module(&mut missing); + tcx.hir().visit_all_item_likes(&mut missing.as_deep_visitor()); } let declared_lang_features = &tcx.features().declared_lang_features; @@ -929,6 +928,16 @@ let declared_lib_features = &tcx.features().declared_lib_features; let mut remaining_lib_features = FxHashMap::default(); for (feature, span) in declared_lib_features { + if !tcx.sess.opts.unstable_features.is_nightly_build() { + struct_span_err!( + tcx.sess, + *span, + E0554, + "`#![feature]` may not be used on the {} release channel", + env!("CFG_RELEASE_CHANNEL") + ) + .emit(); + } if remaining_lib_features.contains_key(&feature) { // Warn if the user enables a lib feature multiple times. duplicate_feature_err(tcx.sess, *span, *feature); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/weak_lang_items.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/weak_lang_items.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_passes/src/weak_lang_items.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_passes/src/weak_lang_items.rs 2021-11-29 19:27:11.000000000 +0000 @@ -33,7 +33,7 @@ { let mut cx = Context { tcx, items }; - tcx.hir().krate().visit_all_item_likes(&mut cx.as_deep_visitor()); + tcx.hir().visit_all_item_likes(&mut cx.as_deep_visitor()); } verify(tcx, items); } @@ -66,8 +66,8 @@ tcx.sess.err("`#[panic_handler]` function required, but not found"); } else if item == LangItem::Oom { if !tcx.features().default_alloc_error_handler { - tcx.sess.err("`#[alloc_error_handler]` function required, but not found."); - tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler."); + tcx.sess.err("`#[alloc_error_handler]` function required, but not found"); + tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler"); } } else { tcx.sess.err(&format!("language item required, but not found: `{}`", name)); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_plugin_impl/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_plugin_impl/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_plugin_impl/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_plugin_impl/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ name = "rustc_plugin_impl" version = "0.0.0" build = false -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_plugin_impl/src/load.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_plugin_impl/src/load.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_plugin_impl/src/load.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_plugin_impl/src/load.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ use rustc_ast::Crate; use rustc_errors::struct_span_err; use rustc_metadata::locator; -use rustc_middle::middle::cstore::MetadataLoader; +use rustc_session::cstore::MetadataLoader; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_privacy/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_privacy/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_privacy/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_privacy/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_privacy" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustc_middle = { path = "../rustc_middle" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_privacy/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_privacy/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_privacy/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_privacy/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -19,8 +19,8 @@ use rustc_middle::bug; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; -use rustc_middle::mir::abstract_const::Node as ACNode; use rustc_middle::span_bug; +use rustc_middle::thir::abstract_const::Node as ACNode; use rustc_middle::ty::fold::TypeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -470,7 +470,7 @@ let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); let attrs = self.tcx.hir().attrs(hir_id); - if attr::find_transparency(&attrs, md.macro_rules).0 != Transparency::Opaque { + if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque { return; } @@ -743,7 +743,9 @@ } hir::ItemKind::Impl(ref impl_) => { for impl_item_ref in impl_.items { - if impl_.of_trait.is_some() || impl_item_ref.vis.node.is_pub() { + if impl_.of_trait.is_some() + || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public + { self.update(impl_item_ref.id.def_id, item_level); } } @@ -768,7 +770,7 @@ } hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - if foreign_item.vis.node.is_pub() { + if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public { self.update(foreign_item.id.def_id, item_level); } } @@ -795,7 +797,7 @@ // Re-exports are handled in `visit_mod`. However, in order to avoid looping over // all of the items of a mod in `visit_mod` looking for use statements, we handle // making sure that intermediate use statements have their visibilities updated here. - hir::ItemKind::Use(ref path, _) => { + hir::ItemKind::Use(path, _) => { if item_level.is_some() { self.update_visibility_of_intermediate_use_statements(path.segments.as_ref()); } @@ -1097,11 +1099,11 @@ } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Struct(ref qpath, fields, ref base) = expr.kind { + if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_res(res); - if let Some(ref base) = *base { + if let Some(base) = *base { // If the expression uses FRU we need to make sure all the unmentioned fields // are checked for privacy (RFC 736). Rather than computing the set of // unmentioned fields, just check them all. @@ -1310,7 +1312,7 @@ return; } match expr.kind { - hir::ExprKind::Assign(_, ref rhs, _) | hir::ExprKind::Match(ref rhs, ..) => { + hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => { // Do not report duplicate errors for `x = y` and `match x { ... }`. if self.check_expr_pat_type(rhs.hir_id, rhs.span) { return; @@ -1395,7 +1397,7 @@ } fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { - if let Some(ref init) = local.init { + if let Some(init) = local.init { if self.check_expr_pat_type(init.hir_id, init.span) { // Do not report duplicate errors for `let x = y`. return; @@ -1472,7 +1474,7 @@ // .. and it corresponds to a private type in the AST (this returns // `None` for type parameters). match self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(did)) { - Some(Node::Item(ref item)) => !item.vis.node.is_pub(), + Some(Node::Item(item)) => !item.vis.node.is_pub(), Some(_) | None => false, } } else { @@ -1488,7 +1490,7 @@ fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) { if let hir::GenericBound::Trait(ref trait_ref, _) = *bound { - if self.path_is_private_type(&trait_ref.trait_ref.path) { + if self.path_is_private_type(trait_ref.trait_ref.path) { self.old_error_set.insert(trait_ref.trait_ref.hir_ref_id); } } @@ -1515,7 +1517,7 @@ } fn visit_ty(&mut self, ty: &hir::Ty<'_>) { - if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind { if self.inner.path_is_private_type(path) { self.contains_private = true; // Found what we're looking for, so let's stop working. @@ -1554,7 +1556,7 @@ // namespace (the contents have their own privacies). hir::ItemKind::ForeignMod { .. } => {} - hir::ItemKind::Trait(.., ref bounds, _) => { + hir::ItemKind::Trait(.., bounds, _) => { if !self.trait_is_public(item.def_id) { return; } @@ -1584,7 +1586,7 @@ at_outer_type: true, outer_type_is_public_path: false, }; - visitor.visit_ty(&impl_.self_ty); + visitor.visit_ty(impl_.self_ty); self_contains_private = visitor.contains_private; self_is_public_path = visitor.outer_type_is_public_path; } @@ -1662,12 +1664,12 @@ // // Those in 2. are warned via walk_generics and this // call here. - intravisit::walk_path(self, &tr.path); + intravisit::walk_path(self, tr.path); // Those in 3. are warned with this call. for impl_item_ref in impl_.items { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - if let hir::ImplItemKind::TyAlias(ref ty) = impl_item.kind { + if let hir::ImplItemKind::TyAlias(ty) = impl_item.kind { self.visit_ty(ty); } } @@ -1678,7 +1680,10 @@ // methods will be visible as `Public::foo`. let mut found_pub_static = false; for impl_item_ref in impl_.items { - if self.item_is_public(impl_item_ref.id.def_id, &impl_item_ref.vis) { + if self.access_levels.is_reachable(impl_item_ref.id.def_id) + || self.tcx.visibility(impl_item_ref.id.def_id) + == ty::Visibility::Public + { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); match impl_item_ref.kind { AssocItemKind::Const => { @@ -1734,7 +1739,7 @@ } hir::WherePredicate::RegionPredicate(_) => {} hir::WherePredicate::EqPredicate(eq_pred) => { - self.visit_ty(&eq_pred.rhs_ty); + self.visit_ty(eq_pred.rhs_ty); } } } @@ -1747,7 +1752,7 @@ } fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { - if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = t.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = t.kind { if self.path_is_private_type(path) { self.old_error_set.insert(t.hir_id); } @@ -2169,7 +2174,7 @@ changed: false, }; loop { - intravisit::walk_crate(&mut visitor, tcx.hir().krate()); + tcx.hir().walk_toplevel_module(&mut visitor); if visitor.changed { visitor.changed = false; } else { @@ -2184,19 +2189,17 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { let access_levels = tcx.privacy_access_levels(()); - let krate = tcx.hir().krate(); - let mut visitor = ObsoleteVisiblePrivateTypesVisitor { tcx, - access_levels: &access_levels, + access_levels, in_variant: false, old_error_set: Default::default(), }; - intravisit::walk_crate(&mut visitor, krate); + tcx.hir().walk_toplevel_module(&mut visitor); let has_pub_restricted = { let mut pub_restricted_visitor = PubRestrictedVisitor { tcx, has_pub_restricted: false }; - intravisit::walk_crate(&mut pub_restricted_visitor, krate); + tcx.hir().walk_toplevel_module(&mut pub_restricted_visitor); pub_restricted_visitor.has_pub_restricted }; @@ -2225,5 +2228,5 @@ .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id)) .collect(), }; - krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); + tcx.hir().visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_query_impl" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/keys.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/keys.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/keys.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/keys.rs 2021-11-29 19:27:11.000000000 +0000 @@ -305,6 +305,16 @@ } } +impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + self.def_id().krate == LOCAL_CRATE + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.def_id()) + } +} + impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { #[inline(always)] fn query_crate_is_local(&self) -> bool { @@ -450,3 +460,25 @@ DUMMY_SP } } + +impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List>) { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + true + } + + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + +impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + true + } + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.0.default_span(tcx) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -20,10 +20,10 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::DiagnosticBuilder; use rustc_middle::dep_graph; -use rustc_middle::ich::StableHashingContext; use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values}; use rustc_middle::ty::query::{Providers, QueryEngine}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_query_system::ich::StableHashingContext; use rustc_span::Span; #[macro_use] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/on_disk_cache.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/on_disk_cache.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/on_disk_cache.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/on_disk_cache.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,15 @@ use crate::QueryCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; +use rustc_data_structures::memmap::Mmap; +use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, interpret}; +use rustc_middle::thir; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; @@ -22,8 +24,7 @@ }; use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::CachingSourceMapView; -use rustc_span::{BytePos, ExpnData, ExpnHash, SourceFile, Span, DUMMY_SP}; -use std::collections::hash_map::Entry; +use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span}; use std::mem; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; @@ -32,6 +33,7 @@ const TAG_FULL_SPAN: u8 = 0; // A partial span with no location information, encoded only with a `SyntaxContext` const TAG_PARTIAL_SPAN: u8 = 1; +const TAG_RELATIVE_SPAN: u8 = 2; const TAG_SYNTAX_CONTEXT: u8 = 0; const TAG_EXPN_DATA: u8 = 1; @@ -42,14 +44,12 @@ /// any side effects that have been emitted during a query. pub struct OnDiskCache<'sess> { // The complete cache data in serialized form. - serialized_data: Vec, + serialized_data: RwLock>, // Collects all `QuerySideEffects` created during the current compilation // session. current_side_effects: Lock>, - cnum_map: OnceCell>, - source_map: &'sess SourceMap, file_index_to_stable_id: FxHashMap, @@ -84,27 +84,11 @@ expn_data: UnhashMap, // Additional information used when decoding hygiene data. hygiene_context: HygieneDecodeContext, - // Maps `DefPathHash`es to their `RawDefId`s from the *previous* + // Maps `ExpnHash`es to their raw value from the *previous* // compilation session. This is used as an initial 'guess' when - // we try to map a `DefPathHash` to its `DefId` in the current compilation - // session. - foreign_def_path_hashes: UnhashMap, - // Likewise for ExpnId. + // we try to map an `ExpnHash` to its value in the current + // compilation session. foreign_expn_data: UnhashMap, - - // The *next* compilation sessison's `foreign_def_path_hashes` - at - // the end of our current compilation session, this will get written - // out to the `foreign_def_path_hashes` field of the `Footer`, which - // will become `foreign_def_path_hashes` of the next compilation session. - // This stores any `DefPathHash` that we may need to map to a `DefId` - // during the next compilation session. - latest_foreign_def_path_hashes: Lock>, - - // Caches all lookups of `DefPathHashes`, both for local and foreign - // definitions. A definition from the previous compilation session - // may no longer exist in the current compilation session, so - // we use `Option` so that we can cache a lookup failure. - def_path_hash_to_def_id_cache: Lock>>, } // This type is used only for serialization and deserialization. @@ -119,7 +103,6 @@ syntax_contexts: FxHashMap, // See `OnDiskCache.expn_data` expn_data: UnhashMap, - foreign_def_path_hashes: UnhashMap, foreign_expn_data: UnhashMap, } @@ -142,19 +125,6 @@ } } -/// Represents a potentially invalid `DefId`. This is used during incremental -/// compilation to represent a `DefId` from the *previous* compilation session, -/// which may no longer be valid. This is used to help map a `DefPathHash` -/// to a `DefId` in the current compilation session. -#[derive(Encodable, Decodable, Copy, Clone, Debug)] -crate struct RawDefId { - // We deliberately do not use `CrateNum` and `DefIndex` - // here, since a crate/index from the previous compilation - // session may no longer exist. - pub krate: u32, - pub index: u32, -} - /// An `EncodedSourceFileId` is the same as a `StableSourceFileId` except that /// the source crate is represented as a [StableCrateId] instead of as a /// `CrateNum`. This way `EncodedSourceFileId` can be encoded and decoded @@ -167,8 +137,8 @@ } impl EncodedSourceFileId { - fn translate(&self, cnum_map: &UnhashMap) -> StableSourceFileId { - let cnum = cnum_map[&self.stable_crate_id]; + fn translate(&self, tcx: TyCtxt<'_>) -> StableSourceFileId { + let cnum = tcx.stable_crate_id_to_crate_num(self.stable_crate_id); StableSourceFileId { file_name_hash: self.file_name_hash, cnum } } @@ -182,7 +152,8 @@ } impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { - fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { + /// Creates a new `OnDiskCache` instance from the serialized data in `data`. + fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self { debug_assert!(sess.opts.incremental.is_some()); // Wrap in a scope so we can borrow `data`. @@ -204,10 +175,9 @@ }; Self { - serialized_data: data, + serialized_data: RwLock::new(Some(data)), file_index_to_stable_id: footer.file_index_to_stable_id, file_index_to_file: Default::default(), - cnum_map: OnceCell::new(), source_map: sess.source_map(), current_side_effects: Default::default(), query_result_index: footer.query_result_index.into_iter().collect(), @@ -217,18 +187,14 @@ expn_data: footer.expn_data, foreign_expn_data: footer.foreign_expn_data, hygiene_context: Default::default(), - foreign_def_path_hashes: footer.foreign_def_path_hashes, - latest_foreign_def_path_hashes: Default::default(), - def_path_hash_to_def_id_cache: Default::default(), } } fn new_empty(source_map: &'sess SourceMap) -> Self { Self { - serialized_data: Vec::new(), + serialized_data: RwLock::new(None), file_index_to_stable_id: Default::default(), file_index_to_file: Default::default(), - cnum_map: OnceCell::new(), source_map, current_side_effects: Default::default(), query_result_index: Default::default(), @@ -238,13 +204,27 @@ expn_data: UnhashMap::default(), foreign_expn_data: UnhashMap::default(), hygiene_context: Default::default(), - foreign_def_path_hashes: Default::default(), - latest_foreign_def_path_hashes: Default::default(), - def_path_hash_to_def_id_cache: Default::default(), } } - fn serialize(&self, tcx: TyCtxt<'sess>, encoder: &mut FileEncoder) -> FileEncodeResult { + /// Execute all cache promotions and release the serialized backing Mmap. + /// + /// Cache promotions require invoking queries, which needs to read the serialized data. + /// In order to serialize the new on-disk cache, the former on-disk cache file needs to be + /// deleted, hence we won't be able to refer to its memmapped data. + fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>) { + // Load everything into memory so we can write it out to the on-disk + // cache. The vast majority of cacheable query results should already + // be in memory, so this should be a cheap operation. + // Do this *before* we clone 'latest_foreign_def_path_hashes', since + // loading existing queries may cause us to create new DepNodes, which + // may in turn end up invoking `store_foreign_def_id_hash` + tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); + + *self.serialized_data.write() = None; + } + + fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -266,22 +246,6 @@ (file_to_file_index, file_index_to_stable_id) }; - // Register any dep nodes that we reused from the previous session, - // but didn't `DepNode::construct` in this session. This ensures - // that their `DefPathHash` to `RawDefId` mappings are registered - // in 'latest_foreign_def_path_hashes' if necessary, since that - // normally happens in `DepNode::construct`. - tcx.dep_graph.register_reused_dep_nodes(tcx); - - // Load everything into memory so we can write it out to the on-disk - // cache. The vast majority of cacheable query results should already - // be in memory, so this should be a cheap operation. - // Do this *before* we clone 'latest_foreign_def_path_hashes', since - // loading existing queries may cause us to create new DepNodes, which - // may in turn end up invoking `store_foreign_def_id_hash` - tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); - - let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone(); let hygiene_encode_context = HygieneEncodeContext::default(); let mut encoder = CacheEncoder { @@ -293,7 +257,6 @@ source_map: CachingSourceMapView::new(tcx.sess.source_map()), file_to_file_index, hygiene_context: &hygiene_encode_context, - latest_foreign_def_path_hashes, }; // Encode query results. @@ -370,9 +333,6 @@ }, )?; - let foreign_def_path_hashes = - std::mem::take(&mut encoder.latest_foreign_def_path_hashes); - // `Encode the file footer. let footer_pos = encoder.position() as u64; encoder.encode_tagged( @@ -385,7 +345,6 @@ syntax_contexts, expn_data, foreign_expn_data, - foreign_def_path_hashes, }, )?; @@ -400,80 +359,21 @@ }) } - fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> Option { - let mut cache = self.def_path_hash_to_def_id_cache.lock(); - match cache.entry(hash) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - debug!("def_path_hash_to_def_id({:?})", hash); - // Check if the `DefPathHash` corresponds to a definition in the current - // crate - if let Some(def_id) = - tcx.definitions_untracked().local_def_path_hash_to_def_id(hash) - { - let def_id = def_id.to_def_id(); - e.insert(Some(def_id)); - return Some(def_id); - } - // This `raw_def_id` represents the `DefId` of this `DefPathHash` in - // the *previous* compliation session. The `DefPathHash` includes the - // owning crate, so if the corresponding definition still exists in the - // current compilation session, the crate is guaranteed to be the same - // (otherwise, we would compute a different `DefPathHash`). - let raw_def_id = self.get_raw_def_id(&hash)?; - debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); - // If the owning crate no longer exists, the corresponding definition definitely - // no longer exists. - let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?; - debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); - // If our `DefPathHash` corresponded to a definition in the local crate, - // we should have either found it in `local_def_path_hash_to_def_id`, or - // never attempted to load it in the first place. Any query result or `DepNode` - // that references a local `DefId` should depend on some HIR-related `DepNode`. - // If a local definition is removed/modified such that its old `DefPathHash` - // no longer has a corresponding definition, that HIR-related `DepNode` should - // end up red. This should prevent us from ever calling - // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any - // queries involved. - debug_assert_ne!(krate, LOCAL_CRATE); - // Try to find a definition in the current session, using the previous `DefIndex` - // as an initial guess. - let opt_def_id = - tcx.cstore_untracked().def_path_hash_to_def_id(krate, raw_def_id.index, hash); - debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); - e.insert(opt_def_id); - opt_def_id - } - } - } + fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> DefId { + debug!("def_path_hash_to_def_id({:?})", hash); - fn register_reused_dep_node(&self, tcx: TyCtxt<'sess>, dep_node: &DepNode) { - // For reused dep nodes, we only need to store the mapping if the node - // is one whose query key we can reconstruct from the hash. We use the - // mapping to aid that reconstruction in the next session. While we also - // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, - // they're already registered during `DefId` encoding. - if dep_node.kind.can_reconstruct_query_key() { - let hash = DefPathHash(dep_node.hash.into()); - - // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to - // `latest_foreign_def_path_hashes`, since the `RawDefId` might have - // changed in the current compilation session (e.g. we've added/removed crates, - // or added/removed definitions before/after the target definition). - if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { - if !def_id.is_local() { - self.store_foreign_def_id_hash(def_id, hash); - } - } - } - } + let stable_crate_id = hash.stable_crate_id(); - fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { - // We may overwrite an existing entry, but it will have the same value, - // so it's fine - self.latest_foreign_def_path_hashes - .lock() - .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); + // If this is a DefPathHash from the local crate, we can look up the + // DefId in the tcx's `Definitions`. + if stable_crate_id == tcx.sess.local_stable_crate_id() { + tcx.definitions_untracked().local_def_path_hash_to_def_id(hash).to_def_id() + } else { + // If this is a DefPathHash from an upstream crate, let the CrateStore map + // it to a DefId. + let cnum = tcx.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id); + tcx.cstore_untracked().def_path_hash_to_def_id(cnum, hash) + } } } @@ -505,17 +405,6 @@ debug_assert!(prev.is_none()); } - fn get_raw_def_id(&self, hash: &DefPathHash) -> Option { - self.foreign_def_path_hashes.get(hash).copied() - } - - fn try_remap_cnum(&self, tcx: TyCtxt<'_>, stable_crate_id: StableCrateId) -> Option { - let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx)); - debug!("try_remap_cnum({:?}): cnum_map={:?}", stable_crate_id, cnum_map); - - cnum_map.get(&stable_crate_id).copied() - } - /// Returns the cached query result if there is something in the cache for /// the given `SerializedDepNodeIndex`; otherwise returns `None`. pub fn try_load_query_result<'tcx, T>( @@ -564,7 +453,7 @@ }) } - fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>( + fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>( &'sess self, tcx: TyCtxt<'tcx>, pos: AbsoluteBytePos, @@ -573,13 +462,11 @@ where T: Decodable>, { - let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx)); - + let serialized_data = self.serialized_data.read(); let mut decoder = CacheDecoder { tcx, - opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), + opaque: opaque::Decoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()), source_map: self.source_map, - cnum_map, file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), @@ -590,23 +477,6 @@ }; f(&mut decoder) } - - // This function builds mapping from previous-session-`CrateNum` to - // current-session-`CrateNum`. There might be `CrateNum`s from the previous - // `Session` that don't occur in the current one. For these, the mapping - // maps to None. - fn compute_cnum_map(tcx: TyCtxt<'_>) -> UnhashMap { - tcx.dep_graph.with_ignore(|| { - tcx.crates(()) - .iter() - .chain(std::iter::once(&LOCAL_CRATE)) - .map(|&cnum| { - let hash = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); - (hash, cnum) - }) - .collect() - }) - } } //- DECODING ------------------------------------------------------------------- @@ -618,7 +488,6 @@ tcx: TyCtxt<'tcx>, opaque: opaque::Decoder<'a>, source_map: &'a SourceMap, - cnum_map: &'a UnhashMap, file_index_to_file: &'a Lock>>, file_index_to_stable_id: &'a FxHashMap, alloc_decoding_session: AllocDecodingSession<'a>, @@ -631,10 +500,10 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc { let CacheDecoder { + tcx, ref file_index_to_file, ref file_index_to_stable_id, ref source_map, - ref cnum_map, .. } = *self; @@ -642,7 +511,7 @@ .borrow_mut() .entry(index) .or_insert_with(|| { - let stable_id = file_index_to_stable_id[&index].translate(cnum_map); + let stable_id = file_index_to_stable_id[&index].translate(tcx); source_map .source_file_by_stable_id(stable_id) .expect("failed to lookup `SourceFile` in new context") @@ -784,7 +653,7 @@ return Ok(expn_id); } - let krate = decoder.cnum_map[&hash.stable_crate_id()]; + let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id()); let expn_id = if krate == LOCAL_CRATE { // We look up the position of the associated `ExpnData` and decode it. @@ -795,33 +664,58 @@ let data: ExpnData = decoder .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA))?; - rustc_span::hygiene::register_local_expn_id(data, hash) + let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash); + + #[cfg(debug_assertions)] + { + use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + let mut hcx = decoder.tcx.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + hcx.while_hashing_spans(true, |hcx| { + expn_id.expn_data().hash_stable(hcx, &mut hasher) + }); + let local_hash: u64 = hasher.finish(); + debug_assert_eq!(hash.local_hash(), local_hash); + } + + expn_id } else { let index_guess = decoder.foreign_expn_data[&hash]; - decoder.tcx.cstore_untracked().expn_hash_to_expn_id(krate, index_guess, hash) + decoder.tcx.cstore_untracked().expn_hash_to_expn_id( + decoder.tcx.sess, + krate, + index_guess, + hash, + ) }; - #[cfg(debug_assertions)] - { - use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - let mut hcx = decoder.tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - hcx.while_hashing_spans(true, |hcx| expn_id.expn_data().hash_stable(hcx, &mut hasher)); - let local_hash: u64 = hasher.finish(); - debug_assert_eq!(hash.local_hash(), local_hash); - } - + debug_assert_eq!(expn_id.krate, krate); Ok(expn_id) } } impl<'a, 'tcx> Decodable> for Span { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { + let ctxt = SyntaxContext::decode(decoder)?; + let parent = Option::::decode(decoder)?; let tag: u8 = Decodable::decode(decoder)?; if tag == TAG_PARTIAL_SPAN { - let ctxt = SyntaxContext::decode(decoder)?; - return Ok(DUMMY_SP.with_ctxt(ctxt)); + return Ok(Span::new(BytePos(0), BytePos(0), ctxt, parent)); + } else if tag == TAG_RELATIVE_SPAN { + let dlo = u32::decode(decoder)?; + let dto = u32::decode(decoder)?; + + let enclosing = + decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data_untracked(); + let span = Span::new( + enclosing.lo + BytePos::from_u32(dlo), + enclosing.lo + BytePos::from_u32(dto), + ctxt, + parent, + ); + + return Ok(span); } else { debug_assert_eq!(tag, TAG_FULL_SPAN); } @@ -830,20 +724,19 @@ let line_lo = usize::decode(decoder)?; let col_lo = BytePos::decode(decoder)?; let len = BytePos::decode(decoder)?; - let ctxt = SyntaxContext::decode(decoder)?; let file_lo = decoder.file_index_to_file(file_lo_index); let lo = file_lo.lines[line_lo - 1] + col_lo; let hi = lo + len; - Ok(Span::new(lo, hi, ctxt)) + Ok(Span::new(lo, hi, ctxt, parent)) } } impl<'a, 'tcx> Decodable> for CrateNum { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { let stable_id = StableCrateId::decode(d)?; - let cnum = d.cnum_map[&stable_id]; + let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id); Ok(cnum) } } @@ -871,12 +764,7 @@ // If we get to this point, then all of the query inputs were green, // which means that the definition with this hash is guaranteed to // still exist in the current compilation session. - Ok(d.tcx() - .on_disk_cache - .as_ref() - .unwrap() - .def_path_hash_to_def_id(d.tcx(), def_path_hash) - .unwrap()) + Ok(d.tcx().on_disk_cache.as_ref().unwrap().def_path_hash_to_def_id(d.tcx(), def_path_hash)) } } @@ -894,7 +782,7 @@ } } -impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { RefDecodable::decode(d) } @@ -941,7 +829,6 @@ source_map: CachingSourceMapView<'tcx>, file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, hygiene_context: &'a HygieneEncodeContext, - latest_foreign_def_path_hashes: UnhashMap, } impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E> @@ -996,10 +883,22 @@ E: 'a + OpaqueEncoder, { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { - let span_data = self.data(); - if self.is_dummy() { - TAG_PARTIAL_SPAN.encode(s)?; - return span_data.ctxt.encode(s); + let span_data = self.data_untracked(); + span_data.ctxt.encode(s)?; + span_data.parent.encode(s)?; + + if span_data.is_dummy() { + return TAG_PARTIAL_SPAN.encode(s); + } + + if let Some(parent) = span_data.parent { + let enclosing = s.tcx.definitions_untracked().def_span(parent).data_untracked(); + if enclosing.contains(span_data) { + TAG_RELATIVE_SPAN.encode(s)?; + (span_data.lo - enclosing.lo).to_u32().encode(s)?; + (span_data.hi - enclosing.lo).to_u32().encode(s)?; + return Ok(()); + } } let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo); @@ -1009,8 +908,7 @@ }; if partial_span { - TAG_PARTIAL_SPAN.encode(s)?; - return span_data.ctxt.encode(s); + return TAG_PARTIAL_SPAN.encode(s); } let (file_lo, line_lo, col_lo) = pos.unwrap(); @@ -1023,8 +921,7 @@ source_file_index.encode(s)?; line_lo.encode(s)?; col_lo.encode(s)?; - len.encode(s)?; - span_data.ctxt.encode(s) + len.encode(s) } } @@ -1064,17 +961,7 @@ E: 'a + OpaqueEncoder, { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { - let def_path_hash = s.tcx.def_path_hash(*self); - // Store additional information when we encode a foreign `DefId`, - // so that we can map its `DefPathHash` back to a `DefId` in the next - // compilation session. - if !self.is_local() { - s.latest_foreign_def_path_hashes.insert( - def_path_hash, - RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() }, - ); - } - def_path_hash.encode(s) + s.tcx.def_path_hash(*self).encode(s) } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/plumbing.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/plumbing.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/plumbing.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/plumbing.rs 2021-11-29 19:27:11.000000000 +0000 @@ -36,7 +36,6 @@ impl HasDepContext for QueryCtxt<'tcx> { type DepKind = rustc_middle::dep_graph::DepKind; - type StableHashingContext = rustc_middle::ich::StableHashingContext<'tcx>; type DepContext = TyCtxt<'tcx>; #[inline] @@ -253,17 +252,17 @@ $error.emit(); Value::from_cycle_error($tcx) }}; - ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{ + ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{ $error.emit(); $tcx.sess.abort_if_errors(); unreachable!() }}; - ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{ + ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{ $error.delay_as_bug(); Value::from_cycle_error($tcx) }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - handle_cycle_error!([$($($modifiers)*)*][$($args)*]) + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + handle_cycle_error!([$($modifiers)*][$($args)*]) }; } @@ -271,11 +270,11 @@ ([]) => {{ false }}; - ([anon $($rest:tt)*]) => {{ + ([(anon) $($rest:tt)*]) => {{ true }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => { - is_anon!([$($($modifiers)*)*]) + ([$other:tt $($modifiers:tt)*]) => { + is_anon!([$($modifiers)*]) }; } @@ -283,11 +282,11 @@ ([]) => {{ false }}; - ([eval_always $($rest:tt)*]) => {{ + ([(eval_always) $($rest:tt)*]) => {{ true }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => { - is_eval_always!([$($($modifiers)*)*]) + ([$other:tt $($modifiers:tt)*]) => { + is_eval_always!([$($modifiers)*]) }; } @@ -295,11 +294,11 @@ ([][$hcx:expr, $result:expr]) => {{ dep_graph::hash_result($hcx, &$result) }}; - ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{ + ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{ None }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - hash_result!([$($($modifiers)*)*][$($args)*]) + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + hash_result!([$($modifiers)*][$($args)*]) }; } @@ -321,10 +320,13 @@ pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame { let kind = dep_graph::DepKind::$name; let name = stringify!($name); - let description = ty::print::with_forced_impl_filename_line( + // Disable visible paths printing for performance reasons. + // Showing visible path instead of any path is not that important in production. + let description = ty::print::with_no_visible_paths( + || ty::print::with_forced_impl_filename_line( // Force filename-line mode to avoid invoking `type_of` query. || queries::$name::describe(tcx, key) - ); + )); let description = if tcx.sess.verbose() { format!("{} [{}]", description, name) } else { @@ -426,6 +428,7 @@ use rustc_middle::ty::query::query_keys; use rustc_query_system::dep_graph::DepNodeParams; use rustc_query_system::query::{force_query, QueryDescription}; + use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. pub const Null: QueryStruct = QueryStruct { @@ -452,9 +455,9 @@ const is_anon: bool = is_anon!([$($modifiers)*]); #[inline(always)] - fn can_reconstruct_query_key() -> bool { + fn fingerprint_style() -> FingerprintStyle { as DepNodeParams>> - ::can_reconstruct_query_key() + ::fingerprint_style() } fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option> { @@ -470,7 +473,7 @@ return } - if !can_reconstruct_query_key() { + if !fingerprint_style().reconstructible() { return } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/stats.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/stats.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_impl/src/stats.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_impl/src/stats.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ use std::any::type_name; use std::mem; -#[cfg(debug_assertions)] -use std::sync::atomic::Ordering; trait KeyStats { fn key_stats(&self, stats: &mut QueryStats); @@ -27,7 +25,6 @@ #[derive(Clone)] struct QueryStats { name: &'static str, - cache_hits: usize, key_size: usize, key_type: &'static str, value_size: usize, @@ -42,10 +39,6 @@ { let mut stats = QueryStats { name, - #[cfg(debug_assertions)] - cache_hits: map.cache_hits.load(Ordering::Relaxed), - #[cfg(not(debug_assertions))] - cache_hits: 0, key_size: mem::size_of::(), key_type: type_name::(), value_size: mem::size_of::(), @@ -63,12 +56,6 @@ pub fn print_stats(tcx: TyCtxt<'_>) { let queries = query_stats(tcx); - if cfg!(debug_assertions) { - let hits: usize = queries.iter().map(|s| s.cache_hits).sum(); - let results: usize = queries.iter().map(|s| s.entry_count).sum(); - eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64); - } - let mut query_key_sizes = queries.clone(); query_key_sizes.sort_by_key(|q| q.key_size); eprintln!("\nLarge query keys:"); @@ -83,20 +70,6 @@ eprintln!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type); } - if cfg!(debug_assertions) { - let mut query_cache_hits = queries.clone(); - query_cache_hits.sort_by_key(|q| q.cache_hits); - eprintln!("\nQuery cache hits:"); - for q in query_cache_hits.iter().rev() { - eprintln!( - " {} - {} ({}%)", - q.name, - q.cache_hits, - q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64 - ); - } - } - let mut query_value_count = queries.clone(); query_value_count.sort_by_key(|q| q.entry_count); eprintln!("\nQuery value count:"); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_query_system" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false @@ -10,12 +10,16 @@ rustc_arena = { path = "../rustc_arena" } tracing = "0.1" rustc-rayon-core = "0.3.1" +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } -rustc_macros = { path = "../rustc_macros" } +rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } parking_lot = "0.11" smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/dep_node.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/dep_node.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/dep_node.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/dep_node.rs 2021-11-29 19:27:11.000000000 +0000 @@ -42,29 +42,17 @@ //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. -use super::{DepContext, DepKind}; +use super::{DepContext, DepKind, FingerprintStyle}; +use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - use std::fmt; use std::hash::Hash; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] pub struct DepNode { pub kind: K, - // Important - whenever a `DepNode` is constructed, we need to make - // sure to register a `DefPathHash -> DefId` mapping if needed. - // This is currently done in two places: - // - // * When a `DepNode::construct` is called, `arg.to_fingerprint()` - // is responsible for calling `OnDiskCache::store_foreign_def_id_hash` - // if needed - // * When we serialize the on-disk cache, `OnDiskCache::serialize` is - // responsible for calling `DepGraph::register_reused_dep_nodes`. - // - // FIXME: Enforce this by preventing manual construction of `DefNode` - // (e.g. add a `_priv: ()` field) pub hash: PackedFingerprint, } @@ -87,7 +75,7 @@ #[cfg(debug_assertions)] { - if !kind.can_reconstruct_query_key() + if !kind.fingerprint_style().reconstructible() && (tcx.sess().opts.debugging_opts.incremental_info || tcx.sess().opts.debugging_opts.query_dep_graph) { @@ -106,7 +94,7 @@ } pub trait DepNodeParams: fmt::Debug + Sized { - fn can_reconstruct_query_key() -> bool; + fn fingerprint_style() -> FingerprintStyle; /// This method turns the parameters of a DepNodeConstructor into an opaque /// Fingerprint to be used in DepNode. @@ -123,7 +111,7 @@ /// This method tries to recover the query key from the given `DepNode`, /// something which is needed when forcing `DepNode`s during red-green /// evaluation. The query system will only call this method if - /// `can_reconstruct_query_key()` is `true`. + /// `fingerprint_style()` is not `FingerprintStyle::Opaque`. /// It is always valid to return `None` here, in which case incremental /// compilation will treat the query as having changed instead of forcing it. fn recover(tcx: Ctxt, dep_node: &DepNode) -> Option; @@ -131,11 +119,11 @@ impl DepNodeParams for T where - T: HashStable + fmt::Debug, + T: for<'a> HashStable> + fmt::Debug, { #[inline] - default fn can_reconstruct_query_key() -> bool { - false + default fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::Opaque } default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/graph.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/graph.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,4 @@ +use parking_lot::Mutex; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef}; @@ -7,10 +8,9 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; use rustc_index::vec::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; - -use parking_lot::Mutex; use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; +use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use std::sync::atomic::Ordering::Relaxed; @@ -18,6 +18,7 @@ use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; +use crate::ich::StableHashingContext; use crate::query::{QueryContext, QuerySideEffects}; #[cfg(debug_assertions)] @@ -95,9 +96,9 @@ dep_node_debug: Lock, String>>, } -pub fn hash_result(hcx: &mut HashCtxt, result: &R) -> Option +pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option where - R: HashStable, + R: for<'a> HashStable>, { let mut stable_hasher = StableHasher::new(); result.hash_stable(hcx, &mut stable_hasher); @@ -208,89 +209,99 @@ /// `arg` parameter. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html - pub fn with_task, A, R>( + pub fn with_task, A: Debug, R>( &self, key: DepNode, cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, - hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, + hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option, ) -> (R, DepNodeIndex) { - self.with_task_impl( - key, - cx, - arg, - task, - |_key| { - Some(TaskDeps { - #[cfg(debug_assertions)] - node: Some(_key), - reads: SmallVec::new(), - read_set: Default::default(), - phantom_data: PhantomData, - }) - }, - hash_result, - ) + if self.is_fully_enabled() { + self.with_task_impl(key, cx, arg, task, hash_result) + } else { + // Incremental compilation is turned off. We just execute the task + // without tracking. We still provide a dep-node index that uniquely + // identifies the task so that we have a cheap way of referring to + // the query for self-profiling. + (task(cx, arg), self.next_virtual_depnode_index()) + } } - fn with_task_impl, A, R>( + fn with_task_impl, A: Debug, R>( &self, key: DepNode, cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, - create_task: fn(DepNode) -> Option>, - hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, + hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option, ) -> (R, DepNodeIndex) { - if let Some(ref data) = self.data { - let dcx = cx.dep_context(); - let task_deps = create_task(key).map(Lock::new); - let result = K::with_deps(task_deps.as_ref(), || task(cx, arg)); - let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); - - let mut hcx = dcx.create_stable_hashing_context(); - let hashing_timer = dcx.profiler().incr_result_hashing(); - let current_fingerprint = hash_result(&mut hcx, &result); - - let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks; - - // Get timer for profiling `DepNode` interning - let node_intern_timer = self - .node_intern_event_id - .map(|eid| dcx.profiler().generic_activity_with_event_id(eid)); - // Intern the new `DepNode`. - let (dep_node_index, prev_and_color) = data.current.intern_node( - dcx.profiler(), - &data.previous, - key, - edges, - current_fingerprint, - print_status, - ); - drop(node_intern_timer); + // This function is only called when the graph is enabled. + let data = self.data.as_ref().unwrap(); - hashing_timer.finish_with_query_invocation_id(dep_node_index.into()); + // If the following assertion triggers, it can have two reasons: + // 1. Something is wrong with DepNode creation, either here or + // in `DepGraph::try_mark_green()`. + // 2. Two distinct query keys get mapped to the same `DepNode` + // (see for example #48923). + assert!( + !self.dep_node_exists(&key), + "forcing query with already existing `DepNode`\n\ + - query-key: {:?}\n\ + - dep-node: {:?}", + arg, + key + ); - if let Some((prev_index, color)) = prev_and_color { - debug_assert!( - data.colors.get(prev_index).is_none(), - "DepGraph::with_task() - Duplicate DepNodeColor \ - insertion for {:?}", - key - ); + let task_deps = if key.kind.is_eval_always() { + None + } else { + Some(Lock::new(TaskDeps { + #[cfg(debug_assertions)] + node: Some(key), + reads: SmallVec::new(), + read_set: Default::default(), + phantom_data: PhantomData, + })) + }; + let result = K::with_deps(task_deps.as_ref(), || task(cx, arg)); + let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); + + let dcx = cx.dep_context(); + let mut hcx = dcx.create_stable_hashing_context(); + let hashing_timer = dcx.profiler().incr_result_hashing(); + let current_fingerprint = hash_result(&mut hcx, &result); + + let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks; + + // Get timer for profiling `DepNode` interning + let node_intern_timer = + self.node_intern_event_id.map(|eid| dcx.profiler().generic_activity_with_event_id(eid)); + // Intern the new `DepNode`. + let (dep_node_index, prev_and_color) = data.current.intern_node( + dcx.profiler(), + &data.previous, + key, + edges, + current_fingerprint, + print_status, + ); + drop(node_intern_timer); - data.colors.insert(prev_index, color); - } + hashing_timer.finish_with_query_invocation_id(dep_node_index.into()); - (result, dep_node_index) - } else { - // Incremental compilation is turned off. We just execute the task - // without tracking. We still provide a dep-node index that uniquely - // identifies the task so that we have a cheap way of referring to - // the query for self-profiling. - (task(cx, arg), self.next_virtual_depnode_index()) + if let Some((prev_index, color)) = prev_and_color { + debug_assert!( + data.colors.get(prev_index).is_none(), + "DepGraph::with_task() - Duplicate DepNodeColor \ + insertion for {:?}", + key + ); + + data.colors.insert(prev_index, color); } + + (result, dep_node_index) } /// Executes something within an "anonymous" task, that is, a task the @@ -357,19 +368,6 @@ } } - /// Executes something within an "eval-always" task which is a task - /// that runs whenever anything changes. - pub fn with_eval_always_task, A, R>( - &self, - key: DepNode, - cx: Ctxt, - arg: A, - task: fn(Ctxt, A) -> R, - hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, - ) -> (R, DepNodeIndex) { - self.with_task_impl(key, cx, arg, task, |_| None, hash_result) - } - #[inline] pub fn read_index(&self, dep_node_index: DepNodeIndex) { if let Some(ref data) = self.data { @@ -484,22 +482,11 @@ None } - /// Try to read a node index for the node dep_node. + /// Try to mark a node index for the node dep_node. + /// /// A node will have an index, when it's already been marked green, or when we can mark it /// green. This function will mark the current task as a reader of the specified node, when /// a node index can be found for that node. - pub fn try_mark_green_and_read>( - &self, - tcx: Ctxt, - dep_node: &DepNode, - ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { - self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| { - debug_assert!(self.is_green(&dep_node)); - self.read_index(dep_node_index); - (prev_index, dep_node_index) - }) - } - pub fn try_mark_green>( &self, tcx: Ctxt, @@ -772,20 +759,6 @@ } } } - - // Register reused dep nodes (i.e. nodes we've marked red or green) with the context. - pub fn register_reused_dep_nodes>(&self, tcx: Ctxt) { - let data = self.data.as_ref().unwrap(); - for prev_index in data.colors.values.indices() { - match data.colors.get(prev_index) { - Some(DepNodeColor::Red) | Some(DepNodeColor::Green(_)) => { - let dep_node = data.previous.index_to_node(prev_index); - tcx.register_reused_dep_node(&dep_node); - } - None => {} - } - } - } pub fn print_incremental_info(&self) { if let Some(data) = &self.data { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,7 @@ pub use query::DepGraphQuery; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; +use crate::ich::StableHashingContext; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_serialize::{opaque::FileEncoder, Encodable}; @@ -19,16 +20,13 @@ pub trait DepContext: Copy { type DepKind: self::DepKind; - type StableHashingContext; /// Create a hashing context for hashing new results. - fn create_stable_hashing_context(&self) -> Self::StableHashingContext; + fn create_stable_hashing_context(&self) -> StableHashingContext<'_>; /// Access the DepGraph. fn dep_graph(&self) -> &DepGraph; - fn register_reused_dep_node(&self, dep_node: &DepNode); - /// Access the profiler. fn profiler(&self) -> &SelfProfilerRef; @@ -38,18 +36,13 @@ pub trait HasDepContext: Copy { type DepKind: self::DepKind; - type StableHashingContext; - type DepContext: self::DepContext< - DepKind = Self::DepKind, - StableHashingContext = Self::StableHashingContext, - >; + type DepContext: self::DepContext; fn dep_context(&self) -> &Self::DepContext; } impl HasDepContext for T { type DepKind = T::DepKind; - type StableHashingContext = T::StableHashingContext; type DepContext = Self; fn dep_context(&self) -> &Self::DepContext { @@ -57,6 +50,27 @@ } } +/// Describes the contents of the fingerprint generated by a given query. +#[derive(PartialEq, Eq, Copy, Clone)] +pub enum FingerprintStyle { + /// The fingerprint is actually a DefPathHash. + DefPathHash, + /// Query key was `()` or equivalent, so fingerprint is just zero. + Unit, + /// Some opaque hash. + Opaque, +} + +impl FingerprintStyle { + #[inline] + pub fn reconstructible(self) -> bool { + match self { + FingerprintStyle::DefPathHash | FingerprintStyle::Unit => true, + FingerprintStyle::Opaque => false, + } + } +} + /// Describe the different families of dependency nodes. pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable + 'static { const NULL: Self; @@ -80,5 +94,5 @@ where OP: for<'a> FnOnce(Option<&'a Lock>>); - fn can_reconstruct_query_key(&self) -> bool; + fn fingerprint_style(&self) -> FingerprintStyle; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/serialized.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/serialized.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/serialized.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/dep_graph/serialized.rs 2021-11-29 19:27:11.000000000 +0000 @@ -99,7 +99,7 @@ impl<'a, K: DepKind + Decodable>> Decodable> for SerializedDepGraph { - #[instrument(skip(d))] + #[instrument(level = "debug", skip(d))] fn decode(d: &mut opaque::Decoder<'a>) -> Result, String> { let start_position = d.position(); @@ -187,7 +187,7 @@ } } - #[instrument(skip(self, record_graph))] + #[instrument(level = "debug", skip(self, record_graph))] fn encode_node( &mut self, node: &NodeInfo, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/hcx.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/hcx.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/hcx.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/hcx.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,212 @@ +use crate::ich; +use rustc_ast as ast; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::Lrc; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::definitions::{DefPathHash, Definitions}; +use rustc_session::cstore::CrateStore; +use rustc_session::Session; +use rustc_span::source_map::SourceMap; +use rustc_span::symbol::Symbol; +use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData}; + +fn compute_ignored_attr_names() -> FxHashSet { + debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty()); + ich::IGNORED_ATTRIBUTES.iter().copied().collect() +} + +/// This is the context state available during incr. comp. hashing. It contains +/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e., +/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various +/// things (e.g., each `DefId`/`DefPath` is only hashed once). +#[derive(Clone)] +pub struct StableHashingContext<'a> { + definitions: &'a Definitions, + cstore: &'a dyn CrateStore, + pub(super) body_resolver: BodyResolver<'a>, + hash_spans: bool, + hash_bodies: bool, + pub(super) node_id_hashing_mode: NodeIdHashingMode, + + // Very often, we are hashing something that does not need the + // `CachingSourceMapView`, so we initialize it lazily. + raw_source_map: &'a SourceMap, + caching_source_map: Option>, +} + +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum NodeIdHashingMode { + Ignore, + HashDefPath, +} + +/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`. +/// We could also just store a plain reference to the `hir::Crate` but we want +/// to avoid that the crate is used to get untracked access to all of the HIR. +#[derive(Clone, Copy)] +pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>); + +impl<'tcx> BodyResolver<'tcx> { + /// Returns a reference to the `hir::Body` with the given `BodyId`. + /// **Does not do any tracking**; use carefully. + pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> { + self.0.body(id) + } +} + +impl<'a> StableHashingContext<'a> { + /// The `krate` here is only used for mapping `BodyId`s to `Body`s. + /// Don't use it for anything else or you'll run the risk of + /// leaking data out of the tracking system. + #[inline] + fn new_with_or_without_spans( + sess: &'a Session, + krate: &'a hir::Crate<'a>, + definitions: &'a Definitions, + cstore: &'a dyn CrateStore, + always_ignore_spans: bool, + ) -> Self { + let hash_spans_initial = + !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans; + + StableHashingContext { + body_resolver: BodyResolver(krate), + definitions, + cstore, + caching_source_map: None, + raw_source_map: sess.source_map(), + hash_spans: hash_spans_initial, + hash_bodies: true, + node_id_hashing_mode: NodeIdHashingMode::HashDefPath, + } + } + + #[inline] + pub fn new( + sess: &'a Session, + krate: &'a hir::Crate<'a>, + definitions: &'a Definitions, + cstore: &'a dyn CrateStore, + ) -> Self { + Self::new_with_or_without_spans( + sess, + krate, + definitions, + cstore, + /*always_ignore_spans=*/ false, + ) + } + + #[inline] + pub fn ignore_spans( + sess: &'a Session, + krate: &'a hir::Crate<'a>, + definitions: &'a Definitions, + cstore: &'a dyn CrateStore, + ) -> Self { + let always_ignore_spans = true; + Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans) + } + + #[inline] + pub fn while_hashing_hir_bodies(&mut self, hash_bodies: bool, f: F) { + let prev_hash_bodies = self.hash_bodies; + self.hash_bodies = hash_bodies; + f(self); + self.hash_bodies = prev_hash_bodies; + } + + #[inline] + pub fn while_hashing_spans(&mut self, hash_spans: bool, f: F) { + let prev_hash_spans = self.hash_spans; + self.hash_spans = hash_spans; + f(self); + self.hash_spans = prev_hash_spans; + } + + #[inline] + pub fn with_node_id_hashing_mode( + &mut self, + mode: NodeIdHashingMode, + f: F, + ) { + let prev = self.node_id_hashing_mode; + self.node_id_hashing_mode = mode; + f(self); + self.node_id_hashing_mode = prev; + } + + #[inline] + pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash { + if let Some(def_id) = def_id.as_local() { + self.local_def_path_hash(def_id) + } else { + self.cstore.def_path_hash(def_id) + } + } + + #[inline] + pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash { + self.definitions.def_path_hash(def_id) + } + + #[inline] + pub fn hash_bodies(&self) -> bool { + self.hash_bodies + } + + #[inline] + pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> { + match self.caching_source_map { + Some(ref mut sm) => sm, + ref mut none => { + *none = Some(CachingSourceMapView::new(self.raw_source_map)); + none.as_mut().unwrap() + } + } + } + + #[inline] + pub fn is_ignored_attr(&self, name: Symbol) -> bool { + thread_local! { + static IGNORED_ATTRIBUTES: FxHashSet = compute_ignored_attr_names(); + } + IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name)) + } +} + +impl<'a> HashStable> for ast::NodeId { + #[inline] + fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { + panic!("Node IDs should not appear in incremental state"); + } +} + +impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { + #[inline] + fn hash_spans(&self) -> bool { + self.hash_spans + } + + #[inline] + fn def_path_hash(&self, def_id: DefId) -> DefPathHash { + self.def_path_hash(def_id) + } + + #[inline] + fn def_span(&self, def_id: LocalDefId) -> Span { + self.definitions.def_span(def_id) + } + + #[inline] + fn span_data_to_lines_and_cols( + &mut self, + span: &SpanData, + ) -> Option<(Lrc, usize, BytePos, usize, BytePos)> { + self.source_map().span_data_to_lines_and_cols(span) + } +} + +impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/impls_hir.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/impls_hir.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/impls_hir.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/impls_hir.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,155 @@ +//! This module contains `HashStable` implementations for various HIR data +//! types in no particular order. + +use crate::ich::{NodeIdHashingMode, StableHashingContext}; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_hir as hir; +use rustc_hir::definitions::DefPathHash; +use smallvec::SmallVec; +use std::mem; + +impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { + #[inline] + fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) { + let hcx = self; + match hcx.node_id_hashing_mode { + NodeIdHashingMode::Ignore => { + // Don't do anything. + } + NodeIdHashingMode::HashDefPath => { + let hir::HirId { owner, local_id } = hir_id; + + hcx.local_def_path_hash(owner).hash_stable(hcx, hasher); + local_id.hash_stable(hcx, hasher); + } + } + } + + #[inline] + fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) { + let hcx = self; + if hcx.hash_bodies() { + hcx.body_resolver.body(id).hash_stable(hcx, hasher); + } + } + + #[inline] + fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) { + let hcx = self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + id.hash_stable(hcx, hasher); + }) + } + + #[inline] + fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) { + let hcx = self; + let hir::Mod { inner: ref inner_span, ref item_ids } = *module; + + inner_span.hash_stable(hcx, hasher); + + // Combining the `DefPathHash`s directly is faster than feeding them + // into the hasher. Because we use a commutative combine, we also don't + // have to sort the array. + let item_ids_hash = item_ids + .iter() + .map(|id| { + let def_path_hash = id.to_stable_hash_key(hcx); + def_path_hash.0 + }) + .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b)); + + item_ids.len().hash_stable(hcx, hasher); + item_ids_hash.hash_stable(hcx, hasher); + } + + fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) { + self.while_hashing_hir_bodies(true, |hcx| { + let hir::Expr { hir_id: _, ref span, ref kind } = *expr; + + span.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); + }) + } + + fn hash_hir_ty(&mut self, ty: &hir::Ty<'_>, hasher: &mut StableHasher) { + self.while_hashing_hir_bodies(true, |hcx| { + let hir::Ty { hir_id: _, ref kind, ref span } = *ty; + + kind.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }) + } + + fn hash_hir_visibility_kind( + &mut self, + vis: &hir::VisibilityKind<'_>, + hasher: &mut StableHasher, + ) { + let hcx = self; + mem::discriminant(vis).hash_stable(hcx, hasher); + match *vis { + hir::VisibilityKind::Public | hir::VisibilityKind::Inherited => { + // No fields to hash. + } + hir::VisibilityKind::Crate(sugar) => { + sugar.hash_stable(hcx, hasher); + } + hir::VisibilityKind::Restricted { ref path, hir_id } => { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + hir_id.hash_stable(hcx, hasher); + }); + path.hash_stable(hcx, hasher); + } + } + } + + #[inline] + fn hash_hir_item_like(&mut self, f: F) { + let prev_hash_node_ids = self.node_id_hashing_mode; + self.node_id_hashing_mode = NodeIdHashingMode::Ignore; + + f(self); + + self.node_id_hashing_mode = prev_hash_node_ids; + } +} + +impl<'a> HashStable> for hir::Body<'_> { + #[inline] + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + let hir::Body { params, value, generator_kind } = self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| { + params.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + generator_kind.hash_stable(hcx, hasher); + }); + } +} + +impl<'a> HashStable> for hir::TraitCandidate { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + let hir::TraitCandidate { def_id, import_ids } = self; + + def_id.hash_stable(hcx, hasher); + import_ids.hash_stable(hcx, hasher); + }); + } +} + +impl<'a> ToStableHashKey> for hir::TraitCandidate { + type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>); + + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { + let hir::TraitCandidate { def_id, import_ids } = self; + + ( + hcx.def_path_hash(*def_id), + import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(), + ) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/impls_syntax.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/impls_syntax.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/impls_syntax.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/impls_syntax.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,146 @@ +//! This module contains `HashStable` implementations for various data types +//! from `rustc_ast` in no particular order. + +use crate::ich::StableHashingContext; + +use rustc_ast as ast; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_span::{BytePos, NormalizedPos, SourceFile}; +use std::assert_matches::assert_matches; + +use smallvec::SmallVec; + +impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {} + +impl<'a> HashStable> for [ast::Attribute] { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + if self.is_empty() { + self.len().hash_stable(hcx, hasher); + return; + } + + // Some attributes are always ignored during hashing. + let filtered: SmallVec<[&ast::Attribute; 8]> = self + .iter() + .filter(|attr| { + !attr.is_doc_comment() + && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)) + }) + .collect(); + + filtered.len().hash_stable(hcx, hasher); + for attr in filtered { + attr.hash_stable(hcx, hasher); + } + } +} + +impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> { + fn hash_attr(&mut self, attr: &ast::Attribute, hasher: &mut StableHasher) { + // Make sure that these have been filtered out. + debug_assert!(!attr.ident().map_or(false, |ident| self.is_ignored_attr(ident.name))); + debug_assert!(!attr.is_doc_comment()); + + let ast::Attribute { kind, id: _, style, span } = attr; + if let ast::AttrKind::Normal(item, tokens) = kind { + item.hash_stable(self, hasher); + style.hash_stable(self, hasher); + span.hash_stable(self, hasher); + assert_matches!( + tokens.as_ref(), + None, + "Tokens should have been removed during lowering!" + ); + } else { + unreachable!(); + } + } +} + +impl<'a> HashStable> for SourceFile { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + let SourceFile { + name: _, // We hash the smaller name_hash instead of this + name_hash, + cnum, + // Do not hash the source as it is not encoded + src: _, + ref src_hash, + external_src: _, + start_pos, + end_pos: _, + ref lines, + ref multibyte_chars, + ref non_narrow_chars, + ref normalized_pos, + } = *self; + + (name_hash as u64).hash_stable(hcx, hasher); + + src_hash.hash_stable(hcx, hasher); + + // We only hash the relative position within this source_file + lines.len().hash_stable(hcx, hasher); + for &line in lines.iter() { + stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); + } + + // We only hash the relative position within this source_file + multibyte_chars.len().hash_stable(hcx, hasher); + for &char_pos in multibyte_chars.iter() { + stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); + } + + non_narrow_chars.len().hash_stable(hcx, hasher); + for &char_pos in non_narrow_chars.iter() { + stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); + } + + normalized_pos.len().hash_stable(hcx, hasher); + for &char_pos in normalized_pos.iter() { + stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher); + } + + cnum.hash_stable(hcx, hasher); + } +} + +fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 { + pos.0 - source_file_start.0 +} + +fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) { + let rustc_span::MultiByteChar { pos, bytes } = mbc; + + (pos.0 - source_file_start.0, bytes as u32) +} + +fn stable_non_narrow_char( + swc: rustc_span::NonNarrowChar, + source_file_start: BytePos, +) -> (u32, u32) { + let pos = swc.pos(); + let width = swc.width(); + + (pos.0 - source_file_start.0, width as u32) +} + +fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) { + let NormalizedPos { pos, diff } = np; + + (pos.0 - source_file_start.0, diff) +} + +impl<'tcx> HashStable> for rustc_feature::Features { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + // Unfortunately we cannot exhaustively list fields here, since the + // struct is macro generated. + self.declared_lang_features.hash_stable(hcx, hasher); + self.declared_lib_features.hash_stable(hcx, hasher); + + self.walk_feature_fields(|feature_name, value| { + feature_name.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + }); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/ich/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +//! ICH - Incremental Compilation Hash + +pub use self::hcx::{NodeIdHashingMode, StableHashingContext}; +use rustc_span::symbol::{sym, Symbol}; + +mod hcx; +mod impls_hir; +mod impls_syntax; + +pub const IGNORED_ATTRIBUTES: &[Symbol] = &[ + sym::cfg, + sym::rustc_if_this_changed, + sym::rustc_then_this_would_need, + sym::rustc_dirty, + sym::rustc_clean, + sym::rustc_partition_reused, + sym::rustc_partition_codegened, + sym::rustc_expected_cgu_reuse, +]; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,4 @@ +#![feature(assert_matches)] #![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(hash_raw_entry)] @@ -14,4 +15,5 @@ pub mod cache; pub mod dep_graph; +pub mod ich; pub mod query; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/query/config.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/query/config.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/query/config.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/query/config.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,7 @@ use crate::dep_graph::DepNode; use crate::dep_graph::SerializedDepNodeIndex; +use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; use crate::query::{QueryCacheStore, QueryContext, QueryState}; @@ -23,7 +24,7 @@ pub dep_kind: CTX::DepKind, pub eval_always: bool, - pub hash_result: fn(&mut CTX::StableHashingContext, &V) -> Option, + pub hash_result: fn(&mut StableHashingContext<'_>, &V) -> Option, pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V, pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool, pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option, @@ -39,7 +40,7 @@ pub(crate) fn hash_result( &self, - hcx: &mut CTX::StableHashingContext, + hcx: &mut StableHashingContext<'_>, value: &V, ) -> Option { (self.hash_result)(hcx, value) @@ -74,10 +75,8 @@ // Don't use this method to compute query results, instead use the methods on TyCtxt fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value; - fn hash_result( - hcx: &mut CTX::StableHashingContext, - result: &Self::Value, - ) -> Option; + fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value) + -> Option; fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/query/job.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/query/job.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/query/job.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/query/job.rs 2021-11-29 19:27:11.000000000 +0000 @@ -143,6 +143,8 @@ where D: Copy + Clone + Eq + Hash, { + #[cold] + #[inline(never)] pub(super) fn find_cycle_in_stack( &self, query_map: QueryMap, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/query/plumbing.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/query/plumbing.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_query_system/src/query/plumbing.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_query_system/src/query/plumbing.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,7 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeParams}; -use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams}; use crate::query::caches::QueryCache; use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt}; use crate::query::job::{ @@ -13,12 +12,12 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHasher}; +#[cfg(parallel_compiler)] +use rustc_data_structures::profiling::TimingGuard; use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded}; use rustc_data_structures::sync::{Lock, LockGuard}; use rustc_data_structures::thin_vec::ThinVec; -#[cfg(not(parallel_compiler))] -use rustc_errors::DiagnosticBuilder; -use rustc_errors::{Diagnostic, FatalError}; +use rustc_errors::{DiagnosticBuilder, FatalError}; use rustc_span::{Span, DUMMY_SP}; use std::cell::Cell; use std::collections::hash_map::Entry; @@ -27,24 +26,15 @@ use std::mem; use std::num::NonZeroU32; use std::ptr; -#[cfg(debug_assertions)] -use std::sync::atomic::{AtomicUsize, Ordering}; pub struct QueryCacheStore { cache: C, shards: Sharded, - #[cfg(debug_assertions)] - pub cache_hits: AtomicUsize, } impl Default for QueryCacheStore { fn default() -> Self { - Self { - cache: C::default(), - shards: Default::default(), - #[cfg(debug_assertions)] - cache_hits: AtomicUsize::new(0), - } + Self { cache: C::default(), shards: Default::default() } } } @@ -148,24 +138,21 @@ /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -struct JobOwner<'tcx, D, C> +struct JobOwner<'tcx, D, K> where D: Copy + Clone + Eq + Hash, - C: QueryCache, + K: Eq + Hash + Clone, { - state: &'tcx QueryState, - cache: &'tcx QueryCacheStore, - key: C::Key, + state: &'tcx QueryState, + key: K, id: QueryJobId, } #[cold] #[inline(never)] -#[cfg(not(parallel_compiler))] fn mk_cycle( tcx: CTX, - root: QueryJobId, - span: Span, + error: CycleError, handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V, cache: &dyn crate::query::QueryStorage, ) -> R @@ -174,20 +161,15 @@ V: std::fmt::Debug, R: Clone, { - let error: CycleError = root.find_cycle_in_stack( - tcx.try_collect_active_jobs().unwrap(), - &tcx.current_query_job(), - span, - ); let error = report_cycle(tcx.dep_context().sess(), error); let value = handle_cycle_error(tcx, error); cache.store_nocache(value) } -impl<'tcx, D, C> JobOwner<'tcx, D, C> +impl<'tcx, D, K> JobOwner<'tcx, D, K> where D: Copy + Clone + Eq + Hash, - C: QueryCache, + K: Eq + Hash + Clone, { /// Either gets a `JobOwner` corresponding the query, allowing us to /// start executing the query, or returns with the result of the query. @@ -199,14 +181,13 @@ /// for some compile-time benchmarks. #[inline(always)] fn try_start<'b, CTX>( - tcx: CTX, - state: &'b QueryState, - cache: &'b QueryCacheStore, + tcx: &'b CTX, + state: &'b QueryState, span: Span, - key: C::Key, + key: K, lookup: QueryLookup, - query: &QueryVtable, - ) -> TryGetJob<'b, CTX::DepKind, C> + dep_kind: CTX::DepKind, + ) -> TryGetJob<'b, CTX::DepKind, K> where CTX: QueryContext, { @@ -227,26 +208,24 @@ let key = entry.key().clone(); entry.insert(QueryResult::Started(job)); - let global_id = QueryJobId::new(id, shard, query.dep_kind); - let owner = JobOwner { state, cache, id: global_id, key }; + let global_id = QueryJobId::new(id, shard, dep_kind); + let owner = JobOwner { state, id: global_id, key }; return TryGetJob::NotYetStarted(owner); } Entry::Occupied(mut entry) => { match entry.get_mut() { #[cfg(not(parallel_compiler))] QueryResult::Started(job) => { - let id = QueryJobId::new(job.id, shard, query.dep_kind); + let id = QueryJobId::new(job.id, shard, dep_kind); drop(state_lock); // If we are single-threaded we know that we have cycle error, // so we just return the error. - return TryGetJob::Cycle(mk_cycle( - tcx, - id, + return TryGetJob::Cycle(id.find_cycle_in_stack( + tcx.try_collect_active_jobs().unwrap(), + &tcx.current_query_job(), span, - query.handle_cycle_error, - &cache.cache, )); } #[cfg(parallel_compiler)] @@ -258,7 +237,6 @@ // Get the latch out let latch = job.latch(); - let key = entry.key().clone(); drop(state_lock); @@ -266,30 +244,10 @@ // thread. let result = latch.wait_on(tcx.current_query_job(), span); - if let Err(cycle) = result { - let cycle = report_cycle(tcx.dep_context().sess(), cycle); - let value = (query.handle_cycle_error)(tcx, cycle); - let value = cache.cache.store_nocache(value); - return TryGetJob::Cycle(value); + match result { + Ok(()) => TryGetJob::JobCompleted(query_blocked_prof_timer), + Err(cycle) => TryGetJob::Cycle(cycle), } - - let cached = cache - .cache - .lookup(cache, &key, |value, index| { - if unlikely!(tcx.dep_context().profiler().enabled()) { - tcx.dep_context().profiler().query_cache_hit(index.into()); - } - #[cfg(debug_assertions)] - { - cache.cache_hits.fetch_add(1, Ordering::Relaxed); - } - (value.clone(), index) - }) - .unwrap_or_else(|_| panic!("value must be in cache after waiting")); - - query_blocked_prof_timer.finish_with_query_invocation_id(cached.1.into()); - - return TryGetJob::JobCompleted(cached); } QueryResult::Poisoned => FatalError.raise(), } @@ -299,11 +257,18 @@ /// Completes the query by updating the query cache with the `result`, /// signals the waiter and forgets the JobOwner, so it won't poison the query - fn complete(self, result: C::Value, dep_node_index: DepNodeIndex) -> C::Stored { + fn complete( + self, + cache: &QueryCacheStore, + result: C::Value, + dep_node_index: DepNodeIndex, + ) -> C::Stored + where + C: QueryCache, + { // We can move out of `self` here because we `mem::forget` it below let key = unsafe { ptr::read(&self.key) }; let state = self.state; - let cache = self.cache; // Forget ourself so our destructor won't poison the query mem::forget(self); @@ -330,19 +295,10 @@ } } -fn with_diagnostics(f: F) -> (R, ThinVec) -where - F: FnOnce(Option<&Lock>>) -> R, -{ - let diagnostics = Lock::new(ThinVec::new()); - let result = f(Some(&diagnostics)); - (result, diagnostics.into_inner()) -} - -impl<'tcx, D, C> Drop for JobOwner<'tcx, D, C> +impl<'tcx, D, K> Drop for JobOwner<'tcx, D, K> where D: Copy + Clone + Eq + Hash, - C: QueryCache, + K: Eq + Hash + Clone, { #[inline(never)] #[cold] @@ -373,22 +329,22 @@ } /// The result of `try_start`. -enum TryGetJob<'tcx, D, C> +enum TryGetJob<'tcx, D, K> where D: Copy + Clone + Eq + Hash, - C: QueryCache, + K: Eq + Hash + Clone, { /// The query is not yet started. Contains a guard to the cache eventually used to start it. - NotYetStarted(JobOwner<'tcx, D, C>), + NotYetStarted(JobOwner<'tcx, D, K>), /// The query was already completed. /// Returns the result of the query and its dep-node index /// if it succeeded or a cycle error if it failed. #[cfg(parallel_compiler)] - JobCompleted((C::Stored, DepNodeIndex)), + JobCompleted(TimingGuard<'tcx>), /// Trying to execute the query resulted in a cycle. - Cycle(C::Stored), + Cycle(CycleError), } /// Checks if the query is already computed and in the cache. @@ -412,10 +368,6 @@ if unlikely!(tcx.profiler().enabled()) { tcx.profiler().query_cache_hit(index.into()); } - #[cfg(debug_assertions)] - { - cache.cache_hits.fetch_add(1, Ordering::Relaxed); - } tcx.dep_graph().read_index(index); on_hit(value) }) @@ -428,119 +380,142 @@ span: Span, key: C::Key, lookup: QueryLookup, + dep_node: Option>, query: &QueryVtable, compute: fn(CTX::DepContext, C::Key) -> C::Value, -) -> C::Stored +) -> (C::Stored, Option) where C: QueryCache, - C::Key: DepNodeParams, + C::Key: Clone + DepNodeParams, CTX: QueryContext, { - let job = match JobOwner::<'_, CTX::DepKind, C>::try_start( - tcx, + match JobOwner::<'_, CTX::DepKind, C::Key>::try_start( + &tcx, state, - cache, span, key.clone(), lookup, - query, + query.dep_kind, ) { - TryGetJob::NotYetStarted(job) => job, - TryGetJob::Cycle(result) => return result, + TryGetJob::NotYetStarted(job) => { + let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id, compute); + let result = job.complete(cache, result, dep_node_index); + (result, Some(dep_node_index)) + } + TryGetJob::Cycle(error) => { + let result = mk_cycle(tcx, error, query.handle_cycle_error, &cache.cache); + (result, None) + } #[cfg(parallel_compiler)] - TryGetJob::JobCompleted((v, index)) => { - tcx.dep_context().dep_graph().read_index(index); - return v; + TryGetJob::JobCompleted(query_blocked_prof_timer) => { + let (v, index) = cache + .cache + .lookup(cache, &key, |value, index| (value.clone(), index)) + .unwrap_or_else(|_| panic!("value must be in cache after waiting")); + + if unlikely!(tcx.dep_context().profiler().enabled()) { + tcx.dep_context().profiler().query_cache_hit(index.into()); + } + query_blocked_prof_timer.finish_with_query_invocation_id(index.into()); + + (v, Some(index)) } - }; + } +} +fn execute_job( + tcx: CTX, + key: K, + mut dep_node_opt: Option>, + query: &QueryVtable, + job_id: QueryJobId, + compute: fn(CTX::DepContext, K) -> V, +) -> (V, DepNodeIndex) +where + K: Clone + DepNodeParams, + V: Debug, + CTX: QueryContext, +{ let dep_graph = tcx.dep_context().dep_graph(); // Fast path for when incr. comp. is off. if !dep_graph.is_fully_enabled() { let prof_timer = tcx.dep_context().profiler().query_provider(); - let result = tcx.start_query(job.id, None, || compute(*tcx.dep_context(), key)); + let result = tcx.start_query(job_id, None, || compute(*tcx.dep_context(), key)); let dep_node_index = dep_graph.next_virtual_depnode_index(); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - return job.complete(result, dep_node_index); + return (result, dep_node_index); } - if query.anon { - let prof_timer = tcx.dep_context().profiler().query_provider(); + if !query.anon && !query.eval_always { + // `to_dep_node` is expensive for some `DepKind`s. + let dep_node = + dep_node_opt.get_or_insert_with(|| query.to_dep_node(*tcx.dep_context(), &key)); - let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { - tcx.start_query(job.id, diagnostics, || { - dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || { - compute(*tcx.dep_context(), key) - }) - }) - }); + // The diagnostics for this query will be promoted to the current session during + // `try_mark_green()`, so we can ignore them here. + if let Some(ret) = tcx.start_query(job_id, None, || { + try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query, compute) + }) { + return ret; + } + } - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); + let prof_timer = tcx.dep_context().profiler().query_provider(); + let diagnostics = Lock::new(ThinVec::new()); - dep_graph.read_index(dep_node_index); + let (result, dep_node_index) = tcx.start_query(job_id, Some(&diagnostics), || { + if query.anon { + return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || { + compute(*tcx.dep_context(), key) + }); + } - let side_effects = QuerySideEffects { diagnostics }; + // `to_dep_node` is expensive for some `DepKind`s. + let dep_node = dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key)); - if unlikely!(!side_effects.is_empty()) { - tcx.store_side_effects_for_anon_node(dep_node_index, side_effects); - } + dep_graph.with_task(dep_node, *tcx.dep_context(), key, compute, query.hash_result) + }); - return job.complete(result, dep_node_index); - } + prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - let dep_node = query.to_dep_node(*tcx.dep_context(), &key); + let diagnostics = diagnostics.into_inner(); + let side_effects = QuerySideEffects { diagnostics }; - if !query.eval_always { - // The diagnostics for this query will be - // promoted to the current session during - // `try_mark_green()`, so we can ignore them here. - let loaded = tcx.start_query(job.id, None, || { - let marked = dep_graph.try_mark_green_and_read(tcx, &dep_node); - marked.map(|(prev_dep_node_index, dep_node_index)| { - ( - load_from_disk_and_cache_in_memory( - tcx, - key.clone(), - prev_dep_node_index, - dep_node_index, - &dep_node, - query, - compute, - ), - dep_node_index, - ) - }) - }); - if let Some((result, dep_node_index)) = loaded { - return job.complete(result, dep_node_index); + if unlikely!(!side_effects.is_empty()) { + if query.anon { + tcx.store_side_effects_for_anon_node(dep_node_index, side_effects); + } else { + tcx.store_side_effects(dep_node_index, side_effects); } } - let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query, compute); - dep_graph.read_index(dep_node_index); - result + (result, dep_node_index) } -fn load_from_disk_and_cache_in_memory( +fn try_load_from_disk_and_cache_in_memory( tcx: CTX, - key: K, - prev_dep_node_index: SerializedDepNodeIndex, - dep_node_index: DepNodeIndex, + key: &K, dep_node: &DepNode, query: &QueryVtable, compute: fn(CTX::DepContext, K) -> V, -) -> V +) -> Option<(V, DepNodeIndex)> where + K: Clone, CTX: QueryContext, + V: Debug, { // Note this function can be called concurrently from the same query // We must ensure that this is handled correctly. - debug_assert!(tcx.dep_context().dep_graph().is_green(dep_node)); + let dep_graph = tcx.dep_context().dep_graph(); + let (prev_dep_node_index, dep_node_index) = dep_graph.try_mark_green(tcx, &dep_node)?; + + debug_assert!(dep_graph.is_green(dep_node)); // First we try to load the result from the on-disk cache. - let result = if query.cache_on_disk(tcx, &key, None) { + // Some things are never cached on disk. + if query.cache_on_disk(tcx, key, None) { let prof_timer = tcx.dep_context().profiler().incr_cache_loading(); let result = query.try_load_from_disk(tcx, prev_dep_node_index); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); @@ -548,47 +523,43 @@ // We always expect to find a cached result for things that // can be forced from `DepNode`. debug_assert!( - !dep_node.kind.can_reconstruct_query_key() || result.is_some(), + !dep_node.kind.fingerprint_style().reconstructible() || result.is_some(), "missing on-disk cache entry for {:?}", dep_node ); - result - } else { - // Some things are never cached on disk. - None - }; - if let Some(result) = result { - // If `-Zincremental-verify-ich` is specified, re-hash results from - // the cache and make sure that they have the expected fingerprint. - if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) { - incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query); + if let Some(result) = result { + // If `-Zincremental-verify-ich` is specified, re-hash results from + // the cache and make sure that they have the expected fingerprint. + if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) { + incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query); + } + + return Some((result, dep_node_index)); } + } - result - } else { - // We could not load a result from the on-disk cache, so - // recompute. - let prof_timer = tcx.dep_context().profiler().query_provider(); + // We could not load a result from the on-disk cache, so + // recompute. + let prof_timer = tcx.dep_context().profiler().query_provider(); - // The dep-graph for this computation is already in-place. - let result = tcx.dep_context().dep_graph().with_ignore(|| compute(*tcx.dep_context(), key)); + // The dep-graph for this computation is already in-place. + let result = dep_graph.with_ignore(|| compute(*tcx.dep_context(), key.clone())); - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); + prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - // Verify that re-running the query produced a result with the expected hash - // This catches bugs in query implementations, turning them into ICEs. - // For example, a query might sort its result by `DefId` - since `DefId`s are - // not stable across compilation sessions, the result could get up getting sorted - // in a different order when the query is re-run, even though all of the inputs - // (e.g. `DefPathHash` values) were green. - // - // See issue #82920 for an example of a miscompilation that would get turned into - // an ICE by this check - incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query); + // Verify that re-running the query produced a result with the expected hash + // This catches bugs in query implementations, turning them into ICEs. + // For example, a query might sort its result by `DefId` - since `DefId`s are + // not stable across compilation sessions, the result could get up getting sorted + // in a different order when the query is re-run, even though all of the inputs + // (e.g. `DefPathHash` values) were green. + // + // See issue #82920 for an example of a miscompilation that would get turned into + // an ICE by this check + incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query); - result - } + Some((result, dep_node_index)) } fn incremental_verify_ich( @@ -648,88 +619,6 @@ } } -fn force_query_with_job( - tcx: CTX, - key: C::Key, - job: JobOwner<'_, CTX::DepKind, C>, - dep_node: DepNode, - query: &QueryVtable, - compute: fn(CTX::DepContext, C::Key) -> C::Value, -) -> (C::Stored, DepNodeIndex) -where - C: QueryCache, - CTX: QueryContext, -{ - // If the following assertion triggers, it can have two reasons: - // 1. Something is wrong with DepNode creation, either here or - // in `DepGraph::try_mark_green()`. - // 2. Two distinct query keys get mapped to the same `DepNode` - // (see for example #48923). - assert!( - !tcx.dep_context().dep_graph().dep_node_exists(&dep_node), - "forcing query with already existing `DepNode`\n\ - - query-key: {:?}\n\ - - dep-node: {:?}", - key, - dep_node - ); - - let prof_timer = tcx.dep_context().profiler().query_provider(); - - let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { - tcx.start_query(job.id, diagnostics, || { - if query.eval_always { - tcx.dep_context().dep_graph().with_eval_always_task( - dep_node, - *tcx.dep_context(), - key, - compute, - query.hash_result, - ) - } else { - tcx.dep_context().dep_graph().with_task( - dep_node, - *tcx.dep_context(), - key, - compute, - query.hash_result, - ) - } - }) - }); - - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - let side_effects = QuerySideEffects { diagnostics }; - - if unlikely!(!side_effects.is_empty()) && dep_node.kind != DepKind::NULL { - tcx.store_side_effects(dep_node_index, side_effects); - } - - let result = job.complete(result, dep_node_index); - - (result, dep_node_index) -} - -#[inline(never)] -fn get_query_impl( - tcx: CTX, - state: &QueryState, - cache: &QueryCacheStore, - span: Span, - key: C::Key, - lookup: QueryLookup, - query: &QueryVtable, - compute: fn(CTX::DepContext, C::Key) -> C::Value, -) -> C::Stored -where - CTX: QueryContext, - C: QueryCache, - C::Key: DepNodeParams, -{ - try_execute_query(tcx, state, cache, span, key, lookup, query, compute) -} - /// Ensure that either this query has all green inputs or been executed. /// Executing `query::ensure(D)` is considered a read of the dep-node `D`. /// Returns true if the query should still run. @@ -739,13 +628,17 @@ /// /// Note: The optimization is only available during incr. comp. #[inline(never)] -fn ensure_must_run(tcx: CTX, key: &K, query: &QueryVtable) -> bool +fn ensure_must_run( + tcx: CTX, + key: &K, + query: &QueryVtable, +) -> (bool, Option>) where K: crate::dep_graph::DepNodeParams, CTX: QueryContext, { if query.eval_always { - return true; + return (true, None); } // Ensuring an anonymous query makes no sense @@ -753,19 +646,21 @@ let dep_node = query.to_dep_node(*tcx.dep_context(), key); - match tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node) { + let dep_graph = tcx.dep_context().dep_graph(); + match dep_graph.try_mark_green(tcx, &dep_node) { None => { - // A None return from `try_mark_green_and_read` means that this is either + // A None return from `try_mark_green` means that this is either // a new dep node or that the dep node has already been marked red. // Either way, we can't call `dep_graph.read()` as we don't have the // DepNodeIndex. We must invoke the query itself. The performance cost // this introduces should be negligible as we'll immediately hit the // in-memory cache, or another query down the line will. - true + (true, Some(dep_node)) } Some((_, dep_node_index)) => { + dep_graph.read_index(dep_node_index); tcx.dep_context().profiler().query_cache_hit(dep_node_index.into()); - false + (false, None) } } } @@ -793,10 +688,6 @@ if unlikely!(tcx.dep_context().profiler().enabled()) { tcx.dep_context().profiler().query_cache_hit(index.into()); } - #[cfg(debug_assertions)] - { - cache.cache_hits.fetch_add(1, Ordering::Relaxed); - } }); let lookup = match cached { @@ -804,23 +695,8 @@ Err(lookup) => lookup, }; - let job = match JobOwner::<'_, CTX::DepKind, C>::try_start( - tcx, - state, - cache, - DUMMY_SP, - key.clone(), - lookup, - query, - ) { - TryGetJob::NotYetStarted(job) => job, - TryGetJob::Cycle(_) => return true, - #[cfg(parallel_compiler)] - TryGetJob::JobCompleted(_) => return true, - }; - - force_query_with_job(tcx, key, job, dep_node, query, compute); - + let _ = + try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), query, compute); true } @@ -842,25 +718,33 @@ CTX: QueryContext, { let query = &Q::VTABLE; - if let QueryMode::Ensure = mode { - if !ensure_must_run(tcx, &key, query) { + let dep_node = if let QueryMode::Ensure = mode { + let (must_run, dep_node) = ensure_must_run(tcx, &key, query); + if !must_run { return None; } - } + dep_node + } else { + None + }; debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span); let compute = Q::compute_fn(tcx, &key); - let value = get_query_impl( + let (result, dep_node_index) = try_execute_query( tcx, Q::query_state(tcx), Q::query_cache(tcx), span, key, lookup, + dep_node, query, compute, ); - Some(value) + if let Some(dep_node_index) = dep_node_index { + tcx.dep_context().dep_graph().read_index(dep_node_index) + } + Some(result) } pub fn force_query(tcx: CTX, dep_node: &DepNode) -> bool @@ -873,7 +757,7 @@ return false; } - if !>::can_reconstruct_query_key() { + if !>::fingerprint_style().reconstructible() { return false; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_resolve" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] test = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/build_reduced_graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/build_reduced_graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/build_reduced_graph.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/build_reduced_graph.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,11 +9,9 @@ use crate::imports::{Import, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; -use crate::{CrateLint, Determinacy, PathResult, ResolutionError, VisResolutionError}; -use crate::{ - ExternPreludeEntry, ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, -}; -use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; +use crate::{CrateLint, Determinacy, ExternPreludeEntry, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError}; +use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; @@ -29,8 +27,8 @@ use rustc_metadata::creader::LoadedMacro; use rustc_middle::bug; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::CrateStore; use rustc_middle::ty; +use rustc_session::cstore::CrateStore; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -95,100 +93,96 @@ } /// Walks up the tree of definitions starting at `def_id`, - /// stopping at the first `DefKind::Mod` encountered - fn nearest_parent_mod(&mut self, def_id: DefId) -> Module<'a> { - let def_key = self.cstore().def_key(def_id); - - let mut parent_id = DefId { - krate: def_id.krate, - index: def_key.parent.expect("failed to get parent for module"), - }; - // The immediate parent may not be a module - // (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`) - // Walk up the tree until we hit a module or the crate root. - while parent_id.index != CRATE_DEF_INDEX - && self.cstore().def_kind(parent_id) != DefKind::Mod - { - let parent_def_key = self.cstore().def_key(parent_id); - parent_id.index = parent_def_key.parent.expect("failed to get parent for module"); + /// stopping at the first encountered module. + /// Parent block modules for arbitrary def-ids are not recorded for the local crate, + /// and are not preserved in metadata for foreign crates, so block modules are never + /// returned by this function. + /// + /// For the local crate ignoring block modules may be incorrect, so use this method with care. + /// + /// For foreign crates block modules can be ignored without introducing observable differences, + /// moreover they has to be ignored right now because they are not kept in metadata. + /// Foreign parent modules are used for resolving names used by foreign macros with def-site + /// hygiene, therefore block module ignorability relies on macros with def-site hygiene and + /// block module parents being unreachable from other crates. + /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`, + /// but they cannot use def-site hygiene, so the assumption holds + /// (). + fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> { + loop { + match self.get_module(def_id) { + Some(module) => return module, + None => { + def_id.index = + self.def_key(def_id).parent.expect("non-root `DefId` without parent") + } + } } - self.get_module(parent_id) } - pub fn get_module(&mut self, def_id: DefId) -> Module<'a> { - // If this is a local module, it will be in `module_map`, no need to recalculate it. - if let Some(def_id) = def_id.as_local() { - return self.module_map[&def_id]; - } + pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> { + self.get_module(def_id).expect("argument `DefId` is not a module") + } - // Cache module resolution - if let Some(&module) = self.extern_module_map.get(&def_id) { - return module; - } + /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum, + /// or trait), then this function returns that module's resolver representation, otherwise it + /// returns `None`. + crate fn get_module(&mut self, def_id: DefId) -> Option> { + if let module @ Some(..) = self.module_map.get(&def_id) { + return module.copied(); + } + + if !def_id.is_local() { + let def_kind = self.cstore().def_kind(def_id); + match def_kind { + DefKind::Mod | DefKind::Enum | DefKind::Trait => { + let def_key = self.cstore().def_key(def_id); + let parent = def_key.parent.map(|index| { + self.get_nearest_non_block_module(DefId { index, krate: def_id.krate }) + }); + let name = if def_id.index == CRATE_DEF_INDEX { + self.cstore().crate_name(def_id.krate) + } else { + def_key.disambiguated_data.data.get_opt_name().expect("module without name") + }; + let expn_id = if def_kind == DefKind::Mod { + self.cstore().module_expansion_untracked(def_id, &self.session) + } else { + // FIXME: Parent expansions for enums and traits are not kept in metadata. + ExpnId::root() + }; - let (name, parent) = if def_id.index == CRATE_DEF_INDEX { - // This is the crate root - (self.cstore().crate_name(def_id.krate), None) + Some(self.new_module( + parent, + ModuleKind::Def(def_kind, def_id, name), + expn_id, + self.cstore().get_span_untracked(def_id, &self.session), + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.map_or(false, |module| module.no_implicit_prelude), + )) + } + _ => None, + } } else { - let def_key = self.cstore().def_key(def_id); - let name = def_key - .disambiguated_data - .data - .get_opt_name() - .expect("given a DefId that wasn't a module"); - - let parent = Some(self.nearest_parent_mod(def_id)); - (name, parent) - }; + None + } + } - // Allocate and return a new module with the information we found - let kind = ModuleKind::Def(DefKind::Mod, def_id, name); - let module = self.arenas.alloc_module(ModuleData::new( - parent, - kind, - def_id, - self.cstore().module_expansion_untracked(def_id, &self.session), - self.cstore().get_span_untracked(def_id, &self.session), - )); - self.extern_module_map.insert(def_id, module); - module - } - - crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { - let def_id = match expn_id.expn_data().macro_def_id { - Some(def_id) => def_id, - None => { - return expn_id - .as_local() - .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) - .unwrap_or(&self.graph_root); - } - }; - self.macro_def_scope_from_def_id(def_id) + crate fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { + match expn_id.expn_data().macro_def_id { + Some(def_id) => self.macro_def_scope(def_id), + None => expn_id + .as_local() + .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) + .unwrap_or(&self.graph_root), + } } - crate fn macro_def_scope_from_def_id(&mut self, def_id: DefId) -> Module<'a> { + crate fn macro_def_scope(&mut self, def_id: DefId) -> Module<'a> { if let Some(id) = def_id.as_local() { self.local_macro_def_scopes[&id] } else { - // This is not entirely correct - a `macro_rules!` macro may occur - // inside a 'block' module: - // - // ```rust - // const _: () = { - // #[macro_export] - // macro_rules! my_macro { - // () => {}; - // } - // ` - // We don't record this information for external crates, so - // the module we compute here will be the closest 'mod' item - // (not necesssarily the actual parent of the `macro_rules!` - // macro). `macro_rules!` macros can't use def-site hygiene, - // so this hopefully won't be a problem. - // - // See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508 - self.nearest_parent_mod(def_id) + self.get_nearest_non_block_module(def_id) } } @@ -226,9 +220,7 @@ } crate fn build_reduced_graph_external(&mut self, module: Module<'a>) { - let def_id = module.def_id().expect("unpopulated module without a def-id"); - for child in self.cstore().item_children_untracked(def_id, self.session) { - let child = child.map_id(|_| panic!("unexpected id")); + for child in self.cstore().item_children_untracked(module.def_id(), self.session) { let parent_scope = ParentScope::module(module, self); BuildReducedGraphVisitor { r: self, parent_scope } .build_reduced_graph_for_external_crate_res(child); @@ -275,7 +267,7 @@ self.r.visibilities[&def_id.expect_local()] } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod), + _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()), }) } ast::VisibilityKind::Restricted { ref path, id, .. } => { @@ -718,7 +710,7 @@ local_def_id, ); self.r.extern_crate_map.insert(local_def_id, crate_id); - self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) + self.r.expect_module(crate_id.as_def_id()) }; let used = self.process_macro_use_imports(item, module); @@ -769,21 +761,15 @@ } ItemKind::Mod(..) => { - let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name); - let module = self.r.arenas.alloc_module(ModuleData { - no_implicit_prelude: parent.no_implicit_prelude || { - self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude) - }, - ..ModuleData::new( - Some(parent), - module_kind, - def_id, - expansion.to_expn_id(), - item.span, - ) - }); + let module = self.r.new_module( + Some(parent), + ModuleKind::Def(DefKind::Mod, def_id, ident.name), + expansion.to_expn_id(), + item.span, + parent.no_implicit_prelude + || self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude), + ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.r.module_map.insert(local_def_id, module); // Descend into the module. self.parent_scope.module = module; @@ -814,13 +800,12 @@ } ItemKind::Enum(_, _) => { - let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name); let module = self.r.new_module( - parent, - module_kind, - parent.nearest_parent_mod, + Some(parent), + ModuleKind::Def(DefKind::Enum, def_id, ident.name), expansion.to_expn_id(), item.span, + parent.no_implicit_prelude, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.parent_scope.module = module; @@ -889,13 +874,12 @@ ItemKind::Trait(..) => { // Add all the items within to a new module. - let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); let module = self.r.new_module( - parent, - module_kind, - parent.nearest_parent_mod, + Some(parent), + ModuleKind::Def(DefKind::Trait, def_id, ident.name), expansion.to_expn_id(), item.span, + parent.no_implicit_prelude, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.parent_scope.module = module; @@ -934,11 +918,11 @@ let expansion = self.parent_scope.expansion; if self.block_needs_anonymous_module(block) { let module = self.r.new_module( - parent, + Some(parent), ModuleKind::Block(block.id), - parent.nearest_parent_mod, expansion.to_expn_id(), block.span, + parent.no_implicit_prelude, ); self.r.block_map.insert(block.id, module); self.parent_scope.module = module; // Descend into the block. @@ -946,20 +930,15 @@ } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) { + fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) { let parent = self.parent_scope.module; let Export { ident, res, vis, span } = child; + let res = res.expect_non_local(); let expansion = self.parent_scope.expansion; // Record primary definitions. match res { - Res::Def(kind @ (DefKind::Mod | DefKind::Enum | DefKind::Trait), def_id) => { - let module = self.r.new_module( - parent, - ModuleKind::Def(kind, def_id, ident.name), - def_id, - expansion.to_expn_id(), - span, - ); + Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => { + let module = self.r.expect_module(def_id); self.r.define(parent, ident, TypeNS, (module, vis, span, expansion)); } Res::Def( diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/def_collector.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/def_collector.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/def_collector.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/def_collector.rs 2021-11-29 19:27:11.000000000 +0000 @@ -32,7 +32,13 @@ fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId { let parent_def = self.parent_def; debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); - self.resolver.create_def(parent_def, node_id, data, self.expansion.to_expn_id(), span) + self.resolver.create_def( + parent_def, + node_id, + data, + self.expansion.to_expn_id(), + span.with_parent(None), + ) } fn with_parent(&mut self, parent_def: LocalDefId, f: F) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/diagnostics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/diagnostics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/diagnostics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/diagnostics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -198,7 +198,7 @@ err.span_label(first_use_span, format!("first use of `{}`", name)); err } - ResolutionError::MethodNotMemberOfTrait(method, trait_) => { + ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => { let mut err = struct_span_err!( self.session, span, @@ -208,9 +208,17 @@ trait_ ); err.span_label(span, format!("not a member of trait `{}`", trait_)); + if let Some(candidate) = candidate { + err.span_suggestion( + method.span, + "there is an associated function with a similar name", + candidate.to_ident_string(), + Applicability::MaybeIncorrect, + ); + } err } - ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { + ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => { let mut err = struct_span_err!( self.session, span, @@ -220,9 +228,17 @@ trait_ ); err.span_label(span, format!("not a member of trait `{}`", trait_)); + if let Some(candidate) = candidate { + err.span_suggestion( + type_.span, + "there is an associated type with a similar name", + candidate.to_ident_string(), + Applicability::MaybeIncorrect, + ); + } err } - ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { + ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => { let mut err = struct_span_err!( self.session, span, @@ -232,6 +248,14 @@ trait_ ); err.span_label(span, format!("not a member of trait `{}`", trait_)); + if let Some(candidate) = candidate { + err.span_suggestion( + const_.span, + "there is an associated constant with a similar name", + candidate.to_ident_string(), + Applicability::MaybeIncorrect, + ); + } err } ResolutionError::VariableNotBoundInPattern(binding_error) => { @@ -777,7 +801,7 @@ None => worklist_via_import.pop(), Some(x) => Some(x), } { - let in_module_is_extern = !in_module.def_id().unwrap().is_local(); + let in_module_is_extern = !in_module.def_id().is_local(); // We have to visit module children in deterministic order to avoid // instabilities in reported imports (#43552). in_module.for_each_child(self, |this, ident, ns, name_binding| { @@ -860,7 +884,7 @@ if !is_extern_crate_that_also_appears_in_prelude { // add the module to the lookup - if seen_modules.insert(module.def_id().unwrap()) { + if seen_modules.insert(module.def_id()) { if via_import { &mut worklist_via_import } else { &mut worklist } .push((module, path_segments, child_accessible)); } @@ -915,8 +939,7 @@ continue; } if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) { - let crate_root = - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); + let crate_root = self.expect_module(crate_id.as_def_id()); suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, namespace, @@ -950,7 +973,15 @@ let import_suggestions = self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); - show_candidates(err, None, &import_suggestions, false, true); + show_candidates( + &self.definitions, + self.session, + err, + None, + &import_suggestions, + false, + true, + ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident); @@ -1246,6 +1277,34 @@ err.emit(); } + + crate fn find_similarly_named_module_or_crate( + &mut self, + ident: Symbol, + current_module: &Module<'a>, + ) -> Option { + let mut candidates = self + .extern_prelude + .iter() + .map(|(ident, _)| ident.name) + .chain( + self.module_map + .iter() + .filter(|(_, module)| { + current_module.is_ancestor_of(module) && !ptr::eq(current_module, *module) + }) + .map(|(_, module)| module.kind.name()) + .flatten(), + ) + .filter(|c| !c.to_string().is_empty()) + .collect::>(); + candidates.sort(); + candidates.dedup(); + match find_best_match_for_name(&candidates, ident, None) { + Some(sugg) if sugg == ident => None, + sugg => sugg, + } + } } impl<'a, 'b> ImportResolver<'a, 'b> { @@ -1690,6 +1749,8 @@ /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way crate fn show_candidates( + definitions: &rustc_hir::definitions::Definitions, + session: &Session, err: &mut DiagnosticBuilder<'_>, // This is `None` if all placement locations are inside expansions use_placement_span: Option, @@ -1701,40 +1762,111 @@ return; } + let mut accessible_path_strings: Vec<(String, &str, Option)> = Vec::new(); + let mut inaccessible_path_strings: Vec<(String, &str, Option)> = Vec::new(); + + candidates.iter().for_each(|c| { + (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings }) + .push((path_names_to_string(&c.path), c.descr, c.did)) + }); + // we want consistent results across executions, but candidates are produced // by iterating through a hash map, so make sure they are ordered: - let mut path_strings: Vec<_> = - candidates.iter().map(|c| path_names_to_string(&c.path)).collect(); + for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] { + path_strings.sort_by(|a, b| a.0.cmp(&b.0)); + let core_path_strings = + path_strings.drain_filter(|p| p.0.starts_with("core::")).collect::>(); + path_strings.extend(core_path_strings); + path_strings.dedup_by(|a, b| a.0 == b.0); + } + + if !accessible_path_strings.is_empty() { + let (determiner, kind) = if accessible_path_strings.len() == 1 { + ("this", accessible_path_strings[0].1) + } else { + ("one of these", "items") + }; - path_strings.sort(); - path_strings.dedup(); + let instead = if instead { " instead" } else { "" }; + let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); - let (determiner, kind) = if candidates.len() == 1 { - ("this", candidates[0].descr) - } else { - ("one of these", "items") - }; + if let Some(span) = use_placement_span { + for candidate in &mut accessible_path_strings { + // produce an additional newline to separate the new use statement + // from the directly following item. + let additional_newline = if found_use { "" } else { "\n" }; + candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline); + } - let instead = if instead { " instead" } else { "" }; - let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); + err.span_suggestions( + span, + &msg, + accessible_path_strings.into_iter().map(|a| a.0), + Applicability::Unspecified, + ); + } else { + msg.push(':'); - if let Some(span) = use_placement_span { - for candidate in &mut path_strings { - // produce an additional newline to separate the new use statement - // from the directly following item. - let additional_newline = if found_use { "" } else { "\n" }; - *candidate = format!("use {};\n{}", candidate, additional_newline); - } + for candidate in accessible_path_strings { + msg.push('\n'); + msg.push_str(&candidate.0); + } - err.span_suggestions(span, &msg, path_strings.into_iter(), Applicability::Unspecified); + err.note(&msg); + } } else { - msg.push(':'); + assert!(!inaccessible_path_strings.is_empty()); - for candidate in path_strings { - msg.push('\n'); - msg.push_str(&candidate); - } + if inaccessible_path_strings.len() == 1 { + let (name, descr, def_id) = &inaccessible_path_strings[0]; + let msg = format!("{} `{}` exists but is inaccessible", descr, name); + + if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { + let span = definitions.def_span(local_def_id); + let span = session.source_map().guess_head_span(span); + let mut multi_span = MultiSpan::from_span(span); + multi_span.push_span_label(span, "not accessible".to_string()); + err.span_note(multi_span, &msg); + } else { + err.note(&msg); + } + } else { + let (_, descr_first, _) = &inaccessible_path_strings[0]; + let descr = if inaccessible_path_strings + .iter() + .skip(1) + .all(|(_, descr, _)| descr == descr_first) + { + descr_first.to_string() + } else { + "item".to_string() + }; + + let mut msg = format!("these {}s exist but are inaccessible", descr); + let mut has_colon = false; + + let mut spans = Vec::new(); + for (name, _, def_id) in &inaccessible_path_strings { + if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { + let span = definitions.def_span(local_def_id); + let span = session.source_map().guess_head_span(span); + spans.push((name, span)); + } else { + if !has_colon { + msg.push(':'); + has_colon = true; + } + msg.push('\n'); + msg.push_str(name); + } + } - err.note(&msg); + let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect()); + for (name, span) in spans { + multi_span.push_span_label(span, format!("`{}`: not accessible", name)); + } + + err.span_note(multi_span, &msg); + } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/imports.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/imports.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/imports.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/imports.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,9 +9,7 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet, Weak}; use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding}; -use rustc_ast::unwrap_or; use rustc_ast::NodeId; -use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::ptr_key::PtrKey; use rustc_errors::{pluralize, struct_span_err, Applicability}; @@ -350,10 +348,10 @@ if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) { continue; } - let module = unwrap_or!( - single_import.imported_module.get(), - return Err((Undetermined, Weak::No)) - ); + let module = match single_import.imported_module.get() { + Some(x) => x, + None => return Err((Undetermined, Weak::No)), + }; let ident = match single_import.kind { ImportKind::Single { source, .. } => source, _ => unreachable!(), @@ -428,7 +426,7 @@ match ident.span.glob_adjust(module.expansion, glob_import.span) { Some(Some(def)) => { tmp_parent_scope = - ParentScope { module: self.macro_def_scope(def), ..*parent_scope }; + ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; adjusted_parent_scope = &tmp_parent_scope; } Some(None) => {} @@ -586,7 +584,7 @@ for import in module.glob_importers.borrow_mut().iter() { let mut ident = key.ident; let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { - Some(Some(def)) => self.macro_def_scope(def), + Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, }; @@ -990,7 +988,7 @@ } if let ModuleOrUniformRoot::Module(module) = module { - if module.def_id() == import.parent_scope.module.def_id() { + if ptr::eq(module, import.parent_scope.module) { // Importing a module into itself is not allowed. return Some(UnresolvedImportError { span: import.span, @@ -1340,9 +1338,9 @@ }; if module.is_trait() { - self.r.session.span_err(import.span, "items in traits are not importable."); + self.r.session.span_err(import.span, "items in traits are not importable"); return; - } else if module.def_id() == import.parent_scope.module.def_id() { + } else if ptr::eq(module, import.parent_scope.module) { return; } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind { self.r.prelude = Some(module); @@ -1365,7 +1363,7 @@ .collect::>(); for (mut key, binding) in bindings { let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) { - Some(Some(def)) => self.r.macro_def_scope(def), + Some(Some(def)) => self.r.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, }; @@ -1387,13 +1385,13 @@ let mut reexports = Vec::new(); - module.for_each_child(self.r, |this, ident, _, binding| { + module.for_each_child(self.r, |_, ident, _, binding| { // Filter away ambiguous imports and anything that has def-site hygiene. // FIXME: Implement actual cross-crate hygiene. let is_good_import = binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion(); if is_good_import || binding.is_macro_def() { - let res = binding.res().map_id(|id| this.local_def_id(id)); + let res = binding.res().expect_non_local(); if res != def::Res::Err { reexports.push(Export { ident, res, span: binding.span, vis: binding.vis }); } @@ -1401,7 +1399,7 @@ }); if !reexports.is_empty() { - if let Some(def_id) = module.def_id() { + if let Some(def_id) = module.opt_def_id() { // Call to `expect_local` should be fine because current // code is only called for local modules. self.r.export_map.insert(def_id.expect_local(), reexports); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/late/diagnostics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/late/diagnostics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/late/diagnostics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/late/diagnostics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,12 +7,12 @@ use rustc_ast::visit::FnKind; use rustc_ast::{ - self as ast, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, NodeId, Path, Ty, - TyKind, + self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, + NodeId, Path, Ty, TyKind, }; use rustc_ast_pretty::pprust::path_segment_to_string; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, SuggestionStyle}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; @@ -768,6 +768,7 @@ args[1].span.lo(), args.last().unwrap().span.hi(), call_span.ctxt(), + None, )) } else { None @@ -1025,9 +1026,15 @@ self.suggest_using_enum_variant(err, source, def_id, span); } - (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { + (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => { let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() { + if let PathSource::Expr(Some(parent)) = source { + if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind { + bad_struct_syntax_suggestion(def_id); + return true; + } + } struct_ctor } else { bad_struct_syntax_suggestion(def_id); @@ -1143,6 +1150,40 @@ true } + /// Given the target `ident` and `kind`, search for the similarly named associated item + /// in `self.current_trait_ref`. + crate fn find_similarly_named_assoc_item( + &mut self, + ident: Symbol, + kind: &AssocItemKind, + ) -> Option { + let module = if let Some((module, _)) = self.current_trait_ref { + module + } else { + return None; + }; + if ident == kw::Underscore { + // We do nothing for `_`. + return None; + } + + let resolutions = self.r.resolutions(module); + let targets = resolutions + .borrow() + .iter() + .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res()))) + .filter(|(_, res)| match (kind, res) { + (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true, + (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true, + (AssocItemKind::TyAlias(..), Res::Def(DefKind::AssocTy, _)) => true, + _ => false, + }) + .map(|(key, _)| key.ident.name) + .collect::>(); + + find_best_match_for_name(&targets, ident, None) + } + fn lookup_assoc_candidate( &mut self, ident: Ident, @@ -1450,7 +1491,7 @@ // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id().unwrap(); + let module_def_id = module.def_id(); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, tokens: None }; @@ -1959,11 +2000,10 @@ introduce_suggestion.push((*span, formatter(<_name))); } } - err.multipart_suggestion_with_style( + err.multipart_suggestion_verbose( &msg, introduce_suggestion, Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); } @@ -1975,14 +2015,13 @@ }) .map(|(formatter, span)| (*span, formatter(name))) .collect(); - err.multipart_suggestion_with_style( + err.multipart_suggestion_verbose( &format!( "consider using the `{}` lifetime", lifetime_names.iter().next().unwrap() ), spans_suggs, Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); }; let suggest_new = |err: &mut DiagnosticBuilder<'_>, suggs: Vec>| { @@ -2073,11 +2112,10 @@ }; spans_suggs.push((span, sugg.to_string())); } - err.multipart_suggestion_with_style( + err.multipart_suggestion_verbose( "consider using the `'static` lifetime", spans_suggs, Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); continue; } @@ -2162,11 +2200,10 @@ .unwrap_or((span, sugg)); introduce_suggestion.push((span, sugg.to_string())); } - err.multipart_suggestion_with_style( + err.multipart_suggestion_verbose( &msg, introduce_suggestion, Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); if should_break { break; @@ -2242,11 +2279,10 @@ if spans_suggs.len() > 0 { // This happens when we have `Foo` where we point at the space before `T`, // but this can be confusing so we give a suggestion with placeholders. - err.multipart_suggestion_with_style( + err.multipart_suggestion_verbose( "consider using one of the available lifetimes here", spans_suggs, Applicability::HasPlaceholders, - SuggestionStyle::ShowAlways, ); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/late/lifetimes.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/late/lifetimes.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/late/lifetimes.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/late/lifetimes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -522,8 +522,7 @@ _ => {} } let item = { - let hir = tcx.hir(); - let mut parent_iter = hir.parent_iter(hir_id); + let mut parent_iter = tcx.hir().parent_iter(hir_id); loop { let node = parent_iter.next().map(|n| n.1); match node { @@ -1652,7 +1651,11 @@ } fn expression_label(ex: &hir::Expr<'_>) -> Option { - if let hir::ExprKind::Loop(_, Some(label), ..) = ex.kind { Some(label.ident) } else { None } + match ex.kind { + hir::ExprKind::Loop(_, Some(label), ..) => Some(label.ident), + hir::ExprKind::Block(_, Some(label)) => Some(label.ident), + _ => None, + } } fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) { @@ -2024,7 +2027,7 @@ // ensure that we issue lints in a repeatable order def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); - for def_id in def_ids { + 'lifetimes: for def_id in def_ids { debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id); let lifetimeuseset = self.lifetime_uses.remove(&def_id); @@ -2067,6 +2070,27 @@ { continue; } + + // opaque types generated when desugaring an async function can have a single + // use lifetime even if it is explicitly denied (Issue #77175) + if let hir::Node::Item(hir::Item { + kind: hir::ItemKind::OpaqueTy(ref opaque), + .. + }) = self.tcx.hir().get(parent_hir_id) + { + if opaque.origin != hir::OpaqueTyOrigin::AsyncFn { + continue 'lifetimes; + } + // We want to do this only if the liftime identifier is already defined + // in the async function that generated this. Otherwise it could be + // an opaque type defined by the developer and we still want this + // lint to fail compilation + for p in opaque.generics.params { + if defined_by.contains_key(&p.name) { + continue 'lifetimes; + } + } + } } } @@ -2716,6 +2740,7 @@ for input in inputs { gather.visit_ty(input); } + trace!(?gather.anon_count); let late_bound_vars = self.map.late_bound_vars.entry(hir_id).or_default(); let named_late_bound_vars = late_bound_vars.len() as u32; late_bound_vars.extend( @@ -3004,6 +3029,7 @@ NestedVisitorMap::None } + #[instrument(skip(self), level = "trace")] fn visit_ty(&mut self, ty: &hir::Ty<'_>) { // If we enter a `BareFn`, then we enter a *new* binding scope if let hir::TyKind::BareFn(_) = ty.kind { @@ -3024,6 +3050,7 @@ intravisit::walk_generic_args(self, path_span, generic_args) } + #[instrument(skip(self), level = "trace")] fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { if lifetime_ref.is_elided() { self.anon_count += 1; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/late.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/late.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/late.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/late.rs 2021-11-29 19:27:11.000000000 +0000 @@ -799,9 +799,7 @@ } fn with_scope(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - let id = self.r.local_def_id(id); - let module = self.r.module_map.get(&id).cloned(); // clones a reference - if let Some(module) = module { + if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) { // Move down in the graph. let orig_module = replace(&mut self.parent_scope.module, module); self.with_rib(ValueNS, ModuleRibKind(module), |this| { @@ -1311,14 +1309,15 @@ use crate::ResolutionError::*; match &item.kind { AssocItemKind::Const(_default, _ty, _expr) => { - debug!("resolve_implementation AssocItemKind::Const",); + debug!("resolve_implementation AssocItemKind::Const"); // If this is a trait impl, ensure the const // exists in trait this.check_trait_item( item.ident, + &item.kind, ValueNS, item.span, - |n, s| ConstNotMemberOfTrait(n, s), + |i, s, c| ConstNotMemberOfTrait(i, s, c), ); // We allow arbitrary const expressions inside of associated consts, @@ -1340,6 +1339,7 @@ ); } AssocItemKind::Fn(box FnKind(.., generics, _)) => { + debug!("resolve_implementation AssocItemKind::Fn"); // We also need a new scope for the impl item type parameters. this.with_generic_param_rib( generics, @@ -1349,9 +1349,10 @@ // exists in trait this.check_trait_item( item.ident, + &item.kind, ValueNS, item.span, - |n, s| MethodNotMemberOfTrait(n, s), + |i, s, c| MethodNotMemberOfTrait(i, s, c), ); visit::walk_assoc_item( @@ -1368,6 +1369,7 @@ _, _, )) => { + debug!("resolve_implementation AssocItemKind::TyAlias"); // We also need a new scope for the impl item type parameters. this.with_generic_param_rib( generics, @@ -1377,9 +1379,10 @@ // exists in trait this.check_trait_item( item.ident, + &item.kind, TypeNS, item.span, - |n, s| TypeNotMemberOfTrait(n, s), + |i, s, c| TypeNotMemberOfTrait(i, s, c), ); visit::walk_assoc_item( @@ -1403,9 +1406,15 @@ }); } - fn check_trait_item(&mut self, ident: Ident, ns: Namespace, span: Span, err: F) - where - F: FnOnce(Symbol, &str) -> ResolutionError<'_>, + fn check_trait_item( + &mut self, + ident: Ident, + kind: &AssocItemKind, + ns: Namespace, + span: Span, + err: F, + ) where + F: FnOnce(Ident, &str, Option) -> ResolutionError<'_>, { // If there is a TraitRef in scope for an impl, then the method must be in the // trait. @@ -1422,8 +1431,9 @@ ) .is_err() { + let candidate = self.find_similarly_named_assoc_item(ident.name, kind); let path = &self.current_trait_ref.as_ref().unwrap().1.path; - self.report_error(span, err(ident.name, &path_names_to_string(path))); + self.report_error(span, err(ident, &path_names_to_string(path), candidate)); } } } @@ -1872,7 +1882,7 @@ if this.should_report_errs() { let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); - let def_id = this.parent_scope.module.nearest_parent_mod; + let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); let suggestion = if res.is_none() { this.report_missing_type_error(path) } else { None }; @@ -1940,7 +1950,7 @@ drop(parent_err); - let def_id = this.parent_scope.module.nearest_parent_mod; + let def_id = this.parent_scope.module.nearest_parent_mod(); if this.should_report_errs() { this.r.use_injections.push(UseError { @@ -1999,9 +2009,8 @@ let item_span = path.iter().last().map_or(span, |segment| segment.ident.span); - let mut hm = self.r.session.confused_type_with_std_module.borrow_mut(); - hm.insert(item_span, span); - hm.insert(span, span); + self.r.confused_type_with_std_module.insert(item_span, span); + self.r.confused_type_with_std_module.insert(span, span); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,14 +10,19 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] +#![feature(drain_filter)] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] #![feature(iter_zip)] +#![feature(never_type)] #![feature(nll)] #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] +#[macro_use] +extern crate tracing; + pub use rustc_hir::def::{Namespace, PerNS}; use Determinacy::*; @@ -39,16 +44,17 @@ use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::TraitCandidate; use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; -use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; +use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; @@ -200,11 +206,11 @@ /// parameter list. NameAlreadyUsedInParameterList(Symbol, Span), /// Error E0407: method is not a member of trait. - MethodNotMemberOfTrait(Symbol, &'a str), + MethodNotMemberOfTrait(Ident, &'a str, Option), /// Error E0437: type is not a member of trait. - TypeNotMemberOfTrait(Symbol, &'a str), + TypeNotMemberOfTrait(Ident, &'a str, Option), /// Error E0438: const is not a member of trait. - ConstNotMemberOfTrait(Symbol, &'a str), + ConstNotMemberOfTrait(Ident, &'a str, Option), /// Error E0408: variable `{}` is not bound in all patterns. VariableNotBoundInPattern(&'a BindingError), /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm. @@ -407,7 +413,7 @@ fn same_def(lhs: Self, rhs: Self) -> bool { match (lhs, rhs) { (ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) => { - lhs.def_id() == rhs.def_id() + ptr::eq(lhs, rhs) } ( ModuleOrUniformRoot::CrateRootAndExternPrelude, @@ -504,10 +510,6 @@ /// What kind of module this is, because this may not be a `mod`. kind: ModuleKind, - /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module). - /// This may be the crate root. - nearest_parent_mod: DefId, - /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'a>, @@ -538,18 +540,21 @@ fn new( parent: Option>, kind: ModuleKind, - nearest_parent_mod: DefId, expansion: ExpnId, span: Span, + no_implicit_prelude: bool, ) -> Self { + let is_foreign = match kind { + ModuleKind::Def(_, def_id, _) => !def_id.is_local(), + ModuleKind::Block(_) => false, + }; ModuleData { parent, kind, - nearest_parent_mod, lazy_resolutions: Default::default(), - populate_on_access: Cell::new(!nearest_parent_mod.is_local()), + populate_on_access: Cell::new(is_foreign), unexpanded_invocations: Default::default(), - no_implicit_prelude: false, + no_implicit_prelude, glob_importers: RefCell::new(Vec::new()), globs: RefCell::new(Vec::new()), traits: RefCell::new(None), @@ -597,7 +602,11 @@ } } - fn def_id(&self) -> Option { + fn def_id(&self) -> DefId { + self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") + } + + fn opt_def_id(&self) -> Option { match self.kind { ModuleKind::Def(_, def_id, _) => Some(def_id), _ => None, @@ -622,6 +631,15 @@ } } + /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module). + /// This may be the crate root. + fn nearest_parent_mod(&self) -> DefId { + match self.kind { + ModuleKind::Def(DefKind::Mod, def_id, _) => def_id, + _ => self.parent.expect("non-root module without parent").nearest_parent_mod(), + } + } + fn is_ancestor_of(&self, mut other: &Self) -> bool { while !ptr::eq(self, other) { if let Some(parent) = other.parent { @@ -911,7 +929,7 @@ /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap, - export_map: ExportMap, + export_map: ExportMap, trait_map: Option>>, /// A map from nodes to anonymous modules. @@ -933,8 +951,7 @@ /// some AST passes can generate identifiers that only resolve to local or /// language items. empty_module: Module<'a>, - module_map: FxHashMap>, - extern_module_map: FxHashMap>, + module_map: FxHashMap>, binding_parent_modules: FxHashMap>, Module<'a>>, underscore_disambiguator: u32, @@ -1012,8 +1029,6 @@ next_node_id: NodeId, - def_id_to_span: IndexVec, - node_id_to_def_id: FxHashMap, def_id_to_node_id: IndexVec, @@ -1038,6 +1053,7 @@ /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. proc_macros: Vec, + confused_type_with_std_module: FxHashMap, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1052,11 +1068,24 @@ } impl<'a> ResolverArenas<'a> { - fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> { - let module = self.modules.alloc(module); - if module.def_id().map_or(true, |def_id| def_id.is_local()) { + fn new_module( + &'a self, + parent: Option>, + kind: ModuleKind, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + module_map: &mut FxHashMap>, + ) -> Module<'a> { + let module = + self.modules.alloc(ModuleData::new(parent, kind, expn_id, span, no_implicit_prelude)); + let def_id = module.opt_def_id(); + if def_id.map_or(true, |def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } + if let Some(def_id) = def_id { + module_map.insert(def_id, module); + } module } fn local_modules(&'a self) -> std::cell::Ref<'a, Vec>> { @@ -1115,6 +1144,11 @@ } } + #[inline] + fn def_span(&self, id: LocalDefId) -> Span { + self.definitions.def_span(id) + } + fn item_generics_num_lifetimes(&self, def_id: DefId) -> usize { if let Some(def_id) = def_id.as_local() { self.item_generics_num_lifetimes[&def_id] @@ -1127,7 +1161,7 @@ self.legacy_const_generic_args(expr) } - fn get_partial_res(&mut self, id: NodeId) -> Option { + fn get_partial_res(&self, id: NodeId) -> Option { self.partial_res_map.get(&id).cloned() } @@ -1196,9 +1230,7 @@ disambiguator }; - let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator); - - assert_eq!(self.def_id_to_span.push(span), def_id); + let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator, span); // Some things for which we allocate `LocalDefId`s don't correspond to // anything in the AST, so they don't have a `NodeId`. For these cases @@ -1225,6 +1257,11 @@ } #[inline] + fn def_span(&self, id: LocalDefId) -> Span { + self.resolver.def_span(id) + } + + #[inline] fn def_path_hash(&self, def_id: DefId) -> DefPathHash { self.resolver.def_path_hash(def_id) } @@ -1247,35 +1284,31 @@ metadata_loader: Box, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a> { - let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }; - let root_def_id = root_local_def_id.to_def_id(); - let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); - let graph_root = arenas.alloc_module(ModuleData { - no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude), - ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span) - }); - let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); - let empty_module = arenas.alloc_module(ModuleData { - no_implicit_prelude: true, - ..ModuleData::new( - Some(graph_root), - empty_module_kind, - root_def_id, - ExpnId::root(), - DUMMY_SP, - ) - }); + let root_def_id = CRATE_DEF_ID.to_def_id(); let mut module_map = FxHashMap::default(); - module_map.insert(root_local_def_id, graph_root); + let graph_root = arenas.new_module( + None, + ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), + ExpnId::root(), + krate.span, + session.contains_name(&krate.attrs, sym::no_implicit_prelude), + &mut module_map, + ); + let empty_module = arenas.new_module( + None, + ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), + ExpnId::root(), + DUMMY_SP, + true, + &mut FxHashMap::default(), + ); - let definitions = Definitions::new(session.local_stable_crate_id()); + let definitions = Definitions::new(session.local_stable_crate_id(), krate.span); let root = definitions.get_root_def(); let mut visibilities = FxHashMap::default(); - visibilities.insert(root_local_def_id, ty::Visibility::Public); + visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public); - let mut def_id_to_span = IndexVec::default(); - assert_eq!(def_id_to_span.push(rustc_span::DUMMY_SP), root); let mut def_id_to_node_id = IndexVec::default(); assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root); let mut node_id_to_def_id = FxHashMap::default(); @@ -1335,7 +1368,6 @@ empty_module, module_map, block_map: Default::default(), - extern_module_map: FxHashMap::default(), binding_parent_modules: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(), @@ -1392,7 +1424,6 @@ .collect(), lint_buffer: LintBuffer::default(), next_node_id: NodeId::from_u32(1), - def_id_to_span, node_id_to_def_id, def_id_to_node_id, placeholder_field_indices: Default::default(), @@ -1404,6 +1435,7 @@ main_def: Default::default(), trait_impls: Default::default(), proc_macros: Default::default(), + confused_type_with_std_module: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1412,6 +1444,18 @@ resolver } + fn new_module( + &mut self, + parent: Option>, + kind: ModuleKind, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + ) -> Module<'a> { + let module_map = &mut self.module_map; + self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map) + } + fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> { ExpandHasher { source_map: CachingSourceMapView::new(self.session.source_map()), @@ -1447,6 +1491,7 @@ let maybe_unused_extern_crates = self.maybe_unused_extern_crates; let glob_map = self.glob_map; let main_def = self.main_def; + let confused_type_with_std_module = self.confused_type_with_std_module; ResolverOutputs { definitions, cstore: Box::new(self.crate_loader.into_cstore()), @@ -1464,6 +1509,7 @@ main_def, trait_impls: self.trait_impls, proc_macros, + confused_type_with_std_module, } } @@ -1483,9 +1529,10 @@ .iter() .map(|(ident, entry)| (ident.name, entry.introduced_by_item)) .collect(), - main_def: self.main_def.clone(), + main_def: self.main_def, trait_impls: self.trait_impls.clone(), proc_macros, + confused_type_with_std_module: self.confused_type_with_std_module.clone(), } } @@ -1545,7 +1592,7 @@ if let Some(module) = current_trait { if self.trait_may_have_item(Some(module), assoc_item) { - let def_id = module.def_id().unwrap(); + let def_id = module.def_id(); found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] }); } } @@ -1623,18 +1670,6 @@ import_ids } - fn new_module( - &self, - parent: Module<'a>, - kind: ModuleKind, - nearest_parent_mod: DefId, - expn_id: ExpnId, - span: Span, - ) -> Module<'a> { - let module = ModuleData::new(Some(parent), kind, nearest_parent_mod, expn_id, span); - self.arenas.alloc_module(module) - } - fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { let ident = ident.normalize_to_macros_2_0(); let disambiguator = if ident.name == kw::Underscore { @@ -2007,7 +2042,7 @@ derive_fallback_lint_id: Option, ) -> Option<(Module<'a>, Option)> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some((self.macro_def_scope(ctxt.remove_mark()), None)); + return Some((self.expn_def_scope(ctxt.remove_mark()), None)); } if let ModuleKind::Block(..) = module.kind { @@ -2076,7 +2111,7 @@ ModuleOrUniformRoot::Module(m) => { if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) { tmp_parent_scope = - ParentScope { module: self.macro_def_scope(def), ..*parent_scope }; + ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; adjusted_parent_scope = &tmp_parent_scope; } } @@ -2149,7 +2184,7 @@ ctxt.adjust(ExpnId::root()) }; let module = match mark { - Some(def) => self.macro_def_scope(def), + Some(def) => self.expn_def_scope(def), None => { debug!( "resolve_crate_root({:?}): found no mark (ident.span = {:?})", @@ -2158,7 +2193,9 @@ return self.graph_root; } }; - let module = self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.nearest_parent_mod }); + let module = self.expect_module( + module.opt_def_id().map_or(LOCAL_CRATE, |def_id| def_id.krate).as_def_id(), + ); debug!( "resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})", ident, @@ -2170,10 +2207,10 @@ } fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> { - let mut module = self.get_module(module.nearest_parent_mod); + let mut module = self.expect_module(module.nearest_parent_mod()); while module.span.ctxt().normalize_to_macros_2_0() != *ctxt { - let parent = module.parent.unwrap_or_else(|| self.macro_def_scope(ctxt.remove_mark())); - module = self.get_module(parent.nearest_parent_mod); + let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark())); + module = self.expect_module(parent.nearest_parent_mod()); } module } @@ -2518,7 +2555,22 @@ (format!("use of undeclared type `{}`", ident), suggestion) } else { - (format!("use of undeclared crate or module `{}`", ident), None) + ( + format!("use of undeclared crate or module `{}`", ident), + self.find_similarly_named_module_or_crate( + ident.name, + &parent_scope.module, + ) + .map(|sugg| { + ( + vec![(ident.span, sugg.to_string())], + String::from( + "there is a crate or module with a similar name", + ), + Applicability::MaybeIncorrect, + ) + }), + ) } } else { let parent = path[i - 1].ident.name; @@ -2887,7 +2939,7 @@ } fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { - vis.is_accessible_from(module.nearest_parent_mod, self) + vis.is_accessible_from(module.nearest_parent_mod(), self) } fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) { @@ -2911,7 +2963,7 @@ self.binding_parent_modules.get(&PtrKey(modularized)), ) { (Some(macro_rules), Some(modularized)) => { - macro_rules.nearest_parent_mod == modularized.nearest_parent_mod + macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod() && modularized.is_ancestor_of(macro_rules) } _ => false, @@ -2955,7 +3007,15 @@ (None, false) }; if !candidates.is_empty() { - diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use); + diagnostics::show_candidates( + &self.definitions, + self.session, + &mut err, + span, + &candidates, + instead, + found_use, + ); } else if let Some((span, msg, sugg, appl)) = suggestion { err.span_suggestion(span, msg, sugg, appl); } @@ -2977,7 +3037,7 @@ } let container = match parent.kind { - ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id().unwrap()), + ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()), ModuleKind::Block(..) => "block", }; @@ -3256,7 +3316,7 @@ } else { self.crate_loader.maybe_process_path_extern(ident.name)? }; - let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); + let crate_root = self.expect_module(crate_id.as_def_id()); Some( (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT) .to_name_binding(self.arenas), @@ -3297,7 +3357,7 @@ tokens: None, } }; - let module = self.get_module(module_id); + let module = self.expect_module(module_id); let parent_scope = &ParentScope::module(module, self); let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?; Ok((path, res)) @@ -3355,7 +3415,7 @@ /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. #[inline] pub fn opt_span(&self, def_id: DefId) -> Option { - if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None } + def_id.as_local().map(|def_id| self.definitions.def_span(def_id)) } /// Checks if an expression refers to a function marked with diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/macros.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/macros.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_resolve/src/macros.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_resolve/src/macros.rs 2021-11-29 19:27:11.000000000 +0000 @@ -180,6 +180,10 @@ self.next_node_id() } + fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId { + self.invocation_parents[&id].0 + } + fn resolve_dollar_crates(&mut self) { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); @@ -221,7 +225,8 @@ features: &[Symbol], parent_module_id: Option, ) -> LocalExpnId { - let parent_module = parent_module_id.map(|module_id| self.local_def_id(module_id)); + let parent_module = + parent_module_id.map(|module_id| self.local_def_id(module_id).to_def_id()); let expn_id = LocalExpnId::fresh( ExpnData::allow_unstable( ExpnKind::AstPass(pass), @@ -229,13 +234,13 @@ self.session.edition(), features.into(), None, - parent_module.map(LocalDefId::to_def_id), + parent_module, ), self.create_stable_hashing_context(), ); - let parent_scope = parent_module - .map_or(self.empty_module, |parent_def_id| self.module_map[&parent_def_id]); + let parent_scope = + parent_module.map_or(self.empty_module, |def_id| self.expect_module(def_id)); self.ast_transform_scopes.insert(expn_id, parent_scope); expn_id @@ -294,51 +299,18 @@ )?; let span = invoc.span(); + let def_id = res.opt_def_id(); invoc_id.set_expn_data( ext.expn_data( parent_scope.expansion, span, fast_print_path(path), - res.opt_def_id(), - res.opt_def_id().map(|macro_def_id| { - self.macro_def_scope_from_def_id(macro_def_id).nearest_parent_mod - }), + def_id, + def_id.map(|def_id| self.macro_def_scope(def_id).nearest_parent_mod()), ), self.create_stable_hashing_context(), ); - if let Res::Def(_, _) = res { - // Gate macro attributes in `#[derive]` output. - if !self.session.features_untracked().macro_attributes_in_derive_output - && kind == MacroKind::Attr - && ext.builtin_name != Some(sym::derive) - { - let mut expn_id = parent_scope.expansion; - loop { - // Helper attr table is a quick way to determine whether the attr is `derive`. - if self.helper_attrs.contains_key(&expn_id) { - feature_err( - &self.session.parse_sess, - sym::macro_attributes_in_derive_output, - path.span, - "macro attributes in `#[derive]` output are unstable", - ) - .emit(); - break; - } else { - let expn_data = expn_id.expn_data(); - match expn_data.kind { - ExpnKind::Root - | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { - break; - } - _ => expn_id = expn_data.parent.expect_local(), - } - } - } - } - } - Ok(ext) } @@ -1165,7 +1137,7 @@ } if let Some(depr) = &ext.deprecation { let path = pprust::path_to_string(&path); - let (message, lint) = stability::deprecation_message(depr, "macro", &path); + let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path); stability::early_report_deprecation( &mut self.lint_buffer, &message, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_save_analysis/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_save_analysis/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_save_analysis/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_save_analysis/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_save_analysis" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] tracing = "0.1" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_save_analysis/src/dump_visitor.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_save_analysis/src/dump_visitor.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_save_analysis/src/dump_visitor.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_save_analysis/src/dump_visitor.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir_pretty::{bounds_to_string, fn_to_string, generic_params_to_string, ty_to_string}; use rustc_middle::hir::map::Map; @@ -128,7 +128,7 @@ self.save_ctxt.lookup_def_id(ref_id) } - pub fn dump_crate_info(&mut self, name: &str, krate: &hir::Crate<'_>) { + pub fn dump_crate_info(&mut self, name: &str) { let source_file = self.tcx.sess.local_crate_source_file.as_ref(); let crate_root = source_file.map(|source_file| { let source_file = Path::new(source_file); @@ -146,7 +146,7 @@ }, crate_root: crate_root.unwrap_or_else(|| "".to_owned()), external_crates: self.save_ctxt.get_external_crates(), - span: self.span_from_span(krate.module().inner), + span: self.span_from_span(self.tcx.def_span(CRATE_DEF_ID)), }; self.dumper.crate_prelude(data); @@ -682,7 +682,7 @@ ); } - // super-traits + // supertraits for super_bound in trait_refs.iter() { let (def_id, sub_span) = match *super_bound { hir::GenericBound::Trait(ref trait_ref, _) => ( @@ -693,7 +693,6 @@ (Some(self.tcx.require_lang_item(lang_item, Some(span))), span) } hir::GenericBound::Outlives(..) => continue, - hir::GenericBound::Unsized(_) => continue, }; if let Some(id) = def_id { @@ -1091,13 +1090,13 @@ } } - pub(crate) fn process_crate(&mut self, krate: &'tcx hir::Crate<'tcx>) { + pub(crate) fn process_crate(&mut self) { let id = hir::CRATE_HIR_ID; let qualname = format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id())); let sm = self.tcx.sess.source_map(); - let krate_mod = krate.module(); + let krate_mod = self.tcx.hir().root_module(); let filename = sm.span_to_filename(krate_mod.inner); let data_id = id_from_hir_id(id, &self.save_ctxt); let children = @@ -1122,7 +1121,7 @@ attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt), }, ); - intravisit::walk_crate(self, krate); + self.tcx.hir().walk_toplevel_module(self); } fn process_bounds(&mut self, bounds: hir::GenericBounds<'tcx>) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_save_analysis/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_save_analysis/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_save_analysis/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_save_analysis/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(if_let_guard)] #![feature(nll)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard #![recursion_limit = "256"] mod dump_visitor; @@ -20,11 +19,11 @@ use rustc_hir::Node; use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string}; use rustc_middle::hir::map::Map; -use rustc_middle::middle::cstore::ExternCrate; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, Input, OutputType}; +use rustc_session::cstore::ExternCrate; use rustc_session::output::{filename_for_metadata, out_filename}; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; @@ -1004,9 +1003,9 @@ let mut visitor = DumpVisitor::new(save_ctxt); - visitor.dump_crate_info(cratename, tcx.hir().krate()); + visitor.dump_crate_info(cratename); visitor.dump_compilation_options(input, cratename); - visitor.process_crate(tcx.hir().krate()); + visitor.process_crate(); handler.save(&visitor.save_ctxt, &visitor.analysis()) }) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_serialize/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_serialize/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_serialize/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_serialize/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_serialize" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] indexmap = "1" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_serialize/src/serialize.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_serialize/src/serialize.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_serialize/src/serialize.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_serialize/src/serialize.rs 2021-11-29 19:27:11.000000000 +0000 @@ -366,6 +366,18 @@ char emit_char read_char } +impl Encodable for ! { + fn encode(&self, _s: &mut S) -> Result<(), S::Error> { + unreachable!() + } +} + +impl Decodable for ! { + fn decode(_d: &mut D) -> Result { + unreachable!() + } +} + impl Encodable for ::std::num::NonZeroU32 { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u32(self.get()) @@ -488,8 +500,8 @@ d.read_seq(|d, len| { assert!(len == N); let mut v = [0u8; N]; - for i in 0..len { - v[i] = d.read_seq_elt(|d| Decodable::decode(d))?; + for x in &mut v { + *x = d.read_seq_elt(|d| Decodable::decode(d))?; } Ok(v) }) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_session" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] getopts = "0.2" @@ -9,6 +9,7 @@ tracing = "0.1" rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } rustc_target = { path = "../rustc_target" } rustc_serialize = { path = "../rustc_serialize" } rustc_data_structures = { path = "../rustc_data_structures" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/config.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/config.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/config.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/config.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1920,9 +1920,10 @@ fn parse_remap_path_prefix( matches: &getopts::Matches, + debugging_opts: &DebuggingOptions, error_format: ErrorOutputType, ) -> Vec<(PathBuf, PathBuf)> { - matches + let mut mapping: Vec<(PathBuf, PathBuf)> = matches .opt_strs("remap-path-prefix") .into_iter() .map(|remap| match remap.rsplit_once('=') { @@ -1932,7 +1933,15 @@ ), Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), }) - .collect() + .collect(); + match &debugging_opts.remap_cwd_prefix { + Some(to) => match std::env::current_dir() { + Ok(cwd) => mapping.push((cwd, to.clone())), + Err(_) => (), + }, + None => (), + }; + mapping } pub fn build_session_options(matches: &getopts::Matches) -> Options { @@ -2000,6 +2009,15 @@ ); } + if debugging_opts.profile_sample_use.is_some() + && (cg.profile_generate.enabled() || cg.profile_use.is_some()) + { + early_error( + error_format, + "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`", + ); + } + if debugging_opts.instrument_coverage.is_some() && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off) { @@ -2077,7 +2095,7 @@ let crate_name = matches.opt_str("crate-name"); - let remap_path_prefix = parse_remap_path_prefix(matches, error_format); + let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format); let pretty = parse_pretty(&debugging_opts, error_format); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/cstore.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/cstore.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/cstore.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/cstore.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,206 @@ +//! the rustc crate store interface. This also includes types that +//! are *mostly* used as a part of that interface, but these should +//! probably get a better home if someone can find one. + +use crate::search_paths::PathKind; +use crate::utils::NativeLibKind; +use crate::Session; +use rustc_ast as ast; +use rustc_data_structures::sync::{self, MetadataRef}; +use rustc_hir::def_id::{CrateNum, DefId, StableCrateId, LOCAL_CRATE}; +use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; +use rustc_span::hygiene::{ExpnHash, ExpnId}; +use rustc_span::symbol::Symbol; +use rustc_span::Span; +use rustc_target::spec::Target; + +use std::any::Any; +use std::path::{Path, PathBuf}; + +// lonely orphan structs and enums looking for a better home + +/// Where a crate came from on the local filesystem. One of these three options +/// must be non-None. +#[derive(PartialEq, Clone, Debug, HashStable_Generic, Encodable, Decodable)] +pub struct CrateSource { + pub dylib: Option<(PathBuf, PathKind)>, + pub rlib: Option<(PathBuf, PathKind)>, + pub rmeta: Option<(PathBuf, PathKind)>, +} + +impl CrateSource { + #[inline] + pub fn paths(&self) -> impl Iterator { + self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0) + } +} + +#[derive(Encodable, Decodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] +#[derive(HashStable_Generic)] +pub enum CrateDepKind { + /// A dependency that is only used for its macros. + MacrosOnly, + /// A dependency that is always injected into the dependency list and so + /// doesn't need to be linked to an rlib, e.g., the injected allocator. + Implicit, + /// A dependency that is required by an rlib version of this crate. + /// Ordinary `extern crate`s result in `Explicit` dependencies. + Explicit, +} + +impl CrateDepKind { + #[inline] + pub fn macros_only(self) -> bool { + match self { + CrateDepKind::MacrosOnly => true, + CrateDepKind::Implicit | CrateDepKind::Explicit => false, + } + } +} + +#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable_Generic)] +pub enum LinkagePreference { + RequireDynamic, + RequireStatic, +} + +#[derive(Debug, Encodable, Decodable, HashStable_Generic)] +pub struct NativeLib { + pub kind: NativeLibKind, + pub name: Option, + pub cfg: Option, + pub foreign_module: Option, + pub wasm_import_module: Option, + pub verbatim: Option, + pub dll_imports: Vec, +} + +#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] +pub struct DllImport { + pub name: Symbol, + pub ordinal: Option, + /// Calling convention for the function. + /// + /// On x86_64, this is always `DllCallingConvention::C`; on i686, it can be any + /// of the values, and we use `DllCallingConvention::C` to represent `"cdecl"`. + pub calling_convention: DllCallingConvention, + /// Span of import's "extern" declaration; used for diagnostics. + pub span: Span, +} + +/// Calling convention for a function defined in an external library. +/// +/// The usize value, where present, indicates the size of the function's argument list +/// in bytes. +#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)] +pub enum DllCallingConvention { + C, + Stdcall(usize), + Fastcall(usize), + Vectorcall(usize), +} + +#[derive(Clone, Encodable, Decodable, HashStable_Generic, Debug)] +pub struct ForeignModule { + pub foreign_items: Vec, + pub def_id: DefId, +} + +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub struct ExternCrate { + pub src: ExternCrateSource, + + /// span of the extern crate that caused this to be loaded + pub span: Span, + + /// Number of links to reach the extern; + /// used to select the extern with the shortest path + pub path_len: usize, + + /// Crate that depends on this crate + pub dependency_of: CrateNum, +} + +impl ExternCrate { + /// If true, then this crate is the crate named by the extern + /// crate referenced above. If false, then this crate is a dep + /// of the crate. + #[inline] + pub fn is_direct(&self) -> bool { + self.dependency_of == LOCAL_CRATE + } + + #[inline] + pub fn rank(&self) -> impl PartialOrd { + // Prefer: + // - direct extern crate to indirect + // - shorter paths to longer + (self.is_direct(), !self.path_len) + } +} + +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub enum ExternCrateSource { + /// Crate is loaded by `extern crate`. + Extern( + /// def_id of the item in the current crate that caused + /// this crate to be loaded; note that there could be multiple + /// such ids + DefId, + ), + /// Crate is implicitly loaded by a path resolving through extern prelude. + Path, +} + +/// The backend's way to give the crate store access to the metadata in a library. +/// Note that it returns the raw metadata bytes stored in the library file, whether +/// it is compressed, uncompressed, some weird mix, etc. +/// rmeta files are backend independent and not handled here. +/// +/// At the time of this writing, there is only one backend and one way to store +/// metadata in library -- this trait just serves to decouple rustc_metadata from +/// the archive reader, which depends on LLVM. +pub trait MetadataLoader { + fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result; + fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result; +} + +pub type MetadataLoaderDyn = dyn MetadataLoader + Sync; + +/// A store of Rust crates, through which their metadata can be accessed. +/// +/// Note that this trait should probably not be expanding today. All new +/// functionality should be driven through queries instead! +/// +/// If you find a method on this trait named `{name}_untracked` it signifies +/// that it's *not* tracked for dependency information throughout compilation +/// (it'd break incremental compilation) and should only be called pre-HIR (e.g. +/// during resolve) +pub trait CrateStore: std::fmt::Debug { + fn as_any(&self) -> &dyn Any; + + // Foreign definitions. + // This information is safe to access, since it's hashed as part of the DefPathHash, which incr. + // comp. uses to identify a DefId. + fn def_key(&self, def: DefId) -> DefKey; + fn def_path(&self, def: DefId) -> DefPath; + fn def_path_hash(&self, def: DefId) -> DefPathHash; + + // This information is safe to access, since it's hashed as part of the StableCrateId, which + // incr. comp. uses to identify a CrateNum. + 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; +} + +pub type CrateStoreDyn = dyn CrateStore + sync::Sync; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/filesearch.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/filesearch.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/filesearch.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/filesearch.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,5 @@ +//! A module for searching for libraries + pub use self::FileMatch::*; use std::env; @@ -14,8 +16,6 @@ FileDoesntMatch, } -// A module for searching for libraries - #[derive(Clone)] pub struct FileSearch<'a> { sysroot: &'a Path, @@ -83,22 +83,10 @@ FileSearch { sysroot, triple, search_paths, tlib_path, kind } } - // Returns just the directories within the search paths. + /// Returns just the directories within the search paths. pub fn search_path_dirs(&self) -> Vec { self.search_paths().map(|sp| sp.dir.to_path_buf()).collect() } - - // Returns a list of directories where target-specific tool binaries are located. - pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec { - let rustlib_path = rustc_target::target_rustlib_path(self.sysroot, &self.triple); - let p = std::array::IntoIter::new([ - Path::new(&self.sysroot), - Path::new(&rustlib_path), - Path::new("bin"), - ]) - .collect::(); - if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] } - } } pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { @@ -107,8 +95,8 @@ .collect::() } -// This function checks if sysroot is found using env::args().next(), and if it -// is not found, uses env::current_exe() to imply sysroot. +/// This function checks if sysroot is found using env::args().next(), and if it +/// is not found, uses env::current_exe() to imply sysroot. pub fn get_or_default_sysroot() -> PathBuf { // Follow symlinks. If the resolved path is relative, make it absolute. fn canonicalize(path: PathBuf) -> PathBuf { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,5 @@ #![feature(crate_visibility_modifier)] +#![feature(min_specialization)] #![feature(once_cell)] #![recursion_limit = "256"] @@ -14,6 +15,7 @@ mod code_stats; #[macro_use] pub mod config; +pub mod cstore; pub mod filesearch; mod options; pub mod search_paths; @@ -28,4 +30,4 @@ /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext {} +pub trait HashStableContext: rustc_ast::HashStableContext + rustc_hir::HashStableContext {} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/options.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/options.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/options.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/options.rs 2021-11-29 19:27:11.000000000 +0000 @@ -349,6 +349,7 @@ pub const parse_threads: &str = parse_number; pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; + pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`"; @@ -549,7 +550,7 @@ } } - crate fn parse_panic_strategy(slot: &mut Option, v: Option<&str>) -> bool { + crate fn parse_opt_panic_strategy(slot: &mut Option, v: Option<&str>) -> bool { match v { Some("unwind") => *slot = Some(PanicStrategy::Unwind), Some("abort") => *slot = Some(PanicStrategy::Abort), @@ -558,6 +559,15 @@ true } + crate fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool { + match v { + Some("unwind") => *slot = PanicStrategy::Unwind, + Some("abort") => *slot = PanicStrategy::Abort, + _ => return false, + } + true + } + crate fn parse_relro_level(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => match s.parse::() { @@ -958,7 +968,7 @@ "optimization level (0-3, s, or z; default: 0)"), overflow_checks: Option = (None, parse_opt_bool, [TRACKED], "use overflow checks for integer arithmetic"), - panic: Option = (None, parse_panic_strategy, [TRACKED], + panic: Option = (None, parse_opt_panic_strategy, [TRACKED], "panic strategy to compile crate with"), passes: Vec = (Vec::new(), parse_list, [TRACKED], "a list of extra LLVM passes to run (space separated)"), @@ -1030,6 +1040,8 @@ "combine CGUs into a single one"), crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), + debug_info_for_profiling: bool = (false, parse_bool, [TRACKED], + "emit discriminators and other data necessary for AutoFDO"), debug_macros: bool = (false, parse_bool, [TRACKED], "emit line numbers debug info inside macros (default: no)"), deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], @@ -1106,6 +1118,8 @@ incremental_info: bool = (false, parse_bool, [UNTRACKED], "print high-level information about incremental reuse (or the lack thereof) \ (default: no)"), + incremental_relative_spans: bool = (false, parse_bool, [TRACKED], + "hash spans relative to their parent item for incr. comp. (default: no)"), incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], "verify incr. comp. hashes of green query instances (default: no)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], @@ -1184,6 +1198,8 @@ "pass `-install_name @rpath/...` to the macOS linker (default: no)"), panic_abort_tests: bool = (false, parse_bool, [TRACKED], "support compiling tests with panic=abort (default: no)"), + panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED], + "panic strategy for panics in drops"), parse_only: bool = (false, parse_bool, [UNTRACKED], "parse only; do not compile, assemble, or link (default: no)"), partially_uninit_const_threshold: Option = (None, parse_opt_number, [TRACKED], @@ -1228,14 +1244,20 @@ (default based on relative source path)"), profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"), + profile_sample_use: Option = (None, parse_opt_pathbuf, [TRACKED], + "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), query_dep_graph: bool = (false, parse_bool, [UNTRACKED], "enable queries of the dependency graph for regression testing (default: no)"), query_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about the query system (default: no)"), + randomize_layout: bool = (false, parse_bool, [TRACKED], + "randomize the layout of types (default: no)"), relax_elf_relocations: Option = (None, parse_opt_bool, [TRACKED], "whether ELF relocations can be relaxed"), relro_level: Option = (None, parse_relro_level, [TRACKED], "choose which RELRO level to use"), + remap_cwd_prefix: Option = (None, parse_opt_pathbuf, [TRACKED], + "remap paths under the current working directory to this path prefix"), simulate_remapped_rust_src_base: Option = (None, parse_opt_pathbuf, [TRACKED], "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ to rust's source base directory. only meant for testing purposes"), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/search_paths.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/search_paths.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/search_paths.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/search_paths.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,17 +9,17 @@ pub files: Vec, } -// The obvious implementation of `SearchPath::files` is a `Vec`. But -// it is searched repeatedly by `find_library_crate`, and the searches involve -// checking the prefix and suffix of the filename of each `PathBuf`. This is -// doable, but very slow, because it involves calls to `file_name` and -// `extension` that are themselves slow. -// -// This type augments the `PathBuf` with an `Option` containing the -// `PathBuf`'s filename. The prefix and suffix checking is much faster on the -// `Option` than the `PathBuf`. (It's an `Option` because -// `Path::file_name` can fail; if that happens then all subsequent checking -// will also fail, which is fine.) +/// The obvious implementation of `SearchPath::files` is a `Vec`. But +/// it is searched repeatedly by `find_library_crate`, and the searches involve +/// checking the prefix and suffix of the filename of each `PathBuf`. This is +/// doable, but very slow, because it involves calls to `file_name` and +/// `extension` that are themselves slow. +/// +/// This type augments the `PathBuf` with an `Option` containing the +/// `PathBuf`'s filename. The prefix and suffix checking is much faster on the +/// `Option` than the `PathBuf`. (It's an `Option` because +/// `Path::file_name` can fail; if that happens then all subsequent checking +/// will also fail, which is fine.) #[derive(Clone, Debug)] pub struct SearchPathFile { pub path: PathBuf, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/session.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/session.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_session/src/session.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_session/src/session.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,9 @@ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use crate::config::{self, CrateType, OutputType, SwitchWithOptPath}; -use crate::filesearch; -use crate::lint::{self, LintId}; use crate::parse::ParseSess; use crate::search_paths::{PathKind, SearchPath}; +use crate::{filesearch, lint}; pub use rustc_ast::attr::MarkedAttrs; pub use rustc_ast::Attribute; @@ -36,15 +35,11 @@ use std::io::Write; use std::num::NonZeroU32; use std::ops::{Div, Mul}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Arc; use std::time::Duration; -pub trait SessionLintStore: sync::Send + sync::Sync { - fn name_to_lint(&self, lint_name: &str) -> LintId; -} - pub struct OptimizationFuel { /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`. remaining: u64, @@ -131,9 +126,8 @@ pub target: Target, pub host: Target, pub opts: config::Options, - pub host_tlib_path: SearchPath, - /// `None` if the host and target are the same. - pub target_tlib_path: Option, + pub host_tlib_path: Lrc, + pub target_tlib_path: Lrc, pub parse_sess: ParseSess, pub sysroot: PathBuf, /// The name of the root source file of the crate, in the local file system. @@ -154,8 +148,6 @@ features: OnceCell, - lint_store: OnceCell>, - incr_comp_session: OneThread>, /// Used for incremental compilation tests. Will only be populated if /// `-Zquery-dep-graph` is specified. @@ -183,10 +175,6 @@ /// Cap lint level specified by a driver specifically. pub driver_lint_caps: FxHashMap, - /// Mapping from ident span to path span for paths that don't exist as written, but that - /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. - pub confused_type_with_std_module: Lock>, - /// Tracks the current behavior of the CTFE engine when an error occurs. /// Options range from returning the error without a backtrace to returning an error /// and immediately printing the backtrace to stderr. @@ -593,13 +581,6 @@ } } - pub fn init_lint_store(&self, lint_store: Lrc) { - self.lint_store - .set(lint_store) - .map_err(|_| ()) - .expect("`lint_store` was initialized twice"); - } - /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line @@ -788,8 +769,7 @@ &self.sysroot, self.opts.target_triple.triple(), &self.opts.search_paths, - // `target_tlib_path == None` means it's the same as `host_tlib_path`. - self.target_tlib_path.as_ref().unwrap_or(&self.host_tlib_path), + &self.target_tlib_path, kind, ) } @@ -803,6 +783,18 @@ ) } + /// Returns a list of directories where target-specific tool binaries are located. + pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec { + let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, &config::host_triple()); + let p = std::array::IntoIter::new([ + Path::new(&self.sysroot), + Path::new(&rustlib_path), + Path::new("bin"), + ]) + .collect::(); + if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] } + } + pub fn init_incr_comp_session( &self, session_dir: PathBuf, @@ -887,13 +879,18 @@ /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; - if let Some(c) = self.opts.debugging_opts.fuel.as_ref().map(|i| &i.0) { + if let Some((ref c, _)) = self.opts.debugging_opts.fuel { if c == crate_name { assert_eq!(self.threads(), 1); let mut fuel = self.optimization_fuel.lock(); ret = fuel.remaining != 0; if fuel.remaining == 0 && !fuel.out_of_fuel { - self.warn(&format!("optimization-fuel-exhausted: {}", msg())); + if self.diagnostic().can_emit_warnings() { + // We only call `msg` in case we can actually emit warnings. + // Otherwise, this could cause a `delay_good_path_bug` to + // trigger (issue #79546). + self.warn(&format!("optimization-fuel-exhausted: {}", msg())); + } fuel.out_of_fuel = true; } else if fuel.remaining > 0 { fuel.remaining -= 1; @@ -1246,11 +1243,13 @@ let host_triple = config::host_triple(); let target_triple = sopts.target_triple.triple(); - let host_tlib_path = SearchPath::from_sysroot_and_triple(&sysroot, host_triple); + let host_tlib_path = Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, host_triple)); let target_tlib_path = if host_triple == target_triple { - None + // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary + // rescanning of the target lib path and an unnecessary allocation. + host_tlib_path.clone() } else { - Some(SearchPath::from_sysroot_and_triple(&sysroot, target_triple)) + Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple)) }; let file_path_mapping = sopts.file_path_mapping(); @@ -1298,7 +1297,6 @@ crate_types: OnceCell::new(), stable_crate_id: OnceCell::new(), features: OnceCell::new(), - lint_store: OnceCell::new(), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), cgu_reuse_tracker, prof, @@ -1313,7 +1311,6 @@ print_fuel, jobserver: jobserver::client(), driver_lint_caps, - confused_type_with_std_module: Lock::new(Default::default()), ctfe_backtrace, miri_unleashed_features: Lock::new(Default::default()), asm_arch, @@ -1356,6 +1353,16 @@ } } + // Do the same for sample profile data. + if let Some(ref path) = sess.opts.debugging_opts.profile_sample_use { + if !path.exists() { + sess.err(&format!( + "File `{}` passed to `-C profile-sample-use` does not exist.", + path.display() + )); + } + } + // Unwind tables cannot be disabled if the target requires them. if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables { if sess.target.requires_uwtable && !include_uwtables { @@ -1387,7 +1394,7 @@ // Cannot enable crt-static with sanitizers on Linux if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() { sess.err( - "Sanitizer is incompatible with statically linked libc, \ + "sanitizer is incompatible with statically linked libc, \ disable it using `-C target-feature=-crt-static`", ); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_span" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/caching_source_map_view.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/caching_source_map_view.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/caching_source_map_view.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/caching_source_map_view.rs 2021-11-29 19:27:11.000000000 +0000 @@ -215,13 +215,13 @@ // Span lo and hi may equal line end when last line doesn't // end in newline, hence the inclusive upper bounds below. - debug_assert!(span_data.lo >= lo.line.start); - debug_assert!(span_data.lo <= lo.line.end); - debug_assert!(span_data.hi >= hi.line.start); - debug_assert!(span_data.hi <= hi.line.end); - debug_assert!(lo.file.contains(span_data.lo)); - debug_assert!(lo.file.contains(span_data.hi)); - debug_assert_eq!(lo.file_index, hi.file_index); + assert!(span_data.lo >= lo.line.start); + assert!(span_data.lo <= lo.line.end); + assert!(span_data.hi >= hi.line.start); + assert!(span_data.hi <= hi.line.end); + assert!(lo.file.contains(span_data.lo)); + assert!(lo.file.contains(span_data.hi)); + assert_eq!(lo.file_index, hi.file_index); Some(( lo.file.clone(), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/hygiene.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/hygiene.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/hygiene.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/hygiene.rs 2021-11-29 19:27:11.000000000 +0000 @@ -601,7 +601,10 @@ let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID"); debug_expn_data((&id.to_expn_id(), expn_data)) }); - data.foreign_expn_data.iter().for_each(debug_expn_data); + // Sort the hash map for more reproducible output. + let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect(); + foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id)); + foreign_expn_data.into_iter().for_each(debug_expn_data); s.push_str("\n\nSyntaxContexts:"); data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| { s.push_str(&format!( @@ -1098,6 +1101,7 @@ Await, ForLoop(ForLoopLoc), LetElse, + WhileLoop, } /// A location in the desugaring of a `for` loop @@ -1119,6 +1123,7 @@ DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop(_) => "`for` loop", DesugaringKind::LetElse => "`let...else`", + DesugaringKind::WhileLoop => "`while` loop", } } } @@ -1357,9 +1362,7 @@ mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash) -> Result<(), E>, ) -> Result<(), E> { let all_data: Vec<_> = HygieneData::with(|data| { - expns - .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn).clone())) - .collect() + expns.map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))).collect() }); for (expn, data, hash) in all_data.into_iter() { f(expn, &data, hash)?; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,11 +21,13 @@ #![feature(nll)] #![feature(min_specialization)] #![feature(thread_local_const_init)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + use rustc_data_structures::AtomicRef; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -42,7 +44,7 @@ pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind}; pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext}; pub mod def_id; -use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE}; +use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE}; pub mod lev_distance; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -79,7 +81,7 @@ // threads within the compilation session, but is not accessible outside the // session. pub struct SessionGlobals { - symbol_interner: Lock, + symbol_interner: symbol::Interner, span_interner: Lock, hygiene_data: Lock, source_map: Lock>>, @@ -88,7 +90,7 @@ impl SessionGlobals { pub fn new(edition: Edition) -> SessionGlobals { SessionGlobals { - symbol_interner: Lock::new(symbol::Interner::fresh()), + symbol_interner: symbol::Interner::fresh(), span_interner: Lock::new(span_encoding::SpanInterner::default()), hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), source_map: Lock::new(None), @@ -435,24 +437,38 @@ /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. pub ctxt: SyntaxContext, + pub parent: Option, } impl SpanData { #[inline] pub fn span(&self) -> Span { - Span::new(self.lo, self.hi, self.ctxt) + Span::new(self.lo, self.hi, self.ctxt, self.parent) } #[inline] pub fn with_lo(&self, lo: BytePos) -> Span { - Span::new(lo, self.hi, self.ctxt) + Span::new(lo, self.hi, self.ctxt, self.parent) } #[inline] pub fn with_hi(&self, hi: BytePos) -> Span { - Span::new(self.lo, hi, self.ctxt) + Span::new(self.lo, hi, self.ctxt, self.parent) } #[inline] pub fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { - Span::new(self.lo, self.hi, ctxt) + Span::new(self.lo, self.hi, ctxt, self.parent) + } + #[inline] + pub fn with_parent(&self, parent: Option) -> Span { + Span::new(self.lo, self.hi, self.ctxt, parent) + } + /// Returns `true` if this is a dummy span with any hygienic context. + #[inline] + pub fn is_dummy(self) -> bool { + self.lo.0 == 0 && self.hi.0 == 0 + } + /// Returns `true` if `self` fully encloses `other`. + pub fn contains(self, other: Self) -> bool { + self.lo <= other.lo && other.hi <= self.hi } } @@ -508,18 +524,25 @@ } #[inline] pub fn ctxt(self) -> SyntaxContext { - self.data().ctxt + self.data_untracked().ctxt } #[inline] pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span { - self.data().with_ctxt(ctxt) + self.data_untracked().with_ctxt(ctxt) + } + #[inline] + pub fn parent(self) -> Option { + self.data().parent + } + #[inline] + pub fn with_parent(self, ctxt: Option) -> Span { + self.data().with_parent(ctxt) } /// Returns `true` if this is a dummy span with any hygienic context. #[inline] pub fn is_dummy(self) -> bool { - let span = self.data(); - span.lo.0 == 0 && span.hi.0 == 0 + self.data_untracked().is_dummy() } /// Returns `true` if this span comes from a macro or desugaring. @@ -535,26 +558,26 @@ #[inline] pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span { - Span::new(lo, hi, SyntaxContext::root()) + Span::new(lo, hi, SyntaxContext::root(), None) } /// Returns a new span representing an empty span at the beginning of this span. #[inline] pub fn shrink_to_lo(self) -> Span { - let span = self.data(); + let span = self.data_untracked(); span.with_hi(span.lo) } /// Returns a new span representing an empty span at the end of this span. #[inline] pub fn shrink_to_hi(self) -> Span { - let span = self.data(); + let span = self.data_untracked(); span.with_lo(span.hi) } #[inline] /// Returns `true` if `hi == lo`. pub fn is_empty(&self) -> bool { - let span = self.data(); + let span = self.data_untracked(); span.hi == span.lo } @@ -567,7 +590,7 @@ pub fn contains(self, other: Span) -> bool { let span = self.data(); let other = other.data(); - span.lo <= other.lo && other.hi <= span.hi + span.contains(other) } /// Returns `true` if `self` touches `other`. @@ -603,7 +626,7 @@ /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, /// if any. - pub fn parent(self) -> Option { + pub fn parent_callsite(self) -> Option { let expn_data = self.ctxt().outer_expn_data(); if !expn_data.is_root() { Some(expn_data.call_site) } else { None } } @@ -611,7 +634,7 @@ /// Walk down the expansion ancestors to find a span that's contained within `outer`. pub fn find_ancestor_inside(mut self, outer: Span) -> Option { while !outer.contains(self) { - self = self.parent()?; + self = self.parent_callsite()?; } Some(self) } @@ -732,6 +755,7 @@ cmp::min(span_data.lo, end_data.lo), cmp::max(span_data.hi, end_data.hi), if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt }, + if span_data.parent == end_data.parent { span_data.parent } else { None }, ) } @@ -749,6 +773,7 @@ span.hi, end.lo, if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt }, + if span.parent == end.parent { span.parent } else { None }, ) } @@ -760,12 +785,30 @@ /// ^^^^^^^^^^^^^^^^^ /// ``` pub fn until(self, end: Span) -> Span { - let span = self.data(); - let end = end.data(); + // Most of this function's body is copied from `to`. + // We can't just do `self.to(end.shrink_to_lo())`, + // because to also does some magic where it uses min/max so + // it can handle overlapping spans. Some advanced mis-use of + // `until` with different ctxts makes this visible. + let span_data = self.data(); + let end_data = end.data(); + // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480). + // Return the macro span on its own to avoid weird diagnostic output. It is preferable to + // have an incomplete span than a completely nonsensical one. + if span_data.ctxt != end_data.ctxt { + if span_data.ctxt == SyntaxContext::root() { + return end; + } else if end_data.ctxt == SyntaxContext::root() { + return self; + } + // Both spans fall within a macro. + // FIXME(estebank): check if it is the *same* macro. + } Span::new( - span.lo, - end.lo, - if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt }, + span_data.lo, + end_data.lo, + if end_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt }, + if span_data.parent == end_data.parent { span_data.parent } else { None }, ) } @@ -775,6 +818,7 @@ span.lo + BytePos::from_usize(inner.start), span.lo + BytePos::from_usize(inner.end), span.ctxt, + span.parent, ) } @@ -813,7 +857,7 @@ pub fn remove_mark(&mut self) -> ExpnId { let mut span = self.data(); let mark = span.ctxt.remove_mark(); - *self = Span::new(span.lo, span.hi, span.ctxt); + *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); mark } @@ -821,7 +865,7 @@ pub fn adjust(&mut self, expn_id: ExpnId) -> Option { let mut span = self.data(); let mark = span.ctxt.adjust(expn_id); - *self = Span::new(span.lo, span.hi, span.ctxt); + *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); mark } @@ -829,7 +873,7 @@ pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option { let mut span = self.data(); let mark = span.ctxt.normalize_to_macros_2_0_and_adjust(expn_id); - *self = Span::new(span.lo, span.hi, span.ctxt); + *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); mark } @@ -837,7 +881,7 @@ pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option> { let mut span = self.data(); let mark = span.ctxt.glob_adjust(expn_id, glob_span); - *self = Span::new(span.lo, span.hi, span.ctxt); + *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); mark } @@ -849,7 +893,7 @@ ) -> Option> { let mut span = self.data(); let mark = span.ctxt.reverse_glob_adjust(expn_id, glob_span); - *self = Span::new(span.lo, span.hi, span.ctxt); + *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); mark } @@ -901,7 +945,7 @@ let lo = d.read_struct_field("lo", Decodable::decode)?; let hi = d.read_struct_field("hi", Decodable::decode)?; - Ok(Span::new(lo, hi, SyntaxContext::root())) + Ok(Span::new(lo, hi, SyntaxContext::root(), None)) }) } } @@ -962,7 +1006,7 @@ impl fmt::Debug for SpanData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt), f) + (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt, self.parent), f) } } @@ -1923,6 +1967,7 @@ pub static SPAN_DEBUG: AtomicRef) -> fmt::Result> = AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); +pub static SPAN_TRACK: AtomicRef = AtomicRef::new(&((|_| {}) as fn(_))); // _____________________________________________________________________________ // SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions @@ -1977,6 +2022,7 @@ pub trait HashStableContext { fn def_path_hash(&self, def_id: DefId) -> DefPathHash; fn hash_spans(&self) -> bool; + fn def_span(&self, def_id: LocalDefId) -> Span; fn span_data_to_lines_and_cols( &mut self, span: &SpanData, @@ -2000,22 +2046,35 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; + const TAG_RELATIVE_SPAN: u8 = 2; if !ctx.hash_spans() { return; } - self.ctxt().hash_stable(ctx, hasher); + let span = self.data_untracked(); + span.ctxt.hash_stable(ctx, hasher); + span.parent.hash_stable(ctx, hasher); - if self.is_dummy() { + if span.is_dummy() { Hash::hash(&TAG_INVALID_SPAN, hasher); return; } + if let Some(parent) = span.parent { + let def_span = ctx.def_span(parent).data_untracked(); + if def_span.contains(span) { + // This span is enclosed in a definition: only hash the relative position. + Hash::hash(&TAG_RELATIVE_SPAN, hasher); + (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher); + (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher); + return; + } + } + // If this is not an empty or invalid span, we want to hash the last // position that belongs to it, as opposed to hashing the first // position past it. - let span = self.data(); let (file, line_lo, col_lo, line_hi, col_hi) = match ctx.span_data_to_lines_and_cols(&span) { Some(pos) => pos, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/source_map.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/source_map.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/source_map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/source_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -474,11 +474,12 @@ f.lookup_line(sp.lo()) != f.lookup_line(sp.hi()) } + #[instrument(skip(self), level = "trace")] pub fn is_valid_span(&self, sp: Span) -> Result<(Loc, Loc), SpanLinesError> { let lo = self.lookup_char_pos(sp.lo()); - debug!("span_to_lines: lo={:?}", lo); + trace!(?lo); let hi = self.lookup_char_pos(sp.hi()); - debug!("span_to_lines: hi={:?}", hi); + trace!(?hi); if lo.file.start_pos != hi.file.start_pos { return Err(SpanLinesError::DistinctSources(DistinctSources { begin: (lo.file.name.clone(), lo.file.start_pos), @@ -652,6 +653,18 @@ }) } + /// Extends the given `Span` while the next character matches the predicate + pub fn span_extend_while( + &self, + span: Span, + f: impl Fn(char) -> bool, + ) -> Result { + self.span_to_source(span, |s, _start, end| { + let n = s[end..].char_indices().find(|&(_, c)| !f(c)).map_or(s.len() - end, |(i, _)| i); + Ok(span.with_hi(span.hi() + BytePos(n as u32))) + }) + } + /// Extends the given `Span` to just after the next occurrence of `c`. pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span { if let Ok(next_source) = self.span_to_next_source(sp) { @@ -794,7 +807,7 @@ start_of_next_point.checked_add(width - 1).unwrap_or(start_of_next_point); let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point)); - Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt()) + Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None) } /// Finds the width of the character, either before or after the end of provided span, @@ -1012,6 +1025,32 @@ let source_file = &self.files()[source_file_index]; source_file.is_imported() } + + /// Gets the span of a statement. If the statement is a macro expansion, the + /// span in the context of the block span is found. The trailing semicolon is included + /// on a best-effort basis. + pub fn stmt_span(&self, stmt_span: Span, block_span: Span) -> Span { + if !stmt_span.from_expansion() { + return stmt_span; + } + let mac_call = original_sp(stmt_span, block_span); + self.mac_call_stmt_semi_span(mac_call).map_or(mac_call, |s| mac_call.with_hi(s.hi())) + } + + /// Tries to find the span of the semicolon of a macro call statement. + /// The input must be the *call site* span of a statement from macro expansion. + /// + /// v output + /// mac!(); + /// ^^^^^^ input + pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option { + 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) + } } #[derive(Clone)] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/span_encoding.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/span_encoding.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/span_encoding.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/span_encoding.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,9 @@ // The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd. // See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28 +use crate::def_id::LocalDefId; use crate::hygiene::SyntaxContext; +use crate::SPAN_TRACK; use crate::{BytePos, SpanData}; use rustc_data_structures::fx::FxIndexSet; @@ -54,6 +56,10 @@ /// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt`, /// but larger crates might need more than 16 bits. /// +/// In order to reliably use parented spans in incremental compilation, +/// the dependency to the parent definition's span. This is performed +/// using the callback `SPAN_TRACK` to access the query engine. +/// #[derive(Clone, Copy, Eq, PartialEq, Hash)] pub struct Span { base_or_index: u32, @@ -70,25 +76,42 @@ impl Span { #[inline] - pub fn new(mut lo: BytePos, mut hi: BytePos, ctxt: SyntaxContext) -> Self { + pub fn new( + mut lo: BytePos, + mut hi: BytePos, + ctxt: SyntaxContext, + parent: Option, + ) -> Self { if lo > hi { std::mem::swap(&mut lo, &mut hi); } let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32()); - if len <= MAX_LEN && ctxt2 <= MAX_CTXT { + if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() { // Inline format. Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_zero: ctxt2 as u16 } } else { // Interned format. - let index = with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt })); + let index = + with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })); Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_zero: 0 } } } #[inline] pub fn data(self) -> SpanData { + let data = self.data_untracked(); + if let Some(parent) = data.parent { + (*SPAN_TRACK)(parent); + } + data + } + + /// Internal function to translate between an encoded span and the expanded representation. + /// This function must not be used outside the incremental engine. + #[inline] + pub fn data_untracked(self) -> SpanData { if self.len_or_tag != LEN_TAG { // Inline format. debug_assert!(self.len_or_tag as u32 <= MAX_LEN); @@ -96,6 +119,7 @@ lo: BytePos(self.base_or_index), hi: BytePos(self.base_or_index + self.len_or_tag as u32), ctxt: SyntaxContext::from_u32(self.ctxt_or_zero as u32), + parent: None, } } else { // Interned format. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/symbol/tests.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/symbol/tests.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/symbol/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/symbol/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ #[test] fn interner_tests() { - let mut i: Interner = Interner::default(); + let i = Interner::default(); // first one is zero: assert_eq!(i.intern("dog"), Symbol::new(0)); // re-use gets the same entry: diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/symbol.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/symbol.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_span/src/symbol.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_span/src/symbol.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,6 +5,7 @@ use rustc_arena::DroplessArena; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::sync::Lock; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -168,6 +169,7 @@ Default, Deref, DirBuilder, + Display, DoubleEndedIterator, Duration, Encodable, @@ -193,6 +195,7 @@ Hasher, Implied, Input, + Into, IntoIterator, IoRead, IoWrite, @@ -203,6 +206,7 @@ Left, LinkedList, LintPass, + Mutex, None, Ok, Option, @@ -218,6 +222,7 @@ PathBuf, Pending, Pin, + Pointer, Poll, ProcMacro, ProcMacroHack, @@ -241,6 +246,7 @@ Send, SeqCst, Some, + String, StructuralEq, StructuralPartialEq, Sync, @@ -248,11 +254,15 @@ ToOwned, ToString, Try, + TryFrom, + TryInto, Ty, TyCtxt, TyKind, Unknown, + UnsafeArg, Vec, + VecDeque, Yield, _DECLS, _Self, @@ -389,6 +399,7 @@ cfg_attr_multi, cfg_doctest, cfg_eval, + cfg_hide, cfg_panic, cfg_sanitize, cfg_target_abi, @@ -406,6 +417,7 @@ clone_from, closure, closure_to_fn_coercion, + closure_track_caller, cmp, cmp_max, cmp_min, @@ -429,6 +441,8 @@ const_compare_raw_pointers, const_constructor, const_eval_limit, + const_eval_select, + const_eval_select_ct, const_evaluatable_checked, const_extern_fn, const_fn, @@ -504,7 +518,6 @@ debug_assert_macro, debug_assertions, debug_struct, - debug_trait, debug_trait_builder, debug_tuple, decl_macro, @@ -536,7 +549,9 @@ div_assign, doc, doc_alias, + doc_auto_cfg, doc_cfg, + doc_cfg_hide, doc_keyword, doc_masked, doc_notable_trait, @@ -651,7 +666,6 @@ from_output, from_residual, from_size_align_unchecked, - from_trait, from_usize, fsub_fast, fundamental, @@ -674,8 +688,6 @@ gt, half_open_range_patterns, hash, - hashmap_type, - hashset_type, hexagon_target_feature, hidden, homogeneous_aggregate, @@ -720,7 +732,6 @@ instruction_set, intel, into_iter, - into_trait, intra_doc_pointers, intrinsics, irrefutable_let_patterns, @@ -808,6 +819,7 @@ mem_size_of, mem_size_of_val, mem_uninitialized, + mem_variant_count, mem_zeroed, member_constraints, memory, @@ -837,6 +849,7 @@ mul, mul_assign, mul_with_overflow, + must_not_suspend, must_use, mut_ptr, mut_slice_ptr, @@ -884,6 +897,7 @@ nomem, non_ascii_idents, non_exhaustive, + non_exhaustive_omitted_patterns_lint, non_modrs_mods, none_error, nontemporal_store, @@ -910,7 +924,6 @@ optin_builtin_traits, option, option_env, - option_type, options, or, or_patterns, @@ -924,6 +937,7 @@ panic_2021, panic_abort, panic_bounds_check, + panic_display, panic_fmt, panic_handler, panic_impl, @@ -935,7 +949,6 @@ panic_unwind, panicking, param_attrs, - parent_trait, partial_cmp, partial_ord, passes, @@ -952,7 +965,6 @@ plugins, pointee_trait, pointer, - pointer_trait, pointer_trait_fmt, poll, position, @@ -1048,7 +1060,6 @@ repr_transparent, residual, result, - result_type, rhs, rintf32, rintf64, @@ -1089,6 +1100,7 @@ rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, + rustc_do_not_const_check, rustc_dummy, rustc_dump_env_program_clauses, rustc_dump_program_clauses, @@ -1135,6 +1147,7 @@ rustc_synthetic, rustc_test_marker, rustc_then_this_would_need, + rustc_trivial_field_reads, rustc_unsafe_specialization_marker, rustc_variance, rustdoc, @@ -1148,7 +1161,6 @@ self_in_typedefs, self_struct_ctor, semitransparent, - send_trait, shl, shl_assign, should_panic, @@ -1211,6 +1223,7 @@ simd_select_bitmask, simd_shl, simd_shr, + simd_shuffle, simd_sub, simd_trunc, simd_xor, @@ -1257,7 +1270,6 @@ store, str, str_alloc, - string_type, stringify, struct_field_attributes, struct_inherit, @@ -1272,7 +1284,6 @@ suggestion, sym, sync, - sync_trait, t32, target_abi, target_arch, @@ -1318,9 +1329,7 @@ truncf64, try_blocks, try_from, - try_from_trait, try_into, - try_into_trait, try_trait_v2, tt, tuple, @@ -1392,8 +1401,6 @@ var, variant_count, vec, - vec_type, - vecdeque_type, version, vis, visible_private_types, @@ -1418,6 +1425,7 @@ wrapping_sub, wreg, write_bytes, + write_str, x87_reg, xer, xmm_reg, @@ -1612,7 +1620,7 @@ pub struct Symbol(SymbolIndex); rustc_index::newtype_index! { - pub struct SymbolIndex { .. } + struct SymbolIndex { .. } } impl Symbol { @@ -1622,14 +1630,15 @@ /// Maps a string to its interned representation. pub fn intern(string: &str) -> Self { - with_interner(|interner| interner.intern(string)) + with_session_globals(|session_globals| session_globals.symbol_interner.intern(string)) } /// Convert to a `SymbolStr`. This is a slowish operation because it /// requires locking the symbol interner. pub fn as_str(self) -> SymbolStr { - with_interner(|interner| unsafe { - SymbolStr { string: std::mem::transmute::<&str, &str>(interner.get(self)) } + with_session_globals(|session_globals| { + let symbol_str = session_globals.symbol_interner.get(self); + unsafe { SymbolStr { string: std::mem::transmute::<&str, &str>(symbol_str) } } }) } @@ -1637,10 +1646,6 @@ self.0.as_u32() } - pub fn len(self) -> usize { - with_interner(|interner| interner.get(self).len()) - } - pub fn is_empty(self) -> bool { self == kw::Empty } @@ -1695,13 +1700,19 @@ } } +#[derive(Default)] +pub(crate) struct Interner(Lock); + // The `&'static str`s in this type actually point into the arena. // // The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278 // found that to regress performance up to 2% in some cases. This might be // revisited after further improvements to `indexmap`. +// +// This type is private to prevent accidentally constructing more than one `Interner` on the same +// thread, which makes it easy to mixup `Symbol`s between `Interner`s. #[derive(Default)] -pub struct Interner { +struct InternerInner { arena: DroplessArena, names: FxHashMap<&'static str, Symbol>, strings: Vec<&'static str>, @@ -1709,37 +1720,38 @@ impl Interner { fn prefill(init: &[&'static str]) -> Self { - Interner { + Interner(Lock::new(InternerInner { strings: init.into(), names: init.iter().copied().zip((0..).map(Symbol::new)).collect(), ..Default::default() - } + })) } #[inline] - pub fn intern(&mut self, string: &str) -> Symbol { - if let Some(&name) = self.names.get(string) { + fn intern(&self, string: &str) -> Symbol { + let mut inner = self.0.lock(); + if let Some(&name) = inner.names.get(string) { return name; } - let name = Symbol::new(self.strings.len() as u32); + let name = Symbol::new(inner.strings.len() as u32); // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be // UTF-8. let string: &str = - unsafe { str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) }; + unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) }; // It is safe to extend the arena allocation to `'static` because we only access // these while the arena is still alive. let string: &'static str = unsafe { &*(string as *const str) }; - self.strings.push(string); - self.names.insert(string, name); + inner.strings.push(string); + inner.names.insert(string, name); name } // Get the symbol as a string. `Symbol::as_str()` should be used in // preference to this function. - pub fn get(&self, symbol: Symbol) -> &str { - self.strings[symbol.0.as_usize()] + fn get(&self, symbol: Symbol) -> &str { + self.0.lock().strings[symbol.0.as_usize()] } } @@ -1870,11 +1882,6 @@ } } -#[inline] -fn with_interner T>(f: F) -> T { - with_session_globals(|session_globals| f(&mut *session_globals.symbol_interner.lock())) -} - /// An alternative to [`Symbol`], useful when the chars within the symbol need to /// be accessed. It deliberately has limited functionality and should only be /// used for temporary values. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_symbol_mangling/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_symbol_mangling/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_symbol_mangling/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_symbol_mangling/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_symbol_mangling" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false @@ -16,4 +16,5 @@ rustc_hir = { path = "../rustc_hir" } rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_symbol_mangling/src/legacy.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_symbol_mangling/src/legacy.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_symbol_mangling/src/legacy.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_symbol_mangling/src/legacy.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::ich::NodeIdHashingMode; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::print::{PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_middle::util::common::record_time; +use rustc_query_system::ich::NodeIdHashingMode; use tracing::debug; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_symbol_mangling/src/test.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_symbol_mangling/src/test.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_symbol_mangling/src/test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_symbol_mangling/src/test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -23,7 +23,7 @@ tcx.dep_graph.with_ignore(|| { let mut visitor = SymbolNamesTest { tcx }; - tcx.hir().krate().visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes(&mut visitor); }) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_target" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] bitflags = "1.2.1" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/m68k.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/m68k.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/m68k.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/m68k.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +use crate::abi::call::{ArgAbi, FnAbi}; + +fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { + if ret.layout.is_aggregate() { + ret.make_indirect(); + } else { + ret.extend_integer_width_to(32); + } +} + +fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { + if arg.layout.is_aggregate() { + arg.make_indirect_byval(); + } else { + arg.extend_integer_width_to(32); + } +} + +pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { + if !fn_abi.ret.is_ignore() { + classify_ret(&mut fn_abi.ret); + } + + for arg in &mut fn_abi.args { + if arg.is_ignore() { + continue; + } + classify_arg(arg); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/mips64.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/mips64.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/mips64.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/mips64.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ fn extend_integer_width_mips(arg: &mut ArgAbi<'_, Ty>, bits: u64) { // Always sign extend u32 values on 64-bit mips - if let abi::Abi::Scalar(ref scalar) = arg.layout.abi { + if let abi::Abi::Scalar(scalar) = arg.layout.abi { if let abi::Int(i, signed) = scalar.value { if !signed && i.size().bits() == 32 { if let PassMode::Direct(ref mut attrs) = arg.mode { @@ -23,7 +23,7 @@ C: HasDataLayout, { match ret.layout.field(cx, i).abi { - abi::Abi::Scalar(ref scalar) => match scalar.value { + abi::Abi::Scalar(scalar) => match scalar.value { abi::F32 => Some(Reg::f32()), abi::F64 => Some(Reg::f64()), _ => None, @@ -107,7 +107,7 @@ let offset = arg.layout.fields.offset(i); // We only care about aligned doubles - if let abi::Abi::Scalar(ref scalar) = field.abi { + if let abi::Abi::Scalar(scalar) = field.abi { if let abi::F64 = scalar.value { if offset.is_aligned(dl.f64_align.abi) { // Insert enough integers to cover [last_offset, offset) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ use crate::abi::{self, Abi, Align, FieldsShape, Size}; use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout}; use crate::spec::{self, HasTargetSpec}; +use std::fmt; mod aarch64; mod amdgpu; @@ -8,6 +9,7 @@ mod avr; mod bpf; mod hexagon; +mod m68k; mod mips; mod mips64; mod msp430; @@ -24,7 +26,7 @@ mod x86_64; mod x86_win64; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum PassMode { /// Ignore the argument. /// @@ -59,7 +61,7 @@ mod attr_impl { // The subset of llvm::Attribute needed for arguments, packed into a bitfield. bitflags::bitflags! { - #[derive(Default)] + #[derive(Default, HashStable_Generic)] pub struct ArgAttribute: u16 { const NoAlias = 1 << 1; const NoCapture = 1 << 2; @@ -76,7 +78,7 @@ /// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum /// defines if this extension should be zero-extension or sign-extension when necessary. When it is /// not necessary to extend the argument, this enum is ignored. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum ArgExtension { None, Zext, @@ -85,7 +87,7 @@ /// A compact representation of LLVM attributes (at least those relevant for this module) /// that can be manipulated without interacting with LLVM's Attribute machinery. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct ArgAttributes { pub regular: ArgAttribute, pub arg_ext: ArgExtension, @@ -126,14 +128,14 @@ } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum RegKind { Integer, Float, Vector, } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct Reg { pub kind: RegKind, pub size: Size, @@ -183,7 +185,7 @@ /// An argument passed entirely registers with the /// same kind (e.g., HFA / HVA on PPC64 and AArch64). -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct Uniform { pub unit: Reg, @@ -208,7 +210,7 @@ } } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct CastTarget { pub prefix: [Option; 8], pub prefix_chunk_size: Size, @@ -322,7 +324,7 @@ Abi::Uninhabited => Err(Heterogeneous), // The primitive for this algorithm. - Abi::Scalar(ref scalar) => { + Abi::Scalar(scalar) => { let kind = match scalar.value { abi::Int(..) | abi::Pointer => RegKind::Integer, abi::F32 | abi::F64 => RegKind::Float, @@ -436,7 +438,7 @@ /// Information about how to pass an argument to, /// or return a value from, a function, under some ABI. -#[derive(Debug)] +#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct ArgAbi<'a, Ty> { pub layout: TyAndLayout<'a, Ty>, @@ -450,9 +452,9 @@ pub fn new( cx: &impl HasDataLayout, layout: TyAndLayout<'a, Ty>, - scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, &abi::Scalar, Size) -> ArgAttributes, + scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, abi::Scalar, Size) -> ArgAttributes, ) -> Self { - let mode = match &layout.abi { + let mode = match layout.abi { Abi::Uninhabited => PassMode::Ignore, Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)), Abi::ScalarPair(a, b) => PassMode::Pair( @@ -504,7 +506,7 @@ pub fn extend_integer_width_to(&mut self, bits: u64) { // Only integers have signedness - if let Abi::Scalar(ref scalar) = self.layout.abi { + if let Abi::Scalar(scalar) = self.layout.abi { if let abi::Int(i, signed) = scalar.value { if i.size().bits() < bits { if let PassMode::Direct(ref mut attrs) = self.mode { @@ -544,7 +546,7 @@ } } -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum Conv { // General language calling conventions, for which every target // should have its own backend (e.g. LLVM) support. @@ -578,7 +580,7 @@ /// /// I will do my best to describe this structure, but these /// comments are reverse-engineered and may be inaccurate. -NDM -#[derive(Debug)] +#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct FnAbi<'a, Ty> { /// The LLVM types of each argument. pub args: Vec>, @@ -599,8 +601,29 @@ pub can_unwind: bool, } +/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI. +#[derive(Clone, Debug, HashStable_Generic)] +pub enum AdjustForForeignAbiError { + /// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs. + Unsupported { arch: String, abi: spec::abi::Abi }, +} + +impl fmt::Display for AdjustForForeignAbiError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unsupported { arch, abi } => { + write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi) + } + } + } +} + impl<'a, Ty> FnAbi<'a, Ty> { - pub fn adjust_for_cabi(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String> + pub fn adjust_for_foreign_abi( + &mut self, + cx: &C, + abi: spec::abi::Abi, + ) -> Result<(), AdjustForForeignAbiError> where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, @@ -634,6 +657,7 @@ "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), "avr" => avr::compute_abi_info(self), + "m68k" => m68k::compute_abi_info(self), "mips" => mips::compute_abi_info(cx, self), "mips64" => mips64::compute_abi_info(cx, self), "powerpc" => powerpc::compute_abi_info(self), @@ -655,7 +679,9 @@ } "asmjs" => wasm::compute_c_abi_info(cx, self), "bpf" => bpf::compute_abi_info(self), - a => return Err(format!("unrecognized arch \"{}\" in target specification", a)), + arch => { + return Err(AdjustForForeignAbiError::Unsupported { arch: arch.to_string(), abi }); + } } Ok(()) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/riscv.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/riscv.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/riscv.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/riscv.rs 2021-11-29 19:27:11.000000000 +0000 @@ -44,7 +44,7 @@ Ty: TyAbiInterface<'a, C> + Copy, { match arg_layout.abi { - Abi::Scalar(ref scalar) => match scalar.value { + Abi::Scalar(scalar) => match scalar.value { abi::Int(..) | abi::Pointer => { if arg_layout.size.bits() > xlen { return Err(CannotUseFpConv); @@ -297,7 +297,7 @@ } fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) { - if let Abi::Scalar(ref scalar) = arg.layout.abi { + if let Abi::Scalar(scalar) = arg.layout.abi { if let abi::Int(i, _) = scalar.value { // 32-bit integers are always sign-extended if i.size().bits() == 32 && xlen > 32 { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/s390x.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/s390x.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/s390x.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/s390x.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ C: HasDataLayout, { match layout.abi { - abi::Abi::Scalar(ref scalar) => scalar.value.is_float(), + abi::Abi::Scalar(scalar) => scalar.value.is_float(), abi::Abi::Aggregate { .. } => { if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { is_single_fp_element(cx, layout.field(cx, 0)) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/x86_64.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/x86_64.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/x86_64.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/x86_64.rs 2021-11-29 19:27:11.000000000 +0000 @@ -49,7 +49,7 @@ let mut c = match layout.abi { Abi::Uninhabited => return Ok(()), - Abi::Scalar(ref scalar) => match scalar.value { + Abi::Scalar(scalar) => match scalar.value { abi::Int(..) | abi::Pointer => Class::Int, abi::F32 | abi::F64 => Class::Sse, }, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/x86.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/x86.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/x86.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/call/x86.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,7 +14,7 @@ C: HasDataLayout, { match layout.abi { - abi::Abi::Scalar(ref scalar) => scalar.value.is_float(), + abi::Abi::Scalar(scalar) => scalar.value.is_float(), abi::Abi::Aggregate { .. } => { if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { is_single_fp_element(cx, layout.field(cx, 0)) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/abi/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/abi/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,13 +7,12 @@ use std::fmt; use std::iter::Step; use std::num::NonZeroUsize; -use std::ops::{Add, AddAssign, Deref, Mul, Range, RangeInclusive, Sub}; +use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub}; use std::str::FromStr; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable_Generic; use rustc_serialize::json::{Json, ToJson}; -use rustc_span::Span; pub mod call; @@ -393,6 +392,21 @@ // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). (value << shift) >> shift } + + #[inline] + pub fn signed_int_min(&self) -> i128 { + self.sign_extend(1_u128 << (self.bits() - 1)) as i128 + } + + #[inline] + pub fn signed_int_max(&self) -> i128 { + i128::MAX >> (128 - self.bits()) + } + + #[inline] + pub fn unsigned_int_max(&self) -> u128 { + u128::MAX >> (128 - self.bits()) + } } // Panicking addition, subtraction and multiplication for convenience. @@ -740,9 +754,8 @@ /// /// 254 (-2), 255 (-1), 0, 1, 2 /// -/// This is intended specifically to mirror LLVM’s `!range` metadata, -/// semantics. -#[derive(Clone, PartialEq, Eq, Hash)] +/// This is intended specifically to mirror LLVM’s `!range` metadata semantics. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[derive(HashStable_Generic)] pub struct WrappingRange { pub start: u128, @@ -760,13 +773,6 @@ } } - /// Returns `true` if zero is contained in the range. - /// Equal to `range.contains(0)` but should be faster. - #[inline(always)] - pub fn contains_zero(&self) -> bool { - self.start > self.end || self.start == 0 - } - /// Returns `self` with replaced `start` #[inline(always)] pub fn with_start(mut self, start: u128) -> Self { @@ -780,17 +786,29 @@ self.end = end; self } + + /// Returns `true` if `size` completely fills the range. + #[inline] + pub fn is_full_for(&self, size: Size) -> bool { + let max_value = size.unsigned_int_max(); + debug_assert!(self.start <= max_value && self.end <= max_value); + self.start == (self.end.wrapping_add(1) & max_value) + } } impl fmt::Debug for WrappingRange { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{}..={}", self.start, self.end)?; + if self.start > self.end { + write!(fmt, "(..={}) | ({}..)", self.end, self.start)?; + } else { + write!(fmt, "{}..={}", self.start, self.end)?; + } Ok(()) } } /// Information about one scalar component of a Rust type. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[derive(HashStable_Generic)] pub struct Scalar { pub value: Primitive, @@ -804,25 +822,16 @@ impl Scalar { #[inline] pub fn is_bool(&self) -> bool { - matches!(self.value, Int(I8, false)) - && matches!(self.valid_range, WrappingRange { start: 0, end: 1 }) + matches!( + self, + Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } } + ) } - /// Returns the valid range as a `x..y` range. - /// - /// If `x` and `y` are equal, the range is full, not empty. - pub fn valid_range_exclusive(&self, cx: &C) -> Range { - // For a (max) value of -1, max will be `-1 as usize`, which overflows. - // However, that is fine here (it would still represent the full range), - // i.e., if the range is everything. - let bits = self.value.size(cx).bits(); - assert!(bits <= 128); - let mask = !0u128 >> (128 - bits); - let start = self.valid_range.start; - let end = self.valid_range.end; - assert_eq!(start, start & mask); - assert_eq!(end, end & mask); - start..(end.wrapping_add(1) & mask) + /// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole layout + #[inline] + pub fn is_always_valid(&self, cx: &C) -> bool { + self.valid_range.is_full_for(self.value.size(cx)) } } @@ -961,7 +970,7 @@ /// Describes how values of the type are passed by target ABIs, /// in terms of categories of C types there are ABI rules for. -#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum Abi { Uninhabited, Scalar(Scalar), @@ -989,8 +998,8 @@ /// Returns `true` if this is a single signed integer scalar #[inline] pub fn is_signed(&self) -> bool { - match *self { - Abi::Scalar(ref scal) => match scal.value { + match self { + Abi::Scalar(scal) => match scal.value { Primitive::Int(_, signed) => signed, _ => false, }, @@ -1059,7 +1068,7 @@ }, } -#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct Niche { pub offset: Size, pub scalar: Scalar, @@ -1072,10 +1081,10 @@ } pub fn available(&self, cx: &C) -> u128 { - let Scalar { value, valid_range: ref v } = self.scalar; - let bits = value.size(cx).bits(); - assert!(bits <= 128); - let max_value = !0u128 >> (128 - bits); + let Scalar { value, valid_range: v } = self.scalar; + let size = value.size(cx); + assert!(size.bits() <= 128); + let max_value = size.unsigned_int_max(); // Find out how many values are outside the valid range. let niche = v.end.wrapping_add(1)..v.start; @@ -1085,24 +1094,58 @@ pub fn reserve(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> { assert!(count > 0); - let Scalar { value, valid_range: v } = self.scalar.clone(); - let bits = value.size(cx).bits(); - assert!(bits <= 128); - let max_value = !0u128 >> (128 - bits); + let Scalar { value, valid_range: v } = self.scalar; + let size = value.size(cx); + assert!(size.bits() <= 128); + let max_value = size.unsigned_int_max(); - if count > max_value { + let niche = v.end.wrapping_add(1)..v.start; + let available = niche.end.wrapping_sub(niche.start) & max_value; + if count > available { return None; } - // Compute the range of invalid values being reserved. - let start = v.end.wrapping_add(1) & max_value; - let end = v.end.wrapping_add(count) & max_value; - - if v.contains(end) { - return None; + // Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound. + // Given an eventual `Option`, we try to maximize the chance for `None` to occupy the niche of zero. + // This is accomplished by prefering enums with 2 variants(`count==1`) and always taking the shortest path to niche zero. + // Having `None` in niche zero can enable some special optimizations. + // + // Bound selection criteria: + // 1. Select closest to zero given wrapping semantics. + // 2. Avoid moving past zero if possible. + // + // In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly. + // If niche zero is already reserved, the selection of bounds are of little interest. + let move_start = |v: WrappingRange| { + let start = v.start.wrapping_sub(count) & max_value; + Some((start, Scalar { value, valid_range: v.with_start(start) })) + }; + let move_end = |v: WrappingRange| { + let start = v.end.wrapping_add(1) & max_value; + let end = v.end.wrapping_add(count) & max_value; + Some((start, Scalar { value, valid_range: v.with_end(end) })) + }; + let distance_end_zero = max_value - v.end; + if v.start > v.end { + // zero is unavailable because wrapping occurs + move_end(v) + } else if v.start <= distance_end_zero { + if count <= v.start { + move_start(v) + } else { + // moved past zero, use other bound + move_end(v) + } + } else { + let end = v.end.wrapping_add(count) & max_value; + let overshot_zero = (1..=v.end).contains(&end); + if overshot_zero { + // moved past zero, use other bound + move_start(v) + } else { + move_end(v) + } } - - Some((start, Scalar { value, valid_range: v.with_end(end) })) } } @@ -1139,7 +1182,7 @@ impl Layout { pub fn scalar(cx: &C, scalar: Scalar) -> Self { - let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar.clone()); + let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let size = scalar.value.size(cx); let align = scalar.value.align(cx); Layout { @@ -1173,46 +1216,6 @@ } } -/// Trait for context types that can compute layouts of things. -pub trait LayoutOf<'a>: Sized { - type Ty: TyAbiInterface<'a, Self>; - type TyAndLayout: MaybeResult>; - - fn layout_of(&self, ty: Self::Ty) -> Self::TyAndLayout; - fn spanned_layout_of(&self, ty: Self::Ty, _span: Span) -> Self::TyAndLayout { - self.layout_of(ty) - } -} - -pub trait MaybeResult { - type Error; - - fn from(x: Result) -> Self; - fn to_result(self) -> Result; -} - -impl MaybeResult for T { - type Error = !; - - fn from(Ok(x): Result) -> Self { - x - } - fn to_result(self) -> Result { - Ok(self) - } -} - -impl MaybeResult for Result { - type Error = E; - - fn from(x: Result) -> Self { - x - } - fn to_result(self) -> Result { - self - } -} - #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PointerKind { /// Most general case, we know no restrictions to tell LLVM. @@ -1305,25 +1308,22 @@ Ty: TyAbiInterface<'a, C>, C: HasDataLayout, { - let scalar_allows_raw_init = move |s: &Scalar| -> bool { + let scalar_allows_raw_init = move |s: Scalar| -> bool { if zero { // The range must contain 0. - s.valid_range.contains_zero() + s.valid_range.contains(0) } else { - // The range must include all values. `valid_range_exclusive` handles - // the wrap-around using target arithmetic; with wrap-around then the full - // range is one where `start == end`. - let range = s.valid_range_exclusive(cx); - range.start == range.end + // The range must include all values. + s.is_always_valid(cx) } }; // Check the ABI. - let valid = match &self.abi { + let valid = match self.abi { Abi::Uninhabited => false, // definitely UB Abi::Scalar(s) => scalar_allows_raw_init(s), Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), - Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s), + Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), Abi::Aggregate { .. } => true, // Fields are checked below. }; if !valid { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,7 +15,6 @@ #![feature(exhaustive_patterns)] #![feature(min_specialization)] #![feature(step_trait)] -#![feature(unchecked_math)] use std::path::{Path, PathBuf}; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,9 @@ let mut base = super::apple_base::opts("macos"); base.cpu = "apple-a12".to_string(); base.max_atomic_width = Some(128); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; + + // FIXME: The leak sanitizer currently fails the tests, see #88132. + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]); base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "aarch64-unknown-none".to_string(), + pointer_width: 64, + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), + arch: "aarch64".to_string(), + options: TargetOptions { + linker: Some("aarch64-kmc-elf-gcc".to_owned()), + features: "+neon,+fp-armv8".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(128), + ..base + }, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/android_base.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/android_base.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/android_base.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/android_base.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ use crate::spec::{LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let mut base = super::linux_gnu_base::opts(); + let mut base = super::linux_base::opts(); base.os = "android".to_string(); // Many of the symbols defined in compiler-rt are also defined in libgcc. // Android's linker doesn't like that by default. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,43 @@ +use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions}; + +/// A base target for Nintendo 3DS devices using the devkitARM toolchain. +/// +/// Requires the devkitARM toolchain for 3DS targets on the host system. + +pub fn target() -> Target { + let mut pre_link_args = LinkArgs::new(); + pre_link_args.insert( + LinkerFlavor::Gcc, + vec![ + "-specs=3dsx.specs".to_string(), + "-mtune=mpcore".to_string(), + "-mfloat-abi=hard".to_string(), + "-mtp=soft".to_string(), + ], + ); + + Target { + llvm_target: "armv6k-none-eabihf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + + options: TargetOptions { + os: "horizon".to_string(), + env: "newlib".to_string(), + vendor: "nintendo".to_string(), + abi: "eabihf".to_string(), + linker_flavor: LinkerFlavor::Gcc, + cpu: "mpcore".to_string(), + executables: true, + families: vec!["unix".to_string()], + linker: Some("arm-none-eabi-gcc".to_string()), + relocation_model: RelocModel::Static, + features: "+vfp2".to_string(), + pre_link_args, + exe_suffix: ".elf".to_string(), + panic_strategy: PanicStrategy::Abort, + ..Default::default() + }, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "armv7a-none-eabihf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + options: TargetOptions { + linker: Some("arm-kmc-eabi-gcc".to_owned()), + features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + ..base + }, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "armv7a-none-eabi".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + options: TargetOptions { + linker: Some("arm-kmc-eabi-gcc".to_owned()), + features: "+v7,+soft-float,+thumb2,-neon".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + ..base + }, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ +use crate::spec::{Target, TargetOptions}; + +// This target is for uclibc Linux on ARMv7 without NEON or +// thumb-mode. See the thumbv7neon variant for enabling both. + +pub fn target() -> Target { + let base = super::linux_uclibc_base::opts(); + Target { + llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + + options: TargetOptions { + // Info about features at https://wiki.debian.org/ArmHardFloatPort + features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(), + cpu: "generic".to_string(), + max_atomic_width: Some(64), + mcount: "_mcount".to_string(), + abi: "eabihf".to_string(), + ..base + }, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +use crate::abi::Endian; +use crate::spec::{Target, TargetOptions}; + +pub fn target() -> Target { + let mut base = super::linux_base::opts(); + base.max_atomic_width = Some(32); + + Target { + llvm_target: "m68k-unknown-linux-gnu".to_string(), + pointer_width: 32, + data_layout: "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16".to_string(), + arch: "m68k".to_string(), + options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base }, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -75,6 +75,7 @@ mod openbsd_base; mod redox_base; mod solaris_base; +mod solid_base; mod thumb_base; mod uefi_msvc_base; mod vxworks_base; @@ -287,6 +288,7 @@ pub enum RelocModel { Static, Pic, + Pie, DynamicNoPic, Ropi, Rwpi, @@ -300,6 +302,7 @@ Ok(match s { "static" => RelocModel::Static, "pic" => RelocModel::Pic, + "pie" => RelocModel::Pie, "dynamic-no-pic" => RelocModel::DynamicNoPic, "ropi" => RelocModel::Ropi, "rwpi" => RelocModel::Rwpi, @@ -314,6 +317,7 @@ match *self { RelocModel::Static => "static", RelocModel::Pic => "pic", + RelocModel::Pie => "pie", RelocModel::DynamicNoPic => "dynamic-no-pic", RelocModel::Ropi => "ropi", RelocModel::Rwpi => "rwpi", @@ -742,6 +746,7 @@ ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32), ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), + ("m68k-unknown-linux-gnu", m68k_unknown_linux_gnu), ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64), @@ -931,6 +936,10 @@ ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe), ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks), + ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3), + ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi), + ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf), + ("mipsel-sony-psp", mipsel_sony_psp), ("mipsel-unknown-none", mipsel_unknown_none), ("thumbv4t-none-eabi", thumbv4t_none_eabi), @@ -941,6 +950,10 @@ ("bpfeb-unknown-none", bpfeb_unknown_none), ("bpfel-unknown-none", bpfel_unknown_none), + + ("armv6k-nintendo-3ds", armv6k_nintendo_3ds), + + ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf), } /// Warnings encountered when parsing the target `json`. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/solid_base.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/solid_base.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_target/src/spec/solid_base.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_target/src/spec/solid_base.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +use super::FramePointer; +use crate::spec::TargetOptions; + +pub fn opts(kernel: &str) -> TargetOptions { + TargetOptions { + os: format!("solid_{}", kernel), + vendor: "kmc".to_string(), + frame_pointer: FramePointer::NonLeaf, + has_elf_tls: true, + ..Default::default() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_traits" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] tracing = "0.1" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/src/chalk/lowering.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/src/chalk/lowering.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/src/chalk/lowering.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/src/chalk/lowering.rs 2021-11-29 19:27:11.000000000 +0000 @@ -892,7 +892,7 @@ match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { ty::BoundRegionKind::BrNamed(def_id, _name) => { - if self.named_parameters.iter().find(|d| **d == def_id).is_none() { + if !self.named_parameters.iter().any(|d| *d == def_id) { self.named_parameters.push(def_id); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/src/implied_outlives_bounds.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/src/implied_outlives_bounds.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/src/implied_outlives_bounds.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/src/implied_outlives_bounds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,14 +4,14 @@ use rustc_hir as hir; use rustc_infer::infer::canonical::{self, Canonical}; +use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::TraitEngineExt as _; -use rustc_middle::ty::outlives::Component; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::outlives_bounds::OutlivesBound; use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; use rustc_trait_selection::traits::wf; use rustc_trait_selection::traits::FulfillmentContext; @@ -118,7 +118,7 @@ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => { let ty_a = infcx.resolve_vars_if_possible(ty_a); let mut components = smallvec![]; - tcx.push_outlives_components(ty_a, &mut components); + push_outlives_components(tcx, ty_a, &mut components); implied_bounds_from_components(r_b, components) } }, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -19,7 +19,7 @@ mod normalize_projection_ty; mod type_op; -pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span}; +pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use rustc_middle::ty::query::Providers; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/src/type_op.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/src/type_op.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_traits/src/type_op.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_traits/src/type_op.rs 2021-11-29 19:27:11.000000000 +0000 @@ -156,7 +156,8 @@ self.relate(self_ty, Variance::Invariant, impl_self_ty)?; self.prove_predicate( - ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())) + .to_predicate(self.tcx()), span, ); } @@ -173,7 +174,7 @@ // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... self.prove_predicate( - ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()), span, ); Ok(()) @@ -256,7 +257,7 @@ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { - type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None); + type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy()); Ok(()) }) } @@ -264,17 +265,12 @@ /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. -pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>( +pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>( infcx: &'a InferCtxt<'a, 'tcx>, fulfill_cx: &'a mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, - span: Option, + cause: ObligationCause<'tcx>, ) { - let cause = if let Some(span) = span { - ObligationCause::dummy_with_span(span) - } else { - ObligationCause::dummy() - }; let (param_env, ProvePredicate { predicate }) = key.into_parts(); fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate)); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_trait_selection" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false @@ -17,7 +17,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } +rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/autoderef.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/autoderef.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/autoderef.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/autoderef.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc_middle::ty::{ToPredicate, TypeFoldable}; -use rustc_session::DiagnosticMessageId; +use rustc_session::{DiagnosticMessageId, Limit}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::Span; @@ -135,7 +135,7 @@ let obligation = traits::Obligation::new( cause.clone(), self.param_env, - trait_ref.without_const().to_predicate(tcx), + ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), ); if !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); @@ -217,7 +217,10 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { // We've reached the recursion limit, error gracefully. - let suggested_limit = tcx.recursion_limit() * 2; + let suggested_limit = match tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); @@ -231,7 +234,8 @@ ) .span_label(span, "deref recursion limit reached") .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", suggested_limit, tcx.crate_name(LOCAL_CRATE), )) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/infer.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/infer.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/infer.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/infer.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,8 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::query::outlives_bounds::InferCtxtExt as _; use crate::traits::{self, TraitEngine, TraitEngineExt}; -use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::traits::ObligationCause; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse}; @@ -119,7 +116,7 @@ cause: traits::ObligationCause::dummy(), param_env, recursion_depth: 0, - predicate: trait_ref.without_const().to_predicate(self.tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx), }; self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) } @@ -179,48 +176,3 @@ ) } } - -pub trait OutlivesEnvironmentExt<'tcx> { - fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: &[Ty<'tcx>], - body_id: hir::HirId, - span: Span, - ); -} - -impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { - /// This method adds "implied bounds" into the outlives environment. - /// Implied bounds are outlives relationships that we can deduce - /// on the basis that certain types must be well-formed -- these are - /// either the types that appear in the function signature or else - /// the input types to an impl. For example, if you have a function - /// like - /// - /// ``` - /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } - /// ``` - /// - /// we can assume in the caller's body that `'b: 'a` and that `T: - /// 'b` (and hence, transitively, that `T: 'a`). This method would - /// add those assumptions into the outlives-environment. - /// - /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs` - fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: &[Ty<'tcx>], - body_id: hir::HirId, - span: Span, - ) { - debug!("add_implied_bounds()"); - - for &ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(ty); - debug!("add_implied_bounds: ty = {}", ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); - self.add_outlives_bounds(Some(infcx), implied_bounds) - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/opaque_types.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/opaque_types.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/opaque_types.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/opaque_types.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -use crate::infer::InferCtxtExt as _; use crate::traits::{self, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -499,7 +498,7 @@ /// - `substs`, the substs used to instantiate this opaque type /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of /// `opaque_defn.concrete_ty` - #[instrument(skip(self))] + #[instrument(level = "debug", skip(self))] fn infer_opaque_definition_from_instantiation( &self, opaque_type_key: OpaqueTypeKey<'tcx>, @@ -518,6 +517,7 @@ debug!(?id_substs); let map: FxHashMap, GenericArg<'tcx>> = substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); + debug!("map = {:#?}", map); // Convert the type from the function into a type valid outside // the function, by replacing invalid regions with 'static, @@ -673,6 +673,7 @@ self.tcx } + #[instrument(skip(self), level = "debug")] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r { // Ignore bound regions and `'static` regions that appear in the @@ -863,7 +864,6 @@ } impl<'a, 'tcx> Instantiator<'a, 'tcx> { - #[instrument(skip(self))] fn instantiate_opaque_types_in_map>(&mut self, value: T) -> T { let tcx = self.infcx.tcx; value.fold_with(&mut BottomUpFolder { @@ -954,6 +954,7 @@ }) } + #[instrument(skip(self), level = "debug")] fn fold_opaque_ty( &mut self, ty: Ty<'tcx>, @@ -964,25 +965,18 @@ let tcx = infcx.tcx; let OpaqueTypeKey { def_id, substs } = opaque_type_key; - debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs); - // Use the same type variable if the exact same opaque type appears more // than once in the return type (e.g., if it's passed to a type alias). if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) { - debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty); + debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind()); return opaque_defn.concrete_ty; } + let ty_var = infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span: self.value_span, }); - // Make sure that we are in fact defining the *entire* type - // (e.g., `type Foo = impl Bar;` needs to be - // defined by a function like `fn foo() -> Foo`). - debug!("instantiate_opaque_types: param_env={:#?}", self.param_env,); - debug!("instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id),); - // Ideally, we'd get the span where *this specific `ty` came // from*, but right now we just use the span from the overall // value being folded. In simple cases like `-> impl Foo`, @@ -999,43 +993,40 @@ infcx.opaque_types_vars.insert(ty_var, ty); } - debug!("instantiate_opaque_types: ty_var={:?}", ty_var); - self.compute_opaque_type_obligations(opaque_type_key); - - ty_var - } - - fn compute_opaque_type_obligations(&mut self, opaque_type_key: OpaqueTypeKey<'tcx>) { - let infcx = self.infcx; - let tcx = infcx.tcx; - let OpaqueTypeKey { def_id, substs } = opaque_type_key; + debug!("generated new type inference var {:?}", ty_var.kind()); let item_bounds = tcx.explicit_item_bounds(def_id); - debug!("instantiate_opaque_types: bounds={:#?}", item_bounds); - let bounds: Vec<_> = - item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect(); - - let param_env = tcx.param_env(def_id); - let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in( - ObligationCause::misc(self.value_span, self.body_id), - param_env, - bounds, - ); - self.obligations.extend(obligations); - debug!("instantiate_opaque_types: bounds={:?}", bounds); + self.obligations.reserve(item_bounds.len()); + for (predicate, _) in item_bounds { + debug!(?predicate); + let predicate = predicate.subst(tcx, substs); + debug!(?predicate); + + // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them. + let predicate = predicate.fold_with(&mut BottomUpFolder { + tcx, + ty_op: |ty| match ty.kind() { + ty::Projection(projection_ty) => infcx.infer_projection( + self.param_env, + *projection_ty, + ObligationCause::misc(self.value_span, self.body_id), + 0, + &mut self.obligations, + ), + _ => ty, + }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }); + debug!(?predicate); - for predicate in &bounds { if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() { if projection.ty.references_error() { // No point on adding these obligations since there's a type error involved. - return; + return tcx.ty_error(); } } - } - - self.obligations.reserve(bounds.len()); - for predicate in bounds { // Change the predicate to refer to the type variable, // which will be the concrete type instead of the opaque type. // This also instantiates nested instances of `impl Trait`. @@ -1045,9 +1036,11 @@ traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType); // Require that the predicate holds for the concrete type. - debug!("instantiate_opaque_types: predicate={:?}", predicate); + debug!(?predicate); self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate)); } + + ty_var } } @@ -1071,11 +1064,7 @@ /// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`), /// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`. /// For the above example, this function returns `true` for `f1` and `false` for `f2`. -pub fn may_define_opaque_type( - tcx: TyCtxt<'_>, - def_id: LocalDefId, - opaque_hir_id: hir::HirId, -) -> bool { +fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool { let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id); // Named opaque types can be defined by any siblings or children of siblings. @@ -1111,18 +1100,17 @@ /// /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. +#[instrument(skip(tcx, predicates), level = "debug")] crate fn required_region_bounds( tcx: TyCtxt<'tcx>, erased_self_ty: Ty<'tcx>, predicates: impl Iterator>, ) -> Vec> { - debug!("required_region_bounds(erased_self_ty={:?})", erased_self_ty); - assert!(!erased_self_ty.has_escaping_bound_vars()); traits::elaborate_predicates(tcx, predicates) .filter_map(|obligation| { - debug!("required_region_bounds(obligation={:?})", obligation); + debug!(?obligation); match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Projection(..) | ty::PredicateKind::Trait(..) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,16 +7,21 @@ ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, PredicateObligation, SelectionError, TraitEngine, }; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_middle::ty::{self, Ty}; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet>, + + relationships: FxHashMap, } impl FulfillmentContext<'tcx> { crate fn new() -> Self { - FulfillmentContext { obligations: FxIndexSet::default() } + FulfillmentContext { + obligations: FxIndexSet::default(), + relationships: FxHashMap::default(), + } } } @@ -39,6 +44,8 @@ assert!(!infcx.is_in_snapshot()); let obligation = infcx.resolve_vars_if_possible(obligation); + super::relationships::update(self, infcx, &obligation); + self.obligations.insert(obligation); } @@ -57,7 +64,6 @@ .map(|obligation| FulfillmentError { obligation: obligation.clone(), code: FulfillmentErrorCode::CodeAmbiguity, - points_at_arg_span: false, // FIXME - does Chalk have a notation of 'root obligation'? // This is just for diagnostics, so it's okay if this is wrong root_obligation: obligation.clone(), @@ -112,7 +118,6 @@ code: FulfillmentErrorCode::CodeSelectionError( SelectionError::Unimplemented, ), - points_at_arg_span: false, // FIXME - does Chalk have a notation of 'root obligation'? // This is just for diagnostics, so it's okay if this is wrong root_obligation: obligation, @@ -129,7 +134,6 @@ code: FulfillmentErrorCode::CodeSelectionError( SelectionError::Unimplemented, ), - points_at_arg_span: false, // FIXME - does Chalk have a notation of 'root obligation'? // This is just for diagnostics, so it's okay if this is wrong root_obligation: obligation, @@ -149,4 +153,8 @@ fn pending_obligations(&self) -> Vec> { self.obligations.iter().cloned().collect() } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,16 +6,16 @@ //! this is not as easy. //! //! In this case we try to build an abstract representation of this constant using -//! `mir_abstract_const` which can then be checked for structural equality with other +//! `thir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; -use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; -use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable}; +use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; +use rustc_middle::thir; +use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; @@ -196,7 +196,7 @@ tcx: TyCtxt<'tcx>, uv: ty::Unevaluated<'tcx, ()>, ) -> Result>, ErrorReported> { - let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?; + let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?; debug!("AbstractConst::new({:?}) = {:?}", uv, inner); Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) })) } @@ -223,36 +223,36 @@ } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct WorkNode<'tcx> { - node: Node<'tcx>, - span: Span, - used: bool, -} - struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, + body_id: thir::ExprId, + body: &'a thir::Thir<'tcx>, /// The current WIP node tree. - /// - /// We require all nodes to be used in the final abstract const, - /// so we store this here. Note that we also consider nodes as used - /// if they are mentioned in an assert, so some used nodes are never - /// actually reachable by walking the [`AbstractConst`]. - nodes: IndexVec>, - locals: IndexVec, - /// We only allow field accesses if they access - /// the result of a checked operation. - checked_op_locals: BitSet, + nodes: IndexVec>, } impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { - fn error(&mut self, span: Option, msg: &str) -> Result { + fn root_span(&self) -> Span { + self.body.exprs[self.body_id].span + } + + fn error(&mut self, span: Span, msg: &str) -> Result { + self.tcx + .sess + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span, msg) + .help("consider moving this anonymous constant into a `const` function") + .emit(); + + Err(ErrorReported) + } + fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result { self.tcx .sess - .struct_span_err(self.body.span, "overly complex generic constant") - .span_label(span.unwrap_or(self.body.span), msg) + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span, msg) .help("consider moving this anonymous constant into a `const` function") + .note("this operation may be supported in the future") .emit(); Err(ErrorReported) @@ -260,98 +260,49 @@ fn new( tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, + (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId), ) -> Result>, ErrorReported> { - let mut builder = AbstractConstBuilder { - tcx, - body, - nodes: IndexVec::new(), - locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls), - checked_op_locals: BitSet::new_empty(body.local_decls.len()), - }; - - // We don't have to look at concrete constants, as we - // can just evaluate them. - if !body.is_polymorphic { - return Ok(None); - } + let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() }; - // We only allow consts without control flow, so - // we check for cycles here which simplifies the - // rest of this implementation. - if body.is_cfg_cyclic() { - builder.error(None, "cyclic anonymous constants are forbidden")?; + struct IsThirPolymorphic<'a, 'tcx> { + is_poly: bool, + thir: &'a thir::Thir<'tcx>, + tcx: TyCtxt<'tcx>, } - Ok(Some(builder)) - } + use thir::visit; + impl<'a, 'tcx: 'a> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { + fn thir(&self) -> &'a thir::Thir<'tcx> { + &self.thir + } - fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId { - // Mark used nodes. - match node { - Node::Leaf(_) => (), - Node::Binop(_, lhs, rhs) => { - self.nodes[lhs].used = true; - self.nodes[rhs].used = true; - } - Node::UnaryOp(_, input) => { - self.nodes[input].used = true; - } - Node::FunctionCall(func, nodes) => { - self.nodes[func].used = true; - nodes.iter().for_each(|&n| self.nodes[n].used = true); - } - Node::Cast(_, operand, _) => { - self.nodes[operand].used = true; + fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { + self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx); + if !self.is_poly { + visit::walk_expr(self, expr) + } + } + + fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) { + self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx); + if !self.is_poly { + visit::walk_pat(self, pat); + } } - } - // Nodes start as unused. - self.nodes.push(WorkNode { node, span, used: false }) - } - - fn place_to_local( - &mut self, - span: Span, - p: &mir::Place<'tcx>, - ) -> Result { - const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); - // Do not allow any projections. - // - // One exception are field accesses on the result of checked operations, - // which are required to support things like `1 + 2`. - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - Ok(p) - } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { - // Only allow field accesses if the given local - // contains the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - Ok(p.local) - } else { - self.error(Some(span), "unsupported projection")?; - } - } else { - self.error(Some(span), "unsupported projection")?; + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) { + self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx); + } } - } - fn operand_to_node( - &mut self, - span: Span, - op: &mir::Operand<'tcx>, - ) -> Result { - debug!("operand_to_node: op={:?}", op); - match op { - mir::Operand::Copy(p) | mir::Operand::Move(p) => { - let local = self.place_to_local(span, p)?; - Ok(self.locals[local]) - } - mir::Operand::Constant(ct) => match ct.literal { - mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)), - mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?, - }, + let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx }; + visit::walk_expr(&mut is_poly_vis, &body[body_id]); + debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly); + if !is_poly_vis.is_poly { + return Ok(None); } + + Ok(Some(builder)) } /// We do not allow all binary operations in abstract consts, so filter disallowed ones. @@ -373,170 +324,166 @@ } } - fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> { - debug!("AbstractConstBuilder: stmt={:?}", stmt); - let span = stmt.source_info.span; - match stmt.kind { - StatementKind::Assign(box (ref place, ref rvalue)) => { - let local = self.place_to_local(span, place)?; - match *rvalue { - Rvalue::Use(ref operand) => { - self.locals[local] = self.operand_to_node(span, operand)?; - Ok(()) - } - Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) if Self::check_binop(op) => { - let lhs = self.operand_to_node(span, lhs)?; - let rhs = self.operand_to_node(span, rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); - if op.is_checkable() { - bug!("unexpected unchecked checkable binary operation"); - } else { - Ok(()) - } - } - Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) - if Self::check_binop(op) => - { - let lhs = self.operand_to_node(span, lhs)?; - let rhs = self.operand_to_node(span, rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); - self.checked_op_locals.insert(local); - Ok(()) - } - Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { - let operand = self.operand_to_node(span, operand)?; - self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span); - Ok(()) - } - Rvalue::Cast(cast_kind, ref operand, ty) => { - let operand = self.operand_to_node(span, operand)?; - self.locals[local] = - self.add_node(Node::Cast(cast_kind, operand, ty), span); - Ok(()) - } - _ => self.error(Some(span), "unsupported rvalue")?, - } - } - // These are not actually relevant for us here, so we can ignore them. - StatementKind::AscribeUserType(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) => Ok(()), - _ => self.error(Some(stmt.source_info.span), "unsupported statement")?, - } - } - - /// Possible return values: - /// - /// - `None`: unsupported terminator, stop building - /// - `Some(None)`: supported terminator, finish building - /// - `Some(Some(block))`: support terminator, build `block` next - fn build_terminator( - &mut self, - terminator: &mir::Terminator<'tcx>, - ) -> Result, ErrorReported> { - debug!("AbstractConstBuilder: terminator={:?}", terminator); - match terminator.kind { - TerminatorKind::Goto { target } => Ok(Some(target)), - TerminatorKind::Return => Ok(None), - TerminatorKind::Call { - ref func, - ref args, - destination: Some((ref place, target)), - // We do not care about `cleanup` here. Any branch which - // uses `cleanup` will fail const-eval and they therefore - // do not matter when checking for const evaluatability. - // - // Do note that even if `panic::catch_unwind` is made const, - // we still do not have to care about this, as we do not look - // into functions. - cleanup: _, - // Do not allow overloaded operators for now, - // we probably do want to allow this in the future. - // - // This is currently fairly irrelevant as it requires `const Trait`s. - from_hir_call: true, - fn_span, - } => { - let local = self.place_to_local(fn_span, place)?; - let func = self.operand_to_node(fn_span, func)?; - let args = self.tcx.arena.alloc_from_iter( - args.iter() - .map(|arg| self.operand_to_node(terminator.source_info.span, arg)) - .collect::, _>>()?, - ); - self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span); - Ok(Some(target)) - } - TerminatorKind::Assert { ref cond, expected: false, target, .. } => { - let p = match cond { - mir::Operand::Copy(p) | mir::Operand::Move(p) => p, - mir::Operand::Constant(_) => bug!("unexpected assert"), - }; - - const ONE_FIELD: mir::Field = mir::Field::from_usize(1); - debug!("proj: {:?}", p.projection); - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - // Mark locals directly used in asserts as used. - // - // This is needed because division does not use `CheckedBinop` but instead - // adds an explicit assert for `divisor != 0`. - self.nodes[self.locals[p]].used = true; - return Ok(Some(target)); - } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { - // Only allow asserts checking the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - return Ok(Some(target)); - } - } - - self.error(Some(terminator.source_info.span), "unsupported assertion")?; - } - _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?, - } - } - - /// Builds the abstract const by walking the mir from start to finish - /// and bailing out when encountering an unsupported operation. + /// Builds the abstract const by walking the thir and bailing out when + /// encountering an unspported operation. fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> { - let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; - // We checked for a cyclic cfg above, so this should terminate. - loop { - debug!("AbstractConstBuilder: block={:?}", block); - for stmt in block.statements.iter() { - self.build_statement(stmt)?; - } - - if let Some(next) = self.build_terminator(block.terminator())? { - block = &self.body.basic_blocks()[next]; - } else { - break; - } - } + debug!("Abstractconstbuilder::build: body={:?}", &*self.body); + self.recurse_build(self.body_id)?; - assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap()); for n in self.nodes.iter() { - if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node { + if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n { // `AbstractConst`s should not contain any promoteds as they require references which // are not allowed. assert_eq!(ct.promoted, None); } } - self.nodes[self.locals[mir::RETURN_PLACE]].used = true; - if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { - self.error(Some(unused.span), "dead code")?; - } + Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter())) + } - Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node))) + fn recurse_build(&mut self, node: thir::ExprId) -> Result { + use thir::ExprKind; + let node = &self.body.exprs[node]; + debug!("recurse_build: node={:?}", node); + Ok(match &node.kind { + // I dont know if handling of these 3 is correct + &ExprKind::Scope { value, .. } => self.recurse_build(value)?, + &ExprKind::PlaceTypeAscription { source, .. } + | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + + // subtle: associated consts are literals this arm handles + // `::ASSOC` as well as `12` + &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)), + + ExprKind::Call { fun, args, .. } => { + let fun = self.recurse_build(*fun)?; + + let mut new_args = Vec::::with_capacity(args.len()); + for &id in args.iter() { + new_args.push(self.recurse_build(id)?); + } + let new_args = self.tcx.arena.alloc_slice(&new_args); + self.nodes.push(Node::FunctionCall(fun, new_args)) + } + &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { + let lhs = self.recurse_build(lhs)?; + let rhs = self.recurse_build(rhs)?; + self.nodes.push(Node::Binop(op, lhs, rhs)) + } + &ExprKind::Unary { op, arg } if Self::check_unop(op) => { + let arg = self.recurse_build(arg)?; + self.nodes.push(Node::UnaryOp(op, arg)) + } + // This is necessary so that the following compiles: + // + // ``` + // fn foo(a: [(); N + 1]) { + // bar::<{ N + 1 }>(); + // } + // ``` + ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => { + self.recurse_build(*e)? + } + // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a + // "coercion cast" i.e. using a coercion or is a no-op. + // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) + &ExprKind::Use { source } => { + let arg = self.recurse_build(source)?; + self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty)) + } + &ExprKind::Cast { source } => { + let arg = self.recurse_build(source)?; + self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty)) + } + + // FIXME(generic_const_exprs): We may want to support these. + ExprKind::AddressOf { .. } + | ExprKind::Borrow { .. } + | ExprKind::Deref { .. } => self.maybe_supported_error( + node.span, + "dereferencing is not supported in generic constants", + )?, + ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( + node.span, + "array construction is not supported in generic constants", + )?, + ExprKind::Block { .. } => self.maybe_supported_error( + node.span, + "blocks are not supported in generic constant", + )?, + ExprKind::NeverToAny { .. } => self.maybe_supported_error( + node.span, + "converting nevers to any is not supported in generic constant", + )?, + ExprKind::Tuple { .. } => self.maybe_supported_error( + node.span, + "tuple construction is not supported in generic constants", + )?, + ExprKind::Index { .. } => self.maybe_supported_error( + node.span, + "indexing is not supported in generic constant", + )?, + ExprKind::Field { .. } => self.maybe_supported_error( + node.span, + "field access is not supported in generic constant", + )?, + ExprKind::ConstBlock { .. } => self.maybe_supported_error( + node.span, + "const blocks are not supported in generic constant", + )?, + ExprKind::Adt(_) => self.maybe_supported_error( + node.span, + "struct/enum construction is not supported in generic constants", + )?, + // dont know if this is correct + ExprKind::Pointer { .. } => + self.error(node.span, "pointer casts are not allowed in generic constants")?, + ExprKind::Yield { .. } => + self.error(node.span, "generator control flow is not allowed in generic constants")?, + ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self + .error( + node.span, + "loops and loop control flow are not supported in generic constants", + )?, + ExprKind::Box { .. } => + self.error(node.span, "allocations are not allowed in generic constants")?, + + ExprKind::Unary { .. } => unreachable!(), + // we handle valid unary/binary ops above + ExprKind::Binary { .. } => + self.error(node.span, "unsupported binary operation in generic constants")?, + ExprKind::LogicalOp { .. } => + self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?, + ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { + self.error(node.span, "assignment is not supported in generic constants")? + } + ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error( + node.span, + "closures and function keywords are not supported in generic constants", + )?, + // let expressions imply control flow + ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => + self.error(node.span, "control flow is not supported in generic constants")?, + ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => { + self.error(node.span, "assembly is not supported in generic constants")? + } + + // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen + ExprKind::VarRef { .. } + | ExprKind::UpvarRef { .. } + | ExprKind::StaticRef { .. } + | ExprKind::ThreadLocalRef(_) => { + self.error(node.span, "unsupported operation in generic constant")? + } + }) } } /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. -pub(super) fn mir_abstract_const<'tcx>( +pub(super) fn thir_abstract_const<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, -) -> Result]>, ErrorReported> { +) -> Result]>, ErrorReported> { if tcx.features().generic_const_exprs { match tcx.def_kind(def.did) { // FIXME(generic_const_exprs): We currently only do this for anonymous constants, @@ -547,8 +494,16 @@ DefKind::AnonConst => (), _ => return Ok(None), } - let body = tcx.mir_const(def).borrow(); - AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose() + + let body = tcx.thir_body(def); + if body.0.borrow().exprs.is_empty() { + // type error in constant, there is no thir + return Err(ErrorReported); + } + + AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))? + .map(AbstractConstBuilder::build) + .transpose() } else { Ok(None) } @@ -682,11 +637,16 @@ && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } - (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty)) - if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) => + (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) + if (a_ty == b_ty) && (a_kind == b_kind) => { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } - _ => false, + // use this over `_ => false` to make adding variants to `Node` less error prone + (Node::Cast(..), _) + | (Node::FunctionCall(..), _) + | (Node::UnaryOp(..), _) + | (Node::Binop(..), _) + | (Node::Leaf(..), _) => false, } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -19,7 +19,7 @@ use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{ @@ -66,7 +66,6 @@ root_obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, fallback_has_occurred: bool, - points_at_arg: bool, ); /// Given some node representing a fn-like thing in the HIR map, @@ -237,7 +236,6 @@ root_obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, fallback_has_occurred: bool, - points_at_arg: bool, ) { let tcx = self.tcx; let mut span = obligation.cause.span; @@ -249,10 +247,10 @@ if let ObligationCauseCode::WellFormed(Some(wf_loc)) = root_obligation.cause.code.peel_derives() { - if let Some(cause) = self.tcx.diagnostic_hir_wf_check(( - tcx.erase_regions(obligation.predicate), - wf_loc.clone(), - )) { + if let Some(cause) = self + .tcx + .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc)) + { obligation.cause = cause; span = obligation.cause.span; } @@ -387,7 +385,6 @@ &obligation, &mut err, &trait_ref, - points_at_arg, have_alt_message, ) { self.note_obligation_cause(&mut err, &obligation); @@ -430,8 +427,8 @@ err.span_label(enclosing_scope_span, s.as_str()); } - self.suggest_dereferences(&obligation, &mut err, trait_ref, points_at_arg); - self.suggest_fn_call(&obligation, &mut err, trait_ref, points_at_arg); + self.suggest_dereferences(&obligation, &mut err, trait_ref); + self.suggest_fn_call(&obligation, &mut err, trait_ref); self.suggest_remove_reference(&obligation, &mut err, trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref); self.note_version_mismatch(&mut err, &trait_ref); @@ -500,12 +497,7 @@ // Changing mutability doesn't make a difference to whether we have // an `Unsize` impl (Fixes ICE in #71036) if !is_unsize { - self.suggest_change_mut( - &obligation, - &mut err, - trait_ref, - points_at_arg, - ); + self.suggest_change_mut(&obligation, &mut err, trait_ref); } // If this error is due to `!: Trait` not implemented but `(): Trait` is @@ -524,12 +516,12 @@ }); let unit_obligation = obligation.with(predicate.to_predicate(tcx)); if self.predicate_may_hold(&unit_obligation) { - err.note("this trait is implemented for `()`."); + err.note("this trait is implemented for `()`"); err.note( "this error might have been caused by changes to \ Rust's type-inference algorithm (see issue #48950 \ \ - for more information).", + for more information)", ); err.help("did you intend to use the type `()` here instead?"); } @@ -541,9 +533,9 @@ // example). let trait_is_debug = - self.tcx.is_diagnostic_item(sym::debug_trait, trait_ref.def_id()); + self.tcx.is_diagnostic_item(sym::Debug, trait_ref.def_id()); let trait_is_display = - self.tcx.is_diagnostic_item(sym::display_trait, trait_ref.def_id()); + self.tcx.is_diagnostic_item(sym::Display, trait_ref.def_id()); let in_std_macro = match obligation.cause.span.ctxt().outer_expn_data().macro_def_id { @@ -730,7 +722,10 @@ }; let found_did = match *found_trait_ty.kind() { - ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), + ty::Closure(did, _) + | ty::Foreign(did) + | ty::FnDef(did, _) + | ty::Generator(did, ..) => Some(did), ty::Adt(def, _) => Some(def.did), _ => None, }; @@ -847,6 +842,9 @@ Overflow => { bug!("overflow should be handled before the `report_selection_error` path"); } + SelectionError::ErrorReporting => { + bug!("ErrorReporting Overflow should not reach `report_selection_err` call") + } }; self.note_obligation_cause(&mut err, &obligation); @@ -1200,13 +1198,13 @@ false } + #[instrument(skip(self), level = "debug")] fn report_fulfillment_error( &self, error: &FulfillmentError<'tcx>, body_id: Option, fallback_has_occurred: bool, ) { - debug!("report_fulfillment_error({:?})", error); match error.code { FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { self.report_selection_error( @@ -1214,7 +1212,6 @@ &error.root_obligation, selection_error, fallback_has_occurred, - error.points_at_arg_span, ); } FulfillmentErrorCode::CodeProjectionError(ref e) => { @@ -1534,6 +1531,7 @@ ) } + #[instrument(skip(self), level = "debug")] fn maybe_report_ambiguity( &self, obligation: &PredicateObligation<'tcx>, @@ -1548,8 +1546,7 @@ let span = obligation.cause.span; debug!( - "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", - predicate, obligation, body_id, obligation.cause.code, + ?predicate, ?obligation.cause.code, ); // Ambiguity errors are often caused as fallout from earlier @@ -1562,7 +1559,7 @@ let mut err = match bound_predicate.skip_binder() { ty::PredicateKind::Trait(data) => { let trait_ref = bound_predicate.rebind(data.trait_ref); - debug!("trait_ref {:?}", trait_ref); + debug!(?trait_ref); if predicate.references_error() { return; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs 2021-11-29 19:27:11.000000000 +0000 @@ -154,9 +154,6 @@ flags.push((sym::from_method, Some(method.to_string()))); } } - if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) { - flags.push((sym::parent_trait, Some(t))); - } if let Some(k) = obligation.cause.span.desugaring_kind() { flags.push((sym::from_desugaring, None)); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,10 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style}; +use rustc_data_structures::sync::Lrc; +use rustc_errors::{ + error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, +}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -21,9 +24,10 @@ Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; +use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; +use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::fmt; @@ -54,7 +58,6 @@ obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, - points_at_arg: bool, ); fn get_closure_name( @@ -69,7 +72,6 @@ obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - points_at_arg: bool, ); fn suggest_add_reference_to_arg( @@ -77,7 +79,6 @@ obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, - points_at_arg: bool, has_custom_message: bool, ) -> bool; @@ -93,7 +94,6 @@ obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - points_at_arg: bool, ); fn suggest_semicolon_removal( @@ -490,16 +490,19 @@ obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, - points_at_arg: bool, ) { // It only make sense when suggesting dereferences for arguments - if !points_at_arg { + let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = + &obligation.cause.code + { + parent_code.clone() + } else { return; - } + }; let param_env = obligation.param_env; let body_id = obligation.cause.body_id; let span = obligation.cause.span; - let real_trait_ref = match &obligation.cause.code { + let real_trait_ref = match &*code { ObligationCauseCode::ImplDerivedObligation(cause) | ObligationCauseCode::DerivedObligation(cause) | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref, @@ -584,7 +587,6 @@ obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - points_at_arg: bool, ) { let self_ty = match trait_ref.self_ty().no_bound_vars() { None => return, @@ -656,11 +658,11 @@ } _ => return, }; - if points_at_arg { + if matches!(obligation.cause.code, ObligationCauseCode::FunctionArgumentObligation { .. }) { // When the obligation error has been ensured to have been caused by // an argument, the `obligation.cause.span` points at the expression - // of the argument, so we can provide a suggestion. This is signaled - // by `points_at_arg`. Otherwise, we give a more general note. + // of the argument, so we can provide a suggestion. Otherwise, we give + // a more general note. err.span_suggestion_verbose( obligation.cause.span.shrink_to_hi(), &msg, @@ -676,13 +678,22 @@ &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, - points_at_arg: bool, + poly_trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, has_custom_message: bool, ) -> bool { - if !points_at_arg { + let span = obligation.cause.span; + + let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = + &obligation.cause.code + { + parent_code.clone() + } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) = + span.ctxt().outer_expn_data().kind + { + Lrc::new(obligation.cause.code.clone()) + } else { return false; - } + }; // List of traits for which it would be nonsensical to suggest borrowing. // For instance, immutable references are always Copy, so suggesting to @@ -693,11 +704,12 @@ .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok()) .collect(); - never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::send_trait).unwrap()); + if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) { + never_suggest_borrow.push(def_id); + } - let span = obligation.cause.span; let param_env = obligation.param_env; - let trait_ref = trait_ref.skip_binder(); + let trait_ref = poly_trait_ref.skip_binder(); let found_ty = trait_ref.self_ty(); let found_ty_str = found_ty.to_string(); @@ -707,22 +719,28 @@ let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]); // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>, - expected_trait_ref: ty::TraitRef<'tcx>, - mtbl: bool, + let mut try_borrowing = |new_imm_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + new_mut_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, blacklist: &[DefId]| -> bool { - if blacklist.contains(&expected_trait_ref.def_id) { + if blacklist.contains(&expected_trait_ref.def_id()) { return false; } - let new_obligation = Obligation::new( + let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new( ObligationCause::dummy(), param_env, - new_trait_ref.without_const().to_predicate(self.tcx), - ); + new_imm_trait_ref.without_const().to_predicate(self.tcx), + )); - if self.predicate_must_hold_modulo_regions(&new_obligation) { + let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new( + ObligationCause::dummy(), + param_env, + new_mut_trait_ref.without_const().to_predicate(self.tcx), + )); + + if imm_result || mut_result { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument // might solve the problem. In cases like this, the important part is the @@ -754,7 +772,11 @@ ); // This if is to prevent a special edge-case - if !span.from_expansion() { + if matches!( + span.ctxt().outer_expn_data().kind, + ExpnKind::Root + | ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ) { // We don't want a borrowing suggestion on the fields in structs, // ``` // struct Foo { @@ -762,15 +784,24 @@ // } // ``` - err.span_suggestion( - span, - &format!( - "consider{} borrowing here", - if mtbl { " mutably" } else { "" } - ), - format!("&{}{}", if mtbl { "mut " } else { "" }, snippet), - Applicability::MaybeIncorrect, - ); + if imm_result && mut_result { + err.span_suggestions( + span.shrink_to_lo(), + "consider borrowing here", + ["&".to_string(), "&mut ".to_string()].into_iter(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "consider{} borrowing here", + if mut_result { " mutably" } else { "" } + ), + format!("&{}", if mut_result { "mut " } else { "" }), + Applicability::MaybeIncorrect, + ); + } } return true; } @@ -778,35 +809,22 @@ return false; }; - if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code { - let expected_trait_ref = obligation.parent_trait_ref.skip_binder(); - let new_imm_trait_ref = - ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs); - let new_mut_trait_ref = - ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs); - if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) { - return true; - } else { - return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]); - } + if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code { + let expected_trait_ref = obligation.parent_trait_ref; + let new_imm_trait_ref = poly_trait_ref + .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs)); + let new_mut_trait_ref = poly_trait_ref + .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs)); + return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]); } else if let ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ItemObligation(_) = &obligation.cause.code + | ObligationCauseCode::ItemObligation(_) = &*code { - if try_borrowing( - ty::TraitRef::new(trait_ref.def_id, imm_substs), - trait_ref, - false, + return try_borrowing( + poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, imm_substs)), + poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, mut_substs)), + *poly_trait_ref, &never_suggest_borrow[..], - ) { - return true; - } else { - return try_borrowing( - ty::TraitRef::new(trait_ref.def_id, mut_substs), - trait_ref, - true, - &never_suggest_borrow[..], - ); - } + ); } else { false } @@ -882,8 +900,12 @@ obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - points_at_arg: bool, ) { + let points_at_arg = matches!( + obligation.cause.code, + ObligationCauseCode::FunctionArgumentObligation { .. }, + ); + let span = obligation.cause.span; if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { let refs_number = @@ -1241,33 +1263,40 @@ trait_ref: ty::PolyTraitRef<'tcx>, ) -> String { let inputs = trait_ref.skip_binder().substs.type_at(1); - let sig = if let ty::Tuple(inputs) = inputs.kind() { - tcx.mk_fn_sig( - inputs.iter().map(|k| k.expect_ty()), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), - false, - hir::Unsafety::Normal, - abi::Abi::Rust, - ) - } else { - tcx.mk_fn_sig( + let sig = match inputs.kind() { + ty::Tuple(inputs) + if tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() => + { + tcx.mk_fn_sig( + inputs.iter().map(|k| k.expect_ty()), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), + false, + hir::Unsafety::Normal, + abi::Abi::Rust, + ) + } + _ => tcx.mk_fn_sig( std::iter::once(inputs), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), false, hir::Unsafety::Normal, abi::Abi::Rust, - ) + ), }; trait_ref.rebind(sig).to_string() } - let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); + let argument_kind = match expected_ref.skip_binder().substs.type_at(0) { + t if t.is_closure() => "closure", + t if t.is_generator() => "generator", + _ => "function", + }; let mut err = struct_span_err!( self.tcx.sess, span, E0631, "type mismatch in {} arguments", - if argument_is_closure { "closure" } else { "function" } + argument_kind ); let found_str = format!("expected signature of `{}`", build_fn_sig_string(self.tcx, found)); @@ -1609,12 +1638,12 @@ // Special case the primary error message when send or sync is the trait that was // not implemented. - let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id); - let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id); let hir = self.tcx.hir(); - let trait_explanation = if is_send || is_sync { + let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) = + self.tcx.get_diagnostic_name(trait_ref.def_id) + { let (trait_name, trait_verb) = - if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; + if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; err.clear_code(); err.set_primary_message(format!( @@ -2248,7 +2277,11 @@ parent_trait_ref = child_trait_ref; } if count > 0 { - err.note(&format!("{} redundant requirements hidden", count)); + err.note(&format!( + "{} redundant requirement{} hidden", + count, + pluralize!(count) + )); err.note(&format!( "required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref.print_only_trait_path(), @@ -2280,6 +2313,56 @@ ) }); } + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id, + call_hir_id, + ref parent_code, + } => { + let hir = self.tcx.hir(); + if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) = + hir.find(arg_hir_id) + { + let in_progress_typeck_results = + self.in_progress_typeck_results.map(|t| t.borrow()); + let parent_id = hir.local_def_id(hir.get_parent_item(arg_hir_id)); + let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results { + Some(t) if t.hir_owner == parent_id => t, + _ => self.tcx.typeck(parent_id), + }; + let ty = typeck_results.expr_ty_adjusted(expr); + let span = expr.peel_blocks().span; + if Some(span) != err.span.primary_span() { + err.span_label( + span, + &if ty.references_error() { + String::new() + } else { + format!("this tail expression is of type `{:?}`", ty) + }, + ); + } + } + if let Some(Node::Expr(hir::Expr { + kind: + hir::ExprKind::Call(hir::Expr { span, .. }, _) + | hir::ExprKind::MethodCall(_, span, ..), + .. + })) = hir.find(call_hir_id) + { + if Some(*span) != err.span.primary_span() { + err.span_label(*span, "required by a bound introduced by this call"); + } + } + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + err, + predicate, + &parent_code, + obligated_types, + seen_requirements, + ) + }); + } ObligationCauseCode::CompareImplMethodObligation { item_name, trait_item_def_id, @@ -2352,10 +2435,13 @@ } fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { - let current_limit = self.tcx.recursion_limit(); - let suggested_limit = current_limit * 2; + let suggested_limit = match self.tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", suggested_limit, self.tcx.crate_name(LOCAL_CRATE), )); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/fulfill.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/fulfill.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/fulfill.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/fulfill.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,13 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; @@ -53,6 +54,9 @@ // A list of all obligations that have been registered with this // fulfillment context. predicates: ObligationForest>, + + relationships: FxHashMap, + // Should this fulfillment context register type-lives-for-region // obligations on its parent infcx? In some cases, region // obligations are either already known to hold (normalization) or @@ -97,6 +101,7 @@ pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: true, usable_in_snapshot: false, } @@ -105,6 +110,7 @@ pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: true, usable_in_snapshot: true, } @@ -113,6 +119,7 @@ pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: false, usable_in_snapshot: false, } @@ -210,6 +217,8 @@ assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); + super::relationships::update(self, infcx, &obligation); + self.predicates .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } @@ -265,6 +274,10 @@ fn pending_obligations(&self) -> Vec> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } } struct FulfillProcessor<'a, 'b, 'tcx> { @@ -405,7 +418,8 @@ | ty::PredicateKind::Coerce(_) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) => { - let pred = infcx.replace_bound_vars_with_placeholders(binder); + let pred = + ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); ProcessResult::Changed(mk_pending(vec![ obligation.with(pred.to_predicate(self.selcx.tcx())), ])) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,6 +15,7 @@ mod on_unimplemented; mod project; pub mod query; +pub(crate) mod relationships; mod select; mod specialize; mod structural_match; @@ -63,7 +64,9 @@ pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_match::NonStructuralMatchTy; -pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; +pub use self::util::{ + elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs, +}; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{ get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, @@ -139,7 +142,8 @@ infcx.tcx.def_path_str(def_id) ); - let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; + let trait_ref = + ty::Binder::dummy(ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }); let obligation = Obligation { param_env, cause: ObligationCause::misc(span, hir::CRATE_HIR_ID), @@ -621,10 +625,35 @@ trait_ref: ty::PolyTraitRef<'tcx>, entries: &[VtblEntry<'tcx>], ) { - let msg = format!("Vtable entries for `{}`: {:#?}", trait_ref, entries); + let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries); tcx.sess.struct_span_err(sp, &msg).emit(); } +fn own_existential_vtable_entries<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyExistentialTraitRef<'tcx>, +) -> &'tcx [DefId] { + let trait_methods = tcx + .associated_items(trait_ref.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Fn); + // Now list each method's DefId (for within its trait). + let own_entries = trait_methods.filter_map(move |trait_method| { + debug!("own_existential_vtable_entry: trait_method={:?}", trait_method); + let def_id = trait_method.def_id; + + // Some methods cannot be called on an object; skip those. + if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) { + debug!("own_existential_vtable_entry: not vtable safe"); + return None; + } + + Some(def_id) + }); + + tcx.arena.alloc_from_iter(own_entries.into_iter()) +} + /// Given a trait `trait_ref`, iterates the vtable entries /// that come from `trait_ref`, including its supertraits. fn vtable_entries<'tcx>( @@ -641,21 +670,15 @@ entries.extend(COMMON_VTABLE_ENTRIES); } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - let trait_methods = tcx - .associated_items(trait_ref.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Fn); - // Now list each method's DefId and InternalSubsts (for within its trait). - // If the method can never be called from this object, produce `Vacant`. - let own_entries = trait_methods.map(move |trait_method| { - debug!("vtable_entries: trait_method={:?}", trait_method); - let def_id = trait_method.def_id; - - // Some methods cannot be called on an object; skip those. - if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) { - debug!("vtable_entries: not vtable safe"); - return VtblEntry::Vacant; - } + let existential_trait_ref = trait_ref + .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + + // Lookup the shape of vtable for the trait. + let own_existential_entries = + tcx.own_existential_vtable_entries(existential_trait_ref); + + let own_entries = own_existential_entries.iter().copied().map(|def_id| { + debug!("vtable_entries: trait_method={:?}", def_id); // The method may have some early-bound lifetimes; add regions for those. let substs = trait_ref.map_bound(|trait_ref| { @@ -804,19 +827,20 @@ specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, + own_existential_vtable_entries, vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, - mir_abstract_const: |tcx, def_id| { + thir_abstract_const: |tcx, def_id| { let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.mir_abstract_const_of_const_arg(def) + tcx.thir_abstract_const_of_const_arg(def) } else { - const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) + const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) } }, - mir_abstract_const_of_const_arg: |tcx, (did, param_did)| { - const_evaluatable::mir_abstract_const( + thir_abstract_const_of_const_arg: |tcx, (did, param_did)| { + const_evaluatable::thir_abstract_const( tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }, ) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/object_safety.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/object_safety.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/object_safety.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/object_safety.rs 2021-11-29 19:27:11.000000000 +0000 @@ -250,7 +250,7 @@ trait_def_id: DefId, supertraits_only: bool, ) -> SmallVec<[Span; 1]> { - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); + let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); let predicates = if supertraits_only { tcx.super_predicates_of(trait_def_id) } else { @@ -465,9 +465,9 @@ let param_env = tcx.param_env(method.def_id); - let abi_of_ty = |ty: Ty<'tcx>| -> Option<&Abi> { + let abi_of_ty = |ty: Ty<'tcx>| -> Option { match tcx.layout_of(param_env.and(ty)) { - Ok(layout) => Some(&layout.abi), + Ok(layout) => Some(layout.abi), Err(err) => { // #78372 tcx.sess.delay_span_bug( @@ -554,11 +554,11 @@ let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait( - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), - )); + let trait_predicate = trait_ref.map_bound(|trait_ref| { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) + }); - let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) + let mut associated_types = traits::supertraits(tcx, trait_ref) .flat_map(|super_trait_ref| { tcx.associated_items(super_trait_ref.def_id()) .in_definition_order() @@ -671,10 +671,10 @@ let param_env = tcx.param_env(method.def_id); // Self: Unsize - let unsize_predicate = ty::TraitRef { + let unsize_predicate = ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), - } + }) .without_const() .to_predicate(tcx); @@ -689,7 +689,9 @@ } }); - ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx) + ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs }) + .without_const() + .to_predicate(tcx) }; let caller_bounds: Vec> = param_env @@ -703,10 +705,10 @@ // Receiver: DispatchFromDyn U]> let obligation = { - let predicate = ty::TraitRef { + let predicate = ty::Binder::dummy(ty::TraitRef { def_id: dispatch_from_dyn_did, substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), - } + }) .without_const() .to_predicate(tcx); @@ -789,8 +791,7 @@ // Compute supertraits of current trait lazily. if self.supertraits.is_none() { - let trait_ref = - ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)); + let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id); self.supertraits = Some( traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(), ); @@ -836,7 +837,7 @@ // // This shouldn't really matter though as we can't really use any // constants which are not considered const evaluatable. - use rustc_middle::mir::abstract_const::Node; + use rustc_middle::thir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/project.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/project.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/project.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/project.rs 2021-11-29 19:27:11.000000000 +0000 @@ -27,7 +27,7 @@ use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_span::symbol::sym; use std::collections::BTreeMap; @@ -558,7 +558,7 @@ fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { let infcx = self.infcx; let index = - self.universe_indices.len() - debruijn.as_usize() + self.current_index.as_usize() - 1; + self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1; let universe = self.universe_indices[index].unwrap_or_else(|| { for i in self.universe_indices.iter_mut().take(index + 1) { *i = i.or_else(|| Some(infcx.create_next_universe())) @@ -595,7 +595,7 @@ ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); let p = ty::PlaceholderRegion { universe, name: br.kind }; - self.mapped_regions.insert(p.clone(), br); + self.mapped_regions.insert(p, br); self.infcx.tcx.mk_region(ty::RePlaceholder(p)) } _ => r, @@ -613,7 +613,7 @@ ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); let p = ty::PlaceholderType { universe, name: bound_ty.var }; - self.mapped_types.insert(p.clone(), bound_ty); + self.mapped_types.insert(p, bound_ty); self.infcx.tcx.mk_ty(ty::Placeholder(p)) } _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), @@ -637,7 +637,7 @@ universe, name: ty::BoundConst { var: bound_const, ty }, }; - self.mapped_consts.insert(p.clone(), bound_const); + self.mapped_consts.insert(p, bound_const); self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty }) } _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self), @@ -810,17 +810,7 @@ // and a deferred predicate to resolve this when more type // information is available. - let tcx = selcx.infcx().tcx; - let def_id = projection_ty.item_def_id; - let ty_var = selcx.infcx().next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: tcx.def_span(def_id), - }); - let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var }); - let obligation = - Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate(tcx)); - obligations.push(obligation); - ty_var + selcx.infcx().infer_projection(param_env, projection_ty, cause, depth + 1, obligations) }) } @@ -1038,7 +1028,7 @@ cause: ObligationCause<'tcx>, depth: usize, ) -> NormalizedTy<'tcx> { - let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); + let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx())); let trait_obligation = Obligation { cause, recursion_depth: depth, @@ -1300,7 +1290,7 @@ // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx())); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let _ = selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { @@ -1495,7 +1485,8 @@ } super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) - | super::ImplSource::TraitUpcasting(_) => { + | super::ImplSource::TraitUpcasting(_) + | super::ImplSource::ConstDrop(_) => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( obligation.cause.span, @@ -1567,7 +1558,8 @@ | super::ImplSource::Param(..) | super::ImplSource::Builtin(..) | super::ImplSource::TraitUpcasting(_) - | super::ImplSource::TraitAlias(..) => { + | super::ImplSource::TraitAlias(..) + | super::ImplSource::ConstDrop(_) => { // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -83,17 +83,21 @@ ) -> EvaluationResult { match self.evaluate_obligation(obligation) { Ok(result) => result, - Err(OverflowError) => { + Err(OverflowError::Canonical) => { let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); - selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| { - span_bug!( - obligation.cause.span, - "Overflow should be caught earlier in standard query mode: {:?}, {:?}", - obligation, - r, - ) + selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r { + OverflowError::Canonical => { + span_bug!( + obligation.cause.span, + "Overflow should be caught earlier in standard query mode: {:?}, {:?}", + obligation, + r, + ) + } + OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr, }) } + Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr, } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,6 @@ pub mod evaluate_obligation; pub mod method_autoderef; pub mod normalize; -pub mod outlives_bounds; pub mod type_op; pub use rustc_middle::traits::query::*; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::query::NoSolution; -use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine}; -use rustc_hir as hir; -use rustc_infer::traits::TraitEngineExt as _; -use rustc_middle::ty::{self, Ty}; -use rustc_span::source_map::Span; - -pub use rustc_middle::traits::query::OutlivesBound; - -pub trait InferCtxtExt<'tcx> { - fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - span: Span, - ) -> Vec>; -} - -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { - /// Implied bounds are region relationships that we deduce - /// automatically. The idea is that (e.g.) a caller must check that a - /// function's argument types are well-formed immediately before - /// calling that fn, and hence the *callee* can assume that its - /// argument types are well-formed. This may imply certain relationships - /// between generic parameters. For example: - /// - /// fn foo<'a,T>(x: &'a T) - /// - /// can only be called with a `'a` and `T` such that `&'a T` is WF. - /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. - /// - /// # Parameters - /// - /// - `param_env`, the where-clauses in scope - /// - `body_id`, the body-id to use when normalizing assoc types. - /// Note that this may cause outlives obligations to be injected - /// into the inference context with this body-id. - /// - `ty`, the type that we are supposed to assume is WF. - /// - `span`, a span to use when normalizing, hopefully not important, - /// might be useful if a `bug!` occurs. - fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - span: Span, - ) -> Vec> { - debug!("implied_outlives_bounds(ty = {:?})", ty); - - let mut orig_values = OriginalQueryValues::default(); - let key = self.canonicalize_query(param_env.and(ty), &mut orig_values); - let result = match self.tcx.implied_outlives_bounds(key) { - Ok(r) => r, - Err(NoSolution) => { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve all obligations", - ); - return vec![]; - } - }; - assert!(result.value.is_proven()); - - let result = self.instantiate_query_response_and_region_obligations( - &ObligationCause::misc(span, body_id), - param_env, - &orig_values, - result, - ); - debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); - let result = match result { - Ok(v) => v, - Err(_) => { - self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate"); - return vec![]; - } - }; - - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let mut fulfill_cx = FulfillmentContext::new(); - fulfill_cx.register_predicate_obligations(self, result.obligations); - if fulfill_cx.select_all_or_error(self).is_err() { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); - } - - result.value - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::outlives_bounds::OutlivesBound; use crate::traits::query::Fallible; +use rustc_infer::traits::query::OutlivesBound; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/relationships.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/relationships.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/relationships.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/relationships.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,69 @@ +use crate::infer::InferCtxt; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{ObligationCause, PredicateObligation}; +use rustc_infer::traits::TraitEngine; +use rustc_middle::ty::{self, ToPredicate}; + +pub(crate) fn update<'tcx, T>( + engine: &mut T, + infcx: &InferCtxt<'_, 'tcx>, + obligation: &PredicateObligation<'tcx>, +) where + T: TraitEngine<'tcx>, +{ + // (*) binder skipped + if let ty::PredicateKind::Trait(predicate) = obligation.predicate.kind().skip_binder() { + if let Some(ty) = + infcx.shallow_resolve(predicate.self_ty()).ty_vid().map(|t| infcx.root_var(t)) + { + if infcx + .tcx + .lang_items() + .sized_trait() + .map_or(false, |st| st != predicate.trait_ref.def_id) + { + let new_self_ty = infcx.tcx.types.unit; + + let trait_ref = ty::TraitRef { + substs: infcx + .tcx + .mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]), + ..predicate.trait_ref + }; + + // Then contstruct a new obligation with Self = () added + // to the ParamEnv, and see if it holds. + let o = rustc_infer::traits::Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + obligation + .predicate + .kind() + .map_bound(|_| { + // (*) binder moved here + ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + constness: predicate.constness, + }) + }) + .to_predicate(infcx.tcx), + ); + // Don't report overflow errors. Otherwise equivalent to may_hold. + if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) { + if result.may_apply() { + engine.relationships().entry(ty).or_default().self_in_trait = true; + } + } + } + } + } + + if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() { + // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, + // we need to make it into one. + if let Some(vid) = predicate.ty.ty_vid() { + debug!("relationship: {:?}.output = true", vid); + engine.relationships().entry(vid).or_default().output = true; + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,14 +6,19 @@ //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::traits::TraitEngine; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, TypeFoldable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness}; use rustc_target::spec::abi::Abi; +use crate::traits; use crate::traits::coherence::Conflict; +use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{util, SelectionResult}; -use crate::traits::{Overflow, Unimplemented}; +use crate::traits::{ErrorReporting, Overflow, Unimplemented}; use super::BuiltinImplConditions; use super::IntercrateAmbiguityCause; @@ -156,7 +161,8 @@ Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) } Ok(_) => Ok(None), - Err(OverflowError) => Err(Overflow), + Err(OverflowError::Canonical) => Err(Overflow), + Err(OverflowError::ErrorReporting) => Err(ErrorReporting), }) .flat_map(Result::transpose) .collect::, _>>()?; @@ -220,6 +226,7 @@ self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation) } + #[instrument(skip(self, stack), level = "debug")] pub(super) fn assemble_candidates<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -277,6 +284,16 @@ self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); } else if lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } else if lang_items.drop_trait() == Some(def_id) + && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst + { + if self.is_in_const_context { + self.assemble_const_drop_candidates(obligation, &mut candidates)?; + } else { + debug!("passing ~const Drop bound; in non-const context"); + // `~const Drop` when we are not in a const context has no effect. + candidates.vec.push(ConstDropCandidate) + } } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -465,7 +482,7 @@ .. } = self_ty.fn_sig(self.tcx()).skip_binder() { - candidates.vec.push(FnPointerCandidate); + candidates.vec.push(FnPointerCandidate { is_const: false }); } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). @@ -478,7 +495,9 @@ } = self_ty.fn_sig(self.tcx()).skip_binder() { if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { - candidates.vec.push(FnPointerCandidate); + candidates + .vec + .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); } } } @@ -659,6 +678,55 @@ }) } + /// Temporary migration for #89190 + fn need_migrate_deref_output_trait_object( + &mut self, + ty: Ty<'tcx>, + cause: &traits::ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Option<(Ty<'tcx>, DefId)> { + let tcx = self.tcx(); + if tcx.features().trait_upcasting { + return None; + } + + // + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().deref_trait()?, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let obligation = traits::Obligation::new( + cause.clone(), + param_env, + ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + ); + if !self.infcx.predicate_may_hold(&obligation) { + return None; + } + + let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); + let normalized_ty = fulfillcx.normalize_projection_type( + &self.infcx, + param_env, + ty::ProjectionTy { + item_def_id: tcx.lang_items().deref_target()?, + substs: trait_ref.substs, + }, + cause.clone(), + ); + + let data = if let ty::Dynamic(ref data, ..) = normalized_ty.kind() { + data + } else { + return None; + }; + + let def_id = data.principal_def_id()?; + + return Some((normalized_ty, def_id)); + } + /// Searches for unsizing that might apply to `obligation`. fn assemble_candidates_for_unsizing( &mut self, @@ -719,6 +787,30 @@ let principal_a = data_a.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); + if let Some((deref_output_ty, deref_output_trait_did)) = self + .need_migrate_deref_output_trait_object( + source, + &obligation.cause, + obligation.param_env, + ) + { + if deref_output_trait_did == target_trait_did { + self.tcx().struct_span_lint_hir( + DEREF_INTO_DYN_SUPERTRAIT, + obligation.cause.body_id, + obligation.cause.span, + |lint| { + lint.build(&format!( + "`{}` implements `Deref` with supertrait `{}` as output", + source, + deref_output_ty + )).emit(); + }, + ); + return; + } + } + for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() { @@ -803,4 +895,122 @@ } } } + + fn assemble_const_drop_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)]; + + while let Some((ty, depth)) = stack.pop() { + let mut noreturn = false; + + self.check_recursion_depth(depth, obligation)?; + let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + let mut copy_obligation = + obligation.with(obligation.predicate.rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: self.tcx().require_lang_item(hir::LangItem::Copy, None), + substs: self.tcx().mk_substs_trait(ty, &[]), + }, + constness: ty::BoundConstness::NotConst, + })); + copy_obligation.recursion_depth = depth + 1; + self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates); + let copy_conditions = self.copy_clone_conditions(©_obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut copy_candidates); + if !copy_candidates.vec.is_empty() { + noreturn = true; + } + debug!(?copy_candidates.vec, "assemble_const_drop_candidates - copy"); + + match ty.kind() { + ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::FnPtr(_) + | ty::Never + | ty::Ref(..) + | ty::FnDef(..) + | ty::RawPtr(_) + | ty::Bool + | ty::Char + | ty::Str + | ty::Foreign(_) => {} // Do nothing. These types satisfy `const Drop`. + + ty::Adt(def, subst) => { + let mut set = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + self.assemble_candidates_from_impls( + &obligation.with(obligation.predicate.map_bound(|mut pred| { + pred.trait_ref.substs = self.tcx().mk_substs_trait(ty, &[]); + pred + })), + &mut set, + ); + stack.extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1))); + + debug!(?set.vec, "assemble_const_drop_candidates - ty::Adt"); + if set.vec.into_iter().any(|candidate| { + if let SelectionCandidate::ImplCandidate(did) = candidate { + matches!(self.tcx().impl_constness(did), hir::Constness::NotConst) + } else { + false + } + }) { + if !noreturn { + // has non-const Drop + return Ok(()); + } + debug!("not returning"); + } + } + + ty::Array(ty, _) => stack.push((ty, depth + 1)), + + ty::Tuple(_) => stack.extend(ty.tuple_fields().map(|t| (t, depth + 1))), + + ty::Closure(_, substs) => { + let substs = substs.as_closure(); + let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty()); + stack.push((ty, depth + 1)); + } + + ty::Generator(_, substs, _) => { + let substs = substs.as_generator(); + let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty()); + + stack.push((ty, depth + 1)); + stack.push((substs.witness(), depth + 1)); + } + + ty::GeneratorWitness(tys) => stack.extend( + self.tcx().erase_late_bound_regions(*tys).iter().map(|t| (t, depth + 1)), + ), + + ty::Slice(ty) => stack.push((ty, depth + 1)), + + ty::Opaque(..) + | ty::Dynamic(..) + | ty::Error(_) + | ty::Bound(..) + | ty::Infer(_) + | ty::Placeholder(_) + | ty::Projection(..) + | ty::Param(..) => { + if !noreturn { + return Ok(()); + } + debug!("not returning"); + } + } + debug!(?stack, "assemble_const_drop_candidates - in loop"); + } + // all types have passed. + candidates.vec.push(ConstDropCandidate); + + Ok(()) + } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/confirmation.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/confirmation.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/confirmation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/confirmation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,7 +28,7 @@ use crate::traits::VtblSegment; use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation}; use crate::traits::{ - ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, + ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceConstDropData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, @@ -92,7 +92,7 @@ Ok(ImplSource::Generator(vtable_generator)) } - FnPointerCandidate => { + FnPointerCandidate { .. } => { let data = self.confirm_fn_pointer_candidate(obligation)?; Ok(ImplSource::FnPointer(data)) } @@ -124,6 +124,8 @@ let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; Ok(ImplSource::TraitUpcasting(data)) } + + ConstDropCandidate => Ok(ImplSource::ConstDrop(ImplSourceConstDropData)), } } @@ -139,6 +141,7 @@ let placeholder_trait_predicate = self.infcx().replace_bound_vars_with_placeholders(trait_predicate); let placeholder_self_ty = placeholder_trait_predicate.self_ty(); + let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { ty::Projection(proj) => (proj.item_def_id, proj.substs), ty::Opaque(def_id, substs) => (def_id, substs), @@ -162,7 +165,7 @@ obligations.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate.value) + .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); @@ -598,12 +601,11 @@ Ok(ImplSourceGeneratorData { generator_def_id, substs, nested: obligations }) } + #[instrument(skip(self), level = "debug")] fn confirm_closure_candidate( &mut self, obligation: &TraitObligation<'tcx>, ) -> Result>, SelectionError<'tcx>> { - debug!(?obligation, "confirm_closure_candidate"); - let kind = self .tcx() .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) @@ -644,7 +646,7 @@ obligations.push(Obligation::new( obligation.cause.clone(), obligation.param_env, - ty::PredicateKind::ClosureKind(closure_def_id, substs, kind) + ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)) .to_predicate(self.tcx()), )); } @@ -677,6 +679,7 @@ /// because these output type parameters should not affect the /// selection of the impl. Therefore, if there is a mismatch, we /// report an error to the user. + #[instrument(skip(self), level = "trace")] fn confirm_poly_trait_refs( &mut self, obligation_cause: ObligationCause<'tcx>, @@ -896,10 +899,10 @@ ); // We can only make objects from sized types. - let tr = ty::TraitRef::new( + let tr = ty::Binder::dummy(ty::TraitRef::new( tcx.require_lang_item(LangItem::Sized, None), tcx.mk_substs_trait(source, &[]), - ); + )); nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx))); // If the type is `Foo + 'a`, ensure that the type diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/select/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,18 +14,17 @@ use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; use super::wf; use super::DerivedObligationCause; +use super::Normalized; use super::Obligation; use super::ObligationCauseCode; use super::Selection; use super::SelectionResult; use super::TraitQueryMode; -use super::{Normalized, ProjectionCacheKey}; +use super::{ErrorReporting, Overflow, SelectionError, Unimplemented}; use super::{ObligationCause, PredicateObligation, TraitObligation}; -use super::{Overflow, SelectionError, Unimplemented}; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::traits::error_reporting::InferCtxtExt; -use crate::traits::project::ProjectionCacheKeyExt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; @@ -34,8 +33,8 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; @@ -452,6 +451,7 @@ /// Evaluates the predicates in `predicates` recursively. Note that /// this applies projections in the predicates, and therefore /// is run within an inference probe. + #[instrument(skip(self, stack), level = "debug")] fn evaluate_predicates_recursively<'o, I>( &mut self, stack: TraitObligationStackList<'o, 'tcx>, @@ -461,7 +461,6 @@ I: IntoIterator> + std::fmt::Debug, { let mut result = EvaluatedToOk; - debug!(?predicates, "evaluate_predicates_recursively"); for obligation in predicates { let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; if let EvaluatedToErr = eval { @@ -578,14 +577,7 @@ match project::poly_project_and_unify_type(self, &project_obligation) { Ok(Ok(Some(mut subobligations))) => { self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); - let result = self - .evaluate_predicates_recursively(previous_stack, subobligations); - if let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate(self, data) - { - self.infcx.inner.borrow_mut().projection_cache().complete(key); - } - result + self.evaluate_predicates_recursively(previous_stack, subobligations) } Ok(Ok(None)) => Ok(EvaluatedToAmbig), Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur), @@ -691,13 +683,12 @@ result } + #[instrument(skip(self, previous_stack), level = "debug")] fn evaluate_trait_predicate_recursively<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, ) -> Result { - debug!(?obligation, "evaluate_trait_predicate_recursively"); - if !self.intercrate && obligation.is_global(self.tcx()) && obligation @@ -709,7 +700,7 @@ // If a param env has no global bounds, global obligations do not // depend on its particular value in order to work, so we can clear // out the param env and get better caching. - debug!("evaluate_trait_predicate_recursively - in global"); + debug!("in global"); obligation.param_env = obligation.param_env.without_caller_bounds(); } @@ -761,7 +752,7 @@ } else { debug!(?result, "PROVISIONAL"); debug!( - "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ + "caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", fresh_trait_ref, stack.depth, reached_depth, ); @@ -909,7 +900,8 @@ match self.candidate_from_obligation(stack) { Ok(Some(c)) => self.evaluate_candidate(stack, &c), Ok(None) => Ok(EvaluatedToAmbig), - Err(Overflow) => Err(OverflowError), + Err(Overflow) => Err(OverflowError::Canonical), + Err(ErrorReporting) => Err(OverflowError::ErrorReporting), Err(..) => Ok(EvaluatedToErr), } } @@ -1058,28 +1050,40 @@ it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); } - /// Checks that the recursion limit has not been exceeded. - /// - /// The weird return type of this function allows it to be used with the `try` (`?`) - /// operator within certain functions. - fn check_recursion_limit, V: Display + TypeFoldable<'tcx>>( + fn check_recursion_depth>( &self, - obligation: &Obligation<'tcx, T>, - error_obligation: &Obligation<'tcx, V>, + depth: usize, + error_obligation: &Obligation<'tcx, T>, ) -> Result<(), OverflowError> { - if !self.infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) { + if !self.infcx.tcx.recursion_limit().value_within_limit(depth) { match self.query_mode { TraitQueryMode::Standard => { - self.infcx().report_overflow_error(error_obligation, true); + if self.infcx.is_tainted_by_errors() { + return Err(OverflowError::ErrorReporting); + } + self.infcx.report_overflow_error(error_obligation, true); } TraitQueryMode::Canonical => { - return Err(OverflowError); + return Err(OverflowError::Canonical); } } } Ok(()) } + /// Checks that the recursion limit has not been exceeded. + /// + /// The weird return type of this function allows it to be used with the `try` (`?`) + /// operator within certain functions. + #[inline(always)] + fn check_recursion_limit, V: Display + TypeFoldable<'tcx>>( + &self, + obligation: &Obligation<'tcx, T>, + error_obligation: &Obligation<'tcx, V>, + ) -> Result<(), OverflowError> { + self.check_recursion_depth(obligation.recursion_depth, error_obligation) + } + fn in_task(&mut self, op: OP) -> (R, DepNodeIndex) where OP: FnOnce(&mut Self) -> R, @@ -1099,28 +1103,25 @@ let tcx = self.tcx(); // Respect const trait obligations if self.is_trait_predicate_const(obligation.predicate.skip_binder()) { - if Some(obligation.predicate.skip_binder().trait_ref.def_id) - != tcx.lang_items().sized_trait() - // const Sized bounds are skipped - { - match candidate { - // const impl - ImplCandidate(def_id) - if tcx.impl_constness(def_id) == hir::Constness::Const => {} - // const param - ParamCandidate(ty::ConstnessAnd { - constness: ty::BoundConstness::ConstIfConst, - .. - }) => {} - // auto trait impl - AutoImplCandidate(..) => {} - // generator, this will raise error in other places - // or ignore error with const_async_blocks feature - GeneratorCandidate => {} - _ => { - // reject all other types of candidates - return Err(Unimplemented); - } + match candidate { + // const impl + ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {} + // const param + ParamCandidate(ty::ConstnessAnd { + constness: ty::BoundConstness::ConstIfConst, + .. + }) => {} + // auto trait impl + AutoImplCandidate(..) => {} + // generator, this will raise error in other places + // or ignore error with const_async_blocks feature + GeneratorCandidate => {} + // FnDef where the function is const + FnPointerCandidate { is_const: true } => {} + ConstDropCandidate => {} + _ => { + // reject all other types of candidates + return Err(Unimplemented); } } } @@ -1510,21 +1511,24 @@ ( BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate - | PointeeCandidate, + | PointeeCandidate + | ConstDropCandidate, _, ) => true, ( _, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate - | PointeeCandidate, + | PointeeCandidate + | ConstDropCandidate, ) => false, (ParamCandidate(other), ParamCandidate(victim)) => { - let value_same_except_bound_vars = other.value.skip_binder() + let same_except_bound_vars = other.value.skip_binder() == victim.value.skip_binder() + && other.constness == victim.constness && !other.value.skip_binder().has_escaping_bound_vars(); - if value_same_except_bound_vars { + if same_except_bound_vars { // See issue #84398. In short, we can generate multiple ParamCandidates which are // the same except for unused bound vars. Just pick the one with the fewest bound vars // or the current one if tied (they should both evaluate to the same answer). This is @@ -1541,6 +1545,9 @@ } } + // Drop otherwise equivalent non-const fn pointer candidates + (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true, + // Global bounds from the where clause should be ignored // here (see issue #50825). Otherwise, we have a where // clause so don't go around looking for impls. @@ -1551,7 +1558,7 @@ ImplCandidate(..) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1569,7 +1576,7 @@ ImplCandidate(_) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1599,7 +1606,7 @@ ImplCandidate(..) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1611,7 +1618,7 @@ ImplCandidate(..) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1692,7 +1699,7 @@ ImplCandidate(_) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1701,7 +1708,7 @@ ImplCandidate(_) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -2053,7 +2060,7 @@ let cause = ObligationCause::new( obligation.cause.span, obligation.cause.body_id, - ObligationCauseCode::MatchImpl(Lrc::new(obligation.cause.code.clone()), impl_def_id), + ObligationCauseCode::MatchImpl(obligation.cause.clone(), impl_def_id), ); let InferOk { obligations, .. } = self @@ -2125,13 +2132,12 @@ /// Returns `Ok` if `poly_trait_ref` being true implies that the /// obligation is satisfied. + #[instrument(skip(self), level = "debug")] fn match_poly_trait_ref( &mut self, obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result>, ()> { - debug!(?obligation, ?poly_trait_ref, "match_poly_trait_ref"); - self.infcx .at(&obligation.cause, obligation.param_env) .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) @@ -2175,12 +2181,12 @@ } } + #[instrument(skip(self), level = "debug")] fn closure_trait_ref_unnormalized( &mut self, obligation: &TraitObligation<'tcx>, substs: SubstsRef<'tcx>, ) -> ty::PolyTraitRef<'tcx> { - debug!(?obligation, ?substs, "closure_trait_ref_unnormalized"); let closure_sig = substs.as_closure().sig(); debug!(?closure_sig); @@ -2479,7 +2485,7 @@ "get_provisional = {:#?}", self.map.borrow().get(&fresh_trait_ref), ); - Some(self.map.borrow().get(&fresh_trait_ref)?.clone()) + Some(*self.map.borrow().get(&fresh_trait_ref)?) } /// Insert a provisional result into the cache. The result came diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs 2021-11-29 19:27:11.000000000 +0000 @@ -50,7 +50,7 @@ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); - self.nonblanket_impls.entry(st).or_default().push(impl_def_id) + self.non_blanket_impls.entry(st).or_default().push(impl_def_id) } else { debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id); self.blanket_impls.push(impl_def_id) @@ -65,7 +65,7 @@ let vec: &mut Vec; if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); - vec = self.nonblanket_impls.get_mut(&st).unwrap(); + vec = self.non_blanket_impls.get_mut(&st).unwrap(); } else { debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id); vec = &mut self.blanket_impls; @@ -104,19 +104,21 @@ let self_ty = trait_ref.self_ty(); // FIXME: should postpone string formatting until we decide to actually emit. - with_no_trimmed_paths(|| OverlapError { - with_impl: possible_sibling, - trait_desc: trait_ref.print_only_trait_path().to_string(), - // Only report the `Self` type if it has at least - // some outer concrete shell; otherwise, it's - // not adding much information. - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, - involves_placeholder: overlap.involves_placeholder, + with_no_trimmed_paths(|| { + OverlapError { + with_impl: possible_sibling, + trait_desc: trait_ref.print_only_trait_path().to_string(), + // Only report the `Self` type if it has at least + // some outer concrete shell; otherwise, it's + // not adding much information. + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }, + intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, + involves_placeholder: overlap.involves_placeholder, + } }) }; @@ -216,7 +218,7 @@ } fn iter_children(children: &mut Children) -> impl Iterator + '_ { - let nonblanket = children.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); + let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter()); children.blanket_impls.iter().chain(nonblanket).cloned() } @@ -224,7 +226,7 @@ children: &mut Children, st: SimplifiedType, ) -> impl Iterator + '_ { - let nonblanket = children.nonblanket_impls.entry(st).or_default().iter(); + let nonblanket = children.non_blanket_impls.entry(st).or_default().iter(); children.blanket_impls.iter().chain(nonblanket).cloned() } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/util.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/util.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/util.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/util.rs 2021-11-29 19:27:11.000000000 +0000 @@ -248,7 +248,7 @@ cause, param_env, recursion_depth, - predicate: trait_ref.without_const().to_predicate(tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), } } @@ -285,15 +285,10 @@ /// that come from `trait_ref`, excluding its supertraits. Used in /// computing the vtable base for an upcast trait of a trait object. pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { - let mut entries = 0; - // Count number of methods and add them to the total offset. - // Skip over associated types and constants. - for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() { - if trait_item.kind == ty::AssocKind::Fn { - entries += 1; - } - } - entries + let existential_trait_ref = + trait_ref.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let existential_trait_ref = tcx.erase_regions(existential_trait_ref); + tcx.own_existential_vtable_entries(existential_trait_ref).len() } /// Given an upcast trait object described by `object`, returns the @@ -304,22 +299,21 @@ object: &super::ImplSourceObjectData<'tcx, N>, method_def_id: DefId, ) -> usize { + let existential_trait_ref = object + .upcast_trait_ref + .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let existential_trait_ref = tcx.erase_regions(existential_trait_ref); // Count number of methods preceding the one we are selecting and // add them to the total offset. - // Skip over associated types and constants, as those aren't stored in the vtable. - let mut entries = object.vtable_base; - for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() { - if trait_item.def_id == method_def_id { - // The item with the ID we were given really ought to be a method. - assert_eq!(trait_item.kind, ty::AssocKind::Fn); - return entries; - } - if trait_item.kind == ty::AssocKind::Fn { - entries += 1; - } - } - - bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id); + let index = tcx + .own_existential_vtable_entries(existential_trait_ref) + .iter() + .copied() + .position(|def_id| def_id == method_def_id) + .unwrap_or_else(|| { + bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id); + }); + object.vtable_base + index } pub fn closure_trait_ref_and_return_type( diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/wf.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/wf.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/wf.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_trait_selection/src/traits/wf.rs 2021-11-29 19:27:11.000000000 +0000 @@ -209,7 +209,7 @@ _ => return, }; let fix_span = - |impl_item_ref: &hir::ImplItemRef<'_>| match tcx.hir().impl_item(impl_item_ref.id).kind { + |impl_item_ref: &hir::ImplItemRef| match tcx.hir().impl_item(impl_item_ref.id).kind { hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span, _ => impl_item_ref.span, }; @@ -349,7 +349,7 @@ new_cause, depth, param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx), ) }), ); @@ -399,7 +399,7 @@ cause.clone(), depth, param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx), ) }), ); @@ -416,7 +416,7 @@ cause, self.recursion_depth, self.param_env, - trait_ref.without_const().to_predicate(self.infcx.tcx), + ty::Binder::dummy(trait_ref).without_const().to_predicate(self.infcx.tcx), )); } } @@ -443,9 +443,9 @@ let obligations = self.nominal_obligations(uv.def.did, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable( + let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable( ty::Unevaluated::new(uv.def, substs), - ) + )) .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::with_depth( @@ -469,8 +469,10 @@ cause, self.recursion_depth, self.param_env, - ty::PredicateKind::WellFormed(resolved_constant.into()) - .to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed( + resolved_constant.into(), + )) + .to_predicate(self.tcx()), )); } } @@ -556,8 +558,10 @@ cause, depth, param_env, - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(rty, r)) - .to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(rty, r), + )) + .to_predicate(self.tcx()), )); } } @@ -646,7 +650,8 @@ cause.clone(), depth, param_env, - ty::PredicateKind::ObjectSafe(did).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did)) + .to_predicate(tcx), ) })); } @@ -673,7 +678,8 @@ cause, self.recursion_depth, param_env, - ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())) + .to_predicate(self.tcx()), )); } else { // Yes, resolved, proceed with the result. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_typeck" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] test = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/errors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/errors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -199,7 +199,7 @@ /// When there are any missing associated types, emit an E0191 error and attempt to supply a /// reasonable suggestion on how to write it. For the case of multiple associated types in the - /// same trait bound have the same name (as they come from different super-traits), we instead + /// same trait bound have the same name (as they come from different supertraits), we instead /// emit a generic note suggesting using a `where` clause to constraint instead. pub(crate) fn complain_about_missing_associated_types( &self, @@ -340,7 +340,7 @@ using the fully-qualified path to the associated types"; if !where_constraints.is_empty() && suggestions.is_empty() { // If there are duplicates associated type names and a single trait bound do not - // use structured suggestion, it means that there are multiple super-traits with + // use structured suggestion, it means that there are multiple supertraits with // the same associated type name. err.help(where_msg); } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/generics.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/generics.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/generics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/generics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -132,7 +132,7 @@ } let kind_ord = param.kind.to_ord(tcx); - let arg_ord = arg.to_ord(&tcx.features()); + let arg_ord = arg.to_ord(tcx.features()); // This note is only true when generic parameters are strictly ordered by their kind. if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { @@ -423,7 +423,7 @@ is_method_call: IsMethodCall, ) -> GenericArgCountResult { let empty_args = hir::GenericArgs::none(); - let suppress_mismatch = Self::check_impl_trait(tcx, seg, &generics); + let suppress_mismatch = Self::check_impl_trait(tcx, seg, generics); let gen_args = seg.args.unwrap_or(&empty_args); let gen_pos = if is_method_call == IsMethodCall::Yes { @@ -441,6 +441,7 @@ /// Checks that the correct number of generic arguments have been provided. /// This is used both for datatypes and function calls. + #[instrument(skip(tcx, gen_pos), level = "debug")] pub(crate) fn check_generic_arg_count( tcx: TyCtxt<'_>, span: Span, @@ -452,11 +453,6 @@ has_self: bool, infer_args: bool, ) -> GenericArgCountResult { - debug!( - "check_generic_arg_count(span: {:?}, def_id: {:?}, seg: {:?}, gen_params: {:?}, gen_args: {:?})", - span, def_id, seg, gen_params, gen_args - ); - let default_counts = gen_params.own_defaults(); let param_counts = gen_params.own_counts(); @@ -556,9 +552,12 @@ let mut check_types_and_consts = |expected_min, expected_max, provided, params_offset, args_offset| { debug!( - "check_types_and_consts(expected_min: {:?}, expected_max: {:?}, \ - provided: {:?}, params_offset: {:?}, args_offset: {:?}", - expected_min, expected_max, provided, params_offset, args_offset + ?expected_min, + ?expected_max, + ?provided, + ?params_offset, + ?args_offset, + "check_types_and_consts" ); if (expected_min..=expected_max).contains(&provided) { return true; @@ -589,7 +588,7 @@ } }; - debug!("gen_args_info: {:?}", gen_args_info); + debug!(?gen_args_info); WrongNumberOfGenericArgs::new( tcx, @@ -601,7 +600,7 @@ def_id, ) .diagnostic() - .emit(); + .emit_unless(gen_args.has_err()); false }; @@ -614,8 +613,8 @@ - default_counts.types - default_counts.consts }; - debug!("expected_min: {:?}", expected_min); - debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params()); + debug!(?expected_min); + debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params()); check_types_and_consts( expected_min, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/astconv/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -111,11 +111,6 @@ fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); } -pub enum SizedByDefault { - Yes, - No, -} - #[derive(Debug)] struct ConvertedBinding<'a, 'tcx> { hir_id: hir::HirId, @@ -357,8 +352,8 @@ span, def_id, seg, - &generics, - &generic_args, + generics, + generic_args, GenericArgPosition::Type, self_ty.is_some(), infer_args, @@ -368,7 +363,7 @@ // Traits always have `Self` as a generic parameter, which means they will not return early // here and so associated type bindings will be handled regardless of whether there are any // non-`Self` generic parameters. - if generics.params.len() == 0 { + if generics.params.is_empty() { return (tcx.intern_substs(&[]), arg_count); } @@ -422,7 +417,7 @@ let tcx = self.astconv.tcx(); match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.astconv.ast_region_to_region(<, Some(param)).into() + self.astconv.ast_region_to_region(lt, Some(param)).into() } (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { if has_default { @@ -446,7 +441,7 @@ self.inferred_params.push(ty.span); tcx.ty_error().into() } else { - self.astconv.ast_ty_to_ty(&ty).into() + self.astconv.ast_ty_to_ty(ty).into() } } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { @@ -627,10 +622,10 @@ .iter() .map(|binding| { let kind = match binding.kind { - hir::TypeBindingKind::Equality { ref ty } => { + hir::TypeBindingKind::Equality { ty } => { ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)) } - hir::TypeBindingKind::Constraint { ref bounds } => { + hir::TypeBindingKind::Constraint { bounds } => { ConvertedBindingKind::Constraint(bounds) } }; @@ -698,6 +693,61 @@ ) } + fn instantiate_poly_trait_ref_inner( + &self, + hir_id: hir::HirId, + span: Span, + binding_span: Option, + constness: ty::BoundConstness, + bounds: &mut Bounds<'tcx>, + speculative: bool, + trait_ref_span: Span, + trait_def_id: DefId, + trait_segment: &hir::PathSegment<'_>, + args: &GenericArgs<'_>, + infer_args: bool, + self_ty: Ty<'tcx>, + ) -> GenericArgCountResult { + let (substs, arg_count) = self.create_substs_for_ast_path( + trait_ref_span, + trait_def_id, + &[], + trait_segment, + args, + infer_args, + Some(self_ty), + ); + + let tcx = self.tcx(); + let bound_vars = tcx.late_bound_vars(hir_id); + debug!(?bound_vars); + + let assoc_bindings = self.create_assoc_bindings_for_generic_args(args); + + let poly_trait_ref = + ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars); + + debug!(?poly_trait_ref, ?assoc_bindings); + bounds.trait_bounds.push((poly_trait_ref, span, constness)); + + let mut dup_bindings = FxHashMap::default(); + for binding in &assoc_bindings { + // Specify type to assert that error was already reported in `Err` case. + let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( + hir_id, + poly_trait_ref, + binding, + bounds, + speculative, + &mut dup_bindings, + binding_span.unwrap_or(binding.span), + ); + // Okay to ignore `Err` because of `ErrorReported` (see above). + } + + arg_count + } + /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct /// a full trait reference. The resulting trait reference is returned. This may also generate /// auxiliary bounds, which are added to `bounds`. @@ -718,7 +768,7 @@ /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, /// however. #[tracing::instrument(level = "debug", skip(self, span, constness, bounds, speculative))] - pub fn instantiate_poly_trait_ref( + pub(crate) fn instantiate_poly_trait_ref( &self, trait_ref: &hir::TraitRef<'_>, span: Span, @@ -727,48 +777,34 @@ bounds: &mut Bounds<'tcx>, speculative: bool, ) -> GenericArgCountResult { + let hir_id = trait_ref.hir_ref_id; + let binding_span = None; + let trait_ref_span = trait_ref.path.span; let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); + let trait_segment = trait_ref.path.segments.last().unwrap(); + let args = trait_segment.args(); + let infer_args = trait_segment.infer_args; self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); + self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); - let tcx = self.tcx(); - let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); - debug!(?bound_vars); - - let (substs, arg_count) = self.create_substs_for_ast_trait_ref( - trait_ref.path.span, + self.instantiate_poly_trait_ref_inner( + hir_id, + span, + binding_span, + constness, + bounds, + speculative, + trait_ref_span, trait_def_id, + trait_segment, + args, + infer_args, self_ty, - trait_ref.path.segments.last().unwrap(), - ); - let assoc_bindings = self - .create_assoc_bindings_for_generic_args(trait_ref.path.segments.last().unwrap().args()); - - let poly_trait_ref = - ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars); - - debug!(?poly_trait_ref, ?assoc_bindings); - bounds.trait_bounds.push((poly_trait_ref, span, constness)); - - let mut dup_bindings = FxHashMap::default(); - for binding in &assoc_bindings { - // Specify type to assert that error was already reported in `Err` case. - let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( - trait_ref.hir_ref_id, - poly_trait_ref, - binding, - bounds, - speculative, - &mut dup_bindings, - binding.span, - ); - // Okay to ignore `Err` because of `ErrorReported` (see above). - } - - arg_count + ) } - pub fn instantiate_lang_item_trait_ref( + pub(crate) fn instantiate_lang_item_trait_ref( &self, lang_item: hir::LangItem, span: Span, @@ -777,36 +813,28 @@ self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, ) { + let binding_span = Some(span); + let constness = ty::BoundConstness::NotConst; + let speculative = false; + let trait_ref_span = span; let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); + let trait_segment = &hir::PathSegment::invalid(); + let infer_args = false; - let (substs, _) = self.create_substs_for_ast_path( + self.instantiate_poly_trait_ref_inner( + hir_id, span, + binding_span, + constness, + bounds, + speculative, + trait_ref_span, trait_def_id, - &[], - &hir::PathSegment::invalid(), + trait_segment, args, - false, - Some(self_ty), + infer_args, + self_ty, ); - let assoc_bindings = self.create_assoc_bindings_for_generic_args(args); - let tcx = self.tcx(); - let bound_vars = tcx.late_bound_vars(hir_id); - let poly_trait_ref = - ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars); - bounds.trait_bounds.push((poly_trait_ref, span, ty::BoundConstness::NotConst)); - - let mut dup_bindings = FxHashMap::default(); - for binding in assoc_bindings { - let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( - hir_id, - poly_trait_ref, - &binding, - bounds, - false, - &mut dup_bindings, - span, - ); - } } fn ast_path_to_mono_trait_ref( @@ -853,46 +881,73 @@ .is_some() } - // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { + // Sets `implicitly_sized` to true on `Bounds` if necessary + pub(crate) fn add_implicitly_sized<'hir>( + &self, + bounds: &mut Bounds<'hir>, + ast_bounds: &'hir [hir::GenericBound<'hir>], + self_ty_where_predicates: Option<(hir::HirId, &'hir [hir::WherePredicate<'hir>])>, + span: Span, + ) { let tcx = self.tcx(); // Try to find an unbound in bounds. let mut unbound = None; - for ab in ast_bounds { - if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { - if unbound.is_none() { - unbound = Some(&ptr.trait_ref); - } else { - tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); + let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| { + for ab in ast_bounds { + if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { + if unbound.is_none() { + unbound = Some(&ptr.trait_ref); + } else { + tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); + } + } + } + }; + search_bounds(ast_bounds); + if let Some((self_ty, where_clause)) = self_ty_where_predicates { + let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id(); + for clause in where_clause { + if let hir::WherePredicate::BoundPredicate(pred) = clause { + match pred.bounded_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res { + Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {} + _ => continue, + }, + _ => continue, + } + search_bounds(pred.bounds); } } } - let kind_id = tcx.lang_items().require(LangItem::Sized); - match unbound { - Some(tpb) => { - // FIXME(#8559) currently requires the unbound to be built-in. - if let Ok(kind_id) = kind_id { - if tpb.path.res != Res::Def(DefKind::Trait, kind_id) { - tcx.sess.span_warn( - span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default; only `?Sized` is supported", - ); - return false; - } - } + let sized_def_id = tcx.lang_items().require(LangItem::Sized); + match (&sized_def_id, unbound) { + (Ok(sized_def_id), Some(tpb)) + if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) => + { + // There was in fact a `?Sized` bound, return without doing anything + return; + } + (_, Some(_)) => { + // There was a `?Trait` bound, but it was not `?Sized`; warn. + tcx.sess.span_warn( + span, + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default; only `?Sized` is supported", + ); + // Otherwise, add implicitly sized if `Sized` is available. } - _ if kind_id.is_ok() => { - return false; + _ => { + // There was no `?Sized` bound; add implicitly sized if `Sized` is available. } + } + if sized_def_id.is_err() { // No lang item for `Sized`, so we can't add it as a bound. - None => {} + return; } - - true + bounds.implicitly_sized = Some(span); } /// This helper takes a *converted* parameter type (`param_ty`) @@ -910,46 +965,43 @@ /// **A note on binders:** there is an implied binder around /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` /// for more details. - #[tracing::instrument(level = "debug", skip(self, bounds))] - fn add_bounds( + #[tracing::instrument(level = "debug", skip(self, ast_bounds, bounds))] + pub(crate) fn add_bounds<'hir, I: Iterator>>( &self, param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], + ast_bounds: I, bounds: &mut Bounds<'tcx>, bound_vars: &'tcx ty::List, ) { for ast_bound in ast_bounds { - match *ast_bound { - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { - self.instantiate_poly_trait_ref( - &b.trait_ref, - b.span, - ty::BoundConstness::NotConst, + match ast_bound { + hir::GenericBound::Trait(poly_trait_ref, modifier) => { + let constness = match modifier { + hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst, + hir::TraitBoundModifier::None => ty::BoundConstness::NotConst, + hir::TraitBoundModifier::Maybe => continue, + }; + + let _ = self.instantiate_poly_trait_ref( + &poly_trait_ref.trait_ref, + poly_trait_ref.span, + constness, param_ty, bounds, false, ); } - hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { - self.instantiate_poly_trait_ref( - &b.trait_ref, - b.span, - ty::BoundConstness::ConstIfConst, - param_ty, - bounds, - false, + &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { + self.instantiate_lang_item_trait_ref( + lang_item, span, hir_id, args, param_ty, bounds, ); } - hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) - | hir::GenericBound::Unsized(_) => {} - hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self - .instantiate_lang_item_trait_ref( - lang_item, span, hir_id, args, param_ty, bounds, - ), - hir::GenericBound::Outlives(ref l) => bounds.region_bounds.push(( - ty::Binder::bind_with_vars(self.ast_region_to_region(l, None), bound_vars), - l.span, - )), + hir::GenericBound::Outlives(lifetime) => { + let region = self.ast_region_to_region(lifetime, None); + bounds + .region_bounds + .push((ty::Binder::bind_with_vars(region, bound_vars), lifetime.span)); + } } } } @@ -970,24 +1022,20 @@ /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. /// /// `span` should be the declaration size of the parameter. - pub fn compute_bounds( + pub(crate) fn compute_bounds( &self, param_ty: Ty<'tcx>, ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, ) -> Bounds<'tcx> { - self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span) + self.compute_bounds_inner(param_ty, ast_bounds) } /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type /// named `assoc_name` into ty::Bounds. Ignore the rest. - pub fn compute_bounds_that_match_assoc_type( + pub(crate) fn compute_bounds_that_match_assoc_type( &self, param_ty: Ty<'tcx>, ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, assoc_name: Ident, ) -> Bounds<'tcx> { let mut result = Vec::new(); @@ -1002,25 +1050,17 @@ } } - self.compute_bounds_inner(param_ty, &result, sized_by_default, span) + self.compute_bounds_inner(param_ty, &result) } fn compute_bounds_inner( &self, param_ty: Ty<'tcx>, ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, ) -> Bounds<'tcx> { let mut bounds = Bounds::default(); - self.add_bounds(param_ty, ast_bounds, &mut bounds, ty::List::empty()); - - bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } - } else { - None - }; + self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty()); bounds } @@ -1188,7 +1228,7 @@ } match binding.kind { - ConvertedBindingKind::Equality(ref ty) => { + ConvertedBindingKind::Equality(ty) => { // "Desugar" a constraint like `T: Iterator` this to // the "projection predicate" for: // @@ -1212,7 +1252,7 @@ // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` // parameter to have a skipped binder. let param_ty = tcx.mk_ty(ty::Projection(projection_ty.skip_binder())); - self.add_bounds(param_ty, ast_bounds, bounds, candidate.bound_vars()); + self.add_bounds(param_ty, ast_bounds.iter(), bounds, candidate.bound_vars()); } } Ok(()) @@ -1279,7 +1319,7 @@ ); first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); err.help(&format!( - "consider creating a new trait with all of these as super-traits and using that \ + "consider creating a new trait with all of these as supertraits and using that \ trait here instead: `trait NewTrait: {} {{}}`", regular_traits .iter() @@ -1495,9 +1535,8 @@ let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); if let (true, Ok(snippet)) = ( self.tcx() - .sess + .resolutions(()) .confused_type_with_std_module - .borrow() .keys() .any(|full_span| full_span.contains(span)), self.tcx().sess.source_map().span_to_snippet(span), @@ -1645,14 +1684,13 @@ constraint=constraint, )); } else { - err.span_suggestion( - span, + err.span_suggestion_verbose( + span.with_hi(assoc_name.span.lo()), "use fully qualified syntax to disambiguate", format!( - "<{} as {}>::{}", + "<{} as {}>::", ty_param_name(), bound.print_only_trait_path(), - assoc_name, ), Applicability::MaybeIncorrect, ); @@ -2166,7 +2204,7 @@ assert_eq!(opt_self_ty, None); let path_segs = - self.def_ids_for_value_path_segments(&path.segments, None, kind, def_id); + self.def_ids_for_value_path_segments(path.segments, None, kind, def_id); let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); self.prohibit_generics(path.segments.iter().enumerate().filter_map( @@ -2263,34 +2301,32 @@ let tcx = self.tcx(); let result_ty = match ast_ty.kind { - hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(&ty)), + hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)), hir::TyKind::Ptr(ref mt) => { - tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl }) + tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl }) } hir::TyKind::Rptr(ref region, ref mt) => { let r = self.ast_region_to_region(region, None); debug!(?r); - let t = self.ast_ty_to_ty_inner(&mt.ty, true); + let t = self.ast_ty_to_ty_inner(mt.ty, true); tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) } hir::TyKind::Never => tcx.types.never, - hir::TyKind::Tup(ref fields) => { - tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t))) - } - hir::TyKind::BareFn(ref bf) => { - require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); + hir::TyKind::Tup(fields) => tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(t))), + hir::TyKind::BareFn(bf) => { + require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span); tcx.mk_fn_ptr(self.ty_of_fn( ast_ty.hir_id, bf.unsafety, bf.abi, - &bf.decl, + bf.decl, &hir::Generics::empty(), None, Some(ast_ty), )) } - hir::TyKind::TraitObject(ref bounds, ref lifetime, _) => { + hir::TyKind::TraitObject(bounds, ref lifetime, _) => { self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) } hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { @@ -2298,7 +2334,7 @@ let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); self.res_to_ty(opt_self_ty, path, false) } - hir::TyKind::OpaqueDef(item_id, ref lifetimes) => { + hir::TyKind::OpaqueDef(item_id, lifetimes) => { let opaque_ty = tcx.hir().item(item_id); let def_id = item_id.def_id.to_def_id(); @@ -2313,7 +2349,7 @@ debug!(?qself, ?segment); let ty = self.ast_ty_to_ty(qself); - let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind { + let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind { path.res } else { Res::Err @@ -2338,7 +2374,7 @@ hir::TyKind::Array(ref ty, ref length) => { let length_def_id = tcx.hir().local_def_id(length.hir_id); let length = ty::Const::from_anon_const(tcx, length_def_id); - let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); + let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length)); self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref e) => { @@ -2376,13 +2412,14 @@ let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { // Our own parameters are the resolved lifetimes. - match param.kind { - GenericParamDefKind::Lifetime - if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] => - { + if let GenericParamDefKind::Lifetime = param.kind { + if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { self.ast_region_to_region(lifetime, None).into() + } else { + bug!() } - _ => bug!(), + } else { + bug!() } } else { match param.kind { @@ -2443,7 +2480,7 @@ let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None)); let output_ty = match decl.output { - hir::FnRetTy::Return(ref output) => { + hir::FnRetTy::Return(output) => { visitor.visit_ty(output); self.ast_ty_to_ty(output) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/callee.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/callee.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/callee.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/callee.rs 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; -use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -72,7 +72,16 @@ arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let original_callee_ty = self.check_expr(callee_expr); + let original_callee_ty = match &callee_expr.kind { + hir::ExprKind::Path(hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)) => self + .check_expr_with_expectation_and_args( + callee_expr, + Expectation::NoExpectation, + arg_exprs, + ), + _ => self.check_expr(callee_expr), + }; + let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty); let mut autoderef = self.autoderef(callee_expr.span, expr_ty); @@ -237,12 +246,18 @@ if borrow { // Check for &self vs &mut self in the method signature. Since this is either // the Fn or FnMut trait, it should be one of those. - let (region, mutbl) = - if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind() { - (r, mutbl) - } else { - span_bug!(call_expr.span, "input to call/call_mut is not a ref?"); - }; + let (region, mutbl) = if let ty::Ref(r, _, mutbl) = + method.sig.inputs()[0].kind() + { + (r, mutbl) + } else { + // The `fn`/`fn_mut` lang item is ill-formed, which should have + // caused an error elsewhere. + self.tcx + .sess + .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref?"); + return None; + }; let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, @@ -302,6 +317,8 @@ ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { ty::FnDef(def_id, subst) => { + let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst); + // Unit testing: function items annotated with // `#[rustc_evaluate_where_clauses]` trigger special output // to let us test the trait evaluation system. @@ -314,7 +331,7 @@ let obligation = Obligation::new( ObligationCause::dummy_with_span(callee_expr.span), self.param_env, - predicate.clone(), + *predicate, ); let result = self.infcx.evaluate_obligation(&obligation); self.tcx @@ -327,7 +344,7 @@ .emit(); } } - (callee_ty.fn_sig(self.tcx), Some(def_id)) + (fn_sig, Some(def_id)) } ty::FnPtr(sig) => (sig, None), ref t => { @@ -341,6 +358,7 @@ } } + let callee_ty = self.resolve_vars_if_possible(callee_ty); let mut err = type_error_struct!( self.tcx.sess, callee_expr.span, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/cast.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/cast.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/cast.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/cast.rs 2021-11-29 19:27:11.000000000 +0000 @@ -351,7 +351,7 @@ ); let mut sugg = None; let mut sugg_mutref = false; - if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() { + if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() { if fcx .try_coerce( @@ -362,10 +362,11 @@ ), self.cast_ty, AllowTwoPhase::No, + None, ) .is_ok() { - sugg = Some(format!("&{}*", mutbl.prefix_str())); + sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty)); } } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() { if expr_mutbl == Mutability::Not @@ -379,6 +380,7 @@ ), self.cast_ty, AllowTwoPhase::No, + None, ) .is_ok() { @@ -394,10 +396,11 @@ fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }), self.cast_ty, AllowTwoPhase::No, + None, ) .is_ok() { - sugg = Some(format!("&{}", mutbl.prefix_str())); + sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() { if fcx @@ -409,22 +412,51 @@ ), self.cast_ty, AllowTwoPhase::No, + None, ) .is_ok() { - sugg = Some(format!("&{}", mutbl.prefix_str())); + sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } if sugg_mutref { err.span_label(self.span, "invalid cast"); err.span_note(self.expr.span, "this reference is immutable"); err.span_note(self.cast_span, "trying to cast to a mutable reference type"); - } else if let Some(sugg) = sugg { + } else if let Some((sugg, remove_cast)) = sugg { err.span_label(self.span, "invalid cast"); - err.span_suggestion_verbose( - self.expr.span.shrink_to_lo(), + + let has_parens = fcx + .tcx + .sess + .source_map() + .span_to_snippet(self.expr.span) + .map_or(false, |snip| snip.starts_with('(')); + + // Very crude check to see whether the expression must be wrapped + // in parentheses for the suggestion to work (issue #89497). + // Can/should be extended in the future. + let needs_parens = !has_parens + && match self.expr.kind { + hir::ExprKind::Cast(..) => true, + _ => false, + }; + + let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)]; + if needs_parens { + suggestion[0].1 += "("; + suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string())); + } + if remove_cast { + suggestion.push(( + self.expr.span.shrink_to_hi().to(self.cast_span), + String::new(), + )); + } + + err.multipart_suggestion_verbose( "consider borrowing the value", - sugg, + suggestion, Applicability::MachineApplicable, ); } else if !matches!( @@ -434,7 +466,7 @@ let mut label = true; // Check `impl From for self.cast_ty {}` for accurate suggestion: if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { - if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) { + if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) { let ty = fcx.resolve_vars_if_possible(self.cast_ty); // Erase regions to avoid panic in `prove_value` when calling // `type_implements_trait`. @@ -666,6 +698,7 @@ self.expr_ty, fcx.tcx.mk_fn_ptr(f), AllowTwoPhase::No, + None, ); if let Err(TypeError::IntrinsicCast) = res { return Err(CastError::IllegalCast); @@ -829,7 +862,7 @@ // Coerce to a raw pointer so that we generate AddressOf in MIR. let array_ptr_type = fcx.tcx.mk_ptr(m_expr); - fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No) + fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) .unwrap_or_else(|_| { bug!( "could not cast from reference to array to pointer to array ({:?} to {:?})", @@ -861,7 +894,7 @@ } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> { - match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) { + match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) { Ok(_) => Ok(()), Err(err) => Err(err), } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/check.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/check.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/check.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/check.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,7 +31,7 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) { let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().par_visit_all_item_likes(&visit); + tcx.hir().par_visit_all_item_likes(&visit); } pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { @@ -58,7 +58,7 @@ tcx.sess, span, E0781, - "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers." + "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" ) .emit() } @@ -70,6 +70,7 @@ /// /// * ... /// * inherited: other fields inherited from the enclosing fn (if any) +#[instrument(skip(inherited, body), level = "debug")] pub(super) fn check_fn<'a, 'tcx>( inherited: &'a Inherited<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -82,8 +83,6 @@ ) -> (FnCtxt<'a, 'tcx>, Option>) { let mut fn_sig = fn_sig; - debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); - // Create the function context. This is either derived from scratch or, // in the case of closures, based on the outer context. let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); @@ -214,7 +213,7 @@ fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); } else { fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - fcx.check_return_expr(&body.value); + fcx.check_return_expr(&body.value, false); } fcx.in_tail_expr = false; @@ -241,32 +240,16 @@ // we saw and assigning it to the expected return type. This isn't // really expected to fail, since the coercions would have failed // earlier when trying to find a LUB. - // - // However, the behavior around `!` is sort of complex. In the - // event that the `actual_return_ty` comes back as `!`, that - // indicates that the fn either does not return or "returns" only - // values of type `!`. In this case, if there is an expected - // return type that is *not* `!`, that should be ok. But if the - // return type is being inferred, we want to "fallback" to `!`: - // - // let x = move || panic!(); - // - // To allow for that, I am creating a type variable with diverging - // fallback. This was deemed ever so slightly better than unifying - // the return value with `!` because it allows for the caller to - // make more assumptions about the return type (e.g., they could do - // - // let y: Option = Some(x()); - // - // which would then cause this return type to become `u32`, not - // `!`). let coercion = fcx.ret_coercion.take().unwrap().into_inner(); let mut actual_return_ty = coercion.complete(&fcx); - if actual_return_ty.is_never() { - actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::DivergingFn, - span, - }); + debug!("actual_return_ty = {:?}", actual_return_ty); + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // We have special-cased the case where the function is declared + // `-> dyn Foo` and we don't actually relate it to the + // `fcx.ret_coercion`, so just substitute a type variable. + actual_return_ty = + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); + debug!("actual_return_ty replaced with {:?}", actual_return_ty); } fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); @@ -688,7 +671,7 @@ // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, hir_id); - fcx.regionck_item(hir_id, span, &[]); + fcx.regionck_item(hir_id, span, FxHashSet::default()); }); } @@ -906,7 +889,7 @@ full_impl_span: Span, impl_id: LocalDefId, impl_trait_ref: ty::TraitRef<'tcx>, - impl_item_refs: &[hir::ImplItemRef<'_>], + impl_item_refs: &[hir::ImplItemRef], ) { // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/closure.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/closure.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/closure.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -33,6 +33,7 @@ } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + #[instrument(skip(self, expr, _capture, decl, body_id), level = "debug")] pub fn check_expr_closure( &self, expr: &hir::Expr<'_>, @@ -42,7 +43,8 @@ gen: Option, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); + trace!("decl = {:#?}", decl); + trace!("expr = {:#?}", expr); // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected @@ -55,6 +57,7 @@ self.check_closure(expr, expected_kind, decl, body, gen, expected_sig) } + #[instrument(skip(self, expr, body, decl), level = "debug")] fn check_closure( &self, expr: &hir::Expr<'_>, @@ -64,14 +67,14 @@ gen: Option, expected_sig: Option>, ) -> Ty<'tcx> { - debug!("check_closure(opt_kind={:?}, expected_sig={:?})", opt_kind, expected_sig); - + trace!("decl = {:#?}", decl); let expr_def_id = self.tcx.hir().local_def_id(expr.hir_id); + debug!(?expr_def_id); let ClosureSignatures { bound_sig, liberated_sig } = self.sig_of_closure(expr.hir_id, expr_def_id.to_def_id(), decl, body, expected_sig); - debug!("check_closure: ty_of_closure returns {:?}", liberated_sig); + debug!(?bound_sig, ?liberated_sig); let return_type_pre_known = !liberated_sig.output().is_ty_infer(); @@ -130,10 +133,7 @@ ) }); - debug!( - "check_closure: expr_def_id={:?}, sig={:?}, opt_kind={:?}", - expr_def_id, sig, opt_kind - ); + debug!(?sig, ?opt_kind); let closure_kind_ty = match opt_kind { Some(kind) => kind.to_ty(self.tcx), @@ -159,19 +159,18 @@ let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs); - debug!("check_closure: expr.hir_id={:?} closure_type={:?}", expr.hir_id, closure_type); + debug!(?expr.hir_id, ?closure_type); closure_type } /// Given the expected type, figures out what it can about this closure we /// are about to type check: + #[instrument(skip(self), level = "debug")] fn deduce_expectations_from_expected_type( &self, expected_ty: Ty<'tcx>, ) -> (Option>, Option) { - debug!("deduce_expectations_from_expected_type(expected_ty={:?})", expected_ty); - match *expected_ty.kind() { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -314,6 +313,7 @@ /// If there is no expected signature, then we will convert the /// types that the user gave into a signature. + #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")] fn sig_of_closure_no_expectation( &self, hir_id: hir::HirId, @@ -321,8 +321,6 @@ decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, ) -> ClosureSignatures<'tcx> { - debug!("sig_of_closure_no_expectation()"); - let bound_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body); self.closure_sigs(expr_def_id, body, bound_sig) @@ -375,6 +373,7 @@ /// - `expected_sig`: the expected signature (if any). Note that /// this is missing a binder: that is, there may be late-bound /// regions with depth 1, which are bound then by the closure. + #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")] fn sig_of_closure_with_expectation( &self, hir_id: hir::HirId, @@ -383,8 +382,6 @@ body: &hir::Body<'_>, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { - debug!("sig_of_closure_with_expectation(expected_sig={:?})", expected_sig); - // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. @@ -553,6 +550,7 @@ /// types that the user gave into a signature. /// /// Also, record this closure signature for later. + #[instrument(skip(self, decl, body), level = "debug")] fn supplied_sig_of_closure( &self, hir_id: hir::HirId, @@ -562,10 +560,8 @@ ) -> ty::PolyFnSig<'tcx> { let astconv: &dyn AstConv<'_> = self; - debug!( - "supplied_sig_of_closure(decl={:?}, body.generator_kind={:?})", - decl, body.generator_kind, - ); + trace!("decl = {:#?}", decl); + debug!(?body.generator_kind); let bound_vars = self.tcx.late_bound_vars(hir_id); @@ -578,7 +574,7 @@ // we expect the return type of the block to match that of the enclosing // function. Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => { - debug!("supplied_sig_of_closure: closure is async fn body"); + debug!("closure is async fn body"); self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| { // AFAIK, deducing the future output // always succeeds *except* in error cases @@ -606,7 +602,7 @@ bound_vars, ); - debug!("supplied_sig_of_closure: result={:?}", result); + debug!(?result); let c_result = self.inh.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/coercion.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/coercion.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/coercion.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/coercion.rs 2021-11-29 19:27:11.000000000 +0000 @@ -42,7 +42,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; -use rustc_infer::traits::Obligation; +use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, @@ -54,7 +54,7 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{self, BytePos, Span}; +use rustc_span::{self, BytePos, DesugaringKind, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -146,6 +146,7 @@ .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations)) } + #[instrument(skip(self))] fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { // First, remove any resolved type variables (at the top level, at least): let a = self.shallow_resolve(a); @@ -159,24 +160,7 @@ // Coercing from `!` to any type is allowed: if a.is_never() { - // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound - // type variable, we want `?T` to fallback to `!` if not - // otherwise constrained. An example where this arises: - // - // let _: Option = Some({ return; }); - // - // here, we would coerce from `!` to `?T`. - return if b.is_ty_var() { - // Micro-optimization: no need for this if `b` is - // already resolved in some way. - let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::AdjustmentType, - span: self.cause.span, - }); - self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny)) - } else { - success(simple(Adjust::NeverToAny)(b), b, vec![]) - }; + return success(simple(Adjust::NeverToAny)(b), b, vec![]); } // Coercing *from* an unresolved inference variable means that @@ -273,10 +257,10 @@ obligations.push(Obligation::new( self.cause.clone(), self.param_env, - ty::PredicateKind::Coerce(ty::CoercePredicate { + ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate { a: source_ty, b: target_ty, - }) + })) .to_predicate(self.tcx()), )); } @@ -499,12 +483,11 @@ // &[T; n] or &mut [T; n] -> &[T] // or &mut [T; n] -> &mut [T] // or &Concrete -> &Trait, etc. + #[instrument(skip(self), level = "debug")] fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { - debug!("coerce_unsized(source={:?}, target={:?})", source, target); - source = self.shallow_resolve(source); target = self.shallow_resolve(target); - debug!("coerce_unsized: resolved source={:?} target={:?}", source, target); + debug!(?source, ?target); // These 'if' statements require some explanation. // The `CoerceUnsized` trait is special - it is only @@ -707,13 +690,7 @@ // Object safety violations or miscellaneous. Err(err) => { - self.report_selection_error( - obligation.clone(), - &obligation, - &err, - false, - false, - ); + self.report_selection_error(obligation.clone(), &obligation, &err, false); // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. @@ -941,11 +918,13 @@ expr_ty: Ty<'tcx>, target: Ty<'tcx>, allow_two_phase: AllowTwoPhase, + cause: Option>, ) -> RelateResult<'tcx, Ty<'tcx>> { let source = self.resolve_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); - let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); + let cause = + cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable)); let coerce = Coerce::new(self, cause, allow_two_phase); let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; @@ -955,14 +934,25 @@ } /// Same as `try_coerce()`, but without side-effects. + /// + /// Returns false if the coercion creates any obligations that result in + /// errors. pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool { let source = self.resolve_vars_with_obligations(expr_ty); - debug!("coercion::can({:?} -> {:?})", source, target); + debug!("coercion::can_with_predicates({:?} -> {:?})", source, target); let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion let coerce = Coerce::new(self, cause, AllowTwoPhase::No); - self.probe(|_| coerce.coerce(source, target)).is_ok() + self.probe(|_| { + let ok = match coerce.coerce(source, target) { + Ok(ok) => ok, + _ => return false, + }; + let mut fcx = traits::FulfillmentContext::new_in_snapshot(); + fcx.register_predicate_obligations(self, ok.obligations); + fcx.select_where_possible(&self).is_ok() + }) } /// Given a type and a target type, this function will calculate and return @@ -1003,6 +993,12 @@ exprs.len() ); + // The following check fixes #88097, where the compiler erroneously + // attempted to coerce a closure type to itself via a function pointer. + if prev_ty == new_ty { + return Ok(prev_ty); + } + // Special-case that coercion alone cannot handle: // Function items or non-capturing closures of differing IDs or InternalSubsts. let (a_sig, b_sig) = { @@ -1363,7 +1359,13 @@ // Special-case the first expression we are coercing. // To be honest, I'm not entirely sure why we do this. // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why - fcx.try_coerce(expression, expression_ty, self.expected_ty, AllowTwoPhase::No) + fcx.try_coerce( + expression, + expression_ty, + self.expected_ty, + AllowTwoPhase::No, + Some(cause.clone()), + ) } else { match self.expressions { Expressions::Dynamic(ref exprs) => fcx.try_find_coercion_lub( @@ -1494,21 +1496,7 @@ fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None); } - // Error possibly reported in `check_assign` so avoid emitting error again. - let assign_to_bool = expression - // #67273: Use initial expected type as opposed to `expected`. - // Otherwise we end up using prior coercions in e.g. a `match` expression: - // ``` - // match i { - // 0 => true, // Because of this... - // 1 => i = 1, // ...`expected == bool` now, but not when checking `i = 1`. - // _ => (), - // }; - // ``` - .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty())) - .is_some(); - - err.emit_unless(assign_to_bool || unsized_return); + err.emit_unless(unsized_return); self.final_ty = Some(fcx.tcx.ty_error()); } @@ -1546,8 +1534,10 @@ // If the block is from an external macro or try (`?`) desugaring, then // do not suggest adding a semicolon, because there's nowhere to put it. // See issues #81943 and #87051. - if cond_expr.span.desugaring_kind().is_none() - && !in_external_macro(fcx.tcx.sess, cond_expr.span) + if matches!( + cond_expr.span.desugaring_kind(), + None | Some(DesugaringKind::WhileLoop) + ) && !in_external_macro(fcx.tcx.sess, cond_expr.span) && !matches!( cond_expr.kind, hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/compare_method.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/compare_method.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/compare_method.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/compare_method.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,5 @@ use crate::errors::LifetimesOrBoundsMismatchOnTrait; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -250,7 +251,7 @@ // Compute placeholder form of impl and trait method tys. let tcx = infcx.tcx; - let mut wf_tys = vec![]; + let mut wf_tys = FxHashSet::default(); let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, @@ -265,14 +266,9 @@ // First liberate late bound regions and subst placeholders let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id)); let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs); - // Next, add all inputs and output as well-formed tys. Importantly, - // we have to do this before normalization, since the normalized ty may - // not contain the input parameters. See issue #87748. - wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig); - // Also add the resulting inputs and output as well-formed. - // This probably isn't strictly necessary. + // Add the resulting inputs and output as well-formed. wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); @@ -398,7 +394,7 @@ // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id); - fcx.regionck_item(impl_m_hir_id, impl_m_span, &wf_tys); + fcx.regionck_item(impl_m_hir_id, impl_m_span, wf_tys); Ok(()) }) @@ -1098,7 +1094,7 @@ } let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id); - fcx.regionck_item(impl_c_hir_id, impl_c_span, &[]); + fcx.regionck_item(impl_c_hir_id, impl_c_span, FxHashSet::default()); }); } @@ -1216,7 +1212,7 @@ // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); - fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]); + fcx.regionck_item(impl_ty_hir_id, impl_ty_span, FxHashSet::default()); Ok(()) }) @@ -1436,10 +1432,10 @@ // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); let implied_bounds = match impl_ty.container { - ty::TraitContainer(_) => vec![], + ty::TraitContainer(_) => FxHashSet::default(), ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span), }; - fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &implied_bounds); + fcx.regionck_item(impl_ty_hir_id, impl_ty_span, implied_bounds); Ok(()) }) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/demand.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/demand.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/demand.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/demand.rs 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,6 @@ use super::method::probe; -use std::fmt; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -60,6 +59,7 @@ self.demand_suptype_with_origin(&self.misc(sp), expected, actual) } + #[instrument(skip(self), level = "debug")] pub fn demand_suptype_with_origin( &self, cause: &ObligationCause<'tcx>, @@ -135,22 +135,17 @@ ) -> (Ty<'tcx>, Option>) { let expected = self.resolve_vars_with_obligations(expected); - let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase) { + let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) { Ok(ty) => return (ty, None), Err(e) => e, }; + self.set_tainted_by_errors(); let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); let expr_ty = self.resolve_vars_with_obligations(checked_ty); let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); - if self.is_assign_to_bool(expr, expected) { - // Error reported in `check_assign` so avoid emitting error again. - err.delay_as_bug(); - return (expected, None); - } - self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr); (expected, Some(err)) @@ -172,14 +167,6 @@ } } - /// Returns whether the expected type is `bool` and the expression is `x = y`. - pub fn is_assign_to_bool(&self, expr: &hir::Expr<'_>, expected: Ty<'tcx>) -> bool { - if let hir::ExprKind::Assign(..) = expr.kind { - return expected == self.tcx.types.bool; - } - false - } - /// If the expected type is an enum (Issue #55250) with any variants whose /// sole field is of the found type, suggest such variants. (Issue #42764) fn suggest_compatible_variants( @@ -589,7 +576,8 @@ // E.g. for `&format!("")`, where we want the span to the // `format!()` invocation instead of its expansion. if let Some(call_span) = - iter::successors(Some(expr.span), |s| s.parent()).find(|&s| sp.contains(s)) + iter::successors(Some(expr.span), |s| s.parent_callsite()) + .find(|&s| sp.contains(s)) { if sm.span_to_snippet(call_span).is_ok() { return Some(( @@ -771,9 +759,10 @@ // For now, don't suggest casting with `as`. let can_cast = false; - let prefix = if let Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Struct(_, fields, _), - .. + let mut sugg = vec![]; + + if let Some(hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Struct(_, fields, _), .. })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) { // `expr` is a literal field for a struct, only suggest if appropriate @@ -782,12 +771,12 @@ .find(|field| field.expr.hir_id == expr.hir_id && field.is_shorthand) { // This is a field literal - Some(field) => format!("{}: ", field.ident), + Some(field) => { + sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident))); + } // Likely a field was meant, but this field wasn't found. Do not suggest anything. None => return false, } - } else { - String::new() }; if let hir::ExprKind::Call(path, args) = &expr.kind { @@ -842,28 +831,38 @@ checked_ty, expected_ty, ); - let with_opt_paren: fn(&dyn fmt::Display) -> String = - if expr.precedence().order() < PREC_POSTFIX { - |s| format!("({})", s) - } else { - |s| s.to_string() - }; + let close_paren = if expr.precedence().order() < PREC_POSTFIX { + sugg.push((expr.span.shrink_to_lo(), "(".to_string())); + ")" + } else { + "" + }; - let cast_suggestion = format!("{}{} as {}", prefix, with_opt_paren(&src), expected_ty); - let into_suggestion = format!("{}{}.into()", prefix, with_opt_paren(&src)); - let suffix_suggestion = with_opt_paren(&format_args!( - "{}{}", + let mut cast_suggestion = sugg.clone(); + cast_suggestion + .push((expr.span.shrink_to_hi(), format!("{} as {}", close_paren, expected_ty))); + let mut into_suggestion = sugg.clone(); + into_suggestion.push((expr.span.shrink_to_hi(), format!("{}.into()", close_paren))); + let mut suffix_suggestion = sugg.clone(); + suffix_suggestion.push(( if matches!( (&expected_ty.kind(), &checked_ty.kind()), (ty::Int(_) | ty::Uint(_), ty::Float(_)) ) { // Remove fractional part from literal, for example `42.0f32` into `42` let src = src.trim_end_matches(&checked_ty.to_string()); - src.split('.').next().unwrap() + let len = src.split('.').next().unwrap().len(); + expr.span.with_lo(expr.span.lo() + BytePos(len as u32)) } else { - src.trim_end_matches(&checked_ty.to_string()) + let len = src.trim_end_matches(&checked_ty.to_string()).len(); + expr.span.with_lo(expr.span.lo() + BytePos(len as u32)) + }, + if expr.precedence().order() < PREC_POSTFIX { + // Readd `)` + format!("{})", expected_ty) + } else { + expected_ty.to_string() }, - expected_ty, )); let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| { if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false } @@ -890,22 +889,32 @@ .ok() .map(|src| (expr, src)) }); - let (span, msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) = + let (msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) = (lhs_expr_and_src, exp_to_found_is_fallible) { let msg = format!( "you can convert `{}` from `{}` to `{}`, matching the type of `{}`", lhs_src, expected_ty, checked_ty, src ); - let suggestion = format!("{}::from({})", checked_ty, lhs_src); - (lhs_expr.span, msg, suggestion) + let suggestion = vec![ + (lhs_expr.span.shrink_to_lo(), format!("{}::from(", checked_ty)), + (lhs_expr.span.shrink_to_hi(), ")".to_string()), + ]; + (msg, suggestion) } else { let msg = format!("{} and panic if the converted value doesn't fit", msg); - let suggestion = - format!("{}{}.try_into().unwrap()", prefix, with_opt_paren(&src)); - (expr.span, msg, suggestion) + let mut suggestion = sugg.clone(); + suggestion.push(( + expr.span.shrink_to_hi(), + format!("{}.try_into().unwrap()", close_paren), + )); + (msg, suggestion) }; - err.span_suggestion(span, &msg, suggestion, Applicability::MachineApplicable); + err.multipart_suggestion_verbose( + &msg, + suggestion, + Applicability::MachineApplicable, + ); }; let suggest_to_change_suffix_or_into = @@ -943,7 +952,7 @@ } else { into_suggestion.clone() }; - err.span_suggestion(expr.span, msg, suggestion, Applicability::MachineApplicable); + err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable); }; match (&expected_ty.kind(), &checked_ty.kind()) { @@ -997,16 +1006,14 @@ if found.bit_width() < exp.bit_width() { suggest_to_change_suffix_or_into(err, false, true); } else if literal_is_ty_suffixed(expr) { - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &lit_msg, suffix_suggestion, Applicability::MachineApplicable, ); } else if can_cast { // Missing try_into implementation for `f64` to `f32` - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &format!("{}, producing the closest possible value", cast_msg), cast_suggestion, Applicability::MaybeIncorrect, // lossy conversion @@ -1016,16 +1023,14 @@ } (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => { if literal_is_ty_suffixed(expr) { - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &lit_msg, suffix_suggestion, Applicability::MachineApplicable, ); } else if can_cast { // Missing try_into implementation for `{float}` to `{integer}` - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &format!("{}, rounding the float towards zero", msg), cast_suggestion, Applicability::MaybeIncorrect, // lossy conversion @@ -1036,8 +1041,7 @@ (&ty::Float(ref exp), &ty::Uint(ref found)) => { // if `found` is `None` (meaning found is `usize`), don't suggest `.into()` if exp.bit_width() > found.bit_width().unwrap_or(256) { - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &format!( "{}, producing the floating point representation of the integer", msg, @@ -1046,16 +1050,14 @@ Applicability::MachineApplicable, ); } else if literal_is_ty_suffixed(expr) { - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &lit_msg, suffix_suggestion, Applicability::MachineApplicable, ); } else { // Missing try_into implementation for `{integer}` to `{float}` - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &format!( "{}, producing the floating point representation of the integer, rounded if necessary", @@ -1070,8 +1072,7 @@ (&ty::Float(ref exp), &ty::Int(ref found)) => { // if `found` is `None` (meaning found is `isize`), don't suggest `.into()` if exp.bit_width() > found.bit_width().unwrap_or(256) { - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &format!( "{}, producing the floating point representation of the integer", &msg, @@ -1080,16 +1081,14 @@ Applicability::MachineApplicable, ); } else if literal_is_ty_suffixed(expr) { - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &lit_msg, suffix_suggestion, Applicability::MachineApplicable, ); } else { // Missing try_into implementation for `{integer}` to `{float}` - err.span_suggestion( - expr.span, + err.multipart_suggestion_verbose( &format!( "{}, producing the floating point representation of the integer, \ rounded if necessary", diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/dropck.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/dropck.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/dropck.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/dropck.rs 2021-11-29 19:27:11.000000000 +0000 @@ -239,8 +239,12 @@ ty::PredicateKind::ConstEvaluatable(a), ty::PredicateKind::ConstEvaluatable(b), ) => tcx.try_unify_abstract_consts((a, b)), - (ty::PredicateKind::TypeOutlives(a), ty::PredicateKind::TypeOutlives(b)) => { - relator.relate(predicate.rebind(a.0), p.rebind(b.0)).is_ok() + ( + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)), + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)), + ) => { + relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok() + && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok() } _ => predicate == p, } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/expr.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/expr.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/expr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/expr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -77,7 +77,7 @@ !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id), "expression with never type wound up being adjusted" ); - let adj_ty = self.next_diverging_ty_var(TypeVariableOrigin { + let adj_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::AdjustmentType, span: expr.span, }); @@ -92,8 +92,7 @@ let expr = expr.peel_drop_temps(); self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None); extend_err(&mut err); - // Error possibly reported in `check_assign` so avoid emitting error again. - err.emit_unless(self.is_assign_to_bool(expr, expected_ty)); + err.emit(); } ty } @@ -156,12 +155,23 @@ /// Note that inspecting a type's structure *directly* may expose the fact /// that there are actually multiple representations for `Error`, so avoid /// that when err needs to be handled differently. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self, expr), level = "debug")] pub(super) fn check_expr_with_expectation( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { + self.check_expr_with_expectation_and_args(expr, expected, &[]) + } + + /// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a + /// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`. + pub(super) fn check_expr_with_expectation_and_args( + &self, + expr: &'tcx hir::Expr<'tcx>, + expected: Expectation<'tcx>, + args: &'tcx [hir::Expr<'tcx>], + ) -> Ty<'tcx> { if self.tcx().sess.verbose() { // make this code only run with -Zverbose because it is probably slow if let Ok(lint_str) = self.tcx.sess.source_map().span_to_snippet(expr.span) { @@ -198,7 +208,12 @@ let old_diverges = self.diverges.replace(Diverges::Maybe); let old_has_errors = self.has_errors.replace(false); - let ty = ensure_sufficient_stack(|| self.check_expr_kind(expr, expected)); + let ty = ensure_sufficient_stack(|| match &expr.kind { + hir::ExprKind::Path( + qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..), + ) => self.check_expr_path(qpath, expr, args), + _ => self.check_expr_kind(expr, expected), + }); // Warn for non-block expressions with diverging children. match expr.kind { @@ -238,12 +253,13 @@ ty } + #[instrument(skip(self, expr), level = "debug")] fn check_expr_kind( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - debug!("check_expr_kind(expected={:?}, expr={:?})", expected, expr); + trace!("expr={:#?}", expr); let tcx = self.tcx; match expr.kind { @@ -261,7 +277,7 @@ ExprKind::Path(QPath::LangItem(lang_item, _)) => { self.check_lang_item_path(lang_item, expr) } - ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr), + ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]), ExprKind::InlineAsm(asm) => self.check_expr_asm(asm), ExprKind::LlvmInlineAsm(asm) => { for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) { @@ -481,10 +497,11 @@ self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1 } - fn check_expr_path( + pub(crate) fn check_expr_path( &self, qpath: &'tcx hir::QPath<'tcx>, expr: &'tcx hir::Expr<'tcx>, + args: &'tcx [hir::Expr<'tcx>], ) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = @@ -517,16 +534,17 @@ // We just want to check sizedness, so instead of introducing // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. + let span = args.get(i).map(|a| a.span).unwrap_or(expr.span); let input = self .replace_bound_vars_with_fresh_vars( - expr.span, + span, infer::LateBoundRegionConversionTime::FnCall, fn_sig.input(i), ) .0; self.require_type_is_sized_deferred( input, - expr.span, + span, traits::SizedArgumentType(None), ); } @@ -747,7 +765,7 @@ if self.ret_coercion_span.get().is_none() { self.ret_coercion_span.set(Some(e.span)); } - self.check_return_expr(e); + self.check_return_expr(e, true); } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); if self.ret_coercion_span.get().is_none() { @@ -776,16 +794,32 @@ self.tcx.types.never } - pub(super) fn check_return_expr(&self, return_expr: &'tcx hir::Expr<'tcx>) { + /// `explicit_return` is `true` if we're checkng an explicit `return expr`, + /// and `false` if we're checking a trailing expression. + pub(super) fn check_return_expr( + &self, + return_expr: &'tcx hir::Expr<'tcx>, + explicit_return: bool, + ) { let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| { span_bug!(return_expr.span, "check_return_expr called outside fn body") }); let ret_ty = ret_coercion.borrow().expected_ty(); let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty); + let mut span = return_expr.span; + // Use the span of the trailing expression for our cause, + // not the span of the entire function + if !explicit_return { + if let ExprKind::Block(body, _) = return_expr.kind { + if let Some(last_expr) = body.expr { + span = last_expr.span; + } + } + } ret_coercion.borrow_mut().coerce( self, - &self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)), + &self.cause(span, ObligationCauseCode::ReturnValue(return_expr.hir_id)), return_expr, return_expr_ty, ); @@ -1236,6 +1270,7 @@ variant, fields, base_expr.is_none(), + expr.span, ); if let Some(base_expr) = base_expr { // If check_expr_struct_fields hit an error, do not attempt to populate @@ -1283,6 +1318,7 @@ variant: &'tcx ty::VariantDef, ast_fields: &'tcx [hir::ExprField<'tcx>], check_completeness: bool, + expr_span: Span, ) -> bool { let tcx = self.tcx; @@ -1334,7 +1370,9 @@ ident, }); } else { - self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span); + self.report_unknown_field( + adt_ty, variant, field, ast_fields, kind_name, expr_span, + ); } tcx.ty_error() @@ -1467,7 +1505,7 @@ field: &hir::ExprField<'_>, skip_fields: &[hir::ExprField<'_>], kind_name: &str, - ty_span: Span, + expr_span: Span, ) { if variant.is_recovered() { self.set_tainted_by_errors(); @@ -1510,8 +1548,8 @@ ), ); err.span_label(field.ident.span, "field does not exist"); - err.span_suggestion( - ty_span, + err.span_suggestion_verbose( + expr_span, &format!( "`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax", adt = ty, @@ -1528,8 +1566,8 @@ _ => { err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty)); err.span_label(field.ident.span, "field does not exist"); - err.span_suggestion( - ty_span, + err.span_suggestion_verbose( + expr_span, &format!( "`{adt}` is a tuple {kind_name}, use the appropriate syntax", adt = ty, @@ -1660,15 +1698,15 @@ // Save the index of all fields regardless of their visibility in case // of error recovery. self.write_field_index(expr.hir_id, index); + let adjustments = self.adjust_steps(&autoderef); if field.vis.is_accessible_from(def_scope, self.tcx) { - let adjustments = self.adjust_steps(&autoderef); self.apply_adjustments(base, adjustments); self.register_predicates(autoderef.into_obligations()); self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); return field_ty; } - private_candidate = Some((base_def.did, field_ty)); + private_candidate = Some((adjustments, base_def.did, field_ty)); } } ty::Tuple(tys) => { @@ -1691,7 +1729,10 @@ } self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); - if let Some((did, field_ty)) = private_candidate { + if let Some((adjustments, did, field_ty)) = private_candidate { + // (#90483) apply adjustments to avoid ExprUseVisitor from + // creating erroneous projection. + self.apply_adjustments(base, adjustments); self.ban_private_field_access(expr, expr_t, field, did); return field_ty; } @@ -1822,6 +1863,7 @@ field, expr_t, expr, + None, ); } err.emit(); @@ -1838,13 +1880,43 @@ expr_t ); err.span_label(field.span, "method, not a field"); - if !self.expr_in_place(expr.hir_id) { + let expr_is_call = + if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) = + self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id)) + { + expr.hir_id == callee.hir_id + } else { + false + }; + let expr_snippet = + self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new()); + let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')'); + let after_open = expr.span.lo() + rustc_span::BytePos(1); + let before_close = expr.span.hi() - rustc_span::BytePos(1); + + if expr_is_call && is_wrapped { + err.multipart_suggestion( + "remove wrapping parentheses to call the method", + vec![ + (expr.span.with_hi(after_open), String::new()), + (expr.span.with_lo(before_close), String::new()), + ], + Applicability::MachineApplicable, + ); + } else if !self.expr_in_place(expr.hir_id) { + // Suggest call parentheses inside the wrapping parentheses + let span = if is_wrapped { + expr.span.with_lo(after_open).with_hi(before_close) + } else { + expr.span + }; self.suggest_method_call( &mut err, "use parentheses to call the method", field, expr_t, expr, + Some(span), ); } else { err.help("methods are immutable and cannot be assigned to"); @@ -2067,7 +2139,7 @@ idx_t } else { let base_t = self.structurally_resolved_type(base.span, base_t); - match self.lookup_indexing(expr, base, base_t, idx_t) { + match self.lookup_indexing(expr, base, base_t, idx, idx_t) { Some((index_ty, element_ty)) => { // two-phase not needed because index_ty is never mutable self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fallback.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fallback.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fallback.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fallback.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,29 +1,52 @@ use crate::check::FnCtxt; -use rustc_infer::infer::type_variable::Diverging; +use rustc_data_structures::{ + fx::FxHashMap, + graph::WithSuccessors, + graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + stable_set::FxHashSet, +}; use rustc_middle::ty::{self, Ty}; impl<'tcx> FnCtxt<'_, 'tcx> { /// Performs type inference fallback, returning true if any fallback /// occurs. pub(super) fn type_inference_fallback(&self) -> bool { + debug!( + "type-inference-fallback start obligations: {:#?}", + self.fulfillment_cx.borrow_mut().pending_obligations() + ); + // All type checking constraints were added, try to fallback unsolved variables. self.select_obligations_where_possible(false, |_| {}); - let mut fallback_has_occurred = false; + debug!( + "type-inference-fallback post selection obligations: {:#?}", + self.fulfillment_cx.borrow_mut().pending_obligations() + ); + + // Check if we have any unsolved varibales. If not, no need for fallback. + let unsolved_variables = self.unsolved_variables(); + if unsolved_variables.is_empty() { + return false; + } + + let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables); + + let mut fallback_has_occurred = false; // We do fallback in two passes, to try to generate // better error messages. // The first time, we do *not* replace opaque types. - for ty in &self.unsolved_variables() { + for ty in unsolved_variables { debug!("unsolved_variable = {:?}", ty); - fallback_has_occurred |= self.fallback_if_possible(ty); + fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback); } - // We now see if we can make progress. This might - // cause us to unify inference variables for opaque types, - // since we may have unified some other type variables - // during the first phase of fallback. - // This means that we only replace inference variables with their underlying - // opaque types as a last resort. + // We now see if we can make progress. This might cause us to + // unify inference variables for opaque types, since we may + // have unified some other type variables during the first + // phase of fallback. This means that we only replace + // inference variables with their underlying opaque types as a + // last resort. // // In code like this: // @@ -62,36 +85,44 @@ // // - Unconstrained floats are replaced with with `f64`. // - // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` - // is enabled. Otherwise, they are replaced with `()`. + // - Non-numerics may get replaced with `()` or `!`, depending on + // how they were categorized by `calculate_diverging_fallback` + // (and the setting of `#![feature(never_type_fallback)]`). + // + // Fallback becomes very dubious if we have encountered + // type-checking errors. In that case, fallback to Error. // - // Fallback becomes very dubious if we have encountered type-checking errors. - // In that case, fallback to Error. // The return value indicates whether fallback has occurred. - fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool { + fn fallback_if_possible( + &self, + ty: Ty<'tcx>, + diverging_fallback: &FxHashMap, Ty<'tcx>>, + ) -> bool { // Careful: we do NOT shallow-resolve `ty`. We know that `ty` - // is an unsolved variable, and we determine its fallback based - // solely on how it was created, not what other type variables - // it may have been unified with since then. - // - // The reason this matters is that other attempts at fallback may - // (in principle) conflict with this fallback, and we wish to generate - // a type error in that case. (However, this actually isn't true right now, - // because we're only using the builtin fallback rules. This would be - // true if we were using user-supplied fallbacks. But it's still useful - // to write the code to detect bugs.) - // - // (Note though that if we have a general type variable `?T` that is then unified - // with an integer type variable `?I` that ultimately never gets - // resolved to a special integral type, `?T` is not considered unsolved, - // but `?I` is. The same is true for float variables.) + // is an unsolved variable, and we determine its fallback + // based solely on how it was created, not what other type + // variables it may have been unified with since then. + // + // The reason this matters is that other attempts at fallback + // may (in principle) conflict with this fallback, and we wish + // to generate a type error in that case. (However, this + // actually isn't true right now, because we're only using the + // builtin fallback rules. This would be true if we were using + // user-supplied fallbacks. But it's still useful to write the + // code to detect bugs.) + // + // (Note though that if we have a general type variable `?T` + // that is then unified with an integer type variable `?I` + // that ultimately never gets resolved to a special integral + // type, `?T` is not considered unsolved, but `?I` is. The + // same is true for float variables.) let fallback = match ty.kind() { _ if self.is_tainted_by_errors() => self.tcx.ty_error(), ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, - _ => match self.type_var_diverges(ty) { - Diverging::Diverges => self.tcx.mk_diverging_default(), - Diverging::NotDiverging => return false, + _ => match diverging_fallback.get(&ty) { + Some(&fallback_ty) => fallback_ty, + None => return false, }, }; debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); @@ -105,11 +136,10 @@ true } - /// Second round of fallback: Unconstrained type variables - /// created from the instantiation of an opaque - /// type fall back to the opaque type itself. This is a - /// somewhat incomplete attempt to manage "identity passthrough" - /// for `impl Trait` types. + /// Second round of fallback: Unconstrained type variables created + /// from the instantiation of an opaque type fall back to the + /// opaque type itself. This is a somewhat incomplete attempt to + /// manage "identity passthrough" for `impl Trait` types. /// /// For example, in this code: /// @@ -158,4 +188,274 @@ return false; } } + + /// The "diverging fallback" system is rather complicated. This is + /// a result of our need to balance 'do the right thing' with + /// backwards compatibility. + /// + /// "Diverging" type variables are variables created when we + /// coerce a `!` type into an unbound type variable `?X`. If they + /// never wind up being constrained, the "right and natural" thing + /// is that `?X` should "fallback" to `!`. This means that e.g. an + /// expression like `Some(return)` will ultimately wind up with a + /// type like `Option` (presuming it is not assigned or + /// constrained to have some other type). + /// + /// However, the fallback used to be `()` (before the `!` type was + /// added). Moreover, there are cases where the `!` type 'leaks + /// out' from dead code into type variables that affect live + /// code. The most common case is something like this: + /// + /// ```rust + /// match foo() { + /// 22 => Default::default(), // call this type `?D` + /// _ => return, // return has type `!` + /// } // call the type of this match `?M` + /// ``` + /// + /// Here, coercing the type `!` into `?M` will create a diverging + /// type variable `?X` where `?X <: ?M`. We also have that `?D <: + /// ?M`. If `?M` winds up unconstrained, then `?X` will + /// fallback. If it falls back to `!`, then all the type variables + /// will wind up equal to `!` -- this includes the type `?D` + /// (since `!` doesn't implement `Default`, we wind up a "trait + /// not implemented" error in code like this). But since the + /// original fallback was `()`, this code used to compile with `?D + /// = ()`. This is somewhat surprising, since `Default::default()` + /// on its own would give an error because the types are + /// insufficiently constrained. + /// + /// Our solution to this dilemma is to modify diverging variables + /// so that they can *either* fallback to `!` (the default) or to + /// `()` (the backwards compatibility case). We decide which + /// fallback to use based on whether there is a coercion pattern + /// like this: + /// + /// ``` + /// ?Diverging -> ?V + /// ?NonDiverging -> ?V + /// ?V != ?NonDiverging + /// ``` + /// + /// Here `?Diverging` represents some diverging type variable and + /// `?NonDiverging` represents some non-diverging type + /// variable. `?V` can be any type variable (diverging or not), so + /// long as it is not equal to `?NonDiverging`. + /// + /// Intuitively, what we are looking for is a case where a + /// "non-diverging" type variable (like `?M` in our example above) + /// is coerced *into* some variable `?V` that would otherwise + /// fallback to `!`. In that case, we make `?V` fallback to `!`, + /// along with anything that would flow into `?V`. + /// + /// The algorithm we use: + /// * Identify all variables that are coerced *into* by a + /// diverging variable. Do this by iterating over each + /// diverging, unsolved variable and finding all variables + /// reachable from there. Call that set `D`. + /// * Walk over all unsolved, non-diverging variables, and find + /// any variable that has an edge into `D`. + fn calculate_diverging_fallback( + &self, + unsolved_variables: &[Ty<'tcx>], + ) -> FxHashMap, Ty<'tcx>> { + debug!("calculate_diverging_fallback({:?})", unsolved_variables); + + let relationships = self.fulfillment_cx.borrow_mut().relationships().clone(); + + // Construct a coercion graph where an edge `A -> B` indicates + // a type variable is that is coerced + let coercion_graph = self.create_coercion_graph(); + + // Extract the unsolved type inference variable vids; note that some + // unsolved variables are integer/float variables and are excluded. + let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid()); + + // Compute the diverging root vids D -- that is, the root vid of + // those type variables that (a) are the target of a coercion from + // a `!` type and (b) have not yet been solved. + // + // These variables are the ones that are targets for fallback to + // either `!` or `()`. + let diverging_roots: FxHashSet = self + .diverging_type_vars + .borrow() + .iter() + .map(|&ty| self.infcx.shallow_resolve(ty)) + .filter_map(|ty| ty.ty_vid()) + .map(|vid| self.infcx.root_var(vid)) + .collect(); + debug!( + "calculate_diverging_fallback: diverging_type_vars={:?}", + self.diverging_type_vars.borrow() + ); + debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots); + + // Find all type variables that are reachable from a diverging + // type variable. These will typically default to `!`, unless + // we find later that they are *also* reachable from some + // other type variable outside this set. + let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph); + let mut diverging_vids = vec![]; + let mut non_diverging_vids = vec![]; + for unsolved_vid in unsolved_vids { + let root_vid = self.infcx.root_var(unsolved_vid); + debug!( + "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}", + unsolved_vid, + root_vid, + diverging_roots.contains(&root_vid), + ); + if diverging_roots.contains(&root_vid) { + diverging_vids.push(unsolved_vid); + roots_reachable_from_diverging.push_start_node(root_vid); + + debug!( + "calculate_diverging_fallback: root_vid={:?} reaches {:?}", + root_vid, + coercion_graph.depth_first_search(root_vid).collect::>() + ); + + // drain the iterator to visit all nodes reachable from this node + roots_reachable_from_diverging.complete_search(); + } else { + non_diverging_vids.push(unsolved_vid); + } + } + + debug!( + "calculate_diverging_fallback: roots_reachable_from_diverging={:?}", + roots_reachable_from_diverging, + ); + + // Find all type variables N0 that are not reachable from a + // diverging variable, and then compute the set reachable from + // N0, which we call N. These are the *non-diverging* type + // variables. (Note that this set consists of "root variables".) + let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph); + for &non_diverging_vid in &non_diverging_vids { + let root_vid = self.infcx.root_var(non_diverging_vid); + if roots_reachable_from_diverging.visited(root_vid) { + continue; + } + roots_reachable_from_non_diverging.push_start_node(root_vid); + roots_reachable_from_non_diverging.complete_search(); + } + debug!( + "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}", + roots_reachable_from_non_diverging, + ); + + debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations()); + debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations()); + debug!("relationships: {:#?}", relationships); + + // For each diverging variable, figure out whether it can + // reach a member of N. If so, it falls back to `()`. Else + // `!`. + let mut diverging_fallback = FxHashMap::default(); + diverging_fallback.reserve(diverging_vids.len()); + for &diverging_vid in &diverging_vids { + let diverging_ty = self.tcx.mk_ty_var(diverging_vid); + let root_vid = self.infcx.root_var(diverging_vid); + let can_reach_non_diverging = coercion_graph + .depth_first_search(root_vid) + .any(|n| roots_reachable_from_non_diverging.visited(n)); + + let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false }; + + for (vid, rel) in relationships.iter() { + if self.infcx.root_var(*vid) == root_vid { + relationship.self_in_trait |= rel.self_in_trait; + relationship.output |= rel.output; + } + } + + if relationship.self_in_trait && relationship.output { + // This case falls back to () to ensure that the code pattern in + // src/test/ui/never_type/fallback-closure-ret.rs continues to + // compile when never_type_fallback is enabled. + // + // This rule is not readily explainable from first principles, + // but is rather intended as a patchwork fix to ensure code + // which compiles before the stabilization of never type + // fallback continues to work. + // + // Typically this pattern is encountered in a function taking a + // closure as a parameter, where the return type of that closure + // (checked by `relationship.output`) is expected to implement + // some trait (checked by `relationship.self_in_trait`). This + // can come up in non-closure cases too, so we do not limit this + // rule to specifically `FnOnce`. + // + // When the closure's body is something like `panic!()`, the + // return type would normally be inferred to `!`. However, it + // needs to fall back to `()` in order to still compile, as the + // trait is specifically implemented for `()` but not `!`. + // + // For details on the requirements for these relationships to be + // set, see the relationship finding module in + // compiler/rustc_trait_selection/src/traits/relationships.rs. + debug!("fallback to () - found trait and projection: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else if can_reach_non_diverging { + debug!("fallback to () - reached non-diverging: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else { + debug!("fallback to ! - all diverging: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default()); + } + } + + diverging_fallback + } + + /// Returns a graph whose nodes are (unresolved) inference variables and where + /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. + fn create_coercion_graph(&self) -> VecGraph { + let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations(); + debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations); + let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations + .into_iter() + .filter_map(|obligation| { + // The predicates we are looking for look like `Coerce(?A -> ?B)`. + // They will have no bound variables. + obligation.predicate.kind().no_bound_vars() + }) + .filter_map(|atom| { + // We consider both subtyping and coercion to imply 'flow' from + // some position in the code `a` to a different position `b`. + // This is then used to determine which variables interact with + // live code, and as such must fall back to `()` to preserve + // soundness. + // + // In practice currently the two ways that this happens is + // coercion and subtyping. + let (a, b) = if let ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) = atom { + (a, b) + } else if let ty::PredicateKind::Subtype(ty::SubtypePredicate { + a_is_expected: _, + a, + b, + }) = atom + { + (a, b) + } else { + return None; + }; + + let a_vid = self.root_vid(a)?; + let b_vid = self.root_vid(b)?; + Some((a_vid, b_vid)) + }) + .collect(); + debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges); + let num_ty_vars = self.infcx.num_ty_vars(); + VecGraph::new(num_ty_vars, coercion_edges) + } + + /// If `ty` is an unresolved type variable, returns its root vid. + fn root_vid(&self, ty: Ty<'tcx>) -> Option { + Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?)) + } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,7 @@ }; use rustc_ast as ast; +use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -324,6 +325,7 @@ self.point_at_arg_instead_of_call_if_possible( errors, &final_arg_types[..], + expr, sp, &args, ); @@ -354,8 +356,8 @@ continue; } - debug!("checking the argument"); let formal_ty = formal_tys[i]; + debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty); // The special-cased logic below has three functions: // 1. Provide as good of an expected type as possible. @@ -367,6 +369,42 @@ // to, which is `expected_ty` if `rvalue_hint` returns an // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); + + // Cause selection errors caused by resolving a single argument to point at the + // argument and not the call. This is otherwise redundant with the `demand_coerce` + // call immediately after, but it lets us customize the span pointed to in the + // fulfillment error to be more accurate. + let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment( + coerce_ty, + |errors| { + // This is not coming from a macro or a `derive`. + if sp.desugaring_kind().is_none() + && !arg.span.from_expansion() + // Do not change the spans of `async fn`s. + && !matches!( + expr.kind, + hir::ExprKind::Call( + hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::LangItem(_, _)), + .. + }, + _ + ) + ) { + for error in errors { + error.obligation.cause.make_mut().span = arg.span; + let code = error.obligation.cause.code.clone(); + error.obligation.cause.make_mut().code = + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id: arg.hir_id, + call_hir_id: expr.hir_id, + parent_code: Lrc::new(code), + }; + } + } + }, + ); + // We're processing function arguments so we definitely want to use // two-phase borrows. self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); @@ -494,15 +532,25 @@ Some((variant, ty)) } else { - struct_span_err!( - self.tcx.sess, - path_span, - E0071, - "expected struct, variant or union type, found {}", - ty.sort_string(self.tcx) - ) - .span_label(path_span, "not a struct") - .emit(); + match ty.kind() { + ty::Error(_) => { + // E0071 might be caused by a spelling error, which will have + // already caused an error message and probably a suggestion + // elsewhere. Refrain from emitting more unhelpful errors here + // (issue #88844). + } + _ => { + struct_span_err!( + self.tcx.sess, + path_span, + E0071, + "expected struct, variant or union type, found {}", + ty.sort_string(self.tcx) + ) + .span_label(path_span, "not a struct") + .emit(); + } + } None } } @@ -907,6 +955,7 @@ &self, errors: &mut Vec>, final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)], + expr: &'tcx hir::Expr<'tcx>, call_sp: Span, args: &'tcx [hir::Expr<'tcx>], ) { @@ -956,7 +1005,13 @@ // We make sure that only *one* argument matches the obligation failure // and we assign the obligation's span to its expression's. error.obligation.cause.make_mut().span = args[ref_in].span; - error.points_at_arg_span = true; + let code = error.obligation.cause.code.clone(); + error.obligation.cause.make_mut().code = + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id: args[ref_in].hir_id, + call_hir_id: expr.hir_id, + parent_code: Lrc::new(code), + }; } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs 2021-11-29 19:27:11.000000000 +0000 @@ -83,19 +83,26 @@ /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. - pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_vars_with_obligations(ty={:?})", ty); + pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {}) + } + #[instrument(skip(self, mutate_fulfillment_errors), level = "debug")] + pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment( + &self, + mut ty: Ty<'tcx>, + mutate_fulfillment_errors: impl Fn(&mut Vec>), + ) -> Ty<'tcx> { // No Infer()? Nothing needs doing. if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!("no inference var, nothing needs doing"); return ty; } // If `ty` is a type variable, see whether we already know what it is. ty = self.resolve_vars_if_possible(ty); if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!(?ty); return ty; } @@ -103,10 +110,10 @@ // possible. This can help substantially when there are // indirect dependencies that don't seem worth tracking // precisely. - self.select_obligations_where_possible(false, |_| {}); + self.select_obligations_where_possible(false, mutate_fulfillment_errors); ty = self.resolve_vars_if_possible(ty); - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!(?ty); ty } @@ -222,6 +229,7 @@ /// This should be invoked **before any unifications have /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. + #[instrument(skip(self), level = "debug")] pub fn write_user_type_annotation_from_substs( &self, hir_id: hir::HirId, @@ -229,37 +237,25 @@ substs: SubstsRef<'tcx>, user_self_ty: Option>, ) { - debug!( - "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ - user_self_ty={:?} in fcx {}", - hir_id, - def_id, - substs, - user_self_ty, - self.tag(), - ); + debug!("fcx {}", self.tag()); if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) { let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( def_id, UserSubsts { substs, user_self_ty }, )); - debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); + debug!(?canonicalized); self.write_user_type_annotation(hir_id, canonicalized); } } + #[instrument(skip(self), level = "debug")] pub fn write_user_type_annotation( &self, hir_id: hir::HirId, canonical_user_type_annotation: CanonicalUserType<'tcx>, ) { - debug!( - "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", - hir_id, - canonical_user_type_annotation, - self.tag(), - ); + debug!("fcx {}", self.tag()); if !canonical_user_type_annotation.is_identity() { self.typeck_results @@ -267,17 +263,27 @@ .user_provided_types_mut() .insert(hir_id, canonical_user_type_annotation); } else { - debug!("write_user_type_annotation: skipping identity substs"); + debug!("skipping identity substs"); } } + #[instrument(skip(self, expr), level = "debug")] pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec>) { - debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); + debug!("expr = {:#?}", expr); if adj.is_empty() { return; } + for a in &adj { + if let Adjust::NeverToAny = a.kind { + if a.target.is_ty_var() { + self.diverging_type_vars.borrow_mut().insert(a.target); + debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target); + } + } + } + let autoborrow_mut = adj.iter().any(|adj| { matches!( adj, @@ -568,7 +574,7 @@ self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx), )); } @@ -635,8 +641,8 @@ } } + #[instrument(skip(self), level = "debug")] pub(in super::super) fn select_all_obligations_or_error(&self) { - debug!("select_all_obligations_or_error"); if let Err(errors) = self .fulfillment_cx .borrow_mut() @@ -677,16 +683,15 @@ ret_ty.builtin_deref(true).unwrap() } + #[instrument(skip(self), level = "debug")] fn self_type_matches_expected_vid( &self, trait_ref: ty::PolyTraitRef<'tcx>, expected_vid: ty::TyVid, ) -> bool { let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); - debug!( - "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", - trait_ref, self_ty, expected_vid - ); + debug!(?self_ty); + match *self_ty.kind() { ty::Infer(ty::TyVar(found_vid)) => { // FIXME: consider using `sub_root_var` here so we @@ -699,6 +704,7 @@ } } + #[instrument(skip(self), level = "debug")] pub(in super::super) fn obligations_for_self_ty<'b>( &'b self, self_ty: ty::TyVid, @@ -708,12 +714,7 @@ // FIXME: consider using `sub_root_var` here so we // can see through subtyping. let ty_var_root = self.root_var(self_ty); - debug!( - "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", - self_ty, - ty_var_root, - self.fulfillment_cx.borrow().pending_obligations() - ); + trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations()); self.fulfillment_cx .borrow() @@ -763,6 +764,7 @@ /// Unifies the output type with the expected type early, for more coercions /// and forward type information on the input expressions. + #[instrument(skip(self, call_span), level = "debug")] pub(in super::super) fn expected_inputs_for_expected_output( &self, call_span: Span, @@ -809,10 +811,7 @@ Ok(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()) }) .unwrap_or_default(); - debug!( - "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", - formal_args, formal_ret, expect_args, expected_ret - ); + debug!(?formal_args, ?formal_ret, ?expect_args, ?expected_ret); expect_args } @@ -1172,12 +1171,18 @@ { return None; } - let original_span = original_sp(last_stmt.span, blk.span); - Some((original_span.with_lo(original_span.hi() - BytePos(1)), needs_box)) + let span = if last_stmt.span.from_expansion() { + let mac_call = 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)) + }; + Some((span, needs_box)) } // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. + #[instrument(skip(self, span), level = "debug")] pub fn instantiate_value_path( &self, segments: &[hir::PathSegment<'_>], @@ -1186,11 +1191,6 @@ span: Span, hir_id: hir::HirId, ) -> (Ty<'tcx>, Res) { - debug!( - "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", - segments, self_ty, res, hir_id, - ); - let tcx = self.tcx; let path_segs = match res { @@ -1213,7 +1213,7 @@ } Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { let container = tcx.associated_item(def_id).container; - debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); + debug!(?def_id, ?container); match container { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,11 +8,11 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{Expr, ExprKind, ItemKind, Node, Stmt, StmtKind}; +use rustc_hir::{Expr, ExprKind, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind}; use rustc_infer::infer; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, Ty}; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, sym}; use std::iter; @@ -341,12 +341,16 @@ for (sp, label) in spans_and_labels { multi_span.push_span_label(sp, label); } - err.span_note(multi_span, "closures can only be coerced to `fn` types if they do not capture any variables"); + err.span_note( + multi_span, + "closures can only be coerced to `fn` types if they do not capture any variables" + ); } } } /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. + #[instrument(skip(self, err))] pub(in super::super) fn suggest_calling_boxed_future_when_appropriate( &self, err: &mut DiagnosticBuilder<'_>, @@ -361,33 +365,74 @@ return false; } let pin_did = self.tcx.lang_items().pin_type(); - match expected.kind() { - ty::Adt(def, _) if Some(def.did) != pin_did => return false, - // This guards the `unwrap` and `mk_box` below. - _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, - _ => {} + // This guards the `unwrap` and `mk_box` below. + if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() { + return false; } - let boxed_found = self.tcx.mk_box(found); - let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap(); - if self.can_coerce(new_found, expected) { - match found.kind() { - ty::Adt(def, _) if def.is_box() => { - err.help("use `Box::pin`"); + let box_found = self.tcx.mk_box(found); + let pin_box_found = self.tcx.mk_lang_item(box_found, LangItem::Pin).unwrap(); + let pin_found = self.tcx.mk_lang_item(found, LangItem::Pin).unwrap(); + match expected.kind() { + ty::Adt(def, _) if Some(def.did) == pin_did => { + if self.can_coerce(pin_box_found, expected) { + debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected); + match found.kind() { + ty::Adt(def, _) if def.is_box() => { + err.help("use `Box::pin`"); + } + _ => { + err.multipart_suggestion( + "you need to pin and box this expression", + vec![ + (expr.span.shrink_to_lo(), "Box::pin(".to_string()), + (expr.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } + } + true + } else if self.can_coerce(pin_found, expected) { + match found.kind() { + ty::Adt(def, _) if def.is_box() => { + err.help("use `Box::pin`"); + true + } + _ => false, + } + } else { + false } - _ => { - err.multipart_suggestion( - "you need to pin and box this expression", - vec![ - (expr.span.shrink_to_lo(), "Box::pin(".to_string()), - (expr.span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ); + } + ty::Adt(def, _) if def.is_box() && self.can_coerce(box_found, expected) => { + // Check if the parent expression is a call to Pin::new. If it + // is and we were expecting a Box, ergo Pin>, we + // can suggest Box::pin. + let parent = self.tcx.hir().get_parent_node(expr.hir_id); + let fn_name = match self.tcx.hir().find(parent) { + Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) => fn_name, + _ => return false, + }; + match fn_name.kind { + ExprKind::Path(QPath::TypeRelative( + hir::Ty { + kind: TyKind::Path(QPath::Resolved(_, Path { res: recv_ty, .. })), + .. + }, + method, + )) if recv_ty.opt_def_id() == pin_did && method.ident.name == sym::new => { + err.span_suggestion( + fn_name.span, + "use `Box::pin` to pin and box this expression", + "Box::pin".to_string(), + Applicability::MachineApplicable, + ); + true + } + _ => false, } } - true - } else { - false + _ => false, } } @@ -484,8 +529,9 @@ debug!("suggest_missing_return_type: return type {:?}", ty); debug!("suggest_missing_return_type: expected type {:?}", ty); let bound_vars = self.tcx.late_bound_vars(fn_id); - let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); + let ty = Binder::bind_with_vars(ty, bound_vars); let ty = self.normalize_associated_types_in(sp, ty); + let ty = self.tcx.erase_late_bound_regions(ty); if self.can_coerce(expected, ty) { err.span_label(sp, format!("expected `{}` because of return type", expected)); return true; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/generator_interior.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/generator_interior.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/generator_interior.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/generator_interior.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,11 @@ //! This calculates the types which has storage which lives across a suspension point in a //! generator from the perspective of typeck. The actual types used at runtime -//! is calculated in `rustc_mir::transform::generator` and may be a subset of the +//! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the //! types computed here. use super::FnCtxt; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -12,9 +13,11 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; use rustc_middle::middle::region::{self, YieldData}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; +use tracing::debug; struct InteriorVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -30,12 +33,14 @@ /// that they may succeed the said yield point in the post-order. guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>, guard_bindings_set: HirIdSet, + linted_values: HirIdSet, } impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { fn record( &mut self, ty: Ty<'tcx>, + hir_id: HirId, scope: Option, expr: Option<&'tcx Expr<'tcx>>, source_span: Span, @@ -117,6 +122,23 @@ } else { // Insert the type into the ordered set. let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree)); + + if !self.linted_values.contains(&hir_id) { + check_must_not_suspend_ty( + self.fcx, + ty, + hir_id, + SuspendCheckData { + expr, + source_span, + yield_span: yield_data.span, + plural_len: 1, + ..Default::default() + }, + ); + self.linted_values.insert(hir_id); + } + self.types.insert(ty::GeneratorInteriorTypeCause { span: source_span, ty: &ty, @@ -163,6 +185,7 @@ prev_unresolved_span: None, guard_bindings: <_>::default(), guard_bindings_set: <_>::default(), + linted_values: <_>::default(), }; intravisit::walk_body(&mut visitor, body); @@ -290,7 +313,7 @@ if let PatKind::Binding(..) = pat.kind { let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id); let ty = self.fcx.typeck_results.borrow().pat_ty(pat); - self.record(ty, Some(scope), None, pat.span, false); + self.record(ty, pat.hir_id, Some(scope), None, pat.span, false); } } @@ -342,7 +365,14 @@ // If there are adjustments, then record the final type -- // this is the actual value that is being produced. if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) { - self.record(adjusted_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); + self.record( + adjusted_ty, + expr.hir_id, + scope, + Some(expr), + expr.span, + guard_borrowing_from_pattern, + ); } // Also record the unadjusted type (which is the only type if @@ -380,9 +410,23 @@ tcx.mk_region(ty::RegionKind::ReErased), ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }, ); - self.record(ref_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); + self.record( + ref_ty, + expr.hir_id, + scope, + Some(expr), + expr.span, + guard_borrowing_from_pattern, + ); } - self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); + self.record( + ty, + expr.hir_id, + scope, + Some(expr), + expr.span, + guard_borrowing_from_pattern, + ); } else { self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node"); } @@ -409,3 +453,173 @@ } } } + +#[derive(Default)] +pub struct SuspendCheckData<'a, 'tcx> { + expr: Option<&'tcx Expr<'tcx>>, + source_span: Span, + yield_span: Span, + descr_pre: &'a str, + descr_post: &'a str, + plural_len: usize, +} + +// Returns whether it emitted a diagnostic or not +// Note that this fn and the proceding one are based on the code +// for creating must_use diagnostics +// +// Note that this technique was chosen over things like a `Suspend` marker trait +// as it is simpler and has precendent in the compiler +pub fn check_must_not_suspend_ty<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + ty: Ty<'tcx>, + hir_id: HirId, + data: SuspendCheckData<'_, 'tcx>, +) -> bool { + if ty.is_unit() + // FIXME: should this check `is_ty_uninhabited_from`. This query is not available in this stage + // of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in + // `must_use` + // || fcx.tcx.is_ty_uninhabited_from(fcx.tcx.parent_module(hir_id).to_def_id(), ty, fcx.param_env) + { + return false; + } + + let plural_suffix = pluralize!(data.plural_len); + + match *ty.kind() { + ty::Adt(..) if ty.is_box() => { + let boxed_ty = ty.boxed_ty(); + let descr_pre = &format!("{}boxed ", data.descr_pre); + check_must_not_suspend_ty(fcx, boxed_ty, hir_id, SuspendCheckData { descr_pre, ..data }) + } + ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did, hir_id, data), + // FIXME: support adding the attribute to TAITs + ty::Opaque(def, _) => { + let mut has_emitted = false; + for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) { + // We only look at the `DefId`, so it is safe to skip the binder here. + if let ty::PredicateKind::Trait(ref poly_trait_predicate) = + predicate.kind().skip_binder() + { + let def_id = poly_trait_predicate.trait_ref.def_id; + let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix); + if check_must_not_suspend_def( + fcx.tcx, + def_id, + hir_id, + SuspendCheckData { descr_pre, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Dynamic(binder, _) => { + let mut has_emitted = false; + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { + let def_id = trait_ref.def_id; + let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post); + if check_must_not_suspend_def( + fcx.tcx, + def_id, + hir_id, + SuspendCheckData { descr_post, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Tuple(ref tys) => { + let mut has_emitted = false; + let spans = if let Some(hir::ExprKind::Tup(comps)) = data.expr.map(|e| &e.kind) { + debug_assert_eq!(comps.len(), tys.len()); + comps.iter().map(|e| e.span).collect() + } else { + vec![] + }; + for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { + let descr_post = &format!(" in tuple element {}", i); + let span = *spans.get(i).unwrap_or(&data.source_span); + if check_must_not_suspend_ty( + fcx, + ty, + hir_id, + SuspendCheckData { descr_post, source_span: span, ..data }, + ) { + has_emitted = true; + } + } + has_emitted + } + ty::Array(ty, len) => { + let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty( + fcx, + ty, + hir_id, + SuspendCheckData { + descr_pre, + plural_len: len.try_eval_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize + + 1, + ..data + }, + ) + } + _ => false, + } +} + +fn check_must_not_suspend_def( + tcx: TyCtxt<'_>, + def_id: DefId, + hir_id: HirId, + data: SuspendCheckData<'_, '_>, +) -> bool { + for attr in tcx.get_attrs(def_id).iter() { + if attr.has_name(sym::must_not_suspend) { + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::MUST_NOT_SUSPEND, + hir_id, + data.source_span, + |lint| { + let msg = format!( + "{}`{}`{} held across a suspend point, but should not be", + data.descr_pre, + tcx.def_path_str(def_id), + data.descr_post, + ); + let mut err = lint.build(&msg); + + // add span pointing to the offending yield/await + err.span_label(data.yield_span, "the value is held across this suspend point"); + + // Add optional reason note + if let Some(note) = attr.value_str() { + // FIXME(guswynn): consider formatting this better + err.span_note(data.source_span, ¬e.as_str()); + } + + // Add some quick suggestions on what to do + // FIXME: can `drop` work as a suggestion here as well? + err.span_help( + data.source_span, + "consider using a block (`{ ... }`) \ + to shrink the value's scope, ending before the suspend point", + ); + + err.emit(); + }, + ); + + return true; + } + } + false +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/inherited.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/inherited.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/inherited.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/inherited.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ use super::callee::DeferredCallResolution; use super::MaybeInProgressTables; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::HirIdMap; @@ -56,6 +57,11 @@ pub(super) constness: hir::Constness, pub(super) body_id: Option, + + /// Whenever we introduce an adjustment from `!` into a type variable, + /// we record that type variable here. This is later used to inform + /// fallback. See the `fallback` module for details. + pub(super) diverging_type_vars: RefCell>>, } impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { @@ -121,6 +127,7 @@ deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), + diverging_type_vars: RefCell::new(Default::default()), constness, body_id, } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/intrinsic.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/intrinsic.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/intrinsic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/intrinsic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ //! intrinsics that the compiler exposes. use crate::errors::{ - SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, + UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, WrongNumberOfGenericArgumentsToIntrinsic, }; use crate::require_same_types; @@ -390,6 +390,8 @@ sym::black_box => (1, vec![param(0)], param(0)), + sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), + other => { tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); return; @@ -468,6 +470,7 @@ | sym::simd_reduce_max | sym::simd_reduce_min_nanless | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)), + sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)), name if name.as_str().starts_with("simd_shuffle") => { match name.as_str()["simd_shuffle".len()..].parse() { Ok(n) => { @@ -475,7 +478,9 @@ (2, params, param(1)) } Err(_) => { - tcx.sess.emit_err(SimdShuffleMissingLength { span: it.span, name }); + let msg = + format!("unrecognized platform-specific intrinsic function: `{}`", name); + tcx.sess.struct_span_err(it.span, &msg).emit(); return; } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/_match.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/_match.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/_match.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/_match.rs 2021-11-29 19:27:11.000000000 +0000 @@ -524,13 +524,14 @@ for o in obligations { match o.predicate.kind().skip_binder() { ty::PredicateKind::Trait(t) => { - let pred = ty::PredicateKind::Trait(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: t.def_id(), - substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]), - }, - constness: t.constness, - }); + let pred = + ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: t.def_id(), + substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]), + }, + constness: t.constness, + })); let obl = Obligation::new( o.cause.clone(), self.param_env, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/confirm.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/confirm.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/confirm.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/confirm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,7 +28,7 @@ impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> { type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { - &self.fcx + self.fcx } } @@ -290,7 +290,7 @@ .autoderef(self.span, self_ty) .include_raw_pointers() .find_map(|(ty, _)| match ty.kind() { - ty::Dynamic(ref data, ..) => Some(closure( + ty::Dynamic(data, ..) => Some(closure( self, ty, data.principal().unwrap_or_else(|| { @@ -323,7 +323,7 @@ self.tcx, self.span, pick.item.def_id, - &generics, + generics, seg, IsMethodCall::Yes, ); @@ -343,7 +343,7 @@ def_id: DefId, ) -> (Option<&'a hir::GenericArgs<'a>>, bool) { if def_id == self.pick.item.def_id { - if let Some(ref data) = self.seg.args { + if let Some(data) = self.seg.args { return (Some(data), false); } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,7 +21,7 @@ use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits; @@ -141,6 +141,7 @@ method_name: Ident, self_ty: Ty<'tcx>, call_expr: &hir::Expr<'_>, + span: Option, ) { let params = self .probe_for_name( @@ -159,7 +160,7 @@ .unwrap_or(0); // Account for `foo.bar`; - let sugg_span = call_expr.span.shrink_to_hi(); + let sugg_span = span.unwrap_or(call_expr.span).shrink_to_hi(); let (suggestion, applicability) = ( format!("({})", (0..params).map(|_| "_").collect::>().join(", ")), if params > 0 { Applicability::HasPlaceholders } else { Applicability::MaybeIncorrect }, @@ -289,29 +290,14 @@ ) } - /// `lookup_method_in_trait` is used for overloaded operators. - /// It does a very narrow slice of what the normal probe/confirm path does. - /// In particular, it doesn't really do any probing: it simply constructs - /// an obligation for a particular trait with the given self type and checks - /// whether that trait is implemented. - // - // FIXME(#18741): it seems likely that we can consolidate some of this - // code with the other method-lookup code. In particular, the second half - // of this method is basically the same as confirmation. - #[instrument(level = "debug", skip(self, span, opt_input_types))] - pub fn lookup_method_in_trait( + pub(super) fn obligation_for_method( &self, span: Span, - m_name: Ident, trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, - ) -> Option>> { - debug!( - "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})", - self_ty, m_name, trait_def_id, opt_input_types - ); - + ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List>) + { // Construct a trait-reference `self_ty : Trait` let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { @@ -319,7 +305,7 @@ GenericParamDefKind::Type { .. } => { if param.index == 0 { return self_ty.into(); - } else if let Some(ref input_types) = opt_input_types { + } else if let Some(input_types) = opt_input_types { return input_types[param.index as usize - 1].into(); } } @@ -330,18 +316,49 @@ let trait_ref = ty::TraitRef::new(trait_def_id, substs); // Construct an obligation - let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = traits::Obligation::misc( - span, - self.body_id, - self.param_env, - poly_trait_ref.without_const().to_predicate(self.tcx), + let poly_trait_ref = ty::Binder::dummy(trait_ref); + ( + traits::Obligation::misc( + span, + self.body_id, + self.param_env, + poly_trait_ref.without_const().to_predicate(self.tcx), + ), + substs, + ) + } + + /// `lookup_method_in_trait` is used for overloaded operators. + /// It does a very narrow slice of what the normal probe/confirm path does. + /// In particular, it doesn't really do any probing: it simply constructs + /// an obligation for a particular trait with the given self type and checks + /// whether that trait is implemented. + // + // FIXME(#18741): it seems likely that we can consolidate some of this + // code with the other method-lookup code. In particular, the second half + // of this method is basically the same as confirmation. + #[instrument(level = "debug", skip(self, span, opt_input_types))] + pub(super) fn lookup_method_in_trait( + &self, + span: Span, + m_name: Ident, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + opt_input_types: Option<&[Ty<'tcx>]>, + ) -> Option>> { + debug!( + "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})", + self_ty, m_name, trait_def_id, opt_input_types ); + let (obligation, substs) = + self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types); + // Now we want to know if this can be matched if !self.predicate_may_hold(&obligation) { debug!("--> Cannot match obligation"); - return None; // Cannot be matched, no such method resolution is possible. + // Cannot be matched, no such method resolution is possible. + return None; } // Trait must have a method named `m_name` and it should not have @@ -412,10 +429,10 @@ obligations.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx), )); - let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig }; + let callee = MethodCallee { def_id, substs, sig: fn_sig }; debug!("callee = {:?}", callee); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/probe.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/probe.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/probe.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/probe.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,9 +21,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{ - self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::lev_distance::{find_best_match_for_name, lev_distance}; @@ -90,7 +88,7 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { - &self.fcx + self.fcx } } @@ -186,7 +184,7 @@ impl<'tcx> AutorefOrPtrAdjustment<'tcx> { fn get_unsize(&self) -> Option> { match self { - AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => unsize.clone(), + AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize, AutorefOrPtrAdjustment::ToConstPtr => None, } } @@ -616,7 +614,7 @@ let lang_items = self.tcx.lang_items(); match *self_ty.value.value.kind() { - ty::Dynamic(ref data, ..) if let Some(p) = data.principal() => { + ty::Dynamic(data, ..) if let Some(p) = data.principal() => { // Subtle: we can't use `instantiate_query_response` here: using it will // commit to all of the type equalities assumed by inference going through // autoderef (see the `method-probe-no-guessing` test). @@ -636,7 +634,7 @@ // type variables in any form, so just do that! let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = self.fcx - .instantiate_canonical_with_fresh_inference_vars(self.span, &self_ty); + .instantiate_canonical_with_fresh_inference_vars(self.span, self_ty); self.assemble_inherent_candidates_from_object(generalized_self_ty); self.assemble_inherent_impl_candidates_for_type(p.def_id()); @@ -755,17 +753,27 @@ let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); let impl_ty = impl_ty.subst(self.tcx, impl_substs); + debug!("impl_ty: {:?}", impl_ty); + // Determine the receiver type that the method itself expects. - let xform_tys = self.xform_self_ty(&item, impl_ty, impl_substs); + let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs); + debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty); // We can't use normalize_associated_types_in as it will pollute the // fcx's fulfillment context after this probe is over. + // Note: we only normalize `xform_self_ty` here since the normalization + // of the return type can lead to inference results that prohibit + // valid canidates from being found, see issue #85671 + // FIXME Postponing the normalization of the return type likely only hides a deeper bug, + // which might be caused by the `param_env` itself. The clauses of the `param_env` + // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized, + // see isssue #89650 let cause = traits::ObligationCause::misc(self.span, self.body_id); let selcx = &mut traits::SelectionContext::new(self.fcx); - let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } = - traits::normalize(selcx, self.param_env, cause, xform_tys); + let traits::Normalized { value: xform_self_ty, obligations } = + traits::normalize(selcx, self.param_env, cause, xform_self_ty); debug!( - "assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}", + "assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}", xform_self_ty, xform_ret_ty ); @@ -966,8 +974,8 @@ let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs); if self.tcx.is_trait_alias(trait_def_id) { - // For trait aliases, assume all super-traits are relevant. - let bounds = iter::once(trait_ref.to_poly_trait_ref()); + // For trait aliases, assume all supertraits are relevant. + let bounds = iter::once(ty::Binder::dummy(trait_ref)); self.elaborate_bounds(bounds, |this, new_trait_ref, item| { let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); @@ -1372,7 +1380,7 @@ trait_ref: ty::TraitRef<'tcx>, ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> { let cause = traits::ObligationCause::misc(self.span, self.body_id); - let predicate = trait_ref.to_poly_trait_ref().to_poly_trait_predicate(); + let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate(); let obligation = traits::Obligation::new(cause, self.param_env, predicate); traits::SelectionContext::new(self).select(&obligation) } @@ -1422,6 +1430,9 @@ }; let mut result = ProbeResult::Match; + let mut xform_ret_ty = probe.xform_ret_ty; + debug!(?xform_ret_ty); + let selcx = &mut traits::SelectionContext::new(self); let cause = traits::ObligationCause::misc(self.span, self.body_id); @@ -1431,6 +1442,16 @@ // don't have enough information to fully evaluate). match probe.kind { InherentImplCandidate(ref substs, ref ref_obligations) => { + // `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`, + // see the reasons mentioned in the comments in `assemble_inherent_impl_probe` + // for why this is necessary + let traits::Normalized { + value: normalized_xform_ret_ty, + obligations: normalization_obligations, + } = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty); + xform_ret_ty = normalized_xform_ret_ty; + debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty); + // Check whether the impl imposes obligations we have to worry about. let impl_def_id = probe.item.container.id(); let impl_bounds = self.tcx.predicates_of(impl_def_id); @@ -1444,7 +1465,9 @@ let candidate_obligations = impl_obligations .chain(norm_obligations.into_iter()) - .chain(ref_obligations.iter().cloned()); + .chain(ref_obligations.iter().cloned()) + .chain(normalization_obligations.into_iter()); + // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations { let o = self.resolve_vars_if_possible(o); @@ -1470,7 +1493,8 @@ } } } - let predicate = trait_ref.without_const().to_predicate(self.tcx); + let predicate = + ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx); let obligation = traits::Obligation::new(cause, self.param_env, predicate); if !self.predicate_may_hold(&obligation) { result = ProbeResult::NoMatch; @@ -1528,9 +1552,7 @@ } if let ProbeResult::Match = result { - if let (Some(return_ty), Some(xform_ret_ty)) = - (self.return_type, probe.xform_ret_ty) - { + if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, xform_ret_ty) { let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty); debug!( "comparing return_ty {:?} with xform ret ty {:?}", @@ -1670,6 +1692,7 @@ self.static_candidates.push(source); } + #[instrument(level = "debug", skip(self))] fn xform_self_ty( &self, item: &ty::AssocItem, @@ -1684,9 +1707,10 @@ } } + #[instrument(level = "debug", skip(self))] fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> { let fn_sig = self.tcx.fn_sig(method); - debug!("xform_self_ty(fn_sig={:?}, substs={:?})", fn_sig, substs); + debug!(?fn_sig); assert!(!substs.has_escaping_bound_vars()); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/suggest.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/suggest.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/suggest.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/method/suggest.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,21 +6,18 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; -use rustc_hir::intravisit; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::fast_reject::simplify_type; use rustc_middle::ty::print::with_crate_prefix; -use rustc_middle::ty::{ - self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::lev_distance; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{source_map, FileName, Span}; +use rustc_span::{source_map, FileName, MultiSpan, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::Obligation; +use rustc_trait_selection::traits::{FulfillmentError, Obligation}; use std::cmp::Ordering; use std::iter; @@ -54,7 +51,7 @@ .into()], ); let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(trait_ref); let obligation = Obligation::misc( span, self.body_id, @@ -179,6 +176,7 @@ sugg_span, idx, self.tcx.sess.source_map(), + item.fn_has_self_parameter, ); } } @@ -221,6 +219,7 @@ sugg_span, idx, self.tcx.sess.source_map(), + item.fn_has_self_parameter, ); } } @@ -329,48 +328,44 @@ Applicability::MaybeIncorrect, ); } - ExprKind::Path(ref qpath) => { + ExprKind::Path(QPath::Resolved(_, path)) => { // local binding - if let QPath::Resolved(_, path) = qpath { - if let hir::def::Res::Local(hir_id) = path.res { - let span = tcx.hir().span(hir_id); - let snippet = tcx.sess.source_map().span_to_snippet(span); - let filename = tcx.sess.source_map().span_to_filename(span); + if let hir::def::Res::Local(hir_id) = path.res { + let span = tcx.hir().span(hir_id); + let snippet = tcx.sess.source_map().span_to_snippet(span); + let filename = tcx.sess.source_map().span_to_filename(span); + + let parent_node = + self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)); + let msg = format!( + "you must specify a type for this binding, like `{}`", + concrete_type, + ); - let parent_node = self - .tcx - .hir() - .get(self.tcx.hir().get_parent_node(hir_id)); - let msg = format!( - "you must specify a type for this binding, like `{}`", - concrete_type, - ); - - match (filename, parent_node, snippet) { - ( - FileName::Real(_), - Node::Local(hir::Local { - source: hir::LocalSource::Normal, - ty, - .. - }), - Ok(ref snippet), - ) => { - err.span_suggestion( - // account for `let x: _ = 42;` - // ^^^^ - span.to(ty - .as_ref() - .map(|ty| ty.span) - .unwrap_or(span)), - &msg, - format!("{}: {}", snippet, concrete_type), - Applicability::MaybeIncorrect, - ); - } - _ => { - err.span_label(span, msg); - } + match (filename, parent_node, snippet) { + ( + FileName::Real(_), + Node::Local(hir::Local { + source: hir::LocalSource::Normal, + ty, + .. + }), + Ok(ref snippet), + ) => { + err.span_suggestion( + // account for `let x: _ = 42;` + // ^^^^ + span.to(ty + .as_ref() + .map(|ty| ty.span) + .unwrap_or(span)), + &msg, + format!("{}: {}", snippet, concrete_type), + Applicability::MaybeIncorrect, + ); + } + _ => { + err.span_label(span, msg); } } } @@ -384,11 +379,11 @@ // Don't show generic arguments when the method can't be found in any implementation (#81576). let mut ty_str_reported = ty_str.clone(); - if let ty::Adt(_, ref generics) = actual.kind() { + if let ty::Adt(_, generics) = actual.kind() { if generics.len() > 0 { let mut autoderef = self.autoderef(span, actual); let candidate_found = autoderef.any(|(ty, _)| { - if let ty::Adt(ref adt_deref, _) = ty.kind() { + if let ty::Adt(adt_deref, _) = ty.kind() { self.tcx .inherent_impls(adt_deref.did) .iter() @@ -435,7 +430,7 @@ } } if let Some(span) = - tcx.sess.confused_type_with_std_module.borrow().get(&span) + tcx.resolutions(()).confused_type_with_std_module.get(&span) { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) { err.span_suggestion( @@ -483,7 +478,7 @@ let mut label_span_not_found = || { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); - if let ty::Adt(ref adt, _) = rcvr_ty.kind() { + if let ty::Adt(adt, _) = rcvr_ty.kind() { let mut inherent_impls_candidate = self .tcx .inherent_impls(adt.did) @@ -512,7 +507,7 @@ } }) .collect::>(); - if inherent_impls_candidate.len() > 0 { + if !inherent_impls_candidate.is_empty() { inherent_impls_candidate.sort(); inherent_impls_candidate.dedup(); @@ -566,7 +561,7 @@ let is_accessible = field.vis.is_accessible_from(scope, self.tcx); if is_accessible { - if self.is_fn_ty(&field_ty, span) { + if self.is_fn_ty(field_ty, span) { let expr_span = expr.span.to(item_name.span); err.multipart_suggestion( &format!( @@ -606,7 +601,7 @@ label_span_not_found(); } - if self.is_fn_ty(&rcvr_ty, span) { + if self.is_fn_ty(rcvr_ty, span) { fn report_function( err: &mut DiagnosticBuilder<'_>, name: T, @@ -619,7 +614,7 @@ if let SelfSource::MethodCall(expr) = source { if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) { report_function(&mut err, expr_string); - } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind { + } else if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind { if let Some(segment) = path.segments.last() { report_function(&mut err, segment.ident); } @@ -743,7 +738,7 @@ let projection_ty = pred.skip_binder().projection_ty; let substs_with_infer_self = tcx.mk_substs( - iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into()) + iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into()) .chain(projection_ty.substs.iter().skip(1)), ); @@ -809,7 +804,7 @@ ); } - bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically. + bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically. bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order. bound_spans.sort(); @@ -830,6 +825,8 @@ err.note(&format!( "the following trait bounds were not satisfied:\n{bound_list}" )); + self.suggest_derive(&mut err, &unsatisfied_predicates); + unsatisfied_bounds = true; } } @@ -972,6 +969,155 @@ None } + crate fn note_unmet_impls_on_type( + &self, + err: &mut rustc_errors::DiagnosticBuilder<'_>, + errors: Vec>, + ) { + let all_local_types_needing_impls = + errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(pred) => match pred.self_ty().kind() { + ty::Adt(def, _) => def.did.is_local(), + _ => false, + }, + _ => false, + }); + let mut preds: Vec<_> = errors + .iter() + .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(pred) => Some(pred), + _ => None, + }) + .collect(); + preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty())); + let def_ids = preds + .iter() + .filter_map(|pred| match pred.self_ty().kind() { + ty::Adt(def, _) => Some(def.did), + _ => None, + }) + .collect::>(); + let sm = self.tcx.sess.source_map(); + let mut spans: MultiSpan = def_ids + .iter() + .filter_map(|def_id| { + let span = self.tcx.def_span(*def_id); + if span.is_dummy() { None } else { Some(sm.guess_head_span(span)) } + }) + .collect::>() + .into(); + + for pred in &preds { + match pred.self_ty().kind() { + ty::Adt(def, _) => { + spans.push_span_label( + sm.guess_head_span(self.tcx.def_span(def.did)), + format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), + ); + } + _ => {} + } + } + + if all_local_types_needing_impls && spans.primary_span().is_some() { + let msg = if preds.len() == 1 { + format!( + "an implementation of `{}` might be missing for `{}`", + preds[0].trait_ref.print_only_trait_path(), + preds[0].self_ty() + ) + } else { + format!( + "the following type{} would have to `impl` {} required trait{} for this \ + operation to be valid", + pluralize!(def_ids.len()), + if def_ids.len() == 1 { "its" } else { "their" }, + pluralize!(preds.len()), + ) + }; + err.span_note(spans, &msg); + } + + let preds: Vec<_> = errors.iter().map(|e| (e.obligation.predicate, None)).collect(); + self.suggest_derive(err, &preds); + } + + fn suggest_derive( + &self, + err: &mut DiagnosticBuilder<'_>, + unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option>)>, + ) { + let mut derives = Vec::<(String, Span, String)>::new(); + let mut traits = Vec::::new(); + for (pred, _) in unsatisfied_predicates { + let trait_pred = match pred.kind().skip_binder() { + ty::PredicateKind::Trait(trait_pred) => trait_pred, + _ => continue, + }; + let adt = match trait_pred.self_ty().ty_adt_def() { + Some(adt) if adt.did.is_local() => adt, + _ => continue, + }; + let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) { + Some(sym::Default) => !adt.is_enum(), + Some( + sym::Eq + | sym::PartialEq + | sym::Ord + | sym::PartialOrd + | sym::Clone + | sym::Copy + | sym::Hash + | sym::Debug, + ) => true, + _ => false, + }; + if can_derive { + derives.push(( + format!("{}", trait_pred.self_ty()), + self.tcx.def_span(adt.did), + format!("{}", trait_pred.trait_ref.print_only_trait_name()), + )); + } else { + traits.push(self.tcx.def_span(trait_pred.def_id())); + } + } + derives.sort(); + let derives_grouped = derives.into_iter().fold( + Vec::<(String, Span, String)>::new(), + |mut acc, (self_name, self_span, trait_name)| { + if let Some((acc_self_name, _, ref mut traits)) = acc.last_mut() { + if acc_self_name == &self_name { + traits.push_str(format!(", {}", trait_name).as_str()); + return acc; + } + } + acc.push((self_name, self_span, trait_name)); + acc + }, + ); + traits.sort(); + traits.dedup(); + + let len = traits.len(); + if len > 0 { + let span: MultiSpan = traits.into(); + err.span_note( + span, + &format!("the following trait{} must be implemented", pluralize!(len),), + ); + } + + for (self_name, self_span, traits) in &derives_grouped { + err.span_suggestion_verbose( + self_span.shrink_to_lo(), + &format!("consider annotating `{}` with `#[derive({})]`", self_name, traits), + format!("#[derive({})]\n", traits), + Applicability::MaybeIncorrect, + ); + } + } + /// Print out the type for use in value namespace. fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String { match ty.kind() { @@ -1011,9 +1157,7 @@ candidates: Vec, ) { let module_did = self.tcx.parent_module(self.body_id); - let module_id = self.tcx.hir().local_def_id_to_hir_id(module_did); - let krate = self.tcx.hir().krate(); - let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id); + let (span, found_use) = find_use_placement(self.tcx, module_did); if let Some(span) = span { let path_strings = candidates.iter().map(|did| { // Produce an additional newline to separate the new use statement @@ -1293,9 +1437,7 @@ ) }; // Obtain the span for `param` and use it for a structured suggestion. - if let (Some(ref param), Some(ref table)) = - (param_type, self.in_progress_typeck_results) - { + if let (Some(param), Some(table)) = (param_type, self.in_progress_typeck_results) { let table_owner = table.borrow().hir_owner; let generics = self.tcx.generics_of(table_owner.to_def_id()); let type_param = generics.type_param(param, self.tcx); @@ -1306,7 +1448,7 @@ // We do this to avoid suggesting code that ends up as `T: FooBar`, // instead we suggest `T: Foo + Bar` in that case. match hir.get(id) { - Node::GenericParam(ref param) => { + Node::GenericParam(param) => { let mut impl_trait = false; let has_bounds = if let hir::GenericParamKind::Type { synthetic: Some(_), .. } = @@ -1480,7 +1622,7 @@ match ty.kind() { ty::Adt(def, _) => def.did.is_local(), ty::Foreign(did) => did.is_local(), - ty::Dynamic(ref tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()), + ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()), ty::Param(_) => true, // Everything else (primitive types, etc.) is effectively @@ -1568,7 +1710,7 @@ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } - tcx.hir().krate().visit_all_item_likes(&mut Visitor { traits: &mut traits }); + tcx.hir().visit_all_item_likes(&mut Visitor { traits: &mut traits }); // Cross-crate: @@ -1577,7 +1719,7 @@ tcx: TyCtxt<'_>, traits: &mut Vec, external_mods: &mut FxHashSet, - res: Res, + res: Res, ) { match res { Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => { @@ -1606,64 +1748,38 @@ providers.all_traits = compute_all_traits; } -struct UsePlacementFinder<'tcx> { - target_module: hir::HirId, - span: Option, - found_use: bool, - tcx: TyCtxt<'tcx>, -} - -impl UsePlacementFinder<'tcx> { - fn check( - tcx: TyCtxt<'tcx>, - krate: &'tcx hir::Crate<'tcx>, - target_module: hir::HirId, - ) -> (Option, bool) { - let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx }; - intravisit::walk_crate(&mut finder, krate); - (finder.span, finder.found_use) - } -} - -impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> { - fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) { - if self.span.is_some() { - return; - } - if hir_id != self.target_module { - intravisit::walk_mod(self, module, hir_id); - return; - } - // Find a `use` statement. - for &item_id in module.item_ids { - let item = self.tcx.hir().item(item_id); - match item.kind { - hir::ItemKind::Use(..) => { - // Don't suggest placing a `use` before the prelude - // import or other generated ones. +fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Option, bool) { + let mut span = None; + let mut found_use = false; + let (module, _, _) = tcx.hir().get_module(target_module); + + // Find a `use` statement. + for &item_id in module.item_ids { + let item = tcx.hir().item(item_id); + match item.kind { + hir::ItemKind::Use(..) => { + // Don't suggest placing a `use` before the prelude + // import or other generated ones. + if !item.span.from_expansion() { + span = Some(item.span.shrink_to_lo()); + found_use = true; + break; + } + } + // Don't place `use` before `extern crate`... + hir::ItemKind::ExternCrate(_) => {} + // ...but do place them before the first other item. + _ => { + if span.map_or(true, |span| item.span < span) { if !item.span.from_expansion() { - self.span = Some(item.span.shrink_to_lo()); - self.found_use = true; - return; - } - } - // Don't place `use` before `extern crate`... - hir::ItemKind::ExternCrate(_) => {} - // ...but do place them before the first other item. - _ => { - if self.span.map_or(true, |span| item.span < span) { - if !item.span.from_expansion() { - self.span = Some(item.span.shrink_to_lo()); - // Don't insert between attributes and an item. - let attrs = self.tcx.hir().attrs(item.hir_id()); - // Find the first attribute on the item. - // FIXME: This is broken for active attributes. - for attr in attrs { - if !attr.span.is_dummy() - && self.span.map_or(true, |span| attr.span < span) - { - self.span = Some(attr.span.shrink_to_lo()); - } + span = Some(item.span.shrink_to_lo()); + // Don't insert between attributes and an item. + let attrs = tcx.hir().attrs(item.hir_id()); + // Find the first attribute on the item. + // FIXME: This is broken for active attributes. + for attr in attrs { + if !attr.span.is_dummy() && span.map_or(true, |span| attr.span < span) { + span = Some(attr.span.shrink_to_lo()); } } } @@ -1672,11 +1788,7 @@ } } - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } + (span, found_use) } fn print_disambiguation_help( @@ -1690,6 +1802,7 @@ span: Span, candidate: Option, source_map: &source_map::SourceMap, + fn_has_self_parameter: bool, ) { let mut applicability = Applicability::MachineApplicable; let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) { @@ -1708,9 +1821,14 @@ .collect::>() .join(", "), ); + let trait_name = if !fn_has_self_parameter { + format!("<{} as {}>", rcvr_ty, trait_name) + } else { + trait_name + }; (span, format!("{}::{}{}", trait_name, item_name, args)) } else { - (span.with_hi(item_name.span.lo()), format!("{}::", trait_name)) + (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name)) }; err.span_suggestion_verbose( span, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -271,22 +271,22 @@ ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { match tcx.hir().get(id) { Node::Item(item) => match item.kind { - hir::ItemKind::Const(ref ty, body) | hir::ItemKind::Static(ref ty, _, body) => { + hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { Some((body, Some(ty), None)) } - hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(&sig))), + hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), _ => None, }, Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None)), + hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)), hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - Some((body, None, Some(&sig))) + Some((body, None, Some(sig))) } _ => None, }, Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None)), - hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(&sig))), + hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)), + hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))), _ => None, }, Node::AnonConst(constant) => Some((constant.body, None, None)), @@ -388,10 +388,9 @@ // from normalization. We could just discard these, but to align with // compare_method and elsewhere, we just add implied bounds for // these types. - let mut wf_tys = vec![]; + let mut wf_tys = FxHashSet::default(); // Compute the fty from point of view of inside the fn. let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); - wf_tys.extend(fn_sig.inputs_and_output.iter()); let fn_sig = inh.normalize_associated_types_in( body.value.span, body_id.hir_id, @@ -451,7 +450,7 @@ fcx.write_ty(id, expected_type); - (fcx, vec![]) + (fcx, FxHashSet::default()) }; let fallback_has_occurred = fcx.type_inference_fallback(); @@ -475,7 +474,7 @@ fcx.select_all_obligations_or_error(); if fn_sig.is_some() { - fcx.regionck_fn(id, body, span, &wf_tys); + fcx.regionck_fn(id, body, span, wf_tys); } else { fcx.regionck_expr(body); } @@ -555,16 +554,13 @@ // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. - match tcx.eval_static_initializer(id.to_def_id()) { - Ok(alloc) => { - if alloc.relocations().len() != 0 { - let msg = "statics with a custom `#[link_section]` must be a \ + if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) { + if alloc.relocations().len() != 0 { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.sess.span_err(span, msg); - } + tcx.sess.span_err(span, msg); } - Err(_) => {} } } @@ -631,7 +627,7 @@ let padding: String = " ".repeat(indentation); for trait_item in missing_items { - let snippet = suggestion_signature(&trait_item, tcx); + let snippet = suggestion_signature(trait_item, tcx); let code = format!("{}{}\n{}", padding, snippet, padding); let msg = format!("implement the missing item: `{}`", snippet); let appl = Applicability::HasPlaceholders; @@ -921,9 +917,7 @@ } fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { - tcx.par_body_owners(|body_owner_def_id| { - tcx.ensure().typeck(body_owner_def_id); - }); + tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); } fn fatally_break_rust(sess: &Session) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/op.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/op.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/op.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/op.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,6 +18,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt}; use std::ops::ControlFlow; @@ -257,12 +258,10 @@ method.sig.output() } // error types are considered "builtin" - Err(()) if lhs_ty.references_error() || rhs_ty.references_error() => { - self.tcx.ty_error() - } - Err(()) => { + Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), + Err(errors) => { let source_map = self.tcx.sess.source_map(); - let (mut err, missing_trait, use_output, involves_fn) = match is_assign { + let (mut err, missing_trait, use_output) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( self.tcx.sess, @@ -289,7 +288,8 @@ hir::BinOpKind::Shr => Some("std::ops::ShrAssign"), _ => None, }; - (err, missing_trait, false, false) + self.note_unmet_impls_on_type(&mut err, errors); + (err, missing_trait, false) } IsAssign::No => { let (message, missing_trait, use_output) = match op.node { @@ -376,9 +376,8 @@ }; let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{}", message.as_str()); - let mut involves_fn = false; if !lhs_expr.span.eq(&rhs_expr.span) { - involves_fn |= self.add_type_neq_err_label( + self.add_type_neq_err_label( &mut err, lhs_expr.span, lhs_ty, @@ -386,7 +385,7 @@ op, is_assign, ); - involves_fn |= self.add_type_neq_err_label( + self.add_type_neq_err_label( &mut err, rhs_expr.span, rhs_ty, @@ -395,10 +394,10 @@ is_assign, ); } - (err, missing_trait, use_output, involves_fn) + self.note_unmet_impls_on_type(&mut err, errors); + (err, missing_trait, use_output) } }; - let mut suggested_deref = false; if let Ref(_, rty, _) = lhs_ty.kind() { if { self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span) @@ -423,7 +422,6 @@ "*".to_string(), rustc_errors::Applicability::MachineApplicable, ); - suggested_deref = true; } } } @@ -444,7 +442,7 @@ // Check if the method would be found if the type param wasn't // involved. If so, it means that adding a trait bound to the param is // enough. Otherwise we do not give the suggestion. - let mut eraser = TypeParamEraser(&self, expr.span); + let mut eraser = TypeParamEraser(self, expr.span); let needs_bound = self .lookup_op_method( eraser.fold_ty(lhs_ty), @@ -474,8 +472,6 @@ } else { bug!("type param visitor stored a non type param: {:?}", ty.kind()); } - } else if !suggested_deref && !involves_fn { - suggest_impl_missing(&mut err, lhs_ty, &missing_trait); } } err.emit(); @@ -572,7 +568,7 @@ on the left and may require reallocation. This \ requires ownership of the string on the left"; - let string_type = self.tcx.get_diagnostic_item(sym::string_type); + let string_type = self.tcx.get_diagnostic_item(sym::String); let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() { Some(ty_def) => Some(ty_def.did) == string_type, None => false, @@ -665,7 +661,7 @@ self.write_method_call(ex.hir_id, method); method.sig.output() } - Err(()) => { + Err(errors) => { let actual = self.resolve_vars_if_possible(operand_ty); if !actual.references_error() { let mut err = struct_span_err!( @@ -680,42 +676,48 @@ ex.span, format!("cannot apply unary operator `{}`", op.as_str()), ); - match actual.kind() { - Uint(_) if op == hir::UnOp::Neg => { - err.note("unsigned values cannot be negated"); - - if let hir::ExprKind::Unary( - _, - hir::Expr { - kind: - hir::ExprKind::Lit(Spanned { - node: ast::LitKind::Int(1, _), - .. - }), - .. - }, - ) = ex.kind - { - err.span_suggestion( - ex.span, - &format!( - "you may have meant the maximum value of `{}`", - actual - ), - format!("{}::MAX", actual), - Applicability::MaybeIncorrect, - ); + + let sp = self.tcx.sess.source_map().start_point(ex.span); + if let Some(sp) = + self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) + { + // If the previous expression was a block expression, suggest parentheses + // (turning this into a binary subtraction operation instead.) + // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs) + self.tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp); + } else { + match actual.kind() { + Uint(_) if op == hir::UnOp::Neg => { + err.note("unsigned values cannot be negated"); + + if let hir::ExprKind::Unary( + _, + hir::Expr { + kind: + hir::ExprKind::Lit(Spanned { + node: ast::LitKind::Int(1, _), + .. + }), + .. + }, + ) = ex.kind + { + err.span_suggestion( + ex.span, + &format!( + "you may have meant the maximum value of `{}`", + actual + ), + format!("{}::MAX", actual), + Applicability::MaybeIncorrect, + ); + } + } + Str | Never | Char | Tuple(_) | Array(_, _) => {} + Ref(_, lty, _) if *lty.kind() == Str => {} + _ => { + self.note_unmet_impls_on_type(&mut err, errors); } - } - Str | Never | Char | Tuple(_) | Array(_, _) => {} - Ref(_, ref lty, _) if *lty.kind() == Str => {} - _ => { - let missing_trait = match op { - hir::UnOp::Neg => "std::ops::Neg", - hir::UnOp::Not => "std::ops::Not", - hir::UnOp::Deref => "std::ops::UnDerf", - }; - suggest_impl_missing(&mut err, operand_ty, &missing_trait); } } err.emit(); @@ -730,7 +732,7 @@ lhs_ty: Ty<'tcx>, other_tys: &[Ty<'tcx>], op: Op, - ) -> Result, ()> { + ) -> Result, Vec>> { let lang = self.tcx.lang_items(); let span = match op { @@ -809,22 +811,31 @@ Op::Unary(..) => 0, }, ) { - return Err(()); + return Err(vec![]); } + let opname = Ident::with_dummy_span(opname); let method = trait_did.and_then(|trait_did| { - let opname = Ident::with_dummy_span(opname); self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) }); - match method { - Some(ok) => { + match (method, trait_did) { + (Some(ok), _) => { let method = self.register_infer_ok_obligations(ok); self.select_obligations_where_possible(false, |_| {}); - Ok(method) } - None => Err(()), + (None, None) => Err(vec![]), + (None, Some(trait_did)) => { + let (obligation, _) = + self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys)); + let mut fulfill = >::new(self.tcx); + fulfill.register_predicate_obligation(self, obligation); + Err(match fulfill.select_where_possible(&self.infcx) { + Err(errors) => errors, + _ => vec![], + }) + } } } } @@ -950,18 +961,6 @@ } } } - -/// If applicable, note that an implementation of `trait` for `ty` may fix the error. -fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) { - if let Adt(def, _) = ty.peel_refs().kind() { - if def.did.is_local() { - err.note(&format!( - "an implementation of `{}` might be missing for `{}`", - missing_trait, ty - )); - } - } -} fn suggest_constraining_param( tcx: TyCtxt<'_>, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/pat.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/pat.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/pat.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/pat.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,6 +11,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::subst::GenericArg; use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable}; +use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; @@ -180,8 +181,8 @@ self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) } PatKind::Path(_) => self.check_pat_path(pat, path_res.unwrap(), expected, ti), - PatKind::Struct(ref qpath, fields, etc) => { - self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti) + PatKind::Struct(ref qpath, fields, has_rest_pat) => { + self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti) } PatKind::Or(pats) => { let parent_pat = Some(pat); @@ -340,7 +341,7 @@ expected: Ty<'tcx>, mut def_bm: BindingMode, ) -> (Ty<'tcx>, BindingMode) { - let mut expected = self.resolve_vars_with_obligations(&expected); + let mut expected = self.resolve_vars_with_obligations(expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches @@ -448,16 +449,22 @@ ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr { - None => (None, None), + None => None, Some(expr) => { let ty = self.check_expr(expr); - // Check that the end-point is of numeric or char type. - let fail = !(ty.is_numeric() || ty.is_char() || ty.references_error()); - (Some(ty), Some((fail, ty, expr.span))) + // Check that the end-point is possibly of numeric or char type. + // The early check here is not for correctness, but rather better + // diagnostics (e.g. when `&str` is being matched, `expected` will + // be peeled to `str` while ty here is still `&str`, if we don't + // err ealy here, a rather confusing unification error will be + // emitted instead). + let fail = + !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error()); + Some((fail, ty, expr.span)) } }; - let (lhs_ty, lhs) = calc_side(lhs); - let (rhs_ty, rhs) = calc_side(rhs); + let mut lhs = calc_side(lhs); + let mut rhs = calc_side(rhs); if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { // There exists a side that didn't meet our criteria that the end-point @@ -466,25 +473,42 @@ return self.tcx.ty_error(); } - // Now that we know the types can be unified we find the unified type - // and use it to type the entire expression. - let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected)); - + // Unify each side with `expected`. // Subtyping doesn't matter here, as the value is some kind of scalar. - let demand_eqtype = |x, y| { - if let Some((_, x_ty, x_span)) = x { + let demand_eqtype = |x: &mut _, y| { + if let Some((ref mut fail, x_ty, x_span)) = *x { if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) { if let Some((_, y_ty, y_span)) = y { self.endpoint_has_type(&mut err, y_span, y_ty); } err.emit(); + *fail = true; }; } }; - demand_eqtype(lhs, rhs); - demand_eqtype(rhs, lhs); + demand_eqtype(&mut lhs, rhs); + demand_eqtype(&mut rhs, lhs); + + if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { + return self.tcx.ty_error(); + } - common_type + // Find the unified type and check if it's of numeric or char type again. + // This check is needed if both sides are inference variables. + // We require types to be resolved here so that we emit inference failure + // rather than "_ is not a char or numeric". + let ty = self.structurally_resolved_type(span, expected); + if !(ty.is_numeric() || ty.is_char() || ty.references_error()) { + if let Some((ref mut fail, _, _)) = lhs { + *fail = true; + } + if let Some((ref mut fail, _, _)) = rhs { + *fail = true; + } + self.emit_err_pat_range(span, lhs, rhs); + return self.tcx.ty_error(); + } + ty } fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) { @@ -511,10 +535,14 @@ E0029, "only `char` and numeric types are allowed in range patterns" ); - let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty); + let msg = |ty| { + let ty = self.resolve_vars_if_possible(ty); + format!("this is of type `{}` but it should be `char` or numeric", ty) + }; let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { err.span_label(first_span, &msg(first_ty)); if let Some((_, ty, sp)) = second { + let ty = self.resolve_vars_if_possible(ty); self.endpoint_has_type(&mut err, sp, ty); } }; @@ -586,7 +614,7 @@ } if let Some(p) = sub { - self.check_pat(&p, expected, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); + self.check_pat(p, expected, def_bm, TopInfo { parent_pat: Some(pat), ..ti }); } local_ty @@ -684,7 +712,7 @@ pat: &'tcx Pat<'tcx>, qpath: &hir::QPath<'_>, fields: &'tcx [hir::PatField<'tcx>], - etc: bool, + has_rest_pat: bool, expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, @@ -696,8 +724,8 @@ } else { let err = self.tcx.ty_error(); for field in fields { - let ti = TopInfo { parent_pat: Some(&pat), ..ti }; - self.check_pat(&field.pat, err, def_bm, ti); + let ti = TopInfo { parent_pat: Some(pat), ..ti }; + self.check_pat(field.pat, err, def_bm, ti); } return err; }; @@ -706,7 +734,7 @@ self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) { + if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) { pat_ty } else { self.tcx.ty_error() @@ -875,7 +903,7 @@ let on_error = || { let parent_pat = Some(pat); for pat in subpats { - self.check_pat(&pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti }); + self.check_pat(pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti }); } }; let report_unexpected_res = |res: Res| { @@ -960,7 +988,7 @@ }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); - self.check_pat(&subpat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); + self.check_pat(subpat, field_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti }); self.tcx.check_stability( variant.fields[i].did, @@ -1150,7 +1178,7 @@ let mut expected_len = elements.len(); if ddpos.is_some() { // Require known type only when `..` is present. - if let ty::Tuple(ref tys) = self.structurally_resolved_type(span, expected).kind() { + if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() { expected_len = tys.len(); } } @@ -1171,12 +1199,12 @@ // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| tcx.ty_error()); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, &tcx.ty_error(), def_bm, ti); + self.check_pat(elem, tcx.ty_error(), def_bm, ti); } tcx.mk_tup(element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, &element_tys[i].expect_ty(), def_bm, ti); + self.check_pat(elem, element_tys[i].expect_ty(), def_bm, ti); } pat_ty } @@ -1188,7 +1216,7 @@ pat: &'tcx Pat<'tcx>, variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], - etc: bool, + has_rest_pat: bool, def_bm: BindingMode, ti: TopInfo<'tcx>, ) -> bool { @@ -1239,14 +1267,14 @@ } }; - self.check_pat(&field.pat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); + self.check_pat(field.pat, field_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti }); } let mut unmentioned_fields = variant .fields .iter() .map(|field| (field, field.ident.normalize_to_macros_2_0())) - .filter(|(_, ident)| !used_fields.contains_key(&ident)) + .filter(|(_, ident)| !used_fields.contains_key(ident)) .collect::>(); let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) { @@ -1261,7 +1289,8 @@ }; // Require `..` if struct has non_exhaustive attribute. - if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc { + let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local(); + if non_exhaustive && !has_rest_pat { self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); } @@ -1273,10 +1302,10 @@ .struct_span_err(pat.span, "union patterns should have exactly one field") .emit(); } - if etc { + if has_rest_pat { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } - } else if !etc && !unmentioned_fields.is_empty() { + } else if !unmentioned_fields.is_empty() { let accessible_unmentioned_fields: Vec<_> = unmentioned_fields .iter() .copied() @@ -1285,15 +1314,23 @@ }) .collect(); - if accessible_unmentioned_fields.is_empty() { - unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); - } else { - unmentioned_err = Some(self.error_unmentioned_fields( + if !has_rest_pat { + if accessible_unmentioned_fields.is_empty() { + unmentioned_err = Some(self.error_no_accessible_fields(pat, fields)); + } else { + unmentioned_err = Some(self.error_unmentioned_fields( + pat, + &accessible_unmentioned_fields, + accessible_unmentioned_fields.len() != unmentioned_fields.len(), + fields, + )); + } + } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() { + self.lint_non_exhaustive_omitted_patterns( pat, &accessible_unmentioned_fields, - accessible_unmentioned_fields.len() != unmentioned_fields.len(), - &fields, - )); + adt_ty, + ) } } match (inexistent_fields_err, unmentioned_err) { @@ -1447,7 +1484,8 @@ plural ), ); - if plural == "" { + + if unmentioned_fields.len() == 1 { let input = unmentioned_fields.iter().map(|(_, field)| field.name).collect::>(); let suggested_name = find_best_match_for_name(&input, ident.name, None); @@ -1468,6 +1506,18 @@ // We don't want to throw `E0027` in case we have thrown `E0026` for them. unmentioned_fields.retain(|&(_, x)| x.name != suggested_name); } + } else if inexistent_fields.len() == 1 { + let unmentioned_field = unmentioned_fields[0].1.name; + err.span_suggestion_short( + ident.span, + &format!( + "`{}` has a field named `{}`", + tcx.def_path_str(variant.def_id), + unmentioned_field + ), + unmentioned_field.to_string(), + Applicability::MaybeIncorrect, + ); } } } @@ -1604,6 +1654,51 @@ err } + /// Report that a pattern for a `#[non_exhaustive]` struct marked with `non_exhaustive_omitted_patterns` + /// is not exhaustive enough. + /// + /// Nb: the partner lint for enums lives in `compiler/rustc_mir_build/src/thir/pattern/usefulness.rs`. + fn lint_non_exhaustive_omitted_patterns( + &self, + pat: &Pat<'_>, + unmentioned_fields: &[(&ty::FieldDef, Ident)], + ty: Ty<'tcx>, + ) { + fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String { + const LIMIT: usize = 3; + match witnesses { + [] => bug!(), + [witness] => format!("`{}`", witness), + [head @ .., tail] if head.len() < LIMIT => { + let head: Vec<_> = head.iter().map(<_>::to_string).collect(); + format!("`{}` and `{}`", head.join("`, `"), tail) + } + _ => { + let (head, tail) = witnesses.split_at(LIMIT); + let head: Vec<_> = head.iter().map(<_>::to_string).collect(); + format!("`{}` and {} more", head.join("`, `"), tail.len()) + } + } + } + let joined_patterns = joined_uncovered_patterns( + &unmentioned_fields.iter().map(|(_, i)| i).collect::>(), + ); + + self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| { + let mut lint = build.build("some fields are not explicitly listed"); + lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)); + + lint.help( + "ensure that all fields are mentioned explicitly by adding the suggested fields", + ); + lint.note(&format!( + "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found", + ty, + )); + lint.emit(); + }); + } + /// Returns a diagnostic reporting a struct pattern which does not mention some fields. /// /// ```text @@ -1700,7 +1795,7 @@ ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, &inner) { + let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, inner) { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using `demand::eqtype`. let inner_ty = self.next_ty_var(TypeVariableOrigin { @@ -1714,7 +1809,7 @@ let err = tcx.ty_error(); (err, err) }; - self.check_pat(&inner, inner_ty, def_bm, ti); + self.check_pat(inner, inner_ty, def_bm, ti); box_ty } @@ -1729,7 +1824,7 @@ ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); - let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, &inner) { + let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, inner) { // `demand::subtype` would be good enough, but using `eqtype` turns // out to be equally general. See (note_1) for details. @@ -1751,7 +1846,7 @@ // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` if let Some(mut err) = err { - self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected); + self.borrow_pat_suggestion(&mut err, pat, inner, expected); err.emit(); } (rptr_ty, inner_ty) @@ -1761,7 +1856,7 @@ let err = tcx.ty_error(); (err, err) }; - self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); + self.check_pat(inner, inner_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti }); rptr_ty } @@ -1817,15 +1912,15 @@ // Type check all the patterns before `slice`. for elt in before { - self.check_pat(&elt, element_ty, def_bm, ti); + self.check_pat(elt, element_ty, def_bm, ti); } // Type check the `slice`, if present, against its expected type. if let Some(slice) = slice { - self.check_pat(&slice, opt_slice_ty.unwrap(), def_bm, ti); + self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti); } // Type check the elements after `slice`, if present. for elt in after { - self.check_pat(&elt, element_ty, def_bm, ti); + self.check_pat(elt, element_ty, def_bm, ti); } inferred } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/place_op.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/place_op.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/place_op.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/place_op.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,7 @@ use crate::check::method::MethodCallee; use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp}; +use rustc_ast as ast; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; @@ -47,6 +49,7 @@ expr: &hir::Expr<'_>, base_expr: &'tcx hir::Expr<'tcx>, base_ty: Ty<'tcx>, + index_expr: &'tcx hir::Expr<'tcx>, idx_ty: Ty<'tcx>, ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { // FIXME(#18741) -- this is almost but not quite the same as the @@ -56,12 +59,42 @@ let mut autoderef = self.autoderef(base_expr.span, base_ty); let mut result = None; while result.is_none() && autoderef.next().is_some() { - result = self.try_index_step(expr, base_expr, &autoderef, idx_ty); + result = self.try_index_step(expr, base_expr, &autoderef, idx_ty, index_expr); } self.register_predicates(autoderef.into_obligations()); result } + fn negative_index( + &self, + ty: Ty<'tcx>, + span: Span, + base_expr: &hir::Expr<'_>, + ) -> Option<(Ty<'tcx>, Ty<'tcx>)> { + let ty = self.resolve_vars_if_possible(ty); + let mut err = self.tcx.sess.struct_span_err( + span, + &format!("negative integers cannot be used to index on a `{}`", ty), + ); + err.span_label(span, &format!("cannot use a negative integer for indexing on `{}`", ty)); + if let (hir::ExprKind::Path(..), Ok(snippet)) = + (&base_expr.kind, self.tcx.sess.source_map().span_to_snippet(base_expr.span)) + { + // `foo[-1]` to `foo[foo.len() - 1]` + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "to access an element starting from the end of the `{}`, compute the index", + ty, + ), + format!("{}.len() ", snippet), + Applicability::MachineApplicable, + ); + } + err.emit(); + Some((self.tcx.ty_error(), self.tcx.ty_error())) + } + /// To type-check `base_expr[index_expr]`, we progressively autoderef /// (and otherwise adjust) `base_expr`, looking for a type which either /// supports builtin indexing or overloaded indexing. @@ -73,6 +106,7 @@ base_expr: &hir::Expr<'_>, autoderef: &Autoderef<'a, 'tcx>, index_ty: Ty<'tcx>, + index_expr: &hir::Expr<'_>, ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { let adjusted_ty = self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); @@ -82,6 +116,27 @@ expr, base_expr, adjusted_ty, index_ty ); + if let hir::ExprKind::Unary( + hir::UnOp::Neg, + hir::Expr { + kind: hir::ExprKind::Lit(hir::Lit { node: ast::LitKind::Int(..), .. }), + .. + }, + ) = index_expr.kind + { + match adjusted_ty.kind() { + ty::Adt(ty::AdtDef { did, .. }, _) + if self.tcx.is_diagnostic_item(sym::Vec, *did) => + { + return self.negative_index(adjusted_ty, index_expr.span, base_expr); + } + ty::Slice(_) | ty::Array(_, _) => { + return self.negative_index(adjusted_ty, index_expr.span, base_expr); + } + _ => {} + } + } + for unsize in [false, true] { let mut self_ty = adjusted_ty; if unsize { @@ -233,7 +288,7 @@ | hir::ExprKind::Index(ref expr, _) | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind { - exprs.push(&expr); + exprs.push(expr); } debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs); @@ -295,10 +350,10 @@ } match expr.kind { - hir::ExprKind::Index(ref base_expr, ..) => { + hir::ExprKind::Index(base_expr, ..) => { self.convert_place_op_to_mutable(PlaceOp::Index, expr, base_expr); } - hir::ExprKind::Unary(hir::UnOp::Deref, ref base_expr) => { + hir::ExprKind::Unary(hir::UnOp::Deref, base_expr) => { self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr); } _ => {} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/regionck.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/regionck.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/regionck.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/regionck.rs 2021-11-29 19:27:11.000000000 +0000 @@ -76,18 +76,19 @@ use crate::check::FnCtxt; use crate::mem_categorization as mc; use crate::middle::region; +use crate::outlives::outlives_bounds::InferCtxtExt as _; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::PatKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{self, RegionObligation, RegionckMode}; +use rustc_infer::infer::{self, InferCtxt, RegionObligation, RegionckMode}; use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId}; use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; -use rustc_trait_selection::infer::OutlivesEnvironmentExt; -use rustc_trait_selection::opaque_types::InferCtxtExt; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; use std::ops::Deref; // a variation on try that just returns unit @@ -103,6 +104,51 @@ }; } +trait OutlivesEnvironmentExt<'tcx> { + fn add_implied_bounds( + &mut self, + infcx: &InferCtxt<'a, 'tcx>, + fn_sig_tys: FxHashSet>, + body_id: hir::HirId, + span: Span, + ); +} + +impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { + /// This method adds "implied bounds" into the outlives environment. + /// Implied bounds are outlives relationships that we can deduce + /// on the basis that certain types must be well-formed -- these are + /// either the types that appear in the function signature or else + /// the input types to an impl. For example, if you have a function + /// like + /// + /// ``` + /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } + /// ``` + /// + /// we can assume in the caller's body that `'b: 'a` and that `T: + /// 'b` (and hence, transitively, that `T: 'a`). This method would + /// add those assumptions into the outlives-environment. + /// + /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs` + fn add_implied_bounds( + &mut self, + infcx: &InferCtxt<'a, 'tcx>, + fn_sig_tys: FxHashSet>, + body_id: hir::HirId, + span: Span, + ) { + debug!("add_implied_bounds()"); + + for ty in fn_sig_tys { + let ty = infcx.resolve_vars_if_possible(ty); + debug!("add_implied_bounds: ty = {}", ty); + let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); + self.add_outlives_bounds(Some(infcx), implied_bounds) + } + } +} + /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS @@ -126,7 +172,7 @@ /// Region checking during the WF phase for items. `wf_tys` are the /// types from which we should derive implied bounds, if any. - pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: &[Ty<'tcx>]) { + pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: FxHashSet>) { debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys); let subject = self.tcx.hir().local_def_id(item_id); let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env); @@ -149,7 +195,7 @@ fn_id: hir::HirId, body: &'tcx hir::Body<'tcx>, span: Span, - wf_tys: &[Ty<'tcx>], + wf_tys: FxHashSet>, ) { debug!("regionck_fn(id={})", fn_id); let subject = self.tcx.hir().body_owner_def_id(body.id()); @@ -189,7 +235,7 @@ impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> { type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { - &self.fcx + self.fcx } } @@ -286,17 +332,12 @@ // because it will have no effect. // // FIXME(#27579) return types should not be implied bounds - let fn_sig_tys: Vec<_> = + let fn_sig_tys: FxHashSet<_> = fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect(); - self.outlives_environment.add_implied_bounds( - self.fcx, - &fn_sig_tys[..], - body_id.hir_id, - span, - ); + self.outlives_environment.add_implied_bounds(self.fcx, fn_sig_tys, body_id.hir_id, span); self.outlives_environment.save_implied_bounds(body_id.hir_id); - self.link_fn_params(&body.params); + self.link_fn_params(body.params); self.visit_body(body); self.visit_region_obligations(body_id.hir_id); @@ -383,13 +424,13 @@ fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { // see above - self.constrain_bindings_in_pat(&arm.pat); + self.constrain_bindings_in_pat(arm.pat); intravisit::walk_arm(self, arm); } fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { // see above - self.constrain_bindings_in_pat(&l.pat); + self.constrain_bindings_in_pat(l.pat); self.link_local(l); intravisit::walk_local(self, l); } @@ -411,13 +452,13 @@ match expr.kind { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => { - self.link_addr_of(expr, m, &base); + self.link_addr_of(expr, m, base); intravisit::walk_expr(self, expr); } - hir::ExprKind::Match(ref discr, ref arms, _) => { - self.link_match(&discr, &arms[..]); + hir::ExprKind::Match(ref discr, arms, _) => { + self.link_match(discr, arms); intravisit::walk_expr(self, expr); } @@ -452,7 +493,7 @@ let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; let typeck_results = self.typeck_results.borrow(); - let adjustments = typeck_results.expr_adjustments(&expr); + let adjustments = typeck_results.expr_adjustments(expr); if adjustments.is_empty() { return Ok(place); } @@ -479,7 +520,7 @@ self.link_autoref(expr, &place, autoref); } - place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, &adjustment))?; + place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, adjustment))?; } Ok(place) @@ -544,10 +585,10 @@ None => { return; } - Some(ref expr) => &**expr, + Some(expr) => &*expr, }; let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))); - self.link_pattern(discr_cmt, &local.pat); + self.link_pattern(discr_cmt, local.pat); } /// Computes the guarantors for any ref bindings in a match and @@ -558,7 +599,7 @@ let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))); debug!("discr_cmt={:?}", discr_cmt); for arm in arms { - self.link_pattern(discr_cmt.clone(), &arm.pat); + self.link_pattern(discr_cmt.clone(), arm.pat); } } @@ -571,7 +612,7 @@ let param_cmt = self.with_mc(|mc| mc.cat_rvalue(param.hir_id, param.pat.span, param_ty)); debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param); - self.link_pattern(param_cmt, ¶m.pat); + self.link_pattern(param_cmt, param.pat); } } @@ -586,7 +627,7 @@ if let Some(ty::BindByReference(mutbl)) = mc.typeck_results.extract_binding_mode(self.tcx.sess, *hir_id, *span) { - self.link_region_from_node_type(*span, *hir_id, mutbl, &sub_cmt); + self.link_region_from_node_type(*span, *hir_id, mutbl, sub_cmt); } } }) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/upvar.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/upvar.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/upvar.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/upvar.rs 2021-11-29 19:27:11.000000000 +0000 @@ -86,18 +86,55 @@ /// Intermediate format to store the hir_id pointing to the use that resulted in the /// corresponding place being captured and a String which contains the captured value's /// name (i.e: a.b.c) -type CapturesInfo = (Option, String); +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum UpvarMigrationInfo { + /// We previously captured all of `x`, but now we capture some sub-path. + CapturingPrecise { source_expr: Option, var_name: String }, + CapturingNothing { + // where the variable appears in the closure (but is not captured) + use_span: Span, + }, +} + +/// Reasons that we might issue a migration warning. +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct MigrationWarningReason { + /// When we used to capture `x` in its entirety, we implemented the auto-trait(s) + /// in this vec, but now we don't. + auto_traits: Vec<&'static str>, + + /// When we used to capture `x` in its entirety, we would execute some destructors + /// at a different time. + drop_order: bool, +} -/// Intermediate format to store information needed to generate migration lint. The tuple -/// contains the hir_id pointing to the use that resulted in the -/// corresponding place being captured, a String which contains the captured value's -/// name (i.e: a.b.c) and a String which contains the reason why migration is needed for that -/// capture -type MigrationNeededForCapture = (Option, String, String); +impl MigrationWarningReason { + fn migration_message(&self) -> String { + let base = "changes to closure capture in Rust 2021 will affect"; + if !self.auto_traits.is_empty() && self.drop_order { + format!("{} drop order and which traits the closure implements", base) + } else if self.drop_order { + format!("{} drop order", base) + } else { + format!("{} which traits the closure implements", base) + } + } +} + +/// Intermediate format to store information needed to generate a note in the migration lint. +struct MigrationLintNote { + captures_info: UpvarMigrationInfo, + + /// reasons why migration is needed for this capture + reason: MigrationWarningReason, +} /// Intermediate format to store the hir id of the root variable and a HashSet containing /// information on why the root variable should be fully captured -type MigrationDiagnosticInfo = (hir::HirId, Vec); +struct NeededMigration { + var_hir_id: hir::HirId, + diagnostics_info: Vec, +} struct InferBorrowKindVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -123,6 +160,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Analysis starting point. + #[instrument(skip(self, body), level = "debug")] fn analyze_closure( &self, closure_hir_id: hir::HirId, @@ -131,8 +169,6 @@ body: &'tcx hir::Body<'tcx>, capture_clause: hir::CaptureBy, ) { - debug!("analyze_closure(id={:?}, body.id={:?})", closure_hir_id, body.id()); - // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); let (closure_def_id, substs) = match *ty.kind() { @@ -708,47 +744,66 @@ closure_head_span, |lint| { let mut diagnostics_builder = lint.build( - format!( - "changes to closure capture in Rust 2021 will affect {}", - reasons - ) - .as_str(), + &reasons.migration_message(), ); - for (var_hir_id, diagnostics_info) in need_migrations.iter() { + for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { // Labels all the usage of the captured variable and why they are responsible // for migration being needed - for (captured_hir_id, captured_name, reasons) in diagnostics_info.iter() { - if let Some(captured_hir_id) = captured_hir_id { - let cause_span = self.tcx.hir().span(*captured_hir_id); - diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", - self.tcx.hir().name(*var_hir_id), - captured_name, - )); + for lint_note in diagnostics_info.iter() { + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => { + let cause_span = self.tcx.hir().span(*capture_expr_id); + diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", + self.tcx.hir().name(*var_hir_id), + captured_name, + )); + } + UpvarMigrationInfo::CapturingNothing { use_span } => { + diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", + self.tcx.hir().name(*var_hir_id), + )); + } + + _ => { } } // Add a label pointing to where a captured variable affected by drop order // is dropped - if reasons.contains("drop order") { + if lint_note.reason.drop_order { let drop_location_span = drop_location_span(self.tcx, &closure_hir_id); - diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", - self.tcx.hir().name(*var_hir_id), - captured_name, - )); + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { + diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", + self.tcx.hir().name(*var_hir_id), + captured_name, + )); + } + UpvarMigrationInfo::CapturingNothing { use_span: _ } => { + diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", + v = self.tcx.hir().name(*var_hir_id), + )); + } + } } // Add a label explaining why a closure no longer implements a trait - if reasons.contains("trait implementation") { - let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1]; + for &missing_trait in &lint_note.reason.auto_traits { + // not capturing something anymore cannot cause a trait to fail to be implemented: + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { + let var_name = self.tcx.hir().name(*var_hir_id); + diagnostics_builder.span_label(closure_head_span, format!("\ + in Rust 2018, this closure implements {missing_trait} \ + as `{var_name}` implements {missing_trait}, but in Rust 2021, \ + this closure will no longer implement {missing_trait} \ + because `{var_name}` is not fully captured \ + and `{captured_name}` does not implement {missing_trait}")); + } - diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as `{}` does not implement {}", - missing_trait, - self.tcx.hir().name(*var_hir_id), - missing_trait, - missing_trait, - captured_name, - missing_trait, - )); + // Cannot happen: if we don't capture a variable, we impl strictly more traits + UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"), + } } } } @@ -792,7 +847,7 @@ // This is a multi-line closure with just a `{` on the first line, // so we put the `let` on its own line. // We take the indentation from the next non-empty line. - let line2 = lines.filter(|line| !line.is_empty()).next().unwrap_or_default(); + let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default(); let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0; diagnostics_builder.span_suggestion( closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(), @@ -841,25 +896,16 @@ /// Combines all the reasons for 2229 migrations fn compute_2229_migrations_reasons( &self, - auto_trait_reasons: FxHashSet<&str>, - drop_reason: bool, - ) -> String { - let mut reasons = String::new(); - - if auto_trait_reasons.len() > 0 { - reasons = format!( - "{} trait implementation for closure", - auto_trait_reasons.clone().into_iter().collect::>().join(", ") - ); - } + auto_trait_reasons: FxHashSet<&'static str>, + drop_order: bool, + ) -> MigrationWarningReason { + let mut reasons = MigrationWarningReason::default(); - if auto_trait_reasons.len() > 0 && drop_reason { - reasons = format!("{} and ", reasons); + for auto_trait in auto_trait_reasons { + reasons.auto_traits.push(auto_trait); } - if drop_reason { - reasons = format!("{}drop order", reasons); - } + reasons.drop_order = drop_order; reasons } @@ -875,11 +921,11 @@ min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, var_hir_id: hir::HirId, closure_clause: hir::CaptureBy, - ) -> Option>> { + ) -> Option>> { let auto_traits_def_id = vec![ self.tcx.lang_items().clone_trait(), self.tcx.lang_items().sync_trait(), - self.tcx.get_diagnostic_item(sym::send_trait), + self.tcx.get_diagnostic_item(sym::Send), self.tcx.lang_items().unpin_trait(), self.tcx.get_diagnostic_item(sym::unwind_safe_trait), self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), @@ -887,13 +933,7 @@ let auto_traits = vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"]; - let root_var_min_capture_list = if let Some(root_var_min_capture_list) = - min_captures.and_then(|m| m.get(&var_hir_id)) - { - root_var_min_capture_list - } else { - return None; - }; + let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?; let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); @@ -968,14 +1008,17 @@ } } - if capture_problems.len() > 0 { + if !capture_problems.is_empty() { problematic_captures.insert( - (capture.info.path_expr_id, capture.to_string(self.tcx)), + UpvarMigrationInfo::CapturingPrecise { + source_expr: capture.info.path_expr_id, + var_name: capture.to_string(self.tcx), + }, capture_problems, ); } } - if problematic_captures.len() > 0 { + if !problematic_captures.is_empty() { return Some(problematic_captures); } None @@ -993,6 +1036,7 @@ /// /// This function only returns a HashSet of CapturesInfo for significant drops. If there /// are no significant drops than None is returned + #[instrument(level = "debug", skip(self))] fn compute_2229_migrations_for_drop( &self, closure_def_id: DefId, @@ -1000,10 +1044,11 @@ min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, closure_clause: hir::CaptureBy, var_hir_id: hir::HirId, - ) -> Option> { + ) -> Option> { let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) { + debug!("does not have significant drop"); return None; } @@ -1013,16 +1058,31 @@ root_var_min_capture_list } else { // The upvar is mentioned within the closure but no path starting from it is - // used. + // used. This occurs when you have (e.g.) + // + // ``` + // let x = move || { + // let _ = y; + // }); + // ``` + debug!("no path starting from it is used"); + match closure_clause { // Only migrate if closure is a move closure - hir::CaptureBy::Value => return Some(FxHashSet::default()), + hir::CaptureBy::Value => { + let mut diagnostics_info = FxHashSet::default(); + let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar"); + let upvar = upvars[&var_hir_id]; + diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); + return Some(diagnostics_info); + } hir::CaptureBy::Ref => {} } return None; }; + debug!(?root_var_min_capture_list); let mut projections_list = Vec::new(); let mut diagnostics_info = FxHashSet::default(); @@ -1032,19 +1092,24 @@ // Only care about captures that are moved into the closure ty::UpvarCapture::ByValue(..) => { projections_list.push(captured_place.place.projections.as_slice()); - diagnostics_info.insert(( - captured_place.info.path_expr_id, - captured_place.to_string(self.tcx), - )); + diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise { + source_expr: captured_place.info.path_expr_id, + var_name: captured_place.to_string(self.tcx), + }); } ty::UpvarCapture::ByRef(..) => {} } } + debug!(?projections_list); + debug!(?diagnostics_info); + let is_moved = !projections_list.is_empty(); + debug!(?is_moved); let is_not_completely_captured = - root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0); + root_var_min_capture_list.iter().any(|capture| !capture.place.projections.is_empty()); + debug!(?is_not_completely_captured); if is_moved && is_not_completely_captured @@ -1058,7 +1123,7 @@ return Some(diagnostics_info); } - return None; + None } /// Figures out the list of root variables (and their types) that aren't completely @@ -1077,17 +1142,18 @@ /// Returns a tuple containing a vector of MigrationDiagnosticInfo, as well as a String /// containing the reason why root variables whose HirId is contained in the vector should /// be captured + #[instrument(level = "debug", skip(self))] fn compute_2229_migrations( &self, closure_def_id: DefId, closure_span: Span, closure_clause: hir::CaptureBy, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, - ) -> (Vec, String) { + ) -> (Vec, MigrationWarningReason) { let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { upvars } else { - return (Vec::new(), format!("")); + return (Vec::new(), MigrationWarningReason::default()); }; let mut need_migrations = Vec::new(); @@ -1096,7 +1162,7 @@ // Perform auto-trait analysis for (&var_hir_id, _) in upvars.iter() { - let mut responsible_captured_hir_ids = Vec::new(); + let mut diagnostics_info = Vec::new(); let auto_trait_diagnostic = if let Some(diagnostics_info) = self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) @@ -1128,34 +1194,33 @@ let mut capture_diagnostic = capture_diagnostic.into_iter().collect::>(); capture_diagnostic.sort(); - for captured_info in capture_diagnostic.iter() { + for captures_info in capture_diagnostic { // Get the auto trait reasons of why migration is needed because of that capture, if there are any let capture_trait_reasons = - if let Some(reasons) = auto_trait_diagnostic.get(captured_info) { + if let Some(reasons) = auto_trait_diagnostic.get(&captures_info) { reasons.clone() } else { FxHashSet::default() }; // Check if migration is needed because of drop reorder as a result of that capture - let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(captured_info); + let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(&captures_info); // Combine all the reasons of why the root variable should be captured as a result of // auto trait implementation issues auto_trait_migration_reasons.extend(capture_trait_reasons.clone()); - responsible_captured_hir_ids.push(( - captured_info.0, - captured_info.1.clone(), - self.compute_2229_migrations_reasons( + diagnostics_info.push(MigrationLintNote { + captures_info, + reason: self.compute_2229_migrations_reasons( capture_trait_reasons, capture_drop_reorder_reason, ), - )); + }); } - if capture_diagnostic.len() > 0 { - need_migrations.push((var_hir_id, responsible_captured_hir_ids)); + if !diagnostics_info.is_empty() { + need_migrations.push(NeededMigration { var_hir_id, diagnostics_info }); } } ( @@ -1684,15 +1749,12 @@ } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_consume( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); let tcx = self.fcx.tcx; let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { upvar_id @@ -1700,7 +1762,7 @@ return; }; - debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id); + debug!(?upvar_id); let usage_span = tcx.hir().span(diag_expr_id); @@ -1719,16 +1781,12 @@ /// Indicates that `place_with_id` is being directly mutated (e.g., assigned /// to). If the place is based on a by-ref upvar, this implies that /// the upvar must be borrowed using an `&mut` borrow. + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_mut( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_mut(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); - if let PlaceBase::Upvar(_) = place_with_id.place.base { // Raw pointers don't inherit mutability if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { @@ -1738,16 +1796,12 @@ } } + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_unique( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_unique(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); - if let PlaceBase::Upvar(_) = place_with_id.place.base { if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { // Raw pointers don't inherit mutability. @@ -1784,6 +1838,7 @@ /// moving from left to right as needed (but never right to left). /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -1792,10 +1847,7 @@ ) { let curr_capture_info = self.capture_information[&place_with_id.place]; - debug!( - "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})", - place_with_id, diag_expr_id, curr_capture_info, kind - ); + debug!(?curr_capture_info); if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind { // It's already captured by value, we don't need to do anything here @@ -1815,6 +1867,7 @@ }; } + #[instrument(skip(self, diag_expr_id), level = "debug")] fn init_capture_info_for_place( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -1841,7 +1894,7 @@ self.capture_information.insert(place_with_id.place.clone(), capture_info); } else { - debug!("Not upvar: {:?}", place_with_id); + debug!("Not upvar"); } } } @@ -1868,27 +1921,22 @@ } } + #[instrument(skip(self), level = "debug")] fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { - debug!("consume(place_with_id={:?}, diag_expr_id={:?})", place_with_id, diag_expr_id); - if !self.capture_information.contains_key(&place_with_id.place) { - self.init_capture_info_for_place(&place_with_id, diag_expr_id); + self.init_capture_info_for_place(place_with_id, diag_expr_id); } - self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id); + self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id); } + #[instrument(skip(self), level = "debug")] fn borrow( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, bk: ty::BorrowKind, ) { - debug!( - "borrow(place_with_id={:?}, diag_expr_id={:?}, bk={:?})", - place_with_id, diag_expr_id, bk - ); - // The region here will get discarded/ignored let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased }); @@ -1925,9 +1973,8 @@ } } + #[instrument(skip(self), level = "debug")] fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { - debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id); - self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow); } } @@ -2017,7 +2064,7 @@ } } - return (place, curr_mode); + (place, curr_mode) } /// Truncate deref of any reference. @@ -2086,7 +2133,7 @@ place: &Place<'tcx>, capture_info: &ty::CaptureInfo<'tcx>, ) -> String { - let place_str = construct_place_string(tcx, &place); + let place_str = construct_place_string(tcx, place); let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue(_) => "ByValue".into(), @@ -2097,7 +2144,7 @@ } fn construct_path_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String { - let place_str = construct_place_string(tcx, &place); + let place_str = construct_place_string(tcx, place); format!("{} used here", place_str) } @@ -2107,7 +2154,7 @@ place: &Place<'tcx>, capture_info: &ty::CaptureInfo<'tcx>, ) -> String { - let place_str = construct_place_string(tcx, &place); + let place_str = construct_place_string(tcx, place); let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue(_) => "ByValue".into(), @@ -2120,6 +2167,7 @@ tcx.hir().name(var_hir_id) } +#[instrument(level = "debug", skip(tcx))] fn should_do_rust_2021_incompatible_closure_captures_analysis( tcx: TyCtxt<'_>, closure_id: hir::HirId, @@ -2135,10 +2183,12 @@ /// - s2: Comma separated names of the variables being migrated. fn migration_suggestion_for_2229( tcx: TyCtxt<'_>, - need_migrations: &Vec, + need_migrations: &Vec, ) -> (String, String) { - let need_migrations_variables = - need_migrations.iter().map(|(v, _)| var_name(tcx, *v)).collect::>(); + let need_migrations_variables = need_migrations + .iter() + .map(|NeededMigration { var_hir_id: v, .. }| var_name(tcx, *v)) + .collect::>(); let migration_ref_concat = need_migrations_variables.iter().map(|v| format!("&{}", v)).collect::>().join(", "); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/wfcheck.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/wfcheck.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/wfcheck.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/wfcheck.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -12,7 +12,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_middle::hir::map as hir_map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -20,7 +20,6 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; @@ -44,7 +43,7 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> { fn with_fcx(&mut self, f: F) where - F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> Vec>, + F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> FxHashSet>, { let id = self.id; let span = self.span; @@ -59,7 +58,7 @@ } let wf_tys = f(&fcx); fcx.select_all_obligations_or_error(); - fcx.regionck_item(id, span, &wf_tys); + fcx.regionck_item(id, span, wf_tys); }); } } @@ -77,14 +76,14 @@ /// We do this check as a pre-pass before checking fn bodies because if these constraints are /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. +#[instrument(skip(tcx), level = "debug")] pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let item = tcx.hir().expect_item(hir_id); debug!( - "check_item_well_formed(it.def_id={:?}, it.name={})", - item.def_id, - tcx.def_path_str(def_id.to_def_id()) + ?item.def_id, + item.name = ? tcx.def_path_str(def_id.to_def_id()) ); match item.kind { @@ -143,23 +142,23 @@ } } hir::ItemKind::Fn(ref sig, ..) => { - check_item_fn(tcx, item.hir_id(), item.ident, item.span, sig.decl); + check_item_fn(tcx, item.def_id, item.ident, item.span, sig.decl); } - hir::ItemKind::Static(ref ty, ..) => { - check_item_type(tcx, item.hir_id(), ty.span, false); + hir::ItemKind::Static(ty, ..) => { + check_item_type(tcx, item.def_id, ty.span, false); } - hir::ItemKind::Const(ref ty, ..) => { - check_item_type(tcx, item.hir_id(), ty.span, false); + hir::ItemKind::Const(ty, ..) => { + check_item_type(tcx, item.def_id, ty.span, false); } hir::ItemKind::ForeignMod { items, .. } => { for it in items.iter() { let it = tcx.hir().foreign_item(it.id); match it.kind { - hir::ForeignItemKind::Fn(ref decl, ..) => { - check_item_fn(tcx, it.hir_id(), it.ident, it.span, decl) + hir::ForeignItemKind::Fn(decl, ..) => { + check_item_fn(tcx, it.def_id, it.ident, it.span, decl) } - hir::ForeignItemKind::Static(ref ty, ..) => { - check_item_type(tcx, it.hir_id(), ty.span, true) + hir::ForeignItemKind::Static(ty, ..) => { + check_item_type(tcx, it.def_id, ty.span, true) } hir::ForeignItemKind::Type => (), } @@ -199,8 +198,61 @@ hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span), _ => (None, trait_item.span), }; - check_object_unsafe_self_trait_by_name(tcx, &trait_item); - check_associated_item(tcx, trait_item.hir_id(), span, method_sig); + check_object_unsafe_self_trait_by_name(tcx, trait_item); + check_associated_item(tcx, trait_item.def_id, span, method_sig); + + let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id); + let encl_trait = tcx.hir().expect_item(encl_trait_hir_id); + let encl_trait_def_id = encl_trait.def_id.to_def_id(); + let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() { + Some("fn") + } else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() { + Some("fn_mut") + } else { + None + }; + + if let (Some(fn_lang_item_name), "call") = + (fn_lang_item_name, trait_item.ident.name.to_ident_string().as_str()) + { + // We are looking at the `call` function of the `fn` or `fn_mut` lang item. + // Do some rudimentary sanity checking to avoid an ICE later (issue #83471). + if let Some(hir::FnSig { decl, span, .. }) = method_sig { + if let [self_ty, _] = decl.inputs { + if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) { + tcx.sess + .struct_span_err( + self_ty.span, + &format!( + "first argument of `call` in `{}` lang item must be a reference", + fn_lang_item_name + ), + ) + .emit(); + } + } else { + tcx.sess + .struct_span_err( + *span, + &format!( + "`call` function in `{}` lang item takes exactly two arguments", + fn_lang_item_name + ), + ) + .emit(); + } + } else { + tcx.sess + .struct_span_err( + trait_item.span, + &format!( + "`call` trait item in `{}` lang item must be a function", + fn_lang_item_name + ), + ) + .emit(); + } + } } fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { @@ -275,7 +327,7 @@ _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.hir_id(), span, method_sig); + check_associated_item(tcx, impl_item.def_id, span, method_sig); } fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { @@ -385,16 +437,16 @@ #[tracing::instrument(level = "debug", skip(tcx, span, sig_if_method))] fn check_associated_item( tcx: TyCtxt<'_>, - item_id: hir::HirId, + item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))); + let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id))); for_id(tcx, item_id, span).with_fcx(|fcx| { - let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id)); + let item = fcx.tcx.associated_item(item_id); let (mut implied_bounds, self_ty) = match item.container { - ty::TraitContainer(_) => (vec![], fcx.tcx.types.self_param), + ty::TraitContainer(_) => (FxHashSet::default(), fcx.tcx.types.self_param), ty::ImplContainer(def_id) => { (fcx.impl_implied_bounds(def_id, span), fcx.tcx.type_of(def_id)) } @@ -403,11 +455,7 @@ match item.kind { ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf( - span, - ty, - WellFormedLoc::Ty(item_id.expect_owner()), - ); + let ty = fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id)); fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { @@ -421,7 +469,7 @@ item.def_id, &mut implied_bounds, ); - check_method_receiver(fcx, hir_sig, &item, self_ty); + check_method_receiver(fcx, hir_sig, item, self_ty); } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer(_) = item.container { @@ -429,11 +477,8 @@ } if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf( - span, - ty, - WellFormedLoc::Ty(item_id.expect_owner()), - ); + let ty = + fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id)); fcx.register_wf_obligation(ty.into(), span, code.clone()); } } @@ -444,14 +489,13 @@ } fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> { - for_id(tcx, item.hir_id(), item.span) + for_id(tcx, item.def_id, item.span) } -fn for_id(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) -> CheckWfFcxBuilder<'_> { - let def_id = tcx.hir().local_def_id(id); +fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> { CheckWfFcxBuilder { inherited: Inherited::build(tcx, def_id), - id, + id: hir::HirId::make_owner(def_id), span, param_env: tcx.param_env(def_id), } @@ -541,10 +585,10 @@ fcx.register_predicate(traits::Obligation::new( cause, fcx.param_env, - ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), discr_substs, - )) + ))) .to_predicate(tcx), )); } @@ -553,12 +597,13 @@ check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None); // No implied bounds in a struct definition. - vec![] + FxHashSet::default() }); } +#[instrument(skip(tcx, item))] fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { - debug!("check_trait: {:?}", item.def_id); + debug!(?item.def_id); let trait_def = tcx.trait_def(item.def_id); if trait_def.is_marker @@ -579,7 +624,7 @@ for_item(tcx, item).with_fcx(|fcx| { check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None); - vec![] + FxHashSet::default() }); } @@ -612,30 +657,25 @@ fn check_item_fn( tcx: TyCtxt<'_>, - item_id: hir::HirId, + def_id: LocalDefId, ident: Ident, span: Span, decl: &hir::FnDecl<'_>, ) { - for_id(tcx, item_id, span).with_fcx(|fcx| { - let def_id = tcx.hir().local_def_id(item_id); + for_id(tcx, def_id, span).with_fcx(|fcx| { let sig = tcx.fn_sig(def_id); - let mut implied_bounds = vec![]; + let mut implied_bounds = FxHashSet::default(); check_fn_or_method(fcx, ident.span, sig, decl, def_id.to_def_id(), &mut implied_bounds); implied_bounds }) } -fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_foreign_ty: bool) { +fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) { debug!("check_item_type: {:?}", item_id); for_id(tcx, item_id, ty_span).with_fcx(|fcx| { - let ty = tcx.type_of(tcx.hir().local_def_id(item_id)); - let item_ty = fcx.normalize_associated_types_in_wf( - ty_span, - ty, - WellFormedLoc::Ty(item_id.expect_owner()), - ); + let ty = tcx.type_of(item_id); + let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, WellFormedLoc::Ty(item_id)); let mut forbid_unsized = true; if allow_foreign_ty { @@ -648,7 +688,7 @@ fcx.register_wf_obligation( item_ty.into(), ty_span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))), + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id))), ); if forbid_unsized { fcx.register_bound( @@ -659,7 +699,7 @@ } // No implied bounds in a const, etc. - vec![] + FxHashSet::default() }); } @@ -712,13 +752,13 @@ } /// Checks where-clauses and inline bounds that are declared on `def_id`. +#[instrument(skip(fcx), level = "debug")] fn check_where_clauses<'tcx, 'fcx>( fcx: &FnCtxt<'fcx, 'tcx>, span: Span, def_id: DefId, return_ty: Option<(Ty<'tcx>, Span)>, ) { - debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty); let tcx = fcx.tcx; let predicates = tcx.predicates_of(def_id); @@ -741,7 +781,7 @@ for param in &generics.params { match param.kind { GenericParamDefKind::Type { .. } => { - if is_our_default(¶m) { + if is_our_default(param) { let ty = tcx.type_of(param.def_id); // Ignore dependent defaults -- that is, where the default of one type // parameter includes another (e.g., ``). In those cases, we can't @@ -756,7 +796,7 @@ } } GenericParamDefKind::Const { .. } => { - if is_our_default(¶m) { + if is_our_default(param) { // FIXME(const_generics_defaults): This // is incorrect when dealing with unused substs, for example // for `struct Foo` @@ -888,17 +928,15 @@ let predicates = predicates.instantiate_identity(tcx); - if let Some((mut return_ty, span)) = return_ty { + if let Some((return_ty, _)) = return_ty { if return_ty.has_infer_types_or_consts() { fcx.select_obligations_where_possible(false, |_| {}); - return_ty = fcx.resolve_vars_if_possible(return_ty); } - check_opaque_types(fcx, def_id.expect_local(), span, return_ty); } let predicates = fcx.normalize_associated_types_in(span, predicates); - debug!("check_where_clauses: predicates={:?}", predicates.predicates); + debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { @@ -918,15 +956,10 @@ sig: ty::PolyFnSig<'tcx>, hir_decl: &hir::FnDecl<'_>, def_id: DefId, - implied_bounds: &mut Vec>, + implied_bounds: &mut FxHashSet>, ) { let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); - // Unnormalized types in signature are WF too - implied_bounds.extend(sig.inputs()); - // FIXME(#27579) return types should not be implied bounds - implied_bounds.push(sig.output()); - // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` // on the entire `FnSig`, since this would use the same `WellFormedLoc` @@ -977,150 +1010,13 @@ ); // FIXME(#27579) return types should not be implied bounds - implied_bounds.push(sig.output()); + implied_bounds.insert(sig.output()); debug!(?implied_bounds); check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span()))); } -/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions -/// laid for "higher-order pattern unification". -/// This ensures that inference is tractable. -/// In particular, definitions of opaque types can only use other generics as arguments, -/// and they cannot repeat an argument. Example: -/// -/// ```rust -/// type Foo = impl Bar; -/// -/// // Okay -- `Foo` is applied to two distinct, generic types. -/// fn a() -> Foo { .. } -/// -/// // Not okay -- `Foo` is applied to `T` twice. -/// fn b() -> Foo { .. } -/// -/// // Not okay -- `Foo` is applied to a non-generic type. -/// fn b() -> Foo { .. } -/// ``` -/// -fn check_opaque_types<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, - fn_def_id: LocalDefId, - span: Span, - ty: Ty<'tcx>, -) { - trace!("check_opaque_types(fn_def_id={:?}, ty={:?})", fn_def_id, ty); - let tcx = fcx.tcx; - - ty.fold_with(&mut ty::fold::BottomUpFolder { - tcx, - ty_op: |ty| { - if let ty::Opaque(def_id, substs) = *ty.kind() { - trace!("check_opaque_types: opaque_ty, {:?}, {:?}", def_id, substs); - let generics = tcx.generics_of(def_id); - - let opaque_hir_id = if let Some(local_id) = def_id.as_local() { - tcx.hir().local_def_id_to_hir_id(local_id) - } else { - // Opaque types from other crates won't have defining uses in this crate. - return ty; - }; - if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) = - tcx.hir().expect_item(opaque_hir_id).kind - { - // No need to check return position impl trait (RPIT) - // because for type and const parameters they are correct - // by construction: we convert - // - // fn foo() -> impl Trait - // - // into - // - // type Foo - // fn foo() -> Foo. - // - // For lifetime parameters we convert - // - // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> - // - // into - // - // type foo::<'p0..'pn>::Foo<'q0..'qm> - // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. - // - // which would error here on all of the `'static` args. - return ty; - } - if !may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) { - return ty; - } - trace!("check_opaque_types: may define, generics={:#?}", generics); - let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); - for (i, arg) in substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - - GenericArgKind::Lifetime(region) if let ty::ReStatic = region => { - tcx.sess - .struct_span_err( - span, - "non-defining opaque type use in defining scope", - ) - .span_label( - tcx.def_span(generics.param_at(i, tcx).def_id), - "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", - ) - .emit(); - continue; - } - - GenericArgKind::Lifetime(_) => true, - - GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), - }; - - if arg_is_param { - seen_params.entry(arg).or_default().push(i); - } else { - // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = generics.param_at(i, tcx); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); - } - } // for (arg, param) - - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(generics.param_at(i, tcx).def_id)) - .collect(); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, &format!("{} used multiple times", descr)) - .emit(); - } - } - } // if let Opaque - ty - }, - lt_op: |lt| lt, - ct_op: |ct| ct, - }); -} - const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box`, \ `self: Rc`, `self: Arc`, or `self: Pin

: parent, : child, (?): don't-care + /// + /// DETACHED (-1) --------------------> EXITED (?) + /// finish/exd_tsk + /// ^ + /// | + /// |

detach + /// | + /// + /// INIT (0) -----------------------> FINISHED (-1) + /// finish + /// | | + /// |

join/slp_tsk |

join/del_tsk + /// | |

detach/del_tsk + /// v v + /// + /// JOINING JOINED (?) + /// (parent_tid) + /// ^ + /// \ / + /// \ finish/wup_tsk /

slp_tsk-complete/ter_tsk + /// \ / & del_tsk + /// \ / + /// '--> JOIN_FINALIZE ---' + /// (-1) + /// + lifecycle: AtomicUsize, +} + +// Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by +// the task represented by `ThreadInner`. +unsafe impl Sync for ThreadInner {} + +const LIFECYCLE_INIT: usize = 0; +const LIFECYCLE_FINISHED: usize = usize::MAX; +const LIFECYCLE_DETACHED: usize = usize::MAX; +const LIFECYCLE_JOIN_FINALIZE: usize = usize::MAX; +const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX; +const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX; +// there's no single value for `JOINING` + +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * crate::mem::size_of::(); + +impl Thread { + /// # Safety + /// + /// See `thread::Builder::spawn_unchecked` for safety requirements. + pub unsafe fn new(stack: usize, p: Box) -> io::Result { + // Inherit the current task's priority + let current_task = task::try_current_task_id().map_err(|e| e.as_io_error())?; + let priority = task::try_task_priority(current_task).map_err(|e| e.as_io_error())?; + + let inner = Box::new(ThreadInner { + start: UnsafeCell::new(ManuallyDrop::new(p)), + lifecycle: AtomicUsize::new(LIFECYCLE_INIT), + }); + + unsafe extern "C" fn trampoline(exinf: isize) { + // Safety: `ThreadInner` is alive at this point + let inner = unsafe { &*(exinf as *const ThreadInner) }; + + // Safety: Since `trampoline` is called only once for each + // `ThreadInner` and only `trampoline` touches `start`, + // `start` contains contents and is safe to mutably borrow. + let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) }; + p(); + + // Fix the current thread's state just in case, so that the + // destructors won't abort + // Safety: Not really unsafe + let _ = unsafe { abi::unl_cpu() }; + let _ = unsafe { abi::ena_dsp() }; + + // Run TLS destructors now because they are not + // called automatically for terminated tasks. + unsafe { run_dtors() }; + + let old_lifecycle = inner + .lifecycle + .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release); + + match old_lifecycle { + LIFECYCLE_DETACHED => { + // [DETACHED → EXITED] + // No one will ever join, so we'll ask the collector task to + // delete the task. + + // In this case, `inner`'s ownership has been moved to us, + // And we are responsible for dropping it. The acquire + // ordering is not necessary because the parent thread made + // no memory acccess needing synchronization since the call + // to `acre_tsk`. + // Safety: See above. + let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) }; + + // Safety: There are no pinned references to the stack + unsafe { terminate_and_delete_current_task() }; + } + LIFECYCLE_INIT => { + // [INIT → FINISHED] + // The parent hasn't decided whether to join or detach this + // thread yet. Whichever option the parent chooses, + // it'll have to delete this task. + // Since the parent might drop `*inner` as soon as it sees + // `FINISHED`, the release ordering must be used in the + // above `swap` call. + } + parent_tid => { + // Since the parent might drop `*inner` and terminate us as + // soon as it sees `JOIN_FINALIZE`, the release ordering + // must be used in the above `swap` call. + + // [JOINING → JOIN_FINALIZE] + // Wake up the parent task. + expect_success( + unsafe { + let mut er = abi::wup_tsk(parent_tid as _); + if er == abi::E_QOVR { + // `E_QOVR` indicates there's already + // a parking token + er = abi::E_OK; + } + er + }, + &"wup_tsk", + ); + } + } + } + + let inner_ptr = (&*inner) as *const ThreadInner; + + let new_task = ItronError::err_if_negative(unsafe { + abi::acre_tsk(&abi::T_CTSK { + // Activate this task immediately + tskatr: abi::TA_ACT, + exinf: inner_ptr as abi::EXINF, + // The entry point + task: Some(trampoline), + itskpri: priority, + stksz: stack, + // Let the kernel allocate the stack, + stk: crate::ptr::null_mut(), + }) + }) + .map_err(|e| e.as_io_error())?; + + Ok(Self { inner: ManuallyDrop::new(inner), task: new_task }) + } + + pub fn yield_now() { + expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq"); + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(dur: Duration) { + for timeout in dur2reltims(dur) { + expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk"); + } + } + + pub fn join(mut self) { + let inner = &*self.inner; + // Get the current task ID. Panicking here would cause a resource leak, + // so just abort on failure. + let current_task = task::current_task_id_aborting(); + debug_assert!(usize::try_from(current_task).is_ok()); + debug_assert_ne!(current_task as usize, LIFECYCLE_INIT); + debug_assert_ne!(current_task as usize, LIFECYCLE_DETACHED); + + let current_task = current_task as usize; + + match inner.lifecycle.swap(current_task, Ordering::Acquire) { + LIFECYCLE_INIT => { + // [INIT → JOINING] + // The child task will transition the state to `JOIN_FINALIZE` + // and wake us up. + loop { + expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk"); + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of + // `JOIN_FINALIZE`, `Ordering::Acquire` must be used for the + // `load`. + if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE { + break; + } + } + + // [JOIN_FINALIZE → JOINED] + } + LIFECYCLE_FINISHED => { + // [FINISHED → JOINED] + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of `FINISHED`, + // `Ordering::Acquire` must be used for the above `swap` call`. + } + _ => unsafe { hint::unreachable_unchecked() }, + } + + // Terminate and delete the task + // Safety: `self.task` still represents a task we own (because this + // method or `detach_inner` is called only once for each + // `Thread`). The task indicated that it's safe to delete by + // entering the `FINISHED` or `JOIN_FINALIZE` state. + unsafe { terminate_and_delete_task(self.task) }; + + // In either case, we are responsible for dropping `inner`. + // Safety: The contents of `self.inner` will not be accessed hereafter + let _inner = unsafe { ManuallyDrop::take(&mut self.inner) }; + + // Skip the destructor (because it would attempt to detach the thread) + crate::mem::forget(self); + } +} + +impl Drop for Thread { + fn drop(&mut self) { + // Detach the thread. + match self.inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) { + LIFECYCLE_INIT => { + // [INIT → DETACHED] + // When the time comes, the child will figure out that no + // one will ever join it. + // The ownership of `self.inner` is moved to the child thread. + // However, the release ordering is not necessary because we + // made no memory acccess needing synchronization since the call + // to `acre_tsk`. + } + LIFECYCLE_FINISHED => { + // [FINISHED → JOINED] + // The task has already decided that we should delete the task. + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of `FINISHED`, + // the acquire ordering is required for the above `swap` call. + + // Terminate and delete the task + // Safety: `self.task` still represents a task we own (because + // this method or `join_inner` is called only once for + // each `Thread`). The task indicated that it's safe to + // delete by entering the `FINISHED` state. + unsafe { terminate_and_delete_task(self.task) }; + + // Wwe are responsible for dropping `inner`. + // Safety: The contents of `self.inner` will not be accessed + // hereafter + unsafe { ManuallyDrop::drop(&mut self.inner) }; + } + _ => unsafe { hint::unreachable_unchecked() }, + } + } +} + +pub mod guard { + pub type Guard = !; + pub unsafe fn current() -> Option { + None + } + pub unsafe fn init() -> Option { + None + } +} + +/// Terminate and delete the specified task. +/// +/// This function will abort if `deleted_task` refers to the calling task. +/// +/// It is assumed that the specified task is solely managed by the caller - +/// i.e., other threads must not "resuscitate" the specified task or delete it +/// prematurely while this function is still in progress. It is allowed for the +/// specified task to exit by its own. +/// +/// # Safety +/// +/// The task must be safe to terminate. This is in general not true +/// because there might be pinned references to the task's stack. +unsafe fn terminate_and_delete_task(deleted_task: abi::ID) { + // Terminate the task + // Safety: Upheld by the caller + match unsafe { abi::ter_tsk(deleted_task) } { + // Indicates the task is already dormant, ignore it + abi::E_OBJ => {} + er => { + expect_success_aborting(er, &"ter_tsk"); + } + } + + // Delete the task + // Safety: Upheld by the caller + expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk"); +} + +/// Terminate and delete the calling task. +/// +/// Atomicity is not required - i.e., it can be assumed that other threads won't +/// `ter_tsk` the calling task while this function is still in progress. (This +/// property makes it easy to implement this operation on μITRON-derived kernels +/// that don't support `exd_tsk`.) +/// +/// # Safety +/// +/// The task must be safe to terminate. This is in general not true +/// because there might be pinned references to the task's stack. +unsafe fn terminate_and_delete_current_task() -> ! { + expect_success_aborting(unsafe { abi::exd_tsk() }, &"exd_tsk"); + // Safety: `exd_tsk` never returns on success + unsafe { crate::hint::unreachable_unchecked() }; +} + +pub fn available_concurrency() -> io::Result { + super::unsupported() +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/time/tests.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/time/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/time/tests.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/time/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +use super::*; + +fn reltim2dur(t: u64) -> Duration { + Duration::from_micros(t) +} + +#[test] +fn test_dur2reltims() { + assert_eq!(dur2reltims(reltim2dur(0)).collect::>(), vec![]); + assert_eq!(dur2reltims(reltim2dur(42)).collect::>(), vec![42]); + assert_eq!( + dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), + vec![abi::TMAX_RELTIM] + ); + assert_eq!( + dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), + vec![abi::TMAX_RELTIM, 10000] + ); +} + +#[test] +fn test_dur2tmos() { + assert_eq!(dur2tmos(reltim2dur(0)).collect::>(), vec![0]); + assert_eq!(dur2tmos(reltim2dur(42)).collect::>(), vec![42]); + assert_eq!( + dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), + vec![abi::TMAX_RELTIM] + ); + assert_eq!( + dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), + vec![abi::TMAX_RELTIM, 10000] + ); +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/time.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/time.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/time.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/time.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,123 @@ +use super::{abi, error::expect_success}; +use crate::{convert::TryInto, mem::MaybeUninit, time::Duration}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(abi::SYSTIM); + +impl Instant { + pub fn now() -> Instant { + // Safety: The provided pointer is valid + unsafe { + let mut out = MaybeUninit::uninit(); + expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim"); + Instant(out.assume_init()) + } + } + + pub const fn zero() -> Instant { + Instant(0) + } + + pub fn actually_monotonic() -> bool { + // There are ways to change the system time + false + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0).map(|ticks| { + // `SYSTIM` is measured in microseconds + Duration::from_micros(ticks) + }) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + // `SYSTIM` is measured in microseconds + let ticks = other.as_micros(); + + Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + // `SYSTIM` is measured in microseconds + let ticks = other.as_micros(); + + Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?)) + } +} + +/// Split `Duration` into zero or more `RELTIM`s. +#[inline] +pub fn dur2reltims(dur: Duration) -> impl Iterator { + // `RELTIM` is microseconds + let mut ticks = dur.as_micros(); + + crate::iter::from_fn(move || { + if ticks == 0 { + None + } else if ticks <= abi::TMAX_RELTIM as u128 { + Some(crate::mem::replace(&mut ticks, 0) as abi::RELTIM) + } else { + ticks -= abi::TMAX_RELTIM as u128; + Some(abi::TMAX_RELTIM) + } + }) +} + +/// Split `Duration` into one or more `TMO`s. +#[inline] +fn dur2tmos(dur: Duration) -> impl Iterator { + // `TMO` is microseconds + let mut ticks = dur.as_micros(); + let mut end = false; + + crate::iter::from_fn(move || { + if end { + None + } else if ticks <= abi::TMAX_RELTIM as u128 { + end = true; + Some(crate::mem::replace(&mut ticks, 0) as abi::TMO) + } else { + ticks -= abi::TMAX_RELTIM as u128; + Some(abi::TMAX_RELTIM) + } + }) +} + +/// Split `Duration` into one or more API calls with timeout. +#[inline] +pub fn with_tmos(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER { + let mut er = abi::E_TMOUT; + for tmo in dur2tmos(dur) { + er = f(tmo); + if er != abi::E_TMOUT { + break; + } + } + er +} + +/// Split `Duration` into one or more API calls with timeout. This function can +/// handle spurious wakeups. +#[inline] +pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER { + // `TMO` and `SYSTIM` are microseconds. + // Clamp at `SYSTIM::MAX` for performance reasons. This shouldn't cause + // a problem in practice. (`u64::MAX` μs ≈ 584942 years) + let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM; + + let start = Instant::now().0; + let mut elapsed = 0; + let mut er = abi::E_TMOUT; + while elapsed <= ticks { + er = f(elapsed.min(abi::TMAX_RELTIM as abi::SYSTIM) as abi::TMO); + if er != abi::E_TMOUT { + break; + } + elapsed = Instant::now().0.wrapping_sub(start); + } + + er +} + +#[cfg(test)] +mod tests; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,6 +31,9 @@ } else if #[cfg(windows)] { mod windows; pub use self::windows::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use self::solid::*; } else if #[cfg(target_os = "hermit")] { mod hermit; pub use self::hermit::*; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/sgx/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/sgx/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/sgx/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/sgx/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -137,7 +137,7 @@ } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/abi/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/abi/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/abi/fs.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/abi/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,53 @@ +//! `solid_fs.h` +use crate::os::raw::{c_char, c_int, c_uchar}; +pub use libc::{ + blksize_t, dev_t, ino_t, off_t, stat, time_t, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, + O_TRUNC, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, S_IEXEC, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, + S_IFMT, S_IFREG, S_IREAD, S_IWRITE, +}; + +pub const O_ACCMODE: c_int = 0x3; + +pub const SOLID_MAX_PATH: usize = 256; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct dirent { + pub d_ino: ino_t, + pub d_type: c_uchar, + pub d_name: [c_char; 256usize], +} + +pub const DT_UNKNOWN: c_uchar = 0; +pub const DT_FIFO: c_uchar = 1; +pub const DT_CHR: c_uchar = 2; +pub const DT_DIR: c_uchar = 4; +pub const DT_BLK: c_uchar = 6; +pub const DT_REG: c_uchar = 8; +pub const DT_LNK: c_uchar = 10; +pub const DT_SOCK: c_uchar = 12; +pub const DT_WHT: c_uchar = 14; + +pub type S_DIR = c_int; + +extern "C" { + pub fn SOLID_FS_Open(fd: *mut c_int, path: *const c_char, mode: c_int) -> c_int; + pub fn SOLID_FS_Close(fd: c_int) -> c_int; + pub fn SOLID_FS_Read(fd: c_int, buf: *mut u8, size: usize, result: *mut usize) -> c_int; + pub fn SOLID_FS_Write(fd: c_int, buf: *const u8, size: usize, result: *mut usize) -> c_int; + pub fn SOLID_FS_Lseek(fd: c_int, offset: off_t, whence: c_int) -> c_int; + pub fn SOLID_FS_Sync(fd: c_int) -> c_int; + pub fn SOLID_FS_Ftell(fd: c_int, result: *mut off_t) -> c_int; + pub fn SOLID_FS_Feof(fd: c_int, result: *mut c_int) -> c_int; + pub fn SOLID_FS_Fsize(fd: c_int, result: *mut usize) -> c_int; + pub fn SOLID_FS_Truncate(path: *const c_char, size: off_t) -> c_int; + pub fn SOLID_FS_OpenDir(path: *const c_char, pDir: *mut S_DIR) -> c_int; + pub fn SOLID_FS_CloseDir(dir: S_DIR) -> c_int; + pub fn SOLID_FS_ReadDir(dir: S_DIR, dirp: *mut dirent) -> c_int; + pub fn SOLID_FS_Stat(path: *const c_char, buf: *mut stat) -> c_int; + pub fn SOLID_FS_Unlink(path: *const c_char) -> c_int; + pub fn SOLID_FS_Rename(oldpath: *const c_char, newpath: *const c_char) -> c_int; + pub fn SOLID_FS_Chmod(path: *const c_char, mode: c_int) -> c_int; + pub fn SOLID_FS_Utime(path: *const c_char, time: time_t) -> c_int; + pub fn SOLID_FS_Mkdir(path: *const c_char) -> c_int; +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/abi/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/abi/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/abi/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/abi/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,92 @@ +use crate::os::raw::c_int; + +mod fs; +pub mod sockets; +pub use self::fs::*; + +pub const SOLID_BP_PROGRAM_EXITED: usize = 15; +pub const SOLID_BP_CSABORT: usize = 16; + +#[inline(always)] +pub fn breakpoint_program_exited(tid: usize) { + unsafe { + match () { + #[cfg(target_arch = "arm")] + () => asm!("bkpt #{}", const SOLID_BP_PROGRAM_EXITED, in("r0") tid), + #[cfg(target_arch = "aarch64")] + () => asm!("hlt #{}", const SOLID_BP_PROGRAM_EXITED, in("x0") tid), + } + } +} + +#[inline(always)] +pub fn breakpoint_abort() { + unsafe { + match () { + #[cfg(target_arch = "arm")] + () => asm!("bkpt #{}", const SOLID_BP_CSABORT), + #[cfg(target_arch = "aarch64")] + () => asm!("hlt #{}", const SOLID_BP_CSABORT), + } + } +} + +// `solid_types.h` +pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID}; + +pub const SOLID_ERR_NOTFOUND: ER = -1000; +pub const SOLID_ERR_NOTSUPPORTED: ER = -1001; +pub const SOLID_ERR_EBADF: ER = -1002; +pub const SOLID_ERR_INVALIDCONTENT: ER = -1003; +pub const SOLID_ERR_NOTUSED: ER = -1004; +pub const SOLID_ERR_ALREADYUSED: ER = -1005; +pub const SOLID_ERR_OUTOFBOUND: ER = -1006; +pub const SOLID_ERR_BADSEQUENCE: ER = -1007; +pub const SOLID_ERR_UNKNOWNDEVICE: ER = -1008; +pub const SOLID_ERR_BUSY: ER = -1009; +pub const SOLID_ERR_TIMEOUT: ER = -1010; +pub const SOLID_ERR_INVALIDACCESS: ER = -1011; +pub const SOLID_ERR_NOTREADY: ER = -1012; + +// `solid_rtc.h` +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SOLID_RTC_TIME { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, +} + +extern "C" { + pub fn SOLID_RTC_ReadTime(time: *mut SOLID_RTC_TIME) -> c_int; +} + +// `solid_log.h` +extern "C" { + pub fn SOLID_LOG_write(s: *const u8, l: usize); +} + +// `solid_mem.h` +extern "C" { + pub fn SOLID_TLS_AddDestructor(id: i32, dtor: unsafe extern "C" fn(*mut u8)); +} + +// `solid_rng.h` +extern "C" { + pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> c_int; +} + +// `rwlock.h` +extern "C" { + pub fn rwl_loc_rdl(id: ID) -> ER; + pub fn rwl_loc_wrl(id: ID) -> ER; + pub fn rwl_ploc_rdl(id: ID) -> ER; + pub fn rwl_ploc_wrl(id: ID) -> ER; + pub fn rwl_unl_rwl(id: ID) -> ER; + pub fn rwl_acre_rwl() -> ER_ID; + pub fn rwl_del_rwl(id: ID) -> ER; +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/abi/sockets.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/abi/sockets.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/abi/sockets.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/abi/sockets.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,274 @@ +use crate::os::raw::{c_char, c_uint, c_void}; +pub use libc::{c_int, c_long, size_t, ssize_t, suseconds_t, time_t, timeval}; + +pub const SOLID_NET_ERR_BASE: c_int = -2000; +pub const EINPROGRESS: c_int = SOLID_NET_ERR_BASE - libc::EINPROGRESS; + +pub const AF_INET6: i32 = 10; +pub const AF_INET: i32 = 2; +pub const IPPROTO_IP: i32 = 0; +pub const IPPROTO_IPV6: i32 = 41; +pub const IPPROTO_TCP: i32 = 6; +pub const IPV6_ADD_MEMBERSHIP: i32 = 12; +pub const IPV6_DROP_MEMBERSHIP: i32 = 13; +pub const IPV6_MULTICAST_LOOP: i32 = 19; +pub const IPV6_V6ONLY: i32 = 27; +pub const IP_TTL: i32 = 2; +pub const IP_MULTICAST_TTL: i32 = 5; +pub const IP_MULTICAST_LOOP: i32 = 7; +pub const IP_ADD_MEMBERSHIP: i32 = 3; +pub const IP_DROP_MEMBERSHIP: i32 = 4; +pub const SHUT_RD: i32 = 0; +pub const SHUT_RDWR: i32 = 2; +pub const SHUT_WR: i32 = 1; +pub const SOCK_DGRAM: i32 = 2; +pub const SOCK_STREAM: i32 = 1; +pub const SOL_SOCKET: i32 = 4095; +pub const SO_BROADCAST: i32 = 32; +pub const SO_ERROR: i32 = 4103; +pub const SO_RCVTIMEO: i32 = 4102; +pub const SO_REUSEADDR: i32 = 4; +pub const SO_SNDTIMEO: i32 = 4101; +pub const SO_LINGER: i32 = 128; +pub const TCP_NODELAY: i32 = 1; +pub const MSG_PEEK: c_int = 1; +pub const FIONBIO: c_long = 0x8008667eu32 as c_long; +pub const EAI_NONAME: i32 = -2200; +pub const EAI_SERVICE: i32 = -2201; +pub const EAI_FAIL: i32 = -2202; +pub const EAI_MEMORY: i32 = -2203; +pub const EAI_FAMILY: i32 = -2204; + +pub type sa_family_t = u8; +pub type socklen_t = u32; +pub type in_addr_t = u32; +pub type in_port_t = u16; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct in_addr { + pub s_addr: in_addr_t, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct in6_addr { + pub s6_addr: [u8; 16], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: socklen_t, + pub msg_iov: *mut iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: socklen_t, + pub msg_flags: c_int, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14usize], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [c_char; 8usize], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: in6_addr, + pub sin6_scope_id: u32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr_storage { + pub s2_len: u8, + pub ss_family: sa_family_t, + pub s2_data1: [c_char; 2usize], + pub s2_data2: [u32; 3usize], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + pub ai_addr: *mut sockaddr, + pub ai_canonname: *mut c_char, + pub ai_next: *mut addrinfo, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: usize, +} + +/// This value can be chosen by an application +pub const SOLID_NET_FD_SETSIZE: usize = 1; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct fd_set { + pub num_fds: usize, + pub fds: [c_int; SOLID_NET_FD_SETSIZE], +} + +extern "C" { + #[link_name = "SOLID_NET_StrError"] + pub fn strerror(errnum: c_int) -> *const c_char; + + pub fn SOLID_NET_GetLastError() -> c_int; + + #[link_name = "SOLID_NET_Accept"] + pub fn accept(s: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Bind"] + pub fn bind(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Connect"] + pub fn connect(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Close"] + pub fn close(s: c_int) -> c_int; + + #[link_name = "SOLID_NET_GetPeerName"] + pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_GetSockName"] + pub fn getsockname(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_GetSockOpt"] + pub fn getsockopt( + s: c_int, + level: c_int, + optname: c_int, + optval: *mut c_void, + optlen: *mut socklen_t, + ) -> c_int; + + #[link_name = "SOLID_NET_SetSockOpt"] + pub fn setsockopt( + s: c_int, + level: c_int, + optname: c_int, + optval: *const c_void, + optlen: socklen_t, + ) -> c_int; + + #[link_name = "SOLID_NET_Ioctl"] + pub fn ioctl(s: c_int, cmd: c_long, argp: *mut c_void) -> c_int; + + #[link_name = "SOLID_NET_Listen"] + pub fn listen(s: c_int, backlog: c_int) -> c_int; + + #[link_name = "SOLID_NET_Recv"] + pub fn recv(s: c_int, mem: *mut c_void, len: size_t, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_Read"] + pub fn read(s: c_int, mem: *mut c_void, len: size_t) -> ssize_t; + + #[link_name = "SOLID_NET_Readv"] + pub fn readv(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_RecvFrom"] + pub fn recvfrom( + s: c_int, + mem: *mut c_void, + len: size_t, + flags: c_int, + from: *mut sockaddr, + fromlen: *mut socklen_t, + ) -> ssize_t; + + #[link_name = "SOLID_NET_Send"] + pub fn send(s: c_int, mem: *const c_void, len: size_t, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_SendMsg"] + pub fn sendmsg(s: c_int, message: *const msghdr, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_SendTo"] + pub fn sendto( + s: c_int, + mem: *const c_void, + len: size_t, + flags: c_int, + to: *const sockaddr, + tolen: socklen_t, + ) -> ssize_t; + + #[link_name = "SOLID_NET_Shutdown"] + pub fn shutdown(s: c_int, how: c_int) -> c_int; + + #[link_name = "SOLID_NET_Socket"] + pub fn socket(domain: c_int, type_: c_int, protocol: c_int) -> c_int; + + #[link_name = "SOLID_NET_Write"] + pub fn write(s: c_int, mem: *const c_void, len: size_t) -> ssize_t; + + #[link_name = "SOLID_NET_Writev"] + pub fn writev(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_FreeAddrInfo"] + pub fn freeaddrinfo(ai: *mut addrinfo); + + #[link_name = "SOLID_NET_GetAddrInfo"] + pub fn getaddrinfo( + nodename: *const c_char, + servname: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo, + ) -> c_int; + + #[link_name = "SOLID_NET_Select"] + pub fn select( + maxfdp1: c_int, + readset: *mut fd_set, + writeset: *mut fd_set, + exceptset: *mut fd_set, + timeout: *mut timeval, + ) -> c_int; +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/alloc.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/alloc.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/alloc.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/alloc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,32 @@ +use crate::{ + alloc::{GlobalAlloc, Layout, System}, + sys::common::alloc::{realloc_fallback, MIN_ALIGN}, +}; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + unsafe { libc::malloc(layout.size()) as *mut u8 } + } else { + unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 } + } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + unsafe { libc::free(ptr as *mut libc::c_void) } + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + unsafe { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + } else { + realloc_fallback(self, ptr, layout, new_size) + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/env.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/env.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/env.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/env.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +pub mod os { + pub const FAMILY: &str = "itron"; + pub const OS: &str = "solid"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/error.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/error.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/error.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,55 @@ +use super::{abi, itron, net}; +use crate::io::ErrorKind; + +pub use self::itron::error::{expect_success, ItronError as SolidError}; + +/// Describe the specified SOLID error code. Returns `None` if it's an +/// undefined error code. +/// +/// The SOLID error codes are a superset of μITRON error codes. +pub fn error_name(er: abi::ER) -> Option<&'static str> { + match er { + // Success + er if er >= 0 => None, + er if er < abi::sockets::SOLID_NET_ERR_BASE => net::error_name(er), + + abi::SOLID_ERR_NOTFOUND => Some("not found"), + abi::SOLID_ERR_NOTSUPPORTED => Some("not supported"), + abi::SOLID_ERR_EBADF => Some("bad flags"), + abi::SOLID_ERR_INVALIDCONTENT => Some("invalid content"), + abi::SOLID_ERR_NOTUSED => Some("not used"), + abi::SOLID_ERR_ALREADYUSED => Some("already used"), + abi::SOLID_ERR_OUTOFBOUND => Some("out of bounds"), + abi::SOLID_ERR_BADSEQUENCE => Some("bad sequence"), + abi::SOLID_ERR_UNKNOWNDEVICE => Some("unknown device"), + abi::SOLID_ERR_BUSY => Some("busy"), + abi::SOLID_ERR_TIMEOUT => Some("operation timed out"), + abi::SOLID_ERR_INVALIDACCESS => Some("invalid access"), + abi::SOLID_ERR_NOTREADY => Some("not ready"), + + _ => itron::error::error_name(er), + } +} + +pub fn decode_error_kind(er: abi::ER) -> ErrorKind { + match er { + // Success + er if er >= 0 => ErrorKind::Uncategorized, + er if er < abi::sockets::SOLID_NET_ERR_BASE => net::decode_error_kind(er), + + abi::SOLID_ERR_NOTFOUND => ErrorKind::NotFound, + abi::SOLID_ERR_NOTSUPPORTED => ErrorKind::Unsupported, + abi::SOLID_ERR_EBADF => ErrorKind::InvalidInput, + abi::SOLID_ERR_INVALIDCONTENT => ErrorKind::InvalidData, + // abi::SOLID_ERR_NOTUSED + // abi::SOLID_ERR_ALREADYUSED + abi::SOLID_ERR_OUTOFBOUND => ErrorKind::InvalidInput, + // abi::SOLID_ERR_BADSEQUENCE + abi::SOLID_ERR_UNKNOWNDEVICE => ErrorKind::NotFound, + // abi::SOLID_ERR_BUSY + abi::SOLID_ERR_TIMEOUT => ErrorKind::TimedOut, + // abi::SOLID_ERR_INVALIDACCESS + // abi::SOLID_ERR_NOTREADY + _ => itron::error::decode_error_kind(er), + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/fs.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,529 @@ +use super::{abi, error}; +use crate::{ + ffi::{CStr, CString, OsStr, OsString}, + fmt, + io::{self, IoSlice, IoSliceMut, SeekFrom}, + mem::MaybeUninit, + os::raw::{c_int, c_short}, + os::solid::ffi::OsStrExt, + path::{Path, PathBuf}, + sync::Arc, + sys::time::SystemTime, + sys::unsupported, +}; + +pub use crate::sys_common::fs::try_exists; + +/// A file descriptor. +#[derive(Clone, Copy)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +struct FileDesc { + fd: c_int, +} + +impl FileDesc { + #[inline] + fn new(fd: c_int) -> FileDesc { + assert_ne!(fd, -1i32); + // Safety: we just asserted that the value is in the valid range and + // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { FileDesc { fd } } + } + + #[inline] + fn raw(&self) -> c_int { + self.fd + } +} + +pub struct File { + fd: FileDesc, +} + +#[derive(Clone)] +pub struct FileAttr { + stat: abi::stat, +} + +// all DirEntry's will have a reference to this struct +struct InnerReadDir { + dirp: abi::S_DIR, + root: PathBuf, +} + +pub struct ReadDir { + inner: Arc, +} + +pub struct DirEntry { + entry: abi::dirent, + inner: Arc, +} + +#[derive(Clone, Debug)] +pub struct OpenOptions { + // generic + read: bool, + write: bool, + append: bool, + truncate: bool, + create: bool, + create_new: bool, + // system-specific + custom_flags: i32, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions(c_short); + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct FileType(c_short); + +#[derive(Debug)] +pub struct DirBuilder {} + +impl FileAttr { + pub fn size(&self) -> u64 { + self.stat.st_size as u64 + } + + pub fn perm(&self) -> FilePermissions { + FilePermissions(self.stat.st_mode) + } + + pub fn file_type(&self) -> FileType { + FileType(self.stat.st_mode) + } + + pub fn modified(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_mtime)) + } + + pub fn accessed(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_atime)) + } + + pub fn created(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_ctime)) + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + (self.0 & abi::S_IWRITE) == 0 + } + + pub fn set_readonly(&mut self, readonly: bool) { + if readonly { + self.0 &= !abi::S_IWRITE; + } else { + self.0 |= abi::S_IWRITE; + } + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.is(abi::S_IFDIR) + } + pub fn is_file(&self) -> bool { + self.is(abi::S_IFREG) + } + pub fn is_symlink(&self) -> bool { + false + } + + pub fn is(&self, mode: c_short) -> bool { + self.0 & abi::S_IFMT == mode + } +} + +pub fn readdir(p: &Path) -> io::Result { + unsafe { + let mut dir = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_OpenDir( + cstr(p)?.as_ptr(), + dir.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + let inner = Arc::new(InnerReadDir { dirp: dir.assume_init(), root: p.to_owned() }); + Ok(ReadDir { inner }) + } +} + +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. + // Thus the result will be e g 'ReadDir("/home")' + fmt::Debug::fmt(&*self.inner.root, f) + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + unsafe { + let mut out_dirent = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir( + self.inner.dirp, + out_dirent.as_mut_ptr(), + )) + .ok()?; + Some(Ok(DirEntry { entry: out_dirent.assume_init(), inner: Arc::clone(&self.inner) })) + } + } +} + +impl Drop for InnerReadDir { + fn drop(&mut self) { + unsafe { abi::SOLID_FS_CloseDir(self.dirp) }; + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + self.inner.root.join(OsStr::from_bytes( + unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes(), + )) + } + + pub fn file_name(&self) -> OsString { + OsStr::from_bytes(unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes()) + .to_os_string() + } + + pub fn metadata(&self) -> io::Result { + lstat(&self.path()) + } + + pub fn file_type(&self) -> io::Result { + match self.entry.d_type { + abi::DT_CHR => Ok(FileType(abi::S_IFCHR)), + abi::DT_FIFO => Ok(FileType(abi::S_IFIFO)), + abi::DT_REG => Ok(FileType(abi::S_IFREG)), + abi::DT_DIR => Ok(FileType(abi::S_IFDIR)), + abi::DT_BLK => Ok(FileType(abi::S_IFBLK)), + _ => lstat(&self.path()).map(|m| m.file_type()), + } + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { + // generic + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + // system-specific + custom_flags: 0, + } + } + + pub fn read(&mut self, read: bool) { + self.read = read; + } + pub fn write(&mut self, write: bool) { + self.write = write; + } + pub fn append(&mut self, append: bool) { + self.append = append; + } + pub fn truncate(&mut self, truncate: bool) { + self.truncate = truncate; + } + pub fn create(&mut self, create: bool) { + self.create = create; + } + pub fn create_new(&mut self, create_new: bool) { + self.create_new = create_new; + } + + pub fn custom_flags(&mut self, flags: i32) { + self.custom_flags = flags; + } + pub fn mode(&mut self, _mode: u32) {} + + fn get_access_mode(&self) -> io::Result { + match (self.read, self.write, self.append) { + (true, false, false) => Ok(abi::O_RDONLY), + (false, true, false) => Ok(abi::O_WRONLY), + (true, true, false) => Ok(abi::O_RDWR), + (false, _, true) => Ok(abi::O_WRONLY | abi::O_APPEND), + (true, _, true) => Ok(abi::O_RDWR | abi::O_APPEND), + (false, false, false) => Err(io::Error::from_raw_os_error(libc::EINVAL)), + } + } + + fn get_creation_mode(&self) -> io::Result { + match (self.write, self.append) { + (true, false) => {} + (false, false) => { + if self.truncate || self.create || self.create_new { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } + } + (_, true) => { + if self.truncate && !self.create_new { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } + } + } + + Ok(match (self.create, self.truncate, self.create_new) { + (false, false, false) => 0, + (true, false, false) => abi::O_CREAT, + (false, true, false) => abi::O_TRUNC, + (true, true, false) => abi::O_CREAT | abi::O_TRUNC, + (_, _, true) => abi::O_CREAT | abi::O_EXCL, + }) + } +} + +fn cstr(path: &Path) -> io::Result { + Ok(CString::new(path.as_os_str().as_bytes())?) +} + +impl File { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + let flags = opts.get_access_mode()? + | opts.get_creation_mode()? + | (opts.custom_flags as c_int & !abi::O_ACCMODE); + unsafe { + let mut fd = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Open( + fd.as_mut_ptr(), + cstr(path)?.as_ptr(), + flags, + )) + .map_err(|e| e.as_io_error())?; + Ok(File { fd: FileDesc::new(fd.assume_init()) }) + } + } + + pub fn file_attr(&self) -> io::Result { + unsupported() + } + + pub fn fsync(&self) -> io::Result<()> { + self.flush() + } + + pub fn datasync(&self) -> io::Result<()> { + self.flush() + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + unsupported() + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + unsafe { + let mut out_num_bytes = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Read( + self.fd.raw(), + buf.as_mut_ptr(), + buf.len(), + out_num_bytes.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_num_bytes.assume_init()) + } + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + unsafe { + let mut out_num_bytes = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Write( + self.fd.raw(), + buf.as_ptr(), + buf.len(), + out_num_bytes.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_num_bytes.assume_init()) + } + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn flush(&self) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Sync(self.fd.raw()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + let (whence, pos) = match pos { + // Casting to `i64` is fine, too large values will end up as + // negative which will cause an error in `SOLID_FS_Lseek`. + SeekFrom::Start(off) => (abi::SEEK_SET, off as i64), + SeekFrom::End(off) => (abi::SEEK_END, off), + SeekFrom::Current(off) => (abi::SEEK_CUR, off), + }; + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Lseek(self.fd.raw(), pos, whence) + }) + .map_err(|e| e.as_io_error())?; + + // Get the new offset + unsafe { + let mut out_offset = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Ftell( + self.fd.raw(), + out_offset.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_offset.assume_init() as u64) + } + } + + pub fn duplicate(&self) -> io::Result { + unsupported() + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + unsupported() + } +} + +impl Drop for File { + fn drop(&mut self) { + unsafe { abi::SOLID_FS_Close(self.fd.raw()) }; + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Mkdir(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } +} + +impl fmt::Debug for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("File").field("fd", &self.fd.raw()).finish() + } +} + +pub fn unlink(p: &Path) -> io::Result<()> { + if stat(p)?.file_type().is_dir() { + Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory")) + } else { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } +} + +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Rename(cstr(old)?.as_ptr(), cstr(new)?.as_ptr()) + }) + .map_err(|e| e.as_io_error())?; + Ok(()) +} + +pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Chmod(cstr(p)?.as_ptr(), perm.0.into()) + }) + .map_err(|e| e.as_io_error())?; + Ok(()) +} + +pub fn rmdir(p: &Path) -> io::Result<()> { + if stat(p)?.file_type().is_dir() { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } else { + Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory")) + } +} + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + for child in readdir(path)? { + let child = child?; + let child_type = child.file_type()?; + if child_type.is_dir() { + remove_dir_all(&child.path())?; + } else { + unlink(&child.path())?; + } + } + rmdir(path) +} + +pub fn readlink(p: &Path) -> io::Result { + // This target doesn't support symlinks + stat(p)?; + Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link")) +} + +pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { + // This target doesn't support symlinks + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + // This target doesn't support symlinks + unsupported() +} + +pub fn stat(p: &Path) -> io::Result { + // This target doesn't support symlinks + lstat(p) +} + +pub fn lstat(p: &Path) -> io::Result { + unsafe { + let mut out_stat = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Stat( + cstr(p)?.as_ptr(), + out_stat.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(FileAttr { stat: out_stat.assume_init() }) + } +} + +pub fn canonicalize(_p: &Path) -> io::Result { + unsupported() +} + +pub fn copy(from: &Path, to: &Path) -> io::Result { + use crate::fs::File; + + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + + io::copy(&mut reader, &mut writer) +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/io.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/io.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/io.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/io.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,77 @@ +use crate::marker::PhantomData; +use crate::slice; + +use super::abi::sockets::iovec; +use libc::c_void; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSlice beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +#[repr(transparent)] +pub struct IoSliceMut<'a> { + vec: iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSliceMut beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/memchr.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/memchr.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/memchr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/memchr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +pub fn memchr(needle: u8, haystack: &[u8]) -> Option { + let p = unsafe { + libc::memchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len(), + ) + }; + if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } +} + +pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { + let p = unsafe { + libc::memrchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len(), + ) + }; + if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,96 @@ +#![allow(dead_code)] +#![allow(missing_docs, nonstandard_style)] +#![deny(unsafe_op_in_unsafe_fn)] + +mod abi; + +#[path = "../itron"] +mod itron { + pub(super) mod abi; + pub mod condvar; + pub(super) mod error; + pub mod mutex; + pub(super) mod spin; + pub(super) mod task; + pub mod thread; + pub(super) mod time; + use super::unsupported; +} + +pub mod alloc; +#[path = "../unsupported/args.rs"] +pub mod args; +#[path = "../unix/cmath.rs"] +pub mod cmath; +pub mod env; +// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as +// `crate::sys::error` +pub(crate) mod error; +pub mod fs; +pub mod io; +pub mod net; +pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; +pub mod path; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +#[path = "../unsupported/process.rs"] +pub mod process; +pub mod rwlock; +pub mod stdio; +pub use self::itron::{condvar, mutex, thread}; +pub mod memchr; +pub mod thread_local_dtor; +pub mod thread_local_key; +pub mod time; + +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. +pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} + +// SAFETY: must be called only once during runtime cleanup. +pub unsafe fn cleanup() {} + +pub fn unsupported() -> crate::io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> crate::io::Error { + crate::io::Error::new_const( + crate::io::ErrorKind::Unsupported, + &"operation not supported on this platform", + ) +} + +pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { + error::decode_error_kind(code) +} + +#[inline(always)] +pub fn abort_internal() -> ! { + loop { + abi::breakpoint_abort(); + } +} + +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub extern "C" fn __rust_abort() { + abort_internal(); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + unsafe { + let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit(); + let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16); + assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result); + let [x1, x2] = out.assume_init(); + (x1, x2) + } +} + +pub use libc::strlen; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/net.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/net.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/net.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/net.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,469 @@ +use super::abi; +use crate::{ + cmp, + ffi::CStr, + io::{self, ErrorKind, IoSlice, IoSliceMut}, + mem, + net::{Shutdown, SocketAddr}, + ptr, str, + sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}, + sys_common::{AsInner, FromInner, IntoInner}, + time::Duration, +}; + +use self::netc::{sockaddr, socklen_t, MSG_PEEK}; +use libc::{c_int, c_void, size_t}; + +pub mod netc { + pub use super::super::abi::sockets::*; +} + +pub type wrlen_t = size_t; + +const READ_LIMIT: usize = libc::ssize_t::MAX as usize; + +const fn max_iov() -> usize { + // Judging by the source code, it's unlimited, but specify a lower + // value just in case. + 1024 +} + +/// A file descriptor. +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +struct FileDesc { + fd: c_int, +} + +impl FileDesc { + #[inline] + fn new(fd: c_int) -> FileDesc { + assert_ne!(fd, -1i32); + // Safety: we just asserted that the value is in the valid range and + // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { FileDesc { fd } } + } + + #[inline] + fn raw(&self) -> c_int { + self.fd + } + + /// Extracts the actual file descriptor without closing it. + #[inline] + fn into_raw(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + fn read(&self, buf: &mut [u8]) -> io::Result { + let ret = cvt(unsafe { + netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) + })?; + Ok(ret as usize) + } + + fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let ret = cvt(unsafe { + netc::readv( + self.fd, + bufs.as_ptr() as *const netc::iovec, + cmp::min(bufs.len(), max_iov()) as c_int, + ) + })?; + Ok(ret as usize) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + true + } + + fn write(&self, buf: &[u8]) -> io::Result { + let ret = cvt(unsafe { + netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) + })?; + Ok(ret as usize) + } + + fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let ret = cvt(unsafe { + netc::writev( + self.fd, + bufs.as_ptr() as *const netc::iovec, + cmp::min(bufs.len(), max_iov()) as c_int, + ) + })?; + Ok(ret as usize) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + fn duplicate(&self) -> io::Result { + super::unsupported() + } +} + +impl AsInner for FileDesc { + fn as_inner(&self) -> &c_int { + &self.fd + } +} + +impl Drop for FileDesc { + fn drop(&mut self) { + unsafe { netc::close(self.fd) }; + } +} + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt(t: T) -> io::Result { + if t.is_minus_one() { Err(last_error()) } else { Ok(t) } +} + +/// A variant of `cvt` for `getaddrinfo` which return 0 for a success. +pub fn cvt_gai(err: c_int) -> io::Result<()> { + if err == 0 { + Ok(()) + } else { + let msg: &dyn crate::fmt::Display = match err { + netc::EAI_NONAME => &"name or service not known", + netc::EAI_SERVICE => &"service not supported", + netc::EAI_FAIL => &"non-recoverable failure in name resolution", + netc::EAI_MEMORY => &"memory allocation failure", + netc::EAI_FAMILY => &"family not supported", + _ => &err, + }; + Err(io::Error::new( + io::ErrorKind::Uncategorized, + &format!("failed to lookup address information: {}", msg)[..], + )) + } +} + +/// Just to provide the same interface as sys/unix/net.rs +pub fn cvt_r(mut f: F) -> io::Result +where + T: IsMinusOne, + F: FnMut() -> T, +{ + cvt(f()) +} + +/// Returns the last error from the network subsystem. +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() }) +} + +pub(super) fn error_name(er: abi::ER) -> Option<&'static str> { + unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok() +} + +pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind { + let errno = netc::SOLID_NET_ERR_BASE - er; + match errno as libc::c_int { + libc::ECONNREFUSED => ErrorKind::ConnectionRefused, + libc::ECONNRESET => ErrorKind::ConnectionReset, + libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, + libc::EPIPE => ErrorKind::BrokenPipe, + libc::ENOTCONN => ErrorKind::NotConnected, + libc::ECONNABORTED => ErrorKind::ConnectionAborted, + libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, + libc::EADDRINUSE => ErrorKind::AddrInUse, + libc::ENOENT => ErrorKind::NotFound, + libc::EINTR => ErrorKind::Interrupted, + libc::EINVAL => ErrorKind::InvalidInput, + libc::ETIMEDOUT => ErrorKind::TimedOut, + libc::EEXIST => ErrorKind::AlreadyExists, + libc::ENOSYS => ErrorKind::Unsupported, + libc::ENOMEM => ErrorKind::OutOfMemory, + libc::EAGAIN => ErrorKind::WouldBlock, + + _ => ErrorKind::Uncategorized, + } +} + +pub fn init() {} + +pub struct Socket(FileDesc); + +impl Socket { + pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { + let fam = match *addr { + SocketAddr::V4(..) => netc::AF_INET, + SocketAddr::V6(..) => netc::AF_INET6, + }; + Socket::new_raw(fam, ty) + } + + pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { + unsafe { + let fd = cvt(netc::socket(fam, ty, 0))?; + let fd = FileDesc::new(fd); + let socket = Socket(fd); + + Ok(socket) + } + } + + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { + self.set_nonblocking(true)?; + let r = unsafe { + let (addrp, len) = addr.into_inner(); + cvt(netc::connect(self.0.raw(), addrp, len)) + }; + self.set_nonblocking(false)?; + + match r { + Ok(_) => return Ok(()), + // there's no ErrorKind for EINPROGRESS + Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {} + Err(e) => return Err(e), + } + + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"cannot set a 0 duration timeout", + )); + } + + let mut timeout = + netc::timeval { tv_sec: timeout.as_secs() as _, tv_usec: timeout.subsec_micros() as _ }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + + let fds = netc::fd_set { num_fds: 1, fds: [self.0.raw()] }; + + let mut writefds = fds; + let mut errorfds = fds; + + let n = unsafe { + cvt(netc::select( + self.0.raw() + 1, + ptr::null_mut(), + &mut writefds, + &mut errorfds, + &mut timeout, + ))? + }; + + match n { + 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")), + _ => { + let can_write = writefds.num_fds != 0; + if !can_write { + if let Some(e) = self.take_error()? { + return Err(e); + } + } + Ok(()) + } + } + } + + pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result { + let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?; + let fd = FileDesc::new(fd); + Ok(Socket(fd)) + } + + pub fn duplicate(&self) -> io::Result { + self.0.duplicate().map(Socket) + } + + fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + let ret = cvt(unsafe { + netc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + })?; + Ok(ret as usize) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, 0) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, MSG_PEEK) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + fn recv_from_with_flags( + &self, + buf: &mut [u8], + flags: c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; + + let n = cvt(unsafe { + netc::recvfrom( + self.0.raw(), + buf.as_mut_ptr() as *mut c_void, + buf.len(), + flags, + &mut storage as *mut _ as *mut _, + &mut addrlen, + ) + })?; + Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, 0) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, MSG_PEEK) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> { + let timeout = match dur { + Some(dur) => { + if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"cannot set a 0 duration timeout", + )); + } + + let secs = if dur.as_secs() > netc::c_long::MAX as u64 { + netc::c_long::MAX + } else { + dur.as_secs() as netc::c_long + }; + let mut timeout = netc::timeval { tv_sec: secs, tv_usec: dur.subsec_micros() as _ }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => netc::timeval { tv_sec: 0, tv_usec: 0 }, + }; + setsockopt(self, netc::SOL_SOCKET, kind, timeout) + } + + pub fn timeout(&self, kind: c_int) -> io::Result> { + let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + if raw.tv_sec == 0 && raw.tv_usec == 0 { + Ok(None) + } else { + let sec = raw.tv_sec as u64; + let nsec = (raw.tv_usec as u32) * 1000; + Ok(Some(Duration::new(sec, nsec))) + } + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + let how = match how { + Shutdown::Write => netc::SHUT_WR, + Shutdown::Read => netc::SHUT_RD, + Shutdown::Both => netc::SHUT_RDWR, + }; + cvt(unsafe { netc::shutdown(self.0.raw(), how) })?; + Ok(()) + } + + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + let linger = netc::linger { + l_onoff: linger.is_some() as netc::c_int, + l_linger: linger.unwrap_or_default().as_secs() as netc::c_int, + }; + + setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) + } + + pub fn linger(&self) -> io::Result> { + let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?; + + Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) + } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) + } + + pub fn nodelay(&self) -> io::Result { + let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + Ok(raw != 0) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_int; + cvt(unsafe { + netc::ioctl(*self.as_inner(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _) + }) + .map(drop) + } + + pub fn take_error(&self) -> io::Result> { + let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } + } + + // This method is used by sys_common code to abstract over targets. + pub fn as_raw(&self) -> c_int { + *self.as_inner() + } +} + +impl AsInner for Socket { + fn as_inner(&self) -> &c_int { + self.0.as_inner() + } +} + +impl FromInner for Socket { + fn from_inner(fd: c_int) -> Socket { + Socket(FileDesc::new(fd)) + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> c_int { + self.0.into_raw() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/os.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/os.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/os.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/os.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,200 @@ +use super::unsupported; +use crate::error::Error as StdError; +use crate::ffi::{CStr, CString, OsStr, OsString}; +use crate::fmt; +use crate::io; +use crate::os::{ + raw::{c_char, c_int}, + solid::ffi::{OsStrExt, OsStringExt}, +}; +use crate::path::{self, PathBuf}; +use crate::sys_common::rwlock::StaticRWLock; +use crate::vec; + +use super::{abi, error, itron, memchr}; + +// `solid` directly maps `errno`s to μITRON error codes. +impl itron::error::ItronError { + #[inline] + pub(crate) fn as_io_error(self) -> crate::io::Error { + crate::io::Error::from_raw_os_error(self.as_raw()) + } +} + +pub fn errno() -> i32 { + 0 +} + +pub fn error_string(errno: i32) -> String { + if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) } +} + +pub fn getcwd() -> io::Result { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + unsupported() +} + +pub struct SplitPaths<'a>(&'a !); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { + *self.0 + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result +where + I: Iterator, + T: AsRef, +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "not supported on this platform yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + #[allow(deprecated)] + fn description(&self) -> &str { + "not supported on this platform yet" + } +} + +pub fn current_exe() -> io::Result { + unsupported() +} + +static ENV_LOCK: StaticRWLock = StaticRWLock::new(); + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + extern "C" { + static mut environ: *const *const c_char; + } + + unsafe { + let _guard = ENV_LOCK.read(); + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env { iter: result.into_iter() }; + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option { + // environment variables with a nul byte can't be set, so their value is + // always None as well + let k = CString::new(k.as_bytes()).ok()?; + unsafe { + let _guard = ENV_LOCK.read(); + let s = libc::getenv(k.as_ptr()) as *const libc::c_char; + if s.is_null() { + None + } else { + Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) + } + } +} + +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let k = CString::new(k.as_bytes())?; + let v = CString::new(v.as_bytes())?; + + unsafe { + let _guard = ENV_LOCK.write(); + cvt_env(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) + } +} + +pub fn unsetenv(n: &OsStr) -> io::Result<()> { + let nbuf = CString::new(n.as_bytes())?; + + unsafe { + let _guard = ENV_LOCK.write(); + cvt_env(libc::unsetenv(nbuf.as_ptr())).map(drop) + } +} + +/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this +/// function just returns a generic error. +fn cvt_env(t: c_int) -> io::Result { + if t == -1 { + Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure")) + } else { + Ok(t) + } +} + +pub fn temp_dir() -> PathBuf { + panic!("no standard temporary directory on this platform") +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(_code: i32) -> ! { + let tid = itron::task::try_current_task_id().unwrap_or(0); + loop { + abi::breakpoint_program_exited(tid as usize); + } +} + +pub fn getpid() -> u32 { + panic!("no pids on this platform") +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/path.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/path.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/path.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/path.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +use crate::ffi::OsStr; +use crate::path::Prefix; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'\\' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'\\' +} + +pub fn parse_prefix(_: &OsStr) -> Option> { + None +} + +pub const MAIN_SEP_STR: &str = "\\"; +pub const MAIN_SEP: char = '\\'; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/rwlock.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/rwlock.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/rwlock.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/rwlock.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,92 @@ +//! A readers-writer lock implementation backed by the SOLID kernel extension. +use super::{ + abi, + itron::{ + error::{expect_success, expect_success_aborting, fail, ItronError}, + spin::SpinIdOnceCell, + }, +}; + +pub struct RWLock { + /// The ID of the underlying mutex object + rwl: SpinIdOnceCell<()>, +} + +pub type MovableRWLock = RWLock; + +// Safety: `num_readers` is protected by `mtx_num_readers` +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} + +fn new_rwl() -> Result { + ItronError::err_if_negative(unsafe { abi::rwl_acre_rwl() }) +} + +impl RWLock { + pub const fn new() -> RWLock { + RWLock { rwl: SpinIdOnceCell::new() } + } + + /// Get the inner mutex's ID, which is lazily created. + fn raw(&self) -> abi::ID { + match self.rwl.get_or_try_init(|| new_rwl().map(|id| (id, ()))) { + Ok((id, ())) => id, + Err(e) => fail(e, &"rwl_acre_rwl"), + } + } + + #[inline] + pub unsafe fn read(&self) { + let rwl = self.raw(); + expect_success(unsafe { abi::rwl_loc_rdl(rwl) }, &"rwl_loc_rdl"); + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + let rwl = self.raw(); + match unsafe { abi::rwl_ploc_rdl(rwl) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"rwl_ploc_rdl"); + true + } + } + } + + #[inline] + pub unsafe fn write(&self) { + let rwl = self.raw(); + expect_success(unsafe { abi::rwl_loc_wrl(rwl) }, &"rwl_loc_wrl"); + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + let rwl = self.raw(); + match unsafe { abi::rwl_ploc_wrl(rwl) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"rwl_ploc_wrl"); + true + } + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + let rwl = self.raw(); + expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); + } + + #[inline] + pub unsafe fn write_unlock(&self) { + let rwl = self.raw(); + expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); + } + + #[inline] + pub unsafe fn destroy(&self) { + if let Some(rwl) = self.rwl.get().map(|x| x.0) { + expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl"); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/stdio.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/stdio.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/stdio.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/stdio.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,80 @@ +use super::abi; +use crate::io; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; +struct PanicOutput; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Ok(0) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl PanicOutput { + pub const fn new() -> PanicOutput { + PanicOutput + } +} + +impl io::Write for PanicOutput { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option { + Some(PanicOutput::new()) +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/thread_local_dtor.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/thread_local_dtor.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/thread_local_dtor.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/thread_local_dtor.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,50 @@ +#![cfg(target_thread_local)] +#![unstable(feature = "thread_local_internals", issue = "none")] + +// Simplify dtor registration by using a list of destructors. + +use super::{abi, itron::task}; +use crate::cell::Cell; +use crate::ptr; + +#[thread_local] +static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut()); + +type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; + +pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { + if DTORS.get().is_null() { + let tid = task::current_task_id_aborting(); + let v: Box = box Vec::new(); + DTORS.set(Box::into_raw(v)); + + // Register `tls_dtor` to make sure the TLS destructors are called + // for tasks created by other means than `std::thread` + unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) }; + } + + let list: &mut List = unsafe { &mut *DTORS.get() }; + list.push((t, dtor)); +} + +pub unsafe fn run_dtors() { + let ptr = DTORS.get(); + if !ptr.is_null() { + // Swap the destructor list, call all registered destructors, + // and repeat this until the list becomes permanently empty. + while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new())) + .filter(|list| !list.is_empty()) + { + for (ptr, dtor) in list.into_iter() { + unsafe { dtor(ptr) }; + } + } + + // Drop the destructor list + unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) }; + } +} + +unsafe extern "C" fn tls_dtor(_unused: *mut u8) { + unsafe { run_dtors() }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/thread_local_key.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/thread_local_key.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/thread_local_key.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/thread_local_key.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +pub type Key = usize; + +#[inline] +pub unsafe fn create(_dtor: Option) -> Key { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn set(_key: Key, _value: *mut u8) { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn get(_key: Key) -> *mut u8 { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn destroy(_key: Key) { + panic!("should not be used on the solid target"); +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + panic!("should not be used on the solid target"); +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/time.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/time.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/solid/time.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/solid/time.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,56 @@ +use super::{abi, error::expect_success}; +use crate::{convert::TryInto, mem::MaybeUninit, time::Duration}; + +pub use super::itron::time::Instant; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(abi::time_t); + +pub const UNIX_EPOCH: SystemTime = SystemTime(0); + +impl SystemTime { + pub fn now() -> SystemTime { + let rtc = unsafe { + let mut out = MaybeUninit::zeroed(); + expect_success(abi::SOLID_RTC_ReadTime(out.as_mut_ptr()), &"SOLID_RTC_ReadTime"); + out.assume_init() + }; + let t = unsafe { + libc::mktime(&mut libc::tm { + tm_sec: rtc.tm_sec, + tm_min: rtc.tm_min, + tm_hour: rtc.tm_hour, + tm_mday: rtc.tm_mday, + tm_mon: rtc.tm_mon, + tm_year: rtc.tm_year, + tm_wday: rtc.tm_wday, + tm_yday: 0, + tm_isdst: 0, + tm_gmtoff: 0, + tm_zone: crate::ptr::null_mut(), + }) + }; + assert_ne!(t, -1, "mktime failed"); + SystemTime(t) + } + + pub(super) fn from_time_t(t: abi::time_t) -> Self { + Self(t) + } + + pub fn sub_time(&self, other: &SystemTime) -> Result { + if self.0 >= other.0 { + Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64))) + } else { + Err(Duration::from_secs((other.0 as u64).wrapping_sub(self.0 as u64))) + } + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_add(other.as_secs().try_into().ok()?)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(other.as_secs().try_into().ok()?)?)) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/fs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1416,6 +1416,23 @@ Ok(bytes_copied as u64) } +pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { + let path = cstr(path)?; + cvt(unsafe { libc::chown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + +pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> { + cvt(unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + +pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { + let path = cstr(path)?; + cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] pub fn chroot(dir: &Path) -> io::Result<()> { let dir = cstr(dir)?; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -120,7 +120,7 @@ unsafe fn reset_sigpipe() { #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); + rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } } @@ -307,6 +307,9 @@ #[link(name = "zircon")] #[link(name = "fdio")] extern "C" {} + } else if #[cfg(all(target_os = "linux", target_env = "uclibc"))] { + #[link(name = "dl")] + extern "C" {} } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/os.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/os.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/os.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/os.rs 2021-11-29 19:27:11.000000000 +0000 @@ -380,20 +380,24 @@ #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub fn current_exe() -> io::Result { - extern "C" { - fn getexecname() -> *const c_char; - } - unsafe { - let path = getexecname(); - if path.is_null() { - Err(io::Error::last_os_error()) - } else { - let filename = CStr::from_ptr(path).to_bytes(); - let path = PathBuf::from(::from_bytes(filename)); + if let Ok(path) = crate::fs::read_link("/proc/self/path/a.out") { + Ok(path) + } else { + extern "C" { + fn getexecname() -> *const c_char; + } + unsafe { + let path = getexecname(); + if path.is_null() { + Err(io::Error::last_os_error()) + } else { + let filename = CStr::from_ptr(path).to_bytes(); + let path = PathBuf::from(::from_bytes(filename)); - // Prepend a current working directory to the path if - // it doesn't contain an absolute pathname. - if filename[0] == b'/' { Ok(path) } else { getcwd().map(|cwd| cwd.join(path)) } + // Prepend a current working directory to the path if + // it doesn't contain an absolute pathname. + if filename[0] == b'/' { Ok(path) } else { getcwd().map(|cwd| cwd.join(path)) } + } } } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/process/process_common.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/process/process_common.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/process/process_common.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/process/process_common.rs 2021-11-29 19:27:11.000000000 +0000 @@ -457,9 +457,15 @@ } } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy)] pub struct ExitCode(u8); +impl fmt::Debug for ExitCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("unix_exit_status").field(&self.0).finish() + } +} + impl ExitCode { pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/process/process_unix.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/process/process_unix.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/process/process_unix.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/process/process_unix.rs 2021-11-29 19:27:11.000000000 +0000 @@ -170,7 +170,7 @@ // so we use it sparingly for now. See #89522 for details. // Some tools (e.g. sandboxing tools) may also expect `fork` // rather than `clone3`. - let want_clone3 = self.get_create_pidfd(); + let want_clone3_pidfd = self.get_create_pidfd(); // If we fail to create a pidfd for any reason, this will // stay as -1, which indicates an error. @@ -179,14 +179,9 @@ // Attempt to use the `clone3` syscall, which supports more arguments // (in particular, the ability to create a pidfd). If this fails, // we will fall through this block to a call to `fork()` - if want_clone3 && HAS_CLONE3.load(Ordering::Relaxed) { - let mut flags = 0; - if self.get_create_pidfd() { - flags |= CLONE_PIDFD; - } - + if want_clone3_pidfd && HAS_CLONE3.load(Ordering::Relaxed) { let mut args = clone_args { - flags, + flags: CLONE_PIDFD, pidfd: &mut pidfd as *mut pid_t as u64, child_tid: 0, parent_tid: 0, @@ -339,9 +334,19 @@ let mut set = MaybeUninit::::uninit(); cvt(sigemptyset(set.as_mut_ptr()))?; cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?; - let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); - if ret == libc::SIG_ERR { - return Err(io::Error::last_os_error()); + + #[cfg(target_os = "android")] // see issue #88585 + { + let mut action: libc::sigaction = mem::zeroed(); + action.sa_sigaction = libc::SIG_DFL; + cvt(libc::sigaction(libc::SIGPIPE, &action, ptr::null_mut()))?; + } + #[cfg(not(target_os = "android"))] + { + let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); + if ret == libc::SIG_ERR { + return Err(io::Error::last_os_error()); + } } } @@ -558,8 +563,7 @@ use crate::os::unix::io::FromRawFd; use crate::sys_common::FromInner; // Safety: If `pidfd` is nonnegative, we assume it's valid and otherwise unowned. - let pidfd = (pidfd >= 0) - .then(|| PidFd::from_inner(unsafe { sys::fd::FileDesc::from_raw_fd(pidfd) })); + let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::from_raw_fd(pidfd))); Process { pid, status: None, pidfd } } @@ -613,9 +617,15 @@ } /// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy)] pub struct ExitStatus(c_int); +impl fmt::Debug for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("unix_wait_status").field(&self.0).finish() + } +} + impl ExitStatus { pub fn new(status: c_int) -> ExitStatus { ExitStatus(status) @@ -689,7 +699,7 @@ } } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy)] pub struct ExitStatusError(NonZero_c_int); impl Into for ExitStatusError { @@ -698,6 +708,12 @@ } } +impl fmt::Debug for ExitStatusError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("unix_wait_status").field(&self.0).finish() + } +} + impl ExitStatusError { pub fn code(self) -> Option { ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap()) diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/process/zircon.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/process/zircon.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/process/zircon.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/process/zircon.rs 2021-11-29 19:27:11.000000000 +0000 @@ -25,9 +25,12 @@ pub const ZX_RIGHT_SAME_RIGHTS: zx_rights_t = 1 << 31; +// The upper four bits gives the minor version. pub type zx_object_info_topic_t = u32; -pub const ZX_INFO_PROCESS: zx_object_info_topic_t = 3; +pub const ZX_INFO_PROCESS: zx_object_info_topic_t = 3 | (1 << 28); + +pub type zx_info_process_flags_t = u32; pub fn zx_cvt(t: T) -> io::Result where @@ -68,9 +71,9 @@ #[repr(C)] pub struct zx_info_process_t { pub return_code: i64, - pub started: bool, - pub exited: bool, - pub debugger_attached: bool, + pub start_time: zx_time_t, + pub flags: zx_info_process_flags_t, + pub reserved1: u32, } extern "C" { diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/stack_overflow.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/stack_overflow.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/stack_overflow.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/stack_overflow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -143,14 +143,15 @@ } unsafe fn get_stackp() -> *mut libc::c_void { - let stackp = mmap( - ptr::null_mut(), - SIGSTKSZ + page_size(), - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - -1, - 0, - ); + // OpenBSD requires this flag for stack mapping + // otherwise the said mapping will fail as a no-op on most systems + // and has a different meaning on FreeBSD + #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",))] + let flags = MAP_PRIVATE | MAP_ANON | libc::MAP_STACK; + #[cfg(not(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",)))] + let flags = MAP_PRIVATE | MAP_ANON; + let stackp = + mmap(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0); if stackp == MAP_FAILED { panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error()); } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -263,7 +263,7 @@ } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { cfg_if::cfg_if! { if #[cfg(any( target_os = "android", @@ -338,8 +338,21 @@ } Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) + } else if #[cfg(target_os = "haiku")] { + // system_info cpu_count field gets the static data set at boot time with `smp_set_num_cpus` + // `get_system_info` calls then `smp_get_num_cpus` + unsafe { + let mut sinfo: libc::system_info = crate::mem::zeroed(); + let res = libc::get_system_info(&mut sinfo); + + if res != libc::B_OK { + return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")); + } + + Ok(NonZeroUsize::new_unchecked(sinfo.cpu_count as usize)) + } } else { - // FIXME: implement on vxWorks, Redox, Haiku, l4re + // FIXME: implement on vxWorks, Redox, l4re Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Getting the number of hardware threads is not supported on the target platform")) } } @@ -581,7 +594,8 @@ Some(stackaddr - guardsize..stackaddr) } else if cfg!(all(target_os = "linux", target_env = "musl")) { Some(stackaddr - guardsize..stackaddr) - } else if cfg!(all(target_os = "linux", target_env = "gnu")) { + } else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc"))) + { // glibc used to include the guard area within the stack, as noted in the BUGS // section of `man pthread_attr_getguardsize`. This has been corrected starting // with glibc 2.27, and in some distro backports, so the guard is now placed at the diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/time.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/time.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unix/time.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unix/time.rs 2021-11-29 19:27:11.000000000 +0000 @@ -303,6 +303,7 @@ pub fn actually_monotonic() -> bool { (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) + || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64")) || cfg!(target_os = "fuchsia") } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unsupported/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unsupported/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/unsupported/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/unsupported/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,7 +31,7 @@ } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/wasi/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/wasi/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/wasi/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/wasi/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -64,7 +64,7 @@ } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/wasm/atomics/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/wasm/atomics/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/wasm/atomics/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/wasm/atomics/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -40,7 +40,7 @@ pub fn join(self) {} } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/c.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/c.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/c.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/c.rs 2021-11-29 19:27:11.000000000 +0000 @@ -262,6 +262,8 @@ pub const STATUS_SUCCESS: NTSTATUS = 0x00000000; +pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; + #[repr(C)] #[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { @@ -678,10 +680,6 @@ #[link(name = "advapi32")] extern "system" { - // Forbidden when targeting UWP - #[link_name = "SystemFunction036"] - pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; - // Allowed but unused by UWP pub fn OpenProcessToken( ProcessHandle: HANDLE, @@ -743,8 +741,6 @@ // UWP specific functions & types cfg_if::cfg_if! { if #[cfg(target_vendor = "uwp")] { - pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; - #[repr(C)] pub struct FILE_STANDARD_INFO { pub AllocationSize: LARGE_INTEGER, @@ -754,15 +750,6 @@ pub Directory: BOOLEAN, } - #[link(name = "bcrypt")] - extern "system" { - pub fn BCryptGenRandom( - hAlgorithm: LPVOID, - pBuffer: *mut u8, - cbBuffer: ULONG, - dwFlags: ULONG, - ) -> LONG; - } #[link(name = "kernel32")] extern "system" { pub fn GetFileInformationByHandleEx( @@ -1085,6 +1072,18 @@ ) -> c_int; } +#[link(name = "bcrypt")] +extern "system" { + // >= Vista / Server 2008 + // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom + pub fn BCryptGenRandom( + hAlgorithm: LPVOID, + pBuffer: *mut u8, + cbBuffer: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; +} + // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn! { diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/fs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -558,7 +558,7 @@ impl FromInner for File { fn from_inner(handle: Handle) -> File { - File { handle: handle } + File { handle } } } @@ -672,7 +672,7 @@ impl FileType { fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType { - FileType { attributes: attrs, reparse_tag: reparse_tag } + FileType { attributes: attrs, reparse_tag } } pub fn is_dir(&self) -> bool { !self.is_symlink() && self.is_directory() diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/net.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/net.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/net.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/net.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,13 @@ use crate::cmp; use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::lazy::SyncOnceCell; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; use crate::ptr; -use crate::sync::Once; use crate::sys; use crate::sys::c; use crate::sys_common::net; @@ -29,26 +29,31 @@ pub struct Socket(OwnedSocket); -static INIT: Once = Once::new(); +static WSA_CLEANUP: SyncOnceCell i32> = SyncOnceCell::new(); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. pub fn init() { - INIT.call_once(|| unsafe { + let _ = WSA_CLEANUP.get_or_init(|| unsafe { let mut data: c::WSADATA = mem::zeroed(); let ret = c::WSAStartup( 0x202, // version 2.2 &mut data, ); assert_eq!(ret, 0); + + // Only register `WSACleanup` if `WSAStartup` is actually ever called. + // Workaround to prevent linking to `WS2_32.dll` when no network functionality is used. + // See issue #85441. + c::WSACleanup }); } pub fn cleanup() { - if INIT.is_completed() { - // only close the socket interface if it has actually been started + // only perform cleanup if network functionality was actually initialized + if let Some(cleanup) = WSA_CLEANUP.get() { unsafe { - c::WSACleanup(); + cleanup(); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/rand.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/rand.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/rand.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/rand.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,18 +2,6 @@ use crate::mem; use crate::sys::c; -#[cfg(not(target_vendor = "uwp"))] -pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - let ret = - unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; - if ret == 0 { - panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); - } - v -} - -#[cfg(target_vendor = "uwp")] pub fn hashmap_random_keys() -> (u64, u64) { use crate::ptr; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/stack_overflow.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/stack_overflow.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/stack_overflow.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/stack_overflow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,10 +9,10 @@ pub unsafe fn new() -> Handler { // This API isn't available on XP, so don't panic in that case and just // pray it works out ok. - if c::SetThreadStackGuarantee(&mut 0x5000) == 0 { - if c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32 { - panic!("failed to reserve stack space for exception handling"); - } + if c::SetThreadStackGuarantee(&mut 0x5000) == 0 + && c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32 + { + panic!("failed to reserve stack space for exception handling"); } Handler } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/stdio.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/stdio.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/stdio.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/stdio.rs 2021-11-29 19:27:11.000000000 +0000 @@ -291,15 +291,25 @@ }; let mut amount = 0; - cvt(unsafe { - c::ReadConsoleW( - handle, - buf.as_mut_ptr() as c::LPVOID, - buf.len() as u32, - &mut amount, - &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL, - ) - })?; + loop { + cvt(unsafe { + c::SetLastError(0); + c::ReadConsoleW( + handle, + buf.as_mut_ptr() as c::LPVOID, + buf.len() as u32, + &mut amount, + &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL, + ) + })?; + + // ReadConsoleW returns success with ERROR_OPERATION_ABORTED for Ctrl-C or Ctrl-Break. + // Explicitly check for that case here and try again. + if amount == 0 && unsafe { c::GetLastError() } == c::ERROR_OPERATION_ABORTED { + continue; + } + break; + } if amount > 0 && buf[amount as usize - 1] == CTRL_Z { amount -= 1; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/windows/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/windows/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -100,7 +100,7 @@ } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { let res = unsafe { let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed(); c::GetSystemInfo(&mut sysinfo); diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/backtrace.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/backtrace.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/backtrace.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/backtrace.rs 2021-11-29 19:27:11.000000000 +0000 @@ -93,10 +93,8 @@ if stop { return false; } - if !hit { - if start { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); - } + if !hit && start { + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } idx += 1; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,8 +28,6 @@ pub mod mutex; pub mod process; pub mod remutex; -#[macro_use] -pub mod rt; pub mod rwlock; pub mod thread; pub mod thread_info; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/process.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/process.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/process.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/process.rs 2021-11-29 19:27:11.000000000 +0000 @@ -106,13 +106,13 @@ /// This struct is created by /// [`Command::get_envs`][crate::process::Command::get_envs]. See its /// documentation for more. -#[unstable(feature = "command_access", issue = "44434")] +#[stable(feature = "command_access", since = "1.57.0")] #[derive(Debug)] pub struct CommandEnvs<'a> { iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, } -#[unstable(feature = "command_access", issue = "44434")] +#[stable(feature = "command_access", since = "1.57.0")] impl<'a> Iterator for CommandEnvs<'a> { type Item = (&'a OsStr, Option<&'a OsStr>); fn next(&mut self) -> Option { @@ -123,7 +123,7 @@ } } -#[unstable(feature = "command_access", issue = "44434")] +#[stable(feature = "command_access", since = "1.57.0")] impl<'a> ExactSizeIterator for CommandEnvs<'a> { fn len(&self) -> usize { self.iter.len() diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/rt.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/rt.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/rt.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/rt.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] -#![allow(unused_macros)] - -use crate::sync::Once; -use crate::sys; -use crate::sys_common::thread_info; -use crate::thread::Thread; - -// One-time runtime initialization. -// Runs before `main`. -// SAFETY: must be called only once during runtime initialization. -// NOTE: this is not guaranteed to run, for example when Rust code is called externally. -#[cfg_attr(test, allow(dead_code))] -pub unsafe fn init(argc: isize, argv: *const *const u8) { - unsafe { - sys::init(argc, argv); - - let main_guard = sys::thread::guard::init(); - // Next, set up the current Thread with the guard information we just - // created. Note that this isn't necessary in general for new threads, - // but we just do this to name the main thread and to give it correct - // info about the stack bounds. - let thread = Thread::new(Some("main".to_owned())); - thread_info::set(main_guard, thread); - } -} - -// One-time runtime cleanup. -// Runs after `main` or at program exit. -// NOTE: this is not guaranteed to run, for example when the program aborts. -#[cfg_attr(test, allow(dead_code))] -pub fn cleanup() { - static CLEANUP: Once = Once::new(); - CLEANUP.call_once(|| unsafe { - // Flush stdout and disable buffering. - crate::io::cleanup(); - // SAFETY: Only called once during runtime cleanup. - sys::cleanup(); - }); -} - -// Prints to the "panic output", depending on the platform this may be: -// - the standard error output -// - some dedicated platform specific output -// - nothing (so this macro is a no-op) -macro_rules! rtprintpanic { - ($($t:tt)*) => { - if let Some(mut out) = crate::sys::stdio::panic_output() { - let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); - } - } -} - -macro_rules! rtabort { - ($($t:tt)*) => { - { - rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*)); - crate::sys::abort_internal(); - } - } -} - -macro_rules! rtassert { - ($e:expr) => { - if !$e { - rtabort!(concat!("assertion failed: ", stringify!($e))); - } - }; -} - -macro_rules! rtunwrap { - ($ok:ident, $e:expr) => { - match $e { - $ok(v) => v, - ref err => { - let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug - rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) - } - } - }; -} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/thread_info.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/thread_info.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys_common/thread_info.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys_common/thread_info.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,5 @@ #![allow(dead_code)] // stack_guard isn't used right now on all platforms +#![allow(unused_unsafe)] // thread_local with `const {}` triggers this liny use crate::cell::RefCell; use crate::sys::thread::guard::Guard; @@ -9,7 +10,7 @@ thread: Thread, } -thread_local! { static THREAD_INFO: RefCell> = RefCell::new(None) } +thread_local! { static THREAD_INFO: RefCell> = const { RefCell::new(None) } } impl ThreadInfo { fn with(f: F) -> Option @@ -17,12 +18,13 @@ F: FnOnce(&mut ThreadInfo) -> R, { THREAD_INFO - .try_with(move |c| { - if c.borrow().is_none() { - *c.borrow_mut() = - Some(ThreadInfo { stack_guard: None, thread: Thread::new(None) }) - } - f(c.borrow_mut().as_mut().unwrap()) + .try_with(move |thread_info| { + let mut thread_info = thread_info.borrow_mut(); + let thread_info = thread_info.get_or_insert_with(|| ThreadInfo { + stack_guard: None, + thread: Thread::new(None), + }); + f(thread_info) }) .ok() } @@ -37,10 +39,9 @@ } pub fn set(stack_guard: Option, thread: Thread) { - THREAD_INFO.with(|c| assert!(c.borrow().is_none())); - THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo { stack_guard, thread })); -} - -pub fn reset_guard(stack_guard: Option) { - THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard); + THREAD_INFO.with(move |thread_info| { + let mut thread_info = thread_info.borrow_mut(); + rtassert!(thread_info.is_none()); + *thread_info = Some(ThreadInfo { stack_guard, thread }); + }); } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/thread/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/thread/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/thread/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/thread/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -412,9 +412,9 @@ /// /// # Safety /// - /// The caller has to ensure that no references in the supplied thread closure - /// or its return type can outlive the spawned thread's lifetime. This can be - /// guaranteed in two ways: + /// The caller has to ensure that the spawned thread does not outlive any + /// references in the supplied thread closure and its return type. + /// This can be guaranteed in two ways: /// /// - ensure that [`join`][`JoinHandle::join`] is called before any referenced /// data is dropped @@ -457,7 +457,9 @@ let stack_size = stack_size.unwrap_or_else(thread::min_stack); - let my_thread = Thread::new(name); + let my_thread = Thread::new(name.map(|name| { + CString::new(name).expect("thread name may not contain interior null bytes") + })); let their_thread = my_thread.clone(); let my_packet: Arc>>> = Arc::new(UnsafeCell::new(None)); @@ -1029,6 +1031,7 @@ /// value is entirely opaque -- only equality testing is stable. Note that /// it is not guaranteed which values new threads will return, and this may /// change across Rust versions. + #[must_use] #[unstable(feature = "thread_id_value", issue = "67939")] pub fn as_u64(&self) -> NonZeroU64 { self.0 @@ -1073,12 +1076,8 @@ impl Thread { // Used only internally to construct a thread object without spawning // Panics if the name contains nuls. - pub(crate) fn new(name: Option) -> Thread { - let cname = - name.map(|n| CString::new(n).expect("thread name may not contain interior null bytes")); - Thread { - inner: Arc::new(Inner { name: cname, id: ThreadId::new(), parker: Parker::new() }), - } + pub(crate) fn new(name: Option) -> Thread { + Thread { inner: Arc::new(Inner { name, id: ThreadId::new(), parker: Parker::new() }) } } /// Atomically makes the handle's token available if it is not already. @@ -1429,38 +1428,77 @@ _assert_both::(); } -/// Returns the number of hardware threads available to the program. -/// -/// This value should be considered only a hint. -/// -/// # Platform-specific behavior +/// Returns an estimate of the default amount of parallelism a program should use. /// -/// If interpreted as the number of actual hardware threads, it may undercount on -/// Windows systems with more than 64 hardware threads. If interpreted as the -/// available concurrency for that process, it may overcount on Windows systems -/// when limited by a process wide affinity mask or job object limitations, and -/// it may overcount on Linux systems when limited by a process wide affinity -/// mask or affected by cgroups limits. +/// Parallelism is a resource. A given machine provides a certain capacity for +/// parallelism, i.e., a bound on the number of computations it can perform +/// simultaneously. This number often corresponds to the amount of CPUs or +/// computer has, but it may diverge in various cases. +/// +/// Host environments such as VMs or container orchestrators may want to +/// restrict the amount of parallelism made available to programs in them. This +/// is often done to limit the potential impact of (unintentionally) +/// resource-intensive programs on other programs running on the same machine. +/// +/// # Limitations +/// +/// The purpose of this API is to provide an easy and portable way to query +/// the default amount of parallelism the program should use. Among other things it +/// does not expose information on NUMA regions, does not account for +/// differences in (co)processor capabilities, and will not modify the program's +/// global state in order to more accurately query the amount of available +/// parallelism. +/// +/// The value returned by this function should be considered a simplified +/// approximation of the actual amount of parallelism available at any given +/// time. To get a more detailed or precise overview of the amount of +/// parallelism available to the program, you may wish to use +/// platform-specific APIs as well. The following platform limitations currently +/// apply to `available_parallelism`: +/// +/// On Windows: +/// - It may undercount the amount of parallelism available on systems with more +/// than 64 logical CPUs. However, programs typically need specific support to +/// take advantage of more than 64 logical CPUs, and in the absence of such +/// support, the number returned by this function accurately reflects the +/// number of logical CPUs the program can use by default. +/// - It may overcount the amount of parallelism available on systems limited by +/// process-wide affinity masks, or job object limitations. +/// +/// On Linux: +/// - It may overcount the amount of parallelism available when limited by a +/// process-wide affinity mask, or when affected by cgroup limits. +/// +/// On all targets: +/// - It may overcount the amount of parallelism available when running in a VM +/// with CPU usage limits (e.g. an overcommitted host). /// /// # Errors /// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: +/// This function will, but is not limited to, return errors in the following +/// cases: /// -/// - If the number of hardware threads is not known for the target platform. -/// - The process lacks permissions to view the number of hardware threads -/// available. +/// - If the amount of parallelism is not known for the target platform. +/// - If the program lacks permission to query the amount of parallelism made +/// available to it. /// /// # Examples /// /// ``` /// # #![allow(dead_code)] -/// #![feature(available_concurrency)] -/// use std::thread; +/// #![feature(available_parallelism)] +/// use std::{io, thread}; /// -/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1); +/// fn main() -> io::Result<()> { +/// let count = thread::available_parallelism()?.get(); +/// assert!(count >= 1_usize); +/// Ok(()) +/// } /// ``` -#[unstable(feature = "available_concurrency", issue = "74479")] -pub fn available_concurrency() -> io::Result { - imp::available_concurrency() +#[doc(alias = "available_concurrency")] // Alias for a previous name we gave this API on unstable. +#[doc(alias = "hardware_concurrency")] // Alias for C++ `std::thread::hardware_concurrency`. +#[doc(alias = "num_cpus")] // Alias for a popular ecosystem crate which provides similar functionality. +#[unstable(feature = "available_parallelism", issue = "74479")] +pub fn available_parallelism() -> io::Result { + imp::available_parallelism() } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/time/monotonic.rs rustc-1.57.0+dfsg1+llvm/library/std/src/time/monotonic.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/time/monotonic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/time/monotonic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ inner::monotonize(raw) } -#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))] +#[cfg(any(all(target_has_atomic = "64", not(target_has_atomic = "128")), target_arch = "aarch64"))] pub mod inner { use crate::sync::atomic::AtomicU64; use crate::sync::atomic::Ordering::*; @@ -37,40 +37,41 @@ // This could be a problem for programs that call instants at intervals greater // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true. let packed = (secs << 32) | nanos; - let old = mono.load(Relaxed); - - if old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2 { - mono.store(packed, Relaxed); - raw - } else { - // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the - // passed in value and the 64bits loaded from the atomic - let seconds_lower = old >> 32; - let mut seconds_upper = secs & 0xffff_ffff_0000_0000; - if secs & 0xffff_ffff > seconds_lower { - // Backslide caused the lower 32bit of the seconds part to wrap. - // This must be the case because the seconds part is larger even though - // we are in the backslide branch, i.e. the seconds count should be smaller or equal. - // - // We assume that backslides are smaller than 2^32 seconds - // which means we need to add 1 to the upper half to restore it. - // - // Example: - // most recent observed time: 0xA1_0000_0000_0000_0000u128 - // bits stored in AtomicU64: 0x0000_0000_0000_0000u64 - // backslide by 1s - // caller time is 0xA0_ffff_ffff_0000_0000u128 - // -> we can fix up the upper half time by adding 1 << 32 - seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000); + let updated = mono.fetch_update(Relaxed, Relaxed, |old| { + (old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2).then_some(packed) + }); + match updated { + Ok(_) => raw, + Err(newer) => { + // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the + // passed in value and the 64bits loaded from the atomic + let seconds_lower = newer >> 32; + let mut seconds_upper = secs & 0xffff_ffff_0000_0000; + if secs & 0xffff_ffff > seconds_lower { + // Backslide caused the lower 32bit of the seconds part to wrap. + // This must be the case because the seconds part is larger even though + // we are in the backslide branch, i.e. the seconds count should be smaller or equal. + // + // We assume that backslides are smaller than 2^32 seconds + // which means we need to add 1 to the upper half to restore it. + // + // Example: + // most recent observed time: 0xA1_0000_0000_0000_0000u128 + // bits stored in AtomicU64: 0x0000_0000_0000_0000u64 + // backslide by 1s + // caller time is 0xA0_ffff_ffff_0000_0000u128 + // -> we can fix up the upper half time by adding 1 << 32 + seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000); + } + let secs = seconds_upper | seconds_lower; + let nanos = newer as u32; + ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap() } - let secs = seconds_upper | seconds_lower; - let nanos = old as u32; - ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap() } } } -#[cfg(target_has_atomic = "128")] +#[cfg(all(target_has_atomic = "128", not(target_arch = "aarch64")))] pub mod inner { use crate::sync::atomic::AtomicU128; use crate::sync::atomic::Ordering::*; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/time.rs rustc-1.57.0+dfsg1+llvm/library/std/src/time.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/time.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/time.rs 2021-11-29 19:27:11.000000000 +0000 @@ -44,6 +44,9 @@ #[stable(feature = "time", since = "1.3.0")] pub use core::time::Duration; +#[unstable(feature = "duration_checked_float", issue = "83400")] +pub use core::time::FromSecsError; + /// A measurement of a monotonically nondecreasing clock. /// Opaque and useful only with [`Duration`]. /// @@ -105,6 +108,7 @@ /// | UNIX | [clock_gettime (Monotonic Clock)] | /// | Darwin | [mach_absolute_time] | /// | VXWorks | [clock_gettime (Monotonic Clock)] | +/// | SOLID | `get_tim` | /// | WASI | [__wasi_clock_time_get (Monotonic Clock)] | /// | Windows | [QueryPerformanceCounter] | /// @@ -181,6 +185,7 @@ /// | UNIX | [clock_gettime (Realtime Clock)] | /// | Darwin | [gettimeofday] | /// | VXWorks | [clock_gettime (Realtime Clock)] | +/// | SOLID | `SOLID_RTC_ReadTime` | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | /// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | /// @@ -263,6 +268,20 @@ // // To hopefully mitigate the impact of this, a few platforms are // excluded as "these at least haven't gone backwards yet". + // + // While issues have been seen on arm64 platforms the Arm architecture + // requires that the counter monotonically increases and that it must + // provide a uniform view of system time (e.g. it must not be possible + // for a core to recieve a message from another core with a time stamp + // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While + // there have been a few 64bit SoCs that have bugs which cause time to + // not monoticially increase, these have been fixed in the Linux kernel + // and we shouldn't penalize all Arm SoCs for those who refuse to + // update their kernels: + // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1 + // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10 + // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11 + // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12 if time::Instant::actually_monotonic() { return Instant(os_now); } @@ -469,7 +488,7 @@ /// as the system clock being adjusted either forwards or backwards). /// [`Instant`] can be used to measure elapsed time without this risk of failure. /// - /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents + /// If successful, [Ok]\([Duration]) is returned where the duration represents /// the amount of time elapsed from the specified measurement to this one. /// /// Returns an [`Err`] if `earlier` is later than `self`, and the error @@ -496,7 +515,7 @@ /// /// This function may fail as the underlying system clock is susceptible to /// drift and updates (e.g., the system clock could go backwards), so this - /// function might not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is + /// function might not always succeed. If successful, [Ok]\([Duration]) is /// returned where the duration represents the amount of time elapsed from /// this time measurement to the current time. /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/Cargo.toml rustc-1.57.0+dfsg1+llvm/library/stdarch/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/library/stdarch/Cargo.toml 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/Cargo.toml 2021-11-29 19:27:28.000000000 +0000 @@ -4,6 +4,7 @@ "crates/core_arch", "crates/std_detect", "crates/stdarch-gen", + "crates/intrinsic-test", "examples/" ] exclude = [ diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile rustc-1.57.0+dfsg1+llvm/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile --- rustc-1.56.0+dfsg1+llvm/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile 2021-11-29 19:27:28.000000000 +0000 @@ -1,13 +1,17 @@ FROM ubuntu:20.04 RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ + g++ \ ca-certificates \ libc6-dev \ gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu \ libc6-dev-arm64-cross \ qemu-user \ make \ - file + file \ + clang-12 \ + lld ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu" \ diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/ci/run-docker.sh rustc-1.57.0+dfsg1+llvm/library/stdarch/ci/run-docker.sh --- rustc-1.56.0+dfsg1+llvm/library/stdarch/ci/run-docker.sh 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/ci/run-docker.sh 2021-11-29 19:27:28.000000000 +0000 @@ -9,7 +9,7 @@ target=$(echo "${1}" | sed 's/-emulated//') echo "Building docker container for TARGET=${1}" docker build -t stdarch -f "ci/docker/${1}/Dockerfile" ci/ - mkdir -p target + mkdir -p target c_programs rust_programs echo "Running docker" # shellcheck disable=SC2016 docker run \ @@ -29,6 +29,8 @@ --volume "$(rustc --print sysroot)":/rust:ro \ --volume "$(pwd)":/checkout:ro \ --volume "$(pwd)"/target:/checkout/target \ + --volume "$(pwd)"/c_programs:/checkout/c_programs \ + --volume "$(pwd)"/rust_programs:/checkout/rust_programs \ --init \ --workdir /checkout \ --privileged \ diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/ci/run.sh rustc-1.57.0+dfsg1+llvm/library/stdarch/ci/run.sh --- rustc-1.56.0+dfsg1+llvm/library/stdarch/ci/run.sh 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/ci/run.sh 2021-11-29 19:27:28.000000000 +0000 @@ -10,10 +10,17 @@ #export RUST_TEST_NOCAPTURE=1 #export RUST_TEST_THREADS=1 -RUSTFLAGS="$RUSTFLAGS -D warnings " +export RUSTFLAGS="${RUSTFLAGS} -D warnings -Z merge-functions=disabled " + +export STDARCH_DISABLE_DEDUP_GUARD=1 case ${TARGET} in + # On Windows the linker performs identical COMDAT folding (ICF) by default + # in release mode which removes identical COMDAT sections. This interferes + # with our instruction assertions just like LLVM's MergeFunctions pass so + # we disable it. *-pc-windows-msvc) + export RUSTFLAGS="${RUSTFLAGS} -Clink-args=/OPT:NOICF" ;; # On 32-bit use a static relocation model which avoids some extra # instructions when dealing with static data, notably allowing some @@ -65,6 +72,8 @@ CORE_ARCH="--manifest-path=crates/core_arch/Cargo.toml" STD_DETECT="--manifest-path=crates/std_detect/Cargo.toml" STDARCH_EXAMPLES="--manifest-path=examples/Cargo.toml" +INTRINSIC_TEST="--manifest-path=crates/intrinsic-test/Cargo.toml" + cargo_test "${CORE_ARCH} --release" if [ "$NOSTD" != "1" ]; then @@ -111,6 +120,11 @@ esac +if [ "${TARGET}" = "aarch64-unknown-linux-gnu" ]; then + export CPPFLAGS="-fuse-ld=lld -I/usr/aarch64-linux-gnu/include/ -I/usr/aarch64-linux-gnu/include/c++/9/aarch64-linux-gnu/" + cargo run ${INTRINSIC_TEST} --release --bin intrinsic-test -- crates/intrinsic-test/neon-intrinsics.csv --runner "${CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER}" --cppcompiler "clang++-12" +fi + if [ "$NORUN" != "1" ] && [ "$NOSTD" != 1 ]; then # Test examples ( diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/assert-instr-macro/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/assert-instr-macro/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/assert-instr-macro/src/lib.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/assert-instr-macro/src/lib.rs 2021-11-29 19:27:28.000000000 +0000 @@ -41,6 +41,10 @@ // testing for. let disable_assert_instr = std::env::var("STDARCH_DISABLE_ASSERT_INSTR").is_ok(); + // Disable dedup guard. Only works if the LLVM MergeFunctions pass is disabled, e.g. + // with `-Z merge-functions=disabled` in RUSTFLAGS. + let disable_dedup_guard = std::env::var("STDARCH_DISABLE_DEDUP_GUARD").is_ok(); + // If instruction tests are disabled avoid emitting this shim at all, just // return the original item without our attribute. if !cfg!(optimized) || disable_assert_instr { @@ -58,6 +62,10 @@ &format!("stdarch_test_shim_{}_{}", name, instr_str), name.span(), ); + let shim_name_ptr = syn::Ident::new( + &format!("stdarch_test_shim_{}_{}_ptr", name, instr_str).to_ascii_uppercase(), + name.span(), + ); let mut inputs = Vec::new(); let mut input_vals = Vec::new(); let mut const_vals = Vec::new(); @@ -124,34 +132,38 @@ syn::LitStr::new("C", proc_macro2::Span::call_site()) }; let shim_name_str = format!("{}{}", shim_name, assert_name); - let to_test = quote! { - #attrs - #[no_mangle] - #[inline(never)] - pub unsafe extern #abi fn #shim_name(#(#inputs),*) #ret { - // The compiler in optimized mode by default runs a pass called - // "mergefunc" where it'll merge functions that look identical. - // Turns out some intrinsics produce identical code and they're - // folded together, meaning that one just jumps to another. This - // messes up our inspection of the disassembly of this function and - // we're not a huge fan of that. - // - // To thwart this pass and prevent functions from being merged we - // generate some code that's hopefully very tight in terms of - // codegen but is otherwise unique to prevent code from being - // folded. - // - // This is avoided on Wasm32 right now since these functions aren't - // inlined which breaks our tests since each intrinsic looks like it - // calls functions. Turns out functions aren't similar enough to get - // merged on wasm32 anyway. This bug is tracked at - // rust-lang/rust#74320. - #[cfg(not(target_arch = "wasm32"))] - ::stdarch_test::_DONT_DEDUP.store( - std::mem::transmute(#shim_name_str.as_bytes().as_ptr()), - std::sync::atomic::Ordering::Relaxed, - ); - #name::<#(#const_vals),*>(#(#input_vals),*) + let to_test = if disable_dedup_guard { + quote! { + #attrs + #[no_mangle] + #[inline(never)] + pub unsafe extern #abi fn #shim_name(#(#inputs),*) #ret { + #name::<#(#const_vals),*>(#(#input_vals),*) + } + } + } else { + quote! { + + const #shim_name_ptr : *const u8 = #shim_name_str.as_ptr(); + + #attrs + #[no_mangle] + #[inline(never)] + pub unsafe extern #abi fn #shim_name(#(#inputs),*) #ret { + // The compiler in optimized mode by default runs a pass called + // "mergefunc" where it'll merge functions that look identical. + // Turns out some intrinsics produce identical code and they're + // folded together, meaning that one just jumps to another. This + // messes up our inspection of the disassembly of this function and + // we're not a huge fan of that. + // + // To thwart this pass and prevent functions from being merged we + // generate some code that's hopefully very tight in terms of + // codegen but is otherwise unique to prevent code from being + // folded. + ::stdarch_test::_DONT_DEDUP = #shim_name_ptr; + #name::<#(#const_vals),*>(#(#input_vals),*) + } } }; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/crc.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/crc.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/crc.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/crc.rs 2021-11-29 19:27:28.000000000 +0000 @@ -1,4 +1,4 @@ -extern "C" { +extern "unadjusted" { #[link_name = "llvm.aarch64.crc32x"] fn crc32x_(crc: u32, data: u64) -> u32; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs 2021-11-29 19:27:28.000000000 +0000 @@ -15,7 +15,7 @@ #[cfg_attr(test, assert_instr(fabd))] pub unsafe fn vabd_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fabd.v1f64")] fn vabd_f64_(a: float64x1_t, b: float64x1_t) -> float64x1_t; } @@ -28,7 +28,7 @@ #[cfg_attr(test, assert_instr(fabd))] pub unsafe fn vabdq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fabd.v2f64")] fn vabdq_f64_(a: float64x2_t, b: float64x2_t) -> float64x2_t; } @@ -1084,7 +1084,7 @@ #[cfg_attr(test, assert_instr(facgt))] pub unsafe fn vcagt_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.facgt.v1i64.v1f64")] fn vcagt_f64_(a: float64x1_t, b: float64x1_t) -> uint64x1_t; } @@ -1097,7 +1097,7 @@ #[cfg_attr(test, assert_instr(facgt))] pub unsafe fn vcagtq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.facgt.v2i64.v2f64")] fn vcagtq_f64_(a: float64x2_t, b: float64x2_t) -> uint64x2_t; } @@ -1110,7 +1110,7 @@ #[cfg_attr(test, assert_instr(facge))] pub unsafe fn vcage_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.facge.v1i64.v1f64")] fn vcage_f64_(a: float64x1_t, b: float64x1_t) -> uint64x1_t; } @@ -1123,7 +1123,7 @@ #[cfg_attr(test, assert_instr(facge))] pub unsafe fn vcageq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.facge.v2i64.v2f64")] fn vcageq_f64_(a: float64x2_t, b: float64x2_t) -> uint64x2_t; } @@ -2103,7 +2103,7 @@ #[cfg_attr(test, assert_instr(fcvtxn))] pub unsafe fn vcvtx_f32_f64(a: float64x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtxn.v2f32.v2f64")] fn vcvtx_f32_f64_(a: float64x2_t) -> float32x2_t; } @@ -2126,7 +2126,7 @@ pub unsafe fn vcvt_n_f64_s64(a: int64x1_t) -> float64x1_t { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxs2fp.v1f64.v1i64")] fn vcvt_n_f64_s64_(a: int64x1_t, n: i32) -> float64x1_t; } @@ -2141,7 +2141,7 @@ pub unsafe fn vcvtq_n_f64_s64(a: int64x2_t) -> float64x2_t { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxs2fp.v2f64.v2i64")] fn vcvtq_n_f64_s64_(a: int64x2_t, n: i32) -> float64x2_t; } @@ -2156,7 +2156,7 @@ pub unsafe fn vcvts_n_f32_s32(a: i32) -> f32 { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxs2fp.f32.i32")] fn vcvts_n_f32_s32_(a: i32, n: i32) -> f32; } @@ -2171,7 +2171,7 @@ pub unsafe fn vcvtd_n_f64_s64(a: i64) -> f64 { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxs2fp.f64.i64")] fn vcvtd_n_f64_s64_(a: i64, n: i32) -> f64; } @@ -2186,7 +2186,7 @@ pub unsafe fn vcvt_n_f64_u64(a: uint64x1_t) -> float64x1_t { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxu2fp.v1f64.v1i64")] fn vcvt_n_f64_u64_(a: uint64x1_t, n: i32) -> float64x1_t; } @@ -2201,7 +2201,7 @@ pub unsafe fn vcvtq_n_f64_u64(a: uint64x2_t) -> float64x2_t { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxu2fp.v2f64.v2i64")] fn vcvtq_n_f64_u64_(a: uint64x2_t, n: i32) -> float64x2_t; } @@ -2216,7 +2216,7 @@ pub unsafe fn vcvts_n_f32_u32(a: u32) -> f32 { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxu2fp.f32.i32")] fn vcvts_n_f32_u32_(a: u32, n: i32) -> f32; } @@ -2231,7 +2231,7 @@ pub unsafe fn vcvtd_n_f64_u64(a: u64) -> f64 { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxu2fp.f64.i64")] fn vcvtd_n_f64_u64_(a: u64, n: i32) -> f64; } @@ -2246,7 +2246,7 @@ pub unsafe fn vcvt_n_s64_f64(a: float64x1_t) -> int64x1_t { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxs.v1i64.v1f64")] fn vcvt_n_s64_f64_(a: float64x1_t, n: i32) -> int64x1_t; } @@ -2261,7 +2261,7 @@ pub unsafe fn vcvtq_n_s64_f64(a: float64x2_t) -> int64x2_t { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxs.v2i64.v2f64")] fn vcvtq_n_s64_f64_(a: float64x2_t, n: i32) -> int64x2_t; } @@ -2276,7 +2276,7 @@ pub unsafe fn vcvts_n_s32_f32(a: f32) -> i32 { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxs.i32.f32")] fn vcvts_n_s32_f32_(a: f32, n: i32) -> i32; } @@ -2291,7 +2291,7 @@ pub unsafe fn vcvtd_n_s64_f64(a: f64) -> i64 { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxs.i64.f64")] fn vcvtd_n_s64_f64_(a: f64, n: i32) -> i64; } @@ -2306,7 +2306,7 @@ pub unsafe fn vcvt_n_u64_f64(a: float64x1_t) -> uint64x1_t { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxu.v1i64.v1f64")] fn vcvt_n_u64_f64_(a: float64x1_t, n: i32) -> uint64x1_t; } @@ -2321,7 +2321,7 @@ pub unsafe fn vcvtq_n_u64_f64(a: float64x2_t) -> uint64x2_t { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxu.v2i64.v2f64")] fn vcvtq_n_u64_f64_(a: float64x2_t, n: i32) -> uint64x2_t; } @@ -2336,7 +2336,7 @@ pub unsafe fn vcvts_n_u32_f32(a: f32) -> u32 { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxu.i32.f32")] fn vcvts_n_u32_f32_(a: f32, n: i32) -> u32; } @@ -2351,7 +2351,7 @@ pub unsafe fn vcvtd_n_u64_f64(a: f64) -> u64 { static_assert!(N : i32 where N >= 1 && N <= 64); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxu.i64.f64")] fn vcvtd_n_u64_f64_(a: f64, n: i32) -> u64; } @@ -2428,7 +2428,7 @@ #[cfg_attr(test, assert_instr(fcvtzs))] pub unsafe fn vcvt_s64_f64(a: float64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fptosi.sat.v1i64.v1f64")] fn vcvt_s64_f64_(a: float64x1_t) -> int64x1_t; } @@ -2441,7 +2441,7 @@ #[cfg_attr(test, assert_instr(fcvtzs))] pub unsafe fn vcvtq_s64_f64(a: float64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fptosi.sat.v2i64.v2f64")] fn vcvtq_s64_f64_(a: float64x2_t) -> int64x2_t; } @@ -2454,7 +2454,7 @@ #[cfg_attr(test, assert_instr(fcvtzu))] pub unsafe fn vcvt_u64_f64(a: float64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fptoui.sat.v1i64.v1f64")] fn vcvt_u64_f64_(a: float64x1_t) -> uint64x1_t; } @@ -2467,7 +2467,7 @@ #[cfg_attr(test, assert_instr(fcvtzu))] pub unsafe fn vcvtq_u64_f64(a: float64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fptoui.sat.v2i64.v2f64")] fn vcvtq_u64_f64_(a: float64x2_t) -> uint64x2_t; } @@ -2480,7 +2480,7 @@ #[cfg_attr(test, assert_instr(fcvtas))] pub unsafe fn vcvta_s32_f32(a: float32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtas.v2i32.v2f32")] fn vcvta_s32_f32_(a: float32x2_t) -> int32x2_t; } @@ -2493,7 +2493,7 @@ #[cfg_attr(test, assert_instr(fcvtas))] pub unsafe fn vcvtaq_s32_f32(a: float32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtas.v4i32.v4f32")] fn vcvtaq_s32_f32_(a: float32x4_t) -> int32x4_t; } @@ -2506,7 +2506,7 @@ #[cfg_attr(test, assert_instr(fcvtas))] pub unsafe fn vcvta_s64_f64(a: float64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtas.v1i64.v1f64")] fn vcvta_s64_f64_(a: float64x1_t) -> int64x1_t; } @@ -2519,7 +2519,7 @@ #[cfg_attr(test, assert_instr(fcvtas))] pub unsafe fn vcvtaq_s64_f64(a: float64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtas.v2i64.v2f64")] fn vcvtaq_s64_f64_(a: float64x2_t) -> int64x2_t; } @@ -2532,7 +2532,7 @@ #[cfg_attr(test, assert_instr(fcvtas))] pub unsafe fn vcvtas_s32_f32(a: f32) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtas.i32.f32")] fn vcvtas_s32_f32_(a: f32) -> i32; } @@ -2545,7 +2545,7 @@ #[cfg_attr(test, assert_instr(fcvtas))] pub unsafe fn vcvtad_s64_f64(a: f64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtas.i64.f64")] fn vcvtad_s64_f64_(a: f64) -> i64; } @@ -2558,7 +2558,7 @@ #[cfg_attr(test, assert_instr(fcvtau))] pub unsafe fn vcvtas_u32_f32(a: f32) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtau.i32.f32")] fn vcvtas_u32_f32_(a: f32) -> u32; } @@ -2571,7 +2571,7 @@ #[cfg_attr(test, assert_instr(fcvtau))] pub unsafe fn vcvtad_u64_f64(a: f64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtau.i64.f64")] fn vcvtad_u64_f64_(a: f64) -> u64; } @@ -2584,7 +2584,7 @@ #[cfg_attr(test, assert_instr(fcvtns))] pub unsafe fn vcvtn_s32_f32(a: float32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtns.v2i32.v2f32")] fn vcvtn_s32_f32_(a: float32x2_t) -> int32x2_t; } @@ -2597,7 +2597,7 @@ #[cfg_attr(test, assert_instr(fcvtns))] pub unsafe fn vcvtnq_s32_f32(a: float32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtns.v4i32.v4f32")] fn vcvtnq_s32_f32_(a: float32x4_t) -> int32x4_t; } @@ -2610,7 +2610,7 @@ #[cfg_attr(test, assert_instr(fcvtns))] pub unsafe fn vcvtn_s64_f64(a: float64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtns.v1i64.v1f64")] fn vcvtn_s64_f64_(a: float64x1_t) -> int64x1_t; } @@ -2623,7 +2623,7 @@ #[cfg_attr(test, assert_instr(fcvtns))] pub unsafe fn vcvtnq_s64_f64(a: float64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtns.v2i64.v2f64")] fn vcvtnq_s64_f64_(a: float64x2_t) -> int64x2_t; } @@ -2636,7 +2636,7 @@ #[cfg_attr(test, assert_instr(fcvtns))] pub unsafe fn vcvtns_s32_f32(a: f32) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtns.i32.f32")] fn vcvtns_s32_f32_(a: f32) -> i32; } @@ -2649,7 +2649,7 @@ #[cfg_attr(test, assert_instr(fcvtns))] pub unsafe fn vcvtnd_s64_f64(a: f64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtns.i64.f64")] fn vcvtnd_s64_f64_(a: f64) -> i64; } @@ -2662,7 +2662,7 @@ #[cfg_attr(test, assert_instr(fcvtms))] pub unsafe fn vcvtm_s32_f32(a: float32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtms.v2i32.v2f32")] fn vcvtm_s32_f32_(a: float32x2_t) -> int32x2_t; } @@ -2675,7 +2675,7 @@ #[cfg_attr(test, assert_instr(fcvtms))] pub unsafe fn vcvtmq_s32_f32(a: float32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtms.v4i32.v4f32")] fn vcvtmq_s32_f32_(a: float32x4_t) -> int32x4_t; } @@ -2688,7 +2688,7 @@ #[cfg_attr(test, assert_instr(fcvtms))] pub unsafe fn vcvtm_s64_f64(a: float64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtms.v1i64.v1f64")] fn vcvtm_s64_f64_(a: float64x1_t) -> int64x1_t; } @@ -2701,7 +2701,7 @@ #[cfg_attr(test, assert_instr(fcvtms))] pub unsafe fn vcvtmq_s64_f64(a: float64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtms.v2i64.v2f64")] fn vcvtmq_s64_f64_(a: float64x2_t) -> int64x2_t; } @@ -2714,7 +2714,7 @@ #[cfg_attr(test, assert_instr(fcvtms))] pub unsafe fn vcvtms_s32_f32(a: f32) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtms.i32.f32")] fn vcvtms_s32_f32_(a: f32) -> i32; } @@ -2727,7 +2727,7 @@ #[cfg_attr(test, assert_instr(fcvtms))] pub unsafe fn vcvtmd_s64_f64(a: f64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtms.i64.f64")] fn vcvtmd_s64_f64_(a: f64) -> i64; } @@ -2740,7 +2740,7 @@ #[cfg_attr(test, assert_instr(fcvtps))] pub unsafe fn vcvtp_s32_f32(a: float32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtps.v2i32.v2f32")] fn vcvtp_s32_f32_(a: float32x2_t) -> int32x2_t; } @@ -2753,7 +2753,7 @@ #[cfg_attr(test, assert_instr(fcvtps))] pub unsafe fn vcvtpq_s32_f32(a: float32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtps.v4i32.v4f32")] fn vcvtpq_s32_f32_(a: float32x4_t) -> int32x4_t; } @@ -2766,7 +2766,7 @@ #[cfg_attr(test, assert_instr(fcvtps))] pub unsafe fn vcvtp_s64_f64(a: float64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtps.v1i64.v1f64")] fn vcvtp_s64_f64_(a: float64x1_t) -> int64x1_t; } @@ -2779,7 +2779,7 @@ #[cfg_attr(test, assert_instr(fcvtps))] pub unsafe fn vcvtpq_s64_f64(a: float64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtps.v2i64.v2f64")] fn vcvtpq_s64_f64_(a: float64x2_t) -> int64x2_t; } @@ -2792,7 +2792,7 @@ #[cfg_attr(test, assert_instr(fcvtps))] pub unsafe fn vcvtps_s32_f32(a: f32) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtps.i32.f32")] fn vcvtps_s32_f32_(a: f32) -> i32; } @@ -2805,7 +2805,7 @@ #[cfg_attr(test, assert_instr(fcvtps))] pub unsafe fn vcvtpd_s64_f64(a: f64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtps.i64.f64")] fn vcvtpd_s64_f64_(a: f64) -> i64; } @@ -2818,7 +2818,7 @@ #[cfg_attr(test, assert_instr(fcvtau))] pub unsafe fn vcvta_u32_f32(a: float32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtau.v2i32.v2f32")] fn vcvta_u32_f32_(a: float32x2_t) -> uint32x2_t; } @@ -2831,7 +2831,7 @@ #[cfg_attr(test, assert_instr(fcvtau))] pub unsafe fn vcvtaq_u32_f32(a: float32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtau.v4i32.v4f32")] fn vcvtaq_u32_f32_(a: float32x4_t) -> uint32x4_t; } @@ -2844,7 +2844,7 @@ #[cfg_attr(test, assert_instr(fcvtau))] pub unsafe fn vcvta_u64_f64(a: float64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtau.v1i64.v1f64")] fn vcvta_u64_f64_(a: float64x1_t) -> uint64x1_t; } @@ -2857,7 +2857,7 @@ #[cfg_attr(test, assert_instr(fcvtau))] pub unsafe fn vcvtaq_u64_f64(a: float64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtau.v2i64.v2f64")] fn vcvtaq_u64_f64_(a: float64x2_t) -> uint64x2_t; } @@ -2870,7 +2870,7 @@ #[cfg_attr(test, assert_instr(fcvtnu))] pub unsafe fn vcvtn_u32_f32(a: float32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtnu.v2i32.v2f32")] fn vcvtn_u32_f32_(a: float32x2_t) -> uint32x2_t; } @@ -2883,7 +2883,7 @@ #[cfg_attr(test, assert_instr(fcvtnu))] pub unsafe fn vcvtnq_u32_f32(a: float32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtnu.v4i32.v4f32")] fn vcvtnq_u32_f32_(a: float32x4_t) -> uint32x4_t; } @@ -2896,7 +2896,7 @@ #[cfg_attr(test, assert_instr(fcvtnu))] pub unsafe fn vcvtn_u64_f64(a: float64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtnu.v1i64.v1f64")] fn vcvtn_u64_f64_(a: float64x1_t) -> uint64x1_t; } @@ -2909,7 +2909,7 @@ #[cfg_attr(test, assert_instr(fcvtnu))] pub unsafe fn vcvtnq_u64_f64(a: float64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtnu.v2i64.v2f64")] fn vcvtnq_u64_f64_(a: float64x2_t) -> uint64x2_t; } @@ -2922,7 +2922,7 @@ #[cfg_attr(test, assert_instr(fcvtnu))] pub unsafe fn vcvtns_u32_f32(a: f32) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtnu.i32.f32")] fn vcvtns_u32_f32_(a: f32) -> u32; } @@ -2935,7 +2935,7 @@ #[cfg_attr(test, assert_instr(fcvtnu))] pub unsafe fn vcvtnd_u64_f64(a: f64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtnu.i64.f64")] fn vcvtnd_u64_f64_(a: f64) -> u64; } @@ -2948,7 +2948,7 @@ #[cfg_attr(test, assert_instr(fcvtmu))] pub unsafe fn vcvtm_u32_f32(a: float32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtmu.v2i32.v2f32")] fn vcvtm_u32_f32_(a: float32x2_t) -> uint32x2_t; } @@ -2961,7 +2961,7 @@ #[cfg_attr(test, assert_instr(fcvtmu))] pub unsafe fn vcvtmq_u32_f32(a: float32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtmu.v4i32.v4f32")] fn vcvtmq_u32_f32_(a: float32x4_t) -> uint32x4_t; } @@ -2974,7 +2974,7 @@ #[cfg_attr(test, assert_instr(fcvtmu))] pub unsafe fn vcvtm_u64_f64(a: float64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtmu.v1i64.v1f64")] fn vcvtm_u64_f64_(a: float64x1_t) -> uint64x1_t; } @@ -2987,7 +2987,7 @@ #[cfg_attr(test, assert_instr(fcvtmu))] pub unsafe fn vcvtmq_u64_f64(a: float64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtmu.v2i64.v2f64")] fn vcvtmq_u64_f64_(a: float64x2_t) -> uint64x2_t; } @@ -3000,7 +3000,7 @@ #[cfg_attr(test, assert_instr(fcvtmu))] pub unsafe fn vcvtms_u32_f32(a: f32) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtmu.i32.f32")] fn vcvtms_u32_f32_(a: f32) -> u32; } @@ -3013,7 +3013,7 @@ #[cfg_attr(test, assert_instr(fcvtmu))] pub unsafe fn vcvtmd_u64_f64(a: f64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtmu.i64.f64")] fn vcvtmd_u64_f64_(a: f64) -> u64; } @@ -3026,7 +3026,7 @@ #[cfg_attr(test, assert_instr(fcvtpu))] pub unsafe fn vcvtp_u32_f32(a: float32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtpu.v2i32.v2f32")] fn vcvtp_u32_f32_(a: float32x2_t) -> uint32x2_t; } @@ -3039,7 +3039,7 @@ #[cfg_attr(test, assert_instr(fcvtpu))] pub unsafe fn vcvtpq_u32_f32(a: float32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtpu.v4i32.v4f32")] fn vcvtpq_u32_f32_(a: float32x4_t) -> uint32x4_t; } @@ -3052,7 +3052,7 @@ #[cfg_attr(test, assert_instr(fcvtpu))] pub unsafe fn vcvtp_u64_f64(a: float64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtpu.v1i64.v1f64")] fn vcvtp_u64_f64_(a: float64x1_t) -> uint64x1_t; } @@ -3065,7 +3065,7 @@ #[cfg_attr(test, assert_instr(fcvtpu))] pub unsafe fn vcvtpq_u64_f64(a: float64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtpu.v2i64.v2f64")] fn vcvtpq_u64_f64_(a: float64x2_t) -> uint64x2_t; } @@ -3078,7 +3078,7 @@ #[cfg_attr(test, assert_instr(fcvtpu))] pub unsafe fn vcvtps_u32_f32(a: f32) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtpu.i32.f32")] fn vcvtps_u32_f32_(a: f32) -> u32; } @@ -3091,7 +3091,7 @@ #[cfg_attr(test, assert_instr(fcvtpu))] pub unsafe fn vcvtpd_u64_f64(a: f64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fcvtpu.i64.f64")] fn vcvtpd_u64_f64_(a: f64) -> u64; } @@ -3914,7 +3914,7 @@ #[cfg_attr(test, assert_instr(sqneg))] pub unsafe fn vqneg_s64(a: int64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqneg.v1i64")] fn vqneg_s64_(a: int64x1_t) -> int64x1_t; } @@ -3927,7 +3927,7 @@ #[cfg_attr(test, assert_instr(sqneg))] pub unsafe fn vqnegq_s64(a: int64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqneg.v2i64")] fn vqnegq_s64_(a: int64x2_t) -> int64x2_t; } @@ -3980,7 +3980,7 @@ #[cfg_attr(test, assert_instr(uqsub))] pub unsafe fn vqsubs_u32(a: u32, b: u32) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.i32")] fn vqsubs_u32_(a: u32, b: u32) -> u32; } @@ -3993,7 +3993,7 @@ #[cfg_attr(test, assert_instr(uqsub))] pub unsafe fn vqsubd_u64(a: u64, b: u64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.i64")] fn vqsubd_u64_(a: u64, b: u64) -> u64; } @@ -4006,7 +4006,7 @@ #[cfg_attr(test, assert_instr(sqsub))] pub unsafe fn vqsubs_s32(a: i32, b: i32) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.i32")] fn vqsubs_s32_(a: i32, b: i32) -> i32; } @@ -4019,7 +4019,7 @@ #[cfg_attr(test, assert_instr(sqsub))] pub unsafe fn vqsubd_s64(a: i64, b: i64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.i64")] fn vqsubd_s64_(a: i64, b: i64) -> i64; } @@ -4032,7 +4032,7 @@ #[cfg_attr(test, assert_instr(rbit))] pub unsafe fn vrbit_s8(a: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.rbit.v8i8")] fn vrbit_s8_(a: int8x8_t) -> int8x8_t; } @@ -4045,7 +4045,7 @@ #[cfg_attr(test, assert_instr(rbit))] pub unsafe fn vrbitq_s8(a: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.rbit.v16i8")] fn vrbitq_s8_(a: int8x16_t) -> int8x16_t; } @@ -4090,7 +4090,7 @@ #[cfg_attr(test, assert_instr(frintx))] pub unsafe fn vrndx_f32(a: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.rint.v2f32")] fn vrndx_f32_(a: float32x2_t) -> float32x2_t; } @@ -4103,7 +4103,7 @@ #[cfg_attr(test, assert_instr(frintx))] pub unsafe fn vrndxq_f32(a: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.rint.v4f32")] fn vrndxq_f32_(a: float32x4_t) -> float32x4_t; } @@ -4116,7 +4116,7 @@ #[cfg_attr(test, assert_instr(frintx))] pub unsafe fn vrndx_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.rint.v1f64")] fn vrndx_f64_(a: float64x1_t) -> float64x1_t; } @@ -4129,7 +4129,7 @@ #[cfg_attr(test, assert_instr(frintx))] pub unsafe fn vrndxq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.rint.v2f64")] fn vrndxq_f64_(a: float64x2_t) -> float64x2_t; } @@ -4142,7 +4142,7 @@ #[cfg_attr(test, assert_instr(frinta))] pub unsafe fn vrnda_f32(a: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.round.v2f32")] fn vrnda_f32_(a: float32x2_t) -> float32x2_t; } @@ -4155,7 +4155,7 @@ #[cfg_attr(test, assert_instr(frinta))] pub unsafe fn vrndaq_f32(a: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.round.v4f32")] fn vrndaq_f32_(a: float32x4_t) -> float32x4_t; } @@ -4168,7 +4168,7 @@ #[cfg_attr(test, assert_instr(frinta))] pub unsafe fn vrnda_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.round.v1f64")] fn vrnda_f64_(a: float64x1_t) -> float64x1_t; } @@ -4181,7 +4181,7 @@ #[cfg_attr(test, assert_instr(frinta))] pub unsafe fn vrndaq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.round.v2f64")] fn vrndaq_f64_(a: float64x2_t) -> float64x2_t; } @@ -4194,7 +4194,7 @@ #[cfg_attr(test, assert_instr(frintn))] pub unsafe fn vrndn_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frintn.v1f64")] fn vrndn_f64_(a: float64x1_t) -> float64x1_t; } @@ -4207,7 +4207,7 @@ #[cfg_attr(test, assert_instr(frintn))] pub unsafe fn vrndnq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frintn.v2f64")] fn vrndnq_f64_(a: float64x2_t) -> float64x2_t; } @@ -4220,7 +4220,7 @@ #[cfg_attr(test, assert_instr(frintm))] pub unsafe fn vrndm_f32(a: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.floor.v2f32")] fn vrndm_f32_(a: float32x2_t) -> float32x2_t; } @@ -4233,7 +4233,7 @@ #[cfg_attr(test, assert_instr(frintm))] pub unsafe fn vrndmq_f32(a: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.floor.v4f32")] fn vrndmq_f32_(a: float32x4_t) -> float32x4_t; } @@ -4246,7 +4246,7 @@ #[cfg_attr(test, assert_instr(frintm))] pub unsafe fn vrndm_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.floor.v1f64")] fn vrndm_f64_(a: float64x1_t) -> float64x1_t; } @@ -4259,7 +4259,7 @@ #[cfg_attr(test, assert_instr(frintm))] pub unsafe fn vrndmq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.floor.v2f64")] fn vrndmq_f64_(a: float64x2_t) -> float64x2_t; } @@ -4272,7 +4272,7 @@ #[cfg_attr(test, assert_instr(frintp))] pub unsafe fn vrndp_f32(a: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.ceil.v2f32")] fn vrndp_f32_(a: float32x2_t) -> float32x2_t; } @@ -4285,7 +4285,7 @@ #[cfg_attr(test, assert_instr(frintp))] pub unsafe fn vrndpq_f32(a: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.ceil.v4f32")] fn vrndpq_f32_(a: float32x4_t) -> float32x4_t; } @@ -4298,7 +4298,7 @@ #[cfg_attr(test, assert_instr(frintp))] pub unsafe fn vrndp_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.ceil.v1f64")] fn vrndp_f64_(a: float64x1_t) -> float64x1_t; } @@ -4311,7 +4311,7 @@ #[cfg_attr(test, assert_instr(frintp))] pub unsafe fn vrndpq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.ceil.v2f64")] fn vrndpq_f64_(a: float64x2_t) -> float64x2_t; } @@ -4324,7 +4324,7 @@ #[cfg_attr(test, assert_instr(frintz))] pub unsafe fn vrnd_f32(a: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.trunc.v2f32")] fn vrnd_f32_(a: float32x2_t) -> float32x2_t; } @@ -4337,7 +4337,7 @@ #[cfg_attr(test, assert_instr(frintz))] pub unsafe fn vrndq_f32(a: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.trunc.v4f32")] fn vrndq_f32_(a: float32x4_t) -> float32x4_t; } @@ -4350,7 +4350,7 @@ #[cfg_attr(test, assert_instr(frintz))] pub unsafe fn vrnd_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.trunc.v1f64")] fn vrnd_f64_(a: float64x1_t) -> float64x1_t; } @@ -4363,7 +4363,7 @@ #[cfg_attr(test, assert_instr(frintz))] pub unsafe fn vrndq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.trunc.v2f64")] fn vrndq_f64_(a: float64x2_t) -> float64x2_t; } @@ -4376,7 +4376,7 @@ #[cfg_attr(test, assert_instr(frinti))] pub unsafe fn vrndi_f32(a: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.nearbyint.v2f32")] fn vrndi_f32_(a: float32x2_t) -> float32x2_t; } @@ -4389,7 +4389,7 @@ #[cfg_attr(test, assert_instr(frinti))] pub unsafe fn vrndiq_f32(a: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.nearbyint.v4f32")] fn vrndiq_f32_(a: float32x4_t) -> float32x4_t; } @@ -4402,7 +4402,7 @@ #[cfg_attr(test, assert_instr(frinti))] pub unsafe fn vrndi_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.nearbyint.v1f64")] fn vrndi_f64_(a: float64x1_t) -> float64x1_t; } @@ -4415,7 +4415,7 @@ #[cfg_attr(test, assert_instr(frinti))] pub unsafe fn vrndiq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.nearbyint.v2f64")] fn vrndiq_f64_(a: float64x2_t) -> float64x2_t; } @@ -4468,7 +4468,7 @@ #[cfg_attr(test, assert_instr(uqadd))] pub unsafe fn vqadds_u32(a: u32, b: u32) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.i32")] fn vqadds_u32_(a: u32, b: u32) -> u32; } @@ -4481,7 +4481,7 @@ #[cfg_attr(test, assert_instr(uqadd))] pub unsafe fn vqaddd_u64(a: u64, b: u64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.i64")] fn vqaddd_u64_(a: u64, b: u64) -> u64; } @@ -4494,7 +4494,7 @@ #[cfg_attr(test, assert_instr(sqadd))] pub unsafe fn vqadds_s32(a: i32, b: i32) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.i32")] fn vqadds_s32_(a: i32, b: i32) -> i32; } @@ -4507,13 +4507,169 @@ #[cfg_attr(test, assert_instr(sqadd))] pub unsafe fn vqaddd_s64(a: i64, b: i64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.i64")] fn vqaddd_s64_(a: i64, b: i64) -> i64; } vqaddd_s64_(a, b) } +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ld1))] +pub unsafe fn vld1_f64_x2(a: *const f64) -> float64x1x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v1f64.p0f64")] + fn vld1_f64_x2_(a: *const f64) -> float64x1x2_t; + } + vld1_f64_x2_(a) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ld1))] +pub unsafe fn vld1q_f64_x2(a: *const f64) -> float64x2x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v2f64.p0f64")] + fn vld1q_f64_x2_(a: *const f64) -> float64x2x2_t; + } + vld1q_f64_x2_(a) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ld1))] +pub unsafe fn vld1_f64_x3(a: *const f64) -> float64x1x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v1f64.p0f64")] + fn vld1_f64_x3_(a: *const f64) -> float64x1x3_t; + } + vld1_f64_x3_(a) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ld1))] +pub unsafe fn vld1q_f64_x3(a: *const f64) -> float64x2x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v2f64.p0f64")] + fn vld1q_f64_x3_(a: *const f64) -> float64x2x3_t; + } + vld1q_f64_x3_(a) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ld1))] +pub unsafe fn vld1_f64_x4(a: *const f64) -> float64x1x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v1f64.p0f64")] + fn vld1_f64_x4_(a: *const f64) -> float64x1x4_t; + } + vld1_f64_x4_(a) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ld1))] +pub unsafe fn vld1q_f64_x4(a: *const f64) -> float64x2x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v2f64.p0f64")] + fn vld1q_f64_x4_(a: *const f64) -> float64x2x4_t; + } + vld1q_f64_x4_(a) +} + +/// Store multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(st1))] +pub unsafe fn vst1_f64_x2(a: *mut f64, b: float64x1x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v1f64.p0f64")] + fn vst1_f64_x2_(a: float64x1_t, b: float64x1_t, ptr: *mut f64); + } + vst1_f64_x2_(b.0, b.1, a) +} + +/// Store multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(st1))] +pub unsafe fn vst1q_f64_x2(a: *mut f64, b: float64x2x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v2f64.p0f64")] + fn vst1q_f64_x2_(a: float64x2_t, b: float64x2_t, ptr: *mut f64); + } + vst1q_f64_x2_(b.0, b.1, a) +} + +/// Store multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(st1))] +pub unsafe fn vst1_f64_x3(a: *mut f64, b: float64x1x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v1f64.p0f64")] + fn vst1_f64_x3_(a: float64x1_t, b: float64x1_t, c: float64x1_t, ptr: *mut f64); + } + vst1_f64_x3_(b.0, b.1, b.2, a) +} + +/// Store multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(st1))] +pub unsafe fn vst1q_f64_x3(a: *mut f64, b: float64x2x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v2f64.p0f64")] + fn vst1q_f64_x3_(a: float64x2_t, b: float64x2_t, c: float64x2_t, ptr: *mut f64); + } + vst1q_f64_x3_(b.0, b.1, b.2, a) +} + +/// Store multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(st1))] +pub unsafe fn vst1_f64_x4(a: *mut f64, b: float64x1x4_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v1f64.p0f64")] + fn vst1_f64_x4_(a: float64x1_t, b: float64x1_t, c: float64x1_t, d: float64x1_t, ptr: *mut f64); + } + vst1_f64_x4_(b.0, b.1, b.2, b.3, a) +} + +/// Store multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(st1))] +pub unsafe fn vst1q_f64_x4(a: *mut f64, b: float64x2x4_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v2f64.p0f64")] + fn vst1q_f64_x4_(a: float64x2_t, b: float64x2_t, c: float64x2_t, d: float64x2_t, ptr: *mut f64); + } + vst1q_f64_x4_(b.0, b.1, b.2, b.3, a) +} + /// Multiply #[inline] #[target_feature(enable = "neon")] @@ -4696,7 +4852,7 @@ #[cfg_attr(test, assert_instr(pmull))] pub unsafe fn vmull_p64(a: p64, b: p64) -> p128 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.pmull64")] fn vmull_p64_(a: p64, b: p64) -> int8x16_t; } @@ -4839,7 +4995,7 @@ #[cfg_attr(test, assert_instr(fmulx))] pub unsafe fn vmulx_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmulx.v2f32")] fn vmulx_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; } @@ -4852,7 +5008,7 @@ #[cfg_attr(test, assert_instr(fmulx))] pub unsafe fn vmulxq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmulx.v4f32")] fn vmulxq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; } @@ -4865,7 +5021,7 @@ #[cfg_attr(test, assert_instr(fmulx))] pub unsafe fn vmulx_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmulx.v1f64")] fn vmulx_f64_(a: float64x1_t, b: float64x1_t) -> float64x1_t; } @@ -4878,7 +5034,7 @@ #[cfg_attr(test, assert_instr(fmulx))] pub unsafe fn vmulxq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmulx.v2f64")] fn vmulxq_f64_(a: float64x2_t, b: float64x2_t) -> float64x2_t; } @@ -4971,7 +5127,7 @@ #[cfg_attr(test, assert_instr(fmulx))] pub unsafe fn vmulxs_f32(a: f32, b: f32) -> f32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmulx.f32")] fn vmulxs_f32_(a: f32, b: f32) -> f32; } @@ -4984,7 +5140,7 @@ #[cfg_attr(test, assert_instr(fmulx))] pub unsafe fn vmulxd_f64(a: f64, b: f64) -> f64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmulx.f64")] fn vmulxd_f64_(a: f64, b: f64) -> f64; } @@ -5037,7 +5193,7 @@ #[cfg_attr(test, assert_instr(fmadd))] pub unsafe fn vfma_f64(a: float64x1_t, b: float64x1_t, c: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.v1f64")] fn vfma_f64_(a: float64x1_t, b: float64x1_t, c: float64x1_t) -> float64x1_t; } @@ -5050,7 +5206,7 @@ #[cfg_attr(test, assert_instr(fmla))] pub unsafe fn vfmaq_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.v2f64")] fn vfmaq_f64_(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> float64x2_t; } @@ -5160,7 +5316,7 @@ #[rustc_legacy_const_generics(3)] pub unsafe fn vfmas_lane_f32(a: f32, b: f32, c: float32x2_t) -> f32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.f32")] fn vfmas_lane_f32_(a: f32, b: f32, c: f32) -> f32; } @@ -5176,7 +5332,7 @@ #[rustc_legacy_const_generics(3)] pub unsafe fn vfmas_laneq_f32(a: f32, b: f32, c: float32x4_t) -> f32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.f32")] fn vfmas_laneq_f32_(a: f32, b: f32, c: f32) -> f32; } @@ -5192,7 +5348,7 @@ #[rustc_legacy_const_generics(3)] pub unsafe fn vfmad_lane_f64(a: f64, b: f64, c: float64x1_t) -> f64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.f64")] fn vfmad_lane_f64_(a: f64, b: f64, c: f64) -> f64; } @@ -5208,7 +5364,7 @@ #[rustc_legacy_const_generics(3)] pub unsafe fn vfmad_laneq_f64(a: f64, b: f64, c: float64x2_t) -> f64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.f64")] fn vfmad_laneq_f64_(a: f64, b: f64, c: f64) -> f64; } @@ -5421,7 +5577,7 @@ #[cfg_attr(test, assert_instr(saddlv))] pub unsafe fn vaddlv_s16(a: int16x4_t) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.saddlv.i32.v4i16")] fn vaddlv_s16_(a: int16x4_t) -> i32; } @@ -5434,7 +5590,7 @@ #[cfg_attr(test, assert_instr(saddlv))] pub unsafe fn vaddlvq_s16(a: int16x8_t) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.saddlv.i32.v8i16")] fn vaddlvq_s16_(a: int16x8_t) -> i32; } @@ -5447,7 +5603,7 @@ #[cfg_attr(test, assert_instr(saddlp))] pub unsafe fn vaddlv_s32(a: int32x2_t) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.saddlv.i64.v2i32")] fn vaddlv_s32_(a: int32x2_t) -> i64; } @@ -5460,7 +5616,7 @@ #[cfg_attr(test, assert_instr(saddlv))] pub unsafe fn vaddlvq_s32(a: int32x4_t) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.saddlv.i64.v4i32")] fn vaddlvq_s32_(a: int32x4_t) -> i64; } @@ -5473,7 +5629,7 @@ #[cfg_attr(test, assert_instr(uaddlv))] pub unsafe fn vaddlv_u16(a: uint16x4_t) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uaddlv.i32.v4i16")] fn vaddlv_u16_(a: uint16x4_t) -> u32; } @@ -5486,7 +5642,7 @@ #[cfg_attr(test, assert_instr(uaddlv))] pub unsafe fn vaddlvq_u16(a: uint16x8_t) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uaddlv.i32.v8i16")] fn vaddlvq_u16_(a: uint16x8_t) -> u32; } @@ -5499,7 +5655,7 @@ #[cfg_attr(test, assert_instr(uaddlp))] pub unsafe fn vaddlv_u32(a: uint32x2_t) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uaddlv.i64.v2i32")] fn vaddlv_u32_(a: uint32x2_t) -> u64; } @@ -5512,7 +5668,7 @@ #[cfg_attr(test, assert_instr(uaddlv))] pub unsafe fn vaddlvq_u32(a: uint32x4_t) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uaddlv.i64.v4i32")] fn vaddlvq_u32_(a: uint32x4_t) -> u64; } @@ -5651,7 +5807,7 @@ #[cfg_attr(test, assert_instr(fmax))] pub unsafe fn vmax_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v1f64")] fn vmax_f64_(a: float64x1_t, b: float64x1_t) -> float64x1_t; } @@ -5664,7 +5820,7 @@ #[cfg_attr(test, assert_instr(fmax))] pub unsafe fn vmaxq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v2f64")] fn vmaxq_f64_(a: float64x2_t, b: float64x2_t) -> float64x2_t; } @@ -5677,7 +5833,7 @@ #[cfg_attr(test, assert_instr(fmaxnm))] pub unsafe fn vmaxnm_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnm.v1f64")] fn vmaxnm_f64_(a: float64x1_t, b: float64x1_t) -> float64x1_t; } @@ -5690,7 +5846,7 @@ #[cfg_attr(test, assert_instr(fmaxnm))] pub unsafe fn vmaxnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnm.v2f64")] fn vmaxnmq_f64_(a: float64x2_t, b: float64x2_t) -> float64x2_t; } @@ -5703,7 +5859,7 @@ #[cfg_attr(test, assert_instr(fmaxnmp))] pub unsafe fn vpmaxnm_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnmp.v2f32")] fn vpmaxnm_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; } @@ -5716,7 +5872,7 @@ #[cfg_attr(test, assert_instr(fmaxnmp))] pub unsafe fn vpmaxnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnmp.v2f64")] fn vpmaxnmq_f64_(a: float64x2_t, b: float64x2_t) -> float64x2_t; } @@ -5729,7 +5885,7 @@ #[cfg_attr(test, assert_instr(fmaxnmp))] pub unsafe fn vpmaxnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnmp.v4f32")] fn vpmaxnmq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; } @@ -5742,7 +5898,7 @@ #[cfg_attr(test, assert_instr(fmin))] pub unsafe fn vmin_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v1f64")] fn vmin_f64_(a: float64x1_t, b: float64x1_t) -> float64x1_t; } @@ -5755,7 +5911,7 @@ #[cfg_attr(test, assert_instr(fmin))] pub unsafe fn vminq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v2f64")] fn vminq_f64_(a: float64x2_t, b: float64x2_t) -> float64x2_t; } @@ -5768,7 +5924,7 @@ #[cfg_attr(test, assert_instr(fminnm))] pub unsafe fn vminnm_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnm.v1f64")] fn vminnm_f64_(a: float64x1_t, b: float64x1_t) -> float64x1_t; } @@ -5781,7 +5937,7 @@ #[cfg_attr(test, assert_instr(fminnm))] pub unsafe fn vminnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnm.v2f64")] fn vminnmq_f64_(a: float64x2_t, b: float64x2_t) -> float64x2_t; } @@ -5794,7 +5950,7 @@ #[cfg_attr(test, assert_instr(fminnmp))] pub unsafe fn vpminnm_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnmp.v2f32")] fn vpminnm_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; } @@ -5807,7 +5963,7 @@ #[cfg_attr(test, assert_instr(fminnmp))] pub unsafe fn vpminnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnmp.v2f64")] fn vpminnmq_f64_(a: float64x2_t, b: float64x2_t) -> float64x2_t; } @@ -5820,7 +5976,7 @@ #[cfg_attr(test, assert_instr(fminnmp))] pub unsafe fn vpminnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnmp.v4f32")] fn vpminnmq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; } @@ -5843,7 +5999,7 @@ #[cfg_attr(test, assert_instr(sqdmull))] pub unsafe fn vqdmulls_s32(a: i32, b: i32) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulls.scalar")] fn vqdmulls_s32_(a: i32, b: i32) -> i64; } @@ -6290,7 +6446,7 @@ #[cfg_attr(test, assert_instr(sqxtn))] pub unsafe fn vqmovnd_s64(a: i64) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.scalar.sqxtn.i32.i64")] fn vqmovnd_s64_(a: i64) -> i32; } @@ -6303,7 +6459,7 @@ #[cfg_attr(test, assert_instr(uqxtn))] pub unsafe fn vqmovnd_u64(a: u64) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.scalar.uqxtn.i32.i64")] fn vqmovnd_u64_(a: u64) -> u32; } @@ -6580,7 +6736,7 @@ #[cfg_attr(test, assert_instr(sqrshl))] pub unsafe fn vqrshls_s32(a: i32, b: i32) -> i32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.i32")] fn vqrshls_s32_(a: i32, b: i32) -> i32; } @@ -6593,7 +6749,7 @@ #[cfg_attr(test, assert_instr(sqrshl))] pub unsafe fn vqrshld_s64(a: i64, b: i64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.i64")] fn vqrshld_s64_(a: i64, b: i64) -> i64; } @@ -6626,7 +6782,7 @@ #[cfg_attr(test, assert_instr(uqrshl))] pub unsafe fn vqrshls_u32(a: u32, b: i32) -> u32 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.i32")] fn vqrshls_u32_(a: u32, b: i32) -> u32; } @@ -6639,7 +6795,7 @@ #[cfg_attr(test, assert_instr(uqrshl))] pub unsafe fn vqrshld_u64(a: u64, b: i64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.i64")] fn vqrshld_u64_(a: u64, b: i64) -> u64; } @@ -6861,7 +7017,7 @@ #[cfg_attr(test, assert_instr(sqshl))] pub unsafe fn vqshld_s64(a: i64, b: i64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.i64")] fn vqshld_s64_(a: i64, b: i64) -> i64; } @@ -6901,7 +7057,7 @@ #[cfg_attr(test, assert_instr(uqshl))] pub unsafe fn vqshld_u64(a: u64, b: i64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.i64")] fn vqshld_u64_(a: u64, b: i64) -> u64; } @@ -7023,7 +7179,7 @@ pub unsafe fn vqshrnd_n_s64(a: i64) -> i32 { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrn.i32")] fn vqshrnd_n_s64_(a: i64, n: i32) -> i32; } @@ -7088,7 +7244,7 @@ pub unsafe fn vqshrnd_n_u64(a: u64) -> u32 { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshrn.i32")] fn vqshrnd_n_u64_(a: u64, n: i32) -> u32; } @@ -7243,7 +7399,7 @@ #[cfg_attr(test, assert_instr(frsqrte))] pub unsafe fn vrsqrte_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frsqrte.v1f64")] fn vrsqrte_f64_(a: float64x1_t) -> float64x1_t; } @@ -7256,7 +7412,7 @@ #[cfg_attr(test, assert_instr(frsqrte))] pub unsafe fn vrsqrteq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frsqrte.v2f64")] fn vrsqrteq_f64_(a: float64x2_t) -> float64x2_t; } @@ -7269,7 +7425,7 @@ #[cfg_attr(test, assert_instr(frecpe))] pub unsafe fn vrecpe_f64(a: float64x1_t) -> float64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frecpe.v1f64")] fn vrecpe_f64_(a: float64x1_t) -> float64x1_t; } @@ -7282,7 +7438,7 @@ #[cfg_attr(test, assert_instr(frecpe))] pub unsafe fn vrecpeq_f64(a: float64x2_t) -> float64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frecpe.v2f64")] fn vrecpeq_f64_(a: float64x2_t) -> float64x2_t; } @@ -7292,7 +7448,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_s64_p64(a: poly64x1_t) -> int64x1_t { transmute(a) } @@ -7300,7 +7456,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_u64_p64(a: poly64x1_t) -> uint64x1_t { transmute(a) } @@ -7308,7 +7464,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_s64(a: int64x1_t) -> poly64x1_t { transmute(a) } @@ -7316,7 +7472,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_u64(a: uint64x1_t) -> poly64x1_t { transmute(a) } @@ -7324,7 +7480,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_s64_p64(a: poly64x2_t) -> int64x2_t { transmute(a) } @@ -7332,7 +7488,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_u64_p64(a: poly64x2_t) -> uint64x2_t { transmute(a) } @@ -7340,7 +7496,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_s64(a: int64x2_t) -> poly64x2_t { transmute(a) } @@ -7348,7 +7504,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_u64(a: uint64x2_t) -> poly64x2_t { transmute(a) } @@ -7356,7 +7512,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_s32_p64(a: poly64x1_t) -> int32x2_t { transmute(a) } @@ -7364,7 +7520,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_u32_p64(a: poly64x1_t) -> uint32x2_t { transmute(a) } @@ -7372,7 +7528,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_s32_p64(a: poly64x2_t) -> int32x4_t { transmute(a) } @@ -7380,7 +7536,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_u32_p64(a: poly64x2_t) -> uint32x4_t { transmute(a) } @@ -7388,7 +7544,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_s32(a: int32x2_t) -> poly64x1_t { transmute(a) } @@ -7396,7 +7552,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_u32(a: uint32x2_t) -> poly64x1_t { transmute(a) } @@ -7404,7 +7560,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_s32(a: int32x4_t) -> poly64x2_t { transmute(a) } @@ -7412,7 +7568,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_u32(a: uint32x4_t) -> poly64x2_t { transmute(a) } @@ -7420,7 +7576,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_s16_p64(a: poly64x1_t) -> int16x4_t { transmute(a) } @@ -7428,7 +7584,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_u16_p64(a: poly64x1_t) -> uint16x4_t { transmute(a) } @@ -7436,7 +7592,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p16_p64(a: poly64x1_t) -> poly16x4_t { transmute(a) } @@ -7444,7 +7600,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_s16_p64(a: poly64x2_t) -> int16x8_t { transmute(a) } @@ -7452,7 +7608,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_u16_p64(a: poly64x2_t) -> uint16x8_t { transmute(a) } @@ -7460,7 +7616,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p16_p64(a: poly64x2_t) -> poly16x8_t { transmute(a) } @@ -7468,7 +7624,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_p16(a: poly16x4_t) -> poly64x1_t { transmute(a) } @@ -7476,7 +7632,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_s16(a: int16x4_t) -> poly64x1_t { transmute(a) } @@ -7484,7 +7640,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_u16(a: uint16x4_t) -> poly64x1_t { transmute(a) } @@ -7492,7 +7648,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_p16(a: poly16x8_t) -> poly64x2_t { transmute(a) } @@ -7500,7 +7656,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_s16(a: int16x8_t) -> poly64x2_t { transmute(a) } @@ -7508,7 +7664,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_u16(a: uint16x8_t) -> poly64x2_t { transmute(a) } @@ -7516,7 +7672,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_s8_p64(a: poly64x1_t) -> int8x8_t { transmute(a) } @@ -7524,7 +7680,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_u8_p64(a: poly64x1_t) -> uint8x8_t { transmute(a) } @@ -7532,7 +7688,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p8_p64(a: poly64x1_t) -> poly8x8_t { transmute(a) } @@ -7540,7 +7696,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_s8_p64(a: poly64x2_t) -> int8x16_t { transmute(a) } @@ -7548,7 +7704,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_u8_p64(a: poly64x2_t) -> uint8x16_t { transmute(a) } @@ -7556,7 +7712,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p8_p64(a: poly64x2_t) -> poly8x16_t { transmute(a) } @@ -7564,7 +7720,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_p8(a: poly8x8_t) -> poly64x1_t { transmute(a) } @@ -7572,7 +7728,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_s8(a: int8x8_t) -> poly64x1_t { transmute(a) } @@ -7580,7 +7736,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_u8(a: uint8x8_t) -> poly64x1_t { transmute(a) } @@ -7588,7 +7744,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_p8(a: poly8x16_t) -> poly64x2_t { transmute(a) } @@ -7596,7 +7752,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_s8(a: int8x16_t) -> poly64x2_t { transmute(a) } @@ -7604,7 +7760,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_u8(a: uint8x16_t) -> poly64x2_t { transmute(a) } @@ -7612,7 +7768,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_s8_f64(a: float64x1_t) -> int8x8_t { transmute(a) } @@ -7620,7 +7776,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_s16_f64(a: float64x1_t) -> int16x4_t { transmute(a) } @@ -7628,7 +7784,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_s32_f64(a: float64x1_t) -> int32x2_t { transmute(a) } @@ -7636,7 +7792,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_s64_f64(a: float64x1_t) -> int64x1_t { transmute(a) } @@ -7644,7 +7800,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_s8_f64(a: float64x2_t) -> int8x16_t { transmute(a) } @@ -7652,7 +7808,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_s16_f64(a: float64x2_t) -> int16x8_t { transmute(a) } @@ -7660,7 +7816,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_s32_f64(a: float64x2_t) -> int32x4_t { transmute(a) } @@ -7668,7 +7824,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_s64_f64(a: float64x2_t) -> int64x2_t { transmute(a) } @@ -7676,7 +7832,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_u8_f64(a: float64x1_t) -> uint8x8_t { transmute(a) } @@ -7684,7 +7840,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_u16_f64(a: float64x1_t) -> uint16x4_t { transmute(a) } @@ -7692,7 +7848,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_u32_f64(a: float64x1_t) -> uint32x2_t { transmute(a) } @@ -7700,7 +7856,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_u64_f64(a: float64x1_t) -> uint64x1_t { transmute(a) } @@ -7708,7 +7864,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_u8_f64(a: float64x2_t) -> uint8x16_t { transmute(a) } @@ -7716,7 +7872,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_u16_f64(a: float64x2_t) -> uint16x8_t { transmute(a) } @@ -7724,7 +7880,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_u32_f64(a: float64x2_t) -> uint32x4_t { transmute(a) } @@ -7732,7 +7888,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_u64_f64(a: float64x2_t) -> uint64x2_t { transmute(a) } @@ -7740,7 +7896,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p8_f64(a: float64x1_t) -> poly8x8_t { transmute(a) } @@ -7748,7 +7904,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p16_f64(a: float64x1_t) -> poly16x4_t { transmute(a) } @@ -7756,7 +7912,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_f32(a: float32x2_t) -> poly64x1_t { transmute(a) } @@ -7764,7 +7920,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_p64_f64(a: float64x1_t) -> poly64x1_t { transmute(a) } @@ -7772,7 +7928,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p8_f64(a: float64x2_t) -> poly8x16_t { transmute(a) } @@ -7780,7 +7936,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p16_f64(a: float64x2_t) -> poly16x8_t { transmute(a) } @@ -7788,7 +7944,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_f32(a: float32x4_t) -> poly64x2_t { transmute(a) } @@ -7796,7 +7952,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_p64_f64(a: float64x2_t) -> poly64x2_t { transmute(a) } @@ -7804,7 +7960,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_s8(a: int8x8_t) -> float64x1_t { transmute(a) } @@ -7812,7 +7968,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_s16(a: int16x4_t) -> float64x1_t { transmute(a) } @@ -7820,7 +7976,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_s32(a: int32x2_t) -> float64x1_t { transmute(a) } @@ -7828,7 +7984,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_s64(a: int64x1_t) -> float64x1_t { transmute(a) } @@ -7836,7 +7992,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_s8(a: int8x16_t) -> float64x2_t { transmute(a) } @@ -7844,7 +8000,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_s16(a: int16x8_t) -> float64x2_t { transmute(a) } @@ -7852,7 +8008,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_s32(a: int32x4_t) -> float64x2_t { transmute(a) } @@ -7860,7 +8016,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_s64(a: int64x2_t) -> float64x2_t { transmute(a) } @@ -7868,7 +8024,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_p8(a: poly8x8_t) -> float64x1_t { transmute(a) } @@ -7876,7 +8032,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_u16(a: uint16x4_t) -> float64x1_t { transmute(a) } @@ -7884,7 +8040,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_u32(a: uint32x2_t) -> float64x1_t { transmute(a) } @@ -7892,7 +8048,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_u64(a: uint64x1_t) -> float64x1_t { transmute(a) } @@ -7900,7 +8056,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_p8(a: poly8x16_t) -> float64x2_t { transmute(a) } @@ -7908,7 +8064,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_u16(a: uint16x8_t) -> float64x2_t { transmute(a) } @@ -7916,7 +8072,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_u32(a: uint32x4_t) -> float64x2_t { transmute(a) } @@ -7924,7 +8080,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_u64(a: uint64x2_t) -> float64x2_t { transmute(a) } @@ -7932,7 +8088,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_u8(a: uint8x8_t) -> float64x1_t { transmute(a) } @@ -7940,7 +8096,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_p16(a: poly16x4_t) -> float64x1_t { transmute(a) } @@ -7948,7 +8104,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_p64(a: poly64x1_t) -> float64x1_t { transmute(a) } @@ -7956,7 +8112,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f32_p64(a: poly64x1_t) -> float32x2_t { transmute(a) } @@ -7964,7 +8120,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_u8(a: uint8x16_t) -> float64x2_t { transmute(a) } @@ -7972,7 +8128,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_p16(a: poly16x8_t) -> float64x2_t { transmute(a) } @@ -7980,7 +8136,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_p64(a: poly64x2_t) -> float64x2_t { transmute(a) } @@ -7988,7 +8144,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f32_p64(a: poly64x2_t) -> float32x4_t { transmute(a) } @@ -7996,7 +8152,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f64_f32(a: float32x2_t) -> float64x1_t { transmute(a) } @@ -8004,7 +8160,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpret_f32_f64(a: float64x1_t) -> float32x2_t { transmute(a) } @@ -8012,7 +8168,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f64_f32(a: float32x4_t) -> float64x2_t { transmute(a) } @@ -8020,7 +8176,7 @@ /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vreinterpretq_f32_f64(a: float64x2_t) -> float32x4_t { transmute(a) } @@ -8031,7 +8187,7 @@ #[cfg_attr(test, assert_instr(srshl))] pub unsafe fn vrshld_s64(a: i64, b: i64) -> i64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.i64")] fn vrshld_s64_(a: i64, b: i64) -> i64; } @@ -8044,7 +8200,7 @@ #[cfg_attr(test, assert_instr(urshl))] pub unsafe fn vrshld_u64(a: u64, b: i64) -> u64 { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.i64")] fn vrshld_u64_(a: u64, b: i64) -> u64; } @@ -9446,7 +9602,7 @@ #[cfg_attr(test, assert_instr(sqabs))] pub unsafe fn vqabs_s64(a: int64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v1i64")] fn vqabs_s64_(a: int64x1_t) -> int64x1_t; } @@ -9459,7 +9615,7 @@ #[cfg_attr(test, assert_instr(sqabs))] pub unsafe fn vqabsq_s64(a: int64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v2i64")] fn vqabsq_s64_(a: int64x2_t) -> int64x2_t; } @@ -12857,6 +13013,108 @@ assert_eq!(r, e); } + #[simd_test(enable = "neon")] + unsafe fn test_vld1_f64_x2() { + let a: [f64; 3] = [0., 1., 2.]; + let e: [f64; 2] = [1., 2.]; + let r: [f64; 2] = transmute(vld1_f64_x2(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_f64_x2() { + let a: [f64; 5] = [0., 1., 2., 3., 4.]; + let e: [f64x2; 2] = [f64x2::new(1., 2.), f64x2::new(3., 4.)]; + let r: [f64x2; 2] = transmute(vld1q_f64_x2(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_f64_x3() { + let a: [f64; 4] = [0., 1., 2., 3.]; + let e: [f64; 3] = [1., 2., 3.]; + let r: [f64; 3] = transmute(vld1_f64_x3(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_f64_x3() { + let a: [f64; 7] = [0., 1., 2., 3., 4., 5., 6.]; + let e: [f64x2; 3] = [f64x2::new(1., 2.), f64x2::new(3., 4.), f64x2::new(5., 6.)]; + let r: [f64x2; 3] = transmute(vld1q_f64_x3(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_f64_x4() { + let a: [f64; 5] = [0., 1., 2., 3., 4.]; + let e: [f64; 4] = [1., 2., 3., 4.]; + let r: [f64; 4] = transmute(vld1_f64_x4(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_f64_x4() { + let a: [f64; 9] = [0., 1., 2., 3., 4., 5., 6., 7., 8.]; + let e: [f64x2; 4] = [f64x2::new(1., 2.), f64x2::new(3., 4.), f64x2::new(5., 6.), f64x2::new(7., 8.)]; + let r: [f64x2; 4] = transmute(vld1q_f64_x4(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vst1_f64_x2() { + let a: [f64; 3] = [0., 1., 2.]; + let e: [f64; 2] = [1., 2.]; + let mut r: [f64; 2] = [0f64; 2]; + vst1_f64_x2(r.as_mut_ptr(), vld1_f64_x2(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vst1q_f64_x2() { + let a: [f64; 5] = [0., 1., 2., 3., 4.]; + let e: [f64; 4] = [1., 2., 3., 4.]; + let mut r: [f64; 4] = [0f64; 4]; + vst1q_f64_x2(r.as_mut_ptr(), vld1q_f64_x2(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vst1_f64_x3() { + let a: [f64; 4] = [0., 1., 2., 3.]; + let e: [f64; 3] = [1., 2., 3.]; + let mut r: [f64; 3] = [0f64; 3]; + vst1_f64_x3(r.as_mut_ptr(), vld1_f64_x3(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vst1q_f64_x3() { + let a: [f64; 7] = [0., 1., 2., 3., 4., 5., 6.]; + let e: [f64; 6] = [1., 2., 3., 4., 5., 6.]; + let mut r: [f64; 6] = [0f64; 6]; + vst1q_f64_x3(r.as_mut_ptr(), vld1q_f64_x3(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vst1_f64_x4() { + let a: [f64; 5] = [0., 1., 2., 3., 4.]; + let e: [f64; 4] = [1., 2., 3., 4.]; + let mut r: [f64; 4] = [0f64; 4]; + vst1_f64_x4(r.as_mut_ptr(), vld1_f64_x4(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vst1q_f64_x4() { + let a: [f64; 9] = [0., 1., 2., 3., 4., 5., 6., 7., 8.]; + let e: [f64; 8] = [1., 2., 3., 4., 5., 6., 7., 8.]; + let mut r: [f64; 8] = [0f64; 8]; + vst1q_f64_x4(r.as_mut_ptr(), vld1q_f64_x4(a[1..].as_ptr())); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] unsafe fn test_vmul_f64() { let a: f64 = 1.0; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs 2021-11-29 19:27:28.000000000 +0000 @@ -12,8 +12,8 @@ use crate::{ core_arch::{arm_shared::*, simd::*, simd_llvm::*}, hint::unreachable_unchecked, - mem::{size_of, transmute, zeroed}, - ptr::copy_nonoverlapping, + mem::{transmute, zeroed}, + ptr::{read_unaligned, write_unaligned}, }; #[cfg(test)] use stdarch_test::assert_instr; @@ -25,48 +25,38 @@ pub struct float64x2_t(f64, f64); } -/// ARM-specific type containing two `int8x16_t` vectors. +/// ARM-specific type containing two `float64x1_t` vectors. #[derive(Copy, Clone)] -pub struct int8x16x2_t(pub int8x16_t, pub int8x16_t); -/// ARM-specific type containing three `int8x16_t` vectors. +pub struct float64x1x2_t(pub float64x1_t, pub float64x1_t); +/// ARM-specific type containing three `float64x1_t` vectors. #[derive(Copy, Clone)] -pub struct int8x16x3_t(pub int8x16_t, pub int8x16_t, pub int8x16_t); -/// ARM-specific type containing four `int8x16_t` vectors. +pub struct float64x1x3_t(pub float64x1_t, pub float64x1_t, pub float64x1_t); +/// ARM-specific type containing four `float64x1_t` vectors. #[derive(Copy, Clone)] -pub struct int8x16x4_t(pub int8x16_t, pub int8x16_t, pub int8x16_t, pub int8x16_t); - -/// ARM-specific type containing two `uint8x16_t` vectors. -#[derive(Copy, Clone)] -pub struct uint8x16x2_t(pub uint8x16_t, pub uint8x16_t); -/// ARM-specific type containing three `uint8x16_t` vectors. -#[derive(Copy, Clone)] -pub struct uint8x16x3_t(pub uint8x16_t, pub uint8x16_t, pub uint8x16_t); -/// ARM-specific type containing four `uint8x16_t` vectors. -#[derive(Copy, Clone)] -pub struct uint8x16x4_t( - pub uint8x16_t, - pub uint8x16_t, - pub uint8x16_t, - pub uint8x16_t, +pub struct float64x1x4_t( + pub float64x1_t, + pub float64x1_t, + pub float64x1_t, + pub float64x1_t, ); -/// ARM-specific type containing two `poly8x16_t` vectors. +/// ARM-specific type containing two `float64x2_t` vectors. #[derive(Copy, Clone)] -pub struct poly8x16x2_t(pub poly8x16_t, pub poly8x16_t); -/// ARM-specific type containing three `poly8x16_t` vectors. +pub struct float64x2x2_t(pub float64x2_t, pub float64x2_t); +/// ARM-specific type containing three `float64x2_t` vectors. #[derive(Copy, Clone)] -pub struct poly8x16x3_t(pub poly8x16_t, pub poly8x16_t, pub poly8x16_t); -/// ARM-specific type containing four `poly8x16_t` vectors. +pub struct float64x2x3_t(pub float64x2_t, pub float64x2_t, pub float64x2_t); +/// ARM-specific type containing four `float64x2_t` vectors. #[derive(Copy, Clone)] -pub struct poly8x16x4_t( - pub poly8x16_t, - pub poly8x16_t, - pub poly8x16_t, - pub poly8x16_t, +pub struct float64x2x4_t( + pub float64x2_t, + pub float64x2_t, + pub float64x2_t, + pub float64x2_t, ); #[allow(improper_ctypes)] -extern "C" { +extern "unadjusted" { // absolute value #[link_name = "llvm.aarch64.neon.abs.i64"] fn vabsd_s64_(a: i64) -> i64; @@ -474,16 +464,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_s8(ptr: *const i8) -> int8x8_t { - transmute(i8x8::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -491,24 +472,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_s8(ptr: *const i8) -> int8x16_t { - transmute(i8x16::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - *ptr.offset(8), - *ptr.offset(9), - *ptr.offset(10), - *ptr.offset(11), - *ptr.offset(12), - *ptr.offset(13), - *ptr.offset(14), - *ptr.offset(15), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -516,12 +480,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_s16(ptr: *const i16) -> int16x4_t { - transmute(i16x4::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -529,16 +488,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_s16(ptr: *const i16) -> int16x8_t { - transmute(i16x8::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -546,7 +496,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_s32(ptr: *const i32) -> int32x2_t { - transmute(i32x2::new(*ptr, *ptr.offset(1))) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -554,12 +504,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_s32(ptr: *const i32) -> int32x4_t { - transmute(i32x4::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -567,7 +512,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_s64(ptr: *const i64) -> int64x1_t { - transmute(i64x1::new(*ptr)) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -575,7 +520,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_s64(ptr: *const i64) -> int64x2_t { - transmute(i64x2::new(*ptr, *ptr.offset(1))) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -583,16 +528,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_u8(ptr: *const u8) -> uint8x8_t { - transmute(u8x8::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -600,24 +536,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_u8(ptr: *const u8) -> uint8x16_t { - transmute(u8x16::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - *ptr.offset(8), - *ptr.offset(9), - *ptr.offset(10), - *ptr.offset(11), - *ptr.offset(12), - *ptr.offset(13), - *ptr.offset(14), - *ptr.offset(15), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -625,12 +544,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_u16(ptr: *const u16) -> uint16x4_t { - transmute(u16x4::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -638,16 +552,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_u16(ptr: *const u16) -> uint16x8_t { - transmute(u16x8::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -655,7 +560,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_u32(ptr: *const u32) -> uint32x2_t { - transmute(u32x2::new(*ptr, *ptr.offset(1))) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -663,12 +568,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_u32(ptr: *const u32) -> uint32x4_t { - transmute(u32x4::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -676,7 +576,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_u64(ptr: *const u64) -> uint64x1_t { - transmute(u64x1::new(*ptr)) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -684,7 +584,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_u64(ptr: *const u64) -> uint64x2_t { - transmute(u64x2::new(*ptr, *ptr.offset(1))) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -692,16 +592,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_p8(ptr: *const p8) -> poly8x8_t { - transmute(u8x8::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -709,24 +600,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_p8(ptr: *const p8) -> poly8x16_t { - transmute(u8x16::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - *ptr.offset(8), - *ptr.offset(9), - *ptr.offset(10), - *ptr.offset(11), - *ptr.offset(12), - *ptr.offset(13), - *ptr.offset(14), - *ptr.offset(15), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -734,12 +608,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_p16(ptr: *const p16) -> poly16x4_t { - transmute(u16x4::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -747,16 +616,23 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_p16(ptr: *const p16) -> poly16x8_t { - transmute(u16x8::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - *ptr.offset(4), - *ptr.offset(5), - *ptr.offset(6), - *ptr.offset(7), - )) + read_unaligned(ptr.cast()) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_p64(ptr: *const p64) -> poly64x1_t { + read_unaligned(ptr.cast()) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_p64(ptr: *const p64) -> poly64x2_t { + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -764,7 +640,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_f32(ptr: *const f32) -> float32x2_t { - transmute(f32x2::new(*ptr, *ptr.offset(1))) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -772,12 +648,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_f32(ptr: *const f32) -> float32x4_t { - transmute(f32x4::new( - *ptr, - *ptr.offset(1), - *ptr.offset(2), - *ptr.offset(3), - )) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -785,7 +656,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1_f64(ptr: *const f64) -> float64x1_t { - transmute(f64x1::new(*ptr)) + read_unaligned(ptr.cast()) } /// Load multiple single-element structures to one, two, three, or four registers. @@ -793,7 +664,44 @@ #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ldr))] pub unsafe fn vld1q_f64(ptr: *const f64) -> float64x2_t { - transmute(f64x2::new(*ptr, *ptr.offset(1))) + read_unaligned(ptr.cast()) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_dup_f64(ptr: *const f64) -> float64x1_t { + vld1_f64(ptr) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_dup_f64(ptr: *const f64) -> float64x2_t { + let x = vld1q_lane_f64::<0>(ptr, transmute(f64x2::splat(0.))); + simd_shuffle2!(x, x, [0, 0]) +} + +/// Load one single-element structure to one lane of one register. +#[inline] +#[target_feature(enable = "neon")] +#[rustc_legacy_const_generics(2)] +#[cfg_attr(test, assert_instr(ldr, LANE = 0))] +pub unsafe fn vld1_lane_f64(ptr: *const f64, src: float64x1_t) -> float64x1_t { + static_assert!(LANE : i32 where LANE == 0); + simd_insert(src, LANE as u32, *ptr) +} + +/// Load one single-element structure to one lane of one register. +#[inline] +#[target_feature(enable = "neon")] +#[rustc_legacy_const_generics(2)] +#[cfg_attr(test, assert_instr(ldr, LANE = 1))] +pub unsafe fn vld1q_lane_f64(ptr: *const f64, src: float64x2_t) -> float64x2_t { + static_assert_imm1!(LANE); + simd_insert(src, LANE as u32, *ptr) } /// Store multiple single-element structures from one, two, three, or four registers. @@ -802,11 +710,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_s8(ptr: *mut i8, a: int8x8_t) { - copy_nonoverlapping( - &a as *const int8x8_t as *const i8, - ptr as *mut i8, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -815,11 +719,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_s8(ptr: *mut i8, a: int8x16_t) { - copy_nonoverlapping( - &a as *const int8x16_t as *const i8, - ptr as *mut i8, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -828,11 +728,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_s16(ptr: *mut i16, a: int16x4_t) { - copy_nonoverlapping( - &a as *const int16x4_t as *const i16, - ptr as *mut i16, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -841,11 +737,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_s16(ptr: *mut i16, a: int16x8_t) { - copy_nonoverlapping( - &a as *const int16x8_t as *const i16, - ptr as *mut i16, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -854,11 +746,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_s32(ptr: *mut i32, a: int32x2_t) { - copy_nonoverlapping( - &a as *const int32x2_t as *const i32, - ptr as *mut i32, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -867,11 +755,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_s32(ptr: *mut i32, a: int32x4_t) { - copy_nonoverlapping( - &a as *const int32x4_t as *const i32, - ptr as *mut i32, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -880,11 +764,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_s64(ptr: *mut i64, a: int64x1_t) { - copy_nonoverlapping( - &a as *const int64x1_t as *const i64, - ptr as *mut i64, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -893,11 +773,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_s64(ptr: *mut i64, a: int64x2_t) { - copy_nonoverlapping( - &a as *const int64x2_t as *const i64, - ptr as *mut i64, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -906,11 +782,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_u8(ptr: *mut u8, a: uint8x8_t) { - copy_nonoverlapping( - &a as *const uint8x8_t as *const u8, - ptr as *mut u8, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -919,11 +791,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_u8(ptr: *mut u8, a: uint8x16_t) { - copy_nonoverlapping( - &a as *const uint8x16_t as *const u8, - ptr as *mut u8, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -932,11 +800,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_u16(ptr: *mut u16, a: uint16x4_t) { - copy_nonoverlapping( - &a as *const uint16x4_t as *const u16, - ptr as *mut u16, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -945,11 +809,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_u16(ptr: *mut u16, a: uint16x8_t) { - copy_nonoverlapping( - &a as *const uint16x8_t as *const u16, - ptr as *mut u16, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -958,11 +818,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_u32(ptr: *mut u32, a: uint32x2_t) { - copy_nonoverlapping( - &a as *const uint32x2_t as *const u32, - ptr as *mut u32, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -971,11 +827,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_u32(ptr: *mut u32, a: uint32x4_t) { - copy_nonoverlapping( - &a as *const uint32x4_t as *const u32, - ptr as *mut u32, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -984,11 +836,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_u64(ptr: *mut u64, a: uint64x1_t) { - copy_nonoverlapping( - &a as *const uint64x1_t as *const u64, - ptr as *mut u64, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -997,11 +845,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_u64(ptr: *mut u64, a: uint64x2_t) { - copy_nonoverlapping( - &a as *const uint64x2_t as *const u64, - ptr as *mut u64, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -1010,11 +854,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_p8(ptr: *mut p8, a: poly8x8_t) { - copy_nonoverlapping( - &a as *const poly8x8_t as *const p8, - ptr as *mut p8, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -1023,11 +863,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_p8(ptr: *mut p8, a: poly8x16_t) { - copy_nonoverlapping( - &a as *const poly8x16_t as *const p8, - ptr as *mut p8, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -1036,11 +872,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_p16(ptr: *mut p16, a: poly16x4_t) { - copy_nonoverlapping( - &a as *const poly16x4_t as *const p16, - ptr as *mut p16, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Store multiple single-element structures from one, two, three, or four registers. @@ -1049,11 +881,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_p16(ptr: *mut p16, a: poly16x8_t) { - copy_nonoverlapping( - &a as *const poly16x8_t as *const p16, - ptr as *mut p16, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } // Store multiple single-element structures from one, two, three, or four registers. @@ -1062,11 +890,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_p64(ptr: *mut p64, a: poly64x1_t) { - copy_nonoverlapping( - &a as *const poly64x1_t as *const p64, - ptr as *mut p64, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } // Store multiple single-element structures from one, two, three, or four registers. @@ -1075,11 +899,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_p64(ptr: *mut p64, a: poly64x2_t) { - copy_nonoverlapping( - &a as *const poly64x2_t as *const p64, - ptr as *mut p64, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } // Store multiple single-element structures from one, two, three, or four registers. @@ -1088,11 +908,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_f32(ptr: *mut f32, a: float32x2_t) { - copy_nonoverlapping( - &a as *const float32x2_t as *const f32, - ptr as *mut f32, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } // Store multiple single-element structures from one, two, three, or four registers. @@ -1101,11 +917,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_f32(ptr: *mut f32, a: float32x4_t) { - copy_nonoverlapping( - &a as *const float32x4_t as *const f32, - ptr as *mut f32, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } // Store multiple single-element structures from one, two, three, or four registers. @@ -1114,11 +926,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1_f64(ptr: *mut f64, a: float64x1_t) { - copy_nonoverlapping( - &a as *const float64x1_t as *const f64, - ptr as *mut f64, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } // Store multiple single-element structures from one, two, three, or four registers. @@ -1127,11 +935,7 @@ #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] pub unsafe fn vst1q_f64(ptr: *mut f64, a: float64x2_t) { - copy_nonoverlapping( - &a as *const float64x2_t as *const f64, - ptr as *mut f64, - size_of::(), - ) + write_unaligned(ptr.cast(), a); } /// Absolute Value (wrapping). @@ -1905,7 +1709,7 @@ /// Extract vector from pair of vectors #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str, N = 0))] +#[cfg_attr(test, assert_instr(nop, N = 0))] #[rustc_legacy_const_generics(2)] pub unsafe fn vext_p64(a: poly64x1_t, _b: poly64x1_t) -> poly64x1_t { if N != 0 { @@ -1917,7 +1721,7 @@ /// Extract vector from pair of vectors #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(str, N = 0))] +#[cfg_attr(test, assert_instr(nop, N = 0))] #[rustc_legacy_const_generics(2)] pub unsafe fn vext_f64(a: float64x1_t, _b: float64x1_t) -> float64x1_t { if N != 0 { @@ -2016,7 +1820,7 @@ /// Duplicate vector element to vector or scalar #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vdup_n_f64(value: f64) -> float64x1_t { float64x1_t(value) } @@ -2048,7 +1852,7 @@ /// Duplicate vector element to vector or scalar #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vmov_n_f64(value: f64) -> float64x1_t { vdup_n_f64(value) } @@ -2080,7 +1884,7 @@ /// Duplicate vector element to vector or scalar #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(ldr))] +#[cfg_attr(test, assert_instr(ext))] pub unsafe fn vget_high_p64(a: poly64x2_t) -> poly64x1_t { transmute(u64x1::new(simd_extract(a, 1))) } @@ -2088,7 +1892,7 @@ /// Duplicate vector element to vector or scalar #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_f64(a: float64x2_t) -> float64x1_t { float64x1_t(simd_extract(a, 0)) } @@ -2096,7 +1900,7 @@ /// Duplicate vector element to vector or scalar #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_p64(a: poly64x2_t) -> poly64x1_t { transmute(u64x1::new(simd_extract(a, 0))) } @@ -4950,6 +4754,56 @@ } #[simd_test(enable = "neon")] + unsafe fn test_vld1_f64() { + let a: [f64; 2] = [0., 1.]; + let e = f64x1::new(1.); + let r: f64x1 = transmute(vld1_f64(a[1..].as_ptr())); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_f64() { + let a: [f64; 3] = [0., 1., 2.]; + let e = f64x2::new(1., 2.); + let r: f64x2 = transmute(vld1q_f64(a[1..].as_ptr())); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_f64() { + let a: [f64; 2] = [1., 42.]; + let e = f64x1::new(42.); + let r: f64x1 = transmute(vld1_dup_f64(a[1..].as_ptr())); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_f64() { + let elem: f64 = 42.; + let e = f64x2::new(42., 42.); + let r: f64x2 = transmute(vld1q_dup_f64(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_f64() { + let a = f64x1::new(0.); + let elem: f64 = 42.; + let e = f64x1::new(42.); + let r: f64x1 = transmute(vld1_lane_f64::<0>(&elem, transmute(a))); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_f64() { + let a = f64x2::new(0., 1.); + let elem: f64 = 42.; + let e = f64x2::new(0., 42.); + let r: f64x2 = transmute(vld1q_lane_f64::<1>(&elem, transmute(a))); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] unsafe fn test_vst1_p64() { let mut vals = [0_u64; 2]; let a = u64x1::new(1); diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs 2021-11-29 19:27:28.000000000 +0000 @@ -1,7 +1,7 @@ #[cfg(test)] use stdarch_test::assert_instr; -extern "C" { +extern "unadjusted" { #[link_name = "llvm.prefetch"] fn prefetch(p: *const i8, rw: i32, loc: i32, ty: i32); } diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/tme.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/tme.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/tme.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/aarch64/tme.rs 2021-11-29 19:27:28.000000000 +0000 @@ -17,7 +17,7 @@ #[cfg(test)] use stdarch_test::assert_instr; -extern "C" { +extern "unadjusted" { #[link_name = "llvm.aarch64.tstart"] fn aarch64_tstart() -> u64; #[link_name = "llvm.aarch64.tcommit"] diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/dsp.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/dsp.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/dsp.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/dsp.rs 2021-11-29 19:27:28.000000000 +0000 @@ -32,7 +32,7 @@ pub struct uint16x2_t(u16, u16); } -extern "C" { +extern "unadjusted" { #[link_name = "llvm.arm.smulbb"] fn arm_smulbb(a: i32, b: i32) -> i32; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/ex.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/ex.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/ex.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/ex.rs 2021-11-29 19:27:28.000000000 +0000 @@ -11,7 +11,7 @@ doc ))] pub unsafe fn __clrex() { - extern "C" { + extern "unadjusted" { #[link_name = "llvm.arm.clrex"] fn clrex(); } @@ -27,7 +27,7 @@ doc ))] pub unsafe fn __ldrexb(p: *const u8) -> u8 { - extern "C" { + extern "unadjusted" { #[link_name = "llvm.arm.ldrex.p0i8"] fn ldrex8(p: *const u8) -> u32; } @@ -43,7 +43,7 @@ doc ))] pub unsafe fn __ldrexh(p: *const u16) -> u16 { - extern "C" { + extern "unadjusted" { #[link_name = "llvm.arm.ldrex.p0i16"] fn ldrex16(p: *const u16) -> u32; } @@ -60,7 +60,7 @@ doc ))] pub unsafe fn __ldrex(p: *const u32) -> u32 { - extern "C" { + extern "unadjusted" { #[link_name = "llvm.arm.ldrex.p0i32"] fn ldrex32(p: *const u32) -> u32; } @@ -78,7 +78,7 @@ doc ))] pub unsafe fn __strexb(value: u32, addr: *mut u8) -> u32 { - extern "C" { + extern "unadjusted" { #[link_name = "llvm.arm.strex.p0i8"] fn strex8(value: u32, addr: *mut u8) -> u32; } @@ -97,7 +97,7 @@ doc ))] pub unsafe fn __strexh(value: u16, addr: *mut u16) -> u32 { - extern "C" { + extern "unadjusted" { #[link_name = "llvm.arm.strex.p0i16"] fn strex16(value: u32, addr: *mut u16) -> u32; } @@ -116,7 +116,7 @@ doc ))] pub unsafe fn __strex(value: u32, addr: *mut u32) -> u32 { - extern "C" { + extern "unadjusted" { #[link_name = "llvm.arm.strex.p0i32"] fn strex32(value: u32, addr: *mut u32) -> u32; } diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/mod.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/mod.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/mod.rs 2021-11-29 19:27:28.000000000 +0000 @@ -107,7 +107,7 @@ dbg(IMM4); } -extern "C" { +extern "unadjusted" { #[link_name = "llvm.arm.dbg"] fn dbg(_: i32); } diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/neon.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/neon.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/neon.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/neon.rs 2021-11-29 19:27:28.000000000 +0000 @@ -12,7 +12,7 @@ pub(crate) type p16 = u16; #[allow(improper_ctypes)] -extern "C" { +extern "unadjusted" { #[link_name = "llvm.arm.neon.vbsl.v8i8"] fn vbsl_s8_(a: int8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t; #[link_name = "llvm.arm.neon.vbsl.v16i8"] @@ -290,6 +290,22 @@ /// Load multiple single-element structures to one, two, three, or four registers. #[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(test, assert_instr(vldr))] +pub unsafe fn vld1_p64(ptr: *const p64) -> poly64x1_t { + transmute(vld1_v1i64(ptr as *const i8, align_of::() as i32)) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(test, assert_instr("vld1.64"))] +pub unsafe fn vld1q_p64(ptr: *const p64) -> poly64x2_t { + transmute(vld1q_v2i64(ptr as *const i8, align_of::() as i32)) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] #[target_feature(enable = "neon,v7")] #[cfg_attr(test, assert_instr(vldr))] pub unsafe fn vld1_f32(ptr: *const f32) -> float32x2_t { @@ -307,7 +323,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.8"))] pub unsafe fn vst1_s8(ptr: *mut i8, a: int8x8_t) { vst1_v8i8(ptr as *const i8, a, align_of::() as i32) } @@ -315,7 +331,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.8"))] pub unsafe fn vst1q_s8(ptr: *mut i8, a: int8x16_t) { vst1q_v16i8(ptr as *const i8, a, align_of::() as i32) } @@ -323,7 +339,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.16"))] pub unsafe fn vst1_s16(ptr: *mut i16, a: int16x4_t) { vst1_v4i16(ptr as *const i8, a, align_of::() as i32) } @@ -331,7 +347,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.16"))] pub unsafe fn vst1q_s16(ptr: *mut i16, a: int16x8_t) { vst1q_v8i16(ptr as *const i8, a, align_of::() as i32) } @@ -339,7 +355,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.32"))] pub unsafe fn vst1_s32(ptr: *mut i32, a: int32x2_t) { vst1_v2i32(ptr as *const i8, a, align_of::() as i32) } @@ -347,7 +363,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.32"))] pub unsafe fn vst1q_s32(ptr: *mut i32, a: int32x4_t) { vst1q_v4i32(ptr as *const i8, a, align_of::() as i32) } @@ -355,7 +371,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.64"))] pub unsafe fn vst1_s64(ptr: *mut i64, a: int64x1_t) { vst1_v1i64(ptr as *const i8, a, align_of::() as i32) } @@ -363,7 +379,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.64"))] pub unsafe fn vst1q_s64(ptr: *mut i64, a: int64x2_t) { vst1q_v2i64(ptr as *const i8, a, align_of::() as i32) } @@ -371,7 +387,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.8"))] pub unsafe fn vst1_u8(ptr: *mut u8, a: uint8x8_t) { vst1_v8i8(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -379,7 +395,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.8"))] pub unsafe fn vst1q_u8(ptr: *mut u8, a: uint8x16_t) { vst1q_v16i8(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -387,7 +403,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.16"))] pub unsafe fn vst1_u16(ptr: *mut u16, a: uint16x4_t) { vst1_v4i16(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -395,7 +411,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.16"))] pub unsafe fn vst1q_u16(ptr: *mut u16, a: uint16x8_t) { vst1q_v8i16(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -403,7 +419,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.32"))] pub unsafe fn vst1_u32(ptr: *mut u32, a: uint32x2_t) { vst1_v2i32(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -411,7 +427,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.32"))] pub unsafe fn vst1q_u32(ptr: *mut u32, a: uint32x4_t) { vst1q_v4i32(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -419,7 +435,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.64"))] pub unsafe fn vst1_u64(ptr: *mut u64, a: uint64x1_t) { vst1_v1i64(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -427,7 +443,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.64"))] pub unsafe fn vst1q_u64(ptr: *mut u64, a: uint64x2_t) { vst1q_v2i64(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -435,7 +451,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.8"))] pub unsafe fn vst1_p8(ptr: *mut p8, a: poly8x8_t) { vst1_v8i8(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -443,7 +459,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.8"))] pub unsafe fn vst1q_p8(ptr: *mut p8, a: poly8x16_t) { vst1q_v16i8(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -451,7 +467,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.16"))] pub unsafe fn vst1_p16(ptr: *mut p16, a: poly16x4_t) { vst1_v4i16(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -459,7 +475,7 @@ /// Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.16"))] pub unsafe fn vst1q_p16(ptr: *mut p16, a: poly16x8_t) { vst1q_v8i16(ptr as *const i8, transmute(a), align_of::() as i32) } @@ -467,7 +483,7 @@ // Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.32"))] pub unsafe fn vst1_f32(ptr: *mut f32, a: float32x2_t) { vst1_v2f32(ptr as *const i8, a, align_of::() as i32) } @@ -475,7 +491,7 @@ // Store multiple single-element structures from one, two, three, or four registers. #[inline] #[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(str))] +#[cfg_attr(test, assert_instr("vst1.32"))] pub unsafe fn vst1q_f32(ptr: *mut f32, a: float32x4_t) { vst1q_v4f32(ptr as *const i8, a, align_of::() as i32) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/simd32.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/simd32.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/simd32.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm/simd32.rs 2021-11-29 19:27:28.000000000 +0000 @@ -80,7 +80,7 @@ }; } -extern "C" { +extern "unadjusted" { #[link_name = "llvm.arm.qadd8"] fn arm_qadd8(a: i32, b: i32) -> i32; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/barrier/mod.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/barrier/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/barrier/mod.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/barrier/mod.rs 2021-11-29 19:27:28.000000000 +0000 @@ -122,7 +122,7 @@ arg.__isb() } -extern "C" { +extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.dmb")] #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.dmb")] fn dmb(_: i32); diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/crc.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/crc.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/crc.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/crc.rs 2021-11-29 19:27:28.000000000 +0000 @@ -1,4 +1,4 @@ -extern "C" { +extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crc32b")] #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.crc32b")] fn crc32b_(crc: u32, data: u32) -> u32; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/crypto.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/crypto.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/crypto.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/crypto.rs 2021-11-29 19:27:28.000000000 +0000 @@ -1,7 +1,7 @@ use crate::core_arch::arm_shared::{uint32x4_t, uint8x16_t}; #[allow(improper_ctypes)] -extern "C" { +extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.aese")] #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.aese")] fn vaeseq_u8_(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/hints.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/hints.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/hints.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/hints.rs 2021-11-29 19:27:28.000000000 +0000 @@ -80,7 +80,7 @@ asm!("nop", options(nomem, nostack, preserves_flags)); } -extern "C" { +extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.hint")] #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.hint")] fn hint(_: i32); diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs 2021-11-29 19:27:28.000000000 +0000 @@ -497,7 +497,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabd))] pub unsafe fn vabd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sabd.v8i8")] fn vabd_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; @@ -513,7 +513,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabd))] pub unsafe fn vabdq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sabd.v16i8")] fn vabdq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; @@ -529,7 +529,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabd))] pub unsafe fn vabd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sabd.v4i16")] fn vabd_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; @@ -545,7 +545,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabd))] pub unsafe fn vabdq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sabd.v8i16")] fn vabdq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; @@ -561,7 +561,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabd))] pub unsafe fn vabd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sabd.v2i32")] fn vabd_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; @@ -577,7 +577,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabd))] pub unsafe fn vabdq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sabd.v4i32")] fn vabdq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; @@ -593,7 +593,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabd))] pub unsafe fn vabd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabdu.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uabd.v8i8")] fn vabd_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; @@ -609,7 +609,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabd))] pub unsafe fn vabdq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabdu.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uabd.v16i8")] fn vabdq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; @@ -625,7 +625,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabd))] pub unsafe fn vabd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabdu.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uabd.v4i16")] fn vabd_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; @@ -641,7 +641,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabd))] pub unsafe fn vabdq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabdu.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uabd.v8i16")] fn vabdq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; @@ -657,7 +657,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabd))] pub unsafe fn vabd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabdu.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uabd.v2i32")] fn vabd_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; @@ -673,7 +673,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabd))] pub unsafe fn vabdq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabdu.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uabd.v4i32")] fn vabdq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; @@ -689,7 +689,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fabd))] pub unsafe fn vabd_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v2f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fabd.v2f32")] fn vabd_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; @@ -705,7 +705,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fabd))] pub unsafe fn vabdq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v4f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fabd.v4f32")] fn vabdq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; @@ -1692,7 +1692,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cls))] pub unsafe fn vcls_s8(a: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcls.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.cls.v8i8")] fn vcls_s8_(a: int8x8_t) -> int8x8_t; @@ -1708,7 +1708,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cls))] pub unsafe fn vclsq_s8(a: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcls.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.cls.v16i8")] fn vclsq_s8_(a: int8x16_t) -> int8x16_t; @@ -1724,7 +1724,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cls))] pub unsafe fn vcls_s16(a: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcls.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.cls.v4i16")] fn vcls_s16_(a: int16x4_t) -> int16x4_t; @@ -1740,7 +1740,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cls))] pub unsafe fn vclsq_s16(a: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcls.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.cls.v8i16")] fn vclsq_s16_(a: int16x8_t) -> int16x8_t; @@ -1756,7 +1756,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cls))] pub unsafe fn vcls_s32(a: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcls.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.cls.v2i32")] fn vcls_s32_(a: int32x2_t) -> int32x2_t; @@ -1772,7 +1772,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cls))] pub unsafe fn vclsq_s32(a: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcls.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.cls.v4i32")] fn vclsq_s32_(a: int32x4_t) -> int32x4_t; @@ -1908,7 +1908,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(facgt))] pub unsafe fn vcagt_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vacgt.v2i32.v2f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.facgt.v2i32.v2f32")] fn vcagt_f32_(a: float32x2_t, b: float32x2_t) -> uint32x2_t; @@ -1924,7 +1924,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(facgt))] pub unsafe fn vcagtq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vacgt.v4i32.v4f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.facgt.v4i32.v4f32")] fn vcagtq_f32_(a: float32x4_t, b: float32x4_t) -> uint32x4_t; @@ -1940,7 +1940,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(facge))] pub unsafe fn vcage_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vacge.v2i32.v2f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.facge.v2i32.v2f32")] fn vcage_f32_(a: float32x2_t, b: float32x2_t) -> uint32x2_t; @@ -1956,7 +1956,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(facge))] pub unsafe fn vcageq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vacge.v4i32.v4f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.facge.v4i32.v4f32")] fn vcageq_f32_(a: float32x4_t, b: float32x4_t) -> uint32x4_t; @@ -2087,7 +2087,7 @@ /// Insert vector element from another vector element #[inline] #[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] pub unsafe fn vcreate_p64(a: u64) -> poly64x1_t { @@ -2153,7 +2153,7 @@ pub unsafe fn vcvt_n_f32_s32(a: int32x2_t) -> float32x2_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcvtfxs2fp.v2f32.v2i32")] fn vcvt_n_f32_s32_(a: int32x2_t, n: i32) -> float32x2_t; } @@ -2169,7 +2169,7 @@ pub unsafe fn vcvt_n_f32_s32(a: int32x2_t) -> float32x2_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxs2fp.v2f32.v2i32")] fn vcvt_n_f32_s32_(a: int32x2_t, n: i32) -> float32x2_t; } @@ -2185,7 +2185,7 @@ pub unsafe fn vcvtq_n_f32_s32(a: int32x4_t) -> float32x4_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcvtfxs2fp.v4f32.v4i32")] fn vcvtq_n_f32_s32_(a: int32x4_t, n: i32) -> float32x4_t; } @@ -2201,7 +2201,7 @@ pub unsafe fn vcvtq_n_f32_s32(a: int32x4_t) -> float32x4_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxs2fp.v4f32.v4i32")] fn vcvtq_n_f32_s32_(a: int32x4_t, n: i32) -> float32x4_t; } @@ -2217,7 +2217,7 @@ pub unsafe fn vcvt_n_f32_u32(a: uint32x2_t) -> float32x2_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcvtfxu2fp.v2f32.v2i32")] fn vcvt_n_f32_u32_(a: uint32x2_t, n: i32) -> float32x2_t; } @@ -2233,7 +2233,7 @@ pub unsafe fn vcvt_n_f32_u32(a: uint32x2_t) -> float32x2_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxu2fp.v2f32.v2i32")] fn vcvt_n_f32_u32_(a: uint32x2_t, n: i32) -> float32x2_t; } @@ -2249,7 +2249,7 @@ pub unsafe fn vcvtq_n_f32_u32(a: uint32x4_t) -> float32x4_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcvtfxu2fp.v4f32.v4i32")] fn vcvtq_n_f32_u32_(a: uint32x4_t, n: i32) -> float32x4_t; } @@ -2265,7 +2265,7 @@ pub unsafe fn vcvtq_n_f32_u32(a: uint32x4_t) -> float32x4_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfxu2fp.v4f32.v4i32")] fn vcvtq_n_f32_u32_(a: uint32x4_t, n: i32) -> float32x4_t; } @@ -2281,7 +2281,7 @@ pub unsafe fn vcvt_n_s32_f32(a: float32x2_t) -> int32x2_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcvtfp2fxs.v2i32.v2f32")] fn vcvt_n_s32_f32_(a: float32x2_t, n: i32) -> int32x2_t; } @@ -2297,7 +2297,7 @@ pub unsafe fn vcvt_n_s32_f32(a: float32x2_t) -> int32x2_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxs.v2i32.v2f32")] fn vcvt_n_s32_f32_(a: float32x2_t, n: i32) -> int32x2_t; } @@ -2313,7 +2313,7 @@ pub unsafe fn vcvtq_n_s32_f32(a: float32x4_t) -> int32x4_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcvtfp2fxs.v4i32.v4f32")] fn vcvtq_n_s32_f32_(a: float32x4_t, n: i32) -> int32x4_t; } @@ -2329,7 +2329,7 @@ pub unsafe fn vcvtq_n_s32_f32(a: float32x4_t) -> int32x4_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxs.v4i32.v4f32")] fn vcvtq_n_s32_f32_(a: float32x4_t, n: i32) -> int32x4_t; } @@ -2345,7 +2345,7 @@ pub unsafe fn vcvt_n_u32_f32(a: float32x2_t) -> uint32x2_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcvtfp2fxu.v2i32.v2f32")] fn vcvt_n_u32_f32_(a: float32x2_t, n: i32) -> uint32x2_t; } @@ -2361,7 +2361,7 @@ pub unsafe fn vcvt_n_u32_f32(a: float32x2_t) -> uint32x2_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxu.v2i32.v2f32")] fn vcvt_n_u32_f32_(a: float32x2_t, n: i32) -> uint32x2_t; } @@ -2377,7 +2377,7 @@ pub unsafe fn vcvtq_n_u32_f32(a: float32x4_t) -> uint32x4_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vcvtfp2fxu.v4i32.v4f32")] fn vcvtq_n_u32_f32_(a: float32x4_t, n: i32) -> uint32x4_t; } @@ -2393,7 +2393,7 @@ pub unsafe fn vcvtq_n_u32_f32(a: float32x4_t) -> uint32x4_t { static_assert!(N : i32 where N >= 1 && N <= 32); #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.vcvtfp2fxu.v4i32.v4f32")] fn vcvtq_n_u32_f32_(a: float32x4_t, n: i32) -> uint32x4_t; } @@ -2408,7 +2408,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fcvtzs))] pub unsafe fn vcvt_s32_f32(a: float32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.fptosi.sat.v2i32.v2f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fptosi.sat.v2i32.v2f32")] fn vcvt_s32_f32_(a: float32x2_t) -> int32x2_t; @@ -2424,7 +2424,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fcvtzs))] pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.fptosi.sat.v4i32.v4f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fptosi.sat.v4i32.v4f32")] fn vcvtq_s32_f32_(a: float32x4_t) -> int32x4_t; @@ -2440,7 +2440,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fcvtzu))] pub unsafe fn vcvt_u32_f32(a: float32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.fptoui.sat.v2i32.v2f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fptoui.sat.v2i32.v2f32")] fn vcvt_u32_f32_(a: float32x2_t) -> uint32x2_t; @@ -2456,7 +2456,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fcvtzu))] pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.fptoui.sat.v4i32.v4f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fptoui.sat.v4i32.v4f32")] fn vcvtq_u32_f32_(a: float32x4_t) -> uint32x4_t; @@ -4842,7 +4842,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqneg))] pub unsafe fn vqneg_s8(a: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqneg.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqneg.v8i8")] fn vqneg_s8_(a: int8x8_t) -> int8x8_t; @@ -4858,7 +4858,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqneg))] pub unsafe fn vqnegq_s8(a: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqneg.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqneg.v16i8")] fn vqnegq_s8_(a: int8x16_t) -> int8x16_t; @@ -4874,7 +4874,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqneg))] pub unsafe fn vqneg_s16(a: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqneg.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqneg.v4i16")] fn vqneg_s16_(a: int16x4_t) -> int16x4_t; @@ -4890,7 +4890,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqneg))] pub unsafe fn vqnegq_s16(a: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqneg.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqneg.v8i16")] fn vqnegq_s16_(a: int16x8_t) -> int16x8_t; @@ -4906,7 +4906,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqneg))] pub unsafe fn vqneg_s32(a: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqneg.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqneg.v2i32")] fn vqneg_s32_(a: int32x2_t) -> int32x2_t; @@ -4922,7 +4922,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqneg))] pub unsafe fn vqnegq_s32(a: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqneg.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqneg.v4i32")] fn vqnegq_s32_(a: int32x4_t) -> int32x4_t; @@ -4938,7 +4938,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqsub))] pub unsafe fn vqsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.v8i8")] fn vqsub_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; @@ -4954,7 +4954,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqsub))] pub unsafe fn vqsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.v16i8")] fn vqsubq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; @@ -4970,7 +4970,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqsub))] pub unsafe fn vqsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.v4i16")] fn vqsub_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; @@ -4986,7 +4986,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqsub))] pub unsafe fn vqsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.v8i16")] fn vqsubq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; @@ -5002,7 +5002,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqsub))] pub unsafe fn vqsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.v2i32")] fn vqsub_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; @@ -5018,7 +5018,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqsub))] pub unsafe fn vqsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.v4i32")] fn vqsubq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; @@ -5034,7 +5034,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqsub))] pub unsafe fn vqsub_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v1i64")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.v1i64")] fn vqsub_u64_(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t; @@ -5050,7 +5050,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqsub))] pub unsafe fn vqsubq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v2i64")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqsub.v2i64")] fn vqsubq_u64_(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t; @@ -5066,7 +5066,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqsub))] pub unsafe fn vqsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.v8i8")] fn vqsub_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; @@ -5082,7 +5082,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqsub))] pub unsafe fn vqsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.v16i8")] fn vqsubq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; @@ -5098,7 +5098,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqsub))] pub unsafe fn vqsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.v4i16")] fn vqsub_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; @@ -5114,7 +5114,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqsub))] pub unsafe fn vqsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.v8i16")] fn vqsubq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; @@ -5130,7 +5130,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqsub))] pub unsafe fn vqsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.v2i32")] fn vqsub_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; @@ -5146,7 +5146,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqsub))] pub unsafe fn vqsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.v4i32")] fn vqsubq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; @@ -5162,7 +5162,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqsub))] pub unsafe fn vqsub_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v1i64")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.v1i64")] fn vqsub_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; @@ -5178,7 +5178,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqsub))] pub unsafe fn vqsubq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v2i64")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqsub.v2i64")] fn vqsubq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; @@ -5194,7 +5194,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhadd))] pub unsafe fn vhadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhaddu.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhadd.v8i8")] fn vhadd_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; @@ -5210,7 +5210,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhadd))] pub unsafe fn vhaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhaddu.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhadd.v16i8")] fn vhaddq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; @@ -5226,7 +5226,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhadd))] pub unsafe fn vhadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhaddu.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhadd.v4i16")] fn vhadd_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; @@ -5242,7 +5242,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhadd))] pub unsafe fn vhaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhaddu.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhadd.v8i16")] fn vhaddq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; @@ -5258,7 +5258,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhadd))] pub unsafe fn vhadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhaddu.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhadd.v2i32")] fn vhadd_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; @@ -5274,7 +5274,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhadd))] pub unsafe fn vhaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhaddu.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhadd.v4i32")] fn vhaddq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; @@ -5290,7 +5290,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shadd))] pub unsafe fn vhadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhadds.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shadd.v8i8")] fn vhadd_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; @@ -5306,7 +5306,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shadd))] pub unsafe fn vhaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhadds.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shadd.v16i8")] fn vhaddq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; @@ -5322,7 +5322,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shadd))] pub unsafe fn vhadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhadds.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shadd.v4i16")] fn vhadd_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; @@ -5338,7 +5338,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shadd))] pub unsafe fn vhaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhadds.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shadd.v8i16")] fn vhaddq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; @@ -5354,7 +5354,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shadd))] pub unsafe fn vhadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhadds.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shadd.v2i32")] fn vhadd_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; @@ -5370,7 +5370,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shadd))] pub unsafe fn vhaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhadds.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shadd.v4i32")] fn vhaddq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; @@ -5386,7 +5386,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urhadd))] pub unsafe fn vrhadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhaddu.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urhadd.v8i8")] fn vrhadd_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; @@ -5402,7 +5402,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urhadd))] pub unsafe fn vrhaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhaddu.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urhadd.v16i8")] fn vrhaddq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; @@ -5418,7 +5418,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urhadd))] pub unsafe fn vrhadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhaddu.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urhadd.v4i16")] fn vrhadd_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; @@ -5434,7 +5434,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urhadd))] pub unsafe fn vrhaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhaddu.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urhadd.v8i16")] fn vrhaddq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; @@ -5450,7 +5450,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urhadd))] pub unsafe fn vrhadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhaddu.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urhadd.v2i32")] fn vrhadd_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; @@ -5466,7 +5466,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urhadd))] pub unsafe fn vrhaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhaddu.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urhadd.v4i32")] fn vrhaddq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; @@ -5482,7 +5482,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srhadd))] pub unsafe fn vrhadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhadds.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srhadd.v8i8")] fn vrhadd_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; @@ -5498,7 +5498,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srhadd))] pub unsafe fn vrhaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhadds.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srhadd.v16i8")] fn vrhaddq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; @@ -5514,7 +5514,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srhadd))] pub unsafe fn vrhadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhadds.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srhadd.v4i16")] fn vrhadd_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; @@ -5530,7 +5530,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srhadd))] pub unsafe fn vrhaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhadds.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srhadd.v8i16")] fn vrhaddq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; @@ -5546,7 +5546,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srhadd))] pub unsafe fn vrhadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhadds.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srhadd.v2i32")] fn vrhadd_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; @@ -5562,7 +5562,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srhadd))] pub unsafe fn vrhaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrhadds.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srhadd.v4i32")] fn vrhaddq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; @@ -5578,7 +5578,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frintn))] pub unsafe fn vrndn_f32(a: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrintn.v2f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frintn.v2f32")] fn vrndn_f32_(a: float32x2_t) -> float32x2_t; @@ -5594,7 +5594,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frintn))] pub unsafe fn vrndnq_f32(a: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrintn.v4f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frintn.v4f32")] fn vrndnq_f32_(a: float32x4_t) -> float32x4_t; @@ -5610,7 +5610,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqadd))] pub unsafe fn vqadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.v8i8")] fn vqadd_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; @@ -5626,7 +5626,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqadd))] pub unsafe fn vqaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.v16i8")] fn vqaddq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; @@ -5642,7 +5642,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqadd))] pub unsafe fn vqadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.v4i16")] fn vqadd_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; @@ -5658,7 +5658,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqadd))] pub unsafe fn vqaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.v8i16")] fn vqaddq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; @@ -5674,7 +5674,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqadd))] pub unsafe fn vqadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.v2i32")] fn vqadd_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; @@ -5690,7 +5690,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqadd))] pub unsafe fn vqaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.v4i32")] fn vqaddq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; @@ -5706,7 +5706,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqadd))] pub unsafe fn vqadd_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v1i64")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.v1i64")] fn vqadd_u64_(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t; @@ -5722,7 +5722,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqadd))] pub unsafe fn vqaddq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v2i64")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqadd.v2i64")] fn vqaddq_u64_(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t; @@ -5738,7 +5738,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqadd))] pub unsafe fn vqadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.v8i8")] fn vqadd_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; @@ -5754,7 +5754,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqadd))] pub unsafe fn vqaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v16i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.v16i8")] fn vqaddq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; @@ -5770,7 +5770,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqadd))] pub unsafe fn vqadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.v4i16")] fn vqadd_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; @@ -5786,7 +5786,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqadd))] pub unsafe fn vqaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v8i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.v8i16")] fn vqaddq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; @@ -5802,7 +5802,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqadd))] pub unsafe fn vqadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v2i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.v2i32")] fn vqadd_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; @@ -5818,7 +5818,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqadd))] pub unsafe fn vqaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v4i32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.v4i32")] fn vqaddq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; @@ -5834,7 +5834,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqadd))] pub unsafe fn vqadd_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v1i64")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.v1i64")] fn vqadd_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; @@ -5850,7 +5850,7 @@ #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqadd))] pub unsafe fn vqaddq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { #[allow(improper_ctypes)] - extern "C" { + extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v2i64")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqadd.v2i64")] fn vqaddq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; @@ -5858,5997 +5858,6397 @@ vqaddq_s64_(a, b) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s8_x2(a: *const i8) -> int8x8x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v8i8.p0i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v8i8.p0i8")] + fn vld1_s8_x2_(a: *const i8) -> int8x8x2_t; + } +vld1_s8_x2_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s16_x2(a: *const i16) -> int16x4x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v4i16.p0i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v4i16.p0i16")] + fn vld1_s16_x2_(a: *const i16) -> int16x4x2_t; + } +vld1_s16_x2_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s32_x2(a: *const i32) -> int32x2x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v2i32.p0i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v2i32.p0i32")] + fn vld1_s32_x2_(a: *const i32) -> int32x2x2_t; + } +vld1_s32_x2_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s64_x2(a: *const i64) -> int64x1x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v1i64.p0i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v1i64.p0i64")] + fn vld1_s64_x2_(a: *const i64) -> int64x1x2_t; + } +vld1_s64_x2_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s8_x2(a: *const i8) -> int8x16x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v16i8.p0i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v16i8.p0i8")] + fn vld1q_s8_x2_(a: *const i8) -> int8x16x2_t; + } +vld1q_s8_x2_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s16_x2(a: *const i16) -> int16x8x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v8i16.p0i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v8i16.p0i16")] + fn vld1q_s16_x2_(a: *const i16) -> int16x8x2_t; + } +vld1q_s16_x2_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s32_x2(a: *const i32) -> int32x4x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v4i32.p0i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v4i32.p0i32")] + fn vld1q_s32_x2_(a: *const i32) -> int32x4x2_t; + } +vld1q_s32_x2_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s64_x2(a: *const i64) -> int64x2x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v2i64.p0i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v2i64.p0i64")] + fn vld1q_s64_x2_(a: *const i64) -> int64x2x2_t; + } +vld1q_s64_x2_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s8_x3(a: *const i8) -> int8x8x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v8i8.p0i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v8i8.p0i8")] + fn vld1_s8_x3_(a: *const i8) -> int8x8x3_t; + } +vld1_s8_x3_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s16_x3(a: *const i16) -> int16x4x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v4i16.p0i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v4i16.p0i16")] + fn vld1_s16_x3_(a: *const i16) -> int16x4x3_t; + } +vld1_s16_x3_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s32_x3(a: *const i32) -> int32x2x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v2i32.p0i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v2i32.p0i32")] + fn vld1_s32_x3_(a: *const i32) -> int32x2x3_t; + } +vld1_s32_x3_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s64_x3(a: *const i64) -> int64x1x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v1i64.p0i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v1i64.p0i64")] + fn vld1_s64_x3_(a: *const i64) -> int64x1x3_t; + } +vld1_s64_x3_(a) } -/// Polynomial multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(pmul))] -pub unsafe fn vmul_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s8_x3(a: *const i8) -> int8x16x3_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulp.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.pmul.v8i8")] - fn vmul_p8_(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v16i8.p0i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v16i8.p0i8")] + fn vld1q_s8_x3_(a: *const i8) -> int8x16x3_t; } -vmul_p8_(a, b) +vld1q_s8_x3_(a) } -/// Polynomial multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(pmul))] -pub unsafe fn vmulq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s16_x3(a: *const i16) -> int16x8x3_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulp.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.pmul.v16i8")] - fn vmulq_p8_(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v8i16.p0i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v8i16.p0i16")] + fn vld1q_s16_x3_(a: *const i16) -> int16x8x3_t; } -vmulq_p8_(a, b) +vld1q_s16_x3_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.f32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul))] -pub unsafe fn vmul_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s32_x3(a: *const i32) -> int32x4x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v4i32.p0i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v4i32.p0i32")] + fn vld1q_s32_x3_(a: *const i32) -> int32x4x3_t; + } +vld1q_s32_x3_(a) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.f32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul))] -pub unsafe fn vmulq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { - simd_mul(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s64_x3(a: *const i64) -> int64x2x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v2i64.p0i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v2i64.p0i64")] + fn vld1q_s64_x3_(a: *const i64) -> int64x2x3_t; + } +vld1q_s64_x3_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_n_s16(a: int16x4_t, b: i16) -> int16x4_t { - simd_mul(a, vdup_n_s16(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s8_x4(a: *const i8) -> int8x8x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v8i8.p0i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v8i8.p0i8")] + fn vld1_s8_x4_(a: *const i8) -> int8x8x4_t; + } +vld1_s8_x4_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_n_s16(a: int16x8_t, b: i16) -> int16x8_t { - simd_mul(a, vdupq_n_s16(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s16_x4(a: *const i16) -> int16x4x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v4i16.p0i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v4i16.p0i16")] + fn vld1_s16_x4_(a: *const i16) -> int16x4x4_t; + } +vld1_s16_x4_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_n_s32(a: int32x2_t, b: i32) -> int32x2_t { - simd_mul(a, vdup_n_s32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s32_x4(a: *const i32) -> int32x2x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v2i32.p0i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v2i32.p0i32")] + fn vld1_s32_x4_(a: *const i32) -> int32x2x4_t; + } +vld1_s32_x4_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_n_s32(a: int32x4_t, b: i32) -> int32x4_t { - simd_mul(a, vdupq_n_s32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_s64_x4(a: *const i64) -> int64x1x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v1i64.p0i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v1i64.p0i64")] + fn vld1_s64_x4_(a: *const i64) -> int64x1x4_t; + } +vld1_s64_x4_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_n_u16(a: uint16x4_t, b: u16) -> uint16x4_t { - simd_mul(a, vdup_n_u16(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s8_x4(a: *const i8) -> int8x16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v16i8.p0i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v16i8.p0i8")] + fn vld1q_s8_x4_(a: *const i8) -> int8x16x4_t; + } +vld1q_s8_x4_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_n_u16(a: uint16x8_t, b: u16) -> uint16x8_t { - simd_mul(a, vdupq_n_u16(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s16_x4(a: *const i16) -> int16x8x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v8i16.p0i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v8i16.p0i16")] + fn vld1q_s16_x4_(a: *const i16) -> int16x8x4_t; + } +vld1q_s16_x4_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmul_n_u32(a: uint32x2_t, b: u32) -> uint32x2_t { - simd_mul(a, vdup_n_u32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s32_x4(a: *const i32) -> int32x4x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v4i32.p0i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v4i32.p0i32")] + fn vld1q_s32_x4_(a: *const i32) -> int32x4x4_t; + } +vld1q_s32_x4_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] -pub unsafe fn vmulq_n_u32(a: uint32x4_t, b: u32) -> uint32x4_t { - simd_mul(a, vdupq_n_u32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_s64_x4(a: *const i64) -> int64x2x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v2i64.p0i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v2i64.p0i64")] + fn vld1q_s64_x4_(a: *const i64) -> int64x2x4_t; + } +vld1q_s64_x4_(a) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul))] -pub unsafe fn vmul_n_f32(a: float32x2_t, b: f32) -> float32x2_t { - simd_mul(a, vdup_n_f32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u8_x2(a: *const u8) -> uint8x8x2_t { + transmute(vld1_s8_x2(transmute(a))) } -/// Vector multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul))] -pub unsafe fn vmulq_n_f32(a: float32x4_t, b: f32) -> float32x4_t { - simd_mul(a, vdupq_n_f32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u16_x2(a: *const u16) -> uint16x4x2_t { + transmute(vld1_s16_x2(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_lane_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u32_x2(a: *const u32) -> uint32x2x2_t { + transmute(vld1_s32_x2(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_laneq_s16(a: int16x4_t, b: int16x8_t) -> int16x4_t { - static_assert_imm3!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u64_x2(a: *const u64) -> uint64x1x2_t { + transmute(vld1_s64_x2(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_lane_s16(a: int16x8_t, b: int16x4_t) -> int16x8_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u8_x2(a: *const u8) -> uint8x16x2_t { + transmute(vld1q_s8_x2(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_laneq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - static_assert_imm3!(LANE); - simd_mul(a, simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u16_x2(a: *const u16) -> uint16x8x2_t { + transmute(vld1q_s16_x2(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_lane_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - static_assert_imm1!(LANE); - simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u32_x2(a: *const u32) -> uint32x4x2_t { + transmute(vld1q_s32_x2(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_laneq_s32(a: int32x2_t, b: int32x4_t) -> int32x2_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u64_x2(a: *const u64) -> uint64x2x2_t { + transmute(vld1q_s64_x2(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_lane_s32(a: int32x4_t, b: int32x2_t) -> int32x4_t { - static_assert_imm1!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u8_x3(a: *const u8) -> uint8x8x3_t { + transmute(vld1_s8_x3(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_laneq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u16_x3(a: *const u16) -> uint16x4x3_t { + transmute(vld1_s16_x3(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_lane_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u32_x3(a: *const u32) -> uint32x2x3_t { + transmute(vld1_s32_x3(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_laneq_u16(a: uint16x4_t, b: uint16x8_t) -> uint16x4_t { - static_assert_imm3!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u64_x3(a: *const u64) -> uint64x1x3_t { + transmute(vld1_s64_x3(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_lane_u16(a: uint16x8_t, b: uint16x4_t) -> uint16x8_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u8_x3(a: *const u8) -> uint8x16x3_t { + transmute(vld1q_s8_x3(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_laneq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - static_assert_imm3!(LANE); - simd_mul(a, simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u16_x3(a: *const u16) -> uint16x8x3_t { + transmute(vld1q_s16_x3(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_lane_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - static_assert_imm1!(LANE); - simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u32_x3(a: *const u32) -> uint32x4x3_t { + transmute(vld1q_s32_x3(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_laneq_u32(a: uint32x2_t, b: uint32x4_t) -> uint32x2_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u64_x3(a: *const u64) -> uint64x2x3_t { + transmute(vld1q_s64_x3(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_lane_u32(a: uint32x4_t, b: uint32x2_t) -> uint32x4_t { - static_assert_imm1!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u8_x4(a: *const u8) -> uint8x8x4_t { + transmute(vld1_s8_x4(transmute(a))) } -/// Multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_laneq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u16_x4(a: *const u16) -> uint16x4x4_t { + transmute(vld1_s16_x4(transmute(a))) } -/// Floating-point multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_lane_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { - static_assert_imm1!(LANE); - simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u32_x4(a: *const u32) -> uint32x2x4_t { + transmute(vld1_s32_x4(transmute(a))) } -/// Floating-point multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmul_laneq_f32(a: float32x2_t, b: float32x4_t) -> float32x2_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_u64_x4(a: *const u64) -> uint64x1x4_t { + transmute(vld1_s64_x4(transmute(a))) } -/// Floating-point multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_lane_f32(a: float32x4_t, b: float32x2_t) -> float32x4_t { - static_assert_imm1!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u8_x4(a: *const u8) -> uint8x16x4_t { + transmute(vld1q_s8_x4(transmute(a))) } -/// Floating-point multiply +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmulq_laneq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { - static_assert_imm2!(LANE); - simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u16_x4(a: *const u16) -> uint16x8x4_t { + transmute(vld1q_s16_x4(transmute(a))) } -/// Signed multiply long +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.s8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] -pub unsafe fn vmull_s8(a: int8x8_t, b: int8x8_t) -> int16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulls.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smull.v8i8")] - fn vmull_s8_(a: int8x8_t, b: int8x8_t) -> int16x8_t; - } -vmull_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u32_x4(a: *const u32) -> uint32x4x4_t { + transmute(vld1q_s32_x4(transmute(a))) } -/// Signed multiply long +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.s16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] -pub unsafe fn vmull_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulls.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smull.v4i16")] - fn vmull_s16_(a: int16x4_t, b: int16x4_t) -> int32x4_t; - } -vmull_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_u64_x4(a: *const u64) -> uint64x2x4_t { + transmute(vld1q_s64_x4(transmute(a))) } -/// Signed multiply long +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.s32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] -pub unsafe fn vmull_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulls.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smull.v2i32")] - fn vmull_s32_(a: int32x2_t, b: int32x2_t) -> int64x2_t; - } -vmull_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p8_x2(a: *const p8) -> poly8x8x2_t { + transmute(vld1_s8_x2(transmute(a))) } -/// Unsigned multiply long +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.u8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] -pub unsafe fn vmull_u8(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmullu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umull.v8i8")] - fn vmull_u8_(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t; - } -vmull_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p8_x3(a: *const p8) -> poly8x8x3_t { + transmute(vld1_s8_x3(transmute(a))) } -/// Unsigned multiply long +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.u16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] -pub unsafe fn vmull_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmullu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umull.v4i16")] - fn vmull_u16_(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t; - } -vmull_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p8_x4(a: *const p8) -> poly8x8x4_t { + transmute(vld1_s8_x4(transmute(a))) } -/// Unsigned multiply long +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.u32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] -pub unsafe fn vmull_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmullu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umull.v2i32")] - fn vmull_u32_(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t; - } -vmull_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p8_x2(a: *const p8) -> poly8x16x2_t { + transmute(vld1q_s8_x2(transmute(a))) } -/// Polynomial multiply long +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.p8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(pmull))] -pub unsafe fn vmull_p8(a: poly8x8_t, b: poly8x8_t) -> poly16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmullp.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.pmull.v8i8")] - fn vmull_p8_(a: poly8x8_t, b: poly8x8_t) -> poly16x8_t; - } -vmull_p8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p8_x3(a: *const p8) -> poly8x16x3_t { + transmute(vld1q_s8_x3(transmute(a))) } -/// Vector long multiply with scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] -pub unsafe fn vmullh_n_s16(a: int16x4_t, b: i16) -> int32x4_t { - vmull_s16(a, vdup_n_s16(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p8_x4(a: *const p8) -> poly8x16x4_t { + transmute(vld1q_s8_x4(transmute(a))) } -/// Vector long multiply with scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] -pub unsafe fn vmulls_n_s32(a: int32x2_t, b: i32) -> int64x2_t { - vmull_s32(a, vdup_n_s32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p16_x2(a: *const p16) -> poly16x4x2_t { + transmute(vld1_s16_x2(transmute(a))) } -/// Vector long multiply with scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] -pub unsafe fn vmullh_n_u16(a: uint16x4_t, b: u16) -> uint32x4_t { - vmull_u16(a, vdup_n_u16(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p16_x3(a: *const p16) -> poly16x4x3_t { + transmute(vld1_s16_x3(transmute(a))) } -/// Vector long multiply with scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] -pub unsafe fn vmulls_n_u32(a: uint32x2_t, b: u32) -> uint64x2_t { - vmull_u32(a, vdup_n_u32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p16_x4(a: *const p16) -> poly16x4x4_t { + transmute(vld1_s16_x4(transmute(a))) } -/// Vector long multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmull_lane_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { - static_assert_imm2!(LANE); - vmull_s16(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p16_x2(a: *const p16) -> poly16x8x2_t { + transmute(vld1q_s16_x2(transmute(a))) } -/// Vector long multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmull_laneq_s16(a: int16x4_t, b: int16x8_t) -> int32x4_t { - static_assert_imm3!(LANE); - vmull_s16(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p16_x3(a: *const p16) -> poly16x8x3_t { + transmute(vld1q_s16_x3(transmute(a))) } -/// Vector long multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmull_lane_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { - static_assert_imm1!(LANE); - vmull_s32(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p16_x4(a: *const p16) -> poly16x8x4_t { + transmute(vld1q_s16_x4(transmute(a))) } -/// Vector long multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmull_laneq_s32(a: int32x2_t, b: int32x4_t) -> int64x2_t { - static_assert_imm2!(LANE); - vmull_s32(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p64_x2(a: *const p64) -> poly64x1x2_t { + transmute(vld1_s64_x2(transmute(a))) } -/// Vector long multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmull_lane_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { - static_assert_imm2!(LANE); - vmull_u16(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(ldr))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p64_x3(a: *const p64) -> poly64x1x3_t { + transmute(vld1_s64_x3(transmute(a))) } -/// Vector long multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(ldr))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_p64_x4(a: *const p64) -> poly64x1x4_t { + transmute(vld1_s64_x4(transmute(a))) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(ldr))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p64_x2(a: *const p64) -> poly64x2x2_t { + transmute(vld1q_s64_x2(transmute(a))) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(ldr))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p64_x3(a: *const p64) -> poly64x2x3_t { + transmute(vld1q_s64_x3(transmute(a))) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(ldr))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_p64_x4(a: *const p64) -> poly64x2x4_t { + transmute(vld1q_s64_x4(transmute(a))) +} + +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmull_laneq_u16(a: uint16x4_t, b: uint16x8_t) -> uint32x4_t { - static_assert_imm3!(LANE); - vmull_u16(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_f32_x2(a: *const f32) -> float32x2x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v2f32.p0f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v2f32.p0f32")] + fn vld1_f32_x2_(a: *const f32) -> float32x2x2_t; + } +vld1_f32_x2_(a) } -/// Vector long multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmull_lane_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { - static_assert_imm1!(LANE); - vmull_u32(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_f32_x2(a: *const f32) -> float32x4x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x2.v4f32.p0f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x2.v4f32.p0f32")] + fn vld1q_f32_x2_(a: *const f32) -> float32x4x2_t; + } +vld1q_f32_x2_(a) } -/// Vector long multiply by scalar +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vmull_laneq_u32(a: uint32x2_t, b: uint32x4_t) -> uint64x2_t { - static_assert_imm2!(LANE); - vmull_u32(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_f32_x3(a: *const f32) -> float32x2x3_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v2f32.p0f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v2f32.p0f32")] + fn vld1_f32_x3_(a: *const f32) -> float32x2x3_t; + } +vld1_f32_x3_(a) } -/// Floating-point fused Multiply-Add to accumulator(vector) +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfma))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmla))] -pub unsafe fn vfma_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float32x2_t { +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_f32_x3(a: *const f32) -> float32x4x3_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.fma.v2f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.v2f32")] - fn vfma_f32_(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x3.v4f32.p0f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x3.v4f32.p0f32")] + fn vld1q_f32_x3_(a: *const f32) -> float32x4x3_t; } -vfma_f32_(b, c, a) +vld1q_f32_x3_(a) } -/// Floating-point fused Multiply-Add to accumulator(vector) +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfma))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmla))] -pub unsafe fn vfmaq_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float32x4_t { +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1_f32_x4(a: *const f32) -> float32x2x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.fma.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.v4f32")] - fn vfmaq_f32_(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v2f32.p0f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v2f32.p0f32")] + fn vld1_f32_x4_(a: *const f32) -> float32x2x4_t; } -vfmaq_f32_(b, c, a) +vld1_f32_x4_(a) } -/// Floating-point fused Multiply-Add to accumulator(vector) +/// Load multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfma))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmla))] -pub unsafe fn vfma_n_f32(a: float32x2_t, b: float32x2_t, c: f32) -> float32x2_t { - vfma_f32(a, b, vdup_n_f32(c)) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1))] +pub unsafe fn vld1q_f32_x4(a: *const f32) -> float32x4x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v4f32.p0f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v4f32.p0f32")] + fn vld1q_f32_x4_(a: *const f32) -> float32x4x4_t; + } +vld1q_f32_x4_(a) } -/// Floating-point fused Multiply-Add to accumulator(vector) +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfma))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmla))] -pub unsafe fn vfmaq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t { - vfmaq_f32(a, b, vdupq_n_f32(c)) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s8_x2(a: *mut i8, b: int8x8x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0i8.v8i8")] + fn vst1_s8_x2_(ptr: *mut i8, a: int8x8_t, b: int8x8_t); + } +vst1_s8_x2_(a, b.0, b.1) } -/// Floating-point fused multiply-subtract from accumulator +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfms))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmls))] -pub unsafe fn vfms_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float32x2_t { - let b: float32x2_t = simd_neg(b); - vfma_f32(a, b, c) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s8_x2(a: *mut i8, b: int8x8x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v8i8.p0i8")] + fn vst1_s8_x2_(a: int8x8_t, b: int8x8_t, ptr: *mut i8); + } +vst1_s8_x2_(b.0, b.1, a) } -/// Floating-point fused multiply-subtract from accumulator +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfms))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmls))] -pub unsafe fn vfmsq_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float32x4_t { - let b: float32x4_t = simd_neg(b); - vfmaq_f32(a, b, c) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s16_x2(a: *mut i16, b: int16x4x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0i16.v4i16")] + fn vst1_s16_x2_(ptr: *mut i16, a: int16x4_t, b: int16x4_t); + } +vst1_s16_x2_(a, b.0, b.1) } -/// Floating-point fused Multiply-subtract to accumulator(vector) +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfms))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmls))] -pub unsafe fn vfms_n_f32(a: float32x2_t, b: float32x2_t, c: f32) -> float32x2_t { - vfms_f32(a, b, vdup_n_f32(c)) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s16_x2(a: *mut i16, b: int16x4x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v4i16.p0i16")] + fn vst1_s16_x2_(a: int16x4_t, b: int16x4_t, ptr: *mut i16); + } +vst1_s16_x2_(b.0, b.1, a) } -/// Floating-point fused Multiply-subtract to accumulator(vector) +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfms))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmls))] -pub unsafe fn vfmsq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t { - vfmsq_f32(a, b, vdupq_n_f32(c)) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s32_x2(a: *mut i32, b: int32x2x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0i32.v2i32")] + fn vst1_s32_x2_(ptr: *mut i32, a: int32x2_t, b: int32x2_t); + } +vst1_s32_x2_(a, b.0, b.1) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s32_x2(a: *mut i32, b: int32x2x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v2i32.p0i32")] + fn vst1_s32_x2_(a: int32x2_t, b: int32x2_t, ptr: *mut i32); + } +vst1_s32_x2_(b.0, b.1, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s64_x2(a: *mut i64, b: int64x1x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0i64.v1i64")] + fn vst1_s64_x2_(ptr: *mut i64, a: int64x1_t, b: int64x1_t); + } +vst1_s64_x2_(a, b.0, b.1) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s64_x2(a: *mut i64, b: int64x1x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v1i64.p0i64")] + fn vst1_s64_x2_(a: int64x1_t, b: int64x1_t, ptr: *mut i64); + } +vst1_s64_x2_(b.0, b.1, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s8_x2(a: *mut i8, b: int8x16x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0i8.v16i8")] + fn vst1q_s8_x2_(ptr: *mut i8, a: int8x16_t, b: int8x16_t); + } +vst1q_s8_x2_(a, b.0, b.1) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s8_x2(a: *mut i8, b: int8x16x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v16i8.p0i8")] + fn vst1q_s8_x2_(a: int8x16_t, b: int8x16_t, ptr: *mut i8); + } +vst1q_s8_x2_(b.0, b.1, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s16_x2(a: *mut i16, b: int16x8x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0i16.v8i16")] + fn vst1q_s16_x2_(ptr: *mut i16, a: int16x8_t, b: int16x8_t); + } +vst1q_s16_x2_(a, b.0, b.1) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s16_x2(a: *mut i16, b: int16x8x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v8i16.p0i16")] + fn vst1q_s16_x2_(a: int16x8_t, b: int16x8_t, ptr: *mut i16); + } +vst1q_s16_x2_(b.0, b.1, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s32_x2(a: *mut i32, b: int32x4x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0i32.v4i32")] + fn vst1q_s32_x2_(ptr: *mut i32, a: int32x4_t, b: int32x4_t); + } +vst1q_s32_x2_(a, b.0, b.1) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s32_x2(a: *mut i32, b: int32x4x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v4i32.p0i32")] + fn vst1q_s32_x2_(a: int32x4_t, b: int32x4_t, ptr: *mut i32); + } +vst1q_s32_x2_(b.0, b.1, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s64_x2(a: *mut i64, b: int64x2x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0i64.v2i64")] + fn vst1q_s64_x2_(ptr: *mut i64, a: int64x2_t, b: int64x2_t); + } +vst1q_s64_x2_(a, b.0, b.1) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s64_x2(a: *mut i64, b: int64x2x2_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v2i64.p0i64")] + fn vst1q_s64_x2_(a: int64x2_t, b: int64x2_t, ptr: *mut i64); + } +vst1q_s64_x2_(b.0, b.1, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s8_x3(a: *mut i8, b: int8x8x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0i8.v8i8")] + fn vst1_s8_x3_(ptr: *mut i8, a: int8x8_t, b: int8x8_t, c: int8x8_t); + } +vst1_s8_x3_(a, b.0, b.1, b.2) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i64"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsub_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s8_x3(a: *mut i8, b: int8x8x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v8i8.p0i8")] + fn vst1_s8_x3_(a: int8x8_t, b: int8x8_t, c: int8x8_t, ptr: *mut i8); + } +vst1_s8_x3_(b.0, b.1, b.2, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i64"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsubq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s16_x3(a: *mut i16, b: int16x4x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0i16.v4i16")] + fn vst1_s16_x3_(ptr: *mut i16, a: int16x4_t, b: int16x4_t, c: int16x4_t); + } +vst1_s16_x3_(a, b.0, b.1, b.2) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i64"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsub_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s16_x3(a: *mut i16, b: int16x4x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v4i16.p0i16")] + fn vst1_s16_x3_(a: int16x4_t, b: int16x4_t, c: int16x4_t, ptr: *mut i16); + } +vst1_s16_x3_(b.0, b.1, b.2, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i64"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] -pub unsafe fn vsubq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s32_x3(a: *mut i32, b: int32x2x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0i32.v2i32")] + fn vst1_s32_x3_(ptr: *mut i32, a: int32x2_t, b: int32x2_t, c: int32x2_t); + } +vst1_s32_x3_(a, b.0, b.1, b.2) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.f32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fsub))] -pub unsafe fn vsub_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { - simd_sub(a, b) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s32_x3(a: *mut i32, b: int32x2x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v2i32.p0i32")] + fn vst1_s32_x3_(a: int32x2_t, b: int32x2_t, c: int32x2_t, ptr: *mut i32); + } +vst1_s32_x3_(b.0, b.1, b.2, a) } -/// Subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.f32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fsub))] -pub unsafe fn vsubq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { - simd_sub(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s64_x3(a: *mut i64, b: int64x1x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0i64.v1i64")] + fn vst1_s64_x3_(ptr: *mut i64, a: int64x1_t, b: int64x1_t, c: int64x1_t); + } +vst1_s64_x3_(a, b.0, b.1, b.2) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] -pub unsafe fn vsubhn_s16(a: int16x8_t, b: int16x8_t) -> int8x8_t { - let c: i16x8 = i16x8::new(8, 8, 8, 8, 8, 8, 8, 8); - simd_cast(simd_shr(simd_sub(a, b), transmute(c))) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s64_x3(a: *mut i64, b: int64x1x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v1i64.p0i64")] + fn vst1_s64_x3_(a: int64x1_t, b: int64x1_t, c: int64x1_t, ptr: *mut i64); + } +vst1_s64_x3_(b.0, b.1, b.2, a) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s8_x3(a: *mut i8, b: int8x16x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0i8.v16i8")] + fn vst1q_s8_x3_(ptr: *mut i8, a: int8x16_t, b: int8x16_t, c: int8x16_t); + } +vst1q_s8_x3_(a, b.0, b.1, b.2) +} + +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] -pub unsafe fn vsubhn_s32(a: int32x4_t, b: int32x4_t) -> int16x4_t { - let c: i32x4 = i32x4::new(16, 16, 16, 16); - simd_cast(simd_shr(simd_sub(a, b), transmute(c))) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s8_x3(a: *mut i8, b: int8x16x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v16i8.p0i8")] + fn vst1q_s8_x3_(a: int8x16_t, b: int8x16_t, c: int8x16_t, ptr: *mut i8); + } +vst1q_s8_x3_(b.0, b.1, b.2, a) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] -pub unsafe fn vsubhn_s64(a: int64x2_t, b: int64x2_t) -> int32x2_t { - let c: i64x2 = i64x2::new(32, 32); - simd_cast(simd_shr(simd_sub(a, b), transmute(c))) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s16_x3(a: *mut i16, b: int16x8x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0i16.v8i16")] + fn vst1q_s16_x3_(ptr: *mut i16, a: int16x8_t, b: int16x8_t, c: int16x8_t); + } +vst1q_s16_x3_(a, b.0, b.1, b.2) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] -pub unsafe fn vsubhn_u16(a: uint16x8_t, b: uint16x8_t) -> uint8x8_t { - let c: u16x8 = u16x8::new(8, 8, 8, 8, 8, 8, 8, 8); - simd_cast(simd_shr(simd_sub(a, b), transmute(c))) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s16_x3(a: *mut i16, b: int16x8x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v8i16.p0i16")] + fn vst1q_s16_x3_(a: int16x8_t, b: int16x8_t, c: int16x8_t, ptr: *mut i16); + } +vst1q_s16_x3_(b.0, b.1, b.2, a) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] -pub unsafe fn vsubhn_u32(a: uint32x4_t, b: uint32x4_t) -> uint16x4_t { - let c: u32x4 = u32x4::new(16, 16, 16, 16); - simd_cast(simd_shr(simd_sub(a, b), transmute(c))) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s32_x3(a: *mut i32, b: int32x4x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0i32.v4i32")] + fn vst1q_s32_x3_(ptr: *mut i32, a: int32x4_t, b: int32x4_t, c: int32x4_t); + } +vst1q_s32_x3_(a, b.0, b.1, b.2) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] -pub unsafe fn vsubhn_u64(a: uint64x2_t, b: uint64x2_t) -> uint32x2_t { - let c: u64x2 = u64x2::new(32, 32); - simd_cast(simd_shr(simd_sub(a, b), transmute(c))) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s32_x3(a: *mut i32, b: int32x4x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v4i32.p0i32")] + fn vst1q_s32_x3_(a: int32x4_t, b: int32x4_t, c: int32x4_t, ptr: *mut i32); + } +vst1q_s32_x3_(b.0, b.1, b.2, a) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] -pub unsafe fn vsubhn_high_s16(a: int8x8_t, b: int16x8_t, c: int16x8_t) -> int8x16_t { - let d: int8x8_t = vsubhn_s16(b, c); - simd_shuffle16!(a, d, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s64_x3(a: *mut i64, b: int64x2x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0i64.v2i64")] + fn vst1q_s64_x3_(ptr: *mut i64, a: int64x2_t, b: int64x2_t, c: int64x2_t); + } +vst1q_s64_x3_(a, b.0, b.1, b.2) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] -pub unsafe fn vsubhn_high_s32(a: int16x4_t, b: int32x4_t, c: int32x4_t) -> int16x8_t { - let d: int16x4_t = vsubhn_s32(b, c); - simd_shuffle8!(a, d, [0, 1, 2, 3, 4, 5, 6, 7]) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s64_x3(a: *mut i64, b: int64x2x3_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v2i64.p0i64")] + fn vst1q_s64_x3_(a: int64x2_t, b: int64x2_t, c: int64x2_t, ptr: *mut i64); + } +vst1q_s64_x3_(b.0, b.1, b.2, a) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] -pub unsafe fn vsubhn_high_s64(a: int32x2_t, b: int64x2_t, c: int64x2_t) -> int32x4_t { - let d: int32x2_t = vsubhn_s64(b, c); - simd_shuffle4!(a, d, [0, 1, 2, 3]) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s8_x4(a: *mut i8, b: int8x8x4_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0i8.v8i8")] + fn vst1_s8_x4_(ptr: *mut i8, a: int8x8_t, b: int8x8_t, c: int8x8_t, d: int8x8_t); + } +vst1_s8_x4_(a, b.0, b.1, b.2, b.3) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] -pub unsafe fn vsubhn_high_u16(a: uint8x8_t, b: uint16x8_t, c: uint16x8_t) -> uint8x16_t { - let d: uint8x8_t = vsubhn_u16(b, c); - simd_shuffle16!(a, d, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s8_x4(a: *mut i8, b: int8x8x4_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v8i8.p0i8")] + fn vst1_s8_x4_(a: int8x8_t, b: int8x8_t, c: int8x8_t, d: int8x8_t, ptr: *mut i8); + } +vst1_s8_x4_(b.0, b.1, b.2, b.3, a) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] -pub unsafe fn vsubhn_high_u32(a: uint16x4_t, b: uint32x4_t, c: uint32x4_t) -> uint16x8_t { - let d: uint16x4_t = vsubhn_u32(b, c); - simd_shuffle8!(a, d, [0, 1, 2, 3, 4, 5, 6, 7]) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s16_x4(a: *mut i16, b: int16x4x4_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0i16.v4i16")] + fn vst1_s16_x4_(ptr: *mut i16, a: int16x4_t, b: int16x4_t, c: int16x4_t, d: int16x4_t); + } +vst1_s16_x4_(a, b.0, b.1, b.2, b.3) } -/// Subtract returning high narrow +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] -pub unsafe fn vsubhn_high_u64(a: uint32x2_t, b: uint64x2_t, c: uint64x2_t) -> uint32x4_t { - let d: uint32x2_t = vsubhn_u64(b, c); - simd_shuffle4!(a, d, [0, 1, 2, 3]) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s16_x4(a: *mut i16, b: int16x4x4_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v4i16.p0i16")] + fn vst1_s16_x4_(a: int16x4_t, b: int16x4_t, c: int16x4_t, d: int16x4_t, ptr: *mut i16); + } +vst1_s16_x4_(b.0, b.1, b.2, b.3, a) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] -pub unsafe fn vhsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s32_x4(a: *mut i32, b: int32x2x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v8i8")] - fn vhsub_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0i32.v2i32")] + fn vst1_s32_x4_(ptr: *mut i32, a: int32x2_t, b: int32x2_t, c: int32x2_t, d: int32x2_t); } -vhsub_u8_(a, b) +vst1_s32_x4_(a, b.0, b.1, b.2, b.3) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] -pub unsafe fn vhsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s32_x4(a: *mut i32, b: int32x2x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v16i8")] - fn vhsubq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v2i32.p0i32")] + fn vst1_s32_x4_(a: int32x2_t, b: int32x2_t, c: int32x2_t, d: int32x2_t, ptr: *mut i32); } -vhsubq_u8_(a, b) +vst1_s32_x4_(b.0, b.1, b.2, b.3, a) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] -pub unsafe fn vhsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_s64_x4(a: *mut i64, b: int64x1x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v4i16")] - fn vhsub_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0i64.v1i64")] + fn vst1_s64_x4_(ptr: *mut i64, a: int64x1_t, b: int64x1_t, c: int64x1_t, d: int64x1_t); } -vhsub_u16_(a, b) +vst1_s64_x4_(a, b.0, b.1, b.2, b.3) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] -pub unsafe fn vhsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_s64_x4(a: *mut i64, b: int64x1x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v8i16")] - fn vhsubq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v1i64.p0i64")] + fn vst1_s64_x4_(a: int64x1_t, b: int64x1_t, c: int64x1_t, d: int64x1_t, ptr: *mut i64); } -vhsubq_u16_(a, b) +vst1_s64_x4_(b.0, b.1, b.2, b.3, a) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] -pub unsafe fn vhsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s8_x4(a: *mut i8, b: int8x16x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v2i32")] - fn vhsub_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0i8.v16i8")] + fn vst1q_s8_x4_(ptr: *mut i8, a: int8x16_t, b: int8x16_t, c: int8x16_t, d: int8x16_t); } -vhsub_u32_(a, b) +vst1q_s8_x4_(a, b.0, b.1, b.2, b.3) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] -pub unsafe fn vhsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s8_x4(a: *mut i8, b: int8x16x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v4i32")] - fn vhsubq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v16i8.p0i8")] + fn vst1q_s8_x4_(a: int8x16_t, b: int8x16_t, c: int8x16_t, d: int8x16_t, ptr: *mut i8); } -vhsubq_u32_(a, b) +vst1q_s8_x4_(b.0, b.1, b.2, b.3, a) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] -pub unsafe fn vhsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s16_x4(a: *mut i16, b: int16x8x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v8i8")] - fn vhsub_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0i16.v8i16")] + fn vst1q_s16_x4_(ptr: *mut i16, a: int16x8_t, b: int16x8_t, c: int16x8_t, d: int16x8_t); } -vhsub_s8_(a, b) +vst1q_s16_x4_(a, b.0, b.1, b.2, b.3) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] -pub unsafe fn vhsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s16_x4(a: *mut i16, b: int16x8x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v16i8")] - fn vhsubq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v8i16.p0i16")] + fn vst1q_s16_x4_(a: int16x8_t, b: int16x8_t, c: int16x8_t, d: int16x8_t, ptr: *mut i16); } -vhsubq_s8_(a, b) +vst1q_s16_x4_(b.0, b.1, b.2, b.3, a) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] -pub unsafe fn vhsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s32_x4(a: *mut i32, b: int32x4x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v4i16")] - fn vhsub_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0i32.v4i32")] + fn vst1q_s32_x4_(ptr: *mut i32, a: int32x4_t, b: int32x4_t, c: int32x4_t, d: int32x4_t); } -vhsub_s16_(a, b) +vst1q_s32_x4_(a, b.0, b.1, b.2, b.3) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] -pub unsafe fn vhsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s32_x4(a: *mut i32, b: int32x4x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v8i16")] - fn vhsubq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v4i32.p0i32")] + fn vst1q_s32_x4_(a: int32x4_t, b: int32x4_t, c: int32x4_t, d: int32x4_t, ptr: *mut i32); } -vhsubq_s16_(a, b) +vst1q_s32_x4_(b.0, b.1, b.2, b.3, a) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] -pub unsafe fn vhsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_s64_x4(a: *mut i64, b: int64x2x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v2i32")] - fn vhsub_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0i64.v2i64")] + fn vst1q_s64_x4_(ptr: *mut i64, a: int64x2_t, b: int64x2_t, c: int64x2_t, d: int64x2_t); } -vhsub_s32_(a, b) +vst1q_s64_x4_(a, b.0, b.1, b.2, b.3) } -/// Signed halving subtract +/// Store multiple single-element structures from one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] -pub unsafe fn vhsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_s64_x4(a: *mut i64, b: int64x2x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v4i32")] - fn vhsubq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v2i64.p0i64")] + fn vst1q_s64_x4_(a: int64x2_t, b: int64x2_t, c: int64x2_t, d: int64x2_t, ptr: *mut i64); } -vhsubq_s32_(a, b) +vst1q_s64_x4_(b.0, b.1, b.2, b.3, a) } -/// Signed Subtract Wide +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubw))] -pub unsafe fn vsubw_s8(a: int16x8_t, b: int8x8_t) -> int16x8_t { - simd_sub(a, simd_cast(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u8_x2(a: *mut u8, b: uint8x8x2_t) { + vst1_s8_x2(transmute(a), transmute(b)) } -/// Signed Subtract Wide +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubw))] -pub unsafe fn vsubw_s16(a: int32x4_t, b: int16x4_t) -> int32x4_t { - simd_sub(a, simd_cast(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u16_x2(a: *mut u16, b: uint16x4x2_t) { + vst1_s16_x2(transmute(a), transmute(b)) } -/// Signed Subtract Wide +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubw))] -pub unsafe fn vsubw_s32(a: int64x2_t, b: int32x2_t) -> int64x2_t { - simd_sub(a, simd_cast(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u32_x2(a: *mut u32, b: uint32x2x2_t) { + vst1_s32_x2(transmute(a), transmute(b)) } -/// Unsigned Subtract Wide +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubw))] -pub unsafe fn vsubw_u8(a: uint16x8_t, b: uint8x8_t) -> uint16x8_t { - simd_sub(a, simd_cast(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u64_x2(a: *mut u64, b: uint64x1x2_t) { + vst1_s64_x2(transmute(a), transmute(b)) } -/// Unsigned Subtract Wide +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubw))] -pub unsafe fn vsubw_u16(a: uint32x4_t, b: uint16x4_t) -> uint32x4_t { - simd_sub(a, simd_cast(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u8_x2(a: *mut u8, b: uint8x16x2_t) { + vst1q_s8_x2(transmute(a), transmute(b)) } -/// Unsigned Subtract Wide +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubw))] -pub unsafe fn vsubw_u32(a: uint64x2_t, b: uint32x2_t) -> uint64x2_t { - simd_sub(a, simd_cast(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u16_x2(a: *mut u16, b: uint16x8x2_t) { + vst1q_s16_x2(transmute(a), transmute(b)) } -/// Signed Subtract Long +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubl))] -pub unsafe fn vsubl_s8(a: int8x8_t, b: int8x8_t) -> int16x8_t { - let c: int16x8_t = simd_cast(a); - let d: int16x8_t = simd_cast(b); - simd_sub(c, d) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u32_x2(a: *mut u32, b: uint32x4x2_t) { + vst1q_s32_x2(transmute(a), transmute(b)) } -/// Signed Subtract Long +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubl))] -pub unsafe fn vsubl_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { - let c: int32x4_t = simd_cast(a); - let d: int32x4_t = simd_cast(b); - simd_sub(c, d) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u64_x2(a: *mut u64, b: uint64x2x2_t) { + vst1q_s64_x2(transmute(a), transmute(b)) } -/// Signed Subtract Long +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubl))] -pub unsafe fn vsubl_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { - let c: int64x2_t = simd_cast(a); - let d: int64x2_t = simd_cast(b); - simd_sub(c, d) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u8_x3(a: *mut u8, b: uint8x8x3_t) { + vst1_s8_x3(transmute(a), transmute(b)) } -/// Unsigned Subtract Long +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubl))] -pub unsafe fn vsubl_u8(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t { - let c: uint16x8_t = simd_cast(a); - let d: uint16x8_t = simd_cast(b); - simd_sub(c, d) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u16_x3(a: *mut u16, b: uint16x4x3_t) { + vst1_s16_x3(transmute(a), transmute(b)) } -/// Unsigned Subtract Long +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubl))] -pub unsafe fn vsubl_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { - let c: uint32x4_t = simd_cast(a); - let d: uint32x4_t = simd_cast(b); - simd_sub(c, d) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u32_x3(a: *mut u32, b: uint32x2x3_t) { + vst1_s32_x3(transmute(a), transmute(b)) } -/// Unsigned Subtract Long +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubl))] -pub unsafe fn vsubl_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { - let c: uint64x2_t = simd_cast(a); - let d: uint64x2_t = simd_cast(b); - simd_sub(c, d) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u64_x3(a: *mut u64, b: uint64x1x3_t) { + vst1_s64_x3(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] -pub unsafe fn vmax_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v8i8")] - fn vmax_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; - } -vmax_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u8_x3(a: *mut u8, b: uint8x16x3_t) { + vst1q_s8_x3(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] -pub unsafe fn vmaxq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v16i8")] - fn vmaxq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; - } -vmaxq_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u16_x3(a: *mut u16, b: uint16x8x3_t) { + vst1q_s16_x3(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] -pub unsafe fn vmax_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v4i16")] - fn vmax_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } -vmax_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u32_x3(a: *mut u32, b: uint32x4x3_t) { + vst1q_s32_x3(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] -pub unsafe fn vmaxq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v8i16")] - fn vmaxq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } -vmaxq_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u64_x3(a: *mut u64, b: uint64x2x3_t) { + vst1q_s64_x3(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] -pub unsafe fn vmax_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v2i32")] - fn vmax_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } -vmax_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u8_x4(a: *mut u8, b: uint8x8x4_t) { + vst1_s8_x4(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] -pub unsafe fn vmaxq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v4i32")] - fn vmaxq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } -vmaxq_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u16_x4(a: *mut u16, b: uint16x4x4_t) { + vst1_s16_x4(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] -pub unsafe fn vmax_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v8i8")] - fn vmax_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; - } -vmax_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u32_x4(a: *mut u32, b: uint32x2x4_t) { + vst1_s32_x4(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] -pub unsafe fn vmaxq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v16i8")] - fn vmaxq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; - } -vmaxq_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_u64_x4(a: *mut u64, b: uint64x1x4_t) { + vst1_s64_x4(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] -pub unsafe fn vmax_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v4i16")] - fn vmax_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; - } -vmax_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u8_x4(a: *mut u8, b: uint8x16x4_t) { + vst1q_s8_x4(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] -pub unsafe fn vmaxq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v8i16")] - fn vmaxq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; - } -vmaxq_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u16_x4(a: *mut u16, b: uint16x8x4_t) { + vst1q_s16_x4(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] -pub unsafe fn vmax_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v2i32")] - fn vmax_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; - } -vmax_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u32_x4(a: *mut u32, b: uint32x4x4_t) { + vst1q_s32_x4(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] -pub unsafe fn vmaxq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v4i32")] - fn vmaxq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; - } -vmaxq_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_u64_x4(a: *mut u64, b: uint64x2x4_t) { + vst1q_s64_x4(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] -pub unsafe fn vmax_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v2f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v2f32")] - fn vmax_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; - } -vmax_f32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_p8_x2(a: *mut p8, b: poly8x8x2_t) { + vst1_s8_x2(transmute(a), transmute(b)) } -/// Maximum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] -pub unsafe fn vmaxq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v4f32")] - fn vmaxq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; - } -vmaxq_f32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_p8_x3(a: *mut p8, b: poly8x8x3_t) { + vst1_s8_x3(transmute(a), transmute(b)) } -/// Floating-point Maximun Number (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmaxnm))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmaxnm))] -pub unsafe fn vmaxnm_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxnm.v2f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnm.v2f32")] - fn vmaxnm_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; - } -vmaxnm_f32_(a, b) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_p8_x4(a: *mut p8, b: poly8x8x4_t) { + vst1_s8_x4(transmute(a), transmute(b)) } -/// Floating-point Maximun Number (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmaxnm))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmaxnm))] -pub unsafe fn vmaxnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxnm.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnm.v4f32")] - fn vmaxnmq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; - } -vmaxnmq_f32_(a, b) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_p8_x2(a: *mut p8, b: poly8x16x2_t) { + vst1q_s8_x2(transmute(a), transmute(b)) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] -pub unsafe fn vmin_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v8i8")] - fn vmin_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; - } -vmin_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_p8_x3(a: *mut p8, b: poly8x16x3_t) { + vst1q_s8_x3(transmute(a), transmute(b)) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] -pub unsafe fn vminq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v16i8")] - fn vminq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; - } -vminq_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_p8_x4(a: *mut p8, b: poly8x16x4_t) { + vst1q_s8_x4(transmute(a), transmute(b)) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] -pub unsafe fn vmin_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v4i16")] - fn vmin_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } -vmin_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_p16_x2(a: *mut p16, b: poly16x4x2_t) { + vst1_s16_x2(transmute(a), transmute(b)) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] -pub unsafe fn vminq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v8i16")] - fn vminq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } -vminq_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_p16_x3(a: *mut p16, b: poly16x4x3_t) { + vst1_s16_x3(transmute(a), transmute(b)) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] -pub unsafe fn vmin_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v2i32")] - fn vmin_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } -vmin_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_p16_x4(a: *mut p16, b: poly16x4x4_t) { + vst1_s16_x4(transmute(a), transmute(b)) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] -pub unsafe fn vminq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v4i32")] - fn vminq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } -vminq_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_p16_x2(a: *mut p16, b: poly16x8x2_t) { + vst1q_s16_x2(transmute(a), transmute(b)) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] -pub unsafe fn vmin_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v8i8")] - fn vmin_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; - } -vmin_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_p16_x3(a: *mut p16, b: poly16x8x3_t) { + vst1q_s16_x3(transmute(a), transmute(b)) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] -pub unsafe fn vminq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_p16_x4(a: *mut p16, b: poly16x8x4_t) { + vst1q_s16_x4(transmute(a), transmute(b)) +} + +/// Store multiple single-element structures to one, two, three, or four registers +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_f32_x2(a: *mut f32, b: float32x2x2_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v16i8")] - fn vminq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0f32.v2f32")] + fn vst1_f32_x2_(ptr: *mut f32, a: float32x2_t, b: float32x2_t); } -vminq_u8_(a, b) +vst1_f32_x2_(a, b.0, b.1) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] -pub unsafe fn vmin_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_f32_x2(a: *mut f32, b: float32x2x2_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v4i16")] - fn vmin_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v2f32.p0f32")] + fn vst1_f32_x2_(a: float32x2_t, b: float32x2_t, ptr: *mut f32); } -vmin_u16_(a, b) +vst1_f32_x2_(b.0, b.1, a) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] -pub unsafe fn vminq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_f32_x2(a: *mut f32, b: float32x4x2_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v8i16")] - fn vminq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0f32.v4f32")] + fn vst1q_f32_x2_(ptr: *mut f32, a: float32x4_t, b: float32x4_t); } -vminq_u16_(a, b) +vst1q_f32_x2_(a, b.0, b.1) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] -pub unsafe fn vmin_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_f32_x2(a: *mut f32, b: float32x4x2_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v2i32")] - fn vmin_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x2.v4f32.p0f32")] + fn vst1q_f32_x2_(a: float32x4_t, b: float32x4_t, ptr: *mut f32); } -vmin_u32_(a, b) +vst1q_f32_x2_(b.0, b.1, a) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] -pub unsafe fn vminq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_f32_x3(a: *mut f32, b: float32x2x3_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v4i32")] - fn vminq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0f32.v2f32")] + fn vst1_f32_x3_(ptr: *mut f32, a: float32x2_t, b: float32x2_t, c: float32x2_t); } -vminq_u32_(a, b) +vst1_f32_x3_(a, b.0, b.1, b.2) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] -pub unsafe fn vmin_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_f32_x3(a: *mut f32, b: float32x2x3_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v2f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v2f32")] - fn vmin_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v2f32.p0f32")] + fn vst1_f32_x3_(a: float32x2_t, b: float32x2_t, c: float32x2_t, ptr: *mut f32); } -vmin_f32_(a, b) +vst1_f32_x3_(b.0, b.1, b.2, a) } -/// Minimum (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] -pub unsafe fn vminq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_f32_x3(a: *mut f32, b: float32x4x3_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v4f32")] - fn vminq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0f32.v4f32")] + fn vst1q_f32_x3_(ptr: *mut f32, a: float32x4_t, b: float32x4_t, c: float32x4_t); } -vminq_f32_(a, b) +vst1q_f32_x3_(a, b.0, b.1, b.2) } -/// Floating-point Minimun Number (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vminnm))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fminnm))] -pub unsafe fn vminnm_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_f32_x3(a: *mut f32, b: float32x4x3_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminnm.v2f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnm.v2f32")] - fn vminnm_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x3.v4f32.p0f32")] + fn vst1q_f32_x3_(a: float32x4_t, b: float32x4_t, c: float32x4_t, ptr: *mut f32); } -vminnm_f32_(a, b) +vst1q_f32_x3_(b.0, b.1, b.2, a) } -/// Floating-point Minimun Number (vector) +/// Store multiple single-element structures to one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vminnm))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fminnm))] -pub unsafe fn vminnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1_f32_x4(a: *mut f32, b: float32x2x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminnm.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnm.v4f32")] - fn vminnmq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0f32.v2f32")] + fn vst1_f32_x4_(ptr: *mut f32, a: float32x2_t, b: float32x2_t, c: float32x2_t, d: float32x2_t); } -vminnmq_f32_(a, b) +vst1_f32_x4_(a, b.0, b.1, b.2, b.3) } -/// Signed saturating doubling multiply long +/// Store multiple single-element structures to one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull))] -pub unsafe fn vqdmull_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1_f32_x4(a: *mut f32, b: float32x2x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmull.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmull.v4i32")] - fn vqdmull_s16_(a: int16x4_t, b: int16x4_t) -> int32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v2f32.p0f32")] + fn vst1_f32_x4_(a: float32x2_t, b: float32x2_t, c: float32x2_t, d: float32x2_t, ptr: *mut f32); } -vqdmull_s16_(a, b) +vst1_f32_x4_(b.0, b.1, b.2, b.3, a) } -/// Signed saturating doubling multiply long +/// Store multiple single-element structures to one, two, three, or four registers #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull))] -pub unsafe fn vqdmull_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vst1))] +pub unsafe fn vst1q_f32_x4(a: *mut f32, b: float32x4x4_t) { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmull.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmull.v2i64")] - fn vqdmull_s32_(a: int32x2_t, b: int32x2_t) -> int64x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x4.p0f32.v4f32")] + fn vst1q_f32_x4_(ptr: *mut f32, a: float32x4_t, b: float32x4_t, c: float32x4_t, d: float32x4_t); } -vqdmull_s32_(a, b) +vst1q_f32_x4_(a, b.0, b.1, b.2, b.3) } -/// Vector saturating doubling long multiply with scalar +/// Store multiple single-element structures to one, two, three, or four registers #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull))] -pub unsafe fn vqdmull_n_s16(a: int16x4_t, b: i16) -> int32x4_t { - vqdmull_s16(a, vdup_n_s16(b)) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(st1))] +pub unsafe fn vst1q_f32_x4(a: *mut f32, b: float32x4x4_t) { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.st1x4.v4f32.p0f32")] + fn vst1q_f32_x4_(a: float32x4_t, b: float32x4_t, c: float32x4_t, d: float32x4_t, ptr: *mut f32); + } +vst1q_f32_x4_(b.0, b.1, b.2, b.3, a) } -/// Vector saturating doubling long multiply with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull))] -pub unsafe fn vqdmull_n_s32(a: int32x2_t, b: i32) -> int64x2_t { - vqdmull_s32(a, vdup_n_s32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + simd_mul(a, b) } -/// Vector saturating doubling long multiply by scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vqdmull_lane_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { - static_assert_imm2!(N); - let b: int16x4_t = simd_shuffle4!(b, b, [N as u32, N as u32, N as u32, N as u32]); - vqdmull_s16(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + simd_mul(a, b) } -/// Vector saturating doubling long multiply by scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull, N = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull, N = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vqdmull_lane_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { - static_assert_imm1!(N); - let b: int32x2_t = simd_shuffle2!(b, b, [N as u32, N as u32]); - vqdmull_s32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + simd_mul(a, b) } -/// Signed saturating doubling multiply-add long +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal))] -pub unsafe fn vqdmlal_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { - vqaddq_s32(a, vqdmull_s16(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + simd_mul(a, b) } -/// Signed saturating doubling multiply-add long +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal))] -pub unsafe fn vqdmlal_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { - vqaddq_s64(a, vqdmull_s32(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + simd_mul(a, b) } -/// Vector widening saturating doubling multiply accumulate with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal))] -pub unsafe fn vqdmlal_n_s16(a: int32x4_t, b: int16x4_t, c: i16) -> int32x4_t { - vqaddq_s32(a, vqdmull_n_s16(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + simd_mul(a, b) } -/// Vector widening saturating doubling multiply accumulate with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal))] -pub unsafe fn vqdmlal_n_s32(a: int64x2_t, b: int32x2_t, c: i32) -> int64x2_t { - vqaddq_s64(a, vqdmull_n_s32(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + simd_mul(a, b) } -/// Vector widening saturating doubling multiply accumulate with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal, N = 2))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqdmlal_lane_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { - static_assert_imm2!(N); - vqaddq_s32(a, vqdmull_lane_s16::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { + simd_mul(a, b) } -/// Vector widening saturating doubling multiply accumulate with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal, N = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal, N = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqdmlal_lane_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { - static_assert_imm1!(N); - vqaddq_s64(a, vqdmull_lane_s32::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + simd_mul(a, b) } -/// Signed saturating doubling multiply-subtract long +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl))] -pub unsafe fn vqdmlsl_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { - vqsubq_s32(a, vqdmull_s16(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + simd_mul(a, b) } -/// Signed saturating doubling multiply-subtract long +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl))] -pub unsafe fn vqdmlsl_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { - vqsubq_s64(a, vqdmull_s32(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + simd_mul(a, b) } -/// Vector widening saturating doubling multiply subtract with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl))] -pub unsafe fn vqdmlsl_n_s16(a: int32x4_t, b: int16x4_t, c: i16) -> int32x4_t { - vqsubq_s32(a, vqdmull_n_s16(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.i32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + simd_mul(a, b) } -/// Vector widening saturating doubling multiply subtract with scalar +/// Polynomial multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl))] -pub unsafe fn vqdmlsl_n_s32(a: int64x2_t, b: int32x2_t, c: i32) -> int64x2_t { - vqsubq_s64(a, vqdmull_n_s32(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(pmul))] +pub unsafe fn vmul_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulp.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.pmul.v8i8")] + fn vmul_p8_(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t; + } +vmul_p8_(a, b) } -/// Vector widening saturating doubling multiply subtract with scalar +/// Polynomial multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl, N = 2))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqdmlsl_lane_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { - static_assert_imm2!(N); - vqsubq_s32(a, vqdmull_lane_s16::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(pmul))] +pub unsafe fn vmulq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulp.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.pmul.v16i8")] + fn vmulq_p8_(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t; + } +vmulq_p8_(a, b) } -/// Vector widening saturating doubling multiply subtract with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl, N = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl, N = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqdmlsl_lane_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { - static_assert_imm1!(N); - vqsubq_s64(a, vqdmull_lane_s32::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.f32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul))] +pub unsafe fn vmul_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + simd_mul(a, b) } -/// Signed saturating doubling multiply returning high half +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] -pub unsafe fn vqdmulh_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmulh.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulh.v4i16")] - fn vqdmulh_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } -vqdmulh_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmul.f32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul))] +pub unsafe fn vmulq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + simd_mul(a, b) } -/// Signed saturating doubling multiply returning high half +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] -pub unsafe fn vqdmulhq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmulh.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulh.v8i16")] - fn vqdmulhq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } -vqdmulhq_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_n_s16(a: int16x4_t, b: i16) -> int16x4_t { + simd_mul(a, vdup_n_s16(b)) } -/// Signed saturating doubling multiply returning high half +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] -pub unsafe fn vqdmulh_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmulh.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulh.v2i32")] - fn vqdmulh_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } -vqdmulh_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_n_s16(a: int16x8_t, b: i16) -> int16x8_t { + simd_mul(a, vdupq_n_s16(b)) } -/// Signed saturating doubling multiply returning high half +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] -pub unsafe fn vqdmulhq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmulh.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulh.v4i32")] - fn vqdmulhq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } -vqdmulhq_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_n_s32(a: int32x2_t, b: i32) -> int32x2_t { + simd_mul(a, vdup_n_s32(b)) } -/// Vector saturating doubling multiply high with scalar +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] -pub unsafe fn vqdmulh_n_s16(a: int16x4_t, b: i16) -> int16x4_t { - let b: int16x4_t = vdup_n_s16(b); - vqdmulh_s16(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_n_s32(a: int32x4_t, b: i32) -> int32x4_t { + simd_mul(a, vdupq_n_s32(b)) } -/// Vector saturating doubling multiply high with scalar +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] -pub unsafe fn vqdmulh_n_s32(a: int32x2_t, b: i32) -> int32x2_t { - let b: int32x2_t = vdup_n_s32(b); - vqdmulh_s32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_n_u16(a: uint16x4_t, b: u16) -> uint16x4_t { + simd_mul(a, vdup_n_u16(b)) } -/// Vector saturating doubling multiply high with scalar +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] -pub unsafe fn vqdmulhq_nq_s16(a: int16x8_t, b: i16) -> int16x8_t { - let b: int16x8_t = vdupq_n_s16(b); - vqdmulhq_s16(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_n_u16(a: uint16x8_t, b: u16) -> uint16x8_t { + simd_mul(a, vdupq_n_u16(b)) } -/// Vector saturating doubling multiply high with scalar +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] -pub unsafe fn vqdmulhq_nq_s32(a: int32x4_t, b: i32) -> int32x4_t { - let b: int32x4_t = vdupq_n_s32(b); - vqdmulhq_s32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmul_n_u32(a: uint32x2_t, b: u32) -> uint32x2_t { + simd_mul(a, vdup_n_u32(b)) } -/// Signed saturating extract narrow +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtn))] -pub unsafe fn vqmovn_s16(a: int16x8_t) -> int8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovns.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtn.v8i8")] - fn vqmovn_s16_(a: int16x8_t) -> int8x8_t; - } -vqmovn_s16_(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul))] +pub unsafe fn vmulq_n_u32(a: uint32x4_t, b: u32) -> uint32x4_t { + simd_mul(a, vdupq_n_u32(b)) } -/// Signed saturating extract narrow +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtn))] -pub unsafe fn vqmovn_s32(a: int32x4_t) -> int16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovns.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtn.v4i16")] - fn vqmovn_s32_(a: int32x4_t) -> int16x4_t; - } -vqmovn_s32_(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul))] +pub unsafe fn vmul_n_f32(a: float32x2_t, b: f32) -> float32x2_t { + simd_mul(a, vdup_n_f32(b)) } -/// Signed saturating extract narrow +/// Vector multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtn))] -pub unsafe fn vqmovn_s64(a: int64x2_t) -> int32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovns.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtn.v2i32")] - fn vqmovn_s64_(a: int64x2_t) -> int32x2_t; - } -vqmovn_s64_(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul))] +pub unsafe fn vmulq_n_f32(a: float32x4_t, b: f32) -> float32x4_t { + simd_mul(a, vdupq_n_f32(b)) } -/// Unsigned saturating extract narrow +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqxtn))] -pub unsafe fn vqmovn_u16(a: uint16x8_t) -> uint8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqxtn.v8i8")] - fn vqmovn_u16_(a: uint16x8_t) -> uint8x8_t; - } -vqmovn_u16_(a) -} - -/// Unsigned saturating extract narrow -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqxtn))] -pub unsafe fn vqmovn_u32(a: uint32x4_t) -> uint16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqxtn.v4i16")] - fn vqmovn_u32_(a: uint32x4_t) -> uint16x4_t; - } -vqmovn_u32_(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmul_lane_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + static_assert_imm2!(LANE); + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Unsigned saturating extract narrow +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqxtn))] -pub unsafe fn vqmovn_u64(a: uint64x2_t) -> uint32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqxtn.v2i32")] - fn vqmovn_u64_(a: uint64x2_t) -> uint32x2_t; - } -vqmovn_u64_(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmul_laneq_s16(a: int16x4_t, b: int16x8_t) -> int16x4_t { + static_assert_imm3!(LANE); + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating extract unsigned narrow +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovun))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtun))] -pub unsafe fn vqmovun_s16(a: int16x8_t) -> uint8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnsu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtun.v8i8")] - fn vqmovun_s16_(a: int16x8_t) -> uint8x8_t; - } -vqmovun_s16_(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmulq_lane_s16(a: int16x8_t, b: int16x4_t) -> int16x8_t { + static_assert_imm2!(LANE); + simd_mul(a, simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating extract unsigned narrow +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovun))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtun))] -pub unsafe fn vqmovun_s32(a: int32x4_t) -> uint16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnsu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtun.v4i16")] - fn vqmovun_s32_(a: int32x4_t) -> uint16x4_t; - } -vqmovun_s32_(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmulq_laneq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + static_assert_imm3!(LANE); + simd_mul(a, simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating extract unsigned narrow +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovun))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtun))] -pub unsafe fn vqmovun_s64(a: int64x2_t) -> uint32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnsu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtun.v2i32")] - fn vqmovun_s64_(a: int64x2_t) -> uint32x2_t; - } -vqmovun_s64_(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmul_lane_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + static_assert_imm1!(LANE); + simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply returning high half +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmulh_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrdmulh.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrdmulh.v4i16")] - fn vqrdmulh_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } -vqrdmulh_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmul_laneq_s32(a: int32x2_t, b: int32x4_t) -> int32x2_t { + static_assert_imm2!(LANE); + simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply returning high half +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmulhq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrdmulh.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrdmulh.v8i16")] - fn vqrdmulhq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } -vqrdmulhq_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmulq_lane_s32(a: int32x4_t, b: int32x2_t) -> int32x4_t { + static_assert_imm1!(LANE); + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply returning high half +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmulh_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrdmulh.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrdmulh.v2i32")] - fn vqrdmulh_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } -vqrdmulh_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmulq_laneq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + static_assert_imm2!(LANE); + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply returning high half +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmulhq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrdmulh.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrdmulh.v4i32")] - fn vqrdmulhq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } -vqrdmulhq_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmul_lane_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + static_assert_imm2!(LANE); + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Vector saturating rounding doubling multiply high with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmulh_n_s16(a: int16x4_t, b: i16) -> int16x4_t { - vqrdmulh_s16(a, vdup_n_s16(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmul_laneq_u16(a: uint16x4_t, b: uint16x8_t) -> uint16x4_t { + static_assert_imm3!(LANE); + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Vector saturating rounding doubling multiply high with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmulhq_n_s16(a: int16x8_t, b: i16) -> int16x8_t { - vqrdmulhq_s16(a, vdupq_n_s16(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmulq_lane_u16(a: uint16x8_t, b: uint16x4_t) -> uint16x8_t { + static_assert_imm2!(LANE); + simd_mul(a, simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Vector saturating rounding doubling multiply high with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmulh_n_s32(a: int32x2_t, b: i32) -> int32x2_t { - vqrdmulh_s32(a, vdup_n_s32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmulq_laneq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + static_assert_imm3!(LANE); + simd_mul(a, simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Vector saturating rounding doubling multiply high with scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmulhq_n_s32(a: int32x4_t, b: i32) -> int32x4_t { - vqrdmulhq_s32(a, vdupq_n_s32(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmul_lane_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + static_assert_imm1!(LANE); + simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Vector rounding saturating doubling multiply high by scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] #[rustc_legacy_const_generics(2)] -pub unsafe fn vqrdmulh_lane_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { +pub unsafe fn vmul_laneq_u32(a: uint32x2_t, b: uint32x4_t) -> uint32x2_t { static_assert_imm2!(LANE); - let b: int16x4_t = simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32]); - vqrdmulh_s16(a, b) + simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Vector rounding saturating doubling multiply high by scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] #[rustc_legacy_const_generics(2)] -pub unsafe fn vqrdmulh_laneq_s16(a: int16x4_t, b: int16x8_t) -> int16x4_t { - static_assert_imm3!(LANE); - let b: int16x4_t = simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32]); - vqrdmulh_s16(a, b) +pub unsafe fn vmulq_lane_u32(a: uint32x4_t, b: uint32x2_t) -> uint32x4_t { + static_assert_imm1!(LANE); + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Vector rounding saturating doubling multiply high by scalar +/// Multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mul, LANE = 1))] #[rustc_legacy_const_generics(2)] -pub unsafe fn vqrdmulhq_lane_s16(a: int16x8_t, b: int16x4_t) -> int16x8_t { +pub unsafe fn vmulq_laneq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { static_assert_imm2!(LANE); - let b: int16x8_t = simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32]); - vqrdmulhq_s16(a, b) + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Vector rounding saturating doubling multiply high by scalar +/// Floating-point multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul, LANE = 0))] #[rustc_legacy_const_generics(2)] -pub unsafe fn vqrdmulhq_laneq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - static_assert_imm3!(LANE); - let b: int16x8_t = simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32]); - vqrdmulhq_s16(a, b) +pub unsafe fn vmul_lane_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + static_assert_imm1!(LANE); + simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Vector rounding saturating doubling multiply high by scalar +/// Floating-point multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul, LANE = 0))] #[rustc_legacy_const_generics(2)] -pub unsafe fn vqrdmulh_lane_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - static_assert_imm1!(LANE); - let b: int32x2_t = simd_shuffle2!(b, b, [LANE as u32, LANE as u32]); - vqrdmulh_s32(a, b) -} - -/// Vector rounding saturating doubling multiply high by scalar -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vqrdmulh_laneq_s32(a: int32x2_t, b: int32x4_t) -> int32x2_t { +pub unsafe fn vmul_laneq_f32(a: float32x2_t, b: float32x4_t) -> float32x2_t { static_assert_imm2!(LANE); - let b: int32x2_t = simd_shuffle2!(b, b, [LANE as u32, LANE as u32]); - vqrdmulh_s32(a, b) + simd_mul(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Vector rounding saturating doubling multiply high by scalar +/// Floating-point multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul, LANE = 0))] #[rustc_legacy_const_generics(2)] -pub unsafe fn vqrdmulhq_lane_s32(a: int32x4_t, b: int32x2_t) -> int32x4_t { +pub unsafe fn vmulq_lane_f32(a: float32x4_t, b: float32x2_t) -> float32x4_t { static_assert_imm1!(LANE); - let b: int32x4_t = simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32]); - vqrdmulhq_s32(a, b) + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Vector rounding saturating doubling multiply high by scalar +/// Floating-point multiply #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmul, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmul, LANE = 0))] #[rustc_legacy_const_generics(2)] -pub unsafe fn vqrdmulhq_laneq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { +pub unsafe fn vmulq_laneq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { static_assert_imm2!(LANE); - let b: int32x4_t = simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32]); - vqrdmulhq_s32(a, b) + simd_mul(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Signed multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmlah_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { - vqadd_s16(a, vqrdmulh_s16(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.s8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] +pub unsafe fn vmull_s8(a: int8x8_t, b: int8x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulls.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smull.v8i8")] + fn vmull_s8_(a: int8x8_t, b: int8x8_t) -> int16x8_t; + } +vmull_s8_(a, b) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Signed multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmlahq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { - vqaddq_s16(a, vqrdmulhq_s16(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.s16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] +pub unsafe fn vmull_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulls.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smull.v4i16")] + fn vmull_s16_(a: int16x4_t, b: int16x4_t) -> int32x4_t; + } +vmull_s16_(a, b) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Signed multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmlah_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { - vqadd_s32(a, vqrdmulh_s32(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.s32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] +pub unsafe fn vmull_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmulls.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smull.v2i32")] + fn vmull_s32_(a: int32x2_t, b: int32x2_t) -> int64x2_t; + } +vmull_s32_(a, b) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Unsigned multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmlahq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { - vqaddq_s32(a, vqrdmulhq_s32(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.u8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] +pub unsafe fn vmull_u8(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmullu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umull.v8i8")] + fn vmull_u8_(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t; + } +vmull_u8_(a, b) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Unsigned multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlah_lane_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { - static_assert_imm2!(LANE); - vqadd_s16(a, vqrdmulh_lane_s16::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.u16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] +pub unsafe fn vmull_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmullu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umull.v4i16")] + fn vmull_u16_(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t; + } +vmull_u16_(a, b) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Unsigned multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlah_laneq_s16(a: int16x4_t, b: int16x4_t, c: int16x8_t) -> int16x4_t { - static_assert_imm3!(LANE); - vqadd_s16(a, vqrdmulh_laneq_s16::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.u32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] +pub unsafe fn vmull_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmullu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umull.v2i32")] + fn vmull_u32_(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t; + } +vmull_u32_(a, b) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Polynomial multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlahq_lane_s16(a: int16x8_t, b: int16x8_t, c: int16x4_t) -> int16x8_t { - static_assert_imm2!(LANE); - vqaddq_s16(a, vqrdmulhq_lane_s16::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmull.p8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(pmull))] +pub unsafe fn vmull_p8(a: poly8x8_t, b: poly8x8_t) -> poly16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmullp.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.pmull.v8i8")] + fn vmull_p8_(a: poly8x8_t, b: poly8x8_t) -> poly16x8_t; + } +vmull_p8_(a, b) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Vector long multiply with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlahq_laneq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { - static_assert_imm3!(LANE); - vqaddq_s16(a, vqrdmulhq_laneq_s16::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] +pub unsafe fn vmull_n_s16(a: int16x4_t, b: i16) -> int32x4_t { + vmull_s16(a, vdup_n_s16(b)) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Vector long multiply with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlah_lane_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { - static_assert_imm1!(LANE); - vqadd_s32(a, vqrdmulh_lane_s32::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull))] +pub unsafe fn vmull_n_s32(a: int32x2_t, b: i32) -> int64x2_t { + vmull_s32(a, vdup_n_s32(b)) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Vector long multiply with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlah_laneq_s32(a: int32x2_t, b: int32x2_t, c: int32x4_t) -> int32x2_t { - static_assert_imm2!(LANE); - vqadd_s32(a, vqrdmulh_laneq_s32::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] +pub unsafe fn vmull_n_u16(a: uint16x4_t, b: u16) -> uint32x4_t { + vmull_u16(a, vdup_n_u16(b)) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Vector long multiply with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlahq_lane_s32(a: int32x4_t, b: int32x4_t, c: int32x2_t) -> int32x4_t { - static_assert_imm1!(LANE); - vqaddq_s32(a, vqrdmulhq_lane_s32::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull))] +pub unsafe fn vmull_n_u32(a: uint32x2_t, b: u32) -> uint64x2_t { + vmull_u32(a, vdup_n_u32(b)) } -/// Signed saturating rounding doubling multiply accumulate returning high half +/// Vector long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlahq_laneq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmull_lane_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { static_assert_imm2!(LANE); - vqaddq_s32(a, vqrdmulhq_laneq_s32::(b, c)) + vmull_s16(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Vector long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmlsh_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { - vqsub_s16(a, vqrdmulh_s16(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmull_laneq_s16(a: int16x4_t, b: int16x8_t) -> int32x4_t { + static_assert_imm3!(LANE); + vmull_s16(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Vector long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmlshq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { - vqsubq_s16(a, vqrdmulhq_s16(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmull_lane_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { + static_assert_imm1!(LANE); + vmull_s32(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Vector long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmlsh_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { - vqsub_s32(a, vqrdmulh_s32(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smull, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmull_laneq_s32(a: int32x2_t, b: int32x4_t) -> int64x2_t { + static_assert_imm2!(LANE); + vmull_s32(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Vector long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] -pub unsafe fn vqrdmlshq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { - vqsubq_s32(a, vqrdmulhq_s32(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmull_lane_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { + static_assert_imm2!(LANE); + vmull_u16(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Vector long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlsh_lane_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { - static_assert_imm2!(LANE); - vqsub_s16(a, vqrdmulh_lane_s16::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmull_laneq_u16(a: uint16x4_t, b: uint16x8_t) -> uint32x4_t { + static_assert_imm3!(LANE); + vmull_u16(a, simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Vector long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlsh_laneq_s16(a: int16x4_t, b: int16x4_t, c: int16x8_t) -> int16x4_t { - static_assert_imm3!(LANE); - vqsub_s16(a, vqrdmulh_laneq_s16::(b, c)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmull_lane_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { + static_assert_imm1!(LANE); + vmull_u32(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Vector long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlshq_lane_s16(a: int16x8_t, b: int16x8_t, c: int16x4_t) -> int16x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmull, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umull, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vmull_laneq_u32(a: uint32x2_t, b: uint32x4_t) -> uint64x2_t { static_assert_imm2!(LANE); - vqsubq_s16(a, vqrdmulhq_lane_s16::(b, c)) + vmull_u32(a, simd_shuffle2!(b, b, [LANE as u32, LANE as u32])) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Floating-point fused Multiply-Add to accumulator(vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlshq_laneq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { - static_assert_imm3!(LANE); - vqsubq_s16(a, vqrdmulhq_laneq_s16::(b, c)) +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfma))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmla))] +pub unsafe fn vfma_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.fma.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.v2f32")] + fn vfma_f32_(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float32x2_t; + } +vfma_f32_(b, c, a) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Floating-point fused Multiply-Add to accumulator(vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlsh_lane_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { - static_assert_imm1!(LANE); - vqsub_s32(a, vqrdmulh_lane_s32::(b, c)) +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfma))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmla))] +pub unsafe fn vfmaq_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.fma.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.fma.v4f32")] + fn vfmaq_f32_(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float32x4_t; + } +vfmaq_f32_(b, c, a) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Floating-point fused Multiply-Add to accumulator(vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlsh_laneq_s32(a: int32x2_t, b: int32x2_t, c: int32x4_t) -> int32x2_t { - static_assert_imm2!(LANE); - vqsub_s32(a, vqrdmulh_laneq_s32::(b, c)) +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfma))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmla))] +pub unsafe fn vfma_n_f32(a: float32x2_t, b: float32x2_t, c: f32) -> float32x2_t { + vfma_f32(a, b, vdup_n_f32_vfp4(c)) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Floating-point fused Multiply-Add to accumulator(vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlshq_lane_s32(a: int32x4_t, b: int32x4_t, c: int32x2_t) -> int32x4_t { - static_assert_imm1!(LANE); - vqsubq_s32(a, vqrdmulhq_lane_s32::(b, c)) +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfma))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmla))] +pub unsafe fn vfmaq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t { + vfmaq_f32(a, b, vdupq_n_f32_vfp4(c)) } -/// Signed saturating rounding doubling multiply subtract returning high half +/// Floating-point fused multiply-subtract from accumulator #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] -#[rustc_legacy_const_generics(3)] -pub unsafe fn vqrdmlshq_laneq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { - static_assert_imm2!(LANE); - vqsubq_s32(a, vqrdmulhq_laneq_s32::(b, c)) +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfms))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmls))] +pub unsafe fn vfms_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float32x2_t { + let b: float32x2_t = simd_neg(b); + vfma_f32(a, b, c) } -/// Signed saturating rounding shift left +/// Floating-point fused multiply-subtract from accumulator #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] -pub unsafe fn vqrshl_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v8i8")] - fn vqrshl_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; - } -vqrshl_s8_(a, b) +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfms))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmls))] +pub unsafe fn vfmsq_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float32x4_t { + let b: float32x4_t = simd_neg(b); + vfmaq_f32(a, b, c) } -/// Signed saturating rounding shift left +/// Floating-point fused Multiply-subtract to accumulator(vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] -pub unsafe fn vqrshlq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v16i8")] - fn vqrshlq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; - } -vqrshlq_s8_(a, b) +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfms))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmls))] +pub unsafe fn vfms_n_f32(a: float32x2_t, b: float32x2_t, c: f32) -> float32x2_t { + vfms_f32(a, b, vdup_n_f32_vfp4(c)) } -/// Signed saturating rounding shift left +/// Floating-point fused Multiply-subtract to accumulator(vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] -pub unsafe fn vqrshl_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v4i16")] - fn vqrshl_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } -vqrshl_s16_(a, b) +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vfms))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmls))] +pub unsafe fn vfmsq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t { + vfmsq_f32(a, b, vdupq_n_f32_vfp4(c)) } -/// Signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] -pub unsafe fn vqrshlq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v8i16")] - fn vqrshlq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } -vqrshlq_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + simd_sub(a, b) } -/// Signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] -pub unsafe fn vqrshl_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v2i32")] - fn vqrshl_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } -vqrshl_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + simd_sub(a, b) } -/// Signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] -pub unsafe fn vqrshlq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v4i32")] - fn vqrshlq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } -vqrshlq_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + simd_sub(a, b) } -/// Signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] -pub unsafe fn vqrshl_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v1i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v1i64")] - fn vqrshl_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; - } -vqrshl_s64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + simd_sub(a, b) } -/// Signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] -pub unsafe fn vqrshlq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v2i64")] - fn vqrshlq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; - } -vqrshlq_s64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + simd_sub(a, b) } -/// Unsigned signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] -pub unsafe fn vqrshl_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v8i8")] - fn vqrshl_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; - } -vqrshl_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + simd_sub(a, b) } -/// Unsigned signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] -pub unsafe fn vqrshlq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v16i8")] - fn vqrshlq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; - } -vqrshlq_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + simd_sub(a, b) } -/// Unsigned signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] -pub unsafe fn vqrshl_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v4i16")] - fn vqrshl_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; - } -vqrshl_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { + simd_sub(a, b) } -/// Unsigned signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] -pub unsafe fn vqrshlq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v8i16")] - fn vqrshlq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; - } -vqrshlq_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + simd_sub(a, b) } -/// Unsigned signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] -pub unsafe fn vqrshl_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v2i32")] - fn vqrshl_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; - } -vqrshl_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + simd_sub(a, b) } -/// Unsigned signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] -pub unsafe fn vqrshlq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v4i32")] - fn vqrshlq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; - } -vqrshlq_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + simd_sub(a, b) } -/// Unsigned signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] -pub unsafe fn vqrshl_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v1i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v1i64")] - fn vqrshl_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; - } -vqrshl_u64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + simd_sub(a, b) } -/// Unsigned signed saturating rounding shift left +/// Subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] -pub unsafe fn vqrshlq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v2i64")] - fn vqrshlq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; - } -vqrshlq_u64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i64"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsub_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + simd_sub(a, b) } -/// Signed saturating rounded shift right narrow +/// Subtract #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_s16(a: int16x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftns.v8i8")] - fn vqrshrn_n_s16_(a: int16x8_t, n: int16x8_t) -> int8x8_t; - } -vqrshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i64"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsubq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { + simd_sub(a, b) } -/// Signed saturating rounded shift right narrow +/// Subtract #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_s16(a: int16x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrn.v8i8")] - fn vqrshrn_n_s16_(a: int16x8_t, n: i32) -> int8x8_t; - } -vqrshrn_n_s16_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i64"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsub_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { + simd_sub(a, b) } -/// Signed saturating rounded shift right narrow +/// Subtract #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_s32(a: int32x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftns.v4i16")] - fn vqrshrn_n_s32_(a: int32x4_t, n: int32x4_t) -> int16x4_t; - } -vqrshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.i64"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sub))] +pub unsafe fn vsubq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { + simd_sub(a, b) } -/// Signed saturating rounded shift right narrow +/// Subtract #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_s32(a: int32x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrn.v4i16")] - fn vqrshrn_n_s32_(a: int32x4_t, n: i32) -> int16x4_t; - } -vqrshrn_n_s32_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.f32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fsub))] +pub unsafe fn vsub_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + simd_sub(a, b) } -/// Signed saturating rounded shift right narrow +/// Subtract #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_s64(a: int64x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftns.v2i32")] - fn vqrshrn_n_s64_(a: int64x2_t, n: int64x2_t) -> int32x2_t; - } -vqrshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vsub.f32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fsub))] +pub unsafe fn vsubq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + simd_sub(a, b) } -/// Signed saturating rounded shift right narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_s64(a: int64x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrn.v2i32")] - fn vqrshrn_n_s64_(a: int64x2_t, n: i32) -> int32x2_t; - } -vqrshrn_n_s64_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] +pub unsafe fn vsubhn_s16(a: int16x8_t, b: int16x8_t) -> int8x8_t { + let c: i16x8 = i16x8::new(8, 8, 8, 8, 8, 8, 8, 8); + simd_cast(simd_shr(simd_sub(a, b), transmute(c))) } -/// Unsigned signed saturating rounded shift right narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_u16(a: uint16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnu.v8i8")] - fn vqrshrn_n_u16_(a: uint16x8_t, n: uint16x8_t) -> uint8x8_t; - } -vqrshrn_n_u16_(a, uint16x8_t(-N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] +pub unsafe fn vsubhn_s32(a: int32x4_t, b: int32x4_t) -> int16x4_t { + let c: i32x4 = i32x4::new(16, 16, 16, 16); + simd_cast(simd_shr(simd_sub(a, b), transmute(c))) } -/// Unsigned signed saturating rounded shift right narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_u16(a: uint16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshrn.v8i8")] - fn vqrshrn_n_u16_(a: uint16x8_t, n: i32) -> uint8x8_t; - } -vqrshrn_n_u16_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] +pub unsafe fn vsubhn_s64(a: int64x2_t, b: int64x2_t) -> int32x2_t { + let c: i64x2 = i64x2::new(32, 32); + simd_cast(simd_shr(simd_sub(a, b), transmute(c))) } -/// Unsigned signed saturating rounded shift right narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_u32(a: uint32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnu.v4i16")] - fn vqrshrn_n_u32_(a: uint32x4_t, n: uint32x4_t) -> uint16x4_t; - } -vqrshrn_n_u32_(a, uint32x4_t(-N as u32, -N as u32, -N as u32, -N as u32)) -} - -/// Unsigned signed saturating rounded shift right narrow -#[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_u32(a: uint32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshrn.v4i16")] - fn vqrshrn_n_u32_(a: uint32x4_t, n: i32) -> uint16x4_t; - } -vqrshrn_n_u32_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] +pub unsafe fn vsubhn_u16(a: uint16x8_t, b: uint16x8_t) -> uint8x8_t { + let c: u16x8 = u16x8::new(8, 8, 8, 8, 8, 8, 8, 8); + simd_cast(simd_shr(simd_sub(a, b), transmute(c))) } -/// Unsigned signed saturating rounded shift right narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_u64(a: uint64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnu.v2i32")] - fn vqrshrn_n_u64_(a: uint64x2_t, n: uint64x2_t) -> uint32x2_t; - } -vqrshrn_n_u64_(a, uint64x2_t(-N as u64, -N as u64)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] +pub unsafe fn vsubhn_u32(a: uint32x4_t, b: uint32x4_t) -> uint16x4_t { + let c: u32x4 = u32x4::new(16, 16, 16, 16); + simd_cast(simd_shr(simd_sub(a, b), transmute(c))) } -/// Unsigned signed saturating rounded shift right narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrn_n_u64(a: uint64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshrn.v2i32")] - fn vqrshrn_n_u64_(a: uint64x2_t, n: i32) -> uint32x2_t; - } -vqrshrn_n_u64_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn))] +pub unsafe fn vsubhn_u64(a: uint64x2_t, b: uint64x2_t) -> uint32x2_t { + let c: u64x2 = u64x2::new(32, 32); + simd_cast(simd_shr(simd_sub(a, b), transmute(c))) } -/// Signed saturating rounded shift right unsigned narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrun_n_s16(a: int16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnsu.v8i8")] - fn vqrshrun_n_s16_(a: int16x8_t, n: int16x8_t) -> uint8x8_t; - } -vqrshrun_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] +pub unsafe fn vsubhn_high_s16(a: int8x8_t, b: int16x8_t, c: int16x8_t) -> int8x16_t { + let d: int8x8_t = vsubhn_s16(b, c); + simd_shuffle16!(a, d, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) } -/// Signed saturating rounded shift right unsigned narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrun_n_s16(a: int16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrun.v8i8")] - fn vqrshrun_n_s16_(a: int16x8_t, n: i32) -> uint8x8_t; - } -vqrshrun_n_s16_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] +pub unsafe fn vsubhn_high_s32(a: int16x4_t, b: int32x4_t, c: int32x4_t) -> int16x8_t { + let d: int16x4_t = vsubhn_s32(b, c); + simd_shuffle8!(a, d, [0, 1, 2, 3, 4, 5, 6, 7]) } -/// Signed saturating rounded shift right unsigned narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrun_n_s32(a: int32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnsu.v4i16")] - fn vqrshrun_n_s32_(a: int32x4_t, n: int32x4_t) -> uint16x4_t; - } -vqrshrun_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] +pub unsafe fn vsubhn_high_s64(a: int32x2_t, b: int64x2_t, c: int64x2_t) -> int32x4_t { + let d: int32x2_t = vsubhn_s64(b, c); + simd_shuffle4!(a, d, [0, 1, 2, 3]) } -/// Signed saturating rounded shift right unsigned narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrun_n_s32(a: int32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrun.v4i16")] - fn vqrshrun_n_s32_(a: int32x4_t, n: i32) -> uint16x4_t; - } -vqrshrun_n_s32_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] +pub unsafe fn vsubhn_high_u16(a: uint8x8_t, b: uint16x8_t, c: uint16x8_t) -> uint8x16_t { + let d: uint8x8_t = vsubhn_u16(b, c); + simd_shuffle16!(a, d, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) } -/// Signed saturating rounded shift right unsigned narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrun_n_s64(a: int64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnsu.v2i32")] - fn vqrshrun_n_s64_(a: int64x2_t, n: int64x2_t) -> uint32x2_t; - } -vqrshrun_n_s64_(a, int64x2_t(-N as i64, -N as i64)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] +pub unsafe fn vsubhn_high_u32(a: uint16x4_t, b: uint32x4_t, c: uint32x4_t) -> uint16x8_t { + let d: uint16x4_t = vsubhn_u32(b, c); + simd_shuffle8!(a, d, [0, 1, 2, 3, 4, 5, 6, 7]) } -/// Signed saturating rounded shift right unsigned narrow +/// Subtract returning high narrow #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqrshrun_n_s64(a: int64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrun.v2i32")] - fn vqrshrun_n_s64_(a: int64x2_t, n: i32) -> uint32x2_t; - } -vqrshrun_n_s64_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(subhn2))] +pub unsafe fn vsubhn_high_u64(a: uint32x2_t, b: uint64x2_t, c: uint64x2_t) -> uint32x4_t { + let d: uint32x2_t = vsubhn_u64(b, c); + simd_shuffle4!(a, d, [0, 1, 2, 3]) } -/// Signed saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] -pub unsafe fn vqshl_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] +pub unsafe fn vhsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v8i8")] - fn vqshl_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v8i8")] + fn vhsub_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; } -vqshl_s8_(a, b) +vhsub_u8_(a, b) } -/// Signed saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] -pub unsafe fn vqshlq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] +pub unsafe fn vhsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v16i8")] - fn vqshlq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v16i8")] + fn vhsubq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; } -vqshlq_s8_(a, b) +vhsubq_u8_(a, b) } -/// Signed saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] -pub unsafe fn vqshl_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] +pub unsafe fn vhsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v4i16")] - fn vqshl_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v4i16")] + fn vhsub_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; } -vqshl_s16_(a, b) +vhsub_u16_(a, b) } -/// Signed saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] -pub unsafe fn vqshlq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] +pub unsafe fn vhsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v8i16")] - fn vqshlq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v8i16")] + fn vhsubq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; } -vqshlq_s16_(a, b) +vhsubq_u16_(a, b) } -/// Signed saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] -pub unsafe fn vqshl_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] +pub unsafe fn vhsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v2i32")] - fn vqshl_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v2i32")] + fn vhsub_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; } -vqshl_s32_(a, b) +vhsub_u32_(a, b) } -/// Signed saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] -pub unsafe fn vqshlq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.u32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uhsub))] +pub unsafe fn vhsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v4i32")] - fn vqshlq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uhsub.v4i32")] + fn vhsubq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; } -vqshlq_s32_(a, b) +vhsubq_u32_(a, b) } -/// Signed saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] -pub unsafe fn vqshl_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] +pub unsafe fn vhsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v1i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v1i64")] - fn vqshl_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v8i8")] + fn vhsub_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; } -vqshl_s64_(a, b) +vhsub_s8_(a, b) } -/// Signed saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] -pub unsafe fn vqshlq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] +pub unsafe fn vhsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v2i64")] - fn vqshlq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v16i8")] + fn vhsubq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; } -vqshlq_s64_(a, b) +vhsubq_s8_(a, b) } -/// Unsigned saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] -pub unsafe fn vqshl_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] +pub unsafe fn vhsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v8i8")] - fn vqshl_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v4i16")] + fn vhsub_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; } -vqshl_u8_(a, b) +vhsub_s16_(a, b) } -/// Unsigned saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] -pub unsafe fn vqshlq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] +pub unsafe fn vhsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v16i8")] - fn vqshlq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v8i16")] + fn vhsubq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; } -vqshlq_u8_(a, b) +vhsubq_s16_(a, b) } -/// Unsigned saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] -pub unsafe fn vqshl_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] +pub unsafe fn vhsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v4i16")] - fn vqshl_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v2i32")] + fn vhsub_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; } -vqshl_u16_(a, b) +vhsub_s32_(a, b) } -/// Unsigned saturating shift left +/// Signed halving subtract #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] -pub unsafe fn vqshlq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vhsub.s32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shsub))] +pub unsafe fn vhsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v8i16")] - fn vqshlq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vhsubs.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.shsub.v4i32")] + fn vhsubq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; } -vqshlq_u16_(a, b) +vhsubq_s32_(a, b) } -/// Unsigned saturating shift left +/// Signed Subtract Wide #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] -pub unsafe fn vqshl_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v2i32")] - fn vqshl_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; - } -vqshl_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubw))] +pub unsafe fn vsubw_s8(a: int16x8_t, b: int8x8_t) -> int16x8_t { + simd_sub(a, simd_cast(b)) } -/// Unsigned saturating shift left +/// Signed Subtract Wide #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] -pub unsafe fn vqshlq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v4i32")] - fn vqshlq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; - } -vqshlq_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubw))] +pub unsafe fn vsubw_s16(a: int32x4_t, b: int16x4_t) -> int32x4_t { + simd_sub(a, simd_cast(b)) } -/// Unsigned saturating shift left +/// Signed Subtract Wide #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] -pub unsafe fn vqshl_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v1i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v1i64")] - fn vqshl_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; - } -vqshl_u64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubw))] +pub unsafe fn vsubw_s32(a: int64x2_t, b: int32x2_t) -> int64x2_t { + simd_sub(a, simd_cast(b)) } -/// Unsigned saturating shift left +/// Unsigned Subtract Wide #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] -pub unsafe fn vqshlq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v2i64")] - fn vqshlq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; - } -vqshlq_u64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubw))] +pub unsafe fn vsubw_u8(a: uint16x8_t, b: uint8x8_t) -> uint16x8_t { + simd_sub(a, simd_cast(b)) } -/// Signed saturating shift left +/// Unsigned Subtract Wide #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshl_n_s8(a: int8x8_t) -> int8x8_t { - static_assert_imm3!(N); - vqshl_s8(a, vdup_n_s8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubw))] +pub unsafe fn vsubw_u16(a: uint32x4_t, b: uint16x4_t) -> uint32x4_t { + simd_sub(a, simd_cast(b)) } -/// Signed saturating shift left +/// Unsigned Subtract Wide #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshlq_n_s8(a: int8x16_t) -> int8x16_t { - static_assert_imm3!(N); - vqshlq_s8(a, vdupq_n_s8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubw))] +pub unsafe fn vsubw_u32(a: uint64x2_t, b: uint32x2_t) -> uint64x2_t { + simd_sub(a, simd_cast(b)) } -/// Signed saturating shift left +/// Signed Subtract Long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshl_n_s16(a: int16x4_t) -> int16x4_t { - static_assert_imm4!(N); - vqshl_s16(a, vdup_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubl))] +pub unsafe fn vsubl_s8(a: int8x8_t, b: int8x8_t) -> int16x8_t { + let c: int16x8_t = simd_cast(a); + let d: int16x8_t = simd_cast(b); + simd_sub(c, d) } -/// Signed saturating shift left +/// Signed Subtract Long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshlq_n_s16(a: int16x8_t) -> int16x8_t { - static_assert_imm4!(N); - vqshlq_s16(a, vdupq_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubl))] +pub unsafe fn vsubl_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { + let c: int32x4_t = simd_cast(a); + let d: int32x4_t = simd_cast(b); + simd_sub(c, d) } -/// Signed saturating shift left +/// Signed Subtract Long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshl_n_s32(a: int32x2_t) -> int32x2_t { - static_assert_imm5!(N); - vqshl_s32(a, vdup_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssubl))] +pub unsafe fn vsubl_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { + let c: int64x2_t = simd_cast(a); + let d: int64x2_t = simd_cast(b); + simd_sub(c, d) } -/// Signed saturating shift left +/// Unsigned Subtract Long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshlq_n_s32(a: int32x4_t) -> int32x4_t { - static_assert_imm5!(N); - vqshlq_s32(a, vdupq_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubl))] +pub unsafe fn vsubl_u8(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t { + let c: uint16x8_t = simd_cast(a); + let d: uint16x8_t = simd_cast(b); + simd_sub(c, d) } -/// Signed saturating shift left +/// Unsigned Subtract Long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshl_n_s64(a: int64x1_t) -> int64x1_t { - static_assert_imm6!(N); - vqshl_s64(a, vdup_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubl))] +pub unsafe fn vsubl_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { + let c: uint32x4_t = simd_cast(a); + let d: uint32x4_t = simd_cast(b); + simd_sub(c, d) } -/// Signed saturating shift left +/// Unsigned Subtract Long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshlq_n_s64(a: int64x2_t) -> int64x2_t { - static_assert_imm6!(N); - vqshlq_s64(a, vdupq_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsubl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usubl))] +pub unsafe fn vsubl_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { + let c: uint64x2_t = simd_cast(a); + let d: uint64x2_t = simd_cast(b); + simd_sub(c, d) } -/// Unsigned saturating shift left +/// Maximum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshl_n_u8(a: uint8x8_t) -> uint8x8_t { - static_assert_imm3!(N); - vqshl_u8(a, vdup_n_s8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmax_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v8i8")] + fn vmax_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + } +vmax_s8_(a, b) } -/// Unsigned saturating shift left +/// Maximum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshlq_n_u8(a: uint8x16_t) -> uint8x16_t { - static_assert_imm3!(N); - vqshlq_u8(a, vdupq_n_s8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmaxq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v16i8")] + fn vmaxq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + } +vmaxq_s8_(a, b) } -/// Unsigned saturating shift left +/// Maximum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshl_n_u16(a: uint16x4_t) -> uint16x4_t { - static_assert_imm4!(N); - vqshl_u16(a, vdup_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmax_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v4i16")] + fn vmax_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + } +vmax_s16_(a, b) } -/// Unsigned saturating shift left +/// Maximum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshlq_n_u16(a: uint16x8_t) -> uint16x8_t { - static_assert_imm4!(N); - vqshlq_u16(a, vdupq_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmaxq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v8i16")] + fn vmaxq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + } +vmaxq_s16_(a, b) } -/// Unsigned saturating shift left +/// Maximum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshl_n_u32(a: uint32x2_t) -> uint32x2_t { - static_assert_imm5!(N); - vqshl_u32(a, vdup_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmax_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v2i32")] + fn vmax_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + } +vmax_s32_(a, b) } -/// Unsigned saturating shift left +/// Maximum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshlq_n_u32(a: uint32x4_t) -> uint32x4_t { - static_assert_imm5!(N); - vqshlq_u32(a, vdupq_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmaxq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v4i32")] + fn vmaxq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + } +vmaxq_s32_(a, b) } -/// Unsigned saturating shift left +/// Maximum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshl_n_u64(a: uint64x1_t) -> uint64x1_t { - static_assert_imm6!(N); - vqshl_u64(a, vdup_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmax_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v8i8")] + fn vmax_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; + } +vmax_u8_(a, b) } -/// Unsigned saturating shift left +/// Maximum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshlq_n_u64(a: uint64x2_t) -> uint64x2_t { - static_assert_imm6!(N); - vqshlq_u64(a, vdupq_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmaxq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v16i8")] + fn vmaxq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; + } +vmaxq_u8_(a, b) } -/// Signed saturating shift right narrow +/// Maximum (vector) #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_s16(a: int16x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmax_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftns.v8i8")] - fn vqshrn_n_s16_(a: int16x8_t, n: int16x8_t) -> int8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v4i16")] + fn vmax_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; } -vqshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) +vmax_u16_(a, b) } -/// Signed saturating shift right narrow +/// Maximum (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_s16(a: int16x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmaxq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrn.v8i8")] - fn vqshrn_n_s16_(a: int16x8_t, n: i32) -> int8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v8i16")] + fn vmaxq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; } -vqshrn_n_s16_(a, N) +vmaxq_u16_(a, b) } -/// Signed saturating shift right narrow +/// Maximum (vector) #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_s32(a: int32x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmax_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftns.v4i16")] - fn vqshrn_n_s32_(a: int32x4_t, n: int32x4_t) -> int16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v2i32")] + fn vmax_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; } -vqshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) +vmax_u32_(a, b) } -/// Signed saturating shift right narrow +/// Maximum (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_s32(a: int32x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmaxq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrn.v4i16")] - fn vqshrn_n_s32_(a: int32x4_t, n: i32) -> int16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v4i32")] + fn vmaxq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; } -vqshrn_n_s32_(a, N) +vmaxq_u32_(a, b) } -/// Signed saturating shift right narrow +/// Maximum (vector) #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_s64(a: int64x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] +pub unsafe fn vmax_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftns.v2i32")] - fn vqshrn_n_s64_(a: int64x2_t, n: int64x2_t) -> int32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v2f32")] + fn vmax_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; } -vqshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) +vmax_f32_(a, b) } -/// Signed saturating shift right narrow +/// Maximum (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_s64(a: int64x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrn.v2i32")] - fn vqshrn_n_s64_(a: int64x2_t, n: i32) -> int32x2_t; - } -vqshrn_n_s64_(a, N) -} - -/// Unsigned saturating shift right narrow -#[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_u16(a: uint16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] +pub unsafe fn vmaxq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnu.v8i8")] - fn vqshrn_n_u16_(a: uint16x8_t, n: uint16x8_t) -> uint8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v4f32")] + fn vmaxq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; } -vqshrn_n_u16_(a, uint16x8_t(-N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16)) +vmaxq_f32_(a, b) } -/// Unsigned saturating shift right narrow +/// Floating-point Maximun Number (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_u16(a: uint16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); +#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmaxnm))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmaxnm))] +pub unsafe fn vmaxnm_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshrn.v8i8")] - fn vqshrn_n_u16_(a: uint16x8_t, n: i32) -> uint8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxnm.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnm.v2f32")] + fn vmaxnm_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; } -vqshrn_n_u16_(a, N) +vmaxnm_f32_(a, b) } -/// Unsigned saturating shift right narrow +/// Floating-point Maximun Number (vector) #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_u32(a: uint32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmaxnm))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmaxnm))] +pub unsafe fn vmaxnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnu.v4i16")] - fn vqshrn_n_u32_(a: uint32x4_t, n: uint32x4_t) -> uint16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxnm.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxnm.v4f32")] + fn vmaxnmq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; } -vqshrn_n_u32_(a, uint32x4_t(-N as u32, -N as u32, -N as u32, -N as u32)) +vmaxnmq_f32_(a, b) } -/// Unsigned saturating shift right narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_u32(a: uint32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vmin_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshrn.v4i16")] - fn vqshrn_n_u32_(a: uint32x4_t, n: i32) -> uint16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v8i8")] + fn vmin_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; } -vqshrn_n_u32_(a, N) +vmin_s8_(a, b) } -/// Unsigned saturating shift right narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_u64(a: uint64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vminq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnu.v2i32")] - fn vqshrn_n_u64_(a: uint64x2_t, n: uint64x2_t) -> uint32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v16i8")] + fn vminq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; } -vqshrn_n_u64_(a, uint64x2_t(-N as u64, -N as u64)) +vminq_s8_(a, b) } -/// Unsigned saturating shift right narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrn_n_u64(a: uint64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vmin_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshrn.v2i32")] - fn vqshrn_n_u64_(a: uint64x2_t, n: i32) -> uint32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v4i16")] + fn vmin_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; } -vqshrn_n_u64_(a, N) +vmin_s16_(a, b) } -/// Signed saturating shift right unsigned narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrun_n_s16(a: int16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vminq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnsu.v8i8")] - fn vqshrun_n_s16_(a: int16x8_t, n: int16x8_t) -> uint8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v8i16")] + fn vminq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; } -vqshrun_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) +vminq_s16_(a, b) } -/// Signed saturating shift right unsigned narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrun_n_s16(a: int16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vmin_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrun.v8i8")] - fn vqshrun_n_s16_(a: int16x8_t, n: i32) -> uint8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v2i32")] + fn vmin_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; } -vqshrun_n_s16_(a, N) +vmin_s32_(a, b) } -/// Signed saturating shift right unsigned narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrun_n_s32(a: int32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vminq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnsu.v4i16")] - fn vqshrun_n_s32_(a: int32x4_t, n: int32x4_t) -> uint16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v4i32")] + fn vminq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; } -vqshrun_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) +vminq_s32_(a, b) } -/// Signed saturating shift right unsigned narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrun_n_s32(a: int32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vmin_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrun.v4i16")] - fn vqshrun_n_s32_(a: int32x4_t, n: i32) -> uint16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v8i8")] + fn vmin_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; } -vqshrun_n_s32_(a, N) +vmin_u8_(a, b) } -/// Signed saturating shift right unsigned narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrun_n_s64(a: int64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vminq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnsu.v2i32")] - fn vqshrun_n_s64_(a: int64x2_t, n: int64x2_t) -> uint32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v16i8")] + fn vminq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; } -vqshrun_n_s64_(a, int64x2_t(-N as i64, -N as i64)) +vminq_u8_(a, b) } -/// Signed saturating shift right unsigned narrow +/// Minimum (vector) #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrun, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vqshrun_n_s64(a: int64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vmin_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrun.v2i32")] - fn vqshrun_n_s64_(a: int64x2_t, n: i32) -> uint32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v4i16")] + fn vmin_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; } -vqshrun_n_s64_(a, N) +vmin_u16_(a, b) } -/// Reciprocal square-root estimate. +/// Minimum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsqrte))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frsqrte))] -pub unsafe fn vrsqrte_f32(a: float32x2_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vminq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrsqrte.v2f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frsqrte.v2f32")] - fn vrsqrte_f32_(a: float32x2_t) -> float32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v8i16")] + fn vminq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; } -vrsqrte_f32_(a) +vminq_u16_(a, b) } -/// Reciprocal square-root estimate. +/// Minimum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsqrte))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frsqrte))] -pub unsafe fn vrsqrteq_f32(a: float32x4_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vmin_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrsqrte.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frsqrte.v4f32")] - fn vrsqrteq_f32_(a: float32x4_t) -> float32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v2i32")] + fn vmin_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; } -vrsqrteq_f32_(a) +vmin_u32_(a, b) } -/// Reciprocal estimate. +/// Minimum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrecpe))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frecpe))] -pub unsafe fn vrecpe_f32(a: float32x2_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vminq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrecpe.v2f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frecpe.v2f32")] - fn vrecpe_f32_(a: float32x2_t) -> float32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v4i32")] + fn vminq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; } -vrecpe_f32_(a) +vminq_u32_(a, b) } -/// Reciprocal estimate. +/// Minimum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrecpe))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frecpe))] -pub unsafe fn vrecpeq_f32(a: float32x4_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] +pub unsafe fn vmin_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrecpe.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frecpe.v4f32")] - fn vrecpeq_f32_(a: float32x4_t) -> float32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v2f32")] + fn vmin_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; } -vrecpeq_f32_(a) +vmin_f32_(a, b) } -/// Vector reinterpret cast operation +/// Minimum (vector) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_u8(a: uint8x8_t) -> int8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] +pub unsafe fn vminq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v4f32")] + fn vminq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; + } +vminq_f32_(a, b) } -/// Vector reinterpret cast operation +/// Floating-point Minimun Number (vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_p8(a: poly8x8_t) -> int8x8_t { - transmute(a) +#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vminnm))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fminnm))] +pub unsafe fn vminnm_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminnm.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnm.v2f32")] + fn vminnm_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; + } +vminnm_f32_(a, b) } -/// Vector reinterpret cast operation +/// Floating-point Minimun Number (vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_p16(a: poly16x4_t) -> int16x4_t { - transmute(a) +#[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vminnm))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fminnm))] +pub unsafe fn vminnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminnm.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fminnm.v4f32")] + fn vminnmq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; + } +vminnmq_f32_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_u16(a: uint16x4_t) -> int16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull))] +pub unsafe fn vqdmull_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmull.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmull.v4i32")] + fn vqdmull_s16_(a: int16x4_t, b: int16x4_t) -> int32x4_t; + } +vqdmull_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_u32(a: uint32x2_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull))] +pub unsafe fn vqdmull_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmull.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmull.v2i64")] + fn vqdmull_s32_(a: int32x2_t, b: int32x2_t) -> int64x2_t; + } +vqdmull_s32_(a, b) } -/// Vector reinterpret cast operation +/// Vector saturating doubling long multiply with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_u64(a: uint64x1_t) -> int64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull))] +pub unsafe fn vqdmull_n_s16(a: int16x4_t, b: i16) -> int32x4_t { + vqdmull_s16(a, vdup_n_s16(b)) } -/// Vector reinterpret cast operation +/// Vector saturating doubling long multiply with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_u8(a: uint8x16_t) -> int8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull))] +pub unsafe fn vqdmull_n_s32(a: int32x2_t, b: i32) -> int64x2_t { + vqdmull_s32(a, vdup_n_s32(b)) } -/// Vector reinterpret cast operation +/// Vector saturating doubling long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_p8(a: poly8x16_t) -> int8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqdmull_lane_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { + static_assert_imm2!(N); + let b: int16x4_t = simd_shuffle4!(b, b, [N as u32, N as u32, N as u32, N as u32]); + vqdmull_s16(a, b) } -/// Vector reinterpret cast operation +/// Vector saturating doubling long multiply by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_p16(a: poly16x8_t) -> int16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmull, N = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmull, N = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqdmull_lane_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { + static_assert_imm1!(N); + let b: int32x2_t = simd_shuffle2!(b, b, [N as u32, N as u32]); + vqdmull_s32(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply-add long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_u16(a: uint16x8_t) -> int16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal))] +pub unsafe fn vqdmlal_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { + vqaddq_s32(a, vqdmull_s16(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply-add long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_u32(a: uint32x4_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal))] +pub unsafe fn vqdmlal_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { + vqaddq_s64(a, vqdmull_s32(b, c)) } -/// Vector reinterpret cast operation +/// Vector widening saturating doubling multiply accumulate with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_u64(a: uint64x2_t) -> int64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal))] +pub unsafe fn vqdmlal_n_s16(a: int32x4_t, b: int16x4_t, c: i16) -> int32x4_t { + vqaddq_s32(a, vqdmull_n_s16(b, c)) } -/// Vector reinterpret cast operation +/// Vector widening saturating doubling multiply accumulate with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_p8(a: poly8x8_t) -> uint8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal))] +pub unsafe fn vqdmlal_n_s32(a: int64x2_t, b: int32x2_t, c: i32) -> int64x2_t { + vqaddq_s64(a, vqdmull_n_s32(b, c)) } -/// Vector reinterpret cast operation +/// Vector widening saturating doubling multiply accumulate with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_s8(a: int8x8_t) -> uint8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal, N = 2))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqdmlal_lane_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { + static_assert_imm2!(N); + vqaddq_s32(a, vqdmull_lane_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Vector widening saturating doubling multiply accumulate with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_p16(a: poly16x4_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlal, N = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlal, N = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqdmlal_lane_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { + static_assert_imm1!(N); + vqaddq_s64(a, vqdmull_lane_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply-subtract long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_s16(a: int16x4_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl))] +pub unsafe fn vqdmlsl_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { + vqsubq_s32(a, vqdmull_s16(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply-subtract long #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_s32(a: int32x2_t) -> uint32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl))] +pub unsafe fn vqdmlsl_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { + vqsubq_s64(a, vqdmull_s32(b, c)) } -/// Vector reinterpret cast operation +/// Vector widening saturating doubling multiply subtract with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_s64(a: int64x1_t) -> uint64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl))] +pub unsafe fn vqdmlsl_n_s16(a: int32x4_t, b: int16x4_t, c: i16) -> int32x4_t { + vqsubq_s32(a, vqdmull_n_s16(b, c)) } -/// Vector reinterpret cast operation +/// Vector widening saturating doubling multiply subtract with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_p8(a: poly8x16_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl))] +pub unsafe fn vqdmlsl_n_s32(a: int64x2_t, b: int32x2_t, c: i32) -> int64x2_t { + vqsubq_s64(a, vqdmull_n_s32(b, c)) } -/// Vector reinterpret cast operation +/// Vector widening saturating doubling multiply subtract with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_s8(a: int8x16_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl, N = 2))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqdmlsl_lane_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { + static_assert_imm2!(N); + vqsubq_s32(a, vqdmull_lane_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Vector widening saturating doubling multiply subtract with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_p16(a: poly16x8_t) -> uint16x8_t { - transmute(a) -} - -/// Vector reinterpret cast operation -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_s16(a: int16x8_t) -> uint16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmlsl, N = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmlsl, N = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqdmlsl_lane_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { + static_assert_imm1!(N); + vqsubq_s64(a, vqdmull_lane_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_s32(a: int32x4_t) -> uint32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] +pub unsafe fn vqdmulh_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmulh.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulh.v4i16")] + fn vqdmulh_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + } +vqdmulh_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_s64(a: int64x2_t) -> uint64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] +pub unsafe fn vqdmulhq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmulh.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulh.v8i16")] + fn vqdmulhq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + } +vqdmulhq_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_s8(a: int8x8_t) -> poly8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] +pub unsafe fn vqdmulh_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmulh.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulh.v2i32")] + fn vqdmulh_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + } +vqdmulh_s32_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating doubling multiply returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_u8(a: uint8x8_t) -> poly8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] +pub unsafe fn vqdmulhq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqdmulh.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqdmulh.v4i32")] + fn vqdmulhq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + } +vqdmulhq_s32_(a, b) } -/// Vector reinterpret cast operation +/// Vector saturating doubling multiply high with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_s16(a: int16x4_t) -> poly16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] +pub unsafe fn vqdmulh_n_s16(a: int16x4_t, b: i16) -> int16x4_t { + let b: int16x4_t = vdup_n_s16(b); + vqdmulh_s16(a, b) } -/// Vector reinterpret cast operation +/// Vector saturating doubling multiply high with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_u16(a: uint16x4_t) -> poly16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] +pub unsafe fn vqdmulh_n_s32(a: int32x2_t, b: i32) -> int32x2_t { + let b: int32x2_t = vdup_n_s32(b); + vqdmulh_s32(a, b) } -/// Vector reinterpret cast operation +/// Vector saturating doubling multiply high with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_s8(a: int8x16_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] +pub unsafe fn vqdmulhq_n_s16(a: int16x8_t, b: i16) -> int16x8_t { + let b: int16x8_t = vdupq_n_s16(b); + vqdmulhq_s16(a, b) } -/// Vector reinterpret cast operation +/// Vector saturating doubling multiply high with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_u8(a: uint8x16_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqdmulh))] +pub unsafe fn vqdmulhq_n_s32(a: int32x4_t, b: i32) -> int32x4_t { + let b: int32x4_t = vdupq_n_s32(b); + vqdmulhq_s32(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating extract narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_s16(a: int16x8_t) -> poly16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtn))] +pub unsafe fn vqmovn_s16(a: int16x8_t) -> int8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovns.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtn.v8i8")] + fn vqmovn_s16_(a: int16x8_t) -> int8x8_t; + } +vqmovn_s16_(a) } -/// Vector reinterpret cast operation +/// Signed saturating extract narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_u16(a: uint16x8_t) -> poly16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtn))] +pub unsafe fn vqmovn_s32(a: int32x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovns.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtn.v4i16")] + fn vqmovn_s32_(a: int32x4_t) -> int16x4_t; + } +vqmovn_s32_(a) } -/// Vector reinterpret cast operation +/// Signed saturating extract narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_s16(a: int16x4_t) -> int8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtn))] +pub unsafe fn vqmovn_s64(a: int64x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovns.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtn.v2i32")] + fn vqmovn_s64_(a: int64x2_t) -> int32x2_t; + } +vqmovn_s64_(a) } -/// Vector reinterpret cast operation +/// Unsigned saturating extract narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_u16(a: uint16x4_t) -> int8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqxtn))] +pub unsafe fn vqmovn_u16(a: uint16x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqxtn.v8i8")] + fn vqmovn_u16_(a: uint16x8_t) -> uint8x8_t; + } +vqmovn_u16_(a) } -/// Vector reinterpret cast operation +/// Unsigned saturating extract narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_p16(a: poly16x4_t) -> int8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqxtn))] +pub unsafe fn vqmovn_u32(a: uint32x4_t) -> uint16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqxtn.v4i16")] + fn vqmovn_u32_(a: uint32x4_t) -> uint16x4_t; + } +vqmovn_u32_(a) } -/// Vector reinterpret cast operation +/// Unsigned saturating extract narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_s32(a: int32x2_t) -> int16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqxtn))] +pub unsafe fn vqmovn_u64(a: uint64x2_t) -> uint32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqxtn.v2i32")] + fn vqmovn_u64_(a: uint64x2_t) -> uint32x2_t; + } +vqmovn_u64_(a) } -/// Vector reinterpret cast operation +/// Signed saturating extract unsigned narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_u32(a: uint32x2_t) -> int16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovun))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtun))] +pub unsafe fn vqmovun_s16(a: int16x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnsu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtun.v8i8")] + fn vqmovun_s16_(a: int16x8_t) -> uint8x8_t; + } +vqmovun_s16_(a) } -/// Vector reinterpret cast operation +/// Signed saturating extract unsigned narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_s64(a: int64x1_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovun))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtun))] +pub unsafe fn vqmovun_s32(a: int32x4_t) -> uint16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnsu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtun.v4i16")] + fn vqmovun_s32_(a: int32x4_t) -> uint16x4_t; + } +vqmovun_s32_(a) } -/// Vector reinterpret cast operation +/// Signed saturating extract unsigned narrow #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_u64(a: uint64x1_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovun))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqxtun))] +pub unsafe fn vqmovun_s64(a: int64x2_t) -> uint32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqmovnsu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqxtun.v2i32")] + fn vqmovun_s64_(a: int64x2_t) -> uint32x2_t; + } +vqmovun_s64_(a) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_s16(a: int16x8_t) -> int8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmulh_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrdmulh.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrdmulh.v4i16")] + fn vqrdmulh_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + } +vqrdmulh_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_u16(a: uint16x8_t) -> int8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmulhq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrdmulh.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrdmulh.v8i16")] + fn vqrdmulhq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + } +vqrdmulhq_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_p16(a: poly16x8_t) -> int8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmulh_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrdmulh.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrdmulh.v2i32")] + fn vqrdmulh_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + } +vqrdmulh_s32_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_s32(a: int32x4_t) -> int16x8_t { - transmute(a) -} +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmulhq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrdmulh.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrdmulh.v4i32")] + fn vqrdmulhq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + } +vqrdmulhq_s32_(a, b) +} -/// Vector reinterpret cast operation +/// Vector saturating rounding doubling multiply high with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_u32(a: uint32x4_t) -> int16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmulh_n_s16(a: int16x4_t, b: i16) -> int16x4_t { + vqrdmulh_s16(a, vdup_n_s16(b)) } -/// Vector reinterpret cast operation +/// Vector saturating rounding doubling multiply high with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_s64(a: int64x2_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmulhq_n_s16(a: int16x8_t, b: i16) -> int16x8_t { + vqrdmulhq_s16(a, vdupq_n_s16(b)) } -/// Vector reinterpret cast operation +/// Vector saturating rounding doubling multiply high with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_u64(a: uint64x2_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmulh_n_s32(a: int32x2_t, b: i32) -> int32x2_t { + vqrdmulh_s32(a, vdup_n_s32(b)) } -/// Vector reinterpret cast operation +/// Vector saturating rounding doubling multiply high with scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_p16(a: poly16x4_t) -> uint8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmulhq_n_s32(a: int32x4_t, b: i32) -> int32x4_t { + vqrdmulhq_s32(a, vdupq_n_s32(b)) } -/// Vector reinterpret cast operation +/// Vector rounding saturating doubling multiply high by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_s16(a: int16x4_t) -> uint8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqrdmulh_lane_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + static_assert_imm2!(LANE); + let b: int16x4_t = simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32]); + vqrdmulh_s16(a, b) } -/// Vector reinterpret cast operation +/// Vector rounding saturating doubling multiply high by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_u16(a: uint16x4_t) -> uint8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqrdmulh_laneq_s16(a: int16x4_t, b: int16x8_t) -> int16x4_t { + static_assert_imm3!(LANE); + let b: int16x4_t = simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32]); + vqrdmulh_s16(a, b) } -/// Vector reinterpret cast operation +/// Vector rounding saturating doubling multiply high by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_s32(a: int32x2_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqrdmulhq_lane_s16(a: int16x8_t, b: int16x4_t) -> int16x8_t { + static_assert_imm2!(LANE); + let b: int16x8_t = simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32]); + vqrdmulhq_s16(a, b) } -/// Vector reinterpret cast operation +/// Vector rounding saturating doubling multiply high by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_u32(a: uint32x2_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqrdmulhq_laneq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + static_assert_imm3!(LANE); + let b: int16x8_t = simd_shuffle8!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32, LANE as u32]); + vqrdmulhq_s16(a, b) } -/// Vector reinterpret cast operation +/// Vector rounding saturating doubling multiply high by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_s64(a: int64x1_t) -> uint32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqrdmulh_lane_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + static_assert_imm1!(LANE); + let b: int32x2_t = simd_shuffle2!(b, b, [LANE as u32, LANE as u32]); + vqrdmulh_s32(a, b) } -/// Vector reinterpret cast operation +/// Vector rounding saturating doubling multiply high by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_u64(a: uint64x1_t) -> uint32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqrdmulh_laneq_s32(a: int32x2_t, b: int32x4_t) -> int32x2_t { + static_assert_imm2!(LANE); + let b: int32x2_t = simd_shuffle2!(b, b, [LANE as u32, LANE as u32]); + vqrdmulh_s32(a, b) } -/// Vector reinterpret cast operation +/// Vector rounding saturating doubling multiply high by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_p16(a: poly16x8_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqrdmulhq_lane_s32(a: int32x4_t, b: int32x2_t) -> int32x4_t { + static_assert_imm1!(LANE); + let b: int32x4_t = simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32]); + vqrdmulhq_s32(a, b) } -/// Vector reinterpret cast operation +/// Vector rounding saturating doubling multiply high by scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_s16(a: int16x8_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vqrdmulhq_laneq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + static_assert_imm2!(LANE); + let b: int32x4_t = simd_shuffle4!(b, b, [LANE as u32, LANE as u32, LANE as u32, LANE as u32]); + vqrdmulhq_s32(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_u16(a: uint16x8_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmlah_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { + vqadd_s16(a, vqrdmulh_s16(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_s32(a: int32x4_t) -> uint16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmlahq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { + vqaddq_s16(a, vqrdmulhq_s16(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_u32(a: uint32x4_t) -> uint16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmlah_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { + vqadd_s32(a, vqrdmulh_s32(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_s64(a: int64x2_t) -> uint32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmlahq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { + vqaddq_s32(a, vqrdmulhq_s32(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_u64(a: uint64x2_t) -> uint32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlah_lane_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { + static_assert_imm2!(LANE); + vqadd_s16(a, vqrdmulh_lane_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_p16(a: poly16x4_t) -> poly8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlah_laneq_s16(a: int16x4_t, b: int16x4_t, c: int16x8_t) -> int16x4_t { + static_assert_imm3!(LANE); + vqadd_s16(a, vqrdmulh_laneq_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_s16(a: int16x4_t) -> poly8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlahq_lane_s16(a: int16x8_t, b: int16x8_t, c: int16x4_t) -> int16x8_t { + static_assert_imm2!(LANE); + vqaddq_s16(a, vqrdmulhq_lane_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_u16(a: uint16x4_t) -> poly8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlahq_laneq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { + static_assert_imm3!(LANE); + vqaddq_s16(a, vqrdmulhq_laneq_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_s32(a: int32x2_t) -> poly16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlah_lane_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { + static_assert_imm1!(LANE); + vqadd_s32(a, vqrdmulh_lane_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_u32(a: uint32x2_t) -> poly16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlah_laneq_s32(a: int32x2_t, b: int32x2_t, c: int32x4_t) -> int32x2_t { + static_assert_imm2!(LANE); + vqadd_s32(a, vqrdmulh_laneq_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_p16(a: poly16x8_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlahq_lane_s32(a: int32x4_t, b: int32x4_t, c: int32x2_t) -> int32x4_t { + static_assert_imm1!(LANE); + vqaddq_s32(a, vqrdmulhq_lane_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply accumulate returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_s16(a: int16x8_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlahq_laneq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { + static_assert_imm2!(LANE); + vqaddq_s32(a, vqrdmulhq_laneq_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_u16(a: uint16x8_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmlsh_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { + vqsub_s16(a, vqrdmulh_s16(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_s32(a: int32x4_t) -> poly16x8_t { - transmute(a) -} - -/// Vector reinterpret cast operation -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_u32(a: uint32x4_t) -> poly16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmlshq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { + vqsubq_s16(a, vqrdmulhq_s16(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_p8(a: poly8x8_t) -> int16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmlsh_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { + vqsub_s32(a, vqrdmulh_s32(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_s8(a: int8x8_t) -> int16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh))] +pub unsafe fn vqrdmlshq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { + vqsubq_s32(a, vqrdmulhq_s32(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_u8(a: uint8x8_t) -> int16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlsh_lane_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { + static_assert_imm2!(LANE); + vqsub_s16(a, vqrdmulh_lane_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_p16(a: poly16x4_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlsh_laneq_s16(a: int16x4_t, b: int16x4_t, c: int16x8_t) -> int16x4_t { + static_assert_imm3!(LANE); + vqsub_s16(a, vqrdmulh_laneq_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_s16(a: int16x4_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlshq_lane_s16(a: int16x8_t, b: int16x8_t, c: int16x4_t) -> int16x8_t { + static_assert_imm2!(LANE); + vqsubq_s16(a, vqrdmulhq_lane_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_u16(a: uint16x4_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlshq_laneq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { + static_assert_imm3!(LANE); + vqsubq_s16(a, vqrdmulhq_laneq_s16::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_s32(a: int32x2_t) -> int64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlsh_lane_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { + static_assert_imm1!(LANE); + vqsub_s32(a, vqrdmulh_lane_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_u32(a: uint32x2_t) -> int64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlsh_laneq_s32(a: int32x2_t, b: int32x2_t, c: int32x4_t) -> int32x2_t { + static_assert_imm2!(LANE); + vqsub_s32(a, vqrdmulh_laneq_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_p8(a: poly8x16_t) -> int16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlshq_lane_s32(a: int32x4_t, b: int32x4_t, c: int32x2_t) -> int32x4_t { + static_assert_imm1!(LANE); + vqsubq_s32(a, vqrdmulhq_lane_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding doubling multiply subtract returning high half #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_s8(a: int8x16_t) -> int16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrdmulh, LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrdmulh, LANE = 1))] +#[rustc_legacy_const_generics(3)] +pub unsafe fn vqrdmlshq_laneq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { + static_assert_imm2!(LANE); + vqsubq_s32(a, vqrdmulhq_laneq_s32::(b, c)) } -/// Vector reinterpret cast operation +/// Signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_u8(a: uint8x16_t) -> int16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] +pub unsafe fn vqrshl_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v8i8")] + fn vqrshl_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + } +vqrshl_s8_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_p16(a: poly16x8_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] +pub unsafe fn vqrshlq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v16i8")] + fn vqrshlq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + } +vqrshlq_s8_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_s16(a: int16x8_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] +pub unsafe fn vqrshl_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v4i16")] + fn vqrshl_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + } +vqrshl_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_u16(a: uint16x8_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] +pub unsafe fn vqrshlq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v8i16")] + fn vqrshlq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + } +vqrshlq_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_s32(a: int32x4_t) -> int64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] +pub unsafe fn vqrshl_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v2i32")] + fn vqrshl_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + } +vqrshl_s32_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_u32(a: uint32x4_t) -> int64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] +pub unsafe fn vqrshlq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v4i32")] + fn vqrshlq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + } +vqrshlq_s32_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_p8(a: poly8x8_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] +pub unsafe fn vqrshl_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v1i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v1i64")] + fn vqrshl_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; + } +vqrshl_s64_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_s8(a: int8x8_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshl))] +pub unsafe fn vqrshlq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshifts.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshl.v2i64")] + fn vqrshlq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; + } +vqrshlq_s64_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_u8(a: uint8x8_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] +pub unsafe fn vqrshl_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v8i8")] + fn vqrshl_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; + } +vqrshl_u8_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_p16(a: poly16x4_t) -> uint32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] +pub unsafe fn vqrshlq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v16i8")] + fn vqrshlq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; + } +vqrshlq_u8_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_s16(a: int16x4_t) -> uint32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] +pub unsafe fn vqrshl_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v4i16")] + fn vqrshl_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; + } +vqrshl_u16_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_u16(a: uint16x4_t) -> uint32x2_t { - transmute(a) -} - -/// Vector reinterpret cast operation +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] +pub unsafe fn vqrshlq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v8i16")] + fn vqrshlq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; + } +vqrshlq_u16_(a, b) +} + +/// Unsigned signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_s32(a: int32x2_t) -> uint64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] +pub unsafe fn vqrshl_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v2i32")] + fn vqrshl_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; + } +vqrshl_u32_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] +pub unsafe fn vqrshlq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v4i32")] + fn vqrshlq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; + } +vqrshlq_u32_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_p8(a: poly8x16_t) -> uint16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] +pub unsafe fn vqrshl_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v1i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v1i64")] + fn vqrshl_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; + } +vqrshl_u64_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_s8(a: int8x16_t) -> uint16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshl))] +pub unsafe fn vqrshlq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftu.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshl.v2i64")] + fn vqrshlq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; + } +vqrshlq_u64_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_u8(a: uint8x16_t) -> uint16x8_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_s16(a: int16x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftns.v8i8")] + fn vqrshrn_n_s16_(a: int16x8_t, n: int16x8_t) -> int8x8_t; + } +vqrshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_p16(a: poly16x8_t) -> uint32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_s16(a: int16x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrn.v8i8")] + fn vqrshrn_n_s16_(a: int16x8_t, n: i32) -> int8x8_t; + } +vqrshrn_n_s16_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_s16(a: int16x8_t) -> uint32x4_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_s32(a: int32x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftns.v4i16")] + fn vqrshrn_n_s32_(a: int32x4_t, n: int32x4_t) -> int16x4_t; + } +vqrshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_u16(a: uint16x8_t) -> uint32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_s32(a: int32x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrn.v4i16")] + fn vqrshrn_n_s32_(a: int32x4_t, n: i32) -> int16x4_t; + } +vqrshrn_n_s32_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_s32(a: int32x4_t) -> uint64x2_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_s64(a: int64x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftns.v2i32")] + fn vqrshrn_n_s64_(a: int64x2_t, n: int64x2_t) -> int32x2_t; + } +vqrshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_u32(a: uint32x4_t) -> uint64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_s64(a: int64x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrn.v2i32")] + fn vqrshrn_n_s64_(a: int64x2_t, n: i32) -> int32x2_t; + } +vqrshrn_n_s64_(a, N) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounded shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_p8(a: poly8x8_t) -> poly16x4_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_u16(a: uint16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnu.v8i8")] + fn vqrshrn_n_u16_(a: uint16x8_t, n: uint16x8_t) -> uint8x8_t; + } +vqrshrn_n_u16_(a, uint16x8_t(-N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16)) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounded shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_s8(a: int8x8_t) -> poly16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_u16(a: uint16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshrn.v8i8")] + fn vqrshrn_n_u16_(a: uint16x8_t, n: i32) -> uint8x8_t; + } +vqrshrn_n_u16_(a, N) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounded shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_u8(a: uint8x8_t) -> poly16x4_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_u32(a: uint32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnu.v4i16")] + fn vqrshrn_n_u32_(a: uint32x4_t, n: uint32x4_t) -> uint16x4_t; + } +vqrshrn_n_u32_(a, uint32x4_t(-N as u32, -N as u32, -N as u32, -N as u32)) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounded shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_p8(a: poly8x16_t) -> poly16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_u32(a: uint32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshrn.v4i16")] + fn vqrshrn_n_u32_(a: uint32x4_t, n: i32) -> uint16x4_t; + } +vqrshrn_n_u32_(a, N) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounded shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_s8(a: int8x16_t) -> poly16x8_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_u64(a: uint64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnu.v2i32")] + fn vqrshrn_n_u64_(a: uint64x2_t, n: uint64x2_t) -> uint32x2_t; + } +vqrshrn_n_u64_(a, uint64x2_t(-N as u64, -N as u64)) } -/// Vector reinterpret cast operation +/// Unsigned signed saturating rounded shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_u8(a: uint8x16_t) -> poly16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrn_n_u64(a: uint64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqrshrn.v2i32")] + fn vqrshrn_n_u64_(a: uint64x2_t, n: i32) -> uint32x2_t; + } +vqrshrn_n_u64_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right unsigned narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_s32(a: int32x2_t) -> int8x8_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrun_n_s16(a: int16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnsu.v8i8")] + fn vqrshrun_n_s16_(a: int16x8_t, n: int16x8_t) -> uint8x8_t; + } +vqrshrun_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right unsigned narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_u32(a: uint32x2_t) -> int8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrun_n_s16(a: int16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrun.v8i8")] + fn vqrshrun_n_s16_(a: int16x8_t, n: i32) -> uint8x8_t; + } +vqrshrun_n_s16_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right unsigned narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_s64(a: int64x1_t) -> int16x4_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrun_n_s32(a: int32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnsu.v4i16")] + fn vqrshrun_n_s32_(a: int32x4_t, n: int32x4_t) -> uint16x4_t; + } +vqrshrun_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right unsigned narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_u64(a: uint64x1_t) -> int16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrun_n_s32(a: int32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrun.v4i16")] + fn vqrshrun_n_s32_(a: int32x4_t, n: i32) -> uint16x4_t; + } +vqrshrun_n_s32_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right unsigned narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_s32(a: int32x4_t) -> int8x16_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqrshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrun_n_s64(a: int64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqrshiftnsu.v2i32")] + fn vqrshrun_n_s64_(a: int64x2_t, n: int64x2_t) -> uint32x2_t; + } +vqrshrun_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } -/// Vector reinterpret cast operation +/// Signed saturating rounded shift right unsigned narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_u32(a: uint32x4_t) -> int8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqrshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqrshrun_n_s64(a: int64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqrshrun.v2i32")] + fn vqrshrun_n_s64_(a: int64x2_t, n: i32) -> uint32x2_t; + } +vqrshrun_n_s64_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_s64(a: int64x2_t) -> int16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] +pub unsafe fn vqshl_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v8i8")] + fn vqshl_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + } +vqshl_s8_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_u64(a: uint64x2_t) -> int16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] +pub unsafe fn vqshlq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v16i8")] + fn vqshlq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + } +vqshlq_s8_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_s32(a: int32x2_t) -> uint8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] +pub unsafe fn vqshl_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v4i16")] + fn vqshl_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + } +vqshl_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_u32(a: uint32x2_t) -> uint8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] +pub unsafe fn vqshlq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v8i16")] + fn vqshlq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + } +vqshlq_s16_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_s64(a: int64x1_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] +pub unsafe fn vqshl_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v2i32")] + fn vqshl_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + } +vqshl_s32_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_u64(a: uint64x1_t) -> uint16x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] +pub unsafe fn vqshlq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v4i32")] + fn vqshlq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + } +vqshlq_s32_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_s32(a: int32x4_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] +pub unsafe fn vqshl_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v1i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v1i64")] + fn vqshl_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; + } +vqshl_s64_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_u32(a: uint32x4_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl))] +pub unsafe fn vqshlq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshifts.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshl.v2i64")] + fn vqshlq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; + } +vqshlq_s64_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_s64(a: int64x2_t) -> uint16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] +pub unsafe fn vqshl_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v8i8")] + fn vqshl_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; + } +vqshl_u8_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_u64(a: uint64x2_t) -> uint16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] +pub unsafe fn vqshlq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v16i8")] + fn vqshlq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; + } +vqshlq_u8_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_s32(a: int32x2_t) -> poly8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] +pub unsafe fn vqshl_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v4i16")] + fn vqshl_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; + } +vqshl_u16_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_u32(a: uint32x2_t) -> poly8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] +pub unsafe fn vqshlq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v8i16")] + fn vqshlq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; + } +vqshlq_u16_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_s64(a: int64x1_t) -> poly16x4_t { - transmute(a) -} - -/// Vector reinterpret cast operation -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_u64(a: uint64x1_t) -> poly16x4_t { - transmute(a) -} - -/// Vector reinterpret cast operation -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_s32(a: int32x4_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] +pub unsafe fn vqshl_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v2i32")] + fn vqshl_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; + } +vqshl_u32_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_u32(a: uint32x4_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] +pub unsafe fn vqshlq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v4i32")] + fn vqshlq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; + } +vqshlq_u32_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_s64(a: int64x2_t) -> poly16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] +pub unsafe fn vqshl_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v1i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v1i64")] + fn vqshl_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; + } +vqshl_u64_(a, b) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_u64(a: uint64x2_t) -> poly16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl))] +pub unsafe fn vqshlq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftu.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshl.v2i64")] + fn vqshlq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; + } +vqshlq_u64_(a, b) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_p8(a: poly8x8_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshl_n_s8(a: int8x8_t) -> int8x8_t { + static_assert_imm3!(N); + vqshl_s8(a, vdup_n_s8(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_s8(a: int8x8_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshlq_n_s8(a: int8x16_t) -> int8x16_t { + static_assert_imm3!(N); + vqshlq_s8(a, vdupq_n_s8(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_u8(a: uint8x8_t) -> int32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshl_n_s16(a: int16x4_t) -> int16x4_t { + static_assert_imm4!(N); + vqshl_s16(a, vdup_n_s16(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_p16(a: poly16x4_t) -> int64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshlq_n_s16(a: int16x8_t) -> int16x8_t { + static_assert_imm4!(N); + vqshlq_s16(a, vdupq_n_s16(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_s16(a: int16x4_t) -> int64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshl_n_s32(a: int32x2_t) -> int32x2_t { + static_assert_imm5!(N); + vqshl_s32(a, vdup_n_s32(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_u16(a: uint16x4_t) -> int64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshlq_n_s32(a: int32x4_t) -> int32x4_t { + static_assert_imm5!(N); + vqshlq_s32(a, vdupq_n_s32(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_p8(a: poly8x16_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshl_n_s64(a: int64x1_t) -> int64x1_t { + static_assert_imm6!(N); + vqshl_s64(a, vdup_n_s64(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Signed saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_s8(a: int8x16_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshlq_n_s64(a: int64x2_t) -> int64x2_t { + static_assert_imm6!(N); + vqshlq_s64(a, vdupq_n_s64(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_u8(a: uint8x16_t) -> int32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshl_n_u8(a: uint8x8_t) -> uint8x8_t { + static_assert_imm3!(N); + vqshl_u8(a, vdup_n_s8(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_p16(a: poly16x8_t) -> int64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshlq_n_u8(a: uint8x16_t) -> uint8x16_t { + static_assert_imm3!(N); + vqshlq_u8(a, vdupq_n_s8(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_s16(a: int16x8_t) -> int64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshl_n_u16(a: uint16x4_t) -> uint16x4_t { + static_assert_imm4!(N); + vqshl_u16(a, vdup_n_s16(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_u16(a: uint16x8_t) -> int64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshlq_n_u16(a: uint16x8_t) -> uint16x8_t { + static_assert_imm4!(N); + vqshlq_u16(a, vdupq_n_s16(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_p8(a: poly8x8_t) -> uint32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshl_n_u32(a: uint32x2_t) -> uint32x2_t { + static_assert_imm5!(N); + vqshl_u32(a, vdup_n_s32(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_s8(a: int8x8_t) -> uint32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshlq_n_u32(a: uint32x4_t) -> uint32x4_t { + static_assert_imm5!(N); + vqshlq_u32(a, vdupq_n_s32(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_u8(a: uint8x8_t) -> uint32x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshl_n_u64(a: uint64x1_t) -> uint64x1_t { + static_assert_imm6!(N); + vqshl_u64(a, vdup_n_s64(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_p16(a: poly16x4_t) -> uint64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshlq_n_u64(a: uint64x2_t) -> uint64x2_t { + static_assert_imm6!(N); + vqshlq_u64(a, vdupq_n_s64(N.try_into().unwrap())) } -/// Vector reinterpret cast operation +/// Signed saturating shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_s16(a: int16x4_t) -> uint64x1_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_s16(a: int16x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftns.v8i8")] + fn vqshrn_n_s16_(a: int16x8_t, n: int16x8_t) -> int8x8_t; + } +vqshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) } -/// Vector reinterpret cast operation +/// Signed saturating shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_u16(a: uint16x4_t) -> uint64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_s16(a: int16x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrn.v8i8")] + fn vqshrn_n_s16_(a: int16x8_t, n: i32) -> int8x8_t; + } +vqshrn_n_s16_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_p8(a: poly8x16_t) -> uint32x4_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_s32(a: int32x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftns.v4i16")] + fn vqshrn_n_s32_(a: int32x4_t, n: int32x4_t) -> int16x4_t; + } +vqshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } -/// Vector reinterpret cast operation +/// Signed saturating shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_s8(a: int8x16_t) -> uint32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_s32(a: int32x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrn.v4i16")] + fn vqshrn_n_s32_(a: int32x4_t, n: i32) -> int16x4_t; + } +vqshrn_n_s32_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_u8(a: uint8x16_t) -> uint32x4_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_s64(a: int64x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftns.v2i32")] + fn vqshrn_n_s64_(a: int64x2_t, n: int64x2_t) -> int32x2_t; + } +vqshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } -/// Vector reinterpret cast operation +/// Signed saturating shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_p16(a: poly16x8_t) -> uint64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_s64(a: int64x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrn.v2i32")] + fn vqshrn_n_s64_(a: int64x2_t, n: i32) -> int32x2_t; + } +vqshrn_n_s64_(a, N) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_s16(a: int16x8_t) -> uint64x2_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_u16(a: uint16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnu.v8i8")] + fn vqshrn_n_u16_(a: uint16x8_t, n: uint16x8_t) -> uint8x8_t; + } +vqshrn_n_u16_(a, uint16x8_t(-N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16, -N as u16)) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_u16(a: uint16x8_t) -> uint64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_u16(a: uint16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshrn.v8i8")] + fn vqshrn_n_u16_(a: uint16x8_t, n: i32) -> uint8x8_t; + } +vqshrn_n_u16_(a, N) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_s64(a: int64x1_t) -> int8x8_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_u32(a: uint32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnu.v4i16")] + fn vqshrn_n_u32_(a: uint32x4_t, n: uint32x4_t) -> uint16x4_t; + } +vqshrn_n_u32_(a, uint32x4_t(-N as u32, -N as u32, -N as u32, -N as u32)) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_u64(a: uint64x1_t) -> int8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_u32(a: uint32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshrn.v4i16")] + fn vqshrn_n_u32_(a: uint32x4_t, n: i32) -> uint16x4_t; + } +vqshrn_n_u32_(a, N) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift right narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_s64(a: int64x1_t) -> uint8x8_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_u64(a: uint64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnu.v2i32")] + fn vqshrn_n_u64_(a: uint64x2_t, n: uint64x2_t) -> uint32x2_t; + } +vqshrn_n_u64_(a, uint64x2_t(-N as u64, -N as u64)) } -/// Vector reinterpret cast operation +/// Unsigned saturating shift right narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_u64(a: uint64x1_t) -> uint8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrn_n_u64(a: uint64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.uqshrn.v2i32")] + fn vqshrn_n_u64_(a: uint64x2_t, n: i32) -> uint32x2_t; + } +vqshrn_n_u64_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating shift right unsigned narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_s64(a: int64x1_t) -> poly8x8_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrun_n_s16(a: int16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnsu.v8i8")] + fn vqshrun_n_s16_(a: int16x8_t, n: int16x8_t) -> uint8x8_t; + } +vqshrun_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) } -/// Vector reinterpret cast operation +/// Signed saturating shift right unsigned narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_u64(a: uint64x1_t) -> poly8x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrun_n_s16(a: int16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrun.v8i8")] + fn vqshrun_n_s16_(a: int16x8_t, n: i32) -> uint8x8_t; + } +vqshrun_n_s16_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating shift right unsigned narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_s64(a: int64x2_t) -> int8x16_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrun_n_s32(a: int32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnsu.v4i16")] + fn vqshrun_n_s32_(a: int32x4_t, n: int32x4_t) -> uint16x4_t; + } +vqshrun_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } -/// Vector reinterpret cast operation +/// Signed saturating shift right unsigned narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_u64(a: uint64x2_t) -> int8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrun_n_s32(a: int32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrun.v4i16")] + fn vqshrun_n_s32_(a: int32x4_t, n: i32) -> uint16x4_t; + } +vqshrun_n_s32_(a, N) } -/// Vector reinterpret cast operation +/// Signed saturating shift right unsigned narrow #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_s64(a: int64x2_t) -> uint8x16_t { - transmute(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrun_n_s64(a: int64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqshiftnsu.v2i32")] + fn vqshrun_n_s64_(a: int64x2_t, n: int64x2_t) -> uint32x2_t; + } +vqshrun_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } -/// Vector reinterpret cast operation +/// Signed saturating shift right unsigned narrow #[inline] +#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_u64(a: uint64x2_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqshrun, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vqshrun_n_s64(a: int64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqshrun.v2i32")] + fn vqshrun_n_s64_(a: int64x2_t, n: i32) -> uint32x2_t; + } +vqshrun_n_s64_(a, N) } -/// Vector reinterpret cast operation +/// Reciprocal square-root estimate. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_s64(a: int64x2_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsqrte))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frsqrte))] +pub unsafe fn vrsqrte_f32(a: float32x2_t) -> float32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrsqrte.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frsqrte.v2f32")] + fn vrsqrte_f32_(a: float32x2_t) -> float32x2_t; + } +vrsqrte_f32_(a) } -/// Vector reinterpret cast operation +/// Reciprocal square-root estimate. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_u64(a: uint64x2_t) -> poly8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsqrte))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frsqrte))] +pub unsafe fn vrsqrteq_f32(a: float32x4_t) -> float32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrsqrte.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frsqrte.v4f32")] + fn vrsqrteq_f32_(a: float32x4_t) -> float32x4_t; + } +vrsqrteq_f32_(a) } -/// Vector reinterpret cast operation +/// Reciprocal estimate. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_p8(a: poly8x8_t) -> int64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrecpe))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frecpe))] +pub unsafe fn vrecpe_f32(a: float32x2_t) -> float32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrecpe.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frecpe.v2f32")] + fn vrecpe_f32_(a: float32x2_t) -> float32x2_t; + } +vrecpe_f32_(a) } -/// Vector reinterpret cast operation +/// Reciprocal estimate. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_s8(a: int8x8_t) -> int64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrecpe))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frecpe))] +pub unsafe fn vrecpeq_f32(a: float32x4_t) -> float32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrecpe.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.frecpe.v4f32")] + fn vrecpeq_f32_(a: float32x4_t) -> float32x4_t; + } +vrecpeq_f32_(a) } /// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_u8(a: uint8x8_t) -> int64x1_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_u8(a: uint8x8_t) -> int8x8_t { transmute(a) } @@ -11856,9 +12256,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_p8(a: poly8x8_t) -> uint64x1_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_p8(a: poly8x8_t) -> int8x8_t { transmute(a) } @@ -11866,9 +12266,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_s8(a: int8x8_t) -> uint64x1_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_p16(a: poly16x4_t) -> int16x4_t { transmute(a) } @@ -11876,9 +12276,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_u8(a: uint8x8_t) -> uint64x1_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_u16(a: uint16x4_t) -> int16x4_t { transmute(a) } @@ -11886,9 +12286,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_p8(a: poly8x16_t) -> int64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_u32(a: uint32x2_t) -> int32x2_t { transmute(a) } @@ -11896,9 +12296,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_s8(a: int8x16_t) -> int64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_u64(a: uint64x1_t) -> int64x1_t { transmute(a) } @@ -11906,9 +12306,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_u8(a: uint8x16_t) -> int64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_u8(a: uint8x16_t) -> int8x16_t { transmute(a) } @@ -11916,9 +12316,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_p8(a: poly8x16_t) -> uint64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_p8(a: poly8x16_t) -> int8x16_t { transmute(a) } @@ -11926,9 +12326,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_s8(a: int8x16_t) -> uint64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_p16(a: poly16x8_t) -> int16x8_t { transmute(a) } @@ -11936,9 +12336,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_u8(a: uint8x16_t) -> uint64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_u16(a: uint16x8_t) -> int16x8_t { transmute(a) } @@ -11946,9 +12346,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s8_f32(a: float32x2_t) -> int8x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_u32(a: uint32x4_t) -> int32x4_t { transmute(a) } @@ -11956,9 +12356,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s16_f32(a: float32x2_t) -> int16x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_u64(a: uint64x2_t) -> int64x2_t { transmute(a) } @@ -11966,9 +12366,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s32_f32(a: float32x2_t) -> int32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_p8(a: poly8x8_t) -> uint8x8_t { transmute(a) } @@ -11976,9 +12376,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_s64_f32(a: float32x2_t) -> int64x1_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_s8(a: int8x8_t) -> uint8x8_t { transmute(a) } @@ -11986,9 +12386,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s8_f32(a: float32x4_t) -> int8x16_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_p16(a: poly16x4_t) -> uint16x4_t { transmute(a) } @@ -11996,9 +12396,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s16_f32(a: float32x4_t) -> int16x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_s16(a: int16x4_t) -> uint16x4_t { transmute(a) } @@ -12006,9 +12406,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s32_f32(a: float32x4_t) -> int32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_s32(a: int32x2_t) -> uint32x2_t { transmute(a) } @@ -12016,9 +12416,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_s64_f32(a: float32x4_t) -> int64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_s64(a: int64x1_t) -> uint64x1_t { transmute(a) } @@ -12026,9 +12426,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u8_f32(a: float32x2_t) -> uint8x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_p8(a: poly8x16_t) -> uint8x16_t { transmute(a) } @@ -12036,9 +12436,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u16_f32(a: float32x2_t) -> uint16x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_s8(a: int8x16_t) -> uint8x16_t { transmute(a) } @@ -12046,9 +12446,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u32_f32(a: float32x2_t) -> uint32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_p16(a: poly16x8_t) -> uint16x8_t { transmute(a) } @@ -12056,9 +12456,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_u64_f32(a: float32x2_t) -> uint64x1_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_s16(a: int16x8_t) -> uint16x8_t { transmute(a) } @@ -12066,9 +12466,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u8_f32(a: float32x4_t) -> uint8x16_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_s32(a: int32x4_t) -> uint32x4_t { transmute(a) } @@ -12076,9 +12476,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u16_f32(a: float32x4_t) -> uint16x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_s64(a: int64x2_t) -> uint64x2_t { transmute(a) } @@ -12086,9 +12486,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u32_f32(a: float32x4_t) -> uint32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_s8(a: int8x8_t) -> poly8x8_t { transmute(a) } @@ -12096,9 +12496,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_u64_f32(a: float32x4_t) -> uint64x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_u8(a: uint8x8_t) -> poly8x8_t { transmute(a) } @@ -12106,9 +12506,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p8_f32(a: float32x2_t) -> poly8x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_s16(a: int16x4_t) -> poly16x4_t { transmute(a) } @@ -12116,9 +12516,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_p16_f32(a: float32x2_t) -> poly16x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_u16(a: uint16x4_t) -> poly16x4_t { transmute(a) } @@ -12126,9 +12526,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p8_f32(a: float32x4_t) -> poly8x16_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_s8(a: int8x16_t) -> poly8x16_t { transmute(a) } @@ -12136,9 +12536,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_p16_f32(a: float32x4_t) -> poly16x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_u8(a: uint8x16_t) -> poly8x16_t { transmute(a) } @@ -12146,9 +12546,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_s8(a: int8x8_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_s16(a: int16x8_t) -> poly16x8_t { transmute(a) } @@ -12156,9 +12556,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_s16(a: int16x4_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_u16(a: uint16x8_t) -> poly16x8_t { transmute(a) } @@ -12166,9 +12566,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_s32(a: int32x2_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_s16(a: int16x4_t) -> int8x8_t { transmute(a) } @@ -12176,9 +12576,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_s64(a: int64x1_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_u16(a: uint16x4_t) -> int8x8_t { transmute(a) } @@ -12186,9 +12586,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_s8(a: int8x16_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_p16(a: poly16x4_t) -> int8x8_t { transmute(a) } @@ -12196,9 +12596,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_s16(a: int16x8_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_s32(a: int32x2_t) -> int16x4_t { transmute(a) } @@ -12206,9 +12606,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_s32(a: int32x4_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_u32(a: uint32x2_t) -> int16x4_t { transmute(a) } @@ -12216,9 +12616,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_s64(a: int64x2_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_s64(a: int64x1_t) -> int32x2_t { transmute(a) } @@ -12226,9 +12626,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_u8(a: uint8x8_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_u64(a: uint64x1_t) -> int32x2_t { transmute(a) } @@ -12236,9 +12636,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_u16(a: uint16x4_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_s16(a: int16x8_t) -> int8x16_t { transmute(a) } @@ -12246,9 +12646,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_u32(a: uint32x2_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_u16(a: uint16x8_t) -> int8x16_t { transmute(a) } @@ -12256,9 +12656,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_u64(a: uint64x1_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_p16(a: poly16x8_t) -> int8x16_t { transmute(a) } @@ -12266,9 +12666,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_u8(a: uint8x16_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_s32(a: int32x4_t) -> int16x8_t { transmute(a) } @@ -12276,9 +12676,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_u16(a: uint16x8_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_u32(a: uint32x4_t) -> int16x8_t { transmute(a) } @@ -12286,9 +12686,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_u32(a: uint32x4_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_s64(a: int64x2_t) -> int32x4_t { transmute(a) } @@ -12296,9 +12696,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_u64(a: uint64x2_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_u64(a: uint64x2_t) -> int32x4_t { transmute(a) } @@ -12306,9 +12706,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_p8(a: poly8x8_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_p16(a: poly16x4_t) -> uint8x8_t { transmute(a) } @@ -12316,9 +12716,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpret_f32_p16(a: poly16x4_t) -> float32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_s16(a: int16x4_t) -> uint8x8_t { transmute(a) } @@ -12326,9 +12726,9 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_p8(a: poly8x16_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_u16(a: uint16x4_t) -> uint8x8_t { transmute(a) } @@ -12336,6628 +12736,9498 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(str))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(str))] -pub unsafe fn vreinterpretq_f32_p16(a: poly16x8_t) -> float32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_s32(a: int32x2_t) -> uint16x4_t { transmute(a) } -/// Signed rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] -pub unsafe fn vrshl_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v8i8")] - fn vrshl_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; - } -vrshl_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_u32(a: uint32x2_t) -> uint16x4_t { + transmute(a) } -/// Signed rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] -pub unsafe fn vrshlq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v16i8")] - fn vrshlq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; - } -vrshlq_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_s64(a: int64x1_t) -> uint32x2_t { + transmute(a) } -/// Signed rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] -pub unsafe fn vrshl_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v4i16")] - fn vrshl_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } -vrshl_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_u64(a: uint64x1_t) -> uint32x2_t { + transmute(a) } -/// Signed rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] -pub unsafe fn vrshlq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v8i16")] - fn vrshlq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } -vrshlq_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_p16(a: poly16x8_t) -> uint8x16_t { + transmute(a) } -/// Signed rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] -pub unsafe fn vrshl_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v2i32")] - fn vrshl_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } -vrshl_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_s16(a: int16x8_t) -> uint8x16_t { + transmute(a) } -/// Signed rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] -pub unsafe fn vrshlq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v4i32")] - fn vrshlq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } -vrshlq_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_u16(a: uint16x8_t) -> uint8x16_t { + transmute(a) } -/// Signed rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] -pub unsafe fn vrshl_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v1i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v1i64")] - fn vrshl_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; - } -vrshl_s64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_s32(a: int32x4_t) -> uint16x8_t { + transmute(a) } -/// Signed rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] -pub unsafe fn vrshlq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v2i64")] - fn vrshlq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; - } -vrshlq_s64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_u32(a: uint32x4_t) -> uint16x8_t { + transmute(a) } -/// Unsigned rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] -pub unsafe fn vrshl_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v8i8")] - fn vrshl_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; - } -vrshl_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_s64(a: int64x2_t) -> uint32x4_t { + transmute(a) } -/// Unsigned rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] -pub unsafe fn vrshlq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v16i8")] - fn vrshlq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; - } -vrshlq_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_u64(a: uint64x2_t) -> uint32x4_t { + transmute(a) } -/// Unsigned rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] -pub unsafe fn vrshl_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v4i16")] - fn vrshl_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; - } -vrshl_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_p16(a: poly16x4_t) -> poly8x8_t { + transmute(a) } -/// Unsigned rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] -pub unsafe fn vrshlq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v8i16")] - fn vrshlq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; - } -vrshlq_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_s16(a: int16x4_t) -> poly8x8_t { + transmute(a) } -/// Unsigned rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] -pub unsafe fn vrshl_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v2i32")] - fn vrshl_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; - } -vrshl_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_u16(a: uint16x4_t) -> poly8x8_t { + transmute(a) } -/// Unsigned rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] -pub unsafe fn vrshlq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v4i32")] - fn vrshlq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; - } -vrshlq_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_s32(a: int32x2_t) -> poly16x4_t { + transmute(a) } -/// Unsigned rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] -pub unsafe fn vrshl_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v1i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v1i64")] - fn vrshl_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; - } -vrshl_u64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_u32(a: uint32x2_t) -> poly16x4_t { + transmute(a) } -/// Unsigned rounding shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] -pub unsafe fn vrshlq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v2i64")] - fn vrshlq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; - } -vrshlq_u64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_p16(a: poly16x8_t) -> poly8x16_t { + transmute(a) } -/// Signed rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshr_n_s8(a: int8x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - vrshl_s8(a, vdup_n_s8((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_s16(a: int16x8_t) -> poly8x16_t { + transmute(a) } -/// Signed rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrq_n_s8(a: int8x16_t) -> int8x16_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - vrshlq_s8(a, vdupq_n_s8((-N).try_into().unwrap())) -} - -/// Signed rounding shift right +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_u16(a: uint16x8_t) -> poly8x16_t { + transmute(a) +} + +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshr_n_s16(a: int16x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - vrshl_s16(a, vdup_n_s16((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_s32(a: int32x4_t) -> poly16x8_t { + transmute(a) } -/// Signed rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrq_n_s16(a: int16x8_t) -> int16x8_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - vrshlq_s16(a, vdupq_n_s16((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_u32(a: uint32x4_t) -> poly16x8_t { + transmute(a) } -/// Signed rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshr_n_s32(a: int32x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - vrshl_s32(a, vdup_n_s32((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_p8(a: poly8x8_t) -> int16x4_t { + transmute(a) } -/// Signed rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrq_n_s32(a: int32x4_t) -> int32x4_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - vrshlq_s32(a, vdupq_n_s32((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_s8(a: int8x8_t) -> int16x4_t { + transmute(a) } -/// Signed rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshr_n_s64(a: int64x1_t) -> int64x1_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - vrshl_s64(a, vdup_n_s64((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_u8(a: uint8x8_t) -> int16x4_t { + transmute(a) } -/// Signed rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrq_n_s64(a: int64x2_t) -> int64x2_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - vrshlq_s64(a, vdupq_n_s64((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_p16(a: poly16x4_t) -> int32x2_t { + transmute(a) } -/// Unsigned rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshr_n_u8(a: uint8x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - vrshl_u8(a, vdup_n_s8((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_s16(a: int16x4_t) -> int32x2_t { + transmute(a) } -/// Unsigned rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrq_n_u8(a: uint8x16_t) -> uint8x16_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - vrshlq_u8(a, vdupq_n_s8((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_u16(a: uint16x4_t) -> int32x2_t { + transmute(a) } -/// Unsigned rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshr_n_u16(a: uint16x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - vrshl_u16(a, vdup_n_s16((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_s32(a: int32x2_t) -> int64x1_t { + transmute(a) } -/// Unsigned rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrq_n_u16(a: uint16x8_t) -> uint16x8_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - vrshlq_u16(a, vdupq_n_s16((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_u32(a: uint32x2_t) -> int64x1_t { + transmute(a) } -/// Unsigned rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshr_n_u32(a: uint32x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - vrshl_u32(a, vdup_n_s32((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_p8(a: poly8x16_t) -> int16x8_t { + transmute(a) } -/// Unsigned rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrq_n_u32(a: uint32x4_t) -> uint32x4_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - vrshlq_u32(a, vdupq_n_s32((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_s8(a: int8x16_t) -> int16x8_t { + transmute(a) } -/// Unsigned rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshr_n_u64(a: uint64x1_t) -> uint64x1_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - vrshl_u64(a, vdup_n_s64((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_u8(a: uint8x16_t) -> int16x8_t { + transmute(a) } -/// Unsigned rounding shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrq_n_u64(a: uint64x2_t) -> uint64x2_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - vrshlq_u64(a, vdupq_n_s64((-N).try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_p16(a: poly16x8_t) -> int32x4_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_s16(a: int16x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftn.v8i8")] - fn vrshrn_n_s16_(a: int16x8_t, n: int16x8_t) -> int8x8_t; - } -vrshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_s16(a: int16x8_t) -> int32x4_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_s16(a: int16x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.rshrn.v8i8")] - fn vrshrn_n_s16_(a: int16x8_t, n: i32) -> int8x8_t; - } -vrshrn_n_s16_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_u16(a: uint16x8_t) -> int32x4_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_s32(a: int32x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftn.v4i16")] - fn vrshrn_n_s32_(a: int32x4_t, n: int32x4_t) -> int16x4_t; - } -vrshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_s32(a: int32x4_t) -> int64x2_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_s32(a: int32x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.rshrn.v4i16")] - fn vrshrn_n_s32_(a: int32x4_t, n: i32) -> int16x4_t; - } -vrshrn_n_s32_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_u32(a: uint32x4_t) -> int64x2_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_s64(a: int64x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftn.v2i32")] - fn vrshrn_n_s64_(a: int64x2_t, n: int64x2_t) -> int32x2_t; - } -vrshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_p8(a: poly8x8_t) -> uint16x4_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] -#[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_s64(a: int64x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.rshrn.v2i32")] - fn vrshrn_n_s64_(a: int64x2_t, n: i32) -> int32x2_t; - } -vrshrn_n_s64_(a, N) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_s8(a: int8x8_t) -> uint16x4_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_u16(a: uint16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - transmute(vrshrn_n_s16::(transmute(a))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_u8(a: uint8x8_t) -> uint16x4_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_u32(a: uint32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - transmute(vrshrn_n_s32::(transmute(a))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_p16(a: poly16x4_t) -> uint32x2_t { + transmute(a) } -/// Rounding shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vrshrn_n_u64(a: uint64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - transmute(vrshrn_n_s64::(transmute(a))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_s16(a: int16x4_t) -> uint32x2_t { + transmute(a) } -/// Signed rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsra_n_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_add(a, vrshr_n_s8::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_u16(a: uint16x4_t) -> uint32x2_t { + transmute(a) } -/// Signed rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsraq_n_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_add(a, vrshrq_n_s8::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_s32(a: int32x2_t) -> uint64x1_t { + transmute(a) } -/// Signed rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsra_n_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_add(a, vrshr_n_s16::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { + transmute(a) } -/// Signed rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsraq_n_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_add(a, vrshrq_n_s16::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_p8(a: poly8x16_t) -> uint16x8_t { + transmute(a) } -/// Signed rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsra_n_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_add(a, vrshr_n_s32::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_s8(a: int8x16_t) -> uint16x8_t { + transmute(a) } -/// Signed rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsraq_n_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_add(a, vrshrq_n_s32::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_u8(a: uint8x16_t) -> uint16x8_t { + transmute(a) } -/// Signed rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsra_n_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_add(a, vrshr_n_s64::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_p16(a: poly16x8_t) -> uint32x4_t { + transmute(a) } -/// Signed rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsraq_n_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_add(a, vrshrq_n_s64::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_s16(a: int16x8_t) -> uint32x4_t { + transmute(a) } -/// Unsigned rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsra_n_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_add(a, vrshr_n_u8::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_u16(a: uint16x8_t) -> uint32x4_t { + transmute(a) } -/// Unsigned rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsraq_n_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_add(a, vrshrq_n_u8::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_s32(a: int32x4_t) -> uint64x2_t { + transmute(a) } -/// Unsigned rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsra_n_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_add(a, vrshr_n_u16::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_u32(a: uint32x4_t) -> uint64x2_t { + transmute(a) } -/// Unsigned rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsraq_n_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_add(a, vrshrq_n_u16::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_p8(a: poly8x8_t) -> poly16x4_t { + transmute(a) } -/// Unsigned rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsra_n_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_add(a, vrshr_n_u32::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_s8(a: int8x8_t) -> poly16x4_t { + transmute(a) } -/// Unsigned rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsraq_n_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_add(a, vrshrq_n_u32::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_u8(a: uint8x8_t) -> poly16x4_t { + transmute(a) } -/// Unsigned rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsra_n_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_add(a, vrshr_n_u64::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_p8(a: poly8x16_t) -> poly16x8_t { + transmute(a) } -/// Unsigned rounding shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vrsraq_n_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_add(a, vrshrq_n_u64::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_s8(a: int8x16_t) -> poly16x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_s8(a: i8, b: int8x8_t) -> int8x8_t { - static_assert_imm3!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_u8(a: uint8x16_t) -> poly16x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_s16(a: i16, b: int16x4_t) -> int16x4_t { - static_assert_imm2!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_s32(a: int32x2_t) -> int8x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_s32(a: i32, b: int32x2_t) -> int32x2_t { - static_assert_imm1!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_u32(a: uint32x2_t) -> int8x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_s64(a: i64, b: int64x1_t) -> int64x1_t { - static_assert!(LANE : i32 where LANE == 0); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_s64(a: int64x1_t) -> int16x4_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_u8(a: u8, b: uint8x8_t) -> uint8x8_t { - static_assert_imm3!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_u64(a: uint64x1_t) -> int16x4_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_u16(a: u16, b: uint16x4_t) -> uint16x4_t { - static_assert_imm2!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_s32(a: int32x4_t) -> int8x16_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_u32(a: u32, b: uint32x2_t) -> uint32x2_t { - static_assert_imm1!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_u32(a: uint32x4_t) -> int8x16_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_u64(a: u64, b: uint64x1_t) -> uint64x1_t { - static_assert!(LANE : i32 where LANE == 0); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_s64(a: int64x2_t) -> int16x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_p8(a: p8, b: poly8x8_t) -> poly8x8_t { - static_assert_imm3!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_u64(a: uint64x2_t) -> int16x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_p16(a: p16, b: poly16x4_t) -> poly16x4_t { - static_assert_imm2!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_s32(a: int32x2_t) -> uint8x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_p64(a: p64, b: poly64x1_t) -> poly64x1_t { - static_assert!(LANE : i32 where LANE == 0); - simd_insert(b, LANE as u32, a) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_u32(a: uint32x2_t) -> uint8x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_s8(a: i8, b: int8x16_t) -> int8x16_t { - static_assert_imm4!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_s64(a: int64x1_t) -> uint16x4_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_s16(a: i16, b: int16x8_t) -> int16x8_t { - static_assert_imm3!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_u64(a: uint64x1_t) -> uint16x4_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_s32(a: i32, b: int32x4_t) -> int32x4_t { - static_assert_imm2!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_s32(a: int32x4_t) -> uint8x16_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_s64(a: i64, b: int64x2_t) -> int64x2_t { - static_assert_imm1!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_u32(a: uint32x4_t) -> uint8x16_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_u8(a: u8, b: uint8x16_t) -> uint8x16_t { - static_assert_imm4!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_s64(a: int64x2_t) -> uint16x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_u16(a: u16, b: uint16x8_t) -> uint16x8_t { - static_assert_imm3!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_u64(a: uint64x2_t) -> uint16x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_u32(a: u32, b: uint32x4_t) -> uint32x4_t { - static_assert_imm2!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_s32(a: int32x2_t) -> poly8x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_u64(a: u64, b: uint64x2_t) -> uint64x2_t { - static_assert_imm1!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_u32(a: uint32x2_t) -> poly8x8_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_p8(a: p8, b: poly8x16_t) -> poly8x16_t { - static_assert_imm4!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_s64(a: int64x1_t) -> poly16x4_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_p16(a: p16, b: poly16x8_t) -> poly16x8_t { - static_assert_imm3!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_u64(a: uint64x1_t) -> poly16x4_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_p64(a: p64, b: poly64x2_t) -> poly64x2_t { - static_assert_imm1!(LANE); - simd_insert(b, LANE as u32, a) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_s32(a: int32x4_t) -> poly8x16_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vset_lane_f32(a: f32, b: float32x2_t) -> float32x2_t { - static_assert_imm1!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_u32(a: uint32x4_t) -> poly8x16_t { + transmute(a) } -/// Insert vector element from another vector element +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsetq_lane_f32(a: f32, b: float32x4_t) -> float32x4_t { - static_assert_imm2!(LANE); - simd_insert(b, LANE as u32, a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_s64(a: int64x2_t) -> poly16x8_t { + transmute(a) } -/// Signed Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] -pub unsafe fn vshl_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v8i8")] - fn vshl_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; - } -vshl_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_u64(a: uint64x2_t) -> poly16x8_t { + transmute(a) } -/// Signed Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] -pub unsafe fn vshlq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v16i8")] - fn vshlq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; - } -vshlq_s8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_p8(a: poly8x8_t) -> int32x2_t { + transmute(a) } -/// Signed Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] -pub unsafe fn vshl_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v4i16")] - fn vshl_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } -vshl_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_s8(a: int8x8_t) -> int32x2_t { + transmute(a) } -/// Signed Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] -pub unsafe fn vshlq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v8i16")] - fn vshlq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } -vshlq_s16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_u8(a: uint8x8_t) -> int32x2_t { + transmute(a) } -/// Signed Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] -pub unsafe fn vshl_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v2i32")] - fn vshl_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } -vshl_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_p16(a: poly16x4_t) -> int64x1_t { + transmute(a) } -/// Signed Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] -pub unsafe fn vshlq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v4i32")] - fn vshlq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } -vshlq_s32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_s16(a: int16x4_t) -> int64x1_t { + transmute(a) } -/// Signed Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] -pub unsafe fn vshl_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v1i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v1i64")] - fn vshl_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; - } -vshl_s64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_u16(a: uint16x4_t) -> int64x1_t { + transmute(a) } -/// Signed Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] -pub unsafe fn vshlq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v2i64")] - fn vshlq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; - } -vshlq_s64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_p8(a: poly8x16_t) -> int32x4_t { + transmute(a) } -/// Unsigned Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] -pub unsafe fn vshl_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v8i8")] - fn vshl_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; - } -vshl_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_s8(a: int8x16_t) -> int32x4_t { + transmute(a) } -/// Unsigned Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] -pub unsafe fn vshlq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v16i8")] - fn vshlq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; - } -vshlq_u8_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_u8(a: uint8x16_t) -> int32x4_t { + transmute(a) } -/// Unsigned Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] -pub unsafe fn vshl_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v4i16")] - fn vshl_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; - } -vshl_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_p16(a: poly16x8_t) -> int64x2_t { + transmute(a) } -/// Unsigned Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] -pub unsafe fn vshlq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v8i16")] - fn vshlq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; - } -vshlq_u16_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_s16(a: int16x8_t) -> int64x2_t { + transmute(a) } -/// Unsigned Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] -pub unsafe fn vshl_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v2i32")] - fn vshl_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; - } -vshl_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_u16(a: uint16x8_t) -> int64x2_t { + transmute(a) } -/// Unsigned Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] -pub unsafe fn vshlq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v4i32")] - fn vshlq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; - } -vshlq_u32_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_p8(a: poly8x8_t) -> uint32x2_t { + transmute(a) } -/// Unsigned Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] -pub unsafe fn vshl_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v1i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v1i64")] - fn vshl_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; - } -vshl_u64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_s8(a: int8x8_t) -> uint32x2_t { + transmute(a) } -/// Unsigned Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] -pub unsafe fn vshlq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { - #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v2i64")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v2i64")] - fn vshlq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; - } -vshlq_u64_(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_u8(a: uint8x8_t) -> uint32x2_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshl_n_s8(a: int8x8_t) -> int8x8_t { - static_assert_imm3!(N); - simd_shl(a, vdup_n_s8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_p16(a: poly16x4_t) -> uint64x1_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshlq_n_s8(a: int8x16_t) -> int8x16_t { - static_assert_imm3!(N); - simd_shl(a, vdupq_n_s8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_s16(a: int16x4_t) -> uint64x1_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshl_n_s16(a: int16x4_t) -> int16x4_t { - static_assert_imm4!(N); - simd_shl(a, vdup_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_u16(a: uint16x4_t) -> uint64x1_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshlq_n_s16(a: int16x8_t) -> int16x8_t { - static_assert_imm4!(N); - simd_shl(a, vdupq_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_p8(a: poly8x16_t) -> uint32x4_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshl_n_s32(a: int32x2_t) -> int32x2_t { - static_assert_imm5!(N); - simd_shl(a, vdup_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_s8(a: int8x16_t) -> uint32x4_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshlq_n_s32(a: int32x4_t) -> int32x4_t { - static_assert_imm5!(N); - simd_shl(a, vdupq_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_u8(a: uint8x16_t) -> uint32x4_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshl_n_u8(a: uint8x8_t) -> uint8x8_t { - static_assert_imm3!(N); - simd_shl(a, vdup_n_u8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_p16(a: poly16x8_t) -> uint64x2_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshlq_n_u8(a: uint8x16_t) -> uint8x16_t { - static_assert_imm3!(N); - simd_shl(a, vdupq_n_u8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_s16(a: int16x8_t) -> uint64x2_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshl_n_u16(a: uint16x4_t) -> uint16x4_t { - static_assert_imm4!(N); - simd_shl(a, vdup_n_u16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_u16(a: uint16x8_t) -> uint64x2_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshlq_n_u16(a: uint16x8_t) -> uint16x8_t { - static_assert_imm4!(N); - simd_shl(a, vdupq_n_u16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_s64(a: int64x1_t) -> int8x8_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshl_n_u32(a: uint32x2_t) -> uint32x2_t { - static_assert_imm5!(N); - simd_shl(a, vdup_n_u32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_u64(a: uint64x1_t) -> int8x8_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshlq_n_u32(a: uint32x4_t) -> uint32x4_t { - static_assert_imm5!(N); - simd_shl(a, vdupq_n_u32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_s64(a: int64x1_t) -> uint8x8_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshl_n_s64(a: int64x1_t) -> int64x1_t { - static_assert_imm6!(N); - simd_shl(a, vdup_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_u64(a: uint64x1_t) -> uint8x8_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshlq_n_s64(a: int64x2_t) -> int64x2_t { - static_assert_imm6!(N); - simd_shl(a, vdupq_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_s64(a: int64x1_t) -> poly8x8_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshl_n_u64(a: uint64x1_t) -> uint64x1_t { - static_assert_imm6!(N); - simd_shl(a, vdup_n_u64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_u64(a: uint64x1_t) -> poly8x8_t { + transmute(a) } -/// Shift left +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshlq_n_u64(a: uint64x2_t) -> uint64x2_t { - static_assert_imm6!(N); - simd_shl(a, vdupq_n_u64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_s64(a: int64x2_t) -> int8x16_t { + transmute(a) } -/// Signed shift left long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.s8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshll, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshll_n_s8(a: int8x8_t) -> int16x8_t { - static_assert!(N : i32 where N >= 0 && N <= 8); - simd_shl(simd_cast(a), vdupq_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_u64(a: uint64x2_t) -> int8x16_t { + transmute(a) } -/// Signed shift left long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.s16", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshll, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshll_n_s16(a: int16x4_t) -> int32x4_t { - static_assert!(N : i32 where N >= 0 && N <= 16); - simd_shl(simd_cast(a), vdupq_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_s64(a: int64x2_t) -> uint8x16_t { + transmute(a) } -/// Signed shift left long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.s32", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshll, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshll_n_s32(a: int32x2_t) -> int64x2_t { - static_assert!(N : i32 where N >= 0 && N <= 32); - simd_shl(simd_cast(a), vdupq_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_u64(a: uint64x2_t) -> uint8x16_t { + transmute(a) } -/// Signed shift left long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.u8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushll, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshll_n_u8(a: uint8x8_t) -> uint16x8_t { - static_assert!(N : i32 where N >= 0 && N <= 8); - simd_shl(simd_cast(a), vdupq_n_u16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_s64(a: int64x2_t) -> poly8x16_t { + transmute(a) } -/// Signed shift left long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.u16", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushll, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshll_n_u16(a: uint16x4_t) -> uint32x4_t { - static_assert!(N : i32 where N >= 0 && N <= 16); - simd_shl(simd_cast(a), vdupq_n_u32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_u64(a: uint64x2_t) -> poly8x16_t { + transmute(a) } -/// Signed shift left long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.u32", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushll, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshll_n_u32(a: uint32x2_t) -> uint64x2_t { - static_assert!(N : i32 where N >= 0 && N <= 32); - simd_shl(simd_cast(a), vdupq_n_u64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_p8(a: poly8x8_t) -> int64x1_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshr_n_s8(a: int8x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_shr(a, vdup_n_s8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_s8(a: int8x8_t) -> int64x1_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrq_n_s8(a: int8x16_t) -> int8x16_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_shr(a, vdupq_n_s8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_u8(a: uint8x8_t) -> int64x1_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s16", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshr_n_s16(a: int16x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_shr(a, vdup_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_p8(a: poly8x8_t) -> uint64x1_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s16", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrq_n_s16(a: int16x8_t) -> int16x8_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_shr(a, vdupq_n_s16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_s8(a: int8x8_t) -> uint64x1_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s32", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshr_n_s32(a: int32x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_shr(a, vdup_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_u8(a: uint8x8_t) -> uint64x1_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s32", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrq_n_s32(a: int32x4_t) -> int32x4_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_shr(a, vdupq_n_s32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_p8(a: poly8x16_t) -> int64x2_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s64", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshr_n_s64(a: int64x1_t) -> int64x1_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_shr(a, vdup_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_s8(a: int8x16_t) -> int64x2_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s64", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrq_n_s64(a: int64x2_t) -> int64x2_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_shr(a, vdupq_n_s64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_u8(a: uint8x16_t) -> int64x2_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshr_n_u8(a: uint8x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_shr(a, vdup_n_u8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_p8(a: poly8x16_t) -> uint64x2_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrq_n_u8(a: uint8x16_t) -> uint8x16_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_shr(a, vdupq_n_u8(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_s8(a: int8x16_t) -> uint64x2_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u16", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshr_n_u16(a: uint16x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_shr(a, vdup_n_u16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_u8(a: uint8x16_t) -> uint64x2_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u16", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrq_n_u16(a: uint16x8_t) -> uint16x8_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_shr(a, vdupq_n_u16(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s8_f32(a: float32x2_t) -> int8x8_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u32", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshr_n_u32(a: uint32x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_shr(a, vdup_n_u32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s16_f32(a: float32x2_t) -> int16x4_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u32", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrq_n_u32(a: uint32x4_t) -> uint32x4_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_shr(a, vdupq_n_u32(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s32_f32(a: float32x2_t) -> int32x2_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u64", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshr_n_u64(a: uint64x1_t) -> uint64x1_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_shr(a, vdup_n_u64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_s64_f32(a: float32x2_t) -> int64x1_t { + transmute(a) } -/// Shift right +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u64", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrq_n_u64(a: uint64x2_t) -> uint64x2_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_shr(a, vdupq_n_u64(N.try_into().unwrap())) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_f32(a: float32x4_t) -> int8x16_t { + transmute(a) } -/// Shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i16", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrn_n_s16(a: int16x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_cast(simd_shr(a, vdupq_n_s16(N.try_into().unwrap()))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s16_f32(a: float32x4_t) -> int16x8_t { + transmute(a) } -/// Shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i32", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrn_n_s32(a: int32x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_cast(simd_shr(a, vdupq_n_s32(N.try_into().unwrap()))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s32_f32(a: float32x4_t) -> int32x4_t { + transmute(a) } -/// Shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i64", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrn_n_s64(a: int64x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_cast(simd_shr(a, vdupq_n_s64(N.try_into().unwrap()))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_s64_f32(a: float32x4_t) -> int64x2_t { + transmute(a) } -/// Shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i16", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrn_n_u16(a: uint16x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_cast(simd_shr(a, vdupq_n_u16(N.try_into().unwrap()))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u8_f32(a: float32x2_t) -> uint8x8_t { + transmute(a) } -/// Shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i32", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrn_n_u32(a: uint32x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_cast(simd_shr(a, vdupq_n_u32(N.try_into().unwrap()))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u16_f32(a: float32x2_t) -> uint16x4_t { + transmute(a) } -/// Shift right narrow +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i64", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] -#[rustc_legacy_const_generics(1)] -pub unsafe fn vshrn_n_u64(a: uint64x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_cast(simd_shr(a, vdupq_n_u64(N.try_into().unwrap()))) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u32_f32(a: float32x2_t) -> uint32x2_t { + transmute(a) } -/// Signed shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsra_n_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_add(a, vshr_n_s8::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_u64_f32(a: float32x2_t) -> uint64x1_t { + transmute(a) } -/// Signed shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsraq_n_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_add(a, vshrq_n_s8::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_f32(a: float32x4_t) -> uint8x16_t { + transmute(a) } -/// Signed shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsra_n_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_add(a, vshr_n_s16::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_f32(a: float32x4_t) -> uint16x8_t { + transmute(a) } -/// Signed shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsraq_n_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_add(a, vshrq_n_s16::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_f32(a: float32x4_t) -> uint32x4_t { + transmute(a) } -/// Signed shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsra_n_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_add(a, vshr_n_s32::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_f32(a: float32x4_t) -> uint64x2_t { + transmute(a) } -/// Signed shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsraq_n_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_add(a, vshrq_n_s32::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p8_f32(a: float32x2_t) -> poly8x8_t { + transmute(a) } -/// Signed shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsra_n_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_add(a, vshr_n_s64::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_p16_f32(a: float32x2_t) -> poly16x4_t { + transmute(a) } -/// Signed shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsraq_n_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_add(a, vshrq_n_s64::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p8_f32(a: float32x4_t) -> poly8x16_t { + transmute(a) } -/// Unsigned shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsra_n_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_add(a, vshr_n_u8::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_p16_f32(a: float32x4_t) -> poly16x8_t { + transmute(a) } -/// Unsigned shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsraq_n_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - static_assert!(N : i32 where N >= 1 && N <= 8); - simd_add(a, vshrq_n_u8::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_s8(a: int8x8_t) -> float32x2_t { + transmute(a) } -/// Unsigned shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsra_n_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_add(a, vshr_n_u16::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_s16(a: int16x4_t) -> float32x2_t { + transmute(a) } -/// Unsigned shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsraq_n_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - static_assert!(N : i32 where N >= 1 && N <= 16); - simd_add(a, vshrq_n_u16::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_s32(a: int32x2_t) -> float32x2_t { + transmute(a) } -/// Unsigned shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsra_n_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_add(a, vshr_n_u32::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_s64(a: int64x1_t) -> float32x2_t { + transmute(a) } -/// Unsigned shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsraq_n_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - static_assert!(N : i32 where N >= 1 && N <= 32); - simd_add(a, vshrq_n_u32::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_s8(a: int8x16_t) -> float32x4_t { + transmute(a) } -/// Unsigned shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsra_n_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_add(a, vshr_n_u64::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_s16(a: int16x8_t) -> float32x4_t { + transmute(a) } -/// Unsigned shift right and accumulate +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] -#[rustc_legacy_const_generics(2)] -pub unsafe fn vsraq_n_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { - static_assert!(N : i32 where N >= 1 && N <= 64); - simd_add(a, vshrq_n_u64::(b)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_s32(a: int32x4_t) -> float32x4_t { + transmute(a) } -/// Unsigned Absolute difference and Accumulate Long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.u8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabal))] -pub unsafe fn vabal_u8(a: uint16x8_t, b: uint8x8_t, c: uint8x8_t) -> uint16x8_t { - let d: uint8x8_t = vabd_u8(b, c); - simd_add(a, simd_cast(d)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_s64(a: int64x2_t) -> float32x4_t { + transmute(a) } -/// Unsigned Absolute difference and Accumulate Long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.u16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabal))] -pub unsafe fn vabal_u16(a: uint32x4_t, b: uint16x4_t, c: uint16x4_t) -> uint32x4_t { - let d: uint16x4_t = vabd_u16(b, c); - simd_add(a, simd_cast(d)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_u8(a: uint8x8_t) -> float32x2_t { + transmute(a) } -/// Unsigned Absolute difference and Accumulate Long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.u32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabal))] -pub unsafe fn vabal_u32(a: uint64x2_t, b: uint32x2_t, c: uint32x2_t) -> uint64x2_t { - let d: uint32x2_t = vabd_u32(b, c); - simd_add(a, simd_cast(d)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_u16(a: uint16x4_t) -> float32x2_t { + transmute(a) } -/// Signed Absolute difference and Accumulate Long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.s8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabal))] -pub unsafe fn vabal_s8(a: int16x8_t, b: int8x8_t, c: int8x8_t) -> int16x8_t { - let d: int8x8_t = vabd_s8(b, c); - let e: uint8x8_t = simd_cast(d); - simd_add(a, simd_cast(e)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_u32(a: uint32x2_t) -> float32x2_t { + transmute(a) } -/// Signed Absolute difference and Accumulate Long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.s16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabal))] -pub unsafe fn vabal_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { - let d: int16x4_t = vabd_s16(b, c); - let e: uint16x4_t = simd_cast(d); - simd_add(a, simd_cast(e)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_u64(a: uint64x1_t) -> float32x2_t { + transmute(a) } -/// Signed Absolute difference and Accumulate Long +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.s32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabal))] -pub unsafe fn vabal_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { - let d: int32x2_t = vabd_s32(b, c); - let e: uint32x2_t = simd_cast(d); - simd_add(a, simd_cast(e)) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_u8(a: uint8x16_t) -> float32x4_t { + transmute(a) } -/// Singned saturating Absolute value +/// Vector reinterpret cast operation #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] -pub unsafe fn vqabs_s8(a: int8x8_t) -> int8x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_u16(a: uint16x8_t) -> float32x4_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_u32(a: uint32x4_t) -> float32x4_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_u64(a: uint64x2_t) -> float32x4_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_p8(a: poly8x8_t) -> float32x2_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpret_f32_p16(a: poly16x4_t) -> float32x2_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_p8(a: poly8x16_t) -> float32x4_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop))] +pub unsafe fn vreinterpretq_f32_p16(a: poly16x8_t) -> float32x4_t { + transmute(a) +} + +/// Signed rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] +pub unsafe fn vrshl_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v8i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v8i8")] - fn vqabs_s8_(a: int8x8_t) -> int8x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v8i8")] + fn vrshl_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; } -vqabs_s8_(a) +vrshl_s8_(a, b) } -/// Singned saturating Absolute value +/// Signed rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] -pub unsafe fn vqabsq_s8(a: int8x16_t) -> int8x16_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] +pub unsafe fn vrshlq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v16i8")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v16i8")] - fn vqabsq_s8_(a: int8x16_t) -> int8x16_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v16i8")] + fn vrshlq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; } -vqabsq_s8_(a) +vrshlq_s8_(a, b) } -/// Singned saturating Absolute value +/// Signed rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] -pub unsafe fn vqabs_s16(a: int16x4_t) -> int16x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] +pub unsafe fn vrshl_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v4i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v4i16")] - fn vqabs_s16_(a: int16x4_t) -> int16x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v4i16")] + fn vrshl_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; } -vqabs_s16_(a) +vrshl_s16_(a, b) } -/// Singned saturating Absolute value +/// Signed rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s16"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] -pub unsafe fn vqabsq_s16(a: int16x8_t) -> int16x8_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] +pub unsafe fn vrshlq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v8i16")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v8i16")] - fn vqabsq_s16_(a: int16x8_t) -> int16x8_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v8i16")] + fn vrshlq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; } -vqabsq_s16_(a) +vrshlq_s16_(a, b) } -/// Singned saturating Absolute value +/// Signed rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] -pub unsafe fn vqabs_s32(a: int32x2_t) -> int32x2_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] +pub unsafe fn vrshl_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v2i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v2i32")] - fn vqabs_s32_(a: int32x2_t) -> int32x2_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v2i32")] + fn vrshl_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; } -vqabs_s32_(a) +vrshl_s32_(a, b) } -/// Singned saturating Absolute value +/// Signed rounding shift left #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] -pub unsafe fn vqabsq_s32(a: int32x4_t) -> int32x4_t { +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] +pub unsafe fn vrshlq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { #[allow(improper_ctypes)] - extern "C" { - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v4i32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v4i32")] - fn vqabsq_s32_(a: int32x4_t) -> int32x4_t; + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v4i32")] + fn vrshlq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; } -vqabsq_s32_(a) +vrshlq_s32_(a, b) } -#[cfg(test)] -#[allow(overflowing_literals)] -mod test { - use super::*; - use crate::core_arch::simd::*; - use std::mem::transmute; - use stdarch_test::simd_test; - - #[simd_test(enable = "neon")] - unsafe fn test_vand_s8() { - let a: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i8x8 = i8x8::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); - let e: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: i8x8 = transmute(vand_s8(transmute(a), transmute(b))); - assert_eq!(r, e); +/// Signed rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] +pub unsafe fn vrshl_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v1i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v1i64")] + fn vrshl_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; + } +vrshl_s64_(a, b) +} - let a: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i8x8 = i8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i8x8 = i8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let r: i8x8 = transmute(vand_s8(transmute(a), transmute(b))); - assert_eq!(r, e); +/// Signed rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshl))] +pub unsafe fn vrshlq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshifts.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.srshl.v2i64")] + fn vrshlq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; } +vrshlq_s64_(a, b) +} - #[simd_test(enable = "neon")] - unsafe fn test_vandq_s8() { +/// Unsigned rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] +pub unsafe fn vrshl_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v8i8")] + fn vrshl_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; + } +vrshl_u8_(a, b) +} + +/// Unsigned rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] +pub unsafe fn vrshlq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v16i8")] + fn vrshlq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; + } +vrshlq_u8_(a, b) +} + +/// Unsigned rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] +pub unsafe fn vrshl_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v4i16")] + fn vrshl_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; + } +vrshl_u16_(a, b) +} + +/// Unsigned rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] +pub unsafe fn vrshlq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v8i16")] + fn vrshlq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; + } +vrshlq_u16_(a, b) +} + +/// Unsigned rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] +pub unsafe fn vrshl_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v2i32")] + fn vrshl_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; + } +vrshl_u32_(a, b) +} + +/// Unsigned rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] +pub unsafe fn vrshlq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v4i32")] + fn vrshlq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; + } +vrshlq_u32_(a, b) +} + +/// Unsigned rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] +pub unsafe fn vrshl_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v1i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v1i64")] + fn vrshl_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; + } +vrshl_u64_(a, b) +} + +/// Unsigned rounding shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshl))] +pub unsafe fn vrshlq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftu.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.urshl.v2i64")] + fn vrshlq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; + } +vrshlq_u64_(a, b) +} + +/// Signed rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshr_n_s8(a: int8x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + vrshl_s8(a, vdup_n_s8((-N).try_into().unwrap())) +} + +/// Signed rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrq_n_s8(a: int8x16_t) -> int8x16_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + vrshlq_s8(a, vdupq_n_s8((-N).try_into().unwrap())) +} + +/// Signed rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshr_n_s16(a: int16x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + vrshl_s16(a, vdup_n_s16((-N).try_into().unwrap())) +} + +/// Signed rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrq_n_s16(a: int16x8_t) -> int16x8_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + vrshlq_s16(a, vdupq_n_s16((-N).try_into().unwrap())) +} + +/// Signed rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshr_n_s32(a: int32x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + vrshl_s32(a, vdup_n_s32((-N).try_into().unwrap())) +} + +/// Signed rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrq_n_s32(a: int32x4_t) -> int32x4_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + vrshlq_s32(a, vdupq_n_s32((-N).try_into().unwrap())) +} + +/// Signed rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshr_n_s64(a: int64x1_t) -> int64x1_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + vrshl_s64(a, vdup_n_s64((-N).try_into().unwrap())) +} + +/// Signed rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrq_n_s64(a: int64x2_t) -> int64x2_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + vrshlq_s64(a, vdupq_n_s64((-N).try_into().unwrap())) +} + +/// Unsigned rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshr_n_u8(a: uint8x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + vrshl_u8(a, vdup_n_s8((-N).try_into().unwrap())) +} + +/// Unsigned rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrq_n_u8(a: uint8x16_t) -> uint8x16_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + vrshlq_u8(a, vdupq_n_s8((-N).try_into().unwrap())) +} + +/// Unsigned rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshr_n_u16(a: uint16x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + vrshl_u16(a, vdup_n_s16((-N).try_into().unwrap())) +} + +/// Unsigned rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrq_n_u16(a: uint16x8_t) -> uint16x8_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + vrshlq_u16(a, vdupq_n_s16((-N).try_into().unwrap())) +} + +/// Unsigned rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshr_n_u32(a: uint32x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + vrshl_u32(a, vdup_n_s32((-N).try_into().unwrap())) +} + +/// Unsigned rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrq_n_u32(a: uint32x4_t) -> uint32x4_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + vrshlq_u32(a, vdupq_n_s32((-N).try_into().unwrap())) +} + +/// Unsigned rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshr_n_u64(a: uint64x1_t) -> uint64x1_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + vrshl_u64(a, vdup_n_s64((-N).try_into().unwrap())) +} + +/// Unsigned rounding shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshr, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(urshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrq_n_u64(a: uint64x2_t) -> uint64x2_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + vrshlq_u64(a, vdupq_n_s64((-N).try_into().unwrap())) +} + +/// Rounding shift right narrow +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_s16(a: int16x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftn.v8i8")] + fn vrshrn_n_s16_(a: int16x8_t, n: int16x8_t) -> int8x8_t; + } +vrshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16, -N as i16)) +} + +/// Rounding shift right narrow +#[inline] +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "neon")] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_s16(a: int16x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.rshrn.v8i8")] + fn vrshrn_n_s16_(a: int16x8_t, n: i32) -> int8x8_t; + } +vrshrn_n_s16_(a, N) +} + +/// Rounding shift right narrow +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_s32(a: int32x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftn.v4i16")] + fn vrshrn_n_s32_(a: int32x4_t, n: int32x4_t) -> int16x4_t; + } +vrshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) +} + +/// Rounding shift right narrow +#[inline] +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "neon")] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_s32(a: int32x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.rshrn.v4i16")] + fn vrshrn_n_s32_(a: int32x4_t, n: i32) -> int16x4_t; + } +vrshrn_n_s32_(a, N) +} + +/// Rounding shift right narrow +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_s64(a: int64x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrshiftn.v2i32")] + fn vrshrn_n_s64_(a: int64x2_t, n: int64x2_t) -> int32x2_t; + } +vrshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) +} + +/// Rounding shift right narrow +#[inline] +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "neon")] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_s64(a: int64x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.rshrn.v2i32")] + fn vrshrn_n_s64_(a: int64x2_t, n: i32) -> int32x2_t; + } +vrshrn_n_s64_(a, N) +} + +/// Rounding shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_u16(a: uint16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + transmute(vrshrn_n_s16::(transmute(a))) +} + +/// Rounding shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_u32(a: uint32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + transmute(vrshrn_n_s32::(transmute(a))) +} + +/// Rounding shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrshrn, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rshrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vrshrn_n_u64(a: uint64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + transmute(vrshrn_n_s64::(transmute(a))) +} + +/// Signed rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsra_n_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_add(a, vrshr_n_s8::(b)) +} + +/// Signed rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsraq_n_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_add(a, vrshrq_n_s8::(b)) +} + +/// Signed rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsra_n_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_add(a, vrshr_n_s16::(b)) +} + +/// Signed rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsraq_n_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_add(a, vrshrq_n_s16::(b)) +} + +/// Signed rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsra_n_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_add(a, vrshr_n_s32::(b)) +} + +/// Signed rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsraq_n_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_add(a, vrshrq_n_s32::(b)) +} + +/// Signed rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsra_n_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_add(a, vrshr_n_s64::(b)) +} + +/// Signed rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(srsra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsraq_n_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_add(a, vrshrq_n_s64::(b)) +} + +/// Unsigned rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsra_n_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_add(a, vrshr_n_u8::(b)) +} + +/// Unsigned rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsraq_n_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_add(a, vrshrq_n_u8::(b)) +} + +/// Unsigned rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsra_n_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_add(a, vrshr_n_u16::(b)) +} + +/// Unsigned rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsraq_n_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_add(a, vrshrq_n_u16::(b)) +} + +/// Unsigned rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsra_n_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_add(a, vrshr_n_u32::(b)) +} + +/// Unsigned rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsraq_n_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_add(a, vrshrq_n_u32::(b)) +} + +/// Unsigned rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsra_n_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_add(a, vrshr_n_u64::(b)) +} + +/// Unsigned rounding shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ursra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vrsraq_n_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_add(a, vrshrq_n_u64::(b)) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_s8(a: i8, b: int8x8_t) -> int8x8_t { + static_assert_imm3!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_s16(a: i16, b: int16x4_t) -> int16x4_t { + static_assert_imm2!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_s32(a: i32, b: int32x2_t) -> int32x2_t { + static_assert_imm1!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_s64(a: i64, b: int64x1_t) -> int64x1_t { + static_assert!(LANE : i32 where LANE == 0); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_u8(a: u8, b: uint8x8_t) -> uint8x8_t { + static_assert_imm3!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_u16(a: u16, b: uint16x4_t) -> uint16x4_t { + static_assert_imm2!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_u32(a: u32, b: uint32x2_t) -> uint32x2_t { + static_assert_imm1!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_u64(a: u64, b: uint64x1_t) -> uint64x1_t { + static_assert!(LANE : i32 where LANE == 0); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_p8(a: p8, b: poly8x8_t) -> poly8x8_t { + static_assert_imm3!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_p16(a: p16, b: poly16x4_t) -> poly16x4_t { + static_assert_imm2!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_p64(a: p64, b: poly64x1_t) -> poly64x1_t { + static_assert!(LANE : i32 where LANE == 0); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_s8(a: i8, b: int8x16_t) -> int8x16_t { + static_assert_imm4!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_s16(a: i16, b: int16x8_t) -> int16x8_t { + static_assert_imm3!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_s32(a: i32, b: int32x4_t) -> int32x4_t { + static_assert_imm2!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_s64(a: i64, b: int64x2_t) -> int64x2_t { + static_assert_imm1!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_u8(a: u8, b: uint8x16_t) -> uint8x16_t { + static_assert_imm4!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_u16(a: u16, b: uint16x8_t) -> uint16x8_t { + static_assert_imm3!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_u32(a: u32, b: uint32x4_t) -> uint32x4_t { + static_assert_imm2!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_u64(a: u64, b: uint64x2_t) -> uint64x2_t { + static_assert_imm1!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_p8(a: p8, b: poly8x16_t) -> poly8x16_t { + static_assert_imm4!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_p16(a: p16, b: poly16x8_t) -> poly16x8_t { + static_assert_imm3!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_p64(a: p64, b: poly64x2_t) -> poly64x2_t { + static_assert_imm1!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vset_lane_f32(a: f32, b: float32x2_t) -> float32x2_t { + static_assert_imm1!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Insert vector element from another vector element +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop, LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(nop, LANE = 0))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsetq_lane_f32(a: f32, b: float32x4_t) -> float32x4_t { + static_assert_imm2!(LANE); + simd_insert(b, LANE as u32, a) +} + +/// Signed Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] +pub unsafe fn vshl_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v8i8")] + fn vshl_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + } +vshl_s8_(a, b) +} + +/// Signed Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] +pub unsafe fn vshlq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v16i8")] + fn vshlq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + } +vshlq_s8_(a, b) +} + +/// Signed Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] +pub unsafe fn vshl_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v4i16")] + fn vshl_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + } +vshl_s16_(a, b) +} + +/// Signed Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] +pub unsafe fn vshlq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v8i16")] + fn vshlq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + } +vshlq_s16_(a, b) +} + +/// Signed Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] +pub unsafe fn vshl_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v2i32")] + fn vshl_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + } +vshl_s32_(a, b) +} + +/// Signed Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] +pub unsafe fn vshlq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v4i32")] + fn vshlq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + } +vshlq_s32_(a, b) +} + +/// Signed Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] +pub unsafe fn vshl_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v1i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v1i64")] + fn vshl_s64_(a: int64x1_t, b: int64x1_t) -> int64x1_t; + } +vshl_s64_(a, b) +} + +/// Signed Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshl))] +pub unsafe fn vshlq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshifts.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sshl.v2i64")] + fn vshlq_s64_(a: int64x2_t, b: int64x2_t) -> int64x2_t; + } +vshlq_s64_(a, b) +} + +/// Unsigned Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] +pub unsafe fn vshl_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v8i8")] + fn vshl_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; + } +vshl_u8_(a, b) +} + +/// Unsigned Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] +pub unsafe fn vshlq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v16i8")] + fn vshlq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; + } +vshlq_u8_(a, b) +} + +/// Unsigned Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] +pub unsafe fn vshl_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v4i16")] + fn vshl_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; + } +vshl_u16_(a, b) +} + +/// Unsigned Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] +pub unsafe fn vshlq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v8i16")] + fn vshlq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; + } +vshlq_u16_(a, b) +} + +/// Unsigned Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] +pub unsafe fn vshl_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v2i32")] + fn vshl_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; + } +vshl_u32_(a, b) +} + +/// Unsigned Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] +pub unsafe fn vshlq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v4i32")] + fn vshlq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; + } +vshlq_u32_(a, b) +} + +/// Unsigned Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] +pub unsafe fn vshl_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v1i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v1i64")] + fn vshl_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; + } +vshl_u64_(a, b) +} + +/// Unsigned Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushl))] +pub unsafe fn vshlq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vshiftu.v2i64")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ushl.v2i64")] + fn vshlq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; + } +vshlq_u64_(a, b) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshl_n_s8(a: int8x8_t) -> int8x8_t { + static_assert_imm3!(N); + simd_shl(a, vdup_n_s8(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshlq_n_s8(a: int8x16_t) -> int8x16_t { + static_assert_imm3!(N); + simd_shl(a, vdupq_n_s8(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshl_n_s16(a: int16x4_t) -> int16x4_t { + static_assert_imm4!(N); + simd_shl(a, vdup_n_s16(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshlq_n_s16(a: int16x8_t) -> int16x8_t { + static_assert_imm4!(N); + simd_shl(a, vdupq_n_s16(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshl_n_s32(a: int32x2_t) -> int32x2_t { + static_assert_imm5!(N); + simd_shl(a, vdup_n_s32(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshlq_n_s32(a: int32x4_t) -> int32x4_t { + static_assert_imm5!(N); + simd_shl(a, vdupq_n_s32(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshl_n_u8(a: uint8x8_t) -> uint8x8_t { + static_assert_imm3!(N); + simd_shl(a, vdup_n_u8(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshlq_n_u8(a: uint8x16_t) -> uint8x16_t { + static_assert_imm3!(N); + simd_shl(a, vdupq_n_u8(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshl_n_u16(a: uint16x4_t) -> uint16x4_t { + static_assert_imm4!(N); + simd_shl(a, vdup_n_u16(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshlq_n_u16(a: uint16x8_t) -> uint16x8_t { + static_assert_imm4!(N); + simd_shl(a, vdupq_n_u16(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshl_n_u32(a: uint32x2_t) -> uint32x2_t { + static_assert_imm5!(N); + simd_shl(a, vdup_n_u32(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshlq_n_u32(a: uint32x4_t) -> uint32x4_t { + static_assert_imm5!(N); + simd_shl(a, vdupq_n_u32(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshl_n_s64(a: int64x1_t) -> int64x1_t { + static_assert_imm6!(N); + simd_shl(a, vdup_n_s64(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshlq_n_s64(a: int64x2_t) -> int64x2_t { + static_assert_imm6!(N); + simd_shl(a, vdupq_n_s64(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshl_n_u64(a: uint64x1_t) -> uint64x1_t { + static_assert_imm6!(N); + simd_shl(a, vdup_n_u64(N.try_into().unwrap())) +} + +/// Shift left +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vshl, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshlq_n_u64(a: uint64x2_t) -> uint64x2_t { + static_assert_imm6!(N); + simd_shl(a, vdupq_n_u64(N.try_into().unwrap())) +} + +/// Signed shift left long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.s8", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshll, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshll_n_s8(a: int8x8_t) -> int16x8_t { + static_assert!(N : i32 where N >= 0 && N <= 8); + simd_shl(simd_cast(a), vdupq_n_s16(N.try_into().unwrap())) +} + +/// Signed shift left long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.s16", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshll, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshll_n_s16(a: int16x4_t) -> int32x4_t { + static_assert!(N : i32 where N >= 0 && N <= 16); + simd_shl(simd_cast(a), vdupq_n_s32(N.try_into().unwrap())) +} + +/// Signed shift left long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.s32", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshll, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshll_n_s32(a: int32x2_t) -> int64x2_t { + static_assert!(N : i32 where N >= 0 && N <= 32); + simd_shl(simd_cast(a), vdupq_n_s64(N.try_into().unwrap())) +} + +/// Signed shift left long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.u8", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushll, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshll_n_u8(a: uint8x8_t) -> uint16x8_t { + static_assert!(N : i32 where N >= 0 && N <= 8); + simd_shl(simd_cast(a), vdupq_n_u16(N.try_into().unwrap())) +} + +/// Signed shift left long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.u16", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushll, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshll_n_u16(a: uint16x4_t) -> uint32x4_t { + static_assert!(N : i32 where N >= 0 && N <= 16); + simd_shl(simd_cast(a), vdupq_n_u32(N.try_into().unwrap())) +} + +/// Signed shift left long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshll.u32", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushll, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshll_n_u32(a: uint32x2_t) -> uint64x2_t { + static_assert!(N : i32 where N >= 0 && N <= 32); + simd_shl(simd_cast(a), vdupq_n_u64(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s8", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshr_n_s8(a: int8x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_shr(a, vdup_n_s8(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s8", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrq_n_s8(a: int8x16_t) -> int8x16_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_shr(a, vdupq_n_s8(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s16", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshr_n_s16(a: int16x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_shr(a, vdup_n_s16(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s16", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrq_n_s16(a: int16x8_t) -> int16x8_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_shr(a, vdupq_n_s16(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s32", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshr_n_s32(a: int32x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_shr(a, vdup_n_s32(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s32", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrq_n_s32(a: int32x4_t) -> int32x4_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_shr(a, vdupq_n_s32(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s64", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshr_n_s64(a: int64x1_t) -> int64x1_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_shr(a, vdup_n_s64(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.s64", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sshr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrq_n_s64(a: int64x2_t) -> int64x2_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_shr(a, vdupq_n_s64(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u8", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshr_n_u8(a: uint8x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_shr(a, vdup_n_u8(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u8", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrq_n_u8(a: uint8x16_t) -> uint8x16_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_shr(a, vdupq_n_u8(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u16", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshr_n_u16(a: uint16x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_shr(a, vdup_n_u16(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u16", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrq_n_u16(a: uint16x8_t) -> uint16x8_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_shr(a, vdupq_n_u16(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u32", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshr_n_u32(a: uint32x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_shr(a, vdup_n_u32(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u32", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrq_n_u32(a: uint32x4_t) -> uint32x4_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_shr(a, vdupq_n_u32(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u64", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshr_n_u64(a: uint64x1_t) -> uint64x1_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_shr(a, vdup_n_u64(N.try_into().unwrap())) +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u64", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ushr, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrq_n_u64(a: uint64x2_t) -> uint64x2_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_shr(a, vdupq_n_u64(N.try_into().unwrap())) +} + +/// Shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i16", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrn_n_s16(a: int16x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_cast(simd_shr(a, vdupq_n_s16(N.try_into().unwrap()))) +} + +/// Shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i32", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrn_n_s32(a: int32x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_cast(simd_shr(a, vdupq_n_s32(N.try_into().unwrap()))) +} + +/// Shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i64", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrn_n_s64(a: int64x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_cast(simd_shr(a, vdupq_n_s64(N.try_into().unwrap()))) +} + +/// Shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i16", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrn_n_u16(a: uint16x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_cast(simd_shr(a, vdupq_n_u16(N.try_into().unwrap()))) +} + +/// Shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i32", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrn_n_u32(a: uint32x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_cast(simd_shr(a, vdupq_n_u32(N.try_into().unwrap()))) +} + +/// Shift right narrow +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshrn.i64", N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shrn, N = 2))] +#[rustc_legacy_const_generics(1)] +pub unsafe fn vshrn_n_u64(a: uint64x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_cast(simd_shr(a, vdupq_n_u64(N.try_into().unwrap()))) +} + +/// Signed shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsra_n_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_add(a, vshr_n_s8::(b)) +} + +/// Signed shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsraq_n_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_add(a, vshrq_n_s8::(b)) +} + +/// Signed shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsra_n_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_add(a, vshr_n_s16::(b)) +} + +/// Signed shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsraq_n_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_add(a, vshrq_n_s16::(b)) +} + +/// Signed shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsra_n_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_add(a, vshr_n_s32::(b)) +} + +/// Signed shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsraq_n_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_add(a, vshrq_n_s32::(b)) +} + +/// Signed shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsra_n_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_add(a, vshr_n_s64::(b)) +} + +/// Signed shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ssra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsraq_n_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_add(a, vshrq_n_s64::(b)) +} + +/// Unsigned shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsra_n_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_add(a, vshr_n_u8::(b)) +} + +/// Unsigned shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsraq_n_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { + static_assert!(N : i32 where N >= 1 && N <= 8); + simd_add(a, vshrq_n_u8::(b)) +} + +/// Unsigned shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsra_n_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_add(a, vshr_n_u16::(b)) +} + +/// Unsigned shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsraq_n_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + static_assert!(N : i32 where N >= 1 && N <= 16); + simd_add(a, vshrq_n_u16::(b)) +} + +/// Unsigned shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsra_n_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_add(a, vshr_n_u32::(b)) +} + +/// Unsigned shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsraq_n_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + static_assert!(N : i32 where N >= 1 && N <= 32); + simd_add(a, vshrq_n_u32::(b)) +} + +/// Unsigned shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsra_n_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_add(a, vshr_n_u64::(b)) +} + +/// Unsigned shift right and accumulate +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vsra, N = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(usra, N = 2))] +#[rustc_legacy_const_generics(2)] +pub unsafe fn vsraq_n_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { + static_assert!(N : i32 where N >= 1 && N <= 64); + simd_add(a, vshrq_n_u64::(b)) +} + +/// Unsigned Absolute difference and Accumulate Long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.u8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabal))] +pub unsafe fn vabal_u8(a: uint16x8_t, b: uint8x8_t, c: uint8x8_t) -> uint16x8_t { + let d: uint8x8_t = vabd_u8(b, c); + simd_add(a, simd_cast(d)) +} + +/// Unsigned Absolute difference and Accumulate Long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.u16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabal))] +pub unsafe fn vabal_u16(a: uint32x4_t, b: uint16x4_t, c: uint16x4_t) -> uint32x4_t { + let d: uint16x4_t = vabd_u16(b, c); + simd_add(a, simd_cast(d)) +} + +/// Unsigned Absolute difference and Accumulate Long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.u32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uabal))] +pub unsafe fn vabal_u32(a: uint64x2_t, b: uint32x2_t, c: uint32x2_t) -> uint64x2_t { + let d: uint32x2_t = vabd_u32(b, c); + simd_add(a, simd_cast(d)) +} + +/// Signed Absolute difference and Accumulate Long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.s8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabal))] +pub unsafe fn vabal_s8(a: int16x8_t, b: int8x8_t, c: int8x8_t) -> int16x8_t { + let d: int8x8_t = vabd_s8(b, c); + let e: uint8x8_t = simd_cast(d); + simd_add(a, simd_cast(e)) +} + +/// Signed Absolute difference and Accumulate Long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.s16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabal))] +pub unsafe fn vabal_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { + let d: int16x4_t = vabd_s16(b, c); + let e: uint16x4_t = simd_cast(d); + simd_add(a, simd_cast(e)) +} + +/// Signed Absolute difference and Accumulate Long +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vabal.s32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sabal))] +pub unsafe fn vabal_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { + let d: int32x2_t = vabd_s32(b, c); + let e: uint32x2_t = simd_cast(d); + simd_add(a, simd_cast(e)) +} + +/// Singned saturating Absolute value +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] +pub unsafe fn vqabs_s8(a: int8x8_t) -> int8x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v8i8")] + fn vqabs_s8_(a: int8x8_t) -> int8x8_t; + } +vqabs_s8_(a) +} + +/// Singned saturating Absolute value +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] +pub unsafe fn vqabsq_s8(a: int8x16_t) -> int8x16_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v16i8")] + fn vqabsq_s8_(a: int8x16_t) -> int8x16_t; + } +vqabsq_s8_(a) +} + +/// Singned saturating Absolute value +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] +pub unsafe fn vqabs_s16(a: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v4i16")] + fn vqabs_s16_(a: int16x4_t) -> int16x4_t; + } +vqabs_s16_(a) +} + +/// Singned saturating Absolute value +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] +pub unsafe fn vqabsq_s16(a: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v8i16")] + fn vqabsq_s16_(a: int16x8_t) -> int16x8_t; + } +vqabsq_s16_(a) +} + +/// Singned saturating Absolute value +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] +pub unsafe fn vqabs_s32(a: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v2i32")] + fn vqabs_s32_(a: int32x2_t) -> int32x2_t; + } +vqabs_s32_(a) +} + +/// Singned saturating Absolute value +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vqabs.s32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sqabs))] +pub unsafe fn vqabsq_s32(a: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vqabs.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.sqabs.v4i32")] + fn vqabsq_s32_(a: int32x4_t) -> int32x4_t; + } +vqabsq_s32_(a) +} + +#[cfg(test)] +#[allow(overflowing_literals)] +mod test { + use super::*; + use crate::core_arch::simd::*; + use std::mem::transmute; + use stdarch_test::simd_test; + + #[simd_test(enable = "neon")] + unsafe fn test_vand_s8() { + let a: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i8x8 = i8x8::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); + let e: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: i8x8 = transmute(vand_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i8x8 = i8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i8x8 = i8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let r: i8x8 = transmute(vand_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vandq_s8() { let a: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); let b: i8x16 = i8x16::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); let e: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); let r: i8x16 = transmute(vandq_s8(transmute(a), transmute(b))); assert_eq!(r, e); - let a: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); - let b: i8x16 = i8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i8x16 = i8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let r: i8x16 = transmute(vandq_s8(transmute(a), transmute(b))); + let a: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); + let b: i8x16 = i8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i8x16 = i8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let r: i8x16 = transmute(vandq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vand_s16() { + let a: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); + let b: i16x4 = i16x4::new(0x0F, 0x0F, 0x0F, 0x0F); + let e: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); + let r: i16x4 = transmute(vand_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); + let b: i16x4 = i16x4::new(0x00, 0x00, 0x00, 0x00); + let e: i16x4 = i16x4::new(0x00, 0x00, 0x00, 0x00); + let r: i16x4 = transmute(vand_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vandq_s16() { + let a: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i16x8 = i16x8::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); + let e: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: i16x8 = transmute(vandq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i16x8 = i16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i16x8 = i16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let r: i16x8 = transmute(vandq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vand_s32() { + let a: i32x2 = i32x2::new(0x00, 0x01); + let b: i32x2 = i32x2::new(0x0F, 0x0F); + let e: i32x2 = i32x2::new(0x00, 0x01); + let r: i32x2 = transmute(vand_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i32x2 = i32x2::new(0x00, 0x01); + let b: i32x2 = i32x2::new(0x00, 0x00); + let e: i32x2 = i32x2::new(0x00, 0x00); + let r: i32x2 = transmute(vand_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vandq_s32() { + let a: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); + let b: i32x4 = i32x4::new(0x0F, 0x0F, 0x0F, 0x0F); + let e: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); + let r: i32x4 = transmute(vandq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); + let b: i32x4 = i32x4::new(0x00, 0x00, 0x00, 0x00); + let e: i32x4 = i32x4::new(0x00, 0x00, 0x00, 0x00); + let r: i32x4 = transmute(vandq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vand_u8() { + let a: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u8x8 = u8x8::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); + let e: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: u8x8 = transmute(vand_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u8x8 = u8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u8x8 = u8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let r: u8x8 = transmute(vand_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vandq_u8() { + let a: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); + let b: u8x16 = u8x16::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); + let e: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); + let r: u8x16 = transmute(vandq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); + let b: u8x16 = u8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u8x16 = u8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let r: u8x16 = transmute(vandq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vand_u16() { + let a: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); + let b: u16x4 = u16x4::new(0x0F, 0x0F, 0x0F, 0x0F); + let e: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); + let r: u16x4 = transmute(vand_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); + let b: u16x4 = u16x4::new(0x00, 0x00, 0x00, 0x00); + let e: u16x4 = u16x4::new(0x00, 0x00, 0x00, 0x00); + let r: u16x4 = transmute(vand_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vandq_u16() { + let a: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u16x8 = u16x8::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); + let e: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: u16x8 = transmute(vandq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u16x8 = u16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u16x8 = u16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let r: u16x8 = transmute(vandq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vand_u32() { + let a: u32x2 = u32x2::new(0x00, 0x01); + let b: u32x2 = u32x2::new(0x0F, 0x0F); + let e: u32x2 = u32x2::new(0x00, 0x01); + let r: u32x2 = transmute(vand_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u32x2 = u32x2::new(0x00, 0x01); + let b: u32x2 = u32x2::new(0x00, 0x00); + let e: u32x2 = u32x2::new(0x00, 0x00); + let r: u32x2 = transmute(vand_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vandq_u32() { + let a: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); + let b: u32x4 = u32x4::new(0x0F, 0x0F, 0x0F, 0x0F); + let e: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); + let r: u32x4 = transmute(vandq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); + let b: u32x4 = u32x4::new(0x00, 0x00, 0x00, 0x00); + let e: u32x4 = u32x4::new(0x00, 0x00, 0x00, 0x00); + let r: u32x4 = transmute(vandq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vand_s64() { + let a: i64x1 = i64x1::new(0x00); + let b: i64x1 = i64x1::new(0x0F); + let e: i64x1 = i64x1::new(0x00); + let r: i64x1 = transmute(vand_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i64x1 = i64x1::new(0x00); + let b: i64x1 = i64x1::new(0x00); + let e: i64x1 = i64x1::new(0x00); + let r: i64x1 = transmute(vand_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vandq_s64() { + let a: i64x2 = i64x2::new(0x00, 0x01); + let b: i64x2 = i64x2::new(0x0F, 0x0F); + let e: i64x2 = i64x2::new(0x00, 0x01); + let r: i64x2 = transmute(vandq_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i64x2 = i64x2::new(0x00, 0x01); + let b: i64x2 = i64x2::new(0x00, 0x00); + let e: i64x2 = i64x2::new(0x00, 0x00); + let r: i64x2 = transmute(vandq_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vand_u64() { + let a: u64x1 = u64x1::new(0x00); + let b: u64x1 = u64x1::new(0x0F); + let e: u64x1 = u64x1::new(0x00); + let r: u64x1 = transmute(vand_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u64x1 = u64x1::new(0x00); + let b: u64x1 = u64x1::new(0x00); + let e: u64x1 = u64x1::new(0x00); + let r: u64x1 = transmute(vand_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vandq_u64() { + let a: u64x2 = u64x2::new(0x00, 0x01); + let b: u64x2 = u64x2::new(0x0F, 0x0F); + let e: u64x2 = u64x2::new(0x00, 0x01); + let r: u64x2 = transmute(vandq_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u64x2 = u64x2::new(0x00, 0x01); + let b: u64x2 = u64x2::new(0x00, 0x00); + let e: u64x2 = u64x2::new(0x00, 0x00); + let r: u64x2 = transmute(vandq_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorr_s8() { + let a: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i8x8 = i8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: i8x8 = transmute(vorr_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorrq_s8() { + let a: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); + let b: i8x16 = i8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); + let r: i8x16 = transmute(vorrq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorr_s16() { + let a: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); + let b: i16x4 = i16x4::new(0x00, 0x00, 0x00, 0x00); + let e: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); + let r: i16x4 = transmute(vorr_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorrq_s16() { + let a: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i16x8 = i16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: i16x8 = transmute(vorrq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorr_s32() { + let a: i32x2 = i32x2::new(0x00, 0x01); + let b: i32x2 = i32x2::new(0x00, 0x00); + let e: i32x2 = i32x2::new(0x00, 0x01); + let r: i32x2 = transmute(vorr_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorrq_s32() { + let a: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); + let b: i32x4 = i32x4::new(0x00, 0x00, 0x00, 0x00); + let e: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); + let r: i32x4 = transmute(vorrq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorr_u8() { + let a: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u8x8 = u8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: u8x8 = transmute(vorr_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorrq_u8() { + let a: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); + let b: u8x16 = u8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); + let r: u8x16 = transmute(vorrq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorr_u16() { + let a: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); + let b: u16x4 = u16x4::new(0x00, 0x00, 0x00, 0x00); + let e: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); + let r: u16x4 = transmute(vorr_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorrq_u16() { + let a: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u16x8 = u16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: u16x8 = transmute(vorrq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorr_u32() { + let a: u32x2 = u32x2::new(0x00, 0x01); + let b: u32x2 = u32x2::new(0x00, 0x00); + let e: u32x2 = u32x2::new(0x00, 0x01); + let r: u32x2 = transmute(vorr_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorrq_u32() { + let a: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); + let b: u32x4 = u32x4::new(0x00, 0x00, 0x00, 0x00); + let e: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); + let r: u32x4 = transmute(vorrq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorr_s64() { + let a: i64x1 = i64x1::new(0x00); + let b: i64x1 = i64x1::new(0x00); + let e: i64x1 = i64x1::new(0x00); + let r: i64x1 = transmute(vorr_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorrq_s64() { + let a: i64x2 = i64x2::new(0x00, 0x01); + let b: i64x2 = i64x2::new(0x00, 0x00); + let e: i64x2 = i64x2::new(0x00, 0x01); + let r: i64x2 = transmute(vorrq_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorr_u64() { + let a: u64x1 = u64x1::new(0x00); + let b: u64x1 = u64x1::new(0x00); + let e: u64x1 = u64x1::new(0x00); + let r: u64x1 = transmute(vorr_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vorrq_u64() { + let a: u64x2 = u64x2::new(0x00, 0x01); + let b: u64x2 = u64x2::new(0x00, 0x00); + let e: u64x2 = u64x2::new(0x00, 0x01); + let r: u64x2 = transmute(vorrq_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veor_s8() { + let a: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i8x8 = i8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: i8x8 = transmute(veor_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veorq_s8() { + let a: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); + let b: i8x16 = i8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); + let r: i8x16 = transmute(veorq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veor_s16() { + let a: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); + let b: i16x4 = i16x4::new(0x00, 0x00, 0x00, 0x00); + let e: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); + let r: i16x4 = transmute(veor_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veorq_s16() { + let a: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i16x8 = i16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: i16x8 = transmute(veorq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veor_s32() { + let a: i32x2 = i32x2::new(0x00, 0x01); + let b: i32x2 = i32x2::new(0x00, 0x00); + let e: i32x2 = i32x2::new(0x00, 0x01); + let r: i32x2 = transmute(veor_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veorq_s32() { + let a: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); + let b: i32x4 = i32x4::new(0x00, 0x00, 0x00, 0x00); + let e: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); + let r: i32x4 = transmute(veorq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veor_u8() { + let a: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u8x8 = u8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: u8x8 = transmute(veor_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veorq_u8() { + let a: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); + let b: u8x16 = u8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); + let r: u8x16 = transmute(veorq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veor_u16() { + let a: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); + let b: u16x4 = u16x4::new(0x00, 0x00, 0x00, 0x00); + let e: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); + let r: u16x4 = transmute(veor_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veorq_u16() { + let a: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u16x8 = u16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let r: u16x8 = transmute(veorq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veor_u32() { + let a: u32x2 = u32x2::new(0x00, 0x01); + let b: u32x2 = u32x2::new(0x00, 0x00); + let e: u32x2 = u32x2::new(0x00, 0x01); + let r: u32x2 = transmute(veor_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veorq_u32() { + let a: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); + let b: u32x4 = u32x4::new(0x00, 0x00, 0x00, 0x00); + let e: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); + let r: u32x4 = transmute(veorq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veor_s64() { + let a: i64x1 = i64x1::new(0x00); + let b: i64x1 = i64x1::new(0x00); + let e: i64x1 = i64x1::new(0x00); + let r: i64x1 = transmute(veor_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veorq_s64() { + let a: i64x2 = i64x2::new(0x00, 0x01); + let b: i64x2 = i64x2::new(0x00, 0x00); + let e: i64x2 = i64x2::new(0x00, 0x01); + let r: i64x2 = transmute(veorq_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veor_u64() { + let a: u64x1 = u64x1::new(0x00); + let b: u64x1 = u64x1::new(0x00); + let e: u64x1 = u64x1::new(0x00); + let r: u64x1 = transmute(veor_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_veorq_u64() { + let a: u64x2 = u64x2::new(0x00, 0x01); + let b: u64x2 = u64x2::new(0x00, 0x00); + let e: u64x2 = u64x2::new(0x00, 0x01); + let r: u64x2 = transmute(veorq_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabd_s8() { + let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i8x8 = i8x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: i8x8 = i8x8::new(15, 13, 11, 9, 7, 5, 3, 1); + let r: i8x8 = transmute(vabd_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdq_s8() { + let a: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: i8x16 = i8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let e: i8x16 = i8x16::new(15, 13, 11, 9, 7, 5, 3, 1, 1, 3, 5, 7, 9, 11, 13, 15); + let r: i8x16 = transmute(vabdq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabd_s16() { + let a: i16x4 = i16x4::new(1, 2, 3, 4); + let b: i16x4 = i16x4::new(16, 15, 14, 13); + let e: i16x4 = i16x4::new(15, 13, 11, 9); + let r: i16x4 = transmute(vabd_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdq_s16() { + let a: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i16x8 = i16x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: i16x8 = i16x8::new(15, 13, 11, 9, 7, 5, 3, 1); + let r: i16x8 = transmute(vabdq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabd_s32() { + let a: i32x2 = i32x2::new(1, 2); + let b: i32x2 = i32x2::new(16, 15); + let e: i32x2 = i32x2::new(15, 13); + let r: i32x2 = transmute(vabd_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdq_s32() { + let a: i32x4 = i32x4::new(1, 2, 3, 4); + let b: i32x4 = i32x4::new(16, 15, 14, 13); + let e: i32x4 = i32x4::new(15, 13, 11, 9); + let r: i32x4 = transmute(vabdq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabd_u8() { + let a: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u8x8 = u8x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: u8x8 = u8x8::new(15, 13, 11, 9, 7, 5, 3, 1); + let r: u8x8 = transmute(vabd_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdq_u8() { + let a: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: u8x16 = u8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let e: u8x16 = u8x16::new(15, 13, 11, 9, 7, 5, 3, 1, 1, 3, 5, 7, 9, 11, 13, 15); + let r: u8x16 = transmute(vabdq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabd_u16() { + let a: u16x4 = u16x4::new(1, 2, 3, 4); + let b: u16x4 = u16x4::new(16, 15, 14, 13); + let e: u16x4 = u16x4::new(15, 13, 11, 9); + let r: u16x4 = transmute(vabd_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdq_u16() { + let a: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u16x8 = u16x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: u16x8 = u16x8::new(15, 13, 11, 9, 7, 5, 3, 1); + let r: u16x8 = transmute(vabdq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabd_u32() { + let a: u32x2 = u32x2::new(1, 2); + let b: u32x2 = u32x2::new(16, 15); + let e: u32x2 = u32x2::new(15, 13); + let r: u32x2 = transmute(vabd_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdq_u32() { + let a: u32x4 = u32x4::new(1, 2, 3, 4); + let b: u32x4 = u32x4::new(16, 15, 14, 13); + let e: u32x4 = u32x4::new(15, 13, 11, 9); + let r: u32x4 = transmute(vabdq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabd_f32() { + let a: f32x2 = f32x2::new(1.0, 2.0); + let b: f32x2 = f32x2::new(9.0, 3.0); + let e: f32x2 = f32x2::new(8.0, 1.0); + let r: f32x2 = transmute(vabd_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdq_f32() { + let a: f32x4 = f32x4::new(1.0, 2.0, 5.0, -4.0); + let b: f32x4 = f32x4::new(9.0, 3.0, 2.0, 8.0); + let e: f32x4 = f32x4::new(8.0, 1.0, 3.0, 12.0); + let r: f32x4 = transmute(vabdq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdl_u8() { + let a: u8x8 = u8x8::new(1, 2, 3, 4, 4, 3, 2, 1); + let b: u8x8 = u8x8::new(10, 10, 10, 10, 10, 10, 10, 10); + let e: u16x8 = u16x8::new(9, 8, 7, 6, 6, 7, 8, 9); + let r: u16x8 = transmute(vabdl_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdl_u16() { + let a: u16x4 = u16x4::new(1, 2, 3, 4); + let b: u16x4 = u16x4::new(10, 10, 10, 10); + let e: u32x4 = u32x4::new(9, 8, 7, 6); + let r: u32x4 = transmute(vabdl_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdl_u32() { + let a: u32x2 = u32x2::new(1, 2); + let b: u32x2 = u32x2::new(10, 10); + let e: u64x2 = u64x2::new(9, 8); + let r: u64x2 = transmute(vabdl_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdl_s8() { + let a: i8x8 = i8x8::new(1, 2, 3, 4, 4, 3, 2, 1); + let b: i8x8 = i8x8::new(10, 10, 10, 10, 10, 10, 10, 10); + let e: i16x8 = i16x8::new(9, 8, 7, 6, 6, 7, 8, 9); + let r: i16x8 = transmute(vabdl_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdl_s16() { + let a: i16x4 = i16x4::new(1, 2, 11, 12); + let b: i16x4 = i16x4::new(10, 10, 10, 10); + let e: i32x4 = i32x4::new(9, 8, 1, 2); + let r: i32x4 = transmute(vabdl_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabdl_s32() { + let a: i32x2 = i32x2::new(1, 11); + let b: i32x2 = i32x2::new(10, 10); + let e: i64x2 = i64x2::new(9, 1); + let r: i64x2 = transmute(vabdl_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceq_u8() { + let a: u8x8 = u8x8::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u8x8 = u8x8::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vceq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u8x8 = u8x8::new(0, 0, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u8x8 = u8x8::new(0, 0xFF, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); + let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); + let r: u8x8 = transmute(vceq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceqq_u8() { + let a: u8x16 = u8x16::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0xFF); + let b: u8x16 = u8x16::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0xFF); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vceqq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u8x16 = u8x16::new(0, 0, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xCC, 0x0D, 0xEE, 0xFF); + let b: u8x16 = u8x16::new(0, 0xFF, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08, 0x08, 0x00, 0x0A, 0x0A, 0xCC, 0xD0, 0xEE, 0); + let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); + let r: u8x16 = transmute(vceqq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceq_u16() { + let a: u16x4 = u16x4::new(0, 0x01, 0x02, 0x03); + let b: u16x4 = u16x4::new(0, 0x01, 0x02, 0x03); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vceq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u16x4 = u16x4::new(0, 0, 0x02, 0x03); + let b: u16x4 = u16x4::new(0, 0xFF_FF, 0x02, 0x04); + let e: u16x4 = u16x4::new(0xFF_FF, 0, 0xFF_FF, 0); + let r: u16x4 = transmute(vceq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceqq_u16() { + let a: u16x8 = u16x8::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u16x8 = u16x8::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vceqq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u16x8 = u16x8::new(0, 0, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: u16x8 = u16x8::new(0, 0xFF_FF, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); + let e: u16x8 = u16x8::new(0xFF_FF, 0, 0xFF_FF, 0, 0xFF_FF, 0, 0xFF_FF, 0); + let r: u16x8 = transmute(vceqq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceq_u32() { + let a: u32x2 = u32x2::new(0, 0x01); + let b: u32x2 = u32x2::new(0, 0x01); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vceq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u32x2 = u32x2::new(0, 0); + let b: u32x2 = u32x2::new(0, 0xFF_FF_FF_FF); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0); + let r: u32x2 = transmute(vceq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceqq_u32() { + let a: u32x4 = u32x4::new(0, 0x01, 0x02, 0x03); + let b: u32x4 = u32x4::new(0, 0x01, 0x02, 0x03); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vceqq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: u32x4 = u32x4::new(0, 0, 0x02, 0x03); + let b: u32x4 = u32x4::new(0, 0xFF_FF_FF_FF, 0x02, 0x04); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF, 0); + let r: u32x4 = transmute(vceqq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceq_s8() { + let a: i8x8 = i8x8::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i8x8 = i8x8::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vceq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i8x8 = i8x8::new(-128, -128, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i8x8 = i8x8::new(-128, 0x7F, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); + let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); + let r: u8x8 = transmute(vceq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceqq_s8() { + let a: i8x16 = i8x16::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x7F); + let b: i8x16 = i8x16::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x7F); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vceqq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i8x16 = i8x16::new(-128, -128, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xCC, 0x0D, 0xEE, 0x7F); + let b: i8x16 = i8x16::new(-128, 0x7F, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08, 0x08, 0x00, 0x0A, 0x0A, 0xCC, 0xD0, 0xEE, -128); + let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); + let r: u8x16 = transmute(vceqq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceq_s16() { + let a: i16x4 = i16x4::new(-32768, 0x01, 0x02, 0x03); + let b: i16x4 = i16x4::new(-32768, 0x01, 0x02, 0x03); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vceq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i16x4 = i16x4::new(-32768, -32768, 0x02, 0x03); + let b: i16x4 = i16x4::new(-32768, 0x7F_FF, 0x02, 0x04); + let e: u16x4 = u16x4::new(0xFF_FF, 0, 0xFF_FF, 0); + let r: u16x4 = transmute(vceq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceqq_s16() { + let a: i16x8 = i16x8::new(-32768, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i16x8 = i16x8::new(-32768, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vceqq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i16x8 = i16x8::new(-32768, -32768, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i16x8 = i16x8::new(-32768, 0x7F_FF, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); + let e: u16x8 = u16x8::new(0xFF_FF, 0, 0xFF_FF, 0, 0xFF_FF, 0, 0xFF_FF, 0); + let r: u16x8 = transmute(vceqq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceq_s32() { + let a: i32x2 = i32x2::new(-2147483648, 0x01); + let b: i32x2 = i32x2::new(-2147483648, 0x01); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vceq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i32x2 = i32x2::new(-2147483648, -2147483648); + let b: i32x2 = i32x2::new(-2147483648, 0x7F_FF_FF_FF); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0); + let r: u32x2 = transmute(vceq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceqq_s32() { + let a: i32x4 = i32x4::new(-2147483648, 0x01, 0x02, 0x03); + let b: i32x4 = i32x4::new(-2147483648, 0x01, 0x02, 0x03); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vceqq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i32x4 = i32x4::new(-2147483648, -2147483648, 0x02, 0x03); + let b: i32x4 = i32x4::new(-2147483648, 0x7F_FF_FF_FF, 0x02, 0x04); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF, 0); + let r: u32x4 = transmute(vceqq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceq_p8() { + let a: i8x8 = i8x8::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i8x8 = i8x8::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vceq_p8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i8x8 = i8x8::new(-128, -128, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); + let b: i8x8 = i8x8::new(-128, 0x7F, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); + let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); + let r: u8x8 = transmute(vceq_p8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceqq_p8() { + let a: i8x16 = i8x16::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x7F); + let b: i8x16 = i8x16::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x7F); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vceqq_p8(transmute(a), transmute(b))); + assert_eq!(r, e); + + let a: i8x16 = i8x16::new(-128, -128, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xCC, 0x0D, 0xEE, 0x7F); + let b: i8x16 = i8x16::new(-128, 0x7F, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08, 0x08, 0x00, 0x0A, 0x0A, 0xCC, 0xD0, 0xEE, -128); + let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); + let r: u8x16 = transmute(vceqq_p8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vand_s16() { - let a: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); - let b: i16x4 = i16x4::new(0x0F, 0x0F, 0x0F, 0x0F); - let e: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); - let r: i16x4 = transmute(vand_s16(transmute(a), transmute(b))); + unsafe fn test_vceq_f32() { + let a: f32x2 = f32x2::new(1.2, 3.4); + let b: f32x2 = f32x2::new(1.2, 3.4); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vceq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vceqq_f32() { + let a: f32x4 = f32x4::new(1.2, 3.4, 5.6, 7.8); + let b: f32x4 = f32x4::new(1.2, 3.4, 5.6, 7.8); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vceqq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtst_s8() { + let a: i8x8 = i8x8::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let b: i8x8 = i8x8::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vtst_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtstq_s8() { + let a: i8x16 = i8x16::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x7F); + let b: i8x16 = i8x16::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x7F); + let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vtstq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtst_s16() { + let a: i16x4 = i16x4::new(-32768, 0x00, 0x01, 0x02); + let b: i16x4 = i16x4::new(-32768, 0x00, 0x01, 0x02); + let e: u16x4 = u16x4::new(0xFF_FF, 0, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vtst_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtstq_s16() { + let a: i16x8 = i16x8::new(-32768, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let b: i16x8 = i16x8::new(-32768, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let e: u16x8 = u16x8::new(0xFF_FF, 0, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vtstq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtst_s32() { + let a: i32x2 = i32x2::new(-2147483648, 0x00); + let b: i32x2 = i32x2::new(-2147483648, 0x00); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0); + let r: u32x2 = transmute(vtst_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtstq_s32() { + let a: i32x4 = i32x4::new(-2147483648, 0x00, 0x01, 0x02); + let b: i32x4 = i32x4::new(-2147483648, 0x00, 0x01, 0x02); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vtstq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtst_p8() { + let a: i8x8 = i8x8::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let b: i8x8 = i8x8::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vtst_p8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtstq_p8() { + let a: i8x16 = i8x16::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x7F); + let b: i8x16 = i8x16::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x7F); + let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vtstq_p8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtst_u8() { + let a: u8x8 = u8x8::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let b: u8x8 = u8x8::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let e: u8x8 = u8x8::new(0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vtst_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtstq_u8() { + let a: u8x16 = u8x16::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0xFF); + let b: u8x16 = u8x16::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0xFF); + let e: u8x16 = u8x16::new(0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vtstq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtst_u16() { + let a: u16x4 = u16x4::new(0, 0x00, 0x01, 0x02); + let b: u16x4 = u16x4::new(0, 0x00, 0x01, 0x02); + let e: u16x4 = u16x4::new(0, 0, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vtst_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtstq_u16() { + let a: u16x8 = u16x8::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let b: u16x8 = u16x8::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); + let e: u16x8 = u16x8::new(0, 0, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vtstq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtst_u32() { + let a: u32x2 = u32x2::new(0, 0x00); + let b: u32x2 = u32x2::new(0, 0x00); + let e: u32x2 = u32x2::new(0, 0); + let r: u32x2 = transmute(vtst_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vtstq_u32() { + let a: u32x4 = u32x4::new(0, 0x00, 0x01, 0x02); + let b: u32x4 = u32x4::new(0, 0x00, 0x01, 0x02); + let e: u32x4 = u32x4::new(0, 0, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vtstq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabs_f32() { + let a: f32x2 = f32x2::new(-0.1, -2.2); + let e: f32x2 = f32x2::new(0.1, 2.2); + let r: f32x2 = transmute(vabs_f32(transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vabsq_f32() { + let a: f32x4 = f32x4::new(-0.1, -2.2, -3.3, -6.6); + let e: f32x4 = f32x4::new(0.1, 2.2, 3.3, 6.6); + let r: f32x4 = transmute(vabsq_f32(transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgt_s8() { + let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vcgt_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgtq_s8() { + let a: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vcgtq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgt_s16() { + let a: i16x4 = i16x4::new(1, 2, 3, 4); + let b: i16x4 = i16x4::new(0, 1, 2, 3); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vcgt_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgtq_s16() { + let a: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vcgtq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgt_s32() { + let a: i32x2 = i32x2::new(1, 2); + let b: i32x2 = i32x2::new(0, 1); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcgt_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgtq_s32() { + let a: i32x4 = i32x4::new(1, 2, 3, 4); + let b: i32x4 = i32x4::new(0, 1, 2, 3); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcgtq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgt_u8() { + let a: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vcgt_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgtq_u8() { + let a: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vcgtq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcgt_u16() { + let a: u16x4 = u16x4::new(1, 2, 3, 4); + let b: u16x4 = u16x4::new(0, 1, 2, 3); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vcgt_u16(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); - let b: i16x4 = i16x4::new(0x00, 0x00, 0x00, 0x00); - let e: i16x4 = i16x4::new(0x00, 0x00, 0x00, 0x00); - let r: i16x4 = transmute(vand_s16(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcgtq_u16() { + let a: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vcgtq_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vandq_s16() { - let a: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i16x8 = i16x8::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); - let e: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: i16x8 = transmute(vandq_s16(transmute(a), transmute(b))); + unsafe fn test_vcgt_u32() { + let a: u32x2 = u32x2::new(1, 2); + let b: u32x2 = u32x2::new(0, 1); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcgt_u32(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i16x8 = i16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i16x8 = i16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let r: i16x8 = transmute(vandq_s16(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcgtq_u32() { + let a: u32x4 = u32x4::new(1, 2, 3, 4); + let b: u32x4 = u32x4::new(0, 1, 2, 3); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcgtq_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vand_s32() { - let a: i32x2 = i32x2::new(0x00, 0x01); - let b: i32x2 = i32x2::new(0x0F, 0x0F); - let e: i32x2 = i32x2::new(0x00, 0x01); - let r: i32x2 = transmute(vand_s32(transmute(a), transmute(b))); + unsafe fn test_vcgt_f32() { + let a: f32x2 = f32x2::new(1.2, 2.3); + let b: f32x2 = f32x2::new(0.1, 1.2); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcgt_f32(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: i32x2 = i32x2::new(0x00, 0x01); - let b: i32x2 = i32x2::new(0x00, 0x00); - let e: i32x2 = i32x2::new(0x00, 0x00); - let r: i32x2 = transmute(vand_s32(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcgtq_f32() { + let a: f32x4 = f32x4::new(1.2, 2.3, 3.4, 4.5); + let b: f32x4 = f32x4::new(0.1, 1.2, 2.3, 3.4); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcgtq_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vandq_s32() { - let a: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); - let b: i32x4 = i32x4::new(0x0F, 0x0F, 0x0F, 0x0F); - let e: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); - let r: i32x4 = transmute(vandq_s32(transmute(a), transmute(b))); + unsafe fn test_vclt_s8() { + let a: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vclt_s8(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); - let b: i32x4 = i32x4::new(0x00, 0x00, 0x00, 0x00); - let e: i32x4 = i32x4::new(0x00, 0x00, 0x00, 0x00); - let r: i32x4 = transmute(vandq_s32(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcltq_s8() { + let a: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vcltq_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vand_u8() { - let a: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u8x8 = u8x8::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); - let e: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: u8x8 = transmute(vand_u8(transmute(a), transmute(b))); + unsafe fn test_vclt_s16() { + let a: i16x4 = i16x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(1, 2, 3, 4); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vclt_s16(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u8x8 = u8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u8x8 = u8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let r: u8x8 = transmute(vand_u8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcltq_s16() { + let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vcltq_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vandq_u8() { - let a: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); - let b: u8x16 = u8x16::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); - let e: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); - let r: u8x16 = transmute(vandq_u8(transmute(a), transmute(b))); + unsafe fn test_vclt_s32() { + let a: i32x2 = i32x2::new(0, 1); + let b: i32x2 = i32x2::new(1, 2); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vclt_s32(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x00); - let b: u8x16 = u8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u8x16 = u8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let r: u8x16 = transmute(vandq_u8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcltq_s32() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i32x4 = i32x4::new(1, 2, 3, 4); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcltq_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vand_u16() { - let a: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); - let b: u16x4 = u16x4::new(0x0F, 0x0F, 0x0F, 0x0F); - let e: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); - let r: u16x4 = transmute(vand_u16(transmute(a), transmute(b))); + unsafe fn test_vclt_u8() { + let a: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vclt_u8(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); - let b: u16x4 = u16x4::new(0x00, 0x00, 0x00, 0x00); - let e: u16x4 = u16x4::new(0x00, 0x00, 0x00, 0x00); - let r: u16x4 = transmute(vand_u16(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcltq_u8() { + let a: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vcltq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vandq_u16() { - let a: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u16x8 = u16x8::new(0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F); - let e: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: u16x8 = transmute(vandq_u16(transmute(a), transmute(b))); + unsafe fn test_vclt_u16() { + let a: u16x4 = u16x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(1, 2, 3, 4); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vclt_u16(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u16x8 = u16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u16x8 = u16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let r: u16x8 = transmute(vandq_u16(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcltq_u16() { + let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vcltq_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vand_u32() { - let a: u32x2 = u32x2::new(0x00, 0x01); - let b: u32x2 = u32x2::new(0x0F, 0x0F); - let e: u32x2 = u32x2::new(0x00, 0x01); - let r: u32x2 = transmute(vand_u32(transmute(a), transmute(b))); + unsafe fn test_vclt_u32() { + let a: u32x2 = u32x2::new(0, 1); + let b: u32x2 = u32x2::new(1, 2); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vclt_u32(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: u32x2 = u32x2::new(0x00, 0x01); - let b: u32x2 = u32x2::new(0x00, 0x00); - let e: u32x2 = u32x2::new(0x00, 0x00); - let r: u32x2 = transmute(vand_u32(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcltq_u32() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u32x4 = u32x4::new(1, 2, 3, 4); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcltq_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vandq_u32() { - let a: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); - let b: u32x4 = u32x4::new(0x0F, 0x0F, 0x0F, 0x0F); - let e: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); - let r: u32x4 = transmute(vandq_u32(transmute(a), transmute(b))); + unsafe fn test_vclt_f32() { + let a: f32x2 = f32x2::new(0.1, 1.2); + let b: f32x2 = f32x2::new(1.2, 2.3); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vclt_f32(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); - let b: u32x4 = u32x4::new(0x00, 0x00, 0x00, 0x00); - let e: u32x4 = u32x4::new(0x00, 0x00, 0x00, 0x00); - let r: u32x4 = transmute(vandq_u32(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcltq_f32() { + let a: f32x4 = f32x4::new(0.1, 1.2, 2.3, 3.4); + let b: f32x4 = f32x4::new(1.2, 2.3, 3.4, 4.5); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcltq_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vand_s64() { - let a: i64x1 = i64x1::new(0x00); - let b: i64x1 = i64x1::new(0x0F); - let e: i64x1 = i64x1::new(0x00); - let r: i64x1 = transmute(vand_s64(transmute(a), transmute(b))); + unsafe fn test_vcle_s8() { + let a: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vcle_s8(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: i64x1 = i64x1::new(0x00); - let b: i64x1 = i64x1::new(0x00); - let e: i64x1 = i64x1::new(0x00); - let r: i64x1 = transmute(vand_s64(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcleq_s8() { + let a: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vcleq_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vandq_s64() { - let a: i64x2 = i64x2::new(0x00, 0x01); - let b: i64x2 = i64x2::new(0x0F, 0x0F); - let e: i64x2 = i64x2::new(0x00, 0x01); - let r: i64x2 = transmute(vandq_s64(transmute(a), transmute(b))); + unsafe fn test_vcle_s16() { + let a: i16x4 = i16x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(1, 2, 3, 4); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vcle_s16(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: i64x2 = i64x2::new(0x00, 0x01); - let b: i64x2 = i64x2::new(0x00, 0x00); - let e: i64x2 = i64x2::new(0x00, 0x00); - let r: i64x2 = transmute(vandq_s64(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcleq_s16() { + let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vcleq_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vand_u64() { - let a: u64x1 = u64x1::new(0x00); - let b: u64x1 = u64x1::new(0x0F); - let e: u64x1 = u64x1::new(0x00); - let r: u64x1 = transmute(vand_u64(transmute(a), transmute(b))); + unsafe fn test_vcle_s32() { + let a: i32x2 = i32x2::new(0, 1); + let b: i32x2 = i32x2::new(1, 2); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcle_s32(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: u64x1 = u64x1::new(0x00); - let b: u64x1 = u64x1::new(0x00); - let e: u64x1 = u64x1::new(0x00); - let r: u64x1 = transmute(vand_u64(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcleq_s32() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i32x4 = i32x4::new(1, 2, 3, 4); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcleq_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vandq_u64() { - let a: u64x2 = u64x2::new(0x00, 0x01); - let b: u64x2 = u64x2::new(0x0F, 0x0F); - let e: u64x2 = u64x2::new(0x00, 0x01); - let r: u64x2 = transmute(vandq_u64(transmute(a), transmute(b))); + unsafe fn test_vcle_u8() { + let a: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vcle_u8(transmute(a), transmute(b))); assert_eq!(r, e); + } - let a: u64x2 = u64x2::new(0x00, 0x01); - let b: u64x2 = u64x2::new(0x00, 0x00); - let e: u64x2 = u64x2::new(0x00, 0x00); - let r: u64x2 = transmute(vandq_u64(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcleq_u8() { + let a: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vcleq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorr_s8() { - let a: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i8x8 = i8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: i8x8 = transmute(vorr_s8(transmute(a), transmute(b))); + unsafe fn test_vcle_u16() { + let a: u16x4 = u16x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(1, 2, 3, 4); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vcle_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorrq_s8() { - let a: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); - let b: i8x16 = i8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); - let r: i8x16 = transmute(vorrq_s8(transmute(a), transmute(b))); + unsafe fn test_vcleq_u16() { + let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vcleq_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorr_s16() { - let a: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); - let b: i16x4 = i16x4::new(0x00, 0x00, 0x00, 0x00); - let e: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); - let r: i16x4 = transmute(vorr_s16(transmute(a), transmute(b))); + unsafe fn test_vcle_u32() { + let a: u32x2 = u32x2::new(0, 1); + let b: u32x2 = u32x2::new(1, 2); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcle_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorrq_s16() { - let a: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i16x8 = i16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: i16x8 = transmute(vorrq_s16(transmute(a), transmute(b))); + unsafe fn test_vcleq_u32() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u32x4 = u32x4::new(1, 2, 3, 4); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcleq_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorr_s32() { - let a: i32x2 = i32x2::new(0x00, 0x01); - let b: i32x2 = i32x2::new(0x00, 0x00); - let e: i32x2 = i32x2::new(0x00, 0x01); - let r: i32x2 = transmute(vorr_s32(transmute(a), transmute(b))); + unsafe fn test_vcle_f32() { + let a: f32x2 = f32x2::new(0.1, 1.2); + let b: f32x2 = f32x2::new(1.2, 2.3); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcle_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorrq_s32() { - let a: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); - let b: i32x4 = i32x4::new(0x00, 0x00, 0x00, 0x00); - let e: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); - let r: i32x4 = transmute(vorrq_s32(transmute(a), transmute(b))); + unsafe fn test_vcleq_f32() { + let a: f32x4 = f32x4::new(0.1, 1.2, 2.3, 3.4); + let b: f32x4 = f32x4::new(1.2, 2.3, 3.4, 4.5); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcleq_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorr_u8() { - let a: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u8x8 = u8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: u8x8 = transmute(vorr_u8(transmute(a), transmute(b))); + unsafe fn test_vcge_s8() { + let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vcge_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorrq_u8() { - let a: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); - let b: u8x16 = u8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); - let r: u8x16 = transmute(vorrq_u8(transmute(a), transmute(b))); + unsafe fn test_vcgeq_s8() { + let a: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vcgeq_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorr_u16() { - let a: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); - let b: u16x4 = u16x4::new(0x00, 0x00, 0x00, 0x00); - let e: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); - let r: u16x4 = transmute(vorr_u16(transmute(a), transmute(b))); + unsafe fn test_vcge_s16() { + let a: i16x4 = i16x4::new(1, 2, 3, 4); + let b: i16x4 = i16x4::new(0, 1, 2, 3); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vcge_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorrq_u16() { - let a: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u16x8 = u16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: u16x8 = transmute(vorrq_u16(transmute(a), transmute(b))); + unsafe fn test_vcgeq_s16() { + let a: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vcgeq_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorr_u32() { - let a: u32x2 = u32x2::new(0x00, 0x01); - let b: u32x2 = u32x2::new(0x00, 0x00); - let e: u32x2 = u32x2::new(0x00, 0x01); - let r: u32x2 = transmute(vorr_u32(transmute(a), transmute(b))); + unsafe fn test_vcge_s32() { + let a: i32x2 = i32x2::new(1, 2); + let b: i32x2 = i32x2::new(0, 1); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcge_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorrq_u32() { - let a: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); - let b: u32x4 = u32x4::new(0x00, 0x00, 0x00, 0x00); - let e: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); - let r: u32x4 = transmute(vorrq_u32(transmute(a), transmute(b))); + unsafe fn test_vcgeq_s32() { + let a: i32x4 = i32x4::new(1, 2, 3, 4); + let b: i32x4 = i32x4::new(0, 1, 2, 3); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcgeq_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorr_s64() { - let a: i64x1 = i64x1::new(0x00); - let b: i64x1 = i64x1::new(0x00); - let e: i64x1 = i64x1::new(0x00); - let r: i64x1 = transmute(vorr_s64(transmute(a), transmute(b))); + unsafe fn test_vcge_u8() { + let a: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x8 = transmute(vcge_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorrq_s64() { - let a: i64x2 = i64x2::new(0x00, 0x01); - let b: i64x2 = i64x2::new(0x00, 0x00); - let e: i64x2 = i64x2::new(0x00, 0x01); - let r: i64x2 = transmute(vorrq_s64(transmute(a), transmute(b))); + unsafe fn test_vcgeq_u8() { + let a: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + let r: u8x16 = transmute(vcgeq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorr_u64() { - let a: u64x1 = u64x1::new(0x00); - let b: u64x1 = u64x1::new(0x00); - let e: u64x1 = u64x1::new(0x00); - let r: u64x1 = transmute(vorr_u64(transmute(a), transmute(b))); + unsafe fn test_vcge_u16() { + let a: u16x4 = u16x4::new(1, 2, 3, 4); + let b: u16x4 = u16x4::new(0, 1, 2, 3); + let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x4 = transmute(vcge_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vorrq_u64() { - let a: u64x2 = u64x2::new(0x00, 0x01); - let b: u64x2 = u64x2::new(0x00, 0x00); - let e: u64x2 = u64x2::new(0x00, 0x01); - let r: u64x2 = transmute(vorrq_u64(transmute(a), transmute(b))); + unsafe fn test_vcgeq_u16() { + let a: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); + let r: u16x8 = transmute(vcgeq_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veor_s8() { - let a: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i8x8 = i8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i8x8 = i8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: i8x8 = transmute(veor_s8(transmute(a), transmute(b))); + unsafe fn test_vcge_u32() { + let a: u32x2 = u32x2::new(1, 2); + let b: u32x2 = u32x2::new(0, 1); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcge_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veorq_s8() { - let a: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); - let b: i8x16 = i8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i8x16 = i8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); - let r: i8x16 = transmute(veorq_s8(transmute(a), transmute(b))); + unsafe fn test_vcgeq_u32() { + let a: u32x4 = u32x4::new(1, 2, 3, 4); + let b: u32x4 = u32x4::new(0, 1, 2, 3); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcgeq_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veor_s16() { - let a: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); - let b: i16x4 = i16x4::new(0x00, 0x00, 0x00, 0x00); - let e: i16x4 = i16x4::new(0x00, 0x01, 0x02, 0x03); - let r: i16x4 = transmute(veor_s16(transmute(a), transmute(b))); + unsafe fn test_vcge_f32() { + let a: f32x2 = f32x2::new(1.2, 2.3); + let b: f32x2 = f32x2::new(0.1, 1.2); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcge_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veorq_s16() { - let a: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i16x8 = i16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i16x8 = i16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: i16x8 = transmute(veorq_s16(transmute(a), transmute(b))); + unsafe fn test_vcgeq_f32() { + let a: f32x4 = f32x4::new(1.2, 2.3, 3.4, 4.5); + let b: f32x4 = f32x4::new(0.1, 1.2, 2.3, 3.4); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcgeq_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veor_s32() { - let a: i32x2 = i32x2::new(0x00, 0x01); - let b: i32x2 = i32x2::new(0x00, 0x00); - let e: i32x2 = i32x2::new(0x00, 0x01); - let r: i32x2 = transmute(veor_s32(transmute(a), transmute(b))); + unsafe fn test_vcls_s8() { + let a: i8x8 = i8x8::new(-128, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i8x8 = i8x8::new(0, 7, 7, 7, 7, 7, 7, 7); + let r: i8x8 = transmute(vcls_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veorq_s32() { - let a: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); - let b: i32x4 = i32x4::new(0x00, 0x00, 0x00, 0x00); - let e: i32x4 = i32x4::new(0x00, 0x01, 0x02, 0x03); - let r: i32x4 = transmute(veorq_s32(transmute(a), transmute(b))); + unsafe fn test_vclsq_s8() { + let a: i8x16 = i8x16::new(-128, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F); + let e: i8x16 = i8x16::new(0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0); + let r: i8x16 = transmute(vclsq_s8(transmute(a))); assert_eq!(r, e); } - #[simd_test(enable = "neon")] - unsafe fn test_veor_u8() { - let a: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u8x8 = u8x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u8x8 = u8x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: u8x8 = transmute(veor_u8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcls_s16() { + let a: i16x4 = i16x4::new(-32768, -1, 0x00, 0x00); + let e: i16x4 = i16x4::new(0, 15, 15, 15); + let r: i16x4 = transmute(vcls_s16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veorq_u8() { - let a: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); - let b: u8x16 = u8x16::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u8x16 = u8x16::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F); - let r: u8x16 = transmute(veorq_u8(transmute(a), transmute(b))); + unsafe fn test_vclsq_s16() { + let a: i16x8 = i16x8::new(-32768, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + let e: i16x8 = i16x8::new(0, 15, 15, 15, 15, 15, 15, 15); + let r: i16x8 = transmute(vclsq_s16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veor_u16() { - let a: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); - let b: u16x4 = u16x4::new(0x00, 0x00, 0x00, 0x00); - let e: u16x4 = u16x4::new(0x00, 0x01, 0x02, 0x03); - let r: u16x4 = transmute(veor_u16(transmute(a), transmute(b))); + unsafe fn test_vcls_s32() { + let a: i32x2 = i32x2::new(-2147483648, -1); + let e: i32x2 = i32x2::new(0, 31); + let r: i32x2 = transmute(vcls_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veorq_u16() { - let a: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u16x8 = u16x8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: u16x8 = u16x8::new(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let r: u16x8 = transmute(veorq_u16(transmute(a), transmute(b))); + unsafe fn test_vclsq_s32() { + let a: i32x4 = i32x4::new(-2147483648, -1, 0x00, 0x00); + let e: i32x4 = i32x4::new(0, 31, 31, 31); + let r: i32x4 = transmute(vclsq_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veor_u32() { - let a: u32x2 = u32x2::new(0x00, 0x01); - let b: u32x2 = u32x2::new(0x00, 0x00); - let e: u32x2 = u32x2::new(0x00, 0x01); - let r: u32x2 = transmute(veor_u32(transmute(a), transmute(b))); + unsafe fn test_vclz_s8() { + let a: i8x8 = i8x8::new(-128, -1, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01); + let e: i8x8 = i8x8::new(0, 0, 8, 7, 7, 7, 7, 7); + let r: i8x8 = transmute(vclz_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veorq_u32() { - let a: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); - let b: u32x4 = u32x4::new(0x00, 0x00, 0x00, 0x00); - let e: u32x4 = u32x4::new(0x00, 0x01, 0x02, 0x03); - let r: u32x4 = transmute(veorq_u32(transmute(a), transmute(b))); + unsafe fn test_vclzq_s8() { + let a: i8x16 = i8x16::new(-128, -1, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7F); + let e: i8x16 = i8x16::new(0, 0, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1); + let r: i8x16 = transmute(vclzq_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veor_s64() { - let a: i64x1 = i64x1::new(0x00); - let b: i64x1 = i64x1::new(0x00); - let e: i64x1 = i64x1::new(0x00); - let r: i64x1 = transmute(veor_s64(transmute(a), transmute(b))); + unsafe fn test_vclz_s16() { + let a: i16x4 = i16x4::new(-32768, -1, 0x00, 0x01); + let e: i16x4 = i16x4::new(0, 0, 16, 15); + let r: i16x4 = transmute(vclz_s16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veorq_s64() { - let a: i64x2 = i64x2::new(0x00, 0x01); - let b: i64x2 = i64x2::new(0x00, 0x00); - let e: i64x2 = i64x2::new(0x00, 0x01); - let r: i64x2 = transmute(veorq_s64(transmute(a), transmute(b))); + unsafe fn test_vclzq_s16() { + let a: i16x8 = i16x8::new(-32768, -1, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01); + let e: i16x8 = i16x8::new(0, 0, 16, 15, 15, 15, 15, 15); + let r: i16x8 = transmute(vclzq_s16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veor_u64() { - let a: u64x1 = u64x1::new(0x00); - let b: u64x1 = u64x1::new(0x00); - let e: u64x1 = u64x1::new(0x00); - let r: u64x1 = transmute(veor_u64(transmute(a), transmute(b))); + unsafe fn test_vclz_s32() { + let a: i32x2 = i32x2::new(-2147483648, -1); + let e: i32x2 = i32x2::new(0, 0); + let r: i32x2 = transmute(vclz_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_veorq_u64() { - let a: u64x2 = u64x2::new(0x00, 0x01); - let b: u64x2 = u64x2::new(0x00, 0x00); - let e: u64x2 = u64x2::new(0x00, 0x01); - let r: u64x2 = transmute(veorq_u64(transmute(a), transmute(b))); + unsafe fn test_vclzq_s32() { + let a: i32x4 = i32x4::new(-2147483648, -1, 0x00, 0x01); + let e: i32x4 = i32x4::new(0, 0, 32, 31); + let r: i32x4 = transmute(vclzq_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabd_s8() { - let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: i8x8 = i8x8::new(16, 15, 14, 13, 12, 11, 10, 9); - let e: i8x8 = i8x8::new(15, 13, 11, 9, 7, 5, 3, 1); - let r: i8x8 = transmute(vabd_s8(transmute(a), transmute(b))); + unsafe fn test_vclz_u8() { + let a: u8x8 = u8x8::new(0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01); + let e: u8x8 = u8x8::new(8, 8, 7, 7, 7, 7, 7, 7); + let r: u8x8 = transmute(vclz_u8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdq_s8() { - let a: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b: i8x16 = i8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); - let e: i8x16 = i8x16::new(15, 13, 11, 9, 7, 5, 3, 1, 1, 3, 5, 7, 9, 11, 13, 15); - let r: i8x16 = transmute(vabdq_s8(transmute(a), transmute(b))); + unsafe fn test_vclzq_u8() { + let a: u8x16 = u8x16::new(0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF); + let e: u8x16 = u8x16::new(8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0); + let r: u8x16 = transmute(vclzq_u8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabd_s16() { - let a: i16x4 = i16x4::new(1, 2, 3, 4); - let b: i16x4 = i16x4::new(16, 15, 14, 13); - let e: i16x4 = i16x4::new(15, 13, 11, 9); - let r: i16x4 = transmute(vabd_s16(transmute(a), transmute(b))); + unsafe fn test_vclz_u16() { + let a: u16x4 = u16x4::new(0, 0x00, 0x01, 0x01); + let e: u16x4 = u16x4::new(16, 16, 15, 15); + let r: u16x4 = transmute(vclz_u16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdq_s16() { - let a: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: i16x8 = i16x8::new(16, 15, 14, 13, 12, 11, 10, 9); - let e: i16x8 = i16x8::new(15, 13, 11, 9, 7, 5, 3, 1); - let r: i16x8 = transmute(vabdq_s16(transmute(a), transmute(b))); + unsafe fn test_vclzq_u16() { + let a: u16x8 = u16x8::new(0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01); + let e: u16x8 = u16x8::new(16, 16, 15, 15, 15, 15, 15, 15); + let r: u16x8 = transmute(vclzq_u16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabd_s32() { - let a: i32x2 = i32x2::new(1, 2); - let b: i32x2 = i32x2::new(16, 15); - let e: i32x2 = i32x2::new(15, 13); - let r: i32x2 = transmute(vabd_s32(transmute(a), transmute(b))); + unsafe fn test_vclz_u32() { + let a: u32x2 = u32x2::new(0, 0x00); + let e: u32x2 = u32x2::new(32, 32); + let r: u32x2 = transmute(vclz_u32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdq_s32() { - let a: i32x4 = i32x4::new(1, 2, 3, 4); - let b: i32x4 = i32x4::new(16, 15, 14, 13); - let e: i32x4 = i32x4::new(15, 13, 11, 9); - let r: i32x4 = transmute(vabdq_s32(transmute(a), transmute(b))); + unsafe fn test_vclzq_u32() { + let a: u32x4 = u32x4::new(0, 0x00, 0x01, 0x01); + let e: u32x4 = u32x4::new(32, 32, 31, 31); + let r: u32x4 = transmute(vclzq_u32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabd_u8() { - let a: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: u8x8 = u8x8::new(16, 15, 14, 13, 12, 11, 10, 9); - let e: u8x8 = u8x8::new(15, 13, 11, 9, 7, 5, 3, 1); - let r: u8x8 = transmute(vabd_u8(transmute(a), transmute(b))); + unsafe fn test_vcagt_f32() { + let a: f32x2 = f32x2::new(-1.2, 0.0); + let b: f32x2 = f32x2::new(-1.1, 0.0); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0); + let r: u32x2 = transmute(vcagt_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdq_u8() { - let a: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b: u8x16 = u8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); - let e: u8x16 = u8x16::new(15, 13, 11, 9, 7, 5, 3, 1, 1, 3, 5, 7, 9, 11, 13, 15); - let r: u8x16 = transmute(vabdq_u8(transmute(a), transmute(b))); + unsafe fn test_vcagtq_f32() { + let a: f32x4 = f32x4::new(-1.2, 0.0, 1.2, 2.3); + let b: f32x4 = f32x4::new(-1.1, 0.0, 1.1, 2.4); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF, 0); + let r: u32x4 = transmute(vcagtq_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabd_u16() { - let a: u16x4 = u16x4::new(1, 2, 3, 4); - let b: u16x4 = u16x4::new(16, 15, 14, 13); - let e: u16x4 = u16x4::new(15, 13, 11, 9); - let r: u16x4 = transmute(vabd_u16(transmute(a), transmute(b))); + unsafe fn test_vcage_f32() { + let a: f32x2 = f32x2::new(-1.2, 0.0); + let b: f32x2 = f32x2::new(-1.1, 0.0); + let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcage_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdq_u16() { - let a: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: u16x8 = u16x8::new(16, 15, 14, 13, 12, 11, 10, 9); - let e: u16x8 = u16x8::new(15, 13, 11, 9, 7, 5, 3, 1); - let r: u16x8 = transmute(vabdq_u16(transmute(a), transmute(b))); + unsafe fn test_vcageq_f32() { + let a: f32x4 = f32x4::new(-1.2, 0.0, 1.2, 2.3); + let b: f32x4 = f32x4::new(-1.1, 0.0, 1.1, 2.4); + let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0); + let r: u32x4 = transmute(vcageq_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabd_u32() { - let a: u32x2 = u32x2::new(1, 2); - let b: u32x2 = u32x2::new(16, 15); - let e: u32x2 = u32x2::new(15, 13); - let r: u32x2 = transmute(vabd_u32(transmute(a), transmute(b))); + unsafe fn test_vcalt_f32() { + let a: f32x2 = f32x2::new(-1.2, 0.0); + let b: f32x2 = f32x2::new(-1.1, 0.0); + let e: u32x2 = u32x2::new(0, 0); + let r: u32x2 = transmute(vcalt_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdq_u32() { - let a: u32x4 = u32x4::new(1, 2, 3, 4); - let b: u32x4 = u32x4::new(16, 15, 14, 13); - let e: u32x4 = u32x4::new(15, 13, 11, 9); - let r: u32x4 = transmute(vabdq_u32(transmute(a), transmute(b))); + unsafe fn test_vcaltq_f32() { + let a: f32x4 = f32x4::new(-1.2, 0.0, 1.2, 2.3); + let b: f32x4 = f32x4::new(-1.1, 0.0, 1.1, 2.4); + let e: u32x4 = u32x4::new(0, 0, 0, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcaltq_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabd_f32() { - let a: f32x2 = f32x2::new(1.0, 2.0); - let b: f32x2 = f32x2::new(9.0, 3.0); - let e: f32x2 = f32x2::new(8.0, 1.0); - let r: f32x2 = transmute(vabd_f32(transmute(a), transmute(b))); + unsafe fn test_vcale_f32() { + let a: f32x2 = f32x2::new(-1.2, 0.0); + let b: f32x2 = f32x2::new(-1.1, 0.0); + let e: u32x2 = u32x2::new(0, 0xFF_FF_FF_FF); + let r: u32x2 = transmute(vcale_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdq_f32() { - let a: f32x4 = f32x4::new(1.0, 2.0, 5.0, -4.0); - let b: f32x4 = f32x4::new(9.0, 3.0, 2.0, 8.0); - let e: f32x4 = f32x4::new(8.0, 1.0, 3.0, 12.0); - let r: f32x4 = transmute(vabdq_f32(transmute(a), transmute(b))); + unsafe fn test_vcaleq_f32() { + let a: f32x4 = f32x4::new(-1.2, 0.0, 1.2, 2.3); + let b: f32x4 = f32x4::new(-1.1, 0.0, 1.1, 2.4); + let e: u32x4 = u32x4::new(0, 0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF); + let r: u32x4 = transmute(vcaleq_f32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdl_u8() { - let a: u8x8 = u8x8::new(1, 2, 3, 4, 4, 3, 2, 1); - let b: u8x8 = u8x8::new(10, 10, 10, 10, 10, 10, 10, 10); - let e: u16x8 = u16x8::new(9, 8, 7, 6, 6, 7, 8, 9); - let r: u16x8 = transmute(vabdl_u8(transmute(a), transmute(b))); + unsafe fn test_vcreate_s8() { + let a: u64 = 1; + let e: i8x8 = i8x8::new(1, 0, 0, 0, 0, 0, 0, 0); + let r: i8x8 = transmute(vcreate_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdl_u16() { - let a: u16x4 = u16x4::new(1, 2, 3, 4); - let b: u16x4 = u16x4::new(10, 10, 10, 10); - let e: u32x4 = u32x4::new(9, 8, 7, 6); - let r: u32x4 = transmute(vabdl_u16(transmute(a), transmute(b))); + unsafe fn test_vcreate_s32() { + let a: u64 = 1; + let e: i32x2 = i32x2::new(1, 0); + let r: i32x2 = transmute(vcreate_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdl_u32() { - let a: u32x2 = u32x2::new(1, 2); - let b: u32x2 = u32x2::new(10, 10); - let e: u64x2 = u64x2::new(9, 8); - let r: u64x2 = transmute(vabdl_u32(transmute(a), transmute(b))); + unsafe fn test_vcreate_s64() { + let a: u64 = 1; + let e: i64x1 = i64x1::new(1); + let r: i64x1 = transmute(vcreate_s64(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdl_s8() { - let a: i8x8 = i8x8::new(1, 2, 3, 4, 4, 3, 2, 1); - let b: i8x8 = i8x8::new(10, 10, 10, 10, 10, 10, 10, 10); - let e: i16x8 = i16x8::new(9, 8, 7, 6, 6, 7, 8, 9); - let r: i16x8 = transmute(vabdl_s8(transmute(a), transmute(b))); + unsafe fn test_vcreate_u8() { + let a: u64 = 1; + let e: u8x8 = u8x8::new(1, 0, 0, 0, 0, 0, 0, 0); + let r: u8x8 = transmute(vcreate_u8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdl_s16() { - let a: i16x4 = i16x4::new(1, 2, 11, 12); - let b: i16x4 = i16x4::new(10, 10, 10, 10); - let e: i32x4 = i32x4::new(9, 8, 1, 2); - let r: i32x4 = transmute(vabdl_s16(transmute(a), transmute(b))); + unsafe fn test_vcreate_u32() { + let a: u64 = 1; + let e: u32x2 = u32x2::new(1, 0); + let r: u32x2 = transmute(vcreate_u32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabdl_s32() { - let a: i32x2 = i32x2::new(1, 11); - let b: i32x2 = i32x2::new(10, 10); - let e: i64x2 = i64x2::new(9, 1); - let r: i64x2 = transmute(vabdl_s32(transmute(a), transmute(b))); + unsafe fn test_vcreate_u64() { + let a: u64 = 1; + let e: u64x1 = u64x1::new(1); + let r: u64x1 = transmute(vcreate_u64(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceq_u8() { - let a: u8x8 = u8x8::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u8x8 = u8x8::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vceq_u8(transmute(a), transmute(b))); + unsafe fn test_vcreate_p8() { + let a: u64 = 1; + let e: i8x8 = i8x8::new(1, 0, 0, 0, 0, 0, 0, 0); + let r: i8x8 = transmute(vcreate_p8(transmute(a))); assert_eq!(r, e); + } - let a: u8x8 = u8x8::new(0, 0, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u8x8 = u8x8::new(0, 0xFF, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); - let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); - let r: u8x8 = transmute(vceq_u8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcreate_p16() { + let a: u64 = 1; + let e: i16x4 = i16x4::new(1, 0, 0, 0); + let r: i16x4 = transmute(vcreate_p16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceqq_u8() { - let a: u8x16 = u8x16::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0xFF); - let b: u8x16 = u8x16::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0xFF); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vceqq_u8(transmute(a), transmute(b))); + unsafe fn test_vcreate_p64() { + let a: u64 = 1; + let e: i64x1 = i64x1::new(1); + let r: i64x1 = transmute(vcreate_p64(transmute(a))); assert_eq!(r, e); + } - let a: u8x16 = u8x16::new(0, 0, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xCC, 0x0D, 0xEE, 0xFF); - let b: u8x16 = u8x16::new(0, 0xFF, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08, 0x08, 0x00, 0x0A, 0x0A, 0xCC, 0xD0, 0xEE, 0); - let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); - let r: u8x16 = transmute(vceqq_u8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcreate_f32() { + let a: u64 = 0; + let e: f32x2 = f32x2::new(0., 0.); + let r: f32x2 = transmute(vcreate_f32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceq_u16() { - let a: u16x4 = u16x4::new(0, 0x01, 0x02, 0x03); - let b: u16x4 = u16x4::new(0, 0x01, 0x02, 0x03); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vceq_u16(transmute(a), transmute(b))); + unsafe fn test_vcvt_f32_s32() { + let a: i32x2 = i32x2::new(1, 2); + let e: f32x2 = f32x2::new(1., 2.); + let r: f32x2 = transmute(vcvt_f32_s32(transmute(a))); assert_eq!(r, e); + } - let a: u16x4 = u16x4::new(0, 0, 0x02, 0x03); - let b: u16x4 = u16x4::new(0, 0xFF_FF, 0x02, 0x04); - let e: u16x4 = u16x4::new(0xFF_FF, 0, 0xFF_FF, 0); - let r: u16x4 = transmute(vceq_u16(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_f32_s32() { + let a: i32x4 = i32x4::new(1, 2, 3, 4); + let e: f32x4 = f32x4::new(1., 2., 3., 4.); + let r: f32x4 = transmute(vcvtq_f32_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceqq_u16() { - let a: u16x8 = u16x8::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u16x8 = u16x8::new(0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vceqq_u16(transmute(a), transmute(b))); + unsafe fn test_vcvt_f32_u32() { + let a: u32x2 = u32x2::new(1, 2); + let e: f32x2 = f32x2::new(1., 2.); + let r: f32x2 = transmute(vcvt_f32_u32(transmute(a))); assert_eq!(r, e); + } - let a: u16x8 = u16x8::new(0, 0, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: u16x8 = u16x8::new(0, 0xFF_FF, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); - let e: u16x8 = u16x8::new(0xFF_FF, 0, 0xFF_FF, 0, 0xFF_FF, 0, 0xFF_FF, 0); - let r: u16x8 = transmute(vceqq_u16(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_f32_u32() { + let a: u32x4 = u32x4::new(1, 2, 3, 4); + let e: f32x4 = f32x4::new(1., 2., 3., 4.); + let r: f32x4 = transmute(vcvtq_f32_u32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceq_u32() { - let a: u32x2 = u32x2::new(0, 0x01); - let b: u32x2 = u32x2::new(0, 0x01); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vceq_u32(transmute(a), transmute(b))); + unsafe fn test_vcvt_n_f32_s32() { + let a: i32x2 = i32x2::new(1, 2); + let e: f32x2 = f32x2::new(0.25, 0.5); + let r: f32x2 = transmute(vcvt_n_f32_s32::<2>(transmute(a))); assert_eq!(r, e); + } - let a: u32x2 = u32x2::new(0, 0); - let b: u32x2 = u32x2::new(0, 0xFF_FF_FF_FF); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0); - let r: u32x2 = transmute(vceq_u32(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_n_f32_s32() { + let a: i32x4 = i32x4::new(1, 2, 3, 4); + let e: f32x4 = f32x4::new(0.25, 0.5, 0.75, 1.); + let r: f32x4 = transmute(vcvtq_n_f32_s32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceqq_u32() { - let a: u32x4 = u32x4::new(0, 0x01, 0x02, 0x03); - let b: u32x4 = u32x4::new(0, 0x01, 0x02, 0x03); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vceqq_u32(transmute(a), transmute(b))); + unsafe fn test_vcvt_n_f32_u32() { + let a: u32x2 = u32x2::new(1, 2); + let e: f32x2 = f32x2::new(0.25, 0.5); + let r: f32x2 = transmute(vcvt_n_f32_u32::<2>(transmute(a))); assert_eq!(r, e); + } - let a: u32x4 = u32x4::new(0, 0, 0x02, 0x03); - let b: u32x4 = u32x4::new(0, 0xFF_FF_FF_FF, 0x02, 0x04); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF, 0); - let r: u32x4 = transmute(vceqq_u32(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_n_f32_u32() { + let a: u32x4 = u32x4::new(1, 2, 3, 4); + let e: f32x4 = f32x4::new(0.25, 0.5, 0.75, 1.); + let r: f32x4 = transmute(vcvtq_n_f32_u32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceq_s8() { - let a: i8x8 = i8x8::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i8x8 = i8x8::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vceq_s8(transmute(a), transmute(b))); + unsafe fn test_vcvt_n_s32_f32() { + let a: f32x2 = f32x2::new(0.25, 0.5); + let e: i32x2 = i32x2::new(1, 2); + let r: i32x2 = transmute(vcvt_n_s32_f32::<2>(transmute(a))); assert_eq!(r, e); + } - let a: i8x8 = i8x8::new(-128, -128, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i8x8 = i8x8::new(-128, 0x7F, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); - let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); - let r: u8x8 = transmute(vceq_s8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_n_s32_f32() { + let a: f32x4 = f32x4::new(0.25, 0.5, 0.75, 1.); + let e: i32x4 = i32x4::new(1, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_n_s32_f32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceqq_s8() { - let a: i8x16 = i8x16::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x7F); - let b: i8x16 = i8x16::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x7F); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vceqq_s8(transmute(a), transmute(b))); + unsafe fn test_vcvt_n_u32_f32() { + let a: f32x2 = f32x2::new(0.25, 0.5); + let e: u32x2 = u32x2::new(1, 2); + let r: u32x2 = transmute(vcvt_n_u32_f32::<2>(transmute(a))); assert_eq!(r, e); + } - let a: i8x16 = i8x16::new(-128, -128, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xCC, 0x0D, 0xEE, 0x7F); - let b: i8x16 = i8x16::new(-128, 0x7F, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08, 0x08, 0x00, 0x0A, 0x0A, 0xCC, 0xD0, 0xEE, -128); - let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); - let r: u8x16 = transmute(vceqq_s8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_n_u32_f32() { + let a: f32x4 = f32x4::new(0.25, 0.5, 0.75, 1.); + let e: u32x4 = u32x4::new(1, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_n_u32_f32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceq_s16() { - let a: i16x4 = i16x4::new(-32768, 0x01, 0x02, 0x03); - let b: i16x4 = i16x4::new(-32768, 0x01, 0x02, 0x03); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vceq_s16(transmute(a), transmute(b))); + unsafe fn test_vcvt_s32_f32() { + let a: f32x2 = f32x2::new(-1.1, 2.1); + let e: i32x2 = i32x2::new(-1, 2); + let r: i32x2 = transmute(vcvt_s32_f32(transmute(a))); assert_eq!(r, e); + } - let a: i16x4 = i16x4::new(-32768, -32768, 0x02, 0x03); - let b: i16x4 = i16x4::new(-32768, 0x7F_FF, 0x02, 0x04); - let e: u16x4 = u16x4::new(0xFF_FF, 0, 0xFF_FF, 0); - let r: u16x4 = transmute(vceq_s16(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_s32_f32() { + let a: f32x4 = f32x4::new(-1.1, 2.1, -2.9, 3.9); + let e: i32x4 = i32x4::new(-1, 2, -2, 3); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceqq_s16() { - let a: i16x8 = i16x8::new(-32768, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i16x8 = i16x8::new(-32768, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vceqq_s16(transmute(a), transmute(b))); + unsafe fn test_vcvt_u32_f32() { + let a: f32x2 = f32x2::new(1.1, 2.1); + let e: u32x2 = u32x2::new(1, 2); + let r: u32x2 = transmute(vcvt_u32_f32(transmute(a))); assert_eq!(r, e); + } - let a: i16x8 = i16x8::new(-32768, -32768, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i16x8 = i16x8::new(-32768, 0x7F_FF, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); - let e: u16x8 = u16x8::new(0xFF_FF, 0, 0xFF_FF, 0, 0xFF_FF, 0, 0xFF_FF, 0); - let r: u16x8 = transmute(vceqq_s16(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_u32_f32() { + let a: f32x4 = f32x4::new(1.1, 2.1, 2.9, 3.9); + let e: u32x4 = u32x4::new(1, 2, 2, 3); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceq_s32() { - let a: i32x2 = i32x2::new(-2147483648, 0x01); - let b: i32x2 = i32x2::new(-2147483648, 0x01); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vceq_s32(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_s8() { + let a: i8x8 = i8x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: i8x8 = transmute(vdup_lane_s8::<4>(transmute(a))); assert_eq!(r, e); + } - let a: i32x2 = i32x2::new(-2147483648, -2147483648); - let b: i32x2 = i32x2::new(-2147483648, 0x7F_FF_FF_FF); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0); - let r: u32x2 = transmute(vceq_s32(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vdupq_laneq_s8() { + let a: i8x16 = i8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); + let e: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r: i8x16 = transmute(vdupq_laneq_s8::<8>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceqq_s32() { - let a: i32x4 = i32x4::new(-2147483648, 0x01, 0x02, 0x03); - let b: i32x4 = i32x4::new(-2147483648, 0x01, 0x02, 0x03); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vceqq_s32(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_s16() { + let a: i16x4 = i16x4::new(1, 1, 1, 4); + let e: i16x4 = i16x4::new(1, 1, 1, 1); + let r: i16x4 = transmute(vdup_lane_s16::<2>(transmute(a))); assert_eq!(r, e); + } - let a: i32x4 = i32x4::new(-2147483648, -2147483648, 0x02, 0x03); - let b: i32x4 = i32x4::new(-2147483648, 0x7F_FF_FF_FF, 0x02, 0x04); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF, 0); - let r: u32x4 = transmute(vceqq_s32(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vdupq_laneq_s16() { + let a: i16x8 = i16x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: i16x8 = transmute(vdupq_laneq_s16::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceq_p8() { - let a: i8x8 = i8x8::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i8x8 = i8x8::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vceq_p8(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_s32() { + let a: i32x2 = i32x2::new(1, 1); + let e: i32x2 = i32x2::new(1, 1); + let r: i32x2 = transmute(vdup_lane_s32::<1>(transmute(a))); assert_eq!(r, e); + } - let a: i8x8 = i8x8::new(-128, -128, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07); - let b: i8x8 = i8x8::new(-128, 0x7F, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08); - let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); - let r: u8x8 = transmute(vceq_p8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vdupq_laneq_s32() { + let a: i32x4 = i32x4::new(1, 1, 1, 4); + let e: i32x4 = i32x4::new(1, 1, 1, 1); + let r: i32x4 = transmute(vdupq_laneq_s32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceqq_p8() { - let a: i8x16 = i8x16::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x7F); - let b: i8x16 = i8x16::new(-128, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x7F); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vceqq_p8(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_s8() { + let a: i8x16 = i8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); + let e: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: i8x8 = transmute(vdup_laneq_s8::<8>(transmute(a))); assert_eq!(r, e); + } - let a: i8x16 = i8x16::new(-128, -128, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xCC, 0x0D, 0xEE, 0x7F); - let b: i8x16 = i8x16::new(-128, 0x7F, 0x02, 0x04, 0x04, 0x00, 0x06, 0x08, 0x08, 0x00, 0x0A, 0x0A, 0xCC, 0xD0, 0xEE, -128); - let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0); - let r: u8x16 = transmute(vceqq_p8(transmute(a), transmute(b))); + #[simd_test(enable = "neon")] + unsafe fn test_vdup_laneq_s16() { + let a: i16x8 = i16x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: i16x4 = i16x4::new(1, 1, 1, 1); + let r: i16x4 = transmute(vdup_laneq_s16::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceq_f32() { - let a: f32x2 = f32x2::new(1.2, 3.4); - let b: f32x2 = f32x2::new(1.2, 3.4); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vceq_f32(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_s32() { + let a: i32x4 = i32x4::new(1, 1, 1, 4); + let e: i32x2 = i32x2::new(1, 1); + let r: i32x2 = transmute(vdup_laneq_s32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vceqq_f32() { - let a: f32x4 = f32x4::new(1.2, 3.4, 5.6, 7.8); - let b: f32x4 = f32x4::new(1.2, 3.4, 5.6, 7.8); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vceqq_f32(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_s8() { + let a: i8x8 = i8x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r: i8x16 = transmute(vdupq_lane_s8::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtst_s8() { - let a: i8x8 = i8x8::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let b: i8x8 = i8x8::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vtst_s8(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_s16() { + let a: i16x4 = i16x4::new(1, 1, 1, 4); + let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: i16x8 = transmute(vdupq_lane_s16::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtstq_s8() { - let a: i8x16 = i8x16::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x7F); - let b: i8x16 = i8x16::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x7F); - let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vtstq_s8(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_s32() { + let a: i32x2 = i32x2::new(1, 1); + let e: i32x4 = i32x4::new(1, 1, 1, 1); + let r: i32x4 = transmute(vdupq_lane_s32::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtst_s16() { - let a: i16x4 = i16x4::new(-32768, 0x00, 0x01, 0x02); - let b: i16x4 = i16x4::new(-32768, 0x00, 0x01, 0x02); - let e: u16x4 = u16x4::new(0xFF_FF, 0, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vtst_s16(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_u8() { + let a: u8x8 = u8x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: u8x8 = u8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: u8x8 = transmute(vdup_lane_u8::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtstq_s16() { - let a: i16x8 = i16x8::new(-32768, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let b: i16x8 = i16x8::new(-32768, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let e: u16x8 = u16x8::new(0xFF_FF, 0, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vtstq_s16(transmute(a), transmute(b))); + unsafe fn test_vdupq_laneq_u8() { + let a: u8x16 = u8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r: u8x16 = transmute(vdupq_laneq_u8::<8>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtst_s32() { - let a: i32x2 = i32x2::new(-2147483648, 0x00); - let b: i32x2 = i32x2::new(-2147483648, 0x00); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0); - let r: u32x2 = transmute(vtst_s32(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_u16() { + let a: u16x4 = u16x4::new(1, 1, 1, 4); + let e: u16x4 = u16x4::new(1, 1, 1, 1); + let r: u16x4 = transmute(vdup_lane_u16::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtstq_s32() { - let a: i32x4 = i32x4::new(-2147483648, 0x00, 0x01, 0x02); - let b: i32x4 = i32x4::new(-2147483648, 0x00, 0x01, 0x02); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vtstq_s32(transmute(a), transmute(b))); + unsafe fn test_vdupq_laneq_u16() { + let a: u16x8 = u16x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: u16x8 = u16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: u16x8 = transmute(vdupq_laneq_u16::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtst_p8() { - let a: i8x8 = i8x8::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let b: i8x8 = i8x8::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let e: u8x8 = u8x8::new(0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vtst_p8(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_u32() { + let a: u32x2 = u32x2::new(1, 1); + let e: u32x2 = u32x2::new(1, 1); + let r: u32x2 = transmute(vdup_lane_u32::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtstq_p8() { - let a: i8x16 = i8x16::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x7F); - let b: i8x16 = i8x16::new(-128, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x7F); - let e: u8x16 = u8x16::new(0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vtstq_p8(transmute(a), transmute(b))); + unsafe fn test_vdupq_laneq_u32() { + let a: u32x4 = u32x4::new(1, 1, 1, 4); + let e: u32x4 = u32x4::new(1, 1, 1, 1); + let r: u32x4 = transmute(vdupq_laneq_u32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtst_u8() { - let a: u8x8 = u8x8::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let b: u8x8 = u8x8::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let e: u8x8 = u8x8::new(0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vtst_u8(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_u8() { + let a: u8x16 = u8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); + let e: u8x8 = u8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: u8x8 = transmute(vdup_laneq_u8::<8>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtstq_u8() { - let a: u8x16 = u8x16::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0xFF); - let b: u8x16 = u8x16::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0xFF); - let e: u8x16 = u8x16::new(0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vtstq_u8(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_u16() { + let a: u16x8 = u16x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: u16x4 = u16x4::new(1, 1, 1, 1); + let r: u16x4 = transmute(vdup_laneq_u16::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtst_u16() { - let a: u16x4 = u16x4::new(0, 0x00, 0x01, 0x02); - let b: u16x4 = u16x4::new(0, 0x00, 0x01, 0x02); - let e: u16x4 = u16x4::new(0, 0, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vtst_u16(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_u32() { + let a: u32x4 = u32x4::new(1, 1, 1, 4); + let e: u32x2 = u32x2::new(1, 1); + let r: u32x2 = transmute(vdup_laneq_u32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtstq_u16() { - let a: u16x8 = u16x8::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let b: u16x8 = u16x8::new(0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06); - let e: u16x8 = u16x8::new(0, 0, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vtstq_u16(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_u8() { + let a: u8x8 = u8x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: u8x16 = u8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r: u8x16 = transmute(vdupq_lane_u8::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtst_u32() { - let a: u32x2 = u32x2::new(0, 0x00); - let b: u32x2 = u32x2::new(0, 0x00); - let e: u32x2 = u32x2::new(0, 0); - let r: u32x2 = transmute(vtst_u32(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_u16() { + let a: u16x4 = u16x4::new(1, 1, 1, 4); + let e: u16x8 = u16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: u16x8 = transmute(vdupq_lane_u16::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vtstq_u32() { - let a: u32x4 = u32x4::new(0, 0x00, 0x01, 0x02); - let b: u32x4 = u32x4::new(0, 0x00, 0x01, 0x02); - let e: u32x4 = u32x4::new(0, 0, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vtstq_u32(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_u32() { + let a: u32x2 = u32x2::new(1, 1); + let e: u32x4 = u32x4::new(1, 1, 1, 1); + let r: u32x4 = transmute(vdupq_lane_u32::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabs_f32() { - let a: f32x2 = f32x2::new(-0.1, -2.2); - let e: f32x2 = f32x2::new(0.1, 2.2); - let r: f32x2 = transmute(vabs_f32(transmute(a))); + unsafe fn test_vdup_lane_p8() { + let a: i8x8 = i8x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: i8x8 = transmute(vdup_lane_p8::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vabsq_f32() { - let a: f32x4 = f32x4::new(-0.1, -2.2, -3.3, -6.6); - let e: f32x4 = f32x4::new(0.1, 2.2, 3.3, 6.6); - let r: f32x4 = transmute(vabsq_f32(transmute(a))); + unsafe fn test_vdupq_laneq_p8() { + let a: i8x16 = i8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); + let e: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r: i8x16 = transmute(vdupq_laneq_p8::<8>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgt_s8() { - let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vcgt_s8(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_p16() { + let a: i16x4 = i16x4::new(1, 1, 1, 4); + let e: i16x4 = i16x4::new(1, 1, 1, 1); + let r: i16x4 = transmute(vdup_lane_p16::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgtq_s8() { - let a: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vcgtq_s8(transmute(a), transmute(b))); + unsafe fn test_vdupq_laneq_p16() { + let a: i16x8 = i16x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: i16x8 = transmute(vdupq_laneq_p16::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgt_s16() { - let a: i16x4 = i16x4::new(1, 2, 3, 4); - let b: i16x4 = i16x4::new(0, 1, 2, 3); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vcgt_s16(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_p8() { + let a: i8x16 = i8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); + let e: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: i8x8 = transmute(vdup_laneq_p8::<8>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgtq_s16() { - let a: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vcgtq_s16(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_p16() { + let a: i16x8 = i16x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: i16x4 = i16x4::new(1, 1, 1, 1); + let r: i16x4 = transmute(vdup_laneq_p16::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgt_s32() { - let a: i32x2 = i32x2::new(1, 2); - let b: i32x2 = i32x2::new(0, 1); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcgt_s32(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_p8() { + let a: i8x8 = i8x8::new(1, 1, 1, 4, 1, 6, 7, 8); + let e: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r: i8x16 = transmute(vdupq_lane_p8::<4>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgtq_s32() { - let a: i32x4 = i32x4::new(1, 2, 3, 4); - let b: i32x4 = i32x4::new(0, 1, 2, 3); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcgtq_s32(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_p16() { + let a: i16x4 = i16x4::new(1, 1, 1, 4); + let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let r: i16x8 = transmute(vdupq_lane_p16::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgt_u8() { - let a: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vcgt_u8(transmute(a), transmute(b))); + unsafe fn test_vdupq_laneq_s64() { + let a: i64x2 = i64x2::new(1, 1); + let e: i64x2 = i64x2::new(1, 1); + let r: i64x2 = transmute(vdupq_laneq_s64::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgtq_u8() { - let a: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vcgtq_u8(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_s64() { + let a: i64x1 = i64x1::new(1); + let e: i64x2 = i64x2::new(1, 1); + let r: i64x2 = transmute(vdupq_lane_s64::<0>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgt_u16() { - let a: u16x4 = u16x4::new(1, 2, 3, 4); - let b: u16x4 = u16x4::new(0, 1, 2, 3); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vcgt_u16(transmute(a), transmute(b))); + unsafe fn test_vdupq_laneq_u64() { + let a: u64x2 = u64x2::new(1, 1); + let e: u64x2 = u64x2::new(1, 1); + let r: u64x2 = transmute(vdupq_laneq_u64::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgtq_u16() { - let a: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vcgtq_u16(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_u64() { + let a: u64x1 = u64x1::new(1); + let e: u64x2 = u64x2::new(1, 1); + let r: u64x2 = transmute(vdupq_lane_u64::<0>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgt_u32() { - let a: u32x2 = u32x2::new(1, 2); - let b: u32x2 = u32x2::new(0, 1); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcgt_u32(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_f32() { + let a: f32x2 = f32x2::new(1., 1.); + let e: f32x2 = f32x2::new(1., 1.); + let r: f32x2 = transmute(vdup_lane_f32::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgtq_u32() { - let a: u32x4 = u32x4::new(1, 2, 3, 4); - let b: u32x4 = u32x4::new(0, 1, 2, 3); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcgtq_u32(transmute(a), transmute(b))); + unsafe fn test_vdupq_laneq_f32() { + let a: f32x4 = f32x4::new(1., 1., 1., 4.); + let e: f32x4 = f32x4::new(1., 1., 1., 1.); + let r: f32x4 = transmute(vdupq_laneq_f32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgt_f32() { - let a: f32x2 = f32x2::new(1.2, 2.3); - let b: f32x2 = f32x2::new(0.1, 1.2); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcgt_f32(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_f32() { + let a: f32x4 = f32x4::new(1., 1., 1., 4.); + let e: f32x2 = f32x2::new(1., 1.); + let r: f32x2 = transmute(vdup_laneq_f32::<2>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgtq_f32() { - let a: f32x4 = f32x4::new(1.2, 2.3, 3.4, 4.5); - let b: f32x4 = f32x4::new(0.1, 1.2, 2.3, 3.4); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcgtq_f32(transmute(a), transmute(b))); + unsafe fn test_vdupq_lane_f32() { + let a: f32x2 = f32x2::new(1., 1.); + let e: f32x4 = f32x4::new(1., 1., 1., 1.); + let r: f32x4 = transmute(vdupq_lane_f32::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclt_s8() { - let a: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vclt_s8(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_s64() { + let a: i64x1 = i64x1::new(0); + let e: i64x1 = i64x1::new(0); + let r: i64x1 = transmute(vdup_lane_s64::<0>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcltq_s8() { - let a: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vcltq_s8(transmute(a), transmute(b))); + unsafe fn test_vdup_lane_u64() { + let a: u64x1 = u64x1::new(0); + let e: u64x1 = u64x1::new(0); + let r: u64x1 = transmute(vdup_lane_u64::<0>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclt_s16() { - let a: i16x4 = i16x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(1, 2, 3, 4); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vclt_s16(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_s64() { + let a: i64x2 = i64x2::new(0, 1); + let e: i64x1 = i64x1::new(1); + let r: i64x1 = transmute(vdup_laneq_s64::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcltq_s16() { - let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vcltq_s16(transmute(a), transmute(b))); + unsafe fn test_vdup_laneq_u64() { + let a: u64x2 = u64x2::new(0, 1); + let e: u64x1 = u64x1::new(1); + let r: u64x1 = transmute(vdup_laneq_u64::<1>(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclt_s32() { - let a: i32x2 = i32x2::new(0, 1); - let b: i32x2 = i32x2::new(1, 2); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vclt_s32(transmute(a), transmute(b))); + unsafe fn test_vext_s8() { + let a: i8x8 = i8x8::new(0, 8, 8, 9, 8, 9, 9, 11); + let b: i8x8 = i8x8::new(9, 11, 14, 15, 16, 17, 18, 19); + let e: i8x8 = i8x8::new(8, 9, 9, 11, 9, 11, 14, 15); + let r: i8x8 = transmute(vext_s8::<4>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcltq_s32() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i32x4 = i32x4::new(1, 2, 3, 4); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcltq_s32(transmute(a), transmute(b))); + unsafe fn test_vextq_s8() { + let a: i8x16 = i8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); + let b: i8x16 = i8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); + let e: i8x16 = i8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); + let r: i8x16 = transmute(vextq_s8::<8>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclt_u8() { - let a: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vclt_u8(transmute(a), transmute(b))); + unsafe fn test_vext_s16() { + let a: i16x4 = i16x4::new(0, 8, 8, 9); + let b: i16x4 = i16x4::new(9, 11, 14, 15); + let e: i16x4 = i16x4::new(8, 9, 9, 11); + let r: i16x4 = transmute(vext_s16::<2>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcltq_u8() { - let a: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vcltq_u8(transmute(a), transmute(b))); + unsafe fn test_vextq_s16() { + let a: i16x8 = i16x8::new(0, 8, 8, 9, 8, 9, 9, 11); + let b: i16x8 = i16x8::new(9, 11, 14, 15, 16, 17, 18, 19); + let e: i16x8 = i16x8::new(8, 9, 9, 11, 9, 11, 14, 15); + let r: i16x8 = transmute(vextq_s16::<4>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclt_u16() { - let a: u16x4 = u16x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(1, 2, 3, 4); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vclt_u16(transmute(a), transmute(b))); + unsafe fn test_vext_s32() { + let a: i32x2 = i32x2::new(0, 8); + let b: i32x2 = i32x2::new(9, 11); + let e: i32x2 = i32x2::new(8, 9); + let r: i32x2 = transmute(vext_s32::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcltq_u16() { - let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vcltq_u16(transmute(a), transmute(b))); + unsafe fn test_vextq_s32() { + let a: i32x4 = i32x4::new(0, 8, 8, 9); + let b: i32x4 = i32x4::new(9, 11, 14, 15); + let e: i32x4 = i32x4::new(8, 9, 9, 11); + let r: i32x4 = transmute(vextq_s32::<2>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclt_u32() { - let a: u32x2 = u32x2::new(0, 1); - let b: u32x2 = u32x2::new(1, 2); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vclt_u32(transmute(a), transmute(b))); + unsafe fn test_vext_u8() { + let a: u8x8 = u8x8::new(0, 8, 8, 9, 8, 9, 9, 11); + let b: u8x8 = u8x8::new(9, 11, 14, 15, 16, 17, 18, 19); + let e: u8x8 = u8x8::new(8, 9, 9, 11, 9, 11, 14, 15); + let r: u8x8 = transmute(vext_u8::<4>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcltq_u32() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u32x4 = u32x4::new(1, 2, 3, 4); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcltq_u32(transmute(a), transmute(b))); + unsafe fn test_vextq_u8() { + let a: u8x16 = u8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); + let b: u8x16 = u8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); + let e: u8x16 = u8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); + let r: u8x16 = transmute(vextq_u8::<8>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclt_f32() { - let a: f32x2 = f32x2::new(0.1, 1.2); - let b: f32x2 = f32x2::new(1.2, 2.3); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vclt_f32(transmute(a), transmute(b))); + unsafe fn test_vext_u16() { + let a: u16x4 = u16x4::new(0, 8, 8, 9); + let b: u16x4 = u16x4::new(9, 11, 14, 15); + let e: u16x4 = u16x4::new(8, 9, 9, 11); + let r: u16x4 = transmute(vext_u16::<2>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcltq_f32() { - let a: f32x4 = f32x4::new(0.1, 1.2, 2.3, 3.4); - let b: f32x4 = f32x4::new(1.2, 2.3, 3.4, 4.5); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcltq_f32(transmute(a), transmute(b))); + unsafe fn test_vextq_u16() { + let a: u16x8 = u16x8::new(0, 8, 8, 9, 8, 9, 9, 11); + let b: u16x8 = u16x8::new(9, 11, 14, 15, 16, 17, 18, 19); + let e: u16x8 = u16x8::new(8, 9, 9, 11, 9, 11, 14, 15); + let r: u16x8 = transmute(vextq_u16::<4>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcle_s8() { - let a: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vcle_s8(transmute(a), transmute(b))); + unsafe fn test_vext_u32() { + let a: u32x2 = u32x2::new(0, 8); + let b: u32x2 = u32x2::new(9, 11); + let e: u32x2 = u32x2::new(8, 9); + let r: u32x2 = transmute(vext_u32::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcleq_s8() { - let a: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vcleq_s8(transmute(a), transmute(b))); + unsafe fn test_vextq_u32() { + let a: u32x4 = u32x4::new(0, 8, 8, 9); + let b: u32x4 = u32x4::new(9, 11, 14, 15); + let e: u32x4 = u32x4::new(8, 9, 9, 11); + let r: u32x4 = transmute(vextq_u32::<2>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcle_s16() { - let a: i16x4 = i16x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(1, 2, 3, 4); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vcle_s16(transmute(a), transmute(b))); + unsafe fn test_vext_p8() { + let a: i8x8 = i8x8::new(0, 8, 8, 9, 8, 9, 9, 11); + let b: i8x8 = i8x8::new(9, 11, 14, 15, 16, 17, 18, 19); + let e: i8x8 = i8x8::new(8, 9, 9, 11, 9, 11, 14, 15); + let r: i8x8 = transmute(vext_p8::<4>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcleq_s16() { - let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vcleq_s16(transmute(a), transmute(b))); + unsafe fn test_vextq_p8() { + let a: i8x16 = i8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); + let b: i8x16 = i8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); + let e: i8x16 = i8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); + let r: i8x16 = transmute(vextq_p8::<8>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcle_s32() { - let a: i32x2 = i32x2::new(0, 1); - let b: i32x2 = i32x2::new(1, 2); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcle_s32(transmute(a), transmute(b))); + unsafe fn test_vext_p16() { + let a: i16x4 = i16x4::new(0, 8, 8, 9); + let b: i16x4 = i16x4::new(9, 11, 14, 15); + let e: i16x4 = i16x4::new(8, 9, 9, 11); + let r: i16x4 = transmute(vext_p16::<2>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcleq_s32() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i32x4 = i32x4::new(1, 2, 3, 4); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcleq_s32(transmute(a), transmute(b))); + unsafe fn test_vextq_p16() { + let a: i16x8 = i16x8::new(0, 8, 8, 9, 8, 9, 9, 11); + let b: i16x8 = i16x8::new(9, 11, 14, 15, 16, 17, 18, 19); + let e: i16x8 = i16x8::new(8, 9, 9, 11, 9, 11, 14, 15); + let r: i16x8 = transmute(vextq_p16::<4>(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vextq_s64() { + let a: i64x2 = i64x2::new(0, 8); + let b: i64x2 = i64x2::new(9, 11); + let e: i64x2 = i64x2::new(8, 9); + let r: i64x2 = transmute(vextq_s64::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcle_u8() { - let a: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vcle_u8(transmute(a), transmute(b))); + unsafe fn test_vextq_u64() { + let a: u64x2 = u64x2::new(0, 8); + let b: u64x2 = u64x2::new(9, 11); + let e: u64x2 = u64x2::new(8, 9); + let r: u64x2 = transmute(vextq_u64::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcleq_u8() { - let a: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vcleq_u8(transmute(a), transmute(b))); + unsafe fn test_vext_f32() { + let a: f32x2 = f32x2::new(0., 2.); + let b: f32x2 = f32x2::new(3., 4.); + let e: f32x2 = f32x2::new(2., 3.); + let r: f32x2 = transmute(vext_f32::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcle_u16() { - let a: u16x4 = u16x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(1, 2, 3, 4); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vcle_u16(transmute(a), transmute(b))); + unsafe fn test_vextq_f32() { + let a: f32x4 = f32x4::new(0., 2., 2., 3.); + let b: f32x4 = f32x4::new(3., 4., 5., 6.); + let e: f32x4 = f32x4::new(2., 3., 3., 4.); + let r: f32x4 = transmute(vextq_f32::<2>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcleq_u16() { - let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vcleq_u16(transmute(a), transmute(b))); + unsafe fn test_vmla_s8() { + let a: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i8x8 = i8x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: i8x8 = i8x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: i8x8 = transmute(vmla_s8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcle_u32() { - let a: u32x2 = u32x2::new(0, 1); - let b: u32x2 = u32x2::new(1, 2); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcle_u32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_s8() { + let a: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b: i8x16 = i8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let c: i8x16 = i8x16::new(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); + let e: i8x16 = i8x16::new(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); + let r: i8x16 = transmute(vmlaq_s8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcleq_u32() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u32x4 = u32x4::new(1, 2, 3, 4); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcleq_u32(transmute(a), transmute(b))); + unsafe fn test_vmla_s16() { + let a: i16x4 = i16x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x4 = i16x4::new(3, 3, 3, 3); + let e: i16x4 = i16x4::new(6, 7, 8, 9); + let r: i16x4 = transmute(vmla_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcle_f32() { - let a: f32x2 = f32x2::new(0.1, 1.2); - let b: f32x2 = f32x2::new(1.2, 2.3); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcle_f32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_s16() { + let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i16x8 = i16x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: i16x8 = transmute(vmlaq_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcleq_f32() { - let a: f32x4 = f32x4::new(0.1, 1.2, 2.3, 3.4); - let b: f32x4 = f32x4::new(1.2, 2.3, 3.4, 4.5); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcleq_f32(transmute(a), transmute(b))); + unsafe fn test_vmla_s32() { + let a: i32x2 = i32x2::new(0, 1); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x2 = i32x2::new(3, 3); + let e: i32x2 = i32x2::new(6, 7); + let r: i32x2 = transmute(vmla_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcge_s8() { - let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vcge_s8(transmute(a), transmute(b))); + unsafe fn test_vmlaq_s32() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let c: i32x4 = i32x4::new(3, 3, 3, 3); + let e: i32x4 = i32x4::new(6, 7, 8, 9); + let r: i32x4 = transmute(vmlaq_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgeq_s8() { - let a: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vcgeq_s8(transmute(a), transmute(b))); + unsafe fn test_vmla_u8() { + let a: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u8x8 = u8x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: u8x8 = u8x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: u8x8 = transmute(vmla_u8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcge_s16() { - let a: i16x4 = i16x4::new(1, 2, 3, 4); - let b: i16x4 = i16x4::new(0, 1, 2, 3); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vcge_s16(transmute(a), transmute(b))); + unsafe fn test_vmlaq_u8() { + let a: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b: u8x16 = u8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let c: u8x16 = u8x16::new(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); + let e: u8x16 = u8x16::new(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); + let r: u8x16 = transmute(vmlaq_u8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgeq_s16() { - let a: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vcgeq_s16(transmute(a), transmute(b))); + unsafe fn test_vmla_u16() { + let a: u16x4 = u16x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x4 = u16x4::new(3, 3, 3, 3); + let e: u16x4 = u16x4::new(6, 7, 8, 9); + let r: u16x4 = transmute(vmla_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcge_s32() { - let a: i32x2 = i32x2::new(1, 2); - let b: i32x2 = i32x2::new(0, 1); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcge_s32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_u16() { + let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u16x8 = u16x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: u16x8 = transmute(vmlaq_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgeq_s32() { - let a: i32x4 = i32x4::new(1, 2, 3, 4); - let b: i32x4 = i32x4::new(0, 1, 2, 3); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcgeq_s32(transmute(a), transmute(b))); + unsafe fn test_vmla_u32() { + let a: u32x2 = u32x2::new(0, 1); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x2 = u32x2::new(3, 3); + let e: u32x2 = u32x2::new(6, 7); + let r: u32x2 = transmute(vmla_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcge_u8() { - let a: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let e: u8x8 = u8x8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x8 = transmute(vcge_u8(transmute(a), transmute(b))); + unsafe fn test_vmlaq_u32() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let c: u32x4 = u32x4::new(3, 3, 3, 3); + let e: u32x4 = u32x4::new(6, 7, 8, 9); + let r: u32x4 = transmute(vmlaq_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgeq_u8() { - let a: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let e: u8x16 = u8x16::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - let r: u8x16 = transmute(vcgeq_u8(transmute(a), transmute(b))); + unsafe fn test_vmla_f32() { + let a: f32x2 = f32x2::new(0., 1.); + let b: f32x2 = f32x2::new(2., 2.); + let c: f32x2 = f32x2::new(3., 3.); + let e: f32x2 = f32x2::new(6., 7.); + let r: f32x2 = transmute(vmla_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcge_u16() { - let a: u16x4 = u16x4::new(1, 2, 3, 4); - let b: u16x4 = u16x4::new(0, 1, 2, 3); - let e: u16x4 = u16x4::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x4 = transmute(vcge_u16(transmute(a), transmute(b))); + unsafe fn test_vmlaq_f32() { + let a: f32x4 = f32x4::new(0., 1., 2., 3.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let c: f32x4 = f32x4::new(3., 3., 3., 3.); + let e: f32x4 = f32x4::new(6., 7., 8., 9.); + let r: f32x4 = transmute(vmlaq_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgeq_u16() { - let a: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let b: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let e: u16x8 = u16x8::new(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF); - let r: u16x8 = transmute(vcgeq_u16(transmute(a), transmute(b))); + unsafe fn test_vmla_n_s16() { + let a: i16x4 = i16x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16 = 3; + let e: i16x4 = i16x4::new(6, 7, 8, 9); + let r: i16x4 = transmute(vmla_n_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcge_u32() { - let a: u32x2 = u32x2::new(1, 2); - let b: u32x2 = u32x2::new(0, 1); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcge_u32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_n_s16() { + let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i16 = 3; + let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: i16x8 = transmute(vmlaq_n_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgeq_u32() { - let a: u32x4 = u32x4::new(1, 2, 3, 4); - let b: u32x4 = u32x4::new(0, 1, 2, 3); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcgeq_u32(transmute(a), transmute(b))); + unsafe fn test_vmla_n_s32() { + let a: i32x2 = i32x2::new(0, 1); + let b: i32x2 = i32x2::new(2, 2); + let c: i32 = 3; + let e: i32x2 = i32x2::new(6, 7); + let r: i32x2 = transmute(vmla_n_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcge_f32() { - let a: f32x2 = f32x2::new(1.2, 2.3); - let b: f32x2 = f32x2::new(0.1, 1.2); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcge_f32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_n_s32() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let c: i32 = 3; + let e: i32x4 = i32x4::new(6, 7, 8, 9); + let r: i32x4 = transmute(vmlaq_n_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcgeq_f32() { - let a: f32x4 = f32x4::new(1.2, 2.3, 3.4, 4.5); - let b: f32x4 = f32x4::new(0.1, 1.2, 2.3, 3.4); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcgeq_f32(transmute(a), transmute(b))); + unsafe fn test_vmla_n_u16() { + let a: u16x4 = u16x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16 = 3; + let e: u16x4 = u16x4::new(6, 7, 8, 9); + let r: u16x4 = transmute(vmla_n_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcls_s8() { - let a: i8x8 = i8x8::new(-128, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i8x8 = i8x8::new(0, 7, 7, 7, 7, 7, 7, 7); - let r: i8x8 = transmute(vcls_s8(transmute(a))); + unsafe fn test_vmlaq_n_u16() { + let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u16 = 3; + let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: u16x8 = transmute(vmlaq_n_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclsq_s8() { - let a: i8x16 = i8x16::new(-128, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F); - let e: i8x16 = i8x16::new(0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0); - let r: i8x16 = transmute(vclsq_s8(transmute(a))); + unsafe fn test_vmla_n_u32() { + let a: u32x2 = u32x2::new(0, 1); + let b: u32x2 = u32x2::new(2, 2); + let c: u32 = 3; + let e: u32x2 = u32x2::new(6, 7); + let r: u32x2 = transmute(vmla_n_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcls_s16() { - let a: i16x4 = i16x4::new(-32768, -1, 0x00, 0x00); - let e: i16x4 = i16x4::new(0, 15, 15, 15); - let r: i16x4 = transmute(vcls_s16(transmute(a))); + unsafe fn test_vmlaq_n_u32() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let c: u32 = 3; + let e: u32x4 = u32x4::new(6, 7, 8, 9); + let r: u32x4 = transmute(vmlaq_n_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclsq_s16() { - let a: i16x8 = i16x8::new(-32768, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - let e: i16x8 = i16x8::new(0, 15, 15, 15, 15, 15, 15, 15); - let r: i16x8 = transmute(vclsq_s16(transmute(a))); + unsafe fn test_vmla_n_f32() { + let a: f32x2 = f32x2::new(0., 1.); + let b: f32x2 = f32x2::new(2., 2.); + let c: f32 = 3.; + let e: f32x2 = f32x2::new(6., 7.); + let r: f32x2 = transmute(vmla_n_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcls_s32() { - let a: i32x2 = i32x2::new(-2147483648, -1); - let e: i32x2 = i32x2::new(0, 31); - let r: i32x2 = transmute(vcls_s32(transmute(a))); + unsafe fn test_vmlaq_n_f32() { + let a: f32x4 = f32x4::new(0., 1., 2., 3.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let c: f32 = 3.; + let e: f32x4 = f32x4::new(6., 7., 8., 9.); + let r: f32x4 = transmute(vmlaq_n_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclsq_s32() { - let a: i32x4 = i32x4::new(-2147483648, -1, 0x00, 0x00); - let e: i32x4 = i32x4::new(0, 31, 31, 31); - let r: i32x4 = transmute(vclsq_s32(transmute(a))); + unsafe fn test_vmla_lane_s16() { + let a: i16x4 = i16x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x4 = i16x4::new(0, 3, 0, 0); + let e: i16x4 = i16x4::new(6, 7, 8, 9); + let r: i16x4 = transmute(vmla_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclz_s8() { - let a: i8x8 = i8x8::new(-128, -1, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01); - let e: i8x8 = i8x8::new(0, 0, 8, 7, 7, 7, 7, 7); - let r: i8x8 = transmute(vclz_s8(transmute(a))); + unsafe fn test_vmla_laneq_s16() { + let a: i16x4 = i16x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: i16x4 = i16x4::new(6, 7, 8, 9); + let r: i16x4 = transmute(vmla_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclzq_s8() { - let a: i8x16 = i8x16::new(-128, -1, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7F); - let e: i8x16 = i8x16::new(0, 0, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1); - let r: i8x16 = transmute(vclzq_s8(transmute(a))); + unsafe fn test_vmlaq_lane_s16() { + let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i16x4 = i16x4::new(0, 3, 0, 0); + let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: i16x8 = transmute(vmlaq_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclz_s16() { - let a: i16x4 = i16x4::new(-32768, -1, 0x00, 0x01); - let e: i16x4 = i16x4::new(0, 0, 16, 15); - let r: i16x4 = transmute(vclz_s16(transmute(a))); + unsafe fn test_vmlaq_laneq_s16() { + let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: i16x8 = transmute(vmlaq_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclzq_s16() { - let a: i16x8 = i16x8::new(-32768, -1, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01); - let e: i16x8 = i16x8::new(0, 0, 16, 15, 15, 15, 15, 15); - let r: i16x8 = transmute(vclzq_s16(transmute(a))); + unsafe fn test_vmla_lane_s32() { + let a: i32x2 = i32x2::new(0, 1); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x2 = i32x2::new(0, 3); + let e: i32x2 = i32x2::new(6, 7); + let r: i32x2 = transmute(vmla_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclz_s32() { - let a: i32x2 = i32x2::new(-2147483648, -1); - let e: i32x2 = i32x2::new(0, 0); - let r: i32x2 = transmute(vclz_s32(transmute(a))); + unsafe fn test_vmla_laneq_s32() { + let a: i32x2 = i32x2::new(0, 1); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x4 = i32x4::new(0, 3, 0, 0); + let e: i32x2 = i32x2::new(6, 7); + let r: i32x2 = transmute(vmla_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclzq_s32() { - let a: i32x4 = i32x4::new(-2147483648, -1, 0x00, 0x01); - let e: i32x4 = i32x4::new(0, 0, 32, 31); - let r: i32x4 = transmute(vclzq_s32(transmute(a))); + unsafe fn test_vmlaq_lane_s32() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let c: i32x2 = i32x2::new(0, 3); + let e: i32x4 = i32x4::new(6, 7, 8, 9); + let r: i32x4 = transmute(vmlaq_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclz_u8() { - let a: u8x8 = u8x8::new(0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01); - let e: u8x8 = u8x8::new(8, 8, 7, 7, 7, 7, 7, 7); - let r: u8x8 = transmute(vclz_u8(transmute(a))); + unsafe fn test_vmlaq_laneq_s32() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let c: i32x4 = i32x4::new(0, 3, 0, 0); + let e: i32x4 = i32x4::new(6, 7, 8, 9); + let r: i32x4 = transmute(vmlaq_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclzq_u8() { - let a: u8x16 = u8x16::new(0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF); - let e: u8x16 = u8x16::new(8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0); - let r: u8x16 = transmute(vclzq_u8(transmute(a))); + unsafe fn test_vmla_lane_u16() { + let a: u16x4 = u16x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x4 = u16x4::new(0, 3, 0, 0); + let e: u16x4 = u16x4::new(6, 7, 8, 9); + let r: u16x4 = transmute(vmla_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclz_u16() { - let a: u16x4 = u16x4::new(0, 0x00, 0x01, 0x01); - let e: u16x4 = u16x4::new(16, 16, 15, 15); - let r: u16x4 = transmute(vclz_u16(transmute(a))); + unsafe fn test_vmla_laneq_u16() { + let a: u16x4 = u16x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: u16x4 = u16x4::new(6, 7, 8, 9); + let r: u16x4 = transmute(vmla_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclzq_u16() { - let a: u16x8 = u16x8::new(0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01); - let e: u16x8 = u16x8::new(16, 16, 15, 15, 15, 15, 15, 15); - let r: u16x8 = transmute(vclzq_u16(transmute(a))); + unsafe fn test_vmlaq_lane_u16() { + let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u16x4 = u16x4::new(0, 3, 0, 0); + let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: u16x8 = transmute(vmlaq_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclz_u32() { - let a: u32x2 = u32x2::new(0, 0x00); - let e: u32x2 = u32x2::new(32, 32); - let r: u32x2 = transmute(vclz_u32(transmute(a))); + unsafe fn test_vmlaq_laneq_u16() { + let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: u16x8 = transmute(vmlaq_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vclzq_u32() { - let a: u32x4 = u32x4::new(0, 0x00, 0x01, 0x01); - let e: u32x4 = u32x4::new(32, 32, 31, 31); - let r: u32x4 = transmute(vclzq_u32(transmute(a))); + unsafe fn test_vmla_lane_u32() { + let a: u32x2 = u32x2::new(0, 1); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x2 = u32x2::new(0, 3); + let e: u32x2 = u32x2::new(6, 7); + let r: u32x2 = transmute(vmla_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcagt_f32() { - let a: f32x2 = f32x2::new(-1.2, 0.0); - let b: f32x2 = f32x2::new(-1.1, 0.0); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0); - let r: u32x2 = transmute(vcagt_f32(transmute(a), transmute(b))); + unsafe fn test_vmla_laneq_u32() { + let a: u32x2 = u32x2::new(0, 1); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x4 = u32x4::new(0, 3, 0, 0); + let e: u32x2 = u32x2::new(6, 7); + let r: u32x2 = transmute(vmla_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcagtq_f32() { - let a: f32x4 = f32x4::new(-1.2, 0.0, 1.2, 2.3); - let b: f32x4 = f32x4::new(-1.1, 0.0, 1.1, 2.4); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF, 0); - let r: u32x4 = transmute(vcagtq_f32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_lane_u32() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let c: u32x2 = u32x2::new(0, 3); + let e: u32x4 = u32x4::new(6, 7, 8, 9); + let r: u32x4 = transmute(vmlaq_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcage_f32() { - let a: f32x2 = f32x2::new(-1.2, 0.0); - let b: f32x2 = f32x2::new(-1.1, 0.0); - let e: u32x2 = u32x2::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcage_f32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_laneq_u32() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let c: u32x4 = u32x4::new(0, 3, 0, 0); + let e: u32x4 = u32x4::new(6, 7, 8, 9); + let r: u32x4 = transmute(vmlaq_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcageq_f32() { - let a: f32x4 = f32x4::new(-1.2, 0.0, 1.2, 2.3); - let b: f32x4 = f32x4::new(-1.1, 0.0, 1.1, 2.4); - let e: u32x4 = u32x4::new(0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0xFF_FF_FF_FF, 0); - let r: u32x4 = transmute(vcageq_f32(transmute(a), transmute(b))); + unsafe fn test_vmla_lane_f32() { + let a: f32x2 = f32x2::new(0., 1.); + let b: f32x2 = f32x2::new(2., 2.); + let c: f32x2 = f32x2::new(0., 3.); + let e: f32x2 = f32x2::new(6., 7.); + let r: f32x2 = transmute(vmla_lane_f32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcalt_f32() { - let a: f32x2 = f32x2::new(-1.2, 0.0); - let b: f32x2 = f32x2::new(-1.1, 0.0); - let e: u32x2 = u32x2::new(0, 0); - let r: u32x2 = transmute(vcalt_f32(transmute(a), transmute(b))); + unsafe fn test_vmla_laneq_f32() { + let a: f32x2 = f32x2::new(0., 1.); + let b: f32x2 = f32x2::new(2., 2.); + let c: f32x4 = f32x4::new(0., 3., 0., 0.); + let e: f32x2 = f32x2::new(6., 7.); + let r: f32x2 = transmute(vmla_laneq_f32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcaltq_f32() { - let a: f32x4 = f32x4::new(-1.2, 0.0, 1.2, 2.3); - let b: f32x4 = f32x4::new(-1.1, 0.0, 1.1, 2.4); - let e: u32x4 = u32x4::new(0, 0, 0, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcaltq_f32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_lane_f32() { + let a: f32x4 = f32x4::new(0., 1., 2., 3.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let c: f32x2 = f32x2::new(0., 3.); + let e: f32x4 = f32x4::new(6., 7., 8., 9.); + let r: f32x4 = transmute(vmlaq_lane_f32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcale_f32() { - let a: f32x2 = f32x2::new(-1.2, 0.0); - let b: f32x2 = f32x2::new(-1.1, 0.0); - let e: u32x2 = u32x2::new(0, 0xFF_FF_FF_FF); - let r: u32x2 = transmute(vcale_f32(transmute(a), transmute(b))); + unsafe fn test_vmlaq_laneq_f32() { + let a: f32x4 = f32x4::new(0., 1., 2., 3.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let c: f32x4 = f32x4::new(0., 3., 0., 0.); + let e: f32x4 = f32x4::new(6., 7., 8., 9.); + let r: f32x4 = transmute(vmlaq_laneq_f32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcaleq_f32() { - let a: f32x4 = f32x4::new(-1.2, 0.0, 1.2, 2.3); - let b: f32x4 = f32x4::new(-1.1, 0.0, 1.1, 2.4); - let e: u32x4 = u32x4::new(0, 0xFF_FF_FF_FF, 0, 0xFF_FF_FF_FF); - let r: u32x4 = transmute(vcaleq_f32(transmute(a), transmute(b))); + unsafe fn test_vmlal_s8() { + let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i8x8 = i8x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: i16x8 = transmute(vmlal_s8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_s8() { - let a: u64 = 1; - let e: i8x8 = i8x8::new(1, 0, 0, 0, 0, 0, 0, 0); - let r: i8x8 = transmute(vcreate_s8(transmute(a))); + unsafe fn test_vmlal_s16() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x4 = i16x4::new(3, 3, 3, 3); + let e: i32x4 = i32x4::new(6, 7, 8, 9); + let r: i32x4 = transmute(vmlal_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_s32() { - let a: u64 = 1; - let e: i32x2 = i32x2::new(1, 0); - let r: i32x2 = transmute(vcreate_s32(transmute(a))); + unsafe fn test_vmlal_s32() { + let a: i64x2 = i64x2::new(0, 1); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x2 = i32x2::new(3, 3); + let e: i64x2 = i64x2::new(6, 7); + let r: i64x2 = transmute(vmlal_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_s64() { - let a: u64 = 1; - let e: i64x1 = i64x1::new(1); - let r: i64x1 = transmute(vcreate_s64(transmute(a))); + unsafe fn test_vmlal_u8() { + let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u8x8 = u8x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let r: u16x8 = transmute(vmlal_u8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_u8() { - let a: u64 = 1; - let e: u8x8 = u8x8::new(1, 0, 0, 0, 0, 0, 0, 0); - let r: u8x8 = transmute(vcreate_u8(transmute(a))); + unsafe fn test_vmlal_u16() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x4 = u16x4::new(3, 3, 3, 3); + let e: u32x4 = u32x4::new(6, 7, 8, 9); + let r: u32x4 = transmute(vmlal_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_u32() { - let a: u64 = 1; - let e: u32x2 = u32x2::new(1, 0); - let r: u32x2 = transmute(vcreate_u32(transmute(a))); + unsafe fn test_vmlal_u32() { + let a: u64x2 = u64x2::new(0, 1); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x2 = u32x2::new(3, 3); + let e: u64x2 = u64x2::new(6, 7); + let r: u64x2 = transmute(vmlal_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_u64() { - let a: u64 = 1; - let e: u64x1 = u64x1::new(1); - let r: u64x1 = transmute(vcreate_u64(transmute(a))); + unsafe fn test_vmlal_n_s16() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16 = 3; + let e: i32x4 = i32x4::new(6, 7, 8, 9); + let r: i32x4 = transmute(vmlal_n_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_p8() { - let a: u64 = 1; - let e: i8x8 = i8x8::new(1, 0, 0, 0, 0, 0, 0, 0); - let r: i8x8 = transmute(vcreate_p8(transmute(a))); + unsafe fn test_vmlal_n_s32() { + let a: i64x2 = i64x2::new(0, 1); + let b: i32x2 = i32x2::new(2, 2); + let c: i32 = 3; + let e: i64x2 = i64x2::new(6, 7); + let r: i64x2 = transmute(vmlal_n_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_p16() { - let a: u64 = 1; - let e: i16x4 = i16x4::new(1, 0, 0, 0); - let r: i16x4 = transmute(vcreate_p16(transmute(a))); + unsafe fn test_vmlal_n_u16() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16 = 3; + let e: u32x4 = u32x4::new(6, 7, 8, 9); + let r: u32x4 = transmute(vmlal_n_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_p64() { - let a: u64 = 1; - let e: i64x1 = i64x1::new(1); - let r: i64x1 = transmute(vcreate_p64(transmute(a))); + unsafe fn test_vmlal_n_u32() { + let a: u64x2 = u64x2::new(0, 1); + let b: u32x2 = u32x2::new(2, 2); + let c: u32 = 3; + let e: u64x2 = u64x2::new(6, 7); + let r: u64x2 = transmute(vmlal_n_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcreate_f32() { - let a: u64 = 0; - let e: f32x2 = f32x2::new(0., 0.); - let r: f32x2 = transmute(vcreate_f32(transmute(a))); + unsafe fn test_vmlal_lane_s16() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x4 = i16x4::new(0, 3, 0, 0); + let e: i32x4 = i32x4::new(6, 7, 8, 9); + let r: i32x4 = transmute(vmlal_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvt_f32_s32() { - let a: i32x2 = i32x2::new(1, 2); - let e: f32x2 = f32x2::new(1., 2.); - let r: f32x2 = transmute(vcvt_f32_s32(transmute(a))); + unsafe fn test_vmlal_laneq_s16() { + let a: i32x4 = i32x4::new(0, 1, 2, 3); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: i32x4 = i32x4::new(6, 7, 8, 9); + let r: i32x4 = transmute(vmlal_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_f32_s32() { - let a: i32x4 = i32x4::new(1, 2, 3, 4); - let e: f32x4 = f32x4::new(1., 2., 3., 4.); - let r: f32x4 = transmute(vcvtq_f32_s32(transmute(a))); + unsafe fn test_vmlal_lane_s32() { + let a: i64x2 = i64x2::new(0, 1); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x2 = i32x2::new(0, 3); + let e: i64x2 = i64x2::new(6, 7); + let r: i64x2 = transmute(vmlal_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvt_f32_u32() { - let a: u32x2 = u32x2::new(1, 2); - let e: f32x2 = f32x2::new(1., 2.); - let r: f32x2 = transmute(vcvt_f32_u32(transmute(a))); + unsafe fn test_vmlal_laneq_s32() { + let a: i64x2 = i64x2::new(0, 1); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x4 = i32x4::new(0, 3, 0, 0); + let e: i64x2 = i64x2::new(6, 7); + let r: i64x2 = transmute(vmlal_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_f32_u32() { - let a: u32x4 = u32x4::new(1, 2, 3, 4); - let e: f32x4 = f32x4::new(1., 2., 3., 4.); - let r: f32x4 = transmute(vcvtq_f32_u32(transmute(a))); + unsafe fn test_vmlal_lane_u16() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x4 = u16x4::new(0, 3, 0, 0); + let e: u32x4 = u32x4::new(6, 7, 8, 9); + let r: u32x4 = transmute(vmlal_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvt_n_f32_s32() { - let a: i32x2 = i32x2::new(1, 2); - let e: f32x2 = f32x2::new(0.25, 0.5); - let r: f32x2 = transmute(vcvt_n_f32_s32::<2>(transmute(a))); + unsafe fn test_vmlal_laneq_u16() { + let a: u32x4 = u32x4::new(0, 1, 2, 3); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: u32x4 = u32x4::new(6, 7, 8, 9); + let r: u32x4 = transmute(vmlal_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_n_f32_s32() { - let a: i32x4 = i32x4::new(1, 2, 3, 4); - let e: f32x4 = f32x4::new(0.25, 0.5, 0.75, 1.); - let r: f32x4 = transmute(vcvtq_n_f32_s32::<2>(transmute(a))); + unsafe fn test_vmlal_lane_u32() { + let a: u64x2 = u64x2::new(0, 1); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x2 = u32x2::new(0, 3); + let e: u64x2 = u64x2::new(6, 7); + let r: u64x2 = transmute(vmlal_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvt_n_f32_u32() { - let a: u32x2 = u32x2::new(1, 2); - let e: f32x2 = f32x2::new(0.25, 0.5); - let r: f32x2 = transmute(vcvt_n_f32_u32::<2>(transmute(a))); + unsafe fn test_vmlal_laneq_u32() { + let a: u64x2 = u64x2::new(0, 1); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x4 = u32x4::new(0, 3, 0, 0); + let e: u64x2 = u64x2::new(6, 7); + let r: u64x2 = transmute(vmlal_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_n_f32_u32() { - let a: u32x4 = u32x4::new(1, 2, 3, 4); - let e: f32x4 = f32x4::new(0.25, 0.5, 0.75, 1.); - let r: f32x4 = transmute(vcvtq_n_f32_u32::<2>(transmute(a))); + unsafe fn test_vmls_s8() { + let a: i8x8 = i8x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i8x8 = i8x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: i8x8 = transmute(vmls_s8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvt_n_s32_f32() { - let a: f32x2 = f32x2::new(0.25, 0.5); - let e: i32x2 = i32x2::new(1, 2); - let r: i32x2 = transmute(vcvt_n_s32_f32::<2>(transmute(a))); + unsafe fn test_vmlsq_s8() { + let a: i8x16 = i8x16::new(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); + let b: i8x16 = i8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let c: i8x16 = i8x16::new(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); + let e: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r: i8x16 = transmute(vmlsq_s8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_n_s32_f32() { - let a: f32x4 = f32x4::new(0.25, 0.5, 0.75, 1.); - let e: i32x4 = i32x4::new(1, 2, 3, 4); - let r: i32x4 = transmute(vcvtq_n_s32_f32::<2>(transmute(a))); + unsafe fn test_vmls_s16() { + let a: i16x4 = i16x4::new(6, 7, 8, 9); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x4 = i16x4::new(3, 3, 3, 3); + let e: i16x4 = i16x4::new(0, 1, 2, 3); + let r: i16x4 = transmute(vmls_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvt_n_u32_f32() { - let a: f32x2 = f32x2::new(0.25, 0.5); - let e: u32x2 = u32x2::new(1, 2); - let r: u32x2 = transmute(vcvt_n_u32_f32::<2>(transmute(a))); + unsafe fn test_vmlsq_s16() { + let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i16x8 = i16x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: i16x8 = transmute(vmlsq_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_n_u32_f32() { - let a: f32x4 = f32x4::new(0.25, 0.5, 0.75, 1.); - let e: u32x4 = u32x4::new(1, 2, 3, 4); - let r: u32x4 = transmute(vcvtq_n_u32_f32::<2>(transmute(a))); + unsafe fn test_vmls_s32() { + let a: i32x2 = i32x2::new(6, 7); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x2 = i32x2::new(3, 3); + let e: i32x2 = i32x2::new(0, 1); + let r: i32x2 = transmute(vmls_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvt_s32_f32() { - let a: f32x2 = f32x2::new(-1.1, 2.1); - let e: i32x2 = i32x2::new(-1, 2); - let r: i32x2 = transmute(vcvt_s32_f32(transmute(a))); + unsafe fn test_vmlsq_s32() { + let a: i32x4 = i32x4::new(6, 7, 8, 9); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let c: i32x4 = i32x4::new(3, 3, 3, 3); + let e: i32x4 = i32x4::new(0, 1, 2, 3); + let r: i32x4 = transmute(vmlsq_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_s32_f32() { - let a: f32x4 = f32x4::new(-1.1, 2.1, -2.9, 3.9); - let e: i32x4 = i32x4::new(-1, 2, -2, 3); - let r: i32x4 = transmute(vcvtq_s32_f32(transmute(a))); + unsafe fn test_vmls_u8() { + let a: u8x8 = u8x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u8x8 = u8x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: u8x8 = transmute(vmls_u8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvt_u32_f32() { - let a: f32x2 = f32x2::new(1.1, 2.1); - let e: u32x2 = u32x2::new(1, 2); - let r: u32x2 = transmute(vcvt_u32_f32(transmute(a))); + unsafe fn test_vmlsq_u8() { + let a: u8x16 = u8x16::new(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); + let b: u8x16 = u8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let c: u8x16 = u8x16::new(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); + let e: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r: u8x16 = transmute(vmlsq_u8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_u32_f32() { - let a: f32x4 = f32x4::new(1.1, 2.1, 2.9, 3.9); - let e: u32x4 = u32x4::new(1, 2, 2, 3); - let r: u32x4 = transmute(vcvtq_u32_f32(transmute(a))); + unsafe fn test_vmls_u16() { + let a: u16x4 = u16x4::new(6, 7, 8, 9); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x4 = u16x4::new(3, 3, 3, 3); + let e: u16x4 = u16x4::new(0, 1, 2, 3); + let r: u16x4 = transmute(vmls_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_s8() { - let a: i8x8 = i8x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i8x8 = transmute(vdup_lane_s8::<4>(transmute(a))); + unsafe fn test_vmlsq_u16() { + let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u16x8 = u16x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: u16x8 = transmute(vmlsq_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_s8() { - let a: i8x16 = i8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); - let e: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r: i8x16 = transmute(vdupq_laneq_s8::<8>(transmute(a))); + unsafe fn test_vmls_u32() { + let a: u32x2 = u32x2::new(6, 7); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x2 = u32x2::new(3, 3); + let e: u32x2 = u32x2::new(0, 1); + let r: u32x2 = transmute(vmls_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_s16() { - let a: i16x4 = i16x4::new(1, 1, 1, 4); - let e: i16x4 = i16x4::new(1, 1, 1, 1); - let r: i16x4 = transmute(vdup_lane_s16::<2>(transmute(a))); + unsafe fn test_vmlsq_u32() { + let a: u32x4 = u32x4::new(6, 7, 8, 9); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let c: u32x4 = u32x4::new(3, 3, 3, 3); + let e: u32x4 = u32x4::new(0, 1, 2, 3); + let r: u32x4 = transmute(vmlsq_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_s16() { - let a: i16x8 = i16x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i16x8 = transmute(vdupq_laneq_s16::<4>(transmute(a))); + unsafe fn test_vmls_f32() { + let a: f32x2 = f32x2::new(6., 7.); + let b: f32x2 = f32x2::new(2., 2.); + let c: f32x2 = f32x2::new(3., 3.); + let e: f32x2 = f32x2::new(0., 1.); + let r: f32x2 = transmute(vmls_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_s32() { - let a: i32x2 = i32x2::new(1, 1); - let e: i32x2 = i32x2::new(1, 1); - let r: i32x2 = transmute(vdup_lane_s32::<1>(transmute(a))); + unsafe fn test_vmlsq_f32() { + let a: f32x4 = f32x4::new(6., 7., 8., 9.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let c: f32x4 = f32x4::new(3., 3., 3., 3.); + let e: f32x4 = f32x4::new(0., 1., 2., 3.); + let r: f32x4 = transmute(vmlsq_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_s32() { - let a: i32x4 = i32x4::new(1, 1, 1, 4); - let e: i32x4 = i32x4::new(1, 1, 1, 1); - let r: i32x4 = transmute(vdupq_laneq_s32::<2>(transmute(a))); + unsafe fn test_vmls_n_s16() { + let a: i16x4 = i16x4::new(6, 7, 8, 9); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16 = 3; + let e: i16x4 = i16x4::new(0, 1, 2, 3); + let r: i16x4 = transmute(vmls_n_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_s8() { - let a: i8x16 = i8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); - let e: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i8x8 = transmute(vdup_laneq_s8::<8>(transmute(a))); + unsafe fn test_vmlsq_n_s16() { + let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i16 = 3; + let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: i16x8 = transmute(vmlsq_n_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_s16() { - let a: i16x8 = i16x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: i16x4 = i16x4::new(1, 1, 1, 1); - let r: i16x4 = transmute(vdup_laneq_s16::<4>(transmute(a))); + unsafe fn test_vmls_n_s32() { + let a: i32x2 = i32x2::new(6, 7); + let b: i32x2 = i32x2::new(2, 2); + let c: i32 = 3; + let e: i32x2 = i32x2::new(0, 1); + let r: i32x2 = transmute(vmls_n_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_s32() { - let a: i32x4 = i32x4::new(1, 1, 1, 4); - let e: i32x2 = i32x2::new(1, 1); - let r: i32x2 = transmute(vdup_laneq_s32::<2>(transmute(a))); + unsafe fn test_vmlsq_n_s32() { + let a: i32x4 = i32x4::new(6, 7, 8, 9); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let c: i32 = 3; + let e: i32x4 = i32x4::new(0, 1, 2, 3); + let r: i32x4 = transmute(vmlsq_n_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_s8() { - let a: i8x8 = i8x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r: i8x16 = transmute(vdupq_lane_s8::<4>(transmute(a))); + unsafe fn test_vmls_n_u16() { + let a: u16x4 = u16x4::new(6, 7, 8, 9); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16 = 3; + let e: u16x4 = u16x4::new(0, 1, 2, 3); + let r: u16x4 = transmute(vmls_n_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_s16() { - let a: i16x4 = i16x4::new(1, 1, 1, 4); - let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i16x8 = transmute(vdupq_lane_s16::<2>(transmute(a))); + unsafe fn test_vmlsq_n_u16() { + let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u16 = 3; + let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: u16x8 = transmute(vmlsq_n_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_s32() { - let a: i32x2 = i32x2::new(1, 1); - let e: i32x4 = i32x4::new(1, 1, 1, 1); - let r: i32x4 = transmute(vdupq_lane_s32::<1>(transmute(a))); + unsafe fn test_vmls_n_u32() { + let a: u32x2 = u32x2::new(6, 7); + let b: u32x2 = u32x2::new(2, 2); + let c: u32 = 3; + let e: u32x2 = u32x2::new(0, 1); + let r: u32x2 = transmute(vmls_n_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_u8() { - let a: u8x8 = u8x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: u8x8 = u8x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: u8x8 = transmute(vdup_lane_u8::<4>(transmute(a))); + unsafe fn test_vmlsq_n_u32() { + let a: u32x4 = u32x4::new(6, 7, 8, 9); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let c: u32 = 3; + let e: u32x4 = u32x4::new(0, 1, 2, 3); + let r: u32x4 = transmute(vmlsq_n_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_u8() { - let a: u8x16 = u8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r: u8x16 = transmute(vdupq_laneq_u8::<8>(transmute(a))); + unsafe fn test_vmls_n_f32() { + let a: f32x2 = f32x2::new(6., 7.); + let b: f32x2 = f32x2::new(2., 2.); + let c: f32 = 3.; + let e: f32x2 = f32x2::new(0., 1.); + let r: f32x2 = transmute(vmls_n_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_u16() { - let a: u16x4 = u16x4::new(1, 1, 1, 4); - let e: u16x4 = u16x4::new(1, 1, 1, 1); - let r: u16x4 = transmute(vdup_lane_u16::<2>(transmute(a))); + unsafe fn test_vmlsq_n_f32() { + let a: f32x4 = f32x4::new(6., 7., 8., 9.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let c: f32 = 3.; + let e: f32x4 = f32x4::new(0., 1., 2., 3.); + let r: f32x4 = transmute(vmlsq_n_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_u16() { - let a: u16x8 = u16x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: u16x8 = u16x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: u16x8 = transmute(vdupq_laneq_u16::<4>(transmute(a))); + unsafe fn test_vmls_lane_s16() { + let a: i16x4 = i16x4::new(6, 7, 8, 9); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x4 = i16x4::new(0, 3, 0, 0); + let e: i16x4 = i16x4::new(0, 1, 2, 3); + let r: i16x4 = transmute(vmls_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_u32() { - let a: u32x2 = u32x2::new(1, 1); - let e: u32x2 = u32x2::new(1, 1); - let r: u32x2 = transmute(vdup_lane_u32::<1>(transmute(a))); + unsafe fn test_vmls_laneq_s16() { + let a: i16x4 = i16x4::new(6, 7, 8, 9); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: i16x4 = i16x4::new(0, 1, 2, 3); + let r: i16x4 = transmute(vmls_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_u32() { - let a: u32x4 = u32x4::new(1, 1, 1, 4); - let e: u32x4 = u32x4::new(1, 1, 1, 1); - let r: u32x4 = transmute(vdupq_laneq_u32::<2>(transmute(a))); + unsafe fn test_vmlsq_lane_s16() { + let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i16x4 = i16x4::new(0, 3, 0, 0); + let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: i16x8 = transmute(vmlsq_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_u8() { - let a: u8x16 = u8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); - let e: u8x8 = u8x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: u8x8 = transmute(vdup_laneq_u8::<8>(transmute(a))); + unsafe fn test_vmlsq_laneq_s16() { + let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: i16x8 = transmute(vmlsq_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_u16() { - let a: u16x8 = u16x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: u16x4 = u16x4::new(1, 1, 1, 1); - let r: u16x4 = transmute(vdup_laneq_u16::<4>(transmute(a))); + unsafe fn test_vmls_lane_s32() { + let a: i32x2 = i32x2::new(6, 7); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x2 = i32x2::new(0, 3); + let e: i32x2 = i32x2::new(0, 1); + let r: i32x2 = transmute(vmls_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_u32() { - let a: u32x4 = u32x4::new(1, 1, 1, 4); - let e: u32x2 = u32x2::new(1, 1); - let r: u32x2 = transmute(vdup_laneq_u32::<2>(transmute(a))); + unsafe fn test_vmls_laneq_s32() { + let a: i32x2 = i32x2::new(6, 7); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x4 = i32x4::new(0, 3, 0, 0); + let e: i32x2 = i32x2::new(0, 1); + let r: i32x2 = transmute(vmls_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_u8() { - let a: u8x8 = u8x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: u8x16 = u8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r: u8x16 = transmute(vdupq_lane_u8::<4>(transmute(a))); + unsafe fn test_vmlsq_lane_s32() { + let a: i32x4 = i32x4::new(6, 7, 8, 9); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let c: i32x2 = i32x2::new(0, 3); + let e: i32x4 = i32x4::new(0, 1, 2, 3); + let r: i32x4 = transmute(vmlsq_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_u16() { - let a: u16x4 = u16x4::new(1, 1, 1, 4); - let e: u16x8 = u16x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: u16x8 = transmute(vdupq_lane_u16::<2>(transmute(a))); + unsafe fn test_vmlsq_laneq_s32() { + let a: i32x4 = i32x4::new(6, 7, 8, 9); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let c: i32x4 = i32x4::new(0, 3, 0, 0); + let e: i32x4 = i32x4::new(0, 1, 2, 3); + let r: i32x4 = transmute(vmlsq_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_u32() { - let a: u32x2 = u32x2::new(1, 1); - let e: u32x4 = u32x4::new(1, 1, 1, 1); - let r: u32x4 = transmute(vdupq_lane_u32::<1>(transmute(a))); + unsafe fn test_vmls_lane_u16() { + let a: u16x4 = u16x4::new(6, 7, 8, 9); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x4 = u16x4::new(0, 3, 0, 0); + let e: u16x4 = u16x4::new(0, 1, 2, 3); + let r: u16x4 = transmute(vmls_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_p8() { - let a: i8x8 = i8x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i8x8 = transmute(vdup_lane_p8::<4>(transmute(a))); + unsafe fn test_vmls_laneq_u16() { + let a: u16x4 = u16x4::new(6, 7, 8, 9); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: u16x4 = u16x4::new(0, 1, 2, 3); + let r: u16x4 = transmute(vmls_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_p8() { - let a: i8x16 = i8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); - let e: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r: i8x16 = transmute(vdupq_laneq_p8::<8>(transmute(a))); + unsafe fn test_vmlsq_lane_u16() { + let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u16x4 = u16x4::new(0, 3, 0, 0); + let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: u16x8 = transmute(vmlsq_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_p16() { - let a: i16x4 = i16x4::new(1, 1, 1, 4); - let e: i16x4 = i16x4::new(1, 1, 1, 1); - let r: i16x4 = transmute(vdup_lane_p16::<2>(transmute(a))); + unsafe fn test_vmlsq_laneq_u16() { + let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: u16x8 = transmute(vmlsq_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_p16() { - let a: i16x8 = i16x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i16x8 = transmute(vdupq_laneq_p16::<4>(transmute(a))); + unsafe fn test_vmls_lane_u32() { + let a: u32x2 = u32x2::new(6, 7); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x2 = u32x2::new(0, 3); + let e: u32x2 = u32x2::new(0, 1); + let r: u32x2 = transmute(vmls_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_p8() { - let a: i8x16 = i8x16::new(1, 1, 1, 4, 1, 6, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16); - let e: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i8x8 = transmute(vdup_laneq_p8::<8>(transmute(a))); + unsafe fn test_vmls_laneq_u32() { + let a: u32x2 = u32x2::new(6, 7); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x4 = u32x4::new(0, 3, 0, 0); + let e: u32x2 = u32x2::new(0, 1); + let r: u32x2 = transmute(vmls_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_p16() { - let a: i16x8 = i16x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: i16x4 = i16x4::new(1, 1, 1, 1); - let r: i16x4 = transmute(vdup_laneq_p16::<4>(transmute(a))); + unsafe fn test_vmlsq_lane_u32() { + let a: u32x4 = u32x4::new(6, 7, 8, 9); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let c: u32x2 = u32x2::new(0, 3); + let e: u32x4 = u32x4::new(0, 1, 2, 3); + let r: u32x4 = transmute(vmlsq_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_p8() { - let a: i8x8 = i8x8::new(1, 1, 1, 4, 1, 6, 7, 8); - let e: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r: i8x16 = transmute(vdupq_lane_p8::<4>(transmute(a))); + unsafe fn test_vmlsq_laneq_u32() { + let a: u32x4 = u32x4::new(6, 7, 8, 9); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let c: u32x4 = u32x4::new(0, 3, 0, 0); + let e: u32x4 = u32x4::new(0, 1, 2, 3); + let r: u32x4 = transmute(vmlsq_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_p16() { - let a: i16x4 = i16x4::new(1, 1, 1, 4); - let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i16x8 = transmute(vdupq_lane_p16::<2>(transmute(a))); + unsafe fn test_vmls_lane_f32() { + let a: f32x2 = f32x2::new(6., 7.); + let b: f32x2 = f32x2::new(2., 2.); + let c: f32x2 = f32x2::new(0., 3.); + let e: f32x2 = f32x2::new(0., 1.); + let r: f32x2 = transmute(vmls_lane_f32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_s64() { - let a: i64x2 = i64x2::new(1, 1); - let e: i64x2 = i64x2::new(1, 1); - let r: i64x2 = transmute(vdupq_laneq_s64::<1>(transmute(a))); + unsafe fn test_vmls_laneq_f32() { + let a: f32x2 = f32x2::new(6., 7.); + let b: f32x2 = f32x2::new(2., 2.); + let c: f32x4 = f32x4::new(0., 3., 0., 0.); + let e: f32x2 = f32x2::new(0., 1.); + let r: f32x2 = transmute(vmls_laneq_f32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_s64() { - let a: i64x1 = i64x1::new(1); - let e: i64x2 = i64x2::new(1, 1); - let r: i64x2 = transmute(vdupq_lane_s64::<0>(transmute(a))); + unsafe fn test_vmlsq_lane_f32() { + let a: f32x4 = f32x4::new(6., 7., 8., 9.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let c: f32x2 = f32x2::new(0., 3.); + let e: f32x4 = f32x4::new(0., 1., 2., 3.); + let r: f32x4 = transmute(vmlsq_lane_f32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_u64() { - let a: u64x2 = u64x2::new(1, 1); - let e: u64x2 = u64x2::new(1, 1); - let r: u64x2 = transmute(vdupq_laneq_u64::<1>(transmute(a))); + unsafe fn test_vmlsq_laneq_f32() { + let a: f32x4 = f32x4::new(6., 7., 8., 9.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let c: f32x4 = f32x4::new(0., 3., 0., 0.); + let e: f32x4 = f32x4::new(0., 1., 2., 3.); + let r: f32x4 = transmute(vmlsq_laneq_f32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_u64() { - let a: u64x1 = u64x1::new(1); - let e: u64x2 = u64x2::new(1, 1); - let r: u64x2 = transmute(vdupq_lane_u64::<0>(transmute(a))); + unsafe fn test_vmlsl_s8() { + let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: i8x8 = i8x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: i16x8 = transmute(vmlsl_s8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_f32() { - let a: f32x2 = f32x2::new(1., 1.); - let e: f32x2 = f32x2::new(1., 1.); - let r: f32x2 = transmute(vdup_lane_f32::<1>(transmute(a))); + unsafe fn test_vmlsl_s16() { + let a: i32x4 = i32x4::new(6, 7, 8, 9); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x4 = i16x4::new(3, 3, 3, 3); + let e: i32x4 = i32x4::new(0, 1, 2, 3); + let r: i32x4 = transmute(vmlsl_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_laneq_f32() { - let a: f32x4 = f32x4::new(1., 1., 1., 4.); - let e: f32x4 = f32x4::new(1., 1., 1., 1.); - let r: f32x4 = transmute(vdupq_laneq_f32::<2>(transmute(a))); + unsafe fn test_vmlsl_s32() { + let a: i64x2 = i64x2::new(6, 7); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x2 = i32x2::new(3, 3); + let e: i64x2 = i64x2::new(0, 1); + let r: i64x2 = transmute(vmlsl_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_f32() { - let a: f32x4 = f32x4::new(1., 1., 1., 4.); - let e: f32x2 = f32x2::new(1., 1.); - let r: f32x2 = transmute(vdup_laneq_f32::<2>(transmute(a))); + unsafe fn test_vmlsl_u8() { + let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); + let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let c: u8x8 = u8x8::new(3, 3, 3, 3, 3, 3, 3, 3); + let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r: u16x8 = transmute(vmlsl_u8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_lane_f32() { - let a: f32x2 = f32x2::new(1., 1.); - let e: f32x4 = f32x4::new(1., 1., 1., 1.); - let r: f32x4 = transmute(vdupq_lane_f32::<1>(transmute(a))); + unsafe fn test_vmlsl_u16() { + let a: u32x4 = u32x4::new(6, 7, 8, 9); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x4 = u16x4::new(3, 3, 3, 3); + let e: u32x4 = u32x4::new(0, 1, 2, 3); + let r: u32x4 = transmute(vmlsl_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_s64() { - let a: i64x1 = i64x1::new(0); - let e: i64x1 = i64x1::new(0); - let r: i64x1 = transmute(vdup_lane_s64::<0>(transmute(a))); + unsafe fn test_vmlsl_u32() { + let a: u64x2 = u64x2::new(6, 7); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x2 = u32x2::new(3, 3); + let e: u64x2 = u64x2::new(0, 1); + let r: u64x2 = transmute(vmlsl_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_lane_u64() { - let a: u64x1 = u64x1::new(0); - let e: u64x1 = u64x1::new(0); - let r: u64x1 = transmute(vdup_lane_u64::<0>(transmute(a))); + unsafe fn test_vmlsl_n_s16() { + let a: i32x4 = i32x4::new(6, 7, 8, 9); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16 = 3; + let e: i32x4 = i32x4::new(0, 1, 2, 3); + let r: i32x4 = transmute(vmlsl_n_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_s64() { - let a: i64x2 = i64x2::new(0, 1); - let e: i64x1 = i64x1::new(1); - let r: i64x1 = transmute(vdup_laneq_s64::<1>(transmute(a))); + unsafe fn test_vmlsl_n_s32() { + let a: i64x2 = i64x2::new(6, 7); + let b: i32x2 = i32x2::new(2, 2); + let c: i32 = 3; + let e: i64x2 = i64x2::new(0, 1); + let r: i64x2 = transmute(vmlsl_n_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdup_laneq_u64() { - let a: u64x2 = u64x2::new(0, 1); - let e: u64x1 = u64x1::new(1); - let r: u64x1 = transmute(vdup_laneq_u64::<1>(transmute(a))); + unsafe fn test_vmlsl_n_u16() { + let a: u32x4 = u32x4::new(6, 7, 8, 9); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16 = 3; + let e: u32x4 = u32x4::new(0, 1, 2, 3); + let r: u32x4 = transmute(vmlsl_n_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_s8() { - let a: i8x8 = i8x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: i8x8 = i8x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: i8x8 = i8x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: i8x8 = transmute(vext_s8::<4>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_n_u32() { + let a: u64x2 = u64x2::new(6, 7); + let b: u32x2 = u32x2::new(2, 2); + let c: u32 = 3; + let e: u64x2 = u64x2::new(0, 1); + let r: u64x2 = transmute(vmlsl_n_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_s8() { - let a: i8x16 = i8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); - let b: i8x16 = i8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); - let e: i8x16 = i8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); - let r: i8x16 = transmute(vextq_s8::<8>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_lane_s16() { + let a: i32x4 = i32x4::new(6, 7, 8, 9); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x4 = i16x4::new(0, 3, 0, 0); + let e: i32x4 = i32x4::new(0, 1, 2, 3); + let r: i32x4 = transmute(vmlsl_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_s16() { - let a: i16x4 = i16x4::new(0, 8, 8, 9); - let b: i16x4 = i16x4::new(9, 11, 14, 15); - let e: i16x4 = i16x4::new(8, 9, 9, 11); - let r: i16x4 = transmute(vext_s16::<2>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_laneq_s16() { + let a: i32x4 = i32x4::new(6, 7, 8, 9); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: i32x4 = i32x4::new(0, 1, 2, 3); + let r: i32x4 = transmute(vmlsl_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_s16() { - let a: i16x8 = i16x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: i16x8 = i16x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: i16x8 = i16x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: i16x8 = transmute(vextq_s16::<4>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_lane_s32() { + let a: i64x2 = i64x2::new(6, 7); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x2 = i32x2::new(0, 3); + let e: i64x2 = i64x2::new(0, 1); + let r: i64x2 = transmute(vmlsl_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_s32() { - let a: i32x2 = i32x2::new(0, 8); - let b: i32x2 = i32x2::new(9, 11); - let e: i32x2 = i32x2::new(8, 9); - let r: i32x2 = transmute(vext_s32::<1>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_laneq_s32() { + let a: i64x2 = i64x2::new(6, 7); + let b: i32x2 = i32x2::new(2, 2); + let c: i32x4 = i32x4::new(0, 3, 0, 0); + let e: i64x2 = i64x2::new(0, 1); + let r: i64x2 = transmute(vmlsl_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_s32() { - let a: i32x4 = i32x4::new(0, 8, 8, 9); - let b: i32x4 = i32x4::new(9, 11, 14, 15); - let e: i32x4 = i32x4::new(8, 9, 9, 11); - let r: i32x4 = transmute(vextq_s32::<2>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_lane_u16() { + let a: u32x4 = u32x4::new(6, 7, 8, 9); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x4 = u16x4::new(0, 3, 0, 0); + let e: u32x4 = u32x4::new(0, 1, 2, 3); + let r: u32x4 = transmute(vmlsl_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_u8() { - let a: u8x8 = u8x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: u8x8 = u8x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: u8x8 = u8x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: u8x8 = transmute(vext_u8::<4>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_laneq_u16() { + let a: u32x4 = u32x4::new(6, 7, 8, 9); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); + let e: u32x4 = u32x4::new(0, 1, 2, 3); + let r: u32x4 = transmute(vmlsl_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_u8() { - let a: u8x16 = u8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); - let b: u8x16 = u8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); - let e: u8x16 = u8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); - let r: u8x16 = transmute(vextq_u8::<8>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_lane_u32() { + let a: u64x2 = u64x2::new(6, 7); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x2 = u32x2::new(0, 3); + let e: u64x2 = u64x2::new(0, 1); + let r: u64x2 = transmute(vmlsl_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_u16() { - let a: u16x4 = u16x4::new(0, 8, 8, 9); - let b: u16x4 = u16x4::new(9, 11, 14, 15); - let e: u16x4 = u16x4::new(8, 9, 9, 11); - let r: u16x4 = transmute(vext_u16::<2>(transmute(a), transmute(b))); + unsafe fn test_vmlsl_laneq_u32() { + let a: u64x2 = u64x2::new(6, 7); + let b: u32x2 = u32x2::new(2, 2); + let c: u32x4 = u32x4::new(0, 3, 0, 0); + let e: u64x2 = u64x2::new(0, 1); + let r: u64x2 = transmute(vmlsl_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_u16() { - let a: u16x8 = u16x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: u16x8 = u16x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: u16x8 = u16x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: u16x8 = transmute(vextq_u16::<4>(transmute(a), transmute(b))); + unsafe fn test_vneg_s8() { + let a: i8x8 = i8x8::new(0, 1, -1, 2, -2, 3, -3, 4); + let e: i8x8 = i8x8::new(0, -1, 1, -2, 2, -3, 3, -4); + let r: i8x8 = transmute(vneg_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_u32() { - let a: u32x2 = u32x2::new(0, 8); - let b: u32x2 = u32x2::new(9, 11); - let e: u32x2 = u32x2::new(8, 9); - let r: u32x2 = transmute(vext_u32::<1>(transmute(a), transmute(b))); + unsafe fn test_vnegq_s8() { + let a: i8x16 = i8x16::new(0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8); + let e: i8x16 = i8x16::new(0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8); + let r: i8x16 = transmute(vnegq_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_u32() { - let a: u32x4 = u32x4::new(0, 8, 8, 9); - let b: u32x4 = u32x4::new(9, 11, 14, 15); - let e: u32x4 = u32x4::new(8, 9, 9, 11); - let r: u32x4 = transmute(vextq_u32::<2>(transmute(a), transmute(b))); + unsafe fn test_vneg_s16() { + let a: i16x4 = i16x4::new(0, 1, -1, 2); + let e: i16x4 = i16x4::new(0, -1, 1, -2); + let r: i16x4 = transmute(vneg_s16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_p8() { - let a: i8x8 = i8x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: i8x8 = i8x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: i8x8 = i8x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: i8x8 = transmute(vext_p8::<4>(transmute(a), transmute(b))); + unsafe fn test_vnegq_s16() { + let a: i16x8 = i16x8::new(0, 1, -1, 2, -2, 3, -3, 4); + let e: i16x8 = i16x8::new(0, -1, 1, -2, 2, -3, 3, -4); + let r: i16x8 = transmute(vnegq_s16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_p8() { - let a: i8x16 = i8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); - let b: i8x16 = i8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); - let e: i8x16 = i8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); - let r: i8x16 = transmute(vextq_p8::<8>(transmute(a), transmute(b))); + unsafe fn test_vneg_s32() { + let a: i32x2 = i32x2::new(0, 1); + let e: i32x2 = i32x2::new(0, -1); + let r: i32x2 = transmute(vneg_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_p16() { - let a: i16x4 = i16x4::new(0, 8, 8, 9); - let b: i16x4 = i16x4::new(9, 11, 14, 15); - let e: i16x4 = i16x4::new(8, 9, 9, 11); - let r: i16x4 = transmute(vext_p16::<2>(transmute(a), transmute(b))); + unsafe fn test_vnegq_s32() { + let a: i32x4 = i32x4::new(0, 1, -1, 2); + let e: i32x4 = i32x4::new(0, -1, 1, -2); + let r: i32x4 = transmute(vnegq_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_p16() { - let a: i16x8 = i16x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: i16x8 = i16x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: i16x8 = i16x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: i16x8 = transmute(vextq_p16::<4>(transmute(a), transmute(b))); + unsafe fn test_vneg_f32() { + let a: f32x2 = f32x2::new(0., 1.); + let e: f32x2 = f32x2::new(0., -1.); + let r: f32x2 = transmute(vneg_f32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_s64() { - let a: i64x2 = i64x2::new(0, 8); - let b: i64x2 = i64x2::new(9, 11); - let e: i64x2 = i64x2::new(8, 9); - let r: i64x2 = transmute(vextq_s64::<1>(transmute(a), transmute(b))); + unsafe fn test_vnegq_f32() { + let a: f32x4 = f32x4::new(0., 1., -1., 2.); + let e: f32x4 = f32x4::new(0., -1., 1., -2.); + let r: f32x4 = transmute(vnegq_f32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_u64() { - let a: u64x2 = u64x2::new(0, 8); - let b: u64x2 = u64x2::new(9, 11); - let e: u64x2 = u64x2::new(8, 9); - let r: u64x2 = transmute(vextq_u64::<1>(transmute(a), transmute(b))); + unsafe fn test_vqneg_s8() { + let a: i8x8 = i8x8::new(-128, 0, 1, -1, 2, -2, 3, -3); + let e: i8x8 = i8x8::new(0x7F, 0, -1, 1, -2, 2, -3, 3); + let r: i8x8 = transmute(vqneg_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vext_f32() { - let a: f32x2 = f32x2::new(0., 2.); - let b: f32x2 = f32x2::new(3., 4.); - let e: f32x2 = f32x2::new(2., 3.); - let r: f32x2 = transmute(vext_f32::<1>(transmute(a), transmute(b))); + unsafe fn test_vqnegq_s8() { + let a: i8x16 = i8x16::new(-128, 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7); + let e: i8x16 = i8x16::new(0x7F, 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7); + let r: i8x16 = transmute(vqnegq_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_f32() { - let a: f32x4 = f32x4::new(0., 2., 2., 3.); - let b: f32x4 = f32x4::new(3., 4., 5., 6.); - let e: f32x4 = f32x4::new(2., 3., 3., 4.); - let r: f32x4 = transmute(vextq_f32::<2>(transmute(a), transmute(b))); + unsafe fn test_vqneg_s16() { + let a: i16x4 = i16x4::new(-32768, 0, 1, -1); + let e: i16x4 = i16x4::new(0x7F_FF, 0, -1, 1); + let r: i16x4 = transmute(vqneg_s16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_s8() { - let a: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i8x8 = i8x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: i8x8 = i8x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: i8x8 = transmute(vmla_s8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqnegq_s16() { + let a: i16x8 = i16x8::new(-32768, 0, 1, -1, 2, -2, 3, -3); + let e: i16x8 = i16x8::new(0x7F_FF, 0, -1, 1, -2, 2, -3, 3); + let r: i16x8 = transmute(vqnegq_s16(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_s8() { - let a: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b: i8x16 = i8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let c: i8x16 = i8x16::new(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); - let e: i8x16 = i8x16::new(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); - let r: i8x16 = transmute(vmlaq_s8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqneg_s32() { + let a: i32x2 = i32x2::new(-2147483648, 0); + let e: i32x2 = i32x2::new(0x7F_FF_FF_FF, 0); + let r: i32x2 = transmute(vqneg_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_s16() { - let a: i16x4 = i16x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x4 = i16x4::new(3, 3, 3, 3); - let e: i16x4 = i16x4::new(6, 7, 8, 9); - let r: i16x4 = transmute(vmla_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqnegq_s32() { + let a: i32x4 = i32x4::new(-2147483648, 0, 1, -1); + let e: i32x4 = i32x4::new(0x7F_FF_FF_FF, 0, -1, 1); + let r: i32x4 = transmute(vqnegq_s32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_s16() { - let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i16x8 = i16x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: i16x8 = transmute(vmlaq_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsub_u8() { + let a: u8x8 = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u8x8 = u8x8::new(41, 40, 39, 38, 37, 36, 35, 34); + let r: u8x8 = transmute(vqsub_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_s32() { - let a: i32x2 = i32x2::new(0, 1); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x2 = i32x2::new(3, 3); - let e: i32x2 = i32x2::new(6, 7); - let r: i32x2 = transmute(vmla_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsubq_u8() { + let a: u8x16 = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); + let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26); + let r: u8x16 = transmute(vqsubq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_s32() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i32x4 = i32x4::new(2, 2, 2, 2); - let c: i32x4 = i32x4::new(3, 3, 3, 3); - let e: i32x4 = i32x4::new(6, 7, 8, 9); - let r: i32x4 = transmute(vmlaq_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsub_u16() { + let a: u16x4 = u16x4::new(42, 42, 42, 42); + let b: u16x4 = u16x4::new(1, 2, 3, 4); + let e: u16x4 = u16x4::new(41, 40, 39, 38); + let r: u16x4 = transmute(vqsub_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_u8() { - let a: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u8x8 = u8x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: u8x8 = u8x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: u8x8 = transmute(vmla_u8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsubq_u16() { + let a: u16x8 = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u16x8 = u16x8::new(41, 40, 39, 38, 37, 36, 35, 34); + let r: u16x8 = transmute(vqsubq_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_u8() { - let a: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b: u8x16 = u8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let c: u8x16 = u8x16::new(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); - let e: u8x16 = u8x16::new(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); - let r: u8x16 = transmute(vmlaq_u8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsub_u32() { + let a: u32x2 = u32x2::new(42, 42); + let b: u32x2 = u32x2::new(1, 2); + let e: u32x2 = u32x2::new(41, 40); + let r: u32x2 = transmute(vqsub_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_u16() { - let a: u16x4 = u16x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x4 = u16x4::new(3, 3, 3, 3); - let e: u16x4 = u16x4::new(6, 7, 8, 9); - let r: u16x4 = transmute(vmla_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsubq_u32() { + let a: u32x4 = u32x4::new(42, 42, 42, 42); + let b: u32x4 = u32x4::new(1, 2, 3, 4); + let e: u32x4 = u32x4::new(41, 40, 39, 38); + let r: u32x4 = transmute(vqsubq_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_u16() { - let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u16x8 = u16x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: u16x8 = transmute(vmlaq_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsub_u64() { + let a: u64x1 = u64x1::new(42); + let b: u64x1 = u64x1::new(1); + let e: u64x1 = u64x1::new(41); + let r: u64x1 = transmute(vqsub_u64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_u32() { - let a: u32x2 = u32x2::new(0, 1); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x2 = u32x2::new(3, 3); - let e: u32x2 = u32x2::new(6, 7); - let r: u32x2 = transmute(vmla_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsubq_u64() { + let a: u64x2 = u64x2::new(42, 42); + let b: u64x2 = u64x2::new(1, 2); + let e: u64x2 = u64x2::new(41, 40); + let r: u64x2 = transmute(vqsubq_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vqsub_s8() { + let a: i8x8 = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: i8x8 = i8x8::new(41, 40, 39, 38, 37, 36, 35, 34); + let r: i8x8 = transmute(vqsub_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_u32() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u32x4 = u32x4::new(2, 2, 2, 2); - let c: u32x4 = u32x4::new(3, 3, 3, 3); - let e: u32x4 = u32x4::new(6, 7, 8, 9); - let r: u32x4 = transmute(vmlaq_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsubq_s8() { + let a: i8x16 = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); + let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: i8x16 = i8x16::new(41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26); + let r: i8x16 = transmute(vqsubq_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_f32() { - let a: f32x2 = f32x2::new(0., 1.); - let b: f32x2 = f32x2::new(2., 2.); - let c: f32x2 = f32x2::new(3., 3.); - let e: f32x2 = f32x2::new(6., 7.); - let r: f32x2 = transmute(vmla_f32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsub_s16() { + let a: i16x4 = i16x4::new(42, 42, 42, 42); + let b: i16x4 = i16x4::new(1, 2, 3, 4); + let e: i16x4 = i16x4::new(41, 40, 39, 38); + let r: i16x4 = transmute(vqsub_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_f32() { - let a: f32x4 = f32x4::new(0., 1., 2., 3.); - let b: f32x4 = f32x4::new(2., 2., 2., 2.); - let c: f32x4 = f32x4::new(3., 3., 3., 3.); - let e: f32x4 = f32x4::new(6., 7., 8., 9.); - let r: f32x4 = transmute(vmlaq_f32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsubq_s16() { + let a: i16x8 = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: i16x8 = i16x8::new(41, 40, 39, 38, 37, 36, 35, 34); + let r: i16x8 = transmute(vqsubq_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_n_s16() { - let a: i16x4 = i16x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16 = 3; - let e: i16x4 = i16x4::new(6, 7, 8, 9); - let r: i16x4 = transmute(vmla_n_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsub_s32() { + let a: i32x2 = i32x2::new(42, 42); + let b: i32x2 = i32x2::new(1, 2); + let e: i32x2 = i32x2::new(41, 40); + let r: i32x2 = transmute(vqsub_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_n_s16() { - let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i16 = 3; - let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: i16x8 = transmute(vmlaq_n_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsubq_s32() { + let a: i32x4 = i32x4::new(42, 42, 42, 42); + let b: i32x4 = i32x4::new(1, 2, 3, 4); + let e: i32x4 = i32x4::new(41, 40, 39, 38); + let r: i32x4 = transmute(vqsubq_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_n_s32() { - let a: i32x2 = i32x2::new(0, 1); - let b: i32x2 = i32x2::new(2, 2); - let c: i32 = 3; - let e: i32x2 = i32x2::new(6, 7); - let r: i32x2 = transmute(vmla_n_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsub_s64() { + let a: i64x1 = i64x1::new(42); + let b: i64x1 = i64x1::new(1); + let e: i64x1 = i64x1::new(41); + let r: i64x1 = transmute(vqsub_s64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_n_s32() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i32x4 = i32x4::new(2, 2, 2, 2); - let c: i32 = 3; - let e: i32x4 = i32x4::new(6, 7, 8, 9); - let r: i32x4 = transmute(vmlaq_n_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqsubq_s64() { + let a: i64x2 = i64x2::new(42, 42); + let b: i64x2 = i64x2::new(1, 2); + let e: i64x2 = i64x2::new(41, 40); + let r: i64x2 = transmute(vqsubq_s64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_n_u16() { - let a: u16x4 = u16x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16 = 3; - let e: u16x4 = u16x4::new(6, 7, 8, 9); - let r: u16x4 = transmute(vmla_n_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhadd_u8() { + let a: u8x8 = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u8x8 = u8x8::new(21, 22, 22, 23, 23, 24, 24, 25); + let r: u8x8 = transmute(vhadd_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_n_u16() { - let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u16 = 3; - let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: u16x8 = transmute(vmlaq_n_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhaddq_u8() { + let a: u8x16 = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); + let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29); + let r: u8x16 = transmute(vhaddq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_n_u32() { - let a: u32x2 = u32x2::new(0, 1); - let b: u32x2 = u32x2::new(2, 2); - let c: u32 = 3; - let e: u32x2 = u32x2::new(6, 7); - let r: u32x2 = transmute(vmla_n_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhadd_u16() { + let a: u16x4 = u16x4::new(42, 42, 42, 42); + let b: u16x4 = u16x4::new(1, 2, 3, 4); + let e: u16x4 = u16x4::new(21, 22, 22, 23); + let r: u16x4 = transmute(vhadd_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_n_u32() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u32x4 = u32x4::new(2, 2, 2, 2); - let c: u32 = 3; - let e: u32x4 = u32x4::new(6, 7, 8, 9); - let r: u32x4 = transmute(vmlaq_n_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhaddq_u16() { + let a: u16x8 = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u16x8 = u16x8::new(21, 22, 22, 23, 23, 24, 24, 25); + let r: u16x8 = transmute(vhaddq_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_n_f32() { - let a: f32x2 = f32x2::new(0., 1.); - let b: f32x2 = f32x2::new(2., 2.); - let c: f32 = 3.; - let e: f32x2 = f32x2::new(6., 7.); - let r: f32x2 = transmute(vmla_n_f32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhadd_u32() { + let a: u32x2 = u32x2::new(42, 42); + let b: u32x2 = u32x2::new(1, 2); + let e: u32x2 = u32x2::new(21, 22); + let r: u32x2 = transmute(vhadd_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_n_f32() { - let a: f32x4 = f32x4::new(0., 1., 2., 3.); - let b: f32x4 = f32x4::new(2., 2., 2., 2.); - let c: f32 = 3.; - let e: f32x4 = f32x4::new(6., 7., 8., 9.); - let r: f32x4 = transmute(vmlaq_n_f32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhaddq_u32() { + let a: u32x4 = u32x4::new(42, 42, 42, 42); + let b: u32x4 = u32x4::new(1, 2, 3, 4); + let e: u32x4 = u32x4::new(21, 22, 22, 23); + let r: u32x4 = transmute(vhaddq_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_lane_s16() { - let a: i16x4 = i16x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x4 = i16x4::new(0, 3, 0, 0); - let e: i16x4 = i16x4::new(6, 7, 8, 9); - let r: i16x4 = transmute(vmla_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhadd_s8() { + let a: i8x8 = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: i8x8 = i8x8::new(21, 22, 22, 23, 23, 24, 24, 25); + let r: i8x8 = transmute(vhadd_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_laneq_s16() { - let a: i16x4 = i16x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: i16x4 = i16x4::new(6, 7, 8, 9); - let r: i16x4 = transmute(vmla_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhaddq_s8() { + let a: i8x16 = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); + let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: i8x16 = i8x16::new(21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29); + let r: i8x16 = transmute(vhaddq_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_lane_s16() { - let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i16x4 = i16x4::new(0, 3, 0, 0); - let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: i16x8 = transmute(vmlaq_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhadd_s16() { + let a: i16x4 = i16x4::new(42, 42, 42, 42); + let b: i16x4 = i16x4::new(1, 2, 3, 4); + let e: i16x4 = i16x4::new(21, 22, 22, 23); + let r: i16x4 = transmute(vhadd_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_laneq_s16() { - let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: i16x8 = transmute(vmlaq_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhaddq_s16() { + let a: i16x8 = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: i16x8 = i16x8::new(21, 22, 22, 23, 23, 24, 24, 25); + let r: i16x8 = transmute(vhaddq_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_lane_s32() { - let a: i32x2 = i32x2::new(0, 1); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x2 = i32x2::new(0, 3); - let e: i32x2 = i32x2::new(6, 7); - let r: i32x2 = transmute(vmla_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhadd_s32() { + let a: i32x2 = i32x2::new(42, 42); + let b: i32x2 = i32x2::new(1, 2); + let e: i32x2 = i32x2::new(21, 22); + let r: i32x2 = transmute(vhadd_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_laneq_s32() { - let a: i32x2 = i32x2::new(0, 1); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x4 = i32x4::new(0, 3, 0, 0); - let e: i32x2 = i32x2::new(6, 7); - let r: i32x2 = transmute(vmla_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vhaddq_s32() { + let a: i32x4 = i32x4::new(42, 42, 42, 42); + let b: i32x4 = i32x4::new(1, 2, 3, 4); + let e: i32x4 = i32x4::new(21, 22, 22, 23); + let r: i32x4 = transmute(vhaddq_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_lane_s32() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i32x4 = i32x4::new(2, 2, 2, 2); - let c: i32x2 = i32x2::new(0, 3); - let e: i32x4 = i32x4::new(6, 7, 8, 9); - let r: i32x4 = transmute(vmlaq_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhadd_u8() { + let a: u8x8 = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u8x8 = u8x8::new(22, 22, 23, 23, 24, 24, 25, 25); + let r: u8x8 = transmute(vrhadd_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_laneq_s32() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i32x4 = i32x4::new(2, 2, 2, 2); - let c: i32x4 = i32x4::new(0, 3, 0, 0); - let e: i32x4 = i32x4::new(6, 7, 8, 9); - let r: i32x4 = transmute(vmlaq_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhaddq_u8() { + let a: u8x16 = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); + let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29); + let r: u8x16 = transmute(vrhaddq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_lane_u16() { - let a: u16x4 = u16x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x4 = u16x4::new(0, 3, 0, 0); - let e: u16x4 = u16x4::new(6, 7, 8, 9); - let r: u16x4 = transmute(vmla_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhadd_u16() { + let a: u16x4 = u16x4::new(42, 42, 42, 42); + let b: u16x4 = u16x4::new(1, 2, 3, 4); + let e: u16x4 = u16x4::new(22, 22, 23, 23); + let r: u16x4 = transmute(vrhadd_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_laneq_u16() { - let a: u16x4 = u16x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: u16x4 = u16x4::new(6, 7, 8, 9); - let r: u16x4 = transmute(vmla_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhaddq_u16() { + let a: u16x8 = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u16x8 = u16x8::new(22, 22, 23, 23, 24, 24, 25, 25); + let r: u16x8 = transmute(vrhaddq_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_lane_u16() { - let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u16x4 = u16x4::new(0, 3, 0, 0); - let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: u16x8 = transmute(vmlaq_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhadd_u32() { + let a: u32x2 = u32x2::new(42, 42); + let b: u32x2 = u32x2::new(1, 2); + let e: u32x2 = u32x2::new(22, 22); + let r: u32x2 = transmute(vrhadd_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_laneq_u16() { - let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: u16x8 = transmute(vmlaq_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhaddq_u32() { + let a: u32x4 = u32x4::new(42, 42, 42, 42); + let b: u32x4 = u32x4::new(1, 2, 3, 4); + let e: u32x4 = u32x4::new(22, 22, 23, 23); + let r: u32x4 = transmute(vrhaddq_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_lane_u32() { - let a: u32x2 = u32x2::new(0, 1); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x2 = u32x2::new(0, 3); - let e: u32x2 = u32x2::new(6, 7); - let r: u32x2 = transmute(vmla_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhadd_s8() { + let a: i8x8 = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: i8x8 = i8x8::new(22, 22, 23, 23, 24, 24, 25, 25); + let r: i8x8 = transmute(vrhadd_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_laneq_u32() { - let a: u32x2 = u32x2::new(0, 1); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x4 = u32x4::new(0, 3, 0, 0); - let e: u32x2 = u32x2::new(6, 7); - let r: u32x2 = transmute(vmla_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhaddq_s8() { + let a: i8x16 = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); + let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: i8x16 = i8x16::new(22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29); + let r: i8x16 = transmute(vrhaddq_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_lane_u32() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u32x4 = u32x4::new(2, 2, 2, 2); - let c: u32x2 = u32x2::new(0, 3); - let e: u32x4 = u32x4::new(6, 7, 8, 9); - let r: u32x4 = transmute(vmlaq_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhadd_s16() { + let a: i16x4 = i16x4::new(42, 42, 42, 42); + let b: i16x4 = i16x4::new(1, 2, 3, 4); + let e: i16x4 = i16x4::new(22, 22, 23, 23); + let r: i16x4 = transmute(vrhadd_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_laneq_u32() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u32x4 = u32x4::new(2, 2, 2, 2); - let c: u32x4 = u32x4::new(0, 3, 0, 0); - let e: u32x4 = u32x4::new(6, 7, 8, 9); - let r: u32x4 = transmute(vmlaq_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhaddq_s16() { + let a: i16x8 = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: i16x8 = i16x8::new(22, 22, 23, 23, 24, 24, 25, 25); + let r: i16x8 = transmute(vrhaddq_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_lane_f32() { - let a: f32x2 = f32x2::new(0., 1.); - let b: f32x2 = f32x2::new(2., 2.); - let c: f32x2 = f32x2::new(0., 3.); - let e: f32x2 = f32x2::new(6., 7.); - let r: f32x2 = transmute(vmla_lane_f32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhadd_s32() { + let a: i32x2 = i32x2::new(42, 42); + let b: i32x2 = i32x2::new(1, 2); + let e: i32x2 = i32x2::new(22, 22); + let r: i32x2 = transmute(vrhadd_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmla_laneq_f32() { - let a: f32x2 = f32x2::new(0., 1.); - let b: f32x2 = f32x2::new(2., 2.); - let c: f32x4 = f32x4::new(0., 3., 0., 0.); - let e: f32x2 = f32x2::new(6., 7.); - let r: f32x2 = transmute(vmla_laneq_f32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrhaddq_s32() { + let a: i32x4 = i32x4::new(42, 42, 42, 42); + let b: i32x4 = i32x4::new(1, 2, 3, 4); + let e: i32x4 = i32x4::new(22, 22, 23, 23); + let r: i32x4 = transmute(vrhaddq_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_lane_f32() { - let a: f32x4 = f32x4::new(0., 1., 2., 3.); - let b: f32x4 = f32x4::new(2., 2., 2., 2.); - let c: f32x2 = f32x2::new(0., 3.); - let e: f32x4 = f32x4::new(6., 7., 8., 9.); - let r: f32x4 = transmute(vmlaq_lane_f32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrndn_f32() { + let a: f32x2 = f32x2::new(-1.5, 0.5); + let e: f32x2 = f32x2::new(-2.0, 0.0); + let r: f32x2 = transmute(vrndn_f32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlaq_laneq_f32() { - let a: f32x4 = f32x4::new(0., 1., 2., 3.); - let b: f32x4 = f32x4::new(2., 2., 2., 2.); - let c: f32x4 = f32x4::new(0., 3., 0., 0.); - let e: f32x4 = f32x4::new(6., 7., 8., 9.); - let r: f32x4 = transmute(vmlaq_laneq_f32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vrndnq_f32() { + let a: f32x4 = f32x4::new(-1.5, 0.5, 1.5, 2.5); + let e: f32x4 = f32x4::new(-2.0, 0.0, 2.0, 2.0); + let r: f32x4 = transmute(vrndnq_f32(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_s8() { - let a: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i8x8 = i8x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: i16x8 = transmute(vmlal_s8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqadd_u8() { + let a: u8x8 = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u8x8 = u8x8::new(43, 44, 45, 46, 47, 48, 49, 50); + let r: u8x8 = transmute(vqadd_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_s16() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x4 = i16x4::new(3, 3, 3, 3); - let e: i32x4 = i32x4::new(6, 7, 8, 9); - let r: i32x4 = transmute(vmlal_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqaddq_u8() { + let a: u8x16 = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); + let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: u8x16 = u8x16::new(43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58); + let r: u8x16 = transmute(vqaddq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_s32() { - let a: i64x2 = i64x2::new(0, 1); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x2 = i32x2::new(3, 3); - let e: i64x2 = i64x2::new(6, 7); - let r: i64x2 = transmute(vmlal_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqadd_u16() { + let a: u16x4 = u16x4::new(42, 42, 42, 42); + let b: u16x4 = u16x4::new(1, 2, 3, 4); + let e: u16x4 = u16x4::new(43, 44, 45, 46); + let r: u16x4 = transmute(vqadd_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_u8() { - let a: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u8x8 = u8x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let r: u16x8 = transmute(vmlal_u8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqaddq_u16() { + let a: u16x8 = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: u16x8 = u16x8::new(43, 44, 45, 46, 47, 48, 49, 50); + let r: u16x8 = transmute(vqaddq_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_u16() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x4 = u16x4::new(3, 3, 3, 3); - let e: u32x4 = u32x4::new(6, 7, 8, 9); - let r: u32x4 = transmute(vmlal_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqadd_u32() { + let a: u32x2 = u32x2::new(42, 42); + let b: u32x2 = u32x2::new(1, 2); + let e: u32x2 = u32x2::new(43, 44); + let r: u32x2 = transmute(vqadd_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_u32() { - let a: u64x2 = u64x2::new(0, 1); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x2 = u32x2::new(3, 3); - let e: u64x2 = u64x2::new(6, 7); - let r: u64x2 = transmute(vmlal_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqaddq_u32() { + let a: u32x4 = u32x4::new(42, 42, 42, 42); + let b: u32x4 = u32x4::new(1, 2, 3, 4); + let e: u32x4 = u32x4::new(43, 44, 45, 46); + let r: u32x4 = transmute(vqaddq_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_n_s16() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16 = 3; - let e: i32x4 = i32x4::new(6, 7, 8, 9); - let r: i32x4 = transmute(vmlal_n_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqadd_u64() { + let a: u64x1 = u64x1::new(42); + let b: u64x1 = u64x1::new(1); + let e: u64x1 = u64x1::new(43); + let r: u64x1 = transmute(vqadd_u64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_n_s32() { - let a: i64x2 = i64x2::new(0, 1); - let b: i32x2 = i32x2::new(2, 2); - let c: i32 = 3; - let e: i64x2 = i64x2::new(6, 7); - let r: i64x2 = transmute(vmlal_n_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqaddq_u64() { + let a: u64x2 = u64x2::new(42, 42); + let b: u64x2 = u64x2::new(1, 2); + let e: u64x2 = u64x2::new(43, 44); + let r: u64x2 = transmute(vqaddq_u64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_n_u16() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16 = 3; - let e: u32x4 = u32x4::new(6, 7, 8, 9); - let r: u32x4 = transmute(vmlal_n_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqadd_s8() { + let a: i8x8 = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: i8x8 = i8x8::new(43, 44, 45, 46, 47, 48, 49, 50); + let r: i8x8 = transmute(vqadd_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_n_u32() { - let a: u64x2 = u64x2::new(0, 1); - let b: u32x2 = u32x2::new(2, 2); - let c: u32 = 3; - let e: u64x2 = u64x2::new(6, 7); - let r: u64x2 = transmute(vmlal_n_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqaddq_s8() { + let a: i8x16 = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); + let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e: i8x16 = i8x16::new(43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58); + let r: i8x16 = transmute(vqaddq_s8(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_lane_s16() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x4 = i16x4::new(0, 3, 0, 0); - let e: i32x4 = i32x4::new(6, 7, 8, 9); - let r: i32x4 = transmute(vmlal_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqadd_s16() { + let a: i16x4 = i16x4::new(42, 42, 42, 42); + let b: i16x4 = i16x4::new(1, 2, 3, 4); + let e: i16x4 = i16x4::new(43, 44, 45, 46); + let r: i16x4 = transmute(vqadd_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_laneq_s16() { - let a: i32x4 = i32x4::new(0, 1, 2, 3); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: i32x4 = i32x4::new(6, 7, 8, 9); - let r: i32x4 = transmute(vmlal_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqaddq_s16() { + let a: i16x8 = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let e: i16x8 = i16x8::new(43, 44, 45, 46, 47, 48, 49, 50); + let r: i16x8 = transmute(vqaddq_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_lane_s32() { - let a: i64x2 = i64x2::new(0, 1); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x2 = i32x2::new(0, 3); - let e: i64x2 = i64x2::new(6, 7); - let r: i64x2 = transmute(vmlal_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqadd_s32() { + let a: i32x2 = i32x2::new(42, 42); + let b: i32x2 = i32x2::new(1, 2); + let e: i32x2 = i32x2::new(43, 44); + let r: i32x2 = transmute(vqadd_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vqaddq_s32() { + let a: i32x4 = i32x4::new(42, 42, 42, 42); + let b: i32x4 = i32x4::new(1, 2, 3, 4); + let e: i32x4 = i32x4::new(43, 44, 45, 46); + let r: i32x4 = transmute(vqaddq_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_laneq_s32() { - let a: i64x2 = i64x2::new(0, 1); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x4 = i32x4::new(0, 3, 0, 0); - let e: i64x2 = i64x2::new(6, 7); - let r: i64x2 = transmute(vmlal_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqadd_s64() { + let a: i64x1 = i64x1::new(42); + let b: i64x1 = i64x1::new(1); + let e: i64x1 = i64x1::new(43); + let r: i64x1 = transmute(vqadd_s64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_lane_u16() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x4 = u16x4::new(0, 3, 0, 0); - let e: u32x4 = u32x4::new(6, 7, 8, 9); - let r: u32x4 = transmute(vmlal_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vqaddq_s64() { + let a: i64x2 = i64x2::new(42, 42); + let b: i64x2 = i64x2::new(1, 2); + let e: i64x2 = i64x2::new(43, 44); + let r: i64x2 = transmute(vqaddq_s64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_laneq_u16() { - let a: u32x4 = u32x4::new(0, 1, 2, 3); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: u32x4 = u32x4::new(6, 7, 8, 9); - let r: u32x4 = transmute(vmlal_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s8_x2() { + let a: [i8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i8x8; 2] = [i8x8::new(1, 2, 3, 4, 5, 6, 7, 8), i8x8::new(9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [i8x8; 2] = transmute(vld1_s8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_lane_u32() { - let a: u64x2 = u64x2::new(0, 1); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x2 = u32x2::new(0, 3); - let e: u64x2 = u64x2::new(6, 7); - let r: u64x2 = transmute(vmlal_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s16_x2() { + let a: [i16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i16x4; 2] = [i16x4::new(1, 2, 3, 4), i16x4::new(5, 6, 7, 8)]; + let r: [i16x4; 2] = transmute(vld1_s16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlal_laneq_u32() { - let a: u64x2 = u64x2::new(0, 1); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x4 = u32x4::new(0, 3, 0, 0); - let e: u64x2 = u64x2::new(6, 7); - let r: u64x2 = transmute(vmlal_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s32_x2() { + let a: [i32; 5] = [0, 1, 2, 3, 4]; + let e: [i32x2; 2] = [i32x2::new(1, 2), i32x2::new(3, 4)]; + let r: [i32x2; 2] = transmute(vld1_s32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_s8() { - let a: i8x8 = i8x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i8x8 = i8x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: i8x8 = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: i8x8 = transmute(vmls_s8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s64_x2() { + let a: [i64; 3] = [0, 1, 2]; + let e: [i64x1; 2] = [i64x1::new(1), i64x1::new(2)]; + let r: [i64x1; 2] = transmute(vld1_s64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_s8() { - let a: i8x16 = i8x16::new(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); - let b: i8x16 = i8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let c: i8x16 = i8x16::new(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); - let e: i8x16 = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let r: i8x16 = transmute(vmlsq_s8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s8_x2() { + let a: [i8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8x16; 2] = [i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), i8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [i8x16; 2] = transmute(vld1q_s8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_s16() { - let a: i16x4 = i16x4::new(6, 7, 8, 9); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x4 = i16x4::new(3, 3, 3, 3); - let e: i16x4 = i16x4::new(0, 1, 2, 3); - let r: i16x4 = transmute(vmls_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s16_x2() { + let a: [i16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i16x8; 2] = [i16x8::new(1, 2, 3, 4, 5, 6, 7, 8), i16x8::new(9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [i16x8; 2] = transmute(vld1q_s16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_s16() { - let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i16x8 = i16x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: i16x8 = transmute(vmlsq_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s32_x2() { + let a: [i32; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i32x4; 2] = [i32x4::new(1, 2, 3, 4), i32x4::new(5, 6, 7, 8)]; + let r: [i32x4; 2] = transmute(vld1q_s32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_s32() { - let a: i32x2 = i32x2::new(6, 7); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x2 = i32x2::new(3, 3); - let e: i32x2 = i32x2::new(0, 1); - let r: i32x2 = transmute(vmls_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s64_x2() { + let a: [i64; 5] = [0, 1, 2, 3, 4]; + let e: [i64x2; 2] = [i64x2::new(1, 2), i64x2::new(3, 4)]; + let r: [i64x2; 2] = transmute(vld1q_s64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_s32() { - let a: i32x4 = i32x4::new(6, 7, 8, 9); - let b: i32x4 = i32x4::new(2, 2, 2, 2); - let c: i32x4 = i32x4::new(3, 3, 3, 3); - let e: i32x4 = i32x4::new(0, 1, 2, 3); - let r: i32x4 = transmute(vmlsq_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s8_x3() { + let a: [i8; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [i8x8; 3] = [i8x8::new(1, 2, 3, 4, 5, 6, 7, 8), i8x8::new(9, 10, 11, 12, 13, 14, 15, 16), i8x8::new(17, 18, 19, 20, 21, 22, 23, 24)]; + let r: [i8x8; 3] = transmute(vld1_s8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_u8() { - let a: u8x8 = u8x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u8x8 = u8x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: u8x8 = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: u8x8 = transmute(vmls_u8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s16_x3() { + let a: [i16; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [i16x4; 3] = [i16x4::new(1, 2, 3, 4), i16x4::new(5, 6, 7, 8), i16x4::new(9, 10, 11, 12)]; + let r: [i16x4; 3] = transmute(vld1_s16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_u8() { - let a: u8x16 = u8x16::new(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); - let b: u8x16 = u8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let c: u8x16 = u8x16::new(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); - let e: u8x16 = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let r: u8x16 = transmute(vmlsq_u8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s32_x3() { + let a: [i32; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [i32x2; 3] = [i32x2::new(1, 2), i32x2::new(3, 4), i32x2::new(5, 6)]; + let r: [i32x2; 3] = transmute(vld1_s32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_u16() { - let a: u16x4 = u16x4::new(6, 7, 8, 9); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x4 = u16x4::new(3, 3, 3, 3); - let e: u16x4 = u16x4::new(0, 1, 2, 3); - let r: u16x4 = transmute(vmls_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s64_x3() { + let a: [i64; 4] = [0, 1, 2, 3]; + let e: [i64x1; 3] = [i64x1::new(1), i64x1::new(2), i64x1::new(3)]; + let r: [i64x1; 3] = transmute(vld1_s64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_u16() { - let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u16x8 = u16x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: u16x8 = transmute(vmlsq_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s8_x3() { + let a: [i8; 49] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i8x16; 3] = [i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), i8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32), i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [i8x16; 3] = transmute(vld1q_s8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_u32() { - let a: u32x2 = u32x2::new(6, 7); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x2 = u32x2::new(3, 3); - let e: u32x2 = u32x2::new(0, 1); - let r: u32x2 = transmute(vmls_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s16_x3() { + let a: [i16; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [i16x8; 3] = [i16x8::new(1, 2, 3, 4, 5, 6, 7, 8), i16x8::new(9, 10, 11, 12, 13, 14, 15, 16), i16x8::new(17, 18, 19, 20, 21, 22, 23, 24)]; + let r: [i16x8; 3] = transmute(vld1q_s16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_u32() { - let a: u32x4 = u32x4::new(6, 7, 8, 9); - let b: u32x4 = u32x4::new(2, 2, 2, 2); - let c: u32x4 = u32x4::new(3, 3, 3, 3); - let e: u32x4 = u32x4::new(0, 1, 2, 3); - let r: u32x4 = transmute(vmlsq_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s32_x3() { + let a: [i32; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [i32x4; 3] = [i32x4::new(1, 2, 3, 4), i32x4::new(5, 6, 7, 8), i32x4::new(9, 10, 11, 12)]; + let r: [i32x4; 3] = transmute(vld1q_s32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_f32() { - let a: f32x2 = f32x2::new(6., 7.); - let b: f32x2 = f32x2::new(2., 2.); - let c: f32x2 = f32x2::new(3., 3.); - let e: f32x2 = f32x2::new(0., 1.); - let r: f32x2 = transmute(vmls_f32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s64_x3() { + let a: [i64; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [i64x2; 3] = [i64x2::new(1, 2), i64x2::new(3, 4), i64x2::new(5, 6)]; + let r: [i64x2; 3] = transmute(vld1q_s64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_f32() { - let a: f32x4 = f32x4::new(6., 7., 8., 9.); - let b: f32x4 = f32x4::new(2., 2., 2., 2.); - let c: f32x4 = f32x4::new(3., 3., 3., 3.); - let e: f32x4 = f32x4::new(0., 1., 2., 3.); - let r: f32x4 = transmute(vmlsq_f32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s8_x4() { + let a: [i8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8x8; 4] = [i8x8::new(1, 2, 3, 4, 5, 6, 7, 8), i8x8::new(9, 10, 11, 12, 13, 14, 15, 16), i8x8::new(17, 18, 19, 20, 21, 22, 23, 24), i8x8::new(25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [i8x8; 4] = transmute(vld1_s8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_n_s16() { - let a: i16x4 = i16x4::new(6, 7, 8, 9); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16 = 3; - let e: i16x4 = i16x4::new(0, 1, 2, 3); - let r: i16x4 = transmute(vmls_n_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s16_x4() { + let a: [i16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i16x4; 4] = [i16x4::new(1, 2, 3, 4), i16x4::new(5, 6, 7, 8), i16x4::new(9, 10, 11, 12), i16x4::new(13, 14, 15, 16)]; + let r: [i16x4; 4] = transmute(vld1_s16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_n_s16() { - let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i16 = 3; - let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: i16x8 = transmute(vmlsq_n_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s32_x4() { + let a: [i32; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i32x2; 4] = [i32x2::new(1, 2), i32x2::new(3, 4), i32x2::new(5, 6), i32x2::new(7, 8)]; + let r: [i32x2; 4] = transmute(vld1_s32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_n_s32() { - let a: i32x2 = i32x2::new(6, 7); - let b: i32x2 = i32x2::new(2, 2); - let c: i32 = 3; - let e: i32x2 = i32x2::new(0, 1); - let r: i32x2 = transmute(vmls_n_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_s64_x4() { + let a: [i64; 5] = [0, 1, 2, 3, 4]; + let e: [i64x1; 4] = [i64x1::new(1), i64x1::new(2), i64x1::new(3), i64x1::new(4)]; + let r: [i64x1; 4] = transmute(vld1_s64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_n_s32() { - let a: i32x4 = i32x4::new(6, 7, 8, 9); - let b: i32x4 = i32x4::new(2, 2, 2, 2); - let c: i32 = 3; - let e: i32x4 = i32x4::new(0, 1, 2, 3); - let r: i32x4 = transmute(vmlsq_n_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s8_x4() { + let a: [i8; 65] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8x16; 4] = [i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), i8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32), i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), i8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [i8x16; 4] = transmute(vld1q_s8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_n_u16() { - let a: u16x4 = u16x4::new(6, 7, 8, 9); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16 = 3; - let e: u16x4 = u16x4::new(0, 1, 2, 3); - let r: u16x4 = transmute(vmls_n_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s16_x4() { + let a: [i16; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i16x8; 4] = [i16x8::new(1, 2, 3, 4, 5, 6, 7, 8), i16x8::new(9, 10, 11, 12, 13, 14, 15, 16), i16x8::new(17, 18, 19, 20, 21, 22, 23, 24), i16x8::new(25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [i16x8; 4] = transmute(vld1q_s16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_n_u16() { - let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u16 = 3; - let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: u16x8 = transmute(vmlsq_n_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s32_x4() { + let a: [i32; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i32x4; 4] = [i32x4::new(1, 2, 3, 4), i32x4::new(5, 6, 7, 8), i32x4::new(9, 10, 11, 12), i32x4::new(13, 14, 15, 16)]; + let r: [i32x4; 4] = transmute(vld1q_s32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_n_u32() { - let a: u32x2 = u32x2::new(6, 7); - let b: u32x2 = u32x2::new(2, 2); - let c: u32 = 3; - let e: u32x2 = u32x2::new(0, 1); - let r: u32x2 = transmute(vmls_n_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_s64_x4() { + let a: [i64; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i64x2; 4] = [i64x2::new(1, 2), i64x2::new(3, 4), i64x2::new(5, 6), i64x2::new(7, 8)]; + let r: [i64x2; 4] = transmute(vld1q_s64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_n_u32() { - let a: u32x4 = u32x4::new(6, 7, 8, 9); - let b: u32x4 = u32x4::new(2, 2, 2, 2); - let c: u32 = 3; - let e: u32x4 = u32x4::new(0, 1, 2, 3); - let r: u32x4 = transmute(vmlsq_n_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u8_x2() { + let a: [u8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u8x8; 2] = [u8x8::new(1, 2, 3, 4, 5, 6, 7, 8), u8x8::new(9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [u8x8; 2] = transmute(vld1_u8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_n_f32() { - let a: f32x2 = f32x2::new(6., 7.); - let b: f32x2 = f32x2::new(2., 2.); - let c: f32 = 3.; - let e: f32x2 = f32x2::new(0., 1.); - let r: f32x2 = transmute(vmls_n_f32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u16_x2() { + let a: [u16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u16x4; 2] = [u16x4::new(1, 2, 3, 4), u16x4::new(5, 6, 7, 8)]; + let r: [u16x4; 2] = transmute(vld1_u16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_n_f32() { - let a: f32x4 = f32x4::new(6., 7., 8., 9.); - let b: f32x4 = f32x4::new(2., 2., 2., 2.); - let c: f32 = 3.; - let e: f32x4 = f32x4::new(0., 1., 2., 3.); - let r: f32x4 = transmute(vmlsq_n_f32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u32_x2() { + let a: [u32; 5] = [0, 1, 2, 3, 4]; + let e: [u32x2; 2] = [u32x2::new(1, 2), u32x2::new(3, 4)]; + let r: [u32x2; 2] = transmute(vld1_u32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_lane_s16() { - let a: i16x4 = i16x4::new(6, 7, 8, 9); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x4 = i16x4::new(0, 3, 0, 0); - let e: i16x4 = i16x4::new(0, 1, 2, 3); - let r: i16x4 = transmute(vmls_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u64_x2() { + let a: [u64; 3] = [0, 1, 2]; + let e: [u64x1; 2] = [u64x1::new(1), u64x1::new(2)]; + let r: [u64x1; 2] = transmute(vld1_u64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_laneq_s16() { - let a: i16x4 = i16x4::new(6, 7, 8, 9); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: i16x4 = i16x4::new(0, 1, 2, 3); - let r: i16x4 = transmute(vmls_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u8_x2() { + let a: [u8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8x16; 2] = [u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), u8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [u8x16; 2] = transmute(vld1q_u8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_lane_s16() { - let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i16x4 = i16x4::new(0, 3, 0, 0); - let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: i16x8 = transmute(vmlsq_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u16_x2() { + let a: [u16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u16x8; 2] = [u16x8::new(1, 2, 3, 4, 5, 6, 7, 8), u16x8::new(9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [u16x8; 2] = transmute(vld1q_u16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_laneq_s16() { - let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: i16x8 = transmute(vmlsq_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u32_x2() { + let a: [u32; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u32x4; 2] = [u32x4::new(1, 2, 3, 4), u32x4::new(5, 6, 7, 8)]; + let r: [u32x4; 2] = transmute(vld1q_u32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_lane_s32() { - let a: i32x2 = i32x2::new(6, 7); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x2 = i32x2::new(0, 3); - let e: i32x2 = i32x2::new(0, 1); - let r: i32x2 = transmute(vmls_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u64_x2() { + let a: [u64; 5] = [0, 1, 2, 3, 4]; + let e: [u64x2; 2] = [u64x2::new(1, 2), u64x2::new(3, 4)]; + let r: [u64x2; 2] = transmute(vld1q_u64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_laneq_s32() { - let a: i32x2 = i32x2::new(6, 7); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x4 = i32x4::new(0, 3, 0, 0); - let e: i32x2 = i32x2::new(0, 1); - let r: i32x2 = transmute(vmls_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u8_x3() { + let a: [u8; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [u8x8; 3] = [u8x8::new(1, 2, 3, 4, 5, 6, 7, 8), u8x8::new(9, 10, 11, 12, 13, 14, 15, 16), u8x8::new(17, 18, 19, 20, 21, 22, 23, 24)]; + let r: [u8x8; 3] = transmute(vld1_u8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_lane_s32() { - let a: i32x4 = i32x4::new(6, 7, 8, 9); - let b: i32x4 = i32x4::new(2, 2, 2, 2); - let c: i32x2 = i32x2::new(0, 3); - let e: i32x4 = i32x4::new(0, 1, 2, 3); - let r: i32x4 = transmute(vmlsq_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u16_x3() { + let a: [u16; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [u16x4; 3] = [u16x4::new(1, 2, 3, 4), u16x4::new(5, 6, 7, 8), u16x4::new(9, 10, 11, 12)]; + let r: [u16x4; 3] = transmute(vld1_u16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_laneq_s32() { - let a: i32x4 = i32x4::new(6, 7, 8, 9); - let b: i32x4 = i32x4::new(2, 2, 2, 2); - let c: i32x4 = i32x4::new(0, 3, 0, 0); - let e: i32x4 = i32x4::new(0, 1, 2, 3); - let r: i32x4 = transmute(vmlsq_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u32_x3() { + let a: [u32; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [u32x2; 3] = [u32x2::new(1, 2), u32x2::new(3, 4), u32x2::new(5, 6)]; + let r: [u32x2; 3] = transmute(vld1_u32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_lane_u16() { - let a: u16x4 = u16x4::new(6, 7, 8, 9); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x4 = u16x4::new(0, 3, 0, 0); - let e: u16x4 = u16x4::new(0, 1, 2, 3); - let r: u16x4 = transmute(vmls_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u64_x3() { + let a: [u64; 4] = [0, 1, 2, 3]; + let e: [u64x1; 3] = [u64x1::new(1), u64x1::new(2), u64x1::new(3)]; + let r: [u64x1; 3] = transmute(vld1_u64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_laneq_u16() { - let a: u16x4 = u16x4::new(6, 7, 8, 9); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: u16x4 = u16x4::new(0, 1, 2, 3); - let r: u16x4 = transmute(vmls_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u8_x3() { + let a: [u8; 49] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u8x16; 3] = [u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), u8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32), u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [u8x16; 3] = transmute(vld1q_u8_x3(a[1..].as_ptr())); assert_eq!(r, e); } - - #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_lane_u16() { - let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u16x4 = u16x4::new(0, 3, 0, 0); - let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: u16x8 = transmute(vmlsq_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_u16_x3() { + let a: [u16; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [u16x8; 3] = [u16x8::new(1, 2, 3, 4, 5, 6, 7, 8), u16x8::new(9, 10, 11, 12, 13, 14, 15, 16), u16x8::new(17, 18, 19, 20, 21, 22, 23, 24)]; + let r: [u16x8; 3] = transmute(vld1q_u16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_laneq_u16() { - let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: u16x8 = transmute(vmlsq_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u32_x3() { + let a: [u32; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [u32x4; 3] = [u32x4::new(1, 2, 3, 4), u32x4::new(5, 6, 7, 8), u32x4::new(9, 10, 11, 12)]; + let r: [u32x4; 3] = transmute(vld1q_u32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_lane_u32() { - let a: u32x2 = u32x2::new(6, 7); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x2 = u32x2::new(0, 3); - let e: u32x2 = u32x2::new(0, 1); - let r: u32x2 = transmute(vmls_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u64_x3() { + let a: [u64; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [u64x2; 3] = [u64x2::new(1, 2), u64x2::new(3, 4), u64x2::new(5, 6)]; + let r: [u64x2; 3] = transmute(vld1q_u64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_laneq_u32() { - let a: u32x2 = u32x2::new(6, 7); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x4 = u32x4::new(0, 3, 0, 0); - let e: u32x2 = u32x2::new(0, 1); - let r: u32x2 = transmute(vmls_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u8_x4() { + let a: [u8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8x8; 4] = [u8x8::new(1, 2, 3, 4, 5, 6, 7, 8), u8x8::new(9, 10, 11, 12, 13, 14, 15, 16), u8x8::new(17, 18, 19, 20, 21, 22, 23, 24), u8x8::new(25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [u8x8; 4] = transmute(vld1_u8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_lane_u32() { - let a: u32x4 = u32x4::new(6, 7, 8, 9); - let b: u32x4 = u32x4::new(2, 2, 2, 2); - let c: u32x2 = u32x2::new(0, 3); - let e: u32x4 = u32x4::new(0, 1, 2, 3); - let r: u32x4 = transmute(vmlsq_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u16_x4() { + let a: [u16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u16x4; 4] = [u16x4::new(1, 2, 3, 4), u16x4::new(5, 6, 7, 8), u16x4::new(9, 10, 11, 12), u16x4::new(13, 14, 15, 16)]; + let r: [u16x4; 4] = transmute(vld1_u16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_laneq_u32() { - let a: u32x4 = u32x4::new(6, 7, 8, 9); - let b: u32x4 = u32x4::new(2, 2, 2, 2); - let c: u32x4 = u32x4::new(0, 3, 0, 0); - let e: u32x4 = u32x4::new(0, 1, 2, 3); - let r: u32x4 = transmute(vmlsq_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u32_x4() { + let a: [u32; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u32x2; 4] = [u32x2::new(1, 2), u32x2::new(3, 4), u32x2::new(5, 6), u32x2::new(7, 8)]; + let r: [u32x2; 4] = transmute(vld1_u32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_lane_f32() { - let a: f32x2 = f32x2::new(6., 7.); - let b: f32x2 = f32x2::new(2., 2.); - let c: f32x2 = f32x2::new(0., 3.); - let e: f32x2 = f32x2::new(0., 1.); - let r: f32x2 = transmute(vmls_lane_f32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_u64_x4() { + let a: [u64; 5] = [0, 1, 2, 3, 4]; + let e: [u64x1; 4] = [u64x1::new(1), u64x1::new(2), u64x1::new(3), u64x1::new(4)]; + let r: [u64x1; 4] = transmute(vld1_u64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmls_laneq_f32() { - let a: f32x2 = f32x2::new(6., 7.); - let b: f32x2 = f32x2::new(2., 2.); - let c: f32x4 = f32x4::new(0., 3., 0., 0.); - let e: f32x2 = f32x2::new(0., 1.); - let r: f32x2 = transmute(vmls_laneq_f32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u8_x4() { + let a: [u8; 65] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8x16; 4] = [u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), u8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32), u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), u8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [u8x16; 4] = transmute(vld1q_u8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_lane_f32() { - let a: f32x4 = f32x4::new(6., 7., 8., 9.); - let b: f32x4 = f32x4::new(2., 2., 2., 2.); - let c: f32x2 = f32x2::new(0., 3.); - let e: f32x4 = f32x4::new(0., 1., 2., 3.); - let r: f32x4 = transmute(vmlsq_lane_f32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u16_x4() { + let a: [u16; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u16x8; 4] = [u16x8::new(1, 2, 3, 4, 5, 6, 7, 8), u16x8::new(9, 10, 11, 12, 13, 14, 15, 16), u16x8::new(17, 18, 19, 20, 21, 22, 23, 24), u16x8::new(25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [u16x8; 4] = transmute(vld1q_u16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsq_laneq_f32() { - let a: f32x4 = f32x4::new(6., 7., 8., 9.); - let b: f32x4 = f32x4::new(2., 2., 2., 2.); - let c: f32x4 = f32x4::new(0., 3., 0., 0.); - let e: f32x4 = f32x4::new(0., 1., 2., 3.); - let r: f32x4 = transmute(vmlsq_laneq_f32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u32_x4() { + let a: [u32; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u32x4; 4] = [u32x4::new(1, 2, 3, 4), u32x4::new(5, 6, 7, 8), u32x4::new(9, 10, 11, 12), u32x4::new(13, 14, 15, 16)]; + let r: [u32x4; 4] = transmute(vld1q_u32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_s8() { - let a: i16x8 = i16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: i8x8 = i8x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: i16x8 = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: i16x8 = transmute(vmlsl_s8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_u64_x4() { + let a: [u64; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u64x2; 4] = [u64x2::new(1, 2), u64x2::new(3, 4), u64x2::new(5, 6), u64x2::new(7, 8)]; + let r: [u64x2; 4] = transmute(vld1q_u64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_s16() { - let a: i32x4 = i32x4::new(6, 7, 8, 9); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x4 = i16x4::new(3, 3, 3, 3); - let e: i32x4 = i32x4::new(0, 1, 2, 3); - let r: i32x4 = transmute(vmlsl_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p8_x2() { + let a: [u8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i8x8; 2] = [i8x8::new(1, 2, 3, 4, 5, 6, 7, 8), i8x8::new(9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [i8x8; 2] = transmute(vld1_p8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_s32() { - let a: i64x2 = i64x2::new(6, 7); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x2 = i32x2::new(3, 3); - let e: i64x2 = i64x2::new(0, 1); - let r: i64x2 = transmute(vmlsl_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p8_x3() { + let a: [u8; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [i8x8; 3] = [i8x8::new(1, 2, 3, 4, 5, 6, 7, 8), i8x8::new(9, 10, 11, 12, 13, 14, 15, 16), i8x8::new(17, 18, 19, 20, 21, 22, 23, 24)]; + let r: [i8x8; 3] = transmute(vld1_p8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_u8() { - let a: u16x8 = u16x8::new(6, 7, 8, 9, 10, 11, 12, 13); - let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); - let c: u8x8 = u8x8::new(3, 3, 3, 3, 3, 3, 3, 3); - let e: u16x8 = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); - let r: u16x8 = transmute(vmlsl_u8(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p8_x4() { + let a: [u8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8x8; 4] = [i8x8::new(1, 2, 3, 4, 5, 6, 7, 8), i8x8::new(9, 10, 11, 12, 13, 14, 15, 16), i8x8::new(17, 18, 19, 20, 21, 22, 23, 24), i8x8::new(25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [i8x8; 4] = transmute(vld1_p8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_u16() { - let a: u32x4 = u32x4::new(6, 7, 8, 9); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x4 = u16x4::new(3, 3, 3, 3); - let e: u32x4 = u32x4::new(0, 1, 2, 3); - let r: u32x4 = transmute(vmlsl_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_p8_x2() { + let a: [u8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8x16; 2] = [i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), i8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [i8x16; 2] = transmute(vld1q_p8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_u32() { - let a: u64x2 = u64x2::new(6, 7); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x2 = u32x2::new(3, 3); - let e: u64x2 = u64x2::new(0, 1); - let r: u64x2 = transmute(vmlsl_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_p8_x3() { + let a: [u8; 49] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i8x16; 3] = [i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), i8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32), i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [i8x16; 3] = transmute(vld1q_p8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_n_s16() { - let a: i32x4 = i32x4::new(6, 7, 8, 9); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16 = 3; - let e: i32x4 = i32x4::new(0, 1, 2, 3); - let r: i32x4 = transmute(vmlsl_n_s16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_p8_x4() { + let a: [u8; 65] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8x16; 4] = [i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), i8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32), i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), i8x16::new(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [i8x16; 4] = transmute(vld1q_p8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_n_s32() { - let a: i64x2 = i64x2::new(6, 7); - let b: i32x2 = i32x2::new(2, 2); - let c: i32 = 3; - let e: i64x2 = i64x2::new(0, 1); - let r: i64x2 = transmute(vmlsl_n_s32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p16_x2() { + let a: [u16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i16x4; 2] = [i16x4::new(1, 2, 3, 4), i16x4::new(5, 6, 7, 8)]; + let r: [i16x4; 2] = transmute(vld1_p16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_n_u16() { - let a: u32x4 = u32x4::new(6, 7, 8, 9); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16 = 3; - let e: u32x4 = u32x4::new(0, 1, 2, 3); - let r: u32x4 = transmute(vmlsl_n_u16(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p16_x3() { + let a: [u16; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [i16x4; 3] = [i16x4::new(1, 2, 3, 4), i16x4::new(5, 6, 7, 8), i16x4::new(9, 10, 11, 12)]; + let r: [i16x4; 3] = transmute(vld1_p16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_n_u32() { - let a: u64x2 = u64x2::new(6, 7); - let b: u32x2 = u32x2::new(2, 2); - let c: u32 = 3; - let e: u64x2 = u64x2::new(0, 1); - let r: u64x2 = transmute(vmlsl_n_u32(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p16_x4() { + let a: [u16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i16x4; 4] = [i16x4::new(1, 2, 3, 4), i16x4::new(5, 6, 7, 8), i16x4::new(9, 10, 11, 12), i16x4::new(13, 14, 15, 16)]; + let r: [i16x4; 4] = transmute(vld1_p16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_lane_s16() { - let a: i32x4 = i32x4::new(6, 7, 8, 9); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x4 = i16x4::new(0, 3, 0, 0); - let e: i32x4 = i32x4::new(0, 1, 2, 3); - let r: i32x4 = transmute(vmlsl_lane_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_p16_x2() { + let a: [u16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i16x8; 2] = [i16x8::new(1, 2, 3, 4, 5, 6, 7, 8), i16x8::new(9, 10, 11, 12, 13, 14, 15, 16)]; + let r: [i16x8; 2] = transmute(vld1q_p16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_laneq_s16() { - let a: i32x4 = i32x4::new(6, 7, 8, 9); - let b: i16x4 = i16x4::new(2, 2, 2, 2); - let c: i16x8 = i16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: i32x4 = i32x4::new(0, 1, 2, 3); - let r: i32x4 = transmute(vmlsl_laneq_s16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_p16_x3() { + let a: [u16; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [i16x8; 3] = [i16x8::new(1, 2, 3, 4, 5, 6, 7, 8), i16x8::new(9, 10, 11, 12, 13, 14, 15, 16), i16x8::new(17, 18, 19, 20, 21, 22, 23, 24)]; + let r: [i16x8; 3] = transmute(vld1q_p16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_lane_s32() { - let a: i64x2 = i64x2::new(6, 7); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x2 = i32x2::new(0, 3); - let e: i64x2 = i64x2::new(0, 1); - let r: i64x2 = transmute(vmlsl_lane_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_p16_x4() { + let a: [u16; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i16x8; 4] = [i16x8::new(1, 2, 3, 4, 5, 6, 7, 8), i16x8::new(9, 10, 11, 12, 13, 14, 15, 16), i16x8::new(17, 18, 19, 20, 21, 22, 23, 24), i16x8::new(25, 26, 27, 28, 29, 30, 31, 32)]; + let r: [i16x8; 4] = transmute(vld1q_p16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_laneq_s32() { - let a: i64x2 = i64x2::new(6, 7); - let b: i32x2 = i32x2::new(2, 2); - let c: i32x4 = i32x4::new(0, 3, 0, 0); - let e: i64x2 = i64x2::new(0, 1); - let r: i64x2 = transmute(vmlsl_laneq_s32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p64_x2() { + let a: [u64; 3] = [0, 1, 2]; + let e: [i64x1; 2] = [i64x1::new(1), i64x1::new(2)]; + let r: [i64x1; 2] = transmute(vld1_p64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_lane_u16() { - let a: u32x4 = u32x4::new(6, 7, 8, 9); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x4 = u16x4::new(0, 3, 0, 0); - let e: u32x4 = u32x4::new(0, 1, 2, 3); - let r: u32x4 = transmute(vmlsl_lane_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p64_x3() { + let a: [u64; 4] = [0, 1, 2, 3]; + let e: [i64x1; 3] = [i64x1::new(1), i64x1::new(2), i64x1::new(3)]; + let r: [i64x1; 3] = transmute(vld1_p64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_laneq_u16() { - let a: u32x4 = u32x4::new(6, 7, 8, 9); - let b: u16x4 = u16x4::new(2, 2, 2, 2); - let c: u16x8 = u16x8::new(0, 3, 0, 0, 0, 0, 0, 0); - let e: u32x4 = u32x4::new(0, 1, 2, 3); - let r: u32x4 = transmute(vmlsl_laneq_u16::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1_p64_x4() { + let a: [u64; 5] = [0, 1, 2, 3, 4]; + let e: [i64x1; 4] = [i64x1::new(1), i64x1::new(2), i64x1::new(3), i64x1::new(4)]; + let r: [i64x1; 4] = transmute(vld1_p64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_lane_u32() { - let a: u64x2 = u64x2::new(6, 7); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x2 = u32x2::new(0, 3); - let e: u64x2 = u64x2::new(0, 1); - let r: u64x2 = transmute(vmlsl_lane_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_p64_x2() { + let a: [u64; 5] = [0, 1, 2, 3, 4]; + let e: [i64x2; 2] = [i64x2::new(1, 2), i64x2::new(3, 4)]; + let r: [i64x2; 2] = transmute(vld1q_p64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmlsl_laneq_u32() { - let a: u64x2 = u64x2::new(6, 7); - let b: u32x2 = u32x2::new(2, 2); - let c: u32x4 = u32x4::new(0, 3, 0, 0); - let e: u64x2 = u64x2::new(0, 1); - let r: u64x2 = transmute(vmlsl_laneq_u32::<1>(transmute(a), transmute(b), transmute(c))); + unsafe fn test_vld1q_p64_x3() { + let a: [u64; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [i64x2; 3] = [i64x2::new(1, 2), i64x2::new(3, 4), i64x2::new(5, 6)]; + let r: [i64x2; 3] = transmute(vld1q_p64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vneg_s8() { - let a: i8x8 = i8x8::new(0, 1, -1, 2, -2, 3, -3, 4); - let e: i8x8 = i8x8::new(0, -1, 1, -2, 2, -3, 3, -4); - let r: i8x8 = transmute(vneg_s8(transmute(a))); + unsafe fn test_vld1q_p64_x4() { + let a: [u64; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i64x2; 4] = [i64x2::new(1, 2), i64x2::new(3, 4), i64x2::new(5, 6), i64x2::new(7, 8)]; + let r: [i64x2; 4] = transmute(vld1q_p64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vnegq_s8() { - let a: i8x16 = i8x16::new(0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8); - let e: i8x16 = i8x16::new(0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8); - let r: i8x16 = transmute(vnegq_s8(transmute(a))); + unsafe fn test_vld1_f32_x2() { + let a: [f32; 5] = [0., 1., 2., 3., 4.]; + let e: [f32x2; 2] = [f32x2::new(1., 2.), f32x2::new(3., 4.)]; + let r: [f32x2; 2] = transmute(vld1_f32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vneg_s16() { - let a: i16x4 = i16x4::new(0, 1, -1, 2); - let e: i16x4 = i16x4::new(0, -1, 1, -2); - let r: i16x4 = transmute(vneg_s16(transmute(a))); + unsafe fn test_vld1q_f32_x2() { + let a: [f32; 9] = [0., 1., 2., 3., 4., 5., 6., 7., 8.]; + let e: [f32x4; 2] = [f32x4::new(1., 2., 3., 4.), f32x4::new(5., 6., 7., 8.)]; + let r: [f32x4; 2] = transmute(vld1q_f32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vnegq_s16() { - let a: i16x8 = i16x8::new(0, 1, -1, 2, -2, 3, -3, 4); - let e: i16x8 = i16x8::new(0, -1, 1, -2, 2, -3, 3, -4); - let r: i16x8 = transmute(vnegq_s16(transmute(a))); + unsafe fn test_vld1_f32_x3() { + let a: [f32; 7] = [0., 1., 2., 3., 4., 5., 6.]; + let e: [f32x2; 3] = [f32x2::new(1., 2.), f32x2::new(3., 4.), f32x2::new(5., 6.)]; + let r: [f32x2; 3] = transmute(vld1_f32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vneg_s32() { - let a: i32x2 = i32x2::new(0, 1); - let e: i32x2 = i32x2::new(0, -1); - let r: i32x2 = transmute(vneg_s32(transmute(a))); + unsafe fn test_vld1q_f32_x3() { + let a: [f32; 13] = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let e: [f32x4; 3] = [f32x4::new(1., 2., 3., 4.), f32x4::new(5., 6., 7., 8.), f32x4::new(9., 10., 11., 12.)]; + let r: [f32x4; 3] = transmute(vld1q_f32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vnegq_s32() { - let a: i32x4 = i32x4::new(0, 1, -1, 2); - let e: i32x4 = i32x4::new(0, -1, 1, -2); - let r: i32x4 = transmute(vnegq_s32(transmute(a))); + unsafe fn test_vld1_f32_x4() { + let a: [f32; 9] = [0., 1., 2., 3., 4., 5., 6., 7., 8.]; + let e: [f32x2; 4] = [f32x2::new(1., 2.), f32x2::new(3., 4.), f32x2::new(5., 6.), f32x2::new(7., 8.)]; + let r: [f32x2; 4] = transmute(vld1_f32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vneg_f32() { - let a: f32x2 = f32x2::new(0., 1.); - let e: f32x2 = f32x2::new(0., -1.); - let r: f32x2 = transmute(vneg_f32(transmute(a))); + unsafe fn test_vld1q_f32_x4() { + let a: [f32; 17] = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.]; + let e: [f32x4; 4] = [f32x4::new(1., 2., 3., 4.), f32x4::new(5., 6., 7., 8.), f32x4::new(9., 10., 11., 12.), f32x4::new(13., 14., 15., 16.)]; + let r: [f32x4; 4] = transmute(vld1q_f32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vnegq_f32() { - let a: f32x4 = f32x4::new(0., 1., -1., 2.); - let e: f32x4 = f32x4::new(0., -1., 1., -2.); - let r: f32x4 = transmute(vnegq_f32(transmute(a))); + unsafe fn test_vst1_s8_x2() { + let a: [i8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [i8; 16] = [0i8; 16]; + vst1_s8_x2(r.as_mut_ptr(), vld1_s8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqneg_s8() { - let a: i8x8 = i8x8::new(-128, 0, 1, -1, 2, -2, 3, -3); - let e: i8x8 = i8x8::new(0x7F, 0, -1, 1, -2, 2, -3, 3); - let r: i8x8 = transmute(vqneg_s8(transmute(a))); + unsafe fn test_vst1_s16_x2() { + let a: [i16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i16; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [i16; 8] = [0i16; 8]; + vst1_s16_x2(r.as_mut_ptr(), vld1_s16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqnegq_s8() { - let a: i8x16 = i8x16::new(-128, 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7); - let e: i8x16 = i8x16::new(0x7F, 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7); - let r: i8x16 = transmute(vqnegq_s8(transmute(a))); + unsafe fn test_vst1_s32_x2() { + let a: [i32; 5] = [0, 1, 2, 3, 4]; + let e: [i32; 4] = [1, 2, 3, 4]; + let mut r: [i32; 4] = [0i32; 4]; + vst1_s32_x2(r.as_mut_ptr(), vld1_s32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqneg_s16() { - let a: i16x4 = i16x4::new(-32768, 0, 1, -1); - let e: i16x4 = i16x4::new(0x7F_FF, 0, -1, 1); - let r: i16x4 = transmute(vqneg_s16(transmute(a))); + unsafe fn test_vst1_s64_x2() { + let a: [i64; 3] = [0, 1, 2]; + let e: [i64; 2] = [1, 2]; + let mut r: [i64; 2] = [0i64; 2]; + vst1_s64_x2(r.as_mut_ptr(), vld1_s64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqnegq_s16() { - let a: i16x8 = i16x8::new(-32768, 0, 1, -1, 2, -2, 3, -3); - let e: i16x8 = i16x8::new(0x7F_FF, 0, -1, 1, -2, 2, -3, 3); - let r: i16x8 = transmute(vqnegq_s16(transmute(a))); + unsafe fn test_vst1q_s8_x2() { + let a: [i8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [i8; 32] = [0i8; 32]; + vst1q_s8_x2(r.as_mut_ptr(), vld1q_s8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqneg_s32() { - let a: i32x2 = i32x2::new(-2147483648, 0); - let e: i32x2 = i32x2::new(0x7F_FF_FF_FF, 0); - let r: i32x2 = transmute(vqneg_s32(transmute(a))); + unsafe fn test_vst1q_s16_x2() { + let a: [i16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i16; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [i16; 16] = [0i16; 16]; + vst1q_s16_x2(r.as_mut_ptr(), vld1q_s16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqnegq_s32() { - let a: i32x4 = i32x4::new(-2147483648, 0, 1, -1); - let e: i32x4 = i32x4::new(0x7F_FF_FF_FF, 0, -1, 1); - let r: i32x4 = transmute(vqnegq_s32(transmute(a))); + unsafe fn test_vst1q_s32_x2() { + let a: [i32; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [i32; 8] = [0i32; 8]; + vst1q_s32_x2(r.as_mut_ptr(), vld1q_s32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsub_u8() { - let a: u8x8 = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u8x8 = u8x8::new(41, 40, 39, 38, 37, 36, 35, 34); - let r: u8x8 = transmute(vqsub_u8(transmute(a), transmute(b))); + unsafe fn test_vst1q_s64_x2() { + let a: [i64; 5] = [0, 1, 2, 3, 4]; + let e: [i64; 4] = [1, 2, 3, 4]; + let mut r: [i64; 4] = [0i64; 4]; + vst1q_s64_x2(r.as_mut_ptr(), vld1q_s64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsubq_u8() { - let a: u8x16 = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); - let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26); - let r: u8x16 = transmute(vqsubq_u8(transmute(a), transmute(b))); + unsafe fn test_vst1_s8_x3() { + let a: [i8; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [i8; 24] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let mut r: [i8; 24] = [0i8; 24]; + vst1_s8_x3(r.as_mut_ptr(), vld1_s8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsub_u16() { - let a: u16x4 = u16x4::new(42, 42, 42, 42); - let b: u16x4 = u16x4::new(1, 2, 3, 4); - let e: u16x4 = u16x4::new(41, 40, 39, 38); - let r: u16x4 = transmute(vqsub_u16(transmute(a), transmute(b))); + unsafe fn test_vst1_s16_x3() { + let a: [i16; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [i16; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let mut r: [i16; 12] = [0i16; 12]; + vst1_s16_x3(r.as_mut_ptr(), vld1_s16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsubq_u16() { - let a: u16x8 = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u16x8 = u16x8::new(41, 40, 39, 38, 37, 36, 35, 34); - let r: u16x8 = transmute(vqsubq_u16(transmute(a), transmute(b))); + unsafe fn test_vst1_s32_x3() { + let a: [i32; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [i32; 6] = [1, 2, 3, 4, 5, 6]; + let mut r: [i32; 6] = [0i32; 6]; + vst1_s32_x3(r.as_mut_ptr(), vld1_s32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsub_u32() { - let a: u32x2 = u32x2::new(42, 42); - let b: u32x2 = u32x2::new(1, 2); - let e: u32x2 = u32x2::new(41, 40); - let r: u32x2 = transmute(vqsub_u32(transmute(a), transmute(b))); + unsafe fn test_vst1_s64_x3() { + let a: [i64; 4] = [0, 1, 2, 3]; + let e: [i64; 3] = [1, 2, 3]; + let mut r: [i64; 3] = [0i64; 3]; + vst1_s64_x3(r.as_mut_ptr(), vld1_s64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsubq_u32() { - let a: u32x4 = u32x4::new(42, 42, 42, 42); - let b: u32x4 = u32x4::new(1, 2, 3, 4); - let e: u32x4 = u32x4::new(41, 40, 39, 38); - let r: u32x4 = transmute(vqsubq_u32(transmute(a), transmute(b))); + unsafe fn test_vst1q_s8_x3() { + let a: [i8; 49] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i8; 48] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [i8; 48] = [0i8; 48]; + vst1q_s8_x3(r.as_mut_ptr(), vld1q_s8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsub_u64() { - let a: u64x1 = u64x1::new(42); - let b: u64x1 = u64x1::new(1); - let e: u64x1 = u64x1::new(41); - let r: u64x1 = transmute(vqsub_u64(transmute(a), transmute(b))); + unsafe fn test_vst1q_s16_x3() { + let a: [i16; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [i16; 24] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let mut r: [i16; 24] = [0i16; 24]; + vst1q_s16_x3(r.as_mut_ptr(), vld1q_s16_x3(a[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vst1q_s32_x3() { + let a: [i32; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [i32; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let mut r: [i32; 12] = [0i32; 12]; + vst1q_s32_x3(r.as_mut_ptr(), vld1q_s32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsubq_u64() { - let a: u64x2 = u64x2::new(42, 42); - let b: u64x2 = u64x2::new(1, 2); - let e: u64x2 = u64x2::new(41, 40); - let r: u64x2 = transmute(vqsubq_u64(transmute(a), transmute(b))); + unsafe fn test_vst1q_s64_x3() { + let a: [i64; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [i64; 6] = [1, 2, 3, 4, 5, 6]; + let mut r: [i64; 6] = [0i64; 6]; + vst1q_s64_x3(r.as_mut_ptr(), vld1q_s64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsub_s8() { - let a: i8x8 = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: i8x8 = i8x8::new(41, 40, 39, 38, 37, 36, 35, 34); - let r: i8x8 = transmute(vqsub_s8(transmute(a), transmute(b))); + unsafe fn test_vst1_s8_x4() { + let a: [i8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [i8; 32] = [0i8; 32]; + vst1_s8_x4(r.as_mut_ptr(), vld1_s8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsubq_s8() { - let a: i8x16 = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); - let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: i8x16 = i8x16::new(41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26); - let r: i8x16 = transmute(vqsubq_s8(transmute(a), transmute(b))); + unsafe fn test_vst1_s16_x4() { + let a: [i16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i16; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [i16; 16] = [0i16; 16]; + vst1_s16_x4(r.as_mut_ptr(), vld1_s16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsub_s16() { - let a: i16x4 = i16x4::new(42, 42, 42, 42); - let b: i16x4 = i16x4::new(1, 2, 3, 4); - let e: i16x4 = i16x4::new(41, 40, 39, 38); - let r: i16x4 = transmute(vqsub_s16(transmute(a), transmute(b))); + unsafe fn test_vst1_s32_x4() { + let a: [i32; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [i32; 8] = [0i32; 8]; + vst1_s32_x4(r.as_mut_ptr(), vld1_s32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsubq_s16() { - let a: i16x8 = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: i16x8 = i16x8::new(41, 40, 39, 38, 37, 36, 35, 34); - let r: i16x8 = transmute(vqsubq_s16(transmute(a), transmute(b))); + unsafe fn test_vst1_s64_x4() { + let a: [i64; 5] = [0, 1, 2, 3, 4]; + let e: [i64; 4] = [1, 2, 3, 4]; + let mut r: [i64; 4] = [0i64; 4]; + vst1_s64_x4(r.as_mut_ptr(), vld1_s64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsub_s32() { - let a: i32x2 = i32x2::new(42, 42); - let b: i32x2 = i32x2::new(1, 2); - let e: i32x2 = i32x2::new(41, 40); - let r: i32x2 = transmute(vqsub_s32(transmute(a), transmute(b))); + unsafe fn test_vst1q_s8_x4() { + let a: [i8; 65] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i8; 64] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [i8; 64] = [0i8; 64]; + vst1q_s8_x4(r.as_mut_ptr(), vld1q_s8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsubq_s32() { - let a: i32x4 = i32x4::new(42, 42, 42, 42); - let b: i32x4 = i32x4::new(1, 2, 3, 4); - let e: i32x4 = i32x4::new(41, 40, 39, 38); - let r: i32x4 = transmute(vqsubq_s32(transmute(a), transmute(b))); + unsafe fn test_vst1q_s16_x4() { + let a: [i16; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [i16; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [i16; 32] = [0i16; 32]; + vst1q_s16_x4(r.as_mut_ptr(), vld1q_s16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsub_s64() { - let a: i64x1 = i64x1::new(42); - let b: i64x1 = i64x1::new(1); - let e: i64x1 = i64x1::new(41); - let r: i64x1 = transmute(vqsub_s64(transmute(a), transmute(b))); + unsafe fn test_vst1q_s32_x4() { + let a: [i32; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [i32; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [i32; 16] = [0i32; 16]; + vst1q_s32_x4(r.as_mut_ptr(), vld1q_s32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqsubq_s64() { - let a: i64x2 = i64x2::new(42, 42); - let b: i64x2 = i64x2::new(1, 2); - let e: i64x2 = i64x2::new(41, 40); - let r: i64x2 = transmute(vqsubq_s64(transmute(a), transmute(b))); + unsafe fn test_vst1q_s64_x4() { + let a: [i64; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [i64; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [i64; 8] = [0i64; 8]; + vst1q_s64_x4(r.as_mut_ptr(), vld1q_s64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhadd_u8() { - let a: u8x8 = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u8x8 = u8x8::new(21, 22, 22, 23, 23, 24, 24, 25); - let r: u8x8 = transmute(vhadd_u8(transmute(a), transmute(b))); + unsafe fn test_vst1_u8_x2() { + let a: [u8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u8; 16] = [0u8; 16]; + vst1_u8_x2(r.as_mut_ptr(), vld1_u8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhaddq_u8() { - let a: u8x16 = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); - let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29); - let r: u8x16 = transmute(vhaddq_u8(transmute(a), transmute(b))); + unsafe fn test_vst1_u16_x2() { + let a: [u16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u16; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [u16; 8] = [0u16; 8]; + vst1_u16_x2(r.as_mut_ptr(), vld1_u16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhadd_u16() { - let a: u16x4 = u16x4::new(42, 42, 42, 42); - let b: u16x4 = u16x4::new(1, 2, 3, 4); - let e: u16x4 = u16x4::new(21, 22, 22, 23); - let r: u16x4 = transmute(vhadd_u16(transmute(a), transmute(b))); + unsafe fn test_vst1_u32_x2() { + let a: [u32; 5] = [0, 1, 2, 3, 4]; + let e: [u32; 4] = [1, 2, 3, 4]; + let mut r: [u32; 4] = [0u32; 4]; + vst1_u32_x2(r.as_mut_ptr(), vld1_u32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhaddq_u16() { - let a: u16x8 = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u16x8 = u16x8::new(21, 22, 22, 23, 23, 24, 24, 25); - let r: u16x8 = transmute(vhaddq_u16(transmute(a), transmute(b))); + unsafe fn test_vst1_u64_x2() { + let a: [u64; 3] = [0, 1, 2]; + let e: [u64; 2] = [1, 2]; + let mut r: [u64; 2] = [0u64; 2]; + vst1_u64_x2(r.as_mut_ptr(), vld1_u64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhadd_u32() { - let a: u32x2 = u32x2::new(42, 42); - let b: u32x2 = u32x2::new(1, 2); - let e: u32x2 = u32x2::new(21, 22); - let r: u32x2 = transmute(vhadd_u32(transmute(a), transmute(b))); + unsafe fn test_vst1q_u8_x2() { + let a: [u8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [u8; 32] = [0u8; 32]; + vst1q_u8_x2(r.as_mut_ptr(), vld1q_u8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhaddq_u32() { - let a: u32x4 = u32x4::new(42, 42, 42, 42); - let b: u32x4 = u32x4::new(1, 2, 3, 4); - let e: u32x4 = u32x4::new(21, 22, 22, 23); - let r: u32x4 = transmute(vhaddq_u32(transmute(a), transmute(b))); + unsafe fn test_vst1q_u16_x2() { + let a: [u16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u16; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u16; 16] = [0u16; 16]; + vst1q_u16_x2(r.as_mut_ptr(), vld1q_u16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhadd_s8() { - let a: i8x8 = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: i8x8 = i8x8::new(21, 22, 22, 23, 23, 24, 24, 25); - let r: i8x8 = transmute(vhadd_s8(transmute(a), transmute(b))); + unsafe fn test_vst1q_u32_x2() { + let a: [u32; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [u32; 8] = [0u32; 8]; + vst1q_u32_x2(r.as_mut_ptr(), vld1q_u32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhaddq_s8() { - let a: i8x16 = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); - let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: i8x16 = i8x16::new(21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29); - let r: i8x16 = transmute(vhaddq_s8(transmute(a), transmute(b))); + unsafe fn test_vst1q_u64_x2() { + let a: [u64; 5] = [0, 1, 2, 3, 4]; + let e: [u64; 4] = [1, 2, 3, 4]; + let mut r: [u64; 4] = [0u64; 4]; + vst1q_u64_x2(r.as_mut_ptr(), vld1q_u64_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhadd_s16() { - let a: i16x4 = i16x4::new(42, 42, 42, 42); - let b: i16x4 = i16x4::new(1, 2, 3, 4); - let e: i16x4 = i16x4::new(21, 22, 22, 23); - let r: i16x4 = transmute(vhadd_s16(transmute(a), transmute(b))); + unsafe fn test_vst1_u8_x3() { + let a: [u8; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [u8; 24] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let mut r: [u8; 24] = [0u8; 24]; + vst1_u8_x3(r.as_mut_ptr(), vld1_u8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhaddq_s16() { - let a: i16x8 = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: i16x8 = i16x8::new(21, 22, 22, 23, 23, 24, 24, 25); - let r: i16x8 = transmute(vhaddq_s16(transmute(a), transmute(b))); + unsafe fn test_vst1_u16_x3() { + let a: [u16; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [u16; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let mut r: [u16; 12] = [0u16; 12]; + vst1_u16_x3(r.as_mut_ptr(), vld1_u16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhadd_s32() { - let a: i32x2 = i32x2::new(42, 42); - let b: i32x2 = i32x2::new(1, 2); - let e: i32x2 = i32x2::new(21, 22); - let r: i32x2 = transmute(vhadd_s32(transmute(a), transmute(b))); + unsafe fn test_vst1_u32_x3() { + let a: [u32; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [u32; 6] = [1, 2, 3, 4, 5, 6]; + let mut r: [u32; 6] = [0u32; 6]; + vst1_u32_x3(r.as_mut_ptr(), vld1_u32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vhaddq_s32() { - let a: i32x4 = i32x4::new(42, 42, 42, 42); - let b: i32x4 = i32x4::new(1, 2, 3, 4); - let e: i32x4 = i32x4::new(21, 22, 22, 23); - let r: i32x4 = transmute(vhaddq_s32(transmute(a), transmute(b))); + unsafe fn test_vst1_u64_x3() { + let a: [u64; 4] = [0, 1, 2, 3]; + let e: [u64; 3] = [1, 2, 3]; + let mut r: [u64; 3] = [0u64; 3]; + vst1_u64_x3(r.as_mut_ptr(), vld1_u64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhadd_u8() { - let a: u8x8 = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u8x8 = u8x8::new(22, 22, 23, 23, 24, 24, 25, 25); - let r: u8x8 = transmute(vrhadd_u8(transmute(a), transmute(b))); + unsafe fn test_vst1q_u8_x3() { + let a: [u8; 49] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u8; 48] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u8; 48] = [0u8; 48]; + vst1q_u8_x3(r.as_mut_ptr(), vld1q_u8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhaddq_u8() { - let a: u8x16 = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); - let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29); - let r: u8x16 = transmute(vrhaddq_u8(transmute(a), transmute(b))); + unsafe fn test_vst1q_u16_x3() { + let a: [u16; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [u16; 24] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let mut r: [u16; 24] = [0u16; 24]; + vst1q_u16_x3(r.as_mut_ptr(), vld1q_u16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhadd_u16() { - let a: u16x4 = u16x4::new(42, 42, 42, 42); - let b: u16x4 = u16x4::new(1, 2, 3, 4); - let e: u16x4 = u16x4::new(22, 22, 23, 23); - let r: u16x4 = transmute(vrhadd_u16(transmute(a), transmute(b))); + unsafe fn test_vst1q_u32_x3() { + let a: [u32; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [u32; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let mut r: [u32; 12] = [0u32; 12]; + vst1q_u32_x3(r.as_mut_ptr(), vld1q_u32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhaddq_u16() { - let a: u16x8 = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u16x8 = u16x8::new(22, 22, 23, 23, 24, 24, 25, 25); - let r: u16x8 = transmute(vrhaddq_u16(transmute(a), transmute(b))); + unsafe fn test_vst1q_u64_x3() { + let a: [u64; 7] = [0, 1, 2, 3, 4, 5, 6]; + let e: [u64; 6] = [1, 2, 3, 4, 5, 6]; + let mut r: [u64; 6] = [0u64; 6]; + vst1q_u64_x3(r.as_mut_ptr(), vld1q_u64_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhadd_u32() { - let a: u32x2 = u32x2::new(42, 42); - let b: u32x2 = u32x2::new(1, 2); - let e: u32x2 = u32x2::new(22, 22); - let r: u32x2 = transmute(vrhadd_u32(transmute(a), transmute(b))); + unsafe fn test_vst1_u8_x4() { + let a: [u8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [u8; 32] = [0u8; 32]; + vst1_u8_x4(r.as_mut_ptr(), vld1_u8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhaddq_u32() { - let a: u32x4 = u32x4::new(42, 42, 42, 42); - let b: u32x4 = u32x4::new(1, 2, 3, 4); - let e: u32x4 = u32x4::new(22, 22, 23, 23); - let r: u32x4 = transmute(vrhaddq_u32(transmute(a), transmute(b))); + unsafe fn test_vst1_u16_x4() { + let a: [u16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u16; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u16; 16] = [0u16; 16]; + vst1_u16_x4(r.as_mut_ptr(), vld1_u16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhadd_s8() { - let a: i8x8 = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: i8x8 = i8x8::new(22, 22, 23, 23, 24, 24, 25, 25); - let r: i8x8 = transmute(vrhadd_s8(transmute(a), transmute(b))); + unsafe fn test_vst1_u32_x4() { + let a: [u32; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [u32; 8] = [0u32; 8]; + vst1_u32_x4(r.as_mut_ptr(), vld1_u32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhaddq_s8() { - let a: i8x16 = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); - let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: i8x16 = i8x16::new(22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29); - let r: i8x16 = transmute(vrhaddq_s8(transmute(a), transmute(b))); + unsafe fn test_vst1_u64_x4() { + let a: [u64; 5] = [0, 1, 2, 3, 4]; + let e: [u64; 4] = [1, 2, 3, 4]; + let mut r: [u64; 4] = [0u64; 4]; + vst1_u64_x4(r.as_mut_ptr(), vld1_u64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhadd_s16() { - let a: i16x4 = i16x4::new(42, 42, 42, 42); - let b: i16x4 = i16x4::new(1, 2, 3, 4); - let e: i16x4 = i16x4::new(22, 22, 23, 23); - let r: i16x4 = transmute(vrhadd_s16(transmute(a), transmute(b))); + unsafe fn test_vst1q_u8_x4() { + let a: [u8; 65] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8; 64] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [u8; 64] = [0u8; 64]; + vst1q_u8_x4(r.as_mut_ptr(), vld1q_u8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhaddq_s16() { - let a: i16x8 = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: i16x8 = i16x8::new(22, 22, 23, 23, 24, 24, 25, 25); - let r: i16x8 = transmute(vrhaddq_s16(transmute(a), transmute(b))); + unsafe fn test_vst1q_u16_x4() { + let a: [u16; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u16; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [u16; 32] = [0u16; 32]; + vst1q_u16_x4(r.as_mut_ptr(), vld1q_u16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhadd_s32() { - let a: i32x2 = i32x2::new(42, 42); - let b: i32x2 = i32x2::new(1, 2); - let e: i32x2 = i32x2::new(22, 22); - let r: i32x2 = transmute(vrhadd_s32(transmute(a), transmute(b))); + unsafe fn test_vst1q_u32_x4() { + let a: [u32; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u32; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u32; 16] = [0u32; 16]; + vst1q_u32_x4(r.as_mut_ptr(), vld1q_u32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrhaddq_s32() { - let a: i32x4 = i32x4::new(42, 42, 42, 42); - let b: i32x4 = i32x4::new(1, 2, 3, 4); - let e: i32x4 = i32x4::new(22, 22, 23, 23); - let r: i32x4 = transmute(vrhaddq_s32(transmute(a), transmute(b))); + unsafe fn test_vst1q_u64_x4() { + let a: [u64; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u64; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [u64; 8] = [0u64; 8]; + vst1q_u64_x4(r.as_mut_ptr(), vld1q_u64_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrndn_f32() { - let a: f32x2 = f32x2::new(-1.5, 0.5); - let e: f32x2 = f32x2::new(-2.0, 0.0); - let r: f32x2 = transmute(vrndn_f32(transmute(a))); + unsafe fn test_vst1_p8_x2() { + let a: [u8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u8; 16] = [0u8; 16]; + vst1_p8_x2(r.as_mut_ptr(), vld1_p8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vrndnq_f32() { - let a: f32x4 = f32x4::new(-1.5, 0.5, 1.5, 2.5); - let e: f32x4 = f32x4::new(-2.0, 0.0, 2.0, 2.0); - let r: f32x4 = transmute(vrndnq_f32(transmute(a))); + unsafe fn test_vst1_p8_x3() { + let a: [u8; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [u8; 24] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let mut r: [u8; 24] = [0u8; 24]; + vst1_p8_x3(r.as_mut_ptr(), vld1_p8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqadd_u8() { - let a: u8x8 = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u8x8 = u8x8::new(43, 44, 45, 46, 47, 48, 49, 50); - let r: u8x8 = transmute(vqadd_u8(transmute(a), transmute(b))); + unsafe fn test_vst1_p8_x4() { + let a: [u8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [u8; 32] = [0u8; 32]; + vst1_p8_x4(r.as_mut_ptr(), vld1_p8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqaddq_u8() { - let a: u8x16 = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); - let b: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: u8x16 = u8x16::new(43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58); - let r: u8x16 = transmute(vqaddq_u8(transmute(a), transmute(b))); + unsafe fn test_vst1q_p8_x2() { + let a: [u8; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [u8; 32] = [0u8; 32]; + vst1q_p8_x2(r.as_mut_ptr(), vld1q_p8_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqadd_u16() { - let a: u16x4 = u16x4::new(42, 42, 42, 42); - let b: u16x4 = u16x4::new(1, 2, 3, 4); - let e: u16x4 = u16x4::new(43, 44, 45, 46); - let r: u16x4 = transmute(vqadd_u16(transmute(a), transmute(b))); + unsafe fn test_vst1q_p8_x3() { + let a: [u8; 49] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u8; 48] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u8; 48] = [0u8; 48]; + vst1q_p8_x3(r.as_mut_ptr(), vld1q_p8_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqaddq_u16() { - let a: u16x8 = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: u16x8 = u16x8::new(43, 44, 45, 46, 47, 48, 49, 50); - let r: u16x8 = transmute(vqaddq_u16(transmute(a), transmute(b))); + unsafe fn test_vst1q_p8_x4() { + let a: [u8; 65] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u8; 64] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [u8; 64] = [0u8; 64]; + vst1q_p8_x4(r.as_mut_ptr(), vld1q_p8_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqadd_u32() { - let a: u32x2 = u32x2::new(42, 42); - let b: u32x2 = u32x2::new(1, 2); - let e: u32x2 = u32x2::new(43, 44); - let r: u32x2 = transmute(vqadd_u32(transmute(a), transmute(b))); + unsafe fn test_vst1_p16_x2() { + let a: [u16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e: [u16; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut r: [u16; 8] = [0u16; 8]; + vst1_p16_x2(r.as_mut_ptr(), vld1_p16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqaddq_u32() { - let a: u32x4 = u32x4::new(42, 42, 42, 42); - let b: u32x4 = u32x4::new(1, 2, 3, 4); - let e: u32x4 = u32x4::new(43, 44, 45, 46); - let r: u32x4 = transmute(vqaddq_u32(transmute(a), transmute(b))); + unsafe fn test_vst1_p16_x3() { + let a: [u16; 13] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let e: [u16; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let mut r: [u16; 12] = [0u16; 12]; + vst1_p16_x3(r.as_mut_ptr(), vld1_p16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqadd_u64() { - let a: u64x1 = u64x1::new(42); - let b: u64x1 = u64x1::new(1); - let e: u64x1 = u64x1::new(43); - let r: u64x1 = transmute(vqadd_u64(transmute(a), transmute(b))); + unsafe fn test_vst1_p16_x4() { + let a: [u16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u16; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u16; 16] = [0u16; 16]; + vst1_p16_x4(r.as_mut_ptr(), vld1_p16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqaddq_u64() { - let a: u64x2 = u64x2::new(42, 42); - let b: u64x2 = u64x2::new(1, 2); - let e: u64x2 = u64x2::new(43, 44); - let r: u64x2 = transmute(vqaddq_u64(transmute(a), transmute(b))); + unsafe fn test_vst1q_p16_x2() { + let a: [u16; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e: [u16; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let mut r: [u16; 16] = [0u16; 16]; + vst1q_p16_x2(r.as_mut_ptr(), vld1q_p16_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqadd_s8() { - let a: i8x8 = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: i8x8 = i8x8::new(43, 44, 45, 46, 47, 48, 49, 50); - let r: i8x8 = transmute(vqadd_s8(transmute(a), transmute(b))); + unsafe fn test_vst1q_p16_x3() { + let a: [u16; 25] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let e: [u16; 24] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + let mut r: [u16; 24] = [0u16; 24]; + vst1q_p16_x3(r.as_mut_ptr(), vld1q_p16_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqaddq_s8() { - let a: i8x16 = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); - let b: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e: i8x16 = i8x16::new(43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58); - let r: i8x16 = transmute(vqaddq_s8(transmute(a), transmute(b))); + unsafe fn test_vst1q_p16_x4() { + let a: [u16; 33] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let e: [u16; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let mut r: [u16; 32] = [0u16; 32]; + vst1q_p16_x4(r.as_mut_ptr(), vld1q_p16_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqadd_s16() { - let a: i16x4 = i16x4::new(42, 42, 42, 42); - let b: i16x4 = i16x4::new(1, 2, 3, 4); - let e: i16x4 = i16x4::new(43, 44, 45, 46); - let r: i16x4 = transmute(vqadd_s16(transmute(a), transmute(b))); + unsafe fn test_vst1_f32_x2() { + let a: [f32; 5] = [0., 1., 2., 3., 4.]; + let e: [f32; 4] = [1., 2., 3., 4.]; + let mut r: [f32; 4] = [0f32; 4]; + vst1_f32_x2(r.as_mut_ptr(), vld1_f32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqaddq_s16() { - let a: i16x8 = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); - let b: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let e: i16x8 = i16x8::new(43, 44, 45, 46, 47, 48, 49, 50); - let r: i16x8 = transmute(vqaddq_s16(transmute(a), transmute(b))); + unsafe fn test_vst1q_f32_x2() { + let a: [f32; 9] = [0., 1., 2., 3., 4., 5., 6., 7., 8.]; + let e: [f32; 8] = [1., 2., 3., 4., 5., 6., 7., 8.]; + let mut r: [f32; 8] = [0f32; 8]; + vst1q_f32_x2(r.as_mut_ptr(), vld1q_f32_x2(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqadd_s32() { - let a: i32x2 = i32x2::new(42, 42); - let b: i32x2 = i32x2::new(1, 2); - let e: i32x2 = i32x2::new(43, 44); - let r: i32x2 = transmute(vqadd_s32(transmute(a), transmute(b))); + unsafe fn test_vst1_f32_x3() { + let a: [f32; 7] = [0., 1., 2., 3., 4., 5., 6.]; + let e: [f32; 6] = [1., 2., 3., 4., 5., 6.]; + let mut r: [f32; 6] = [0f32; 6]; + vst1_f32_x3(r.as_mut_ptr(), vld1_f32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqaddq_s32() { - let a: i32x4 = i32x4::new(42, 42, 42, 42); - let b: i32x4 = i32x4::new(1, 2, 3, 4); - let e: i32x4 = i32x4::new(43, 44, 45, 46); - let r: i32x4 = transmute(vqaddq_s32(transmute(a), transmute(b))); + unsafe fn test_vst1q_f32_x3() { + let a: [f32; 13] = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let e: [f32; 12] = [1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]; + let mut r: [f32; 12] = [0f32; 12]; + vst1q_f32_x3(r.as_mut_ptr(), vld1q_f32_x3(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqadd_s64() { - let a: i64x1 = i64x1::new(42); - let b: i64x1 = i64x1::new(1); - let e: i64x1 = i64x1::new(43); - let r: i64x1 = transmute(vqadd_s64(transmute(a), transmute(b))); + unsafe fn test_vst1_f32_x4() { + let a: [f32; 9] = [0., 1., 2., 3., 4., 5., 6., 7., 8.]; + let e: [f32; 8] = [1., 2., 3., 4., 5., 6., 7., 8.]; + let mut r: [f32; 8] = [0f32; 8]; + vst1_f32_x4(r.as_mut_ptr(), vld1_f32_x4(a[1..].as_ptr())); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqaddq_s64() { - let a: i64x2 = i64x2::new(42, 42); - let b: i64x2 = i64x2::new(1, 2); - let e: i64x2 = i64x2::new(43, 44); - let r: i64x2 = transmute(vqaddq_s64(transmute(a), transmute(b))); + unsafe fn test_vst1q_f32_x4() { + let a: [f32; 17] = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.]; + let e: [f32; 16] = [1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.]; + let mut r: [f32; 16] = [0f32; 16]; + vst1q_f32_x4(r.as_mut_ptr(), vld1q_f32_x4(a[1..].as_ptr())); assert_eq!(r, e); } @@ -19439,38 +22709,38 @@ } #[simd_test(enable = "neon")] - unsafe fn test_vmullh_n_s16() { + unsafe fn test_vmull_n_s16() { let a: i16x4 = i16x4::new(1, 2, 3, 4); let b: i16 = 2; let e: i32x4 = i32x4::new(2, 4, 6, 8); - let r: i32x4 = transmute(vmullh_n_s16(transmute(a), transmute(b))); + let r: i32x4 = transmute(vmull_n_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmulls_n_s32() { + unsafe fn test_vmull_n_s32() { let a: i32x2 = i32x2::new(1, 2); let b: i32 = 2; let e: i64x2 = i64x2::new(2, 4); - let r: i64x2 = transmute(vmulls_n_s32(transmute(a), transmute(b))); + let r: i64x2 = transmute(vmull_n_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmullh_n_u16() { + unsafe fn test_vmull_n_u16() { let a: u16x4 = u16x4::new(1, 2, 3, 4); let b: u16 = 2; let e: u32x4 = u32x4::new(2, 4, 6, 8); - let r: u32x4 = transmute(vmullh_n_u16(transmute(a), transmute(b))); + let r: u32x4 = transmute(vmull_n_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmulls_n_u32() { + unsafe fn test_vmull_n_u32() { let a: u32x2 = u32x2::new(1, 2); let b: u32 = 2; let e: u64x2 = u64x2::new(2, 4); - let r: u64x2 = transmute(vmulls_n_u32(transmute(a), transmute(b))); + let r: u64x2 = transmute(vmull_n_u32(transmute(a), transmute(b))); assert_eq!(r, e); } @@ -20635,20 +23905,20 @@ } #[simd_test(enable = "neon")] - unsafe fn test_vqdmulhq_nq_s16() { + unsafe fn test_vqdmulhq_n_s16() { let a: i16x8 = i16x8::new(0x7F_FF, 0x7F_FF, 0x7F_FF, 0x7F_FF, 0x7F_FF, 0x7F_FF, 0x7F_FF, 0x7F_FF); let b: i16 = 2; let e: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); - let r: i16x8 = transmute(vqdmulhq_nq_s16(transmute(a), transmute(b))); + let r: i16x8 = transmute(vqdmulhq_n_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqdmulhq_nq_s32() { + unsafe fn test_vqdmulhq_n_s32() { let a: i32x4 = i32x4::new(0x7F_FF_FF_FF, 0x7F_FF_FF_FF, 0x7F_FF_FF_FF, 0x7F_FF_FF_FF); let b: i32 = 2; let e: i32x4 = i32x4::new(1, 1, 1, 1); - let r: i32x4 = transmute(vqdmulhq_nq_s32(transmute(a), transmute(b))); + let r: i32x4 = transmute(vqdmulhq_n_s32(transmute(a), transmute(b))); assert_eq!(r, e); } diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/load_tests.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/load_tests.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/load_tests.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/load_tests.rs 2021-11-29 19:27:28.000000000 +0000 @@ -173,6 +173,22 @@ assert_eq!(r, e) } +#[simd_test(enable = "neon,aes")] +unsafe fn test_vld1_p64() { + let a: [p64; 2] = [0, 1]; + let e = u64x1::new(1); + let r: u64x1 = transmute(vld1_p64(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon,aes")] +unsafe fn test_vld1q_p64() { + let a: [p64; 3] = [0, 1, 2]; + let e = u64x2::new(1, 2); + let r: u64x2 = transmute(vld1q_p64(a[1..].as_ptr())); + assert_eq!(r, e) +} + #[simd_test(enable = "neon")] unsafe fn test_vld1_f32() { let a: [f32; 3] = [0., 1., 2.]; @@ -188,21 +204,3 @@ let r: f32x4 = transmute(vld1q_f32(a[1..].as_ptr())); assert_eq!(r, e) } - -#[cfg(target_arch = "aarch64")] -#[simd_test(enable = "neon")] -unsafe fn test_vld1_f64() { - let a: [f64; 2] = [0., 1.]; - let e = f64x1::new(1.); - let r: f64x1 = transmute(vld1_f64(a[1..].as_ptr())); - assert_eq!(r, e) -} - -#[cfg(target_arch = "aarch64")] -#[simd_test(enable = "neon")] -unsafe fn test_vld1q_f64() { - let a: [f64; 3] = [0., 1., 2.]; - let e = f64x2::new(1., 2.); - let r: f64x2 = transmute(vld1q_f64(a[1..].as_ptr())); - assert_eq!(r, e) -} diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs 2021-11-29 19:27:28.000000000 +0000 @@ -92,6 +92,16 @@ #[derive(Copy, Clone)] pub struct int8x8x4_t(pub int8x8_t, pub int8x8_t, pub int8x8_t, pub int8x8_t); +/// ARM-specific type containing two `int8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct int8x16x2_t(pub int8x16_t, pub int8x16_t); +/// ARM-specific type containing three `int8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct int8x16x3_t(pub int8x16_t, pub int8x16_t, pub int8x16_t); +/// ARM-specific type containing four `int8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct int8x16x4_t(pub int8x16_t, pub int8x16_t, pub int8x16_t, pub int8x16_t); + /// ARM-specific type containing two `uint8x8_t` vectors. #[derive(Copy, Clone)] pub struct uint8x8x2_t(pub uint8x8_t, pub uint8x8_t); @@ -102,6 +112,21 @@ #[derive(Copy, Clone)] pub struct uint8x8x4_t(pub uint8x8_t, pub uint8x8_t, pub uint8x8_t, pub uint8x8_t); +/// ARM-specific type containing two `uint8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct uint8x16x2_t(pub uint8x16_t, pub uint8x16_t); +/// ARM-specific type containing three `uint8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct uint8x16x3_t(pub uint8x16_t, pub uint8x16_t, pub uint8x16_t); +/// ARM-specific type containing four `uint8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct uint8x16x4_t( + pub uint8x16_t, + pub uint8x16_t, + pub uint8x16_t, + pub uint8x16_t, +); + /// ARM-specific type containing two `poly8x8_t` vectors. #[derive(Copy, Clone)] pub struct poly8x8x2_t(pub poly8x8_t, pub poly8x8_t); @@ -112,8 +137,263 @@ #[derive(Copy, Clone)] pub struct poly8x8x4_t(pub poly8x8_t, pub poly8x8_t, pub poly8x8_t, pub poly8x8_t); +/// ARM-specific type containing two `poly8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct poly8x16x2_t(pub poly8x16_t, pub poly8x16_t); +/// ARM-specific type containing three `poly8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct poly8x16x3_t(pub poly8x16_t, pub poly8x16_t, pub poly8x16_t); +/// ARM-specific type containing four `poly8x16_t` vectors. +#[derive(Copy, Clone)] +pub struct poly8x16x4_t( + pub poly8x16_t, + pub poly8x16_t, + pub poly8x16_t, + pub poly8x16_t, +); + +/// ARM-specific type containing two `int16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t); +/// ARM-specific type containing three `int16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct int16x4x3_t(pub int16x4_t, pub int16x4_t, pub int16x4_t); +/// ARM-specific type containing four `int16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct int16x4x4_t(pub int16x4_t, pub int16x4_t, pub int16x4_t, pub int16x4_t); + +/// ARM-specific type containing two `int16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct int16x8x2_t(pub int16x8_t, pub int16x8_t); +/// ARM-specific type containing three `int16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct int16x8x3_t(pub int16x8_t, pub int16x8_t, pub int16x8_t); +/// ARM-specific type containing four `int16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct int16x8x4_t(pub int16x8_t, pub int16x8_t, pub int16x8_t, pub int16x8_t); + +/// ARM-specific type containing two `uint16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct uint16x4x2_t(pub uint16x4_t, pub uint16x4_t); +/// ARM-specific type containing three `uint16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct uint16x4x3_t(pub uint16x4_t, pub uint16x4_t, pub uint16x4_t); +/// ARM-specific type containing four `uint16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct uint16x4x4_t( + pub uint16x4_t, + pub uint16x4_t, + pub uint16x4_t, + pub uint16x4_t, +); + +/// ARM-specific type containing two `uint16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct uint16x8x2_t(pub uint16x8_t, pub uint16x8_t); +/// ARM-specific type containing three `uint16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct uint16x8x3_t(pub uint16x8_t, pub uint16x8_t, pub uint16x8_t); +/// ARM-specific type containing four `uint16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct uint16x8x4_t( + pub uint16x8_t, + pub uint16x8_t, + pub uint16x8_t, + pub uint16x8_t, +); + +/// ARM-specific type containing two `poly16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct poly16x4x2_t(pub poly16x4_t, pub poly16x4_t); +/// ARM-specific type containing three `poly16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct poly16x4x3_t(pub poly16x4_t, pub poly16x4_t, pub poly16x4_t); +/// ARM-specific type containing four `poly16x4_t` vectors. +#[derive(Copy, Clone)] +pub struct poly16x4x4_t( + pub poly16x4_t, + pub poly16x4_t, + pub poly16x4_t, + pub poly16x4_t, +); + +/// ARM-specific type containing two `poly16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct poly16x8x2_t(pub poly16x8_t, pub poly16x8_t); +/// ARM-specific type containing three `poly16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct poly16x8x3_t(pub poly16x8_t, pub poly16x8_t, pub poly16x8_t); +/// ARM-specific type containing four `poly16x8_t` vectors. +#[derive(Copy, Clone)] +pub struct poly16x8x4_t( + pub poly16x8_t, + pub poly16x8_t, + pub poly16x8_t, + pub poly16x8_t, +); + +/// ARM-specific type containing two `int32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct int32x2x2_t(pub int32x2_t, pub int32x2_t); +/// ARM-specific type containing three `int32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct int32x2x3_t(pub int32x2_t, pub int32x2_t, pub int32x2_t); +/// ARM-specific type containing four `int32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct int32x2x4_t(pub int32x2_t, pub int32x2_t, pub int32x2_t, pub int32x2_t); + +/// ARM-specific type containing two `int32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct int32x4x2_t(pub int32x4_t, pub int32x4_t); +/// ARM-specific type containing three `int32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct int32x4x3_t(pub int32x4_t, pub int32x4_t, pub int32x4_t); +/// ARM-specific type containing four `int32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct int32x4x4_t(pub int32x4_t, pub int32x4_t, pub int32x4_t, pub int32x4_t); + +/// ARM-specific type containing two `uint32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct uint32x2x2_t(pub uint32x2_t, pub uint32x2_t); +/// ARM-specific type containing three `uint32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct uint32x2x3_t(pub uint32x2_t, pub uint32x2_t, pub uint32x2_t); +/// ARM-specific type containing four `uint32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct uint32x2x4_t( + pub uint32x2_t, + pub uint32x2_t, + pub uint32x2_t, + pub uint32x2_t, +); + +/// ARM-specific type containing two `uint32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct uint32x4x2_t(pub uint32x4_t, pub uint32x4_t); +/// ARM-specific type containing three `uint32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct uint32x4x3_t(pub uint32x4_t, pub uint32x4_t, pub uint32x4_t); +/// ARM-specific type containing four `uint32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct uint32x4x4_t( + pub uint32x4_t, + pub uint32x4_t, + pub uint32x4_t, + pub uint32x4_t, +); + +/// ARM-specific type containing two `float32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct float32x2x2_t(pub float32x2_t, pub float32x2_t); +/// ARM-specific type containing three `float32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct float32x2x3_t(pub float32x2_t, pub float32x2_t, pub float32x2_t); +/// ARM-specific type containing four `float32x2_t` vectors. +#[derive(Copy, Clone)] +pub struct float32x2x4_t( + pub float32x2_t, + pub float32x2_t, + pub float32x2_t, + pub float32x2_t, +); + +/// ARM-specific type containing two `float32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct float32x4x2_t(pub float32x4_t, pub float32x4_t); +/// ARM-specific type containing three `float32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct float32x4x3_t(pub float32x4_t, pub float32x4_t, pub float32x4_t); +/// ARM-specific type containing four `float32x4_t` vectors. +#[derive(Copy, Clone)] +pub struct float32x4x4_t( + pub float32x4_t, + pub float32x4_t, + pub float32x4_t, + pub float32x4_t, +); + +/// ARM-specific type containing four `int64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct int64x1x2_t(pub int64x1_t, pub int64x1_t); +/// ARM-specific type containing four `int64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct int64x1x3_t(pub int64x1_t, pub int64x1_t, pub int64x1_t); +/// ARM-specific type containing four `int64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct int64x1x4_t(pub int64x1_t, pub int64x1_t, pub int64x1_t, pub int64x1_t); + +/// ARM-specific type containing four `int64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct int64x2x2_t(pub int64x2_t, pub int64x2_t); +/// ARM-specific type containing four `int64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct int64x2x3_t(pub int64x2_t, pub int64x2_t, pub int64x2_t); +/// ARM-specific type containing four `int64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct int64x2x4_t(pub int64x2_t, pub int64x2_t, pub int64x2_t, pub int64x2_t); + +/// ARM-specific type containing four `uint64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct uint64x1x2_t(pub uint64x1_t, pub uint64x1_t); +/// ARM-specific type containing four `uint64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct uint64x1x3_t(pub uint64x1_t, pub uint64x1_t, pub uint64x1_t); +/// ARM-specific type containing four `uint64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct uint64x1x4_t( + pub uint64x1_t, + pub uint64x1_t, + pub uint64x1_t, + pub uint64x1_t, +); + +/// ARM-specific type containing four `uint64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct uint64x2x2_t(pub uint64x2_t, pub uint64x2_t); +/// ARM-specific type containing four `uint64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct uint64x2x3_t(pub uint64x2_t, pub uint64x2_t, pub uint64x2_t); +/// ARM-specific type containing four `uint64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct uint64x2x4_t( + pub uint64x2_t, + pub uint64x2_t, + pub uint64x2_t, + pub uint64x2_t, +); + +/// ARM-specific type containing four `poly64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct poly64x1x2_t(pub poly64x1_t, pub poly64x1_t); +/// ARM-specific type containing four `poly64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct poly64x1x3_t(pub poly64x1_t, pub poly64x1_t, pub poly64x1_t); +/// ARM-specific type containing four `poly64x1_t` vectors. +#[derive(Copy, Clone)] +pub struct poly64x1x4_t( + pub poly64x1_t, + pub poly64x1_t, + pub poly64x1_t, + pub poly64x1_t, +); + +/// ARM-specific type containing four `poly64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct poly64x2x2_t(pub poly64x2_t, pub poly64x2_t); +/// ARM-specific type containing four `poly64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct poly64x2x3_t(pub poly64x2_t, pub poly64x2_t, pub poly64x2_t); +/// ARM-specific type containing four `poly64x2_t` vectors. +#[derive(Copy, Clone)] +pub struct poly64x2x4_t( + pub poly64x2_t, + pub poly64x2_t, + pub poly64x2_t, + pub poly64x2_t, +); + #[allow(improper_ctypes)] -extern "C" { +extern "unadjusted" { // absolute value (64-bit) #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabs.v8i8")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.abs.v8i8")] @@ -545,6 +825,30 @@ /// Load one single-element structure to one lane of one register. #[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_legacy_const_generics(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr", LANE = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr, LANE = 0))] +pub unsafe fn vld1_lane_p64(ptr: *const p64, src: poly64x1_t) -> poly64x1_t { + static_assert!(LANE : i32 where LANE == 0); + simd_insert(src, LANE as u32, *ptr) +} + +/// Load one single-element structure to one lane of one register. +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_legacy_const_generics(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr", LANE = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, LANE = 1))] +pub unsafe fn vld1q_lane_p64(ptr: *const p64, src: poly64x2_t) -> poly64x2_t { + static_assert_imm1!(LANE); + simd_insert(src, LANE as u32, *ptr) +} + +/// Load one single-element structure to one lane of one register. +#[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(2)] @@ -812,6 +1116,34 @@ /// Load one single-element structure and Replicate to all lanes (of one register). #[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +pub unsafe fn vld1_dup_p64(ptr: *const p64) -> poly64x1_t { + #[cfg(target_arch = "aarch64")] + { + crate::core_arch::aarch64::vld1_p64(ptr) + } + #[cfg(target_arch = "arm")] + { + crate::core_arch::arm::vld1_p64(ptr) + } +} + +/// Load one single-element structure and Replicate to all lanes (of one register). +#[inline] +#[target_feature(enable = "neon,aes")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_p64(ptr: *const p64) -> poly64x2_t { + let x = vld1q_lane_p64::<0>(ptr, transmute(u64x2::splat(0))); + simd_shuffle2!(x, x, [0, 0]) +} + +/// Load one single-element structure and Replicate to all lanes (of one register). +#[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] @@ -2867,11 +3199,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, IMM5 = 1))] -// Based on the discussion in https://github.com/rust-lang/stdarch/pull/792 -// `mov` seems to be an acceptable intrinsic to compile to -// #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(vmov, IMM5 = 1))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 1))] pub unsafe fn vgetq_lane_u64(v: uint64x2_t) -> u64 { static_assert_imm1!(IMM5); simd_extract(v, IMM5 as u32) @@ -2882,10 +3210,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmov, IMM5 = 0))] -// FIXME: no 32bit this seems to be turned into two vmov.32 instructions -// validate correctness +#[cfg_attr(test, assert_instr(nop, IMM5 = 0))] pub unsafe fn vget_lane_u64(v: uint64x1_t) -> u64 { static_assert!(IMM5 : i32 where IMM5 == 0); simd_extract(v, 0) @@ -2896,8 +3221,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u16", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vget_lane_u16(v: uint16x4_t) -> u16 { static_assert_imm2!(IMM5); simd_extract(v, IMM5 as u32) @@ -2908,8 +3232,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.s16", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vget_lane_s16(v: int16x4_t) -> i16 { static_assert_imm2!(IMM5); simd_extract(v, IMM5 as u32) @@ -2920,8 +3243,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u16", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vget_lane_p16(v: poly16x4_t) -> p16 { static_assert_imm2!(IMM5); simd_extract(v, IMM5 as u32) @@ -2932,8 +3254,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, IMM5 = 1))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 1))] pub unsafe fn vget_lane_u32(v: uint32x2_t) -> u32 { static_assert_imm1!(IMM5); simd_extract(v, IMM5 as u32) @@ -2944,8 +3265,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, IMM5 = 1))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 1))] pub unsafe fn vget_lane_s32(v: int32x2_t) -> i32 { static_assert_imm1!(IMM5); simd_extract(v, IMM5 as u32) @@ -2956,8 +3276,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.f32", IMM5 = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, IMM5 = 1))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 1))] pub unsafe fn vget_lane_f32(v: float32x2_t) -> f32 { static_assert_imm1!(IMM5); simd_extract(v, IMM5 as u32) @@ -2968,8 +3287,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.f32", IMM5 = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, IMM5 = 1))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 1))] pub unsafe fn vgetq_lane_f32(v: float32x4_t) -> f32 { static_assert_imm2!(IMM5); simd_extract(v, IMM5 as u32) @@ -2980,8 +3298,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmov, IMM5 = 0))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 0))] pub unsafe fn vget_lane_p64(v: poly64x1_t) -> p64 { static_assert!(IMM5 : i32 where IMM5 == 0); simd_extract(v, IMM5 as u32) @@ -2992,8 +3309,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmov, IMM5 = 0))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 0))] pub unsafe fn vgetq_lane_p64(v: poly64x2_t) -> p64 { static_assert_imm1!(IMM5); simd_extract(v, IMM5 as u32) @@ -3004,8 +3320,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmov, IMM5 = 0))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 0))] pub unsafe fn vget_lane_s64(v: int64x1_t) -> i64 { static_assert!(IMM5 : i32 where IMM5 == 0); simd_extract(v, IMM5 as u32) @@ -3016,8 +3331,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmov, IMM5 = 0))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 0))] pub unsafe fn vgetq_lane_s64(v: int64x2_t) -> i64 { static_assert_imm1!(IMM5); simd_extract(v, IMM5 as u32) @@ -3028,8 +3342,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u16", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vgetq_lane_u16(v: uint16x8_t) -> u16 { static_assert_imm3!(IMM5); simd_extract(v, IMM5 as u32) @@ -3040,8 +3353,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vgetq_lane_u32(v: uint32x4_t) -> u32 { static_assert_imm2!(IMM5); simd_extract(v, IMM5 as u32) @@ -3052,8 +3364,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.s16", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vgetq_lane_s16(v: int16x8_t) -> i16 { static_assert_imm3!(IMM5); simd_extract(v, IMM5 as u32) @@ -3064,8 +3375,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u16", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vgetq_lane_p16(v: poly16x8_t) -> p16 { static_assert_imm3!(IMM5); simd_extract(v, IMM5 as u32) @@ -3076,8 +3386,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vgetq_lane_s32(v: int32x4_t) -> i32 { static_assert_imm2!(IMM5); simd_extract(v, IMM5 as u32) @@ -3088,8 +3397,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u8", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vget_lane_u8(v: uint8x8_t) -> u8 { static_assert_imm3!(IMM5); simd_extract(v, IMM5 as u32) @@ -3100,8 +3408,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.s8", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vget_lane_s8(v: int8x8_t) -> i8 { static_assert_imm3!(IMM5); simd_extract(v, IMM5 as u32) @@ -3112,8 +3419,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u8", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vget_lane_p8(v: poly8x8_t) -> p8 { static_assert_imm3!(IMM5); simd_extract(v, IMM5 as u32) @@ -3124,8 +3430,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u8", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vgetq_lane_u8(v: uint8x16_t) -> u8 { static_assert_imm4!(IMM5); simd_extract(v, IMM5 as u32) @@ -3136,8 +3441,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.s8", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vgetq_lane_s8(v: int8x16_t) -> i8 { static_assert_imm4!(IMM5); simd_extract(v, IMM5 as u32) @@ -3148,8 +3452,7 @@ #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[rustc_legacy_const_generics(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u8", IMM5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, IMM5 = 2))] +#[cfg_attr(test, assert_instr(nop, IMM5 = 2))] pub unsafe fn vgetq_lane_p8(v: poly8x16_t) -> p8 { static_assert_imm4!(IMM5); simd_extract(v, IMM5 as u32) @@ -3269,8 +3572,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_s8(a: int8x16_t) -> int8x8_t { simd_shuffle8!(a, a, [0, 1, 2, 3, 4, 5, 6, 7]) } @@ -3279,8 +3581,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_s16(a: int16x8_t) -> int16x4_t { simd_shuffle4!(a, a, [0, 1, 2, 3]) } @@ -3289,8 +3590,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_s32(a: int32x4_t) -> int32x2_t { simd_shuffle2!(a, a, [0, 1]) } @@ -3299,8 +3599,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_s64(a: int64x2_t) -> int64x1_t { int64x1_t(simd_extract(a, 0)) } @@ -3309,8 +3608,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_u8(a: uint8x16_t) -> uint8x8_t { simd_shuffle8!(a, a, [0, 1, 2, 3, 4, 5, 6, 7]) } @@ -3319,8 +3617,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_u16(a: uint16x8_t) -> uint16x4_t { simd_shuffle4!(a, a, [0, 1, 2, 3]) } @@ -3329,8 +3626,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_u32(a: uint32x4_t) -> uint32x2_t { simd_shuffle2!(a, a, [0, 1]) } @@ -3339,8 +3635,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_u64(a: uint64x2_t) -> uint64x1_t { uint64x1_t(simd_extract(a, 0)) } @@ -3349,8 +3644,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_p8(a: poly8x16_t) -> poly8x8_t { simd_shuffle8!(a, a, [0, 1, 2, 3, 4, 5, 6, 7]) } @@ -3359,8 +3653,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_p16(a: poly16x8_t) -> poly16x4_t { simd_shuffle4!(a, a, [0, 1, 2, 3]) } @@ -3369,8 +3662,7 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("ldr"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +#[cfg_attr(test, assert_instr(nop))] pub unsafe fn vget_low_f32(a: float32x4_t) -> float32x2_t { simd_shuffle2!(a, a, [0, 1]) } @@ -3495,6 +3787,19 @@ } /// Duplicate vector element to vector or scalar +/// +/// Private vfp4 version used by FMA intriniscs because LLVM does +/// not inline the non-vfp4 version in vfp4 functions. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vdup.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(dup))] +unsafe fn vdupq_n_f32_vfp4(value: f32) -> float32x4_t { + float32x4_t(value, value, value, value) +} + +/// Duplicate vector element to vector or scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3605,6 +3910,19 @@ } /// Duplicate vector element to vector or scalar +/// +/// Private vfp4 version used by FMA intriniscs because LLVM does +/// not inline the non-vfp4 version in vfp4 functions. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vdup.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(dup))] +unsafe fn vdup_n_f32_vfp4(value: f32) -> float32x2_t { + float32x2_t(value, value) +} + +/// Duplicate vector element to vector or scalar #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3828,8 +4146,8 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("str", N = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr("str", N = 0))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("nop", N = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr("nop", N = 0))] #[rustc_legacy_const_generics(2)] pub unsafe fn vext_s64(a: int64x1_t, _b: int64x1_t) -> int64x1_t { if N != 0 { @@ -3842,8 +4160,8 @@ #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("str", N = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr("str", N = 0))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("nop", N = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr("nop", N = 0))] #[rustc_legacy_const_generics(2)] pub unsafe fn vext_u64(a: uint64x1_t, _b: uint64x1_t) -> uint64x1_t { if N != 0 { @@ -4663,6 +4981,24 @@ assert_eq!(r, e) } + #[simd_test(enable = "neon,aes")] + unsafe fn test_vld1_lane_p64() { + let a = u64x1::new(0); + let elem: u64 = 42; + let e = u64x1::new(42); + let r: u64x1 = transmute(vld1_lane_p64::<0>(&elem, transmute(a))); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon,aes")] + unsafe fn test_vld1q_lane_p64() { + let a = u64x2::new(0, 1); + let elem: u64 = 42; + let e = u64x2::new(0, 42); + let r: u64x2 = transmute(vld1q_lane_p64::<1>(&elem, transmute(a))); + assert_eq!(r, e) + } + #[simd_test(enable = "neon")] unsafe fn test_vld1_lane_f32() { let a = f32x2::new(0., 1.); @@ -4847,6 +5183,22 @@ assert_eq!(r, e) } + #[simd_test(enable = "neon,aes")] + unsafe fn test_vld1_dup_p64() { + let elem: u64 = 42; + let e = u64x1::new(42); + let r: u64x1 = transmute(vld1_dup_p64(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon,aes")] + unsafe fn test_vld1q_dup_p64() { + let elem: u64 = 42; + let e = u64x2::new(42, 42); + let r: u64x2 = transmute(vld1q_dup_p64(&elem)); + assert_eq!(r, e) + } + #[simd_test(enable = "neon")] unsafe fn test_vld1_dup_f32() { let elem: f32 = 42.; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/powerpc/vsx.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/powerpc/vsx.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/powerpc/vsx.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/powerpc/vsx.rs 2021-11-29 19:27:28.000000000 +0000 @@ -21,7 +21,7 @@ pub struct vector_signed_long(i64, i64); /// PowerPC-specific 128-bit wide vector of two packed `u64` pub struct vector_unsigned_long(u64, u64); - /// PowerPC-specific 128-bit wide vector mask of two elements + /// PowerPC-specific 128-bit wide vector mask of two `i64` pub struct vector_bool_long(i64, i64); /// PowerPC-specific 128-bit wide vector of two packed `f64` pub struct vector_double(f64, f64); diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/x86/avx512bw.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/x86/avx512bw.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/x86/avx512bw.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/x86/avx512bw.rs 2021-11-29 19:27:28.000000000 +0000 @@ -8013,7 +8013,7 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movepi16_mask&expand=3873) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(mov))] // should be vpmovw2m but msvc does not generate it +#[cfg_attr(test, assert_instr(vpmovw2m))] pub unsafe fn _mm512_movepi16_mask(a: __m512i) -> __mmask32 { let filter = _mm512_set1_epi16(1 << 15); let a = _mm512_and_si512(a, filter); @@ -8025,7 +8025,7 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_movepi16_mask&expand=3872) #[inline] #[target_feature(enable = "avx512bw,avx512vl")] -#[cfg_attr(test, assert_instr(mov))] // should be vpmovw2m but msvc does not generate it +#[cfg_attr(test, assert_instr(vpmovw2m))] pub unsafe fn _mm256_movepi16_mask(a: __m256i) -> __mmask16 { let filter = _mm256_set1_epi16(1 << 15); let a = _mm256_and_si256(a, filter); @@ -8037,7 +8037,7 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movepi16_mask&expand=3871) #[inline] #[target_feature(enable = "avx512bw,avx512vl")] -#[cfg_attr(test, assert_instr(mov))] // should be vpmovw2m but msvc does not generate it +#[cfg_attr(test, assert_instr(vpmovw2m))] pub unsafe fn _mm_movepi16_mask(a: __m128i) -> __mmask8 { let filter = _mm_set1_epi16(1 << 15); let a = _mm_and_si128(a, filter); @@ -8049,7 +8049,7 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movepi8_mask&expand=3883) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(mov))] // should be vpmovb2m but msvc does not generate it +#[cfg_attr(test, assert_instr(vpmovb2m))] pub unsafe fn _mm512_movepi8_mask(a: __m512i) -> __mmask64 { let filter = _mm512_set1_epi8(1 << 7); let a = _mm512_and_si512(a, filter); @@ -8061,7 +8061,8 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_movepi8_mask&expand=3882) #[inline] #[target_feature(enable = "avx512bw,avx512vl")] -#[cfg_attr(test, assert_instr(mov))] // should be vpmovb2m but msvc does not generate it +#[cfg_attr(test, assert_instr(vpmovmskb))] // should be vpmovb2m but compiled to vpmovmskb in the test shim because that takes less cycles than + // using vpmovb2m plus converting the mask register to a standard register. pub unsafe fn _mm256_movepi8_mask(a: __m256i) -> __mmask32 { let filter = _mm256_set1_epi8(1 << 7); let a = _mm256_and_si256(a, filter); @@ -8073,7 +8074,8 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movepi8_mask&expand=3881) #[inline] #[target_feature(enable = "avx512bw,avx512vl")] -#[cfg_attr(test, assert_instr(mov))] // should be vpmovb2m but msvc does not generate it +#[cfg_attr(test, assert_instr(vpmovmskb))] // should be vpmovb2m but compiled to vpmovmskb in the test shim because that takes less cycles than + // using vpmovb2m plus converting the mask register to a standard register. pub unsafe fn _mm_movepi8_mask(a: __m128i) -> __mmask16 { let filter = _mm_set1_epi8(1 << 7); let a = _mm_and_si128(a, filter); @@ -8216,8 +8218,9 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kadd_mask32&expand=3207) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kaddd - //llvm.x86.avx512.kadd.d +#[cfg_attr(all(test, target_arch = "x86"), assert_instr(add))] +#[cfg_attr(all(test, target_arch = "x86_64"), assert_instr(lea))] // generate normal lea/add code instead of kaddd + //llvm.x86.avx512.kadd.d pub unsafe fn _kadd_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { transmute(a + b) } @@ -8227,7 +8230,9 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kadd_mask64&expand=3208) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kaddq +#[cfg_attr(all(test, target_arch = "x86"), assert_instr(add))] +#[cfg_attr(all(test, target_arch = "x86_64"), assert_instr(lea))] // generate normal lea/add code instead of kaddd + //llvm.x86.avx512.kadd.d pub unsafe fn _kadd_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { transmute(a + b) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs 2021-11-29 19:27:28.000000000 +0000 @@ -75,7 +75,7 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_ss&expand=2035) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(mov))] // should be vcvtusi2ss +#[cfg_attr(test, assert_instr(vcvtusi2ss))] pub unsafe fn _mm_cvtu64_ss(a: __m128, b: u64) -> __m128 { let b = b as f32; let r = simd_insert(a, 0, b); @@ -87,7 +87,7 @@ /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_sd&expand=2034) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(mov))] // should be vcvtusi2sd +#[cfg_attr(test, assert_instr(vcvtusi2sd))] pub unsafe fn _mm_cvtu64_sd(a: __m128d, b: u64) -> __m128d { let b = b as f64; let r = simd_insert(a, 0, b); diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/Cargo.toml rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/Cargo.toml 2021-11-29 19:27:28.000000000 +0000 @@ -0,0 +1,16 @@ +[package] +name = "intrinsic-test" +version = "0.1.0" +authors = ["Jamie Cunliffe "] +edition = "2018" + +[dependencies] +lazy_static = "1.4.0" +serde = { version = "1", features = ["derive"] } +csv = "1.1" +clap = "2.33.3" +regex = "1.4.2" +log = "0.4.11" +pretty_env_logger = "0.4.0" +rayon = "1.5.0" +diff = "0.1.12" \ No newline at end of file diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/neon-intrinsics.csv rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/neon-intrinsics.csv --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/neon-intrinsics.csv 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/neon-intrinsics.csv 2021-11-29 19:27:28.000000000 +0000 @@ -0,0 +1,4356 @@ +enabled,name,args,return,comment +FALSE,__crc32b,"a: u32, b: u8",u32,CRC32 checksum +FALSE,__crc32cb,"a: u32, b: u8",u32,CRC32 checksum +TRUE,__crc32cd,"a: u32, b: u64",u32,CRC32 checksum +FALSE,__crc32ch,"a: u32, b: u16",u32,CRC32 checksum +FALSE,__crc32cw,"a: u32, b: u32",u32,CRC32 checksum +TRUE,__crc32d,"a: u32, b: u64",u32,CRC32 checksum +FALSE,__crc32h,"a: u32, b: u16",u32,CRC32 checksum +FALSE,__crc32w,"a: u32, b: u32",u32,CRC32 checksum +TRUE,vaba_s16,"a: int16x4_t, b: int16x4_t, c: int16x4_t",int16x4_t,Signed absolute difference and accumulate +TRUE,vaba_s32,"a: int32x2_t, b: int32x2_t, c: int32x2_t",int32x2_t,Signed absolute difference and accumulate +TRUE,vaba_s8,"a: int8x8_t, b: int8x8_t, c: int8x8_t",int8x8_t,Signed absolute difference and accumulate +TRUE,vaba_u16,"a: uint16x4_t, b: uint16x4_t, c: uint16x4_t",uint16x4_t,Unsigned absolute difference and accumulate +TRUE,vaba_u32,"a: uint32x2_t, b: uint32x2_t, c: uint32x2_t",uint32x2_t,Unsigned absolute difference and accumulate +TRUE,vaba_u8,"a: uint8x8_t, b: uint8x8_t, c: uint8x8_t",uint8x8_t,Unsigned absolute difference and accumulate +TRUE,vabal_high_s16,"a: int32x4_t, b: int16x8_t, c: int16x8_t",int32x4_t,Signed absolute difference and accumulate long +TRUE,vabal_high_s32,"a: int64x2_t, b: int32x4_t, c: int32x4_t",int64x2_t,Signed absolute difference and accumulate long +TRUE,vabal_high_s8,"a: int16x8_t, b: int8x16_t, c: int8x16_t",int16x8_t,Signed absolute difference and accumulate long +TRUE,vabal_high_u16,"a: uint32x4_t, b: uint16x8_t, c: uint16x8_t",uint32x4_t,Unsigned absolute difference and accumulate long +TRUE,vabal_high_u32,"a: uint64x2_t, b: uint32x4_t, c: uint32x4_t",uint64x2_t,Unsigned absolute difference and accumulate long +TRUE,vabal_high_u8,"a: uint16x8_t, b: uint8x16_t, c: uint8x16_t",uint16x8_t,Unsigned absolute difference and accumulate long +TRUE,vabal_s16,"a: int32x4_t, b: int16x4_t, c: int16x4_t",int32x4_t,Signed absolute difference and accumulate long +TRUE,vabal_s32,"a: int64x2_t, b: int32x2_t, c: int32x2_t",int64x2_t,Signed absolute difference and accumulate long +TRUE,vabal_s8,"a: int16x8_t, b: int8x8_t, c: int8x8_t",int16x8_t,Signed absolute difference and accumulate long +TRUE,vabal_u16,"a: uint32x4_t, b: uint16x4_t, c: uint16x4_t",uint32x4_t,Unsigned absolute difference and accumulate long +TRUE,vabal_u32,"a: uint64x2_t, b: uint32x2_t, c: uint32x2_t",uint64x2_t,Unsigned absolute difference and accumulate long +TRUE,vabal_u8,"a: uint16x8_t, b: uint8x8_t, c: uint8x8_t",uint16x8_t,Unsigned absolute difference and accumulate long +TRUE,vabaq_s16,"a: int16x8_t, b: int16x8_t, c: int16x8_t",int16x8_t,Signed absolute difference and accumulate +TRUE,vabaq_s32,"a: int32x4_t, b: int32x4_t, c: int32x4_t",int32x4_t,Signed absolute difference and accumulate +TRUE,vabaq_s8,"a: int8x16_t, b: int8x16_t, c: int8x16_t",int8x16_t,Signed absolute difference and accumulate +TRUE,vabaq_u16,"a: uint16x8_t, b: uint16x8_t, c: uint16x8_t",uint16x8_t,Unsigned absolute difference and accumulate +TRUE,vabaq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,Unsigned absolute difference and accumulate +TRUE,vabaq_u8,"a: uint8x16_t, b: uint8x16_t, c: uint8x16_t",uint8x16_t,Unsigned absolute difference and accumulate +FALSE,vabd_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point absolute difference +TRUE,vabd_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point absolute difference +TRUE,vabd_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point absolute difference +TRUE,vabd_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed absolute difference +TRUE,vabd_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed absolute difference +TRUE,vabd_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed absolute difference +TRUE,vabd_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned absolute difference +TRUE,vabd_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned absolute difference +TRUE,vabd_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned absolute difference +FALSE,vabdd_f64,"a: float64_t, b: float64_t",float64_t,Floating-point absolute difference +FALSE,vabdh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point absolute difference +TRUE,vabdl_high_s16,"a: int16x8_t, b: int16x8_t",int32x4_t,Signed absolute difference long +TRUE,vabdl_high_s32,"a: int32x4_t, b: int32x4_t",int64x2_t,Signed absolute difference long +TRUE,vabdl_high_s8,"a: int8x16_t, b: int8x16_t",int16x8_t,Signed absolute difference long +TRUE,vabdl_high_u16,"a: uint16x8_t, b: uint16x8_t",uint32x4_t,Unsigned absolute difference long +TRUE,vabdl_high_u32,"a: uint32x4_t, b: uint32x4_t",uint64x2_t,Unsigned absolute difference long +TRUE,vabdl_high_u8,"a: uint8x16_t, b: uint8x16_t",uint16x8_t,Unsigned absolute difference long +TRUE,vabdl_s16,"a: int16x4_t, b: int16x4_t",int32x4_t,Signed absolute difference long +TRUE,vabdl_s32,"a: int32x2_t, b: int32x2_t",int64x2_t,Signed absolute difference long +TRUE,vabdl_s8,"a: int8x8_t, b: int8x8_t",int16x8_t,Signed absolute difference long +TRUE,vabdl_u16,"a: uint16x4_t, b: uint16x4_t",uint32x4_t,Unsigned absolute difference long +TRUE,vabdl_u32,"a: uint32x2_t, b: uint32x2_t",uint64x2_t,Unsigned absolute difference long +TRUE,vabdl_u8,"a: uint8x8_t, b: uint8x8_t",uint16x8_t,Unsigned absolute difference long +FALSE,vabdq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point absolute difference +TRUE,vabdq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point absolute difference +TRUE,vabdq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point absolute difference +TRUE,vabdq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed absolute difference +TRUE,vabdq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed absolute difference +TRUE,vabdq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,l +TRUE,vabdq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned absolute difference +TRUE,vabdq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned absolute difference +TRUE,vabdq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned absolute difference +FALSE,vabds_f32,"a: f32, b: f32",f32,Floating-point absolute difference +FALSE,vabs_f16,a: float16x4_t,float16x4_t,Floating-point absolute value +TRUE,vabs_f32,a: float32x2_t,float32x2_t,Floating-point absolute value +TRUE,vabs_f64,a: float64x1_t,float64x1_t,Floating-point absolute value +TRUE,vabs_s16,a: int16x4_t,int16x4_t,Absolute value +TRUE,vabs_s32,a: int32x2_t,int32x2_t,Absolute value +TRUE,vabs_s64,a: int64x1_t,int64x1_t,Absolute value +TRUE,vabs_s8,a: int8x8_t,int8x8_t,Absolute value +TRUE,vabsd_s64,a: i64,i64,Absolute value +FALSE,vabsh_f16,a: float16_t,float16_t,Floating-point absolute value +FALSE,vabsq_f16,a: float16x8_t,float16x8_t,Floating-point absolute value +TRUE,vabsq_f32,a: float32x4_t,float32x4_t,Floating-point absolute value +TRUE,vabsq_f64,a: float64x2_t,float64x2_t,Floating-point absolute value +TRUE,vabsq_s16,a: int16x8_t,int16x8_t,Absolute value +TRUE,vabsq_s32,a: int32x4_t,int32x4_t,Absolute value +TRUE,vabsq_s64,a: int64x2_t,int64x2_t,Absolute value +TRUE,vabsq_s8,a: int8x16_t,int8x16_t,Absolute value +FALSE,vadd_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point add +TRUE,vadd_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point add +TRUE,vadd_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point add +FALSE,vadd_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4_t,Bitwise exclusive OR +FALSE,vadd_p64,"a: poly64x1_t, b: poly64x1_t",poly64x1_t,Bitwise exclusive OR +FALSE,vadd_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8_t,Bitwise exclusive OR +TRUE,vadd_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Add +TRUE,vadd_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Add +TRUE,vadd_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Add +TRUE,vadd_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Add +TRUE,vadd_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Add +TRUE,vadd_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Add +TRUE,vadd_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Add +TRUE,vadd_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Add +TRUE,vaddd_s64,"a: i64, b: i64",i64,Add +TRUE,vaddd_u64,"a: u64, b: u64",u64,Add +FALSE,vaddh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point add +TRUE,vaddhn_high_s16,"r: int8x8_t, a: int16x8_t, b: int16x8_t",int8x16_t,Add returning high narrow +TRUE,vaddhn_high_s32,"r: int16x4_t, a: int32x4_t, b: int32x4_t",int16x8_t,Add returning high narrow +TRUE,vaddhn_high_s64,"r: int32x2_t, a: int64x2_t, b: int64x2_t",int32x4_t,Add returning high narrow +TRUE,vaddhn_high_u16,"r: uint8x8_t, a: uint16x8_t, b: uint16x8_t",uint8x16_t,Add returning high narrow +TRUE,vaddhn_high_u32,"r: uint16x4_t, a: uint32x4_t, b: uint32x4_t",uint16x8_t,Add returning high narrow +TRUE,vaddhn_high_u64,"r: uint32x2_t, a: uint64x2_t, b: uint64x2_t",uint32x4_t,Add returning high narrow +TRUE,vaddhn_s16,"a: int16x8_t, b: int16x8_t",int8x8_t,Add returning high narrow +TRUE,vaddhn_s32,"a: int32x4_t, b: int32x4_t",int16x4_t,Add returning high narrow +TRUE,vaddhn_s64,"a: int64x2_t, b: int64x2_t",int32x2_t,Add returning high narrow +TRUE,vaddhn_u16,"a: uint16x8_t, b: uint16x8_t",uint8x8_t,Add returning high narrow +TRUE,vaddhn_u32,"a: uint32x4_t, b: uint32x4_t",uint16x4_t,Add returning high narrow +TRUE,vaddhn_u64,"a: uint64x2_t, b: uint64x2_t",uint32x2_t,Add returning high narrow +TRUE,vaddl_high_s16,"a: int16x8_t, b: int16x8_t",int32x4_t,Signed add long +TRUE,vaddl_high_s32,"a: int32x4_t, b: int32x4_t",int64x2_t,Signed add long +TRUE,vaddl_high_s8,"a: int8x16_t, b: int8x16_t",int16x8_t,Signed add long +TRUE,vaddl_high_u16,"a: uint16x8_t, b: uint16x8_t",uint32x4_t,Unsigned add long +TRUE,vaddl_high_u32,"a: uint32x4_t, b: uint32x4_t",uint64x2_t,Unsigned add long +TRUE,vaddl_high_u8,"a: uint8x16_t, b: uint8x16_t",uint16x8_t,Unsigned add long +TRUE,vaddl_s16,"a: int16x4_t, b: int16x4_t",int32x4_t,Signed add long +TRUE,vaddl_s32,"a: int32x2_t, b: int32x2_t",int64x2_t,Signed add long +TRUE,vaddl_s8,"a: int8x8_t, b: int8x8_t",int16x8_t,Signed add long +TRUE,vaddl_u16,"a: uint16x4_t, b: uint16x4_t",uint32x4_t,Unsigned add long +TRUE,vaddl_u32,"a: uint32x2_t, b: uint32x2_t",uint64x2_t,Unsigned add long +TRUE,vaddl_u8,"a: uint8x8_t, b: uint8x8_t",uint16x8_t,Unsigned add long +FALSE,vaddlv_s16,a: int16x4_t,i32,Signed add long across vector +FALSE,vaddlv_s32,a: int32x2_t,i64,Signed add long pairwise +FALSE,vaddlv_s8,a: int8x8_t,i16,Signed add long across vector +FALSE,vaddlv_u16,a: uint16x4_t,u32,Unsigned sum long across vector +FALSE,vaddlv_u32,a: uint32x2_t,u64,Unsigned add long pairwise +FALSE,vaddlv_u8,a: uint8x8_t,u16,Unsigned sum long across vector +FALSE,vaddlvq_s16,a: int16x8_t,i32,Signed add long across vector +FALSE,vaddlvq_s32,a: int32x4_t,i64,Signed add long across vector +FALSE,vaddlvq_s8,a: int8x16_t,i16,Signed add long across vector +FALSE,vaddlvq_u16,a: uint16x8_t,u32,Unsigned sum long across vector +FALSE,vaddlvq_u32,a: uint32x4_t,u64,Unsigned sum long across vector +FALSE,vaddlvq_u8,a: uint8x16_t,u16,Unsigned sum long across vector +FALSE,vaddq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point add +TRUE,vaddq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point add +TRUE,vaddq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point add +FALSE,vaddq_p128,"a: poly128_t, b: poly128_t",poly128_t,Bitwise exclusive OR +FALSE,vaddq_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8_t,Bitwise exclusive OR +FALSE,vaddq_p64,"a: poly64x2_t, b: poly64x2_t",poly64x2_t,Bitwise exclusive OR +FALSE,vaddq_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16_t,Bitwise exclusive OR +TRUE,vaddq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Add +TRUE,vaddq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Add +TRUE,vaddq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Add +TRUE,vaddq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Add +TRUE,vaddq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Add +TRUE,vaddq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Add +TRUE,vaddq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Add +TRUE,vaddq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Add +FALSE,vaddv_f32,a: float32x2_t,f32,Floating-point add across vector +TRUE,vaddv_s16,a: int16x4_t,i16,Add across vector +TRUE,vaddv_s32,a: int32x2_t,i32,Add across vector +TRUE,vaddv_s8,a: int8x8_t,i8,Add across vector +TRUE,vaddv_u16,a: uint16x4_t,u16,Add across vector +TRUE,vaddv_u32,a: uint32x2_t,u32,Add across vector +TRUE,vaddv_u8,a: uint8x8_t,u8,Add across vector +FALSE,vaddvq_f32,a: float32x4_t,f32,Floating-point add across vector +FALSE,vaddvq_f64,a: float64x2_t,float64_t,Floating-point add across vector +TRUE,vaddvq_s16,a: int16x8_t,i16,Add across vector +TRUE,vaddvq_s32,a: int32x4_t,i32,Add across vector +TRUE,vaddvq_s64,a: int64x2_t,i64,Add across vector +TRUE,vaddvq_s8,a: int8x16_t,i8,Add across vector +TRUE,vaddvq_u16,a: uint16x8_t,u16,Add across vector +TRUE,vaddvq_u32,a: uint32x4_t,u32,Add across vector +TRUE,vaddvq_u64,a: uint64x2_t,u64,Add across vector +TRUE,vaddvq_u8,a: uint8x16_t,u8,Add across vector +TRUE,vaddw_high_s16,"a: int32x4_t, b: int16x8_t",int32x4_t,Signed add wide +TRUE,vaddw_high_s32,"a: int64x2_t, b: int32x4_t",int64x2_t,Signed add wide +TRUE,vaddw_high_s8,"a: int16x8_t, b: int8x16_t",int16x8_t,Signed add wide +TRUE,vaddw_high_u16,"a: uint32x4_t, b: uint16x8_t",uint32x4_t,Unsigned add wide +TRUE,vaddw_high_u32,"a: uint64x2_t, b: uint32x4_t",uint64x2_t,Unsigned add wide +TRUE,vaddw_high_u8,"a: uint16x8_t, b: uint8x16_t",uint16x8_t,Unsigned add wide +TRUE,vaddw_s16,"a: int32x4_t, b: int16x4_t",int32x4_t,Signed add wide +TRUE,vaddw_s32,"a: int64x2_t, b: int32x2_t",int64x2_t,Signed add wide +TRUE,vaddw_s8,"a: int16x8_t, b: int8x8_t",int16x8_t,Signed add wide +TRUE,vaddw_u16,"a: uint32x4_t, b: uint16x4_t",uint32x4_t,Unsigned add wide +TRUE,vaddw_u32,"a: uint64x2_t, b: uint32x2_t",uint64x2_t,Unsigned add wide +TRUE,vaddw_u8,"a: uint16x8_t, b: uint8x8_t",uint16x8_t,Unsigned add wide +TRUE,vaesdq_u8,"data: uint8x16_t, key: uint8x16_t",uint8x16_t,AES single round decryption +TRUE,vaeseq_u8,"data: uint8x16_t, key: uint8x16_t",uint8x16_t,AES single round encryption +TRUE,vaesimcq_u8,data: uint8x16_t,uint8x16_t,AES inverse mix columns +TRUE,vaesmcq_u8,data: uint8x16_t,uint8x16_t,AES mix columns +TRUE,vand_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Bitwise AND +TRUE,vand_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Bitwise AND +TRUE,vand_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Bitwise AND +TRUE,vand_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Bitwise AND +TRUE,vand_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Bitwise AND +TRUE,vand_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Bitwise AND +TRUE,vand_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Bitwise AND +TRUE,vand_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Bitwise AND +TRUE,vandq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Bitwise AND +TRUE,vandq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Bitwise AND +TRUE,vandq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Bitwise AND +TRUE,vandq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Bitwise AND +TRUE,vandq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Bitwise AND +TRUE,vandq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Bitwise AND +TRUE,vandq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Bitwise AND +TRUE,vandq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Bitwise AND +FALSE,vbcaxq_s16,"a: int16x8_t, b: int16x8_t, c: int16x8_t",int16x8_t,Bit clear and exclusive OR +FALSE,vbcaxq_s32,"a: int32x4_t, b: int32x4_t, c: int32x4_t",int32x4_t,Bit clear and exclusive OR +FALSE,vbcaxq_s64,"a: int64x2_t, b: int64x2_t, c: int64x2_t",int64x2_t,Bit clear and exclusive OR +FALSE,vbcaxq_s8,"a: int8x16_t, b: int8x16_t, c: int8x16_t",int8x16_t,Bit clear and exclusive OR +FALSE,vbcaxq_u16,"a: uint16x8_t, b: uint16x8_t, c: uint16x8_t",uint16x8_t,Bit clear and exclusive OR +FALSE,vbcaxq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,Bit clear and exclusive OR +FALSE,vbcaxq_u64,"a: uint64x2_t, b: uint64x2_t, c: uint64x2_t",uint64x2_t,Bit clear and exclusive OR +FALSE,vbcaxq_u8,"a: uint8x16_t, b: uint8x16_t, c: uint8x16_t",uint8x16_t,Bit clear and exclusive OR +FALSE,vbfdot_f32,"r: float32x2_t, a: bfloat16x4_t, b: bfloat16x4_t",float32x2_t,Bfloat16 floating-point dot product +FALSE,vbfdot_lane_f32,"r: float32x2_t, a: bfloat16x4_t, b: bfloat16x4_t, lane: const int",float32x2_t,Bfloat16 floating-point dot product +FALSE,vbfdot_laneq_f32,"r: float32x2_t, a: bfloat16x4_t, b: bfloat16x8_t, lane: const int",float32x2_t,Bfloat16 floating-point dot product +FALSE,vbfdotq_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x8_t",float32x4_t,Bfloat16 floating-point dot product +FALSE,vbfdotq_lane_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x4_t, lane: const int",float32x4_t,Bfloat16 floating-point dot product +FALSE,vbfdotq_laneq_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x8_t, lane: const int",float32x4_t,Bfloat16 floating-point dot product +FALSE,vbfmlalbq_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x8_t",float32x4_t,Bfloat16 floating-point widening multiply-add long +FALSE,vbfmlalbq_lane_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x4_t, lane: const int",float32x4_t,Bfloat16 floating-point widening multiply-add long +FALSE,vbfmlalbq_laneq_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x8_t, lane: const int",float32x4_t,Bfloat16 floating-point widening multiply-add long +FALSE,vbfmlaltq_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x8_t",float32x4_t,Bfloat16 floating-point widening multiply-add long +FALSE,vbfmlaltq_lane_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x4_t, lane: const int",float32x4_t,Bfloat16 floating-point widening multiply-add long +FALSE,vbfmlaltq_laneq_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x8_t, lane: const int",float32x4_t,Bfloat16 floating-point widening multiply-add long +FALSE,vbfmmlaq_f32,"r: float32x4_t, a: bfloat16x8_t, b: bfloat16x8_t",float32x4_t,Bfloat16 floating-point matrix multiply-accumulate into 2x2 matrix +TRUE,vbic_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbic_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbic_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbic_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbic_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbic_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbic_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbic_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbicq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbicq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbicq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbicq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbicq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbicq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbicq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,"Bitwise bit clear (vector, immediate)" +TRUE,vbicq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,"Bitwise bit clear (vector, immediate)" +FALSE,vbsl_f16,"a: uint16x4_t, b: float16x4_t, c: float16x4_t",float16x4_t,Bitwise select +TRUE,vbsl_f32,"a: uint32x2_t, b: float32x2_t, c: float32x2_t",float32x2_t,Bitwise select +TRUE,vbsl_f64,"a: uint64x1_t, b: float64x1_t, c: float64x1_t",float64x1_t,Bitwise select +TRUE,vbsl_p16,"a: uint16x4_t, b: poly16x4_t, c: poly16x4_t",poly16x4_t,Bitwise select +TRUE,vbsl_p64,"a: poly64x1_t, b: poly64x1_t, c: poly64x1_t",poly64x1_t,Bitwise select +TRUE,vbsl_p8,"a: uint8x8_t, b: poly8x8_t, c: poly8x8_t",poly8x8_t,Bitwise select +TRUE,vbsl_s16,"a: uint16x4_t, b: int16x4_t, c: int16x4_t",int16x4_t,Bitwise select +TRUE,vbsl_s32,"a: uint32x2_t, b: int32x2_t, c: int32x2_t",int32x2_t,Bitwise select +TRUE,vbsl_s64,"a: uint64x1_t, b: int64x1_t, c: int64x1_t",int64x1_t,Bitwise select +TRUE,vbsl_s8,"a: uint8x8_t, b: int8x8_t, c: int8x8_t",int8x8_t,Bitwise select +TRUE,vbsl_u16,"a: uint16x4_t, b: uint16x4_t, c: uint16x4_t",uint16x4_t,Bitwise select +TRUE,vbsl_u32,"a: uint32x2_t, b: uint32x2_t, c: uint32x2_t",uint32x2_t,Bitwise select +TRUE,vbsl_u64,"a: uint64x1_t, b: uint64x1_t, c: uint64x1_t",uint64x1_t,Bitwise select +TRUE,vbsl_u8,"a: uint8x8_t, b: uint8x8_t, c: uint8x8_t",uint8x8_t,Bitwise select +FALSE,vbslq_f16,"a: uint16x8_t, b: float16x8_t, c: float16x8_t",float16x8_t,Bitwise select +TRUE,vbslq_f32,"a: uint32x4_t, b: float32x4_t, c: float32x4_t",float32x4_t,Bitwise select +TRUE,vbslq_f64,"a: uint64x2_t, b: float64x2_t, c: float64x2_t",float64x2_t,Bitwise select +TRUE,vbslq_p16,"a: uint16x8_t, b: poly16x8_t, c: poly16x8_t",poly16x8_t,Bitwise select +TRUE,vbslq_p64,"a: poly64x2_t, b: poly64x2_t, c: poly64x2_t",poly64x2_t,Bitwise select +TRUE,vbslq_p8,"a: uint8x16_t, b: poly8x16_t, c: poly8x16_t",poly8x16_t,Bitwise select +TRUE,vbslq_s16,"a: uint16x8_t, b: int16x8_t, c: int16x8_t",int16x8_t,Bitwise select +TRUE,vbslq_s32,"a: uint32x4_t, b: int32x4_t, c: int32x4_t",int32x4_t,Bitwise select +TRUE,vbslq_s64,"a: uint64x2_t, b: int64x2_t, c: int64x2_t",int64x2_t,Bitwise select +TRUE,vbslq_s8,"a: uint8x16_t, b: int8x16_t, c: int8x16_t",int8x16_t,Bitwise select +TRUE,vbslq_u16,"a: uint16x8_t, b: uint16x8_t, c: uint16x8_t",uint16x8_t,Bitwise select +TRUE,vbslq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,Bitwise select +TRUE,vbslq_u64,"a: uint64x2_t, b: uint64x2_t, c: uint64x2_t",uint64x2_t,Bitwise select +TRUE,vbslq_u8,"a: uint8x16_t, b: uint8x16_t, c: uint8x16_t",uint8x16_t,Bitwise select +FALSE,vcadd_rot270_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point complex add +FALSE,vcadd_rot270_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point complex add +FALSE,vcadd_rot90_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point complex add +FALSE,vcadd_rot90_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point complex add +FALSE,vcaddq_rot270_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point complex add +FALSE,vcaddq_rot270_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point complex add +FALSE,vcaddq_rot270_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point complex add +FALSE,vcaddq_rot90_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point complex add +FALSE,vcaddq_rot90_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point complex add +FALSE,vcaddq_rot90_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point complex add +FALSE,vcage_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point absolute compare greater than or equal +TRUE,vcage_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point absolute compare greater than or equal +TRUE,vcage_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point absolute compare greater than or equal +FALSE,vcaged_f64,"a: float64_t, b: float64_t",u64,Floating-point absolute compare greater than or equal +FALSE,vcageh_f16,"a: float16_t, b: float16_t",u16,Floating-point absolute compare greater than or equal +FALSE,vcageq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point absolute compare greater than or equal +TRUE,vcageq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point absolute compare greater than or equal +TRUE,vcageq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point absolute compare greater than or equal +FALSE,vcages_f32,"a: f32, b: f32",u32,Floating-point absolute compare greater than or equal +FALSE,vcagt_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point absolute compare greater than +TRUE,vcagt_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point absolute compare greater than +TRUE,vcagt_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point absolute compare greater than +FALSE,vcagtd_f64,"a: float64_t, b: float64_t",u64,Floating-point absolute compare greater than +FALSE,vcagth_f16,"a: float16_t, b: float16_t",u16,Floating-point absolute compare greater than +FALSE,vcagtq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point absolute compare greater than +TRUE,vcagtq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point absolute compare greater than +TRUE,vcagtq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point absolute compare greater than +FALSE,vcagts_f32,"a: f32, b: f32",u32,Floating-point absolute compare greater than +FALSE,vcale_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point absolute compare less than or equal +TRUE,vcale_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point absolute compare less than or equal +TRUE,vcale_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point absolute compare less than or equal +FALSE,vcaled_f64,"a: float64_t, b: float64_t",u64,Floating-point absolute compare less than or equal +FALSE,vcaleh_f16,"a: float16_t, b: float16_t",u16,Floating-point absolute compare less than or equal +FALSE,vcaleq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point absolute compare less than or equal +TRUE,vcaleq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point absolute compare less than or equal +TRUE,vcaleq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point absolute compare less than or equal +FALSE,vcales_f32,"a: f32, b: f32",u32,Floating-point absolute compare less than or equal +FALSE,vcalt_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point absolute compare less than +TRUE,vcalt_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point absolute compare less than +TRUE,vcalt_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point absolute compare less than +FALSE,vcaltd_f64,"a: float64_t, b: float64_t",u64,Floating-point absolute compare less than +FALSE,vcalth_f16,"a: float16_t, b: float16_t",u16,Floating-point absolute compare less than +FALSE,vcaltq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point absolute compare less than +TRUE,vcaltq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point absolute compare less than +TRUE,vcaltq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point absolute compare less than +FALSE,vcalts_f32,"a: f32, b: f32",u32,Floating-point absolute compare less than +FALSE,vceq_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point compare equal +TRUE,vceq_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point compare equal +TRUE,vceq_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point compare equal +TRUE,vceq_p64,"a: poly64x1_t, b: poly64x1_t",uint64x1_t,Compare bitwise equal +FALSE,vceq_p8,"a: poly8x8_t, b: poly8x8_t",uint8x8_t,Compare bitwise equal +TRUE,vceq_s16,"a: int16x4_t, b: int16x4_t",uint16x4_t,Compare bitwise equal +TRUE,vceq_s32,"a: int32x2_t, b: int32x2_t",uint32x2_t,Compare bitwise equal +TRUE,vceq_s64,"a: int64x1_t, b: int64x1_t",uint64x1_t,Compare bitwise equal +TRUE,vceq_s8,"a: int8x8_t, b: int8x8_t",uint8x8_t,Compare bitwise equal +TRUE,vceq_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Compare bitwise equal +TRUE,vceq_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Compare bitwise equal +TRUE,vceq_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Compare bitwise equal +TRUE,vceq_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Compare bitwise equal +FALSE,vceqd_f64,"a: float64_t, b: float64_t",u64,Floating-point compare equal +FALSE,vceqd_s64,"a: i64, b: i64",u64,Compare bitwise equal +FALSE,vceqd_u64,"a: u64, b: u64",u64,Compare bitwise equal +FALSE,vceqh_f16,"a: float16_t, b: float16_t",u16,Floating-point compare equal +FALSE,vceqq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point compare equal +TRUE,vceqq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point compare equal +TRUE,vceqq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point compare equal +TRUE,vceqq_p64,"a: poly64x2_t, b: poly64x2_t",uint64x2_t,Compare bitwise equal +TRUE,vceqq_p8,"a: poly8x16_t, b: poly8x16_t",uint8x16_t,Compare bitwise equal +TRUE,vceqq_s16,"a: int16x8_t, b: int16x8_t",uint16x8_t,Compare bitwise equal +TRUE,vceqq_s32,"a: int32x4_t, b: int32x4_t",uint32x4_t,Compare bitwise equal +TRUE,vceqq_s64,"a: int64x2_t, b: int64x2_t",uint64x2_t,Compare bitwise equal +TRUE,vceqq_s8,"a: int8x16_t, b: int8x16_t",uint8x16_t,Compare bitwise equal +TRUE,vceqq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Compare bitwise equal +TRUE,vceqq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Compare bitwise equal +TRUE,vceqq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Compare bitwise equal +TRUE,vceqq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Compare bitwise equal +FALSE,vceqs_f32,"a: f32, b: f32",u32,Floating-point compare equal +FALSE,vceqz_f16,a: float16x4_t,uint16x4_t,Floating-point compare equal to zero +TRUE,vceqz_f32,a: float32x2_t,uint32x2_t,Floating-point compare equal to zero +TRUE,vceqz_f64,a: float64x1_t,uint64x1_t,Floating-point compare equal to zero +TRUE,vceqz_p64,a: poly64x1_t,uint64x1_t,Compare bitwise equal to zero +TRUE,vceqz_p8,a: poly8x8_t,uint8x8_t,Compare bitwise equal to zero +TRUE,vceqz_s16,a: int16x4_t,uint16x4_t,Compare bitwise equal to zero +TRUE,vceqz_s32,a: int32x2_t,uint32x2_t,Compare bitwise equal to zero +TRUE,vceqz_s64,a: int64x1_t,uint64x1_t,Compare bitwise equal to zero +TRUE,vceqz_s8,a: int8x8_t,uint8x8_t,Compare bitwise equal to zero +TRUE,vceqz_u16,a: uint16x4_t,uint16x4_t,Compare bitwise equal to zero +TRUE,vceqz_u32,a: uint32x2_t,uint32x2_t,Compare bitwise equal to zero +TRUE,vceqz_u64,a: uint64x1_t,uint64x1_t,Compare bitwise equal to zero +TRUE,vceqz_u8,a: uint8x8_t,uint8x8_t,Compare bitwise equal to zero +FALSE,vceqzd_f64,a: float64_t,u64,Floating-point compare equal to zero +FALSE,vceqzd_s64,a: i64,u64,Compare bitwise equal to zero +FALSE,vceqzd_u64,a: u64,u64,Compare bitwise equal to zero +FALSE,vceqzh_f16,a: float16_t,u16,Floating-point compare equal to zero +FALSE,vceqzq_f16,a: float16x8_t,uint16x8_t,Floating-point compare equal to zero +TRUE,vceqzq_f32,a: float32x4_t,uint32x4_t,Floating-point compare equal to zero +TRUE,vceqzq_f64,a: float64x2_t,uint64x2_t,Floating-point compare equal to zero +TRUE,vceqzq_p64,a: poly64x2_t,uint64x2_t,Compare bitwise equal to zero +TRUE,vceqzq_p8,a: poly8x16_t,uint8x16_t,Compare bitwise equal to zero +TRUE,vceqzq_s16,a: int16x8_t,uint16x8_t,Compare bitwise equal to zero +TRUE,vceqzq_s32,a: int32x4_t,uint32x4_t,Compare bitwise equal to zero +TRUE,vceqzq_s64,a: int64x2_t,uint64x2_t,Compare bitwise equal to zero +TRUE,vceqzq_s8,a: int8x16_t,uint8x16_t,Compare bitwise equal to zero +TRUE,vceqzq_u16,a: uint16x8_t,uint16x8_t,Compare bitwise equal to zero +TRUE,vceqzq_u32,a: uint32x4_t,uint32x4_t,Compare bitwise equal to zero +TRUE,vceqzq_u64,a: uint64x2_t,uint64x2_t,Compare bitwise equal to zero +TRUE,vceqzq_u8,a: uint8x16_t,uint8x16_t,Compare bitwise equal to zero +FALSE,vceqzs_f32,a: f32,u32,Floating-point compare equal to zero +FALSE,vcge_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point compare greater than or equal +TRUE,vcge_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point compare greater than or equal +TRUE,vcge_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point compare greater than or equal +TRUE,vcge_s16,"a: int16x4_t, b: int16x4_t",uint16x4_t,Compare signed greater than or equal +TRUE,vcge_s32,"a: int32x2_t, b: int32x2_t",uint32x2_t,Compare signed greater than or equal +TRUE,vcge_s64,"a: int64x1_t, b: int64x1_t",uint64x1_t,Compare signed greater than or equal +TRUE,vcge_s8,"a: int8x8_t, b: int8x8_t",uint8x8_t,Compare signed greater than or equal +TRUE,vcge_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Compare unsigned higher or same +TRUE,vcge_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Compare unsigned higher or same +TRUE,vcge_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Compare unsigned higher or same +TRUE,vcge_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Compare unsigned higher or same +FALSE,vcged_f64,"a: float64_t, b: float64_t",u64,Floating-point compare greater than or equal +FALSE,vcged_s64,"a: i64, b: i64",u64,Compare signed greater than or equal +FALSE,vcged_u64,"a: u64, b: u64",u64,Compare unsigned higher or same +FALSE,vcgeh_f16,"a: float16_t, b: float16_t",u16,Floating-point compare greater than or equal +FALSE,vcgeq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point compare greater than or equal +TRUE,vcgeq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point compare greater than or equal +TRUE,vcgeq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point compare greater than or equal +TRUE,vcgeq_s16,"a: int16x8_t, b: int16x8_t",uint16x8_t,Compare signed greater than or equal +TRUE,vcgeq_s32,"a: int32x4_t, b: int32x4_t",uint32x4_t,Compare signed greater than or equal +TRUE,vcgeq_s64,"a: int64x2_t, b: int64x2_t",uint64x2_t,Compare signed greater than or equal +TRUE,vcgeq_s8,"a: int8x16_t, b: int8x16_t",uint8x16_t,Compare signed greater than or equal +TRUE,vcgeq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Compare unsigned higher or same +TRUE,vcgeq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Compare unsigned higher or same +TRUE,vcgeq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Compare unsigned higher or same +TRUE,vcgeq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Compare unsigned higher or same +FALSE,vcges_f32,"a: f32, b: f32",u32,Floating-point compare greater than or equal +FALSE,vcgez_f16,a: float16x4_t,uint16x4_t,Floating-point compare greater than or equal to zero +TRUE,vcgez_f32,a: float32x2_t,uint32x2_t,Floating-point compare greater than or equal to zero +TRUE,vcgez_f64,a: float64x1_t,uint64x1_t,Floating-point compare greater than or equal to zero +TRUE,vcgez_s16,a: int16x4_t,uint16x4_t,Compare signed greater than or equal to zero +TRUE,vcgez_s32,a: int32x2_t,uint32x2_t,Compare signed greater than or equal to zero +TRUE,vcgez_s64,a: int64x1_t,uint64x1_t,Compare signed greater than or equal to zero +TRUE,vcgez_s8,a: int8x8_t,uint8x8_t,Compare signed greater than or equal to zero +FALSE,vcgezd_f64,a: float64_t,u64,Floating-point compare greater than or equal to zero +FALSE,vcgezd_s64,a: i64,u64,Compare signed greater than or equal to zero +FALSE,vcgezh_f16,a: float16_t,u16,Floating-point compare greater than or equal to zero +FALSE,vcgezq_f16,a: float16x8_t,uint16x8_t,Floating-point compare greater than or equal to zero +TRUE,vcgezq_f32,a: float32x4_t,uint32x4_t,Floating-point compare greater than or equal to zero +TRUE,vcgezq_f64,a: float64x2_t,uint64x2_t,Floating-point compare greater than or equal to zero +TRUE,vcgezq_s16,a: int16x8_t,uint16x8_t,Compare signed greater than or equal to zero +TRUE,vcgezq_s32,a: int32x4_t,uint32x4_t,Compare signed greater than or equal to zero +TRUE,vcgezq_s64,a: int64x2_t,uint64x2_t,Compare signed greater than or equal to zero +TRUE,vcgezq_s8,a: int8x16_t,uint8x16_t,Compare signed greater than or equal to zero +FALSE,vcgezs_f32,a: f32,u32,Floating-point compare greater than or equal to zero +FALSE,vcgt_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point compare greater than +TRUE,vcgt_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point compare greater than +TRUE,vcgt_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point compare greater than +TRUE,vcgt_s16,"a: int16x4_t, b: int16x4_t",uint16x4_t,Compare signed greater than +TRUE,vcgt_s32,"a: int32x2_t, b: int32x2_t",uint32x2_t,Compare signed greater than +TRUE,vcgt_s64,"a: int64x1_t, b: int64x1_t",uint64x1_t,Compare signed greater than +TRUE,vcgt_s8,"a: int8x8_t, b: int8x8_t",uint8x8_t,Compare signed greater than +TRUE,vcgt_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Compare unsigned higher +TRUE,vcgt_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Compare unsigned higher +TRUE,vcgt_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Compare unsigned higher +TRUE,vcgt_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Compare unsigned higher +FALSE,vcgtd_f64,"a: float64_t, b: float64_t",u64,Floating-point compare greater than +FALSE,vcgtd_s64,"a: i64, b: i64",u64,Compare signed greater than +FALSE,vcgtd_u64,"a: u64, b: u64",u64,Compare unsigned higher +FALSE,vcgth_f16,"a: float16_t, b: float16_t",u16,Floating-point compare greater than +FALSE,vcgtq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point compare greater than +TRUE,vcgtq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point compare greater than +TRUE,vcgtq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point compare greater than +TRUE,vcgtq_s16,"a: int16x8_t, b: int16x8_t",uint16x8_t,Compare signed greater than +TRUE,vcgtq_s32,"a: int32x4_t, b: int32x4_t",uint32x4_t,Compare signed greater than +TRUE,vcgtq_s64,"a: int64x2_t, b: int64x2_t",uint64x2_t,Compare signed greater than +TRUE,vcgtq_s8,"a: int8x16_t, b: int8x16_t",uint8x16_t,Compare signed greater than +TRUE,vcgtq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Compare unsigned higher +TRUE,vcgtq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Compare unsigned higher +TRUE,vcgtq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Compare unsigned higher +TRUE,vcgtq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Compare unsigned higher +FALSE,vcgts_f32,"a: f32, b: f32",u32,Floating-point compare greater than +FALSE,vcgtz_f16,a: float16x4_t,uint16x4_t,Floating-point compare greater than zero +TRUE,vcgtz_f32,a: float32x2_t,uint32x2_t,Floating-point compare greater than zero +TRUE,vcgtz_f64,a: float64x1_t,uint64x1_t,Floating-point compare greater than zero +TRUE,vcgtz_s16,a: int16x4_t,uint16x4_t,Compare signed greater than zero +TRUE,vcgtz_s32,a: int32x2_t,uint32x2_t,Compare signed greater than zero +TRUE,vcgtz_s64,a: int64x1_t,uint64x1_t,Compare signed greater than zero +TRUE,vcgtz_s8,a: int8x8_t,uint8x8_t,Compare signed greater than zero +FALSE,vcgtzd_f64,a: float64_t,u64,Floating-point compare greater than zero +FALSE,vcgtzd_s64,a: i64,u64,Compare signed greater than zero +FALSE,vcgtzh_f16,a: float16_t,u16,Floating-point compare greater than zero +FALSE,vcgtzq_f16,a: float16x8_t,uint16x8_t,Floating-point compare greater than zero +TRUE,vcgtzq_f32,a: float32x4_t,uint32x4_t,Floating-point compare greater than zero +TRUE,vcgtzq_f64,a: float64x2_t,uint64x2_t,Floating-point compare greater than zero +TRUE,vcgtzq_s16,a: int16x8_t,uint16x8_t,Compare signed greater than zero +TRUE,vcgtzq_s32,a: int32x4_t,uint32x4_t,Compare signed greater than zero +TRUE,vcgtzq_s64,a: int64x2_t,uint64x2_t,Compare signed greater than zero +TRUE,vcgtzq_s8,a: int8x16_t,uint8x16_t,Compare signed greater than zero +FALSE,vcgtzs_f32,a: f32,u32,Floating-point compare greater than zero +FALSE,vcle_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point compare less than or equal +TRUE,vcle_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point compare less than or equal +TRUE,vcle_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point compare less than or equal +TRUE,vcle_s16,"a: int16x4_t, b: int16x4_t",uint16x4_t,Compare signed less than or equal +TRUE,vcle_s32,"a: int32x2_t, b: int32x2_t",uint32x2_t,Compare signed less than or equal +TRUE,vcle_s64,"a: int64x1_t, b: int64x1_t",uint64x1_t,Compare signed less than or equal +TRUE,vcle_s8,"a: int8x8_t, b: int8x8_t",uint8x8_t,Compare signed less than or equal +TRUE,vcle_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Compare unsigned less than or equal +TRUE,vcle_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Compare unsigned less than or equal +TRUE,vcle_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Compare unsigned less than or equal +TRUE,vcle_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Compare unsigned less than or equal +FALSE,vcled_f64,"a: float64_t, b: float64_t",u64,Floating-point compare less than or equal +FALSE,vcled_s64,"a: i64, b: i64",u64,Compare signed less than or equal +FALSE,vcled_u64,"a: u64, b: u64",u64,Compare unsigned less than or equal +FALSE,vcleh_f16,"a: float16_t, b: float16_t",u16,Floating-point compare less than or equal +FALSE,vcleq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point compare less than or equal +TRUE,vcleq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point compare less than or equal +TRUE,vcleq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point compare less than or equal +TRUE,vcleq_s16,"a: int16x8_t, b: int16x8_t",uint16x8_t,Compare signed less than or equal +TRUE,vcleq_s32,"a: int32x4_t, b: int32x4_t",uint32x4_t,Compare signed less than or equal +TRUE,vcleq_s64,"a: int64x2_t, b: int64x2_t",uint64x2_t,Compare signed less than or equal +TRUE,vcleq_s8,"a: int8x16_t, b: int8x16_t",uint8x16_t,Compare signed less than or equal +TRUE,vcleq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Compare unsigned less than or equal +TRUE,vcleq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Compare unsigned less than or equal +TRUE,vcleq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Compare unsigned less than or equal +TRUE,vcleq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Compare unsigned less than or equal +FALSE,vcles_f32,"a: f32, b: f32",u32,Floating-point compare less than or equal +FALSE,vclez_f16,a: float16x4_t,uint16x4_t,Floating-point compare less than or equal to zero +TRUE,vclez_f32,a: float32x2_t,uint32x2_t,Floating-point compare less than or equal to zero +TRUE,vclez_f64,a: float64x1_t,uint64x1_t,Floating-point compare less than or equal to zero +TRUE,vclez_s16,a: int16x4_t,uint16x4_t,Compare signed less than or equal to zero +TRUE,vclez_s32,a: int32x2_t,uint32x2_t,Compare signed less than or equal to zero +TRUE,vclez_s64,a: int64x1_t,uint64x1_t,Compare signed less than or equal to zero +TRUE,vclez_s8,a: int8x8_t,uint8x8_t,Compare signed less than or equal to zero +FALSE,vclezd_f64,a: float64_t,u64,Floating-point compare less than or equal to zero +FALSE,vclezd_s64,a: i64,u64,Compare signed less than or equal to zero +FALSE,vclezh_f16,a: float16_t,u16,Floating-point compare less than or equal to zero +FALSE,vclezq_f16,a: float16x8_t,uint16x8_t,Floating-point compare less than or equal to zero +TRUE,vclezq_f32,a: float32x4_t,uint32x4_t,Floating-point compare less than or equal to zero +TRUE,vclezq_f64,a: float64x2_t,uint64x2_t,Floating-point compare less than or equal to zero +TRUE,vclezq_s16,a: int16x8_t,uint16x8_t,Compare signed less than or equal to zero +TRUE,vclezq_s32,a: int32x4_t,uint32x4_t,Compare signed less than or equal to zero +TRUE,vclezq_s64,a: int64x2_t,uint64x2_t,Compare signed less than or equal to zero +TRUE,vclezq_s8,a: int8x16_t,uint8x16_t,Compare signed less than or equal to zero +FALSE,vclezs_f32,a: f32,u32,Floating-point compare less than or equal to zero +TRUE,vcls_s16,a: int16x4_t,int16x4_t,Count leading sign bits +TRUE,vcls_s32,a: int32x2_t,int32x2_t,Count leading sign bits +TRUE,vcls_s8,a: int8x8_t,int8x8_t,Count leading sign bits +TRUE,vclsq_s16,a: int16x8_t,int16x8_t,Count leading sign bits +TRUE,vclsq_s32,a: int32x4_t,int32x4_t,Count leading sign bits +TRUE,vclsq_s8,a: int8x16_t,int8x16_t,Count leading sign bits +FALSE,vclt_f16,"a: float16x4_t, b: float16x4_t",uint16x4_t,Floating-point compare less than +TRUE,vclt_f32,"a: float32x2_t, b: float32x2_t",uint32x2_t,Floating-point compare less than +TRUE,vclt_f64,"a: float64x1_t, b: float64x1_t",uint64x1_t,Floating-point compare less than +TRUE,vclt_s16,"a: int16x4_t, b: int16x4_t",uint16x4_t,Compare signed less than +TRUE,vclt_s32,"a: int32x2_t, b: int32x2_t",uint32x2_t,Compare signed less than +TRUE,vclt_s64,"a: int64x1_t, b: int64x1_t",uint64x1_t,Compare signed less than +TRUE,vclt_s8,"a: int8x8_t, b: int8x8_t",uint8x8_t,Compare signed less than +TRUE,vclt_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Compare unsigned less than +TRUE,vclt_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Compare unsigned less than +TRUE,vclt_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Compare unsigned less than +TRUE,vclt_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Compare unsigned less than +FALSE,vcltd_f64,"a: float64_t, b: float64_t",u64,Floating-point compare less than +FALSE,vcltd_s64,"a: i64, b: i64",u64,Compare signed less than +FALSE,vcltd_u64,"a: u64, b: u64",u64,Compare unsigned less than +FALSE,vclth_f16,"a: float16_t, b: float16_t",u16,Floating-point compare less than +FALSE,vcltq_f16,"a: float16x8_t, b: float16x8_t",uint16x8_t,Floating-point compare less than +TRUE,vcltq_f32,"a: float32x4_t, b: float32x4_t",uint32x4_t,Floating-point compare less than +TRUE,vcltq_f64,"a: float64x2_t, b: float64x2_t",uint64x2_t,Floating-point compare less than +TRUE,vcltq_s16,"a: int16x8_t, b: int16x8_t",uint16x8_t,Compare signed less than +TRUE,vcltq_s32,"a: int32x4_t, b: int32x4_t",uint32x4_t,Compare signed less than +TRUE,vcltq_s64,"a: int64x2_t, b: int64x2_t",uint64x2_t,Compare signed less than +TRUE,vcltq_s8,"a: int8x16_t, b: int8x16_t",uint8x16_t,Compare signed less than +TRUE,vcltq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Compare unsigned less than +TRUE,vcltq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Compare unsigned less than +TRUE,vcltq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Compare unsigned less than +TRUE,vcltq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Compare unsigned less than +FALSE,vclts_f32,"a: f32, b: f32",u32,Floating-point compare less than +FALSE,vcltz_f16,a: float16x4_t,uint16x4_t,Floating-point compare less than zero +TRUE,vcltz_f32,a: float32x2_t,uint32x2_t,Floating-point compare less than zero +TRUE,vcltz_f64,a: float64x1_t,uint64x1_t,Floating-point compare less than zero +TRUE,vcltz_s16,a: int16x4_t,uint16x4_t,Compare signed less than zero +TRUE,vcltz_s32,a: int32x2_t,uint32x2_t,Compare signed less than zero +TRUE,vcltz_s64,a: int64x1_t,uint64x1_t,Compare signed less than zero +TRUE,vcltz_s8,a: int8x8_t,uint8x8_t,Compare signed less than zero +FALSE,vcltzd_f64,a: float64_t,u64,Floating-point compare less than zero +FALSE,vcltzd_s64,a: i64,u64,Compare signed less than zero +FALSE,vcltzh_f16,a: float16_t,u16,Floating-point compare less than zero +FALSE,vcltzq_f16,a: float16x8_t,uint16x8_t,Floating-point compare less than zero +TRUE,vcltzq_f32,a: float32x4_t,uint32x4_t,Floating-point compare less than zero +TRUE,vcltzq_f64,a: float64x2_t,uint64x2_t,Floating-point compare less than zero +TRUE,vcltzq_s16,a: int16x8_t,uint16x8_t,Compare signed less than zero +TRUE,vcltzq_s32,a: int32x4_t,uint32x4_t,Compare signed less than zero +TRUE,vcltzq_s64,a: int64x2_t,uint64x2_t,Compare signed less than zero +TRUE,vcltzq_s8,a: int8x16_t,uint8x16_t,Compare signed less than zero +FALSE,vcltzs_f32,a: f32,u32,Floating-point compare less than zero +TRUE,vclz_s16,a: int16x4_t,int16x4_t,Count leading zero bits +TRUE,vclz_s32,a: int32x2_t,int32x2_t,Count leading zero bits +TRUE,vclz_s8,a: int8x8_t,int8x8_t,Count leading zero bits +TRUE,vclz_u16,a: uint16x4_t,uint16x4_t,Count leading zero bits +TRUE,vclz_u32,a: uint32x2_t,uint32x2_t,Count leading zero bits +TRUE,vclz_u8,a: uint8x8_t,uint8x8_t,Count leading zero bits +TRUE,vclzq_s16,a: int16x8_t,int16x8_t,Count leading zero bits +TRUE,vclzq_s32,a: int32x4_t,int32x4_t,Count leading zero bits +TRUE,vclzq_s8,a: int8x16_t,int8x16_t,Count leading zero bits +TRUE,vclzq_u16,a: uint16x8_t,uint16x8_t,Count leading zero bits +TRUE,vclzq_u32,a: uint32x4_t,uint32x4_t,Count leading zero bits +TRUE,vclzq_u8,a: uint8x16_t,uint8x16_t,Count leading zero bits +FALSE,vcmla_f16,"r: float16x4_t, a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_f32,"r: float32x2_t, a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_lane_f16,"r: float16x4_t, a: float16x4_t, b: float16x4_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_lane_f32,"r: float32x2_t, a: float32x2_t, b: float32x2_t, lane: const int",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_laneq_f16,"r: float16x4_t, a: float16x4_t, b: float16x8_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_laneq_f16,"r: float16x4_t, a: float16x4_t, b: float16x8_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_laneq_f32,"r: float32x2_t, a: float32x2_t, b: float32x4_t, lane: const int",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot180_f16,"r: float16x4_t, a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot180_f32,"r: float32x2_t, a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot180_lane_f16,"r: float16x4_t, a: float16x4_t, b: float16x4_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot180_lane_f32,"r: float32x2_t, a: float32x2_t, b: float32x2_t, lane: const int",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot180_laneq_f16,"r: float16x4_t, a: float16x4_t, b: float16x8_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot180_laneq_f16,"r: float16x4_t, a: float16x4_t, b: float16x8_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot180_laneq_f32,"r: float32x2_t, a: float32x2_t, b: float32x4_t, lane: const int",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot270_f16,"r: float16x4_t, a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot270_f32,"r: float32x2_t, a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot270_lane_f16,"r: float16x4_t, a: float16x4_t, b: float16x4_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot270_lane_f32,"r: float32x2_t, a: float32x2_t, b: float32x2_t, lane: const int",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot270_laneq_f16,"r: float16x4_t, a: float16x4_t, b: float16x8_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot270_laneq_f16,"r: float16x4_t, a: float16x4_t, b: float16x8_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot270_laneq_f32,"r: float32x2_t, a: float32x2_t, b: float32x4_t, lane: const int",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot90_f16,"r: float16x4_t, a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot90_f32,"r: float32x2_t, a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot90_lane_f16,"r: float16x4_t, a: float16x4_t, b: float16x4_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot90_lane_f32,"r: float32x2_t, a: float32x2_t, b: float32x2_t, lane: const int",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot90_laneq_f16,"r: float16x4_t, a: float16x4_t, b: float16x8_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot90_laneq_f16,"r: float16x4_t, a: float16x4_t, b: float16x8_t, lane: const int",float16x4_t,Floating-point complex multiply accumulate +FALSE,vcmla_rot90_laneq_f32,"r: float32x2_t, a: float32x2_t, b: float32x4_t, lane: const int",float32x2_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_f16,"r: float16x8_t, a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_f32,"r: float32x4_t, a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_f64,"r: float64x2_t, a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_lane_f16,"r: float16x8_t, a: float16x8_t, b: float16x4_t, lane: const int",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_lane_f32,"r: float32x4_t, a: float32x4_t, b: float32x2_t, lane: const int",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_laneq_f16,"r: float16x8_t, a: float16x8_t, b: float16x8_t, lane: const int",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_laneq_f32,"r: float32x4_t, a: float32x4_t, b: float32x4_t, lane: const int",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot180_f16,"r: float16x8_t, a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot180_f32,"r: float32x4_t, a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot180_f64,"r: float64x2_t, a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot180_lane_f16,"r: float16x8_t, a: float16x8_t, b: float16x4_t, lane: const int",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot180_lane_f32,"r: float32x4_t, a: float32x4_t, b: float32x2_t, lane: const int",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot180_laneq_f16,"r: float16x8_t, a: float16x8_t, b: float16x8_t, lane: const int",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot180_laneq_f32,"r: float32x4_t, a: float32x4_t, b: float32x4_t, lane: const int",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot270_f16,"r: float16x8_t, a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot270_f32,"r: float32x4_t, a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot270_f64,"r: float64x2_t, a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot270_lane_f16,"r: float16x8_t, a: float16x8_t, b: float16x4_t, lane: const int",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot270_lane_f32,"r: float32x4_t, a: float32x4_t, b: float32x2_t, lane: const int",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot270_laneq_f16,"r: float16x8_t, a: float16x8_t, b: float16x8_t, lane: const int",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot270_laneq_f32,"r: float32x4_t, a: float32x4_t, b: float32x4_t, lane: const int",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot90_f16,"r: float16x8_t, a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot90_f32,"r: float32x4_t, a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot90_f64,"r: float64x2_t, a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot90_lane_f16,"r: float16x8_t, a: float16x8_t, b: float16x4_t, lane: const int",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot90_lane_f32,"r: float32x4_t, a: float32x4_t, b: float32x2_t, lane: const int",float32x4_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot90_laneq_f16,"r: float16x8_t, a: float16x8_t, b: float16x8_t, lane: const int",float16x8_t,Floating-point complex multiply accumulate +FALSE,vcmlaq_rot90_laneq_f32,"r: float32x4_t, a: float32x4_t, b: float32x4_t, lane: const int",float32x4_t,Floating-point complex multiply accumulate +TRUE,vcnt_p8,a: poly8x8_t,poly8x8_t,Population count per byte +TRUE,vcnt_s8,a: int8x8_t,int8x8_t,Population count per byte +TRUE,vcnt_u8,a: uint8x8_t,uint8x8_t,Population count per byte +TRUE,vcntq_p8,a: poly8x16_t,poly8x16_t,Population count per byte +TRUE,vcntq_s8,a: int8x16_t,int8x16_t,Population count per byte +TRUE,vcntq_u8,a: uint8x16_t,uint8x16_t,Population count per byte +FALSE,vcombine_bf16,"low: bfloat16x4_t, high: bfloat16x4_t",bfloat16x8_t,Insert vector element from another vector element +FALSE,vcombine_f16,"low: float16x4_t, high: float16x4_t",float16x8_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_f32,"low: float32x2_t, high: float32x2_t",float32x4_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_f64,"low: float64x1_t, high: float64x1_t",float64x2_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_p16,"low: poly16x4_t, high: poly16x4_t",poly16x8_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_p64,"low: poly64x1_t, high: poly64x1_t",poly64x2_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_p8,"low: poly8x8_t, high: poly8x8_t",poly8x16_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_s16,"low: int16x4_t, high: int16x4_t",int16x8_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_s32,"low: int32x2_t, high: int32x2_t",int32x4_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_s64,"low: int64x1_t, high: int64x1_t",int64x2_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_s8,"low: int8x8_t, high: int8x8_t",int8x16_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_u16,"low: uint16x4_t, high: uint16x4_t",uint16x8_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_u32,"low: uint32x2_t, high: uint32x2_t",uint32x4_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_u64,"low: uint64x1_t, high: uint64x1_t",uint64x2_t,Join two smaller vectors into a single larger vector +TRUE,vcombine_u8,"low: uint8x8_t, high: uint8x8_t",uint8x16_t,Join two smaller vectors into a single larger vector +FALSE,vcopy_lane_bf16,"a: bfloat16x4_t, lane1: const int, b: bfloat16x4_t, lane2: const int",bfloat16x4_t,Insert vector element from another vector element +FALSE,vcopy_lane_f32,"a: float32x2_t, lane1: const int, b: float32x2_t, lane2: const int",float32x2_t,Insert vector element from another vector element +FALSE,vcopy_lane_f64,"a: float64x1_t, lane1: const int, b: float64x1_t, lane2: const int",float64x1_t,Duplicate vector element to vector or scalar +FALSE,vcopy_lane_p16,"a: poly16x4_t, lane1: const int, b: poly16x4_t, lane2: const int",poly16x4_t,Insert vector element from another vector element +FALSE,vcopy_lane_p64,"a: poly64x1_t, lane1: const int, b: poly64x1_t, lane2: const int",poly64x1_t,Duplicate vector element to vector or scalar +FALSE,vcopy_lane_p8,"a: poly8x8_t, lane1: const int, b: poly8x8_t, lane2: const int",poly8x8_t,Insert vector element from another vector element +FALSE,vcopy_lane_s16,"a: int16x4_t, lane1: const int, b: int16x4_t, lane2: const int",int16x4_t,Insert vector element from another vector element +FALSE,vcopy_lane_s32,"a: int32x2_t, lane1: const int, b: int32x2_t, lane2: const int",int32x2_t,Insert vector element from another vector element +FALSE,vcopy_lane_s64,"a: int64x1_t, lane1: const int, b: int64x1_t, lane2: const int",int64x1_t,Duplicate vector element to vector or scalar +FALSE,vcopy_lane_s8,"a: int8x8_t, lane1: const int, b: int8x8_t, lane2: const int",int8x8_t,Insert vector element from another vector element +FALSE,vcopy_lane_u16,"a: uint16x4_t, lane1: const int, b: uint16x4_t, lane2: const int",uint16x4_t,Insert vector element from another vector element +FALSE,vcopy_lane_u32,"a: uint32x2_t, lane1: const int, b: uint32x2_t, lane2: const int",uint32x2_t,Insert vector element from another vector element +FALSE,vcopy_lane_u64,"a: uint64x1_t, lane1: const int, b: uint64x1_t, lane2: const int",uint64x1_t,Duplicate vector element to vector or scalar +FALSE,vcopy_lane_u8,"a: uint8x8_t, lane1: const int, b: uint8x8_t, lane2: const int",uint8x8_t,Insert vector element from another vector element +FALSE,vcopy_laneq_bf16,"a: bfloat16x4_t, lane1: const int, b: bfloat16x8_t, lane2: const int",bfloat16x4_t,Insert vector element from another vector element +FALSE,vcopy_laneq_f32,"a: float32x2_t, lane1: const int, b: float32x4_t, lane2: const int",float32x2_t,Insert vector element from another vector element +FALSE,vcopy_laneq_f64,"a: float64x1_t, lane1: const int, b: float64x2_t, lane2: const int",float64x1_t,Duplicate vector element to vector or scalar +FALSE,vcopy_laneq_p16,"a: poly16x4_t, lane1: const int, b: poly16x8_t, lane2: const int",poly16x4_t,Insert vector element from another vector element +FALSE,vcopy_laneq_p64,"a: poly64x1_t, lane1: const int, b: poly64x2_t, lane2: const int",poly64x1_t,Duplicate vector element to vector or scalar +FALSE,vcopy_laneq_p8,"a: poly8x8_t, lane1: const int, b: poly8x16_t, lane2: const int",poly8x8_t,Insert vector element from another vector element +FALSE,vcopy_laneq_s16,"a: int16x4_t, lane1: const int, b: int16x8_t, lane2: const int",int16x4_t,Insert vector element from another vector element +FALSE,vcopy_laneq_s32,"a: int32x2_t, lane1: const int, b: int32x4_t, lane2: const int",int32x2_t,Insert vector element from another vector element +FALSE,vcopy_laneq_s64,"a: int64x1_t, lane1: const int, b: int64x2_t, lane2: const int",int64x1_t,Duplicate vector element to vector or scalar +FALSE,vcopy_laneq_s8,"a: int8x8_t, lane1: const int, b: int8x16_t, lane2: const int",int8x8_t,Insert vector element from another vector element +FALSE,vcopy_laneq_u16,"a: uint16x4_t, lane1: const int, b: uint16x8_t, lane2: const int",uint16x4_t,Insert vector element from another vector element +FALSE,vcopy_laneq_u32,"a: uint32x2_t, lane1: const int, b: uint32x4_t, lane2: const int",uint32x2_t,Insert vector element from another vector element +FALSE,vcopy_laneq_u64,"a: uint64x1_t, lane1: const int, b: uint64x2_t, lane2: const int",uint64x1_t,Duplicate vector element to vector or scalar +FALSE,vcopy_laneq_u8,"a: uint8x8_t, lane1: const int, b: uint8x16_t, lane2: const int",uint8x8_t,Insert vector element from another vector element +FALSE,vcopyq_lane_bf16,"a: bfloat16x8_t, lane1: const int, b: bfloat16x4_t, lane2: const int",bfloat16x8_t,Insert vector element from another vector element +FALSE,vcopyq_lane_f32,"a: float32x4_t, lane1: const int, b: float32x2_t, lane2: const int",float32x4_t,Insert vector element from another vector element +FALSE,vcopyq_lane_f64,"a: float64x2_t, lane1: const int, b: float64x1_t, lane2: const int",float64x2_t,Insert vector element from another vector element +FALSE,vcopyq_lane_p16,"a: poly16x8_t, lane1: const int, b: poly16x4_t, lane2: const int",poly16x8_t,Insert vector element from another vector element +FALSE,vcopyq_lane_p64,"a: poly64x2_t, lane1: const int, b: poly64x1_t, lane2: const int",poly64x2_t,Insert vector element from another vector element +FALSE,vcopyq_lane_p8,"a: poly8x16_t, lane1: const int, b: poly8x8_t, lane2: const int",poly8x16_t,Insert vector element from another vector element +FALSE,vcopyq_lane_s16,"a: int16x8_t, lane1: const int, b: int16x4_t, lane2: const int",int16x8_t,Insert vector element from another vector element +FALSE,vcopyq_lane_s32,"a: int32x4_t, lane1: const int, b: int32x2_t, lane2: const int",int32x4_t,Insert vector element from another vector element +FALSE,vcopyq_lane_s64,"a: int64x2_t, lane1: const int, b: int64x1_t, lane2: const int",int64x2_t,Insert vector element from another vector element +FALSE,vcopyq_lane_s8,"a: int8x16_t, lane1: const int, b: int8x8_t, lane2: const int",int8x16_t,Insert vector element from another vector element +FALSE,vcopyq_lane_u16,"a: uint16x8_t, lane1: const int, b: uint16x4_t, lane2: const int",uint16x8_t,Insert vector element from another vector element +FALSE,vcopyq_lane_u32,"a: uint32x4_t, lane1: const int, b: uint32x2_t, lane2: const int",uint32x4_t,Insert vector element from another vector element +FALSE,vcopyq_lane_u64,"a: uint64x2_t, lane1: const int, b: uint64x1_t, lane2: const int",uint64x2_t,Insert vector element from another vector element +FALSE,vcopyq_lane_u8,"a: uint8x16_t, lane1: const int, b: uint8x8_t, lane2: const int",uint8x16_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_bf16,"a: bfloat16x8_t, lane1: const int, b: bfloat16x8_t, lane2: const int",bfloat16x8_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_f32,"a: float32x4_t, lane1: const int, b: float32x4_t, lane2: const int",float32x4_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_f64,"a: float64x2_t, lane1: const int, b: float64x2_t, lane2: const int",float64x2_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_p16,"a: poly16x8_t, lane1: const int, b: poly16x8_t, lane2: const int",poly16x8_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_p64,"a: poly64x2_t, lane1: const int, b: poly64x2_t, lane2: const int",poly64x2_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_p8,"a: poly8x16_t, lane1: const int, b: poly8x16_t, lane2: const int",poly8x16_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_s16,"a: int16x8_t, lane1: const int, b: int16x8_t, lane2: const int",int16x8_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_s32,"a: int32x4_t, lane1: const int, b: int32x4_t, lane2: const int",int32x4_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_s64,"a: int64x2_t, lane1: const int, b: int64x2_t, lane2: const int",int64x2_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_s8,"a: int8x16_t, lane1: const int, b: int8x16_t, lane2: const int",int8x16_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_u16,"a: uint16x8_t, lane1: const int, b: uint16x8_t, lane2: const int",uint16x8_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_u32,"a: uint32x4_t, lane1: const int, b: uint32x4_t, lane2: const int",uint32x4_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_u64,"a: uint64x2_t, lane1: const int, b: uint64x2_t, lane2: const int",uint64x2_t,Insert vector element from another vector element +FALSE,vcopyq_laneq_u8,"a: uint8x16_t, lane1: const int, b: uint8x16_t, lane2: const int",uint8x16_t,Insert vector element from another vector element +FALSE,vcreate_bf16,a: u64,bfloat16x4_t,Insert vector element from another vector element +FALSE,vcreate_f16,a: u64,float16x4_t,Insert vector element from another vector element +FALSE,vcreate_f32,a: u64,float32x2_t,Insert vector element from another vector element +FALSE,vcreate_f64,a: u64,float64x1_t,Insert vector element from another vector element +FALSE,vcreate_p16,a: u64,poly16x4_t,Insert vector element from another vector element +FALSE,vcreate_p64,a: u64,poly64x1_t,Insert vector element from another vector element +FALSE,vcreate_p8,a: u64,poly8x8_t,Insert vector element from another vector element +FALSE,vcreate_s16,a: u64,int16x4_t,Insert vector element from another vector element +FALSE,vcreate_s32,a: u64,int32x2_t,Insert vector element from another vector element +FALSE,vcreate_s64,a: u64,int64x1_t,Insert vector element from another vector element +FALSE,vcreate_s8,a: u64,int8x8_t,Insert vector element from another vector element +FALSE,vcreate_u16,a: u64,uint16x4_t,Insert vector element from another vector element +FALSE,vcreate_u32,a: u64,uint32x2_t,Insert vector element from another vector element +FALSE,vcreate_u64,a: u64,uint64x1_t,Insert vector element from another vector element +FALSE,vcreate_u8,a: u64,uint8x8_t,Insert vector element from another vector element +FALSE,vcvt_f16_f32,a: float32x4_t,float16x4_t,Floating-point convert to lower precision narrow +FALSE,vcvt_f16_s16,a: int16x4_t,float16x4_t,Signed fixed-point convert to floating-point +FALSE,vcvt_f16_u16,a: uint16x4_t,float16x4_t,Unsigned fixed-point convert to floating-point +FALSE,vcvt_f32_bf16,a: bfloat16x4_t,float32x4_t,Shift left long +FALSE,vcvt_f32_f16,a: float16x4_t,float32x4_t,Floating-point convert to higher precision long +TRUE,vcvt_f32_f64,a: float64x2_t,float32x2_t,Floating-point convert to lower precision narrow +FALSE,vcvt_f32_s32,a: int32x2_t,float32x2_t,Signed fixed-point convert to floating-point +FALSE,vcvt_f32_u32,a: uint32x2_t,float32x2_t,Unsigned fixed-point convert to floating-point +TRUE,vcvt_f64_f32,a: float32x2_t,float64x2_t,Floating-point convert to higher precision long +FALSE,vcvt_f64_s64,a: int64x1_t,float64x1_t,Signed fixed-point convert to floating-point +FALSE,vcvt_f64_u64,a: uint64x1_t,float64x1_t,Unsigned fixed-point convert to floating-point +FALSE,vcvt_high_bf16_f32,"inactive: bfloat16x4_t, a: float32x4_t",bfloat16x4_t,Floating-point convert from single-precision to bfloat16 format +FALSE,vcvt_high_f16_f32,"r: float16x4_t, a: float32x4_t",float16x8_t,Floating-point convert to lower precision narrow +FALSE,vcvt_high_f32_f16,a: float16x8_t,float32x4_t,Floating-point convert to higher precision long +TRUE,vcvt_high_f32_f64,"r: float32x2_t, a: float64x2_t",float32x4_t,Floating-point convert to lower precision narrow +TRUE,vcvt_high_f64_f32,a: float32x4_t,float64x2_t,Floating-point convert to higher precision long +FALSE,vcvt_low_bf16_f32,a: float32x4_t,bfloat16x4_t,Floating-point convert from single-precision to bfloat16 format +FALSE,vcvt_n_f16_s16,"a: int16x4_t, n: const int",float16x4_t,Signed fixed-point convert to floating-point +FALSE,vcvt_n_f16_u16,"a: uint16x4_t, n: const int",float16x4_t,Unsigned fixed-point convert to floating-point +FALSE,vcvt_n_f32_s32,"a: int32x2_t, n: const int",float32x2_t,Signed fixed-point convert to floating-point +FALSE,vcvt_n_f32_u32,"a: uint32x2_t, n: const int",float32x2_t,Unsigned fixed-point convert to floating-point +FALSE,vcvt_n_f64_s64,"a: int64x1_t, n: const int",float64x1_t,Signed fixed-point convert to floating-point +FALSE,vcvt_n_f64_u64,"a: uint64x1_t, n: const int",float64x1_t,Unsigned fixed-point convert to floating-point +FALSE,vcvt_n_s16_f16,"a: float16x4_t, n: const int",int16x4_t,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvt_n_s32_f32,"a: float32x2_t, n: const int",int32x2_t,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvt_n_s64_f64,"a: float64x1_t, n: const int",int64x1_t,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvt_n_u16_f16,"a: float16x4_t, n: const int",uint16x4_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvt_n_u32_f32,"a: float32x2_t, n: const int",uint32x2_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvt_n_u64_f64,"a: float64x1_t, n: const int",uint64x1_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvt_s16_f16,a: float16x4_t,int16x4_t,"Floating-point convert to signed fixed-point, rounding toward zero" +TRUE,vcvt_s32_f32,a: float32x2_t,int32x2_t,"Floating-point convert to signed fixed-point, rounding toward zero" +TRUE,vcvt_s64_f64,a: float64x1_t,int64x1_t,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvt_u16_f16,a: float16x4_t,uint16x4_t,"Floating-point convert to signed fixed-point, rounding toward zero" +TRUE,vcvt_u32_f32,a: float32x2_t,uint32x2_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +TRUE,vcvt_u64_f64,a: float64x1_t,uint64x1_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvta_s16_f16,a: float16x4_t,int16x4_t,"Floating-point convert to signed integer, rounding to nearest with ties to away" +TRUE,vcvta_s32_f32,a: float32x2_t,int32x2_t,"Floating-point convert to signed integer, rounding to nearest with ties to away" +TRUE,vcvta_s64_f64,a: float64x1_t,int64x1_t,"Floating-point convert to signed integer, rounding to nearest with ties to away" +FALSE,vcvta_u16_f16,a: float16x4_t,uint16x4_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +TRUE,vcvta_u32_f32,a: float32x2_t,uint32x2_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +TRUE,vcvta_u64_f64,a: float64x1_t,uint64x1_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +FALSE,vcvtad_s64_f64,a: float64_t,i64,"Floating-point convert to signed integer, rounding to nearest with ties to away" +FALSE,vcvtad_u64_f64,a: float64_t,u64,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +FALSE,vcvtah_f32_bf16,a: bfloat16_t,f32,Shift left +FALSE,vcvtah_s16_f16,a: float16_t,i16,"Floating-point convert to signed integer, rounding to nearest with ties to away" +FALSE,vcvtah_s32_f16,a: float16_t,i32,"Floating-point convert to signed integer, rounding to nearest with ties to away" +FALSE,vcvtah_s64_f16,a: float16_t,i64,"Floating-point convert to signed integer, rounding to nearest with ties to away" +FALSE,vcvtah_u16_f16,a: float16_t,u16,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +FALSE,vcvtah_u32_f16,a: float16_t,u32,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +FALSE,vcvtah_u64_f16,a: float16_t,u64,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +FALSE,vcvtaq_s16_f16,a: float16x8_t,int16x8_t,"Floating-point convert to signed integer, rounding to nearest with ties to away" +TRUE,vcvtaq_s32_f32,a: float32x4_t,int32x4_t,"Floating-point convert to signed integer, rounding to nearest with ties to away" +TRUE,vcvtaq_s64_f64,a: float64x2_t,int64x2_t,"Floating-point convert to signed integer, rounding to nearest with ties to away" +FALSE,vcvtaq_u16_f16,a: float16x8_t,uint16x8_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +TRUE,vcvtaq_u32_f32,a: float32x4_t,uint32x4_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +TRUE,vcvtaq_u64_f64,a: float64x2_t,uint64x2_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +FALSE,vcvtas_s32_f32,a: f32,i32,"Floating-point convert to signed integer, rounding to nearest with ties to away" +FALSE,vcvtas_u32_f32,a: f32,u32,"Floating-point convert to unsigned integer, rounding to nearest with ties to away" +FALSE,vcvtd_f64_s64,a: i64,float64_t,Signed fixed-point convert to floating-point +FALSE,vcvtd_f64_u64,a: u64,float64_t,Unsigned fixed-point convert to floating-point +FALSE,vcvtd_n_f64_s64,"a: i64, n: const int",float64_t,Signed fixed-point convert to floating-point +FALSE,vcvtd_n_f64_u64,"a: u64, n: const int",float64_t,Unsigned fixed-point convert to floating-point +FALSE,vcvtd_n_s64_f64,"a: float64_t, n: const int",i64,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvtd_n_u64_f64,"a: float64_t, n: const int",u64,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvtd_s64_f64,a: float64_t,i64,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvtd_u64_f64,a: float64_t,u64,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvth_bf16_f32,a: f32,bfloat16_t,Floating-point convert from single-precision to bfloat16 format +FALSE,vcvth_f16_s16,a: i16,float16_t,Signed fixed-point convert to floating-point +FALSE,vcvth_f16_s32,a: i32,float16_t,Signed fixed-point convert to floating-point +FALSE,vcvth_f16_s64,a: i64,float16_t,Signed fixed-point convert to floating-point +FALSE,vcvth_f16_u16,a: u16,float16_t,Unsigned fixed-point convert to floating-point +FALSE,vcvth_f16_u32,a: u32,float16_t,Unsigned fixed-point convert to floating-point +FALSE,vcvth_f16_u64,a: u64,float16_t,Unsigned fixed-point convert to floating-point +FALSE,vcvth_n_f16_s16,"a: i16, n: const int",float16_t,Signed fixed-point convert to floating-point +FALSE,vcvth_n_f16_s32,"a: i32, n: const int",float16_t,Signed fixed-point convert to floating-point +FALSE,vcvth_n_f16_s64,"a: i64, n: const int",float16_t,Signed fixed-point convert to floating-point +FALSE,vcvth_n_f16_u16,"a: u16, n: const int",float16_t,Unsigned fixed-point convert to floating-point +FALSE,vcvth_n_f16_u32,"a: u32, n: const int",float16_t,Unsigned fixed-point convert to floating-point +FALSE,vcvth_n_f16_u64,"a: u64, n: const int",float16_t,Unsigned fixed-point convert to floating-point +FALSE,vcvth_n_s16_f16,"a: float16_t, n: const int",i16,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvth_n_s32_f16,"a: float16_t, n: const int",i32,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvth_n_s64_f16,"a: float16_t, n: const int",i64,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvth_n_u16_f16,"a: float16_t, n: const int",u16,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvth_n_u32_f16,"a: float16_t, n: const int",u32,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvth_n_u64_f16,"a: float16_t, n: const int",u64,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvth_s16_f16,a: float16_t,i16,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvth_s32_f16,a: float16_t,i32,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvth_s64_f16,a: float16_t,i64,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvth_u16_f16,a: float16_t,u16,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvth_u32_f16,a: float16_t,u32,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvth_u64_f16,a: float16_t,u64,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvtm_s16_f16,a: float16x4_t,int16x4_t,"Floating-point convert to signed integer, rounding toward minus infinity" +TRUE,vcvtm_s32_f32,a: float32x2_t,int32x2_t,"Floating-point convert to signed integer, rounding toward minus infinity" +TRUE,vcvtm_s64_f64,a: float64x1_t,int64x1_t,"Floating-point convert to signed integer, rounding toward minus infinity" +FALSE,vcvtm_u16_f16,a: float16x4_t,uint16x4_t,"Floating-point convert to unsigned integer, rounding toward minus infinity" +TRUE,vcvtm_u32_f32,a: float32x2_t,uint32x2_t,"Floating-point convert to unsigned integer, rounding toward minus infinity" +TRUE,vcvtm_u64_f64,a: float64x1_t,uint64x1_t,"Floating-point convert to unsigned integer, rounding toward minus infinity" +FALSE,vcvtmd_s64_f64,a: float64_t,i64,"Floating-point convert to signed integer, rounding toward minus infinity" +FALSE,vcvtmd_u64_f64,a: float64_t,u64,"Floating-point convert to unsigned integer, rounding toward minus infinity" +FALSE,vcvtmh_s16_f16,a: float16_t,i16,"Floating-point convert to signed integer, rounding toward minus infinity" +FALSE,vcvtmh_s32_f16,a: float16_t,i32,"Floating-point convert to signed integer, rounding toward minus infinity" +FALSE,vcvtmh_s64_f16,a: float16_t,i64,"Floating-point convert to signed integer, rounding toward minus infinity" +FALSE,vcvtmh_u16_f16,a: float16_t,u16,"Floating-point convert to unsigned integer, rounding toward minus infinity" +FALSE,vcvtmh_u32_f16,a: float16_t,u32,"Floating-point convert to unsigned integer, rounding toward minus infinity" +FALSE,vcvtmh_u64_f16,a: float16_t,u64,"Floating-point convert to unsigned integer, rounding toward minus infinity" +FALSE,vcvtmq_s16_f16,a: float16x8_t,int16x8_t,"Floating-point convert to signed integer, rounding toward minus infinity" +TRUE,vcvtmq_s32_f32,a: float32x4_t,int32x4_t,"Floating-point convert to signed integer, rounding toward minus infinity" +TRUE,vcvtmq_s64_f64,a: float64x2_t,int64x2_t,"Floating-point convert to signed integer, rounding toward minus infinity" +FALSE,vcvtmq_u16_f16,a: float16x8_t,uint16x8_t,"Floating-point convert to unsigned integer, rounding toward minus infinity" +TRUE,vcvtmq_u32_f32,a: float32x4_t,uint32x4_t,"Floating-point convert to unsigned integer, rounding toward minus infinity" +TRUE,vcvtmq_u64_f64,a: float64x2_t,uint64x2_t,"Floating-point convert to unsigned integer, rounding toward minus infinity" +FALSE,vcvtms_s32_f32,a: f32,i32,"Floating-point convert to signed integer, rounding toward minus infinity" +FALSE,vcvtms_u32_f32,a: f32,u32,"Floating-point convert to unsigned integer, rounding toward minus infinity" +FALSE,vcvtn_s16_f16,a: float16x4_t,int16x4_t,"Floating-point convert to signed integer, rounding to nearest with ties to even" +TRUE,vcvtn_s32_f32,a: float32x2_t,int32x2_t,"Floating-point convert to signed integer, rounding to nearest with ties to even" +TRUE,vcvtn_s64_f64,a: float64x1_t,int64x1_t,"Floating-point convert to signed integer, rounding to nearest with ties to even" +FALSE,vcvtn_u16_f16,a: float16x4_t,uint16x4_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +TRUE,vcvtn_u32_f32,a: float32x2_t,uint32x2_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +TRUE,vcvtn_u64_f64,a: float64x1_t,uint64x1_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +FALSE,vcvtnd_s64_f64,a: float64_t,i64,"Floating-point convert to signed integer, rounding to nearest with ties to even" +FALSE,vcvtnd_u64_f64,a: float64_t,u64,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +FALSE,vcvtnh_s16_f16,a: float16_t,i16,"Floating-point convert to signed integer, rounding to nearest with ties to even" +FALSE,vcvtnh_s32_f16,a: float16_t,i32,"Floating-point convert to signed integer, rounding to nearest with ties to even" +FALSE,vcvtnh_s64_f16,a: float16_t,i64,"Floating-point convert to signed integer, rounding to nearest with ties to even" +FALSE,vcvtnh_u16_f16,a: float16_t,u16,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +FALSE,vcvtnh_u32_f16,a: float16_t,u32,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +FALSE,vcvtnh_u64_f16,a: float16_t,u64,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +FALSE,vcvtnq_s16_f16,a: float16x8_t,int16x8_t,"Floating-point convert to signed integer, rounding to nearest with ties to even" +TRUE,vcvtnq_s32_f32,a: float32x4_t,int32x4_t,"Floating-point convert to signed integer, rounding to nearest with ties to even" +TRUE,vcvtnq_s64_f64,a: float64x2_t,int64x2_t,"Floating-point convert to signed integer, rounding to nearest with ties to even" +FALSE,vcvtnq_u16_f16,a: float16x8_t,uint16x8_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +TRUE,vcvtnq_u32_f32,a: float32x4_t,uint32x4_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +TRUE,vcvtnq_u64_f64,a: float64x2_t,uint64x2_t,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +FALSE,vcvtns_s32_f32,a: f32,i32,"Floating-point convert to signed integer, rounding to nearest with ties to even" +FALSE,vcvtns_u32_f32,a: f32,u32,"Floating-point convert to unsigned integer, rounding to nearest with ties to even" +FALSE,vcvtp_s16_f16,a: float16x4_t,int16x4_t,"Floating-point convert to signed integer, rounding toward plus infinity" +TRUE,vcvtp_s32_f32,a: float32x2_t,int32x2_t,"Floating-point convert to signed integer, rounding toward plus infinity" +TRUE,vcvtp_s64_f64,a: float64x1_t,int64x1_t,"Floating-point convert to signed integer, rounding toward plus infinity" +FALSE,vcvtp_u16_f16,a: float16x4_t,uint16x4_t,"Floating-point convert to unsigned integer, rounding toward plus infinity" +TRUE,vcvtp_u32_f32,a: float32x2_t,uint32x2_t,"Floating-point convert to unsigned integer, rounding toward plus infinity" +TRUE,vcvtp_u64_f64,a: float64x1_t,uint64x1_t,"Floating-point convert to unsigned integer, rounding toward plus infinity" +FALSE,vcvtpd_s64_f64,a: float64_t,i64,"Floating-point convert to signed integer, rounding toward plus infinity" +FALSE,vcvtpd_u64_f64,a: float64_t,u64,"Floating-point convert to unsigned integer, rounding toward plus infinity" +FALSE,vcvtph_s16_f16,a: float16_t,i16,"Floating-point convert to signed integer, rounding toward plus infinity" +FALSE,vcvtph_s32_f16,a: float16_t,i32,"Floating-point convert to signed integer, rounding toward plus infinity" +FALSE,vcvtph_s64_f16,a: float16_t,i64,"Floating-point convert to signed integer, rounding toward plus infinity" +FALSE,vcvtph_u16_f16,a: float16_t,u16,"Floating-point convert to unsigned integer, rounding toward plus infinity" +FALSE,vcvtph_u32_f16,a: float16_t,u32,"Floating-point convert to unsigned integer, rounding toward plus infinity" +FALSE,vcvtph_u64_f16,a: float16_t,u64,"Floating-point convert to unsigned integer, rounding toward plus infinity" +FALSE,vcvtpq_s16_f16,a: float16x8_t,int16x8_t,"Floating-point convert to signed integer, rounding toward plus infinity" +TRUE,vcvtpq_s32_f32,a: float32x4_t,int32x4_t,"Floating-point convert to signed integer, rounding toward plus infinity" +TRUE,vcvtpq_s64_f64,a: float64x2_t,int64x2_t,"Floating-point convert to signed integer, rounding toward plus infinity" +FALSE,vcvtpq_u16_f16,a: float16x8_t,uint16x8_t,"Floating-point convert to unsigned integer, rounding toward plus infinity" +TRUE,vcvtpq_u32_f32,a: float32x4_t,uint32x4_t,"Floating-point convert to unsigned integer, rounding toward plus infinity" +TRUE,vcvtpq_u64_f64,a: float64x2_t,uint64x2_t,"Floating-point convert to unsigned integer, rounding toward plus infinity" +FALSE,vcvtps_s32_f32,a: f32,i32,"Floating-point convert to signed integer, rounding toward plus infinity" +FALSE,vcvtps_u32_f32,a: f32,u32,"Floating-point convert to unsigned integer, rounding toward plus infinity" +FALSE,vcvtq_f16_s16,a: int16x8_t,float16x8_t,Signed fixed-point convert to floating-point +FALSE,vcvtq_f16_u16,a: uint16x8_t,float16x8_t,Unsigned fixed-point convert to floating-point +FALSE,vcvtq_f32_s32,a: int32x4_t,float32x4_t,Signed fixed-point convert to floating-point +FALSE,vcvtq_f32_u32,a: uint32x4_t,float32x4_t,Unsigned fixed-point convert to floating-point +FALSE,vcvtq_f64_s64,a: int64x2_t,float64x2_t,Signed fixed-point convert to floating-point +FALSE,vcvtq_f64_u64,a: uint64x2_t,float64x2_t,Unsigned fixed-point convert to floating-point +FALSE,vcvtq_high_bf16_f32,"inactive: bfloat16x8_t, a: float32x4_t",bfloat16x8_t,Floating-point convert from single-precision to bfloat16 format +FALSE,vcvtq_high_f32_bf16,a: bfloat16x8_t,float32x4_t,Shift left long +FALSE,vcvtq_low_bf16_f32,a: float32x4_t,bfloat16x8_t,Floating-point convert from single-precision to bfloat16 format +FALSE,vcvtq_low_f32_bf16,a: bfloat16x8_t,float32x4_t,Shift left long +FALSE,vcvtq_n_f16_s16,"a: int16x8_t, n: const int",float16x8_t,Signed fixed-point convert to floating-point +FALSE,vcvtq_n_f16_u16,"a: uint16x8_t, n: const int",float16x8_t,Unsigned fixed-point convert to floating-point +FALSE,vcvtq_n_f32_s32,"a: int32x4_t, n: const int",float32x4_t,Signed fixed-point convert to floating-point +FALSE,vcvtq_n_f32_u32,"a: uint32x4_t, n: const int",float32x4_t,Unsigned fixed-point convert to floating-point +FALSE,vcvtq_n_f64_s64,"a: int64x2_t, n: const int",float64x2_t,Signed fixed-point convert to floating-point +FALSE,vcvtq_n_f64_u64,"a: uint64x2_t, n: const int",float64x2_t,Unsigned fixed-point convert to floating-point +FALSE,vcvtq_n_s16_f16,"a: float16x8_t, n: const int",int16x8_t,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvtq_n_s32_f32,"a: float32x4_t, n: const int",int32x4_t,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvtq_n_s64_f64,"a: float64x2_t, n: const int",int64x2_t,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvtq_n_u16_f16,"a: float16x8_t, n: const int",uint16x8_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvtq_n_u32_f32,"a: float32x4_t, n: const int",uint32x4_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvtq_n_u64_f64,"a: float64x2_t, n: const int",uint64x2_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvtq_s16_f16,a: float16x8_t,int16x8_t,"Floating-point convert to signed fixed-point, rounding toward zero" +TRUE,vcvtq_s32_f32,a: float32x4_t,int32x4_t,"Floating-point convert to signed fixed-point, rounding toward zero" +TRUE,vcvtq_s64_f64,a: float64x2_t,int64x2_t,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvtq_u16_f16,a: float16x8_t,uint16x8_t,"Floating-point convert to signed fixed-point, rounding toward zero" +TRUE,vcvtq_u32_f32,a: float32x4_t,uint32x4_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +TRUE,vcvtq_u64_f64,a: float64x2_t,uint64x2_t,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvts_f32_s32,a: i32,f32,Signed fixed-point convert to floating-point +FALSE,vcvts_f32_u32,a: u32,f32,Unsigned fixed-point convert to floating-point +FALSE,vcvts_n_f32_s32,"a: i32, n: const int",f32,Signed fixed-point convert to floating-point +FALSE,vcvts_n_f32_u32,"a: u32, n: const int",f32,Unsigned fixed-point convert to floating-point +FALSE,vcvts_n_s32_f32,"a: f32, n: const int",i32,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvts_n_u32_f32,"a: f32, n: const int",u32,"Floating-point convert to unsigned fixed-point, rounding toward zero" +FALSE,vcvts_s32_f32,a: f32,i32,"Floating-point convert to signed fixed-point, rounding toward zero" +FALSE,vcvts_u32_f32,a: f32,u32,"Floating-point convert to unsigned fixed-point, rounding toward zero" +TRUE,vcvtx_f32_f64,a: float64x2_t,float32x2_t,"Floating-point convert to lower precision narrow, rounding to odd" +TRUE,vcvtx_high_f32_f64,"r: float32x2_t, a: float64x2_t",float32x4_t,"Floating-point convert to lower precision narrow, rounding to odd" +FALSE,vcvtxd_f32_f64,a: float64_t,f32,"Floating-point convert to lower precision narrow, rounding to odd" +FALSE,vdiv_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point divide +TRUE,vdiv_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point divide +TRUE,vdiv_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point divide +FALSE,vdivh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point divide +FALSE,vdivq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point divide +TRUE,vdivq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point divide +TRUE,vdivq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point divide +FALSE,vdot_lane_s32,"r: int32x2_t, a: int8x8_t, b: int8x8_t, lane: const int",int32x2_t,Dot product signed arithmetic +FALSE,vdot_lane_u32,"r: uint32x2_t, a: uint8x8_t, b: uint8x8_t, lane: const int",uint32x2_t,Dot product unsigned arithmetic +FALSE,vdot_laneq_s32,"r: int32x2_t, a: int8x8_t, b: int8x16_t, lane: const int",int32x2_t,Dot product signed arithmetic +FALSE,vdot_laneq_u32,"r: uint32x2_t, a: uint8x8_t, b: uint8x16_t, lane: const int",uint32x2_t,Dot product unsigned arithmetic +FALSE,vdot_s32,"r: int32x2_t, a: int8x8_t, b: int8x8_t",int32x2_t,Dot product signed arithmetic +FALSE,vdot_u32,"r: uint32x2_t, a: uint8x8_t, b: uint8x8_t",uint32x2_t,Dot product unsigned arithmetic +FALSE,vdotq_lane_s32,"r: int32x4_t, a: int8x16_t, b: int8x8_t, lane: const int",int32x4_t,Dot product signed arithmetic +FALSE,vdotq_lane_u32,"r: uint32x4_t, a: uint8x16_t, b: uint8x8_t, lane: const int",uint32x4_t,Dot product unsigned arithmetic +FALSE,vdotq_laneq_s32,"r: int32x4_t, a: int8x16_t, b: int8x16_t, lane: const int",int32x4_t,Dot product signed arithmetic +FALSE,vdotq_laneq_u32,"r: uint32x4_t, a: uint8x16_t, b: uint8x16_t, lane: const int",uint32x4_t,Dot product unsigned arithmetic +FALSE,vdotq_s32,"r: int32x4_t, a: int8x16_t, b: int8x16_t",int32x4_t,Dot product signed arithmetic +FALSE,vdotq_u32,"r: uint32x4_t, a: uint8x16_t, b: uint8x16_t",uint32x4_t,Dot product unsigned arithmetic +FALSE,vdup_lane_bf16,"vec: bfloat16x4_t, lane: const int",bfloat16x4_t,Duplicate vector element to vector or scalar +FALSE,vdup_lane_f16,"vec: float16x4_t, lane: const int",float16x4_t,Set all vector lanes to the same value +TRUE,vdup_lane_f32,"vec: float32x2_t, lane: const int",float32x2_t,Set all vector lanes to the same value +TRUE,vdup_lane_f64,"vec: float64x1_t, lane: const int",float64x1_t,Set all vector lanes to the same value +TRUE,vdup_lane_p16,"vec: poly16x4_t, lane: const int",poly16x4_t,Set all vector lanes to the same value +TRUE,vdup_lane_p64,"vec: poly64x1_t, lane: const int",poly64x1_t,Set all vector lanes to the same value +TRUE,vdup_lane_p8,"vec: poly8x8_t, lane: const int",poly8x8_t,Set all vector lanes to the same value +TRUE,vdup_lane_s16,"vec: int16x4_t, lane: const int",int16x4_t,Set all vector lanes to the same value +TRUE,vdup_lane_s32,"vec: int32x2_t, lane: const int",int32x2_t,Set all vector lanes to the same value +TRUE,vdup_lane_s64,"vec: int64x1_t, lane: const int",int64x1_t,Set all vector lanes to the same value +TRUE,vdup_lane_s8,"vec: int8x8_t, lane: const int",int8x8_t,Set all vector lanes to the same value +TRUE,vdup_lane_u16,"vec: uint16x4_t, lane: const int",uint16x4_t,Set all vector lanes to the same value +TRUE,vdup_lane_u32,"vec: uint32x2_t, lane: const int",uint32x2_t,Set all vector lanes to the same value +TRUE,vdup_lane_u64,"vec: uint64x1_t, lane: const int",uint64x1_t,Set all vector lanes to the same value +TRUE,vdup_lane_u8,"vec: uint8x8_t, lane: const int",uint8x8_t,Set all vector lanes to the same value +FALSE,vdup_laneq_bf16,"vec: bfloat16x8_t, lane: const int",bfloat16x4_t,Duplicate vector element to vector or scalar +FALSE,vdup_laneq_f16,"vec: float16x8_t, lane: const int",float16x4_t,Set all vector lanes to the same value +TRUE,vdup_laneq_f32,"vec: float32x4_t, lane: const int",float32x2_t,Set all vector lanes to the same value +TRUE,vdup_laneq_f64,"vec: float64x2_t, lane: const int",float64x1_t,Set all vector lanes to the same value +TRUE,vdup_laneq_p16,"vec: poly16x8_t, lane: const int",poly16x4_t,Set all vector lanes to the same value +TRUE,vdup_laneq_p64,"vec: poly64x2_t, lane: const int",poly64x1_t,Set all vector lanes to the same value +TRUE,vdup_laneq_p8,"vec: poly8x16_t, lane: const int",poly8x8_t,Set all vector lanes to the same value +TRUE,vdup_laneq_s16,"vec: int16x8_t, lane: const int",int16x4_t,Set all vector lanes to the same value +TRUE,vdup_laneq_s32,"vec: int32x4_t, lane: const int",int32x2_t,Set all vector lanes to the same value +TRUE,vdup_laneq_s64,"vec: int64x2_t, lane: const int",int64x1_t,Set all vector lanes to the same value +TRUE,vdup_laneq_s8,"vec: int8x16_t, lane: const int",int8x8_t,Set all vector lanes to the same value +TRUE,vdup_laneq_u16,"vec: uint16x8_t, lane: const int",uint16x4_t,Set all vector lanes to the same value +TRUE,vdup_laneq_u32,"vec: uint32x4_t, lane: const int",uint32x2_t,Set all vector lanes to the same value +TRUE,vdup_laneq_u64,"vec: uint64x2_t, lane: const int",uint64x1_t,Set all vector lanes to the same value +TRUE,vdup_laneq_u8,"vec: uint8x16_t, lane: const int",uint8x8_t,Set all vector lanes to the same value +FALSE,vdup_n_bf16,value: bfloat16_t,bfloat16x4_t,Duplicate vector element to vector or scalar +FALSE,vdup_n_f16,value: float16_t,float16x4_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_f32,value: f32,float32x2_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_f64,value: float64_t,float64x1_t,Insert vector element from another vector element +TRUE,vdup_n_p16,value: poly16_t,poly16x4_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_p64,value: poly64_t,poly64x1_t,Insert vector element from another vector element +TRUE,vdup_n_p8,value: poly8_t,poly8x8_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_s16,value: i16,int16x4_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_s32,value: i32,int32x2_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_s64,value: i64,int64x1_t,Insert vector element from another vector element +TRUE,vdup_n_s8,value: i8,int8x8_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_u16,value: u16,uint16x4_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_u32,value: u32,uint32x2_t,Duplicate vector element to vector or scalar +TRUE,vdup_n_u64,value: u64,uint64x1_t,Insert vector element from another vector element +TRUE,vdup_n_u8,value: u8,uint8x8_t,Duplicate vector element to vector or scalar +TRUE,vdupb_lane_p8,"vec: poly8x8_t, lane: const int",poly8_t,Set all vector lanes to the same value +TRUE,vdupb_lane_s8,"vec: int8x8_t, lane: const int",i8,Set all vector lanes to the same value +TRUE,vdupb_lane_u8,"vec: uint8x8_t, lane: const int",u8,Set all vector lanes to the same value +TRUE,vdupb_laneq_p8,"vec: poly8x16_t, lane: const int",poly8_t,Set all vector lanes to the same value +TRUE,vdupb_laneq_s8,"vec: int8x16_t, lane: const int",i8,Set all vector lanes to the same value +TRUE,vdupb_laneq_u8,"vec: uint8x16_t, lane: const int",u8,Set all vector lanes to the same value +TRUE,vdupd_lane_f64,"vec: float64x1_t, lane: const int",float64_t,Set all vector lanes to the same value +TRUE,vdupd_lane_s64,"vec: int64x1_t, lane: const int",i64,Set all vector lanes to the same value +TRUE,vdupd_lane_u64,"vec: uint64x1_t, lane: const int",u64,Set all vector lanes to the same value +TRUE,vdupd_laneq_f64,"vec: float64x2_t, lane: const int",float64_t,Set all vector lanes to the same value +TRUE,vdupd_laneq_s64,"vec: int64x2_t, lane: const int",i64,Set all vector lanes to the same value +TRUE,vdupd_laneq_u64,"vec: uint64x2_t, lane: const int",u64,Set all vector lanes to the same value +FALSE,vduph_lane_bf16,"vec: bfloat16x4_t, lane: const int",bfloat16_t,Duplicate vector element to vector or scalar +FALSE,vduph_lane_f16,"vec: float16x4_t, lane: const int",float16_t,Set all vector lanes to the same value +TRUE,vduph_lane_p16,"vec: poly16x4_t, lane: const int",poly16_t,Set all vector lanes to the same value +TRUE,vduph_lane_s16,"vec: int16x4_t, lane: const int",i16,Set all vector lanes to the same value +TRUE,vduph_lane_u16,"vec: uint16x4_t, lane: const int",u16,Set all vector lanes to the same value +FALSE,vduph_laneq_bf16,"vec: bfloat16x8_t, lane: const int",bfloat16_t,Duplicate vector element to vector or scalar +FALSE,vduph_laneq_f16,"vec: float16x8_t, lane: const int",float16_t,Set all vector lanes to the same value +TRUE,vduph_laneq_p16,"vec: poly16x8_t, lane: const int",poly16_t,Set all vector lanes to the same value +TRUE,vduph_laneq_s16,"vec: int16x8_t, lane: const int",i16,Set all vector lanes to the same value +TRUE,vduph_laneq_u16,"vec: uint16x8_t, lane: const int",u16,Set all vector lanes to the same value +FALSE,vdupq_lane_bf16,"vec: bfloat16x4_t, lane: const int",bfloat16x8_t,Duplicate vector element to vector or scalar +FALSE,vdupq_lane_f16,"vec: float16x4_t, lane: const int",float16x8_t,Set all vector lanes to the same value +TRUE,vdupq_lane_f32,"vec: float32x2_t, lane: const int",float32x4_t,Set all vector lanes to the same value +TRUE,vdupq_lane_f64,"vec: float64x1_t, lane: const int",float64x2_t,Set all vector lanes to the same value +TRUE,vdupq_lane_p16,"vec: poly16x4_t, lane: const int",poly16x8_t,Set all vector lanes to the same value +TRUE,vdupq_lane_p64,"vec: poly64x1_t, lane: const int",poly64x2_t,Set all vector lanes to the same value +TRUE,vdupq_lane_p8,"vec: poly8x8_t, lane: const int",poly8x16_t,Set all vector lanes to the same value +TRUE,vdupq_lane_s16,"vec: int16x4_t, lane: const int",int16x8_t,Set all vector lanes to the same value +TRUE,vdupq_lane_s32,"vec: int32x2_t, lane: const int",int32x4_t,Set all vector lanes to the same value +TRUE,vdupq_lane_s64,"vec: int64x1_t, lane: const int",int64x2_t,Set all vector lanes to the same value +TRUE,vdupq_lane_s8,"vec: int8x8_t, lane: const int",int8x16_t,Set all vector lanes to the same value +TRUE,vdupq_lane_u16,"vec: uint16x4_t, lane: const int",uint16x8_t,Set all vector lanes to the same value +TRUE,vdupq_lane_u32,"vec: uint32x2_t, lane: const int",uint32x4_t,Set all vector lanes to the same value +TRUE,vdupq_lane_u64,"vec: uint64x1_t, lane: const int",uint64x2_t,Set all vector lanes to the same value +TRUE,vdupq_lane_u8,"vec: uint8x8_t, lane: const int",uint8x16_t,Set all vector lanes to the same value +FALSE,vdupq_laneq_bf16,"vec: bfloat16x8_t, lane: const int",bfloat16x8_t,Duplicate vector element to vector or scalar +FALSE,vdupq_laneq_f16,"vec: float16x8_t, lane: const int",float16x8_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_f32,"vec: float32x4_t, lane: const int",float32x4_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_f64,"vec: float64x2_t, lane: const int",float64x2_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_p16,"vec: poly16x8_t, lane: const int",poly16x8_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_p64,"vec: poly64x2_t, lane: const int",poly64x2_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_p8,"vec: poly8x16_t, lane: const int",poly8x16_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_s16,"vec: int16x8_t, lane: const int",int16x8_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_s32,"vec: int32x4_t, lane: const int",int32x4_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_s64,"vec: int64x2_t, lane: const int",int64x2_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_s8,"vec: int8x16_t, lane: const int",int8x16_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_u16,"vec: uint16x8_t, lane: const int",uint16x8_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_u32,"vec: uint32x4_t, lane: const int",uint32x4_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_u64,"vec: uint64x2_t, lane: const int",uint64x2_t,Set all vector lanes to the same value +TRUE,vdupq_laneq_u8,"vec: uint8x16_t, lane: const int",uint8x16_t,Set all vector lanes to the same value +FALSE,vdupq_n_bf16,value: bfloat16_t,bfloat16x8_t,Duplicate vector element to vector or scalar +FALSE,vdupq_n_f16,value: float16_t,float16x8_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_f32,value: f32,float32x4_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_f64,value: float64_t,float64x2_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_p16,value: poly16_t,poly16x8_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_p64,value: poly64_t,poly64x2_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_p8,value: poly8_t,poly8x16_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_s16,value: i16,int16x8_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_s32,value: i32,int32x4_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_s64,value: i64,int64x2_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_s8,value: i8,int8x16_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_u16,value: u16,uint16x8_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_u32,value: u32,uint32x4_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_u64,value: u64,uint64x2_t,Duplicate vector element to vector or scalar +TRUE,vdupq_n_u8,value: u8,uint8x16_t,Duplicate vector element to vector or scalar +TRUE,vdups_lane_f32,"vec: float32x2_t, lane: const int",f32,Set all vector lanes to the same value +TRUE,vdups_lane_s32,"vec: int32x2_t, lane: const int",i32,Set all vector lanes to the same value +TRUE,vdups_lane_u32,"vec: uint32x2_t, lane: const int",u32,Set all vector lanes to the same value +TRUE,vdups_laneq_f32,"vec: float32x4_t, lane: const int",f32,Set all vector lanes to the same value +TRUE,vdups_laneq_s32,"vec: int32x4_t, lane: const int",i32,Set all vector lanes to the same value +TRUE,vdups_laneq_u32,"vec: uint32x4_t, lane: const int",u32,Set all vector lanes to the same value +TRUE,veor_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Bitwise exclusive OR +TRUE,veor_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Bitwise exclusive OR +TRUE,veor_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Bitwise exclusive OR +TRUE,veor_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Bitwise exclusive OR +TRUE,veor_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Bitwise exclusive OR +TRUE,veor_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Bitwise exclusive OR +TRUE,veor_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Bitwise exclusive OR +TRUE,veor_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Bitwise exclusive OR +FALSE,veor3q_s16,"a: int16x8_t, b: int16x8_t, c: int16x8_t",int16x8_t,Three-way exclusive OR +FALSE,veor3q_s32,"a: int32x4_t, b: int32x4_t, c: int32x4_t",int32x4_t,Three-way exclusive OR +FALSE,veor3q_s64,"a: int64x2_t, b: int64x2_t, c: int64x2_t",int64x2_t,Three-way exclusive OR +FALSE,veor3q_s8,"a: int8x16_t, b: int8x16_t, c: int8x16_t",int8x16_t,Three-way exclusive OR +FALSE,veor3q_u16,"a: uint16x8_t, b: uint16x8_t, c: uint16x8_t",uint16x8_t,Three-way exclusive OR +FALSE,veor3q_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,Three-way exclusive OR +FALSE,veor3q_u64,"a: uint64x2_t, b: uint64x2_t, c: uint64x2_t",uint64x2_t,Three-way exclusive OR +FALSE,veor3q_u8,"a: uint8x16_t, b: uint8x16_t, c: uint8x16_t",uint8x16_t,Three-way exclusive OR +TRUE,veorq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Bitwise exclusive OR +TRUE,veorq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Bitwise exclusive OR +TRUE,veorq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Bitwise exclusive OR +TRUE,veorq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Bitwise exclusive OR +TRUE,veorq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Bitwise exclusive OR +TRUE,veorq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Bitwise exclusive OR +TRUE,veorq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Bitwise exclusive OR +TRUE,veorq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Bitwise exclusive OR +FALSE,vext_f16,"a: float16x4_t, b: float16x4_t, n: const int",float16x4_t,Extract vector from pair of vectors +TRUE,vext_f32,"a: float32x2_t, b: float32x2_t, n: const int",float32x2_t,Extract vector from pair of vectors +TRUE,vext_f64,"a: float64x1_t, b: float64x1_t, n: const int",float64x1_t,Extract vector from pair of vectors +TRUE,vext_p16,"a: poly16x4_t, b: poly16x4_t, n: const int",poly16x4_t,Extract vector from pair of vectors +TRUE,vext_p64,"a: poly64x1_t, b: poly64x1_t, n: const int",poly64x1_t,Extract vector from pair of vectors +TRUE,vext_p8,"a: poly8x8_t, b: poly8x8_t, n: const int",poly8x8_t,Extract vector from pair of vectors +TRUE,vext_s16,"a: int16x4_t, b: int16x4_t, n: const int",int16x4_t,Extract vector from pair of vectors +TRUE,vext_s32,"a: int32x2_t, b: int32x2_t, n: const int",int32x2_t,Extract vector from pair of vectors +TRUE,vext_s64,"a: int64x1_t, b: int64x1_t, n: const int",int64x1_t,Extract vector from pair of vectors +TRUE,vext_s8,"a: int8x8_t, b: int8x8_t, n: const int",int8x8_t,Extract vector from pair of vectors +TRUE,vext_u16,"a: uint16x4_t, b: uint16x4_t, n: const int",uint16x4_t,Extract vector from pair of vectors +TRUE,vext_u32,"a: uint32x2_t, b: uint32x2_t, n: const int",uint32x2_t,Extract vector from pair of vectors +TRUE,vext_u64,"a: uint64x1_t, b: uint64x1_t, n: const int",uint64x1_t,Extract vector from pair of vectors +TRUE,vext_u8,"a: uint8x8_t, b: uint8x8_t, n: const int",uint8x8_t,Extract vector from pair of vectors +FALSE,vextq_f16,"a: float16x8_t, b: float16x8_t, n: const int",float16x8_t,Extract vector from pair of vectors +TRUE,vextq_f32,"a: float32x4_t, b: float32x4_t, n: const int",float32x4_t,Extract vector from pair of vectors +TRUE,vextq_f64,"a: float64x2_t, b: float64x2_t, n: const int",float64x2_t,Extract vector from pair of vectors +TRUE,vextq_p16,"a: poly16x8_t, b: poly16x8_t, n: const int",poly16x8_t,Extract vector from pair of vectors +TRUE,vextq_p64,"a: poly64x2_t, b: poly64x2_t, n: const int",poly64x2_t,Extract vector from pair of vectors +TRUE,vextq_p8,"a: poly8x16_t, b: poly8x16_t, n: const int",poly8x16_t,Extract vector from pair of vectors +TRUE,vextq_s16,"a: int16x8_t, b: int16x8_t, n: const int",int16x8_t,Extract vector from pair of vectors +TRUE,vextq_s32,"a: int32x4_t, b: int32x4_t, n: const int",int32x4_t,Extract vector from pair of vectors +TRUE,vextq_s64,"a: int64x2_t, b: int64x2_t, n: const int",int64x2_t,Extract vector from pair of vectors +TRUE,vextq_s8,"a: int8x16_t, b: int8x16_t, n: const int",int8x16_t,Extract vector from pair of vectors +TRUE,vextq_u16,"a: uint16x8_t, b: uint16x8_t, n: const int",uint16x8_t,Extract vector from pair of vectors +TRUE,vextq_u32,"a: uint32x4_t, b: uint32x4_t, n: const int",uint32x4_t,Extract vector from pair of vectors +TRUE,vextq_u64,"a: uint64x2_t, b: uint64x2_t, n: const int",uint64x2_t,Extract vector from pair of vectors +TRUE,vextq_u8,"a: uint8x16_t, b: uint8x16_t, n: const int",uint8x16_t,Extract vector from pair of vectors +FALSE,vfma_f16,"a: float16x4_t, b: float16x4_t, c: float16x4_t",float16x4_t,Floating-point fused multiply-add to accumulator +TRUE,vfma_f32,"a: float32x2_t, b: float32x2_t, c: float32x2_t",float32x2_t,Floating-point fused multiply-add to accumulator +TRUE,vfma_f64,"a: float64x1_t, b: float64x1_t, c: float64x1_t",float64x1_t,Floating-point fused multiply-add +FALSE,vfma_lane_f16,"a: float16x4_t, b: float16x4_t, v: float16x4_t, lane: const int",float16x4_t,Floating-point fused multiply-add to accumulator +FALSE,vfma_lane_f32,"a: float32x2_t, b: float32x2_t, v: float32x2_t, lane: const int",float32x2_t,Floating-point fused multiply-add to accumulator +FALSE,vfma_lane_f64,"a: float64x1_t, b: float64x1_t, v: float64x1_t, lane: const int",float64x1_t,Floating-point fused multiply-add to accumulator +FALSE,vfma_laneq_f16,"a: float16x4_t, b: float16x4_t, v: float16x8_t, lane: const int",float16x4_t,Floating-point fused multiply-add to accumulator +FALSE,vfma_laneq_f32,"a: float32x2_t, b: float32x2_t, v: float32x4_t, lane: const int",float32x2_t,Floating-point fused multiply-add to accumulator +FALSE,vfma_laneq_f64,"a: float64x1_t, b: float64x1_t, v: float64x2_t, lane: const int",float64x1_t,Floating-point fused multiply-add to accumulator +FALSE,vfma_n_f16,"a: float16x4_t, b: float16x4_t, n: float16_t",float16x4_t,Floating-point fused multiply-add to accumulator +TRUE,vfma_n_f32,"a: float32x2_t, b: float32x2_t, n: f32",float32x2_t,Floating-point fused multiply-add to accumulator +TRUE,vfma_n_f64,"a: float64x1_t, b: float64x1_t, n: float64_t",float64x1_t,Floating-point fused multiply-add +FALSE,vfmad_lane_f64,"a: float64_t, b: float64_t, v: float64x1_t, lane: const int",float64_t,Floating-point fused multiply-add to accumulator +FALSE,vfmad_laneq_f64,"a: float64_t, b: float64_t, v: float64x2_t, lane: const int",float64_t,Floating-point fused multiply-add to accumulator +FALSE,vfmah_f16,"a: float16_t, b: float16_t, c: float16_t",float16_t,Floating-point fused multiply-add +FALSE,vfmah_lane_f16,"a: float16_t, b: float16_t, v: float16x4_t, lane: const int",float16_t,Floating-point fused multiply-add to accumulator +FALSE,vfmah_laneq_f16,"a: float16_t, b: float16_t, v: float16x8_t, lane: const int",float16_t,Floating-point fused multiply-add to accumulator +FALSE,vfmaq_f16,"a: float16x8_t, b: float16x8_t, c: float16x8_t",float16x8_t,Floating-point fused multiply-add to accumulator +TRUE,vfmaq_f32,"a: float32x4_t, b: float32x4_t, c: float32x4_t",float32x4_t,Floating-point fused multiply-add to accumulator +TRUE,vfmaq_f64,"a: float64x2_t, b: float64x2_t, c: float64x2_t",float64x2_t,Floating-point fused multiply-add to accumulator +FALSE,vfmaq_lane_f16,"a: float16x8_t, b: float16x8_t, v: float16x4_t, lane: const int",float16x8_t,Floating-point fused multiply-add to accumulator +FALSE,vfmaq_lane_f32,"a: float32x4_t, b: float32x4_t, v: float32x2_t, lane: const int",float32x4_t,Floating-point fused multiply-add to accumulator +FALSE,vfmaq_lane_f64,"a: float64x2_t, b: float64x2_t, v: float64x1_t, lane: const int",float64x2_t,Floating-point fused multiply-add to accumulator +FALSE,vfmaq_laneq_f16,"a: float16x8_t, b: float16x8_t, v: float16x8_t, lane: const int",float16x8_t,Floating-point fused multiply-add to accumulator +FALSE,vfmaq_laneq_f32,"a: float32x4_t, b: float32x4_t, v: float32x4_t, lane: const int",float32x4_t,Floating-point fused multiply-add to accumulator +FALSE,vfmaq_laneq_f64,"a: float64x2_t, b: float64x2_t, v: float64x2_t, lane: const int",float64x2_t,Floating-point fused multiply-add to accumulator +FALSE,vfmaq_n_f16,"a: float16x8_t, b: float16x8_t, n: float16_t",float16x8_t,Floating-point fused multiply-add to accumulator +TRUE,vfmaq_n_f32,"a: float32x4_t, b: float32x4_t, n: f32",float32x4_t,Floating-point fused multiply-add to accumulator +TRUE,vfmaq_n_f64,"a: float64x2_t, b: float64x2_t, n: float64_t",float64x2_t,Floating-point fused multiply-add to accumulator +FALSE,vfmas_lane_f32,"a: f32, b: f32, v: float32x2_t, lane: const int",f32,Floating-point fused multiply-add to accumulator +FALSE,vfmas_laneq_f32,"a: f32, b: f32, v: float32x4_t, lane: const int",f32,Floating-point fused multiply-add to accumulator +FALSE,vfmlal_high_f16,"r: float32x2_t, a: float16x4_t, b: float16x4_t",float32x2_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlal_lane_high_f16,"r: float32x2_t, a: float16x4_t, b: float16x4_t, lane: const int",float32x2_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlal_lane_low_f16,"r: float32x2_t, a: float16x4_t, b: float16x4_t, lane: const int",float32x2_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlal_laneq_high_f16,"r: float32x2_t, a: float16x4_t, b: float16x8_t, lane: const int",float32x2_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlal_laneq_low_f16,"r: float32x2_t, a: float16x4_t, b: float16x8_t, lane: const int",float32x2_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlal_low_f16,"r: float32x2_t, a: float16x4_t, b: float16x4_t",float32x2_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlalq_high_f16,"r: float32x4_t, a: float16x8_t, b: float16x8_t",float32x4_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlalq_lane_high_f16,"r: float32x4_t, a: float16x8_t, b: float16x4_t, lane: const int",float32x4_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlalq_lane_low_f16,"r: float32x4_t, a: float16x8_t, b: float16x4_t, lane: const int",float32x4_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlalq_laneq_high_f16,"r: float32x4_t, a: float16x8_t, b: float16x8_t, lane: const int",float32x4_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlalq_laneq_low_f16,"r: float32x4_t, a: float16x8_t, b: float16x8_t, lane: const int",float32x4_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlalq_low_f16,"r: float32x4_t, a: float16x8_t, b: float16x8_t",float32x4_t,Floating-point fused multiply-add long to accumulator +FALSE,vfmlsl_high_f16,"r: float32x2_t, a: float16x4_t, b: float16x4_t",float32x2_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlsl_lane_high_f16,"r: float32x2_t, a: float16x4_t, b: float16x4_t, lane: const int",float32x2_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlsl_lane_low_f16,"r: float32x2_t, a: float16x4_t, b: float16x4_t, lane: const int",float32x2_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlsl_laneq_high_f16,"r: float32x2_t, a: float16x4_t, b: float16x8_t, lane: const int",float32x2_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlsl_laneq_low_f16,"r: float32x2_t, a: float16x4_t, b: float16x8_t, lane: const int",float32x2_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlsl_low_f16,"r: float32x2_t, a: float16x4_t, b: float16x4_t",float32x2_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlslq_high_f16,"r: float32x4_t, a: float16x8_t, b: float16x8_t",float32x4_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlslq_lane_high_f16,"r: float32x4_t, a: float16x8_t, b: float16x4_t, lane: const int",float32x4_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlslq_lane_low_f16,"r: float32x4_t, a: float16x8_t, b: float16x4_t, lane: const int",float32x4_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlslq_laneq_high_f16,"r: float32x4_t, a: float16x8_t, b: float16x8_t, lane: const int",float32x4_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlslq_laneq_low_f16,"r: float32x4_t, a: float16x8_t, b: float16x8_t, lane: const int",float32x4_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfmlslq_low_f16,"r: float32x4_t, a: float16x8_t, b: float16x8_t",float32x4_t,Floating-point fused multiply-subtract long from accumulator +FALSE,vfms_f16,"a: float16x4_t, b: float16x4_t, c: float16x4_t",float16x4_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_f32,"a: float32x2_t, b: float32x2_t, c: float32x2_t",float32x2_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_f64,"a: float64x1_t, b: float64x1_t, c: float64x1_t",float64x1_t,Floating-point fused multiply-subtract +FALSE,vfms_lane_f16,"a: float16x4_t, b: float16x4_t, v: float16x4_t, lane: const int",float16x4_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_lane_f32,"a: float32x2_t, b: float32x2_t, v: float32x2_t, lane: const int",float32x2_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_lane_f64,"a: float64x1_t, b: float64x1_t, v: float64x1_t, lane: const int",float64x1_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_laneq_f16,"a: float16x4_t, b: float16x4_t, v: float16x8_t, lane: const int",float16x4_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_laneq_f32,"a: float32x2_t, b: float32x2_t, v: float32x4_t, lane: const int",float32x2_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_laneq_f64,"a: float64x1_t, b: float64x1_t, v: float64x2_t, lane: const int",float64x1_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_n_f16,"a: float16x4_t, b: float16x4_t, n: float16_t",float16x4_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_n_f32,"a: float32x2_t, b: float32x2_t, n: f32",float32x2_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfms_n_f64,"a: float64x1_t, b: float64x1_t, n: float64_t",float64x1_t,Floating-point fused multiply-subtract +FALSE,vfmsd_lane_f64,"a: float64_t, b: float64_t, v: float64x1_t, lane: const int",float64_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsd_laneq_f64,"a: float64_t, b: float64_t, v: float64x2_t, lane: const int",float64_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsh_f16,"a: float16_t, b: float16_t, c: float16_t",float16_t,Floating-point fused multiply-subtract +FALSE,vfmsh_lane_f16,"a: float16_t, b: float16_t, v: float16x4_t, lane: const int",float16_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsh_laneq_f16,"a: float16_t, b: float16_t, v: float16x8_t, lane: const int",float16_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_f16,"a: float16x8_t, b: float16x8_t, c: float16x8_t",float16x8_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_f32,"a: float32x4_t, b: float32x4_t, c: float32x4_t",float32x4_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_f64,"a: float64x2_t, b: float64x2_t, c: float64x2_t",float64x2_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_lane_f16,"a: float16x8_t, b: float16x8_t, v: float16x4_t, lane: const int",float16x8_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_lane_f32,"a: float32x4_t, b: float32x4_t, v: float32x2_t, lane: const int",float32x4_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_lane_f64,"a: float64x2_t, b: float64x2_t, v: float64x1_t, lane: const int",float64x2_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_laneq_f16,"a: float16x8_t, b: float16x8_t, v: float16x8_t, lane: const int",float16x8_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_laneq_f32,"a: float32x4_t, b: float32x4_t, v: float32x4_t, lane: const int",float32x4_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_laneq_f64,"a: float64x2_t, b: float64x2_t, v: float64x2_t, lane: const int",float64x2_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_n_f16,"a: float16x8_t, b: float16x8_t, n: float16_t",float16x8_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_n_f32,"a: float32x4_t, b: float32x4_t, n: f32",float32x4_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmsq_n_f64,"a: float64x2_t, b: float64x2_t, n: float64_t",float64x2_t,Floating-point fused multiply-subtract from accumulator +FALSE,vfmss_lane_f32,"a: f32, b: f32, v: float32x2_t, lane: const int",f32,Floating-point fused multiply-subtract from accumulator +FALSE,vfmss_laneq_f32,"a: f32, b: f32, v: float32x4_t, lane: const int",f32,Floating-point fused multiply-subtract from accumulator +FALSE,vget_high_bf16,a: bfloat16x8_t,bfloat16x4_t,Duplicate vector element to vector or scalar +FALSE,vget_high_f16,a: float16x8_t,float16x4_t,Duplicate vector element to vector or scalar +TRUE,vget_high_f32,a: float32x4_t,float32x2_t,Duplicate vector element to vector or scalar +TRUE,vget_high_f64,a: float64x2_t,float64x1_t,Duplicate vector element to vector or scalar +TRUE,vget_high_p16,a: poly16x8_t,poly16x4_t,Duplicate vector element to vector or scalar +TRUE,vget_high_p64,a: poly64x2_t,poly64x1_t,Duplicate vector element to vector or scalar +TRUE,vget_high_p8,a: poly8x16_t,poly8x8_t,Duplicate vector element to vector or scalar +TRUE,vget_high_s16,a: int16x8_t,int16x4_t,Duplicate vector element to vector or scalar +TRUE,vget_high_s32,a: int32x4_t,int32x2_t,Duplicate vector element to vector or scalar +TRUE,vget_high_s64,a: int64x2_t,int64x1_t,Duplicate vector element to vector or scalar +TRUE,vget_high_s8,a: int8x16_t,int8x8_t,Duplicate vector element to vector or scalar +TRUE,vget_high_u16,a: uint16x8_t,uint16x4_t,Duplicate vector element to vector or scalar +TRUE,vget_high_u32,a: uint32x4_t,uint32x2_t,Duplicate vector element to vector or scalar +TRUE,vget_high_u64,a: uint64x2_t,uint64x1_t,Duplicate vector element to vector or scalar +TRUE,vget_high_u8,a: uint8x16_t,uint8x8_t,Duplicate vector element to vector or scalar +FALSE,vget_lane_bf16,"v: bfloat16x4_t, lane: const int",bfloat16_t,Duplicate vector element to vector or scalar +FALSE,vget_lane_f16,"v: float16x4_t, lane: const int",float16_t,Duplicate vector element to vector or scalar +FALSE,vget_lane_f32,"v: float32x2_t, lane: const int",f32,Duplicate vector element to vector or scalar +FALSE,vget_lane_f64,"v: float64x1_t, lane: const int",float64_t,Duplicate vector element to vector or scalar +FALSE,vget_lane_p16,"v: poly16x4_t, lane: const int",poly16_t,Unsigned move vector element to general-purpose register +FALSE,vget_lane_p64,"v: poly64x1_t, lane: const int",poly64_t,Unsigned move vector element to general-purpose register +FALSE,vget_lane_p8,"v: poly8x8_t, lane: const int",poly8_t,Unsigned move vector element to general-purpose register +FALSE,vget_lane_s16,"v: int16x4_t, lane: const int",i16,Signed move vector element to general-purpose register +FALSE,vget_lane_s32,"v: int32x2_t, lane: const int",i32,Signed move vector element to general-purpose register +FALSE,vget_lane_s64,"v: int64x1_t, lane: const int",i64,Unsigned move vector element to general-purpose register +FALSE,vget_lane_s8,"v: int8x8_t, lane: const int",i8,Signed move vector element to general-purpose register +FALSE,vget_lane_u16,"v: uint16x4_t, lane: const int",u16,Unsigned move vector element to general-purpose register +FALSE,vget_lane_u32,"v: uint32x2_t, lane: const int",u32,Unsigned move vector element to general-purpose register +TRUE,vget_lane_u64,"v: uint64x1_t, lane: const int",u64,Unsigned move vector element to general-purpose register +TRUE,vget_lane_u8,"v: uint8x8_t, lane: const int",u8,Unsigned move vector element to general-purpose register +FALSE,vget_low_bf16,a: bfloat16x8_t,bfloat16x4_t,Duplicate vector element to vector or scalar +FALSE,vget_low_f16,a: float16x8_t,float16x4_t,Duplicate vector element to vector or scalar +TRUE,vget_low_f32,a: float32x4_t,float32x2_t,Duplicate vector element to vector or scalar +TRUE,vget_low_f64,a: float64x2_t,float64x1_t,Duplicate vector element to vector or scalar +TRUE,vget_low_p16,a: poly16x8_t,poly16x4_t,Duplicate vector element to vector or scalar +TRUE,vget_low_p64,a: poly64x2_t,poly64x1_t,Duplicate vector element to vector or scalar +TRUE,vget_low_p8,a: poly8x16_t,poly8x8_t,Duplicate vector element to vector or scalar +TRUE,vget_low_s16,a: int16x8_t,int16x4_t,Duplicate vector element to vector or scalar +TRUE,vget_low_s32,a: int32x4_t,int32x2_t,Duplicate vector element to vector or scalar +TRUE,vget_low_s64,a: int64x2_t,int64x1_t,Duplicate vector element to vector or scalar +TRUE,vget_low_s8,a: int8x16_t,int8x8_t,Duplicate vector element to vector or scalar +TRUE,vget_low_u16,a: uint16x8_t,uint16x4_t,Duplicate vector element to vector or scalar +TRUE,vget_low_u32,a: uint32x4_t,uint32x2_t,Duplicate vector element to vector or scalar +TRUE,vget_low_u64,a: uint64x2_t,uint64x1_t,Duplicate vector element to vector or scalar +TRUE,vget_low_u8,a: uint8x16_t,uint8x8_t,Duplicate vector element to vector or scalar +FALSE,vgetq_lane_bf16,"v: bfloat16x8_t, lane: const int",bfloat16_t,Duplicate vector element to vector or scalar +FALSE,vgetq_lane_f16,"v: float16x8_t, lane: const int",float16_t,Duplicate vector element to vector or scalar +FALSE,vgetq_lane_f32,"v: float32x4_t, lane: const int",f32,Duplicate vector element to vector or scalar +FALSE,vgetq_lane_f64,"v: float64x2_t, lane: const int",float64_t,Duplicate vector element to vector or scalar +FALSE,vgetq_lane_p16,"v: poly16x8_t, lane: const int",poly16_t,Unsigned move vector element to general-purpose register +FALSE,vgetq_lane_p64,"v: poly64x2_t, lane: const int",poly64_t,Unsigned move vector element to general-purpose register +FALSE,vgetq_lane_p8,"v: poly8x16_t, lane: const int",poly8_t,Unsigned move vector element to general-purpose register +FALSE,vgetq_lane_s16,"v: int16x8_t, lane: const int",i16,Signed move vector element to general-purpose register +FALSE,vgetq_lane_s32,"v: int32x4_t, lane: const int",i32,Signed move vector element to general-purpose register +FALSE,vgetq_lane_s64,"v: int64x2_t, lane: const int",i64,Unsigned move vector element to general-purpose register +FALSE,vgetq_lane_s8,"v: int8x16_t, lane: const int",i8,Signed move vector element to general-purpose register +TRUE,vgetq_lane_u16,"v: uint16x8_t, lane: const int",u16,Unsigned move vector element to general-purpose register +TRUE,vgetq_lane_u32,"v: uint32x4_t, lane: const int",u32,Unsigned move vector element to general-purpose register +TRUE,vgetq_lane_u64,"v: uint64x2_t, lane: const int",u64,Unsigned move vector element to general-purpose register +FALSE,vgetq_lane_u8,"v: uint8x16_t, lane: const int",u8,Unsigned move vector element to general-purpose register +TRUE,vhadd_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed halving add +TRUE,vhadd_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed halving add +TRUE,vhadd_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed halving add +TRUE,vhadd_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned halving add +TRUE,vhadd_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned halving add +TRUE,vhadd_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned halving add +TRUE,vhaddq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed halving add +TRUE,vhaddq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed halving add +TRUE,vhaddq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed halving add +TRUE,vhaddq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned halving add +TRUE,vhaddq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned halving add +TRUE,vhaddq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned halving add +TRUE,vhsub_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed halving subtract +TRUE,vhsub_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed halving subtract +TRUE,vhsub_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed halving subtract +TRUE,vhsub_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned halving subtract +TRUE,vhsub_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned halving subtract +TRUE,vhsub_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned halving subtract +TRUE,vhsubq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed halving subtract +TRUE,vhsubq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed halving subtract +TRUE,vhsubq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed halving subtract +TRUE,vhsubq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned halving subtract +TRUE,vhsubq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned halving subtract +TRUE,vhsubq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned halving subtract +FALSE,vld1_bf16,ptr: *const bfloat16_t,bfloat16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_bf16_x2,ptr: *const bfloat16_t,bfloat16x4x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_bf16_x3,ptr: *const bfloat16_t,bfloat16x4x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_bf16_x4,ptr: *const bfloat16_t,bfloat16x4x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_dup_bf16,ptr: *const bfloat16_t,bfloat16x4_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_f16,ptr: *const float16_t,float16x4_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_f32,ptr: *const f32,float32x2_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_f64,ptr: *const float64_t,float64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_dup_p16,ptr: *const poly16_t,poly16x4_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_p64,ptr: *const poly64_t,poly64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_dup_p8,ptr: *const poly8_t,poly8x8_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_s16,ptr: *const i16,int16x4_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_s32,ptr: *const i32,int32x2_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_s64,ptr: *const i64,int64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_dup_s8,ptr: *const i8,int8x8_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_u16,ptr: *const u16,uint16x4_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_u32,ptr: *const u32,uint32x2_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_dup_u64,ptr: *const u64,uint64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_dup_u8,ptr: *const u8,uint8x8_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1_f16,ptr: *const float16_t,float16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f16_x2,ptr: *const float16_t,float16x4x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f16_x3,ptr: *const float16_t,float16x4x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f16_x4,ptr: *const float16_t,float16x4x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f32,ptr: *const f32,float32x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f32_x2,ptr: *const f32,float32x2x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f32_x3,ptr: *const f32,float32x2x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f32_x4,ptr: *const f32,float32x2x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f64,ptr: *const float64_t,float64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f64_x2,ptr: *const float64_t,float64x1x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f64_x3,ptr: *const float64_t,float64x1x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_f64_x4,ptr: *const float64_t,float64x1x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_bf16,"ptr: *const bfloat16_t, src: bfloat16x4_t, lane: const int",bfloat16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_f16,"ptr: *const float16_t, src: float16x4_t, lane: const int",float16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_f32,"ptr: *const f32, src: float32x2_t, lane: const int",float32x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_f64,"ptr: *const float64_t, src: float64x1_t, lane: const int",float64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_p16,"ptr: *const poly16_t, src: poly16x4_t, lane: const int",poly16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_p64,"ptr: *const poly64_t, src: poly64x1_t, lane: const int",poly64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_p8,"ptr: *const poly8_t, src: poly8x8_t, lane: const int",poly8x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_s16,"ptr: *const i16, src: int16x4_t, lane: const int",int16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_s32,"ptr: *const i32, src: int32x2_t, lane: const int",int32x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_s64,"ptr: *const i64, src: int64x1_t, lane: const int",int64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_s8,"ptr: *const i8, src: int8x8_t, lane: const int",int8x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_u16,"ptr: *const u16, src: uint16x4_t, lane: const int",uint16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_u32,"ptr: *const u32, src: uint32x2_t, lane: const int",uint32x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_u64,"ptr: *const u64, src: uint64x1_t, lane: const int",uint64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_lane_u8,"ptr: *const u8, src: uint8x8_t, lane: const int",uint8x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p16,ptr: *const poly16_t,poly16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p16_x2,ptr: *const poly16_t,poly16x4x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p16_x3,ptr: *const poly16_t,poly16x4x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p16_x4,ptr: *const poly16_t,poly16x4x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p64,ptr: *const poly64_t,poly64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p64_x2,ptr: *const poly64_t,poly64x1x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p64_x3,ptr: *const poly64_t,poly64x1x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p64_x4,ptr: *const poly64_t,poly64x1x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p8,ptr: *const poly8_t,poly8x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p8_x2,ptr: *const poly8_t,poly8x8x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p8_x3,ptr: *const poly8_t,poly8x8x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_p8_x4,ptr: *const poly8_t,poly8x8x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s16,ptr: *const i16,int16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s16_x2,ptr: *const i16,int16x4x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s16_x3,ptr: *const i16,int16x4x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s16_x4,ptr: *const i16,int16x4x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s32,ptr: *const i32,int32x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s32_x2,ptr: *const i32,int32x2x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s32_x3,ptr: *const i32,int32x2x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s32_x4,ptr: *const i32,int32x2x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s64,ptr: *const i64,int64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s64_x2,ptr: *const i64,int64x1x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s64_x3,ptr: *const i64,int64x1x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s64_x4,ptr: *const i64,int64x1x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s8,ptr: *const i8,int8x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s8_x2,ptr: *const i8,int8x8x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s8_x3,ptr: *const i8,int8x8x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_s8_x4,ptr: *const i8,int8x8x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u16,ptr: *const u16,uint16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u16_x2,ptr: *const u16,uint16x4x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u16_x3,ptr: *const u16,uint16x4x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u16_x4,ptr: *const u16,uint16x4x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u32,ptr: *const u32,uint32x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u32_x2,ptr: *const u32,uint32x2x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u32_x3,ptr: *const u32,uint32x2x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u32_x4,ptr: *const u32,uint32x2x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u64,ptr: *const u64,uint64x1_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u64_x2,ptr: *const u64,uint64x1x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u64_x3,ptr: *const u64,uint64x1x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u64_x4,ptr: *const u64,uint64x1x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u8,ptr: *const u8,uint8x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u8_x2,ptr: *const u8,uint8x8x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u8_x3,ptr: *const u8,uint8x8x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1_u8_x4,ptr: *const u8,uint8x8x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_bf16,ptr: *const bfloat16_t,bfloat16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_bf16_x2,ptr: *const bfloat16_t,bfloat16x8x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_bf16_x3,ptr: *const bfloat16_t,bfloat16x8x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_bf16_x4,ptr: *const bfloat16_t,bfloat16x8x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_dup_bf16,ptr: *const bfloat16_t,bfloat16x8_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_f16,ptr: *const float16_t,float16x8_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_f32,ptr: *const f32,float32x4_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_f64,ptr: *const float64_t,float64x2_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_p16,ptr: *const poly16_t,poly16x8_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_p64,ptr: *const poly64_t,poly64x2_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_p8,ptr: *const poly8_t,poly8x16_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_s16,ptr: *const i16,int16x8_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_s32,ptr: *const i32,int32x4_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_s64,ptr: *const i64,int64x2_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_s8,ptr: *const i8,int8x16_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_u16,ptr: *const u16,uint16x8_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_u32,ptr: *const u32,uint32x4_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_u64,ptr: *const u64,uint64x2_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_dup_u8,ptr: *const u8,uint8x16_t,Load one single-element structure and replicate to all lanes (of one register) +FALSE,vld1q_f16,ptr: *const float16_t,float16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f16_x2,ptr: *const float16_t,float16x8x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f16_x3,ptr: *const float16_t,float16x8x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f16_x4,ptr: *const float16_t,float16x8x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f32,ptr: *const f32,float32x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f32_x2,ptr: *const f32,float32x4x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f32_x3,ptr: *const f32,float32x4x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f32_x4,ptr: *const f32,float32x4x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f64,ptr: *const float64_t,float64x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f64_x2,ptr: *const float64_t,float64x2x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f64_x3,ptr: *const float64_t,float64x2x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_f64_x4,ptr: *const float64_t,float64x2x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_bf16,"ptr: *const bfloat16_t, src: bfloat16x8_t, lane: const int",bfloat16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_f16,"ptr: *const float16_t, src: float16x8_t, lane: const int",float16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_f32,"ptr: *const f32, src: float32x4_t, lane: const int",float32x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_f64,"ptr: *const float64_t, src: float64x2_t, lane: const int",float64x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_p16,"ptr: *const poly16_t, src: poly16x8_t, lane: const int",poly16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_p64,"ptr: *const poly64_t, src: poly64x2_t, lane: const int",poly64x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_p8,"ptr: *const poly8_t, src: poly8x16_t, lane: const int",poly8x16_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_s16,"ptr: *const i16, src: int16x8_t, lane: const int",int16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_s32,"ptr: *const i32, src: int32x4_t, lane: const int",int32x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_s64,"ptr: *const i64, src: int64x2_t, lane: const int",int64x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_s8,"ptr: *const i8, src: int8x16_t, lane: const int",int8x16_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_u16,"ptr: *const u16, src: uint16x8_t, lane: const int",uint16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_u32,"ptr: *const u32, src: uint32x4_t, lane: const int",uint32x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_u64,"ptr: *const u64, src: uint64x2_t, lane: const int",uint64x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_lane_u8,"ptr: *const u8, src: uint8x16_t, lane: const int",uint8x16_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p16,ptr: *const poly16_t,poly16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p16_x2,ptr: *const poly16_t,poly16x8x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p16_x3,ptr: *const poly16_t,poly16x8x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p16_x4,ptr: *const poly16_t,poly16x8x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p64,ptr: *const poly64_t,poly64x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p64_x2,ptr: *const poly64_t,poly64x2x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p64_x3,ptr: *const poly64_t,poly64x2x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p64_x4,ptr: *const poly64_t,poly64x2x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p8,ptr: *const poly8_t,poly8x16_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p8_x2,ptr: *const poly8_t,poly8x16x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p8_x3,ptr: *const poly8_t,poly8x16x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_p8_x4,ptr: *const poly8_t,poly8x16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s16,ptr: *const i16,int16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s16_x2,ptr: *const i16,int16x8x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s16_x3,ptr: *const i16,int16x8x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s16_x4,ptr: *const i16,int16x8x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s32,ptr: *const i32,int32x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s32_x2,ptr: *const i32,int32x4x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s32_x3,ptr: *const i32,int32x4x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s32_x4,ptr: *const i32,int32x4x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s64,ptr: *const i64,int64x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s64_x2,ptr: *const i64,int64x2x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s64_x3,ptr: *const i64,int64x2x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s64_x4,ptr: *const i64,int64x2x4_t,"Load multiple single-element structures to one, two, three, or four registers" +TRUE,vld1q_s8,ptr: *const i8,int8x16_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s8_x2,ptr: *const i8,int8x16x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s8_x3,ptr: *const i8,int8x16x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_s8_x4,ptr: *const i8,int8x16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u16,ptr: *const u16,uint16x8_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u16_x2,ptr: *const u16,uint16x8x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u16_x3,ptr: *const u16,uint16x8x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u16_x4,ptr: *const u16,uint16x8x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u32,ptr: *const u32,uint32x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u32_x2,ptr: *const u32,uint32x4x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u32_x3,ptr: *const u32,uint32x4x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u32_x4,ptr: *const u32,uint32x4x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u64,ptr: *const u64,uint64x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u64_x2,ptr: *const u64,uint64x2x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u64_x3,ptr: *const u64,uint64x2x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u64_x4,ptr: *const u64,uint64x2x4_t,"Load multiple single-element structures to one, two, three, or four registers" +TRUE,vld1q_u8,ptr: *const u8,uint8x16_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u8_x2,ptr: *const u8,uint8x16x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u8_x3,ptr: *const u8,uint8x16x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld1q_u8_x4,ptr: *const u8,uint8x16x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld2_bf16,ptr: *const bfloat16_t,bfloat16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_dup_bf16,ptr: *const bfloat16_t,bfloat16x4x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_f16,ptr: *const float16_t,float16x4x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_f32,ptr: *const f32,float32x2x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_f64,ptr: *const float64_t,float64x1x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_p16,ptr: *const poly16_t,poly16x4x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_p64,ptr: *const poly64_t,poly64x1x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_p8,ptr: *const poly8_t,poly8x8x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_s16,ptr: *const i16,int16x4x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_s32,ptr: *const i32,int32x2x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_s64,ptr: *const i64,int64x1x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_s8,ptr: *const i8,int8x8x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_u16,ptr: *const u16,uint16x4x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_u32,ptr: *const u32,uint32x2x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_u64,ptr: *const u64,uint64x1x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_dup_u8,ptr: *const u8,uint8x8x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2_f16,ptr: *const float16_t,float16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_f32,ptr: *const f32,float32x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_f64,ptr: *const float64_t,float64x1x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld2_lane_bf16,"ptr: *const bfloat16_t, src: bfloat16x4x2_t, lane: const int",bfloat16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_f16,"ptr: *const float16_t, src: float16x4x2_t, lane: const int",float16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_f32,"ptr: *const f32, src: float32x2x2_t, lane: const int",float32x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_f64,"ptr: *const float64_t, src: float64x1x2_t, lane: const int",float64x1x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_p16,"ptr: *const poly16_t, src: poly16x4x2_t, lane: const int",poly16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_p64,"ptr: *const poly64_t, src: poly64x1x2_t, lane: const int",poly64x1x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_p8,"ptr: *const poly8_t, src: poly8x8x2_t, lane: const int",poly8x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_s16,"ptr: *const i16, src: int16x4x2_t, lane: const int",int16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_s32,"ptr: *const i32, src: int32x2x2_t, lane: const int",int32x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_s64,"ptr: *const i64, src: int64x1x2_t, lane: const int",int64x1x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_s8,"ptr: *const i8, src: int8x8x2_t, lane: const int",int8x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_u16,"ptr: *const u16, src: uint16x4x2_t, lane: const int",uint16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_u32,"ptr: *const u32, src: uint32x2x2_t, lane: const int",uint32x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_u64,"ptr: *const u64, src: uint64x1x2_t, lane: const int",uint64x1x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_lane_u8,"ptr: *const u8, src: uint8x8x2_t, lane: const int",uint8x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_p16,ptr: *const poly16_t,poly16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_p64,ptr: *const poly64_t,poly64x1x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld2_p8,ptr: *const poly8_t,poly8x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_s16,ptr: *const i16,int16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_s32,ptr: *const i32,int32x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_s64,ptr: *const i64,int64x1x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld2_s8,ptr: *const i8,int8x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_u16,ptr: *const u16,uint16x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_u32,ptr: *const u32,uint32x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2_u64,ptr: *const u64,uint64x1x2_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld2_u8,ptr: *const u8,uint8x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_bf16,ptr: *const bfloat16_t,bfloat16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_dup_bf16,ptr: *const bfloat16_t,bfloat16x8x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_f16,ptr: *const float16_t,float16x8x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_f32,ptr: *const f32,float32x4x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_f64,ptr: *const float64_t,float64x2x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_p16,ptr: *const poly16_t,poly16x8x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_p64,ptr: *const poly64_t,poly64x2x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_p8,ptr: *const poly8_t,poly8x16x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_s16,ptr: *const i16,int16x8x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_s32,ptr: *const i32,int32x4x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_s64,ptr: *const i64,int64x2x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_s8,ptr: *const i8,int8x16x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_u16,ptr: *const u16,uint16x8x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_u32,ptr: *const u32,uint32x4x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_u64,ptr: *const u64,uint64x2x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_dup_u8,ptr: *const u8,uint8x16x2_t,Load single 2-element structure and replicate to all lanes of two registers +FALSE,vld2q_f16,ptr: *const float16_t,float16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_f32,ptr: *const f32,float32x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_f64,ptr: *const float64_t,float64x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_bf16,"ptr: *const bfloat16_t, src: bfloat16x8x2_t, lane: const int",bfloat16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_f16,"ptr: *const float16_t, src: float16x8x2_t, lane: const int",float16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_f32,"ptr: *const f32, src: float32x4x2_t, lane: const int",float32x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_f64,"ptr: *const float64_t, src: float64x2x2_t, lane: const int",float64x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_p16,"ptr: *const poly16_t, src: poly16x8x2_t, lane: const int",poly16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_p64,"ptr: *const poly64_t, src: poly64x2x2_t, lane: const int",poly64x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_p8,"ptr: *const poly8_t, src: poly8x16x2_t, lane: const int",poly8x16x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_s16,"ptr: *const i16, src: int16x8x2_t, lane: const int",int16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_s32,"ptr: *const i32, src: int32x4x2_t, lane: const int",int32x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_s64,"ptr: *const i64, src: int64x2x2_t, lane: const int",int64x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_s8,"ptr: *const i8, src: int8x16x2_t, lane: const int",int8x16x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_u16,"ptr: *const u16, src: uint16x8x2_t, lane: const int",uint16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_u32,"ptr: *const u32, src: uint32x4x2_t, lane: const int",uint32x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_u64,"ptr: *const u64, src: uint64x2x2_t, lane: const int",uint64x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_lane_u8,"ptr: *const u8, src: uint8x16x2_t, lane: const int",uint8x16x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_p16,ptr: *const poly16_t,poly16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_p64,ptr: *const poly64_t,poly64x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_p8,ptr: *const poly8_t,poly8x16x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_s16,ptr: *const i16,int16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_s32,ptr: *const i32,int32x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_s64,ptr: *const i64,int64x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_s8,ptr: *const i8,int8x16x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_u16,ptr: *const u16,uint16x8x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_u32,ptr: *const u32,uint32x4x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_u64,ptr: *const u64,uint64x2x2_t,Load multiple 2-element structures to two registers +FALSE,vld2q_u8,ptr: *const u8,uint8x16x2_t,Load multiple 2-element structures to two registers +FALSE,vld3_bf16,ptr: *const bfloat16_t,bfloat16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_dup_bf16,ptr: *const bfloat16_t,bfloat16x4x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_f16,ptr: *const float16_t,float16x4x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_f32,ptr: *const f32,float32x2x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_f64,ptr: *const float64_t,float64x1x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_p16,ptr: *const poly16_t,poly16x4x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_p64,ptr: *const poly64_t,poly64x1x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_p8,ptr: *const poly8_t,poly8x8x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_s16,ptr: *const i16,int16x4x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_s32,ptr: *const i32,int32x2x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_s64,ptr: *const i64,int64x1x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_s8,ptr: *const i8,int8x8x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_u16,ptr: *const u16,uint16x4x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_u32,ptr: *const u32,uint32x2x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_u64,ptr: *const u64,uint64x1x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_dup_u8,ptr: *const u8,uint8x8x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3_f16,ptr: *const float16_t,float16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_f32,ptr: *const f32,float32x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_f64,ptr: *const float64_t,float64x1x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld3_lane_bf16,"ptr: *const bfloat16_t, src: bfloat16x4x3_t, lane: const int",bfloat16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_f16,"ptr: *const float16_t, src: float16x4x3_t, lane: const int",float16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_f32,"ptr: *const f32, src: float32x2x3_t, lane: const int",float32x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_f64,"ptr: *const float64_t, src: float64x1x3_t, lane: const int",float64x1x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_p16,"ptr: *const poly16_t, src: poly16x4x3_t, lane: const int",poly16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_p64,"ptr: *const poly64_t, src: poly64x1x3_t, lane: const int",poly64x1x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_p8,"ptr: *const poly8_t, src: poly8x8x3_t, lane: const int",poly8x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_s16,"ptr: *const i16, src: int16x4x3_t, lane: const int",int16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_s32,"ptr: *const i32, src: int32x2x3_t, lane: const int",int32x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_s64,"ptr: *const i64, src: int64x1x3_t, lane: const int",int64x1x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_s8,"ptr: *const i8, src: int8x8x3_t, lane: const int",int8x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_u16,"ptr: *const u16, src: uint16x4x3_t, lane: const int",uint16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_u32,"ptr: *const u32, src: uint32x2x3_t, lane: const int",uint32x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_u64,"ptr: *const u64, src: uint64x1x3_t, lane: const int",uint64x1x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_lane_u8,"ptr: *const u8, src: uint8x8x3_t, lane: const int",uint8x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_p16,ptr: *const poly16_t,poly16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_p64,ptr: *const poly64_t,poly64x1x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld3_p8,ptr: *const poly8_t,poly8x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_s16,ptr: *const i16,int16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_s32,ptr: *const i32,int32x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_s64,ptr: *const i64,int64x1x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld3_s8,ptr: *const i8,int8x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_u16,ptr: *const u16,uint16x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_u32,ptr: *const u32,uint32x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3_u64,ptr: *const u64,uint64x1x3_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld3_u8,ptr: *const u8,uint8x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_bf16,ptr: *const bfloat16_t,bfloat16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_dup_bf16,ptr: *const bfloat16_t,bfloat16x8x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_f16,ptr: *const float16_t,float16x8x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_f32,ptr: *const f32,float32x4x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_f64,ptr: *const float64_t,float64x2x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_p16,ptr: *const poly16_t,poly16x8x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_p64,ptr: *const poly64_t,poly64x2x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_p8,ptr: *const poly8_t,poly8x16x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_s16,ptr: *const i16,int16x8x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_s32,ptr: *const i32,int32x4x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_s64,ptr: *const i64,int64x2x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_s8,ptr: *const i8,int8x16x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_u16,ptr: *const u16,uint16x8x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_u32,ptr: *const u32,uint32x4x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_u64,ptr: *const u64,uint64x2x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_dup_u8,ptr: *const u8,uint8x16x3_t,Load single 3-element structure and replicate to all lanes of three registers +FALSE,vld3q_f16,ptr: *const float16_t,float16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_f32,ptr: *const f32,float32x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_f64,ptr: *const float64_t,float64x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_bf16,"ptr: *const bfloat16_t, src: bfloat16x8x3_t, lane: const int",bfloat16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_f16,"ptr: *const float16_t, src: float16x8x3_t, lane: const int",float16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_f32,"ptr: *const f32, src: float32x4x3_t, lane: const int",float32x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_f64,"ptr: *const float64_t, src: float64x2x3_t, lane: const int",float64x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_p16,"ptr: *const poly16_t, src: poly16x8x3_t, lane: const int",poly16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_p64,"ptr: *const poly64_t, src: poly64x2x3_t, lane: const int",poly64x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_p8,"ptr: *const poly8_t, src: poly8x16x3_t, lane: const int",poly8x16x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_s16,"ptr: *const i16, src: int16x8x3_t, lane: const int",int16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_s32,"ptr: *const i32, src: int32x4x3_t, lane: const int",int32x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_s64,"ptr: *const i64, src: int64x2x3_t, lane: const int",int64x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_s8,"ptr: *const i8, src: int8x16x3_t, lane: const int",int8x16x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_u16,"ptr: *const u16, src: uint16x8x3_t, lane: const int",uint16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_u32,"ptr: *const u32, src: uint32x4x3_t, lane: const int",uint32x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_u64,"ptr: *const u64, src: uint64x2x3_t, lane: const int",uint64x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_lane_u8,"ptr: *const u8, src: uint8x16x3_t, lane: const int",uint8x16x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_p16,ptr: *const poly16_t,poly16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_p64,ptr: *const poly64_t,poly64x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_p8,ptr: *const poly8_t,poly8x16x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_s16,ptr: *const i16,int16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_s32,ptr: *const i32,int32x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_s64,ptr: *const i64,int64x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_s8,ptr: *const i8,int8x16x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_u16,ptr: *const u16,uint16x8x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_u32,ptr: *const u32,uint32x4x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_u64,ptr: *const u64,uint64x2x3_t,Load multiple 3-element structures to three registers +FALSE,vld3q_u8,ptr: *const u8,uint8x16x3_t,Load multiple 3-element structures to three registers +FALSE,vld4_bf16,ptr: *const bfloat16_t,bfloat16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_dup_bf16,ptr: *const bfloat16_t,bfloat16x4x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_f16,ptr: *const float16_t,float16x4x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_f32,ptr: *const f32,float32x2x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_f64,ptr: *const float64_t,float64x1x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_p16,ptr: *const poly16_t,poly16x4x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_p64,ptr: *const poly64_t,poly64x1x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_p8,ptr: *const poly8_t,poly8x8x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_s16,ptr: *const i16,int16x4x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_s32,ptr: *const i32,int32x2x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_s64,ptr: *const i64,int64x1x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_s8,ptr: *const i8,int8x8x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_u16,ptr: *const u16,uint16x4x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_u32,ptr: *const u32,uint32x2x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_u64,ptr: *const u64,uint64x1x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_dup_u8,ptr: *const u8,uint8x8x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4_f16,ptr: *const float16_t,float16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_f32,ptr: *const f32,float32x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_f64,ptr: *const float64_t,float64x1x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld4_lane_bf16,"ptr: *const bfloat16_t, src: bfloat16x4x4_t, lane: const int",bfloat16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_f16,"ptr: *const float16_t, src: float16x4x4_t, lane: const int",float16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_f32,"ptr: *const f32, src: float32x2x4_t, lane: const int",float32x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_f64,"ptr: *const float64_t, src: float64x1x4_t, lane: const int",float64x1x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_p16,"ptr: *const poly16_t, src: poly16x4x4_t, lane: const int",poly16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_p64,"ptr: *const poly64_t, src: poly64x1x4_t, lane: const int",poly64x1x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_p8,"ptr: *const poly8_t, src: poly8x8x4_t, lane: const int",poly8x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_s16,"ptr: *const i16, src: int16x4x4_t, lane: const int",int16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_s32,"ptr: *const i32, src: int32x2x4_t, lane: const int",int32x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_s64,"ptr: *const i64, src: int64x1x4_t, lane: const int",int64x1x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_s8,"ptr: *const i8, src: int8x8x4_t, lane: const int",int8x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_u16,"ptr: *const u16, src: uint16x4x4_t, lane: const int",uint16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_u32,"ptr: *const u32, src: uint32x2x4_t, lane: const int",uint32x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_u64,"ptr: *const u64, src: uint64x1x4_t, lane: const int",uint64x1x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_lane_u8,"ptr: *const u8, src: uint8x8x4_t, lane: const int",uint8x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_p16,ptr: *const poly16_t,poly16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_p64,ptr: *const poly64_t,poly64x1x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld4_p8,ptr: *const poly8_t,poly8x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_s16,ptr: *const i16,int16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_s32,ptr: *const i32,int32x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_s64,ptr: *const i64,int64x1x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld4_s8,ptr: *const i8,int8x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_u16,ptr: *const u16,uint16x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_u32,ptr: *const u32,uint32x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4_u64,ptr: *const u64,uint64x1x4_t,"Load multiple single-element structures to one, two, three, or four registers" +FALSE,vld4_u8,ptr: *const u8,uint8x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_bf16,ptr: *const bfloat16_t,bfloat16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_dup_bf16,ptr: *const bfloat16_t,bfloat16x8x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_f16,ptr: *const float16_t,float16x8x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_f32,ptr: *const f32,float32x4x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_f64,ptr: *const float64_t,float64x2x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_p16,ptr: *const poly16_t,poly16x8x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_p64,ptr: *const poly64_t,poly64x2x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_p8,ptr: *const poly8_t,poly8x16x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_s16,ptr: *const i16,int16x8x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_s32,ptr: *const i32,int32x4x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_s64,ptr: *const i64,int64x2x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_s8,ptr: *const i8,int8x16x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_u16,ptr: *const u16,uint16x8x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_u32,ptr: *const u32,uint32x4x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_u64,ptr: *const u64,uint64x2x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_dup_u8,ptr: *const u8,uint8x16x4_t,Load single 4-element structure and replicate to all lanes of four registers +FALSE,vld4q_f16,ptr: *const float16_t,float16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_f32,ptr: *const f32,float32x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_f64,ptr: *const float64_t,float64x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_bf16,"ptr: *const bfloat16_t, src: bfloat16x8x4_t, lane: const int",bfloat16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_f16,"ptr: *const float16_t, src: float16x8x4_t, lane: const int",float16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_f32,"ptr: *const f32, src: float32x4x4_t, lane: const int",float32x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_f64,"ptr: *const float64_t, src: float64x2x4_t, lane: const int",float64x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_p16,"ptr: *const poly16_t, src: poly16x8x4_t, lane: const int",poly16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_p64,"ptr: *const poly64_t, src: poly64x2x4_t, lane: const int",poly64x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_p8,"ptr: *const poly8_t, src: poly8x16x4_t, lane: const int",poly8x16x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_s16,"ptr: *const i16, src: int16x8x4_t, lane: const int",int16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_s32,"ptr: *const i32, src: int32x4x4_t, lane: const int",int32x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_s64,"ptr: *const i64, src: int64x2x4_t, lane: const int",int64x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_s8,"ptr: *const i8, src: int8x16x4_t, lane: const int",int8x16x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_u16,"ptr: *const u16, src: uint16x8x4_t, lane: const int",uint16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_u32,"ptr: *const u32, src: uint32x4x4_t, lane: const int",uint32x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_u64,"ptr: *const u64, src: uint64x2x4_t, lane: const int",uint64x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_lane_u8,"ptr: *const u8, src: uint8x16x4_t, lane: const int",uint8x16x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_p16,ptr: *const poly16_t,poly16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_p64,ptr: *const poly64_t,poly64x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_p8,ptr: *const poly8_t,poly8x16x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_s16,ptr: *const i16,int16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_s32,ptr: *const i32,int32x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_s64,ptr: *const i64,int64x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_s8,ptr: *const i8,int8x16x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_u16,ptr: *const u16,uint16x8x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_u32,ptr: *const u32,uint32x4x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_u64,ptr: *const u64,uint64x2x4_t,Load multiple 4-element structures to four registers +FALSE,vld4q_u8,ptr: *const u8,uint8x16x4_t,Load multiple 4-element structures to four registers +FALSE,vldrq_p128,ptr: *const poly128_t,poly128_t,Load SIMD&FP register (immediate offset) +FALSE,vmax_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point maximum +TRUE,vmax_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point maximum +TRUE,vmax_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point maximum +TRUE,vmax_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed maximum +TRUE,vmax_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed maximum +TRUE,vmax_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed maximum +TRUE,vmax_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned maximum +TRUE,vmax_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned maximum +TRUE,vmax_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned maximum +FALSE,vmaxh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point maximum +FALSE,vmaxnm_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point maximum number +TRUE,vmaxnm_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point maximum number +TRUE,vmaxnm_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point maximum number +FALSE,vmaxnmh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point maximum number +FALSE,vmaxnmq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point maximum number +TRUE,vmaxnmq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point maximum number +TRUE,vmaxnmq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point maximum number +FALSE,vmaxnmv_f16,a: float16x4_t,float16_t,Floating-point maximum number pairwise +FALSE,vmaxnmv_f32,a: float32x2_t,f32,Floating-point maximum number pairwise +FALSE,vmaxnmvq_f16,a: float16x8_t,float16_t,Floating-point maximum number pairwise +FALSE,vmaxnmvq_f32,a: float32x4_t,f32,Floating-point maximum number across vector +FALSE,vmaxnmvq_f64,a: float64x2_t,float64_t,Floating-point maximum number pairwise +FALSE,vmaxq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point maximum +TRUE,vmaxq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point maximum +TRUE,vmaxq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point maximum +TRUE,vmaxq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed maximum +TRUE,vmaxq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed maximum +TRUE,vmaxq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed maximum +TRUE,vmaxq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned maximum +TRUE,vmaxq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned maximum +TRUE,vmaxq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned maximum +FALSE,vmaxv_f16,a: float16x4_t,float16_t,Floating-point maximum pairwise +TRUE,vmaxv_f32,a: float32x2_t,f32,Floating-point maximum pairwise +TRUE,vmaxv_s16,a: int16x4_t,i16,Signed maximum across vector +TRUE,vmaxv_s32,a: int32x2_t,i32,Signed maximum pairwise +TRUE,vmaxv_s8,a: int8x8_t,i8,Signed maximum across vector +TRUE,vmaxv_u16,a: uint16x4_t,u16,Unsigned maximum across vector +TRUE,vmaxv_u32,a: uint32x2_t,u32,Unsigned maximum pairwise +TRUE,vmaxv_u8,a: uint8x8_t,u8,Unsigned maximum across vector +FALSE,vmaxvq_f16,a: float16x8_t,float16_t,Floating-point maximum pairwise +TRUE,vmaxvq_f32,a: float32x4_t,f32,Floating-point maximum across vector +TRUE,vmaxvq_f64,a: float64x2_t,float64_t,Floating-point maximum pairwise +TRUE,vmaxvq_s16,a: int16x8_t,i16,Signed maximum across vector +TRUE,vmaxvq_s32,a: int32x4_t,i32,Signed maximum across vector +TRUE,vmaxvq_s8,a: int8x16_t,i8,Signed maximum across vector +TRUE,vmaxvq_u16,a: uint16x8_t,u16,Unsigned maximum across vector +TRUE,vmaxvq_u32,a: uint32x4_t,u32,Unsigned maximum across vector +TRUE,vmaxvq_u8,a: uint8x16_t,u8,Unsigned maximum across vector +FALSE,vmin_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point minimum +TRUE,vmin_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point minimum +TRUE,vmin_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point minimum +TRUE,vmin_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed minimum +TRUE,vmin_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed minimum +TRUE,vmin_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed minimum +TRUE,vmin_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned minimum +TRUE,vmin_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned minimum +TRUE,vmin_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned minimum +FALSE,vminh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point minimum +FALSE,vminnm_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point minimum number +FALSE,vminnm_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point minimum number +FALSE,vminnm_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point minimum number +FALSE,vminnmh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point minimum number +FALSE,vminnmq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point minimum number +FALSE,vminnmq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point minimum number +FALSE,vminnmq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point minimum number +FALSE,vminnmv_f16,a: float16x4_t,float16_t,Floating-point minimum number pairwise +FALSE,vminnmv_f32,a: float32x2_t,f32,Floating-point minimum number pairwise +FALSE,vminnmvq_f16,a: float16x8_t,float16_t,Floating-point minimum number pairwise +FALSE,vminnmvq_f32,a: float32x4_t,f32,Floating-point minimum number across vector +FALSE,vminnmvq_f64,a: float64x2_t,float64_t,Floating-point minimum number pairwise +FALSE,vminq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point minimum +TRUE,vminq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point minimum +FALSE,vminq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point minimum +TRUE,vminq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed minimum +TRUE,vminq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed minimum +TRUE,vminq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed minimum +TRUE,vminq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned minimum +TRUE,vminq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned minimum +TRUE,vminq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned minimum +FALSE,vminv_f16,a: float16x4_t,float16_t,Floating-point minimum pairwise +TRUE,vminv_f32,a: float32x2_t,f32,Floating-point minimum pairwise +TRUE,vminv_s16,a: int16x4_t,i16,Signed minimum across vector +TRUE,vminv_s32,a: int32x2_t,i32,Signed minimum pairwise +TRUE,vminv_s8,a: int8x8_t,i8,Signed minimum across vector +TRUE,vminv_u16,a: uint16x4_t,u16,Unsigned minimum across vector +TRUE,vminv_u32,a: uint32x2_t,u32,Unsigned minimum pairwise +TRUE,vminv_u8,a: uint8x8_t,u8,Unsigned minimum across vector +FALSE,vminvq_f16,a: float16x8_t,float16_t,Floating-point minimum pairwise +TRUE,vminvq_f32,a: float32x4_t,f32,Floating-point minimum across vector +TRUE,vminvq_f64,a: float64x2_t,float64_t,Floating-point minimum pairwise +TRUE,vminvq_s16,a: int16x8_t,i16,Signed minimum across vector +TRUE,vminvq_s32,a: int32x4_t,i32,Signed minimum across vector +TRUE,vminvq_s8,a: int8x16_t,i8,Signed minimum across vector +TRUE,vminvq_u16,a: uint16x8_t,u16,Unsigned minimum across vector +TRUE,vminvq_u32,a: uint32x4_t,u32,Unsigned minimum across vector +TRUE,vminvq_u8,a: uint8x16_t,u8,Unsigned minimum across vector +TRUE,vmla_f32,"a: float32x2_t, b: float32x2_t, c: float32x2_t",float32x2_t,Floating-point multiply-add to accumulator +TRUE,vmla_f64,"a: float64x1_t, b: float64x1_t, c: float64x1_t",float64x1_t,Floating-point multiply-add to accumulator +FALSE,vmla_lane_f32,"a: float32x2_t, b: float32x2_t, v: float32x2_t, lane: const int",float32x2_t,Vector multiply accumulate with scalar +FALSE,vmla_lane_s16,"a: int16x4_t, b: int16x4_t, v: int16x4_t, lane: const int",int16x4_t,Vector multiply accumulate with scalar +FALSE,vmla_lane_s32,"a: int32x2_t, b: int32x2_t, v: int32x2_t, lane: const int",int32x2_t,Vector multiply accumulate with scalar +FALSE,vmla_lane_u16,"a: uint16x4_t, b: uint16x4_t, v: uint16x4_t, lane: const int",uint16x4_t,Vector multiply accumulate with scalar +FALSE,vmla_lane_u32,"a: uint32x2_t, b: uint32x2_t, v: uint32x2_t, lane: const int",uint32x2_t,Vector multiply accumulate with scalar +FALSE,vmla_laneq_f32,"a: float32x2_t, b: float32x2_t, v: float32x4_t, lane: const int",float32x2_t,Multiply-Add to accumulator +FALSE,vmla_laneq_s16,"a: int16x4_t, b: int16x4_t, v: int16x8_t, lane: const int",int16x4_t,Multiply-add to accumulator +FALSE,vmla_laneq_s32,"a: int32x2_t, b: int32x2_t, v: int32x4_t, lane: const int",int32x2_t,Multiply-add to accumulator +FALSE,vmla_laneq_u16,"a: uint16x4_t, b: uint16x4_t, v: uint16x8_t, lane: const int",uint16x4_t,Multiply-add to accumulator +FALSE,vmla_laneq_u32,"a: uint32x2_t, b: uint32x2_t, v: uint32x4_t, lane: const int",uint32x2_t,Multiply-add to accumulator +FALSE,vmla_n_f32,"a: float32x2_t, b: float32x2_t, c: f32",float32x2_t,Vector multiply accumulate with scalar +FALSE,vmla_n_s16,"a: int16x4_t, b: int16x4_t, c: i16",int16x4_t,Vector multiply accumulate with scalar +FALSE,vmla_n_s32,"a: int32x2_t, b: int32x2_t, c: i32",int32x2_t,Vector multiply accumulate with scalar +FALSE,vmla_n_u16,"a: uint16x4_t, b: uint16x4_t, c: u16",uint16x4_t,Vector multiply accumulate with scalar +FALSE,vmla_n_u32,"a: uint32x2_t, b: uint32x2_t, c: u32",uint32x2_t,Vector multiply accumulate with scalar +TRUE,vmla_s16,"a: int16x4_t, b: int16x4_t, c: int16x4_t",int16x4_t,Multiply-add to accumulator +TRUE,vmla_s32,"a: int32x2_t, b: int32x2_t, c: int32x2_t",int32x2_t,Multiply-add to accumulator +TRUE,vmla_s8,"a: int8x8_t, b: int8x8_t, c: int8x8_t",int8x8_t,Multiply-add to accumulator +TRUE,vmla_u16,"a: uint16x4_t, b: uint16x4_t, c: uint16x4_t",uint16x4_t,Multiply-add to accumulator +TRUE,vmla_u32,"a: uint32x2_t, b: uint32x2_t, c: uint32x2_t",uint32x2_t,Multiply-add to accumulator +TRUE,vmla_u8,"a: uint8x8_t, b: uint8x8_t, c: uint8x8_t",uint8x8_t,Multiply-add to accumulator +FALSE,vmlal_high_lane_s16,"a: int32x4_t, b: int16x8_t, v: int16x4_t, lane: const int",int32x4_t,Signed multiply-add long +FALSE,vmlal_high_lane_s32,"a: int64x2_t, b: int32x4_t, v: int32x2_t, lane: const int",int64x2_t,Signed multiply-add long +FALSE,vmlal_high_lane_u16,"a: uint32x4_t, b: uint16x8_t, v: uint16x4_t, lane: const int",uint32x4_t,Unsigned multiply-add long +FALSE,vmlal_high_lane_u32,"a: uint64x2_t, b: uint32x4_t, v: uint32x2_t, lane: const int",uint64x2_t,Unsigned multiply-add long +FALSE,vmlal_high_laneq_s16,"a: int32x4_t, b: int16x8_t, v: int16x8_t, lane: const int",int32x4_t,Signed multiply-add long +FALSE,vmlal_high_laneq_s32,"a: int64x2_t, b: int32x4_t, v: int32x4_t, lane: const int",int64x2_t,Signed multiply-add long +FALSE,vmlal_high_laneq_u16,"a: uint32x4_t, b: uint16x8_t, v: uint16x8_t, lane: const int",uint32x4_t,Unsigned multiply-add long +FALSE,vmlal_high_laneq_u32,"a: uint64x2_t, b: uint32x4_t, v: uint32x4_t, lane: const int",uint64x2_t,Unsigned multiply-add long +FALSE,vmlal_high_n_s16,"a: int32x4_t, b: int16x8_t, c: i16",int32x4_t,Signed multiply-add long +FALSE,vmlal_high_n_s32,"a: int64x2_t, b: int32x4_t, c: i32",int64x2_t,Signed multiply-add long +FALSE,vmlal_high_n_u16,"a: uint32x4_t, b: uint16x8_t, c: u16",uint32x4_t,Unsigned multiply-add long +FALSE,vmlal_high_n_u32,"a: uint64x2_t, b: uint32x4_t, c: u32",uint64x2_t,Unsigned multiply-add long +TRUE,vmlal_high_s16,"a: int32x4_t, b: int16x8_t, c: int16x8_t",int32x4_t,Signed multiply-add long +TRUE,vmlal_high_s32,"a: int64x2_t, b: int32x4_t, c: int32x4_t",int64x2_t,Signed multiply-add long +TRUE,vmlal_high_s8,"a: int16x8_t, b: int8x16_t, c: int8x16_t",int16x8_t,Signed multiply-add long +TRUE,vmlal_high_u16,"a: uint32x4_t, b: uint16x8_t, c: uint16x8_t",uint32x4_t,Unsigned multiply-add long +TRUE,vmlal_high_u32,"a: uint64x2_t, b: uint32x4_t, c: uint32x4_t",uint64x2_t,Unsigned multiply-add long +TRUE,vmlal_high_u8,"a: uint16x8_t, b: uint8x16_t, c: uint8x16_t",uint16x8_t,Unsigned multiply-add long +FALSE,vmlal_lane_s16,"a: int32x4_t, b: int16x4_t, v: int16x4_t, lane: const int",int32x4_t,Vector widening multiply accumulate with scalar +FALSE,vmlal_lane_s32,"a: int64x2_t, b: int32x2_t, v: int32x2_t, lane: const int",int64x2_t,Vector widening multiply accumulate with scalar +FALSE,vmlal_lane_u16,"a: uint32x4_t, b: uint16x4_t, v: uint16x4_t, lane: const int",uint32x4_t,Vector widening multiply accumulate with scalar +FALSE,vmlal_lane_u32,"a: uint64x2_t, b: uint32x2_t, v: uint32x2_t, lane: const int",uint64x2_t,Vector widening multiply accumulate with scalar +FALSE,vmlal_laneq_s16,"a: int32x4_t, b: int16x4_t, v: int16x8_t, lane: const int",int32x4_t,Signed multiply-add long +FALSE,vmlal_laneq_s32,"a: int64x2_t, b: int32x2_t, v: int32x4_t, lane: const int",int64x2_t,Signed multiply-add long +FALSE,vmlal_laneq_u16,"a: uint32x4_t, b: uint16x4_t, v: uint16x8_t, lane: const int",uint32x4_t,Unsigned multiply-add long +FALSE,vmlal_laneq_u32,"a: uint64x2_t, b: uint32x2_t, v: uint32x4_t, lane: const int",uint64x2_t,Unsigned multiply-add long +FALSE,vmlal_n_s16,"a: int32x4_t, b: int16x4_t, c: i16",int32x4_t,Vector widening multiply accumulate with scalar +FALSE,vmlal_n_s32,"a: int64x2_t, b: int32x2_t, c: i32",int64x2_t,Vector widening multiply accumulate with scalar +FALSE,vmlal_n_u16,"a: uint32x4_t, b: uint16x4_t, c: u16",uint32x4_t,Vector widening multiply accumulate with scalar +FALSE,vmlal_n_u32,"a: uint64x2_t, b: uint32x2_t, c: u32",uint64x2_t,Vector widening multiply accumulate with scalar +TRUE,vmlal_s16,"a: int32x4_t, b: int16x4_t, c: int16x4_t",int32x4_t,Signed multiply-add long +TRUE,vmlal_s32,"a: int64x2_t, b: int32x2_t, c: int32x2_t",int64x2_t,Signed multiply-add long +TRUE,vmlal_s8,"a: int16x8_t, b: int8x8_t, c: int8x8_t",int16x8_t,Signed multiply-add long +TRUE,vmlal_u16,"a: uint32x4_t, b: uint16x4_t, c: uint16x4_t",uint32x4_t,Unsigned multiply-add long +TRUE,vmlal_u32,"a: uint64x2_t, b: uint32x2_t, c: uint32x2_t",uint64x2_t,Unsigned multiply-add long +TRUE,vmlal_u8,"a: uint16x8_t, b: uint8x8_t, c: uint8x8_t",uint16x8_t,Unsigned multiply-add long +TRUE,vmlaq_f32,"a: float32x4_t, b: float32x4_t, c: float32x4_t",float32x4_t,Floating-point multiply-add to accumulator +TRUE,vmlaq_f64,"a: float64x2_t, b: float64x2_t, c: float64x2_t",float64x2_t,Floating-point multiply-add to accumulator +FALSE,vmlaq_lane_f32,"a: float32x4_t, b: float32x4_t, v: float32x2_t, lane: const int",float32x4_t,Vector multiply accumulate with scalar +FALSE,vmlaq_lane_s16,"a: int16x8_t, b: int16x8_t, v: int16x4_t, lane: const int",int16x8_t,Vector multiply accumulate with scalar +FALSE,vmlaq_lane_s32,"a: int32x4_t, b: int32x4_t, v: int32x2_t, lane: const int",int32x4_t,Vector multiply accumulate with scalar +FALSE,vmlaq_lane_u16,"a: uint16x8_t, b: uint16x8_t, v: uint16x4_t, lane: const int",uint16x8_t,Vector multiply accumulate with scalar +FALSE,vmlaq_lane_u32,"a: uint32x4_t, b: uint32x4_t, v: uint32x2_t, lane: const int",uint32x4_t,Vector multiply accumulate with scalar +FALSE,vmlaq_laneq_f32,"a: float32x4_t, b: float32x4_t, v: float32x4_t, lane: const int",float32x4_t,Multiply-Add to accumulator +FALSE,vmlaq_laneq_s16,"a: int16x8_t, b: int16x8_t, v: int16x8_t, lane: const int",int16x8_t,Multiply-add to accumulator +FALSE,vmlaq_laneq_s32,"a: int32x4_t, b: int32x4_t, v: int32x4_t, lane: const int",int32x4_t,Multiply-add to accumulator +FALSE,vmlaq_laneq_u16,"a: uint16x8_t, b: uint16x8_t, v: uint16x8_t, lane: const int",uint16x8_t,Multiply-add to accumulator +FALSE,vmlaq_laneq_u32,"a: uint32x4_t, b: uint32x4_t, v: uint32x4_t, lane: const int",uint32x4_t,Multiply-add to accumulator +FALSE,vmlaq_n_f32,"a: float32x4_t, b: float32x4_t, c: f32",float32x4_t,Vector multiply accumulate with scalar +FALSE,vmlaq_n_s16,"a: int16x8_t, b: int16x8_t, c: i16",int16x8_t,Vector multiply accumulate with scalar +FALSE,vmlaq_n_s32,"a: int32x4_t, b: int32x4_t, c: i32",int32x4_t,Vector multiply accumulate with scalar +FALSE,vmlaq_n_u16,"a: uint16x8_t, b: uint16x8_t, c: u16",uint16x8_t,Vector multiply accumulate with scalar +FALSE,vmlaq_n_u32,"a: uint32x4_t, b: uint32x4_t, c: u32",uint32x4_t,Vector multiply accumulate with scalar +TRUE,vmlaq_s16,"a: int16x8_t, b: int16x8_t, c: int16x8_t",int16x8_t,Multiply-add to accumulator +TRUE,vmlaq_s32,"a: int32x4_t, b: int32x4_t, c: int32x4_t",int32x4_t,Multiply-add to accumulator +TRUE,vmlaq_s8,"a: int8x16_t, b: int8x16_t, c: int8x16_t",int8x16_t,Multiply-add to accumulator +TRUE,vmlaq_u16,"a: uint16x8_t, b: uint16x8_t, c: uint16x8_t",uint16x8_t,Multiply-add to accumulator +TRUE,vmlaq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,Multiply-add to accumulator +TRUE,vmlaq_u8,"a: uint8x16_t, b: uint8x16_t, c: uint8x16_t",uint8x16_t,Multiply-add to accumulator +TRUE,vmls_f32,"a: float32x2_t, b: float32x2_t, c: float32x2_t",float32x2_t,Multiply-subtract from accumulator +TRUE,vmls_f64,"a: float64x1_t, b: float64x1_t, c: float64x1_t",float64x1_t,Multiply-subtract from accumulator +FALSE,vmls_lane_f32,"a: float32x2_t, b: float32x2_t, v: float32x2_t, lane: const int",float32x2_t,Vector multiply subtract with scalar +FALSE,vmls_lane_s16,"a: int16x4_t, b: int16x4_t, v: int16x4_t, lane: const int",int16x4_t,Vector multiply subtract with scalar +FALSE,vmls_lane_s32,"a: int32x2_t, b: int32x2_t, v: int32x2_t, lane: const int",int32x2_t,Vector multiply subtract with scalar +FALSE,vmls_lane_u16,"a: uint16x4_t, b: uint16x4_t, v: uint16x4_t, lane: const int",uint16x4_t,Vector multiply subtract with scalar +FALSE,vmls_lane_u32,"a: uint32x2_t, b: uint32x2_t, v: uint32x2_t, lane: const int",uint32x2_t,Vector multiply subtract with scalar +FALSE,vmls_laneq_f32,"a: float32x2_t, b: float32x2_t, v: float32x4_t, lane: const int",float32x2_t,Multiply-subtract from accumulator +FALSE,vmls_laneq_s16,"a: int16x4_t, b: int16x4_t, v: int16x8_t, lane: const int",int16x4_t,Multiply-subtract from accumulator +FALSE,vmls_laneq_s32,"a: int32x2_t, b: int32x2_t, v: int32x4_t, lane: const int",int32x2_t,Multiply-subtract from accumulator +FALSE,vmls_laneq_u16,"a: uint16x4_t, b: uint16x4_t, v: uint16x8_t, lane: const int",uint16x4_t,Multiply-subtract from accumulator +FALSE,vmls_laneq_u32,"a: uint32x2_t, b: uint32x2_t, v: uint32x4_t, lane: const int",uint32x2_t,Multiply-subtract from accumulator +FALSE,vmls_n_f32,"a: float32x2_t, b: float32x2_t, c: f32",float32x2_t,Vector multiply subtract with scalar +FALSE,vmls_n_s16,"a: int16x4_t, b: int16x4_t, c: i16",int16x4_t,Vector multiply subtract with scalar +FALSE,vmls_n_s32,"a: int32x2_t, b: int32x2_t, c: i32",int32x2_t,Vector multiply subtract with scalar +FALSE,vmls_n_u16,"a: uint16x4_t, b: uint16x4_t, c: u16",uint16x4_t,Vector multiply subtract with scalar +FALSE,vmls_n_u32,"a: uint32x2_t, b: uint32x2_t, c: u32",uint32x2_t,Vector multiply subtract with scalar +TRUE,vmls_s16,"a: int16x4_t, b: int16x4_t, c: int16x4_t",int16x4_t,Multiply-subtract from accumulator +TRUE,vmls_s32,"a: int32x2_t, b: int32x2_t, c: int32x2_t",int32x2_t,Multiply-subtract from accumulator +TRUE,vmls_s8,"a: int8x8_t, b: int8x8_t, c: int8x8_t",int8x8_t,Multiply-subtract from accumulator +TRUE,vmls_u16,"a: uint16x4_t, b: uint16x4_t, c: uint16x4_t",uint16x4_t,Multiply-subtract from accumulator +TRUE,vmls_u32,"a: uint32x2_t, b: uint32x2_t, c: uint32x2_t",uint32x2_t,Multiply-subtract from accumulator +TRUE,vmls_u8,"a: uint8x8_t, b: uint8x8_t, c: uint8x8_t",uint8x8_t,Multiply-subtract from accumulator +FALSE,vmlsl_high_lane_s16,"a: int32x4_t, b: int16x8_t, v: int16x4_t, lane: const int",int32x4_t,Signed multiply-subtract long +FALSE,vmlsl_high_lane_s32,"a: int64x2_t, b: int32x4_t, v: int32x2_t, lane: const int",int64x2_t,Signed multiply-subtract long +FALSE,vmlsl_high_lane_u16,"a: uint32x4_t, b: uint16x8_t, v: uint16x4_t, lane: const int",uint32x4_t,Unsigned multiply-subtract long +FALSE,vmlsl_high_lane_u32,"a: uint64x2_t, b: uint32x4_t, v: uint32x2_t, lane: const int",uint64x2_t,Unsigned multiply-subtract long +FALSE,vmlsl_high_laneq_s16,"a: int32x4_t, b: int16x8_t, v: int16x8_t, lane: const int",int32x4_t,Signed multiply-subtract long +FALSE,vmlsl_high_laneq_s32,"a: int64x2_t, b: int32x4_t, v: int32x4_t, lane: const int",int64x2_t,Signed multiply-subtract long +FALSE,vmlsl_high_laneq_u16,"a: uint32x4_t, b: uint16x8_t, v: uint16x8_t, lane: const int",uint32x4_t,Unsigned multiply-subtract long +FALSE,vmlsl_high_laneq_u32,"a: uint64x2_t, b: uint32x4_t, v: uint32x4_t, lane: const int",uint64x2_t,Unsigned multiply-subtract long +FALSE,vmlsl_high_n_s16,"a: int32x4_t, b: int16x8_t, c: i16",int32x4_t,Signed multiply-subtract long +FALSE,vmlsl_high_n_s32,"a: int64x2_t, b: int32x4_t, c: i32",int64x2_t,Signed multiply-subtract long +FALSE,vmlsl_high_n_u16,"a: uint32x4_t, b: uint16x8_t, c: u16",uint32x4_t,Unsigned multiply-subtract long +FALSE,vmlsl_high_n_u32,"a: uint64x2_t, b: uint32x4_t, c: u32",uint64x2_t,Unsigned multiply-subtract long +TRUE,vmlsl_high_s16,"a: int32x4_t, b: int16x8_t, c: int16x8_t",int32x4_t,Signed multiply-subtract long +TRUE,vmlsl_high_s32,"a: int64x2_t, b: int32x4_t, c: int32x4_t",int64x2_t,Signed multiply-subtract long +TRUE,vmlsl_high_s8,"a: int16x8_t, b: int8x16_t, c: int8x16_t",int16x8_t,Signed multiply-subtract long +TRUE,vmlsl_high_u16,"a: uint32x4_t, b: uint16x8_t, c: uint16x8_t",uint32x4_t,Unsigned multiply-subtract long +TRUE,vmlsl_high_u32,"a: uint64x2_t, b: uint32x4_t, c: uint32x4_t",uint64x2_t,Unsigned multiply-subtract long +TRUE,vmlsl_high_u8,"a: uint16x8_t, b: uint8x16_t, c: uint8x16_t",uint16x8_t,Unsigned multiply-subtract long +FALSE,vmlsl_lane_s16,"a: int32x4_t, b: int16x4_t, v: int16x4_t, lane: const int",int32x4_t,Vector widening multiply subtract with scalar +FALSE,vmlsl_lane_s32,"a: int64x2_t, b: int32x2_t, v: int32x2_t, lane: const int",int64x2_t,Vector widening multiply subtract with scalar +FALSE,vmlsl_lane_u16,"a: uint32x4_t, b: uint16x4_t, v: uint16x4_t, lane: const int",uint32x4_t,Vector widening multiply subtract with scalar +FALSE,vmlsl_lane_u32,"a: uint64x2_t, b: uint32x2_t, v: uint32x2_t, lane: const int",uint64x2_t,Vector widening multiply subtract with scalar +FALSE,vmlsl_laneq_s16,"a: int32x4_t, b: int16x4_t, v: int16x8_t, lane: const int",int32x4_t,Signed multiply-subtract long +FALSE,vmlsl_laneq_s32,"a: int64x2_t, b: int32x2_t, v: int32x4_t, lane: const int",int64x2_t,Signed multiply-subtract long +FALSE,vmlsl_laneq_u16,"a: uint32x4_t, b: uint16x4_t, v: uint16x8_t, lane: const int",uint32x4_t,Unsigned multiply-subtract long +FALSE,vmlsl_laneq_u32,"a: uint64x2_t, b: uint32x2_t, v: uint32x4_t, lane: const int",uint64x2_t,Unsigned multiply-subtract long +FALSE,vmlsl_n_s16,"a: int32x4_t, b: int16x4_t, c: i16",int32x4_t,Vector widening multiply subtract with scalar +FALSE,vmlsl_n_s32,"a: int64x2_t, b: int32x2_t, c: i32",int64x2_t,Vector widening multiply subtract with scalar +FALSE,vmlsl_n_u16,"a: uint32x4_t, b: uint16x4_t, c: u16",uint32x4_t,Vector widening multiply subtract with scalar +FALSE,vmlsl_n_u32,"a: uint64x2_t, b: uint32x2_t, c: u32",uint64x2_t,Vector widening multiply subtract with scalar +TRUE,vmlsl_s16,"a: int32x4_t, b: int16x4_t, c: int16x4_t",int32x4_t,Signed multiply-subtract long +TRUE,vmlsl_s32,"a: int64x2_t, b: int32x2_t, c: int32x2_t",int64x2_t,Signed multiply-subtract long +TRUE,vmlsl_s8,"a: int16x8_t, b: int8x8_t, c: int8x8_t",int16x8_t,Signed multiply-subtract long +TRUE,vmlsl_u16,"a: uint32x4_t, b: uint16x4_t, c: uint16x4_t",uint32x4_t,Unsigned multiply-subtract long +TRUE,vmlsl_u32,"a: uint64x2_t, b: uint32x2_t, c: uint32x2_t",uint64x2_t,Unsigned multiply-subtract long +TRUE,vmlsl_u8,"a: uint16x8_t, b: uint8x8_t, c: uint8x8_t",uint16x8_t,Unsigned multiply-subtract long +TRUE,vmlsq_f32,"a: float32x4_t, b: float32x4_t, c: float32x4_t",float32x4_t,Multiply-subtract from accumulator +TRUE,vmlsq_f64,"a: float64x2_t, b: float64x2_t, c: float64x2_t",float64x2_t,Multiply-subtract from accumulator +FALSE,vmlsq_lane_f32,"a: float32x4_t, b: float32x4_t, v: float32x2_t, lane: const int",float32x4_t,Vector multiply subtract with scalar +FALSE,vmlsq_lane_s16,"a: int16x8_t, b: int16x8_t, v: int16x4_t, lane: const int",int16x8_t,Vector multiply subtract with scalar +FALSE,vmlsq_lane_s32,"a: int32x4_t, b: int32x4_t, v: int32x2_t, lane: const int",int32x4_t,Vector multiply subtract with scalar +FALSE,vmlsq_lane_u16,"a: uint16x8_t, b: uint16x8_t, v: uint16x4_t, lane: const int",uint16x8_t,Vector multiply subtract with scalar +FALSE,vmlsq_lane_u32,"a: uint32x4_t, b: uint32x4_t, v: uint32x2_t, lane: const int",uint32x4_t,Vector multiply subtract with scalar +FALSE,vmlsq_laneq_f32,"a: float32x4_t, b: float32x4_t, v: float32x4_t, lane: const int",float32x4_t,Multiply-subtract from accumulator +FALSE,vmlsq_laneq_s16,"a: int16x8_t, b: int16x8_t, v: int16x8_t, lane: const int",int16x8_t,Multiply-subtract from accumulator +FALSE,vmlsq_laneq_s32,"a: int32x4_t, b: int32x4_t, v: int32x4_t, lane: const int",int32x4_t,Multiply-subtract from accumulator +FALSE,vmlsq_laneq_u16,"a: uint16x8_t, b: uint16x8_t, v: uint16x8_t, lane: const int",uint16x8_t,Multiply-subtract from accumulator +FALSE,vmlsq_laneq_u32,"a: uint32x4_t, b: uint32x4_t, v: uint32x4_t, lane: const int",uint32x4_t,Multiply-subtract from accumulator +FALSE,vmlsq_n_f32,"a: float32x4_t, b: float32x4_t, c: f32",float32x4_t,Vector multiply subtract with scalar +FALSE,vmlsq_n_s16,"a: int16x8_t, b: int16x8_t, c: i16",int16x8_t,Vector multiply subtract with scalar +FALSE,vmlsq_n_s32,"a: int32x4_t, b: int32x4_t, c: i32",int32x4_t,Vector multiply subtract with scalar +FALSE,vmlsq_n_u16,"a: uint16x8_t, b: uint16x8_t, c: u16",uint16x8_t,Vector multiply subtract with scalar +FALSE,vmlsq_n_u32,"a: uint32x4_t, b: uint32x4_t, c: u32",uint32x4_t,Vector multiply subtract with scalar +TRUE,vmlsq_s16,"a: int16x8_t, b: int16x8_t, c: int16x8_t",int16x8_t,Multiply-subtract from accumulator +TRUE,vmlsq_s32,"a: int32x4_t, b: int32x4_t, c: int32x4_t",int32x4_t,Multiply-subtract from accumulator +TRUE,vmlsq_s8,"a: int8x16_t, b: int8x16_t, c: int8x16_t",int8x16_t,Multiply-subtract from accumulator +TRUE,vmlsq_u16,"a: uint16x8_t, b: uint16x8_t, c: uint16x8_t",uint16x8_t,Multiply-subtract from accumulator +TRUE,vmlsq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,Multiply-subtract from accumulator +TRUE,vmlsq_u8,"a: uint8x16_t, b: uint8x16_t, c: uint8x16_t",uint8x16_t,Multiply-subtract from accumulator +FALSE,vmmlaq_s32,"r: int32x4_t, a: int8x16_t, b: int8x16_t",int32x4_t,Signed 8-bit integer matrix multiply-accumulate +FALSE,vmmlaq_u32,"r: uint32x4_t, a: uint8x16_t, b: uint8x16_t",uint32x4_t,Unsigned 8-bit integer matrix multiply-accumulate +FALSE,vmov_n_f16,value: float16_t,float16x4_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_f32,value: f32,float32x2_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_f64,value: float64_t,float64x1_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_p16,value: poly16_t,poly16x4_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_p8,value: poly8_t,poly8x8_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_s16,value: i16,int16x4_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_s32,value: i32,int32x2_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_s64,value: i64,int64x1_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_s8,value: i8,int8x8_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_u16,value: u16,uint16x4_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_u32,value: u32,uint32x2_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_u64,value: u64,uint64x1_t,Duplicate vector element to vector or scalar +TRUE,vmov_n_u8,value: u8,uint8x8_t,Duplicate vector element to vector or scalar +FALSE,vmovl_high_s16,a: int16x8_t,int32x4_t,Vector move +FALSE,vmovl_high_s32,a: int32x4_t,int64x2_t,Vector move +FALSE,vmovl_high_s8,a: int8x16_t,int16x8_t,Vector move +FALSE,vmovl_high_u16,a: uint16x8_t,uint32x4_t,Vector move +FALSE,vmovl_high_u32,a: uint32x4_t,uint64x2_t,Vector move +FALSE,vmovl_high_u8,a: uint8x16_t,uint16x8_t,Vector move +TRUE,vmovl_s16,a: int16x4_t,int32x4_t,Vector move +TRUE,vmovl_s32,a: int32x2_t,int64x2_t,Vector move +TRUE,vmovl_s8,a: int8x8_t,int16x8_t,Vector move +TRUE,vmovl_u16,a: uint16x4_t,uint32x4_t,Vector move +TRUE,vmovl_u32,a: uint32x2_t,uint64x2_t,Vector move +TRUE,vmovl_u8,a: uint8x8_t,uint16x8_t,Vector move +TRUE,vmovn_high_s16,"r: int8x8_t, a: int16x8_t",int8x16_t,Extract narrow +TRUE,vmovn_high_s32,"r: int16x4_t, a: int32x4_t",int16x8_t,Extract narrow +TRUE,vmovn_high_s64,"r: int32x2_t, a: int64x2_t",int32x4_t,Extract narrow +TRUE,vmovn_high_u16,"r: uint8x8_t, a: uint16x8_t",uint8x16_t,Extract narrow +TRUE,vmovn_high_u32,"r: uint16x4_t, a: uint32x4_t",uint16x8_t,Extract narrow +TRUE,vmovn_high_u64,"r: uint32x2_t, a: uint64x2_t",uint32x4_t,Extract narrow +TRUE,vmovn_s16,a: int16x8_t,int8x8_t,Extract narrow +TRUE,vmovn_s32,a: int32x4_t,int16x4_t,Extract narrow +TRUE,vmovn_s64,a: int64x2_t,int32x2_t,Extract narrow +TRUE,vmovn_u16,a: uint16x8_t,uint8x8_t,Extract narrow +TRUE,vmovn_u32,a: uint32x4_t,uint16x4_t,Extract narrow +TRUE,vmovn_u64,a: uint64x2_t,uint32x2_t,Extract narrow +FALSE,vmovq_n_f16,value: float16_t,float16x8_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_f32,value: f32,float32x4_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_f64,value: float64_t,float64x2_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_p16,value: poly16_t,poly16x8_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_p8,value: poly8_t,poly8x16_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_s16,value: i16,int16x8_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_s32,value: i32,int32x4_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_s64,value: i64,int64x2_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_s8,value: i8,int8x16_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_u16,value: u16,uint16x8_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_u32,value: u32,uint32x4_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_u64,value: u64,uint64x2_t,Duplicate vector element to vector or scalar +TRUE,vmovq_n_u8,value: u8,uint8x16_t,Duplicate vector element to vector or scalar +FALSE,vmul_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point multiply +TRUE,vmul_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point multiply +TRUE,vmul_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point multiply +FALSE,vmul_lane_f16,"a: float16x4_t, v: float16x4_t, lane: const int",float16x4_t,Floating-point multiply +FALSE,vmul_lane_f32,"a: float32x2_t, v: float32x2_t, lane: const int",float32x2_t,Floating-point multiply +FALSE,vmul_lane_f64,"a: float64x1_t, v: float64x1_t, lane: const int",float64x1_t,Floating-point multiply +FALSE,vmul_lane_s16,"a: int16x4_t, v: int16x4_t, lane: const int",int16x4_t,Multiply +FALSE,vmul_lane_s32,"a: int32x2_t, v: int32x2_t, lane: const int",int32x2_t,Multiply +FALSE,vmul_lane_u16,"a: uint16x4_t, v: uint16x4_t, lane: const int",uint16x4_t,Multiply +FALSE,vmul_lane_u32,"a: uint32x2_t, v: uint32x2_t, lane: const int",uint32x2_t,Multiply +FALSE,vmul_laneq_f16,"a: float16x4_t, v: float16x8_t, lane: const int",float16x4_t,Floating-point multiply +FALSE,vmul_laneq_f32,"a: float32x2_t, v: float32x4_t, lane: const int",float32x2_t,Floating-point multiply +FALSE,vmul_laneq_f64,"a: float64x1_t, v: float64x2_t, lane: const int",float64x1_t,Floating-point multiply +FALSE,vmul_laneq_s16,"a: int16x4_t, v: int16x8_t, lane: const int",int16x4_t,Multiply +FALSE,vmul_laneq_s32,"a: int32x2_t, v: int32x4_t, lane: const int",int32x2_t,Multiply +FALSE,vmul_laneq_u16,"a: uint16x4_t, v: uint16x8_t, lane: const int",uint16x4_t,Multiply +FALSE,vmul_laneq_u32,"a: uint32x2_t, v: uint32x4_t, lane: const int",uint32x2_t,Multiply +FALSE,vmul_n_f16,"a: float16x4_t, n: float16_t",float16x4_t,Floating-point multiply +FALSE,vmul_n_f32,"a: float32x2_t, b: f32",float32x2_t,Vector multiply by scalar +FALSE,vmul_n_f64,"a: float64x1_t, b: float64_t",float64x1_t,Floating-point multiply +FALSE,vmul_n_s16,"a: int16x4_t, b: i16",int16x4_t,Vector multiply by scalar +FALSE,vmul_n_s32,"a: int32x2_t, b: i32",int32x2_t,Vector multiply by scalar +FALSE,vmul_n_u16,"a: uint16x4_t, b: u16",uint16x4_t,Vector multiply by scalar +FALSE,vmul_n_u32,"a: uint32x2_t, b: u32",uint32x2_t,Vector multiply by scalar +FALSE,vmul_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8_t,Polynomial multiply +TRUE,vmul_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Multiply +TRUE,vmul_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Multiply +TRUE,vmul_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Multiply +TRUE,vmul_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Multiply +TRUE,vmul_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Multiply +TRUE,vmul_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Multiply +FALSE,vmuld_lane_f64,"a: float64_t, v: float64x1_t, lane: const int",float64_t,Floating-point multiply +FALSE,vmuld_laneq_f64,"a: float64_t, v: float64x2_t, lane: const int",float64_t,Floating-point multiply +FALSE,vmulh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point multiply +FALSE,vmulh_lane_f16,"a: float16_t, v: float16x4_t, lane: const int",float16_t,Floating-point multiply +FALSE,vmulh_laneq_f16,"a: float16_t, v: float16x8_t, lane: const int",float16_t,Floating-point multiply +FALSE,vmull_high_lane_s16,"a: int16x8_t, v: int16x4_t, lane: const int",int32x4_t,Signed multiply long +FALSE,vmull_high_lane_s32,"a: int32x4_t, v: int32x2_t, lane: const int",int64x2_t,Signed multiply long +FALSE,vmull_high_lane_u16,"a: uint16x8_t, v: uint16x4_t, lane: const int",uint32x4_t,Unsigned multiply long +FALSE,vmull_high_lane_u32,"a: uint32x4_t, v: uint32x2_t, lane: const int",uint64x2_t,Unsigned multiply long +FALSE,vmull_high_laneq_s16,"a: int16x8_t, v: int16x8_t, lane: const int",int32x4_t,Signed multiply long +FALSE,vmull_high_laneq_s32,"a: int32x4_t, v: int32x4_t, lane: const int",int64x2_t,Signed multiply long +FALSE,vmull_high_laneq_u16,"a: uint16x8_t, v: uint16x8_t, lane: const int",uint32x4_t,Unsigned multiply long +FALSE,vmull_high_laneq_u32,"a: uint32x4_t, v: uint32x4_t, lane: const int",uint64x2_t,Unsigned multiply long +FALSE,vmull_high_n_s16,"a: int16x8_t, b: i16",int32x4_t,Signed multiply long +FALSE,vmull_high_n_s32,"a: int32x4_t, b: i32",int64x2_t,Signed multiply long +FALSE,vmull_high_n_u16,"a: uint16x8_t, b: u16",uint32x4_t,Unsigned multiply long +FALSE,vmull_high_n_u32,"a: uint32x4_t, b: u32",uint64x2_t,Unsigned multiply long +FALSE,vmull_high_p64,"a: poly64x2_t, b: poly64x2_t",poly128_t,Polynomial multiply long +TRUE,vmull_high_p8,"a: poly8x16_t, b: poly8x16_t",poly16x8_t,Polynomial multiply long +TRUE,vmull_high_s16,"a: int16x8_t, b: int16x8_t",int32x4_t,Signed multiply long +TRUE,vmull_high_s32,"a: int32x4_t, b: int32x4_t",int64x2_t,Signed multiply long +TRUE,vmull_high_s8,"a: int8x16_t, b: int8x16_t",int16x8_t,Signed multiply long +TRUE,vmull_high_u16,"a: uint16x8_t, b: uint16x8_t",uint32x4_t,Unsigned multiply long +TRUE,vmull_high_u32,"a: uint32x4_t, b: uint32x4_t",uint64x2_t,Unsigned multiply long +TRUE,vmull_high_u8,"a: uint8x16_t, b: uint8x16_t",uint16x8_t,Unsigned multiply long +FALSE,vmull_lane_s16,"a: int16x4_t, v: int16x4_t, lane: const int",int32x4_t,Vector long multiply by scalar +FALSE,vmull_lane_s32,"a: int32x2_t, v: int32x2_t, lane: const int",int64x2_t,Vector long multiply by scalar +FALSE,vmull_lane_u16,"a: uint16x4_t, v: uint16x4_t, lane: const int",uint32x4_t,Vector long multiply by scalar +FALSE,vmull_lane_u32,"a: uint32x2_t, v: uint32x2_t, lane: const int",uint64x2_t,Vector long multiply by scalar +FALSE,vmull_laneq_s16,"a: int16x4_t, v: int16x8_t, lane: const int",int32x4_t,Signed multiply long +FALSE,vmull_laneq_s32,"a: int32x2_t, v: int32x4_t, lane: const int",int64x2_t,Signed multiply long +FALSE,vmull_laneq_u16,"a: uint16x4_t, v: uint16x8_t, lane: const int",uint32x4_t,Unsigned multiply long +FALSE,vmull_laneq_u32,"a: uint32x2_t, v: uint32x4_t, lane: const int",uint64x2_t,Unsigned multiply long +FALSE,vmull_n_s16,"a: int16x4_t, b: i16",int32x4_t,Vector long multiply with scalar +FALSE,vmull_n_s32,"a: int32x2_t, b: i32",int64x2_t,Vector long multiply with scalar +FALSE,vmull_n_u16,"a: uint16x4_t, b: u16",uint32x4_t,Vector long multiply with scalar +FALSE,vmull_n_u32,"a: uint32x2_t, b: u32",uint64x2_t,Vector long multiply with scalar +TRUE,vmull_p64,"a: poly64_t, b: poly64_t",poly128_t,Polynomial multiply long +TRUE,vmull_p8,"a: poly8x8_t, b: poly8x8_t",poly16x8_t,Polynomial multiply long +TRUE,vmull_s16,"a: int16x4_t, b: int16x4_t",int32x4_t,Signed multiply long +TRUE,vmull_s32,"a: int32x2_t, b: int32x2_t",int64x2_t,Signed multiply long +TRUE,vmull_s8,"a: int8x8_t, b: int8x8_t",int16x8_t,Signed multiply long +TRUE,vmull_u16,"a: uint16x4_t, b: uint16x4_t",uint32x4_t,Unsigned multiply long +TRUE,vmull_u32,"a: uint32x2_t, b: uint32x2_t",uint64x2_t,Unsigned multiply long +TRUE,vmull_u8,"a: uint8x8_t, b: uint8x8_t",uint16x8_t,Unsigned multiply long +FALSE,vmulq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point multiply +TRUE,vmulq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point multiply +TRUE,vmulq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point multiply +FALSE,vmulq_lane_f16,"a: float16x8_t, v: float16x4_t, lane: const int",float16x8_t,Floating-point multiply +FALSE,vmulq_lane_f32,"a: float32x4_t, v: float32x2_t, lane: const int",float32x4_t,Floating-point multiply +FALSE,vmulq_lane_f64,"a: float64x2_t, v: float64x1_t, lane: const int",float64x2_t,Floating-point multiply +FALSE,vmulq_lane_s16,"a: int16x8_t, v: int16x4_t, lane: const int",int16x8_t,Multiply +FALSE,vmulq_lane_s32,"a: int32x4_t, v: int32x2_t, lane: const int",int32x4_t,Multiply +FALSE,vmulq_lane_u16,"a: uint16x8_t, v: uint16x4_t, lane: const int",uint16x8_t,Multiply +FALSE,vmulq_lane_u32,"a: uint32x4_t, v: uint32x2_t, lane: const int",uint32x4_t,Multiply +FALSE,vmulq_laneq_f16,"a: float16x8_t, v: float16x8_t, lane: const int",float16x8_t,Floating-point multiply +FALSE,vmulq_laneq_f32,"a: float32x4_t, v: float32x4_t, lane: const int",float32x4_t,Floating-point multiply +FALSE,vmulq_laneq_f64,"a: float64x2_t, v: float64x2_t, lane: const int",float64x2_t,Floating-point multiply +FALSE,vmulq_laneq_s16,"a: int16x8_t, v: int16x8_t, lane: const int",int16x8_t,Multiply +FALSE,vmulq_laneq_s32,"a: int32x4_t, v: int32x4_t, lane: const int",int32x4_t,Multiply +FALSE,vmulq_laneq_u16,"a: uint16x8_t, v: uint16x8_t, lane: const int",uint16x8_t,Multiply +FALSE,vmulq_laneq_u32,"a: uint32x4_t, v: uint32x4_t, lane: const int",uint32x4_t,Multiply +FALSE,vmulq_n_f16,"a: float16x8_t, n: float16_t",float16x8_t,Floating-point multiply +FALSE,vmulq_n_f32,"a: float32x4_t, b: f32",float32x4_t,Vector multiply by scalar +FALSE,vmulq_n_f64,"a: float64x2_t, b: float64_t",float64x2_t,Floating-point multiply +FALSE,vmulq_n_s16,"a: int16x8_t, b: i16",int16x8_t,Vector multiply by scalar +FALSE,vmulq_n_s32,"a: int32x4_t, b: i32",int32x4_t,Vector multiply by scalar +FALSE,vmulq_n_u16,"a: uint16x8_t, b: u16",uint16x8_t,Vector multiply by scalar +FALSE,vmulq_n_u32,"a: uint32x4_t, b: u32",uint32x4_t,Vector multiply by scalar +FALSE,vmulq_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16_t,Polynomial multiply +TRUE,vmulq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Multiply +TRUE,vmulq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Multiply +TRUE,vmulq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Multiply +TRUE,vmulq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Multiply +TRUE,vmulq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Multiply +TRUE,vmulq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Multiply +FALSE,vmuls_lane_f32,"a: f32, v: float32x2_t, lane: const int",f32,Floating-point multiply +FALSE,vmuls_laneq_f32,"a: f32, v: float32x4_t, lane: const int",f32,Floating-point multiply +FALSE,vmulx_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point multiply extended +FALSE,vmulx_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point multiply extended +FALSE,vmulx_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point multiply extended +FALSE,vmulx_lane_f16,"a: float16x4_t, v: float16x4_t, lane: const int",float16x4_t,Floating-point multiply extended +FALSE,vmulx_lane_f32,"a: float32x2_t, v: float32x2_t, lane: const int",float32x2_t,Floating-point multiply extended +FALSE,vmulx_lane_f64,"a: float64x1_t, v: float64x1_t, lane: const int",float64x1_t,Floating-point multiply extended +FALSE,vmulx_laneq_f16,"a: float16x4_t, v: float16x8_t, lane: const int",float16x4_t,Floating-point multiply extended +FALSE,vmulx_laneq_f32,"a: float32x2_t, v: float32x4_t, lane: const int",float32x2_t,Floating-point multiply extended +FALSE,vmulx_laneq_f64,"a: float64x1_t, v: float64x2_t, lane: const int",float64x1_t,Floating-point multiply extended +FALSE,vmulx_n_f16,"a: float16x4_t, n: float16_t",float16x4_t,Floating-point multiply extended +FALSE,vmulxd_f64,"a: float64_t, b: float64_t",float64_t,Floating-point multiply extended +FALSE,vmulxd_lane_f64,"a: float64_t, v: float64x1_t, lane: const int",float64_t,Floating-point multiply extended +FALSE,vmulxd_laneq_f64,"a: float64_t, v: float64x2_t, lane: const int",float64_t,Floating-point multiply extended +FALSE,vmulxh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point multiply extended +FALSE,vmulxh_lane_f16,"a: float16_t, v: float16x4_t, lane: const int",float16_t,Floating-point multiply extended +FALSE,vmulxh_laneq_f16,"a: float16_t, v: float16x8_t, lane: const int",float16_t,Floating-point multiply extended +FALSE,vmulxq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point multiply extended +FALSE,vmulxq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point multiply extended +FALSE,vmulxq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point multiply extended +FALSE,vmulxq_lane_f16,"a: float16x8_t, v: float16x4_t, lane: const int",float16x8_t,Floating-point multiply extended +FALSE,vmulxq_lane_f32,"a: float32x4_t, v: float32x2_t, lane: const int",float32x4_t,Floating-point multiply extended +FALSE,vmulxq_lane_f64,"a: float64x2_t, v: float64x1_t, lane: const int",float64x2_t,Floating-point multiply extended +FALSE,vmulxq_laneq_f16,"a: float16x8_t, v: float16x8_t, lane: const int",float16x8_t,Floating-point multiply extended +FALSE,vmulxq_laneq_f32,"a: float32x4_t, v: float32x4_t, lane: const int",float32x4_t,Floating-point multiply extended +FALSE,vmulxq_laneq_f64,"a: float64x2_t, v: float64x2_t, lane: const int",float64x2_t,Floating-point multiply extended +FALSE,vmulxq_n_f16,"a: float16x8_t, n: float16_t",float16x8_t,Floating-point multiply extended +FALSE,vmulxs_f32,"a: f32, b: f32",f32,Floating-point multiply extended +FALSE,vmulxs_lane_f32,"a: f32, v: float32x2_t, lane: const int",f32,Floating-point multiply extended +FALSE,vmulxs_laneq_f32,"a: f32, v: float32x4_t, lane: const int",f32,Floating-point multiply extended +TRUE,vmvn_p8,a: poly8x8_t,poly8x8_t,Bitwise NOT +TRUE,vmvn_s16,a: int16x4_t,int16x4_t,Bitwise NOT +TRUE,vmvn_s32,a: int32x2_t,int32x2_t,Bitwise NOT +TRUE,vmvn_s8,a: int8x8_t,int8x8_t,Bitwise NOT +TRUE,vmvn_u16,a: uint16x4_t,uint16x4_t,Bitwise NOT +TRUE,vmvn_u32,a: uint32x2_t,uint32x2_t,Bitwise NOT +TRUE,vmvn_u8,a: uint8x8_t,uint8x8_t,Bitwise NOT +TRUE,vmvnq_p8,a: poly8x16_t,poly8x16_t,Bitwise NOT +TRUE,vmvnq_s16,a: int16x8_t,int16x8_t,Bitwise NOT +TRUE,vmvnq_s32,a: int32x4_t,int32x4_t,Bitwise NOT +TRUE,vmvnq_s8,a: int8x16_t,int8x16_t,Bitwise NOT +TRUE,vmvnq_u16,a: uint16x8_t,uint16x8_t,Bitwise NOT +TRUE,vmvnq_u32,a: uint32x4_t,uint32x4_t,Bitwise NOT +TRUE,vmvnq_u8,a: uint8x16_t,uint8x16_t,Bitwise NOT +FALSE,vneg_f16,a: float16x4_t,float16x4_t,Floating-point negate +TRUE,vneg_f32,a: float32x2_t,float32x2_t,Floating-point negate +TRUE,vneg_f64,a: float64x1_t,float64x1_t,Floating-point negate +TRUE,vneg_s16,a: int16x4_t,int16x4_t,Negate +TRUE,vneg_s32,a: int32x2_t,int32x2_t,Negate +TRUE,vneg_s64,a: int64x1_t,int64x1_t,Negate +TRUE,vneg_s8,a: int8x8_t,int8x8_t,Negate +FALSE,vnegd_s64,a: i64,i64,Negate +FALSE,vnegh_f16,a: float16_t,float16_t,Floating-point negate +FALSE,vnegq_f16,a: float16x8_t,float16x8_t,Floating-point negate +TRUE,vnegq_f32,a: float32x4_t,float32x4_t,Floating-point negate +TRUE,vnegq_f64,a: float64x2_t,float64x2_t,Floating-point negate +TRUE,vnegq_s16,a: int16x8_t,int16x8_t,Negate +TRUE,vnegq_s32,a: int32x4_t,int32x4_t,Negate +TRUE,vnegq_s64,a: int64x2_t,int64x2_t,Negate +TRUE,vnegq_s8,a: int8x16_t,int8x16_t,Negate +TRUE,vorn_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Bitwise inclusive OR NOT +TRUE,vorn_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Bitwise inclusive OR NOT +TRUE,vorn_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Bitwise inclusive OR NOT +TRUE,vorn_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Bitwise inclusive OR NOT +TRUE,vorn_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Bitwise inclusive OR NOT +TRUE,vorn_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Bitwise inclusive OR NOT +TRUE,vorn_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Bitwise inclusive OR NOT +TRUE,vorn_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Bitwise inclusive OR NOT +TRUE,vornq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Bitwise inclusive OR NOT +TRUE,vornq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Bitwise inclusive OR NOT +TRUE,vornq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Bitwise inclusive OR NOT +TRUE,vornq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Bitwise inclusive OR NOT +TRUE,vornq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Bitwise inclusive OR NOT +TRUE,vornq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Bitwise inclusive OR NOT +TRUE,vornq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Bitwise inclusive OR NOT +TRUE,vornq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Bitwise inclusive OR NOT +TRUE,vorr_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorr_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorr_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorr_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorr_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorr_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorr_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorr_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorrq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorrq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorrq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorrq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorrq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorrq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorrq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vorrq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,"Bitwise inclusive OR (vector, immediate)" +TRUE,vpadal_s16,"a: int32x2_t, b: int16x4_t",int32x2_t,Signed add and accumulate long pairwise +TRUE,vpadal_s32,"a: int64x1_t, b: int32x2_t",int64x1_t,Signed add and accumulate long pairwise +TRUE,vpadal_s8,"a: int16x4_t, b: int8x8_t",int16x4_t,Signed add and accumulate long pairwise +FALSE,vpadal_u16,"a: uint32x2_t, b: uint16x4_t",uint32x2_t,Unsigned add and accumulate long pairwise +FALSE,vpadal_u32,"a: uint64x1_t, b: uint32x2_t",uint64x1_t,Unsigned add and accumulate long pairwise +FALSE,vpadal_u8,"a: uint16x4_t, b: uint8x8_t",uint16x4_t,Unsigned add and accumulate long pairwise +FALSE,vpadalq_s16,"a: int32x4_t, b: int16x8_t",int32x4_t,Signed add and accumulate long pairwise +FALSE,vpadalq_s32,"a: int64x2_t, b: int32x4_t",int64x2_t,Signed add and accumulate long pairwise +FALSE,vpadalq_s8,"a: int16x8_t, b: int8x16_t",int16x8_t,Signed add and accumulate long pairwise +FALSE,vpadalq_u16,"a: uint32x4_t, b: uint16x8_t",uint32x4_t,Unsigned add and accumulate long pairwise +FALSE,vpadalq_u32,"a: uint64x2_t, b: uint32x4_t",uint64x2_t,Unsigned add and accumulate long pairwise +FALSE,vpadalq_u8,"a: uint16x8_t, b: uint8x16_t",uint16x8_t,Unsigned add and accumulate long pairwise +FALSE,vpadd_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point add pairwise +FALSE,vpadd_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point add pairwise +TRUE,vpadd_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Add pairwise +TRUE,vpadd_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Add pairwise +TRUE,vpadd_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Add pairwise +TRUE,vpadd_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Add pairwise +TRUE,vpadd_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Add pairwise +TRUE,vpadd_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Add pairwise +FALSE,vpaddd_f64,a: float64x2_t,float64_t,Floating-point add pairwise +TRUE,vpaddd_s64,a: int64x2_t,i64,Add pairwise +TRUE,vpaddd_u64,a: uint64x2_t,u64,Add pairwise +FALSE,vpaddl_s16,a: int16x4_t,int32x2_t,Signed add long pairwise +FALSE,vpaddl_s32,a: int32x2_t,int64x1_t,Signed add long pairwise +FALSE,vpaddl_s8,a: int8x8_t,int16x4_t,Signed add long pairwise +FALSE,vpaddl_u16,a: uint16x4_t,uint32x2_t,Unsigned add long pairwise +FALSE,vpaddl_u32,a: uint32x2_t,uint64x1_t,Unsigned add long pairwise +FALSE,vpaddl_u8,a: uint8x8_t,uint16x4_t,Unsigned add long pairwise +FALSE,vpaddlq_s16,a: int16x8_t,int32x4_t,Signed add long pairwise +FALSE,vpaddlq_s32,a: int32x4_t,int64x2_t,Signed add long pairwise +FALSE,vpaddlq_s8,a: int8x16_t,int16x8_t,Signed add long pairwise +FALSE,vpaddlq_u16,a: uint16x8_t,uint32x4_t,Unsigned add long pairwise +FALSE,vpaddlq_u32,a: uint32x4_t,uint64x2_t,Unsigned add long pairwise +FALSE,vpaddlq_u8,a: uint8x16_t,uint16x8_t,Unsigned add long pairwise +FALSE,vpaddq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point add pairwise +FALSE,vpaddq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point add pairwise +FALSE,vpaddq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point add pairwise +TRUE,vpaddq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Add pairwise +TRUE,vpaddq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Add pairwise +FALSE,vpaddq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Add pairwise +TRUE,vpaddq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Add pairwise +TRUE,vpaddq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Add pairwise +TRUE,vpaddq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Add pairwise +FALSE,vpaddq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Add pairwise +TRUE,vpaddq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Add pairwise +FALSE,vpadds_f32,a: float32x2_t,f32,Floating-point add pairwise +FALSE,vpmax_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point maximum pairwise +TRUE,vpmax_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point maximum pairwise +TRUE,vpmax_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed maximum pairwise +TRUE,vpmax_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed maximum pairwise +TRUE,vpmax_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed maximum pairwise +TRUE,vpmax_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned maximum pairwise +TRUE,vpmax_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned maximum pairwise +TRUE,vpmax_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned maximum pairwise +FALSE,vpmaxnm_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point maximum number pairwise +TRUE,vpmaxnm_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point maximum number pairwise +FALSE,vpmaxnmq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point maximum number pairwise +TRUE,vpmaxnmq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point maximum number pairwise +TRUE,vpmaxnmq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point maximum number pairwise +FALSE,vpmaxnmqd_f64,a: float64x2_t,float64_t,Floating-point maximum number pairwise +FALSE,vpmaxnms_f32,a: float32x2_t,f32,Floating-point maximum number pairwise +FALSE,vpmaxq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point maximum pairwise +TRUE,vpmaxq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point maximum pairwise +TRUE,vpmaxq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point maximum pairwise +TRUE,vpmaxq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed maximum pairwise +TRUE,vpmaxq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed maximum pairwise +TRUE,vpmaxq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed maximum pairwise +TRUE,vpmaxq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned maximum pairwise +TRUE,vpmaxq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned maximum pairwise +TRUE,vpmaxq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned maximum pairwise +FALSE,vpmaxqd_f64,a: float64x2_t,float64_t,Floating-point maximum pairwise +FALSE,vpmaxs_f32,a: float32x2_t,f32,Floating-point maximum pairwise +FALSE,vpmin_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point minimum pairwise +TRUE,vpmin_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point minimum pairwise +TRUE,vpmin_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed minimum pairwise +TRUE,vpmin_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed minimum pairwise +TRUE,vpmin_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed minimum pairwise +TRUE,vpmin_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned minimum pairwise +TRUE,vpmin_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned minimum pairwise +TRUE,vpmin_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned minimum pairwise +FALSE,vpminnm_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point minimum number pairwise +FALSE,vpminnm_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point minimum number pairwise +FALSE,vpminnmq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point minimum number pairwise +FALSE,vpminnmq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point minimum number pairwise +FALSE,vpminnmq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point minimum number pairwise +FALSE,vpminnmqd_f64,a: float64x2_t,float64_t,Floating-point minimum number pairwise +FALSE,vpminnms_f32,a: float32x2_t,f32,Floating-point minimum number pairwise +FALSE,vpminq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point minimum pairwise +TRUE,vpminq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point minimum pairwise +TRUE,vpminq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point minimum pairwise +TRUE,vpminq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed minimum pairwise +TRUE,vpminq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed minimum pairwise +TRUE,vpminq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed minimum pairwise +TRUE,vpminq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned minimum pairwise +TRUE,vpminq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned minimum pairwise +TRUE,vpminq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned minimum pairwise +FALSE,vpminqd_f64,a: float64x2_t,float64_t,Floating-point minimum pairwise +FALSE,vpmins_f32,a: float32x2_t,f32,Floating-point minimum pairwise +TRUE,vqabs_s16,a: int16x4_t,int16x4_t,Signed saturating absolute value +TRUE,vqabs_s32,a: int32x2_t,int32x2_t,Signed saturating absolute value +TRUE,vqabs_s64,a: int64x1_t,int64x1_t,Signed saturating absolute value +TRUE,vqabs_s8,a: int8x8_t,int8x8_t,Signed saturating absolute value +FALSE,vqabsb_s8,a: i8,i8,Signed saturating absolute value +FALSE,vqabsd_s64,a: i64,i64,Signed saturating absolute value +FALSE,vqabsh_s16,a: i16,i16,Signed saturating absolute value +TRUE,vqabsq_s16,a: int16x8_t,int16x8_t,Signed saturating absolute value +TRUE,vqabsq_s32,a: int32x4_t,int32x4_t,Signed saturating absolute value +TRUE,vqabsq_s64,a: int64x2_t,int64x2_t,Signed saturating absolute value +TRUE,vqabsq_s8,a: int8x16_t,int8x16_t,Signed saturating absolute value +FALSE,vqabss_s32,a: i32,i32,Signed saturating absolute value +TRUE,vqadd_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed saturating add +TRUE,vqadd_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed saturating add +TRUE,vqadd_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Signed saturating add +TRUE,vqadd_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed saturating add +TRUE,vqadd_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned saturating add +TRUE,vqadd_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned saturating add +TRUE,vqadd_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Unsigned saturating add +TRUE,vqadd_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned saturating add +TRUE,vqaddb_s8,"a: i8, b: i8",i8,Signed saturating add +TRUE,vqaddb_u8,"a: u8, b: u8",u8,Unsigned saturating add +TRUE,vqaddd_s64,"a: i64, b: i64",i64,Signed saturating add +TRUE,vqaddd_u64,"a: u64, b: u64",u64,Unsigned saturating add +TRUE,vqaddh_s16,"a: i16, b: i16",i16,Signed saturating add +TRUE,vqaddh_u16,"a: u16, b: u16",u16,Unsigned saturating add +TRUE,vqaddq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed saturating add +TRUE,vqaddq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed saturating add +TRUE,vqaddq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Signed saturating add +TRUE,vqaddq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed saturating add +TRUE,vqaddq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned saturating add +TRUE,vqaddq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned saturating add +TRUE,vqaddq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Unsigned saturating add +TRUE,vqaddq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned saturating add +TRUE,vqadds_s32,"a: i32, b: i32",i32,Signed saturating add +TRUE,vqadds_u32,"a: u32, b: u32",u32,Unsigned saturating add +TRUE,vqdmlal_high_lane_s16,"a: int32x4_t, b: int16x8_t, v: int16x4_t, lane: const int",int32x4_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_high_lane_s32,"a: int64x2_t, b: int32x4_t, v: int32x2_t, lane: const int",int64x2_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_high_laneq_s16,"a: int32x4_t, b: int16x8_t, v: int16x8_t, lane: const int",int32x4_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_high_laneq_s32,"a: int64x2_t, b: int32x4_t, v: int32x4_t, lane: const int",int64x2_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_high_n_s16,"a: int32x4_t, b: int16x8_t, c: i16",int32x4_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_high_n_s32,"a: int64x2_t, b: int32x4_t, c: i32",int64x2_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_high_s16,"a: int32x4_t, b: int16x8_t, c: int16x8_t",int32x4_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_high_s32,"a: int64x2_t, b: int32x4_t, c: int32x4_t",int64x2_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_lane_s16,"a: int32x4_t, b: int16x4_t, v: int16x4_t, lane: const int",int32x4_t,Vector widening saturating doubling multiply accumulate with scalar +TRUE,vqdmlal_lane_s32,"a: int64x2_t, b: int32x2_t, v: int32x2_t, lane: const int",int64x2_t,Vector widening saturating doubling multiply accumulate with scalar +TRUE,vqdmlal_laneq_s16,"a: int32x4_t, b: int16x4_t, v: int16x8_t, lane: const int",int32x4_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_laneq_s32,"a: int64x2_t, b: int32x2_t, v: int32x4_t, lane: const int",int64x2_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_n_s16,"a: int32x4_t, b: int16x4_t, c: i16",int32x4_t,Vector widening saturating doubling multiply accumulate with scalar +TRUE,vqdmlal_n_s32,"a: int64x2_t, b: int32x2_t, c: i32",int64x2_t,Vector widening saturating doubling multiply accumulate with scalar +TRUE,vqdmlal_s16,"a: int32x4_t, b: int16x4_t, c: int16x4_t",int32x4_t,Signed saturating doubling multiply-add long +TRUE,vqdmlal_s32,"a: int64x2_t, b: int32x2_t, c: int32x2_t",int64x2_t,Signed saturating doubling multiply-add long +FALSE,vqdmlalh_lane_s16,"a: i32, b: i16, v: int16x4_t, lane: const int",i32,Signed saturating doubling multiply-add long +FALSE,vqdmlalh_laneq_s16,"a: i32, b: i16, v: int16x8_t, lane: const int",i32,Signed saturating doubling multiply-add long +FALSE,vqdmlalh_s16,"a: i32, b: i16, c: i16",i32,Signed saturating doubling multiply-add long +FALSE,vqdmlals_lane_s32,"a: i64, b: i32, v: int32x2_t, lane: const int",i64,Signed saturating doubling multiply-add long +FALSE,vqdmlals_laneq_s32,"a: i64, b: i32, v: int32x4_t, lane: const int",i64,Signed saturating doubling multiply-add long +FALSE,vqdmlals_s32,"a: i64, b: i32, c: i32",i64,Signed saturating doubling multiply-add long +TRUE,vqdmlsl_high_lane_s16,"a: int32x4_t, b: int16x8_t, v: int16x4_t, lane: const int",int32x4_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_high_lane_s32,"a: int64x2_t, b: int32x4_t, v: int32x2_t, lane: const int",int64x2_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_high_laneq_s16,"a: int32x4_t, b: int16x8_t, v: int16x8_t, lane: const int",int32x4_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_high_laneq_s32,"a: int64x2_t, b: int32x4_t, v: int32x4_t, lane: const int",int64x2_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_high_n_s16,"a: int32x4_t, b: int16x8_t, c: i16",int32x4_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_high_n_s32,"a: int64x2_t, b: int32x4_t, c: i32",int64x2_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_high_s16,"a: int32x4_t, b: int16x8_t, c: int16x8_t",int32x4_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_high_s32,"a: int64x2_t, b: int32x4_t, c: int32x4_t",int64x2_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_lane_s16,"a: int32x4_t, b: int16x4_t, v: int16x4_t, lane: const int",int32x4_t,Vector widening saturating doubling multiply subtract with scalar +TRUE,vqdmlsl_lane_s32,"a: int64x2_t, b: int32x2_t, v: int32x2_t, lane: const int",int64x2_t,Vector widening saturating doubling multiply subtract with scalar +TRUE,vqdmlsl_laneq_s16,"a: int32x4_t, b: int16x4_t, v: int16x8_t, lane: const int",int32x4_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_laneq_s32,"a: int64x2_t, b: int32x2_t, v: int32x4_t, lane: const int",int64x2_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_n_s16,"a: int32x4_t, b: int16x4_t, c: i16",int32x4_t,Vector widening saturating doubling multiply subtract with scalar +TRUE,vqdmlsl_n_s32,"a: int64x2_t, b: int32x2_t, c: i32",int64x2_t,Vector widening saturating doubling multiply subtract with scalar +TRUE,vqdmlsl_s16,"a: int32x4_t, b: int16x4_t, c: int16x4_t",int32x4_t,Signed saturating doubling multiply-subtract long +TRUE,vqdmlsl_s32,"a: int64x2_t, b: int32x2_t, c: int32x2_t",int64x2_t,Signed saturating doubling multiply-subtract long +FALSE,vqdmlslh_lane_s16,"a: i32, b: i16, v: int16x4_t, lane: const int",i32,Signed saturating doubling multiply-subtract long +FALSE,vqdmlslh_laneq_s16,"a: i32, b: i16, v: int16x8_t, lane: const int",i32,Signed saturating doubling multiply-subtract long +FALSE,vqdmlslh_s16,"a: i32, b: i16, c: i16",i32,Signed saturating doubling multiply-subtract long +FALSE,vqdmlsls_lane_s32,"a: i64, b: i32, v: int32x2_t, lane: const int",i64,Signed saturating doubling multiply-subtract long +FALSE,vqdmlsls_laneq_s32,"a: i64, b: i32, v: int32x4_t, lane: const int",i64,Signed saturating doubling multiply-subtract long +FALSE,vqdmlsls_s32,"a: i64, b: i32, c: i32",i64,Signed saturating doubling multiply-subtract long +FALSE,vqdmulh_lane_s16,"a: int16x4_t, v: int16x4_t, lane: const int",int16x4_t,Vector saturating doubling multiply high by scalar +FALSE,vqdmulh_lane_s32,"a: int32x2_t, v: int32x2_t, lane: const int",int32x2_t,Vector saturating doubling multiply high by scalar +FALSE,vqdmulh_laneq_s16,"a: int16x4_t, v: int16x8_t, lane: const int",int16x4_t,Signed saturating doubling multiply returning high half +FALSE,vqdmulh_laneq_s32,"a: int32x2_t, v: int32x4_t, lane: const int",int32x2_t,Signed saturating doubling multiply returning high half +TRUE,vqdmulh_n_s16,"a: int16x4_t, b: i16",int16x4_t,Vector saturating doubling multiply high with scalar +TRUE,vqdmulh_n_s32,"a: int32x2_t, b: i32",int32x2_t,Vector saturating doubling multiply high with scalar +TRUE,vqdmulh_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed saturating doubling multiply returning high half +TRUE,vqdmulh_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed saturating doubling multiply returning high half +TRUE,vqdmulhh_lane_s16,"a: i16, v: int16x4_t, lane: const int",i16,Signed saturating doubling multiply returning high half +TRUE,vqdmulhh_laneq_s16,"a: i16, v: int16x8_t, lane: const int",i16,Signed saturating doubling multiply returning high half +TRUE,vqdmulhh_s16,"a: i16, b: i16",i16,Signed saturating doubling multiply returning high half +FALSE,vqdmulhq_lane_s16,"a: int16x8_t, v: int16x4_t, lane: const int",int16x8_t,Vector saturating doubling multiply high by scalar +FALSE,vqdmulhq_lane_s32,"a: int32x4_t, v: int32x2_t, lane: const int",int32x4_t,Vector saturating doubling multiply high by scalar +FALSE,vqdmulhq_laneq_s16,"a: int16x8_t, v: int16x8_t, lane: const int",int16x8_t,Signed saturating doubling multiply returning high half +FALSE,vqdmulhq_laneq_s32,"a: int32x4_t, v: int32x4_t, lane: const int",int32x4_t,Signed saturating doubling multiply returning high half +FALSE,vqdmulhq_n_s16,"a: int16x8_t, b: i16",int16x8_t,Vector saturating doubling multiply high with scalar +FALSE,vqdmulhq_n_s32,"a: int32x4_t, b: i32",int32x4_t,Vector saturating doubling multiply high with scalar +FALSE,vqdmulhq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed saturating doubling multiply returning high half +TRUE,vqdmulhq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed saturating doubling multiply returning high half +TRUE,vqdmulhs_lane_s32,"a: i32, v: int32x2_t, lane: const int",i32,Signed saturating doubling multiply returning high half +TRUE,vqdmulhs_laneq_s32,"a: i32, v: int32x4_t, lane: const int",i32,Signed saturating doubling multiply returning high half +TRUE,vqdmulhs_s32,"a: i32, b: i32",i32,Signed saturating doubling multiply returning high half +TRUE,vqdmull_high_lane_s16,"a: int16x8_t, v: int16x4_t, lane: const int",int32x4_t,Signed saturating doubling multiply long +TRUE,vqdmull_high_lane_s32,"a: int32x4_t, v: int32x2_t, lane: const int",int64x2_t,Signed saturating doubling multiply long +TRUE,vqdmull_high_laneq_s16,"a: int16x8_t, v: int16x8_t, lane: const int",int32x4_t,Signed saturating doubling multiply long +TRUE,vqdmull_high_laneq_s32,"a: int32x4_t, v: int32x4_t, lane: const int",int64x2_t,Signed saturating doubling multiply long +TRUE,vqdmull_high_n_s16,"a: int16x8_t, b: i16",int32x4_t,Signed saturating doubling multiply long +TRUE,vqdmull_high_n_s32,"a: int32x4_t, b: i32",int64x2_t,Signed saturating doubling multiply long +TRUE,vqdmull_high_s16,"a: int16x8_t, b: int16x8_t",int32x4_t,Signed saturating doubling multiply long +TRUE,vqdmull_high_s32,"a: int32x4_t, b: int32x4_t",int64x2_t,Signed saturating doubling multiply long +TRUE,vqdmull_lane_s16,"a: int16x4_t, v: int16x4_t, lane: const int",int32x4_t,Vector saturating doubling long multiply by scalar +TRUE,vqdmull_lane_s32,"a: int32x2_t, v: int32x2_t, lane: const int",int64x2_t,Vector saturating doubling long multiply by scalar +TRUE,vqdmull_laneq_s16,"a: int16x4_t, v: int16x8_t, lane: const int",int32x4_t,Signed saturating doubling multiply long +TRUE,vqdmull_laneq_s32,"a: int32x2_t, v: int32x4_t, lane: const int",int64x2_t,Signed saturating doubling multiply long +TRUE,vqdmull_n_s16,"a: int16x4_t, b: i16",int32x4_t,Vector saturating doubling long multiply with scalar +TRUE,vqdmull_n_s32,"a: int32x2_t, b: i32",int64x2_t,Vector saturating doubling long multiply with scalar +TRUE,vqdmull_s16,"a: int16x4_t, b: int16x4_t",int32x4_t,Signed saturating doubling multiply long +TRUE,vqdmull_s32,"a: int32x2_t, b: int32x2_t",int64x2_t,Signed saturating doubling multiply long +TRUE,vqdmullh_lane_s16,"a: i16, v: int16x4_t, lane: const int",i32,Signed saturating doubling multiply long +TRUE,vqdmullh_laneq_s16,"a: i16, v: int16x8_t, lane: const int",i32,Signed saturating doubling multiply long +TRUE,vqdmullh_s16,"a: i16, b: i16",i32,Signed saturating doubling multiply long +TRUE,vqdmulls_lane_s32,"a: i32, v: int32x2_t, lane: const int",i64,Signed saturating doubling multiply long +TRUE,vqdmulls_laneq_s32,"a: i32, v: int32x4_t, lane: const int",i64,Signed saturating doubling multiply long +TRUE,vqdmulls_s32,"a: i32, b: i32",i64,Signed saturating doubling multiply long +FALSE,vqmovn_high_s16,"r: int8x8_t, a: int16x8_t",int8x16_t,Signed saturating extract narrow +FALSE,vqmovn_high_s32,"r: int16x4_t, a: int32x4_t",int16x8_t,Signed saturating extract narrow +FALSE,vqmovn_high_s64,"r: int32x2_t, a: int64x2_t",int32x4_t,Signed saturating extract narrow +FALSE,vqmovn_high_u16,"r: uint8x8_t, a: uint16x8_t",uint8x16_t,Unsigned saturating extract narrow +FALSE,vqmovn_high_u32,"r: uint16x4_t, a: uint32x4_t",uint16x8_t,Unsigned saturating extract narrow +FALSE,vqmovn_high_u64,"r: uint32x2_t, a: uint64x2_t",uint32x4_t,Unsigned saturating extract narrow +FALSE,vqmovn_s16,a: int16x8_t,int8x8_t,Signed saturating extract narrow +FALSE,vqmovn_s32,a: int32x4_t,int16x4_t,Signed saturating extract narrow +FALSE,vqmovn_s64,a: int64x2_t,int32x2_t,Signed saturating extract narrow +FALSE,vqmovn_u16,a: uint16x8_t,uint8x8_t,Unsigned saturating extract narrow +FALSE,vqmovn_u32,a: uint32x4_t,uint16x4_t,Unsigned saturating extract narrow +TRUE,vqmovn_u64,a: uint64x2_t,uint32x2_t,Unsigned saturating extract narrow +FALSE,vqmovnd_s64,a: i64,i32,Signed saturating extract narrow +FALSE,vqmovnd_u64,a: u64,u32,Unsigned saturating extract narrow +FALSE,vqmovnh_s16,a: i16,i8,Signed saturating extract narrow +FALSE,vqmovnh_u16,a: u16,u8,Unsigned saturating extract narrow +FALSE,vqmovns_s32,a: i32,i16,Signed saturating extract narrow +FALSE,vqmovns_u32,a: u32,u16,Unsigned saturating extract narrow +FALSE,vqmovun_high_s16,"r: uint8x8_t, a: int16x8_t",uint8x16_t,Signed saturating extract unsigned narrow +FALSE,vqmovun_high_s32,"r: uint16x4_t, a: int32x4_t",uint16x8_t,Signed saturating extract unsigned narrow +FALSE,vqmovun_high_s64,"r: uint32x2_t, a: int64x2_t",uint32x4_t,Signed saturating extract unsigned narrow +FALSE,vqmovun_s16,a: int16x8_t,uint8x8_t,Signed saturating extract unsigned narrow +FALSE,vqmovun_s32,a: int32x4_t,uint16x4_t,Signed saturating extract unsigned narrow +FALSE,vqmovun_s64,a: int64x2_t,uint32x2_t,Signed saturating extract unsigned narrow +FALSE,vqmovund_s64,a: i64,u32,Signed saturating extract unsigned narrow +FALSE,vqmovunh_s16,a: i16,u8,Signed saturating extract unsigned narrow +FALSE,vqmovuns_s32,a: i32,u16,Signed saturating extract unsigned narrow +TRUE,vqneg_s16,a: int16x4_t,int16x4_t,Signed saturating negate +TRUE,vqneg_s32,a: int32x2_t,int32x2_t,Signed saturating negate +TRUE,vqneg_s64,a: int64x1_t,int64x1_t,Signed saturating negate +TRUE,vqneg_s8,a: int8x8_t,int8x8_t,Signed saturating negate +FALSE,vqnegb_s8,a: i8,i8,Signed saturating negate +FALSE,vqnegd_s64,a: i64,i64,Signed saturating negate +FALSE,vqnegh_s16,a: i16,i16,Signed saturating negate +TRUE,vqnegq_s16,a: int16x8_t,int16x8_t,Signed saturating negate +TRUE,vqnegq_s32,a: int32x4_t,int32x4_t,Signed saturating negate +TRUE,vqnegq_s64,a: int64x2_t,int64x2_t,Signed saturating negate +TRUE,vqnegq_s8,a: int8x16_t,int8x16_t,Signed saturating negate +FALSE,vqnegs_s32,a: i32,i32,Signed saturating negate +FALSE,vqrdmlah_lane_s16,"a: int16x4_t, b: int16x4_t, v: int16x4_t, lane: const int",int16x4_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlah_lane_s32,"a: int32x2_t, b: int32x2_t, v: int32x2_t, lane: const int",int32x2_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlah_laneq_s16,"a: int16x4_t, b: int16x4_t, v: int16x8_t, lane: const int",int16x4_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlah_laneq_s32,"a: int32x2_t, b: int32x2_t, v: int32x4_t, lane: const int",int32x2_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlah_s16,"a: int16x4_t, b: int16x4_t, c: int16x4_t",int16x4_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlah_s32,"a: int32x2_t, b: int32x2_t, c: int32x2_t",int32x2_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahh_lane_s16,"a: i16, b: i16, v: int16x4_t, lane: const int",i16,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahh_laneq_s16,"a: i16, b: i16, v: int16x8_t, lane: const int",i16,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahh_s16,"a: i16, b: i16, c: i16",i16,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlahq_lane_s16,"a: int16x8_t, b: int16x8_t, v: int16x4_t, lane: const int",int16x8_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahq_lane_s32,"a: int32x4_t, b: int32x4_t, v: int32x2_t, lane: const int",int32x4_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahq_laneq_s16,"a: int16x8_t, b: int16x8_t, v: int16x8_t, lane: const int",int16x8_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahq_laneq_s32,"a: int32x4_t, b: int32x4_t, v: int32x4_t, lane: const int",int32x4_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahq_s16,"a: int16x8_t, b: int16x8_t, c: int16x8_t",int16x8_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahq_s32,"a: int32x4_t, b: int32x4_t, c: int32x4_t",int32x4_t,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahs_lane_s32,"a: i32, b: i32, v: int32x4_t, lane: const int",i32,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahs_laneq_s32,"a: i32, b: i32, v: int32x8_t, lane: const int",i32,Signed saturating rounding doubling multiply accumulate returning high half +FALSE,vqrdmlahs_s32,"a: i32, b: i32, c: i32",i32,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlsh_lane_s16,"a: int16x4_t, b: int16x4_t, v: int16x4_t, lane: const int",int16x4_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlsh_lane_s32,"a: int32x2_t, b: int32x2_t, v: int32x2_t, lane: const int",int32x2_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlsh_laneq_s16,"a: int16x4_t, b: int16x4_t, v: int16x8_t, lane: const int",int16x4_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlsh_laneq_s32,"a: int32x2_t, b: int32x2_t, v: int32x4_t, lane: const int",int32x2_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlsh_s16,"a: int16x4_t, b: int16x4_t, c: int16x4_t",int16x4_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlsh_s32,"a: int32x2_t, b: int32x2_t, c: int32x2_t",int32x2_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshh_lane_s16,"a: i16, b: i16, v: int16x4_t, lane: const int",i16,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshh_laneq_s16,"a: i16, b: i16, v: int16x8_t, lane: const int",i16,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshh_s16,"a: i16, b: i16, c: i16",i16,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshq_lane_s16,"a: int16x8_t, b: int16x8_t, v: int16x4_t, lane: const int",int16x8_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshq_lane_s32,"a: int32x4_t, b: int32x4_t, v: int32x2_t, lane: const int",int32x4_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshq_laneq_s16,"a: int16x8_t, b: int16x8_t, v: int16x8_t, lane: const int",int16x8_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshq_laneq_s32,"a: int32x4_t, b: int32x4_t, v: int32x4_t, lane: const int",int32x4_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshq_s16,"a: int16x8_t, b: int16x8_t, c: int16x8_t",int16x8_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshq_s32,"a: int32x4_t, b: int32x4_t, c: int32x4_t",int32x4_t,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshs_lane_s32,"a: i32, b: i32, v: int32x4_t, lane: const int",i32,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshs_laneq_s32,"a: i32, b: i32, v: int32x8_t, lane: const int",i32,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmlshs_s32,"a: i32, b: i32, c: i32",i32,Signed saturating rounding doubling multiply subtract returning high half +FALSE,vqrdmulh_lane_s16,"a: int16x4_t, v: int16x4_t, lane: const int",int16x4_t,Vector rounding saturating doubling multiply high by scalar +FALSE,vqrdmulh_lane_s32,"a: int32x2_t, v: int32x2_t, lane: const int",int32x2_t,Vector rounding saturating doubling multiply high by scalar +FALSE,vqrdmulh_laneq_s16,"a: int16x4_t, v: int16x8_t, lane: const int",int16x4_t,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulh_laneq_s32,"a: int32x2_t, v: int32x4_t, lane: const int",int32x2_t,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulh_n_s16,"a: int16x4_t, b: i16",int16x4_t,Vector saturating rounding doubling multiply high with scalar +FALSE,vqrdmulh_n_s32,"a: int32x2_t, b: i32",int32x2_t,Vector saturating rounding doubling multiply high with scalar +FALSE,vqrdmulh_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulh_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhh_lane_s16,"a: i16, v: int16x4_t, lane: const int",i16,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhh_laneq_s16,"a: i16, v: int16x8_t, lane: const int",i16,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhh_s16,"a: i16, b: i16",i16,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhq_lane_s16,"a: int16x8_t, v: int16x4_t, lane: const int",int16x8_t,Vector rounding saturating doubling multiply high by scalar +FALSE,vqrdmulhq_lane_s32,"a: int32x4_t, v: int32x2_t, lane: const int",int32x4_t,Vector rounding saturating doubling multiply high by scalar +FALSE,vqrdmulhq_laneq_s16,"a: int16x8_t, v: int16x8_t, lane: const int",int16x8_t,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhq_laneq_s32,"a: int32x4_t, v: int32x4_t, lane: const int",int32x4_t,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhq_n_s16,"a: int16x8_t, b: i16",int16x8_t,Vector saturating rounding doubling multiply high with scalar +FALSE,vqrdmulhq_n_s32,"a: int32x4_t, b: i32",int32x4_t,Vector saturating rounding doubling multiply high with scalar +FALSE,vqrdmulhq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhs_lane_s32,"a: i32, v: int32x2_t, lane: const int",i32,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhs_laneq_s32,"a: i32, v: int32x4_t, lane: const int",i32,Signed saturating rounding doubling multiply returning high half +FALSE,vqrdmulhs_s32,"a: i32, b: i32",i32,Signed saturating rounding doubling multiply returning high half +TRUE,vqrshl_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed saturating rounding shift left +TRUE,vqrshl_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed saturating rounding shift left +TRUE,vqrshl_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Signed saturating rounding shift left +TRUE,vqrshl_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed saturating rounding shift left +TRUE,vqrshl_u16,"a: uint16x4_t, b: int16x4_t",uint16x4_t,Unsigned saturating rounding shift left +TRUE,vqrshl_u32,"a: uint32x2_t, b: int32x2_t",uint32x2_t,Unsigned saturating rounding shift left +TRUE,vqrshl_u64,"a: uint64x1_t, b: int64x1_t",uint64x1_t,Unsigned saturating rounding shift left +TRUE,vqrshl_u8,"a: uint8x8_t, b: int8x8_t",uint8x8_t,Unsigned saturating rounding shift left +TRUE,vqrshlb_s8,"a: i8, b: i8",i8,Signed saturating rounding shift left +TRUE,vqrshlb_u8,"a: u8, b: i8",u8,Unsigned saturating rounding shift left +TRUE,vqrshld_s64,"a: i64, b: i64",i64,Signed saturating rounding shift left +TRUE,vqrshld_u64,"a: u64, b: i64",u64,Unsigned saturating rounding shift left +TRUE,vqrshlh_s16,"a: i16, b: i16",i16,Signed saturating rounding shift left +TRUE,vqrshlh_u16,"a: u16, b: i16",u16,Unsigned saturating rounding shift left +TRUE,vqrshlq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed saturating rounding shift left +TRUE,vqrshlq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed saturating rounding shift left +TRUE,vqrshlq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Signed saturating rounding shift left +TRUE,vqrshlq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed saturating rounding shift left +TRUE,vqrshlq_u16,"a: uint16x8_t, b: int16x8_t",uint16x8_t,Unsigned saturating rounding shift left +TRUE,vqrshlq_u32,"a: uint32x4_t, b: int32x4_t",uint32x4_t,Unsigned saturating rounding shift left +TRUE,vqrshlq_u64,"a: uint64x2_t, b: int64x2_t",uint64x2_t,Unsigned saturating rounding shift left +TRUE,vqrshlq_u8,"a: uint8x16_t, b: int8x16_t",uint8x16_t,Unsigned saturating rounding shift left +TRUE,vqrshls_s32,"a: i32, b: i32",i32,Signed saturating rounding shift left +TRUE,vqrshls_u32,"a: u32, b: i32",u32,Unsigned saturating rounding shift left +TRUE,vqrshrn_high_n_s16,"r: int8x8_t, a: int16x8_t, n: const int",int8x16_t,Signed saturating rounded shift right narrow +TRUE,vqrshrn_high_n_s32,"r: int16x4_t, a: int32x4_t, n: const int",int16x8_t,Signed saturating rounded shift right narrow +TRUE,vqrshrn_high_n_s64,"r: int32x2_t, a: int64x2_t, n: const int",int32x4_t,Signed saturating rounded shift right narrow +TRUE,vqrshrn_high_n_u16,"r: uint8x8_t, a: uint16x8_t, n: const int",uint8x16_t,Unsigned saturating rounded shift right narrow +TRUE,vqrshrn_high_n_u32,"r: uint16x4_t, a: uint32x4_t, n: const int",uint16x8_t,Unsigned saturating rounded shift right narrow +TRUE,vqrshrn_high_n_u64,"r: uint32x2_t, a: uint64x2_t, n: const int",uint32x4_t,Unsigned saturating rounded shift right narrow +TRUE,vqrshrn_n_s16,"a: int16x8_t, n: const int",int8x8_t,Signed saturating rounded shift right narrow +TRUE,vqrshrn_n_s32,"a: int32x4_t, n: const int",int16x4_t,Signed saturating rounded shift right narrow +TRUE,vqrshrn_n_s64,"a: int64x2_t, n: const int",int32x2_t,Signed saturating rounded shift right narrow +TRUE,vqrshrn_n_u16,"a: uint16x8_t, n: const int",uint8x8_t,Unsigned saturating rounded shift right narrow +TRUE,vqrshrn_n_u32,"a: uint32x4_t, n: const int",uint16x4_t,Unsigned saturating rounded shift right narrow +TRUE,vqrshrn_n_u64,"a: uint64x2_t, n: const int",uint32x2_t,Unsigned saturating rounded shift right narrow +TRUE,vqrshrnd_n_s64,"a: i64, n: const int",i32,Signed saturating rounded shift right narrow +TRUE,vqrshrnd_n_u64,"a: u64, n: const int",u32,Unsigned saturating rounded shift right narrow +TRUE,vqrshrnh_n_s16,"a: i16, n: const int",i8,Signed saturating rounded shift right narrow +TRUE,vqrshrnh_n_u16,"a: u16, n: const int",u8,Unsigned saturating rounded shift right narrow +TRUE,vqrshrns_n_s32,"a: i32, n: const int",i16,Signed saturating rounded shift right narrow +TRUE,vqrshrns_n_u32,"a: u32, n: const int",u16,Unsigned saturating rounded shift right narrow +TRUE,vqrshrun_high_n_s16,"r: uint8x8_t, a: int16x8_t, n: const int",uint8x16_t,Signed saturating rounded shift right unsigned narrow +TRUE,vqrshrun_high_n_s32,"r: uint16x4_t, a: int32x4_t, n: const int",uint16x8_t,Signed saturating rounded shift right unsigned narrow +TRUE,vqrshrun_high_n_s64,"r: uint32x2_t, a: int64x2_t, n: const int",uint32x4_t,Signed saturating rounded shift right unsigned narrow +TRUE,vqrshrun_n_s16,"a: int16x8_t, n: const int",uint8x8_t,Signed saturating rounded shift right unsigned narrow +TRUE,vqrshrun_n_s32,"a: int32x4_t, n: const int",uint16x4_t,Signed saturating rounded shift right unsigned narrow +TRUE,vqrshrun_n_s64,"a: int64x2_t, n: const int",uint32x2_t,Signed saturating rounded shift right unsigned narrow +TRUE,vqrshrund_n_s64,"a: i64, n: const int",u32,Signed saturating rounded shift right unsigned narrow +TRUE,vqrshrunh_n_s16,"a: i16, n: const int",u8,Signed saturating rounded shift right unsigned narrow +TRUE,vqrshruns_n_s32,"a: i32, n: const int",u16,Signed saturating rounded shift right unsigned narrow +TRUE,vqshl_n_s16,"a: int16x4_t, n: const int",int16x4_t,Signed saturating shift left +TRUE,vqshl_n_s32,"a: int32x2_t, n: const int",int32x2_t,Signed saturating shift left +TRUE,vqshl_n_s64,"a: int64x1_t, n: const int",int64x1_t,Signed saturating shift left +TRUE,vqshl_n_s8,"a: int8x8_t, n: const int",int8x8_t,Signed saturating shift left +TRUE,vqshl_n_u16,"a: uint16x4_t, n: const int",uint16x4_t,Unsigned saturating shift left +TRUE,vqshl_n_u32,"a: uint32x2_t, n: const int",uint32x2_t,Unsigned saturating shift left +TRUE,vqshl_n_u64,"a: uint64x1_t, n: const int",uint64x1_t,Unsigned saturating shift left +TRUE,vqshl_n_u8,"a: uint8x8_t, n: const int",uint8x8_t,Unsigned saturating shift left +TRUE,vqshl_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed saturating shift left +TRUE,vqshl_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed saturating shift left +TRUE,vqshl_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Signed saturating shift left +TRUE,vqshl_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed saturating shift left +TRUE,vqshl_u16,"a: uint16x4_t, b: int16x4_t",uint16x4_t,Unsigned saturating shift left +TRUE,vqshl_u32,"a: uint32x2_t, b: int32x2_t",uint32x2_t,Unsigned saturating shift left +TRUE,vqshl_u64,"a: uint64x1_t, b: int64x1_t",uint64x1_t,Unsigned saturating shift left +TRUE,vqshl_u8,"a: uint8x8_t, b: int8x8_t",uint8x8_t,Unsigned saturating shift left +TRUE,vqshlb_n_s8,"a: i8, n: const int",i8,Signed saturating shift left +TRUE,vqshlb_n_u8,"a: u8, n: const int",u8,Unsigned saturating shift left +TRUE,vqshlb_s8,"a: i8, b: i8",i8,Signed saturating shift left +TRUE,vqshlb_u8,"a: u8, b: i8",u8,Unsigned saturating shift left +TRUE,vqshld_n_s64,"a: i64, n: const int",i64,Signed saturating shift left +TRUE,vqshld_n_u64,"a: u64, n: const int",u64,Unsigned saturating shift left +TRUE,vqshld_s64,"a: i64, b: i64",i64,Signed saturating shift left +TRUE,vqshld_u64,"a: u64, b: i64",u64,Unsigned saturating shift left +TRUE,vqshlh_n_s16,"a: i16, n: const int",i16,Signed saturating shift left +TRUE,vqshlh_n_u16,"a: u16, n: const int",u16,Unsigned saturating shift left +TRUE,vqshlh_s16,"a: i16, b: i16",i16,Signed saturating shift left +TRUE,vqshlh_u16,"a: u16, b: i16",u16,Unsigned saturating shift left +TRUE,vqshlq_n_s16,"a: int16x8_t, n: const int",int16x8_t,Signed saturating shift left +TRUE,vqshlq_n_s32,"a: int32x4_t, n: const int",int32x4_t,Signed saturating shift left +TRUE,vqshlq_n_s64,"a: int64x2_t, n: const int",int64x2_t,Signed saturating shift left +TRUE,vqshlq_n_s8,"a: int8x16_t, n: const int",int8x16_t,Signed saturating shift left +TRUE,vqshlq_n_u16,"a: uint16x8_t, n: const int",uint16x8_t,Unsigned saturating shift left +TRUE,vqshlq_n_u32,"a: uint32x4_t, n: const int",uint32x4_t,Unsigned saturating shift left +TRUE,vqshlq_n_u64,"a: uint64x2_t, n: const int",uint64x2_t,Unsigned saturating shift left +TRUE,vqshlq_n_u8,"a: uint8x16_t, n: const int",uint8x16_t,Unsigned saturating shift left +TRUE,vqshlq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed saturating shift left +TRUE,vqshlq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed saturating shift left +TRUE,vqshlq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Signed saturating shift left +TRUE,vqshlq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed saturating shift left +TRUE,vqshlq_u16,"a: uint16x8_t, b: int16x8_t",uint16x8_t,Unsigned saturating shift left +TRUE,vqshlq_u32,"a: uint32x4_t, b: int32x4_t",uint32x4_t,Unsigned saturating shift left +TRUE,vqshlq_u64,"a: uint64x2_t, b: int64x2_t",uint64x2_t,Unsigned saturating shift left +TRUE,vqshlq_u8,"a: uint8x16_t, b: int8x16_t",uint8x16_t,Unsigned saturating shift left +TRUE,vqshls_n_s32,"a: i32, n: const int",i32,Signed saturating shift left +TRUE,vqshls_n_u32,"a: u32, n: const int",u32,Unsigned saturating shift left +TRUE,vqshls_s32,"a: i32, b: i32",i32,Signed saturating shift left +TRUE,vqshls_u32,"a: u32, b: i32",u32,Unsigned saturating shift left +FALSE,vqshlu_n_s16,"a: int16x4_t, n: const int",uint16x4_t,Signed saturating shift left unsigned +FALSE,vqshlu_n_s32,"a: int32x2_t, n: const int",uint32x2_t,Signed saturating shift left unsigned +FALSE,vqshlu_n_s64,"a: int64x1_t, n: const int",uint64x1_t,Signed saturating shift left unsigned +FALSE,vqshlu_n_s8,"a: int8x8_t, n: const int",uint8x8_t,Signed saturating shift left unsigned +FALSE,vqshlub_n_s8,"a: i8, n: const int",u8,Signed saturating shift left unsigned +FALSE,vqshlud_n_s64,"a: i64, n: const int",u64,Signed saturating shift left unsigned +FALSE,vqshluh_n_s16,"a: i16, n: const int",u16,Signed saturating shift left unsigned +FALSE,vqshluq_n_s16,"a: int16x8_t, n: const int",uint16x8_t,Signed saturating shift left unsigned +FALSE,vqshluq_n_s32,"a: int32x4_t, n: const int",uint32x4_t,Signed saturating shift left unsigned +FALSE,vqshluq_n_s64,"a: int64x2_t, n: const int",uint64x2_t,Signed saturating shift left unsigned +FALSE,vqshluq_n_s8,"a: int8x16_t, n: const int",uint8x16_t,Signed saturating shift left unsigned +FALSE,vqshlus_n_s32,"a: i32, n: const int",u32,Signed saturating shift left unsigned +TRUE,vqshrn_high_n_s16,"r: int8x8_t, a: int16x8_t, n: const int",int8x16_t,Signed saturating shift right narrow +TRUE,vqshrn_high_n_s32,"r: int16x4_t, a: int32x4_t, n: const int",int16x8_t,Signed saturating shift right narrow +TRUE,vqshrn_high_n_s64,"r: int32x2_t, a: int64x2_t, n: const int",int32x4_t,Signed saturating shift right narrow +TRUE,vqshrn_high_n_u16,"r: uint8x8_t, a: uint16x8_t, n: const int",uint8x16_t,Unsigned saturating shift right narrow +TRUE,vqshrn_high_n_u32,"r: uint16x4_t, a: uint32x4_t, n: const int",uint16x8_t,Unsigned saturating shift right narrow +TRUE,vqshrn_high_n_u64,"r: uint32x2_t, a: uint64x2_t, n: const int",uint32x4_t,Unsigned saturating shift right narrow +TRUE,vqshrn_n_s16,"a: int16x8_t, n: const int",int8x8_t,Signed saturating shift right narrow +TRUE,vqshrn_n_s32,"a: int32x4_t, n: const int",int16x4_t,Signed saturating shift right narrow +TRUE,vqshrn_n_s64,"a: int64x2_t, n: const int",int32x2_t,Signed saturating shift right narrow +TRUE,vqshrn_n_u16,"a: uint16x8_t, n: const int",uint8x8_t,Unsigned saturating shift right narrow +TRUE,vqshrn_n_u32,"a: uint32x4_t, n: const int",uint16x4_t,Unsigned saturating shift right narrow +TRUE,vqshrn_n_u64,"a: uint64x2_t, n: const int",uint32x2_t,Unsigned saturating shift right narrow +TRUE,vqshrnd_n_s64,"a: i64, n: const int",i32,Signed saturating shift right narrow +TRUE,vqshrnd_n_u64,"a: u64, n: const int",u32,Unsigned saturating shift right narrow +TRUE,vqshrnh_n_s16,"a: i16, n: const int",i8,Signed saturating shift right narrow +TRUE,vqshrnh_n_u16,"a: u16, n: const int",u8,Unsigned saturating shift right narrow +TRUE,vqshrns_n_s32,"a: i32, n: const int",i16,Signed saturating shift right narrow +TRUE,vqshrns_n_u32,"a: u32, n: const int",u16,Unsigned saturating shift right narrow +TRUE,vqshrun_high_n_s16,"r: uint8x8_t, a: int16x8_t, n: const int",uint8x16_t,Signed saturating shift right unsigned narrow +TRUE,vqshrun_high_n_s32,"r: uint16x4_t, a: int32x4_t, n: const int",uint16x8_t,Signed saturating shift right unsigned narrow +TRUE,vqshrun_high_n_s64,"r: uint32x2_t, a: int64x2_t, n: const int",uint32x4_t,Signed saturating shift right unsigned narrow +TRUE,vqshrun_n_s16,"a: int16x8_t, n: const int",uint8x8_t,Signed saturating shift right unsigned narrow +TRUE,vqshrun_n_s32,"a: int32x4_t, n: const int",uint16x4_t,Signed saturating shift right unsigned narrow +TRUE,vqshrun_n_s64,"a: int64x2_t, n: const int",uint32x2_t,Signed saturating shift right unsigned narrow +TRUE,vqshrund_n_s64,"a: i64, n: const int",u32,Signed saturating shift right unsigned narrow +TRUE,vqshrunh_n_s16,"a: i16, n: const int",u8,Signed saturating shift right unsigned narrow +TRUE,vqshruns_n_s32,"a: i32, n: const int",u16,Signed saturating shift right unsigned narrow +TRUE,vqsub_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed saturating subtract +TRUE,vqsub_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed saturating subtract +TRUE,vqsub_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Signed saturating subtract +TRUE,vqsub_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed saturating subtract +TRUE,vqsub_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned saturating subtract +TRUE,vqsub_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned saturating subtract +TRUE,vqsub_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Unsigned saturating subtract +TRUE,vqsub_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned saturating subtract +TRUE,vqsubb_s8,"a: i8, b: i8",i8,Signed saturating subtract +TRUE,vqsubb_u8,"a: u8, b: u8",u8,Unsigned saturating subtract +TRUE,vqsubd_s64,"a: i64, b: i64",i64,Signed saturating subtract +TRUE,vqsubd_u64,"a: u64, b: u64",u64,Unsigned saturating subtract +TRUE,vqsubh_s16,"a: i16, b: i16",i16,Signed saturating subtract +TRUE,vqsubh_u16,"a: u16, b: u16",u16,Unsigned saturating subtract +TRUE,vqsubq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed saturating subtract +TRUE,vqsubq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed saturating subtract +TRUE,vqsubq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Signed saturating subtract +TRUE,vqsubq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed saturating subtract +TRUE,vqsubq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned saturating subtract +TRUE,vqsubq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned saturating subtract +TRUE,vqsubq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Unsigned saturating subtract +TRUE,vqsubq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned saturating subtract +TRUE,vqsubs_s32,"a: i32, b: i32",i32,Signed saturating subtract +TRUE,vqsubs_u32,"a: u32, b: u32",u32,Unsigned saturating subtract +TRUE,vqtbl1_p8,"t: poly8x16_t, idx: uint8x8_t",poly8x8_t,Table vector lookup +TRUE,vqtbl1_s8,"t: int8x16_t, idx: uint8x8_t",int8x8_t,Table vector lookup +TRUE,vqtbl1_u8,"t: uint8x16_t, idx: uint8x8_t",uint8x8_t,Table vector lookup +TRUE,vqtbl1q_p8,"t: poly8x16_t, idx: uint8x16_t",poly8x16_t,Table vector lookup +TRUE,vqtbl1q_s8,"t: int8x16_t, idx: uint8x16_t",int8x16_t,Table vector lookup +TRUE,vqtbl1q_u8,"t: uint8x16_t, idx: uint8x16_t",uint8x16_t,Table vector lookup +TRUE,vqtbl2_p8,"t: poly8x16x2_t, idx: uint8x8_t",poly8x8_t,Table vector lookup +TRUE,vqtbl2_s8,"t: int8x16x2_t, idx: uint8x8_t",int8x8_t,Table vector lookup +TRUE,vqtbl2_u8,"t: uint8x16x2_t, idx: uint8x8_t",uint8x8_t,Table vector lookup +TRUE,vqtbl2q_p8,"t: poly8x16x2_t, idx: uint8x16_t",poly8x16_t,Table vector lookup +TRUE,vqtbl2q_s8,"t: int8x16x2_t, idx: uint8x16_t",int8x16_t,Table vector lookup +TRUE,vqtbl2q_u8,"t: uint8x16x2_t, idx: uint8x16_t",uint8x16_t,Table vector lookup +TRUE,vqtbl3_p8,"t: poly8x16x3_t, idx: uint8x8_t",poly8x8_t,Table vector lookup +TRUE,vqtbl3_s8,"t: int8x16x3_t, idx: uint8x8_t",int8x8_t,Table vector lookup +TRUE,vqtbl3_u8,"t: uint8x16x3_t, idx: uint8x8_t",uint8x8_t,Table vector lookup +TRUE,vqtbl3q_p8,"t: poly8x16x3_t, idx: uint8x16_t",poly8x16_t,Table vector lookup +TRUE,vqtbl3q_s8,"t: int8x16x3_t, idx: uint8x16_t",int8x16_t,Table vector lookup +TRUE,vqtbl3q_u8,"t: uint8x16x3_t, idx: uint8x16_t",uint8x16_t,Table vector lookup +TRUE,vqtbl4_p8,"t: poly8x16x4_t, idx: uint8x8_t",poly8x8_t,Table vector lookup +TRUE,vqtbl4_s8,"t: int8x16x4_t, idx: uint8x8_t",int8x8_t,Table vector lookup +TRUE,vqtbl4_u8,"t: uint8x16x4_t, idx: uint8x8_t",uint8x8_t,Table vector lookup +TRUE,vqtbl4q_p8,"t: poly8x16x4_t, idx: uint8x16_t",poly8x16_t,Table vector lookup +TRUE,vqtbl4q_s8,"t: int8x16x4_t, idx: uint8x16_t",int8x16_t,Table vector lookup +TRUE,vqtbl4q_u8,"t: uint8x16x4_t, idx: uint8x16_t",uint8x16_t,Table vector lookup +TRUE,vqtbx1_p8,"a: poly8x8_t, t: poly8x16_t, idx: uint8x8_t",poly8x8_t,Table vector lookup extension +TRUE,vqtbx1_s8,"a: int8x8_t, t: int8x16_t, idx: uint8x8_t",int8x8_t,Table vector lookup extension +TRUE,vqtbx1_u8,"a: uint8x8_t, t: uint8x16_t, idx: uint8x8_t",uint8x8_t,Table vector lookup extension +TRUE,vqtbx1q_p8,"a: poly8x16_t, t: poly8x16_t, idx: uint8x16_t",poly8x16_t,Table vector lookup extension +TRUE,vqtbx1q_s8,"a: int8x16_t, t: int8x16_t, idx: uint8x16_t",int8x16_t,Table vector lookup extension +TRUE,vqtbx1q_u8,"a: uint8x16_t, t: uint8x16_t, idx: uint8x16_t",uint8x16_t,Table vector lookup extension +TRUE,vqtbx2_p8,"a: poly8x8_t, t: poly8x16x2_t, idx: uint8x8_t",poly8x8_t,Table vector lookup extension +TRUE,vqtbx2_s8,"a: int8x8_t, t: int8x16x2_t, idx: uint8x8_t",int8x8_t,Table vector lookup extension +TRUE,vqtbx2_u8,"a: uint8x8_t, t: uint8x16x2_t, idx: uint8x8_t",uint8x8_t,Table vector lookup extension +TRUE,vqtbx2q_p8,"a: poly8x16_t, t: poly8x16x2_t, idx: uint8x16_t",poly8x16_t,Table vector lookup extension +TRUE,vqtbx2q_s8,"a: int8x16_t, t: int8x16x2_t, idx: uint8x16_t",int8x16_t,Table vector lookup extension +TRUE,vqtbx2q_u8,"a: uint8x16_t, t: uint8x16x2_t, idx: uint8x16_t",uint8x16_t,Table vector lookup extension +TRUE,vqtbx3_p8,"a: poly8x8_t, t: poly8x16x3_t, idx: uint8x8_t",poly8x8_t,Table vector lookup extension +TRUE,vqtbx3_s8,"a: int8x8_t, t: int8x16x3_t, idx: uint8x8_t",int8x8_t,Table vector lookup extension +TRUE,vqtbx3_u8,"a: uint8x8_t, t: uint8x16x3_t, idx: uint8x8_t",uint8x8_t,Table vector lookup extension +TRUE,vqtbx3q_p8,"a: poly8x16_t, t: poly8x16x3_t, idx: uint8x16_t",poly8x16_t,Table vector lookup extension +TRUE,vqtbx3q_s8,"a: int8x16_t, t: int8x16x3_t, idx: uint8x16_t",int8x16_t,Table vector lookup extension +TRUE,vqtbx3q_u8,"a: uint8x16_t, t: uint8x16x3_t, idx: uint8x16_t",uint8x16_t,Table vector lookup extension +TRUE,vqtbx4_p8,"a: poly8x8_t, t: poly8x16x4_t, idx: uint8x8_t",poly8x8_t,Table vector lookup extension +TRUE,vqtbx4_s8,"a: int8x8_t, t: int8x16x4_t, idx: uint8x8_t",int8x8_t,Table vector lookup extension +TRUE,vqtbx4_u8,"a: uint8x8_t, t: uint8x16x4_t, idx: uint8x8_t",uint8x8_t,Table vector lookup extension +TRUE,vqtbx4q_p8,"a: poly8x16_t, t: poly8x16x4_t, idx: uint8x16_t",poly8x16_t,Table vector lookup extension +TRUE,vqtbx4q_s8,"a: int8x16_t, t: int8x16x4_t, idx: uint8x16_t",int8x16_t,Table vector lookup extension +TRUE,vqtbx4q_u8,"a: uint8x16_t, t: uint8x16x4_t, idx: uint8x16_t",uint8x16_t,Table vector lookup extension +FALSE,vraddhn_high_s16,"r: int8x8_t, a: int16x8_t, b: int16x8_t",int8x16_t,Rounding add returning high narrow +FALSE,vraddhn_high_s32,"r: int16x4_t, a: int32x4_t, b: int32x4_t",int16x8_t,Rounding add returning high narrow +FALSE,vraddhn_high_s64,"r: int32x2_t, a: int64x2_t, b: int64x2_t",int32x4_t,Rounding add returning high narrow +FALSE,vraddhn_high_u16,"r: uint8x8_t, a: uint16x8_t, b: uint16x8_t",uint8x16_t,Rounding add returning high narrow +FALSE,vraddhn_high_u32,"r: uint16x4_t, a: uint32x4_t, b: uint32x4_t",uint16x8_t,Rounding add returning high narrow +FALSE,vraddhn_high_u64,"r: uint32x2_t, a: uint64x2_t, b: uint64x2_t",uint32x4_t,Rounding add returning high narrow +FALSE,vraddhn_s16,"a: int16x8_t, b: int16x8_t",int8x8_t,Rounding add returning high narrow +FALSE,vraddhn_s32,"a: int32x4_t, b: int32x4_t",int16x4_t,Rounding add returning high narrow +FALSE,vraddhn_s64,"a: int64x2_t, b: int64x2_t",int32x2_t,Rounding add returning high narrow +FALSE,vraddhn_u16,"a: uint16x8_t, b: uint16x8_t",uint8x8_t,Rounding add returning high narrow +FALSE,vraddhn_u32,"a: uint32x4_t, b: uint32x4_t",uint16x4_t,Rounding add returning high narrow +FALSE,vraddhn_u64,"a: uint64x2_t, b: uint64x2_t",uint32x2_t,Rounding add returning high narrow +FALSE,vrax1q_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Rotate and exclusive OR +TRUE,vrbit_p8,a: poly8x8_t,poly8x8_t,Reverse bit order +TRUE,vrbit_s8,a: int8x8_t,int8x8_t,Reverse bit order +TRUE,vrbit_u8,a: uint8x8_t,uint8x8_t,Reverse bit order +TRUE,vrbitq_p8,a: poly8x16_t,poly8x16_t,Reverse bit order +TRUE,vrbitq_s8,a: int8x16_t,int8x16_t,Reverse bit order +TRUE,vrbitq_u8,a: uint8x16_t,uint8x16_t,Reverse bit order +FALSE,vrecpe_f16,a: float16x4_t,float16x4_t,Floating-point reciprocal estimate +TRUE,vrecpe_f32,a: float32x2_t,float32x2_t,Floating-point reciprocal estimate +TRUE,vrecpe_f64,a: float64x1_t,float64x1_t,Floating-point reciprocal estimate +FALSE,vrecpe_u32,a: uint32x2_t,uint32x2_t,Unsigned reciprocal estimate +FALSE,vrecped_f64,a: float64_t,float64_t,Floating-point reciprocal estimate +FALSE,vrecpeh_f16,a: float16_t,float16_t,Floating-point reciprocal estimate +FALSE,vrecpeq_f16,a: float16x8_t,float16x8_t,Floating-point reciprocal estimate +TRUE,vrecpeq_f32,a: float32x4_t,float32x4_t,Floating-point reciprocal estimate +TRUE,vrecpeq_f64,a: float64x2_t,float64x2_t,Floating-point reciprocal estimate +FALSE,vrecpeq_u32,a: uint32x4_t,uint32x4_t,Unsigned reciprocal estimate +FALSE,vrecpes_f32,a: f32,f32,Floating-point reciprocal estimate +FALSE,vrecps_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point reciprocal step +FALSE,vrecps_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point reciprocal step +FALSE,vrecps_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point reciprocal step +FALSE,vrecpsd_f64,"a: float64_t, b: float64_t",float64_t,Floating-point reciprocal step +FALSE,vrecpsh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point reciprocal step +FALSE,vrecpsq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point reciprocal step +FALSE,vrecpsq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point reciprocal step +FALSE,vrecpsq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point reciprocal step +FALSE,vrecpss_f32,"a: f32, b: f32",f32,Floating-point reciprocal step +FALSE,vrecpxd_f64,a: float64_t,float64_t,Floating-point reciprocal exponent +FALSE,vrecpxh_f16,a: float16_t,float16_t,Floating-point reciprocal exponent +FALSE,vrecpxs_f32,a: f32,f32,Floating-point reciprocal exponent +FALSE,vreinterpret_bf16_f32,a: float32x2_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_f64,a: float64x1_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_p16,a: poly16x4_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_p64,a: poly64x1_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_p8,a: poly8x8_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_s16,a: int16x4_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_s32,a: int32x2_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_s64,a: int64x1_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_s8,a: int8x8_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_u16,a: uint16x4_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_u32,a: uint32x2_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_u64,a: uint64x1_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_bf16_u8,a: uint8x8_t,bfloat16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_f32,a: float32x2_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_f64,a: float64x1_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_p16,a: poly16x4_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_p64,a: poly64x1_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_p8,a: poly8x8_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_s16,a: int16x4_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_s32,a: int32x2_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_s64,a: int64x1_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_s8,a: int8x8_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_u16,a: uint16x4_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_u32,a: uint32x2_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_u64,a: uint64x1_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f16_u8,a: uint8x8_t,float16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_f32_bf16,a: bfloat16x4_t,float32x2_t,Vector reinterpret cast operation +FALSE,vreinterpret_f32_f16,a: float16x4_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_f64,a: float64x1_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_p16,a: poly16x4_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_p8,a: poly8x8_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_s16,a: int16x4_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_s32,a: int32x2_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_s64,a: int64x1_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_s8,a: int8x8_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_u16,a: uint16x4_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_u32,a: uint32x2_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_u64,a: uint64x1_t,float32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_f32_u8,a: uint8x8_t,float32x2_t,Vector reinterpret cast operation +FALSE,vreinterpret_f64_bf16,a: bfloat16x4_t,float64x1_t,Vector reinterpret cast operation +FALSE,vreinterpret_f64_f16,a: float16x4_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_f32,a: float32x2_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_p16,a: poly16x4_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_p64,a: poly64x1_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_p8,a: poly8x8_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_s16,a: int16x4_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_s32,a: int32x2_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_s64,a: int64x1_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_s8,a: int8x8_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_u16,a: uint16x4_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_u32,a: uint32x2_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_u64,a: uint64x1_t,float64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_f64_u8,a: uint8x8_t,float64x1_t,Vector reinterpret cast operation +FALSE,vreinterpret_p16_bf16,a: bfloat16x4_t,poly16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_p16_f16,a: float16x4_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_f32,a: float32x2_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_f64,a: float64x1_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_p64,a: poly64x1_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_p8,a: poly8x8_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_s16,a: int16x4_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_s32,a: int32x2_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_s64,a: int64x1_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_s8,a: int8x8_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_u16,a: uint16x4_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_u32,a: uint32x2_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_u64,a: uint64x1_t,poly16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_p16_u8,a: uint8x8_t,poly16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_p64_bf16,a: bfloat16x4_t,poly64x1_t,Vector reinterpret cast operation +FALSE,vreinterpret_p64_f16,a: float16x4_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_f32,a: float32x2_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_f64,a: float64x1_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_p16,a: poly16x4_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_p8,a: poly8x8_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_s16,a: int16x4_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_s32,a: int32x2_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_s8,a: int8x8_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_u16,a: uint16x4_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_u32,a: uint32x2_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_u64,a: uint64x1_t,poly64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_p64_u8,a: uint8x8_t,poly64x1_t,Vector reinterpret cast operation +FALSE,vreinterpret_p8_bf16,a: bfloat16x4_t,poly8x8_t,Vector reinterpret cast operation +FALSE,vreinterpret_p8_f16,a: float16x4_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_f32,a: float32x2_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_f64,a: float64x1_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_p16,a: poly16x4_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_p64,a: poly64x1_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_s16,a: int16x4_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_s32,a: int32x2_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_s64,a: int64x1_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_s8,a: int8x8_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_u16,a: uint16x4_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_u32,a: uint32x2_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_u64,a: uint64x1_t,poly8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_p8_u8,a: uint8x8_t,poly8x8_t,Vector reinterpret cast operation +FALSE,vreinterpret_s16_bf16,a: bfloat16x4_t,int16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_s16_f16,a: float16x4_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_f32,a: float32x2_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_f64,a: float64x1_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_p16,a: poly16x4_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_p64,a: poly64x1_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_p8,a: poly8x8_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_s32,a: int32x2_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_s64,a: int64x1_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_s8,a: int8x8_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_u16,a: uint16x4_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_u32,a: uint32x2_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_u64,a: uint64x1_t,int16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_s16_u8,a: uint8x8_t,int16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_s32_bf16,a: bfloat16x4_t,int32x2_t,Vector reinterpret cast operation +FALSE,vreinterpret_s32_f16,a: float16x4_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_f32,a: float32x2_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_f64,a: float64x1_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_p16,a: poly16x4_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_p64,a: poly64x1_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_p8,a: poly8x8_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_s16,a: int16x4_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_s64,a: int64x1_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_s8,a: int8x8_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_u16,a: uint16x4_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_u32,a: uint32x2_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_u64,a: uint64x1_t,int32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_s32_u8,a: uint8x8_t,int32x2_t,Vector reinterpret cast operation +FALSE,vreinterpret_s64_bf16,a: bfloat16x4_t,int64x1_t,Vector reinterpret cast operation +FALSE,vreinterpret_s64_f16,a: float16x4_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_f32,a: float32x2_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_f64,a: float64x1_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_p16,a: poly16x4_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_p64,a: poly64x1_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_p8,a: poly8x8_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_s16,a: int16x4_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_s32,a: int32x2_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_s8,a: int8x8_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_u16,a: uint16x4_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_u32,a: uint32x2_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_u64,a: uint64x1_t,int64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_s64_u8,a: uint8x8_t,int64x1_t,Vector reinterpret cast operation +FALSE,vreinterpret_s8_bf16,a: bfloat16x4_t,int8x8_t,Vector reinterpret cast operation +FALSE,vreinterpret_s8_f16,a: float16x4_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_f32,a: float32x2_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_f64,a: float64x1_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_p16,a: poly16x4_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_p64,a: poly64x1_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_p8,a: poly8x8_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_s16,a: int16x4_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_s32,a: int32x2_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_s64,a: int64x1_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_u16,a: uint16x4_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_u32,a: uint32x2_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_u64,a: uint64x1_t,int8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_s8_u8,a: uint8x8_t,int8x8_t,Vector reinterpret cast operation +FALSE,vreinterpret_u16_bf16,a: bfloat16x4_t,uint16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_u16_f16,a: float16x4_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_f32,a: float32x2_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_f64,a: float64x1_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_p16,a: poly16x4_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_p64,a: poly64x1_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_p8,a: poly8x8_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_s16,a: int16x4_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_s32,a: int32x2_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_s64,a: int64x1_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_s8,a: int8x8_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_u32,a: uint32x2_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_u64,a: uint64x1_t,uint16x4_t,Vector reinterpret cast operation +TRUE,vreinterpret_u16_u8,a: uint8x8_t,uint16x4_t,Vector reinterpret cast operation +FALSE,vreinterpret_u32_bf16,a: bfloat16x4_t,uint32x2_t,Vector reinterpret cast operation +FALSE,vreinterpret_u32_f16,a: float16x4_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_f32,a: float32x2_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_f64,a: float64x1_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_p16,a: poly16x4_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_p64,a: poly64x1_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_p8,a: poly8x8_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_s16,a: int16x4_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_s32,a: int32x2_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_s64,a: int64x1_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_s8,a: int8x8_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_u16,a: uint16x4_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_u64,a: uint64x1_t,uint32x2_t,Vector reinterpret cast operation +TRUE,vreinterpret_u32_u8,a: uint8x8_t,uint32x2_t,Vector reinterpret cast operation +FALSE,vreinterpret_u64_bf16,a: bfloat16x4_t,uint64x1_t,Vector reinterpret cast operation +FALSE,vreinterpret_u64_f16,a: float16x4_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_f32,a: float32x2_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_f64,a: float64x1_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_p16,a: poly16x4_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_p64,a: poly64x1_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_p8,a: poly8x8_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_s16,a: int16x4_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_s32,a: int32x2_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_s64,a: int64x1_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_s8,a: int8x8_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_u16,a: uint16x4_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_u32,a: uint32x2_t,uint64x1_t,Vector reinterpret cast operation +TRUE,vreinterpret_u64_u8,a: uint8x8_t,uint64x1_t,Vector reinterpret cast operation +FALSE,vreinterpret_u8_bf16,a: bfloat16x4_t,uint8x8_t,Vector reinterpret cast operation +FALSE,vreinterpret_u8_f16,a: float16x4_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_f32,a: float32x2_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_f64,a: float64x1_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_p16,a: poly16x4_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_p64,a: poly64x1_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_p8,a: poly8x8_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_s16,a: int16x4_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_s32,a: int32x2_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_s64,a: int64x1_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_s8,a: int8x8_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_u16,a: uint16x4_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_u32,a: uint32x2_t,uint8x8_t,Vector reinterpret cast operation +TRUE,vreinterpret_u8_u64,a: uint64x1_t,uint8x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_f32,a: float32x4_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_f64,a: float64x2_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_p128,a: poly128_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_p16,a: poly16x8_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_p64,a: poly64x2_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_p8,a: poly8x16_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_s16,a: int16x8_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_s32,a: int32x4_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_s64,a: int64x2_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_s8,a: int8x16_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_u16,a: uint16x8_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_u32,a: uint32x4_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_u64,a: uint64x2_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_bf16_u8,a: uint8x16_t,bfloat16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_f32,a: float32x4_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_f64,a: float64x2_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_p128,a: poly128_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_p16,a: poly16x8_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_p64,a: poly64x2_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_p8,a: poly8x16_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_s16,a: int16x8_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_s32,a: int32x4_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_s64,a: int64x2_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_s8,a: int8x16_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_u16,a: uint16x8_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_u32,a: uint32x4_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_u64,a: uint64x2_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f16_u8,a: uint8x16_t,float16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f32_bf16,a: bfloat16x8_t,float32x4_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f32_f16,a: float16x8_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_f64,a: float64x2_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_p16,a: poly16x8_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_p8,a: poly8x16_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_s16,a: int16x8_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_s32,a: int32x4_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_s64,a: int64x2_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_s8,a: int8x16_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_u16,a: uint16x8_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_u32,a: uint32x4_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_u64,a: uint64x2_t,float32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f32_u8,a: uint8x16_t,float32x4_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f64_bf16,a: bfloat16x8_t,float64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f64_f16,a: float16x8_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_f32,a: float32x4_t,float64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_f64_p128,a: poly128_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_p16,a: poly16x8_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_p64,a: poly64x2_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_p8,a: poly8x16_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_s16,a: int16x8_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_s32,a: int32x4_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_s64,a: int64x2_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_s8,a: int8x16_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_u16,a: uint16x8_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_u32,a: uint32x4_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_u64,a: uint64x2_t,float64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_f64_u8,a: uint8x16_t,float64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_bf16,a: bfloat16x8_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_f16,a: float16x8_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_f32,a: float32x4_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_f64,a: float64x2_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_p16,a: poly16x8_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_p8,a: poly8x16_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_s16,a: int16x8_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_s32,a: int32x4_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_s64,a: int64x2_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_s8,a: int8x16_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_u16,a: uint16x8_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_u32,a: uint32x4_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_u64,a: uint64x2_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p128_u8,a: uint8x16_t,poly128_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p16_bf16,a: bfloat16x8_t,poly16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p16_f16,a: float16x8_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_f32,a: float32x4_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_f64,a: float64x2_t,poly16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p16_p128,a: poly128_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_p64,a: poly64x2_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_p8,a: poly8x16_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_s16,a: int16x8_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_s32,a: int32x4_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_s64,a: int64x2_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_s8,a: int8x16_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_u16,a: uint16x8_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_u32,a: uint32x4_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_u64,a: uint64x2_t,poly16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p16_u8,a: uint8x16_t,poly16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p64_bf16,a: bfloat16x8_t,poly64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p64_f16,a: float16x8_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_f32,a: float32x4_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_f64,a: float64x2_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_p16,a: poly16x8_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_p8,a: poly8x16_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_s16,a: int16x8_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_s32,a: int32x4_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_s64,a: int64x2_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_s8,a: int8x16_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_u16,a: uint16x8_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_u32,a: uint32x4_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_u64,a: uint64x2_t,poly64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p64_u8,a: uint8x16_t,poly64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p8_bf16,a: bfloat16x8_t,poly8x16_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p8_f16,a: float16x8_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_f32,a: float32x4_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_f64,a: float64x2_t,poly8x16_t,Vector reinterpret cast operation +FALSE,vreinterpretq_p8_p128,a: poly128_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_p16,a: poly16x8_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_p64,a: poly64x2_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_s16,a: int16x8_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_s32,a: int32x4_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_s64,a: int64x2_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_s8,a: int8x16_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_u16,a: uint16x8_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_u32,a: uint32x4_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_u64,a: uint64x2_t,poly8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_p8_u8,a: uint8x16_t,poly8x16_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s16_bf16,a: bfloat16x8_t,int16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s16_f16,a: float16x8_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_f32,a: float32x4_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_f64,a: float64x2_t,int16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s16_p128,a: poly128_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_p16,a: poly16x8_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_p64,a: poly64x2_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_p8,a: poly8x16_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_s32,a: int32x4_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_s64,a: int64x2_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_s8,a: int8x16_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_u16,a: uint16x8_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_u32,a: uint32x4_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_u64,a: uint64x2_t,int16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s16_u8,a: uint8x16_t,int16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s32_bf16,a: bfloat16x8_t,int32x4_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s32_f16,a: float16x8_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_f32,a: float32x4_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_f64,a: float64x2_t,int32x4_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s32_p128,a: poly128_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_p16,a: poly16x8_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_p64,a: poly64x2_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_p8,a: poly8x16_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_s16,a: int16x8_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_s64,a: int64x2_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_s8,a: int8x16_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_u16,a: uint16x8_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_u32,a: uint32x4_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_u64,a: uint64x2_t,int32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s32_u8,a: uint8x16_t,int32x4_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s64_bf16,a: bfloat16x8_t,int64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s64_f16,a: float16x8_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_f32,a: float32x4_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_f64,a: float64x2_t,int64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s64_p128,a: poly128_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_p16,a: poly16x8_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_p64,a: poly64x2_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_p8,a: poly8x16_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_s16,a: int16x8_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_s32,a: int32x4_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_s8,a: int8x16_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_u16,a: uint16x8_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_u32,a: uint32x4_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_u64,a: uint64x2_t,int64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s64_u8,a: uint8x16_t,int64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s8_bf16,a: bfloat16x8_t,int8x16_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s8_f16,a: float16x8_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_f32,a: float32x4_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_f64,a: float64x2_t,int8x16_t,Vector reinterpret cast operation +FALSE,vreinterpretq_s8_p128,a: poly128_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_p16,a: poly16x8_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_p64,a: poly64x2_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_p8,a: poly8x16_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_s16,a: int16x8_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_s32,a: int32x4_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_s64,a: int64x2_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_u16,a: uint16x8_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_u32,a: uint32x4_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_u64,a: uint64x2_t,int8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_s8_u8,a: uint8x16_t,int8x16_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u16_bf16,a: bfloat16x8_t,uint16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u16_f16,a: float16x8_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_f32,a: float32x4_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_f64,a: float64x2_t,uint16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u16_p128,a: poly128_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_p16,a: poly16x8_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_p64,a: poly64x2_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_p8,a: poly8x16_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_s16,a: int16x8_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_s32,a: int32x4_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_s64,a: int64x2_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_s8,a: int8x16_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_u32,a: uint32x4_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_u64,a: uint64x2_t,uint16x8_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u16_u8,a: uint8x16_t,uint16x8_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u32_bf16,a: bfloat16x8_t,uint32x4_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u32_f16,a: float16x8_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_f32,a: float32x4_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_f64,a: float64x2_t,uint32x4_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u32_p128,a: poly128_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_p16,a: poly16x8_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_p64,a: poly64x2_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_p8,a: poly8x16_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_s16,a: int16x8_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_s32,a: int32x4_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_s64,a: int64x2_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_s8,a: int8x16_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_u16,a: uint16x8_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_u64,a: uint64x2_t,uint32x4_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u32_u8,a: uint8x16_t,uint32x4_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u64_bf16,a: bfloat16x8_t,uint64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u64_f16,a: float16x8_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_f32,a: float32x4_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_f64,a: float64x2_t,uint64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u64_p128,a: poly128_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_p16,a: poly16x8_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_p64,a: poly64x2_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_p8,a: poly8x16_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_s16,a: int16x8_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_s32,a: int32x4_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_s64,a: int64x2_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_s8,a: int8x16_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_u16,a: uint16x8_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_u32,a: uint32x4_t,uint64x2_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u64_u8,a: uint8x16_t,uint64x2_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u8_bf16,a: bfloat16x8_t,uint8x16_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u8_f16,a: float16x8_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_f32,a: float32x4_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_f64,a: float64x2_t,uint8x16_t,Vector reinterpret cast operation +FALSE,vreinterpretq_u8_p128,a: poly128_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_p16,a: poly16x8_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_p64,a: poly64x2_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_p8,a: poly8x16_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_s16,a: int16x8_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_s32,a: int32x4_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_s64,a: int64x2_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_s8,a: int8x16_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_u16,a: uint16x8_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_u32,a: uint32x4_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vreinterpretq_u8_u64,a: uint64x2_t,uint8x16_t,Vector reinterpret cast operation +TRUE,vrev16_p8,vec: poly8x8_t,poly8x8_t,Reverse elements in 16-bit halfwords +TRUE,vrev16_s8,vec: int8x8_t,int8x8_t,Reverse elements in 16-bit halfwords +TRUE,vrev16_u8,vec: uint8x8_t,uint8x8_t,Reverse elements in 16-bit halfwords +TRUE,vrev16q_p8,vec: poly8x16_t,poly8x16_t,Reverse elements in 16-bit halfwords +TRUE,vrev16q_s8,vec: int8x16_t,int8x16_t,Reverse elements in 16-bit halfwords +TRUE,vrev16q_u8,vec: uint8x16_t,uint8x16_t,Reverse elements in 16-bit halfwords +TRUE,vrev32_p16,vec: poly16x4_t,poly16x4_t,Reverse elements in 32-bit words +TRUE,vrev32_p8,vec: poly8x8_t,poly8x8_t,Reverse elements in 32-bit words +TRUE,vrev32_s16,vec: int16x4_t,int16x4_t,Reverse elements in 32-bit words +TRUE,vrev32_s8,vec: int8x8_t,int8x8_t,Reverse elements in 32-bit words +TRUE,vrev32_u16,vec: uint16x4_t,uint16x4_t,Reverse elements in 32-bit words +TRUE,vrev32_u8,vec: uint8x8_t,uint8x8_t,Reverse elements in 32-bit words +TRUE,vrev32q_p16,vec: poly16x8_t,poly16x8_t,Reverse elements in 32-bit words +TRUE,vrev32q_p8,vec: poly8x16_t,poly8x16_t,Reverse elements in 32-bit words +TRUE,vrev32q_s16,vec: int16x8_t,int16x8_t,Reverse elements in 32-bit words +TRUE,vrev32q_s8,vec: int8x16_t,int8x16_t,Reverse elements in 32-bit words +TRUE,vrev32q_u16,vec: uint16x8_t,uint16x8_t,Reverse elements in 32-bit words +TRUE,vrev32q_u8,vec: uint8x16_t,uint8x16_t,Reverse elements in 32-bit words +FALSE,vrev64_f16,vec: float16x4_t,float16x4_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_f32,vec: float32x2_t,float32x2_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_p16,vec: poly16x4_t,poly16x4_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_p8,vec: poly8x8_t,poly8x8_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_s16,vec: int16x4_t,int16x4_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_s32,vec: int32x2_t,int32x2_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_s8,vec: int8x8_t,int8x8_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_u16,vec: uint16x4_t,uint16x4_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_u32,vec: uint32x2_t,uint32x2_t,Reverse elements in 64-bit doublewords +TRUE,vrev64_u8,vec: uint8x8_t,uint8x8_t,Reverse elements in 64-bit doublewords +FALSE,vrev64q_f16,vec: float16x8_t,float16x8_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_f32,vec: float32x4_t,float32x4_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_p16,vec: poly16x8_t,poly16x8_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_p8,vec: poly8x16_t,poly8x16_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_s16,vec: int16x8_t,int16x8_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_s32,vec: int32x4_t,int32x4_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_s8,vec: int8x16_t,int8x16_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_u16,vec: uint16x8_t,uint16x8_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_u32,vec: uint32x4_t,uint32x4_t,Reverse elements in 64-bit doublewords +TRUE,vrev64q_u8,vec: uint8x16_t,uint8x16_t,Reverse elements in 64-bit doublewords +TRUE,vrhadd_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed rounding halving add +TRUE,vrhadd_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed rounding halving add +TRUE,vrhadd_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed rounding halving add +TRUE,vrhadd_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unsigned rounding halving add +TRUE,vrhadd_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unsigned rounding halving add +TRUE,vrhadd_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unsigned rounding halving add +TRUE,vrhaddq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed rounding halving add +TRUE,vrhaddq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed rounding halving add +TRUE,vrhaddq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed rounding halving add +TRUE,vrhaddq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unsigned rounding halving add +TRUE,vrhaddq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unsigned rounding halving add +TRUE,vrhaddq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unsigned rounding halving add +FALSE,vrnd_f16,a: float16x4_t,float16x4_t,"Floating-point round to integral, toward zero" +TRUE,vrnd_f32,a: float32x2_t,float32x2_t,"Floating-point round to integral, toward zero" +TRUE,vrnd_f64,a: float64x1_t,float64x1_t,"Floating-point round to integral, toward zero" +FALSE,vrnd32x_f32,a: float32x2_t,float32x2_t,"Floating-point round to 32-bit integer, using current rounding mode" +FALSE,vrnd32x_f64,a: float64x1_t,float64x1_t,"Floating-point round to 32-bit integer, using current rounding mode" +FALSE,vrnd32xq_f32,a: float32x4_t,float32x4_t,"Floating-point round to 32-bit integer, using current rounding mode" +FALSE,vrnd32xq_f64,a: float64x2_t,float64x2_t,"Floating-point round to 32-bit integer, using current rounding mode" +FALSE,vrnd32z_f32,a: float32x2_t,float32x2_t,Floating-point round to 32-bit integer toward zero +FALSE,vrnd32z_f64,a: float64x1_t,float64x1_t,Floating-point round to 32-bit integer toward zero +FALSE,vrnd32zq_f32,a: float32x4_t,float32x4_t,Floating-point round to 32-bit integer toward zero +FALSE,vrnd32zq_f64,a: float64x2_t,float64x2_t,Floating-point round to 32-bit integer toward zero +FALSE,vrnd64x_f32,a: float32x2_t,float32x2_t,"Floating-point round to 64-bit integer, using current rounding mode" +FALSE,vrnd64x_f64,a: float64x1_t,float64x1_t,"Floating-point round to 64-bit integer, using current rounding mode" +FALSE,vrnd64xq_f32,a: float32x4_t,float32x4_t,"Floating-point round to 64-bit integer, using current rounding mode" +FALSE,vrnd64xq_f64,a: float64x2_t,float64x2_t,"Floating-point round to 64-bit integer, using current rounding mode" +FALSE,vrnd64z_f32,a: float32x2_t,float32x2_t,Floating-point round to 64-bit integer toward zero +FALSE,vrnd64z_f64,a: float64x1_t,float64x1_t,Floating-point round to 64-bit integer toward zero +FALSE,vrnd64zq_f32,a: float32x4_t,float32x4_t,Floating-point round to 64-bit integer toward zero +FALSE,vrnd64zq_f64,a: float64x2_t,float64x2_t,Floating-point round to 64-bit integer toward zero +FALSE,vrnda_f16,a: float16x4_t,float16x4_t,"Floating-point round to integral, to nearest with ties to away" +TRUE,vrnda_f32,a: float32x2_t,float32x2_t,"Floating-point round to integral, to nearest with ties to away" +TRUE,vrnda_f64,a: float64x1_t,float64x1_t,"Floating-point round to integral, to nearest with ties to away" +FALSE,vrndah_f16,a: float16_t,float16_t,"Floating-point round to integral, to nearest with ties to away" +FALSE,vrndaq_f16,a: float16x8_t,float16x8_t,"Floating-point round to integral, to nearest with ties to away" +TRUE,vrndaq_f32,a: float32x4_t,float32x4_t,"Floating-point round to integral, to nearest with ties to away" +TRUE,vrndaq_f64,a: float64x2_t,float64x2_t,"Floating-point round to integral, to nearest with ties to away" +FALSE,vrndh_f16,a: float16_t,float16_t,"Floating-point round to integral, toward zero" +FALSE,vrndi_f16,a: float16x4_t,float16x4_t,"Floating-point round to integral, using current rounding mode" +TRUE,vrndi_f32,a: float32x2_t,float32x2_t,"Floating-point round to integral, using current rounding mode" +TRUE,vrndi_f64,a: float64x1_t,float64x1_t,"Floating-point round to integral, using current rounding mode" +FALSE,vrndih_f16,a: float16_t,float16_t,"Floating-point round to integral, using current rounding mode" +FALSE,vrndiq_f16,a: float16x8_t,float16x8_t,"Floating-point round to integral, using current rounding mode" +TRUE,vrndiq_f32,a: float32x4_t,float32x4_t,"Floating-point round to integral, using current rounding mode" +TRUE,vrndiq_f64,a: float64x2_t,float64x2_t,"Floating-point round to integral, using current rounding mode" +FALSE,vrndm_f16,a: float16x4_t,float16x4_t,"Floating-point round to integral, toward minus infinity" +TRUE,vrndm_f32,a: float32x2_t,float32x2_t,"Floating-point round to integral, toward minus infinity" +TRUE,vrndm_f64,a: float64x1_t,float64x1_t,"Floating-point round to integral, toward minus infinity" +FALSE,vrndmh_f16,a: float16_t,float16_t,"Floating-point round to integral, toward minus infinity" +FALSE,vrndmq_f16,a: float16x8_t,float16x8_t,"Floating-point round to integral, toward minus infinity" +TRUE,vrndmq_f32,a: float32x4_t,float32x4_t,"Floating-point round to integral, toward minus infinity" +TRUE,vrndmq_f64,a: float64x2_t,float64x2_t,"Floating-point round to integral, toward minus infinity" +FALSE,vrndn_f16,a: float16x4_t,float16x4_t,"Floating-point round to integral, to nearest with ties to even" +TRUE,vrndn_f32,a: float32x2_t,float32x2_t,"Floating-point round to integral, to nearest with ties to even" +TRUE,vrndn_f64,a: float64x1_t,float64x1_t,"Floating-point round to integral, to nearest with ties to even" +FALSE,vrndnh_f16,a: float16_t,float16_t,"Floating-point round to integral, to nearest with ties to even" +FALSE,vrndnq_f16,a: float16x8_t,float16x8_t,"Floating-point round to integral, to nearest with ties to even" +TRUE,vrndnq_f32,a: float32x4_t,float32x4_t,"Floating-point round to integral, to nearest with ties to even" +TRUE,vrndnq_f64,a: float64x2_t,float64x2_t,"Floating-point round to integral, to nearest with ties to even" +FALSE,vrndns_f32,a: f32,f32,"Floating-point round to integral, to nearest with ties to even" +FALSE,vrndp_f16,a: float16x4_t,float16x4_t,"Floating-point round to integral, toward plus infinity" +TRUE,vrndp_f32,a: float32x2_t,float32x2_t,"Floating-point round to integral, toward plus infinity" +TRUE,vrndp_f64,a: float64x1_t,float64x1_t,"Floating-point round to integral, toward plus infinity" +FALSE,vrndph_f16,a: float16_t,float16_t,"Floating-point round to integral, toward plus infinity" +FALSE,vrndpq_f16,a: float16x8_t,float16x8_t,"Floating-point round to integral, toward plus infinity" +TRUE,vrndpq_f32,a: float32x4_t,float32x4_t,"Floating-point round to integral, toward plus infinity" +TRUE,vrndpq_f64,a: float64x2_t,float64x2_t,"Floating-point round to integral, toward plus infinity" +FALSE,vrndq_f16,a: float16x8_t,float16x8_t,"Floating-point round to integral, toward zero" +TRUE,vrndq_f32,a: float32x4_t,float32x4_t,"Floating-point round to integral, toward zero" +TRUE,vrndq_f64,a: float64x2_t,float64x2_t,"Floating-point round to integral, toward zero" +FALSE,vrndx_f16,a: float16x4_t,float16x4_t,"Floating-point round to integral exact, using current rounding mode" +TRUE,vrndx_f32,a: float32x2_t,float32x2_t,"Floating-point round to integral exact, using current rounding mode" +TRUE,vrndx_f64,a: float64x1_t,float64x1_t,"Floating-point round to integral exact, using current rounding mode" +FALSE,vrndxh_f16,a: float16_t,float16_t,"Floating-point round to integral exact, using current rounding mode" +FALSE,vrndxq_f16,a: float16x8_t,float16x8_t,"Floating-point round to integral exact, using current rounding mode" +TRUE,vrndxq_f32,a: float32x4_t,float32x4_t,"Floating-point round to integral exact, using current rounding mode" +TRUE,vrndxq_f64,a: float64x2_t,float64x2_t,"Floating-point round to integral exact, using current rounding mode" +TRUE,vrshl_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed rounding shift left +TRUE,vrshl_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed rounding shift left +TRUE,vrshl_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Signed rounding shift left +TRUE,vrshl_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed rounding shift left +TRUE,vrshl_u16,"a: uint16x4_t, b: int16x4_t",uint16x4_t,Unsigned rounding shift left +TRUE,vrshl_u32,"a: uint32x2_t, b: int32x2_t",uint32x2_t,Unsigned rounding shift left +TRUE,vrshl_u64,"a: uint64x1_t, b: int64x1_t",uint64x1_t,Unsigned rounding shift left +TRUE,vrshl_u8,"a: uint8x8_t, b: int8x8_t",uint8x8_t,Unsigned rounding shift left +TRUE,vrshld_s64,"a: i64, b: i64",i64,Signed rounding shift left +TRUE,vrshld_u64,"a: u64, b: i64",u64,Unsigned rounding shift left +TRUE,vrshlq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed rounding shift left +TRUE,vrshlq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed rounding shift left +TRUE,vrshlq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Signed rounding shift left +TRUE,vrshlq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed rounding shift left +TRUE,vrshlq_u16,"a: uint16x8_t, b: int16x8_t",uint16x8_t,Unsigned rounding shift left +TRUE,vrshlq_u32,"a: uint32x4_t, b: int32x4_t",uint32x4_t,Unsigned rounding shift left +TRUE,vrshlq_u64,"a: uint64x2_t, b: int64x2_t",uint64x2_t,Unsigned rounding shift left +TRUE,vrshlq_u8,"a: uint8x16_t, b: int8x16_t",uint8x16_t,Unsigned rounding shift left +TRUE,vrshr_n_s16,"a: int16x4_t, n: const int",int16x4_t,Signed rounding shift right +TRUE,vrshr_n_s32,"a: int32x2_t, n: const int",int32x2_t,Signed rounding shift right +TRUE,vrshr_n_s64,"a: int64x1_t, n: const int",int64x1_t,Signed rounding shift right +TRUE,vrshr_n_s8,"a: int8x8_t, n: const int",int8x8_t,Signed rounding shift right +TRUE,vrshr_n_u16,"a: uint16x4_t, n: const int",uint16x4_t,Unsigned rounding shift right +TRUE,vrshr_n_u32,"a: uint32x2_t, n: const int",uint32x2_t,Unsigned rounding shift right +TRUE,vrshr_n_u64,"a: uint64x1_t, n: const int",uint64x1_t,Unsigned rounding shift right +TRUE,vrshr_n_u8,"a: uint8x8_t, n: const int",uint8x8_t,Unsigned rounding shift right +TRUE,vrshrd_n_s64,"a: i64, n: const int",i64,Signed rounding shift right +TRUE,vrshrd_n_u64,"a: u64, n: const int",u64,Unsigned rounding shift right +TRUE,vrshrn_high_n_s16,"r: int8x8_t, a: int16x8_t, n: const int",int8x16_t,Rounding shift right narrow +TRUE,vrshrn_high_n_s32,"r: int16x4_t, a: int32x4_t, n: const int",int16x8_t,Rounding shift right narrow +TRUE,vrshrn_high_n_s64,"r: int32x2_t, a: int64x2_t, n: const int",int32x4_t,Rounding shift right narrow +TRUE,vrshrn_high_n_u16,"r: uint8x8_t, a: uint16x8_t, n: const int",uint8x16_t,Rounding shift right narrow +TRUE,vrshrn_high_n_u32,"r: uint16x4_t, a: uint32x4_t, n: const int",uint16x8_t,Rounding shift right narrow +TRUE,vrshrn_high_n_u64,"r: uint32x2_t, a: uint64x2_t, n: const int",uint32x4_t,Rounding shift right narrow +TRUE,vrshrn_n_s16,"a: int16x8_t, n: const int",int8x8_t,Rounding shift right narrow +TRUE,vrshrn_n_s32,"a: int32x4_t, n: const int",int16x4_t,Rounding shift right narrow +TRUE,vrshrn_n_s64,"a: int64x2_t, n: const int",int32x2_t,Rounding shift right narrow +TRUE,vrshrn_n_u16,"a: uint16x8_t, n: const int",uint8x8_t,Rounding shift right narrow +TRUE,vrshrn_n_u32,"a: uint32x4_t, n: const int",uint16x4_t,Rounding shift right narrow +TRUE,vrshrn_n_u64,"a: uint64x2_t, n: const int",uint32x2_t,Rounding shift right narrow +TRUE,vrshrq_n_s16,"a: int16x8_t, n: const int",int16x8_t,Signed rounding shift right +TRUE,vrshrq_n_s32,"a: int32x4_t, n: const int",int32x4_t,Signed rounding shift right +TRUE,vrshrq_n_s64,"a: int64x2_t, n: const int",int64x2_t,Signed rounding shift right +TRUE,vrshrq_n_s8,"a: int8x16_t, n: const int",int8x16_t,Signed rounding shift right +TRUE,vrshrq_n_u16,"a: uint16x8_t, n: const int",uint16x8_t,Unsigned rounding shift right +TRUE,vrshrq_n_u32,"a: uint32x4_t, n: const int",uint32x4_t,Unsigned rounding shift right +TRUE,vrshrq_n_u64,"a: uint64x2_t, n: const int",uint64x2_t,Unsigned rounding shift right +TRUE,vrshrq_n_u8,"a: uint8x16_t, n: const int",uint8x16_t,Unsigned rounding shift right +FALSE,vrsqrte_f16,a: float16x4_t,float16x4_t,Floating-point reciprocal square root estimate +TRUE,vrsqrte_f32,a: float32x2_t,float32x2_t,Floating-point reciprocal square root estimate +FALSE,vrsqrte_f64,a: float64x1_t,float64x1_t,Floating-point reciprocal square root estimate +FALSE,vrsqrte_u32,a: uint32x2_t,uint32x2_t,Unsigned reciprocal square root estimate +FALSE,vrsqrted_f64,a: float64_t,float64_t,Floating-point reciprocal square root estimate +FALSE,vrsqrteh_f16,a: float16_t,float16_t,Floating-point reciprocal square root estimate +FALSE,vrsqrteq_f16,a: float16x8_t,float16x8_t,Floating-point reciprocal square root estimate +FALSE,vrsqrteq_f32,a: float32x4_t,float32x4_t,Floating-point reciprocal square root estimate +FALSE,vrsqrteq_f64,a: float64x2_t,float64x2_t,Floating-point reciprocal square root estimate +FALSE,vrsqrteq_u32,a: uint32x4_t,uint32x4_t,Unsigned reciprocal square root estimate +FALSE,vrsqrtes_f32,a: f32,f32,Floating-point reciprocal square root estimate +FALSE,vrsqrts_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point reciprocal square root step +FALSE,vrsqrts_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point reciprocal square root step +FALSE,vrsqrts_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point reciprocal square root step +FALSE,vrsqrtsd_f64,"a: float64_t, b: float64_t",float64_t,Floating-point reciprocal square root step +FALSE,vrsqrtsh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point reciprocal square root step +FALSE,vrsqrtsq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point reciprocal square root step +FALSE,vrsqrtsq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point reciprocal square root step +FALSE,vrsqrtsq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point reciprocal square root step +FALSE,vrsqrtss_f32,"a: f32, b: f32",f32,Floating-point reciprocal square root step +TRUE,vrsra_n_s16,"a: int16x4_t, b: int16x4_t, n: const int",int16x4_t,Signed rounding shift right and accumulate +TRUE,vrsra_n_s32,"a: int32x2_t, b: int32x2_t, n: const int",int32x2_t,Signed rounding shift right and accumulate +TRUE,vrsra_n_s64,"a: int64x1_t, b: int64x1_t, n: const int",int64x1_t,Signed rounding shift right and accumulate +TRUE,vrsra_n_s8,"a: int8x8_t, b: int8x8_t, n: const int",int8x8_t,Signed rounding shift right and accumulate +TRUE,vrsra_n_u16,"a: uint16x4_t, b: uint16x4_t, n: const int",uint16x4_t,Unsigned rounding shift right and accumulate +TRUE,vrsra_n_u32,"a: uint32x2_t, b: uint32x2_t, n: const int",uint32x2_t,Unsigned rounding shift right and accumulate +TRUE,vrsra_n_u64,"a: uint64x1_t, b: uint64x1_t, n: const int",uint64x1_t,Unsigned rounding shift right and accumulate +TRUE,vrsra_n_u8,"a: uint8x8_t, b: uint8x8_t, n: const int",uint8x8_t,Unsigned rounding shift right and accumulate +TRUE,vrsrad_n_s64,"a: i64, b: i64, n: const int",i64,Signed rounding shift right and accumulate +TRUE,vrsrad_n_u64,"a: u64, b: u64, n: const int",u64,Unsigned rounding shift right and accumulate +TRUE,vrsraq_n_s16,"a: int16x8_t, b: int16x8_t, n: const int",int16x8_t,Signed rounding shift right and accumulate +TRUE,vrsraq_n_s32,"a: int32x4_t, b: int32x4_t, n: const int",int32x4_t,Signed rounding shift right and accumulate +TRUE,vrsraq_n_s64,"a: int64x2_t, b: int64x2_t, n: const int",int64x2_t,Signed rounding shift right and accumulate +TRUE,vrsraq_n_s8,"a: int8x16_t, b: int8x16_t, n: const int",int8x16_t,Signed rounding shift right and accumulate +TRUE,vrsraq_n_u16,"a: uint16x8_t, b: uint16x8_t, n: const int",uint16x8_t,Unsigned rounding shift right and accumulate +TRUE,vrsraq_n_u32,"a: uint32x4_t, b: uint32x4_t, n: const int",uint32x4_t,Unsigned rounding shift right and accumulate +TRUE,vrsraq_n_u64,"a: uint64x2_t, b: uint64x2_t, n: const int",uint64x2_t,Unsigned rounding shift right and accumulate +TRUE,vrsraq_n_u8,"a: uint8x16_t, b: uint8x16_t, n: const int",uint8x16_t,Unsigned rounding shift right and accumulate +FALSE,vrsubhn_high_s16,"r: int8x8_t, a: int16x8_t, b: int16x8_t",int8x16_t,Rounding subtract returning high narrow +FALSE,vrsubhn_high_s32,"r: int16x4_t, a: int32x4_t, b: int32x4_t",int16x8_t,Rounding subtract returning high narrow +FALSE,vrsubhn_high_s64,"r: int32x2_t, a: int64x2_t, b: int64x2_t",int32x4_t,Rounding subtract returning high narrow +FALSE,vrsubhn_high_u16,"r: uint8x8_t, a: uint16x8_t, b: uint16x8_t",uint8x16_t,Rounding subtract returning high narrow +FALSE,vrsubhn_high_u32,"r: uint16x4_t, a: uint32x4_t, b: uint32x4_t",uint16x8_t,Rounding subtract returning high narrow +FALSE,vrsubhn_high_u64,"r: uint32x2_t, a: uint64x2_t, b: uint64x2_t",uint32x4_t,Rounding subtract returning high narrow +FALSE,vrsubhn_s16,"a: int16x8_t, b: int16x8_t",int8x8_t,Rounding subtract returning high narrow +FALSE,vrsubhn_s32,"a: int32x4_t, b: int32x4_t",int16x4_t,Rounding subtract returning high narrow +FALSE,vrsubhn_s64,"a: int64x2_t, b: int64x2_t",int32x2_t,Rounding subtract returning high narrow +FALSE,vrsubhn_u16,"a: uint16x8_t, b: uint16x8_t",uint8x8_t,Rounding subtract returning high narrow +FALSE,vrsubhn_u32,"a: uint32x4_t, b: uint32x4_t",uint16x4_t,Rounding subtract returning high narrow +FALSE,vrsubhn_u64,"a: uint64x2_t, b: uint64x2_t",uint32x2_t,Rounding subtract returning high narrow +FALSE,vset_lane_bf16,"a: bfloat16_t, v: bfloat16x4_t, lane: const int",bfloat16x4_t,Insert vector element from another vector element +FALSE,vset_lane_f16,"a: float16_t, v: float16x4_t, lane: const int",float16x4_t,Insert vector element from another vector element +FALSE,vset_lane_f32,"a: f32, v: float32x2_t, lane: const int",float32x2_t,Insert vector element from another vector element +FALSE,vset_lane_f64,"a: float64_t, v: float64x1_t, lane: const int",float64x1_t,Insert vector element from another vector element +FALSE,vset_lane_p16,"a: poly16_t, v: poly16x4_t, lane: const int",poly16x4_t,Insert vector element from another vector element +FALSE,vset_lane_p64,"a: poly64_t, v: poly64x1_t, lane: const int",poly64x1_t,Insert vector element from another vector element +FALSE,vset_lane_p8,"a: poly8_t, v: poly8x8_t, lane: const int",poly8x8_t,Insert vector element from another vector element +FALSE,vset_lane_s16,"a: i16, v: int16x4_t, lane: const int",int16x4_t,Insert vector element from another vector element +FALSE,vset_lane_s32,"a: i32, v: int32x2_t, lane: const int",int32x2_t,Insert vector element from another vector element +FALSE,vset_lane_s64,"a: i64, v: int64x1_t, lane: const int",int64x1_t,Insert vector element from another vector element +FALSE,vset_lane_s8,"a: i8, v: int8x8_t, lane: const int",int8x8_t,Insert vector element from another vector element +FALSE,vset_lane_u16,"a: u16, v: uint16x4_t, lane: const int",uint16x4_t,Insert vector element from another vector element +FALSE,vset_lane_u32,"a: u32, v: uint32x2_t, lane: const int",uint32x2_t,Insert vector element from another vector element +FALSE,vset_lane_u64,"a: u64, v: uint64x1_t, lane: const int",uint64x1_t,Insert vector element from another vector element +FALSE,vset_lane_u8,"a: u8, v: uint8x8_t, lane: const int",uint8x8_t,Insert vector element from another vector element +FALSE,vsetq_lane_bf16,"a: bfloat16_t, v: bfloat16x8_t, lane: const int",bfloat16x8_t,Insert vector element from another vector element +FALSE,vsetq_lane_f16,"a: float16_t, v: float16x8_t, lane: const int",float16x8_t,Insert vector element from another vector element +FALSE,vsetq_lane_f32,"a: f32, v: float32x4_t, lane: const int",float32x4_t,Insert vector element from another vector element +FALSE,vsetq_lane_f64,"a: float64_t, v: float64x2_t, lane: const int",float64x2_t,Insert vector element from another vector element +FALSE,vsetq_lane_p16,"a: poly16_t, v: poly16x8_t, lane: const int",poly16x8_t,Insert vector element from another vector element +FALSE,vsetq_lane_p64,"a: poly64_t, v: poly64x2_t, lane: const int",poly64x2_t,Insert vector element from another vector element +FALSE,vsetq_lane_p8,"a: poly8_t, v: poly8x16_t, lane: const int",poly8x16_t,Insert vector element from another vector element +FALSE,vsetq_lane_s16,"a: i16, v: int16x8_t, lane: const int",int16x8_t,Insert vector element from another vector element +FALSE,vsetq_lane_s32,"a: i32, v: int32x4_t, lane: const int",int32x4_t,Insert vector element from another vector element +FALSE,vsetq_lane_s64,"a: i64, v: int64x2_t, lane: const int",int64x2_t,Insert vector element from another vector element +FALSE,vsetq_lane_s8,"a: i8, v: int8x16_t, lane: const int",int8x16_t,Insert vector element from another vector element +FALSE,vsetq_lane_u16,"a: u16, v: uint16x8_t, lane: const int",uint16x8_t,Insert vector element from another vector element +FALSE,vsetq_lane_u32,"a: u32, v: uint32x4_t, lane: const int",uint32x4_t,Insert vector element from another vector element +FALSE,vsetq_lane_u64,"a: u64, v: uint64x2_t, lane: const int",uint64x2_t,Insert vector element from another vector element +FALSE,vsetq_lane_u8,"a: u8, v: uint8x16_t, lane: const int",uint8x16_t,Insert vector element from another vector element +TRUE,vsha1cq_u32,"hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t",uint32x4_t,SHA1 hash update (choose) +TRUE,vsha1h_u32,hash_e: u32,u32,SHA1 fixed rotate +TRUE,vsha1mq_u32,"hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t",uint32x4_t,SHA1 hash update (majority) +TRUE,vsha1pq_u32,"hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t",uint32x4_t,SHA1 hash update (parity) +TRUE,vsha1su0q_u32,"w0_3: uint32x4_t, w4_7: uint32x4_t, w8_11: uint32x4_t",uint32x4_t,SHA1 schedule update 0 +TRUE,vsha1su1q_u32,"tw0_3: uint32x4_t, w12_15: uint32x4_t",uint32x4_t,SHA1 schedule update 1 +TRUE,vsha256h2q_u32,"hash_efgh: uint32x4_t, hash_abcd: uint32x4_t, wk: uint32x4_t",uint32x4_t,SHA256 hash update (part 2) +TRUE,vsha256hq_u32,"hash_abcd: uint32x4_t, hash_efgh: uint32x4_t, wk: uint32x4_t",uint32x4_t,SHA256 hash update (part 1) +TRUE,vsha256su0q_u32,"w0_3: uint32x4_t, w4_7: uint32x4_t",uint32x4_t,SHA256 schedule update 0 +TRUE,vsha256su1q_u32,"tw0_3: uint32x4_t, w8_11: uint32x4_t, w12_15: uint32x4_t",uint32x4_t,SHA256 schedule update 1 +FALSE,vsha512h2q_u64,"sum_ab: uint64x2_t, hash_c_: uint64x2_t, hash_ab: uint64x2_t",uint64x2_t,SHA512 hash update part 2 +FALSE,vsha512hq_u64,"hash_ed: uint64x2_t, hash_gf: uint64x2_t, kwh_kwh2: uint64x2_t",uint64x2_t,SHA512 hash update part 1 +FALSE,vsha512su0q_u64,"w0_1: uint64x2_t, w2_: uint64x2_t",uint64x2_t,SHA512 schedule update 0 +FALSE,vsha512su1q_u64,"s01_s02: uint64x2_t, w14_15: uint64x2_t, w9_10: uint64x2_t",uint64x2_t,SHA512 schedule update 1 +TRUE,vshl_n_s16,"a: int16x4_t, n: const int",int16x4_t,Shift left +TRUE,vshl_n_s32,"a: int32x2_t, n: const int",int32x2_t,Shift left +TRUE,vshl_n_s64,"a: int64x1_t, n: const int",int64x1_t,Shift left +TRUE,vshl_n_s8,"a: int8x8_t, n: const int",int8x8_t,Shift left +TRUE,vshl_n_u16,"a: uint16x4_t, n: const int",uint16x4_t,Shift left +TRUE,vshl_n_u32,"a: uint32x2_t, n: const int",uint32x2_t,Shift left +TRUE,vshl_n_u64,"a: uint64x1_t, n: const int",uint64x1_t,Shift left +TRUE,vshl_n_u8,"a: uint8x8_t, n: const int",uint8x8_t,Shift left +TRUE,vshl_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Signed shift left +TRUE,vshl_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Signed shift left +TRUE,vshl_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Signed shift left +TRUE,vshl_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Signed shift left +TRUE,vshl_u16,"a: uint16x4_t, b: int16x4_t",uint16x4_t,Unsigned shift left +TRUE,vshl_u32,"a: uint32x2_t, b: int32x2_t",uint32x2_t,Unsigned shift left +TRUE,vshl_u64,"a: uint64x1_t, b: int64x1_t",uint64x1_t,Unsigned shift left +TRUE,vshl_u8,"a: uint8x8_t, b: int8x8_t",uint8x8_t,Unsigned shift left +TRUE,vshld_n_s64,"a: i64, n: const int",i64,Shift left +TRUE,vshld_n_u64,"a: u64, n: const int",u64,Shift left +TRUE,vshld_s64,"a: i64, b: i64",i64,Signed shift left +TRUE,vshld_u64,"a: u64, b: i64",u64,Unsigned shift left +TRUE,vshll_high_n_s16,"a: int16x8_t, n: const int",int32x4_t,Shift left long +TRUE,vshll_high_n_s16,"a: int16x8_t, n: const int",int32x4_t,Signed shift left long +TRUE,vshll_high_n_s32,"a: int32x4_t, n: const int",int64x2_t,Shift left long +TRUE,vshll_high_n_s32,"a: int32x4_t, n: const int",int64x2_t,Signed shift left long +TRUE,vshll_high_n_s8,"a: int8x16_t, n: const int",int16x8_t,Shift left long +TRUE,vshll_high_n_s8,"a: int8x16_t, n: const int",int16x8_t,Signed shift left long +TRUE,vshll_high_n_u16,"a: uint16x8_t, n: const int",uint32x4_t,Shift left long +TRUE,vshll_high_n_u16,"a: uint16x8_t, n: const int",uint32x4_t,Unsigned shift left long +TRUE,vshll_high_n_u32,"a: uint32x4_t, n: const int",uint64x2_t,Shift left long +TRUE,vshll_high_n_u32,"a: uint32x4_t, n: const int",uint64x2_t,Unsigned shift left long +TRUE,vshll_high_n_u8,"a: uint8x16_t, n: const int",uint16x8_t,Shift left long +TRUE,vshll_high_n_u8,"a: uint8x16_t, n: const int",uint16x8_t,Unsigned shift left long +TRUE,vshll_n_s16,"a: int16x4_t, n: const int",int32x4_t,Shift left long +TRUE,vshll_n_s16,"a: int16x4_t, n: const int",int32x4_t,Signed shift left long +TRUE,vshll_n_s32,"a: int32x2_t, n: const int",int64x2_t,Shift left long +TRUE,vshll_n_s32,"a: int32x2_t, n: const int",int64x2_t,Signed shift left long +TRUE,vshll_n_s8,"a: int8x8_t, n: const int",int16x8_t,Shift left long +TRUE,vshll_n_s8,"a: int8x8_t, n: const int",int16x8_t,Signed shift left long +TRUE,vshll_n_u16,"a: uint16x4_t, n: const int",uint32x4_t,Shift left long +TRUE,vshll_n_u16,"a: uint16x4_t, n: const int",uint32x4_t,Unsigned shift left long +TRUE,vshll_n_u32,"a: uint32x2_t, n: const int",uint64x2_t,Shift left long +TRUE,vshll_n_u32,"a: uint32x2_t, n: const int",uint64x2_t,Unsigned shift left long +TRUE,vshll_n_u8,"a: uint8x8_t, n: const int",uint16x8_t,Shift left long +TRUE,vshll_n_u8,"a: uint8x8_t, n: const int",uint16x8_t,Unsigned shift left long +TRUE,vshlq_n_s16,"a: int16x8_t, n: const int",int16x8_t,Shift left +TRUE,vshlq_n_s32,"a: int32x4_t, n: const int",int32x4_t,Shift left +TRUE,vshlq_n_s64,"a: int64x2_t, n: const int",int64x2_t,Shift left +TRUE,vshlq_n_s8,"a: int8x16_t, n: const int",int8x16_t,Shift left +TRUE,vshlq_n_u16,"a: uint16x8_t, n: const int",uint16x8_t,Shift left +TRUE,vshlq_n_u32,"a: uint32x4_t, n: const int",uint32x4_t,Shift left +TRUE,vshlq_n_u64,"a: uint64x2_t, n: const int",uint64x2_t,Shift left +TRUE,vshlq_n_u8,"a: uint8x16_t, n: const int",uint8x16_t,Shift left +TRUE,vshlq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Signed shift left +TRUE,vshlq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Signed shift left +TRUE,vshlq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Signed shift left +TRUE,vshlq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Signed shift left +TRUE,vshlq_u16,"a: uint16x8_t, b: int16x8_t",uint16x8_t,Unsigned shift left +TRUE,vshlq_u32,"a: uint32x4_t, b: int32x4_t",uint32x4_t,Unsigned shift left +TRUE,vshlq_u64,"a: uint64x2_t, b: int64x2_t",uint64x2_t,Unsigned shift left +TRUE,vshlq_u8,"a: uint8x16_t, b: int8x16_t",uint8x16_t,Unsigned shift left +TRUE,vshr_n_s16,"a: int16x4_t, n: const int",int16x4_t,Signed shift right +TRUE,vshr_n_s32,"a: int32x2_t, n: const int",int32x2_t,Signed shift right +TRUE,vshr_n_s64,"a: int64x1_t, n: const int",int64x1_t,Signed shift right +TRUE,vshr_n_s8,"a: int8x8_t, n: const int",int8x8_t,Signed shift right +TRUE,vshr_n_u16,"a: uint16x4_t, n: const int",uint16x4_t,Unsigned shift right +TRUE,vshr_n_u32,"a: uint32x2_t, n: const int",uint32x2_t,Unsigned shift right +TRUE,vshr_n_u64,"a: uint64x1_t, n: const int",uint64x1_t,Unsigned shift right +TRUE,vshr_n_u8,"a: uint8x8_t, n: const int",uint8x8_t,Unsigned shift right +TRUE,vshrd_n_s64,"a: i64, n: const int",i64,Signed shift right +TRUE,vshrd_n_u64,"a: u64, n: const int",u64,Unsigned shift right +TRUE,vshrn_high_n_s16,"r: int8x8_t, a: int16x8_t, n: const int",int8x16_t,Shift right narrow +TRUE,vshrn_high_n_s32,"r: int16x4_t, a: int32x4_t, n: const int",int16x8_t,Shift right narrow +TRUE,vshrn_high_n_s64,"r: int32x2_t, a: int64x2_t, n: const int",int32x4_t,Shift right narrow +TRUE,vshrn_high_n_u16,"r: uint8x8_t, a: uint16x8_t, n: const int",uint8x16_t,Shift right narrow +TRUE,vshrn_high_n_u32,"r: uint16x4_t, a: uint32x4_t, n: const int",uint16x8_t,Shift right narrow +TRUE,vshrn_high_n_u64,"r: uint32x2_t, a: uint64x2_t, n: const int",uint32x4_t,Shift right narrow +TRUE,vshrn_n_s16,"a: int16x8_t, n: const int",int8x8_t,Shift right narrow +TRUE,vshrn_n_s32,"a: int32x4_t, n: const int",int16x4_t,Shift right narrow +TRUE,vshrn_n_s64,"a: int64x2_t, n: const int",int32x2_t,Shift right narrow +TRUE,vshrn_n_u16,"a: uint16x8_t, n: const int",uint8x8_t,Shift right narrow +TRUE,vshrn_n_u32,"a: uint32x4_t, n: const int",uint16x4_t,Shift right narrow +TRUE,vshrn_n_u64,"a: uint64x2_t, n: const int",uint32x2_t,Shift right narrow +TRUE,vshrq_n_s16,"a: int16x8_t, n: const int",int16x8_t,Signed shift right +TRUE,vshrq_n_s32,"a: int32x4_t, n: const int",int32x4_t,Signed shift right +TRUE,vshrq_n_s64,"a: int64x2_t, n: const int",int64x2_t,Signed shift right +TRUE,vshrq_n_s8,"a: int8x16_t, n: const int",int8x16_t,Signed shift right +TRUE,vshrq_n_u16,"a: uint16x8_t, n: const int",uint16x8_t,Unsigned shift right +TRUE,vshrq_n_u32,"a: uint32x4_t, n: const int",uint32x4_t,Unsigned shift right +TRUE,vshrq_n_u64,"a: uint64x2_t, n: const int",uint64x2_t,Unsigned shift right +TRUE,vshrq_n_u8,"a: uint8x16_t, n: const int",uint8x16_t,Unsigned shift right +TRUE,vsli_n_p16,"a: poly16x4_t, b: poly16x4_t, n: const int",poly16x4_t,Shift left and insert +FALSE,vsli_n_p64,"a: poly64x1_t, b: poly64x1_t, n: const int",poly64x1_t,Shift left and insert +TRUE,vsli_n_p8,"a: poly8x8_t, b: poly8x8_t, n: const int",poly8x8_t,Shift left and insert +TRUE,vsli_n_s16,"a: int16x4_t, b: int16x4_t, n: const int",int16x4_t,Shift left and insert +TRUE,vsli_n_s32,"a: int32x2_t, b: int32x2_t, n: const int",int32x2_t,Shift left and insert +TRUE,vsli_n_s64,"a: int64x1_t, b: int64x1_t, n: const int",int64x1_t,Shift left and insert +TRUE,vsli_n_s8,"a: int8x8_t, b: int8x8_t, n: const int",int8x8_t,Shift left and insert +TRUE,vsli_n_u16,"a: uint16x4_t, b: uint16x4_t, n: const int",uint16x4_t,Shift left and insert +TRUE,vsli_n_u32,"a: uint32x2_t, b: uint32x2_t, n: const int",uint32x2_t,Shift left and insert +TRUE,vsli_n_u64,"a: uint64x1_t, b: uint64x1_t, n: const int",uint64x1_t,Shift left and insert +TRUE,vsli_n_u8,"a: uint8x8_t, b: uint8x8_t, n: const int",uint8x8_t,Shift left and insert +TRUE,vslid_n_s64,"a: i64, b: i64, n: const int",i64,Shift left and insert +TRUE,vslid_n_u64,"a: u64, b: u64, n: const int",u64,Shift left and insert +TRUE,vsliq_n_p16,"a: poly16x8_t, b: poly16x8_t, n: const int",poly16x8_t,Shift left and insert +FALSE,vsliq_n_p64,"a: poly64x2_t, b: poly64x2_t, n: const int",poly64x2_t,Shift left and insert +TRUE,vsliq_n_p8,"a: poly8x16_t, b: poly8x16_t, n: const int",poly8x16_t,Shift left and insert +TRUE,vsliq_n_s16,"a: int16x8_t, b: int16x8_t, n: const int",int16x8_t,Shift left and insert +TRUE,vsliq_n_s32,"a: int32x4_t, b: int32x4_t, n: const int",int32x4_t,Shift left and insert +TRUE,vsliq_n_s64,"a: int64x2_t, b: int64x2_t, n: const int",int64x2_t,Shift left and insert +TRUE,vsliq_n_s8,"a: int8x16_t, b: int8x16_t, n: const int",int8x16_t,Shift left and insert +TRUE,vsliq_n_u16,"a: uint16x8_t, b: uint16x8_t, n: const int",uint16x8_t,Shift left and insert +TRUE,vsliq_n_u32,"a: uint32x4_t, b: uint32x4_t, n: const int",uint32x4_t,Shift left and insert +TRUE,vsliq_n_u64,"a: uint64x2_t, b: uint64x2_t, n: const int",uint64x2_t,Shift left and insert +TRUE,vsliq_n_u8,"a: uint8x16_t, b: uint8x16_t, n: const int",uint8x16_t,Shift left and insert +FALSE,vsm3partw1q_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,SM3PARTW1 +FALSE,vsm3partw2q_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,SM3PARTW2 +FALSE,vsm3ss1q_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t",uint32x4_t,SM3SS1 +FALSE,vsm3tt1aq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t, imm2: const int",uint32x4_t,SM3TT1A +FALSE,vsm3tt1bq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t, imm2: const int",uint32x4_t,SM3TT1B +FALSE,vsm3tt2aq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t, imm2: const int",uint32x4_t,SM3TT2A +FALSE,vsm3tt2bq_u32,"a: uint32x4_t, b: uint32x4_t, c: uint32x4_t, imm2: const int",uint32x4_t,SM3TT2B +FALSE,vsm4ekeyq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,SM4 key +FALSE,vsm4eq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,SM4 encode +FALSE,vsqadd_u16,"a: uint16x4_t, b: int16x4_t",uint16x4_t,Unsigned saturating accumulate of signed value +FALSE,vsqadd_u32,"a: uint32x2_t, b: int32x2_t",uint32x2_t,Unsigned saturating accumulate of signed value +FALSE,vsqadd_u64,"a: uint64x1_t, b: int64x1_t",uint64x1_t,Unsigned saturating accumulate of signed value +FALSE,vsqadd_u8,"a: uint8x8_t, b: int8x8_t",uint8x8_t,Unsigned saturating accumulate of signed value +FALSE,vsqaddb_u8,"a: u8, b: i8",u8,Unsigned saturating accumulate of signed value +FALSE,vsqaddd_u64,"a: u64, b: i64",u64,Unsigned saturating accumulate of signed value +FALSE,vsqaddh_u16,"a: u16, b: i16",u16,Unsigned saturating accumulate of signed value +FALSE,vsqaddq_u16,"a: uint16x8_t, b: int16x8_t",uint16x8_t,Unsigned saturating accumulate of signed value +FALSE,vsqaddq_u32,"a: uint32x4_t, b: int32x4_t",uint32x4_t,Unsigned saturating accumulate of signed value +FALSE,vsqaddq_u64,"a: uint64x2_t, b: int64x2_t",uint64x2_t,Unsigned saturating accumulate of signed value +FALSE,vsqaddq_u8,"a: uint8x16_t, b: int8x16_t",uint8x16_t,Unsigned saturating accumulate of signed value +FALSE,vsqadds_u32,"a: u32, b: i32",u32,Unsigned saturating accumulate of signed value +FALSE,vsqrt_f16,a: float16x4_t,float16x4_t,Floating-point square root +TRUE,vsqrt_f32,a: float32x2_t,float32x2_t,Floating-point square root +TRUE,vsqrt_f64,a: float64x1_t,float64x1_t,Floating-point square root +FALSE,vsqrth_f16,a: float16_t,float16_t,Floating-point square root +FALSE,vsqrtq_f16,a: float16x8_t,float16x8_t,Floating-point square root +TRUE,vsqrtq_f32,a: float32x4_t,float32x4_t,Floating-point square root +TRUE,vsqrtq_f64,a: float64x2_t,float64x2_t,Floating-point square root +TRUE,vsra_n_s16,"a: int16x4_t, b: int16x4_t, n: const int",int16x4_t,Signed shift right and accumulate +TRUE,vsra_n_s32,"a: int32x2_t, b: int32x2_t, n: const int",int32x2_t,Signed shift right and accumulate +TRUE,vsra_n_s64,"a: int64x1_t, b: int64x1_t, n: const int",int64x1_t,Signed shift right and accumulate +TRUE,vsra_n_s8,"a: int8x8_t, b: int8x8_t, n: const int",int8x8_t,Signed shift right and accumulate +TRUE,vsra_n_u16,"a: uint16x4_t, b: uint16x4_t, n: const int",uint16x4_t,Unsigned shift right and accumulate +TRUE,vsra_n_u32,"a: uint32x2_t, b: uint32x2_t, n: const int",uint32x2_t,Unsigned shift right and accumulate +TRUE,vsra_n_u64,"a: uint64x1_t, b: uint64x1_t, n: const int",uint64x1_t,Unsigned shift right and accumulate +TRUE,vsra_n_u8,"a: uint8x8_t, b: uint8x8_t, n: const int",uint8x8_t,Unsigned shift right and accumulate +TRUE,vsrad_n_s64,"a: i64, b: i64, n: const int",i64,Signed shift right and accumulate +TRUE,vsrad_n_u64,"a: u64, b: u64, n: const int",u64,Unsigned shift right and accumulate +TRUE,vsraq_n_s16,"a: int16x8_t, b: int16x8_t, n: const int",int16x8_t,Signed shift right and accumulate +TRUE,vsraq_n_s32,"a: int32x4_t, b: int32x4_t, n: const int",int32x4_t,Signed shift right and accumulate +TRUE,vsraq_n_s64,"a: int64x2_t, b: int64x2_t, n: const int",int64x2_t,Signed shift right and accumulate +TRUE,vsraq_n_s8,"a: int8x16_t, b: int8x16_t, n: const int",int8x16_t,Signed shift right and accumulate +TRUE,vsraq_n_u16,"a: uint16x8_t, b: uint16x8_t, n: const int",uint16x8_t,Unsigned shift right and accumulate +TRUE,vsraq_n_u32,"a: uint32x4_t, b: uint32x4_t, n: const int",uint32x4_t,Unsigned shift right and accumulate +TRUE,vsraq_n_u64,"a: uint64x2_t, b: uint64x2_t, n: const int",uint64x2_t,Unsigned shift right and accumulate +TRUE,vsraq_n_u8,"a: uint8x16_t, b: uint8x16_t, n: const int",uint8x16_t,Unsigned shift right and accumulate +TRUE,vsri_n_p16,"a: poly16x4_t, b: poly16x4_t, n: const int",poly16x4_t,Shift right and insert +FALSE,vsri_n_p64,"a: poly64x1_t, b: poly64x1_t, n: const int",poly64x1_t,Shift right and insert +TRUE,vsri_n_p8,"a: poly8x8_t, b: poly8x8_t, n: const int",poly8x8_t,Shift right and insert +TRUE,vsri_n_s16,"a: int16x4_t, b: int16x4_t, n: const int",int16x4_t,Shift right and insert +TRUE,vsri_n_s32,"a: int32x2_t, b: int32x2_t, n: const int",int32x2_t,Shift right and insert +TRUE,vsri_n_s64,"a: int64x1_t, b: int64x1_t, n: const int",int64x1_t,Shift right and insert +TRUE,vsri_n_s8,"a: int8x8_t, b: int8x8_t, n: const int",int8x8_t,Shift right and insert +TRUE,vsri_n_u16,"a: uint16x4_t, b: uint16x4_t, n: const int",uint16x4_t,Shift right and insert +TRUE,vsri_n_u32,"a: uint32x2_t, b: uint32x2_t, n: const int",uint32x2_t,Shift right and insert +TRUE,vsri_n_u64,"a: uint64x1_t, b: uint64x1_t, n: const int",uint64x1_t,Shift right and insert +TRUE,vsri_n_u8,"a: uint8x8_t, b: uint8x8_t, n: const int",uint8x8_t,Shift right and insert +TRUE,vsrid_n_s64,"a: i64, b: i64, n: const int",i64,Shift right and insert +TRUE,vsrid_n_u64,"a: u64, b: u64, n: const int",u64,Shift right and insert +TRUE,vsriq_n_p16,"a: poly16x8_t, b: poly16x8_t, n: const int",poly16x8_t,Shift right and insert +FALSE,vsriq_n_p64,"a: poly64x2_t, b: poly64x2_t, n: const int",poly64x2_t,Shift right and insert +TRUE,vsriq_n_p8,"a: poly8x16_t, b: poly8x16_t, n: const int",poly8x16_t,Shift right and insert +TRUE,vsriq_n_s16,"a: int16x8_t, b: int16x8_t, n: const int",int16x8_t,Shift right and insert +TRUE,vsriq_n_s32,"a: int32x4_t, b: int32x4_t, n: const int",int32x4_t,Shift right and insert +TRUE,vsriq_n_s64,"a: int64x2_t, b: int64x2_t, n: const int",int64x2_t,Shift right and insert +TRUE,vsriq_n_s8,"a: int8x16_t, b: int8x16_t, n: const int",int8x16_t,Shift right and insert +TRUE,vsriq_n_u16,"a: uint16x8_t, b: uint16x8_t, n: const int",uint16x8_t,Shift right and insert +TRUE,vsriq_n_u32,"a: uint32x4_t, b: uint32x4_t, n: const int",uint32x4_t,Shift right and insert +TRUE,vsriq_n_u64,"a: uint64x2_t, b: uint64x2_t, n: const int",uint64x2_t,Shift right and insert +TRUE,vsriq_n_u8,"a: uint8x16_t, b: uint8x16_t, n: const int",uint8x16_t,Shift right and insert +FALSE,vst1_bf16,"ptr: *mut bfloat16_t, val: bfloat16x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_bf16_x2,"ptr: *mut bfloat16_t, val: bfloat16x4x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_bf16_x3,"ptr: *mut bfloat16_t, val: bfloat16x4x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_bf16_x4,"ptr: *mut bfloat16_t, val: bfloat16x4x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f16,"ptr: *mut float16_t, val: float16x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f16_x2,"ptr: *mut float16_t, val: float16x4x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f16_x3,"ptr: *mut float16_t, val: float16x4x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f16_x4,"ptr: *mut float16_t, val: float16x4x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f32,"ptr: *mut f32, val: float32x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f32_x2,"ptr: *mut f32, val: float32x2x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f32_x3,"ptr: *mut f32, val: float32x2x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f32_x4,"ptr: *mut f32, val: float32x2x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f64,"ptr: *mut float64_t, val: float64x1_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f64_x2,"ptr: *mut float64_t, val: float64x1x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f64_x3,"ptr: *mut float64_t, val: float64x1x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_f64_x4,"ptr: *mut float64_t, val: float64x1x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_bf16,"ptr: *mut bfloat16_t, val: bfloat16x4_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_f16,"ptr: *mut float16_t, val: float16x4_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_f32,"ptr: *mut f32, val: float32x2_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_f64,"ptr: *mut float64_t, val: float64x1_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_p16,"ptr: *mut poly16_t, val: poly16x4_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_p64,"ptr: *mut poly64_t, val: poly64x1_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_p8,"ptr: *mut poly8_t, val: poly8x8_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_s16,"ptr: *mut i16, val: int16x4_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_s32,"ptr: *mut i32, val: int32x2_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_s64,"ptr: *mut i64, val: int64x1_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_s8,"ptr: *mut i8, val: int8x8_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_u16,"ptr: *mut u16, val: uint16x4_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_u32,"ptr: *mut u32, val: uint32x2_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_u64,"ptr: *mut u64, val: uint64x1_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_lane_u8,"ptr: *mut u8, val: uint8x8_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p16,"ptr: *mut poly16_t, val: poly16x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p16_x2,"ptr: *mut poly16_t, val: poly16x4x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p16_x3,"ptr: *mut poly16_t, val: poly16x4x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p16_x4,"ptr: *mut poly16_t, val: poly16x4x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p64,"ptr: *mut poly64_t, val: poly64x1_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p64_x2,"ptr: *mut poly64_t, val: poly64x1x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p64_x3,"ptr: *mut poly64_t, val: poly64x1x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p64_x4,"ptr: *mut poly64_t, val: poly64x1x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p8,"ptr: *mut poly8_t, val: poly8x8_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p8_x2,"ptr: *mut poly8_t, val: poly8x8x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p8_x3,"ptr: *mut poly8_t, val: poly8x8x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_p8_x4,"ptr: *mut poly8_t, val: poly8x8x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s16,"ptr: *mut i16, val: int16x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s16_x2,"ptr: *mut i16, val: int16x4x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s16_x3,"ptr: *mut i16, val: int16x4x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s16_x4,"ptr: *mut i16, val: int16x4x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s32,"ptr: *mut i32, val: int32x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s32_x2,"ptr: *mut i32, val: int32x2x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s32_x3,"ptr: *mut i32, val: int32x2x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s32_x4,"ptr: *mut i32, val: int32x2x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s64,"ptr: *mut i64, val: int64x1_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s64_x2,"ptr: *mut i64, val: int64x1x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s64_x3,"ptr: *mut i64, val: int64x1x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s64_x4,"ptr: *mut i64, val: int64x1x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s8,"ptr: *mut i8, val: int8x8_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s8_x2,"ptr: *mut i8, val: int8x8x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s8_x3,"ptr: *mut i8, val: int8x8x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_s8_x4,"ptr: *mut i8, val: int8x8x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u16,"ptr: *mut u16, val: uint16x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u16_x2,"ptr: *mut u16, val: uint16x4x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u16_x3,"ptr: *mut u16, val: uint16x4x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u16_x4,"ptr: *mut u16, val: uint16x4x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u32,"ptr: *mut u32, val: uint32x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u32_x2,"ptr: *mut u32, val: uint32x2x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u32_x3,"ptr: *mut u32, val: uint32x2x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u32_x4,"ptr: *mut u32, val: uint32x2x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u64,"ptr: *mut u64, val: uint64x1_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u64_x2,"ptr: *mut u64, val: uint64x1x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u64_x3,"ptr: *mut u64, val: uint64x1x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u64_x4,"ptr: *mut u64, val: uint64x1x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u8,"ptr: *mut u8, val: uint8x8_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u8_x2,"ptr: *mut u8, val: uint8x8x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u8_x3,"ptr: *mut u8, val: uint8x8x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1_u8_x4,"ptr: *mut u8, val: uint8x8x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_bf16,"ptr: *mut bfloat16_t, val: bfloat16x8_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_bf16_x2,"ptr: *mut bfloat16_t, val: bfloat16x8x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_bf16_x3,"ptr: *mut bfloat16_t, val: bfloat16x8x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_bf16_x4,"ptr: *mut bfloat16_t, val: bfloat16x8x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f16,"ptr: *mut float16_t, val: float16x8_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f16_x2,"ptr: *mut float16_t, val: float16x8x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f16_x3,"ptr: *mut float16_t, val: float16x8x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f16_x4,"ptr: *mut float16_t, val: float16x8x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f32,"ptr: *mut f32, val: float32x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f32_x2,"ptr: *mut f32, val: float32x4x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f32_x3,"ptr: *mut f32, val: float32x4x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f32_x4,"ptr: *mut f32, val: float32x4x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f64,"ptr: *mut float64_t, val: float64x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f64_x2,"ptr: *mut float64_t, val: float64x2x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f64_x3,"ptr: *mut float64_t, val: float64x2x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_f64_x4,"ptr: *mut float64_t, val: float64x2x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_bf16,"ptr: *mut bfloat16_t, val: bfloat16x8_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_f16,"ptr: *mut float16_t, val: float16x8_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_f32,"ptr: *mut f32, val: float32x4_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_f64,"ptr: *mut float64_t, val: float64x2_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_p16,"ptr: *mut poly16_t, val: poly16x8_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_p64,"ptr: *mut poly64_t, val: poly64x2_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_p8,"ptr: *mut poly8_t, val: poly8x16_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_s16,"ptr: *mut i16, val: int16x8_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_s32,"ptr: *mut i32, val: int32x4_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_s64,"ptr: *mut i64, val: int64x2_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_s8,"ptr: *mut i8, val: int8x16_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_u16,"ptr: *mut u16, val: uint16x8_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_u32,"ptr: *mut u32, val: uint32x4_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_u64,"ptr: *mut u64, val: uint64x2_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_lane_u8,"ptr: *mut u8, val: uint8x16_t, lane: const int",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p16,"ptr: *mut poly16_t, val: poly16x8_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p16_x2,"ptr: *mut poly16_t, val: poly16x8x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p16_x3,"ptr: *mut poly16_t, val: poly16x8x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p16_x4,"ptr: *mut poly16_t, val: poly16x8x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p64,"ptr: *mut poly64_t, val: poly64x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p64_x2,"ptr: *mut poly64_t, val: poly64x2x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p64_x3,"ptr: *mut poly64_t, val: poly64x2x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p64_x4,"ptr: *mut poly64_t, val: poly64x2x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p8,"ptr: *mut poly8_t, val: poly8x16_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p8_x2,"ptr: *mut poly8_t, val: poly8x16x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p8_x3,"ptr: *mut poly8_t, val: poly8x16x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_p8_x4,"ptr: *mut poly8_t, val: poly8x16x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s16,"ptr: *mut i16, val: int16x8_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s16_x2,"ptr: *mut i16, val: int16x8x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s16_x3,"ptr: *mut i16, val: int16x8x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s16_x4,"ptr: *mut i16, val: int16x8x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s32,"ptr: *mut i32, val: int32x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s32_x2,"ptr: *mut i32, val: int32x4x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s32_x3,"ptr: *mut i32, val: int32x4x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s32_x4,"ptr: *mut i32, val: int32x4x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s64,"ptr: *mut i64, val: int64x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s64_x2,"ptr: *mut i64, val: int64x2x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s64_x3,"ptr: *mut i64, val: int64x2x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s64_x4,"ptr: *mut i64, val: int64x2x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s8,"ptr: *mut i8, val: int8x16_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s8_x2,"ptr: *mut i8, val: int8x16x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s8_x3,"ptr: *mut i8, val: int8x16x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_s8_x4,"ptr: *mut i8, val: int8x16x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u16,"ptr: *mut u16, val: uint16x8_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u16_x2,"ptr: *mut u16, val: uint16x8x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u16_x3,"ptr: *mut u16, val: uint16x8x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u16_x4,"ptr: *mut u16, val: uint16x8x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u32,"ptr: *mut u32, val: uint32x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u32_x2,"ptr: *mut u32, val: uint32x4x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u32_x3,"ptr: *mut u32, val: uint32x4x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u32_x4,"ptr: *mut u32, val: uint32x4x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u64,"ptr: *mut u64, val: uint64x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u64_x2,"ptr: *mut u64, val: uint64x2x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u64_x3,"ptr: *mut u64, val: uint64x2x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u64_x4,"ptr: *mut u64, val: uint64x2x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u8,"ptr: *mut u8, val: uint8x16_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u8_x2,"ptr: *mut u8, val: uint8x16x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u8_x3,"ptr: *mut u8, val: uint8x16x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst1q_u8_x4,"ptr: *mut u8, val: uint8x16x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst2_bf16,"ptr: *mut bfloat16_t, val: bfloat16x4x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_f16,"ptr: *mut float16_t, val: float16x4x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_f32,"ptr: *mut f32, val: float32x2x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_f64,"ptr: *mut float64_t, val: float64x1x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst2_lane_bf16,"ptr: *mut bfloat16_t, val: bfloat16x4x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_f16,"ptr: *mut float16_t, val: float16x4x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_f32,"ptr: *mut f32, val: float32x2x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_f64,"ptr: *mut float64_t, val: float64x1x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_p16,"ptr: *mut poly16_t, val: poly16x4x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_p64,"ptr: *mut poly64_t, val: poly64x1x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_p8,"ptr: *mut poly8_t, val: poly8x8x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_s16,"ptr: *mut i16, val: int16x4x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_s32,"ptr: *mut i32, val: int32x2x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_s64,"ptr: *mut i64, val: int64x1x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_s8,"ptr: *mut i8, val: int8x8x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_u16,"ptr: *mut u16, val: uint16x4x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_u32,"ptr: *mut u32, val: uint32x2x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_u64,"ptr: *mut u64, val: uint64x1x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_lane_u8,"ptr: *mut u8, val: uint8x8x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2_p16,"ptr: *mut poly16_t, val: poly16x4x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_p64,"ptr: *mut poly64_t, val: poly64x1x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst2_p8,"ptr: *mut poly8_t, val: poly8x8x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_s16,"ptr: *mut i16, val: int16x4x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_s32,"ptr: *mut i32, val: int32x2x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_s64,"ptr: *mut i64, val: int64x1x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst2_s8,"ptr: *mut i8, val: int8x8x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_u16,"ptr: *mut u16, val: uint16x4x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_u32,"ptr: *mut u32, val: uint32x2x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2_u64,"ptr: *mut u64, val: uint64x1x2_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst2_u8,"ptr: *mut u8, val: uint8x8x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_bf16,"ptr: *mut bfloat16_t, val: bfloat16x8x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_f16,"ptr: *mut float16_t, val: float16x8x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_f32,"ptr: *mut f32, val: float32x4x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_f64,"ptr: *mut float64_t, val: float64x2x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_bf16,"ptr: *mut bfloat16_t, val: bfloat16x8x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_f16,"ptr: *mut float16_t, val: float16x8x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_f32,"ptr: *mut f32, val: float32x4x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_f64,"ptr: *mut float64_t, val: float64x2x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_p16,"ptr: *mut poly16_t, val: poly16x8x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_p64,"ptr: *mut poly64_t, val: poly64x2x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_p8,"ptr: *mut poly8_t, val: poly8x16x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_s16,"ptr: *mut i16, val: int16x8x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_s32,"ptr: *mut i32, val: int32x4x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_s64,"ptr: *mut i64, val: int64x2x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_s8,"ptr: *mut i8, val: int8x16x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_u16,"ptr: *mut u16, val: uint16x8x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_u32,"ptr: *mut u32, val: uint32x4x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_u64,"ptr: *mut u64, val: uint64x2x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_lane_u8,"ptr: *mut u8, val: uint8x16x2_t, lane: const int",void,Store multiple 2-element structures from two registers +FALSE,vst2q_p16,"ptr: *mut poly16_t, val: poly16x8x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_p64,"ptr: *mut poly64_t, val: poly64x2x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_p8,"ptr: *mut poly8_t, val: poly8x16x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_s16,"ptr: *mut i16, val: int16x8x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_s32,"ptr: *mut i32, val: int32x4x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_s64,"ptr: *mut i64, val: int64x2x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_s8,"ptr: *mut i8, val: int8x16x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_u16,"ptr: *mut u16, val: uint16x8x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_u32,"ptr: *mut u32, val: uint32x4x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_u64,"ptr: *mut u64, val: uint64x2x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst2q_u8,"ptr: *mut u8, val: uint8x16x2_t",void,Store multiple 2-element structures from two registers +FALSE,vst3_bf16,"ptr: *mut bfloat16_t, val: bfloat16x4x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_f16,"ptr: *mut float16_t, val: float16x4x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_f32,"ptr: *mut f32, val: float32x2x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_f64,"ptr: *mut float64_t, val: float64x1x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst3_lane_bf16,"ptr: *mut bfloat16_t, val: bfloat16x4x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_f16,"ptr: *mut float16_t, val: float16x4x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_f32,"ptr: *mut f32, val: float32x2x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_f64,"ptr: *mut float64_t, val: float64x1x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_p16,"ptr: *mut poly16_t, val: poly16x4x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_p64,"ptr: *mut poly64_t, val: poly64x1x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_p8,"ptr: *mut poly8_t, val: poly8x8x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_s16,"ptr: *mut i16, val: int16x4x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_s32,"ptr: *mut i32, val: int32x2x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_s64,"ptr: *mut i64, val: int64x1x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_s8,"ptr: *mut i8, val: int8x8x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_u16,"ptr: *mut u16, val: uint16x4x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_u32,"ptr: *mut u32, val: uint32x2x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_u64,"ptr: *mut u64, val: uint64x1x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_lane_u8,"ptr: *mut u8, val: uint8x8x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3_p16,"ptr: *mut poly16_t, val: poly16x4x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_p64,"ptr: *mut poly64_t, val: poly64x1x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst3_p8,"ptr: *mut poly8_t, val: poly8x8x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_s16,"ptr: *mut i16, val: int16x4x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_s32,"ptr: *mut i32, val: int32x2x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_s64,"ptr: *mut i64, val: int64x1x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst3_s8,"ptr: *mut i8, val: int8x8x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_u16,"ptr: *mut u16, val: uint16x4x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_u32,"ptr: *mut u32, val: uint32x2x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3_u64,"ptr: *mut u64, val: uint64x1x3_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst3_u8,"ptr: *mut u8, val: uint8x8x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_bf16,"ptr: *mut bfloat16_t, val: bfloat16x8x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_f16,"ptr: *mut float16_t, val: float16x8x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_f32,"ptr: *mut f32, val: float32x4x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_f64,"ptr: *mut float64_t, val: float64x2x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_bf16,"ptr: *mut bfloat16_t, val: bfloat16x8x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_f16,"ptr: *mut float16_t, val: float16x8x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_f32,"ptr: *mut f32, val: float32x4x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_f64,"ptr: *mut float64_t, val: float64x2x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_p16,"ptr: *mut poly16_t, val: poly16x8x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_p64,"ptr: *mut poly64_t, val: poly64x2x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_p8,"ptr: *mut poly8_t, val: poly8x16x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_s16,"ptr: *mut i16, val: int16x8x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_s32,"ptr: *mut i32, val: int32x4x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_s64,"ptr: *mut i64, val: int64x2x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_s8,"ptr: *mut i8, val: int8x16x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_u16,"ptr: *mut u16, val: uint16x8x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_u32,"ptr: *mut u32, val: uint32x4x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_u64,"ptr: *mut u64, val: uint64x2x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_lane_u8,"ptr: *mut u8, val: uint8x16x3_t, lane: const int",void,Store multiple 3-element structures from three registers +FALSE,vst3q_p16,"ptr: *mut poly16_t, val: poly16x8x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_p64,"ptr: *mut poly64_t, val: poly64x2x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_p8,"ptr: *mut poly8_t, val: poly8x16x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_s16,"ptr: *mut i16, val: int16x8x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_s32,"ptr: *mut i32, val: int32x4x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_s64,"ptr: *mut i64, val: int64x2x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_s8,"ptr: *mut i8, val: int8x16x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_u16,"ptr: *mut u16, val: uint16x8x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_u32,"ptr: *mut u32, val: uint32x4x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_u64,"ptr: *mut u64, val: uint64x2x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst3q_u8,"ptr: *mut u8, val: uint8x16x3_t",void,Store multiple 3-element structures from three registers +FALSE,vst4_bf16,"ptr: *mut bfloat16_t, val: bfloat16x4x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_f16,"ptr: *mut float16_t, val: float16x4x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_f32,"ptr: *mut f32, val: float32x2x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_f64,"ptr: *mut float64_t, val: float64x1x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst4_lane_bf16,"ptr: *mut bfloat16_t, val: bfloat16x4x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_f16,"ptr: *mut float16_t, val: float16x4x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_f32,"ptr: *mut f32, val: float32x2x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_f64,"ptr: *mut float64_t, val: float64x1x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_p16,"ptr: *mut poly16_t, val: poly16x4x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_p64,"ptr: *mut poly64_t, val: poly64x1x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_p8,"ptr: *mut poly8_t, val: poly8x8x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_s16,"ptr: *mut i16, val: int16x4x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_s32,"ptr: *mut i32, val: int32x2x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_s64,"ptr: *mut i64, val: int64x1x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_s8,"ptr: *mut i8, val: int8x8x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_u16,"ptr: *mut u16, val: uint16x4x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_u32,"ptr: *mut u32, val: uint32x2x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_u64,"ptr: *mut u64, val: uint64x1x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_lane_u8,"ptr: *mut u8, val: uint8x8x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4_p16,"ptr: *mut poly16_t, val: poly16x4x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_p64,"ptr: *mut poly64_t, val: poly64x1x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst4_p8,"ptr: *mut poly8_t, val: poly8x8x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_s16,"ptr: *mut i16, val: int16x4x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_s32,"ptr: *mut i32, val: int32x2x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_s64,"ptr: *mut i64, val: int64x1x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst4_s8,"ptr: *mut i8, val: int8x8x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_u16,"ptr: *mut u16, val: uint16x4x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_u32,"ptr: *mut u32, val: uint32x2x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4_u64,"ptr: *mut u64, val: uint64x1x4_t",void,"Store multiple single-element structures from one, two, three, or four registers" +FALSE,vst4_u8,"ptr: *mut u8, val: uint8x8x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_bf16,"ptr: *mut bfloat16_t, val: bfloat16x8x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_f16,"ptr: *mut float16_t, val: float16x8x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_f32,"ptr: *mut f32, val: float32x4x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_f64,"ptr: *mut float64_t, val: float64x2x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_bf16,"ptr: *mut bfloat16_t, val: bfloat16x8x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_f16,"ptr: *mut float16_t, val: float16x8x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_f32,"ptr: *mut f32, val: float32x4x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_f64,"ptr: *mut float64_t, val: float64x2x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_p16,"ptr: *mut poly16_t, val: poly16x8x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_p64,"ptr: *mut poly64_t, val: poly64x2x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_p8,"ptr: *mut poly8_t, val: poly8x16x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_s16,"ptr: *mut i16, val: int16x8x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_s32,"ptr: *mut i32, val: int32x4x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_s64,"ptr: *mut i64, val: int64x2x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_s8,"ptr: *mut i8, val: int8x16x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_u16,"ptr: *mut u16, val: uint16x8x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_u32,"ptr: *mut u32, val: uint32x4x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_u64,"ptr: *mut u64, val: uint64x2x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_lane_u8,"ptr: *mut u8, val: uint8x16x4_t, lane: const int",void,Store multiple 4-element structures from four registers +FALSE,vst4q_p16,"ptr: *mut poly16_t, val: poly16x8x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_p64,"ptr: *mut poly64_t, val: poly64x2x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_p8,"ptr: *mut poly8_t, val: poly8x16x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_s16,"ptr: *mut i16, val: int16x8x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_s32,"ptr: *mut i32, val: int32x4x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_s64,"ptr: *mut i64, val: int64x2x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_s8,"ptr: *mut i8, val: int8x16x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_u16,"ptr: *mut u16, val: uint16x8x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_u32,"ptr: *mut u32, val: uint32x4x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_u64,"ptr: *mut u64, val: uint64x2x4_t",void,Store multiple 4-element structures from four registers +FALSE,vst4q_u8,"ptr: *mut u8, val: uint8x16x4_t",void,Store multiple 4-element structures from four registers +FALSE,vstrq_p128,"ptr: *mut poly128_t, val: poly128_t",void,Store SIMD&FP register (immediate offset) +FALSE,vsub_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Floating-point subtract +TRUE,vsub_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Floating-point subtract +TRUE,vsub_f64,"a: float64x1_t, b: float64x1_t",float64x1_t,Floating-point subtract +TRUE,vsub_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Subtract +TRUE,vsub_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Subtract +TRUE,vsub_s64,"a: int64x1_t, b: int64x1_t",int64x1_t,Subtract +TRUE,vsub_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Subtract +TRUE,vsub_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Subtract +TRUE,vsub_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Subtract +TRUE,vsub_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Subtract +TRUE,vsub_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Subtract +FALSE,vsubd_s64,"a: i64, b: i64",i64,Subtract +FALSE,vsubd_u64,"a: u64, b: u64",u64,Subtract +FALSE,vsubh_f16,"a: float16_t, b: float16_t",float16_t,Floating-point subtract +TRUE,vsubhn_high_s16,"r: int8x8_t, a: int16x8_t, b: int16x8_t",int8x16_t,Subtract returning high narrow +TRUE,vsubhn_high_s32,"r: int16x4_t, a: int32x4_t, b: int32x4_t",int16x8_t,Subtract returning high narrow +TRUE,vsubhn_high_s64,"r: int32x2_t, a: int64x2_t, b: int64x2_t",int32x4_t,Subtract returning high narrow +TRUE,vsubhn_high_u16,"r: uint8x8_t, a: uint16x8_t, b: uint16x8_t",uint8x16_t,Subtract returning high narrow +TRUE,vsubhn_high_u32,"r: uint16x4_t, a: uint32x4_t, b: uint32x4_t",uint16x8_t,Subtract returning high narrow +TRUE,vsubhn_high_u64,"r: uint32x2_t, a: uint64x2_t, b: uint64x2_t",uint32x4_t,Subtract returning high narrow +TRUE,vsubhn_s16,"a: int16x8_t, b: int16x8_t",int8x8_t,Subtract returning high narrow +TRUE,vsubhn_s32,"a: int32x4_t, b: int32x4_t",int16x4_t,Subtract returning high narrow +TRUE,vsubhn_s64,"a: int64x2_t, b: int64x2_t",int32x2_t,Subtract returning high narrow +TRUE,vsubhn_u16,"a: uint16x8_t, b: uint16x8_t",uint8x8_t,Subtract returning high narrow +TRUE,vsubhn_u32,"a: uint32x4_t, b: uint32x4_t",uint16x4_t,Subtract returning high narrow +TRUE,vsubhn_u64,"a: uint64x2_t, b: uint64x2_t",uint32x2_t,Subtract returning high narrow +TRUE,vsubl_high_s16,"a: int16x8_t, b: int16x8_t",int32x4_t,Signed subtract long +TRUE,vsubl_high_s32,"a: int32x4_t, b: int32x4_t",int64x2_t,Signed subtract long +TRUE,vsubl_high_s8,"a: int8x16_t, b: int8x16_t",int16x8_t,Signed subtract long +TRUE,vsubl_high_u16,"a: uint16x8_t, b: uint16x8_t",uint32x4_t,Unsigned subtract long +TRUE,vsubl_high_u32,"a: uint32x4_t, b: uint32x4_t",uint64x2_t,Unsigned subtract long +TRUE,vsubl_high_u8,"a: uint8x16_t, b: uint8x16_t",uint16x8_t,Unsigned subtract long +TRUE,vsubl_s16,"a: int16x4_t, b: int16x4_t",int32x4_t,Signed subtract long +TRUE,vsubl_s32,"a: int32x2_t, b: int32x2_t",int64x2_t,Signed subtract long +TRUE,vsubl_s8,"a: int8x8_t, b: int8x8_t",int16x8_t,Signed subtract long +TRUE,vsubl_u16,"a: uint16x4_t, b: uint16x4_t",uint32x4_t,Unsigned subtract long +TRUE,vsubl_u32,"a: uint32x2_t, b: uint32x2_t",uint64x2_t,Unsigned subtract long +TRUE,vsubl_u8,"a: uint8x8_t, b: uint8x8_t",uint16x8_t,Unsigned subtract long +FALSE,vsubq_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Floating-point subtract +TRUE,vsubq_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Floating-point subtract +TRUE,vsubq_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Floating-point subtract +TRUE,vsubq_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Subtract +TRUE,vsubq_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Subtract +TRUE,vsubq_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Subtract +TRUE,vsubq_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Subtract +TRUE,vsubq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Subtract +TRUE,vsubq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Subtract +TRUE,vsubq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Subtract +TRUE,vsubq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Subtract +TRUE,vsubw_high_s16,"a: int32x4_t, b: int16x8_t",int32x4_t,Signed subtract wide +TRUE,vsubw_high_s32,"a: int64x2_t, b: int32x4_t",int64x2_t,Signed subtract wide +TRUE,vsubw_high_s8,"a: int16x8_t, b: int8x16_t",int16x8_t,Signed subtract wide +TRUE,vsubw_high_u16,"a: uint32x4_t, b: uint16x8_t",uint32x4_t,Unsigned subtract wide +TRUE,vsubw_high_u32,"a: uint64x2_t, b: uint32x4_t",uint64x2_t,Unsigned subtract wide +TRUE,vsubw_high_u8,"a: uint16x8_t, b: uint8x16_t",uint16x8_t,Unsigned subtract wide +TRUE,vsubw_s16,"a: int32x4_t, b: int16x4_t",int32x4_t,Signed subtract wide +TRUE,vsubw_s32,"a: int64x2_t, b: int32x2_t",int64x2_t,Signed subtract wide +TRUE,vsubw_s8,"a: int16x8_t, b: int8x8_t",int16x8_t,Signed subtract wide +TRUE,vsubw_u16,"a: uint32x4_t, b: uint16x4_t",uint32x4_t,Unsigned subtract wide +TRUE,vsubw_u32,"a: uint64x2_t, b: uint32x2_t",uint64x2_t,Unsigned subtract wide +TRUE,vsubw_u8,"a: uint16x8_t, b: uint8x8_t",uint16x8_t,Unsigned subtract wide +FALSE,vsudot_lane_s32,"r: int32x2_t, a: int8x8_t, b: uint8x8_t, lane: const int",int32x2_t,Dot product index form with signed and unsigned integers +FALSE,vsudot_laneq_s32,"r: int32x2_t, a: int8x8_t, b: uint8x16_t, lane: const int",int32x2_t,Dot product index form with signed and unsigned integers +FALSE,vsudotq_lane_s32,"r: int32x4_t, a: int8x16_t, b: uint8x8_t, lane: const int",int32x4_t,Dot product index form with signed and unsigned integers +FALSE,vsudotq_laneq_s32,"r: int32x4_t, a: int8x16_t, b: uint8x16_t, lane: const int",int32x4_t,Dot product index form with signed and unsigned integers +TRUE,vtbl1_p8,"a: poly8x8_t, b: uint8x8_t",poly8x8_t,Table vector lookup +TRUE,vtbl1_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Table vector lookup +TRUE,vtbl1_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Table vector lookup +TRUE,vtbl2_p8,"a: poly8x8x2_t, b: uint8x8_t",poly8x8_t,Table vector lookup +TRUE,vtbl2_s8,"a: int8x8x2_t, b: int8x8_t",int8x8_t,Table vector lookup +TRUE,vtbl2_u8,"a: uint8x8x2_t, b: uint8x8_t",uint8x8_t,Table vector lookup +TRUE,vtbl3_p8,"a: poly8x8x3_t, b: uint8x8_t",poly8x8_t,Table vector lookup +TRUE,vtbl3_s8,"a: int8x8x3_t, b: int8x8_t",int8x8_t,Table vector lookup +TRUE,vtbl3_u8,"a: uint8x8x3_t, b: uint8x8_t",uint8x8_t,Table vector lookup +TRUE,vtbl4_p8,"a: poly8x8x4_t, b: uint8x8_t",poly8x8_t,Table vector lookup +TRUE,vtbl4_s8,"a: int8x8x4_t, b: int8x8_t",int8x8_t,Table vector lookup +TRUE,vtbl4_u8,"a: uint8x8x4_t, b: uint8x8_t",uint8x8_t,Table vector lookup +TRUE,vtbx1_p8,"a: poly8x8_t, b: poly8x8_t, c: uint8x8_t",poly8x8_t,Bitwise insert if false +TRUE,vtbx1_s8,"a: int8x8_t, b: int8x8_t, c: int8x8_t",int8x8_t,Bitwise insert if false +TRUE,vtbx1_u8,"a: uint8x8_t, b: uint8x8_t, c: uint8x8_t",uint8x8_t,Bitwise insert if false +TRUE,vtbx2_p8,"a: poly8x8_t, b: poly8x8x2_t, c: uint8x8_t",poly8x8_t,Table vector lookup extension +TRUE,vtbx2_s8,"a: int8x8_t, b: int8x8x2_t, c: int8x8_t",int8x8_t,Table vector lookup extension +TRUE,vtbx2_u8,"a: uint8x8_t, b: uint8x8x2_t, c: uint8x8_t",uint8x8_t,Table vector lookup extension +TRUE,vtbx3_p8,"a: poly8x8_t, b: poly8x8x3_t, c: uint8x8_t",poly8x8_t,Bitwise insert if false +TRUE,vtbx3_s8,"a: int8x8_t, b: int8x8x3_t, c: int8x8_t",int8x8_t,Bitwise insert if false +TRUE,vtbx3_u8,"a: uint8x8_t, b: uint8x8x3_t, c: uint8x8_t",uint8x8_t,Bitwise insert if false +TRUE,vtbx4_p8,"a: poly8x8_t, b: poly8x8x4_t, c: uint8x8_t",poly8x8_t,Table vector lookup extension +TRUE,vtbx4_s8,"a: int8x8_t, b: int8x8x4_t, c: int8x8_t",int8x8_t,Table vector lookup extension +TRUE,vtbx4_u8,"a: uint8x8_t, b: uint8x8x4_t, c: uint8x8_t",uint8x8_t,Table vector lookup extension +FALSE,vtrn_f16,"a: float16x4_t, b: float16x4_t",float16x4x2_t,Transpose elements +FALSE,vtrn_f32,"a: float32x2_t, b: float32x2_t",float32x2x2_t,Transpose elements +FALSE,vtrn_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4x2_t,Transpose elements +FALSE,vtrn_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8x2_t,Transpose elements +FALSE,vtrn_s16,"a: int16x4_t, b: int16x4_t",int16x4x2_t,Transpose elements +FALSE,vtrn_s32,"a: int32x2_t, b: int32x2_t",int32x2x2_t,Transpose elements +FALSE,vtrn_s8,"a: int8x8_t, b: int8x8_t",int8x8x2_t,Transpose elements +FALSE,vtrn_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4x2_t,Transpose elements +FALSE,vtrn_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2x2_t,Transpose elements +FALSE,vtrn_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8x2_t,Transpose elements +FALSE,vtrn1_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Transpose vectors +TRUE,vtrn1_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Transpose vectors +TRUE,vtrn1_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4_t,Transpose vectors +TRUE,vtrn1_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8_t,Transpose vectors +TRUE,vtrn1_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Transpose vectors +TRUE,vtrn1_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Transpose vectors +TRUE,vtrn1_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Transpose vectors +TRUE,vtrn1_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Transpose vectors +TRUE,vtrn1_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Transpose vectors +TRUE,vtrn1_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Transpose vectors +FALSE,vtrn1q_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Transpose vectors +TRUE,vtrn1q_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Transpose vectors +TRUE,vtrn1q_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Transpose vectors +TRUE,vtrn1q_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8_t,Transpose vectors +TRUE,vtrn1q_p64,"a: poly64x2_t, b: poly64x2_t",poly64x2_t,Transpose vectors +TRUE,vtrn1q_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16_t,Transpose vectors +TRUE,vtrn1q_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Transpose vectors +TRUE,vtrn1q_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Transpose vectors +TRUE,vtrn1q_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Transpose vectors +TRUE,vtrn1q_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Transpose vectors +TRUE,vtrn1q_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Transpose vectors +TRUE,vtrn1q_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Transpose vectors +TRUE,vtrn1q_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Transpose vectors +TRUE,vtrn1q_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Transpose vectors +FALSE,vtrn2_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Transpose vectors +TRUE,vtrn2_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Transpose vectors +TRUE,vtrn2_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4_t,Transpose vectors +TRUE,vtrn2_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8_t,Transpose vectors +TRUE,vtrn2_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Transpose vectors +TRUE,vtrn2_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Transpose vectors +TRUE,vtrn2_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Transpose vectors +TRUE,vtrn2_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Transpose vectors +TRUE,vtrn2_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Transpose vectors +TRUE,vtrn2_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Transpose vectors +FALSE,vtrn2q_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Transpose vectors +TRUE,vtrn2q_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Transpose vectors +TRUE,vtrn2q_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Transpose vectors +TRUE,vtrn2q_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8_t,Transpose vectors +TRUE,vtrn2q_p64,"a: poly64x2_t, b: poly64x2_t",poly64x2_t,Transpose vectors +TRUE,vtrn2q_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16_t,Transpose vectors +TRUE,vtrn2q_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Transpose vectors +TRUE,vtrn2q_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Transpose vectors +TRUE,vtrn2q_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Transpose vectors +TRUE,vtrn2q_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Transpose vectors +TRUE,vtrn2q_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Transpose vectors +TRUE,vtrn2q_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Transpose vectors +TRUE,vtrn2q_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Transpose vectors +TRUE,vtrn2q_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Transpose vectors +FALSE,vtrnq_f16,"a: float16x8_t, b: float16x8_t",float16x8x2_t,Transpose elements +FALSE,vtrnq_f32,"a: float32x4_t, b: float32x4_t",float32x4x2_t,Transpose elements +FALSE,vtrnq_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8x2_t,Transpose elements +FALSE,vtrnq_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16x2_t,Transpose elements +FALSE,vtrnq_s16,"a: int16x8_t, b: int16x8_t",int16x8x2_t,Transpose elements +FALSE,vtrnq_s32,"a: int32x4_t, b: int32x4_t",int32x4x2_t,Transpose elements +FALSE,vtrnq_s8,"a: int8x16_t, b: int8x16_t",int8x16x2_t,Transpose elements +FALSE,vtrnq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8x2_t,Transpose elements +FALSE,vtrnq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4x2_t,Transpose elements +FALSE,vtrnq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16x2_t,Transpose elements +TRUE,vtst_p64,"a: poly64x1_t, b: poly64x1_t",uint64x1_t,Compare bitwise test bits nonzero +TRUE,vtst_p8,"a: poly8x8_t, b: poly8x8_t",uint8x8_t,Compare bitwise test bits nonzero +TRUE,vtst_s16,"a: int16x4_t, b: int16x4_t",uint16x4_t,Compare bitwise test bits nonzero +TRUE,vtst_s32,"a: int32x2_t, b: int32x2_t",uint32x2_t,Compare bitwise test bits nonzero +TRUE,vtst_s64,"a: int64x1_t, b: int64x1_t",uint64x1_t,Compare bitwise test bits nonzero +TRUE,vtst_s8,"a: int8x8_t, b: int8x8_t",uint8x8_t,Compare bitwise test bits nonzero +TRUE,vtst_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Compare bitwise test bits nonzero +TRUE,vtst_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Compare bitwise test bits nonzero +TRUE,vtst_u64,"a: uint64x1_t, b: uint64x1_t",uint64x1_t,Compare bitwise test bits nonzero +TRUE,vtst_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Compare bitwise test bits nonzero +FALSE,vtstd_s64,"a: i64, b: i64",u64,Compare bitwise test bits nonzero +FALSE,vtstd_u64,"a: u64, b: u64",u64,Compare bitwise test bits nonzero +TRUE,vtstq_p64,"a: poly64x2_t, b: poly64x2_t",uint64x2_t,Compare bitwise test bits nonzero +TRUE,vtstq_p8,"a: poly8x16_t, b: poly8x16_t",uint8x16_t,Compare bitwise test bits nonzero +TRUE,vtstq_s16,"a: int16x8_t, b: int16x8_t",uint16x8_t,Compare bitwise test bits nonzero +TRUE,vtstq_s32,"a: int32x4_t, b: int32x4_t",uint32x4_t,Compare bitwise test bits nonzero +TRUE,vtstq_s64,"a: int64x2_t, b: int64x2_t",uint64x2_t,Compare bitwise test bits nonzero +TRUE,vtstq_s8,"a: int8x16_t, b: int8x16_t",uint8x16_t,Compare bitwise test bits nonzero +TRUE,vtstq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Compare bitwise test bits nonzero +TRUE,vtstq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Compare bitwise test bits nonzero +TRUE,vtstq_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Compare bitwise test bits nonzero +TRUE,vtstq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Compare bitwise test bits nonzero +FALSE,vuqadd_s16,"a: int16x4_t, b: uint16x4_t",int16x4_t,Signed saturating accumulate of unsigned value +FALSE,vuqadd_s32,"a: int32x2_t, b: uint32x2_t",int32x2_t,Signed saturating accumulate of unsigned value +FALSE,vuqadd_s64,"a: int64x1_t, b: uint64x1_t",int64x1_t,Signed saturating accumulate of unsigned value +FALSE,vuqadd_s8,"a: int8x8_t, b: uint8x8_t",int8x8_t,Signed saturating accumulate of unsigned value +FALSE,vuqaddb_s8,"a: i8, b: u8",i8,Signed saturating accumulate of unsigned value +FALSE,vuqaddd_s64,"a: i64, b: u64",i64,Signed saturating accumulate of unsigned value +FALSE,vuqaddh_s16,"a: i16, b: u16",i16,Signed saturating accumulate of unsigned value +FALSE,vuqaddq_s16,"a: int16x8_t, b: uint16x8_t",int16x8_t,Signed saturating accumulate of unsigned value +FALSE,vuqaddq_s32,"a: int32x4_t, b: uint32x4_t",int32x4_t,Signed saturating accumulate of unsigned value +FALSE,vuqaddq_s64,"a: int64x2_t, b: uint64x2_t",int64x2_t,Signed saturating accumulate of unsigned value +FALSE,vuqaddq_s8,"a: int8x16_t, b: uint8x16_t",int8x16_t,Signed saturating accumulate of unsigned value +FALSE,vuqadds_s32,"a: i32, b: u32",i32,Signed saturating accumulate of unsigned value +FALSE,vusdot_lane_s32,"r: int32x2_t, a: uint8x8_t, b: int8x8_t, lane: const int",int32x2_t,Dot product vector form with unsigned and signed integers +FALSE,vusdot_laneq_s32,"r: int32x2_t, a: uint8x8_t, b: int8x16_t, lane: const int",int32x2_t,Dot product vector form with unsigned and signed integers +FALSE,vusdot_s32,"r: int32x2_t, a: uint8x8_t, b: int8x8_t",int32x2_t,Dot product vector form with unsigned and signed integers +FALSE,vusdotq_lane_s32,"r: int32x4_t, a: uint8x16_t, b: int8x8_t, lane: const int",int32x4_t,Dot product vector form with unsigned and signed integers +FALSE,vusdotq_laneq_s32,"r: int32x4_t, a: uint8x16_t, b: int8x16_t, lane: const int",int32x4_t,Dot product vector form with unsigned and signed integers +FALSE,vusdotq_s32,"r: int32x4_t, a: uint8x16_t, b: int8x16_t",int32x4_t,Dot product vector form with unsigned and signed integers +FALSE,vusmmlaq_s32,"r: int32x4_t, a: uint8x16_t, b: int8x16_t",int32x4_t,Unsigned and signed 8-bit integer matrix multiply-accumulate +FALSE,vuzp_f16,"a: float16x4_t, b: float16x4_t",float16x4x2_t,Unzip vectors +FALSE,vuzp_f32,"a: float32x2_t, b: float32x2_t",float32x2x2_t,Unzip vectors +FALSE,vuzp_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4x2_t,Unzip vectors +FALSE,vuzp_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8x2_t,Unzip vectors +FALSE,vuzp_s16,"a: int16x4_t, b: int16x4_t",int16x4x2_t,Unzip vectors +FALSE,vuzp_s32,"a: int32x2_t, b: int32x2_t",int32x2x2_t,Unzip vectors +FALSE,vuzp_s8,"a: int8x8_t, b: int8x8_t",int8x8x2_t,Unzip vectors +FALSE,vuzp_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4x2_t,Unzip vectors +FALSE,vuzp_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2x2_t,Unzip vectors +FALSE,vuzp_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8x2_t,Unzip vectors +FALSE,vuzp1_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Unzip vectors +TRUE,vuzp1_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Unzip vectors +FALSE,vuzp1_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4_t,Unzip vectors +TRUE,vuzp1_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8_t,Unzip vectors +TRUE,vuzp1_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Unzip vectors +TRUE,vuzp1_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Unzip vectors +TRUE,vuzp1_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Unzip vectors +TRUE,vuzp1_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unzip vectors +TRUE,vuzp1_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unzip vectors +TRUE,vuzp1_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unzip vectors +FALSE,vuzp1q_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Unzip vectors +TRUE,vuzp1q_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Unzip vectors +TRUE,vuzp1q_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Unzip vectors +FALSE,vuzp1q_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8_t,Unzip vectors +TRUE,vuzp1q_p64,"a: poly64x2_t, b: poly64x2_t",poly64x2_t,Unzip vectors +FALSE,vuzp1q_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16_t,Unzip vectors +TRUE,vuzp1q_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Unzip vectors +TRUE,vuzp1q_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Unzip vectors +TRUE,vuzp1q_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Unzip vectors +TRUE,vuzp1q_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Unzip vectors +TRUE,vuzp1q_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unzip vectors +TRUE,vuzp1q_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unzip vectors +TRUE,vuzp1q_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Unzip vectors +TRUE,vuzp1q_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unzip vectors +FALSE,vuzp2_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Unzip vectors +TRUE,vuzp2_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Unzip vectors +FALSE,vuzp2_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4_t,Unzip vectors +TRUE,vuzp2_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8_t,Unzip vectors +TRUE,vuzp2_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Unzip vectors +TRUE,vuzp2_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Unzip vectors +TRUE,vuzp2_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Unzip vectors +TRUE,vuzp2_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Unzip vectors +TRUE,vuzp2_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Unzip vectors +TRUE,vuzp2_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Unzip vectors +FALSE,vuzp2q_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Unzip vectors +TRUE,vuzp2q_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Unzip vectors +TRUE,vuzp2q_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Unzip vectors +FALSE,vuzp2q_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8_t,Unzip vectors +TRUE,vuzp2q_p64,"a: poly64x2_t, b: poly64x2_t",poly64x2_t,Unzip vectors +FALSE,vuzp2q_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16_t,Unzip vectors +TRUE,vuzp2q_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Unzip vectors +TRUE,vuzp2q_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Unzip vectors +TRUE,vuzp2q_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Unzip vectors +TRUE,vuzp2q_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Unzip vectors +TRUE,vuzp2q_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Unzip vectors +TRUE,vuzp2q_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Unzip vectors +TRUE,vuzp2q_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Unzip vectors +TRUE,vuzp2q_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Unzip vectors +FALSE,vuzpq_f16,"a: float16x8_t, b: float16x8_t",float16x8x2_t,Unzip vectors +FALSE,vuzpq_f32,"a: float32x4_t, b: float32x4_t",float32x4x2_t,Unzip vectors +FALSE,vuzpq_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8x2_t,Unzip vectors +FALSE,vuzpq_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16x2_t,Unzip vectors +FALSE,vuzpq_s16,"a: int16x8_t, b: int16x8_t",int16x8x2_t,Unzip vectors +FALSE,vuzpq_s32,"a: int32x4_t, b: int32x4_t",int32x4x2_t,Unzip vectors +FALSE,vuzpq_s8,"a: int8x16_t, b: int8x16_t",int8x16x2_t,Unzip vectors +FALSE,vuzpq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8x2_t,Unzip vectors +FALSE,vuzpq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4x2_t,Unzip vectors +FALSE,vuzpq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16x2_t,Unzip vectors +FALSE,vxarq_u64,"a: uint64x2_t, b: uint64x2_t, imm6: const int",uint64x2_t,Exclusive OR and rotate +FALSE,vzip_f16,"a: float16x4_t, b: float16x4_t",float16x4x2_t,Zip vectors +FALSE,vzip_f32,"a: float32x2_t, b: float32x2_t",float32x2x2_t,Zip vectors +FALSE,vzip_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4x2_t,Zip vectors +FALSE,vzip_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8x2_t,Zip vectors +FALSE,vzip_s16,"a: int16x4_t, b: int16x4_t",int16x4x2_t,Zip vectors +FALSE,vzip_s32,"a: int32x2_t, b: int32x2_t",int32x2x2_t,Zip vectors +FALSE,vzip_s8,"a: int8x8_t, b: int8x8_t",int8x8x2_t,Zip vectors +FALSE,vzip_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4x2_t,Zip vectors +FALSE,vzip_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2x2_t,Zip vectors +FALSE,vzip_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8x2_t,Zip vectors +FALSE,vzip1_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Zip vectors +TRUE,vzip1_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Zip vectors +TRUE,vzip1_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4_t,Zip vectors +TRUE,vzip1_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8_t,Zip vectors +TRUE,vzip1_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Zip vectors +TRUE,vzip1_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Zip vectors +TRUE,vzip1_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Zip vectors +TRUE,vzip1_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Zip vectors +TRUE,vzip1_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Zip vectors +TRUE,vzip1_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Zip vectors +FALSE,vzip1q_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Zip vectors +TRUE,vzip1q_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Zip vectors +TRUE,vzip1q_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Zip vectors +TRUE,vzip1q_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8_t,Zip vectors +TRUE,vzip1q_p64,"a: poly64x2_t, b: poly64x2_t",poly64x2_t,Zip vectors +TRUE,vzip1q_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16_t,Zip vectors +TRUE,vzip1q_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Zip vectors +TRUE,vzip1q_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Zip vectors +TRUE,vzip1q_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Zip vectors +TRUE,vzip1q_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Zip vectors +TRUE,vzip1q_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Zip vectors +TRUE,vzip1q_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Zip vectors +TRUE,vzip1q_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Zip vectors +TRUE,vzip1q_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Zip vectors +FALSE,vzip2_f16,"a: float16x4_t, b: float16x4_t",float16x4_t,Zip vectors +TRUE,vzip2_f32,"a: float32x2_t, b: float32x2_t",float32x2_t,Zip vectors +TRUE,vzip2_p16,"a: poly16x4_t, b: poly16x4_t",poly16x4_t,Zip vectors +TRUE,vzip2_p8,"a: poly8x8_t, b: poly8x8_t",poly8x8_t,Zip vectors +TRUE,vzip2_s16,"a: int16x4_t, b: int16x4_t",int16x4_t,Zip vectors +TRUE,vzip2_s32,"a: int32x2_t, b: int32x2_t",int32x2_t,Zip vectors +TRUE,vzip2_s8,"a: int8x8_t, b: int8x8_t",int8x8_t,Zip vectors +TRUE,vzip2_u16,"a: uint16x4_t, b: uint16x4_t",uint16x4_t,Zip vectors +TRUE,vzip2_u32,"a: uint32x2_t, b: uint32x2_t",uint32x2_t,Zip vectors +TRUE,vzip2_u8,"a: uint8x8_t, b: uint8x8_t",uint8x8_t,Zip vectors +FALSE,vzip2q_f16,"a: float16x8_t, b: float16x8_t",float16x8_t,Zip vectors +TRUE,vzip2q_f32,"a: float32x4_t, b: float32x4_t",float32x4_t,Zip vectors +TRUE,vzip2q_f64,"a: float64x2_t, b: float64x2_t",float64x2_t,Zip vectors +TRUE,vzip2q_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8_t,Zip vectors +TRUE,vzip2q_p64,"a: poly64x2_t, b: poly64x2_t",poly64x2_t,Zip vectors +TRUE,vzip2q_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16_t,Zip vectors +TRUE,vzip2q_s16,"a: int16x8_t, b: int16x8_t",int16x8_t,Zip vectors +TRUE,vzip2q_s32,"a: int32x4_t, b: int32x4_t",int32x4_t,Zip vectors +TRUE,vzip2q_s64,"a: int64x2_t, b: int64x2_t",int64x2_t,Zip vectors +TRUE,vzip2q_s8,"a: int8x16_t, b: int8x16_t",int8x16_t,Zip vectors +TRUE,vzip2q_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8_t,Zip vectors +TRUE,vzip2q_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4_t,Zip vectors +TRUE,vzip2q_u64,"a: uint64x2_t, b: uint64x2_t",uint64x2_t,Zip vectors +TRUE,vzip2q_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16_t,Zip vectors +FALSE,vzipq_f16,"a: float16x8_t, b: float16x8_t",float16x8x2_t,Zip vectors +FALSE,vzipq_f32,"a: float32x4_t, b: float32x4_t",float32x4x2_t,Zip vectors +FALSE,vzipq_p16,"a: poly16x8_t, b: poly16x8_t",poly16x8x2_t,Zip vectors +FALSE,vzipq_p8,"a: poly8x16_t, b: poly8x16_t",poly8x16x2_t,Zip vectors +FALSE,vzipq_s16,"a: int16x8_t, b: int16x8_t",int16x8x2_t,Zip vectors +FALSE,vzipq_s32,"a: int32x4_t, b: int32x4_t",int32x4x2_t,Zip vectors +FALSE,vzipq_s8,"a: int8x16_t, b: int8x16_t",int8x16x2_t,Zip vectors +FALSE,vzipq_u16,"a: uint16x8_t, b: uint16x8_t",uint16x8x2_t,Zip vectors +FALSE,vzipq_u32,"a: uint32x4_t, b: uint32x4_t",uint32x4x2_t,Zip vectors +FALSE,vzipq_u8,"a: uint8x16_t, b: uint8x16_t",uint8x16x2_t,Zip vectors \ No newline at end of file diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/README.md rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/README.md --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/README.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/README.md 2021-11-29 19:27:28.000000000 +0000 @@ -0,0 +1,24 @@ +Generate and run programs using equivalent C and Rust intrinsics, checking that +each produces the same result from random inputs. + +# Usage +``` +USAGE: + intrinsic-test [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --cppcompiler The C++ compiler to use for compiling the c++ code [default: clang++] + --runner Run the C programs under emulation with this command + --toolchain The rust toolchain to use for building the rust code + +ARGS: + The input file containing the intrinsics +``` + +The intrinsic.csv is the arm neon tracking google sheet (https://docs.google.com/spreadsheets/d/1MqW1g8c7tlhdRWQixgdWvR4uJHNZzCYAf4V0oHjZkwA/edit#gid=0) +that contains the intrinsic list. The done percentage column should be renamed to "enabled". + diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/argument.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/argument.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/argument.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/argument.rs 2021-11-29 19:27:28.000000000 +0000 @@ -0,0 +1,137 @@ +use serde::{Deserialize, Deserializer}; + +use crate::types::IntrinsicType; +use crate::Language; + +/// An argument for the intrinsic. +#[derive(Debug, PartialEq, Clone)] +pub struct Argument { + /// The argument's index in the intrinsic function call. + pub pos: usize, + /// The argument name. + pub name: String, + /// The type of the argument. + pub ty: IntrinsicType, +} + +impl Argument { + /// Creates an argument from a Rust style signature i.e. `name: type` + fn from_rust(pos: usize, arg: &str) -> Result { + let mut parts = arg.split(':'); + let name = parts.next().unwrap().trim().to_string(); + let ty = IntrinsicType::from_rust(parts.next().unwrap().trim())?; + + Ok(Self { pos, name, ty }) + } + + fn to_c_type(&self) -> String { + self.ty.c_type() + } + + fn is_simd(&self) -> bool { + self.ty.is_simd() + } + + pub fn is_ptr(&self) -> bool { + self.ty.is_ptr() + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct ArgumentList { + pub args: Vec, +} + +impl ArgumentList { + /// Creates an argument list from a Rust function signature, the data for + /// this function should only be the arguments. + /// e.g. for `fn test(a: u32, b: u32) -> u32` data should just be `a: u32, b: u32` + fn from_rust_arguments(data: &str) -> Result { + let args = data + .split(',') + .enumerate() + .map(|(idx, arg)| Argument::from_rust(idx, arg)) + .collect::>()?; + + Ok(Self { args }) + } + + /// Converts the argument list into the call paramters for a C function call. + /// e.g. this would generate something like `a, &b, c` + pub fn as_call_param_c(&self) -> String { + self.args + .iter() + .map(|arg| match arg.ty { + IntrinsicType::Ptr { .. } => { + format!("&{}", arg.name) + } + IntrinsicType::Type { .. } => arg.name.clone(), + }) + .collect::>() + .join(", ") + } + + /// Converts the argument list into the call paramters for a Rust function. + /// e.g. this would generate something like `a, b, c` + pub fn as_call_param_rust(&self) -> String { + self.args + .iter() + .map(|arg| arg.name.clone()) + .collect::>() + .join(", ") + } + + /// Creates a line that initializes this argument for C code. + /// e.g. `int32x2_t a = { 0x1, 0x2 };` + pub fn init_random_values_c(&self, pass: usize) -> String { + self.iter() + .map(|arg| { + format!( + "{ty} {name} = {{ {values} }};", + ty = arg.to_c_type(), + name = arg.name, + values = arg.ty.populate_random(pass, &Language::C) + ) + }) + .collect::>() + .join("\n ") + } + + /// Creates a line that initializes this argument for Rust code. + /// e.g. `let a = transmute([0x1, 0x2]);` + pub fn init_random_values_rust(&self, pass: usize) -> String { + self.iter() + .map(|arg| { + if arg.is_simd() { + format!( + "let {name} = ::std::mem::transmute([{values}]);", + name = arg.name, + values = arg.ty.populate_random(pass, &Language::Rust), + ) + } else { + format!( + "let {name} = {value};", + name = arg.name, + value = arg.ty.populate_random(pass, &Language::Rust) + ) + } + }) + .collect::>() + .join("\n ") + } + + pub fn iter(&self) -> std::slice::Iter<'_, Argument> { + self.args.iter() + } +} + +impl<'de> Deserialize<'de> for ArgumentList { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + let s = String::deserialize(deserializer)?; + Self::from_rust_arguments(&s).map_err(Error::custom) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/intrinsic.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/intrinsic.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/intrinsic.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/intrinsic.rs 2021-11-29 19:27:28.000000000 +0000 @@ -0,0 +1,112 @@ +use crate::types::{IntrinsicType, TypeKind}; + +use super::argument::ArgumentList; +use serde::de::Unexpected; +use serde::{de, Deserialize, Deserializer}; + +/// An intrinsic +#[derive(Deserialize, Debug, PartialEq, Clone)] +pub struct Intrinsic { + /// If the intrinsic should be tested. + #[serde(deserialize_with = "bool_from_string")] + pub enabled: bool, + + /// The function name of this intrinsic. + pub name: String, + + /// Any arguments for this intrinsinc. + #[serde(rename = "args")] + pub arguments: ArgumentList, + + /// The return type of this intrinsic. + #[serde(rename = "return")] + pub results: IntrinsicType, +} + +impl Intrinsic { + /// Generates a std::cout for the intrinsics results that will match the + /// rust debug output format for the return type. + pub fn print_result_c(&self, index: usize) -> String { + let lanes = if self.results.num_lanes() > 1 { + (0..self.results.num_lanes()) + .map(|idx| -> std::string::String { + format!( + "{cast}{lane_fn}(__return_value, {lane})", + cast = self.results.c_promotion(), + lane_fn = self.results.get_lane_function(), + lane = idx + ) + }) + .collect::>() + .join(r#" << ", " << "#) + } else { + format!( + "{promote}cast<{cast}>(__return_value)", + cast = match self.results.kind() { + TypeKind::Float if self.results.inner_size() == 32 => "float".to_string(), + TypeKind::Float if self.results.inner_size() == 64 => "double".to_string(), + TypeKind::Int => format!("int{}_t", self.results.inner_size()), + TypeKind::UInt => format!("uint{}_t", self.results.inner_size()), + TypeKind::Poly => format!("poly{}_t", self.results.inner_size()), + ty => todo!("print_result_c - Unknown type: {:#?}", ty), + }, + promote = self.results.c_promotion(), + ) + }; + + format!( + r#"std::cout << "Result {idx}: {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#, + ty = if self.results.is_simd() { + format!("{}(", self.results.c_type()) + } else { + String::from("") + }, + close = if self.results.is_simd() { ")" } else { "" }, + lanes = lanes, + idx = index, + ) + } + + pub fn generate_pass_rust(&self, index: usize) -> String { + format!( + r#" + unsafe {{ + {initialized_args} + let res = {intrinsic_call}({args}); + println!("Result {idx}: {{:.150?}}", res); + }}"#, + initialized_args = self.arguments.init_random_values_rust(index), + intrinsic_call = self.name, + args = self.arguments.as_call_param_rust(), + idx = index, + ) + } + + pub fn generate_pass_c(&self, index: usize) -> String { + format!( + r#" {{ + {initialized_args} + auto __return_value = {intrinsic_call}({args}); + {print_result} + }}"#, + initialized_args = self.arguments.init_random_values_c(index), + intrinsic_call = self.name, + args = self.arguments.as_call_param_c(), + print_result = self.print_result_c(index) + ) + } +} + +fn bool_from_string<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + match String::deserialize(deserializer)?.to_uppercase().as_ref() { + "TRUE" => Ok(true), + "FALSE" => Ok(false), + other => Err(de::Error::invalid_value( + Unexpected::Str(other), + &"TRUE or FALSE", + )), + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/main.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/main.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/main.rs 2021-11-29 19:27:28.000000000 +0000 @@ -0,0 +1,400 @@ +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; + +use std::fs::File; +use std::io::Write; +use std::process::Command; + +use clap::{App, Arg}; +use intrinsic::Intrinsic; +use rayon::prelude::*; +use types::TypeKind; + +mod argument; +mod intrinsic; +mod types; +mod values; + +#[derive(Debug, PartialEq)] +pub enum Language { + Rust, + C, +} + +fn generate_c_program(header_files: &[&str], intrinsic: &Intrinsic) -> String { + format!( + r#"{header_files} +#include +#include +#include +#include +template T1 cast(T2 x) {{ + static_assert(sizeof(T1) == sizeof(T2), "sizeof T1 and T2 must be the same"); + T1 ret = 0; + memcpy(&ret, &x, sizeof(T1)); + return ret; +}} +std::ostream& operator<<(std::ostream& os, poly128_t value) {{ + std::stringstream temp; + do {{ + int n = value % 10; + value /= 10; + temp << n; + }} while (value != 0); + std::string tempstr(temp.str()); + std::string res(tempstr.rbegin(), tempstr.rend()); + os << res; + return os; +}} +int main(int argc, char **argv) {{ +{passes} + return 0; +}}"#, + header_files = header_files + .iter() + .map(|header| format!("#include <{}>", header)) + .collect::>() + .join("\n"), + passes = (1..20) + .map(|idx| intrinsic.generate_pass_c(idx)) + .collect::>() + .join("\n"), + ) +} + +fn generate_rust_program(intrinsic: &Intrinsic) -> String { + format!( + r#"#![feature(simd_ffi)] +#![feature(link_llvm_intrinsics)] +#![feature(stdsimd)] +#![allow(overflowing_literals)] +use core_arch::arch::aarch64::*; + +fn main() {{ +{passes} +}} +"#, + passes = (1..20) + .map(|idx| intrinsic.generate_pass_rust(idx)) + .collect::>() + .join("\n"), + ) +} + +fn compile_c(c_filename: &str, intrinsic: &Intrinsic, compiler: &str) -> bool { + let flags = std::env::var("CPPFLAGS").unwrap_or("".into()); + + let output = Command::new("sh") + .arg("-c") + .arg(format!( + "{cpp} {cppflags} {arch_flags} -Wno-narrowing -O2 -target {target} -o c_programs/{intrinsic} {filename}", + target = "aarch64-unknown-linux-gnu", + arch_flags = "-march=armv8-a+crypto+crc", + filename = c_filename, + intrinsic = intrinsic.name, + cpp = compiler, + cppflags = flags, + )) + .output(); + if let Ok(output) = output { + if output.status.success() { + true + } else { + let stderr = std::str::from_utf8(&output.stderr).unwrap_or(""); + if stderr.contains("error: use of undeclared identifier") { + warn!("Skipping intrinsic due to no support: {}", intrinsic.name); + true + } else { + error!( + "Failed to compile code for intrinsic: {}\n\nstdout:\n{}\n\nstderr:\n{}", + intrinsic.name, + std::str::from_utf8(&output.stdout).unwrap_or(""), + std::str::from_utf8(&output.stderr).unwrap_or("") + ); + false + } + } + } else { + error!("Command failed: {:#?}", output); + false + } +} + +fn build_c(intrinsics: &Vec, compiler: &str) -> bool { + let _ = std::fs::create_dir("c_programs"); + intrinsics + .par_iter() + .map(|i| { + let c_filename = format!(r#"c_programs/{}.cpp"#, i.name); + let mut file = File::create(&c_filename).unwrap(); + + let c_code = generate_c_program(&["arm_neon.h", "arm_acle.h"], &i); + file.write_all(c_code.into_bytes().as_slice()).unwrap(); + compile_c(&c_filename, &i, compiler) + }) + .find_any(|x| !x) + .is_none() +} + +fn build_rust(intrinsics: &Vec, toolchain: &str) -> bool { + intrinsics.iter().for_each(|i| { + let rust_dir = format!(r#"rust_programs/{}"#, i.name); + let _ = std::fs::create_dir_all(&rust_dir); + let rust_filename = format!(r#"{}/main.rs"#, rust_dir); + let mut file = File::create(&rust_filename).unwrap(); + + let c_code = generate_rust_program(&i); + file.write_all(c_code.into_bytes().as_slice()).unwrap(); + }); + + let mut cargo = File::create("rust_programs/Cargo.toml").unwrap(); + cargo + .write_all( + format!( + r#"[package] +name = "intrinsic-test" +version = "{version}" +authors = ["{authors}"] +edition = "2018" +[workspace] +[dependencies] +core_arch = {{ path = "../crates/core_arch" }} +{binaries}"#, + version = env!("CARGO_PKG_VERSION"), + authors = env!("CARGO_PKG_AUTHORS"), + binaries = intrinsics + .iter() + .map(|i| { + format!( + r#"[[bin]] +name = "{intrinsic}" +path = "{intrinsic}/main.rs""#, + intrinsic = i.name + ) + }) + .collect::>() + .join("\n") + ) + .into_bytes() + .as_slice(), + ) + .unwrap(); + + let output = Command::new("sh") + .current_dir("rust_programs") + .arg("-c") + .arg(format!( + "cargo {toolchain} build --release --target {target}", + toolchain = toolchain, + target = "aarch64-unknown-linux-gnu", + )) + .output(); + if let Ok(output) = output { + if output.status.success() { + true + } else { + error!( + "Failed to compile code for intrinsics\n\nstdout:\n{}\n\nstderr:\n{}", + std::str::from_utf8(&output.stdout).unwrap_or(""), + std::str::from_utf8(&output.stderr).unwrap_or("") + ); + false + } + } else { + error!("Command failed: {:#?}", output); + false + } +} + +fn main() { + pretty_env_logger::init(); + + let matches = App::new("Intrinsic test tool") + .about("Generates Rust and C programs for intrinsics and compares the output") + .arg( + Arg::with_name("INPUT") + .help("The input file containing the intrinsics") + .required(true) + .index(1), + ) + .arg( + Arg::with_name("TOOLCHAIN") + .takes_value(true) + .long("toolchain") + .help("The rust toolchain to use for building the rust code"), + ) + .arg( + Arg::with_name("CPPCOMPILER") + .takes_value(true) + .default_value("clang++") + .long("cppcompiler") + .help("The C++ compiler to use for compiling the c++ code"), + ) + .arg( + Arg::with_name("RUNNER") + .takes_value(true) + .long("runner") + .help("Run the C programs under emulation with this command"), + ) + .get_matches(); + + let filename = matches.value_of("INPUT").unwrap(); + let toolchain = matches + .value_of("TOOLCHAIN") + .map_or("".into(), |t| format!("+{}", t)); + + let cpp_compiler = matches.value_of("CPPCOMPILER").unwrap(); + let c_runner = matches.value_of("RUNNER").unwrap_or(""); + let mut csv_reader = csv::Reader::from_reader(std::fs::File::open(filename).unwrap()); + + let mut intrinsics = csv_reader + .deserialize() + .filter_map(|x| -> Option { + debug!("Processing {:#?}", x); + match x { + Ok(a) => Some(a), + e => { + error!("{:#?}", e); + None + } + } + }) + // Only perform the test for intrinsics that are enabled... + .filter(|i| i.enabled) + // Not sure how we would compare intrinsic that returns void. + .filter(|i| i.results.kind() != TypeKind::Void) + .filter(|i| i.results.kind() != TypeKind::BFloat) + .filter(|i| !(i.results.kind() == TypeKind::Float && i.results.inner_size() == 16)) + .filter(|i| { + i.arguments + .iter() + .find(|a| a.ty.kind() == TypeKind::BFloat) + .is_none() + }) + .filter(|i| { + i.arguments + .iter() + .find(|a| a.ty.kind() == TypeKind::Float && a.ty.inner_size() == 16) + .is_none() + }) + // Skip pointers for now, we would probably need to look at the return + // type to work out how many elements we need to point to. + .filter(|i| i.arguments.iter().find(|a| a.is_ptr()).is_none()) + // intrinsics with a lane parameter have constraints, deal with them later. + .filter(|i| { + i.arguments + .iter() + .find(|a| a.name.starts_with("lane")) + .is_none() + }) + .filter(|i| i.arguments.iter().find(|a| a.name == "n").is_none()) + // clang-12 fails to compile this intrinsic due to an error. + // fatal error: error in backend: Cannot select: 0x2b99c30: i64 = AArch64ISD::VSHL Constant:i64<1>, Constant:i32<1> + // 0x2b9a520: i64 = Constant<1> + // 0x2b9a248: i32 = Constant<1> + .filter(|i| !["vshld_s64", "vshld_u64"].contains(&i.name.as_str())) + .collect::>(); + intrinsics.dedup(); + + if !build_c(&intrinsics, cpp_compiler) { + std::process::exit(2); + } + + if !build_rust(&intrinsics, &toolchain) { + std::process::exit(3); + } + + if !compare_outputs(&intrinsics, &toolchain, &c_runner) { + std::process::exit(1) + } +} + +enum FailureReason { + RunC(String), + RunRust(String), + Difference(String, String, String), +} + +fn compare_outputs(intrinsics: &Vec, toolchain: &str, runner: &str) -> bool { + let intrinsics = intrinsics + .par_iter() + .filter_map(|intrinsic| { + let c = Command::new("sh") + .arg("-c") + .arg(format!( + "{runner} ./c_programs/{intrinsic}", + runner = runner, + intrinsic = intrinsic.name, + )) + .output(); + let rust = Command::new("sh") + .current_dir("rust_programs") + .arg("-c") + .arg(format!( + "cargo {toolchain} run --release --target {target} --bin {intrinsic}", + intrinsic = intrinsic.name, + toolchain = toolchain, + target = "aarch64-unknown-linux-gnu", + )) + .output(); + + let (c, rust) = match (c, rust) { + (Ok(c), Ok(rust)) => (c, rust), + a => panic!("{:#?}", a), + }; + + if !c.status.success() { + error!("Failed to run C program for intrinsic {}", intrinsic.name); + return Some(FailureReason::RunC(intrinsic.name.clone())); + } + + if !rust.status.success() { + error!( + "Failed to run rust program for intrinsic {}", + intrinsic.name + ); + return Some(FailureReason::RunRust(intrinsic.name.clone())); + } + + info!("Comparing intrinsic: {}", intrinsic.name); + + let c = std::str::from_utf8(&c.stdout) + .unwrap() + .to_lowercase() + .replace("-nan", "nan"); + let rust = std::str::from_utf8(&rust.stdout) + .unwrap() + .to_lowercase() + .replace("-nan", "nan"); + + if c == rust { + None + } else { + Some(FailureReason::Difference(intrinsic.name.clone(), c, rust)) + } + }) + .collect::>(); + + intrinsics.iter().for_each(|reason| match reason { + FailureReason::Difference(intrinsic, c, rust) => { + println!("Difference for intrinsic: {}", intrinsic); + let diff = diff::lines(c, rust); + diff.iter().for_each(|diff| match diff { + diff::Result::Left(c) => println!("C: {}", c), + diff::Result::Right(rust) => println!("Rust: {}", rust), + diff::Result::Both(_, _) => (), + }); + println!("****************************************************************"); + } + FailureReason::RunC(intrinsic) => { + println!("Failed to run C program for intrinsic {}", intrinsic) + } + FailureReason::RunRust(intrinsic) => { + println!("Failed to run rust program for intrinsic {}", intrinsic) + } + }); + println!("{} differences found", intrinsics.len()); + intrinsics.is_empty() +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/types.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/types.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/types.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/types.rs 2021-11-29 19:27:28.000000000 +0000 @@ -0,0 +1,483 @@ +use regex::Regex; +use serde::{Deserialize, Deserializer}; +use std::fmt; +use std::str::FromStr; + +use crate::values::values_for_pass; +use crate::Language; + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum TypeKind { + BFloat, + Float, + Int, + UInt, + Poly, + Void, +} + +impl FromStr for TypeKind { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "bfloat" => Ok(Self::BFloat), + "float" => Ok(Self::Float), + "int" => Ok(Self::Int), + "poly" => Ok(Self::Poly), + "uint" | "unsigned" => Ok(Self::UInt), + "void" => Ok(Self::Void), + _ => Err(format!("Impossible to parse argument kind {}", s)), + } + } +} + +impl fmt::Display for TypeKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::BFloat => "bfloat", + Self::Float => "float", + Self::Int => "int", + Self::UInt => "uint", + Self::Poly => "poly", + Self::Void => "void", + } + ) + } +} + +impl TypeKind { + /// Gets the type part of a c typedef for a type that's in the form of {type}{size}_t. + pub fn c_prefix(&self) -> &str { + match self { + Self::Float => "float", + Self::Int => "int", + Self::UInt => "uint", + Self::Poly => "poly", + _ => unreachable!("Not used: {:#?}", self), + } + } + + /// Gets the rust prefix for the type kind i.e. i, u, f. + pub fn rust_prefix(&self) -> &str { + match self { + Self::Float => "f", + Self::Int => "i", + Self::UInt => "u", + Self::Poly => "u", + _ => unreachable!("Unused type kind: {:#?}", self), + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum IntrinsicType { + Ptr { + constant: bool, + child: Box, + }, + Type { + constant: bool, + kind: TypeKind, + /// The bit length of this type (e.g. 32 for u32). + bit_len: Option, + + /// Length of the SIMD vector (i.e. 4 for uint32x4_t), A value of `None` + /// means this is not a simd type. A `None` can be assumed to be 1, + /// although in some places a distinction is needed between `u64` and + /// `uint64x1_t` this signals that. + simd_len: Option, + + /// The number of rows for SIMD matrices (i.e. 2 for uint8x8x2_t). + /// A value of `None` represents a type that does not contain any + /// rows encoded in the type (e.g. uint8x8_t). + /// A value of `None` can be assumed to be 1 though. + vec_len: Option, + }, +} + +impl IntrinsicType { + /// Get the TypeKind for this type, recursing into pointers. + pub fn kind(&self) -> TypeKind { + match *self { + IntrinsicType::Ptr { ref child, .. } => child.kind(), + IntrinsicType::Type { kind, .. } => kind, + } + } + + /// Get the size of a single element inside this type, recursing into + /// pointers, i.e. a pointer to a u16 would be 16 rather than the size + /// of a pointer. + pub fn inner_size(&self) -> u32 { + match *self { + IntrinsicType::Ptr { ref child, .. } => child.inner_size(), + IntrinsicType::Type { + bit_len: Some(bl), .. + } => bl, + _ => unreachable!(""), + } + } + + pub fn num_lanes(&self) -> u32 { + match *self { + IntrinsicType::Ptr { ref child, .. } => child.num_lanes(), + IntrinsicType::Type { + simd_len: Some(sl), .. + } => sl, + _ => 1, + } + } + + /// Determine if the type is a simd type, this will treat a type such as + /// `uint64x1` as simd. + pub fn is_simd(&self) -> bool { + match *self { + IntrinsicType::Ptr { ref child, .. } => child.is_simd(), + IntrinsicType::Type { + simd_len: None, + vec_len: None, + .. + } => false, + _ => true, + } + } + + pub fn is_ptr(&self) -> bool { + match *self { + IntrinsicType::Ptr { .. } => true, + IntrinsicType::Type { .. } => false, + } + } + + pub fn from_rust(ty: &str) -> Result { + lazy_static! { + static ref SIMD_TYPE: Regex = Regex::new(r#"([a-z]*)([0-9]*)x([0-9]*)_t"#).unwrap(); + static ref MULTI_SIMD_TYPE: Regex = + Regex::new(r#"([a-z]*)([0-9]*)x([0-9]*)x([0-9]*)_t"#).unwrap(); + static ref RUST_TYPE: Regex = Regex::new(r#"([iuf]|float|poly)([0-9]+)"#).unwrap(); + } + + debug!("Parsing type: {}", ty); + + if let Some(ty) = ty.strip_prefix('*') { + let (constant, ty) = if let Some(ty) = ty.strip_prefix("const") { + (true, ty.trim()) + } else if let Some(ty) = ty.strip_prefix("mut") { + (false, ty.trim()) + } else { + (false, ty) + }; + return Ok(Self::Ptr { + constant, + child: Box::new(Self::from_rust(ty)?), + }); + } + + let (constant, ty) = if let Some(ty) = ty.strip_prefix("const") { + (true, ty.trim()) + } else { + (false, ty) + }; + + if let Some(captures) = MULTI_SIMD_TYPE.captures(ty) { + let kind = captures + .get(1) + .map(|s| s.as_str().parse::().unwrap()) + .unwrap(); + let bit_len = captures.get(2).map(|s| s.as_str().parse::().unwrap()); + let simd_len = captures.get(3).map(|s| s.as_str().parse::().unwrap()); + let vec_len = captures.get(4).map(|s| s.as_str().parse::().unwrap()); + Ok(Self::Type { + constant, + kind, + bit_len, + simd_len, + vec_len, + }) + } else if let Some(captures) = SIMD_TYPE.captures(ty) { + let kind = captures + .get(1) + .map(|s| s.as_str().parse::().unwrap()) + .unwrap(); + let bit_len = captures.get(2).map(|s| s.as_str().parse::().unwrap()); + let simd_len = captures.get(3).map(|s| s.as_str().parse::().unwrap()); + + Ok(Self::Type { + constant, + kind, + bit_len, + simd_len, + vec_len: None, + }) + } else if let Some(captures) = RUST_TYPE.captures(ty) { + let kind = captures + .get(1) + .map(|s| match s.as_str() { + "i" => TypeKind::Int, + "u" => TypeKind::UInt, + "f" => TypeKind::Float, + "float" => TypeKind::Float, + "poly" => TypeKind::Poly, + a => panic!("Unexpected type: {} found", a), + }) + .unwrap(); + let bit_len = captures.get(2).map(|s| s.as_str().parse::().unwrap()); + Ok(Self::Type { + constant, + kind, + bit_len, + simd_len: None, + vec_len: None, + }) + } else { + match ty { + "int" => Ok(Self::Type { + constant, + kind: TypeKind::Int, + bit_len: Some(32), + simd_len: None, + vec_len: None, + }), + "void" => Ok(Self::Type { + constant: false, + kind: TypeKind::Void, + bit_len: None, + simd_len: None, + vec_len: None, + }), + _ => Err(format!("Failed to parse type: {}", ty)), + } + } + } + + #[allow(unused)] + fn c_scalar_type(&self) -> String { + format!( + "{prefix}{bits}_t", + prefix = self.kind().c_prefix(), + bits = self.inner_size() + ) + } + + fn rust_scalar_type(&self) -> String { + format!( + "{prefix}{bits}", + prefix = self.kind().rust_prefix(), + bits = self.inner_size() + ) + } + + /// Gets a string containing the typename for this type in C format. + pub fn c_type(&self) -> String { + match self { + IntrinsicType::Ptr { child, .. } => child.c_type(), + IntrinsicType::Type { + constant, + kind, + bit_len: Some(bit_len), + simd_len: None, + vec_len: None, + .. + } => format!( + "{}{}{}_t", + if *constant { "const " } else { "" }, + kind.c_prefix(), + bit_len + ), + IntrinsicType::Type { + kind, + bit_len: Some(bit_len), + simd_len: Some(simd_len), + vec_len: None, + .. + } => format!("{}{}x{}_t", kind.c_prefix(), bit_len, simd_len), + IntrinsicType::Type { + kind, + bit_len: Some(bit_len), + simd_len: Some(simd_len), + vec_len: Some(vec_len), + .. + } => format!("{}{}x{}x{}_t", kind.c_prefix(), bit_len, simd_len, vec_len), + _ => todo!("{:#?}", self), + } + } + + /// Gets a cast for this type if needs promotion. + /// This is required for 8 bit types due to printing as the 8 bit types use + /// a char and when using that in `std::cout` it will print as a character, + /// which means value of 0 will be printed as a null byte. + pub fn c_promotion(&self) -> &str { + match *self { + IntrinsicType::Type { + kind, + bit_len: Some(bit_len), + .. + } if bit_len == 8 => match kind { + TypeKind::Int => "(int)", + TypeKind::UInt => "(unsigned int)", + TypeKind::Poly => "(unsigned int)", + _ => "", + }, + _ => "", + } + } + + /// Generates a comma list of values that can be used to initialize an + /// argument for the intrinsic call. + /// This is determistic based on the pass number. + /// + /// * `pass`: The pass index, i.e. the iteration index for the call to an intrinsic + /// + /// Returns a string such as + /// * `0x1, 0x7F, 0xFF` if `language` is `Language::C` + /// * `0x1 as _, 0x7F as _, 0xFF as _` if `language` is `Language::Rust` + pub fn populate_random(&self, pass: usize, language: &Language) -> String { + match self { + IntrinsicType::Ptr { child, .. } => child.populate_random(pass, language), + IntrinsicType::Type { + bit_len: Some(bit_len), + kind, + simd_len, + vec_len, + .. + } if kind == &TypeKind::Int || kind == &TypeKind::UInt || kind == &TypeKind::Poly => (0 + ..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1))) + .map(|i| { + format!( + "{}{}", + values_for_pass(*bit_len, i, pass), + match language { + &Language::Rust => format!(" as {ty} ", ty = self.rust_scalar_type()), + &Language::C => String::from(""), + } + ) + }) + .collect::>() + .join(","), + IntrinsicType::Type { + kind: TypeKind::Float, + bit_len: Some(32), + simd_len, + vec_len, + .. + } => (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1))) + .map(|i| { + format!( + "{}({})", + match language { + &Language::Rust => "f32::from_bits", + &Language::C => "cast", + }, + values_for_pass(32, i, pass), + ) + }) + .collect::>() + .join(","), + IntrinsicType::Type { + kind: TypeKind::Float, + bit_len: Some(64), + simd_len, + vec_len, + .. + } => (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1))) + .map(|i| { + format!( + "{}({}{})", + match language { + &Language::Rust => "f64::from_bits", + &Language::C => "cast", + }, + values_for_pass(64, i, pass), + match language { + &Language::Rust => " as u64", + &Language::C => "", + } + ) + }) + .collect::>() + .join(","), + _ => unreachable!("populate random: {:#?}", self), + } + } + + /// Determines the load function for this type. + #[allow(unused)] + pub fn get_load_function(&self) -> String { + match self { + IntrinsicType::Ptr { child, .. } => child.get_load_function(), + IntrinsicType::Type { + kind: k, + bit_len: Some(bl), + simd_len, + vec_len, + .. + } => { + let quad = if (simd_len.unwrap_or(1) * bl) > 64 { + "q" + } else { + "" + }; + format!( + "vld{len}{quad}_{type}{size}", + type = match k { + TypeKind::UInt => "u", + TypeKind::Int => "s", + TypeKind::Float => "f", + TypeKind::Poly => "p", + x => todo!("get_load_function TypeKind: {:#?}", x), + }, + size = bl, + quad = quad, + len = vec_len.unwrap_or(1), + ) + } + _ => todo!("get_load_function IntrinsicType: {:#?}", self), + } + } + + /// Determines the get lane function for this type. + pub fn get_lane_function(&self) -> String { + match self { + IntrinsicType::Ptr { child, .. } => child.get_lane_function(), + IntrinsicType::Type { + kind: k, + bit_len: Some(bl), + simd_len, + .. + } => { + let quad = if (simd_len.unwrap_or(1) * bl) > 64 { + "q" + } else { + "" + }; + format!( + "vget{quad}_lane_{type}{size}", + type = match k { + TypeKind::UInt => "u", + TypeKind::Int => "s", + TypeKind::Float => "f", + TypeKind::Poly => "p", + x => todo!("get_load_function TypeKind: {:#?}", x), + }, + size = bl, + quad = quad, + ) + } + _ => todo!("get_lane_function IntrinsicType: {:#?}", self), + } + } +} + +impl<'de> Deserialize<'de> for IntrinsicType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + let s = String::deserialize(deserializer)?; + Self::from_rust(&s).map_err(Error::custom) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/values.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/values.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/values.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/intrinsic-test/src/values.rs 2021-11-29 19:27:28.000000000 +0000 @@ -0,0 +1,126 @@ +/// Gets a hex constant value for a single lane in in a determistic way +/// * `bits`: The number of bits for the type, only 8, 16, 32, 64 are valid values +/// * `simd`: The index of the simd lane we are generating for +/// * `pass`: The index of the pass we are generating the values for +pub fn values_for_pass(bits: u32, simd: u32, pass: usize) -> String { + let index = pass + (simd as usize); + + if bits == 8 { + format!("{:#X}", VALUES_8[index % VALUES_8.len()]) + } else if bits == 16 { + format!("{:#X}", VALUES_16[index % VALUES_16.len()]) + } else if bits == 32 { + format!("{:#X}", VALUES_32[index % VALUES_32.len()]) + } else if bits == 64 { + format!("{:#X}", VALUES_64[index % VALUES_64.len()]) + } else { + panic!("Unknown size: {}", bits); + } +} + +pub const VALUES_8: &[u8] = &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xf0, 0x80, 0x3b, 0xff, +]; + +pub const VALUES_16: &[u16] = &[ + 0x0000, // 0.0 + 0x0400, // The smallest normal value. + 0x37ff, // The value just below 0.5. + 0x3800, // 0.5 + 0x3801, // The value just above 0.5. + 0x3bff, // The value just below 1.0. + 0x3c00, // 1.0 + 0x3c01, // The value just above 1.0. + 0x3e00, // 1.5 + 0x4900, // 10 + 0x7bff, // The largest finite value. + 0x7c00, // Infinity. + // NaNs. + // - Quiet NaNs + 0x7f23, 0x7e00, // - Signalling NaNs + 0x7d23, 0x7c01, // Subnormals. + // - A recognisable bit pattern. + 0x0012, // - The largest subnormal value. + 0x03ff, // - The smallest subnormal value. + 0x0001, // The same values again, but negated. + 0x8000, 0x8400, 0xb7ff, 0xb800, 0xb801, 0xbbff, 0xbc00, 0xbc01, 0xbe00, 0xc900, 0xfbff, 0xfc00, + 0xff23, 0xfe00, 0xfd23, 0xfc01, 0x8012, 0x83ff, 0x8001, +]; + +pub const VALUES_32: &[u32] = &[ + // Simple values. + 0x00000000, // 0.0 + 0x00800000, // The smallest normal value. + 0x3effffff, // The value just below 0.5. + 0x3f000000, // 0.5 + 0x3f000001, // The value just above 0.5. + 0x3f7fffff, // The value just below 1.0. + 0x3f800000, // 1.0 + 0x3f800001, // The value just above 1.0. + 0x3fc00000, // 1.5 + 0x41200000, // 10 + 0x7f8fffff, // The largest finite value. + 0x7f800000, // Infinity. + // NaNs. + // - Quiet NaNs + 0x7fd23456, 0x7fc00000, // - Signalling NaNs + 0x7f923456, 0x7f800001, // Subnormals. + // - A recognisable bit pattern. + 0x00123456, // - The largest subnormal value. + 0x007fffff, // - The smallest subnormal value. + 0x00000001, // The same values again, but negated. + 0x80000000, 0x80800000, 0xbeffffff, 0xbf000000, 0xbf000001, 0xbf7fffff, 0xbf800000, 0xbf800001, + 0xbfc00000, 0xc1200000, 0xff8fffff, 0xff800000, 0xffd23456, 0xffc00000, 0xff923456, 0xff800001, + 0x80123456, 0x807fffff, 0x80000001, +]; + +pub const VALUES_64: &[u64] = &[ + // Simple values. + 0x0000000000000000, // 0.0 + 0x0010000000000000, // The smallest normal value. + 0x3fdfffffffffffff, // The value just below 0.5. + 0x3fe0000000000000, // 0.5 + 0x3fe0000000000001, // The value just above 0.5. + 0x3fefffffffffffff, // The value just below 1.0. + 0x3ff0000000000000, // 1.0 + 0x3ff0000000000001, // The value just above 1.0. + 0x3ff8000000000000, // 1.5 + 0x4024000000000000, // 10 + 0x7fefffffffffffff, // The largest finite value. + 0x7ff0000000000000, // Infinity. + // NaNs. + // - Quiet NaNs + 0x7ff923456789abcd, + 0x7ff8000000000000, + // - Signalling NaNs + 0x7ff123456789abcd, + 0x7ff0000000000000, + // Subnormals. + // - A recognisable bit pattern. + 0x000123456789abcd, + // - The largest subnormal value. + 0x000fffffffffffff, + // - The smallest subnormal value. + 0x0000000000000001, + // The same values again, but negated. + 0x8000000000000000, + 0x8010000000000000, + 0xbfdfffffffffffff, + 0xbfe0000000000000, + 0xbfe0000000000001, + 0xbfefffffffffffff, + 0xbff0000000000000, + 0xbff0000000000001, + 0xbff8000000000000, + 0xc024000000000000, + 0xffefffffffffffff, + 0xfff0000000000000, + 0xfff923456789abcd, + 0xfff8000000000000, + 0xfff123456789abcd, + 0xfff0000000000000, + 0x800123456789abcd, + 0x800fffffffffffff, + 0x8000000000000001, +]; diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-gen/neon.spec rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-gen/neon.spec --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-gen/neon.spec 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-gen/neon.spec 2021-11-29 19:27:28.000000000 +0000 @@ -955,6 +955,7 @@ a = 1, 2, 3, 4 n = 2 validate 0.25, 0.5, 0.75, 1. +arm-aarch64-separate aarch64 = scvtf link-aarch64 = vcvtfxs2fp._EXT2_._EXT_ @@ -971,6 +972,7 @@ arm = vcvt link-arm = vcvtfxs2fp._EXT2_._EXT_ const-arm = N:i32 + generate int32x2_t:float32x2_t, int32x4_t:float32x4_t aarch64 = ucvtf @@ -988,6 +990,7 @@ a = 0.25, 0.5, 0.75, 1. n = 2 validate 1, 2, 3, 4 +arm-aarch64-separate aarch64 = fcvtzs link-aarch64 = vcvtfp2fxs._EXT2_._EXT_ @@ -2033,6 +2036,320 @@ link-aarch64 = sqadd._EXT_ generate i32, i64 +/// Load multiple single-element structures to one, two, three, or four registers +name = vld1 +out-suffix +a = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +validate 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +load_fn + +aarch64 = ld1 +link-aarch64 = ld1x2._EXT2_ +arm = vld1 +link-arm = vld1x2._EXT2_ +generate *const i8:int8x8x2_t, *const i16:int16x4x2_t, *const i32:int32x2x2_t, *const i64:int64x1x2_t +generate *const i8:int8x16x2_t, *const i16:int16x8x2_t, *const i32:int32x4x2_t, *const i64:int64x2x2_t + +link-aarch64 = ld1x3._EXT2_ +link-arm = vld1x3._EXT2_ +generate *const i8:int8x8x3_t, *const i16:int16x4x3_t, *const i32:int32x2x3_t, *const i64:int64x1x3_t +generate *const i8:int8x16x3_t, *const i16:int16x8x3_t, *const i32:int32x4x3_t, *const i64:int64x2x3_t + +link-aarch64 = ld1x4._EXT2_ +link-arm = vld1x4._EXT2_ +generate *const i8:int8x8x4_t, *const i16:int16x4x4_t, *const i32:int32x2x4_t, *const i64:int64x1x4_t +generate *const i8:int8x16x4_t, *const i16:int16x8x4_t, *const i32:int32x4x4_t, *const i64:int64x2x4_t + +/// Load multiple single-element structures to one, two, three, or four registers +name = vld1 +out-suffix +multi_fn = transmute, {vld1-outsigned-noext, transmute(a)} +a = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +validate 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 + +load_fn +aarch64 = ld1 +arm = vld1 +generate *const u8:uint8x8x2_t, *const u16:uint16x4x2_t, *const u32:uint32x2x2_t, *const u64:uint64x1x2_t +generate *const u8:uint8x16x2_t, *const u16:uint16x8x2_t, *const u32:uint32x4x2_t, *const u64:uint64x2x2_t +generate *const u8:uint8x8x3_t, *const u16:uint16x4x3_t, *const u32:uint32x2x3_t, *const u64:uint64x1x3_t +generate *const u8:uint8x16x3_t, *const u16:uint16x8x3_t, *const u32:uint32x4x3_t, *const u64:uint64x2x3_t +generate *const u8:uint8x8x4_t, *const u16:uint16x4x4_t, *const u32:uint32x2x4_t, *const u64:uint64x1x4_t +generate *const u8:uint8x16x4_t, *const u16:uint16x8x4_t, *const u32:uint32x4x4_t, *const u64:uint64x2x4_t +generate *const p8:poly8x8x2_t, *const p8:poly8x8x3_t, *const p8:poly8x8x4_t +generate *const p8:poly8x16x2_t, *const p8:poly8x16x3_t, *const p8:poly8x16x4_t +generate *const p16:poly16x4x2_t, *const p16:poly16x4x3_t, *const p16:poly16x4x4_t +generate *const p16:poly16x8x2_t, *const p16:poly16x8x3_t, *const p16:poly16x8x4_t +target = aes +generate *const p64:poly64x1x2_t +arm = ldr +generate *const p64:poly64x1x3_t, *const p64:poly64x1x4_t +generate *const p64:poly64x2x2_t, *const p64:poly64x2x3_t, *const p64:poly64x2x4_t + +/// Load multiple single-element structures to one, two, three, or four registers +name = vld1 +out-suffix +a = 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16. +validate 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16. +load_fn + +aarch64 = ld1 +link-aarch64 = ld1x2._EXT2_ +generate *const f64:float64x1x2_t, *const f64:float64x2x2_t + +link-aarch64 = ld1x3._EXT2_ +generate *const f64:float64x1x3_t, *const f64:float64x2x3_t + +link-aarch64 = ld1x4._EXT2_ +generate *const f64:float64x1x4_t, *const f64:float64x2x4_t + +arm = vld1 +link-aarch64 = ld1x2._EXT2_ +link-arm = vld1x2._EXT2_ +generate *const f32:float32x2x2_t, *const f32:float32x4x2_t + +link-aarch64 = ld1x3._EXT2_ +link-arm = vld1x3._EXT2_ +generate *const f32:float32x2x3_t, *const f32:float32x4x3_t + +link-aarch64 = ld1x4._EXT2_ +link-arm = vld1x4._EXT2_ +generate *const f32:float32x2x4_t, *const f32:float32x4x4_t + +/// Load multiple 2-element structures to two registers +name = vld2 +out-nox +a = 0, 1, 2, 2, 3, 2, 4, 3, 5, 2, 6, 3, 7, 4, 8, 5, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16, 9, 17 +validate 1, 2, 2, 3, 2, 3, 4, 5, 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 +load_fn + +aarch64 = ld2 +link-aarch64 = ld2._EXTv2_ +arm = vld2 +link-arm = vld2._EXTpi82_ +//generate *const i8:int8x8x2_t, *const i16:int16x4x2_t, *const i32:int32x2x2_t, *const i64:int64x1x2_t +//generate *const i8:int8x16x2_t, *const i16:int16x8x2_t, *const i32:int32x4x2_t, *const i64:int64x2x2_t + +/// Load multiple 2-element structures to two registers +name = vld2 +out-nox +multi_fn = transmute, {vld2-outsignednox-noext, transmute(a)} +a = 0, 1, 2, 2, 3, 2, 4, 3, 5, 2, 6, 3, 7, 4, 8, 5, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16, 9, 17 +validate 1, 2, 2, 3, 2, 3, 4, 5, 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 +load_fn + +aarch64 = ld2 +arm = vld2 +//generate *const u8:uint8x8x2_t, *const u16:uint16x4x2_t, *const u32:uint32x2x2_t, *const u64:uint64x1x2_t +//generate *const u8:uint8x16x2_t, *const u16:uint16x8x2_t, *const u32:uint32x4x2_t, *const u64:uint64x2x2_t +//generate *const p8:poly8x8x2_t, *const p16:poly16x4x2_t, *const p8:poly8x16x2_t, *const p16:poly16x8x2_t + +/// Load multiple 2-element structures to two registers +name = vld2 +out-nox +a = 0., 1., 2., 2., 3., 2., 4., 3., 5., 2., 6., 3., 7., 4., 8., 5., 9. +validate 1., 2., 2., 3., 2., 3., 4., 5., 2., 3., 4., 5., 6., 7., 8., 9. +load_fn + +aarch64 = ld2 +link-aarch64 = ld2._EXTv2_ +//generate *const f64:float64x1x2_t, *const f64:float64x2x2_t + +arm = vld2 +link-arm = vld2._EXTpi82_ +//generate *const f32:float32x2x2_t, *const f32:float32x4x2_t + +/// Load single 2-element structure and replicate to all lanes of two registers +name = vld2 +out-dup-nox +a = 0, 1, 1, 2, 3, 1, 4, 3, 5, 1, 6, 3, 7, 4, 8, 5, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16, 9, 17 +validate 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +load_fn + +arm = vld2dup +link-arm = vld2dup._EXTpi82_ +aarch64 = ld2r +link-aarch64 = ld2r._EXT2_ +//generate *const i8:int8x8x2_t, *const i16:int16x4x2_t, *const i32:int32x2x2_t, *const i64:int64x1x2_t +//generate *const i8:int8x16x2_t, *const i16:int16x8x2_t, *const i32:int32x4x2_t, *const i64:int64x2x2_t + +/// Load single 2-element structure and replicate to all lanes of two registers +name = vld2 +out-dup-nox +multi_fn = transmute, {vld2-outsigneddupnox-noext, transmute(a)} +a = 0, 1, 1, 2, 3, 1, 4, 3, 5, 1, 6, 3, 7, 4, 8, 5, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16, 9, 17 +validate 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +load_fn + +arm = vld2dup +aarch64 = ld2r +//generate *const u8:uint8x8x2_t, *const u16:uint16x4x2_t, *const u32:uint32x2x2_t, *const u64:uint64x1x2_t +//generate *const u8:uint8x16x2_t, *const u16:uint16x8x2_t, *const u32:uint32x4x2_t, *const u64:uint64x2x2_t +//generate *const p8:poly8x8x2_t, *const p16:poly16x4x2_t, *const p8:poly8x16x2_t, *const p16:poly16x8x2_t + +/// Load single 2-element structure and replicate to all lanes of two registers +name = vld2 +out-dup-nox +a = 0., 1., 1., 2., 3., 1., 4., 3., 5. +validate 1., 1., 1., 1., 1., 1., 1., 1. +load_fn + +aarch64 = ld2r +link-aarch64 = ld2r._EXT2_ +//generate *const f64:float64x1x2_t, *const f64:float64x2x2_t + +arm = vld2dup +link-arm = vld2dup._EXTpi82_ +//generate *const f32:float32x2x2_t, *const f32:float32x4x2_t + +/// Load multiple 2-element structures to two registers +name = vld2 +out-lane-nox +multi_fn = static_assert_imm-in_exp_len-LANE +constn = LANE +a = 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 +b = 0, 2, 2, 14, 2, 16, 17, 18, 2, 20, 21, 22, 23, 24, 25, 26, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 +n = 0 +validate 1, 2, 2, 14, 2, 16, 17, 18, 2, 20, 21, 22, 23, 24, 25, 26, 2, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 +load_fn +arm-aarch64-separate + +aarch64 = ld2lane +const-aarch64 = LANE +link-aarch64 = ld2lane._EXTpi82_ +//generate *const i64:int64x1x2_t:int64x1x2_t, *const i64:int64x2x2_t:int64x2x2_t + +arm = vld2lane +const-arm = LANE +link-arm = vld2lane._EXTpi82_ +//generate *const i8:int8x8x2_t:int8x8x2_t, *const i16:int16x4x2_t:int16x4x2_t, *const i32:int32x2x2_t:int32x2x2_t +//generate *const i8:int8x16x2_t:int8x16x2_t, *const i16:int16x8x2_t:int16x8x2_t, *const i32:int32x4x2_t:int32x4x2_t + +/// Load multiple 2-element structures to two registers +name = vld2 +out-lane-nox +multi_fn = static_assert_imm-in_exp_len-LANE +multi_fn = transmute, {vld2-outsignedlanenox-::, transmute(a), transmute(b)} +constn = LANE +a = 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 +b = 0, 2, 2, 14, 2, 16, 17, 18, 2, 20, 21, 22, 23, 24, 25, 26, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 +n = 0 +validate 1, 2, 2, 14, 2, 16, 17, 18, 2, 20, 21, 22, 23, 24, 25, 26, 2, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 +load_fn +arm-aarch64-separate + +aarch64 = ld2lane +const-aarch64 = LANE + +target = aes +//generate *const p64:poly64x1x2_t:poly64x1x2_t, *const p64:poly64x2x2_t:poly64x2x2_t + +target = default +//generate *const u64:uint64x1x2_t:uint64x1x2_t, *const u64:uint64x2x2_t:uint64x2x2_t + +arm = vld2lane +const-arm = LANE +//generate *const u8:uint8x8x2_t:uint8x8x2_t, *const u16:uint16x4x2_t:uint16x4x2_t, *const u32:uint32x2x2_t:uint32x2x2_t +//generate *const u8:uint8x16x2_t:uint8x16x2_t, *const u16:uint16x8x2_t:uint16x8x2_t, *const u32:uint32x4x2_t:uint32x4x2_t +//generate *const p8:poly8x8x2_t:poly8x8x2_t, *const p16:poly16x4x2_t:poly16x4x2_t +//generate *const p8:poly8x16x2_t:poly8x16x2_t, *const p16:poly16x8x2_t:poly16x8x2_t + +/// Load multiple 2-element structures to two registers +name = vld2 +out-lane-nox +multi_fn = static_assert_imm-in_exp_len-LANE +constn = LANE +a = 0., 1., 2., 3., 4., 5., 6., 7., 8. +b = 0., 2., 2., 14., 2., 16., 17., 18. +n = 0 +validate 1., 2., 2., 14., 2., 16., 17., 18. +load_fn +arm-aarch64-separate + +aarch64 = ld2lane +const-aarch64 = LANE +link-aarch64 = ld2lane._EXTpi82_ +//generate *const f64:float64x1x2_t:float64x1x2_t, *const f64:float64x2x2_t:float64x2x2_t + +arm = vld2lane +const-arm = LANE +link-arm = vld2lane._EXTpi82_ +//generate *const f32:float32x2x2_t:float32x2x2_t, *const f32:float32x4x2_t:float32x4x2_t + +/// Store multiple single-element structures from one, two, three, or four registers +name = vst1 +a = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +validate 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +store_fn +arm-aarch64-separate + +aarch64 = st1 +link-aarch64 = st1x2._EXT3_ +arm = vst1 +link-arm = vst1x2._EXTr3_ +generate *mut i8:int8x8x2_t:void, *mut i16:int16x4x2_t:void, *mut i32:int32x2x2_t:void, *mut i64:int64x1x2_t:void +generate *mut i8:int8x16x2_t:void, *mut i16:int16x8x2_t:void, *mut i32:int32x4x2_t:void, *mut i64:int64x2x2_t:void + +link-aarch64 = st1x3._EXT3_ +link-arm = vst1x3._EXTr3_ +generate *mut i8:int8x8x3_t:void, *mut i16:int16x4x3_t:void, *mut i32:int32x2x3_t:void, *mut i64:int64x1x3_t:void +generate *mut i8:int8x16x3_t:void, *mut i16:int16x8x3_t:void, *mut i32:int32x4x3_t:void, *mut i64:int64x2x3_t:void + +link-aarch64 = st1x4._EXT3_ +link-arm = vst1x4._EXTr3_ +generate *mut i8:int8x8x4_t:void, *mut i16:int16x4x4_t:void, *mut i32:int32x2x4_t:void, *mut i64:int64x1x4_t:void +generate *mut i8:int8x16x4_t:void, *mut i16:int16x8x4_t:void, *mut i32:int32x4x4_t:void, *mut i64:int64x2x4_t:void + +/// Store multiple single-element structures to one, two, three, or four registers +name = vst1 +multi_fn = vst1-signed-noext, transmute(a), transmute(b) +a = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +validate 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 + +store_fn +aarch64 = st1 +arm = vst1 +generate *mut u8:uint8x8x2_t:void, *mut u16:uint16x4x2_t:void, *mut u32:uint32x2x2_t:void, *mut u64:uint64x1x2_t:void +generate *mut u8:uint8x16x2_t:void, *mut u16:uint16x8x2_t:void, *mut u32:uint32x4x2_t:void, *mut u64:uint64x2x2_t:void +generate *mut u8:uint8x8x3_t:void, *mut u16:uint16x4x3_t:void, *mut u32:uint32x2x3_t:void, *mut u64:uint64x1x3_t:void +generate *mut u8:uint8x16x3_t:void, *mut u16:uint16x8x3_t:void, *mut u32:uint32x4x3_t:void, *mut u64:uint64x2x3_t:void +generate *mut u8:uint8x8x4_t:void, *mut u16:uint16x4x4_t:void, *mut u32:uint32x2x4_t:void, *mut u64:uint64x1x4_t:void +generate *mut u8:uint8x16x4_t:void, *mut u16:uint16x8x4_t:void, *mut u32:uint32x4x4_t:void, *mut u64:uint64x2x4_t:void +generate *mut p8:poly8x8x2_t:void, *mut p8:poly8x8x3_t:void, *mut p8:poly8x8x4_t:void +generate *mut p8:poly8x16x2_t:void, *mut p8:poly8x16x3_t:void, *mut p8:poly8x16x4_t:void +generate *mut p16:poly16x4x2_t:void, *mut p16:poly16x4x3_t:void, *mut p16:poly16x4x4_t:void +generate *mut p16:poly16x8x2_t:void, *mut p16:poly16x8x3_t:void, *mut p16:poly16x8x4_t:void + +/// Store multiple single-element structures to one, two, three, or four registers +name = vst1 +a = 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16. +validate 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16. +store_fn +arm-aarch64-separate + +aarch64 = st1 +link-aarch64 = st1x2._EXT3_ +generate *mut f64:float64x1x2_t:void, *mut f64:float64x2x2_t:void + +link-aarch64 = st1x3._EXT3_ +generate *mut f64:float64x1x3_t:void, *mut f64:float64x2x3_t:void + +link-aarch64 = st1x4._EXT3_ +generate *mut f64:float64x1x4_t:void, *mut f64:float64x2x4_t:void + +arm = vst1 +link-aarch64 = st1x2._EXT3_ +link-arm = vst1x2._EXTr3_ +generate *mut f32:float32x2x2_t:void, *mut f32:float32x4x2_t:void + +link-aarch64 = st1x3._EXT3_ +link-arm = vst1x3._EXTr3_ +generate *mut f32:float32x2x3_t:void, *mut f32:float32x4x3_t:void + +link-aarch64 = st1x4._EXT3_ +link-arm = vst1x4._EXTr3_ +generate *mut f32:float32x2x4_t:void, *mut f32:float32x4x4_t:void + /// Multiply name = vmul a = 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 @@ -2277,8 +2594,8 @@ generate poly64x2_t:poly64x2_t:p128 /// Vector long multiply with scalar -name = vmull -n-suffix +name = vmull_n +no-q multi_fn = vmull-in0-noext, a, {vdup-nin0-noext, b} a = 1, 2, 3, 4, 5, 6, 7, 8 b = 2 @@ -2416,7 +2733,7 @@ aarch64 = fmla generate float64x2_t -target = fp-armv8 +target = vfp4 arm = vfma link-arm = llvm.fma._EXT_ generate float*_t @@ -2424,7 +2741,7 @@ /// Floating-point fused Multiply-Add to accumulator(vector) name = vfma n-suffix -multi_fn = vfma-self-noext, a, b, {vdup-nself-noext, c} +multi_fn = vfma-self-noext, a, b, {vdup-nselfvfp4-noext, c} a = 2.0, 3.0, 4.0, 5.0 b = 6.0, 4.0, 7.0, 8.0 c = 8.0 @@ -2435,7 +2752,7 @@ aarch64 = fmla generate float64x2_t:float64x2_t:f64:float64x2_t -target = fp-armv8 +target = vfp4 arm = vfma generate float32x2_t:float32x2_t:f32:float32x2_t, float32x4_t:float32x4_t:f32:float32x4_t @@ -2494,14 +2811,14 @@ aarch64 = fmls generate float64x2_t -target = fp-armv8 +target = vfp4 arm = vfms generate float*_t /// Floating-point fused Multiply-subtract to accumulator(vector) name = vfms n-suffix -multi_fn = vfms-self-noext, a, b, {vdup-nself-noext, c} +multi_fn = vfms-self-noext, a, b, {vdup-nselfvfp4-noext, c} a = 50.0, 35.0, 60.0, 69.0 b = 6.0, 4.0, 7.0, 8.0 c = 8.0 @@ -2512,7 +2829,7 @@ aarch64 = fmls generate float64x2_t:float64x2_t:f64:float64x2_t -target = fp-armv8 +target = vfp4 arm = vfms generate float32x2_t:float32x2_t:f32:float32x2_t, float32x4_t:float32x4_t:f32:float32x4_t @@ -3416,7 +3733,7 @@ /// Vector saturating doubling multiply high with scalar name = vqdmulhq_n -out-suffix +no-q multi_fn = vdupq_n-in_ntt-noext, b:out_t, b multi_fn = vqdmulh-out-noext, a, b a = MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX @@ -3794,6 +4111,7 @@ arm = vqrshrn link-arm = vqrshiftns._EXT2_ const-arm = -N as ttn +arm-aarch64-separate generate int16x8_t:int8x8_t, int32x4_t:int16x4_t, int64x2_t:int32x2_t /// Signed saturating rounded shift right narrow @@ -3840,6 +4158,7 @@ arm = vqrshrn link-arm = vqrshiftnu._EXT2_ const-arm = -N as ttn +arm-aarch64-separate generate uint16x8_t:uint8x8_t, uint32x4_t:uint16x4_t, uint64x2_t:uint32x2_t /// Unsigned saturating rounded shift right narrow @@ -3886,6 +4205,7 @@ arm = vqrshrun link-arm = vqrshiftnsu._EXT2_ const-arm = -N as ttn +arm-aarch64-separate generate int16x8_t:uint8x8_t, int32x4_t:uint16x4_t, int64x2_t:uint32x2_t /// Signed saturating rounded shift right unsigned narrow @@ -4031,6 +4351,7 @@ a = 0, 4, 8, 12, 16, 20, 24, 28 n = 2 validate 0, 1, 2, 3, 4, 5, 6, 7 +arm-aarch64-separate aarch64 = sqshrn link-aarch64 = sqshrn._EXT2_ @@ -4077,6 +4398,7 @@ a = 0, 4, 8, 12, 16, 20, 24, 28 n = 2 validate 0, 1, 2, 3, 4, 5, 6, 7 +arm-aarch64-separate aarch64 = uqshrn link-aarch64 = uqshrn._EXT2_ @@ -4123,6 +4445,7 @@ a = 0, 4, 8, 12, 16, 20, 24, 28 n = 2 validate 0, 1, 2, 3, 4, 5, 6, 7 +arm-aarch64-separate aarch64 = sqshrun link-aarch64 = sqshrun._EXT2_ @@ -4202,11 +4525,11 @@ a = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 validate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 -aarch64 = str +aarch64 = nop generate poly64x1_t:int64x1_t, poly64x1_t:uint64x1_t, int64x1_t:poly64x1_t, uint64x1_t:poly64x1_t generate poly64x2_t:int64x2_t, poly64x2_t:uint64x2_t, int64x2_t:poly64x2_t, uint64x2_t:poly64x2_t -arm = str +arm = nop generate uint8x8_t:int8x8_t, poly8x8_t:int8x8_t, poly16x4_t:int16x4_t, uint16x4_t:int16x4_t, uint32x2_t:int32x2_t, uint64x1_t:int64x1_t generate uint8x16_t:int8x16_t, poly8x16_t:int8x16_t, poly16x8_t:int16x8_t, uint16x8_t:int16x8_t, uint32x4_t:int32x4_t, uint64x2_t:int64x2_t generate poly8x8_t:uint8x8_t, int8x8_t:uint8x8_t, poly16x4_t:uint16x4_t, int16x4_t:uint16x4_t, int32x2_t:uint32x2_t, int64x1_t:uint64x1_t @@ -4221,11 +4544,11 @@ a = 0, 1, 2, 3, 4, 5, 6, 7 validate 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0 -aarch64 = str +aarch64 = nop generate poly64x1_t:int32x2_t, poly64x1_t:uint32x2_t generate poly64x2_t:int32x4_t, poly64x2_t:uint32x4_t -arm = str +arm = nop generate int16x4_t:int8x8_t, uint16x4_t:int8x8_t, poly16x4_t:int8x8_t, int32x2_t:int16x4_t, uint32x2_t:int16x4_t, int64x1_t:int32x2_t, uint64x1_t:int32x2_t generate int16x8_t:int8x16_t, uint16x8_t:int8x16_t, poly16x8_t:int8x16_t, int32x4_t:int16x8_t, uint32x4_t:int16x8_t, int64x2_t:int32x4_t, uint64x2_t:int32x4_t generate poly16x4_t:uint8x8_t, int16x4_t:uint8x8_t, uint16x4_t:uint8x8_t, int32x2_t:uint16x4_t, uint32x2_t:uint16x4_t, int64x1_t:uint32x2_t, uint64x1_t:uint32x2_t @@ -4240,11 +4563,11 @@ a = 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0 validate 0, 1, 2, 3, 4, 5, 6, 7 -aarch64 = str +aarch64 = nop generate int32x2_t:poly64x1_t, uint32x2_t:poly64x1_t generate int32x4_t:poly64x2_t, uint32x4_t:poly64x2_t -arm = str +arm = nop generate poly8x8_t:int16x4_t, int8x8_t:int16x4_t, uint8x8_t:int16x4_t, poly16x4_t:int32x2_t, int16x4_t:int32x2_t, uint16x4_t:int32x2_t, int32x2_t:int64x1_t, uint32x2_t:int64x1_t generate poly8x16_t:int16x8_t, int8x16_t:int16x8_t, uint8x16_t:int16x8_t, poly16x8_t:int32x4_t, int16x8_t:int32x4_t, uint16x8_t:int32x4_t, int32x4_t:int64x2_t, uint32x4_t:int64x2_t generate poly8x8_t:uint16x4_t, int8x8_t:uint16x4_t, uint8x8_t:uint16x4_t, poly16x4_t:uint32x2_t, int16x4_t:uint32x2_t, uint16x4_t:uint32x2_t, int32x2_t:uint64x1_t, uint32x2_t:uint64x1_t @@ -4259,11 +4582,11 @@ a = 0, 1, 2, 3 validate 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0 -aarch64 = str +aarch64 = nop generate poly64x1_t:int16x4_t, poly64x1_t:uint16x4_t, poly64x1_t:poly16x4_t generate poly64x2_t:int16x8_t, poly64x2_t:uint16x8_t, poly64x2_t:poly16x8_t -arm = str +arm = nop generate int32x2_t:int8x8_t, uint32x2_t:int8x8_t, int64x1_t:int16x4_t, uint64x1_t:int16x4_t generate int32x4_t:int8x16_t, uint32x4_t:int8x16_t, int64x2_t:int16x8_t, uint64x2_t:int16x8_t generate int32x2_t:uint8x8_t, uint32x2_t:uint8x8_t, int64x1_t:uint16x4_t, uint64x1_t:uint16x4_t @@ -4278,11 +4601,11 @@ a = 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0 validate 0, 1, 2, 3 -aarch64 = str +aarch64 = nop generate poly16x4_t:poly64x1_t, int16x4_t:poly64x1_t, uint16x4_t:poly64x1_t generate poly16x8_t:poly64x2_t, int16x8_t:poly64x2_t, uint16x8_t:poly64x2_t -arm = str +arm = nop generate poly8x8_t:int32x2_t, int8x8_t:int32x2_t, uint8x8_t:int32x2_t, poly16x4_t:int64x1_t, int16x4_t:int64x1_t, uint16x4_t:int64x1_t generate poly8x16_t:int32x4_t, int8x16_t:int32x4_t, uint8x16_t:int32x4_t, poly16x8_t:int64x2_t, int16x8_t:int64x2_t, uint16x8_t:int64x2_t generate poly8x8_t:uint32x2_t, int8x8_t:uint32x2_t, uint8x8_t:uint32x2_t, poly16x4_t:uint64x1_t, int16x4_t:uint64x1_t, uint16x4_t:uint64x1_t @@ -4295,11 +4618,11 @@ a = 0, 1 validate 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 -aarch64 = str +aarch64 = nop generate poly64x1_t:int8x8_t, poly64x1_t:uint8x8_t, poly64x1_t:poly8x8_t generate poly64x2_t:int8x16_t, poly64x2_t:uint8x16_t, poly64x2_t:poly8x16_t -arm = str +arm = nop generate int64x1_t:int8x8_t, uint64x1_t:int8x8_t, int64x1_t:uint8x8_t, uint64x1_t:uint8x8_t, int64x1_t:poly8x8_t, uint64x1_t:poly8x8_t generate int64x2_t:int8x16_t, uint64x2_t:int8x16_t, int64x2_t:uint8x16_t, uint64x2_t:uint8x16_t, int64x2_t:poly8x16_t, uint64x2_t:poly8x16_t @@ -4310,11 +4633,11 @@ a = 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 validate 0, 1 -aarch64 = str +aarch64 = nop generate poly8x8_t:poly64x1_t, int8x8_t:poly64x1_t, uint8x8_t:poly64x1_t generate poly8x16_t:poly64x2_t, int8x16_t:poly64x2_t, uint8x16_t:poly64x2_t -arm = str +arm = nop generate poly8x8_t:int64x1_t, int8x8_t:int64x1_t, uint8x8_t:int64x1_t, poly8x8_t:uint64x1_t, int8x8_t:uint64x1_t, uint8x8_t:uint64x1_t generate poly8x16_t:int64x2_t, int8x16_t:int64x2_t, uint8x16_t:int64x2_t, poly8x16_t:uint64x2_t, int8x16_t:uint64x2_t, uint8x16_t:uint64x2_t @@ -4325,7 +4648,7 @@ a = 0., 0., 0., 0., 0., 0., 0., 0. validate 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -aarch64 = str +aarch64 = nop generate float64x1_t:int8x8_t, float64x1_t:int16x4_t, float64x1_t:int32x2_t, float64x1_t:int64x1_t generate float64x2_t:int8x16_t, float64x2_t:int16x8_t, float64x2_t:int32x4_t, float64x2_t:int64x2_t generate float64x1_t:uint8x8_t, float64x1_t:uint16x4_t, float64x1_t:uint32x2_t, float64x1_t:uint64x1_t @@ -4333,7 +4656,7 @@ generate float64x1_t:poly8x8_t, float64x1_t:poly16x4_t, float32x2_t:poly64x1_t, float64x1_t:poly64x1_t generate float64x2_t:poly8x16_t, float64x2_t:poly16x8_t, float32x4_t:poly64x2_t, float64x2_t:poly64x2_t -arm = str +arm = nop generate float32x2_t:int8x8_t, float32x2_t:int16x4_t, float32x2_t:int32x2_t, float32x2_t:int64x1_t generate float32x4_t:int8x16_t, float32x4_t:int16x8_t, float32x4_t:int32x4_t, float32x4_t:int64x2_t generate float32x2_t:uint8x8_t, float32x2_t:uint16x4_t, float32x2_t:uint32x2_t, float32x2_t:uint64x1_t @@ -4348,7 +4671,7 @@ a = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 validate 0., 0., 0., 0., 0., 0., 0., 0. -aarch64 = str +aarch64 = nop generate int8x8_t:float64x1_t, int16x4_t:float64x1_t, int32x2_t:float64x1_t, int64x1_t:float64x1_t generate int8x16_t:float64x2_t, int16x8_t:float64x2_t, int32x4_t:float64x2_t, int64x2_t:float64x2_t generate poly8x8_t:float64x1_t, uint16x4_t:float64x1_t, uint32x2_t:float64x1_t, uint64x1_t:float64x1_t @@ -4356,7 +4679,7 @@ generate uint8x8_t:float64x1_t, poly16x4_t:float64x1_t, poly64x1_t:float64x1_t, poly64x1_t:float32x2_t generate uint8x16_t:float64x2_t, poly16x8_t:float64x2_t, poly64x2_t:float64x2_t, poly64x2_t:float32x4_t -arm = str +arm = nop generate int8x8_t:float32x2_t, int16x4_t:float32x2_t, int32x2_t:float32x2_t, int64x1_t:float32x2_t generate int8x16_t:float32x4_t, int16x8_t:float32x4_t, int32x4_t:float32x4_t, int64x2_t:float32x4_t generate uint8x8_t:float32x2_t, uint16x4_t:float32x2_t, uint32x2_t:float32x2_t, uint64x1_t:float32x2_t @@ -4371,7 +4694,7 @@ a = 0., 0., 0., 0., 0., 0., 0., 0. validate 0., 0., 0., 0., 0., 0., 0., 0. -aarch64 = str +aarch64 = nop generate float32x2_t:float64x1_t, float64x1_t:float32x2_t generate float32x4_t:float64x2_t, float64x2_t:float32x4_t @@ -4467,6 +4790,7 @@ a = 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64 n = 2 validate 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 +arm-aarch64-separate aarch64 = rshrn link-aarch64 = rshrn._EXT2_ diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-gen/src/main.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-gen/src/main.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-gen/src/main.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-gen/src/main.rs 2021-11-29 19:27:28.000000000 +0000 @@ -51,38 +51,34 @@ ]; fn type_len(t: &str) -> usize { - match t { - "int8x8_t" => 8, - "int8x16_t" => 16, - "int16x4_t" => 4, - "int16x8_t" => 8, - "int32x2_t" => 2, - "int32x4_t" => 4, - "int64x1_t" => 1, - "int64x2_t" => 2, - "uint8x8_t" => 8, - "uint8x16_t" => 16, - "uint16x4_t" => 4, - "uint16x8_t" => 8, - "uint32x2_t" => 2, - "uint32x4_t" => 4, - "uint64x1_t" => 1, - "uint64x2_t" => 2, - "float16x4_t" => 4, - "float16x8_t" => 8, - "float32x2_t" => 2, - "float32x4_t" => 4, - "float64x1_t" => 1, - "float64x2_t" => 2, - "poly8x8_t" => 8, - "poly8x16_t" => 16, - "poly16x4_t" => 4, - "poly16x8_t" => 8, - "poly64x1_t" => 1, - "poly64x2_t" => 2, - "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64" | "p8" - | "p16" | "p64" | "p128" => 1, - _ => panic!("unknown type: {}", t), + let s: Vec<_> = t.split("x").collect(); + if s.len() == 2 { + match &s[1][0..2] { + "1_" => 1, + "2_" => 2, + "4_" => 4, + "8_" => 8, + "16" => 16, + _ => panic!("unknown type: {}", t), + } + } else if s.len() == 3 { + s[1].parse::().unwrap() * type_sub_len(t) + } else { + 1 + } +} + +fn type_sub_len(t: &str) -> usize { + let s: Vec<_> = t.split('x').collect(); + if s.len() != 3 { + 1 + } else { + match s[2] { + "2_t" => 2, + "3_t" => 3, + "4_t" => 4, + _ => panic!("unknown type len: {}", t), + } } } @@ -101,35 +97,14 @@ } fn type_exp_len(t: &str) -> usize { - match t { - "int8x8_t" => 3, - "int8x16_t" => 4, - "int16x4_t" => 2, - "int16x8_t" => 3, - "int32x2_t" => 1, - "int32x4_t" => 2, - "int64x1_t" => 0, - "int64x2_t" => 1, - "uint8x8_t" => 3, - "uint8x16_t" => 4, - "uint16x4_t" => 2, - "uint16x8_t" => 3, - "uint32x2_t" => 1, - "uint32x4_t" => 2, - "uint64x1_t" => 0, - "uint64x2_t" => 1, - "float16x4_t" => 2, - "float16x8_t" => 3, - "float32x2_t" => 1, - "float32x4_t" => 2, - "float64x1_t" => 0, - "float64x2_t" => 1, - "poly8x8_t" => 3, - "poly8x16_t" => 4, - "poly16x4_t" => 2, - "poly16x8_t" => 3, - "poly64x1_t" => 0, - "poly64x2_t" => 1, + let t = type_to_sub_type(t); + let len = type_len(&t); + match len { + 1 => 0, + 2 => 1, + 4 => 2, + 8 => 3, + 16 => 4, _ => panic!("unknown type: {}", t), } } @@ -177,6 +152,84 @@ "poly16x8_t" => "q_p16", "poly64x1_t" => "_p64", "poly64x2_t" => "q_p64", + "int8x8x2_t" => "_s8_x2", + "int8x8x3_t" => "_s8_x3", + "int8x8x4_t" => "_s8_x4", + "int16x4x2_t" => "_s16_x2", + "int16x4x3_t" => "_s16_x3", + "int16x4x4_t" => "_s16_x4", + "int32x2x2_t" => "_s32_x2", + "int32x2x3_t" => "_s32_x3", + "int32x2x4_t" => "_s32_x4", + "int64x1x2_t" => "_s64_x2", + "int64x1x3_t" => "_s64_x3", + "int64x1x4_t" => "_s64_x4", + "uint8x8x2_t" => "_u8_x2", + "uint8x8x3_t" => "_u8_x3", + "uint8x8x4_t" => "_u8_x4", + "uint16x4x2_t" => "_u16_x2", + "uint16x4x3_t" => "_u16_x3", + "uint16x4x4_t" => "_u16_x4", + "uint32x2x2_t" => "_u32_x2", + "uint32x2x3_t" => "_u32_x3", + "uint32x2x4_t" => "_u32_x4", + "uint64x1x2_t" => "_u64_x2", + "uint64x1x3_t" => "_u64_x3", + "uint64x1x4_t" => "_u64_x4", + "poly8x8x2_t" => "_p8_x2", + "poly8x8x3_t" => "_p8_x3", + "poly8x8x4_t" => "_p8_x4", + "poly16x4x2_t" => "_p16_x2", + "poly16x4x3_t" => "_p16_x3", + "poly16x4x4_t" => "_p16_x4", + "poly64x1x2_t" => "_p64_x2", + "poly64x1x3_t" => "_p64_x3", + "poly64x1x4_t" => "_p64_x4", + "float32x2x2_t" => "_f32_x2", + "float32x2x3_t" => "_f32_x3", + "float32x2x4_t" => "_f32_x4", + "float64x1x2_t" => "_f64_x2", + "float64x1x3_t" => "_f64_x3", + "float64x1x4_t" => "_f64_x4", + "int8x16x2_t" => "q_s8_x2", + "int8x16x3_t" => "q_s8_x3", + "int8x16x4_t" => "q_s8_x4", + "int16x8x2_t" => "q_s16_x2", + "int16x8x3_t" => "q_s16_x3", + "int16x8x4_t" => "q_s16_x4", + "int32x4x2_t" => "q_s32_x2", + "int32x4x3_t" => "q_s32_x3", + "int32x4x4_t" => "q_s32_x4", + "int64x2x2_t" => "q_s64_x2", + "int64x2x3_t" => "q_s64_x3", + "int64x2x4_t" => "q_s64_x4", + "uint8x16x2_t" => "q_u8_x2", + "uint8x16x3_t" => "q_u8_x3", + "uint8x16x4_t" => "q_u8_x4", + "uint16x8x2_t" => "q_u16_x2", + "uint16x8x3_t" => "q_u16_x3", + "uint16x8x4_t" => "q_u16_x4", + "uint32x4x2_t" => "q_u32_x2", + "uint32x4x3_t" => "q_u32_x3", + "uint32x4x4_t" => "q_u32_x4", + "uint64x2x2_t" => "q_u64_x2", + "uint64x2x3_t" => "q_u64_x3", + "uint64x2x4_t" => "q_u64_x4", + "poly8x16x2_t" => "q_p8_x2", + "poly8x16x3_t" => "q_p8_x3", + "poly8x16x4_t" => "q_p8_x4", + "poly16x8x2_t" => "q_p16_x2", + "poly16x8x3_t" => "q_p16_x3", + "poly16x8x4_t" => "q_p16_x4", + "poly64x2x2_t" => "q_p64_x2", + "poly64x2x3_t" => "q_p64_x3", + "poly64x2x4_t" => "q_p64_x4", + "float32x4x2_t" => "q_f32_x2", + "float32x4x3_t" => "q_f32_x3", + "float32x4x4_t" => "q_f32_x4", + "float64x2x2_t" => "q_f64_x2", + "float64x2x3_t" => "q_f64_x3", + "float64x2x4_t" => "q_f64_x4", "i8" => "b_s8", "i16" => "h_s16", "i32" => "s_s32", @@ -193,6 +246,18 @@ } } +fn type_to_dup_suffix(t: &str) -> String { + let s: Vec<_> = type_to_suffix(t).split('_').collect(); + assert_eq!(s.len(), 2); + format!("{}_dup_{}", s[0], s[1]) +} + +fn type_to_lane_suffix(t: &str) -> String { + let s: Vec<_> = type_to_suffix(t).split('_').collect(); + assert_eq!(s.len(), 2); + format!("{}_lane_{}", s[0], s[1]) +} + fn type_to_n_suffix(t: &str) -> &str { match t { "int8x8_t" => "_n_s8", @@ -274,18 +339,10 @@ str } -fn type_to_signed(t: &str) -> &str { - match t { - "int8x8_t" | "uint8x8_t" | "poly8x8_t" => "int8x8_t", - "int8x16_t" | "uint8x16_t" | "poly8x16_t" => "int8x16_t", - "int16x4_t" | "uint16x4_t" | "poly16x4_t" => "int16x4_t", - "int16x8_t" | "uint16x8_t" | "poly16x8_t" => "int16x8_t", - "int32x2_t" | "uint32x2_t" => "int32x2_t", - "int32x4_t" | "uint32x4_t" => "int32x4_t", - "int64x1_t" | "uint64x1_t" | "poly64x1_t" => "int64x1_t", - "int64x2_t" | "uint64x2_t" | "poly64x2_t" => "int64x2_t", - _ => panic!("unknown type: {}", t), - } +fn type_to_signed(t: &String) -> String { + let s = t.replace("uint", "int"); + let s = s.replace("poly", "int"); + s } fn type_to_unsigned(t: &str) -> &str { @@ -369,6 +426,9 @@ NoQNSuffix, OutSuffix, OutNSuffix, + OutNox, + OutDupNox, + OutLaneNox, Lane, In2, In2Lane, @@ -378,40 +438,48 @@ enum TargetFeature { Default, ArmV7, + Vfp4, FPArmV8, AES, } +#[derive(Clone, Copy)] +enum Fntype { + Normal, + Load, + Store, +} + fn type_to_global_type(t: &str) -> &str { match t { - "int8x8_t" => "i8x8", - "int8x16_t" => "i8x16", - "int16x4_t" => "i16x4", - "int16x8_t" => "i16x8", - "int32x2_t" => "i32x2", - "int32x4_t" => "i32x4", - "int64x1_t" => "i64x1", - "int64x2_t" => "i64x2", - "uint8x8_t" => "u8x8", - "uint8x16_t" => "u8x16", - "uint16x4_t" => "u16x4", - "uint16x8_t" => "u16x8", - "uint32x2_t" => "u32x2", - "uint32x4_t" => "u32x4", - "uint64x1_t" => "u64x1", - "uint64x2_t" => "u64x2", + "int8x8_t" | "int8x8x2_t" | "int8x8x3_t" | "int8x8x4_t" => "i8x8", + "int8x16_t" | "int8x16x2_t" | "int8x16x3_t" | "int8x16x4_t" => "i8x16", + "int16x4_t" | "int16x4x2_t" | "int16x4x3_t" | "int16x4x4_t" => "i16x4", + "int16x8_t" | "int16x8x2_t" | "int16x8x3_t" | "int16x8x4_t" => "i16x8", + "int32x2_t" | "int32x2x2_t" | "int32x2x3_t" | "int32x2x4_t" => "i32x2", + "int32x4_t" | "int32x4x2_t" | "int32x4x3_t" | "int32x4x4_t" => "i32x4", + "int64x1_t" | "int64x1x2_t" | "int64x1x3_t" | "int64x1x4_t" => "i64x1", + "int64x2_t" | "int64x2x2_t" | "int64x2x3_t" | "int64x2x4_t" => "i64x2", + "uint8x8_t" | "uint8x8x2_t" | "uint8x8x3_t" | "uint8x8x4_t" => "u8x8", + "uint8x16_t" | "uint8x16x2_t" | "uint8x16x3_t" | "uint8x16x4_t" => "u8x16", + "uint16x4_t" | "uint16x4x2_t" | "uint16x4x3_t" | "uint16x4x4_t" => "u16x4", + "uint16x8_t" | "uint16x8x2_t" | "uint16x8x3_t" | "uint16x8x4_t" => "u16x8", + "uint32x2_t" | "uint32x2x2_t" | "uint32x2x3_t" | "uint32x2x4_t" => "u32x2", + "uint32x4_t" | "uint32x4x2_t" | "uint32x4x3_t" | "uint32x4x4_t" => "u32x4", + "uint64x1_t" | "uint64x1x2_t" | "uint64x1x3_t" | "uint64x1x4_t" => "u64x1", + "uint64x2_t" | "uint64x2x2_t" | "uint64x2x3_t" | "uint64x2x4_t" => "u64x2", "float16x4_t" => "f16x4", "float16x8_t" => "f16x8", - "float32x2_t" => "f32x2", - "float32x4_t" => "f32x4", - "float64x1_t" => "f64", - "float64x2_t" => "f64x2", - "poly8x8_t" => "i8x8", - "poly8x16_t" => "i8x16", - "poly16x4_t" => "i16x4", - "poly16x8_t" => "i16x8", - "poly64x1_t" => "i64x1", - "poly64x2_t" => "i64x2", + "float32x2_t" | "float32x2x2_t" | "float32x2x3_t" | "float32x2x4_t" => "f32x2", + "float32x4_t" | "float32x4x2_t" | "float32x4x3_t" | "float32x4x4_t" => "f32x4", + "float64x1_t" | "float64x1x2_t" | "float64x1x3_t" | "float64x1x4_t" => "f64", + "float64x2_t" | "float64x2x2_t" | "float64x2x3_t" | "float64x2x4_t" => "f64x2", + "poly8x8_t" | "poly8x8x2_t" | "poly8x8x3_t" | "poly8x8x4_t" => "i8x8", + "poly8x16_t" | "poly8x16x2_t" | "poly8x16x3_t" | "poly8x16x4_t" => "i8x16", + "poly16x4_t" | "poly16x4x2_t" | "poly16x4x3_t" | "poly16x4x4_t" => "i16x4", + "poly16x8_t" | "poly16x8x2_t" | "poly16x8x3_t" | "poly16x8x4_t" => "i16x8", + "poly64x1_t" | "poly64x1x2_t" | "poly64x1x3_t" | "poly64x1x4_t" => "i64x1", + "poly64x2_t" | "poly64x2x2_t" | "poly64x2x3_t" | "poly64x2x4_t" => "i64x2", "i8" => "i8", "i16" => "i16", "i32" => "i32", @@ -430,20 +498,30 @@ } } -fn type_to_native_type(t: &str) -> &str { - match t { - "int8x8_t" | "int8x16_t" | "i8" => "i8", - "int16x4_t" | "int16x8_t" | "i16" => "i16", - "int32x2_t" | "int32x4_t" | "i32" => "i32", - "int64x1_t" | "int64x2_t" | "i64" => "i64", - "uint8x8_t" | "uint8x16_t" | "u8" => "u8", - "uint16x4_t" | "uint16x8_t" | "u16" => "u16", - "uint32x2_t" | "uint32x4_t" | "u32" => "u32", - "uint64x1_t" | "uint64x2_t" | "u64" => "u64", - "float16x4_t" | "float16x8_t" => "f16", - "float32x2_t" | "float32x4_t" => "f32", - "float64x1_t" | "float64x2_t" => "f64", - "poly64x1_t" | "poly64x2_t" => "u64", +fn type_to_sub_type(t: &str) -> String { + let s: Vec<_> = t.split('x').collect(); + match s.len() { + 2 => String::from(t), + 3 => format!("{}x{}_t", s[0], s[1]), + _ => panic!("unknown type: {}", t), + } +} + +fn type_to_native_type(t: &str) -> String { + let s: Vec<_> = t.split('x').collect(); + match s.len() { + 1 => { + assert!(t.contains("*const") || t.contains("*mut")); + let sub: Vec<_> = t.split(' ').collect(); + String::from(sub[1]) + } + 2 | 3 => match &s[0][0..3] { + "int" => format!("i{}", &s[0][3..]), + "uin" => format!("u{}", &s[0][4..]), + "flo" => format!("f{}", &s[0][5..]), + "pol" => format!("u{}", &s[0][4..]), + _ => panic!("unknown type: {}", t), + }, _ => panic!("unknown type: {}", t), } } @@ -482,54 +560,6 @@ } } -fn type_to_ext(t: &str) -> &str { - match t { - "int8x8_t" => "v8i8", - "int8x16_t" => "v16i8", - "int16x4_t" => "v4i16", - "int16x8_t" => "v8i16", - "int32x2_t" => "v2i32", - "int32x4_t" => "v4i32", - "int64x1_t" => "v1i64", - "int64x2_t" => "v2i64", - "uint8x8_t" => "v8i8", - "uint8x16_t" => "v16i8", - "uint16x4_t" => "v4i16", - "uint16x8_t" => "v8i16", - "uint32x2_t" => "v2i32", - "uint32x4_t" => "v4i32", - "uint64x1_t" => "v1i64", - "uint64x2_t" => "v2i64", - "float16x4_t" => "v4f16", - "float16x8_t" => "v8f16", - "float32x2_t" => "v2f32", - "float32x4_t" => "v4f32", - "float64x1_t" => "v1f64", - "float64x2_t" => "v2f64", - "poly8x8_t" => "v8i8", - "poly8x16_t" => "v16i8", - "poly16x4_t" => "v4i16", - "poly16x8_t" => "v8i16", - "i8" => "i8", - "i16" => "i16", - "i32" => "i32", - "i64" => "i64", - "u8" => "i8", - "u16" => "i16", - "u32" => "i32", - "u64" => "i64", - "f32" => "f32", - "f64" => "f64", - "p64" => "p64", - "p128" => "p128", - /* - "poly64x1_t" => "i64x1", - "poly64x2_t" => "i64x2", - */ - _ => panic!("unknown type for extension: {}", t), - } -} - fn type_to_half(t: &str) -> &str { match t { "int8x16_t" => "int8x8_t", @@ -835,6 +865,53 @@ } } +fn type_to_ext(t: &str, v: bool, r: bool, pi8: bool) -> String { + if !t.contains('x') { + return t.replace("u", "i"); + } + let native = type_to_native_type(t); + let sub_ext = match type_sub_len(t) { + 1 => String::new(), + _ if v => format!( + ".p0v{}{}", + &type_len(&type_to_sub_type(t)).to_string(), + native + ), + _ if pi8 => format!(".p0i8"), + _ => format!(".p0{}", native), + }; + let sub_type = match &native[0..1] { + "i" | "f" => native, + "u" => native.replace("u", "i"), + _ => panic!("unknown type: {}", t), + }; + let ext = format!( + "v{}{}{}", + &type_len(&type_to_sub_type(t)).to_string(), + sub_type, + sub_ext + ); + if r { + let ss: Vec<_> = ext.split('.').collect(); + if ss.len() != 2 { + ext + } else { + format!("{}.{}", ss[1], ss[0]) + } + } else { + ext + } +} + +fn ext(s: &str, in_t: &[&str; 3], out_t: &str) -> String { + s.replace("_EXT_", &type_to_ext(in_t[0], false, false, false)) + .replace("_EXT2_", &type_to_ext(out_t, false, false, false)) + .replace("_EXT3_", &type_to_ext(in_t[1], false, false, false)) + .replace("_EXTr3_", &type_to_ext(in_t[1], false, true, false)) + .replace("_EXTv2_", &type_to_ext(out_t, true, false, false)) + .replace("_EXTpi82_", &type_to_ext(out_t, false, false, true)) +} + #[allow(clippy::too_many_arguments)] fn gen_aarch64( current_comment: &str, @@ -858,9 +935,8 @@ target: TargetFeature, fixed: &Vec, multi_fn: &Vec, + fn_type: Fntype, ) -> (String, String) { - let _global_t = type_to_global_type(in_t[0]); - let _global_ret_t = type_to_global_type(out_t); let name = match suffix { Normal => format!("{}{}", current_name, type_to_suffix(in_t[1])), NoQ => format!("{}{}", current_name, type_to_noq_suffix(in_t[1])), @@ -883,6 +959,21 @@ NoQNSuffix => format!("{}{}", current_name, type_to_noq_n_suffix(in_t[1])), OutSuffix => format!("{}{}", current_name, type_to_suffix(out_t)), OutNSuffix => format!("{}{}", current_name, type_to_n_suffix(out_t)), + OutNox => format!( + "{}{}", + current_name, + type_to_suffix(&type_to_sub_type(out_t)) + ), + OutDupNox => format!( + "{}{}", + current_name, + type_to_dup_suffix(&type_to_sub_type(out_t)) + ), + OutLaneNox => format!( + "{}{}", + current_name, + type_to_lane_suffix(&type_to_sub_type(out_t)) + ), Lane => format!("{}{}", current_name, type_to_lane_suffixes(out_t, in_t[1])), In2 => format!("{}{}", current_name, type_to_suffix(in_t[2])), In2Lane => format!("{}{}", current_name, type_to_lane_suffixes(out_t, in_t[2])), @@ -890,6 +981,7 @@ let current_target = match target { Default => "neon", ArmV7 => "v7", + Vfp4 => "vfp4", FPArmV8 => "fp-armv8,v8", AES => "neon,aes", }; @@ -910,14 +1002,13 @@ String::new() }; let current_aarch64 = current_aarch64.clone().unwrap(); - let mut ext_c = String::new(); - let mut ext_c_const = String::new(); let mut link_t: Vec = vec![ in_t[0].to_string(), in_t[1].to_string(), in_t[2].to_string(), out_t.to_string(), ]; + let mut ext_c = String::new(); if let Some(mut link_aarch64) = link_aarch64.clone() { if link_aarch64.contains(":") { let links: Vec<_> = link_aarch64.split(':').map(|v| v.to_string()).collect(); @@ -930,63 +1021,81 @@ links[4].clone(), ]; } - let ext = type_to_ext(in_t[0]); - let ext2 = type_to_ext(out_t); let link_aarch64 = if link_aarch64.starts_with("llvm") { - link_aarch64.replace("_EXT_", ext).replace("_EXT2_", ext2) + ext(&link_aarch64, in_t, out_t) } else { let mut link = String::from("llvm.aarch64.neon."); link.push_str(&link_aarch64); - link.replace("_EXT_", ext).replace("_EXT2_", ext2) + ext(&link, in_t, out_t) + }; + let (ext_inputs, ext_output) = { + if const_aarch64.is_some() { + if matches!(fn_type, Fntype::Load) { + let sub = type_to_sub_type(in_t[1]); + ( + match type_sub_len(in_t[1]) { + 1 => format!("a: {}, n: i64, ptr: *const i8", sub), + 2 => format!("a: {}, b: {}, n: i64, ptr: *const i8", sub, sub), + 3 => format!( + "a: {}, b: {}, c: {}, n: i64, ptr: *const i8", + sub, sub, sub + ), + 4 => format!( + "a: {}, b: {}, c: {}, d: {}, n: i64, ptr: *const i8", + sub, sub, sub, sub + ), + _ => panic!("unsupported type: {}", in_t[1]), + }, + format!(" -> {}", out_t), + ) + } else { + ( + match para_num { + 1 => format!("a: {}, n: i32", in_t[0]), + 2 => format!("a: {}, b: {}, n: i32", in_t[0], in_t[1]), + 3 => format!("a: {}, b: {}, c: {}, n: i32", in_t[0], in_t[1], in_t[2]), + _ => unimplemented!("unknown para_num"), + }, + format!(" -> {}", out_t), + ) + } + } else if matches!(fn_type, Fntype::Store) { + let sub = type_to_sub_type(in_t[1]); + let native = type_to_native_type(in_t[1]); + ( + match type_sub_len(in_t[1]) { + 1 => format!("a: {}, ptr: *mut {}", sub, native), + 2 => format!("a: {}, b: {}, ptr: *mut {}", sub, sub, native), + 3 => format!("a: {}, b: {}, c: {}, ptr: *mut {}", sub, sub, sub, native), + 4 => format!( + "a: {}, b: {}, c: {}, d: {}, ptr: *mut {}", + sub, sub, sub, sub, native + ), + _ => panic!("unsupported type: {}", in_t[1]), + }, + String::new(), + ) + } else { + ( + match para_num { + 1 => format!("a: {}", link_t[0]), + 2 => format!("a: {}, b: {}", link_t[0], link_t[1]), + 3 => format!("a: {}, b: {}, c: {}", link_t[0], link_t[1], link_t[2]), + _ => unimplemented!("unknown para_num"), + }, + format!(" -> {}", link_t[3]), + ) + } }; ext_c = format!( r#"#[allow(improper_ctypes)] - extern "C" {{ + extern "unadjusted" {{ #[cfg_attr(target_arch = "aarch64", link_name = "{}")] - fn {}({}) -> {}; + fn {}({}){}; }} "#, - link_aarch64, - current_fn, - match para_num { - 1 => { - format!("a: {}", link_t[0]) - } - 2 => { - format!("a: {}, b: {}", link_t[0], link_t[1]) - } - 3 => { - format!("a: {}, b: {}, c: {}", link_t[0], link_t[1], link_t[2]) - } - _ => unimplemented!("unknown para_num"), - }, - link_t[3] + link_aarch64, current_fn, ext_inputs, ext_output, ); - if const_aarch64.is_some() { - ext_c_const = format!( - r#"#[allow(improper_ctypes)] - extern "C" {{ - #[cfg_attr(target_arch = "aarch64", link_name = "{}")] - fn {}({}) -> {}; - }} - "#, - link_aarch64, - current_fn, - match para_num { - 1 => { - format!("a: {}, n: i32", in_t[0]) - } - 2 => { - format!("a: {}, b: {}, n: i32", in_t[0], in_t[1]) - } - 3 => { - format!("a: {}, b: {}, c: {}, n: i32", in_t[0], in_t[1], in_t[2]) - } - _ => unimplemented!("unknown para_num"), - }, - out_t - ); - } }; let const_declare = if let Some(constn) = constn { if constn.contains(":") { @@ -1013,6 +1122,7 @@ out_t, fixed, None, + true, )); } calls @@ -1056,99 +1166,93 @@ } else { String::new() }; - let trans: [&str; 2] = if link_t[3] != out_t { - ["transmute(", ")"] - } else { - ["", ""] + let fn_decl = { + let fn_output = if out_t == "void" { + String::new() + } else { + format!("-> {} ", out_t) + }; + let fn_inputs = match para_num { + 1 => format!("(a: {})", in_t[0]), + 2 => format!("(a: {}, b: {})", in_t[0], in_t[1]), + 3 => format!("(a: {}, b: {}, c: {})", in_t[0], in_t[1], in_t[2]), + _ => panic!("unsupported parameter number"), + }; + format!( + "pub unsafe fn {}{}{} {}", + name, const_declare, fn_inputs, fn_output + ) }; - let call = if let Some(const_aarch64) = const_aarch64 { - match para_num { - 1 => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {} - {}{}(a, {}) -}}"#, - name, - const_declare, - in_t[0], - out_t, - multi_calls, - ext_c_const, - current_fn, - const_aarch64 - ), - 2 => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{}{}(a, b, {}) -}}"#, - name, - const_declare, - in_t[0], - out_t, - multi_calls, - ext_c_const, - current_fn, - const_aarch64 - ), - _ => String::new(), - } - } else { - match (multi_calls.len(), para_num, fixed.len()) { - (0, 1, 0) => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{}{}(a){} -}}"#, - name, const_declare, in_t[0], out_t, ext_c, trans[0], current_fn, trans[1] - ), - (0, 1, _) => { - let fixed: Vec = fixed.iter().take(type_len(in_t[0])).cloned().collect(); + let call_params = { + if let (Some(const_aarch64), Some(_)) = (const_aarch64, link_aarch64) { + if matches!(fn_type, Fntype::Load) { + let subs = match type_sub_len(in_t[1]) { + 1 => "b", + 2 => "b.0, b.1", + 3 => "b.0, b.1, b.2", + 4 => "b.0, b.1, b.2, b.3", + _ => panic!("unsupported type: {}", in_t[1]), + }; format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - let b{}; - {}{}{}(a, transmute(b)){} -}}"#, - name, - const_declare, - in_t[0], - out_t, - values(in_t[0], &fixed), + r#"{} + {}{}({}, {} as i64, a as *const i8)"#, + multi_calls, ext_c, - trans[0], current_fn, - trans[1], + subs, + constn.as_deref().unwrap() ) + } else { + match para_num { + 1 => format!( + r#"{} + {}{}(a, {})"#, + multi_calls, ext_c, current_fn, const_aarch64 + ), + 2 => format!( + r#"{} + {}{}(a, b, {})"#, + multi_calls, ext_c, current_fn, const_aarch64 + ), + _ => String::new(), + } + } + } else if matches!(fn_type, Fntype::Store) { + match type_sub_len(in_t[1]) { + 1 => format!(r#"{}{}(b, a)"#, ext_c, current_fn), + 2 => format!(r#"{}{}(b.0, b.1, a)"#, ext_c, current_fn), + 3 => format!(r#"{}{}(b.0, b.1, b.2, a)"#, ext_c, current_fn), + 4 => format!(r#"{}{}(b.0, b.1, b.2, b.3, a)"#, ext_c, current_fn), + _ => panic!("unsupported type: {}", in_t[1]), + } + } else { + let trans: [&str; 2] = if link_t[3] != out_t { + ["transmute(", ")"] + } else { + ["", ""] + }; + match (multi_calls.len(), para_num, fixed.len()) { + (0, 1, 0) => format!(r#"{}{}{}(a){}"#, ext_c, trans[0], current_fn, trans[1]), + (0, 1, _) => { + let fixed: Vec = + fixed.iter().take(type_len(in_t[0])).cloned().collect(); + format!( + r#"let b{}; + {}{}{}(a, transmute(b)){}"#, + values(in_t[0], &fixed), + ext_c, + trans[0], + current_fn, + trans[1], + ) + } + (0, 2, _) => format!(r#"{}{}{}(a, b){}"#, ext_c, trans[0], current_fn, trans[1],), + (0, 3, _) => format!(r#"{}{}(a, b, c)"#, ext_c, current_fn,), + (_, 1, _) => format!(r#"{}{}"#, ext_c, multi_calls,), + (_, 2, _) => format!(r#"{}{}"#, ext_c, multi_calls,), + (_, 3, _) => format!(r#"{}{}"#, ext_c, multi_calls,), + (_, _, _) => String::new(), } - (0, 2, _) => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}) -> {} {{ - {}{}{}(a, b){} -}}"#, - name, const_declare, in_t[0], in_t[1], out_t, ext_c, trans[0], current_fn, trans[1], - ), - (0, 3, _) => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}, c: {}) -> {} {{ - {}{}(a, b, c) -}}"#, - name, const_declare, in_t[0], in_t[1], in_t[2], out_t, ext_c, current_fn, - ), - (_, 1, _) => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{} -}}"#, - name, const_declare, in_t[0], out_t, ext_c, multi_calls, - ), - (_, 2, _) => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}) -> {} {{ - {}{} -}}"#, - name, const_declare, in_t[0], in_t[1], out_t, ext_c, multi_calls, - ), - (_, 3, _) => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}, c: {}) -> {} {{ - {}{} -}}"#, - name, const_declare, in_t[0], in_t[1], in_t[2], out_t, ext_c, multi_calls, - ), - (_, _, _) => String::new(), } }; let function = format!( @@ -1157,21 +1261,195 @@ #[inline] #[target_feature(enable = "{}")] #[cfg_attr(test, assert_instr({}{}))]{} -{} +{}{{ + {} +}} "#, - current_comment, current_target, current_aarch64, const_assert, const_legacy, call + current_comment, + current_target, + current_aarch64, + const_assert, + const_legacy, + fn_decl, + call_params ); + let test = match fn_type { + Fntype::Normal => gen_test( + &name, + in_t, + &out_t, + current_tests, + [type_len(in_t[0]), type_len(in_t[1]), type_len(in_t[2])], + type_len(out_t), + para_num, + ), + Fntype::Load => gen_load_test(&name, in_t, &out_t, current_tests, type_len(out_t)), + Fntype::Store => gen_store_test(&name, in_t, &out_t, current_tests, type_len(in_t[1])), + }; + (function, test) +} - let test = gen_test( - &name, - in_t, - &out_t, - current_tests, - [type_len(in_t[0]), type_len(in_t[1]), type_len(in_t[2])], - type_len(out_t), - para_num, +fn gen_load_test( + name: &str, + in_t: &[&str; 3], + out_t: &str, + current_tests: &[( + Vec, + Vec, + Vec, + Option, + Vec, + )], + type_len: usize, +) -> String { + let mut test = format!( + r#" + #[simd_test(enable = "neon")] + unsafe fn test_{}() {{"#, + name, ); - (function, test) + for (a, b, _, n, e) in current_tests { + let a: Vec = a.iter().take(type_len + 1).cloned().collect(); + let e: Vec = e.iter().take(type_len).cloned().collect(); + let has_b = b.len() > 0; + let has_n = n.is_some(); + let mut input = String::from("["); + for i in 0..type_len + 1 { + if i != 0 { + input.push_str(", "); + } + input.push_str(&a[i]) + } + input.push_str("]"); + let output = |v: &Vec| { + let mut output = String::from("["); + for i in 0..type_sub_len(out_t) { + if i != 0 { + output.push_str(", "); + } + let sub_len = type_len / type_sub_len(out_t); + if type_to_global_type(out_t) != "f64" { + let mut sub_output = format!("{}::new(", type_to_global_type(out_t)); + for j in 0..sub_len { + if j != 0 { + sub_output.push_str(", "); + } + sub_output.push_str(&v[i * sub_len + j]); + } + sub_output.push_str(")"); + output.push_str(&sub_output); + } else { + output.push_str(&v[i]); + } + } + output.push_str("]"); + output + }; + let input_b = if has_b { + let b: Vec = b.iter().take(type_len).cloned().collect(); + format!( + r#" + let b: [{}; {}] = {};"#, + type_to_global_type(in_t[1]), + type_sub_len(in_t[1]), + output(&b), + ) + } else { + String::new() + }; + let t = format!( + r#" + let a: [{}; {}] = {};{} + let e: [{}; {}] = {}; + let r: [{}; {}] = transmute({}{}(a[1..].as_ptr(){})); + assert_eq!(r, e); +"#, + type_to_native_type(out_t), + type_len + 1, + input, + input_b, + type_to_global_type(out_t), + type_sub_len(out_t), + output(&e), + type_to_global_type(out_t), + type_sub_len(out_t), + name, + if has_n { + format!("::<{}>", n.as_deref().unwrap()) + } else { + String::new() + }, + if has_b { ", transmute(b)" } else { "" }, + ); + test.push_str(&t); + } + test.push_str(" }\n"); + test +} + +fn gen_store_test( + name: &str, + in_t: &[&str; 3], + _out_t: &str, + current_tests: &[( + Vec, + Vec, + Vec, + Option, + Vec, + )], + type_len: usize, +) -> String { + let mut test = format!( + r#" + #[simd_test(enable = "neon")] + unsafe fn test_{}() {{"#, + name, + ); + for (a, _, _, _, e) in current_tests { + let a: Vec = a.iter().take(type_len + 1).cloned().collect(); + let e: Vec = e.iter().take(type_len).cloned().collect(); + let mut input = String::from("["); + for i in 0..type_len + 1 { + if i != 0 { + input.push_str(", "); + } + input.push_str(&a[i]) + } + input.push_str("]"); + let mut output = String::from("["); + for i in 0..type_len { + if i != 0 { + output.push_str(", "); + } + output.push_str(&e[i]) + } + output.push_str("]"); + let t = format!( + r#" + let a: [{}; {}] = {}; + let e: [{}; {}] = {}; + let mut r: [{}; {}] = [0{}; {}]; + {}(r.as_mut_ptr(), {}(a[1..].as_ptr())); + assert_eq!(r, e); +"#, + type_to_native_type(in_t[1]), + type_len + 1, + input, + type_to_native_type(in_t[1]), + type_len, + output, + type_to_native_type(in_t[1]), + type_len, + type_to_native_type(in_t[1]), + type_len, + name, + name.replace("st", "ld"), + ); + test.push_str(&t); + } + test.push_str(" }\n"); + test } fn gen_test( @@ -1305,9 +1583,9 @@ target: TargetFeature, fixed: &Vec, multi_fn: &Vec, + fn_type: Fntype, + separate: bool, ) -> (String, String) { - let _global_t = type_to_global_type(in_t[0]); - let _global_ret_t = type_to_global_type(out_t); let name = match suffix { Normal => format!("{}{}", current_name, type_to_suffix(in_t[1])), NoQ => format!("{}{}", current_name, type_to_noq_suffix(in_t[1])), @@ -1330,6 +1608,21 @@ NoQNSuffix => format!("{}{}", current_name, type_to_noq_n_suffix(in_t[1])), OutSuffix => format!("{}{}", current_name, type_to_suffix(out_t)), OutNSuffix => format!("{}{}", current_name, type_to_n_suffix(out_t)), + OutNox => format!( + "{}{}", + current_name, + type_to_suffix(&type_to_sub_type(out_t)) + ), + OutDupNox => format!( + "{}{}", + current_name, + type_to_dup_suffix(&type_to_sub_type(out_t)) + ), + OutLaneNox => format!( + "{}{}", + current_name, + type_to_lane_suffix(&type_to_sub_type(out_t)) + ), Lane => format!("{}{}", current_name, type_to_lane_suffixes(out_t, in_t[1])), In2 => format!("{}{}", current_name, type_to_suffix(in_t[2])), In2Lane => format!("{}{}", current_name, type_to_lane_suffixes(out_t, in_t[2])), @@ -1340,16 +1633,17 @@ let current_target_aarch64 = match target { Default => "neon", ArmV7 => "neon", + Vfp4 => "neon", FPArmV8 => "neon", AES => "neon,aes", }; let current_target_arm = match target { Default => "v7", ArmV7 => "v7", + Vfp4 => "vfp4", FPArmV8 => "fp-armv8,v8", - AES => "crypto,v8", // TODO: Replace with AES when the minimum LLVM version has b8baa2a9132498ea286dbb0d03f005760ecc6fdb + AES => "aes,v8", }; - let current_fn = if let Some(current_fn) = current_fn.clone() { if link_aarch64.is_some() || link_arm.is_some() { panic!( @@ -1370,7 +1664,7 @@ String::new() }; let mut ext_c = String::new(); - let mut ext_c_arm = if multi_fn.is_empty() { + let mut ext_c_arm = if multi_fn.is_empty() || link_arm.is_none() { String::new() } else { String::from( @@ -1378,7 +1672,7 @@ "#, ) }; - let mut ext_c_aarch64 = if multi_fn.is_empty() { + let mut ext_c_aarch64 = if multi_fn.is_empty() || link_aarch64.is_none() { String::new() } else { String::from( @@ -1421,26 +1715,24 @@ links[4].clone(), ]; } - let ext = type_to_ext(in_t[0]); - let ext2 = type_to_ext(out_t); let link_arm = if link_arm.starts_with("llvm") { - link_arm.replace("_EXT_", ext).replace("_EXT2_", ext2) + ext(&link_arm, in_t, out_t) } else { let mut link = String::from("llvm.arm.neon."); link.push_str(&link_arm); - link.replace("_EXT_", ext).replace("_EXT2_", ext2) + ext(&link, in_t, out_t) }; let link_aarch64 = if link_aarch64.starts_with("llvm") { - link_aarch64.replace("_EXT_", ext).replace("_EXT2_", ext2) + ext(&link_aarch64, in_t, out_t) } else { let mut link = String::from("llvm.aarch64.neon."); link.push_str(&link_aarch64); - link.replace("_EXT_", ext).replace("_EXT2_", ext2) + ext(&link, in_t, out_t) }; if out_t == link_arm_t[3] && out_t == link_aarch64_t[3] { ext_c = format!( r#"#[allow(improper_ctypes)] - extern "C" {{ + extern "unadjusted" {{ #[cfg_attr(target_arch = "arm", link_name = "{}")] #[cfg_attr(target_arch = "aarch64", link_name = "{}")] fn {}({}) -> {}; @@ -1450,138 +1742,165 @@ link_aarch64, current_fn, match para_num { - 1 => { - format!("a: {}", in_t[0]) - } - 2 => { - format!("a: {}, b: {}", in_t[0], in_t[1]) - } - 3 => { - format!("a: {}, b: {}, c: {}", in_t[0], in_t[1], in_t[2]) - } + 1 => format!("a: {}", in_t[0]), + 2 => format!("a: {}, b: {}", in_t[0], in_t[1]), + 3 => format!("a: {}, b: {}, c: {}", in_t[0], in_t[1], in_t[2]), _ => unimplemented!("unknown para_num"), }, out_t ); }; - if let Some(const_arm) = const_arm { - let (_, const_type) = if const_arm.contains(":") { - let consts: Vec<_> = const_arm.split(':').map(|v| v.trim().to_string()).collect(); - (consts[0].clone(), consts[1].clone()) - } else { + let (arm_ext_inputs, arm_ext_output) = { + if let Some(const_arm) = const_arm { + if matches!(fn_type, Fntype::Load) { + let sub_type = type_to_sub_type(in_t[1]); + let inputs = match type_sub_len(in_t[1]) { + 1 => format!("a: {}", sub_type), + 2 => format!("a: {}, b: {}", sub_type, sub_type,), + 3 => format!("a: {}, b: {}, c: {}", sub_type, sub_type, sub_type,), + 4 => format!( + "a: {}, b: {}, c: {}, d: {}", + sub_type, sub_type, sub_type, sub_type, + ), + _ => panic!("unknown type: {}", in_t[1]), + }; + ( + format!("ptr: *const i8, {}, n: i32, size: i32", inputs), + String::new(), + ) + } else { + let (_, const_type) = if const_arm.contains(":") { + let consts: Vec<_> = + const_arm.split(':').map(|v| v.trim().to_string()).collect(); + (consts[0].clone(), consts[1].clone()) + } else { + ( + const_arm.to_string(), + in_t[para_num as usize - 1].to_string(), + ) + }; + ( + match para_num { + 1 => format!("a: {}, n: {}", in_t[0], const_type), + 2 => format!("a: {}, b: {}, n: {}", in_t[0], in_t[1], const_type), + 3 => format!( + "a: {}, b: {}, c: {}, n: {}", + in_t[0], in_t[1], in_t[2], const_type + ), + _ => unimplemented!("unknown para_num"), + }, + format!(" -> {}", out_t), + ) + } + } else if out_t != link_arm_t[3] { ( - const_arm.to_string(), - in_t[para_num as usize - 1].to_string(), + match para_num { + 1 => format!("a: {}", link_arm_t[0]), + 2 => format!("a: {}, b: {}", link_arm_t[0], link_arm_t[1]), + 3 => format!( + "a: {}, b: {}, c: {}", + link_arm_t[0], link_arm_t[1], link_arm_t[2] + ), + _ => unimplemented!("unknown para_num"), + }, + format!(" -> {}", link_arm_t[3]), ) - }; - ext_c_arm.push_str(&format!( - r#"#[allow(improper_ctypes)] - extern "C" {{ - #[cfg_attr(target_arch = "arm", link_name = "{}")] - fn {}({}) -> {}; - }} -"#, - link_arm, - current_fn, - match para_num { - 1 => { - format!("a: {}, n: {}", in_t[0], const_type) - } - 2 => { - format!("a: {}, b: {}, n: {}", in_t[0], in_t[1], const_type) - } - 3 => { - format!( - "a: {}, b: {}, c: {}, n: {}", - in_t[0], in_t[1], in_t[2], const_type - ) - } - _ => unimplemented!("unknown para_num"), - }, - out_t - )); + } else if matches!(fn_type, Fntype::Store) { + let sub_type = type_to_sub_type(in_t[1]); + let inputs = match type_sub_len(in_t[1]) { + 1 => format!("a: {}", sub_type), + 2 => format!("a: {}, b: {}", sub_type, sub_type,), + 3 => format!("a: {}, b: {}, c: {}", sub_type, sub_type, sub_type,), + 4 => format!( + "a: {}, b: {}, c: {}, d: {}", + sub_type, sub_type, sub_type, sub_type, + ), + _ => panic!("unknown type: {}", in_t[1]), + }; + ( + format!("ptr: *mut {}, {}", type_to_native_type(in_t[1]), inputs), + String::new(), + ) + } else { + (String::new(), String::new()) + } }; - if out_t != link_arm_t[3] { - ext_c_arm.push_str(&format!( - r#"#[allow(improper_ctypes)] - extern "C" {{ + ext_c_arm.push_str(&format!( + r#"#[allow(improper_ctypes)] + extern "unadjusted" {{ #[cfg_attr(target_arch = "arm", link_name = "{}")] - fn {}({}) -> {}; + fn {}({}){}; }} "#, - link_arm, - current_fn, - match para_num { - 1 => { - format!("a: {}", link_arm_t[0]) - } - 2 => { - format!("a: {}, b: {}", link_arm_t[0], link_arm_t[1]) - } - 3 => { - format!( + link_arm, current_fn, arm_ext_inputs, arm_ext_output, + )); + let (aarch64_ext_inputs, aarch64_ext_output) = { + if const_aarch64.is_some() { + if matches!(fn_type, Fntype::Load) { + let sub_type = type_to_sub_type(in_t[1]); + let mut inputs = match type_sub_len(in_t[1]) { + 1 => format!("a: {}", sub_type,), + 2 => format!("a: {}, b: {}", sub_type, sub_type,), + 3 => format!("a: {}, b: {}, c: {}", sub_type, sub_type, sub_type,), + 4 => format!( + "a: {}, b: {}, c: {}, d: {}", + sub_type, sub_type, sub_type, sub_type, + ), + _ => panic!("unknown type: {}", in_t[1]), + }; + inputs.push_str(&format!(", n: i64, ptr: *const i8")); + (inputs, format!(" -> {}", out_t)) + } else { + ( + match para_num { + 1 => format!("a: {}, n: i32", in_t[0]), + 2 => format!("a: {}, b: {}, n: i32", in_t[0], in_t[1]), + 3 => format!("a: {}, b: {}, c: {}, n: i32", in_t[0], in_t[1], in_t[2]), + _ => unimplemented!("unknown para_num"), + }, + format!(" -> {}", out_t), + ) + } + } else if out_t != link_aarch64_t[3] { + ( + match para_num { + 1 => format!("a: {}", link_aarch64_t[0]), + 2 => format!("a: {}, b: {}", link_aarch64_t[0], link_aarch64_t[1]), + 3 => format!( "a: {}, b: {}, c: {}", - link_arm_t[0], link_arm_t[1], link_arm_t[2] - ) - } - _ => unimplemented!("unknown para_num"), - }, - link_arm_t[3] - )); - } - if const_aarch64.is_some() { - ext_c_aarch64.push_str(&format!( - r#"#[allow(improper_ctypes)] - extern "C" {{ - #[cfg_attr(target_arch = "aarch64", link_name = "{}")] - fn {}({}) -> {}; - }} -"#, - link_aarch64, - current_fn, - match para_num { - 1 => { - format!("a: {}, n: i32", in_t[0]) - } - 2 => { - format!("a: {}, b: {}, n: i32", in_t[0], in_t[1]) - } - 3 => { - format!("a: {}, b: {}, c: {}, n: i32", in_t[0], in_t[1], in_t[2]) - } - _ => unimplemented!("unknown para_num"), - }, - out_t - )); - } - if out_t != link_aarch64_t[3] { - ext_c_aarch64.push_str(&format!( - r#"#[allow(improper_ctypes)] - extern "C" {{ + link_aarch64_t[0], link_aarch64_t[1], link_aarch64_t[2] + ), + _ => unimplemented!("unknown para_num"), + }, + format!(" -> {}", link_aarch64_t[3]), + ) + } else if matches!(fn_type, Fntype::Store) { + let sub_type = type_to_sub_type(in_t[1]); + let mut inputs = match type_sub_len(in_t[1]) { + 1 => format!("a: {}", sub_type,), + 2 => format!("a: {}, b: {}", sub_type, sub_type,), + 3 => format!("a: {}, b: {}, c: {}", sub_type, sub_type, sub_type,), + 4 => format!( + "a: {}, b: {}, c: {}, d: {}", + sub_type, sub_type, sub_type, sub_type, + ), + _ => panic!("unknown type: {}", in_t[1]), + }; + inputs.push_str(&format!(", ptr: *mut {}", type_to_native_type(in_t[0]))); + (inputs, String::new()) + } else { + (String::new(), String::new()) + } + }; + ext_c_aarch64.push_str(&format!( + r#"#[allow(improper_ctypes)] + extern "unadjusted" {{ #[cfg_attr(target_arch = "aarch64", link_name = "{}")] - fn {}({}) -> {}; + fn {}({}){}; }} "#, - link_aarch64, - current_fn, - match para_num { - 1 => { - format!("a: {}", link_aarch64_t[0]) - } - 2 => { - format!("a: {}, b: {}", link_aarch64_t[0], link_aarch64_t[1]) - } - 3 => { - format!( - "a: {}, b: {}, c: {}", - link_aarch64_t[0], link_aarch64_t[1], link_aarch64_t[2] - ) - } - _ => unimplemented!("unknown para_num"), - }, - link_aarch64_t[3] - )); - } + link_aarch64, current_fn, aarch64_ext_inputs, aarch64_ext_output, + )); }; let const_declare = if let Some(constn) = constn { format!(r#""#, constn) @@ -1602,6 +1921,7 @@ out_t, fixed, None, + false, )); } calls @@ -1622,213 +1942,137 @@ } else { String::new() }; - let trans: [&str; 2] = if out_t == link_arm_t[3] && out_t == link_aarch64_t[3] { - ["", ""] - } else { - ["transmute(", ")"] + let fn_decl = { + let fn_output = if out_t == "void" { + String::new() + } else { + format!("-> {} ", out_t) + }; + let fn_inputs = match para_num { + 1 => format!("(a: {})", in_t[0]), + 2 => format!("(a: {}, b: {})", in_t[0], in_t[1]), + 3 => format!("(a: {}, b: {}, c: {})", in_t[0], in_t[1], in_t[2]), + _ => panic!("unsupported parameter number"), + }; + format!( + "pub unsafe fn {}{}{} {}", + name, const_declare, fn_inputs, fn_output + ) }; - let call = match (multi_calls.len(), para_num, fixed.len()) { - (0, 1, 0) => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{}(a) -}}"#, - name, const_declare, in_t[0], out_t, ext_c, current_fn, - ), - (0, 1, _) => { - let fixed: Vec = fixed.iter().take(type_len(in_t[0])).cloned().collect(); + let function = if separate { + let call_arm = { + let arm_params = if let (Some(const_arm), Some(_)) = (const_arm, link_arm) { + if matches!(fn_type, Fntype::Load) { + let subs = match type_sub_len(in_t[1]) { + 1 => "b", + 2 => "b.0, b.1", + 3 => "b.0, b.1, b.2", + 4 => "b.0, b.1, b.2, b.3", + _ => "", + }; + format!( + "{}(a as *const i8, {}, {}, {})", + current_fn, + subs, + constn.as_deref().unwrap(), + type_bits(&type_to_sub_type(in_t[1])) / 8, + ) + } else { + let cnt = if const_arm.contains(':') { + let consts: Vec<_> = + const_arm.split(':').map(|v| v.trim().to_string()).collect(); + consts[0].clone() + } else { + let const_arm = const_arm.replace("ttn", &type_to_native_type(in_t[1])); + let mut cnt = String::from(in_t[1]); + cnt.push_str("("); + for i in 0..type_len(in_t[1]) { + if i != 0 { + cnt.push_str(", "); + } + cnt.push_str(&const_arm); + } + cnt.push_str(")"); + cnt + }; + match para_num { + 1 => format!("{}(a, {})", current_fn, cnt), + 2 => format!("{}(a, b, {})", current_fn, cnt), + _ => String::new(), + } + } + } else if out_t != link_arm_t[3] { + match para_num { + 1 => format!("transmute({}(a))", current_fn,), + 2 => format!("transmute({}(transmute(a), transmute(b)))", current_fn,), + _ => String::new(), + } + } else if matches!(fn_type, Fntype::Store) { + match type_sub_len(in_t[1]) { + 1 => format!("{}(a, b)", current_fn), + 2 => format!("{}(a, b.0, b.1)", current_fn), + 3 => format!("{}(a, b.0, b.1, b.2)", current_fn), + 4 => format!("{}(a, b.0, b.1, b.2, b.3)", current_fn), + _ => String::new(), + } + } else { + String::new() + }; format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - let b{}; - {}{}(a, transmute(b)) + r#"{}{{ + {}{}{} }}"#, - name, - const_declare, - in_t[0], - out_t, - values(in_t[0], &fixed), - ext_c, - current_fn, + fn_decl, multi_calls, ext_c_arm, arm_params ) - } - (0, 2, _) => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}) -> {} {{ - {}{}(a, b) -}}"#, - name, const_declare, in_t[0], in_t[1], out_t, ext_c, current_fn, - ), - (0, 3, _) => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}, c: {}) -> {} {{ - {}{}(a, b, c) -}}"#, - name, const_declare, in_t[0], in_t[1], in_t[2], out_t, ext_c, current_fn, - ), - (_, 1, _) => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{} -}}"#, - name, const_declare, in_t[0], out_t, ext_c, multi_calls, - ), - (_, 2, _) => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}) -> {} {{ - {}{} -}}"#, - name, const_declare, in_t[0], in_t[1], out_t, ext_c, multi_calls, - ), - (_, 3, _) => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}, c: {}) -> {} {{ - {}{} -}}"#, - name, const_declare, in_t[0], in_t[1], in_t[2], out_t, ext_c, multi_calls, - ), - (_, _, _) => String::new(), - }; - let call_arm = if let Some(const_arm) = const_arm { - let cnt = if const_arm.contains(':') { - let consts: Vec<_> = const_arm.split(':').map(|v| v.trim().to_string()).collect(); - consts[0].clone() - } else { - let const_arm = const_arm.replace("ttn", type_to_native_type(in_t[1])); - let mut cnt = String::from(in_t[1]); - cnt.push_str("("); - for i in 0..type_len(in_t[1]) { - if i != 0 { - cnt.push_str(", "); - } - cnt.push_str(&const_arm); - } - cnt.push_str(")"); - cnt }; - match para_num { - 1 => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{}{}(a, {}) -}}"#, - name, const_declare, in_t[0], out_t, multi_calls, ext_c_arm, current_fn, cnt - ), - 2 => format!( - r#"pub unsafe fn {}{}(a: {}, b:{}) -> {} {{ - {}{}{}(a, b, {}) -}}"#, - name, - const_declare, - in_t[0], - in_t[1], - out_t, - multi_calls, - ext_c_arm, - current_fn, - cnt - ), - _ => String::new(), - } - } else if out_t != link_arm_t[3] { - match para_num { - 1 => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{}{}{}(a){} -}}"#, - name, - const_declare, - in_t[0], - out_t, - multi_calls, - ext_c_arm, - trans[0], - current_fn, - trans[1] - ), - 2 => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}) -> {} {{ - {}{}{}{}(transmute(a), transmute(b)){} -}}"#, - name, - const_declare, - in_t[0], - in_t[1], - out_t, - multi_calls, - ext_c_arm, - trans[0], - current_fn, - trans[1], - ), - _ => String::new(), - } - } else { - String::new() - }; - let call_aarch64 = if let Some(const_aarch64) = const_aarch64 { - match para_num { - 1 => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{}{}(a, {}) -}}"#, - name, - const_declare, - in_t[0], - out_t, - multi_calls, - ext_c_aarch64, - current_fn, - const_aarch64 - ), - 2 => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}) -> {} {{ - {}{}{}(a, b, {}) -}}"#, - name, - const_declare, - in_t[0], - in_t[1], - out_t, - multi_calls, - ext_c_aarch64, - current_fn, - const_aarch64 - ), - _ => String::new(), - } - } else if out_t != link_aarch64_t[3] { - match para_num { - 1 => format!( - r#"pub unsafe fn {}{}(a: {}) -> {} {{ - {}{}{}{}(a){} -}}"#, - name, - const_declare, - in_t[0], - out_t, - multi_calls, - ext_c_aarch64, - trans[0], - current_fn, - trans[1], - ), - 2 => format!( - r#"pub unsafe fn {}{}(a: {}, b: {}) -> {} {{ - {}{}{}{}(a, b){} + let call_aarch64 = { + let aarch64_params = + if let (Some(const_aarch64), Some(_)) = (const_aarch64, link_aarch64) { + if matches!(fn_type, Fntype::Load) { + let subs = match type_sub_len(in_t[1]) { + 1 => "b", + 2 => "b.0, b.1", + 3 => "b.0, b.1, b.2", + 4 => "b.0, b.1, b.2, b.3", + _ => "", + }; + format!( + "{}({}, {} as i64, a as *const i8)", + current_fn, + subs, + constn.as_deref().unwrap() + ) + } else { + match para_num { + 1 => format!("{}(a, {})", current_fn, const_aarch64), + 2 => format!("{}(a, b, {})", current_fn, const_aarch64), + _ => String::new(), + } + } + } else if out_t != link_aarch64_t[3] { + match para_num { + 1 => format!("transmute({}(a))", current_fn,), + 2 => format!("transmute({}(a, b))", current_fn,), + _ => String::new(), + } + } else if matches!(fn_type, Fntype::Store) { + match type_sub_len(in_t[1]) { + 1 => format!("{}(b, a)", current_fn), + 2 => format!("{}(b.0, b.1, a)", current_fn), + 3 => format!("{}(b.0, b.1, b.2, a)", current_fn), + 4 => format!("{}(b.0, b.1, b.2, b.3, a)", current_fn), + _ => String::new(), + } + } else { + String::new() + }; + format!( + r#"{}{{ + {}{}{} }}"#, - name, - const_declare, - in_t[0], - in_t[1], - out_t, - multi_calls, - ext_c_aarch64, - trans[0], - current_fn, - trans[1], - ), - _ => String::new(), - } - } else { - String::new() - }; - let function = if (const_arm.is_some() && const_aarch64.is_some()) - || out_t != link_arm_t[3] - || out_t != link_aarch64_t[3] - { + fn_decl, multi_calls, ext_c_aarch64, aarch64_params + ) + }; format!( r#" {} @@ -1859,6 +2103,38 @@ call_aarch64, ) } else { + let call = { + let stmts = match (multi_calls.len(), para_num, fixed.len()) { + (0, 1, 0) => format!(r#"{}{}(a)"#, ext_c, current_fn,), + (0, 1, _) => { + let fixed: Vec = + fixed.iter().take(type_len(in_t[0])).cloned().collect(); + format!( + r#"let b{}; + {}{}(a, transmute(b))"#, + values(in_t[0], &fixed), + ext_c, + current_fn, + ) + } + (0, 2, _) => format!(r#"{}{}(a, b)"#, ext_c, current_fn,), + (0, 3, _) => format!(r#"{}{}(a, b, c)"#, ext_c, current_fn,), + (_, 1, _) => format!(r#"{}{}"#, ext_c, multi_calls,), + (_, 2, _) => format!(r#"{}{}"#, ext_c, multi_calls,), + (_, 3, _) => format!(r#"{}{}"#, ext_c, multi_calls,), + (_, _, _) => String::new(), + }; + if stmts != String::new() { + format!( + r#"{}{{ + {} +}}"#, + fn_decl, stmts + ) + } else { + String::new() + } + }; format!( r#" {} @@ -1880,16 +2156,19 @@ call, ) }; - let test = gen_test( - &name, - in_t, - &out_t, - current_tests, - [type_len(in_t[0]), type_len(in_t[1]), type_len(in_t[2])], - type_len(out_t), - para_num, - ); - + let test = match fn_type { + Fntype::Normal => gen_test( + &name, + in_t, + &out_t, + current_tests, + [type_len(in_t[0]), type_len(in_t[1]), type_len(in_t[2])], + type_len(out_t), + para_num, + ), + Fntype::Load => gen_load_test(&name, in_t, &out_t, current_tests, type_len(out_t)), + Fntype::Store => gen_store_test(&name, in_t, &out_t, current_tests, type_len(in_t[1])), + }; (function, test) } @@ -2010,6 +2289,7 @@ out_t: &str, fixed: &Vec, n: Option, + aarch64: bool, ) -> String { let params: Vec<_> = in_str.split(',').map(|v| v.trim().to_string()).collect(); assert!(params.len() > 0); @@ -2177,7 +2457,8 @@ in_t, out_t, fixed, - Some(i as i32) + Some(i as i32), + aarch64 ) ); call.push_str(&sub_match); @@ -2226,6 +2507,7 @@ out_t, fixed, n.clone(), + aarch64, ); if !param_str.is_empty() { param_str.push_str(", "); @@ -2296,6 +2578,11 @@ fn_name.push_str(type_to_suffix(in_t[1])); } else if fn_format[1] == "nself" { fn_name.push_str(type_to_n_suffix(in_t[1])); + } else if fn_format[1] == "nselfvfp4" { + fn_name.push_str(type_to_n_suffix(in_t[1])); + if !aarch64 { + fn_name.push_str("_vfp4"); + } } else if fn_format[1] == "out" { fn_name.push_str(type_to_suffix(out_t)); } else if fn_format[1] == "in0" { @@ -2305,7 +2592,21 @@ } else if fn_format[1] == "in2lane" { fn_name.push_str(&type_to_lane_suffixes(out_t, in_t[2])); } else if fn_format[1] == "signed" { - fn_name.push_str(type_to_suffix(type_to_signed(in_t[1]))); + fn_name.push_str(type_to_suffix(&type_to_signed(&String::from(in_t[1])))); + } else if fn_format[1] == "outsigned" { + fn_name.push_str(type_to_suffix(&type_to_signed(&String::from(out_t)))); + } else if fn_format[1] == "outsignednox" { + fn_name.push_str(&type_to_suffix(&type_to_sub_type(&type_to_signed( + &String::from(out_t), + )))); + } else if fn_format[1] == "outsigneddupnox" { + fn_name.push_str(&type_to_dup_suffix(&type_to_sub_type(&type_to_signed( + &String::from(out_t), + )))); + } else if fn_format[1] == "outsignedlanenox" { + fn_name.push_str(&type_to_lane_suffix(&type_to_sub_type(&type_to_signed( + &String::from(out_t), + )))); } else if fn_format[1] == "unsigned" { fn_name.push_str(type_to_suffix(type_to_unsigned(in_t[1]))); } else if fn_format[1] == "doubleself" { @@ -2315,7 +2616,7 @@ } else if fn_format[1] == "noqself" { fn_name.push_str(type_to_noq_suffix(in_t[1])); } else if fn_format[1] == "noqsigned" { - fn_name.push_str(type_to_noq_suffix(type_to_signed(in_t[1]))); + fn_name.push_str(type_to_noq_suffix(&type_to_signed(&String::from(in_t[1])))); } else if fn_format[1] == "nosuffix" { } else if fn_format[1] == "in_len" { fn_name.push_str(&type_len(in_t[1]).to_string()); @@ -2330,7 +2631,7 @@ } else if fn_format[1] == "nin0" { fn_name.push_str(type_to_n_suffix(in_t[0])); } else if fn_format[1] == "nsigned" { - fn_name.push_str(type_to_n_suffix(type_to_signed(in_t[1]))); + fn_name.push_str(type_to_n_suffix(&type_to_signed(&String::from(in_t[1])))); } else if fn_format[1] == "in_ntt" { fn_name.push_str(type_to_suffix(native_type_to_type(in_t[1]))); } else if fn_format[1] == "out_ntt" { @@ -2351,14 +2652,14 @@ let type1 = if types[0] == "element_t" { type_to_native_type(in_t[1]) } else { - &types[0] + String::from(&types[0]) }; let type2 = if types[1] == "element_t" { type_to_native_type(in_t[1]) } else { - &types[1] + String::from(&types[1]) }; - fn_name.push_str(&format!("::<{}, {}>", type1, type2)); + fn_name.push_str(&format!("::<{}, {}>", &type1, &type2)); } else { fn_name.push_str(&fn_format[2]); } @@ -2410,6 +2711,8 @@ )> = Vec::new(); let mut multi_fn: Vec = Vec::new(); let mut target: TargetFeature = Default; + let mut fn_type: Fntype = Fntype::Normal; + let mut separate = false; // // THIS FILE IS GENERATED FORM neon.spec DO NOT CHANGE IT MANUALLY @@ -2491,6 +2794,8 @@ n = None; multi_fn = Vec::new(); target = Default; + fn_type = Fntype::Normal; + separate = false; } else if line.starts_with("//") { } else if line.starts_with("name = ") { current_name = Some(String::from(&line[7..])); @@ -2520,6 +2825,12 @@ suffix = NoQNSuffix; } else if line.starts_with("out-suffix") { suffix = OutSuffix; + } else if line.starts_with("out-nox") { + suffix = OutNox; + } else if line.starts_with("out-dup-nox") { + suffix = OutDupNox; + } else if line.starts_with("out-lane-nox") { + suffix = OutLaneNox; } else if line.starts_with("lane-suffixes") { suffix = Lane; } else if line.starts_with("in2-suffix") { @@ -2547,10 +2858,17 @@ link_arm = Some(String::from(&line[11..])); } else if line.starts_with("const-arm = ") { const_arm = Some(String::from(&line[12..])); + } else if line.starts_with("load_fn") { + fn_type = Fntype::Load; + } else if line.starts_with("store_fn") { + fn_type = Fntype::Store; + } else if line.starts_with("arm-aarch64-separate") { + separate = true; } else if line.starts_with("target = ") { target = match Some(String::from(&line[9..])) { Some(input) => match input.as_str() { "v7" => ArmV7, + "vfp4" => Vfp4, "fp-armv8" => FPArmV8, "aes" => AES, _ => Default, @@ -2593,7 +2911,11 @@ panic!("Bad spec: {}", line) } if b.len() == 0 { - para_num = 1; + if matches!(fn_type, Fntype::Store) { + para_num = 2; + } else { + para_num = 1; + } } else if c.len() != 0 { para_num = 3; } @@ -2618,6 +2940,8 @@ target, &fixed, &multi_fn, + fn_type, + separate, ); out_arm.push_str(&function); tests_arm.push_str(&test); @@ -2638,6 +2962,7 @@ target, &fixed, &multi_fn, + fn_type, ); out_aarch64.push_str(&function); tests_aarch64.push_str(&test); diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-test/src/disassembly.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-test/src/disassembly.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-test/src/disassembly.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-test/src/disassembly.rs 2021-11-29 19:27:28.000000000 +0000 @@ -67,25 +67,18 @@ String::from_utf8_lossy(Vec::leak(output.stdout)) } else if cfg!(target_os = "windows") { panic!("disassembly unimplemented") - } else if cfg!(target_os = "macos") { - let output = Command::new("otool") - .arg("-vt") - .arg(&me) - .output() - .expect("failed to execute otool"); - println!( - "{}\n{}", - output.status, - String::from_utf8_lossy(&output.stderr) - ); - assert!(output.status.success()); - - String::from_utf8_lossy(Vec::leak(output.stdout)) } else { let objdump = env::var("OBJDUMP").unwrap_or_else(|_| "objdump".to_string()); + let add_args = if cfg!(target_os = "macos") && cfg!(target_arch = "aarch64") { + // Target features need to be enabled for LLVM objdump on Macos ARM64 + vec!["--mattr=+v8.6a,+crypto,+tme"] + } else { + vec![] + }; let output = Command::new(objdump.clone()) .arg("--disassemble") .arg("--no-show-raw-insn") + .args(add_args) .arg(&me) .output() .unwrap_or_else(|_| panic!("failed to execute objdump. OBJDUMP={}", objdump)); @@ -132,16 +125,7 @@ cached_header = None; break; } - let parts = if cfg!(target_os = "macos") { - // Each line of instructions should look like: - // - // $addr $instruction... - instruction - .split_whitespace() - .skip(1) - .map(std::string::ToString::to_string) - .collect::>() - } else if cfg!(target_env = "msvc") { + let mut parts = if cfg!(target_env = "msvc") { // Each line looks like: // // > $addr: ab cd ef $instr.. @@ -168,6 +152,29 @@ .map(std::string::ToString::to_string) .collect::>() }; + + if cfg!(target_arch = "aarch64") { + // Normalize [us]shll.* ..., #0 instructions to the preferred form: [us]xtl.* ... + // as LLVM objdump does not do that. + // See https://developer.arm.com/documentation/ddi0602/latest/SIMD-FP-Instructions/UXTL--UXTL2--Unsigned-extend-Long--an-alias-of-USHLL--USHLL2- + // and https://developer.arm.com/documentation/ddi0602/latest/SIMD-FP-Instructions/SXTL--SXTL2--Signed-extend-Long--an-alias-of-SSHLL--SSHLL2- + // for details. + match (parts.first(), parts.last()) { + (Some(instr), Some(last_arg)) + if (instr.starts_with("ushll.") || instr.starts_with("sshll.")) + && last_arg == "#0" => + { + assert_eq!(parts.len(), 4); + let mut new_parts = Vec::with_capacity(3); + let new_instr = format!("{}{}{}", &instr[..1], "xtl", &instr[5..]); + new_parts.push(new_instr); + new_parts.push(parts[1].clone()); + new_parts.push(parts[2][0..parts[2].len() - 1].to_owned()); // strip trailing comma + parts = new_parts; + } + _ => {} + }; + } instructions.push(parts.join(" ")); } let function = Function { diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-test/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-test/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-test/src/lib.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-test/src/lib.rs 2021-11-29 19:27:28.000000000 +0000 @@ -14,7 +14,7 @@ pub use assert_instr_macro::*; pub use simd_test_macro::*; -use std::{cmp, collections::HashSet, env, hash, hint::black_box, str, sync::atomic::AtomicPtr}; +use std::{cmp, collections::HashSet, env, hash, hint::black_box, str}; cfg_if! { if #[cfg(target_arch = "wasm32")] { @@ -76,31 +76,36 @@ instrs = &instrs[..instrs.len() - 1]; } + // Look for `expected` as the first part of any instruction in this + // function, e.g., tzcntl in tzcntl %rax,%rax. + // // There are two cases when the expected instruction is nop: // 1. The expected intrinsic is compiled away so we can't // check for it - aka the intrinsic is not generating any code. // 2. It is a mark, indicating that the instruction will be // compiled into other instructions - mainly because of llvm // optimization. - if expected == "nop" { - return; - } + let found = expected == "nop" || instrs.iter().any(|s| s.starts_with(expected)); - // Look for `expected` as the first part of any instruction in this - // function, e.g., tzcntl in tzcntl %rax,%rax. - let found = instrs.iter().any(|s| s.starts_with(expected)); - - // Look for `call` instructions in the disassembly to detect whether - // inlining failed: all intrinsics are `#[inline(always)]`, so - // calling one intrinsic from another should not generate `call` - // instructions. - let inlining_failed = instrs.windows(2).any(|s| { - // On 32-bit x86 position independent code will call itself and be - // immediately followed by a `pop` to learn about the current address. - // Let's not take that into account when considering whether a function - // failed inlining something. - s[0].contains("call") && (!cfg!(target_arch = "x86") || s[1].contains("pop")) - }); + // Look for subroutine call instructions in the disassembly to detect whether + // inlining failed: all intrinsics are `#[inline(always)]`, so calling one + // intrinsic from another should not generate subroutine call instructions. + let inlining_failed = if cfg!(target_arch = "x86_64") || cfg!(target_arch = "wasm32") { + instrs.iter().any(|s| s.starts_with("call ")) + } else if cfg!(target_arch = "x86") { + instrs.windows(2).any(|s| { + // On 32-bit x86 position independent code will call itself and be + // immediately followed by a `pop` to learn about the current address. + // Let's not take that into account when considering whether a function + // failed inlining something. + s[0].starts_with("call ") && s[1].starts_with("pop") // FIXME: original logic but does not match comment + }) + } else if cfg!(target_arch = "aarch64") { + instrs.iter().any(|s| s.starts_with("bl ")) + } else { + // FIXME: Add detection for other archs + false + }; let instruction_limit = std::env::var("STDARCH_ASSERT_INSTR_LIMIT") .ok() @@ -124,6 +129,9 @@ // vfmaq_n_f32_vfma : #instructions = 26 >= 22 (limit) "usad8" | "vfma" | "vfms" => 27, "qadd8" | "qsub8" | "sadd8" | "sel" | "shadd8" | "shsub8" | "usub8" | "ssub8" => 29, + // core_arch/src/arm_shared/simd32 + // vst1q_s64_x4_vst1 : #instructions = 40 >= 22 (limit) + "vst1" => 41, // Temporary, currently the fptosi.sat and fptoui.sat LLVM // intrinsics emit unnecessary code on arm. This can be @@ -164,8 +172,8 @@ ); } else if inlining_failed { panic!( - "instruction found, but the disassembly contains `call` \ - instructions, which hint that inlining failed" + "instruction found, but the disassembly contains subroutine \ + call instructions, which hint that inlining failed" ); } } @@ -178,4 +186,4 @@ } // See comment in `assert-instr-macro` crate for why this exists -pub static _DONT_DEDUP: AtomicPtr = AtomicPtr::new(b"".as_ptr() as *mut _); +pub static mut _DONT_DEDUP: *const u8 = std::ptr::null(); diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-verify/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-verify/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-verify/src/lib.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-verify/src/lib.rs 2021-11-29 19:27:28.000000000 +0000 @@ -15,7 +15,14 @@ #[proc_macro] pub fn arm_functions(input: TokenStream) -> TokenStream { - functions(input, &["core_arch/src/arm", "core_arch/src/aarch64"]) + functions( + input, + &[ + "core_arch/src/arm", + "core_arch/src/aarch64", + "core_arch/src/arm_shared/neon", + ], + ) } #[proc_macro] @@ -218,11 +225,29 @@ "int8x16_t" => quote! { &I8X16 }, "int16x2_t" => quote! { &I16X2 }, "int16x4_t" => quote! { &I16X4 }, + "int16x4x2_t" => quote! { &I16X4X2 }, + "int16x4x3_t" => quote! { &I16X4X3 }, + "int16x4x4_t" => quote! { &I16X4X4 }, "int16x8_t" => quote! { &I16X8 }, + "int16x8x2_t" => quote! { &I16X8X2 }, + "int16x8x3_t" => quote! { &I16X8X3 }, + "int16x8x4_t" => quote! { &I16X8X4 }, "int32x2_t" => quote! { &I32X2 }, + "int32x2x2_t" => quote! { &I32X2X2 }, + "int32x2x3_t" => quote! { &I32X2X3 }, + "int32x2x4_t" => quote! { &I32X2X4 }, "int32x4_t" => quote! { &I32X4 }, + "int32x4x2_t" => quote! { &I32X4X2 }, + "int32x4x3_t" => quote! { &I32X4X3 }, + "int32x4x4_t" => quote! { &I32X4X4 }, "int64x1_t" => quote! { &I64X1 }, + "int64x1x2_t" => quote! { &I64X1X2 }, + "int64x1x3_t" => quote! { &I64X1X3 }, + "int64x1x4_t" => quote! { &I64X1X4 }, "int64x2_t" => quote! { &I64X2 }, + "int64x2x2_t" => quote! { &I64X2X2 }, + "int64x2x3_t" => quote! { &I64X2X3 }, + "int64x2x4_t" => quote! { &I64X2X4 }, "uint8x8_t" => quote! { &U8X8 }, "uint8x4_t" => quote! { &U8X4 }, "uint8x8x2_t" => quote! { &U8X8X2 }, @@ -233,15 +258,45 @@ "uint8x8x4_t" => quote! { &U8X8X4 }, "uint8x16_t" => quote! { &U8X16 }, "uint16x4_t" => quote! { &U16X4 }, + "uint16x4x2_t" => quote! { &U16X4X2 }, + "uint16x4x3_t" => quote! { &U16X4X3 }, + "uint16x4x4_t" => quote! { &U16X4X4 }, "uint16x8_t" => quote! { &U16X8 }, + "uint16x8x2_t" => quote! { &U16X8X2 }, + "uint16x8x3_t" => quote! { &U16X8X3 }, + "uint16x8x4_t" => quote! { &U16X8X4 }, "uint32x2_t" => quote! { &U32X2 }, + "uint32x2x2_t" => quote! { &U32X2X2 }, + "uint32x2x3_t" => quote! { &U32X2X3 }, + "uint32x2x4_t" => quote! { &U32X2X4 }, "uint32x4_t" => quote! { &U32X4 }, + "uint32x4x2_t" => quote! { &U32X4X2 }, + "uint32x4x3_t" => quote! { &U32X4X3 }, + "uint32x4x4_t" => quote! { &U32X4X4 }, "uint64x1_t" => quote! { &U64X1 }, + "uint64x1x2_t" => quote! { &U64X1X2 }, + "uint64x1x3_t" => quote! { &U64X1X3 }, + "uint64x1x4_t" => quote! { &U64X1X4 }, "uint64x2_t" => quote! { &U64X2 }, + "uint64x2x2_t" => quote! { &U64X2X2 }, + "uint64x2x3_t" => quote! { &U64X2X3 }, + "uint64x2x4_t" => quote! { &U64X2X4 }, "float32x2_t" => quote! { &F32X2 }, + "float32x2x2_t" => quote! { &F32X2X2 }, + "float32x2x3_t" => quote! { &F32X2X3 }, + "float32x2x4_t" => quote! { &F32X2X4 }, "float32x4_t" => quote! { &F32X4 }, + "float32x4x2_t" => quote! { &F32X4X2 }, + "float32x4x3_t" => quote! { &F32X4X3 }, + "float32x4x4_t" => quote! { &F32X4X4 }, "float64x1_t" => quote! { &F64X1 }, + "float64x1x2_t" => quote! { &F64X1X2 }, + "float64x1x3_t" => quote! { &F64X1X3 }, + "float64x1x4_t" => quote! { &F64X1X4 }, "float64x2_t" => quote! { &F64X2 }, + "float64x2x2_t" => quote! { &F64X2X2 }, + "float64x2x3_t" => quote! { &F64X2X3 }, + "float64x2x4_t" => quote! { &F64X2X4 }, "poly8x8_t" => quote! { &POLY8X8 }, "poly8x8x2_t" => quote! { &POLY8X8X2 }, "poly8x8x3_t" => quote! { &POLY8X8X3 }, @@ -254,7 +309,19 @@ "poly64x2_t" => quote! { &POLY64X2 }, "poly8x16_t" => quote! { &POLY8X16 }, "poly16x4_t" => quote! { &POLY16X4 }, + "poly16x4x2_t" => quote! { &P16X4X2 }, + "poly16x4x3_t" => quote! { &P16X4X3 }, + "poly16x4x4_t" => quote! { &P16X4X4 }, "poly16x8_t" => quote! { &POLY16X8 }, + "poly16x8x2_t" => quote! { &P16X8X2 }, + "poly16x8x3_t" => quote! { &P16X8X3 }, + "poly16x8x4_t" => quote! { &P16X8X4 }, + "poly64x1x2_t" => quote! { &P64X1X2 }, + "poly64x1x3_t" => quote! { &P64X1X3 }, + "poly64x1x4_t" => quote! { &P64X1X4 }, + "poly64x2x2_t" => quote! { &P64X2X2 }, + "poly64x2x3_t" => quote! { &P64X2X3 }, + "poly64x2x4_t" => quote! { &P64X2X4 }, "p128" => quote! { &P128 }, "v16i8" => quote! { &v16i8 }, diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-verify/tests/arm.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-verify/tests/arm.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/stdarch-verify/tests/arm.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/stdarch-verify/tests/arm.rs 2021-11-29 19:27:28.000000000 +0000 @@ -411,65 +411,6 @@ "__smusdx", "__usad8", "__usada8", - "vld1_s8", - "vld1q_s8", - "vld1q_s8", - "vld1_s16", - "vld1q_s16", - "vld1_s32", - "vld1q_s32", - "vld1_s64", - "vld1q_s64", - "vld1_u8", - "vld1q_u8", - "vld1_u16", - "vld1q_u16", - "vld1_u32", - "vld1q_u32", - "vld1_u64", - "vld1q_u64", - "vld1_p8", - "vld1q_p8", - "vld1_p16", - "vld1q_p16", - "vld1_f32", - "vld1q_f32", - "vld1_f64", - "vld1q_f64", - "vst1_s8", - "vst1q_s8", - "vst1_s16", - "vst1q_s16", - "vst1_s32", - "vst1q_s32", - "vst1_s64", - "vst1q_s64", - "vst1_u8", - "vst1q_u8", - "vst1_u16", - "vst1q_u16", - "vst1_u32", - "vst1q_u32", - "vst1_u64", - "vst1q_u64", - "vst1_p8", - "vst1q_p8", - "vst1_p16", - "vst1q_p16", - "vst1_f32", - "vst1q_f32", - "vpadal_s8", - "vpadal_s16", - "vpadal_s32", - "vpadalq_s8", - "vpadalq_s16", - "vpadalq_s32", - "vpadal_u8", - "vpadal_u16", - "vpadal_u32", - "vpadalq_u8", - "vpadalq_u16", - "vpadalq_u32", "__ldrex", "__strex", "__ldrexb", @@ -515,12 +456,36 @@ "vqrdmlahh_laneq_s16", "vqrdmlahs_lane_s32", "vqrdmlahs_laneq_s32", + "vqrdmlah_s16", + "vqrdmlah_s32", + "vqrdmlahq_s16", + "vqrdmlahq_s32", + "vqrdmlah_lane_s16", + "vqrdmlah_laneq_s16", + "vqrdmlahq_lane_s16", + "vqrdmlahq_laneq_s16", + "vqrdmlah_lane_s32", + "vqrdmlah_laneq_s32", + "vqrdmlahq_lane_s32", + "vqrdmlahq_laneq_s32", "vqrdmlshh_s16", "vqrdmlshs_s32", "vqrdmlshh_lane_s16", "vqrdmlshh_laneq_s16", "vqrdmlshs_lane_s32", "vqrdmlshs_laneq_s32", + "vqrdmlsh_s16", + "vqrdmlshq_s16", + "vqrdmlsh_s32", + "vqrdmlshq_s32", + "vqrdmlsh_lane_s16", + "vqrdmlsh_laneq_s16", + "vqrdmlshq_lane_s16", + "vqrdmlshq_laneq_s16", + "vqrdmlsh_lane_s32", + "vqrdmlsh_laneq_s32", + "vqrdmlshq_lane_s32", + "vqrdmlshq_laneq_s32", "__dbg", ]; let arm = match map.get(rust.name) { diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs --- rustc-1.56.0+dfsg1+llvm/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs 2021-11-29 19:27:28.000000000 +0000 @@ -1,5 +1,5 @@ //! Parses ELF auxiliary vectors. -#![cfg_attr(not(target_arch = "aarch64"), allow(dead_code))] +#![allow(dead_code)] pub(crate) const AT_NULL: usize = 0; @@ -89,11 +89,10 @@ #[cfg(not(feature = "std_detect_dlsym_getauxval"))] { - let hwcap = unsafe { libc::getauxval(AT_HWCAP as libc::c_ulong) as usize }; - // Targets with only AT_HWCAP: #[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))] { + let hwcap = unsafe { libc::getauxval(AT_HWCAP as libc::c_ulong) as usize }; if hwcap != 0 { return Ok(AuxVec { hwcap }); } @@ -106,6 +105,7 @@ target_arch = "powerpc64" ))] { + let hwcap = unsafe { libc::getauxval(AT_HWCAP as libc::c_ulong) as usize }; let hwcap2 = unsafe { libc::getauxval(AT_HWCAP2 as libc::c_ulong) as usize }; if hwcap != 0 && hwcap2 != 0 { return Ok(AuxVec { hwcap, hwcap2 }); diff -Nru rustc-1.56.0+dfsg1+llvm/library/stdarch/.github/workflows/main.yml rustc-1.57.0+dfsg1+llvm/library/stdarch/.github/workflows/main.yml --- rustc-1.56.0+dfsg1+llvm/library/stdarch/.github/workflows/main.yml 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/stdarch/.github/workflows/main.yml 2021-11-29 19:27:28.000000000 +0000 @@ -138,9 +138,8 @@ norun: true - target: aarch64-unknown-linux-gnu os: ubuntu-latest - # Temporarily disabled because otool crashes with "Out of memory", seems Github CI issue - #- target: x86_64-apple-darwin - # os: macos-latest + - target: x86_64-apple-darwin + os: macos-11 - target: x86_64-pc-windows-msvc os: windows-latest - target: i686-pc-windows-msvc diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/Cargo.toml rustc-1.57.0+dfsg1+llvm/library/test/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/library/test/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -33,3 +33,4 @@ profiler = ["std/profiler"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] +std_detect_env_override = ["std/std_detect_env_override"] diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/cli.rs rustc-1.57.0+dfsg1+llvm/library/test/src/cli.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/cli.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/cli.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,6 +21,8 @@ pub nocapture: bool, pub color: ColorConfig, pub format: OutputFormat, + pub shuffle: bool, + pub shuffle_seed: Option, pub test_threads: Option, pub skip: Vec, pub time_options: Option, @@ -138,6 +140,13 @@ `CRITICAL_TIME` here means the limit that should not be exceeded by test. ", + ) + .optflag("", "shuffle", "Run tests in random order") + .optopt( + "", + "shuffle-seed", + "Run tests in random order; seed the random number generator with SEED", + "SEED", ); opts } @@ -155,6 +164,12 @@ --test-threads flag or the RUST_TEST_THREADS environment variable when running tests (set it to 1). +By default, the tests are run in alphabetical order. Use --shuffle or set +RUST_TEST_SHUFFLE to run the tests in random order. Pass the generated +"shuffle seed" to --shuffle-seed (or set RUST_TEST_SHUFFLE_SEED) to run the +tests in the same order again. Note that --shuffle and --shuffle-seed do not +affect whether the tests are run in parallel. + All tests have their standard output and standard error captured by default. This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE environment variable to a value other than "0". Logging is not captured by default. @@ -218,6 +233,21 @@ }}; } +// Gets the option value and checks if unstable features are enabled. +macro_rules! unstable_optopt { + ($matches:ident, $allow_unstable:ident, $option_name:literal) => {{ + let opt = $matches.opt_str($option_name); + if !$allow_unstable && opt.is_some() { + return Err(format!( + "The \"{}\" option is only accepted on the nightly compiler with -Z unstable-options", + $option_name + )); + } + + opt + }}; +} + // Implementation of `parse_opts` that doesn't care about help message // and returns a `Result`. fn parse_opts_impl(matches: getopts::Matches) -> OptRes { @@ -227,6 +257,8 @@ let force_run_in_process = unstable_optflag!(matches, allow_unstable, "force-run-in-process"); let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic"); let time_options = get_time_options(&matches, allow_unstable)?; + let shuffle = get_shuffle(&matches, allow_unstable)?; + let shuffle_seed = get_shuffle_seed(&matches, allow_unstable)?; let include_ignored = matches.opt_present("include-ignored"); let quiet = matches.opt_present("quiet"); @@ -260,6 +292,8 @@ nocapture, color, format, + shuffle, + shuffle_seed, test_threads, skip, time_options, @@ -303,6 +337,46 @@ Ok(options) } +fn get_shuffle(matches: &getopts::Matches, allow_unstable: bool) -> OptPartRes { + let mut shuffle = unstable_optflag!(matches, allow_unstable, "shuffle"); + if !shuffle && allow_unstable { + shuffle = match env::var("RUST_TEST_SHUFFLE") { + Ok(val) => &val != "0", + Err(_) => false, + }; + } + + Ok(shuffle) +} + +fn get_shuffle_seed(matches: &getopts::Matches, allow_unstable: bool) -> OptPartRes> { + let mut shuffle_seed = match unstable_optopt!(matches, allow_unstable, "shuffle-seed") { + Some(n_str) => match n_str.parse::() { + Ok(n) => Some(n), + Err(e) => { + return Err(format!( + "argument for --shuffle-seed must be a number \ + (error: {})", + e + )); + } + }, + None => None, + }; + + if shuffle_seed.is_none() && allow_unstable { + shuffle_seed = match env::var("RUST_TEST_SHUFFLE_SEED") { + Ok(val) => match val.parse::() { + Ok(n) => Some(n), + Err(_) => panic!("RUST_TEST_SHUFFLE_SEED is `{}`, should be a number.", val), + }, + Err(_) => None, + }; + } + + Ok(shuffle_seed) +} + fn get_test_threads(matches: &getopts::Matches) -> OptPartRes> { let test_threads = match matches.opt_str("test-threads") { Some(n_str) => match n_str.parse::() { diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/console.rs rustc-1.57.0+dfsg1+llvm/library/test/src/console.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/console.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/console.rs 2021-11-29 19:27:11.000000000 +0000 @@ -225,9 +225,9 @@ out: &mut dyn OutputFormatter, ) -> io::Result<()> { match (*event).clone() { - TestEvent::TeFiltered(ref filtered_tests) => { + TestEvent::TeFiltered(ref filtered_tests, shuffle_seed) => { st.total = filtered_tests.len(); - out.write_run_start(filtered_tests.len())?; + out.write_run_start(filtered_tests.len(), shuffle_seed)?; } TestEvent::TeFilteredOut(filtered_out) => { st.filtered_out = filtered_out; diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/event.rs rustc-1.57.0+dfsg1+llvm/library/test/src/event.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/event.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/event.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,7 +28,7 @@ #[derive(Debug, Clone)] pub enum TestEvent { - TeFiltered(Vec), + TeFiltered(Vec, Option), TeWait(TestDesc), TeResult(CompletedTest), TeTimeout(TestDesc), diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/json.rs rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/json.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/json.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/json.rs 2021-11-29 19:27:11.000000000 +0000 @@ -60,10 +60,15 @@ } impl OutputFormatter for JsonFormatter { - fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { + let shuffle_seed_json = if let Some(shuffle_seed) = shuffle_seed { + format!(r#", "shuffle_seed": {}"#, shuffle_seed) + } else { + String::new() + }; self.writeln_message(&*format!( - r#"{{ "type": "suite", "event": "started", "test_count": {} }}"#, - test_count + r#"{{ "type": "suite", "event": "started", "test_count": {}{} }}"#, + test_count, shuffle_seed_json )) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/junit.rs rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/junit.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/junit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/junit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -27,9 +27,14 @@ } impl OutputFormatter for JunitFormatter { - fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> { + fn write_run_start( + &mut self, + _test_count: usize, + _shuffle_seed: Option, + ) -> io::Result<()> { // We write xml header on run start - self.write_message(&"") + self.out.write_all(b"\n")?; + self.write_message("") } fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> { @@ -53,7 +58,7 @@ // Because the testsuit node holds some of the information as attributes, we can't write it // until all of the tests has ran. Instead of writting every result as they come in, we add // them to a Vec and write them all at once when run is complete. - let duration = exec_time.map(|t| t.0.clone()).unwrap_or_default(); + let duration = exec_time.map(|t| t.0).unwrap_or_default(); self.results.push((desc.clone(), result.clone(), duration)); Ok(()) } @@ -133,6 +138,8 @@ self.write_message("")?; self.write_message("")?; + self.out.write_all(b"\n\n")?; + Ok(state.failed == 0) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/mod.rs rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ pub(crate) use self::terse::TerseFormatter; pub(crate) trait OutputFormatter { - fn write_run_start(&mut self, test_count: usize) -> io::Result<()>; + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()>; fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>; fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>; fn write_result( diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/pretty.rs rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/pretty.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/pretty.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/pretty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -181,9 +181,14 @@ } impl OutputFormatter for PrettyFormatter { - fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { let noun = if test_count != 1 { "tests" } else { "test" }; - self.write_plain(&format!("\nrunning {} {}\n", test_count, noun)) + let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed { + format!(" (shuffle seed: {})", shuffle_seed) + } else { + String::new() + }; + self.write_plain(&format!("\nrunning {} {}{}\n", test_count, noun, shuffle_seed_msg)) } fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/terse.rs rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/terse.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/formatters/terse.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/formatters/terse.rs 2021-11-29 19:27:11.000000000 +0000 @@ -170,10 +170,15 @@ } impl OutputFormatter for TerseFormatter { - fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { self.total_test_count = test_count; let noun = if test_count != 1 { "tests" } else { "test" }; - self.write_plain(&format!("\nrunning {} {}\n", test_count, noun)) + let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed { + format!(" (shuffle seed: {})", shuffle_seed) + } else { + String::new() + }; + self.write_plain(&format!("\nrunning {} {}{}\n", test_count, noun, shuffle_seed_msg)) } fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/helpers/concurrency.rs rustc-1.57.0+dfsg1+llvm/library/test/src/helpers/concurrency.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/helpers/concurrency.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/helpers/concurrency.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,6 @@ _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value), } } else { - thread::available_concurrency().map(|n| n.get()).unwrap_or(1) + thread::available_parallelism().map(|n| n.get()).unwrap_or(1) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/helpers/mod.rs rustc-1.57.0+dfsg1+llvm/library/test/src/helpers/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/helpers/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/helpers/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,3 +5,4 @@ pub mod exit_code; pub mod isatty; pub mod metrics; +pub mod shuffle; diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/helpers/shuffle.rs rustc-1.57.0+dfsg1+llvm/library/test/src/helpers/shuffle.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/helpers/shuffle.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/helpers/shuffle.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,67 @@ +use crate::cli::TestOpts; +use crate::types::{TestDescAndFn, TestId, TestName}; +use std::collections::hash_map::DefaultHasher; +use std::hash::Hasher; +use std::time::{SystemTime, UNIX_EPOCH}; + +pub fn get_shuffle_seed(opts: &TestOpts) -> Option { + opts.shuffle_seed.or_else(|| { + if opts.shuffle { + Some( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Failed to get system time") + .as_nanos() as u64, + ) + } else { + None + } + }) +} + +pub fn shuffle_tests(shuffle_seed: u64, tests: &mut [(TestId, TestDescAndFn)]) { + let test_names: Vec<&TestName> = tests.iter().map(|test| &test.1.desc.name).collect(); + let test_names_hash = calculate_hash(&test_names); + let mut rng = Rng::new(shuffle_seed, test_names_hash); + shuffle(&mut rng, tests); +} + +// `shuffle` is from `rust-analyzer/src/cli/analysis_stats.rs`. +fn shuffle(rng: &mut Rng, slice: &mut [T]) { + for i in 0..slice.len() { + randomize_first(rng, &mut slice[i..]); + } + + fn randomize_first(rng: &mut Rng, slice: &mut [T]) { + assert!(!slice.is_empty()); + let idx = rng.rand_range(0..slice.len() as u64) as usize; + slice.swap(0, idx); + } +} + +struct Rng { + state: u64, + extra: u64, +} + +impl Rng { + fn new(seed: u64, extra: u64) -> Self { + Self { state: seed, extra } + } + + fn rand_range(&mut self, range: core::ops::Range) -> u64 { + self.rand_u64() % (range.end - range.start) + range.start + } + + fn rand_u64(&mut self) -> u64 { + self.state = calculate_hash(&(self.state, self.extra)); + self.state + } +} + +// `calculate_hash` is from `core/src/hash/mod.rs`. +fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/test/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -23,7 +23,7 @@ #![feature(libc)] #![feature(rustc_private)] #![feature(nll)] -#![feature(available_concurrency)] +#![feature(available_parallelism)] #![feature(bench_black_box)] #![feature(internal_output_capture)] #![feature(panic_unwind)] @@ -91,6 +91,7 @@ use event::{CompletedTest, TestEvent}; use helpers::concurrency::get_concurrency; use helpers::exit_code::get_exit_code; +use helpers::shuffle::{get_shuffle_seed, shuffle_tests}; use options::{Concurrent, RunStrategy}; use test_result::*; use time::TestExecTime; @@ -247,7 +248,9 @@ let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect(); - let event = TestEvent::TeFiltered(filtered_descs); + let shuffle_seed = get_shuffle_seed(opts); + + let event = TestEvent::TeFiltered(filtered_descs, shuffle_seed); notify_about_test_event(event)?; let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests @@ -259,7 +262,11 @@ let concurrency = opts.test_threads.unwrap_or_else(get_concurrency); let mut remaining = filtered_tests; - remaining.reverse(); + if let Some(shuffle_seed) = shuffle_seed { + shuffle_tests(shuffle_seed, &mut remaining); + } else { + remaining.reverse(); + } let mut pending = 0; let (tx, rx) = channel::(); diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/term/terminfo/mod.rs rustc-1.57.0+dfsg1+llvm/library/test/src/term/terminfo/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/term/terminfo/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/term/terminfo/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,6 +16,7 @@ use searcher::get_dbpath_for_term; /// A parsed terminfo database entry. +#[allow(unused)] #[derive(Debug)] pub(crate) struct TermInfo { /// Names for the terminal diff -Nru rustc-1.56.0+dfsg1+llvm/library/test/src/tests.rs rustc-1.57.0+dfsg1+llvm/library/test/src/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/test/src/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/test/src/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -45,6 +45,8 @@ nocapture: false, color: AutoColor, format: OutputFormat::Pretty, + shuffle: false, + shuffle_seed: None, test_threads: None, skip: vec![], time_options: None, @@ -565,11 +567,7 @@ assert_eq!(exact.len(), 2); } -#[test] -pub fn sort_tests() { - let mut opts = TestOpts::new(); - opts.run_tests = true; - +fn sample_tests() -> Vec { let names = vec![ "sha1::test".to_string(), "isize::test_to_str".to_string(), @@ -583,26 +581,32 @@ "test::run_include_ignored_option".to_string(), "test::sort_tests".to_string(), ]; - let tests = { - fn testfn() {} - let mut tests = Vec::new(); - for name in &names { - let test = TestDescAndFn { - desc: TestDesc { - name: DynTestName((*name).clone()), - ignore: false, - should_panic: ShouldPanic::No, - allow_fail: false, - compile_fail: false, - no_run: false, - test_type: TestType::Unknown, - }, - testfn: DynTestFn(Box::new(testfn)), - }; - tests.push(test); - } - tests - }; + fn testfn() {} + let mut tests = Vec::new(); + for name in &names { + let test = TestDescAndFn { + desc: TestDesc { + name: DynTestName((*name).clone()), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + compile_fail: false, + no_run: false, + test_type: TestType::Unknown, + }, + testfn: DynTestFn(Box::new(testfn)), + }; + tests.push(test); + } + tests +} + +#[test] +pub fn sort_tests() { + let mut opts = TestOpts::new(); + opts.run_tests = true; + + let tests = sample_tests(); let filtered = filter_tests(&opts, tests); let expected = vec![ @@ -625,6 +629,71 @@ } #[test] +pub fn shuffle_tests() { + let mut opts = TestOpts::new(); + opts.shuffle = true; + + let shuffle_seed = get_shuffle_seed(&opts).unwrap(); + + let left = + sample_tests().into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::>(); + let mut right = + sample_tests().into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::>(); + + assert!(left.iter().zip(&right).all(|(a, b)| a.1.desc.name == b.1.desc.name)); + + helpers::shuffle::shuffle_tests(shuffle_seed, right.as_mut_slice()); + + assert!(left.iter().zip(right).any(|(a, b)| a.1.desc.name != b.1.desc.name)); +} + +#[test] +pub fn shuffle_tests_with_seed() { + let mut opts = TestOpts::new(); + opts.shuffle = true; + + let shuffle_seed = get_shuffle_seed(&opts).unwrap(); + + let mut left = + sample_tests().into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::>(); + let mut right = + sample_tests().into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::>(); + + helpers::shuffle::shuffle_tests(shuffle_seed, left.as_mut_slice()); + helpers::shuffle::shuffle_tests(shuffle_seed, right.as_mut_slice()); + + assert!(left.iter().zip(right).all(|(a, b)| a.1.desc.name == b.1.desc.name)); +} + +#[test] +pub fn order_depends_on_more_than_seed() { + let mut opts = TestOpts::new(); + opts.shuffle = true; + + let shuffle_seed = get_shuffle_seed(&opts).unwrap(); + + let mut left_tests = sample_tests(); + let mut right_tests = sample_tests(); + + left_tests.pop(); + right_tests.remove(0); + + let mut left = + left_tests.into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::>(); + let mut right = + right_tests.into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::>(); + + assert_eq!(left.len(), right.len()); + + assert!(left.iter().zip(&right).all(|(a, b)| a.0 == b.0)); + + helpers::shuffle::shuffle_tests(shuffle_seed, left.as_mut_slice()); + helpers::shuffle::shuffle_tests(shuffle_seed, right.as_mut_slice()); + + assert!(left.iter().zip(right).any(|(a, b)| a.0 != b.0)); +} + +#[test] pub fn test_metricmap_compare() { let mut m1 = MetricMap::new(); let mut m2 = MetricMap::new(); diff -Nru rustc-1.56.0+dfsg1+llvm/library/unwind/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/unwind/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/unwind/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/unwind/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -23,6 +23,7 @@ unix, windows, target_os = "psp", + target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx"), ))] { mod libunwind; @@ -62,7 +63,7 @@ // don't want to duplicate it here. #[cfg(all( target_os = "linux", - target_env = "gnu", + any(target_env = "gnu", target_env = "uclibc"), not(feature = "llvm-libunwind"), not(feature = "system-llvm-libunwind") ))] @@ -71,7 +72,7 @@ #[cfg(all( target_os = "linux", - target_env = "gnu", + any(target_env = "gnu", target_env = "uclibc"), not(feature = "llvm-libunwind"), feature = "system-llvm-libunwind" ))] diff -Nru rustc-1.56.0+dfsg1+llvm/RELEASES.md rustc-1.57.0+dfsg1+llvm/RELEASES.md --- rustc-1.56.0+dfsg1+llvm/RELEASES.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/RELEASES.md 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,125 @@ +Version 1.57.0 (2021-12-02) +========================== + +Language +-------- + +- [Macro attributes may follow `#[derive]` and will see the original (pre-`cfg`) input.][87220] +- [Accept curly-brace macros in expressions, like `m!{ .. }.method()` and `m!{ .. }?`.][88690] +- [Allow panicking in constant evaluation.][89508] + +Compiler +-------- + +- [Create more accurate debuginfo for vtables.][89597] +- [Add `armv6k-nintendo-3ds` at Tier 3\*.][88529] +- [Add `armv7-unknown-linux-uclibceabihf` at Tier 3\*.][88952] +- [Add `m68k-unknown-linux-gnu` at Tier 3\*.][88321] +- [Add SOLID targets at Tier 3\*:][86191] `aarch64-kmc-solid_asp3`, `armv7a-kmc-solid_asp3-eabi`, `armv7a-kmc-solid_asp3-eabihf` + +\* Refer to Rust's [platform support page][platform-support-doc] for more + information on Rust's tiered platform support. + +Libraries +--------- + +- [Avoid allocations and copying in `Vec::leak`][89337] +- [Add `#[repr(i8)]` to `Ordering`][89507] +- [Optimize `File::read_to_end` and `read_to_string`][89582] +- [Update to Unicode 14.0][89614] +- [Many more functions are marked `#[must_use]`][89692], producing a warning + when ignoring their return value. This helps catch mistakes such as expecting + a function to mutate a value in place rather than return a new value. + +Stabilised APIs +--------------- + +- [`[T; N]::as_mut_slice`][`array::as_mut_slice`] +- [`[T; N]::as_slice`][`array::as_slice`] +- [`collections::TryReserveError`] +- [`HashMap::try_reserve`] +- [`HashSet::try_reserve`] +- [`String::try_reserve`] +- [`String::try_reserve_exact`] +- [`Vec::try_reserve`] +- [`Vec::try_reserve_exact`] +- [`VecDeque::try_reserve`] +- [`VecDeque::try_reserve_exact`] +- [`Iterator::map_while`] +- [`iter::MapWhile`] +- [`proc_macro::is_available`] +- [`Command::get_program`] +- [`Command::get_args`] +- [`Command::get_envs`] +- [`Command::get_current_dir`] +- [`CommandArgs`] +- [`CommandEnvs`] + +These APIs are now usable in const contexts: + +- [`hint::unreachable_unchecked`] + +Cargo +----- + +- [Stabilize custom profiles][cargo/9943] + +Compatibility notes +------------------- + +Internal changes +---------------- +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc +and related tools. + +- [Added an experimental backend for codegen with `libgccjit`.][87260] + +[86191]: https://github.com/rust-lang/rust/pull/86191/ +[87220]: https://github.com/rust-lang/rust/pull/87220/ +[87260]: https://github.com/rust-lang/rust/pull/87260/ +[88243]: https://github.com/rust-lang/rust/pull/88243/ +[88321]: https://github.com/rust-lang/rust/pull/88321/ +[88529]: https://github.com/rust-lang/rust/pull/88529/ +[88690]: https://github.com/rust-lang/rust/pull/88690/ +[88952]: https://github.com/rust-lang/rust/pull/88952/ +[89337]: https://github.com/rust-lang/rust/pull/89337/ +[89507]: https://github.com/rust-lang/rust/pull/89507/ +[89508]: https://github.com/rust-lang/rust/pull/89508/ +[89582]: https://github.com/rust-lang/rust/pull/89582/ +[89597]: https://github.com/rust-lang/rust/pull/89597/ +[89614]: https://github.com/rust-lang/rust/pull/89614/ +[89692]: https://github.com/rust-lang/rust/issues/89692/ +[cargo/9943]: https://github.com/rust-lang/cargo/pull/9943/ +[`array::as_mut_slice`]: https://doc.rust-lang.org/std/primitive.array.html#method.as_mut_slice +[`array::as_slice`]: https://doc.rust-lang.org/std/primitive.array.html#method.as_slice +[`collections::TryReserveError`]: https://doc.rust-lang.org/std/collections/struct.TryReserveError.html +[`HashMap::try_reserve`]: https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.try_reserve +[`HashSet::try_reserve`]: https://doc.rust-lang.org/std/collections/hash_set/struct.HashSet.html#method.try_reserve +[`String::try_reserve`]: https://doc.rust-lang.org/alloc/string/struct.String.html#method.try_reserve +[`String::try_reserve_exact`]: https://doc.rust-lang.org/alloc/string/struct.String.html#method.try_reserve_exact +[`Vec::try_reserve`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve +[`Vec::try_reserve_exact`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve_exact +[`VecDeque::try_reserve`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.try_reserve +[`VecDeque::try_reserve_exact`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.try_reserve_exact +[`Iterator::map_while`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map_while +[`iter::MapWhile`]: https://doc.rust-lang.org/std/iter/struct.MapWhile.html +[`proc_macro::is_available`]: https://doc.rust-lang.org/proc_macro/fn.is_available.html +[`Command::get_program`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_program +[`Command::get_args`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_args +[`Command::get_envs`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_envs +[`Command::get_current_dir`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_current_dir +[`CommandArgs`]: https://doc.rust-lang.org/std/process/struct.CommandArgs.html +[`CommandEnvs`]: https://doc.rust-lang.org/std/process/struct.CommandEnvs.html + +Version 1.56.1 (2021-11-01) +=========================== + +- New lints to detect the presence of bidirectional-override Unicode + codepoints in the compiled source code ([CVE-2021-42574]) + +[CVE-2021-42574]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-42574 + Version 1.56.0 (2021-10-21) ======================== @@ -77,7 +199,7 @@ - [Cargo supports specifying a minimum supported Rust version in Cargo.toml.][`rust-version`] This has no effect at present on dependency version selection. We encourage crates to specify their minimum supported Rust version, and we encourage CI systems - that support Rust code to include a crate's specified minimum version in the text matrix for that + that support Rust code to include a crate's specified minimum version in the test matrix for that crate by default. Compatibility notes diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/bootstrap.py rustc-1.57.0+dfsg1+llvm/src/bootstrap/bootstrap.py --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/bootstrap.py 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/bootstrap.py 2021-11-29 19:27:11.000000000 +0000 @@ -4,6 +4,7 @@ import datetime import distutils.version import hashlib +import json import os import re import shutil @@ -24,19 +25,17 @@ except tarfile.CompressionError: return False -def get(url, path, verbose=False, do_verify=True): - suffix = '.sha256' - sha_url = url + suffix +def get(base, url, path, checksums, verbose=False, do_verify=True): with tempfile.NamedTemporaryFile(delete=False) as temp_file: temp_path = temp_file.name - with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as sha_file: - sha_path = sha_file.name try: if do_verify: - download(sha_path, sha_url, False, verbose) + if url not in checksums: + raise RuntimeError("src/stage0.json doesn't contain a checksum for {}".format(url)) + sha256 = checksums[url] if os.path.exists(path): - if verify(path, sha_path, False): + if verify(path, sha256, False): if verbose: print("using already-download file", path) return @@ -45,23 +44,17 @@ print("ignoring already-download file", path, "due to failed verification") os.unlink(path) - download(temp_path, url, True, verbose) - if do_verify and not verify(temp_path, sha_path, verbose): + download(temp_path, "{}/{}".format(base, url), True, verbose) + if do_verify and not verify(temp_path, sha256, verbose): raise RuntimeError("failed verification") if verbose: print("moving {} to {}".format(temp_path, path)) shutil.move(temp_path, path) finally: - delete_if_present(sha_path, verbose) - delete_if_present(temp_path, verbose) - - -def delete_if_present(path, verbose): - """Remove the given file if present""" - if os.path.isfile(path): - if verbose: - print("removing", path) - os.unlink(path) + if os.path.isfile(temp_path): + if verbose: + print("removing", temp_path) + os.unlink(temp_path) def download(path, url, probably_big, verbose): @@ -98,14 +91,12 @@ exception=exception) -def verify(path, sha_path, verbose): +def verify(path, expected, verbose): """Check if the sha256 sum of the given path is valid""" if verbose: print("verifying", path) with open(path, "rb") as source: found = hashlib.sha256(source.read()).hexdigest() - with open(sha_path, "r") as sha256sum: - expected = sha256sum.readline().split()[0] verified = found == expected if not verified: print("invalid checksum:\n" @@ -176,15 +167,6 @@ sys.exit(1) -def stage0_data(rust_root): - """Build a dictionary from stage0.txt""" - nightlies = os.path.join(rust_root, "src/stage0.txt") - with open(nightlies, 'r') as nightlies: - lines = [line.rstrip() for line in nightlies - if not line.startswith("#")] - return dict([line.split(": ", 1) for line in lines if line]) - - def format_build_time(duration): """Return a nicer format for build time @@ -295,6 +277,7 @@ 'i486': 'i686', 'i686': 'i686', 'i786': 'i686', + 'm68k': 'm68k', 'powerpc': 'powerpc', 'powerpc64': 'powerpc64', 'powerpc64le': 'powerpc64le', @@ -372,13 +355,22 @@ os.rename(tmp, filepath) +class Stage0Toolchain: + def __init__(self, stage0_payload): + self.date = stage0_payload["date"] + self.version = stage0_payload["version"] + + def channel(self): + return self.version + "-" + self.date + + class RustBuild(object): """Provide all the methods required to build Rust""" def __init__(self): - self.date = '' + self.checksums_sha256 = {} + self.stage0_compiler = None + self.stage0_rustfmt = None self._download_url = '' - self.rustc_channel = '' - self.rustfmt_channel = '' self.build = '' self.build_dir = '' self.clean = False @@ -402,11 +394,10 @@ will move all the content to the right place. """ if rustc_channel is None: - rustc_channel = self.rustc_channel - rustfmt_channel = self.rustfmt_channel + rustc_channel = self.stage0_compiler.version bin_root = self.bin_root(stage0) - key = self.date + key = self.stage0_compiler.date if not stage0: key += str(self.rustc_commit) if self.rustc(stage0).startswith(bin_root) and \ @@ -445,19 +436,23 @@ if self.rustfmt() and self.rustfmt().startswith(bin_root) and ( not os.path.exists(self.rustfmt()) - or self.program_out_of_date(self.rustfmt_stamp(), self.rustfmt_channel) + or self.program_out_of_date( + self.rustfmt_stamp(), + "" if self.stage0_rustfmt is None else self.stage0_rustfmt.channel() + ) ): - if rustfmt_channel: + if self.stage0_rustfmt is not None: tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz' - [channel, date] = rustfmt_channel.split('-', 1) - filename = "rustfmt-{}-{}{}".format(channel, self.build, tarball_suffix) + filename = "rustfmt-{}-{}{}".format( + self.stage0_rustfmt.version, self.build, tarball_suffix, + ) self._download_component_helper( - filename, "rustfmt-preview", tarball_suffix, key=date + filename, "rustfmt-preview", tarball_suffix, key=self.stage0_rustfmt.date ) self.fix_bin_or_dylib("{}/bin/rustfmt".format(bin_root)) self.fix_bin_or_dylib("{}/bin/cargo-fmt".format(bin_root)) with output(self.rustfmt_stamp()) as rustfmt_stamp: - rustfmt_stamp.write(self.rustfmt_channel) + rustfmt_stamp.write(self.stage0_rustfmt.channel()) # Avoid downloading LLVM twice (once for stage0 and once for the master rustc) if self.downloading_llvm() and stage0: @@ -465,7 +460,7 @@ # LLVM more often than necessary. # # This git command finds that commit SHA, looking for bors-authored - # merges that modified src/llvm-project or other relevant version + # commits that modified src/llvm-project or other relevant version # stamp files. # # This works even in a repository that has not yet initialized @@ -475,7 +470,7 @@ ]).decode(sys.getdefaultencoding()).strip() llvm_sha = subprocess.check_output([ "git", "rev-list", "--author=bors@rust-lang.org", "-n1", - "--merges", "--first-parent", "HEAD", + "--first-parent", "HEAD", "--", "{}/src/llvm-project".format(top_level), "{}/src/bootstrap/download-ci-llvm-stamp".format(top_level), @@ -518,7 +513,7 @@ ): if key is None: if stage0: - key = self.date + key = self.stage0_compiler.date else: key = self.rustc_commit cache_dst = os.path.join(self.build_dir, "cache") @@ -527,22 +522,38 @@ os.makedirs(rustc_cache) if stage0: - url = "{}/dist/{}".format(self._download_url, key) + base = self._download_url + url = "dist/{}".format(key) else: - url = "https://ci-artifacts.rust-lang.org/rustc-builds/{}".format(self.rustc_commit) + base = "https://ci-artifacts.rust-lang.org" + url = "rustc-builds/{}".format(self.rustc_commit) tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): - get("{}/{}".format(url, filename), tarball, verbose=self.verbose, do_verify=stage0) + get( + base, + "{}/{}".format(url, filename), + tarball, + self.checksums_sha256, + verbose=self.verbose, + do_verify=stage0, + ) unpack(tarball, tarball_suffix, self.bin_root(stage0), match=pattern, verbose=self.verbose) def _download_ci_llvm(self, llvm_sha, llvm_assertions): + if not llvm_sha: + print("error: could not find commit hash for downloading LLVM") + print("help: maybe your repository history is too shallow?") + print("help: consider disabling `download-ci-llvm`") + print("help: or fetch enough history to include one upstream commit") + exit(1) cache_prefix = "llvm-{}-{}".format(llvm_sha, llvm_assertions) cache_dst = os.path.join(self.build_dir, "cache") rustc_cache = os.path.join(cache_dst, cache_prefix) if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) - url = "https://ci-artifacts.rust-lang.org/rustc-builds/{}".format(llvm_sha) + base = "https://ci-artifacts.rust-lang.org" + url = "rustc-builds/{}".format(llvm_sha) if llvm_assertions: url = url.replace('rustc-builds', 'rustc-builds-alt') # ci-artifacts are only stored as .xz, not .gz @@ -554,7 +565,14 @@ filename = "rust-dev-nightly-" + self.build + tarball_suffix tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): - get("{}/{}".format(url, filename), tarball, verbose=self.verbose, do_verify=False) + get( + base, + "{}/{}".format(url, filename), + tarball, + self.checksums_sha256, + verbose=self.verbose, + do_verify=False, + ) unpack(tarball, tarball_suffix, self.llvm_root(), match="rust-dev", verbose=self.verbose) @@ -582,19 +600,23 @@ if ostype != "Linux": return - # Use `/etc/os-release` instead of `/etc/NIXOS`. - # The latter one does not exist on NixOS when using tmpfs as root. - try: - with open("/etc/os-release", "r") as f: - if not any(line.strip() == "ID=nixos" for line in f): - return - except FileNotFoundError: - return - if os.path.exists("/lib"): - return + # If the user has asked binaries to be patched for Nix, then + # don't check for NixOS or `/lib`, just continue to the patching. + if self.get_toml('patch-binaries-for-nix', 'build') != 'true': + # Use `/etc/os-release` instead of `/etc/NIXOS`. + # The latter one does not exist on NixOS when using tmpfs as root. + try: + with open("/etc/os-release", "r") as f: + if not any(line.strip() == "ID=nixos" for line in f): + return + except FileNotFoundError: + return + if os.path.exists("/lib"): + return - # At this point we're pretty sure the user is running NixOS - nix_os_msg = "info: you seem to be running NixOS. Attempting to patch" + # At this point we're pretty sure the user is running NixOS or + # using Nix + nix_os_msg = "info: you seem to be using Nix. Attempting to patch" print(nix_os_msg, fname) # Only build `.nix-deps` once. @@ -669,9 +691,15 @@ # Only commits merged by bors will have CI artifacts. merge_base = [ "git", "rev-list", "--author=bors@rust-lang.org", "-n1", - "--merges", "--first-parent", "HEAD" + "--first-parent", "HEAD" ] commit = subprocess.check_output(merge_base, universal_newlines=True).strip() + if not commit: + print("error: could not find commit hash for downloading rustc") + print("help: maybe your repository history is too shallow?") + print("help: consider disabling `download-rustc`") + print("help: or fetch enough history to include one upstream commit") + exit(1) # Warn if there were changes to the compiler or standard library since the ancestor commit. status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler, library]) @@ -816,7 +844,7 @@ def rustfmt(self): """Return config path for rustfmt""" - if not self.rustfmt_channel: + if self.stage0_rustfmt is None: return None return self.program_config('rustfmt') @@ -905,10 +933,9 @@ env["LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \ (os.pathsep + env["LIBRARY_PATH"]) \ if "LIBRARY_PATH" in env else "" + # preserve existing RUSTFLAGS env.setdefault("RUSTFLAGS", "") - env["RUSTFLAGS"] += " -Cdebuginfo=2" - build_section = "target.{}".format(self.build) target_features = [] if self.get_toml("crt-static", build_section) == "true": @@ -974,7 +1001,7 @@ run(["git", "submodule", "-q", "sync", module], cwd=self.rust_root, verbose=self.verbose) - update_args = ["git", "submodule", "update", "--init", "--recursive"] + update_args = ["git", "submodule", "update", "--init", "--recursive", "--depth=1"] if self.git_version >= distutils.version.LooseVersion("2.11.0"): update_args.append("--progress") update_args.append(module) @@ -1040,19 +1067,12 @@ self.update_submodule(module[0], module[1], recorded_submodules) print("Submodules updated in %.2f seconds" % (time() - start_time)) - def set_normal_environment(self): + def set_dist_environment(self, url): """Set download URL for normal environment""" if 'RUSTUP_DIST_SERVER' in os.environ: self._download_url = os.environ['RUSTUP_DIST_SERVER'] else: - self._download_url = 'https://static.rust-lang.org' - - def set_dev_environment(self): - """Set download URL for development environment""" - if 'RUSTUP_DEV_DIST_SERVER' in os.environ: - self._download_url = os.environ['RUSTUP_DEV_DIST_SERVER'] - else: - self._download_url = 'https://dev-static.rust-lang.org' + self._download_url = url def check_vendored_status(self): """Check that vendoring is configured properly""" @@ -1161,17 +1181,14 @@ build_dir = build.get_toml('build-dir', 'build') or 'build' build.build_dir = os.path.abspath(build_dir.replace("$ROOT", build.rust_root)) - data = stage0_data(build.rust_root) - build.date = data['date'] - build.rustc_channel = data['rustc'] - - if "rustfmt" in data: - build.rustfmt_channel = data['rustfmt'] + with open(os.path.join(build.rust_root, "src", "stage0.json")) as f: + data = json.load(f) + build.checksums_sha256 = data["checksums_sha256"] + build.stage0_compiler = Stage0Toolchain(data["compiler"]) + if data.get("rustfmt") is not None: + build.stage0_rustfmt = Stage0Toolchain(data["rustfmt"]) - if 'dev' in data: - build.set_dev_environment() - else: - build.set_normal_environment() + build.set_dist_environment(data["dist_server"]) build.build = args.build or build.build_triple() build.update_submodules() diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/bootstrap_test.py rustc-1.57.0+dfsg1+llvm/src/bootstrap/bootstrap_test.py --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/bootstrap_test.py 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/bootstrap_test.py 2021-11-29 19:27:11.000000000 +0000 @@ -13,38 +13,18 @@ import bootstrap -class Stage0DataTestCase(unittest.TestCase): - """Test Case for stage0_data""" - def setUp(self): - self.rust_root = tempfile.mkdtemp() - os.mkdir(os.path.join(self.rust_root, "src")) - with open(os.path.join(self.rust_root, "src", - "stage0.txt"), "w") as stage0: - stage0.write("#ignore\n\ndate: 2017-06-15\nrustc: beta\ncargo: beta\nrustfmt: beta") - - def tearDown(self): - rmtree(self.rust_root) - - def test_stage0_data(self): - """Extract data from stage0.txt""" - expected = {"date": "2017-06-15", "rustc": "beta", "cargo": "beta", "rustfmt": "beta"} - data = bootstrap.stage0_data(self.rust_root) - self.assertDictEqual(data, expected) - - class VerifyTestCase(unittest.TestCase): """Test Case for verify""" def setUp(self): self.container = tempfile.mkdtemp() self.src = os.path.join(self.container, "src.txt") - self.sums = os.path.join(self.container, "sums") self.bad_src = os.path.join(self.container, "bad.txt") content = "Hello world" + self.expected = hashlib.sha256(content.encode("utf-8")).hexdigest() + with open(self.src, "w") as src: src.write(content) - with open(self.sums, "w") as sums: - sums.write(hashlib.sha256(content.encode("utf-8")).hexdigest()) with open(self.bad_src, "w") as bad: bad.write("Hello!") @@ -53,11 +33,11 @@ def test_valid_file(self): """Check if the sha256 sum of the given file is valid""" - self.assertTrue(bootstrap.verify(self.src, self.sums, False)) + self.assertTrue(bootstrap.verify(self.src, self.expected, False)) def test_invalid_file(self): """Should verify that the file is invalid""" - self.assertFalse(bootstrap.verify(self.bad_src, self.sums, False)) + self.assertFalse(bootstrap.verify(self.bad_src, self.expected, False)) class ProgramOutOfDate(unittest.TestCase): @@ -99,7 +79,6 @@ TEST_LOADER = unittest.TestLoader() SUITE.addTest(doctest.DocTestSuite(bootstrap)) SUITE.addTests([ - TEST_LOADER.loadTestsFromTestCase(Stage0DataTestCase), TEST_LOADER.loadTestsFromTestCase(VerifyTestCase), TEST_LOADER.loadTestsFromTestCase(ProgramOutOfDate)]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/builder.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/builder.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/builder.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/builder.rs 2021-11-29 19:27:11.000000000 +0000 @@ -370,7 +370,7 @@ match kind { Kind::Build => describe!( compile::Std, - compile::Rustc, + compile::Assemble, compile::CodegenBackend, compile::StartupObjects, tool::BuildManifest, @@ -523,7 +523,7 @@ install::Src, install::Rustc ), - Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest), + Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0), } } @@ -1342,12 +1342,6 @@ rustdocflags.arg("-Dwarnings"); } - // FIXME(#58633) hide "unused attribute" errors in incremental - // builds of the standard library, as the underlying checks are - // not yet properly integrated with incremental recompilation. - if mode == Mode::Std && compiler.stage == 0 && self.config.incremental { - lint_flags.push("-Aunused-attributes"); - } // This does not use RUSTFLAGS due to caching issues with Cargo. // Clippy is treated as an "in tree" tool, but shares the same // cache as other "submodule" tools. With these options set in @@ -1617,6 +1611,22 @@ // Only execute if it's supposed to run as default if desc.default && should_run.is_really_default() { self.ensure(step) } else { None } } + + /// Checks if any of the "should_run" paths is in the `Builder` paths. + pub(crate) fn was_invoked_explicitly(&'a self) -> bool { + let desc = StepDescription::from::(); + let should_run = (desc.should_run)(ShouldRun::new(self)); + + for path in &self.paths { + if should_run.paths.iter().any(|s| s.has(path)) + && !desc.is_excluded(self, &PathSet::Suite(path.clone())) + { + return true; + } + } + + false + } } #[cfg(test)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/bootstrap/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "bootstrap" version = "0.0.0" -edition = "2018" +edition = "2021" build = "build.rs" [lib] diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/check.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/check.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/check.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/check.rs 2021-11-29 19:27:11.000000000 +0000 @@ -107,6 +107,11 @@ add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); } + // don't run on std twice with x.py clippy + if builder.kind == Kind::Clippy { + return; + } + // Then run cargo again, once we've put the rmeta files for the library // crates into the sysroot. This is needed because e.g., core's tests // depend on `libtest` -- Cargo presumes it will exist, but it doesn't @@ -120,6 +125,7 @@ target, cargo_subcommand(builder.kind), ); + cargo.arg("--all-targets"); std_cargo(builder, target, compiler.stage, &mut cargo); @@ -192,7 +198,12 @@ cargo_subcommand(builder.kind), ); rustc_cargo(builder, &mut cargo, target); - cargo.arg("--all-targets"); + + // For ./x.py clippy, don't run with --all-targets because + // linting tests and benchmarks can produce very noisy results + if builder.kind != Kind::Clippy { + cargo.arg("--all-targets"); + } // Explicitly pass -p for all compiler krates -- this will force cargo // to also check the tests/benches/examples for these crates, rather @@ -232,11 +243,16 @@ const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"]) + run.paths(&[ + "compiler/rustc_codegen_cranelift", + "rustc_codegen_cranelift", + "compiler/rustc_codegen_gcc", + "rustc_codegen_gcc", + ]) } fn make_run(run: RunConfig<'_>) { - for &backend in &[INTERNER.intern_str("cranelift")] { + for &backend in &[INTERNER.intern_str("cranelift"), INTERNER.intern_str("gcc")] { run.builder.ensure(CodegenBackend { target: run.target, backend }); } } @@ -251,7 +267,7 @@ let mut cargo = builder.cargo( compiler, Mode::Codegen, - SourceType::Submodule, + SourceType::InTree, target, cargo_subcommand(builder.kind), ); @@ -313,7 +329,12 @@ $source_type, &[], ); - cargo.arg("--all-targets"); + + // For ./x.py clippy, don't run with --all-targets because + // linting tests and benchmarks can produce very noisy results + if builder.kind != Kind::Clippy { + cargo.arg("--all-targets"); + } // Enable internal lints for clippy and rustdoc // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]` diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/compile.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/compile.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/compile.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/compile.rs 2021-11-29 19:27:11.000000000 +0000 @@ -528,7 +528,7 @@ const DEFAULT: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("compiler/rustc") + run.never() } fn make_run(run: RunConfig<'_>) { @@ -817,8 +817,7 @@ let out_dir = builder.cargo_out(compiler, Mode::Codegen, target); - let mut cargo = - builder.cargo(compiler, Mode::Codegen, SourceType::Submodule, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Codegen, SourceType::InTree, target, "build"); cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend))); @@ -1024,9 +1023,16 @@ impl Step for Assemble { type Output = Compiler; + const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() + run.path("compiler/rustc") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Assemble { + target_compiler: run.builder.compiler(run.builder.top_stage + 1, run.target), + }); } /// Prepare a new compiler from the artifacts in `stage` diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/config.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/config.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/config.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/config.rs 2021-11-29 19:27:11.000000000 +0000 @@ -397,6 +397,7 @@ install_stage: Option, dist_stage: Option, bench_stage: Option, + patch_binaries_for_nix: Option, } /// TOML representation of various global install decisions. @@ -824,15 +825,10 @@ }; } - if config.llvm_thin_lto { - // If we're building with ThinLTO on, we want to link to LLVM - // shared, to avoid re-doing ThinLTO (which happens in the link - // step) with each stage. - assert_ne!( - llvm.link_shared, - Some(false), - "setting link-shared=false is incompatible with thin-lto=true" - ); + if config.llvm_thin_lto && llvm.link_shared.is_none() { + // If we're building with ThinLTO on, by default we want to link + // to LLVM shared, to avoid re-doing ThinLTO (which happens in + // the link step) with each stage. config.llvm_link_shared = true; } } @@ -981,7 +977,8 @@ config.rust_debug_assertions_std = debug_assertions_std.unwrap_or(config.rust_debug_assertions); config.rust_overflow_checks = overflow_checks.unwrap_or(default); - config.rust_overflow_checks_std = overflow_checks_std.unwrap_or(default); + config.rust_overflow_checks_std = + overflow_checks_std.unwrap_or(config.rust_overflow_checks); config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions); diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/configure.py rustc-1.57.0+dfsg1+llvm/src/bootstrap/configure.py --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/configure.py 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/configure.py 2021-11-29 19:27:11.000000000 +0000 @@ -75,7 +75,9 @@ o("llvm-assertions", "llvm.assertions", "build LLVM with assertions") o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface") o("debug-assertions", "rust.debug-assertions", "build with debugging assertions") +o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions") o("overflow-checks", "rust.overflow-checks", "build with overflow checks") +o("overflow-checks-std", "rust.overflow-checks-std", "build the standard library with overflow checks") o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger metadata") v("debuginfo-level", "rust.debuginfo-level", "debuginfo level for Rust code") v("debuginfo-level-rustc", "rust.debuginfo-level-rustc", "debuginfo level for the compiler") diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/defaults/config.library.toml rustc-1.57.0+dfsg1+llvm/src/bootstrap/defaults/config.library.toml --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/defaults/config.library.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/defaults/config.library.toml 2021-11-29 19:27:11.000000000 +0000 @@ -10,6 +10,5 @@ incremental = true [llvm] -# Will download LLVM from CI if available on your platform (Linux only for now) -# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms +# Will download LLVM from CI if available on your platform. download-ci-llvm = "if-available" diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/doc.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/doc.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/doc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/doc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -102,18 +102,10 @@ // Used for deciding whether a particular step is one requested by the user on // the `x.py doc` command line, which determines whether `--open` will open that // page. -fn components_simplified(path: &PathBuf) -> Vec<&str> { +pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> { path.iter().map(|component| component.to_str().unwrap_or("???")).collect() } -fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool { - builder - .paths - .iter() - .map(components_simplified) - .any(|requested| requested.iter().copied().eq(path.split('/'))) -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: TargetSelection, @@ -248,7 +240,7 @@ invoke_rustdoc(builder, compiler, target, path); } - if is_explicit_request(builder, "src/doc/book") { + if builder.was_invoked_explicitly::() { let out = builder.doc_out(target); let index = out.join("book").join("index.html"); open(builder, &index); @@ -408,7 +400,7 @@ // We open doc/index.html as the default if invoked as `x.py doc --open` // with no particular explicit doc requested (e.g. library/core). - if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") { + if builder.paths.is_empty() || builder.was_invoked_explicitly::() { let index = out.join("index.html"); open(builder, &index); } @@ -537,7 +529,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.krate("rustc-main").default_condition(builder.config.docs) + run.krate("rustc-main").path("compiler").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -555,7 +547,20 @@ let target = self.target; builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); - if !builder.config.compiler_docs { + let paths = builder + .paths + .iter() + .map(components_simplified) + .filter_map(|path| { + if path.get(0) == Some(&"compiler") { + path.get(1).map(|p| p.to_owned()) + } else { + None + } + }) + .collect::>(); + + if !builder.config.compiler_docs && !builder.was_invoked_explicitly::() { builder.info("\tskipping - compiler/librustdoc docs disabled"); return; } @@ -589,32 +594,69 @@ cargo.rustdocflag("-Zunstable-options"); cargo.rustdocflag("-Znormalize-docs"); cargo.rustdocflag("--show-type-layout"); + cargo.rustdocflag("--generate-link-to-definition"); compile::rustc_cargo(builder, &mut cargo, target); + cargo.arg("-Zunstable-options"); cargo.arg("-Zskip-rustdoc-fingerprint"); // Only include compiler crates, no dependencies of those, such as `libc`. + // Do link to dependencies on `docs.rs` however using `rustdoc-map`. cargo.arg("--no-deps"); + cargo.arg("-Zrustdoc-map"); + + // FIXME: `-Zrustdoc-map` does not yet correctly work for transitive dependencies, + // once this is no longer an issue the special case for `ena` can be removed. + cargo.rustdocflag("--extern-html-root-url"); + cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); - // Find dependencies for top level crates. let mut compiler_crates = HashSet::new(); - for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { - compiler_crates.extend( - builder - .in_tree_crates(root_crate, Some(target)) - .into_iter() - .map(|krate| krate.name), - ); + + if paths.is_empty() { + // Find dependencies for top level crates. + for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { + compiler_crates.extend( + builder + .in_tree_crates(root_crate, Some(target)) + .into_iter() + .map(|krate| krate.name), + ); + } + } else { + for root_crate in paths { + if !builder.src.join("compiler").join(&root_crate).exists() { + builder.info(&format!( + "\tskipping - compiler/{} (unknown compiler crate)", + root_crate + )); + } else { + compiler_crates.extend( + builder + .in_tree_crates(root_crate, Some(target)) + .into_iter() + .map(|krate| krate.name), + ); + } + } } + let mut to_open = None; for krate in &compiler_crates { // Create all crate output directories first to make sure rustdoc uses // relative links. // FIXME: Cargo should probably do this itself. t!(fs::create_dir_all(out_dir.join(krate))); cargo.arg("-p").arg(krate); + if to_open.is_none() { + to_open = Some(krate); + } } builder.run(&mut cargo.into()); + // Let's open the first crate documentation page: + if let Some(krate) = to_open { + let index = out.join(krate).join("index.html"); + open(builder, &index); + } } } @@ -648,7 +690,14 @@ fn run(self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; - builder.info(&format!("Documenting stage{} {} ({})", stage, stringify!($tool).to_lowercase(), target)); + builder.info( + &format!( + "Documenting stage{} {} ({})", + stage, + stringify!($tool).to_lowercase(), + target, + ), + ); // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); @@ -656,7 +705,7 @@ let compiler = builder.compiler(stage, builder.config.build); - if !builder.config.compiler_docs { + if !builder.config.compiler_docs && !builder.was_invoked_explicitly::() { builder.info("\tskipping - compiler/tool docs disabled"); return; } @@ -691,6 +740,7 @@ cargo.rustdocflag("--document-private-items"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("--show-type-layout"); + cargo.rustdocflag("--generate-link-to-definition"); cargo.rustdocflag("-Zunstable-options"); builder.run(&mut cargo.into()); } @@ -860,7 +910,7 @@ name: INTERNER.intern_str("rustc"), src: INTERNER.intern_path(out_base), }); - if is_explicit_request(builder, "src/doc/rustc") { + if builder.was_invoked_explicitly::() { let out = builder.doc_out(self.target); let index = out.join("rustc").join("index.html"); open(builder, &index); diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/lib.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,7 +31,7 @@ //! When you execute `x.py build`, the steps executed are: //! //! * First, the python script is run. This will automatically download the -//! stage0 rustc and cargo according to `src/stage0.txt`, or use the cached +//! stage0 rustc and cargo according to `src/stage0.json`, or use the cached //! versions if they're available. These are then used to compile rustbuild //! itself (using Cargo). Finally, control is then transferred to rustbuild. //! @@ -1494,8 +1494,13 @@ { eprintln!( " -Couldn't find required command: ninja -You should install ninja, or set `ninja=false` in config.toml in the `[llvm]` section. +Couldn't find required command: ninja (or ninja-build) + +You should install ninja as described at +, +or set `ninja = false` in the `[llvm]` section of `config.toml`. +Alternatively, set `download-ci-llvm = true` in that `[llvm]` section +to download LLVM rather than building it. " ); std::process::exit(1); diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/native.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/native.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/native.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/native.rs 2021-11-29 19:27:11.000000000 +0000 @@ -165,7 +165,7 @@ let llvm_exp_targets = match builder.config.llvm_experimental_targets { Some(ref s) => s, - None => "AVR", + None => "AVR;M68k", }; let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" }; @@ -189,6 +189,11 @@ .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native); + // Parts of our test suite rely on the `FileCheck` tool, which is built by default in + // `build/$TARGET/llvm/build/bin` is but *not* then installed to `build/$TARGET/llvm/bin`. + // This flag makes sure `FileCheck` is copied in the final binaries directory. + cfg.define("LLVM_INSTALL_UTILS", "ON"); + if builder.config.llvm_profile_generate { cfg.define("LLVM_BUILD_INSTRUMENTED", "IR"); cfg.define("LLVM_BUILD_RUNTIME", "No"); diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/run.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/run.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/run.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/run.rs 2021-11-29 19:27:11.000000000 +0000 @@ -82,3 +82,24 @@ builder.run(&mut cmd); } } + +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct BumpStage0; + +impl Step for BumpStage0 { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/bump-stage0") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(BumpStage0); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let mut cmd = builder.tool_cmd(Tool::BumpStage0); + builder.run(&mut cmd); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/sanity.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/sanity.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/sanity.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/sanity.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,7 +15,7 @@ use std::path::PathBuf; use std::process::Command; -use build_helper::{output, t}; +use build_helper::output; use crate::cache::INTERNER; use crate::config::Target; @@ -227,14 +227,4 @@ if let Some(ref s) = build.config.ccache { cmd_finder.must_have(s); } - - if build.config.channel == "stable" { - let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt"))); - if stage0.contains("\ndev:") { - panic!( - "bootstrapping from a dev compiler in a stable release, but \ - should only be bootstrapping from a released compiler!" - ); - } - } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/setup.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/setup.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/setup.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/setup.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,4 @@ +use crate::TargetSelection; use crate::{t, VERSION}; use std::fmt::Write as _; use std::path::{Path, PathBuf}; @@ -107,6 +108,17 @@ let include_path = profile.include_path(src_path); println!("`x.py` will now use the configuration at {}", include_path.display()); + let build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); + let stage_path = ["build", build.rustc_target_arg(), "stage1"].join("/"); + + println!(); + + if !rustup_installed() && profile != Profile::User { + println!("`rustup` is not installed; cannot link `stage1` toolchain"); + } else if stage_dir_exists(&stage_path[..]) { + attempt_toolchain_link(&stage_path[..]); + } + let suggestions = match profile { Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..], Profile::Tools => &[ @@ -139,6 +151,74 @@ } } +fn rustup_installed() -> bool { + Command::new("rustup") + .arg("--version") + .stdout(std::process::Stdio::null()) + .output() + .map_or(false, |output| output.status.success()) +} + +fn stage_dir_exists(stage_path: &str) -> bool { + match fs::create_dir(&stage_path[..]) { + Ok(_) => true, + Err(_) => Path::new(&stage_path[..]).exists(), + } +} + +fn attempt_toolchain_link(stage_path: &str) { + if toolchain_is_linked() { + return; + } + + if try_link_toolchain(&stage_path[..]) { + println!( + "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain" + ); + } else { + println!("`rustup` failed to link stage 1 build to `stage1` toolchain"); + println!( + "To manually link stage 1 build to `stage1` toolchain, run:\n + `rustup toolchain link stage1 {}`", + &stage_path[..] + ); + } +} + +fn toolchain_is_linked() -> bool { + match Command::new("rustup") + .args(&["toolchain", "list"]) + .stdout(std::process::Stdio::piped()) + .output() + { + Ok(toolchain_list) => { + if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") { + return false; + } + // The toolchain has already been linked. + println!( + "`stage1` toolchain already linked; not attempting to link `stage1` toolchain" + ); + } + Err(_) => { + // In this case, we don't know if the `stage1` toolchain has been linked; + // but `rustup` failed, so let's not go any further. + println!( + "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain" + ); + } + } + true +} + +fn try_link_toolchain(stage_path: &str) -> bool { + Command::new("rustup") + .stdout(std::process::Stdio::null()) + .args(&["toolchain", "link", "stage1", &stage_path[..]]) + .output() + .map_or(false, |output| output.status.success()) +} + // Used to get the path for `Subcommand::Setup` pub fn interactive_path() -> io::Result { fn abbrev_all() -> impl Iterator { diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/test.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/test.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -390,7 +390,7 @@ host, "test", "src/tools/rustfmt", - SourceType::Submodule, + SourceType::InTree, &[], ); @@ -653,7 +653,7 @@ let host = self.host; let compiler = builder.compiler(stage, host); - let clippy = builder + builder .ensure(tool::Clippy { compiler, target: self.host, extra_features: Vec::new() }) .expect("in-tree tool"); let mut cargo = tool::prepare_tool_cargo( @@ -672,14 +672,7 @@ cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir()); - let target_libs = builder - .stage_out(compiler, Mode::ToolRustc) - .join(&self.host.triple) - .join(builder.cargo_dir()); cargo.env("HOST_LIBS", host_libs); - cargo.env("TARGET_LIBS", target_libs); - // clippy tests need to find the driver - cargo.env("CLIPPY_DRIVER_PATH", clippy); cargo.arg("--").args(builder.config.cmd.test_args()); @@ -905,7 +898,7 @@ let out_dir = builder.test_out(self.target).join("rustdoc-gui"); // We remove existing folder to be sure there won't be artifacts remaining. - let _ = fs::remove_dir_all(&out_dir); + builder.clear_if_dirty(&out_dir, &builder.rustdoc(self.compiler)); let src_path = builder.build.src.join("src/test/rustdoc-gui/src"); // We generate docs for the libraries present in the rustdoc-gui's src folder. @@ -925,6 +918,11 @@ .env("RUSTDOC", builder.rustdoc(self.compiler)) .env("RUSTC", builder.rustc(self.compiler)) .current_dir(path); + // FIXME: implement a `// compile-flags` command or similar + // instead of hard-coding this test + if entry.file_name() == "link_to_definition" { + cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition"); + } builder.run(&mut cargo); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/bootstrap/tool.rs rustc-1.57.0+dfsg1+llvm/src/bootstrap/tool.rs --- rustc-1.56.0+dfsg1+llvm/src/bootstrap/tool.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/bootstrap/tool.rs 2021-11-29 19:27:11.000000000 +0000 @@ -377,6 +377,7 @@ LintDocs, "src/tools/lint-docs", "lint-docs"; JsonDocCk, "src/tools/jsondocck", "jsondocck"; HtmlChecker, "src/tools/html-checker", "html-checker"; + BumpStage0, "src/tools/bump-stage0", "bump-stage0"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/build_helper/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/build_helper/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/build_helper/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/build_helper/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "build_helper" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] path = "lib.rs" diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/disabled/dist-m68k-linux/Dockerfile rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/disabled/dist-m68k-linux/Dockerfile --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/disabled/dist-m68k-linux/Dockerfile 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/disabled/dist-m68k-linux/Dockerfile 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +FROM ubuntu:20.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-m68k-linux-gnu \ + libssl-dev \ + pkg-config + + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV HOSTS=m68k-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,15 @@ +# We need recent curl, OpenSSL and CA certificates, so we can download further +# dependencies in the debian:6 image. We use an ubuntu 20.04 image download +# those. +FROM ubuntu:20.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates +WORKDIR /tmp +COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/ +RUN ./download-openssl-curl.sh + # We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other # distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and # SLES 11 SP4 (glibc 2.11, kernel 3.0). @@ -14,8 +26,6 @@ apt-get install --allow-unauthenticated -y --no-install-recommends \ automake \ bzip2 \ - ca-certificates \ - curl \ file \ g++ \ g++-multilib \ @@ -34,11 +44,6 @@ xz-utils \ zlib1g-dev -# Install new Let's Encrypt root CA certificate and remove the expired one. -COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt -RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf -RUN /usr/sbin/update-ca-certificates - ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig @@ -50,6 +55,7 @@ # static.rust-lang.org. This'll be used to link into libcurl below (and used # later as well), so build a copy of OpenSSL with dynamic libraries into our # generic root. +COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/ RUN ./build-openssl.sh @@ -59,8 +65,13 @@ # # Note that we also disable a bunch of optional features of curl that we don't # really need. +COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/ -RUN ./build-curl.sh && apt-get remove -y curl +RUN ./build-curl.sh + +# Use up-to-date curl CA bundle +COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem +ENV CURL_CA_BUNDLE /tmp/cacert.pem # binutils < 2.22 has a bug where the 32-bit executables it generates # immediately segfault in Rust, so we need to install our own binutils. diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 58795582905e08fa7748846c1971b4ab911d1e16 +git reset --hard ad5133410f66b93a2381db5b542aad5e0964db96 make -j$(nproc) INSTALL_DIR=/wasm32-wasi install cd .. diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh 2021-11-29 19:27:11.000000000 +0000 @@ -3,18 +3,11 @@ set -ex source shared.sh -VERSION=7.66.0 - -# This needs to be downloaded directly from S3, it can't go through the CDN. -# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1 -# (without paying an absurd amount of money). -curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \ - | xz --decompress \ - | tar xf - +tar xJf curl.tar.xz mkdir curl-build cd curl-build -hide_output ../curl-$VERSION/configure \ +hide_output ../curl-*/configure \ --prefix=/rustroot \ --with-ssl=/rustroot \ --disable-sspi \ @@ -35,4 +28,4 @@ cd .. rm -rf curl-build -rm -rf curl-$VERSION +rm -rf curl-* diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh 2021-11-29 19:27:11.000000000 +0000 @@ -3,21 +3,14 @@ set -ex source shared.sh -VERSION=1.0.2k +tar xzf openssl.tar.gz -# This needs to be downloaded directly from S3, it can't go through the CDN. -# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1 -# (without paying an absurd amount of money). -URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz - -curl $URL | tar xzf - - -cd openssl-$VERSION +cd openssl-* hide_output ./config --prefix=/rustroot shared -fPIC hide_output make -j$(nproc) hide_output make install cd .. -rm -rf openssl-$VERSION +rm -rf openssl-* # Make the system cert collection available to the new install. ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,15 @@ +# We need recent curl, OpenSSL and CA certificates, so we can download further +# dependencies in the debian:6 image. We use an ubuntu 20.04 image download +# those. +FROM ubuntu:20.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates +WORKDIR /tmp +COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/ +RUN ./download-openssl-curl.sh + # We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other # distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and # SLES 11 SP4 (glibc 2.11, kernel 3.0). @@ -14,8 +26,6 @@ apt-get install --allow-unauthenticated -y --no-install-recommends \ automake \ bzip2 \ - ca-certificates \ - curl \ file \ g++ \ g++-multilib \ @@ -34,11 +44,6 @@ xz-utils \ zlib1g-dev -# Install new Let's Encrypt root CA certificate and remove the expired one. -COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt -RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf -RUN /usr/sbin/update-ca-certificates - ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig @@ -50,6 +55,7 @@ # static.rust-lang.org. This'll be used to link into libcurl below (and used # later as well), so build a copy of OpenSSL with dynamic libraries into our # generic root. +COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/ RUN ./build-openssl.sh @@ -59,8 +65,13 @@ # # Note that we also disable a bunch of optional features of curl that we don't # really need. +COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/ -RUN ./build-curl.sh && apt-get remove -y curl +RUN ./build-curl.sh + +# Use up-to-date curl CA bundle +COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem +ENV CURL_CA_BUNDLE /tmp/cacert.pem # binutils < 2.22 has a bug where the 32-bit executables it generates # immediately segfault in Rust, so we need to install our own binutils. diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -ex + +OPENSSL_VERSION=1.0.2k +CURL_VERSION=7.66.0 + +curl -f https://ci-mirrors.rust-lang.org/rustc/openssl-$OPENSSL_VERSION.tar.gz -o openssl.tar.gz +curl -f https://ci-mirrors.rust-lang.org/rustc/curl-$CURL_VERSION.tar.xz -o curl.tar.xz +curl -f https://curl.se/ca/cacert.pem -o cacert.pem diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/run.sh rustc-1.57.0+dfsg1+llvm/src/ci/docker/run.sh --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/run.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/run.sh 2021-11-29 19:27:11.000000000 +0000 @@ -50,7 +50,8 @@ # Look for all source files involves in the COPY command copied_files=/tmp/.docker-copied-files.txt rm -f "$copied_files" - for i in $(sed -n -e 's/^COPY \(.*\) .*$/\1/p' "$docker_dir/$image/Dockerfile"); do + for i in $(sed -n -e '/^COPY --from=/! s/^COPY \(.*\) .*$/\1/p' \ + "$docker_dir/$image/Dockerfile"); do # List the file names find "$script_dir/$i" -type f >> $copied_files done diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/docker/scripts/freebsd-toolchain.sh rustc-1.57.0+dfsg1+llvm/src/ci/docker/scripts/freebsd-toolchain.sh --- rustc-1.56.0+dfsg1+llvm/src/ci/docker/scripts/freebsd-toolchain.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/docker/scripts/freebsd-toolchain.sh 2021-11-29 19:27:11.000000000 +0000 @@ -53,7 +53,7 @@ for lib in c cxxrt gcc_s m thr util; do files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*") done -for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared; do +for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat; do files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*") done diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/github-actions/ci.yml rustc-1.57.0+dfsg1+llvm/src/ci/github-actions/ci.yml --- rustc-1.56.0+dfsg1+llvm/src/ci/github-actions/ci.yml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/github-actions/ci.yml 2021-11-29 19:27:11.000000000 +0000 @@ -153,10 +153,6 @@ run: src/ci/scripts/install-sccache.sh <<: *step - - name: select Xcode - run: src/ci/scripts/select-xcode.sh - <<: *step - - name: install clang run: src/ci/scripts/install-clang.sh <<: *step @@ -498,7 +494,6 @@ --set rust.jemalloc --set llvm.ninja=false RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - SELECT_XCODE: /Applications/Xcode_12.2.app USE_XCODE_CLANG: 1 MACOSX_DEPLOYMENT_TARGET: 11.0 MACOSX_STD_DEPLOYMENT_TARGET: 11.0 diff -Nru rustc-1.56.0+dfsg1+llvm/src/ci/scripts/select-xcode.sh rustc-1.57.0+dfsg1+llvm/src/ci/scripts/select-xcode.sh --- rustc-1.56.0+dfsg1+llvm/src/ci/scripts/select-xcode.sh 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/ci/scripts/select-xcode.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -#!/bin/bash -# This script selects the Xcode instance to use. - -set -euo pipefail -IFS=$'\n\t' - -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" - -if isMacOS; then - if [[ -s "${SELECT_XCODE-}" ]]; then - sudo xcode-select -s "${SELECT_XCODE}" - fi -fi diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/.github/workflows/main.yml rustc-1.57.0+dfsg1+llvm/src/doc/book/.github/workflows/main.yml --- rustc-1.56.0+dfsg1+llvm/src/doc/book/.github/workflows/main.yml 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/.github/workflows/main.yml 2021-09-17 01:17:09.000000000 +0000 @@ -12,12 +12,12 @@ - name: Install Rust run: | rustup set profile minimal - rustup toolchain install 1.54 -c rust-docs - rustup default 1.54 + rustup toolchain install 1.55 -c rust-docs + rustup default 1.55 - name: Install mdbook run: | mkdir bin - curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.5/mdbook-v0.4.5-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.12/mdbook-v0.4.12-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin echo "$(pwd)/bin" >> ${GITHUB_PATH} - name: Report versions run: | @@ -41,7 +41,7 @@ - name: Install mdbook run: | mkdir bin - curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.5/mdbook-v0.4.5-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.12/mdbook-v0.4.12-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin echo "$(pwd)/bin" >> ${GITHUB_PATH} - name: Report versions run: | diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch02-guessing-game-tutorial/listing-02-04/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch02-guessing-game-tutorial/listing-02-04/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch02-guessing-game-tutorial/listing-02-04/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch02-guessing-game-tutorial/listing-02-04/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -16,9 +16,5 @@ = note: expected reference `&String` found reference `&{integer}` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `guessing_game` - -To learn more, run the command again with --verbose. +error: could not compile `guessing_game` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch02-guessing-game-tutorial/no-listing-02-without-expect/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,6 +9,5 @@ = note: `#[warn(unused_must_use)]` on by default = note: this `Result` may be an `Err` variant, which should be handled -warning: 1 warning emitted - +warning: `guessing_game` (bin "guessing_game") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.59s diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ 4 | x = 6; | ^^^^^ cannot assign twice to immutable variable -error: aborting due to previous error - For more information about this error, try `rustc --explain E0384`. -error: could not compile `variables` - -To learn more, run the command again with --verbose. +error: could not compile `variables` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-05-mut-cant-change-types/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 3 | spaces = spaces.len(); | ^^^^^^^^^^^^ expected `&str`, found `usize` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `variables` - -To learn more, run the command again with --verbose. +error: could not compile `variables` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -25,9 +25,6 @@ | = note: `#[warn(unused_parens)]` on by default -error: aborting due to 2 previous errors; 1 warning emitted - For more information about this error, try `rustc --explain E0658`. -error: could not compile `functions` - -To learn more, run the command again with --verbose. +warning: `functions` (bin "functions") generated 1 warning +error: could not compile `functions` due to 2 previous errors; 1 warning emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs 2021-09-17 01:17:09.000000000 +0000 @@ -1,6 +1,4 @@ fn main() { - let x = 5; - let y = { let x = 3; x + 1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -10,9 +10,5 @@ 8 | x + 1; | - help: consider removing this semicolon -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `functions` - -To learn more, run the command again with --verbose. +error: could not compile `functions` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 4 | if number { | ^^^^^^ expected `bool`, found integer -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `branches` - -To learn more, run the command again with --verbose. +error: could not compile `branches` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,9 +8,5 @@ | | | expected because of this -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `branches` - -To learn more, run the command again with --verbose. +error: could not compile `branches` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 2 | let guess = "42".parse().expect("Not a number!"); | ^^^^^ consider giving `guess` a type -error: aborting due to previous error - For more information about this error, try `rustc --explain E0282`. -error: could not compile `no_type_annotations` - -To learn more, run the command again with --verbose. +error: could not compile `no_type_annotations` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/listing-04-06/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/listing-04-06/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/listing-04-06/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/listing-04-06/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,9 +8,5 @@ 8 | some_string.push_str(", world"); | ^^^^^^^^^^^ `some_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error: aborting due to previous error - For more information about this error, try `rustc --explain E0596`. -error: could not compile `ownership` - -To learn more, run the command again with --verbose. +error: could not compile `ownership` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-04-cant-use-after-move/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -11,9 +11,5 @@ 5 | println!("{}, world!", s1); | ^^ value borrowed here after move -error: aborting due to previous error - For more information about this error, try `rustc --explain E0382`. -error: could not compile `ownership` - -To learn more, run the command again with --verbose. +error: could not compile `ownership` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-10-multiple-mut-not-allowed/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -11,9 +11,5 @@ 7 | println!("{}, {}", r1, r2); | -- first borrow later used here -error: aborting due to previous error - For more information about this error, try `rustc --explain E0499`. -error: could not compile `ownership` - -To learn more, run the command again with --verbose. +error: could not compile `ownership` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ 8 | println!("{}, {}, and {}", r1, r2, r3); | -- immutable borrow later used here -error: aborting due to previous error - For more information about this error, try `rustc --explain E0502`. -error: could not compile `ownership` - -To learn more, run the command again with --verbose. +error: could not compile `ownership` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-14-dangling-reference/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ 5 | fn dangle() -> &'static String { | ^^^^^^^^ -error: aborting due to previous error - For more information about this error, try `rustc --explain E0106`. -error: could not compile `ownership` - -To learn more, run the command again with --verbose. +error: could not compile `ownership` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch04-understanding-ownership/no-listing-19-slice-error/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ 20 | println!("the first word is: {}", word); | ---- immutable borrow later used here -error: aborting due to previous error - For more information about this error, try `rustc --explain E0502`. -error: could not compile `ownership` - -To learn more, run the command again with --verbose. +error: could not compile `ownership` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/listing-05-11/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,12 +8,7 @@ | = help: the trait `std::fmt::Display` is not implemented for `Rectangle` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - = note: required by `std::fmt::Display::fmt` = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error - For more information about this error, try `rustc --explain E0277`. -error: could not compile `rectangles` - -To learn more, run the command again with --verbose. +error: could not compile `rectangles` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -1,33 +1,31 @@ $ cargo run Compiling structs v0.1.0 (file:///projects/structs) error[E0106]: missing lifetime specifier - --> src/main.rs:2:15 + --> src/main.rs:3:15 | -2 | username: &str, +3 | username: &str, | ^ expected named lifetime parameter | help: consider introducing a named lifetime parameter | 1 | struct User<'a> { -2 | username: &'a str, +2 | active: bool, +3 | username: &'a str, | error[E0106]: missing lifetime specifier - --> src/main.rs:3:12 + --> src/main.rs:4:12 | -3 | email: &str, +4 | email: &str, | ^ expected named lifetime parameter | help: consider introducing a named lifetime parameter | 1 | struct User<'a> { -2 | username: &str, -3 | email: &'a str, +2 | active: bool, +3 | username: &str, +4 | email: &'a str, | -error: aborting due to 2 previous errors - For more information about this error, try `rustc --explain E0106`. -error: could not compile `structs` - -To learn more, run the command again with --verbose. +error: could not compile `structs` due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch05-using-structs-to-structure-related-data/output-only-01-debug/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -7,13 +7,8 @@ | ^^^^^ `Rectangle` cannot be formatted using `{:?}` | = help: the trait `Debug` is not implemented for `Rectangle` - = note: add `#[derive(Debug)]` or manually implement `Debug` - = note: required by `std::fmt::Debug::fmt` + = note: add `#[derive(Debug)]` to `Rectangle` or manually `impl Debug for Rectangle` = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error - For more information about this error, try `rustc --explain E0277`. -error: could not compile `rectangles` - -To learn more, run the command again with --verbose. +error: could not compile `rectangles` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,9 +8,5 @@ | = help: the trait `Add>` is not implemented for `i8` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0277`. -error: could not compile `enums` - -To learn more, run the command again with --verbose. +error: could not compile `enums` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,9 +9,5 @@ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `Option` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0004`. -error: could not compile `enums` - -To learn more, run the command again with --verbose. +error: could not compile `enums` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch07-managing-growing-projects/listing-07-03/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch07-managing-growing-projects/listing-07-03/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch07-managing-growing-projects/listing-07-03/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch07-managing-growing-projects/listing-07-03/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -24,9 +24,5 @@ 2 | mod hosting { | ^^^^^^^^^^^ -error: aborting due to 2 previous errors - For more information about this error, try `rustc --explain E0603`. -error: could not compile `restaurant` - -To learn more, run the command again with --verbose. +error: could not compile `restaurant` due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch07-managing-growing-projects/listing-07-05/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch07-managing-growing-projects/listing-07-05/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch07-managing-growing-projects/listing-07-05/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch07-managing-growing-projects/listing-07-05/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -24,9 +24,5 @@ 3 | fn add_to_waitlist() {} | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - For more information about this error, try `rustc --explain E0603`. -error: could not compile `restaurant` - -To learn more, run the command again with --verbose. +error: could not compile `restaurant` due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch08-common-collections/listing-08-07/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch08-common-collections/listing-08-07/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch08-common-collections/listing-08-07/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch08-common-collections/listing-08-07/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ 8 | println!("The first element is: {}", first); | ----- immutable borrow later used here -error: aborting due to previous error - For more information about this error, try `rustc --explain E0502`. -error: could not compile `collections` - -To learn more, run the command again with --verbose. +error: could not compile `collections` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch08-common-collections/listing-08-19/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch08-common-collections/listing-08-19/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch08-common-collections/listing-08-19/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch08-common-collections/listing-08-19/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,9 +8,5 @@ | = help: the trait `Index<{integer}>` is not implemented for `String` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0277`. -error: could not compile `collections` - -To learn more, run the command again with --verbose. +error: could not compile `collections` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch09-error-handling/no-listing-02-ask-compiler-for-type/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -11,9 +11,5 @@ = note: expected type `u32` found enum `Result` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `error-handling` - -To learn more, run the command again with --verbose. +error: could not compile `error-handling` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch09-error-handling/no-listing-06-question-mark-in-main/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch09-error-handling/no-listing-06-question-mark-in-main/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch09-error-handling/no-listing-06-question-mark-in-main/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch09-error-handling/no-listing-06-question-mark-in-main/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -1,20 +1,16 @@ $ cargo run Compiling error-handling v0.1.0 (file:///projects/error-handling) error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> src/main.rs:4:36 - | -3 | / fn main() { -4 | | let f = File::open("hello.txt")?; - | | ^ cannot use the `?` operator in a function that returns `()` -5 | | } - | |_- this function should return `Result` or `Option` to accept `?` - | - = help: the trait `FromResidual>` is not implemented for `()` - = note: required by `from_residual` - -error: aborting due to previous error + --> src/main.rs:4:36 + | +3 | / fn main() { +4 | | let f = File::open("hello.txt")?; + | | ^ cannot use the `?` operator in a function that returns `()` +5 | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual>` is not implemented for `()` +note: required by `from_residual` For more information about this error, try `rustc --explain E0277`. -error: could not compile `error-handling` - -To learn more, run the command again with --verbose. +error: could not compile `error-handling` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -13,9 +13,5 @@ 1 | fn largest(list: &[T]) -> T { | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error - For more information about this error, try `rustc --explain E0369`. -error: could not compile `chapter10` - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 7 | let wont_work = Point { x: 5, y: 4.0 }; | ^^^ expected integer, found floating-point number -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `chapter10` - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -11,9 +11,5 @@ 10 | println!("r: {}", r); | - borrow later used here -error: aborting due to previous error - For more information about this error, try `rustc --explain E0597`. -error: could not compile `chapter10` - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ 9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { | ^^^^ ^^^^^^^ ^^^^^^^ ^^^ -error: aborting due to previous error - For more information about this error, try `rustc --explain E0106`. -error: could not compile `chapter10` - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -10,9 +10,5 @@ 8 | println!("The longest string is {}", result); | ------ borrow later used here -error: aborting due to previous error - For more information about this error, try `rustc --explain E0597`. -error: could not compile `chapter10` - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -20,10 +20,6 @@ | |move occurs because `item` has type `T`, which does not implement the `Copy` trait | help: consider removing the `&`: `item` -error: aborting due to 2 previous errors - Some errors have detailed explanations: E0507, E0508. For more information about an error, try `rustc --explain E0507`. -error: could not compile `chapter10` - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,9 +9,5 @@ | returns a value referencing data owned by the current function | `result` is borrowed here -error: aborting due to previous error - For more information about this error, try `rustc --explain E0515`. -error: could not compile `chapter10` - -To learn more, run the command again with --verbose. +error: could not compile `chapter10` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -7,7 +7,7 @@ test expensive_test ... ignored test it_works ... ok -test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.02s +test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests adder diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch12-an-io-project/listing-12-12/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch12-an-io-project/listing-12-12/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch12-an-io-project/listing-12-12/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch12-an-io-project/listing-12-12/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,8 +9,7 @@ = note: `#[warn(unused_must_use)]` on by default = note: this `Result` may be an `Err` variant, which should be handled -warning: 1 warning emitted - +warning: `minigrep` (bin "minigrep") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.71s Running `target/debug/minigrep the poem.txt` Searching for the diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch12-an-io-project/output-only-02-missing-lifetimes/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ 28 | pub fn search<'a>(query: &'a str, contents: &'a str) -> Vec<&'a str> { | ^^^^ ^^^^^^^ ^^^^^^^ ^^^ -error: aborting due to previous error - For more information about this error, try `rustc --explain E0106`. -error: could not compile `minigrep` - -To learn more, run the command again with --verbose. +error: could not compile `minigrep` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/listing-13-08/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/listing-13-08/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/listing-13-08/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/listing-13-08/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,9 +9,5 @@ | expected struct `String`, found integer | help: try using a conversion method: `5.to_string()` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `closure-example` - -To learn more, run the command again with --verbose. +error: could not compile `closure-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/listing-13-17/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/listing-13-17/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/listing-13-17/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/listing-13-17/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,7 +9,6 @@ = note: `#[warn(unused_must_use)]` on by default = note: iterators are lazy and do nothing unless consumed -warning: 1 warning emitted - +warning: `iterators` (bin "iterators") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.47s Running `target/debug/iterators` diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,9 +8,5 @@ | = help: use the `|| { ... }` closure form instead -error: aborting due to previous error - For more information about this error, try `rustc --explain E0434`. -error: could not compile `equal-to-x` - -To learn more, run the command again with --verbose. +error: could not compile `equal-to-x` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/no-listing-03-move-closures/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/no-listing-03-move-closures/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/no-listing-03-move-closures/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch13-functional-features/no-listing-03-move-closures/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -14,9 +14,5 @@ 6 | println!("can't use x here: {:?}", x); | ^ value borrowed here after move -error: aborting due to previous error - For more information about this error, try `rustc --explain E0382`. -error: could not compile `equal-to-x` - -To learn more, run the command again with --verbose. +error: could not compile `equal-to-x` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-03/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-03/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-03/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-03/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -22,10 +22,6 @@ = note: ...which again requires computing drop-check constraints for `List`, completing the cycle = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: List } }` -error: aborting due to 2 previous errors - Some errors have detailed explanations: E0072, E0391. For more information about an error, try `rustc --explain E0072`. -error: could not compile `cons-list` - -To learn more, run the command again with --verbose. +error: could not compile `cons-list` due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-09/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-09/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-09/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-09/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 14 | assert_eq!(5, *y); | ^^ -error: aborting due to previous error - For more information about this error, try `rustc --explain E0614`. -error: could not compile `deref-example` - -To learn more, run the command again with --verbose. +error: could not compile `deref-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-15/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-15/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-15/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-15/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,9 +9,5 @@ | | explicit destructor calls not allowed | help: consider using `drop` function: `drop(c)` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0040`. -error: could not compile `drop-example` - -To learn more, run the command again with --verbose. +error: could not compile `drop-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-17/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-17/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-17/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-17/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -10,9 +10,5 @@ 11 | let c = Cons(4, Box::new(a)); | ^ value used here after move -error: aborting due to previous error - For more information about this error, try `rustc --explain E0382`. -error: could not compile `cons-list` - -To learn more, run the command again with --verbose. +error: could not compile `cons-list` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-21/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-21/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-21/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/listing-15-21/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,11 +9,7 @@ 58 | self.sent_messages.push(String::from(message)); | ^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error: aborting due to previous error - For more information about this error, try `rustc --explain E0596`. -error: could not compile `limit-tracker` - -To learn more, run the command again with --verbose. +error: could not compile `limit-tracker` due to previous error warning: build failed, waiting for other jobs to finish... error: build failed diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,9 +8,5 @@ 3 | let y = &mut x; | ^^^^^^ cannot borrow as mutable -error: aborting due to previous error - For more information about this error, try `rustc --explain E0596`. -error: could not compile `borrowing` - -To learn more, run the command again with --verbose. +error: could not compile `borrowing` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,9 +9,5 @@ = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error - For more information about this error, try `rustc --explain E0277`. -error: could not compile `deref-example` - -To learn more, run the command again with --verbose. +error: could not compile `deref-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-03/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-03/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-03/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-03/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -21,9 +21,5 @@ 6 | let handle = thread::spawn(move || { | ^^^^^^^ -error: aborting due to previous error - For more information about this error, try `rustc --explain E0373`. -error: could not compile `threads` - -To learn more, run the command again with --verbose. +error: could not compile `threads` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-09/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-09/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-09/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-09/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -10,9 +10,5 @@ 10 | println!("val is {}", val); | ^^^ value borrowed here after move -error: aborting due to previous error - For more information about this error, try `rustc --explain E0382`. -error: could not compile `message-passing` - -To learn more, run the command again with --verbose. +error: could not compile `message-passing` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-13/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-13/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-13/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-13/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -11,9 +11,5 @@ 10 | let mut num = counter.lock().unwrap(); | ------- use occurs due to use in closure -error: aborting due to previous error - For more information about this error, try `rustc --explain E0382`. -error: could not compile `shared-state` - -To learn more, run the command again with --verbose. +error: could not compile `shared-state` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-14/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-14/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-14/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/listing-16-14/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -16,9 +16,5 @@ = help: within `[closure@src/main.rs:11:36: 15:10]`, the trait `Send` is not implemented for `Rc>` = note: required because it appears within the type `[closure@src/main.rs:11:36: 15:10]` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0277`. -error: could not compile `shared-state` - -To learn more, run the command again with --verbose. +error: could not compile `shared-state` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -14,9 +14,5 @@ 10 | drop(v); // oh no! | ^ value used here after move -error: aborting due to previous error - For more information about this error, try `rustc --explain E0382`. -error: could not compile `threads` - -To learn more, run the command again with --verbose. +error: could not compile `threads` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch17-oop/listing-17-10/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch17-oop/listing-17-10/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch17-oop/listing-17-10/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch17-oop/listing-17-10/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,9 +8,5 @@ | = note: required for the cast to the object type `dyn Draw` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0277`. -error: could not compile `gui` - -To learn more, run the command again with --verbose. +error: could not compile `gui` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch17-oop/no-listing-01-trait-object-of-clone/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch17-oop/no-listing-01-trait-object-of-clone/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch17-oop/no-listing-01-trait-object-of-clone/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch17-oop/no-listing-01-trait-object-of-clone/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -1,17 +1,13 @@ $ cargo build Compiling gui v0.1.0 (file:///projects/gui) error[E0038]: the trait `Clone` cannot be made into an object - --> src/lib.rs:2:21 + --> src/lib.rs:2:29 | 2 | pub components: Vec>, - | ^^^^^^^^^^^^^^^^^^^ `Clone` cannot be made into an object + | ^^^^^^^^^ `Clone` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit -error: aborting due to previous error - For more information about this error, try `rustc --explain E0038`. -error: could not compile `gui` - -To learn more, run the command again with --verbose. +error: could not compile `gui` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-05/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-05/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-05/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-05/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -11,9 +11,5 @@ = note: expected tuple `({integer}, {integer}, {integer})` found tuple `(_, _)` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0308`. -error: could not compile `patterns` - -To learn more, run the command again with --verbose. +error: could not compile `patterns` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-08/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-08/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-08/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-08/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -14,9 +14,5 @@ 3 | if let Some(x) = some_option_value { /* */ } | -error: aborting due to previous error - For more information about this error, try `rustc --explain E0005`. -error: could not compile `patterns` - -To learn more, run the command again with --verbose. +error: could not compile `patterns` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-10/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-10/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-10/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-10/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,8 +12,7 @@ = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` -warning: 1 warning emitted - +warning: `patterns` (bin "patterns") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.39s Running `target/debug/patterns` 5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-25/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-25/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-25/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch18-patterns-and-matching/listing-18-25/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,8 +8,4 @@ | | | previously used here -error: aborting due to previous error - -error: could not compile `patterns` - -To learn more, run the command again with --verbose. +error: could not compile `patterns` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/listing-19-05/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/listing-19-05/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/listing-19-05/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/listing-19-05/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -13,9 +13,5 @@ | | first mutable borrow occurs here | returning this value requires that `*slice` is borrowed for `'1` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0499`. -error: could not compile `unsafe-example` - -To learn more, run the command again with --verbose. +error: could not compile `unsafe-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/listing-19-20/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/listing-19-20/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/listing-19-20/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/listing-19-20/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -3,17 +3,15 @@ error[E0283]: type annotations needed --> src/main.rs:20:43 | -2 | fn baby_name() -> String; - | ------------------------- required by `Animal::baby_name` -... 20 | println!("A baby dog is called a {}", Animal::baby_name()); | ^^^^^^^^^^^^^^^^^ cannot infer type | = note: cannot satisfy `_: Animal` - -error: aborting due to previous error +note: required by `Animal::baby_name` + --> src/main.rs:2:5 + | +2 | fn baby_name() -> String; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ For more information about this error, try `rustc --explain E0283`. -error: could not compile `traits-example` - -To learn more, run the command again with --verbose. +error: could not compile `traits-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ = help: the trait `std::fmt::Display` is not implemented for `Point` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -error: aborting due to previous error - For more information about this error, try `rustc --explain E0277`. -error: could not compile `traits-example` - -To learn more, run the command again with --verbose. +error: could not compile `traits-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/no-listing-18-returns-closure/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -12,9 +12,5 @@ 1 | fn returns_closure() -> impl Fn(i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error - For more information about this error, try `rustc --explain E0746`. -error: could not compile `functions-example` - -To learn more, run the command again with --verbose. +error: could not compile `functions-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch19-advanced-features/output-only-01-missing-unsafe/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -8,9 +8,5 @@ | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to previous error - For more information about this error, try `rustc --explain E0133`. -error: could not compile `unsafe-example` - -To learn more, run the command again with --verbose. +error: could not compile `unsafe-example` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-12/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-12/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-12/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-12/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 10 | let pool = ThreadPool::new(4); | ^^^^^^^^^^ use of undeclared type `ThreadPool` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0433`. -error: could not compile `hello` - -To learn more, run the command again with --verbose. +error: could not compile `hello` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-17/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-17/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-17/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-17/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -9,9 +9,5 @@ 27 | workers.push(Worker::new(id, receiver)); | ^^^^^^^^ value moved here, in previous iteration of loop -error: aborting due to previous error - For more information about this error, try `rustc --explain E0382`. -error: could not compile `hello` - -To learn more, run the command again with --verbose. +error: could not compile `hello` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-22/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-22/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-22/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/listing-20-22/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 52 | worker.thread.join().unwrap(); | ^^^^^^^^^^^^^ move occurs because `worker.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait -error: aborting due to previous error - For more information about this error, try `rustc --explain E0507`. -error: could not compile `hello` - -To learn more, run the command again with --verbose. +error: could not compile `hello` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-01-define-threadpool-struct/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 11 | let pool = ThreadPool::new(4); | ^^^ function or associated item not found in `ThreadPool` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0599`. -error: could not compile `hello` - -To learn more, run the command again with --verbose. +error: could not compile `hello` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-02-impl-threadpool-new/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -6,9 +6,5 @@ 16 | pool.execute(|| { | ^^^^^^^ method not found in `ThreadPool` -error: aborting due to previous error - For more information about this error, try `rustc --explain E0599`. -error: could not compile `hello` - -To learn more, run the command again with --verbose. +error: could not compile `hello` due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt --- rustc-1.56.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt 2021-09-17 01:17:09.000000000 +0000 @@ -18,10 +18,6 @@ = note: expected enum `Option>` found struct `JoinHandle<_>` -error: aborting due to 2 previous errors - Some errors have detailed explanations: E0308, E0599. For more information about an error, try `rustc --explain E0308`. -error: could not compile `hello` - -To learn more, run the command again with --verbose. +error: could not compile `hello` due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/rust-toolchain rustc-1.57.0+dfsg1+llvm/src/doc/book/rust-toolchain --- rustc-1.56.0+dfsg1+llvm/src/doc/book/rust-toolchain 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/rust-toolchain 2021-09-17 01:17:09.000000000 +0000 @@ -1 +1 @@ -1.54 +1.55 diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/src/appendix-02-operators.md rustc-1.57.0+dfsg1+llvm/src/doc/book/src/appendix-02-operators.md --- rustc-1.56.0+dfsg1+llvm/src/doc/book/src/appendix-02-operators.md 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/src/appendix-02-operators.md 2021-09-17 01:17:09.000000000 +0000 @@ -136,7 +136,7 @@ |--------|-------------| | `T: U` | Generic parameter `T` constrained to types that implement `U` | | `T: 'a` | Generic type `T` must outlive lifetime `'a` (meaning the type cannot transitively contain any references with lifetimes shorter than `'a`) | -| `T : 'static` | Generic type `T` contains no borrowed references other than `'static` ones | +| `T: 'static` | Generic type `T` contains no borrowed references other than `'static` ones | | `'b: 'a` | Generic lifetime `'b` must outlive lifetime `'a` | | `T: ?Sized` | Allow generic type parameter to be a dynamically sized type | | `'a + trait`, `trait + trait` | Compound type constraint | diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/src/ch17-01-what-is-oo.md rustc-1.57.0+dfsg1+llvm/src/doc/book/src/ch17-01-what-is-oo.md --- rustc-1.56.0+dfsg1+llvm/src/doc/book/src/ch17-01-what-is-oo.md 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/src/ch17-01-what-is-oo.md 2021-09-17 01:17:09.000000000 +0000 @@ -12,7 +12,7 @@ The book *Design Patterns: Elements of Reusable Object-Oriented Software* by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley -Professional, 1994) colloquially referred to as *The Gang of Four* book, is a +Professional, 1994), colloquially referred to as *The Gang of Four* book, is a catalog of object-oriented design patterns. It defines OOP this way: > Object-oriented programs are made up of objects. An *object* packages both diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/book/src/title-page.md rustc-1.57.0+dfsg1+llvm/src/doc/book/src/title-page.md --- rustc-1.56.0+dfsg1+llvm/src/doc/book/src/title-page.md 2021-09-01 01:26:19.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/book/src/title-page.md 2021-09-17 01:17:09.000000000 +0000 @@ -2,7 +2,7 @@ *by Steve Klabnik and Carol Nichols, with contributions from the Rust Community* -This version of the text assumes you’re using Rust 1.54 or later with +This version of the text assumes you’re using Rust 1.55 or later with `edition="2018"` in *Cargo.toml* of all projects to use Rust 2018 Edition idioms. See the [“Installation†section of Chapter 1][install] to install or update Rust, and see the new [Appendix E][editions] ```rust,ignore -if inner.rc.fetch_sub(1, Ordering::Relaxed) != 1 { +if inner.rc.fetch_sub(1, Ordering::Release) != 1 { return; } ``` diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/leaking.md rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/leaking.md --- rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/leaking.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/leaking.md 2021-11-29 19:27:28.000000000 +0000 @@ -176,6 +176,12 @@ ## thread::scoped::JoinGuard +> Note: This API has already been removed from std, for more information +> you may refer [issue #24292](https://github.com/rust-lang/rust/issues/24292). +> +> We still remain this chapter here because we think this example is still +> important, regardless of if it is still in std. + The thread::scoped API intended to allow threads to be spawned that reference data on their parent's stack without any synchronization over that data by ensuring the parent joins the thread before any of the shared data goes out diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/lifetimes.md rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/lifetimes.md --- rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/lifetimes.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/lifetimes.md 2021-11-29 19:27:28.000000000 +0000 @@ -224,8 +224,8 @@ ## The area covered by a lifetime A reference (sometimes called a *borrow*) is *alive* from the place it is -created to its last use. The borrowed thing needs to outlive only borrows that -are alive. This looks simple, but there are few subtleties. +created to its last use. The borrowed value needs to outlive only borrows that +are alive. This looks simple, but there are a few subtleties. The following snippet compiles, because after printing `x`, it is no longer needed, so it doesn't matter if it is dangling or aliased (even though the diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/other-reprs.md rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/other-reprs.md --- rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/other-reprs.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/other-reprs.md 2021-11-29 19:27:28.000000000 +0000 @@ -91,7 +91,7 @@ These `repr`s have no effect on a struct. -Adding an explicit `repr(u*)`, `repr(i*)`, or `repr(C)` to an enum suppresses the null-pointer optimization, like: +Adding an explicit `repr(u*)`, `repr(i*)`, or `repr(C)` to an enum with fields suppresses the null-pointer optimization, like: ```rust # use std::mem::size_of; @@ -110,6 +110,8 @@ assert_eq!(16, size_of::>()); ``` +This optimization still applies to fieldless enums with an explicit `repr(u*)`, `repr(i*)`, or `repr(C)`. + ## repr(packed) `repr(packed)` forces Rust to strip any padding, and only align the type to a diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/send-and-sync.md rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/send-and-sync.md --- rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/send-and-sync.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/send-and-sync.md 2021-11-29 19:27:28.000000000 +0000 @@ -102,7 +102,7 @@ pub fn new(value: T) -> Self { // Allocate enough memory on the heap to store one T. assert_ne!(size_of::(), 0, "Zero-sized types are out of the scope of this example"); - let mut memptr = ptr::null_mut() as *mut T; + let mut memptr: *mut T = ptr::null_mut(); unsafe { let ret = libc::posix_memalign( (&mut memptr).cast(), @@ -113,10 +113,10 @@ }; // NonNull is just a wrapper that enforces that the pointer isn't null. - let mut ptr = unsafe { + let ptr = { // Safety: memptr is dereferenceable because we created it from a // reference and have exclusive access. - ptr::NonNull::new(memptr.cast::()) + ptr::NonNull::new(memptr) .expect("Guaranteed non-null if posix_memalign returns 0") }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/subtyping.md rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/subtyping.md --- rustc-1.56.0+dfsg1+llvm/src/doc/nomicon/src/subtyping.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/nomicon/src/subtyping.md 2021-11-29 19:27:28.000000000 +0000 @@ -418,7 +418,7 @@ **contra**variant over their arguments. Now, this is all well and good for the types the standard library provides, but -how is variance determined for type that *you* define? A struct, informally +how is variance determined for types that *you* define? A struct, informally speaking, inherits the variance of its fields. If a struct `MyType` has a generic argument `A` that is used in a field `a`, then MyType's variance over `A` is exactly `a`'s variance over `A`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/attributes/limits.md rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/attributes/limits.md --- rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/attributes/limits.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/attributes/limits.md 2021-11-29 19:27:29.000000000 +0000 @@ -15,10 +15,10 @@ #![recursion_limit = "4"] macro_rules! a { - () => { a!(1) }; - (1) => { a!(2) }; - (2) => { a!(3) }; - (3) => { a!(4) }; + () => { a!(1); }; + (1) => { a!(2); }; + (2) => { a!(3); }; + (3) => { a!(4); }; (4) => { }; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/items/generics.md rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/items/generics.md --- rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/items/generics.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/items/generics.md 2021-11-29 19:27:29.000000000 +0000 @@ -37,7 +37,7 @@ declared. They are not in scope for items declared within the body of a function as described in [item declarations]. -[References], [raw pointers], [arrays], [slices][arrays], [tuples], and +[References], [raw pointers], [arrays], [slices], [tuples], and [function pointers] have lifetime or type parameters as well, but are not referred to with path syntax. @@ -274,6 +274,7 @@ [array repeat expression]: ../expressions/array-expr.md [arrays]: ../types/array.md +[slices]: ../types/slice.md [associated const]: associated-items.md#associated-constants [associated type]: associated-items.md#associated-types [block]: ../expressions/block-expr.md diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/patterns.md rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/patterns.md --- rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/patterns.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/patterns.md 2021-11-29 19:27:29.000000000 +0000 @@ -13,7 +13,6 @@ >    | [_IdentifierPattern_]\ >    | [_WildcardPattern_]\ >    | [_RestPattern_]\ ->    | [_ObsoleteRangePattern_]\ >    | [_ReferencePattern_]\ >    | [_StructPattern_]\ >    | [_TupleStructPattern_]\ @@ -407,7 +406,15 @@ > **Syntax**\ > _RangePattern_ :\ ->    _RangePatternBound_ `..=` _RangePatternBound_ +>       _InclusiveRangePattern_\ +>    | _HalfOpenRangePattern_\ +>    | _ObsoleteRangePattern_ +> +> _InclusiveRangePattern_ :\ +>       _RangePatternBound_ `..=` _RangePatternBound_ +> +> _HalfOpenRangePattern_ :\ +>    | _RangePatternBound_ `..` > > _ObsoleteRangePattern_ :\ >    _RangePatternBound_ `...` _RangePatternBound_ @@ -420,11 +427,20 @@ >    | [_PathInExpression_]\ >    | [_QualifiedPathInExpression_] -Range patterns match values that are within the closed range defined by its lower and -upper bounds. For example, a pattern `'m'..='p'` will match only the values `'m'`, `'n'`, -`'o'`, and `'p'`. The bounds can be literals or paths that point to constant values. +Range patterns match values within the range defined by their bounds. A range pattern may be +closed or half-open. A range pattern is closed if it has both a lower and an upper bound, and +it matches all the values between and including both of its bounds. A range pattern that is +half-open is written with a lower bound but not an upper bound, and matches any value equal to +or greater than the specified lower bound. + +For example, a pattern `'m'..='p'` will match only the values `'m'`, `'n'`, `'o'`, and `'p'`. For an integer the +pattern `1..` will match 9, or 9001, or 9007199254740991 (if it is of an appropriate size), but +not 0, and not negative numbers for signed integers. The bounds can be literals or paths that point +to constant values. + +A half-open range pattern in the style `a..` cannot be used to match within the context of a slice. -A pattern a `..=` b must always have a ≤ b. It is an error to have a range pattern +A pattern `a..=b` must always have a ≤ b. It is an error to have a range pattern `10..=0`, for example. The `...` syntax is kept for backwards compatibility. @@ -456,6 +472,12 @@ _ => unreachable!(), }); +# let uint: u32 = 5; +match uint { + 0 => "zero!", + 1.. => "positive number!", +}; + // using paths to constants: # const TROPOSPHERE_MIN : u8 = 6; # const TROPOSPHERE_MAX : u8 = 20; @@ -736,6 +758,10 @@ a single `..` [rest pattern](#rest-patterns) or [identifier pattern](#identifier-patterns) with the `..` rest pattern as a subpattern. +Within a slice, a half-open range pattern like `a..` must be enclosed in parentheses, +as in `(a..)`, to clarify it is intended to match a single value. +A future version of Rust may give the non-parenthesized version an alternate meaning. + ## Path patterns > **Syntax**\ diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/tokens.md rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/tokens.md --- rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/tokens.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/tokens.md 2021-11-29 19:27:29.000000000 +0000 @@ -585,7 +585,7 @@ | `@` | At | [Subpattern binding] | `_` | Underscore | [Wildcard patterns], [Inferred types], Unnamed items in [constants], [extern crates], and [use declarations] | `.` | Dot | [Field access][field], [Tuple index] -| `..` | DotDot | [Range][range], [Struct expressions], [Patterns] +| `..` | DotDot | [Range][range], [Struct expressions], [Patterns], [Range Patterns][rangepat] | `...` | DotDotDot | [Variadic functions][extern], [Range patterns] | `..=` | DotDotEq | [Inclusive Range][range], [Range patterns] | `,` | Comma | Various separators @@ -646,6 +646,7 @@ [patterns]: patterns.md [question]: expressions/operator-expr.md#the-question-mark-operator [range]: expressions/range-expr.md +[rangepat]: patterns.md#range-patterns [raw pointers]: types/pointer.md#raw-pointers-const-and-mut [references]: types/pointer.md [sized]: trait-bounds.md#sized diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/type-coercions.md rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/type-coercions.md --- rustc-1.56.0+dfsg1+llvm/src/doc/reference/src/type-coercions.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/reference/src/type-coercions.md 2021-11-29 19:27:29.000000000 +0000 @@ -147,7 +147,7 @@ and where `U` can be obtained from `T` by [unsized coercion](#unsized-coercions). * Function item types to `fn` pointers diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/cargo/test.md rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/cargo/test.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/cargo/test.md 2021-08-17 11:01:20.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/cargo/test.md 2021-10-04 11:13:53.000000000 +0000 @@ -150,5 +150,5 @@ [testing]: ../testing.md [unit_testing]: ../testing/unit_testing.md -[integration_testing]: ../testing/unit_testing.md +[integration_testing]: ../testing/integration_testing.md [doc_testing]: ../testing/doc_testing.md diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/fn.md rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/fn.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/fn.md 2021-08-17 11:01:20.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/fn.md 2021-10-04 11:13:53.000000000 +0000 @@ -44,7 +44,7 @@ // When a function returns `()`, the return type can be omitted from the // signature fn fizzbuzz_to(n: u32) { - for n in 1..n + 1 { + for n in 1..=n { fizzbuzz(n); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/generics.md rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/generics.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/generics.md 2021-08-17 11:01:20.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/generics.md 2021-10-04 11:13:53.000000000 +0000 @@ -2,7 +2,7 @@ *Generics* is the topic of generalizing types and functionalities to broader cases. This is extremely useful for reducing code duplication in many ways, -but can call for rather involving syntax. Namely, being generic requires +but can call for rather involved syntax. Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid. The simplest and most common use of generics is for type parameters. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/hello/print/fmt.md rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/hello/print/fmt.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/hello/print/fmt.md 2021-08-17 11:01:20.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/hello/print/fmt.md 2021-10-04 11:13:53.000000000 +0000 @@ -80,7 +80,7 @@ Two hints if you get stuck: * You [may need to list each color more than once][named_parameters], - * You can [pad with zeros to a width of 2][fmt_width] with `:02`. + * You can [pad with zeros to a width of 2][fmt_width] with `:0>2`. ### See also: diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/std/arc.md rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/std/arc.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/std/arc.md 2021-08-17 11:01:20.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/std/arc.md 2021-10-04 11:13:53.000000000 +0000 @@ -3,25 +3,24 @@ When shared ownership between threads is needed, `Arc`(Atomic Reference Counted) can be used. This struct, via the `Clone` implementation can create a reference pointer for the location of a value in the memory heap while increasing the reference counter. As it shares ownership between threads, when the last reference pointer to a value is out of scope, the variable is dropped. ```rust,editable - -fn main() { use std::sync::Arc; use std::thread; -// This variable declaration is where its value is specified. -let apple = Arc::new("the same apple"); - -for _ in 0..10 { - // Here there is no value specification as it is a pointer to a reference - // in the memory heap. - let apple = Arc::clone(&apple); +fn main() { + // This variable declaration is where its value is specified. + let apple = Arc::new("the same apple"); - thread::spawn(move || { - // As Arc was used, threads can be spawned using the value allocated - // in the Arc variable pointer's location. - println!("{:?}", apple); - }); -} + for _ in 0..10 { + // Here there is no value specification as it is a pointer to a reference + // in the memory heap. + let apple = Arc::clone(&apple); + + thread::spawn(move || { + // As Arc was used, threads can be spawned using the value allocated + // in the Arc variable pointer's location. + println!("{:?}", apple); + }); + } } ``` diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/trait/impl_trait.md rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/trait/impl_trait.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rust-by-example/src/trait/impl_trait.md 2021-08-17 11:01:20.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rust-by-example/src/trait/impl_trait.md 2021-10-04 11:13:53.000000000 +0000 @@ -68,4 +68,10 @@ .filter(|x| x > &&0) .map(|x| x * 2) } + +fn main() { + let singles = vec![-3, -2, 2, 3]; + let doubles = double_positives(&singles); + assert_eq!(doubles.collect::>(), vec![4, 6]); +} ``` diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/codegen-options/index.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/codegen-options/index.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/codegen-options/index.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/codegen-options/index.md 2021-11-29 19:27:11.000000000 +0000 @@ -435,6 +435,10 @@ depending on the produced crate types. \ This is the default model for majority of supported targets. +- `pie` - position independent executable, relocatable code but without support for symbol +interpositioning (replacing symbols by name using `LD_PRELOAD` and similar). Equivalent to the "uppercase" `-fPIE` option in other compilers. `pie` +code cannot be linked into shared libraries (you'll get a linking error on attempt to do this). + #### Special relocation models - `dynamic-no-pic` - relocatable external references, non-relocatable code. \ diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,66 @@ +# armv7-unknown-linux-uclibceabihf + +**Tier: 3** + +This tier supports the ARMv7 processor running a Linux kernel and uClibc-ng standard library. It provides full support for rust and the rust standard library. + +## Designated Developers + +* [@skrap](https://github.com/skrap) + +## Requirements + +This target is cross compiled, and requires a cross toolchain. You can find suitable pre-built toolchains at [bootlin](https://toolchains.bootlin.com/) or build one yourself via [buildroot](https://buildroot.org). + +## Building + +### Get a C toolchain + +Compiling rust for this target has been tested on `x86_64` linux hosts. Other host types have not been tested, but may work, if you can find a suitable cross compilation toolchain for them. + +If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2020.08-1.tar.bz2), and unpack it into a directory. + +### Configure rust + +The target can be built by enabling it for a `rustc` build, by placing the following in `config.toml`: + +```toml +[build] +target = ["armv7-unknown-linux-uclibceabihf"] +stage = 2 + +[target.armv7-unknown-linux-uclibceabihf] +# ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN +cc = "/TOOLCHAIN_PATH/bin/arm-buildroot-linux-uclibcgnueabihf-gcc" +``` + +### Build + +```sh +# in rust dir +./x.py build --stage 2 +``` + +## Building and Running Rust Programs + +To test cross-compiled binaries on a `x86_64` system, you can use the `qemu-arm` [userspace emulation](https://qemu-project.gitlab.io/qemu/user/main.html) program. This avoids having a full emulated ARM system by doing dynamic binary translation and dynamic system call translation. It lets you run ARM programs directly on your `x86_64` kernel. It's very convenient! + +To use: + +* Install `qemu-arm` according to your distro. +* Link your built toolchain via: + * `rustup toolchain link stage2 ${RUST}/build/x86_64-unknown-linux-gnu/stage2` +* Create a test program + +```sh +cargo new hello_world +cd hello_world +``` + +* Build and run + +```sh +CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABIHF_RUNNER="qemu-arm -L ${TOOLCHAIN}/arm-buildroot-linux-uclibcgnueabihf/sysroot/" \ +CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABIHF_LINKER=${TOOLCHAIN}/bin/arm-buildroot-linux-uclibcgnueabihf-gcc \ +cargo +stage2 run --target armv7-unknown-linux-uclibceabihf +``` diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/platform-support/kmc-solid.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/platform-support/kmc-solid.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/platform-support/kmc-solid.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/platform-support/kmc-solid.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,65 @@ +# \*-kmc-solid_\* + +**Tier: 3** + +[SOLID] embedded development platform by Kyoto Microcomputer Co., Ltd. + +[SOLID]: https://www.kmckk.co.jp/eng/SOLID/ + +The target names follow this format: `$ARCH-kmc-solid_$KERNEL-$ABI`, where `$ARCH` specifies the target processor architecture, `$KERNEL` the base kernel, and `$ABI` the target ABI (optional). The following targets are currently defined: + +| Target name | `target_arch` | `target_vendor` | `target_os` | +|--------------------------------|---------------|-----------------|--------------| +| `aarch64-kmc-solid_asp3` | `aarch64` | `kmc` | `solid_asp3` | +| `armv7a-kmc-solid_asp3-eabi` | `arm` | `kmc` | `solid_asp3` | +| `armv7a-kmc-solid_asp3-eabihf` | `arm` | `kmc` | `solid_asp3` | + +## Designated Developers + +- [@kawadakk](https://github.com/kawadakk) + +## Requirements + +This target is cross-compiled. +A platform-provided C compiler toolchain is required, though it can be substituted by [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm) for the purpose of building Rust and functional binaries. + +## Building + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["aarch64-kmc-solid_asp3"] +``` + +Make sure `aarch64-kmc-elf-gcc` is included in `$PATH`. Alternatively, you can use GNU Arm Embedded Toolchain by adding the following to `config.toml`: + +```toml +[target.aarch64-kmc-solid_asp3] +cc = "arm-none-eabi-gcc" +``` + +## Cross-compilation + +This target can be cross-compiled from any hosts. + +## Testing + +Currently there is no support to run the rustc test suite for this target. + +## Building Rust programs + +Building executables is not supported yet. + +If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target: + +```shell +$ rustc --target aarch64-kmc-solid_asp3 your-code.rs --crate-type staticlib +$ ls libyour_code.a +``` + +On Rust Nightly it's possible to build without the target artifacts available: + +```text +cargo build -Z build-std --target aarch64-kmc-solid_asp3 +``` diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,97 @@ +# m68k-unknown-linux-gnu + +**Tier: 3** + +Motorola 680x0 Linux + +## Designated Developers + +* [@glaubitz](https://github.com/glaubitz) +* [@ricky26](https://github.com/ricky26) + +## Requirements + +This target requires a Linux/m68k build environment for cross-compilation which +is available on Debian and Debian-based systems, openSUSE and other distributions. + +On Debian, it should be sufficient to install a g++ cross-compiler for the m68k +architecture which will automatically pull in additional dependencies such as +the glibc cross development package: + +```text +# apt install g++-m68k-linux-gnu +``` + +Binaries can be run using QEMU user emulation. On Debian-based systems, it should be +sufficient to install the package `qemu-user-static` to be able to run simple static +binaries: + +```text +# apt install qemu-user-static +``` + +To run more complex programs, it will be necessary to set up a Debian/m68k chroot with +the help of the command `debootstrap`: + +```text +# apt install debootstrap debian-ports-archive-keyring +# debootstrap --keyring=/usr/share/keyrings/debian-ports-archive-keyring.gpg --arch=m68k unstable debian-68k http://ftp.ports.debian.org/debian-ports +``` + +This chroot can then seamlessly entered using the normal `chroot` command thanks to +QEMU user emulation: + +```text +# chroot /path/to/debian-68k +``` + +To get started with native builds, which are currently untested, a native Debian/m68k +system can be installed either on real hardware such as 68k-based Commodore Amiga or +Atari systems or emulated environments such as QEMU version 4.2 or newer or ARAnyM. + +ISO images for installation are provided by the Debian Ports team and can be obtained +from the Debian CD image server available at: + +[https://cdimage.debian.org/cdimage/ports/current](https://cdimage.debian.org/cdimage/ports/current/) + +Documentation for Debian/m68k is available on the Debian Wiki at: + +[https://wiki.debian.org/M68k](https://wiki.debian.org/M68k) + +Support is available either through the `debian-68k` mailing list: + +[https://lists.debian.org/debian-68k/](https://lists.debian.org/debian-68k/) + +or the `#debian-68k` IRC channel on OFTC network. + +## Building + +The codegen for this target should be built by default. However, core and std +are currently missing but are being worked on and should become available in +the near future. + +## Cross-compilation + +This target can be cross-compiled from a standard Debian or Debian-based, openSUSE or any +other distribution which has a basic m68k cross-toolchain available. + +## Testing + +Currently there is no support to run the rustc test suite for this target. + +## Building Rust programs + +Rust programs can be built for that target: + +```text +rustc --target m68k-unknown-linux-gnu your-code.rs +``` + +Very simple progams can be run using the `qemu-m68k-static` program: + +```text +$ qemu-m68k-static your-code +``` + +For more complex applications, a chroot or native (emulated) Debian/m68k system are required +for testing. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/platform-support.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/platform-support.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/platform-support.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/platform-support.md 2021-11-29 19:27:11.000000000 +0000 @@ -133,8 +133,8 @@ `armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL `armv7-linux-androideabi` | ✓ | ARMv7a Android `armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27) -`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux, MUSL -`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL +`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux with MUSL +`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL, hardfloat `armv7a-none-eabi` | * | Bare ARMv7-A `armv7r-none-eabi` | * | Bare ARMv7-R `armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat @@ -202,6 +202,7 @@ -------|:---:|:----:|------- `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 `aarch64-apple-tvos` | * | | ARM64 tvOS +[`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ? | | `aarch64-unknown-uefi` | * | | ARM64 UEFI @@ -217,10 +218,14 @@ `armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD `armv6-unknown-netbsd-eabihf` | ? | | +`armv6k-nintendo-3ds` | * | | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain) `armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8 +`armv7-unknown-linux-uclibceabihf` | ✓ | ? | ARMv7 Linux uClibc `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD `armv7-unknown-netbsd-eabihf` | ✓ | ✓ | `armv7-wrs-vxworks-eabihf` | ? | | +[`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 +[`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat `armv7s-apple-ios` | ✓ | | `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` @@ -237,6 +242,7 @@ `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | `i686-wrs-vxworks` | ? | | +`m68k-unknown-linux-gnu` | ? | | Motorola 680x0 Linux `mips-unknown-linux-uclibc` | ✓ | | MIPS Linux with uClibc `mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP) `mipsel-unknown-linux-uclibc` | ✓ | | MIPS (LE) Linux with uClibc diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/SUMMARY.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/SUMMARY.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/SUMMARY.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/SUMMARY.md 2021-11-29 19:27:11.000000000 +0000 @@ -14,6 +14,7 @@ - [Tests](tests/index.md) - [Platform Support](platform-support.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) + - [\*-kmc-solid_\*](platform-support/kmc-solid.md) - [Target Tier Policy](target-tier-policy.md) - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/tests/index.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/tests/index.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc/src/tests/index.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc/src/tests/index.md 2021-11-29 19:27:11.000000000 +0000 @@ -161,7 +161,7 @@ Sets the number of threads to use for running tests in parallel. By default, uses the amount of concurrency available on the hardware as indicated by -[`available_concurrency`]. +[`available_parallelism`]. This can also be specified with the `RUST_TEST_THREADS` environment variable. @@ -181,6 +181,40 @@ #64888](https://github.com/rust-lang/rust/issues/64888) and the [unstable docs](../../unstable-book/compiler-flags/report-time.html) for more information. +#### `--shuffle` + +Runs the tests in random order, as opposed to the default alphabetical order. + +This may also be specified by setting the `RUST_TEST_SHUFFLE` environment +variable to anything but `0`. + +The random number generator seed that is output can be passed to +[`--shuffle-seed`](#--shuffle-seed-seed) to run the tests in the same order +again. + +Note that `--shuffle` does not affect whether the tests are run in parallel. To +run the tests in random order sequentially, use `--shuffle --test-threads 1`. + +âš ï¸ ðŸš§ This option is [unstable](#unstable-options), and requires the `-Z +unstable-options` flag. See [tracking issue +#89583](https://github.com/rust-lang/rust/issues/89583) for more information. + +#### `--shuffle-seed` _SEED_ + +Like [`--shuffle`](#--shuffle), but seeds the random number generator with +_SEED_. Thus, calling the test harness with `--shuffle-seed` _SEED_ twice runs +the tests in the same order both times. + +_SEED_ is any 64-bit unsigned integer, for example, one produced by +[`--shuffle`](#--shuffle). + +This can also be specified with the `RUST_TEST_SHUFFLE_SEED` environment +variable. + +âš ï¸ ðŸš§ This option is [unstable](#unstable-options), and requires the `-Z +unstable-options` flag. See [tracking issue +#89583](https://github.com/rust-lang/rust/issues/89583) for more information. + ### Output options The following options affect the output behavior. @@ -197,7 +231,7 @@ fails. This may also be specified by setting the `RUST_TEST_NOCAPTURE` environment -variable set to anything but `0`. +variable to anything but `0`. #### `--show-output` @@ -265,7 +299,7 @@ [`--test` option]: ../command-line-arguments.md#option-test [`-Z panic-abort-tests`]: https://github.com/rust-lang/rust/issues/67650 -[`available_concurrency`]: ../../std/thread/fn.available_concurrency.html +[`available_parallelism`]: ../../std/thread/fn.available_parallelism.html [`cargo test`]: ../../cargo/commands/cargo-test.html [`libtest`]: ../../test/index.html [`main` function]: ../../reference/crates-and-source-files.html#main-functions diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md 2021-11-29 19:27:29.000000000 +0000 @@ -2,7 +2,7 @@ -As of January 2021, `rustc_codegen_ssa` provides an +As of October 2021, `rustc_codegen_ssa` provides an abstract interface for all backends to implement, to allow other codegen backends (e.g. [Cranelift]). diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/backend/updating-llvm.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/backend/updating-llvm.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/backend/updating-llvm.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/backend/updating-llvm.md 2021-11-29 19:27:29.000000000 +0000 @@ -67,7 +67,7 @@ ## Feature updates > Note that this information is as of the time of this writing (April 2021). The process for updating LLVM changes with +2021-10 --> (October 2021). The process for updating LLVM changes with practically all LLVM updates, so this may be out of date! Unlike bugfixes, updating to pick up a new feature of LLVM typically requires a diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md 2021-11-29 19:27:29.000000000 +0000 @@ -94,7 +94,7 @@ ## Choices are always lifetime parameters At present, the "choice" regions from a member constraint are always lifetime -parameters from the current function. As of January 2021, +parameters from the current function. As of October 2021, this falls out from the placement of impl Trait, though in the future it may not be the case. We take some advantage of this fact, as it simplifies the current code. In particular, we don't have to consider a case like `'0 member of ['1, diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md 2021-11-29 19:27:29.000000000 +0000 @@ -77,7 +77,7 @@ [converted]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/cx/expr/trait.ToBorrowKind.html#method.to_borrow_kind [`BorrowKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.BorrowKind.html [`GatherBorrows`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/visit/trait.Visitor.html#method.visit_local -[`BorrowData`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/borrow_set/struct.BorrowData.html +[`BorrowData`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/borrow_set/struct.BorrowData.html ## Checking two-phase borrows @@ -95,6 +95,6 @@ by using the [`Dominators`] for the MIR graph. 4. After the activation point, the two-phase borrow acts as a mutable borrow. -[check]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/struct.MirBorrowckCtxt.html#method.check_activations +[check]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/struct.MirBorrowckCtxt.html#method.check_activations [`Dominators`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/graph/dominators/struct.Dominators.html -[`is_active`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/path_utils/fn.is_active.html +[`is_active`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/path_utils/fn.is_active.html diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/building/ctags.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/building/ctags.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/building/ctags.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/building/ctags.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -# ctags - -One of the challenges with rustc is that the RLS can't handle it, since it's a -bootstrapping compiler. This makes code navigation difficult. One solution is to -use `ctags`. - -`ctags` has a long history and several variants. Exuberant Ctags seems to be -quite commonly distributed but it does not have out-of-box Rust support. Some -distributions seem to use [Universal Ctags][utags], which is a maintained fork -and does have built-in Rust support. - -The following script can be used to set up Exuberant Ctags: -[https://github.com/nikomatsakis/rust-etags][etags]. - -`ctags` integrates into emacs and vim quite easily. The following can then be -used to build and generate tags: - -```console -$ rust-ctags src/lib* && ./x.py build -``` - -This allows you to do "jump-to-def" with whatever functions were around when -you last built, which is ridiculously useful. - -[etags]: https://github.com/nikomatsakis/rust-etags -[utags]: https://github.com/universal-ctags/ctags diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/building/suggested.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/building/suggested.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/building/suggested.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/building/suggested.md 2021-11-29 19:27:29.000000000 +0000 @@ -22,7 +22,7 @@ a file. By default, `rust-analyzer` runs the `cargo check` and `rustfmt` commands, but you can override these commands to use more adapted versions of these tools when hacking on `rustc`. For example, for Visual Studio Code, -you can write: +you can write: ```JSON { @@ -32,7 +32,8 @@ "--json-output" ], "rust-analyzer.rustfmt.overrideCommand": [ - "./build/TARGET_TRIPLE/stage0/bin/rustfmt" + "./build/TARGET_TRIPLE/stage0/bin/rustfmt", + "--edition=2021" ], "editor.formatOnSave": true, "rust-analyzer.cargo.runBuildScripts": false, diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/closure.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/closure.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/closure.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/closure.md 2021-11-29 19:27:29.000000000 +0000 @@ -162,7 +162,7 @@ Let's start with [`upvar.rs`][upvar]. This file has something called the [`euv::ExprUseVisitor`] which walks the source of the closure and -invokes a callbackfor each upvar that is borrowed, mutated, or moved. +invokes a callback for each upvar that is borrowed, mutated, or moved. [`euv::ExprUseVisitor`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_typeck/expr_use_visitor/struct.ExprUseVisitor.html @@ -199,7 +199,7 @@ comments, "`cmt` is a complete categorization of a value indicating where it originated and how it is located, as well as the mutability of the memory in which the value is stored". Based on the callback (consume, borrow etc.), we -will call the relevant *adjust_upvar_borrow_kind_for_* and pass the +will call the relevant `adjust_upvar_borrow_kind_for_` and pass the `cmt` along. Once the borrow type is adjusted, we store it in the table, which basically says what borrows were made for each closure. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/compiler-debugging.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/compiler-debugging.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/compiler-debugging.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/compiler-debugging.md 2021-11-29 19:27:29.000000000 +0000 @@ -159,145 +159,12 @@ Cool, now I have a backtrace for the error! ## Getting logging output -[getting-logging-output]: #getting-logging-output The compiler uses the [`tracing`] crate for logging. [`tracing`]: https://docs.rs/tracing -The compiler has a lot of [`debug!`] calls, which print out logging information -at many points. These are very useful to at least narrow down the location of -a bug if not to find it entirely, or just to orient yourself as to why the -compiler is doing a particular thing. - -[`debug!`]: https://docs.rs/tracing/0.1/tracing/macro.debug.html - -To see the logs, you need to set the `RUSTC_LOG` environment variable to your -log filter. Your log filter can be just `debug` to get all `debug!` output and -higher (e.g., it will also include `info!`), or `path::to::module` to get *all* -output (which will include `trace!`) from a particular module, or -`path::to::module=debug` to get `debug!` output and higher from a particular -module. - -For example, to get the `debug!` output and higher for a specific module, you -can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`. -All `debug!` output will then appear in standard error. - -Note that you can use a partial path and the filter will still work. For -example, if you want to see `info!` output from only -`rustdoc::passes::collect_intra_doc_links`, you could use -`RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use -`RUSTDOC_LOG=rustdoc::passes::collect_intra=info`. - -If you are developing rustdoc, use `RUSTDOC_LOG` instead. If you are developing -Miri, use `MIRI_LOG` instead. You get the idea :) - -See the [`tracing`] crate's docs, and specifically the docs for [`debug!`] to -see the full syntax you can use. (Note: unlike the compiler, the [`tracing`] -crate and its examples use the `RUST_LOG` environment variable. rustc, rustdoc, -and other tools set custom environment variables.) - -**Note that unless you use a very strict filter, the logger will emit a lot of -output, so use the most specific module(s) you can (comma-separated if -multiple)**. It's typically a good idea to pipe standard error to a file and -look at the log output with a text editor. - -So, to put it together: - -```bash -# This puts the output of all debug calls in `rustc_middle/src/traits` into -# standard error, which might fill your console backscroll. -$ RUSTC_LOG=rustc_middle::traits=debug rustc +stage1 my-file.rs - -# This puts the output of all debug calls in `rustc_middle/src/traits` in -# `traits-log`, so you can then see it with a text editor. -$ RUSTC_LOG=rustc_middle::traits=debug rustc +stage1 my-file.rs 2>traits-log - -# Not recommended! This will show the output of all `debug!` calls -# in the Rust compiler, and there are a *lot* of them, so it will be -# hard to find anything. -$ RUSTC_LOG=debug rustc +stage1 my-file.rs 2>all-log - -# This will show the output of all `info!` calls in `rustc_codegen_ssa`. -# -# There's an `info!` statement in `codegen_instance` that outputs -# every function that is codegen'd. This is useful to find out -# which function triggers an LLVM assertion, and this is an `info!` -# log rather than a `debug!` log so it will work on the official -# compilers. -$ RUSTC_LOG=rustc_codegen_ssa=info rustc +stage1 my-file.rs - -# This will show the output of all `info!` calls made by rustdoc -# or any rustc library it calls. -$ RUSTDOC_LOG=info rustdoc +stage1 my-file.rs - -# This will only show `debug!` calls made by rustdoc directly, -# not any `rustc*` crate. -$ RUSTDOC_LOG=rustdoc=debug rustdoc +stage1 my-file.rs -``` - -### Log colors - -By default, rustc (and other tools, like rustdoc and Miri) will be smart about -when to use ANSI colors in the log output. If they are outputting to a terminal, -they will use colors, and if they are outputting to a file or being piped -somewhere else, they will not. However, it's hard to read log output in your -terminal unless you have a very strict filter, so you may want to pipe the -output to a pager like `less`. But then there won't be any colors, which makes -it hard to pick out what you're looking for! - -You can override whether to have colors in log output with the `RUSTC_LOG_COLOR` -environment variable (or `RUSTDOC_LOG_COLOR` for rustdoc, or `MIRI_LOG_COLOR` -for Miri, etc.). There are three options: `auto` (the default), `always`, and -`never`. So, if you want to enable colors when piping to `less`, use something -similar to this command: - -```bash -# The `-R` switch tells less to print ANSI colors without escaping them. -$ RUSTC_LOG=debug RUSTC_LOG_COLOR=always rustc +stage1 ... | less -R -``` - -Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, not logs -from rustc functions that Miri calls. Use `RUSTC_LOG_COLOR` to color logs from -rustc. - -### How to keep or remove `debug!` and `trace!` calls from the resulting binary - -While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, -calls to `debug!` and `trace!` are only included in the program if -`debug-logging=true` is turned on in config.toml (it is -turned off by default), so if you don't see `DEBUG` logs, especially -if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see -`INFO` logs, make sure that `debug-logging=true` is turned on in your -config.toml. - -### Logging etiquette and conventions - -Because calls to `debug!` are removed by default, in most cases, don't worry -about adding "unnecessary" calls to `debug!` and leaving them in code you -commit - they won't slow down the performance of what we ship, and if they -helped you pinning down a bug, they will probably help someone else with a -different one. - -A loosely followed convention is to use `debug!("foo(...)")` at the _start_ of -a function `foo` and `debug!("foo: ...")` _within_ the function. Another -loosely followed convention is to use the `{:?}` format specifier for debug -logs. - -One thing to be **careful** of is **expensive** operations in logs. - -If in the module `rustc::foo` you have a statement - -```Rust -debug!("{:?}", random_operation(tcx)); -``` - -Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::bar`, then -`random_operation()` will run. - -This means that you should not put anything too expensive or likely to crash -there - that would annoy anyone who wants to use logging for their own module. -No-one will know it until someone tries to use logging to find *another* bug. +For details see [the guide section on tracing](./tracing.md) ## Formatting Graphviz output (.dot files) [formatting-graphviz-output]: #formatting-graphviz-output diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/constants.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/constants.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/constants.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/constants.md 2021-11-29 19:27:29.000000000 +0000 @@ -0,0 +1,65 @@ +# Constants in the type system + +Constants used in the type system are represented as [`ty::Const`]. +The variants of their [`ty::ConstKind`] mostly mirror the variants of [`ty::TyKind`] +with the two *additional* variants being `ConstKind::Value` and `ConstKind::Unevaluated`. + + +## Unevaluated constants + +*This section talks about what's happening with `feature(generic_const_exprs)` enabled. +On stable we do not yet supply any generic parameters to anonymous constants, +avoiding most of the issues mentioned here.* + +Unless a constant is either a simple literal, e.g. `[u8; 3]` or `foo::<{ 'c' }>()`, +or a generic parameter, e.g. `[u8; N]`, converting a constant to its [`ty::Const`] representation +returns an unevaluated constant. Even fully concrete constants which do not depend on +generic parameters are not evaluated right away. + +We do not eagerly evaluate constant as they can be used in the `where`-clauses of their +parent item, for example: + +```rust +#[feature(generic_const_exprs)] +fn foo() +where + [u8; ::ASSOC + 1]: SomeOtherTrait, +{} +``` + +The constant `::ASSOC + 1` depends on the `T: Trait` bound of +its parents caller bounds, but is also part of another bound itself. +If we were to eagerly evaluate this constant while computing its parents bounds +this would cause a query cycle. + +### Generic arguments of anonymous constants + +Anonymous constants inherit the generic parameters of their parent, which is +why the array length in `foo() -> [u8; N + 1]` can use `N`. + +Without any manual adjustments, this causes us to include parameters even if +the constant doesn't use them in any way. This can cause +[some interesting errors](pcg-unused-substs) and breaks some already stable code. + +To deal with this, we intend to look at the generic parameters explicitly mentioned +by the constants and then search the predicates of its parents to figure out which +of the other generic parameters are reachable by our constant. + +**TODO**: Expand this section once the parameter filtering is implemented. + +As constants can be part of their parents `where`-clauses, we mention unevaluated +constants in their parents predicates. It is therefore necessary to mention unevaluated +constants before we have computed the generic parameters +available to these constants. + +To do this unevaluated constants start out with [`substs_`] being `None` while assuming +that their generic arguments could be arbitrary generic parameters. +When first accessing the generic arguments of an unevaluated constants, we then replace +`substs_` with the actual default arguments of a constants, which are the generic parameters +of their parent we assume to be used by this constant. + +[`ty::Const`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Const.html +[`ty::ConstKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.ConstKind.html +[`ty::TyKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[pcg-unused-substs]: https://github.com/rust-lang/project-const-generics/blob/master/design-docs/anon-const-substs.md#unused-substs +[`substs_`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/kind/struct.Unevaluated.html#structfield.substs_ \ No newline at end of file diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/contributing.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/contributing.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/contributing.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/contributing.md 2021-11-29 19:27:29.000000000 +0000 @@ -424,12 +424,12 @@ Try to format the date as ` ` to ease search. - Additionally, include a machine-readable comment of the form `` (if the current month is January 2021). We have an automated + 2021-10 -->` (if the current month is October 2021). We have an automated tool that uses these (in `ci/date-check`). So, for the month of January 2021, the comment would look like: `As of January 2021`. Make sure to put the comment *between* `as of` - and `January 2021`; see [PR #1066][rdg#1066] for the rationale. + date: 2021-10 --> October 2021`. Make sure to put the comment *between* `as of` + and `October 2021`; see [PR #1066][rdg#1066] for the rationale. - A link to a relevant WG, tracking issue, `rustc` rustdoc page, or similar, that may provide further explanation for the change process or a way to verify that the information is not diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md 2021-11-29 19:27:29.000000000 +0000 @@ -0,0 +1,146 @@ +# Diagnostic Items + +## Background + +While writing lints it's common to check for specific types, traits and functions. This raises +the question on how to check for these. Types can be checked by their complete type path. +However, this requires hard coding paths and can lead to misclassifications in some edge cases. +To counteract this, rustc has introduced diagnostic items that are used to identify types via +[`Symbol`]s. + +## How To Find Diagnostic Items + +Diagnostic items are added to items inside `rustc`/`std`/`core` with the `rustc_diagnostic_item` +attribute. The item for a specific type can be found by opening the source code in the +documentation and looking for this attribute. Note that it's often added with the `cfg_attr` +attribute to avoid compilation errors during tests. A definition often looks like this: + +```rs +// This is the diagnostic item for this type vvvvvvv +#[cfg_attr(not(test), rustc_diagnostic_item = "Penguin")] +struct Penguin; +``` + +Diagnostic items are usually only added to traits, types and standalone functions. If the goal +is to check for an associated type or method, please use the diagnostic item of the item and +reference [*Using Diagnostic Items*](#using-diagnostic-items). + +## How To Add Diagnostic Items + +A new diagnostic item can be added with these two steps: + +1. Find the target item inside the rust repo. Now add the diagnostic item as a string via the + `rustc_diagnostic_item` attribute. This can sometimes cause compilation errors while running + tests. These errors can be avoided by using the `cfg_attr` attribute with the `not(test)` + condition (it's fine adding then for all `rustc_diagnostic_item` attributes as a preventive + manner). At the end, it should look like this: + + ```rs + // This will be the new diagnostic item vvv + #[cfg_attr(not(test), rustc_diagnostic_item = "Cat")] + struct Cat; + ``` + + For the naming conventions of diagnostic items, please refer to + [*Naming Conventions*](#naming-conventions). + +2. As of August 2021 diagnostic items in code are accessed via symbols in + [`rustc_span::symbol::sym`]. To add your newly created diagnostic item simply open the + module file and add the name (In this case `Cat`) at the correct point in the list. + +Now you can create a pull request with your changes. :tada: (Note that when using diagnostic +items in other projects like Clippy, it might take some time until the repos get synchronized.) + +## Naming Conventions + +Diagnostic items don't have a set in stone naming convention yet. These are some guidelines that +should be used for the future, but might differ from existing names: + +* Types, traits and enums are named using UpperCamelCase (Examples: `Iterator`, `HashMap`, ...) +* For type names that are used multiple times like `Writer` it's good to choose a more precise + name, maybe by adding the module to it. (Example: `IoWriter`) +* Associated items should not get their own diagnostic items, but instead be accessed indirectly + by the diagnostic item of the type they're originating from. +* Freestanding functions like `std::mem::swap()` should be named using `snake_case` with one + important (export) module as a prefix (Example: `mem_swap`, `cmp_max`) +* Modules should usually not have a diagnostic item attached to them. Diagnostic items were + added to avoid the usage of paths, using them on modules would therefore most likely to be + counterproductive. + +## How To Use Diagnostic Items + +In rustc, diagnostic items are looked up via [`Symbol`]s from inside the +[`rustc_span::symbol::sym`] module. These can then be mapped to [`DefId`]s using +[`TyCtxt::get_diagnostic_item()`] or checked if they match a [`DefId`] using +[`TyCtxt::is_diagnostic_item()`]. When mapping from a diagnostic item to a [`DefId`] the method +will return a `Option`. This can be `None` if either the symbol isn't a diagnostic item +or the type is not registered, for instance when compiling with `#[no_std]`. All following +examples are based on [`DefId`]s and their usage. + +### Check For A Type + +```rust +use rustc_span::symbol::sym; + +/// This example checks if the given type (`ty`) has the type `HashMap` using +/// `TyCtxt::is_diagnostic_item()` +fn example_1(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::HashMap, adt.did), + _ => false, + } +} +``` + +### Check For A Trait Implementation + +```rust +/// This example checks if a given [`DefId`] from a method is part of a trait +/// implementation defined by a diagnostic item. +fn is_diag_trait_item( + cx: &LateContext<'_>, + def_id: DefId, + diag_item: Symbol +) -> bool { + if let Some(trait_did) = cx.tcx.trait_of_item(def_id) { + return cx.tcx.is_diagnostic_item(diag_item, trait_did); + } + false +} +``` + +### Associated Types + +Associated types of diagnostic items can be accessed indirectly by first getting the [`DefId`] +of the trait and then calling [`TyCtxt::associated_items()`]. This returns an [`AssocItems`] +object which can be used for further checks. Checkout +[`clippy_utils::ty::get_iterator_item_ty()`] for an example usage of this. + +### Usage In Clippy + +Clippy tries to use diagnostic items where possible and has developed some wrapper and utility +functions. Please also refer to its documentation when using diagnostic items in Clippy. (See +[*Common tools for writing lints*][clippy-Common-tools-for-writing-lints].) + +## Related Issues + +This lists some related issues. These are probably only interesting to people who really want to +take a deep dive into the topic :) + +* [rust#60966]: The Rust PR that introduced diagnostic items +* [rust-clippy#5393]: Clippy's tracking issue for moving away from hard coded paths to + diagnostic item + + + +[`rustc_span::symbol::sym`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/sym/index.html +[`Symbol`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html +[`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html +[`TyCtxt::get_diagnostic_item()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.get_diagnostic_item +[`TyCtxt::is_diagnostic_item()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.is_diagnostic_item +[`TyCtxt::associated_items()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.associated_items +[`AssocItems`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/assoc/struct.AssocItems.html +[`clippy_utils::ty::get_iterator_item_ty()`]: https://github.com/rust-lang/rust-clippy/blob/305177342fbc622c0b3cb148467bab4b9524c934/clippy_utils/src/ty.rs#L55-L72 +[clippy-Common-tools-for-writing-lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/common_tools_writing_lints.md +[rust#60966]: https://github.com/rust-lang/rust/pull/60966 +[rust-clippy#5393]: https://github.com/rust-lang/rust-clippy/issues/5393 diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/diagnostics.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/diagnostics.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/diagnostics.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/diagnostics.md 2021-11-29 19:27:29.000000000 +0000 @@ -222,9 +222,13 @@ The error or warning portion should *not* suggest how to fix the problem, only the "help" sub-diagnostic should. -- `note`: emitted to identify additional circumstances and parts of the code - that caused the warning or error. For example, the borrow checker will note - any previous conflicting borrows. +- `note`: emitted to given more context and identify additional circumstances + and parts of the code that caused the warning or error. For example, the + borrow checker will note any previous conflicting borrows. + + `help` vs `note`: `help` should be used to show changes the user can + possibly make to fix the problem. `note` should be used for everything else, + such as other context, information and facts, online resources to read, etc. Not to be confused with *lint levels*, whose guidelines are: diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/getting-started.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/getting-started.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/getting-started.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/getting-started.md 2021-11-29 19:27:29.000000000 +0000 @@ -293,13 +293,15 @@ commit, as this reduces conflicts later. The pinned version is built under `build//stage0/bin/rustfmt`, so if you want, you can use it for a single file or for format-on-save in your editor, which can be faster than `./x.py fmt`. +You'll have to pass the `--edition=2021` argument +yourself when calling `rustfmt` directly. One last thing: you can use `RUSTC_LOG=XXX` to get debug logging. [Read more here][logging]. Notice the `C` in `RUSTC_LOG`. Other than that, it uses normal -[`env_logger`][envlog] syntax. +[`env_logger`][envlog] or `tracing` syntax. [envlog]: https://crates.io/crates/env_logger -[logging]: ./compiler-debugging.html#getting-logging-output +[logging]: ./tracing.md ### Building and Testing `std`/`core`/`alloc`/`test`/`proc_macro`/etc. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/git.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/git.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/git.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/git.md 2021-11-29 19:27:29.000000000 +0000 @@ -269,9 +269,9 @@ ``` To avoid merges as per the [No-Merge Policy](#no-merge-policy), you may want to use -`git config pull.ff only` (this will apply the config to the local repo). -to avoid merge conflicts while pulling, without needing -`--ff-only` or `--rebase` while `git pull`ing +`git config pull.ff only` (this will apply the config only to the local repo) +to ensure that Git doesn't create merge commits when `git pull`ing, without +needing to pass `--ff-only` or `--rebase` every time. You can also `git push --force-with-lease` from master to keep your origin's master in sync with upstream. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md 2021-11-29 19:27:29.000000000 +0000 @@ -298,8 +298,8 @@ `run-make-fulldeps` can be refreshed by running: ```shell -$ ./x.py test mir-opt --blessed -$ ./x.py test src/test/run-make-fulldeps/coverage --blessed +$ ./x.py test mir-opt --bless +$ ./x.py test src/test/run-make-fulldeps/coverage --bless ``` [mir-opt-test]: https://github.com/rust-lang/rust/blob/master/src/test/mir-opt/instrument_coverage.rs diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/overview.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/overview.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/overview.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/overview.md 2021-11-29 19:27:29.000000000 +0000 @@ -43,16 +43,17 @@ - The lexer preserves full fidelity information for both IDEs and proc macros. - The parser [translates the token stream from the lexer into an Abstract Syntax Tree (AST)][parser]. It uses a recursive descent (top-down) approach to syntax - analysis. The crate entry points for the parser are the `Parser::parse_crate_mod()` and - `Parser::parse_mod()` methods found in `rustc_parse::parser::item`. The external - module parsing entry point is `rustc_expand::module::parse_external_mod`. And - the macro parser entry point is [`Parser::parse_nonterminal()`][parse_nonterminal]. + analysis. The crate entry points for the parser are the + [`Parser::parse_crate_mod()`][parse_crate_mod] and [`Parser::parse_mod()`][parse_mod] + methods found in [`rustc_parse::parser::Parser`]. The external module parsing + entry point is [`rustc_expand::module::parse_external_mod`][parse_external_mod]. + And the macro parser entry point is [`Parser::parse_nonterminal()`][parse_nonterminal]. - Parsing is performed with a set of `Parser` utility methods including `fn bump`, `fn check`, `fn eat`, `fn expect`, `fn look_ahead`. - Parsing is organized by the semantic construct that is being parsed. Separate - `parse_*` methods can be found in `rustc_parse` `parser` directory. The source - file name follows the construct name. For example, the following files are found - in the parser: + `parse_*` methods can be found in [`rustc_parse` `parser`][rustc_parse_parser_dir] + directory. The source file name follows the construct name. For example, the + following files are found in the parser: - `expr.rs` - `pat.rs` - `ty.rs` @@ -123,6 +124,11 @@ [`simplify_try`]: https://github.com/rust-lang/rust/pull/66282 [codegen]: https://rustc-dev-guide.rust-lang.org/backend/codegen.html [parse_nonterminal]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html#method.parse_nonterminal +[parse_crate_mod]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html#method.parse_crate_mod +[parse_mod]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html#method.parse_mod +[`rustc_parse::parser::Parser`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html +[parse_external_mod]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/module/fn.parse_external_mod.html +[rustc_parse_parser_dir]: https://github.com/rust-lang/rust/tree/master/compiler/rustc_parse/src/parser ## How it does it @@ -291,12 +297,7 @@ (and are always working on). One aspect of that is parallelizing `rustc` itself. -Currently, there is only one part of rustc that is already parallel: codegen. -During monomorphization, the compiler will split up all the code to be -generated into smaller chunks called _codegen units_. These are then generated -by independent instances of LLVM. Since they are independent, we can run them -in parallel. At the end, the linker is run to combine all the codegen units -together into one binary. +Currently, there is only one part of rustc that is parallel by default: codegen. However, the rest of the compiler is still not yet parallel. There have been lots of efforts spent on this, but it is generally a hard problem. The current diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/parallel-rustc.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/parallel-rustc.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/parallel-rustc.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/parallel-rustc.md 2021-11-29 19:27:29.000000000 +0000 @@ -1,16 +1,70 @@ # Parallel Compilation -Most of the compiler is not parallel. This represents an opportunity for -improving compiler performance. +As of September 2021, The only stage of the compiler +that is already parallel is codegen. The nightly compiler implements query evaluation, +but there is still a lot of work to be done. The lack of parallelism at other stages +also represents an opportunity for improving compiler performance. One can try out the current +parallel compiler work by enabling it in the `config.toml`. + +These next few sections describe where and how parallelism is currently used, +and the current status of making parallel compilation the default in `rustc`. + +The underlying thread-safe data-structures used in the parallel compiler +can be found in the `rustc_data_structures::sync` module. Some of these data structures +use the `parking_lot` crate as well. + +## Codegen + +There are two underlying thread safe data structures used in code generation: + +- `Lrc` + - Which is an [`Arc`][Arc] if `parallel_compiler` is true, and a [`Rc`][Rc] + if it is not. +- `MetadataRef` -> [`OwningRef, [u8]>`][OwningRef] + - This data structure is specific to `rustc`. + +During [monomorphization][monomorphization] the compiler splits up all the code to +be generated into smaller chunks called _codegen units_. These are then generated by +independent instances of LLVM running in parallel. At the end, the linker +is run to combine all the codegen units together into one binary. This process +occurs in the `rustc_codegen_ssa::base` module. + +## Query System + +The query model has some properties that make it actually feasible to evaluate +multiple queries in parallel without too much of an effort: + +- All data a query provider can access is accessed via the query context, so + the query context can take care of synchronizing access. +- Query results are required to be immutable so they can safely be used by + different threads concurrently. + +When a query `foo` is evaluated, the cache table for `foo` is locked. + +- If there already is a result, we can clone it, release the lock and + we are done. +- If there is no cache entry and no other active query invocation computing the + same result, we mark the key as being "in progress", release the lock and + start evaluating. +- If there *is* another query invocation for the same key in progress, we + release the lock, and just block the thread until the other invocation has + computed the result we are waiting for. This cannot deadlock because, as + mentioned before, query invocations form a DAG. Some thread will always make + progress. + +## Rustdoc + +As of September 2021, there are still a number of steps +to complete before rustdoc rendering can be made parallel. More details on +this issue can be found [here][parallel-rustdoc]. + +## Current Status As of July 2021, work on explicitly parallelizing the compiler has stalled. There is a lot of design and correctness work that needs -to be done. - -One can try out the current parallel compiler work by enabling it in the -`config.toml`. +to be done. -There are a few basic ideas in this effort: +These are the basic ideas in the effort to make `rustc` parallel: - There are a lot of loops in the compiler that just iterate over all items in a crate. These can possibly be parallelized. @@ -45,3 +99,8 @@ [imlist]: https://github.com/nikomatsakis/rustc-parallelization/blob/master/interior-mutability-list.md [irlo1]: https://internals.rust-lang.org/t/help-test-parallel-rustc/11503 [tracking]: https://github.com/rust-lang/rust/issues/48685 +[monomorphization]:https://rustc-dev-guide.rust-lang.org/backend/monomorph.html +[parallel-rustdoc]:https://github.com/rust-lang/rust/issues/82741 +[Arc]:https://doc.rust-lang.org/std/sync/struct.Arc.html +[Rc]:https://doc.rust-lang.org/std/rc/struct.Rc.html +[OwningRef]:https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/owning_ref/index.html diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md 2021-11-29 19:27:29.000000000 +0000 @@ -211,29 +211,3 @@ To summarize: "Steal queries" break some of the rules in a controlled way. There are checks in place that make sure that nothing can go silently wrong. - - -## Parallel Query Execution - -The query model has some properties that make it actually feasible to evaluate -multiple queries in parallel without too much of an effort: - -- All data a query provider can access is accessed via the query context, so - the query context can take care of synchronizing access. -- Query results are required to be immutable so they can safely be used by - different threads concurrently. - -The nightly compiler already implements parallel query evaluation as follows: - -When a query `foo` is evaluated, the cache table for `foo` is locked. - -- If there already is a result, we can clone it, release the lock and - we are done. -- If there is no cache entry and no other active query invocation computing the - same result, we mark the key as being "in progress", release the lock and - start evaluating. -- If there *is* another query invocation for the same key in progress, we - release the lock, and just block the thread until the other invocation has - computed the result we are waiting for. This cannot deadlock because, as - mentioned before, query invocations form a DAG. Some thread will always make - progress. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/rustdoc-internals.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/rustdoc-internals.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/rustdoc-internals.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/rustdoc-internals.md 2021-11-29 19:27:29.000000000 +0000 @@ -71,29 +71,25 @@ - `calculate-doc-coverage` calculates information used for the `--show-coverage` flag. +- `check-bare-urls` detects links that are not linkified, e.g., in Markdown such as + `Go to https://example.com/.` It suggests wrapping the link with angle brackets: + `Go to .` to linkify it. This is the code behind the + `rustdoc::bare_urls` lint. + - `check-code-block-syntax` validates syntax inside Rust code blocks (```rust) +- `check-doc-test-visibility` runs doctest visibility–related lints. + - `check-invalid-html-tags` detects invalid HTML (like an unclosed ``) in doc comments. -- `check-non-autolinks` detects links that could or should be written using - angle brackets (the code behind the nightly-only `non_autolinks` - lint). - -- `collapse-docs` concatenates all document attributes into one document - attribute. This is necessary because each line of a doc comment is given as a - separate doc attribute, and this will combine them into a single string with - line breaks between each attribute. - - `collect-intra-doc-links` resolves [intra-doc links](https://doc.rust-lang.org/rustdoc/linking-to-items-by-name.html). - `collect-trait-impls` collects trait impls for each item in the crate. For example, if we define a struct that implements a trait, this pass will note that the struct implements that trait. -- `doc-test-lints` runs various lints on the doctests. - - `propagate-doc-cfg` propagates `#[doc(cfg(...))]` to child items. - `strip-priv-imports` strips all private import statements (`use`, `extern diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/salsa.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/salsa.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/salsa.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/salsa.md 2021-11-29 19:27:29.000000000 +0000 @@ -44,7 +44,7 @@ "pure" function that computes the derived value. For example, there might be a function `ast(x: Path) -> AST`. The produced -`AST` isn't a final value, it's an intermidiate value that the library would +`AST` isn't a final value, it's an intermediate value that the library would use for the computation. This means that when you try to compute with the library, Salsa is going to @@ -126,7 +126,7 @@ ```rust,ignore /// This attribute will process this tree, produce this tree as output, and produce -/// a bunch of intermidiate stuff that Salsa also uses. One of these things is a +/// a bunch of intermediate stuff that Salsa also uses. One of these things is a /// "StorageStruct", whose name we have specified in the attribute. /// /// This query group is a bunch of **input** queries, that do not rely on any diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/sanitizers.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/sanitizers.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/sanitizers.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/sanitizers.md 2021-11-29 19:27:29.000000000 +0000 @@ -5,6 +5,8 @@ * [AddressSanitizer][clang-asan] a faster memory error detector. Can detect out-of-bounds access to heap, stack, and globals, use after free, use after return, double free, invalid free, memory leaks. +* [Hardware-assisted AddressSanitizer][clang-hwasan] a tool similar to + AddressSanitizer but based on partial hardware assistance. * [LeakSanitizer][clang-lsan] a run-time memory leak detector. * [MemorySanitizer][clang-msan] a detector of uninitialized reads. * [ThreadSanitizer][clang-tsan] a fast data race detector. @@ -12,8 +14,9 @@ ## How to use the sanitizers? To enable a sanitizer compile with `-Z sanitizer=...` option, where value is one -of `address`, `leak`, `memory` or `thread`. For more details how to use -sanitizers please refer to [the unstable book](https://doc.rust-lang.org/unstable-book/). +of `address`, `hwaddress`, `leak`, `memory` or `thread`. For more details on how +to use sanitizers please refer to the sanitizer flag in [the unstable +book](https://doc.rust-lang.org/unstable-book/). ## How are sanitizers implemented in rustc? @@ -22,7 +25,8 @@ libraries. Highlight of the most important aspects of the implementation: * The sanitizer runtime libraries are part of the [compiler-rt] project, and - [will be built on supported targets][sanitizer-build] when enabled in `config.toml`: + [will be built][sanitizer-build] on [supported targets][sanitizer-targets] + when enabled in `config.toml`: ```toml [build] @@ -33,9 +37,9 @@ * During LLVM code generation, the functions intended for instrumentation are [marked][sanitizer-attribute] with appropriate LLVM attribute: - `SanitizeAddress`, `SanitizeMemory`, or `SanitizeThread`. By default all - functions are instrumented, but this behaviour can be changed with - `#[no_sanitize(...)]`. + `SanitizeAddress`, `SanitizeHWAddress`, `SanitizeMemory`, or + `SanitizeThread`. By default all functions are instrumented, but this + behaviour can be changed with `#[no_sanitize(...)]`. * The decision whether to perform instrumentation or not is possible only at a function granularity. In the cases were those decision differ between @@ -47,28 +51,66 @@ passes are invoked after optimization passes. * When producing an executable, the sanitizer specific runtime library is - [linked in][sanitizer-link]. The libraries are searched for in target libdir - relative to default system root, so that this process is not affected - by sysroot overrides used for example by cargo `-Z build-std` functionality. + [linked in][sanitizer-link]. The libraries are searched for in the target + libdir. First relative to the overridden system root and subsequently + relative to the default system root. Fall-back to the default system root + ensures that sanitizer runtimes remain available when using sysroot overrides + constructed by cargo `-Z build-std` or xargo. [compiler-rt]: https://github.com/llvm/llvm-project/tree/main/compiler-rt -[sanitizer-build]: https://github.com/rust-lang/rust/blob/a29424a2265411dda7d7446516ac5fd7499e2b55/src/bootstrap/native.rs#L566-L624 -[sanitizer-copy]: https://github.com/rust-lang/rust/blob/a29424a2265411dda7d7446516ac5fd7499e2b55/src/bootstrap/compile.rs#L270-L304 -[sanitizer-attribute]: https://github.com/rust-lang/rust/blob/a29424a2265411dda7d7446516ac5fd7499e2b55/src/librustc_codegen_llvm/attributes.rs#L49-L72 -[inline-mir]: https://github.com/rust-lang/rust/blob/a29424a2265411dda7d7446516ac5fd7499e2b55/src/librustc_mir/transform/inline.rs#L232-L252 +[sanitizer-build]: https://github.com/rust-lang/rust/blob/1.55.0/src/bootstrap/native.rs#L700-L765 +[sanitizer-targets]: https://github.com/rust-lang/rust/blob/1.55.0/src/bootstrap/native.rs#L806-L820 +[sanitizer-copy]: https://github.com/rust-lang/rust/blob/1.55.0/src/bootstrap/compile.rs#L376-L407 +[sanitizer-attribute]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_llvm/src/attributes.rs#L42-L58 +[inline-mir]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_mir/src/transform/inline.rs#L314-L316 [inline-llvm]: https://github.com/rust-lang/llvm-project/blob/9330ec5a4c1df5fc1fa62f993ed6a04da68cb040/llvm/include/llvm/IR/Attributes.td#L225-L241 -[sanitizer-pass]: https://github.com/rust-lang/rust/blob/a29424a2265411dda7d7446516ac5fd7499e2b55/src/librustc_codegen_llvm/back/write.rs#L454-L475 -[sanitizer-link]: https://github.com/rust-lang/rust/blob/a29424a2265411dda7d7446516ac5fd7499e2b55/src/librustc_codegen_ssa/back/link.rs#L748-L787 +[sanitizer-pass]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_llvm/src/back/write.rs#L660-L678 +[sanitizer-link]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_codegen_ssa/src/back/link.rs#L1053-L1089 + +## Testing sanitizers + +Sanitizers are validated by code generation tests in +[`src/test/codegen/sanitize*.rs`][test-cg] and end-to-end functional tests in +[`src/test/ui/sanitize/`][test-ui] directory. + +Testing sanitizer functionality requires the sanitizer runtimes (built when +`sanitizer = true` in `config.toml`) and target providing support for particular +sanitizer. When sanitizer is unsupported on given target, sanitizers tests will +be ignored. This behaviour is controlled by compiletest `needs-sanitizer-*` +directives. + +[test-cg]: https://github.com/rust-lang/rust/tree/master/src/test/codegen +[test-ui]: https://github.com/rust-lang/rust/tree/master/src/test/ui/sanitize + +## Enabling sanitizer on a new target + +To enable a sanitizer on a new target which is already supported by LLVM: + +1. Include the sanitizer in the list of `supported_sanitizers` in [the target + definition][target-definition]. `rustc --target .. -Zsanitizer=..` should now + recognize sanitizer as supported. +2. [Build the runtime for the target and include it in the libdir.][sanitizer-targets] +3. [Teach compiletest that your target now supports the sanitizer.][compiletest-definition] + Tests marked with `needs-sanitizer-*` should now run on the target. +4. Run tests `./x.py test --force-rerun src/test/ui/sanitize/` to verify. +5. [--enable-sanitizers in the CI configuration][ci-configuration] to build and + distribute the sanitizer runtime as part of the release process. + +[target-definition]: https://github.com/rust-lang/rust/blob/1.55.0/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs#L10-L11 +[compiletest-definition]: https://github.com/rust-lang/rust/blob/1.55.0/src/tools/compiletest/src/util.rs#L87-L116 +[ci-configuration]: https://github.com/rust-lang/rust/blob/1.55.0/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile#L94 ## Additional Information * [Sanitizers project page](https://github.com/google/sanitizers/wiki/) * [AddressSanitizer in Clang][clang-asan] +* [Hardware-assisted AddressSanitizer][clang-hwasan] * [LeakSanitizer in Clang][clang-lsan] * [MemorySanitizer in Clang][clang-msan] * [ThreadSanitizer in Clang][clang-tsan] [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html +[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/SUMMARY.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/SUMMARY.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/SUMMARY.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/SUMMARY.md 2021-11-29 19:27:29.000000000 +0000 @@ -14,13 +14,13 @@ - [Distribution artifacts](./building/build-install-distribution-artifacts.md) - [Documenting Compiler](./building/compiler-documenting.md) - [Rustdoc overview](./rustdoc.md) - - [ctags](./building/ctags.md) - [Adding a new target](./building/new-target.md) - [The compiler testing framework](./tests/intro.md) - [Running tests](./tests/running.md) - [Adding new tests](./tests/adding.md) - [Using `compiletest` commands to control test execution](./compiletest.md) - [Debugging the Compiler](./compiler-debugging.md) + - [Using the tracing/logging instrumentation](./tracing.md) - [Profiling the compiler](./profiling.md) - [with the linux perf tool](./profiling/with_perf.md) - [with Windows Performance Analyzer](./profiling/wpa_profiling.md) @@ -99,6 +99,7 @@ - [Generics and substitutions](./generics.md) - [`TypeFolder` and `TypeFoldable`](./ty-fold.md) - [Generic arguments](./generic_arguments.md) + - [Constants in the type system](./constants.md) - [Type inference](./type-inference.md) - [Trait solving](./traits/resolution.md) - [Early and Late Bound Parameters](./early-late-bound.md) @@ -132,6 +133,7 @@ - [Creating Errors With SessionDiagnostic](./diagnostics/sessiondiagnostic.md) - [`LintStore`](./diagnostics/lintstore.md) - [Diagnostic Codes](./diagnostics/diagnostic-codes.md) + - [Diagnostic Items](./diagnostics/diagnostic-items.md) # MIR to Binaries diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/tests/adding.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/tests/adding.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/tests/adding.md 2021-10-18 09:52:56.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/tests/adding.md 2021-11-29 19:27:29.000000000 +0000 @@ -208,9 +208,10 @@ `profiler = true` in rustc's `config.toml`. * `needs-sanitizer-support` - a sanitizer runtime is required, i.e., `sanitizers = true` in rustc's `config.toml`. -* `needs-sanitizer-{address,leak,memory,thread}` - indicates that test - requires a target with a support for AddressSanitizer, LeakSanitizer, - MemorySanitizer or ThreadSanitizer respectively. +* `needs-sanitizer-{address,hwaddress,leak,memory,thread}` - indicates that + test requires a target with a support for AddressSanitizer, hardware-assisted + AddressSanitizer, LeakSanitizer, MemorySanitizer or ThreadSanitizer + respectively. * `error-pattern` checks the diagnostics just like the `ERROR` annotation without specifying error line. This is useful when the error doesn't give any span. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/tracing.md rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/tracing.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/tracing.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustc-dev-guide/src/tracing.md 2021-11-29 19:27:29.000000000 +0000 @@ -0,0 +1,204 @@ +# Using tracing to debug the compiler + + + +The compiler has a lot of [`debug!`] (or `trace!`) calls, which print out logging information +at many points. These are very useful to at least narrow down the location of +a bug if not to find it entirely, or just to orient yourself as to why the +compiler is doing a particular thing. + +[`debug!`]: https://docs.rs/tracing/0.1/tracing/macro.debug.html + +To see the logs, you need to set the `RUSTC_LOG` environment variable to your +log filter. The full syntax of the log filters can be found in the [rustdoc +of `tracing-subscriber`](https://docs.rs/tracing-subscriber/0.2.24/tracing_subscriber/filter/struct.EnvFilter.html#directives). + +## Function level filters + +Lots of functions in rustc are annotated with + +``` +#[instrument(level = "debug", skip(self))] +fn foo(&self, bar: Type) {} +``` + +which allows you to use + +``` +RUSTC_LOG=[foo] +``` + +to do the following all at once + +* log all function calls to `foo` +* log the arguments (except for those in the `skip` list) +* log everything (from anywhere else in the compiler) until the function returns + +### I don't want everything + +Depending on the scope of the function, you may not want to log everything in its body. +As an example: the `do_mir_borrowck` function will dump hundreds of lines even for trivial +code being borrowchecked. + +Since you can combine all filters, you can add a crate/module path, e.g. + +``` +RUSTC_LOG=rustc_borrowck[do_mir_borrowck] +``` + +### I don't want all calls + +If you are compiling libcore, you likely don't want *all* borrowck dumps, but only one +for a specific function. You can filter function calls by their arguments by regexing them. + +``` +RUSTC_LOG=[do_mir_borrowck{id=\.\*from_utf8_unchecked\.\*}] +``` + +will only give you the logs of borrowchecking `from_utf8_unchecked`. Note that you will +still get a short message per ignored `do_mir_borrowck`, but none of the things inside those +calls. This helps you in looking through the calls that are happening and helps you adjust +your regex if you mistyped it. + +## Broad module level filters + +You can also use filters similar to the `log` crate's filters, which will enable +everything within a specific module. This is often too verbose and too unstructured, +so it is recommended to use function level filters. + +Your log filter can be just `debug` to get all `debug!` output and +higher (e.g., it will also include `info!`), or `path::to::module` to get *all* +output (which will include `trace!`) from a particular module, or +`path::to::module=debug` to get `debug!` output and higher from a particular +module. + +For example, to get the `debug!` output and higher for a specific module, you +can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`. +All `debug!` output will then appear in standard error. + +Note that you can use a partial path and the filter will still work. For +example, if you want to see `info!` output from only +`rustdoc::passes::collect_intra_doc_links`, you could use +`RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use +`RUSTDOC_LOG=rustdoc::passes::collect_intra=info`. + +If you are developing rustdoc, use `RUSTDOC_LOG` instead. If you are developing +Miri, use `MIRI_LOG` instead. You get the idea :) + +See the [`tracing`] crate's docs, and specifically the docs for [`debug!`] to +see the full syntax you can use. (Note: unlike the compiler, the [`tracing`] +crate and its examples use the `RUST_LOG` environment variable. rustc, rustdoc, +and other tools set custom environment variables.) + +**Note that unless you use a very strict filter, the logger will emit a lot of +output, so use the most specific module(s) you can (comma-separated if +multiple)**. It's typically a good idea to pipe standard error to a file and +look at the log output with a text editor. + +So, to put it together: + +```bash +# This puts the output of all debug calls in `rustc_middle/src/traits` into +# standard error, which might fill your console backscroll. +$ RUSTC_LOG=rustc_middle::traits=debug rustc +stage1 my-file.rs + +# This puts the output of all debug calls in `rustc_middle/src/traits` in +# `traits-log`, so you can then see it with a text editor. +$ RUSTC_LOG=rustc_middle::traits=debug rustc +stage1 my-file.rs 2>traits-log + +# Not recommended! This will show the output of all `debug!` calls +# in the Rust compiler, and there are a *lot* of them, so it will be +# hard to find anything. +$ RUSTC_LOG=debug rustc +stage1 my-file.rs 2>all-log + +# This will show the output of all `info!` calls in `rustc_codegen_ssa`. +# +# There's an `info!` statement in `codegen_instance` that outputs +# every function that is codegen'd. This is useful to find out +# which function triggers an LLVM assertion, and this is an `info!` +# log rather than a `debug!` log so it will work on the official +# compilers. +$ RUSTC_LOG=rustc_codegen_ssa=info rustc +stage1 my-file.rs + +# This will show the output of all `info!` calls made by rustdoc +# or any rustc library it calls. +$ RUSTDOC_LOG=info rustdoc +stage1 my-file.rs + +# This will only show `debug!` calls made by rustdoc directly, +# not any `rustc*` crate. +$ RUSTDOC_LOG=rustdoc=debug rustdoc +stage1 my-file.rs +``` + +## Log colors + +By default, rustc (and other tools, like rustdoc and Miri) will be smart about +when to use ANSI colors in the log output. If they are outputting to a terminal, +they will use colors, and if they are outputting to a file or being piped +somewhere else, they will not. However, it's hard to read log output in your +terminal unless you have a very strict filter, so you may want to pipe the +output to a pager like `less`. But then there won't be any colors, which makes +it hard to pick out what you're looking for! + +You can override whether to have colors in log output with the `RUSTC_LOG_COLOR` +environment variable (or `RUSTDOC_LOG_COLOR` for rustdoc, or `MIRI_LOG_COLOR` +for Miri, etc.). There are three options: `auto` (the default), `always`, and +`never`. So, if you want to enable colors when piping to `less`, use something +similar to this command: + +```bash +# The `-R` switch tells less to print ANSI colors without escaping them. +$ RUSTC_LOG=debug RUSTC_LOG_COLOR=always rustc +stage1 ... | less -R +``` + +Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, not logs +from rustc functions that Miri calls. Use `RUSTC_LOG_COLOR` to color logs from +rustc. + +## How to keep or remove `debug!` and `trace!` calls from the resulting binary + +While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, +calls to `debug!` and `trace!` are only included in the program if +`debug-logging=true` is turned on in config.toml (it is +turned off by default), so if you don't see `DEBUG` logs, especially +if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see +`INFO` logs, make sure that `debug-logging=true` is turned on in your +config.toml. + +## Logging etiquette and conventions + +Because calls to `debug!` are removed by default, in most cases, don't worry +about the performance of adding "unnecessary" calls to `debug!` and leaving them in code you +commit - they won't slow down the performance of what we ship. + +That said, there can also be excessive tracing calls, especially +when they are redundant with other calls nearby or in functions called from +here. There is no perfect balance to hit here, and is left to the reviewer's +discretion to decide whether to let you leave `debug!` statements in or whether to ask +you to remove them before merging. + +It may be preferrable to use `trace!` over `debug!` for very noisy logs. + +A loosely followed convention is to use `#[instrument(level = "debug")]` +([also see the attribute's documentation](https://docs.rs/tracing-attributes/0.1.17/tracing_attributes/attr.instrument.html)) +in favour of `debug!("foo(...)")` at the start of a function `foo`. +Within functions, prefer `debug!(?variable.field)` over `debug!("xyz = {:?}", variable.field)` +and `debug!(bar = ?var.method(arg))` over `debug!("bar = {:?}", var.method(arg))`. +The documentation for this syntax can be found [here](https://docs.rs/tracing/0.1.28/tracing/#recording-fields). + +One thing to be **careful** of is **expensive** operations in logs. + +If in the module `rustc::foo` you have a statement + +```Rust +debug!(x = ?random_operation(tcx)); +``` + +Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::foo`, then +`random_operation()` will run. `RUSTC_LOG` filters that do not enable this +debug statement will not execute `random_operation`. + +This means that you should not put anything too expensive or likely to crash +there - that would annoy anyone who wants to use logging for that module. +No-one will know it until someone tries to use logging to find *another* bug. + +[`tracing`]: https://docs.rs/tracing \ No newline at end of file diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustdoc/src/lints.md rustc-1.57.0+dfsg1+llvm/src/doc/rustdoc/src/lints.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustdoc/src/lints.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustdoc/src/lints.md 2021-11-29 19:27:11.000000000 +0000 @@ -70,6 +70,8 @@ For example: ```rust +#![warn(rustdoc::private_intra_doc_links)] // note: unnecessary - warns by default. + /// [private] pub fn public() {} fn private() {} @@ -227,6 +229,8 @@ documentation examples that have potentially mis-typed values. For example: ```rust +#![warn(rustdoc::invalid_codeblock_attributes)] // note: unnecessary - warns by default. + /// Example. /// /// ```should-panic @@ -344,6 +348,8 @@ For example: ```rust +#![warn(rustdoc::bare_urls)] // note: unnecessary - warns by default. + /// http://example.org /// [http://example.net] pub fn foo() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/rustdoc/src/unstable-features.md rustc-1.57.0+dfsg1+llvm/src/doc/rustdoc/src/unstable-features.md --- rustc-1.56.0+dfsg1+llvm/src/doc/rustdoc/src/unstable-features.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/rustdoc/src/unstable-features.md 2021-11-29 19:27:11.000000000 +0000 @@ -209,6 +209,22 @@ `rustdoc` will disable this sorting and instead make it print the items in the order they appear in the source. +### `--show-type-layout`: add a section to each type's docs describing its memory layout + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --show-type-layout +``` + +When this flag is passed, rustdoc will add a "Layout" section at the bottom of +each type's docs page that includes a summary of the type's memory layout as +computed by rustc. For example, rustdoc will show the size in bytes that a value +of that type will take in memory. + +Note that most layout information is **completely unstable** and may even differ +between compilations. + ### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs Using this flag looks like this: @@ -222,13 +238,13 @@ specially cache them. This flag will rename all these files in the output to include the suffix in the filename. For example, `light.css` would become `light-suf.css` with the above command. -### `--display-warnings`: display warnings when documenting or running documentation tests +### `--display-doctest-warnings`: display warnings when documenting or running documentation tests Using this flag looks like this: ```bash -$ rustdoc src/lib.rs -Z unstable-options --display-warnings -$ rustdoc --test src/lib.rs -Z unstable-options --display-warnings +$ rustdoc src/lib.rs -Z unstable-options --display-doctest-warnings +$ rustdoc --test src/lib.rs -Z unstable-options --display-doctest-warnings ``` The intent behind this flag is to allow the user to see warnings that occur within their library or @@ -333,7 +349,7 @@ Public items that are not documented can be seen with the built-in `missing_docs` lint. Private items that are not documented can be seen with Clippy's `missing_docs_in_private_items` lint. -## `-w`/`--output-format`: output format +### `-w`/`--output-format`: output format When using [`--show-coverage`](https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#--show-coverage-get-statistics-about-code-documentation-coverage), diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/debug_info_for_profiling.md rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/debug_info_for_profiling.md --- rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/debug_info_for_profiling.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/debug_info_for_profiling.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,35 @@ +# `debug-info-for-profiling + +--- + +## Introduction + +Automatic Feedback Directed Optimization (AFDO) is a method for using sampling +based profiles to guide optimizations. This is contrasted with other methods of +FDO or profile-guided optimization (PGO) which use instrumented profiling. + +Unlike PGO (controlled by the `rustc` flags `-Cprofile-generate` and +`-Cprofile-use`), a binary being profiled does not perform significantly worse, +and thus it's possible to profile binaries used in real workflows and not +necessary to construct artificial workflows. + +## Use + +In order to use AFDO, the target platform must be Linux running on an `x86_64` +architecture with the performance profiler `perf` available. In addition, the +external tool `create_llvm_prof` from [this repository] must be used. + +Given a Rust file `main.rs`, we can produce an optimized binary as follows: + +```shell +rustc -O -Zdebug-info-for-profiling main.rs -o main +perf record -b ./main +create_llvm_prof --binary=main --out=code.prof +rustc -O -Zprofile-sample-use=code.prof main.rs -o main2 +``` + +The `perf` command produces a profile `perf.data`, which is then used by the +`create_llvm_prof` command to create `code.prof`. This final profile is then +used by `rustc` to guide optimizations in producing the binary `main2`. + +[this repository]: https://github.com/google/autofdo diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/profile_sample_use.md rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/profile_sample_use.md --- rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/profile_sample_use.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/profile_sample_use.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +# `profile-sample-use + +--- + +`-Zprofile-sample-use=code.prof` directs `rustc` to use the profile +`code.prof` as a source for Automatic Feedback Directed Optimization (AFDO). +See the documentation of [`-Zdebug-info-for-profiling`] for more information +on using AFDO. + +[`-Zdebug-info-for-profiling`]: debug_info_for_profiling.html diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md --- rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ +# `remap-cwd-prefix` + +The tracking issue for this feature is: [#87325](https://github.com/rust-lang/rust/issues/87325). + +------------------------ + +This flag will rewrite absolute paths under the current working directory, +replacing the current working directory prefix with a specified value. + +The given value may be absolute or relative, or empty. This switch takes +precidence over `--remap-path-prefix` in case they would both match a given +path. + +This flag helps to produce deterministic output, by removing the current working +directory from build output, while allowing the command line to be universally +reproducible, such that the same execution will work on all machines, regardless +of build environment. + +## Example +```sh +# This would produce an absolute path to main.rs in build outputs of +# "./main.rs". +rustc -Z remap-cwd-prefix=. main.rs +``` diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/language-features/closure-track-caller.md rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/language-features/closure-track-caller.md --- rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/language-features/closure-track-caller.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/language-features/closure-track-caller.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +# `closure_track_caller` + +The tracking issue for this feature is: [#87417] + +[#87417]: https://github.com/rust-lang/rust/issues/87417 + +------------------------ + +Allows using the `#[track_caller]` attribute on closures and generators. +Calls made to the closure or generator will have caller information +available through `std::panic::Location::caller()`, just like using +`#[track_caller]` on a function. diff -Nru rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/library-features/asm.md rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/library-features/asm.md --- rustc-1.56.0+dfsg1+llvm/src/doc/unstable-book/src/library-features/asm.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/doc/unstable-book/src/library-features/asm.md 2021-11-29 19:27:11.000000000 +0000 @@ -375,7 +375,7 @@ As a consequence, you should only use GNU assembler **numeric** [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions. -Moreover, on x86 when using the default intel syntax, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `option(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block. +Moreover, on x86 when using the default intel syntax, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `options(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block. ```rust,allow_fail #![feature(asm)] @@ -456,7 +456,7 @@ clobber_abi := "clobber_abi(" ")" option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" options := "options(" option *["," option] [","] ")" -asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi] ["," options] [","] ")" +asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi] *("," options) [","] ")" ``` Inline assembly is currently supported on the following architectures: @@ -613,8 +613,8 @@ | x86 | `xmm_reg` | `sse` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | | x86 | `ymm_reg` | `avx` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` | | x86 | `zmm_reg` | `avx512f` | `i32`, `f32`, `i64`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4`
`i8x64`, `i16x32`, `i32x16`, `i64x8`, `f32x16`, `f64x8` | -| x86 | `kreg` | `axv512f` | `i8`, `i16` | -| x86 | `kreg` | `axv512bw` | `i32`, `i64` | +| x86 | `kreg` | `avx512f` | `i8`, `i16` | +| x86 | `kreg` | `avx512bw` | `i32`, `i64` | | x86 | `mmx_reg` | N/A | Only clobbers | | x86 | `x87_reg` | N/A | Only clobbers | | AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | @@ -804,9 +804,9 @@ | Architecture | ABI name | Clobbered registers | | ------------ | -------- | ------------------- | -| x86-32 | `"C"`, `"system"`, `"efiapi"`, `"cdecl"`, `"stdcall"`, `"fastcall"` | `ax`, `cx`, `dx`, `xmm[0-7]`, `mm[0-7]`, `st([0-7])` | -| x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `st([0-7])` | -| x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `st([0-7])` | +| x86-32 | `"C"`, `"system"`, `"efiapi"`, `"cdecl"`, `"stdcall"`, `"fastcall"` | `ax`, `cx`, `dx`, `xmm[0-7]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` | +| x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` | +| x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` | | AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x30`, `v[0-31]`, `p[0-15]`, `ffr` | | ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` | | RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` | diff -Nru rustc-1.56.0+dfsg1+llvm/src/etc/check_missing_items.py rustc-1.57.0+dfsg1+llvm/src/etc/check_missing_items.py --- rustc-1.56.0+dfsg1+llvm/src/etc/check_missing_items.py 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/etc/check_missing_items.py 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ import sys import json -crate = json.load(open(sys.argv[1])) +crate = json.load(open(sys.argv[1], encoding="utf-8")) def get_local_item(item_id): diff -Nru rustc-1.56.0+dfsg1+llvm/src/etc/test-float-parse/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/etc/test-float-parse/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/etc/test-float-parse/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/etc/test-float-parse/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "test-float-parse" version = "0.1.0" -edition = "2018" +edition = "2021" publish = false [workspace] diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/librustdoc/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustdoc" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] path = "lib.rs" diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/auto_trait.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/auto_trait.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/auto_trait.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/auto_trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -114,17 +114,17 @@ attrs: Default::default(), visibility: Inherited, def_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id }, - kind: Box::new(ImplItem(Impl { + kind: box ImplItem(Impl { span: Span::dummy(), unsafety: hir::Unsafety::Normal, generics: new_generics, - trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), + trait_: Some(trait_ref.clean(self.cx)), for_: ty.clean(self.cx), items: Vec::new(), negative_polarity, synthetic: true, blanket_impl: None, - })), + }), cfg: None, }) } @@ -166,16 +166,16 @@ .clone() } - // This method calculates two things: Lifetime constraints of the form 'a: 'b, - // and region constraints of the form ReVar: 'a - // - // This is essentially a simplified version of lexical_region_resolve. However, - // handle_lifetimes determines what *needs be* true in order for an impl to hold. - // lexical_region_resolve, along with much of the rest of the compiler, is concerned - // with determining if a given set up constraints/predicates *are* met, given some - // starting conditions (e.g., user-provided code). For this reason, it's easier - // to perform the calculations we need on our own, rather than trying to make - // existing inference/solver code do what we want. + /// This method calculates two things: Lifetime constraints of the form `'a: 'b`, + /// and region constraints of the form `RegionVid: 'a` + /// + /// This is essentially a simplified version of lexical_region_resolve. However, + /// handle_lifetimes determines what *needs be* true in order for an impl to hold. + /// lexical_region_resolve, along with much of the rest of the compiler, is concerned + /// with determining if a given set up constraints/predicates *are* met, given some + /// starting conditions (e.g., user-provided code). For this reason, it's easier + /// to perform the calculations we need on our own, rather than trying to make + /// existing inference/solver code do what we want. fn handle_lifetimes<'cx>( regions: &RegionConstraintData<'cx>, names_map: &FxHashMap, @@ -331,9 +331,10 @@ match br { // We only care about named late bound regions, as we need to add them // to the 'for<>' section - ty::BrNamed(_, name) => { - Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime }) - } + ty::BrNamed(_, name) => Some(GenericParamDef { + name, + kind: GenericParamDefKind::Lifetime { outlives: vec![] }, + }), _ => None, } }) @@ -352,52 +353,35 @@ if let Some(data) = ty_to_fn.get(&ty) { let (poly_trait, output) = (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new)); - let new_ty = match poly_trait.trait_ { - Type::ResolvedPath { ref path, ref did, ref is_generic } => { - let mut new_path = path.clone(); - let last_segment = - new_path.segments.pop().expect("segments were empty"); - - let (old_input, old_output) = match last_segment.args { - GenericArgs::AngleBracketed { args, .. } => { - let types = args - .iter() - .filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty.clone()), - _ => None, - }) - .collect(); - (types, None) - } - GenericArgs::Parenthesized { inputs, output, .. } => { - (inputs, output) - } - }; + let mut new_path = poly_trait.trait_.clone(); + let last_segment = new_path.segments.pop().expect("segments were empty"); - if old_output.is_some() && old_output != output { - panic!( - "Output mismatch for {:?} {:?} {:?}", - ty, old_output, data.1 - ); - } + let (old_input, old_output) = match last_segment.args { + GenericArgs::AngleBracketed { args, .. } => { + let types = args + .iter() + .filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty.clone()), + _ => None, + }) + .collect(); + (types, None) + } + GenericArgs::Parenthesized { inputs, output } => (inputs, output), + }; - let new_params = - GenericArgs::Parenthesized { inputs: old_input, output }; + if old_output.is_some() && old_output != output { + panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, data.1); + } - new_path - .segments - .push(PathSegment { name: last_segment.name, args: new_params }); + let new_params = GenericArgs::Parenthesized { inputs: old_input, output }; + + new_path + .segments + .push(PathSegment { name: last_segment.name, args: new_params }); - Type::ResolvedPath { - path: new_path, - did: *did, - is_generic: *is_generic, - } - } - _ => panic!("Unexpected data: {:?}, {:?}", ty, data), - }; bounds.insert(GenericBound::TraitBound( - PolyTrait { trait_: new_ty, generic_params: poly_trait.generic_params }, + PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params }, hir::TraitBoundModifier::None, )); } @@ -426,15 +410,15 @@ .collect() } - // Converts the calculated ParamEnv and lifetime information to a clean::Generics, suitable for - // display on the docs page. Cleaning the Predicates produces sub-optimal `WherePredicate`s, - // so we fix them up: - // - // * Multiple bounds for the same type are coalesced into one: e.g., 'T: Copy', 'T: Debug' - // becomes 'T: Copy + Debug' - // * Fn bounds are handled specially - instead of leaving it as 'T: Fn(), = - // K', we use the dedicated syntax 'T: Fn() -> K' - // * We explicitly add a '?Sized' bound if we didn't find any 'Sized' predicates for a type + /// Converts the calculated `ParamEnv` and lifetime information to a [`clean::Generics`](Generics), suitable for + /// display on the docs page. Cleaning the `Predicates` produces sub-optimal [`WherePredicate`]s, + /// so we fix them up: + /// + /// * Multiple bounds for the same type are coalesced into one: e.g., `T: Copy`, `T: Debug` + /// becomes `T: Copy + Debug` + /// * `Fn` bounds are handled specially - instead of leaving it as `T: Fn(), = + /// K`, we use the dedicated syntax `T: Fn() -> K` + /// * We explicitly add a `?Sized` bound if we didn't find any `Sized` predicates for a type fn param_env_to_generics( &mut self, item_def_id: DefId, @@ -479,7 +463,7 @@ let mut has_sized = FxHashSet::default(); let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); - let mut ty_to_traits: FxHashMap> = Default::default(); + let mut ty_to_traits: FxHashMap> = Default::default(); let mut ty_to_fn: FxHashMap, Option)> = Default::default(); @@ -514,11 +498,11 @@ if b.is_sized_bound(self.cx) { has_sized.insert(ty.clone()); } else if !b - .get_trait_type() - .and_then(|t| { + .get_trait_path() + .and_then(|trait_| { ty_to_traits .get(&ty) - .map(|bounds| bounds.contains(&strip_type(t.clone()))) + .map(|bounds| bounds.contains(&strip_path_generics(trait_.clone()))) }) .unwrap_or(false) { @@ -535,7 +519,7 @@ // that we don't end up with duplicate bounds (e.g., for<'b, 'b>) for_generics.extend(p.generic_params.clone()); p.generic_params = for_generics.into_iter().collect(); - self.is_fn_ty(&p.trait_) + self.is_fn_trait(&p.trait_) } _ => false, }; @@ -561,83 +545,59 @@ match lhs { Type::QPath { name: left_name, ref self_type, ref trait_, .. } => { let ty = &*self_type; - match **trait_ { - Type::ResolvedPath { - path: ref trait_path, - ref did, - ref is_generic, - } => { - let mut new_trait_path = trait_path.clone(); - - if self.is_fn_ty(trait_) && left_name == sym::Output { - ty_to_fn - .entry(*ty.clone()) - .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) - .or_insert((None, Some(rhs))); - continue; - } - - let args = &mut new_trait_path - .segments - .last_mut() - .expect("segments were empty") - .args; - - match args { - // Convert something like ' = u8' - // to 'T: Iterator' - GenericArgs::AngleBracketed { - ref mut bindings, .. - } => { - bindings.push(TypeBinding { - name: left_name, - kind: TypeBindingKind::Equality { ty: rhs }, - }); - } - GenericArgs::Parenthesized { .. } => { - existing_predicates.push(WherePredicate::EqPredicate { - lhs: lhs.clone(), - rhs, - }); - continue; // If something other than a Fn ends up - // with parenthesis, leave it alone - } - } - - let bounds = ty_to_bounds.entry(*ty.clone()).or_default(); - - bounds.insert(GenericBound::TraitBound( - PolyTrait { - trait_: Type::ResolvedPath { - path: new_trait_path, - did: *did, - is_generic: *is_generic, - }, - generic_params: Vec::new(), - }, - hir::TraitBoundModifier::None, - )); - - // Remove any existing 'plain' bound (e.g., 'T: Iterator`) so - // that we don't see a - // duplicate bound like `T: Iterator + Iterator` - // on the docs page. - bounds.remove(&GenericBound::TraitBound( - PolyTrait { - trait_: *trait_.clone(), - generic_params: Vec::new(), - }, - hir::TraitBoundModifier::None, - )); - // Avoid creating any new duplicate bounds later in the outer - // loop - ty_to_traits - .entry(*ty.clone()) - .or_default() - .insert(*trait_.clone()); + let mut new_trait = trait_.clone(); + + if self.is_fn_trait(trait_) && left_name == sym::Output { + ty_to_fn + .entry(*ty.clone()) + .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) + .or_insert((None, Some(rhs))); + continue; + } + + let args = &mut new_trait + .segments + .last_mut() + .expect("segments were empty") + .args; + + match args { + // Convert something like ' = u8' + // to 'T: Iterator' + GenericArgs::AngleBracketed { ref mut bindings, .. } => { + bindings.push(TypeBinding { + name: left_name, + kind: TypeBindingKind::Equality { ty: rhs }, + }); + } + GenericArgs::Parenthesized { .. } => { + existing_predicates.push(WherePredicate::EqPredicate { + lhs: lhs.clone(), + rhs, + }); + continue; // If something other than a Fn ends up + // with parenthesis, leave it alone } - _ => panic!("Unexpected trait {:?} for {:?}", trait_, item_def_id), } + + let bounds = ty_to_bounds.entry(*ty.clone()).or_default(); + + bounds.insert(GenericBound::TraitBound( + PolyTrait { trait_: new_trait, generic_params: Vec::new() }, + hir::TraitBoundModifier::None, + )); + + // Remove any existing 'plain' bound (e.g., 'T: Iterator`) so + // that we don't see a + // duplicate bound like `T: Iterator + Iterator` + // on the docs page. + bounds.remove(&GenericBound::TraitBound( + PolyTrait { trait_: trait_.clone(), generic_params: Vec::new() }, + hir::TraitBoundModifier::None, + )); + // Avoid creating any new duplicate bounds later in the outer + // loop + ty_to_traits.entry(*ty.clone()).or_default().insert(trait_.clone()); } _ => panic!("Unexpected LHS {:?} for {:?}", lhs, item_def_id), } @@ -659,7 +619,7 @@ bounds.insert(0, GenericBound::maybe_sized(self.cx)); } } - GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Lifetime { .. } => {} GenericParamDefKind::Const { ref mut default, .. } => { // We never want something like `impl` default.take(); @@ -672,11 +632,11 @@ Generics { params: generic_params, where_predicates: existing_predicates } } - // Ensure that the predicates are in a consistent order. The precise - // ordering doesn't actually matter, but it's important that - // a given set of predicates always appears in the same order - - // both for visual consistency between 'rustdoc' runs, and to - // make writing tests much easier + /// Ensure that the predicates are in a consistent order. The precise + /// ordering doesn't actually matter, but it's important that + /// a given set of predicates always appears in the same order - + /// both for visual consistency between 'rustdoc' runs, and to + /// make writing tests much easier #[inline] fn sort_where_predicates(&self, mut predicates: &mut Vec) { // We should never have identical bounds - and if we do, @@ -685,11 +645,11 @@ self.unstable_debug_sort(&mut predicates); } - // Ensure that the bounds are in a consistent order. The precise - // ordering doesn't actually matter, but it's important that - // a given set of bounds always appears in the same order - - // both for visual consistency between 'rustdoc' runs, and to - // make writing tests much easier + /// Ensure that the bounds are in a consistent order. The precise + /// ordering doesn't actually matter, but it's important that + /// a given set of bounds always appears in the same order - + /// both for visual consistency between 'rustdoc' runs, and to + /// make writing tests much easier #[inline] fn sort_where_bounds(&self, mut bounds: &mut Vec) { // We should never have identical bounds - and if we do, @@ -698,47 +658,43 @@ self.unstable_debug_sort(&mut bounds); } - // This might look horrendously hacky, but it's actually not that bad. - // - // For performance reasons, we use several different FxHashMaps - // in the process of computing the final set of where predicates. - // However, the iteration order of a HashMap is completely unspecified. - // In fact, the iteration of an FxHashMap can even vary between platforms, - // since FxHasher has different behavior for 32-bit and 64-bit platforms. - // - // Obviously, it's extremely undesirable for documentation rendering - // to be dependent on the platform it's run on. Apart from being confusing - // to end users, it makes writing tests much more difficult, as predicates - // can appear in any order in the final result. - // - // To solve this problem, we sort WherePredicates and GenericBounds - // by their Debug string. The thing to keep in mind is that we don't really - // care what the final order is - we're synthesizing an impl or bound - // ourselves, so any order can be considered equally valid. By sorting the - // predicates and bounds, however, we ensure that for a given codebase, all - // auto-trait impls always render in exactly the same way. - // - // Using the Debug implementation for sorting prevents us from needing to - // write quite a bit of almost entirely useless code (e.g., how should two - // Types be sorted relative to each other). It also allows us to solve the - // problem for both WherePredicates and GenericBounds at the same time. This - // approach is probably somewhat slower, but the small number of items - // involved (impls rarely have more than a few bounds) means that it - // shouldn't matter in practice. + /// This might look horrendously hacky, but it's actually not that bad. + /// + /// For performance reasons, we use several different FxHashMaps + /// in the process of computing the final set of where predicates. + /// However, the iteration order of a HashMap is completely unspecified. + /// In fact, the iteration of an FxHashMap can even vary between platforms, + /// since FxHasher has different behavior for 32-bit and 64-bit platforms. + /// + /// Obviously, it's extremely undesirable for documentation rendering + /// to be dependent on the platform it's run on. Apart from being confusing + /// to end users, it makes writing tests much more difficult, as predicates + /// can appear in any order in the final result. + /// + /// To solve this problem, we sort WherePredicates and GenericBounds + /// by their Debug string. The thing to keep in mind is that we don't really + /// care what the final order is - we're synthesizing an impl or bound + /// ourselves, so any order can be considered equally valid. By sorting the + /// predicates and bounds, however, we ensure that for a given codebase, all + /// auto-trait impls always render in exactly the same way. + /// + /// Using the Debug implementation for sorting prevents us from needing to + /// write quite a bit of almost entirely useless code (e.g., how should two + /// Types be sorted relative to each other). It also allows us to solve the + /// problem for both WherePredicates and GenericBounds at the same time. This + /// approach is probably somewhat slower, but the small number of items + /// involved (impls rarely have more than a few bounds) means that it + /// shouldn't matter in practice. fn unstable_debug_sort(&self, vec: &mut Vec) { vec.sort_by_cached_key(|x| format!("{:?}", x)) } - fn is_fn_ty(&self, ty: &Type) -> bool { + fn is_fn_trait(&self, path: &Path) -> bool { let tcx = self.cx.tcx; - match ty { - &Type::ResolvedPath { did, .. } => { - did == tcx.require_lang_item(LangItem::Fn, None) - || did == tcx.require_lang_item(LangItem::FnMut, None) - || did == tcx.require_lang_item(LangItem::FnOnce, None) - } - _ => false, - } + let did = path.def_id(); + did == tcx.require_lang_item(LangItem::Fn, None) + || did == tcx.require_lang_item(LangItem::FnMut, None) + || did == tcx.require_lang_item(LangItem::FnOnce, None) } } @@ -749,7 +705,7 @@ } } -// Replaces all ReVars in a type with ty::Region's, using the provided map +/// Replaces all [`ty::RegionVid`]s in a type with [`ty::Region`]s, using the provided map. struct RegionReplacer<'a, 'tcx> { vid_to_region: &'a FxHashMap>, tcx: TyCtxt<'tcx>, diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/blanket_impl.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/blanket_impl.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/blanket_impl.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/blanket_impl.rs 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ let param_env = self.cx.tcx.param_env(item_def_id); let ty = self.cx.tcx.type_of(item_def_id); - debug!("get_blanket_impls({:?})", ty); + trace!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); for &trait_def_id in self.cx.tcx.all_traits(()).iter() { if !self.cx.cache.access_levels.is_public(trait_def_id) @@ -28,9 +28,10 @@ // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls let trait_impls = self.cx.tcx.trait_impls_of(trait_def_id); for &impl_def_id in trait_impls.blanket_impls() { - debug!( + trace!( "get_blanket_impls: Considering impl for trait '{:?}' {:?}", - trait_def_id, impl_def_id + trait_def_id, + impl_def_id ); let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_)); @@ -50,9 +51,11 @@ // FIXME(eddyb) ignoring `obligations` might cause false positives. drop(obligations); - debug!( + trace!( "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}", - param_env, trait_ref, ty + param_env, + trait_ref, + ty ); let predicates = self .cx @@ -61,7 +64,11 @@ .instantiate(self.cx.tcx, impl_substs) .predicates .into_iter() - .chain(Some(trait_ref.without_const().to_predicate(infcx.tcx))); + .chain(Some( + ty::Binder::dummy(trait_ref) + .without_const() + .to_predicate(infcx.tcx), + )); for predicate in predicates { debug!("testing predicate {:?}", predicate); let obligation = traits::Obligation::new( @@ -71,7 +78,8 @@ ); match infcx.evaluate_obligation(&obligation) { Ok(eval_result) if eval_result.may_apply() => {} - Err(traits::OverflowError) => {} + Err(traits::OverflowError::Canonical) => {} + Err(traits::OverflowError::ErrorReporting) => {} _ => { return false; } @@ -97,7 +105,7 @@ attrs: Default::default(), visibility: Inherited, def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, - kind: Box::new(ImplItem(Impl { + kind: box ImplItem(Impl { span: Span::new(self.cx.tcx.def_span(impl_def_id)), unsafety: hir::Unsafety::Normal, generics: ( @@ -107,7 +115,7 @@ .clean(self.cx), // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. - trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), + trait_: Some(trait_ref.clean(self.cx)), for_: ty.clean(self.cx), items: self .cx @@ -118,8 +126,8 @@ .clean(self.cx), negative_polarity: false, synthetic: false, - blanket_impl: Some(Box::new(trait_ref.self_ty().clean(self.cx))), - })), + blanket_impl: Some(box trait_ref.self_ty().clean(self.cx)), + }), cfg: None, }); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/cfg.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/cfg.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/cfg.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/cfg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -491,6 +491,7 @@ "aarch64" => "AArch64", "arm" => "ARM", "asmjs" => "JavaScript", + "m68k" => "M68k", "mips" => "MIPS", "mips64" => "MIPS-64", "msp430" => "MSP430", diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/inline.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/inline.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/inline.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/inline.rs 2021-11-29 19:27:11.000000000 +0000 @@ -124,14 +124,8 @@ let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone); cx.inlined.insert(did.into()); - let mut item = clean::Item::from_def_id_and_attrs_and_parts( - did, - Some(name), - kind, - Box::new(attrs), - cx, - cfg, - ); + let mut item = + clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, box attrs, cx, cfg); if let Some(import_def_id) = import_def_id { // The visibility needs to reflect the one from the reexport and not from the "source" DefId. item.visibility = cx.tcx.visibility(import_def_id).clean(cx); @@ -324,10 +318,10 @@ } else { Attributes::from_ast(&both, None) }, - both.cfg(cx.sess()), + both.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } else { - (old_attrs.clean(cx), old_attrs.cfg(cx.sess())) + (old_attrs.clean(cx), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg)) } } @@ -395,13 +389,45 @@ } } + let document_hidden = cx.render_options.document_hidden; let predicates = tcx.explicit_predicates_of(did); let (trait_items, generics) = match impl_item { Some(impl_) => ( impl_ .items .iter() - .map(|item| tcx.hir().impl_item(item.id).clean(cx)) + .map(|item| tcx.hir().impl_item(item.id)) + .filter(|item| { + // Filter out impl items whose corresponding trait item has `doc(hidden)` + // not to document such impl items. + // For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs. + + // When `--document-hidden-items` is passed, we don't + // do any filtering, too. + if document_hidden { + return true; + } + if let Some(associated_trait) = associated_trait { + let assoc_kind = match item.kind { + hir::ImplItemKind::Const(..) => ty::AssocKind::Const, + hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, + hir::ImplItemKind::TyAlias(..) => ty::AssocKind::Type, + }; + let trait_item = tcx + .associated_items(associated_trait.def_id) + .find_by_name_and_kind( + tcx, + item.ident, + assoc_kind, + associated_trait.def_id, + ) + .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name. + !tcx.get_attrs(trait_item.def_id).lists(sym::doc).has_word(sym::hidden) + } else { + true + } + }) + .map(|item| item.clean(cx)) .collect::>(), impl_.generics.clean(cx), ), @@ -420,20 +446,26 @@ ), }; let polarity = tcx.impl_polarity(did); - let trait_ = associated_trait.clean(cx).map(|bound| match bound { - clean::GenericBound::TraitBound(polyt, _) => polyt.trait_, - clean::GenericBound::Outlives(..) => unreachable!(), - }); - if trait_.def_id() == tcx.lang_items().deref_trait() { + let trait_ = associated_trait.clean(cx); + if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() { super::build_deref_target_impls(cx, &trait_items, ret); } // Return if the trait itself or any types of the generic parameters are doc(hidden). - let mut stack: Vec<&Type> = trait_.iter().collect(); - stack.push(&for_); + let mut stack: Vec<&Type> = vec![&for_]; + + if let Some(did) = trait_.as_ref().map(|t| t.def_id()) { + if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) { + return; + } + } + if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) { + stack.extend(generics); + } + while let Some(ty) = stack.pop() { if let Some(did) = ty.def_id() { - if cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) { + if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) { return; } } @@ -442,14 +474,14 @@ } } - if let Some(trait_did) = trait_.def_id() { - record_extern_trait(cx, trait_did); + if let Some(did) = trait_.as_ref().map(|t| t.def_id()) { + record_extern_trait(cx, did); } let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); - debug!("merged_attrs={:?}", merged_attrs); + trace!("merged_attrs={:?}", merged_attrs); - debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); + trace!("build_impl: impl {:?} for {:?}", trait_.as_ref().map(|t| t.def_id()), for_.def_id()); ret.push(clean::Item::from_def_id_and_attrs_and_parts( did, None, @@ -464,7 +496,7 @@ synthetic: false, blanket_impl: None, }), - Box::new(merged_attrs), + box merged_attrs, cx, cfg, )); @@ -482,25 +514,25 @@ // visit each node at most once. for &item in cx.tcx.item_children(did).iter() { if item.vis == ty::Visibility::Public { - if let Some(def_id) = item.res.mod_def_id() { + let res = item.res.expect_non_local(); + if let Some(def_id) = res.mod_def_id() { if did == def_id || !visited.insert(def_id) { continue; } } - if let Res::PrimTy(p) = item.res { + if let Res::PrimTy(p) = res { // Primitive types can't be inlined so generate an import instead. let prim_ty = clean::PrimitiveType::from(p); items.push(clean::Item { name: None, - attrs: Box::new(clean::Attributes::default()), + attrs: box clean::Attributes::default(), def_id: ItemId::Primitive(prim_ty, did.krate), visibility: clean::Public, - kind: Box::new(clean::ImportItem(clean::Import::new_simple( + kind: box clean::ImportItem(clean::Import::new_simple( item.ident.name, clean::ImportSource { path: clean::Path { - global: false, - res: item.res, + res, segments: vec![clean::PathSegment { name: prim_ty.as_sym(), args: clean::GenericArgs::AngleBracketed { @@ -512,12 +544,10 @@ did: None, }, true, - ))), + )), cfg: None, }); - } else if let Some(i) = - try_inline(cx, did, None, item.res, item.ident.name, None, visited) - { + } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) { items.extend(i) } } @@ -557,7 +587,6 @@ name: Symbol, import_def_id: Option, ) -> clean::ItemKind { - let imported_from = cx.tcx.crate_name(def_id.krate); match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) { LoadedMacro::MacroDef(item_def, _) => { if let ast::ItemKind::MacroDef(ref def) = item_def.kind { @@ -569,7 +598,6 @@ def_id, cx.tcx.visibility(import_def_id.unwrap_or(def_id)), ), - imported_from: Some(imported_from), }) } else { unreachable!() @@ -598,11 +626,10 @@ ref mut bounds, .. } if *s == kw::SelfUpper => { - bounds.retain(|bound| match *bound { - clean::GenericBound::TraitBound( - clean::PolyTrait { trait_: clean::ResolvedPath { did, .. }, .. }, - _, - ) => did != trait_did, + bounds.retain(|bound| match bound { + clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => { + trait_.def_id() != trait_did + } _ => true, }); } @@ -610,18 +637,12 @@ } } - g.where_predicates.retain(|pred| match *pred { + g.where_predicates.retain(|pred| match pred { clean::WherePredicate::BoundPredicate { - ty: - clean::QPath { - self_type: box clean::Generic(ref s), - trait_: box clean::ResolvedPath { did, .. }, - name: ref _name, - .. - }, - ref bounds, + ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, name: _, .. }, + bounds, .. - } => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did), + } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did), _ => true, }); g diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/mod.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,6 +11,7 @@ use rustc_ast as ast; use rustc_attr as attr; +use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -22,7 +23,6 @@ use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, AdtKind, DefIdTree, Lift, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_mir::const_eval::{is_const_fn, is_unstable_const_fn}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, ExpnKind}; @@ -30,6 +30,7 @@ use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety; use rustc_typeck::hir_ty_to_ty; +use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; use std::default::Default; use std::hash::Hash; @@ -128,11 +129,10 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound { match *self { hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)), - hir::GenericBound::Unsized(_) => GenericBound::maybe_sized(cx), hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => { let def_id = cx.tcx.require_lang_item(lang_item, Some(span)); - let trait_ref = ty::TraitRef::identity(cx.tcx, def_id); + let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder(); let generic_args = generic_args.clean(cx); let bindings = match generic_args { @@ -152,8 +152,8 @@ } } -impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { - fn clean(&self, cx: &mut DocContext<'_>) -> Type { +impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { + fn clean(&self, cx: &mut DocContext<'_>) -> Path { let (trait_ref, bounds) = *self; let kind = cx.tcx.def_kind(trait_ref.def_id).into(); if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { @@ -164,27 +164,17 @@ ); } inline::record_extern_fqn(cx, trait_ref.def_id, kind); - let path = external_path( - cx, - cx.tcx.item_name(trait_ref.def_id), - Some(trait_ref.def_id), - true, - bounds.to_vec(), - trait_ref.substs, - ); + let path = external_path(cx, trait_ref.def_id, true, bounds.to_vec(), trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); - ResolvedPath { path, did: trait_ref.def_id, is_generic: false } + path } } -impl<'tcx> Clean for ty::TraitRef<'tcx> { - fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound { - GenericBound::TraitBound( - PolyTrait { trait_: (*self, &[][..]).clean(cx), generic_params: vec![] }, - hir::TraitBoundModifier::None, - ) +impl Clean for ty::TraitRef<'tcx> { + fn clean(&self, cx: &mut DocContext<'_>) -> Path { + (*self, &[][..]).clean(cx) } } @@ -199,9 +189,10 @@ .collect_referenced_late_bound_regions(&poly_trait_ref) .into_iter() .filter_map(|br| match br { - ty::BrNamed(_, name) => { - Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime }) - } + ty::BrNamed(_, name) => Some(GenericParamDef { + name, + kind: GenericParamDefKind::Lifetime { outlives: vec![] }, + }), _ => None, }) .collect(); @@ -241,30 +232,6 @@ } } -impl Clean for hir::GenericParam<'_> { - fn clean(&self, _: &mut DocContext<'_>) -> Lifetime { - match self.kind { - hir::GenericParamKind::Lifetime { .. } => { - if !self.bounds.is_empty() { - let mut bounds = self.bounds.iter().map(|bound| match bound { - hir::GenericBound::Outlives(lt) => lt, - _ => panic!(), - }); - let name = bounds.next().expect("no more bounds").name.ident(); - let mut s = format!("{}: {}", self.name.ident(), name); - for bound in bounds { - s.push_str(&format!(" + {}", bound.name.ident())); - } - Lifetime(Symbol::intern(&s)) - } else { - Lifetime(self.name.ident().name) - } - } - _ => panic!(), - } - } -} - impl Clean for hir::ConstArg { fn clean(&self, cx: &mut DocContext<'_>) -> Constant { Constant { @@ -302,11 +269,30 @@ impl Clean for hir::WherePredicate<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate { match *self { - hir::WherePredicate::BoundPredicate(ref wbp) => WherePredicate::BoundPredicate { - ty: wbp.bounded_ty.clean(cx), - bounds: wbp.bounds.clean(cx), - bound_params: wbp.bound_generic_params.into_iter().map(|x| x.clean(cx)).collect(), - }, + hir::WherePredicate::BoundPredicate(ref wbp) => { + let bound_params = wbp + .bound_generic_params + .into_iter() + .map(|param| { + // Higher-ranked params must be lifetimes. + // Higher-ranked lifetimes can't have bounds. + assert_matches!( + param, + hir::GenericParam { + kind: hir::GenericParamKind::Lifetime { .. }, + bounds: [], + .. + } + ); + Lifetime(param.name.ident().name) + }) + .collect(); + WherePredicate::BoundPredicate { + ty: wbp.bounded_ty.clean(cx), + bounds: wbp.bounds.clean(cx), + bound_params, + } + } hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate { lifetime: wrp.lifetime.clean(cx), @@ -395,16 +381,13 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { fn clean(&self, cx: &mut DocContext<'_>) -> Type { let lifted = self.lift_to_tcx(cx.tcx).unwrap(); - let trait_ = match lifted.trait_ref(cx.tcx).clean(cx) { - GenericBound::TraitBound(t, _) => t.trait_, - GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"), - }; + let trait_ = lifted.trait_ref(cx.tcx).clean(cx); let self_type = self.self_ty().clean(cx); Type::QPath { name: cx.tcx.associated_item(self.item_def_id).ident.name, self_def_id: self_type.def_id(), - self_type: Box::new(self_type), - trait_: Box::new(trait_), + self_type: box self_type, + trait_, } } } @@ -412,7 +395,9 @@ impl Clean for ty::GenericParamDef { fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { - ty::GenericParamDefKind::Lifetime => (self.name, GenericParamDefKind::Lifetime), + ty::GenericParamDefKind::Lifetime => { + (self.name, GenericParamDefKind::Lifetime { outlives: vec![] }) + } ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { let default = if has_default { let mut default = cx.tcx.type_of(self.def_id).clean(cx); @@ -462,21 +447,15 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { hir::GenericParamKind::Lifetime { .. } => { - let name = if !self.bounds.is_empty() { - let mut bounds = self.bounds.iter().map(|bound| match bound { - hir::GenericBound::Outlives(lt) => lt, + let outlives = self + .bounds + .iter() + .map(|bound| match bound { + hir::GenericBound::Outlives(lt) => lt.clean(cx), _ => panic!(), - }); - let name = bounds.next().expect("no more bounds").name.ident(); - let mut s = format!("{}: {}", self.name.ident(), name); - for bound in bounds { - s.push_str(&format!(" + {}", bound.name.ident())); - } - Symbol::intern(&s) - } else { - self.name.ident().name - }; - (name, GenericParamDefKind::Lifetime) + }) + .collect(); + (self.name.ident().name, GenericParamDefKind::Lifetime { outlives }) } hir::GenericParamKind::Type { ref default, synthetic } => ( self.name.ident().name, @@ -536,7 +515,7 @@ .map(|param| { let param: GenericParamDef = param.clean(cx); match param.kind { - GenericParamDefKind::Lifetime => unreachable!(), + GenericParamDefKind::Lifetime { .. } => unreachable!(), GenericParamDefKind::Type { did, ref bounds, .. } => { cx.impl_trait_bounds.insert(did.into(), bounds.clone()); } @@ -564,19 +543,13 @@ WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => { - if let [] | [GenericBound::TraitBound(_, hir::TraitBoundModifier::Maybe)] = - &bounds[..] - { + if bounds.is_empty() { for param in &mut generics.params { match param.kind { - GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Lifetime { .. } => {} GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => { if ¶m.name == name { mem::swap(bounds, ty_bounds); - // We now keep track of `?Sized` obligations in the HIR. - // If we don't clear `ty_bounds` we end up with - // `fn foo(_: X) where X: ?Sized`. - ty_bounds.clear(); break; } } @@ -808,7 +781,7 @@ let mut func = (sig, generics, body_id).clean(cx); let def_id = item.def_id.to_def_id(); func.header.constness = - if is_const_fn(cx.tcx, def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() { + if cx.tcx.is_const_fn(def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() { hir::Constness::Const } else { hir::Constness::NotConst @@ -917,10 +890,11 @@ } } -impl Clean for hir::TraitRef<'_> { - fn clean(&self, cx: &mut DocContext<'_>) -> Type { +impl Clean for hir::TraitRef<'_> { + fn clean(&self, cx: &mut DocContext<'_>) -> Path { let path = self.path.clean(cx); - resolve_type(cx, path, self.hir_ref_id) + register_res(cx, path.res); + path } } @@ -1126,9 +1100,8 @@ if *name != my_name { return None; } - match **trait_ { - ResolvedPath { did, .. } if did == self.container.id() => {} - _ => return None, + if trait_.def_id() != self.container.id() { + return None; } match **self_type { Generic(ref s) if *s == kw::SelfUpper => {} @@ -1178,7 +1151,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { use rustc_hir::GenericParamCount; - let hir::Ty { hir_id, span, ref kind } = *hir_ty; + let hir::Ty { hir_id: _, span, ref kind } = *hir_ty; let qpath = match kind { hir::TyKind::Path(qpath) => qpath, _ => unreachable!(), @@ -1285,7 +1258,7 @@ return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx)); } let path = path.clean(cx); - resolve_type(cx, path, hir_id) + resolve_type(cx, path) } hir::QPath::Resolved(Some(ref qself), ref p) => { // Try to normalize `::T` to a type @@ -1294,19 +1267,18 @@ return normalized_value.clean(cx); } - let segments = if p.is_global() { &p.segments[1..] } else { &p.segments }; - let trait_segments = &segments[..segments.len() - 1]; + let trait_segments = &p.segments[..p.segments.len() - 1]; let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id(); - let trait_path = self::Path { - global: p.is_global(), + let trait_ = self::Path { res: Res::Def(DefKind::Trait, trait_def), segments: trait_segments.clean(cx), }; + register_res(cx, trait_.res); Type::QPath { name: p.segments.last().expect("segments were empty").ident.name, self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)), - self_type: Box::new(qself.clean(cx)), - trait_: Box::new(resolve_type(cx, trait_path, hir_id)), + self_type: box qself.clean(cx), + trait_, } } hir::QPath::TypeRelative(ref qself, ref segment) => { @@ -1317,12 +1289,13 @@ ty::Error(_) => return Type::Infer, _ => bug!("clean: expected associated type, found `{:?}`", ty), }; - let trait_path = hir::Path { span, res, segments: &[] }.clean(cx); + let trait_ = hir::Path { span, res, segments: &[] }.clean(cx); + register_res(cx, trait_.res); Type::QPath { name: segment.ident.name, self_def_id: res.opt_def_id(), - self_type: Box::new(qself.clean(cx)), - trait_: Box::new(resolve_type(cx, trait_path, hir_id)), + self_type: box qself.clean(cx), + trait_, } } hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"), @@ -1334,8 +1307,8 @@ use rustc_hir::*; match self.kind { - TyKind::Never => Never, - TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(m.ty.clean(cx))), + TyKind::Never => Primitive(PrimitiveType::Never), + TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)), TyKind::Rptr(ref l, ref m) => { // There are two times a `Fresh` lifetime can be created: // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. @@ -1347,9 +1320,9 @@ let elided = l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_))); let lifetime = if elided { None } else { Some(l.clean(cx)) }; - BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(m.ty.clean(cx)) } + BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) } } - TyKind::Slice(ref ty) => Slice(Box::new(ty.clean(cx))), + TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); // NOTE(min_const_generics): We can't use `const_eval_poly` for constants @@ -1362,7 +1335,7 @@ let ct = ty::Const::from_anon_const(cx.tcx, def_id); let param_env = cx.tcx.param_env(def_id); let length = print_const(cx, ct.eval(cx.tcx, param_env)); - Array(Box::new(ty.clean(cx)), length) + Array(box ty.clean(cx), length) } TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), TyKind::OpaqueDef(item_id, _) => { @@ -1379,7 +1352,7 @@ let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None }; DynTrait(bounds, lifetime) } - TyKind::BareFn(ref barefn) => BareFunction(Box::new(barefn.clean(cx))), + TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err => Infer, TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind), @@ -1420,39 +1393,37 @@ impl<'tcx> Clean for Ty<'tcx> { fn clean(&self, cx: &mut DocContext<'_>) -> Type { - debug!("cleaning type: {:?}", self); + trace!("cleaning type: {:?}", self); let ty = normalize(cx, self).unwrap_or(self); match *ty.kind() { - ty::Never => Never, + ty::Never => Primitive(PrimitiveType::Never), ty::Bool => Primitive(PrimitiveType::Bool), ty::Char => Primitive(PrimitiveType::Char), ty::Int(int_ty) => Primitive(int_ty.into()), ty::Uint(uint_ty) => Primitive(uint_ty.into()), ty::Float(float_ty) => Primitive(float_ty.into()), ty::Str => Primitive(PrimitiveType::Str), - ty::Slice(ty) => Slice(Box::new(ty.clean(cx))), + ty::Slice(ty) => Slice(box ty.clean(cx)), ty::Array(ty, n) => { let mut n = cx.tcx.lift(n).expect("array lift failed"); n = n.eval(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n); - Array(Box::new(ty.clean(cx)), n) + Array(box ty.clean(cx), n) + } + ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)), + ty::Ref(r, ty, mutbl) => { + BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) } } - ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(mt.ty.clean(cx))), - ty::Ref(r, ty, mutbl) => BorrowedRef { - lifetime: r.clean(cx), - mutability: mutbl, - type_: Box::new(ty.clean(cx)), - }, ty::FnDef(..) | ty::FnPtr(_) => { let ty = cx.tcx.lift(*self).expect("FnPtr lift failed"); let sig = ty.fn_sig(cx.tcx); let def_id = DefId::local(CRATE_DEF_INDEX); - BareFunction(Box::new(BareFunctionDecl { + BareFunction(box BareFunctionDecl { unsafety: sig.unsafety(), generic_params: Vec::new(), decl: (def_id, sig).clean(cx), abi: sig.abi(), - })) + }) } ty::Adt(def, substs) => { let did = def.did; @@ -1462,20 +1433,13 @@ AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs); - ResolvedPath { path, did, is_generic: false } + let path = external_path(cx, did, false, vec![], substs); + ResolvedPath { path, did } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); - let path = external_path( - cx, - cx.tcx.item_name(did), - None, - false, - vec![], - InternalSubsts::empty(), - ); - ResolvedPath { path, did, is_generic: false } + let path = external_path(cx, did, false, vec![], InternalSubsts::empty()); + ResolvedPath { path, did } } ty::Dynamic(ref obj, ref reg) => { // HACK: pick the first `did` as the `did` of the trait object. Someone @@ -1498,13 +1462,9 @@ for did in dids { let empty = cx.tcx.intern_substs(&[]); - let path = - external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); + let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); - let bound = PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, - generic_params: Vec::new(), - }; + let bound = PolyTrait { trait_: path, generic_params: Vec::new() }; bounds.push(bound); } @@ -1516,15 +1476,8 @@ }); } - let path = - external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs); - bounds.insert( - 0, - PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, - generic_params: Vec::new(), - }, - ); + let path = external_path(cx, did, false, bindings, substs); + bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() }); DynTrait(bounds, lifetime) } @@ -1763,11 +1716,7 @@ impl Clean for hir::Path<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Path { - Path { - global: self.is_global(), - res: self.res, - segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx), - } + Path { res: self.res, segments: self.segments.clean(cx) } } } @@ -1789,7 +1738,7 @@ } hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)), - hir::GenericArg::Const(ct) => GenericArg::Const(ct.clean(cx)), + hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))), hir::GenericArg::Infer(_inf) => GenericArg::Infer, }) .collect(), @@ -1873,7 +1822,6 @@ } ItemKind::Macro(ref macro_def) => MacroItem(Macro { source: display_macro_source(cx, name, ¯o_def, def_id, &item.vis), - imported_from: None, }), ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => { let items = item_ids @@ -1934,7 +1882,7 @@ // If this impl block is an implementation of the Deref trait, then we // need to try inlining the target's inherent impl blocks as well. - if trait_.def_id() == tcx.lang_items().deref_trait() { + if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() { build_deref_target_impls(cx, &items, &mut ret); } @@ -1943,7 +1891,7 @@ DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)), _ => None, }); - let mut make_item = |trait_: Option, for_: Type, items: Vec| { + let mut make_item = |trait_: Option, for_: Type, items: Vec| { let kind = ImplItem(Impl { span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx), unsafety: impl_.unsafety, @@ -2005,11 +1953,11 @@ // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason vec![Item { name: Some(name), - attrs: Box::new(attrs.clean(cx)), + attrs: box attrs.clean(cx), def_id: crate_def_id.into(), visibility: krate.vis.clean(cx), - kind: Box::new(ExternCrateItem { src: orig_name }), - cfg: attrs.cfg(cx.sess()), + kind: box ExternCrateItem { src: orig_name }, + cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), }] } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/simplify.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/simplify.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/simplify.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/simplify.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,8 +11,7 @@ //! This module attempts to reconstruct the original where and/or parameter //! bounds by special casing scenarios such as these. Fun! -use std::collections::BTreeMap; - +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_middle::ty; use rustc_span::Symbol; @@ -23,8 +22,11 @@ use crate::core::DocContext; crate fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { - // First, partition the where clause into its separate components - let mut params: BTreeMap<_, (Vec<_>, Vec<_>)> = BTreeMap::new(); + // First, partition the where clause into its separate components. + // + // We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to + // the order of the generated bounds. + let mut params: FxIndexMap, Vec<_>)> = FxIndexMap::default(); let mut lifetimes = Vec::new(); let mut equalities = Vec::new(); let mut tybounds = Vec::new(); @@ -97,17 +99,13 @@ clean::GenericBound::TraitBound(ref mut tr, _) => tr, clean::GenericBound::Outlives(..) => return false, }; - let (did, path) = match trait_ref.trait_ { - clean::ResolvedPath { did, ref mut path, .. } => (did, path), - _ => return false, - }; // If this QPath's trait `trait_did` is the same as, or a supertrait // of, the bound's trait `did` then we can keep going, otherwise // this is just a plain old equality bound. - if !trait_is_same_or_supertrait(cx, did, trait_did) { + if !trait_is_same_or_supertrait(cx, trait_ref.trait_.def_id(), trait_did) { return false; } - let last = path.segments.last_mut().expect("segments were empty"); + let last = trait_ref.trait_.segments.last_mut().expect("segments were empty"); match last.args { PP::AngleBracketed { ref mut bindings, .. } => { bindings.push(clean::TypeBinding { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/types.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/types.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/types.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/types.rs 2021-11-29 19:27:11.000000000 +0000 @@ -120,8 +120,7 @@ crate module: Item, crate externs: Vec, crate primitives: ThinVec<(DefId, PrimitiveType)>, - // These are later on moved into `CACHEKEY`, leaving the map empty. - // Only here so that they can be filtered through the rustdoc passes. + /// Only here so that they can be filtered through the rustdoc passes. crate external_traits: Rc>>, crate collapsed: bool, } @@ -212,7 +211,7 @@ crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> { let root = self.def_id(); - let as_keyword = |res: Res| { + let as_keyword = |res: Res| { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = tcx.get_attrs(def_id); let mut keyword = None; @@ -230,8 +229,7 @@ }; if root.is_local() { tcx.hir() - .krate() - .module() + .root_module() .item_ids .iter() .filter_map(|&id| { @@ -243,7 +241,8 @@ hir::ItemKind::Use(ref path, hir::UseKind::Single) if item.vis.node.is_pub() => { - as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim)) + as_keyword(path.res.expect_non_local()) + .map(|(_, prim)| (id.def_id.to_def_id(), prim)) } _ => None, } @@ -274,7 +273,7 @@ // Also note that this does not attempt to deal with modules tagged // duplicately for the same primitive. This is handled later on when // rendering by delegating everything to a hash map. - let as_primitive = |res: Res| { + let as_primitive = |res: Res| { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = tcx.get_attrs(def_id); let mut prim = None; @@ -296,8 +295,7 @@ if root.is_local() { tcx.hir() - .krate() - .module() + .root_module() .item_ids .iter() .filter_map(|&id| { @@ -309,7 +307,7 @@ hir::ItemKind::Use(ref path, hir::UseKind::Single) if item.vis.node.is_pub() => { - as_primitive(path.res).map(|(_, prim)| { + as_primitive(path.res.expect_non_local()).map(|(_, prim)| { // Pretend the primitive is local. (id.def_id.to_def_id(), prim) }) @@ -420,9 +418,9 @@ def_id, name, kind, - Box::new(ast_attrs.clean(cx)), + box ast_attrs.clean(cx), cx, - ast_attrs.cfg(cx.sess()), + ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } @@ -438,7 +436,7 @@ Item { def_id: def_id.into(), - kind: Box::new(kind), + kind: box kind, name, attrs, visibility: cx.tcx.visibility(def_id).clean(cx), @@ -461,60 +459,20 @@ .map_or(&[][..], |v| v.as_slice()) .iter() .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| { - match did { - Some(did) => { - if let Ok((mut href, ..)) = href(did.clone(), cx) { - if let Some(ref fragment) = *fragment { - href.push('#'); - href.push_str(fragment); - } - Some(RenderedLink { - original_text: s.clone(), - new_text: link_text.clone(), - href, - }) - } else { - None - } - } - // FIXME(83083): using fragments as a side-channel for - // primitive names is very unfortunate - None => { - let relative_to = &cx.current; - if let Some(ref fragment) = *fragment { - let url = match cx.cache().extern_locations.get(&self.def_id.krate()) { - Some(&ExternalLocation::Local) => { - if relative_to[0] == "std" { - let depth = relative_to.len() - 1; - "../".repeat(depth) - } else { - let depth = relative_to.len(); - format!("{}std/", "../".repeat(depth)) - } - } - Some(ExternalLocation::Remote(ref s)) => { - format!("{}/std/", s.trim_end_matches('/')) - } - Some(ExternalLocation::Unknown) | None => { - format!("{}/std/", crate::DOC_RUST_LANG_ORG_CHANNEL) - } - }; - // This is a primitive so the url is done "by hand". - let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); - Some(RenderedLink { - original_text: s.clone(), - new_text: link_text.clone(), - href: format!( - "{}primitive.{}.html{}", - url, - &fragment[..tail], - &fragment[tail..] - ), - }) - } else { - panic!("This isn't a primitive?!"); - } + debug!(?did); + if let Ok((mut href, ..)) = href(*did, cx) { + debug!(?href); + if let Some(ref fragment) = *fragment { + href.push('#'); + href.push_str(fragment); } + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href, + }) + } else { + None } }) .collect() @@ -531,18 +489,10 @@ .get(&self.def_id) .map_or(&[][..], |v| v.as_slice()) .iter() - .filter_map(|ItemLink { link: s, link_text, did, fragment }| { - // FIXME(83083): using fragments as a side-channel for - // primitive names is very unfortunate - if did.is_some() || fragment.is_some() { - Some(RenderedLink { - original_text: s.clone(), - new_text: link_text.clone(), - href: String::new(), - }) - } else { - None - } + .map(|ItemLink { link: s, link_text, .. }| RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href: String::new(), }) .collect() } @@ -796,7 +746,7 @@ fn other_attrs(&self) -> Vec; - fn cfg(&self, sess: &Session) -> Option>; + fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option>; } impl AttributesExt for [ast::Attribute] { @@ -821,8 +771,44 @@ self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() } - fn cfg(&self, sess: &Session) -> Option> { - let mut cfg = Cfg::True; + fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option> { + let sess = tcx.sess; + let doc_cfg_active = tcx.features().doc_cfg; + let doc_auto_cfg_active = tcx.features().doc_auto_cfg; + + fn single(it: T) -> Option { + let mut iter = it.into_iter(); + let item = iter.next()?; + if iter.next().is_some() { + return None; + } + Some(item) + } + + let mut cfg = if doc_cfg_active || doc_auto_cfg_active { + let mut doc_cfg = self + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new)) + .filter(|attr| attr.has_name(sym::cfg)) + .peekable(); + if doc_cfg.peek().is_some() && doc_cfg_active { + doc_cfg + .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else if doc_auto_cfg_active { + self.iter() + .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| single(attr.meta_item_list()?)) + .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .filter(|cfg| !hidden_cfg.contains(cfg)) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else { + Cfg::True + } + } else { + Cfg::True + }; for attr in self.iter() { // #[doc] @@ -849,6 +835,8 @@ } } + // treat #[target_feature(enable = "feat")] attributes as if they were + // #[doc(cfg(target_feature = "feat"))] attributes as well for attr in self.lists(sym::target_feature) { if attr.has_name(sym::enable) { if let Some(feat) = attr.value_str() { @@ -955,18 +943,10 @@ } } -/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`, -/// as well as doc comments. -#[derive(Clone, Debug, Default)] -crate struct Attributes { - crate doc_strings: Vec, - crate other_attrs: Vec, -} - -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] /// A link that has not yet been rendered. /// /// This link will be turned into a rendered link by [`Item::links`]. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] crate struct ItemLink { /// The original link written in the markdown pub(crate) link: String, @@ -975,7 +955,7 @@ /// This may not be the same as `link` if there was a disambiguator /// in an intra-doc link (e.g. \[`fn@f`\]) pub(crate) link_text: String, - pub(crate) did: Option, + pub(crate) did: DefId, /// The url fragment to append to the link pub(crate) fragment: Option, } @@ -991,6 +971,14 @@ pub(crate) href: String, } +/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`, +/// as well as doc comments. +#[derive(Clone, Debug, Default)] +crate struct Attributes { + crate doc_strings: Vec, + crate other_attrs: Vec, +} + impl Attributes { crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { self.other_attrs.lists(name) @@ -1158,13 +1146,10 @@ crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); + let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( - PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, - generic_params: Vec::new(), - }, + PolyTrait { trait_: path, generic_params: Vec::new() }, hir::TraitBoundModifier::Maybe, ) } @@ -1172,7 +1157,7 @@ crate fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { use rustc_hir::TraitBoundModifier as TBM; if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { - if trait_.def_id() == cx.tcx.lang_items().sized_trait() { + if Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() { return true; } } @@ -1186,7 +1171,7 @@ None } - crate fn get_trait_type(&self) -> Option { + crate fn get_trait_path(&self) -> Option { if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { Some(trait_.clone()) } else { @@ -1231,7 +1216,9 @@ #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate enum GenericParamDefKind { - Lifetime, + Lifetime { + outlives: Vec, + }, Type { did: DefId, bounds: Vec, @@ -1257,7 +1244,7 @@ match self { GenericParamDefKind::Type { default, .. } => default.clone(), GenericParamDefKind::Const { ty, .. } => Some(ty.clone()), - GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Lifetime { .. } => None, } } } @@ -1271,7 +1258,7 @@ impl GenericParamDef { crate fn is_synthetic_type_param(&self) -> bool { match self.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => false, + GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false, GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(), } } @@ -1416,90 +1403,56 @@ /// A trait reference, which may have higher ranked lifetimes. #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct PolyTrait { - crate trait_: Type, + crate trait_: Path, crate generic_params: Vec, } -/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original -/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most -/// importantly, it does not preserve mutability or boxes. +/// Rustdoc's representation of types, mostly based on the [`hir::Ty`]. #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate enum Type { - /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). - ResolvedPath { - path: Path, - did: DefId, - /// `true` if is a `T::Name` path for associated types. - is_generic: bool, - }, - /// `dyn for<'a> Trait<'a> + Send + 'static` + /// A named type, which could be a trait. + /// + /// This is mostly Rustdoc's version of [`hir::Path`]. It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics. + ResolvedPath { path: Path, did: DefId }, + /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static` DynTrait(Vec, Option), - /// For parameterized types, so the consumer of the JSON don't go - /// looking for types which don't exist anywhere. + /// A type parameter. Generic(Symbol), - /// Primitives are the fixed-size numeric types (plus int/usize/float), char, - /// arrays, slices, and tuples. + /// A primitive (aka, builtin) type. Primitive(PrimitiveType), - /// `extern "ABI" fn` + /// A function pointer: `extern "ABI" fn(...) -> ...` BareFunction(Box), + /// A tuple type: `(i32, &str)`. Tuple(Vec), + /// A slice type (does *not* include the `&`): `[i32]` Slice(Box), - /// The `String` field is about the size or the constant representing the array's length. + /// An array type. + /// + /// The `String` field is a stringified version of the array's length parameter. Array(Box, String), - Never, + /// A raw pointer type: `*const i32`, `*mut i32` RawPointer(Mutability, Box), - BorrowedRef { - lifetime: Option, - mutability: Mutability, - type_: Box, - }, + /// A reference type: `&i32`, `&'a mut Foo` + BorrowedRef { lifetime: Option, mutability: Mutability, type_: Box }, - // `::Name` + /// A qualified path to an associated item: `::Name` QPath { name: Symbol, self_type: Box, + /// FIXME: This is a hack that should be removed; see [this discussion][1]. + /// + /// [1]: https://github.com/rust-lang/rust/pull/85479#discussion_r635729093 self_def_id: Option, - trait_: Box, + trait_: Path, }, - // `_` + /// A type that is inferred: `_` Infer, - // `impl TraitA + TraitB + ...` + /// An `impl Trait`: `impl TraitA + TraitB + ...` ImplTrait(Vec), } -#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] -/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't -/// paths, like `Unit`. -crate enum PrimitiveType { - Isize, - I8, - I16, - I32, - I64, - I128, - Usize, - U8, - U16, - U32, - U64, - U128, - F32, - F64, - Char, - Bool, - Str, - Slice, - Array, - Tuple, - Unit, - RawPointer, - Reference, - Fn, - Never, -} - crate trait GetDefId { /// Use this method to get the [`DefId`] of a [`clean`] AST node. /// This will return [`None`] when called on a primitive [`clean::Type`]. @@ -1543,14 +1496,14 @@ } RawPointer(..) => Some(PrimitiveType::RawPointer), BareFunction(..) => Some(PrimitiveType::Fn), - Never => Some(PrimitiveType::Never), _ => None, } } - crate fn is_generic(&self) -> bool { - match *self { - ResolvedPath { is_generic, .. } => is_generic, + /// Checks if this is a `T::Name` path for an associated type. + crate fn is_assoc_ty(&self) -> bool { + match self { + ResolvedPath { path, .. } => path.is_assoc_ty(), _ => false, } } @@ -1563,34 +1516,8 @@ } crate fn generics(&self) -> Option> { - match *self { - ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { - if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { - Some( - args.iter() - .filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }) - .collect(), - ) - } else { - None - } - }), - _ => None, - } - } - - crate fn bindings(&self) -> Option<&[TypeBinding]> { - match *self { - ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { - if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { - Some(&**bindings) - } else { - None - } - }), + match self { + ResolvedPath { path, .. } => path.generics(), _ => None, } } @@ -1608,19 +1535,13 @@ QPath { self_type, trait_, name, .. } => (self_type, trait_, name), _ => return None, }; - let trait_did = match **trait_ { - ResolvedPath { did, .. } => did, - _ => return None, - }; - Some((&self_, trait_did, *name)) + Some((&self_, trait_.def_id(), *name)) } -} -impl Type { fn inner_def_id(&self, cache: Option<&Cache>) -> Option { let t: PrimitiveType = match *self { ResolvedPath { did, .. } => return Some(did), - DynTrait(ref bounds, _) => return bounds[0].trait_.inner_def_id(cache), + DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()), Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()), BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference, BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache), @@ -1632,7 +1553,6 @@ } } BareFunction(..) => PrimitiveType::Fn, - Never => PrimitiveType::Never, Slice(..) => PrimitiveType::Slice, Array(..) => PrimitiveType::Array, RawPointer(..) => PrimitiveType::RawPointer, @@ -1653,6 +1573,41 @@ } } +/// A primitive (aka, builtin) type. +/// +/// This represents things like `i32`, `str`, etc. +/// +/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't +/// paths, like [`Self::Unit`]. +#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] +crate enum PrimitiveType { + Isize, + I8, + I16, + I32, + I64, + I128, + Usize, + U8, + U16, + U32, + U64, + U128, + F32, + F64, + Char, + Bool, + Str, + Slice, + Array, + Tuple, + Unit, + RawPointer, + Reference, + Fn, + Never, +} + impl PrimitiveType { crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType { use ast::{FloatTy, IntTy, UintTy}; @@ -1800,6 +1755,39 @@ Never => sym::never, } } + + /// Returns the DefId of the module with `doc(primitive)` for this primitive type. + /// Panics if there is no such module. + /// + /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`, + /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked. + /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then + /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.) + crate fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap { + static PRIMITIVE_LOCATIONS: OnceCell> = OnceCell::new(); + PRIMITIVE_LOCATIONS.get_or_init(|| { + let mut primitive_locations = FxHashMap::default(); + // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate. + // This is a degenerate case that I don't plan to support. + for &crate_num in tcx.crates(()) { + let e = ExternalCrate { crate_num }; + let crate_name = e.name(tcx); + debug!(?crate_num, ?crate_name); + for &(def_id, prim) in &e.primitives(tcx) { + // HACK: try to link to std instead where possible + if crate_name == sym::core && primitive_locations.contains_key(&prim) { + continue; + } + primitive_locations.insert(prim, def_id); + } + } + let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx); + for (def_id, prim) in local_primitives { + primitive_locations.insert(prim, def_id); + } + primitive_locations + }) + } } impl From for PrimitiveType { @@ -1988,12 +1976,15 @@ #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct Path { - crate global: bool, crate res: Res, crate segments: Vec, } impl Path { + crate fn def_id(&self) -> DefId { + self.res.def_id() + } + crate fn last(&self) -> Symbol { self.segments.last().expect("segments were empty").name } @@ -2003,8 +1994,48 @@ } crate fn whole_name(&self) -> String { - String::from(if self.global { "::" } else { "" }) - + &self.segments.iter().map(|s| s.name.to_string()).collect::>().join("::") + self.segments + .iter() + .map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() }) + .intersperse("::".into()) + .collect() + } + + /// Checks if this is a `T::Name` path for an associated type. + crate fn is_assoc_ty(&self) -> bool { + match self.res { + Res::SelfTy(..) if self.segments.len() != 1 => true, + Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true, + Res::Def(DefKind::AssocTy, _) => true, + _ => false, + } + } + + crate fn generics(&self) -> Option> { + self.segments.last().and_then(|seg| { + if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { + Some( + args.iter() + .filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + }) + .collect(), + ) + } else { + None + } + }) + } + + crate fn bindings(&self) -> Option<&[TypeBinding]> { + self.segments.last().and_then(|seg| { + if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { + Some(&**bindings) + } else { + None + } + }) } } @@ -2012,10 +2043,15 @@ crate enum GenericArg { Lifetime(Lifetime), Type(Type), - Const(Constant), + Const(Box), Infer, } +// `GenericArg` can occur many times in a single `Path`, so make sure it +// doesn't increase in size unexpectedly. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(GenericArg, 80); + #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate enum GenericArgs { AngleBracketed { args: Vec, bindings: Vec }, @@ -2144,7 +2180,7 @@ crate span: Span, crate unsafety: hir::Unsafety, crate generics: Generics, - crate trait_: Option, + crate trait_: Option, crate for_: Type, crate items: Vec, crate negative_polarity: bool, @@ -2155,7 +2191,8 @@ impl Impl { crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet { self.trait_ - .def_id() + .as_ref() + .map(|t| t.def_id()) .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect()) .unwrap_or_default() } @@ -2195,7 +2232,6 @@ #[derive(Clone, Debug)] crate struct Macro { crate source: String, - crate imported_from: Option, } #[derive(Clone, Debug)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/utils.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/utils.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/clean/utils.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/clean/utils.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, - ItemKind, Lifetime, Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, + ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, Visibility, }; use crate::core::DocContext; @@ -26,12 +26,7 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { use crate::visit_lib::LibEmbargoVisitor; - let krate = cx.tcx.hir().krate(); - let module = crate::visit_ast::RustdocVisitor::new(cx).visit(krate); - - cx.cache.deref_trait_did = cx.tcx.lang_items().deref_trait(); - cx.cache.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); - cx.cache.owned_box_did = cx.tcx.lang_items().owned_box(); + let module = crate::visit_ast::RustdocVisitor::new(cx).visit(); let mut externs = Vec::new(); for &cnum in cx.tcx.crates(()).iter() { @@ -97,7 +92,7 @@ fn external_generic_args( cx: &mut DocContext<'_>, - trait_did: Option, + did: DefId, has_self: bool, bindings: Vec, substs: SubstsRef<'_>, @@ -121,85 +116,47 @@ ty_kind = Some(ty.kind()); Some(GenericArg::Type(ty.clean(cx))) } - GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), + GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))), }) .collect(); - match trait_did { - // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C - Some(did) if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() => { - assert!(ty_kind.is_some()); - let inputs = match ty_kind { - Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), - _ => return GenericArgs::AngleBracketed { args, bindings }, - }; - let output = None; - // FIXME(#20299) return type comes from a projection now - // match types[1].kind { - // ty::Tuple(ref v) if v.is_empty() => None, // -> () - // _ => Some(types[1].clean(cx)) - // }; - GenericArgs::Parenthesized { inputs, output } - } - _ => GenericArgs::AngleBracketed { args, bindings }, + if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() { + let inputs = match ty_kind.unwrap() { + ty::Tuple(tys) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), + _ => return GenericArgs::AngleBracketed { args, bindings }, + }; + let output = None; + // FIXME(#20299) return type comes from a projection now + // match types[1].kind { + // ty::Tuple(ref v) if v.is_empty() => None, // -> () + // _ => Some(types[1].clean(cx)) + // }; + GenericArgs::Parenthesized { inputs, output } + } else { + GenericArgs::AngleBracketed { args, bindings } } } -// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar -// from Fn<(A, B,), C> to Fn(A, B) -> C pub(super) fn external_path( cx: &mut DocContext<'_>, - name: Symbol, - trait_did: Option, + did: DefId, has_self: bool, bindings: Vec, substs: SubstsRef<'_>, ) -> Path { + let def_kind = cx.tcx.def_kind(did); + let name = cx.tcx.item_name(did); Path { - global: false, - res: Res::Err, + res: Res::Def(def_kind, did), segments: vec![PathSegment { name, - args: external_generic_args(cx, trait_did, has_self, bindings, substs), + args: external_generic_args(cx, did, has_self, bindings, substs), }], } } -crate fn strip_type(ty: Type) -> Type { - match ty { - Type::ResolvedPath { path, did, is_generic } => { - Type::ResolvedPath { path: strip_path(&path), did, is_generic } - } - Type::DynTrait(mut bounds, lt) => { - let first = bounds.remove(0); - let stripped_trait = strip_type(first.trait_); - - bounds.insert( - 0, - PolyTrait { trait_: stripped_trait, generic_params: first.generic_params }, - ); - Type::DynTrait(bounds, lt) - } - Type::Tuple(inner_tys) => { - Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect()) - } - Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), - Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), - Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), - Type::BorrowedRef { lifetime, mutability, type_ } => { - Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } - } - Type::QPath { name, self_type, trait_, self_def_id } => Type::QPath { - name, - self_def_id, - self_type: Box::new(strip_type(*self_type)), - trait_: Box::new(strip_type(*trait_)), - }, - _ => ty, - } -} - -crate fn strip_path(path: &Path) -> Path { +/// Remove the generic arguments from a path. +crate fn strip_path_generics(path: Path) -> Path { let segments = path .segments .iter() @@ -209,7 +166,7 @@ }) .collect(); - Path { global: path.global, res: path.res, segments } + Path { res: path.res, segments } } crate fn qpath_to_string(p: &hir::QPath<'_>) -> String { @@ -409,22 +366,18 @@ } /// Given a type Path, resolve it to a Type using the TyCtxt -crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Type { - debug!("resolve_type({:?},{:?})", path, id); +crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { + debug!("resolve_type({:?})", path); - let is_generic = match path.res { - Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)), - Res::SelfTy(..) if path.segments.len() == 1 => { - return Generic(kw::SelfUpper); - } - Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(Symbol::intern(&path.whole_name())); + match path.res { + Res::PrimTy(p) => Primitive(PrimitiveType::from(p)), + Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper), + Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name), + _ => { + let did = register_res(cx, path.res); + ResolvedPath { path, did } } - Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true, - _ => false, - }; - let did = register_res(cx, path.res); - ResolvedPath { path, did, is_generic } + } } crate fn get_auto_trait_and_blanket_impls( diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/config.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/config.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/config.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/config.rs 2021-11-29 19:27:11.000000000 +0000 @@ -137,7 +137,7 @@ crate manual_passes: Vec, /// Whether to display warnings during doc generation or while gathering doctests. By default, /// all non-rustdoc-specific lints are allowed when generating docs. - crate display_warnings: bool, + crate display_doctest_warnings: bool, /// Whether to run the `calculate-doc-coverage` pass, which counts the number of public items /// with and without documentation. crate show_coverage: bool, @@ -192,7 +192,7 @@ .field("persist_doctests", &self.persist_doctests) .field("default_passes", &self.default_passes) .field("manual_passes", &self.manual_passes) - .field("display_warnings", &self.display_warnings) + .field("display_doctest_warnings", &self.display_doctest_warnings) .field("show_coverage", &self.show_coverage) .field("crate_version", &self.crate_version) .field("render_options", &self.render_options) @@ -632,7 +632,7 @@ let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); let playground_url = matches.opt_str("playground-url"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); - let display_warnings = matches.opt_present("display-warnings"); + let display_doctest_warnings = matches.opt_present("display-doctest-warnings"); let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance"); let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default(); let enable_minification = !matches.opt_present("disable-minification"); @@ -696,7 +696,7 @@ test_args, default_passes, manual_passes, - display_warnings, + display_doctest_warnings, show_coverage, crate_version, test_run_directory, diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/core.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/core.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/core.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/core.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,15 +16,18 @@ use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_resolve as resolve; +use rustc_resolve::Namespace::TypeNS; use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::lint; use rustc_session::DiagnosticOutput; use rustc_session::Session; +use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_span::source_map; use rustc_span::symbol::sym; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; +use std::lazy::SyncLazy; use std::mem; use std::rc::Rc; @@ -204,7 +207,6 @@ lint_opts, describe_lints, lint_cap, - display_warnings, .. }: RustdocOptions, ) -> rustc_interface::Config { @@ -237,7 +239,7 @@ maybe_sysroot, search_paths: libs, crate_types, - lint_opts: if !display_warnings { lint_opts } else { vec![] }, + lint_opts, lint_cap, cg: codegen_options, externs, @@ -264,7 +266,7 @@ stderr: None, lint_caps, parse_sess_created: None, - register_lints: Some(Box::new(crate::lint::register_lints)), + register_lints: Some(box crate::lint::register_lints), override_queries: Some(|_sess, providers, _external_providers| { // Most lints will require typechecking, so just don't run them. providers.lint_mod = |_, _| {}; @@ -272,9 +274,8 @@ providers.typeck_item_bodies = |_, _| {}; // hack so that `used_trait_imports` won't try to call typeck providers.used_trait_imports = |_, _| { - lazy_static! { - static ref EMPTY_SET: FxHashSet = FxHashSet::default(); - } + static EMPTY_SET: SyncLazy> = + SyncLazy::new(FxHashSet::default); &EMPTY_SET }; // In case typeck does end up being called, don't ICE in case there were name resolution errors @@ -300,13 +301,43 @@ } crate fn create_resolver<'a>( + externs: config::Externs, queries: &Queries<'a>, sess: &Session, ) -> Rc> { let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek(); let resolver = resolver.clone(); - crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate) + let resolver = crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate); + + // FIXME: somehow rustdoc is still missing crates even though we loaded all + // the known necessary crates. Load them all unconditionally until we find a way to fix this. + // DO NOT REMOVE THIS without first testing on the reproducer in + // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb + let extern_names: Vec = externs + .iter() + .filter(|(_, entry)| entry.add_prelude) + .map(|(name, _)| name) + .cloned() + .collect(); + resolver.borrow_mut().access(|resolver| { + sess.time("load_extern_crates", || { + for extern_name in &extern_names { + debug!("loading extern crate {}", extern_name); + if let Err(()) = resolver + .resolve_str_path_error( + DUMMY_SP, + extern_name, + TypeNS, + LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(), + ) { + warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name) + } + } + }); + }); + + resolver } crate fn run_global_ctxt( @@ -330,18 +361,14 @@ // NOTE: This is copy/pasted from typeck/lib.rs and should be kept in sync with those changes. tcx.sess.time("item_types_checking", || { - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_item_types(module); - } + tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); tcx.sess.abort_if_errors(); tcx.sess.time("missing_docs", || { rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); }); tcx.sess.time("check_mod_attrs", || { - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_attrs(module); - } + tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module)) }); rustc_passes::stability::check_unused_or_stable_features(tcx); diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/docfs.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/docfs.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/docfs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/docfs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ use std::fs; use std::io; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::string::ToString; use std::sync::mpsc::Sender; @@ -55,17 +55,17 @@ fs::create_dir_all(path) } - crate fn write(&self, path: P, contents: C) -> Result<(), E> + crate fn write( + &self, + path: PathBuf, + contents: impl 'static + Send + AsRef<[u8]>, + ) -> Result<(), E> where - P: AsRef, - C: AsRef<[u8]>, E: PathError, { if !self.sync_only && cfg!(windows) { // A possible future enhancement after more detailed profiling would // be to create the file sync so errors are reported eagerly. - let path = path.as_ref().to_path_buf(); - let contents = contents.as_ref().to_vec(); let sender = self.errors.clone().expect("can't write after closing"); rayon::spawn(move || { fs::write(&path, contents).unwrap_or_else(|e| { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/doctest/tests.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/doctest/tests.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/doctest/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/doctest/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -52,7 +52,8 @@ fn make_test_no_crate_inject() { // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip // adding it anyway. - let opts = TestOptions { no_crate_inject: true, display_warnings: false, attrs: vec![] }; + let opts = + TestOptions { no_crate_inject: true, display_doctest_warnings: false, attrs: vec![] }; let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -215,10 +216,10 @@ } #[test] -fn make_test_display_warnings() { +fn make_test_display_doctest_warnings() { // If the user is asking to display doctest warnings, suppress the default `allow(unused)`. let mut opts = TestOptions::default(); - opts.display_warnings = true; + opts.display_doctest_warnings = true; let input = "assert_eq!(2+2, 4);"; let expected = "fn main() { assert_eq!(2+2, 4); diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/doctest.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/doctest.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/doctest.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/doctest.rs 2021-11-29 19:27:11.000000000 +0000 @@ -40,7 +40,7 @@ crate no_crate_inject: bool, /// Whether to emit compilation warnings when compiling doctests. Setting this will suppress /// the default `#![allow(unused)]`. - crate display_warnings: bool, + crate display_doctest_warnings: bool, /// Additional crate-level attributes to add to doctests. crate attrs: Vec, } @@ -72,8 +72,8 @@ maybe_sysroot: options.maybe_sysroot.clone(), search_paths: options.libs.clone(), crate_types, - lint_opts: if !options.display_warnings { lint_opts } else { vec![] }, - lint_cap: Some(options.lint_cap.clone().unwrap_or_else(|| lint::Forbid)), + lint_opts: if !options.display_doctest_warnings { lint_opts } else { vec![] }, + lint_cap: Some(options.lint_cap.unwrap_or_else(|| lint::Forbid)), cg: options.codegen_options.clone(), externs: options.externs.clone(), unstable_features: options.render_options.unstable_features, @@ -99,14 +99,14 @@ stderr: None, lint_caps, parse_sess_created: None, - register_lints: Some(Box::new(crate::lint::register_lints)), + register_lints: Some(box crate::lint::register_lints), override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), }; let test_args = options.test_args.clone(); - let display_warnings = options.display_warnings; + let display_doctest_warnings = options.display_doctest_warnings; let nocapture = options.nocapture; let externs = options.externs.clone(); let json_unused_externs = options.json_unused_externs; @@ -116,11 +116,10 @@ let mut global_ctxt = queries.global_ctxt()?.take(); let collector = global_ctxt.enter(|tcx| { - let krate = tcx.hir().krate(); let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); let mut opts = scrape_test_config(crate_attrs); - opts.display_warnings |= options.display_warnings; + opts.display_doctest_warnings |= options.display_doctest_warnings; let enable_per_target_ignores = options.enable_per_target_ignores; let mut collector = Collector::new( tcx.crate_name(LOCAL_CRATE), @@ -144,10 +143,8 @@ hir_collector.visit_testable( "".to_string(), CRATE_HIR_ID, - krate.module().inner, - |this| { - intravisit::walk_crate(this, krate); - }, + tcx.hir().span(CRATE_HIR_ID), + |this| tcx.hir().walk_toplevel_module(this), ); collector @@ -166,7 +163,7 @@ Err(ErrorReported) => return Err(ErrorReported), }; - run_tests(test_args, nocapture, display_warnings, tests); + run_tests(test_args, nocapture, display_doctest_warnings, tests); // Collect and warn about unused externs, but only if we've gotten // reports for each doctest @@ -212,14 +209,18 @@ crate fn run_tests( mut test_args: Vec, nocapture: bool, - display_warnings: bool, + display_doctest_warnings: bool, tests: Vec, ) { test_args.insert(0, "rustdoctest".to_string()); if nocapture { test_args.push("--nocapture".to_string()); } - test::test_main(&test_args, tests, Some(test::Options::new().display_output(display_warnings))); + test::test_main( + &test_args, + tests, + Some(test::Options::new().display_output(display_doctest_warnings)), + ); } // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. @@ -227,7 +228,7 @@ use rustc_ast_pretty::pprust; let mut opts = - TestOptions { no_crate_inject: false, display_warnings: false, attrs: Vec::new() }; + TestOptions { no_crate_inject: false, display_doctest_warnings: false, attrs: Vec::new() }; let test_attrs: Vec<_> = attrs .iter() @@ -507,7 +508,7 @@ let mut prog = String::new(); let mut supports_color = false; - if opts.attrs.is_empty() && !opts.display_warnings { + if opts.attrs.is_empty() && !opts.display_doctest_warnings { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in @@ -549,10 +550,10 @@ .supports_color(); let emitter = - EmitterWriter::new(Box::new(io::sink()), None, false, false, false, None, false); + EmitterWriter::new(box io::sink(), None, false, false, false, None, false); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser - let handler = Handler::with_emitter(false, None, Box::new(emitter)); + let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, sm); let mut found_main = false; @@ -852,6 +853,7 @@ fn generate_name(&self, line: usize, filename: &FileName) -> String { let mut item_path = self.names.join("::"); + item_path.retain(|c| c != ' '); if !item_path.is_empty() { item_path.push(' '); } @@ -962,7 +964,7 @@ no_run, test_type: test::TestType::DocTest, }, - testfn: test::DynTestFn(Box::new(move || { + testfn: test::DynTestFn(box move || { let report_unused_externs = |uext| { unused_externs.lock().unwrap().push(uext); }; @@ -1042,9 +1044,9 @@ } } - panic::resume_unwind(Box::new(())); + panic::resume_unwind(box ()); } - })), + }), }); } @@ -1121,7 +1123,7 @@ let ast_attrs = self.tcx.hir().attrs(hir_id); let mut attrs = Attributes::from_ast(ast_attrs, None); - if let Some(ref cfg) = ast_attrs.cfg(self.sess) { + if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/externalfiles.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/externalfiles.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/externalfiles.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/externalfiles.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground}; +use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; use crate::rustc_span::edition::Edition; use std::fs; use std::path::Path; @@ -39,14 +39,32 @@ let bc = format!( "{}{}", bc, - Markdown(&m_bc, &[], id_map, codes, edition, playground).into_string() + Markdown { + content: &m_bc, + links: &[], + ids: id_map, + error_codes: codes, + edition, + playground, + heading_offset: HeadingOffset::H2, + } + .into_string() ); let ac = load_external_files(after_content, diag)?; let m_ac = load_external_files(md_after_content, diag)?; let ac = format!( "{}{}", ac, - Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string() + Markdown { + content: &m_ac, + links: &[], + ids: id_map, + error_codes: codes, + edition, + playground, + heading_offset: HeadingOffset::H2, + } + .into_string() ); Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac }) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/fold.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/fold.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/fold.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/fold.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ crate fn strip_item(mut item: Item) -> Item { if !matches!(*item.kind, StrippedItem(..)) { - item.kind = Box::new(StrippedItem(item.kind)); + item.kind = box StrippedItem(item.kind); } item } @@ -69,10 +69,10 @@ /// don't override! fn fold_item_recur(&mut self, mut item: Item) -> Item { - item.kind = Box::new(match *item.kind { - StrippedItem(box i) => StrippedItem(Box::new(self.fold_inner_recur(i))), + item.kind = box match *item.kind { + StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)), _ => self.fold_inner_recur(*item.kind), - }); + }; item } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/formats/cache.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/formats/cache.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/formats/cache.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/formats/cache.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; -use crate::clean::{self, GetDefId, ItemId}; +use crate::clean::{self, GetDefId, ItemId, PrimitiveType}; use crate::config::RenderOptions; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; @@ -98,9 +98,6 @@ stripped_mod: bool, crate search_index: Vec, - crate deref_trait_did: Option, - crate deref_mut_trait_did: Option, - crate owned_box_did: Option, // In rare case where a structure is defined in one module but implemented // in another, if the implementing module is parsed before defining module, @@ -122,6 +119,8 @@ /// /// Links are indexed by the DefId of the item they document. crate intra_doc_links: FxHashMap>, + /// Cfg that have been hidden via #![doc(cfg_hide(...))] + crate hidden_cfg: FxHashSet, } /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. @@ -159,17 +158,16 @@ self.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module)); } - // Cache where all known primitives have their documentation located. - // - // Favor linking to as local extern as possible, so iterate all crates in - // reverse topological order. - for &e in krate.externs.iter().rev() { - for &(def_id, prim) in &e.primitives(tcx) { - self.primitive_locations.insert(prim, def_id); - } - } - for &(def_id, prim) in &krate.primitives { - self.primitive_locations.insert(prim, def_id); + // FIXME: avoid this clone (requires implementing Default manually) + self.primitive_locations = PrimitiveType::primitive_locations(tcx).clone(); + for (prim, &def_id) in &self.primitive_locations { + let crate_name = tcx.crate_name(def_id.krate); + // Recall that we only allow primitive modules to be at the root-level of the crate. + // If that restriction is ever lifted, this will have to include the relative paths instead. + self.external_paths.insert( + def_id, + (vec![crate_name.to_string(), prim.as_sym().to_string()], ItemType::Primitive), + ); } krate = CacheBuilder { tcx, cache: self }.fold_crate(krate); @@ -205,7 +203,9 @@ // masked crate then remove it completely. if let clean::ImplItem(ref i) = *item.kind { if self.cache.masked_crates.contains(&item.def_id.krate()) - || i.trait_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) + || i.trait_ + .as_ref() + .map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate)) || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) { return None; @@ -225,11 +225,11 @@ // Collect all the implementors of traits. if let clean::ImplItem(ref i) = *item.kind { - if let Some(did) = i.trait_.def_id() { + if let Some(trait_) = &i.trait_ { if i.blanket_impl.is_none() { self.cache .implementors - .entry(did) + .entry(trait_.def_id()) .or_default() .push(Impl { impl_item: item.clone() }); } @@ -404,12 +404,8 @@ } clean::DynTrait(ref bounds, _) | clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => { - if let Some(did) = bounds[0].trait_.def_id() { - self.cache.parent_stack.push(did); - true - } else { - false - } + self.cache.parent_stack.push(bounds[0].trait_.def_id()); + true } ref t => { let prim_did = t @@ -443,9 +439,7 @@ } clean::DynTrait(ref bounds, _) | clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => { - if let Some(did) = bounds[0].trait_.def_id() { - dids.insert(did); - } + dids.insert(bounds[0].trait_.def_id()); } ref t => { let did = t diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/formats/mod.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/formats/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/formats/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/formats/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,14 +7,12 @@ crate use renderer::{run_format, FormatRenderer}; use crate::clean; -use crate::clean::types::GetDefId; -use crate::formats::cache::Cache; /// Specifies whether rendering directly implemented trait items or ones from a certain Deref /// impl. crate enum AssocItemRender<'a> { All, - DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type, deref_mut_: bool }, + DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, } /// For different handling of associated items from the Deref target of a type rather than the type @@ -40,10 +38,6 @@ } crate fn trait_did(&self) -> Option { - self.inner_impl().trait_.def_id() - } - - crate fn trait_did_full(&self, cache: &Cache) -> Option { - self.inner_impl().trait_.def_id_full(cache) + self.inner_impl().trait_.as_ref().map(|t| t.def_id()) } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/format.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/format.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/format.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/format.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,9 +18,7 @@ use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_target::spec::abi::Abi; -use crate::clean::{ - self, utils::find_nearest_parent_module, ExternalCrate, GetDefId, ItemId, PrimitiveType, -}; +use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType}; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::render::cache::ExternalLocation; @@ -155,9 +153,23 @@ &'a self, cx: &'a Context<'tcx>, ) -> impl fmt::Display + 'a + Captures<'tcx> { - display_fn(move |f| match self.kind { - clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name), - clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => { + display_fn(move |f| match &self.kind { + clean::GenericParamDefKind::Lifetime { outlives } => { + write!(f, "{}", self.name)?; + + if !outlives.is_empty() { + f.write_str(": ")?; + for (i, lt) in outlives.iter().enumerate() { + if i != 0 { + f.write_str(" + ")?; + } + write!(f, "{}", lt.print())?; + } + } + + Ok(()) + } + clean::GenericParamDefKind::Type { bounds, default, .. } => { f.write_str(&*self.name.as_str())?; if !bounds.is_empty() { @@ -178,7 +190,7 @@ Ok(()) } - clean::GenericParamDefKind::Const { ref ty, ref default, .. } => { + clean::GenericParamDefKind::Const { ty, default, .. } => { if f.alternate() { write!(f, "const {}: {:#}", self.name, ty.print(cx))?; } else { @@ -256,7 +268,7 @@ 0 => String::new(), _ if f.alternate() => { format!( - "for<{:#}> ", + "for<{:#}> ", comma_sep(bound_params.iter().map(|lt| lt.print())) ) } @@ -495,7 +507,11 @@ if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] } } - if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private { + if !did.is_local() + && !cache.access_levels.is_public(did) + && !cache.document_private + && !cache.primitive_locations.values().any(|&id| id == did) + { return Err(HrefError::Private); } @@ -503,6 +519,7 @@ let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) { Some(&(ref fqp, shortty)) => (fqp, shortty, { let module_fqp = to_module_fqp(shortty, fqp); + debug!(?fqp, ?shortty, ?module_fqp); href_relative_parts(module_fqp, relative_to) }), None => { @@ -534,6 +551,7 @@ url_parts.insert(0, root); } } + debug!(?url_parts); let last = &fqp.last().unwrap()[..]; let filename; match shortty { @@ -728,19 +746,22 @@ use_absolute: bool, cx: &'cx Context<'_>, ) -> fmt::Result { - debug!("fmt_type(t = {:?})", t); + trace!("fmt_type(t = {:?})", t); match *t { clean::Generic(name) => write!(f, "{}", name), - clean::ResolvedPath { did, ref path, is_generic } => { + clean::ResolvedPath { did, ref path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. - resolved_path(f, did, path, is_generic, use_absolute, cx) + resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx) } clean::DynTrait(ref bounds, ref lt) => { f.write_str("dyn ")?; fmt::Display::fmt(&tybounds(bounds, lt, cx), f) } clean::Infer => write!(f, "_"), + clean::Primitive(clean::PrimitiveType::Never) => { + primitive_link(f, PrimitiveType::Never, "!", cx) + } clean::Primitive(prim) => primitive_link(f, prim, &*prim.as_sym().as_str(), cx), clean::BareFunction(ref decl) => { if f.alternate() { @@ -799,34 +820,22 @@ primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(n)), cx) } } - clean::Never => primitive_link(f, PrimitiveType::Never, "!", cx), clean::RawPointer(m, ref t) => { let m = match m { hir::Mutability::Mut => "mut", hir::Mutability::Not => "const", }; - match **t { - clean::Generic(_) | clean::ResolvedPath { is_generic: true, .. } => { - if f.alternate() { - primitive_link( - f, - clean::PrimitiveType::RawPointer, - &format!("*{} {:#}", m, t.print(cx)), - cx, - ) - } else { - primitive_link( - f, - clean::PrimitiveType::RawPointer, - &format!("*{} {}", m, t.print(cx)), - cx, - ) - } - } - _ => { - primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?; - fmt::Display::fmt(&t.print(cx), f) - } + + if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { + let text = if f.alternate() { + format!("*{} {:#}", m, t.print(cx)) + } else { + format!("*{} {}", m, t.print(cx)) + }; + primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx) + } else { + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?; + fmt::Display::fmt(&t.print(cx), f) } } clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { @@ -903,15 +912,10 @@ } } clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => { - let should_show_cast = match *trait_ { - box clean::ResolvedPath { ref path, .. } => { - !path.segments.is_empty() - && self_def_id - .zip(trait_.def_id()) - .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_) - } - _ => true, - }; + let should_show_cast = !trait_.segments.is_empty() + && self_def_id + .zip(Some(trait_.def_id())) + .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_); if f.alternate() { if should_show_cast { write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? @@ -925,36 +929,31 @@ write!(f, "{}::", self_type.print(cx))? } }; - match *trait_ { - // It's pretty unsightly to look at `
::C` in output, and - // we've got hyperlinking on our side, so try to avoid longer - // notation as much as possible by making `C` a hyperlink to trait - // `B` to disambiguate. - // - // FIXME: this is still a lossy conversion and there should probably - // be a better way of representing this in general? Most of - // the ugliness comes from inlining across crates where - // everything comes in as a fully resolved QPath (hard to - // look at). - box clean::ResolvedPath { did, .. } => { - match href(did, cx) { - Ok((ref url, _, ref path)) if !f.alternate() => { - write!( - f, - "::C` in output, and + // we've got hyperlinking on our side, so try to avoid longer + // notation as much as possible by making `C` a hyperlink to trait + // `B` to disambiguate. + // + // FIXME: this is still a lossy conversion and there should probably + // be a better way of representing this in general? Most of + // the ugliness comes from inlining across crates where + // everything comes in as a fully resolved QPath (hard to + // look at). + match href(trait_.def_id(), cx) { + Ok((ref url, _, ref path)) if !f.alternate() => { + write!( + f, + "{name}", - url = url, - shortty = ItemType::AssocType, - name = name, - path = path.join("::") - )?; - } - _ => write!(f, "{}", name)?, - } - Ok(()) + url = url, + shortty = ItemType::AssocType, + name = name, + path = path.join("::") + )?; } - _ => write!(f, "{}", name), + _ => write!(f, "{}", name)?, } + Ok(()) } } } @@ -968,6 +967,15 @@ } } +impl clean::Path { + crate fn print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cx: &'a Context<'tcx>, + ) -> impl fmt::Display + 'b + Captures<'tcx> { + display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + } +} + impl clean::Impl { crate fn print<'a, 'tcx: 'a>( &'a self, @@ -1048,7 +1056,11 @@ ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { if !self.generic_params.is_empty() { - write!(f, "for<{}> ", comma_sep(self.generic_params.iter().map(|g| g.print(cx)))) + write!( + f, + "for<{}> ", + comma_sep(self.generic_params.iter().map(|g| g.print(cx))) + ) } else { Ok(()) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/sample.html rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/sample.html --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/sample.html 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/sample.html 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ use std::path::{Path, PathBuf}; #[cfg(target_os = "linux")] -fn main() { +fn main() -> () { let foo = true && false || true; let _: *const () = 0; let _ = &foo; @@ -27,11 +27,11 @@ let mut s = String::new(); match &s { - ref mut x => {} + ref mut x => {} } } macro_rules! bar { - ($foo:tt) => {}; + ($foo:tt) => {}; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/sample.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/sample.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/sample.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/sample.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; #[cfg(target_os = "linux")] -fn main() { +fn main() -> () { let foo = true && false || true; let _: *const () = 0; let _ = &foo; diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/union.html rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/union.html --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/union.html 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/union.html 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +union Foo { + i: i8, + u: i8, +} + +fn main() { + let union = 0; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/union.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/union.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/union.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/fixtures/union.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +union Foo { + i: i8, + u: i8, +} + +fn main() { + let union = 0; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/tests.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/tests.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -54,3 +54,13 @@ expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner()); }); } + +#[test] +fn test_union_highlighting() { + create_default_session_globals_then(|| { + let src = include_str!("fixtures/union.rs"); + let mut html = Buffer::new(); + write_code(&mut html, src, Edition::Edition2018, None); + expect_file!["fixtures/union.html"].assert_eq(&html.into_inner()); + }); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/highlight.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/highlight.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,11 +5,12 @@ //! //! Use the `render_with_highlighting` to highlight some rust code. +use crate::clean::PrimitiveType; use crate::html::escape::Escape; use crate::html::render::Context; +use std::collections::VecDeque; use std::fmt::{Display, Write}; -use std::iter::Peekable; use rustc_lexer::{LiteralKind, TokenKind}; use rustc_span::edition::Edition; @@ -200,10 +201,57 @@ }) } +/// This iterator comes from the same idea than "Peekable" except that it allows to "peek" more than +/// just the next item by using `peek_next`. The `peek` method always returns the next item after +/// the current one whereas `peek_next` will return the next item after the last one peeked. +/// +/// You can use both `peek` and `peek_next` at the same time without problem. +struct PeekIter<'a> { + stored: VecDeque<(TokenKind, &'a str)>, + /// This position is reinitialized when using `next`. It is used in `peek_next`. + peek_pos: usize, + iter: TokenIter<'a>, +} + +impl PeekIter<'a> { + fn new(iter: TokenIter<'a>) -> Self { + Self { stored: VecDeque::new(), peek_pos: 0, iter } + } + /// Returns the next item after the current one. It doesn't interfer with `peek_next` output. + fn peek(&mut self) -> Option<&(TokenKind, &'a str)> { + if self.stored.is_empty() { + if let Some(next) = self.iter.next() { + self.stored.push_back(next); + } + } + self.stored.front() + } + /// Returns the next item after the last one peeked. It doesn't interfer with `peek` output. + fn peek_next(&mut self) -> Option<&(TokenKind, &'a str)> { + self.peek_pos += 1; + if self.peek_pos - 1 < self.stored.len() { + self.stored.get(self.peek_pos - 1) + } else if let Some(next) = self.iter.next() { + self.stored.push_back(next); + self.stored.back() + } else { + None + } + } +} + +impl Iterator for PeekIter<'a> { + type Item = (TokenKind, &'a str); + fn next(&mut self) -> Option { + self.peek_pos = 0; + if let Some(first) = self.stored.pop_front() { Some(first) } else { self.iter.next() } + } +} + /// Processes program tokens, classifying strings of text by highlighting /// category (`Class`). struct Classifier<'a> { - tokens: Peekable>, + tokens: PeekIter<'a>, in_attribute: bool, in_macro: bool, in_macro_nonterminal: bool, @@ -217,7 +265,7 @@ /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondance_map`. fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> { - let tokens = TokenIter { src }.peekable(); + let tokens = PeekIter::new(TokenIter { src }); Classifier { tokens, in_attribute: false, @@ -368,7 +416,7 @@ // Assume that '&' or '*' is the reference or dereference operator // or a reference or pointer type. Unless, of course, it looks like // a logical and or a multiplication operator: `&&` or `* `. - TokenKind::Star => match lookahead { + TokenKind::Star => match self.peek() { Some(TokenKind::Whitespace) => Class::Op, _ => Class::RefKeyWord, }, @@ -387,7 +435,27 @@ _ => Class::RefKeyWord, }, - // Operators. + // These can either be operators, or arrows. + TokenKind::Eq => match lookahead { + Some(TokenKind::Eq) => { + self.next(); + sink(Highlight::Token { text: "==", class: Some(Class::Op) }); + return; + } + Some(TokenKind::Gt) => { + self.next(); + sink(Highlight::Token { text: "=>", class: None }); + return; + } + _ => Class::Op, + }, + TokenKind::Minus if lookahead == Some(TokenKind::Gt) => { + self.next(); + sink(Highlight::Token { text: "->", class: None }); + return; + } + + // Other operators. TokenKind::Minus | TokenKind::Plus | TokenKind::Or @@ -395,7 +463,6 @@ | TokenKind::Caret | TokenKind::Percent | TokenKind::Bang - | TokenKind::Eq | TokenKind::Lt | TokenKind::Gt => Class::Op, @@ -479,6 +546,9 @@ None => match text { "Option" | "Result" => Class::PreludeTy, "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + // "union" is a weak keyword and is only considered as a keyword when declaring + // a union type. + "union" if self.check_if_is_union_keyword() => Class::KeyWord, _ if self.in_macro_nonterminal => { self.in_macro_nonterminal = false; Class::MacroNonTerminal @@ -499,7 +569,17 @@ } fn peek(&mut self) -> Option { - self.tokens.peek().map(|(toke_kind, _text)| *toke_kind) + self.tokens.peek().map(|(token_kind, _text)| *token_kind) + } + + fn check_if_is_union_keyword(&mut self) -> bool { + while let Some(kind) = self.tokens.peek_next().map(|(token_kind, _text)| token_kind) { + if *kind == TokenKind::Whitespace { + continue; + } + return *kind == TokenKind::Ident; + } + false } } @@ -584,6 +664,13 @@ .ok() .map(|(url, _, _)| url) } + LinkFromSrc::Primitive(prim) => format::href_with_root_path( + PrimitiveType::primitive_locations(context.tcx())[&prim], + context, + Some(context_info.root_path), + ) + .ok() + .map(|(url, _, _)| url), } }) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/markdown/tests.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/markdown/tests.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/markdown/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/markdown/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ -use super::{plain_text_summary, short_markdown_summary}; -use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; +use super::{find_testable_code, plain_text_summary, short_markdown_summary}; +use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; #[test] @@ -147,33 +147,41 @@ fn test_header() { fn t(input: &str, expect: &str) { let mut map = IdMap::new(); - let output = - Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); + let output = Markdown { + content: input, + links: &[], + ids: &mut map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &None, + heading_offset: HeadingOffset::H2, + } + .into_string(); assert_eq!(output, expect, "original: {}", input); } t( "# Foo bar", - "

Foo bar

", + "

Foo bar

", ); t( "## Foo-bar_baz qux", - "

\ - Foo-bar_baz qux

", + "

\ + Foo-bar_baz qux

", ); t( "### **Foo** *bar* baz!?!& -_qux_-%", - "

\ + "

\ Foo \ bar baz!?!& -qux-%\ -

", + ", ); t( "#### **Foo?** & \\*bar?!* _`baz`_ ⤠#qux", - "

\ + "

\ Foo? & *bar?!* \ baz ⤠#qux\ -
", + ", ); } @@ -181,40 +189,48 @@ fn test_header_ids_multiple_blocks() { let mut map = IdMap::new(); fn t(map: &mut IdMap, input: &str, expect: &str) { - let output = - Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); + let output = Markdown { + content: input, + links: &[], + ids: map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &None, + heading_offset: HeadingOffset::H2, + } + .into_string(); assert_eq!(output, expect, "original: {}", input); } t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Panics", - "

Panics

", + "

Panics

", ); t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Main", - "

Main

", + "

Main

", ); t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Panics", - "

Panics

", + "

Panics

", ); } @@ -300,3 +316,25 @@ t("Struct<'a, T>", "

Struct<’a, T>

\n"); t("Struct
", "

Struct<br>

\n"); } + +#[test] +fn test_find_testable_code_line() { + fn t(input: &str, expect: &[usize]) { + impl crate::doctest::Tester for Vec { + fn add_test(&mut self, _test: String, _config: LangString, line: usize) { + self.push(line); + } + } + let mut lines = Vec::::new(); + find_testable_code(input, &mut lines, ErrorCodes::No, false, None); + assert_eq!(lines, expect); + } + + t("", &[]); + t("```rust\n```", &[1]); + t(" ```rust\n```", &[1]); + t("\n```rust\n```", &[2]); + t("\n ```rust\n```", &[2]); + t("```rust\n```\n```rust\n```", &[1, 3]); + t("```rust\n```\n ```rust\n```", &[1, 3]); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/markdown.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/markdown.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/markdown.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/markdown.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,11 +8,19 @@ //! extern crate rustc_span; //! //! use rustc_span::edition::Edition; -//! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes}; +//! use rustdoc::html::markdown::{HeadingOffset, IdMap, Markdown, ErrorCodes}; //! //! let s = "My *markdown* _text_"; //! let mut id_map = IdMap::new(); -//! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None); +//! let md = Markdown { +//! content: s, +//! links: &[], +//! ids: &mut id_map, +//! error_codes: ErrorCodes::Yes, +//! edition: Edition::Edition2015, +//! playground: &None, +//! heading_offset: HeadingOffset::H2, +//! }; //! let html = md.into_string(); //! // ... something using html //! ``` @@ -47,8 +55,10 @@ #[cfg(test)] mod tests; +const MAX_HEADER_LEVEL: u32 = 6; + /// Options for rendering Markdown in the main body of documentation. -pub(crate) fn opts() -> Options { +pub(crate) fn main_body_opts() -> Options { Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH @@ -56,25 +66,42 @@ | Options::ENABLE_SMART_PUNCTUATION } -/// A subset of [`opts()`] used for rendering summaries. +/// Options for rendering Markdown in summaries (e.g., in search results). pub(crate) fn summary_opts() -> Options { - Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION | Options::ENABLE_TABLES + Options::ENABLE_TABLES + | Options::ENABLE_FOOTNOTES + | Options::ENABLE_STRIKETHROUGH + | Options::ENABLE_TASKLISTS + | Options::ENABLE_SMART_PUNCTUATION +} + +#[derive(Debug, Clone, Copy)] +pub enum HeadingOffset { + H1 = 0, + H2, + H3, + H4, + H5, + H6, } /// When `to_string` is called, this struct will emit the HTML corresponding to /// the rendered version of the contained markdown string. -pub struct Markdown<'a>( - pub &'a str, +pub struct Markdown<'a> { + pub content: &'a str, /// A list of link replacements. - pub &'a [RenderedLink], + pub links: &'a [RenderedLink], /// The current list of used header IDs. - pub &'a mut IdMap, + pub ids: &'a mut IdMap, /// Whether to allow the use of explicit error codes in doctest lang strings. - pub ErrorCodes, + pub error_codes: ErrorCodes, /// Default edition to use when parsing doctests (to add a `fn main`). - pub Edition, - pub &'a Option, -); + pub edition: Edition, + pub playground: &'a Option, + /// Offset at which we render headings. + /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `

`. + pub heading_offset: HeadingOffset, +} /// A tuple struct like `Markdown` that renders the markdown with a table of contents. crate struct MarkdownWithToc<'a>( crate &'a str, @@ -441,6 +468,42 @@ } } +/// Wrap HTML tables into `
` to prevent having the doc blocks width being too big. +struct TableWrapper<'a, I: Iterator>> { + inner: I, + stored_events: VecDeque>, +} + +impl<'a, I: Iterator>> TableWrapper<'a, I> { + fn new(iter: I) -> Self { + Self { inner: iter, stored_events: VecDeque::new() } + } +} + +impl<'a, I: Iterator>> Iterator for TableWrapper<'a, I> { + type Item = Event<'a>; + + fn next(&mut self) -> Option { + if let Some(first) = self.stored_events.pop_front() { + return Some(first); + } + + let event = self.inner.next()?; + + Some(match event { + Event::Start(Tag::Table(t)) => { + self.stored_events.push_back(Event::Start(Tag::Table(t))); + Event::Html(CowStr::Borrowed("
")) + } + Event::End(Tag::Table(t)) => { + self.stored_events.push_back(Event::Html(CowStr::Borrowed("
"))); + Event::End(Tag::Table(t)) + } + e => e, + }) + } +} + type SpannedEvent<'a> = (Event<'a>, Range); /// Make headings links with anchor IDs and build up TOC. @@ -449,11 +512,17 @@ toc: Option<&'b mut TocBuilder>, buf: VecDeque>, id_map: &'ids mut IdMap, + heading_offset: HeadingOffset, } impl<'a, 'b, 'ids, I> HeadingLinks<'a, 'b, 'ids, I> { - fn new(iter: I, toc: Option<&'b mut TocBuilder>, ids: &'ids mut IdMap) -> Self { - HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids } + fn new( + iter: I, + toc: Option<&'b mut TocBuilder>, + ids: &'ids mut IdMap, + heading_offset: HeadingOffset, + ) -> Self { + HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids, heading_offset } } } @@ -490,6 +559,7 @@ self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0)); } + let level = std::cmp::min(level + (self.heading_offset as u32), MAX_HEADER_LEVEL); self.buf.push_back((Event::Html(format!("", level).into()), 0..0)); let start_tags = format!( @@ -692,6 +762,12 @@ .join("\n"); nb_lines += doc[prev_offset..offset.start].lines().count(); + // If there are characters between the preceding line ending and + // this code block, `str::lines` will return an additional line, + // which we subtract here. + if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with('\n') { + nb_lines -= 1; + } let line = tests.get_line() + nb_lines + 1; tests.add_test(text, block_info, line); prev_offset = offset.start; @@ -959,7 +1035,15 @@ impl Markdown<'_> { pub fn into_string(self) -> String { - let Markdown(md, links, mut ids, codes, edition, playground) = self; + let Markdown { + content: md, + links, + mut ids, + error_codes: codes, + edition, + playground, + heading_offset, + } = self; // This is actually common enough to special-case if md.is_empty() { @@ -975,14 +1059,15 @@ } }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); + let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer)); let p = p.into_offset_iter(); let mut s = String::with_capacity(md.len() * 3 / 2); - let p = HeadingLinks::new(p, None, &mut ids); + let p = HeadingLinks::new(p, None, &mut ids, heading_offset); let p = Footnotes::new(p); let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); + let p = TableWrapper::new(p); let p = CodeBlocks::new(p, codes, edition, playground); html::push_html(&mut s, p); @@ -994,16 +1079,17 @@ crate fn into_string(self) -> String { let MarkdownWithToc(md, mut ids, codes, edition, playground) = self; - let p = Parser::new_ext(md, opts()).into_offset_iter(); + let p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); let mut s = String::with_capacity(md.len() * 3 / 2); let mut toc = TocBuilder::new(); { - let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); + let p = HeadingLinks::new(p, Some(&mut toc), &mut ids, HeadingOffset::H1); let p = Footnotes::new(p); - let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground); + let p = TableWrapper::new(p.map(|(ev, _)| ev)); + let p = CodeBlocks::new(p, codes, edition, playground); html::push_html(&mut s, p); } @@ -1019,7 +1105,7 @@ if md.is_empty() { return String::new(); } - let p = Parser::new_ext(md, opts()).into_offset_iter(); + let p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); // Treat inline HTML as plain text. let p = p.map(|event| match event.0 { @@ -1029,9 +1115,10 @@ let mut s = String::with_capacity(md.len() * 3 / 2); - let p = HeadingLinks::new(p, None, &mut ids); + let p = HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1); let p = Footnotes::new(p); - let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground); + let p = TableWrapper::new(p.map(|(ev, _)| ev)); + let p = CodeBlocks::new(p, codes, edition, playground); html::push_html(&mut s, p); s @@ -1093,7 +1180,7 @@ } }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); + let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)); let mut p = LinkReplacer::new(p, link_names); let mut buf = HtmlWithLimit::new(length_limit); @@ -1240,12 +1327,13 @@ }); None }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)).into_offset_iter(); + let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push)) + .into_offset_iter(); // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. let mut ids = IdMap::new(); - let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids)); + let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1)); for ev in iter { if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 { @@ -1278,7 +1366,7 @@ return code_blocks; } - let mut p = Parser::new_ext(md, opts()).into_offset_iter(); + let mut p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); while let Some((event, offset)) = p.next() { if let Event::Start(Tag::CodeBlock(syntax)) = event { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/cache.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/cache.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/cache.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/cache.rs 2021-11-29 19:27:11.000000000 +0000 @@ -226,16 +226,13 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { match *clean_type { clean::ResolvedPath { ref path, .. } => { - let segments = &path.segments; - let path_segment = segments.iter().last().unwrap_or_else(|| { - panic!( - "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path", - clean_type, accept_generic - ) - }); + let path_segment = path.segments.last().unwrap(); Some(path_segment.name) } - clean::DynTrait(ref bounds, _) => get_index_type_name(&bounds[0].trait_, accept_generic), + clean::DynTrait(ref bounds, _) => { + let path = &bounds[0].trait_; + Some(path.segments.last().unwrap().name) + } clean::Generic(s) if accept_generic => Some(s), clean::Primitive(ref p) => Some(p.as_sym()), clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), @@ -244,7 +241,6 @@ | clean::Tuple(_) | clean::Slice(_) | clean::Array(_, _) - | clean::Never | clean::RawPointer(_, _) | clean::QPath { .. } | clean::Infer @@ -325,7 +321,8 @@ } if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { for bound in bound.get_bounds().unwrap_or(&[]) { - if let Some(ty) = bound.get_trait_type() { + if let Some(path) = bound.get_trait_path() { + let ty = Type::ResolvedPath { did: path.def_id(), path }; let adds = get_real_types(generics, &ty, tcx, recurse + 1, res); nb_added += adds; if adds == 0 && !ty.is_full_generic() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/context.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/context.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/context.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/context.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ use std::cell::RefCell; use std::collections::BTreeMap; -use std::error::Error as StdError; use std::io; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -16,6 +15,7 @@ use super::cache::{build_index, ExternalLocation}; use super::print_item::{full_path, item_path, print_item}; +use super::templates; use super::write_shared::write_shared; use super::{ collect_spans_and_sources, print_sidebar, settings, AllTypes, LinkFromSrc, NameDoc, StylePath, @@ -33,7 +33,6 @@ use crate::html::escape::Escape; use crate::html::format::Buffer; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; -use crate::html::static_files::PAGE; use crate::html::{layout, sources}; /// Major driving force in all rustdoc rendering. This contains information @@ -69,7 +68,7 @@ } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Context<'_>, 104); /// Shared mutable state used in [`Context`] and elsewhere. @@ -225,7 +224,7 @@ &self.shared.layout, &page, |buf: &mut _| print_sidebar(self, it, buf), - |buf: &mut _| print_item(self, it, buf, &page), + |buf: &mut _| print_item(self, &self.shared.templates, it, buf, &page), &self.shared.style_files, ) } else { @@ -416,12 +415,7 @@ }; let mut issue_tracker_base_url = None; let mut include_sources = true; - - let mut templates = tera::Tera::default(); - templates.add_raw_template("page.html", PAGE).map_err(|e| Error { - file: "page.html".into(), - error: format!("{}: {}", e, e.source().map(|e| e.to_string()).unwrap_or_default()), - })?; + let templates = templates::load()?; // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML @@ -574,7 +568,7 @@ |buf: &mut Buffer| all.print(buf), &self.shared.style_files, ); - self.shared.fs.write(final_file, v.as_bytes())?; + self.shared.fs.write(final_file, v)?; // Generating settings page. page.title = "Rustdoc settings"; @@ -596,14 +590,14 @@ )?, &style_files, ); - self.shared.fs.write(&settings_file, v.as_bytes())?; + self.shared.fs.write(settings_file, v)?; if let Some(ref redirections) = self.shared.redirections { if !redirections.borrow().is_empty() { let redirect_map_path = self.dst.join(&*crate_name.as_str()).join("redirect-map.json"); let paths = serde_json::to_string(&*redirections.borrow()).unwrap(); self.shared.ensure_dir(&self.dst.join(&*crate_name.as_str()))?; - self.shared.fs.write(&redirect_map_path, paths.as_bytes())?; + self.shared.fs.write(redirect_map_path, paths)?; } } @@ -641,7 +635,7 @@ if !buf.is_empty() { self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join("index.html"); - scx.fs.write(&joint_dst, buf.as_bytes())?; + scx.fs.write(joint_dst, buf)?; } // Render sidebar-items.js used throughout this module. @@ -653,7 +647,7 @@ let items = self.build_sidebar_items(module); let js_dst = self.dst.join("sidebar-items.js"); let v = format!("initSidebarItems({});", serde_json::to_string(&items).unwrap()); - scx.fs.write(&js_dst, &v)?; + scx.fs.write(js_dst, v)?; } Ok(()) } @@ -687,7 +681,7 @@ let file_name = &item_path(item_type, &name.as_str()); self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join(file_name); - self.shared.fs.write(&joint_dst, buf.as_bytes())?; + self.shared.fs.write(joint_dst, buf)?; if !self.render_redirect_pages { self.shared.all.borrow_mut().append(full_path(self, &item), &item_type); @@ -705,7 +699,7 @@ } else { let v = layout::redirect(file_name); let redir_dst = self.dst.join(redir_name); - self.shared.fs.write(&redir_dst, v.as_bytes())?; + self.shared.fs.write(redir_dst, v)?; } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/mod.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,6 +31,7 @@ mod context; mod print_item; mod span_map; +mod templates; mod write_shared; crate use context::*; @@ -51,6 +52,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::Mutability; use rustc_middle::middle::stability; +use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{kw, sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; @@ -66,7 +68,7 @@ href, print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace, }; -use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine}; /// A pair of name and its optional document. crate type NameDoc = (String, Option); @@ -224,7 +226,6 @@ opaque_tys: FxHashSet, statics: FxHashSet, constants: FxHashSet, - keywords: FxHashSet, attributes: FxHashSet, derives: FxHashSet, trait_aliases: FxHashSet, @@ -245,7 +246,6 @@ opaque_tys: new_set(100), statics: new_set(100), constants: new_set(100), - keywords: new_set(100), attributes: new_set(100), derives: new_set(100), trait_aliases: new_set(100), @@ -471,32 +471,45 @@ )) } -fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option<&clean::Item>) { +fn document( + w: &mut Buffer, + cx: &Context<'_>, + item: &clean::Item, + parent: Option<&clean::Item>, + heading_offset: HeadingOffset, +) { if let Some(ref name) = item.name { info!("Documenting {}", name); } document_item_info(w, cx, item, parent); if parent.is_none() { - document_full_collapsible(w, item, cx); + document_full_collapsible(w, item, cx, heading_offset); } else { - document_full(w, item, cx); + document_full(w, item, cx, heading_offset); } } /// Render md_text as markdown. -fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec) { +fn render_markdown( + w: &mut Buffer, + cx: &Context<'_>, + md_text: &str, + links: Vec, + heading_offset: HeadingOffset, +) { let mut ids = cx.id_map.borrow_mut(); write!( w, "
{}
", - Markdown( - md_text, - &links, - &mut ids, - cx.shared.codes, - cx.shared.edition(), - &cx.shared.playground - ) + Markdown { + content: md_text, + links: &links, + ids: &mut ids, + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + heading_offset, + } .into_string() ) } @@ -532,15 +545,31 @@ } } -fn document_full_collapsible(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) { - document_full_inner(w, item, cx, true); +fn document_full_collapsible( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + heading_offset: HeadingOffset, +) { + document_full_inner(w, item, cx, true, heading_offset); } -fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) { - document_full_inner(w, item, cx, false); +fn document_full( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + heading_offset: HeadingOffset, +) { + document_full_inner(w, item, cx, false, heading_offset); } -fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_collapsible: bool) { +fn document_full_inner( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + is_collapsible: bool, + heading_offset: HeadingOffset, +) { if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) { debug!("Doc block: =====\n{}\n=====", s); if is_collapsible { @@ -550,10 +579,10 @@ Expand description\ ", ); - render_markdown(w, cx, &s, item.links(cx)); + render_markdown(w, cx, &s, item.links(cx), heading_offset); w.write_str(""); } else { - render_markdown(w, cx, &s, item.links(cx)); + render_markdown(w, cx, &s, item.links(cx), heading_offset); } } } @@ -600,14 +629,14 @@ let mut extra_info = vec![]; let error_codes = cx.shared.codes; - if let Some(Deprecation { note, since, is_since_rustc_version, suggestion: _ }) = + if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) = item.deprecation(cx.tcx()) { // We display deprecation messages for #[deprecated] and #[rustc_deprecated] // but only display the future-deprecation messages for #[rustc_deprecated]. let mut message = if let Some(since) = since { let since = &since.as_str(); - if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) { + if !stability::deprecation_in_effect(&depr) { if *since == "TBD" { String::from("Deprecating in a future Rust version") } else { @@ -688,18 +717,12 @@ // Render the list of items inside one of the sections "Trait Implementations", // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages). -fn render_impls( - cx: &Context<'_>, - w: &mut Buffer, - traits: &[&&Impl], - containing_item: &clean::Item, -) { - let cache = cx.cache(); +fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_item: &clean::Item) { let tcx = cx.tcx(); - let mut impls = traits + let mut rendered_impls = impls .iter() .map(|i| { - let did = i.trait_did_full(cache).unwrap(); + let did = i.trait_did().unwrap(); let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods); let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() }; @@ -723,8 +746,8 @@ buffer.into_inner() }) .collect::>(); - impls.sort(); - w.write_str(&impls.join("")); + rendered_impls.sort(); + w.write_str(&rendered_impls.join("")); } fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String { @@ -1069,13 +1092,11 @@ return; } if !traits.is_empty() { - let deref_impl = traits - .iter() - .find(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did); + let deref_impl = + traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait()); if let Some(impl_) = deref_impl { - let has_deref_mut = traits - .iter() - .any(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_mut_trait_did); + let has_deref_mut = + traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait()); render_deref_methods(w, cx, impl_, containing_item, has_deref_mut); } let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = @@ -1165,7 +1186,7 @@ } } -fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bool { +fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool { let self_type_opt = match *item.kind { clean::MethodItem(ref method, _) => method.decl.self_type(), clean::TyMethodItem(ref method) => method.decl.self_type(), @@ -1179,7 +1200,7 @@ (mutability == Mutability::Mut, false, false) } SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => { - (false, Some(did) == cache.owned_box_did, false) + (false, Some(did) == tcx.lang_items().owned_box(), false) } SelfTy::SelfValue => (false, false, true), _ => (false, false, false), @@ -1193,45 +1214,39 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { let mut out = Buffer::html(); - let mut trait_ = String::new(); if let Some(did) = decl.output.def_id_full(cx.cache()) { if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); - if impl_.trait_.def_id().map_or(false, |d| { - cx.cache().traits.get(&d).map(|t| t.is_notable).unwrap_or(false) - }) { - if out.is_empty() { - write!( - &mut out, - "
Notable traits for {}
\ - ", - impl_.for_.print(cx) - ); - trait_.push_str(&impl_.for_.print(cx).to_string()); - } + if let Some(trait_) = &impl_.trait_ { + let trait_did = trait_.def_id(); - //use the "where" class here to make it small - write!( - &mut out, - "{}", - impl_.print(false, cx) - ); - let t_did = impl_.trait_.def_id_full(cx.cache()).unwrap(); - for it in &impl_.items { - if let clean::TypedefItem(ref tydef, _) = *it.kind { - out.push_str(" "); - assoc_type( + if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable) { + if out.is_empty() { + write!( &mut out, - it, - &[], - Some(&tydef.type_), - AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()), - "", - cx, + "
Notable traits for {}
\ + ", + impl_.for_.print(cx) ); - out.push_str(";
"); + } + + //use the "where" class here to make it small + write!( + &mut out, + "{}", + impl_.print(false, cx) + ); + for it in &impl_.items { + if let clean::TypedefItem(ref tydef, _) = *it.kind { + out.push_str(" "); + let empty_set = FxHashSet::default(); + let src_link = + AssocItemLink::GotoSource(trait_did.into(), &empty_set); + assoc_type(&mut out, it, &[], Some(&tydef.type_), src_link, "", cx); + out.push_str(";"); + } } } } @@ -1274,7 +1289,7 @@ ) { let cache = cx.cache(); let traits = &cache.traits; - let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); + let trait_ = i.trait_did().map(|did| &traits[&did]); let mut close_tags = String::new(); // For trait implementations, the `interesting` output contains all methods that have doc @@ -1302,7 +1317,7 @@ && match render_mode { RenderMode::Normal => true, RenderMode::ForDeref { mut_: deref_mut_ } => { - should_render_item(&item, deref_mut_, cx.cache()) + should_render_item(&item, deref_mut_, cx.tcx()) } }; @@ -1322,7 +1337,7 @@ // because impls can't have a stability. if item.doc_value().is_some() { document_item_info(&mut info_buffer, cx, it, Some(parent)); - document_full(&mut doc_buffer, item, cx); + document_full(&mut doc_buffer, item, cx, HeadingOffset::H5); short_documented = false; } else { // In case the item isn't documented, @@ -1340,7 +1355,7 @@ } else { document_item_info(&mut info_buffer, cx, item, Some(parent)); if rendering_params.show_def_docs { - document_full(&mut doc_buffer, item, cx); + document_full(&mut doc_buffer, item, cx, HeadingOffset::H5); short_documented = false; } } @@ -1504,7 +1519,7 @@ if i.items.iter().any(|m| m.name == n) { continue; } - let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap(); + let did = i.trait_.as_ref().unwrap().def_id(); let provided_methods = i.provided_trait_methods(cx.tcx()); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods); @@ -1574,14 +1589,15 @@ write!( w, "
{}
", - Markdown( - &*dox, - &i.impl_item.links(cx), - &mut ids, - cx.shared.codes, - cx.shared.edition(), - &cx.shared.playground - ) + Markdown { + content: &*dox, + links: &i.impl_item.links(cx), + ids: &mut ids, + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + heading_offset: HeadingOffset::H4 + } .into_string() ); } @@ -1795,23 +1811,53 @@ format!("{}-{}", url, add) } +struct SidebarLink { + name: Symbol, + url: String, +} + +impl fmt::Display for SidebarLink { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.url, self.name) + } +} + +impl PartialEq for SidebarLink { + fn eq(&self, other: &Self) -> bool { + self.url == other.url + } +} + +impl Eq for SidebarLink {} + +impl PartialOrd for SidebarLink { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for SidebarLink { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.url.cmp(&other.url) + } +} + fn get_methods( i: &clean::Impl, for_deref: bool, used_links: &mut FxHashSet, deref_mut: bool, - cache: &Cache, -) -> Vec { + tcx: TyCtxt<'_>, +) -> Vec { i.items .iter() .filter_map(|item| match item.name { - Some(ref name) if !name.is_empty() && item.is_method() => { - if !for_deref || should_render_item(item, deref_mut, cache) { - Some(format!( - "{}", - get_next_url(used_links, format!("method.{}", name)), - name - )) + Some(name) if !name.is_empty() && item.is_method() => { + if !for_deref || should_render_item(item, deref_mut, tcx) { + Some(SidebarLink { + name, + url: get_next_url(used_links, format!("method.{}", name)), + }) } else { None } @@ -1821,6 +1867,22 @@ .collect::>() } +fn get_associated_constants( + i: &clean::Impl, + used_links: &mut FxHashSet, +) -> Vec { + i.items + .iter() + .filter_map(|item| match item.name { + Some(name) if !name.is_empty() && item.is_associated_const() => Some(SidebarLink { + name, + url: get_next_url(used_links, format!("associatedconstant.{}", name)), + }), + _ => None, + }) + .collect::>() +} + // The point is to url encode any potential character from a type with genericity. fn small_url_encode(s: String) -> String { let mut st = String::new(); @@ -1865,31 +1927,48 @@ { let used_links_bor = &mut used_links; - let mut ret = v + let mut assoc_consts = v + .iter() + .flat_map(|i| get_associated_constants(i.inner_impl(), used_links_bor)) + .collect::>(); + if !assoc_consts.is_empty() { + // We want links' order to be reproducible so we don't use unstable sort. + assoc_consts.sort(); + + out.push_str( + "

\ + Associated Constants\ +

\ +
", + ); + for line in assoc_consts { + write!(out, "{}", line); + } + out.push_str("
"); + } + let mut methods = v .iter() .filter(|i| i.inner_impl().trait_.is_none()) - .flat_map(move |i| get_methods(i.inner_impl(), false, used_links_bor, false, cache)) + .flat_map(|i| get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx())) .collect::>(); - if !ret.is_empty() { + if !methods.is_empty() { // We want links' order to be reproducible so we don't use unstable sort. - ret.sort(); + methods.sort(); out.push_str( "

Methods

\
", ); - for line in ret { - out.push_str(&line); + for line in methods { + write!(out, "{}", line); } out.push_str("
"); } } if v.iter().any(|i| i.inner_impl().trait_.is_some()) { - if let Some(impl_) = v - .iter() - .filter(|i| i.inner_impl().trait_.is_some()) - .find(|i| i.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did) + if let Some(impl_) = + v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait()) { sidebar_deref_methods(cx, out, impl_, v); } @@ -1988,10 +2067,7 @@ } } } - let deref_mut = v - .iter() - .filter(|i| i.inner_impl().trait_.is_some()) - .any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did); + let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); let inner_impl = target .def_id_full(c) .or_else(|| { @@ -2004,7 +2080,9 @@ let mut ret = impls .iter() .filter(|i| i.inner_impl().trait_.is_none()) - .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c)) + .flat_map(|i| { + get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx.tcx()) + }) .collect::>(); if !ret.is_empty() { write!( @@ -2017,7 +2095,7 @@ ret.sort(); out.push_str("
"); for link in ret { - out.push_str(&link); + write!(out, "{}", link); } out.push_str("
"); } @@ -2056,10 +2134,10 @@ fn get_id_for_impl_on_foreign_type( for_: &clean::Type, - trait_: &clean::Type, + trait_: &clean::Path, cx: &Context<'_>, ) -> String { - small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx),)) + small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx))) } fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> { @@ -2370,6 +2448,15 @@ let mut visited = FxHashSet::default(); let mut work = VecDeque::new(); + let mut process_path = |did: DefId| { + let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone()); + let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern); + + if let Some(path) = fqp { + out.push(path.join("::")); + } + }; + work.push_back(first_ty); while let Some(ty) = work.pop_front() { @@ -2378,14 +2465,7 @@ } match ty { - clean::Type::ResolvedPath { did, .. } => { - let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone()); - let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern); - - if let Some(path) = fqp { - out.push(path.join("::")); - } - } + clean::Type::ResolvedPath { did, .. } => process_path(did), clean::Type::Tuple(tys) => { work.extend(tys.into_iter()); } @@ -2403,7 +2483,7 @@ } clean::Type::QPath { self_type, trait_, .. } => { work.push_back(*self_type); - work.push_back(*trait_); + process_path(trait_.def_id()); } _ => {} } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/print_item.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/print_item.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/print_item.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/print_item.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,10 +8,12 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_middle::middle::stability; +use rustc_middle::span_bug; use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{Adt, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants}; use super::{ collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_strs, notable_traits_decl, @@ -28,16 +30,43 @@ }; use crate::html::highlight; use crate::html::layout::Page; -use crate::html::markdown::MarkdownSummaryLine; +use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; + +use serde::Serialize; const ITEM_TABLE_OPEN: &'static str = "
"; const ITEM_TABLE_CLOSE: &'static str = "
"; +const ITEM_TABLE_ROW_OPEN: &'static str = "
"; +const ITEM_TABLE_ROW_CLOSE: &'static str = "
"; + +// A component in a `use` path, like `string` in std::string::ToString +#[derive(Serialize)] +struct PathComponent<'a> { + path: String, + name: &'a str, +} + +#[derive(Serialize)] +struct ItemVars<'a> { + page: &'a Page<'a>, + static_root_path: &'a str, + typ: &'a str, + name: &'a str, + item_type: &'a str, + path_components: Vec>, + stability_since_raw: &'a str, + src_href: Option<&'a str>, +} -pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, page: &Page<'_>) { +pub(super) fn print_item( + cx: &Context<'_>, + templates: &tera::Tera, + item: &clean::Item, + buf: &mut Buffer, + page: &Page<'_>, +) { debug_assert!(!item.is_stripped()); - // Write the breadcrumb trail header for the top - buf.write_str("

"); - let name = match *item.kind { + let typ = match *item.kind { clean::ModuleItem(_) => { if item.is_crate() { "Crate " @@ -69,48 +98,15 @@ unreachable!(); } }; - buf.write_str(name); - if !item.is_primitive() && !item.is_keyword() { - let cur = &cx.current; - let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() }; - for (i, component) in cur.iter().enumerate().take(amt) { - write!( - buf, - "{}::", - "../".repeat(cur.len() - i - 1), - component - ); - } - } - write!(buf, "{}", item.type_(), item.name.as_ref().unwrap()); - write!( - buf, - "", - static_root_path = page.get_static_root_path(), - suffix = page.resource_suffix, - ); - - buf.write_str(""); // in-band - buf.write_str(""); + let mut stability_since_raw = Buffer::new(); render_stability_since_raw( - buf, + &mut stability_since_raw, item.stable_since(cx.tcx()).as_deref(), item.const_stability(cx.tcx()), None, None, ); - buf.write_str( - "\ - \ - []\ - \ - ", - ); + let stability_since_raw: String = stability_since_raw.into_inner(); // Write `src` tag // @@ -118,11 +114,38 @@ // [src] link in the downstream documentation will actually come back to // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. - if cx.include_sources && !item.is_primitive() { - write_srclink(cx, item, buf); - } + let src_href = + if cx.include_sources && !item.is_primitive() { cx.src_href(item) } else { None }; - buf.write_str("

"); // out-of-band + let path_components = if item.is_primitive() || item.is_keyword() { + vec![] + } else { + let cur = &cx.current; + let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() }; + cur.iter() + .enumerate() + .take(amt) + .map(|(i, component)| PathComponent { + path: "../".repeat(cur.len() - i - 1), + name: component, + }) + .collect() + }; + + let item_vars = ItemVars { + page: page, + static_root_path: page.get_static_root_path(), + typ: typ, + name: &item.name.as_ref().unwrap().as_str(), + item_type: &item.type_().to_string(), + path_components: path_components, + stability_since_raw: &stability_since_raw, + src_href: src_href.as_deref(), + }; + + let teractx = tera::Context::from_serialize(item_vars).unwrap(); + let heading = templates.render("print_item.html", &teractx).unwrap(); + buf.write_str(&heading); match *item.kind { clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items), @@ -171,7 +194,7 @@ } fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) { - document(w, cx, item, None); + document(w, cx, item, None, HeadingOffset::H2); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); @@ -254,9 +277,6 @@ debug!("{:?}", indices); let mut curty = None; - // See: https://github.com/rust-lang/rust/issues/88545 - let item_table_block_size = 900usize; - let mut item_table_nth_element = 0usize; for &idx in &indices { let myitem = &items[idx]; @@ -277,18 +297,19 @@ write!( w, "

\ - {name}

\n{}", + {name}\ +

\n{}", ITEM_TABLE_OPEN, id = cx.derive_id(short.to_owned()), name = name ); - item_table_nth_element = 0; } match *myitem.kind { clean::ExternCrateItem { ref src } => { use crate::html::format::anchor; + w.write_str(ITEM_TABLE_ROW_OPEN); match *src { Some(ref src) => write!( w, @@ -309,6 +330,7 @@ ), } w.write_str(""); + w.write_str(ITEM_TABLE_ROW_CLOSE); } clean::ImportItem(ref import) => { @@ -320,7 +342,7 @@ let import_item = clean::Item { def_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.sess()), + cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg), ..myitem.clone() }; @@ -333,6 +355,7 @@ let add = if stab.is_some() { " " } else { "" }; + w.write_str(ITEM_TABLE_ROW_OPEN); write!( w, "
\ @@ -345,6 +368,7 @@ imp = import.print(cx), stab_tags = stab_tags.unwrap_or_default(), ); + w.write_str(ITEM_TABLE_ROW_CLOSE); } _ => { @@ -365,6 +389,7 @@ let add = if stab.is_some() { " " } else { "" }; let doc_value = myitem.doc_value().unwrap_or_default(); + w.write_str(ITEM_TABLE_ROW_OPEN); write!( w, "
\ @@ -387,15 +412,9 @@ .collect::>() .join(" "), ); + w.write_str(ITEM_TABLE_ROW_CLOSE); } } - - item_table_nth_element += 1; - if item_table_nth_element > item_table_block_size { - w.write_str(ITEM_TABLE_CLOSE); - w.write_str(ITEM_TABLE_OPEN); - item_table_nth_element = 0; - } } if curty.is_some() { @@ -415,10 +434,7 @@ // The trailing space after each tag is to space it properly against the rest of the docs. if let Some(depr) = &item.deprecation(tcx) { let mut message = "Deprecated"; - if !stability::deprecation_in_effect( - depr.is_since_rustc_version, - depr.since.map(|s| s.as_str()).as_deref(), - ) { + if !stability::deprecation_in_effect(depr) { message = "Deprecation planned"; } tags += &tag_html("deprecated", "", message); @@ -485,7 +501,7 @@ notable_traits = notable_traits_decl(&f.decl, cx), ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { @@ -608,7 +624,7 @@ }); // Trait documentation - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( @@ -626,7 +642,7 @@ let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); let mut content = Buffer::empty_from(w); - document(&mut content, cx, m, Some(t)); + document(&mut content, cx, m, Some(t), HeadingOffset::H5); let toggled = !content.is_empty(); if toggled { write!(w, "
"); @@ -709,11 +725,10 @@ let mut implementor_dups: FxHashMap = FxHashMap::default(); for implementor in implementors { match implementor.inner_impl().for_ { - clean::ResolvedPath { ref path, did, is_generic: false, .. } + clean::ResolvedPath { ref path, did, .. } | clean::BorrowedRef { - type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. }, - .. - } => { + type_: box clean::ResolvedPath { ref path, did, .. }, .. + } if !path.is_assoc_ty() => { let &mut (prev_did, ref mut has_duplicates) = implementor_dups.entry(path.last()).or_insert((did, false)); if prev_did != did { @@ -841,7 +856,7 @@ ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -863,7 +878,7 @@ ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -894,7 +909,7 @@ ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let def_id = it.def_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they @@ -912,7 +927,7 @@ }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let mut fields = s .fields @@ -945,7 +960,7 @@ if let Some(stability_class) = field.stability_class(cx.tcx()) { write!(w, "", stab = stability_class); } - document(w, cx, field, Some(it)); + document(w, cx, field, Some(it), HeadingOffset::H3); } } let def_id = it.def_id.expect_def_id(); @@ -1027,7 +1042,7 @@ }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); if !e.variants.is_empty() { write!( @@ -1056,7 +1071,7 @@ w.write_str(""); render_stability_since(w, variant, it, cx.tcx()); w.write_str("
"); - document(w, cx, variant, Some(it)); + document(w, cx, variant, Some(it), HeadingOffset::H3); document_non_exhaustive(w, variant); use crate::clean::Variant; @@ -1096,7 +1111,7 @@ f = field.name.as_ref().unwrap(), t = ty.print(cx) ); - document(w, cx, field, Some(variant)); + document(w, cx, field, Some(variant), HeadingOffset::H4); } _ => unreachable!(), } @@ -1123,7 +1138,7 @@ None, ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { @@ -1153,11 +1168,11 @@ }); } } - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All) } @@ -1196,7 +1211,7 @@ } }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) { @@ -1207,7 +1222,7 @@ }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let mut fields = s .fields @@ -1243,7 +1258,7 @@ name = field_name, ty = ty.print(cx) ); - document(w, cx, field, Some(it)); + document(w, cx, field, Some(it), HeadingOffset::H3); } } } @@ -1264,7 +1279,7 @@ typ = s.type_.print(cx) ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { @@ -1279,13 +1294,13 @@ ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All) } fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order). @@ -1407,11 +1422,12 @@ // If there's already another implementor that has the same abridged name, use the // full path, for example in `std::iter::ExactSizeIterator` let use_absolute = match implementor.inner_impl().for_ { - clean::ResolvedPath { ref path, is_generic: false, .. } - | clean::BorrowedRef { - type_: box clean::ResolvedPath { ref path, is_generic: false, .. }, - .. - } => implementor_dups[&path.last()].1, + clean::ResolvedPath { ref path, .. } + | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path, .. }, .. } + if !path.is_assoc_ty() => + { + implementor_dups[&path.last()].1 + } _ => false, }; render_impl( @@ -1636,6 +1652,15 @@ } fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { + fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) { + if layout.abi.is_unsized() { + write!(w, "(unsized)"); + } else { + let bytes = layout.size.bytes() - tag_size; + write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },); + } + } + if !cx.shared.show_type_layout { return; } @@ -1651,22 +1676,46 @@ writeln!( w, "

Note: Most layout information is \ - completely unstable and may be different between compiler versions and platforms. \ + completely unstable and may even differ between compilations. \ The only exception is types with certain repr(...) attributes. \ Please see the Rust Reference’s \ “Type Layout†\ chapter for details on type layout guarantees.

" ); - if ty_layout.layout.abi.is_unsized() { - writeln!(w, "

Size: (unsized)

"); - } else { - let bytes = ty_layout.layout.size.bytes(); - writeln!( - w, - "

Size: {size} byte{pl}

", - size = bytes, - pl = if bytes == 1 { "" } else { "s" }, - ); + w.write_str("

Size: "); + write_size_of_layout(w, ty_layout.layout, 0); + writeln!(w, "

"); + if let Variants::Multiple { variants, tag, tag_encoding, .. } = + &ty_layout.layout.variants + { + if !variants.is_empty() { + w.write_str( + "

Size for each variant:

\ +
    ", + ); + + let adt = if let Adt(adt, _) = ty_layout.ty.kind() { + adt + } else { + span_bug!(tcx.def_span(ty_def_id), "not an adt") + }; + + let tag_size = if let TagEncoding::Niche { .. } = tag_encoding { + 0 + } else if let Primitive::Int(i, _) = tag.value { + i.size().bytes() + } else { + span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int") + }; + + for (index, layout) in variants.iter_enumerated() { + let ident = adt.variants[index].ident; + write!(w, "
  • {name}: ", name = ident); + write_size_of_layout(w, layout, tag_size); + writeln!(w, "
  • "); + } + w.write_str("
"); + } } } // This kind of layout error can occur with valid code, e.g. if you try to diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/span_map.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/span_map.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/span_map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/span_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -use crate::clean; +use crate::clean::{self, PrimitiveType}; use crate::html::sources; use rustc_data_structures::fx::FxHashMap; @@ -22,6 +22,7 @@ crate enum LinkFromSrc { Local(clean::Span), External(DefId), + Primitive(PrimitiveType), } /// This function will do at most two things: @@ -45,7 +46,7 @@ if include_sources { if generate_link_to_definition { - intravisit::walk_crate(&mut visitor, tcx.hir().krate()); + tcx.hir().walk_toplevel_module(&mut visitor); } let (krate, sources) = sources::collect_local_sources(tcx, src_root, krate); (krate, sources, visitor.matches) @@ -73,17 +74,20 @@ Some(def_id) } Res::Local(_) => None, + Res::PrimTy(p) => { + // FIXME: Doesn't handle "path-like" primitives like arrays or tuples. + let span = path_span.unwrap_or(path.span); + self.matches.insert(span, LinkFromSrc::Primitive(PrimitiveType::from(p))); + return; + } Res::Err => return, _ => return, }; if let Some(span) = self.tcx.hir().res_span(path.res) { - self.matches.insert( - path_span.unwrap_or_else(|| path.span), - LinkFromSrc::Local(clean::Span::new(span)), - ); - } else if let Some(def_id) = info { self.matches - .insert(path_span.unwrap_or_else(|| path.span), LinkFromSrc::External(def_id)); + .insert(path_span.unwrap_or(path.span), LinkFromSrc::Local(clean::Span::new(span))); + } else if let Some(def_id) = info { + self.matches.insert(path_span.unwrap_or(path.span), LinkFromSrc::External(def_id)); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/templates.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/templates.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/templates.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/templates.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +use std::error::Error as StdError; + +use crate::error::Error; + +pub(crate) fn load() -> Result { + let mut templates = tera::Tera::default(); + + macro_rules! include_template { + ($file:literal, $fullpath:literal) => { + templates.add_raw_template($file, include_str!($fullpath)).map_err(|e| Error { + file: $file.into(), + error: format!("{}: {}", e, e.source().map(|e| e.to_string()).unwrap_or_default()), + })? + }; + } + + include_template!("page.html", "../templates/page.html"); + include_template!("print_item.html", "../templates/print_item.html"); + Ok(templates) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/write_shared.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/write_shared.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/render/write_shared.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/render/write_shared.rs 2021-11-29 19:27:11.000000000 +0000 @@ -39,8 +39,9 @@ "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD, "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC, "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE, - "noto-sans-kr-v13-korean-regular.woff" => static_files::noto_sans_kr::REGULAR, - "noto-sans-kr-v13-korean-regular-LICENSE.txt" => static_files::noto_sans_kr::LICENSE, + "noto-sans-kr-regular.woff2" => static_files::noto_sans_kr::REGULAR2, + "noto-sans-kr-regular.woff" => static_files::noto_sans_kr::REGULAR, + "noto-sans-kr-LICENSE.txt" => static_files::noto_sans_kr::LICENSE, "LICENSE-MIT.txt" => static_files::LICENSE_MIT, "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE, "COPYRIGHT.txt" => static_files::COPYRIGHT, @@ -105,10 +106,10 @@ self.dst.join(&filename) } - fn write_shared>( + fn write_shared( &self, resource: SharedResource<'_>, - contents: C, + contents: impl 'static + Send + AsRef<[u8]>, emit: &[EmitType], ) -> Result<(), Error> { if resource.should_emit(emit) { @@ -121,25 +122,23 @@ fn write_minify( &self, resource: SharedResource<'_>, - contents: &str, + contents: impl 'static + Send + AsRef + AsRef<[u8]>, minify: bool, emit: &[EmitType], ) -> Result<(), Error> { - let tmp; - let contents = if minify { - tmp = if resource.extension() == Some(&OsStr::new("css")) { + if minify { + let contents = contents.as_ref(); + let contents = if resource.extension() == Some(&OsStr::new("css")) { minifier::css::minify(contents).map_err(|e| { Error::new(format!("failed to minify CSS file: {}", e), resource.path(self)) })? } else { minifier::js::minify(contents) }; - tmp.as_bytes() + self.write_shared(resource, contents, emit) } else { - contents.as_bytes() - }; - - self.write_shared(resource, contents, emit) + self.write_shared(resource, contents, emit) + } } } @@ -155,15 +154,21 @@ let lock_file = cx.dst.join(".lock"); let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file); - // The weird `: &_` is to work around a borrowck bug: https://github.com/rust-lang/rust/issues/41078#issuecomment-293646723 - let write_minify = |p, c: &_| { + // Minified resources are usually toolchain resources. If they're not, they should use `cx.write_minify` directly. + fn write_minify( + basename: &'static str, + contents: impl 'static + Send + AsRef + AsRef<[u8]>, + cx: &Context<'_>, + options: &RenderOptions, + ) -> Result<(), Error> { cx.write_minify( - SharedResource::ToolchainSpecific { basename: p }, - c, + SharedResource::ToolchainSpecific { basename }, + contents, options.enable_minification, &options.emit, ) - }; + } + // Toolchain resources should never be dynamic. let write_toolchain = |p: &'static _, c: &'static _| { cx.write_shared(SharedResource::ToolchainSpecific { basename: p }, c, &options.emit) @@ -210,12 +215,12 @@ "details.undocumented > summary::before, details.rustdoc-toggle > summary::before", "toggle-plus.svg", ); - write_minify("rustdoc.css", &rustdoc_css)?; + write_minify("rustdoc.css", rustdoc_css, cx, options)?; // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. - write_minify("settings.css", static_files::SETTINGS_CSS)?; - write_minify("noscript.css", static_files::NOSCRIPT_CSS)?; + write_minify("settings.css", static_files::SETTINGS_CSS, cx, options)?; + write_minify("noscript.css", static_files::NOSCRIPT_CSS, cx, options)?; // To avoid "light.css" to be overwritten, we'll first run over the received themes and only // then we'll run over the "official" styles. @@ -228,9 +233,9 @@ // Handle the official themes match theme { - "light" => write_minify("light.css", static_files::themes::LIGHT)?, - "dark" => write_minify("dark.css", static_files::themes::DARK)?, - "ayu" => write_minify("ayu.css", static_files::themes::AYU)?, + "light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?, + "dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?, + "ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?, _ => { // Handle added third-party themes let filename = format!("{}.{}", theme, extension); @@ -264,26 +269,38 @@ // Maybe we can change the representation to move this out of main.js? write_minify( "main.js", - &static_files::MAIN_JS.replace( - "/* INSERT THEMES HERE */", - &format!(" = {}", serde_json::to_string(&themes).unwrap()), - ), + static_files::MAIN_JS + .replace( + "/* INSERT THEMES HERE */", + &format!(" = {}", serde_json::to_string(&themes).unwrap()), + ) + .replace( + "/* INSERT RUSTDOC_VERSION HERE */", + &format!( + "rustdoc {}", + rustc_interface::util::version_str().unwrap_or("unknown version") + ), + ), + cx, + options, )?; - write_minify("search.js", static_files::SEARCH_JS)?; - write_minify("settings.js", static_files::SETTINGS_JS)?; + write_minify("search.js", static_files::SEARCH_JS, cx, options)?; + write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?; if cx.include_sources { - write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?; + write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?; } { write_minify( "storage.js", - &format!( + format!( "var resourcesSuffix = \"{}\";{}", cx.shared.resource_suffix, static_files::STORAGE_JS ), + cx, + options, )?; } @@ -292,12 +309,12 @@ // This varies based on the invocation, so it can't go through the write_minify wrapper. cx.write_minify( SharedResource::InvocationSpecific { basename: "theme.css" }, - &buffer, + buffer, options.enable_minification, &options.emit, )?; } - write_minify("normalize.css", static_files::NORMALIZE_CSS)?; + write_minify("normalize.css", static_files::NORMALIZE_CSS, cx, options)?; for (name, contents) in &*FILES_UNVERSIONED { cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?; } @@ -512,7 +529,7 @@ content, &cx.shared.style_files, ); - cx.shared.fs.write(&dst, v.as_bytes())?; + cx.shared.fs.write(dst, v)?; } } @@ -603,7 +620,7 @@ }", ); v.push_str("})()"); - cx.shared.fs.write(&mydst, &v)?; + cx.shared.fs.write(mydst, v)?; } Ok(()) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/sources.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/sources.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/sources.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/sources.rs 2021-11-29 19:27:11.000000000 +0000 @@ -208,7 +208,7 @@ }, &self.cx.shared.style_files, ); - self.cx.shared.fs.write(&cur, v.as_bytes())?; + self.cx.shared.fs.write(cur, v)?; self.emitted_local_sources.insert(p); Ok(()) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/css/rustdoc.css rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/css/rustdoc.css --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/css/rustdoc.css 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/css/rustdoc.css 2021-11-29 19:27:11.000000000 +0000 @@ -75,12 +75,13 @@ font-display: swap; } -/* Avoid using legacy CJK serif fonts in Windows like Batang */ +/* Avoid using legacy CJK serif fonts in Windows like Batang. */ @font-face { font-family: 'Noto Sans KR'; - src: url("noto-sans-kr-v13-korean-regular.woff") format("woff"); + src: url("noto-sans-kr-regular.woff2") format("woff2"), + url("noto-sans-kr-regular.woff") format("woff"); font-display: swap; - unicode-range: U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF; + unicode-range: U+AC00-D7AF, U+3130-318F, U+1100-11FF, U+A960-A97F, U+D7B0-D7FF; } * { @@ -126,7 +127,7 @@ h3 { font-size: 1.3em; } -h1, h2, h3, h4 { +h1, h2, h3, h4, h5, h6 { font-weight: 500; margin: 20px 0 15px 0; padding-bottom: 6px; @@ -179,7 +180,7 @@ padding-left: 0; } -h1, h2, h3, h4, +h1, h2, h3, h4, h5, h6, .sidebar, a.source, .search-input, .search-results .result-name, .content table td:first-child > a, .item-left > a, @@ -501,27 +502,31 @@ white-space: pre-wrap; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom: 1px solid; } -.top-doc .docblock h1 { font-size: 1.3em; } -.top-doc .docblock h2 { font-size: 1.15em; } -.top-doc .docblock h3, +.top-doc .docblock h2 { font-size: 1.3em; } +.top-doc .docblock h3 { font-size: 1.15em; } .top-doc .docblock h4, -.top-doc .docblock h5 { +.top-doc .docblock h5, +.top-doc .docblock h6 { font-size: 1em; } -.docblock h1 { font-size: 1em; } -.docblock h2 { font-size: 0.95em; } -.docblock h3, .docblock h4, .docblock h5 { font-size: 0.9em; } +.docblock h5 { font-size: 1em; } +.docblock h6 { font-size: 0.95em; } .docblock { margin-left: 24px; position: relative; } +.docblock > * { + max-width: 100%; + overflow-x: auto; +} + .content .out-of-band { flex-grow: 0; text-align: right; @@ -768,22 +773,16 @@ .block a.current.crate { font-weight: 500; } .item-table { - display: grid; - column-gap: 1.2rem; - row-gap: 0.0rem; - grid-template-columns: auto 1fr; - /* align content left */ - justify-items: start; + display: table; +} +.item-row { + display: table-row; } - .item-left, .item-right { - display: block; + display: table-cell; } .item-left { - grid-column: 1; -} -.item-right { - grid-column: 2; + padding-right: 1.2rem; } .search-container { @@ -923,15 +922,24 @@ display: block; margin-right: 0.5rem; } -#help > div > span { +#help span.top, #help span.bottom { text-align: center; display: block; - margin: 10px 0; font-size: 18px; - border-bottom: 1px solid #ccc; + +} +#help span.top { + text-align: center; + display: block; + margin: 10px 0; + border-bottom: 1px solid; padding-bottom: 4px; margin-bottom: 6px; } +#help span.bottom { + clear: both; + border-top: 1px solid; +} #help dd { margin: 5px 35px; } #help .infos { padding-left: 0; } #help h1, #help h2 { margin-top: 0; } @@ -1877,6 +1885,9 @@ /* Display an alternating layout on tablets and phones */ .item-table { + display: block; + } + .item-row { display: flex; flex-flow: column wrap; } @@ -1957,4 +1968,8 @@ .docblock { margin-left: 12px; } + + .docblock code { + overflow-wrap: anywhere; + } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/ayu.css rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/ayu.css --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/ayu.css 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/ayu.css 2021-11-29 19:27:11.000000000 +0000 @@ -136,7 +136,7 @@ border-right: 1px solid #ffb44c; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #5c6773; } @@ -217,7 +217,7 @@ color: #c5c5c5; } body.source .example-wrap pre.rust a { - background: #c5c5c5; + background: #333; } .docblock:not(.type-decl) a:not(.srclink):not(.test-arrow), @@ -286,8 +286,8 @@ border-radius: 4px; } -#help > div > span { - border-bottom-color: #5c6773; +#help span.bottom, #help span.top { + border-color: #5c6773; } .since { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/dark.css rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/dark.css --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/dark.css 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/dark.css 2021-11-29 19:27:11.000000000 +0000 @@ -93,7 +93,7 @@ background-color: #0a042f !important; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #DDD; } @@ -242,8 +242,8 @@ border-color: #bfbfbf; } -#help > div > span { - border-bottom-color: #bfbfbf; +#help span.bottom, #help span.top { + border-color: #bfbfbf; } #help dt { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/light.css rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/light.css --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/light.css 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/css/themes/light.css 2021-11-29 19:27:11.000000000 +0000 @@ -93,7 +93,7 @@ background-color: #f6fdb0 !important; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #ddd; } @@ -232,8 +232,8 @@ border-color: #bfbfbf; } -#help > div > span { - border-bottom-color: #bfbfbf; +#help span.bottom, #help span.top { + border-color: #bfbfbf; } .since { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/js/main.js rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/js/main.js --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static/js/main.js 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static/js/main.js 2021-11-29 19:27:11.000000000 +0000 @@ -911,6 +911,7 @@ }); var book_info = document.createElement("span"); + book_info.className = "top"; book_info.innerHTML = "You can find more information in \ the rustdoc book."; @@ -961,6 +962,14 @@ container.appendChild(div_shortcuts); container.appendChild(div_infos); + var rustdoc_version = document.createElement("span"); + rustdoc_version.className = "bottom"; + var rustdoc_version_code = document.createElement("code"); + rustdoc_version_code.innerText = "/* INSERT RUSTDOC_VERSION HERE */"; + rustdoc_version.appendChild(rustdoc_version_code); + + container.appendChild(rustdoc_version); + popup.appendChild(container); insertAfter(popup, searchState.outputElement()); // So that it's only built once and then it'll do nothing when called! diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static_files.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static_files.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/static_files.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/static_files.rs 2021-11-29 19:27:11.000000000 +0000 @@ -70,8 +70,6 @@ crate static RUST_FAVICON_PNG_16: &[u8] = include_bytes!("static/images/favicon-16x16.png"); crate static RUST_FAVICON_PNG_32: &[u8] = include_bytes!("static/images/favicon-32x32.png"); -crate static PAGE: &str = include_str!("templates/page.html"); - /// The built-in themes given to every documentation site. crate mod themes { /// The "light" theme, selected by default when no setting is available. Used as the basis for @@ -159,15 +157,14 @@ } crate mod noto_sans_kr { - /// The file `noto-sans-kr-v13-korean-regular.woff`, the Regular variant of the Noto Sans KR - /// font. - crate static REGULAR: &[u8] = - include_bytes!("static/fonts/noto-sans-kr-v13-korean-regular.woff"); + /// The file `noto-sans-kr.woff`, the Regular variant of the Noto Sans KR font. + crate static REGULAR: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff"); - /// The file `noto-sans-kr-v13-korean-regular-LICENSE.txt`, the license text of the Noto Sans KR - /// font. - crate static LICENSE: &[u8] = - include_bytes!("static/fonts/noto-sans-kr-v13-korean-regular-LICENSE.txt"); + /// The file `noto-sans-kr.woff2`, the Regular variant of the Noto Sans KR font. + crate static REGULAR2: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff2"); + + /// The file `noto-sans-kr-LICENSE.txt`, the license text of the Noto Sans KR font. + crate static LICENSE: &[u8] = include_bytes!("static/fonts/noto-sans-kr-LICENSE.txt"); } /// Files related to the sidebar in rustdoc sources. diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/templates/print_item.html rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/templates/print_item.html --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/html/templates/print_item.html 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/html/templates/print_item.html 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +

{#- -#} + {#- -#} + {{-typ-}} + {#- The breadcrumbs of the item path, like std::string -#} + {%- for component in path_components -%} + {{component.name}}:: + {%- endfor -%} + {{name}} {#- -#} + {#- -#} + {#- -#} + {#- -#} + {{- stability_since_raw | safe -}} + {#- -#} + {#- -#} + [] {#- -#} + {#- -#} + {#- -#} + {%- if src_href -%} + [src] + {%- endif -%} + {#- -#} +

{#- -#} diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/json/conversions.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/json/conversions.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/json/conversions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/json/conversions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -30,9 +30,7 @@ .get(&item.def_id) .into_iter() .flatten() - .filter_map(|clean::ItemLink { link, did, .. }| { - did.map(|did| (link.clone(), from_item_id(did.into()))) - }) + .map(|clean::ItemLink { link, did, .. }| (link.clone(), from_item_id((*did).into()))) .collect(); let docs = item.attrs.collapsed_doc_value(); let attrs = item @@ -139,7 +137,7 @@ match arg { Lifetime(l) => GenericArg::Lifetime(l.0.to_string()), Type(t) => GenericArg::Type(t.into_tcx(tcx)), - Const(c) => GenericArg::Const(c.into_tcx(tcx)), + Const(box c) => GenericArg::Const(c.into_tcx(tcx)), Infer => GenericArg::Infer, } } @@ -220,6 +218,7 @@ ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)), MacroItem(m) => ItemEnum::Macro(m.source), ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)), + PrimitiveItem(p) => ItemEnum::PrimitiveType(p.as_sym().to_string()), AssocConstItem(t, s) => ItemEnum::AssocConst { type_: t.into_tcx(tcx), default: s }, AssocTypeItem(g, t) => ItemEnum::AssocType { bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(), @@ -227,7 +226,7 @@ }, // `convert_item` early returns `None` for striped items StrippedItem(_) => unreachable!(), - PrimitiveItem(_) | KeywordItem(_) => { + KeywordItem(_) => { panic!("{:?} is not supported for JSON output", item) } ExternCrateItem { ref src } => ItemEnum::ExternCrate { @@ -326,7 +325,9 @@ fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self { use clean::GenericParamDefKind::*; match kind { - Lifetime => GenericParamDefKind::Lifetime, + Lifetime { outlives } => GenericParamDefKind::Lifetime { + outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(), + }, Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type { bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), default: default.map(|x| x.into_tcx(tcx)), @@ -363,8 +364,11 @@ use clean::GenericBound::*; match bound { TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { + // FIXME: should `trait_` be a clean::Path equivalent in JSON? + let trait_ = + clean::ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx); GenericBound::TraitBound { - trait_: trait_.into_tcx(tcx), + trait_, generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), modifier: from_trait_bound_modifier(modifier), } @@ -387,22 +391,19 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { use clean::Type::*; match ty { - ResolvedPath { path, did, is_generic: _ } => Type::ResolvedPath { + ResolvedPath { path, did } => Type::ResolvedPath { name: path.whole_name(), id: from_item_id(did.into()), args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), param_names: Vec::new(), }, DynTrait(mut bounds, lt) => { - let (path, id) = match bounds.remove(0).trait_ { - ResolvedPath { path, did, .. } => (path, did), - _ => unreachable!(), - }; + let first_trait = bounds.remove(0).trait_; Type::ResolvedPath { - name: path.whole_name(), - id: from_item_id(id.into()), - args: path + name: first_trait.whole_name(), + id: from_item_id(first_trait.def_id().into()), + args: first_trait .segments .last() .map(|args| Box::new(args.clone().args.into_tcx(tcx))), @@ -423,7 +424,6 @@ Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s }, ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()), - Never => Type::Never, Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { mutable: mutability == ast::Mutability::Mut, @@ -434,11 +434,15 @@ mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_tcx(tcx)), }, - QPath { name, self_type, trait_, .. } => Type::QualifiedPath { - name: name.to_string(), - self_type: Box::new((*self_type).into_tcx(tcx)), - trait_: Box::new((*trait_).into_tcx(tcx)), - }, + QPath { name, self_type, trait_, .. } => { + // FIXME: should `trait_` be a clean::Path equivalent in JSON? + let trait_ = ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx); + Type::QualifiedPath { + name: name.to_string(), + self_type: Box::new((*self_type).into_tcx(tcx)), + trait_: Box::new(trait_), + } + } } } } @@ -507,6 +511,11 @@ blanket_impl, span: _span, } = impl_; + // FIXME: should `trait_` be a clean::Path equivalent in JSON? + let trait_ = trait_.map(|path| { + let did = path.def_id(); + clean::ResolvedPath { path, did }.into_tcx(tcx) + }); Impl { is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, generics: generics.into_tcx(tcx), @@ -514,7 +523,7 @@ .into_iter() .map(|x| x.to_string()) .collect(), - trait_: trait_.map(|x| x.into_tcx(tcx)), + trait_, for_: for_.into_tcx(tcx), items: ids(items), negative: negative_polarity, diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/json/mod.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/json/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/json/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/json/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -69,7 +69,21 @@ .iter() .filter_map(|i| { let item = &i.impl_item; - if item.def_id.is_local() { + + // HACK(hkmatsumoto): For impls of primitive types, we index them + // regardless of whether they're local. This is because users can + // document primitive items in an arbitrary crate by using + // `doc(primitive)`. + let mut is_primitive_impl = false; + if let clean::types::ItemKind::ImplItem(ref impl_) = *item.kind { + if impl_.trait_.is_none() { + if let clean::types::Type::Primitive(_) = impl_.for_ { + is_primitive_impl = true; + } + } + } + + if item.def_id.is_local() || is_primitive_impl { self.item(item.clone()).unwrap(); Some(from_item_id(item.def_id)) } else { @@ -169,6 +183,8 @@ s.impls = self.get_impls(id.expect_def_id()) } else if let types::ItemEnum::Enum(ref mut e) = new_item.inner { e.impls = self.get_impls(id.expect_def_id()) + } else if let types::ItemEnum::Union(ref mut u) = new_item.inner { + u.impls = self.get_impls(id.expect_def_id()) } let removed = self.index.borrow_mut().insert(from_item_id(id), new_item.clone()); @@ -189,6 +205,11 @@ fn after_krate(&mut self) -> Result<(), Error> { debug!("Done with crate"); + + for primitive in Rc::clone(&self.cache).primitive_locations.values() { + self.get_impls(*primitive); + } + let mut index = (*self.index).clone().into_inner(); index.extend(self.get_trait_items()); // This needs to be the default HashMap for compatibility with the public interface for @@ -234,7 +255,7 @@ ) }) .collect(), - format_version: 6, + format_version: types::FORMAT_VERSION, }; let mut p = self.out_path.clone(); p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/lib.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,8 +4,10 @@ )] #![feature(rustc_private)] #![feature(array_methods)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(control_flow_enum)] +#![feature(box_syntax)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(test)] @@ -18,8 +20,6 @@ #![warn(rustc::internal)] #[macro_use] -extern crate lazy_static; -#[macro_use] extern crate tracing; // N.B. these need `extern crate` even in 2018 edition @@ -34,6 +34,7 @@ extern crate rustc_ast_lowering; extern crate rustc_ast_pretty; extern crate rustc_attr; +extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; @@ -49,7 +50,6 @@ extern crate rustc_lint_defs; extern crate rustc_metadata; extern crate rustc_middle; -extern crate rustc_mir; extern crate rustc_parse; extern crate rustc_passes; extern crate rustc_resolve; @@ -419,8 +419,12 @@ "URL", ) }), - unstable("display-warnings", |o| { - o.optflagmulti("", "display-warnings", "to print code warnings when testing doc") + unstable("display-doctest-warnings", |o| { + o.optflagmulti( + "", + "display-doctest-warnings", + "show warnings that originate in doctests", + ) }), stable("crate-version", |o| { o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") @@ -726,6 +730,7 @@ let default_passes = options.default_passes; let output_format = options.output_format; // FIXME: fix this clone (especially render_options) + let externs = options.externs.clone(); let manual_passes = options.manual_passes.clone(); let render_options = options.render_options.clone(); let config = core::create_config(options); @@ -743,7 +748,7 @@ // We need to hold on to the complete resolver, so we cause everything to be // cloned for the analysis passes to use. Suboptimal, but necessary in the // current architecture. - let resolver = core::create_resolver(queries, &sess); + let resolver = core::create_resolver(externs, queries, sess); if sess.has_errors() { sess.fatal("Compilation failed, aborting rustdoc"); diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/markdown.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/markdown.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/markdown.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/markdown.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,9 @@ use crate::doctest::{Collector, TestOptions}; use crate::html::escape::Escape; use crate::html::markdown; -use crate::html::markdown::{find_testable_code, ErrorCodes, IdMap, Markdown, MarkdownWithToc}; +use crate::html::markdown::{ + find_testable_code, ErrorCodes, HeadingOffset, IdMap, Markdown, MarkdownWithToc, +}; /// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { @@ -70,7 +72,16 @@ let text = if !options.markdown_no_toc { MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string() } else { - Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string() + Markdown { + content: text, + links: &[], + ids: &mut ids, + error_codes, + edition, + playground: &playground, + heading_offset: HeadingOffset::H1, + } + .into_string() }; let err = write!( @@ -120,7 +131,7 @@ .map_err(|err| format!("{}: {}", options.input.display(), err))?; let mut opts = TestOptions::default(); opts.no_crate_inject = true; - opts.display_warnings = options.display_warnings; + opts.display_doctest_warnings = options.display_doctest_warnings; let mut collector = Collector::new( Symbol::intern(&options.input.display().to_string()), options.clone(), @@ -138,7 +149,7 @@ crate::doctest::run_tests( options.test_args, options.nocapture, - options.display_warnings, + options.display_doctest_warnings, collector.tests, ); Ok(()) diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/bare_urls.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/bare_urls.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/bare_urls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/bare_urls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use crate::html::markdown::opts; +use crate::html::markdown::main_body_opts; use core::ops::Range; use pulldown_cmark::{Event, Parser, Tag}; use regex::Regex; @@ -83,7 +83,7 @@ }); }; - let mut p = Parser::new_ext(&dox, opts()).into_offset_iter(); + let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter(); while let Some((event, range)) = p.next() { match event { diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/calculate_doc_coverage.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/calculate_doc_coverage.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/calculate_doc_coverage.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/calculate_doc_coverage.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,12 @@ use crate::core::DocContext; use crate::fold::{self, DocFolder}; use crate::html::markdown::{find_testable_code, ErrorCodes}; -use crate::passes::doc_test_lints::{should_have_doc_example, Tests}; +use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests}; use crate::passes::Pass; +use rustc_hir as hir; use rustc_lint::builtin::MISSING_DOCS; use rustc_middle::lint::LintLevelSource; +use rustc_middle::ty::DefIdTree; use rustc_session::lint; use rustc_span::FileName; use serde::Serialize; @@ -221,10 +223,42 @@ .hir() .local_def_id_to_hir_id(i.def_id.expect_def_id().expect_local()); let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id); + + // In case we have: + // + // ``` + // enum Foo { Bar(u32) } + // // or: + // struct Bar(u32); + // ``` + // + // there is no need to require documentation on the fields of tuple variants and + // tuple structs. + let should_be_ignored = i + .def_id + .as_def_id() + .and_then(|def_id| self.ctx.tcx.parent(def_id)) + .and_then(|def_id| self.ctx.tcx.hir().get_if_local(def_id)) + .map(|node| { + matches!( + node, + hir::Node::Variant(hir::Variant { + data: hir::VariantData::Tuple(_, _), + .. + }) | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Struct(hir::VariantData::Tuple(_, _), _), + .. + }) + ) + }) + .unwrap_or(false); + // `missing_docs` is allow-by-default, so don't treat this as ignoring the item - // unless the user had an explicit `allow` - let should_have_docs = - level != lint::Level::Allow || matches!(source, LintLevelSource::Default); + // unless the user had an explicit `allow`. + // + let should_have_docs = !should_be_ignored + && (level != lint::Level::Allow || matches!(source, LintLevelSource::Default)); + debug!("counting {:?} {:?} in {:?}", i.type_(), i.name, filename); self.items.entry(filename).or_default().count_item( has_docs, diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/check_code_block_syntax.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/check_code_block_syntax.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/check_code_block_syntax.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/check_code_block_syntax.rs 2021-11-29 19:27:11.000000000 +0000 @@ -111,9 +111,9 @@ ); } else if empty_block { diag.span_suggestion( - sp.from_inner(InnerSpan::new(0, 3)), + sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(), explanation, - String::from("```text"), + String::from("text"), Applicability::MachineApplicable, ); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/check_doc_test_visibility.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/check_doc_test_visibility.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/check_doc_test_visibility.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/check_doc_test_visibility.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,141 @@ +//! This pass is overloaded and runs two different lints. +//! +//! - MISSING_DOC_CODE_EXAMPLES: this lint is **UNSTABLE** and looks for public items missing doctests. +//! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doctests. + +use super::Pass; +use crate::clean; +use crate::clean::*; +use crate::core::DocContext; +use crate::fold::DocFolder; +use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; +use crate::visit_ast::inherits_doc_hidden; +use rustc_hir as hir; +use rustc_middle::lint::LintLevelSource; +use rustc_session::lint; +use rustc_span::symbol::sym; + +crate const CHECK_DOC_TEST_VISIBILITY: Pass = Pass { + name: "check_doc_test_visibility", + run: check_doc_test_visibility, + description: "run various visibility-related lints on doctests", +}; + +struct DocTestVisibilityLinter<'a, 'tcx> { + cx: &'a mut DocContext<'tcx>, +} + +crate fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let mut coll = DocTestVisibilityLinter { cx }; + + coll.fold_crate(krate) +} + +impl<'a, 'tcx> DocFolder for DocTestVisibilityLinter<'a, 'tcx> { + fn fold_item(&mut self, item: Item) -> Option { + let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); + + look_for_tests(self.cx, &dox, &item); + + Some(self.fold_item_recur(item)) + } +} + +pub(crate) struct Tests { + pub(crate) found_tests: usize, +} + +impl crate::doctest::Tester for Tests { + fn add_test(&mut self, _: String, config: LangString, _: usize) { + if config.rust && config.ignore == Ignore::None { + self.found_tests += 1; + } + } +} + +crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { + if !cx.cache.access_levels.is_public(item.def_id.expect_def_id()) + || matches!( + *item.kind, + clean::StructFieldItem(_) + | clean::VariantItem(_) + | clean::AssocConstItem(_, _) + | clean::AssocTypeItem(_, _) + | clean::TypedefItem(_, _) + | clean::StaticItem(_) + | clean::ConstantItem(_) + | clean::ExternCrateItem { .. } + | clean::ImportItem(_) + | clean::PrimitiveItem(_) + | clean::KeywordItem(_) + // check for trait impl + | clean::ImplItem(clean::Impl { trait_: Some(_), .. }) + ) + { + return false; + } + + // The `expect_def_id()` should be okay because `local_def_id_to_hir_id` + // would presumably panic if a fake `DefIndex` were passed. + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_def_id().expect_local()); + + // check if parent is trait impl + if let Some(parent_hir_id) = cx.tcx.hir().find_parent_node(hir_id) { + if let Some(parent_node) = cx.tcx.hir().find(parent_hir_id) { + if matches!( + parent_node, + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }), + .. + }) + ) { + return false; + } + } + } + + if cx.tcx.hir().attrs(hir_id).lists(sym::doc).has_word(sym::hidden) + || inherits_doc_hidden(cx.tcx, hir_id) + || cx.tcx.hir().span(hir_id).in_derive_expansion() + { + return false; + } + let (level, source) = cx.tcx.lint_level_at_node(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id); + level != lint::Level::Allow || matches!(source, LintLevelSource::Default) +} + +crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { + let hir_id = match DocContext::as_local_hir_id(cx.tcx, item.def_id) { + Some(hir_id) => hir_id, + None => { + // If non-local, no need to check anything. + return; + } + }; + + let mut tests = Tests { found_tests: 0 }; + + find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); + + if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() { + if should_have_doc_example(cx, &item) { + debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); + let sp = item.attr_span(cx.tcx); + cx.tcx.struct_span_lint_hir( + crate::lint::MISSING_DOC_CODE_EXAMPLES, + hir_id, + sp, + |lint| lint.build("missing code example in this documentation").emit(), + ); + } + } else if tests.found_tests > 0 + && !cx.cache.access_levels.is_public(item.def_id.expect_def_id()) + { + cx.tcx.struct_span_lint_hir( + crate::lint::PRIVATE_DOC_TESTS, + hir_id, + item.attr_span(cx.tcx), + |lint| lint.build("documentation test in private item").emit(), + ); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/collect_intra_doc_links/early.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/collect_intra_doc_links/early.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/collect_intra_doc_links/early.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/collect_intra_doc_links/early.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,4 @@ +use ast::visit; use rustc_ast as ast; use rustc_hir::def::Namespace::TypeNS; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -16,7 +17,7 @@ let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver }; // `walk_crate` doesn't visit the crate itself for some reason. loader.load_links_in_attrs(&krate.attrs, krate.span); - ast::visit::walk_crate(&mut loader, krate); + visit::walk_crate(&mut loader, krate); loader.resolver } @@ -54,7 +55,12 @@ } } -impl ast::visit::Visitor<'_> for IntraLinkCrateLoader { +impl visit::Visitor<'_> for IntraLinkCrateLoader { + fn visit_foreign_item(&mut self, item: &ast::ForeignItem) { + self.load_links_in_attrs(&item.attrs, item.span); + visit::walk_foreign_item(self, item) + } + fn visit_item(&mut self, item: &ast::Item) { use rustc_ast_lowering::ResolverAstLowering; @@ -64,12 +70,29 @@ let old_mod = mem::replace(&mut self.current_mod, new_mod); self.load_links_in_attrs(&item.attrs, item.span); - ast::visit::walk_item(self, item); + visit::walk_item(self, item); self.current_mod = old_mod; } else { self.load_links_in_attrs(&item.attrs, item.span); - ast::visit::walk_item(self, item); + visit::walk_item(self, item); } } + + // NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too. + + fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) { + self.load_links_in_attrs(&item.attrs, item.span); + visit::walk_assoc_item(self, item, ctxt) + } + + fn visit_field_def(&mut self, field: &ast::FieldDef) { + self.load_links_in_attrs(&field.attrs, field.span); + visit::walk_field_def(self, field) + } + + fn visit_variant(&mut self, v: &ast::Variant) { + self.load_links_in_attrs(&v.attrs, v.span); + visit::walk_variant(self, v) + } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/collect_intra_doc_links.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/collect_intra_doc_links.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/collect_intra_doc_links.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/collect_intra_doc_links.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,7 +14,7 @@ }; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_middle::ty::TyCtxt; -use rustc_middle::{bug, ty}; +use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::ParentScope; use rustc_session::lint::Lint; use rustc_span::hygiene::{MacroKind, SyntaxContext}; @@ -64,7 +64,7 @@ impl<'a> From> for ErrorKind<'a> { fn from(err: ResolutionFailure<'a>) -> Self { - ErrorKind::Resolve(Box::new(err)) + ErrorKind::Resolve(box err) } } @@ -98,14 +98,10 @@ } } - fn def_id(self) -> DefId { - self.opt_def_id().expect("called def_id() on a primitive") - } - - fn opt_def_id(self) -> Option { + fn def_id(self, tcx: TyCtxt<'_>) -> DefId { match self { - Res::Def(_, id) => Some(id), - Res::Primitive(_) => None, + Res::Def(_, id) => id, + Res::Primitive(prim) => *PrimitiveType::primitive_locations(tcx).get(&prim).unwrap(), } } @@ -237,10 +233,7 @@ /// link, Rustdoc disallows having a user-specified anchor. /// /// Most of the time this is fine, because you can just link to the page of - /// the item if you want to provide your own anchor. For primitives, though, - /// rustdoc uses the anchor as a side channel to know which page to link to; - /// it doesn't show up in the generated link. Ideally, rustdoc would remove - /// this limitation, allowing you to link to subheaders on primitives. + /// the item if you want to provide your own anchor. RustdocAnchorConflict(Res), } @@ -388,7 +381,7 @@ ty::AssocKind::Const => "associatedconstant", ty::AssocKind::Type => "associatedtype", }; - let fragment = format!("{}#{}.{}", prim_ty.as_sym(), out, item_name); + let fragment = format!("{}.{}", out, item_name); (Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id))) }) }) @@ -475,14 +468,6 @@ return handle_variant(self.cx, res, extra_fragment); } // Not a trait item; just return what we found. - Res::Primitive(ty) => { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure( - AnchorFailure::RustdocAnchorConflict(res), - )); - } - return Ok((res, Some(ty.as_sym().to_string()))); - } _ => return Ok((res, extra_fragment.clone())), } } @@ -517,6 +502,8 @@ let (res, fragment, side_channel) = self.resolve_associated_item(ty_res, item_name, ns, module_id)?; let result = if extra_fragment.is_some() { + // NOTE: can never be a primitive since `side_channel.is_none()` only when `res` + // is a trait (and the side channel DefId is always an associated item). let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r)); Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res))) } else { @@ -772,7 +759,7 @@ let mut resolver = cx.resolver.borrow_mut(); let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| { resolver.access(|resolver| { - let parent_scope = &ParentScope::module(resolver.get_module(module), resolver); + let parent_scope = &ParentScope::module(resolver.expect_module(module), resolver); resolver .traits_in_scope(None, parent_scope, SyntaxContext::root(), None) .into_iter() @@ -1152,7 +1139,7 @@ module_id = DefId { krate, index: CRATE_DEF_INDEX }; } - let (mut res, mut fragment) = self.resolve_with_disambiguator_cached( + let (mut res, fragment) = self.resolve_with_disambiguator_cached( ResolutionInfo { module_id, dis: disambiguator, @@ -1174,16 +1161,7 @@ if let Some(prim) = resolve_primitive(path_str, TypeNS) { // `prim@char` if matches!(disambiguator, Some(Disambiguator::Primitive)) { - if fragment.is_some() { - anchor_failure( - self.cx, - diag_info, - AnchorFailure::RustdocAnchorConflict(prim), - ); - return None; - } res = prim; - fragment = Some(prim.name(self.cx.tcx).to_string()); } else { // `[char]` when a `char` module is in scope let candidates = vec![res, prim]; @@ -1303,12 +1281,17 @@ } } - Some(ItemLink { link: ori_link.link, link_text, did: None, fragment }) + Some(ItemLink { + link: ori_link.link, + link_text, + did: res.def_id(self.cx.tcx), + fragment, + }) } Res::Def(kind, id) => { verify(kind, id)?; let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id)); - Some(ItemLink { link: ori_link.link, link_text, did: Some(id), fragment }) + Some(ItemLink { link: ori_link.link, link_text, did: id, fragment }) } } } @@ -1323,7 +1306,7 @@ if let Some(ref cached) = self.visited_links.get(&key) { match cached { Some(cached) => { - self.kind_side_channel.set(cached.side_channel.clone()); + self.kind_side_channel.set(cached.side_channel); return Some(cached.res.clone()); } None if cache_resolution_failure => return None, @@ -2069,8 +2052,11 @@ diag.span_label(sp, "invalid anchor"); } if let AnchorFailure::RustdocAnchorConflict(Res::Primitive(_)) = failure { - diag.note("this restriction may be lifted in a future release"); - diag.note("see https://github.com/rust-lang/rust/issues/83083 for more information"); + if let Some(sp) = sp { + span_bug!(sp, "anchors should be allowed now"); + } else { + bug!("anchors should be allowed now"); + } } }); } @@ -2198,10 +2184,11 @@ use rustc_middle::ty::DefIdTree; if extra_fragment.is_some() { + // NOTE: `res` can never be a primitive since this function is only called when `tcx.def_kind(res) == DefKind::Variant`. return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))); } cx.tcx - .parent(res.def_id()) + .parent(res.def_id(cx.tcx)) .map(|parent| { let parent_def = Res::Def(DefKind::Enum, parent); let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/collect_trait_impls.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/collect_trait_impls.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/collect_trait_impls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/collect_trait_impls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -57,7 +57,9 @@ // scan through included items ahead of time to splice in Deref targets to the "valid" sets for it in &new_items { if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind { - if cleaner.keep_impl(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() { + if cleaner.keep_impl(for_) + && trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait() + { let target = items .iter() .find_map(|item| match *item.kind { @@ -78,7 +80,9 @@ new_items.retain(|it| { if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind { cleaner.keep_impl(for_) - || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t)) + || trait_ + .as_ref() + .map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into())) || blanket_impl.is_some() } else { true diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/doc_test_lints.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/doc_test_lints.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/doc_test_lints.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/doc_test_lints.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -//! This pass is overloaded and runs two different lints. -//! -//! - MISSING_DOC_CODE_EXAMPLES: this lint is **UNSTABLE** and looks for public items missing doctests -//! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doctests. - -use super::Pass; -use crate::clean; -use crate::clean::*; -use crate::core::DocContext; -use crate::fold::DocFolder; -use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; -use crate::visit_ast::inherits_doc_hidden; -use rustc_middle::lint::LintLevelSource; -use rustc_session::lint; -use rustc_span::symbol::sym; - -crate const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { - name: "check-private-items-doc-tests", - run: check_private_items_doc_tests, - description: "check private items doc tests", -}; - -struct PrivateItemDocTestLinter<'a, 'tcx> { - cx: &'a mut DocContext<'tcx>, -} - -crate fn check_private_items_doc_tests(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut coll = PrivateItemDocTestLinter { cx }; - - coll.fold_crate(krate) -} - -impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option { - let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); - - look_for_tests(self.cx, &dox, &item); - - Some(self.fold_item_recur(item)) - } -} - -pub(crate) struct Tests { - pub(crate) found_tests: usize, -} - -impl crate::doctest::Tester for Tests { - fn add_test(&mut self, _: String, config: LangString, _: usize) { - if config.rust && config.ignore == Ignore::None { - self.found_tests += 1; - } - } -} - -crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { - if !cx.cache.access_levels.is_public(item.def_id.expect_def_id()) - || matches!( - *item.kind, - clean::StructFieldItem(_) - | clean::VariantItem(_) - | clean::AssocConstItem(_, _) - | clean::AssocTypeItem(_, _) - | clean::TypedefItem(_, _) - | clean::StaticItem(_) - | clean::ConstantItem(_) - | clean::ExternCrateItem { .. } - | clean::ImportItem(_) - | clean::PrimitiveItem(_) - | clean::KeywordItem(_) - ) - { - return false; - } - // The `expect_def_id()` should be okay because `local_def_id_to_hir_id` - // would presumably panic if a fake `DefIndex` were passed. - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_def_id().expect_local()); - if cx.tcx.hir().attrs(hir_id).lists(sym::doc).has_word(sym::hidden) - || inherits_doc_hidden(cx.tcx, hir_id) - { - return false; - } - let (level, source) = cx.tcx.lint_level_at_node(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id); - level != lint::Level::Allow || matches!(source, LintLevelSource::Default) -} - -crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { - let hir_id = match DocContext::as_local_hir_id(cx.tcx, item.def_id) { - Some(hir_id) => hir_id, - None => { - // If non-local, no need to check anything. - return; - } - }; - - let mut tests = Tests { found_tests: 0 }; - - find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); - - if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() { - if should_have_doc_example(cx, &item) { - debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); - let sp = item.attr_span(cx.tcx); - cx.tcx.struct_span_lint_hir( - crate::lint::MISSING_DOC_CODE_EXAMPLES, - hir_id, - sp, - |lint| lint.build("missing code example in this documentation").emit(), - ); - } - } else if tests.found_tests > 0 - && !cx.cache.access_levels.is_public(item.def_id.expect_def_id()) - { - cx.tcx.struct_span_lint_hir( - crate::lint::PRIVATE_DOC_TESTS, - hir_id, - item.attr_span(cx.tcx), - |lint| lint.build("documentation test in private item").emit(), - ); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/html_tags.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/html_tags.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/html_tags.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/html_tags.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use crate::html::markdown::opts; +use crate::html::markdown::main_body_opts; use core::ops::Range; use pulldown_cmark::{Event, Parser, Tag}; use std::iter::Peekable; @@ -52,7 +52,7 @@ continue; } let last_tag_name_low = last_tag_name.to_lowercase(); - if ALLOWED_UNCLOSED.iter().any(|&at| at == last_tag_name_low) { + if ALLOWED_UNCLOSED.contains(&last_tag_name_low.as_str()) { continue; } // `tags` is used as a queue, meaning that everything after `pos` is included inside it. @@ -192,7 +192,7 @@ let mut is_in_comment = None; let mut in_code_block = false; - let p = Parser::new_ext(&dox, opts()).into_offset_iter(); + let p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter(); for (event, range) in p { match event { @@ -207,7 +207,7 @@ for (tag, range) in tags.iter().filter(|(t, _)| { let t = t.to_lowercase(); - ALLOWED_UNCLOSED.iter().find(|&&at| at == t).is_none() + !ALLOWED_UNCLOSED.contains(&t.as_str()) }) { report_diag(&format!("unclosed HTML tag `{}`", tag), range); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/mod.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -33,8 +33,8 @@ crate mod collect_intra_doc_links; crate use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; -mod doc_test_lints; -crate use self::doc_test_lints::CHECK_PRIVATE_ITEMS_DOC_TESTS; +mod check_doc_test_visibility; +crate use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; mod collect_trait_impls; crate use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; @@ -79,7 +79,7 @@ /// The full list of passes. crate const PASSES: &[Pass] = &[ - CHECK_PRIVATE_ITEMS_DOC_TESTS, + CHECK_DOC_TEST_VISIBILITY, STRIP_HIDDEN, UNINDENT_COMMENTS, STRIP_PRIVATE, @@ -97,7 +97,7 @@ crate const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(UNINDENT_COMMENTS), - ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS), + ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/stripper.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/stripper.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/passes/stripper.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/passes/stripper.rs 2021-11-29 19:27:11.000000000 +0000 @@ -128,13 +128,13 @@ return None; } if let Some(did) = imp.for_.def_id() { - if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did.into()) + if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into()) { debug!("ImplStripper: impl item for stripped type; removing"); return None; } } - if let Some(did) = imp.trait_.def_id() { + if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) { if did.is_local() && !self.retained.contains(&did.into()) { debug!("ImplStripper: impl item for stripped trait; removing"); return None; diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/visit_ast.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/visit_ast.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/visit_ast.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/visit_ast.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,6 +6,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::Node; +use rustc_hir::CRATE_HIR_ID; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span; @@ -15,7 +16,7 @@ use std::mem; -use crate::clean::{self, AttributesExt, NestedAttributesExt}; +use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt}; use crate::core; use crate::doctree::*; @@ -71,12 +72,12 @@ self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did)); } - crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> { - let span = krate.module().inner; + crate fn visit(mut self) -> Module<'tcx> { + let span = self.cx.tcx.def_span(CRATE_DEF_ID); let mut top_level_module = self.visit_mod_contents( &Spanned { span, node: hir::VisibilityKind::Public }, hir::CRATE_HIR_ID, - &krate.module(), + self.cx.tcx.hir().root_module(), self.cx.tcx.crate_name(LOCAL_CRATE), ); @@ -105,6 +106,29 @@ } } } + + self.cx.cache.hidden_cfg = self + .cx + .tcx + .hir() + .attrs(CRATE_HIR_ID) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) + .filter(|attr| attr.has_name(sym::cfg_hide)) + .flat_map(|attr| { + attr.meta_item_list() + .unwrap_or(&[]) + .iter() + .filter_map(|attr| { + Cfg::parse(attr.meta_item()?) + .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) + .ok() + }) + .collect::>() + }) + .collect(); + self.cx.cache.exact_paths = self.exact_paths; top_level_module } diff -Nru rustc-1.56.0+dfsg1+llvm/src/librustdoc/visit_lib.rs rustc-1.57.0+dfsg1+llvm/src/librustdoc/visit_lib.rs --- rustc-1.56.0+dfsg1+llvm/src/librustdoc/visit_lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/librustdoc/visit_lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -67,7 +67,7 @@ } } - fn visit_item(&mut self, res: Res) { + fn visit_item(&mut self, res: Res) { let def_id = res.def_id(); let vis = self.tcx.visibility(def_id); let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { None }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/cmake/caches/Fuchsia.cmake rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/cmake/caches/Fuchsia.cmake --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/cmake/caches/Fuchsia.cmake 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/cmake/caches/Fuchsia.cmake 2021-11-16 16:47:26.000000000 +0000 @@ -32,7 +32,6 @@ set(CLANG_ENABLE_STATIC_ANALYZER ON CACHE BOOL "") set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "") -set(ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER ON CACHE BOOL "") set(ENABLE_LINKER_BUILD_ID ON CACHE BOOL "") set(ENABLE_X86_RELAX_RELOCATIONS ON CACHE BOOL "") diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/cmake/caches/Fuchsia-stage2.cmake rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/cmake/caches/Fuchsia-stage2.cmake --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/cmake/caches/Fuchsia-stage2.cmake 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/cmake/caches/Fuchsia-stage2.cmake 2021-11-16 16:47:26.000000000 +0000 @@ -41,7 +41,6 @@ set(CLANG_ENABLE_STATIC_ANALYZER ON CACHE BOOL "") set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "") -set(ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER ON CACHE BOOL "") set(ENABLE_LINKER_BUILD_ID ON CACHE BOOL "") set(ENABLE_X86_RELAX_RELOCATIONS ON CACHE BOOL "") diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/docs/OpenCLSupport.rst rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/docs/OpenCLSupport.rst --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/docs/OpenCLSupport.rst 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/docs/OpenCLSupport.rst 2021-11-16 16:47:26.000000000 +0000 @@ -362,41 +362,43 @@ The following table provides an overview of features in OpenCL C 3.0 and their implementation status. -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Category | Feature | Status | Reviews | -+==============================+==============================================================+======================+===========================================================================+ -| Command line interface | New value for ``-cl-std`` flag | :good:`done` | https://reviews.llvm.org/D88300 | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Predefined macros | New version macro | :good:`done` | https://reviews.llvm.org/D88300 | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Predefined macros | Feature macros | :good:`done` | https://reviews.llvm.org/D95776 | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | Generic address space | :none:`worked on` | https://reviews.llvm.org/D95778 (partial frontend) | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | Builtin function overloads with generic address space | :part:`worked on` | https://reviews.llvm.org/D92004 | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | Program scope variables in global memory | :none:`unclaimed` | | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | 3D image writes including builtin functions | :none:`unclaimed` | | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | read_write images including builtin functions | :none:`unclaimed` | | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | C11 atomics memory scopes, ordering and builtin function | :part:`worked on` | https://reviews.llvm.org/D92004 (functions only) | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | Device-side kernel enqueue including builtin functions | :none:`unclaimed` | | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | Pipes including builtin functions | :part:`worked on` | https://reviews.llvm.org/D92004 (functions only) | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | Work group collective functions | :part:`worked on` | https://reviews.llvm.org/D92004 | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| Feature optionality | Image types | :part:`unclaimed` | | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| New functionality | RGBA vector components | :good:`done` | https://reviews.llvm.org/D99969 | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| New functionality | Subgroup functions | :part:`worked on` | https://reviews.llvm.org/D92004 | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ -| New functionality | Atomic mem scopes: subgroup, all devices including functions | :part:`worked on` | https://reviews.llvm.org/D92004 (functions only) | -+------------------------------+--------------------------------------------------------------+----------------------+---------------------------------------------------------------------------+ ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Category | Feature | Status | Reviews | ++==============================+=========================+=========================================+======================+==============================================================================================+ +| Command line interface | New value for ``-cl-std`` flag | :good:`done` | https://reviews.llvm.org/D88300 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Predefined macros | New version macro | :good:`done` | https://reviews.llvm.org/D88300 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Predefined macros | Feature macros | :good:`done` | https://reviews.llvm.org/D95776 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | Generic address space | :good:`done` | https://reviews.llvm.org/D95778 and https://reviews.llvm.org/D103401 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | Builtin function overloads with generic address space | :good:`done` | https://reviews.llvm.org/D105526 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | Program scope variables in global memory | :good:`done` | https://reviews.llvm.org/D103191 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | 3D image writes including builtin functions | :part:`worked on` | https://reviews.llvm.org/D106260 (frontend) | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | read_write images including builtin functions | :part:`worked on` | https://reviews.llvm.org/D104915 (frontend) and https://reviews.llvm.org/D107539 (functions) | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | C11 atomics memory scopes, ordering and builtin function | :good:`done` | https://reviews.llvm.org/D106111 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | Blocks and Device-side kernel enqueue including builtin functions | :none:`unclaimed` | | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | Pipes including builtin functions | :part:`worked on` | https://reviews.llvm.org/D107154 (frontend) and https://reviews.llvm.org/D105858 (functions) | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | Work group collective builtin functions | :part:`worked on` | https://reviews.llvm.org/D105858 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | Image types and builtin functions | :good:`done` | https://reviews.llvm.org/D103911 (frontend) and https://reviews.llvm.org/D107539 (functions) | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| Feature optionality | Double precision floating point type | :good:`done` | https://reviews.llvm.org/D96524 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| New functionality | RGBA vector components | :good:`done` | https://reviews.llvm.org/D99969 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| New functionality | Subgroup functions | :part:`worked on` | https://reviews.llvm.org/D105858 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ +| New functionality | Atomic mem scopes: subgroup, all devices including functions | :part:`worked on` | https://reviews.llvm.org/D103241 | ++------------------------------+-------------------------+-----------------------------------------+----------------------+----------------------------------------------------------------------------------------------+ .. _opencl_experimenal: diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/docs/ReleaseNotes.rst rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/docs/ReleaseNotes.rst --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/docs/ReleaseNotes.rst 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/docs/ReleaseNotes.rst 2021-11-16 16:47:26.000000000 +0000 @@ -63,7 +63,7 @@ ------------------------------------------------- - The default value of _MSC_VER was raised from 1911 to 1914. MSVC 19.14 has the - support to overaligned objects on x86_32 which is required for some LLVM + support to overaligned objects on x86_32 which is required for some LLVM passes. New Compiler Flags @@ -72,6 +72,9 @@ - ``-Wreserved-identifier`` emits warning when user code uses reserved identifiers. +- ``Wunused-but-set-parameter`` and ``-Wunused-but-set-variable`` emit warnings + when a parameter or a variable is set but not used. + - ``-fstack-usage`` generates an extra .su file per input source file. The .su file contains frame size information for each function defined in the source file. @@ -123,6 +126,9 @@ Windows Support --------------- +- Fixed reading ``long double`` arguments with ``va_arg`` on x86_64 MinGW + targets. + C Language Changes in Clang --------------------------- @@ -147,10 +153,85 @@ Objective-C Language Changes in Clang ------------------------------------- -OpenCL C Language Changes in Clang ----------------------------------- +OpenCL Kernel Language Changes in Clang +--------------------------------------- -... + +Command-line interface changes: + +- All builtin types, macros and function declarations are now added by default + without any command-line flags. A flag is provided ``-cl-no-stdinc`` to + suppress the default declarations non-native to the compiler. + +- Clang now compiles using OpenCL C version 1.2 by default if no version is + specified explicitly from the command line. + +- Clang now supports ``.clcpp`` file extension for sources written in + C++ for OpenCL. + +- Clang now accepts ``-cl-std=clc++1.0`` that sets C++ for OpenCL to + the version 1.0 explicitly. + +Misc common changes: + +- Added ``NULL`` definition in internal headers for standards prior to the + version 2.0. + +- Simplified use of pragma in extensions for ``double``, images, atomics, + subgroups, Arm dot product extension. There are less cases where extension + pragma is now required by clang to compile kernel sources. + +- Added missing ``as_size``/``as_ptrdiff``/``as_intptr``/``as_uintptr_t`` + operators to internal headers. + +- Added new builtin function for ndrange, ``cl_khr_subgroup_extended_types``, + ``cl_khr_subgroup_non_uniform_vote``, ``cl_khr_subgroup_ballot``, + ``cl_khr_subgroup_non_uniform_arithmetic``, ``cl_khr_subgroup_shuffle``, + ``cl_khr_subgroup_shuffle_relative``, ``cl_khr_subgroup_clustered_reduce`` + into the default Tablegen-based header. + +- Added online documentation for Tablegen-based header, OpenCL 3.0 support, + new clang extensions. + +- Fixed OpenCL C language version and SPIR address space reporting in DWARF. + +New extensions: + +- ``cl_khr_integer_dot_product`` for dedicated support of dot product. + +- ``cl_khr_extended_bit_ops`` for dedicated support of extra binary operations. + +- ``__cl_clang_bitfields`` for use of bit-fields in the kernel code. + +- ``__cl_clang_non_portable_kernel_param_types`` for relaxing some restrictions + to types of kernel parameters. + +OpenCL C 3.0 related changes: + +- Added parsing support for the optionality of generic address space, images + (including 3d writes and ``read_write`` access qualifier), pipes, program + scope variables, double-precision floating-point support. + +- Added optionality support for builtin functions (in ``opencl-c.h`` header) + for generic address space, C11 atomics. + +- Added ``memory_scope_all_devices`` enum for the atomics in internal headers. + +- Enabled use of ``.rgba`` vector components. + +C++ for OpenCL related changes: + +- Added ``__remove_address_space`` metaprogramming utility in internal headers + to allow removing address spaces from types. + +- Improved overloads resolution logic for constructors wrt address spaces. + +- Improved diagnostics of OpenCL specific types and address space qualified + types in ``reinterpret_cast`` and template functions. + +- Fixed ``NULL`` macro in internal headers to be compatible with C++. + +- Fixed use of ``half`` type. ABI Changes in Clang -------------------- @@ -158,6 +239,26 @@ OpenMP Support in Clang ----------------------- +- Support for loop transformation directives from OpenMP 5.1 have been added. + ``#pragma omp unroll`` is a standardized alternative to ``#pragma unroll`` + (or ``#pragma clang loop unroll(enable)``) but also allows composition with + other OpenMP loop associated constructs as in + + .. code-block:: c + + #pragma omp parallel for + #pragma omp unroll partial(4) + for (int i = 0; i < n; ++i) + + ``#pragma omp tile`` applies tiling to a perfect loop nest using a + user-defined tile size. + + .. code-block:: c + + #pragma omp tile sizes(8,8) + for (int i = 0; i < m; ++i) + for (int j = 0; j < n; ++j) + - ... CUDA Support in Clang @@ -287,12 +388,60 @@ libclang -------- -- ... +- Make libclang SONAME independent from LLVM version. It will be updated only when + needed. Defined in CLANG_SONAME (clang/tools/libclang/CMakeLists.txt). + `More details `_ Static Analyzer --------------- -- ... +.. 2407eb08a574 [analyzer] Update static analyzer to be support sarif-html + +- Add a new analyzer output type, ``sarif-html``, that outputs both HTML and + Sarif files. + +.. 90377308de6c [analyzer] Support allocClassWithName in OSObjectCStyleCast checker + +- Add support for ``allocClassWithName`` in OSObjectCStyleCast checker. + +.. cad9b7f708e2b2d19d7890494980c5e427d6d4ea: Print time taken to analyze each function + +- The option ``-analyzer-display-progress`` now also outputs analysis time for + each function. + +.. 9e02f58780ab8734e5d27a0138bd477d18ae64a1 [analyzer] Highlight arrows for currently selected event + +- For bug reports in HTML format, arrows are now highlighted for the currently + selected event. + +.. Deep Majumder's GSoC'21 +.. 80068ca6232b [analyzer] Fix for faulty namespace test in SmartPtrModelling +.. d825309352b4 [analyzer] Handle std::make_unique +.. 0cd98bef1b6f [analyzer] Handle std::swap for std::unique_ptr +.. 13fe78212fe7 [analyzer] Handle << operator for std::unique_ptr +.. 48688257c52d [analyzer] Model comparision methods of std::unique_ptr +.. f8d3f47e1fd0 [analyzer] Updated comments to reflect D85817 +.. 21daada95079 [analyzer] Fix static_cast on pointer-to-member handling + +- While still in alpha, ``alpha.cplusplus.SmartPtr`` received numerous + improvements and nears production quality. + +.. 21daada95079 [analyzer] Fix static_cast on pointer-to-member handling +.. 170c67d5b8cc [analyzer] Use the MacroExpansionContext for macro expansions in plists +.. 02b51e5316cd [analyzer][solver] Redesign constraint ranges data structure +.. 3085bda2b348 [analyzer][solver] Fix infeasible constraints (PR49642) +.. 015c39882ebc [Analyzer] Infer 0 value when the divisible is 0 (bug fix) +.. 90377308de6c [analyzer] Support allocClassWithName in OSObjectCStyleCast checker +.. df64f471d1e2 [analyzer] DynamicSize: Store the dynamic size +.. e273918038a7 [analyzer] Track leaking object through stores +.. 61ae2db2d7a9 [analyzer] Adjust the reported variable name in retain count checker +.. 50f17e9d3139 [analyzer] RetainCountChecker: Disable reference counting for OSMetaClass. + +- Various fixes and improvements, including modeling of casts (such as + ``std::bit_cast<>``), constraint solving, explaining bug-causing variable + values, macro expansion notes, modeling the size of dynamic objects and the + modeling and reporting of Objective C/C++ retain count related bugs. These + should reduce false positives and make the remaining reports more readable. .. _release-notes-ubsan: diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/docs/UsersManual.rst rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/docs/UsersManual.rst --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/docs/UsersManual.rst 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/docs/UsersManual.rst 2021-11-16 16:47:26.000000000 +0000 @@ -1260,50 +1260,8 @@ Controlling Floating Point Behavior ----------------------------------- -Clang provides a number of ways to control floating point behavior, including -with command line options and source pragmas. This section -describes the various floating point semantic modes and the corresponding options. - -.. csv-table:: Floating Point Semantic Modes - :header: "Mode", "Values" - :widths: 15, 30, 30 - - "except_behavior", "{ignore, strict, may_trap}", "ffp-exception-behavior" - "fenv_access", "{off, on}", "(none)" - "rounding_mode", "{dynamic, tonearest, downward, upward, towardzero}", "frounding-math" - "contract", "{on, off, fast}", "ffp-contract" - "denormal_fp_math", "{IEEE, PreserveSign, PositiveZero}", "fdenormal-fp-math" - "denormal_fp32_math", "{IEEE, PreserveSign, PositiveZero}", "fdenormal-fp-math-fp32" - "support_math_errno", "{on, off}", "fmath-errno" - "no_honor_nans", "{on, off}", "fhonor-nans" - "no_honor_infinities", "{on, off}", "fhonor-infinities" - "no_signed_zeros", "{on, off}", "fsigned-zeros" - "allow_reciprocal", "{on, off}", "freciprocal-math" - "allow_approximate_fns", "{on, off}", "(none)" - "allow_reassociation", "{on, off}", "fassociative-math" - - -This table describes the option settings that correspond to the three -floating point semantic models: precise (the default), strict, and fast. - - -.. csv-table:: Floating Point Models - :header: "Mode", "Precise", "Strict", "Fast" - :widths: 25, 15, 15, 15 - - "except_behavior", "ignore", "strict", "ignore" - "fenv_access", "off", "on", "off" - "rounding_mode", "tonearest", "dynamic", "tonearest" - "contract", "on", "off", "fast" - "denormal_fp_math", "IEEE", "IEEE", "PreserveSign" - "denormal_fp32_math", "IEEE","IEEE", "PreserveSign" - "support_math_errno", "on", "on", "off" - "no_honor_nans", "off", "off", "on" - "no_honor_infinities", "off", "off", "on" - "no_signed_zeros", "off", "off", "on" - "allow_reciprocal", "off", "off", "on" - "allow_approximate_fns", "off", "off", "on" - "allow_reassociation", "off", "off", "on" +Clang provides a number of ways to control floating point behavior. The options +are listed below. .. option:: -ffast-math @@ -1498,7 +1456,7 @@ and ``fast``. Details: - * ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``-ffp-contract=on``). This is the default behavior. + * ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``-ffp-contract=fast``). This is the default behavior. * ``strict`` Enables ``-frounding-math`` and ``-ffp-exception-behavior=strict``, and disables contractions (FMA). All of the ``-ffast-math`` enablements are disabled. Enables ``STDC FENV_ACCESS``: by default ``FENV_ACCESS`` is disabled. This option setting behaves as though ``#pragma STDC FENV_ACESS ON`` appeared at the top of the source file. * ``fast`` Behaves identically to specifying both ``-ffast-math`` and ``ffp-contract=fast`` diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/include/clang/Basic/BuiltinsAArch64.def rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/include/clang/Basic/BuiltinsAArch64.def --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/include/clang/Basic/BuiltinsAArch64.def 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/include/clang/Basic/BuiltinsAArch64.def 2021-11-16 16:47:26.000000000 +0000 @@ -243,6 +243,9 @@ TARGET_HEADER_BUILTIN(_WriteStatusReg, "viLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_AddressOfReturnAddress, "v*", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__mulh, "SLLiSLLiSLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") + #undef BUILTIN #undef LANGBUILTIN #undef TARGET_HEADER_BUILTIN diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/include/clang/Sema/Initialization.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/include/clang/Sema/Initialization.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/include/clang/Sema/Initialization.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/include/clang/Sema/Initialization.h 2021-11-16 16:47:26.000000000 +0000 @@ -298,8 +298,8 @@ /// Create the initialization entity for the result of a function. static InitializedEntity InitializeResult(SourceLocation ReturnLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); + QualType Type) { + return InitializedEntity(EK_Result, ReturnLoc, Type); } static InitializedEntity InitializeStmtExprResult(SourceLocation ReturnLoc, @@ -308,20 +308,20 @@ } static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); + QualType Type) { + return InitializedEntity(EK_BlockElement, BlockVarLoc, Type); } static InitializedEntity InitializeLambdaToBlock(SourceLocation BlockVarLoc, - QualType Type, bool NRVO) { + QualType Type) { return InitializedEntity(EK_LambdaToBlockConversionBlockElement, - BlockVarLoc, Type, NRVO); + BlockVarLoc, Type); } /// Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); + QualType Type) { + return InitializedEntity(EK_Exception, ThrowLoc, Type); } /// Create the initialization entity for an object allocated via new. diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Analysis/ThreadSafety.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Analysis/ThreadSafety.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Analysis/ThreadSafety.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Analysis/ThreadSafety.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1050,7 +1050,7 @@ const CFGBlock* PredBlock, const CFGBlock *CurrBlock); - bool join(const FactEntry &a, const FactEntry &b); + bool join(const FactEntry &a, const FactEntry &b, bool CanModify); void intersectAndWarn(FactSet &EntrySet, const FactSet &ExitSet, SourceLocation JoinLoc, LockErrorKind EntryLEK, @@ -2188,25 +2188,28 @@ } } -/// Given two facts merging on a join point, decide whether to warn and which -/// one to keep. +/// Given two facts merging on a join point, possibly warn and decide whether to +/// keep or replace. /// -/// \return false if we should keep \p A, true if we should keep \p B. -bool ThreadSafetyAnalyzer::join(const FactEntry &A, const FactEntry &B) { +/// \param CanModify Whether we can replace \p A by \p B. +/// \return false if we should keep \p A, true if we should take \p B. +bool ThreadSafetyAnalyzer::join(const FactEntry &A, const FactEntry &B, + bool CanModify) { if (A.kind() != B.kind()) { // For managed capabilities, the destructor should unlock in the right mode // anyway. For asserted capabilities no unlocking is needed. if ((A.managed() || A.asserted()) && (B.managed() || B.asserted())) { - // The shared capability subsumes the exclusive capability. - return B.kind() == LK_Shared; - } else { - Handler.handleExclusiveAndShared("mutex", B.toString(), B.loc(), A.loc()); - // Take the exclusive capability to reduce further warnings. - return B.kind() == LK_Exclusive; - } + // The shared capability subsumes the exclusive capability, if possible. + bool ShouldTakeB = B.kind() == LK_Shared; + if (CanModify || !ShouldTakeB) + return ShouldTakeB; + } + Handler.handleExclusiveAndShared("mutex", B.toString(), B.loc(), A.loc()); + // Take the exclusive capability to reduce further warnings. + return CanModify && B.kind() == LK_Exclusive; } else { // The non-asserted capability is the one we want to track. - return A.asserted() && !B.asserted(); + return CanModify && A.asserted() && !B.asserted(); } } @@ -2237,8 +2240,8 @@ FactSet::iterator EntryIt = EntrySet.findLockIter(FactMan, ExitFact); if (EntryIt != EntrySet.end()) { - if (join(FactMan[*EntryIt], ExitFact) && - EntryLEK == LEK_LockedSomePredecessors) + if (join(FactMan[*EntryIt], ExitFact, + EntryLEK != LEK_LockedSomeLoopIterations)) *EntryIt = Fact; } else if (!ExitFact.managed()) { ExitFact.handleRemovalFromIntersection(ExitSet, FactMan, JoinLoc, diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/AST/ASTContext.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/AST/ASTContext.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/AST/ASTContext.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/AST/ASTContext.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -9653,11 +9653,19 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, bool Unqualified, bool BlockReturnType) { + // For C++ we will not reach this code with reference types (see below), + // for OpenMP variant call overloading we might. + // // C++ [expr]: If an expression initially has the type "reference to T", the // type is adjusted to "T" prior to any further analysis, the expression // designates the object or function denoted by the reference, and the // expression is an lvalue unless the reference is an rvalue reference and // the expression is a function call (possibly inside parentheses). + if (LangOpts.OpenMP && LHS->getAs() && + RHS->getAs() && LHS->getTypeClass() == RHS->getTypeClass()) + return mergeTypes(LHS->getAs()->getPointeeType(), + RHS->getAs()->getPointeeType(), + OfBlockPointer, Unqualified, BlockReturnType); if (LHS->getAs() || RHS->getAs()) return {}; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/AST/ExprConstant.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/AST/ExprConstant.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/AST/ExprConstant.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/AST/ExprConstant.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -9931,10 +9931,19 @@ return false; // Avoid materializing a temporary for an elidable copy/move constructor. - if (E->isElidable() && !ZeroInit) - if (const MaterializeTemporaryExpr *ME - = dyn_cast(E->getArg(0))) + if (E->isElidable() && !ZeroInit) { + // FIXME: This only handles the simplest case, where the source object + // is passed directly as the first argument to the constructor. + // This should also handle stepping though implicit casts and + // and conversion sequences which involve two steps, with a + // conversion operator followed by a converting constructor. + const Expr *SrcObj = E->getArg(0); + assert(SrcObj->isTemporaryObject(Info.Ctx, FD->getParent())); + assert(Info.Ctx.hasSameUnqualifiedType(E->getType(), SrcObj->getType())); + if (const MaterializeTemporaryExpr *ME = + dyn_cast(SrcObj)) return Visit(ME->getSubExpr()); + } if (ZeroInit && !ZeroInitialization(E, T)) return false; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Basic/Targets/OSTargets.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Basic/Targets/OSTargets.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Basic/Targets/OSTargets.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Basic/Targets/OSTargets.h 2021-11-16 16:47:26.000000000 +0000 @@ -460,6 +460,11 @@ Builder.defineMacro("_REENTRANT"); if (this->HasFloat128) Builder.defineMacro("__FLOAT128__"); + + if (Opts.C11) { + Builder.defineMacro("__STDC_NO_ATOMICS__"); + Builder.defineMacro("__STDC_NO_THREADS__"); + } } public: diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -9732,6 +9732,29 @@ return Builder.CreateCall(F); } + if (BuiltinID == AArch64::BI__mulh || BuiltinID == AArch64::BI__umulh) { + llvm::Type *ResType = ConvertType(E->getType()); + llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128); + + bool IsSigned = BuiltinID == AArch64::BI__mulh; + Value *LHS = + Builder.CreateIntCast(EmitScalarExpr(E->getArg(0)), Int128Ty, IsSigned); + Value *RHS = + Builder.CreateIntCast(EmitScalarExpr(E->getArg(1)), Int128Ty, IsSigned); + + Value *MulResult, *HigherBits; + if (IsSigned) { + MulResult = Builder.CreateNSWMul(LHS, RHS); + HigherBits = Builder.CreateAShr(MulResult, 64); + } else { + MulResult = Builder.CreateNUWMul(LHS, RHS); + HigherBits = Builder.CreateLShr(MulResult, 64); + } + HigherBits = Builder.CreateIntCast(HigherBits, ResType, IsSigned); + + return HigherBits; + } + // Handle MSVC intrinsics before argument evaluation to prevent double // evaluation. if (Optional MsvcIntId = translateAarch64ToMsvcIntrin(BuiltinID)) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGExprCXX.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGExprCXX.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGExprCXX.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGExprCXX.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -609,15 +609,18 @@ return; // Elide the constructor if we're constructing from a temporary. - // The temporary check is required because Sema sets this on NRVO - // returns. if (getLangOpts().ElideConstructors && E->isElidable()) { - assert(getContext().hasSameUnqualifiedType(E->getType(), - E->getArg(0)->getType())); - if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) { - EmitAggExpr(E->getArg(0), Dest); - return; - } + // FIXME: This only handles the simplest case, where the source object + // is passed directly as the first argument to the constructor. + // This should also handle stepping though implicit casts and + // conversion sequences which involve two steps, with a + // conversion operator followed by a converting constructor. + const Expr *SrcObj = E->getArg(0); + assert(SrcObj->isTemporaryObject(getContext(), CD->getParent())); + assert( + getContext().hasSameUnqualifiedType(E->getType(), SrcObj->getType())); + EmitAggExpr(SrcObj, Dest); + return; } if (const ArrayType *arrayType diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGOpenMPRuntime.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGOpenMPRuntime.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGOpenMPRuntime.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/CodeGen/CGOpenMPRuntime.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -2120,11 +2120,12 @@ OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); // Ensure we do not inline the function. This is trivially true for the ones - // passed to __kmpc_fork_call but the ones calles in serialized regions + // passed to __kmpc_fork_call but the ones called in serialized regions // could be inlined. This is not a perfect but it is closer to the invariant // we want, namely, every data environment starts with a new function. // TODO: We should pass the if condition to the runtime function and do the // handling there. Much cleaner code. + OutlinedFn->removeFnAttr(llvm::Attribute::AlwaysInline); OutlinedFn->addFnAttr(llvm::Attribute::NoInline); RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/Driver.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/Driver.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/Driver.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/Driver.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -5568,7 +5568,6 @@ if (!Arg.startswith(OptName)) continue; Opt = Arg; - break; } if (Opt.empty()) Opt = ToolChain::getTargetAndModeFromProgramName(ProgName).DriverMode; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -893,3 +893,38 @@ return true; return false; } + +llvm::SmallVector +ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, + const std::string &GPUArch) const { + auto Kind = llvm::AMDGPU::parseArchAMDGCN(GPUArch); + const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); + + std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); + if (LibDeviceFile.empty()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GPUArch; + return {}; + } + + // If --hip-device-lib is not set, add the default bitcode libraries. + // TODO: There are way too many flags that change this. Do we need to check + // them all? + bool DAZ = DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero, + options::OPT_fno_gpu_flush_denormals_to_zero, + getDefaultDenormsAreZeroForTarget(Kind)); + bool FiniteOnly = DriverArgs.hasFlag( + options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, false); + bool UnsafeMathOpt = + DriverArgs.hasFlag(options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, false); + bool FastRelaxedMath = DriverArgs.hasFlag(options::OPT_ffast_math, + options::OPT_fno_fast_math, false); + bool CorrectSqrt = DriverArgs.hasFlag( + options::OPT_fhip_fp32_correctly_rounded_divide_sqrt, + options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt); + bool Wave64 = isWave64(DriverArgs, Kind); + + return RocmInstallation.getCommonBitcodeLibs( + DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, + FastRelaxedMath, CorrectSqrt); +} \ No newline at end of file diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h 2021-11-16 16:47:26.000000000 +0000 @@ -136,6 +136,11 @@ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + + // Returns a list of device library names shared by different languages + llvm::SmallVector + getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, + const std::string &GPUArch) const; }; } // end namespace toolchains diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -9,12 +9,14 @@ #include "AMDGPUOpenMP.h" #include "AMDGPU.h" #include "CommonArgs.h" +#include "ToolChains/ROCm.h" #include "clang/Basic/DiagnosticDriver.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" @@ -84,14 +86,34 @@ } // namespace const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const ArgList &Args, StringRef SubArchName, - StringRef OutputFilePrefix) const { + const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, + const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, + StringRef SubArchName, StringRef OutputFilePrefix) const { ArgStringList CmdArgs; for (const auto &II : Inputs) if (II.isFilename()) CmdArgs.push_back(II.getFilename()); + + if (Args.hasArg(options::OPT_l)) { + auto Lm = Args.getAllArgValues(options::OPT_l); + bool HasLibm = false; + for (auto &Lib : Lm) { + if (Lib == "m") { + HasLibm = true; + break; + } + } + + if (HasLibm) { + SmallVector BCLibs = + AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str()); + llvm::for_each(BCLibs, [&](StringRef BCFile) { + CmdArgs.push_back(Args.MakeArgString(BCFile)); + }); + } + } + // Add an intermediate output file. CmdArgs.push_back("-o"); const char *OutputFileName = @@ -180,8 +202,8 @@ assert(Prefix.length() && "no linker inputs are files "); // Each command outputs different files. - const char *LLVMLinkCommand = - constructLLVMLinkCommand(C, JA, Inputs, Args, GPUArch, Prefix); + const char *LLVMLinkCommand = constructLLVMLinkCommand( + AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix); // Produce readable assembly if save-temps is enabled. if (C.getDriver().isSaveTempsEnabled()) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h 2021-11-16 16:47:26.000000000 +0000 @@ -16,6 +16,10 @@ namespace clang { namespace driver { +namespace toolchains { +class AMDGPUOpenMPToolChain; +} + namespace tools { namespace AMDGCN { @@ -35,11 +39,11 @@ private: /// \return llvm-link output file name. - const char *constructLLVMLinkCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix) const; + const char *constructLLVMLinkCommand( + const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, + const JobAction &JA, const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, + llvm::StringRef OutputFilePrefix) const; /// \return llc output file name. const char *constructLlcCommand(Compilation &C, const JobAction &JA, diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1255,7 +1255,8 @@ // If we are offloading to a target via OpenMP we need to include the // openmp_wrappers folder which contains alternative system headers. if (JA.isDeviceOffloading(Action::OFK_OpenMP) && - getToolChain().getTriple().isNVPTX()){ + (getToolChain().getTriple().isNVPTX() || + getToolChain().getTriple().isAMDGCN())) { if (!Args.hasArg(options::OPT_nobuiltininc)) { // Add openmp_wrappers/* to our system include path. This lets us wrap // standard library headers. @@ -2637,7 +2638,7 @@ llvm::DenormalMode DenormalFPMath = DefaultDenormalFPMath; llvm::DenormalMode DenormalFP32Math = DefaultDenormalFP32Math; - StringRef FPContract = "on"; + StringRef FPContract = ""; bool StrictFPModel = false; @@ -2662,7 +2663,7 @@ ReciprocalMath = false; SignedZeros = true; // -fno_fast_math restores default denormal and fpcontract handling - FPContract = "on"; + FPContract = ""; DenormalFPMath = llvm::DenormalMode::getIEEE(); // FIXME: The target may have picked a non-IEEE default mode here based on @@ -2682,18 +2683,20 @@ // ffp-model= is a Driver option, it is entirely rewritten into more // granular options before being passed into cc1. // Use the gcc option in the switch below. - if (!FPModel.empty() && !FPModel.equals(Val)) + if (!FPModel.empty() && !FPModel.equals(Val)) { D.Diag(clang::diag::warn_drv_overriding_flag_option) << Args.MakeArgString("-ffp-model=" + FPModel) << Args.MakeArgString("-ffp-model=" + Val); + FPContract = ""; + } if (Val.equals("fast")) { optID = options::OPT_ffast_math; FPModel = Val; - FPContract = Val; + FPContract = "fast"; } else if (Val.equals("precise")) { optID = options::OPT_ffp_contract; FPModel = Val; - FPContract = "on"; + FPContract = "fast"; PreciseFPModel = true; } else if (Val.equals("strict")) { StrictFPModel = true; @@ -2779,11 +2782,9 @@ case options::OPT_ffp_contract: { StringRef Val = A->getValue(); if (PreciseFPModel) { - // When -ffp-model=precise is seen on the command line, - // the boolean PreciseFPModel is set to true which indicates - // "the current option is actually PreciseFPModel". The optID - // is changed to OPT_ffp_contract and FPContract is set to "on". - // the argument Val string is "precise": it shouldn't be checked. + // -ffp-model=precise enables ffp-contract=fast as a side effect + // the FPContract value has already been set to a string literal + // and the Val string isn't a pertinent value. ; } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) FPContract = Val; @@ -2881,17 +2882,18 @@ // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = DefaultDenormalFPMath; DenormalFP32Math = llvm::DenormalMode::getIEEE(); - FPContract = "on"; + FPContract = ""; break; } if (StrictFPModel) { // If -ffp-model=strict has been specified on command line but // subsequent options conflict then emit warning diagnostic. - if (HonorINFs && HonorNaNs && !AssociativeMath && !ReciprocalMath && - SignedZeros && TrappingMath && RoundingFPMath && - DenormalFPMath == llvm::DenormalMode::getIEEE() && - DenormalFP32Math == llvm::DenormalMode::getIEEE() && - FPContract.equals("off")) + if (HonorINFs && HonorNaNs && + !AssociativeMath && !ReciprocalMath && + SignedZeros && TrappingMath && RoundingFPMath && + (FPContract.equals("off") || FPContract.empty()) && + DenormalFPMath == llvm::DenormalMode::getIEEE() && + DenormalFP32Math == llvm::DenormalMode::getIEEE()) // OK: Current Arg doesn't conflict with -ffp-model=strict ; else { @@ -7690,8 +7692,11 @@ assert(CurTC == nullptr && "Expected one dependence!"); CurTC = TC; }); + UB += C.addTempFile( + C.getArgs().MakeArgString(CurTC->getInputFilename(Inputs[I]))); + } else { + UB += CurTC->getInputFilename(Inputs[I]); } - UB += CurTC->getInputFilename(Inputs[I]); } CmdArgs.push_back(TCArgs.MakeArgString(UB)); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -775,7 +775,8 @@ CmdArgs.push_back("-ldl"); // Required for backtrace on some OSes if (TC.getTriple().isOSFreeBSD() || - TC.getTriple().isOSNetBSD()) + TC.getTriple().isOSNetBSD() || + TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lexecinfo"); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -588,21 +588,43 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc) || - DriverArgs.hasArg(options::OPT_nostdlibinc)) + if (DriverArgs.hasArg(options::OPT_nostdinc)) return; + const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux(); + const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux(); + const Driver &D = getDriver(); - if (!D.SysRoot.empty()) { + SmallString<128> ResourceDirInclude(D.ResourceDir); + if (!IsELF) { + llvm::sys::path::append(ResourceDirInclude, "include"); + if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && + (!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc))) + addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); + } + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + const bool HasSysRoot = !D.SysRoot.empty(); + if (HasSysRoot) { SmallString<128> P(D.SysRoot); - if (getTriple().isMusl()) + if (IsLinuxMusl) llvm::sys::path::append(P, "usr/include"); else llvm::sys::path::append(P, "include"); + addExternCSystemInclude(DriverArgs, CC1Args, P.str()); - return; + // LOCAL_INCLUDE_DIR + addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include"); + // TOOL_INCLUDE_DIR + AddMultilibIncludeArgs(DriverArgs, CC1Args); } + if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl) + addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); + + if (HasSysRoot) + return; std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -395,35 +395,8 @@ } StringRef GpuArch = getGPUArch(DriverArgs); assert(!GpuArch.empty() && "Must have an explicit GPU arch."); - (void)GpuArch; - auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); - const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); - - std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); - if (LibDeviceFile.empty()) { - getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch; - return {}; - } // If --hip-device-lib is not set, add the default bitcode libraries. - // TODO: There are way too many flags that change this. Do we need to check - // them all? - bool DAZ = DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero, - options::OPT_fno_gpu_flush_denormals_to_zero, - getDefaultDenormsAreZeroForTarget(Kind)); - bool FiniteOnly = - DriverArgs.hasFlag(options::OPT_ffinite_math_only, - options::OPT_fno_finite_math_only, false); - bool UnsafeMathOpt = - DriverArgs.hasFlag(options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations, false); - bool FastRelaxedMath = DriverArgs.hasFlag( - options::OPT_ffast_math, options::OPT_fno_fast_math, false); - bool CorrectSqrt = DriverArgs.hasFlag( - options::OPT_fhip_fp32_correctly_rounded_divide_sqrt, - options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt); - bool Wave64 = isWave64(DriverArgs, Kind); - if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize, false)) { auto AsanRTL = RocmInstallation.getAsanRTLPath(); @@ -442,10 +415,8 @@ // Add the HIP specific bitcode library. BCLibs.push_back(RocmInstallation.getHIPPath().str()); - // Add the generic set of libraries. - BCLibs.append(RocmInstallation.getCommonBitcodeLibs( - DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, - FastRelaxedMath, CorrectSqrt)); + // Add common device libraries like ocml etc. + BCLibs.append(getCommonDeviceLibNames(DriverArgs, GpuArch.str())); // Add instrument lib. auto InstLib = diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -174,6 +174,11 @@ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + // Use the static OpenMP runtime with -static-openmp + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && + !Args.hasArg(options::OPT_static); + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); @@ -221,6 +226,8 @@ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); } + ToolChain.addProfileRTLibs(Args, CmdArgs); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Format/TokenAnnotator.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Format/TokenAnnotator.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Format/TokenAnnotator.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Format/TokenAnnotator.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -2398,7 +2398,7 @@ // This function heuristically determines whether 'Current' starts the name of a // function declaration. -static bool isFunctionDeclarationName(const FormatToken &Current, +static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, const AnnotatedLine &Line) { auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * { for (; Next; Next = Next->Next) { @@ -2476,14 +2476,21 @@ if (Next->MatchingParen->Next && Next->MatchingParen->Next->is(TT_PointerOrReference)) return true; - // Check for K&R C function definitions, e.g.: + + // Check for K&R C function definitions (and C++ function definitions with + // unnamed parameters), e.g.: // int f(i) // { // return i + 1; // } - if (Next->Next && Next->Next->is(tok::identifier) && - !(Next->MatchingParen->Next && Next->MatchingParen->Next->is(tok::semi))) + // bool g(size_t = 0, bool b = false) + // { + // return !b; + // } + if (IsCpp && Next->Next && Next->Next->is(tok::identifier) && + !Line.endsWith(tok::semi)) return true; + for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen; Tok = Tok->Next) { if (Tok->is(TT_TypeDeclarationParen)) @@ -2544,7 +2551,7 @@ calculateArrayInitializerColumnList(Line); while (Current) { - if (isFunctionDeclarationName(*Current, Line)) + if (isFunctionDeclarationName(Style.isCpp(), *Current, Line)) Current->setType(TT_FunctionDeclarationName); if (Current->is(TT_LineComment)) { if (Current->Previous->is(BK_BracedInit) && diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -994,6 +994,13 @@ Keywords.kw_import, tok::kw_export); } +// Checks whether a token is a type in K&R C (aka C78). +static bool isC78Type(const FormatToken &Tok) { + return Tok.isOneOf(tok::kw_char, tok::kw_short, tok::kw_int, tok::kw_long, + tok::kw_unsigned, tok::kw_float, tok::kw_double, + tok::identifier); +} + // This function checks whether a token starts the first parameter declaration // in a K&R C (aka C78) function definition, e.g.: // int f(a, b) @@ -1001,13 +1008,24 @@ // { // return a + b; // } -static bool isC78ParameterDecl(const FormatToken *Tok) { - if (!Tok) +static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next, + const FormatToken *FuncName) { + assert(Tok); + assert(Next); + assert(FuncName); + + if (FuncName->isNot(tok::identifier)) + return false; + + const FormatToken *Prev = FuncName->Previous; + if (!Prev || (Prev->isNot(tok::star) && !isC78Type(*Prev))) return false; - if (!Tok->isOneOf(tok::kw_int, tok::kw_char, tok::kw_float, tok::kw_double, - tok::kw_struct, tok::kw_union, tok::kw_long, tok::kw_short, - tok::kw_unsigned, tok::kw_register, tok::identifier)) + if (!isC78Type(*Tok) && + !Tok->isOneOf(tok::kw_register, tok::kw_struct, tok::kw_union)) + return false; + + if (Next->isNot(tok::star) && !Next->Tok.getIdentifierInfo()) return false; Tok = Tok->Previous; @@ -1368,21 +1386,20 @@ case tok::r_brace: addUnwrappedLine(); return; - case tok::l_paren: + case tok::l_paren: { parseParens(); // Break the unwrapped line if a K&R C function definition has a parameter // declaration. - if (!IsTopLevel || !Style.isCpp()) - break; - if (!Previous || Previous->isNot(tok::identifier)) + if (!IsTopLevel || !Style.isCpp() || !Previous || FormatTok->is(tok::eof)) break; - if (Previous->Previous && Previous->Previous->is(tok::at)) - break; - if (isC78ParameterDecl(FormatTok)) { + const unsigned Position = Tokens->getPosition() + 1; + assert(Position < AllTokens.size()); + if (isC78ParameterDecl(FormatTok, AllTokens[Position], Previous)) { addUnwrappedLine(); return; } break; + } case tok::kw_operator: nextToken(); if (FormatTok->isBinaryOperator()) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_cuda_device_functions.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_cuda_device_functions.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_cuda_device_functions.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_cuda_device_functions.h 2021-11-16 16:47:26.000000000 +0000 @@ -34,10 +34,12 @@ return __nv_brevll(__a); } #if defined(__cplusplus) -__DEVICE__ void __brkpt() { asm volatile("brkpt;"); } +__DEVICE__ void __brkpt() { __asm__ __volatile__("brkpt;"); } __DEVICE__ void __brkpt(int __a) { __brkpt(); } #else -__DEVICE__ void __attribute__((overloadable)) __brkpt(void) { asm volatile("brkpt;"); } +__DEVICE__ void __attribute__((overloadable)) __brkpt(void) { + __asm__ __volatile__("brkpt;"); +} __DEVICE__ void __attribute__((overloadable)) __brkpt(int __a) { __brkpt(); } #endif __DEVICE__ unsigned int __byte_perm(unsigned int __a, unsigned int __b, @@ -507,7 +509,7 @@ } // Parameter must have a known integer value. -#define __prof_trigger(__a) asm __volatile__("pmevent \t%0;" ::"i"(__a)) +#define __prof_trigger(__a) __asm__ __volatile__("pmevent \t%0;" ::"i"(__a)) __DEVICE__ int __rhadd(int __a, int __b) { return __nv_rhadd(__a, __b); } __DEVICE__ unsigned int __sad(int __a, int __b, unsigned int __c) { return __nv_sad(__a, __b, __c); @@ -526,7 +528,7 @@ __DEVICE__ void __threadfence(void) { __nvvm_membar_gl(); } __DEVICE__ void __threadfence_block(void) { __nvvm_membar_cta(); }; __DEVICE__ void __threadfence_system(void) { __nvvm_membar_sys(); }; -__DEVICE__ void __trap(void) { asm volatile("trap;"); } +__DEVICE__ void __trap(void) { __asm__ __volatile__("trap;"); } __DEVICE__ unsigned int __uAtomicAdd(unsigned int *__p, unsigned int __v) { return __nvvm_atom_add_gen_i((int *)__p, __v); } @@ -1051,122 +1053,136 @@ } __DEVICE__ unsigned int __vabs2(unsigned int __a) { unsigned int r; - asm("vabsdiff2.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(0), "r"(0)); + __asm__("vabsdiff2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(0), "r"(0)); return r; } __DEVICE__ unsigned int __vabs4(unsigned int __a) { unsigned int r; - asm("vabsdiff4.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(0), "r"(0)); + __asm__("vabsdiff4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(0), "r"(0)); return r; } __DEVICE__ unsigned int __vabsdiffs2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff2.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vabsdiffs4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff4.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vabsdiffu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff2.u32.u32.u32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vabsdiffu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff4.u32.u32.u32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vabsss2(unsigned int __a) { unsigned int r; - asm("vabsdiff2.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(0), "r"(0)); + __asm__("vabsdiff2.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(0), "r"(0)); return r; } __DEVICE__ unsigned int __vabsss4(unsigned int __a) { unsigned int r; - asm("vabsdiff4.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(0), "r"(0)); + __asm__("vabsdiff4.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(0), "r"(0)); return r; } __DEVICE__ unsigned int __vadd2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vadd4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vaddss2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd2.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd2.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vaddss4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd4.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd4.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vaddus2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd2.u32.u32.u32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd2.u32.u32.u32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vaddus4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd4.u32.u32.u32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd4.u32.u32.u32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vavgs2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vavrg2.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vavrg2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vavgs4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vavrg4.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vavrg4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vavgu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vavrg2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vavrg2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vavgu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vavrg4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vavrg4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vseteq2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.eq %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.eq %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpeq2(unsigned int __a, unsigned int __b) { @@ -1174,7 +1190,9 @@ } __DEVICE__ unsigned int __vseteq4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.eq %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.eq %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpeq4(unsigned int __a, unsigned int __b) { @@ -1182,7 +1200,9 @@ } __DEVICE__ unsigned int __vsetges2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.s32.s32.ge %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.s32.s32.ge %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpges2(unsigned int __a, unsigned int __b) { @@ -1190,7 +1210,9 @@ } __DEVICE__ unsigned int __vsetges4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.s32.s32.ge %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.s32.s32.ge %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpges4(unsigned int __a, unsigned int __b) { @@ -1198,7 +1220,9 @@ } __DEVICE__ unsigned int __vsetgeu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.ge %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.ge %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgeu2(unsigned int __a, unsigned int __b) { @@ -1206,7 +1230,9 @@ } __DEVICE__ unsigned int __vsetgeu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.ge %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.ge %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgeu4(unsigned int __a, unsigned int __b) { @@ -1214,7 +1240,9 @@ } __DEVICE__ unsigned int __vsetgts2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.s32.s32.gt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.s32.s32.gt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgts2(unsigned int __a, unsigned int __b) { @@ -1222,7 +1250,9 @@ } __DEVICE__ unsigned int __vsetgts4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.s32.s32.gt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.s32.s32.gt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgts4(unsigned int __a, unsigned int __b) { @@ -1230,7 +1260,9 @@ } __DEVICE__ unsigned int __vsetgtu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.gt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.gt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgtu2(unsigned int __a, unsigned int __b) { @@ -1238,7 +1270,9 @@ } __DEVICE__ unsigned int __vsetgtu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.gt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.gt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgtu4(unsigned int __a, unsigned int __b) { @@ -1246,7 +1280,9 @@ } __DEVICE__ unsigned int __vsetles2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.s32.s32.le %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.s32.s32.le %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmples2(unsigned int __a, unsigned int __b) { @@ -1254,7 +1290,9 @@ } __DEVICE__ unsigned int __vsetles4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.s32.s32.le %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.s32.s32.le %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmples4(unsigned int __a, unsigned int __b) { @@ -1262,7 +1300,9 @@ } __DEVICE__ unsigned int __vsetleu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.le %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.le %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpleu2(unsigned int __a, unsigned int __b) { @@ -1270,7 +1310,9 @@ } __DEVICE__ unsigned int __vsetleu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.le %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.le %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpleu4(unsigned int __a, unsigned int __b) { @@ -1278,7 +1320,9 @@ } __DEVICE__ unsigned int __vsetlts2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.s32.s32.lt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.s32.s32.lt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmplts2(unsigned int __a, unsigned int __b) { @@ -1286,7 +1330,9 @@ } __DEVICE__ unsigned int __vsetlts4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.s32.s32.lt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.s32.s32.lt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmplts4(unsigned int __a, unsigned int __b) { @@ -1294,7 +1340,9 @@ } __DEVICE__ unsigned int __vsetltu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.lt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.lt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpltu2(unsigned int __a, unsigned int __b) { @@ -1302,7 +1350,9 @@ } __DEVICE__ unsigned int __vsetltu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.lt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.lt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpltu4(unsigned int __a, unsigned int __b) { @@ -1310,7 +1360,9 @@ } __DEVICE__ unsigned int __vsetne2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.ne %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.ne %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpne2(unsigned int __a, unsigned int __b) { @@ -1318,7 +1370,9 @@ } __DEVICE__ unsigned int __vsetne4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.ne %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.ne %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpne4(unsigned int __a, unsigned int __b) { @@ -1345,94 +1399,112 @@ unsigned mask = __vcmpgts2(__a, __b); r = (__a & mask) | (__b & ~mask); } else { - asm("vmax2.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmax2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); } return r; } __DEVICE__ unsigned int __vmaxs4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmax4.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmax4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vmaxu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmax2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmax2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vmaxu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmax4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmax4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vmins2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmin2.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmin2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vmins4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmin4.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmin4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vminu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmin2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmin2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vminu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmin4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmin4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsads2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff2.s32.s32.s32.add %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff2.s32.s32.s32.add %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsads4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff4.s32.s32.s32.add %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff4.s32.s32.s32.add %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsadu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff2.u32.u32.u32.add %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff2.u32.u32.u32.add %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsadu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff4.u32.u32.u32.add %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff4.u32.u32.u32.add %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsub2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vneg2(unsigned int __a) { return __vsub2(0, __a); } __DEVICE__ unsigned int __vsub4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vneg4(unsigned int __a) { return __vsub4(0, __a); } __DEVICE__ unsigned int __vsubss2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub2.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub2.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vnegss2(unsigned int __a) { @@ -1440,9 +1512,9 @@ } __DEVICE__ unsigned int __vsubss4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub4.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub4.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vnegss4(unsigned int __a) { @@ -1450,16 +1522,16 @@ } __DEVICE__ unsigned int __vsubus2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub2.u32.u32.u32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub2.u32.u32.u32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsubus4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub4.u32.u32.u32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub4.u32.u32.u32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } #endif // CUDA_VERSION >= 9020 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_hip_cmath.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_hip_cmath.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_hip_cmath.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_hip_cmath.h 2021-11-16 16:47:26.000000000 +0000 @@ -10,7 +10,7 @@ #ifndef __CLANG_HIP_CMATH_H__ #define __CLANG_HIP_CMATH_H__ -#if !defined(__HIP__) +#if !defined(__HIP__) && !defined(__OPENMP_AMDGCN__) #error "This file is for HIP and OpenMP AMDGCN device compilation only." #endif @@ -25,31 +25,43 @@ #endif // !defined(__HIPCC_RTC__) #pragma push_macro("__DEVICE__") +#pragma push_macro("__CONSTEXPR__") +#ifdef __OPENMP_AMDGCN__ +#define __DEVICE__ static __attribute__((always_inline, nothrow)) +#define __CONSTEXPR__ constexpr +#else #define __DEVICE__ static __device__ inline __attribute__((always_inline)) +#define __CONSTEXPR__ +#endif // __OPENMP_AMDGCN__ // Start with functions that cannot be defined by DEF macros below. #if defined(__cplusplus) -__DEVICE__ double abs(double __x) { return ::fabs(__x); } -__DEVICE__ float abs(float __x) { return ::fabsf(__x); } -__DEVICE__ long long abs(long long __n) { return ::llabs(__n); } -__DEVICE__ long abs(long __n) { return ::labs(__n); } -__DEVICE__ float fma(float __x, float __y, float __z) { +#if defined __OPENMP_AMDGCN__ +__DEVICE__ __CONSTEXPR__ float fabs(float __x) { return ::fabsf(__x); } +__DEVICE__ __CONSTEXPR__ float sin(float __x) { return ::sinf(__x); } +__DEVICE__ __CONSTEXPR__ float cos(float __x) { return ::cosf(__x); } +#endif +__DEVICE__ __CONSTEXPR__ double abs(double __x) { return ::fabs(__x); } +__DEVICE__ __CONSTEXPR__ float abs(float __x) { return ::fabsf(__x); } +__DEVICE__ __CONSTEXPR__ long long abs(long long __n) { return ::llabs(__n); } +__DEVICE__ __CONSTEXPR__ long abs(long __n) { return ::labs(__n); } +__DEVICE__ __CONSTEXPR__ float fma(float __x, float __y, float __z) { return ::fmaf(__x, __y, __z); } #if !defined(__HIPCC_RTC__) // The value returned by fpclassify is platform dependent, therefore it is not // supported by hipRTC. -__DEVICE__ int fpclassify(float __x) { +__DEVICE__ __CONSTEXPR__ int fpclassify(float __x) { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x); } -__DEVICE__ int fpclassify(double __x) { +__DEVICE__ __CONSTEXPR__ int fpclassify(double __x) { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x); } #endif // !defined(__HIPCC_RTC__) -__DEVICE__ float frexp(float __arg, int *__exp) { +__DEVICE__ __CONSTEXPR__ float frexp(float __arg, int *__exp) { return ::frexpf(__arg, __exp); } @@ -71,93 +83,101 @@ // of the variants inside the inner region and avoid the clash. #pragma omp begin declare variant match(implementation = {vendor(llvm)}) -__DEVICE__ int isinf(float __x) { return ::__isinff(__x); } -__DEVICE__ int isinf(double __x) { return ::__isinf(__x); } -__DEVICE__ int isfinite(float __x) { return ::__finitef(__x); } -__DEVICE__ int isfinite(double __x) { return ::__finite(__x); } -__DEVICE__ int isnan(float __x) { return ::__isnanf(__x); } -__DEVICE__ int isnan(double __x) { return ::__isnan(__x); } +__DEVICE__ __CONSTEXPR__ int isinf(float __x) { return ::__isinff(__x); } +__DEVICE__ __CONSTEXPR__ int isinf(double __x) { return ::__isinf(__x); } +__DEVICE__ __CONSTEXPR__ int isfinite(float __x) { return ::__finitef(__x); } +__DEVICE__ __CONSTEXPR__ int isfinite(double __x) { return ::__finite(__x); } +__DEVICE__ __CONSTEXPR__ int isnan(float __x) { return ::__isnanf(__x); } +__DEVICE__ __CONSTEXPR__ int isnan(double __x) { return ::__isnan(__x); } #pragma omp end declare variant #endif // defined(__OPENMP_AMDGCN__) -__DEVICE__ bool isinf(float __x) { return ::__isinff(__x); } -__DEVICE__ bool isinf(double __x) { return ::__isinf(__x); } -__DEVICE__ bool isfinite(float __x) { return ::__finitef(__x); } -__DEVICE__ bool isfinite(double __x) { return ::__finite(__x); } -__DEVICE__ bool isnan(float __x) { return ::__isnanf(__x); } -__DEVICE__ bool isnan(double __x) { return ::__isnan(__x); } +__DEVICE__ __CONSTEXPR__ bool isinf(float __x) { return ::__isinff(__x); } +__DEVICE__ __CONSTEXPR__ bool isinf(double __x) { return ::__isinf(__x); } +__DEVICE__ __CONSTEXPR__ bool isfinite(float __x) { return ::__finitef(__x); } +__DEVICE__ __CONSTEXPR__ bool isfinite(double __x) { return ::__finite(__x); } +__DEVICE__ __CONSTEXPR__ bool isnan(float __x) { return ::__isnanf(__x); } +__DEVICE__ __CONSTEXPR__ bool isnan(double __x) { return ::__isnan(__x); } #if defined(__OPENMP_AMDGCN__) #pragma omp end declare variant #endif // defined(__OPENMP_AMDGCN__) -__DEVICE__ bool isgreater(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool isgreater(float __x, float __y) { return __builtin_isgreater(__x, __y); } -__DEVICE__ bool isgreater(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool isgreater(double __x, double __y) { return __builtin_isgreater(__x, __y); } -__DEVICE__ bool isgreaterequal(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool isgreaterequal(float __x, float __y) { return __builtin_isgreaterequal(__x, __y); } -__DEVICE__ bool isgreaterequal(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool isgreaterequal(double __x, double __y) { return __builtin_isgreaterequal(__x, __y); } -__DEVICE__ bool isless(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool isless(float __x, float __y) { return __builtin_isless(__x, __y); } -__DEVICE__ bool isless(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool isless(double __x, double __y) { return __builtin_isless(__x, __y); } -__DEVICE__ bool islessequal(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool islessequal(float __x, float __y) { return __builtin_islessequal(__x, __y); } -__DEVICE__ bool islessequal(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool islessequal(double __x, double __y) { return __builtin_islessequal(__x, __y); } -__DEVICE__ bool islessgreater(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool islessgreater(float __x, float __y) { return __builtin_islessgreater(__x, __y); } -__DEVICE__ bool islessgreater(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool islessgreater(double __x, double __y) { return __builtin_islessgreater(__x, __y); } -__DEVICE__ bool isnormal(float __x) { return __builtin_isnormal(__x); } -__DEVICE__ bool isnormal(double __x) { return __builtin_isnormal(__x); } -__DEVICE__ bool isunordered(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool isnormal(float __x) { + return __builtin_isnormal(__x); +} +__DEVICE__ __CONSTEXPR__ bool isnormal(double __x) { + return __builtin_isnormal(__x); +} +__DEVICE__ __CONSTEXPR__ bool isunordered(float __x, float __y) { return __builtin_isunordered(__x, __y); } -__DEVICE__ bool isunordered(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool isunordered(double __x, double __y) { return __builtin_isunordered(__x, __y); } -__DEVICE__ float modf(float __x, float *__iptr) { return ::modff(__x, __iptr); } -__DEVICE__ float pow(float __base, int __iexp) { +__DEVICE__ __CONSTEXPR__ float modf(float __x, float *__iptr) { + return ::modff(__x, __iptr); +} +__DEVICE__ __CONSTEXPR__ float pow(float __base, int __iexp) { return ::powif(__base, __iexp); } -__DEVICE__ double pow(double __base, int __iexp) { +__DEVICE__ __CONSTEXPR__ double pow(double __base, int __iexp) { return ::powi(__base, __iexp); } -__DEVICE__ float remquo(float __x, float __y, int *__quo) { +__DEVICE__ __CONSTEXPR__ float remquo(float __x, float __y, int *__quo) { return ::remquof(__x, __y, __quo); } -__DEVICE__ float scalbln(float __x, long int __n) { +__DEVICE__ __CONSTEXPR__ float scalbln(float __x, long int __n) { return ::scalblnf(__x, __n); } -__DEVICE__ bool signbit(float __x) { return ::__signbitf(__x); } -__DEVICE__ bool signbit(double __x) { return ::__signbit(__x); } +__DEVICE__ __CONSTEXPR__ bool signbit(float __x) { return ::__signbitf(__x); } +__DEVICE__ __CONSTEXPR__ bool signbit(double __x) { return ::__signbit(__x); } // Notably missing above is nexttoward. We omit it because // ocml doesn't provide an implementation, and we don't want to be in the // business of implementing tricky libm functions in this header. // Other functions. -__DEVICE__ _Float16 fma(_Float16 __x, _Float16 __y, _Float16 __z) { +__DEVICE__ __CONSTEXPR__ _Float16 fma(_Float16 __x, _Float16 __y, + _Float16 __z) { return __ocml_fma_f16(__x, __y, __z); } -__DEVICE__ _Float16 pow(_Float16 __base, int __iexp) { +__DEVICE__ __CONSTEXPR__ _Float16 pow(_Float16 __base, int __iexp) { return __ocml_pown_f16(__base, __iexp); } +#ifndef __OPENMP_AMDGCN__ // BEGIN DEF_FUN and HIP_OVERLOAD // BEGIN DEF_FUN @@ -168,18 +188,19 @@ // Define cmath functions with float argument and returns __retty. #define __DEF_FUN1(__retty, __func) \ - __DEVICE__ \ - __retty __func(float __x) { return __func##f(__x); } + __DEVICE__ __CONSTEXPR__ __retty __func(float __x) { return __func##f(__x); } // Define cmath functions with two float arguments and returns __retty. #define __DEF_FUN2(__retty, __func) \ - __DEVICE__ \ - __retty __func(float __x, float __y) { return __func##f(__x, __y); } + __DEVICE__ __CONSTEXPR__ __retty __func(float __x, float __y) { \ + return __func##f(__x, __y); \ + } // Define cmath functions with a float and an int argument and returns __retty. #define __DEF_FUN2_FI(__retty, __func) \ - __DEVICE__ \ - __retty __func(float __x, int __y) { return __func##f(__x, __y); } + __DEVICE__ __CONSTEXPR__ __retty __func(float __x, int __y) { \ + return __func##f(__x, __y); \ + } __DEF_FUN1(float, acos) __DEF_FUN1(float, acosh) @@ -426,7 +447,7 @@ // floor(double). #define __HIP_OVERLOAD1(__retty, __fn) \ template \ - __DEVICE__ \ + __DEVICE__ __CONSTEXPR__ \ typename __hip_enable_if<__hip::is_integral<__T>::value, __retty>::type \ __fn(__T __x) { \ return ::__fn((double)__x); \ @@ -438,7 +459,7 @@ #if __cplusplus >= 201103L #define __HIP_OVERLOAD2(__retty, __fn) \ template \ - __DEVICE__ typename __hip_enable_if< \ + __DEVICE__ __CONSTEXPR__ typename __hip_enable_if< \ __hip::is_arithmetic<__T1>::value && __hip::is_arithmetic<__T2>::value, \ typename __hip::__promote<__T1, __T2>::type>::type \ __fn(__T1 __x, __T2 __y) { \ @@ -448,10 +469,11 @@ #else #define __HIP_OVERLOAD2(__retty, __fn) \ template \ - __DEVICE__ typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && \ - __hip::is_arithmetic<__T2>::value, \ - __retty>::type \ - __fn(__T1 __x, __T2 __y) { \ + __DEVICE__ __CONSTEXPR__ \ + typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && \ + __hip::is_arithmetic<__T2>::value, \ + __retty>::type \ + __fn(__T1 __x, __T2 __y) { \ return __fn((double)__x, (double)__y); \ } #endif @@ -526,7 +548,7 @@ // Additional Overloads that don't quite match HIP_OVERLOAD. #if __cplusplus >= 201103L template -__DEVICE__ typename __hip_enable_if< +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if< __hip::is_arithmetic<__T1>::value && __hip::is_arithmetic<__T2>::value && __hip::is_arithmetic<__T3>::value, typename __hip::__promote<__T1, __T2, __T3>::type>::type @@ -536,31 +558,32 @@ } #else template -__DEVICE__ typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && - __hip::is_arithmetic<__T2>::value && - __hip::is_arithmetic<__T3>::value, - double>::type -fma(__T1 __x, __T2 __y, __T3 __z) { +__DEVICE__ __CONSTEXPR__ + typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && + __hip::is_arithmetic<__T2>::value && + __hip::is_arithmetic<__T3>::value, + double>::type + fma(__T1 __x, __T2 __y, __T3 __z) { return ::fma((double)__x, (double)__y, (double)__z); } #endif template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type frexp(__T __x, int *__exp) { return ::frexp((double)__x, __exp); } template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type ldexp(__T __x, int __exp) { return ::ldexp((double)__x, __exp); } template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type modf(__T __x, double *__exp) { return ::modf((double)__x, __exp); @@ -568,7 +591,7 @@ #if __cplusplus >= 201103L template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && __hip::is_arithmetic<__T2>::value, typename __hip::__promote<__T1, __T2>::type>::type @@ -578,23 +601,24 @@ } #else template -__DEVICE__ typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && - __hip::is_arithmetic<__T2>::value, - double>::type -remquo(__T1 __x, __T2 __y, int *__quo) { +__DEVICE__ __CONSTEXPR__ + typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && + __hip::is_arithmetic<__T2>::value, + double>::type + remquo(__T1 __x, __T2 __y, int *__quo) { return ::remquo((double)__x, (double)__y, __quo); } #endif template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type scalbln(__T __x, long int __exp) { return ::scalbln((double)__x, __exp); } template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type scalbn(__T __x, int __exp) { return ::scalbn((double)__x, __exp); @@ -607,8 +631,10 @@ // END DEF_FUN and HIP_OVERLOAD +#endif // ifndef __OPENMP_AMDGCN__ #endif // defined(__cplusplus) +#ifndef __OPENMP_AMDGCN__ // Define these overloads inside the namespace our standard library uses. #if !defined(__HIPCC_RTC__) #ifdef _LIBCPP_BEGIN_NAMESPACE_STD @@ -781,22 +807,26 @@ #if defined(__cplusplus) extern "C" { #endif // defined(__cplusplus) -__DEVICE__ __attribute__((overloadable)) double _Cosh(double x, double y) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) double _Cosh(double x, + double y) { return cosh(x) * y; } -__DEVICE__ __attribute__((overloadable)) float _FCosh(float x, float y) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) float _FCosh(float x, + float y) { return coshf(x) * y; } -__DEVICE__ __attribute__((overloadable)) short _Dtest(double *p) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) short _Dtest(double *p) { return fpclassify(*p); } -__DEVICE__ __attribute__((overloadable)) short _FDtest(float *p) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) short _FDtest(float *p) { return fpclassify(*p); } -__DEVICE__ __attribute__((overloadable)) double _Sinh(double x, double y) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) double _Sinh(double x, + double y) { return sinh(x) * y; } -__DEVICE__ __attribute__((overloadable)) float _FSinh(float x, float y) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) float _FSinh(float x, + float y) { return sinhf(x) * y; } #if defined(__cplusplus) @@ -804,7 +834,9 @@ #endif // defined(__cplusplus) #endif // defined(_MSC_VER) #endif // !defined(__HIPCC_RTC__) +#endif // ifndef __OPENMP_AMDGCN__ #pragma pop_macro("__DEVICE__") +#pragma pop_macro("__CONSTEXPR__") #endif // __CLANG_HIP_CMATH_H__ diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_hip_math.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_hip_math.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_hip_math.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/__clang_hip_math.h 2021-11-16 16:47:26.000000000 +0000 @@ -9,7 +9,7 @@ #ifndef __CLANG_HIP_MATH_H__ #define __CLANG_HIP_MATH_H__ -#if !defined(__HIP__) +#if !defined(__HIP__) && !defined(__OPENMP_AMDGCN__) #error "This file is for HIP and OpenMP AMDGCN device compilation only." #endif @@ -19,18 +19,30 @@ #endif #include #include -#endif // __HIPCC_RTC__ +#ifdef __OPENMP_AMDGCN__ +#include +#endif +#endif // !defined(__HIPCC_RTC__) #pragma push_macro("__DEVICE__") + +#ifdef __OPENMP_AMDGCN__ +#define __DEVICE__ static inline __attribute__((always_inline, nothrow)) +#else #define __DEVICE__ static __device__ inline __attribute__((always_inline)) +#endif // A few functions return bool type starting only in C++11. #pragma push_macro("__RETURN_TYPE") +#ifdef __OPENMP_AMDGCN__ +#define __RETURN_TYPE int +#else #if defined(__cplusplus) #define __RETURN_TYPE bool #else #define __RETURN_TYPE int #endif +#endif // __OPENMP_AMDGCN__ #if defined (__cplusplus) && __cplusplus < 201103L // emulate static_assert on type sizes @@ -249,6 +261,9 @@ __DEVICE__ float frexpf(float __x, int *__nptr) { int __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif float __r = __ocml_frexp_f32(__x, (__attribute__((address_space(5))) int *)&__tmp); *__nptr = __tmp; @@ -334,6 +349,9 @@ __DEVICE__ float modff(float __x, float *__iptr) { float __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif float __r = __ocml_modf_f32(__x, (__attribute__((address_space(5))) float *)&__tmp); *__iptr = __tmp; @@ -414,6 +432,9 @@ __DEVICE__ float remquof(float __x, float __y, int *__quo) { int __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif float __r = __ocml_remquo_f32( __x, __y, (__attribute__((address_space(5))) int *)&__tmp); *__quo = __tmp; @@ -470,6 +491,9 @@ __DEVICE__ void sincosf(float __x, float *__sinptr, float *__cosptr) { float __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif *__sinptr = __ocml_sincos_f32(__x, (__attribute__((address_space(5))) float *)&__tmp); *__cosptr = __tmp; @@ -478,6 +502,9 @@ __DEVICE__ void sincospif(float __x, float *__sinptr, float *__cosptr) { float __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif *__sinptr = __ocml_sincospi_f32( __x, (__attribute__((address_space(5))) float *)&__tmp); *__cosptr = __tmp; @@ -790,6 +817,9 @@ __DEVICE__ double frexp(double __x, int *__nptr) { int __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif double __r = __ocml_frexp_f64(__x, (__attribute__((address_space(5))) int *)&__tmp); *__nptr = __tmp; @@ -874,6 +904,9 @@ __DEVICE__ double modf(double __x, double *__iptr) { double __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif double __r = __ocml_modf_f64(__x, (__attribute__((address_space(5))) double *)&__tmp); *__iptr = __tmp; @@ -962,6 +995,9 @@ __DEVICE__ double remquo(double __x, double __y, int *__quo) { int __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif double __r = __ocml_remquo_f64( __x, __y, (__attribute__((address_space(5))) int *)&__tmp); *__quo = __tmp; @@ -1020,6 +1056,9 @@ __DEVICE__ void sincos(double __x, double *__sinptr, double *__cosptr) { double __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif *__sinptr = __ocml_sincos_f64( __x, (__attribute__((address_space(5))) double *)&__tmp); *__cosptr = __tmp; @@ -1028,6 +1067,9 @@ __DEVICE__ void sincospi(double __x, double *__sinptr, double *__cosptr) { double __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif *__sinptr = __ocml_sincospi_f64( __x, (__attribute__((address_space(5))) double *)&__tmp); *__cosptr = __tmp; @@ -1262,7 +1304,7 @@ __DEVICE__ double min(double __x, double __y) { return fmin(__x, __y); } -#if !defined(__HIPCC_RTC__) +#if !defined(__HIPCC_RTC__) && !defined(__OPENMP_AMDGCN__) __host__ inline static int min(int __arg1, int __arg2) { return std::min(__arg1, __arg2); } @@ -1270,7 +1312,7 @@ __host__ inline static int max(int __arg1, int __arg2) { return std::max(__arg1, __arg2); } -#endif // __HIPCC_RTC__ +#endif // !defined(__HIPCC_RTC__) && !defined(__OPENMP_AMDGCN__) #endif #pragma pop_macro("__DEVICE__") diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/intrin.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/intrin.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/intrin.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/intrin.h 2021-11-16 16:47:26.000000000 +0000 @@ -574,6 +574,9 @@ unsigned short __cdecl _byteswap_ushort(unsigned short val); unsigned long __cdecl _byteswap_ulong (unsigned long val); unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 val); + +__int64 __mulh(__int64 __a, __int64 __b); +unsigned __int64 __umulh(unsigned __int64 __a, unsigned __int64 __b); #endif /*----------------------------------------------------------------------------*\ diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/__clang_openmp_device_functions.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/__clang_openmp_device_functions.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/__clang_openmp_device_functions.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/__clang_openmp_device_functions.h 2021-11-16 16:47:26.000000000 +0000 @@ -14,13 +14,13 @@ #error "This file is for OpenMP compilation only." #endif -#pragma omp begin declare variant match( \ - device = {arch(nvptx, nvptx64)}, implementation = {extension(match_any)}) - #ifdef __cplusplus extern "C" { #endif +#pragma omp begin declare variant match( \ + device = {arch(nvptx, nvptx64)}, implementation = {extension(match_any)}) + #define __CUDA__ #define __OPENMP_NVPTX__ @@ -33,11 +33,33 @@ #undef __OPENMP_NVPTX__ #undef __CUDA__ -#ifdef __cplusplus -} // extern "C" +#pragma omp end declare variant + +#ifdef __AMDGCN__ +#pragma omp begin declare variant match(device = {arch(amdgcn)}) + +// Import types which will be used by __clang_hip_libdevice_declares.h +#ifndef __cplusplus +#include +#include #endif +#define __OPENMP_AMDGCN__ +#pragma push_macro("__device__") +#define __device__ + +/// Include declarations for libdevice functions. +#include <__clang_hip_libdevice_declares.h> + +#pragma pop_macro("__device__") +#undef __OPENMP_AMDGCN__ + #pragma omp end declare variant +#endif + +#ifdef __cplusplus +} // extern "C" +#endif // Ensure we make `_ZdlPv`, aka. `operator delete(void*)` available without the // need to `include ` in C++ mode. diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/cmath rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/cmath --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/cmath 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/cmath 2021-11-16 16:47:26.000000000 +0000 @@ -75,4 +75,58 @@ #pragma omp end declare variant +#ifdef __AMDGCN__ +#pragma omp begin declare variant match(device = {arch(amdgcn)}) + +#pragma push_macro("__constant__") +#define __constant__ __attribute__((constant)) +#define __OPENMP_AMDGCN__ + +#include <__clang_hip_cmath.h> + +#pragma pop_macro("__constant__") +#undef __OPENMP_AMDGCN__ + +// Define overloads otherwise which are absent +#define __DEVICE__ static constexpr __attribute__((always_inline, nothrow)) + +__DEVICE__ float acos(float __x) { return ::acosf(__x); } +__DEVICE__ float acosh(float __x) { return ::acoshf(__x); } +__DEVICE__ float asin(float __x) { return ::asinf(__x); } +__DEVICE__ float asinh(float __x) { return ::asinhf(__x); } +__DEVICE__ float atan(float __x) { return ::atanf(__x); } +__DEVICE__ float atan2(float __x, float __y) { return ::atan2f(__x, __y); } +__DEVICE__ float atanh(float __x) { return ::atanhf(__x); } +__DEVICE__ float cbrt(float __x) { return ::cbrtf(__x); } +__DEVICE__ float cosh(float __x) { return ::coshf(__x); } +__DEVICE__ float erf(float __x) { return ::erff(__x); } +__DEVICE__ float erfc(float __x) { return ::erfcf(__x); } +__DEVICE__ float exp2(float __x) { return ::exp2f(__x); } +__DEVICE__ float expm1(float __x) { return ::expm1f(__x); } +__DEVICE__ float fdim(float __x, float __y) { return ::fdimf(__x, __y); } +__DEVICE__ float hypot(float __x, float __y) { return ::hypotf(__x, __y); } +__DEVICE__ int ilogb(float __x) { return ::ilogbf(__x); } +__DEVICE__ float ldexp(float __arg, int __exp) { + return ::ldexpf(__arg, __exp); +} +__DEVICE__ float lgamma(float __x) { return ::lgammaf(__x); } +__DEVICE__ float log1p(float __x) { return ::log1pf(__x); } +__DEVICE__ float logb(float __x) { return ::logbf(__x); } +__DEVICE__ float nextafter(float __x, float __y) { + return ::nextafterf(__x, __y); +} +__DEVICE__ float remainder(float __x, float __y) { + return ::remainderf(__x, __y); +} +__DEVICE__ float scalbn(float __x, int __y) { return ::scalbnf(__x, __y); } +__DEVICE__ float sinh(float __x) { return ::sinhf(__x); } +__DEVICE__ float tan(float __x) { return ::tanf(__x); } +__DEVICE__ float tanh(float __x) { return ::tanhf(__x); } +__DEVICE__ float tgamma(float __x) { return ::tgammaf(__x); } + +#undef __DEVICE__ + +#pragma omp end declare variant +#endif // __AMDGCN__ + #endif diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/complex rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/complex --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/complex 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/complex 2021-11-16 16:47:26.000000000 +0000 @@ -36,7 +36,7 @@ #ifndef _LIBCPP_STD_VER #pragma omp begin declare variant match( \ - device = {arch(nvptx, nvptx64)}, \ + device = {arch(amdgcn, nvptx, nvptx64)}, \ implementation = {extension(match_any, allow_templates)}) #include diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/math.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/math.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/math.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Headers/openmp_wrappers/math.h 2021-11-16 16:47:26.000000000 +0000 @@ -48,4 +48,14 @@ #pragma omp end declare variant +#ifdef __AMDGCN__ +#pragma omp begin declare variant match(device = {arch(amdgcn)}) + +#define __OPENMP_AMDGCN__ +#include <__clang_hip_math.h> +#undef __OPENMP_AMDGCN__ + +#pragma omp end declare variant +#endif + #endif diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaCoroutine.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaCoroutine.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaCoroutine.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaCoroutine.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1533,7 +1533,7 @@ if (GroType->isVoidType()) { // Trigger a nice error message. InitializedEntity Entity = - InitializedEntity::InitializeResult(Loc, FnRetType, false); + InitializedEntity::InitializeResult(Loc, FnRetType); S.PerformCopyInitialization(Entity, SourceLocation(), ReturnValue); noteMemberDeclaredHere(S, ReturnValue, Fn); return false; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/Sema.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/Sema.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/Sema.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/Sema.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -2010,7 +2010,7 @@ Expr *VarRef = new (S.Context) DeclRefExpr(S.Context, VD, false, T, VK_LValue, Loc); ExprResult Result; - auto IE = InitializedEntity::InitializeBlock(Loc, T, false); + auto IE = InitializedEntity::InitializeBlock(Loc, T); if (S.getLangOpts().CPlusPlus2b) { auto *E = ImplicitCastExpr::Create(S.Context, T, CK_NoOp, VarRef, nullptr, VK_XValue, FPOptionsOverride()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -15262,8 +15262,17 @@ // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor && + // FIXME: Converting constructors should also be accepted. + // But to fix this, the logic that digs down into a CXXConstructExpr + // to find the source object needs to handle it. + // Right now it assumes the source object is passed directly as the + // first argument. Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) { Expr *SubExpr = ExprArgs[0]; + // FIXME: Per above, this is also incorrect if we want to accept + // converting constructors, as isTemporaryObject will + // reject temporaries with different type from the + // CXXRecord itself. Elidable = SubExpr->isTemporaryObject( Context, cast(FoundDecl->getDeclContext())); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaExpr.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaExpr.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaExpr.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaExpr.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -15683,7 +15683,7 @@ if (!Result.isInvalid()) { Result = PerformCopyInitialization( InitializedEntity::InitializeBlock(Var->getLocation(), - Cap.getCaptureType(), false), + Cap.getCaptureType()), Loc, Result.get()); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaExprCXX.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaExprCXX.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaExprCXX.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaExprCXX.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -893,9 +893,8 @@ if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) return ExprError(); - InitializedEntity Entity = InitializedEntity::InitializeException( - OpLoc, ExceptionObjectTy, - /*NRVO=*/NRInfo.isCopyElidable()); + InitializedEntity Entity = + InitializedEntity::InitializeException(OpLoc, ExceptionObjectTy); ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRInfo, Ex); if (Res.isInvalid()) return ExprError(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaLambda.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaLambda.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaLambda.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaLambda.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1975,8 +1975,7 @@ CallOperator->markUsed(Context); ExprResult Init = PerformCopyInitialization( - InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType(), - /*NRVO=*/false), + InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType()), CurrentLocation, Src); if (!Init.isInvalid()) Init = ActOnFinishFullExpr(Init.get(), /*DiscardedValue*/ false); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaObjCProperty.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaObjCProperty.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaObjCProperty.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaObjCProperty.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1467,8 +1467,7 @@ LoadSelfExpr, true, true); ExprResult Res = PerformCopyInitialization( InitializedEntity::InitializeResult(PropertyDiagLoc, - getterMethod->getReturnType(), - /*NRVO=*/false), + getterMethod->getReturnType()), PropertyDiagLoc, IvarRefExpr); if (!Res.isInvalid()) { Expr *ResExpr = Res.getAs(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaStmt.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaStmt.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaStmt.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaStmt.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -3481,7 +3481,8 @@ ExprResult Sema::PerformMoveOrCopyInitialization( const InitializedEntity &Entity, const NamedReturnInfo &NRInfo, Expr *Value, bool SupressSimplerImplicitMoves) { - if ((!getLangOpts().CPlusPlus2b || SupressSimplerImplicitMoves) && + if (getLangOpts().CPlusPlus && + (!getLangOpts().CPlusPlus2b || SupressSimplerImplicitMoves) && NRInfo.isMoveEligible()) { ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), CK_NoOp, Value, VK_XValue, FPOptionsOverride()); @@ -3652,8 +3653,8 @@ // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - InitializedEntity Entity = InitializedEntity::InitializeResult( - ReturnLoc, FnRetType, NRVOCandidate != nullptr); + InitializedEntity Entity = + InitializedEntity::InitializeResult(ReturnLoc, FnRetType); ExprResult Res = PerformMoveOrCopyInitialization( Entity, NRInfo, RetValExp, SupressSimplerImplicitMoves); if (Res.isInvalid()) { @@ -4084,8 +4085,8 @@ // the C version of which boils down to CheckSingleAssignmentConstraints. if (!HasDependentReturnType && !RetValExp->isTypeDependent()) { // we have a non-void function with an expression, continue checking - InitializedEntity Entity = InitializedEntity::InitializeResult( - ReturnLoc, RetType, NRVOCandidate != nullptr); + InitializedEntity Entity = + InitializedEntity::InitializeResult(ReturnLoc, RetType); ExprResult Res = PerformMoveOrCopyInitialization( Entity, NRInfo, RetValExp, SupressSimplerImplicitMoves); if (Res.isInvalid()) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1934,25 +1934,23 @@ return Req; Sema::SFINAETrap Trap(SemaRef); - TemplateDeductionInfo Info(Req->getExpr()->getBeginLoc()); llvm::PointerUnion TransExpr; if (Req->isExprSubstitutionFailure()) TransExpr = Req->getExprSubstitutionDiagnostic(); else { - Sema::InstantiatingTemplate ExprInst(SemaRef, Req->getExpr()->getBeginLoc(), - Req, Info, - Req->getExpr()->getSourceRange()); + Expr *E = Req->getExpr(); + TemplateDeductionInfo Info(E->getBeginLoc()); + Sema::InstantiatingTemplate ExprInst(SemaRef, E->getBeginLoc(), Req, Info, + E->getSourceRange()); if (ExprInst.isInvalid()) return nullptr; - ExprResult TransExprRes = TransformExpr(Req->getExpr()); + ExprResult TransExprRes = TransformExpr(E); if (TransExprRes.isInvalid() || Trap.hasErrorOccurred()) - TransExpr = createSubstDiag(SemaRef, Info, - [&] (llvm::raw_ostream& OS) { - Req->getExpr()->printPretty(OS, nullptr, - SemaRef.getPrintingPolicy()); - }); + TransExpr = createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) { + E->printPretty(OS, nullptr, SemaRef.getPrintingPolicy()); + }); else TransExpr = TransExprRes.get(); } @@ -1966,6 +1964,7 @@ else if (RetReq.isTypeConstraint()) { TemplateParameterList *OrigTPL = RetReq.getTypeConstraintTemplateParameterList(); + TemplateDeductionInfo Info(OrigTPL->getTemplateLoc()); Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(), Req, Info, OrigTPL->getSourceRange()); if (TPLInst.isInvalid()) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1087,7 +1087,7 @@ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner, StartingScope, InstantiatingVarTemplate); - if (D->isNRVOVariable()) { + if (D->isNRVOVariable() && !Var->isInvalidDecl()) { QualType RT; if (auto *F = dyn_cast(DC)) RT = F->getReturnType(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/TreeTransform.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/TreeTransform.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/TreeTransform.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Sema/TreeTransform.h 2021-11-16 16:47:26.000000000 +0000 @@ -6578,7 +6578,7 @@ NewTL.setFoundDecl(TL.getFoundDecl()); NewTL.setLAngleLoc(TL.getLAngleLoc()); NewTL.setRAngleLoc(TL.getRAngleLoc()); - for (unsigned I = 0; I < TL.getNumArgs(); ++I) + for (unsigned I = 0; I < NewTL.getNumArgs(); ++I) NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo()); return Result; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Serialization/ASTReader.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Serialization/ASTReader.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/lib/Serialization/ASTReader.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/lib/Serialization/ASTReader.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -8456,6 +8456,8 @@ LPTMap.insert(std::make_pair(FD, std::move(LT))); } } + + LateParsedTemplates.clear(); } void ASTReader::LoadSelector(Selector Sel) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Analysis/blocks-nrvo.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Analysis/blocks-nrvo.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Analysis/blocks-nrvo.c 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Analysis/blocks-nrvo.c 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,14 @@ +// RUN: %clang_analyze_cc1 -w -analyzer-checker=core -fblocks -verify %s + +// expected-no-diagnostics + +typedef struct { + int x; +} S; + +void foo() { + ^{ + S s; + return s; // no-crash + }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,414 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// expected-no-diagnostics + +// Our very own std::move, copied from libcxx. +template struct remove_reference { typedef _Tp type; }; +template struct remove_reference<_Tp &> { typedef _Tp type; }; +template struct remove_reference<_Tp &&> { typedef _Tp type; }; + +template +inline typename remove_reference<_Tp>::type && +move(_Tp &&__t) { + typedef typename remove_reference<_Tp>::type _Up; + return static_cast<_Up &&>(__t); +} +// --- + +int Good, Bad; +int &also_before() { + return Bad; +} +int also_before(float &&) { + return 0; +} + +#pragma omp begin declare variant match(implementation = {vendor(score(100) \ + : llvm)}) +int also_after(void) { + return 1; +} +int also_after(int &) { + return 2; +} +// This one does overload the int(*)(double&) version! +int also_after(double &) { + return 0; +} +int also_after(double &&) { + return 3; +} +int also_after(short &) { + return 5; +} +int also_after(short &&) { + return 0; +} +#pragma omp end declare variant +#pragma omp begin declare variant match(implementation = {vendor(score(0) \ + : llvm)}) +// This one does overload the int&(*)(void) version! +int &also_before() { + return Good; +} +// This one does *not* overload the int(*)(float&&) version! +int also_before(float &) { + return 6; +} +#pragma omp end declare variant + +int also_after(void) { + return 7; +} +int also_after(int) { + return 8; +} +int also_after(double &) { + return 9; +} +int also_after(short &&) { + return 10; +} + +int test1() { + // Should return 0. + double d; + return also_after(d); +} + +int test2() { + // Should return 0. + return &also_before() == &Good; +} + +int test3(float &&f) { + // Should return 0. + return also_before(move(f)); +} + +int test4(short &&s) { + // Should return 0. + return also_after(move(s)); +} + +int test(float &&f, short &&s) { + // Should return 0. + return test1() + test2() + test3(move(f)) + test4(move(s)); +} + +// CHECK: |-ClassTemplateDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, col:66> col:29 remove_reference +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_1:0x[a-z0-9]*]] col:17 referenced class depth 0 index 0 _Tp +// CHECK-NEXT: | |-CXXRecordDecl [[ADDR_2:0x[a-z0-9]*]] col:29 struct remove_reference definition +// CHECK-NEXT: | | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init +// CHECK-NEXT: | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr +// CHECK-NEXT: | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | | |-MoveConstructor exists simple trivial needs_implicit +// CHECK-NEXT: | | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | | |-MoveAssignment exists simple trivial needs_implicit +// CHECK-NEXT: | | | `-Destructor simple irrelevant trivial needs_implicit +// CHECK-NEXT: | | |-CXXRecordDecl [[ADDR_3:0x[a-z0-9]*]] col:29 implicit struct remove_reference +// CHECK-NEXT: | | `-TypedefDecl [[ADDR_4:0x[a-z0-9]*]] col:60 type '_Tp' +// CHECK-NEXT: | | `-TemplateTypeParmType [[ADDR_5:0x[a-z0-9]*]] '_Tp' dependent depth 0 index 0 +// CHECK-NEXT: | | `-TemplateTypeParm [[ADDR_1]] '_Tp' +// CHECK-NEXT: | |-ClassTemplateSpecializationDecl [[ADDR_6:0x[a-z0-9]*]] col:29 struct remove_reference definition +// CHECK-NEXT: | | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init +// CHECK-NEXT: | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr +// CHECK-NEXT: | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | | |-MoveConstructor exists simple trivial needs_implicit +// CHECK-NEXT: | | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | | |-MoveAssignment exists simple trivial needs_implicit +// CHECK-NEXT: | | | `-Destructor simple irrelevant trivial needs_implicit +// CHECK-NEXT: | | |-TemplateArgument type 'float &' +// CHECK-NEXT: | | | `-LValueReferenceType [[ADDR_7:0x[a-z0-9]*]] 'float &' +// CHECK-NEXT: | | | `-BuiltinType [[ADDR_8:0x[a-z0-9]*]] 'float' +// CHECK-NEXT: | | |-CXXRecordDecl [[ADDR_9:0x[a-z0-9]*]] prev [[ADDR_6]] col:29 implicit struct remove_reference +// CHECK-NEXT: | | `-TypedefDecl [[ADDR_10:0x[a-z0-9]*]] col:67 referenced type 'float':'float' +// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_11:0x[a-z0-9]*]] 'float' sugar +// CHECK-NEXT: | | |-TemplateTypeParmType [[ADDR_12:0x[a-z0-9]*]] '_Tp' dependent depth 0 index 0 +// CHECK-NEXT: | | | `-TemplateTypeParm [[ADDR_13:0x[a-z0-9]*]] '_Tp' +// CHECK-NEXT: | | `-BuiltinType [[ADDR_8]] 'float' +// CHECK-NEXT: | `-ClassTemplateSpecializationDecl [[ADDR_14:0x[a-z0-9]*]] col:29 struct remove_reference definition +// CHECK-NEXT: | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init +// CHECK-NEXT: | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr +// CHECK-NEXT: | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | |-MoveConstructor exists simple trivial needs_implicit +// CHECK-NEXT: | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | |-MoveAssignment exists simple trivial needs_implicit +// CHECK-NEXT: | | `-Destructor simple irrelevant trivial needs_implicit +// CHECK-NEXT: | |-TemplateArgument type 'short &' +// CHECK-NEXT: | | `-LValueReferenceType [[ADDR_15:0x[a-z0-9]*]] 'short &' +// CHECK-NEXT: | | `-BuiltinType [[ADDR_16:0x[a-z0-9]*]] 'short' +// CHECK-NEXT: | |-CXXRecordDecl [[ADDR_17:0x[a-z0-9]*]] prev [[ADDR_14]] col:29 implicit struct remove_reference +// CHECK-NEXT: | `-TypedefDecl [[ADDR_18:0x[a-z0-9]*]] col:67 referenced type 'short':'short' +// CHECK-NEXT: | `-SubstTemplateTypeParmType [[ADDR_19:0x[a-z0-9]*]] 'short' sugar +// CHECK-NEXT: | |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0 +// CHECK-NEXT: | | `-TemplateTypeParm [[ADDR_13]] '_Tp' +// CHECK-NEXT: | `-BuiltinType [[ADDR_16]] 'short' +// CHECK-NEXT: |-ClassTemplatePartialSpecializationDecl [[ADDR_20:0x[a-z0-9]*]] col:29 struct remove_reference definition +// CHECK-NEXT: | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init +// CHECK-NEXT: | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr +// CHECK-NEXT: | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | |-MoveConstructor exists simple trivial needs_implicit +// CHECK-NEXT: | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | |-MoveAssignment exists simple trivial needs_implicit +// CHECK-NEXT: | | `-Destructor simple irrelevant trivial needs_implicit +// CHECK-NEXT: | |-TemplateArgument type 'type-parameter-0-0 &' +// CHECK-NEXT: | | `-LValueReferenceType [[ADDR_21:0x[a-z0-9]*]] 'type-parameter-0-0 &' dependent +// CHECK-NEXT: | | `-TemplateTypeParmType [[ADDR_22:0x[a-z0-9]*]] 'type-parameter-0-0' dependent depth 0 index 0 +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_13]] col:17 referenced class depth 0 index 0 _Tp +// CHECK-NEXT: | |-CXXRecordDecl [[ADDR_23:0x[a-z0-9]*]] col:29 implicit struct remove_reference +// CHECK-NEXT: | `-TypedefDecl [[ADDR_24:0x[a-z0-9]*]] col:67 type '_Tp' +// CHECK-NEXT: | `-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0 +// CHECK-NEXT: | `-TemplateTypeParm [[ADDR_13]] '_Tp' +// CHECK-NEXT: |-ClassTemplatePartialSpecializationDecl [[ADDR_25:0x[a-z0-9]*]] col:29 struct remove_reference definition +// CHECK-NEXT: | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init +// CHECK-NEXT: | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr +// CHECK-NEXT: | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | |-MoveConstructor exists simple trivial needs_implicit +// CHECK-NEXT: | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | |-MoveAssignment exists simple trivial needs_implicit +// CHECK-NEXT: | | `-Destructor simple irrelevant trivial needs_implicit +// CHECK-NEXT: | |-TemplateArgument type 'type-parameter-0-0 &&' +// CHECK-NEXT: | | `-RValueReferenceType [[ADDR_26:0x[a-z0-9]*]] 'type-parameter-0-0 &&' dependent +// CHECK-NEXT: | | `-TemplateTypeParmType [[ADDR_22]] 'type-parameter-0-0' dependent depth 0 index 0 +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_27:0x[a-z0-9]*]] col:17 referenced class depth 0 index 0 _Tp +// CHECK-NEXT: | |-CXXRecordDecl [[ADDR_28:0x[a-z0-9]*]] col:29 implicit struct remove_reference +// CHECK-NEXT: | `-TypedefDecl [[ADDR_29:0x[a-z0-9]*]] col:68 type '_Tp' +// CHECK-NEXT: | `-TemplateTypeParmType [[ADDR_30:0x[a-z0-9]*]] '_Tp' dependent depth 0 index 0 +// CHECK-NEXT: | `-TemplateTypeParm [[ADDR_27]] '_Tp' +// CHECK-NEXT: |-FunctionTemplateDecl [[ADDR_31:0x[a-z0-9]*]] line:11:1 move +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_32:0x[a-z0-9]*]] col:17 referenced class depth 0 index 0 _Tp +// CHECK-NEXT: | |-FunctionDecl [[ADDR_33:0x[a-z0-9]*]] line:11:1 move 'typename remove_reference<_Tp>::type &&(_Tp &&)' inline +// CHECK-NEXT: | | |-ParmVarDecl [[ADDR_34:0x[a-z0-9]*]] col:12 referenced __t '_Tp &&' +// CHECK-NEXT: | | `-CompoundStmt [[ADDR_35:0x[a-z0-9]*]] +// CHECK-NEXT: | | |-DeclStmt [[ADDR_36:0x[a-z0-9]*]] +// CHECK-NEXT: | | | `-TypedefDecl [[ADDR_37:0x[a-z0-9]*]] col:48 referenced _Up 'typename remove_reference<_Tp>::type' +// CHECK-NEXT: | | | `-DependentNameType [[ADDR_38:0x[a-z0-9]*]] 'typename remove_reference<_Tp>::type' dependent +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_39:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-CXXStaticCastExpr [[ADDR_40:0x[a-z0-9]*]] '_Up':'typename remove_reference<_Tp>::type' xvalue static_cast<_Up &&> +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_41:0x[a-z0-9]*]] '_Tp' {{.*}}ParmVar [[ADDR_34]] '__t' '_Tp &&' +// CHECK-NEXT: | |-FunctionDecl [[ADDR_42:0x[a-z0-9]*]] line:11:1 used move 'typename remove_reference::type &&(float &)' inline +// CHECK-NEXT: | | |-TemplateArgument type 'float &' +// CHECK-NEXT: | | | `-LValueReferenceType [[ADDR_7]] 'float &' +// CHECK-NEXT: | | | `-BuiltinType [[ADDR_8]] 'float' +// CHECK-NEXT: | | |-ParmVarDecl [[ADDR_43:0x[a-z0-9]*]] col:12 used __t 'float &' +// CHECK-NEXT: | | `-CompoundStmt [[ADDR_44:0x[a-z0-9]*]] +// CHECK-NEXT: | | |-DeclStmt [[ADDR_45:0x[a-z0-9]*]] +// CHECK-NEXT: | | | `-TypedefDecl [[ADDR_46:0x[a-z0-9]*]] col:48 _Up 'typename remove_reference::type':'float' +// CHECK-NEXT: | | | `-ElaboratedType [[ADDR_47:0x[a-z0-9]*]] 'typename remove_reference::type' sugar +// CHECK-NEXT: | | | `-TypedefType [[ADDR_48:0x[a-z0-9]*]] 'remove_reference::type' sugar +// CHECK-NEXT: | | | |-Typedef [[ADDR_10]] 'type' +// CHECK-NEXT: | | | `-SubstTemplateTypeParmType [[ADDR_11]] 'float' sugar +// CHECK-NEXT: | | | |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0 +// CHECK-NEXT: | | | | `-TemplateTypeParm [[ADDR_13]] '_Tp' +// CHECK-NEXT: | | | `-BuiltinType [[ADDR_8]] 'float' +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_49:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-CXXStaticCastExpr [[ADDR_50:0x[a-z0-9]*]] '_Up':'float' xvalue static_cast<_Up &&> +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_51:0x[a-z0-9]*]] 'float' {{.*}}ParmVar [[ADDR_43]] '__t' 'float &' +// CHECK-NEXT: | `-FunctionDecl [[ADDR_52:0x[a-z0-9]*]] line:11:1 used move 'typename remove_reference::type &&(short &)' inline +// CHECK-NEXT: | |-TemplateArgument type 'short &' +// CHECK-NEXT: | | `-LValueReferenceType [[ADDR_15]] 'short &' +// CHECK-NEXT: | | `-BuiltinType [[ADDR_16]] 'short' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_53:0x[a-z0-9]*]] col:12 used __t 'short &' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_54:0x[a-z0-9]*]] +// CHECK-NEXT: | |-DeclStmt [[ADDR_55:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-TypedefDecl [[ADDR_56:0x[a-z0-9]*]] col:48 _Up 'typename remove_reference::type':'short' +// CHECK-NEXT: | | `-ElaboratedType [[ADDR_57:0x[a-z0-9]*]] 'typename remove_reference::type' sugar +// CHECK-NEXT: | | `-TypedefType [[ADDR_58:0x[a-z0-9]*]] 'remove_reference::type' sugar +// CHECK-NEXT: | | |-Typedef [[ADDR_18]] 'type' +// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_19]] 'short' sugar +// CHECK-NEXT: | | |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0 +// CHECK-NEXT: | | | `-TemplateTypeParm [[ADDR_13]] '_Tp' +// CHECK-NEXT: | | `-BuiltinType [[ADDR_16]] 'short' +// CHECK-NEXT: | `-ReturnStmt [[ADDR_59:0x[a-z0-9]*]] +// CHECK-NEXT: | `-CXXStaticCastExpr [[ADDR_60:0x[a-z0-9]*]] '_Up':'short' xvalue static_cast<_Up &&> +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_61:0x[a-z0-9]*]] 'short' {{.*}}ParmVar [[ADDR_53]] '__t' 'short &' +// CHECK-NEXT: |-VarDecl [[ADDR_62:0x[a-z0-9]*]] col:5 used Good 'int' +// CHECK-NEXT: |-VarDecl [[ADDR_63:0x[a-z0-9]*]] col:11 used Bad 'int' +// CHECK-NEXT: |-FunctionDecl [[ADDR_64:0x[a-z0-9]*]] line:18:6 used also_before 'int &({{.*}})' +// CHECK-NEXT: | |-CompoundStmt [[ADDR_65:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_66:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_67:0x[a-z0-9]*]] 'int' {{.*}}Var [[ADDR_63]] 'Bad' 'int' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_68:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(0): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_69:0x[a-z0-9]*]] 'int &({{.*}})' {{.*}}Function [[ADDR_70:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int &({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_71:0x[a-z0-9]*]] line:21:5 used also_before 'int (float &&)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_72:0x[a-z0-9]*]] col:25 'float &&' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_73:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_74:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_75:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_76:0x[a-z0-9]*]] col:5 implicit also_after 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_77:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_78:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_79:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_79]] line:27:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_80:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_81:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_82:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_83:0x[a-z0-9]*]] col:5 implicit also_after 'int (int &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_84:0x[a-z0-9]*]] col:21 'int &' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_85:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_86:0x[a-z0-9]*]] 'int (int &)' {{.*}}Function [[ADDR_87:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int (int &)' +// CHECK-NEXT: |-FunctionDecl [[ADDR_87]] line:30:1 also_after[implementation={vendor(llvm)}] 'int (int &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_84]] col:21 'int &' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_88:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_89:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_90:0x[a-z0-9]*]] 'int' 2 +// CHECK-NEXT: |-FunctionDecl [[ADDR_91:0x[a-z0-9]*]] col:5 implicit used also_after 'int (double &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_92:0x[a-z0-9]*]] col:24 'double &' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_93:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_94:0x[a-z0-9]*]] 'int (double &)' {{.*}}Function [[ADDR_95:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int (double &)' +// CHECK-NEXT: |-FunctionDecl [[ADDR_95]] line:34:1 also_after[implementation={vendor(llvm)}] 'int (double &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_92]] col:24 'double &' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_96:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_97:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_98:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_99:0x[a-z0-9]*]] col:5 implicit also_after 'int (double &&)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_100:0x[a-z0-9]*]] col:25 'double &&' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_101:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_102:0x[a-z0-9]*]] 'int (double &&)' {{.*}}Function [[ADDR_103:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int (double &&)' +// CHECK-NEXT: |-FunctionDecl [[ADDR_103]] line:37:1 also_after[implementation={vendor(llvm)}] 'int (double &&)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_100]] col:25 'double &&' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_104:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_105:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_106:0x[a-z0-9]*]] 'int' 3 +// CHECK-NEXT: |-FunctionDecl [[ADDR_107:0x[a-z0-9]*]] col:5 implicit also_after 'int (short &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_108:0x[a-z0-9]*]] col:23 'short &' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_109:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_110:0x[a-z0-9]*]] 'int (short &)' {{.*}}Function [[ADDR_111:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int (short &)' +// CHECK-NEXT: |-FunctionDecl [[ADDR_111]] line:40:1 also_after[implementation={vendor(llvm)}] 'int (short &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_108]] col:23 'short &' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_112:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_113:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_114:0x[a-z0-9]*]] 'int' 5 +// CHECK-NEXT: |-FunctionDecl [[ADDR_115:0x[a-z0-9]*]] col:5 implicit used also_after 'int (short &&)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_116:0x[a-z0-9]*]] col:24 'short &&' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_117:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_118:0x[a-z0-9]*]] 'int (short &&)' {{.*}}Function [[ADDR_119:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int (short &&)' +// CHECK-NEXT: |-FunctionDecl [[ADDR_119]] line:43:1 also_after[implementation={vendor(llvm)}] 'int (short &&)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_116]] col:24 'short &&' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_120:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_121:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_122:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_70]] line:50:1 also_before[implementation={vendor(llvm)}] 'int &({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_123:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_124:0x[a-z0-9]*]] +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_125:0x[a-z0-9]*]] 'int' {{.*}}Var [[ADDR_62]] 'Good' 'int' +// CHECK-NEXT: |-FunctionDecl [[ADDR_126:0x[a-z0-9]*]] col:5 implicit also_before 'int (float &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_127:0x[a-z0-9]*]] col:24 'float &' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_128:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(0): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_129:0x[a-z0-9]*]] 'int (float &)' {{.*}}Function [[ADDR_130:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int (float &)' +// CHECK-NEXT: |-FunctionDecl [[ADDR_130]] line:54:1 also_before[implementation={vendor(llvm)}] 'int (float &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_127]] col:24 'float &' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_131:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_132:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_133:0x[a-z0-9]*]] 'int' 6 +// CHECK-NEXT: |-FunctionDecl [[ADDR_134:0x[a-z0-9]*]] prev [[ADDR_76]] line:59:5 also_after 'int ({{.*}})' +// CHECK-NEXT: | |-CompoundStmt [[ADDR_135:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_136:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-IntegerLiteral [[ADDR_137:0x[a-z0-9]*]] 'int' 7 +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_138:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_78]] 'int ({{.*}})' {{.*}}Function [[ADDR_79]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_139:0x[a-z0-9]*]] line:62:5 also_after 'int (int)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_140:0x[a-z0-9]*]] col:19 'int' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_141:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_142:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_143:0x[a-z0-9]*]] 'int' 8 +// CHECK-NEXT: |-FunctionDecl [[ADDR_144:0x[a-z0-9]*]] prev [[ADDR_91]] line:65:5 used also_after 'int (double &)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_145:0x[a-z0-9]*]] col:24 'double &' +// CHECK-NEXT: | |-CompoundStmt [[ADDR_146:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_147:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-IntegerLiteral [[ADDR_148:0x[a-z0-9]*]] 'int' 9 +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_149:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_94]] 'int (double &)' {{.*}}Function [[ADDR_95]] 'also_after[implementation={vendor(llvm)}]' 'int (double &)' +// CHECK-NEXT: |-FunctionDecl [[ADDR_150:0x[a-z0-9]*]] prev [[ADDR_115]] line:68:5 used also_after 'int (short &&)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_151:0x[a-z0-9]*]] col:24 'short &&' +// CHECK-NEXT: | |-CompoundStmt [[ADDR_152:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_153:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-IntegerLiteral [[ADDR_154:0x[a-z0-9]*]] 'int' 10 +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_155:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_118]] 'int (short &&)' {{.*}}Function [[ADDR_119]] 'also_after[implementation={vendor(llvm)}]' 'int (short &&)' +// CHECK-NEXT: |-FunctionDecl [[ADDR_156:0x[a-z0-9]*]] line:72:5 used test1 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_157:0x[a-z0-9]*]] +// CHECK-NEXT: | |-DeclStmt [[ADDR_158:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-VarDecl [[ADDR_159:0x[a-z0-9]*]] col:10 used d 'double' +// CHECK-NEXT: | `-ReturnStmt [[ADDR_160:0x[a-z0-9]*]] +// CHECK-NEXT: | `-PseudoObjectExpr [[ADDR_161:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-CallExpr [[ADDR_162:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | | |-ImplicitCastExpr [[ADDR_163:0x[a-z0-9]*]] 'int (*)(double &)' +// CHECK-NEXT: | | | `-DeclRefExpr [[ADDR_164:0x[a-z0-9]*]] 'int (double &)' {{.*}}Function [[ADDR_144]] 'also_after' 'int (double &)' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_165:0x[a-z0-9]*]] 'double' {{.*}}Var [[ADDR_159]] 'd' 'double' +// CHECK-NEXT: | `-CallExpr [[ADDR_166:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-ImplicitCastExpr [[ADDR_167:0x[a-z0-9]*]] 'int (*)(double &)' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_94]] 'int (double &)' {{.*}}Function [[ADDR_95]] 'also_after[implementation={vendor(llvm)}]' 'int (double &)' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_165]] 'double' {{.*}}Var [[ADDR_159]] 'd' 'double' +// CHECK-NEXT: |-FunctionDecl [[ADDR_168:0x[a-z0-9]*]] line:78:5 used test2 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_169:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_170:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_171:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-BinaryOperator [[ADDR_172:0x[a-z0-9]*]] 'bool' '==' +// CHECK-NEXT: | |-UnaryOperator [[ADDR_173:0x[a-z0-9]*]] 'int *' prefix '&' cannot overflow +// CHECK-NEXT: | | `-PseudoObjectExpr [[ADDR_174:0x[a-z0-9]*]] 'int' lvalue +// CHECK-NEXT: | | |-CallExpr [[ADDR_175:0x[a-z0-9]*]] 'int' lvalue +// CHECK-NEXT: | | | `-ImplicitCastExpr [[ADDR_176:0x[a-z0-9]*]] 'int &(*)({{.*}})' +// CHECK-NEXT: | | | `-DeclRefExpr [[ADDR_177:0x[a-z0-9]*]] 'int &({{.*}})' {{.*}}Function [[ADDR_64]] 'also_before' 'int &({{.*}})' +// CHECK-NEXT: | | `-CallExpr [[ADDR_178:0x[a-z0-9]*]] 'int' lvalue +// CHECK-NEXT: | | `-ImplicitCastExpr [[ADDR_179:0x[a-z0-9]*]] 'int &(*)({{.*}})' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_69]] 'int &({{.*}})' {{.*}}Function [[ADDR_70]] 'also_before[implementation={vendor(llvm)}]' 'int &({{.*}})' +// CHECK-NEXT: | `-UnaryOperator [[ADDR_180:0x[a-z0-9]*]] 'int *' prefix '&' cannot overflow +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_181:0x[a-z0-9]*]] 'int' {{.*}}Var [[ADDR_62]] 'Good' 'int' +// CHECK-NEXT: |-FunctionDecl [[ADDR_182:0x[a-z0-9]*]] line:83:5 used test3 'int (float &&)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_183:0x[a-z0-9]*]] col:19 used f 'float &&' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_184:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_185:0x[a-z0-9]*]] +// CHECK-NEXT: | `-CallExpr [[ADDR_186:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-ImplicitCastExpr [[ADDR_187:0x[a-z0-9]*]] 'int (*)(float &&)' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_188:0x[a-z0-9]*]] 'int (float &&)' {{.*}}Function [[ADDR_71]] 'also_before' 'int (float &&)' +// CHECK-NEXT: | `-CallExpr [[ADDR_189:0x[a-z0-9]*]] 'typename remove_reference::type':'float' xvalue +// CHECK-NEXT: | |-ImplicitCastExpr [[ADDR_190:0x[a-z0-9]*]] 'typename remove_reference::type &&(*)(float &)' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_191:0x[a-z0-9]*]] 'typename remove_reference::type &&(float &)' {{.*}}Function [[ADDR_42]] 'move' 'typename remove_reference::type &&(float &)' (FunctionTemplate [[ADDR_31]] 'move') +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_192:0x[a-z0-9]*]] 'float' {{.*}}ParmVar [[ADDR_183]] 'f' 'float &&' +// CHECK-NEXT: |-FunctionDecl [[ADDR_193:0x[a-z0-9]*]] line:88:5 used test4 'int (short &&)' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_194:0x[a-z0-9]*]] col:19 used s 'short &&' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_195:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_196:0x[a-z0-9]*]] +// CHECK-NEXT: | `-PseudoObjectExpr [[ADDR_197:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-CallExpr [[ADDR_198:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | | |-ImplicitCastExpr [[ADDR_199:0x[a-z0-9]*]] 'int (*)(short &&)' +// CHECK-NEXT: | | | `-DeclRefExpr [[ADDR_200:0x[a-z0-9]*]] 'int (short &&)' {{.*}}Function [[ADDR_150]] 'also_after' 'int (short &&)' +// CHECK-NEXT: | | `-CallExpr [[ADDR_201:0x[a-z0-9]*]] 'typename remove_reference::type':'short' xvalue +// CHECK-NEXT: | | |-ImplicitCastExpr [[ADDR_202:0x[a-z0-9]*]] 'typename remove_reference::type &&(*)(short &)' +// CHECK-NEXT: | | | `-DeclRefExpr [[ADDR_203:0x[a-z0-9]*]] 'typename remove_reference::type &&(short &)' {{.*}}Function [[ADDR_52]] 'move' 'typename remove_reference::type &&(short &)' (FunctionTemplate [[ADDR_31]] 'move') +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_204:0x[a-z0-9]*]] 'short' {{.*}}ParmVar [[ADDR_194]] 's' 'short &&' +// CHECK-NEXT: | `-CallExpr [[ADDR_205:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-ImplicitCastExpr [[ADDR_206:0x[a-z0-9]*]] 'int (*)(short &&)' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_118]] 'int (short &&)' {{.*}}Function [[ADDR_119]] 'also_after[implementation={vendor(llvm)}]' 'int (short &&)' +// CHECK-NEXT: | `-CallExpr [[ADDR_201]] 'typename remove_reference::type':'short' xvalue +// CHECK-NEXT: | |-ImplicitCastExpr [[ADDR_202]] 'typename remove_reference::type &&(*)(short &)' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_203]] 'typename remove_reference::type &&(short &)' {{.*}}Function [[ADDR_52]] 'move' 'typename remove_reference::type &&(short &)' (FunctionTemplate [[ADDR_31]] 'move') +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_204]] 'short' {{.*}}ParmVar [[ADDR_194]] 's' 'short &&' +// CHECK-NEXT: `-FunctionDecl [[ADDR_207:0x[a-z0-9]*]] line:93:5 test 'int (float &&, short &&)' +// CHECK-NEXT: |-ParmVarDecl [[ADDR_208:0x[a-z0-9]*]] col:18 used f 'float &&' +// CHECK-NEXT: |-ParmVarDecl [[ADDR_209:0x[a-z0-9]*]] col:29 used s 'short &&' +// CHECK-NEXT: `-CompoundStmt [[ADDR_210:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_211:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_212:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-BinaryOperator [[ADDR_213:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: | |-BinaryOperator [[ADDR_214:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: | | |-CallExpr [[ADDR_215:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | | | `-ImplicitCastExpr [[ADDR_216:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | | | `-DeclRefExpr [[ADDR_217:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_156]] 'test1' 'int ({{.*}})' +// CHECK-NEXT: | | `-CallExpr [[ADDR_218:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | | `-ImplicitCastExpr [[ADDR_219:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_220:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_168]] 'test2' 'int ({{.*}})' +// CHECK-NEXT: | `-CallExpr [[ADDR_221:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-ImplicitCastExpr [[ADDR_222:0x[a-z0-9]*]] 'int (*)(float &&)' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_223:0x[a-z0-9]*]] 'int (float &&)' {{.*}}Function [[ADDR_182]] 'test3' 'int (float &&)' +// CHECK-NEXT: | `-CallExpr [[ADDR_224:0x[a-z0-9]*]] 'typename remove_reference::type':'float' xvalue +// CHECK-NEXT: | |-ImplicitCastExpr [[ADDR_225:0x[a-z0-9]*]] 'typename remove_reference::type &&(*)(float &)' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_226:0x[a-z0-9]*]] 'typename remove_reference::type &&(float &)' {{.*}}Function [[ADDR_42]] 'move' 'typename remove_reference::type &&(float &)' (FunctionTemplate [[ADDR_31]] 'move') +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_227:0x[a-z0-9]*]] 'float' {{.*}}ParmVar [[ADDR_208]] 'f' 'float &&' +// CHECK-NEXT: `-CallExpr [[ADDR_228:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: |-ImplicitCastExpr [[ADDR_229:0x[a-z0-9]*]] 'int (*)(short &&)' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_230:0x[a-z0-9]*]] 'int (short &&)' {{.*}}Function [[ADDR_193]] 'test4' 'int (short &&)' +// CHECK-NEXT: `-CallExpr [[ADDR_231:0x[a-z0-9]*]] 'typename remove_reference::type':'short' xvalue +// CHECK-NEXT: |-ImplicitCastExpr [[ADDR_232:0x[a-z0-9]*]] 'typename remove_reference::type &&(*)(short &)' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_233:0x[a-z0-9]*]] 'typename remove_reference::type &&(short &)' {{.*}}Function [[ADDR_52]] 'move' 'typename remove_reference::type &&(short &)' (FunctionTemplate [[ADDR_31]] 'move') +// CHECK-NEXT: `-DeclRefExpr [[ADDR_234:0x[a-z0-9]*]] 'short' {{.*}}ParmVar [[ADDR_209]] 's' 'short &&' diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/AST/nrvo.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/AST/nrvo.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/AST/nrvo.c 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/AST/nrvo.c 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -ast-dump -fblocks %s | FileCheck -strict-whitespace %s + +struct A {}; + +struct A f1() { + // CHECK: FunctionDecl 0x{{[^ ]*}} line:[[@LINE-1]]:10 f1 'struct A ()' + // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} + struct A a; + // CHECK-NEXT: DeclStmt 0x{{[^ ]*}} + // CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:12 used a 'struct A':'struct A' nrvo + return a; + // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} + // CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'struct A':'struct A' + // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'struct A':'struct A' lvalue Var 0x{{[^ ]*}} 'a' 'struct A':'struct A' +} + +void f2() { + (void)^{ + // CHECK: BlockDecl 0x{{[^ ]*}} line:[[@LINE-1]]:9 + // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} + struct A a; + // CHECK-NEXT: DeclStmt 0x{{[^ ]*}} + // CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:14 used a 'struct A':'struct A' nrvo + return a; + // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} + // CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'struct A':'struct A' + // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'struct A':'struct A' lvalue Var 0x{{[^ ]*}} 'a' 'struct A':'struct A' + }(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/arm64-microsoft-intrinsics.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/arm64-microsoft-intrinsics.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/arm64-microsoft-intrinsics.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/arm64-microsoft-intrinsics.c 2021-11-16 16:47:26.000000000 +0000 @@ -81,6 +81,28 @@ // CHECK-MSVC: fence syncscope("singlethread") // CHECK-LINUX: error: implicit declaration of function '_ReadWriteBarrier' +long long check_mulh(long long a, long long b) { + return __mulh(a, b); +} + +// CHECK-MSVC: %[[ARG1:.*]] = sext i64 {{.*}} to i128 +// CHECK-MSVC: %[[ARG2:.*]] = sext i64 {{.*}} to i128 +// CHECK-MSVC: %[[PROD:.*]] = mul nsw i128 %[[ARG1]], %[[ARG2]] +// CHECK-MSVC: %[[HIGH:.*]] = ashr i128 %[[PROD]], 64 +// CHECK-MSVC: %[[RES:.*]] = trunc i128 %[[HIGH]] to i64 +// CHECK-LINUX: error: implicit declaration of function '__mulh' + +unsigned long long check_umulh(unsigned long long a, unsigned long long b) { + return __umulh(a, b); +} + +// CHECK-MSVC: %[[ARG1:.*]] = zext i64 {{.*}} to i128 +// CHECK-MSVC: %[[ARG2:.*]] = zext i64 {{.*}} to i128 +// CHECK-MSVC: %[[PROD:.*]] = mul nuw i128 %[[ARG1]], %[[ARG2]] +// CHECK-MSVC: %[[HIGH:.*]] = lshr i128 %[[PROD]], 64 +// CHECK-MSVC: %[[RES:.*]] = trunc i128 %[[HIGH]] to i64 +// CHECK-LINUX: error: implicit declaration of function '__umulh' + unsigned __int64 check__getReg() { unsigned volatile __int64 reg; reg = __getReg(18); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ffp-contract-option.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ffp-contract-option.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ffp-contract-option.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ffp-contract-option.c 2021-11-16 16:47:26.000000000 +0000 @@ -1,46 +1,9 @@ -// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=aarch64-apple-darwin -S -o - %s | FileCheck --check-prefix=CHECK-FMADD %s +// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=aarch64-apple-darwin -S -o - %s | FileCheck %s // REQUIRES: aarch64-registered-target float fma_test1(float a, float b, float c) { -// CHECK-FMADD: fmadd - float x = a * b; - float y = x + c; - return y; -} - -// RUN: %clang_cc1 -triple=x86_64 %s -emit-llvm -o - \ -// RUN:| FileCheck --check-prefix=CHECK-DEFAULT %s -// -// RUN: %clang_cc1 -triple=x86_64 -ffp-contract=off %s -emit-llvm -o - \ -// RUN:| FileCheck --check-prefix=CHECK-DEFAULT %s -// RUN: %clang_cc1 -triple=x86_64 -ffp-contract=on %s -emit-llvm -o - \ -// RUN:| FileCheck --check-prefix=CHECK-ON %s -// RUN: %clang_cc1 -triple=x86_64 -ffp-contract=fast %s -emit-llvm -o - \ -// RUN:| FileCheck --check-prefix=CHECK-CONTRACTFAST %s -// -// RUN: %clang_cc1 -triple=x86_64 -ffast-math %s -emit-llvm -o - \ -// RUN:| FileCheck --check-prefix=CHECK-DEFAULTFAST %s -// RUN: %clang_cc1 -triple=x86_64 -ffast-math -ffp-contract=off %s -emit-llvm -o - \ -// RUN:| FileCheck --check-prefix=CHECK-DEFAULTFAST %s -// RUN: %clang_cc1 -triple=x86_64 -ffast-math -ffp-contract=on %s -emit-llvm -o - \ -// RUN:| FileCheck --check-prefix=CHECK-ONFAST %s -// RUN: %clang_cc1 -triple=x86_64 -ffast-math -ffp-contract=fast %s -emit-llvm -o - \ -// RUN:| FileCheck --check-prefix=CHECK-FASTFAST %s -float mymuladd( float x, float y, float z ) { - return x * y + z; - // CHECK-DEFAULT: = fmul float - // CHECK-DEFAULT: = fadd float - - // CHECK-ON: = call float @llvm.fmuladd.f32 - - // CHECK-CONTRACTFAST: = fmul contract float - // CHECK-CONTRACTFAST: = fadd contract float - - // CHECK-DEFAULTFAST: = fmul reassoc nnan ninf nsz arcp afn float - // CHECK-DEFAULTFAST: = fadd reassoc nnan ninf nsz arcp afn float - - // CHECK-ONFAST: = call reassoc nnan ninf nsz arcp afn float @llvm.fmuladd.f32 - - // CHECK-FASTFAST: = fmul fast float - // CHECK-FASTFAST: = fadd fast float +// CHECK: fmadd + float x = a * b; + float y = x + c; + return y; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/nrvo-tracking.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/nrvo-tracking.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/nrvo-tracking.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/nrvo-tracking.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -282,3 +282,40 @@ } } // namespace test_alignas + +namespace PR51862 { + +template T test() { + T a; + T b; + if (0) + return a; + return b; +} + +struct A { + A(); + A(A &); + A(int); + operator int(); +}; + +// CHECK-LABEL: define{{.*}} void @_ZN7PR518624testINS_1AEEET_v +// CHECK: call i32 @_ZN7PR518621AcviEv +// CHECK-NEXT: call void @_ZN7PR518621AC1Ei +// CHECK-NEXT: call void @llvm.lifetime.end +template A test(); + +struct BSub {}; +struct B : BSub { + B(); + B(B &); + B(const BSub &); +}; + +// CHECK-LABEL: define{{.*}} void @_ZN7PR518624testINS_1BEEET_v +// CHECK: call void @_ZN7PR518621BC1ERKNS_4BSubE +// CHECK-NEXT: call void @llvm.lifetime.end +template B test(); + +} // namespace PR51862 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ppc-emmintrin.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ppc-emmintrin.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ppc-emmintrin.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ppc-emmintrin.c 2021-11-16 16:47:26.000000000 +0000 @@ -2,9 +2,9 @@ // REQUIRES: powerpc-registered-target // RUN: %clang -S -emit-llvm -target powerpc64-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \ -// RUN: -ffp-contract=off -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-BE +// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-BE // RUN: %clang -S -emit-llvm -target powerpc64le-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \ -// RUN: -ffp-contract=off -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-LE +// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-LE // CHECK-BE-DAG: @_mm_movemask_pd.perm_mask = internal constant <4 x i32> , align 16 // CHECK-BE-DAG: @_mm_shuffle_epi32.permute_selectors = internal constant [4 x i32] [i32 66051, i32 67438087, i32 134810123, i32 202182159], align 4 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ppc-xmmintrin.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ppc-xmmintrin.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ppc-xmmintrin.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGen/ppc-xmmintrin.c 2021-11-16 16:47:26.000000000 +0000 @@ -2,11 +2,11 @@ // REQUIRES: powerpc-registered-target // RUN: %clang -S -emit-llvm -target powerpc64-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \ -// RUN: -ffp-contract=off -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-BE +// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-BE // RUN: %clang -x c++ -fsyntax-only -target powerpc64-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \ // RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns // RUN: %clang -S -emit-llvm -target powerpc64le-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \ -// RUN: -ffp-contract=off -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-LE +// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-LE // RUN: %clang -x c++ -fsyntax-only -target powerpc64le-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \ // RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGenCXX/copy-elision.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGenCXX/copy-elision.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGenCXX/copy-elision.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CodeGenCXX/copy-elision.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown-gnu -emit-llvm -O1 -fexperimental-new-pass-manager -o - %s | FileCheck %s + +template T test() { + return T(); +} + +struct A { + A(); + A(A &); + A(int); + operator int(); +}; + +// FIXME: There should be copy elision here. +// CHECK-LABEL: define{{.*}} void @_Z4testI1AET_v +// CHECK: call void @_ZN1AC1Ev +// CHECK-NEXT: call i32 @_ZN1AcviEv +// CHECK-NEXT: call void @_ZN1AC1Ei +// CHECK-NEXT: call void @llvm.lifetime.end +template A test(); + +struct BSub {}; +struct B : BSub { + B(); + B(B &); + B(const BSub &); +}; + +// FIXME: There should be copy elision here. +// CHECK-LABEL: define{{.*}} void @_Z4testI1BET_v +// CHECK: call void @_ZN1BC1Ev +// CHECK: call void @_ZN1BC1ERK4BSub +// CHECK-NEXT: call void @llvm.lifetime.end +template B test(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/class/class.init/class.copy.elision/p3.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/class/class.init/class.copy.elision/p3.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/class/class.init/class.copy.elision/p3.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/class/class.init/class.copy.elision/p3.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -518,3 +518,37 @@ template X test_dependent_invalid_decl(); // expected-note {{requested here}} } // namespace test_auto_variables + +namespace PR51708 { + +class a1; // expected-note 4 {{forward declaration of 'PR51708::a1'}} +template class A2; // expected-note 4 {{template is declared here}} +using a2 = A2; + +template b f() { + // expected-error@-1 {{incomplete result type 'PR51708::a1' in function definition}} + // expected-error@-2 {{implicit instantiation of undefined template 'PR51708::A2}} + + b d; + // expected-error@-1 {{variable has incomplete type 'PR51708::a1'}} + // expected-error@-2 {{implicit instantiation of undefined template 'PR51708::A2}} + + return d; +} +template a1 f(); // expected-note-re {{in instantiation {{.*}} requested here}} +template a2 f(); // expected-note-re {{in instantiation {{.*}} requested here}} + +template b g() { + // expected-error@-1 {{incomplete result type 'PR51708::a1' in function definition}} + // expected-error@-2 {{implicit instantiation of undefined template 'PR51708::A2}} + + b d __attribute__((aligned(1))); + // expected-error@-1 {{variable has incomplete type 'PR51708::a1'}} + // expected-error@-2 {{implicit instantiation of undefined template 'PR51708::A2}} + + return d; +} +template a1 g(); // expected-note-re {{in instantiation {{.*}} requested here}} +template a2 g(); // expected-note-re {{in instantiation {{.*}} requested here}} + +} // namespace PR51708 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -76,3 +76,25 @@ template concept d = true; d<,> auto e = 0; // expected-error{{expected expression}} } + +namespace PR48617 { + template concept C = true; + template class A {}; + + template C auto e(A) { return 0; } + + // FIXME: The error here does not make sense. + template auto e<>(A<>); + // expected-error@-1 {{explicit instantiation of 'e' does not refer to a function template}} + // expected-note@-5 {{candidate template ignored: failed template argument deduction}} + + // FIXME: Should be able to instantiate this with no errors. + template C auto e(A); + // expected-error@-1 {{explicit instantiation of 'e' does not refer to a function template}} + // expected-note@-10 {{candidate template ignored: could not match 'C auto' against 'C auto'}} + + template C<> auto e<>(A<>); + + template A c(Ts...); + int f = e(c(1, 2)); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -192,3 +192,29 @@ using c3 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}} using c4 = C3_check; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}} } + +namespace PR48656 { + +template concept C = requires { requires requires { T::a; }; }; +// expected-note@-1 {{because 'T::a' would be invalid: no member named 'a' in 'PR48656::T1'}} + +template struct A {}; +// expected-note@-1 {{because 'PR48656::T1' does not satisfy 'C'}} + +struct T1 {}; +template struct A; // expected-error {{constraints not satisfied for class template 'A' [with $0 = ]}} + +struct T2 { static constexpr bool a = false; }; +template struct A; + +template struct T3 { + static void m(auto) requires requires { T::fail; } {} + // expected-note@-1 {{constraints not satisfied}} + // expected-note@-2 {{type 'int' cannot be used prior to '::'}} +}; +template void t3(Args... args) { (..., T3::m(args)); } +// expected-error@-1 {{no matching function for call to 'm'}} + +template void t3(int); // expected-note {{requested here}} + +} // namespace PR48656 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -91,7 +91,7 @@ template concept C1 = sizeof(T) != 0; template concept C2 = C1::type>; -template requires C1 void t1() = delete; // expected-note {{candidate function}} +template requires C1 void t1() {}; // expected-note {{candidate function}} template requires C1 && C2 void t1() = delete; // expected-note {{candidate function}} template void t1(); void t1() { t1(); } // expected-error {{call to deleted function 't1'}} diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/amdgpu-openmp-toolchain.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/amdgpu-openmp-toolchain.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/amdgpu-openmp-toolchain.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/amdgpu-openmp-toolchain.c 2021-11-16 16:47:26.000000000 +0000 @@ -74,3 +74,6 @@ // RUN: %clang -### --target=x86_64-unknown-linux-gnu -emit-llvm -S -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx803 -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-EMIT-LLVM-IR // CHECK-EMIT-LLVM-IR: clang{{.*}}"-cc1"{{.*}}"-triple" "amdgcn-amd-amdhsa"{{.*}}"-emit-llvm" + +// RUN: env LIBRARY_PATH=%S/Inputs/hip_dev_lib %clang -### -target x86_64-pc-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx803 -lm --rocm-device-lib-path=%S/Inputs/rocm/amdgcn/bitcode %s 2>&1 | FileCheck %s --check-prefix=CHECK-LIB-DEVICE +// CHECK-LIB-DEVICE: {{.*}}llvm-link{{.*}}ocml.bc"{{.*}}ockl.bc"{{.*}}oclc_daz_opt_on.bc"{{.*}}oclc_unsafe_math_off.bc"{{.*}}oclc_finite_only_off.bc"{{.*}}oclc_correctly_rounded_sqrt_on.bc"{{.*}}oclc_wavefrontsize64_on.bc"{{.*}}oclc_isa_version_803.bc" diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/fopenmp.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/fopenmp.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/fopenmp.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/fopenmp.c 2021-11-16 16:47:26.000000000 +0000 @@ -10,6 +10,9 @@ // RUN: %clang -target x86_64-netbsd -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP // RUN: %clang -target x86_64-netbsd -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP // RUN: %clang -target x86_64-netbsd -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP +// RUN: %clang -target x86_64-openbsd -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP +// RUN: %clang -target x86_64-openbsd -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP +// RUN: %clang -target x86_64-openbsd -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP // RUN: %clang -target x86_64-windows-gnu -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP // RUN: %clang -target x86_64-windows-gnu -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP // RUN: %clang -target x86_64-windows-gnu -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP @@ -74,6 +77,19 @@ // RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP // RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5 // +// RUN: %clang -target x86_64-openbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP +// RUN: %clang -target x86_64-openbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT +// RUN: %clang -target x86_64-openbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5 +// +// RUN: %clang -target x86_64-openbsd -fopenmp=libomp -static-openmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-STATIC-OMP +// RUN: %clang -target x86_64-openbsd -fopenmp=libgomp -static-openmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-STATIC-GOMP --check-prefix=CHECK-LD-STATIC-GOMP-NO-RT +// RUN: %clang -target x86_64-openbsd -fopenmp=libiomp5 -static-openmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-STATIC-IOMP5 +// RUN: %clang -target x86_64-openbsd -fopenmp=libiomp5 -static -static-openmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-STATIC-IOMP5-NO-BDYNAMIC +// +// RUN: %clang -nostdlib -target x86_64-openbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP +// RUN: %clang -nostdlib -target x86_64-openbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP +// RUN: %clang -nostdlib -target x86_64-openbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5 +// // RUN: %clang -target x86_64-windows-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP // RUN: %clang -target x86_64-windows-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT // RUN: %clang -target x86_64-windows-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5MD @@ -120,7 +136,7 @@ // CHECK-LD-STATIC-IOMP5: "-Bstatic" "-liomp5" "-Bdynamic" // // CHECK-LD-STATIC-IOMP5-NO-BDYNAMIC: "{{.*}}ld{{(.exe)?}}" -// For x86 Gnu, the driver passes -static, while NetBSD and FreeBSD pass -Bstatic +// For x86 Gnu, the driver passes -static, while FreeBSD, NetBSD and OpenBSD pass -Bstatic // CHECK-LD-STATIC-IOMP5-NO-BDYNAMIC: "-{{B?}}static" {{.*}} "-liomp5" // CHECK-LD-STATIC-IOMP5-NO-BDYNAMIC-NOT: "-Bdynamic" // @@ -140,6 +156,7 @@ // RUN: %clang -target x86_64-darwin -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANY // RUN: %clang -target x86_64-freebsd -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANY // RUN: %clang -target x86_64-netbsd -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANY +// RUN: %clang -target x86_64-openbsd -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANY // RUN: %clang -target x86_64-windows-gnu -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANYMD // // CHECK-LD-ANY: "{{.*}}ld{{(.exe)?}}" diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/fp-model.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/fp-model.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/fp-model.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/fp-model.c 2021-11-16 16:47:26.000000000 +0000 @@ -1,90 +1,88 @@ // Test that incompatible combinations of -ffp-model= options // and other floating point options get a warning diagnostic. +// +// REQUIRES: clang-driver -// RUN: %clang -target x86_64 -### -ffp-model=fast -ffp-contract=off -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=fast -ffp-contract=off -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN %s // WARN: warning: overriding '-ffp-model=fast' option with '-ffp-contract=off' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=fast -ffp-contract=on -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=fast -ffp-contract=on -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN1 %s // WARN1: warning: overriding '-ffp-model=fast' option with '-ffp-contract=on' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -fassociative-math -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -fassociative-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN2 %s // WARN2: warning: overriding '-ffp-model=strict' option with '-fassociative-math' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -ffast-math -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -ffast-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN3 %s // WARN3: warning: overriding '-ffp-model=strict' option with '-ffast-math' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -ffinite-math-only -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -ffinite-math-only -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN4 %s // WARN4: warning: overriding '-ffp-model=strict' option with '-ffinite-math-only' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -ffp-contract=fast -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -ffp-contract=fast -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN5 %s // WARN5: warning: overriding '-ffp-model=strict' option with '-ffp-contract=fast' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -ffp-contract=fast -c %s 2>&1 \ -// RUN: | FileCheck --check-prefix=WARN6 %s -// WARN6: warning: overriding '-ffp-model=strict' option with '-ffp-contract=fast' [-Woverriding-t-option] - -// RUN: %clang -target x86_64 -### -ffp-model=strict -ffp-contract=on -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -ffp-contract=on -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN7 %s // WARN7: warning: overriding '-ffp-model=strict' option with '-ffp-contract=on' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -fno-honor-infinities -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -fno-honor-infinities -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN8 %s // WARN8: warning: overriding '-ffp-model=strict' option with '-fno-honor-infinities' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -fno-honor-nans -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -fno-honor-nans -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN9 %s // WARN9: warning: overriding '-ffp-model=strict' option with '-fno-honor-nans' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -fno-rounding-math -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -fno-rounding-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARNa %s // WARNa: warning: overriding '-ffp-model=strict' option with '-fno-rounding-math' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -fno-signed-zeros -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -fno-signed-zeros -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARNb %s // WARNb: warning: overriding '-ffp-model=strict' option with '-fno-signed-zeros' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -fno-trapping-math -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -fno-trapping-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARNc %s // WARNc: warning: overriding '-ffp-model=strict' option with '-fno-trapping-math' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -freciprocal-math -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -freciprocal-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARNd %s // WARNd: warning: overriding '-ffp-model=strict' option with '-freciprocal-math' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -funsafe-math-optimizations -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -funsafe-math-optimizations -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARNe %s // WARNe: warning: overriding '-ffp-model=strict' option with '-funsafe-math-optimizations' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -Ofast -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -Ofast -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARNf %s // WARNf: warning: overriding '-ffp-model=strict' option with '-Ofast' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -ffp-model=strict -fdenormal-fp-math=preserve-sign,preserve-sign -c %s 2>&1 \ +// RUN: %clang -### -ffp-model=strict -fdenormal-fp-math=preserve-sign,preserve-sign -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=WARN10 %s // WARN10: warning: overriding '-ffp-model=strict' option with '-fdenormal-fp-math=preserve-sign,preserve-sign' [-Woverriding-t-option] -// RUN: %clang -target x86_64 -### -c %s 2>&1 \ +// RUN: %clang -### -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-NOROUND %s // CHECK-NOROUND: "-cc1" // CHECK-NOROUND: "-fno-rounding-math" -// RUN: %clang -target x86_64 -### -frounding-math -c %s 2>&1 \ +// RUN: %clang -### -frounding-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-ROUND --implicit-check-not ffp-exception-behavior=strict %s // CHECK-ROUND: "-cc1" // CHECK-ROUND: "-frounding-math" -// RUN: %clang -target x86_64 -### -ftrapping-math -c %s 2>&1 \ +// RUN: %clang -### -ftrapping-math -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-TRAP %s // CHECK-TRAP: "-cc1" // CHECK-TRAP: "-ffp-exception-behavior=strict" -// RUN: %clang -target x86_64 -### -nostdinc -ffp-model=fast -c %s 2>&1 \ +// RUN: %clang -### -nostdinc -ffp-model=fast -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FPM-FAST %s // CHECK-FPM-FAST: "-cc1" // CHECK-FPM-FAST: "-menable-no-infs" @@ -98,35 +96,34 @@ // CHECK-FPM-FAST: "-ffast-math" // CHECK-FPM-FAST: "-ffinite-math-only" -// RUN: %clang -target x86_64 -### -nostdinc -ffp-model=precise -c %s 2>&1 \ +// RUN: %clang -### -nostdinc -ffp-model=precise -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FPM-PRECISE %s // CHECK-FPM-PRECISE: "-cc1" -// CHECK-FPM-PRECISE: "-ffp-contract=on" +// CHECK-FPM-PRECISE: "-ffp-contract=fast" // CHECK-FPM-PRECISE: "-fno-rounding-math" -// RUN: %clang -target x86_64 -### -nostdinc -ffp-model=strict -c %s 2>&1 \ +// RUN: %clang -### -nostdinc -ffp-model=strict -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FPM-STRICT %s // CHECK-FPM-STRICT: "-cc1" -// CHECK-FPM-STRICT: "-fmath-errno" -// CHECK-FPM-STRICT: "-ffp-contract=off" // CHECK-FPM-STRICT: "-frounding-math" // CHECK-FPM-STRICT: "-ffp-exception-behavior=strict" -// RUN: %clang -target x86_64 -### -nostdinc -ffp-exception-behavior=strict -c %s 2>&1 \ +// RUN: %clang -### -nostdinc -ffp-exception-behavior=strict -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FEB-STRICT %s // CHECK-FEB-STRICT: "-cc1" // CHECK-FEB-STRICT: "-fno-rounding-math" // CHECK-FEB-STRICT: "-ffp-exception-behavior=strict" -// RUN: %clang -target x86_64 -### -nostdinc -ffp-exception-behavior=maytrap -c %s 2>&1 \ +// RUN: %clang -### -nostdinc -ffp-exception-behavior=maytrap -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FEB-MAYTRAP %s // CHECK-FEB-MAYTRAP: "-cc1" // CHECK-FEB-MAYTRAP: "-fno-rounding-math" // CHECK-FEB-MAYTRAP: "-ffp-exception-behavior=maytrap" -// RUN: %clang -target x86_64 -### -nostdinc -ffp-exception-behavior=ignore -c %s 2>&1 \ +// RUN: %clang -### -nostdinc -ffp-exception-behavior=ignore -c %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-FEB-IGNORE %s // CHECK-FEB-IGNORE: "-cc1" // CHECK-FEB-IGNORE: "-fno-rounding-math" // CHECK-FEB-IGNORE: "-ffp-exception-behavior=ignore" + diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/hexagon-toolchain-linux.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/hexagon-toolchain-linux.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/hexagon-toolchain-linux.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Driver/hexagon-toolchain-linux.c 2021-11-16 16:47:26.000000000 +0000 @@ -1,3 +1,5 @@ +// UNSUPPORTED: system-windows + // ----------------------------------------------------------------------------- // Passing --musl // ----------------------------------------------------------------------------- @@ -94,4 +96,26 @@ // RUN: -mcpu=hexagonv60 \ // RUN: %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK007 %s -// CHECK007: "-internal-isystem" "{{.*}}hexagon{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1" +// CHECK007: "-internal-isystem" "{{.*}}hexagon{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1" +// ----------------------------------------------------------------------------- +// internal-isystem for linux with and without musl +// ----------------------------------------------------------------------------- +// RUN: %clang -### -target hexagon-unknown-linux-musl \ +// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK008 %s +// CHECK008: InstalledDir: [[INSTALLED_DIR:.+]] +// CHECK008: "-resource-dir" "[[RESOURCE:[^"]+]]" +// CHECK008-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include" +// CHECK008-SAME: {{^}} "-internal-externc-isystem" "[[INSTALLED_DIR]]/../target/hexagon/include" + +// RUN: %clang -### -target hexagon-unknown-linux \ +// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK009 %s +// CHECK009: InstalledDir: [[INSTALLED_DIR:.+]] +// CHECK009: "-resource-dir" "[[RESOURCE:[^"]+]]" +// CHECK009-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include" +// CHECK009-SAME: {{^}} "-internal-externc-isystem" "[[INSTALLED_DIR]]/../target/hexagon/include" diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/amdgcn_openmp_device_math.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/amdgcn_openmp_device_math.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/amdgcn_openmp_device_math.c 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/amdgcn_openmp_device_math.c 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -internal-isystem %S/Inputs/include -x c -fopenmp -triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm-bc %s -o %t-host.bc +// RUN: %clang_cc1 -internal-isystem %S/../../lib/Headers/openmp_wrappers -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -x c -fopenmp -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-host.bc -o - | FileCheck %s --check-prefixes=CHECK-C,CHECK +// RUN: %clang_cc1 -internal-isystem %S/Inputs/include -x c++ -fopenmp -triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm-bc %s -o %t-host.bc +// RUN: %clang_cc1 -internal-isystem %S/../../lib/Headers/openmp_wrappers -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -x c++ -fopenmp -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-host.bc -o - | FileCheck %s --check-prefixes=CHECK-CPP,CHECK + +#ifdef __cplusplus +#include +#else +#include +#endif + +void test_math_f64(double x) { +// CHECK-LABEL: define {{.*}}test_math_f64 +#pragma omp target + { + // CHECK: call double @__ocml_sin_f64 + double l1 = sin(x); + // CHECK: call double @__ocml_cos_f64 + double l2 = cos(x); + // CHECK: call double @__ocml_fabs_f64 + double l3 = fabs(x); + } +} + +void test_math_f32(float x) { +// CHECK-LABEL: define {{.*}}test_math_f32 +#pragma omp target + { + // CHECK-C: call double @__ocml_sin_f64 + // CHECK-CPP: call float @__ocml_sin_f32 + float l1 = sin(x); + // CHECK-C: call double @__ocml_cos_f64 + // CHECK-CPP: call float @__ocml_cos_f32 + float l2 = cos(x); + // CHECK-C: call double @__ocml_fabs_f64 + // CHECK-CPP: call float @__ocml_fabs_f32 + float l3 = fabs(x); + } +} +void test_math_f32_suffix(float x) { +// CHECK-LABEL: define {{.*}}test_math_f32_suffix +#pragma omp target + { + // CHECK: call float @__ocml_sin_f32 + float l1 = sinf(x); + // CHECK: call float @__ocml_cos_f32 + float l2 = cosf(x); + // CHECK: call float @__ocml_fabs_f32 + float l3 = fabsf(x); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/amdgcn-openmp-device-math-complex.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/amdgcn-openmp-device-math-complex.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/amdgcn-openmp-device-math-complex.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/amdgcn-openmp-device-math-complex.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -verify -internal-isystem %S/Inputs/include -fopenmp -x c++ -triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm-bc %s -o %t-x86-host.bc +// RUN: %clang_cc1 -verify -internal-isystem %S/../../lib/Headers/openmp_wrappers -include __clang_openmp_device_functions.h -internal-isystem %S/Inputs/include -fopenmp -x c++ -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-x86-host.bc -aux-triple x86_64-unknown-unknown -o - | FileCheck %s +// expected-no-diagnostics + +#include +#include + +// CHECK: define weak {{.*}} @__muldc3 +// CHECK-DAG: call i32 @__ocml_isnan_f64( +// CHECK-DAG: call i32 @__ocml_isinf_f64( + +// CHECK: define weak {{.*}} @__mulsc3 +// CHECK-DAG: call i32 @__ocml_isnan_f32( +// CHECK-DAG: call i32 @__ocml_isinf_f32( +// CHECK-DAG: call float @__ocml_copysign_f32( + +// CHECK: define weak {{.*}} @__divdc3 +// CHECK-DAG: call i32 @__ocml_isnan_f64( +// CHECK-DAG: call i32 @__ocml_isinf_f64( +// CHECK-DAG: call i32 @__ocml_isfinite_f64( +// CHECK-DAG: call double @__ocml_copysign_f64( +// CHECK-DAG: call double @__ocml_scalbn_f64( +// CHECK-DAG: call double @__ocml_fabs_f64( +// CHECK-DAG: call double @__ocml_logb_f64( + +// CHECK: define weak {{.*}} @__divsc3 +// CHECK-DAG: call i32 @__ocml_isnan_f32( +// CHECK-DAG: call i32 @__ocml_isinf_f32( +// CHECK-DAG: call i32 @__ocml_isfinite_f32( +// CHECK-DAG: call float @__ocml_copysign_f32( +// CHECK-DAG: call float @__ocml_scalbn_f32( +// CHECK-DAG: call float @__ocml_fabs_f32( +// CHECK-DAG: call float @__ocml_logb_f32( + +// We actually check that there are no declarations of non-OpenMP functions. +// That is, as long as we don't call an unkown function with a name that +// doesn't start with '__' we are good :) + +// CHECK-NOT: declare.*@[^_] + +void test_scmplx(std::complex a) { +#pragma omp target + { + (void)(a * (a / a)); + } +} + +void test_dcmplx(std::complex a) { +#pragma omp target + { + (void)(a * (a / a)); + } +} + +template +std::complex test_template_math_calls(std::complex a) { + decltype(a) r = a; +#pragma omp target + { + r = std::sin(r); + r = std::cos(r); + r = std::exp(r); + r = std::atan(r); + r = std::acos(r); + } + return r; +} + +std::complex test_scall(std::complex a) { + decltype(a) r; +#pragma omp target + { + r = std::sin(a); + } + return test_template_math_calls(r); +} + +std::complex test_dcall(std::complex a) { + decltype(a) r; +#pragma omp target + { + r = std::exp(a); + } + return test_template_math_calls(r); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/algorithm rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/algorithm --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/algorithm 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/algorithm 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,6 @@ +#pragma once + +namespace std { + template constexpr const T& min(const T& a, const T& b); + template constexpr const T& max(const T& a, const T& b); +} \ No newline at end of file diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/cstdlib rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/cstdlib --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/cstdlib 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/cstdlib 2021-11-16 16:47:26.000000000 +0000 @@ -27,3 +27,4 @@ double abs(double __x) { return fabs(__x); } } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/omp.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/omp.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/omp.h 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/omp.h 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,21 @@ +#ifndef __OMP_H +#define __OMP_H + +#if _OPENMP +// Follows the pattern in interface.h +// Clang sema checks this type carefully, needs to closely match that from omp.h +typedef enum omp_allocator_handle_t { + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + KMP_ALLOCATOR_MAX_HANDLE = ~(0U) +} omp_allocator_handle_t; +#endif + +#endif diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/utility rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/utility --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/utility 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/Inputs/include/utility 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,2 @@ +#pragma once + diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/openmp_device_math_isnan.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/openmp_device_math_isnan.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/openmp_device_math_isnan.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Headers/openmp_device_math_isnan.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -21,14 +21,14 @@ double math(float f, double d) { double r = 0; // INT_RETURN: call i32 @__nv_isnanf(float - // AMD_INT_RETURN: call i32 @_{{.*}}isnanf(float + // AMD_INT_RETURN: call i32 @__ocml_isnan_f32(float // BOOL_RETURN: call i32 @__nv_isnanf(float - // AMD_BOOL_RETURN: call zeroext i1 @_{{.*}}isnanf(float + // AMD_BOOL_RETURN: call i32 @__ocml_isnan_f32(float r += std::isnan(f); // INT_RETURN: call i32 @__nv_isnand(double - // AMD_INT_RETURN: call i32 @_{{.*}}isnand(double + // AMD_INT_RETURN: call i32 @__ocml_isnan_f64(double // BOOL_RETURN: call i32 @__nv_isnand(double - // AMD_BOOL_RETURN: call zeroext i1 @_{{.*}}isnand(double + // AMD_BOOL_RETURN: call i32 @__ocml_isnan_f64(double r += std::isnan(d); return r; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/OpenMP/parallel_if_codegen_PR51349.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/OpenMP/parallel_if_codegen_PR51349.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/OpenMP/parallel_if_codegen_PR51349.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/OpenMP/parallel_if_codegen_PR51349.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,38 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --include-generated-funcs +// RUN: %clang_cc1 -x c++ -O1 -fopenmp-version=45 -disable-llvm-optzns -verify -fopenmp -triple x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() { +#pragma omp parallel if(0) + ; +} + +#endif +// CHECK: Function Attrs: mustprogress nounwind +// CHECK-LABEL: define {{[^@]+}}@_Z3foov +// CHECK-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTBOUND_ZERO_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, i32* [[DOTBOUND_ZERO_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1:[0-9]+]]) +// CHECK-NEXT: call void @__kmpc_serialized_parallel(%struct.ident_t* @[[GLOB1]], i32 [[TMP0]]) +// CHECK-NEXT: store i32 [[TMP0]], i32* [[DOTTHREADID_TEMP_]], align 4, !tbaa [[TBAA3:![0-9]+]] +// CHECK-NEXT: call void @.omp_outlined.(i32* [[DOTTHREADID_TEMP_]], i32* [[DOTBOUND_ZERO_ADDR]]) #[[ATTR2:[0-9]+]] +// CHECK-NEXT: call void @__kmpc_end_serialized_parallel(%struct.ident_t* @[[GLOB1]], i32 [[TMP0]]) +// CHECK-NEXT: ret void +// +// +// CHECK: Function Attrs: noinline norecurse nounwind +// CHECK-LABEL: define {{[^@]+}}@.omp_outlined. +// CHECK-SAME: (i32* noalias [[DOTGLOBAL_TID_:%.*]], i32* noalias [[DOTBOUND_TID_:%.*]]) #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca i32*, align 8 +// CHECK-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca i32*, align 8 +// CHECK-NEXT: store i32* [[DOTGLOBAL_TID_]], i32** [[DOTGLOBAL_TID__ADDR]], align 8, !tbaa [[TBAA7:![0-9]+]] +// CHECK-NEXT: store i32* [[DOTBOUND_TID_]], i32** [[DOTBOUND_TID__ADDR]], align 8, !tbaa [[TBAA7]] +// CHECK-NEXT: ret void +// diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Preprocessor/init.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Preprocessor/init.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/Preprocessor/init.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/Preprocessor/init.c 2021-11-16 16:47:26.000000000 +0000 @@ -1464,6 +1464,16 @@ // OPENBSD:#define __WCHAR_TYPE__ int // OPENBSD:#define __WINT_TYPE__ int // +// RUN: %clang_cc1 -x c -std=c11 -E -dM -ffreestanding -triple=amd64-unknown-openbsd < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD-STDC %s +// RUN: %clang_cc1 -x c -std=gnu11 -E -dM -ffreestanding -triple=amd64-unknown-openbsd < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD-STDC %s +// RUN: %clang_cc1 -x c -std=c17 -E -dM -ffreestanding -triple=amd64-unknown-openbsd < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD-STDC %s +// OPENBSD-STDC:#define __STDC_NO_ATOMICS__ 1 +// OPENBSD-STDC:#define __STDC_NO_THREADS__ 1 +// +// RUN: %clang_cc1 -x c -std=c99 -E -dM -ffreestanding -triple=amd64-unknown-openbsd < /dev/null | FileCheck -match-full-lines -check-prefix OPENBSD-STDC-N %s +// OPENBSD-STDC-N-NOT:#define __STDC_NO_ATOMICS__ 1 +// OPENBSD-STDC-N-NOT:#define __STDC_NO_THREADS__ 1 +// // RUN: %clang_cc1 -E -dM -ffreestanding -triple=xcore-none-none < /dev/null | FileCheck -match-full-lines -check-prefix XCORE %s // XCORE:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ // XCORE:#define __LITTLE_ENDIAN__ 1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/SemaCXX/warn-thread-safety-analysis.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/SemaCXX/warn-thread-safety-analysis.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/test/SemaCXX/warn-thread-safety-analysis.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/test/SemaCXX/warn-thread-safety-analysis.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -2789,6 +2789,25 @@ } } +void loopPromote() { + RelockableMutexLock scope(&mu, SharedTraits{}); + for (unsigned i = 1; i < 10; ++i) { + x = 1; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}} + if (i == 5) + scope.PromoteShared(); + } +} + +void loopDemote() { + RelockableMutexLock scope(&mu, ExclusiveTraits{}); // expected-note {{the other acquisition of mutex 'mu' is here}} + // We have to warn on this join point despite the lock being managed ... + for (unsigned i = 1; i < 10; ++i) { + x = 1; // ... because we might miss that this doesn't always happen under exclusive lock. + if (i == 5) + scope.DemoteExclusive(); // expected-warning {{mutex 'mu' is acquired exclusively and shared in the same scope}} + } +} + void loopAcquireContinue() { RelockableMutexLock scope(&mu, DeferTraits{}); for (unsigned i = 1; i < 10; ++i) { @@ -2811,6 +2830,29 @@ } } } + +void loopPromoteContinue() { + RelockableMutexLock scope(&mu, SharedTraits{}); + for (unsigned i = 1; i < 10; ++i) { + x = 1; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}} + if (i == 5) { + scope.PromoteShared(); + continue; + } + } +} + +void loopDemoteContinue() { + RelockableMutexLock scope(&mu, ExclusiveTraits{}); // expected-note {{the other acquisition of mutex 'mu' is here}} + // We have to warn on this join point despite the lock being managed ... + for (unsigned i = 1; i < 10; ++i) { + x = 1; // ... because we might miss that this doesn't always happen under exclusive lock. + if (i == 5) { + scope.DemoteExclusive(); // expected-warning {{mutex 'mu' is acquired exclusively and shared in the same scope}} + continue; + } + } +} void exclusiveSharedJoin() { RelockableMutexLock scope(&mu, DeferTraits{}); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/tools/clang-repl/CMakeLists.txt rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/tools/clang-repl/CMakeLists.txt --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/tools/clang-repl/CMakeLists.txt 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/tools/clang-repl/CMakeLists.txt 2021-11-16 16:47:26.000000000 +0000 @@ -7,7 +7,7 @@ Support ) -add_clang_executable(clang-repl +add_clang_tool(clang-repl ClangRepl.cpp ) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/tools/libclang/CMakeLists.txt rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/tools/libclang/CMakeLists.txt --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/tools/libclang/CMakeLists.txt 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/tools/libclang/CMakeLists.txt 2021-11-16 16:47:26.000000000 +0000 @@ -1,3 +1,9 @@ +# The SOVERSION should be updated only if a change is made to the libclang +# ABI, and when it is updated, it should be updated to the current +# LLVM_VERSION_MAJOR. +# Please also see clang/tools/libclang/libclang.map +set(CLANG_SONAME 13) + set(SOURCES ARCMigrate.cpp BuildSystem.cpp @@ -171,12 +177,9 @@ set_property(SOURCE ARCMigrate.cpp APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libclang.map) - # The SOVERSION should be updated only if a change is made to the libclang - # ABI, and when it is updated, it should be updated to the current - # LLVM_VERSION_MAJOR. set_target_properties(libclang PROPERTIES VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}${LLVM_VERSION_SUFFIX} - SOVERSION 13) + SOVERSION ${CLANG_SONAME}) endif() endif() diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/tools/scan-build/libexec/ccc-analyzer rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/tools/scan-build/libexec/ccc-analyzer --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/tools/scan-build/libexec/ccc-analyzer 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/tools/scan-build/libexec/ccc-analyzer 2021-11-16 16:47:26.000000000 +0000 @@ -80,6 +80,9 @@ if (-x "/usr/bin/xcrun") { $UseXCRUN = 1; } +} elsif (`uname -a` =~ m/OpenBSD/) { + $DefaultCCompiler = 'cc'; + $DefaultCXXCompiler = 'c++'; } else { $DefaultCCompiler = 'gcc'; $DefaultCXXCompiler = 'g++'; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/unittests/Driver/ToolChainTest.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/unittests/Driver/ToolChainTest.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/unittests/Driver/ToolChainTest.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/unittests/Driver/ToolChainTest.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -16,6 +16,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/VirtualFileSystem.h" @@ -357,4 +358,10 @@ EXPECT_TRUE(CallbackHasCalled); } +TEST(GetDriverMode, PrefersLastDriverMode) { + static constexpr const char *Args[] = {"clang-cl", "--driver-mode=foo", + "--driver-mode=bar", "foo.cpp"}; + EXPECT_EQ(getDriverMode(Args[0], llvm::makeArrayRef(Args).slice(1)), "bar"); +} + } // end anonymous namespace. diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/unittests/Format/FormatTest.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/unittests/Format/FormatTest.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang/unittests/Format/FormatTest.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang/unittests/Format/FormatTest.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -8216,7 +8216,12 @@ "f(i)\n" "{\n" " return i + 1;\n" - "}", + "}\n" + "int\n" // Break here. + "f(i)\n" + "{\n" + " return i + 1;\n" + "};", Style); verifyFormat("int f(a, b, c);\n" // No break here. "int\n" // Break here. @@ -8225,9 +8230,55 @@ "float c;\n" "{\n" " return a + b < c;\n" + "}\n" + "int\n" // Break here. + "f(a, b, c)\n" // Break here. + "short a, b;\n" + "float c;\n" + "{\n" + " return a + b < c;\n" + "};", + Style); + verifyFormat("byte *\n" // Break here. + "f(a)\n" // Break here. + "byte a[];\n" + "{\n" + " return a;\n" + "}", + Style); + verifyFormat("bool f(int a, int) override;\n" + "Bar g(int a, Bar) final;\n" + "Bar h(a, Bar) final;", + Style); + verifyFormat("int\n" + "f(a)", + Style); + verifyFormat("bool\n" + "f(size_t = 0, bool b = false)\n" + "{\n" + " return !b;\n" "}", Style); + // The return breaking style doesn't affect: + // * function and object definitions with attribute-like macros + verifyFormat("Tttttttttttttttttttttttt ppppppppppppppp\n" + " ABSL_GUARDED_BY(mutex) = {};", + getGoogleStyleWithColumns(40)); + verifyFormat("Tttttttttttttttttttttttt ppppppppppppppp\n" + " ABSL_GUARDED_BY(mutex); // comment", + getGoogleStyleWithColumns(40)); + verifyFormat("Tttttttttttttttttttttttt ppppppppppppppp\n" + " ABSL_GUARDED_BY(mutex1)\n" + " ABSL_GUARDED_BY(mutex2);", + getGoogleStyleWithColumns(40)); + verifyFormat("Tttttt f(int a, int b)\n" + " ABSL_GUARDED_BY(mutex1)\n" + " ABSL_GUARDED_BY(mutex2);", + getGoogleStyleWithColumns(40)); + // * typedefs + verifyFormat("typedef ATTR(X) char x;", getGoogleStyle()); + Style = getGNUStyle(); // Test for comments at the end of function declarations. diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -56,7 +56,7 @@ "reverse_const_iterator", "ConstReverseIterator", "Const_Reverse_Iterator", - "const_reverse_iterator" + "const_reverse_iterator", "Constreverseiterator", "constreverseiterator"}); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/cmake/builtin-config-ix.cmake rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/cmake/builtin-config-ix.cmake --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/cmake/builtin-config-ix.cmake 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/cmake/builtin-config-ix.cmake 2021-11-16 16:47:26.000000000 +0000 @@ -10,7 +10,6 @@ builtin_check_c_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG) builtin_check_c_compiler_flag(-std=c11 COMPILER_RT_HAS_STD_C11_FLAG) builtin_check_c_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_VISIBILITY_HIDDEN_FLAG) -builtin_check_c_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG) builtin_check_c_compiler_flag(-ffreestanding COMPILER_RT_HAS_FREESTANDING_FLAG) builtin_check_c_compiler_flag(-fxray-instrument COMPILER_RT_HAS_XRAY_COMPILER_FLAG) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/cmake/config-ix.cmake rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/cmake/config-ix.cmake --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/cmake/config-ix.cmake 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/cmake/config-ix.cmake 2021-11-16 16:47:26.000000000 +0000 @@ -55,6 +55,7 @@ # CodeGen options. check_c_compiler_flag(-ffreestanding COMPILER_RT_HAS_FFREESTANDING_FLAG) +check_c_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG) check_c_compiler_flag(-std=c11 COMPILER_RT_HAS_STD_C11_FLAG) check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/builtins/clear_cache.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/builtins/clear_cache.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/builtins/clear_cache.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/builtins/clear_cache.c 2021-11-16 16:47:26.000000000 +0000 @@ -35,7 +35,7 @@ #include #endif -#if defined(__OpenBSD__) && (defined(__arm__) || defined(__mips__)) +#if defined(__OpenBSD__) && (defined(__arm__) || defined(__mips__) || defined(__riscv)) // clang-format off #include #include @@ -166,6 +166,13 @@ : "=r"(start_reg) : "r"(start_reg), "r"(end_reg), "r"(flags), "r"(syscall_nr)); assert(start_reg == 0 && "Cache flush syscall failed."); +#elif defined(__riscv) && defined(__OpenBSD__) + struct riscv_sync_icache_args arg; + + arg.addr = (uintptr_t)start; + arg.len = (uintptr_t)end - (uintptr_t)start; + + sysarch(RISCV_SYNC_ICACHE, &arg); #else #if __APPLE__ // On Darwin, sys_icache_invalidate() provides this functionality diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingFile.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingFile.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingFile.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingFile.c 2021-11-16 16:47:26.000000000 +0000 @@ -594,9 +594,15 @@ * whether or not the compiler defined this symbol. */ #if defined(_MSC_VER) COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR; -#pragma comment(linker, "/alternatename:" \ - INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" \ - INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR)) +#if defined(_M_IX86) || defined(__i386__) +#define WIN_SYM_PREFIX "_" +#else +#define WIN_SYM_PREFIX +#endif +#pragma comment( \ + linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \ + INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \ + INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR)) #else COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR __attribute__((weak, alias(INSTR_PROF_QUOTE( @@ -651,8 +657,9 @@ const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); - const uint64_t CountersOffset = - sizeof(__llvm_profile_header) + (DataSize * sizeof(__llvm_profile_data)); + const uint64_t CountersOffset = sizeof(__llvm_profile_header) + + __llvm_write_binary_ids(NULL) + + (DataSize * sizeof(__llvm_profile_data)); int Length = getCurFilenameLength(); char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c 2021-11-16 16:47:26.000000000 +0000 @@ -119,8 +119,9 @@ const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); - const uint64_t CountersOffset = - sizeof(__llvm_profile_header) + (DataSize * sizeof(__llvm_profile_data)); + const uint64_t CountersOffset = sizeof(__llvm_profile_header) + + __llvm_write_binary_ids(NULL) + + (DataSize * sizeof(__llvm_profile_data)); uint64_t CountersSize = CountersEnd - CountersBegin; /* Don't publish a VMO if there are no counters. */ diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c 2021-11-16 16:47:26.000000000 +0000 @@ -85,6 +85,7 @@ COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP; +#ifdef NT_GNU_BUILD_ID static size_t RoundUp(size_t size, size_t align) { return (size + align - 1) & ~(align - 1); } @@ -93,8 +94,8 @@ * Write binary id length and then its data, because binary id does not * have a fixed length. */ -int WriteOneBinaryId(ProfDataWriter *Writer, uint64_t BinaryIdLen, - const uint8_t *BinaryIdData) { +static int WriteOneBinaryId(ProfDataWriter *Writer, uint64_t BinaryIdLen, + const uint8_t *BinaryIdData) { ProfDataIOVec BinaryIdIOVec[] = { {&BinaryIdLen, sizeof(uint64_t), 1, 0}, {BinaryIdData, sizeof(uint8_t), BinaryIdLen, 0}}; @@ -118,7 +119,8 @@ * Note sections like .note.ABI-tag and .note.gnu.build-id are aligned * to 4 bytes, so round n_namesz and n_descsz to the nearest 4 bytes. */ -int WriteBinaryIdForNote(ProfDataWriter *Writer, const ElfW(Nhdr) * Note) { +static int WriteBinaryIdForNote(ProfDataWriter *Writer, + const ElfW(Nhdr) * Note) { int BinaryIdSize = 0; const char *NoteName = (const char *)Note + sizeof(ElfW(Nhdr)); @@ -143,8 +145,8 @@ * If writer is given, write binary ids into profiles. * If an error happens while writing, return -1. */ -int WriteBinaryIds(ProfDataWriter *Writer, const ElfW(Nhdr) * Note, - const ElfW(Nhdr) * NotesEnd) { +static int WriteBinaryIds(ProfDataWriter *Writer, const ElfW(Nhdr) * Note, + const ElfW(Nhdr) * NotesEnd) { int TotalBinaryIdsSize = 0; while (Note < NotesEnd) { int Result = WriteBinaryIdForNote(Writer, Note); @@ -188,5 +190,14 @@ return 0; } +#else /* !NT_GNU_BUILD_ID */ +/* + * Fallback implementation for targets that don't support the GNU + * extensions NT_GNU_BUILD_ID and __ehdr_start. + */ +COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) { + return 0; +} +#endif #endif diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/scudo/standalone/CMakeLists.txt rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/scudo/standalone/CMakeLists.txt --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/scudo/standalone/CMakeLists.txt 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/scudo/standalone/CMakeLists.txt 2021-11-16 16:47:26.000000000 +0000 @@ -124,8 +124,11 @@ RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler RTGwpAsanOptionsParser) - list(APPEND SCUDO_CFLAGS -DGWP_ASAN_HOOKS -fno-omit-frame-pointer - -mno-omit-leaf-frame-pointer) + append_list_if(COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG -fno-omit-frame-pointer + -mno-omit-leaf-frame-pointer + SCUDO_CFLAGS) + list(APPEND SCUDO_CFLAGS -DGWP_ASAN_HOOKS) + endif() set(SCUDO_LINK_LIBS) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt 2021-11-16 16:47:26.000000000 +0000 @@ -39,7 +39,10 @@ endforeach() list(APPEND LINK_FLAGS -pthread) # Linking against libatomic is required with some compilers -list(APPEND LINK_FLAGS -latomic) +check_library_exists(atomic __atomic_load_8 "" COMPILER_RT_HAS_LIBATOMIC) +if (COMPILER_RT_HAS_LIBATOMIC) + list(APPEND LINK_FLAGS -latomic) +endif() set(SCUDO_TEST_HEADERS scudo_unit_test.h diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/libunwind/src/Unwind-EHABI.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/libunwind/src/Unwind-EHABI.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/libunwind/src/Unwind-EHABI.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/libunwind/src/Unwind-EHABI.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -97,9 +97,11 @@ case Descriptor::LU32: descriptor = getNextWord(descriptor, &length); descriptor = getNextWord(descriptor, &offset); + break; case Descriptor::LU16: descriptor = getNextNibble(descriptor, &length); descriptor = getNextNibble(descriptor, &offset); + break; default: assert(false); return _URC_FAILURE; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/docs/ReleaseNotes.rst rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/docs/ReleaseNotes.rst --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/docs/ReleaseNotes.rst 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/docs/ReleaseNotes.rst 2021-11-16 16:47:26.000000000 +0000 @@ -24,6 +24,13 @@ ELF Improvements ---------------- +* ``-z start-stop-gc`` is now supported and becomes the default. + (`D96914 `_) + (`rG6d2d3bd0 `_) +* ``--shuffle-sections=`` has been changed to ``--shuffle-sections==``. + If seed is -1, the matched input sections are reversed. + (`D98445 `_) + (`D98679 `_) * ``-Bsymbolic -Bsymbolic-functions`` has been changed to behave the same as ``-Bsymbolic-functions``. This matches GNU ld. (`D102461 `_) * ``-Bno-symbolic`` has been added. @@ -32,6 +39,75 @@ (`D103303 `_) * ``-Bsymbolic-non-weak-functions`` has been added as a ``STB_GLOBAL`` subset of ``-Bsymbolic-functions``. (`D102570 `_) +* ``--no-allow-shlib-undefined`` has been improved to catch more cases. + (`D101996 `_) +* ``__rela_iplt_start`` is no longer defined for -pie/-shared. + This makes GCC/Clang ``-static-pie`` built executables work. + (`rG8cb78e99 `_) +* IRELATIVE/TLSDESC relocations now support ``-z rel``. + (`D100544 `_) +* Section groups with a zero flag are now supported. + This is used by ``comdat nodeduplicate`` in LLVM IR. + (`D96636 `_) + (`D106228 `_) +* Defined symbols are now resolved before undefined symbols to stabilize the bheavior of archive member extraction. + (`D95985 `_) +* ``STB_WEAK`` symbols are now preferred over COMMON symbols as a fix to a ``--fortran-common`` regression. + (`D105945 `_) +* Absolute relocations referencing undef weak now produce dynamic relocations for -pie, matching GOT-generating relocations. + (`D105164 `_) +* Exported symbols are now communicated to the LTO library so as to make LTO + based whole program devirtualization (``-flto=thin -fwhole-program-vtables``) + work with shared objects. + (`D91583 `_) +* Whole program devirtualization now respects ``local:`` version nodes in a version script. + (`D98220 `_) + (`D98686 `_) +* ``local:`` version nodes in a version script now apply to non-default version symbols. + (`D107234 `_) +* If an object file defines both ``foo`` and ``foo@v1``, now only ``foo@v1`` will be in the output. + (`D107235 `_) +* Copy relocations on non-default version symbols are now supported. + (`D107535 `_) + +Linker script changes: + +* ``.``, ``$``, and double quotes can now be used in symbol names in expressions. + (`D98306 `_) + (`rGe7a7ad13 `_) +* Fixed value of ``.`` in the output section description of ``.tbss``. + (`D107288 `_) +* ``NOLOAD`` sections can now be placed in a ``PT_LOAD`` program header. + (`D103815 `_) +* ``OUTPUT_FORMAT(default, big, little)`` now consults ``-EL`` and ``-EB``. + (`D96214 `_) +* The ``OVERWRITE_SECTIONS`` command has been added. + (`D103303 `_) +* The section order within an ``INSERT AFTER`` command is now preserved. + (`D105158 `_) + +Architecture specific changes: + +* aarch64_be is now supported. + (`D96188 `_) +* The AMDGPU port now supports ``--amdhsa-code-object-version=4`` object files; + (`D95811 `_) +* The ARM port now accounts for PC biases in range extension thunk creation. + (`D97550 `_) +* The AVR port now computes ``e_flags``. + (`D99754 `_) +* The Mips port now omits unneeded dynamic relocations for PIE non-preemptible TLS. + (`D101382 `_) +* The PowerPC port now supports ``--power10-stubs=no`` to omit Power10 instructions from call stubs. + (`D94625 `_) +* Fixed a thunk creation bug in the PowerPC port when TOC/NOTOC calls are mixed. + (`D101837 `_) +* The RISC-V port now resolves undefined weak relocations to the current location if not using PLT. + (`D103001 `_) +* ``R_386_GOTOFF`` relocations from .debug_info are now allowed to be compatible with GCC. + (`D95994 `_) +* ``gotEntrySize`` has been added to improve support for the ILP32 ABI of x86-64. + (`D102569 `_) Breaking changes ---------------- @@ -42,17 +118,75 @@ COFF Improvements ----------------- -* ... +* Avoid thread exhaustion when running on 32 bit Windows. + (`D105506 `_) + +* Improve terminating the process on Windows while a thread pool might be + running. (`D102944 `_) MinGW Improvements ------------------ -* ... - -MachO Improvements ------------------- +* Support for linking directly against a DLL without using an import library + has been added. (`D104530 `_ and + `D104531 `_) + +* Fix linking with ``--export-all-symbols`` in combination with + ``-function-sections``. (`D101522 `_ and + `D101615 `_) + +* Fix automatic export of symbols from LTO objects. + (`D101569 `_) + +* Accept more spellings of some options. + (`D107237 `_ and + `D107253 `_) + +Mach-O Improvements +------------------- + +The Mach-O backend is now able to link several large, real-world programs, +though we are still working out the kinks. + +* arm64 is now supported as a target. (`D88629 `_) +* arm64_32 is now supported as a target. (`D99822 `_) +* Branch-range-extension thunks are now supported. (`D100818 `_) +* ``-dead_strip`` is now supported. (`D103324 `_) +* Support for identical code folding (``--icf=all``) has been added. + (`D103292 `_) +* Support for special ``$start`` and ``$end`` symbols for segment & sections has been + added. (`D106767 `_, `D106629 `_) +* ``$ld$previous`` symbols are now supported. (`D103505 `_) +* ``$ld$install_name`` symbols are now supported. (`D103746 `_) +* ``__mh_*_header`` symbols are now supported. (`D97007 `_) +* LC_CODE_SIGNATURE is now supported. (`D96164 `_) +* LC_FUNCTION_STARTS is now supported. (`D97260 `_) +* LC_DATA_IN_CODE is now supported. (`D103006 `_) +* Bind opcodes are more compactly encoded. (`D106128 `_, + `D105075 `_) +* LTO cache support has been added. (`D105922 `_) +* ``-application_extension`` is now supported. (`D105818 `_) +* ``-export_dynamic`` is now partially supported. (`D105482 `_) +* ``-arch_multiple`` is now supported. (`D105450 `_) +* ``-final_output`` is now supported. (`D105449 `_) +* ``-umbrella`` is now supported. (`D105448 `_) +* ``--print-dylib-search`` is now supported. (`D103985 `_) +* ``-force_load_swift_libs`` is now supported. (`D103709 `_) +* ``-reexport_framework``, ``-reexport_library``, ``-reexport-l`` are now supported. + (`D103497 `_) +* ``.weak_def_can_be_hidden`` is now supported. (`D101080 `_) +* ``-add_ast_path`` is now supported. (`D100076 `_) +* ``-segprot`` is now supported. (`D99389 `_) +* ``-dependency_info`` is now partially supported. (`D98559 `_) +* ``--time-trace`` is now supported. (`D98419 `_) +* ``-mark_dead_strippable_dylib`` is now supported. (`D98262 `_) +* ``-[un]exported_symbol[s_list]`` is now supported. (`D98223 `_) +* ``-flat_namespace`` is now supported. (`D97641 `_) +* ``-rename_section`` and ``-rename_segment`` are now supported. (`D97600 `_) +* ``-bundle_loader`` is now supported. (`D95913 `_) +* ``-map`` is now partially supported. (`D98323 `_) -* Item 1. +There were numerous other bug-fixes as well. WebAssembly Improvements ------------------------ diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/ELF/InputSection.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/ELF/InputSection.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/ELF/InputSection.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/ELF/InputSection.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -88,7 +88,22 @@ if (!zlib::isAvailable()) error(toString(file) + ": contains a compressed section, " + "but zlib is not available"); - parseCompressedHeader(); + switch (config->ekind) { + case ELF32LEKind: + parseCompressedHeader(); + break; + case ELF32BEKind: + parseCompressedHeader(); + break; + case ELF64LEKind: + parseCompressedHeader(); + break; + case ELF64BEKind: + parseCompressedHeader(); + break; + default: + llvm_unreachable("unknown ELFT"); + } } } @@ -210,10 +225,7 @@ // When a section is compressed, `rawData` consists with a header followed // by zlib-compressed data. This function parses a header to initialize // `uncompressedSize` member and remove the header from `rawData`. -void InputSectionBase::parseCompressedHeader() { - using Chdr64 = typename ELF64LE::Chdr; - using Chdr32 = typename ELF32LE::Chdr; - +template void InputSectionBase::parseCompressedHeader() { // Old-style header if (name.startswith(".zdebug")) { if (!toStringRef(rawData).startswith("ZLIB")) { @@ -239,32 +251,13 @@ assert(flags & SHF_COMPRESSED); flags &= ~(uint64_t)SHF_COMPRESSED; - // New-style 64-bit header - if (config->is64) { - if (rawData.size() < sizeof(Chdr64)) { - error(toString(this) + ": corrupted compressed section"); - return; - } - - auto *hdr = reinterpret_cast(rawData.data()); - if (hdr->ch_type != ELFCOMPRESS_ZLIB) { - error(toString(this) + ": unsupported compression type"); - return; - } - - uncompressedSize = hdr->ch_size; - alignment = std::max(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); - return; - } - - // New-style 32-bit header - if (rawData.size() < sizeof(Chdr32)) { + // New-style header + if (rawData.size() < sizeof(typename ELFT::Chdr)) { error(toString(this) + ": corrupted compressed section"); return; } - auto *hdr = reinterpret_cast(rawData.data()); + auto *hdr = reinterpret_cast(rawData.data()); if (hdr->ch_type != ELFCOMPRESS_ZLIB) { error(toString(this) + ": unsupported compression type"); return; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/ELF/InputSection.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/ELF/InputSection.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/ELF/InputSection.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/ELF/InputSection.h 2021-11-16 16:47:26.000000000 +0000 @@ -238,6 +238,7 @@ } protected: + template void parseCompressedHeader(); void uncompress() const; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/MinGW/Driver.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/MinGW/Driver.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/MinGW/Driver.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/MinGW/Driver.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -308,13 +308,19 @@ add("-kill-at"); if (args.hasArg(OPT_appcontainer)) add("-appcontainer"); - if (args.hasArg(OPT_no_seh)) + if (args.hasFlag(OPT_no_seh, OPT_disable_no_seh, false)) add("-noseh"); if (args.getLastArgValue(OPT_m) != "thumb2pe" && args.getLastArgValue(OPT_m) != "arm64pe" && - args.hasArg(OPT_no_dynamicbase)) + args.hasFlag(OPT_disable_dynamicbase, OPT_dynamicbase, false)) add("-dynamicbase:no"); + if (args.hasFlag(OPT_disable_high_entropy_va, OPT_high_entropy_va, false)) + add("-highentropyva:no"); + if (args.hasFlag(OPT_disable_nxcompat, OPT_nxcompat, false)) + add("-nxcompat:no"); + if (args.hasFlag(OPT_disable_tsaware, OPT_tsaware, false)) + add("-tsaware:no"); if (args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false)) add("-timestamp:0"); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/MinGW/Options.td rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/MinGW/Options.td --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/MinGW/Options.td 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/MinGW/Options.td 2021-11-16 16:47:26.000000000 +0000 @@ -26,6 +26,11 @@ def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText; } +multiclass B_disable { + def NAME: Flag<["--", "-"], name>, HelpText; + def disable_ # NAME: Flag<["--", "-"], "disable-" # name>, HelpText; +} + def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, HelpText<"Add a directory to the library search path">; defm allow_multiple_definition: B<"allow-multiple-definition", @@ -42,7 +47,7 @@ HelpText<"Don't do automatic imports that require runtime fixups">; def disable_stdcall_fixup: F<"disable-stdcall-fixup">, HelpText<"Don't resolve stdcall/fastcall/vectorcall to undecorated symbols">; -defm dynamicbase: B<"dynamicbase", "Enable ASLR", "Disable ASLR">; +defm dynamicbase: B_disable<"dynamicbase", "Enable ASLR", "Disable ASLR">; def enable_auto_import: F<"enable-auto-import">, HelpText<"Automatically import data symbols from other DLLs where needed">; def enable_runtime_pseudo_reloc: F<"enable-runtime-pseudo-reloc">, @@ -62,6 +67,8 @@ "Remove unused sections", "Don't remove unused sections">; def help: F<"help">, HelpText<"Print option help">; +defm high_entropy_va: B_disable<"high-entropy-va", + "Set the 'high entropy VA' flag", "Don't set the 'high entropy VA' flag">; defm icf: Eq<"icf", "Identical code folding">; defm image_base: Eq<"image-base", "Base address of the program">; defm insert_timestamp: B<"insert-timestamp", @@ -80,7 +87,10 @@ "Set the OS and subsystem minor version">; defm minor_subsystem_version: EqLong<"minor-subsystem-version", "Set the OS and subsystem minor version">; -def no_seh: F<"no-seh">, HelpText<"Set the 'no SEH' flag in the executable">; +defm no_seh: B_disable<"no-seh", + "Set the 'no SEH' flag in the executable", "Don't set the 'no SEH' flag">; +defm nxcompat: B_disable<"nxcompat", + "Set the 'nxcompat' flag in the executable", "Don't set the 'nxcompat' flag">; def large_address_aware: Flag<["--"], "large-address-aware">, HelpText<"Enable large addresses">; def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"">, @@ -99,6 +109,8 @@ "Write a tar file containing input files and command line options to reproduce link">; defm require_defined: Eq<"require-defined", "Force symbol to be added to symbol table as an undefined one">; +defm tsaware: B_disable<"tsaware", + "Set the 'Terminal Server aware' flag", "Don't set the 'Terminal Server aware' flag">; defm undefined: Eq<"undefined", "Include symbol in the link, if available">; defm whole_archive: B<"whole-archive", "Include all object files for following archives", @@ -127,6 +139,7 @@ def alias_Bstatic_non_shared: Flag<["-"], "non_shared">, Alias; def alias_Bstatic_static: Flag<["-"], "static">, Alias; def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias; +def alias_no_dynamicbase: F<"no-dynamicbase">, Alias; def alias_strip_s: Flag<["-"], "s">, Alias; def alias_strip_S: Flag<["-"], "S">, Alias; def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias; @@ -138,14 +151,11 @@ def: F<"enable-auto-image-base">; def: F<"end-group">; def: Flag<["--"], "full-shutdown">; -def: F<"high-entropy-va">; defm: EqNoHelp<"major-image-version">; defm: EqNoHelp<"minor-image-version">; def: F<"no-undefined">; -def: F<"nxcompat">; def: F<"pic-executable">; defm: EqNoHelp<"plugin">; defm: EqNoHelp<"plugin-opt">; defm: EqNoHelp<"sysroot">; def: F<"start-group">; -def: F<"tsaware">; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/test/ELF/compressed-debug-input-err.s rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/test/ELF/compressed-debug-input-err.s --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/test/ELF/compressed-debug-input-err.s 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/test/ELF/compressed-debug-input-err.s 2021-11-16 16:47:26.000000000 +0000 @@ -1,8 +1,11 @@ -# REQUIRES: zlib, x86 +# REQUIRES: zlib, ppc, x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-unknown %s -o %t-be.o +# RUN: not ld.lld %t-be.o -o /dev/null -shared 2>&1 | FileCheck %s + ## Check we are able to report zlib uncompress errors. # CHECK: error: {{.*}}.o:(.debug_str): uncompress failed: zlib error: Z_DATA_ERROR diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/test/ELF/compressed-debug-input.s rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/test/ELF/compressed-debug-input.s --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/test/ELF/compressed-debug-input.s 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/test/ELF/compressed-debug-input.s 2021-11-16 16:47:26.000000000 +0000 @@ -1,7 +1,9 @@ -# REQUIRES: zlib, x86 +# REQUIRES: zlib, ppc, x86 # RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=powerpc64-unknown-unknown %s -o %t-be # RUN: llvm-readobj --sections %t | FileCheck -check-prefix=ZLIB %s +# RUN: llvm-readobj --sections %t-be | FileCheck -check-prefix=ZLIB %s # ZLIB: Section { # ZLIB: Index: 2 # ZLIB: Name: .debug_str @@ -21,7 +23,9 @@ # ZLIB-NEXT: } # RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t2 +# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=powerpc64-unknown-unknown %s -o %t2-be # RUN: llvm-readobj --sections %t2 | FileCheck -check-prefix=GNU %s +# RUN: llvm-readobj --sections %t2-be | FileCheck -check-prefix=GNU %s # GNU: Section { # GNU: Index: 2 # GNU: Name: .zdebug_str @@ -41,9 +45,13 @@ # RUN: ld.lld --hash-style=sysv %t -o %t.so -shared # RUN: llvm-readobj --sections --section-data %t.so | FileCheck -check-prefix=DATA %s +# RUN: ld.lld --hash-style=sysv %t-be -o %t-be.so -shared +# RUN: llvm-readobj --sections --section-data %t-be.so | FileCheck -check-prefix=DATA %s # RUN: ld.lld --hash-style=sysv %t2 -o %t2.so -shared # RUN: llvm-readobj --sections --section-data %t2.so | FileCheck -check-prefix=DATA %s +# RUN: ld.lld --hash-style=sysv %t2-be -o %t2-be.so -shared +# RUN: llvm-readobj --sections --section-data %t2-be.so | FileCheck -check-prefix=DATA %s # DATA: Section { # DATA: Index: 6 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/test/MinGW/driver.test rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/test/MinGW/driver.test --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lld/test/MinGW/driver.test 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lld/test/MinGW/driver.test 2021-11-16 16:47:26.000000000 +0000 @@ -146,9 +146,10 @@ RUN: ld.lld -### -m i386pep foo.o --large-address-aware 2>&1 | FileCheck -check-prefix LARGE-ADDRESS-AWARE %s LARGE-ADDRESS-AWARE: -largeaddressaware -RUN: ld.lld -### -m i386pe foo.o --no-dynamicbase 2>&1 | FileCheck -check-prefix DISABLE-DYNAMICBASE %s +RUN: ld.lld -### -m i386pe foo.o --dynamicbase --no-dynamicbase 2>&1 | FileCheck -check-prefix DISABLE-DYNAMICBASE %s +RUN: ld.lld -### -m i386pe foo.o --dynamicbase --disable-dynamicbase 2>&1 | FileCheck -check-prefix DISABLE-DYNAMICBASE %s DISABLE-DYNAMICBASE: -dynamicbase:no -RUN: ld.lld -### -m i386pe --dynamicbase foo.o 2>&1 | FileCheck -check-prefix NO-DISABLE-DYNAMICBASE %s +RUN: ld.lld -### -m i386pe --disable-dynamicbase --dynamicbase foo.o 2>&1 | FileCheck -check-prefix NO-DISABLE-DYNAMICBASE %s RUN: ld.lld -### -m i386pep -dynamicbase foo.o 2>&1 | FileCheck -check-prefix NO-DISABLE-DYNAMICBASE %s RUN: ld.lld -### -m i386pe foo.o 2>&1 | FileCheck -check-prefix NO-DISABLE-DYNAMICBASE %s RUN: ld.lld -### -m i386pep foo.o 2>&1 | FileCheck -check-prefix NO-DISABLE-DYNAMICBASE %s @@ -159,6 +160,27 @@ RUN: ld.lld -### -m arm64pe foo.o --no-dynamicbase 2>&1 | FileCheck -check-prefix NO-DISABLE-DYNAMICBASE %s NO-DISABLE-DYNAMICBASE-NOT: -dynamicbase:no +RUN: ld.lld -### -m i386pe foo.o -high-entropy-va -disable-high-entropy-va 2>&1 | FileCheck -check-prefix DISABLE-HIGH-ENTROPY-VA %s +RUN: ld.lld -### -m i386pe foo.o --high-entropy-va --disable-high-entropy-va 2>&1 | FileCheck -check-prefix DISABLE-HIGH-ENTROPY-VA %s +DISABLE-HIGH-ENTROPY-VA: -highentropyva:no +RUN: ld.lld -### -m i386pe foo.o -disable-high-entropy-va -high-entropy-va 2>&1 | FileCheck -check-prefix NO-DISABLE-HIGH-ENTROPY-VA %s +RUN: ld.lld -### -m i386pe foo.o --disable-high-entropy-va --high-entropy-va 2>&1 | FileCheck -check-prefix NO-DISABLE-HIGH-ENTROPY-VA %s +NO-DISABLE-HIGH-ENTROPY-VA-NOT: -highentropyva:no + +RUN: ld.lld -### -m i386pe foo.o -nxcompat -disable-nxcompat 2>&1 | FileCheck -check-prefix DISABLE-NXCOMPAT %s +RUN: ld.lld -### -m i386pe foo.o --nxcompat --disable-nxcompat 2>&1 | FileCheck -check-prefix DISABLE-NXCOMPAT %s +DISABLE-NXCOMPAT: -nxcompat:no +RUN: ld.lld -### -m i386pe foo.o -disable-nxcompat -nxcompat 2>&1 | FileCheck -check-prefix NO-DISABLE-NXCOMPAT %s +RUN: ld.lld -### -m i386pe foo.o --disable-nxcompat --nxcompat 2>&1 | FileCheck -check-prefix NO-DISABLE-NXCOMPAT %s +NO-DISABLE-NXCOMPAT-NOT: -nxcompat:no + +RUN: ld.lld -### -m i386pe foo.o -tsaware -disable-tsaware 2>&1 | FileCheck -check-prefix DISABLE-TSAWARE %s +RUN: ld.lld -### -m i386pe foo.o --tsaware --disable-tsaware 2>&1 | FileCheck -check-prefix DISABLE-TSAWARE %s +DISABLE-TSAWARE: -tsaware:no +RUN: ld.lld -### -m i386pe foo.o -disable-tsaware -tsaware 2>&1 | FileCheck -check-prefix NO-DISABLE-TSAWARE %s +RUN: ld.lld -### -m i386pe foo.o --disable-tsaware --tsaware 2>&1 | FileCheck -check-prefix NO-DISABLE-TSAWARE %s +NO-DISABLE-TSAWARE-NOT: -tsaware:no + RUN: ld.lld -### -m i386pep foo.o --image-base 0x1230000 2>&1 | FileCheck -check-prefix IMAGE-BASE %s RUN: ld.lld -### -m i386pep foo.o -image-base 0x1230000 2>&1 | FileCheck -check-prefix IMAGE-BASE %s RUN: ld.lld -### -m i386pep foo.o --image-base=0x1230000 2>&1 | FileCheck -check-prefix IMAGE-BASE %s @@ -273,9 +295,12 @@ RUN: ld.lld -### -m i386pep foo.o -section-alignment=0x2000 2>&1 | FileCheck -check-prefix ALIGN %s ALIGN: -align:0x2000 -RUN: ld.lld -### -m i386pe foo.o -no-seh 2>&1 | FileCheck -check-prefix NOSEH %s -RUN: ld.lld -### -m i386pe foo.o --no-seh 2>&1 | FileCheck -check-prefix NOSEH %s +RUN: ld.lld -### -m i386pe foo.o -disable-no-seh -no-seh 2>&1 | FileCheck -check-prefix NOSEH %s +RUN: ld.lld -### -m i386pe foo.o --disable-no-seh --no-seh 2>&1 | FileCheck -check-prefix NOSEH %s +RUN: ld.lld -### -m i386pe foo.o -no-seh -disable-no-seh 2>&1 | FileCheck -check-prefix DISABLE-NOSEH %s +RUN: ld.lld -### -m i386pe foo.o --no-seh --disable-no-seh 2>&1 | FileCheck -check-prefix DISABLE-NOSEH %s NOSEH: -noseh +DISABLE-NOSEH-NOT: -noseh RUN: ld.lld -### -m i386pep foo.o --no-allow-multiple-definition --allow-multiple-definition 2>&1 | FileCheck -check-prefix ALLOW_MULTIPLE_DEFINITION %s RUN: ld.lld -### -m i386pep foo.o -no-allow-multiple-definition -allow-multiple-definition 2>&1 | FileCheck -check-prefix ALLOW_MULTIPLE_DEFINITION %s diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -46,8 +46,6 @@ #define HWCAP_PACA (1 << 30) #define HWCAP2_MTE (1 << 18) -#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) - using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_linux; @@ -452,45 +450,80 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues( lldb::DataBufferSP &data_sp) { - Status error; + // AArch64 register data must contain GPRs, either FPR or SVE registers + // and optional MTE register. Pointer Authentication (PAC) registers are + // read-only and will be skiped. - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + // In order to create register data checkpoint we first read all register + // values if not done already and calculate total size of register set data. + // We store all register values in data_sp by copying full PTrace data that + // corresponds to register sets enabled by current register context. + Status error; + uint32_t reg_data_byte_size = GetGPRBufferSize(); error = ReadGPR(); if (error.Fail()) return error; - error = ReadFPR(); + // If SVE is enabled we need not copy FPR separately. + if (GetRegisterInfo().IsSVEEnabled()) { + reg_data_byte_size += GetSVEBufferSize(); + error = ReadAllSVE(); + } else { + reg_data_byte_size += GetFPRSize(); + error = ReadFPR(); + } if (error.Fail()) return error; + if (GetRegisterInfo().IsMTEEnabled()) { + reg_data_byte_size += GetMTEControlSize(); + error = ReadMTEControl(); + if (error.Fail()) + return error; + } + + data_sp.reset(new DataBufferHeap(reg_data_byte_size, 0)); uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, GetGPRBuffer(), GetGPRSize()); - dst += GetGPRSize(); - ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); + + ::memcpy(dst, GetGPRBuffer(), GetGPRBufferSize()); + dst += GetGPRBufferSize(); + + if (GetRegisterInfo().IsSVEEnabled()) { + ::memcpy(dst, GetSVEBuffer(), GetSVEBufferSize()); + dst += GetSVEBufferSize(); + } else { + ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); + dst += GetFPRSize(); + } + + if (GetRegisterInfo().IsMTEEnabled()) + ::memcpy(dst, GetMTEControl(), GetMTEControlSize()); return error; } Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues( const lldb::DataBufferSP &data_sp) { - Status error; + // AArch64 register data must contain GPRs, either FPR or SVE registers + // and optional MTE register. Pointer Authentication (PAC) registers are + // read-only and will be skiped. + + // We store all register values in data_sp by copying full PTrace data that + // corresponds to register sets enabled by current register context. In order + // to restore from register data checkpoint we will first restore GPRs, based + // on size of remaining register data either SVE or FPRs should be restored + // next. SVE is not enabled if we have register data size less than or equal + // to size of GPR + FPR + MTE. + Status error; if (!data_sp) { error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", + "NativeRegisterContextLinux_arm64::%s invalid data_sp provided", __FUNCTION__); return error; } - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - uint8_t *src = data_sp->GetBytes(); if (src == nullptr) { error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " @@ -499,19 +532,79 @@ __FUNCTION__); return error; } - ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize()); + + uint64_t reg_data_min_size = GetGPRBufferSize() + GetFPRSize(); + if (data_sp->GetByteSize() < reg_data_min_size) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_arm64::%s data_sp contained insufficient " + "register data bytes, expected at least %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, reg_data_min_size, data_sp->GetByteSize()); + return error; + } + + // Register data starts with GPRs + ::memcpy(GetGPRBuffer(), src, GetGPRBufferSize()); + m_gpr_is_valid = true; error = WriteGPR(); if (error.Fail()) return error; - src += GetRegisterInfoInterface().GetGPRSize(); - ::memcpy(GetFPRBuffer(), src, GetFPRSize()); + src += GetGPRBufferSize(); + + // Verify if register data may contain SVE register values. + bool contains_sve_reg_data = + (data_sp->GetByteSize() > (reg_data_min_size + GetSVEHeaderSize())); + + if (contains_sve_reg_data) { + // We have SVE register data first write SVE header. + ::memcpy(GetSVEHeader(), src, GetSVEHeaderSize()); + if (!sve_vl_valid(m_sve_header.vl)) { + m_sve_header_is_valid = false; + error.SetErrorStringWithFormat("NativeRegisterContextLinux_arm64::%s " + "Invalid SVE header in data_sp", + __FUNCTION__); + return error; + } + m_sve_header_is_valid = true; + error = WriteSVEHeader(); + if (error.Fail()) + return error; + + // SVE header has been written configure SVE vector length if needed. + ConfigureRegisterContext(); + + // Make sure data_sp contains sufficient data to write all SVE registers. + reg_data_min_size = GetGPRBufferSize() + GetSVEBufferSize(); + if (data_sp->GetByteSize() < reg_data_min_size) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_arm64::%s data_sp contained insufficient " + "register data bytes, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, reg_data_min_size, data_sp->GetByteSize()); + return error; + } + + ::memcpy(GetSVEBuffer(), src, GetSVEBufferSize()); + m_sve_buffer_is_valid = true; + error = WriteAllSVE(); + src += GetSVEBufferSize(); + } else { + ::memcpy(GetFPRBuffer(), src, GetFPRSize()); + m_fpu_is_valid = true; + error = WriteFPR(); + src += GetFPRSize(); + } - error = WriteFPR(); if (error.Fail()) return error; + if (GetRegisterInfo().IsMTEEnabled() && + data_sp->GetByteSize() > reg_data_min_size) { + ::memcpy(GetMTEControl(), src, GetMTEControlSize()); + m_mte_ctrl_is_valid = true; + error = WriteMTEControl(); + } + return error; } @@ -864,13 +957,6 @@ return sve_reg_offset; } -void *NativeRegisterContextLinux_arm64::GetSVEBuffer() { - if (m_sve_state == SVEState::FPSIMD) - return m_sve_ptrace_payload.data() + sve::ptrace_fpsimd_offset; - - return m_sve_ptrace_payload.data(); -} - std::vector NativeRegisterContextLinux_arm64::GetExpeditedRegisters( ExpeditedRegs expType) const { std::vector expedited_reg_nums = diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h 2021-11-16 16:47:26.000000000 +0000 @@ -139,7 +139,7 @@ void *GetMTEControl() { return &m_mte_ctrl_reg; } - void *GetSVEBuffer(); + void *GetSVEBuffer() { return m_sve_ptrace_payload.data(); }; size_t GetSVEHeaderSize() { return sizeof(m_sve_header); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h 2021-11-16 16:47:26.000000000 +0000 @@ -110,6 +110,7 @@ bool IsSVEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskSVE); } bool IsPAuthEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskPAuth); } + bool IsMTEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskMTE); } bool IsSVEReg(unsigned reg) const; bool IsSVEZReg(unsigned reg) const; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/source/Symbol/TypeSystem.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/source/Symbol/TypeSystem.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/source/Symbol/TypeSystem.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/source/Symbol/TypeSystem.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -223,62 +223,32 @@ llvm::Expected TypeSystemMap::GetTypeSystemForLanguage( lldb::LanguageType language, llvm::Optional create_callback) { - llvm::Error error = llvm::Error::success(); - assert(!error); // Check the success value when assertions are enabled std::lock_guard guard(m_mutex); - if (m_clear_in_progress) { - error = llvm::make_error( + if (m_clear_in_progress) + return llvm::make_error( "Unable to get TypeSystem because TypeSystemMap is being cleared", llvm::inconvertibleErrorCode()); - } else { - collection::iterator pos = m_map.find(language); - if (pos != m_map.end()) { - auto *type_system = pos->second.get(); - if (type_system) { - llvm::consumeError(std::move(error)); - return *type_system; - } - error = llvm::make_error( - "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); - return std::move(error); - } - for (const auto &pair : m_map) { - if (pair.second && pair.second->SupportsLanguage(language)) { - // Add a new mapping for "language" to point to an already existing - // TypeSystem that supports this language - m_map[language] = pair.second; - if (pair.second.get()) { - llvm::consumeError(std::move(error)); - return *pair.second.get(); - } - error = llvm::make_error( - "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); - return std::move(error); - } - } + collection::iterator pos = m_map.find(language); + if (pos != m_map.end()) { + auto *type_system = pos->second.get(); + if (type_system) + return *type_system; + return llvm::make_error( + "TypeSystem for language " + + llvm::StringRef(Language::GetNameForLanguageType(language)) + + " doesn't exist", + llvm::inconvertibleErrorCode()); + } - if (!create_callback) { - error = llvm::make_error( - "Unable to find type system for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)), - llvm::inconvertibleErrorCode()); - } else { - // Cache even if we get a shared pointer that contains a null type system - // back - TypeSystemSP type_system_sp = (*create_callback)(); - m_map[language] = type_system_sp; - if (type_system_sp.get()) { - llvm::consumeError(std::move(error)); - return *type_system_sp.get(); - } - error = llvm::make_error( + for (const auto &pair : m_map) { + if (pair.second && pair.second->SupportsLanguage(language)) { + // Add a new mapping for "language" to point to an already existing + // TypeSystem that supports this language + m_map[language] = pair.second; + if (pair.second.get()) + return *pair.second.get(); + return llvm::make_error( "TypeSystem for language " + llvm::StringRef(Language::GetNameForLanguageType(language)) + " doesn't exist", @@ -286,7 +256,23 @@ } } - return std::move(error); + if (!create_callback) + return llvm::make_error( + "Unable to find type system for language " + + llvm::StringRef(Language::GetNameForLanguageType(language)), + llvm::inconvertibleErrorCode()); + + // Cache even if we get a shared pointer that contains a null type system + // back + TypeSystemSP type_system_sp = (*create_callback)(); + m_map[language] = type_system_sp; + if (type_system_sp.get()) + return *type_system_sp.get(); + return llvm::make_error( + "TypeSystem for language " + + llvm::StringRef(Language::GetNameForLanguageType(language)) + + " doesn't exist", + llvm::inconvertibleErrorCode()); } llvm::Expected diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c 2021-11-16 16:47:26.000000000 +0000 @@ -1,4 +1,6 @@ -int main() { +#include + +void write_sve_regs() { asm volatile("setffr\n\t"); asm volatile("ptrue p0.b\n\t"); asm volatile("ptrue p1.h\n\t"); @@ -49,5 +51,20 @@ asm volatile("cpy z29.b, p5/z, #30\n\t"); asm volatile("cpy z30.b, p10/z, #31\n\t"); asm volatile("cpy z31.b, p15/z, #32\n\t"); +} + +// This function will be called using jitted expression call. We change vector +// length and write SVE registers. Our program context should restore to +// orignal vector length and register values after expression evaluation. +int expr_eval_func() { + prctl(PR_SVE_SET_VL, 8 * 2); + write_sve_regs(); + prctl(PR_SVE_SET_VL, 8 * 4); + write_sve_regs(); + return 1; +} + +int main() { + write_sve_regs(); return 0; // Set a break point here. } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py 2021-11-16 16:47:26.000000000 +0000 @@ -17,6 +17,51 @@ self.assertEqual(reg_value.GetByteSize(), expected, 'Verify "%s" == %i' % (name, expected)) + def check_sve_regs_read(self, z_reg_size): + p_reg_size = int(z_reg_size / 8) + + for i in range(32): + z_regs_value = '{' + \ + ' '.join('0x{:02x}'.format(i + 1) + for _ in range(z_reg_size)) + '}' + self.expect("register read " + 'z%i' % + (i), substrs=[z_regs_value]) + + p_value_bytes = ['0xff', '0x55', '0x11', '0x01', '0x00'] + for i in range(16): + p_regs_value = '{' + \ + ' '.join(p_value_bytes[i % 5] for _ in range(p_reg_size)) + '}' + self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value]) + + self.expect("register read ffr", substrs=[p_regs_value]) + + def check_sve_regs_read_after_write(self, z_reg_size): + p_reg_size = int(z_reg_size / 8) + + z_regs_value = '{' + \ + ' '.join(('0x9d' for _ in range(z_reg_size))) + '}' + + p_regs_value = '{' + \ + ' '.join(('0xee' for _ in range(p_reg_size))) + '}' + + for i in range(32): + self.runCmd('register write ' + 'z%i' % + (i) + " '" + z_regs_value + "'") + + for i in range(32): + self.expect("register read " + 'z%i' % (i), substrs=[z_regs_value]) + + for i in range(16): + self.runCmd('register write ' + 'p%i' % + (i) + " '" + p_regs_value + "'") + + for i in range(16): + self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value]) + + self.runCmd('register write ' + 'ffr ' + "'" + p_regs_value + "'") + + self.expect("register read " + 'ffr', substrs=[p_regs_value]) + mydir = TestBase.compute_mydir(__file__) @no_debug_info_test @@ -117,43 +162,17 @@ z_reg_size = vg_reg_value * 8 - p_reg_size = int(z_reg_size / 8) - - for i in range(32): - z_regs_value = '{' + \ - ' '.join('0x{:02x}'.format(i + 1) - for _ in range(z_reg_size)) + '}' - self.expect("register read " + 'z%i' % - (i), substrs=[z_regs_value]) + self.check_sve_regs_read(z_reg_size) - p_value_bytes = ['0xff', '0x55', '0x11', '0x01', '0x00'] - for i in range(16): - p_regs_value = '{' + \ - ' '.join(p_value_bytes[i % 5] for _ in range(p_reg_size)) + '}' - self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value]) + # Evaluate simple expression and print function expr_eval_func address. + self.expect("p expr_eval_func", substrs=["= 0x"]) - self.expect("register read ffr", substrs=[p_regs_value]) + # Evaluate expression call function expr_eval_func. + self.expect_expr("expr_eval_func()", + result_type="int", result_value="1") - z_regs_value = '{' + \ - ' '.join(('0x9d' for _ in range(z_reg_size))) + '}' + # We called a jitted function above which must not have changed SVE + # vector length or register values. + self.check_sve_regs_read(z_reg_size) - p_regs_value = '{' + \ - ' '.join(('0xee' for _ in range(p_reg_size))) + '}' - - for i in range(32): - self.runCmd('register write ' + 'z%i' % - (i) + " '" + z_regs_value + "'") - - for i in range(32): - self.expect("register read " + 'z%i' % (i), substrs=[z_regs_value]) - - for i in range(16): - self.runCmd('register write ' + 'p%i' % - (i) + " '" + p_regs_value + "'") - - for i in range(16): - self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value]) - - self.runCmd('register write ' + 'ffr ' + "'" + p_regs_value + "'") - - self.expect("register read " + 'ffr', substrs=[p_regs_value]) + self.check_sve_regs_read_after_write(z_reg_size) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/unittests/Symbol/CMakeLists.txt rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/unittests/Symbol/CMakeLists.txt --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/unittests/Symbol/CMakeLists.txt 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/unittests/Symbol/CMakeLists.txt 2021-11-16 16:47:26.000000000 +0000 @@ -1,6 +1,7 @@ add_lldb_unittest(SymbolTests LocateSymbolFileTest.cpp PostfixExpressionTest.cpp + TestTypeSystem.cpp TestTypeSystemClang.cpp TestClangASTImporter.cpp TestDWARFCallFrameInfo.cpp diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/unittests/Symbol/TestTypeSystem.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/unittests/Symbol/TestTypeSystem.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/lldb/unittests/Symbol/TestTypeSystem.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/lldb/unittests/Symbol/TestTypeSystem.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,92 @@ +//===-- TestTypeSystem.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "TestingSupport/SubsystemRAII.h" +#include "lldb/Core/Module.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/TypeSystem.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_private; + +class TestTypeSystemMap : public testing::Test { +public: + SubsystemRAII subsystems; +}; + +TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithInvalidModule) { + // GetTypeSystemForLanguage called with an invalid Module. + TypeSystemMap map; + Module module{ModuleSpec()}; + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, &module, + /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, &module, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, &module, + /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, &module, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); +} + +TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithNoModule) { + // GetTypeSystemForLanguage called with no Module. + TypeSystemMap map; + Module *module = nullptr; + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, module, + /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, module, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, module, /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, module, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); +} + +TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithNoTarget) { + // GetTypeSystemForLanguage called with no Target. + TypeSystemMap map; + Target *target = nullptr; + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, target, + /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, target, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, target, /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, target, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/cmake/modules/AddLLVM.cmake rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/cmake/modules/AddLLVM.cmake --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/cmake/modules/AddLLVM.cmake 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/cmake/modules/AddLLVM.cmake 2021-11-16 16:47:26.000000000 +0000 @@ -1196,6 +1196,7 @@ llvm-cxxfilt llvm-ranlib llvm-lib + llvm-ml llvm-nm llvm-objcopy llvm-objdump diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/CMakeLists.txt rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/CMakeLists.txt --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/CMakeLists.txt 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/CMakeLists.txt 2021-11-16 16:47:26.000000000 +0000 @@ -702,8 +702,13 @@ endif() option(LLVM_ENABLE_PLUGINS "Enable plugin support" ${LLVM_ENABLE_PLUGINS_default}) -set(ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER TRUE CACHE BOOL +set(LLVM_ENABLE_NEW_PASS_MANAGER TRUE CACHE BOOL "Enable the new pass manager by default.") +if(NOT LLVM_ENABLE_NEW_PASS_MANAGER) + message(WARNING "Using the legacy pass manager for the optimization pipeline" + " is deprecated. The functionality will degrade over time and" + " be removed in a future release.") +endif() include(HandleLLVMOptions) @@ -833,10 +838,6 @@ set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS tf_xla_runtime) endif() -# Keep the legacy CMake flag ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER for -# compatibility. -set(LLVM_ENABLE_NEW_PASS_MANAGER ${ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER}) - # Configure the three LLVM configuration header files. configure_file( ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/config.h.cmake diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/docs/NewPassManager.rst rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/docs/NewPassManager.rst --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/docs/NewPassManager.rst 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/docs/NewPassManager.rst 2021-11-16 16:47:26.000000000 +0000 @@ -449,7 +449,7 @@ For the optimization pipeline, the new PM is the default PM. The legacy PM is available for the optimization pipeline either by setting the CMake flag -``-DENABLE_EXPERIMENTAL_NEW_PASS_MANAGER=OFF`` when building LLVM, or by +``-DLLVM_ENABLE_NEW_PASS_MANAGER=OFF`` when building LLVM, or by various compiler/linker flags, e.g. ``-flegacy-pass-manager`` for ``clang``. There will be efforts to deprecate and remove the legacy PM for the diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/docs/ReleaseNotes.rst rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/docs/ReleaseNotes.rst --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/docs/ReleaseNotes.rst 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/docs/ReleaseNotes.rst 2021-11-16 16:47:26.000000000 +0000 @@ -55,6 +55,17 @@ emits valid unwind entrypoints which are validated when the context is being set during exception handling. +* Flang is now included in the binary packages released by LLVM. + +* The debuginfo-test project has been renamed cross-project-tests and is now + intended for testing components from multiple projects, not just debug + information. The new "cross-project-tests" name replaces "debuginfo-test" in + LLVM_ENABLE_PROJECTS, and a new check-cross-project-tests target has been + added for running all tests in the project. The pre-existing check-debuginfo- + test target remains for running just the debug information tests. + (`D95339 `_ and + `D96513 `_) + Changes to the LLVM IR ---------------------- @@ -64,6 +75,10 @@ * The opaque pointer type ``ptr`` has been introduced. It is still in the process of being worked on and should not be used yet. +* Using the legacy pass manager for the optimization pipeline is deprecated and + will be removed after LLVM 14. In the meantime, only minimal effort will be + made to maintain the legacy pass manager for the optimization pipeline. + Changes to building LLVM ------------------------ @@ -80,10 +95,15 @@ * Introduced assembly support for Armv9-A's Realm Management Extension (RME) and Scalable Matrix Extension (SME). +* Produce proper cross-section relative relocations on COFF + +* Fixed the calling convention on Windows for variadic functions involving + floats in the fixed arguments + Changes to the ARM Backend -------------------------- -During this release ... +* Produce proper cross-section relative relocations on COFF Changes to the MIPS Target -------------------------- @@ -241,6 +261,15 @@ * In lli the default JIT engine switched from MCJIT (``-jit-kind=mcjit``) to ORC (``-jit-kind=orc``). (`D98931 `_) +* llvm-rc got support for invoking Clang to preprocess its input. + (`D100755 `_) + +* llvm-rc got a GNU windres compatible frontend, llvm-windres. + (`D100756 `_) + +* llvm-ml has improved compatibility with MS ml.exe, managing to assemble + more asm files. + Changes to LLDB --------------------------------- diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LazyCallGraph.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LazyCallGraph.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LazyCallGraph.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LazyCallGraph.h 2021-11-16 16:47:26.000000000 +0000 @@ -419,7 +419,7 @@ /// outer structure. SCCs do not support mutation of the call graph, that /// must be done through the containing \c RefSCC in order to fully reason /// about the ordering and connections of the graph. - class SCC { + class LLVM_EXTERNAL_VISIBILITY SCC { friend class LazyCallGraph; friend class LazyCallGraph::Node; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LoopInfo.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LoopInfo.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LoopInfo.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LoopInfo.h 2021-11-16 16:47:26.000000000 +0000 @@ -527,7 +527,7 @@ /// Represents a single loop in the control flow graph. Note that not all SCCs /// in the CFG are necessarily loops. -class Loop : public LoopBase { +class LLVM_EXTERNAL_VISIBILITY Loop : public LoopBase { public: /// A range representing the start and end location of a loop. class LocRange { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LoopNestAnalysis.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LoopNestAnalysis.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LoopNestAnalysis.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/LoopNestAnalysis.h 2021-11-16 16:47:26.000000000 +0000 @@ -24,7 +24,7 @@ class LPMUpdater; /// This class represents a loop nest and can be used to query its properties. -class LoopNest { +class LLVM_EXTERNAL_VISIBILITY LoopNest { public: /// Construct a loop nest rooted by loop \p Root. LoopNest(Loop &Root, ScalarEvolution &SE); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/TargetTransformInfo.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/TargetTransformInfo.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/TargetTransformInfo.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/TargetTransformInfo.h 2021-11-16 16:47:26.000000000 +0000 @@ -97,7 +97,7 @@ Loop *L = nullptr; BasicBlock *ExitBlock = nullptr; BranchInst *ExitBranch = nullptr; - const SCEV *TripCount = nullptr; + const SCEV *ExitCount = nullptr; IntegerType *CountType = nullptr; Value *LoopDecrement = nullptr; // Decrement the loop counter by this // value in every iteration. diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/ValueTracking.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/ValueTracking.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/ValueTracking.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Analysis/ValueTracking.h 2021-11-16 16:47:26.000000000 +0000 @@ -744,6 +744,10 @@ /// minimum/maximum flavor. CmpInst::Predicate getInverseMinMaxPred(SelectPatternFlavor SPF); + /// Return the minimum or maximum constant value for the specified integer + /// min/max flavor and type. + APInt getMinMaxLimit(SelectPatternFlavor SPF, unsigned BitWidth); + /// Check if the values in \p VL are select instructions that can be converted /// to a min or max (vector) intrinsic. Returns the intrinsic ID, if such a /// conversion is possible, together with a bool indicating whether all select diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/CodeGen/MachineFunction.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/CodeGen/MachineFunction.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/CodeGen/MachineFunction.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/CodeGen/MachineFunction.h 2021-11-16 16:47:26.000000000 +0000 @@ -227,7 +227,7 @@ : LandingPadBlock(MBB) {} }; -class MachineFunction { +class LLVM_EXTERNAL_VISIBILITY MachineFunction { Function &F; const LLVMTargetMachine &Target; const TargetSubtargetInfo *STI; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Function.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Function.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Function.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Function.h 2021-11-16 16:47:26.000000000 +0000 @@ -58,7 +58,8 @@ class BranchProbabilityInfo; class BlockFrequencyInfo; -class Function : public GlobalObject, public ilist_node { +class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject, + public ilist_node { public: using BasicBlockListType = SymbolTableList; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Metadata.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Metadata.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Metadata.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Metadata.h 2021-11-16 16:47:26.000000000 +0000 @@ -897,6 +897,7 @@ class MDNode : public Metadata { friend class ReplaceableMetadataImpl; friend class LLVMContextImpl; + friend class DIArgList; unsigned NumOperands; unsigned NumUnresolved; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Module.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Module.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Module.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/IR/Module.h 2021-11-16 16:47:26.000000000 +0000 @@ -64,9 +64,9 @@ /// constant references to global variables in the module. When a global /// variable is destroyed, it should have no entries in the GlobalValueRefMap. /// The main container class for the LLVM Intermediate Representation. -class Module { -/// @name Types And Enumerations -/// @{ +class LLVM_EXTERNAL_VISIBILITY Module { + /// @name Types And Enumerations + /// @{ public: /// The type for the list of global variables. using GlobalListType = SymbolTableList; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h 2021-11-16 16:47:26.000000000 +0000 @@ -65,7 +65,7 @@ bool processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI); bool processMemMove(MemMoveInst *M); bool performCallSlotOptzn(Instruction *cpyLoad, Instruction *cpyStore, - Value *cpyDst, Value *cpySrc, uint64_t cpyLen, + Value *cpyDst, Value *cpySrc, TypeSize cpyLen, Align cpyAlign, CallInst *C); bool processMemCpyMemCpyDependence(MemCpyInst *M, MemCpyInst *MDep); bool processMemSetMemCpyDependence(MemCpyInst *MemCpy, MemSetInst *MemSet); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/InstructionSimplify.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/InstructionSimplify.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/InstructionSimplify.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/InstructionSimplify.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -4080,6 +4080,22 @@ std::swap(TrueVal, FalseVal); } + // Check for integer min/max with a limit constant: + // X > MIN_INT ? X : MIN_INT --> X + // X < MAX_INT ? X : MAX_INT --> X + if (TrueVal->getType()->isIntOrIntVectorTy()) { + Value *X, *Y; + SelectPatternFlavor SPF = + matchDecomposedSelectPattern(cast(CondVal), TrueVal, FalseVal, + X, Y).Flavor; + if (SelectPatternResult::isMinOrMax(SPF) && Pred == getMinMaxPred(SPF)) { + APInt LimitC = getMinMaxLimit(getInverseMinMaxFlavor(SPF), + X->getType()->getScalarSizeInBits()); + if (match(Y, m_SpecificInt(LimitC))) + return X; + } + } + if (Pred == ICmpInst::ICMP_EQ && match(CmpRHS, m_Zero())) { Value *X; const APInt *Y; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -13969,7 +13969,7 @@ if (ExactRegion.isWrappedSet() || ExactRegion.isFullSet()) return false; auto I = RewriteMap.find(LHSUnknown->getValue()); - const SCEV *RewrittenLHS = I != RewriteMap.end() ? I->second : LHS; + const SCEV *RewrittenLHS = I != RewriteMap.end() ? I->second : LHSUnknown; RewriteMap[LHSUnknown->getValue()] = getUMaxExpr( getConstant(ExactRegion.getUnsignedMin()), getUMinExpr(RewrittenLHS, getConstant(ExactRegion.getUnsignedMax()))); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/TargetTransformInfo.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/TargetTransformInfo.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/TargetTransformInfo.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/TargetTransformInfo.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -167,11 +167,7 @@ // Note that this block may not be the loop latch block, even if the loop // has a latch block. ExitBlock = BB; - TripCount = SE.getAddExpr(EC, SE.getOne(EC->getType())); - - if (!EC->getType()->isPointerTy() && EC->getType() != CountType) - TripCount = SE.getZeroExtendExpr(TripCount, CountType); - + ExitCount = EC; break; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/ValueTracking.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/ValueTracking.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/ValueTracking.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Analysis/ValueTracking.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -6253,6 +6253,16 @@ return getMinMaxPred(getInverseMinMaxFlavor(SPF)); } +APInt llvm::getMinMaxLimit(SelectPatternFlavor SPF, unsigned BitWidth) { + switch (SPF) { + case SPF_SMAX: return APInt::getSignedMaxValue(BitWidth); + case SPF_SMIN: return APInt::getSignedMinValue(BitWidth); + case SPF_UMAX: return APInt::getMaxValue(BitWidth); + case SPF_UMIN: return APInt::getMinValue(BitWidth); + default: llvm_unreachable("Unexpected flavor"); + } +} + std::pair llvm::canConvertToMinOrMaxIntrinsic(ArrayRef VL) { // Check if VL contains select instructions that can be folded into a min/max diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1162,7 +1162,7 @@ } DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, - DIE *CalleeDIE, + const DISubprogram *CalleeSP, bool IsTail, const MCSymbol *PCAddr, const MCSymbol *CallAddr, @@ -1176,7 +1176,8 @@ addAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_target), MachineLocation(CallReg)); } else { - assert(CalleeDIE && "No DIE for call site entry origin"); + DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP); + assert(CalleeDIE && "Could not create DIE for call site entry origin"); addDIEEntry(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_origin), *CalleeDIE); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h 2021-11-16 16:47:26.000000000 +0000 @@ -249,16 +249,14 @@ dwarf::LocationAtom getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const; /// Construct a call site entry DIE describing a call within \p Scope to a - /// callee described by \p CalleeDIE. - /// \p CalleeDIE is a declaration or definition subprogram DIE for the callee. - /// For indirect calls \p CalleeDIE is set to nullptr. + /// callee described by \p CalleeSP. /// \p IsTail specifies whether the call is a tail call. /// \p PCAddr points to the PC value after the call instruction. /// \p CallAddr points to the PC value at the call instruction (or is null). /// \p CallReg is a register location for an indirect call. For direct calls /// the \p CallReg is set to 0. - DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, DIE *CalleeDIE, bool IsTail, - const MCSymbol *PCAddr, + DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP, + bool IsTail, const MCSymbol *PCAddr, const MCSymbol *CallAddr, unsigned CallReg); /// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params /// were collected by the \ref collectCallSiteParameters. diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -587,14 +587,6 @@ } } -DIE &DwarfDebug::constructSubprogramDefinitionDIE(const DISubprogram *SP) { - DICompileUnit *Unit = SP->getUnit(); - assert(SP->isDefinition() && "Subprogram not a definition"); - assert(Unit && "Subprogram definition without parent unit"); - auto &CU = getOrCreateDwarfCompileUnit(Unit); - return *CU.getOrCreateSubprogramDIE(SP); -} - /// Represents a parameter whose call site value can be described by applying a /// debug expression to a register in the forwarded register worklist. struct FwdRegParamInfo { @@ -945,7 +937,7 @@ continue; unsigned CallReg = 0; - DIE *CalleeDIE = nullptr; + const DISubprogram *CalleeSP = nullptr; const Function *CalleeDecl = nullptr; if (CalleeOp.isReg()) { CallReg = CalleeOp.getReg(); @@ -955,19 +947,7 @@ CalleeDecl = dyn_cast(CalleeOp.getGlobal()); if (!CalleeDecl || !CalleeDecl->getSubprogram()) continue; - const DISubprogram *CalleeSP = CalleeDecl->getSubprogram(); - - if (CalleeSP->isDefinition()) { - // Ensure that a subprogram DIE for the callee is available in the - // appropriate CU. - CalleeDIE = &constructSubprogramDefinitionDIE(CalleeSP); - } else { - // Create the declaration DIE if it is missing. This is required to - // support compilation of old bitcode with an incomplete list of - // retained metadata. - CalleeDIE = CU.getOrCreateSubprogramDIE(CalleeSP); - } - assert(CalleeDIE && "Must have a DIE for the callee"); + CalleeSP = CalleeDecl->getSubprogram(); } // TODO: Omit call site entries for runtime calls (objc_msgSend, etc). @@ -1004,7 +984,7 @@ << (IsTail ? " [IsTail]" : "") << "\n"); DIE &CallSiteDIE = CU.constructCallSiteEntryDIE( - ScopeDIE, CalleeDIE, IsTail, PCAddr, CallAddr, CallReg); + ScopeDIE, CalleeSP, IsTail, PCAddr, CallAddr, CallReg); // Optionally emit call-site-param debug info. if (emitDebugEntryValues()) { @@ -1121,6 +1101,11 @@ NewCU.setSection(Asm->getObjFileLowering().getDwarfInfoSection()); } + // Create DIEs for function declarations used for call site debug info. + for (auto Scope : DIUnit->getRetainedTypes()) + if (auto *SP = dyn_cast_or_null(Scope)) + NewCU.getOrCreateSubprogramDIE(SP); + CUMap.insert({DIUnit, &NewCU}); CUDieMap.insert({&NewCU.getUnitDie(), &NewCU}); return NewCU; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h 2021-11-16 16:47:26.000000000 +0000 @@ -471,9 +471,6 @@ /// Construct a DIE for this abstract scope. void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope); - /// Construct a DIE for the subprogram definition \p SP and return it. - DIE &constructSubprogramDefinitionDIE(const DISubprogram *SP); - /// Construct DIEs for call site entries describing the calls in \p MF. void constructCallSiteEntryDIEs(const DISubprogram &SP, DwarfCompileUnit &CU, DIE &ScopeDIE, const MachineFunction &MF); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -186,9 +186,8 @@ /// Check whether the DIE for this MDNode can be shared across CUs. bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const { - // When the MDNode can be part of the type system (this includes subprogram - // declarations *and* subprogram definitions, even local definitions), the - // DIE must be shared across CUs. + // When the MDNode can be part of the type system, the DIE can be shared + // across CUs. // Combining type units and cross-CU DIE sharing is lower value (since // cross-CU DIE sharing is used in LTO and removes type redundancy at that // level already) but may be implementable for some value in projects @@ -196,7 +195,9 @@ // together. if (isDwoUnit() && !DD->shareAcrossDWOCUs()) return false; - return (isa(D) || isa(D)) && !DD->generateTypeUnits(); + return (isa(D) || + (isa(D) && !cast(D)->isDefinition())) && + !DD->generateTypeUnits(); } DIE *DwarfUnit::getDIE(const DINode *D) const { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/HardwareLoops.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/HardwareLoops.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/HardwareLoops.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/HardwareLoops.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -187,7 +187,7 @@ const DataLayout &DL, OptimizationRemarkEmitter *ORE) : SE(SE), DL(DL), ORE(ORE), L(Info.L), M(L->getHeader()->getModule()), - TripCount(Info.TripCount), + ExitCount(Info.ExitCount), CountType(Info.CountType), ExitBranch(Info.ExitBranch), LoopDecrement(Info.LoopDecrement), @@ -202,7 +202,7 @@ OptimizationRemarkEmitter *ORE = nullptr; Loop *L = nullptr; Module *M = nullptr; - const SCEV *TripCount = nullptr; + const SCEV *ExitCount = nullptr; Type *CountType = nullptr; BranchInst *ExitBranch = nullptr; Value *LoopDecrement = nullptr; @@ -296,7 +296,7 @@ } assert( - (HWLoopInfo.ExitBlock && HWLoopInfo.ExitBranch && HWLoopInfo.TripCount) && + (HWLoopInfo.ExitBlock && HWLoopInfo.ExitBranch && HWLoopInfo.ExitCount) && "Hardware Loop must have set exit info."); BasicBlock *Preheader = L->getLoopPreheader(); @@ -381,13 +381,18 @@ // loop counter and tests that is not zero? SCEVExpander SCEVE(SE, DL, "loopcnt"); + if (!ExitCount->getType()->isPointerTy() && + ExitCount->getType() != CountType) + ExitCount = SE.getZeroExtendExpr(ExitCount, CountType); + + ExitCount = SE.getAddExpr(ExitCount, SE.getOne(CountType)); // If we're trying to use the 'test and set' form of the intrinsic, we need // to replace a conditional branch that is controlling entry to the loop. It // is likely (guaranteed?) that the preheader has an unconditional branch to // the loop header, so also check if it has a single predecessor. - if (SE.isLoopEntryGuardedByCond(L, ICmpInst::ICMP_NE, TripCount, - SE.getZero(TripCount->getType()))) { + if (SE.isLoopEntryGuardedByCond(L, ICmpInst::ICMP_NE, ExitCount, + SE.getZero(ExitCount->getType()))) { LLVM_DEBUG(dbgs() << " - Attempting to use test.set counter.\n"); UseLoopGuard |= ForceGuardLoopEntry; } else @@ -399,19 +404,19 @@ BasicBlock *Predecessor = BB->getSinglePredecessor(); // If it's not safe to create a while loop then don't force it and create a // do-while loop instead - if (!isSafeToExpandAt(TripCount, Predecessor->getTerminator(), SE)) + if (!isSafeToExpandAt(ExitCount, Predecessor->getTerminator(), SE)) UseLoopGuard = false; else BB = Predecessor; } - if (!isSafeToExpandAt(TripCount, BB->getTerminator(), SE)) { - LLVM_DEBUG(dbgs() << "- Bailing, unsafe to expand TripCount " << *TripCount - << "\n"); + if (!isSafeToExpandAt(ExitCount, BB->getTerminator(), SE)) { + LLVM_DEBUG(dbgs() << "- Bailing, unsafe to expand ExitCount " + << *ExitCount << "\n"); return nullptr; } - Value *Count = SCEVE.expandCodeFor(TripCount, CountType, + Value *Count = SCEVE.expandCodeFor(ExitCount, CountType, BB->getTerminator()); // FIXME: We've expanded Count where we hope to insert the counter setting diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/RegAllocFast.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/RegAllocFast.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/RegAllocFast.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/RegAllocFast.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -15,6 +15,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SparseSet.h" @@ -432,7 +433,7 @@ // every definition of it, meaning we can switch all the DBG_VALUEs over // to just reference the stack slot. SmallVectorImpl &LRIDbgOperands = LiveDbgValueMap[VirtReg]; - SmallDenseMap> + SmallMapVector, 2> SpilledOperandsMap; for (MachineOperand *MO : LRIDbgOperands) SpilledOperandsMap[MO->getParent()].push_back(MO); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -5133,8 +5133,9 @@ if (SDValue V = foldLogicOfSetCCs(true, N0, N1, DL)) return V; + // TODO: Rewrite this to return a new 'AND' instead of using CombineTo. if (N0.getOpcode() == ISD::ADD && N1.getOpcode() == ISD::SRL && - VT.getSizeInBits() <= 64) { + VT.getSizeInBits() <= 64 && N0->hasOneUse()) { if (ConstantSDNode *ADDI = dyn_cast(N0.getOperand(1))) { if (ConstantSDNode *SRLI = dyn_cast(N1.getOperand(1))) { // Look for (and (add x, c1), (lshr y, c2)). If C1 wasn't a legal @@ -20560,8 +20561,12 @@ // otherwise => (extract_subvec V1, ExtIdx) uint64_t InsIdx = V.getConstantOperandVal(2); if (InsIdx * SmallVT.getScalarSizeInBits() == - ExtIdx * NVT.getScalarSizeInBits()) + ExtIdx * NVT.getScalarSizeInBits()) { + if (LegalOperations && !TLI.isOperationLegal(ISD::BITCAST, NVT)) + return SDValue(); + return DAG.getBitcast(NVT, V.getOperand(1)); + } return DAG.getNode( ISD::EXTRACT_SUBVECTOR, SDLoc(N), NVT, DAG.getBitcast(N->getOperand(0).getValueType(), V.getOperand(0)), diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -3464,8 +3464,11 @@ SDValue SatMin = DAG.getConstant(MinVal, dl, VT); SDValue SatMax = DAG.getConstant(MaxVal, dl, VT); SDValue Zero = DAG.getConstant(0, dl, VT); - SDValue ProdNeg = DAG.getSetCC(dl, BoolVT, Product, Zero, ISD::SETLT); - Result = DAG.getSelect(dl, VT, ProdNeg, SatMax, SatMin); + // Xor the inputs, if resulting sign bit is 0 the product will be + // positive, else negative. + SDValue Xor = DAG.getNode(ISD::XOR, dl, VT, LHS, RHS); + SDValue ProdNeg = DAG.getSetCC(dl, BoolVT, Xor, Zero, ISD::SETLT); + Result = DAG.getSelect(dl, VT, ProdNeg, SatMin, SatMax); Result = DAG.getSelect(dl, VT, Overflow, Result, Product); } else { // For unsigned multiplication, we only need to check the max since we diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -8677,8 +8677,10 @@ RegisterSDNode *R = dyn_cast(AsmNodeOperands[CurOp+1]); Register TiedReg = R->getReg(); MVT RegVT = R->getSimpleValueType(0); - const TargetRegisterClass *RC = TiedReg.isVirtual() ? - MRI.getRegClass(TiedReg) : TRI.getMinimalPhysRegClass(TiedReg); + const TargetRegisterClass *RC = + TiedReg.isVirtual() ? MRI.getRegClass(TiedReg) + : RegVT != MVT::Untyped ? TLI.getRegClassFor(RegVT) + : TRI.getMinimalPhysRegClass(TiedReg); unsigned NumRegs = InlineAsm::getNumOperandRegisters(OpFlag); for (unsigned i = 0; i != NumRegs; ++i) Regs.push_back(MRI.createVirtualRegister(RC)); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -8155,8 +8155,11 @@ APInt MaxVal = APInt::getSignedMaxValue(VTSize); SDValue SatMin = DAG.getConstant(MinVal, dl, VT); SDValue SatMax = DAG.getConstant(MaxVal, dl, VT); - SDValue ProdNeg = DAG.getSetCC(dl, BoolVT, Product, Zero, ISD::SETLT); - Result = DAG.getSelect(dl, VT, ProdNeg, SatMax, SatMin); + // Xor the inputs, if resulting sign bit is 0 the product will be + // positive, else negative. + SDValue Xor = DAG.getNode(ISD::XOR, dl, VT, LHS, RHS); + SDValue ProdNeg = DAG.getSetCC(dl, BoolVT, Xor, Zero, ISD::SETLT); + Result = DAG.getSelect(dl, VT, ProdNeg, SatMin, SatMax); return DAG.getSelect(dl, VT, Overflow, Result, Product); } else if (!Signed && isOperationLegalOrCustom(ISD::UMULO, VT)) { SDValue Result = diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/Constants.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/Constants.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/Constants.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/Constants.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -315,9 +315,11 @@ return false; for (unsigned i = 0, e = cast(VTy)->getNumElements(); - i != e; ++i) - if (HasFn(C->getAggregateElement(i))) - return true; + i != e; ++i) { + if (Constant *Elem = C->getAggregateElement(i)) + if (HasFn(Elem)) + return true; + } } return false; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/DebugInfoMetadata.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/DebugInfoMetadata.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/DebugInfoMetadata.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/DebugInfoMetadata.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1592,6 +1592,12 @@ assert((!New || isa(New)) && "DIArgList must be passed a ValueAsMetadata"); untrack(); + bool Uniq = isUniqued(); + if (Uniq) { + // We need to update the uniqueness once the Args are updated since they + // form the key to the DIArgLists store. + eraseFromStore(); + } ValueAsMetadata *NewVM = cast_or_null(New); for (ValueAsMetadata *&VM : Args) { if (&VM == OldVMPtr) { @@ -1601,6 +1607,10 @@ VM = ValueAsMetadata::get(UndefValue::get(VM->getValue()->getType())); } } + if (Uniq) { + if (uniquify() != this) + storeDistinctInContext(); + } track(); } void DIArgList::track() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/LLVMContextImpl.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/LLVMContextImpl.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/LLVMContextImpl.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/LLVMContextImpl.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -55,8 +55,15 @@ // Drop references for MDNodes. Do this before Values get deleted to avoid // unnecessary RAUW when nodes are still unresolved. - for (auto *I : DistinctMDNodes) + for (auto *I : DistinctMDNodes) { + // We may have DIArgList that were uniqued, and as it has a custom + // implementation of dropAllReferences, it needs to be explicitly invoked. + if (auto *AL = dyn_cast(I)) { + AL->dropAllReferences(); + continue; + } I->dropAllReferences(); + } #define HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS) \ for (auto *I : CLASS##s) \ I->dropAllReferences(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/Mangler.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/Mangler.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/Mangler.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/IR/Mangler.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -99,6 +99,11 @@ const unsigned PtrSize = DL.getPointerSize(); for (const Argument &A : F->args()) { + // For the purposes of the byte count suffix, structs returned by pointer + // do not count as function arguments. + if (A.hasStructRetAttr()) + continue; + // 'Dereference' type in case of byval or inalloca parameter attribute. uint64_t AllocSize = A.hasPassPointeeByValueCopyAttr() ? A.getPassPointeeByValueCopySize(DL) : diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Linker/LinkModules.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Linker/LinkModules.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Linker/LinkModules.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Linker/LinkModules.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -177,9 +177,25 @@ // Go with Dst. LinkFromSrc = false; break; - case Comdat::SelectionKind::NoDeduplicate: - return emitError("Linking COMDATs named '" + ComdatName + - "': nodeduplicate has been violated!"); + case Comdat::SelectionKind::NoDeduplicate: { + const GlobalVariable *DstGV; + const GlobalVariable *SrcGV; + if (getComdatLeader(DstM, ComdatName, DstGV) || + getComdatLeader(*SrcM, ComdatName, SrcGV)) + return true; + + if (SrcGV->isWeakForLinker()) { + // Go with Dst. + LinkFromSrc = false; + } else if (DstGV->isWeakForLinker()) { + // Go with Src. + LinkFromSrc = true; + } else { + return emitError("Linking COMDATs named '" + ComdatName + + "': nodeduplicate has been violated!"); + } + break; + } case Comdat::SelectionKind::ExactMatch: case Comdat::SelectionKind::Largest: case Comdat::SelectionKind::SameSize: { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Passes/PassBuilder.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Passes/PassBuilder.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Passes/PassBuilder.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Passes/PassBuilder.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1784,9 +1784,12 @@ MPM.addPass(GlobalOptPass()); // Garbage collect dead functions. - // FIXME: Add ArgumentPromotion pass after once it's ported. MPM.addPass(GlobalDCEPass()); + // If we didn't decide to inline a function, check to see if we can + // transform it to pass arguments by value instead of by reference. + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(ArgumentPromotionPass())); + FunctionPassManager FPM; // The IPO Passes may leave cruft around. Clean up after them. FPM.addPass(InstCombinePass()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -4161,7 +4161,8 @@ bool AArch64TargetLowering::shouldRemoveExtendFromGSIndex(EVT VT) const { if (VT.getVectorElementType() == MVT::i32 && - VT.getVectorElementCount().getKnownMinValue() >= 4) + VT.getVectorElementCount().getKnownMinValue() >= 4 && + !VT.isFixedLengthVector()) return true; return false; @@ -13680,6 +13681,8 @@ N = N.getOperand(0); if (N.getOpcode() != ISD::EXTRACT_SUBVECTOR) return false; + if (N.getOperand(0).getValueType().isScalableVector()) + return false; return cast(N.getOperand(1))->getAPIntValue() == N.getOperand(0).getValueType().getVectorNumElements() / 2; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1301,6 +1301,7 @@ static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI) { assert(Reg.isValid() && "Expected valid register!"); + bool HasZext = false; while (MachineInstr *MI = getDefIgnoringCopies(Reg, MRI)) { unsigned Opc = MI->getOpcode(); @@ -1314,6 +1315,9 @@ // on the truncated x is the same as the bit number on x. if (Opc == TargetOpcode::G_ANYEXT || Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_TRUNC) { + if (Opc == TargetOpcode::G_ZEXT) + HasZext = true; + Register NextReg = MI->getOperand(1).getReg(); // Did we find something worth folding? if (!NextReg.isValid() || !MRI.hasOneNonDBGUse(NextReg)) @@ -1342,8 +1346,12 @@ std::swap(ConstantReg, TestReg); VRegAndVal = getConstantVRegValWithLookThrough(ConstantReg, MRI); } - if (VRegAndVal) - C = VRegAndVal->Value.getSExtValue(); + if (VRegAndVal) { + if (HasZext) + C = VRegAndVal->Value.getZExtValue(); + else + C = VRegAndVal->Value.getSExtValue(); + } break; } case TargetOpcode::G_ASHR: diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -103,8 +103,7 @@ getActionDefinitionsBuilder(G_BSWAP) .legalFor({s32, s64, v4s32, v2s32, v2s64}) .clampScalar(0, s32, s64) - .widenScalarToNextPow2(0) - .customIf(typeIs(0, v2s16)); // custom lower as G_REV32 + G_LSHR + .widenScalarToNextPow2(0); getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR}) .legalFor({s32, s64, v2s32, v4s32, v4s16, v8s16, v16s8, v8s8}) @@ -799,8 +798,6 @@ case TargetOpcode::G_LOAD: case TargetOpcode::G_STORE: return legalizeLoadStore(MI, MRI, MIRBuilder, Observer); - case TargetOpcode::G_BSWAP: - return legalizeBSwap(MI, MRI, MIRBuilder); case TargetOpcode::G_SHL: case TargetOpcode::G_ASHR: case TargetOpcode::G_LSHR: @@ -1014,46 +1011,6 @@ MI.eraseFromParent(); return true; } - -bool AArch64LegalizerInfo::legalizeBSwap(MachineInstr &MI, - MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const { - assert(MI.getOpcode() == TargetOpcode::G_BSWAP); - - // The <2 x half> case needs special lowering because there isn't an - // instruction that does that directly. Instead, we widen to <8 x i8> - // and emit a G_REV32 followed by a G_LSHR knowing that instruction selection - // will later match them as: - // - // rev32.8b v0, v0 - // ushr.2s v0, v0, #16 - // - // We could emit those here directly, but it seems better to keep things as - // generic as possible through legalization, and avoid committing layering - // violations by legalizing & selecting here at the same time. - - Register ValReg = MI.getOperand(1).getReg(); - assert(LLT::fixed_vector(2, 16) == MRI.getType(ValReg)); - const LLT v2s32 = LLT::fixed_vector(2, 32); - const LLT v8s8 = LLT::fixed_vector(8, 8); - const LLT s32 = LLT::scalar(32); - - auto Undef = MIRBuilder.buildUndef(v8s8); - auto Insert = - MIRBuilder - .buildInstr(TargetOpcode::INSERT_SUBREG, {v8s8}, {Undef, ValReg}) - .addImm(AArch64::ssub); - auto Rev32 = MIRBuilder.buildInstr(AArch64::G_REV32, {v8s8}, {Insert}); - auto Bitcast = MIRBuilder.buildBitcast(v2s32, Rev32); - auto Amt = MIRBuilder.buildConstant(v2s32, 16); - auto UShr = - MIRBuilder.buildInstr(TargetOpcode::G_LSHR, {v2s32}, {Bitcast, Amt}); - auto Zero = MIRBuilder.buildConstant(s32, 0); - auto Extract = MIRBuilder.buildExtractVectorElement(s32, UShr, Zero); - MIRBuilder.buildBitcast({MI.getOperand(0).getReg()}, Extract); - MI.eraseFromParent(); - return true; -} bool AArch64LegalizerInfo::legalizeVaArg(MachineInstr &MI, MachineRegisterInfo &MRI, diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h 2021-11-16 16:47:26.000000000 +0000 @@ -35,8 +35,6 @@ MachineInstr &MI) const override; private: - bool legalizeBSwap(MachineInstr &MI, MachineRegisterInfo &MRI, - MachineIRBuilder &MIRBuilder) const; bool legalizeVaArg(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &MIRBuilder) const; bool legalizeLoadStore(MachineInstr &MI, MachineRegisterInfo &MRI, diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -13,6 +13,8 @@ #include "AArch64RegisterBankInfo.h" #include "AArch64InstrInfo.h" +#include "AArch64RegisterInfo.h" +#include "MCTargetDesc/AArch64MCTargetDesc.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" @@ -271,6 +273,7 @@ case AArch64::WSeqPairsClassRegClassID: case AArch64::XSeqPairsClassRegClassID: case AArch64::MatrixIndexGPR32_12_15RegClassID: + case AArch64::GPR64_with_sub_32_in_MatrixIndexGPR32_12_15RegClassID: return getRegBank(AArch64::GPRRegBankID); case AArch64::CCRRegClassID: return getRegBank(AArch64::CCRegBankID); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/SMEInstrFormats.td rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/SMEInstrFormats.td --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/SMEInstrFormats.td 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/AArch64/SMEInstrFormats.td 2021-11-16 16:47:26.000000000 +0000 @@ -480,7 +480,7 @@ MatrixTileVectorOperand tile_ty, ZPRRegOp zpr_ty, Operand imm_ty> { def : InstAlias<"mov\t$ZAd[$Rv, $imm], $Pg/m, $Zn", - (inst tile_ty:$ZAd, MatrixIndexGPR32Op12_15:$Rv, imm0_15:$imm, PPR3bAny:$Pg, zpr_ty:$Zn), 1>; + (inst tile_ty:$ZAd, MatrixIndexGPR32Op12_15:$Rv, imm_ty:$imm, PPR3bAny:$Pg, zpr_ty:$Zn), 1>; } multiclass sme_vector_v_to_tile { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1647,7 +1647,7 @@ "CMP_SWAP not expected to be custom expanded for Thumb1"); assert((UxtOp == 0 || UxtOp == ARM::tUXTB || UxtOp == ARM::tUXTH) && "ARMv8-M.baseline does not have t2UXTB/t2UXTH"); - assert(ARM::tGPRRegClass.contains(DesiredReg) && + assert((UxtOp == 0 || ARM::tGPRRegClass.contains(DesiredReg)) && "DesiredReg used for UXT op must be tGPR"); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -485,6 +485,9 @@ case Intrinsic::experimental_constrained_sin: case Intrinsic::experimental_constrained_cos: return true; + // There is no corresponding FMA instruction for PPC double double. + // Thus, we need to disable CTR loop generation for this type. + case Intrinsic::fmuladd: case Intrinsic::copysign: if (CI->getArgOperand(0)->getType()->getScalarType()-> isPPC_FP128Ty()) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1223,7 +1223,7 @@ // Both of operands are not fixed. Set one of commutable // operands to the tied source. CommutableOpIdx1 = 1; - } else if (SrcOpIdx1 == CommutableOpIdx1) { + } else if (SrcOpIdx1 == CommuteAnyOperandIndex) { // Only one of the operands is not fixed. CommutableOpIdx1 = SrcOpIdx2; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -157,7 +157,7 @@ void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB, MachineMemOperand *MMO); unsigned maskI1Value(unsigned Reg, const Value *V); - unsigned getRegForI1Value(const Value *V, bool &Not); + unsigned getRegForI1Value(const Value *V, const BasicBlock *BB, bool &Not); unsigned zeroExtendToI32(unsigned Reg, const Value *V, MVT::SimpleValueType From); unsigned signExtendToI32(unsigned Reg, const Value *V, @@ -418,20 +418,17 @@ return zeroExtendToI32(Reg, V, MVT::i1); } -unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) { +unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, + const BasicBlock *BB, + bool &Not) { if (const auto *ICmp = dyn_cast(V)) if (const ConstantInt *C = dyn_cast(ICmp->getOperand(1))) - if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) { + if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) && + ICmp->getParent() == BB) { Not = ICmp->isTrueWhenEqual(); return getRegForValue(ICmp->getOperand(0)); } - Value *NotV; - if (match(V, m_Not(m_Value(NotV))) && V->getType()->isIntegerTy(32)) { - Not = true; - return getRegForValue(NotV); - } - Not = false; unsigned Reg = getRegForValue(V); if (Reg == 0) @@ -912,7 +909,8 @@ const auto *Select = cast(I); bool Not; - unsigned CondReg = getRegForI1Value(Select->getCondition(), Not); + unsigned CondReg = + getRegForI1Value(Select->getCondition(), I->getParent(), Not); if (CondReg == 0) return false; @@ -1312,7 +1310,7 @@ MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)]; bool Not; - unsigned CondReg = getRegForI1Value(Br->getCondition(), Not); + unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not); if (CondReg == 0) return false; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFixBrTableDefaults.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -61,9 +61,13 @@ auto ExtMI = MF.getRegInfo().getVRegDef(MI.getOperand(0).getReg()); if (ExtMI->getOpcode() == WebAssembly::I64_EXTEND_U_I32) { // Unnecessarily extending a 32-bit value to 64, remove it. - assert(MI.getOperand(0).getReg() == ExtMI->getOperand(0).getReg()); + auto ExtDefReg = ExtMI->getOperand(0).getReg(); + assert(MI.getOperand(0).getReg() == ExtDefReg); MI.getOperand(0).setReg(ExtMI->getOperand(1).getReg()); - ExtMI->eraseFromParent(); + if (MF.getRegInfo().use_nodbg_empty(ExtDefReg)) { + // No more users of extend, delete it. + ExtMI->eraseFromParent(); + } } else { // Incoming 64-bit value that needs to be truncated. Register Reg32 = diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/X86/X86FrameLowering.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/X86/X86FrameLowering.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/X86/X86FrameLowering.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/X86/X86FrameLowering.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -671,7 +671,9 @@ MF.insert(MBBIter, testMBB); MF.insert(MBBIter, tailMBB); - Register FinalStackProbed = Uses64BitFramePtr ? X86::R11 : X86::R11D; + Register FinalStackProbed = Uses64BitFramePtr ? X86::R11 + : Is64Bit ? X86::R11D + : X86::EAX; BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::COPY), FinalStackProbed) .addReg(StackPtr) .setMIFlag(MachineInstr::FrameSetup); @@ -1092,7 +1094,9 @@ MF.insert(MBBIter, bodyMBB); MF.insert(MBBIter, footMBB); const unsigned MovMIOpc = Is64Bit ? X86::MOV64mi32 : X86::MOV32mi; - Register FinalStackProbed = Uses64BitFramePtr ? X86::R11 : X86::R11D; + Register FinalStackProbed = Uses64BitFramePtr ? X86::R11 + : Is64Bit ? X86::R11D + : X86::EAX; // Setup entry block { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/X86/X86ISelLowering.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/X86/X86ISelLowering.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/X86/X86ISelLowering.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Target/X86/X86ISelLowering.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -6704,17 +6704,21 @@ if (Op.getOpcode() == X86ISD::SUBV_BROADCAST_LOAD) { auto *MemIntr = cast(Op); SDValue Ptr = MemIntr->getBasePtr(); + // The source constant may be larger than the subvector broadcast, + // ensure we extract the correct subvector constants. if (const Constant *Cst = getTargetConstantFromBasePtr(Ptr)) { Type *CstTy = Cst->getType(); unsigned CstSizeInBits = CstTy->getPrimitiveSizeInBits(); - if (!CstTy->isVectorTy() || (SizeInBits % CstSizeInBits) != 0) + unsigned SubVecSizeInBits = MemIntr->getMemoryVT().getStoreSizeInBits(); + if (!CstTy->isVectorTy() || (CstSizeInBits % SubVecSizeInBits) != 0 || + (SizeInBits % SubVecSizeInBits) != 0) return false; - unsigned SubEltSizeInBits = CstTy->getScalarSizeInBits(); - unsigned NumSubElts = CstSizeInBits / SubEltSizeInBits; - unsigned NumSubVecs = SizeInBits / CstSizeInBits; + unsigned CstEltSizeInBits = CstTy->getScalarSizeInBits(); + unsigned NumSubElts = SubVecSizeInBits / CstEltSizeInBits; + unsigned NumSubVecs = SizeInBits / SubVecSizeInBits; APInt UndefSubElts(NumSubElts, 0); SmallVector SubEltBits(NumSubElts * NumSubVecs, - APInt(SubEltSizeInBits, 0)); + APInt(CstEltSizeInBits, 0)); for (unsigned i = 0; i != NumSubElts; ++i) { if (!CollectConstantBits(Cst->getAggregateElement(i), SubEltBits[i], UndefSubElts, i)) @@ -35819,7 +35823,7 @@ // See if the shuffle is a hidden identity shuffle - repeated args in HOPs // etc. can be simplified. - if (VT1 == VT2 && VT1.getSizeInBits() == RootSizeInBits) { + if (VT1 == VT2 && VT1.getSizeInBits() == RootSizeInBits && VT1.isVector()) { SmallVector ScaledMask, IdentityMask; unsigned NumElts = VT1.getVectorNumElements(); if (BaseMask.size() <= NumElts && diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -5158,6 +5158,83 @@ if (!isa(Op1) && Op1Min == Op1Max) return new ICmpInst(Pred, Op0, ConstantExpr::getIntegerValue(Ty, Op1Min)); + // Don't break up a clamp pattern -- (min(max X, Y), Z) -- by replacing a + // min/max canonical compare with some other compare. That could lead to + // conflict with select canonicalization and infinite looping. + // FIXME: This constraint may go away if min/max intrinsics are canonical. + auto isMinMaxCmp = [&](Instruction &Cmp) { + if (!Cmp.hasOneUse()) + return false; + Value *A, *B; + SelectPatternFlavor SPF = matchSelectPattern(Cmp.user_back(), A, B).Flavor; + if (!SelectPatternResult::isMinOrMax(SPF)) + return false; + return match(Op0, m_MaxOrMin(m_Value(), m_Value())) || + match(Op1, m_MaxOrMin(m_Value(), m_Value())); + }; + if (!isMinMaxCmp(I)) { + switch (Pred) { + default: + break; + case ICmpInst::ICMP_ULT: { + if (Op1Min == Op0Max) // A A != B if max(A) == min(B) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); + const APInt *CmpC; + if (match(Op1, m_APInt(CmpC))) { + // A A == C-1 if min(A)+1 == C + if (*CmpC == Op0Min + 1) + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, + ConstantInt::get(Op1->getType(), *CmpC - 1)); + // X X == 0, if the number of zero bits in the bottom of X + // exceeds the log2 of C. + if (Op0Known.countMinTrailingZeros() >= CmpC->ceilLogBase2()) + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, + Constant::getNullValue(Op1->getType())); + } + break; + } + case ICmpInst::ICMP_UGT: { + if (Op1Max == Op0Min) // A >u B -> A != B if min(A) == max(B) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); + const APInt *CmpC; + if (match(Op1, m_APInt(CmpC))) { + // A >u C -> A == C+1 if max(a)-1 == C + if (*CmpC == Op0Max - 1) + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, + ConstantInt::get(Op1->getType(), *CmpC + 1)); + // X >u C --> X != 0, if the number of zero bits in the bottom of X + // exceeds the log2 of C. + if (Op0Known.countMinTrailingZeros() >= CmpC->getActiveBits()) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, + Constant::getNullValue(Op1->getType())); + } + break; + } + case ICmpInst::ICMP_SLT: { + if (Op1Min == Op0Max) // A A != B if max(A) == min(B) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); + const APInt *CmpC; + if (match(Op1, m_APInt(CmpC))) { + if (*CmpC == Op0Min + 1) // A A == C-1 if min(A)+1 == C + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, + ConstantInt::get(Op1->getType(), *CmpC - 1)); + } + break; + } + case ICmpInst::ICMP_SGT: { + if (Op1Max == Op0Min) // A >s B -> A != B if min(A) == max(B) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); + const APInt *CmpC; + if (match(Op1, m_APInt(CmpC))) { + if (*CmpC == Op0Max - 1) // A >s C -> A == C+1 if max(A)-1 == C + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, + ConstantInt::get(Op1->getType(), *CmpC + 1)); + } + break; + } + } + } + // Based on the range information we know about the LHS, see if we can // simplify this comparison. For example, (x&4) < 8 is always true. switch (Pred) { @@ -5219,21 +5296,6 @@ return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType())); if (Op0Min.uge(Op1Max)) // A false if min(A) >= max(B) return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType())); - if (Op1Min == Op0Max) // A A != B if max(A) == min(B) - return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); - - const APInt *CmpC; - if (match(Op1, m_APInt(CmpC))) { - // A A == C-1 if min(A)+1 == C - if (*CmpC == Op0Min + 1) - return new ICmpInst(ICmpInst::ICMP_EQ, Op0, - ConstantInt::get(Op1->getType(), *CmpC - 1)); - // X X == 0, if the number of zero bits in the bottom of X - // exceeds the log2 of C. - if (Op0Known.countMinTrailingZeros() >= CmpC->ceilLogBase2()) - return new ICmpInst(ICmpInst::ICMP_EQ, Op0, - Constant::getNullValue(Op1->getType())); - } break; } case ICmpInst::ICMP_UGT: { @@ -5241,21 +5303,6 @@ return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType())); if (Op0Max.ule(Op1Min)) // A >u B -> false if max(A) <= max(B) return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType())); - if (Op1Max == Op0Min) // A >u B -> A != B if min(A) == max(B) - return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); - - const APInt *CmpC; - if (match(Op1, m_APInt(CmpC))) { - // A >u C -> A == C+1 if max(a)-1 == C - if (*CmpC == Op0Max - 1) - return new ICmpInst(ICmpInst::ICMP_EQ, Op0, - ConstantInt::get(Op1->getType(), *CmpC + 1)); - // X >u C --> X != 0, if the number of zero bits in the bottom of X - // exceeds the log2 of C. - if (Op0Known.countMinTrailingZeros() >= CmpC->getActiveBits()) - return new ICmpInst(ICmpInst::ICMP_NE, Op0, - Constant::getNullValue(Op1->getType())); - } break; } case ICmpInst::ICMP_SLT: { @@ -5263,14 +5310,6 @@ return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType())); if (Op0Min.sge(Op1Max)) // A false if min(A) >= max(C) return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType())); - if (Op1Min == Op0Max) // A A != B if max(A) == min(B) - return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); - const APInt *CmpC; - if (match(Op1, m_APInt(CmpC))) { - if (*CmpC == Op0Min + 1) // A A == C-1 if min(A)+1 == C - return new ICmpInst(ICmpInst::ICMP_EQ, Op0, - ConstantInt::get(Op1->getType(), *CmpC - 1)); - } break; } case ICmpInst::ICMP_SGT: { @@ -5278,14 +5317,6 @@ return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType())); if (Op0Max.sle(Op1Min)) // A >s B -> false if max(A) <= min(B) return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType())); - if (Op1Max == Op0Min) // A >s B -> A != B if min(A) == max(B) - return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); - const APInt *CmpC; - if (match(Op1, m_APInt(CmpC))) { - if (*CmpC == Op0Max - 1) // A >s C -> A == C+1 if max(A)-1 == C - return new ICmpInst(ICmpInst::ICMP_EQ, Op0, - ConstantInt::get(Op1->getType(), *CmpC + 1)); - } break; } case ICmpInst::ICMP_SGE: diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/Attributor.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/Attributor.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/Attributor.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/Attributor.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -251,10 +251,12 @@ return Constant::getNullValue(&Ty); if (C->getType()->isPointerTy() && Ty.isPointerTy()) return ConstantExpr::getPointerCast(C, &Ty); - if (C->getType()->isIntegerTy() && Ty.isIntegerTy()) - return ConstantExpr::getTrunc(C, &Ty, /* OnlyIfReduced */ true); - if (C->getType()->isFloatingPointTy() && Ty.isFloatingPointTy()) - return ConstantExpr::getFPTrunc(C, &Ty, /* OnlyIfReduced */ true); + if (C->getType()->getPrimitiveSizeInBits() >= Ty.getPrimitiveSizeInBits()) { + if (C->getType()->isIntegerTy() && Ty.isIntegerTy()) + return ConstantExpr::getTrunc(C, &Ty, /* OnlyIfReduced */ true); + if (C->getType()->isFloatingPointTy() && Ty.isFloatingPointTy()) + return ConstantExpr::getFPTrunc(C, &Ty, /* OnlyIfReduced */ true); + } } return nullptr; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1996,7 +1996,8 @@ UndefValue::get(Int8Ty), F->getName() + ".ID"); for (Use *U : ToBeReplacedStateMachineUses) - U->set(ConstantExpr::getBitCast(ID, U->get()->getType())); + U->set(ConstantExpr::getPointerBitCastOrAddrSpaceCast( + ID, U->get()->getType())); ++NumOpenMPParallelRegionsReplacedInGPUStateMachine; @@ -3183,10 +3184,14 @@ IsWorker->setDebugLoc(DLoc); BranchInst::Create(StateMachineBeginBB, UserCodeEntryBB, IsWorker, InitBB); + Module &M = *Kernel->getParent(); + // Create local storage for the work function pointer. + const DataLayout &DL = M.getDataLayout(); Type *VoidPtrTy = Type::getInt8PtrTy(Ctx); - AllocaInst *WorkFnAI = new AllocaInst(VoidPtrTy, 0, "worker.work_fn.addr", - &Kernel->getEntryBlock().front()); + Instruction *WorkFnAI = + new AllocaInst(VoidPtrTy, DL.getAllocaAddrSpace(), nullptr, + "worker.work_fn.addr", &Kernel->getEntryBlock().front()); WorkFnAI->setDebugLoc(DLoc); auto &OMPInfoCache = static_cast(A.getInfoCache()); @@ -3199,13 +3204,23 @@ Value *Ident = KernelInitCB->getArgOperand(0); Value *GTid = KernelInitCB; - Module &M = *Kernel->getParent(); FunctionCallee BarrierFn = OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction( M, OMPRTL___kmpc_barrier_simple_spmd); CallInst::Create(BarrierFn, {Ident, GTid}, "", StateMachineBeginBB) ->setDebugLoc(DLoc); + if (WorkFnAI->getType()->getPointerAddressSpace() != + (unsigned int)AddressSpace::Generic) { + WorkFnAI = new AddrSpaceCastInst( + WorkFnAI, + PointerType::getWithSamePointeeType( + cast(WorkFnAI->getType()), + (unsigned int)AddressSpace::Generic), + WorkFnAI->getName() + ".generic", StateMachineBeginBB); + WorkFnAI->setDebugLoc(DLoc); + } + FunctionCallee KernelParallelFn = OMPInfoCache.OMPBuilder.getOrCreateRuntimeFunction( M, OMPRTL___kmpc_kernel_parallel); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -33,6 +33,19 @@ namespace { +// Determine if a promotion alias should be created for a symbol name. +static bool allowPromotionAlias(const std::string &Name) { + // Promotion aliases are used only in inline assembly. It's safe to + // simply skip unusual names. Subset of MCAsmInfo::isAcceptableChar() + // and MCAsmInfoXCOFF::isAcceptableChar(). + for (const char &C : Name) { + if (isAlnum(C) || C == '_' || C == '.') + continue; + return false; + } + return true; +} + // Promote each local-linkage entity defined by ExportM and used by ImportM by // changing visibility and appending the given ModuleId. void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId, @@ -55,6 +68,7 @@ } } + std::string OldName = Name.str(); std::string NewName = (Name + ModuleId).str(); if (const auto *C = ExportGV.getComdat()) @@ -69,6 +83,13 @@ ImportGV->setName(NewName); ImportGV->setVisibility(GlobalValue::HiddenVisibility); } + + if (isa(&ExportGV) && allowPromotionAlias(OldName)) { + // Create a local alias with the original name to avoid breaking + // references from inline assembly. + std::string Alias = ".set " + OldName + "," + NewName + "\n"; + ExportM.appendModuleInlineAsm(Alias); + } } if (!RenamedComdats.empty()) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -221,6 +221,10 @@ AAPtr = AAPtr->stripPointerCastsSameRepresentation(); AlignSCEV = SE->getSCEV(AlignOB.Inputs[1].get()); AlignSCEV = SE->getTruncateOrZeroExtend(AlignSCEV, Int64Ty); + if (!isa(AlignSCEV)) + // Added to suppress a crash because consumer doesn't expect non-constant + // alignments in the assume bundle. TODO: Consider generalizing caller. + return false; if (AlignOB.Inputs.size() == 3) OffSCEV = SE->getSCEV(AlignOB.Inputs[2].get()); else diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1247,6 +1247,11 @@ mayLoopAccessLocation(StoreBasePtr, ModRefInfo::ModRef, CurLoop, BECount, StoreSize, *AA, Stores); if (UseMemMove) { + // For memmove case it's not enough to guarantee that loop doesn't access + // TheStore and TheLoad. Additionally we need to make sure that TheStore is + // the only user of TheLoad. + if (!TheLoad->hasOneUse()) + return Changed; Stores.insert(TheLoad); if (mayLoopAccessLocation(StoreBasePtr, ModRefInfo::ModRef, CurLoop, BECount, StoreSize, *AA, Stores)) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -178,9 +178,9 @@ } void addStore(int64_t OffsetFromFirst, StoreInst *SI) { - int64_t StoreSize = DL.getTypeStoreSize(SI->getOperand(0)->getType()); - - addRange(OffsetFromFirst, StoreSize, SI->getPointerOperand(), + TypeSize StoreSize = DL.getTypeStoreSize(SI->getOperand(0)->getType()); + assert(!StoreSize.isScalable() && "Can't track scalable-typed stores"); + addRange(OffsetFromFirst, StoreSize.getFixedSize(), SI->getPointerOperand(), SI->getAlign().value(), SI); } @@ -371,6 +371,11 @@ Value *ByteVal) { const DataLayout &DL = StartInst->getModule()->getDataLayout(); + // We can't track scalable types + if (StoreInst *SI = dyn_cast(StartInst)) + if (DL.getTypeStoreSize(SI->getOperand(0)->getType()).isScalable()) + return nullptr; + // Okay, so we now have a single store that can be splatable. Scan to find // all subsequent stores of the same value to offset from the same pointer. // Join these together into ranges, so we can decide whether contiguous blocks @@ -426,6 +431,10 @@ if (DL.isNonIntegralPointerType(StoredVal->getType()->getScalarType())) break; + // We can't track ranges involving scalable types. + if (DL.getTypeStoreSize(StoredVal->getType()).isScalable()) + break; + // Check to see if this stored value is of the same byte-splattable value. Value *StoredByte = isBytewiseValue(StoredVal, DL); if (isa(ByteVal) && StoredByte) @@ -859,7 +868,7 @@ /// the call write its result directly into the destination of the memcpy. bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad, Instruction *cpyStore, Value *cpyDest, - Value *cpySrc, uint64_t cpyLen, + Value *cpySrc, TypeSize cpySize, Align cpyAlign, CallInst *C) { // The general transformation to keep in mind is // @@ -875,6 +884,10 @@ // src only holds uninitialized values at the moment of the call, meaning that // the memcpy can be discarded rather than moved. + // We can't optimize scalable types. + if (cpySize.isScalable()) + return false; + // Lifetime marks shouldn't be operated on. if (Function *F = C->getCalledFunction()) if (F->isIntrinsic() && F->getIntrinsicID() == Intrinsic::lifetime_start) @@ -893,13 +906,13 @@ uint64_t srcSize = DL.getTypeAllocSize(srcAlloca->getAllocatedType()) * srcArraySize->getZExtValue(); - if (cpyLen < srcSize) + if (cpySize < srcSize) return false; // Check that accessing the first srcSize bytes of dest will not cause a // trap. Otherwise the transform is invalid since it might cause a trap // to occur earlier than it otherwise would. - if (!isDereferenceableAndAlignedPointer(cpyDest, Align(1), APInt(64, cpyLen), + if (!isDereferenceableAndAlignedPointer(cpyDest, Align(1), APInt(64, cpySize), DL, C, DT)) return false; @@ -1452,9 +1465,10 @@ // of conservatively taking the minimum? Align Alignment = std::min(M->getDestAlign().valueOrOne(), M->getSourceAlign().valueOrOne()); - if (performCallSlotOptzn(M, M, M->getDest(), M->getSource(), - CopySize->getZExtValue(), Alignment, - C)) { + if (performCallSlotOptzn( + M, M, M->getDest(), M->getSource(), + TypeSize::getFixed(CopySize->getZExtValue()), Alignment, + C)) { LLVM_DEBUG(dbgs() << "Performed call slot optimization:\n" << " call: " << *C << "\n" << " memcpy: " << *M << "\n"); @@ -1509,7 +1523,8 @@ Align Alignment = std::min(M->getDestAlign().valueOrOne(), M->getSourceAlign().valueOrOne()); if (performCallSlotOptzn(M, M, M->getDest(), M->getSource(), - CopySize->getZExtValue(), Alignment, C)) { + TypeSize::getFixed(CopySize->getZExtValue()), + Alignment, C)) { eraseInstruction(M); ++NumMemCpyInstr; return true; @@ -1584,7 +1599,7 @@ // Find out what feeds this byval argument. Value *ByValArg = CB.getArgOperand(ArgNo); Type *ByValTy = CB.getParamByValType(ArgNo); - uint64_t ByValSize = DL.getTypeAllocSize(ByValTy); + TypeSize ByValSize = DL.getTypeAllocSize(ByValTy); MemoryLocation Loc(ByValArg, LocationSize::precise(ByValSize)); MemCpyInst *MDep = nullptr; if (EnableMemorySSA) { @@ -1612,7 +1627,8 @@ // The length of the memcpy must be larger or equal to the size of the byval. ConstantInt *C1 = dyn_cast(MDep->getLength()); - if (!C1 || C1->getValue().getZExtValue() < ByValSize) + if (!C1 || !TypeSize::isKnownGE( + TypeSize::getFixed(C1->getValue().getZExtValue()), ByValSize)) return false; // Get the alignment of the byval. If the call doesn't specify the alignment, diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1587,10 +1587,12 @@ BB->eraseFromParent(); } -static void deleteDeadBlocksFromLoop(Loop &L, - SmallVectorImpl &ExitBlocks, - DominatorTree &DT, LoopInfo &LI, - MemorySSAUpdater *MSSAU) { +static void +deleteDeadBlocksFromLoop(Loop &L, + SmallVectorImpl &ExitBlocks, + DominatorTree &DT, LoopInfo &LI, + MemorySSAUpdater *MSSAU, + function_ref DestroyLoopCB) { // Find all the dead blocks tied to this loop, and remove them from their // successors. SmallSetVector DeadBlockSet; @@ -1640,6 +1642,7 @@ }) && "If the child loop header is dead all blocks in the child loop must " "be dead as well!"); + DestroyLoopCB(*ChildL, ChildL->getName()); LI.destroy(ChildL); return true; }); @@ -1980,6 +1983,8 @@ ParentL->removeChildLoop(llvm::find(*ParentL, &L)); else LI.removeLoop(llvm::find(LI, &L)); + // markLoopAsDeleted for L should be triggered by the caller (it is typically + // done by using the UnswitchCB callback). LI.destroy(&L); return false; } @@ -2019,7 +2024,8 @@ SmallVectorImpl &ExitBlocks, IVConditionInfo &PartialIVInfo, DominatorTree &DT, LoopInfo &LI, AssumptionCache &AC, function_ref)> UnswitchCB, - ScalarEvolution *SE, MemorySSAUpdater *MSSAU) { + ScalarEvolution *SE, MemorySSAUpdater *MSSAU, + function_ref DestroyLoopCB) { auto *ParentBB = TI.getParent(); BranchInst *BI = dyn_cast(&TI); SwitchInst *SI = BI ? nullptr : cast(&TI); @@ -2319,7 +2325,7 @@ // Now that our cloned loops have been built, we can update the original loop. // First we delete the dead blocks from it and then we rebuild the loop // structure taking these deletions into account. - deleteDeadBlocksFromLoop(L, ExitBlocks, DT, LI, MSSAU); + deleteDeadBlocksFromLoop(L, ExitBlocks, DT, LI, MSSAU, DestroyLoopCB); if (MSSAU && VerifyMemorySSA) MSSAU->getMemorySSA()->verifyMemorySSA(); @@ -2670,7 +2676,8 @@ Loop &L, DominatorTree &DT, LoopInfo &LI, AssumptionCache &AC, AAResults &AA, TargetTransformInfo &TTI, function_ref)> UnswitchCB, - ScalarEvolution *SE, MemorySSAUpdater *MSSAU) { + ScalarEvolution *SE, MemorySSAUpdater *MSSAU, + function_ref DestroyLoopCB) { // Collect all invariant conditions within this loop (as opposed to an inner // loop which would be handled when visiting that inner loop). SmallVector>, 4> @@ -2958,7 +2965,7 @@ << "\n"); unswitchNontrivialInvariants(L, *BestUnswitchTI, BestUnswitchInvariants, ExitBlocks, PartialIVInfo, DT, LI, AC, - UnswitchCB, SE, MSSAU); + UnswitchCB, SE, MSSAU, DestroyLoopCB); return true; } @@ -2988,7 +2995,8 @@ AAResults &AA, TargetTransformInfo &TTI, bool Trivial, bool NonTrivial, function_ref)> UnswitchCB, - ScalarEvolution *SE, MemorySSAUpdater *MSSAU) { + ScalarEvolution *SE, MemorySSAUpdater *MSSAU, + function_ref DestroyLoopCB) { assert(L.isRecursivelyLCSSAForm(DT, LI) && "Loops must be in LCSSA form before unswitching."); @@ -3036,7 +3044,8 @@ // Try to unswitch the best invariant condition. We prefer this full unswitch to // a partial unswitch when possible below the threshold. - if (unswitchBestCondition(L, DT, LI, AC, AA, TTI, UnswitchCB, SE, MSSAU)) + if (unswitchBestCondition(L, DT, LI, AC, AA, TTI, UnswitchCB, SE, MSSAU, + DestroyLoopCB)) return true; // No other opportunities to unswitch. @@ -3083,6 +3092,10 @@ U.markLoopAsDeleted(L, LoopName); }; + auto DestroyLoopCB = [&U](Loop &L, StringRef Name) { + U.markLoopAsDeleted(L, Name); + }; + Optional MSSAU; if (AR.MSSA) { MSSAU = MemorySSAUpdater(AR.MSSA); @@ -3091,7 +3104,8 @@ } if (!unswitchLoop(L, AR.DT, AR.LI, AR.AC, AR.AA, AR.TTI, Trivial, NonTrivial, UnswitchCB, &AR.SE, - MSSAU.hasValue() ? MSSAU.getPointer() : nullptr)) + MSSAU.hasValue() ? MSSAU.getPointer() : nullptr, + DestroyLoopCB)) return PreservedAnalyses::all(); if (AR.MSSA && VerifyMemorySSA) @@ -3179,12 +3193,17 @@ LPM.markLoopAsDeleted(*L); }; + auto DestroyLoopCB = [&LPM](Loop &L, StringRef /* Name */) { + LPM.markLoopAsDeleted(L); + }; + if (MSSA && VerifyMemorySSA) MSSA->verifyMemorySSA(); bool Changed = unswitchLoop(*L, DT, LI, AC, AA, TTI, true, NonTrivial, UnswitchCB, SE, - MSSAU.hasValue() ? MSSAU.getPointer() : nullptr); + MSSAU.hasValue() ? MSSAU.getPointer() : nullptr, + DestroyLoopCB); if (MSSA && VerifyMemorySSA) MSSA->verifyMemorySSA(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Utils/SimplifyCFG.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Utils/SimplifyCFG.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Utils/SimplifyCFG.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1094,17 +1094,24 @@ // Update (liveout) uses of bonus instructions, // now that the bonus instruction has been cloned into predecessor. - SSAUpdater SSAUpdate; - SSAUpdate.Initialize(BonusInst.getType(), - (NewBonusInst->getName() + ".merge").str()); - SSAUpdate.AddAvailableValue(BB, &BonusInst); - SSAUpdate.AddAvailableValue(PredBlock, NewBonusInst); + // Note that we expect to be in a block-closed SSA form for this to work! for (Use &U : make_early_inc_range(BonusInst.uses())) { auto *UI = cast(U.getUser()); - if (UI->getParent() != PredBlock) - SSAUpdate.RewriteUseAfterInsertions(U); - else // Use is in the same block as, and comes before, NewBonusInst. - SSAUpdate.RewriteUse(U); + auto *PN = dyn_cast(UI); + if (!PN) { + assert(UI->getParent() == BB && BonusInst.comesBefore(UI) && + "If the user is not a PHI node, then it should be in the same " + "block as, and come after, the original bonus instruction."); + continue; // Keep using the original bonus instruction. + } + // Is this the block-closed SSA form PHI node? + if (PN->getIncomingBlock(U) == BB) + continue; // Great, keep using the original bonus instruction. + // The only other alternative is an "use" when coming from + // the predecessor block - here we should refer to the cloned bonus instr. + assert(PN->getIncomingBlock(U) == PredBlock && + "Not in block-closed SSA form?"); + U.set(NewBonusInst); } } } @@ -3207,6 +3214,17 @@ // Early exits once we reach the limit. if (NumBonusInsts > BonusInstThreshold) return false; + + auto IsBCSSAUse = [BB, &I](Use &U) { + auto *UI = cast(U.getUser()); + if (auto *PN = dyn_cast(UI)) + return PN->getIncomingBlock(U) == BB; + return UI->getParent() == BB && I.comesBefore(UI); + }; + + // Does this instruction require rewriting of uses? + if (!all_of(I.uses(), IsBCSSAUse)) + return false; } // Ok, we have the budget. Perform the transformation. diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -5433,6 +5433,21 @@ // lane 0 demanded or b) are uses which demand only lane 0 of their operand. for (auto *BB : TheLoop->blocks()) for (auto &I : *BB) { + if (IntrinsicInst *II = dyn_cast(&I)) { + switch (II->getIntrinsicID()) { + case Intrinsic::sideeffect: + case Intrinsic::experimental_noalias_scope_decl: + case Intrinsic::assume: + case Intrinsic::lifetime_start: + case Intrinsic::lifetime_end: + if (TheLoop->hasLoopInvariantOperands(&I)) + addToWorklistIfAllowed(&I); + break; + default: + break; + } + } + // If there's no pointer operand, there's nothing to do. auto *Ptr = getLoadStorePointerOperand(&I); if (!Ptr) @@ -8916,6 +8931,37 @@ bool IsPredicated = LoopVectorizationPlanner::getDecisionAndClampRange( [&](ElementCount VF) { return CM.isPredicatedInst(I); }, Range); + // Even if the instruction is not marked as uniform, there are certain + // intrinsic calls that can be effectively treated as such, so we check for + // them here. Conservatively, we only do this for scalable vectors, since + // for fixed-width VFs we can always fall back on full scalarization. + if (!IsUniform && Range.Start.isScalable() && isa(I)) { + switch (cast(I)->getIntrinsicID()) { + case Intrinsic::assume: + case Intrinsic::lifetime_start: + case Intrinsic::lifetime_end: + // For scalable vectors if one of the operands is variant then we still + // want to mark as uniform, which will generate one instruction for just + // the first lane of the vector. We can't scalarize the call in the same + // way as for fixed-width vectors because we don't know how many lanes + // there are. + // + // The reasons for doing it this way for scalable vectors are: + // 1. For the assume intrinsic generating the instruction for the first + // lane is still be better than not generating any at all. For + // example, the input may be a splat across all lanes. + // 2. For the lifetime start/end intrinsics the pointer operand only + // does anything useful when the input comes from a stack object, + // which suggests it should always be uniform. For non-stack objects + // the effect is to poison the object, which still allows us to + // remove the call. + IsUniform = true; + break; + default: + break; + } + } + auto *Recipe = new VPReplicateRecipe(I, Plan->mapToVPValues(I->operands()), IsUniform, IsPredicated); setRecipe(I, Recipe); diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -234,12 +234,15 @@ for (VPRecipeBase &Phi1ToMove : make_early_inc_range(reverse(*Merge1))) { VPValue *PredInst1 = cast(&Phi1ToMove)->getOperand(0); - for (VPUser *U : Phi1ToMove.getVPSingleValue()->users()) { + VPValue *Phi1ToMoveV = Phi1ToMove.getVPSingleValue(); + SmallVector Users(Phi1ToMoveV->user_begin(), + Phi1ToMoveV->user_end()); + for (VPUser *U : Users) { auto *UI = dyn_cast(U); if (!UI || UI->getParent() != Then2) continue; for (unsigned I = 0, E = U->getNumOperands(); I != E; ++I) { - if (Phi1ToMove.getVPSingleValue() != U->getOperand(I)) + if (Phi1ToMoveV != U->getOperand(I)) continue; U->setOperand(I, PredInst1); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/runtimes/CMakeLists.txt rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/runtimes/CMakeLists.txt --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/runtimes/CMakeLists.txt 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/runtimes/CMakeLists.txt 2021-11-16 16:47:26.000000000 +0000 @@ -350,15 +350,24 @@ # Create a runtimes target that uses this file as its top-level CMake file. # The runtimes target is a configuration of all the runtime libraries # together in a single CMake invocaiton. + set(extra_deps "") + if("openmp" IN_LIST LLVM_ENABLE_RUNTIMES) + if(TARGET opt) + list(APPEND extra_deps opt) + endif() + if(TARGET llvm-link) + list(APPEND extra_deps llvm-link) + endif() + endif() if(NOT LLVM_RUNTIME_TARGETS) runtime_default_target( - DEPENDS ${deps} + DEPENDS ${deps} ${extra_deps} PREFIXES ${prefixes}) set(test_targets check-runtimes) else() if("default" IN_LIST LLVM_RUNTIME_TARGETS) runtime_default_target( - DEPENDS ${deps} + DEPENDS ${deps} ${extra_deps} PREFIXES ${prefixes}) list(REMOVE_ITEM LLVM_RUNTIME_TARGETS "default") else() diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/legalize-bswap.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/legalize-bswap.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/legalize-bswap.mir 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/legalize-bswap.mir 2021-11-16 16:47:26.000000000 +0000 @@ -8,8 +8,6 @@ define i16 @bswap_s16(i16 %a) { ret i16 0 } - define <2 x i16> @bswap_2xi16(<2 x i16> %a) { ret <2 x i16> } - attributes #0 = { nounwind readnone speculatable willreturn } ... @@ -44,40 +42,3 @@ RET_ReallyLR implicit $w0 ... ---- -name: bswap_2xi16 -alignment: 4 -tracksRegLiveness: true -registers: - - { id: 0, class: _ } - - { id: 1, class: _ } -liveins: - - { reg: '$s0' } -frameInfo: - maxAlignment: 1 -machineFunctionInfo: {} -body: | - bb.1: - liveins: $s0 - - ; CHECK-LABEL: name: bswap_2xi16 - ; CHECK: liveins: $s0 - ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s16>) = COPY $s0 - ; CHECK: [[DEF:%[0-9]+]]:_(<8 x s8>) = G_IMPLICIT_DEF - ; CHECK: [[INSERT_SUBREG:%[0-9]+]]:_(<8 x s8>) = INSERT_SUBREG [[DEF]](<8 x s8>), [[COPY]](<2 x s16>), %subreg.ssub - ; CHECK: [[REV32_:%[0-9]+]]:_(<8 x s8>) = G_REV32 [[INSERT_SUBREG]] - ; CHECK: [[BITCAST:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[REV32_]](<8 x s8>) - ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 - ; CHECK: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32) - ; CHECK: [[LSHR:%[0-9]+]]:_(<2 x s32>) = G_LSHR [[BITCAST]], [[BUILD_VECTOR]](<2 x s32>) - ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 0 - ; CHECK: [[EVEC:%[0-9]+]]:_(s32) = G_EXTRACT_VECTOR_ELT [[LSHR]](<2 x s32>), [[C1]](s64) - ; CHECK: [[BITCAST1:%[0-9]+]]:_(<2 x s16>) = G_BITCAST [[EVEC]](s32) - ; CHECK: $s0 = COPY [[BITCAST1]](<2 x s16>) - ; CHECK: RET_ReallyLR - %0:_(<2 x s16>) = COPY $s0 - %1:_(<2 x s16>) = G_BSWAP %0 - $s0 = COPY %1(<2 x s16>) - RET_ReallyLR - -... diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir 2021-11-16 16:47:26.000000000 +0000 @@ -555,8 +555,8 @@ # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: G_BSWAP (opcode {{[0-9]+}}): 1 type index, 0 imm indices -# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected -# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected +# DEBUG-NEXT: .. the first uncovered type index: 1, OK +# DEBUG-NEXT: .. the first uncovered imm index: 0, OK # DEBUG-NEXT: G_BITREVERSE (opcode {{[0-9]+}}): 1 type index, 0 imm indices # DEBUG-NEXT: .. the first uncovered type index: 1, OK # DEBUG-NEXT: .. the first uncovered imm index: 0, OK diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/opt-fold-xor-tbz-tbnz.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/opt-fold-xor-tbz-tbnz.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/opt-fold-xor-tbz-tbnz.mir 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/opt-fold-xor-tbz-tbnz.mir 2021-11-16 16:47:26.000000000 +0000 @@ -117,6 +117,38 @@ RET_ReallyLR ... --- +name: dont_flip_eq_zext +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: dont_flip_eq_zext + ; CHECK: bb.0: + ; CHECK: successors: %bb.0(0x40000000), %bb.1(0x40000000) + ; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $wzr + ; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64all = SUBREG_TO_REG 0, [[COPY]], %subreg.sub_32 + ; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY [[SUBREG_TO_REG]] + ; CHECK: TBNZX [[COPY1]], 63, %bb.1 + ; CHECK: B %bb.0 + ; CHECK: bb.1: + ; CHECK: RET_ReallyLR + bb.0: + successors: %bb.0(0x40000000), %bb.1(0x40000000) + + %1:gpr(s32) = G_CONSTANT i32 0 + %3:gpr(s32) = G_CONSTANT i32 -1 + %4:gpr(s32) = G_XOR %1, %3 + %5:gpr(s64) = G_ZEXT %4(s32) + %15:gpr(s64) = G_CONSTANT i64 0 + %13:gpr(s32) = G_ICMP intpred(slt), %5(s64), %15 + %7:gpr(s1) = G_TRUNC %13(s32) + G_BRCOND %7(s1), %bb.1 + G_BR %bb.0 + bb.1: + RET_ReallyLR +... +--- name: dont_flip_ne alignment: 4 legalized: true diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/rbs-matrixindex-regclass-crash.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/rbs-matrixindex-regclass-crash.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/rbs-matrixindex-regclass-crash.mir 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/rbs-matrixindex-regclass-crash.mir 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,56 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple=aarch64 -run-pass=regbankselect -verify-machineinstrs %s -o - | FileCheck %s + +# Check we don't crash because of an unhandled new regclass GPR64_with_sub_32_in_MatrixIndexGPR32_12_15RegClassID. +--- +name: foo +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1: + ; CHECK-LABEL: name: foo + ; CHECK: [[DEF:%[0-9]+]]:gpr(s64) = G_IMPLICIT_DEF + ; CHECK-NEXT: $x0 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x1 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x2 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x3 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x4 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x5 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x6 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x7 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x8 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x9 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x10 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x11 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x12 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x13 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x14 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x15 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x16 = COPY [[DEF]](s64) + ; CHECK-NEXT: $x17 = COPY [[DEF]](s64) + ; CHECK-NEXT: INLINEASM &"svc 0", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x0, 10 /* regdef */, implicit-def $x1, 10 /* regdef */, implicit-def $x2, 10 /* regdef */, implicit-def $x3, 10 /* regdef */, implicit-def $x4, 10 /* regdef */, implicit-def $x5, 10 /* regdef */, implicit-def $x6, 10 /* regdef */, implicit-def $x7, 10 /* regdef */, implicit-def $x8, 10 /* regdef */, implicit-def $x9, 10 /* regdef */, implicit-def $x10, 10 /* regdef */, implicit-def $x11, 10 /* regdef */, implicit-def $x12, 10 /* regdef */, implicit-def $x13, 10 /* regdef */, implicit-def $x14, 10 /* regdef */, implicit-def $x15, 10 /* regdef */, implicit-def $x16, 10 /* regdef */, implicit-def $x17, 9 /* reguse */, $x0, 9 /* reguse */, $x1, 9 /* reguse */, $x2, 9 /* reguse */, $x3, 9 /* reguse */, $x4, 9 /* reguse */, $x5, 9 /* reguse */, $x6, 9 /* reguse */, $x7, 9 /* reguse */, $x8, 9 /* reguse */, $x9, 9 /* reguse */, $x10, 9 /* reguse */, $x11, 9 /* reguse */, $x12, 9 /* reguse */, $x13, 9 /* reguse */, $x14, 9 /* reguse */, $x15, 9 /* reguse */, $x16, 9 /* reguse */, $x17 + ; CHECK-NEXT: RET_ReallyLR + %0:_(s64) = G_IMPLICIT_DEF + $x0 = COPY %0(s64) + $x1 = COPY %0(s64) + $x2 = COPY %0(s64) + $x3 = COPY %0(s64) + $x4 = COPY %0(s64) + $x5 = COPY %0(s64) + $x6 = COPY %0(s64) + $x7 = COPY %0(s64) + $x8 = COPY %0(s64) + $x9 = COPY %0(s64) + $x10 = COPY %0(s64) + $x11 = COPY %0(s64) + $x12 = COPY %0(s64) + $x13 = COPY %0(s64) + $x14 = COPY %0(s64) + $x15 = COPY %0(s64) + $x16 = COPY %0(s64) + $x17 = COPY %0(s64) + INLINEASM &"svc 0", 1 /* sideeffect attdialect */, 10 /* regdef */, implicit-def $x0, 10 /* regdef */, implicit-def $x1, 10 /* regdef */, implicit-def $x2, 10 /* regdef */, implicit-def $x3, 10 /* regdef */, implicit-def $x4, 10 /* regdef */, implicit-def $x5, 10 /* regdef */, implicit-def $x6, 10 /* regdef */, implicit-def $x7, 10 /* regdef */, implicit-def $x8, 10 /* regdef */, implicit-def $x9, 10 /* regdef */, implicit-def $x10, 10 /* regdef */, implicit-def $x11, 10 /* regdef */, implicit-def $x12, 10 /* regdef */, implicit-def $x13, 10 /* regdef */, implicit-def $x14, 10 /* regdef */, implicit-def $x15, 10 /* regdef */, implicit-def $x16, 10 /* regdef */, implicit-def $x17, 9 /* reguse */, $x0, 9 /* reguse */, $x1, 9 /* reguse */, $x2, 9 /* reguse */, $x3, 9 /* reguse */, $x4, 9 /* reguse */, $x5, 9 /* reguse */, $x6, 9 /* reguse */, $x7, 9 /* reguse */, $x8, 9 /* reguse */, $x9, 9 /* reguse */, $x10, 9 /* reguse */, $x11, 9 /* reguse */, $x12, 9 /* reguse */, $x13, 9 /* reguse */, $x14, 9 /* reguse */, $x15, 9 /* reguse */, $x16, 9 /* reguse */, $x17 + RET_ReallyLR + +... diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/ARM/cmpxchg.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/ARM/cmpxchg.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/ARM/cmpxchg.mir 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/ARM/cmpxchg.mir 2021-11-16 16:47:26.000000000 +0000 @@ -1,5 +1,6 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -o - %s -mtriple=armv7-unknown-linux-gnu -verify-machineinstrs -run-pass=arm-pseudo | FileCheck %s +# RUN: llc -o - %s -mtriple=thumbv7-unknown-linux-gnu -verify-machineinstrs -run-pass=arm-pseudo | FileCheck %s --check-prefix=THUMB --- name: func tracksRegLiveness: true @@ -23,5 +24,62 @@ ; CHECK: CMPri killed $r2, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr ; CHECK: Bcc %bb.1, 1 /* CC::ne */, killed $cpsr ; CHECK: .3: + ; THUMB-LABEL: name: func + ; THUMB: successors: %bb.1(0x80000000) + ; THUMB: liveins: $r0_r1, $r4_r5, $r3, $lr + ; THUMB: .1: + ; THUMB: successors: %bb.3(0x40000000), %bb.2(0x40000000) + ; THUMB: liveins: $r4, $r5, $r3 + ; THUMB: $r0, $r1 = t2LDREXD $r3, 14 /* CC::al */, $noreg + ; THUMB: tCMPhir killed $r0, $r4, 14 /* CC::al */, $noreg, implicit-def $cpsr + ; THUMB: tCMPhir killed $r1, $r5, 0 /* CC::eq */, killed $cpsr, implicit-def $cpsr + ; THUMB: tBcc %bb.3, 1 /* CC::ne */, killed $cpsr + ; THUMB: .2: + ; THUMB: successors: %bb.1(0x40000000), %bb.3(0x40000000) + ; THUMB: liveins: $r4, $r5, $r3 + ; THUMB: early-clobber $r2 = t2STREXD $r4, $r5, $r3, 14 /* CC::al */, $noreg + ; THUMB: t2CMPri killed $r2, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr + ; THUMB: tBcc %bb.1, 1 /* CC::ne */, killed $cpsr + ; THUMB: .3: dead early-clobber renamable $r0_r1, dead early-clobber renamable $r2 = CMP_SWAP_64 killed renamable $r3, killed renamable $r4_r5, renamable $r4_r5 :: (volatile load store monotonic monotonic (s64)) ... +--- +name: func2 +tracksRegLiveness: true +body: | + bb.0: + liveins: $r1, $r2, $r3, $r12, $lr + ; CHECK-LABEL: name: func2 + ; CHECK: successors: %bb.1(0x80000000) + ; CHECK: liveins: $r1, $r2, $r3, $r12, $lr + ; CHECK: .1: + ; CHECK: successors: %bb.3(0x40000000), %bb.2(0x40000000) + ; CHECK: liveins: $lr, $r3, $r12 + ; CHECK: $r1 = LDREX $r3, 14 /* CC::al */, $noreg + ; CHECK: CMPrr killed $r1, $r12, 14 /* CC::al */, $noreg, implicit-def $cpsr + ; CHECK: Bcc %bb.3, 1 /* CC::ne */, killed $cpsr + ; CHECK: .2: + ; CHECK: successors: %bb.1(0x40000000), %bb.3(0x40000000) + ; CHECK: liveins: $lr, $r3, $r12 + ; CHECK: early-clobber $r2 = STREX $lr, $r3, 14 /* CC::al */, $noreg + ; CHECK: CMPri killed $r2, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr + ; CHECK: Bcc %bb.1, 1 /* CC::ne */, killed $cpsr + ; CHECK: .3: + ; THUMB-LABEL: name: func2 + ; THUMB: successors: %bb.1(0x80000000) + ; THUMB: liveins: $r1, $r2, $r3, $r12, $lr + ; THUMB: .1: + ; THUMB: successors: %bb.3(0x40000000), %bb.2(0x40000000) + ; THUMB: liveins: $lr, $r3, $r12 + ; THUMB: $r1 = t2LDREX $r3, 0, 14 /* CC::al */, $noreg + ; THUMB: tCMPhir killed $r1, $r12, 14 /* CC::al */, $noreg, implicit-def $cpsr + ; THUMB: tBcc %bb.3, 1 /* CC::ne */, killed $cpsr + ; THUMB: .2: + ; THUMB: successors: %bb.1(0x40000000), %bb.3(0x40000000) + ; THUMB: liveins: $lr, $r3, $r12 + ; THUMB: early-clobber $r2 = t2STREX $lr, $r3, 0, 14 /* CC::al */, $noreg + ; THUMB: t2CMPri killed $r2, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr + ; THUMB: tBcc %bb.1, 1 /* CC::ne */, killed $cpsr + ; THUMB: .3: + dead early-clobber renamable $r1, dead early-clobber renamable $r2 = CMP_SWAP_32 killed renamable $r3, killed renamable $r12, killed renamable $lr +... diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/RISCV/rvv/commuted-op-indices-regression.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/RISCV/rvv/commuted-op-indices-regression.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/RISCV/rvv/commuted-op-indices-regression.mir 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/CodeGen/RISCV/rvv/commuted-op-indices-regression.mir 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,45 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -march=riscv64 -mattr=+experimental-v -run-pass=simple-register-coalescing %s -o - 2>&1 | FileCheck %s + +# This test used to crash in the register coalescer when the target would +# return the out-of-bounds CommuteAnyOperandIndex for one of its commutable +# operand indices. + +--- | + target triple = "riscv64" + target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128" + + define void @commuted_op_indices() { + unreachable + } +... +--- +name: commuted_op_indices +tracksRegLiveness: true +registers: + - { id: 0, class: vr, preferred-register: '' } + - { id: 1, class: vrnov0, preferred-register: '' } + - { id: 2, class: vrnov0, preferred-register: '' } + - { id: 3, class: vr, preferred-register: '' } +body: | + bb.0: + liveins: $v0, $v1, $v2 + ; CHECK-LABEL: name: commuted_op_indices + ; CHECK: liveins: $v0, $v1, $v2 + ; CHECK: [[COPY:%[0-9]+]]:vr = COPY $v0 + ; CHECK: [[COPY1:%[0-9]+]]:vrnov0 = COPY $v1 + ; CHECK: [[COPY2:%[0-9]+]]:vrnov0 = COPY $v2 + ; CHECK: [[PseudoVNMSUB_VV_M1_COMMUTABLE:%[0-9]+]]:vr = PseudoVNMSUB_VV_M1_COMMUTABLE [[PseudoVNMSUB_VV_M1_COMMUTABLE]], [[COPY1]], [[COPY2]], $x0, 6, implicit $vl, implicit $vtype + ; CHECK: [[COPY2:%[0-9]+]]:vr = COPY [[PseudoVNMSUB_VV_M1_COMMUTABLE]] + ; CHECK: dead [[COPY2]]:vr = PseudoVSLL_VI_M1 [[COPY2]], 11, $noreg, 6, implicit $vl, implicit $vtype + ; CHECK: $v0 = COPY [[PseudoVNMSUB_VV_M1_COMMUTABLE]] + ; CHECK: PseudoRET implicit $v0 + %0:vr = COPY $v0 + %1:vrnov0 = COPY $v1 + %2:vrnov0 = COPY $v2 + %0:vr = PseudoVNMSUB_VV_M1_COMMUTABLE %0, %1, killed %2, $x0, 6, implicit $vl, implicit $vtype + %3:vr = COPY %0 + %3:vr = PseudoVSLL_VI_M1 %3, 11, $noreg, 6, implicit $vl, implicit $vtype + $v0 = COPY %0 + PseudoRET implicit $v0 +... diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir 2021-11-16 16:47:26.000000000 +0000 @@ -21,6 +21,10 @@ # After w0 is clobbered, we should get an indirect parameter entry value for "f". +# DWARF-LABEL: DW_TAG_subprogram +# DWARF: DW_AT_name ("baz") + +# DWARF-LABEL: DW_TAG_subprogram # DWARF-LABEL: DW_TAG_formal_parameter # DWARF-NEXT: DW_AT_location # DWARF-NEXT: [0x0000000000000000, 0x0000000000000010): DW_OP_breg0 W0+0 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir 2021-11-16 16:47:26.000000000 +0000 @@ -159,7 +159,7 @@ ... # CHECK: DW_TAG_GNU_call_site -# CHECK-NEXT: DW_AT_abstract_origin ({{.*}} "call_int") +# CHECK-NEXT: DW_AT_abstract_origin (0x0000002a "call_int") # # CHECK: DW_TAG_GNU_call_site_parameter # CHECK-NEXT: DW_AT_location (DW_OP_reg0 W0) @@ -205,7 +205,7 @@ ... # CHECK: DW_TAG_GNU_call_site -# CHECK-NEXT: DW_AT_abstract_origin ({{.*}} "call_long") +# CHECK-NEXT: DW_AT_abstract_origin (0x0000003e "call_long") # # CHECK: DW_TAG_GNU_call_site_parameter # CHECK-NEXT: DW_AT_location (DW_OP_reg0 W0) @@ -265,7 +265,7 @@ ... # CHECK: DW_TAG_GNU_call_site -# CHECK-NEXT: DW_AT_abstract_origin ({{.*}} "call_int_int") +# CHECK-NEXT: DW_AT_abstract_origin (0x00000052 "call_int_int") # # CHECK: DW_TAG_GNU_call_site_parameter # CHECK-NEXT: DW_AT_location (DW_OP_reg0 W0) diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir 2021-11-16 16:47:26.000000000 +0000 @@ -1,8 +1,12 @@ # RUN: llc -start-after=livedebugvalues -mtriple=x86_64-apple-darwin -o - %s -filetype=obj \ # RUN: -emit-call-site-info | llvm-dwarfdump - | FileCheck %s -implicit-check-not=call_site_parameter -# CHECK: DW_TAG_formal_parameter -# CHECK-NEXT: DW_AT_location (DW_OP_reg17 XMM0) +# CHECK-LABEL: DW_TAG_subprogram +# CHECK: DW_AT_name ("f") +# CHECK-LABEL: DW_TAG_subprogram +# CHECK: DW_AT_name ("g") +# CHECK: DW_TAG_formal_parameter +# CHECK-NEXT: DW_AT_location (DW_OP_reg17 XMM0) # struct S { # float w; diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir 2021-11-16 16:47:26.000000000 +0000 @@ -39,11 +39,17 @@ # CHECK-GNU-NEXT: DW_AT_location (DW_OP_reg8 R8) # CHECK-GNU-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg14 R14+3) -# CHECK-DWARF5: DW_TAG_call_site -# CHECK-DWARF5: DW_AT_call_origin ([[getValue_SP:.*]]) +# CHECK-DWARF5: [[getValue_SP:.*]]: DW_TAG_subprogram +# CHECK-DWARF5-NEXT: DW_AT_name ("getVal") +# CHECK-DWARF5: [[foo_SP:.*]]: DW_TAG_subprogram +# CHECK-DWARF5-NEXT: DW_AT_name ("foo") + +# CHECK-DWARF5: DW_TAG_call_site +# CHECK-DWARF5: DW_AT_call_origin ([[getValue_SP]]) +# # CHECK-DWARF5: DW_TAG_call_site -# CHECK-DWARF5: DW_AT_call_origin ([[foo_SP:.*]]) +# CHECK-DWARF5: DW_AT_call_origin ([[foo_SP]]) # CHECK-DWARF5: DW_AT_call_return_pc {{.*}} # CHECK-DWARF5-EMPTY: # CHECK-DWARF5: DW_TAG_call_site_parameter @@ -65,12 +71,6 @@ # CHECK-DWARF5-NEXT: DW_AT_location (DW_OP_reg8 R8) # CHECK-DWARF5-NEXT: DW_AT_call_value (DW_OP_breg14 R14+3) -# CHECK-DWARF5: [[getValue_SP]]: DW_TAG_subprogram -# CHECK-DWARF5-NEXT: DW_AT_name ("getVal") - -# CHECK-DWARF5: [[foo_SP]]: DW_TAG_subprogram -# CHECK-DWARF5-NEXT: DW_AT_name ("foo") - --- | ; ModuleID = 'test.c' source_filename = "test.c" diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/tools/llvm-cov/branch-export-lcov.test rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/tools/llvm-cov/branch-export-lcov.test --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/tools/llvm-cov/branch-export-lcov.test 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/tools/llvm-cov/branch-export-lcov.test 2021-11-16 16:47:26.000000000 +0000 @@ -34,7 +34,7 @@ // CHECK-DAG: BRDA:53,0,1,5 // CHECK-NOT: BRDA // CHECK: BRF:30 -// CHECK: BFH:26 +// CHECK: BRH:26 // Check recursive macro-expansions. // RUN: llvm-profdata merge %S/Inputs/branch-macros.proftext -o %t.profdata @@ -70,4 +70,4 @@ // MACROS-NOT: BRDA:37 // MACROS-NOT: BRDA // MACROS: BRF:40 -// MACROS: BFH:24 +// MACROS: BRH:24 diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs-exec.test rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs-exec.test --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs-exec.test 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs-exec.test 2021-11-16 16:47:26.000000000 +0000 @@ -0,0 +1,59 @@ +## Check that 'llvm-objdump -dr' correctly prints relocations in executables. + +# RUN: yaml2obj --docnum=1 %s -o %t +# RUN: llvm-objdump -dr %t | FileCheck %s + +# CHECK: 400000: 90 nop +# CHECK-NEXT: 400001: bf 10 00 40 00 movl $4194320, %edi +# CHECK-NEXT: 0000000000400002: R_X86_64_32 .rodata +# CHECK-NEXT: 400006: e8 fc fe ff ff callq 0x3fff07 +# CHECK-NEXT: 0000000000400007: R_X86_64_PLT32 puts-0x4 +# CHECK-NEXT: 40000b: 90 nop + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + FirstSec: .text + LastSec: .rodata + VAddr: 0x400000 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x400000 + AddressAlign: 0x10 + Content: 90BF10004000E8FCFEFFFF90 + - Name: .rodata + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + AddressAlign: 0x8 + Content: 00 + - Name: .rela.text + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + AddressAlign: 0x8 + Info: .text + Relocations: + - Offset: 0x400002 + Symbol: .rodata + Type: R_X86_64_32 + Addend: 0 + - Offset: 0x400007 + Symbol: puts + Type: R_X86_64_PLT32 + Addend: -4 +Symbols: + - Name: .rodata + Type: STT_SECTION + Section: .rodata + Value: 0x400628 + - Name: puts + Type: STT_FUNC + Binding: STB_GLOBAL +... diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterLcov.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterLcov.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterLcov.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/tools/llvm-cov/CoverageExporterLcov.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -167,7 +167,7 @@ void renderBranchSummary(raw_ostream &OS, const FileCoverageSummary &Summary) { OS << "BRF:" << Summary.BranchCoverage.getNumBranches() << '\n' - << "BFH:" << Summary.BranchCoverage.getCovered() << '\n'; + << "BRH:" << Summary.BranchCoverage.getCovered() << '\n'; } void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage, diff -Nru rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp --- rustc-1.56.0+dfsg1+llvm/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp 2021-08-27 13:15:25.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp 2021-11-16 16:47:26.000000000 +0000 @@ -1286,6 +1286,10 @@ if (shouldAdjustVA(Section)) VMAAdjustment = AdjustVMA; + // In executable and shared objects, r_offset holds a virtual address. + // Subtract SectionAddr from the r_offset field of a relocation to get + // the section offset. + uint64_t RelAdjustment = Obj->isRelocatableObject() ? 0 : SectionAddr; uint64_t Size; uint64_t Index; bool PrintedSection = false; @@ -1432,7 +1436,8 @@ // For --reloc: print zero blocks patched by relocations, so that // relocations can be shown in the dump. if (RelCur != RelEnd) - MaxOffset = RelCur->getOffset() - Index; + MaxOffset = std::min(RelCur->getOffset() - RelAdjustment - Index, + MaxOffset); if (size_t N = countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) { @@ -1581,7 +1586,7 @@ if (Obj->getArch() != Triple::hexagon) { // Print relocation for instruction and data. while (RelCur != RelEnd) { - uint64_t Offset = RelCur->getOffset(); + uint64_t Offset = RelCur->getOffset() - RelAdjustment; // If this relocation is hidden, skip it. if (getHidden(*RelCur) || SectionAddr + Offset < StartAddress) { ++RelCur; diff -Nru rustc-1.56.0+dfsg1+llvm/src/rustdoc-json-types/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/rustdoc-json-types/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/rustdoc-json-types/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/rustdoc-json-types/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustdoc-json-types" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] path = "lib.rs" diff -Nru rustc-1.56.0+dfsg1+llvm/src/rustdoc-json-types/lib.rs rustc-1.57.0+dfsg1+llvm/src/rustdoc-json-types/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/rustdoc-json-types/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/rustdoc-json-types/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -221,6 +221,8 @@ Macro(String), ProcMacro(ProcMacro), + PrimitiveType(String), + AssocConst { #[serde(rename = "type")] type_: Type, @@ -323,7 +325,7 @@ #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum GenericParamDefKind { - Lifetime, + Lifetime { outlives: Vec }, Type { bounds: Vec, default: Option }, Const { ty: Type, default: Option }, } @@ -386,8 +388,6 @@ }, /// `impl TraitA + TraitB + ...` ImplTrait(Vec), - /// `!` - Never, /// `_` Infer, /// `*mut u32`, `*u8`, etc. @@ -510,5 +510,8 @@ pub expr: String, } +/// rustdoc format-version. +pub const FORMAT_VERSION: u32 = 9; + #[cfg(test)] mod tests; diff -Nru rustc-1.56.0+dfsg1+llvm/src/stage0.json rustc-1.57.0+dfsg1+llvm/src/stage0.json --- rustc-1.56.0+dfsg1+llvm/src/stage0.json 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/stage0.json 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,291 @@ +{ + "__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.", + "dist_server": "https://static.rust-lang.org", + "compiler": { + "date": "2021-11-01", + "version": "1.56.1" + }, + "rustfmt": null, + "checksums_sha256": { + "dist/2021-11-01/cargo-1.56.1-aarch64-apple-darwin.tar.gz": "6ed30275214e956ee10b03db87b0b4297948fd102d39896cece01669555047ef", + "dist/2021-11-01/cargo-1.56.1-aarch64-apple-darwin.tar.xz": "f2e184a62e6b112fce2f6dd0d707c60a84addc29f774cdebcfded663ae81291a", + "dist/2021-11-01/cargo-1.56.1-aarch64-pc-windows-msvc.tar.gz": "8eaaf29bf6012ac99732c9fdeff3d23763620ed30b4fee9b9dac1406b8f3dfbb", + "dist/2021-11-01/cargo-1.56.1-aarch64-pc-windows-msvc.tar.xz": "b230a5d81ce5157de3b6df264fe5d9e74c91ab3de2a27a14e9588016f92ca48b", + "dist/2021-11-01/cargo-1.56.1-aarch64-unknown-linux-gnu.tar.gz": "9aa557436b0cf2a2f4f0d6c4aed5b95062c0637a4a94c000522402e59db1c93a", + "dist/2021-11-01/cargo-1.56.1-aarch64-unknown-linux-gnu.tar.xz": "3d263eb1871b5d6ca4b198b9611925923e9353e1f5c2becf8c7b784298e88743", + "dist/2021-11-01/cargo-1.56.1-aarch64-unknown-linux-musl.tar.gz": "313f095df71bdd7cab5934641990cbcf325acdfefdcdf9d7a4a8aa950fc655d6", + "dist/2021-11-01/cargo-1.56.1-aarch64-unknown-linux-musl.tar.xz": "27f73d4ddcad9cddcc2fd25d194e26fefafbc9c6a98a14e0617b0fa63413f8b9", + "dist/2021-11-01/cargo-1.56.1-arm-unknown-linux-gnueabi.tar.gz": "c6f4190231a062acc7371a14de52dab33dbf3a3a96be50069892cef6318e4b8e", + "dist/2021-11-01/cargo-1.56.1-arm-unknown-linux-gnueabi.tar.xz": "09e69dd23cbf00ed599487eb94e6556c8fd4a28177427fe56ea4c549a94d3122", + "dist/2021-11-01/cargo-1.56.1-arm-unknown-linux-gnueabihf.tar.gz": "fe444ee7d5d3e8777507e3d671e252465295df8552367d69e4d163de6b1ef4b0", + "dist/2021-11-01/cargo-1.56.1-arm-unknown-linux-gnueabihf.tar.xz": "01ce6ec7c0666e91d2be48d25ee1dfd56f05c01f85eaa2c1464dc055fe064e35", + "dist/2021-11-01/cargo-1.56.1-armv7-unknown-linux-gnueabihf.tar.gz": "61b4686b778d1eb118e23d40d79b9da248dbff93a1edc0f64a920f8ba195be59", + "dist/2021-11-01/cargo-1.56.1-armv7-unknown-linux-gnueabihf.tar.xz": "151c96c9cb7c13bec2f2de9c949d494cae3d72bf4f59951b74d905ca03df891a", + "dist/2021-11-01/cargo-1.56.1-i686-pc-windows-gnu.tar.gz": "7e184de74b95ff456eb8aba5bbb98ac21d60b13d7977b292a7824c85c3a7ac53", + "dist/2021-11-01/cargo-1.56.1-i686-pc-windows-gnu.tar.xz": "a91f12926e7646b0fd307e8ddf9a5049d58f6fa81ad3745ff91bca3778871581", + "dist/2021-11-01/cargo-1.56.1-i686-pc-windows-msvc.tar.gz": "6d11253bac7a2b067da40de7bafcb538f6e49b8729d2999716bce4d5701a478b", + "dist/2021-11-01/cargo-1.56.1-i686-pc-windows-msvc.tar.xz": "fb0b06ac6641649b9f19aa07efa19e731e2d316376f98dbcf7e43b7b8204eb4a", + "dist/2021-11-01/cargo-1.56.1-i686-unknown-linux-gnu.tar.gz": "1142c1b8a29d17794d5d2682de93a6c0807d09047dd1462af4d613e0fe63269b", + "dist/2021-11-01/cargo-1.56.1-i686-unknown-linux-gnu.tar.xz": "0a09556948da5ac0041df581a2f16d80c61bcef6d22cc9b26b4d8c64859cfd84", + "dist/2021-11-01/cargo-1.56.1-mips-unknown-linux-gnu.tar.gz": "dc29f524d3879a5eec09684d97469e853aecb6b02281000b4d72efd886f05edb", + "dist/2021-11-01/cargo-1.56.1-mips-unknown-linux-gnu.tar.xz": "32c269755f0e1160f47b80cefa05ac7b77cd3639776d0bb9757d21effdb74456", + "dist/2021-11-01/cargo-1.56.1-mips64-unknown-linux-gnuabi64.tar.gz": "96be8e56ad31c6d35d90c51d54086939ebe03613779c5e643724b6583777b6cf", + "dist/2021-11-01/cargo-1.56.1-mips64-unknown-linux-gnuabi64.tar.xz": "ec1ffacc30cd0ced255fc65272aab1f9870fb376b751f7e10f60f494508d3a61", + "dist/2021-11-01/cargo-1.56.1-mips64el-unknown-linux-gnuabi64.tar.gz": "cd187465cb3d330c98399f6e79665720a3a44b80f1580a8e9525bee6bdc5ce1a", + "dist/2021-11-01/cargo-1.56.1-mips64el-unknown-linux-gnuabi64.tar.xz": "bfe618804ac9e72cc59b7130a7e945633b1cef99cfe148b64e97dc823ab4d0eb", + "dist/2021-11-01/cargo-1.56.1-mipsel-unknown-linux-gnu.tar.gz": "61550d9a5c3a4ec784a1cf152292d514037064941a59bdf402aa725ad48d0992", + "dist/2021-11-01/cargo-1.56.1-mipsel-unknown-linux-gnu.tar.xz": "75bc41bcbe867dba7ae47ee82ded3a24ef53a1589cb413a58603368c735f21d5", + "dist/2021-11-01/cargo-1.56.1-powerpc-unknown-linux-gnu.tar.gz": "537518dd84100d727bfd7cf41fa390de05645ecf7369517cbe519ba9c8c71d5f", + "dist/2021-11-01/cargo-1.56.1-powerpc-unknown-linux-gnu.tar.xz": "89da39892488aca3c0931a81b2cd94cc99c23635b0926d38ca64ad64a097bdd6", + "dist/2021-11-01/cargo-1.56.1-powerpc64-unknown-linux-gnu.tar.gz": "68005d4d5588c9aa9a1fe813ae866b551ea7dff6857956f360d272fad617a27b", + "dist/2021-11-01/cargo-1.56.1-powerpc64-unknown-linux-gnu.tar.xz": "b1be5b5e52bececa56be33b5df3c4c6c14b72de6621c2eabaabcdd5e86c928df", + "dist/2021-11-01/cargo-1.56.1-powerpc64le-unknown-linux-gnu.tar.gz": "2806e83799c007b607d007950e283aac6982d5ecc134f4b26e2600d476aab8a1", + "dist/2021-11-01/cargo-1.56.1-powerpc64le-unknown-linux-gnu.tar.xz": "06be63ee1aec76307a3de1b79f3627e70dec642969682ad8013ce43079e49d57", + "dist/2021-11-01/cargo-1.56.1-riscv64gc-unknown-linux-gnu.tar.gz": "4740f2ed48e2be09be50f3b4c9fefc509b4bbcc17f0dd59892656b7bff2edce0", + "dist/2021-11-01/cargo-1.56.1-riscv64gc-unknown-linux-gnu.tar.xz": "84b760d148bfdb8c9858ed087df7101af707b466a6c850abce377866e4879d0e", + "dist/2021-11-01/cargo-1.56.1-s390x-unknown-linux-gnu.tar.gz": "2600d8d1f031413904978b8aed652af2a2b5a022700ef60aede3ff8580ec8ee8", + "dist/2021-11-01/cargo-1.56.1-s390x-unknown-linux-gnu.tar.xz": "534c6f28fe9e96ff8b2f42cf64ca294fef3174b15d819cf0616336642226a09e", + "dist/2021-11-01/cargo-1.56.1-x86_64-apple-darwin.tar.gz": "cd60c32d0bb0ed59508df96bebb83cf6f85accb9908fb5d63ca95c983a190cf3", + "dist/2021-11-01/cargo-1.56.1-x86_64-apple-darwin.tar.xz": "46840c92c510b1bcfffb0ea7f0c0ee649a54ec0308965a2f3e154ae9d1780f29", + "dist/2021-11-01/cargo-1.56.1-x86_64-pc-windows-gnu.tar.gz": "78f20b3a746b4b2b700dc82710311d56f95e51dc08e979707bab59d35a69fb5d", + "dist/2021-11-01/cargo-1.56.1-x86_64-pc-windows-gnu.tar.xz": "dd1b4f61fb5bb3c0aa4a2886041d20dbea5bd920a65ca77559101713225b1eb6", + "dist/2021-11-01/cargo-1.56.1-x86_64-pc-windows-msvc.tar.gz": "0606835d9c41137552ee63f339c5df1a2ed6f722c871f9fc5cb92b02c7372373", + "dist/2021-11-01/cargo-1.56.1-x86_64-pc-windows-msvc.tar.xz": "264281bfee9fee1fabde6805a9bf916ca24337a7bb130a34b6a5fe1ed2fc42c2", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-freebsd.tar.gz": "a1656603049a4612cdf44179ac7ccdb3c342f0b152cb114f61a228d321b0f384", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-freebsd.tar.xz": "c987fc8c70bd4c92f753a51a14ce49dbe666a8dc209df681562575efcfe7921b", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-illumos.tar.gz": "292ed7f6efa78cf93f91aed38508da1d0ef192f4cdba5fa37d9e739ed0d78a88", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-illumos.tar.xz": "a3854cdba97226d7ce123eb4c3e9d9ba8c9b480bdcd54978909ec57ea0431b3f", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-linux-gnu.tar.gz": "c896c033bb1f430c4e200ae8af0f74d792e4909a458086b9597f076e1dcc2ab2", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-linux-gnu.tar.xz": "dfed65a50e2b58b6807c1fb6f8afa7abd5c3b22c682d505721d615823687c708", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-linux-musl.tar.gz": "4ecdd39695d9e09c3f4efffff61d67451cd41f28f09155485ac7dcc8f7a65a26", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-linux-musl.tar.xz": "ceb8e3e273ade68766b526a7d076fc8ebfb19c2b2d4946f789bcf2597d06f83a", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-netbsd.tar.gz": "4c458fbe9121fdd9e01cee4129249b1abf86301c0f441f7e78e8a6ba554d8cfc", + "dist/2021-11-01/cargo-1.56.1-x86_64-unknown-netbsd.tar.xz": "24148a57a64aeb2fdf84044728e138a53353d08fadfd3136771f355ea52eb7e0", + "dist/2021-11-01/rust-std-1.56.1-aarch64-apple-darwin.tar.gz": "59fcdb16c264fce206a1a59261fc576f547fa0a807d3370b542ab25261ae5158", + "dist/2021-11-01/rust-std-1.56.1-aarch64-apple-darwin.tar.xz": "733d5855a4b4158778e4eab50229a96cfdd492cfa8cf1877bfe7c9a242d523cd", + "dist/2021-11-01/rust-std-1.56.1-aarch64-apple-ios-sim.tar.gz": "eca6dc2d6ab37ed2ea58d408c9f0496ed2cca03b49c3d748fdcc41640fee2225", + "dist/2021-11-01/rust-std-1.56.1-aarch64-apple-ios-sim.tar.xz": "be91d88dd4ea439cc16d2affb90ec7d88436562938e77f39993899e87f1e0173", + "dist/2021-11-01/rust-std-1.56.1-aarch64-apple-ios.tar.gz": "2032f94869f69bf03c0f01c82e84ef174c827d333feab7823e75b408b8124648", + "dist/2021-11-01/rust-std-1.56.1-aarch64-apple-ios.tar.xz": "13b883914ba238f697a75cd14044e87dc2617cd2bee09de8840dcb7a84636778", + "dist/2021-11-01/rust-std-1.56.1-aarch64-fuchsia.tar.gz": "04f82af2f37cb003f5e4dbd48499f1e8e25c610f11c72ed8bc24388a90ef14bd", + "dist/2021-11-01/rust-std-1.56.1-aarch64-fuchsia.tar.xz": "ffba901f4ff822ca9b1c474840cb38ecc4aad83a4e755cdb780372eb534838e7", + "dist/2021-11-01/rust-std-1.56.1-aarch64-linux-android.tar.gz": "b340fff6db68427472ab654773b1b5537d6b6b6e135490c914f9d5928b34c6db", + "dist/2021-11-01/rust-std-1.56.1-aarch64-linux-android.tar.xz": "2ac95848896317aed41583d779641342ca411440efb72cc132497848ccfb6b13", + "dist/2021-11-01/rust-std-1.56.1-aarch64-pc-windows-msvc.tar.gz": "51a6feee2170a5c73bd1ac866b8337ffac310488ca541b663b791308db7eb20f", + "dist/2021-11-01/rust-std-1.56.1-aarch64-pc-windows-msvc.tar.xz": "71b75f9124241a2b8c90238374c7e5b05bd47bb8dcaa72214f02836a5c621233", + "dist/2021-11-01/rust-std-1.56.1-aarch64-unknown-linux-gnu.tar.gz": "d577c25879cf160ec1a04d5101971dd684f9b4f87b3cb463a7521b676dc3df89", + "dist/2021-11-01/rust-std-1.56.1-aarch64-unknown-linux-gnu.tar.xz": "a83416d15354e4dfa1c1e4a756282c6be7169679f2b04eca82ed34e2116b93f0", + "dist/2021-11-01/rust-std-1.56.1-aarch64-unknown-linux-musl.tar.gz": "444d5cb43bb82322562afe54c249c3d85b5b1cf215fcd0cfdabd2e657fcda687", + "dist/2021-11-01/rust-std-1.56.1-aarch64-unknown-linux-musl.tar.xz": "50603cfa6332846ee1a7e9c0440f976b57b49d1800a2504ef0be1fb484646bbc", + "dist/2021-11-01/rust-std-1.56.1-aarch64-unknown-none-softfloat.tar.gz": "0bf6e201e77c0ca2261398853cfd882a391dfd62dda2a8321b3d43e131dd0334", + "dist/2021-11-01/rust-std-1.56.1-aarch64-unknown-none-softfloat.tar.xz": "02b4e72a8d4f4125acf4bee59854ddc937d7fbe38b0436bb780b8326edd4bb97", + "dist/2021-11-01/rust-std-1.56.1-aarch64-unknown-none.tar.gz": "45c7d49e25675a1e520e952b91b965122610c4a2a7f1c59964005470073dae23", + "dist/2021-11-01/rust-std-1.56.1-aarch64-unknown-none.tar.xz": "d23e31946836a59f074ed0b24c79913e87fc61cf0ef6cb27077ea51d4768ef69", + "dist/2021-11-01/rust-std-1.56.1-arm-linux-androideabi.tar.gz": "a687eea48c20a2f377f84e42d547e67532d393ac6278740a097519a6f3c490d3", + "dist/2021-11-01/rust-std-1.56.1-arm-linux-androideabi.tar.xz": "01396ddd5ab1d8b1a7a3f13734d7c83558cd67a745e77c53bda2c81face56d4f", + "dist/2021-11-01/rust-std-1.56.1-arm-unknown-linux-gnueabi.tar.gz": "13a618ef5ee18e00b76d5891fcd1886f1fdb042ca81962dae30df6c535d42bef", + "dist/2021-11-01/rust-std-1.56.1-arm-unknown-linux-gnueabi.tar.xz": "3a7d1b12b961ecee610b89258260b0c596b81cc0e9444b9b651669844f6f056d", + "dist/2021-11-01/rust-std-1.56.1-arm-unknown-linux-gnueabihf.tar.gz": "01963e591bfbe7e33e2b264984005320e0ac0c5849a23bb897613de38bef9abd", + "dist/2021-11-01/rust-std-1.56.1-arm-unknown-linux-gnueabihf.tar.xz": "ee5dda5e1901379a617a1070152890b463b117267aeabd8dd9cdcfece826eccb", + "dist/2021-11-01/rust-std-1.56.1-arm-unknown-linux-musleabi.tar.gz": "c09983c442b5307b3564c406bad2f306153d07fff6acc7584265b36714e7cb01", + "dist/2021-11-01/rust-std-1.56.1-arm-unknown-linux-musleabi.tar.xz": "eac145da4edd6200a304f50bcde86eb6ecc62418b20f1ce618a65031f15f99a6", + "dist/2021-11-01/rust-std-1.56.1-arm-unknown-linux-musleabihf.tar.gz": "9410faa13d85080b4d338b4e16b03c2fbadaa97f7463392196cb0ffa69cc3ad9", + "dist/2021-11-01/rust-std-1.56.1-arm-unknown-linux-musleabihf.tar.xz": "6211547d48e961344024226a0dbad40d97d458f497fe4c54f4768cd7c76d4307", + "dist/2021-11-01/rust-std-1.56.1-armebv7r-none-eabi.tar.gz": "dec378a0e599a7d20a489b4de0713e21bb9153f444d1892fbc195579b2aa4a72", + "dist/2021-11-01/rust-std-1.56.1-armebv7r-none-eabi.tar.xz": "84d3d03676bdde599df1759268cb055476529623c0124ca0b97b0d4cc6462739", + "dist/2021-11-01/rust-std-1.56.1-armebv7r-none-eabihf.tar.gz": "3fae86e0e86440dce288575ab6ed311841cfeec0f7e9ba62ad5f8e1968ede580", + "dist/2021-11-01/rust-std-1.56.1-armebv7r-none-eabihf.tar.xz": "3f135a57508fd61d8652995737cb520808aebbf4e11b2105836064f8164f69d1", + "dist/2021-11-01/rust-std-1.56.1-armv5te-unknown-linux-gnueabi.tar.gz": "ce240263fee9de563727e4feb5c6ee038c837189b3fa93d2d2f5b4ec7077f42e", + "dist/2021-11-01/rust-std-1.56.1-armv5te-unknown-linux-gnueabi.tar.xz": "5a85910a68c80976af123cf31229eaf70028298da8f4f212e832b004c4ef405b", + "dist/2021-11-01/rust-std-1.56.1-armv5te-unknown-linux-musleabi.tar.gz": "e3aa96cd1ec07512575b6daf74677fefee766a18de678a0a77f44614f606c1a7", + "dist/2021-11-01/rust-std-1.56.1-armv5te-unknown-linux-musleabi.tar.xz": "9f375a46531a66b670e55df432cc5cebcdf7e7647ab7fd61814560ff3a115ba3", + "dist/2021-11-01/rust-std-1.56.1-armv7-linux-androideabi.tar.gz": "197477edffa06dae19c461cabe57ee45c20b7e4c3850094671209fec9438acd1", + "dist/2021-11-01/rust-std-1.56.1-armv7-linux-androideabi.tar.xz": "187a79c99463128a7533d092042a0376dd7866cbc8ba15567cc5c188e8145933", + "dist/2021-11-01/rust-std-1.56.1-armv7-unknown-linux-gnueabi.tar.gz": "5e2adde15b1177814137f7f93ca6392ecb4dc44bf82f05ca3cc8abd24a8072be", + "dist/2021-11-01/rust-std-1.56.1-armv7-unknown-linux-gnueabi.tar.xz": "0c6fb440c8dc219093674fa685bf08432ca7d2f1bad2e724a344a718571d90c0", + "dist/2021-11-01/rust-std-1.56.1-armv7-unknown-linux-gnueabihf.tar.gz": "cedd08ec5f94e7b6348befde00e42a8e1e5981586762be8d264b34e1f7de9818", + "dist/2021-11-01/rust-std-1.56.1-armv7-unknown-linux-gnueabihf.tar.xz": "d4eeeae7cd711372c3ccde1b943d1b6e1055918c59a637bba7f5fe3cd2aede4a", + "dist/2021-11-01/rust-std-1.56.1-armv7-unknown-linux-musleabi.tar.gz": "3c7dd1cac570038cc95fc1edcd8b965dd19447bdcf29782fb7745d64f98ce7da", + "dist/2021-11-01/rust-std-1.56.1-armv7-unknown-linux-musleabi.tar.xz": "d485fa9a545d3ad20dc96c8665a06f436447b841cff68db34c156bcd28186351", + "dist/2021-11-01/rust-std-1.56.1-armv7-unknown-linux-musleabihf.tar.gz": "21a6f072752c57c5692d36fce19e45cfd3704a22e263c4c31963587d085c7530", + "dist/2021-11-01/rust-std-1.56.1-armv7-unknown-linux-musleabihf.tar.xz": "406276fb537b0e26957b5c3274c01d59f80ee12b2dda1c035dc45df6435cc5a0", + "dist/2021-11-01/rust-std-1.56.1-armv7a-none-eabi.tar.gz": "c8dafb090c29ae58fc991003303b49e80d2657dc0e256016953b72430fadd88c", + "dist/2021-11-01/rust-std-1.56.1-armv7a-none-eabi.tar.xz": "cfc2089bacf64e8d937d1b1e7dfe0d608e3d01ad5832bb66cab315998b2ba200", + "dist/2021-11-01/rust-std-1.56.1-armv7r-none-eabi.tar.gz": "75dcae3d8d31ab06646f11504c533ef3386c22717ecab4ea90f5087a3a480067", + "dist/2021-11-01/rust-std-1.56.1-armv7r-none-eabi.tar.xz": "a647b0717acaf54abd60912e08a9c7e1ec9e09463692f3da6f9e1567305c49c3", + "dist/2021-11-01/rust-std-1.56.1-armv7r-none-eabihf.tar.gz": "4cef8deef36d9ec3a27cc12d2aef0918da581748622b9b6f15bdad4c27c47ba7", + "dist/2021-11-01/rust-std-1.56.1-armv7r-none-eabihf.tar.xz": "a09b855ff61abc5522199aee787adcbf7d3a08b750d61c2a3e1a443c9b3334cb", + "dist/2021-11-01/rust-std-1.56.1-asmjs-unknown-emscripten.tar.gz": "5912086ddf103ab831cd478b3ecbbdaba97a4d0b3287aaeeb6b5ccbcfde6f21e", + "dist/2021-11-01/rust-std-1.56.1-asmjs-unknown-emscripten.tar.xz": "dae15590f62445c8c45f46de98ee03782701eb0ce70572af7e7978926626c2ed", + "dist/2021-11-01/rust-std-1.56.1-i586-pc-windows-msvc.tar.gz": "18ac156546ec8c997356596268bf64b7f0fcaa71dd58ba2262d4a54d3bc8c058", + "dist/2021-11-01/rust-std-1.56.1-i586-pc-windows-msvc.tar.xz": "454dd3fdc3432774c137753f514f063c87e05b185eda5c20f289b9acdaa4869a", + "dist/2021-11-01/rust-std-1.56.1-i586-unknown-linux-gnu.tar.gz": "9aa048d2bc7e97e1c4a648d43e856050ce41ef9c53d684aae18faf0284e5193a", + "dist/2021-11-01/rust-std-1.56.1-i586-unknown-linux-gnu.tar.xz": "3979068f4785080db04437bd080402d6c472b87828ec6de32b2b7003cb3326df", + "dist/2021-11-01/rust-std-1.56.1-i586-unknown-linux-musl.tar.gz": "77aa024712e5e4cd1e96b996c0105c3d57cf3c7719b76b63b460482d658b929c", + "dist/2021-11-01/rust-std-1.56.1-i586-unknown-linux-musl.tar.xz": "2e449ac494d1455e6cef943b498e0551e9fc16db1da5dffd01aec9d53cb7cdca", + "dist/2021-11-01/rust-std-1.56.1-i686-linux-android.tar.gz": "ef735709105b89782d9f6948f01ee739b4ab62e8d879ed207d0dcf1ed90c0fe4", + "dist/2021-11-01/rust-std-1.56.1-i686-linux-android.tar.xz": "0ec3b10470da960da6907ea7390e3a2abbca95876e684d51fc751c598cf87969", + "dist/2021-11-01/rust-std-1.56.1-i686-pc-windows-gnu.tar.gz": "f7bb9af44b2407b46d4c98a0ff335c7d05fedc7fdbb2b32a224ce004211f90f1", + "dist/2021-11-01/rust-std-1.56.1-i686-pc-windows-gnu.tar.xz": "840ef76c8b462f7434be2c2fd2677b78e5659098c85becf40490ddfc1bfb4e2d", + "dist/2021-11-01/rust-std-1.56.1-i686-pc-windows-msvc.tar.gz": "c2108cca173656766b8743d41b5c0c0c20c6c4855b0a022c749bc70a231c42ce", + "dist/2021-11-01/rust-std-1.56.1-i686-pc-windows-msvc.tar.xz": "d6807c920f6cd448ea4a4f87bf1d6f1402ff7b5b6d98c7196a8719541e26593a", + "dist/2021-11-01/rust-std-1.56.1-i686-unknown-freebsd.tar.gz": "db427a44cca63c9811ee7af6774356a29c49b6056b9f6057cba4d0955991e7da", + "dist/2021-11-01/rust-std-1.56.1-i686-unknown-freebsd.tar.xz": "257b4669776a4b6b16c04e02ffad81704c001edaf3c73bbbb3954aee33821572", + "dist/2021-11-01/rust-std-1.56.1-i686-unknown-linux-gnu.tar.gz": "daff2db4e3d42916094a59b7c4eef169030b1fe0050c3cf882e7e293279298bd", + "dist/2021-11-01/rust-std-1.56.1-i686-unknown-linux-gnu.tar.xz": "616c78507a68439355116d45353c0bd07f1356d4021406b72a47a2f3f833996f", + "dist/2021-11-01/rust-std-1.56.1-i686-unknown-linux-musl.tar.gz": "67578ed8b2e2625e09d8f0c23f34feb28b9be847cfabdc53e778ede8a3b38511", + "dist/2021-11-01/rust-std-1.56.1-i686-unknown-linux-musl.tar.xz": "c1e56f99785ad3bd84ca723c0e65ca578aa0734ddfe5e0d4f252bda9fbfcc445", + "dist/2021-11-01/rust-std-1.56.1-mips-unknown-linux-gnu.tar.gz": "3ed4c2c3975ac4296b016910df2bf129dfafca30d6a9fda68f6fa1a3f22a0a23", + "dist/2021-11-01/rust-std-1.56.1-mips-unknown-linux-gnu.tar.xz": "c13790eae5d9a7e76e0406161c19cae3249dc096b6fcf33934954a928c724649", + "dist/2021-11-01/rust-std-1.56.1-mips-unknown-linux-musl.tar.gz": "e87448e5561c4325fcd11d2cf47a002c43b339ead6cfa73ea14687e2a4b6114b", + "dist/2021-11-01/rust-std-1.56.1-mips-unknown-linux-musl.tar.xz": "003619386c44b45e6f3274c8bbbdc5598727d0e69b1e7bb01e6e86e9527490d7", + "dist/2021-11-01/rust-std-1.56.1-mips64-unknown-linux-gnuabi64.tar.gz": "f4bca093a787bbcfc88bdb2a1b19e8ec05cd34b34fadc28557eed2651178d7b5", + "dist/2021-11-01/rust-std-1.56.1-mips64-unknown-linux-gnuabi64.tar.xz": "c036d1b576f8c8f1026ea972712da7c89e7fdeee6e193050f0a7ceadf660e031", + "dist/2021-11-01/rust-std-1.56.1-mips64-unknown-linux-muslabi64.tar.gz": "ba9b96c5541745083d222e4d261c60c68612373d467113840c4b3fe5bd0d76ac", + "dist/2021-11-01/rust-std-1.56.1-mips64-unknown-linux-muslabi64.tar.xz": "318f663f00add6af66fe5601ce4813d4b667a3e64b2680e384907739fc6577d8", + "dist/2021-11-01/rust-std-1.56.1-mips64el-unknown-linux-gnuabi64.tar.gz": "e5946fcda6275b53568cf7564ffaff9b738ab3e098e9497abd7483c5083b1920", + "dist/2021-11-01/rust-std-1.56.1-mips64el-unknown-linux-gnuabi64.tar.xz": "f56f5dcd7e96d7986ad7e32eee6be6e84ce3172dbbe1d2af15e677226e0d518d", + "dist/2021-11-01/rust-std-1.56.1-mips64el-unknown-linux-muslabi64.tar.gz": "bf53a5a55a3f31e7a5f4ce5220cbe75f9ead277d96de89ef01929c932cfe39ea", + "dist/2021-11-01/rust-std-1.56.1-mips64el-unknown-linux-muslabi64.tar.xz": "46af98067623584b355e8e542dc3283543ec51f1ab7b83ec2acbb878b27dd34d", + "dist/2021-11-01/rust-std-1.56.1-mipsel-unknown-linux-gnu.tar.gz": "739bf07f42374a1e272cdd0639311c65897e230bed3336b217f616b7479ae905", + "dist/2021-11-01/rust-std-1.56.1-mipsel-unknown-linux-gnu.tar.xz": "b08ed2c414fda72493f6409b1a9b4505179a531ffeb157c20581474f7f1c7c15", + "dist/2021-11-01/rust-std-1.56.1-mipsel-unknown-linux-musl.tar.gz": "c6907e51847bbe1aa527375a4ad8ff1c1747d2b86ba05677960c047f3a3918c9", + "dist/2021-11-01/rust-std-1.56.1-mipsel-unknown-linux-musl.tar.xz": "851461985a31ca5f5879db3a6a86ee651e3e7f3b7214e0bcfdb7aadabd1276fe", + "dist/2021-11-01/rust-std-1.56.1-nvptx64-nvidia-cuda.tar.gz": "464903fbec2740f996ff0507bbeac45231cdc031397d5620d73090dcd4c48d2d", + "dist/2021-11-01/rust-std-1.56.1-nvptx64-nvidia-cuda.tar.xz": "fde4334b448ffcef5588aab776545e552b757612dcec25a4761f5992c30ae5ff", + "dist/2021-11-01/rust-std-1.56.1-powerpc-unknown-linux-gnu.tar.gz": "11d753855c461d220222824a5d4bdb31424251ff447e38657a7ad348d95908f5", + "dist/2021-11-01/rust-std-1.56.1-powerpc-unknown-linux-gnu.tar.xz": "0c1de91436fbe52ed9388f8d0bab4931a3fa19160e283361afd79acd5ef9ca7c", + "dist/2021-11-01/rust-std-1.56.1-powerpc64-unknown-linux-gnu.tar.gz": "b1a4ea580685fa9e4332f774e94d25d80713692d5e0c4659a01534bd479c8ae7", + "dist/2021-11-01/rust-std-1.56.1-powerpc64-unknown-linux-gnu.tar.xz": "1d74331e02088997cadd3c534aa1da4b34fdf0587b64770788e6efe08dd63dba", + "dist/2021-11-01/rust-std-1.56.1-powerpc64le-unknown-linux-gnu.tar.gz": "d9c8b33f38d6acd73529e3658f8044316144e9a5a8a79eba66747f64d99c256e", + "dist/2021-11-01/rust-std-1.56.1-powerpc64le-unknown-linux-gnu.tar.xz": "0bda1a2e91c9a471e907bd34b75859c1b152e03f1509344a927fba214c4c5bc6", + "dist/2021-11-01/rust-std-1.56.1-riscv32i-unknown-none-elf.tar.gz": "140c35c4f7502690e0065411ede32cdc3a1e7e40003a985db5e746cb2e69d1c6", + "dist/2021-11-01/rust-std-1.56.1-riscv32i-unknown-none-elf.tar.xz": "b044c51563843b4d7f970a31b0ddd7d5f4a15bc2818762021b8fcaef2ae9c740", + "dist/2021-11-01/rust-std-1.56.1-riscv32imac-unknown-none-elf.tar.gz": "adecc46de4ba90d4d71cfd441a566138d8fcb1dcf028faa8e4e7eaad3a5d56dc", + "dist/2021-11-01/rust-std-1.56.1-riscv32imac-unknown-none-elf.tar.xz": "4fc9d42a749deb606a76a36a6cd1dc4df3cc6ec46378fe230b704f7f5a7e3e14", + "dist/2021-11-01/rust-std-1.56.1-riscv32imc-unknown-none-elf.tar.gz": "517c934d61cc96264b37f2fe08b9e12b8d5d1c700940dc4622ccea7a3472e154", + "dist/2021-11-01/rust-std-1.56.1-riscv32imc-unknown-none-elf.tar.xz": "2d040592fec1de79ccca2e2dc18089886ab69884a82ea014b6cbe458c3e3277d", + "dist/2021-11-01/rust-std-1.56.1-riscv64gc-unknown-linux-gnu.tar.gz": "76e04d6afa8ae6e983ea7f0aeb98594e0ff228e0872f388d3de806bb7c3519b9", + "dist/2021-11-01/rust-std-1.56.1-riscv64gc-unknown-linux-gnu.tar.xz": "fe5b7b7a14588101a09cf4d9bbe421ae8b071231a791f96ace22b9eaa5875756", + "dist/2021-11-01/rust-std-1.56.1-riscv64gc-unknown-none-elf.tar.gz": "b6c3049fcb6b559176cb4f4c75a4ca01cad61b972e500c7485e58918ed8ddc0e", + "dist/2021-11-01/rust-std-1.56.1-riscv64gc-unknown-none-elf.tar.xz": "649fe72f7d519dda2410e60f7e61ce1ffd692a102a35f05402a842231afa63dc", + "dist/2021-11-01/rust-std-1.56.1-riscv64imac-unknown-none-elf.tar.gz": "fcf27d893b5bdd08b55481b85a8990d893b408abddd9b57dda6c19aa95bc8c80", + "dist/2021-11-01/rust-std-1.56.1-riscv64imac-unknown-none-elf.tar.xz": "ff302ff438f710eb75633ed7426ed050e8e0c7edaee84eafb6fabba6c72a1cd5", + "dist/2021-11-01/rust-std-1.56.1-s390x-unknown-linux-gnu.tar.gz": "531f7a2f22df9e91cf6efc01b3d0b58e3b96afbc93090a1716cdcbc904cc3dcf", + "dist/2021-11-01/rust-std-1.56.1-s390x-unknown-linux-gnu.tar.xz": "c3526a691da0a2877225727f60798130dcb2ff00bcf97f0a5b391ccb85eb092e", + "dist/2021-11-01/rust-std-1.56.1-sparc64-unknown-linux-gnu.tar.gz": "cab263b4634f82b2d47bb806570ee9c8798e737ea84e555ef98d5f746e0d24fb", + "dist/2021-11-01/rust-std-1.56.1-sparc64-unknown-linux-gnu.tar.xz": "b607cc4a489d40ecbee50a926ebe49fba4e1ab25528be0d43b182d6245f3369c", + "dist/2021-11-01/rust-std-1.56.1-sparcv9-sun-solaris.tar.gz": "06da09aede77790c98a0a87aca4f1b4fef76cb14037a554d585a6b023b84c4f2", + "dist/2021-11-01/rust-std-1.56.1-sparcv9-sun-solaris.tar.xz": "aa9110244da119b3611836ff8ed4d2e12361925118d4b0692cde1acf39cbd444", + "dist/2021-11-01/rust-std-1.56.1-thumbv6m-none-eabi.tar.gz": "375e97ad8f5895ead09798f666377c50833bd3443614de2abf05929d5599fee8", + "dist/2021-11-01/rust-std-1.56.1-thumbv6m-none-eabi.tar.xz": "591dfff0d8bc3e2a699975e8145cf420f0637f9c5b4862f7a3f68c531b608e71", + "dist/2021-11-01/rust-std-1.56.1-thumbv7em-none-eabi.tar.gz": "7081fa371997641bb8b3f1b1850efe41daebb27e9ec13a8dfad0eac8161c8fdd", + "dist/2021-11-01/rust-std-1.56.1-thumbv7em-none-eabi.tar.xz": "0516f076e3ddb9aa8380ecf4baf607a39b0ab2c9184ecdc5c29d71b328a0c7bd", + "dist/2021-11-01/rust-std-1.56.1-thumbv7em-none-eabihf.tar.gz": "dc0f66f3065565f664fe70e907303b6c5f031e999cf8313c6a02975517b96b0a", + "dist/2021-11-01/rust-std-1.56.1-thumbv7em-none-eabihf.tar.xz": "ca2cc134e2b3698764b4ba71d979709fb7f689030c3468de62c087c079f8ec5c", + "dist/2021-11-01/rust-std-1.56.1-thumbv7m-none-eabi.tar.gz": "8d10efbaa6ea8002e164d199ded6262a65259291cbef60c43fe5e06eeae2a104", + "dist/2021-11-01/rust-std-1.56.1-thumbv7m-none-eabi.tar.xz": "833dffcdc9fde44a935a3ba6f2157ae54daf96932109f879602c4bdaf5e4b772", + "dist/2021-11-01/rust-std-1.56.1-thumbv7neon-linux-androideabi.tar.gz": "04c2b78fc9e8bce32ae501e7218f1f327051da8f2c345b9efd624efd4bc1f494", + "dist/2021-11-01/rust-std-1.56.1-thumbv7neon-linux-androideabi.tar.xz": "fe3830203073eec0e4631ed4f7d2292fb86751d222833ca92815ae56200d1c10", + "dist/2021-11-01/rust-std-1.56.1-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "9604c64703da0795ccd8e44970beace05e7c97612b060d0b36d15ce0feb64dd4", + "dist/2021-11-01/rust-std-1.56.1-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "73f20b47af9f9c13dae8955a6118e990c2ae060b81a428cd56d093f064b0944b", + "dist/2021-11-01/rust-std-1.56.1-thumbv8m.base-none-eabi.tar.gz": "27c9783e294f51a25f1de9a79b24ba057c462bd340cc07e4785be1e644bdb242", + "dist/2021-11-01/rust-std-1.56.1-thumbv8m.base-none-eabi.tar.xz": "64a4bf70b1ab301a5f0e9b5e7b1c632a3e53c9519512df5553a50e6d2cde0d2b", + "dist/2021-11-01/rust-std-1.56.1-thumbv8m.main-none-eabi.tar.gz": "21eb29cd9597cbd5b52ebdb48a01ac8e38bb675c9ecb7f9c928b3a2b73c65a58", + "dist/2021-11-01/rust-std-1.56.1-thumbv8m.main-none-eabi.tar.xz": "77c3fe1b10fcf7c630371ab6064a7300b1befea2cbc2e20c5c7defee0acde15a", + "dist/2021-11-01/rust-std-1.56.1-thumbv8m.main-none-eabihf.tar.gz": "5c2cd41b5047f83f3c1d67b8454fc43e42203493e003db9cf0aae150e5d4d32d", + "dist/2021-11-01/rust-std-1.56.1-thumbv8m.main-none-eabihf.tar.xz": "b84061540ca71fad799ff9398fbf6b5874dcbb8adbd478729d5be1abf9e7de35", + "dist/2021-11-01/rust-std-1.56.1-wasm32-unknown-emscripten.tar.gz": "f318d3bf38ce83e3f3531114ba59af31c853cbdb5720d8804ae77970e40048dc", + "dist/2021-11-01/rust-std-1.56.1-wasm32-unknown-emscripten.tar.xz": "7f437a469dd0adcb9041b1cb0413a4f7e80531b67dc88347001a9096632a0ab8", + "dist/2021-11-01/rust-std-1.56.1-wasm32-unknown-unknown.tar.gz": "4e62beca963a5b8c98913dd10abc493126675a0a35c2817afdf6975a49cc1bce", + "dist/2021-11-01/rust-std-1.56.1-wasm32-unknown-unknown.tar.xz": "4ad9c1d9eb00c2dc569f6e2b5ca5acd715db02db3456af08ba61d00f40e3a0fd", + "dist/2021-11-01/rust-std-1.56.1-wasm32-wasi.tar.gz": "a7eaf9bf238671f7a54afe00cd76dbb354933e525ab5bceb10d156a2bc414dd7", + "dist/2021-11-01/rust-std-1.56.1-wasm32-wasi.tar.xz": "c5ae515041a447a94de4d7f9559f82e70fcc7b48571bfb26d9866dcb2fa5cfa6", + "dist/2021-11-01/rust-std-1.56.1-x86_64-apple-darwin.tar.gz": "a1cedfaea1508bf3bfc8a77d82d15c693b41e70e56fad930d24f21f0bce5052a", + "dist/2021-11-01/rust-std-1.56.1-x86_64-apple-darwin.tar.xz": "5e58c2ecb19b09dd56637bd21813fd76778aee2be3104d324b62bc6c4ec3c46d", + "dist/2021-11-01/rust-std-1.56.1-x86_64-apple-ios.tar.gz": "68fec8fd73357d2da75027eed38858cbe64e174a59bc0aeea133aa74f554bcac", + "dist/2021-11-01/rust-std-1.56.1-x86_64-apple-ios.tar.xz": "dea687c9e1c33351d03fb8fe3f0141c56f9e0965938d4e16566a662197719ecb", + "dist/2021-11-01/rust-std-1.56.1-x86_64-fortanix-unknown-sgx.tar.gz": "c5e30e097b86df00c90149cc221c450b5a687608d489537b1808a72ac720ef98", + "dist/2021-11-01/rust-std-1.56.1-x86_64-fortanix-unknown-sgx.tar.xz": "ca51c524f939eb8cdb73421e9dd9cc1640e3ff5e89fa453bdfde7d0a07c760cf", + "dist/2021-11-01/rust-std-1.56.1-x86_64-fuchsia.tar.gz": "ae37eaf74470b57448fc03bd199d558cc9e00bafc9c41cef16eb89bdda786b9e", + "dist/2021-11-01/rust-std-1.56.1-x86_64-fuchsia.tar.xz": "0e2de360c1066f78d5d9a405dafe934f204728968f4103cae68e826ba5122c46", + "dist/2021-11-01/rust-std-1.56.1-x86_64-linux-android.tar.gz": "9bd1ef68894d68c4d33a0344ddf2ccce2469e4c9a5ced235459e33f76e789063", + "dist/2021-11-01/rust-std-1.56.1-x86_64-linux-android.tar.xz": "272d6eaef8259ea9fd4b51e84976135f885a04314feffedaad18b84828b479f0", + "dist/2021-11-01/rust-std-1.56.1-x86_64-pc-solaris.tar.gz": "f8718bba856c0569ac14ae99cc83206617161f68a1f775163962385145c437f8", + "dist/2021-11-01/rust-std-1.56.1-x86_64-pc-solaris.tar.xz": "1fa68f6aec421592e23fee0d0b2c203417f0bc9444b2aa9e690c76d806242ec1", + "dist/2021-11-01/rust-std-1.56.1-x86_64-pc-windows-gnu.tar.gz": "8c5d425d2882a93827850672a70bfc2e643cae425aaffa9dafa6808fcd4bc798", + "dist/2021-11-01/rust-std-1.56.1-x86_64-pc-windows-gnu.tar.xz": "3cefe2bdf19d8edbc4bb124c541770b200cf5f19f2129c9cdf1e1361dbaa9b1a", + "dist/2021-11-01/rust-std-1.56.1-x86_64-pc-windows-msvc.tar.gz": "ace5ea90e70b9d035b28b405175d52e1796fb1bb36cfbdead1048ff00e9ec1fe", + "dist/2021-11-01/rust-std-1.56.1-x86_64-pc-windows-msvc.tar.xz": "064e4e9a030057c20e398c2f4c46e6e5e2d3b493b5e677c2e5e32fe77d1ecfb2", + "dist/2021-11-01/rust-std-1.56.1-x86_64-sun-solaris.tar.gz": "4c7182fffa8f7ef456c01babdb50b64fd608fe7c6ec28909d34b2d508a1bc85a", + "dist/2021-11-01/rust-std-1.56.1-x86_64-sun-solaris.tar.xz": "46f1b3f6c440d0549c6187b92aa89afe03dd3dc2ccb378a085205544496fafdd", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-freebsd.tar.gz": "1382799af56e1ec48cf3971f84122c9d445996422055b822d9d6226a31a20737", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-freebsd.tar.xz": "8ae63f5c03a8d8a60be62dc536672b6ae8e5259837cf2a543f1c4c30d4cbb5e6", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-illumos.tar.gz": "171b2e2600d091aa2e3c9bdf4c8336f29582c42dc894341418fef83e22141599", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-illumos.tar.xz": "d7b3fdda726a014434a3944b7e1136cc6e97a34cd223f8a9fc08e79e14e01b1b", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-linux-gnu.tar.gz": "afd959b295e17640d1e94648278a944dc5f349ebdd9e59e2404729db0810c531", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-linux-gnu.tar.xz": "b01011cbb5503c456ecc6a557a38e099994b8497df545c661ce8fd48c5beadc6", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-linux-gnux32.tar.gz": "059c7db359dbcffb77f236fd59ed757478f7a817d715eb5554f53309dfa13109", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-linux-gnux32.tar.xz": "338ae41e07c6e07fa929cff76d957f806bd3276a1a54140041ac720a4bb1d2fd", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-linux-musl.tar.gz": "88bfd0dce45d4321b0781550a300f90da5344dda20744219b6b23072b6cb03af", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-linux-musl.tar.xz": "055c5f8676712d8b86c3685d857d45bc0757594cb59f04dce4949a91df99635c", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-netbsd.tar.gz": "76eeb1ae5d876c8cbda6994806892597e48fa49adc01ed47228961c5508daa22", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-netbsd.tar.xz": "a4adabe39a73919957235629a9df3beb61353e829442f6e44f1c605fe5cddae3", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-redox.tar.gz": "ddfead63d5d9c4ee589684068156edf00ad50bbe680f1e000e821b2279a753d6", + "dist/2021-11-01/rust-std-1.56.1-x86_64-unknown-redox.tar.xz": "a50ea76404efc7fc49ac79ecf9ad4962bd914c52061687fee5b343e25e71a215", + "dist/2021-11-01/rustc-1.56.1-aarch64-apple-darwin.tar.gz": "fcb2c2e46e3cc7e7cba3abbb78ba87131aea56770145f8d97944b675a491312a", + "dist/2021-11-01/rustc-1.56.1-aarch64-apple-darwin.tar.xz": "b68f42d3d5ef3c88ac21f5958149a25bacc4144c69a5d6b04ed3d05530265817", + "dist/2021-11-01/rustc-1.56.1-aarch64-pc-windows-msvc.tar.gz": "c02a963a7635e2971c500125fcd3c3f2f5fad87262007af1456fc520c866e60c", + "dist/2021-11-01/rustc-1.56.1-aarch64-pc-windows-msvc.tar.xz": "d715013ab58c18219cb735861484e1d728a50f36370ac6c635f2f771d51b64fe", + "dist/2021-11-01/rustc-1.56.1-aarch64-unknown-linux-gnu.tar.gz": "9e7461908d0b3e6f4bbb158b71d85e536c186fe571c9960f8ef4300328b25a11", + "dist/2021-11-01/rustc-1.56.1-aarch64-unknown-linux-gnu.tar.xz": "77aec6a8c5f3d33941c79a48cda3bb08878c23dd1947dc027dfe5c4da41305b3", + "dist/2021-11-01/rustc-1.56.1-aarch64-unknown-linux-musl.tar.gz": "1e913b7f39d0f478c48ff9b9dd6a05dfe67a6ad58e478509cafb20e106512965", + "dist/2021-11-01/rustc-1.56.1-aarch64-unknown-linux-musl.tar.xz": "d8e7e6b9a9f07b9a9f3c080d9fd2ab93684776b8e0434bb06c147ce626adef05", + "dist/2021-11-01/rustc-1.56.1-arm-unknown-linux-gnueabi.tar.gz": "509796815de3cde667a1c253d9255e4fd9af13c835ffefaf11c853edc75b0c77", + "dist/2021-11-01/rustc-1.56.1-arm-unknown-linux-gnueabi.tar.xz": "4030921274328ce7e3fcc2a7aed19d09d28831eb4d426200a5749bd698c51589", + "dist/2021-11-01/rustc-1.56.1-arm-unknown-linux-gnueabihf.tar.gz": "3d542c8c14c5f103ba8a8a685a22a7658efdff1ca06adc99a6639b20fbda0abd", + "dist/2021-11-01/rustc-1.56.1-arm-unknown-linux-gnueabihf.tar.xz": "2507cdd49bd7f5c07d4b351b933d172bd92f53718569bb2fc7de506cd1750dab", + "dist/2021-11-01/rustc-1.56.1-armv7-unknown-linux-gnueabihf.tar.gz": "bbbe46c312c9355c1689d4dbce1c8291d9827a91ae69eea7754f789dcdccc37c", + "dist/2021-11-01/rustc-1.56.1-armv7-unknown-linux-gnueabihf.tar.xz": "6ca09ce8d5170162135817da08866a7d0afbb68bea46220882cea68c5a3d35df", + "dist/2021-11-01/rustc-1.56.1-i686-pc-windows-gnu.tar.gz": "81ab13668fc09e79a9a50bd2dc264063aa0a02be81608bee34a0c0bd1cb00645", + "dist/2021-11-01/rustc-1.56.1-i686-pc-windows-gnu.tar.xz": "dd7353dd36878caee807fafd8f88f74519107e0e69812190f86df9a84c1ebb43", + "dist/2021-11-01/rustc-1.56.1-i686-pc-windows-msvc.tar.gz": "2a7356c843eca8619b18d01e22f498879a2b3d6f3a30a620c989a1941bd4bf05", + "dist/2021-11-01/rustc-1.56.1-i686-pc-windows-msvc.tar.xz": "88344ed564c825f06d5a2666cb0be330d55855ecf887d287479ccaf50b50fea2", + "dist/2021-11-01/rustc-1.56.1-i686-unknown-linux-gnu.tar.gz": "a6ce2439963fd848199347fb75b323f9d1b7e1a6fa5b1d02cd741322a582ad65", + "dist/2021-11-01/rustc-1.56.1-i686-unknown-linux-gnu.tar.xz": "ac97b1887881d3703635d1118977d53b54d24a24899d79e3b1a13c92adbcb317", + "dist/2021-11-01/rustc-1.56.1-mips-unknown-linux-gnu.tar.gz": "33523515ad417544a50a9339702a5227a41debefdd06708897aeff7936c617e2", + "dist/2021-11-01/rustc-1.56.1-mips-unknown-linux-gnu.tar.xz": "02d46cabdbfe64a2ccb7fed78097352b8ec6d98a1912c8a319ca9474da7260bf", + "dist/2021-11-01/rustc-1.56.1-mips64-unknown-linux-gnuabi64.tar.gz": "3446859f0028eab1289602d3f020e4f98356d6881639264de658d87763844a46", + "dist/2021-11-01/rustc-1.56.1-mips64-unknown-linux-gnuabi64.tar.xz": "11a5eff326595db4ed8f4c3e642a4d3cdbdc226a68044d55f077873dcb67ca05", + "dist/2021-11-01/rustc-1.56.1-mips64el-unknown-linux-gnuabi64.tar.gz": "0c582b3bd06c04d0de33124c6096d61cac65cae159fbc39e7fd84b595075d1cb", + "dist/2021-11-01/rustc-1.56.1-mips64el-unknown-linux-gnuabi64.tar.xz": "06fd3d739d074f44f08bcc308d2b4866cc8f347043ebfc61044fb6a515f214a1", + "dist/2021-11-01/rustc-1.56.1-mipsel-unknown-linux-gnu.tar.gz": "91e59e111fb5a10abdcfb1d65881b8159e514216da3076433a64fd5bb29eb2e8", + "dist/2021-11-01/rustc-1.56.1-mipsel-unknown-linux-gnu.tar.xz": "357f728b7c592f8b994641eeed9b7c732bf2cb2bea34a06a60bfa1c8c2dc1bc0", + "dist/2021-11-01/rustc-1.56.1-powerpc-unknown-linux-gnu.tar.gz": "10306ea9eee418341d2c6160b4f4135f5d921acaaf5bee9687f85297f9750539", + "dist/2021-11-01/rustc-1.56.1-powerpc-unknown-linux-gnu.tar.xz": "3837b4377cad3e539f8679d8c420423fe9a5015b83fc8a697c49cfaf8edee4ce", + "dist/2021-11-01/rustc-1.56.1-powerpc64-unknown-linux-gnu.tar.gz": "e0ff6e79744753642b0b7eec91ec9d4769c26563e7ef6b5ae2b3b1b8ba221eec", + "dist/2021-11-01/rustc-1.56.1-powerpc64-unknown-linux-gnu.tar.xz": "07e8078e131aac48ecc68b7dbf82061cd1cbcc6764016464f5535b4eb4b95ae4", + "dist/2021-11-01/rustc-1.56.1-powerpc64le-unknown-linux-gnu.tar.gz": "0517345c67aa77eef9a7facffd28d679655e9d453892d61bfc9d8c09ff8e9dce", + "dist/2021-11-01/rustc-1.56.1-powerpc64le-unknown-linux-gnu.tar.xz": "96c6accf1829ebaeedddb3998e53d10439d9e566970b3f8c89c4026421e75277", + "dist/2021-11-01/rustc-1.56.1-riscv64gc-unknown-linux-gnu.tar.gz": "8ec8ae0c1ea281d99eb83f93bfc8e38d8c6ffac20d5b18004e3d2bbeaa362f1b", + "dist/2021-11-01/rustc-1.56.1-riscv64gc-unknown-linux-gnu.tar.xz": "a14b25c11f929ecc6e6aee3ce2a608d054f5349453304f3fb41e020d8fcf0ab1", + "dist/2021-11-01/rustc-1.56.1-s390x-unknown-linux-gnu.tar.gz": "6bdd92400c1f150009215fd5122c6ac9f1b5ed59a055e8268169115313f792ed", + "dist/2021-11-01/rustc-1.56.1-s390x-unknown-linux-gnu.tar.xz": "0b6edfc6aeb8d390afdc1ee18a921fd2ea7bdbdb9c7e1a6ed61d4198db9cdb8f", + "dist/2021-11-01/rustc-1.56.1-x86_64-apple-darwin.tar.gz": "876b9ed13a71ada3c00878c6006d837b852973cba84419753445c8a8a76efe00", + "dist/2021-11-01/rustc-1.56.1-x86_64-apple-darwin.tar.xz": "aa7f98ef0cbf1cd3e983d8240474d381c800e25c33522532abf03fb960c065d6", + "dist/2021-11-01/rustc-1.56.1-x86_64-pc-windows-gnu.tar.gz": "c901b2ea9d6cc460b4e726ea0acf97a604cd50594f57470d10e848eed7cc557d", + "dist/2021-11-01/rustc-1.56.1-x86_64-pc-windows-gnu.tar.xz": "8c6add5c7068ff8d958292e17efb76c4064373d45283bf68075fee1220317435", + "dist/2021-11-01/rustc-1.56.1-x86_64-pc-windows-msvc.tar.gz": "709fa5ad9723e233025ab0cd142b628cd8a4bb8d11fcdbb97a779d78a60604e5", + "dist/2021-11-01/rustc-1.56.1-x86_64-pc-windows-msvc.tar.xz": "68970f47f8eb37b683521c97ce1e9fc711bb526a8474c8950b798fb5f5482412", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-freebsd.tar.gz": "b6a440bf5c3b1e4930effc07c6e50bf03cc44c0465f0c379d626b800f4971700", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-freebsd.tar.xz": "630a2d54a614c7d2b2f57f83c8d36c9b037299b42233e267bfedb05ef178de28", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-illumos.tar.gz": "4dbb2778c2210c4f02a8e4b8088b087f0b1141adbe466e82197f23cdbc839573", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-illumos.tar.xz": "b9eb72e9f112c691000daabe4e4ba1964d21e6fb8e0dd2c1d5595b6bb542c609", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-linux-gnu.tar.gz": "d09557a497a4f3b0726cae4c8e193843e403c80615f25f6ef740c79d7e4c122b", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-linux-gnu.tar.xz": "a7001d1218b62d377cab15522d1b1c376b073c05f7d0ff32cf278871a5eeda3d", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-linux-musl.tar.gz": "b49ef5d9d8a2c49e48dda8bf08fc5a95ac87095a8895df9dbce0ecfb1a97c70a", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-linux-musl.tar.xz": "1b1f83b69502240ea66a45426bb1ba3a7c1291b05c31b59a28ac0551933e1210", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-netbsd.tar.gz": "a79a181ea75bd0ed282cff60c42b4abad1126f7ea62f46c5f648866cb1a2815f", + "dist/2021-11-01/rustc-1.56.1-x86_64-unknown-netbsd.tar.xz": "58ab590c0421689b4bbe7f41918a508e3640d68e9ad98798d810a12dc16d8780" + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/stage0.txt rustc-1.57.0+dfsg1+llvm/src/stage0.txt --- rustc-1.56.0+dfsg1+llvm/src/stage0.txt 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/stage0.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -# This file describes the stage0 compiler that's used to then bootstrap the Rust -# compiler itself. -# -# Currently Rust always bootstraps from the previous stable release, and in our -# train model this means that the master branch bootstraps from beta, beta -# bootstraps from current stable, and stable bootstraps from the previous stable -# release. -# -# If you're looking at this file on the master branch, you'll likely see that -# rustc is configured to `beta`, whereas if you're looking at a source tarball -# for a stable release you'll likely see `1.x.0` for rustc, with the previous -# stable release's version number. `date` is the date where the release we're -# bootstrapping off was released. - -date: 2021-09-09 -rustc: 1.55.0 - -# We use a nightly rustfmt to format the source because it solves some -# bootstrapping issues with use of new syntax in this repo. If you're looking at -# the beta/stable branch, this key should be omitted, as we don't want to depend -# on rustfmt from nightly there. -#rustfmt: nightly-2021-03-25 - -# When making a stable release the process currently looks like: -# -# 1. Produce stable build, upload it to dev-static -# 2. Produce a beta build from the previous stable build, upload to static -# 3. Produce a nightly build from previous beta, upload to static -# 4. Upload stable build to static, publish full release -# -# This means that there's a small window of time (a few days) where artifacts -# are downloaded from dev-static.rust-lang.org instead of static.rust-lang.org. -# In order to ease this transition we have an extra key which is in the -# configuration file below. When uncommented this will instruct the bootstrap.py -# script to download from dev-static.rust-lang.org. -# -# This key is typically commented out at all times. If you're looking at a -# stable release tarball it should *definitely* be commented out. If you're -# looking at a beta source tarball and it's uncommented we'll shortly comment it -# out. - -#dev: 1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/assembly/asm/aarch64-outline-atomics.rs rustc-1.57.0+dfsg1+llvm/src/test/assembly/asm/aarch64-outline-atomics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/assembly/asm/aarch64-outline-atomics.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/assembly/asm/aarch64-outline-atomics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +// min-llvm-version: 12.0 +// assembly-output: emit-asm +// compile-flags: -O +// compile-flags: --target aarch64-unknown-linux-gnu +// needs-llvm-components: aarch64 +// only-aarch64 +// only-linux + +#![crate_type = "rlib"] + +use std::sync::atomic::{AtomicI32, Ordering::*}; + +pub fn compare_exchange(a: &AtomicI32) { + // On AArch64 LLVM should outline atomic operations. + // CHECK: __aarch64_cas4_relax + let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/assembly/asm/bpf-types.rs rustc-1.57.0+dfsg1+llvm/src/test/assembly/asm/bpf-types.rs --- rustc-1.56.0+dfsg1+llvm/src/test/assembly/asm/bpf-types.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/assembly/asm/bpf-types.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -// min-llvm-version: 10.0.1 +// min-llvm-version: 13.0 // assembly-output: emit-asm // compile-flags: --target bpfel-unknown-none -C target_feature=+alu32 // needs-llvm-components: bpf diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/assembly/niche-prefer-zero.rs rustc-1.57.0+dfsg1+llvm/src/test/assembly/niche-prefer-zero.rs --- rustc-1.56.0+dfsg1+llvm/src/test/assembly/niche-prefer-zero.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/assembly/niche-prefer-zero.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,25 @@ +// Check that niche selection prefers zero and that jumps are optimized away. +// See https://github.com/rust-lang/rust/pull/87794 +// assembly-output: emit-asm +// only-x86 +// compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[repr(u8)] +pub enum Size { + One = 1, + Two = 2, + Three = 3, +} + +#[no_mangle] +pub fn handle(x: Option) -> u8 { + match x { + None => 0, + Some(size) => size as u8, + } +} + +// There should be no jumps in output +// CHECK-NOT: j diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/assembly/pic-relocation-model.rs rustc-1.57.0+dfsg1+llvm/src/test/assembly/pic-relocation-model.rs --- rustc-1.56.0+dfsg1+llvm/src/test/assembly/pic-relocation-model.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/assembly/pic-relocation-model.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,35 @@ +// revisions: x64 +// assembly-output: emit-asm +// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pic +// [x64] needs-llvm-components: x86 + + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type="rlib"] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +// CHECK-LABEL: call_other_fn: +// CHECK: {{(jmpq|callq)}} *other_fn@GOTPCREL(%rip) +#[no_mangle] +pub fn call_other_fn() -> u8 { + unsafe { + other_fn() + } +} + +// CHECK-LABEL: other_fn: +// CHECK: callq *foreign_fn@GOTPCREL(%rip) +#[no_mangle] +#[inline(never)] +pub fn other_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +extern "C" {fn foreign_fn() -> u8;} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/assembly/pie-relocation-model.rs rustc-1.57.0+dfsg1+llvm/src/test/assembly/pie-relocation-model.rs --- rustc-1.56.0+dfsg1+llvm/src/test/assembly/pie-relocation-model.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/assembly/pie-relocation-model.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,38 @@ +// revisions: x64 +// assembly-output: emit-asm +// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pie +// [x64] needs-llvm-components: x86 + + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type="rlib"] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +// CHECK-LABEL: call_other_fn: +// With PIE local functions are called "directly". +// CHECK: {{(jmp|callq)}} other_fn +#[no_mangle] +pub fn call_other_fn() -> u8 { + unsafe { + other_fn() + } +} + +// CHECK-LABEL: other_fn: +// External functions are still called through GOT, since we don't know if the symbol +// is defined in the binary or in the shared library. +// CHECK: callq *foreign_fn@GOTPCREL(%rip) +#[no_mangle] +#[inline(never)] +pub fn other_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +extern "C" {fn foreign_fn() -> u8;} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/assembly/x86_64-sse_crc.rs rustc-1.57.0+dfsg1+llvm/src/test/assembly/x86_64-sse_crc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/assembly/x86_64-sse_crc.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/assembly/x86_64-sse_crc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// only-x86_64 +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib -Ctarget-feature=+sse4.2 + +// CHECK-LABEL: banana +// CHECK: crc32 +#[no_mangle] +pub unsafe fn banana(v: u8) -> u32 { + use std::arch::x86_64::*; + let out = !0u32; + _mm_crc32_u8(out, v) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen/alloc-optimisation.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen/alloc-optimisation.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen/alloc-optimisation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen/alloc-optimisation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,5 @@ // +// no-system-llvm // min-llvm-version: 10.0.1 // compile-flags: -O #![crate_type="lib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen/debug-vtable.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen/debug-vtable.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen/debug-vtable.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen/debug-vtable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,57 @@ +// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Ccodegen-units=1 +// ignore-tidy-linelength + +// This test checks the debuginfo for the expected 3 vtables is generated for correct names and number +// of entries. + +// NONMSVC-LABEL: !DIGlobalVariable(name: "::{vtable}" +// MSVC-LABEL: !DIGlobalVariable(name: "impl$::vtable$" +// NONMSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()", +// MSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$ >", +// CHECK: !DISubrange(count: 5 + +// NONMSVC-LABEL: !DIGlobalVariable(name: ">::{vtable}" +// MSVC-LABEL: !DIGlobalVariable(name: "impl$ >::vtable$" +// CHECK: !DISubrange(count: 4 + +// NONMSVC-LABEL: !DIGlobalVariable(name: "::{vtable}" +// MSVC-LABEL: !DIGlobalVariable(name: "impl$::vtable$" +// CHECK: !DISubrange(count: 3 + +// NONMSVC-LABEL: !DIGlobalVariable(name: ">)>>::{vtable}" +// MSVC-LABEL: !DIGlobalVariable(name: "impl$,assoc$ > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$" + +#![crate_type = "lib"] + +pub struct Foo; + +pub trait SomeTrait { + fn method1(&self) -> u32; + fn method2(&self) -> u32; +} + +impl SomeTrait for Foo { + fn method1(&self) -> u32 { 1 } + fn method2(&self) -> u32 { 2 } +} + +pub trait SomeTraitWithGenerics { + fn method1(&self) -> (T, U); +} + +impl SomeTraitWithGenerics for Foo { + fn method1(&self) -> (u64, i8) { (1, 2) } +} + +pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) { + let y: &dyn SomeTrait = x; + let z: &dyn SomeTraitWithGenerics = x; + (y.method1(), z.method1(), x as &dyn Send) +} + +// Constructing the debuginfo name for the FnOnce vtable below initially caused an ICE on MSVC +// because the trait type contains a late bound region that needed to be erased before the type +// layout for the niche enum `Option<&dyn Fn()>` could be computed. +pub fn bar() -> Box)> { + Box::new(|_x: Option<&dyn Fn()>| {}) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen/intrinsics/const_eval_select.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen/intrinsics/const_eval_select.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen/intrinsics/const_eval_select.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen/intrinsics/const_eval_select.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(const_eval_select)] + +use std::intrinsics::const_eval_select; + +const fn foo(_: i32) -> i32 { 1 } + +#[no_mangle] +pub fn hi(n: i32) -> i32 { n } + +#[no_mangle] +pub unsafe fn hey() { + // CHECK: call i32 @hi(i32 + const_eval_select((42,), foo, hi); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen/panic-in-drop-abort.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen/panic-in-drop-abort.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen/panic-in-drop-abort.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen/panic-in-drop-abort.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,59 @@ +// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no + +// Ensure that unwinding code paths are eliminated from the output after +// optimization. + +// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen +// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that +// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we +// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC +// targets. We should either forbid longjmps, or not assume nounwind, making this optimization +// incompatible with the current behavior of running cleanuppads on longjmp unwinding. + +// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output + +#![crate_type = "lib"] +use std::any::Any; +use std::mem::forget; + +pub struct ExternDrop; +impl Drop for ExternDrop { + #[inline(always)] + fn drop(&mut self) { + // This call may potentially unwind. + extern "Rust" { + fn extern_drop(); + } + unsafe { + extern_drop(); + } + } +} + +struct AssertNeverDrop; +impl Drop for AssertNeverDrop { + #[inline(always)] + fn drop(&mut self) { + // This call should be optimized away as unreachable. + extern "C" { + fn should_not_appear_in_output(); + } + unsafe { + should_not_appear_in_output(); + } + } +} + +#[no_mangle] +pub fn normal_drop(x: ExternDrop) { + let guard = AssertNeverDrop; + drop(x); + forget(guard); +} + +#[no_mangle] +pub fn indirect_drop(x: Box) { + let guard = AssertNeverDrop; + drop(x); + forget(guard); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen/pic-relocation-model.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen/pic-relocation-model.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen/pic-relocation-model.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen/pic-relocation-model.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// compile-flags: -C relocation-model=pic + +#![crate_type = "rlib"] + +// CHECK: define i8 @call_foreign_fn() +#[no_mangle] +pub fn call_foreign_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +// CHECK: declare zeroext i8 @foreign_fn() +extern "C" {fn foreign_fn() -> u8;} + +// CHECK: !{i32 7, !"PIC Level", i32 2} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen/pie-relocation-model.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen/pie-relocation-model.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen/pie-relocation-model.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen/pie-relocation-model.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +// compile-flags: -C relocation-model=pie +// only-x86_64-unknown-linux-gnu + +#![crate_type = "rlib"] + +// With PIE we know local functions cannot be interpositioned, we can mark them +// as dso_local. +// CHECK: define dso_local i8 @call_foreign_fn() +#[no_mangle] +pub fn call_foreign_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +// External functions are still marked as non-dso_local, since we don't know if the symbol +// is defined in the binary or in the shared library. +// CHECK: declare zeroext i8 @foreign_fn() +extern "C" {fn foreign_fn() -> u8;} + +// CHECK: !{i32 7, !"PIC Level", i32 2} +// CHECK: !{i32 7, !"PIE Level", i32 2} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen/sse42-implies-crc32.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen/sse42-implies-crc32.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen/sse42-implies-crc32.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen/sse42-implies-crc32.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// only-x86_64 +// min-llvm-version: 14.0 +// compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse4.2")] +#[no_mangle] +pub unsafe fn crc32sse(v: u8) -> u32 { + use std::arch::x86_64::*; + let out = !0u32; + _mm_crc32_u8(out, v) +} + +// CHECK: attributes #0 {{.*"target-features"="\+sse4.2,\+crc32"}} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen/vtabletype.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen/vtabletype.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen/vtabletype.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen/vtabletype.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -// This test depends on a patch that was committed to upstream LLVM -// after 5.0, then backported to the Rust LLVM fork. - -// ignore-windows -// ignore-macos - -// compile-flags: -g -C no-prepopulate-passes - -// CHECK-LABEL: @main -// CHECK: {{.*}}DICompositeType{{.*}}name: "vtable",{{.*}}vtableHolder:{{.*}} - -pub trait T { -} - -impl T for f64 { -} - -pub fn main() { - let d = 23.0f64; - let td = &d as &T; -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/extern-drop-glue.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/extern-drop-glue.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/extern-drop-glue.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/extern-drop-glue.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,10 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/extern-drop-glue +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus -Copt-level=0 #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/extern-generic.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/extern-generic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/extern-generic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/extern-generic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y +// incremental +// compile-flags:-Zprint-mono-items=eager -Zshare-generics=y #![allow(dead_code)] #![crate_type="lib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/incremental-merging.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/incremental-merging.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/incremental-merging.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/incremental-merging.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/incremental-merging +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Ccodegen-units=3 #![crate_type = "rlib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/inlining-from-extern-crate +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![crate_type="lib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-drop-glue.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-drop-glue.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-drop-glue.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-drop-glue.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,9 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-drop-glue +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus -Copt-level=0 #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-generic.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-generic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-generic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-generic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/local-generic +// incremental +// compile-flags:-Zprint-mono-items=eager #![allow(dead_code)] #![crate_type="lib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining-but-not-all +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus=no #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-inlining.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-inlining.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-inlining.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-inlining.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-transitive-inlining.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-transitive-inlining.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-transitive-inlining.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/local-transitive-inlining.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-transitive-inlining +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/methods-are-with-self-type.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/methods-are-with-self-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/methods-are-with-self-type.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/methods-are-with-self-type.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,9 +4,10 @@ // ignore-test // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/methods-are-with-self-type +// incremental +// compile-flags:-Zprint-mono-items=lazy #![allow(dead_code)] #![feature(start)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/regular-modules.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/regular-modules.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/regular-modules.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/regular-modules.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/regular-modules +// incremental +// compile-flags:-Zprint-mono-items=eager #![allow(dead_code)] #![crate_type="lib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/shared-generics.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/shared-generics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/shared-generics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/shared-generics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,8 @@ // no-prefer-dynamic // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels // prevent drop-glue from participating in share-generics. -// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Cincremental=tmp/partitioning-tests/shared-generics-exe -Copt-level=0 +// incremental +// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Copt-level=0 #![crate_type="rlib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/statics.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/statics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/statics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/statics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/statics +// incremental +// compile-flags:-Zprint-mono-items=lazy #![crate_type="rlib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/vtable-through-const.rs rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/vtable-through-const.rs --- rustc-1.56.0+dfsg1+llvm/src/test/codegen-units/partitioning/vtable-through-const.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/codegen-units/partitioning/vtable-through-const.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,9 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/vtable-through-const +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus // This test case makes sure, that references made through constants are diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/basic-types.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/basic-types.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/basic-types.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/basic-types.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,10 +9,6 @@ // This fails on lldb 6.0.1 on x86-64 Fedora 28; so ignore Linux for now. // ignore-linux -// This started failing in windows too. See https://github.com/rust-lang/rust/issues/88796 -// FIXME: fix and unignore this on windows -// ignore-windows - // compile-flags:-g // === GDB TESTS =================================================================================== @@ -132,8 +128,9 @@ // cdb-command:dx f64 // cdb-check:f64 : 3.500000 [Type: double] // cdb-command:.enable_unicode 1 +// FIXME(#88840): The latest version of the Windows SDK broke the visualizer for str. // cdb-command:dx s -// cdb-check:s : "Hello, World!" [Type: str] +// cdb-check:s : [...] [Type: str] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/borrowed-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/borrowed-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/borrowed-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/borrowed-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -63,7 +63,6 @@ // lldbr-check:(f64) *unique_val_interior_ref_2 = 26.5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -79,7 +78,7 @@ let stack_val_interior_ref_2: &f64 = &stack_val.y; let ref_to_unnamed: &SomeStruct = &SomeStruct { x: 11, y: 24.5 }; - let unique_val: Box<_> = box SomeStruct { x: 13, y: 26.5 }; + let unique_val: Box<_> = Box::new(SomeStruct { x: 13, y: 26.5 }); let unique_val_ref: &SomeStruct = &*unique_val; let unique_val_interior_ref_1: &isize = &unique_val.x; let unique_val_interior_ref_2: &f64 = &unique_val.y; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/borrowed-tuple.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/borrowed-tuple.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/borrowed-tuple.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/borrowed-tuple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -37,7 +37,6 @@ #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -46,7 +45,7 @@ let stack_val_ref: &(i16, f32) = &stack_val; let ref_to_unnamed: &(i16, f32) = &(-15, -20f32); - let unique_val: Box<(i16, f32)> = box (-17, -22f32); + let unique_val: Box<(i16, f32)> = Box::new((-17, -22f32)); let unique_val_ref: &(i16, f32) = &*unique_val; zzz(); // #break diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/borrowed-unique-basic.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/borrowed-unique-basic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/borrowed-unique-basic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/borrowed-unique-basic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -116,51 +116,50 @@ // lldbr-check:(f64) *f64_ref = 3.5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { - let bool_box: Box = box true; + let bool_box: Box = Box::new(true); let bool_ref: &bool = &*bool_box; - let int_box: Box = box -1; + let int_box: Box = Box::new(-1); let int_ref: &isize = &*int_box; - let char_box: Box = box 'a'; + let char_box: Box = Box::new('a'); let char_ref: &char = &*char_box; - let i8_box: Box = box 68; + let i8_box: Box = Box::new(68); let i8_ref: &i8 = &*i8_box; - let i16_box: Box = box -16; + let i16_box: Box = Box::new(-16); let i16_ref: &i16 = &*i16_box; - let i32_box: Box = box -32; + let i32_box: Box = Box::new(-32); let i32_ref: &i32 = &*i32_box; - let i64_box: Box = box -64; + let i64_box: Box = Box::new(-64); let i64_ref: &i64 = &*i64_box; - let uint_box: Box = box 1; + let uint_box: Box = Box::new(1); let uint_ref: &usize = &*uint_box; - let u8_box: Box = box 100; + let u8_box: Box = Box::new(100); let u8_ref: &u8 = &*u8_box; - let u16_box: Box = box 16; + let u16_box: Box = Box::new(16); let u16_ref: &u16 = &*u16_box; - let u32_box: Box = box 32; + let u32_box: Box = Box::new(32); let u32_ref: &u32 = &*u32_box; - let u64_box: Box = box 64; + let u64_box: Box = Box::new(64); let u64_ref: &u64 = &*u64_box; - let f32_box: Box = box 2.5; + let f32_box: Box = Box::new(2.5); let f32_ref: &f32 = &*f32_box; - let f64_box: Box = box 3.5; + let f64_box: Box = Box::new(3.5); let f64_ref: &f64 = &*f64_box; zzz(); // #break diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/boxed-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/boxed-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/boxed-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/boxed-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,7 +28,6 @@ // lldbr-check:(boxed_struct::StructWithDestructor) *boxed_with_dtor = { x = 77 y = 777 z = 7777 w = 77777 } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -52,9 +51,19 @@ fn main() { - let boxed_with_padding: Box<_> = box StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }; - - let boxed_with_dtor: Box<_> = box StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }; + let boxed_with_padding: Box<_> = Box::new(StructWithSomePadding { + x: 99, + y: 999, + z: 9999, + w: 99999, + }); + + let boxed_with_dtor: Box<_> = Box::new(StructWithDestructor { + x: 77, + y: 777, + z: 7777, + w: 77777, + }); zzz(); // #break } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/box.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/box.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/box.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/box.rs 2021-11-29 19:27:11.000000000 +0000 @@ -24,13 +24,12 @@ // lldbr-check:((i32, f64)) *b = { 0 = 2 1 = 3.5 } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { - let a = box 1; - let b = box (2, 3.5f64); + let a = Box::new(1); + let b = Box::new((2, 3.5f64)); zzz(); // #break } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/closure-in-generic-function.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/closure-in-generic-function.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/closure-in-generic-function.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/closure-in-generic-function.rs 2021-11-29 19:27:11.000000000 +0000 @@ -39,7 +39,6 @@ // lldbr-check:(i32) *y = 110 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/destructured-fn-argument.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/destructured-fn-argument.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/destructured-fn-argument.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/destructured-fn-argument.rs 2021-11-29 19:27:11.000000000 +0000 @@ -358,7 +358,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -480,7 +479,7 @@ managed_box(&(34, 35)); borrowed_pointer(&(36, 37)); contained_borrowed_pointer((&38, 39)); - unique_pointer(box (40, 41, 42)); + unique_pointer(Box::new((40, 41, 42))); ref_binding((43, 44, 45)); ref_binding_in_tuple((46, (47, 48))); ref_binding_in_struct(Struct { a: 49, b: 50 }); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/destructured-for-loop-variable.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/destructured-for-loop-variable.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/destructured-for-loop-variable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/destructured-for-loop-variable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -173,7 +173,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -214,7 +213,7 @@ y: -300001.5, z: true }, - box 854237.5); + Box::new(854237.5)); for &(v1, &Struct { x: x1, y: ref y1, z: z1 }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/destructured-local.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/destructured-local.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/destructured-local.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/destructured-local.rs 2021-11-29 19:27:11.000000000 +0000 @@ -285,7 +285,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -345,7 +344,7 @@ let (&cc, _) = (&38, 39); // unique pointer - let box dd = box (40, 41, 42); + let box dd = Box::new((40, 41, 42)); // ref binding let ref ee = (43, 44, 45); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/function-names.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/function-names.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/function-names.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/function-names.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,36 +9,37 @@ // gdb-command:info functions -q function_names::main // gdb-check:[...]static fn function_names::main(); // gdb-command:info functions -q function_names::generic_func<* -// gdb-check:[...]static fn function_names::generic_func(i32) -> i32; +// gdb-check:[...]static fn function_names::generic_func(i32) -> i32; // Implementations // gdb-command:info functions -q function_names::.*::impl_function.* -// gdb-check:[...]static fn function_names::GenericStruct::impl_function(); +// gdb-check:[...]static fn function_names::GenericStruct::impl_function(); // gdb-check:[...]static fn function_names::Mod1::TestStruct2::impl_function(); // gdb-check:[...]static fn function_names::TestStruct1::impl_function(); // Trait implementations // gdb-command:info functions -q function_names::.*::trait_function.* -// gdb-check:[...]static fn as function_names::TestTrait1>::trait_function(); -// gdb-check:[...]static fn as function_names::TestTrait1>::trait_function(); -// gdb-check:[...]static fn ::trait_function(); -// gdb-check:[...]static fn ::trait_function(); +// gdb-check:[...]static fn function_names::Mod1::{impl#1}::trait_function(); +// gdb-check:[...]static fn function_names::{impl#1}::trait_function(); +// gdb-check:[...]static fn function_names::{impl#3}::trait_function(); +// gdb-check:[...]static fn function_names::{impl#5}::trait_function3(); +// gdb-check:[...]static fn function_names::{impl#6}::trait_function(); // Closure -// gdb-command:info functions -q function_names::.*::{{closure.* -// gdb-check:[...]static fn function_names::GenericStruct::impl_function::{{closure}}(*mut function_names::{impl#2}::impl_function::{closure#0}); -// gdb-check:[...]static fn function_names::generic_func::{{closure}}(*mut function_names::generic_func::{closure#0}); -// gdb-check:[...]static fn function_names::main::{{closure}}(*mut function_names::main::{closure#0}); +// gdb-command:info functions -q function_names::.*::{closure.* +// gdb-check:[...]static fn function_names::generic_func::{closure#0}(*mut function_names::generic_func::{closure#0}); +// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure#0}); +// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}(*mut function_names::{impl#2}::impl_function::{closure#0}); // Generator // Generators don't seem to appear in GDB's symbol table. // Const generic parameter // gdb-command:info functions -q function_names::const_generic_fn.* -// gdb-check:[...]static fn function_names::const_generic_fn_bool(); -// gdb-check:[...]static fn function_names::const_generic_fn_non_int(); -// gdb-check:[...]static fn function_names::const_generic_fn_signed_int(); -// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int(); +// gdb-check:[...]static fn function_names::const_generic_fn_bool(); +// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>(); +// gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>(); +// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>(); // === CDB TESTS =================================================================================== @@ -103,7 +104,7 @@ GenericStruct::::trait_function3(); // Generic function - let _ = generic_func(42); + let _ = generic_func(42i32); // Closure let closure = || { TestStruct1 }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/generic-method-on-generic-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/generic-method-on-generic-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/generic-method-on-generic-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/generic-method-on-generic-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -123,7 +123,6 @@ // lldbr-check:(f32) arg2 = -10.5 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -155,7 +154,7 @@ let _ = stack.self_by_ref(-1, 2_u16); let _ = stack.self_by_val(-3, -4_i16); - let owned: Box<_> = box Struct { x: 1234.5f64 }; + let owned: Box<_> = Box::new(Struct { x: 1234.5f64 }); let _ = owned.self_by_ref(-5, -6_i32); let _ = owned.self_by_val(-7, -8_i64); let _ = owned.self_owned(-9, -10.5_f32); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-enum.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-enum.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-enum.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-enum.rs 2021-11-29 19:27:11.000000000 +0000 @@ -107,7 +107,6 @@ // lldb-check:[...]$14 = -10 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -140,7 +139,7 @@ let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Enum::Variant1{ x: 1799, y: 1799 }; + let owned: Box<_> = Box::new(Enum::Variant1{ x: 1799, y: 1799 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-generic-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-generic-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-generic-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-generic-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -123,8 +123,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -156,7 +154,7 @@ let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 1234.5f64 }; + let owned: Box<_> = Box::new(Struct { x: 1234.5f64 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +152,7 @@ let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-trait.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -160,7 +158,7 @@ let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-tuple-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-tuple-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/method-on-tuple-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/method-on-tuple-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -152,7 +150,7 @@ let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box TupleStruct(200, -200.5); + let owned: Box<_> = Box::new(TupleStruct(200, -200.5)); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/msvc-pretty-enums.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/msvc-pretty-enums.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/msvc-pretty-enums.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/msvc-pretty-enums.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,67 +1,45 @@ // only-cdb -// ignore-tidy-linelength // compile-flags:-g -// This started failing recently. See https://github.com/rust-lang/rust/issues/88796 -// FIXME: fix and unignore this -// ignore-windows - // cdb-command: g -// Note: The natvis used to visualize niche-layout enums don't work correctly in cdb -// so the best we can do is to make sure we are generating the right debuginfo. -// Therefore, we use the `!` [format specifier](https://docs.microsoft.com/en-us/visualstudio/debugger/format-specifiers-in-cpp?view=vs-2019#BKMK_Visual_Studio_2012_format_specifiers) -// to disable the natvis for a given expression. We also provide the `-r2` flag -// to expand the expression 2 levels. - -// cdb-command: dx -r2 a,! -// cdb-check:a,! [Type: enum$ >, 2, 16, Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$ >, 2, 16, Some>::Some] -// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$ >, 2, 16, Some>::Discriminant$] - -// cdb-command: dx -r2 b,! -// cdb-check:b,! [Type: enum$ >, 2, 16, Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$ >, 2, 16, Some>::Some] -// cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$ >, 2, 16, Some>::Discriminant$] - -// cdb-command: dx -r2 c,! -// cdb-check:c,! [Type: enum$] -// cdb-check: [+0x000] dataful_variant [Type: enum$::Data] -// cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$::Discriminant$] - -// cdb-command: dx -r2 d,! -// cdb-check:d,! [Type: enum$] -// cdb-check: [+0x000] dataful_variant [Type: enum$::Data] -// cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant : 0x10 [Type: enum$::Discriminant$] - -// cdb-command: dx -r2 e,! -// cdb-check:e,! [Type: enum$] -// cdb-check: [+0x000] dataful_variant [Type: enum$::Data] -// cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$::Discriminant$] - -// cdb-command: dx -r2 f,! -// cdb-check:f,! [Type: enum$ >, 1, [...], Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$ >, 1, [...], Some>::Some] -// cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] -// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$ >, 1, [...], Some>::Discriminant$] - -// cdb-command: dx -r2 g,! -// cdb-check:g,! [Type: enum$ >, 1, [...], Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$ >, 1, [...], Some>::Some] -// cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *] -// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$ >, 1, [...], Some>::Discriminant$] - -// cdb-command: dx -r2 h,! -// cdb-check:h,! : Some [Type: enum$ >] -// cdb-check: [+0x000] variant0 [Type: enum$ >::None] -// cdb-check: [+0x000] variant1 [Type: enum$ >::Some] -// cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] -// cdb-check: [+0x000] discriminant : Some (0x1) [Type: core::option::Option] +// cdb-command: dx a +// cdb-check:a : Some({...}) [Type: enum$ >, 2, 16, Some>] +// cdb-check: [] [Type: enum$ >, 2, 16, Some>] +// cdb-check: [variant] : Some +// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] + +// cdb-command: dx b +// cdb-check:b : None [Type: enum$ >, 2, 16, Some>] +// cdb-check: [] [Type: enum$ >, 2, 16, Some>] +// cdb-check: [variant] : None + +// cdb-command: dx c +// cdb-check:c : Tag1 [Type: enum$] +// cdb-check: [] [Type: enum$] +// cdb-check: [variant] : Tag1 + +// cdb-command: dx d +// cdb-check:d : Data({...}) [Type: enum$] +// cdb-check: [] [Type: enum$] +// cdb-check: [variant] : Data +// cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] + +// cdb-command: dx e +// cdb-check:e : Tag2 [Type: enum$] +// cdb-check: [] [Type: enum$] +// cdb-check: [variant] : Tag2 + +// cdb-command: dx f +// cdb-check:f : Some({...}) [Type: enum$ >, 1, [...], Some>] +// cdb-check: [] [Type: enum$ >, 1, [...], Some>] +// cdb-check: [variant] : Some +// cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] + +// cdb-command: dx g +// cdb-check:g : None [Type: enum$ >, 1, [...], Some>] +// cdb-check: [] [Type: enum$ >, 1, [...], Some>] +// cdb-check: [variant] : None // cdb-command: dx h // cdb-check:h : Some [Type: enum$ >] @@ -69,13 +47,6 @@ // cdb-check: [variant] : Some // cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] -// cdb-command: dx -r2 i,! -// cdb-check:i,! : None [Type: enum$ >] -// cdb-check: [+0x000] variant0 [Type: enum$ >::None] -// cdb-check: [+0x000] variant1 [Type: enum$ >::Some] -// cdb-check: [+0x004] __0 : 0x[...] [Type: unsigned int] -// cdb-check: [+0x000] discriminant : None (0x0) [Type: core::option::Option] - // cdb-command: dx i // cdb-check:i : None [Type: enum$ >] // cdb-check: [] [Type: enum$ >] @@ -84,16 +55,17 @@ // cdb-command: dx j // cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] -// cdb-command: dx -r2 k,! -// cdb-check:k,! [Type: enum$, 1, [...], Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] -// cdb-check: [+0x000] __0 [Type: alloc::string::String] -// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::Discriminant$] - -// cdb-command: dx -r2 l,! -// cdb-check:l,! : $T2 [Type: enum$ >, Ok>] -// cdb-check: [+0x000] Ok [Type: enum$ >, Ok>::Ok] -// cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] +// cdb-command: dx k +// cdb-check:k : Some({...}) [Type: enum$, 1, [...], Some>] +// cdb-check: [] [Type: enum$, 1, [...], Some>] +// cdb-check: [variant] : Some +// cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] + +// cdb-command: dx l +// cdb-check:l : Ok [Type: enum$ >, Ok>] +// cdb-check: [] [Type: enum$ >, Ok>] +// cdb-check: [variant] : Ok +// cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] pub enum CStyleEnum { Low = 2, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/msvc-scalarpair-params.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/msvc-scalarpair-params.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/msvc-scalarpair-params.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/msvc-scalarpair-params.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,101 @@ +// only-cdb +// compile-flags: -g + +// cdb-command: g + +// cdb-command: dx r1 +// cdb-check:r1 : (0xa..0xc) [Type: core::ops::range::Range] +// cdb-command: dx r2 +// cdb-check:r2 : (0x14..0x1e) [Type: core::ops::range::Range] + +// cdb-command: g + +// cdb-command: dx r1 +// cdb-check:r1 : (0x9..0x64) [Type: core::ops::range::Range] +// cdb-command: dx r2 +// cdb-check:r2 : (0xc..0x5a) [Type: core::ops::range::Range] + +// cdb-command: g + +// cdb-command: dx o1 +// cdb-check:o1 : Some [Type: enum$ >] +// cdb-check: [variant] : Some +// cdb-check: [+0x004] __0 : 0x4d2 [Type: [...]] +// cdb-command: dx o2 +// cdb-check:o2 : Some [Type: enum$ >] +// cdb-check: [variant] : Some +// cdb-check: [+0x008] __0 : 0x162e [Type: unsigned __int64] + +// cdb-command: g + +// cdb-command: dx t1 +// cdb-check:t1 : (0xa, 0x14) [Type: tuple$] +// cdb-check: [0] : 0xa [Type: unsigned int] +// cdb-check: [1] : 0x14 [Type: unsigned int] +// cdb-command: dx t2 +// cdb-check:t2 : (0x1e, 0x28) [Type: tuple$] +// cdb-check: [0] : 0x1e [Type: unsigned __int64] +// cdb-check: [1] : 0x28 [Type: unsigned __int64] + +// cdb-command: g + +// cdb-command: dx s +// cdb-check:s : "this is a static str" [Type: str] +// cdb-check: [len] : 0x14 [Type: unsigned [...]] +// cdb-check: [chars] + +// cdb-command: g + +// cdb-command: dx s +// cdb-check:s : { len=0x5 } [Type: slice$] +// cdb-check: [len] : 0x5 [Type: unsigned [...]] +// cdb-check: [0] : 0x1 [Type: unsigned char] +// cdb-check: [1] : 0x2 [Type: unsigned char] +// cdb-check: [2] : 0x3 [Type: unsigned char] +// cdb-check: [3] : 0x4 [Type: unsigned char] +// cdb-check: [4] : 0x5 [Type: unsigned char] + +use std::ops::Range; + +fn range(r1: Range, r2: Range) { + zzz(); // #break +} + +fn range_mut(mut r1: Range, mut r2: Range) { + if r1.start == 9 { + r1.end = 100; + } + + if r2.start == 12 { + r2.end = 90; + } + + zzz(); // #break +} + +fn option(o1: Option, o2: Option) { + zzz(); // #break +} + +fn tuple(t1: (u32, u32), t2: (u64, u64)) { + zzz(); // #break +} + +fn str(s: &str) { + zzz(); // #break +} + +fn slice(s: &[u8]) { + zzz(); // #break +} + +fn zzz() { } + +fn main() { + range(10..12, 20..30); + range_mut(9..20, 12..80); + option(Some(1234), Some(5678)); + tuple((10, 20), (30, 40)); + str("this is a static str"); + slice(&[1, 2, 3, 4, 5]); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/mutex.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/mutex.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/mutex.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/mutex.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ // cdb-only // min-cdb-version: 10.0.21287.1005 // compile-flags:-g -// FIXME: Failed on update to 10.0.22000.1 -// ignore-windows // === CDB TESTS ================================================================================== // @@ -14,17 +12,17 @@ // cdb-check:m,d [Type: std::sync::mutex::Mutex] // cdb-check: [...] inner [Type: std::sys_common::mutex::MovableMutex] // cdb-check: [...] poison [Type: std::sync::poison::Flag] -// cdb-check: [...] data [Type: core::cell::UnsafeCell] +// cdb-check: [...] data : 0 [Type: core::cell::UnsafeCell] // // cdb-command:dx m.data,d -// cdb-check:m.data,d [Type: core::cell::UnsafeCell] -// cdb-check: [...] value : 0 [Type: int] +// cdb-check:m.data,d : 0 [Type: core::cell::UnsafeCell] +// cdb-check: [] [Type: core::cell::UnsafeCell] // // cdb-command:dx lock,d -// cdb-check:lock,d : Ok [Type: enum$, enum$ >, 0, 1, Poisoned> > >] -// cdb-check: [...] variant$ : Ok (0) [Type: core::result::Result] +// cdb-check:lock,d : Ok [Type: enum$,enum$ >, 0, 1, Poisoned> > >] +// cdb-check: [variant] : Ok // cdb-check: [...] __0 [Type: std::sync::mutex::MutexGuard] use std::sync::Mutex; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/pretty-std.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/pretty-std.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/pretty-std.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/pretty-std.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,10 +6,6 @@ // min-lldb-version: 310 // min-cdb-version: 10.0.18317.1001 -// This started failing recently. See https://github.com/rust-lang/rust/issues/88796 -// FIXME: fix and unignore this -// ignore-windows - // === GDB TESTS =================================================================================== // gdb-command: run @@ -115,9 +111,11 @@ // cdb-check: [11] : 33 '!' [Type: char] // cdb-command: dx os_string -// cdb-check:os_string : "IAMA OS string 😃" [Type: std::ffi::os_str::OsString] +// NOTE: OSString is WTF-8 encoded which Windows debuggers don't understand. Verify the UTF-8 +// portion displays correctly. +// cdb-check:os_string : "IAMA OS string [...]" [Type: std::ffi::os_str::OsString] // cdb-check: [] [Type: std::ffi::os_str::OsString] -// cdb-check: [chars] : "IAMA OS string 😃" +// cdb-check: [chars] : "IAMA OS string [...]" // cdb-command: dx some // cdb-check:some : Some [Type: enum$ >] @@ -131,8 +129,10 @@ // cdb-check: [variant] : None // cdb-command: dx some_string -// NOTE: cdb fails to interpret debug info of Option enums on i686. -// cdb-check:some_string [Type: enum$, 1, [...], Some>] +// cdb-check:some_string : Some({...}) [Type: enum$, 1, [...], Some>] +// cdb-check: [] [Type: enum$, 1, [...], Some>] +// cdb-check: [variant] : Some +// cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] // cdb-command: dx linkedlist // cdb-check:linkedlist : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/recursive-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/recursive-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/recursive-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/recursive-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -52,20 +52,20 @@ // gdb-command:print long_cycle4.value // gdb-check:$18 = 29.5 -// gdbr-command:print long_cycle_w_anonymous_types.value +// gdbr-command:print long_cycle_w_anon_types.value // gdb-check:$19 = 30 -// gdbr-command:print long_cycle_w_anonymous_types.next.val.value +// gdbr-command:print long_cycle_w_anon_types.next.val.value // gdb-check:$20 = 31 // gdb-command:continue #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Opt::{Empty, Val}; +use std::boxed::Box as B; enum Opt { Empty, @@ -120,75 +120,75 @@ fn main() { let stack_unique: UniqueNode = UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 1, - } + }) }, value: 0, }; - let unique_unique: Box> = box UniqueNode { + let unique_unique: Box> = Box::new(UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 3, - } + }) }, value: 2, - }; + }); let vec_unique: [UniqueNode; 1] = [UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 7.5, - } + }) }, value: 6.5, }]; let borrowed_unique: &UniqueNode = &UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 9.5, - } + }) }, value: 8.5, }; // LONG CYCLE let long_cycle1: LongCycle1 = LongCycle1 { - next: box LongCycle2 { - next: box LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle2 { + next: Box::new(LongCycle3 { + next: Box::new(LongCycle4 { next: None, value: 23, - }, + }), value: 22, - }, + }), value: 21 - }, + }), value: 20 }; let long_cycle2: LongCycle2 = LongCycle2 { - next: box LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle3 { + next: Box::new(LongCycle4 { next: None, value: 26, - }, + }), value: 25, - }, + }), value: 24 }; let long_cycle3: LongCycle3 = LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle4 { next: None, value: 28, - }, + }), value: 27, }; @@ -199,15 +199,15 @@ // It's important that LongCycleWithAnonymousTypes is encountered only at the end of the // `box` chain. - let long_cycle_w_anonymous_types = box box box box box LongCycleWithAnonymousTypes { + let long_cycle_w_anon_types = B::new(B::new(B::new(B::new(B::new(LongCycleWithAnonymousTypes { next: Val { - val: box box box box box LongCycleWithAnonymousTypes { + val: Box::new(Box::new(Box::new(Box::new(Box::new(LongCycleWithAnonymousTypes { next: Empty, value: 31, - } + }))))) }, value: 30 - }; + }))))); zzz(); // #break } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/self-in-default-method.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/self-in-default-method.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/self-in-default-method.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/self-in-default-method.rs 2021-11-29 19:27:11.000000000 +0000 @@ -121,7 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +153,7 @@ let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/self-in-generic-default-method.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/self-in-generic-default-method.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/self-in-generic-default-method.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/self-in-generic-default-method.rs 2021-11-29 19:27:11.000000000 +0000 @@ -121,7 +121,6 @@ // lldbr-check:(f32) arg2 = -10.5 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -155,7 +154,7 @@ let _ = stack.self_by_ref(-1, 2_u16); let _ = stack.self_by_val(-3, -4_i16); - let owned: Box<_> = box Struct { x: 879 }; + let owned: Box<_> = Box::new(Struct { x: 879 }); let _ = owned.self_by_ref(-5, -6_i32); let _ = owned.self_by_val(-7, -8_i64); let _ = owned.self_owned(-9, -10.5_f32); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/trait-pointers.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/trait-pointers.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/trait-pointers.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/trait-pointers.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,6 @@ // lldb-command:run #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -24,5 +23,5 @@ fn main() { let stack_struct = Struct { a:0, b: 1.0 }; let reference: &Trait = &stack_struct as &Trait; - let unique: Box = box Struct { a:2, b: 3.0 } as Box; + let unique: Box = Box::new(Struct { a:2, b: 3.0 }) as Box; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/type-names.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/type-names.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/type-names.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/type-names.rs 2021-11-29 19:27:11.000000000 +0000 @@ -262,7 +262,6 @@ // cdb-check:struct ForeignType2 * foreign2 = [...] // cdb-check:struct ForeignType1 * foreign1 = [...] -#![feature(box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -373,8 +372,8 @@ let tuple2 = ((Struct1, mod1::mod2::Struct3), mod1::Variant1, 'x'); // Box - let box1 = (box 1f32, 0i32); - let box2 = (box mod1::mod2::Variant2(1f32), 0i32); + let box1 = (Box::new(1f32), 0i32); + let box2 = (Box::new(mod1::mod2::Variant2(1f32)), 0i32); // References let ref1 = (&Struct1, 0i32); @@ -404,14 +403,14 @@ let slice2 = &*vec2; // Trait Objects - let box_trait = (box 0_isize) as Box; + let box_trait = Box::new(0_isize) as Box; let ref_trait = &0_isize as &dyn Trait1; let mut mut_int1 = 0_isize; let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1; - let no_principal_trait = (box 0_isize) as Box<(dyn Send + Sync)>; + let no_principal_trait = Box::new(0_isize) as Box<(dyn Send + Sync)>; let has_associated_type_trait = &0_isize as &(dyn Trait3 + Send); - let generic_box_trait = (box 0_isize) as Box>; + let generic_box_trait = Box::new(0_isize) as Box>; let generic_ref_trait = (&0_isize) as &dyn Trait2; let mut generic_mut_ref_trait_impl = 0_isize; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/unique-enum.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/unique-enum.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/unique-enum.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/unique-enum.rs 2021-11-29 19:27:11.000000000 +0000 @@ -32,7 +32,6 @@ // lldbr-check:(unique_enum::Univariant) *univariant = { TheOnlyCase = { = 123234 } } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -59,15 +58,15 @@ // 0b01111100011111000111110001111100 = 2088533116 // 0b0111110001111100 = 31868 // 0b01111100 = 124 - let the_a: Box<_> = box ABC::TheA { x: 0, y: 8970181431921507452 }; + let the_a: Box<_> = Box::new(ABC::TheA { x: 0, y: 8970181431921507452 }); // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 // 0b00010001000100010001000100010001 = 286331153 // 0b0001000100010001 = 4369 // 0b00010001 = 17 - let the_b: Box<_> = box ABC::TheB (0, 286331153, 286331153); + let the_b: Box<_> = Box::new(ABC::TheB (0, 286331153, 286331153)); - let univariant: Box<_> = box Univariant::TheOnlyCase(123234); + let univariant: Box<_> = Box::new(Univariant::TheOnlyCase(123234)); zzz(); // #break } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-nested-closure.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-nested-closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-nested-closure.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-nested-closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -133,7 +133,6 @@ // cdb-check:closure_local : 8 [Type: [...]] #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +153,7 @@ }; let struct_ref = &a_struct; - let owned: Box<_> = box 6; + let owned: Box<_> = Box::new(6); let mut closure = || { let closure_local = 8; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-sendable-closure.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-sendable-closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-sendable-closure.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-sendable-closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -34,7 +34,6 @@ // lldbr-check:(isize) *owned = 5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -53,7 +52,7 @@ c: 4 }; - let owned: Box<_> = box 5; + let owned: Box<_> = Box::new(5); let closure = move || { zzz(); // #break diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-stack-closure.rs rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-stack-closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-stack-closure.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/debuginfo/var-captured-in-stack-closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -115,7 +115,6 @@ // cdb-command: dx owned // cdb-check:owned : 0x[...] : 6 [Type: [...] *] -#![feature(box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -137,7 +136,7 @@ }; let struct_ref = &a_struct; - let owned: Box<_> = box 6; + let owned: Box<_> = Box::new(6); { let mut first_closure = || { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/change_symbol_export_status.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/change_symbol_export_status.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/change_symbol_export_status.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/change_symbol_export_status.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,15 @@ -// revisions: rpass1 rpass2 +// revisions: rpass1 rpass2 rpass3 rpass4 // compile-flags: -Zquery-dep-graph +// [rpass1]compile-flags: -Zincremental-ignore-spans +// [rpass2]compile-flags: -Zincremental-ignore-spans +// [rpass3]compile-flags: -Zincremental-relative-spans +// [rpass4]compile-flags: -Zincremental-relative-spans #![feature(rustc_attrs)] -#![rustc_partition_codegened(module = "change_symbol_export_status-mod1", cfg = "rpass2")] +#![rustc_partition_reused(module = "change_symbol_export_status-mod1", cfg = "rpass2")] #![rustc_partition_reused(module = "change_symbol_export_status-mod2", cfg = "rpass2")] +#![rustc_partition_reused(module = "change_symbol_export_status-mod1", cfg = "rpass4")] +#![rustc_partition_reused(module = "change_symbol_export_status-mod2", cfg = "rpass4")] // This test case makes sure that a change in symbol visibility is detected by // our dependency tracking. We do this by changing a module's visibility to @@ -13,13 +19,13 @@ // even from an executable. Plain Rust functions are only exported from Rust // libraries, which our test infrastructure does not support. -#[cfg(rpass1)] +#[cfg(any(rpass1,rpass3))] pub mod mod1 { #[no_mangle] pub fn foo() {} } -#[cfg(rpass2)] +#[cfg(any(rpass2,rpass4))] mod mod1 { #[no_mangle] pub fn foo() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/call_expressions.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/call_expressions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/call_expressions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/call_expressions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] @@ -19,14 +25,16 @@ // Change Callee (Function) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_callee_function() { callee1(1, 2) } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_callee_function() { callee2(1, 2) } @@ -34,14 +42,16 @@ // Change Argument (Function) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_argument_function() { callee1(1, 2) } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_argument_function() { callee1(1, 3) } @@ -50,13 +60,15 @@ // Change Callee Indirectly (Function) mod change_callee_indirectly_function { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::callee1 as callee; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::callee2 as callee; #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] pub fn change_callee_indirectly_function() { callee(1, 2) } @@ -70,15 +82,17 @@ } // Change Callee (Method) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_callee_method() { let s = Struct; s.method1('x', true); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_callee_method() { let s = Struct; s.method2('x', true); @@ -87,15 +101,17 @@ // Change Argument (Method) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_argument_method() { let s = Struct; s.method1('x', true); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_argument_method() { let s = Struct; s.method1('y', true); @@ -104,15 +120,17 @@ // Change Callee (Method, UFCS) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_ufcs_callee_method() { let s = Struct; Struct::method1(&s, 'x', true); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_ufcs_callee_method() { let s = Struct; Struct::method2(&s, 'x', true); @@ -121,32 +139,36 @@ // Change Argument (Method, UFCS) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_argument_method_ufcs() { let s = Struct; Struct::method1(&s, 'x', true); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_argument_method_ufcs() { let s = Struct; - Struct::method1(&s, 'x', false); + Struct::method1(&s, 'x',false); } // Change To UFCS -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_to_ufcs() { let s = Struct; - s.method1('x', true); + s.method1('x', true); // ------ } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] // One might think this would be expanded in the hir_owner_nodes/Mir, but it actually // results in slightly different hir_owner/Mir. pub fn change_to_ufcs() { @@ -162,15 +184,15 @@ // Change UFCS Callee Indirectly pub mod change_ufcs_callee_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::Struct as Struct; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::Struct2 as Struct; #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - - + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail6")] pub fn change_ufcs_callee_indirectly() { let s = Struct; Struct::method1(&s, 'q', false) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/closure_expressions.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/closure_expressions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/closure_expressions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/closure_expressions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans -Zmir-opt-level=0 +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph -Zmir-opt-level=0 +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -15,14 +21,16 @@ // Change closure body -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_closure_body() { let _ = || 1u32; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn change_closure_body() { let _ = || 3u32; } @@ -30,15 +38,17 @@ // Add parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_parameter() { let x = 0u32; - let _ = || x + 1; + let _ = | | x + 1; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_parameter() { let x = 0u32; let _ = |x: u32| x + 1; @@ -47,14 +57,16 @@ // Change parameter pattern -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_parameter_pattern() { - let _ = |x: (u32,)| x; + let _ = | x : (u32,)| x; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_parameter_pattern() { let _ = |(x,): (u32,)| x; } @@ -62,14 +74,16 @@ // Add `move` to closure -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_move() { - let _ = || 1; + let _ = || 1; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_move() { let _ = move || 1; } @@ -77,15 +91,17 @@ // Add type ascription to parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_type_ascription_to_parameter() { - let closure = |x| x + 1u32; + let closure = |x | x + 1u32; let _: u32 = closure(1); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, typeck")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner_nodes, typeck")] +#[rustc_clean(cfg = "cfail6")] pub fn add_type_ascription_to_parameter() { let closure = |x: u32| x + 1u32; let _: u32 = closure(1); @@ -94,15 +110,17 @@ // Change parameter type -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_parameter_type() { let closure = |x: u32| (x as u64) + 1; let _ = closure(1); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_parameter_type() { let closure = |x: u16| (x as u64) + 1; let _ = closure(1); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/consts.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/consts.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/consts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/consts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ // build-pass (FIXME(62277): could be check-pass?) // revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// compile-flags: -Z query-dep-graph #![allow(warnings)] #![feature(rustc_attrs)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/enum_constructors.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/enum_constructors.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/enum_constructors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/enum_constructors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans -Zmir-opt-level=0 +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph -Zmir-opt-level=0 +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -24,7 +30,7 @@ } // Change field value (struct-like) ----------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_field_value_struct_like() -> Enum { Enum::Struct { x: 0, @@ -33,9 +39,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_field_value_struct_like() -> Enum { Enum::Struct { x: 0, @@ -47,7 +55,7 @@ // Change field order (struct-like) ----------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_field_order_struct_like() -> Enum { Enum::Struct { x: 3, @@ -56,9 +64,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] // FIXME(michaelwoerister):Interesting. I would have thought that that changes the MIR. And it // would if it were not all constants pub fn change_field_order_struct_like() -> Enum { @@ -86,18 +96,20 @@ } // Change constructor path (struct-like) ------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_constructor_path_struct_like() { - let _ = Enum::Struct { + let _ = Enum ::Struct { x: 0, y: 1, z: 2, }; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_struct_like() { let _ = Enum2::Struct { x: 0, @@ -109,18 +121,20 @@ // Change variant (regular struct) ------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_constructor_variant_struct_like() { - let _ = Enum2::Struct { + let _ = Enum2::Struct { x: 0, y: 1, z: 2, }; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_constructor_variant_struct_like() { let _ = Enum2::Struct2 { x: 0, @@ -132,9 +146,9 @@ // Change constructor path indirectly (struct-like) ------------------------- pub mod change_constructor_path_indirectly_struct_like { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::Enum as TheEnum; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::Enum2 as TheEnum; #[rustc_clean( @@ -143,6 +157,12 @@ typeck" )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ + typeck" + )] + #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::Struct { x: 0, @@ -156,13 +176,15 @@ // Change constructor variant indirectly (struct-like) --------------------------- pub mod change_constructor_variant_indirectly_struct_like { use super::Enum2; - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::Enum2::Struct as Variant; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::Enum2::Struct2 as Variant; #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail6")] pub fn function() -> Enum2 { Variant { x: 0, @@ -174,14 +196,16 @@ // Change field value (tuple-like) ------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_field_value_tuple_like() -> Enum { Enum::Tuple(0, 1, 2) } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_field_value_tuple_like() -> Enum { Enum::Tuple(0, 1, 3) } @@ -189,17 +213,22 @@ // Change constructor path (tuple-like) -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_constructor_path_tuple_like() { - let _ = Enum::Tuple(0, 1, 2); + let _ = Enum ::Tuple(0, 1, 2); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck" )] #[rustc_clean(cfg="cfail3")] +#[rustc_clean( + cfg="cfail5", + except="hir_owner_nodes,optimized_mir,typeck" +)] +#[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_tuple_like() { let _ = Enum2::Tuple(0, 1, 2); } @@ -207,17 +236,22 @@ // Change constructor variant (tuple-like) -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_constructor_variant_tuple_like() { - let _ = Enum2::Tuple(0, 1, 2); + let _ = Enum2::Tuple (0, 1, 2); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck" )] #[rustc_clean(cfg="cfail3")] +#[rustc_clean( + cfg="cfail5", + except="hir_owner_nodes,optimized_mir,typeck" +)] +#[rustc_clean(cfg="cfail6")] pub fn change_constructor_variant_tuple_like() { let _ = Enum2::Tuple2(0, 1, 2); } @@ -225,9 +259,9 @@ // Change constructor path indirectly (tuple-like) --------------------------- pub mod change_constructor_path_indirectly_tuple_like { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::Enum as TheEnum; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::Enum2 as TheEnum; #[rustc_clean( @@ -236,6 +270,12 @@ typeck" )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ + typeck" + )] + #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::Tuple(0, 1, 2) } @@ -246,13 +286,15 @@ // Change constructor variant indirectly (tuple-like) --------------------------- pub mod change_constructor_variant_indirectly_tuple_like { use super::Enum2; - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::Enum2::Tuple as Variant; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::Enum2::Tuple2 as Variant; #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail6")] pub fn function() -> Enum2 { Variant(0, 1, 2) } @@ -272,14 +314,16 @@ } // Change constructor path (C-like) -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_constructor_path_c_like() { - let _x = Clike::B; + let _x = Clike ::B; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_c_like() { let _x = Clike2::B; } @@ -287,14 +331,16 @@ // Change constructor variant (C-like) -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_constructor_variant_c_like() { let _x = Clike::A; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_constructor_variant_c_like() { let _x = Clike::C; } @@ -302,9 +348,9 @@ // Change constructor path indirectly (C-like) --------------------------- pub mod change_constructor_path_indirectly_c_like { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::Clike as TheEnum; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::Clike2 as TheEnum; #[rustc_clean( @@ -313,6 +359,12 @@ typeck" )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\ + typeck" + )] + #[rustc_clean(cfg="cfail6")] pub fn function() -> TheEnum { TheEnum::B } @@ -323,13 +375,15 @@ // Change constructor variant indirectly (C-like) --------------------------- pub mod change_constructor_variant_indirectly_c_like { use super::Clike; - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::Clike::A as Variant; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::Clike::B as Variant; #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail6")] pub fn function() -> Clike { Variant } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/enum_defs.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/enum_defs.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/enum_defs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/enum_defs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,8 +11,14 @@ // the same between rev2 and rev3. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -22,12 +28,14 @@ // Change enum visibility ----------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumVisibility { A } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub enum EnumVisibility { A } @@ -35,15 +43,17 @@ // Change name of a c-style variant ------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeNameCStyleVariant { Variant1, Variant2, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeNameCStyleVariant { Variant1, Variant2Changed, @@ -52,15 +62,17 @@ // Change name of a tuple-style variant --------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeNameTupleStyleVariant { Variant1, Variant2(u32, f32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeNameTupleStyleVariant { Variant1, Variant2Changed(u32, f32), @@ -69,15 +81,17 @@ // Change name of a struct-style variant -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeNameStructStyleVariant { Variant1, Variant2 { a: u32, b: f32 }, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeNameStructStyleVariant { Variant1, Variant2Changed { a: u32, b: f32 }, @@ -86,31 +100,33 @@ // Change the value of a c-style variant -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeValueCStyleVariant0 { Variant1, Variant2 = 11, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeValueCStyleVariant0 { Variant1, - - Variant2 = - 22, + Variant2 = 22, } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeValueCStyleVariant1 { Variant1, Variant2, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeValueCStyleVariant1 { Variant1, Variant2 = 11, @@ -119,14 +135,16 @@ // Add a c-style variant ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddCStyleVariant { Variant1, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddCStyleVariant { Variant1, Variant2, @@ -135,15 +153,17 @@ // Remove a c-style variant --------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumRemoveCStyleVariant { Variant1, Variant2, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumRemoveCStyleVariant { Variant1, } @@ -151,14 +171,16 @@ // Add a tuple-style variant -------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddTupleStyleVariant { Variant1, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddTupleStyleVariant { Variant1, Variant2(u32, f32), @@ -167,15 +189,17 @@ // Remove a tuple-style variant ----------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumRemoveTupleStyleVariant { Variant1, Variant2(u32, f32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumRemoveTupleStyleVariant { Variant1, } @@ -183,14 +207,16 @@ // Add a struct-style variant ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddStructStyleVariant { Variant1, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddStructStyleVariant { Variant1, Variant2 { a: u32, b: f32 }, @@ -199,15 +225,17 @@ // Remove a struct-style variant ---------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumRemoveStructStyleVariant { Variant1, Variant2 { a: u32, b: f32 }, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumRemoveStructStyleVariant { Variant1, } @@ -215,14 +243,16 @@ // Change the type of a field in a tuple-style variant ------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeFieldTypeTupleStyleVariant { Variant1(u32, u32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeFieldTypeTupleStyleVariant { Variant1(u32, u64), @@ -231,15 +261,17 @@ // Change the type of a field in a struct-style variant ----------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeFieldTypeStructStyleVariant { Variant1, Variant2 { a: u32, b: u32 }, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeFieldTypeStructStyleVariant { Variant1, Variant2 { @@ -251,14 +283,16 @@ // Change the name of a field in a struct-style variant ----------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeFieldNameStructStyleVariant { Variant1 { a: u32, b: u32 }, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeFieldNameStructStyleVariant { Variant1 { a: u32, c: u32 }, } @@ -266,14 +300,16 @@ // Change order of fields in a tuple-style variant ---------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeOrderTupleStyleVariant { Variant1(u32, u64), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeOrderTupleStyleVariant { Variant1( u64, @@ -283,14 +319,16 @@ // Change order of fields in a struct-style variant --------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeFieldOrderStructStyleVariant { Variant1 { a: u32, b: f32 }, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeFieldOrderStructStyleVariant { Variant1 { b: f32, a: u32 }, } @@ -298,14 +336,16 @@ // Add a field to a tuple-style variant --------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddFieldTupleStyleVariant { Variant1(u32, u32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddFieldTupleStyleVariant { Variant1(u32, u32, u32), } @@ -313,14 +353,16 @@ // Add a field to a struct-style variant -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddFieldStructStyleVariant { Variant1 { a: u32, b: u32 }, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddFieldStructStyleVariant { Variant1 { a: u32, b: u32, c: u32 }, } @@ -328,15 +370,17 @@ // Add #[must_use] to the enum ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddMustUse { Variant1, Variant2, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] #[must_use] enum EnumAddMustUse { Variant1, @@ -346,15 +390,17 @@ // Add #[repr(C)] to the enum ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddReprC { Variant1, Variant2, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="type_of")] +#[rustc_clean(cfg="cfail6")] #[repr(C)] enum EnumAddReprC { Variant1, @@ -364,14 +410,16 @@ // Change the name of a type parameter ---------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeNameOfTypeParameter { Variant1(S), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeNameOfTypeParameter { Variant1(T), } @@ -379,15 +427,17 @@ // Add a type parameter ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddTypeParameter { Variant1(S), Variant2(S), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddTypeParameter { Variant1(S), Variant2(T), @@ -396,14 +446,16 @@ // Change the name of a lifetime parameter ------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumChangeNameOfLifetimeParameter<'a> { Variant1(&'a u32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumChangeNameOfLifetimeParameter<'b> { Variant1(&'b u32), } @@ -411,15 +463,17 @@ // Add a lifetime parameter --------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddLifetimeParameter<'a> { Variant1(&'a u32), Variant2(&'a u32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameter<'a, 'b> { Variant1(&'a u32), Variant2(&'b u32), @@ -428,30 +482,34 @@ // Add a lifetime bound to a lifetime parameter ------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddLifetimeParameterBound<'a, 'b> { Variant1(&'a u32), Variant2(&'b u32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameterBound<'a, 'b: 'a> { Variant1(&'a u32), Variant2(&'b u32), } // Add a lifetime bound to a type parameter ----------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddLifetimeBoundToParameter<'a, T> { Variant1(T), Variant2(&'a u32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameter<'a, T: 'a> { Variant1(T), Variant2(&'a u32), @@ -460,14 +518,16 @@ // Add a trait bound to a type parameter -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddTraitBound { Variant1(S), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddTraitBound { Variant1(T), } @@ -475,15 +535,17 @@ // Add a lifetime bound to a lifetime parameter in where clause --------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddLifetimeParameterBoundWhere<'a, 'b> { Variant1(&'a u32), Variant2(&'b u32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a { Variant1(&'a u32), Variant2(&'b u32), @@ -492,15 +554,17 @@ // Add a lifetime bound to a type parameter in where clause ------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddLifetimeBoundToParameterWhere<'a, T> { Variant1(T), Variant2(&'a u32), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a { Variant1(T), Variant2(&'a u32), @@ -509,14 +573,16 @@ // Add a trait bound to a type parameter in where clause ---------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumAddTraitBoundWhere { Variant1(S), } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] +#[rustc_clean(cfg="cfail6")] enum EnumAddTraitBoundWhere where T: Sync { Variant1(T), } @@ -524,15 +590,17 @@ // In an enum with two variants, swap usage of type parameters ---------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumSwapUsageTypeParameters { Variant1 { a: A }, Variant2 { a: B }, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] enum EnumSwapUsageTypeParameters { Variant1 { a: B @@ -545,15 +613,17 @@ // In an enum with two variants, swap usage of lifetime parameters ------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] enum EnumSwapUsageLifetimeParameters<'a, 'b> { Variant1 { a: &'a u32 }, Variant2 { b: &'b u32 }, } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] enum EnumSwapUsageLifetimeParameters<'a, 'b> { Variant1 { a: &'b u32 @@ -572,13 +642,15 @@ // Change field type in tuple-style variant indirectly by modifying a use statement mod change_field_type_indirectly_tuple_style { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedType1 as FieldType; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail6")] enum TupleStyle { Variant1( FieldType @@ -590,13 +662,15 @@ // Change field type in record-style variant indirectly by modifying a use statement mod change_field_type_indirectly_struct_style { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedType1 as FieldType; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail6")] enum StructStyle { Variant1 { a: FieldType @@ -613,13 +687,15 @@ // Change trait bound of type parameter indirectly by modifying a use statement mod change_trait_bound_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait1 as Trait; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail6")] enum Enum { Variant1(T) } @@ -629,13 +705,15 @@ // Change trait bound of type parameter in where clause indirectly by modifying a use statement mod change_trait_bound_indirectly_where { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait1 as Trait; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail6")] enum Enum where T: Trait { Variant1(T) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/exported_vs_not.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/exported_vs_not.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/exported_vs_not.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/exported_vs_not.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,12 @@ // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -10,14 +16,16 @@ // the hash of the hir_owner_nodes node should change, but not the hash of // either the hir_owner or the Metadata node. -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn body_not_exported_to_metadata() -> u32 { 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn body_not_exported_to_metadata() -> u32 { 2 } @@ -28,15 +36,17 @@ // marked as #[inline]. Only the hash of the hir_owner depnode should be // unaffected by a change to the body. -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[inline] pub fn body_exported_to_metadata_because_of_inline() -> u32 { 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] #[inline] pub fn body_exported_to_metadata_because_of_inline() -> u32 { 2 @@ -48,15 +58,17 @@ // generic. Only the hash of the hir_owner depnode should be // unaffected by a change to the body. -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[inline] pub fn body_exported_to_metadata_because_of_generic() -> u32 { 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] #[inline] pub fn body_exported_to_metadata_because_of_generic() -> u32 { 2 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/extern_mods.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/extern_mods.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/extern_mods.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/extern_mods.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -15,146 +21,168 @@ #![crate_type = "rlib"] // Change function name -------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { pub fn change_function_name1(c: i64) -> i32; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner")] +#[rustc_clean(cfg = "cfail6")] extern "C" { pub fn change_function_name2(c: i64) -> i32; } // Change parameter name ------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { pub fn change_parameter_name(c: i64) -> i32; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] extern "C" { pub fn change_parameter_name(d: i64) -> i32; } // Change parameter type ------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { pub fn change_parameter_type(c: i64) -> i32; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] extern "C" { pub fn change_parameter_type(c: i32) -> i32; } // Change return type ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { pub fn change_return_type(c: i32) -> i32; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] extern "C" { - pub fn change_return_type(c: i32) -> i8; + pub fn change_return_type(c: i32) -> i8 ; } // Add parameter --------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { - pub fn add_parameter(c: i32) -> i32; + pub fn add_parameter(c: i32 ) -> i32; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] extern "C" { pub fn add_parameter(c: i32, d: i32) -> i32; } // Add return type ------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { - pub fn add_return_type(c: i32); + pub fn add_return_type(c: i32) ; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] extern "C" { pub fn add_return_type(c: i32) -> i32; } // Make function variadic ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { - pub fn make_function_variadic(c: i32); + pub fn make_function_variadic(c: i32 ); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] extern "C" { pub fn make_function_variadic(c: i32, ...); } // Change calling convention --------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { pub fn change_calling_convention(c: i32); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner")] +#[rustc_clean(cfg = "cfail6")] extern "rust-call" { pub fn change_calling_convention(c: i32); } // Make function public -------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { - fn make_function_public(c: i32); + fn make_function_public(c: i32); } -#[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] extern "C" { pub fn make_function_public(c: i32); } // Add function ---------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] extern "C" { pub fn add_function1(c: i32); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner")] +#[rustc_clean(cfg = "cfail6")] extern "C" { pub fn add_function1(c: i32); pub fn add_function2(); } // Change link-name ------------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[link(name = "foo")] extern "C" { pub fn change_link_name(c: i32); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] #[link(name = "bar")] extern "C" { pub fn change_link_name(c: i32); @@ -165,13 +193,15 @@ // Indirectly change parameter type -------------------------------------------- mod indirectly_change_parameter_type { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::c_i32 as c_int; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::c_i64 as c_int; #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] + #[rustc_clean(cfg = "cfail5")] + #[rustc_clean(cfg = "cfail6")] extern "C" { pub fn indirectly_change_parameter_type(c: c_int); } @@ -179,13 +209,15 @@ // Indirectly change return type -------------------------------------------- mod indirectly_change_return_type { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::c_i32 as c_int; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::c_i64 as c_int; #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] + #[rustc_clean(cfg = "cfail5")] + #[rustc_clean(cfg = "cfail6")] extern "C" { pub fn indirectly_change_return_type() -> c_int; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/for_loops.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/for_loops.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/for_loops.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/for_loops.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -15,7 +21,7 @@ // Change loop body ------------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_loop_body() { let mut _x = 0; for _ in 0..1 { @@ -24,9 +30,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_loop_body() { let mut _x = 0; for _ in 0..1 { @@ -38,7 +46,7 @@ // Change iteration variable name ---------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_iteration_variable_name() { let mut _x = 0; for _i in 0..1 { @@ -47,9 +55,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_iteration_variable_name() { let mut _x = 0; for _a in 0..1 { @@ -61,18 +71,20 @@ // Change iteration variable pattern ------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_iteration_variable_pattern() { let mut _x = 0; - for _i in &[0, 1, 2] { + for _i in &[0, 1, 2] { _x = 1; break; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck, promoted_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_iteration_variable_pattern() { let mut _x = 0; for &_i in &[0, 1, 2] { @@ -84,7 +96,7 @@ // Change iterable ------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_iterable() { let mut _x = 0; for _ in &[0, 1, 2] { @@ -93,9 +105,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_iterable() { let mut _x = 0; for _ in &[0, 1, 3] { @@ -107,17 +121,20 @@ // Add break ------------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_break() { let mut _x = 0; for _ in 0..1 { _x = 1; + // --- } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_break() { let mut _x = 0; for _ in 0..1 { @@ -129,18 +146,20 @@ // Add loop label -------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label() { let mut _x = 0; - for _ in 0..1 { + for _ in 0..1 { _x = 1; break; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label() { let mut _x = 0; 'label: for _ in 0..1 { @@ -152,18 +171,20 @@ // Add loop label to break ----------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label_to_break() { let mut _x = 0; 'label: for _ in 0..1 { _x = 1; - break; + break ; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; 'label: for _ in 0..1 { @@ -175,7 +196,7 @@ // Change break label ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_break_label() { let mut _x = 0; 'outer: for _ in 0..1 { @@ -186,9 +207,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_break_label() { let mut _x = 0; 'outer: for _ in 0..1 { @@ -202,18 +225,20 @@ // Add loop label to continue -------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label_to_continue() { let mut _x = 0; 'label: for _ in 0..1 { _x = 1; - continue; + continue ; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_continue() { let mut _x = 0; 'label: for _ in 0..1 { @@ -225,7 +250,7 @@ // Change continue label ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_continue_label() { let mut _x = 0; 'outer: for _ in 0..1 { @@ -236,9 +261,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_continue_label() { let mut _x = 0; 'outer: for _ in 0..1 { @@ -252,7 +279,7 @@ // Change continue to break ---------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_continue_to_break() { let mut _x = 0; for _ in 0..1 { @@ -261,13 +288,15 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_continue_to_break() { let mut _x = 0; for _ in 0..1 { _x = 1; - break; + break ; } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/function_interfaces.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/function_interfaces.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/function_interfaces.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/function_interfaces.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(linkage)] @@ -16,248 +22,310 @@ // Add Parameter --------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_parameter() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" +)] +#[rustc_clean(cfg = "cfail6")] pub fn add_parameter(p: i32) {} // Add Return Type ------------------------------------------------------------- -#[cfg(cfail1)] -pub fn add_return_type() {} +#[cfg(any(cfail1,cfail4))] +pub fn add_return_type() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg = "cfail6")] pub fn add_return_type() -> () {} // Change Parameter Type ------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn type_of_parameter(p: i32) {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" +)] +#[rustc_clean(cfg = "cfail6")] pub fn type_of_parameter(p: i64) {} // Change Parameter Type Reference --------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn type_of_parameter_ref(p: &i32) {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" +)] +#[rustc_clean(cfg = "cfail6")] pub fn type_of_parameter_ref(p: &mut i32) {} // Change Parameter Order ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn order_of_parameters(p1: i32, p2: i64) {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" +)] +#[rustc_clean(cfg = "cfail6")] pub fn order_of_parameters(p2: i64, p1: i32) {} // Unsafe ---------------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn make_unsafe() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" +)] +#[rustc_clean(cfg = "cfail6")] pub unsafe fn make_unsafe() {} // Extern ---------------------------------------------------------------------- -#[cfg(cfail1)] -pub fn make_extern() {} +#[cfg(any(cfail1,cfail4))] +pub fn make_extern() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")] +#[rustc_clean(cfg = "cfail6")] pub extern "C" fn make_extern() {} // Type Parameter -------------------------------------------------------------- -#[cfg(cfail1)] -pub fn type_parameter() {} +#[cfg(any(cfail1,cfail4))] +pub fn type_parameter () {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of" )] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of" +)] +#[rustc_clean(cfg = "cfail6")] pub fn type_parameter() {} // Lifetime Parameter ---------------------------------------------------------- -#[cfg(cfail1)] -pub fn lifetime_parameter() {} +#[cfg(any(cfail1,cfail4))] +pub fn lifetime_parameter () {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, generics_of,fn_sig")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, generics_of,fn_sig")] +#[rustc_clean(cfg = "cfail6")] pub fn lifetime_parameter<'a>() {} // Trait Bound ----------------------------------------------------------------- -#[cfg(cfail1)] -pub fn trait_bound() {} +#[cfg(any(cfail1,cfail4))] +pub fn trait_bound() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn trait_bound() {} // Builtin Bound --------------------------------------------------------------- -#[cfg(cfail1)] -pub fn builtin_bound() {} +#[cfg(any(cfail1,cfail4))] +pub fn builtin_bound() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail6")] pub fn builtin_bound() {} // Lifetime Bound -------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn lifetime_bound<'a, T>() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig,optimized_mir" +)] +#[rustc_clean(cfg = "cfail6")] pub fn lifetime_bound<'a, T: 'a>() {} // Second Trait Bound ---------------------------------------------------------- -#[cfg(cfail1)] -pub fn second_trait_bound() {} +#[cfg(any(cfail1,cfail4))] +pub fn second_trait_bound() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn second_trait_bound() {} // Second Builtin Bound -------------------------------------------------------- -#[cfg(cfail1)] -pub fn second_builtin_bound() {} +#[cfg(any(cfail1,cfail4))] +pub fn second_builtin_bound() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, predicates_of")] +#[rustc_clean(cfg = "cfail6")] pub fn second_builtin_bound() {} // Second Lifetime Bound ------------------------------------------------------- -#[cfg(cfail1)] -pub fn second_lifetime_bound<'a, 'b, T: 'a>() {} +#[cfg(any(cfail1,cfail4))] +pub fn second_lifetime_bound<'a, 'b, T: 'a >() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean( cfg = "cfail2", except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" )] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, generics_of, type_of, predicates_of,fn_sig" +)] +#[rustc_clean(cfg = "cfail6")] pub fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {} // Inline ---------------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn inline() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] #[inline] pub fn inline() {} // Inline Never ---------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[inline(always)] pub fn inline_never() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] #[inline(never)] pub fn inline_never() {} // No Mangle ------------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn no_mangle() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] #[no_mangle] pub fn no_mangle() {} // Linkage --------------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn linkage() {} -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] #[linkage = "weak_odr"] pub fn linkage() {} // Return Impl Trait ----------------------------------------------------------- -#[cfg(cfail1)] -pub fn return_impl_trait() -> i32 { +#[cfg(any(cfail1,cfail4))] +pub fn return_impl_trait() -> i32 { 0 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")] #[rustc_clean(cfg = "cfail3")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")] +#[rustc_clean(cfg = "cfail6")] pub fn return_impl_trait() -> impl Clone { 0 } // Change Return Impl Trait ---------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_return_impl_trait() -> impl Clone { 0u32 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] -pub fn change_return_impl_trait() -> impl Copy { +#[rustc_clean(cfg = "cfail5")] +#[rustc_clean(cfg = "cfail6")] +pub fn change_return_impl_trait() -> impl Copy { 0u32 } @@ -267,9 +335,9 @@ pub struct ReferencedType2; pub mod change_return_type_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedType1 as ReturnType; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as ReturnType; #[rustc_clean( @@ -277,6 +345,11 @@ except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] + #[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + )] + #[rustc_clean(cfg = "cfail6")] pub fn indirect_return_type() -> ReturnType { ReturnType {} } @@ -285,9 +358,9 @@ // Change Parameter Type Indirectly -------------------------------------------- pub mod change_parameter_type_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedType1 as ParameterType; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as ParameterType; #[rustc_clean( @@ -295,6 +368,11 @@ except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" )] #[rustc_clean(cfg = "cfail3")] + #[rustc_clean( + cfg = "cfail5", + except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig" + )] + #[rustc_clean(cfg = "cfail6")] pub fn indirect_parameter_type(p: ParameterType) {} } @@ -304,26 +382,30 @@ pub trait ReferencedTrait2 {} pub mod change_trait_bound_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait1 as Trait; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] + #[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail6")] pub fn indirect_trait_bound(p: T) {} } // Change Trait Bound Indirectly In Where Clause ------------------------------- pub mod change_trait_bound_indirectly_in_where_clause { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait1 as Trait; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, predicates_of")] #[rustc_clean(cfg = "cfail3")] + #[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, predicates_of")] + #[rustc_clean(cfg = "cfail6")] pub fn indirect_trait_bound_where(p: T) where T: Trait, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/if_expressions.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/if_expressions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/if_expressions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/if_expressions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,27 +6,34 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans - +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] #![crate_type="rlib"] // Change condition (if) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_condition(x: bool) -> u32 { - if x { + if x { return 1 } return 0 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_condition(x: bool) -> u32 { if !x { return 1 @@ -36,7 +43,7 @@ } // Change then branch (if) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_then_branch(x: bool) -> u32 { if x { return 1 @@ -45,9 +52,11 @@ return 0 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_then_branch(x: bool) -> u32 { if x { return 2 @@ -59,7 +68,7 @@ // Change else branch (if) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_else_branch(x: bool) -> u32 { if x { 1 @@ -68,9 +77,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_else_branch(x: bool) -> u32 { if x { 1 @@ -82,20 +93,23 @@ // Add else branch (if) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_else_branch(x: bool) -> u32 { let mut ret = 1; if x { ret = 2; + /*----*/ } ret } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_else_branch(x: bool) -> u32 { let mut ret = 1; @@ -110,7 +124,7 @@ // Change condition (if let) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_condition_if_let(x: Option) -> u32 { if let Some(_x) = x { return 1 @@ -119,11 +133,13 @@ 0 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_condition_if_let(x: Option) -> u32 { - if let Some(_) = x { + if let Some(_ ) = x { return 1 } @@ -133,18 +149,20 @@ // Change then branch (if let) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_then_branch_if_let(x: Option) -> u32 { if let Some(x) = x { - return x + return x //- } 0 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_then_branch_if_let(x: Option) -> u32 { if let Some(x) = x { return x + 1 @@ -156,7 +174,7 @@ // Change else branch (if let) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_else_branch_if_let(x: Option) -> u32 { if let Some(x) = x { x @@ -165,9 +183,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_else_branch_if_let(x: Option) -> u32 { if let Some(x) = x { x @@ -179,20 +199,23 @@ // Add else branch (if let) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_else_branch_if_let(x: Option) -> u32 { let mut ret = 1; if let Some(x) = x { ret = x; + /*----*/ } ret } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_else_branch_if_let(x: Option) -> u32 { let mut ret = 1; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/indexing_expressions.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/indexing_expressions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/indexing_expressions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/indexing_expressions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,22 +6,30 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] #![crate_type="rlib"] // Change simple index -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] fn change_simple_index(slice: &[u32]) -> u32 { slice[3] } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] fn change_simple_index(slice: &[u32]) -> u32 { slice[4] } @@ -29,14 +37,16 @@ // Change lower bound -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] fn change_lower_bound(slice: &[u32]) -> &[u32] { &slice[3..5] } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] fn change_lower_bound(slice: &[u32]) -> &[u32] { &slice[2..5] } @@ -44,14 +54,16 @@ // Change upper bound -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] fn change_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..5] } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] fn change_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] } @@ -59,14 +71,16 @@ // Add lower bound -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] fn add_lower_bound(slice: &[u32]) -> &[u32] { - &slice[..4] + &slice[ ..4] } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] fn add_lower_bound(slice: &[u32]) -> &[u32] { &slice[3..4] } @@ -74,14 +88,16 @@ // Add upper bound -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] fn add_upper_bound(slice: &[u32]) -> &[u32] { - &slice[3..] + &slice[3.. ] } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] fn add_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] } @@ -89,29 +105,33 @@ // Change mutability -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] fn change_mutability(slice: &mut [u32]) -> u32 { (&mut slice[3..5])[0] } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] fn change_mutability(slice: &mut [u32]) -> u32 { - (&slice[3..5])[0] + (& slice[3..5])[0] } // Exclusive to inclusive range -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { - &slice[3..7] + &slice[3.. 7] } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { &slice[3..=7] } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/inherent_impls.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/inherent_impls.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/inherent_impls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/inherent_impls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] @@ -17,36 +23,46 @@ pub struct Foo; // Change Method Name ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { pub fn method_name() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,associated_item_def_ids")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail6")] pub fn method_name2() { } } // Change Method Body ----------------------------------------------------------- // // This should affect the method itself, but not the impl. -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn method_body() { } + //-------------------------------------------------------------------------------------- + //-------------------------- + //-------------------------------------------------------------------------------------- + //-------------------------- + pub fn method_body() { + // ----------------------- + } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean( - cfg="cfail2", - except="hir_owner_nodes,optimized_mir,promoted_mir,typeck" - )] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck")] + #[rustc_clean(cfg="cfail6")] pub fn method_body() { println!("Hello, world!"); } @@ -56,21 +72,40 @@ // Change Method Body (inlined) ------------------------------------------------ // // This should affect the method itself, but not the impl. -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { + //------------ + //--------------- + //------------------------------------------------------------ + // + //-------------------------- + //------------ + //--------------- + //------------------------------------------------------------ + // + //-------------------------- #[inline] - pub fn method_body_inlined() { } + pub fn method_body_inlined() { + // ----------------------- + } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean( cfg="cfail2", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck" )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="hir_owner_nodes,optimized_mir,promoted_mir,typeck" + )] + #[rustc_clean(cfg="cfail6")] #[inline] pub fn method_body_inlined() { println!("Hello, world!"); @@ -79,146 +114,209 @@ // Change Method Privacy ------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { + //------------------------------------------------------------------------------ + //-------------------------- + //------------------------------------------------------------------------------ + //-------------------------- pub fn method_privacy() { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="associated_item,hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] - fn method_privacy() { } + #[rustc_clean(cfg="cfail5", except="associated_item,hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg="cfail6")] + fn method_privacy() { } } // Change Method Selfness ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { + //------------ + //--------------- + //--------------------------------------------------------------------------------------------- + // + //-------------------------- + //------------ + //--------------- + //--------------------------------------------------------------------------------------------- + // + //-------------------------- pub fn method_selfness() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean( cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", + )] + #[rustc_clean(cfg="cfail6")] pub fn method_selfness(&self) { } } // Change Method Selfmutness --------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn method_selfmutness(&self) { } + //------------------------------------------------------------------------------------------ + //-------------------------- + //------------------------------------------------------------------------------------------ + //-------------------------- + pub fn method_selfmutness(& self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean( - cfg="cfail2", - except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir" - )] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail6")] pub fn method_selfmutness(&mut self) { } } // Add Method To Impl ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { pub fn add_method_to_impl1(&self) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,associated_item_def_ids")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] pub fn add_method_to_impl1(&self) { } #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail6")] pub fn add_method_to_impl2(&self) { } } // Add Method Parameter -------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn add_method_parameter(&self) { } + //------------------------------------------------------------------------------------------ + //-------------------------- + //------------------------------------------------------------------------------------------ + //-------------------------- + pub fn add_method_parameter(&self ) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean( - cfg="cfail2", - except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir" - )] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail6")] pub fn add_method_parameter(&self, _: i32) { } } // Change Method Parameter Name ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { + //------------------------------------------------------------------ + //-------------------------- + //------------------------------------------------------------------ + //-------------------------- pub fn change_method_parameter_name(&self, a: i64) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail6")] pub fn change_method_parameter_name(&self, b: i64) { } } // Change Method Return Type --------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { + //------------------------------------------------------------------------------------------ + //-------------------------- + //------------------------------------------------------------------------------------------ + //-------------------------- pub fn change_method_return_type(&self) -> u16 { 0 } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean( - cfg="cfail2", - except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - pub fn change_method_return_type(&self) -> u8 { 0 } + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail6")] + pub fn change_method_return_type(&self) -> u32 { 0 } } // Make Method #[inline] ------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { + //-------------------------- + //-------------------------- + //-------------------------- + //-------------------------- + //------- pub fn make_method_inline(&self) -> u8 { 0 } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] #[inline] pub fn make_method_inline(&self) -> u8 { 0 } } @@ -226,85 +324,129 @@ // Change order of parameters ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { + //------------------------------------------------------------------ + //-------------------------- + //------------------------------------------------------------------ + //-------------------------- pub fn change_method_parameter_order(&self, a: i64, b: i64) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] + #[rustc_clean(cfg="cfail6")] pub fn change_method_parameter_order(&self, b: i64, a: i64) { } } // Make method unsafe ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn make_method_unsafe(&self) { } + //------------------------------------------------------------------------------------------ + //-------------------------- + //------------------------------------------------------------------------------------------ + //-------------------------- + pub fn make_method_unsafe(&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean( - cfg="cfail2", - except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir" - )] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] + #[rustc_clean(cfg="cfail6")] pub unsafe fn make_method_unsafe(&self) { } } // Make method extern ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn make_method_extern(&self) { } + //---------------------------------------------------------------------------- + //-------------------------- + //---------------------------------------------------------------------------- + //-------------------------- + pub fn make_method_extern(&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail6")] pub extern "C" fn make_method_extern(&self) { } } // Change method calling convention -------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub extern "C" fn change_method_calling_convention(&self) { } + //---------------------------------------------------------------------------- + //-------------------------- + //---------------------------------------------------------------------------- + //-------------------------- + pub extern "C" fn change_method_calling_convention(&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] + #[rustc_clean(cfg="cfail6")] pub extern "system" fn change_method_calling_convention(&self) { } } // Add Lifetime Parameter to Method -------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn add_lifetime_parameter_to_method(&self) { } + // ----------------------------------------------------- + // --------------------------------------------------------- + // ---------------------------------------------------------- + // ------------------------------------------------------- + // ------------------------------------------------------- + // -------------------------------------------------------- + // ---------------------------------------------------------- + // ----------------------------------------------------------- + // ---------------------------------------------------------- + // -------------------------------------------------------------------- + // ------------------------- + // -------------------------------------------------------------------------------- + // ------------------------- + pub fn add_lifetime_parameter_to_method (&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { // Warning: Note that `typeck` are coming up clean here. // The addition or removal of lifetime parameters that don't @@ -317,20 +459,43 @@ // `typeck` appear dirty, that might be the cause. -nmatsakis #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,fn_sig,generics_of")] + #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } // Add Type Parameter To Method ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn add_type_parameter_to_method(&self) { } + // ----------------------------------------------------- + // --------------------------------------------------------------- + // ------------------------------------------------------------- + // ----------------------------------------------------- + // ------------------------------------------------------------- + // --------------------------------------------------- + // ------------------------------------------------------------ + // ------------------------------------------------------ + // ------------------------------------------------- + // ----------- + // -------------- + // ---------------------------------------------------------------------- + // + // ------------------------- + // ----------- + // -------------- + // ---------------------------------------------------------------------- + // + // ------------------------- + pub fn add_type_parameter_to_method (&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { // Warning: Note that `typeck` are coming up clean here. // The addition or removal of type parameters that don't appear in @@ -346,40 +511,83 @@ except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of", )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of", + )] + #[rustc_clean(cfg="cfail6")] pub fn add_type_parameter_to_method(&self) { } } // Add Lifetime Bound to Lifetime Parameter of Method -------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b>(&self) { } + //------------ + //--------------- + //----------------------------------------------------------------------------- + // + //-------------------------- + //------------ + //--------------- + //----------------------------------------------------------------------------- + // + //-------------------------- + pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b >(&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean( cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + )] + #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { } } // Add Lifetime Bound to Type Parameter of Method ------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn add_lifetime_bound_to_type_param_of_method<'a, T>(&self) { } + // ----------------------------------------------------- + // ---------------------------------------------------------- + // ------------------------------------------------------------- + // ------------------------------------------------- + // ------------------------------------------------------------- + // --------------------------------------------------- + // ------------------------------------------------------------ + // ------------------------------------------------------ + // ------------------------------------------------- + // ----------- + // -------------- + // ---------------------------------------------------------------------------- + // + // ------------------------- + // ----------- + // -------------- + // ---------------------------------------------------------------------------- + // + // ------------------------- + pub fn add_lifetime_bound_to_type_param_of_method<'a, T >(&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { // Warning: Note that `typeck` are coming up clean here. // The addition or removal of bounds that don't appear in the @@ -390,23 +598,45 @@ // generics before the body, then the `HirId` for things in the // body will be affected. So if you start to see `typeck` // appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,\ - type_of,fn_sig")] + #[rustc_clean( + cfg="cfail2", + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig" + )] + #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { } } // Add Trait Bound to Type Parameter of Method ------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { - pub fn add_trait_bound_to_type_param_of_method(&self) { } + // ----------------------------------------------------- + // ---------------------------------------------------------- + // ------------------------------------------------------------- + // ------------------------------------------------- + // ------------------------------------------------------------- + // --------------------------------------------------- + // ------------------------------------------------------------ + // ------------------------------------------------------ + // ------------------------------------------------- + // --------------------------------------------------------------------------- + // ------------------------- + // --------------------------------------------------------------------------- + // ------------------------- + pub fn add_trait_bound_to_type_param_of_method(&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { // Warning: Note that `typeck` are coming up clean here. // The addition or removal of bounds that don't appear in the @@ -419,23 +649,34 @@ // appear dirty, that might be the cause. -nmatsakis #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] + #[rustc_clean(cfg="cfail6")] pub fn add_trait_bound_to_type_param_of_method(&self) { } } // Add #[no_mangle] to Method -------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Foo { + //-------------------------- + //-------------------------- + //-------------------------- + //-------------------------- + //---------- pub fn add_no_mangle_to_method(&self) { } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] #[no_mangle] pub fn add_no_mangle_to_method(&self) { } } @@ -445,71 +686,90 @@ struct Bar(T); // Add Type Parameter To Impl -------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Bar { pub fn add_type_parameter_to_impl(&self) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of")] +#[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean( cfg="cfail2", except="generics_of,fn_sig,typeck,type_of,optimized_mir" )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="generics_of,fn_sig,typeck,type_of,optimized_mir" + )] + #[rustc_clean(cfg="cfail6")] pub fn add_type_parameter_to_impl(&self) { } } // Change Self Type of Impl ---------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Bar { pub fn change_impl_self_type(&self) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner")] +#[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="fn_sig,optimized_mir,typeck")] + #[rustc_clean(cfg="cfail6")] pub fn change_impl_self_type(&self) { } } // Add Lifetime Bound to Impl -------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Bar { pub fn add_lifetime_bound_to_impl_parameter(&self) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] pub fn add_lifetime_bound_to_impl_parameter(&self) { } } // Add Trait Bound to Impl Parameter ------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl Bar { pub fn add_trait_bound_to_impl_parameter(&self) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] impl Bar { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] pub fn add_trait_bound_to_impl_parameter(&self) { } } @@ -518,12 +778,12 @@ pub fn instantiation_root() { Foo::method_privacy(); - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] { Bar(0u32).change_impl_self_type(); } - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] { Bar(0u64).change_impl_self_type(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/inline_asm.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/inline_asm.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/inline_asm.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/inline_asm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -17,7 +23,7 @@ // Change template -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_template(a: i32) -> i32 { let c: i32; @@ -32,9 +38,11 @@ c } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_template(a: i32) -> i32 { let c: i32; @@ -52,7 +60,7 @@ // Change output -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_output(a: i32) -> i32 { let mut _out1: i32 = 0; @@ -68,9 +76,11 @@ _out1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_output(a: i32) -> i32 { let mut _out1: i32 = 0; @@ -89,7 +99,7 @@ // Change input -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input(_a: i32, _b: i32) -> i32 { let _out; @@ -104,9 +114,11 @@ _out } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input(_a: i32, _b: i32) -> i32 { let _out; @@ -124,7 +136,7 @@ // Change input constraint -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input_constraint(_a: i32, _b: i32) -> i32 { let _out; @@ -139,9 +151,11 @@ _out } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input_constraint(_a: i32, _b: i32) -> i32 { let _out; @@ -159,7 +173,7 @@ // Change clobber -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_clobber(_a: i32) -> i32 { let _out; @@ -167,16 +181,18 @@ llvm_asm!("add 1, $0" : "=r"(_out) : "0"(_a) - : + :/*--*/ : ); } _out } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_clobber(_a: i32) -> i32 { let _out; @@ -194,7 +210,7 @@ // Change options -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_options(_a: i32) -> i32 { let _out; @@ -203,15 +219,17 @@ : "=r"(_out) : "0"(_a) : - : + :/*-------*/ ); } _out } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_options(_a: i32) -> i32 { let _out; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/let_expressions.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/let_expressions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/let_expressions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/let_expressions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,24 +6,30 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans - +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] #![crate_type="rlib"] // Change Name ----------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_name() { let _x = 2u64; } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_name() { let _y = 2u64; } @@ -31,15 +37,16 @@ // Add Type -------------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_type() { - let _x = 2u32; + let _x = 2u32; } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_type() { let _x: u32 = 2u32; } @@ -47,31 +54,33 @@ // Change Type ----------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_type() { let _x: u64 = 2; } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_type() { - let _x: u8 = 2; + let _x: u8 = 2; } // Change Mutability of Reference Type ----------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_mutability_of_reference_type() { - let _x: &u64; + let _x: & u64; } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_mutability_of_reference_type() { let _x: &mut u64; } @@ -79,31 +88,33 @@ // Change Mutability of Slot --------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_mutability_of_slot() { let mut _x: u64 = 0; } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_mutability_of_slot() { - let _x: u64 = 0; + let _x: u64 = 0; } // Change Simple Binding to Pattern -------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_simple_binding_to_pattern() { - let _x = (0u8, 'x'); + let _x = (0u8, 'x'); } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_simple_binding_to_pattern() { let (_a, _b) = (0u8, 'x'); } @@ -111,15 +122,16 @@ // Change Name in Pattern ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_name_in_pattern() { let (_a, _b) = (1u8, 'y'); } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_name_in_pattern() { let (_a, _c) = (1u8, 'y'); } @@ -127,15 +139,16 @@ // Add `ref` in Pattern -------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_ref_in_pattern() { - let (_a, _b) = (1u8, 'y'); + let ( _a, _b) = (1u8, 'y'); } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_ref_in_pattern() { let (ref _a, _b) = (1u8, 'y'); } @@ -143,15 +156,16 @@ // Add `&` in Pattern ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_amp_in_pattern() { - let (_a, _b) = (&1u8, 'y'); + let ( _a, _b) = (&1u8, 'y'); } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_amp_in_pattern() { let (&_a, _b) = (&1u8, 'y'); } @@ -159,15 +173,16 @@ // Change Mutability of Binding in Pattern ------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_mutability_of_binding_in_pattern() { - let (_a, _b) = (99u8, 'q'); + let ( _a, _b) = (99u8, 'q'); } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_mutability_of_binding_in_pattern() { let (mut _a, _b) = (99u8, 'q'); } @@ -175,15 +190,16 @@ // Add Initializer ------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_initializer() { - let _x: i16; + let _x: i16 ; } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_initializer() { let _x: i16 = 3i16; } @@ -191,15 +207,16 @@ // Change Initializer ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_initializer() { let _x = 4u16; } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_initializer() { let _x = 5u16; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/loop_expressions.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/loop_expressions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/loop_expressions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/loop_expressions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -15,7 +21,7 @@ // Change loop body -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_loop_body() { let mut _x = 0; loop { @@ -24,9 +30,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_loop_body() { let mut _x = 0; loop { @@ -38,17 +46,20 @@ // Add break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_break() { let mut _x = 0; loop { _x = 1; + //---- } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_break() { let mut _x = 0; loop { @@ -60,18 +71,20 @@ // Add loop label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label() { let mut _x = 0; - loop { + /*---*/ loop { _x = 1; break; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label() { let mut _x = 0; 'label: loop { @@ -83,18 +96,20 @@ // Add loop label to break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label_to_break() { let mut _x = 0; 'label: loop { _x = 1; - break; + break ; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; 'label: loop { @@ -106,7 +121,7 @@ // Change break label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_break_label() { let mut _x = 0; 'outer: loop { @@ -117,9 +132,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_break_label() { let mut _x = 0; 'outer: loop { @@ -133,18 +150,20 @@ // Add loop label to continue -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label_to_continue() { let mut _x = 0; 'label: loop { _x = 1; - continue; + continue ; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_continue() { let mut _x = 0; 'label: loop { @@ -156,7 +175,7 @@ // Change continue label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_continue_label() { let mut _x = 0; 'outer: loop { @@ -167,9 +186,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_continue_label() { let mut _x = 0; 'outer: loop { @@ -183,7 +204,7 @@ // Change continue to break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_continue_to_break() { let mut _x = 0; loop { @@ -192,13 +213,15 @@ } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_continue_to_break() { let mut _x = 0; loop { _x = 1; - break; + break ; } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/match_expressions.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/match_expressions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/match_expressions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/match_expressions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,28 +6,35 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans - +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] #![crate_type="rlib"] // Add Arm --------------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_arm(x: u32) -> u32 { match x { 0 => 0, 1 => 1, + /*---*/ _ => 100, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_arm(x: u32) -> u32 { match x { 0 => 0, @@ -40,7 +47,7 @@ // Change Order Of Arms -------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_order_of_arms(x: u32) -> u32 { match x { 0 => 0, @@ -49,10 +56,11 @@ } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_order_of_arms(x: u32) -> u32 { match x { 1 => 1, @@ -64,19 +72,20 @@ // Add Guard Clause ------------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_guard_clause(x: u32, y: bool) -> u32 { match x { 0 => 0, - 1 => 1, + 1 => 1, _ => 100, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_guard_clause(x: u32, y: bool) -> u32 { match x { 0 => 0, @@ -88,19 +97,20 @@ // Change Guard Clause ------------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_guard_clause(x: u32, y: bool) -> u32 { match x { 0 => 0, - 1 if y => 1, + 1 if y => 1, _ => 100, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_guard_clause(x: u32, y: bool) -> u32 { match x { 0 => 0, @@ -112,19 +122,20 @@ // Add @-Binding --------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_at_binding(x: u32) -> u32 { match x { 0 => 0, 1 => 1, - _ => x, + _ => x, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_at_binding(x: u32) -> u32 { match x { 0 => 0, @@ -136,7 +147,7 @@ // Change Name of @-Binding ---------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_name_of_at_binding(x: u32) -> u32 { match x { 0 => 0, @@ -145,10 +156,11 @@ } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_name_of_at_binding(x: u32) -> u32 { match x { 0 => 0, @@ -160,18 +172,19 @@ // Change Simple Binding To Pattern -------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_simple_name_to_pattern(x: u32) -> u32 { match (x, x & 1) { (0, 0) => 0, - a => 1, + a => 1, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_simple_name_to_pattern(x: u32) -> u32 { match (x, x & 1) { (0, 0) => 0, @@ -182,7 +195,7 @@ // Change Name In Pattern ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_name_in_pattern(x: u32) -> u32 { match (x, x & 1) { (a, 0) => 0, @@ -191,10 +204,11 @@ } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_name_in_pattern(x: u32) -> u32 { match (x, x & 1) { (b, 0) => 0, @@ -206,18 +220,19 @@ // Change Mutability Of Binding In Pattern ------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { - (a, 0) => 0, + ( a, 0) => 0, _ => 1, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { (mut a, 0) => 0, @@ -228,18 +243,19 @@ // Add `ref` To Binding In Pattern ------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { - (a, 0) => 0, + ( a, 0) => 0, _ => 1, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { (ref a, 0) => 0, @@ -250,18 +266,19 @@ // Add `&` To Binding In Pattern ------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { match (&x, x & 1) { - (a, 0) => 0, + ( a, 0) => 0, _ => 1, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", -except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { match (&x, x & 1) { (&a, 0) => 0, @@ -272,7 +289,7 @@ // Change RHS Of Arm ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_rhs_of_arm(x: u32) -> u32 { match x { 0 => 0, @@ -281,10 +298,11 @@ } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_rhs_of_arm(x: u32) -> u32 { match x { 0 => 0, @@ -296,19 +314,20 @@ // Add Alternative To Arm ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_alternative_to_arm(x: u32) -> u32 { match x { - 0 => 0, + 0 => 0, 1 => 1, _ => 2, } } -#[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,optimized_mir,typeck")] +#[cfg(not(any(cfail1,cfail4)))] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_alternative_to_arm(x: u32) -> u32 { match x { 0 | 7 => 0, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/statics.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/statics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/statics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/statics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -17,86 +23,102 @@ // Change static visibility -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] static STATIC_VISIBILITY: u8 = 0; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub static STATIC_VISIBILITY: u8 = 0; // Change static mutability -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] static STATIC_MUTABILITY: u8 = 0; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] static mut STATIC_MUTABILITY: u8 = 0; // Add linkage attribute -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] static STATIC_LINKAGE: u8 = 0; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] #[linkage="weak_odr"] static STATIC_LINKAGE: u8 = 0; // Add no_mangle attribute -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] static STATIC_NO_MANGLE: u8 = 0; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] #[no_mangle] static STATIC_NO_MANGLE: u8 = 0; // Add thread_local attribute -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] static STATIC_THREAD_LOCAL: u8 = 0; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] #[thread_local] static STATIC_THREAD_LOCAL: u8 = 0; // Change type from i16 to u64 -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] static STATIC_CHANGE_TYPE_1: i16 = 0; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_1: u64 = 0; // Change type from Option to Option -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] static STATIC_CHANGE_TYPE_2: Option = None; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] +#[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_2: Option = None; // Change value between simple literals #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_VALUE_1: i16 = { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] { 1 } - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] { 2 } }; @@ -104,31 +126,37 @@ // Change value between expressions #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_VALUE_2: i16 = { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] { 1 + 1 } - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] { 1 + 2 } }; #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_VALUE_3: i16 = { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] { 2 + 3 } - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] { 2 * 3 } }; #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_VALUE_4: i16 = { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] { 1 + 2 * 3 } - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] { 1 + 2 * 4 } }; @@ -138,17 +166,21 @@ struct ReferencedType2; mod static_change_type_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedType1 as Type; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as Type; #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type; #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,type_of")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,type_of")] + #[rustc_clean(cfg="cfail6")] static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option = None; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/struct_constructors.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/struct_constructors.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/struct_constructors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/struct_constructors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -21,7 +27,7 @@ } // Change field value (regular struct) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_field_value_regular_struct() -> RegularStruct { RegularStruct { x: 0, @@ -30,9 +36,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_field_value_regular_struct() -> RegularStruct { RegularStruct { x: 0, @@ -44,7 +52,7 @@ // Change field order (regular struct) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_field_order_regular_struct() -> RegularStruct { RegularStruct { x: 3, @@ -53,9 +61,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_field_order_regular_struct() -> RegularStruct { RegularStruct { y: 4, @@ -67,7 +77,7 @@ // Add field (regular struct) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { x: 3, @@ -77,13 +87,16 @@ RegularStruct { x: 7, + // -- .. struct1 } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { x: 3, @@ -101,7 +114,7 @@ // Change field label (regular struct) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_field_label_regular_struct() -> RegularStruct { let struct1 = RegularStruct { x: 3, @@ -116,9 +129,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_field_label_regular_struct() -> RegularStruct { let struct1 = RegularStruct { x: 3, @@ -142,18 +157,20 @@ } // Change constructor path (regular struct) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_constructor_path_regular_struct() { - let _ = RegularStruct { + let _ = RegularStruct { x: 0, y: 1, z: 2, }; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_regular_struct() { let _ = RegularStruct2 { x: 0, @@ -166,9 +183,9 @@ // Change constructor path indirectly (regular struct) pub mod change_constructor_path_indirectly_regular_struct { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::RegularStruct as Struct; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::RegularStruct2 as Struct; #[rustc_clean( @@ -176,6 +193,11 @@ except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck" )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + cfg="cfail5", + except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck" + )] + #[rustc_clean(cfg="cfail6")] pub fn function() -> Struct { Struct { x: 0, @@ -190,14 +212,16 @@ pub struct TupleStruct(i32, i64, i16); // Change field value (tuple struct) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_field_value_tuple_struct() -> TupleStruct { TupleStruct(0, 1, 2) } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_field_value_tuple_struct() -> TupleStruct { TupleStruct(0, 1, 3) } @@ -207,14 +231,16 @@ pub struct TupleStruct2(u16, u16, u16); // Change constructor path (tuple struct) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_constructor_path_tuple_struct() { - let _ = TupleStruct(0, 1, 2); + let _ = TupleStruct (0, 1, 2); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_constructor_path_tuple_struct() { let _ = TupleStruct2(0, 1, 2); } @@ -223,12 +249,17 @@ // Change constructor path indirectly (tuple struct) pub mod change_constructor_path_indirectly_tuple_struct { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::TupleStruct as Struct; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::TupleStruct2 as Struct; #[rustc_clean( + cfg="cfail5", + except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck" + )] + #[rustc_clean(cfg="cfail6")] + #[rustc_clean( cfg="cfail2", except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck" )] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/struct_defs.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/struct_defs.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/struct_defs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/struct_defs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,42 +11,53 @@ // the same between rev2 and rev3. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans - +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] #![crate_type="rlib"] // Layout ---------------------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub struct LayoutPacked; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="type_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] #[repr(packed)] pub struct LayoutPacked; -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct LayoutC; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="type_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] #[repr(C)] struct LayoutC; // Tuple Struct Change Field Type ---------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct TupleStructFieldType(i32); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] // Note that changing the type of a field does not change the type of the struct or enum, but // adding/removing fields or changing a fields name or visibility does. struct TupleStructFieldType( @@ -56,12 +67,14 @@ // Tuple Struct Add Field ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct TupleStructAddField(i32); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct TupleStructAddField( i32, u32 @@ -70,23 +83,27 @@ // Tuple Struct Field Visibility ----------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct TupleStructFieldVisibility(char); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct TupleStructFieldVisibility(pub char); // Record Struct Field Type ---------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct RecordStructFieldType { x: f32 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] // Note that changing the type of a field does not change the type of the struct or enum, but // adding/removing fields or changing a fields name or visibility does. struct RecordStructFieldType { @@ -96,23 +113,27 @@ // Record Struct Field Name ---------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct RecordStructFieldName { x: f32 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct RecordStructFieldName { y: f32 } // Record Struct Add Field ----------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct RecordStructAddField { x: f32 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct RecordStructAddField { x: f32, y: () } @@ -120,12 +141,14 @@ // Record Struct Field Visibility ---------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct RecordStructFieldVisibility { x: f32 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct RecordStructFieldVisibility { pub x: f32 } @@ -133,34 +156,40 @@ // Add Lifetime Parameter ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct AddLifetimeParameter<'a>(&'a f32, &'a f64); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64); // Add Lifetime Parameter Bound ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct AddLifetimeParameterBound<'a, 'b: 'a>( &'a f32, &'b f64 ); -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct AddLifetimeParameterBoundWhereClause<'a, 'b>( &'a f32, &'b f64) @@ -169,12 +198,14 @@ // Add Type Parameter ---------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct AddTypeParameter(T1, T1); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct AddTypeParameter( // The field contains the parent's Generics, so it's dirty even though its // type hasn't changed. @@ -185,23 +216,27 @@ // Add Type Parameter Bound ---------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct AddTypeParameterBound(T); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct AddTypeParameterBound( T ); -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct AddTypeParameterBoundWhereClause(T); -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] struct AddTypeParameterBoundWhereClause( T ) where T: Sync; @@ -214,17 +249,21 @@ // Note: there is no #[cfg(...)], so this is ALWAYS compiled #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub struct EmptyStruct; // Visibility ------------------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] struct Visibility; -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub struct Visibility; struct ReferencedType1; @@ -232,13 +271,15 @@ // Tuple Struct Change Field Type Indirectly ----------------------------------- mod tuple_struct_change_field_type_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedType1 as FieldType; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] struct TupleStruct( FieldType ); @@ -247,13 +288,15 @@ // Record Struct Change Field Type Indirectly ----------------------------------- mod record_struct_change_field_type_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedType1 as FieldType; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedType2 as FieldType; #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] struct RecordStruct { _x: FieldType } @@ -267,24 +310,28 @@ // Change Trait Bound Indirectly ----------------------------------------------- mod change_trait_bound_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait1 as Trait; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] struct Struct(T); } // Change Trait Bound Indirectly In Where Clause ------------------------------- mod change_trait_bound_indirectly_in_where_clause { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait1 as Trait; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait2 as Trait; #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] struct Struct(T) where T : Trait; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/trait_defs.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/trait_defs.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/trait_defs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/trait_defs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,8 +11,14 @@ // the same between rev2 and rev3. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -21,35 +27,41 @@ // Change trait visibility -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitVisibility { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub trait TraitVisibility { } // Change trait unsafety -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitUnsafety { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] unsafe trait TraitUnsafety { } // Add method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddMethod { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub trait TraitAddMethod { fn method(); } @@ -57,14 +69,16 @@ // Change name of method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeMethodName { fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeMethodName { fn methodChanged(); } @@ -72,157 +86,227 @@ // Add return type to method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddReturnType { - fn method(); + //----------------------------------------------------- + //-------------------------- + //----------------------------------------------------- + //-------------------------- + fn method() ; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddReturnType { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method() -> u32; } // Change return type of method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeReturnType { + // -------------------------------------------------------------------- + // ------------------------- + // -------------------------------------------------------------------- + // ------------------------- fn method() -> u32; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeReturnType { #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method() -> u64; } // Add parameter to method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddParameterToMethod { - fn method(); + // ---------------------------------------------------- + // ------------------------- + // ---------------------------------------------------- + // ------------------------- + fn method( ); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddParameterToMethod { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(a: u32); } // Change name of method parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterName { + //------------------------------------------------------ + //---------------------------------------------- + //-------------------------- + //---------------------------------------------- + //-------------------------- fn method(a: u32); + + //------------------------------------------------------------------ + //-------------------------- + //------------------------------------------------------------------ + //-------------------------- fn with_default(x: i32) {} } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(b: u32); #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn with_default(y: i32) {} } // Change type of method parameter (i32 => i64) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterType { + // ---------------------------------------------------- + // ------------------------- + // ---------------------------------------------------- + // ------------------------- fn method(a: i32); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterType { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(a: i64); } // Change type of method parameter (&i32 => &mut i32) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterTypeRef { - fn method(a: &i32); + // ---------------------------------------------------- + // ------------------------- + // ---------------------------------------------------- + // ------------------------- + fn method(a: & i32); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterTypeRef { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(a: &mut i32); } // Change order of method parameters -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParametersOrder { + // ---------------------------------------------------- + // ------------------------- + // ---------------------------------------------------- + // ------------------------- fn method(a: i32, b: i64); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParametersOrder { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(b: i64, a: i32); } // Add default implementation to method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddMethodAutoImplementation { fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddMethodAutoImplementation { #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method() { } } // Change order of methods -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeOrderOfMethods { fn method0(); fn method1(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeOrderOfMethods { fn method1(); fn method0(); @@ -231,134 +315,198 @@ // Change mode of self parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfRefToMut { - fn method(&self); + // ---------------------------------------------------- + // ------------------------- + // ---------------------------------------------------- + // ------------------------- + fn method(& self); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfRefToMut { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(&mut self); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfOwnToMut: Sized { - fn method(self) {} + // ---------------------------------------------------------------------------------- + // ------------------------- + // ---------------------------------------------------------------------------------- + // ------------------------- + fn method( self) {} } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfOwnToMut: Sized { #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(mut self) {} } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfOwnToRef { - fn method(self); + // ---------------------------------------------------------------- + // ------------------------- + // ---------------------------------------------------------------- + // ------------------------- + fn method( self); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfOwnToRef { #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(&self); } // Add unsafe modifier to method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddUnsafeModifier { - fn method(); + // ---------------------------------------------------- + // ------------------------- + // ---------------------------------------------------- + // ------------------------- + fn method() ; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddUnsafeModifier { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] unsafe fn method(); } // Add extern modifier to method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddExternModifier { - fn method(); + // ---------------------------------------------------- + // ------------------------- + // ---------------------------------------------------- + // ------------------------- + fn method() ; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddExternModifier { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] extern "C" fn method(); } // Change extern "C" to extern "stdcall" -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeExternCToRustIntrinsic { - extern "C" fn method(); + // ---------------------------------------------------- + // ------------------------- + // ---------------------------------------------------- + // ------------------------- + extern "C" fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeExternCToRustIntrinsic { #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] extern "stdcall" fn method(); } // Add type parameter to method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddTypeParameterToMethod { - fn method(); + // ------------------------------------------------------------------------------- + // ------------------------- + // ------------------------------------------------------------------------------- + // ------------------------- + fn method (); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddTypeParameterToMethod { #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(); } // Add lifetime parameter to method -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeParameterToMethod { - fn method(); + // ---------------------------------------------------------------- + // ------------------------- + // ---------------------------------------------------------------- + // ------------------------- + fn method (); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeParameterToMethod { #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method<'a>(); } @@ -369,137 +517,220 @@ trait ReferencedTrait1 { } // Add trait bound to method type parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToMethodTypeParameter { - fn method(); + // --------------------------------------------------------------------------- + // ------------------------- + // --------------------------------------------------------------------------- + // ------------------------- + fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToMethodTypeParameter { #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(); } // Add builtin bound to method type parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddBuiltinBoundToMethodTypeParameter { - fn method(); + // --------------------------------------------------------------------------- + // ------------------------- + // --------------------------------------------------------------------------- + // ------------------------- + fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToMethodTypeParameter { #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(); } // Add lifetime bound to method lifetime parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToMethodLifetimeParameter { - fn method<'a, 'b>(a: &'a u32, b: &'b u32); + // ----------- + // ----------------------------------------------------------------------------- + // -------------- + // + // ------------------------- + // ----------- + // ----------------------------------------------------------------------------- + // -------------- + // + // ------------------------- + fn method<'a, 'b >(a: &'a u32, b: &'b u32); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[rustc_clean( except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + cfg="cfail5", + )] + #[rustc_clean(cfg="cfail6")] fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32); } // Add second trait bound to method type parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondTraitBoundToMethodTypeParameter { - fn method(); + // --------------------------------------------------------------------------- + // ------------------------- + // --------------------------------------------------------------------------- + // ------------------------- + fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToMethodTypeParameter { #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(); } // Add second builtin bound to method type parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { - fn method(); + // --------------------------------------------------------------------------- + // ------------------------- + // --------------------------------------------------------------------------- + // ------------------------- + fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(); } // Add second lifetime bound to method lifetime parameter -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { - fn method<'a, 'b, 'c: 'a>(a: &'a u32, b: &'b u32, c: &'c u32); + // ----------- + // ----------------------------------------------------------------------------- + // -------------- + // + // ------------------------- + // ----------- + // ----------------------------------------------------------------------------- + // -------------- + // + // ------------------------- + fn method<'a, 'b, 'c: 'a >(a: &'a u32, b: &'b u32, c: &'c u32); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[rustc_clean( except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + cfg="cfail5", + )] + #[rustc_clean(cfg="cfail6")] fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32); } // Add associated type -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddAssociatedType { + //-------------------------- + //-------------------------- + // ------------- - #[rustc_clean(except="hir_owner", cfg="cfail2")] - #[rustc_clean(cfg="cfail3")] + //-------------------------- + //-------------------------- + //-------------------------- + //-------------------------- fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddAssociatedType { + #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail6")] type Associated; + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(); } // Add trait bound to associated type -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToAssociatedType { - type Associated; + // --------------------------------------------- + // ------------------------- + // --------------------------------------------- + // ------------------------- + type Associated ; fn method(); } @@ -507,12 +738,16 @@ // Apparently the type bound contributes to the predicates of the trait, but // does not change the associated item itself. -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToAssociatedType { #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] type Associated: ReferencedTrait0; fn method(); @@ -521,19 +756,27 @@ // Add lifetime bound to associated type -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToAssociatedType<'a> { - type Associated; + // --------------------------------------------- + // ------------------------- + // --------------------------------------------- + // ------------------------- + type Associated ; fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToAssociatedType<'a> { #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] type Associated: 'a; fn method(); @@ -542,19 +785,23 @@ // Add default to associated type -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddDefaultToAssociatedType { type Associated; fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddDefaultToAssociatedType { #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] type Associated = ReferenceType0; fn method(); @@ -563,14 +810,16 @@ // Add associated constant -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddAssociatedConstant { fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddAssociatedConstant { const Value: u32; @@ -580,269 +829,331 @@ // Add initializer to associated constant -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddInitializerToAssociatedConstant { const Value: u32; fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddInitializerToAssociatedConstant { #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] const Value: u32 = 1; #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(); } // Change type of associated constant -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitChangeTypeOfAssociatedConstant { + // ----------------------------------------------------- + // ------------------------- + // ----------------------------------------------------- + // ------------------------- const Value: u32; + // ------------------------- + // ------------------------- + // ------------------------- + // ------------------------- fn method(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitChangeTypeOfAssociatedConstant { #[rustc_clean(except="hir_owner,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,type_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] const Value: f64; #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(); } // Add super trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSuperTrait { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSuperTrait : ReferencedTrait0 { } // Add builtin bound (Send or Copy) -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddBuiltiBound { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddBuiltiBound : Send { } // Add 'static lifetime bound to trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddStaticLifetimeBound { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddStaticLifetimeBound : 'static { } // Add super trait as second bound -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddTraitAsSecondBound : ReferencedTrait0 { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddTraitAsSecondBoundFromBuiltin : Send { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } // Add builtin bound as second bound -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } // Add 'static bounds as second bound -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } // Add type parameter to trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddTypeParameterToTrait { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddTypeParameterToTrait { } // Add lifetime parameter to trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeParameterToTrait { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeParameterToTrait<'a> { } // Add trait bound to type parameter of trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToTypeParameterOfTrait { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToTypeParameterOfTrait { } // Add lifetime bound to type parameter of trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } // Add lifetime bound to lifetime parameter of trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } // Add builtin bound to type parameter of trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddBuiltinBoundToTypeParameterOfTrait { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToTypeParameterOfTrait { } // Add second type parameter to trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondTypeParameterToTrait { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondTypeParameterToTrait { } // Add second lifetime parameter to trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondLifetimeParameterToTrait<'a> { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } // Add second trait bound to type parameter of trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } // Add second lifetime bound to type parameter of trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } // Add second lifetime bound to lifetime parameter of trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { } // Add second builtin bound to type parameter of trait -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } @@ -853,105 +1164,125 @@ // Add trait bound to type parameter of trait in where clause -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToTypeParameterOfTraitWhere { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } // Add lifetime bound to type parameter of trait in where clause -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } // Add lifetime bound to lifetime parameter of trait in where clause -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { } // Add builtin bound to type parameter of trait in where clause -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } // Add second trait bound to type parameter of trait in where clause -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 + ReferencedTrait1 { } // Add second lifetime bound to type parameter of trait in where clause -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { } // Add second lifetime bound to lifetime parameter of trait in where clause -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { } // Add second builtin bound to type parameter of trait in where clause -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } // Change return type of method indirectly by modifying a use statement mod change_return_type_of_method_indirectly_use { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferenceType0 as ReturnType; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferenceType1 as ReturnType; #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] trait TraitChangeReturnType { #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method() -> ReturnType; } } @@ -960,9 +1291,9 @@ // Change type of method parameter indirectly by modifying a use statement mod change_method_parameter_type_indirectly_by_use { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferenceType0 as ArgType; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferenceType1 as ArgType; #[rustc_clean(cfg="cfail2")] @@ -978,9 +1309,9 @@ // Change trait bound of method type parameter indirectly by modifying a use statement mod change_method_parameter_type_bound_indirectly_by_use { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait0 as Bound; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait1 as Bound; #[rustc_clean(cfg="cfail2")] @@ -997,16 +1328,20 @@ // Change trait bound of method type parameter in where clause indirectly // by modifying a use statement mod change_method_parameter_type_bound_indirectly_by_use_where { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait0 as Bound; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait1 as Bound; #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] trait TraitChangeBoundOfMethodTypeParameterWhere { #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(a: T) where T: Bound; } } @@ -1015,9 +1350,9 @@ // Change trait bound of trait type parameter indirectly by modifying a use statement mod change_method_type_parameter_bound_indirectly { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait0 as Bound; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait1 as Bound; #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] @@ -1032,13 +1367,15 @@ // Change trait bound of trait type parameter in where clause indirectly // by modifying a use statement mod change_method_type_parameter_bound_indirectly_where { - #[cfg(cfail1)] + #[cfg(any(cfail1,cfail4))] use super::ReferencedTrait0 as Bound; - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1,cfail4)))] use super::ReferencedTrait1 as Bound; #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] trait TraitChangeTraitBoundWhere where T: Bound { fn method(a: T); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/trait_impls.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/trait_impls.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/trait_impls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/trait_impls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,9 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans - +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -19,29 +24,35 @@ // Change Method Name ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait ChangeMethodNameTrait { fn method_name(); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeMethodNameTrait for Foo { fn method_name() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub trait ChangeMethodNameTrait { #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail6")] fn method_name2(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeMethodNameTrait for Foo { #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail6")] fn method_name2() { } } @@ -53,17 +64,27 @@ fn method_name(); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeMethodBodyTrait for Foo { - fn method_name() { } + // ---------------------------------------------------------- + // ------------------------- + // ---------------------------------------------------------- + // ------------------------- + fn method_name() { + // + } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeMethodBodyTrait for Foo { #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method_name() { () } @@ -77,18 +98,28 @@ fn method_name(); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeMethodBodyTraitInlined for Foo { + // ------------------------------------------------------------------------ + // ------------------------- + // ------------------------------------------------------------------------ + // ------------------------- #[inline] - fn method_name() { } + fn method_name() { + // ----- + } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeMethodBodyTraitInlined for Foo { #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] #[inline] fn method_name() { panic!() @@ -97,30 +128,37 @@ // Change Method Selfness ------------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait ChangeMethodSelfnessTrait { fn method_name(); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeMethodSelfnessTrait for Foo { fn method_name() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] pub trait ChangeMethodSelfnessTrait { fn method_name(&self); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeMethodSelfnessTrait for Foo { #[rustc_clean( except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + cfg="cfail5", + )] + #[rustc_clean(cfg="cfail6")] fn method_name(&self) { () } @@ -128,130 +166,151 @@ // Change Method Selfness ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait RemoveMethodSelfnessTrait { fn method_name(&self); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl RemoveMethodSelfnessTrait for Foo { fn method_name(&self) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] pub trait RemoveMethodSelfnessTrait { fn method_name(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl RemoveMethodSelfnessTrait for Foo { #[rustc_clean( except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + cfg="cfail5", + )] + #[rustc_clean(cfg="cfail6")] fn method_name() {} } // Change Method Selfmutness ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait ChangeMethodSelfmutnessTrait { fn method_name(&self); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeMethodSelfmutnessTrait for Foo { - fn method_name(&self) { } + // ----------------------------------------------------------------------------------------- + // ------------------------- + // ----------------------------------------------------------------------------------------- + // ------------------------- + fn method_name(& self) {} } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] pub trait ChangeMethodSelfmutnessTrait { fn method_name(&mut self); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeMethodSelfmutnessTrait for Foo { #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method_name(&mut self) {} } // Change item kind ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait ChangeItemKindTrait { fn name(); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeItemKindTrait for Foo { fn name() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] pub trait ChangeItemKindTrait { type name; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeItemKindTrait for Foo { type name = (); } // Remove item ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait RemoveItemTrait { type TypeName; fn method_name(); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl RemoveItemTrait for Foo { type TypeName = (); fn method_name() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] pub trait RemoveItemTrait { type TypeName; } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl RemoveItemTrait for Foo { type TypeName = (); } // Add item ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait AddItemTrait { type TypeName; } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl AddItemTrait for Foo { type TypeName = (); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] pub trait AddItemTrait { type TypeName; fn method_name(); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl AddItemTrait for Foo { type TypeName = (); fn method_name() { } @@ -259,28 +318,34 @@ // Change has-value ----------------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait ChangeHasValueTrait { fn method_name(); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeHasValueTrait for Foo { fn method_name() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub trait ChangeHasValueTrait { #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method_name() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeHasValueTrait for Foo { fn method_name() { } } @@ -291,69 +356,91 @@ fn method_name(); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl AddDefaultTrait for Foo { - fn method_name() { } + // ------------------------------------------------------------------------------------------- + // ------------------------- + fn method_name() { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl AddDefaultTrait for Foo { #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item,optimized_mir", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] default fn method_name() { } } // Add arguments -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait AddArgumentTrait { fn method_name(&self); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl AddArgumentTrait for Foo { - fn method_name(&self) { } + // ----------------------------------------------------------------------------------------- + // ------------------------- + // ----------------------------------------------------------------------------------------- + // ------------------------- + fn method_name(&self ) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] pub trait AddArgumentTrait { fn method_name(&self, x: u32); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl AddArgumentTrait for Foo { #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method_name(&self, _x: u32) { } } // Change argument type -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub trait ChangeArgumentTypeTrait { fn method_name(&self, x: u32); } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeArgumentTypeTrait for Foo { - fn method_name(&self, _x: u32) { } + // ----------------------------------------------------------------------------------------- + // ------------------------- + // ----------------------------------------------------------------------------------------- + // ------------------------- + fn method_name(&self, _x: u32 ) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] pub trait ChangeArgumentTypeTrait { fn method_name(&self, x: char); } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeArgumentTypeTrait for Foo { #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method_name(&self, _x: char) { } } @@ -366,21 +453,28 @@ fn id(t: T) -> T; } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl AddTypeParameterToImpl for Bar { fn id(t: u32) -> u32 { t } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -impl AddTypeParameterToImpl for Bar { +#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] +impl AddTypeParameterToImpl for Bar { #[rustc_clean( except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", cfg="cfail2", )] #[rustc_clean(cfg="cfail3")] - fn id(t: T) -> T { t } + #[rustc_clean( + except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", + cfg="cfail5", + )] + #[rustc_clean(cfg="cfail6")] + fn id(t: TTT) -> TTT { t } } @@ -390,17 +484,21 @@ fn id(self) -> Self; } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl ChangeSelfTypeOfImpl for u32 { fn id(self) -> Self { self } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl ChangeSelfTypeOfImpl for u64 { #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn id(self) -> Self { self } } @@ -411,17 +509,21 @@ fn id(self) -> Self; } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl AddLifetimeBoundToImplParameter for T { fn id(self) -> Self { self } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl AddLifetimeBoundToImplParameter for T { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn id(self) -> Self { self } } @@ -432,17 +534,21 @@ fn id(self) -> Self; } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl AddTraitBoundToImplParameter for T { fn id(self) -> Self { self } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl AddTraitBoundToImplParameter for T { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn id(self) -> Self { self } } @@ -453,17 +559,26 @@ fn add_no_mangle_to_method(&self) { } } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl AddNoMangleToMethod for Foo { + // ------------------------- + // ------------------------- + // ------------------------- + // ------------------------- + // --------- fn add_no_mangle_to_method(&self) { } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl AddNoMangleToMethod for Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] #[no_mangle] fn add_no_mangle_to_method(&self) { } } @@ -474,17 +589,26 @@ fn make_method_inline(&self) -> u8 { 0 } } -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] impl MakeMethodInline for Foo { + // ------------------------- + // ------------------------- + // ------------------------- + // ------------------------- + // ------ fn make_method_inline(&self) -> u8 { 0 } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] impl MakeMethodInline for Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] #[inline] fn make_method_inline(&self) -> u8 { 0 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/type_defs.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/type_defs.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/type_defs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/type_defs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -12,7 +12,7 @@ // build-pass (FIXME(62277): could be check-pass?) // revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// compile-flags: -Z query-dep-graph #![allow(warnings)] #![feature(rustc_attrs)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/unary_and_binary_exprs.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/unary_and_binary_exprs.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/unary_and_binary_exprs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/unary_and_binary_exprs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -15,44 +21,50 @@ // Change constant operand of negation ----------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn const_negation() -> i32 { -10 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn const_negation() -> i32 { - -1 + -1 } // Change constant operand of bitwise not -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn const_bitwise_not() -> i32 { !100 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn const_bitwise_not() -> i32 { - !99 + !99 } // Change variable operand of negation ----------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn var_negation(x: i32, y: i32) -> i32 { -x } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn var_negation(x: i32, y: i32) -> i32 { -y } @@ -60,14 +72,16 @@ // Change variable operand of bitwise not -------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn var_bitwise_not(x: i32, y: i32) -> i32 { !x } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn var_bitwise_not(x: i32, y: i32) -> i32 { !y } @@ -75,14 +89,16 @@ // Change variable operand of deref -------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn var_deref(x: &i32, y: &i32) -> i32 { *x } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn var_deref(x: &i32, y: &i32) -> i32 { *y } @@ -90,14 +106,16 @@ // Change first constant operand of addition ----------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn first_const_add() -> i32 { 1 + 3 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn first_const_add() -> i32 { 2 + 3 } @@ -105,14 +123,16 @@ // Change second constant operand of addition ----------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn second_const_add() -> i32 { 1 + 2 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn second_const_add() -> i32 { 1 + 3 } @@ -120,14 +140,16 @@ // Change first variable operand of addition ----------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn first_var_add(a: i32, b: i32) -> i32 { a + 2 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn first_var_add(a: i32, b: i32) -> i32 { b + 2 } @@ -135,14 +157,16 @@ // Change second variable operand of addition ---------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn second_var_add(a: i32, b: i32) -> i32 { 1 + a } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn second_var_add(a: i32, b: i32) -> i32 { 1 + b } @@ -150,14 +174,16 @@ // Change operator from + to - ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn plus_to_minus(a: i32) -> i32 { 1 + a } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn plus_to_minus(a: i32) -> i32 { 1 - a } @@ -165,14 +191,16 @@ // Change operator from + to * ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn plus_to_mult(a: i32) -> i32 { 1 + a } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn plus_to_mult(a: i32) -> i32 { 1 * a } @@ -180,14 +208,16 @@ // Change operator from + to / ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn plus_to_div(a: i32) -> i32 { 1 + a } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn plus_to_div(a: i32) -> i32 { 1 / a } @@ -195,14 +225,16 @@ // Change operator from + to % ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn plus_to_mod(a: i32) -> i32 { 1 + a } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn plus_to_mod(a: i32) -> i32 { 1 % a } @@ -210,14 +242,16 @@ // Change operator from && to || ----------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn and_to_or(a: bool, b: bool) -> bool { a && b } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn and_to_or(a: bool, b: bool) -> bool { a || b } @@ -225,14 +259,16 @@ // Change operator from & to | ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 { 1 & a } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 { 1 | a } @@ -240,14 +276,16 @@ // Change operator from & to ^ ------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 { 1 & a } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 { 1 ^ a } @@ -255,14 +293,16 @@ // Change operator from & to << ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn bitwise_and_to_lshift(a: i32) -> i32 { - a & 1 + a & 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn bitwise_and_to_lshift(a: i32) -> i32 { a << 1 } @@ -270,14 +310,16 @@ // Change operator from & to >> ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn bitwise_and_to_rshift(a: i32) -> i32 { - a & 1 + a & 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn bitwise_and_to_rshift(a: i32) -> i32 { a >> 1 } @@ -285,14 +327,16 @@ // Change operator from == to != ----------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn eq_to_uneq(a: i32) -> bool { a == 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn eq_to_uneq(a: i32) -> bool { a != 1 } @@ -300,44 +344,50 @@ // Change operator from == to < ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn eq_to_lt(a: i32) -> bool { a == 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn eq_to_lt(a: i32) -> bool { - a < 1 + a < 1 } // Change operator from == to > ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn eq_to_gt(a: i32) -> bool { a == 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn eq_to_gt(a: i32) -> bool { - a > 1 + a > 1 } // Change operator from == to <= ----------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn eq_to_le(a: i32) -> bool { a == 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn eq_to_le(a: i32) -> bool { a <= 1 } @@ -345,14 +395,16 @@ // Change operator from == to >= ----------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn eq_to_ge(a: i32) -> bool { a == 1 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn eq_to_ge(a: i32) -> bool { a >= 1 } @@ -360,16 +412,18 @@ // Change type in cast expression ---------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn type_cast(a: u8) -> u64 { let b = a as i32; let c = b as u64; c } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir,typeck", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir,typeck", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn type_cast(a: u8) -> u64 { let b = a as u32; let c = b as u64; @@ -379,14 +433,16 @@ // Change value in cast expression --------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn value_cast(a: u32) -> i32 { 1 as i32 } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn value_cast(a: u32) -> i32 { 2 as i32 } @@ -394,7 +450,7 @@ // Change place in assignment -------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn place() -> i32 { let mut x = 10; let mut y = 11; @@ -402,9 +458,11 @@ x } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn place() -> i32 { let mut x = 10; let mut y = 11; @@ -415,16 +473,18 @@ // Change r-value in assignment ------------------------------------------------ -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn rvalue() -> i32 { let mut x = 10; x = 9; x } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn rvalue() -> i32 { let mut x = 10; x = 8; @@ -434,14 +494,16 @@ // Change index into slice ----------------------------------------------------- -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 { s[i] } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail5")] +#[rustc_clean(cfg="cfail6")] pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 { s[j] } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/while_let_loops.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/while_let_loops.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/while_let_loops.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/while_let_loops.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -15,7 +21,7 @@ // Change loop body -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_loop_body() { let mut _x = 0; while let Some(0u32) = None { @@ -24,9 +30,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn change_loop_body() { let mut _x = 0; while let Some(0u32) = None { @@ -38,7 +46,7 @@ // Change loop body -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_loop_condition() { let mut _x = 0; while let Some(0u32) = None { @@ -47,9 +55,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn change_loop_condition() { let mut _x = 0; while let Some(1u32) = None { @@ -61,17 +71,20 @@ // Add break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_break() { let mut _x = 0; while let Some(0u32) = None { _x = 1; + // --- } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_break() { let mut _x = 0; while let Some(0u32) = None { @@ -83,18 +96,20 @@ // Add loop label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label() { let mut _x = 0; - while let Some(0u32) = None { + while let Some(0u32) = None { _x = 1; break; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label() { let mut _x = 0; 'label: while let Some(0u32) = None { @@ -106,18 +121,20 @@ // Add loop label to break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label_to_break() { let mut _x = 0; 'label: while let Some(0u32) = None { _x = 1; - break; + break ; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; 'label: while let Some(0u32) = None { @@ -129,7 +146,7 @@ // Change break label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_break_label() { let mut _x = 0; 'outer: while let Some(0u32) = None { @@ -140,9 +157,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_break_label() { let mut _x = 0; 'outer: while let Some(0u32) = None { @@ -154,18 +173,20 @@ } // Add loop label to continue -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label_to_continue() { let mut _x = 0; 'label: while let Some(0u32) = None { _x = 1; - continue; + continue ; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_continue() { let mut _x = 0; 'label: while let Some(0u32) = None { @@ -177,7 +198,7 @@ // Change continue label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_continue_label() { let mut _x = 0; 'outer: while let Some(0u32) = None { @@ -188,9 +209,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_continue_label() { let mut _x = 0; 'outer: while let Some(0u32) = None { @@ -204,7 +227,7 @@ // Change continue to break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_continue_to_break() { let mut _x = 0; while let Some(0u32) = None { @@ -213,13 +236,15 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn change_continue_to_break() { let mut _x = 0; while let Some(0u32) = None { _x = 1; - break; + break ; } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/while_loops.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/while_loops.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/hashes/while_loops.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/hashes/while_loops.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,14 @@ // rev3 and make sure that the hash has not changed. // build-pass (FIXME(62277): could be check-pass?) -// revisions: cfail1 cfail2 cfail3 -// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// compile-flags: -Z query-dep-graph +// [cfail1]compile-flags: -Zincremental-ignore-spans +// [cfail2]compile-flags: -Zincremental-ignore-spans +// [cfail3]compile-flags: -Zincremental-ignore-spans +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans #![allow(warnings)] #![feature(rustc_attrs)] @@ -15,7 +21,7 @@ // Change loop body -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_loop_body() { let mut _x = 0; while true { @@ -24,9 +30,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_loop_body() { let mut _x = 0; while true { @@ -38,18 +46,20 @@ // Change loop body -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_loop_condition() { let mut _x = 0; - while true { + while true { _x = 1; break; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_loop_condition() { let mut _x = 0; while false { @@ -61,17 +71,20 @@ // Add break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_break() { let mut _x = 0; while true { _x = 1; + // --- } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")] +#[rustc_clean(cfg="cfail6")] pub fn add_break() { let mut _x = 0; while true { @@ -83,18 +96,20 @@ // Add loop label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label() { let mut _x = 0; - while true { + while true { _x = 1; break; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label() { let mut _x = 0; 'label: while true { @@ -106,18 +121,20 @@ // Add loop label to break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label_to_break() { let mut _x = 0; 'label: while true { _x = 1; - break; + break ; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; 'label: while true { @@ -129,7 +146,7 @@ // Change break label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_break_label() { let mut _x = 0; 'outer: while true { @@ -140,9 +157,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] +#[rustc_clean(cfg="cfail6")] pub fn change_break_label() { let mut _x = 0; 'outer: while true { @@ -156,18 +175,20 @@ // Add loop label to continue -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn add_loop_label_to_continue() { let mut _x = 0; 'label: while true { _x = 1; - continue; + continue ; } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_continue() { let mut _x = 0; 'label: while true { @@ -179,7 +200,7 @@ // Change continue label -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_continue_label() { let mut _x = 0; 'outer: while true { @@ -190,9 +211,11 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_continue_label() { let mut _x = 0; 'outer: while true { @@ -206,7 +229,7 @@ // Change continue to break -#[cfg(cfail1)] +#[cfg(any(cfail1,cfail4))] pub fn change_continue_to_break() { let mut _x = 0; while true { @@ -215,13 +238,15 @@ } } -#[cfg(not(cfail1))] +#[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] +#[rustc_clean(cfg="cfail6")] pub fn change_continue_to_break() { let mut _x = 0; while true { _x = 1; - break; + break ; } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/mir-opt.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/mir-opt.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/mir-opt.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/mir-opt.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +// MIR optimizations can create expansions after the TyCtxt has been created. +// This test verifies that those expansions can be decoded correctly. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph -Z mir-opt-level=3 + +fn main() { + if std::env::var("a").is_ok() { + println!("b"); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/spans_significant_w_debuginfo.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/spans_significant_w_debuginfo.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/spans_significant_w_debuginfo.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/spans_significant_w_debuginfo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,16 +1,21 @@ // This test makes sure that just changing a definition's location in the // source file also changes its incr. comp. hash, if debuginfo is enabled. -// revisions:rpass1 rpass2 +// revisions:rpass1 rpass2 rpass3 rpass4 // ignore-asmjs wasm2js does not support source maps yet // compile-flags: -g -Z query-dep-graph +// [rpass3]compile-flags: -Zincremental-relative-spans +// [rpass4]compile-flags: -Zincremental-relative-spans #![feature(rustc_attrs)] +#![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass2")] +#![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass4")] -#[cfg(rpass1)] +#[cfg(any(rpass1, rpass3))] pub fn main() {} -#[cfg(rpass2)] -#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")] +#[cfg(any(rpass2, rpass4))] +#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")] +#[rustc_clean(cfg = "rpass4")] pub fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/spans_significant_w_panic.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/spans_significant_w_panic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/spans_significant_w_panic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/spans_significant_w_panic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,19 +1,29 @@ // This test makes sure that just changing a definition's location in the // source file also changes its incr. comp. hash, if debuginfo is enabled. -// revisions:rpass1 rpass2 +// revisions:rpass1 rpass2 rpass3 rpass4 +// [rpass3]compile-flags: -Zincremental-relative-spans +// [rpass4]compile-flags: -Zincremental-relative-spans // compile-flags: -C overflow-checks=on -Z query-dep-graph #![feature(rustc_attrs)] +#![feature(bench_black_box)] +#![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass2")] +#![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass4")] -#[cfg(rpass1)] +#[cfg(any(rpass1, rpass3))] pub fn main() { - let _ = 0u8 + 1; + if std::hint::black_box(false) { + panic!() + } } -#[cfg(rpass2)] -#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")] +#[cfg(any(rpass2, rpass4))] +#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")] +#[rustc_clean(cfg = "rpass4")] pub fn main() { - let _ = 0u8 + 1; + if std::hint::black_box(false) { + panic!() + } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/string_constant.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/string_constant.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/string_constant.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/string_constant.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,7 @@ -// revisions: cfail1 cfail2 +// revisions: cfail1 cfail2 cfail3 cfail4 // compile-flags: -Z query-dep-graph +// [cfail3]compile-flags: -Zincremental-relative-spans +// [cfail4]compile-flags: -Zincremental-relative-spans // build-pass (FIXME(62277): could be check-pass?) #![allow(warnings)] @@ -10,15 +12,15 @@ // Therefore, the compiler deduces (correctly) that typeck is not // needed even for callers of `x`. - pub mod x { - #[cfg(cfail1)] + #[cfg(any(cfail1, cfail3))] pub fn x() { println!("{}", "1"); } - #[cfg(cfail2)] - #[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg="cfail2")] + #[cfg(any(cfail2, cfail4))] + #[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg = "cfail2")] + #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail4")] pub fn x() { println!("{}", "2"); } @@ -27,7 +29,8 @@ pub mod y { use x; - #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg = "cfail2")] + #[rustc_clean(cfg = "cfail4")] pub fn y() { x::x(); } @@ -36,7 +39,8 @@ pub mod z { use y; - #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg = "cfail2")] + #[rustc_clean(cfg = "cfail4")] pub fn z() { y::y(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs rustc-1.57.0+dfsg1+llvm/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,36 +3,61 @@ // ends up with any spans in its LLVM bitecode, so LLVM is able to skip // re-building any modules which import 'inlined_fn' -// revisions: cfail1 cfail2 cfail3 +// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 +// [cfail4]compile-flags: -Zincremental-relative-spans +// [cfail5]compile-flags: -Zincremental-relative-spans +// [cfail6]compile-flags: -Zincremental-relative-spans // compile-flags: -Z query-dep-graph -O // build-pass (FIXME(62277): could be check-pass?) #![feature(rustc_attrs)] -#![crate_type="rlib"] - -#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo", - cfg="cfail2", - kind="no")] -#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo", - cfg="cfail3", - kind="post-lto")] - -#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar", - cfg="cfail2", - kind="post-lto")] -#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar", - cfg="cfail3", - kind="post-lto")] +#![crate_type = "rlib"] +#![rustc_expected_cgu_reuse(module = "cgu_keeps_identical_fn-foo", cfg = "cfail2", kind = "no")] +#![rustc_expected_cgu_reuse( + module = "cgu_keeps_identical_fn-foo", + cfg = "cfail3", + kind = "post-lto" +)] +#![rustc_expected_cgu_reuse( + module = "cgu_keeps_identical_fn-foo", + cfg = "cfail5", + kind = "post-lto" +)] +#![rustc_expected_cgu_reuse( + module = "cgu_keeps_identical_fn-foo", + cfg = "cfail6", + kind = "post-lto" +)] +#![rustc_expected_cgu_reuse( + module = "cgu_keeps_identical_fn-bar", + cfg = "cfail2", + kind = "post-lto" +)] +#![rustc_expected_cgu_reuse( + module = "cgu_keeps_identical_fn-bar", + cfg = "cfail3", + kind = "post-lto" +)] +#![rustc_expected_cgu_reuse( + module = "cgu_keeps_identical_fn-bar", + cfg = "cfail5", + kind = "post-lto" +)] +#![rustc_expected_cgu_reuse( + module = "cgu_keeps_identical_fn-bar", + cfg = "cfail6", + kind = "post-lto" +)] mod foo { // Trivial functions like this one are imported very reliably by ThinLTO. - #[cfg(cfail1)] + #[cfg(any(cfail1, cfail4))] pub fn inlined_fn() -> u32 { 1234 } - #[cfg(not(cfail1))] + #[cfg(not(any(cfail1, cfail4)))] pub fn inlined_fn() -> u32 { 1234 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir 2021-11-29 19:27:11.000000000 +0000 @@ -3,64 +3,78 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/box_expr.rs:6:11: 6:11 let _1: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:9: 7:10 - let mut _2: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 - let _3: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11 + let mut _2: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _3: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _4: *mut u8; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _5: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let _6: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11 scope 1 { debug x => _1; // in scope 1 at $DIR/box_expr.rs:7:9: 7:10 } + scope 2 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 - StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + _2 = SizeOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25 + _3 = AlignOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:7:13: 7:25 // mir::Constant - // + span: $DIR/box_expr.rs:7:17: 7:23 - // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } + // + span: $DIR/box_expr.rs:7:13: 7:25 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - drop(_2) -> bb2; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + StorageLive(_5); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + _5 = ShallowInitBox(move _4, S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + // mir::Constant + // + span: $DIR/box_expr.rs:7:17: 7:23 + // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } } bb2: { - StorageDead(_2); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 - StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 - StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = std::mem::drop::>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _1 = move _5; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + drop(_5) -> bb3; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + } + + bb3: { + StorageDead(_5); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + StorageLive(_6); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + StorageLive(_7); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 + _7 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 + _6 = std::mem::drop::>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } } - bb3: { - StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 + bb4: { + StorageDead(_7); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 + StorageDead(_6); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 - drop(_1) -> bb4; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_1) -> bb5; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb4: { + bb5: { StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2 return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2 } - bb5 (cleanup): { - drop(_4) -> bb6; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - } - bb6 (cleanup): { - drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_7) -> bb7; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 } bb7 (cleanup): { - drop(_2) -> bb8; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + drop(_1) -> bb9; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } bb8 (cleanup): { + drop(_5) -> bb9; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + } + + bb9 (cleanup): { resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // MIR for `BAR::promoted[0]` after SimplifyCfg-elaborate-drops promoted[0] in BAR: &[&i32; 1] = { - let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 let mut _3: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 @@ -16,8 +16,8 @@ // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) } _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff 2021-11-29 19:27:11.000000000 +0000 @@ -3,21 +3,21 @@ static mut BAR: *const &i32 = { let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:17: 9:28 - let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 let _5: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 -+ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 ++ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 bb0: { - StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 - StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 - StorageLive(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 - _5 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 -+ _6 = const BAR::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 ++ _6 = const BAR::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 // ty::Const - // + ty: &i32 - // + val: Value(Scalar(alloc1)) @@ -28,11 +28,11 @@ - // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) } - _4 = &(*_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 -- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 -+ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35 +- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 ++ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:44 + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } -+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 ++ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // MIR for `FOO::promoted[0]` after SimplifyCfg-elaborate-drops promoted[0] in FOO: &[&i32; 1] = { - let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 let mut _3: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 @@ -16,8 +16,8 @@ // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43 _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff 2021-11-29 19:27:11.000000000 +0000 @@ -3,23 +3,23 @@ static mut FOO: *const &i32 = { let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:17: 13:28 - let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 let _5: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 -+ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 ++ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 scope 1 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 - StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 - StorageLive(_5); // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 - _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 -+ _6 = const FOO::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 ++ _6 = const FOO::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 // ty::Const - // + ty: *const i32 - // + val: Value(Scalar(alloc3)) @@ -30,11 +30,11 @@ - // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } - _4 = &(*_5); // scope 1 at $DIR/const-promotion-extern-static.rs:13:41: 13:43 - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 -- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 -+ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46 +- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 ++ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:55 + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } -+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 ++ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff 2021-11-29 19:27:11.000000000 +0000 @@ -6,34 +6,51 @@ let _1: i32; // in scope 0 at $DIR/boxes.rs:12:9: 12:10 let mut _2: i32; // in scope 0 at $DIR/boxes.rs:12:13: 12:22 let mut _3: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _4: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _5: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _6: *mut u8; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 scope 1 { debug x => _1; // in scope 1 at $DIR/boxes.rs:12:9: 12:10 } + scope 2 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/boxes.rs:12:9: 12:10 StorageLive(_2); // scope 0 at $DIR/boxes.rs:12:13: 12:22 StorageLive(_3); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - StorageLive(_4); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - _4 = Box(i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - (*_4) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21 - _3 = move _4; // scope 0 at $DIR/boxes.rs:12:14: 12:22 - StorageDead(_4); // scope 0 at $DIR/boxes.rs:12:21: 12:22 +- _4 = SizeOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22 +- _5 = AlignOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22 +- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _4 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _5 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 + // mir::Constant + // + span: $DIR/boxes.rs:12:14: 12:22 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_7); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + _7 = ShallowInitBox(move _6, i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + (*_7) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21 + _3 = move _7; // scope 0 at $DIR/boxes.rs:12:14: 12:22 + StorageDead(_7); // scope 0 at $DIR/boxes.rs:12:21: 12:22 _2 = (*_3); // scope 0 at $DIR/boxes.rs:12:13: 12:22 _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/boxes.rs:12:13: 12:26 StorageDead(_2); // scope 0 at $DIR/boxes.rs:12:25: 12:26 - drop(_3) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/boxes.rs:12:26: 12:27 + drop(_3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/boxes.rs:12:26: 12:27 } - bb1: { + bb2: { StorageDead(_3); // scope 0 at $DIR/boxes.rs:12:26: 12:27 nop; // scope 0 at $DIR/boxes.rs:11:11: 13:2 StorageDead(_1); // scope 0 at $DIR/boxes.rs:13:1: 13:2 return; // scope 0 at $DIR/boxes.rs:13:2: 13:2 } - bb2 (cleanup): { + bb3 (cleanup): { resume; // scope 0 at $DIR/boxes.rs:11:1: 13:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff 2021-11-29 19:27:11.000000000 +0000 @@ -12,6 +12,7 @@ let mut _7: usize; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 let mut _8: bool; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 let mut _9: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let mut _10: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 bb0: { StorageLive(_1); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 @@ -27,14 +28,16 @@ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _10 = _3; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 StorageDead(_3); // scope 0 at $DIR/slice_len.rs:5:18: 5:19 StorageLive(_6); // scope 0 at $DIR/slice_len.rs:5:31: 5:32 _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32 -- _7 = Len((*_2)); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageDead(_10); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 -+ _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff 2021-11-29 19:27:11.000000000 +0000 @@ -12,6 +12,7 @@ let mut _7: usize; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 let mut _8: bool; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 let mut _9: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let mut _10: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 bb0: { StorageLive(_1); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 @@ -27,14 +28,16 @@ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _10 = _3; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 StorageDead(_3); // scope 0 at $DIR/slice_len.rs:5:18: 5:19 StorageLive(_6); // scope 0 at $DIR/slice_len.rs:5:31: 5:32 _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32 -- _7 = Len((*_2)); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageDead(_10); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 -+ _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,12 @@ graph [fontname="Courier, monospace"]; node [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"]; - bcb2__Cov_0_3 [shape="none", label=<
bcb2
Expression(bcb0 - bcb1) at 13:10-13:10
13:10-13:10: @4[0]: Coverage::Expression(4294967295) = 1 - 2 for $DIR/coverage_graphviz.rs:13:10 - 13:11
bb4: Goto
>]; - bcb1__Cov_0_3 [shape="none", label=<
bcb1
Counter(bcb1) at 12:13-12:18
12:13-12:18: @3[0]: Coverage::Expression(4294967294) = 2 + 0 for $DIR/coverage_graphviz.rs:15:1 - 15:2
Expression(bcb1 + 0) at 15:2-15:2
15:2-15:2: @3.Return: return
bb3: Return
>]; - bcb0__Cov_0_3 [shape="none", label=<
bcb0
Counter(bcb0) at 9:1-11:17
11:12-11:17: @1.Call: _2 = bar() -> [return: bb2, unwind: bb5]
bb0: FalseUnwind
bb1: Call
bb2: SwitchInt
>]; - bcb2__Cov_0_3 -> bcb0__Cov_0_3 [label=<>]; - bcb0__Cov_0_3 -> bcb2__Cov_0_3 [label=]; - bcb0__Cov_0_3 -> bcb1__Cov_0_3 [label=]; + bcb3__Cov_0_3 [shape="none", label=<
bcb3
Counter(bcb3) at 13:10-13:10
13:10-13:10: @5[0]: Coverage::Counter(2) for $DIR/coverage_graphviz.rs:13:10 - 13:11
bb5: Goto
>]; + bcb2__Cov_0_3 [shape="none", label=<
bcb2
Expression(bcb1:(bcb0 + bcb3) - bcb3) at 12:13-12:18
12:13-12:18: @4[0]: Coverage::Expression(4294967293) = 4294967294 + 0 for $DIR/coverage_graphviz.rs:15:1 - 15:2
Expression(bcb2:(bcb1:(bcb0 + bcb3) - bcb3) + 0) at 15:2-15:2
15:2-15:2: @4.Return: return
bb4: Return
>]; + bcb1__Cov_0_3 [shape="none", label=<
bcb1
Expression(bcb0 + bcb3) at 10:5-11:17
11:12-11:17: @2.Call: _2 = bar() -> [return: bb3, unwind: bb6]
bb1: FalseUnwind
bb2: Call
bb3: SwitchInt
>]; + bcb0__Cov_0_3 [shape="none", label=<
bcb0
Counter(bcb0) at 9:1-9:11
bb0: Goto
>]; + bcb3__Cov_0_3 -> bcb1__Cov_0_3 [label=<>]; + bcb1__Cov_0_3 -> bcb3__Cov_0_3 [label=]; + bcb1__Cov_0_3 -> bcb2__Cov_0_3 [label=]; + bcb0__Cov_0_3 -> bcb1__Cov_0_3 [label=<>]; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ debug s => _1; // in scope 0 at $DIR/deduplicate_blocks.rs:2:36: 2:37 let mut _0: bool; // return place in scope 0 at $DIR/deduplicate_blocks.rs:2:48: 2:52 let mut _2: &[u8]; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 - let mut _3: &str; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:12 + let mut _3: &str; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 let mut _4: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 let mut _5: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 let mut _6: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 @@ -19,8 +19,8 @@ bb0: { StorageLive(_2); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 - StorageLive(_3); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:12 - _3 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:12 + StorageLive(_3); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + _3 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 StorageLive(_8); // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23 _8 = _3; // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23 - _2 = transmute::<&str, &[u8]>(move _8) -> bb14; // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff 2021-11-29 19:27:11.000000000 +0000 @@ -7,9 +7,9 @@ debug upper => _3; // in scope 0 at $DIR/funky_arms.rs:11:69: 11:74 let mut _0: std::result::Result<(), std::fmt::Error>; // return place in scope 0 at $DIR/funky_arms.rs:11:85: 11:91 let _4: bool; // in scope 0 at $DIR/funky_arms.rs:15:9: 15:19 - let mut _5: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:15:22: 15:25 + let mut _5: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:15:22: 15:37 let mut _7: std::option::Option; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:45 - let mut _8: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:33 + let mut _8: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:45 let mut _9: isize; // in scope 0 at $DIR/funky_arms.rs:24:12: 24:27 let mut _11: &mut std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:26:43: 26:46 let mut _12: &T; // in scope 0 at $DIR/funky_arms.rs:26:48: 26:51 @@ -36,8 +36,8 @@ bb0: { StorageLive(_4); // scope 0 at $DIR/funky_arms.rs:15:9: 15:19 - StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:15:22: 15:25 - _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:15:22: 15:25 + StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 + _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 _4 = Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 // mir::Constant // + span: $DIR/funky_arms.rs:15:26: 15:35 @@ -62,8 +62,8 @@ bb4: { StorageLive(_7); // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 - StorageLive(_8); // scope 2 at $DIR/funky_arms.rs:24:30: 24:33 - _8 = &(*_1); // scope 2 at $DIR/funky_arms.rs:24:30: 24:33 + StorageLive(_8); // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 + _8 = &(*_1); // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 _7 = Formatter::precision(move _8) -> bb5; // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 // mir::Constant // + span: $DIR/funky_arms.rs:24:34: 24:43 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_diverging.h.Inline.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_diverging.h.Inline.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_diverging.h.Inline.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_diverging.h.Inline.diff 2021-11-29 19:27:11.000000000 +0000 @@ -47,7 +47,7 @@ + _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_9); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + _9 = const (); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ goto -> bb1; // scope 4 at $DIR/inline-diverging.rs:22:5: 22:22 ++ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22 } bb1: { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff 2021-11-29 19:27:11.000000000 +0000 @@ -4,23 +4,37 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - let mut _2: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 -+ let mut _4: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ let mut _7: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11 } -+ scope 2 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + scope 2 { + } ++ scope 3 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = Vec::::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageLive(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + // mir::Constant + // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 +- (*_5) = Vec::::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ ((*_7).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 + // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -30,32 +44,32 @@ - // + literal: Const { ty: fn() -> std::vec::Vec {std::vec::Vec::::new}, val: Value(Scalar()) } - } - -- bb1: { +- bb2: { + // + span: $DIR/inline-into-box-place.rs:8:33: 8:43 + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageDead(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 - _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 -- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 +- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } -- bb2: { -+ bb1: { +- bb3: { ++ bb2: { StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } -- bb3 (cleanup): { -+ bb2 (cleanup): { +- bb4 (cleanup): { ++ bb3 (cleanup): { resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 - } - -- bb4 (cleanup): { -- _3 = alloc::alloc::box_free::, std::alloc::Global>(move (_2.0: std::ptr::Unique>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- bb5 (cleanup): { +- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value(Scalar()) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff 2021-11-29 19:27:11.000000000 +0000 @@ -4,23 +4,37 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - let mut _2: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 -+ let mut _4: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ let mut _7: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11 } -+ scope 2 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + scope 2 { + } ++ scope 3 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = Vec::::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageLive(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + // mir::Constant + // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 +- (*_5) = Vec::::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ ((*_7).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 + // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -30,32 +44,32 @@ - // + literal: Const { ty: fn() -> std::vec::Vec {std::vec::Vec::::new}, val: Value(Scalar()) } - } - -- bb1: { +- bb2: { + // + span: $DIR/inline-into-box-place.rs:8:33: 8:43 + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageDead(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 - _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 -- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 +- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } -- bb2: { -+ bb1: { +- bb3: { ++ bb2: { StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } -- bb3 (cleanup): { -+ bb2 (cleanup): { +- bb4 (cleanup): { ++ bb3 (cleanup): { resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 - } - -- bb4 (cleanup): { -- _3 = alloc::alloc::box_free::, std::alloc::Global>(move (_2.0: std::ptr::Unique>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- bb5 (cleanup): { +- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value(Scalar()) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_shims.clone.Inline.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_shims.clone.Inline.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_shims.clone.Inline.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_shims.clone.Inline.diff 2021-11-29 19:27:11.000000000 +0000 @@ -4,13 +4,13 @@ fn clone(_1: fn(A, B)) -> fn(A, B) { debug f => _1; // in scope 0 at $DIR/inline-shims.rs:5:20: 5:21 let mut _0: fn(A, B); // return place in scope 0 at $DIR/inline-shims.rs:5:36: 5:44 - let mut _2: &fn(A, B); // in scope 0 at $DIR/inline-shims.rs:6:5: 6:6 + let mut _2: &fn(A, B); // in scope 0 at $DIR/inline-shims.rs:6:5: 6:14 + scope 1 (inlined ::clone - shim(fn(A, B))) { // at $DIR/inline-shims.rs:6:5: 6:14 + } bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-shims.rs:6:5: 6:6 - _2 = &_1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:6 + StorageLive(_2); // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 + _2 = &_1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 - _0 = ::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 - // mir::Constant - // + span: $DIR/inline-shims.rs:6:7: 6:12 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -3,11 +3,11 @@ fn test(_1: &dyn X) -> u32 { debug x => _1; // in scope 0 at $DIR/inline-trait-method.rs:8:9: 8:10 let mut _0: u32; // return place in scope 0 at $DIR/inline-trait-method.rs:8:23: 8:26 - let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method.rs:9:5: 9:6 + let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:6 - _2 = &(*_1); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:6 + StorageLive(_2); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 + _2 = &(*_1); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 _0 = ::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 // mir::Constant // + span: $DIR/inline-trait-method.rs:9:7: 9:8 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ let mut _0: &mut [T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:2:29: 2:37 let mut _2: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 let mut _3: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 - let mut _4: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 + let mut _4: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 debug self => _4; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 let mut _5: &mut [T]; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 @@ -14,8 +14,8 @@ bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 - StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 - _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 + StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageLive(_5); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 _5 = &mut (*_4); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 _3 = &mut (*_5); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ let mut _0: &mut T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:7:32: 7:38 let mut _2: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 let mut _3: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 - let mut _4: &mut std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 + let mut _4: &mut std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 scope 1 (inlined as AsMut>::as_mut) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 debug self => _4; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 let mut _5: &mut T; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 @@ -15,8 +15,8 @@ bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 - StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 - _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 + StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageLive(_5); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageLive(_6); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 _6 = &mut (*(*_4)); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -4,15 +4,15 @@ debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:12:13: 12:14 let mut _0: &[T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:12:25: 12:29 let _2: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 - let mut _3: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:6 + let mut _3: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 debug self => _3; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 } bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 - StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:6 - _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:6 + StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 + _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 _2 = _3; // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:14: 13:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -4,15 +4,15 @@ debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:13: 17:14 let mut _0: &T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:28: 17:30 let _2: &T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 - let mut _3: &std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:6 + let mut _3: &std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 scope 1 (inlined as AsRef>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 debug self => _3; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 } bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 - StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:6 - _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:6 + StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 + _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 _2 = &(*(*_3)); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:14: 18:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff 2021-11-29 19:27:11.000000000 +0000 @@ -8,38 +8,43 @@ let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10 bb0: { -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 - falseUnwind -> [real: bb1, cleanup: bb5]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 10:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 + goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } bb1: { ++ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:11:5 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 + falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 + } + + bb2: { StorageLive(_2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 - _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 + _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 // mir::Constant // + span: /the/src/instrument_coverage.rs:12:12: 12:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar()) } } - bb2: { - switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 + bb3: { + switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 } - bb3: { -+ Coverage::Expression(4294967294) = 2 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 -+ Coverage::Counter(2) for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 + bb4: { ++ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 ++ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 _0 = const (); // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:14:9: 14:10 return; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 } - bb4: { -+ Coverage::Expression(4294967295) = 1 - 2 for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 + bb5: { ++ Coverage::Counter(2) for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:14:10: 14:10 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:14:9: 14:10 - goto -> bb0; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 + goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } - bb5 (cleanup): { + bb6 (cleanup): { resume; // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir 2021-11-29 19:27:11.000000000 +0000 @@ -3,106 +3,120 @@ fn test() -> Option> { let mut _0: std::option::Option>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 let mut _1: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _2: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - let mut _4: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _6: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _7: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _8: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _2: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _3: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _4: *mut u8; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _5: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _6: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _7: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + let mut _8: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _9: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _10: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _11: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _12: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 scope 1 { - debug residual => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20 - scope 2 { + } + scope 2 { + debug residual => _9; // in scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + scope 3 { } } - scope 3 { - debug val => _9; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20 - scope 4 { + scope 4 { + debug val => _12; // in scope 4 at $DIR/issue-62289.rs:9:15: 9:20 + scope 5 { } } bb0: { StorageLive(_1); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - StorageLive(_2); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - _2 = Box(u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _2 = SizeOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 + _3 = AlignOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 // mir::Constant - // + span: $DIR/issue-62289.rs:9:15: 9:20 - // + literal: Const { ty: fn(std::option::Option) -> std::ops::ControlFlow< as std::ops::Try>::Residual, as std::ops::Try>::Output> { as std::ops::Try>::branch}, val: Value(Scalar()) } + // + span: $DIR/issue-62289.rs:9:10: 9:21 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_4); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _5 = discriminant(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_5); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_7); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _7 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _6 = as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + // mir::Constant + // + span: $DIR/issue-62289.rs:9:15: 9:20 + // + literal: Const { ty: fn(std::option::Option) -> std::ops::ControlFlow< as std::ops::Try>::Residual, as std::ops::Try>::Output> { as std::ops::Try>::branch}, val: Value(Scalar()) } } bb2: { - StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - (*_2) = _9; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 - StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_7); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = discriminant(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb3: { - unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_12); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + (*_5) = _12; // scope 5 at $DIR/issue-62289.rs:9:15: 9:20 + StorageDead(_12); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _1 = move _5; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb4: { - StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _6 = ((_3 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as FromResidual>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 - // mir::Constant - // + span: $DIR/issue-62289.rs:9:19: 9:20 - // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } + unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb5: { - StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _9 = ((_6 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + StorageLive(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + _11 = _9; // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = > as FromResidual>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:9:15: 9:20 + // mir::Constant + // + span: $DIR/issue-62289.rs:9:19: 9:20 + // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } } bb6: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + drop(_5) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb8: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb9: { - return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb10 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + bb10: { + return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb11 (cleanup): { - drop(_2) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb12 (cleanup): { + drop(_5) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + } + + bb13 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff 2021-11-29 19:27:11.000000000 +0000 @@ -22,6 +22,7 @@ let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 let mut _22: !; // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL + let mut _23: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 scope 1 { debug v => _2; // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10 let _13: &T; // in scope 1 at $DIR/issue_76432.rs:9:10: 9:16 @@ -51,16 +52,17 @@ StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 _4 = &_5; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 _3 = _4; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_23); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _23 = _3; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:7:29: 7:30 StorageLive(_9); // scope 1 at $DIR/issue_76432.rs:8:5: 11:6 - _10 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _10 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + StorageDead(_23); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 _11 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -- _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -- switchInt(move _12) -> [false: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -+ nop; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -+ switchInt(move _10) -> [3_usize: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _12 = const true; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + goto -> bb2; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 } bb1: { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,66 @@ +- // MIR for `array_bound` before InstCombine ++ // MIR for `array_bound` after InstCombine + + fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _7 = _2; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _11 = _7; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 +- _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + } + + bb1: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + } + + bb2: { + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb3: { + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,79 @@ +- // MIR for `array_bound_mut` before InstCombine ++ // MIR for `array_bound_mut` after InstCombine + + fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _14 = _7; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 +- _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + } + + bb1: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + } + + bb2: { + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb3: { + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ _12 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + } + + bb4: { + (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb5: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,81 @@ +- // MIR for `array_bound_mut` before NormalizeArrayLen ++ // MIR for `array_bound_mut` after NormalizeArrayLen + + fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _14 = _7; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 +- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + } + + bb1: { + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + } + + bb2: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + } + + bb3: { + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb6; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb4: { + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb5; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + } + + bb5: { + (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb6; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb6: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,96 @@ +- // MIR for `array_bound_mut` before SimplifyLocals ++ // MIR for `array_bound_mut` after SimplifyLocals + + fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ let _9: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ let mut _10: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ let mut _11: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- _14 = _7; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 + _5 = const N; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + } + + bb1: { +- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + } + + bb2: { +- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 ++ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb3: { +- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _12 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- _13 = Lt(const 0_usize, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ StorageLive(_9); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ _9 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ _10 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ _11 = Lt(const 0_usize, _10); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + } + + bb4: { +- (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 +- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 ++ (*_2)[_9] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 ++ StorageDead(_9); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb5: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,68 @@ +- // MIR for `array_bound` before NormalizeArrayLen ++ // MIR for `array_bound` after NormalizeArrayLen + + fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _11 = _7; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 +- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + } + + bb1: { + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + } + + bb2: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + } + + bb3: { + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb4: { + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb5: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,73 @@ +- // MIR for `array_bound` before SimplifyLocals ++ // MIR for `array_bound` after SimplifyLocals + + fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _7 = _2; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _11 = _7; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 + _5 = const N; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + } + + bb1: { +- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + } + + bb2: { +- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 ++ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb3: { + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +- // MIR for `array_len_by_value` before InstCombine ++ // MIR for `array_len_by_value` after InstCombine + + fn array_len_by_value(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _4 = _3; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 +- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +- // MIR for `array_len_by_value` before NormalizeArrayLen ++ // MIR for `array_len_by_value` after NormalizeArrayLen + + fn array_len_by_value(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 +- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + } + + bb1: { + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,25 @@ +- // MIR for `array_len_by_value` before SimplifyLocals ++ // MIR for `array_len_by_value` after SimplifyLocals + + fn array_len_by_value(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 +- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- _4 = _3; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 + _0 = const N; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,27 @@ +- // MIR for `array_len` before InstCombine ++ // MIR for `array_len` after InstCombine + + fn array_len(_1: &[u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _3 = _1; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _4 = _3; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 +- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +- // MIR for `array_len` before NormalizeArrayLen ++ // MIR for `array_len` after NormalizeArrayLen + + fn array_len(_1: &[u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 +- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + } + + bb1: { + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,25 @@ +- // MIR for `array_len` before SimplifyLocals ++ // MIR for `array_len` after SimplifyLocals + + fn array_len(_1: &[u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 +- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _3 = _1; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _4 = _3; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 + _0 = const N; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.rs rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.rs --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_array_len.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,47 @@ +// compile-flags: -Z mir-opt-level=4 + +// EMIT_MIR lower_array_len.array_bound.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_bound.SimplifyLocals.diff +// EMIT_MIR lower_array_len.array_bound.InstCombine.diff +pub fn array_bound(index: usize, slice: &[u8; N]) -> u8 { + if index < slice.len() { + slice[index] + } else { + 42 + } +} + +// EMIT_MIR lower_array_len.array_bound_mut.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_bound_mut.SimplifyLocals.diff +// EMIT_MIR lower_array_len.array_bound_mut.InstCombine.diff +pub fn array_bound_mut(index: usize, slice: &mut [u8; N]) -> u8 { + if index < slice.len() { + slice[index] + } else { + slice[0] = 42; + + 42 + } +} + +// EMIT_MIR lower_array_len.array_len.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_len.SimplifyLocals.diff +// EMIT_MIR lower_array_len.array_len.InstCombine.diff +pub fn array_len(arr: &[u8; N]) -> usize { + arr.len() +} + +// EMIT_MIR lower_array_len.array_len_by_value.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_len_by_value.SimplifyLocals.diff +// EMIT_MIR lower_array_len.array_len_by_value.InstCombine.diff +pub fn array_len_by_value(arr: [u8; N]) -> usize { + arr.len() +} + +fn main() { + let _ = array_bound(3, &[0, 1, 2, 3]); + let mut tmp = [0, 1, 2, 3, 4]; + let _ = array_bound_mut(3, &mut [0, 1, 2, 3]); + let _ = array_len(&[0]); + let _ = array_len_by_value([0, 2]); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ +- // MIR for `align_of` before LowerIntrinsics ++ // MIR for `align_of` after LowerIntrinsics + + fn align_of() -> usize { + let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:18:25: 18:30 + + bb0: { +- _0 = std::intrinsics::min_align_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:19:5: 19:40 +- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::}, val: Value(Scalar()) } ++ _0 = AlignOf(T); // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 + } + + bb1: { + return; // scope 0 at $DIR/lower_intrinsics.rs:20:2: 20:2 + } + + bb2 (cleanup): { + resume; // scope 0 at $DIR/lower_intrinsics.rs:18:1: 20:2 + } + } + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff 2021-11-29 19:27:11.000000000 +0000 @@ -2,127 +2,127 @@ + // MIR for `discriminant` after LowerIntrinsics fn discriminant(_1: T) -> () { - debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:68:24: 68:25 - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:68:30: 68:30 - let _2: ::Discriminant; // in scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 - let mut _3: &T; // in scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 - let _4: &T; // in scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 - let _5: u8; // in scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 - let mut _6: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 - let _7: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 - let _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:70:43: 70:44 - let _9: u8; // in scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 - let mut _10: &(); // in scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 - let _11: &(); // in scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 - let _12: (); // in scope 0 at $DIR/lower_intrinsics.rs:71:43: 71:45 - let _13: isize; // in scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 - let mut _14: &E; // in scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 - let _15: &E; // in scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 - let _16: E; // in scope 0 at $DIR/lower_intrinsics.rs:72:43: 72:47 - let mut _17: &E; // in scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 - let mut _18: &(); // in scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 - let mut _19: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:73:24: 73:25 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:73:30: 73:30 + let _2: ::Discriminant; // in scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 + let mut _3: &T; // in scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + let _4: &T; // in scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + let _5: u8; // in scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 + let mut _6: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + let _7: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + let _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:75:43: 75:44 + let _9: u8; // in scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 + let mut _10: &(); // in scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + let _11: &(); // in scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + let _12: (); // in scope 0 at $DIR/lower_intrinsics.rs:76:43: 76:45 + let _13: isize; // in scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 + let mut _14: &E; // in scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + let _15: &E; // in scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + let _16: E; // in scope 0 at $DIR/lower_intrinsics.rs:77:43: 77:47 + let mut _17: &E; // in scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + let mut _18: &(); // in scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + let mut _19: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 - StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 - StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 - _4 = &_1; // scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 - _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:69:42: 69:44 -- _2 = discriminant_value::(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 + StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + _4 = &_1; // scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 + _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:74:42: 74:44 +- _2 = discriminant_value::(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:69:5: 69:41 +- // + span: $DIR/lower_intrinsics.rs:74:5: 74:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> ::Discriminant {std::intrinsics::discriminant_value::}, val: Value(Scalar()) } -+ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 -+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:69:5: 69:45 ++ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 } bb1: { - StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:69:44: 69:45 - StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:69:45: 69:46 - StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:69:45: 69:46 - StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 - StorageLive(_6); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 - StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 - _19 = const discriminant::::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 + StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:74:44: 74:45 + StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:74:45: 74:46 + StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:74:45: 74:46 + StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 + StorageLive(_6); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + _19 = const discriminant::::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 // ty::Const // + ty: &i32 // + val: Unevaluated(discriminant, [T], Some(promoted[2])) // mir::Constant - // + span: $DIR/lower_intrinsics.rs:70:42: 70:44 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[2]) }) } - _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 - _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 -- _5 = discriminant_value::(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 + // + span: $DIR/lower_intrinsics.rs:75:42: 75:44 + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[2]) }) } + _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 + _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 +- _5 = discriminant_value::(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:70:5: 70:41 +- // + span: $DIR/lower_intrinsics.rs:75:5: 75:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> ::Discriminant {std::intrinsics::discriminant_value::}, val: Value(Scalar()) } -+ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 -+ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 ++ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 ++ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 } bb2: { - StorageDead(_6); // scope 0 at $DIR/lower_intrinsics.rs:70:44: 70:45 - StorageDead(_7); // scope 0 at $DIR/lower_intrinsics.rs:70:45: 70:46 - StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:70:45: 70:46 - StorageLive(_9); // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 - StorageLive(_10); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 - StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 - _18 = const discriminant::::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 + StorageDead(_6); // scope 0 at $DIR/lower_intrinsics.rs:75:44: 75:45 + StorageDead(_7); // scope 0 at $DIR/lower_intrinsics.rs:75:45: 75:46 + StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:75:45: 75:46 + StorageLive(_9); // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 + StorageLive(_10); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + _18 = const discriminant::::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 // ty::Const // + ty: &() // + val: Unevaluated(discriminant, [T], Some(promoted[1])) // mir::Constant - // + span: $DIR/lower_intrinsics.rs:71:42: 71:45 - // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[1]) }) } - _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 - _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 -- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 + // + span: $DIR/lower_intrinsics.rs:76:42: 76:45 + // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[1]) }) } + _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 + _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 +- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:71:5: 71:41 +- // + span: $DIR/lower_intrinsics.rs:76:5: 76:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as std::marker::DiscriminantKind>::Discriminant {std::intrinsics::discriminant_value::<()>}, val: Value(Scalar()) } -+ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 -+ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 ++ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 ++ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 } bb3: { - StorageDead(_10); // scope 0 at $DIR/lower_intrinsics.rs:71:45: 71:46 - StorageDead(_11); // scope 0 at $DIR/lower_intrinsics.rs:71:46: 71:47 - StorageDead(_9); // scope 0 at $DIR/lower_intrinsics.rs:71:46: 71:47 - StorageLive(_13); // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 - StorageLive(_14); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 - StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 - _17 = const discriminant::::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 + StorageDead(_10); // scope 0 at $DIR/lower_intrinsics.rs:76:45: 76:46 + StorageDead(_11); // scope 0 at $DIR/lower_intrinsics.rs:76:46: 76:47 + StorageDead(_9); // scope 0 at $DIR/lower_intrinsics.rs:76:46: 76:47 + StorageLive(_13); // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 + StorageLive(_14); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + _17 = const discriminant::::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 // ty::Const // + ty: &E // + val: Unevaluated(discriminant, [T], Some(promoted[0])) // mir::Constant - // + span: $DIR/lower_intrinsics.rs:72:42: 72:47 - // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[0]) }) } - _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 - _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 -- _13 = discriminant_value::(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 + // + span: $DIR/lower_intrinsics.rs:77:42: 77:47 + // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[0]) }) } + _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 + _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 +- _13 = discriminant_value::(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:72:5: 72:41 +- // + span: $DIR/lower_intrinsics.rs:77:5: 77:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> ::Discriminant {std::intrinsics::discriminant_value::}, val: Value(Scalar()) } -+ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 -+ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 ++ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 ++ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 } bb4: { - StorageDead(_14); // scope 0 at $DIR/lower_intrinsics.rs:72:47: 72:48 - StorageDead(_15); // scope 0 at $DIR/lower_intrinsics.rs:72:48: 72:49 - StorageDead(_13); // scope 0 at $DIR/lower_intrinsics.rs:72:48: 72:49 - _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:68:30: 73:2 - drop(_1) -> bb5; // scope 0 at $DIR/lower_intrinsics.rs:73:1: 73:2 + StorageDead(_14); // scope 0 at $DIR/lower_intrinsics.rs:77:47: 77:48 + StorageDead(_15); // scope 0 at $DIR/lower_intrinsics.rs:77:48: 77:49 + StorageDead(_13); // scope 0 at $DIR/lower_intrinsics.rs:77:48: 77:49 + _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:73:30: 78:2 + drop(_1) -> bb5; // scope 0 at $DIR/lower_intrinsics.rs:78:1: 78:2 } bb5: { - return; // scope 0 at $DIR/lower_intrinsics.rs:73:2: 73:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:78:2: 78:2 } bb6 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:68:1: 73:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:73:1: 78:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff 2021-11-29 19:27:11.000000000 +0000 @@ -2,32 +2,32 @@ + // MIR for `forget` after LowerIntrinsics fn forget(_1: T) -> () { - debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:18:18: 18:19 - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:18:24: 18:24 - let mut _2: T; // in scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31 + debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:23:18: 23:19 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:23:24: 23:24 + let mut _2: T; // in scope 0 at $DIR/lower_intrinsics.rs:24:30: 24:31 bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31 - _2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31 -- _0 = std::intrinsics::forget::(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:24:30: 24:31 + _2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:24:30: 24:31 +- _0 = std::intrinsics::forget::(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:19:5: 19:29 +- // + span: $DIR/lower_intrinsics.rs:24:5: 24:29 - // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::}, val: Value(Scalar()) } -+ _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32 -+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32 ++ _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 } bb1: { - StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:19:31: 19:32 - goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:20:1: 20:2 + StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:24:31: 24:32 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:25:1: 25:2 } bb2: { - return; // scope 0 at $DIR/lower_intrinsics.rs:20:2: 20:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:25:2: 25:2 } bb3 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:18:1: 20:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:23:1: 25:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir 2021-11-29 19:27:11.000000000 +0000 @@ -1,32 +1,32 @@ // MIR for `f_u64` before PreCodegen fn f_u64() -> () { - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:16 - let mut _1: u64; // in scope 0 at $DIR/lower_intrinsics.rs:35:5: 35:21 - scope 1 (inlined f_dispatch::) { // at $DIR/lower_intrinsics.rs:35:5: 35:21 - debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 - let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 - let mut _3: u64; // in scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 - scope 2 (inlined std::mem::size_of::) { // at $DIR/lower_intrinsics.rs:35:5: 35:21 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:39:16: 39:16 + let mut _1: u64; // in scope 0 at $DIR/lower_intrinsics.rs:40:5: 40:21 + scope 1 (inlined f_dispatch::) { // at $DIR/lower_intrinsics.rs:40:5: 40:21 + debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 + let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 + let mut _3: u64; // in scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 + scope 2 (inlined std::mem::size_of::) { // at $DIR/lower_intrinsics.rs:40:5: 40:21 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:35:5: 35:21 - _1 = const 0_u64; // scope 0 at $DIR/lower_intrinsics.rs:35:5: 35:21 - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 - _3 = move _1; // scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 - _2 = f_non_zst::(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:40:5: 40:21 + _1 = const 0_u64; // scope 0 at $DIR/lower_intrinsics.rs:40:5: 40:21 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 + _3 = move _1; // scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 + _2 = f_non_zst::(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:35:5: 35:21 + // + span: $DIR/lower_intrinsics.rs:40:5: 40:21 // + literal: Const { ty: fn(u64) {f_non_zst::}, val: Value(Scalar()) } } bb1: { - StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:35:5: 35:21 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:35:5: 35:21 - return; // scope 0 at $DIR/lower_intrinsics.rs:36:2: 36:2 + StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:40:5: 40:21 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:40:5: 40:21 + return; // scope 0 at $DIR/lower_intrinsics.rs:41:2: 41:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir 2021-11-29 19:27:11.000000000 +0000 @@ -1,27 +1,27 @@ // MIR for `f_unit` before PreCodegen fn f_unit() -> () { - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:28:17: 28:17 - let mut _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:29:16: 29:18 - scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics.rs:29:5: 29:19 - debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:29:5: 29:19 - let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:29:5: 29:19 - scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:29:5: 29:19 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:33:17: 33:17 + let mut _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:18 + scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics.rs:34:5: 34:19 + debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:34:5: 34:19 + let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:34:5: 34:19 + scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:34:5: 34:19 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:29:16: 29:18 - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:29:5: 29:19 - _2 = f_zst::<()>(const ()) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:29:5: 29:19 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:18 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:34:5: 34:19 + _2 = f_zst::<()>(const ()) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:34:5: 34:19 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:29:5: 29:19 + // + span: $DIR/lower_intrinsics.rs:34:5: 34:19 // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(Scalar()) } } bb1: { - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:29:5: 29:19 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:29:18: 29:19 - return; // scope 0 at $DIR/lower_intrinsics.rs:30:2: 30:2 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:34:5: 34:19 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:34:18: 34:19 + return; // scope 0 at $DIR/lower_intrinsics.rs:35:2: 35:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff 2021-11-29 19:27:11.000000000 +0000 @@ -2,34 +2,34 @@ + // MIR for `non_const` after LowerIntrinsics fn non_const() -> usize { - let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:55:26: 55:31 - let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; // in scope 0 at $DIR/lower_intrinsics.rs:57:9: 57:18 - let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; // in scope 0 at $DIR/lower_intrinsics.rs:58:5: 58:14 + let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:60:26: 60:31 + let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; // in scope 0 at $DIR/lower_intrinsics.rs:62:9: 62:18 + let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; // in scope 0 at $DIR/lower_intrinsics.rs:63:5: 63:14 scope 1 { - debug size_of_t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:57:9: 57:18 + debug size_of_t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:62:9: 62:18 } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:57:9: 57:18 - _1 = std::intrinsics::size_of::; // scope 0 at $DIR/lower_intrinsics.rs:57:21: 57:51 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:62:9: 62:18 + _1 = std::intrinsics::size_of::; // scope 0 at $DIR/lower_intrinsics.rs:62:21: 62:51 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:57:21: 57:51 + // + span: $DIR/lower_intrinsics.rs:62:21: 62:51 // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value(Scalar()) } - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:14 - _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:14 -- _0 = move _2() -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:16 -+ _0 = SizeOf(T); // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:16 -+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:16 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:14 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:14 +- _0 = move _2() -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:16 ++ _0 = SizeOf(T); // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:16 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:16 } bb1: { - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:58:15: 58:16 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:59:1: 59:2 - return; // scope 0 at $DIR/lower_intrinsics.rs:59:2: 59:2 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:63:15: 63:16 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:64:1: 64:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:64:2: 64:2 } bb2 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:55:1: 59:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:60:1: 64:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.rs rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,6 +14,11 @@ core::intrinsics::size_of::() } +// EMIT_MIR lower_intrinsics.align_of.LowerIntrinsics.diff +pub fn align_of() -> usize { + core::intrinsics::min_align_of::() +} + // EMIT_MIR lower_intrinsics.forget.LowerIntrinsics.diff pub fn forget(t: T) { core::intrinsics::forget(t) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff 2021-11-29 19:27:11.000000000 +0000 @@ -2,25 +2,25 @@ + // MIR for `unreachable` after LowerIntrinsics fn unreachable() -> ! { - let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:23:25: 23:26 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:23:27: 25:2 - let _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:24:14: 24:45 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:24:14: 24:45 + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:28:25: 28:26 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:28:27: 30:2 + let _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:29:14: 29:45 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:29:14: 29:45 scope 1 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:47 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:24:14: 24:45 -- std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:24:14: 24:45 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:29:5: 29:47 + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45 +- std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:24:14: 24:43 +- // + span: $DIR/lower_intrinsics.rs:29:14: 29:43 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(Scalar()) } -+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:24:14: 24:45 ++ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45 } bb1 (cleanup): { - resume; // scope 0 at $DIR/lower_intrinsics.rs:23:1: 25:2 + resume; // scope 0 at $DIR/lower_intrinsics.rs:28:1: 30:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ let mut _3: bool; // in scope 0 at $DIR/lower_slice_len.rs:5:8: 5:27 let mut _4: usize; // in scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 let mut _5: usize; // in scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_slice_len.rs:5:16: 5:21 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 let _7: usize; // in scope 0 at $DIR/lower_slice_len.rs:6:15: 6:20 let mut _8: usize; // in scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 let mut _9: bool; // in scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 @@ -18,8 +18,8 @@ StorageLive(_4); // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 _4 = _1; // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 StorageLive(_5); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - StorageLive(_6); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:21 - _6 = &(*_2); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:21 + StorageLive(_6); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 + _6 = &(*_2); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - _5 = core::slice::::len(move _6) -> bb1; // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - // mir::Constant - // + span: $DIR/lower_slice_len.rs:5:22: 5:25 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir 2021-11-29 19:27:11.000000000 +0000 @@ -4,13 +4,13 @@ let mut _0: (); // return place in scope 0 at $DIR/no-spurious-drop-after-call.rs:8:11: 8:11 let _1: (); // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 let mut _2: std::string::String; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 - let mut _3: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 + let mut _3: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 let _4: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 bb0: { StorageLive(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 StorageLive(_2); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 - StorageLive(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 + StorageLive(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 StorageLive(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 _4 = const ""; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 // ty::Const @@ -19,7 +19,7 @@ // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [], len: Size { raw: 0 } }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 0 }) } - _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 + _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 _2 = ::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir 2021-11-29 19:27:11.000000000 +0000 @@ -10,15 +10,15 @@ let mut _0: (); // return place in scope 0 at $DIR/receiver-ptr-mutability.rs:13:11: 13:11 let _1: *mut Test as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 let _2: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 - let mut _3: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + let mut _3: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 let mut _4: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 let _6: &&&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41 let _7: &&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:35: 18:41 let _8: &&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:36: 18:41 let _9: &*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:37: 18:41 let _10: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 - let mut _11: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 - let mut _12: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 + let mut _11: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + let mut _12: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 scope 1 { debug ptr => _1; // in scope 1 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 let _5: &&&&*mut Test as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16 @@ -39,10 +39,10 @@ FakeRead(ForLet(None), _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:14: 14:23 StorageLive(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 - StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 StorageLive(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 _4 = _1; // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 - _3 = move _4 as *const Test (Pointer(MutToConstPointer)); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + _3 = move _4 as *const Test (Pointer(MutToConstPointer)); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 StorageDead(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:7: 15:8 _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 // mir::Constant @@ -67,10 +67,10 @@ AscribeUserType(_5, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:18: 18:31 StorageDead(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:41: 18:42 StorageLive(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 - StorageLive(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 - StorageLive(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 - _12 = (*(*(*(*_5)))); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 - _11 = move _12 as *const Test (Pointer(MutToConstPointer)); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 + StorageLive(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + StorageLive(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + _12 = (*(*(*(*_5)))); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + _11 = move _12 as *const Test (Pointer(MutToConstPointer)); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 StorageDead(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:11: 19:12 _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 // mir::Constant diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ // MIR for `no_codegen` after PreCodegen fn no_codegen() -> () { - let mut _0: (); // return place in scope 0 at $DIR/remove-never-const.rs:19:20: 19:20 + let mut _0: (); // return place in scope 0 at $DIR/remove-never-const.rs:18:20: 18:20 scope 1 { } bb0: { - unreachable; // scope 0 at $DIR/remove-never-const.rs:20:13: 20:33 + unreachable; // scope 0 at $DIR/remove-never-const.rs:19:13: 19:33 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/remove-never-const.rs rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/remove-never-const.rs --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/remove-never-const.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/remove-never-const.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,6 @@ // Force generation of optimized mir for functions that do not reach codegen. // compile-flags: --emit mir,link -#![feature(const_panic)] #![feature(never_type)] #![warn(const_err)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff 2021-11-29 19:27:11.000000000 +0000 @@ -80,7 +80,7 @@ - StorageDead(_7); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 - StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 - StorageDead(_4); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 -- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:8:18: 8:19 +- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 - StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:11:1: 11:2 return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ let mut _0: (); // return place in scope 0 at $DIR/retag.rs:29:11: 29:11 let mut _1: i32; // in scope 0 at $DIR/retag.rs:30:9: 30:14 let _2: (); // in scope 0 at $DIR/retag.rs:31:5: 37:6 - let mut _4: &Test; // in scope 0 at $DIR/retag.rs:32:17: 32:24 + let mut _4: &Test; // in scope 0 at $DIR/retag.rs:32:17: 32:36 let _5: Test; // in scope 0 at $DIR/retag.rs:32:17: 32:24 let mut _6: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 let mut _7: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 @@ -15,7 +15,7 @@ let mut _17: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 let _18: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 let _19: &i32; // in scope 0 at $DIR/retag.rs:47:5: 47:24 - let mut _20: &Test; // in scope 0 at $DIR/retag.rs:47:5: 47:12 + let mut _20: &Test; // in scope 0 at $DIR/retag.rs:47:5: 47:24 let _21: Test; // in scope 0 at $DIR/retag.rs:47:5: 47:12 let mut _22: &i32; // in scope 0 at $DIR/retag.rs:47:21: 47:23 let _23: &i32; // in scope 0 at $DIR/retag.rs:47:21: 47:23 @@ -60,11 +60,11 @@ _1 = const 0_i32; // scope 0 at $DIR/retag.rs:30:17: 30:18 StorageLive(_2); // scope 1 at $DIR/retag.rs:31:5: 37:6 StorageLive(_3); // scope 1 at $DIR/retag.rs:32:13: 32:14 - StorageLive(_4); // scope 1 at $DIR/retag.rs:32:17: 32:24 + StorageLive(_4); // scope 1 at $DIR/retag.rs:32:17: 32:36 StorageLive(_5); // scope 1 at $DIR/retag.rs:32:17: 32:24 _5 = Test(const 0_i32); // scope 1 at $DIR/retag.rs:32:17: 32:24 - _4 = &_5; // scope 1 at $DIR/retag.rs:32:17: 32:24 - Retag(_4); // scope 1 at $DIR/retag.rs:32:17: 32:24 + _4 = &_5; // scope 1 at $DIR/retag.rs:32:17: 32:36 + Retag(_4); // scope 1 at $DIR/retag.rs:32:17: 32:36 StorageLive(_6); // scope 1 at $DIR/retag.rs:32:29: 32:35 StorageLive(_7); // scope 1 at $DIR/retag.rs:32:29: 32:35 _7 = &mut _1; // scope 1 at $DIR/retag.rs:32:29: 32:35 @@ -140,11 +140,11 @@ StorageDead(_16); // scope 6 at $DIR/retag.rs:44:18: 44:19 StorageDead(_18); // scope 6 at $DIR/retag.rs:44:19: 44:20 StorageLive(_19); // scope 7 at $DIR/retag.rs:47:5: 47:24 - StorageLive(_20); // scope 7 at $DIR/retag.rs:47:5: 47:12 + StorageLive(_20); // scope 7 at $DIR/retag.rs:47:5: 47:24 StorageLive(_21); // scope 7 at $DIR/retag.rs:47:5: 47:12 _21 = Test(const 0_i32); // scope 7 at $DIR/retag.rs:47:5: 47:12 - _20 = &_21; // scope 7 at $DIR/retag.rs:47:5: 47:12 - Retag(_20); // scope 7 at $DIR/retag.rs:47:5: 47:12 + _20 = &_21; // scope 7 at $DIR/retag.rs:47:5: 47:24 + Retag(_20); // scope 7 at $DIR/retag.rs:47:5: 47:24 StorageLive(_22); // scope 7 at $DIR/retag.rs:47:21: 47:23 StorageLive(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 _28 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:47:21: 47:23 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff 2021-11-29 19:27:11.000000000 +0000 @@ -8,40 +8,44 @@ let mut _3: !; // in scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10 bb0: { -- goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 + goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 + } + + bb1: { +- goto -> bb2; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 - } - -- bb1: { +- bb2: { StorageLive(_2); // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 -- _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 -+ _2 = bar() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 +- _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 ++ _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 // mir::Constant // + span: $DIR/simplify_cfg.rs:9:12: 9:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar()) } } -- bb2: { -- switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 -+ bb1: { -+ switchInt(move _2) -> [false: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 - } - - bb3: { +- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 + bb2: { ++ switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 + } + +- bb4: { ++ bb3: { _0 = const (); // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18 StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 return; // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2 } -- bb4: { -+ bb3: { +- bb5: { ++ bb4: { _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:11:10: 11:10 StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 - goto -> bb0; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 + goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 } -- bb5 (cleanup): { -+ bb4 (cleanup): { +- bb6 (cleanup): { ++ bb5 (cleanup): { resume; // scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff 2021-11-29 19:27:11.000000000 +0000 @@ -8,38 +8,35 @@ let mut _3: !; // in scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10 bb0: { -- goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 -+ falseUnwind -> [real: bb1, cleanup: bb5]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 + goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 } bb1: { - falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 -- } -- -- bb2: { ++ falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 + } + + bb2: { StorageLive(_2); // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 - _2 = bar() -> [return: bb3, unwind: bb11]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 -+ _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 ++ _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 // mir::Constant // + span: $DIR/simplify_cfg.rs:9:12: 9:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar()) } } -- bb3: { -- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 -+ bb2: { -+ switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 + bb3: { + switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 } -- bb4: { -+ bb3: { + bb4: { _0 = const (); // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18 - goto -> bb10; // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18 + StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 + return; // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2 } -- bb5: { + bb5: { - goto -> bb8; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 - } - @@ -52,15 +49,13 @@ - } - - bb8: { -+ bb4: { _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:11:10: 11:10 - goto -> bb9; // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10 - } - - bb9: { StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10 -- goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 -+ goto -> bb0; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 + goto -> bb1; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6 } - bb10: { @@ -69,7 +64,7 @@ - } - - bb11 (cleanup): { -+ bb5 (cleanup): { ++ bb6 (cleanup): { resume; // scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir 2021-11-29 19:27:11.000000000 +0000 @@ -4,80 +4,108 @@ let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:10:27: 10:27 let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - let mut _3: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - let mut _5: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 scope 1 { debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:11:9: 11:10 - let _6: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 - scope 2 { - debug _y => _6; // in scope 2 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + let _12: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + scope 4 { + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:12:10: 12:17 } } + scope 2 { + } + scope 3 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 } bb2: { - StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb3: { - StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 } bb4: { + StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 + drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb5: { + StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb6: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 - StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 - _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb5: { - StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + bb7: { + StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb6: { + bb8: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + bb9 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb10 (cleanup): { + drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb11 (cleanup): { + drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } - bb10 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir 2021-11-29 19:27:11.000000000 +0000 @@ -4,80 +4,108 @@ let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:4:24: 4:24 let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - let mut _3: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - let mut _5: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 scope 1 { debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:5:9: 5:10 - let _6: std::boxed::Box; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 - scope 2 { - debug _y => _6; // in scope 2 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + let _12: std::boxed::Box; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + scope 4 { + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:6:14: 6:16 } } + scope 2 { + } + scope 3 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 } bb2: { - StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb3: { - StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 } bb4: { + StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 + drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb5: { + StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb6: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 - StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 - _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + _12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb5: { - StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + bb7: { + StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb6: { + bb8: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + bb9 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb10 (cleanup): { + drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb11 (cleanup): { + drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } - bb10 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff 2021-11-29 19:27:11.000000000 +0000 @@ -49,7 +49,7 @@ bb3: { StorageLive(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:13: 16:41 - llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm_2.rs:16:22: 16:39 + llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm_2.rs:16:22: 16:38 _7 = const (); // scope 3 at $DIR/unreachable_asm_2.rs:16:13: 16:41 StorageDead(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:40: 16:41 _4 = const 21_i32; // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20 @@ -60,7 +60,7 @@ bb4: { StorageLive(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:13: 20:41 - llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 4 at $DIR/unreachable_asm_2.rs:20:22: 20:39 + llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 4 at $DIR/unreachable_asm_2.rs:20:22: 20:38 _8 = const (); // scope 4 at $DIR/unreachable_asm_2.rs:20:13: 20:41 StorageDead(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:40: 20:41 _4 = const 42_i32; // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff 2021-11-29 19:27:11.000000000 +0000 @@ -59,7 +59,7 @@ StorageDead(_6); // scope 2 at $DIR/unreachable_asm.rs:18:9: 18:10 StorageDead(_5); // scope 2 at $DIR/unreachable_asm.rs:18:9: 18:10 StorageLive(_7); // scope 2 at $DIR/unreachable_asm.rs:21:9: 21:37 - llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm.rs:21:18: 21:35 + llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm.rs:21:18: 21:34 _7 = const (); // scope 3 at $DIR/unreachable_asm.rs:21:9: 21:37 StorageDead(_7); // scope 2 at $DIR/unreachable_asm.rs:21:36: 21:37 StorageLive(_8); // scope 2 at $DIR/unreachable_asm.rs:22:9: 22:21 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir --- rustc-1.56.0+dfsg1+llvm/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir 2021-11-29 19:27:11.000000000 +0000 @@ -9,51 +9,55 @@ let mut _5: bool; // in scope 0 at $DIR/while-storage.rs:11:21: 11:22 bb0: { + goto -> bb1; // scope 0 at $DIR/while-storage.rs:10:5: 14:6 + } + + bb1: { StorageLive(_2); // scope 0 at $DIR/while-storage.rs:10:11: 10:22 StorageLive(_3); // scope 0 at $DIR/while-storage.rs:10:20: 10:21 _3 = _1; // scope 0 at $DIR/while-storage.rs:10:20: 10:21 - _2 = get_bool(move _3) -> bb1; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 + _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 // mir::Constant // + span: $DIR/while-storage.rs:10:11: 10:19 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar()) } } - bb1: { + bb2: { StorageDead(_3); // scope 0 at $DIR/while-storage.rs:10:21: 10:22 - switchInt(move _2) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 + switchInt(move _2) -> [false: bb7, otherwise: bb3]; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 } - bb2: { + bb3: { StorageLive(_4); // scope 0 at $DIR/while-storage.rs:11:12: 11:23 StorageLive(_5); // scope 0 at $DIR/while-storage.rs:11:21: 11:22 _5 = _1; // scope 0 at $DIR/while-storage.rs:11:21: 11:22 - _4 = get_bool(move _5) -> bb3; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 + _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 // mir::Constant // + span: $DIR/while-storage.rs:11:12: 11:20 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar()) } } - bb3: { + bb4: { StorageDead(_5); // scope 0 at $DIR/while-storage.rs:11:22: 11:23 - switchInt(move _4) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 + switchInt(move _4) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 } - bb4: { + bb5: { StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10 - goto -> bb7; // scope 0 at no-location + goto -> bb8; // scope 0 at no-location } - bb5: { + bb6: { StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10 StorageDead(_2); // scope 0 at $DIR/while-storage.rs:14:5: 14:6 - goto -> bb0; // scope 0 at $DIR/while-storage.rs:10:5: 14:6 + goto -> bb1; // scope 0 at $DIR/while-storage.rs:10:5: 14:6 } - bb6: { - goto -> bb7; // scope 0 at no-location + bb7: { + goto -> bb8; // scope 0 at no-location } - bb7: { + bb8: { StorageDead(_2); // scope 0 at $DIR/while-storage.rs:14:5: 14:6 return; // scope 0 at $DIR/while-storage.rs:15:2: 15:2 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/pretty/dollar-crate.pp rustc-1.57.0+dfsg1+llvm/src/test/pretty/dollar-crate.pp --- rustc-1.56.0+dfsg1+llvm/src/test/pretty/dollar-crate.pp 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/pretty/dollar-crate.pp 2021-11-29 19:27:11.000000000 +0000 @@ -10,11 +10,9 @@ fn main() { { - ::std::io::_print(match match () { () => [], } { - ref args => unsafe { - ::core::fmt::Arguments::new_v1(&["rust\n"], - args) - } - }); + ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], + &match () { + () => [], + })); }; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/pretty/issue-4264.pp rustc-1.57.0+dfsg1+llvm/src/test/pretty/issue-4264.pp --- rustc-1.56.0+dfsg1+llvm/src/test/pretty/issue-4264.pp 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/pretty/issue-4264.pp 2021-11-29 19:27:11.000000000 +0000 @@ -32,39 +32,29 @@ ({ let res = ((::alloc::fmt::format as - for<'r> fn(Arguments<'r>) -> String {format})((match (match (() - as - ()) - { - () - => - ([] - as - [ArgumentV1; 0]), - } - as - [ArgumentV1; 0]) - { - ref args - => - unsafe - { - ((::core::fmt::Arguments::new_v1 - as - unsafe fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" - as - &str)] - as - [&str; 1]) - as - &[&str; 1]), - (args - as - &[ArgumentV1; 0])) - as - Arguments) - } - } + for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 + as + fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" + as + &str)] + as + [&str; 1]) + as + &[&str; 1]), + (&(match (() + as + ()) + { + () + => + ([] + as + [ArgumentV1; 0]), + } + as + [ArgumentV1; 0]) + as + &[ArgumentV1; 0])) as Arguments)) as String); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/dep-graph/foo.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/dep-graph/foo.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/dep-graph/foo.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/dep-graph/foo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/dep-graph/Makefile rustc-1.57.0+dfsg1+llvm/src/test/run-make/dep-graph/Makefile --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/dep-graph/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/dep-graph/Makefile 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +-include ../../run-make-fulldeps/tools.mk + +# ignore-cross-compile + +# Just verify that we successfully run and produce dep graphs when requested. + +all: + RUST_DEP_GRAPH=$(TMPDIR)/dep-graph $(RUSTC) \ + -Cincremental=$(TMPDIR)/incr \ + -Zquery-dep-graph -Zdump-dep-graph foo.rs + test -f $(TMPDIR)/dep-graph.txt + test -f $(TMPDIR)/dep-graph.dot diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/issue-85441/empty.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/issue-85441/empty.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/issue-85441/empty.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/issue-85441/empty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/issue-85441/Makefile rustc-1.57.0+dfsg1+llvm/src/test/run-make/issue-85441/Makefile --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/issue-85441/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/issue-85441/Makefile 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +# only-windows-msvc + +-include ../../run-make-fulldeps/tools.mk + +# Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 + +all: + $(RUSTC) empty.rs + objdump -p $(TMPDIR)/empty.exe | $(CGREP) -v -i "WS2_32.dll" diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/c_static_lib_with_constructor.cpp rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/c_static_lib_with_constructor.cpp --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/c_static_lib_with_constructor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/c_static_lib_with_constructor.cpp 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +#include + +// Since this is a global variable, its constructor will be called before +// main() is executed. But only if the object file containing it actually +// gets linked into the executable. +struct Foo { + Foo() { + printf("static-initializer."); + fflush(stdout); + } +} FOO; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/directly_linked.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/directly_linked.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/directly_linked.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/directly_linked.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +use std::io::Write; + +fn main() { + print!("directly_linked."); + std::io::stdout().flush().unwrap(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/indirectly_linked.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/indirectly_linked.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/indirectly_linked.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/indirectly_linked.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +extern crate rlib_with_cmdline_native_lib; + +fn main() { + rlib_with_cmdline_native_lib::hello(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/indirectly_linked_via_attr.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/indirectly_linked_via_attr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/indirectly_linked_via_attr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/indirectly_linked_via_attr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +extern crate native_lib_in_src; + +fn main() { + native_lib_in_src::hello(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/Makefile rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/Makefile --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/Makefile 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +# ignore-cross-compile -- compiling C++ code does not work well when cross-compiling + +# This test case makes sure that native libraries are linked with --whole-archive semantics +# when the `-bundle,+whole-archive` modifiers are applied to them. +# +# The test works by checking that the resulting executables produce the expected output, +# part of which is emitted by otherwise unreferenced C code. If +whole-archive didn't work +# that code would never make it into the final executable and we'd thus be missing some +# of the output. + +-include ../../run-make-fulldeps/tools.mk + +all: $(TMPDIR)/$(call BIN,directly_linked) $(TMPDIR)/$(call BIN,indirectly_linked) $(TMPDIR)/$(call BIN,indirectly_linked_via_attr) + $(call RUN,directly_linked) | $(CGREP) 'static-initializer.directly_linked.' + $(call RUN,indirectly_linked) | $(CGREP) 'static-initializer.indirectly_linked.' + $(call RUN,indirectly_linked_via_attr) | $(CGREP) 'static-initializer.native_lib_in_src.' + +# Native lib linked directly into executable +$(TMPDIR)/$(call BIN,directly_linked): $(call NATIVE_STATICLIB,c_static_lib_with_constructor) + $(RUSTC) directly_linked.rs -Z unstable-options -l static:+whole-archive=c_static_lib_with_constructor + +# Native lib linked into RLIB via `-l static:-bundle,+whole-archive`, RLIB linked into executable +$(TMPDIR)/$(call BIN,indirectly_linked): $(TMPDIR)/librlib_with_cmdline_native_lib.rlib + $(RUSTC) indirectly_linked.rs + +# Native lib linked into RLIB via #[link] attribute, RLIB linked into executable +$(TMPDIR)/$(call BIN,indirectly_linked_via_attr): $(TMPDIR)/libnative_lib_in_src.rlib + $(RUSTC) indirectly_linked_via_attr.rs + +# Native lib linked into rlib with via commandline +$(TMPDIR)/librlib_with_cmdline_native_lib.rlib: $(call NATIVE_STATICLIB,c_static_lib_with_constructor) + $(RUSTC) rlib_with_cmdline_native_lib.rs -Z unstable-options --crate-type=rlib -l static:-bundle,+whole-archive=c_static_lib_with_constructor + +# Native lib linked into rlib via `#[link()]` attribute on extern block. +$(TMPDIR)/libnative_lib_in_src.rlib: $(call NATIVE_STATICLIB,c_static_lib_with_constructor) + $(RUSTC) native_lib_in_src.rs --crate-type=rlib + +$(TMPDIR)/libc_static_lib_with_constructor.o: c_static_lib_with_constructor.cpp + $(call COMPILE_OBJ_CXX,$@,$<) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/native_lib_in_src.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +#![feature(native_link_modifiers_bundle)] +#![feature(native_link_modifiers_whole_archive)] +#![feature(native_link_modifiers)] + +use std::io::Write; + +#[link(name = "c_static_lib_with_constructor", + kind = "static", + modifiers = "-bundle,+whole-archive")] +extern {} + +pub fn hello() { + print!("native_lib_in_src."); + std::io::stdout().flush().unwrap(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/rlib_with_cmdline_native_lib.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/rlib_with_cmdline_native_lib.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/rlib_with_cmdline_native_lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/native-link-modifier-whole-archive/rlib_with_cmdline_native_lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +use std::io::Write; + +pub fn hello() { + print!("indirectly_linked."); + std::io::stdout().flush().unwrap(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/driver.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/driver.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/driver.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/driver.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +extern crate raw_dylib_test; + +fn main() { + raw_dylib_test::library_function(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/exporter.c rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/exporter.c --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/exporter.c 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/exporter.c 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +#include + +void exported_function() { + printf("exported_function\n"); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/exporter.def rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/exporter.def --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/exporter.def 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/exporter.def 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,3 @@ +LIBRARY exporter +EXPORTS + exported_function @13 NONAME diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/lib.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +#![feature(raw_dylib)] + +#[link(name = "exporter", kind = "raw-dylib")] +extern { + #[link_ordinal(13)] + fn imported_function(); +} + +pub fn library_function() { + unsafe { + imported_function(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/Makefile rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/Makefile --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/Makefile 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +# Test the behavior of #[link(.., kind = "raw-dylib")] and #[link_ordinal] on windows-msvc + +# only-windows-msvc + +-include ../../run-make-fulldeps/tools.mk + +all: + $(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c) + $(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll + $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs + $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" + "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/output.txt output.txt +else + $(DIFF) output.txt "$(TMPDIR)"/output.txt +endif diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/output.txt rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/output.txt --- rustc-1.56.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/output.txt 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make/raw-dylib-link-ordinal/output.txt 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +exported_function diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt --- rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt 2021-11-29 19:27:11.000000000 +0000 @@ -31,15 +31,15 @@ 24| 1| println!("{:?}", Foo(1)); 25| 1| 26| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); - ^0 ^0 ^0 ^0 + ^0 ^0 ^0 27| 1| assert_ne!( 28| | Foo(0) 29| | , 30| | Foo(5) 31| | , 32| 0| "{}" - 33| | , - 34| | if + 33| 0| , + 34| 0| if 35| 0| is_true 36| | { 37| 0| "true message" diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,11 +2,12 @@ #![deny(warnings)] extern crate rustc_codegen_ssa; -extern crate rustc_errors; -extern crate rustc_middle; extern crate rustc_data_structures; extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_hir; +extern crate rustc_metadata; +extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; extern crate rustc_symbol_mangling; @@ -16,8 +17,8 @@ use rustc_codegen_ssa::{CodegenResults, CrateInfo}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorReported; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::ty::TyCtxt; use rustc_session::config::OutputFilenames; use rustc_session::Session; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/obtain-borrowck/driver.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/obtain-borrowck/driver.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/obtain-borrowck/driver.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/obtain-borrowck/driver.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,13 +11,14 @@ //! `optimized_mir` and pulls out the MIR bodies with the borrowck information //! from the thread local storage. +extern crate rustc_borrowck; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_middle; -extern crate rustc_mir; extern crate rustc_session; +use rustc_borrowck::consumers::BodyWithBorrowckFacts; use rustc_driver::Compilation; use rustc_hir::def_id::LocalDefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; @@ -26,7 +27,6 @@ use rustc_middle::ty::query::query_values::mir_borrowck; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; -use rustc_mir::consumers::BodyWithBorrowckFacts; use rustc_session::Session; use std::cell::RefCell; use std::collections::HashMap; @@ -48,7 +48,6 @@ pub struct CompilerCalls; impl rustc_driver::Callbacks for CompilerCalls { - // In this callback we override the mir_borrowck query. fn config(&mut self, config: &mut Config) { assert!(config.override_queries.is_none()); @@ -64,12 +63,10 @@ ) -> Compilation { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - // Collect definition ids of MIR bodies. let hir = tcx.hir(); - let krate = hir.krate(); let mut visitor = HirVisitor { bodies: Vec::new() }; - krate.visit_all_item_likes(&mut visitor); + hir.visit_all_item_likes(&mut visitor); // Trigger borrow checking of all bodies. for def_id in visitor.bodies { @@ -108,7 +105,7 @@ } fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> mir_borrowck<'tcx> { - let body_with_facts = rustc_mir::consumers::get_body_with_borrowck_facts( + let body_with_facts = rustc_borrowck::consumers::get_body_with_borrowck_facts( tcx, ty::WithOptConstParam::unknown(def_id), ); @@ -120,7 +117,7 @@ assert!(map.insert(def_id, body_with_facts).is_none()); }); let mut providers = Providers::default(); - rustc_mir::provide(&mut providers); + rustc_borrowck::provide(&mut providers); let original_mir_borrowck = providers.mir_borrowck; original_mir_borrowck(tcx, def_id) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/reproducible-build/Makefile rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/reproducible-build/Makefile --- rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/reproducible-build/Makefile 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/reproducible-build/Makefile 2021-11-29 19:27:11.000000000 +0000 @@ -9,9 +9,19 @@ opt \ link_paths \ remap_paths \ - different_source_dirs \ + different_source_dirs_rlib \ + remap_cwd_rlib \ + remap_cwd_to_empty \ extern_flags +# TODO: Builds of `bin` crate types are not deterministic with debuginfo=2 on +# Windows. +# See: https://github.com/rust-lang/rust/pull/87320#issuecomment-920105533 +# Issue: https://github.com/rust-lang/rust/issues/88982 +# +# different_source_dirs_bin \ +# remap_cwd_bin \ + smoke: rm -rf $(TMPDIR) && mkdir $(TMPDIR) $(RUSTC) linker.rs -O @@ -52,7 +62,19 @@ $(RUSTC) reproducible-build.rs --crate-type rlib --remap-path-prefix=/b=/c cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1 -different_source_dirs: +different_source_dirs_bin: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + mkdir $(TMPDIR)/test + cp reproducible-build.rs $(TMPDIR)/test + $(RUSTC) reproducible-build.rs --crate-type bin --remap-path-prefix=$$PWD=/b + cp $(TMPDIR)/reproducible-build $(TMPDIR)/foo + (cd $(TMPDIR)/test && $(RUSTC) reproducible-build.rs \ + --remap-path-prefix=$(TMPDIR)/test=/b \ + --crate-type bin) + cmp "$(TMPDIR)/reproducible-build" "$(TMPDIR)/foo" || exit 1 + +different_source_dirs_rlib: rm -rf $(TMPDIR) && mkdir $(TMPDIR) $(RUSTC) reproducible-build-aux.rs mkdir $(TMPDIR)/test @@ -64,6 +86,45 @@ --crate-type rlib) cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1 +remap_cwd_bin: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + mkdir $(TMPDIR)/test + cp reproducible-build.rs $(TMPDIR)/test + $(RUSTC) reproducible-build.rs --crate-type bin -C debuginfo=2 \ + -Z remap-cwd-prefix=. + cp $(TMPDIR)/reproducible-build $(TMPDIR)/first + (cd $(TMPDIR)/test && \ + $(RUSTC) reproducible-build.rs --crate-type bin -C debuginfo=2 \ + -Z remap-cwd-prefix=.) + cmp "$(TMPDIR)/first" "$(TMPDIR)/reproducible-build" || exit 1 + +remap_cwd_rlib: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + mkdir $(TMPDIR)/test + cp reproducible-build.rs $(TMPDIR)/test + $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \ + -Z remap-cwd-prefix=. + cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfirst.rlib + (cd $(TMPDIR)/test && \ + $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \ + -Z remap-cwd-prefix=.) + cmp "$(TMPDIR)/libfirst.rlib" "$(TMPDIR)/libreproducible_build.rlib" || exit 1 + +remap_cwd_to_empty: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + mkdir $(TMPDIR)/test + cp reproducible-build.rs $(TMPDIR)/test + $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \ + -Z remap-cwd-prefix= + cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfirst.rlib + (cd $(TMPDIR)/test && \ + $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \ + -Z remap-cwd-prefix=) + cmp "$(TMPDIR)/libfirst.rlib" "$(TMPDIR)/libreproducible_build.rlib" || exit 1 + extern_flags: rm -rf $(TMPDIR) && mkdir $(TMPDIR) $(RUSTC) reproducible-build-aux.rs diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/sepcomp-cci-copies/Makefile rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/sepcomp-cci-copies/Makefile --- rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/sepcomp-cci-copies/Makefile 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/sepcomp-cci-copies/Makefile 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ # Check that cross-crate inlined items are inlined in all compilation units # that refer to them, and not in any other compilation units. # Note that we have to pass `-C codegen-units=6` because up to two CGUs may be -# created for each source module (see `rustc_mir::monomorphize::partitioning`). +# created for each source module (see `rustc_const_eval::monomorphize::partitioning`). all: $(RUSTC) cci_lib.rs diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py --- rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py 2021-11-29 19:27:11.000000000 +0000 @@ -17,6 +17,17 @@ return s +def set_ld_lib_path(): + var = os.environ.get("LD_LIB_PATH_ENVVAR") + rpath = os.environ.get("HOST_RPATH_DIR") + if var and rpath: + path = os.environ.get(var) + if path: + os.environ[var] = rpath + os.pathsep + path + else: + os.environ[var] = rpath + + def exec_command(command, to_input=None): child = None if to_input is None: @@ -50,7 +61,9 @@ if isfile(join(dir_path, f)) and f.endswith('.rlib') and f not in STABLE_CRATES] +set_ld_lib_path() sysroot = exec_command([os.environ['RUSTC'], '--print', 'sysroot'])[0].replace('\n', '') +assert sysroot, "Could not read the rustc sysroot!" libs = get_all_libs(join(sysroot, 'lib/rustlib/{}/lib'.format(os.environ['TARGET']))) ret = 0 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/target-specs/foo.rs rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/target-specs/foo.rs --- rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/target-specs/foo.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/target-specs/foo.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ auto trait Freeze {} #[lang = "start"] -fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { +fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { 0 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/tools.mk rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/tools.mk --- rustc-1.56.0+dfsg1+llvm/src/test/run-make-fulldeps/tools.mk 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/run-make-fulldeps/tools.mk 2021-11-29 19:27:11.000000000 +0000 @@ -101,9 +101,9 @@ # Extra flags needed to compile a working executable with the standard library ifdef IS_WINDOWS ifdef IS_MSVC - EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib + EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib else - EXTRACFLAGS := -lws2_32 -luserenv + EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt EXTRACXXFLAGS := -lstdc++ # So this is a bit hacky: we can't use the DLL version of libstdc++ because # it pulls in the DLL version of libgcc, which means that we end up with 2 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/associated-consts.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/associated-consts.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/associated-consts.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/associated-consts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,31 @@ +#![crate_name = "foo"] + +pub trait Trait { + const FOO: u32 = 12; + + fn foo(); +} + +pub struct Bar; + +// @has 'foo/struct.Bar.html' +// @has - '//h3[@class="sidebar-title"]' 'Associated Constants' +// @has - '//div[@class="sidebar-elems"]//div[@class="sidebar-links"]/a' 'FOO' +impl Trait for Bar { + const FOO: u32 = 1; + + fn foo() {} +} + +pub enum Foo { + A, +} + +// @has 'foo/enum.Foo.html' +// @has - '//h3[@class="sidebar-title"]' 'Associated Constants' +// @has - '//div[@class="sidebar-elems"]//div[@class="sidebar-links"]/a' 'FOO' +impl Trait for Foo { + const FOO: u32 = 1; + + fn foo() {} +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/auxiliary/issue-15318.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/auxiliary/issue-15318.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/auxiliary/issue-15318.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/auxiliary/issue-15318.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,15 @@ +// no-prefer-dynamic // compile-flags: -Cmetadata=aux - +#![crate_type = "rlib"] #![doc(html_root_url = "http://example.com/")] +#![feature(lang_items)] +#![no_std] + +#[lang = "eh_personality"] +fn foo() {} + +#[panic_handler] +fn bar(_: &core::panic::PanicInfo) -> ! { loop {} } /// dox #[doc(primitive = "pointer")] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/auxiliary/primitive-doc.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/auxiliary/primitive-doc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/auxiliary/primitive-doc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/auxiliary/primitive-doc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,8 @@ // compile-flags: --crate-type lib --edition 2018 +#![feature(no_core)] +#![no_core] + #[doc(primitive = "usize")] /// This is the built-in type `usize`. mod usize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/check-source-code-urls-to-def.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/check-source-code-urls-to-def.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/check-source-code-urls-to-def.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/check-source-code-urls-to-def.rs 2021-11-29 19:27:11.000000000 +0000 @@ -27,6 +27,8 @@ fn babar() {} // @has - '//a/@href' '/struct.String.html' +// @has - '//a/@href' '/primitive.u32.html' +// @has - '//a/@href' '/primitive.str.html' // @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#21"]' 5 // @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode' pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) { @@ -40,5 +42,9 @@ // @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'bar::sub::Trait' // @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait' -pub fn foo2(t: &T, v: &V) { +pub fn foo2(t: &T, v: &V, b: bool) { } + +// @has - '//a[@href="../../foo/primitive.bool.html"]' 'bool' +#[doc(primitive = "bool")] +mod whatever {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/check-source-code-urls-to-def-std.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/check-source-code-urls-to-def-std.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/check-source-code-urls-to-def-std.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/check-source-code-urls-to-def-std.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +// compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +// @has 'src/foo/check-source-code-urls-to-def-std.rs.html' + +fn babar() {} + +// @has - '//a[@href="{{channel}}/std/primitive.u32.html"]' 'u32' +// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str' +// @has - '//a[@href="{{channel}}/std/primitive.bool.html"]' 'bool' +// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#7"]' 'babar' +pub fn foo(a: u32, b: &str, c: String) { + let x = 12; + let y: bool = true; + babar(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/cross-crate-primitive-doc.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/cross-crate-primitive-doc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/cross-crate-primitive-doc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/cross-crate-primitive-doc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,13 @@ // aux-build:primitive-doc.rs // compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options +// only-linux -#![no_std] +#![feature(no_core)] +#![no_core] extern crate primitive_doc; // @has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'usize' +// @has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'link' +/// [link](usize) pub fn foo() -> usize { 0 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/doc-auto-cfg.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/doc-auto-cfg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/doc-auto-cfg.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/doc-auto-cfg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +#![feature(doc_auto_cfg)] + +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test' +#[cfg(not(test))] +pub fn foo() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-hide.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-hide.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-hide.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-hide.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,32 @@ +#![crate_name = "oud"] +#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)] + +#![doc(cfg_hide(feature = "solecism"))] + +// @has 'oud/struct.Solecism.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="solecism" +#[cfg(feature = "solecism")] +pub struct Solecism; + +// @has 'oud/struct.Scribacious.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature solecism' +#[cfg(feature = "solecism")] +#[doc(cfg(feature = "solecism"))] +pub struct Scribacious; + +// @has 'oud/struct.Hyperdulia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature hyperdulia' +// compile-flags:--cfg feature="hyperdulia" +#[cfg(feature = "solecism")] +#[cfg(feature = "hyperdulia")] +pub struct Hyperdulia; + +// @has 'oud/struct.Oystercatcher.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate features solecism and oystercatcher' +// compile-flags:--cfg feature="oystercatcher" +#[cfg(all(feature = "solecism", feature = "oystercatcher"))] +pub struct Oystercatcher; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-implicit-gate.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-implicit-gate.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-implicit-gate.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-implicit-gate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +// compile-flags:--cfg feature="worricow" +#![crate_name = "xenogenous"] + +// @has 'xenogenous/struct.Worricow.html' +// @count - '//*[@class="stab portability"]' 0 +#[cfg(feature = "worricow")] +pub struct Worricow; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-implicit.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-implicit.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-implicit.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/doc-cfg-implicit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,31 @@ +#![crate_name = "funambulism"] +#![feature(doc_auto_cfg, doc_cfg)] + +// @has 'funambulism/struct.Disorbed.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature disorbed' +// compile-flags:--cfg feature="disorbed" +#[cfg(feature = "disorbed")] +pub struct Disorbed; + +// @has 'funambulism/struct.Aesthesia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature aesthesia' +// compile-flags:--cfg feature="aesthesia" +#[doc(cfg(feature = "aesthesia"))] +pub struct Aesthesia; + +// @has 'funambulism/struct.Pliothermic.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature pliothermic' +// compile-flags:--cfg feature="epopoeist" +#[cfg(feature = "epopoeist")] +#[doc(cfg(feature = "pliothermic"))] +pub struct Pliothermic; + +// @has 'funambulism/struct.Simillimum.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="simillimum" +#[cfg(feature = "simillimum")] +#[doc(cfg(all()))] +pub struct Simillimum; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/external-cross.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/external-cross.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/external-cross.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/external-cross.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,5 +6,5 @@ extern crate external_cross; // @has host/struct.NeedMoreDocs.html -// @has - '//h1' 'Cross-crate imported docs' +// @has - '//h2' 'Cross-crate imported docs' pub use external_cross::NeedMoreDocs; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/external-doc.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/external-doc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/external-doc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/external-doc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // @has external_doc/struct.IncludeStrDocs.html -// @has - '//h1' 'External Docs' -// @has - '//h2' 'Inline Docs' +// @has - '//h2' 'External Docs' +// @has - '//h3' 'Inline Docs' #[doc = include_str!("auxiliary/external-doc.md")] /// ## Inline Docs pub struct IncludeStrDocs; @@ -8,7 +8,7 @@ macro_rules! dir { () => { "auxiliary" } } // @has external_doc/struct.EagerExpansion.html -// @has - '//h1' 'External Docs' +// @has - '//h2' 'External Docs' #[doc = include_str!(concat!(dir!(), "/external-doc.md"))] /// ## Inline Docs pub struct EagerExpansion; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/feature-gate-doc_auto_cfg.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/feature-gate-doc_auto_cfg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/feature-gate-doc_auto_cfg.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/feature-gate-doc_auto_cfg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +#![feature(doc_cfg)] + +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @count - '//*[@class="item-info"]/*[@class="stab portability"]' 0 +#[cfg(not(test))] +pub fn foo() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/hidden-trait-methods.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/hidden-trait-methods.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/hidden-trait-methods.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/hidden-trait-methods.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +// test for trait methods with `doc(hidden)`. +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @!has - '//*[@id="tymethod.f"]' 'fn f()' +// @has - '//*[@id="tymethod.g"]' 'fn g()' +pub trait Trait { + #[doc(hidden)] + type Foo; + type Bar; + #[doc(hidden)] + fn f(); + fn g(); +} + +// @has foo/struct.S.html +// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @!has - '//*[@id="method.f"]' 'fn f()' +// @has - '//*[@id="method.g"]' 'fn g()' +pub struct S; +impl Trait for S { + type Foo = (); + type Bar = (); + fn f() {} + fn g() {} +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,31 @@ +// compile-flags: -Z unstable-options --document-hidden-items + +// test for trait methods with `doc(hidden)` with `--document-hidden-items` passed. +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +// @has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @has - '//*[@id="tymethod.f"]' 'fn f()' +// @has - '//*[@id="tymethod.g"]' 'fn g()' +pub trait Trait { + #[doc(hidden)] + type Foo; + type Bar; + #[doc(hidden)] + fn f(); + fn g(); +} + +// @has foo/struct.S.html +// @has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @has - '//*[@id="method.f"]' 'fn f()' +// @has - '//*[@id="method.g"]' 'fn g()' +pub struct S; +impl Trait for S { + type Foo = (); + type Bar = (); + fn f() {} + fn g() {} +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-doc/anchors.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-doc/anchors.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-doc/anchors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-doc/anchors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,3 +10,15 @@ /// /// To link to [Something#Anchor!] pub struct SomeOtherType; + +/// Primitives? +/// +/// [u32#hello] +// @has anchors/fn.x.html +// @has - '//a/@href' '{{channel}}/std/primitive.u32.html#hello' +pub fn x() {} + +/// [prim@usize#x] +// @has anchors/usize/index.html +// @has - '//a/@href' '{{channel}}/std/primitive.usize.html#x' +pub mod usize {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-doc/auxiliary/my-core.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-doc/auxiliary/my-core.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-doc/auxiliary/my-core.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-doc/auxiliary/my-core.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,10 @@ #![no_core] #![crate_type="rlib"] +#[doc(primitive = "char")] +/// Some char docs +mod char {} + #[lang = "char"] impl char { pub fn len_utf8(self) -> usize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-doc/prim-methods-external-core.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-doc/prim-methods-external-core.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-doc/prim-methods-external-core.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-doc/prim-methods-external-core.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // aux-build:my-core.rs // build-aux-docs // ignore-cross-compile -// ignore-windows +// only-linux #![deny(broken_intra_doc_links)] #![feature(no_core, lang_items)] @@ -9,8 +9,8 @@ #![crate_type = "rlib"] // @has prim_methods_external_core/index.html -// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char' -// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8' +// @has - '//*[@id="main"]//a[@href="../my_core/primitive.char.html"]' 'char' +// @has - '//*[@id="main"]//a[@href="../my_core/primitive.char.html#method.len_utf8"]' 'char::len_utf8' //! A [`char`] and its [`char::len_utf8`]. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-doc/prim-methods-local.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-doc/prim-methods-local.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-doc/prim-methods-local.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-doc/prim-methods-local.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,10 +5,13 @@ // @has prim_methods_local/index.html -// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char' -// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8' +// @has - '//*[@id="main"]//a[@href="primitive.char.html"]' 'char' +// @has - '//*[@id="main"]//a[@href="primitive.char.html#method.len_utf8"]' 'char::len_utf8' -//! A [`char`] and its [`char::len_utf8`]. +//! A [prim@`char`] and its [`char::len_utf8`]. + +#[doc(primitive = "char")] +mod char {} #[lang = "char"] impl char { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-link-prim-self.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-link-prim-self.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/intra-link-prim-self.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/intra-link-prim-self.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,8 @@ /// [Self::f] /// [Self::MAX] // @has intra_link_prim_self/primitive.usize.html -// @has - '//a[@href="{{channel}}/std/primitive.usize.html#method.f"]' 'Self::f' -// @has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX' +// @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f' +// @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX' impl usize { /// Some docs pub fn f() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/issue-15318-2.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/issue-15318-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/issue-15318-2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/issue-15318-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ // aux-build:issue-15318.rs // ignore-cross-compile +#![no_std] extern crate issue_15318; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/issue-42760.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/issue-42760.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/issue-42760.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/issue-42760.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // @has issue_42760/struct.NonGen.html -// @has - '//h1' 'Example' +// @has - '//h2' 'Example' /// Item docs. /// diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/issue-89309-heading-levels.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/issue-89309-heading-levels.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/issue-89309-heading-levels.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/issue-89309-heading-levels.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +#![crate_name = "foo"] + +// @has foo/trait.Read.html +// @has - '//h2' 'Trait examples' +/// # Trait examples +pub trait Read { + // @has - '//h5' 'Function examples' + /// # Function examples + fn read(&mut self, buf: &mut [u8]) -> Result; +} + +pub struct Foo; + +// @has foo/struct.Foo.html +impl Foo { + // @has - '//h5' 'Implementation header' + /// # Implementation header + pub fn bar(&self) -> usize { + 1 + } +} + +impl Read for Foo { + // @has - '//h5' 'Trait implementation header' + /// # Trait implementation header + fn read(&mut self, buf: &mut [u8]) -> Result { + Ok(1) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/macro-document-private-duplicate.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/macro-document-private-duplicate.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/macro-document-private-duplicate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/macro-document-private-duplicate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,5 @@ +// ignore-test (fails spuriously, see issue #89228) + // FIXME: If two macros in the same module have the same name // (yes, that's a thing), rustdoc lists both of them on the index page, // but only documents the first one on the page for the macro. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/macro_rules-matchers.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/macro_rules-matchers.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/macro_rules-matchers.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/macro_rules-matchers.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,37 +6,31 @@ // @has 'foo/macro.todo.html' // @has - '//span[@class="macro"]' 'macro_rules!' // @has - '//span[@class="ident"]' 'todo' -// Note: count = 2 * ('=' + '>') + '+' = 2 * (1 + 1) + 1 = 5 -// @count - '//pre[@class="rust macro"]//span[@class="op"]' 5 +// Note: the only op is the `+` +// @count - '//pre[@class="rust macro"]//span[@class="op"]' 1 -// @has - '{ ()' -// @has - '//span[@class="op"]' '=' -// @has - '//span[@class="op"]' '>' -// @has - '{ ... };' - -// @has - '($(' +// @has - '{ () => { ... }; ($(' // @has - '//span[@class="macro-nonterminal"]' '$' // @has - '//span[@class="macro-nonterminal"]' 'arg' // @has - ':' // @has - '//span[@class="ident"]' 'tt' // @has - '),' // @has - '//span[@class="op"]' '+' -// @has - ')' +// @has - ') => { ... }; }' pub use std::todo; mod mod1 { // @has 'foo/macro.macro1.html' // @has - 'macro_rules!' // @has - 'macro1' - // @has - '{ ()' - // @has - '($(' + // @has - '{ () => { ... }; ($(' // @has - '//span[@class="macro-nonterminal"]' '$' // @has - '//span[@class="macro-nonterminal"]' 'arg' // @has - ':' // @has - 'expr' // @has - '),' // @has - '+' - // @has - ')' + // @has - ') => { ... }; }' #[macro_export] macro_rules! macro1 { () => {}; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/no_std-primitive.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/no_std-primitive.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/no_std-primitive.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/no_std-primitive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +#![no_std] + +/// Link to [intra-doc link][u8] +// @has 'no_std_primitive/fn.foo.html' '//a[@href="{{channel}}/core/primitive.u8.html"]' 'intra-doc link' +// @has - '//a[@href="{{channel}}/core/primitive.u8.html"]' 'u8' +pub fn foo() -> u8 {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/primitive/no_std.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/primitive/no_std.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/primitive/no_std.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/primitive/no_std.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +#![no_std] +#![deny(warnings)] +#![deny(rustdoc::broken_intra_doc_links)] + +// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'u8' +// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'primitive link' +/// Link to [primitive link][u8] +pub fn foo() -> u8 {} + +// Test that all primitives can be linked to. +/// [isize] [i8] [i16] [i32] [i64] [i128] +/// [usize] [u8] [u16] [u32] [u64] [u128] +/// [f32] [f64] +/// [char] [bool] [str] [slice] [array] [tuple] [unit] +/// [pointer] [reference] [fn] [never] +pub fn bar() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/short-docblock.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/short-docblock.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/short-docblock.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/short-docblock.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ // @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'fooo' // @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h1' 'fooo' -// @has foo/fn.foo.html '//h1[@id="fooo"]/a[@href="#fooo"]' 'fooo' +// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo' /// # fooo /// @@ -11,7 +11,7 @@ // @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'mooood' // @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h2' 'mooood' -// @has foo/foo/index.html '//h2[@id="mooood"]/a[@href="#mooood"]' 'mooood' +// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood' /// ## mooood /// diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/smart-punct.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/smart-punct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/smart-punct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/smart-punct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,7 +21,7 @@ //! ``` // @has "foo/index.html" "//p" "This is the “start†of the ‘document’! How’d you know that “it’s†the start?" -// @has "foo/index.html" "//h1" "Header with “smart punct’â€" +// @has "foo/index.html" "//h2" "Header with “smart punct’â€" // @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’†– yessiree!" // @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\"" // @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";" diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/synthetic_auto/no-redundancy.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/synthetic_auto/no-redundancy.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/synthetic_auto/no-redundancy.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/synthetic_auto/no-redundancy.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ // @has no_redundancy/struct.Outer.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl Send for Outer where T: Copy + Send" +// "impl Send for Outer where T: Send + Copy" pub struct Outer { inner_field: Inner, } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/table-in-docblock.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/table-in-docblock.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/table-in-docblock.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/table-in-docblock.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @count - '//*[@class="docblock"]/div/table' 2 +// @!has - '//*[@class="docblock"]/table' +/// | hello | hello2 | +/// | ----- | ------ | +/// | data | data2 | +pub struct Foo; + +impl Foo { + /// | hello | hello2 | + /// | ----- | ------ | + /// | data | data2 | + pub fn foo(&self) {} +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/type-layout.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/type-layout.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc/type-layout.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc/type-layout.rs 2021-11-29 19:27:11.000000000 +0000 @@ -52,3 +52,21 @@ // @!has type_layout/trait.MyTrait.html 'Size: ' pub trait MyTrait {} + +// @has type_layout/enum.Variants.html 'Size: ' +// @has - '2 bytes' +// @has - 'A: 0 bytes' +// @has - 'B: 1 byte' +pub enum Variants { + A, + B(u8), +} + +// @has type_layout/enum.WithNiche.html 'Size: ' +// @has - //p '4 bytes' +// @has - 'None: 0 bytes' +// @has - 'Some: 4 bytes' +pub enum WithNiche { + None, + Some(std::num::NonZeroU32), +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/code-sidebar-toggle.goml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/code-sidebar-toggle.goml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/code-sidebar-toggle.goml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/code-sidebar-toggle.goml 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ goto: file://|DOC_PATH|/test_docs/index.html click: ".srclink" +wait-for: "#sidebar-toggle" click: "#sidebar-toggle" wait-for: 500 fail: true diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/docblock-big-code-mobile.goml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/docblock-big-code-mobile.goml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/docblock-big-code-mobile.goml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/docblock-big-code-mobile.goml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +// If we have a long ``, we need to ensure that it'll be fully displayed on mobile, meaning +// that it'll be on two lines. +emulate: "iPhone 8" // it has the following size: (375, 667) +goto: file://|DOC_PATH|/test_docs/long_code_block/index.html +// We now check that the block is on two lines: +show-text: true // We need to enable text draw to be able to have the "real" size +// Little explanations for this test: if the text wasn't displayed on two lines, it would take +// around 20px (which is the font size). +assert-property: (".docblock p > code", {"offsetHeight": "42"}) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/docblock-table-overflow.goml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/docblock-table-overflow.goml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/docblock-table-overflow.goml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/docblock-table-overflow.goml 2021-11-29 19:27:11.000000000 +0000 @@ -7,3 +7,11 @@ assert-property: (".top-doc .docblock", {"scrollWidth": "816"}) // However, since there is overflow in the , its scroll width is bigger. assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"}) + +// Checking it works on other doc blocks as well... + +// Logically, the ".docblock" and the "

" should have the same scroll width. +compare-elements-property: ("#implementations + details .docblock", "#implementations + details .docblock > p", ["scrollWidth"]) +assert-property: ("#implementations + details .docblock", {"scrollWidth": "816"}) +// However, since there is overflow in the

, its scroll width is bigger. +assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"}) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/header-size.goml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/header-size.goml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/header-size.goml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/header-size.goml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,99 @@ +// This test check that headers (a) have the correct heading level, and (b) are the right size. +// The sizes may change as design changes, but try to make sure a lower header is never bigger than +// its parent headers. +// Most of these sizes are set in CSS in `em` units, so here's a conversion chart based on our +// default 16px font size: +// 24px 1.5em +// 22.4px 1.4em +// 20.8px 1.3em +// 18.4px 1.15em +// 17.6px 1.1em +// 16px 1em +// 15.2px 0.95em +goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html + +assert-css: ("h1.fqn", {"font-size": "24px"}) + +assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"}) +assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "16px"}) + +assert-css: ("h2#fields", {"font-size": "22.4px"}) +assert-css: ("h3#title-for-field", {"font-size": "20.8px"}) +assert-css: ("h4#sub-heading-for-field", {"font-size": "16px"}) + +assert-css: ("h2#implementations", {"font-size": "22.4px"}) + +assert-css: ("#impl > h3.code-header", {"font-size": "16px"}) +assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"}) + +assert-css: ("h4#title-for-struct-impl-doc", {"font-size": "16px"}) +assert-css: ("h5#sub-heading-for-struct-impl-doc", {"font-size": "16px"}) +assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "15.2px"}) + +assert-css: ("h5#title-for-struct-impl-item-doc", {"font-size": "16px"}) +assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"}) +assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"}) + +goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html + +assert-css: ("h1.fqn", {"font-size": "24px"}) + +assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"}) +assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "16px"}) + +assert-css: ("h2#variants", {"font-size": "22.4px"}) + +assert-css: ("h3#none-prose-title", {"font-size": "20.8px"}) +assert-css: ("h4#none-prose-sub-heading", {"font-size": "16px"}) + +assert-css: ("h3#wrapped-prose-title", {"font-size": "20.8px"}) +assert-css: ("h4#wrapped-prose-sub-heading", {"font-size": "16px"}) + +assert-css: ("h4#wrapped0-prose-title", {"font-size": "16px"}) +assert-css: ("h5#wrapped0-prose-sub-heading", {"font-size": "16px"}) + +assert-css: ("h4#structy-prose-title", {"font-size": "16px"}) +assert-css: ("h5#structy-prose-sub-heading", {"font-size": "16px"}) + +assert-css: ("h2#implementations", {"font-size": "22.4px"}) + +assert-css: ("#impl > h3.code-header", {"font-size": "16px"}) +assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"}) + +assert-css: ("h4#title-for-enum-impl-doc", {"font-size": "16px"}) +assert-css: ("h5#sub-heading-for-enum-impl-doc", {"font-size": "16px"}) +assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "15.2px"}) + +assert-css: ("h5#title-for-enum-impl-item-doc", {"font-size": "16px"}) +assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"}) +assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"}) + +goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html + +assert-css: ("h1.fqn", {"font-size": "24px"}) + +assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"}) + +assert-css: ("h2#fields", {"font-size": "22.4px"}) + +assert-css: ("h3#title-for-union-variant", {"font-size": "20.8px"}) +assert-css: ("h4#sub-heading-for-union-variant", {"font-size": "16px"}) + +assert-css: ("h2#implementations", {"font-size": "22.4px"}) + +assert-css: ("#impl > h3.code-header", {"font-size": "16px"}) +assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"}) +assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"}) + +assert-css: ("h5#title-for-union-impl-item-doc", {"font-size": "16px"}) +assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "15.2px"}) + +goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html + +assert-css: ("h1.fqn", {"font-size": "24px"}) + +assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"}) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/huge-collection-of-constants.goml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/huge-collection-of-constants.goml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/huge-collection-of-constants.goml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/huge-collection-of-constants.goml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html + +// Make sure that the last two entries are more than 12 pixels apart and not stacked on each other. + +compare-elements-position-near-false: ("//*[@class='item-table']//div[last()-1]", "//*[@class='item-table']//div[last()-3]", {"y": 12}) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/jump-to-def-background.goml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/jump-to-def-background.goml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/jump-to-def-background.goml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/jump-to-def-background.goml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +// We check the background color on the jump to definition links in the source code page. +goto: file://|DOC_PATH|/src/link_to_definition/lib.rs.html + +// Set the theme to dark. +local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(51, 51, 51)"}, ALL) + +// Set the theme to ayu. +local-storage: {"rustdoc-theme": "ayu", "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(51, 51, 51)"}, ALL) + +// Set the theme to light. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(238, 238, 238)"}, ALL) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/sidebar.goml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/sidebar.goml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/sidebar.goml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/sidebar.goml 2021-11-29 19:27:11.000000000 +0000 @@ -7,12 +7,14 @@ assert-text: (".sidebar-elems > .crate > ul > li > a.current", "test_docs") // And we're also supposed to have the list of items in the current module. assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(6)", "Type Definitions") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(7)", "Keywords") +assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Macros") +assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Structs") +assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Enums") +assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Traits") +assert-text: (".sidebar-elems > .items > ul > li:nth-child(6)", "Functions") +assert-text: (".sidebar-elems > .items > ul > li:nth-child(7)", "Type Definitions") +assert-text: (".sidebar-elems > .items > ul > li:nth-child(8)", "Unions") +assert-text: (".sidebar-elems > .items > ul > li:nth-child(9)", "Keywords") assert-text: ("#structs + .item-table .item-left > a", "Foo") click: "#structs + .item-table .item-left > a" diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/lib2/lib.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/lib2/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/lib2/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/lib2/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -67,6 +67,15 @@ /// /// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq pub struct Foo; + + /// | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | + /// | ----------- | ----------- | ----------- | ----------- | + /// | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | + /// + /// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq + impl Foo { + pub fn foo(&self) {} + } } pub mod summary_table { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "link_to_definition" +version = "0.1.0" diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +[package] +name = "link_to_definition" +version = "0.1.0" +edition = "2018" + +[lib] +path = "lib.rs" diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/lib.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/link_to_definition/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +pub struct Bar { + pub a: String, + pub b: u32, +} + +pub fn foo(_b: &Bar) {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/build.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/build.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/build.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/build.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +//! generate 2000 constants for testing + +use std::{fs::write, path::PathBuf}; + +fn main() -> std::io::Result<()> { + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is not defined"); + + let mut output = String::new(); + for i in 0..2000 { + let line = format!("/// Some const A{0}\npub const A{0}: isize = 0;\n", i); + output.push_str(&*line); + }; + + write(&[&*out_dir, "huge_amount_of_consts.rs"].iter().collect::(), output) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -3,5 +3,7 @@ version = "0.1.0" edition = "2018" +build = "build.rs" + [lib] path = "lib.rs" diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/lib.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-gui/src/test_docs/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -116,3 +116,136 @@ /// Just some type alias. pub type SomeType = u32; + +pub mod huge_amount_of_consts { + include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs")); +} + +/// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`. +pub mod long_code_block {} + +/// # Top-doc Prose title +/// +/// Text below title. +/// +/// ## Top-doc Prose sub-heading +/// +/// Text below sub-heading. +/// +/// ### Top-doc Prose sub-sub-heading +/// +/// Text below sub-sub-heading +pub struct HeavilyDocumentedStruct { + /// # Title for field + /// ## Sub-heading for field + pub nothing: (), +} + +/// # Title for struct impl doc +/// +/// Text below heading. +/// +/// ## Sub-heading for struct impl doc +/// +/// Text below sub-heading. +/// +/// ### Sub-sub-heading for struct impl doc +/// +/// Text below sub-sub-heading. +/// +impl HeavilyDocumentedStruct { + /// # Title for struct impl-item doc + /// Text below title. + /// ## Sub-heading for struct impl-item doc + /// Text below sub-heading. + /// ### Sub-sub-heading for struct impl-item doc + /// Text below sub-sub-heading. + pub fn do_nothing() {} +} + +/// # Top-doc Prose title +/// +/// Text below title. +/// +/// ## Top-doc Prose sub-heading +/// +/// Text below sub-heading. +/// +/// ### Top-doc Prose sub-sub-heading +/// +/// Text below sub-sub-heading +pub enum HeavilyDocumentedEnum { + /// # None prose title + /// ## None prose sub-heading + None, + /// # Wrapped prose title + /// ## Wrapped prose sub-heading + Wrapped( + /// # Wrapped.0 prose title + /// ## Wrapped.0 prose sub-heading + String, + String, + ), + Structy { + /// # Structy prose title + /// ## Structy prose sub-heading + alpha: String, + beta: String, + }, +} + +/// # Title for enum impl doc +/// +/// Text below heading. +/// +/// ## Sub-heading for enum impl doc +/// +/// Text below sub-heading. +/// +/// ### Sub-sub-heading for enum impl doc +/// +/// Text below sub-sub-heading. +/// +impl HeavilyDocumentedEnum { + /// # Title for enum impl-item doc + /// Text below title. + /// ## Sub-heading for enum impl-item doc + /// Text below sub-heading. + /// ### Sub-sub-heading for enum impl-item doc + /// Text below sub-sub-heading. + pub fn do_nothing() {} +} + +/// # Top-doc prose title +/// +/// Text below heading. +/// +/// ## Top-doc prose sub-heading +/// +/// Text below heading. +pub union HeavilyDocumentedUnion { + /// # Title for union variant + /// ## Sub-heading for union variant + pub nothing: (), + pub something: f32, +} + +/// # Title for union impl doc +/// ## Sub-heading for union impl doc +impl HeavilyDocumentedUnion { + /// # Title for union impl-item doc + /// ## Sub-heading for union impl-item doc + pub fn do_nothing() {} +} + +/// # Top-doc prose title +/// +/// Text below heading. +/// +/// ## Top-doc prose sub-heading +/// +/// Text below heading. +#[macro_export] +macro_rules! heavily_documented_macro { + () => {}; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-json/primitive.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-json/primitive.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-json/primitive.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-json/primitive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// edition:2018 + +#![feature(doc_primitive)] + +#[doc(primitive = "usize")] +mod usize {} + +// @set local_crate_id = primitive.json "$.index[*][?(@.name=='primitive')].crate_id" + +// @has - "$.index[*][?(@.name=='log10')]" +// @!is - "$.index[*][?(@.name=='log10')].crate_id" $local_crate_id +// @has - "$.index[*][?(@.name=='checked_add')]" +// @!is - "$.index[*][?(@.name=='checked_add')]" $local_crate_id +// @!has - "$.index[*][?(@.name=='is_ascii_uppercase')]" diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-json/primitives.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-json/primitives.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-json/primitives.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-json/primitives.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +#![feature(never_type)] + +// @has primitives.json "$.index[*][?(@.name=='PrimNever')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='PrimNever')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimNever')].inner.type.inner" \"never\" +pub type PrimNever = !; + +// @has - "$.index[*][?(@.name=='PrimStr')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimStr')].inner.type.inner" \"str\" +pub type PrimStr = str; + +// @has - "$.index[*][?(@.name=='PrimBool')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimBool')].inner.type.inner" \"bool\" +pub type PrimBool = bool; + +// @has - "$.index[*][?(@.name=='PrimChar')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimChar')].inner.type.inner" \"char\" +pub type PrimChar = char; + +// @has - "$.index[*][?(@.name=='PrimU8')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimU8')].inner.type.inner" \"u8\" +pub type PrimU8 = u8; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-json/structs/with_primitives.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-json/structs/with_primitives.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-json/structs/with_primitives.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-json/structs/with_primitives.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // @has with_primitives.json "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" // @has - "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\" // @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\" -// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind" \"lifetime\" +// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" [] // @has - "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\" // @has - "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true pub struct WithPrimitives<'a> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-json/unions/impl.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-json/unions/impl.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-json/unions/impl.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-json/unions/impl.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +#![no_std] + +// @has impl.json "$.index[*][?(@.name=='Ux')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Ux')].kind" \"union\" +pub union Ux { + a: u32, + b: u64 +} + +// @has - "$.index[*][?(@.name=='Num')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Num')].kind" \"trait\" +pub trait Num {} + +// @count - "$.index[*][?(@.name=='Ux')].inner.impls" 1 +impl Num for Ux {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-js-std/multi-query.js rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-js-std/multi-query.js --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-js-std/multi-query.js 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-js-std/multi-query.js 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,9 @@ const EXPECTED = { 'others': [ - { 'path': 'std', 'name': 'str' }, - { 'path': 'std', 'name': 'u8' }, - { 'path': 'std::ffi', 'name': 'CStr' }, + { 'path': 'std', 'name': 'str', 'href': '../std/primitive.str.html' }, + { 'path': 'std', 'name': 'u8', 'href': '../std/primitive.u8.html' }, + { 'path': 'std', 'name': 'str', 'href': '../std/str/index.html' }, + { 'path': 'std', 'name': 'u8', 'href': '../std/u8/index.html' }, ], }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,6 @@ pub const AssocConst: Self::AssocTy = 42; //~^ ERROR ambiguous associated type //~| HELP use fully-qualified syntax - // FIXME: for some reason, the error is shown twice with rustdoc but only once with rustc //~| ERROR ambiguous associated type //~| HELP use fully-qualified syntax } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/bounded-hr-lifetime.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/bounded-hr-lifetime.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/bounded-hr-lifetime.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/bounded-hr-lifetime.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +// This test ensures that rustdoc doesn't panic on higher-ranked lifetimes +// with bounds, because an error should have already been emitted by rustc. + +pub fn hrlt<'b, 'c>() +where + for<'a: 'b + 'c> &'a (): std::fmt::Debug, + //~^ ERROR lifetime bounds cannot be used in this context +{ +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/bounded-hr-lifetime.stderr rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/bounded-hr-lifetime.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/bounded-hr-lifetime.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/bounded-hr-lifetime.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: lifetime bounds cannot be used in this context + --> $DIR/bounded-hr-lifetime.rs:6:13 + | +LL | for<'a: 'b + 'c> &'a (): std::fmt::Debug, + | ^^ ^^ + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enums.stdout rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enums.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enums.stdout 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enums.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ +-------------------------------------+------------+------------+------------+------------+ | File | Documented | Percentage | Examples | Percentage | +-------------------------------------+------------+------------+------------+------------+ -| ...est/rustdoc-ui/coverage/enums.rs | 6 | 66.7% | 0 | 0.0% | +| ...est/rustdoc-ui/coverage/enums.rs | 6 | 75.0% | 0 | 0.0% | +-------------------------------------+------------+------------+------------+------------+ -| Total | 6 | 66.7% | 0 | 0.0% | +| Total | 6 | 75.0% | 0 | 0.0% | +-------------------------------------+------------+------------+------------+------------+ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,37 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +// The point of this test is to ensure that the number of "documented" items +// is higher than in `enum-tuple.rs`. + +//! (remember the crate root is still a module) + +/// so check out this enum here +pub enum ThisEnum { + /// VarOne. + VarOne( + /// hello! + String, + ), + /// Var Two. + VarTwo( + /// Hello + String, + /// Bis repetita. + String, + ), +} + +/// Struct. +pub struct ThisStruct( + /// hello + u32, +); + +/// Struct. +pub struct ThisStruct2( + /// hello + u32, + /// Bis repetita. + u8, +); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...overage/enum-tuple-documented.rs | 9 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 9 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! (remember the crate root is still a module) + +/// so check out this enum here +pub enum ThisEnum { + /// No need to document the field if there is only one in a tuple variant! + VarOne(String), + /// But if there is more than one... still fine! + VarTwo(String, String), +} + +/// Struct. +pub struct ThisStruct(u32); + +/// Struct. +pub struct ThisStruct2(u32, u8); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple.stdout rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple.stdout 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/coverage/enum-tuple.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...ustdoc-ui/coverage/enum-tuple.rs | 6 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 6 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/display-output.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/display-output.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/display-output.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/display-output.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +// check-pass +// compile-flags:-Zunstable-options --display-doctest-warnings --test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// let x = 12; +/// ``` +pub fn foo() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/display-output.stdout rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/display-output.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/display-output.stdout 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/display-output.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ + +running 1 test +test $DIR/display-output.rs - foo (line 6) ... ok + +successes: + +---- $DIR/display-output.rs - foo (line 6) stdout ---- +warning: unused variable: `x` + --> $DIR/display-output.rs:7:5 + | +LL | let x = 12; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | + = note: `#[warn(unused_variables)]` on by default + +warning: 1 warning emitted + + + +successes: + $DIR/display-output.rs - foo (line 6) + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/doc-cfg.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/doc-cfg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/doc-cfg.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/doc-cfg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +#![feature(doc_cfg)] + +#[doc(cfg(), cfg(foo, bar))] +//~^ ERROR +//~^^ ERROR +#[doc(cfg(foo), cfg(bar))] // ok! +#[doc(cfg())] //~ ERROR +#[doc(cfg(foo, bar))] //~ ERROR +pub fn foo() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/doc-cfg.stderr rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/doc-cfg.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/doc-cfg.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/doc-cfg.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:3:7 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:3:23 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^ + +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:7:7 + | +LL | #[doc(cfg())] + | ^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:8:16 + | +LL | #[doc(cfg(foo, bar))] + | ^^^ + +error: aborting due to 4 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/doctest-edition.stderr rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/doctest-edition.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/doctest-edition.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/doctest-edition.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,7 @@ help: mark blocks that do not contain Rust code as text | LL | //! ```text - | ~~~~~~~ + | ++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +#![doc(cfg_hide(test))] +//~^ ERROR `#[doc(cfg_hide)]` is experimental + +#[cfg(not(test))] +pub fn public_fn() {} +#[cfg(test)] +pub fn internal_use_only() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0658]: `#[doc(cfg_hide)]` is experimental + --> $DIR/feature-gate-doc_cfg_hide.rs:1:1 + | +LL | #![doc(cfg_hide(test))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg_hide)]` to the crate attributes to enable + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/anchors.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/anchors.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/anchors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/anchors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -37,13 +37,3 @@ /// Damn enum's variants: [Enum::A#whatever]. //~^ ERROR `Enum::A#whatever` contains an anchor pub fn enum_link() {} - -/// Primitives? -/// -/// [u32#hello] -//~^ ERROR `u32#hello` contains an anchor -pub fn x() {} - -/// [prim@usize#x] -//~^ ERROR `prim@usize#x` contains an anchor -pub mod usize {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/anchors.stderr rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/anchors.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/anchors.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/anchors.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,19 +1,3 @@ -error: `prim@usize#x` contains an anchor, but links to builtin types are already anchored - --> $DIR/anchors.rs:47:6 - | -LL | /// [prim@usize#x] - | ^^^^^^^^^^-- - | | - | invalid anchor - | -note: the lint level is defined here - --> $DIR/anchors.rs:1:9 - | -LL | #![deny(rustdoc::broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this restriction may be lifted in a future release - = note: see https://github.com/rust-lang/rust/issues/83083 for more information - error: `Foo::f#hola` contains an anchor, but links to fields are already anchored --> $DIR/anchors.rs:25:15 | @@ -21,6 +5,12 @@ | ^^^^^^----- | | | invalid anchor + | +note: the lint level is defined here + --> $DIR/anchors.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `hello#people#!` contains multiple anchors --> $DIR/anchors.rs:31:28 @@ -38,16 +28,5 @@ | | | invalid anchor -error: `u32#hello` contains an anchor, but links to builtin types are already anchored - --> $DIR/anchors.rs:43:6 - | -LL | /// [u32#hello] - | ^^^------ - | | - | invalid anchor - | - = note: this restriction may be lifted in a future release - = note: see https://github.com/rust-lang/rust/issues/83083 for more information - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +// intentionally empty diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +// intentionally empty diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +// intentionally empty diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +// intentionally empty diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +// check-pass +// aux-crate:dep1=dep1.rs +// aux-crate:dep2=dep2.rs +// aux-crate:dep3=dep3.rs +// aux-crate:dep4=dep4.rs +#![deny(rustdoc::broken_intra_doc_links)] + +pub trait Trait { + /// [dep1] + type Item; +} + +pub struct S { + /// [dep2] + pub x: usize, +} + +extern "C" { + /// [dep3] + pub fn printf(); +} + +pub enum E { + /// [dep4] + A +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/warning.stderr rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/warning.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/warning.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/intra-doc/warning.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -88,7 +88,7 @@ | ^^^^^^^^^^^ ... LL | f!("Foo\nbar [BarF] bar\nbaz"); - | ------------------------------- in this macro invocation + | ------------------------------ in this macro invocation | = note: the link appears in this line: diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/invalid-syntax.stderr rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/invalid-syntax.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/invalid-syntax.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/invalid-syntax.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -14,7 +14,7 @@ help: mark blocks that do not contain Rust code as text | LL | /// ```text - | ~~~~~~~ + | ++++ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:9:5 @@ -32,7 +32,7 @@ help: mark blocks that do not contain Rust code as text | LL | /// ```text - | ~~~~~~~ + | ++++ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:21:5 @@ -47,7 +47,7 @@ help: mark blocks that do not contain Rust code as text | LL | /// ```text - | ~~~~~~~ + | ++++ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:35:5 @@ -123,7 +123,7 @@ help: mark blocks that do not contain Rust code as text | LL | /// ```text - | ~~~~~~~ + | ++++ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:92:9 @@ -148,7 +148,7 @@ help: mark blocks that do not contain Rust code as text | LL | /// ```text - | ~~~~~~~ + | ++++ warning: 12 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/lint-missing-doc-code-example.rs rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/lint-missing-doc-code-example.rs --- rustc-1.56.0+dfsg1+llvm/src/test/rustdoc-ui/lint-missing-doc-code-example.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/rustdoc-ui/lint-missing-doc-code-example.rs 2021-11-29 19:27:11.000000000 +0000 @@ -70,6 +70,22 @@ b: f32, } +// no code example and it's fine! +impl Clone for Struct { + fn clone(&self) -> Self { + Self { field: self.field } + } +} + + + +/// doc +/// +/// ``` +/// println!("hello"); +/// ``` +#[derive(Clone)] +pub struct NiceStruct; #[doc(hidden)] pub mod foo { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/alignment-gep-tup-like-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/alignment-gep-tup-like-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/alignment-gep-tup-like-1.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/alignment-gep-tup-like-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -#![feature(box_syntax)] - struct pair { a: A, b: B } @@ -25,10 +23,10 @@ } fn f(a: A, b: u16) -> Box+'static> { - box Invoker { + Box::new(Invoker { a: a, b: b, - } as Box+'static> + }) as Box+'static> } pub fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/annotate-snippet/multispan.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/annotate-snippet/multispan.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/annotate-snippet/multispan.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/annotate-snippet/multispan.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,41 +2,41 @@ --> $DIR/multispan.rs:15:5 | LL | hello!(hi); - | ^^^^^^^^^^^ + | ^^^^^^^^^^ | error: hello to you, too! --> $DIR/multispan.rs:18:5 | LL | hello!(hi hi); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | error: hello to you, too! --> $DIR/multispan.rs:21:5 | LL | hello!(hi hi hi); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | error: hello to you, too! --> $DIR/multispan.rs:24:5 | LL | hello!(hi hey hi yo hi beep beep hi hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! --> $DIR/multispan.rs:25:5 | LL | hello!(hi there, hi how are you? hi... hi.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! --> $DIR/multispan.rs:26:5 | LL | hello!(whoah. hi di hi di ho); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! --> $DIR/multispan.rs:27:5 | LL | hello!(hi good hi and good bye); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/anon-params/anon-params-denied-2018.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/anon-params/anon-params-denied-2018.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/anon-params/anon-params-denied-2018.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/anon-params/anon-params-denied-2018.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,15 +8,15 @@ help: if this is a `self` type, give it a parameter name | LL | fn foo(self: i32); - | ~~~~~~~~~ + | +++++ help: if this is a parameter name, give it a type | LL | fn foo(i32: TypeName); - | ~~~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | fn foo(_: i32); - | ~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:9:29 @@ -28,7 +28,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn foo_with_ref(self: &mut i32); - | ~~~~~~~~~~~~~~ + | +++++ help: if this is a parameter name, give it a type | LL | fn foo_with_ref(i32: &mut TypeName); @@ -36,7 +36,7 @@ help: if this is a type, explicitly ignore the parameter name | LL | fn foo_with_ref(_: &mut i32); - | ~~~~~~~~~~~ + | ++ error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:12:47 @@ -96,15 +96,15 @@ help: if this is a `self` type, give it a parameter name | LL | fn bar_with_default_impl(self: String, String) {} - | ~~~~~~~~~~~~ + | +++++ help: if this is a parameter name, give it a type | LL | fn bar_with_default_impl(String: TypeName, String) {} - | ~~~~~~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | fn bar_with_default_impl(_: String, String) {} - | ~~~~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:22:44 @@ -116,11 +116,11 @@ help: if this is a parameter name, give it a type | LL | fn bar_with_default_impl(String, String: TypeName) {} - | ~~~~~~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | fn bar_with_default_impl(String, _: String) {} - | ~~~~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:27:22 @@ -132,11 +132,11 @@ help: if this is a parameter name, give it a type | LL | fn baz(a:usize, b: TypeName, c: usize) -> usize { - | ~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | fn baz(a:usize, _: b, c: usize) -> usize { - | ~~~~ + | ++ error: aborting due to 9 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/anon-params/anon-params-deprecated.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/anon-params/anon-params-deprecated.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/anon-params/anon-params-deprecated.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/anon-params/anon-params-deprecated.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -warning: anonymous parameters are deprecated and will be removed in the next edition. +warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/anon-params-deprecated.rs:9:12 | LL | fn foo(i32); @@ -12,7 +12,7 @@ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #41686 -warning: anonymous parameters are deprecated and will be removed in the next edition. +warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/anon-params-deprecated.rs:12:30 | LL | fn bar_with_default_impl(String, String) {} @@ -21,7 +21,7 @@ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #41686 -warning: anonymous parameters are deprecated and will be removed in the next edition. +warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/anon-params-deprecated.rs:12:38 | LL | fn bar_with_default_impl(String, String) {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/array-slice-vec/slice_binary_search.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/array-slice-vec/slice_binary_search.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/array-slice-vec/slice_binary_search.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/array-slice-vec/slice_binary_search.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,7 @@ // Test binary_search_by_key lifetime. Issue #34683 +#[allow(dead_code)] #[derive(Debug)] struct Assignment { topic: String, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/array-slice-vec/vec-dst.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/array-slice-vec/vec-dst.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/array-slice-vec/vec-dst.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/array-slice-vec/vec-dst.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,9 @@ // run-pass -#![feature(box_syntax)] - pub fn main() { - // Tests for indexing into box/& [T; n] + // Tests for indexing into Box<[T; n]>/& [T; n] let x: [isize; 3] = [1, 2, 3]; - let mut x: Box<[isize; 3]> = box x; + let mut x: Box<[isize; 3]> = x.into(); assert_eq!(x[0], 1); assert_eq!(x[1], 2); assert_eq!(x[2], 3); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/array-slice-vec/vec-mut-iter-borrow.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/array-slice-vec/vec-mut-iter-borrow.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/array-slice-vec/vec-mut-iter-borrow.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/array-slice-vec/vec-mut-iter-borrow.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | first mutable borrow occurs here | first borrow later used here LL | xs.push(1) - | ^^ second mutable borrow occurs here + | ^^^^^^^^^^ second mutable borrow occurs here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/array-slice-vec/vector-no-ann-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/array-slice-vec/vector-no-ann-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/array-slice-vec/vector-no-ann-2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/array-slice-vec/vector-no-ann-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,6 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - -pub fn main() { let _quux: Box> = box Vec::new(); } +pub fn main() { + let _quux: Box> = Box::new(Vec::new()); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-options.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-options.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-options.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-options.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +// only-aarch64 + +#![feature(asm, global_asm)] + +fn main() { + let mut foo = 0; + unsafe { + asm!("", options(nomem, readonly)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + asm!("", options(pure, nomem, noreturn)); + //~^ ERROR the `pure` and `noreturn` options are mutually exclusive + //~^^ ERROR asm with the `pure` option must have at least one output + asm!("{}", in(reg) foo, options(pure, nomem)); + //~^ ERROR asm with the `pure` option must have at least one output + asm!("{}", out(reg) foo, options(noreturn)); + //~^ ERROR asm outputs are not allowed with the `noreturn` option + } + + unsafe { + asm!("", clobber_abi("foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("{}", out(reg) foo, clobber_abi("C")); + //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + asm!("", out("x0") foo, clobber_abi("C")); + } +} + +global_asm!("", options(nomem)); +//~^ ERROR expected one of +global_asm!("", options(readonly)); +//~^ ERROR expected one of +global_asm!("", options(noreturn)); +//~^ ERROR expected one of +global_asm!("", options(pure)); +//~^ ERROR expected one of +global_asm!("", options(nostack)); +//~^ ERROR expected one of +global_asm!("", options(preserves_flags)); +//~^ ERROR expected one of diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-options.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-options.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-options.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-options.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,84 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/bad-options.rs:8:18 + | +LL | asm!("", options(nomem, readonly)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:13:33 + | +LL | asm!("{}", in(reg) foo, options(pure, nomem)); + | ^^^^^^^^^^^^^^^^^^^^ + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/bad-options.rs:15:20 + | +LL | asm!("{}", out(reg) foo, options(noreturn)); + | ^^^^^^^^^^^^ + +error: asm with `clobber_abi` must specify explicit registers for outputs + --> $DIR/bad-options.rs:22:20 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C")); + | ^^^^^^^^^^^^ ---------------- clobber_abi + | | + | generic outputs + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/bad-options.rs:28:25 + | +LL | global_asm!("", options(nomem)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` + --> $DIR/bad-options.rs:30:25 + | +LL | global_asm!("", options(readonly)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` + --> $DIR/bad-options.rs:32:25 + | +LL | global_asm!("", options(noreturn)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `pure` + --> $DIR/bad-options.rs:34:25 + | +LL | global_asm!("", options(pure)); + | ^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` + --> $DIR/bad-options.rs:36:25 + | +LL | global_asm!("", options(nostack)); + | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` + --> $DIR/bad-options.rs:38:25 + | +LL | global_asm!("", options(preserves_flags)); + | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-options.rs:20:18 + | +LL | asm!("", clobber_abi("foo")); + | ^^^^^^^^^^^^^^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi` + +error: aborting due to 13 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-reg.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-reg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-reg.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-reg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,59 @@ +// only-aarch64 +// compile-flags: -C target-feature=+fp + +#![feature(asm)] + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + // Bad register/register class + + asm!("{}", in(foo) foo); + //~^ ERROR invalid register class `foo`: unknown register class + asm!("", in("foo") foo); + //~^ ERROR invalid register `foo`: unknown register + asm!("{:z}", in(reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(vreg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(vreg_low16) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:a}", const 0); + //~^ ERROR asm template modifiers are not allowed for `const` arguments + asm!("{:a}", sym main); + //~^ ERROR asm template modifiers are not allowed for `sym` arguments + asm!("", in("x29") foo); + //~^ ERROR invalid register `x29`: the frame pointer cannot be used as an operand + asm!("", in("sp") foo); + //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand + asm!("", in("xzr") foo); + //~^ ERROR invalid register `xzr`: the zero register cannot be used as an operand + asm!("", in("x18") foo); + //~^ ERROR invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm + asm!("", in("x19") foo); + //~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm + + asm!("", in("p0") foo); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + asm!("", out("p0") _); + asm!("{}", in(preg) foo); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + asm!("{}", out(preg) _); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + + // Explicit register conflicts + // (except in/lateout which don't conflict) + + asm!("", in("x0") foo, in("w0") bar); + //~^ ERROR register `x0` conflicts with register `x0` + asm!("", in("x0") foo, out("x0") bar); + //~^ ERROR register `x0` conflicts with register `x0` + asm!("", in("w0") foo, lateout("w0") bar); + asm!("", in("v0") foo, in("q0") bar); + //~^ ERROR register `v0` conflicts with register `v0` + asm!("", in("v0") foo, out("q0") bar); + //~^ ERROR register `v0` conflicts with register `v0` + asm!("", in("v0") foo, lateout("q0") bar); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-reg.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-reg.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-reg.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/bad-reg.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,152 @@ +error: invalid register class `foo`: unknown register class + --> $DIR/bad-reg.rs:12:20 + | +LL | asm!("{}", in(foo) foo); + | ^^^^^^^^^^^ + +error: invalid register `foo`: unknown register + --> $DIR/bad-reg.rs:14:18 + | +LL | asm!("", in("foo") foo); + | ^^^^^^^^^^^^^ + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:16:15 + | +LL | asm!("{:z}", in(reg) foo); + | ^^^^ ----------- argument + | | + | template modifier + | + = note: the `reg` register class supports the following template modifiers: `w`, `x` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:18:15 + | +LL | asm!("{:r}", in(vreg) foo); + | ^^^^ ------------ argument + | | + | template modifier + | + = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:20:15 + | +LL | asm!("{:r}", in(vreg_low16) foo); + | ^^^^ ------------------ argument + | | + | template modifier + | + = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` + +error: asm template modifiers are not allowed for `const` arguments + --> $DIR/bad-reg.rs:22:15 + | +LL | asm!("{:a}", const 0); + | ^^^^ ------- argument + | | + | template modifier + +error: asm template modifiers are not allowed for `sym` arguments + --> $DIR/bad-reg.rs:24:15 + | +LL | asm!("{:a}", sym main); + | ^^^^ -------- argument + | | + | template modifier + +error: invalid register `x29`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:26:18 + | +LL | asm!("", in("x29") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:28:18 + | +LL | asm!("", in("sp") foo); + | ^^^^^^^^^^^^ + +error: invalid register `xzr`: the zero register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", in("xzr") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", in("x18") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:34:18 + | +LL | asm!("", in("x19") foo); + | ^^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:37:18 + | +LL | asm!("", in("p0") foo); + | ^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:40:20 + | +LL | asm!("{}", in(preg) foo); + | ^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:42:20 + | +LL | asm!("{}", out(preg) _); + | ^^^^^^^^^^^ + +error: register `x0` conflicts with register `x0` + --> $DIR/bad-reg.rs:48:32 + | +LL | asm!("", in("x0") foo, in("w0") bar); + | ------------ ^^^^^^^^^^^^ register `x0` + | | + | register `x0` + +error: register `x0` conflicts with register `x0` + --> $DIR/bad-reg.rs:50:32 + | +LL | asm!("", in("x0") foo, out("x0") bar); + | ------------ ^^^^^^^^^^^^^ register `x0` + | | + | register `x0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:50:18 + | +LL | asm!("", in("x0") foo, out("x0") bar); + | ^^^^^^^^^^^^ + +error: register `v0` conflicts with register `v0` + --> $DIR/bad-reg.rs:53:32 + | +LL | asm!("", in("v0") foo, in("q0") bar); + | ------------ ^^^^^^^^^^^^ register `v0` + | | + | register `v0` + +error: register `v0` conflicts with register `v0` + --> $DIR/bad-reg.rs:55:32 + | +LL | asm!("", in("v0") foo, out("q0") bar); + | ------------ ^^^^^^^^^^^^^ register `v0` + | | + | register `v0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:55:18 + | +LL | asm!("", in("v0") foo, out("q0") bar); + | ^^^^^^^^^^^^ + +error: aborting due to 19 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/const.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/const.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/const.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/const.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,42 @@ +// min-llvm-version: 10.0.1 +// only-aarch64 +// run-pass +// revisions: mirunsafeck thirunsafeck +// [thirunsafeck]compile-flags: -Z thir-unsafeck + +#![feature(asm, global_asm)] + +fn const_generic() -> usize { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const X); + a + } +} + +const fn constfn(x: usize) -> usize { + x +} + +fn main() { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const 5); + assert_eq!(a, 5); + + let b: usize; + asm!("mov {}, {}", out(reg) b, const constfn(5)); + assert_eq!(b, 5); + + let c: usize; + asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5)); + assert_eq!(c, 10); + } + + let d = const_generic::<5>(); + assert_eq!(d, 5); +} + +global_asm!("mov x0, {}", const 5); +global_asm!("mov x0, {}", const constfn(5)); +global_asm!("mov x0, {}", const constfn(5) + constfn(5)); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +// only-aarch64 +// run-rustfix + +#![feature(asm, global_asm)] + +fn main() { + unsafe { + asm!("", options(nomem, )); + //~^ ERROR the `nomem` option was already provided + asm!("", options(preserves_flags, )); + //~^ ERROR the `preserves_flags` option was already provided + asm!("", options(nostack, preserves_flags), options()); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, ), options(), options()); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(preserves_flags, ), //~ ERROR the `noreturn` option was already provided + options( nostack), //~ ERROR the `nomem` option was already provided + options(), //~ ERROR the `noreturn` option was already provided + ); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +// only-aarch64 +// run-rustfix + +#![feature(asm, global_asm)] + +fn main() { + unsafe { + asm!("", options(nomem, nomem)); + //~^ ERROR the `nomem` option was already provided + asm!("", options(preserves_flags, preserves_flags)); + //~^ ERROR the `preserves_flags` option was already provided + asm!("", options(nostack, preserves_flags), options(nostack)); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, nostack), options(nostack), options(nostack)); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(preserves_flags, noreturn), //~ ERROR the `noreturn` option was already provided + options(nomem, nostack), //~ ERROR the `nomem` option was already provided + options(noreturn), //~ ERROR the `noreturn` option was already provided + ); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/duplicate-options.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,56 @@ +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:8:33 + | +LL | asm!("", options(nomem, nomem)); + | ^^^^^ this option was already provided + +error: the `preserves_flags` option was already provided + --> $DIR/duplicate-options.rs:10:43 + | +LL | asm!("", options(preserves_flags, preserves_flags)); + | ^^^^^^^^^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:12:61 + | +LL | asm!("", options(nostack, preserves_flags), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:35 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:53 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:71 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:21:38 + | +LL | options(preserves_flags, noreturn), + | ^^^^^^^^ this option was already provided + +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:22:21 + | +LL | options(nomem, nostack), + | ^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:23:21 + | +LL | options(noreturn), + | ^^^^^^^^ this option was already provided + +error: aborting due to 9 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/interpolated-idents.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/interpolated-idents.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/interpolated-idents.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/interpolated-idents.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ +// only-aarch64 + +#![feature(asm)] + +macro_rules! m { + ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident + $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident + $noreturn:ident $nostack:ident $options:ident) => { + unsafe { + asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + //~^ ERROR asm outputs are not allowed with the `noreturn` option + const x, sym x, + $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + //~| ERROR the `pure` and `noreturn` options are mutually exclusive + } + }; +} + +fn main() { + m!(in out lateout inout inlateout const sym + pure nomem readonly preserves_flags + noreturn nostack options); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/interpolated-idents.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/interpolated-idents.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/interpolated-idents.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/interpolated-idents.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | |________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | |________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/interpolated-idents.rs:10:32 + | +LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ +... +LL | m!(in out lateout inout inlateout const sym + | _____- + | |_____| + | |_____| + | |_____| + | | +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | | - + | |________________________________| + | |________________________________in this macro invocation + | |________________________________in this macro invocation + | |________________________________in this macro invocation + | in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/parse-error.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/parse-error.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/parse-error.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/parse-error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,135 @@ +// only-aarch64 + +#![feature(asm, global_asm)] + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + asm!(); + //~^ ERROR requires at least a template string argument + asm!(foo); + //~^ ERROR asm template must be a string literal + asm!("{}" foo); + //~^ ERROR expected token: `,` + asm!("{}", foo); + //~^ ERROR expected operand, clobber_abi, options, or additional template string + asm!("{}", in foo); + //~^ ERROR expected `(`, found `foo` + asm!("{}", in(reg foo)); + //~^ ERROR expected `)`, found `foo` + asm!("{}", in(reg)); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", inout(=) foo => bar); + //~^ ERROR expected register class or explicit register + asm!("{}", inout(reg) foo =>); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", in(reg) foo => bar); + //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + asm!("{}", sym foo + bar); + //~^ ERROR argument to `sym` must be a path expression + asm!("", options(foo)); + //~^ ERROR expected one of + asm!("", options(nomem foo)); + //~^ ERROR expected one of + asm!("", options(nomem, foo)); + //~^ ERROR expected one of + asm!("{}", options(), const foo); + //~^ ERROR arguments are not allowed after options + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", clobber_abi(foo)); + //~^ ERROR expected string literal + asm!("", clobber_abi("C" foo)); + //~^ ERROR expected `)`, found `foo` + asm!("", clobber_abi("C", foo)); + //~^ ERROR expected `)`, found `,` + asm!("{}", clobber_abi("C"), const foo); + //~^ ERROR arguments are not allowed after clobber_abi + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), clobber_abi("C")); + //~^ ERROR clobber_abi is not allowed after options + asm!("{}", options(), clobber_abi("C"), const foo); + //~^ ERROR clobber_abi is not allowed after options + asm!("", clobber_abi("C"), clobber_abi("C")); + //~^ ERROR clobber_abi specified multiple times + asm!("{a}", a = const foo, a = const bar); + //~^ ERROR duplicate argument named `a` + //~^^ ERROR argument never used + //~^^^ ERROR attempt to use a non-constant value in a constant + //~^^^^ ERROR attempt to use a non-constant value in a constant + asm!("", a = in("x0") foo); + //~^ ERROR explicit register arguments cannot have names + asm!("{a}", in("x0") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{a}", in("x0") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{1}", in("x0") foo, const bar); + //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), ""); + //~^ ERROR expected one of + asm!("{}", in(reg) foo, "{}", out(reg) foo); + //~^ ERROR expected one of + asm!(format!("{{{}}}", 0), in(reg) foo); + //~^ ERROR asm template must be a string literal + asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + //~^ ERROR asm template must be a string literal + asm!("{}", in(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inout(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inlateout(reg) _); + //~^ ERROR _ cannot be used for input operands + } +} + +const FOO: i32 = 1; +const BAR: i32 = 2; +global_asm!(); +//~^ ERROR requires at least a template string argument +global_asm!(FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{}" FOO); +//~^ ERROR expected token: `,` +global_asm!("{}", FOO); +//~^ ERROR expected operand, options, or additional template string +global_asm!("{}", const); +//~^ ERROR expected expression, found end of macro arguments +global_asm!("{}", const(reg) FOO); +//~^ ERROR expected one of +global_asm!("", options(FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem, FOO)); +//~^ ERROR expected one of +global_asm!("{}", options(), const FOO); +//~^ ERROR arguments are not allowed after options +global_asm!("", clobber_abi(FOO)); +//~^ ERROR expected string literal +global_asm!("", clobber_abi("C" FOO)); +//~^ ERROR expected `)`, found `FOO` +global_asm!("", clobber_abi("C", FOO)); +//~^ ERROR expected `)`, found `,` +global_asm!("{}", clobber_abi("C"), const FOO); +//~^ ERROR arguments are not allowed after clobber_abi +//~^^ ERROR `clobber_abi` cannot be used with `global_asm!` +global_asm!("", options(), clobber_abi("C")); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("{}", options(), clobber_abi("C"), const FOO); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("", clobber_abi("C"), clobber_abi("C")); +//~^ ERROR clobber_abi specified multiple times +global_asm!("{a}", a = const FOO, a = const BAR); +//~^ ERROR duplicate argument named `a` +//~^^ ERROR argument never used +global_asm!("", options(), ""); +//~^ ERROR expected one of +global_asm!("{}", const FOO, "{}", const FOO); +//~^ ERROR expected one of +global_asm!(format!("{{{}}}", 0), const FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); +//~^ ERROR asm template must be a string literal diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/parse-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/parse-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/parse-error.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/parse-error.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,462 @@ +error: requires at least a template string argument + --> $DIR/parse-error.rs:9:9 + | +LL | asm!(); + | ^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:11:14 + | +LL | asm!(foo); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:13:19 + | +LL | asm!("{}" foo); + | ^^^ expected `,` + +error: expected operand, clobber_abi, options, or additional template string + --> $DIR/parse-error.rs:15:20 + | +LL | asm!("{}", foo); + | ^^^ expected operand, clobber_abi, options, or additional template string + +error: expected `(`, found `foo` + --> $DIR/parse-error.rs:17:23 + | +LL | asm!("{}", in foo); + | ^^^ expected `(` + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:19:27 + | +LL | asm!("{}", in(reg foo)); + | ^^^ expected `)` + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:21:27 + | +LL | asm!("{}", in(reg)); + | ^ expected expression + +error: expected register class or explicit register + --> $DIR/parse-error.rs:23:26 + | +LL | asm!("{}", inout(=) foo => bar); + | ^ + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:25:37 + | +LL | asm!("{}", inout(reg) foo =>); + | ^ expected expression + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + --> $DIR/parse-error.rs:27:32 + | +LL | asm!("{}", in(reg) foo => bar); + | ^^ expected one of 7 possible tokens + +error: argument to `sym` must be a path expression + --> $DIR/parse-error.rs:29:24 + | +LL | asm!("{}", sym foo + bar); + | ^^^^^^^^^ + +error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:31:26 + | +LL | asm!("", options(foo)); + | ^^^ expected one of 9 possible tokens + +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:33:32 + | +LL | asm!("", options(nomem foo)); + | ^^^ expected one of `)` or `,` + +error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:35:33 + | +LL | asm!("", options(nomem, foo)); + | ^^^ expected one of 9 possible tokens + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:37:31 + | +LL | asm!("{}", options(), const foo); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:40:30 + | +LL | asm!("", clobber_abi(foo)); + | ^^^ not a string literal + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:42:34 + | +LL | asm!("", clobber_abi("C" foo)); + | ^^^ expected `)` + +error: expected `)`, found `,` + --> $DIR/parse-error.rs:44:33 + | +LL | asm!("", clobber_abi("C", foo)); + | ^ expected `)` + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:46:38 + | +LL | asm!("{}", clobber_abi("C"), const foo); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:49:29 + | +LL | asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:51:31 + | +LL | asm!("{}", options(), clobber_abi("C"), const foo); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi specified multiple times + --> $DIR/parse-error.rs:53:36 + | +LL | asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | clobber_abi previously specified here + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:55:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:55:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: explicit register arguments cannot have names + --> $DIR/parse-error.rs:60:18 + | +LL | asm!("", a = in("x0") foo); + | ^^^^^^^^^^^^^^^^ + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:62:35 + | +LL | asm!("{a}", in("x0") foo, a = const bar); + | ------------ ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:65:35 + | +LL | asm!("{a}", in("x0") foo, a = const bar); + | ------------ ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: positional arguments cannot follow named arguments or explicit register arguments + --> $DIR/parse-error.rs:68:35 + | +LL | asm!("{1}", in("x0") foo, const bar); + | ------------ ^^^^^^^^^ positional argument + | | + | explicit register argument + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` + --> $DIR/parse-error.rs:71:29 + | +LL | asm!("", options(), ""); + | ^^ expected one of 9 possible tokens + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:73:33 + | +LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); + | ^^^^ expected one of 9 possible tokens + +error: asm template must be a string literal + --> $DIR/parse-error.rs:75:14 + | +LL | asm!(format!("{{{}}}", 0), in(reg) foo); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:77:21 + | +LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:79:28 + | +LL | asm!("{}", in(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:81:31 + | +LL | asm!("{}", inout(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:83:35 + | +LL | asm!("{}", inlateout(reg) _); + | ^ + +error: requires at least a template string argument + --> $DIR/parse-error.rs:90:1 + | +LL | global_asm!(); + | ^^^^^^^^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:92:13 + | +LL | global_asm!(FOO); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:94:18 + | +LL | global_asm!("{}" FOO); + | ^^^ expected `,` + +error: expected operand, options, or additional template string + --> $DIR/parse-error.rs:96:19 + | +LL | global_asm!("{}", FOO); + | ^^^ expected operand, options, or additional template string + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:98:24 + | +LL | global_asm!("{}", const); + | ^ expected expression + +error: expected one of `,`, `.`, `?`, or an operator, found `FOO` + --> $DIR/parse-error.rs:100:30 + | +LL | global_asm!("{}", const(reg) FOO); + | ^^^ expected one of `,`, `.`, `?`, or an operator + +error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` + --> $DIR/parse-error.rs:102:25 + | +LL | global_asm!("", options(FOO)); + | ^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:104:25 + | +LL | global_asm!("", options(nomem FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:106:25 + | +LL | global_asm!("", options(nomem, FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:108:30 + | +LL | global_asm!("{}", options(), const FOO); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:110:29 + | +LL | global_asm!("", clobber_abi(FOO)); + | ^^^ not a string literal + +error: expected `)`, found `FOO` + --> $DIR/parse-error.rs:112:33 + | +LL | global_asm!("", clobber_abi("C" FOO)); + | ^^^ expected `)` + +error: expected `)`, found `,` + --> $DIR/parse-error.rs:114:32 + | +LL | global_asm!("", clobber_abi("C", FOO)); + | ^ expected `)` + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:116:37 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:116:19 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ^^^^^^^^^^^^^^^^ + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:119:28 + | +LL | global_asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:121:30 + | +LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi specified multiple times + --> $DIR/parse-error.rs:123:35 + | +LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | clobber_abi previously specified here + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:125:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:125:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: expected one of `clobber_abi`, `const`, or `options`, found `""` + --> $DIR/parse-error.rs:128:28 + | +LL | global_asm!("", options(), ""); + | ^^ expected one of `clobber_abi`, `const`, or `options` + +error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"` + --> $DIR/parse-error.rs:130:30 + | +LL | global_asm!("{}", const FOO, "{}", const FOO); + | ^^^^ expected one of `clobber_abi`, `const`, or `options` + +error: asm template must be a string literal + --> $DIR/parse-error.rs:132:13 + | +LL | global_asm!(format!("{{{}}}", 0), const FOO); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:134:20 + | +LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:37:37 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", options(), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:46:44 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", clobber_abi("C"), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:55:31 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:55:46 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:62:45 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("x0") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:65:45 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("x0") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:68:41 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{1}", in("x0") foo, const bar); + | ^^^ non-constant value + +error: aborting due to 66 previous errors + +For more information about this error, try `rustc --explain E0435`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/srcloc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/srcloc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/srcloc.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/srcloc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,121 @@ +// min-llvm-version: 10.0.1 +// only-aarch64 +// build-fail +// compile-flags: -Ccodegen-units=1 +#![feature(asm)] + +// Checks that inline asm errors are mapped to the correct line in the source code. + +fn main() { + unsafe { + asm!("invalid_instruction"); + //~^ ERROR: unrecognized instruction mnemonic + + asm!(" + invalid_instruction + "); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!(r#" + invalid_instruction + "#); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!(" + mov x0, x0 + invalid_instruction + mov x0, x0 + "); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!(r#" + mov x0, x0 + invalid_instruction + mov x0, x0 + "#); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!(concat!("invalid", "_", "instruction")); + //~^ ERROR: unrecognized instruction mnemonic + + asm!( + "invalid_instruction", + ); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0", + "invalid_instruction", + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0\n", + "invalid_instruction", + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0", + concat!("invalid", "_", "instruction"), + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!("mov x0", ", ", "x0"), + concat!("invalid", "_", "instruction"), + concat!("mov x0", ", ", "x0"), + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + // Make sure template strings get separated + asm!( + "invalid_instruction1", + "invalid_instruction2", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + ); + //~^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", + ), + ); + //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", "\n", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", "\n", + ), + ); + //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^ ERROR: unrecognized instruction mnemonic + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/srcloc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/srcloc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/srcloc.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/srcloc.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,278 @@ +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:11:15 + | +LL | asm!("invalid_instruction"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:15:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:20:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:26:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:33:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:38:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:42:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:48:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:55:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:62:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:69:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:76:14 + | +LL | "invalid_instruction1", + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:77:14 + | +LL | "invalid_instruction2", + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:83:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:83:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:92:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:92:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:107:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:107:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction4 + | ^ + +error: aborting due to 23 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/sym.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/sym.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/sym.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/sym.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,80 @@ +// min-llvm-version: 10.0.1 +// only-aarch64 +// only-linux +// run-pass + +#![feature(asm, thread_local)] + +extern "C" fn f1() -> i32 { + 111 +} + +// The compiler will generate a shim to hide the caller location parameter. +#[track_caller] +fn f2() -> i32 { + 222 +} + +macro_rules! call { + ($func:path) => { + unsafe { + let result: i32; + asm!("bl {}", sym $func, + out("w0") result, + out("x20") _, out("x21") _, out("x22") _, + out("x23") _, out("x24") _, out("x25") _, + out("x26") _, out("x27") _, out("x28") _, + ); + result + } + } +} + +macro_rules! static_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + // ADRP gives the address of a 4KB page from a PC-relative address + "adrp {out}, {sym}", + // We then add the remaining lower 12 bits + "add {out}, {out}, #:lo12:{sym}", + out = out(reg) result, + sym = sym $s); + result + } + } +} +macro_rules! static_tls_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + // Load the thread pointer register + "mrs {out}, TPIDR_EL0", + // Add the top 12 bits of the symbol's offset + "add {out}, {out}, :tprel_hi12:{sym}", + // And the bottom 12 bits + "add {out}, {out}, :tprel_lo12_nc:{sym}", + out = out(reg) result, + sym = sym $s + ); + result + } + } +} + +static S1: u32 = 111; +#[thread_local] +static S2: u32 = 222; + +fn main() { + assert_eq!(call!(f1), 111); + assert_eq!(call!(f2), 222); + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + std::thread::spawn(|| { + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + }).join().unwrap(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,84 @@ +// only-aarch64 + +#![feature(asm, repr_simd, never_type)] + +#[repr(simd)] +#[derive(Clone, Copy)] +struct SimdType(f32, f32, f32, f32); + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + //~^ ERROR use of possibly-uninitialized variable: `x` + let mut y: u64; + asm!("{}", inout(reg) y); + //~^ ERROR use of possibly-uninitialized variable: `y` + let _ = y; + + // Outputs require mutable places + + let v: Vec = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + asm!("{}", inout(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + + // Sym operands must point to a function or static + + const C: i32 = 0; + static S: i32 = 0; + asm!("{}", sym S); + asm!("{}", sym main); + asm!("{}", sym C); + //~^ ERROR asm `sym` operand must point to a fn or static + asm!("{}", sym x); + //~^ ERROR asm `sym` operand must point to a fn or static + + // Register operands must be Copy + + asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + //~^ ERROR arguments for inline assembly must be copyable + + // Register operands must be integers, floats, SIMD vectors, pointers or + // function pointers. + + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + asm!("{:v}", in(vreg) SimdType(0.0, 0.0, 0.0, 0.0)); + asm!("{}", in(reg) 0 as *const u8); + asm!("{}", in(reg) 0 as *mut u8); + asm!("{}", in(reg) main as fn()); + asm!("{}", in(reg) |x: i32| x); + //~^ ERROR cannot use value of type + asm!("{}", in(reg) vec![0]); + //~^ ERROR cannot use value of type `Vec` for inline assembly + asm!("{}", in(reg) (1, 2, 3)); + //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly + asm!("{}", in(reg) [1, 2, 3]); + //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly + + // Register inputs (but not outputs) allow references and function types + + let mut f = main; + let mut r = &mut 0; + asm!("{}", in(reg) f); + asm!("{}", inout(reg) f); + //~^ ERROR cannot use value of type `fn() {main}` for inline assembly + asm!("{}", in(reg) r); + asm!("{}", inout(reg) r); + //~^ ERROR cannot use value of type `&mut i32` for inline assembly + let _ = (f, r); + + // Type checks ignore never type + + let u: ! = unreachable!(); + asm!("{}", in(reg) u); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-2.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,103 @@ +error: arguments for inline assembly must be copyable + --> $DIR/type-check-2.rs:46:31 + | +LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `SimdNonCopy` does not implement the Copy trait + +error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly + --> $DIR/type-check-2.rs:58:28 + | +LL | asm!("{}", in(reg) |x: i32| x); + | ^^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `Vec` for inline assembly + --> $DIR/type-check-2.rs:60:28 + | +LL | asm!("{}", in(reg) vec![0]); + | ^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use value of type `(i32, i32, i32)` for inline assembly + --> $DIR/type-check-2.rs:62:28 + | +LL | asm!("{}", in(reg) (1, 2, 3)); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[i32; 3]` for inline assembly + --> $DIR/type-check-2.rs:64:28 + | +LL | asm!("{}", in(reg) [1, 2, 3]); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `fn() {main}` for inline assembly + --> $DIR/type-check-2.rs:72:31 + | +LL | asm!("{}", inout(reg) f); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `&mut i32` for inline assembly + --> $DIR/type-check-2.rs:75:31 + | +LL | asm!("{}", inout(reg) r); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: asm `sym` operand must point to a fn or static + --> $DIR/type-check-2.rs:39:24 + | +LL | asm!("{}", sym C); + | ^ + +error: asm `sym` operand must point to a fn or static + --> $DIR/type-check-2.rs:41:24 + | +LL | asm!("{}", sym x); + | ^ + +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/type-check-2.rs:17:28 + | +LL | asm!("{}", in(reg) x); + | ^ use of possibly-uninitialized `x` + +error[E0381]: use of possibly-uninitialized variable: `y` + --> $DIR/type-check-2.rs:20:9 + | +LL | asm!("{}", inout(reg) y); + | ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2.rs:28:29 + | +LL | let v: Vec = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +LL | asm!("{}", in(reg) v[0]); +LL | asm!("{}", out(reg) v[0]); + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2.rs:30:31 + | +LL | let v: Vec = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +... +LL | asm!("{}", inout(reg) v[0]); + | ^ cannot borrow as mutable + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0381, E0596. +For more information about an error, try `rustc --explain E0381`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-3.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-3.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,115 @@ +// only-aarch64 +// compile-flags: -C target-feature=+neon + +#![feature(asm, global_asm, repr_simd, stdsimd)] + +use std::arch::aarch64::float64x2_t; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct Simd256bit(f64, f64,f64, f64); + +fn main() { + let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) }; + let f64x4 = Simd256bit(0.0, 0.0, 0.0, 0.0); + + unsafe { + // Types must be listed in the register class. + + // Success cases + asm!("{:w}", in(reg) 0u8); + asm!("{:w}", in(reg) 0u16); + asm!("{:w}", in(reg) 0u32); + asm!("{:w}", in(reg) 0f32); + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + + asm!("{:b}", in(vreg) 0u8); + asm!("{:h}", in(vreg) 0u16); + asm!("{:s}", in(vreg) 0u32); + asm!("{:s}", in(vreg) 0f32); + asm!("{:d}", in(vreg) 0u64); + asm!("{:d}", in(vreg) 0f64); + asm!("{:q}", in(vreg) f64x2); + asm!("{:v}", in(vreg) f64x2); + + // Should be the same as vreg + asm!("{:q}", in(vreg_low16) f64x2); + + // Template modifiers of a different size to the argument are fine + asm!("{:w}", in(reg) 0u64); + asm!("{:x}", in(reg) 0u32); + asm!("{:b}", in(vreg) 0u64); + asm!("{:d}", in(vreg_low16) f64x2); + + + // Template modifier suggestions for sub-registers + + asm!("{}", in(reg) 0u8); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0u16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0f32); + //~^ WARN formatting may not be suitable for sub-register argument + + asm!("{}", in(vreg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg) 0f32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg) 0f64); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg_low16) 0f64); + //~^ WARN formatting may not be suitable for sub-register argument + + asm!("{0} {0}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{0} {0:x}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + + // Invalid registers + + asm!("{}", in(reg) 0i128); + //~^ ERROR type `i128` cannot be used with this register class + asm!("{}", in(reg) f64x2); + //~^ ERROR type `float64x2_t` cannot be used with this register class + asm!("{}", in(vreg) f64x4); + //~^ ERROR type `Simd256bit` cannot be used with this register class + + // Split inout operands must have compatible types + + let mut val_i16: i16; + let mut val_f32: f32; + let mut val_u32: u32; + let mut val_u64: u64; + let mut val_ptr: *mut u8; + asm!("{:x}", inout(reg) 0u16 => val_i16); + asm!("{:x}", inout(reg) 0u32 => val_f32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) 0u32 => val_ptr); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) main => val_u32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) 0u64 => val_ptr); + asm!("{:x}", inout(reg) main => val_u64); + } +} + +// Constants must be... constant + +static S: i32 = 1; +const fn const_foo(x: i32) -> i32 { + x +} +const fn const_bar(x: T) -> T { + x +} +global_asm!("{}", const S); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_foo(0)); +global_asm!("{}", const const_foo(S)); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_bar(0)); +global_asm!("{}", const const_bar(S)); +//~^ ERROR constants cannot refer to statics diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-3.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/aarch64/type-check-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,172 @@ +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:48:15 + | +LL | asm!("{}", in(reg) 0u8); + | ^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:50:15 + | +LL | asm!("{}", in(reg) 0u16); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:52:15 + | +LL | asm!("{}", in(reg) 0i32); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:54:15 + | +LL | asm!("{}", in(reg) 0f32); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:57:15 + | +LL | asm!("{}", in(vreg) 0i16); + | ^^ ---- for this argument + | + = help: use the `h` modifier to have the register formatted as `h0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:59:15 + | +LL | asm!("{}", in(vreg) 0f32); + | ^^ ---- for this argument + | + = help: use the `s` modifier to have the register formatted as `s0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:61:15 + | +LL | asm!("{}", in(vreg) 0f64); + | ^^ ---- for this argument + | + = help: use the `d` modifier to have the register formatted as `d0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:63:15 + | +LL | asm!("{}", in(vreg_low16) 0f64); + | ^^ ---- for this argument + | + = help: use the `d` modifier to have the register formatted as `d0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:66:15 + | +LL | asm!("{0} {0}", in(reg) 0i16); + | ^^^ ^^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:68:15 + | +LL | asm!("{0} {0:x}", in(reg) 0i16); + | ^^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +error: type `i128` cannot be used with this register class + --> $DIR/type-check-3.rs:73:28 + | +LL | asm!("{}", in(reg) 0i128); + | ^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `float64x2_t` cannot be used with this register class + --> $DIR/type-check-3.rs:75:28 + | +LL | asm!("{}", in(reg) f64x2); + | ^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `Simd256bit` cannot be used with this register class + --> $DIR/type-check-3.rs:77:29 + | +LL | asm!("{}", in(vreg) f64x4); + | ^^^^^ + | + = note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:88:33 + | +LL | asm!("{:x}", inout(reg) 0u32 => val_f32); + | ^^^^ ^^^^^^^ type `f32` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:90:33 + | +LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); + | ^^^^ ^^^^^^^ type `*mut u8` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:92:33 + | +LL | asm!("{:x}", inout(reg) main => val_u32); + | ^^^^ ^^^^^^^ type `u32` + | | + | type `fn()` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:108:25 + | +LL | global_asm!("{}", const S); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:111:35 + | +LL | global_asm!("{}", const const_foo(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:114:35 + | +LL | global_asm!("{}", const const_bar(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 9 previous errors; 10 warnings emitted + +For more information about this error, try `rustc --explain E0013`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-arch.mirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-arch.mirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-arch.mirunsafeck.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-arch.mirunsafeck.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,13 @@ --> $DIR/bad-arch.rs:22:9 | LL | asm!(""); - | ^^^^^^^^^ + | ^^^^^^^^ error[E0472]: inline assembly is unsupported on this target --> $DIR/bad-arch.rs:27:1 | LL | global_asm!(""); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: this error originates in the macro `global_asm` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-arch.thirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-arch.thirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-arch.thirunsafeck.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-arch.thirunsafeck.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,13 @@ --> $DIR/bad-arch.rs:22:9 | LL | asm!(""); - | ^^^^^^^^^ + | ^^^^^^^^ error[E0472]: inline assembly is unsupported on this target --> $DIR/bad-arch.rs:27:1 | LL | global_asm!(""); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: this error originates in the macro `global_asm` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-options.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-options.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-options.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-options.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -// only-x86_64 - -#![feature(asm, global_asm)] - -fn main() { - let mut foo = 0; - unsafe { - asm!("", options(nomem, readonly)); - //~^ ERROR the `nomem` and `readonly` options are mutually exclusive - asm!("", options(pure, nomem, noreturn)); - //~^ ERROR the `pure` and `noreturn` options are mutually exclusive - //~^^ ERROR asm with the `pure` option must have at least one output - asm!("{}", in(reg) foo, options(pure, nomem)); - //~^ ERROR asm with the `pure` option must have at least one output - asm!("{}", out(reg) foo, options(noreturn)); - //~^ ERROR asm outputs are not allowed with the `noreturn` option - } - - unsafe { - asm!("", clobber_abi("foo")); - //~^ ERROR invalid ABI for `clobber_abi` - asm!("{}", out(reg) foo, clobber_abi("C")); - //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs - asm!("", out("eax") foo, clobber_abi("C")); - } -} - -global_asm!("", options(nomem)); -//~^ ERROR expected one of -global_asm!("", options(readonly)); -//~^ ERROR expected one of -global_asm!("", options(noreturn)); -//~^ ERROR expected one of -global_asm!("", options(pure)); -//~^ ERROR expected one of -global_asm!("", options(nostack)); -//~^ ERROR expected one of -global_asm!("", options(preserves_flags)); -//~^ ERROR expected one of diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-options.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-options.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-options.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-options.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -error: the `nomem` and `readonly` options are mutually exclusive - --> $DIR/bad-options.rs:8:18 - | -LL | asm!("", options(nomem, readonly)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: the `pure` and `noreturn` options are mutually exclusive - --> $DIR/bad-options.rs:10:18 - | -LL | asm!("", options(pure, nomem, noreturn)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: asm with the `pure` option must have at least one output - --> $DIR/bad-options.rs:10:18 - | -LL | asm!("", options(pure, nomem, noreturn)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: asm with the `pure` option must have at least one output - --> $DIR/bad-options.rs:13:33 - | -LL | asm!("{}", in(reg) foo, options(pure, nomem)); - | ^^^^^^^^^^^^^^^^^^^^ - -error: asm outputs are not allowed with the `noreturn` option - --> $DIR/bad-options.rs:15:20 - | -LL | asm!("{}", out(reg) foo, options(noreturn)); - | ^^^^^^^^^^^^ - -error: asm with `clobber_abi` must specify explicit registers for outputs - --> $DIR/bad-options.rs:22:20 - | -LL | asm!("{}", out(reg) foo, clobber_abi("C")); - | ^^^^^^^^^^^^ ---------------- clobber_abi - | | - | generic outputs - -error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/bad-options.rs:28:25 - | -LL | global_asm!("", options(nomem)); - | ^^^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` - --> $DIR/bad-options.rs:30:25 - | -LL | global_asm!("", options(readonly)); - | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` - --> $DIR/bad-options.rs:32:25 - | -LL | global_asm!("", options(noreturn)); - | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected one of `)`, `att_syntax`, or `raw`, found `pure` - --> $DIR/bad-options.rs:34:25 - | -LL | global_asm!("", options(pure)); - | ^^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` - --> $DIR/bad-options.rs:36:25 - | -LL | global_asm!("", options(nostack)); - | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` - --> $DIR/bad-options.rs:38:25 - | -LL | global_asm!("", options(preserves_flags)); - | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` - -error: invalid ABI for `clobber_abi` - --> $DIR/bad-options.rs:20:18 - | -LL | asm!("", clobber_abi("foo")); - | ^^^^^^^^^^^^^^^^^^ - | - = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` - -error: aborting due to 13 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-reg.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-reg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-reg.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-reg.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -// only-x86_64 -// compile-flags: -C target-feature=+avx2 - -#![feature(asm)] - -fn main() { - let mut foo = 0; - let mut bar = 0; - unsafe { - // Bad register/register class - - asm!("{}", in(foo) foo); - //~^ ERROR invalid register class `foo`: unknown register class - asm!("", in("foo") foo); - //~^ ERROR invalid register `foo`: unknown register - asm!("{:z}", in(reg) foo); - //~^ ERROR invalid asm template modifier for this register class - asm!("{:r}", in(xmm_reg) foo); - //~^ ERROR invalid asm template modifier for this register class - asm!("{:a}", const 0); - //~^ ERROR asm template modifiers are not allowed for `const` arguments - asm!("{:a}", sym main); - //~^ ERROR asm template modifiers are not allowed for `sym` arguments - asm!("{}", in(zmm_reg) foo); - //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature - asm!("", in("zmm0") foo); - //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature - asm!("", in("ebp") foo); - //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand - asm!("", in("rsp") foo); - //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand - asm!("", in("ip") foo); - //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand - asm!("", in("k0") foo); - //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand - asm!("", in("ah") foo); - //~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand - - asm!("", in("st(2)") foo); - //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output - asm!("", in("mm0") foo); - //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output - asm!("", out("st(2)") _); - asm!("", out("mm0") _); - asm!("{}", in(x87_reg) foo); - //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output - asm!("{}", in(mmx_reg) foo); - //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output - asm!("{}", out(x87_reg) _); - //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output - asm!("{}", out(mmx_reg) _); - //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output - - // Explicit register conflicts - // (except in/lateout which don't conflict) - - asm!("", in("eax") foo, in("al") bar); - //~^ ERROR register `al` conflicts with register `ax` - asm!("", in("rax") foo, out("rax") bar); - //~^ ERROR register `ax` conflicts with register `ax` - asm!("", in("al") foo, lateout("al") bar); - asm!("", in("xmm0") foo, in("ymm0") bar); - //~^ ERROR register `ymm0` conflicts with register `xmm0` - asm!("", in("xmm0") foo, out("ymm0") bar); - //~^ ERROR register `ymm0` conflicts with register `xmm0` - asm!("", in("xmm0") foo, lateout("ymm0") bar); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-reg.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-reg.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-reg.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-reg.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,172 +0,0 @@ -error: invalid register class `foo`: unknown register class - --> $DIR/bad-reg.rs:12:20 - | -LL | asm!("{}", in(foo) foo); - | ^^^^^^^^^^^ - -error: invalid register `foo`: unknown register - --> $DIR/bad-reg.rs:14:18 - | -LL | asm!("", in("foo") foo); - | ^^^^^^^^^^^^^ - -error: invalid asm template modifier for this register class - --> $DIR/bad-reg.rs:16:15 - | -LL | asm!("{:z}", in(reg) foo); - | ^^^^ ----------- argument - | | - | template modifier - | - = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r` - -error: invalid asm template modifier for this register class - --> $DIR/bad-reg.rs:18:15 - | -LL | asm!("{:r}", in(xmm_reg) foo); - | ^^^^ --------------- argument - | | - | template modifier - | - = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z` - -error: asm template modifiers are not allowed for `const` arguments - --> $DIR/bad-reg.rs:20:15 - | -LL | asm!("{:a}", const 0); - | ^^^^ ------- argument - | | - | template modifier - -error: asm template modifiers are not allowed for `sym` arguments - --> $DIR/bad-reg.rs:22:15 - | -LL | asm!("{:a}", sym main); - | ^^^^ -------- argument - | | - | template modifier - -error: register class `zmm_reg` requires the `avx512f` target feature - --> $DIR/bad-reg.rs:24:20 - | -LL | asm!("{}", in(zmm_reg) foo); - | ^^^^^^^^^^^^^^^ - -error: register class `zmm_reg` requires the `avx512f` target feature - --> $DIR/bad-reg.rs:26:18 - | -LL | asm!("", in("zmm0") foo); - | ^^^^^^^^^^^^^^ - -error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:28:18 - | -LL | asm!("", in("ebp") foo); - | ^^^^^^^^^^^^^ - -error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:30:18 - | -LL | asm!("", in("rsp") foo); - | ^^^^^^^^^^^^^ - -error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 - | -LL | asm!("", in("ip") foo); - | ^^^^^^^^^^^^ - -error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:34:18 - | -LL | asm!("", in("k0") foo); - | ^^^^^^^^^^^^ - -error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64 - --> $DIR/bad-reg.rs:36:18 - | -LL | asm!("", in("ah") foo); - | ^^^^^^^^^^^^ - -error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:39:18 - | -LL | asm!("", in("st(2)") foo); - | ^^^^^^^^^^^^^^^ - -error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:41:18 - | -LL | asm!("", in("mm0") foo); - | ^^^^^^^^^^^^^ - -error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:45:20 - | -LL | asm!("{}", in(x87_reg) foo); - | ^^^^^^^^^^^^^^^ - -error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:47:20 - | -LL | asm!("{}", in(mmx_reg) foo); - | ^^^^^^^^^^^^^^^ - -error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:49:20 - | -LL | asm!("{}", out(x87_reg) _); - | ^^^^^^^^^^^^^^ - -error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:51:20 - | -LL | asm!("{}", out(mmx_reg) _); - | ^^^^^^^^^^^^^^ - -error: register `al` conflicts with register `ax` - --> $DIR/bad-reg.rs:57:33 - | -LL | asm!("", in("eax") foo, in("al") bar); - | ------------- ^^^^^^^^^^^^ register `al` - | | - | register `ax` - -error: register `ax` conflicts with register `ax` - --> $DIR/bad-reg.rs:59:33 - | -LL | asm!("", in("rax") foo, out("rax") bar); - | ------------- ^^^^^^^^^^^^^^ register `ax` - | | - | register `ax` - | -help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:59:18 - | -LL | asm!("", in("rax") foo, out("rax") bar); - | ^^^^^^^^^^^^^ - -error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:62:34 - | -LL | asm!("", in("xmm0") foo, in("ymm0") bar); - | -------------- ^^^^^^^^^^^^^^ register `ymm0` - | | - | register `xmm0` - -error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:64:34 - | -LL | asm!("", in("xmm0") foo, out("ymm0") bar); - | -------------- ^^^^^^^^^^^^^^^ register `ymm0` - | | - | register `xmm0` - | -help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:64:18 - | -LL | asm!("", in("xmm0") foo, out("ymm0") bar); - | ^^^^^^^^^^^^^^ - -error: aborting due to 23 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,187 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:15 + | +LL | asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:48:15 + | +LL | asm!("{}", in("x0") foo); + | ^^ ------------ explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:48:20 + | +LL | asm!("{}", in("x0") foo); + | ^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:52:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:58:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:60:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:60:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:63:14 + | +LL | global_asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:65:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:68:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:68:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:71:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:73:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: aborting due to 21 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,187 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:15 + | +LL | asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:48:15 + | +LL | asm!("{}", in("x0") foo); + | ^^ ------------ explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:48:20 + | +LL | asm!("{}", in("x0") foo); + | ^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:52:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:58:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:60:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:60:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:63:14 + | +LL | global_asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:65:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:68:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:68:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:71:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:73:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: aborting due to 21 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.mirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.mirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.mirunsafeck.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.mirunsafeck.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:10:15 - | -LL | asm!("{}"); - | ^^ from here - | - = note: no arguments were given - -error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:12:15 - | -LL | asm!("{1}", in(reg) foo); - | ^^^ from here - | - = note: there is 1 argument - -error: argument never used - --> $DIR/bad-template.rs:12:21 - | -LL | asm!("{1}", in(reg) foo); - | ^^^^^^^^^^^ argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` - -error: there is no argument named `a` - --> $DIR/bad-template.rs:15:15 - | -LL | asm!("{a}"); - | ^^^ - -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:17:15 - | -LL | asm!("{}", a = in(reg) foo); - | ^^ --------------- named argument - | | - | from here - | - = note: no positional arguments were given -note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:17:20 - | -LL | asm!("{}", a = in(reg) foo); - | ^^^^^^^^^^^^^^^ - -error: named argument never used - --> $DIR/bad-template.rs:17:20 - | -LL | asm!("{}", a = in(reg) foo); - | ^^^^^^^^^^^^^^^ named argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` - -error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:20:15 - | -LL | asm!("{1}", a = in(reg) foo); - | ^^^ from here - | - = note: no positional arguments were given - -error: named argument never used - --> $DIR/bad-template.rs:20:21 - | -LL | asm!("{1}", a = in(reg) foo); - | ^^^^^^^^^^^^^^^ named argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` - -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:23:15 - | -LL | asm!("{}", in("eax") foo); - | ^^ ------------- explicit register argument - | | - | from here - | - = note: no positional arguments were given -note: explicit register arguments cannot be used in the asm template - --> $DIR/bad-template.rs:23:20 - | -LL | asm!("{}", in("eax") foo); - | ^^^^^^^^^^^^^ - -error: asm template modifier must be a single character - --> $DIR/bad-template.rs:25:17 - | -LL | asm!("{:foo}", in(reg) foo); - | ^^^ - -error: multiple unused asm arguments - --> $DIR/bad-template.rs:27:18 - | -LL | asm!("", in(reg) 0, in(reg) 1); - | ^^^^^^^^^ ^^^^^^^^^ argument never used - | | - | argument never used - | - = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` - -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:33:14 - | -LL | global_asm!("{}"); - | ^^ from here - | - = note: no arguments were given - -error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:35:14 - | -LL | global_asm!("{1}", const FOO); - | ^^^ from here - | - = note: there is 1 argument - -error: argument never used - --> $DIR/bad-template.rs:35:20 - | -LL | global_asm!("{1}", const FOO); - | ^^^^^^^^^ argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` - -error: there is no argument named `a` - --> $DIR/bad-template.rs:38:14 - | -LL | global_asm!("{a}"); - | ^^^ - -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:40:14 - | -LL | global_asm!("{}", a = const FOO); - | ^^ ------------- named argument - | | - | from here - | - = note: no positional arguments were given -note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:40:19 - | -LL | global_asm!("{}", a = const FOO); - | ^^^^^^^^^^^^^ - -error: named argument never used - --> $DIR/bad-template.rs:40:19 - | -LL | global_asm!("{}", a = const FOO); - | ^^^^^^^^^^^^^ named argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` - -error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:43:14 - | -LL | global_asm!("{1}", a = const FOO); - | ^^^ from here - | - = note: no positional arguments were given - -error: named argument never used - --> $DIR/bad-template.rs:43:20 - | -LL | global_asm!("{1}", a = const FOO); - | ^^^^^^^^^^^^^ named argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` - -error: asm template modifier must be a single character - --> $DIR/bad-template.rs:46:16 - | -LL | global_asm!("{:foo}", const FOO); - | ^^^ - -error: multiple unused asm arguments - --> $DIR/bad-template.rs:48:17 - | -LL | global_asm!("", const FOO, const FOO); - | ^^^^^^^^^ ^^^^^^^^^ argument never used - | | - | argument never used - | - = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` - -error: aborting due to 21 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,29 @@ -// only-x86_64 -// revisions: mirunsafeck thirunsafeck -// [thirunsafeck]compile-flags: -Z thir-unsafeck +// revisions: x86_64_mirunsafeck aarch64_mirunsafeck x86_64_thirunsafeck aarch64_thirunsafeck -#![feature(asm, global_asm)] +// [x86_64_thirunsafeck] compile-flags: -Z thir-unsafeck --target x86_64-unknown-linux-gnu +// [aarch64_thirunsafeck] compile-flags: -Z thir-unsafeck --target aarch64-unknown-linux-gnu +// [x86_64_mirunsafeck] compile-flags: --target x86_64-unknown-linux-gnu +// [aarch64_mirunsafeck] compile-flags: --target aarch64-unknown-linux-gnu + +// [x86_64_thirunsafeck] needs-llvm-components: x86 +// [x86_64_mirunsafeck] needs-llvm-components: x86 +// [aarch64_thirunsafeck] needs-llvm-components: aarch64 +// [aarch64_mirunsafeck] needs-llvm-components: aarch64 + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! global_asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} fn main() { let mut foo = 0; @@ -20,8 +41,12 @@ asm!("{1}", a = in(reg) foo); //~^ ERROR invalid reference to argument at index 1 //~^^ ERROR named argument never used + #[cfg(any(x86_64_thirunsafeck, x86_64_mirunsafeck))] asm!("{}", in("eax") foo); - //~^ ERROR invalid reference to argument at index 0 + //[x86_64_thirunsafeck,x86_64_mirunsafeck]~^ ERROR invalid reference to argument at index 0 + #[cfg(any(aarch64_thirunsafeck, aarch64_mirunsafeck))] + asm!("{}", in("x0") foo); + //[aarch64_thirunsafeck,aarch64_mirunsafeck]~^ ERROR invalid reference to argument at index 0 asm!("{:foo}", in(reg) foo); //~^ ERROR asm template modifier must be a single character asm!("", in(reg) 0, in(reg) 1); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.thirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.thirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.thirunsafeck.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.thirunsafeck.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:10:15 - | -LL | asm!("{}"); - | ^^ from here - | - = note: no arguments were given - -error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:12:15 - | -LL | asm!("{1}", in(reg) foo); - | ^^^ from here - | - = note: there is 1 argument - -error: argument never used - --> $DIR/bad-template.rs:12:21 - | -LL | asm!("{1}", in(reg) foo); - | ^^^^^^^^^^^ argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` - -error: there is no argument named `a` - --> $DIR/bad-template.rs:15:15 - | -LL | asm!("{a}"); - | ^^^ - -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:17:15 - | -LL | asm!("{}", a = in(reg) foo); - | ^^ --------------- named argument - | | - | from here - | - = note: no positional arguments were given -note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:17:20 - | -LL | asm!("{}", a = in(reg) foo); - | ^^^^^^^^^^^^^^^ - -error: named argument never used - --> $DIR/bad-template.rs:17:20 - | -LL | asm!("{}", a = in(reg) foo); - | ^^^^^^^^^^^^^^^ named argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` - -error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:20:15 - | -LL | asm!("{1}", a = in(reg) foo); - | ^^^ from here - | - = note: no positional arguments were given - -error: named argument never used - --> $DIR/bad-template.rs:20:21 - | -LL | asm!("{1}", a = in(reg) foo); - | ^^^^^^^^^^^^^^^ named argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` - -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:23:15 - | -LL | asm!("{}", in("eax") foo); - | ^^ ------------- explicit register argument - | | - | from here - | - = note: no positional arguments were given -note: explicit register arguments cannot be used in the asm template - --> $DIR/bad-template.rs:23:20 - | -LL | asm!("{}", in("eax") foo); - | ^^^^^^^^^^^^^ - -error: asm template modifier must be a single character - --> $DIR/bad-template.rs:25:17 - | -LL | asm!("{:foo}", in(reg) foo); - | ^^^ - -error: multiple unused asm arguments - --> $DIR/bad-template.rs:27:18 - | -LL | asm!("", in(reg) 0, in(reg) 1); - | ^^^^^^^^^ ^^^^^^^^^ argument never used - | | - | argument never used - | - = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` - -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:33:14 - | -LL | global_asm!("{}"); - | ^^ from here - | - = note: no arguments were given - -error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:35:14 - | -LL | global_asm!("{1}", const FOO); - | ^^^ from here - | - = note: there is 1 argument - -error: argument never used - --> $DIR/bad-template.rs:35:20 - | -LL | global_asm!("{1}", const FOO); - | ^^^^^^^^^ argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` - -error: there is no argument named `a` - --> $DIR/bad-template.rs:38:14 - | -LL | global_asm!("{a}"); - | ^^^ - -error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:40:14 - | -LL | global_asm!("{}", a = const FOO); - | ^^ ------------- named argument - | | - | from here - | - = note: no positional arguments were given -note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:40:19 - | -LL | global_asm!("{}", a = const FOO); - | ^^^^^^^^^^^^^ - -error: named argument never used - --> $DIR/bad-template.rs:40:19 - | -LL | global_asm!("{}", a = const FOO); - | ^^^^^^^^^^^^^ named argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` - -error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:43:14 - | -LL | global_asm!("{1}", a = const FOO); - | ^^^ from here - | - = note: no positional arguments were given - -error: named argument never used - --> $DIR/bad-template.rs:43:20 - | -LL | global_asm!("{1}", a = const FOO); - | ^^^^^^^^^^^^^ named argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` - -error: asm template modifier must be a single character - --> $DIR/bad-template.rs:46:16 - | -LL | global_asm!("{:foo}", const FOO); - | ^^^ - -error: multiple unused asm arguments - --> $DIR/bad-template.rs:48:17 - | -LL | global_asm!("", const FOO, const FOO); - | ^^^^^^^^^ ^^^^^^^^^ argument never used - | | - | argument never used - | - = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` - -error: aborting due to 21 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,187 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:15 + | +LL | asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:45:15 + | +LL | asm!("{}", in("eax") foo); + | ^^ ------------- explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:45:20 + | +LL | asm!("{}", in("eax") foo); + | ^^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:52:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:58:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:60:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:60:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:63:14 + | +LL | global_asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:65:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:68:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:68:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:71:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:73:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: aborting due to 21 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,187 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:15 + | +LL | asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:45:15 + | +LL | asm!("{}", in("eax") foo); + | ^^ ------------- explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:45:20 + | +LL | asm!("{}", in("eax") foo); + | ^^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:52:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:58:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:60:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:60:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:63:14 + | +LL | global_asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:65:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:68:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:68:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:71:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:73:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: aborting due to 21 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/const.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/const.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/const.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/const.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -// min-llvm-version: 10.0.1 -// only-x86_64 -// run-pass -// revisions: mirunsafeck thirunsafeck -// [thirunsafeck]compile-flags: -Z thir-unsafeck - -#![feature(asm, global_asm)] - -fn const_generic() -> usize { - unsafe { - let a: usize; - asm!("mov {}, {}", out(reg) a, const X); - a - } -} - -const fn constfn(x: usize) -> usize { - x -} - -fn main() { - unsafe { - let a: usize; - asm!("mov {}, {}", out(reg) a, const 5); - assert_eq!(a, 5); - - let b: usize; - asm!("mov {}, {}", out(reg) b, const constfn(5)); - assert_eq!(b, 5); - - let c: usize; - asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5)); - assert_eq!(c, 10); - } - - let d = const_generic::<5>(); - assert_eq!(d, 5); -} - -global_asm!("mov eax, {}", const 5); -global_asm!("mov eax, {}", const constfn(5)); -global_asm!("mov eax, {}", const constfn(5) + constfn(5)); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.fixed 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.fixed 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -// only-x86_64 -// run-rustfix - -#![feature(asm, global_asm)] - -fn main() { - unsafe { - asm!("", options(nomem, )); - //~^ ERROR the `nomem` option was already provided - asm!("", options(att_syntax, )); - //~^ ERROR the `att_syntax` option was already provided - asm!("", options(nostack, att_syntax), options()); - //~^ ERROR the `nostack` option was already provided - asm!("", options(nostack, ), options(), options()); - //~^ ERROR the `nostack` option was already provided - //~| ERROR the `nostack` option was already provided - //~| ERROR the `nostack` option was already provided - asm!( - "", - options(nomem, noreturn), - options(att_syntax, ), //~ ERROR the `noreturn` option was already provided - options( nostack), //~ ERROR the `nomem` option was already provided - options(), //~ ERROR the `noreturn` option was already provided - ); - } -} - -global_asm!("", options(att_syntax, )); -//~^ ERROR the `att_syntax` option was already provided diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -// only-x86_64 -// run-rustfix - -#![feature(asm, global_asm)] - -fn main() { - unsafe { - asm!("", options(nomem, nomem)); - //~^ ERROR the `nomem` option was already provided - asm!("", options(att_syntax, att_syntax)); - //~^ ERROR the `att_syntax` option was already provided - asm!("", options(nostack, att_syntax), options(nostack)); - //~^ ERROR the `nostack` option was already provided - asm!("", options(nostack, nostack), options(nostack), options(nostack)); - //~^ ERROR the `nostack` option was already provided - //~| ERROR the `nostack` option was already provided - //~| ERROR the `nostack` option was already provided - asm!( - "", - options(nomem, noreturn), - options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided - options(nomem, nostack), //~ ERROR the `nomem` option was already provided - options(noreturn), //~ ERROR the `noreturn` option was already provided - ); - } -} - -global_asm!("", options(att_syntax, att_syntax)); -//~^ ERROR the `att_syntax` option was already provided diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/duplicate-options.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -error: the `nomem` option was already provided - --> $DIR/duplicate-options.rs:8:33 - | -LL | asm!("", options(nomem, nomem)); - | ^^^^^ this option was already provided - -error: the `att_syntax` option was already provided - --> $DIR/duplicate-options.rs:10:38 - | -LL | asm!("", options(att_syntax, att_syntax)); - | ^^^^^^^^^^ this option was already provided - -error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:12:56 - | -LL | asm!("", options(nostack, att_syntax), options(nostack)); - | ^^^^^^^ this option was already provided - -error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:14:35 - | -LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ this option was already provided - -error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:14:53 - | -LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ this option was already provided - -error: the `nostack` option was already provided - --> $DIR/duplicate-options.rs:14:71 - | -LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); - | ^^^^^^^ this option was already provided - -error: the `noreturn` option was already provided - --> $DIR/duplicate-options.rs:21:33 - | -LL | options(att_syntax, noreturn), - | ^^^^^^^^ this option was already provided - -error: the `nomem` option was already provided - --> $DIR/duplicate-options.rs:22:21 - | -LL | options(nomem, nostack), - | ^^^^^ this option was already provided - -error: the `noreturn` option was already provided - --> $DIR/duplicate-options.rs:23:21 - | -LL | options(noreturn), - | ^^^^^^^^ this option was already provided - -error: the `att_syntax` option was already provided - --> $DIR/duplicate-options.rs:28:37 - | -LL | global_asm!("", options(att_syntax, att_syntax)); - | ^^^^^^^^^^ this option was already provided - -error: aborting due to 10 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/interpolated-idents.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/interpolated-idents.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/interpolated-idents.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/interpolated-idents.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -// only-x86_64 - -#![feature(asm)] - -macro_rules! m { - ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident - $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident - $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => { - unsafe { - asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, - //~^ ERROR asm outputs are not allowed with the `noreturn` option - const x, sym x, - $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); - //~^ ERROR the `nomem` and `readonly` options are mutually exclusive - //~| ERROR the `pure` and `noreturn` options are mutually exclusive - } - }; -} - -fn main() { - m!(in out lateout inout inlateout const sym - pure nomem readonly preserves_flags - noreturn nostack att_syntax options); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/interpolated-idents.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/interpolated-idents.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/interpolated-idents.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/interpolated-idents.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -error: the `nomem` and `readonly` options are mutually exclusive - --> $DIR/interpolated-idents.rs:13:13 - | -LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | / m!(in out lateout inout inlateout const sym -LL | | pure nomem readonly preserves_flags -LL | | noreturn nostack att_syntax options); - | |____________________________________________- in this macro invocation - | - = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: the `pure` and `noreturn` options are mutually exclusive - --> $DIR/interpolated-idents.rs:13:13 - | -LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | / m!(in out lateout inout inlateout const sym -LL | | pure nomem readonly preserves_flags -LL | | noreturn nostack att_syntax options); - | |____________________________________________- in this macro invocation - | - = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: asm outputs are not allowed with the `noreturn` option - --> $DIR/interpolated-idents.rs:10:32 - | -LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, - | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ -... -LL | m!(in out lateout inout inlateout const sym - | _____- - | |_____| - | |_____| - | |_____| - | | -LL | | pure nomem readonly preserves_flags -LL | | noreturn nostack att_syntax options); - | | - - | |____________________________________________| - | |____________________________________________in this macro invocation - | |____________________________________________in this macro invocation - | |____________________________________________in this macro invocation - | in this macro invocation - | - = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 3 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-72570.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-72570.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-72570.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-72570.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // compile-flags: -Zsave-analysis -// only-x86_64 +// needs-asm-support // Also test for #72960 #![feature(asm)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-82869.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-82869.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-82869.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-82869.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -// only-x86_64 -// Make sure rustc doesn't ICE on asm! for a foreign architecture. - -#![feature(asm)] -#![crate_type = "rlib"] - -pub unsafe fn aarch64(a: f64, b: f64) -> f64 { - let c; - asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { - || {}; - b - }); - //~^^^^ invalid register class - //~^^^^^ invalid register class - //~^^^^^^ invalid register - c -} - -pub unsafe fn x86(a: f64, b: f64) -> f64 { - let c; - asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b); - c -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-82869.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-82869.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-82869.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-82869.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -error: invalid register class `vreg`: unknown register class - --> $DIR/issue-82869.rs:9:32 - | -LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { - | ^^^^^^^^^^^ - -error: invalid register class `vreg`: unknown register class - --> $DIR/issue-82869.rs:9:45 - | -LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { - | ^^^^^^^^^^ - -error: invalid register `d0`: unknown register - --> $DIR/issue-82869.rs:9:57 - | -LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { - | _________________________________________________________^ -LL | | || {}; -LL | | b -LL | | }); - | |_____^ - -error: aborting due to 3 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-87802.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-87802.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-87802.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-87802.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 // Make sure rustc doesn't ICE on asm! when output type is !. #![feature(asm)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-87802.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-87802.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-87802.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-87802.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error: cannot use value of type `!` for inline assembly - --> $DIR/issue-87802.rs:9:36 + --> $DIR/issue-87802.rs:12:36 | LL | asm!("/* {0} */", out(reg) x); | ^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-89305.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-89305.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-89305.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-89305.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// Regression test for #89305, where a variable was erroneously reported +// as both unused and possibly-uninitialized. + +// check-pass + +#![feature(asm)] +#![warn(unused)] + +fn main() { + unsafe { + let x: () = asm!("nop"); + //~^ WARNING: unused variable: `x` + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-89305.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-89305.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/issue-89305.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/issue-89305.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +warning: unused variable: `x` + --> $DIR/issue-89305.rs:11:13 + | +LL | let x: () = asm!("nop"); + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/issue-89305.rs:7:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-ffi.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-ffi.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-ffi.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-ffi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // check-pass -// only-x86_64 +// needs-asm-support #![feature(asm)] #![feature(naked_functions)] #![crate_type = "lib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,8 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 + #![feature(asm)] #![feature(llvm_asm)] #![feature(naked_functions)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,35 +1,35 @@ error: asm with the `pure` option must have at least one output - --> $DIR/naked-functions.rs:127:14 + --> $DIR/naked-functions.rs:131:14 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:14:5 + --> $DIR/naked-functions.rs:18:5 | LL | mut a: u32, | ^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:16:5 + --> $DIR/naked-functions.rs:20:5 | LL | &b: &i32, | ^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:18:6 + --> $DIR/naked-functions.rs:22:6 | LL | (None | Some(_)): Option>, | ^^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:20:5 + --> $DIR/naked-functions.rs:24:5 | LL | P { x, y }: P, | ^^^^^^^^^^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:30:5 + --> $DIR/naked-functions.rs:34:5 | LL | a + 1 | ^ @@ -37,7 +37,7 @@ = help: follow the calling convention in asm block to use parameters warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:27:1 + --> $DIR/naked-functions.rs:31:1 | LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 { LL | | @@ -53,7 +53,7 @@ = note: for more information, see issue #32408 error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:36:31 + --> $DIR/naked-functions.rs:40:31 | LL | asm!("/* {0} */", in(reg) a, options(noreturn)); | ^ @@ -61,7 +61,7 @@ = help: follow the calling convention in asm block to use parameters warning: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:36:23 + --> $DIR/naked-functions.rs:40:23 | LL | asm!("/* {0} */", in(reg) a, options(noreturn)); | ^^^^^^^^^ @@ -70,7 +70,7 @@ = note: for more information, see issue #32408 warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:43:1 + --> $DIR/naked-functions.rs:47:1 | LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { LL | | @@ -84,7 +84,7 @@ = note: for more information, see issue #32408 warning: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:63:10 + --> $DIR/naked-functions.rs:67:10 | LL | in(reg) a, | ^^^^^^^^^ @@ -102,7 +102,7 @@ = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:60:5 + --> $DIR/naked-functions.rs:64:5 | LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */", LL | | @@ -111,13 +111,13 @@ ... | LL | | sym G, LL | | ); - | |______^ + | |_____^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:50:1 + --> $DIR/naked-functions.rs:54:1 | LL | / pub unsafe extern "C" fn unsupported_operands() { LL | | @@ -141,7 +141,7 @@ = note: for more information, see issue #32408 warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:76:1 + --> $DIR/naked-functions.rs:80:1 | LL | / pub extern "C" fn missing_assembly() { LL | | @@ -153,34 +153,34 @@ = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:85:5 + --> $DIR/naked-functions.rs:89:5 | LL | asm!(""); - | ^^^^^^^^^ + | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:88:5 + --> $DIR/naked-functions.rs:92:5 | LL | asm!(""); - | ^^^^^^^^^ + | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:91:5 + --> $DIR/naked-functions.rs:95:5 | LL | asm!(""); - | ^^^^^^^^^ + | ^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:82:1 + --> $DIR/naked-functions.rs:86:1 | LL | / pub extern "C" fn too_many_asm_blocks() { LL | | @@ -188,13 +188,13 @@ LL | | asm!(""); ... | LL | | asm!(""); - | | --------- multiple asm blocks are unsupported in naked functions + | | -------- multiple asm blocks are unsupported in naked functions ... | LL | | asm!(""); - | | --------- multiple asm blocks are unsupported in naked functions + | | -------- multiple asm blocks are unsupported in naked functions ... | LL | | asm!("", options(noreturn)); - | | ---------------------------- multiple asm blocks are unsupported in naked functions + | | --------------------------- multiple asm blocks are unsupported in naked functions LL | | } | |_^ | @@ -202,7 +202,7 @@ = note: for more information, see issue #32408 error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:102:11 + --> $DIR/naked-functions.rs:106:11 | LL | *&y | ^ @@ -210,7 +210,7 @@ = help: follow the calling convention in asm block to use parameters warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:99:5 + --> $DIR/naked-functions.rs:103:5 | LL | / pub extern "C" fn inner(y: usize) -> usize { LL | | @@ -225,10 +225,10 @@ = note: for more information, see issue #32408 warning: the LLVM-style inline assembly is unsupported in naked functions - --> $DIR/naked-functions.rs:112:5 + --> $DIR/naked-functions.rs:116:5 | LL | llvm_asm!(""); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 @@ -236,7 +236,7 @@ = note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info) warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:109:1 + --> $DIR/naked-functions.rs:113:1 | LL | / unsafe extern "C" fn llvm() -> ! { LL | | @@ -252,34 +252,34 @@ = note: for more information, see issue #32408 warning: asm options unsupported in naked functions: `nomem`, `preserves_flags` - --> $DIR/naked-functions.rs:120:5 + --> $DIR/naked-functions.rs:124:5 | LL | asm!("", options(nomem, preserves_flags, noreturn)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly` - --> $DIR/naked-functions.rs:127:5 + --> $DIR/naked-functions.rs:131:5 | LL | asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:127:5 + --> $DIR/naked-functions.rs:131:5 | LL | asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:136:15 + --> $DIR/naked-functions.rs:140:15 | LL | pub unsafe fn default_abi() { | ^^^^^^^^^^^ @@ -287,13 +287,13 @@ = note: `#[warn(undefined_naked_function_abi)]` on by default warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:142:29 + --> $DIR/naked-functions.rs:146:29 | LL | pub unsafe extern "Rust" fn rust_abi() { | ^^^^^^^^ warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:176:1 + --> $DIR/naked-functions.rs:180:1 | LL | #[inline] | ^^^^^^^^^ @@ -302,7 +302,7 @@ = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:184:1 + --> $DIR/naked-functions.rs:188:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ @@ -311,7 +311,7 @@ = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:192:1 + --> $DIR/naked-functions.rs:196:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ @@ -320,7 +320,7 @@ = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:200:1 + --> $DIR/naked-functions.rs:204:1 | LL | #[inline] | ^^^^^^^^^ @@ -329,7 +329,7 @@ = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:203:1 + --> $DIR/naked-functions.rs:207:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ @@ -338,7 +338,7 @@ = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:206:1 + --> $DIR/naked-functions.rs:210:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.aarch64.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.aarch64.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.aarch64.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.aarch64.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,69 @@ +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:15:32 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/naked-functions-unused.rs:4:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:15:42 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:24:38 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:24:48 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:30:41 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:30:51 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:38:40 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:38:50 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:44:43 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:44:53 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: aborting due to 10 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,16 +1,18 @@ -// only-x86_64 +// revisions: x86_64 aarch64 +//[x86_64] only-x86_64 +//[aarch64] only-aarch64 #![deny(unused)] #![feature(asm)] #![feature(naked_functions)] #![crate_type = "lib"] pub trait Trait { - extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize; - extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize; + extern "C" fn trait_associated(a: usize, b: usize) -> usize; + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize; } pub mod normal { - pub extern "sysv64" fn function(a: usize, b: usize) -> usize { + pub extern "C" fn function(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } @@ -19,13 +21,13 @@ pub struct Normal; impl Normal { - pub extern "sysv64" fn associated(a: usize, b: usize) -> usize { + pub extern "C" fn associated(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } } - pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize { + pub extern "C" fn method(&self, a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } @@ -33,13 +35,13 @@ } impl super::Trait for Normal { - extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize { + extern "C" fn trait_associated(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } } - extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize { + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } @@ -49,7 +51,7 @@ pub mod naked { #[naked] - pub extern "sysv64" fn function(a: usize, b: usize) -> usize { + pub extern "C" fn function(a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } @@ -57,24 +59,24 @@ impl Naked { #[naked] - pub extern "sysv64" fn associated(a: usize, b: usize) -> usize { + pub extern "C" fn associated(a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } #[naked] - pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize { + pub extern "C" fn method(&self, a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } } impl super::Trait for Naked { #[naked] - extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize { + extern "C" fn trait_associated(a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } #[naked] - extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize { + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:13:37 - | -LL | pub extern "sysv64" fn function(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - | -note: the lint level is defined here - --> $DIR/naked-functions-unused.rs:2:9 - | -LL | #![deny(unused)] - | ^^^^^^ - = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:13:47 - | -LL | pub extern "sysv64" fn function(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:22:43 - | -LL | pub extern "sysv64" fn associated(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:22:53 - | -LL | pub extern "sysv64" fn associated(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:28:46 - | -LL | pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:28:56 - | -LL | pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:36:45 - | -LL | extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:36:55 - | -LL | extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:42:48 - | -LL | extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:42:58 - | -LL | extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: aborting due to 10 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.x86_64.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.x86_64.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.x86_64.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/naked-functions-unused.x86_64.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,69 @@ +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:15:32 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/naked-functions-unused.rs:4:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:15:42 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:24:38 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:24:48 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:30:41 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:30:51 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:38:40 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:38:50 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:44:43 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:44:53 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: aborting due to 10 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/named-asm-labels.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/named-asm-labels.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/named-asm-labels.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/named-asm-labels.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 // Tests that the use of named labels in the `asm!` macro are linted against // except for in `#[naked]` fns. @@ -99,9 +102,6 @@ asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); //~ ERROR avoid using named labels // Non-label colons - should pass - // (most of these are stolen from other places) - asm!("{:l}", in(reg) 0i64); - asm!("{:e}", in(reg) 0f32); asm!("mov rax, qword ptr fs:[0]"); // Comments diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/named-asm-labels.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/named-asm-labels.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/named-asm-labels.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/named-asm-labels.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:19:15 + --> $DIR/named-asm-labels.rs:22:15 | LL | asm!("bar: nop"); | ^^^ @@ -9,7 +9,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:22:15 + --> $DIR/named-asm-labels.rs:25:15 | LL | asm!("abcd:"); | ^^^^ @@ -18,7 +18,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:25:15 + --> $DIR/named-asm-labels.rs:28:15 | LL | asm!("foo: bar1: nop"); | ^^^ ^^^^ @@ -27,7 +27,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:29:15 + --> $DIR/named-asm-labels.rs:32:15 | LL | asm!("foo1: nop", "nop"); | ^^^^ @@ -36,7 +36,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:30:15 + --> $DIR/named-asm-labels.rs:33:15 | LL | asm!("foo2: foo3: nop", "nop"); | ^^^^ ^^^^ @@ -45,7 +45,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:32:22 + --> $DIR/named-asm-labels.rs:35:22 | LL | asm!("nop", "foo4: nop"); | ^^^^ @@ -54,7 +54,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:33:15 + --> $DIR/named-asm-labels.rs:36:15 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -63,7 +63,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:33:28 + --> $DIR/named-asm-labels.rs:36:28 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -72,7 +72,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:38:15 + --> $DIR/named-asm-labels.rs:41:15 | LL | asm!("foo7: nop; foo8: nop"); | ^^^^ ^^^^ @@ -81,7 +81,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:40:15 + --> $DIR/named-asm-labels.rs:43:15 | LL | asm!("foo9: nop; nop"); | ^^^^ @@ -90,7 +90,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:41:20 + --> $DIR/named-asm-labels.rs:44:20 | LL | asm!("nop; foo10: nop"); | ^^^^^ @@ -99,7 +99,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:44:15 + --> $DIR/named-asm-labels.rs:47:15 | LL | asm!("bar2: nop\n bar3: nop"); | ^^^^ ^^^^ @@ -108,7 +108,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:46:15 + --> $DIR/named-asm-labels.rs:49:15 | LL | asm!("bar4: nop\n nop"); | ^^^^ @@ -117,7 +117,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:47:21 + --> $DIR/named-asm-labels.rs:50:21 | LL | asm!("nop\n bar5: nop"); | ^^^^ @@ -126,7 +126,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:48:21 + --> $DIR/named-asm-labels.rs:51:21 | LL | asm!("nop\n bar6: bar7: nop"); | ^^^^ ^^^^ @@ -135,7 +135,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:54:13 + --> $DIR/named-asm-labels.rs:57:13 | LL | blah2: nop | ^^^^^ @@ -146,7 +146,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:63:19 + --> $DIR/named-asm-labels.rs:66:19 | LL | nop ; blah4: nop | ^^^^^ @@ -155,7 +155,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:77:15 + --> $DIR/named-asm-labels.rs:80:15 | LL | asm!("blah1: 2bar: nop"); | ^^^^^ @@ -164,7 +164,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:80:15 + --> $DIR/named-asm-labels.rs:83:15 | LL | asm!("def: def: nop"); | ^^^ @@ -173,7 +173,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:81:15 + --> $DIR/named-asm-labels.rs:84:15 | LL | asm!("def: nop\ndef: nop"); | ^^^ @@ -182,7 +182,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:82:15 + --> $DIR/named-asm-labels.rs:85:15 | LL | asm!("def: nop; def: nop"); | ^^^ @@ -191,7 +191,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:90:15 + --> $DIR/named-asm-labels.rs:93:15 | LL | asm!("fooo\u{003A} nop"); | ^^^^^^^^^^^^^^^^ @@ -200,7 +200,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:91:15 + --> $DIR/named-asm-labels.rs:94:15 | LL | asm!("foooo\x3A nop"); | ^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:94:15 + --> $DIR/named-asm-labels.rs:97:15 | LL | asm!("fooooo:\u{000A} nop"); | ^^^^^^ @@ -218,7 +218,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:95:15 + --> $DIR/named-asm-labels.rs:98:15 | LL | asm!("foooooo:\x0A nop"); | ^^^^^^^ @@ -227,7 +227,7 @@ = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:99:14 + --> $DIR/named-asm-labels.rs:102:14 | LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/noreturn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/noreturn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/noreturn.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/noreturn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -// only-x86_64 +// needs-asm-support // check-pass #![feature(asm, never_type)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/parse-error.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/parse-error.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/parse-error.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/parse-error.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -// only-x86_64 - -#![feature(asm, global_asm)] - -fn main() { - let mut foo = 0; - let mut bar = 0; - unsafe { - asm!(); - //~^ ERROR requires at least a template string argument - asm!(foo); - //~^ ERROR asm template must be a string literal - asm!("{}" foo); - //~^ ERROR expected token: `,` - asm!("{}", foo); - //~^ ERROR expected operand, clobber_abi, options, or additional template string - asm!("{}", in foo); - //~^ ERROR expected `(`, found `foo` - asm!("{}", in(reg foo)); - //~^ ERROR expected `)`, found `foo` - asm!("{}", in(reg)); - //~^ ERROR expected expression, found end of macro arguments - asm!("{}", inout(=) foo => bar); - //~^ ERROR expected register class or explicit register - asm!("{}", inout(reg) foo =>); - //~^ ERROR expected expression, found end of macro arguments - asm!("{}", in(reg) foo => bar); - //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` - asm!("{}", sym foo + bar); - //~^ ERROR argument to `sym` must be a path expression - asm!("", options(foo)); - //~^ ERROR expected one of - asm!("", options(nomem foo)); - //~^ ERROR expected one of - asm!("", options(nomem, foo)); - //~^ ERROR expected one of - asm!("{}", options(), const foo); - //~^ ERROR arguments are not allowed after options - //~^^ ERROR attempt to use a non-constant value in a constant - asm!("", clobber_abi(foo)); - //~^ ERROR expected string literal - asm!("", clobber_abi("C" foo)); - //~^ ERROR expected `)`, found `foo` - asm!("", clobber_abi("C", foo)); - //~^ ERROR expected `)`, found `,` - asm!("{}", clobber_abi("C"), const foo); - //~^ ERROR arguments are not allowed after clobber_abi - //~^^ ERROR attempt to use a non-constant value in a constant - asm!("", options(), clobber_abi("C")); - //~^ ERROR clobber_abi is not allowed after options - asm!("{}", options(), clobber_abi("C"), const foo); - //~^ ERROR clobber_abi is not allowed after options - asm!("", clobber_abi("C"), clobber_abi("C")); - //~^ ERROR clobber_abi specified multiple times - asm!("{a}", a = const foo, a = const bar); - //~^ ERROR duplicate argument named `a` - //~^^ ERROR argument never used - //~^^^ ERROR attempt to use a non-constant value in a constant - //~^^^^ ERROR attempt to use a non-constant value in a constant - asm!("", a = in("eax") foo); - //~^ ERROR explicit register arguments cannot have names - asm!("{a}", in("eax") foo, a = const bar); - //~^ ERROR named arguments cannot follow explicit register arguments - //~^^ ERROR attempt to use a non-constant value in a constant - asm!("{a}", in("eax") foo, a = const bar); - //~^ ERROR named arguments cannot follow explicit register arguments - //~^^ ERROR attempt to use a non-constant value in a constant - asm!("{1}", in("eax") foo, const bar); - //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments - //~^^ ERROR attempt to use a non-constant value in a constant - asm!("", options(), ""); - //~^ ERROR expected one of - asm!("{}", in(reg) foo, "{}", out(reg) foo); - //~^ ERROR expected one of - asm!(format!("{{{}}}", 0), in(reg) foo); - //~^ ERROR asm template must be a string literal - asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); - //~^ ERROR asm template must be a string literal - } -} - -const FOO: i32 = 1; -const BAR: i32 = 2; -global_asm!(); -//~^ ERROR requires at least a template string argument -global_asm!(FOO); -//~^ ERROR asm template must be a string literal -global_asm!("{}" FOO); -//~^ ERROR expected token: `,` -global_asm!("{}", FOO); -//~^ ERROR expected operand, options, or additional template string -global_asm!("{}", const); -//~^ ERROR expected expression, found end of macro arguments -global_asm!("{}", const(reg) FOO); -//~^ ERROR expected one of -global_asm!("", options(FOO)); -//~^ ERROR expected one of -global_asm!("", options(nomem FOO)); -//~^ ERROR expected one of -global_asm!("", options(nomem, FOO)); -//~^ ERROR expected one of -global_asm!("{}", options(), const FOO); -//~^ ERROR arguments are not allowed after options -global_asm!("", clobber_abi(FOO)); -//~^ ERROR expected string literal -global_asm!("", clobber_abi("C" FOO)); -//~^ ERROR expected `)`, found `FOO` -global_asm!("", clobber_abi("C", FOO)); -//~^ ERROR expected `)`, found `,` -global_asm!("{}", clobber_abi("C"), const FOO); -//~^ ERROR arguments are not allowed after clobber_abi -//~^^ ERROR `clobber_abi` cannot be used with `global_asm!` -global_asm!("", options(), clobber_abi("C")); -//~^ ERROR clobber_abi is not allowed after options -global_asm!("{}", options(), clobber_abi("C"), const FOO); -//~^ ERROR clobber_abi is not allowed after options -global_asm!("", clobber_abi("C"), clobber_abi("C")); -//~^ ERROR clobber_abi specified multiple times -global_asm!("{a}", a = const FOO, a = const BAR); -//~^ ERROR duplicate argument named `a` -//~^^ ERROR argument never used -global_asm!("", options(), ""); -//~^ ERROR expected one of -global_asm!("{}", const FOO, "{}", const FOO); -//~^ ERROR expected one of -global_asm!(format!("{{{}}}", 0), const FOO); -//~^ ERROR asm template must be a string literal -global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); -//~^ ERROR asm template must be a string literal diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/parse-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/parse-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/parse-error.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/parse-error.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,444 +0,0 @@ -error: requires at least a template string argument - --> $DIR/parse-error.rs:9:9 - | -LL | asm!(); - | ^^^^^^^ - -error: asm template must be a string literal - --> $DIR/parse-error.rs:11:14 - | -LL | asm!(foo); - | ^^^ - -error: expected token: `,` - --> $DIR/parse-error.rs:13:19 - | -LL | asm!("{}" foo); - | ^^^ expected `,` - -error: expected operand, clobber_abi, options, or additional template string - --> $DIR/parse-error.rs:15:20 - | -LL | asm!("{}", foo); - | ^^^ expected operand, clobber_abi, options, or additional template string - -error: expected `(`, found `foo` - --> $DIR/parse-error.rs:17:23 - | -LL | asm!("{}", in foo); - | ^^^ expected `(` - -error: expected `)`, found `foo` - --> $DIR/parse-error.rs:19:27 - | -LL | asm!("{}", in(reg foo)); - | ^^^ expected `)` - -error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:21:27 - | -LL | asm!("{}", in(reg)); - | ^ expected expression - -error: expected register class or explicit register - --> $DIR/parse-error.rs:23:26 - | -LL | asm!("{}", inout(=) foo => bar); - | ^ - -error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:25:37 - | -LL | asm!("{}", inout(reg) foo =>); - | ^ expected expression - -error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` - --> $DIR/parse-error.rs:27:32 - | -LL | asm!("{}", in(reg) foo => bar); - | ^^ expected one of 7 possible tokens - -error: argument to `sym` must be a path expression - --> $DIR/parse-error.rs:29:24 - | -LL | asm!("{}", sym foo + bar); - | ^^^^^^^^^ - -error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` - --> $DIR/parse-error.rs:31:26 - | -LL | asm!("", options(foo)); - | ^^^ expected one of 9 possible tokens - -error: expected one of `)` or `,`, found `foo` - --> $DIR/parse-error.rs:33:32 - | -LL | asm!("", options(nomem foo)); - | ^^^ expected one of `)` or `,` - -error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` - --> $DIR/parse-error.rs:35:33 - | -LL | asm!("", options(nomem, foo)); - | ^^^ expected one of 9 possible tokens - -error: arguments are not allowed after options - --> $DIR/parse-error.rs:37:31 - | -LL | asm!("{}", options(), const foo); - | --------- ^^^^^^^^^ argument - | | - | previous options - -error: expected string literal - --> $DIR/parse-error.rs:40:30 - | -LL | asm!("", clobber_abi(foo)); - | ^^^ not a string literal - -error: expected `)`, found `foo` - --> $DIR/parse-error.rs:42:34 - | -LL | asm!("", clobber_abi("C" foo)); - | ^^^ expected `)` - -error: expected `)`, found `,` - --> $DIR/parse-error.rs:44:33 - | -LL | asm!("", clobber_abi("C", foo)); - | ^ expected `)` - -error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:46:38 - | -LL | asm!("{}", clobber_abi("C"), const foo); - | ---------------- ^^^^^^^^^ argument - | | - | clobber_abi - -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:49:29 - | -LL | asm!("", options(), clobber_abi("C")); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options - -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:51:31 - | -LL | asm!("{}", options(), clobber_abi("C"), const foo); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options - -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:53:36 - | -LL | asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here - -error: duplicate argument named `a` - --> $DIR/parse-error.rs:55:36 - | -LL | asm!("{a}", a = const foo, a = const bar); - | ------------- ^^^^^^^^^^^^^ duplicate argument - | | - | previously here - -error: argument never used - --> $DIR/parse-error.rs:55:36 - | -LL | asm!("{a}", a = const foo, a = const bar); - | ^^^^^^^^^^^^^ argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` - -error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:60:18 - | -LL | asm!("", a = in("eax") foo); - | ^^^^^^^^^^^^^^^^^ - -error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:62:36 - | -LL | asm!("{a}", in("eax") foo, a = const bar); - | ------------- ^^^^^^^^^^^^^ named argument - | | - | explicit register argument - -error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:65:36 - | -LL | asm!("{a}", in("eax") foo, a = const bar); - | ------------- ^^^^^^^^^^^^^ named argument - | | - | explicit register argument - -error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:68:36 - | -LL | asm!("{1}", in("eax") foo, const bar); - | ------------- ^^^^^^^^^ positional argument - | | - | explicit register argument - -error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` - --> $DIR/parse-error.rs:71:29 - | -LL | asm!("", options(), ""); - | ^^ expected one of 9 possible tokens - -error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:73:33 - | -LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); - | ^^^^ expected one of 9 possible tokens - -error: asm template must be a string literal - --> $DIR/parse-error.rs:75:14 - | -LL | asm!(format!("{{{}}}", 0), in(reg) foo); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: asm template must be a string literal - --> $DIR/parse-error.rs:77:21 - | -LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: requires at least a template string argument - --> $DIR/parse-error.rs:84:1 - | -LL | global_asm!(); - | ^^^^^^^^^^^^^^ - -error: asm template must be a string literal - --> $DIR/parse-error.rs:86:13 - | -LL | global_asm!(FOO); - | ^^^ - -error: expected token: `,` - --> $DIR/parse-error.rs:88:18 - | -LL | global_asm!("{}" FOO); - | ^^^ expected `,` - -error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:90:19 - | -LL | global_asm!("{}", FOO); - | ^^^ expected operand, options, or additional template string - -error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:92:24 - | -LL | global_asm!("{}", const); - | ^ expected expression - -error: expected one of `,`, `.`, `?`, or an operator, found `FOO` - --> $DIR/parse-error.rs:94:30 - | -LL | global_asm!("{}", const(reg) FOO); - | ^^^ expected one of `,`, `.`, `?`, or an operator - -error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` - --> $DIR/parse-error.rs:96:25 - | -LL | global_asm!("", options(FOO)); - | ^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/parse-error.rs:98:25 - | -LL | global_asm!("", options(nomem FOO)); - | ^^^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/parse-error.rs:100:25 - | -LL | global_asm!("", options(nomem, FOO)); - | ^^^^^ expected one of `)`, `att_syntax`, or `raw` - -error: arguments are not allowed after options - --> $DIR/parse-error.rs:102:30 - | -LL | global_asm!("{}", options(), const FOO); - | --------- ^^^^^^^^^ argument - | | - | previous options - -error: expected string literal - --> $DIR/parse-error.rs:104:29 - | -LL | global_asm!("", clobber_abi(FOO)); - | ^^^ not a string literal - -error: expected `)`, found `FOO` - --> $DIR/parse-error.rs:106:33 - | -LL | global_asm!("", clobber_abi("C" FOO)); - | ^^^ expected `)` - -error: expected `)`, found `,` - --> $DIR/parse-error.rs:108:32 - | -LL | global_asm!("", clobber_abi("C", FOO)); - | ^ expected `)` - -error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:110:37 - | -LL | global_asm!("{}", clobber_abi("C"), const FOO); - | ---------------- ^^^^^^^^^ argument - | | - | clobber_abi - -error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:110:19 - | -LL | global_asm!("{}", clobber_abi("C"), const FOO); - | ^^^^^^^^^^^^^^^^ - -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:113:28 - | -LL | global_asm!("", options(), clobber_abi("C")); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options - -error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:115:30 - | -LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); - | --------- ^^^^^^^^^^^^^^^^ - | | - | options - -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:117:35 - | -LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here - -error: duplicate argument named `a` - --> $DIR/parse-error.rs:119:35 - | -LL | global_asm!("{a}", a = const FOO, a = const BAR); - | ------------- ^^^^^^^^^^^^^ duplicate argument - | | - | previously here - -error: argument never used - --> $DIR/parse-error.rs:119:35 - | -LL | global_asm!("{a}", a = const FOO, a = const BAR); - | ^^^^^^^^^^^^^ argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` - -error: expected one of `clobber_abi`, `const`, or `options`, found `""` - --> $DIR/parse-error.rs:122:28 - | -LL | global_asm!("", options(), ""); - | ^^ expected one of `clobber_abi`, `const`, or `options` - -error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"` - --> $DIR/parse-error.rs:124:30 - | -LL | global_asm!("{}", const FOO, "{}", const FOO); - | ^^^^ expected one of `clobber_abi`, `const`, or `options` - -error: asm template must be a string literal - --> $DIR/parse-error.rs:126:13 - | -LL | global_asm!(format!("{{{}}}", 0), const FOO); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: asm template must be a string literal - --> $DIR/parse-error.rs:128:20 - | -LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:37:37 - | -LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` -... -LL | asm!("{}", options(), const foo); - | ^^^ non-constant value - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:46:44 - | -LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` -... -LL | asm!("{}", clobber_abi("C"), const foo); - | ^^^ non-constant value - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:55:31 - | -LL | let mut foo = 0; - | ---------- help: consider using `const` instead of `let`: `const foo` -... -LL | asm!("{a}", a = const foo, a = const bar); - | ^^^ non-constant value - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:55:46 - | -LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` -... -LL | asm!("{a}", a = const foo, a = const bar); - | ^^^ non-constant value - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:62:46 - | -LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` -... -LL | asm!("{a}", in("eax") foo, a = const bar); - | ^^^ non-constant value - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:65:46 - | -LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` -... -LL | asm!("{a}", in("eax") foo, a = const bar); - | ^^^ non-constant value - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:68:42 - | -LL | let mut bar = 0; - | ---------- help: consider using `const` instead of `let`: `const bar` -... -LL | asm!("{1}", in("eax") foo, const bar); - | ^^^ non-constant value - -error: aborting due to 63 previous errors - -For more information about this error, try `rustc --explain E0435`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.fixed 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // run-rustfix -// only-x86_64 +// needs-asm-support #![feature(asm, llvm_asm)] #![allow(deprecated)] // llvm_asm! diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // run-rustfix -// only-x86_64 +// needs-asm-support #![feature(asm, llvm_asm)] #![allow(deprecated)] // llvm_asm! diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/rustfix-asm.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/rustfix-asm.rs:11:9 | LL | asm!("" :: "r" (x)); - | ----^^^^^^^^^^^^^^^^ + | ----^^^^^^^^^^^^^^^ | | | help: replace with: `llvm_asm!` | @@ -13,7 +13,7 @@ --> $DIR/rustfix-asm.rs:13:9 | LL | asm!("" : "=r" (y)); - | ----^^^^^^^^^^^^^^^^ + | ----^^^^^^^^^^^^^^^ | | | help: replace with: `llvm_asm!` | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/srcloc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/srcloc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/srcloc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/srcloc.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -// min-llvm-version: 10.0.1 -// only-x86_64 -// build-fail -// compile-flags: -Ccodegen-units=1 -#![feature(asm)] - -// Checks that inline asm errors are mapped to the correct line in the source code. - -fn main() { - unsafe { - asm!("invalid_instruction"); - //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!(" - invalid_instruction - "); - //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!(r#" - invalid_instruction - "#); - //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!(" - mov eax, eax - invalid_instruction - mov eax, eax - "); - //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!(r#" - mov eax, eax - invalid_instruction - mov eax, eax - "#); - //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!(concat!("invalid", "_", "instruction")); - //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); - //~^ WARN: scale factor without index register is ignored - - asm!( - "invalid_instruction", - ); - //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!( - "mov eax, eax", - "invalid_instruction", - "mov eax, eax", - ); - //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!( - "mov eax, eax\n", - "invalid_instruction", - "mov eax, eax", - ); - //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!( - "mov eax, eax", - concat!("invalid", "_", "instruction"), - "mov eax, eax", - ); - //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - asm!( - concat!("mov eax", ", ", "eax"), - concat!("invalid", "_", "instruction"), - concat!("mov eax", ", ", "eax"), - ); - //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' - - // Make sure template strings get separated - asm!( - "invalid_instruction1", - "invalid_instruction2", - ); - //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' - //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' - - asm!( - concat!( - "invalid", "_", "instruction1", "\n", - "invalid", "_", "instruction2", - ), - ); - //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' - //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' - - asm!( - concat!( - "invalid", "_", "instruction1", "\n", - "invalid", "_", "instruction2", - ), - concat!( - "invalid", "_", "instruction3", "\n", - "invalid", "_", "instruction4", - ), - ); - //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' - //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' - //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' - //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' - - asm!( - concat!( - "invalid", "_", "instruction1", "\n", - "invalid", "_", "instruction2", "\n", - ), - concat!( - "invalid", "_", "instruction3", "\n", - "invalid", "_", "instruction4", "\n", - ), - ); - //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' - //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' - //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' - //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/srcloc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/srcloc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/srcloc.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/srcloc.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,290 +0,0 @@ -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:11:15 - | -LL | asm!("invalid_instruction"); - | ^ - | -note: instantiated into assembly here - --> :2:2 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:15:13 - | -LL | invalid_instruction - | ^ - | -note: instantiated into assembly here - --> :3:13 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:20:13 - | -LL | invalid_instruction - | ^ - | -note: instantiated into assembly here - --> :3:13 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:26:13 - | -LL | invalid_instruction - | ^ - | -note: instantiated into assembly here - --> :4:13 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:33:13 - | -LL | invalid_instruction - | ^ - | -note: instantiated into assembly here - --> :4:13 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:38:14 - | -LL | asm!(concat!("invalid", "_", "instruction")); - | ^ - | -note: instantiated into assembly here - --> :2:2 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -warning: scale factor without index register is ignored - --> $DIR/srcloc.rs:41:15 - | -LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); - | ^ - | -note: instantiated into assembly here - --> :1:23 - | -LL | movaps %xmm3, (%esi, 2) - | ^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:45:14 - | -LL | "invalid_instruction", - | ^ - | -note: instantiated into assembly here - --> :2:2 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:51:14 - | -LL | "invalid_instruction", - | ^ - | -note: instantiated into assembly here - --> :3:1 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:58:14 - | -LL | "invalid_instruction", - | ^ - | -note: instantiated into assembly here - --> :4:1 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:65:13 - | -LL | concat!("invalid", "_", "instruction"), - | ^ - | -note: instantiated into assembly here - --> :3:1 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:72:13 - | -LL | concat!("invalid", "_", "instruction"), - | ^ - | -note: instantiated into assembly here - --> :3:1 - | -LL | invalid_instruction - | ^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:79:14 - | -LL | "invalid_instruction1", - | ^ - | -note: instantiated into assembly here - --> :2:2 - | -LL | invalid_instruction1 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:80:14 - | -LL | "invalid_instruction2", - | ^ - | -note: instantiated into assembly here - --> :3:1 - | -LL | invalid_instruction2 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:86:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :2:2 - | -LL | invalid_instruction1 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:86:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :3:1 - | -LL | invalid_instruction2 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:95:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :2:2 - | -LL | invalid_instruction1 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:95:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :3:1 - | -LL | invalid_instruction2 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:99:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :4:1 - | -LL | invalid_instruction3 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:99:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :5:1 - | -LL | invalid_instruction4 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:110:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :2:2 - | -LL | invalid_instruction1 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:110:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :3:1 - | -LL | invalid_instruction2 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:114:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :5:1 - | -LL | invalid_instruction3 - | ^^^^^^^^^^^^^^^^^^^^ - -error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:114:13 - | -LL | concat!( - | ^ - | -note: instantiated into assembly here - --> :6:1 - | -LL | invalid_instruction4 - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 23 previous errors; 1 warning emitted - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/sym.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/sym.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/sym.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/sym.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -// min-llvm-version: 10.0.1 -// only-x86_64 -// only-linux -// run-pass - -#![feature(asm, thread_local)] - -extern "C" fn f1() -> i32 { - 111 -} - -// The compiler will generate a shim to hide the caller location parameter. -#[track_caller] -fn f2() -> i32 { - 222 -} - -macro_rules! call { - ($func:path) => { - unsafe { - let result: i32; - asm!("call {}", sym $func, - out("rax") result, - out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _, - out("r8") _, out("r9") _, out("r10") _, out("r11") _, - out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _, - out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _, - out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _, - out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _, - ); - result - } - } -} - -macro_rules! static_addr { - ($s:expr) => { - unsafe { - let result: *const u32; - // LEA performs a RIP-relative address calculation and returns the address - asm!("lea {}, [rip + {}]", out(reg) result, sym $s); - result - } - } -} -macro_rules! static_tls_addr { - ($s:expr) => { - unsafe { - let result: *const u32; - asm!( - " - # Load TLS base address - mov {out}, qword ptr fs:[0] - # Calculate the address of sym in the TLS block. The @tpoff - # relocation gives the offset of the symbol from the start - # of the TLS block. - lea {out}, [{out} + {sym}@tpoff] - ", - out = out(reg) result, - sym = sym $s - ); - result - } - } -} - -static S1: u32 = 111; -#[thread_local] -static S2: u32 = 222; - -fn main() { - assert_eq!(call!(f1), 111); - assert_eq!(call!(f2), 222); - assert_eq!(static_addr!(S1), &S1 as *const u32); - assert_eq!(static_tls_addr!(S2), &S2 as *const u32); - std::thread::spawn(|| { - assert_eq!(static_addr!(S1), &S1 as *const u32); - assert_eq!(static_tls_addr!(S2), &S2 as *const u32); - }).join().unwrap(); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-1.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 #![feature(asm, global_asm)] @@ -49,6 +52,8 @@ //~^ ERROR mismatched types asm!("{}", const 0 as *mut u8); //~^ ERROR mismatched types + asm!("{}", const &0); + //~^ ERROR mismatched types } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:34:26 + --> $DIR/type-check-1.rs:37:26 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -8,7 +8,7 @@ | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:37:36 + --> $DIR/type-check-1.rs:40:36 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -17,7 +17,7 @@ | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:40:36 + --> $DIR/type-check-1.rs:43:36 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -26,13 +26,13 @@ | ^ non-constant value error[E0308]: mismatched types - --> $DIR/type-check-1.rs:48:26 + --> $DIR/type-check-1.rs:51:26 | LL | asm!("{}", const 0f32); | ^^^^ expected integer, found `f32` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:50:26 + --> $DIR/type-check-1.rs:53:26 | LL | asm!("{}", const 0 as *mut u8); | ^^^^^^^^^^^^ expected integer, found *-ptr @@ -40,20 +40,32 @@ = note: expected type `{integer}` found raw pointer `*mut u8` +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:55:26 + | +LL | asm!("{}", const &0); + | ^^ expected integer, found `&{integer}` + | +help: consider removing the borrow + | +LL - asm!("{}", const &0); +LL + asm!("{}", const 0); + | + error: invalid asm output - --> $DIR/type-check-1.rs:10:29 + --> $DIR/type-check-1.rs:13:29 | LL | asm!("{}", out(reg) 1 + 2); | ^^^^^ cannot assign to this expression error: invalid asm output - --> $DIR/type-check-1.rs:12:31 + --> $DIR/type-check-1.rs:15:31 | LL | asm!("{}", inout(reg) 1 + 2); | ^^^^^ cannot assign to this expression error[E0277]: the size for values of type `[u64]` cannot be known at compilation time - --> $DIR/type-check-1.rs:18:28 + --> $DIR/type-check-1.rs:21:28 | LL | asm!("{}", in(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time @@ -62,7 +74,7 @@ = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time - --> $DIR/type-check-1.rs:20:29 + --> $DIR/type-check-1.rs:23:29 | LL | asm!("{}", out(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time @@ -71,7 +83,7 @@ = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time - --> $DIR/type-check-1.rs:22:31 + --> $DIR/type-check-1.rs:25:31 | LL | asm!("{}", inout(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time @@ -80,13 +92,13 @@ = note: all inline asm arguments must have a statically known size error[E0308]: mismatched types - --> $DIR/type-check-1.rs:60:25 + --> $DIR/type-check-1.rs:65:25 | LL | global_asm!("{}", const 0f32); | ^^^^ expected integer, found `f32` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:62:25 + --> $DIR/type-check-1.rs:67:25 | LL | global_asm!("{}", const 0 as *mut u8); | ^^^^^^^^^^^^ expected integer, found *-ptr @@ -94,7 +106,7 @@ = note: expected type `{integer}` found raw pointer `*mut u8` -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors Some errors have detailed explanations: E0277, E0308, E0435. For more information about an error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-2.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -// only-x86_64 - -#![feature(asm, repr_simd, never_type)] - -#[repr(simd)] -struct SimdNonCopy(f32, f32, f32, f32); - -fn main() { - unsafe { - // Inputs must be initialized - - let x: u64; - asm!("{}", in(reg) x); - //~^ ERROR use of possibly-uninitialized variable: `x` - let mut y: u64; - asm!("{}", inout(reg) y); - //~^ ERROR use of possibly-uninitialized variable: `y` - let _ = y; - - // Outputs require mutable places - - let v: Vec = vec![0, 1, 2]; - asm!("{}", in(reg) v[0]); - asm!("{}", out(reg) v[0]); - //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable - asm!("{}", inout(reg) v[0]); - //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable - - // This currently causes an ICE: https://github.com/rust-lang/rust/issues/81857 - // asm!("{}", const &0); - // ERROR asm `const` arguments must be integer or floating-point values - - // Sym operands must point to a function or static - - const C: i32 = 0; - static S: i32 = 0; - asm!("{}", sym S); - asm!("{}", sym main); - asm!("{}", sym C); - //~^ ERROR asm `sym` operand must point to a fn or static - asm!("{}", sym x); - //~^ ERROR asm `sym` operand must point to a fn or static - - // Register operands must be Copy - - asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); - //~^ ERROR arguments for inline assembly must be copyable - - // Register operands must be integers, floats, SIMD vectors, pointers or - // function pointers. - - asm!("{}", in(reg) 0i64); - asm!("{}", in(reg) 0f64); - asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps()); - asm!("{}", in(reg) 0 as *const u8); - asm!("{}", in(reg) 0 as *mut u8); - asm!("{}", in(reg) main as fn()); - asm!("{}", in(reg) |x: i32| x); - //~^ ERROR cannot use value of type - asm!("{}", in(reg) vec![0]); - //~^ ERROR cannot use value of type `Vec` for inline assembly - asm!("{}", in(reg) (1, 2, 3)); - //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly - asm!("{}", in(reg) [1, 2, 3]); - //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly - - // Register inputs (but not outputs) allow references and function types - - let mut f = main; - let mut r = &mut 0; - asm!("{}", in(reg) f); - asm!("{}", inout(reg) f); - //~^ ERROR cannot use value of type `fn() {main}` for inline assembly - asm!("{}", in(reg) r); - asm!("{}", inout(reg) r); - //~^ ERROR cannot use value of type `&mut i32` for inline assembly - let _ = (f, r); - - // Type checks ignore never type - - let u: ! = unreachable!(); - asm!("{}", in(reg) u); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-2.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -error: arguments for inline assembly must be copyable - --> $DIR/type-check-2.rs:46:32 - | -LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `SimdNonCopy` does not implement the Copy trait - -error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly - --> $DIR/type-check-2.rs:58:28 - | -LL | asm!("{}", in(reg) |x: i32| x); - | ^^^^^^^^^^ - | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly - -error: cannot use value of type `Vec` for inline assembly - --> $DIR/type-check-2.rs:60:28 - | -LL | asm!("{}", in(reg) vec![0]); - | ^^^^^^^ - | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly - = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: cannot use value of type `(i32, i32, i32)` for inline assembly - --> $DIR/type-check-2.rs:62:28 - | -LL | asm!("{}", in(reg) (1, 2, 3)); - | ^^^^^^^^^ - | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly - -error: cannot use value of type `[i32; 3]` for inline assembly - --> $DIR/type-check-2.rs:64:28 - | -LL | asm!("{}", in(reg) [1, 2, 3]); - | ^^^^^^^^^ - | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly - -error: cannot use value of type `fn() {main}` for inline assembly - --> $DIR/type-check-2.rs:72:31 - | -LL | asm!("{}", inout(reg) f); - | ^ - | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly - -error: cannot use value of type `&mut i32` for inline assembly - --> $DIR/type-check-2.rs:75:31 - | -LL | asm!("{}", inout(reg) r); - | ^ - | - = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly - -error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:39:24 - | -LL | asm!("{}", sym C); - | ^ - -error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:41:24 - | -LL | asm!("{}", sym x); - | ^ - -error[E0381]: use of possibly-uninitialized variable: `x` - --> $DIR/type-check-2.rs:13:28 - | -LL | asm!("{}", in(reg) x); - | ^ use of possibly-uninitialized `x` - -error[E0381]: use of possibly-uninitialized variable: `y` - --> $DIR/type-check-2.rs:16:9 - | -LL | asm!("{}", inout(reg) y); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` - -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/type-check-2.rs:24:29 - | -LL | let v: Vec = vec![0, 1, 2]; - | - help: consider changing this to be mutable: `mut v` -LL | asm!("{}", in(reg) v[0]); -LL | asm!("{}", out(reg) v[0]); - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/type-check-2.rs:26:31 - | -LL | let v: Vec = vec![0, 1, 2]; - | - help: consider changing this to be mutable: `mut v` -... -LL | asm!("{}", inout(reg) v[0]); - | ^ cannot borrow as mutable - -error: aborting due to 13 previous errors - -Some errors have detailed explanations: E0381, E0596. -For more information about an error, try `rustc --explain E0381`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-3.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-3.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -// only-x86_64 -// compile-flags: -C target-feature=+avx512f - -#![feature(asm, global_asm)] - -use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps}; - -fn main() { - unsafe { - // Types must be listed in the register class. - - asm!("{}", in(reg) 0i128); - //~^ ERROR type `i128` cannot be used with this register class - asm!("{}", in(reg) _mm_setzero_ps()); - //~^ ERROR type `__m128` cannot be used with this register class - asm!("{}", in(reg) _mm256_setzero_ps()); - //~^ ERROR type `__m256` cannot be used with this register class - asm!("{}", in(xmm_reg) 0u8); - //~^ ERROR type `u8` cannot be used with this register class - asm!("{:e}", in(reg) 0i32); - asm!("{}", in(xmm_reg) 0i32); - asm!("{:e}", in(reg) 0f32); - asm!("{}", in(xmm_reg) 0f32); - asm!("{}", in(xmm_reg) _mm_setzero_ps()); - asm!("{:x}", in(ymm_reg) _mm_setzero_ps()); - asm!("{}", in(kreg) 0u16); - asm!("{}", in(kreg) 0u64); - //~^ ERROR `avx512bw` target feature is not enabled - - // Template modifier suggestions for sub-registers - - asm!("{0} {0}", in(reg) 0i16); - //~^ WARN formatting may not be suitable for sub-register argument - asm!("{0} {0:x}", in(reg) 0i16); - //~^ WARN formatting may not be suitable for sub-register argument - asm!("{}", in(reg) 0i32); - //~^ WARN formatting may not be suitable for sub-register argument - asm!("{}", in(reg) 0i64); - asm!("{}", in(ymm_reg) 0i64); - //~^ WARN formatting may not be suitable for sub-register argument - asm!("{}", in(ymm_reg) _mm256_setzero_ps()); - asm!("{:l}", in(reg) 0i16); - asm!("{:l}", in(reg) 0i32); - asm!("{:l}", in(reg) 0i64); - asm!("{:x}", in(ymm_reg) 0i64); - asm!("{:x}", in(ymm_reg) _mm256_setzero_ps()); - - // Suggest different register class for type - - asm!("{}", in(reg) 0i8); - //~^ ERROR type `i8` cannot be used with this register class - asm!("{}", in(reg_byte) 0i8); - - // Split inout operands must have compatible types - - let mut val_i16: i16; - let mut val_f32: f32; - let mut val_u32: u32; - let mut val_u64: u64; - let mut val_ptr: *mut u8; - asm!("{:r}", inout(reg) 0u16 => val_i16); - asm!("{:r}", inout(reg) 0u32 => val_f32); - //~^ ERROR incompatible types for asm inout argument - asm!("{:r}", inout(reg) 0u32 => val_ptr); - //~^ ERROR incompatible types for asm inout argument - asm!("{:r}", inout(reg) main => val_u32); - //~^ ERROR incompatible types for asm inout argument - asm!("{:r}", inout(reg) 0u64 => val_ptr); - asm!("{:r}", inout(reg) main => val_u64); - } -} - -// Constants must be... constant - -static S: i32 = 1; -const fn const_foo(x: i32) -> i32 { - x -} -const fn const_bar(x: T) -> T { - x -} -global_asm!("{}", const S); -//~^ ERROR constants cannot refer to statics -global_asm!("{}", const const_foo(0)); -global_asm!("{}", const const_foo(S)); -//~^ ERROR constants cannot refer to statics -global_asm!("{}", const const_bar(0)); -global_asm!("{}", const const_bar(S)); -//~^ ERROR constants cannot refer to statics diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-3.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-3.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,143 +0,0 @@ -error: type `i128` cannot be used with this register class - --> $DIR/type-check-3.rs:12:28 - | -LL | asm!("{}", in(reg) 0i128); - | ^^^^^ - | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 - -error: type `__m128` cannot be used with this register class - --> $DIR/type-check-3.rs:14:28 - | -LL | asm!("{}", in(reg) _mm_setzero_ps()); - | ^^^^^^^^^^^^^^^^ - | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 - -error: type `__m256` cannot be used with this register class - --> $DIR/type-check-3.rs:16:28 - | -LL | asm!("{}", in(reg) _mm256_setzero_ps()); - | ^^^^^^^^^^^^^^^^^^^ - | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 - -error: type `u8` cannot be used with this register class - --> $DIR/type-check-3.rs:18:32 - | -LL | asm!("{}", in(xmm_reg) 0u8); - | ^^^ - | - = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 - -error: `avx512bw` target feature is not enabled - --> $DIR/type-check-3.rs:27:29 - | -LL | asm!("{}", in(kreg) 0u64); - | ^^^^ - | - = note: this is required to use type `u64` with register class `kreg` - -warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:32:15 - | -LL | asm!("{0} {0}", in(reg) 0i16); - | ^^^ ^^^ ---- for this argument - | - = note: `#[warn(asm_sub_register)]` on by default - = help: use the `x` modifier to have the register formatted as `ax` - = help: or use the `r` modifier to keep the default formatting of `rax` - -warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:34:15 - | -LL | asm!("{0} {0:x}", in(reg) 0i16); - | ^^^ ---- for this argument - | - = help: use the `x` modifier to have the register formatted as `ax` - = help: or use the `r` modifier to keep the default formatting of `rax` - -warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:36:15 - | -LL | asm!("{}", in(reg) 0i32); - | ^^ ---- for this argument - | - = help: use the `e` modifier to have the register formatted as `eax` - = help: or use the `r` modifier to keep the default formatting of `rax` - -warning: formatting may not be suitable for sub-register argument - --> $DIR/type-check-3.rs:39:15 - | -LL | asm!("{}", in(ymm_reg) 0i64); - | ^^ ---- for this argument - | - = help: use the `x` modifier to have the register formatted as `xmm0` - = help: or use the `y` modifier to keep the default formatting of `ymm0` - -error: type `i8` cannot be used with this register class - --> $DIR/type-check-3.rs:50:28 - | -LL | asm!("{}", in(reg) 0i8); - | ^^^ - | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 - = help: consider using the `reg_byte` register class instead - -error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:62:33 - | -LL | asm!("{:r}", inout(reg) 0u32 => val_f32); - | ^^^^ ^^^^^^^ type `f32` - | | - | type `u32` - | - = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size - -error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:64:33 - | -LL | asm!("{:r}", inout(reg) 0u32 => val_ptr); - | ^^^^ ^^^^^^^ type `*mut u8` - | | - | type `u32` - | - = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size - -error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:66:33 - | -LL | asm!("{:r}", inout(reg) main => val_u32); - | ^^^^ ^^^^^^^ type `u32` - | | - | type `fn()` - | - = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size - -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:82:25 - | -LL | global_asm!("{}", const S); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:85:35 - | -LL | global_asm!("{}", const const_foo(S)); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:88:35 - | -LL | global_asm!("{}", const const_bar(S)); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error: aborting due to 12 previous errors; 4 warnings emitted - -For more information about this error, try `rustc --explain E0013`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-4.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-4.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-4.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-4.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 #![feature(asm)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/type-check-4.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/type-check-4.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,16 +1,16 @@ error[E0506]: cannot assign to `a` because it is borrowed - --> $DIR/type-check-4.rs:11:9 + --> $DIR/type-check-4.rs:14:9 | LL | let p = &a; | -- borrow of `a` occurs here LL | asm!("{}", out(reg) a); - | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here LL | LL | println!("{}", p); | - borrow later used here error[E0503]: cannot use `a` because it was mutably borrowed - --> $DIR/type-check-4.rs:19:28 + --> $DIR/type-check-4.rs:22:28 | LL | let p = &mut a; | ------ borrow of `a` occurs here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-options.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-options.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-options.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-options.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +// only-x86_64 + +#![feature(asm, global_asm)] + +fn main() { + let mut foo = 0; + unsafe { + asm!("", options(nomem, readonly)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + asm!("", options(pure, nomem, noreturn)); + //~^ ERROR the `pure` and `noreturn` options are mutually exclusive + //~^^ ERROR asm with the `pure` option must have at least one output + asm!("{}", in(reg) foo, options(pure, nomem)); + //~^ ERROR asm with the `pure` option must have at least one output + asm!("{}", out(reg) foo, options(noreturn)); + //~^ ERROR asm outputs are not allowed with the `noreturn` option + } + + unsafe { + asm!("", clobber_abi("foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("{}", out(reg) foo, clobber_abi("C")); + //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + asm!("", out("eax") foo, clobber_abi("C")); + } +} + +global_asm!("", options(nomem)); +//~^ ERROR expected one of +global_asm!("", options(readonly)); +//~^ ERROR expected one of +global_asm!("", options(noreturn)); +//~^ ERROR expected one of +global_asm!("", options(pure)); +//~^ ERROR expected one of +global_asm!("", options(nostack)); +//~^ ERROR expected one of +global_asm!("", options(preserves_flags)); +//~^ ERROR expected one of diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-options.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-options.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-options.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-options.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,84 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/bad-options.rs:8:18 + | +LL | asm!("", options(nomem, readonly)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:13:33 + | +LL | asm!("{}", in(reg) foo, options(pure, nomem)); + | ^^^^^^^^^^^^^^^^^^^^ + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/bad-options.rs:15:20 + | +LL | asm!("{}", out(reg) foo, options(noreturn)); + | ^^^^^^^^^^^^ + +error: asm with `clobber_abi` must specify explicit registers for outputs + --> $DIR/bad-options.rs:22:20 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C")); + | ^^^^^^^^^^^^ ---------------- clobber_abi + | | + | generic outputs + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/bad-options.rs:28:25 + | +LL | global_asm!("", options(nomem)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` + --> $DIR/bad-options.rs:30:25 + | +LL | global_asm!("", options(readonly)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` + --> $DIR/bad-options.rs:32:25 + | +LL | global_asm!("", options(noreturn)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `pure` + --> $DIR/bad-options.rs:34:25 + | +LL | global_asm!("", options(pure)); + | ^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` + --> $DIR/bad-options.rs:36:25 + | +LL | global_asm!("", options(nostack)); + | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` + --> $DIR/bad-options.rs:38:25 + | +LL | global_asm!("", options(preserves_flags)); + | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-options.rs:20:18 + | +LL | asm!("", clobber_abi("foo")); + | ^^^^^^^^^^^^^^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: aborting due to 13 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-reg.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-reg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-reg.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-reg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,64 @@ +// only-x86_64 +// compile-flags: -C target-feature=+avx2 + +#![feature(asm)] + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + // Bad register/register class + + asm!("{}", in(foo) foo); + //~^ ERROR invalid register class `foo`: unknown register class + asm!("", in("foo") foo); + //~^ ERROR invalid register `foo`: unknown register + asm!("{:z}", in(reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(xmm_reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:a}", const 0); + //~^ ERROR asm template modifiers are not allowed for `const` arguments + asm!("{:a}", sym main); + //~^ ERROR asm template modifiers are not allowed for `sym` arguments + asm!("", in("ebp") foo); + //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand + asm!("", in("rsp") foo); + //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand + asm!("", in("ip") foo); + //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand + asm!("", in("k0") foo); + //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand + asm!("", in("ah") foo); + //~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand + + asm!("", in("st(2)") foo); + //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output + asm!("", in("mm0") foo); + //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output + asm!("", out("st(2)") _); + asm!("", out("mm0") _); + asm!("{}", in(x87_reg) foo); + //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output + asm!("{}", in(mmx_reg) foo); + //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output + asm!("{}", out(x87_reg) _); + //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output + asm!("{}", out(mmx_reg) _); + //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output + + // Explicit register conflicts + // (except in/lateout which don't conflict) + + asm!("", in("eax") foo, in("al") bar); + //~^ ERROR register `al` conflicts with register `ax` + asm!("", in("rax") foo, out("rax") bar); + //~^ ERROR register `ax` conflicts with register `ax` + asm!("", in("al") foo, lateout("al") bar); + asm!("", in("xmm0") foo, in("ymm0") bar); + //~^ ERROR register `ymm0` conflicts with register `xmm0` + asm!("", in("xmm0") foo, out("ymm0") bar); + //~^ ERROR register `ymm0` conflicts with register `xmm0` + asm!("", in("xmm0") foo, lateout("ymm0") bar); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-reg.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-reg.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-reg.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/bad-reg.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,160 @@ +error: invalid register class `foo`: unknown register class + --> $DIR/bad-reg.rs:12:20 + | +LL | asm!("{}", in(foo) foo); + | ^^^^^^^^^^^ + +error: invalid register `foo`: unknown register + --> $DIR/bad-reg.rs:14:18 + | +LL | asm!("", in("foo") foo); + | ^^^^^^^^^^^^^ + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:16:15 + | +LL | asm!("{:z}", in(reg) foo); + | ^^^^ ----------- argument + | | + | template modifier + | + = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:18:15 + | +LL | asm!("{:r}", in(xmm_reg) foo); + | ^^^^ --------------- argument + | | + | template modifier + | + = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z` + +error: asm template modifiers are not allowed for `const` arguments + --> $DIR/bad-reg.rs:20:15 + | +LL | asm!("{:a}", const 0); + | ^^^^ ------- argument + | | + | template modifier + +error: asm template modifiers are not allowed for `sym` arguments + --> $DIR/bad-reg.rs:22:15 + | +LL | asm!("{:a}", sym main); + | ^^^^ -------- argument + | | + | template modifier + +error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:24:18 + | +LL | asm!("", in("ebp") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:26:18 + | +LL | asm!("", in("rsp") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:28:18 + | +LL | asm!("", in("ip") foo); + | ^^^^^^^^^^^^ + +error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", in("k0") foo); + | ^^^^^^^^^^^^ + +error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64 + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", in("ah") foo); + | ^^^^^^^^^^^^ + +error: register class `x87_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:35:18 + | +LL | asm!("", in("st(2)") foo); + | ^^^^^^^^^^^^^^^ + +error: register class `mmx_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:37:18 + | +LL | asm!("", in("mm0") foo); + | ^^^^^^^^^^^^^ + +error: register class `x87_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:41:20 + | +LL | asm!("{}", in(x87_reg) foo); + | ^^^^^^^^^^^^^^^ + +error: register class `mmx_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:43:20 + | +LL | asm!("{}", in(mmx_reg) foo); + | ^^^^^^^^^^^^^^^ + +error: register class `x87_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:45:20 + | +LL | asm!("{}", out(x87_reg) _); + | ^^^^^^^^^^^^^^ + +error: register class `mmx_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:47:20 + | +LL | asm!("{}", out(mmx_reg) _); + | ^^^^^^^^^^^^^^ + +error: register `al` conflicts with register `ax` + --> $DIR/bad-reg.rs:53:33 + | +LL | asm!("", in("eax") foo, in("al") bar); + | ------------- ^^^^^^^^^^^^ register `al` + | | + | register `ax` + +error: register `ax` conflicts with register `ax` + --> $DIR/bad-reg.rs:55:33 + | +LL | asm!("", in("rax") foo, out("rax") bar); + | ------------- ^^^^^^^^^^^^^^ register `ax` + | | + | register `ax` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:55:18 + | +LL | asm!("", in("rax") foo, out("rax") bar); + | ^^^^^^^^^^^^^ + +error: register `ymm0` conflicts with register `xmm0` + --> $DIR/bad-reg.rs:58:34 + | +LL | asm!("", in("xmm0") foo, in("ymm0") bar); + | -------------- ^^^^^^^^^^^^^^ register `ymm0` + | | + | register `xmm0` + +error: register `ymm0` conflicts with register `xmm0` + --> $DIR/bad-reg.rs:60:34 + | +LL | asm!("", in("xmm0") foo, out("ymm0") bar); + | -------------- ^^^^^^^^^^^^^^^ register `ymm0` + | | + | register `xmm0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:60:18 + | +LL | asm!("", in("xmm0") foo, out("ymm0") bar); + | ^^^^^^^^^^^^^^ + +error: aborting due to 21 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/const.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/const.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/const.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/const.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,42 @@ +// min-llvm-version: 10.0.1 +// only-x86_64 +// run-pass +// revisions: mirunsafeck thirunsafeck +// [thirunsafeck]compile-flags: -Z thir-unsafeck + +#![feature(asm, global_asm)] + +fn const_generic() -> usize { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const X); + a + } +} + +const fn constfn(x: usize) -> usize { + x +} + +fn main() { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const 5); + assert_eq!(a, 5); + + let b: usize; + asm!("mov {}, {}", out(reg) b, const constfn(5)); + assert_eq!(b, 5); + + let c: usize; + asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5)); + assert_eq!(c, 10); + } + + let d = const_generic::<5>(); + assert_eq!(d, 5); +} + +global_asm!("mov eax, {}", const 5); +global_asm!("mov eax, {}", const constfn(5)); +global_asm!("mov eax, {}", const constfn(5) + constfn(5)); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +// only-x86_64 +// run-rustfix + +#![feature(asm, global_asm)] + +fn main() { + unsafe { + asm!("", options(nomem, )); + //~^ ERROR the `nomem` option was already provided + asm!("", options(att_syntax, )); + //~^ ERROR the `att_syntax` option was already provided + asm!("", options(nostack, att_syntax), options()); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, ), options(), options()); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(att_syntax, ), //~ ERROR the `noreturn` option was already provided + options( nostack), //~ ERROR the `nomem` option was already provided + options(), //~ ERROR the `noreturn` option was already provided + ); + } +} + +global_asm!("", options(att_syntax, )); +//~^ ERROR the `att_syntax` option was already provided diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +// only-x86_64 +// run-rustfix + +#![feature(asm, global_asm)] + +fn main() { + unsafe { + asm!("", options(nomem, nomem)); + //~^ ERROR the `nomem` option was already provided + asm!("", options(att_syntax, att_syntax)); + //~^ ERROR the `att_syntax` option was already provided + asm!("", options(nostack, att_syntax), options(nostack)); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, nostack), options(nostack), options(nostack)); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided + options(nomem, nostack), //~ ERROR the `nomem` option was already provided + options(noreturn), //~ ERROR the `noreturn` option was already provided + ); + } +} + +global_asm!("", options(att_syntax, att_syntax)); +//~^ ERROR the `att_syntax` option was already provided diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/duplicate-options.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,62 @@ +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:8:33 + | +LL | asm!("", options(nomem, nomem)); + | ^^^^^ this option was already provided + +error: the `att_syntax` option was already provided + --> $DIR/duplicate-options.rs:10:38 + | +LL | asm!("", options(att_syntax, att_syntax)); + | ^^^^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:12:56 + | +LL | asm!("", options(nostack, att_syntax), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:35 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:53 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:71 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:21:33 + | +LL | options(att_syntax, noreturn), + | ^^^^^^^^ this option was already provided + +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:22:21 + | +LL | options(nomem, nostack), + | ^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:23:21 + | +LL | options(noreturn), + | ^^^^^^^^ this option was already provided + +error: the `att_syntax` option was already provided + --> $DIR/duplicate-options.rs:28:37 + | +LL | global_asm!("", options(att_syntax, att_syntax)); + | ^^^^^^^^^^ this option was already provided + +error: aborting due to 10 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/interpolated-idents.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/interpolated-idents.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/interpolated-idents.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/interpolated-idents.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ +// only-x86_64 + +#![feature(asm)] + +macro_rules! m { + ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident + $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident + $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => { + unsafe { + asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + //~^ ERROR asm outputs are not allowed with the `noreturn` option + const x, sym x, + $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + //~| ERROR the `pure` and `noreturn` options are mutually exclusive + } + }; +} + +fn main() { + m!(in out lateout inout inlateout const sym + pure nomem readonly preserves_flags + noreturn nostack att_syntax options); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/interpolated-idents.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/interpolated-idents.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/interpolated-idents.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/interpolated-idents.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack att_syntax options); + | |___________________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack att_syntax options); + | |___________________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/interpolated-idents.rs:10:32 + | +LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ +... +LL | m!(in out lateout inout inlateout const sym + | _____- + | |_____| + | |_____| + | |_____| + | | +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack att_syntax options); + | | - + | |___________________________________________| + | |___________________________________________in this macro invocation + | |___________________________________________in this macro invocation + | |___________________________________________in this macro invocation + | in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/issue-82869.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/issue-82869.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/issue-82869.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/issue-82869.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +// only-x86_64 +// Make sure rustc doesn't ICE on asm! for a foreign architecture. + +#![feature(asm)] +#![crate_type = "rlib"] + +pub unsafe fn aarch64(a: f64, b: f64) -> f64 { + let c; + asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + || {}; + b + }); + //~^^^^ invalid register class + //~^^^^^ invalid register class + //~^^^^^^ invalid register + c +} + +pub unsafe fn x86(a: f64, b: f64) -> f64 { + let c; + asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b); + c +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/issue-82869.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/issue-82869.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/issue-82869.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/issue-82869.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ +error: invalid register class `vreg`: unknown register class + --> $DIR/issue-82869.rs:9:32 + | +LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + | ^^^^^^^^^^^ + +error: invalid register class `vreg`: unknown register class + --> $DIR/issue-82869.rs:9:45 + | +LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + | ^^^^^^^^^^ + +error: invalid register `d0`: unknown register + --> $DIR/issue-82869.rs:9:57 + | +LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + | _________________________________________________________^ +LL | | || {}; +LL | | b +LL | | }); + | |_____^ + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/parse-error.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/parse-error.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/parse-error.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/parse-error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,135 @@ +// only-x86_64 + +#![feature(asm, global_asm)] + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + asm!(); + //~^ ERROR requires at least a template string argument + asm!(foo); + //~^ ERROR asm template must be a string literal + asm!("{}" foo); + //~^ ERROR expected token: `,` + asm!("{}", foo); + //~^ ERROR expected operand, clobber_abi, options, or additional template string + asm!("{}", in foo); + //~^ ERROR expected `(`, found `foo` + asm!("{}", in(reg foo)); + //~^ ERROR expected `)`, found `foo` + asm!("{}", in(reg)); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", inout(=) foo => bar); + //~^ ERROR expected register class or explicit register + asm!("{}", inout(reg) foo =>); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", in(reg) foo => bar); + //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + asm!("{}", sym foo + bar); + //~^ ERROR argument to `sym` must be a path expression + asm!("", options(foo)); + //~^ ERROR expected one of + asm!("", options(nomem foo)); + //~^ ERROR expected one of + asm!("", options(nomem, foo)); + //~^ ERROR expected one of + asm!("{}", options(), const foo); + //~^ ERROR arguments are not allowed after options + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", clobber_abi(foo)); + //~^ ERROR expected string literal + asm!("", clobber_abi("C" foo)); + //~^ ERROR expected `)`, found `foo` + asm!("", clobber_abi("C", foo)); + //~^ ERROR expected `)`, found `,` + asm!("{}", clobber_abi("C"), const foo); + //~^ ERROR arguments are not allowed after clobber_abi + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), clobber_abi("C")); + //~^ ERROR clobber_abi is not allowed after options + asm!("{}", options(), clobber_abi("C"), const foo); + //~^ ERROR clobber_abi is not allowed after options + asm!("", clobber_abi("C"), clobber_abi("C")); + //~^ ERROR clobber_abi specified multiple times + asm!("{a}", a = const foo, a = const bar); + //~^ ERROR duplicate argument named `a` + //~^^ ERROR argument never used + //~^^^ ERROR attempt to use a non-constant value in a constant + //~^^^^ ERROR attempt to use a non-constant value in a constant + asm!("", a = in("eax") foo); + //~^ ERROR explicit register arguments cannot have names + asm!("{a}", in("eax") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{a}", in("eax") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{1}", in("eax") foo, const bar); + //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), ""); + //~^ ERROR expected one of + asm!("{}", in(reg) foo, "{}", out(reg) foo); + //~^ ERROR expected one of + asm!(format!("{{{}}}", 0), in(reg) foo); + //~^ ERROR asm template must be a string literal + asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + //~^ ERROR asm template must be a string literal + asm!("{}", in(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inout(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inlateout(reg) _); + //~^ ERROR _ cannot be used for input operands + } +} + +const FOO: i32 = 1; +const BAR: i32 = 2; +global_asm!(); +//~^ ERROR requires at least a template string argument +global_asm!(FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{}" FOO); +//~^ ERROR expected token: `,` +global_asm!("{}", FOO); +//~^ ERROR expected operand, options, or additional template string +global_asm!("{}", const); +//~^ ERROR expected expression, found end of macro arguments +global_asm!("{}", const(reg) FOO); +//~^ ERROR expected one of +global_asm!("", options(FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem, FOO)); +//~^ ERROR expected one of +global_asm!("{}", options(), const FOO); +//~^ ERROR arguments are not allowed after options +global_asm!("", clobber_abi(FOO)); +//~^ ERROR expected string literal +global_asm!("", clobber_abi("C" FOO)); +//~^ ERROR expected `)`, found `FOO` +global_asm!("", clobber_abi("C", FOO)); +//~^ ERROR expected `)`, found `,` +global_asm!("{}", clobber_abi("C"), const FOO); +//~^ ERROR arguments are not allowed after clobber_abi +//~^^ ERROR `clobber_abi` cannot be used with `global_asm!` +global_asm!("", options(), clobber_abi("C")); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("{}", options(), clobber_abi("C"), const FOO); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("", clobber_abi("C"), clobber_abi("C")); +//~^ ERROR clobber_abi specified multiple times +global_asm!("{a}", a = const FOO, a = const BAR); +//~^ ERROR duplicate argument named `a` +//~^^ ERROR argument never used +global_asm!("", options(), ""); +//~^ ERROR expected one of +global_asm!("{}", const FOO, "{}", const FOO); +//~^ ERROR expected one of +global_asm!(format!("{{{}}}", 0), const FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); +//~^ ERROR asm template must be a string literal diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/parse-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/parse-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/parse-error.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/parse-error.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,462 @@ +error: requires at least a template string argument + --> $DIR/parse-error.rs:9:9 + | +LL | asm!(); + | ^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:11:14 + | +LL | asm!(foo); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:13:19 + | +LL | asm!("{}" foo); + | ^^^ expected `,` + +error: expected operand, clobber_abi, options, or additional template string + --> $DIR/parse-error.rs:15:20 + | +LL | asm!("{}", foo); + | ^^^ expected operand, clobber_abi, options, or additional template string + +error: expected `(`, found `foo` + --> $DIR/parse-error.rs:17:23 + | +LL | asm!("{}", in foo); + | ^^^ expected `(` + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:19:27 + | +LL | asm!("{}", in(reg foo)); + | ^^^ expected `)` + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:21:27 + | +LL | asm!("{}", in(reg)); + | ^ expected expression + +error: expected register class or explicit register + --> $DIR/parse-error.rs:23:26 + | +LL | asm!("{}", inout(=) foo => bar); + | ^ + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:25:37 + | +LL | asm!("{}", inout(reg) foo =>); + | ^ expected expression + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + --> $DIR/parse-error.rs:27:32 + | +LL | asm!("{}", in(reg) foo => bar); + | ^^ expected one of 7 possible tokens + +error: argument to `sym` must be a path expression + --> $DIR/parse-error.rs:29:24 + | +LL | asm!("{}", sym foo + bar); + | ^^^^^^^^^ + +error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:31:26 + | +LL | asm!("", options(foo)); + | ^^^ expected one of 9 possible tokens + +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:33:32 + | +LL | asm!("", options(nomem foo)); + | ^^^ expected one of `)` or `,` + +error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:35:33 + | +LL | asm!("", options(nomem, foo)); + | ^^^ expected one of 9 possible tokens + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:37:31 + | +LL | asm!("{}", options(), const foo); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:40:30 + | +LL | asm!("", clobber_abi(foo)); + | ^^^ not a string literal + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:42:34 + | +LL | asm!("", clobber_abi("C" foo)); + | ^^^ expected `)` + +error: expected `)`, found `,` + --> $DIR/parse-error.rs:44:33 + | +LL | asm!("", clobber_abi("C", foo)); + | ^ expected `)` + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:46:38 + | +LL | asm!("{}", clobber_abi("C"), const foo); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:49:29 + | +LL | asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:51:31 + | +LL | asm!("{}", options(), clobber_abi("C"), const foo); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi specified multiple times + --> $DIR/parse-error.rs:53:36 + | +LL | asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | clobber_abi previously specified here + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:55:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:55:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: explicit register arguments cannot have names + --> $DIR/parse-error.rs:60:18 + | +LL | asm!("", a = in("eax") foo); + | ^^^^^^^^^^^^^^^^^ + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:62:36 + | +LL | asm!("{a}", in("eax") foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:65:36 + | +LL | asm!("{a}", in("eax") foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: positional arguments cannot follow named arguments or explicit register arguments + --> $DIR/parse-error.rs:68:36 + | +LL | asm!("{1}", in("eax") foo, const bar); + | ------------- ^^^^^^^^^ positional argument + | | + | explicit register argument + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` + --> $DIR/parse-error.rs:71:29 + | +LL | asm!("", options(), ""); + | ^^ expected one of 9 possible tokens + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:73:33 + | +LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); + | ^^^^ expected one of 9 possible tokens + +error: asm template must be a string literal + --> $DIR/parse-error.rs:75:14 + | +LL | asm!(format!("{{{}}}", 0), in(reg) foo); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:77:21 + | +LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:79:28 + | +LL | asm!("{}", in(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:81:31 + | +LL | asm!("{}", inout(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:83:35 + | +LL | asm!("{}", inlateout(reg) _); + | ^ + +error: requires at least a template string argument + --> $DIR/parse-error.rs:90:1 + | +LL | global_asm!(); + | ^^^^^^^^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:92:13 + | +LL | global_asm!(FOO); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:94:18 + | +LL | global_asm!("{}" FOO); + | ^^^ expected `,` + +error: expected operand, options, or additional template string + --> $DIR/parse-error.rs:96:19 + | +LL | global_asm!("{}", FOO); + | ^^^ expected operand, options, or additional template string + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:98:24 + | +LL | global_asm!("{}", const); + | ^ expected expression + +error: expected one of `,`, `.`, `?`, or an operator, found `FOO` + --> $DIR/parse-error.rs:100:30 + | +LL | global_asm!("{}", const(reg) FOO); + | ^^^ expected one of `,`, `.`, `?`, or an operator + +error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` + --> $DIR/parse-error.rs:102:25 + | +LL | global_asm!("", options(FOO)); + | ^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:104:25 + | +LL | global_asm!("", options(nomem FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:106:25 + | +LL | global_asm!("", options(nomem, FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:108:30 + | +LL | global_asm!("{}", options(), const FOO); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:110:29 + | +LL | global_asm!("", clobber_abi(FOO)); + | ^^^ not a string literal + +error: expected `)`, found `FOO` + --> $DIR/parse-error.rs:112:33 + | +LL | global_asm!("", clobber_abi("C" FOO)); + | ^^^ expected `)` + +error: expected `)`, found `,` + --> $DIR/parse-error.rs:114:32 + | +LL | global_asm!("", clobber_abi("C", FOO)); + | ^ expected `)` + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:116:37 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:116:19 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ^^^^^^^^^^^^^^^^ + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:119:28 + | +LL | global_asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:121:30 + | +LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi specified multiple times + --> $DIR/parse-error.rs:123:35 + | +LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | clobber_abi previously specified here + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:125:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:125:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: expected one of `clobber_abi`, `const`, or `options`, found `""` + --> $DIR/parse-error.rs:128:28 + | +LL | global_asm!("", options(), ""); + | ^^ expected one of `clobber_abi`, `const`, or `options` + +error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"` + --> $DIR/parse-error.rs:130:30 + | +LL | global_asm!("{}", const FOO, "{}", const FOO); + | ^^^^ expected one of `clobber_abi`, `const`, or `options` + +error: asm template must be a string literal + --> $DIR/parse-error.rs:132:13 + | +LL | global_asm!(format!("{{{}}}", 0), const FOO); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:134:20 + | +LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:37:37 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", options(), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:46:44 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", clobber_abi("C"), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:55:31 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:55:46 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:62:46 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("eax") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:65:46 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("eax") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:68:42 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{1}", in("eax") foo, const bar); + | ^^^ non-constant value + +error: aborting due to 66 previous errors + +For more information about this error, try `rustc --explain E0435`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/srcloc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/srcloc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/srcloc.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/srcloc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,124 @@ +// min-llvm-version: 10.0.1 +// only-x86_64 +// build-fail +// compile-flags: -Ccodegen-units=1 +#![feature(asm)] + +// Checks that inline asm errors are mapped to the correct line in the source code. + +fn main() { + unsafe { + asm!("invalid_instruction"); + //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(" + invalid_instruction + "); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(r#" + invalid_instruction + "#); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(" + mov eax, eax + invalid_instruction + mov eax, eax + "); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(r#" + mov eax, eax + invalid_instruction + mov eax, eax + "#); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(concat!("invalid", "_", "instruction")); + //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); + //~^ WARN: scale factor without index register is ignored + + asm!( + "invalid_instruction", + ); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax", + "invalid_instruction", + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax\n", + "invalid_instruction", + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax", + concat!("invalid", "_", "instruction"), + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + concat!("mov eax", ", ", "eax"), + concat!("invalid", "_", "instruction"), + concat!("mov eax", ", ", "eax"), + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + // Make sure template strings get separated + asm!( + "invalid_instruction1", + "invalid_instruction2", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + ); + //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", + ), + ); + //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' + //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", "\n", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", "\n", + ), + ); + //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' + //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/srcloc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/srcloc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/srcloc.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/srcloc.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,290 @@ +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:11:15 + | +LL | asm!("invalid_instruction"); + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:15:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:20:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:26:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:33:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:38:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +warning: scale factor without index register is ignored + --> $DIR/srcloc.rs:41:15 + | +LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); + | ^ + | +note: instantiated into assembly here + --> :1:23 + | +LL | movaps %xmm3, (%esi, 2) + | ^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:45:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:51:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:58:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:65:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:72:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:79:14 + | +LL | "invalid_instruction1", + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:80:14 + | +LL | "invalid_instruction2", + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:86:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:86:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:95:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:95:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:99:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:99:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:110:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:110:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:114:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:114:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :6:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 23 previous errors; 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/sym.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/sym.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/sym.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/sym.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,80 @@ +// min-llvm-version: 10.0.1 +// only-x86_64 +// only-linux +// run-pass + +#![feature(asm, thread_local)] + +extern "C" fn f1() -> i32 { + 111 +} + +// The compiler will generate a shim to hide the caller location parameter. +#[track_caller] +fn f2() -> i32 { + 222 +} + +macro_rules! call { + ($func:path) => { + unsafe { + let result: i32; + asm!("call {}", sym $func, + out("rax") result, + out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _, + out("r8") _, out("r9") _, out("r10") _, out("r11") _, + out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _, + out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _, + out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _, + out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _, + ); + result + } + } +} + +macro_rules! static_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + // LEA performs a RIP-relative address calculation and returns the address + asm!("lea {}, [rip + {}]", out(reg) result, sym $s); + result + } + } +} +macro_rules! static_tls_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + " + # Load TLS base address + mov {out}, qword ptr fs:[0] + # Calculate the address of sym in the TLS block. The @tpoff + # relocation gives the offset of the symbol from the start + # of the TLS block. + lea {out}, [{out} + {sym}@tpoff] + ", + out = out(reg) result, + sym = sym $s + ); + result + } + } +} + +static S1: u32 = 111; +#[thread_local] +static S2: u32 = 222; + +fn main() { + assert_eq!(call!(f1), 111); + assert_eq!(call!(f2), 222); + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + std::thread::spawn(|| { + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + }).join().unwrap(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/target-feature-attr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/target-feature-attr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/target-feature-attr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/target-feature-attr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,40 @@ +// only-x86_64 + +#![feature(asm, avx512_target_feature)] + +#[target_feature(enable = "avx")] +unsafe fn foo() { + let mut x = 1; + let y = 2; + asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + assert_eq!(x, 3); +} + +unsafe fn bar() { + let mut x = 1; + let y = 2; + asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + //~^ ERROR: register class `ymm_reg` requires the `avx` target feature + //~| ERROR: register class `ymm_reg` requires the `avx` target feature + //~| ERROR: register class `ymm_reg` requires the `avx` target feature + assert_eq!(x, 3); +} + +#[target_feature(enable = "avx512bw")] +unsafe fn baz() { + let x = 1; + asm!("/* {0} */", in(kreg) x); +} + +unsafe fn baz2() { + let x = 1; + asm!("/* {0} */", in(kreg) x); + //~^ ERROR: register class `kreg` requires at least one of the following target features: avx512bw, avx512f +} + +fn main() { + unsafe { + foo(); + bar(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/target-feature-attr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/target-feature-attr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/target-feature-attr.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/target-feature-attr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +error: register class `ymm_reg` requires the `avx` target feature + --> $DIR/target-feature-attr.rs:16:40 + | +LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + | ^^^^^^^^^^^^^ + +error: register class `ymm_reg` requires the `avx` target feature + --> $DIR/target-feature-attr.rs:16:55 + | +LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + | ^^^^^^^^^^^^^ + +error: register class `ymm_reg` requires the `avx` target feature + --> $DIR/target-feature-attr.rs:16:70 + | +LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + | ^^^^^^^^^^^^^^^^^^ + +error: register class `kreg` requires at least one of the following target features: avx512bw, avx512f + --> $DIR/target-feature-attr.rs:31:23 + | +LL | asm!("/* {0} */", in(kreg) x); + | ^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,80 @@ +// only-x86_64 + +#![feature(asm, repr_simd, never_type)] + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + //~^ ERROR use of possibly-uninitialized variable: `x` + let mut y: u64; + asm!("{}", inout(reg) y); + //~^ ERROR use of possibly-uninitialized variable: `y` + let _ = y; + + // Outputs require mutable places + + let v: Vec = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + asm!("{}", inout(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + + // Sym operands must point to a function or static + + const C: i32 = 0; + static S: i32 = 0; + asm!("{}", sym S); + asm!("{}", sym main); + asm!("{}", sym C); + //~^ ERROR asm `sym` operand must point to a fn or static + asm!("{}", sym x); + //~^ ERROR asm `sym` operand must point to a fn or static + + // Register operands must be Copy + + asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + //~^ ERROR arguments for inline assembly must be copyable + + // Register operands must be integers, floats, SIMD vectors, pointers or + // function pointers. + + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps()); + asm!("{}", in(reg) 0 as *const u8); + asm!("{}", in(reg) 0 as *mut u8); + asm!("{}", in(reg) main as fn()); + asm!("{}", in(reg) |x: i32| x); + //~^ ERROR cannot use value of type + asm!("{}", in(reg) vec![0]); + //~^ ERROR cannot use value of type `Vec` for inline assembly + asm!("{}", in(reg) (1, 2, 3)); + //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly + asm!("{}", in(reg) [1, 2, 3]); + //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly + + // Register inputs (but not outputs) allow references and function types + + let mut f = main; + let mut r = &mut 0; + asm!("{}", in(reg) f); + asm!("{}", inout(reg) f); + //~^ ERROR cannot use value of type `fn() {main}` for inline assembly + asm!("{}", in(reg) r); + asm!("{}", inout(reg) r); + //~^ ERROR cannot use value of type `&mut i32` for inline assembly + let _ = (f, r); + + // Type checks ignore never type + + let u: ! = unreachable!(); + asm!("{}", in(reg) u); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-2.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,103 @@ +error: arguments for inline assembly must be copyable + --> $DIR/type-check-2.rs:42:32 + | +LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `SimdNonCopy` does not implement the Copy trait + +error: cannot use value of type `[closure@$DIR/type-check-2.rs:54:28: 54:38]` for inline assembly + --> $DIR/type-check-2.rs:54:28 + | +LL | asm!("{}", in(reg) |x: i32| x); + | ^^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `Vec` for inline assembly + --> $DIR/type-check-2.rs:56:28 + | +LL | asm!("{}", in(reg) vec![0]); + | ^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use value of type `(i32, i32, i32)` for inline assembly + --> $DIR/type-check-2.rs:58:28 + | +LL | asm!("{}", in(reg) (1, 2, 3)); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[i32; 3]` for inline assembly + --> $DIR/type-check-2.rs:60:28 + | +LL | asm!("{}", in(reg) [1, 2, 3]); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `fn() {main}` for inline assembly + --> $DIR/type-check-2.rs:68:31 + | +LL | asm!("{}", inout(reg) f); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `&mut i32` for inline assembly + --> $DIR/type-check-2.rs:71:31 + | +LL | asm!("{}", inout(reg) r); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: asm `sym` operand must point to a fn or static + --> $DIR/type-check-2.rs:35:24 + | +LL | asm!("{}", sym C); + | ^ + +error: asm `sym` operand must point to a fn or static + --> $DIR/type-check-2.rs:37:24 + | +LL | asm!("{}", sym x); + | ^ + +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/type-check-2.rs:13:28 + | +LL | asm!("{}", in(reg) x); + | ^ use of possibly-uninitialized `x` + +error[E0381]: use of possibly-uninitialized variable: `y` + --> $DIR/type-check-2.rs:16:9 + | +LL | asm!("{}", inout(reg) y); + | ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2.rs:24:29 + | +LL | let v: Vec = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +LL | asm!("{}", in(reg) v[0]); +LL | asm!("{}", out(reg) v[0]); + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2.rs:26:31 + | +LL | let v: Vec = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +... +LL | asm!("{}", inout(reg) v[0]); + | ^ cannot borrow as mutable + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0381, E0596. +For more information about an error, try `rustc --explain E0381`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-3.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-3.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,89 @@ +// only-x86_64 +// compile-flags: -C target-feature=+avx512f + +#![feature(asm, global_asm)] + +use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps}; + +fn main() { + unsafe { + // Types must be listed in the register class. + + asm!("{}", in(reg) 0i128); + //~^ ERROR type `i128` cannot be used with this register class + asm!("{}", in(reg) _mm_setzero_ps()); + //~^ ERROR type `__m128` cannot be used with this register class + asm!("{}", in(reg) _mm256_setzero_ps()); + //~^ ERROR type `__m256` cannot be used with this register class + asm!("{}", in(xmm_reg) 0u8); + //~^ ERROR type `u8` cannot be used with this register class + asm!("{:e}", in(reg) 0i32); + asm!("{}", in(xmm_reg) 0i32); + asm!("{:e}", in(reg) 0f32); + asm!("{}", in(xmm_reg) 0f32); + asm!("{}", in(xmm_reg) _mm_setzero_ps()); + asm!("{:x}", in(ymm_reg) _mm_setzero_ps()); + asm!("{}", in(kreg) 0u16); + asm!("{}", in(kreg) 0u64); + //~^ ERROR `avx512bw` target feature is not enabled + + // Template modifier suggestions for sub-registers + + asm!("{0} {0}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{0} {0:x}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i64); + asm!("{}", in(ymm_reg) 0i64); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(ymm_reg) _mm256_setzero_ps()); + asm!("{:l}", in(reg) 0i16); + asm!("{:l}", in(reg) 0i32); + asm!("{:l}", in(reg) 0i64); + asm!("{:x}", in(ymm_reg) 0i64); + asm!("{:x}", in(ymm_reg) _mm256_setzero_ps()); + + // Suggest different register class for type + + asm!("{}", in(reg) 0i8); + //~^ ERROR type `i8` cannot be used with this register class + asm!("{}", in(reg_byte) 0i8); + + // Split inout operands must have compatible types + + let mut val_i16: i16; + let mut val_f32: f32; + let mut val_u32: u32; + let mut val_u64: u64; + let mut val_ptr: *mut u8; + asm!("{:r}", inout(reg) 0u16 => val_i16); + asm!("{:r}", inout(reg) 0u32 => val_f32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) 0u32 => val_ptr); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) main => val_u32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) 0u64 => val_ptr); + asm!("{:r}", inout(reg) main => val_u64); + } +} + +// Constants must be... constant + +static S: i32 = 1; +const fn const_foo(x: i32) -> i32 { + x +} +const fn const_bar(x: T) -> T { + x +} +global_asm!("{}", const S); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_foo(0)); +global_asm!("{}", const const_foo(S)); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_bar(0)); +global_asm!("{}", const const_bar(S)); +//~^ ERROR constants cannot refer to statics diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-3.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/asm/x86_64/type-check-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,143 @@ +error: type `i128` cannot be used with this register class + --> $DIR/type-check-3.rs:12:28 + | +LL | asm!("{}", in(reg) 0i128); + | ^^^^^ + | + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + +error: type `__m128` cannot be used with this register class + --> $DIR/type-check-3.rs:14:28 + | +LL | asm!("{}", in(reg) _mm_setzero_ps()); + | ^^^^^^^^^^^^^^^^ + | + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + +error: type `__m256` cannot be used with this register class + --> $DIR/type-check-3.rs:16:28 + | +LL | asm!("{}", in(reg) _mm256_setzero_ps()); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + +error: type `u8` cannot be used with this register class + --> $DIR/type-check-3.rs:18:32 + | +LL | asm!("{}", in(xmm_reg) 0u8); + | ^^^ + | + = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + +error: `avx512bw` target feature is not enabled + --> $DIR/type-check-3.rs:27:29 + | +LL | asm!("{}", in(kreg) 0u64); + | ^^^^ + | + = note: this is required to use type `u64` with register class `kreg` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:32:15 + | +LL | asm!("{0} {0}", in(reg) 0i16); + | ^^^ ^^^ ---- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `x` modifier to have the register formatted as `ax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:34:15 + | +LL | asm!("{0} {0:x}", in(reg) 0i16); + | ^^^ ---- for this argument + | + = help: use the `x` modifier to have the register formatted as `ax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:36:15 + | +LL | asm!("{}", in(reg) 0i32); + | ^^ ---- for this argument + | + = help: use the `e` modifier to have the register formatted as `eax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:39:15 + | +LL | asm!("{}", in(ymm_reg) 0i64); + | ^^ ---- for this argument + | + = help: use the `x` modifier to have the register formatted as `xmm0` + = help: or use the `y` modifier to keep the default formatting of `ymm0` + +error: type `i8` cannot be used with this register class + --> $DIR/type-check-3.rs:50:28 + | +LL | asm!("{}", in(reg) 0i8); + | ^^^ + | + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = help: consider using the `reg_byte` register class instead + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:62:33 + | +LL | asm!("{:r}", inout(reg) 0u32 => val_f32); + | ^^^^ ^^^^^^^ type `f32` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:64:33 + | +LL | asm!("{:r}", inout(reg) 0u32 => val_ptr); + | ^^^^ ^^^^^^^ type `*mut u8` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:66:33 + | +LL | asm!("{:r}", inout(reg) main => val_u32); + | ^^^^ ^^^^^^^ type `u32` + | | + | type `fn()` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:82:25 + | +LL | global_asm!("{}", const S); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:85:35 + | +LL | global_asm!("{}", const const_foo(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:88:35 + | +LL | global_asm!("{}", const const_bar(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 12 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0013`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/assignment-operator-unimplemented.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/assignment-operator-unimplemented.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/assignment-operator-unimplemented.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/assignment-operator-unimplemented.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,22 @@ | | | cannot use `+=` on type `Foo` | - = note: an implementation of `std::ops::AddAssign` might be missing for `Foo` +note: an implementation of `AddAssign<_>` might be missing for `Foo` + --> $DIR/assignment-operator-unimplemented.rs:1:1 + | +LL | struct Foo; + | ^^^^^^^^^^^ must implement `AddAssign<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait AddAssign { +LL | | /// Performs the `+=` operation. +LL | | /// +LL | | /// # Example +... | +LL | | fn add_assign(&mut self, rhs: Rhs); +LL | | } + | |_^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,12 +16,12 @@ | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated constant for candidate #1 | -LL | const X: i32 = Foo::ID; - | ~~~~~ +LL | const X: i32 = ::ID; + | ~~~~~~~~~~~~~~ help: disambiguate the associated constant for candidate #2 | -LL | const X: i32 = Bar::ID; - | ~~~~~ +LL | const X: i32 = ::ID; + | ~~~~~~~~~~~~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected reference `&'static str` found reference `&'a str` -note: the lifetime `'a` as defined on the impl at 6:6... +note: the lifetime `'a` as defined here... --> $DIR/associated-const-impl-wrong-lifetime.rs:6:6 | LL | impl<'a> Foo for &'a () { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-in-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-in-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-in-trait.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-consts/associated-const-in-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | impl dyn Trait { | ^^^^^^^^^ `Trait` cannot be made into an object | - = help: consider moving `N` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/associated-const-in-trait.rs:6:11 | @@ -12,6 +11,7 @@ | ----- this trait cannot be made into an object... LL | const N: usize; | ^ ...because it contains this associated `const` + = help: consider moving `N` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,7 +20,7 @@ --> $DIR/defaults-not-assumed-fail.rs:34:5 | LL | assert_eq!(<() as Tr>::B, 0); // causes the error above - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-item/issue-48027.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-item/issue-48027.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-item/issue-48027.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-item/issue-48027.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -21,7 +21,6 @@ LL | impl dyn Bar {} | ^^^^^^^ `Bar` cannot be made into an object | - = help: consider moving `X` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-48027.rs:2:11 | @@ -29,6 +28,7 @@ | --- this trait cannot be made into an object... LL | const X: usize; | ^ ...because it contains this associated `const` + = help: consider moving `X` to another trait error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-referencing.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-referencing.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-referencing.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-referencing.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -// check-pass - -// The goal of this test is to ensure that T: Bar -// in the where clause does not cycle - -trait Foo { - type Item; -} - -trait Bar {} - -fn baz() -where - T: Foo, - T: Bar, -{ -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-referencing.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-referencing.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-referencing.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-referencing.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +// check-pass + +// The goal of this test is to ensure that T: Bar +// in the where clause does not cycle + +trait Foo { + type Item; +} + +trait Bar {} + +fn baz() +where + T: Foo, + T: Bar, +{ +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -// check-pass -trait Foo { - type Bar; -} -trait Qux: Foo + AsRef {} -trait Foo2 {} - -trait Qux2: Foo2 + AsRef { - type Bar; -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-referencing-self.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-referencing-self.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-referencing-self.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-referencing-self.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// check-pass +trait Foo { + type Bar; +} +trait Qux: Foo + AsRef {} +trait Foo2 {} + +trait Qux2: Foo2 + AsRef { + type Bar; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -// check-pass - -// Test that we do not get a cycle due to -// resolving `Self::Bar` in the where clauses -// on a trait definition (in particular, in -// a where clause that is defining a superpredicate). - -trait Foo { - type Bar; -} -trait Qux -where - Self: Foo, - Self: AsRef, -{ -} -trait Foo2 {} - -trait Qux2 -where - Self: Foo2, - Self: AsRef, -{ - type Bar; -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-where-referencing-self.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-where-referencing-self.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-where-referencing-self.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/supertrait-where-referencing-self.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,27 @@ +// check-pass + +// Test that we do not get a cycle due to +// resolving `Self::Bar` in the where clauses +// on a trait definition (in particular, in +// a where clause that is defining a superpredicate). + +trait Foo { + type Bar; +} +trait Qux +where + Self: Foo, + Self: AsRef, +{ +} +trait Foo2 {} + +trait Qux2 +where + Self: Foo2, + Self: AsRef, +{ + type Bar; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // check-pass -// compile-flags:-Cincremental=tmp/traits-assoc-type-macros +// incremental // This test case makes sure that we can compile with incremental compilation // enabled when there are macros, traits, inheritance and associated types involved. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,11 +13,11 @@ help: use fully qualified syntax to disambiguate | LL | fn a(_: ::Color) { - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | fn a(_: ::Color) { - | ~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:20:12 @@ -34,11 +34,11 @@ help: use fully qualified syntax to disambiguate | LL | fn b(_: ::Color) where C : Vehicle+Box { - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | fn b(_: ::Color) where C : Vehicle+Box { - | ~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:24:12 @@ -55,11 +55,11 @@ help: use fully qualified syntax to disambiguate | LL | fn c(_: ::Color) where C : Vehicle, C : Box { - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | fn c(_: ::Color) where C : Vehicle, C : Box { - | ~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:35:20 @@ -76,11 +76,11 @@ help: use fully qualified syntax to disambiguate | LL | fn e(&self, _: ::Color) where X : Box; - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | fn e(&self, _: ::Color) where X : Box; - | ~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:38:20 @@ -97,11 +97,11 @@ help: use fully qualified syntax to disambiguate | LL | fn f(&self, _: ::Color) where X : Box { } - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | fn f(&self, _: ::Color) where X : Box { } - | ~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:30:20 @@ -118,11 +118,11 @@ help: use fully qualified syntax to disambiguate | LL | fn d(&self, _: ::Color) where X : Box { } - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | fn d(&self, _: ::Color) where X : Box { } - | ~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -21,11 +21,11 @@ help: use fully qualified syntax to disambiguate | LL | fn dent(c: C, color: ::Color) { - | ~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | fn dent(c: C, color: ::Color) { - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error[E0222]: ambiguous associated type `Color` in bounds of `BoxCar` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:37 @@ -74,11 +74,11 @@ help: use fully qualified syntax to disambiguate | LL | fn paint(c: C, d: ::Color) { - | ~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | fn paint(c: C, d: ::Color) { - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error[E0191]: the value of the associated types `Color` (from trait `Box`), `Color` (from trait `Vehicle`) must be specified --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:32 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-bound-failure.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-bound-failure.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-bound-failure.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-bound-failure.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/associated-types-bound-failure.rs:19:19 | LL | ToInt::to_int(&g.get()) - | ^^^^^^^^ the trait `ToInt` is not implemented for `::R` + | ------------- ^^^^^^^^ the trait `ToInt` is not implemented for `::R` + | | + | required by a bound introduced by this call | note: required by `ToInt::to_int` --> $DIR/associated-types-bound-failure.rs:6:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-doubleendediterator-object.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-doubleendediterator-object.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-doubleendediterator-object.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-doubleendediterator-object.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn pairwise_sub(mut t: Box>) -> isize { let mut result = 0; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -19,11 +19,11 @@ help: use fully qualified syntax to disambiguate | LL | pub fn f2(a: T, x: ::A) {} - | ~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | pub fn f2(a: T, x: ::A) {} - | ~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -28,13 +28,11 @@ pub fn f1_uint_uint() { f1(2u32, 4u32); //~^ ERROR `u32: Foo` is not satisfied - //~| ERROR `u32: Foo` is not satisfied } pub fn f1_uint_int() { f1(2u32, 4i32); //~^ ERROR `u32: Foo` is not satisfied - //~| ERROR `u32: Foo` is not satisfied } pub fn f2_int() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-path-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,13 +7,15 @@ help: change the type of the numeric literal from `i32` to `u32` | LL | f1(2i32, 4u32); - | ~~~~ + | ~~~ error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:29:5 + --> $DIR/associated-types-path-2.rs:29:14 | LL | f1(2u32, 4u32); - | ^^ the trait `Foo` is not implemented for `u32` + | -- ^^^^ the trait `Foo` is not implemented for `u32` + | | + | required by a bound introduced by this call | note: required by a bound in `f1` --> $DIR/associated-types-path-2.rs:13:14 @@ -22,16 +24,12 @@ | ^^^ required by this bound in `f1` error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:29:5 - | -LL | f1(2u32, 4u32); - | ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32` - -error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:35:5 + --> $DIR/associated-types-path-2.rs:34:14 | LL | f1(2u32, 4i32); - | ^^ the trait `Foo` is not implemented for `u32` + | -- ^^^^ the trait `Foo` is not implemented for `u32` + | | + | required by a bound introduced by this call | note: required by a bound in `f1` --> $DIR/associated-types-path-2.rs:13:14 @@ -39,14 +37,8 @@ LL | pub fn f1(a: T, x: T::A) {} | ^^^ required by this bound in `f1` -error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:35:5 - | -LL | f1(2u32, 4i32); - | ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32` - error[E0308]: mismatched types - --> $DIR/associated-types-path-2.rs:41:18 + --> $DIR/associated-types-path-2.rs:39:18 | LL | let _: i32 = f2(2i32); | --- ^^^^^^^^ expected `i32`, found `u32` @@ -56,9 +48,9 @@ help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | let _: i32 = f2(2i32).try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,12 @@ --> $DIR/associated-types-project-from-hrtb-in-fn.rs:13:8 | LL | x: I::A) - | ^^^^ help: use a fully qualified path with inferred lifetimes: `>::A` + | ^^^^ + | +help: use a fully qualified path with inferred lifetimes + | +LL | x: >::A) + | ~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,23 @@ --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:13:32 | LL | fn some_method(&self, arg: I::A); - | ^^^^ help: use a fully qualified path with inferred lifetimes: `>::A` + | ^^^^ + | +help: use a fully qualified path with inferred lifetimes + | +LL | fn some_method(&self, arg: >::A); + | ~~~~~~~~~~~~~~~~~~~~ error[E0212]: cannot use the associated type of a trait with uninferred generic parameters --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:32:24 | LL | fn mango(&self) -> X::Assoc { - | ^^^^^^^^ help: use a fully qualified path with inferred lifetimes: `>::Assoc` + | ^^^^^^^^ + | +help: use a fully qualified path with inferred lifetimes + | +LL | fn mango(&self) -> >::Assoc { + | ~~~~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | bar(foo, x) | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | bar(foo, x) | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,6 +6,11 @@ | = note: expected reference `&'a ()` found reference `&()` +note: the lifetime requirement is introduced here + --> $DIR/higher-ranked-projection.rs:15:33 + | +LL | where for<'a> &'a T: Mirror + | ^^^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/hr-associated-type-bound-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/hr-associated-type-bound-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/hr-associated-type-bound-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/hr-associated-type-bound-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ LL | | } | |_^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`hr_associated_type_bound_2`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hr_associated_type_bound_2`) note: required because of the requirements on the impl of `for<'b> X<'b>` for `u32` --> $DIR/hr-associated-type-bound-2.rs:11:6 | @@ -24,7 +24,7 @@ LL | type U = str; | ^^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`hr_associated_type_bound_2`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hr_associated_type_bound_2`) note: required because of the requirements on the impl of `for<'b> X<'b>` for `u32` --> $DIR/hr-associated-type-bound-2.rs:11:6 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/impl-wf-cycle-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/impl-wf-cycle-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/impl-wf-cycle-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/impl-wf-cycle-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -15,7 +15,7 @@ | LL | impl Grault for (T,) | ^^^^^^ ^^^^ - = note: 1 redundant requirements hidden + = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Grault` for `(T,)` error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` @@ -29,7 +29,7 @@ | LL | impl Grault for (T,) | ^^^^^^ ^^^^ - = note: 1 redundant requirements hidden + = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Grault` for `(T,)` error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` @@ -43,7 +43,7 @@ | LL | impl Grault for (T,) | ^^^^^^ ^^^^ - = note: 1 redundant requirements hidden + = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Grault` for `(T,)` error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-19883.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-19883.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-19883.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-19883.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +trait From { + type Output; + + fn from(src: Src) -> >::Output; +} + +trait To: Sized { + fn to>(self) -> + >::Dst + //~^ ERROR cannot find associated type `Dst` in trait `From` + { + From::from(self) + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-19883.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-19883.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-19883.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-19883.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0576]: cannot find associated type `Dst` in trait `From` + --> $DIR/issue-19883.rs:9:30 + | +LL | type Output; + | ------------ associated type `Output` defined here +... +LL | >::Dst + | ^^^ + | | + | not found in `From` + | help: maybe you meant this associated type: `Output` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0576`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-21363.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-21363.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-21363.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-21363.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +// check-pass +// pretty-expanded FIXME #23616 + +#![no_implicit_prelude] + +trait Iterator { + type Item; + fn dummy(&self) { } +} + +impl<'a, T> Iterator for &'a mut (dyn Iterator + 'a) { + type Item = T; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-22560.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-22560.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-22560.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-22560.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -32,7 +32,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-27675-unchecked-bounds.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-27675-unchecked-bounds.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-27675-unchecked-bounds.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-27675-unchecked-bounds.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-27675-unchecked-bounds.rs:15:31 | LL | copy::>(t) - | ^ the trait `Copy` is not implemented for `T` + | ------------------------- ^ the trait `Copy` is not implemented for `T` + | | + | required by a bound introduced by this call | note: required by a bound in `copy` --> $DIR/issue-27675-unchecked-bounds.rs:10:12 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-36499.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-36499.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/issue-36499.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/issue-36499.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,14 @@ -error: expected expression, found `+` +error: leading `+` is not supported --> $DIR/issue-36499.rs:4:9 | LL | 2 + +2; - | ^ expected expression + | ^ unexpected `+` + | +help: try removing the `+` + | +LL - 2 + +2; +LL + 2 + 2; + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/missing-associated-types.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/missing-associated-types.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/associated-types/missing-associated-types.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/associated-types/missing-associated-types.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + X + Y {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub + X + Y {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `Add`), `Output` (from trait `Mul`), `Output` (from trait `Sub`) must be specified @@ -35,7 +35,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + X + Z {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub + X + Z {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `Add`), `Output` (from trait `Div`), `Output` (from trait `Div`), `Output` (from trait `Mul`), `Output` (from trait `Sub`) must be specified @@ -71,7 +71,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + Y {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub + Y {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified @@ -99,7 +99,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + Fine {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub + Fine {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/auxiliary/issue-72470-lib.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/auxiliary/issue-72470-lib.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/auxiliary/issue-72470-lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/auxiliary/issue-72470-lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,175 @@ +// compile-flags: -C opt-level=3 +// edition:2018 + +use std::future::Future; +use std::marker::PhantomData; +use std::pin::Pin; +use std::sync::atomic::AtomicUsize; +use std::sync::Arc; +use std::task::Poll::{Pending, Ready}; +use std::task::Waker; +use std::task::{Context, Poll}; +use std::{ + ptr, + task::{RawWaker, RawWakerVTable}, +}; + +/// Future for the [`poll_fn`] function. +pub struct PollFn { + f: F, +} + +impl Unpin for PollFn {} + +/// Creates a new future wrapping around a function returning [`Poll`]. +pub fn poll_fn(f: F) -> PollFn +where + F: FnMut(&mut Context<'_>) -> Poll, +{ + PollFn { f } +} + +impl Future for PollFn +where + F: FnMut(&mut Context<'_>) -> Poll, +{ + type Output = T; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + (&mut self.f)(cx) + } +} +pub fn run(future: F) -> F::Output { + BasicScheduler.block_on(future) +} + +pub(crate) struct BasicScheduler; + +impl BasicScheduler { + pub(crate) fn block_on(&mut self, mut future: F) -> F::Output + where + F: Future, + { + let waker = unsafe { Waker::from_raw(raw_waker()) }; + let mut cx = std::task::Context::from_waker(&waker); + + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + loop { + if let Ready(v) = future.as_mut().poll(&mut cx) { + return v; + } + } + } +} + +// ===== impl Spawner ===== + +fn raw_waker() -> RawWaker { + RawWaker::new(ptr::null(), waker_vtable()) +} + +fn waker_vtable() -> &'static RawWakerVTable { + &RawWakerVTable::new( + clone_arc_raw, + wake_arc_raw, + wake_by_ref_arc_raw, + drop_arc_raw, + ) +} + +unsafe fn clone_arc_raw(_: *const ()) -> RawWaker { + raw_waker() +} + +unsafe fn wake_arc_raw(_: *const ()) {} + +unsafe fn wake_by_ref_arc_raw(_: *const ()) {} + +unsafe fn drop_arc_raw(_: *const ()) {} + +struct AtomicWaker {} + +impl AtomicWaker { + /// Create an `AtomicWaker` + fn new() -> AtomicWaker { + AtomicWaker {} + } + + fn register_by_ref(&self, _waker: &Waker) {} +} + +#[allow(dead_code)] +struct Tx { + inner: Arc>, +} + +struct Rx { + inner: Arc>, +} + +#[allow(dead_code)] +struct Chan { + tx: PhantomData, + semaphore: Sema, + rx_waker: AtomicWaker, + rx_closed: bool, +} + +fn channel() -> (Tx, Rx) { + let chan = Arc::new(Chan { + tx: PhantomData, + semaphore: Sema(AtomicUsize::new(0)), + rx_waker: AtomicWaker::new(), + rx_closed: false, + }); + + ( + Tx { + inner: chan.clone(), + }, + Rx { inner: chan }, + ) +} + +// ===== impl Rx ===== + +impl Rx { + /// Receive the next value + fn recv(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.rx_waker.register_by_ref(cx.waker()); + + if self.inner.rx_closed && self.inner.semaphore.is_idle() { + Ready(None) + } else { + Pending + } + } +} + +struct Sema(AtomicUsize); + +impl Sema { + fn is_idle(&self) -> bool { + false + } +} + +pub struct UnboundedReceiver { + chan: Rx, +} + +pub fn unbounded_channel() -> UnboundedReceiver { + let (tx, rx) = channel(); + + drop(tx); + let rx = UnboundedReceiver { chan: rx }; + + rx +} + +impl UnboundedReceiver { + pub async fn recv(&mut self) -> Option { + poll_fn(|cx| self.chan.recv(cx)).await + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-61452.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-61452.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-61452.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-61452.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | pub async fn f(x: Option) { | - help: consider changing this to be mutable: `mut x` LL | x.take(); - | ^ cannot borrow as mutable + | ^^^^^^^^ cannot borrow as mutable error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/issue-61452.rs:9:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-64130-non-send-future-diags.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-64130-non-send-future-diags.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-64130-non-send-future-diags.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-64130-non-send-future-diags.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ // edition:2018 +#![feature(must_not_suspend)] +#![allow(must_not_suspend)] // This tests the basic example case for the async-await-specific error. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/issue-64130-non-send-future-diags.rs:21:5 + --> $DIR/issue-64130-non-send-future-diags.rs:23:5 | LL | is_send(foo()); | ^^^^^^^ future returned by `foo` is not `Send` | = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>` note: future is not `Send` as this value is used across an await - --> $DIR/issue-64130-non-send-future-diags.rs:15:5 + --> $DIR/issue-64130-non-send-future-diags.rs:17:5 | LL | let g = x.lock().unwrap(); | - has type `MutexGuard<'_, u32>` which is not `Send` @@ -15,7 +15,7 @@ LL | } | - `g` is later dropped here note: required by a bound in `is_send` - --> $DIR/issue-64130-non-send-future-diags.rs:7:15 + --> $DIR/issue-64130-non-send-future-diags.rs:9:15 | LL | fn is_send(t: T) { } | ^^^^ required by this bound in `is_send` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-71137.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-71137.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-71137.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-71137.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ // edition:2018 +#![feature(must_not_suspend)] +#![allow(must_not_suspend)] use std::future::Future; use std::sync::Mutex; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-71137.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-71137.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-71137.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-71137.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/issue-71137.rs:20:3 + --> $DIR/issue-71137.rs:22:3 | LL | fake_spawn(wrong_mutex()); | ^^^^^^^^^^ future returned by `wrong_mutex` is not `Send` | = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>` note: future is not `Send` as this value is used across an await - --> $DIR/issue-71137.rs:12:5 + --> $DIR/issue-71137.rs:14:5 | LL | let mut guard = m.lock().unwrap(); | --------- has type `MutexGuard<'_, i32>` which is not `Send` @@ -16,7 +16,7 @@ LL | } | - `mut guard` is later dropped here note: required by a bound in `fake_spawn` - --> $DIR/issue-71137.rs:6:27 + --> $DIR/issue-71137.rs:8:27 | LL | fn fake_spawn(f: F) { } | ^^^^ required by this bound in `fake_spawn` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-72442.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-72442.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-72442.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-72442.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // edition:2018 -// compile-flags:-Cincremental=tmp/issue-72442 +// incremental use std::fs::File; use std::future::Future; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-72442.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-72442.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-72442.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-72442.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-72442.rs:12:36 | LL | let mut f = File::open(path.to_str())?; - | ^^^^^^^^^^^^^ the trait `AsRef` is not implemented for `Option<&str>` + | ---------- ^^^^^^^^^^^^^ the trait `AsRef` is not implemented for `Option<&str>` + | | + | required by a bound introduced by this call | note: required by a bound in `File::open` --> $SRC_DIR/std/src/fs.rs:LL:COL diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-72470-llvm-dominate.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-72470-llvm-dominate.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-72470-llvm-dominate.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-72470-llvm-dominate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,66 @@ +// compile-flags: -C opt-level=3 +// aux-build: issue-72470-lib.rs +// edition:2018 +// build-pass + +// Regression test for issue #72470, using the minimization +// in https://github.com/jonas-schievink/llvm-error + +extern crate issue_72470_lib; + +use std::future::Future; +use std::pin::Pin; +use std::sync::Mutex; +use std::task::Poll::{Pending, Ready}; + +#[allow(dead_code)] +enum Msg { + A(Vec<()>), + B, +} + +#[allow(dead_code)] +enum Out { + _0(Option), + Disabled, +} + +#[allow(unused_must_use)] +fn main() { + let mut rx = issue_72470_lib::unbounded_channel::(); + let entity = Mutex::new(()); + issue_72470_lib::run(async move { + { + let output = { + let mut fut = rx.recv(); + issue_72470_lib::poll_fn(|cx| { + loop { + let fut = unsafe { Pin::new_unchecked(&mut fut) }; + let out = match fut.poll(cx) { + Ready(out) => out, + Pending => { + break; + } + }; + #[allow(unused_variables)] + match &out { + Some(_msg) => {} + _ => break, + } + return Ready(Out::_0(out)); + } + Ready(Out::_0(None)) + }) + .await + }; + match output { + Out::_0(Some(_msg)) => { + entity.lock(); + } + Out::_0(None) => unreachable!(), + _ => unreachable!(), + } + } + entity.lock(); + }); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-73541-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-73541-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-73541-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-73541-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | ^^ unreachable label `'a` ... LL | b!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: labels are unreachable through functions, closures, async blocks and modules = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-76547.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-76547.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issue-76547.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issue-76547.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,20 +1,22 @@ error: lifetime may not live long enough - --> $DIR/issue-76547.rs:19:14 + --> $DIR/issue-76547.rs:20:13 | LL | async fn fut(bufs: &mut [&mut [u8]]) { - | ^^^^ - - let's call the lifetime of this reference `'2` - | | | - | | let's call the lifetime of this reference `'1` - | assignment requires that `'1` must outlive `'2` + | - - let's call the lifetime of this reference `'2` + | | + | let's call the lifetime of this reference `'1` +LL | ListFut(bufs).await + | ^^^^ this usage requires that `'1` must outlive `'2` error: lifetime may not live long enough - --> $DIR/issue-76547.rs:33:15 + --> $DIR/issue-76547.rs:34:14 | LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 { - | ^^^^ - - let's call the lifetime of this reference `'2` - | | | - | | let's call the lifetime of this reference `'1` - | assignment requires that `'1` must outlive `'2` + | - - let's call the lifetime of this reference `'2` + | | + | let's call the lifetime of this reference `'1` +LL | ListFut2(bufs).await + | ^^^^ this usage requires that `'1` must outlive `'2` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-54752-async-block.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-54752-async-block.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-54752-async-block.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-54752-async-block.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,14 @@ --> $DIR/issue-54752-async-block.rs:6:22 | LL | fn main() { let _a = (async { }); } - | ^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ | = note: `#[warn(unused_parens)]` on by default +help: remove these parentheses + | +LL - fn main() { let _a = (async { }); } +LL + fn main() { let _a = async { }; } + | warning: 1 warning emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-61187.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-61187.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-61187.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-61187.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | async fn response(data: Vec) { | ---- help: consider changing this to be mutable: `mut data` LL | data.reverse(); - | ^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-62097.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-62097.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-62097.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-62097.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,9 +20,15 @@ --> $DIR/issue-62097.rs:13:9 | LL | pub async fn run_dummy_fn(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | foo(|| self.bar()).await; - | ^^^^^^^^^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-64964.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-64964.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-64964.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-64964.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ // check-pass -// compile-flags: -Z query-dep-graph -C incremental=tmp/issue-64964 +// incremental +// compile-flags: -Z query-dep-graph // edition:2018 // Regression test for ICE related to `await`ing in a method + incr. comp. (#64964) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-65159.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-65159.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-65159.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-65159.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,6 @@ //~^ ERROR this enum takes 2 generic arguments { Ok(()) - //~^ ERROR type annotations needed } fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-65159.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-65159.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-65159.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/async-await/issues/issue-65159.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,13 +16,6 @@ LL | async fn copy() -> Result<(), E> | +++ -error[E0282]: type annotations needed - --> $DIR/issue-65159.rs:8:5 - | -LL | Ok(()) - | ^^ cannot infer type for type parameter `E` declared on the enum `Result` +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0107, E0282. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/extented-attribute-macro-error.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/extented-attribute-macro-error.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/extented-attribute-macro-error.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/extented-attribute-macro-error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +// normalize-stderr-test: "couldn't read.*" -> "couldn't read the file" + +#![feature(extended_key_value_attributes)] +#![doc = include_str!("../not_existing_file.md")] +struct Documented {} +//~^^ ERROR couldn't read + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/extented-attribute-macro-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/extented-attribute-macro-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/extented-attribute-macro-error.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/extented-attribute-macro-error.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: couldn't read the file + --> $DIR/extented-attribute-macro-error.rs:4:10 + | +LL | #![doc = include_str!("../not_existing_file.md")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/key-value-expansion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/key-value-expansion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/key-value-expansion.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/key-value-expansion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -11,22 +11,18 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | bug!(); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected token: `{ let res = - ::alloc::fmt::format(match match (&"u8",) { - (arg0,) => - [::core::fmt::ArgumentV1::new(arg0, - ::core::fmt::Display::fmt)], - } { - ref args => unsafe { - ::core::fmt::Arguments::new_v1(&[""], - args) - } - }); + ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], + &match (&"u8",) { + (arg0,) => + [::core::fmt::ArgumentV1::new(arg0, + ::core::fmt::Display::fmt)], + })); res }.as_str()` --> $DIR/key-value-expansion.rs:48:23 @@ -35,7 +31,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | some_macro!(u8); - | ---------------- in this macro invocation + | --------------- in this macro invocation | = note: this error originates in the macro `some_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/nonterminal-expansion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/nonterminal-expansion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/nonterminal-expansion.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/nonterminal-expansion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ ... LL | pass_nonterminal!(n!()); - | ------------------------ in this macro invocation + | ----------------------- in this macro invocation | = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^^^^^^ ... LL | pass_nonterminal!(n!()); - | ------------------------ in this macro invocation + | ----------------------- in this macro invocation | = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/register-attr-tool-fail.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/register-attr-tool-fail.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/attributes/register-attr-tool-fail.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/attributes/register-attr-tool-fail.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -30,13 +30,13 @@ --> $DIR/register-attr-tool-fail.rs:4:1 | LL | #![register_attr] - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_attr(attr1, attr2, ...)]` + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_attr(attr1, attr2, ...)]` error: malformed `register_tool` attribute input --> $DIR/register-attr-tool-fail.rs:5:1 | LL | #![register_tool] - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_tool(tool1, tool2, ...)]` + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_tool(tool1, tool2, ...)]` error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/autoderef-full-lval.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/autoderef-full-lval.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/autoderef-full-lval.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/autoderef-full-lval.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,23 +1,23 @@ -#![feature(box_syntax)] - struct Clam { x: Box, y: Box, } + + struct Fish { a: Box, } fn main() { - let a: Clam = Clam{x: box 1, y: box 2}; - let b: Clam = Clam{x: box 10, y: box 20}; + let a: Clam = Clam{ x: Box::new(1), y: Box::new(2) }; + let b: Clam = Clam{ x: Box::new(10), y: Box::new(20) }; let z: isize = a.x + b.y; //~^ ERROR cannot add `Box` to `Box` println!("{}", z); assert_eq!(z, 21); - let forty: Fish = Fish{a: box 40}; - let two: Fish = Fish{a: box 2}; + let forty: Fish = Fish{ a: Box::new(40) }; + let two: Fish = Fish{ a: Box::new(2) }; let answer: isize = forty.a + two.a; //~^ ERROR cannot add `Box` to `Box` println!("{}", answer); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self: Box) -> usize; @@ -11,6 +10,6 @@ } pub fn main() { - let x: Box<_> = box (box 3usize as Box); + let x: Box<_> = Box::new(Box::new(3usize) as Box); assert_eq!(x.double(), 6); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-priority.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-priority.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-priority.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-priority.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self) -> usize; @@ -15,6 +14,6 @@ } pub fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); assert_eq!(x.double(), 6); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self: Box) -> usize; @@ -11,6 +10,6 @@ } pub fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); assert_eq!(x.double(), 6); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self: Box) -> usize; @@ -11,6 +10,6 @@ } pub fn main() { - let x: Box>>>> = box box box box box 3; + let x: Box>>>> = Box::new(Box::new(Box::new(Box::new(Box::new(3))))); assert_eq!(x.double(), 6); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-twice.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-twice.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-twice.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoderef-method-twice.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self: Box) -> usize; @@ -11,6 +10,6 @@ } pub fn main() { - let x: Box> = box box 3; + let x: Box> = Box::new(Box::new(3)); assert_eq!(x.double(), 6); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] trait Foo { fn foo(&self) -> String; @@ -18,6 +17,6 @@ } pub fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); assert_eq!(x.foo(), "box 3".to_string()); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/issue-38940.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/issue-38940.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/autoref-autoderef/issue-38940.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/autoref-autoderef/issue-38940.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`issue_38940`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`issue_38940`) error[E0308]: mismatched types --> $DIR/issue-38940.rs:43:22 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +#![feature(auto_traits)] + +// run-rustfix + +auto trait Generic {} +//~^ auto traits cannot have generic parameters [E0567] +auto trait Bound {} +//~^ auto traits cannot have super traits or lifetime bounds [E0568] +auto trait LifetimeBound {} +//~^ auto traits cannot have super traits or lifetime bounds [E0568] +auto trait MyTrait { } +//~^ auto traits cannot have associated items [E0380] +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,13 @@ #![feature(auto_traits)] +// run-rustfix + auto trait Generic {} //~^ auto traits cannot have generic parameters [E0567] auto trait Bound : Copy {} -//~^ auto traits cannot have super traits [E0568] +//~^ auto traits cannot have super traits or lifetime bounds [E0568] +auto trait LifetimeBound : 'static {} +//~^ auto traits cannot have super traits or lifetime bounds [E0568] auto trait MyTrait { fn foo() {} } -//~^ auto traits cannot have methods or associated items [E0380] +//~^ auto traits cannot have associated items [E0380] fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/auto-trait-validation.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,28 +1,37 @@ error[E0567]: auto traits cannot have generic parameters - --> $DIR/auto-trait-validation.rs:3:19 + --> $DIR/auto-trait-validation.rs:5:19 | LL | auto trait Generic {} | -------^^^ help: remove the parameters | | | auto trait cannot have generic parameters -error[E0568]: auto traits cannot have super traits - --> $DIR/auto-trait-validation.rs:5:20 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/auto-trait-validation.rs:7:17 | LL | auto trait Bound : Copy {} - | ----- ^^^^ help: remove the super traits + | -----^^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have super traits + | auto trait cannot have super traits or lifetime bounds -error[E0380]: auto traits cannot have methods or associated items - --> $DIR/auto-trait-validation.rs:7:25 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/auto-trait-validation.rs:9:25 | -LL | auto trait MyTrait { fn foo() {} } - | ------- ^^^ +LL | auto trait LifetimeBound : 'static {} + | -------------^^^^^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have items + | auto trait cannot have super traits or lifetime bounds + +error[E0380]: auto traits cannot have associated items + --> $DIR/auto-trait-validation.rs:11:25 + | +LL | auto trait MyTrait { fn foo() {} } + | ------- ---^^^----- + | | | + | | help: remove these associated items + | auto trait cannot have associated items -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0380, E0567, E0568. For more information about an error, try `rustc --explain E0380`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/issue-23080-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/issue-23080-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/issue-23080-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/issue-23080-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -error[E0380]: auto traits cannot have methods or associated items +error[E0380]: auto traits cannot have associated items --> $DIR/issue-23080-2.rs:5:10 | LL | unsafe auto trait Trait { - | ----- auto trait cannot have items + | ----- auto trait cannot have associated items LL | type Output; - | ^^^^^^ + | -----^^^^^^- help: remove these associated items error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/issue-23080.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/issue-23080.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/issue-23080.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/issue-23080.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,13 @@ -error[E0380]: auto traits cannot have methods or associated items +error[E0380]: auto traits cannot have associated items --> $DIR/issue-23080.rs:5:8 | -LL | unsafe auto trait Trait { - | ----- auto trait cannot have items -LL | fn method(&self) { - | ^^^^^^ +LL | unsafe auto trait Trait { + | ----- auto trait cannot have associated items +LL | fn method(&self) { + | _____- ^^^^^^ +LL | | println!("Hello"); +LL | | } + | |_____- help: remove these associated items error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/issue-84075.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/issue-84075.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/issue-84075.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/issue-84075.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// Regression test for issue #84075. + +#![feature(auto_traits)] + +auto trait Magic where Self: Copy {} //~ ERROR E0568 +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); + println!("{:?} {:?}", a, b); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/issue-84075.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/issue-84075.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/issue-84075.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/issue-84075.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/issue-84075.rs:5:18 + | +LL | auto trait Magic where Self: Copy {} + | ----- ^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds + | | + | auto trait cannot have super traits or lifetime bounds + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0568`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,7 @@ #![feature(negative_impls)] auto trait Magic : Sized where Option : Magic {} //~ ERROR E0568 +//~^ ERROR E0568 impl Magic for T {} fn copy(x: T) -> (T, T) { (x, x) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,19 @@ -error[E0568]: auto traits cannot have super traits - --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:20 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:17 | LL | auto trait Magic : Sized where Option : Magic {} - | ----- ^^^^^ help: remove the super traits + | -----^^^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have super traits + | auto trait cannot have super traits or lifetime bounds -error: aborting due to previous error +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:26 + | +LL | auto trait Magic : Sized where Option : Magic {} + | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds + | | + | auto trait cannot have super traits or lifetime bounds + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0568`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -error[E0568]: auto traits cannot have super traits - --> $DIR/typeck-auto-trait-no-supertraits.rs:28:19 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/typeck-auto-trait-no-supertraits.rs:28:17 | LL | auto trait Magic: Copy {} - | ----- ^^^^ help: remove the super traits + | -----^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have super traits + | auto trait cannot have super traits or lifetime bounds error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auxiliary/define-macro.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/auxiliary/define-macro.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auxiliary/define-macro.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auxiliary/define-macro.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -#[macro_export] -macro_rules! define_macro { - ($i:ident) => { - macro_rules! $i { () => {} } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/auxiliary/issue-72470-lib.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/auxiliary/issue-72470-lib.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/auxiliary/issue-72470-lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/auxiliary/issue-72470-lib.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -// compile-flags: -C opt-level=3 -// edition:2018 - -use std::future::Future; -use std::marker::PhantomData; -use std::pin::Pin; -use std::sync::atomic::AtomicUsize; -use std::sync::Arc; -use std::task::Poll::{Pending, Ready}; -use std::task::Waker; -use std::task::{Context, Poll}; -use std::{ - ptr, - task::{RawWaker, RawWakerVTable}, -}; - -/// Future for the [`poll_fn`] function. -pub struct PollFn { - f: F, -} - -impl Unpin for PollFn {} - -/// Creates a new future wrapping around a function returning [`Poll`]. -pub fn poll_fn(f: F) -> PollFn -where - F: FnMut(&mut Context<'_>) -> Poll, -{ - PollFn { f } -} - -impl Future for PollFn -where - F: FnMut(&mut Context<'_>) -> Poll, -{ - type Output = T; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - (&mut self.f)(cx) - } -} -pub fn run(future: F) -> F::Output { - BasicScheduler.block_on(future) -} - -pub(crate) struct BasicScheduler; - -impl BasicScheduler { - pub(crate) fn block_on(&mut self, mut future: F) -> F::Output - where - F: Future, - { - let waker = unsafe { Waker::from_raw(raw_waker()) }; - let mut cx = std::task::Context::from_waker(&waker); - - let mut future = unsafe { Pin::new_unchecked(&mut future) }; - - loop { - if let Ready(v) = future.as_mut().poll(&mut cx) { - return v; - } - } - } -} - -// ===== impl Spawner ===== - -fn raw_waker() -> RawWaker { - RawWaker::new(ptr::null(), waker_vtable()) -} - -fn waker_vtable() -> &'static RawWakerVTable { - &RawWakerVTable::new( - clone_arc_raw, - wake_arc_raw, - wake_by_ref_arc_raw, - drop_arc_raw, - ) -} - -unsafe fn clone_arc_raw(_: *const ()) -> RawWaker { - raw_waker() -} - -unsafe fn wake_arc_raw(_: *const ()) {} - -unsafe fn wake_by_ref_arc_raw(_: *const ()) {} - -unsafe fn drop_arc_raw(_: *const ()) {} - -struct AtomicWaker {} - -impl AtomicWaker { - /// Create an `AtomicWaker` - fn new() -> AtomicWaker { - AtomicWaker {} - } - - fn register_by_ref(&self, _waker: &Waker) {} -} - -#[allow(dead_code)] -struct Tx { - inner: Arc>, -} - -struct Rx { - inner: Arc>, -} - -#[allow(dead_code)] -struct Chan { - tx: PhantomData, - semaphore: Sema, - rx_waker: AtomicWaker, - rx_closed: bool, -} - -fn channel() -> (Tx, Rx) { - let chan = Arc::new(Chan { - tx: PhantomData, - semaphore: Sema(AtomicUsize::new(0)), - rx_waker: AtomicWaker::new(), - rx_closed: false, - }); - - ( - Tx { - inner: chan.clone(), - }, - Rx { inner: chan }, - ) -} - -// ===== impl Rx ===== - -impl Rx { - /// Receive the next value - fn recv(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.rx_waker.register_by_ref(cx.waker()); - - if self.inner.rx_closed && self.inner.semaphore.is_idle() { - Ready(None) - } else { - Pending - } - } -} - -struct Sema(AtomicUsize); - -impl Sema { - fn is_idle(&self) -> bool { - false - } -} - -pub struct UnboundedReceiver { - chan: Rx, -} - -pub fn unbounded_channel() -> UnboundedReceiver { - let (tx, rx) = channel(); - - drop(tx); - let rx = UnboundedReceiver { chan: rx }; - - rx -} - -impl UnboundedReceiver { - pub async fn recv(&mut self) -> Option { - poll_fn(|cx| self.chan.recv(cx)).await - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/expr-match-generic-unique1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/expr-match-generic-unique1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/expr-match-generic-unique1.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/expr-match-generic-unique1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn test_generic(expected: Box, eq: F) where F: FnOnce(Box, Box) -> bool { let actual: Box = match true { @@ -13,7 +12,7 @@ fn compare_box(b1: Box, b2: Box) -> bool { return *b1 == *b2; } - test_generic::(box true, compare_box); + test_generic::(Box::new(true), compare_box); } pub fn main() { test_box(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/expr-match-generic-unique2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/expr-match-generic-unique2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/expr-match-generic-unique2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/expr-match-generic-unique2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn test_generic(expected: T, eq: F) where F: FnOnce(T, T) -> bool { let actual: T = match true { @@ -11,7 +10,7 @@ fn test_vec() { fn compare_box(v1: Box, v2: Box) -> bool { return v1 == v2; } - test_generic::, _>(box 1, compare_box); + test_generic::, _>(Box::new(1), compare_box); } pub fn main() { test_vec(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/expr-match-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/expr-match-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/expr-match-unique.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/expr-match-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,8 @@ // run-pass -#![feature(box_syntax)] // Tests for match as expressions resulting in boxed types fn test_box() { - let res: Box<_> = match true { true => { box 100 }, _ => panic!() }; + let res: Box<_> = match true { true => { Box::new(100) }, _ => panic!() }; assert_eq!(*res, 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/func-arg-incomplete-pattern.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/func-arg-incomplete-pattern.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/func-arg-incomplete-pattern.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/func-arg-incomplete-pattern.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ // Test that we do not leak when the arg pattern must drop part of the // argument (in this case, the `y` field). -#![feature(box_syntax)] - struct Foo { x: Box, y: Box, @@ -16,9 +14,9 @@ } pub fn main() { - let obj: Box<_> = box 1; + let obj: Box<_> = Box::new(1); let objptr: *const usize = &*obj; - let f = Foo {x: obj, y: box 2}; + let f = Foo { x: obj, y: Box::new(2) }; let xptr = foo(f); assert_eq!(objptr, xptr); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/func-arg-ref-pattern.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/func-arg-ref-pattern.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/func-arg-ref-pattern.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/func-arg-ref-pattern.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,6 @@ // pattern. #![feature(box_patterns)] -#![feature(box_syntax)] fn getaddr(box ref x: Box) -> *const usize { let addr: *const usize = &*x; @@ -17,11 +16,11 @@ } pub fn main() { - let obj: Box<_> = box 1; + let obj: Box<_> = Box::new(1); let objptr: *const usize = &*obj; let xptr = getaddr(obj); assert_eq!(objptr, xptr); - let obj = box 22; + let obj = Box::new(22); assert_eq!(checkval(obj), 22); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/let-assignability.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/let-assignability.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/let-assignability.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/let-assignability.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] fn f() { - let a: Box<_> = box 1; + let a: Box<_> = Box::new(1); let b: &isize = &*a; println!("{}", b); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/match-implicit-copy-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/match-implicit-copy-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/match-implicit-copy-unique.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/match-implicit-copy-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,16 +1,15 @@ // run-pass #![allow(non_shorthand_field_patterns)] -#![feature(box_syntax)] struct Pair { a: Box, b: Box } pub fn main() { - let mut x: Box<_> = box Pair {a: box 10, b: box 20}; + let mut x: Box<_> = Box::new(Pair { a: Box::new(10), b: Box::new(20) }); let x_internal = &mut *x; match *x_internal { Pair {a: ref mut a, b: ref mut _b} => { assert_eq!(**a, 10); - *a = box 30; + *a = Box::new(30); assert_eq!(**a, 30); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/match-unique-bind.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/match-unique-bind.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/match-unique-bind.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/match-unique-bind.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,8 @@ // run-pass #![feature(box_patterns)] -#![feature(box_syntax)] pub fn main() { - match box 100 { + match Box::new(100) { box x => { println!("{}", x); assert_eq!(x, 100); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/match-value-binding-in-guard-3291.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/match-value-binding-in-guard-3291.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binding/match-value-binding-in-guard-3291.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binding/match-value-binding-in-guard-3291.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn foo(x: Option>, b: bool) -> isize { match x { None => { 1 } @@ -12,8 +10,8 @@ } pub fn main() { - foo(Some(box 22), true); - foo(Some(box 22), false); + foo(Some(Box::new(22)), true); + foo(Some(Box::new(22)), false); foo(None, true); foo(None, false); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binop/binop-move-semantics.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/binop/binop-move-semantics.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binop/binop-move-semantics.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binop/binop-move-semantics.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -30,7 +30,7 @@ | - value moved here LL | + LL | x.clone(); - | ^ value borrowed here after move + | ^^^^^^^^^ value borrowed here after move | help: consider further restricting this bound | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binop/issue-28837.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/binop/issue-28837.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binop/issue-28837.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binop/issue-28837.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,22 @@ | | | A | - = note: an implementation of `std::ops::Add` might be missing for `A` +note: an implementation of `Add<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Add<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Add { +LL | | /// The resulting type after applying the `+` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn add(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot subtract `A` from `A` --> $DIR/issue-28837.rs:8:7 @@ -16,7 +31,22 @@ | | | A | - = note: an implementation of `std::ops::Sub` might be missing for `A` +note: an implementation of `Sub<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Sub<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Sub { +LL | | /// The resulting type after applying the `-` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn sub(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot multiply `A` by `A` --> $DIR/issue-28837.rs:10:7 @@ -26,7 +56,22 @@ | | | A | - = note: an implementation of `std::ops::Mul` might be missing for `A` +note: an implementation of `Mul<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Mul<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Mul { +LL | | /// The resulting type after applying the `*` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn mul(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot divide `A` by `A` --> $DIR/issue-28837.rs:12:7 @@ -36,7 +81,22 @@ | | | A | - = note: an implementation of `std::ops::Div` might be missing for `A` +note: an implementation of `Div<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Div<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Div { +LL | | /// The resulting type after applying the `/` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn div(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot mod `A` by `A` --> $DIR/issue-28837.rs:14:7 @@ -46,7 +106,22 @@ | | | A | - = note: an implementation of `std::ops::Rem` might be missing for `A` +note: an implementation of `Rem<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Rem<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Rem { +LL | | /// The resulting type after applying the `%` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn rem(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: no implementation for `A & A` --> $DIR/issue-28837.rs:16:7 @@ -56,7 +131,22 @@ | | | A | - = note: an implementation of `std::ops::BitAnd` might be missing for `A` +note: an implementation of `BitAnd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `BitAnd<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait BitAnd { +LL | | /// The resulting type after applying the `&` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn bitand(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: no implementation for `A | A` --> $DIR/issue-28837.rs:18:7 @@ -66,7 +156,22 @@ | | | A | - = note: an implementation of `std::ops::BitOr` might be missing for `A` +note: an implementation of `BitOr<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `BitOr<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait BitOr { +LL | | /// The resulting type after applying the `|` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn bitor(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: no implementation for `A << A` --> $DIR/issue-28837.rs:20:7 @@ -76,7 +181,22 @@ | | | A | - = note: an implementation of `std::ops::Shl` might be missing for `A` +note: an implementation of `Shl<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Shl<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait Shl { +LL | | /// The resulting type after applying the `<<` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn shl(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: no implementation for `A >> A` --> $DIR/issue-28837.rs:22:7 @@ -86,7 +206,22 @@ | | | A | - = note: an implementation of `std::ops::Shr` might be missing for `A` +note: an implementation of `Shr<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Shr<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait Shr { +LL | | /// The resulting type after applying the `>>` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn shr(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: binary operation `==` cannot be applied to type `A` --> $DIR/issue-28837.rs:24:7 @@ -96,7 +231,15 @@ | | | A | - = note: an implementation of `std::cmp::PartialEq` might be missing for `A` +note: an implementation of `PartialEq<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialEq<_>` +help: consider annotating `A` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `A` --> $DIR/issue-28837.rs:26:7 @@ -106,7 +249,15 @@ | | | A | - = note: an implementation of `std::cmp::PartialEq` might be missing for `A` +note: an implementation of `PartialEq<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialEq<_>` +help: consider annotating `A` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `<` cannot be applied to type `A` --> $DIR/issue-28837.rs:28:7 @@ -116,7 +267,15 @@ | | | A | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` +note: an implementation of `PartialOrd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialOrd<_>` +help: consider annotating `A` with `#[derive(PartialOrd)]` + | +LL | #[derive(PartialOrd)] + | error[E0369]: binary operation `<=` cannot be applied to type `A` --> $DIR/issue-28837.rs:30:7 @@ -126,7 +285,15 @@ | | | A | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` +note: an implementation of `PartialOrd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialOrd<_>` +help: consider annotating `A` with `#[derive(PartialOrd)]` + | +LL | #[derive(PartialOrd)] + | error[E0369]: binary operation `>` cannot be applied to type `A` --> $DIR/issue-28837.rs:32:7 @@ -136,7 +303,15 @@ | | | A | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` +note: an implementation of `PartialOrd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialOrd<_>` +help: consider annotating `A` with `#[derive(PartialOrd)]` + | +LL | #[derive(PartialOrd)] + | error[E0369]: binary operation `>=` cannot be applied to type `A` --> $DIR/issue-28837.rs:34:7 @@ -146,7 +321,15 @@ | | | A | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` +note: an implementation of `PartialOrd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialOrd<_>` +help: consider annotating `A` with `#[derive(PartialOrd)]` + | +LL | #[derive(PartialOrd)] + | error: aborting due to 15 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/binop/issue-77910-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/binop/issue-77910-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/binop/issue-77910-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/binop/issue-77910-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-77910-1.rs:8:5 | LL | assert_eq!(foo, y); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | | | for<'r> fn(&'r i32) -> &'r i32 {foo} | _ @@ -13,7 +13,7 @@ --> $DIR/issue-77910-1.rs:8:5 | LL | assert_eq!(foo, y); - | ^^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.fixed 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -10,4 +10,11 @@ "removeme".to_string() } +pub fn macro_tests() -> u32 { //~ ERROR mismatched types + macro_rules! mac { + () => (1); + } + mac!() +} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,4 +10,11 @@ "removeme".to_string(); } +pub fn macro_tests() -> u32 { //~ ERROR mismatched types + macro_rules! mac { + () => (1); + } + mac!(); +} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/block-result/consider-removing-last-semi.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,6 +20,17 @@ LL | "removeme".to_string(); | - help: consider removing this semicolon -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/consider-removing-last-semi.rs:13:25 + | +LL | pub fn macro_tests() -> u32 { + | ----------- ^^^ expected `u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +... +LL | mac!(); + | - help: consider removing this semicolon + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/block-result/issue-13428.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/block-result/issue-13428.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/block-result/issue-13428.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/block-result/issue-13428.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,9 +5,6 @@ | --- ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression -... -LL | ; - | - help: consider removing this semicolon error[E0308]: mismatched types --> $DIR/issue-13428.rs:11:13 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-argument.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-argument.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-argument.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-argument.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | fn func(arg: S) { | --- help: consider changing this to be mutable: `mut arg` LL | arg.mutate(); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:15:9 @@ -12,7 +12,7 @@ LL | fn method(&self, arg: S) { | --- help: consider changing this to be mutable: `mut arg` LL | arg.mutate(); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:21:9 @@ -20,13 +20,13 @@ LL | fn default(&self, arg: S) { | --- help: consider changing this to be mutable: `mut arg` LL | arg.mutate(); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:32:17 | LL | (|arg: S| { arg.mutate() })(s); - | --- ^^^ cannot borrow as mutable + | --- ^^^^^^^^^^^^ cannot borrow as mutable | | | help: consider changing this to be mutable: `mut arg` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let x = Foo { x: 3 }; | - help: consider changing this to be mutable: `mut x` LL | x.printme(); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ // Test that we detect nested calls that could free pointers evaluated // for earlier arguments. -#![feature(box_syntax)] + fn rewrite(v: &mut Box) -> usize { - *v = box 22; + *v = Box::new(22); **v } @@ -13,7 +13,7 @@ } fn implicit() { - let mut a: Box<_> = box 1; + let mut a: Box<_> = Box::new(1); // Note the danger here: // @@ -26,7 +26,7 @@ } fn explicit() { - let mut a: Box<_> = box 1; + let mut a: Box<_> = Box::new(1); add( &*a, rewrite(&mut a)); //~ ERROR cannot borrow diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ // Test that we detect nested calls that could free pointers evaluated // for earlier arguments. -#![feature(box_syntax)] + fn rewrite(v: &mut Box) -> usize { - *v = box 22; + *v = Box::new(22); **v } @@ -13,7 +13,7 @@ } fn implicit() { - let mut a: Box<_> = box 1; + let mut a: Box<_> = Box::new(1); // Note the danger here: // @@ -26,7 +26,7 @@ } fn explicit() { - let mut a: Box<_> = box 1; + let mut a: Box<_> = Box::new(1); add( &*a, a); //~ ERROR cannot move diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -//buggy.rs +use std::collections::HashMap; + + -#![feature(box_syntax)] -use std::collections::HashMap; fn main() { let tmp: Box<_>; @@ -10,6 +10,6 @@ buggy_map.insert(42, &*Box::new(1)); //~ ERROR temporary value dropped while borrowed // but it is ok if we use a temporary - tmp = box 2; + tmp = Box::new(2); buggy_map.insert(43, &*tmp); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | creates a temporary which is freed while still in use ... LL | buggy_map.insert(43, &*tmp); - | --------- borrow later used here + | --------------------------- borrow later used here | = note: consider using a `let` binding to create a longer lived value diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn borrow(x: &isize, f: F) where F: FnOnce(&isize) { f(x) @@ -14,5 +13,5 @@ } pub fn main() { - test1(&box 22); + test1(&Box::new(22)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - struct A; impl A { @@ -7,8 +5,10 @@ } } + + pub fn main() { - let a: Box<_> = box A; + let a: Box<_> = Box::new(A); a.foo(); //~^ ERROR cannot borrow `*a` as mutable, as `a` is not declared as mutable [E0596] } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5 | -LL | let a: Box<_> = box A; +LL | let a: Box<_> = Box::new(A); | - help: consider changing this to be mutable: `mut a` LL | a.foo(); - | ^ cannot borrow as mutable + | ^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,11 +2,11 @@ --> $DIR/borrowck-borrow-mut-object-twice.rs:13:5 | LL | let y = x.f1(); - | - first mutable borrow occurs here + | ------ first mutable borrow occurs here LL | x.f2(); - | ^ second mutable borrow occurs here + | ^^^^^^ second mutable borrow occurs here LL | y.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -58,7 +58,7 @@ --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:72:5 | LL | x.set(0, 0); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -66,7 +66,7 @@ --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:76:5 | LL | x.set(0, 0); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -74,7 +74,7 @@ --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:84:5 | LL | x.y_mut() - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -82,7 +82,7 @@ --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:88:5 | LL | x.y_mut() - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -90,7 +90,7 @@ --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:92:6 | LL | *x.y_mut() = 3; - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -98,7 +98,7 @@ --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:96:6 | LL | *x.y_mut() = 3; - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -106,7 +106,7 @@ --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:100:6 | LL | *x.y_mut() = 3; - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-box-sensitivity.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-box-sensitivity.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-box-sensitivity.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-box-sensitivity.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ // run-pass -#![feature(box_syntax)] - struct A { x: Box, y: isize, @@ -26,97 +24,97 @@ } fn copy_after_move() { - let a: Box<_> = box A { x: box 0, y: 1 }; + let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = a.x; let _y = a.y; } fn move_after_move() { - let a: Box<_> = box B { x: box 0, y: box 1 }; + let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); let _x = a.x; let _y = a.y; } fn borrow_after_move() { - let a: Box<_> = box A { x: box 0, y: 1 }; + let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = a.x; let _y = &a.y; } fn move_after_borrow() { - let a: Box<_> = box B { x: box 0, y: box 1 }; + let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); let _x = &a.x; let _y = a.y; use_imm(_x); } fn copy_after_mut_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = &mut a.x; let _y = a.y; use_mut(_x); } fn move_after_mut_borrow() { - let mut a: Box<_> = box B { x: box 0, y: box 1 }; + let mut a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); let _x = &mut a.x; let _y = a.y; use_mut(_x); } fn borrow_after_mut_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = &mut a.x; let _y = &a.y; use_mut(_x); } fn mut_borrow_after_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = &a.x; let _y = &mut a.y; use_imm(_x); } fn copy_after_move_nested() { - let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = a.x.x; let _y = a.y; } fn move_after_move_nested() { - let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); let _x = a.x.x; let _y = a.y; } fn borrow_after_move_nested() { - let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = a.x.x; let _y = &a.y; } fn move_after_borrow_nested() { - let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); let _x = &a.x.x; let _y = a.y; use_imm(_x); } fn copy_after_mut_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = &mut a.x.x; let _y = a.y; use_mut(_x); } fn move_after_mut_borrow_nested() { - let mut a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let mut a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); let _x = &mut a.x.x; let _y = a.y; use_mut(_x); } fn borrow_after_mut_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = &mut a.x.x; let _y = &a.y; use_mut(_x); } fn mut_borrow_after_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = &a.x.x; let _y = &mut a.y; use_imm(_x); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,6 @@ // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. -#![feature(box_syntax)] - fn get(x: &isize) -> isize { *x } @@ -11,6 +9,8 @@ *x = 4; } + + fn a() { let mut x = 3; let c1 = || x = 4; @@ -52,7 +52,7 @@ } fn f() { - let mut x: Box<_> = box 3; + let mut x: Box<_> = Box::new(3); let c1 = || get(&*x); *x = 5; //~^ ERROR cannot assign to `*x` because it is borrowed @@ -64,7 +64,7 @@ f: Box } - let mut x: Box<_> = box Foo { f: box 3 }; + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); let c1 = || get(&*x.f); *x.f = 5; //~^ ERROR cannot assign to `*x.f` because it is borrowed @@ -76,7 +76,7 @@ f: Box } - let mut x: Box<_> = box Foo { f: box 3 }; + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); let c1 = || get(&*x.f); let c2 = || *x.f = 5; //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ // access to the variable, whether that mutable access be used // for direct assignment or for taking mutable ref. Issue #6801. -#![feature(box_syntax)] + @@ -48,7 +48,7 @@ f: Box } - let mut x: Box<_> = box Foo { f: box 3 }; + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); let c1 = to_fn_mut(|| set(&mut *x.f)); let c2 = to_fn_mut(|| set(&mut *x.f)); //~^ ERROR cannot borrow `x` as mutable more than once diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-two-mut.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-two-mut.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-two-mut.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-two-mut.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ // access to the variable, whether that mutable access be used // for direct assignment or for taking mutable ref. Issue #6801. -#![feature(box_syntax)] + fn to_fn_mut(f: F) -> F { f } @@ -44,7 +44,7 @@ f: Box } - let mut x: Box<_> = box Foo { f: box 3 }; + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); let c1 = to_fn_mut(|| set(&mut *x.f)); let c2 = to_fn_mut(|| set(&mut *x.f)); //~^ ERROR cannot borrow `x` as mutable more than once diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | &mut this.x; | ^^^^^^^^^^^ mutable borrow occurs here LL | p.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-use-after-free.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-use-after-free.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-use-after-free.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-use-after-free.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,6 @@ // cannot also be supplied a borrowed version of that // variable's contents. Issue #11192. -#![feature(box_syntax)] - struct Foo { x: isize } @@ -14,10 +12,12 @@ } } + + fn main() { - let mut ptr: Box<_> = box Foo { x: 0 }; + let mut ptr: Box<_> = Box::new(Foo { x: 0 }); let mut test = |foo: &Foo| { - ptr = box Foo { x: ptr.x + 1 }; + ptr = Box::new(Foo { x: ptr.x + 1 }); }; test(&*ptr); //~ ERROR cannot borrow `*ptr` } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ | LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here -LL | ptr = box Foo { x: ptr.x + 1 }; +LL | ptr = Box::new(Foo { x: ptr.x + 1 }); | --- first borrow occurs due to use of `ptr` in closure LL | }; LL | test(&*ptr); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-describe-lvalue.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-describe-lvalue.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-describe-lvalue.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-describe-lvalue.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -41,7 +41,7 @@ --> $DIR/borrowck-describe-lvalue.rs:37:9 | LL | let x = f.x(); - | - borrow of `f` occurs here + | ----- borrow of `f` occurs here LL | f.x; | ^^^ use of borrowed `f` LL | drop(x); @@ -51,7 +51,7 @@ --> $DIR/borrowck-describe-lvalue.rs:44:9 | LL | let x = g.x(); - | - borrow of `g` occurs here + | ----- borrow of `g` occurs here LL | g.0; | ^^^ use of borrowed `g` LL | drop(x); @@ -71,7 +71,7 @@ --> $DIR/borrowck-describe-lvalue.rs:59:20 | LL | let x = e.x(); - | - borrow of `e` occurs here + | ----- borrow of `e` occurs here LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` @@ -93,7 +93,7 @@ --> $DIR/borrowck-describe-lvalue.rs:74:9 | LL | let x = f.x(); - | - borrow of `*f` occurs here + | ----- borrow of `*f` occurs here LL | f.x; | ^^^ use of borrowed `*f` LL | drop(x); @@ -103,7 +103,7 @@ --> $DIR/borrowck-describe-lvalue.rs:81:9 | LL | let x = g.x(); - | - borrow of `*g` occurs here + | ----- borrow of `*g` occurs here LL | g.0; | ^^^ use of borrowed `*g` LL | drop(x); @@ -123,7 +123,7 @@ --> $DIR/borrowck-describe-lvalue.rs:96:20 | LL | let x = e.x(); - | - borrow of `*e` occurs here + | ----- borrow of `*e` occurs here LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,89 +3,87 @@ #![allow(unused_variables)] // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - struct A { a: isize, b: Box } struct B { a: Box, b: Box } fn move_after_copy() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.a); drop(x.b); } fn move_after_fu_copy() { - let x = A { a: 1, b: box 2 }; - let _y = A { b: box 3, .. x }; + let x = A { a: 1, b: Box::new(2) }; + let _y = A { b: Box::new(3), .. x }; drop(x.b); } fn fu_move_after_copy() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.a); let _y = A { a: 3, .. x }; } fn fu_move_after_fu_copy() { - let x = A { a: 1, b: box 2 }; - let _y = A { b: box 3, .. x }; + let x = A { a: 1, b: Box::new(2) }; + let _y = A { b: Box::new(3), .. x }; let _z = A { a: 4, .. x }; } fn copy_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); drop(x.a); } fn copy_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let y = A { a: 3, .. x }; drop(x.a); } fn fu_copy_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); - let _y = A { b: box 3, .. x }; + let _y = A { b: Box::new(3), .. x }; } fn fu_copy_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - let _z = A { b: box 3, .. x }; + let _z = A { b: Box::new(3), .. x }; } fn borrow_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); let p = &x.a; drop(*p); } fn borrow_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; let p = &x.a; drop(*p); } fn move_after_borrow() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let p = &x.a; drop(x.b); drop(*p); } fn fu_move_after_borrow() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let p = &x.a; let _y = A { a: 3, .. x }; drop(*p); } fn mut_borrow_after_mut_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; let q = &mut x.b; drop(*p); @@ -93,134 +91,134 @@ } fn move_after_move() { - let x = B { a: box 1, b: box 2 }; + let x = B { a: Box::new(1), b: Box::new(2) }; drop(x.a); drop(x.b); } fn move_after_fu_move() { - let x = B { a: box 1, b: box 2 }; - let y = B { a: box 3, .. x }; + let x = B { a: Box::new(1), b: Box::new(2) }; + let y = B { a: Box::new(3), .. x }; drop(x.a); } fn fu_move_after_move() { - let x = B { a: box 1, b: box 2 }; + let x = B { a: Box::new(1), b: Box::new(2) }; drop(x.a); - let z = B { a: box 3, .. x }; + let z = B { a: Box::new(3), .. x }; drop(z.b); } fn fu_move_after_fu_move() { - let x = B { a: box 1, b: box 2 }; - let _y = B { b: box 3, .. x }; - let _z = B { a: box 4, .. x }; + let x = B { a: Box::new(1), b: Box::new(2) }; + let _y = B { b: Box::new(3), .. x }; + let _z = B { a: Box::new(4), .. x }; } fn copy_after_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; drop(*x.b); } fn copy_after_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; drop(*x.b); } fn copy_after_field_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x.b = box 3; + x.b = Box::new(3); drop(*x.b); } fn copy_after_field_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x.b = box 3; + x.b = Box::new(3); drop(*x.b); } fn borrow_after_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; let p = &x.b; drop(**p); } fn borrow_after_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; let p = &x.b; drop(**p); } fn borrow_after_field_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x.b = box 3; + x.b = Box::new(3); let p = &x.b; drop(**p); } fn borrow_after_field_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x.b = box 3; + x.b = Box::new(3); let p = &x.b; drop(**p); } fn move_after_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = x.b; - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; drop(x.b); } fn move_after_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; drop(x.b); } fn move_after_field_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x.b = box 3; + x.b = Box::new(3); drop(x.b); } fn move_after_field_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x.b = box 3; + x.b = Box::new(3); drop(x.b); } fn copy_after_assign_after_uninit() { let mut x: A; - x = A { a: 1, b: box 2 }; + x = A { a: 1, b: Box::new(2) }; drop(x.a); } fn borrow_after_assign_after_uninit() { let mut x: A; - x = A { a: 1, b: box 2 }; + x = A { a: 1, b: Box::new(2) }; let p = &x.a; drop(*p); } fn move_after_assign_after_uninit() { let mut x: A; - x = A { a: 1, b: box 2 }; + x = A { a: 1, b: Box::new(2) }; drop(x.b); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,49 +1,49 @@ -#![feature(box_syntax)] - struct A { a: isize, b: Box } + + fn deref_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); drop(*x.b); //~ ERROR use of moved value: `x.b` } fn deref_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let y = A { a: 3, .. x }; drop(*x.b); //~ ERROR use of moved value: `x.b` } fn borrow_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); let p = &x.b; //~ ERROR borrow of moved value: `x.b` drop(**p); } fn borrow_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; let p = &x.b; //~ ERROR borrow of moved value: `x.b` drop(**p); } fn move_after_borrow() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let p = &x.b; drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed drop(**p); } fn fu_move_after_borrow() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let p = &x.b; let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed drop(**p); } fn mut_borrow_after_mut_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time drop(*p); @@ -51,25 +51,25 @@ } fn move_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); drop(x.b); //~ ERROR use of moved value: `x.b` } fn move_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; drop(x.b); //~ ERROR use of moved value: `x.b` } fn fu_move_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); let _z = A { a: 3, .. x }; //~ ERROR use of moved value: `x.b` } fn fu_move_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; let _z = A { a: 4, .. x }; //~ ERROR use of moved value: `x.b` } @@ -91,7 +91,7 @@ fn move_after_field_assign_after_uninit() { let mut x: A; - x.b = box 1; //~ ERROR assign to part of possibly-uninitialized variable: `x` + x.b = Box::new(1); //~ ERROR assign to part of possibly-uninitialized variable: `x` drop(x.b); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-field-sensitivity.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -123,7 +123,7 @@ error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/borrowck-field-sensitivity.rs:94:5 | -LL | x.b = box 1; +LL | x.b = Box::new(1); | ^^^ use of possibly-uninitialized `x` error: aborting due to 14 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // Issue #16205. -#![feature(box_syntax)] + struct Foo { a: [Box; 3], @@ -13,12 +13,12 @@ } let f = Foo { - a: [box 3, box 4, box 5], + a: [Box::new(3), Box::new(4), Box::new(5)], }; for &a in &f.a { //~ ERROR cannot move out } - let x: Option> = Some(box 1); + let x: Option> = Some(Box::new(1)); for &a in x.iter() { //~ ERROR cannot move out } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-for-loop-head-linkage.rs:7:9 - | -LL | for &x in &vector { - | ------- - | | - | immutable borrow occurs here - | immutable borrow later used here -LL | let cap = vector.capacity(); -LL | vector.extend(repeat(0)); - | ^^^^^^ mutable borrow occurs here - -error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-for-loop-head-linkage.rs:8:9 - | -LL | for &x in &vector { - | ------- - | | - | immutable borrow occurs here - | immutable borrow later used here -... -LL | vector[1] = 5; - | ^^^^^^ mutable borrow occurs here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-insert-during-each.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-insert-during-each.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-insert-during-each.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-insert-during-each.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,15 +16,17 @@ error[E0500]: closure requires unique access to `f` but it is already borrowed --> $DIR/borrowck-insert-during-each.rs:18:9 | -LL | f.foo( - | - --- first borrow later used by call - | | - | borrow occurs here -LL | -LL | |a| { - | ^^^ closure construction occurs here -LL | f.n.insert(*a); - | --- second borrow occurs due to use of `f` in closure +LL | f.foo( + | - --- first borrow later used by call + | _____| + | | +LL | | +LL | | |a| { + | | ^^^ closure construction occurs here +LL | | f.n.insert(*a); + | | --- second borrow occurs due to use of `f` in closure +LL | | }) + | |__________- borrow occurs here error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-in-static.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-in-static.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-in-static.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-in-static.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,10 @@ LL | let x = Box::new(0); | - captured outer variable LL | Box::new(|| x) - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | ---^ + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `Fn` closure error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-14498.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-14498.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-14498.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-14498.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,14 +4,14 @@ // Also includes tests of the errors reported when the Box in question // is immutable (#14270). -#![feature(box_syntax)] + struct A { a: isize } struct B<'a> { a: Box<&'a mut isize> } fn indirect_write_to_imm_box() { let mut x: isize = 1; - let y: Box<_> = box &mut x; + let y: Box<_> = Box::new(&mut x); let p = &y; ***p = 2; //~ ERROR cannot assign to `***p` drop(p); @@ -19,7 +19,7 @@ fn borrow_in_var_from_var() { let mut x: isize = 1; - let mut y: Box<_> = box &mut x; + let mut y: Box<_> = Box::new(&mut x); let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed @@ -29,7 +29,7 @@ fn borrow_in_var_from_var_via_imm_box() { let mut x: isize = 1; - let y: Box<_> = box &mut x; + let y: Box<_> = Box::new(&mut x); let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed @@ -39,7 +39,7 @@ fn borrow_in_var_from_field() { let mut x = A { a: 1 }; - let mut y: Box<_> = box &mut x.a; + let mut y: Box<_> = Box::new(&mut x.a); let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed @@ -49,7 +49,7 @@ fn borrow_in_var_from_field_via_imm_box() { let mut x = A { a: 1 }; - let y: Box<_> = box &mut x.a; + let y: Box<_> = Box::new(&mut x.a); let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed @@ -59,7 +59,7 @@ fn borrow_in_field_from_var() { let mut x: isize = 1; - let mut y = B { a: box &mut x }; + let mut y = B { a: Box::new(&mut x) }; let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed @@ -69,7 +69,7 @@ fn borrow_in_field_from_var_via_imm_box() { let mut x: isize = 1; - let y = B { a: box &mut x }; + let y = B { a: Box::new(&mut x) }; let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed @@ -79,7 +79,7 @@ fn borrow_in_field_from_field() { let mut x = A { a: 1 }; - let mut y = B { a: box &mut x.a }; + let mut y = B { a: Box::new(&mut x.a) }; let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed @@ -89,7 +89,7 @@ fn borrow_in_field_from_field_via_imm_box() { let mut x = A { a: 1 }; - let y = B { a: box &mut x.a }; + let y = B { a: Box::new(&mut x.a) }; let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-1.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,9 @@ -#![feature(box_syntax)] - +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl Fake for T { } fn main() { - let x: Option> = Some(box 1); + let x: Option> = Some(Box::new(1)); match x { Some(ref _y) => { let _a = x; //~ ERROR cannot move @@ -12,6 +12,3 @@ _ => {} } } - -trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } -impl Fake for T { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | let _a = x; | ^ move out of `x` occurs here LL | _y.use_ref(); - | -- borrow later used here + | ------------ borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-issue-2657-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - fn main() { - let x: Option> = Some(box 1); + + let x: Option> = Some(Box::new(1)); + match x { Some(ref y) => { let _b = *y; //~ ERROR cannot move out diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-if.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-if.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-if.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-if.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ // either genuine or would require more advanced changes. The latter // cases are noted. -#![feature(box_syntax)] + fn borrow(_v: &isize) {} fn borrow_mut(_v: &mut isize) {} @@ -13,15 +13,15 @@ fn produce() -> T { panic!(); } fn inc(v: &mut Box) { - *v = box (**v + 1); + *v = Box::new(**v + 1); } fn pre_freeze_cond() { // In this instance, the freeze is conditional and starts before // the mut borrow. - let u = box 0; - let mut v: Box<_> = box 3; + let u = Box::new(0); + let mut v: Box<_> = Box::new(3); let mut _w = &u; if cond() { _w = &v; @@ -34,8 +34,8 @@ // In this instance, the freeze and mut borrow are on separate sides // of the if. - let u = box 0; - let mut v: Box<_> = box 3; + let u = Box::new(0); + let mut v: Box<_> = Box::new(3); let mut _w = &u; if cond() { _w = &v; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-if.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-if.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-if.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-if.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | borrow_mut(&mut *v); | ^^^^^^^ mutable borrow occurs here LL | _w.use_ref(); - | -- immutable borrow later used here + | ------------ immutable borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-loop.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-loop.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-loop.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-loop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,18 +1,18 @@ -#![feature(box_syntax)] - fn borrow(_v: &isize) {} fn borrow_mut(_v: &mut isize) {} fn cond() -> bool { panic!() } fn produce() -> T { panic!(); } + fn inc(v: &mut Box) { - *v = box (**v + 1); + *v = Box::new(**v + 1); } + fn loop_overarching_alias_mut() { // In this instance, the borrow ends on the line before the loop - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let mut x = &mut v; **x += 1; loop { @@ -23,18 +23,18 @@ fn block_overarching_alias_mut() { // In this instance, the borrow encompasses the entire closure call. - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let mut x = &mut v; for _ in 0..3 { borrow(&*v); //~ ERROR cannot borrow } - *x = box 5; + *x = Box::new(5); } fn loop_aliased_mut() { // In this instance, the borrow ends right after each assignment to _x - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut _x = &w; loop { borrow_mut(&mut *v); // OK @@ -45,8 +45,8 @@ fn while_aliased_mut() { // In this instance, the borrow ends right after each assignment to _x - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut _x = &w; while cond() { borrow_mut(&mut *v); // OK @@ -58,8 +58,8 @@ fn loop_aliased_mut_break() { // In this instance, the borrow ends right after each assignment to _x - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut _x = &w; loop { borrow_mut(&mut *v); @@ -72,8 +72,8 @@ fn while_aliased_mut_break() { // In this instance, the borrow ends right after each assignment to _x - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut _x = &w; while cond() { borrow_mut(&mut *v); @@ -84,8 +84,8 @@ } fn while_aliased_mut_cond(cond: bool, cond2: bool) { - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut x = &mut w; while cond { **x += 1; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | borrow(&*v); | ^^^ immutable borrow occurs here LL | } -LL | *x = box 5; +LL | *x = Box::new(5); | -- mutable borrow later used here error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ // either genuine or would require more advanced changes. The latter // cases are noted. -#![feature(box_syntax)] + fn borrow(_v: &isize) {} fn borrow_mut(_v: &mut isize) {} @@ -13,13 +13,13 @@ fn produce() -> T { panic!(); } fn inc(v: &mut Box) { - *v = box (**v + 1); + *v = Box::new(**v + 1); } fn pre_freeze() { // In this instance, the freeze starts before the mut borrow. - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let _w = &v; borrow_mut(&mut *v); //~ ERROR cannot borrow _w.use_ref(); @@ -28,7 +28,7 @@ fn post_freeze() { // In this instance, the const alias starts after the borrow. - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); borrow_mut(&mut *v); let _w = &v; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-lend-flow.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | borrow_mut(&mut *v); | ^^^^^^^ mutable borrow occurs here LL | _w.use_ref(); - | -- immutable borrow later used here + | ------------ immutable borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - use std::thread; @@ -8,8 +6,10 @@ f(v); } + + fn box_imm() { - let v: Box<_> = box 3; + let v: Box<_> = Box::new(3); let w = &v; thread::spawn(move|| { //~^ ERROR cannot move out of `v` because it is borrowed @@ -19,7 +19,7 @@ } fn box_imm_explicit() { - let v: Box<_> = box 3; + let v: Box<_> = Box::new(3); let w = &v; thread::spawn(move|| { //~^ ERROR cannot move diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ | -- move occurs due to use in closure LL | }); LL | w.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0505]: cannot move out of `v` because it is borrowed --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19 @@ -24,7 +24,7 @@ | -- move occurs due to use in closure LL | }); LL | w.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,12 @@ -#![feature(box_syntax)] +fn take(_v: Box) { +} + -fn take(_v: Box) { -} fn box_imm() { - let v = box 3; + let v = Box::new(3); let w = &v; take(v); //~ ERROR cannot move out of `v` because it is borrowed w.use_ref(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | take(v); | ^ move out of `v` occurs here LL | w.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,14 @@ -#![feature(box_syntax)] - fn borrow(v: &isize, f: F) where F: FnOnce(&isize) { f(v); } + + fn box_imm() { - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); borrow(&*v, |w| { //~ ERROR cannot borrow `v` as mutable - v = box 4; + v = Box::new(4); assert_eq!(*v, 3); assert_eq!(*w, 4); }) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | immutable borrow later used by call LL | |w| { | ^^^ mutable borrow occurs here -LL | v = box 4; +LL | v = Box::new(4); | - second borrow occurs due to use of `v` in closure error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + use std::ops::Add; @@ -12,12 +12,12 @@ fn add(self, f: Foo) -> Foo { let Foo(box i) = self; let Foo(box j) = f; - Foo(box (i + j)) + Foo(Box::new(i + j)) } } fn main() { - let x = Foo(box 3); + let x = Foo(Box::new(3)); let _y = {x} + x.clone(); // the `{x}` forces a move to occur //~^ ERROR borrow of moved value: `x` } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ error[E0382]: borrow of moved value: `x` --> $DIR/borrowck-loan-in-overloaded-op.rs:21:20 | -LL | let x = Foo(box 3); +LL | let x = Foo(Box::new(3)); | - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur - | - ^ value borrowed here after move + | - ^^^^^^^^^ value borrowed here after move | | | value moved here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ | ------ mutable borrow occurs here ... LL | p.times(3); - | ^ immutable borrow occurs here + | ^^^^^^^^^^ immutable borrow occurs here LL | LL | *q + 3; // OK to use the new alias `q` | -- mutable borrow later used here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-rcvr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-rcvr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-rcvr.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-loan-rcvr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,15 @@ error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable --> $DIR/borrowck-loan-rcvr.rs:23:14 | -LL | p.blockm(|| { - | - ------ ^^ mutable borrow occurs here - | | | - | | immutable borrow later used by call - | immutable borrow occurs here -LL | p.x = 10; - | --- second borrow occurs due to use of `p` in closure +LL | p.blockm(|| { + | - ------ ^^ mutable borrow occurs here + | | | + | _____| immutable borrow later used by call + | | +LL | | p.x = 10; + | | --- second borrow occurs due to use of `p` in closure +LL | | }) + | |______- immutable borrow occurs here error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable --> $DIR/borrowck-loan-rcvr.rs:34:5 @@ -15,7 +17,7 @@ LL | let l = &mut p; | ------ mutable borrow occurs here LL | p.impurem(); - | ^ immutable borrow occurs here + | ^^^^^^^^^^^ immutable borrow occurs here LL | LL | l.x += 1; | -------- mutable borrow later used here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,9 +6,7 @@ // Check that we do not ICE when compiling this // macro, which reuses the expression `$id` - #![feature(box_patterns)] -#![feature(box_syntax)] struct Foo { a: isize @@ -23,7 +21,7 @@ macro_rules! declare { ($id:expr, $rest:expr) => ({ self.check_id($id); - box Bar::Bar2($id, $rest) + Box::new(Bar::Bar2($id, $rest)) }) } match s { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture-ok.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture-ok.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture-ok.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture-ok.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let bar: Box<_> = box 3; + let bar: Box<_> = Box::new(3); let h = || -> isize { *bar }; assert_eq!(h(), 3); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(box_syntax,unboxed_closures)] +#![feature(unboxed_closures)] fn to_fn_mut>(f: F) -> F { f } fn to_fn_once>(f: F) -> F { f } pub fn main() { - let bar: Box<_> = box 3; + let bar: Box<_> = Box::new(3); let _g = to_fn_mut(|| { let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of }); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-by-capture.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,15 +1,18 @@ error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure --> $DIR/borrowck-move-by-capture.rs:9:29 | -LL | let bar: Box<_> = box 3; - | --- captured outer variable -LL | let _g = to_fn_mut(|| { -LL | let _h = to_fn_once(move || -> isize { *bar }); - | ^^^^^^^^^^^^^^^^ ---- - | | | - | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait - | | move occurs due to use in closure - | move out of `bar` occurs here +LL | let bar: Box<_> = Box::new(3); + | --- captured outer variable +LL | let _g = to_fn_mut(|| { + | ________________________- +LL | | let _h = to_fn_once(move || -> isize { *bar }); + | | ^^^^^^^^^^^^^^^^ ---- + | | | | + | | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait + | | | move occurs due to use in closure + | | move out of `bar` occurs here +LL | | }); + | |_____- captured by this `FnMut` closure error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-error-with-note.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-error-with-note.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-error-with-note.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-error-with-note.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,14 @@ -#![feature(box_syntax)] - enum Foo { Foo1(Box, Box), Foo2(Box), Foo3, } + + fn blah() { - let f = &Foo::Foo1(box 1, box 2); - match *f { //~ ERROR cannot move out of + let f = &Foo::Foo1(Box::new(1), Box::new(2)); + match *f { //~ ERROR cannot move out of Foo::Foo1(num1, num2) => (), Foo::Foo2(num) => (), @@ -42,8 +42,8 @@ fn free(_: T) {} fn blah2() { - let a = &A { a: box 1 }; - match a.a { //~ ERROR cannot move out of + let a = &A { a: Box::new(1) }; + match a.a { //~ ERROR cannot move out of n => { free(n) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,10 +3,10 @@ -#![feature(box_syntax)] + fn main() { - let a: Box> = box box 2; + let a: Box> = Box::new(Box::new(2)); let b = &a; let z = *a; //~ ERROR: cannot move out of `*a` because it is borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | let z = *a; | ^^ move out of `*a` occurs here LL | b.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ -#![feature(box_syntax)] - fn call_f isize>(f: F) -> isize { f() } + + fn main() { - let t: Box<_> = box 3; + let t: Box<_> = Box::new(3); call_f(move|| { *t + 1 }); call_f(move|| { *t + 1 }); //~ ERROR use of moved value diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `t` --> $DIR/borrowck-move-moved-value-into-closure.rs:11:12 | -LL | let t: Box<_> = box 3; +LL | let t: Box<_> = Box::new(3); | - move occurs because `t` has type `Box`, which does not implement the `Copy` trait LL | LL | call_f(move|| { *t + 1 }); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^^ move out of `t0` occurs here LL | *t1 = 22; LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14 | LL | let _x = Rc::new(vec![1, 2]).into_iter(); - | ^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-subcomponent.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-subcomponent.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-subcomponent.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-move-subcomponent.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // Tests that the borrow checker checks all components of a path when moving // out. -#![feature(box_syntax)] + struct S { x : Box @@ -10,7 +10,7 @@ fn f(_: T) {} fn main() { - let a : S = S { x : box 1 }; + let a : S = S { x : Box::new(1) }; let pb = &a; let S { x: ax } = a; //~ ERROR cannot move out f(pb); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-multiple-captures.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-multiple-captures.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-multiple-captures.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-multiple-captures.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,13 @@ -#![feature(box_syntax)] - use std::thread; + fn borrow(_: &T) { } + fn different_vars_after_borrows() { - let x1: Box<_> = box 1; + let x1: Box<_> = Box::new(1); let p1 = &x1; - let x2: Box<_> = box 2; + let x2: Box<_> = Box::new(2); let p2 = &x2; thread::spawn(move|| { //~^ ERROR cannot move out of `x1` because it is borrowed @@ -20,9 +20,9 @@ } fn different_vars_after_moves() { - let x1: Box<_> = box 1; + let x1: Box<_> = Box::new(1); drop(x1); - let x2: Box<_> = box 2; + let x2: Box<_> = Box::new(2); drop(x2); thread::spawn(move|| { //~^ ERROR use of moved value: `x1` @@ -33,7 +33,7 @@ } fn same_var_after_borrow() { - let x: Box<_> = box 1; + let x: Box<_> = Box::new(1); let p = &x; thread::spawn(move|| { //~^ ERROR cannot move out of `x` because it is borrowed @@ -44,7 +44,7 @@ } fn same_var_after_move() { - let x: Box<_> = box 1; + let x: Box<_> = Box::new(1); drop(x); thread::spawn(move|| { //~^ ERROR use of moved value: `x` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-multiple-captures.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-multiple-captures.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-multiple-captures.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-multiple-captures.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -30,7 +30,7 @@ error[E0382]: use of moved value: `x1` --> $DIR/borrowck-multiple-captures.rs:27:19 | -LL | let x1: Box<_> = box 1; +LL | let x1: Box<_> = Box::new(1); | -- move occurs because `x1` has type `Box`, which does not implement the `Copy` trait LL | drop(x1); | -- value moved here @@ -44,7 +44,7 @@ error[E0382]: use of moved value: `x2` --> $DIR/borrowck-multiple-captures.rs:27:19 | -LL | let x2: Box<_> = box 2; +LL | let x2: Box<_> = Box::new(2); | -- move occurs because `x2` has type `Box`, which does not implement the `Copy` trait LL | drop(x2); | -- value moved here @@ -91,7 +91,7 @@ error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:49:19 | -LL | let x: Box<_> = box 1; +LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | drop(x); | - value moved here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,9 @@ | ^^^^^^ second mutable borrow occurs here LL | 2 => { addr.push(&mut x); } LL | _ => { addr.push(&mut x); } - | ---- ------ first mutable borrow occurs here - | | + | ----------------- + | | | + | | first mutable borrow occurs here | first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time @@ -15,8 +16,9 @@ LL | 2 => { addr.push(&mut x); } | ^^^^^^ second mutable borrow occurs here LL | _ => { addr.push(&mut x); } - | ---- ------ first mutable borrow occurs here - | | + | ----------------- + | | | + | | first mutable borrow occurs here | first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^^^^^^^ mutable borrow occurs here LL | **t2 += 1; // Mutates `*t0` LL | p.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0499]: cannot borrow `t0` as mutable more than once at a time --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:19:18 @@ -18,7 +18,7 @@ | ^^^^^^^ second mutable borrow occurs here LL | **t2 += 1; // Mutates `*t0` but not through `*p` LL | p.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-uniq.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-uniq.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-uniq.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-mut-uniq.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] use std::mem::swap; @@ -20,7 +19,7 @@ } pub fn main() { - let mut ints: Box<_> = box Ints {sum: box 0, values: Vec::new()}; + let mut ints: Box<_> = Box::new(Ints {sum: Box::new(0), values: Vec::new()}); add_int(&mut *ints, 22); add_int(&mut *ints, 44); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - struct Node_ { a: Box } @@ -8,8 +6,10 @@ Node(Node_), Empty, } + fn main() { - let mut x: Box<_> = box Cycle::Node(Node_ {a: box Cycle::Empty}); + let mut x: Box<_> = Box::new(Cycle::Node(Node_ {a: Box::new(Cycle::Empty)})); + // Create a cycle! match *x { Cycle::Node(ref mut y) => { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-object-lifetime.rs:20:13 - | -LL | let y = x.borrowed(); - | - immutable borrow occurs here -LL | let z = x.mut_borrowed(); - | ^ mutable borrow occurs here -LL | y.use_ref(); - | - immutable borrow later used here - -error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-object-lifetime.rs:26:13 - | -LL | let y = x.borrowed(); - | - immutable borrow occurs here -LL | let z = &mut x; - | ^^^^^^ mutable borrow occurs here -LL | y.use_ref(); - | - immutable borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-object-lifetime.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-object-lifetime.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-object-lifetime.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-object-lifetime.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,21 +2,21 @@ --> $DIR/borrowck-object-lifetime.rs:20:13 | LL | let y = x.borrowed(); - | - immutable borrow occurs here + | ------------ immutable borrow occurs here LL | let z = x.mut_borrowed(); | ^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/borrowck-object-lifetime.rs:26:13 | LL | let y = x.borrowed(); - | - immutable borrow occurs here + | ------------ immutable borrow occurs here LL | let z = &mut x; | ^^^^^^ mutable borrow occurs here LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | let q = &f[&s]; | ^ immutable borrow occurs here LL | p.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/borrowck-overloaded-index-autoderef.rs:43:18 @@ -16,7 +16,7 @@ LL | let q = &mut f[&s]; | ^ second mutable borrow occurs here LL | p.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error[E0499]: cannot borrow `f.foo` as mutable more than once at a time --> $DIR/borrowck-overloaded-index-autoderef.rs:53:18 @@ -26,7 +26,7 @@ LL | let q = &mut f.foo[&s]; | ^^^^^ second mutable borrow occurs here LL | p.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable --> $DIR/borrowck-overloaded-index-autoderef.rs:65:18 @@ -36,7 +36,7 @@ LL | let q = &mut f.foo[&s]; | ^^^^^ mutable borrow occurs here LL | p.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0506]: cannot assign to `f.foo` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:71:5 @@ -46,7 +46,7 @@ LL | f.foo = g; | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `*f` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:77:5 @@ -56,7 +56,7 @@ LL | *f = g; | ^^^^^^ assignment to borrowed `*f` occurs here LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `f.foo` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:83:5 @@ -66,7 +66,7 @@ LL | f.foo = g; | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here LL | p.use_mut(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `*f` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:89:5 @@ -76,7 +76,7 @@ LL | *f = g; | ^^^^^^ assignment to borrowed `*f` occurs here LL | p.use_mut(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to 8 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - use std::ops::Index; struct MyVec { @@ -14,8 +12,10 @@ } } + + fn main() { - let v = MyVec::> { data: vec![box 1, box 2, box 3] }; + let v = MyVec::> { data: vec![Box::new(1), Box::new(2), Box::new(3)] }; let good = &v[0]; // Shouldn't fail here let bad = v[0]; //~^ ERROR cannot move out of index of `MyVec>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | ^^ immutable borrow occurs here ... LL | y.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/borrowck-report-with-custom-diagnostic.rs:21:21 @@ -20,7 +20,7 @@ | ^^^^^^ mutable borrow occurs here ... LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-report-with-custom-diagnostic.rs:36:17 @@ -32,7 +32,7 @@ | ^^^^^^ second mutable borrow occurs here ... LL | y.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^^^^^^^ mutable borrow occurs here LL | *t1 = 22; LL | p.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | let b = u.c; | ^^^ use of borrowed `u.s.a` LL | ra.use_mut(); - | -- borrow later used here + | ------------ borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-uniq-via-lend.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-uniq-via-lend.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-uniq-via-lend.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-uniq-via-lend.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,17 +1,17 @@ -#![feature(box_syntax)] +fn borrow(_v: &isize) {} + -fn borrow(_v: &isize) {} fn local() { - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); borrow(&*v); } fn local_rec() { struct F { f: Box } - let mut v = F {f: box 3}; + let mut v = F {f: Box::new(3)}; borrow(&*v.f); } @@ -19,35 +19,35 @@ struct F { f: G } struct G { g: H } struct H { h: Box } - let mut v = F {f: G {g: H {h: box 3}}}; + let mut v = F {f: G {g: H {h: Box::new(3)}}}; borrow(&*v.f.g.h); } fn aliased_imm() { - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let w = &v; borrow(&*v); w.use_ref(); } fn aliased_mut() { - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let w = &mut v; borrow(&*v); //~ ERROR cannot borrow `*v` w.use_mut(); } fn aliased_other() { - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let x = &mut w; borrow(&*v); x.use_mut(); } fn aliased_other_reassign() { - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut x = &mut w; x = &mut v; borrow(&*v); //~ ERROR cannot borrow `*v` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | borrow(&*v); | ^^^ immutable borrow occurs here LL | w.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable --> $DIR/borrowck-uniq-via-lend.rs:53:12 @@ -16,7 +16,7 @@ LL | borrow(&*v); | ^^^ immutable borrow occurs here LL | x.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-unused-mut-locals.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-unused-mut-locals.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-unused-mut-locals.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-unused-mut-locals.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,5 @@ // run-pass +#![allow(dead_code)] #![deny(unused_mut)] #[derive(Debug)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,41 +1,39 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - struct A { a: isize, b: Box } fn field_copy_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.b; drop(x.a); **p = 3; } fn fu_field_copy_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.b; - let y = A { b: box 3, .. x }; + let y = A { b: Box::new(3), .. x }; drop(y); **p = 4; } fn field_deref_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; drop(*x.b); *p = 3; } fn field_move_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; drop(x.b); *p = 3; } fn fu_field_move_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; let y = A { a: 3, .. x }; drop(y); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-use-mut-borrow.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-use-mut-borrow.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-use-mut-borrow.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-use-mut-borrow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - #[derive(Copy, Clone)] struct A { a: isize, b: isize } struct B { a: isize, b: Box } + + fn var_copy_after_var_borrow() { let mut x: isize = 1; let p = &mut x; @@ -50,21 +50,21 @@ } fn var_deref_after_var_borrow() { - let mut x: Box = box 1; + let mut x: Box = Box::new(1); let p = &mut x; drop(*x); //~ ERROR cannot use `*x` because it was mutably borrowed **p = 2; } fn field_deref_after_var_borrow() { - let mut x = B { a: 1, b: box 2 }; + let mut x = B { a: 1, b: Box::new(2) }; let p = &mut x; drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed p.a = 3; } fn field_deref_after_field_borrow() { - let mut x = B { a: 1, b: box 2 }; + let mut x = B { a: 1, b: Box::new(2) }; let p = &mut x.b; drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed **p = 3; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,9 @@ | ------ first mutable borrow occurs here ... LL | v.push(tail[0] + tail[1]); - | ^ ------- first borrow later used here - | | + | ^^^^^^^-------^^^^^^^^^^^ + | | | + | | first borrow later used here | second mutable borrow occurs here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,12 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + fn a() { - let mut vec = [box 1, box 2, box 3]; + let mut vec = [Box::new(1), Box::new(2), Box::new(3)]; match vec { [box ref _a, _, _] => { //~^ NOTE borrow of `vec[_]` occurs here - vec[0] = box 4; //~ ERROR cannot assign + vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE assignment to borrowed `vec[_]` occurs here _a.use_ref(); //~^ NOTE borrow later used here @@ -15,12 +15,12 @@ } fn b() { - let mut vec = vec![box 1, box 2, box 3]; + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; let vec: &mut [Box] = &mut vec; match vec { &mut [ref _b @ ..] => { //~^ borrow of `vec[_]` occurs here - vec[0] = box 4; //~ ERROR cannot assign + vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE assignment to borrowed `vec[_]` occurs here _b.use_ref(); //~^ NOTE borrow later used here @@ -29,7 +29,7 @@ } fn c() { - let mut vec = vec![box 1, box 2, box 3]; + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; let vec: &mut [Box] = &mut vec; match vec { //~^ ERROR cannot move out @@ -50,7 +50,7 @@ } fn d() { - let mut vec = vec![box 1, box 2, box 3]; + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; let vec: &mut [Box] = &mut vec; match vec { //~^ ERROR cannot move out @@ -69,7 +69,7 @@ } fn e() { - let mut vec = vec![box 1, box 2, box 3]; + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; let vec: &mut [Box] = &mut vec; match vec { //~^ ERROR cannot move out diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,11 +4,11 @@ LL | [box ref _a, _, _] => { | ------ borrow of `vec[_]` occurs here LL | -LL | vec[0] = box 4; +LL | vec[0] = Box::new(4); | ^^^^^^ assignment to borrowed `vec[_]` occurs here LL | LL | _a.use_ref(); - | -- borrow later used here + | ------------ borrow later used here error[E0506]: cannot assign to `vec[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 @@ -16,11 +16,11 @@ LL | &mut [ref _b @ ..] => { | ----------- borrow of `vec[_]` occurs here LL | -LL | vec[0] = box 4; +LL | vec[0] = Box::new(4); | ^^^^^^ assignment to borrowed `vec[_]` occurs here LL | LL | _b.use_ref(); - | -- borrow later used here + | ------------ borrow later used here error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:34:11 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrow-tuple-fields.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrow-tuple-fields.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrow-tuple-fields.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrow-tuple-fields.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,13 @@ -#![feature(box_syntax)] +struct Foo(Box, isize); + +struct Bar(isize, isize); -struct Foo(Box, isize); -struct Bar(isize, isize); fn main() { - let x: (Box<_>, _) = (box 1, 2); + let x: (Box<_>, _) = (Box::new(1), 2); let r = &x.0; let y = x; //~ ERROR cannot move out of `x` because it is borrowed @@ -23,7 +23,7 @@ let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time a.use_ref(); - let x = Foo(box 1, 2); + let x = Foo(Box::new(1), 2); let r = &x.0; let y = x; //~ ERROR cannot move out of `x` because it is borrowed r.use_ref(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrow-tuple-fields.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrow-tuple-fields.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/borrow-tuple-fields.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/borrow-tuple-fields.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^ move out of `x` occurs here LL | LL | r.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable --> $DIR/borrow-tuple-fields.rs:18:13 @@ -17,7 +17,7 @@ LL | let b = &mut x.0; | ^^^^^^^^ mutable borrow occurs here LL | a.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0499]: cannot borrow `x.0` as mutable more than once at a time --> $DIR/borrow-tuple-fields.rs:23:13 @@ -27,7 +27,7 @@ LL | let b = &mut x.0; | ^^^^^^^^ second mutable borrow occurs here LL | a.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/borrow-tuple-fields.rs:28:13 @@ -37,7 +37,7 @@ LL | let y = x; | ^ move out of `x` occurs here LL | r.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable --> $DIR/borrow-tuple-fields.rs:33:13 @@ -47,7 +47,7 @@ LL | let b = &mut x.0; | ^^^^^^^^ mutable borrow occurs here LL | a.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0499]: cannot borrow `x.0` as mutable more than once at a time --> $DIR/borrow-tuple-fields.rs:38:13 @@ -57,7 +57,7 @@ LL | let b = &mut x.0; | ^^^^^^^^ second mutable borrow occurs here LL | a.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/fsu-moves-and-copies.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/fsu-moves-and-copies.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/fsu-moves-and-copies.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/fsu-moves-and-copies.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ // Issue 4691: Ensure that functional-struct-updates operates // correctly and moves rather than copy when appropriate. -#![feature(box_syntax, core)] +#![feature(core)] struct ncint { v: isize } fn ncint(v: isize) -> ncint { ncint { v: v } } @@ -17,7 +17,7 @@ struct MoveFoo { copied: isize, moved: Box, } impl MoveFoo { - fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: box y } } + fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: Box::new(y) } } } struct DropNoFoo { inner: NoFoo } @@ -53,8 +53,8 @@ // Case 2: Owned let f = DropMoveFoo::new(5, 6); - let b = DropMoveFoo { inner: MoveFoo { moved: box 7, ..f.inner }}; - let c = DropMoveFoo { inner: MoveFoo { moved: box 8, ..f.inner }}; + let b = DropMoveFoo { inner: MoveFoo { moved: Box::new(7), ..f.inner }}; + let c = DropMoveFoo { inner: MoveFoo { moved: Box::new(8), ..f.inner }}; assert_eq!(f.inner.copied, 5); assert_eq!(*f.inner.moved, 6); @@ -69,7 +69,7 @@ // copying move-by-default fields from `f`, so it moves: let f = MoveFoo::new(11, 12); - let b = MoveFoo {moved: box 13, ..f}; + let b = MoveFoo {moved: Box::new(13), ..f}; let c = MoveFoo {copied: 14, ..f}; assert_eq!(b.copied, 11); assert_eq!(*b.moved, 13); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/index-mut-help.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/index-mut-help.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/index-mut-help.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/index-mut-help.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/index-mut-help.rs:11:5 | LL | map["peter"].clear(); - | ^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/index-mut-help-with-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/index-mut-help-with-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/index-mut-help-with-impl.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/index-mut-help-with-impl.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/index-mut-help-with-impl.rs:9:5 | LL | Index::index(&v, 1..2).make_ascii_uppercase(); - | ^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-17263.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-17263.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-17263.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-17263.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,12 @@ // check-pass -#![feature(box_syntax)] - struct Foo { a: isize, b: isize } fn main() { - let mut x: Box<_> = box Foo { a: 1, b: 2 }; + let mut x: Box<_> = Box::new(Foo { a: 1, b: 2 }); let (a, b) = (&mut x.a, &mut x.b); - let mut foo: Box<_> = box Foo { a: 1, b: 2 }; + let mut foo: Box<_> = Box::new(Foo { a: 1, b: 2 }); let (c, d) = (&mut foo.a, &foo.b); // We explicitly use the references created above to illustrate that the diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-42344.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-42344.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-42344.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-42344.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-42344.rs:4:5 | LL | TAB[0].iter_mut(); - | ^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-51117.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-51117.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-51117.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-51117.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | Some(baz) => { | --- first mutable borrow occurs here LL | bar.take(); - | ^^^ second mutable borrow occurs here + | ^^^^^^^^^^ second mutable borrow occurs here LL | drop(baz); | --- first borrow later used here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-81365-10.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-81365-10.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-81365-10.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-81365-10.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-81365-10.rs:21:9 | LL | let first = &self.deref().target_field; - | ---- borrow of `self.container_field` occurs here + | ------------ borrow of `self.container_field` occurs here LL | self.container_field = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here LL | first; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-81365-5.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-81365-5.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-81365-5.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-81365-5.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-81365-5.rs:28:9 | LL | let first = self.get(); - | ---- borrow of `self.container_field` occurs here + | ---------- borrow of `self.container_field` occurs here LL | self.container_field = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here LL | first; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82032.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82032.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82032.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82032.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | | help: use mutable method: `values_mut()` | this iterator yields `&` references LL | v.flush(); - | ^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,6 @@ //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied //~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied LockedMarket(generator.lock().unwrap().buy()) - //~^ ERROR cannot return value referencing temporary value } struct LockedMarket(T); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | expected 0 lifetime arguments | note: struct defined here, with 0 lifetime parameters - --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8 + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8 | LL | struct LockedMarket(T); | ^^^^^^^^^^^^ @@ -19,7 +19,7 @@ | ^^^^^^^^^^^^ expected 1 generic argument | note: struct defined here, with 1 generic parameter: `T` - --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8 + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8 | LL | struct LockedMarket(T); | ^^^^^^^^^^^^ - @@ -28,16 +28,6 @@ LL | async fn buy_lock(generator: &Mutex) -> LockedMarket<'_, T> { | +++ -error[E0515]: cannot return value referencing temporary value - --> $DIR/issue-82126-mismatched-subst-and-hir.rs:19:5 - | -LL | LockedMarket(generator.lock().unwrap().buy()) - | ^^^^^^^^^^^^^-------------------------^^^^^^^ - | | | - | | temporary value created here - | returns a value referencing data owned by the current function - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0107, E0515. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82462.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82462.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82462.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82462.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +struct DroppingSlice<'a>(&'a [i32]); + +impl Drop for DroppingSlice<'_> { + fn drop(&mut self) { + println!("hi from slice"); + } +} + +impl DroppingSlice<'_> { + fn iter(&self) -> std::slice::Iter<'_, i32> { + self.0.iter() + } +} + +fn main() { + let mut v = vec![1, 2, 3, 4]; + for x in DroppingSlice(&*v).iter() { + v.push(*x); //~ERROR + break; + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82462.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82462.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-82462.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-82462.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/issue-82462.rs:18:9 + | +LL | for x in DroppingSlice(&*v).iter() { + | ------------------ + | | | + | | immutable borrow occurs here + | a temporary with access to the immutable borrow is created here ... +LL | v.push(*x); + | ^^^^^^^^^^ mutable borrow occurs here +LL | break; +LL | } + | - ... and the immutable borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DroppingSlice` + | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + | +LL | }; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-85581.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-85581.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-85581.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-85581.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | first mutable borrow occurs here | a temporary with access to the first borrow is created here ... LL | Some(_) => { heap.pop(); }, - | ^^^^ second mutable borrow occurs here + | ^^^^^^^^^^ second mutable borrow occurs here ... LL | } | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-85765.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-85765.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-85765.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-85765.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ---- help: consider changing this to be a mutable reference: `&mut Vec>` LL | LL | rofl.push(Vec::new()); - | ^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0594]: cannot assign to `*r`, which is behind a `&` reference --> $DIR/issue-85765.rs:12:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-87456-point-to-closure.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-87456-point-to-closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-87456-point-to-closure.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-87456-point-to-closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// Regression test for #87456. + +fn take_mut(_val: impl FnMut()) {} + +fn main() { + let val = String::new(); + //~^ NOTE: captured outer variable + take_mut(|| { + //~^ NOTE: captured by this `FnMut` closure + let _foo: String = val; + //~^ ERROR: cannot move out of `val`, a captured variable in an `FnMut` closure [E0507] + //~| NOTE: move occurs because + }) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-87456-point-to-closure.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-87456-point-to-closure.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-87456-point-to-closure.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-87456-point-to-closure.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure + --> $DIR/issue-87456-point-to-closure.rs:10:28 + | +LL | let val = String::new(); + | --- captured outer variable +LL | +LL | take_mut(|| { + | ______________- +LL | | +LL | | let _foo: String = val; + | | ^^^ + | | | + | | move occurs because `val` has type `String`, which does not implement the `Copy` trait + | | help: consider borrowing here: `&val` +LL | | +LL | | +LL | | }) + | |_____- captured by this `FnMut` closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-minimal-example.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-minimal-example.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-minimal-example.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-minimal-example.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +#![feature(const_fn_trait_bound)] +// Regression test related to issue 88434 + +const _CONST: &() = &f(&|_| {}); + +const fn f(_: &F) +where + F: FnMut(&u8), +{ + panic!() //~ ERROR evaluation of constant value failed +} + +fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-minimal-example.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-minimal-example.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-minimal-example.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-minimal-example.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-88434-minimal-example.rs:10:5 + | +LL | const _CONST: &() = &f(&|_| {}); + | ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:4:22 +... +LL | panic!() + | ^^^^^^^^ + | | + | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5 + | inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:4:25: 4:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +#![feature(const_fn_trait_bound)] +// Regression test for issue 88434 + +const _CONST: &[u8] = &f(&[], |_| {}); + +const fn f(_: &[u8], _: F) -> &[u8] +where + F: FnMut(&u8), +{ + panic!() //~ ERROR evaluation of constant value failed +} + +fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5 + | +LL | const _CONST: &[u8] = &f(&[], |_| {}); + | -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:4:24 +... +LL | panic!() + | ^^^^^^^^ + | | + | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5 + | inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/move-error-snippets.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/move-error-snippets.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/move-error-snippets.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/move-error-snippets.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ ::: $DIR/move-error-snippets.rs:21:1 | LL | sss!(); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `aaa` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -53,7 +53,7 @@ --> $DIR/mut-borrow-of-mut-ref.rs:35:5 | LL | f.bar(); - | ^ cannot borrow as mutable + | ^^^^^^^ cannot borrow as mutable | help: consider making the binding mutable | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/mut-borrow-outside-loop.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/mut-borrow-outside-loop.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/mut-borrow-outside-loop.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/mut-borrow-outside-loop.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | let second = &mut void; | ^^^^^^^^^ second mutable borrow occurs here LL | first.use_mut(); - | ----- first borrow later used here + | --------------- first borrow later used here error[E0499]: cannot borrow `inner_void` as mutable more than once at a time --> $DIR/mut-borrow-outside-loop.rs:15:28 @@ -17,7 +17,7 @@ | ^^^^^^^^^^^^^^^ second mutable borrow occurs here LL | inner_second.use_mut(); LL | inner_first.use_mut(); - | ----------- first borrow later used here + | --------------------- first borrow later used here error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -24,12 +24,12 @@ | = note: expected fn pointer `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)` found fn pointer `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)` -note: the lifetime `'c` as defined on the method body at 27:24... +note: the lifetime `'c` as defined here... --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 | LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { | ^^ -note: ...does not necessarily outlive the lifetime `'c` as defined on the method body at 27:24 +note: ...does not necessarily outlive the lifetime `'c` as defined here --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 | LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { @@ -43,12 +43,12 @@ | = note: expected fn pointer `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)` found fn pointer `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)` -note: the lifetime `'c` as defined on the method body at 27:24... +note: the lifetime `'c` as defined here... --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 | LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { | ^^ -note: ...does not necessarily outlive the lifetime `'c` as defined on the method body at 27:24 +note: ...does not necessarily outlive the lifetime `'c` as defined here --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 | LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-across-loop.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-across-loop.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-across-loop.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-across-loop.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/two-phase-across-loop.rs:17:22 | LL | strings.push(foo.get_string()); - | ^^^ `foo` was mutably borrowed here in the previous iteration of the loop + | ^^^^^^^^^^^^^^^^ `foo` was mutably borrowed here in the previous iteration of the loop error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,18 @@ error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:16:9 | -LL | vec.get({ - | --- --- immutable borrow later used by call - | | - | immutable borrow occurs here -LL | -LL | vec.push(2); - | ^^^ mutable borrow occurs here +LL | vec.get({ + | - --- immutable borrow later used by call + | _____| + | | +LL | | +LL | | vec.push(2); + | | ^^^^^^^^^^^ mutable borrow occurs here +LL | | +LL | | +LL | | 0 +LL | | }); + | |______- immutable borrow occurs here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-multi-mut.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-multi-mut.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-multi-mut.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-multi-mut.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -12,8 +12,9 @@ --> $DIR/two-phase-multi-mut.rs:11:16 | LL | foo.method(&mut foo); - | --- ------ ^^^^^^^^ second mutable borrow occurs here - | | | + | -----------^^^^^^^^- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -27,8 +27,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here | = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -27,8 +27,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here | = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,9 @@ | -- immutable borrow occurs here LL | LL | v.extend(shared); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^^^------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable @@ -26,8 +27,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,9 @@ | -- immutable borrow occurs here LL | LL | v.extend(shared); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^^^------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable @@ -26,8 +27,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable @@ -16,8 +17,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable @@ -27,8 +29,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here | note: the lint level is defined here @@ -24,8 +25,9 @@ | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here | note: the lint level is defined here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-sneaky.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-sneaky.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-sneaky.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-sneaky.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | first mutable borrow occurs here LL | LL | v.push(format!("foo")); - | ^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ --> $DIR/two-phase-surprise-no-conflict.rs:57:17 | LL | self.hash_expr(&self.cx_mut.body(eid).value); - | ^^^^^---------^^-----------^^^^^^^^^^^^^^^^^ + | ^^^^^---------^^---------------------^^^^^^^ | | | | | | | immutable borrow occurs here | | immutable borrow later used by call @@ -23,8 +23,9 @@ --> $DIR/two-phase-surprise-no-conflict.rs:119:51 | LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); - | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ----------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -32,8 +33,9 @@ --> $DIR/two-phase-surprise-no-conflict.rs:122:54 | LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | -------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -41,8 +43,9 @@ --> $DIR/two-phase-surprise-no-conflict.rs:125:53 | LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -50,8 +53,9 @@ --> $DIR/two-phase-surprise-no-conflict.rs:128:44 | LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ---------------------------------------^^^^^^^^^^^^^^^^^-- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -102,8 +106,9 @@ --> $DIR/two-phase-surprise-no-conflict.rs:154:54 | LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | -------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -124,8 +129,9 @@ --> $DIR/two-phase-surprise-no-conflict.rs:158:53 | LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -143,8 +149,9 @@ --> $DIR/two-phase-surprise-no-conflict.rs:162:44 | LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ---------------------------------------^^^^^^^^^^^^^^^^^-- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,15 @@ error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9 | -LL | let y = vec![format!("World")]; - | - captured outer variable -LL | call(|| { -LL | y.into_iter(); - | ^ move occurs because `y` has type `Vec`, which does not implement the `Copy` trait +LL | let y = vec![format!("World")]; + | - captured outer variable +LL | call(|| { + | __________- +LL | | y.into_iter(); + | | ^ move occurs because `y` has type `Vec`, which does not implement the `Copy` trait +LL | | +LL | | }); + | |_____- captured by this `Fn` closure error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/box/into-boxed-slice-fail.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/box/into-boxed-slice-fail.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/box/into-boxed-slice-fail.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/box/into-boxed-slice-fail.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/into-boxed-slice-fail.rs:7:35 | LL | let _ = Box::into_boxed_slice(boxed_slice); - | ^^^^^^^^^^^ doesn't have a size known at compile-time + | --------------------- ^^^^^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by `Box::::into_boxed_slice` @@ -24,7 +26,9 @@ --> $DIR/into-boxed-slice-fail.rs:11:35 | LL | let _ = Box::into_boxed_slice(boxed_trait); - | ^^^^^^^^^^^ doesn't have a size known at compile-time + | --------------------- ^^^^^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `dyn Debug` note: required by `Box::::into_boxed_slice` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/box/leak-alloc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/box/leak-alloc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/box/leak-alloc.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/box/leak-alloc.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/leak-alloc.rs:26:10 | LL | let boxed = Box::new_in(10, alloc.by_ref()); - | ----- borrow of `alloc` occurs here + | -------------- borrow of `alloc` occurs here LL | let theref = Box::leak(boxed); LL | drop(alloc); | ^^^^^ move out of `alloc` occurs here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/bug-7183-generics.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/bug-7183-generics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/bug-7183-generics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/bug-7183-generics.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -// run-pass - -trait Speak : Sized { - fn say(&self, s:&str) -> String; - fn hi(&self) -> String { hello(self) } -} - -fn hello(s:&S) -> String{ - s.say("hello") -} - -impl Speak for isize { - fn say(&self, s:&str) -> String { - format!("{}: {}", s, *self) - } -} - -impl Speak for Option { - fn say(&self, s:&str) -> String { - match *self { - None => format!("{} - none", s), - Some(ref x) => { format!("something!{}", x.say(s)) } - } - } -} - - -pub fn main() { - assert_eq!(3.hi(), "hello: 3".to_string()); - assert_eq!(Some(Some(3)).hi(), - "something!something!hello: 3".to_string()); - assert_eq!(None::.hi(), "hello - none".to_string()); - - assert_eq!(Some(None::).hi(), "something!hello - none".to_string()); - assert_eq!(Some(3).hi(), "something!hello: 3".to_string()); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,10 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn foo(x: &mut Box) { - *x = box 5; + *x = Box::new(5); } pub fn main() { - foo(&mut box 4); + foo(&mut Box::new(4)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cannot-mutate-captured-non-mut-var.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/cannot-mutate-captured-non-mut-var.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cannot-mutate-captured-non-mut-var.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cannot-mutate-captured-non-mut-var.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -12,7 +12,7 @@ LL | let s = std::io::stdin(); | - help: consider changing this to be mutable: `mut s` LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cast/issue-89497.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/cast/issue-89497.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cast/issue-89497.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cast/issue-89497.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +// Regression test for issue #89497. + +// run-rustfix + +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { &*(pointer as *const i32) }; + //~^ ERROR: non-primitive cast + //~| HELP: consider borrowing the value +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cast/issue-89497.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/cast/issue-89497.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cast/issue-89497.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cast/issue-89497.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +// Regression test for issue #89497. + +// run-rustfix + +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; + //~^ ERROR: non-primitive cast + //~| HELP: consider borrowing the value +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cast/issue-89497.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/cast/issue-89497.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cast/issue-89497.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cast/issue-89497.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0605]: non-primitive cast: `*const i32` as `&'static i32` + --> $DIR/issue-89497.rs:7:45 + | +LL | let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL - let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; +LL + let _reference: &'static i32 = unsafe { &*(pointer as *const i32) }; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0605`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/chalkify/type_inference.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/chalkify/type_inference.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/chalkify/type_inference.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/chalkify/type_inference.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/type_inference.rs:27:14 | LL | only_bar(x); - | ^ the trait `Bar` is not implemented for `{float}` + | -------- ^ the trait `Bar` is not implemented for `{float}` + | | + | required by a bound introduced by this call | = help: the following implementations were found: diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/class-cast-to-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/class-cast-to-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/class-cast-to-trait.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/class-cast-to-trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - trait Noisy { fn speak(&self); } @@ -48,7 +46,9 @@ } } + + fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; nyan.eat(); //~ ERROR no method named `eat` found } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cleanup-arm-conditional.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/cleanup-arm-conditional.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cleanup-arm-conditional.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cleanup-arm-conditional.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax, os)] +#![feature(os)] use std::os; @@ -15,7 +15,7 @@ impl Test { fn get_x(&self) -> Option> { - Some(box self.x) + Some(Box::new(self.x)) } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cleanup-rvalue-scopes.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/cleanup-rvalue-scopes.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cleanup-rvalue-scopes.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cleanup-rvalue-scopes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,6 @@ // lifetime rules. #![feature(box_patterns)] -#![feature(box_syntax)] use std::ops::Drop; @@ -106,8 +105,8 @@ end_of_block!(AddFlags { bits: ref _x }, AddFlags(1)); end_of_block!(&AddFlags { bits }, &AddFlags(1)); end_of_block!((_, ref _y), (AddFlags(1), 22)); - end_of_block!(box ref _x, box AddFlags(1)); - end_of_block!(box _x, box AddFlags(1)); + end_of_block!(box ref _x, std::boxed::Box::new(AddFlags(1))); + end_of_block!(box _x, std::boxed::Box::new(AddFlags(1))); end_of_block!(_, { { check_flags(0); &AddFlags(1) } }); end_of_block!(_, &((Box { f: AddFlags(1) }).f)); end_of_block!(_, &(([AddFlags(1)])[0])); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,8 +21,6 @@ // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; enum Conzabble { @@ -40,7 +38,7 @@ pub fn fails() { let x = 2; let mut y: Vec> = Vec::new(); - y.push(box Conzabble::Bickwick(do_it(&get_bar(x)))); + y.push(Box::new(Conzabble::Bickwick(do_it(&get_bar(x))))); } pub fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/clone-with-exterior.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/clone-with-exterior.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/clone-with-exterior.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/clone-with-exterior.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ #![allow(unused_must_use)] // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; struct Pair { @@ -13,7 +11,7 @@ } pub fn main() { - let z: Box<_> = box Pair { a : 10, b : 12}; + let z: Box<_> = Box::new(Pair { a : 10, b : 12}); thread::spawn(move|| { assert_eq!(z.a, 10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/close-over-big-then-small-data.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/close-over-big-then-small-data.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/close-over-big-then-small-data.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/close-over-big-then-small-data.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ // storing closure data (as we used to do), the u64 would // overwrite the u16. -#![feature(box_syntax)] - struct Pair { a: A, b: B } @@ -27,10 +25,10 @@ } fn f(a: A, b: u16) -> Box+'static> { - box Invoker { + Box::new(Invoker { a: a, b: b, - } as Box+'static> + }) as Box+'static> } pub fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closure-expected.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closure-expected.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closure-expected.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closure-expected.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/closure-expected.rs:3:23 | LL | let y = x.or_else(4); - | ^ expected an `FnOnce<()>` closure, found `{integer}` + | ------- ^ expected an `FnOnce<()>` closure, found `{integer}` + | | + | required by a bound introduced by this call | = help: the trait `FnOnce<()>` is not implemented for `{integer}` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -18,8 +18,6 @@ ... LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^ requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` error[E0308]: mismatched types --> $DIR/expect-fn-supply-fn.rs:32:49 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected fn pointer `fn(&u32)` found fn pointer `fn(&'x u32)` -note: the anonymous lifetime #1 defined on the body at 16:48... +note: the anonymous lifetime #1 defined here... --> $DIR/expect-fn-supply-fn.rs:16:48 | LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 13:36 +note: ...does not necessarily outlive the lifetime `'x` as defined here --> $DIR/expect-fn-supply-fn.rs:13:36 | LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) { @@ -25,12 +25,12 @@ | = note: expected fn pointer `fn(&u32)` found fn pointer `fn(&'x u32)` -note: the lifetime `'x` as defined on the function body at 13:36... +note: the lifetime `'x` as defined here... --> $DIR/expect-fn-supply-fn.rs:13:36 | LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) { | ^^ -note: ...does not necessarily outlive the anonymous lifetime #1 defined on the body at 16:48 +note: ...does not necessarily outlive the anonymous lifetime #1 defined here --> $DIR/expect-fn-supply-fn.rs:16:48 | LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ // edition:2021 + + // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. -#![feature(box_syntax)] - #[derive(Debug)] struct Point { x: i32, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,6 +3,7 @@ // check-pass #![allow(unreachable_code)] #![warn(unused)] +#![allow(dead_code)] #[derive(Debug)] struct Point { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ warning: value captured by `a` is never read - --> $DIR/liveness.rs:23:9 + --> $DIR/liveness.rs:24:9 | LL | a = 1; | ^ @@ -13,7 +13,7 @@ = help: did you mean to capture by reference instead? warning: unused variable: `a` - --> $DIR/liveness.rs:32:9 + --> $DIR/liveness.rs:33:9 | LL | a += 1; | ^ @@ -27,7 +27,7 @@ = help: did you mean to capture by reference instead? warning: value assigned to `a` is never read - --> $DIR/liveness.rs:52:9 + --> $DIR/liveness.rs:53:9 | LL | a += 1; | ^ @@ -35,7 +35,7 @@ = help: maybe it is overwritten before being read? warning: value assigned to `a` is never read - --> $DIR/liveness.rs:76:13 + --> $DIR/liveness.rs:77:13 | LL | a = Some("d1"); | ^ @@ -43,7 +43,7 @@ = help: maybe it is overwritten before being read? warning: value assigned to `b` is never read - --> $DIR/liveness.rs:84:13 + --> $DIR/liveness.rs:85:13 | LL | b = Some("e1"); | ^ @@ -51,7 +51,7 @@ = help: maybe it is overwritten before being read? warning: value assigned to `b` is never read - --> $DIR/liveness.rs:86:13 + --> $DIR/liveness.rs:87:13 | LL | b = Some("e2"); | ^ @@ -59,7 +59,7 @@ = help: maybe it is overwritten before being read? warning: unused variable: `b` - --> $DIR/liveness.rs:84:13 + --> $DIR/liveness.rs:85:13 | LL | b = Some("e1"); | ^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,7 @@ // check-pass #![warn(unused)] +#![allow(dead_code)] #[derive(Debug)] struct MyStruct { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ warning: value assigned to `a` is never read - --> $DIR/liveness_unintentional_copy.rs:19:9 + --> $DIR/liveness_unintentional_copy.rs:20:9 | LL | a = s; | ^ @@ -13,7 +13,7 @@ = help: maybe it is overwritten before being read? warning: unused variable: `a` - --> $DIR/liveness_unintentional_copy.rs:19:9 + --> $DIR/liveness_unintentional_copy.rs:20:9 | LL | a = s; | ^ @@ -27,7 +27,7 @@ = help: did you mean to capture by reference instead? warning: unused variable: `a` - --> $DIR/liveness_unintentional_copy.rs:35:9 + --> $DIR/liveness_unintentional_copy.rs:36:9 | LL | a += x; | ^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,35 @@ +// run-rustfix + +#![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE lint level is defined here + +fn main() { + struct Foo(u32); + impl Drop for Foo { + fn drop(&mut self) { + println!("dropped {}", self.0); + } + } + + let f0 = Foo(0); + let f1 = Foo(1); + + let c0 = move || { + let _ = &f0; + //~^ ERROR changes to closure capture in Rust 2021 will affect drop order + //~| NOTE for more information + let _ = f0; + //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect + }; + + let c1 = move || { + let _ = &f1; + }; + + println!("dropping 0"); + drop(c0); + println!("dropping 1"); + drop(c1); + println!("dropped all"); +} +//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,34 @@ +// run-rustfix + +#![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE lint level is defined here + +fn main() { + struct Foo(u32); + impl Drop for Foo { + fn drop(&mut self) { + println!("dropped {}", self.0); + } + } + + let f0 = Foo(0); + let f1 = Foo(1); + + let c0 = move || { + //~^ ERROR changes to closure capture in Rust 2021 will affect drop order + //~| NOTE for more information + let _ = f0; + //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect + }; + + let c1 = move || { + let _ = &f1; + }; + + println!("dropping 0"); + drop(c0); + println!("dropping 1"); + drop(c1); + println!("dropped all"); +} +//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/issue-90465.rs:17:14 + | +LL | let c0 = move || { + | ^^^^^^^ +... +LL | let _ = f0; + | -- in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect +... +LL | } + | - in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure + | +note: the lint level is defined here + --> $DIR/issue-90465.rs:3:9 + | +LL | #![deny(rust_2021_incompatible_closure_captures)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see +help: add a dummy let to cause `f0` to be fully captured + | +LL ~ let c0 = move || { +LL + let _ = &f0; + | + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -20,8 +20,8 @@ let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -40,8 +40,9 @@ let f = CustomInt(&mut f as *mut i32); let fptr = SyncPointer(f); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -65,8 +66,8 @@ let f = U(S(Foo(0)), T(0)); let c = || { let _ = &f; - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + //~| NOTE: in Rust 2018, this closure implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs 2021-11-29 19:27:11.000000000 +0000 @@ -20,8 +20,8 @@ let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || unsafe { - //~^ ERROR: `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -40,8 +40,9 @@ let f = CustomInt(&mut f as *mut i32); let fptr = SyncPointer(f); thread::spawn(move || unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -64,8 +65,8 @@ fn test_clone_trait() { let f = U(S(Foo(0)), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + //~| NOTE: in Rust 2018, this closure implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/auto_traits.rs:22:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send` ... LL | *fptr.0 = 20; | ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0` @@ -23,11 +23,14 @@ LL | *fptr.0 = 20; ... -error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/auto_traits.rs:42:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + | ^^^^^^^^^^^^^^ + | | + | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync` + | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send` ... LL | *fptr.0.0 = 20; | --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0` @@ -40,14 +43,14 @@ LL | LL | LL | -LL | *fptr.0.0 = 20; +LL | ... -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/auto_traits.rs:66:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/auto_traits.rs:67:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f` is not fully captured and `f.1` does not implement `Clone` ... LL | let f_1 = f.1; | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ | | --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0` LL | | println!("{:?}", x); LL | | }); - | |_______- in this macro invocation + | |______- in this macro invocation | note: the lint level is defined here --> $DIR/closure-body-macro-fragment.rs:4:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,37 @@ +// Test that rustc doesn't ICE as in #90024. +// check-pass +// edition=2018 + +#![warn(rust_2021_incompatible_closure_captures)] + +// Checks there's no double-subst into the generic args, otherwise we get OOB +// MCVE by @lqd +pub struct Graph { + _edges: E, + _nodes: N, + _ix: Vec, +} +fn graph() -> Graph { + todo!() +} +fn first_ice() { + let g = graph::(); + let _ = || g; +} + +// Checks that there is a subst into the fields, otherwise we get normalization error +// MCVE by @cuviper +use std::iter::Empty; +struct Foo { + data: Vec, +} +pub fn second_ice() { + let v = Foo::> { data: vec![] }; + + (|| v.data[0])(); +} + +pub fn main() { + first_ice(); + second_ice(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -19,8 +19,9 @@ let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { let _ = &f; - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,8 +18,9 @@ { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,11 @@ -error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/mir_calls_to_shims.rs:20:38 | LL | let result = panic::catch_unwind(move || { - | ^^^^^^^ in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + | ^^^^^^^ + | | + | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe` + | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` because `f` is not fully captured and `f.0` does not implement `RefUnwindSafe` ... LL | f.0() | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,6 @@ } } - struct S(Foo); #[derive(Clone)] @@ -37,8 +36,8 @@ let f2 = U(S(Foo::from("bar")), T(0)); let c = || { let _ = (&f1, &f2); - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured let _f_1 = f1.0; @@ -57,8 +56,8 @@ let f1 = U(S(Foo::from("foo")), T(0)); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_1 = f1.0; @@ -83,9 +82,9 @@ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -103,8 +102,8 @@ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -136,9 +135,10 @@ let mut f2 = 10; let fptr2 = SendPointer(&mut f2 as *mut i32); thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured *fptr1.0.0 = 20; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,6 @@ } } - struct S(Foo); #[derive(Clone)] @@ -36,8 +35,8 @@ let f1 = U(S(Foo::from("foo")), T(0)); let f2 = U(S(Foo::from("bar")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured let _f_1 = f1.0; @@ -55,8 +54,8 @@ fn test_capturing_all_disjoint_fields_individually() { let f1 = U(S(Foo::from("foo")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_1 = f1.0; @@ -80,9 +79,9 @@ fn test_capturing_several_disjoint_fields_individually_1() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { - //~^ ERROR: `Clone` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -99,8 +98,8 @@ fn test_capturing_several_disjoint_fields_individually_2() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -132,9 +131,10 @@ let mut f2 = 10; let fptr2 = SendPointer(&mut f2 as *mut i32); thread::spawn(move || unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured *fptr1.0.0 = 20; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:38:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/multi_diagnostics.rs:37:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_1 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -25,11 +25,11 @@ LL + let _ = (&f1, &f2); | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:57:13 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:56:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_1 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -41,14 +41,14 @@ LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:82:13 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:81:13 | LL | let c = || { | ^^ | | - | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` + | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.2` does not implement `Clone` ... LL | let _f_0 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -63,11 +63,11 @@ LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:101:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/multi_diagnostics.rs:100:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_0 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -88,14 +88,15 @@ LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/multi_diagnostics.rs:134:19 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:133:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ | | - | in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` - | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync` + | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send` + | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr2` is not fully captured and `fptr2.0` does not implement `Send` ... LL | *fptr1.0.0 = 20; | ---------- in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ // edition:2021 //check-pass #![warn(unused)] +#![allow(dead_code)] #![feature(rustc_attrs)] #[derive(Debug, Clone, Copy)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,6 +3,8 @@ // Test that we can use raw ptrs when using `capture_disjoint_fields`. +#![allow(dead_code)] + #[derive(Debug)] struct S { s: String, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/closure-bounds-subtype.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/closure-bounds-subtype.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/closure-bounds-subtype.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/closure-bounds-subtype.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/closure-bounds-subtype.rs:13:22 | LL | take_const_owned(f); - | ^ `F` cannot be shared between threads safely + | ---------------- ^ `F` cannot be shared between threads safely + | | + | required by a bound introduced by this call | note: required by a bound in `take_const_owned` --> $DIR/closure-bounds-subtype.rs:4:50 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,8 +17,6 @@ ... LL | closure_expecting_bound(|x: &'x u32| { | ^ requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected reference `&u32` found reference `&'x u32` -note: the anonymous lifetime #1 defined on the body at 14:29... +note: the anonymous lifetime #1 defined here... --> $DIR/expect-region-supply-region-2.rs:14:29 | LL | closure_expecting_bound(|x: &'x u32| { @@ -18,7 +18,7 @@ LL | | f = Some(x); LL | | }); | |_____^ -note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 9:30 +note: ...does not necessarily outlive the lifetime `'x` as defined here --> $DIR/expect-region-supply-region-2.rs:9:30 | LL | fn expect_bound_supply_named<'x>() { @@ -32,12 +32,12 @@ | = note: expected reference `&u32` found reference `&'x u32` -note: the lifetime `'x` as defined on the function body at 9:30... +note: the lifetime `'x` as defined here... --> $DIR/expect-region-supply-region-2.rs:9:30 | LL | fn expect_bound_supply_named<'x>() { | ^^ -note: ...does not necessarily outlive the anonymous lifetime #1 defined on the body at 14:29 +note: ...does not necessarily outlive the anonymous lifetime #1 defined here --> $DIR/expect-region-supply-region-2.rs:14:29 | LL | closure_expecting_bound(|x: &'x u32| { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/coerce-unsafe-to-closure.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/coerce-unsafe-to-closure.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/coerce-unsafe-to-closure.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/coerce-unsafe-to-closure.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/coerce-unsafe-to-closure.rs:2:44 | LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); - | ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` + | --- ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` + | | + | required by a bound introduced by this call | = help: the trait `FnOnce<(&str,)>` is not implemented for `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/issue-78720.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/issue-78720.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/issue-78720.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/issue-78720.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +fn server() -> impl { +//~^ ERROR at least one trait must be specified + ().map2(|| "") +} + +trait FilterBase2 { + fn map2(self, f: F) -> Map2 {} + //~^ ERROR mismatched types + //~^^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +struct Map2 { + _func: F, + //~^ ERROR cannot find type `F` in this scope +} + +impl FilterBase2 for F {} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/issue-78720.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/issue-78720.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/issue-78720.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/issue-78720.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,55 @@ +error: at least one trait must be specified + --> $DIR/issue-78720.rs:1:16 + | +LL | fn server() -> impl { + | ^^^^ + +error[E0412]: cannot find type `F` in this scope + --> $DIR/issue-78720.rs:13:12 + | +LL | _func: F, + | ^ + | + ::: $SRC_DIR/core/src/ops/function.rs:LL:COL + | +LL | pub trait Fn: FnMut { + | ------------------------------- similarly named trait `Fn` defined here + | +help: a trait with a similar name exists + | +LL | _func: Fn, + | ~~ +help: you might be missing a type parameter + | +LL | struct Map2 { + | +++ + +error[E0308]: mismatched types + --> $DIR/issue-78720.rs:7:39 + | +LL | fn map2(self, f: F) -> Map2 {} + | ^^ expected struct `Map2`, found `()` + | + = note: expected struct `Map2` + found unit type `()` + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/issue-78720.rs:7:16 + | +LL | fn map2(self, f: F) -> Map2 {} + | ^^^^ doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider further restricting `Self` + | +LL | fn map2(self, f: F) -> Map2 where Self: Sized {} + | +++++++++++++++++ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn map2(&self, f: F) -> Map2 {} + | + + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0308, E0412. +For more information about an error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/issue-87814-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/issue-87814-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/closures/issue-87814-2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/closures/issue-87814-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // check-pass -#![feature(try_reserve)] fn main() { let mut schema_all: (Vec, Vec) = (vec![], vec![]); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers. +error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers --> $DIR/wrong-abi-location-1.rs:8:1 | LL | pub extern "C-cmse-nonsecure-call" fn test() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers. +error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers --> $DIR/wrong-abi-location-2.rs:8:1 | LL | / extern "C-cmse-nonsecure-call" { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/codemap_tests/bad-format-args.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/codemap_tests/bad-format-args.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/codemap_tests/bad-format-args.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/codemap_tests/bad-format-args.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/bad-format-args.rs:2:5 | LL | format!(); - | ^^^^^^^^^^ + | ^^^^^^^^^ | = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/codemap_tests/issue-11715.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/codemap_tests/issue-11715.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/codemap_tests/issue-11715.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/codemap_tests/issue-11715.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^^^^^^ second mutable borrow occurs here LL | z.use_mut(); LL | y.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/codemap_tests/issue-28308.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/codemap_tests/issue-28308.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/codemap_tests/issue-28308.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/codemap_tests/issue-28308.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-28308.rs:2:5 | LL | assert!("foo"); - | ^^^^^^^^^^^^^^^ cannot apply unary operator `!` + | ^^^^^^^^^^^^^^ cannot apply unary operator `!` | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/codemap_tests/one_line.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/codemap_tests/one_line.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/codemap_tests/one_line.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/codemap_tests/one_line.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,9 @@ --> $DIR/one_line.rs:3:12 | LL | v.push(v.pop().unwrap()); - | - ---- ^ second mutable borrow occurs here - | | | + | -------^^^^^^^---------- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/coercion/coerce-expect-unsized.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/coercion/coerce-expect-unsized.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/coercion/coerce-expect-unsized.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/coercion/coerce-expect-unsized.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(unused_braces)] -#![feature(box_syntax)] use std::cell::RefCell; use std::fmt::Debug; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `(): std::error::Error` is not satisfied + --> $DIR/coerce-issue-49593-box-never.rs:17:53 + | +LL | /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` + | + = note: required for the cast to the object type `dyn std::error::Error` + +error[E0277]: the trait bound `(): std::error::Error` is not satisfied + --> $DIR/coerce-issue-49593-box-never.rs:22:49 + | +LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` + | + = note: required for the cast to the object type `(dyn std::error::Error + 'static)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/coercion/coerce-issue-49593-box-never.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/coercion/coerce-issue-49593-box-never.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/coercion/coerce-issue-49593-box-never.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/coercion/coerce-issue-49593-box-never.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,9 @@ -// check-pass -#![feature(never_type, never_type_fallback)] +// revisions: nofallback fallback +//[fallback] check-pass +//[nofallback] check-fail + +#![feature(never_type)] +#![cfg_attr(fallback, feature(never_type_fallback))] #![allow(unreachable_code)] use std::error::Error; @@ -11,10 +15,12 @@ fn foo(x: !) -> Box { /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) + //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn foo_raw_ptr(x: !) -> *mut dyn Error { /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) + //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn no_coercion(d: *mut dyn Error) -> *mut dyn Error { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/coercion/issue-88097.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/coercion/issue-88097.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/coercion/issue-88097.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/coercion/issue-88097.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,31 @@ +// In #88097, the compiler attempted to coerce a closure type to itself via +// a function pointer, which caused an unnecessary error. Check that this +// behavior has been fixed. + +// check-pass + +fn peculiar() -> impl Fn(u8) -> u8 { + return |x| x + 1 +} + +fn peculiar2() -> impl Fn(u8) -> u8 { + return |x| x + 1; +} + +fn peculiar3() -> impl Fn(u8) -> u8 { + let f = |x| x + 1; + return f +} + +fn peculiar4() -> impl Fn(u8) -> u8 { + let f = |x| x + 1; + f +} + +fn peculiar5() -> impl Fn(u8) -> u8 { + let f = |x| x + 1; + let g = |x| x + 2; + return if true { f } else { g } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | impl NotObjectSafe for dyn NotObjectSafe { } | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object | - = help: consider moving `eq` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:6:43 | @@ -12,6 +11,7 @@ | ------------- ^^^^ ...because method `eq` references the `Self` type in this parameter | | | this trait cannot be made into an object... + = help: consider moving `eq` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/coherence/coherence_inherent_cc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/coherence/coherence_inherent_cc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/coherence/coherence_inherent_cc.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/coherence/coherence_inherent_cc.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,10 @@ | ^^^^^^ method not found in `&TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope; perhaps add a `use` for it: - `use coherence_inherent_cc_lib::TheTrait;` +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use coherence_inherent_cc_lib::TheTrait; + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/coherence/coherence_inherent.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/coherence/coherence_inherent.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/coherence/coherence_inherent.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/coherence/coherence_inherent.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,10 @@ | ^^^^^^ method not found in `&TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope; perhaps add a `use` for it: - `use Lib::TheTrait;` +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use Lib::TheTrait; + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/coherence-unsafe-trait-object-impl.rs:15:13 | LL | takes_t(t); - | ^ the trait `Trait` is not implemented for `&dyn Trait` + | ------- ^ the trait `Trait` is not implemented for `&dyn Trait` + | | + | required by a bound introduced by this call | note: required by a bound in `takes_t` --> $DIR/coherence-unsafe-trait-object-impl.rs:10:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/command/command-pre-exec.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/command/command-pre-exec.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/command/command-pre-exec.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/command/command-pre-exec.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,6 +8,8 @@ // ignore-sgx no processes #![feature(process_exec, rustc_private)] +extern crate libc; + use std::env; use std::io::Error; use std::os::unix::process::CommandExt; @@ -15,23 +17,6 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -#[cfg(not(target_os = "linux"))] -fn getpid() -> u32 { - use std::process; - process::id() -} - -/// We need to directly use the getpid syscall instead of using `process::id()` -/// because the libc wrapper might return incorrect values after a process was -/// forked. -#[cfg(target_os = "linux")] -fn getpid() -> u32 { - extern crate libc; - unsafe { - libc::syscall(libc::SYS_getpid) as _ - } -} - fn main() { if let Some(arg) = env::args().nth(1) { match &arg[..] { @@ -83,12 +68,14 @@ }; assert_eq!(output.raw_os_error(), Some(102)); - let pid = getpid(); + let pid = unsafe { libc::getpid() }; + assert!(pid >= 0); let output = unsafe { Command::new(&me) .arg("empty") .pre_exec(move || { - let child = getpid(); + let child = libc::getpid(); + assert!(child >= 0); assert!(pid != child); Ok(()) }) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/compile_error_macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/compile_error_macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/compile_error_macro.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/compile_error_macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/compile_error_macro.rs:2:5 | LL | compile_error!("a very descriptive error message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -59,7 +59,7 @@ | ^^^^^ ... LL | generate_s10!(concat!("nonexistent")); - | -------------------------------------- in this macro invocation + | ------------------------------------- in this macro invocation | = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -70,7 +70,7 @@ | ^^^^^ ... LL | generate_s10!(concat!("nonexistent")); - | -------------------------------------- in this macro invocation + | ------------------------------------- in this macro invocation | = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^ ... LL | foo!(); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/broken-mir-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/broken-mir-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/broken-mir-2.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/broken-mir-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ // run-pass + +#![allow(dead_code)] + use std::fmt::Debug; #[derive(Debug)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/expose-default-substs-param-env.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/expose-default-substs-param-env.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/expose-default-substs-param-env.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/expose-default-substs-param-env.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +// build-pass + +#![feature(generic_const_exprs)] +#![allow(unused_braces, incomplete_features)] + +pub trait Foo {} +pub trait Bar: Foo<{ 1 }> { } + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +fn foo(a: [(); N as usize]) { + bar::<{ N as usize as usize }>(); + //~^ error: unconstrained generic constant +} + +fn bar() {} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/abstract-consts-as-cast-5.rs:5:11 + | +LL | bar::<{ N as usize as usize }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N as usize as usize }]:` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,9 +10,10 @@ --> $DIR/array-size-in-generic-struct-param.rs:19:15 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^ unsupported projection + | ^^^^^^^^^^^^ field access is not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/closures.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/closures.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/closures.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/closures.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,9 +4,10 @@ LL | fn test() -> [u8; N + (|| 42)()] {} | ^^^^-------^^ | | - | unsupported rvalue + | dereferencing is not supported in generic constants | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +// run-pass +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Foo { + type Assoc: Default; +} + +impl Foo<0> for () { + type Assoc = u32; +} + +impl Foo<3> for () { + type Assoc = i64; +} + +fn foo(_: T) -> <() as Foo<{ N + 1 }>>::Assoc +where + (): Foo<{ N + 1 }>, +{ + Default::default() +} + +fn main() { + // Test that we can correctly infer `T` which requires evaluating + // `{ N + 1 }` which has substs containing an inference var + let mut _q = Default::default(); + _q = foo::<_, 2>(_q); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,21 +2,19 @@ --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` cannot be made into an object | - = help: consider moving `test` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-err-ret.rs:8:23 | @@ -12,6 +11,7 @@ | --- this trait cannot be made into an object... LL | fn test(&self) -> [u8; bar::()]; | ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type + = help: consider moving `test` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,35 @@ +#![feature(generic_const_exprs, adt_const_params, const_trait_impl)] +#![allow(incomplete_features)] + +// test `N + N` unifies with explicit function calls for non-builtin-types +#[derive(PartialEq, Eq)] +struct Foo(u8); + +impl const std::ops::Add for Foo { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + self + } +} + +struct Evaluatable; + +fn foo(a: Evaluatable<{ N + N }>) { + bar::<{ std::ops::Add::add(N, N) }>(); +} + +fn bar() {} + +// test that `N + N` unifies with explicit function calls for builin-types +struct Evaluatable2; + +fn foo2(a: Evaluatable2<{ N + N }>) { + bar2::<{ std::ops::Add::add(N, N) }>(); + //~^ error: unconstrained generic constant + // FIXME(generic_const_exprs) make this not an error +} + +fn bar2() {} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/unify-op-with-fn-call.rs:28:12 + | +LL | bar2::<{ std::ops::Add::add(N, N) }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { std::ops::Add::add(N, N) }]:` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,31 +2,28 @@ --> $DIR/unused_expr.rs:4:34 | LL | fn add() -> [u8; { N + 1; 5 }] { - | ^^-----^^^^^ - | | - | dead code + | ^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/unused_expr.rs:9:34 | LL | fn div() -> [u8; { N / 1; 5 }] { - | ^^-----^^^^^ - | | - | dead code + | ^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/unused_expr.rs:16:38 | LL | fn fn_call() -> [u8; { foo(N); 5 }] { - | ^^------^^^^^ - | | - | dead code + | ^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-67375.full.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-67375.full.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-67375.full.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-67375.full.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,9 @@ --> $DIR/issue-67375.rs:7:17 | LL | inner: [(); { [|_: &T| {}; 0].len() }], - | ^^^----------^^^^^^^^^^^^ - | | - | unsupported rvalue + | ^^---------------------^^ + | | + | pointer casts are not allowed in generic constants | = help: consider moving this anonymous constant into a `const` function diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-67945-2.full.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-67945-2.full.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-67945-2.full.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-67945-2.full.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,13 +5,13 @@ | _____________^ LL | | LL | | let x: Option> = None; - | | ---- unsupported rvalue LL | | LL | | 0 LL | | }], - | |_____^ + | |_____^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-82956.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-82956.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-82956.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-82956.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +#![feature(generic_const_exprs, array_map)] +#![allow(incomplete_features)] + +pub struct ConstCheck; + +pub trait True {} +impl True for ConstCheck {} + +pub trait OrdesDec { + type Newlen; + type Output; + + fn pop(self) -> (Self::Newlen, Self::Output); +} + +impl OrdesDec for [T; N] +where + ConstCheck<{N > 1}>: True, + [T; N - 1]: Sized, +{ + type Newlen = [T; N - 1]; + type Output = T; + + fn pop(self) -> (Self::Newlen, Self::Output) { + let mut iter = IntoIter::new(self); + //~^ ERROR: failed to resolve: use of undeclared type `IntoIter` + let end = iter.next_back().unwrap(); + let new = [(); N - 1].map(move |()| iter.next().unwrap()); + (new, end) + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-82956.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-82956.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-82956.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-82956.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0433]: failed to resolve: use of undeclared type `IntoIter` + --> $DIR/issue-82956.rs:25:24 + | +LL | let mut iter = IntoIter::new(self); + | ^^^^^^^^ not found in this scope + | +help: consider importing one of these items + | +LL | use std::array::IntoIter; + | +LL | use std::collections::binary_heap::IntoIter; + | +LL | use std::collections::btree_map::IntoIter; + | +LL | use std::collections::btree_set::IntoIter; + | + and 8 other candidates + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-84659.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-84659.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-84659.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-84659.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +trait Bar {} + +trait Foo<'a> { + const N: usize; + type Baz: Bar<{ Self::N }>; + //~^ ERROR: unconstrained generic constant +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-84659.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-84659.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-84659.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-84659.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/issue-84659.rs:8:15 + | +LL | type Baz: Bar<{ Self::N }>; + | ^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { Self::N }]:` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86530.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86530.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86530.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86530.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +pub trait X { + const Y: usize; +} + +fn z(t: T) +where + T: X, + [(); T::Y]: , +{ +} + +fn unit_literals() { + z(" "); + //~^ ERROR: the trait bound `&str: X` is not satisfied +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86530.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86530.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86530.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86530.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `&str: X` is not satisfied + --> $DIR/issue-86530.rs:16:7 + | +LL | z(" "); + | - ^^^ the trait `X` is not implemented for `&str` + | | + | required by a bound introduced by this call + | +note: required by a bound in `z` + --> $DIR/issue-86530.rs:10:8 + | +LL | fn z(t: T) + | - required by a bound in this +LL | where +LL | T: X, + | ^ required by this bound in `z` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86535-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86535-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86535-2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86535-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +// run-pass +#![feature(adt_const_params, generic_const_exprs)] +#![allow(incomplete_features)] + +pub trait Foo { + const ASSOC_C: usize; + fn foo() where [(); Self::ASSOC_C]:; +} + +struct Bar; +impl Foo for Bar { + const ASSOC_C: usize = 3; + + fn foo() where [u8; Self::ASSOC_C]: { + let _: [u8; Self::ASSOC_C] = loop {}; + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86535.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86535.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86535.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-86535.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +// run-pass +#![feature(adt_const_params, generic_const_exprs)] +#![allow(incomplete_features, unused_variables)] + +struct F; +impl X for F<{ S }> { + const W: usize = 3; + + fn d(r: &[u8; Self::W]) -> F<{ S }> { + let x: [u8; Self::W] = [0; Self::W]; + F + } +} + +pub trait X { + const W: usize; + fn d(r: &[u8; Self::W]) -> Self; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-87493.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-87493.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-87493.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-87493.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +pub trait MyTrait { + type Assoc; +} + +pub fn foo(_s: S, _t: T) +where + S: MyTrait, + T: MyTrait, + //~^ ERROR: expected one of `,` or `>`, found `==` + //~| ERROR: this trait takes 0 generic arguments but 1 generic argument was supplied +{ +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-87493.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-87493.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-87493.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-87493.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,28 @@ +error: expected one of `,` or `>`, found `==` + --> $DIR/issue-87493.rs:8:22 + | +LL | T: MyTrait, + | ^^ expected one of `,` or `>` + | +help: if you meant to use an associated type binding, replace `==` with `=` + | +LL | T: MyTrait, + | ~ + +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/issue-87493.rs:8:8 + | +LL | T: MyTrait, + | ^^^^^^^------------------- help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/issue-87493.rs:1:11 + | +LL | pub trait MyTrait { + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-89334.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-89334.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-89334.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/issues/issue-89334.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// build-pass + +#![feature(generic_const_exprs)] +#![allow(unused_braces, incomplete_features)] + +pub trait AnotherTrait{ + const ARRAY_SIZE: usize; +} +pub trait Shard: + AsMut<[[u8; T::ARRAY_SIZE]]> +where + [(); T::ARRAY_SIZE]: Sized +{ +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo for Bar { +//~^ERROR expected lifetime, type, or constant, found keyword `const` + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error: expected lifetime, type, or constant, found keyword `const` + --> $DIR/issue-89013-no-assoc.rs:9:10 + | +LL | impl Foo for Bar { + | ^^^^^ + | +help: the `const` keyword is only needed in the definition of the type + | +LL - impl Foo for Bar { +LL + impl Foo<3> for Bar { + | + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo for Bar { +//~^ ERROR cannot constrain an associated constant to a value +//~| ERROR associated type bindings are not allowed here + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +error: cannot constrain an associated constant to a value + --> $DIR/issue-89013-no-kw.rs:9:10 + | +LL | impl Foo for Bar { + | -^^^- + | | | + | | ...cannot be constrained to this value + | this associated constant... + +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-89013-no-kw.rs:9:10 + | +LL | impl Foo for Bar { + | ^^^^^ associated type not allowed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0229`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo for Bar { +//~^ ERROR expected lifetime, type, or constant, found keyword `const` +//~| ERROR cannot constrain an associated constant to a value +//~| ERROR associated type bindings are not allowed here + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +error: expected lifetime, type, or constant, found keyword `const` + --> $DIR/issue-89013.rs:9:14 + | +LL | impl Foo for Bar { + | ^^^^^ + | +help: the `const` keyword is only needed in the definition of the type + | +LL - impl Foo for Bar { +LL + impl Foo for Bar { + | + +error: cannot constrain an associated constant to a value + --> $DIR/issue-89013.rs:9:10 + | +LL | impl Foo for Bar { + | -^^^^^^^^^- + | | | + | | ...cannot be constrained to this value + | this associated constant... + +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-89013.rs:9:10 + | +LL | impl Foo for Bar { + | ^^^^^^^^^^^ associated type not allowed here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0229`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo for Bar { +//~^ERROR missing type to the right of `=` + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: missing type to the right of `=` + --> $DIR/issue-89013-type.rs:9:13 + | +LL | impl Foo for Bar { + | ^---- expected type, found keyword `type` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/sneaky-array-repeat-expr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/sneaky-array-repeat-expr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/sneaky-array-repeat-expr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/sneaky-array-repeat-expr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,32 @@ +trait Trait { + const Assoc: usize; +} + +impl Trait for () { + const Assoc: usize = 1; +} + + +pub const fn foo() where (): Trait { + let bar = [(); <()>::Assoc]; + //~^ error: constant expression depends on a generic parameter +} + +trait Trait2 { + const Assoc2: usize; +} + +impl Trait2 for () { + const Assoc2: usize = N - 1; +} + + +pub const fn foo2() where (): Trait2 { + let bar2 = [(); <()>::Assoc2]; + //~^ error: constant expression depends on a generic parameter +} + +fn main() { + foo::<0>(); + foo2::<0>(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/sneaky-array-repeat-expr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/sneaky-array-repeat-expr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/sneaky-array-repeat-expr.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/sneaky-array-repeat-expr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +error: constant expression depends on a generic parameter + --> $DIR/sneaky-array-repeat-expr.rs:11:20 + | +LL | let bar = [(); <()>::Assoc]; + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/sneaky-array-repeat-expr.rs:25:21 + | +LL | let bar2 = [(); <()>::Assoc2]; + | ^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `u16` to `u8` | LL | assert_eq!(R.method::<1u8>(), 1); - | ~~~ + | ~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `u16` to `u8` | LL | assert_eq!(R.method::<1u8>(), 1); - | ~~~ + | ~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/unused_braces.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/unused_braces.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/const-generics/unused_braces.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/const-generics/unused_braces.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,18 @@ --> $DIR/unused_braces.rs:9:14 | LL | let _: A<{ 7 }>; - | ^^^^^ help: remove these braces + | ^^ ^^ | note: the lint level is defined here --> $DIR/unused_braces.rs:3:9 | LL | #![warn(unused_braces)] | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - let _: A<{ 7 }>; +LL + let _: A<7>; + | warning: 1 warning emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_2021.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_2021.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_2021.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_2021.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // edition:2021 -#![feature(const_panic)] #![crate_type = "lib"] +const MSG: &str = "hello"; + const A: () = std::panic!("blåhaj"); //~^ ERROR evaluation of constant value failed @@ -14,14 +15,20 @@ const D: () = std::unimplemented!(); //~^ ERROR evaluation of constant value failed -const E: () = core::panic!("shark"); +const E: () = std::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed + +const A_CORE: () = core::panic!("shark"); +//~^ ERROR evaluation of constant value failed + +const B_CORE: () = core::panic!(); //~^ ERROR evaluation of constant value failed -const F: () = core::panic!(); +const C_CORE: () = core::unreachable!(); //~^ ERROR evaluation of constant value failed -const G: () = core::unreachable!(); +const D_CORE: () = core::unimplemented!(); //~^ ERROR evaluation of constant value failed -const H: () = core::unimplemented!(); +const E_CORE: () = core::panic!("{}", MSG); //~^ ERROR evaluation of constant value failed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_2021.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_2021.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_2021.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_2021.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,67 +1,83 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:5:15 + --> $DIR/const_panic_2021.rs:6:15 | LL | const A: () = std::panic!("blåhaj"); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:5:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:6:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:8:15 + --> $DIR/const_panic_2021.rs:9:15 | LL | const B: () = std::panic!(); - | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:8:15 + | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:9:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:11:15 + --> $DIR/const_panic_2021.rs:12:15 | LL | const C: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:11:15 + | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:12:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:14:15 + --> $DIR/const_panic_2021.rs:15:15 | LL | const D: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:14:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:15:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:17:15 + --> $DIR/const_panic_2021.rs:18:15 | -LL | const E: () = core::panic!("shark"); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:17:15 +LL | const E: () = std::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:18:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:20:15 + --> $DIR/const_panic_2021.rs:21:20 | -LL | const F: () = core::panic!(); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:20:15 +LL | const A_CORE: () = core::panic!("shark"); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:21:20 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:23:15 + --> $DIR/const_panic_2021.rs:24:20 | -LL | const G: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:23:15 +LL | const B_CORE: () = core::panic!(); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:24:20 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:27:20 + | +LL | const C_CORE: () = core::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:27:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:26:15 + --> $DIR/const_panic_2021.rs:30:20 | -LL | const H: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:26:15 +LL | const D_CORE: () = core::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:30:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 8 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:33:20 + | +LL | const E_CORE: () = core::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:33:20 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0080`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ #![crate_type = "bin"] #![feature(lang_items)] -#![feature(const_panic)] #![no_main] #![no_std] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,24 +1,24 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_libcore_bin.rs:9:15 + --> $DIR/const_panic_libcore_bin.rs:8:15 | LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:9:15 + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:8:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_libcore_bin.rs:12:15 + --> $DIR/const_panic_libcore_bin.rs:11:15 | LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:12:15 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:11:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_libcore_bin.rs:15:15 + --> $DIR/const_panic_libcore_bin.rs:14:15 | LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:15:15 + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:14:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -#![feature(const_panic)] #![allow(non_fmt_panics)] #![crate_type = "lib"] @@ -15,10 +14,13 @@ const X: () = std::unimplemented!(); //~^ ERROR evaluation of constant value failed -// + const W: () = std::panic!(MSG); //~^ ERROR evaluation of constant value failed +const W2: () = std::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed + const Z_CORE: () = core::panic!("cheese"); //~^ ERROR evaluation of constant value failed @@ -33,3 +35,6 @@ const W_CORE: () = core::panic!(MSG); //~^ ERROR evaluation of constant value failed + +const W2_CORE: () = core::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,83 +1,99 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:7:15 + --> $DIR/const_panic.rs:6:15 | LL | const Z: () = std::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:6:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:10:16 + --> $DIR/const_panic.rs:9:16 | LL | const Z2: () = std::panic!(); - | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16 + | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:9:16 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:13:15 + --> $DIR/const_panic.rs:12:15 | LL | const Y: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:13:15 + | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:12:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:16:15 + --> $DIR/const_panic.rs:15:15 | LL | const X: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:16:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:15:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:19:15 + --> $DIR/const_panic.rs:18:15 | LL | const W: () = std::panic!(MSG); - | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:19:15 + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:18:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:22:20 + --> $DIR/const_panic.rs:21:16 + | +LL | const W2: () = std::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:21:16 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:24:20 | LL | const Z_CORE: () = core::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20 + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:24:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:25:21 + --> $DIR/const_panic.rs:27:21 | LL | const Z2_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:27:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:28:20 + --> $DIR/const_panic.rs:30:20 | LL | const Y_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20 + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:30:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:31:20 + --> $DIR/const_panic.rs:33:20 | LL | const X_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20 + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:33:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:34:20 + --> $DIR/const_panic.rs:36:20 | LL | const W_CORE: () = core::panic!(MSG); - | ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20 + | ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:36:20 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:39:21 + | +LL | const W2_CORE: () = core::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:39:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0080`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_track_caller.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_track_caller.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_track_caller.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_track_caller.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -#![feature(const_panic)] #![allow(non_fmt_panics)] #![crate_type = "lib"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_track_caller.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_track_caller.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_track_caller.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_panic_track_caller.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,14 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_track_caller.rs:16:5 + --> $DIR/const_panic_track_caller.rs:15:5 | LL | b() | ^^^ | | - | the evaluated program panicked at 'hey', $DIR/const_panic_track_caller.rs:16:5 - | inside `c` at $DIR/const_panic_track_caller.rs:16:5 + | the evaluated program panicked at 'hey', $DIR/const_panic_track_caller.rs:15:5 + | inside `c` at $DIR/const_panic_track_caller.rs:15:5 ... LL | const X: u32 = c(); - | --- inside `X` at $DIR/const_panic_track_caller.rs:22:16 + | --- inside `X` at $DIR/const_panic_track_caller.rs:21:16 error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/const_raw_ptr_ops.rs:4:26 | LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; @@ -6,7 +6,7 @@ | = note: see issue #53020 for more information -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/const_raw_ptr_ops.rs:6:27 | LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/feature-gate-const_panic.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/feature-gate-const_panic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/feature-gate-const_panic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/feature-gate-const_panic.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -fn main() {} - -const Z: () = panic!("cheese"); -//~^ ERROR panicking in constants is unstable - -const Y: () = unreachable!(); -//~^ ERROR panicking in constants is unstable - -const X: () = unimplemented!(); -//~^ ERROR panicking in constants is unstable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -error[E0658]: panicking in constants is unstable - --> $DIR/feature-gate-const_panic.rs:3:15 - | -LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: panicking in constants is unstable - --> $DIR/feature-gate-const_panic.rs:6:15 - | -LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: panicking in constants is unstable - --> $DIR/feature-gate-const_panic.rs:9:15 - | -LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/match-test-ptr-null.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/match-test-ptr-null.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/match-test-ptr-null.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/match-test-ptr-null.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/match-test-ptr-null.rs:6:15 | LL | match &1 as *const i32 as usize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-assoc-never-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-assoc-never-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-assoc-never-type.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-assoc-never-type.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,6 @@ // Regression test for #66975 #![warn(const_err)] -#![feature(const_panic)] #![feature(never_type)] struct PrintName; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ error[E0080]: evaluation of constant value failed - --> $DIR/panic-assoc-never-type.rs:11:21 + --> $DIR/panic-assoc-never-type.rs:10:21 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:11:21 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:10:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-never-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-never-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-never-type.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-never-type.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // Regression test for #66975 #![warn(const_err)] -#![feature(const_panic)] #![feature(never_type)] const VOID: ! = panic!(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-never-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-never-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-never-type.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/panic-never-type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ error[E0080]: evaluation of constant value failed - --> $DIR/panic-never-type.rs:6:17 + --> $DIR/panic-never-type.rs:5:17 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:6:17 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:5:17 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/unwind-abort.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/unwind-abort.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-eval/unwind-abort.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-eval/unwind-abort.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -#![feature(c_unwind, const_panic, const_extern_fn)] +#![feature(c_unwind, const_extern_fn)] const extern "C" fn foo() { panic!() //~ ERROR evaluation of constant value failed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-external-macro-const-err.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-external-macro-const-err.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-external-macro-const-err.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-external-macro-const-err.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/const-external-macro-const-err.rs:12:5 | LL | static_assert!(2 + 2 == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -25,7 +25,7 @@ = note: see issue #57241 for more information = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/const-extern-fn-min-const-fn.rs:9:48 | LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-float-bits-conv.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-float-bits-conv.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-float-bits-conv.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-float-bits-conv.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ // compile-flags: -Zmir-opt-level=0 // run-pass -#![feature(const_panic)] #![feature(const_float_bits_conv)] #![feature(const_float_classify)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-float-classify.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-float-classify.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-float-classify.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-float-classify.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ // compile-flags: -Zmir-opt-level=0 // run-pass -#![feature(const_panic)] #![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_trait_impl)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_fn_trait_bound.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_fn_trait_bound.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_fn_trait_bound.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_fn_trait_bound.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,9 +8,9 @@ const fn test1() {} //[stock]~^ trait bounds const fn test2(_x: &dyn Send) {} -//[stock]~^ trait bounds +//[stock]~^ trait objects in const fn are unstable const fn test3() -> &'static dyn Send { loop {} } -//[stock]~^ trait bounds +//[stock]~^ trait objects in const fn are unstable #[rustc_error] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_fn_trait_bound.stock.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_fn_trait_bound.stock.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_fn_trait_bound.stock.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_fn_trait_bound.stock.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/const_fn_trait_bound.rs:10:16 | LL | const fn test2(_x: &dyn Send) {} @@ -16,7 +16,7 @@ = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/const_fn_trait_bound.rs:12:21 | LL | const fn test3() -> &'static dyn Send { loop {} } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_in_pattern/issue-73431.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_in_pattern/issue-73431.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_in_pattern/issue-73431.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_in_pattern/issue-73431.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +WARN rustc_mir_build::thir::pattern::const_to_pat MIR const-checker found novel structural match violation. See #73448. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_in_pattern/issue-78057.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_in_pattern/issue-78057.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_in_pattern/issue-78057.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_in_pattern/issue-78057.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,11 @@ error: unreachable pattern --> $DIR/issue-78057.rs:14:9 | +LL | FOO => {}, + | --- matches any value +LL | LL | _ => {} - | ^ + | ^ unreachable pattern | note: the lint level is defined here --> $DIR/issue-78057.rs:1:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_let_assign3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_let_assign3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_let_assign3.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_let_assign3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ --> $DIR/const_let_assign3.rs:14:5 | LL | s.foo(3); - | ^ + | ^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ // run-pass -#![feature(const_unreachable_unchecked)] - const unsafe fn foo(x: bool) -> bool { match x { true => true, @@ -12,5 +10,5 @@ const BAR: bool = unsafe { foo(true) }; fn main() { - assert_eq!(BAR, true); + assert_eq!(BAR, true); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable_ub.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable_ub.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable_ub.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable_ub.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // error-pattern: evaluation of constant value failed -#![feature(const_unreachable_unchecked)] const unsafe fn foo(x: bool) -> bool { match x { @@ -11,5 +10,5 @@ const BAR: bool = unsafe { foo(false) }; fn main() { - assert_eq!(BAR, true); + assert_eq!(BAR, true); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable_ub.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable_ub.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable_ub.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const_unsafe_unreachable_ub.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,13 +7,13 @@ | entering unreachable code | inside `unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL | - ::: $DIR/const_unsafe_unreachable_ub.rs:7:18 + ::: $DIR/const_unsafe_unreachable_ub.rs:6:18 | LL | false => std::hint::unreachable_unchecked(), - | ---------------------------------- inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:7:18 + | ---------------------------------- inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:6:18 ... LL | const BAR: bool = unsafe { foo(false) }; - | ---------- inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:11:28 + | ---------- inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:10:28 error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-variant-count.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-variant-count.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/const-variant-count.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/const-variant-count.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // run-pass -#![allow(dead_code)] +#![allow(dead_code, enum_intrinsics_non_enums)] #![feature(variant_count)] #![feature(never_type)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.const_panic.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.const_panic.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.const_panic.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.const_panic.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/assert.rs:10:15 - | -LL | const _: () = assert!(false); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15 - | - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0080`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,8 @@ -// Test that `assert` works when `const_panic` is enabled. - -// revisions: stock const_panic - -#![cfg_attr(const_panic, feature(const_panic))] +// Test that `assert` works in consts. const _: () = assert!(true); -//[stock]~^ ERROR panicking in constants is unstable const _: () = assert!(false); -//[stock]~^ ERROR panicking in constants is unstable -//[const_panic]~^^ ERROR evaluation of constant value failed +//~^ ERROR evaluation of constant value failed fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/assert.rs:5:15 + | +LL | const _: () = assert!(false); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:5:15 + | + = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.stock.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.stock.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.stock.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/assert.stock.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -error[E0658]: panicking in constants is unstable - --> $DIR/assert.rs:7:15 - | -LL | const _: () = assert!(true); - | ^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: panicking in constants is unstable - --> $DIR/assert.rs:10:15 - | -LL | const _: () = assert!(false); - | ^^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/basics.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/basics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/basics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/basics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,6 @@ // run-pass -#![feature(const_panic)] - const X: u32 = 4; const Y: u32 = 5; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/short-circuit-let.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/short-circuit-let.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/short-circuit-let.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/short-circuit-let.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,6 @@ // run-pass -#![feature(const_panic)] - const X: i32 = { let mut x = 0; let _ = true && { x = 1; false }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/short-circuit.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/short-circuit.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/control-flow/short-circuit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/control-flow/short-circuit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ // Test that both `&&` and `||` actually short-circuit. // Formerly, both sides were evaluated unconditionally -#![feature(const_panic)] - const TRUE: bool = true || panic!(); const FALSE: bool = false && panic!(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-17458.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-17458.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-17458.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-17458.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/issue-17458.rs:1:28 | LL | static X: usize = unsafe { core::ptr::null::() as usize }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-23833.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-23833.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-23833.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-23833.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +// run-pass +#![allow(unused_imports)] +use std::fmt; + +const A_I8_T + : [u32; (i8::MAX as i8 - 1i8) as usize] + = [0; (i8::MAX as usize) - 1]; + +fn main() { + foo(&A_I8_T[..]); +} + +fn foo(x: T) { + println!("{:?}", x); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-25826.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-25826.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-25826.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-25826.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-32829.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-32829.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-32829.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-32829.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ static S : u64 = { { panic!("foo"); 0 } }; -//~^ ERROR panicking in statics is unstable +//~^ ERROR could not evaluate static initializer fn main() { println!("{:?}", S); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-32829.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-32829.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-32829.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-32829.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,11 @@ -error[E0658]: panicking in statics is unstable +error[E0080]: could not evaluate static initializer --> $DIR/issue-32829.rs:1:22 | LL | static S : u64 = { { panic!("foo"); 0 } }; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ the evaluated program panicked at 'foo', $DIR/issue-32829.rs:1:22 | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0080`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-34784.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-34784.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-34784.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-34784.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +// run-pass + +#![warn(pointer_structural_match)] +#![allow(dead_code)] +const C: *const u8 = &0; + +fn foo(x: *const u8) { + match x { + C => {} + _ => {} + } +} + +const D: *const [u8; 4] = b"abcd"; + +fn main() { + match D { + D => {} + _ => {} + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/issue-52023-array-size-pointer-cast.rs:2:17 | LL | let _ = [0; (&0 as *const i32) as usize]; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-66693-panic-in-array-len.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-66693-panic-in-array-len.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-66693-panic-in-array-len.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-66693-panic-in-array-len.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,6 @@ // in a separate stage before `const`s and `statics` and so the error below is hit and // the compiler exits before generating errors for the others. -#![feature(const_panic)] - fn main() { let _ = [0i32; panic!(2f32)]; //~^ ERROR: argument to `panic!()` in a const context must have type `&str` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-66693-panic-in-array-len.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-66693-panic-in-array-len.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-66693-panic-in-array-len.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-66693-panic-in-array-len.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error: argument to `panic!()` in a const context must have type `&str` - --> $DIR/issue-66693-panic-in-array-len.rs:8:20 + --> $DIR/issue-66693-panic-in-array-len.rs:6:20 | LL | let _ = [0i32; panic!(2f32)]; | ^^^^^^^^^^^^ @@ -7,10 +7,10 @@ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/issue-66693-panic-in-array-len.rs:12:21 + --> $DIR/issue-66693-panic-in-array-len.rs:10:21 | LL | let _ = [false; panic!()]; - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693-panic-in-array-len.rs:12:21 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693-panic-in-array-len.rs:10:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-66693.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-66693.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-66693.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-66693.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,6 @@ // Tests that the compiler does not ICE when const-evaluating a `panic!()` invocation with a // non-`&str` argument. -#![feature(const_panic)] - const _: () = panic!(1); //~^ ERROR: argument to `panic!()` in a const context must have type `&str` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-66693.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-66693.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-66693.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-66693.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error: argument to `panic!()` in a const context must have type `&str` - --> $DIR/issue-66693.rs:6:15 + --> $DIR/issue-66693.rs:4:15 | LL | const _: () = panic!(1); | ^^^^^^^^^ @@ -7,7 +7,7 @@ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: argument to `panic!()` in a const context must have type `&str` - --> $DIR/issue-66693.rs:9:19 + --> $DIR/issue-66693.rs:7:19 | LL | static _FOO: () = panic!(true); | ^^^^^^^^^^^^ @@ -15,10 +15,10 @@ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: argument to `panic!()` in a const context must have type `&str` - --> $DIR/issue-66693.rs:13:5 + --> $DIR/issue-66693.rs:11:5 | LL | panic!(&1); - | ^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-76064.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-76064.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-76064.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-76064.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -// Note: non-`&str` panic arguments gained a separate error in PR #80734 -// which is why this doesn't match the issue -struct Bug([u8; panic!("panic")]); //~ ERROR panicking in constants is unstable +struct Bug([u8; panic!("panic")]); //~ ERROR evaluation of constant value failed fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-76064.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-76064.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-76064.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-76064.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,11 @@ -error[E0658]: panicking in constants is unstable - --> $DIR/issue-76064.rs:3:17 +error[E0080]: evaluation of constant value failed + --> $DIR/issue-76064.rs:1:17 | LL | struct Bug([u8; panic!("panic")]); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ the evaluated program panicked at 'panic', $DIR/issue-76064.rs:1:17 | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0080`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-88071.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-88071.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-88071.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-88071.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +// check-pass +// +// regression test for #88071 + +#![feature(const_btree_new)] +#![feature(const_fn_trait_bound)] + +use std::collections::BTreeMap; + +pub struct CustomMap(BTreeMap); + +impl CustomMap +where + K: Ord, +{ + pub const fn new() -> Self { + CustomMap(BTreeMap::new()) + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-89088.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-89088.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/issue-89088.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/issue-89088.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +// Regression test for the ICE described in #89088. + +// check-pass + +#![allow(indirect_structural_match)] +use std::borrow::Cow; + +const FOO: &A = &A::Field(Cow::Borrowed("foo")); + +#[derive(PartialEq, Eq)] +enum A { + Field(Cow<'static, str>) +} + +fn main() { + let var = A::Field(Cow::Borrowed("bar")); + + match &var { + FOO => todo!(), + _ => todo!() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,7 @@ = note: see issue #57563 for more information = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/cmp_fn_pointers.rs:4:14 | LL | unsafe { x == y } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,9 +7,9 @@ const fn no_inner_dyn_trait(_x: Hide) {} const fn no_inner_dyn_trait2(x: Hide) { x.0.field; -//~^ ERROR trait bounds other than `Sized` +//~^ ERROR trait objects in const fn are unstable } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } -//~^ ERROR trait bounds other than `Sized` +//~^ ERROR trait objects in const fn are unstable fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,17 +1,21 @@ -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/min_const_fn_dyn.rs:9:5 | +LL | const fn no_inner_dyn_trait2(x: Hide) { + | ------------------------------------- function declared as const here LL | x.0.field; | ^^^^^^^^^ | = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/min_const_fn_dyn.rs:12:66 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } - | ^^ + | ----------------------------------------- ^^ + | | + | function declared as const here | = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: `foo2` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:24:26 @@ -12,7 +12,7 @@ LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_fn_libstd_stability.rs:29:26 @@ -35,7 +35,7 @@ LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -130,16 +130,16 @@ //~^ ERROR trait bounds other than `Sized` //~| ERROR destructor const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} -//~^ ERROR trait bounds other than `Sized` +//~^ ERROR trait objects in const fn are unstable const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } -//~^ ERROR trait bounds other than `Sized` +//~^ ERROR trait objects in const fn are unstable const fn no_unsafe() { unsafe {} } const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } -//~^ ERROR trait bounds other than `Sized` -//~| ERROR trait bounds other than `Sized` -//~| ERROR trait bounds other than `Sized` +//~^ ERROR trait objects in const fn are unstable +//~| ERROR trait objects in const fn are unstable +//~| ERROR trait objects in const fn are unstable const fn no_fn_ptrs(_x: fn()) {} //~^ ERROR function pointer diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -164,7 +164,7 @@ | = help: consider extracting the value of the `static` to a `const`, and referring to that -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:92:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } @@ -173,7 +173,7 @@ = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:94:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } @@ -182,7 +182,7 @@ = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:96:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } @@ -191,7 +191,7 @@ = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:98:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } @@ -214,6 +214,9 @@ | LL | impl Foo { | ^ +LL | +LL | const fn foo(&self) {} + | ------------------- function declared as const here | = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable @@ -223,6 +226,9 @@ | LL | impl Foo { | ^ +LL | +LL | const fn foo2(&self) {} + | -------------------- function declared as const here | = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable @@ -232,6 +238,9 @@ | LL | impl Foo { | ^ +LL | +LL | const fn foo3(&self) {} + | -------------------- function declared as const here | = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable @@ -270,7 +279,7 @@ | | | constant functions cannot evaluate destructors -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/min_const_fn.rs:132:23 | LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} @@ -279,7 +288,7 @@ = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/min_const_fn.rs:134:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } @@ -288,29 +297,35 @@ = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/min_const_fn.rs:139:41 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | function declared as const here | = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/min_const_fn.rs:139:42 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | function declared as const here | = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0658]: trait objects in const fn are unstable --> $DIR/min_const_fn.rs:139:42 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | function declared as const here | = note: see issue #57563 for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 @@ -12,7 +12,7 @@ LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: `foo2_gated` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 @@ -20,7 +20,7 @@ LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 @@ -12,7 +12,7 @@ LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 @@ -35,7 +35,7 @@ LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/box.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/box.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/box.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/box.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,5 +9,5 @@ static TEST_BAD: &mut i32 = { &mut *(box 0) //~^ ERROR could not evaluate static initializer - //~| NOTE heap allocations + //~| NOTE calling non-const function `alloc::alloc::exchange_malloc` }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/box.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/box.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/box.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/box.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/box.rs:10:11 | LL | &mut *(box 0) - | ^^^^^^^ "heap allocations via `box` keyword" needs an rfc before being allowed inside constants + | ^^^^^^^ calling non-const function `alloc::alloc::exchange_malloc` warning: skipping const checks | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -161,17 +161,11 @@ | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_panic` feature - --> $DIR/const_refers_to_static_cross_crate.rs:32:77 - | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^ help: skipping check that does not even have a feature gate --> $DIR/const_refers_to_static_cross_crate.rs:32:20 | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors; 3 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -161,17 +161,11 @@ | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_panic` feature - --> $DIR/const_refers_to_static_cross_crate.rs:32:77 - | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^ help: skipping check that does not even have a feature gate --> $DIR/const_refers_to_static_cross_crate.rs:32:20 | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors; 3 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/inline_asm.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/inline_asm.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/inline_asm.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/miri_unleashed/inline_asm.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/inline_asm.rs:11:14 | LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inline assembly is not supported + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inline assembly is not supported | = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -10,7 +10,7 @@ --> $DIR/inline_asm.rs:20:14 | LL | unsafe { asm!("nop"); } - | ^^^^^^^^^^^^ inline assembly is not supported + | ^^^^^^^^^^^ inline assembly is not supported warning: skipping const checks | @@ -18,12 +18,12 @@ --> $DIR/inline_asm.rs:11:14 | LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate --> $DIR/inline_asm.rs:20:14 | LL | unsafe { asm!("nop"); } - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ = note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors; 1 warning emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/not_const_clusure_in_const.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/not_const_clusure_in_const.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/not_const_clusure_in_const.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/not_const_clusure_in_const.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +// run-pass + +const _FOO: fn() -> String = || "foo".into(); + +pub fn bar() -> fn() -> String { + || "bar".into() +} + +fn main(){} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/ptr_comparisons.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/ptr_comparisons.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/ptr_comparisons.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/ptr_comparisons.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,6 @@ // normalize-stderr-64bit: "size 8" -> "size $$WORD" #![feature( - const_panic, core_intrinsics, const_raw_ptr_comparison, const_ptr_offset, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/ptr_comparisons.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/ptr_comparisons.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/ptr_comparisons.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/ptr_comparisons.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,19 +7,19 @@ | pointer arithmetic failed: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/ptr_comparisons.rs:61:34 + ::: $DIR/ptr_comparisons.rs:60:34 | LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) }; - | ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:61:34 + | ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:60:34 error[E0080]: evaluation of constant value failed - --> $DIR/ptr_comparisons.rs:64:33 + --> $DIR/ptr_comparisons.rs:63:33 | LL | unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc3 has size $WORD, so pointer to 1000 bytes starting at offset 0 is out-of-bounds error: any use of this value will cause an error - --> $DIR/ptr_comparisons.rs:68:27 + --> $DIR/ptr_comparisons.rs:67:27 | LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 }; | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -31,7 +31,7 @@ = note: for more information, see issue #71800 error: any use of this value will cause an error - --> $DIR/ptr_comparisons.rs:73:27 + --> $DIR/ptr_comparisons.rs:72:27 | LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 }; | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/ptr_is_null.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/ptr_is_null.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/ptr_is_null.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/ptr_is_null.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // compile-flags: --crate-type=lib // check-pass -#![feature(const_ptr_is_null, const_panic)] +#![feature(const_ptr_is_null)] const FOO: &usize = &42; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_eq-issue-88384.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_eq-issue-88384.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_eq-issue-88384.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_eq-issue-88384.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,25 @@ +// check-pass + +#![feature(fn_traits)] +#![feature(adt_const_params)] +//~^ WARNING the feature `adt_const_params` is incomplete + +#[derive(PartialEq, Eq)] +struct CompileTimeSettings{ + hooks: &'static[fn()], +} + +struct Foo; + +impl Foo { + fn call_hooks(){ + } +} + +fn main(){ + const SETTINGS: CompileTimeSettings = CompileTimeSettings{ + hooks: &[], + }; + + Foo::::call_hooks(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/refs_check_const_eq-issue-88384.rs:4:12 + | +LL | #![feature(adt_const_params)] + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +warning: 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_value_eq-issue-88876.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_value_eq-issue-88876.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_value_eq-issue-88876.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/refs_check_const_value_eq-issue-88876.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// check-pass + +#![allow(incomplete_features)] +#![feature(adt_const_params)] + +struct FooConst {} + +const FOO_ARR: &[&'static str; 2] = &["Hello", "Friend"]; + +fn main() { + let _ = FooConst:: {}; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/unwind-abort.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/unwind-abort.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/consts/unwind-abort.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/consts/unwind-abort.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // check-pass -#![feature(c_unwind, const_panic, const_extern_fn)] +#![feature(c_unwind, const_extern_fn)] // We don't unwind in const-eval anyways. const extern "C" fn foo() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +// compile-flags:-C extra-filename=-1 --emit=metadata +#![crate_name = "crateresolve2"] +#![crate_type = "lib"] + +pub fn f() -> isize { 10 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +// compile-flags:-C extra-filename=-2 --emit=metadata +#![crate_name = "crateresolve2"] +#![crate_type = "lib"] + +pub fn f() -> isize { 20 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +// compile-flags:-C extra-filename=-3 --emit=metadata +#![crate_name = "crateresolve2"] +#![crate_type = "lib"] + +pub fn f() -> isize { 30 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve1.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,15 @@ -// dont-check-compiler-stderr // aux-build:crateresolve1-1.rs // aux-build:crateresolve1-2.rs // aux-build:crateresolve1-3.rs -// error-pattern:multiple matching crates for `crateresolve1` + +// normalize-stderr-test: "\.nll/" -> "/" +// normalize-stderr-test: "\\\?\\" -> "" +// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib" + +// NOTE: This test is duplicated at `src/test/ui/error-codes/E0464.rs`. extern crate crateresolve1; +//~^ ERROR multiple matching crates for `crateresolve1` fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve1.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0464]: multiple matching crates for `crateresolve1` + --> $DIR/crateresolve1.rs:11:1 + | +LL | extern crate crateresolve1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: candidates: + crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-1.somelib + crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-2.somelib + crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-3.somelib + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0464`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// check-fail + +// aux-build:crateresolve2-1.rs +// aux-build:crateresolve2-2.rs +// aux-build:crateresolve2-3.rs + +// normalize-stderr-test: "\.nll/" -> "/" +// normalize-stderr-test: "\\\?\\" -> "" + +extern crate crateresolve2; +//~^ ERROR multiple matching crates for `crateresolve2` + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve2.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-loading/crateresolve2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0464]: multiple matching crates for `crateresolve2` + --> $DIR/crateresolve2.rs:10:1 + | +LL | extern crate crateresolve2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: candidates: + crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-1.rmeta + crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-2.rmeta + crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-3.rmeta + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0464`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-method-reexport-grrrrrrr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-method-reexport-grrrrrrr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/crate-method-reexport-grrrrrrr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/crate-method-reexport-grrrrrrr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - // This is a regression test that the metadata for the // name_pool::methods impl in the other crate is reachable from this // crate. @@ -14,7 +12,7 @@ pub fn main() { use crate_method_reexport_grrrrrrr2::rust::add; use crate_method_reexport_grrrrrrr2::rust::cx; - let x: Box<_> = box (); + let x: Box<_> = Box::new(()); x.cx(); let y = (); y.add("hi".to_string()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cross/cross-borrow-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/cross/cross-borrow-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cross/cross-borrow-trait.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cross/cross-borrow-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,8 @@ --> $DIR/cross-borrow-trait.rs:10:26 | LL | let _y: &dyn Trait = x; - | ---------- ^ - | | | - | | expected `&dyn Trait`, found struct `Box` - | | help: consider borrowing here: `&x` + | ---------- ^ expected `&dyn Trait`, found struct `Box` + | | | expected due to this | = note: expected reference `&dyn Trait` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cross/cross-crate-macro-backtrace/main.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/cross/cross-crate-macro-backtrace/main.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cross/cross-crate-macro-backtrace/main.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cross/cross-crate-macro-backtrace/main.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/main.rs:6:5 | LL | myprintln!("{}"); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cross/cross-file-errors/main.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/cross/cross-file-errors/main.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cross/cross-file-errors/main.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cross/cross-file-errors/main.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ ::: $DIR/main.rs:5:5 | LL | underscore!(); - | -------------- in this macro invocation + | ------------- in this macro invocation | = note: see issue #71126 for more information = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable @@ -22,7 +22,7 @@ ::: $DIR/main.rs:5:5 | LL | underscore!(); - | -------------- in this macro invocation + | ------------- in this macro invocation | = note: this error originates in the macro `underscore` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - use std::cell::RefCell; pub struct Entry { @@ -37,7 +35,7 @@ fn eq_int(a: isize, b: isize) -> bool { a == b } return alist { eq_fn: eq_int, - data: box RefCell::new(Vec::new()), + data: Box::new(RefCell::new(Vec::new())), }; } @@ -47,6 +45,6 @@ fn eq_int(a: isize, b: isize) -> bool { a == b } return alist { eq_fn: eq_int, - data: box RefCell::new(Vec::new()), + data: Box::new(RefCell::new(Vec::new())), }; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/cross-crate/cci_borrow.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/cross-crate/cci_borrow.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/cross-crate/cci_borrow.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/cross-crate/cci_borrow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,11 @@ // run-pass // aux-build:cci_borrow_lib.rs -#![feature(box_syntax)] - extern crate cci_borrow_lib; use cci_borrow_lib::foo; pub fn main() { - let p: Box<_> = box 22; + let p: Box<_> = Box::new(22); let r = foo(&*p); println!("r={}", r); assert_eq!(r, 22); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/c-variadic/issue-86053-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/c-variadic/issue-86053-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/c-variadic/issue-86053-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/c-variadic/issue-86053-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -84,12 +84,12 @@ LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 10:16 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/issue-86053-1.rs:10:16 | LL | fn ordering4 < 'a , 'b > ( a : , self , self , self , | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 10:21 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/issue-86053-1.rs:10:21 | LL | fn ordering4 < 'a , 'b > ( a : , self , self , self , diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/c-variadic/issue-86053-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/c-variadic/issue-86053-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/c-variadic/issue-86053-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/c-variadic/issue-86053-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^ | = note: the pointer is valid for the static lifetime -note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 8:32 +note: but the referenced data is only valid for the lifetime `'a` as defined here --> $DIR/issue-86053-2.rs:8:32 | LL | unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // Test that when a trait impl changes, fns whose body uses that trait // must also be recompiled. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-assoc-type-codegen +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(warnings)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error: OK - --> $DIR/dep-graph-assoc-type-codegen.rs:28:5 + --> $DIR/dep-graph-assoc-type-codegen.rs:29:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-caller-callee.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-caller-callee.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-caller-callee.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-caller-callee.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // Test that immediate callers have to change when callee changes, but // not callers' callers. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-caller-callee +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-caller-callee.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-caller-callee.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-caller-callee.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-caller-callee.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ error: OK - --> $DIR/dep-graph-caller-callee.rs:20:5 + --> $DIR/dep-graph-caller-callee.rs:21:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `x` to `typeck` - --> $DIR/dep-graph-caller-callee.rs:31:5 + --> $DIR/dep-graph-caller-callee.rs:32:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-struct-signature.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-struct-signature.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-struct-signature.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-struct-signature.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // Test cases where a changing struct appears in the signature of fns // and methods. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-struct-signature +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-struct-signature.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-struct-signature.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-struct-signature.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-struct-signature.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,131 +1,131 @@ error: no path from `WillChange` to `type_of` - --> $DIR/dep-graph-struct-signature.rs:27:5 + --> $DIR/dep-graph-struct-signature.rs:28:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `associated_item` - --> $DIR/dep-graph-struct-signature.rs:28:5 + --> $DIR/dep-graph-struct-signature.rs:29:5 | LL | #[rustc_then_this_would_need(associated_item)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `trait_def` - --> $DIR/dep-graph-struct-signature.rs:29:5 + --> $DIR/dep-graph-struct-signature.rs:30:5 | LL | #[rustc_then_this_would_need(trait_def)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:31:9 + --> $DIR/dep-graph-struct-signature.rs:32:9 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:35:5 + --> $DIR/dep-graph-struct-signature.rs:36:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:36:5 + --> $DIR/dep-graph-struct-signature.rs:37:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:39:5 + --> $DIR/dep-graph-struct-signature.rs:40:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:40:5 + --> $DIR/dep-graph-struct-signature.rs:41:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:45:5 + --> $DIR/dep-graph-struct-signature.rs:46:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:47:9 + --> $DIR/dep-graph-struct-signature.rs:48:9 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:48:9 + --> $DIR/dep-graph-struct-signature.rs:49:9 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:52:5 + --> $DIR/dep-graph-struct-signature.rs:53:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:54:9 + --> $DIR/dep-graph-struct-signature.rs:55:9 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:55:9 + --> $DIR/dep-graph-struct-signature.rs:56:9 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:60:9 + --> $DIR/dep-graph-struct-signature.rs:61:9 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:62:9 + --> $DIR/dep-graph-struct-signature.rs:63:9 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `type_of` - --> $DIR/dep-graph-struct-signature.rs:67:5 + --> $DIR/dep-graph-struct-signature.rs:68:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `type_of` - --> $DIR/dep-graph-struct-signature.rs:74:5 + --> $DIR/dep-graph-struct-signature.rs:75:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `fn_sig` - --> $DIR/dep-graph-struct-signature.rs:76:9 + --> $DIR/dep-graph-struct-signature.rs:77:9 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `fn_sig` - --> $DIR/dep-graph-struct-signature.rs:80:5 + --> $DIR/dep-graph-struct-signature.rs:81:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `fn_sig` - --> $DIR/dep-graph-struct-signature.rs:83:5 + --> $DIR/dep-graph-struct-signature.rs:84:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `typeck` - --> $DIR/dep-graph-struct-signature.rs:84:5 + --> $DIR/dep-graph-struct-signature.rs:85:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // Test that when a trait impl changes, fns whose body uses that trait // must also be recompiled. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(warnings)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,29 +1,29 @@ error: OK - --> $DIR/dep-graph-trait-impl.rs:27:5 + --> $DIR/dep-graph-trait-impl.rs:28:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-trait-impl.rs:32:5 + --> $DIR/dep-graph-trait-impl.rs:33:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-trait-impl.rs:37:5 + --> $DIR/dep-graph-trait-impl.rs:38:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-trait-impl.rs:42:5 + --> $DIR/dep-graph-trait-impl.rs:43:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `x::` to `typeck` - --> $DIR/dep-graph-trait-impl.rs:55:5 + --> $DIR/dep-graph-trait-impl.rs:56:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // Test that adding an impl to a trait `Foo` does not affect functions // that only use `Bar`, so long as they do not have methods in common. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(warnings)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // Test that adding an impl to a trait `Foo` DOES affect functions // that only use `Bar` if they have methods in common. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits-same-method +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ error: OK - --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:32:5 + --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:33:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `x::` to `typeck` - --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:41:5 + --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:42:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ error: no path from `x::` to `typeck` - --> $DIR/dep-graph-trait-impl-two-traits.rs:31:5 + --> $DIR/dep-graph-trait-impl-two-traits.rs:32:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `x::` to `typeck` - --> $DIR/dep-graph-trait-impl-two-traits.rs:40:5 + --> $DIR/dep-graph-trait-impl-two-traits.rs:41:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-type-alias.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-type-alias.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-type-alias.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-type-alias.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ // Test that changing what a `type` points to does not go unnoticed. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-type-alias +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-type-alias.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-type-alias.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-type-alias.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-type-alias.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,71 +1,71 @@ error: no path from `TypeAlias` to `type_of` - --> $DIR/dep-graph-type-alias.rs:17:1 + --> $DIR/dep-graph-type-alias.rs:18:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:19:5 + --> $DIR/dep-graph-type-alias.rs:20:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `TypeAlias` to `type_of` - --> $DIR/dep-graph-type-alias.rs:24:1 + --> $DIR/dep-graph-type-alias.rs:25:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:27:9 + --> $DIR/dep-graph-type-alias.rs:28:9 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `TypeAlias` to `type_of` - --> $DIR/dep-graph-type-alias.rs:33:1 + --> $DIR/dep-graph-type-alias.rs:34:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:35:5 + --> $DIR/dep-graph-type-alias.rs:36:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `TypeAlias` to `type_of` - --> $DIR/dep-graph-type-alias.rs:41:1 + --> $DIR/dep-graph-type-alias.rs:42:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:43:5 + --> $DIR/dep-graph-type-alias.rs:44:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:44:5 + --> $DIR/dep-graph-type-alias.rs:45:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:48:1 + --> $DIR/dep-graph-type-alias.rs:49:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:51:1 + --> $DIR/dep-graph-type-alias.rs:52:1 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:52:1 + --> $DIR/dep-graph-type-alias.rs:53:1 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-variance-alias.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-variance-alias.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-variance-alias.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-variance-alias.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,8 @@ // Test that changing what a `type` points to does not go unnoticed // by the variance analysis. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-variance-alias +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-variance-alias.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-variance-alias.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-variance-alias.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dep-graph/dep-graph-variance-alias.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error: OK - --> $DIR/dep-graph-variance-alias.rs:18:1 + --> $DIR/dep-graph-variance-alias.rs:19:1 | LL | #[rustc_then_this_would_need(variances_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deprecation/deprecation-lint-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/deprecation/deprecation-lint-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deprecation/deprecation-lint-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deprecation/deprecation-lint-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/deprecation-lint-2.rs:12:5 | LL | macro_test!(); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/deprecation-lint-2.rs:4:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deref.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/deref.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deref.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deref.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,7 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let x: Box = box 10; + let x: Box = Box::new(10); let _y: isize = *x; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/clone-debug-dead-code.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/clone-debug-dead-code.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/clone-debug-dead-code.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/clone-debug-dead-code.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,45 @@ +// Checks that derived implementations of Clone and Debug do not +// contribute to dead code analysis (issue #84647). + +#![forbid(dead_code)] + +struct A { f: () } +//~^ ERROR: field is never read: `f` + +#[derive(Clone)] +struct B { f: () } +//~^ ERROR: field is never read: `f` + +#[derive(Debug)] +struct C { f: () } +//~^ ERROR: field is never read: `f` + +#[derive(Debug,Clone)] +struct D { f: () } +//~^ ERROR: field is never read: `f` + +struct E { f: () } +//~^ ERROR: field is never read: `f` +// Custom impl, still doesn't read f +impl Clone for E { + fn clone(&self) -> Self { + Self { f: () } + } +} + +struct F { f: () } +// Custom impl that actually reads f +impl Clone for F { + fn clone(&self) -> Self { + Self { f: self.f } + } +} + +fn main() { + let _ = A { f: () }; + let _ = B { f: () }; + let _ = C { f: () }; + let _ = D { f: () }; + let _ = E { f: () }; + let _ = F { f: () }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/clone-debug-dead-code.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/clone-debug-dead-code.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/clone-debug-dead-code.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/clone-debug-dead-code.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,38 @@ +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:6:12 + | +LL | struct A { f: () } + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/clone-debug-dead-code.rs:4:11 + | +LL | #![forbid(dead_code)] + | ^^^^^^^^^ + +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:10:12 + | +LL | struct B { f: () } + | ^^^^^ + +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:14:12 + | +LL | struct C { f: () } + | ^^^^^ + +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:18:12 + | +LL | struct D { f: () } + | ^^^^^ + +error: field is never read: `f` + --> $DIR/clone-debug-dead-code.rs:21:12 + | +LL | struct E { f: () } + | ^^^^^ + +error: aborting due to 5 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derive-assoc-type-not-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derive-assoc-type-not-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derive-assoc-type-not-impl.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derive-assoc-type-not-impl.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -19,6 +19,10 @@ = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` +help: consider annotating `NotClone` with `#[derive(Clone)]` + | +LL | #[derive(Clone)] + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-enum.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-enum.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-enum.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-enum.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,16 @@ LL | Error | ^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-enum.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-enum.rs:9:6 @@ -19,8 +27,16 @@ LL | Error | ^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-enum.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,16 @@ LL | x: Error | ^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:9:6 @@ -19,8 +27,16 @@ LL | x: Error | ^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-struct.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-struct.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,16 @@ LL | x: Error | ^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-struct.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-struct.rs:8:5 @@ -19,8 +27,16 @@ LL | x: Error | ^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-struct.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,16 @@ LL | Error | ^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-tuple-struct.rs:8:5 @@ -19,8 +27,16 @@ LL | Error | ^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/deriving-copyclone.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/deriving-copyclone.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/deriving-copyclone.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/deriving-copyclone.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,9 @@ --> $DIR/deriving-copyclone.rs:31:13 | LL | is_copy(B { a: 1, b: C }); - | ^^^^^^^^^^^^^^^^ - | | - | expected an implementor of trait `Copy` - | help: consider borrowing here: `&B { a: 1, b: C }` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy` + | | + | required by a bound introduced by this call | note: required because of the requirements on the impl of `Copy` for `B` --> $DIR/deriving-copyclone.rs:9:10 @@ -18,15 +17,18 @@ LL | fn is_copy(_: T) {} | ^^^^ required by this bound in `is_copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_copy(&B { a: 1, b: C }); + | + error[E0277]: the trait bound `C: Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:14 | LL | is_clone(B { a: 1, b: C }); - | ^^^^^^^^^^^^^^^^ - | | - | expected an implementor of trait `Clone` - | help: consider borrowing here: `&B { a: 1, b: C }` + | -------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone` + | | + | required by a bound introduced by this call | note: required because of the requirements on the impl of `Clone` for `B` --> $DIR/deriving-copyclone.rs:9:16 @@ -39,15 +41,18 @@ LL | fn is_clone(_: T) {} | ^^^^^ required by this bound in `is_clone` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_clone(&B { a: 1, b: C }); + | + error[E0277]: the trait bound `D: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:13 | LL | is_copy(B { a: 1, b: D }); - | ^^^^^^^^^^^^^^^^ - | | - | expected an implementor of trait `Copy` - | help: consider borrowing here: `&B { a: 1, b: D }` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy` + | | + | required by a bound introduced by this call | note: required because of the requirements on the impl of `Copy` for `B` --> $DIR/deriving-copyclone.rs:9:10 @@ -60,6 +65,10 @@ LL | fn is_copy(_: T) {} | ^^^^ required by this bound in `is_copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_copy(&B { a: 1, b: D }); + | + error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,16 @@ LL | x: NoCloneOrEq | ^^^^^^^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq` +note: an implementation of `PartialEq<_>` might be missing for `NoCloneOrEq` + --> $DIR/deriving-no-inner-impl-error-message.rs:1:1 + | +LL | struct NoCloneOrEq; + | ^^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `NoCloneOrEq` --> $DIR/deriving-no-inner-impl-error-message.rs:5:5 @@ -19,8 +27,16 @@ LL | x: NoCloneOrEq | ^^^^^^^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq` +note: an implementation of `PartialEq<_>` might be missing for `NoCloneOrEq` + --> $DIR/deriving-no-inner-impl-error-message.rs:1:1 + | +LL | struct NoCloneOrEq; + | ^^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0277]: the trait bound `NoCloneOrEq: Clone` is not satisfied --> $DIR/deriving-no-inner-impl-error-message.rs:10:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-generic-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-generic-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-generic-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-generic-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dead_code)] + #[derive(Clone)] struct S { foo: (), diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dead_code)] + #[derive(Clone)] struct S { _int: isize, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-tuple-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-tuple-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-tuple-struct.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-clone-tuple-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dead_code)] + #[derive(Clone)] struct S((), ()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-default-box.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-default-box.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-default-box.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-default-box.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,4 @@ // run-pass -#![feature(box_syntax)] - use std::default::Default; #[derive(Default)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-in-fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-in-fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/deriving-in-fn.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/deriving-in-fn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ // run-pass + +#![allow(dead_code)] + pub fn main() { #[derive(Debug)] struct Foo { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/issue-3935.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/issue-3935.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/issue-3935.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/issue-3935.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +// run-pass + +#[derive(PartialEq)] +struct Bike { + name: String, +} + +pub fn main() { + let town_bike = Bike { name: "schwinn".to_string() }; + let my_bike = Bike { name: "surly".to_string() }; + + assert!(town_bike != my_bike); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/issue-89188-gat-hrtb.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/issue-89188-gat-hrtb.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/deriving/issue-89188-gat-hrtb.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/deriving/issue-89188-gat-hrtb.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +// check-pass + +#![feature(generic_associated_types)] + +trait CallWithShim: Sized { + type Shim<'s> + where + Self: 's; +} + +#[derive(Clone)] +struct ShimMethod(pub &'static dyn for<'s> Fn(&'s mut T::Shim<'s>)); + +trait CallWithShim2: Sized { + type Shim; +} + +struct S<'s>(&'s ()); + +#[derive(Clone)] +struct ShimMethod2(pub &'static dyn for<'s> Fn(&'s mut T::Shim>)); + +trait Trait<'s, 't, 'u> {} + +#[derive(Clone)] +struct ShimMethod3( + pub &'static dyn for<'s> Fn( + &'s mut T::Shim Fn(&'s mut T::Shim Trait<'s, 't, 'u>>)>, + ), +); + +trait Trait2 { + type As; +} + +#[derive(Clone)] +struct ShimMethod4(pub &'static dyn for<'s> Fn(&'s mut T::As)); + +pub fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/destructure-trait-ref.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/destructure-trait-ref.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/destructure-trait-ref.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/destructure-trait-ref.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,11 +2,11 @@ // reference work properly. #![feature(box_patterns)] -#![feature(box_syntax)] trait T { fn foo(&self) {} } impl T for isize {} + fn main() { // For an expression of the form: // @@ -25,7 +25,7 @@ // n == m let &x = &1isize as &dyn T; //~ ERROR type `&dyn T` cannot be dereferenced let &&x = &(&1isize as &dyn T); //~ ERROR type `&dyn T` cannot be dereferenced - let box x = box 1isize as Box; + let box x = Box::new(1isize) as Box; //~^ ERROR type `Box` cannot be dereferenced // n > m @@ -37,7 +37,7 @@ //~^ ERROR mismatched types //~| expected trait object `dyn T` //~| found reference `&_` - let box box x = box 1isize as Box; + let box box x = Box::new(1isize) as Box; //~^ ERROR mismatched types //~| expected trait object `dyn T` //~| found struct `Box<_>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/destructure-trait-ref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/destructure-trait-ref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/destructure-trait-ref.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/destructure-trait-ref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ error[E0033]: type `Box` cannot be dereferenced --> $DIR/destructure-trait-ref.rs:28:9 | -LL | let box x = box 1isize as Box; +LL | let box x = Box::new(1isize) as Box; | ^^^^^ type `Box` cannot be dereferenced error[E0308]: mismatched types @@ -43,8 +43,8 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:40:13 | -LL | let box box x = box 1isize as Box; - | ^^^^^ ------------------------ this expression has type `Box` +LL | let box box x = Box::new(1isize) as Box; + | ^^^^^ ------------------------------ this expression has type `Box` | | | expected trait object `dyn T`, found struct `Box` | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/destructuring-assignment/note-unsupported.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/destructuring-assignment/note-unsupported.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/destructuring-assignment/note-unsupported.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/destructuring-assignment/note-unsupported.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -99,7 +99,22 @@ | | | cannot use `+=` on type `S` | - = note: an implementation of `std::ops::AddAssign` might be missing for `S` +note: an implementation of `AddAssign<_>` might be missing for `S` + --> $DIR/note-unsupported.rs:1:1 + | +LL | struct S { x: u8, y: u8 } + | ^^^^^^^^ must implement `AddAssign<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait AddAssign { +LL | | /// Performs the `+=` operation. +LL | | /// +LL | | /// # Example +... | +LL | | fn add_assign(&mut self, rhs: Rhs); +LL | | } + | |_^ error[E0067]: invalid left-hand side of assignment --> $DIR/note-unsupported.rs:17:22 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/bad-assoc-expr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/bad-assoc-expr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/bad-assoc-expr.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/bad-assoc-expr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -53,7 +53,7 @@ | ^^^^^^^^^^ help: try: `<$ty>::clone` ... LL | expr!(u8); - | ---------- in this macro invocation + | --------- in this macro invocation | = note: this error originates in the macro `expr` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-34126.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-34126.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-34126.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-34126.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -19,8 +19,9 @@ --> $DIR/issue-34126.rs:6:18 | LL | self.run(&mut self); - | ---- --- ^^^^^^^^^ mutable borrow occurs here - | | | + | ---------^^^^^^^^^- + | | | | + | | | mutable borrow occurs here | | immutable borrow later used by call | immutable borrow occurs here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-35937.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-35937.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-35937.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-35937.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let f = Foo { v: Vec::new() }; | - help: consider changing this to be mutable: `mut f` LL | f.v.push("cat".to_string()); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable --> $DIR/issue-35937.rs:16:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | fn f(&self) { | ----- help: consider changing this to be a mutable reference: `&mut self` LL | self.s.push('x'); - | ^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ---------- help: consider changing this to be mutable: `&'a mut String` ... LL | self.s.push('x'); - | ^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-3.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ---------- help: consider changing this to be mutable: `&'a mut String` ... LL | self.s.push('x'); - | ^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-4.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-38147-4.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | fn f(x: usize, f: &Foo) { | ---- help: consider changing this to be a mutable reference: `&mut Foo<'_>` LL | f.s.push('x'); - | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-39802-show-5-trait-impls.rs:24:21 | LL | Foo::::bar(&1i8); - | ^^^^ the trait `Foo` is not implemented for `i8` + | --------------- ^^^^ the trait `Foo` is not implemented for `i8` + | | + | required by a bound introduced by this call | = help: the following implementations were found: > @@ -20,7 +22,9 @@ --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 | LL | Foo::::bar(&1u8); - | ^^^^ the trait `Foo` is not implemented for `u8` + | --------------- ^^^^ the trait `Foo` is not implemented for `u8` + | | + | required by a bound introduced by this call | = help: the following implementations were found: > @@ -37,7 +41,9 @@ --> $DIR/issue-39802-show-5-trait-impls.rs:26:21 | LL | Foo::::bar(&true); - | ^^^^^ the trait `Foo` is not implemented for `bool` + | --------------- ^^^^^ the trait `Foo` is not implemented for `bool` + | | + | required by a bound introduced by this call | = help: the following implementations were found: > diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-40823.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-40823.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-40823.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-40823.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let mut buf = &[1, 2, 3, 4]; | ------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4]` LL | buf.iter_mut(); - | ^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +fn main() {} + +const FOO: [u8; 3] = { //~ ERROR this code is interpreted as a block expression + 1, 2, 3 +}; + +const BAR: [&str; 3] = {"one", "two", "three"}; +//~^ ERROR this code is interpreted as a block expression + +fn foo() { + {1, 2, 3}; + //~^ ERROR this code is interpreted as a block expression +} + +fn bar() { + 1, 2, 3 //~ ERROR expected one of +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,49 @@ +error: this code is interpreted as a block expression, not an array + --> $DIR/issue-87830-try-brackets-for-arrays.rs:3:22 + | +LL | const FOO: [u8; 3] = { + | ______________________^ +LL | | 1, 2, 3 +LL | | }; + | |_^ + | + = note: to define an array, one would use square brackets instead of curly braces +help: try using [] instead of {} + | +LL ~ const FOO: [u8; 3] = [ +LL | 1, 2, 3 +LL ~ ]; + | + +error: this code is interpreted as a block expression, not an array + --> $DIR/issue-87830-try-brackets-for-arrays.rs:7:24 + | +LL | const BAR: [&str; 3] = {"one", "two", "three"}; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: to define an array, one would use square brackets instead of curly braces +help: try using [] instead of {} + | +LL | const BAR: [&str; 3] = ["one", "two", "three"]; + | ~ ~ + +error: this code is interpreted as a block expression, not an array + --> $DIR/issue-87830-try-brackets-for-arrays.rs:11:5 + | +LL | {1, 2, 3}; + | ^^^^^^^^^ + | + = note: to define an array, one would use square brackets instead of curly braces +help: try using [] instead of {} + | +LL | [1, 2, 3]; + | ~ ~ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/issue-87830-try-brackets-for-arrays.rs:16:6 + | +LL | 1, 2, 3 + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: aborting due to 4 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit_deref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit_deref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit_deref.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit_deref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit_deref`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit_deref`) error[E0308]: mismatched types --> $DIR/recursion_limit_deref.rs:50:22 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit_macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit_macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit_macro.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit_macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,9 +5,9 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); - | -------------------------------------------------- in this macro invocation + | ------------------------------------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit_macro`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit_macro`) = note: this error originates in the macro `recurse` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/did_you_mean/recursion_limit.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | is_send::(); | ^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`) note: required because it appears within the type `J` --> $DIR/recursion_limit.rs:24:9 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/directory_ownership/macro-expanded-mod.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/directory_ownership/macro-expanded-mod.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/directory_ownership/macro-expanded-mod.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/directory_ownership/macro-expanded-mod.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^ ... LL | mod_decl!(foo); - | --------------- in this macro invocation + | -------------- in this macro invocation | = note: this error originates in the macro `mod_decl` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/discrim/discrim-ill-typed.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/discrim/discrim-ill-typed.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/discrim/discrim-ill-typed.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/discrim/discrim-ill-typed.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `u8` to `i8` | LL | OhNo = 0_i8, - | ~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:28:16 @@ -18,7 +18,7 @@ help: change the type of the numeric literal from `i8` to `u8` | LL | OhNo = 0_u8, - | ~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:41:16 @@ -29,7 +29,7 @@ help: change the type of the numeric literal from `u16` to `i16` | LL | OhNo = 0_i16, - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:54:16 @@ -40,7 +40,7 @@ help: change the type of the numeric literal from `i16` to `u16` | LL | OhNo = 0_u16, - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:67:16 @@ -51,7 +51,7 @@ help: change the type of the numeric literal from `u32` to `i32` | LL | OhNo = 0_i32, - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:80:16 @@ -62,7 +62,7 @@ help: change the type of the numeric literal from `i32` to `u32` | LL | OhNo = 0_u32, - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:93:16 @@ -73,7 +73,7 @@ help: change the type of the numeric literal from `u64` to `i64` | LL | OhNo = 0_i64, - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/discrim-ill-typed.rs:106:16 @@ -84,7 +84,7 @@ help: change the type of the numeric literal from `i64` to `u64` | LL | OhNo = 0_u64, - | ~~~~~ + | ~~~ error: aborting due to 8 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^ `$crate` in paths can only be used in start position ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^^^^^^ no `$crate` in `a` ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -27,7 +27,7 @@ | ^^^^^^ `$crate` in paths can only be used in start position ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dollar-crate/dollar-crate-is-keyword.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dollar-crate/dollar-crate-is-keyword.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dollar-crate/dollar-crate-is-keyword.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dollar-crate/dollar-crate-is-keyword.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^ expected identifier, found reserved identifier ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^^^ expected identifier, found reserved identifier ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -27,7 +27,7 @@ | ^^^^^^^^^^^ ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -38,7 +38,7 @@ | ^^^^^^^^^^^^^^^^^^^^^ ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/drop/drop-on-empty-block-exit.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/drop/drop-on-empty-block-exit.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/drop/drop-on-empty-block-exit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/drop/drop-on-empty-block-exit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,11 +2,9 @@ // pretty-expanded FIXME #23616 #![allow(non_camel_case_types)] -#![feature(box_syntax)] - enum t { foo(Box), } pub fn main() { - let tt = t::foo(box 10); + let tt = t::foo(Box::new(10)); match tt { t::foo(_z) => { } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/drop/drop-struct-as-object.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/drop/drop-struct-as-object.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/drop/drop-struct-as-object.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/drop/drop-struct-as-object.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ // Test that destructor on a struct runs successfully after the struct // is boxed and converted to an object. -#![feature(box_syntax)] - static mut value: usize = 0; struct Cat { @@ -29,7 +27,7 @@ pub fn main() { { - let x = box Cat {name: 22}; + let x = Box::new(Cat {name: 22}); let nyan: Box = x as Box; } unsafe { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/drop/drop-trait-enum.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/drop/drop-trait-enum.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/drop/drop-trait-enum.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/drop/drop-trait-enum.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,8 +4,6 @@ #![allow(unused_variables)] // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; use std::sync::mpsc::{channel, Sender}; @@ -57,7 +55,7 @@ let (sender, receiver) = channel(); { - let v = Foo::NestedVariant(box 42, SendOnDrop { sender: sender.clone() }, sender); + let v = Foo::NestedVariant(Box::new(42), SendOnDrop { sender: sender.clone() }, sender); } assert_eq!(receiver.recv().unwrap(), Message::DestructorRan); assert_eq!(receiver.recv().unwrap(), Message::Dropped); @@ -74,10 +72,10 @@ let (sender, receiver) = channel(); let t = { thread::spawn(move|| { - let mut v = Foo::NestedVariant(box 42, SendOnDrop { + let mut v = Foo::NestedVariant(Box::new(42), SendOnDrop { sender: sender.clone() }, sender.clone()); - v = Foo::NestedVariant(box 42, + v = Foo::NestedVariant(Box::new(42), SendOnDrop { sender: sender.clone() }, sender.clone()); v = Foo::SimpleVariant(sender.clone()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/drop-with-active-borrows-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/drop-with-active-borrows-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/drop-with-active-borrows-1.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/drop-with-active-borrows-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/drop-with-active-borrows-1.rs:4:10 | LL | let b: Vec<&str> = a.lines().collect(); - | - borrow of `a` occurs here + | --------- borrow of `a` occurs here LL | drop(a); | ^ move out of `a` occurs here LL | for s in &b { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/drop-with-active-borrows-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/drop-with-active-borrows-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/drop-with-active-borrows-2.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/drop-with-active-borrows-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/drop-with-active-borrows-2.rs:3:5 | LL | raw_lines.iter().map(|l| l.trim()).collect() - | ---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | returns a value referencing data owned by the current function | `raw_lines` is borrowed here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/reject-specialized-drops-8142.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/reject-specialized-drops-8142.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/reject-specialized-drops-8142.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/reject-specialized-drops-8142.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -30,7 +30,7 @@ | = note: expected struct `N<'n>` found struct `N<'static>` -note: the lifetime `'n` as defined on the struct at 7:10... +note: the lifetime `'n` as defined here... --> $DIR/reject-specialized-drops-8142.rs:7:10 | LL | struct N<'n> { x: &'n i8 } @@ -91,12 +91,12 @@ LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'l1` as defined on the struct at 16:10... +note: first, the lifetime cannot outlive the lifetime `'l1` as defined here... --> $DIR/reject-specialized-drops-8142.rs:16:10 | LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } | ^^^ -note: ...but the lifetime must also be valid for the lifetime `'l2` as defined on the struct at 16:15... +note: ...but the lifetime must also be valid for the lifetime `'l2` as defined here... --> $DIR/reject-specialized-drops-8142.rs:16:15 | LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +struct Wrapper<'a, T>(&'a T) +where + T: 'a; + +impl<'a, T> Drop for Wrapper<'a, T> +where + T: 'static, + //~^ error: `Drop` impl requires `T: 'static` but the struct it is implemented for does not +{ + fn drop(&mut self) {} +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +error[E0367]: `Drop` impl requires `T: 'static` but the struct it is implemented for does not + --> $DIR/relate_lt_in_type_outlives_bound.rs:7:8 + | +LL | T: 'static, + | ^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/relate_lt_in_type_outlives_bound.rs:1:1 + | +LL | / struct Wrapper<'a, T>(&'a T) +LL | | where +LL | | T: 'a; + | |__________^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0367`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dst/dst-bad-coercions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/dst/dst-bad-coercions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dst/dst-bad-coercions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dst/dst-bad-coercions.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,10 +13,8 @@ --> $DIR/dst-bad-coercions.rs:15:21 | LL | let y: &dyn T = x; - | ------ ^ - | | | - | | expected `&dyn T`, found *-ptr - | | help: consider borrowing here: `&x` + | ------ ^ expected `&dyn T`, found *-ptr + | | | expected due to this | = note: expected reference `&dyn T` @@ -37,10 +35,8 @@ --> $DIR/dst-bad-coercions.rs:20:21 | LL | let y: &dyn T = x; - | ------ ^ - | | | - | | expected `&dyn T`, found *-ptr - | | help: consider borrowing here: `&x` + | ------ ^ expected `&dyn T`, found *-ptr + | | | expected due to this | = note: expected reference `&dyn T` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/duplicate_doc_alias.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/duplicate_doc_alias.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/duplicate_doc_alias.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/duplicate_doc_alias.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +#![deny(unused_attributes)] + +#[doc(alias = "A")] +#[doc(alias = "A")] //~ ERROR +#[doc(alias = "B")] +#[doc(alias("B"))] //~ ERROR +pub struct Foo; + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/duplicate_doc_alias.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/duplicate_doc_alias.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/duplicate_doc_alias.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/duplicate_doc_alias.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ +error: doc alias is duplicated + --> $DIR/duplicate_doc_alias.rs:4:7 + | +LL | #[doc(alias = "A")] + | ----------- first defined here +LL | #[doc(alias = "A")] + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/duplicate_doc_alias.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: doc alias is duplicated + --> $DIR/duplicate_doc_alias.rs:6:13 + | +LL | #[doc(alias = "B")] + | ----------- first defined here +LL | #[doc(alias("B"))] + | ^^^ + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,6 @@ #![allow(type_alias_bounds)] #![allow(unused_features)] -#![feature(box_syntax)] #![feature(unsized_tuple_coercion)] type Fat = (isize, &'static str, T); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/dynamically-sized-types/dst-tuple.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/dynamically-sized-types/dst-tuple.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/dynamically-sized-types/dst-tuple.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/dynamically-sized-types/dst-tuple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ // run-pass #![allow(type_alias_bounds)] -#![feature(box_syntax)] #![feature(unsized_tuple_coercion)] type Fat = (isize, &'static str, T); @@ -109,7 +108,7 @@ assert_eq!((*f2)[1], 2); // Nested Box. - let f1 : Box> = box (5, "some str", [1, 2, 3]); + let f1 : Box> = Box::new((5, "some str", [1, 2, 3])); foo(&*f1); let f2 : Box> = f1; foo(&*f2); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/editions/edition-imports-2015.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/editions/edition-imports-2015.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/editions/edition-imports-2015.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/editions/edition-imports-2015.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/edition-imports-2015.rs:23:5 | LL | gen_glob!(); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: this error originates in the macro `gen_glob` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/editions/edition-imports-2018.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/editions/edition-imports-2018.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/editions/edition-imports-2018.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/editions/edition-imports-2018.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/edition-imports-2018.rs:24:5 | LL | gen_glob!(); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: this error originates in the macro `gen_glob` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/edition-imports-virtual-2015-gated.rs:8:5 | LL | gen_gated!(); - | ^^^^^^^^^^^^^ could not find `E` in the list of imported crates + | ^^^^^^^^^^^^ could not find `E` in the list of imported crates | = note: this error originates in the macro `gen_gated` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/empty/empty-comment.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/empty/empty-comment.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/empty/empty-comment.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/empty/empty-comment.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | -------------------------- when calling this macro ... LL | one_arg_macro!(/**/); - | ^^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/enable-unstable-lib-feature.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/enable-unstable-lib-feature.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/enable-unstable-lib-feature.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/enable-unstable-lib-feature.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -// Test that enabling an unstable feature disables warnings - -// aux-build:stability-cfg2.rs - -#![feature(unstable_test_feature)] -#![deny(non_snake_case)] // To trigger a hard error - -// Shouldn't generate a warning about unstable features -extern crate stability_cfg2; - -pub fn BOGUS() { } //~ ERROR - -pub fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/enable-unstable-lib-feature.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/enable-unstable-lib-feature.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/enable-unstable-lib-feature.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/enable-unstable-lib-feature.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -error: function `BOGUS` should have a snake case name - --> $DIR/enable-unstable-lib-feature.rs:11:8 - | -LL | pub fn BOGUS() { } - | ^^^^^ help: convert the identifier to snake case: `bogus` - | -note: the lint level is defined here - --> $DIR/enable-unstable-lib-feature.rs:6:9 - | -LL | #![deny(non_snake_case)] // To trigger a hard error - | ^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ // run-pass + +#![allow(enum_intrinsics_non_enums)] + use std::mem; enum ADT { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/enum-discriminant/issue-90038.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/enum-discriminant/issue-90038.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/enum-discriminant/issue-90038.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/enum-discriminant/issue-90038.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +// run-pass + +#[repr(u32)] +pub enum Foo { + // Greater than or equal to 2 + A = 2, +} + +pub enum Bar { + A(Foo), + // More than two const variants + B, + C, +} + +fn main() { + match Bar::A(Foo::A) { + Bar::A(_) => (), + _ => unreachable!(), + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/enum-discriminant/niche-prefer-zero.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/enum-discriminant/niche-prefer-zero.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/enum-discriminant/niche-prefer-zero.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/enum-discriminant/niche-prefer-zero.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// Check that niche selection prefers zero. +// See https://github.com/rust-lang/rust/pull/87794 +// run-pass +#[repr(u8)] +pub enum Size { + One = 1, + Two = 2, + Three = 3, +} + +fn main() { + // check that `None` is zero + assert_eq!(0, unsafe { std::mem::transmute::, u8>(None) }); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/enum-discriminant/niche.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/enum-discriminant/niche.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/enum-discriminant/niche.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/enum-discriminant/niche.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ // run-pass -#![feature(const_panic)] - //! Make sure that we read and write enum discriminants correctly for corner cases caused //! by layout optimizations. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-1.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +// compile-flags:-C extra-filename=-1 +#![crate_name = "crateresolve1"] +#![crate_type = "lib"] + +pub fn f() -> isize { 10 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +// compile-flags:-C extra-filename=-2 +#![crate_name = "crateresolve1"] +#![crate_type = "lib"] + +pub fn f() -> isize { 20 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-3.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/auxiliary/crateresolve1-3.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,5 @@ +// compile-flags:-C extra-filename=-3 +#![crate_name = "crateresolve1"] +#![crate_type = "lib"] + +pub fn f() -> isize { 30 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0034.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0034.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0034.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0034.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,12 +16,12 @@ | ^^^^^^^^ help: disambiguate the associated function for candidate #1 | -LL | Trait1::foo() - | ~~~~~~~~ +LL | ::foo() + | ~~~~~~~~~~~~~~~~~~ help: disambiguate the associated function for candidate #2 | -LL | Trait2::foo() - | ~~~~~~~~ +LL | ::foo() + | ~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0038.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0038.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0038.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0038.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn call_foo(x: Box) { | ^^^^^^^^^ `Trait` cannot be made into an object | - = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/E0038.rs:2:22 | @@ -12,6 +11,7 @@ | ----- this trait cannot be made into an object... LL | fn foo(&self) -> Self; | ^^^^ ...because method `foo` references the `Self` type in its return type + = help: consider moving `foo` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0055.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0055.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0055.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0055.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | ref_foo.foo(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="8"]` attribute to your crate (`E0055`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`E0055`) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/e0119/complex-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/e0119/complex-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/e0119/complex-impl.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/e0119/complex-impl.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: conflicting implementation in crate `complex_impl_support`: - impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box, V, W>) - where >::Output == V, ::Item == T, 'b: 'a, T: 'a, U: FnOnce<(T,)>, U: 'static, V: Iterator, V: Clone, W: Add, ::Output: Copy; + where >::Output == V, ::Item == T, 'b: 'a, T: 'a, U: 'static, U: FnOnce<(T,)>, V: Iterator, V: Clone, W: Add, ::Output: Copy; error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/complex-impl.rs:9:1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0161.edition.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0161.edition.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0161.edition.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0161.edition.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/E0161.rs:29:5 | LL | x.f(); - | ^ + | ^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0161.migrate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0161.migrate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0161.migrate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0161.migrate.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/E0161.rs:29:5 | LL | x.f(); - | ^ + | ^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0161.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0161.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0161.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0161.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/E0161.rs:29:5 | LL | x.f(); - | ^ + | ^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0161.zflags.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0161.zflags.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0161.zflags.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0161.zflags.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/E0161.rs:29:5 | LL | x.f(); - | ^ + | ^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0221.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0221.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0221.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0221.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,11 +13,11 @@ help: use fully qualified syntax to disambiguate | LL | let _: ::A; - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~ help: use fully qualified syntax to disambiguate | LL | let _: ::A; - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~ error[E0221]: ambiguous associated type `Err` in bounds of `Self` --> $DIR/E0221.rs:21:16 @@ -26,12 +26,13 @@ | ------------- ambiguous `Err` from `My` LL | fn test() { LL | let _: Self::Err; - | ^^^^^^^^^ - | | - | ambiguous associated type `Err` - | help: use fully qualified syntax to disambiguate: `::Err` + | ^^^^^^^^^ ambiguous associated type `Err` | = note: associated type `Self` could derive from `FromStr` +help: use fully qualified syntax to disambiguate + | +LL | let _: ::Err; + | ~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0225.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0225.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0225.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0225.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -23,7 +23,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0275.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0275.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0275.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0275.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | impl Foo for T where Bar: Foo {} | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`E0275`) note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/E0275.rs:5:9 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0277.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0277.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0277.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0277.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,9 @@ --> $DIR/E0277.rs:15:15 | LL | some_func(5i32); - | ^^^^ the trait `Foo` is not implemented for `i32` + | --------- ^^^^ the trait `Foo` is not implemented for `i32` + | | + | required by a bound introduced by this call | note: required by a bound in `some_func` --> $DIR/E0277.rs:7:17 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0308-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0308-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0308-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0308-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,9 +4,9 @@ LL | impl Eq for &dyn DynEq {} | ^^ lifetime mismatch | - = note: expected trait `PartialEq` - found trait `PartialEq` -note: the lifetime `'_` as defined on the impl at 9:13... + = note: expected trait `<&dyn DynEq as PartialEq>` + found trait `<&(dyn DynEq + 'static) as PartialEq>` +note: the lifetime `'_` as defined here... --> $DIR/E0308-2.rs:9:13 | LL | impl Eq for &dyn DynEq {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0395.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0395.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0395.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0395.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/E0395.rs:4:29 | LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0407.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0407.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0407.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0407.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,10 @@ --> $DIR/E0407.rs:9:5 | LL | fn b() {} - | ^^^^^^^^^ not a member of trait `Foo` + | ^^^-^^^^^ + | | | + | | help: there is an associated function with a similar name: `a` + | not a member of trait `Foo` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0439.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0439.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0439.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0439.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -#![feature(platform_intrinsics)] - -extern "platform-intrinsic" { - fn simd_shuffle(a: A, b: A, c: [u32; 8]) -> B; //~ ERROR E0439 -} - -fn main () { -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0439.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0439.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0439.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0439.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -error[E0439]: invalid `simd_shuffle`, needs length: `simd_shuffle` - --> $DIR/E0439.rs:4:5 - | -LL | fn simd_shuffle(a: A, b: A, c: [u32; 8]) -> B; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0439`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0464.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0464.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0464.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0464.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +// aux-build:crateresolve1-1.rs +// aux-build:crateresolve1-2.rs +// aux-build:crateresolve1-3.rs + +// normalize-stderr-test: "\.nll/" -> "/" +// normalize-stderr-test: "\\\?\\" -> "" +// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib" + +// NOTE: This test is duplicated from `src/test/ui/crate-loading/crateresolve1.rs`. + +extern crate crateresolve1; +//~^ ERROR multiple matching crates for `crateresolve1` + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0464.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0464.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0464.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0464.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0464]: multiple matching crates for `crateresolve1` + --> $DIR/E0464.rs:11:1 + | +LL | extern crate crateresolve1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: candidates: + crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-1.somelib + crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-2.somelib + crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-3.somelib + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0464`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0478.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0478.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0478.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0478.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | child: Box + 'SnowWhite>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'SnowWhite` as defined on the struct at 3:22 +note: lifetime parameter instantiated with the lifetime `'SnowWhite` as defined here --> $DIR/E0478.rs:3:22 | LL | struct Prince<'kiss, 'SnowWhite> { | ^^^^^^^^^^ -note: but lifetime parameter must outlive the lifetime `'kiss` as defined on the struct at 3:15 +note: but lifetime parameter must outlive the lifetime `'kiss` as defined here --> $DIR/E0478.rs:3:15 | LL | struct Prince<'kiss, 'SnowWhite> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0490.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0490.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0490.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0490.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | let x: &'a _ = &y; | ^^ | -note: the type is valid for the lifetime `'a` as defined on the function body at 1:6 +note: the type is valid for the lifetime `'a` as defined here --> $DIR/E0490.rs:1:6 | LL | fn f<'a, 'b>(y: &'b ()) { | ^^ -note: but the borrow lasts for the lifetime `'b` as defined on the function body at 1:10 +note: but the borrow lasts for the lifetime `'b` as defined here --> $DIR/E0490.rs:1:10 | LL | fn f<'a, 'b>(y: &'b ()) { @@ -21,7 +21,7 @@ LL | let x: &'a _ = &y; | ^^ | -note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 1:10... +note: first, the lifetime cannot outlive the lifetime `'b` as defined here... --> $DIR/E0490.rs:1:10 | LL | fn f<'a, 'b>(y: &'b ()) { @@ -31,7 +31,7 @@ | LL | let x: &'a _ = &y; | ^^ -note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/E0490.rs:1:6 | LL | fn f<'a, 'b>(y: &'b ()) { @@ -48,7 +48,7 @@ LL | let x: &'a _ = &y; | ^^ | -note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 1:10... +note: first, the lifetime cannot outlive the lifetime `'b` as defined here... --> $DIR/E0490.rs:1:10 | LL | fn f<'a, 'b>(y: &'b ()) { @@ -60,7 +60,7 @@ | ^^ = note: expected `&'a &()` found `&'a &'b ()` -note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/E0490.rs:1:6 | LL | fn f<'a, 'b>(y: &'b ()) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0499.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0499.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0499.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0499.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^^^^^^ second mutable borrow occurs here LL | a.use_mut(); LL | x.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0502.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0502.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0502.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0502.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | bar(a); | ^ mutable borrow occurs here LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0502.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0502.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0502.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0502.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | bar(a); | ^^^^^^ mutable borrow occurs here LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0503.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0503.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0503.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0503.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | let _sum = value + 1; | ^^^^^ use of borrowed `value` LL | _borrow.use_mut(); - | ------- borrow later used here + | ----------------- borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0505.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0505.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0505.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0505.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | eat(x); | ^ move out of `x` occurs here LL | _ref_to_val.use_ref(); - | ----------- borrow later used here + | --------------------- borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0507.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0507.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0507.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0507.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/E0507.rs:12:5 | LL | x.borrow().nothing_is_true(); - | ^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0605.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0605.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0605.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0605.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -12,8 +12,9 @@ | help: consider borrowing the value | -LL | &*v as &u8; - | ++ +LL - v as &u8; +LL + &*v; + | error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0660.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0660.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-codes/E0660.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-codes/E0660.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,13 @@ --> $DIR/E0660.rs:6:5 | LL | llvm_asm!("nop" "nop"); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0660]: malformed inline assembly --> $DIR/E0660.rs:8:5 | LL | llvm_asm!("nop" "nop" : "=r"(a)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-festival.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-festival.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-festival.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-festival.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -36,7 +36,22 @@ LL | !Question::Yes; | ^^^^^^^^^^^^^^ cannot apply unary operator `!` | - = note: an implementation of `std::ops::Not` might be missing for `Question` +note: an implementation of `Not` might be missing for `Question` + --> $DIR/error-festival.rs:1:1 + | +LL | enum Question { + | ^^^^^^^^^^^^^ must implement `Not` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait Not { +LL | | /// The resulting type after applying the `!` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn not(self) -> Self::Output; +LL | | } + | |_^ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/error-festival.rs:25:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/errors/issue-89280-emitter-overflow-splice-lines.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/errors/issue-89280-emitter-overflow-splice-lines.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/errors/issue-89280-emitter-overflow-splice-lines.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/errors/issue-89280-emitter-overflow-splice-lines.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +// check-pass + +trait X { + fn test(x: u32, ( +//~^ WARN anonymous parameters are deprecated and will be removed in the next edition +//~^^ WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + )) {} +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +warning: anonymous parameters are deprecated and will be removed in the next edition + --> $DIR/issue-89280-emitter-overflow-splice-lines.rs:4:21 + | +LL | fn test(x: u32, ( + | _____________________^ +LL | | +LL | | +LL | | )) {} + | |_____^ + | + = note: `#[warn(anonymous_parameters)]` on by default + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #41686 +help: try naming the parameter or explicitly ignoring it + | +LL ~ fn test(x: u32, _: ( +LL + +LL + +LL ~ )) {} + | + +warning: 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/error-should-say-copy-not-pod.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/error-should-say-copy-not-pod.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/error-should-say-copy-not-pod.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/error-should-say-copy-not-pod.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/error-should-say-copy-not-pod.rs:6:17 | LL | check_bound("nocopy".to_string()); - | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | ----------- ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | | + | required by a bound introduced by this call | note: required by a bound in `check_bound` --> $DIR/error-should-say-copy-not-pod.rs:3:18 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `Foo<'a, 'b>` found struct `Foo<'b, 'a>` -note: the lifetime `'b` as defined on the impl at 6:9... +note: the lifetime `'b` as defined here... --> $DIR/explicit-self-lifetime-mismatch.rs:6:9 | LL | impl<'a,'b> Foo<'a,'b> { | ^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 6:6 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/explicit-self-lifetime-mismatch.rs:6:6 | LL | impl<'a,'b> Foo<'a,'b> { @@ -25,12 +25,12 @@ | = note: expected struct `Foo<'a, 'b>` found struct `Foo<'b, 'a>` -note: the lifetime `'a` as defined on the impl at 6:6... +note: the lifetime `'a` as defined here... --> $DIR/explicit-self-lifetime-mismatch.rs:6:6 | LL | impl<'a,'b> Foo<'a,'b> { | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 6:9 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/explicit-self-lifetime-mismatch.rs:6:9 | LL | impl<'a,'b> Foo<'a,'b> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/if/if-let.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/if/if-let.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/if/if-let.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/if/if-let.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | / foo!(a, 1, { LL | | println!("irrefutable pattern"); LL | | }); - | |_______- in this macro invocation + | |______- in this macro invocation | = note: `#[warn(irrefutable_let_patterns)]` on by default = note: this pattern will always match, so the `if let` is useless @@ -23,7 +23,7 @@ LL | / bar!(a, 1, { LL | | println!("irrefutable pattern"); LL | | }); - | |_______- in this macro invocation + | |______- in this macro invocation | = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +// This snippet ensures that no attempt to recover on a semicolon instead of +// comma is made next to a closure body. +// +// If this recovery happens, then plenty of errors are emitted. Here, we expect +// only one error. +// +// This is part of issue #88065: +// https://github.com/rust-lang/rust/issues/88065 + +// run-rustfix + +fn main() { + let num = 5; + (1..num).reduce(|a, b| { + //~^ ERROR: closure bodies that contain statements must be surrounded by braces + println!("{}", a); + a * b + }).unwrap(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +// This snippet ensures that no attempt to recover on a semicolon instead of +// comma is made next to a closure body. +// +// If this recovery happens, then plenty of errors are emitted. Here, we expect +// only one error. +// +// This is part of issue #88065: +// https://github.com/rust-lang/rust/issues/88065 + +// run-rustfix + +fn main() { + let num = 5; + (1..num).reduce(|a, b| + //~^ ERROR: closure bodies that contain statements must be surrounded by braces + println!("{}", a); + a * b + ).unwrap(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,38 @@ +error: closure bodies that contain statements must be surrounded by braces + --> $DIR/missing_braces_around_block.rs:14:26 + | +LL | (1..num).reduce(|a, b| + | ^ +... +LL | ).unwrap(); + | ^ + | +note: statement found outside of a block + --> $DIR/missing_braces_around_block.rs:16:26 + | +LL | println!("{}", a); + | -----------------^ this `;` turns the preceding closure into a statement + | | + | this expression is a statement because of the trailing semicolon +note: the closure body may be incorrectly delimited + --> $DIR/missing_braces_around_block.rs:14:21 + | +LL | (1..num).reduce(|a, b| + | _____________________^ +LL | | +LL | | println!("{}", a); + | |_________________________^ this is the parsed closure... +LL | a * b +LL | ).unwrap(); + | - ...but likely you meant the closure to end here +help: try adding braces + | +LL ~ (1..num).reduce(|a, b| { +LL | +LL | println!("{}", a); +LL | a * b +LL ~ }).unwrap(); + | + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/ruby_style_closure.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/ruby_style_closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/ruby_style_closure.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/ruby_style_closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// Part of issue #27300. +// The problem here is that ruby-style closures are parsed as blocks whose +// first statement is a closure. See the issue for more details: +// https://github.com/rust-lang/rust/issues/27300 + +// Note: this test represents what the compiler currently emits. The error +// message will be improved later. + +fn main() { + let p = Some(45).and_then({ + //~^ expected a `FnOnce<({integer},)>` closure, found `Option<_>` + |x| println!("doubling {}", x); + Some(x * 2) + //~^ ERROR: cannot find value `x` in this scope + }); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,27 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/ruby_style_closure.rs:13:14 + | +LL | Some(x * 2) + | ^ not found in this scope + +error[E0277]: expected a `FnOnce<({integer},)>` closure, found `Option<_>` + --> $DIR/ruby_style_closure.rs:10:31 + | +LL | let p = Some(45).and_then({ + | ______________________--------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | |x| println!("doubling {}", x); +LL | | Some(x * 2) + | | ----------- +LL | | +LL | | }); + | |_____^ expected an `FnOnce<({integer},)>` closure, found `Option<_>` + | + = help: the trait `FnOnce<({integer},)>` is not implemented for `Option<_>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0425. +For more information about an error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-block-generic-unique1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-block-generic-unique1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-block-generic-unique1.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-block-generic-unique1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(unused_braces)] -#![feature(box_syntax)] fn test_generic(expected: Box, eq: F) where T: Clone, F: FnOnce(Box, Box) -> bool { let actual: Box = { expected.clone() }; @@ -13,7 +12,7 @@ println!("{}", *b2); return *b1 == *b2; } - test_generic::(box true, compare_box); + test_generic::(Box::new(true), compare_box); } pub fn main() { test_box(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-block-generic-unique2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-block-generic-unique2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-block-generic-unique2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-block-generic-unique2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(unused_braces)] -#![feature(box_syntax)] fn test_generic(expected: T, eq: F) where T: Clone, F: FnOnce(T, T) -> bool { let actual: T = { expected.clone() }; @@ -9,7 +8,7 @@ fn test_vec() { fn compare_vec(v1: Box, v2: Box) -> bool { return v1 == v2; } - test_generic::, _>(box 1, compare_vec); + test_generic::, _>(Box::new(1), compare_vec); } pub fn main() { test_vec(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-block-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-block-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-block-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-block-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass #![allow(unused_braces)] -#![feature(box_syntax)] -pub fn main() { let x: Box<_> = { box 100 }; assert_eq!(*x, 100); } +pub fn main() { let x: Box<_> = { Box::new(100) }; assert_eq!(*x, 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-empty-ret.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-empty-ret.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-empty-ret.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-empty-ret.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -// run-pass - -#![allow(dead_code)] -// Issue #521 - -// pretty-expanded FIXME #23616 - -fn f() { - let _x = match true { - true => { 10 } - false => { return } - }; -} - -pub fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-if-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-if-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/expr-if-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/expr-if-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,8 @@ // run-pass -#![feature(box_syntax)] - // Tests for if as expressions returning boxed types fn test_box() { - let rs: Box<_> = if true { box 100 } else { box 101 }; + let rs: Box<_> = if true { Box::new(100) } else { Box::new(101) }; assert_eq!(*rs, 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/extenv/extenv-no-args.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/extenv/extenv-no-args.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/extenv/extenv-no-args.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/extenv/extenv-no-args.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/extenv-no-args.rs:1:13 | LL | fn main() { env!(); } - | ^^^^^^^ + | ^^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/extenv/extenv-not-defined-custom.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/extenv/extenv-not-defined-custom.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/extenv/extenv-not-defined-custom.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/extenv/extenv-not-defined-custom.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/extenv-not-defined-custom.rs:1:13 | LL | fn main() { env!("__HOPEFULLY_NOT_DEFINED__", "my error message"); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/extenv/extenv-not-defined-default.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/extenv/extenv-not-defined-default.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/extenv/extenv-not-defined-default.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/extenv/extenv-not-defined-default.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/extenv-not-defined-default.rs:2:5 | LL | env!("__HOPEFULLY_NOT_DEFINED__"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/extenv/extenv-too-many-args.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/extenv/extenv-too-many-args.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/extenv/extenv-too-many-args.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/extenv/extenv-too-many-args.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/extenv-too-many-args.rs:1:13 | LL | fn main() { env!("one", "two", "three"); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/extern/extern-wrong-value-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/extern/extern-wrong-value-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/extern/extern-wrong-value-type.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/extern/extern-wrong-value-type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/extern-wrong-value-type.rs:9:11 | LL | is_fn(f); - | ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` + | ----- ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` + | | + | required by a bound introduced by this call | = help: the trait `Fn<()>` is not implemented for `extern "C" fn() {f}` = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/extoption_env-no-args.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/extoption_env-no-args.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/extoption_env-no-args.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/extoption_env-no-args.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/extoption_env-no-args.rs:1:13 | LL | fn main() { option_env!(); } - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/extoption_env-too-many-args.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/extoption_env-too-many-args.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/extoption_env-too-many-args.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/extoption_env-too-many-args.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/extoption_env-too-many-args.rs:1:13 | LL | fn main() { option_env!("one", "two"); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-allow-internal-unsafe-nested-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-allow-internal-unsafe-nested-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-allow-internal-unsafe-nested-macro.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-allow-internal-unsafe-nested-macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | bar!(); - | ------- in this macro invocation + | ------ in this macro invocation | = help: add `#![feature(allow_internal_unsafe)]` to the crate attributes to enable = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-nested-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-nested-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-nested-macro.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-nested-macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | bar!(); - | ------- in this macro invocation + | ------ in this macro invocation | = help: add `#![feature(allow_internal_unstable)]` to the crate attributes to enable = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-closure_track_caller.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-closure_track_caller.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-closure_track_caller.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-closure_track_caller.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +#![feature(stmt_expr_attributes)] +#![feature(generators)] + +fn main() { + let _closure = #[track_caller] || {}; //~ `#[track_caller]` on closures + let _generator = #[track_caller] || { yield; }; //~ `#[track_caller]` on closures +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-closure_track_caller.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-closure_track_caller.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-closure_track_caller.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-closure_track_caller.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/feature-gate-closure_track_caller.rs:5:20 + | +LL | let _closure = #[track_caller] || {}; + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/feature-gate-closure_track_caller.rs:6:22 + | +LL | let _generator = #[track_caller] || { yield; }; + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ --> $DIR/feature-gate-concat_idents2.rs:2:5 | LL | concat_idents!(a, b); - | ^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^ not found in this scope | = note: this error originates in the macro `concat_idents` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,31 @@ +#![deny(non_exhaustive_omitted_patterns)] +//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable +//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable +#![allow(non_exhaustive_omitted_patterns)] +//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable +//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable + +fn main() { + enum Foo { + A, B, C, + } + + #[allow(non_exhaustive_omitted_patterns)] + match Foo::A { + Foo::A => {} + Foo::B => {} + } + //~^^^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable + //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable + //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable + //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable + + match Foo::A { + Foo::A => {} + Foo::B => {} + #[warn(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable + //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,93 @@ +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1 + | +LL | #![deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1 + | +LL | #![allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5 + | +LL | #[allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5 + | +LL | #[allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1 + | +LL | #![deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1 + | +LL | #![allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5 + | +LL | #[allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5 + | +LL | #[allow(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #89554 for more information + = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -40,7 +40,6 @@ LL | fn takes_non_object_safe_box(obj: Box) { | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object | - = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:11:8 | @@ -48,6 +47,7 @@ | -------------- this trait cannot be made into an object... LL | fn foo(&self); | ^^^ ...because method `foo` has generic type parameters + = help: consider moving `foo` to another trait error[E0038]: the trait `NonObjectSafe4` cannot be made into an object --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:35 @@ -55,7 +55,6 @@ LL | fn return_non_object_safe_rc() -> std::rc::Rc { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe4` cannot be made into an object | - = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:15:22 | @@ -63,6 +62,7 @@ | -------------- this trait cannot be made into an object... LL | fn foo(&self, s: &Self); | ^^^^^ ...because method `foo` references the `Self` type in this parameter + = help: consider moving `foo` to another trait error[E0038]: the trait `NonObjectSafe1` cannot be made into an object --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:16 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-try_reserve.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-try_reserve.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-try_reserve.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-try_reserve.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -fn main() { - let v = Vec::new(); - v.try_reserve(10); //~ ERROR: use of unstable library feature 'try_reserve' -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-try_reserve.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-try_reserve.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-try_reserve.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-try_reserve.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -error[E0658]: use of unstable library feature 'try_reserve': new API - --> $DIR/feature-gate-try_reserve.rs:3:7 - | -LL | v.try_reserve(10); - | ^^^^^^^^^^^ - | - = note: see issue #48043 for more information - = help: add `#![feature(try_reserve)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -101,5 +101,5 @@ error: aborting due to 12 previous errors -Some errors have detailed explanations: E0229, E0658. -For more information about an error, try `rustc --explain E0229`. +Some errors have detailed explanations: E0183, E0229, E0658. +For more information about an error, try `rustc --explain E0183`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -26,4 +26,5 @@ error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0183, E0658. +For more information about an error, try `rustc --explain E0183`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -12,10 +12,10 @@ | + error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time - --> $DIR/feature-gate-unsized_fn_params.rs:24:5 + --> $DIR/feature-gate-unsized_fn_params.rs:24:9 | LL | foo(*x); - | ^^^ doesn't have a size known at compile-time + | ^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` = note: all function arguments must have a statically known size diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/thread-local-const-init.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/thread-local-const-init.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/thread-local-const-init.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/thread-local-const-init.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/thread-local-const-init.rs:1:1 | LL | thread_local!(static X: u32 = const { 0 }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #84223 for more information = help: add `#![feature(thread_local_const_init)]` to the crate attributes to enable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/trace_macros-gate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/trace_macros-gate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/feature-gates/trace_macros-gate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/feature-gates/trace_macros-gate.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ --> $DIR/trace_macros-gate.rs:4:5 | LL | trace_macros!(); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:6:5 @@ -38,7 +38,7 @@ | ^^^^^^^^^^^^ ... LL | expando!(true); - | --------------- in this macro invocation + | -------------- in this macro invocation | = note: see issue #29598 for more information = help: add `#![feature(trace_macros)]` to the crate attributes to enable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/float-literal-inference-restrictions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/float-literal-inference-restrictions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/float-literal-inference-restrictions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/float-literal-inference-restrictions.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -19,7 +19,7 @@ help: change the type of the numeric literal from `f64` to `f32` | LL | let y: f32 = 1f32; - | ~~~~ + | ~~~ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/fmt/ifmt-bad-format-args.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/fmt/ifmt-bad-format-args.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/fmt/ifmt-bad-format-args.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/fmt/ifmt-bad-format-args.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/ifmt-bad-format-args.rs:2:5 | LL | format_args!(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/fmt/issue-89173.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/fmt/issue-89173.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/fmt/issue-89173.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/fmt/issue-89173.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// Regression test for #89173: Make sure a helpful note is issued for +// printf-style format strings using `*` to specify the width. + +fn main() { + let num = 0x0abcde; + let width = 6; + print!("%0*x", width, num); + //~^ ERROR: multiple unused formatting arguments + //~| NOTE: multiple missing formatting specifiers + //~| NOTE: argument never used + //~| NOTE: argument never used + //~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width + //~| NOTE: printf formatting not supported +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/fmt/issue-89173.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/fmt/issue-89173.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/fmt/issue-89173.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/fmt/issue-89173.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +error: multiple unused formatting arguments + --> $DIR/issue-89173.rs:7:20 + | +LL | print!("%0*x", width, num); + | ------ ^^^^^ ^^^ argument never used + | | | + | | argument never used + | multiple missing formatting specifiers + | +note: format specifiers use curly braces, and you have to use a positional or named parameter for the width + --> $DIR/issue-89173.rs:7:13 + | +LL | print!("%0*x", width, num); + | ^^^^ + = note: printf formatting not supported; see the documentation for `std::fmt` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/fn-trait-formatting.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/fn-trait-formatting.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/fn-trait-formatting.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/fn-trait-formatting.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,17 +1,17 @@ -#![feature(box_syntax)] - fn needs_fn(x: F) where F: Fn(isize) -> isize {} + + fn main() { - let _: () = (box |_: isize| {}) as Box; + let _: () = Box::new(|_: isize| {}) as Box; //~^ ERROR mismatched types //~| expected unit type `()` //~| found struct `Box` - let _: () = (box |_: isize, isize| {}) as Box; + let _: () = Box::new(|_: isize, isize| {}) as Box; //~^ ERROR mismatched types //~| expected unit type `()` //~| found struct `Box` - let _: () = (box || -> isize { unimplemented!() }) as Box isize>; + let _: () = Box::new(|| -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types //~| expected unit type `()` //~| found struct `Box isize>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/fn-trait-formatting.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/fn-trait-formatting.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/fn-trait-formatting.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/fn-trait-formatting.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:6:17 | -LL | let _: () = (box |_: isize| {}) as Box; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` +LL | let _: () = Box::new(|_: isize| {}) as Box; + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | @@ -12,8 +12,8 @@ error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:10:17 | -LL | let _: () = (box |_: isize, isize| {}) as Box; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` +LL | let _: () = Box::new(|_: isize, isize| {}) as Box; + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | @@ -23,8 +23,8 @@ error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:14:17 | -LL | let _: () = (box || -> isize { unimplemented!() }) as Box isize>; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` +LL | let _: () = Box::new(|| -> isize { unimplemented!() }) as Box isize>; + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | @@ -35,11 +35,13 @@ --> $DIR/fn-trait-formatting.rs:19:14 | LL | needs_fn(1); - | ^ expected an `Fn<(isize,)>` closure, found `{integer}` + | -------- ^ expected an `Fn<(isize,)>` closure, found `{integer}` + | | + | required by a bound introduced by this call | = help: the trait `Fn<(isize,)>` is not implemented for `{integer}` note: required by a bound in `needs_fn` - --> $DIR/fn-trait-formatting.rs:3:31 + --> $DIR/fn-trait-formatting.rs:1:31 | LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} | ^^^^^^^^^^^^^^^^^^ required by this bound in `needs_fn` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5 + | +LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | s + | ^ returning this value requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +// check-fail +// See issue #91068. Types in the substs of an associated type can't be implied +// to be WF, since they don't actually have to be constructed. + +trait Trait { + type Type; +} + +impl Trait for T { + type Type = (); +} + +fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { + s //~ ERROR lifetime mismatch [E0623] +} + +fn main() { + let x = String::from("Hello World!"); + let y = f(&x, ()); + drop(x); + println!("{}", y); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +error[E0623]: lifetime mismatch + --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5 + | +LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { + | ------- ---------- + | | + | these two types are declared with different lifetimes... +LL | s + | ^ ...but data from `s` flows here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,6 @@ // This test verifies that temporaries created for `while`'s and `if` // conditions are dropped after the condition is evaluated. -#![feature(box_syntax)] - struct Temporary; static mut DROPPED: isize = 0; @@ -18,7 +16,7 @@ fn do_stuff(&self) -> bool {true} } -fn borrow() -> Box { box Temporary } +fn borrow() -> Box { Box::new(Temporary) } pub fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/future-incompatible-lint-group.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/future-incompatible-lint-group.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/future-incompatible-lint-group.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/future-incompatible-lint-group.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -warning: anonymous parameters are deprecated and will be removed in the next edition. +warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/future-incompatible-lint-group.rs:7:10 | LL | fn f(u8) {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/gated-bad-feature.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/gated-bad-feature.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/gated-bad-feature.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/gated-bad-feature.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,13 +20,13 @@ --> $DIR/gated-bad-feature.rs:5:1 | LL | #![feature] - | ^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]` + | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name1, ...)]` error: malformed `feature` attribute input --> $DIR/gated-bad-feature.rs:6:1 | LL | #![feature = "foo"] - | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]` + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name1, ...)]` error: aborting due to 5 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/dropck-resume.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/dropck-resume.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/dropck-resume.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/dropck-resume.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ------ mutable borrow occurs here ... LL | r = y.as_ref().unwrap(); - | ^ immutable borrow occurs here + | ^^^^^^^^^^ immutable borrow occurs here LL | LL | } | - mutable borrow might be used here, when `g` is dropped and runs the destructor for generator diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/dropck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/dropck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/dropck.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/dropck.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/dropck.rs:10:40 | LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); - | ^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^^^^ borrowed value does not live long enough ... LL | } | - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/issue-88653.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/issue-88653.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/issue-88653.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/issue-88653.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +// Regression test for #88653, where a confusing warning about a +// type mismatch in generator arguments was issued. + +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +fn foo(bar: bool) -> impl Generator<(bool,)> { +//~^ ERROR: type mismatch in generator arguments [E0631] +//~| NOTE: expected signature of `fn((bool,)) -> _` + |bar| { + //~^ NOTE: found signature of `fn(bool) -> _` + if bar { + yield bar; + } + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/issue-88653.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/issue-88653.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/issue-88653.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/issue-88653.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +error[E0631]: type mismatch in generator arguments + --> $DIR/issue-88653.rs:8:22 + | +LL | fn foo(bar: bool) -> impl Generator<(bool,)> { + | ^^^^^^^^^^^^^^^^^^^^^^^ expected signature of `fn((bool,)) -> _` +... +LL | |bar| { + | ----- found signature of `fn(bool) -> _` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0631`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/resume-arg-late-bound.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/resume-arg-late-bound.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/resume-arg-late-bound.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/resume-arg-late-bound.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,6 +6,11 @@ | = note: expected type `for<'a> Generator<&'a mut bool>` found type `Generator<&mut bool>` +note: the lifetime requirement is introduced here + --> $DIR/resume-arg-late-bound.rs:8:17 + | +LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/resume-arg-late-bound.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/resume-arg-late-bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/resume-arg-late-bound.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/resume-arg-late-bound.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected type `for<'a> Generator<&'a mut bool>` found type `Generator<&mut bool>` -note: the required lifetime does not necessarily outlive the anonymous lifetime #1 defined on the body at 11:15 +note: the required lifetime does not necessarily outlive the anonymous lifetime #1 defined here --> $DIR/resume-arg-late-bound.rs:11:15 | LL | let gen = |arg: &mut bool| { @@ -29,7 +29,7 @@ | = note: expected type `for<'a> Generator<&'a mut bool>` found type `Generator<&mut bool>` -note: the anonymous lifetime #1 defined on the body at 11:15 doesn't meet the lifetime requirements +note: the anonymous lifetime #1 defined here doesn't meet the lifetime requirements --> $DIR/resume-arg-late-bound.rs:11:15 | LL | let gen = |arg: &mut bool| { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/static-not-unpin.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/static-not-unpin.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/static-not-unpin.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/static-not-unpin.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/static-not-unpin.rs:14:18 | LL | assert_unpin(generator); - | ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` + | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` + | | + | required by a bound introduced by this call | = note: consider using `Box::pin` note: required by a bound in `assert_unpin` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/yield-in-box.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/yield-in-box.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/yield-in-box.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/yield-in-box.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,10 @@ // run-pass - // Test that box-statements with yields in them work. -#![feature(generators, box_syntax)] +#![feature(generators, box_syntax, generator_trait)] +use std::pin::Pin; +use std::ops::Generator; +use std::ops::GeneratorState; fn main() { let x = 0i32; @@ -15,4 +17,8 @@ _t => {} } }; + + let mut g = |_| box yield; + assert_eq!(Pin::new(&mut g).resume(1), GeneratorState::Yielded(())); + assert_eq!(Pin::new(&mut g).resume(2), GeneratorState::Complete(box 2)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/yield-in-box.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/yield-in-box.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generator/yield-in-box.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generator/yield-in-box.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ warning: unused generator that must be used - --> $DIR/yield-in-box.rs:9:5 + --> $DIR/yield-in-box.rs:11:5 | LL | / || { LL | | let y = 2u32; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/gat-in-trait-path.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/gat-in-trait-path.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/gat-in-trait-path.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/gat-in-trait-path.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn f(_arg : Box Foo = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | - = help: consider moving `A` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/gat-in-trait-path.rs:5:10 | @@ -12,6 +11,7 @@ | --- this trait cannot be made into an object... LL | type A<'a> where Self: 'a; | ^ ...because it contains the generic associated type `A` + = help: consider moving `A` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/impl_bounds.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/impl_bounds.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/impl_bounds.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/impl_bounds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -13,9 +13,9 @@ impl Foo for Fooy { type A<'a> where Self: 'static = (&'a ()); - //~^ ERROR the parameter type `T` may not live long enough + //~^ ERROR `impl` associated type type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - //~^ ERROR lifetime bound not satisfied + //~^ ERROR `impl` associated type //~| ERROR lifetime bound not satisfied type C where Self: Copy = String; //~^ ERROR the trait bound `T: Copy` is not satisfied diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/impl_bounds.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/impl_bounds.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/impl_bounds.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/impl_bounds.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,28 +1,20 @@ -error[E0310]: the parameter type `T` may not live long enough +error: `impl` associated type signature for `A` doesn't match `trait` associated type signature --> $DIR/impl_bounds.rs:15:5 | +LL | type A<'a> where Self: 'a; + | -------------------------- expected +... LL | type A<'a> where Self: 'static = (&'a ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `Fooy` will meet its required lifetime bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found -error[E0478]: lifetime bound not satisfied +error: `impl` associated type signature for `B` doesn't match `trait` associated type signature --> $DIR/impl_bounds.rs:17:5 | +LL | type B<'a, 'b> where 'a: 'b; + | ---------------------------- expected +... LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: lifetime parameter instantiated with the lifetime `'b` as defined on the associated item at 17:16 - --> $DIR/impl_bounds.rs:17:16 - | -LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^ -note: but lifetime parameter must outlive the lifetime `'a` as defined on the associated item at 17:12 - --> $DIR/impl_bounds.rs:17:12 - | -LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:5 @@ -30,12 +22,12 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'a` as defined on the associated item at 17:12 +note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/impl_bounds.rs:17:12 | LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^ -note: but lifetime parameter must outlive the lifetime `'b` as defined on the associated item at 17:16 +note: but lifetime parameter must outlive the lifetime `'b` as defined here --> $DIR/impl_bounds.rs:17:16 | LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); @@ -93,5 +85,5 @@ error: aborting due to 5 previous errors -Some errors have detailed explanations: E0277, E0310, E0478. +Some errors have detailed explanations: E0277, E0478. For more information about an error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-67510-pass.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-67510-pass.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-67510-pass.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-67510-pass.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn _func1<'a>(_x: Box=&'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | - = help: consider moving `Y` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-67510-pass.rs:4:10 | @@ -12,6 +11,7 @@ | - this trait cannot be made into an object... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` + = help: consider moving `Y` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-76535.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-76535.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-76535.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-76535.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,7 +20,6 @@ LL | let sub: Box> = Box::new(SuperStruct::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object | - = help: consider moving `SubType` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-76535.rs:6:10 | @@ -28,6 +27,7 @@ | ---------- this trait cannot be made into an object... LL | type SubType<'a>: SubTrait; | ^^^^^^^ ...because it contains the generic associated type `SubType` + = help: consider moving `SubType` to another trait error[E0038]: the trait `SuperTrait` cannot be made into an object --> $DIR/issue-76535.rs:36:57 @@ -35,7 +35,6 @@ LL | let sub: Box> = Box::new(SuperStruct::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object | - = help: consider moving `SubType` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-76535.rs:6:10 | @@ -43,6 +42,7 @@ | ---------- this trait cannot be made into an object... LL | type SubType<'a>: SubTrait; | ^^^^^^^ ...because it contains the generic associated type `SubType` + = help: consider moving `SubType` to another trait = note: required because of the requirements on the impl of `CoerceUnsized>>>` for `Box` = note: required by cast to type `Box>>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ | LL | type T<'a>: A; | ^ introduces a `'static` lifetime requirement -note: the lifetime `'a` as defined on the associated item at 17:12... +note: the lifetime `'a` as defined here... --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:17:12 | LL | type T<'a> = Box; @@ -36,7 +36,7 @@ | LL | type T<'a>: C; | ^ introduces a `'static` lifetime requirement -note: the lifetime `'a` as defined on the associated item at 27:12... +note: the lifetime `'a` as defined here... --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:27:12 | LL | type T<'a> = Box; @@ -58,7 +58,7 @@ | LL | type T<'a>: E; | ^ introduces a `'static` lifetime requirement -note: the lifetime `'a` as defined on the associated item at 37:12... +note: the lifetime `'a` as defined here... --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:37:12 | LL | type T<'a> = (Box, Box); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-78671.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-78671.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-78671.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-78671.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,7 +20,6 @@ LL | Box::new(Family) as &dyn CollectionFamily | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object | - = help: consider moving `Member` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-78671.rs:4:10 | @@ -28,6 +27,7 @@ | ---------------- this trait cannot be made into an object... LL | type Member; | ^^^^^^ ...because it contains the generic associated type `Member` + = help: consider moving `Member` to another trait error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-79422.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-79422.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-79422.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-79422.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,7 +20,6 @@ LL | as Box>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object | - = help: consider moving `VRefCont` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-79422.rs:20:10 | @@ -28,6 +27,7 @@ | ------- this trait cannot be made into an object... LL | type VRefCont<'a>: RefCont<'a, V>; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` + = help: consider moving `VRefCont` to another trait error[E0038]: the trait `MapLike` cannot be made into an object --> $DIR/issue-79422.rs:41:13 @@ -35,7 +35,6 @@ LL | let m = Box::new(std::collections::BTreeMap::::new()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object | - = help: consider moving `VRefCont` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-79422.rs:20:10 | @@ -43,6 +42,7 @@ | ------- this trait cannot be made into an object... LL | type VRefCont<'a>: RefCont<'a, V>; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` + = help: consider moving `VRefCont` to another trait = note: required because of the requirements on the impl of `CoerceUnsized + 'static)>>>` for `Box>` = note: required by cast to type `Box + 'static)>>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-86787.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-86787.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-86787.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-86787.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,8 +21,8 @@ { type T = Either; type TRef<'a> - //~^ the associated type - //~^^ the associated type + //~^ `impl` associated type signature + //~^^ `impl` associated type signature where ::T: 'a, ::T: 'a diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-86787.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-86787.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-86787.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-86787.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,29 +1,32 @@ -error[E0309]: the associated type `::T` may not live long enough +error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature --> $DIR/issue-86787.rs:23:5 | +LL | type TRef<'a>; + | -------------- expected +... LL | / type TRef<'a> LL | | LL | | LL | | where LL | | ::T: 'a, LL | | ::T: 'a - | | - help: consider adding a where clause: `, ::T: 'a` LL | | = Either<&'a Left::T, &'a Right::T>; - | |________________________________________^ ...so that the type `::T` will meet its required lifetime bounds + | |________________________________________^ found -error[E0309]: the associated type `::T` may not live long enough +error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature --> $DIR/issue-86787.rs:23:5 | +LL | type TRef<'a>; + | -------------- expected +... LL | / type TRef<'a> LL | | LL | | LL | | where LL | | ::T: 'a, LL | | ::T: 'a - | | - help: consider adding a where clause: `, ::T: 'a` LL | | = Either<&'a Left::T, &'a Right::T>; - | |________________________________________^ ...so that the type `::T` will meet its required lifetime bounds + | |________________________________________^ found error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0309`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87748.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87748.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87748.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87748.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -// Checks that we properly add implied bounds from unnormalized projections in -// inputs when typechecking functions. - -// check-pass - -#![feature(generic_associated_types)] - -trait MyTrait { - type Assoc<'a, 'b> where 'b: 'a; - fn do_sth(arg: Self::Assoc<'_, '_>); -} - -struct A; -struct B; -struct C; - -impl MyTrait for A { - type Assoc<'a, 'b> where 'b: 'a = u32; - fn do_sth(_: u32) {} -} -impl MyTrait for B { - type Assoc<'a, 'b> where 'b: 'a = u32; - fn do_sth(_: Self::Assoc<'_, '_>) {} -} -impl MyTrait for C { - type Assoc<'a, 'b> where 'b: 'a = u32; - fn do_sth(_: Self::Assoc<'static, 'static>) {} -} - -fn main () {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87750.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87750.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87750.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87750.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +#![feature(generic_associated_types)] + +trait PointerFamily { + type Pointer; +} + +struct Rc(Box); +struct RcFamily; + +impl PointerFamily for RcFamily { + type Pointer = Rc; +} + +#[allow(dead_code)] +enum Node where P::Pointer>: Sized { + Cons(P::Pointer>), +} + +fn main() { + let _list: ::Pointer>; + //~^ ERROR overflow evaluating the requirement `Node: Sized` +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87750.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87750.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87750.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-87750.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `Node: Sized` + --> $DIR/issue-87750.rs:20:16 + | +LL | let _list: ::Pointer>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88287.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88287.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88287.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88287.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +// check-pass +// edition:2018 + +#![feature(generic_associated_types)] +#![feature(type_alias_impl_trait)] + +use std::future::Future; + +trait SearchableResource { + type SearchResult; +} + +trait SearchableResourceExt: SearchableResource { + type Future<'f, A: 'f + ?Sized, B: 'f>: Future, ()>> + 'f + where + A: SearchableResource; + + fn search<'c>(&'c self, client: &'c ()) -> Self::Future<'c, Self, Criteria>; +} + +type SearchFutureTy<'f, A, B: 'f> +where + A: SearchableResource + ?Sized + 'f, += impl Future, ()>> + 'f; +impl SearchableResourceExt for T +where + T: SearchableResource, +{ + type Future<'f, A, B: 'f> + where + A: SearchableResource + ?Sized + 'f, + = SearchFutureTy<'f, A, B>; + + fn search<'c>(&'c self, _client: &'c ()) -> Self::Future<'c, Self, Criteria> { + async move { todo!() } + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88360.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88360.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88360.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88360.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +#![feature(generic_associated_types)] + +trait GatTrait { + type Gat<'a>; + + fn test(&self) -> Self::Gat<'_>; +} + +trait SuperTrait +where + for<'a> Self: GatTrait = &'a T>, +{ + fn copy(&self) -> Self::Gat<'_> where T: Copy { + *self.test() + //~^ mismatched types + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88360.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88360.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88360.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88360.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/issue-88360.rs:14:9 + | +LL | trait SuperTrait + | - this type parameter +... +LL | fn copy(&self) -> Self::Gat<'_> where T: Copy { + | ------------- expected `&T` because of return type +LL | *self.test() + | ^^^^^^^^^^^^ + | | + | expected `&T`, found type parameter `T` + | help: consider borrowing here: `&*self.test()` + | + = note: expected reference `&T` + found type parameter `T` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88405.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88405.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88405.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/issue-88405.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// check-pass + +#![feature(generic_associated_types)] + +trait SomeTrait {} +trait OtherTrait { + type Item; +} + +trait ErrorSimpleExample { + type AssociatedType: SomeTrait; + type GatBounded; + type ErrorMinimal: OtherTrait>; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +// check-fail + +#![feature(generic_associated_types)] + +trait Foo { + type Assoc<'a, 'b>; +} +impl Foo for () { + type Assoc<'a, 'b> where 'a: 'b = (); + //~^ `impl` associated type +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +error: `impl` associated type signature for `Assoc` doesn't match `trait` associated type signature + --> $DIR/missing-where-clause-on-trait.rs:9:5 + | +LL | type Assoc<'a, 'b>; + | ------------------- expected +... +LL | type Assoc<'a, 'b> where 'a: 'b = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/trait-objects.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/trait-objects.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/trait-objects.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/trait-objects.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object | - = help: consider moving `Item` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/trait-objects.rs:4:10 | @@ -12,6 +11,7 @@ | ----------------- this trait cannot be made into an object... LL | type Item<'a> where Self: 'a; | ^^^^ ...because it contains the generic associated type `Item` + = help: consider moving `Item` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -12,7 +12,7 @@ LL | f: ::Y<'a>, | ^^^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 12:10 +note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/unsatified-item-lifetime-bound.rs:12:10 | LL | struct B<'a, T: for<'r> X = &'r ()>> { @@ -25,7 +25,7 @@ LL | f: ::Y<'a>, | ^^^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 17:10 +note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/unsatified-item-lifetime-bound.rs:17:10 | LL | struct C<'a, T: X> { @@ -38,7 +38,7 @@ LL | f: <() as X>::Y<'a>, | ^^^^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 22:10 +note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/unsatified-item-lifetime-bound.rs:22:10 | LL | struct D<'a> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | type Item<'a> = &'b (); | ^^^^^^^^^^^^^^^^^^^^^^^ | -note: type must outlive the lifetime `'a` as defined on the associated item at 8:15 as required by this binding +note: type must outlive the lifetime `'a` as defined here as required by this binding --> $DIR/unsatisfied-outlives-bound.rs:8:15 | LL | type Item<'a> = &'b (); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-alias-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-alias-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-alias-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-alias-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] fn id(t: T) -> T { return t; } pub fn main() { - let expected: Box<_> = box 100; + let expected: Box<_> = Box::new(100); let actual = id::>(expected.clone()); println!("{}", *actual); assert_eq!(*expected, *actual); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-exterior-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-exterior-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-exterior-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-exterior-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,8 @@ // run-pass -#![feature(box_syntax)] struct Recbox {x: Box} -fn reclift(t: T) -> Recbox { return Recbox {x: box t}; } +fn reclift(t: T) -> Recbox { return Recbox { x: Box::new(t) }; } pub fn main() { let foo: isize = 17; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-fn-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-fn-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-fn-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-fn-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,8 @@ // run-pass -#![feature(box_syntax)] fn f(x: Box) -> Box { return x; } -pub fn main() { let x = f(box 3); println!("{}", *x); } +pub fn main() { + let x = f(Box::new(3)); + println!("{}", *x); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-object.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-object.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-object.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-object.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] trait Foo { fn get(&self) -> T; @@ -16,7 +15,7 @@ } pub fn main() { - let x = box S { x: 1 }; + let x = Box::new(S { x: 1 }); let y = x as Box>; assert_eq!(y.get(), 1); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-recursive-tag.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-recursive-tag.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-recursive-tag.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-recursive-tag.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,12 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] enum list { cons(Box, Box>), nil, } pub fn main() { let _a: list = - list::cons::(box 10, - box list::cons::(box 12, - box list::cons::(box 13, - box list::nil::))); + list::cons::(Box::new(10), + Box::new(list::cons::(Box::new(12), + Box::new(list::cons::(Box::new(13), + Box::new(list::nil::)))))); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-tag.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-tag.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-tag.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-tag.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,11 +5,10 @@ // pretty-expanded FIXME #23616 #![allow(unused_variables)] -#![feature(box_syntax)] enum option { some(Box), none, } pub fn main() { - let mut a: option = option::some::(box 10); + let mut a: option = option::some::(Box::new(10)); a = option::none::; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/generic-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/generic-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,9 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct Triple { x: T, y: T, z: T } -fn box_it(x: Triple) -> Box> { return box x; } +fn box_it(x: Triple) -> Box> { return Box::new(x); } pub fn main() { let x: Box> = box_it::(Triple{x: 1, y: 2, z: 3}); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/mid-path-type-params.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/mid-path-type-params.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/mid-path-type-params.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/mid-path-type-params.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,37 @@ +// run-pass + +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +struct S { + contents: T, +} + +impl S { + fn new(x: T, _: U) -> S { + S { + contents: x, + } + } +} + +trait Trait { + fn new(x: T, y: U) -> Self; +} + +struct S2 { + contents: isize, +} + +impl Trait for S2 { + fn new(x: isize, _: U) -> S2 { + S2 { + contents: x, + } + } +} + +pub fn main() { + let _ = S::::new::(1, 1.0); + let _: S2 = Trait::::new::(1, 1.0); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/wrong-number-of-args.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/wrong-number-of-args.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/generics/wrong-number-of-args.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/generics/wrong-number-of-args.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -440,17 +440,6 @@ LL | trait GenericLifetimeAT<'a> { | ^^^^^^^^^^^^^^^^^ -- -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:169:44 - | -LL | type C = Box>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type C<'a> = Box>; - | ++++ +++ - error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied --> $DIR/wrong-number-of-args.rs:169:26 | @@ -465,6 +454,17 @@ LL | trait GenericLifetimeAT<'a> { | ^^^^^^^^^^^^^^^^^ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:169:44 + | +LL | type C = Box>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type C<'a> = Box>; + | ++++ +++ + error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:181:26 | @@ -525,17 +525,6 @@ LL | type C = Box>; | +++ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:201:48 - | -LL | type A = Box>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++ - error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:201:26 | @@ -552,6 +541,17 @@ LL | type A = Box>; | ++ +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:201:48 + | +LL | type A = Box>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++ + error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:207:26 | @@ -609,17 +609,6 @@ LL | type D<'a> = Box>; | ++++ +++ -error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:221:48 - | -LL | type E = Box>; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | type E<'a> = Box>; - | ++++ +++ - error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:221:26 | @@ -634,6 +623,17 @@ LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - +error[E0106]: missing lifetime specifier + --> $DIR/wrong-number-of-args.rs:221:48 + | +LL | type E = Box>; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | type E<'a> = Box>; + | ++++ +++ + error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied --> $DIR/wrong-number-of-args.rs:227:26 | @@ -767,17 +767,6 @@ LL | type B = Box>; | ++++ -error[E0106]: missing lifetime specifiers - --> $DIR/wrong-number-of-args.rs:279:56 - | -LL | type A = Box>; - | ^ expected 2 lifetime parameters - | -help: consider introducing a named lifetime parameter - | -LL | type A<'a> = Box>; - | ++++ +++++++ - error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied --> $DIR/wrong-number-of-args.rs:279:26 | @@ -794,6 +783,17 @@ LL | type A = Box>; | ++ +error[E0106]: missing lifetime specifiers + --> $DIR/wrong-number-of-args.rs:279:56 + | +LL | type A = Box>; + | ^ expected 2 lifetime parameters + | +help: consider introducing a named lifetime parameter + | +LL | type A<'a> = Box>; + | ++++ +++++++ + error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied --> $DIR/wrong-number-of-args.rs:285:26 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/guards.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/guards.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/guards.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/guards.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -// run-pass - -#![allow(non_shorthand_field_patterns)] - -#[derive(Copy, Clone)] -struct Pair { x: isize, y: isize } - -pub fn main() { - let a: isize = - match 10 { x if x < 7 => { 1 } x if x < 11 => { 2 } 10 => { 3 } _ => { 4 } }; - assert_eq!(a, 2); - - let b: isize = - match (Pair {x: 10, y: 20}) { - x if x.x < 5 && x.y < 5 => { 1 } - Pair {x: x, y: y} if x == 10 && y == 20 => { 2 } - Pair {x: _x, y: _y} => { 3 } - }; - assert_eq!(b, 2); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -29,7 +29,7 @@ | ^^^ help: use `..=` instead ... LL | mac!(0); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -37,7 +37,7 @@ | ^^^ help: use `..` instead ... LL | mac!(0); - | -------- in this macro invocation + | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -49,7 +49,7 @@ | ^^^ help: use `..` instead ... LL | mac!(0); - | -------- in this macro invocation + | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-iter-value-lifetime.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-iter-value-lifetime.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-iter-value-lifetime.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-iter-value-lifetime.nll.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as immutable - --> $DIR/hashmap-iter-value-lifetime.rs:7:5 - | -LL | let (_, thing) = my_stuff.iter().next().unwrap(); - | -------- immutable borrow occurs here -LL | -LL | my_stuff.clear(); - | ^^^^^^^^ mutable borrow occurs here -LL | -LL | println!("{}", *thing); - | ------ immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-iter-value-lifetime.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-iter-value-lifetime.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-iter-value-lifetime.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-iter-value-lifetime.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/hashmap-iter-value-lifetime.rs:7:5 | LL | let (_, thing) = my_stuff.iter().next().unwrap(); - | -------- immutable borrow occurs here + | --------------- immutable borrow occurs here LL | LL | my_stuff.clear(); | ^^^^^^^^^^^^^^^^ mutable borrow occurs here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-lifetimes.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-lifetimes.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-lifetimes.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-lifetimes.nll.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as immutable - --> $DIR/hashmap-lifetimes.rs:6:5 - | -LL | let mut it = my_stuff.iter(); - | -------- immutable borrow occurs here -LL | my_stuff.insert(1, 43); - | ^^^^^^^^ mutable borrow occurs here -LL | it; - | -- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-lifetimes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-lifetimes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-lifetimes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hashmap/hashmap-lifetimes.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/hashmap-lifetimes.rs:6:5 | LL | let mut it = my_stuff.iter(); - | -------- immutable borrow occurs here + | --------------- immutable borrow occurs here LL | my_stuff.insert(1, 43); | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | it; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,19 @@ error[E0631]: type mismatch in closure arguments --> $DIR/issue-62529-1.rs:80:10 | -LL | task(annotate( - | ^^^^^^^^ expected signature of `for<'r> fn( as FamilyLt<'r>>::Out) -> _` -... -LL | |value: &mut usize| { - | ------------------- found signature of `for<'r> fn(&'r mut usize) -> _` +LL | task(annotate( + | _____----_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | +LL | | Annotate::>::new(), +LL | | |value: &mut usize| { + | | ------------------- found signature of `for<'r> fn(&'r mut usize) -> _` +LL | | *value = 2; +LL | | } +LL | | )); + | |_____^ expected signature of `for<'r> fn( as FamilyLt<'r>>::Out) -> _` | note: required by a bound in `annotate` --> $DIR/issue-62529-1.rs:44:8 @@ -20,7 +28,9 @@ --> $DIR/issue-62529-1.rs:80:10 | LL | task(annotate( - | __________^ + | _____----_^ + | | | + | | required by a bound introduced by this call LL | | LL | | LL | | Annotate::>::new(), @@ -44,7 +54,9 @@ --> $DIR/issue-62529-1.rs:80:10 | LL | task(annotate( - | __________^ + | _____----_^ + | | | + | | required by a bound introduced by this call LL | | LL | | LL | | Annotate::>::new(), diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,70 @@ +// check-pass +// edition:2018 + +type BoxFuture = std::pin::Pin>>; + +fn main() { + f(); +} + +async fn f() { + run("dependency").await; +} + +struct InMemoryStorage; + +struct User<'dep> { + dep: &'dep str, +} + +impl<'a> StorageRequest for SaveUser<'a> { + fn execute(&self) -> BoxFuture> { + todo!() + } +} + +trait Storage { + type Error; +} + +impl Storage for InMemoryStorage { + type Error = String; +} + +trait StorageRequestReturnType { + type Output; +} + +trait StorageRequest: StorageRequestReturnType { + fn execute( + &self, + ) -> BoxFuture::Output, ::Error>>; +} + +struct SaveUser<'a> { + name: &'a str, +} + +impl<'a> StorageRequestReturnType for SaveUser<'a> { + type Output = (); +} + +impl<'dep> User<'dep> { + async fn save(self) + where + S: Storage, + for<'a> SaveUser<'a>: StorageRequest, + { + SaveUser { name: "Joe" } + .execute() + .await; + } +} + +async fn run(dep: &str) +where + S: Storage, + for<'a> SaveUser<'a>: StorageRequest, +{ + User { dep }.save().await; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +// check-pass + +trait Bar { + type Type; +} +struct Foo<'a>(&'a ()); +impl<'a> Bar for Foo<'a> { + type Type = (); +} + +fn func<'a>(_: as Bar>::Type) {} +fn assert_is_func(_: fn(A)) {} + +fn test() +where + for<'a> as Bar>::Type: Sized, +{ + assert_is_func(func); +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +// check-pass + +pub trait Indexable { + type Idx; +} +impl Indexable for u8 { + type Idx = u8; +} +impl Indexable for u16 { + type Idx = u16; +} + +pub trait Indexer: std::ops::Index {} + +trait StoreIndex: Indexer + Indexer {} + +fn foo(st: &impl StoreIndex) -> &dyn StoreIndex { + st as &dyn StoreIndex +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +#![feature(unboxed_closures)] + +trait SomeTrait<'a> { + type Associated; +} + +fn give_me_ice() { + callee:: >::Associated>(); + //~^ ERROR: the trait bound `T: SomeTrait<'_>` is not satisfied +} + +fn callee>() { + println!("{}", std::any::type_name::<>::Output>()); +} + +fn main() { + give_me_ice::<()>(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied + --> $DIR/issue-85455.rs:8:5 + | +LL | callee:: >::Associated>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | fn give_me_ice>() { + | +++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,32 @@ +trait BufferMut {} +struct Ctx(D); + +trait BufferUdpStateContext {} +impl BufferUdpStateContext for C {} + +trait StackContext +where + Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, +{ + type Dispatcher; +} + +trait TimerContext { + type Handler; +} +impl TimerContext for C +where + C: StackContext, + //~^ ERROR: is not satisfied [E0277] +{ + type Handler = Ctx; + //~^ ERROR: is not satisfied [E0277] +} + +struct EthernetWorker(C) +where + Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>; +impl EthernetWorker {} +//~^ ERROR: is not satisfied [E0277] + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,63 @@ +error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied + --> $DIR/issue-89118.rs:19:8 + | +LL | C: StackContext, + | ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | +note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` + --> $DIR/issue-89118.rs:5:23 + | +LL | impl BufferUdpStateContext for C {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^ +note: required by a bound in `StackContext` + --> $DIR/issue-89118.rs:9:14 + | +LL | trait StackContext + | ------------ required by a bound in this +LL | where +LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext` + +error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied + --> $DIR/issue-89118.rs:22:20 + | +LL | type Handler = Ctx; + | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | +note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` + --> $DIR/issue-89118.rs:5:23 + | +LL | impl BufferUdpStateContext for C {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^ +note: required by a bound in `StackContext` + --> $DIR/issue-89118.rs:9:14 + | +LL | trait StackContext + | ------------ required by a bound in this +LL | where +LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext` + +error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied + --> $DIR/issue-89118.rs:29:9 + | +LL | impl EthernetWorker {} + | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | +note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` + --> $DIR/issue-89118.rs:5:23 + | +LL | impl BufferUdpStateContext for C {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^ +note: required by a bound in `EthernetWorker` + --> $DIR/issue-89118.rs:28:14 + | +LL | struct EthernetWorker(C) + | -------------- required by a bound in this +LL | where +LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EthernetWorker` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,8 +8,8 @@ LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } | |_____________________________________________- in this macro invocation | - = note: expected enum `Option fn(&'r u32, &'s u32) -> &'r u32>` - found enum `Option fn(&'r u32, &'r u32) -> &'r u32>` + = note: expected enum `Option fn(&'a u32, &'b u32) -> &'a u32>` + found enum `Option fn(&'a u32, &'a u32) -> &'a u32>` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ LL | | fn(&'x u32)) } | |______________- in this macro invocation | - = note: expected enum `Option fn(&'r u32)>` + = note: expected enum `Option fn(&'a u32)>` found enum `Option` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,8 +8,8 @@ LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } | |__________________________________- in this macro invocation | - = note: expected enum `Option fn(Inv<'r>, Inv<'s>)>` - found enum `Option fn(Inv<'r>, Inv<'r>)>` + = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` + found enum `Option fn(Inv<'a>, Inv<'a>)>` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types @@ -22,8 +22,8 @@ LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } | |__________________________________- in this macro invocation | - = note: expected enum `Option fn(Inv<'r>, Inv<'s>)>` - found enum `Option fn(Inv<'r>, Inv<'r>)>` + = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` + found enum `Option fn(Inv<'a>, Inv<'a>)>` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ | = note: expected enum `Option)>` found enum `Option)>` -note: the lifetime `'x` as defined on the function body at 38:20... +note: the lifetime `'x` as defined here... --> $DIR/hr-subtype.rs:38:20 | LL | fn subtype<'x, 'y: 'x, 'z: 'y>() { @@ -19,7 +19,7 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), LL | | fn(Inv<'y>)) } | |______________- in this macro invocation -note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:24 +note: ...does not necessarily outlive the lifetime `'y` as defined here --> $DIR/hr-subtype.rs:38:24 | LL | fn subtype<'x, 'y: 'x, 'z: 'y>() { @@ -42,7 +42,7 @@ | = note: expected enum `Option)>` found enum `Option)>` -note: the lifetime `'x` as defined on the function body at 44:22... +note: the lifetime `'x` as defined here... --> $DIR/hr-subtype.rs:44:22 | LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { @@ -51,7 +51,7 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), LL | | fn(Inv<'y>)) } | |______________- in this macro invocation -note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26 +note: ...does not necessarily outlive the lifetime `'y` as defined here --> $DIR/hr-subtype.rs:44:26 | LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ | = note: expected enum `Option` found enum `Option` -note: the lifetime `'x` as defined on the function body at 44:22... +note: the lifetime `'x` as defined here... --> $DIR/hr-subtype.rs:44:22 | LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { @@ -19,7 +19,7 @@ LL | / check! { free_x_vs_free_y: (fn(&'x u32), LL | | fn(&'y u32)) } | |______________- in this macro invocation -note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26 +note: ...does not necessarily outlive the lifetime `'y` as defined here --> $DIR/hr-subtype.rs:44:26 | LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,9 @@ --> $DIR/hrtb-debruijn-in-receiver.rs:17:5 | LL | foo.insert(); - | --- first mutable borrow occurs here + | ------------ first mutable borrow occurs here LL | foo.insert(); - | ^^^ + | ^^^^^^^^^^^^ | | | second mutable borrow occurs here | first borrow later used here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26 | LL | want_foo_for_any_tcx(f); - | ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` + | -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` + | | + | required by a bound introduced by this call | note: required by a bound in `want_foo_for_any_tcx` --> $DIR/hrtb-higher-ranker-supertraits.rs:22:15 @@ -20,7 +22,9 @@ --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26 | LL | want_bar_for_any_ccx(b); - | ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` + | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` + | | + | required by a bound introduced by this call | note: required by a bound in `want_bar_for_any_ccx` --> $DIR/hrtb-higher-ranker-supertraits.rs:39:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26 | LL | want_bar_for_any_ccx(b); - | ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` + | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` + | | + | required by a bound introduced by this call | note: required by a bound in `want_bar_for_any_ccx` --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -14,8 +14,6 @@ | -- lifetime `'a` defined here LL | want_hrtb::<&'a u32>() | ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:30:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -54,8 +54,6 @@ ... LL | foo_hrtb_bar_not(&mut t); | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` - | - = help: consider replacing `'b` with `'static` error: implementation of `Bar` is not general enough --> $DIR/hrtb-perfect-forwarding.rs:43:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/issue-88446.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/issue-88446.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hrtb/issue-88446.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hrtb/issue-88446.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,35 @@ +// check-pass + +trait Yokeable<'a> { + type Output: 'a; +} +impl<'a> Yokeable<'a> for () { + type Output = (); +} + +trait DataMarker<'data> { + type Yokeable: for<'a> Yokeable<'a>; +} +impl<'data> DataMarker<'data> for () { + type Yokeable = (); +} + +struct DataPayload<'data, M>(&'data M); + +impl DataPayload<'static, ()> { + pub fn map_project_with_capture( + _: for<'a> fn( + capture: T, + std::marker::PhantomData<&'a ()>, + ) -> >::Output, + ) -> DataPayload<'static, M2> + where + M2: DataMarker<'static>, + { + todo!() + } +} + +fn main() { + let _: DataPayload<()> = DataPayload::<()>::map_project_with_capture::<_, &()>(|_, _| todo!()); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/assoc_item_ctxt.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/assoc_item_ctxt.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/assoc_item_ctxt.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/assoc_item_ctxt.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,13 @@ --> $DIR/assoc_item_ctxt.rs:35:13 | LL | fn method() {} - | ^^^^^^^^^^^^^^ not a member of trait `Tr` + | ^^^------^^^^^ + | | | + | | help: there is an associated function with a similar name: `method` + | not a member of trait `Tr` ... LL | mac_trait_impl!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this error originates in the macro `mac_trait_impl` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -19,7 +22,7 @@ | ^^^^^^^^^^^^^^ missing `method` in implementation ... LL | mac_trait_impl!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this error originates in the macro `mac_trait_impl` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/duplicate_lifetimes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/duplicate_lifetimes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/duplicate_lifetimes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/duplicate_lifetimes.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ declared twice ... LL | m!('a); - | ------- + | ------ | | | | | previous declaration here | in this macro invocation @@ -19,7 +19,7 @@ | ^^ declared twice ... LL | n!('a); - | ------- + | ------ | | | | | previous declaration here | in this macro invocation diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -14,7 +14,7 @@ | ^^^^^^^ no `my_core` in the root ... LL | a!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -25,7 +25,7 @@ | ^^^^^^^ use of undeclared crate or module `my_core` ... LL | a!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/fields-definition.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/fields-definition.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/fields-definition.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/fields-definition.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^^^^^^ field already declared ... LL | legacy!(a); - | ----------- in this macro invocation + | ---------- in this macro invocation | = note: this error originates in the macro `legacy` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/fields-numeric-borrowck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/fields-numeric-borrowck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/fields-numeric-borrowck.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/fields-numeric-borrowck.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^^^^^^^^^^^^^^^ second mutable borrow occurs here ... LL | borrow1.use_mut(); - | ------- first borrow later used here + | ----------------- first borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/generate-mod.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/generate-mod.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/generate-mod.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/generate-mod.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ | ^^^^^^^^^^^ not found in this scope ... LL | genmod_transparent!(); - | ---------------------- in this macro invocation + | --------------------- in this macro invocation | = note: this error originates in the macro `genmod_transparent` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -28,7 +28,7 @@ | ^^^^^ not found in this scope ... LL | genmod_transparent!(); - | ---------------------- in this macro invocation + | --------------------- in this macro invocation | = note: this error originates in the macro `genmod_transparent` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -39,7 +39,7 @@ | ^^^^^^^^^^^ not found in this scope ... LL | genmod_legacy!(); - | ----------------- in this macro invocation + | ---------------- in this macro invocation | = note: this error originates in the macro `genmod_legacy` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -50,7 +50,7 @@ | ^^^^^ not found in this scope ... LL | genmod_legacy!(); - | ----------------- in this macro invocation + | ---------------- in this macro invocation | = note: this error originates in the macro `genmod_legacy` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/globs.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/globs.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/globs.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/globs.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | f(); | ^ not found in this scope | -help: consider importing one of these items +help: consider importing this function | LL | use foo::f; | @@ -32,12 +32,12 @@ --> $DIR/globs.rs:61:12 | LL | n!(f); - | ------ in this macro invocation + | ----- in this macro invocation ... LL | n!(f); | ^ not found in this scope | - = note: consider importing one of these items: + = note: consider importing this function: foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -45,12 +45,12 @@ --> $DIR/globs.rs:65:17 | LL | n!(f); - | ------ in this macro invocation + | ----- in this macro invocation ... LL | f | ^ not found in this scope | - = note: consider importing one of these items: + = note: consider importing this function: foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-label-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-label-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-label-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-label-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ undeclared label `'x` ... LL | 'x: loop { foo!(); } - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-label-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-label-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-label-3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-label-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ undeclared label `'x` ... LL | foo!(); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-labels-in-let.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-labels-in-let.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-labels-in-let.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-labels-in-let.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | -- first declared here LL | // this 'x should refer to the outer loop, lexically LL | loop_x!(break 'x); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -40,7 +40,7 @@ | -- first declared here ... LL | loop_x!(break 'x); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -54,7 +54,7 @@ | label `'x` already in scope ... LL | loop_x!(break 'x); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -68,7 +68,7 @@ | -- first declared here ... LL | loop_x!(break 'x); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -118,7 +118,7 @@ | -- first declared here ... LL | while_true!(break 'x); - | ---------------------- in this macro invocation + | --------------------- in this macro invocation | = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -132,7 +132,7 @@ | ^^ label `'x` already in scope ... LL | while_true!(break 'x); - | ---------------------- in this macro invocation + | --------------------- in this macro invocation | = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -146,7 +146,7 @@ | -- first declared here ... LL | while_true!(break 'x); - | ---------------------- in this macro invocation + | --------------------- in this macro invocation | = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -160,7 +160,7 @@ | ^^ label `'x` already in scope ... LL | while_true!(break 'x); - | ---------------------- in this macro invocation + | --------------------- in this macro invocation | = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -174,7 +174,7 @@ | -- first declared here ... LL | while_true!(break 'x); - | ---------------------- in this macro invocation + | --------------------- in this macro invocation | = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -242,7 +242,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -256,7 +256,7 @@ | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -270,7 +270,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -284,7 +284,7 @@ | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -298,7 +298,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -312,7 +312,7 @@ | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -326,7 +326,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-labels.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-labels.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-labels.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/hygienic-labels.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | -- first declared here LL | // this 'x should refer to the outer loop, lexically LL | loop_x!(break 'x); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -40,7 +40,7 @@ | -- first declared here ... LL | loop_x!(break 'x); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -54,7 +54,7 @@ | label `'x` already in scope ... LL | loop_x!(break 'x); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -68,7 +68,7 @@ | -- first declared here ... LL | loop_x!(break 'x); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -118,7 +118,7 @@ | -- first declared here ... LL | while_x!(break 'x); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -132,7 +132,7 @@ | ^^ label `'x` already in scope ... LL | while_x!(break 'x); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -146,7 +146,7 @@ | -- first declared here ... LL | while_x!(break 'x); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -160,7 +160,7 @@ | ^^ label `'x` already in scope ... LL | while_x!(break 'x); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -174,7 +174,7 @@ | -- first declared here ... LL | while_x!(break 'x); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -242,7 +242,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -256,7 +256,7 @@ | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -270,7 +270,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -284,7 +284,7 @@ | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -298,7 +298,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -312,7 +312,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -326,7 +326,7 @@ | -- first declared here ... LL | run_once!(continue 'x); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/impl_items.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/impl_items.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/impl_items.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/impl_items.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ private type ... LL | foo::m!(); - | ---------- in this macro invocation + | --------- in this macro invocation | = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/missing-self-diag.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/missing-self-diag.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/missing-self-diag.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/missing-self-diag.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ ... LL | / pub fn foo(&self) { LL | | call_bar!(); - | | ------------ in this macro invocation + | | ----------- in this macro invocation LL | | } | |_____- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/no_implicit_prelude.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/no_implicit_prelude.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/no_implicit_prelude.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/no_implicit_prelude.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/no_implicit_prelude.rs:11:9 | LL | fn f() { ::bar::m!(); } - | ------------ in this macro invocation + | ----------- in this macro invocation ... LL | Vec::new(); | ^^^ not found in this scope @@ -17,15 +17,17 @@ --> $DIR/no_implicit_prelude.rs:12:12 | LL | fn f() { ::bar::m!(); } - | ------------ in this macro invocation + | ----------- in this macro invocation ... LL | ().clone() | ^^^^^ method not found in `()` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope; perhaps add a `use` for it: - `use std::clone::Clone;` = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use std::clone::Clone; + | error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/privacy-early.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/privacy-early.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/privacy-early.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/privacy-early.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^ ... LL | foo::m!(); - | ---------- in this macro invocation + | --------- in this macro invocation | note: consider marking `f` as `pub` in the imported module --> $DIR/privacy-early.rs:10:13 @@ -14,7 +14,7 @@ | ^^^^^^ ... LL | foo::m!(); - | ---------- in this macro invocation + | --------- in this macro invocation = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/trait_items.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/trait_items.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/hygiene/trait_items.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/hygiene/trait_items.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,15 +5,17 @@ | - the method is available for `()` here ... LL | fn f() { ::baz::m!(); } - | ------------ in this macro invocation + | ----------- in this macro invocation ... LL | pub macro m() { ().f() } | ^ method not found in `()` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope; perhaps add a `use` for it: - `use foo::T;` = note: this error originates in the macro `::baz::m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use foo::T; + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,11 +2,14 @@ --> $DIR/dyn-trait.rs:20:5 | LL | fn with_dyn_debug_static<'a>(x: Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | static_val(x); - | ^^^^^^^^^^^^^ `x` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/auto-trait-leak.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/auto-trait-leak.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/auto-trait-leak.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/auto-trait-leak.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -34,7 +34,7 @@ | LL | send(cycle2().clone()); | ^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... note: ...which requires computing type of `cycle2::{opaque#0}`... --> $DIR/auto-trait-leak.rs:19:16 | @@ -70,7 +70,7 @@ | LL | send(cycle1().clone()); | ^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/hidden-lifetimes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/hidden-lifetimes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/hidden-lifetimes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/hidden-lifetimes.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,25 +2,27 @@ --> $DIR/hidden-lifetimes.rs:28:54 | LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { - | ^^^^^^^^^^^^^^ + | -- ^^^^^^^^^^^^^^ + | | + | hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here | -note: hidden type `&'a mut &'b T` captures the lifetime `'b` as defined on the function body at 28:17 - --> $DIR/hidden-lifetimes.rs:28:17 +help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound | -LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { - | ^^ +LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b { + | ++++ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/hidden-lifetimes.rs:45:70 | LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { - | ^^^^^^^^^^^^^^ + | -- ^^^^^^^^^^^^^^ + | | + | hidden type `Rc>` captures the lifetime `'b` as defined here | -note: hidden type `Rc>` captures the lifetime `'b` as defined on the function body at 45:24 - --> $DIR/hidden-lifetimes.rs:45:24 +help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound | -LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { - | ^^ +LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a + 'b { + | ++++ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,3 @@ -// compile-flags:-Zborrowck=mir - -#![feature(member_constraints)] #![feature(type_alias_impl_trait)] #[derive(Clone)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,10 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/error-handling-2.rs:13:60 + --> $DIR/error-handling-2.rs:10:60 | LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { - | ^^^^^^^^^ - | -note: hidden type `*mut &'a i32` captures the lifetime `'a` as defined on the function body at 13:8 - --> $DIR/error-handling-2.rs:13:8 - | -LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { - | ^^ + | -- ^^^^^^^^^ + | | + | hidden type `*mut &'a i32` captures the lifetime `'a` as defined here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -// compile-flags:-Zborrowck=mir - #![feature(type_alias_impl_trait)] #[derive(Clone)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/error-handling.rs:22:16 + --> $DIR/error-handling.rs:20:16 | LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { | -- -- lifetime `'b` defined here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,14 @@ --> $DIR/ordinary-bounds-unrelated.rs:16:74 | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> - | ^^^^^^^^^^^^^^^^^^ + | -- ^^^^^^^^^^^^^^^^^^ + | | + | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here | - = note: hidden type `Ordinary<'_>` captures lifetime '_#9r +help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound + | +LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b + | ++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,14 @@ --> $DIR/ordinary-bounds-unsuited.rs:18:62 | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> - | ^^^^^^^^^^^^^^^^^^ + | -- ^^^^^^^^^^^^^^^^^^ + | | + | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here | - = note: hidden type `Ordinary<'_>` captures lifetime '_#6r +help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound + | +LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b + | ++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -19,7 +19,6 @@ | | | lifetime `'a` defined here | - = help: consider replacing `'a` with `'static` help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } @@ -42,7 +41,6 @@ | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` | = help: consider replacing `'a` with `'static` - = help: consider replacing `'a` with `'static` error[E0621]: explicit lifetime required in the type of `x` --> $DIR/must_outlive_least_region_or_bound.rs:11:41 @@ -67,7 +65,6 @@ | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` | = help: consider replacing `'a` with `'static` - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:32:61 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/region-escape-via-bound.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/region-escape-via-bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/region-escape-via-bound.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/region-escape-via-bound.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -3,12 +3,14 @@ | LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> | ^^^^^^^^^^^^^^ +LL | +LL | where 'x: 'y + | -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here | -note: hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined on the function body at 17:7 - --> $DIR/region-escape-via-bound.rs:17:7 +help: to declare that the `impl Trait` captures 'x, you can add an explicit `'x` lifetime bound | -LL | where 'x: 'y - | ^^ +LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> + 'x + | ++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -19,7 +19,6 @@ | | | lifetime `'a` defined here | - = help: consider replacing `'a` with `'static` help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +trait Foo { + type T; + fn foo(&self, t: Self::T); +//~^ NOTE expected 0 type parameters +} + +impl Foo for u32 { + type T = (); + + fn foo(&self, t: impl Clone) {} +//~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters +//~| NOTE found 1 type parameter +//~| NOTE `impl Trait` introduces an implicit type parameter +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/impl-trait/type-arg-mismatch-due-to-impl-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22 + | +LL | fn foo(&self, t: Self::T); + | - expected 0 type parameters +... +LL | fn foo(&self, t: impl Clone) {} + | ^^^^^^^^^^ + | | + | found 1 type parameter + | `impl Trait` introduces an implicit type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | define_std_as_non_existent!(); - | ------------------------------ in this macro invocation + | ----------------------------- in this macro invocation | = note: this error originates in the macro `define_std_as_non_existent` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | define_other_core!(); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -22,7 +22,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | define_vec!(); - | -------------- in this macro invocation + | ------------- in this macro invocation note: `Vec` could also refer to the struct defined here --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/glob-resolve1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/glob-resolve1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/glob-resolve1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/glob-resolve1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,10 +4,11 @@ LL | fpriv(); | ^^^^^ not found in this scope | -help: consider importing this function - | -LL | use bar::fpriv; +note: function `bar::fpriv` exists but is inaccessible + --> $DIR/glob-resolve1.rs:7:5 | +LL | fn fpriv() {} + | ^^^^^^^^^^ not accessible error[E0425]: cannot find function `epriv` in this scope --> $DIR/glob-resolve1.rs:27:5 @@ -15,10 +16,11 @@ LL | epriv(); | ^^^^^ not found in this scope | -help: consider importing this function - | -LL | use bar::epriv; +note: function `bar::epriv` exists but is inaccessible + --> $DIR/glob-resolve1.rs:9:9 | +LL | fn epriv(); + | ^^^^^^^^^^^ not accessible error[E0423]: expected value, found enum `B` --> $DIR/glob-resolve1.rs:28:5 @@ -44,10 +46,11 @@ LL | C; | ^ not found in this scope | -help: consider importing this unit struct - | -LL | use bar::C; +note: unit struct `bar::C` exists but is inaccessible + --> $DIR/glob-resolve1.rs:18:5 | +LL | struct C; + | ^^^^^^^^^ not accessible error[E0425]: cannot find function `import` in this scope --> $DIR/glob-resolve1.rs:30:5 @@ -67,16 +70,13 @@ | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists + | ^ help: an enum with a similar name exists: `B` | -LL | foo::(); - | ~ -help: consider importing this enum - | -LL | use bar::A; +note: enum `bar::A` exists but is inaccessible + --> $DIR/glob-resolve1.rs:11:5 | +LL | enum A { + | ^^^^^^ not accessible error[E0412]: cannot find type `C` in this scope --> $DIR/glob-resolve1.rs:33:11 @@ -85,16 +85,13 @@ | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists - | -LL | foo::(); - | ~ -help: consider importing this struct + | ^ help: an enum with a similar name exists: `B` | -LL | use bar::C; +note: struct `bar::C` exists but is inaccessible + --> $DIR/glob-resolve1.rs:18:5 | +LL | struct C; + | ^^^^^^^^^ not accessible error[E0412]: cannot find type `D` in this scope --> $DIR/glob-resolve1.rs:34:11 @@ -103,16 +100,13 @@ | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists - | -LL | foo::(); - | ~ -help: consider importing this type alias + | ^ help: an enum with a similar name exists: `B` | -LL | use bar::D; +note: type alias `bar::D` exists but is inaccessible + --> $DIR/glob-resolve1.rs:20:5 | +LL | type D = isize; + | ^^^^^^^^^^^^^^^ not accessible error: aborting due to 8 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/import-crate-var.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/import-crate-var.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/import-crate-var.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/import-crate-var.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/import-crate-var.rs:6:5 | LL | m!(); - | ^^^^^ + | ^^^^ | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/issue-30560.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/issue-30560.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/issue-30560.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/issue-30560.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: items in traits are not importable. +error: items in traits are not importable --> $DIR/issue-30560.rs:7:5 | LL | use T::*; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/issue-4366-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/issue-4366-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/issue-4366-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/issue-4366-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,10 +4,11 @@ LL | fn sub() -> Bar { 1 } | ^^^ not found in this scope | -help: consider importing this type alias - | -LL | use a::b::Bar; +note: type alias `a::b::Bar` exists but is inaccessible + --> $DIR/issue-4366-2.rs:11:9 | +LL | type Bar = isize; + | ^^^^^^^^^^^^^^^^^ not accessible error[E0423]: expected function, found module `foo` --> $DIR/issue-4366-2.rs:25:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/local-modularized-tricky-fail-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/local-modularized-tricky-fail-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/local-modularized-tricky-fail-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/local-modularized-tricky-fail-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ | |_____^ ... LL | define_exported!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation note: `exported` could also refer to the macro imported here --> $DIR/local-modularized-tricky-fail-1.rs:22:5 | @@ -37,7 +37,7 @@ | |_____^ ... LL | define_exported!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation note: `exported` could also refer to the macro imported here --> $DIR/local-modularized-tricky-fail-1.rs:22:5 | @@ -62,7 +62,7 @@ | |_____^ ... LL | define_panic!(); - | ---------------- in this macro invocation + | --------------- in this macro invocation = help: use `crate::panic` to refer to this macro unambiguously = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -82,7 +82,7 @@ | |_____^ ... LL | define_include!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation = help: use `crate::include` to refer to this macro unambiguously = note: this error originates in the macro `define_include` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/local-modularized-tricky-fail-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/local-modularized-tricky-fail-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/local-modularized-tricky-fail-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/local-modularized-tricky-fail-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,7 @@ | |_____^ ... LL | define_exported!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths @@ -36,7 +36,7 @@ | |_____^ ... LL | define_exported!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/shadow_builtin_macros.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/shadow_builtin_macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/imports/shadow_builtin_macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/imports/shadow_builtin_macros.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -27,7 +27,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | } } LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `n` is ambiguous (glob import vs any other name from outer scope during import/macro resolution) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -35,7 +35,7 @@ | ^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` ... LL | autowrapper!(Autowrapped, autowrap_gift, 'a); - | --------------------------------------------- in this macro invocation + | -------------------------------------------- in this macro invocation | = note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/indexing-requires-a-uint.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/indexing-requires-a-uint.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/indexing-requires-a-uint.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/indexing-requires-a-uint.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,7 @@ help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | bar::(i.try_into().unwrap()); // i should not be re-coerced back to an isize - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/inference/deref-suggestion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/inference/deref-suggestion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/inference/deref-suggestion.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/inference/deref-suggestion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -56,7 +56,7 @@ --> $DIR/deref-suggestion.rs:36:5 | LL | assert_eq!(3i32, &3i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&i32` + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&i32` | = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/inference/issue-71309.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/inference/issue-71309.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/inference/issue-71309.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/inference/issue-71309.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +fn foo(x: Result) -> Result<(), ()> { + let y: u32 = x?; + //~^ ERROR: `?` operator has incompatible types + Ok(()) +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/inference/issue-71309.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/inference/issue-71309.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/inference/issue-71309.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/inference/issue-71309.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0308]: `?` operator has incompatible types + --> $DIR/issue-71309.rs:2:18 + | +LL | let y: u32 = x?; + | ^^ expected `u32`, found `i32` + | + = note: `?` operator cannot convert from `i32` to `u32` +help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit + | +LL | let y: u32 = x?.try_into().unwrap(); + | ++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/infinite/infinite-autoderef.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/infinite/infinite-autoderef.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/infinite/infinite-autoderef.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/infinite/infinite-autoderef.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // error-pattern: reached the recursion limit while auto-dereferencing -#![feature(box_syntax)] + use std::ops::Deref; @@ -17,7 +17,7 @@ pub fn main() { let mut x; loop { - x = box x; + x = Box::new(x); x.foo; x.bar(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/infinite/infinite-autoderef.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/infinite/infinite-autoderef.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/infinite/infinite-autoderef.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/infinite/infinite-autoderef.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,10 @@ error[E0308]: mismatched types --> $DIR/infinite-autoderef.rs:20:13 | -LL | x = box x; - | ^^^^^ cyclic type of infinite size - | -help: try using a conversion method - | -LL | x = (box x).to_string(); - | + +++++++++++++ +LL | x = Box::new(x); + | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | cyclic type of infinite size error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:5 @@ -15,7 +12,7 @@ LL | Foo.foo; | ^^^^^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -23,7 +20,7 @@ LL | Foo.foo; | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) error[E0609]: no field `foo` on type `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -37,7 +34,7 @@ LL | Foo.bar(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) error[E0599]: no method named `bar` found for struct `Foo` in the current scope --> $DIR/infinite-autoderef.rs:26:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/infinite/infinite-macro-expansion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/infinite/infinite-macro-expansion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/infinite/infinite-macro-expansion.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/infinite/infinite-macro-expansion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | recursive!() | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_macro_expansion`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_macro_expansion`) = note: this error originates in the macro `recursive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/inherent-impls-overlap-check/no-overlap.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/inherent-impls-overlap-check/no-overlap.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/inherent-impls-overlap-check/no-overlap.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/inherent-impls-overlap-check/no-overlap.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,4 +31,23 @@ impl Bar { fn foo() {} } impl Bar { fn foo() {} } +// Regression test for issue #89820: + +impl Bar { + pub fn a() {} + pub fn aa() {} +} + +impl Bar { + pub fn b() {} + pub fn bb() {} +} + +impl Bar { + pub fn a() {} + pub fn aa() {} + pub fn bb() {} + pub fn b() {} +} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/init-res-into-things.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/init-res-into-things.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/init-res-into-things.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/init-res-into-things.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -#![feature(box_syntax)] use std::cell::Cell; @@ -58,7 +57,7 @@ fn test_unique() { let i = &Cell::new(0); { - let _a: Box<_> = box r(i); + let _a: Box<_> = Box::new(r(i)); } assert_eq!(i.get(), 1); } @@ -66,9 +65,9 @@ fn test_unique_rec() { let i = &Cell::new(0); { - let _a: Box<_> = box BoxR { + let _a: Box<_> = Box::new(BoxR { x: r(i) - }; + }); } assert_eq!(i.get(), 1); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/integer-literal-suffix-inference.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/integer-literal-suffix-inference.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/integer-literal-suffix-inference.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/integer-literal-suffix-inference.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:41:11 @@ -18,7 +18,7 @@ help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:44:11 @@ -29,7 +29,7 @@ help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:47:11 @@ -40,16 +40,18 @@ help: you can convert an `isize` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(asize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:51:12 | LL | id_i16(a8); - | ^^ - | | - | expected `i16`, found `i8` - | help: you can convert an `i8` to an `i16`: `a8.into()` + | ^^ expected `i16`, found `i8` + | +help: you can convert an `i8` to an `i16` + | +LL | id_i16(a8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:55:12 @@ -60,7 +62,7 @@ help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(a32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:58:12 @@ -71,7 +73,7 @@ help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(a64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:61:12 @@ -82,25 +84,29 @@ help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(asize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:65:12 | LL | id_i32(a8); - | ^^ - | | - | expected `i32`, found `i8` - | help: you can convert an `i8` to an `i32`: `a8.into()` + | ^^ expected `i32`, found `i8` + | +help: you can convert an `i8` to an `i32` + | +LL | id_i32(a8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:68:12 | LL | id_i32(a16); - | ^^^ - | | - | expected `i32`, found `i16` - | help: you can convert an `i16` to an `i32`: `a16.into()` + | ^^^ expected `i32`, found `i16` + | +help: you can convert an `i16` to an `i32` + | +LL | id_i32(a16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:72:12 @@ -111,7 +117,7 @@ help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(a64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:75:12 @@ -122,34 +128,40 @@ help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(asize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:79:12 | LL | id_i64(a8); - | ^^ - | | - | expected `i64`, found `i8` - | help: you can convert an `i8` to an `i64`: `a8.into()` + | ^^ expected `i64`, found `i8` + | +help: you can convert an `i8` to an `i64` + | +LL | id_i64(a8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:82:12 | LL | id_i64(a16); - | ^^^ - | | - | expected `i64`, found `i16` - | help: you can convert an `i16` to an `i64`: `a16.into()` + | ^^^ expected `i64`, found `i16` + | +help: you can convert an `i16` to an `i64` + | +LL | id_i64(a16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:85:12 | LL | id_i64(a32); - | ^^^ - | | - | expected `i64`, found `i32` - | help: you can convert an `i32` to an `i64`: `a32.into()` + | ^^^ expected `i64`, found `i32` + | +help: you can convert an `i32` to an `i64` + | +LL | id_i64(a32.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:89:12 @@ -160,25 +172,29 @@ help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | id_i64(asize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:93:14 | LL | id_isize(a8); - | ^^ - | | - | expected `isize`, found `i8` - | help: you can convert an `i8` to an `isize`: `a8.into()` + | ^^ expected `isize`, found `i8` + | +help: you can convert an `i8` to an `isize` + | +LL | id_isize(a8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:96:14 | LL | id_isize(a16); - | ^^^ - | | - | expected `isize`, found `i16` - | help: you can convert an `i16` to an `isize`: `a16.into()` + | ^^^ expected `isize`, found `i16` + | +help: you can convert an `i16` to an `isize` + | +LL | id_isize(a16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:99:14 @@ -189,7 +205,7 @@ help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | id_isize(a32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:102:14 @@ -200,7 +216,7 @@ help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | id_isize(a64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:108:11 @@ -211,7 +227,7 @@ help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:111:11 @@ -222,7 +238,7 @@ help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:114:11 @@ -233,16 +249,18 @@ help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:118:12 | LL | id_i16(c8); - | ^^ - | | - | expected `i16`, found `i8` - | help: you can convert an `i8` to an `i16`: `c8.into()` + | ^^ expected `i16`, found `i8` + | +help: you can convert an `i8` to an `i16` + | +LL | id_i16(c8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:122:12 @@ -253,7 +271,7 @@ help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(c32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:125:12 @@ -264,25 +282,29 @@ help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(c64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:129:12 | LL | id_i32(c8); - | ^^ - | | - | expected `i32`, found `i8` - | help: you can convert an `i8` to an `i32`: `c8.into()` + | ^^ expected `i32`, found `i8` + | +help: you can convert an `i8` to an `i32` + | +LL | id_i32(c8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:132:12 | LL | id_i32(c16); - | ^^^ - | | - | expected `i32`, found `i16` - | help: you can convert an `i16` to an `i32`: `c16.into()` + | ^^^ expected `i32`, found `i16` + | +help: you can convert an `i16` to an `i32` + | +LL | id_i32(c16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:136:12 @@ -293,34 +315,40 @@ help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(c64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:140:12 | LL | id_i64(a8); - | ^^ - | | - | expected `i64`, found `i8` - | help: you can convert an `i8` to an `i64`: `a8.into()` + | ^^ expected `i64`, found `i8` + | +help: you can convert an `i8` to an `i64` + | +LL | id_i64(a8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:143:12 | LL | id_i64(a16); - | ^^^ - | | - | expected `i64`, found `i16` - | help: you can convert an `i16` to an `i64`: `a16.into()` + | ^^^ expected `i64`, found `i16` + | +help: you can convert an `i16` to an `i64` + | +LL | id_i64(a16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:146:12 | LL | id_i64(a32); - | ^^^ - | | - | expected `i64`, found `i32` - | help: you can convert an `i32` to an `i64`: `a32.into()` + | ^^^ expected `i64`, found `i32` + | +help: you can convert an `i32` to an `i64` + | +LL | id_i64(a32.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:152:11 @@ -331,7 +359,7 @@ help: you can convert a `u16` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:155:11 @@ -342,7 +370,7 @@ help: you can convert a `u32` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:158:11 @@ -353,7 +381,7 @@ help: you can convert a `u64` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:161:11 @@ -364,16 +392,18 @@ help: you can convert a `usize` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(bsize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:165:12 | LL | id_u16(b8); - | ^^ - | | - | expected `u16`, found `u8` - | help: you can convert a `u8` to a `u16`: `b8.into()` + | ^^ expected `u16`, found `u8` + | +help: you can convert a `u8` to a `u16` + | +LL | id_u16(b8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:169:12 @@ -384,7 +414,7 @@ help: you can convert a `u32` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(b32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:172:12 @@ -395,7 +425,7 @@ help: you can convert a `u64` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(b64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:175:12 @@ -406,25 +436,29 @@ help: you can convert a `usize` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(bsize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:179:12 | LL | id_u32(b8); - | ^^ - | | - | expected `u32`, found `u8` - | help: you can convert a `u8` to a `u32`: `b8.into()` + | ^^ expected `u32`, found `u8` + | +help: you can convert a `u8` to a `u32` + | +LL | id_u32(b8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:182:12 | LL | id_u32(b16); - | ^^^ - | | - | expected `u32`, found `u16` - | help: you can convert a `u16` to a `u32`: `b16.into()` + | ^^^ expected `u32`, found `u16` + | +help: you can convert a `u16` to a `u32` + | +LL | id_u32(b16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:186:12 @@ -435,7 +469,7 @@ help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit | LL | id_u32(b64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:189:12 @@ -446,34 +480,40 @@ help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | id_u32(bsize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:193:12 | LL | id_u64(b8); - | ^^ - | | - | expected `u64`, found `u8` - | help: you can convert a `u8` to a `u64`: `b8.into()` + | ^^ expected `u64`, found `u8` + | +help: you can convert a `u8` to a `u64` + | +LL | id_u64(b8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:196:12 | LL | id_u64(b16); - | ^^^ - | | - | expected `u64`, found `u16` - | help: you can convert a `u16` to a `u64`: `b16.into()` + | ^^^ expected `u64`, found `u16` + | +help: you can convert a `u16` to a `u64` + | +LL | id_u64(b16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:199:12 | LL | id_u64(b32); - | ^^^ - | | - | expected `u64`, found `u32` - | help: you can convert a `u32` to a `u64`: `b32.into()` + | ^^^ expected `u64`, found `u32` + | +help: you can convert a `u32` to a `u64` + | +LL | id_u64(b32.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:203:12 @@ -484,25 +524,29 @@ help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | id_u64(bsize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:207:14 | LL | id_usize(b8); - | ^^ - | | - | expected `usize`, found `u8` - | help: you can convert a `u8` to a `usize`: `b8.into()` + | ^^ expected `usize`, found `u8` + | +help: you can convert a `u8` to a `usize` + | +LL | id_usize(b8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:210:14 | LL | id_usize(b16); - | ^^^ - | | - | expected `usize`, found `u16` - | help: you can convert a `u16` to a `usize`: `b16.into()` + | ^^^ expected `usize`, found `u16` + | +help: you can convert a `u16` to a `usize` + | +LL | id_usize(b16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:213:14 @@ -513,7 +557,7 @@ help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | id_usize(b32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:216:14 @@ -524,7 +568,7 @@ help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | id_usize(b64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to 52 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/internal/internal-unstable-noallow.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/internal/internal-unstable-noallow.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/internal/internal-unstable-noallow.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/internal/internal-unstable-noallow.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/internal-unstable-noallow.rs:16:5 | LL | call_unstable_noallow!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(function)]` to the crate attributes to enable = note: this error originates in the macro `call_unstable_noallow` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -11,7 +11,7 @@ --> $DIR/internal-unstable-noallow.rs:18:5 | LL | construct_unstable_noallow!(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(struct_field)]` to the crate attributes to enable = note: this error originates in the macro `construct_unstable_noallow` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/internal/internal-unstable.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/internal/internal-unstable.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/internal/internal-unstable.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/internal/internal-unstable.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -37,7 +37,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | bar!(internal_unstable::unstable()); - | ------------------------------------ in this macro invocation + | ----------------------------------- in this macro invocation | = help: add `#![feature(function)]` to the crate attributes to enable = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-bad.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-bad.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-bad.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-bad.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,36 @@ +#![feature(const_eval_select)] + +use std::intrinsics::const_eval_select; + +const fn not_fn_items() { + const_eval_select((), || {}, || {}); + //~^ ERROR expected a `FnOnce<()>` closure + const_eval_select((), 42, 0xDEADBEEF); + //~^ ERROR expected a `FnOnce<()>` closure +} + +const fn foo(n: i32) -> i32 { + n +} + +fn bar(n: i32) -> bool { + assert_eq!(n, 0, "{} must be equal to {}", n, 0); + n == 0 +} + +fn baz(n: bool) -> i32 { + assert!(n, "{} must be true", n); + n as i32 +} + +const fn return_ty_mismatch() { + const_eval_select((1,), foo, bar); + //~^ ERROR type mismatch +} + +const fn args_ty_mismatch() { + const_eval_select((true,), foo, baz); + //~^ ERROR type mismatch +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-bad.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-bad.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-bad.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-bad.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,65 @@ +error[E0277]: expected a `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` + --> $DIR/const-eval-select-bad.rs:6:34 + | +LL | const_eval_select((), || {}, || {}); + | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` + = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `const_eval_select` + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | F: ~const FnOnce, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` + +error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` + --> $DIR/const-eval-select-bad.rs:8:31 + | +LL | const_eval_select((), 42, 0xDEADBEEF); + | ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<()>` is not implemented for `{integer}` + = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `const_eval_select` + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | F: ~const FnOnce, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` + +error[E0271]: type mismatch resolving ` bool {bar} as FnOnce<(i32,)>>::Output == i32` + --> $DIR/const-eval-select-bad.rs:27:5 + | +LL | const_eval_select((1,), foo, bar); + | ^^^^^^^^^^^^^^^^^ expected `i32`, found `bool` + | +note: required by a bound in `const_eval_select` + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | G: FnOnce + ~const Drop, + | ^^^^^^^^^^^^ required by this bound in `const_eval_select` + +error[E0631]: type mismatch in function arguments + --> $DIR/const-eval-select-bad.rs:32:37 + | +LL | const fn foo(n: i32) -> i32 { + | --------------------------- found signature of `fn(i32) -> _` +... +LL | const_eval_select((true,), foo, baz); + | ----------------- ^^^ expected signature of `fn(bool) -> _` + | | + | required by a bound introduced by this call + | +note: required by a bound in `const_eval_select` + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | F: ~const FnOnce, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0271, E0277, E0631. +For more information about an error, try `rustc --explain E0271`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +// run-pass + +#![feature(const_eval_select)] + +use std::intrinsics::const_eval_select; + +const fn yes() -> bool { + true +} + +fn no() -> bool { + false +} + +// not a sound use case; testing only +const fn is_const_eval() -> bool { + unsafe { const_eval_select((), yes, no) } +} + +fn main() { + const YES: bool = is_const_eval(); + let no = is_const_eval(); + + assert_eq!(true, YES); + assert_eq!(false, no); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-stability.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-stability.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-stability.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-stability.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +#![feature(staged_api)] +#![feature(const_eval_select)] +#![stable(since = "1.0", feature = "ui_test")] + +use std::intrinsics::const_eval_select; + +fn log() { + println!("HEY HEY HEY") +} + +const fn nothing(){} + +#[stable(since = "1.0", feature = "hey")] +#[rustc_const_stable(since = "1.0", feature = "const_hey")] +pub const unsafe fn hey() { + const_eval_select((), nothing, log); + //~^ ERROR `const_eval_select` is not yet stable as a const fn +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-stability.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-stability.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-stability.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-stability.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: `const_eval_select` is not yet stable as a const fn + --> $DIR/const-eval-select-stability.rs:16:5 + | +LL | const_eval_select((), nothing, log); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-x86_64.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-x86_64.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-x86_64.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/const-eval-select-x86_64.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +// run-pass +// only-x86_64 + +#![feature(const_eval_select)] +use std::intrinsics::const_eval_select; +use std::arch::x86_64::*; +use std::mem::transmute; + +const fn eq_ct(x: [i32; 4], y: [i32; 4]) -> bool { + x[0] == y[0] && x[1] == y[1] && x[2] == y[2] && x[3] == y[3] +} + +fn eq_rt(x: [i32; 4], y: [i32; 4]) -> bool { + unsafe { + let x = _mm_loadu_si128(&x as *const _ as *const _); + let y = _mm_loadu_si128(&y as *const _ as *const _); + let r = _mm_cmpeq_epi32(x, y); + let r = _mm_movemask_ps(transmute(r) ); + r == 0b1111 + } +} + +const fn eq(x: [i32; 4], y: [i32; 4]) -> bool { + unsafe { + const_eval_select((x, y), eq_ct, eq_rt) + } +} + +fn main() { + const X: bool = eq([0, 1, 2, 3], [0, 1, 2, 3]); + assert_eq!(X, true); + let x = eq([0, 1, 2, 3], [0, 1, 2, 3]); + assert_eq!(x, true); + + const Y: bool = eq([0, 1, 2, 3], [0, 1, 3, 2]); + assert_eq!(Y, false); + let y = eq([0, 1, 2, 3], [0, 1, 3, 2]); + assert_eq!(y, false); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/intrinsic-atomics.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/intrinsic-atomics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/intrinsic-atomics.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/intrinsic-atomics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] #![feature(intrinsics)] mod rusti { @@ -34,7 +33,7 @@ pub fn main() { unsafe { - let mut x: Box<_> = box 1; + let mut x: Box<_> = Box::new(1); assert_eq!(rusti::atomic_load(&*x), 1); *x = 5; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,6 +2,7 @@ // ignore-wasm32-bare compiled with panic=abort by default // revisions: mir thir // [thir]compile-flags: -Zthir-unsafeck +// ignore-tidy-linelength // This test checks panic emitted from `mem::{uninitialized,zeroed}`. @@ -114,11 +115,11 @@ test_panic_msg( || mem::uninitialized::<*const dyn Send>(), - "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid" + "attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid" ); test_panic_msg( || mem::zeroed::<*const dyn Send>(), - "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid" + "attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid" ); /* FIXME(#66151) we conservatively do not error here yet. @@ -145,12 +146,12 @@ test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), - "attempted to leave type `(std::ptr::NonNull, u32, u32)` uninitialized, \ + "attempted to leave type `(core::ptr::non_null::NonNull, u32, u32)` uninitialized, \ which is invalid" ); test_panic_msg( || mem::zeroed::<(NonNull, u32, u32)>(), - "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ + "attempted to zero-initialize type `(core::ptr::non_null::NonNull, u32, u32)`, \ which is invalid" ); @@ -187,7 +188,7 @@ ); test_panic_msg( || mem::uninitialized::>(), - "attempted to leave type `std::mem::ManuallyDrop` uninitialized, which is invalid" + "attempted to leave type `core::mem::manually_drop::ManuallyDrop` uninitialized, which is invalid" ); // Some things that should work. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/invalid/invalid-crate-type-macro.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/invalid/invalid-crate-type-macro.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/invalid/invalid-crate-type-macro.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/invalid/invalid-crate-type-macro.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +#![crate_type = foo!()] //~ ERROR malformed `crate_type` attribute + +macro_rules! foo { + () => {"rlib"}; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/invalid/invalid-crate-type-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/invalid/invalid-crate-type-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/invalid/invalid-crate-type-macro.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/invalid/invalid-crate-type-macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: malformed `crate_type` attribute input + --> $DIR/invalid-crate-type-macro.rs:1:1 + | +LL | #![crate_type = foo!()] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/invalid_crate_type_syntax.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/invalid_crate_type_syntax.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/invalid_crate_type_syntax.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/invalid_crate_type_syntax.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/invalid_crate_type_syntax.rs:2:1 | LL | #![crate_type(lib)] - | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]` + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issue-72470-llvm-dominate.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issue-72470-llvm-dominate.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issue-72470-llvm-dominate.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issue-72470-llvm-dominate.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -// compile-flags: -C opt-level=3 -// aux-build: issue-72470-lib.rs -// edition:2018 -// build-pass - -// Regression test for issue #72470, using the minimization -// in https://github.com/jonas-schievink/llvm-error - -extern crate issue_72470_lib; - -use std::future::Future; -use std::pin::Pin; -use std::sync::Mutex; -use std::task::Poll::{Pending, Ready}; - -#[allow(dead_code)] -enum Msg { - A(Vec<()>), - B, -} - -#[allow(dead_code)] -enum Out { - _0(Option), - Disabled, -} - -#[allow(unused_must_use)] -fn main() { - let mut rx = issue_72470_lib::unbounded_channel::(); - let entity = Mutex::new(()); - issue_72470_lib::run(async move { - { - let output = { - let mut fut = rx.recv(); - issue_72470_lib::poll_fn(|cx| { - loop { - let fut = unsafe { Pin::new_unchecked(&mut fut) }; - let out = match fut.poll(cx) { - Ready(out) => out, - Pending => { - break; - } - }; - #[allow(unused_variables)] - match &out { - Some(_msg) => {} - _ => break, - } - return Ready(Out::_0(out)); - } - Ready(Out::_0(None)) - }) - .await - }; - match output { - Out::_0(Some(_msg)) => { - entity.lock(); - } - Out::_0(None) => unreachable!(), - _ => unreachable!(), - } - } - entity.lock(); - }); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-10291.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-10291.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-10291.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-10291.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ LL | drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { LL | x | ^ returning this value requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-10291.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-10291.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-10291.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-10291.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | x | ^ | -note: ...the reference is valid for the anonymous lifetime #1 defined on the body at 2:69... +note: ...the reference is valid for the anonymous lifetime #1 defined here... --> $DIR/issue-10291.rs:2:69 | LL | drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { @@ -12,7 +12,7 @@ LL | | x LL | | })); | |_____^ -note: ...but the borrowed content is only valid for the lifetime `'x` as defined on the function body at 1:9 +note: ...but the borrowed content is only valid for the lifetime `'x` as defined here --> $DIR/issue-10291.rs:1:9 | LL | fn test<'x>(x: &'x isize) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-10465.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-10465.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-10465.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-10465.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,10 @@ | ^^^ method not found in `&B` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope; perhaps add a `use` for it: - `use a::A;` +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use a::A; + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-13359.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-13359.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-13359.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-13359.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | foo((1*(1 as isize)).try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | + +++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/issue-13359.rs:10:9 @@ -18,7 +18,7 @@ help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | bar((1*(1 as usize)).try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | + +++++++++++++++++++++ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-13497-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-13497-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-13497-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-13497-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,14 @@ error[E0515]: cannot return value referencing local variable `rawLines` --> $DIR/issue-13497-2.rs:3:5 | -LL | rawLines - | ^------- - | | - | _____`rawLines` is borrowed here - | | -LL | | .iter().map(|l| l.trim()).collect() - | |___________________________________________^ returns a value referencing data owned by the current function +LL | rawLines + | _____^ + | |_____| + | || +LL | || .iter().map(|l| l.trim()).collect() + | ||_______________-___________________________^ returns a value referencing data owned by the current function + | |________________| + | `rawLines` is borrowed here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-1362.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-1362.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-1362.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-1362.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ help: change the type of the numeric literal from `i32` to `u32` | LL | let x: u32 = 20u32; - | ~~~~~ + | ~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-14091-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-14091-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-14091-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-14091-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,24 @@ --> $DIR/issue-14091-2.rs:15:5 | LL | assert!(x, x); - | ^^^^^^^^^^^^^^ cannot apply unary operator `!` + | ^^^^^^^^^^^^^ cannot apply unary operator `!` | - = note: an implementation of `std::ops::Not` might be missing for `BytePos` +note: an implementation of `Not` might be missing for `BytePos` + --> $DIR/issue-14091-2.rs:6:1 + | +LL | pub struct BytePos(pub u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `Not` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait Not { +LL | | /// The resulting type after applying the `!` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn not(self) -> Self::Output; +LL | | } + | |_^ = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-14091.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-14091.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-14091.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-14091.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-14091.rs:2:5 | LL | assert!(1,1); - | ^^^^^^^^^^^^^ expected `bool`, found integer + | ^^^^^^^^^^^^ expected `bool`, found integer error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-1448-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-1448-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-1448-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-1448-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `i32` to `u32` | LL | println!("{}", foo(10u32)); - | ~~~~~ + | ~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-16098.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-16098.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-16098.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-16098.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | println!("Problem 1: {}", prob1!(1000)); | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_16098`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_16098`) = note: this error originates in the macro `prob1` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-16683.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-16683.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-16683.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-16683.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,19 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-16683.rs:4:9 | +LL | trait T<'a> { + | -- lifetime `'a` defined here +LL | fn a(&'a self) -> &'a bool; LL | fn b(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | self.a(); - | ^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-16683.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-16683.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-16683.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-16683.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | self.a(); | ^ | -note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 3:10... +note: first, the lifetime cannot outlive the anonymous lifetime defined here... --> $DIR/issue-16683.rs:3:10 | LL | fn b(&self) { @@ -14,7 +14,7 @@ | LL | self.a(); | ^^^^ -note: but, the lifetime must be valid for the lifetime `'a` as defined on the trait at 1:9... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/issue-16683.rs:1:9 | LL | trait T<'a> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-16966.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-16966.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-16966.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-16966.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-16966.rs:2:5 | LL | panic!(std::default::Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic` | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17651.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17651.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17651.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17651.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,5 +4,4 @@ fn main() { (|| Box::new(*(&[0][..])))(); //~^ ERROR the size for values of type - //~| ERROR the size for values of type } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17651.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17651.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17651.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17651.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-17651.rs:5:18 | LL | (|| Box::new(*(&[0][..])))(); - | ^^^^^^^^^^^ doesn't have a size known at compile-time + | -------- ^^^^^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[{integer}]` note: required by `Box::::new` @@ -11,16 +13,6 @@ LL | pub fn new(x: T) -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time - --> $DIR/issue-17651.rs:5:9 - | -LL | (|| Box::new(*(&[0][..])))(); - | ^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[{integer}]` - = note: all function arguments must have a statically known size - = help: unsized fn params are gated as an unstable feature - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17740.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17740.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17740.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17740.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `Foo<'a>` found struct `Foo<'_>` -note: the anonymous lifetime defined on the method body at 6:23... +note: the anonymous lifetime defined here... --> $DIR/issue-17740.rs:6:23 | LL | fn bar(self: &mut Foo) { | ^^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 5:7 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/issue-17740.rs:5:7 | LL | impl <'a> Foo<'a>{ @@ -25,12 +25,12 @@ | = note: expected struct `Foo<'a>` found struct `Foo<'_>` -note: the lifetime `'a` as defined on the impl at 5:7... +note: the lifetime `'a` as defined here... --> $DIR/issue-17740.rs:5:7 | LL | impl <'a> Foo<'a>{ | ^^ -note: ...does not necessarily outlive the anonymous lifetime defined on the method body at 6:23 +note: ...does not necessarily outlive the anonymous lifetime defined here --> $DIR/issue-17740.rs:6:23 | LL | fn bar(self: &mut Foo) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17758.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17758.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17758.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17758.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,19 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-17758.rs:7:9 | +LL | trait Foo<'a> { + | -- lifetime `'a` defined here +LL | fn foo(&'a self); LL | fn bar(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | self.foo(); - | ^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17758.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17758.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17758.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17758.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | self.foo(); | ^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 6:12... +note: first, the lifetime cannot outlive the anonymous lifetime defined here... --> $DIR/issue-17758.rs:6:12 | LL | fn bar(&self) { @@ -14,7 +14,7 @@ | LL | self.foo(); | ^^^^ -note: but, the lifetime must be valid for the lifetime `'a` as defined on the trait at 4:11... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/issue-17758.rs:4:11 | LL | trait Foo<'a> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17905-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17905-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-17905-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-17905-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `Pair<&str, _>` found struct `Pair<&str, _>` -note: the anonymous lifetime defined on the method body at 8:24... +note: the anonymous lifetime defined here... --> $DIR/issue-17905-2.rs:8:24 | LL | fn say(self: &Pair<&str, isize>) { | ^^^^ -note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 5:5 +note: ...does not necessarily outlive the lifetime `'_` as defined here --> $DIR/issue-17905-2.rs:5:5 | LL | &str, @@ -25,12 +25,12 @@ | = note: expected struct `Pair<&str, _>` found struct `Pair<&str, _>` -note: the lifetime `'_` as defined on the impl at 5:5... +note: the lifetime `'_` as defined here... --> $DIR/issue-17905-2.rs:5:5 | LL | &str, | ^ -note: ...does not necessarily outlive the anonymous lifetime defined on the method body at 8:24 +note: ...does not necessarily outlive the anonymous lifetime defined here --> $DIR/issue-17905-2.rs:8:24 | LL | fn say(self: &Pair<&str, isize>) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-18294.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-18294.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-18294.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-18294.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/issue-18294.rs:3:31 | LL | const Y: usize = unsafe { &X as *const u32 as usize }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-18400.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-18400.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-18400.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-18400.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | 0.contains(bits); | ^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_18400`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_18400`) note: required because of the requirements on the impl of `Set<&[_]>` for `{integer}` --> $DIR/issue-18400.rs:6:16 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-18959.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-18959.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-18959.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-18959.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn foo(b: &dyn Bar) { | ^^^^^^^ `Bar` cannot be made into an object | - = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-18959.rs:1:20 | @@ -12,6 +11,7 @@ | ^^^ ...because method `foo` has generic type parameters LL | pub trait Bar: Foo { } | --- this trait cannot be made into an object... + = help: consider moving `foo` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19163.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19163.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19163.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19163.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,10 @@ error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/issue-19163.rs:9:14 + --> $DIR/issue-19163.rs:9:5 | LL | mywrite!(&v, "Hello world"); - | ^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | + = note: this error originates in the macro `mywrite` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19358.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19358.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19358.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19358.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,7 @@ // run-pass + +#![allow(dead_code)] + trait Trait { fn dummy(&self) { } } #[derive(Debug)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19538.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19538.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19538.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19538.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^^^ `Bar` cannot be made into an object | - = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-19538.rs:2:8 | @@ -13,6 +12,7 @@ ... LL | trait Bar: Foo { } | --- this trait cannot be made into an object... + = help: consider moving `foo` to another trait error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/issue-19538.rs:17:30 @@ -20,7 +20,6 @@ LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^ `Bar` cannot be made into an object | - = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-19538.rs:2:8 | @@ -29,6 +28,7 @@ ... LL | trait Bar: Foo { } | --- this trait cannot be made into an object... + = help: consider moving `foo` to another trait = note: required because of the requirements on the impl of `CoerceUnsized<&mut dyn Bar>` for `&mut Thing` = note: required by cast to type `&mut dyn Bar` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19883.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19883.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19883.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19883.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -trait From { - type Output; - - fn from(src: Src) -> >::Output; -} - -trait To: Sized { - fn to>(self) -> - >::Dst - //~^ ERROR cannot find associated type `Dst` in trait `From` - { - From::from(self) - } -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19883.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19883.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-19883.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-19883.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -error[E0576]: cannot find associated type `Dst` in trait `From` - --> $DIR/issue-19883.rs:9:30 - | -LL | type Output; - | ------------ associated type `Output` defined here -... -LL | >::Dst - | ^^^ - | | - | not found in `From` - | help: maybe you meant this associated type: `Output` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0576`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20413.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20413.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20413.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20413.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ LL | impl Foo for T where NoData: Foo { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:8:9 | @@ -33,7 +33,7 @@ LL | impl Foo for T where NoData: Foo { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:8:9 | @@ -53,7 +53,7 @@ LL | impl Bar for T where EvenLessData: Baz { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Bar` for `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:28:9 | @@ -78,7 +78,7 @@ LL | impl Bar for T where EvenLessData: Baz { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Bar` for `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:28:9 | @@ -103,7 +103,7 @@ LL | impl Baz for T where AlmostNoData: Bar { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Baz` for `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:36:9 | @@ -128,7 +128,7 @@ LL | impl Baz for T where AlmostNoData: Bar { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Baz` for `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:36:9 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20605.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20605.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20605.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20605.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,15 +2,19 @@ --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } - | ^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^ expected an implementor of trait `IntoIterator` | - = help: the trait `Sized` is not implemented for `dyn Iterator` + = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator` note: required by `into_iter` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider mutably borrowing here + | +LL | for item in &mut *things { *item = 0 } + | ++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20692.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20692.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20692.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20692.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -trait Array: Sized + Copy {} - -fn f(x: &T) { - let _ = x - //~^ ERROR `Array` cannot be made into an object - as - &dyn Array; - //~^ ERROR `Array` cannot be made into an object -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20692.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20692.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20692.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20692.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -error[E0038]: the trait `Array` cannot be made into an object - --> $DIR/issue-20692.rs:7:5 - | -LL | &dyn Array; - | ^^^^^^^^^^ `Array` cannot be made into an object - | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-20692.rs:1:14 - | -LL | trait Array: Sized + Copy {} - | ----- ^^^^^ ^^^^ ...because it requires `Self: Sized` - | | | - | | ...because it requires `Self: Sized` - | this trait cannot be made into an object... - -error[E0038]: the trait `Array` cannot be made into an object - --> $DIR/issue-20692.rs:4:13 - | -LL | let _ = x - | ^ `Array` cannot be made into an object - | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-20692.rs:1:14 - | -LL | trait Array: Sized + Copy {} - | ----- ^^^^^ ^^^^ ...because it requires `Self: Sized` - | | | - | | ...because it requires `Self: Sized` - | this trait cannot be made into an object... - = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Array>` for `&T` - = note: required by cast to type `&dyn Array` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0038`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20831-debruijn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20831-debruijn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-20831-debruijn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-20831-debruijn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { | ^^^^^^^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 28:58... +note: first, the lifetime cannot outlive the anonymous lifetime defined here... --> $DIR/issue-20831-debruijn.rs:28:58 | LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the impl at 26:6... +note: ...but the lifetime must also be valid for the lifetime `'a` as defined here... --> $DIR/issue-20831-debruijn.rs:26:6 | LL | impl<'a> Publisher<'a> for MyStruct<'a> { @@ -19,8 +19,8 @@ | LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { | ^^^^^^^^^ - = note: expected `Publisher<'_>` - found `Publisher<'_>` + = note: expected ` as Publisher<'_>>` + found ` as Publisher<'_>>` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-21363.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-21363.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-21363.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-21363.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -// check-pass -// pretty-expanded FIXME #23616 - -#![no_implicit_prelude] - -trait Iterator { - type Item; - fn dummy(&self) { } -} - -impl<'a, T> Iterator for &'a mut (dyn Iterator + 'a) { - type Item = T; -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-2150.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-2150.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-2150.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-2150.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-2150.rs:8:5 | LL | panic!(); - | --------- any code following this expression is unreachable + | -------- any code following this expression is unreachable LL | for x in &v { i += 1; } | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-21600.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-21600.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-21600.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-21600.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | - change this to accept `FnMut` instead of `Fn` ... LL | call_it(|| x.gen_mut()); - | ------- ^ cannot borrow as mutable + | ------- ^^^^^^^^^^^ cannot borrow as mutable | | | expects `Fn` instead of `FnMut` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-23122-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-23122-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-23122-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-23122-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`) note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` --> $DIR/issue-23122-2.rs:8:15 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-23825.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-23825.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-23825.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-23825.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -// run-pass -trait Stringify { - fn to_string(&self) -> String; -} - -impl Stringify for u32 { - fn to_string(&self) -> String { format!("u32: {}", *self) } -} - -impl Stringify for f32 { - fn to_string(&self) -> String { format!("f32: {}", *self) } -} - -fn print(x: T) -> String { - x.to_string() -} - -fn main() { - assert_eq!(&print(5), "u32: 5"); - assert_eq!(&print(5.0), "f32: 5"); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-23833.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-23833.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-23833.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-23833.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -// run-pass -#![allow(unused_imports)] -use std::fmt; - -const A_I8_T - : [u32; (i8::MAX as i8 - 1i8) as usize] - = [0; (i8::MAX as usize) - 1]; - -fn main() { - foo(&A_I8_T[..]); -} - -fn foo(x: T) { - println!("{:?}", x); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-23966.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-23966.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-23966.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-23966.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-23966.rs:2:32 | LL | "".chars().fold(|_, _| (), ()); - | ^^ expected an `FnMut<(_, char)>` closure, found `()` + | ---- ^^ expected an `FnMut<(_, char)>` closure, found `()` + | | + | required by a bound introduced by this call | = help: the trait `FnMut<(_, char)>` is not implemented for `()` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-25076.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-25076.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-25076.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-25076.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-25076.rs:10:20 | LL | do_fold(bot(), ()); - | ^^ the trait `InOut<_>` is not implemented for `()` + | ------- ^^ the trait `InOut<_>` is not implemented for `()` + | | + | required by a bound introduced by this call | note: required by a bound in `do_fold` --> $DIR/issue-25076.rs:5:18 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-25385.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-25385.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-25385.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-25385.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^ method not found in `i32` ... LL | foo!(a); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-26093.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-26093.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-26093.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-26093.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ ... LL | not_a_place!(99); - | ----------------- + | ---------------- | | | | | cannot assign to this expression | in this macro invocation @@ -19,7 +19,7 @@ | ^^ ... LL | not_a_place!(99); - | ----------------- + | ---------------- | | | | | cannot assign to this expression | in this macro invocation diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-26217.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-26217.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-26217.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-26217.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | foo::<&'a i32>(); | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-27942.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-27942.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-27942.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-27942.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected type `Resources<'_>` found type `Resources<'a>` -note: the anonymous lifetime defined on the method body at 5:15... +note: the anonymous lifetime defined here... --> $DIR/issue-27942.rs:5:15 | LL | fn select(&self) -> BufferViewHandle; | ^^^^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the trait at 3:18 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/issue-27942.rs:3:18 | LL | pub trait Buffer<'a, R: Resources<'a>> { @@ -25,12 +25,12 @@ | = note: expected type `Resources<'_>` found type `Resources<'a>` -note: the lifetime `'a` as defined on the trait at 3:18... +note: the lifetime `'a` as defined here... --> $DIR/issue-27942.rs:3:18 | LL | pub trait Buffer<'a, R: Resources<'a>> { | ^^ -note: ...does not necessarily outlive the anonymous lifetime defined on the method body at 5:15 +note: ...does not necessarily outlive the anonymous lifetime defined here --> $DIR/issue-27942.rs:5:15 | LL | fn select(&self) -> BufferViewHandle; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-28098.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-28098.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-28098.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-28098.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-28098.rs:2:28 | LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^ `()` is not an iterator + | -------------- ^^^^^^^ `()` is not an iterator + | | + | required by a bound introduced by this call | = help: the trait `Iterator` is not implemented for `()` note: required by `std::iter::Iterator::next` @@ -29,7 +31,9 @@ --> $DIR/issue-28098.rs:9:28 | LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^ `()` is not an iterator + | -------------- ^^^^^^^ `()` is not an iterator + | | + | required by a bound introduced by this call | = help: the trait `Iterator` is not implemented for `()` note: required by `std::iter::Iterator::next` @@ -50,7 +54,9 @@ --> $DIR/issue-28098.rs:18:28 | LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^ `()` is not an iterator + | -------------- ^^^^^^^ `()` is not an iterator + | | + | required by a bound introduced by this call | = help: the trait `Iterator` is not implemented for `()` note: required by `std::iter::Iterator::next` @@ -63,7 +69,9 @@ --> $DIR/issue-28098.rs:22:28 | LL | let _ = Iterator::next(&mut ()); - | ^^^^^^^ `()` is not an iterator + | -------------- ^^^^^^^ `()` is not an iterator + | | + | required by a bound introduced by this call | = help: the trait `Iterator` is not implemented for `()` note: required by `std::iter::Iterator::next` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-29084.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-29084.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-29084.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-29084.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^ expected `u8`, found `&mut u8` ... LL | foo!(0u8); - | ---------- in this macro invocation + | --------- in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-2995.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-2995.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-2995.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-2995.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,9 @@ | help: consider borrowing the value | -LL | let _q: &isize = &*p as &isize; - | ++ +LL - let _q: &isize = p as &isize; +LL + let _q: &isize = &*p; + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-30355.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-30355.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-30355.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-30355.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/issue-30355.rs:5:6 + --> $DIR/issue-30355.rs:5:8 | LL | &X(*Y) - | ^ doesn't have a size known at compile-time + | ^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: all function arguments must have a statically known size diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-31011.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-31011.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-31011.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-31011.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | - type parameter 'T' declared here LL | { LL | log!(context, "entered wrapper"); - | --------------------------------- in this macro invocation + | -------------------------------- in this macro invocation | = note: this error originates in the macro `log` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-31076.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-31076.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-31076.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-31076.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ fn main() { let x = 5 + 6; - //~^ ERROR cannot add `{integer}` to `{integer}` + //~^ ERROR cannot add `i32` to `{integer}` let y = 5i32 + 6i32; //~^ ERROR cannot add `i32` to `i32` } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-31076.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-31076.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-31076.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-31076.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -error[E0369]: cannot add `{integer}` to `{integer}` +error[E0369]: cannot add `i32` to `{integer}` --> $DIR/issue-31076.rs:13:15 | LL | let x = 5 + 6; - | - ^ - {integer} + | - ^ - i32 | | | {integer} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-32655.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-32655.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-32655.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-32655.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^ ... LL | foo!(); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-32782.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-32782.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-32782.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-32782.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | foo!(); - | ------- in this macro invocation + | ------ in this macro invocation | = help: add `#![feature(allow_internal_unstable)]` to the crate attributes to enable = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-32963.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-32963.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-32963.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-32963.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Misc + Copy {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -17,7 +17,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Misc + Copy {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-33498.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-33498.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-33498.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-33498.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -// run-pass -#![allow(unused_variables)] -pub fn main() { - let x = (0, 2); - - match x { - (0, ref y) => {} - (y, 0) => {} - _ => (), - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-34194.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-34194.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-34194.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-34194.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -// build-pass -#![allow(dead_code)] - -struct A { - a: &'static (), -} - -static B: &'static A = &A { a: &() }; -static C: &'static A = &B; - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-34255-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-34255-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-34255-1.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-34255-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,5 +6,5 @@ fn main() { Test::Drill(field: 42); - //~^ ERROR expected type, found + //~^ ERROR invalid `struct` delimiters or `fn` call arguments } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-34255-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-34255-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-34255-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-34255-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,18 @@ -error: expected type, found `42` - --> $DIR/issue-34255-1.rs:8:24 +error: invalid `struct` delimiters or `fn` call arguments + --> $DIR/issue-34255-1.rs:8:5 | LL | Test::Drill(field: 42); - | - ^^ expected type - | | - | tried to parse a type due to this type ascription + | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` - = note: see issue #23416 for more information +help: if `Test::Drill` is a struct, use braces as delimiters + | +LL | Test::Drill { field: 42 }; + | ~ ~ +help: if `Test::Drill` is a function, use the arguments directly + | +LL - Test::Drill(field: 42); +LL + Test::Drill(42); + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-34784.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-34784.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-34784.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-34784.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -// run-pass - -#![warn(pointer_structural_match)] -#![allow(dead_code)] -const C: *const u8 = &0; - -fn foo(x: *const u8) { - match x { - C => {} - _ => {} - } -} - -const D: *const [u8; 4] = b"abcd"; - -fn main() { - match D { - D => {} - _ => {} - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-35376.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-35376.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-35376.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-35376.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -// check-pass -#![feature(specialization)] -//~^ WARN the feature `specialization` is incomplete - -fn main() {} - -pub trait Alpha { } - -pub trait Beta { - type Event; -} - -pub trait Delta { - type Handle; - fn process(&self); -} - -pub struct Parent(A, T); - -impl Delta for Parent -where A: Alpha, - T: Delta, - T::Handle: Beta::Event> { - type Handle = Handle; - default fn process(&self) { - unimplemented!() - } -} - -impl Delta for Parent -where A: Alpha + Alpha, - T: Delta, - T::Handle: Beta::Event> { - fn process(&self) { - unimplemented!() - } -} - -pub struct Handle; - -impl Beta for Handle { - type Event = (); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-35376.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-35376.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-35376.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-35376.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-35376.rs:2:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - -warning: 1 warning emitted - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-36768.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-36768.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-36768.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-36768.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -// run-pass -// compile-flags:--test -#![deny(private_in_public)] - -#[test] fn foo() {} -mod foo {} - -#[test] fn core() {} -extern crate core; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-37433.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-37433.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-37433.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-37433.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -// build-fail -// ignore-emscripten no llvm_asm! support - -#![feature(llvm_asm)] -#![allow(deprecated)] // llvm_asm! - -fn main() { - unsafe { - llvm_asm!("" :: "r"("")); - //~^ ERROR: invalid value for constraint in inline assembly - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-37433.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-37433.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-37433.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-37433.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -error[E0669]: invalid value for constraint in inline assembly - --> $DIR/issue-37433.rs:9:29 - | -LL | llvm_asm!("" :: "r"("")); - | ^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0669`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-37884.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-37884.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-37884.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-37884.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -11,12 +11,12 @@ | = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>` found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>` -note: the anonymous lifetime #1 defined on the method body at 6:5... +note: the anonymous lifetime #1 defined here... --> $DIR/issue-37884.rs:6:5 | LL | fn next(&'a mut self) -> Option | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 3:6 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/issue-37884.rs:3:6 | LL | impl<'a, T: 'a> Iterator for RepeatMut<'a, T> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-3794.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-3794.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-3794.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-3794.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ // run-pass #![feature(box_syntax)] +#![allow(dead_code)] trait T { fn print(&self); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-38002.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-38002.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-38002.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-38002.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -// run-pass -#![allow(dead_code)] -// Check that constant ADTs are codegened OK, part k of N. - -enum Bar { - C -} - -enum Foo { - A {}, - B { - y: usize, - z: Bar - }, -} - -const LIST: [(usize, Foo); 2] = [ - (51, Foo::B { y: 42, z: Bar::C }), - (52, Foo::B { y: 45, z: Bar::C }), -]; - -pub fn main() { - match LIST { - [ - (51, Foo::B { y: 42, z: Bar::C }), - (52, Foo::B { y: 45, z: Bar::C }) - ] => {} - _ => { - // I would want to print the enum here, but if - // the discriminant is garbage this causes an - // `unreachable` and silent process exit. - panic!("trivial match failed") - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-3820.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-3820.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-3820.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-3820.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,22 @@ | | | Thing | - = note: an implementation of `std::ops::Mul` might be missing for `Thing` +note: an implementation of `Mul<_>` might be missing for `Thing` + --> $DIR/issue-3820.rs:1:1 + | +LL | struct Thing { + | ^^^^^^^^^^^^ must implement `Mul<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Mul { +LL | | /// The resulting type after applying the `*` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn mul(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-3935.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-3935.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-3935.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-3935.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -// run-pass - -#[derive(PartialEq)] -struct Bike { - name: String, -} - -pub fn main() { - let town_bike = Bike { name: "schwinn".to_string() }; - let my_bike = Bike { name: "surly".to_string() }; - - assert!(town_bike != my_bike); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-39848.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-39848.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-39848.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-39848.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ | this `if` expression has a condition, but no block ... LL | get_opt!(bar, foo); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `get_opt` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-41255.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-41255.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-41255.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-41255.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -// Matching against float literals should result in a linter error - -#![feature(exclusive_range_pattern)] -#![feature(half_open_range_patterns)] -#![allow(unused)] -#![forbid(illegal_floating_point_literal_pattern)] - -fn main() { - let x = 42.0; - match x { - 5.0 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - 5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - 1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - //~| ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - 39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns - //~| ERROR floating-point types cannot be used in patterns - //~| WARNING hard error - //~| WARNING hard error - - ..71.0 => {} - //~^ ERROR floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - ..=72.0 => {} - //~^ ERROR floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - 71.0.. => {} - //~^ ERROR floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - _ => {}, - }; - let y = 5.0; - // Same for tuples - match (x, 5) { - (3.14, 1) => {}, //~ ERROR floating-point types cannot be used - //~| WARNING hard error - _ => {}, - } - // Or structs - struct Foo { x: f32 }; - match (Foo { x }) { - Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used - //~| WARNING hard error - _ => {}, - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-41255.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-41255.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-41255.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-41255.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:11:9 - | -LL | 5.0 => {}, - | ^^^ - | -note: the lint level is defined here - --> $DIR/issue-41255.rs:6:11 - | -LL | #![forbid(illegal_floating_point_literal_pattern)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:13:9 - | -LL | 5.0f32 => {}, - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:15:10 - | -LL | -5.0 => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:17:9 - | -LL | 1.0 .. 33.0 => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:17:16 - | -LL | 1.0 .. 33.0 => {}, - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:21:9 - | -LL | 39.0 ..= 70.0 => {}, - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:21:18 - | -LL | 39.0 ..= 70.0 => {}, - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:26:11 - | -LL | ..71.0 => {} - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:29:12 - | -LL | ..=72.0 => {} - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:32:9 - | -LL | 71.0.. => {} - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:40:10 - | -LL | (3.14, 1) => {}, - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: floating-point types cannot be used in patterns - --> $DIR/issue-41255.rs:47:18 - | -LL | Foo { x: 2.0 } => {}, - | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: aborting due to 12 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-41726.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-41726.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-41726.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-41726.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-41726.rs:5:9 | LL | things[src.as_str()].sort(); - | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-42106.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-42106.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-42106.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-42106.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,9 +4,9 @@ LL | let _a = &collection; | ----------- immutable borrow occurs here LL | collection.swap(1, 2); - | ^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | _a.use_ref(); - | -- immutable borrow later used here + | ------------ immutable borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-42944.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-42944.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-42944.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-42944.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -mod foo { - pub struct Bx(()); -} - -mod bar { - use foo::Bx; - - fn foo() { - Bx(()); - //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] - } -} - -mod baz { - fn foo() { - Bx(()); - //~^ ERROR cannot find function, tuple struct or tuple variant `Bx` in this scope [E0425] - } -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-42944.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-42944.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-42944.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-42944.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -error[E0423]: cannot initialize a tuple struct which contains private fields - --> $DIR/issue-42944.rs:9:9 - | -LL | Bx(()); - | ^^ - | -note: constructor is not visible here due to private fields - --> $DIR/issue-42944.rs:2:19 - | -LL | pub struct Bx(()); - | ^^ private field - -error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope - --> $DIR/issue-42944.rs:16:9 - | -LL | Bx(()); - | ^^ not found in this scope - | -help: consider importing this tuple struct - | -LL | use foo::Bx; - | - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0423, E0425. -For more information about an error, try `rustc --explain E0423`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-42954.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-42954.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-42954.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-42954.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | not interpreted as comparison ... LL | is_plainly_printable!(c); - | ------------------------- in this macro invocation + | ------------------------ in this macro invocation | = note: this error originates in the macro `is_plainly_printable` (in Nightly builds, run with -Z macro-backtrace for more info) help: try comparing the cast value diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-4335.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-4335.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-4335.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-4335.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,10 @@ LL | fn f<'r, T>(v: &'r T) -> Box T + 'r> { | - captured outer variable LL | id(Box::new(|| *v)) - | ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait + | ---^^ + | | | + | | move occurs because `*v` has type `T`, which does not implement the `Copy` trait + | captured by this `FnMut` closure error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-44405.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-44405.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-44405.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-44405.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-44405.rs:21:5 | LL | container[&mut val].test(); - | ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Container` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13 - | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -LL | let f = |v: &mut Vec<_>| { -LL | unsafe { - | ^^^^^^ unnecessary `unsafe` block - | -note: the lint level is defined here - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8 - | -LL | #[deny(unused_unsafe)] - | ^^^^^^^^^^^^^ - -error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38 - | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -... -LL | |w: &mut Vec| { unsafe { - | ^^^^^^ unnecessary `unsafe` block - -error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34 - | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -... -LL | |x: &mut Vec| { unsafe { - | ^^^^^^ unnecessary `unsafe` block - -error: aborting due to 3 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -// revisions: mir thir -// [thir]compile-flags: -Zthir-unsafeck - -#[deny(unused_unsafe)] -fn main() { - let mut v = Vec::::with_capacity(24); - - unsafe { - let f = |v: &mut Vec<_>| { - unsafe { //~ ERROR unnecessary `unsafe` - v.set_len(24); - |w: &mut Vec| { unsafe { //~ ERROR unnecessary `unsafe` - w.set_len(32); - } }; - } - |x: &mut Vec| { unsafe { //~ ERROR unnecessary `unsafe` - x.set_len(40); - } }; - }; - - v.set_len(0); - f(&mut v); - } - - |y: &mut Vec| { unsafe { - y.set_len(48); - } }; -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13 - | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -LL | let f = |v: &mut Vec<_>| { -LL | unsafe { - | ^^^^^^ unnecessary `unsafe` block - | -note: the lint level is defined here - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8 - | -LL | #[deny(unused_unsafe)] - | ^^^^^^^^^^^^^ - -error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38 - | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -... -LL | |w: &mut Vec| { unsafe { - | ^^^^^^ unnecessary `unsafe` block - -error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34 - | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -... -LL | |x: &mut Vec| { unsafe { - | ^^^^^^ unnecessary `unsafe` block - -error: aborting due to 3 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-4736.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-4736.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-4736.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-4736.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,9 +5,12 @@ | ----------- `NonCopyable` defined here ... LL | let z = NonCopyable{ p: () }; - | ----------- ^ field does not exist - | | - | help: `NonCopyable` is a tuple struct, use the appropriate syntax: `NonCopyable(/* fields */)` + | ^ field does not exist + | +help: `NonCopyable` is a tuple struct, use the appropriate syntax + | +LL | let z = NonCopyable(/* fields */); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-47646.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-47646.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-47646.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-47646.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-47646.rs:9:30 | LL | let borrow = heap.peek_mut(); - | ---- mutable borrow occurs here + | --------------- mutable borrow occurs here LL | LL | match (borrow, ()) { | ------------ a temporary with access to the mutable borrow is created here ... diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-47706.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-47706.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-47706.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-47706.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,9 @@ | ------------------------------------------ takes 2 arguments ... LL | self.foo.map(Foo::new) - | ^^^^^^^^ expected function that takes 1 argument + | --- ^^^^^^^^ expected function that takes 1 argument + | | + | required by a bound introduced by this call error[E0593]: function is expected to take 0 arguments, but it takes 1 argument --> $DIR/issue-47706.rs:27:9 @@ -14,7 +16,9 @@ | -------- takes 1 argument ... LL | foo(Qux::Bar); - | ^^^^^^^^ expected function that takes 0 arguments + | --- ^^^^^^^^ expected function that takes 0 arguments + | | + | required by a bound introduced by this call | note: required by a bound in `foo` --> $DIR/issue-47706.rs:22:8 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-47706-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-47706-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-47706-trait.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-47706-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,9 @@ LL | fn f(&self, _: ()) { | ------------------ takes 2 distinct arguments LL | None::<()>.map(Self::f); - | ^^^^^^^ expected function that takes a single 0-tuple as argument + | --- ^^^^^^^ expected function that takes a single 0-tuple as argument + | | + | required by a bound introduced by this call error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: the following trait bounds were not satisfied: `{integer}: DerefMut` - `<{integer} as Deref>::Target = _` + `{integer}: Deref` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,6 @@ | = note: the following trait bounds were not satisfied: `{integer}: Deref` - `<{integer} as Deref>::Target = _` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: the following trait bounds were not satisfied: `{integer}: DerefMut` - `<{integer} as Deref>::Target = _` + `{integer}: Deref` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,6 @@ | = note: the following trait bounds were not satisfied: `{integer}: Deref` - `<{integer} as Deref>::Target = _` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50403.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50403.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-50403.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-50403.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: concat_idents! takes 1 or more arguments. +error: concat_idents! takes 1 or more arguments --> $DIR/issue-50403.rs:4:13 | LL | let x = concat_idents!(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-51102.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-51102.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-51102.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-51102.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,10 @@ --> $DIR/issue-51102.rs:13:17 | LL | state: 0, - | ^^^^^ struct `SimpleStruct` does not have this field + | ^^^^^ + | | + | struct `SimpleStruct` does not have this field + | help: `SimpleStruct` has a field named `no_state_here` error[E0025]: field `no_state_here` bound multiple times in the pattern --> $DIR/issue-51102.rs:24:17 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ fn forbidden_narratives() -> Result { missing_discourses()? - //~^ ERROR try expression alternatives have incompatible types + //~^ ERROR: `?` operator has incompatible types } fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,10 @@ -error[E0308]: try expression alternatives have incompatible types +error[E0308]: `?` operator has incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | LL | missing_discourses()? | ^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `isize` | + = note: `?` operator cannot convert from `isize` to `Result` = note: expected enum `Result` found type `isize` help: try removing this `?` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-51848.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-51848.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-51848.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-51848.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | because of this opening brace ... LL | macro_with_error!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: if you intended to print `{`, you can escape it using `{{` = note: this error originates in the macro `macro_with_error` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-52126-assign-op-invariance.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-52126-assign-op-invariance.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-52126-assign-op-invariance.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-52126-assign-op-invariance.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-52126-assign-op-invariance.rs:34:28 | LL | let v: Vec<&str> = line.split_whitespace().collect(); - | ^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough ... LL | acc += cnt2; | --- borrow later used here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-52213.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-52213.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-52213.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-52213.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | match (&t,) { | ^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 1:23... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/issue-52213.rs:1:23 | LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T { @@ -16,7 +16,7 @@ | ^^^^^ = note: expected `(&&(T,),)` found `(&&'a (T,),)` -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/issue-52213.rs:1:27 | LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-52533-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-52533-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-52533-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-52533-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected reference `&Foo<'_, '_, u32>` found reference `&Foo<'_, '_, u32>` -note: the anonymous lifetime #3 defined on the body at 9:11... +note: the anonymous lifetime #3 defined here... --> $DIR/issue-52533-1.rs:9:11 | LL | gimme(|x, y| y) | ^^^^^^^^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 9:11 +note: ...does not necessarily outlive the anonymous lifetime #2 defined here --> $DIR/issue-52533-1.rs:9:11 | LL | gimme(|x, y| y) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-52533.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-52533.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-52533.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-52533.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | foo(|a, b| b) | ^ | -note: ...the reference is valid for the anonymous lifetime #1 defined on the body at 5:9... +note: ...the reference is valid for the anonymous lifetime #1 defined here... --> $DIR/issue-52533.rs:5:9 | LL | foo(|a, b| b) | ^^^^^^^^ -note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the body at 5:9 +note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined here --> $DIR/issue-52533.rs:5:9 | LL | foo(|a, b| b) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-53251.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-53251.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-53251.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-53251.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | expected 0 generic arguments ... LL | impl_add!(a b); - | --------------- in this macro invocation + | -------------- in this macro invocation | note: associated function defined here, with 0 generic parameters --> $DIR/issue-53251.rs:4:8 @@ -25,7 +25,7 @@ | expected 0 generic arguments ... LL | impl_add!(a b); - | --------------- in this macro invocation + | -------------- in this macro invocation | note: associated function defined here, with 0 generic parameters --> $DIR/issue-53251.rs:4:8 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-53912.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-53912.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-53912.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-53912.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -// build-pass - -// This test is the same code as in ui/symbol-names/issue-60925.rs but this checks that the -// reproduction compiles successfully and doesn't segfault, whereas that test just checks that the -// symbol mangling fix produces the correct result. - -fn dummy() {} - -mod llvm { - pub(crate) struct Foo; -} -mod foo { - pub(crate) struct Foo(T); - - impl Foo<::llvm::Foo> { - pub(crate) fn foo() { - for _ in 0..0 { - for _ in &[::dummy()] { - ::dummy(); - ::dummy(); - ::dummy(); - } - } - } - } - - pub(crate) fn foo() { - Foo::foo(); - Foo::foo(); - } -} - -pub fn foo() { - foo::foo(); -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-54943.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-54943.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-54943.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-54943.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | let x = foo::<&'a u32>(); | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-55796.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-55796.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-55796.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-55796.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-55796.rs:23:9 @@ -17,8 +15,6 @@ ... LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-55796.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-55796.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-55796.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-55796.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the trait at 7:17... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/issue-55796.rs:7:17 | LL | pub trait Graph<'a> { @@ -15,7 +15,7 @@ LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/issue-55796.rs:18:9 | LL | Box::new(self.out_edges(u).map(|e| e.target())) @@ -29,7 +29,7 @@ LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the trait at 7:17... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/issue-55796.rs:7:17 | LL | pub trait Graph<'a> { @@ -40,7 +40,7 @@ LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/issue-55796.rs:23:9 | LL | Box::new(self.in_edges(u).map(|e| e.target())) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-56031.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-56031.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-56031.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-56031.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -3,6 +3,16 @@ | LL | impl for T {} | ^ + | +help: add a trait here + | +LL | impl Trait for T {} + | +++++ +help: for an inherent impl, drop this `for` + | +LL - impl for T {} +LL + impl T {} + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-56685.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-56685.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-56685.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-56685.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -#![allow(dead_code)] -#![deny(unused_variables)] - -// This test aims to check that unused variable suggestions update bindings in all -// match arms. - -fn main() { - enum E { - A(i32,), - B(i32,), - } - - match E::A(1) { - E::A(x) | E::B(x) => {} - //~^ ERROR unused variable: `x` - } - - enum F { - A(i32, i32,), - B(i32, i32,), - C(i32, i32,), - } - - let _ = match F::A(1, 2) { - F::A(x, y) | F::B(x, y) => { y }, - //~^ ERROR unused variable: `x` - F::C(a, b) => { 3 } - //~^ ERROR unused variable: `a` - //~^^ ERROR unused variable: `b` - }; - - let _ = if let F::A(x, y) | F::B(x, y) = F::A(1, 2) { - //~^ ERROR unused variable: `x` - y - } else { - 3 - }; - - while let F::A(x, y) | F::B(x, y) = F::A(1, 2) { - //~^ ERROR unused variable: `x` - let _ = y; - break; - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-56685.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-56685.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-56685.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-56685.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -error: unused variable: `x` - --> $DIR/issue-56685.rs:14:14 - | -LL | E::A(x) | E::B(x) => {} - | ^ ^ - | -note: the lint level is defined here - --> $DIR/issue-56685.rs:2:9 - | -LL | #![deny(unused_variables)] - | ^^^^^^^^^^^^^^^^ -help: if this is intentional, prefix it with an underscore - | -LL | E::A(_x) | E::B(_x) => {} - | ~~ ~~ - -error: unused variable: `x` - --> $DIR/issue-56685.rs:25:14 - | -LL | F::A(x, y) | F::B(x, y) => { y }, - | ^ ^ - | -help: if this is intentional, prefix it with an underscore - | -LL | F::A(_x, y) | F::B(_x, y) => { y }, - | ~~ ~~ - -error: unused variable: `a` - --> $DIR/issue-56685.rs:27:14 - | -LL | F::C(a, b) => { 3 } - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/issue-56685.rs:27:17 - | -LL | F::C(a, b) => { 3 } - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `x` - --> $DIR/issue-56685.rs:32:25 - | -LL | let _ = if let F::A(x, y) | F::B(x, y) = F::A(1, 2) { - | ^ ^ - | -help: if this is intentional, prefix it with an underscore - | -LL | let _ = if let F::A(_x, y) | F::B(_x, y) = F::A(1, 2) { - | ~~ ~~ - -error: unused variable: `x` - --> $DIR/issue-56685.rs:39:20 - | -LL | while let F::A(x, y) | F::B(x, y) = F::A(1, 2) { - | ^ ^ - | -help: if this is intentional, prefix it with an underscore - | -LL | while let F::A(_x, y) | F::B(_x, y) = F::A(1, 2) { - | ~~ ~~ - -error: aborting due to 6 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-57410.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-57410.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-57410.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-57410.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -// check-pass - -// Tests that the `unreachable_pub` lint doesn't fire for `pub self::imp::f`. - -#![deny(unreachable_pub)] - -mod m { - mod imp { - pub fn f() {} - } - - pub use self::imp::f; -} - -pub use self::m::f; - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-5791.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-5791.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-5791.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-5791.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -// run-pass -#![allow(dead_code)] -#![warn(clashing_extern_declarations)] -// pretty-expanded FIXME #23616 - -extern "C" { - #[link_name = "malloc"] - fn malloc1(len: i32) -> *const u8; - #[link_name = "malloc"] - //~^ WARN `malloc2` redeclares `malloc` with a different signature - fn malloc2(len: i32, foo: i32) -> *const u8; -} - -pub fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-5791.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-5791.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-5791.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-5791.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -warning: `malloc2` redeclares `malloc` with a different signature - --> $DIR/issue-5791.rs:9:5 - | -LL | / #[link_name = "malloc"] -LL | | fn malloc1(len: i32) -> *const u8; - | |______________________________________- `malloc` previously declared here -LL | / #[link_name = "malloc"] -LL | | -LL | | fn malloc2(len: i32, foo: i32) -> *const u8; - | |________________________________________________^ this signature doesn't match the previous declaration - | -note: the lint level is defined here - --> $DIR/issue-5791.rs:3:9 - | -LL | #![warn(clashing_extern_declarations)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `unsafe extern "C" fn(i32) -> *const u8` - found `unsafe extern "C" fn(i32, i32) -> *const u8` - -warning: 1 warning emitted - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-59488.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-59488.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-59488.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-59488.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -72,7 +72,7 @@ --> $DIR/issue-59488.rs:30:5 | LL | assert_eq!(Foo::Bar, i); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ | | | fn(usize) -> Foo {Foo::Bar} | fn(usize) -> Foo {Foo::Bar} @@ -83,7 +83,7 @@ --> $DIR/issue-59488.rs:30:5 | LL | assert_eq!(Foo::Bar, i); - | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-59494.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-59494.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-59494.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-59494.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-59494.rs:21:22 | LL | let t8 = t8n(t7, t7p(f, g)); - | ^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>` + | --- ^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>` + | | + | required by a bound introduced by this call | = help: the trait `Fn<(_,)>` is not implemented for `impl Fn<(((_, _), _),)>` note: required by a bound in `t8n` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-60218.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-60218.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-60218.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-60218.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,10 @@ error[E0277]: the trait bound `&u32: Foo` is not satisfied - --> $DIR/issue-60218.rs:18:5 + --> $DIR/issue-60218.rs:18:27 | LL | trigger_error(vec![], |x: &u32| x) - | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `&u32` + | ------------- ^^^^^^^^^^^ the trait `Foo` is not implemented for `&u32` + | | + | required by a bound introduced by this call | note: required by a bound in `trigger_error` --> $DIR/issue-60218.rs:13:72 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-60283.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-60283.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-60283.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-60283.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,11 @@ --> $DIR/issue-60283.rs:17:13 | LL | foo((), drop) - | ^^^^ - | | - | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _` - | found signature of `fn(()) -> _` + | --- ^^^^ + | | | + | | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _` + | | found signature of `fn(()) -> _` + | required by a bound introduced by this call | note: required by a bound in `foo` --> $DIR/issue-60283.rs:12:16 @@ -20,7 +21,9 @@ --> $DIR/issue-60283.rs:17:13 | LL | foo((), drop) - | ^^^^ doesn't have a size known at compile-time + | --- ^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `<() as Trait<'_>>::Item` note: required by a bound in `std::mem::drop` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-61108.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-61108.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-61108.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-61108.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ | help: consider borrowing to avoid moving into the for loop: `&bad_letters` ... LL | bad_letters.push('s'); - | ^^^^^^^^^^^ value borrowed here after move + | ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move | note: this function takes ownership of the receiver `self`, which moves `bad_letters` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-61882-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-61882-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-61882-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-61882-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `x` is borrowed for `'static` + | this usage requires that `x` is borrowed for `'static` LL | LL | } | - `x` dropped here while still borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-62375.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-62375.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-62375.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-62375.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,15 @@ | | | A | - = note: an implementation of `std::cmp::PartialEq` might be missing for `A` +note: an implementation of `PartialEq<_>` might be missing for `A` + --> $DIR/issue-62375.rs:1:1 + | +LL | enum A { + | ^^^^^^ must implement `PartialEq<_>` +help: consider annotating `A` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-65230.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-65230.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-65230.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-65230.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +trait T0 {} +trait T1: T0 {} + +trait T2 {} + +impl<'a> T0 for &'a (dyn T2 + 'static) {} + +impl T1 for &dyn T2 {} +//~^ ERROR mismatched types + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-65230.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-65230.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-65230.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-65230.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/issue-65230.rs:8:6 + | +LL | impl T1 for &dyn T2 {} + | ^^ lifetime mismatch + | + = note: expected trait `<&dyn T2 as T0>` + found trait `<&(dyn T2 + 'static) as T0>` +note: the lifetime `'_` as defined here... + --> $DIR/issue-65230.rs:8:13 + | +LL | impl T1 for &dyn T2 {} + | ^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-6596-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-6596-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-6596-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-6596-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^ expected expression ... LL | e!(foo); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-6596-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-6596-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-6596-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-6596-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^ expected one of 8 possible tokens ... LL | g!(foo); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `g` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-66353.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-66353.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-66353.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-66353.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,9 @@ --> $DIR/issue-66353.rs:12:41 | LL | _Func::< <() as _A>::AssocT >::func(()); - | ^^ the trait `_Func<_>` is not implemented for `()` + | ----------------------------------- ^^ the trait `_Func<_>` is not implemented for `()` + | | + | required by a bound introduced by this call | note: required by `_Func::func` --> $DIR/issue-66353.rs:4:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ | ^^ expected `bool`, found `()` ... LL | x!(if); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `x` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 | LL | assert_eq!(a, 0); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | | | fn() -> i32 {a} | {integer} @@ -14,7 +14,7 @@ --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 | LL | assert_eq!(a, 0); - | ^^^^^^^^^^^^^^^^^ expected fn item, found integer + | ^^^^^^^^^^^^^^^^ expected fn item, found integer | = note: expected fn item `fn() -> i32 {a}` found type `i32` @@ -27,7 +27,7 @@ | - consider calling this function ... LL | assert_eq!(a, 0); - | ^^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `fn() -> i32 {a}` = help: use parentheses to call the function: `a()` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-74614.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-74614.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-74614.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-74614.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -// compile-flags:-Zpolymorphize=on -// build-pass - -fn test() { - std::mem::size_of::(); -} - -pub fn foo(_: T) -> &'static fn() { - &(test:: as fn()) -} - -fn outer() { - foo(|| ()); -} - -fn main() { - outer::(); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-75777.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-75777.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-75777.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-75777.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ LL | let fut: BoxFuture<'a, A> = Box::pin(future::ready(v)); LL | Box::new(move |_| fut) | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-75777.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-75777.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-75777.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-75777.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | Box::new(move |_| fut) | ^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 11:11... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/issue-75777.rs:11:11 | LL | fn inject<'a, Env: 'a, A: 'a + Send>(v: A) -> Box BoxFuture<'a, A>> { @@ -17,7 +17,7 @@ = note: expected `(Pin + Send>>,)` found `(Pin + Send + 'a)>>,)` = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/issue-75777.rs:13:5 | LL | Box::new(move |_| fut) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-78720.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-78720.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-78720.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-78720.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -fn server() -> impl { -//~^ ERROR at least one trait must be specified - ().map2(|| "") -} - -trait FilterBase2 { - fn map2(self, f: F) -> Map2 {} - //~^ ERROR mismatched types - //~^^ ERROR the size for values of type `Self` cannot be known at compilation time -} - -struct Map2 { - _func: F, - //~^ ERROR cannot find type `F` in this scope -} - -impl FilterBase2 for F {} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-78720.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-78720.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-78720.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-78720.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -error: at least one trait must be specified - --> $DIR/issue-78720.rs:1:16 - | -LL | fn server() -> impl { - | ^^^^ - -error[E0412]: cannot find type `F` in this scope - --> $DIR/issue-78720.rs:13:12 - | -LL | _func: F, - | ^ - | - ::: $SRC_DIR/core/src/ops/function.rs:LL:COL - | -LL | pub trait Fn: FnMut { - | ------------------------------- similarly named trait `Fn` defined here - | -help: a trait with a similar name exists - | -LL | _func: Fn, - | ~~ -help: you might be missing a type parameter - | -LL | struct Map2 { - | +++ - -error[E0308]: mismatched types - --> $DIR/issue-78720.rs:7:39 - | -LL | fn map2(self, f: F) -> Map2 {} - | ^^ expected struct `Map2`, found `()` - | - = note: expected struct `Map2` - found unit type `()` - -error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/issue-78720.rs:7:16 - | -LL | fn map2(self, f: F) -> Map2 {} - | ^^^^ doesn't have a size known at compile-time - | - = help: unsized fn params are gated as an unstable feature -help: consider further restricting `Self` - | -LL | fn map2(self, f: F) -> Map2 where Self: Sized {} - | +++++++++++++++++ -help: function arguments must have a statically known size, borrowed types always have a known size - | -LL | fn map2(&self, f: F) -> Map2 {} - | + - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0277, E0308, E0412. -For more information about an error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-79593.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-79593.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-79593.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-79593.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -mod foo { - pub struct Pub { private: () } - - pub enum Enum { - Variant { x: (), y: () }, - Other - } - - fn correct() { - Pub {}; - //~^ ERROR missing field `private` in initializer of `Pub` - Enum::Variant { x: () }; - //~^ ERROR missing field `y` in initializer of `Enum` - } -} - -fn correct() { - foo::Pub {}; - //~^ ERROR cannot construct `Pub` with struct literal syntax due to inaccessible fields -} - -fn wrong() { - foo::Enum::Variant { x: () }; - //~^ ERROR missing field `y` in initializer of `Enum` - foo::Enum::Variant { }; - //~^ ERROR missing fields `x` and `y` in initializer of `Enum` -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-79593.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-79593.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-79593.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-79593.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -error[E0063]: missing field `private` in initializer of `Pub` - --> $DIR/issue-79593.rs:10:9 - | -LL | Pub {}; - | ^^^ missing `private` - -error[E0063]: missing field `y` in initializer of `Enum` - --> $DIR/issue-79593.rs:12:9 - | -LL | Enum::Variant { x: () }; - | ^^^^^^^^^^^^^ missing `y` - -error: cannot construct `Pub` with struct literal syntax due to inaccessible fields - --> $DIR/issue-79593.rs:18:5 - | -LL | foo::Pub {}; - | ^^^^^^^^ - -error[E0063]: missing field `y` in initializer of `Enum` - --> $DIR/issue-79593.rs:23:5 - | -LL | foo::Enum::Variant { x: () }; - | ^^^^^^^^^^^^^^^^^^ missing `y` - -error[E0063]: missing fields `x` and `y` in initializer of `Enum` - --> $DIR/issue-79593.rs:25:5 - | -LL | foo::Enum::Variant { }; - | ^^^^^^^^^^^^^^^^^^ missing `x` and `y` - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0063`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-7970a.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-7970a.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-7970a.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-7970a.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | -------------------------- when calling this macro ... LL | one_arg_macro!(); - | ^^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^^^^^^^ missing tokens in macro arguments error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-79744.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-79744.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-79744.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-79744.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -fn main() { - let elem = 6i8; - let e2 = 230; - //~^ ERROR literal out of range for `i8` - //~| HELP consider using the type `u8` instead - - let mut vec = Vec::new(); - - vec.push(e2); - vec.push(elem); - - println!("{:?}", vec); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-79744.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-79744.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-79744.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-79744.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -error: literal out of range for `i8` - --> $DIR/issue-79744.rs:3:14 - | -LL | let e2 = 230; - | ^^^ - | - = note: `#[deny(overflowing_literals)]` on by default - = note: the literal `230` does not fit into the type `i8` whose range is `-128..=127` - = help: consider using the type `u8` instead - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-80607.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-80607.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-80607.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-80607.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,9 +5,12 @@ | -- `Enum::V1` defined here ... LL | Enum::V1 { x } - | -------- ^ field does not exist - | | - | help: `Enum::V1` is a tuple variant, use the appropriate syntax: `Enum::V1(/* fields */)` + | ^ field does not exist + | +help: `Enum::V1` is a tuple variant, use the appropriate syntax + | +LL | Enum::V1(/* fields */) + | ~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-81584.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-81584.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-81584.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-81584.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-81584.rs:5:22 | LL | .map(|y| y.iter().map(|x| x + 1)) - | -^^^^^^^^^^^^^^^^^^^^^^ + | --------^^^^^^^^^^^^^^^ | | | returns a value referencing data owned by the current function | `y` is borrowed here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-86865.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-86865.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-86865.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-86865.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +use std::fmt::Write; + +fn main() { + println!(b"foo"); + //~^ ERROR format argument must be a string literal + //~| HELP consider removing the leading `b` + let mut s = String::new(); + write!(s, b"foo{}", "bar"); + //~^ ERROR format argument must be a string literal + //~| HELP consider removing the leading `b` +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-86865.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-86865.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-86865.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-86865.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +error: format argument must be a string literal + --> $DIR/issue-86865.rs:4:14 + | +LL | println!(b"foo"); + | -^^^^^ + | | + | help: consider removing the leading `b` + +error: format argument must be a string literal + --> $DIR/issue-86865.rs:8:15 + | +LL | write!(s, b"foo{}", "bar"); + | -^^^^^^^ + | | + | help: consider removing the leading `b` + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-87199.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-87199.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-87199.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-87199.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,7 +20,9 @@ --> $DIR/issue-87199.rs:18:22 | LL | ref_arg::<[i32]>(&[5]); - | ^^^^ doesn't have a size known at compile-time + | ---------------- ^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[i32]` note: required by a bound in `ref_arg` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-8761.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-8761.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/issue-8761.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/issue-8761.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `i64` to `isize` | LL | A = 1isize, - | ~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/issue-8761.rs:5:9 @@ -18,7 +18,7 @@ help: change the type of the numeric literal from `u8` to `isize` | LL | B = 2isize - | ~~~~~~ + | ~~~~~ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -trait Foo { - type T; - fn foo(&self, t: Self::T); -//~^ NOTE expected 0 type parameters -} - -impl Foo for u32 { - type T = (); - - fn foo(&self, t: impl Clone) {} -//~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters -//~| NOTE found 1 type parameter -//~| NOTE `impl Trait` introduces an implicit type parameter -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22 - | -LL | fn foo(&self, t: Self::T); - | - expected 0 type parameters -... -LL | fn foo(&self, t: impl Clone) {} - | ^^^^^^^^^^ - | | - | found 1 type parameter - | `impl Trait` introduces an implicit type parameter - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0049`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/iterators/into-iter-on-arrays-2018.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/iterators/into-iter-on-arrays-2018.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/iterators/into-iter-on-arrays-2018.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/iterators/into-iter-on-arrays-2018.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:14:34 | LL | let _: Iter<'_, i32> = array.into_iter(); @@ -16,7 +16,7 @@ LL | let _: Iter<'_, i32> = IntoIterator::into_iter(array); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:18:44 | LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); @@ -25,7 +25,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:22:43 | LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); @@ -34,7 +34,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:25:41 | LL | let _: Iter<'_, i32> = Array(array).into_iter(); @@ -43,7 +43,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:32:24 | LL | for _ in [1, 2, 3].into_iter() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/iterators/into-iter-on-arrays-lint.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/iterators/into-iter-on-arrays-lint.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/iterators/into-iter-on-arrays-lint.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/iterators/into-iter-on-arrays-lint.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:10:11 | LL | small.into_iter(); @@ -16,7 +16,7 @@ LL | IntoIterator::into_iter(small); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:13:12 | LL | [1, 2].into_iter(); @@ -33,7 +33,7 @@ LL | IntoIterator::into_iter([1, 2]); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:16:9 | LL | big.into_iter(); @@ -50,7 +50,7 @@ LL | IntoIterator::into_iter(big); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:19:15 | LL | [0u8; 33].into_iter(); @@ -67,7 +67,7 @@ LL | IntoIterator::into_iter([0u8; 33]); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:23:21 | LL | Box::new(small).into_iter(); @@ -76,7 +76,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:26:22 | LL | Box::new([1, 2]).into_iter(); @@ -85,7 +85,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:29:19 | LL | Box::new(big).into_iter(); @@ -94,7 +94,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:32:25 | LL | Box::new([0u8; 33]).into_iter(); @@ -103,7 +103,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:36:31 | LL | Box::new(Box::new(small)).into_iter(); @@ -112,7 +112,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:39:32 | LL | Box::new(Box::new([1, 2])).into_iter(); @@ -121,7 +121,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:42:29 | LL | Box::new(Box::new(big)).into_iter(); @@ -130,7 +130,7 @@ = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:45:35 | LL | Box::new(Box::new([0u8; 33])).into_iter(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,15 +1,15 @@ -#![feature(box_syntax)] - trait Foo { } + + impl Foo for T { } fn take_param(foo: &T) { } fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); take_param(&x); //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/kindck-impl-type-params-2.rs:13:16 | LL | take_param(&x); - | ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | | + | required by a bound introduced by this call | note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` --> $DIR/kindck-impl-type-params-2.rs:6:14 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-impl-type-params.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // Issue #14061: tests the interaction between generic implementation // parameter bounds and trait objects. -#![feature(box_syntax)] + use std::marker; @@ -34,7 +34,7 @@ } fn foo2<'a>() { - let t: Box> = box S(marker::PhantomData); + let t: Box> = Box::new(S(marker::PhantomData)); let a = t as Box>; //~^ ERROR : Copy` is not satisfied } @@ -42,7 +42,7 @@ fn foo3<'a>() { struct Foo; // does not impl Copy - let t: Box> = box S(marker::PhantomData); + let t: Box> = Box::new(S(marker::PhantomData)); let a: Box> = t; //~^ ERROR : Copy` is not satisfied } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | take_param(&x); - | ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | | + | required by a bound introduced by this call | note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` --> $DIR/kindck-inherited-copy-bound.rs:14:14 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | take_param(&x); - | ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` + | | + | required by a bound introduced by this call | note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` --> $DIR/kindck-inherited-copy-bound.rs:14:14 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/kindck/kindck-inherited-copy-bound.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ // revisions: curr object_safe_for_dispatch #![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] -#![feature(box_syntax)] + use std::any::Any; @@ -17,13 +17,13 @@ fn take_param(foo: &T) { } fn a() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); take_param(&x); //[curr]~ ERROR E0277 //[object_safe_for_dispatch]~^ ERROR E0277 } fn b() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); let y = &x; let z = &x as &dyn Foo; //[curr]~^ ERROR E0038 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,27 @@ +// Make sure that an error is reported if the `call` function of the +// `fn`/`fn_mut` lang item is grossly ill-formed. + +#![feature(lang_items)] +#![feature(no_core)] +#![no_core] + +#[lang = "fn"] +trait MyFn { + const call: i32 = 42; + //~^ ERROR: `call` trait item in `fn` lang item must be a function +} + +#[lang = "fn_mut"] +trait MyFnMut { + fn call(i: i32, j: i32) -> i32 { i + j } + //~^ ERROR: first argument of `call` in `fn_mut` lang item must be a reference +} + +fn main() { + let a = || 42; + a(); + + let mut i = 0; + let mut b = || { i += 1; }; + b(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error: `call` trait item in `fn` lang item must be a function + --> $DIR/fn-fn_mut-call-ill-formed.rs:10:5 + | +LL | const call: i32 = 42; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: first argument of `call` in `fn_mut` lang item must be a reference + --> $DIR/fn-fn_mut-call-ill-formed.rs:16:16 + | +LL | fn call(i: i32, j: i32) -> i32 { i + j } + | ^^^ + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/issue-83471.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/issue-83471.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/issue-83471.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/issue-83471.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +// Regression test for the ICE reported in issue #83471. + +#![crate_type="lib"] +#![feature(no_core)] +#![no_core] + +#[lang = "sized"] +//~^ ERROR: language items are subject to change [E0658] +trait Sized {} + +#[lang = "fn"] +//~^ ERROR: language items are subject to change [E0658] +//~| ERROR: `fn` language item must be applied to a trait with 1 generic argument +trait Fn { + fn call(export_name); + //~^ ERROR: expected type + //~| WARNING: anonymous parameters are deprecated + //~| WARNING: this is accepted in the current edition +} +fn call_through_fn_trait() { + a() + //~^ ERROR: cannot find function +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/issue-83471.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/issue-83471.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/issue-83471.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/issue-83471.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +error[E0573]: expected type, found built-in attribute `export_name` + --> $DIR/issue-83471.rs:15:13 + | +LL | fn call(export_name); + | ^^^^^^^^^^^ not a type + +error[E0425]: cannot find function `a` in this scope + --> $DIR/issue-83471.rs:21:5 + | +LL | a() + | ^ not found in this scope + +error[E0658]: language items are subject to change + --> $DIR/issue-83471.rs:7:1 + | +LL | #[lang = "sized"] + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(lang_items)]` to the crate attributes to enable + +error[E0658]: language items are subject to change + --> $DIR/issue-83471.rs:11:1 + | +LL | #[lang = "fn"] + | ^^^^^^^^^^^^^^ + | + = help: add `#![feature(lang_items)]` to the crate attributes to enable + +warning: anonymous parameters are deprecated and will be removed in the next edition + --> $DIR/issue-83471.rs:15:13 + | +LL | fn call(export_name); + | ^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: export_name` + | + = note: `#[warn(anonymous_parameters)]` on by default + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #41686 + +error[E0718]: `fn` language item must be applied to a trait with 1 generic argument + --> $DIR/issue-83471.rs:11:1 + | +LL | #[lang = "fn"] + | ^^^^^^^^^^^^^^ +... +LL | trait Fn { + | - this trait has 0 generic arguments + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0425, E0573, E0658, E0718. +For more information about an error, try `rustc --explain E0425`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/lang-item-generic-requirements.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/lang-item-generic-requirements.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/lang-item-generic-requirements.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/lang-item-generic-requirements.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,8 @@ -// Checks whether declaring a lang item with the wrong number -// of generic arguments crashes the compiler (issue #83893, #87573, and part of #9307). +// Checks that declaring a lang item with the wrong number +// of generic arguments errors rather than crashing (issue #83893, #87573, part of #9307, #79559). #![feature(lang_items, no_core)] #![no_core] -#![crate_type = "lib"] #[lang = "sized"] trait MySized {} @@ -26,6 +25,14 @@ //~^ ERROR parameter `T` is never used //~| ERROR parameter `U` is never used +// When the `start` lang item is missing generics very odd things can happen, especially when +// it comes to cross-crate monomorphization +#[lang = "start"] +//~^ ERROR `start` language item must be applied to a function with 1 generic argument [E0718] +fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { + 0 +} + fn ice() { // Use add let r = 5; @@ -42,3 +49,6 @@ // Use phantomdata let _ = MyPhantomData::<(), i32>; } + +// use `start` +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/lang-item-generic-requirements.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/lang-item-generic-requirements.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lang-items/lang-item-generic-requirements.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lang-items/lang-item-generic-requirements.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error[E0718]: `add` language item must be applied to a trait with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:11:1 + --> $DIR/lang-item-generic-requirements.rs:10:1 | LL | #[lang = "add"] | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ | ------- this trait has 2 generic arguments error[E0718]: `drop_in_place` language item must be applied to a function with at least 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:15:1 + --> $DIR/lang-item-generic-requirements.rs:14:1 | LL | #[lang = "drop_in_place"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ | - this function has 0 generic arguments error[E0718]: `index` language item must be applied to a trait with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:19:1 + --> $DIR/lang-item-generic-requirements.rs:18:1 | LL | #[lang = "index"] | ^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ | ------- this trait has 2 generic arguments error[E0718]: `phantom_data` language item must be applied to a struct with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:23:1 + --> $DIR/lang-item-generic-requirements.rs:22:1 | LL | #[lang = "phantom_data"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,8 +32,17 @@ LL | struct MyPhantomData; | ------ this struct has 2 generic arguments +error[E0718]: `start` language item must be applied to a function with 1 generic argument + --> $DIR/lang-item-generic-requirements.rs:30:1 + | +LL | #[lang = "start"] + | ^^^^^^^^^^^^^^^^^ +LL | +LL | fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { + | - this function has 0 generic arguments + error[E0392]: parameter `T` is never used - --> $DIR/lang-item-generic-requirements.rs:25:22 + --> $DIR/lang-item-generic-requirements.rs:24:22 | LL | struct MyPhantomData; | ^ unused parameter @@ -42,7 +51,7 @@ = help: if you intended `T` to be a const parameter, use `const T: usize` instead error[E0392]: parameter `U` is never used - --> $DIR/lang-item-generic-requirements.rs:25:25 + --> $DIR/lang-item-generic-requirements.rs:24:25 | LL | struct MyPhantomData; | ^ unused parameter @@ -50,7 +59,7 @@ = help: consider removing `U` or referring to it in a field = help: if you intended `U` to be a const parameter, use `const U: usize` instead -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0392, E0718. For more information about an error, try `rustc --explain E0392`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/last-use-is-capture.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/last-use-is-capture.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/last-use-is-capture.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/last-use-is-capture.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,13 +3,11 @@ #![allow(dead_code)] // Make sure #1399 stays fixed -#![feature(box_syntax)] - struct A { a: Box } pub fn main() { fn invoke(f: F) where F: FnOnce() { f(); } - let k: Box<_> = box 22; + let k: Box<_> = 22.into(); let _u = A {a: k.clone()}; invoke(|| println!("{}", k.clone()) ) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/leak-unique-as-tydesc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/leak-unique-as-tydesc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/leak-unique-as-tydesc.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/leak-unique-as-tydesc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,9 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn leaky(_t: T) { } -pub fn main() { let x = box 10; leaky::>(x); } +pub fn main() { + let x = Box::new(10); + leaky::>(x); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/borrowck-let-suggestion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/borrowck-let-suggestion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/borrowck-let-suggestion.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/borrowck-let-suggestion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | creates a temporary which is freed while still in use LL | LL | x.use_mut(); - | - borrow later used here + | ----------- borrow later used here | = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/issue-77175.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/issue-77175.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/issue-77175.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/issue-77175.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +#[deny(single_use_lifetimes)] +// edition:2018 +// check-pass + +// Prior to the fix, the compiler complained that the 'a lifetime was only used +// once. This was obviously wrong since the lifetime is used twice: For the s3 +// parameter and the return type. The issue was caused by the compiler +// desugaring the async function into a generator that uses only a single +// lifetime, which then the validator complained about becauase of the +// single_use_lifetimes constraints. +async fn bar<'a>(s1: String, s2: &'_ str, s3: &'a str) -> &'a str { + s3 +} + +fn foo<'a>(s1: String, s2: &'_ str, s3: &'a str) -> &'a str { + s3 +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187-2.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187-2.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187-2.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187-2.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,6 +38,11 @@ | LL | take_foo(|a| a); | ^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:9:5 @@ -47,6 +52,11 @@ | = note: expected reference `&i32` found reference `&i32` +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:10:5 @@ -56,6 +66,11 @@ | = note: expected reference `&i32` found reference `&i32` +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -25,7 +25,7 @@ | = note: expected reference `&i32` found reference `&i32` -note: the anonymous lifetime #1 defined on the body at 9:14 doesn't meet the lifetime requirements +note: the anonymous lifetime #1 defined here doesn't meet the lifetime requirements --> $DIR/issue-79187-2.rs:9:14 | LL | take_foo(|a: &i32| a); @@ -44,7 +44,7 @@ | = note: expected reference `&i32` found reference `&i32` -note: the anonymous lifetime #1 defined on the body at 10:14 doesn't meet the lifetime requirements +note: the anonymous lifetime #1 defined here doesn't meet the lifetime requirements --> $DIR/issue-79187-2.rs:10:14 | LL | take_foo(|a: &i32| -> &i32 { a }); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/issue-79187.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -11,6 +11,11 @@ | LL | let f = |_| (); | ^^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/issue-79187.rs:1:18 + | +LL | fn thing(x: impl FnOnce(&u32)) {} + | ^^^^^^^^^^^^ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,23 +2,29 @@ --> $DIR/lifetime-bound-will-change-warning.rs:34:5 | LL | fn test2<'a>(x: &'a Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | // but ref_obj will not, so warn. LL | ref_obj(x) - | ^^^^^^^^^^ `x` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/lifetime-bound-will-change-warning.rs:39:5 | LL | fn test2cc<'a>(x: &'a Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | // same as test2, but cross crate LL | lib::ref_obj(x) - | ^^^^^^^^^^^^^^^ `x` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected reference `&Box<(dyn Fn() + 'static)>` found reference `&Box<(dyn Fn() + 'a)>` -note: the lifetime `'a` as defined on the function body at 32:10... +note: the lifetime `'a` as defined here... --> $DIR/lifetime-bound-will-change-warning.rs:32:10 | LL | fn test2<'a>(x: &'a Box) { @@ -21,7 +21,7 @@ | = note: expected reference `&Box<(dyn Fn() + 'static)>` found reference `&Box<(dyn Fn() + 'a)>` -note: the lifetime `'a` as defined on the function body at 37:12... +note: the lifetime `'a` as defined here... --> $DIR/lifetime-bound-will-change-warning.rs:37:12 | LL | fn test2cc<'a>(x: &'a Box) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,3 @@ -error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable - --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 - | -LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { - | - help: consider changing this to be mutable: `mut y` -LL | y.push(z); - | ^ cannot borrow as mutable - error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 | @@ -16,6 +8,14 @@ LL | y.push(z); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable + --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 + | +LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { + | - help: consider changing this to be mutable: `mut y` +LL | y.push(z); + | ^^^^^^^^^ cannot borrow as mutable + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0596`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,3 @@ -error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable - --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 - | -LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { - | - help: consider changing this to be mutable: `mut y` -LL | y.push(z); - | ^ cannot borrow as mutable - error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 | @@ -16,6 +8,14 @@ LL | y.push(z); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable + --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 + | +LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { + | - help: consider changing this to be mutable: `mut y` +LL | y.push(z); + | ^^^^^^^^^ cannot borrow as mutable + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0596`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,35 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/issue_74400.rs:12:5 + | +LL | f(data, identity) + | ^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error[E0308]: mismatched types + --> $DIR/issue_74400.rs:12:5 + | +LL | f(data, identity) + | ^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected type `for<'r> Fn<(&'r T,)>` + found type `Fn<(&T,)>` +note: the lifetime requirement is introduced here + --> $DIR/issue_74400.rs:8:34 + | +LL | fn f(data: &[T], key: impl Fn(&T) -> S) { + | ^^^^^^^^^^^ + +error: implementation of `FnOnce` is not general enough + --> $DIR/issue_74400.rs:12:5 + | +LL | f(data, identity) + | ^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `FnOnce<(&'1 T,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 T,)>`, for some specific lifetime `'2` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0310. +For more information about an error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +//! Regression test for #74400: Type mismatch in function arguments E0631, E0271 are falsely +//! recognized as E0308 mismatched types. + +use std::convert::identity; + +fn main() {} + +fn f(data: &[T], key: impl Fn(&T) -> S) { +} + +fn g(data: &[T]) { + f(data, identity) //~ ERROR implementation of `FnOnce` is not general +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/issue_74400.rs:12:5 + | +LL | f(data, identity) + | ^ implementation of `FnOnce` is not general enough + | + = note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `FnOnce<(&'1 T,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 T,)>`, for some specific lifetime `'2` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,17 @@ = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 + | +LL | #[derive(Eq, PartialEq)] + | -- lifetime `'b` is missing in item created through this procedural macro +LL | struct Test { +LL | a: &'b str, + | ^^ undeclared lifetime + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:13:13 | LL | fn foo(&'b self) {} @@ -24,17 +35,6 @@ LL | fn foo<'b>(&'b self) {} | ++++ -error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9 - | -LL | #[derive(Eq, PartialEq)] - | -- lifetime `'b` is missing in item created through this procedural macro -LL | struct Test { -LL | a: &'b str, - | ^^ undeclared lifetime - | - = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0261`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/enable-unstable-lib-feature.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/enable-unstable-lib-feature.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/enable-unstable-lib-feature.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/enable-unstable-lib-feature.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +// Test that enabling an unstable feature disables warnings + +// aux-build:stability-cfg2.rs + +#![feature(unstable_test_feature)] +#![deny(non_snake_case)] // To trigger a hard error + +// Shouldn't generate a warning about unstable features +extern crate stability_cfg2; + +pub fn BOGUS() { } //~ ERROR + +pub fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/enable-unstable-lib-feature.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/enable-unstable-lib-feature.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/enable-unstable-lib-feature.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/enable-unstable-lib-feature.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +error: function `BOGUS` should have a snake case name + --> $DIR/enable-unstable-lib-feature.rs:11:8 + | +LL | pub fn BOGUS() { } + | ^^^^^ help: convert the identifier to snake case: `bogus` + | +note: the lint level is defined here + --> $DIR/enable-unstable-lib-feature.rs:6:9 + | +LL | #![deny(non_snake_case)] // To trigger a hard error + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-57410.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-57410.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-57410.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-57410.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +// check-pass + +// Tests that the `unreachable_pub` lint doesn't fire for `pub self::imp::f`. + +#![deny(unreachable_pub)] + +mod m { + mod imp { + pub fn f() {} + } + + pub use self::imp::f; +} + +pub use self::m::f; + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,8 +21,6 @@ #![deny(unused)] //~^ ERROR: deny(unused) incompatible with previous forbid //~| WARNING being phased out - //~| ERROR: deny(unused) incompatible with previous forbid - //~| WARNING being phased out #![warn(unused)] #![allow(unused)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -14,16 +14,5 @@ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #81670 -error: deny(unused) incompatible with previous forbid - --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13 - | -LL | #![forbid(unused)] - | ------ `forbid` level set here -LL | #![deny(unused)] - | ^^^^^^ overruled by previous forbid - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #81670 - -error: aborting due to 2 previous errors +error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-79546-fuel-ice.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-79546-fuel-ice.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-79546-fuel-ice.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-79546-fuel-ice.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +// Regression test for the ICE described in #79546. + +// compile-flags: --cap-lints=allow -Zfuel=issue79546=0 +// check-pass +#![crate_name="issue79546"] + +struct S; +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-79744.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-79744.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-79744.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-79744.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +fn main() { + let elem = 6i8; + let e2 = 230; + //~^ ERROR literal out of range for `i8` + //~| HELP consider using the type `u8` instead + + let mut vec = Vec::new(); + + vec.push(e2); + vec.push(elem); + + println!("{:?}", vec); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-79744.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-79744.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-79744.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-79744.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +error: literal out of range for `i8` + --> $DIR/issue-79744.rs:3:14 + | +LL | let e2 = 230; + | ^^^ + | + = note: `#[deny(overflowing_literals)]` on by default + = note: the literal `230` does not fit into the type `i8` whose range is `-128..=127` + = help: consider using the type `u8` instead + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-87308.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-87308.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-87308.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-87308.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// Regression test for issue #87308. + +// compile-flags: -Zunpretty=everybody_loops +// check-pass + +macro_rules! foo { + () => { break 'x; } +} + +pub fn main() { + 'x: loop { foo!() } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-87308.stdout rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-87308.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-87308.stdout 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-87308.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +// Regression test for issue #87308. + +// compile-flags: -Zunpretty=everybody_loops +// check-pass + +macro_rules! foo { () => { break 'x ; } } + +pub fn main() { loop { } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-89469.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-89469.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-89469.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-89469.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +// Regression test for #89469, where an extra non_snake_case warning was +// reported for a shorthand field binding. + +// check-pass +#![deny(non_snake_case)] + +#[allow(non_snake_case)] +struct Entry { + A: u16, + a: u16 +} + +fn foo() -> Entry {todo!()} + +pub fn f() { + let Entry { A, a } = foo(); + let _ = (A, a); +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +// check-pass +// Allowing the code lint should work without warning and +// the text flow char in the comment should be ignored. + +#![allow(text_direction_codepoint_in_comment)] + +fn main() { + // U+2066 LEFT-TO-RIGHT ISOLATE follows:â¦â¦ +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/known-tool-in-submodule/root.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/known-tool-in-submodule/root.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/known-tool-in-submodule/root.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/known-tool-in-submodule/root.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +// check-pass + +#![feature(register_tool)] +#![register_tool(tool)] + +mod submodule; + +fn main() { + submodule::foo(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/known-tool-in-submodule/submodule.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/known-tool-in-submodule/submodule.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/known-tool-in-submodule/submodule.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/known-tool-in-submodule/submodule.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,4 @@ +// ignore-test: not a test + +#[allow(tool::lint)] +pub fn foo() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes-fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes-fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes-fn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes-fn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -66,6 +66,10 @@ pub extern "C" fn ptr_type2(size: *const Foo) { } +pub extern "C" fn ptr_unit(p: *const ()) { } + +pub extern "C" fn ptr_tuple(p: *const ((),)) { } + pub extern "C" fn slice_type(p: &[u32]) { } //~^ ERROR: uses type `[u32]` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes-fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes-fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ error: `extern` fn uses type `[u32]`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:69:33 + --> $DIR/lint-ctypes-fn.rs:73:33 | LL | pub extern "C" fn slice_type(p: &[u32]) { } | ^^^^^^ not FFI-safe @@ -13,7 +13,7 @@ = note: slices have no C equivalent error: `extern` fn uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:72:31 + --> $DIR/lint-ctypes-fn.rs:76:31 | LL | pub extern "C" fn str_type(p: &str) { } | ^^^^ not FFI-safe @@ -22,7 +22,7 @@ = note: string slices have no C equivalent error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:79:34 + --> $DIR/lint-ctypes-fn.rs:83:34 | LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { } | ^^^^^^^^^ not FFI-safe @@ -30,7 +30,7 @@ = note: box cannot be represented as a single pointer error: `extern` fn uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:82:35 + --> $DIR/lint-ctypes-fn.rs:86:35 | LL | pub extern "C" fn boxed_string(p: Box) { } | ^^^^^^^^ not FFI-safe @@ -38,7 +38,7 @@ = note: box cannot be represented as a single pointer error: `extern` fn uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:85:34 + --> $DIR/lint-ctypes-fn.rs:89:34 | LL | pub extern "C" fn boxed_trait(p: Box) { } | ^^^^^^^^^^^^^^ not FFI-safe @@ -46,7 +46,7 @@ = note: box cannot be represented as a single pointer error: `extern` fn uses type `char`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:88:32 + --> $DIR/lint-ctypes-fn.rs:92:32 | LL | pub extern "C" fn char_type(p: char) { } | ^^^^ not FFI-safe @@ -55,7 +55,7 @@ = note: the `char` type has no C equivalent error: `extern` fn uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:91:32 + --> $DIR/lint-ctypes-fn.rs:95:32 | LL | pub extern "C" fn i128_type(p: i128) { } | ^^^^ not FFI-safe @@ -63,7 +63,7 @@ = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:94:32 + --> $DIR/lint-ctypes-fn.rs:98:32 | LL | pub extern "C" fn u128_type(p: u128) { } | ^^^^ not FFI-safe @@ -71,7 +71,7 @@ = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:97:33 + --> $DIR/lint-ctypes-fn.rs:101:33 | LL | pub extern "C" fn tuple_type(p: (i32, i32)) { } | ^^^^^^^^^^ not FFI-safe @@ -80,7 +80,7 @@ = note: tuples have unspecified layout error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:100:34 + --> $DIR/lint-ctypes-fn.rs:104:34 | LL | pub extern "C" fn tuple_type2(p: I32Pair) { } | ^^^^^^^ not FFI-safe @@ -89,7 +89,7 @@ = note: tuples have unspecified layout error: `extern` fn uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:103:32 + --> $DIR/lint-ctypes-fn.rs:107:32 | LL | pub extern "C" fn zero_size(p: ZeroSize) { } | ^^^^^^^^ not FFI-safe @@ -103,7 +103,7 @@ | ^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:106:40 + --> $DIR/lint-ctypes-fn.rs:110:40 | LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { } | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -116,7 +116,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:109:51 + --> $DIR/lint-ctypes-fn.rs:113:51 | LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -124,7 +124,7 @@ = note: composed only of `PhantomData` error: `extern` fn uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:114:30 + --> $DIR/lint-ctypes-fn.rs:118:30 | LL | pub extern "C" fn fn_type(p: RustFn) { } | ^^^^^^ not FFI-safe @@ -133,7 +133,7 @@ = note: this function pointer has Rust-specific calling convention error: `extern` fn uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:117:31 + --> $DIR/lint-ctypes-fn.rs:121:31 | LL | pub extern "C" fn fn_type2(p: fn()) { } | ^^^^ not FFI-safe @@ -142,7 +142,7 @@ = note: this function pointer has Rust-specific calling convention error: `extern` fn uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:122:39 + --> $DIR/lint-ctypes-fn.rs:126:39 | LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } | ^^^^^^^^^^^^^^^ not FFI-safe @@ -150,7 +150,7 @@ = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:125:38 + --> $DIR/lint-ctypes-fn.rs:129:38 | LL | pub extern "C" fn transparent_str(p: TransparentStr) { } | ^^^^^^^^^^^^^^ not FFI-safe @@ -159,7 +159,7 @@ = note: string slices have no C equivalent error: `extern` fn uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:171:43 + --> $DIR/lint-ctypes-fn.rs:175:43 | LL | pub extern "C" fn unused_generic2() -> PhantomData { | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -167,7 +167,7 @@ = note: composed only of `PhantomData` error: `extern` fn uses type `Vec`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:184:39 + --> $DIR/lint-ctypes-fn.rs:188:39 | LL | pub extern "C" fn used_generic4(x: Vec) { } | ^^^^^^ not FFI-safe @@ -176,7 +176,7 @@ = note: this struct has unspecified layout error: `extern` fn uses type `Vec`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:187:41 + --> $DIR/lint-ctypes-fn.rs:191:41 | LL | pub extern "C" fn used_generic5() -> Vec { | ^^^^^^ not FFI-safe diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes.rs 2021-11-29 19:27:11.000000000 +0000 @@ -47,6 +47,8 @@ extern "C" { pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo` pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` + pub fn ptr_unit(p: *const ()); + pub fn ptr_tuple(p: *const ((),)); //~ ERROR: uses type `((),)` pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` pub fn str_type(p: &str); //~ ERROR: uses type `str` pub fn box_type(p: Box); //~ ERROR uses type `Box` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-ctypes.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -31,8 +31,17 @@ LL | pub struct Foo; | ^^^^^^^^^^^^^^^ +error: `extern` block uses type `((),)`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:51:25 + | +LL | pub fn ptr_tuple(p: *const ((),)); + | ^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a struct instead + = note: tuples have unspecified layout + error: `extern` block uses type `[u32]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:50:26 + --> $DIR/lint-ctypes.rs:52:26 | LL | pub fn slice_type(p: &[u32]); | ^^^^^^ not FFI-safe @@ -41,7 +50,7 @@ = note: slices have no C equivalent error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:51:24 + --> $DIR/lint-ctypes.rs:53:24 | LL | pub fn str_type(p: &str); | ^^^^ not FFI-safe @@ -50,7 +59,7 @@ = note: string slices have no C equivalent error: `extern` block uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:52:24 + --> $DIR/lint-ctypes.rs:54:24 | LL | pub fn box_type(p: Box); | ^^^^^^^^ not FFI-safe @@ -59,7 +68,7 @@ = note: this struct has unspecified layout error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:53:28 + --> $DIR/lint-ctypes.rs:55:28 | LL | pub fn opt_box_type(p: Option>); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -68,7 +77,7 @@ = note: enum has no representation hint error: `extern` block uses type `char`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:55:25 + --> $DIR/lint-ctypes.rs:57:25 | LL | pub fn char_type(p: char); | ^^^^ not FFI-safe @@ -77,7 +86,7 @@ = note: the `char` type has no C equivalent error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:56:25 + --> $DIR/lint-ctypes.rs:58:25 | LL | pub fn i128_type(p: i128); | ^^^^ not FFI-safe @@ -85,7 +94,7 @@ = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:57:25 + --> $DIR/lint-ctypes.rs:59:25 | LL | pub fn u128_type(p: u128); | ^^^^ not FFI-safe @@ -93,7 +102,7 @@ = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `dyn Bar`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:58:26 + --> $DIR/lint-ctypes.rs:60:26 | LL | pub fn trait_type(p: &dyn Bar); | ^^^^^^^^ not FFI-safe @@ -101,7 +110,7 @@ = note: trait objects have no C equivalent error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:59:26 + --> $DIR/lint-ctypes.rs:61:26 | LL | pub fn tuple_type(p: (i32, i32)); | ^^^^^^^^^^ not FFI-safe @@ -110,7 +119,7 @@ = note: tuples have unspecified layout error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:60:27 + --> $DIR/lint-ctypes.rs:62:27 | LL | pub fn tuple_type2(p: I32Pair); | ^^^^^^^ not FFI-safe @@ -119,7 +128,7 @@ = note: tuples have unspecified layout error: `extern` block uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:61:25 + --> $DIR/lint-ctypes.rs:63:25 | LL | pub fn zero_size(p: ZeroSize); | ^^^^^^^^ not FFI-safe @@ -133,7 +142,7 @@ | ^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:62:33 + --> $DIR/lint-ctypes.rs:64:33 | LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -146,7 +155,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:65:12 + --> $DIR/lint-ctypes.rs:67:12 | LL | -> ::std::marker::PhantomData; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -154,7 +163,7 @@ = note: composed only of `PhantomData` error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:66:23 + --> $DIR/lint-ctypes.rs:68:23 | LL | pub fn fn_type(p: RustFn); | ^^^^^^ not FFI-safe @@ -163,7 +172,7 @@ = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:67:24 + --> $DIR/lint-ctypes.rs:69:24 | LL | pub fn fn_type2(p: fn()); | ^^^^ not FFI-safe @@ -172,7 +181,7 @@ = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:68:28 + --> $DIR/lint-ctypes.rs:70:28 | LL | pub fn fn_contained(p: RustBadRet); | ^^^^^^^^^^ not FFI-safe @@ -181,7 +190,7 @@ = note: this struct has unspecified layout error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:69:32 + --> $DIR/lint-ctypes.rs:71:32 | LL | pub fn transparent_i128(p: TransparentI128); | ^^^^^^^^^^^^^^^ not FFI-safe @@ -189,7 +198,7 @@ = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:70:31 + --> $DIR/lint-ctypes.rs:72:31 | LL | pub fn transparent_str(p: TransparentStr); | ^^^^^^^^^^^^^^ not FFI-safe @@ -198,7 +207,7 @@ = note: string slices have no C equivalent error: `extern` block uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:71:30 + --> $DIR/lint-ctypes.rs:73:30 | LL | pub fn transparent_fn(p: TransparentBadFn); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -207,7 +216,7 @@ = note: this struct has unspecified layout error: `extern` block uses type `[u8; 8]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:72:27 + --> $DIR/lint-ctypes.rs:74:27 | LL | pub fn raw_array(arr: [u8; 8]); | ^^^^^^^ not FFI-safe @@ -216,7 +225,7 @@ = note: passing raw arrays by value is not FFI-safe error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:74:26 + --> $DIR/lint-ctypes.rs:76:26 | LL | pub fn no_niche_a(a: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -225,7 +234,7 @@ = note: enum has no representation hint error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:76:26 + --> $DIR/lint-ctypes.rs:78:26 | LL | pub fn no_niche_b(b: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -234,7 +243,7 @@ = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:79:34 + --> $DIR/lint-ctypes.rs:81:34 | LL | pub static static_u128_type: u128; | ^^^^ not FFI-safe @@ -242,12 +251,12 @@ = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:80:40 + --> $DIR/lint-ctypes.rs:82:40 | LL | pub static static_u128_array_type: [u128; 16]; | ^^^^^^^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-enum-intrinsics-non-enums.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-enum-intrinsics-non-enums.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-enum-intrinsics-non-enums.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-enum-intrinsics-non-enums.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,67 @@ +// Test the enum_intrinsics_non_enums lint. + +#![feature(variant_count)] + +use std::mem::{discriminant, variant_count}; + +enum SomeEnum { + A, + B, +} + +struct SomeStruct; + +fn generic_discriminant(v: &T) { + discriminant::(v); +} + +fn generic_variant_count() -> usize { + variant_count::() +} + +fn test_discriminant() { + discriminant(&SomeEnum::A); + generic_discriminant(&SomeEnum::B); + + discriminant(&()); + //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + + discriminant(&&SomeEnum::B); + //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + + discriminant(&SomeStruct); + //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + + discriminant(&123u32); + //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + + discriminant(&&123i8); + //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type +} + +fn test_variant_count() { + variant_count::(); + generic_variant_count::(); + + variant_count::<&str>(); + //~^ error: the return value of `mem::variant_count` is unspecified when called with a non-enum type + + variant_count::<*const u8>(); + //~^ error: the return value of `mem::variant_count` is unspecified when called with a non-enum type + + variant_count::<()>(); + //~^ error: the return value of `mem::variant_count` is unspecified when called with a non-enum type + + variant_count::<&SomeEnum>(); + //~^ error: the return value of `mem::variant_count` is unspecified when called with a non-enum type +} + +fn main() { + test_discriminant(); + test_variant_count(); + + // The lint ignores cases where the type is generic, so these should be + // allowed even though their return values are unspecified + generic_variant_count::(); + generic_discriminant::(&SomeStruct); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-enum-intrinsics-non-enums.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-enum-intrinsics-non-enums.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-enum-intrinsics-non-enums.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-enum-intrinsics-non-enums.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,95 @@ +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:26:5 + | +LL | discriminant(&()); + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(enum_intrinsics_non_enums)]` on by default +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `()`, which is not an enum. + --> $DIR/lint-enum-intrinsics-non-enums.rs:26:18 + | +LL | discriminant(&()); + | ^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:29:5 + | +LL | discriminant(&&SomeEnum::B); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&SomeEnum`, which is not an enum. + --> $DIR/lint-enum-intrinsics-non-enums.rs:29:18 + | +LL | discriminant(&&SomeEnum::B); + | ^^^^^^^^^^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:32:5 + | +LL | discriminant(&SomeStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `SomeStruct`, which is not an enum. + --> $DIR/lint-enum-intrinsics-non-enums.rs:32:18 + | +LL | discriminant(&SomeStruct); + | ^^^^^^^^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:35:5 + | +LL | discriminant(&123u32); + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `u32`, which is not an enum. + --> $DIR/lint-enum-intrinsics-non-enums.rs:35:18 + | +LL | discriminant(&123u32); + | ^^^^^^^ + +error: the return value of `mem::discriminant` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:38:5 + | +LL | discriminant(&&123i8); + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&i8`, which is not an enum. + --> $DIR/lint-enum-intrinsics-non-enums.rs:38:18 + | +LL | discriminant(&&123i8); + | ^^^^^^^ + +error: the return value of `mem::variant_count` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:46:5 + | +LL | variant_count::<&str>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&str`, which is not an enum. + +error: the return value of `mem::variant_count` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:49:5 + | +LL | variant_count::<*const u8>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `*const u8`, which is not an enum. + +error: the return value of `mem::variant_count` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:52:5 + | +LL | variant_count::<()>(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `()`, which is not an enum. + +error: the return value of `mem::variant_count` is unspecified when called with a non-enum type + --> $DIR/lint-enum-intrinsics-non-enums.rs:55:5 + | +LL | variant_count::<&SomeEnum>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&SomeEnum`, which is not an enum. + +error: aborting due to 9 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-malformed.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-malformed.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-malformed.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-malformed.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -14,7 +14,7 @@ --> $DIR/lint-malformed.rs:1:1 | LL | #![deny = "foo"] - | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]` + | ^^^^^^^^^^^^^^^^ help: must be of the form: `#![deny(lint1, lint2, ..., /*opt*/ reason = "...")]` error[E0452]: malformed lint attribute input --> $DIR/lint-malformed.rs:2:10 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-owned-heap-memory.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-owned-heap-memory.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-owned-heap-memory.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-owned-heap-memory.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,12 @@ #![allow(dead_code)] #![forbid(box_pointers)] -#![feature(box_syntax)] + struct Foo { x: Box //~ ERROR type uses owned } fn main() { - let _x : Foo = Foo {x : box 10}; + let _x: Foo = Foo { x : Box::new(10) }; //~^ ERROR type uses owned } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-owned-heap-memory.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-owned-heap-memory.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-owned-heap-memory.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-owned-heap-memory.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,8 +13,8 @@ error: type uses owned (Box type) pointers: Box --> $DIR/lint-owned-heap-memory.rs:10:29 | -LL | let _x : Foo = Foo {x : box 10}; - | ^^^^^^ +LL | let _x: Foo = Foo { x : Box::new(10) }; + | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lints-in-foreign-macros.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lints-in-foreign-macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lints-in-foreign-macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lints-in-foreign-macros.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^ ... LL | mod a { foo!(); } - | ------- in this macro invocation + | ------ in this macro invocation | note: the lint level is defined here --> $DIR/lints-in-foreign-macros.rs:4:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-stability2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-stability2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-stability2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-stability2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/lint-stability2.rs:12:5 | LL | macro_test!(); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-stability2.rs:4:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-unnecessary-parens.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-unnecessary-parens.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/lint-unnecessary-parens.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/lint-unnecessary-parens.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,109 +2,210 @@ --> $DIR/lint-unnecessary-parens.rs:13:12 | LL | return (1); - | ^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/lint-unnecessary-parens.rs:3:9 | LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - return (1); +LL + return 1; + | error: unnecessary parentheses around `return` value --> $DIR/lint-unnecessary-parens.rs:16:12 | LL | return (X { y }); - | ^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - return (X { y }); +LL + return X { y }; + | error: unnecessary parentheses around type --> $DIR/lint-unnecessary-parens.rs:19:46 | LL | pub fn unused_parens_around_return_type() -> (u32) { - | ^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn unused_parens_around_return_type() -> (u32) { +LL + pub fn unused_parens_around_return_type() -> u32 { + | error: unnecessary parentheses around block return value --> $DIR/lint-unnecessary-parens.rs:25:9 | LL | (5) - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (5) +LL + 5 + | error: unnecessary parentheses around block return value --> $DIR/lint-unnecessary-parens.rs:27:5 | LL | (5) - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (5) +LL + 5 + | error: unnecessary parentheses around assigned value --> $DIR/lint-unnecessary-parens.rs:44:31 | LL | pub const CONST_ITEM: usize = (10); - | ^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - pub const CONST_ITEM: usize = (10); +LL + pub const CONST_ITEM: usize = 10; + | error: unnecessary parentheses around assigned value --> $DIR/lint-unnecessary-parens.rs:45:33 | LL | pub static STATIC_ITEM: usize = (10); - | ^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - pub static STATIC_ITEM: usize = (10); +LL + pub static STATIC_ITEM: usize = 10; + | error: unnecessary parentheses around function argument --> $DIR/lint-unnecessary-parens.rs:49:9 | LL | bar((true)); - | ^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - bar((true)); +LL + bar(true); + | error: unnecessary parentheses around `if` condition --> $DIR/lint-unnecessary-parens.rs:51:8 | LL | if (true) {} - | ^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if (true) {} +LL + if true {} + | error: unnecessary parentheses around `while` condition --> $DIR/lint-unnecessary-parens.rs:52:11 | LL | while (true) {} - | ^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - while (true) {} +LL + while true {} + | error: unnecessary parentheses around `match` scrutinee expression --> $DIR/lint-unnecessary-parens.rs:53:11 | LL | match (true) { - | ^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - match (true) { +LL + match true { + | error: unnecessary parentheses around `let` scrutinee expression --> $DIR/lint-unnecessary-parens.rs:56:16 | LL | if let 1 = (1) {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let 1 = (1) {} +LL + if let 1 = 1 {} + | error: unnecessary parentheses around `let` scrutinee expression --> $DIR/lint-unnecessary-parens.rs:57:19 | LL | while let 1 = (2) {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - while let 1 = (2) {} +LL + while let 1 = 2 {} + | error: unnecessary parentheses around method argument --> $DIR/lint-unnecessary-parens.rs:73:24 | LL | X { y: false }.foo((true)); - | ^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - X { y: false }.foo((true)); +LL + X { y: false }.foo(true); + | error: unnecessary parentheses around assigned value --> $DIR/lint-unnecessary-parens.rs:75:18 | LL | let mut _a = (0); - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - let mut _a = (0); +LL + let mut _a = 0; + | error: unnecessary parentheses around assigned value --> $DIR/lint-unnecessary-parens.rs:76:10 | LL | _a = (0); - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - _a = (0); +LL + _a = 0; + | error: unnecessary parentheses around assigned value --> $DIR/lint-unnecessary-parens.rs:77:11 | LL | _a += (1); - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - _a += (1); +LL + _a += 1; + | error: aborting due to 17 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/boxed.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/boxed.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/boxed.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/boxed.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,25 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend = "You gotta use Umm's, ya know?"] +struct Umm { + i: i64 +} + + +fn bar() -> Box { + Box::new(Umm { + i: 1 + }) +} + +async fn other() {} + +pub async fn uhoh() { + let _guard = bar(); //~ ERROR boxed `Umm` held across + other().await; +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/boxed.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/boxed.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/boxed.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/boxed.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +error: boxed `Umm` held across a suspend point, but should not be + --> $DIR/boxed.rs:20:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/boxed.rs:3:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +note: You gotta use Umm's, ya know? + --> $DIR/boxed.rs:20:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/boxed.rs:20:9 + | +LL | let _guard = bar(); + | ^^^^^^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/dedup.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/dedup.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/dedup.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/dedup.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend] +struct No {} + +async fn shushspend() {} + +async fn wheeee(t: T) { + shushspend().await; + drop(t); +} + +async fn yes() { + wheeee(No {}).await; //~ ERROR `No` held across +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/dedup.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/dedup.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/dedup.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/dedup.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +error: `No` held across a suspend point, but should not be + --> $DIR/dedup.rs:16:12 + | +LL | wheeee(No {}).await; + | -------^^^^^------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/dedup.rs:3:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/dedup.rs:16:12 + | +LL | wheeee(No {}).await; + | ^^^^^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/feature-gate-must_not_suspend.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/feature-gate-must_not_suspend.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/feature-gate-must_not_suspend.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/feature-gate-must_not_suspend.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +// edition:2018 + +#[must_not_suspend = "You gotta use Umm's, ya know?"] //~ ERROR the `#[must_not_suspend]` +struct Umm { + _i: i64 +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/feature-gate-must_not_suspend.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/feature-gate-must_not_suspend.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/feature-gate-must_not_suspend.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/feature-gate-must_not_suspend.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +error[E0658]: the `#[must_not_suspend]` attribute is an experimental feature + --> $DIR/feature-gate-must_not_suspend.rs:3:1 + | +LL | #[must_not_suspend = "You gotta use Umm's, ya know?"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #83310 for more information + = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/gated.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/gated.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/gated.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/gated.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// edition:2018 +#![deny(must_not_suspend)] //~ ERROR the `must_not_suspend` +//~| ERROR the `must_not_suspend` +//~| ERROR the `must_not_suspend` + +async fn other() {} + +pub async fn uhoh(m: std::sync::Mutex<()>) { + let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across + other().await; +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/gated.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/gated.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/gated.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/gated.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,54 @@ +error[E0658]: the `must_not_suspend` lint is unstable + --> $DIR/gated.rs:2:1 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #83310 for more information + = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable + +error[E0658]: the `must_not_suspend` lint is unstable + --> $DIR/gated.rs:2:1 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #83310 for more information + = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable + +error[E0658]: the `must_not_suspend` lint is unstable + --> $DIR/gated.rs:2:1 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #83310 for more information + = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable + +error: `MutexGuard` held across a suspend point, but should not be + --> $DIR/gated.rs:9:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ +LL | other().await; + | ------------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/gated.rs:2:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send` + --> $DIR/gated.rs:9:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/gated.rs:9:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/generic.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/generic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/generic.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/generic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +// edition:2018 +// run-pass +// +// this test shows a case where the lint doesn't fire in generic code +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend] +struct No {} + +async fn shushspend() {} + +async fn wheeee(t: T) { + shushspend().await; + drop(t); +} + +fn main() { + let _fut = wheeee(No {}); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/handled.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/handled.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/handled.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/handled.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,28 @@ +// edition:2018 +// run-pass +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend = "You gotta use Umm's, ya know?"] +struct Umm { + _i: i64 +} + + +fn bar() -> Umm { + Umm { + _i: 1 + } +} + +async fn other() {} + +pub async fn uhoh() { + { + let _guard = bar(); + } + other().await; +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/issue-89562.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/issue-89562.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/issue-89562.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/issue-89562.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +// edition:2018 +// run-pass + +use std::sync::Mutex; + +// Copied from the issue. Allow-by-default for now, so run-pass +pub async fn foo() { + let foo = Mutex::new(1); + let lock = foo.lock().unwrap(); + + // Prevent mutex lock being held across `.await` point. + drop(lock); + + bar().await; +} + +async fn bar() {} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/mutex.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/mutex.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/mutex.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/mutex.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +async fn other() {} + +pub async fn uhoh(m: std::sync::Mutex<()>) { + let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across + other().await; +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/mutex.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/mutex.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/mutex.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/mutex.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +error: `MutexGuard` held across a suspend point, but should not be + --> $DIR/mutex.rs:8:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ +LL | other().await; + | ------------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/mutex.rs:3:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send` + --> $DIR/mutex.rs:8:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/mutex.rs:8:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/other_items.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/other_items.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/other_items.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/other_items.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend] //~ ERROR attribute should be +mod inner {} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/other_items.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/other_items.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/other_items.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/other_items.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: `must_not_suspend` attribute should be applied to a struct, enum, or trait + --> $DIR/other_items.rs:5:1 + | +LL | #[must_not_suspend] + | ^^^^^^^^^^^^^^^^^^^ +LL | mod inner {} + | ------------ is not a struct, enum, or trait + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/ref.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/ref.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/ref.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/ref.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend = "You gotta use Umm's, ya know?"] +struct Umm { + i: i64 +} + +struct Bar { + u: Umm, +} + +async fn other() {} + +impl Bar { + async fn uhoh(&mut self) { + let guard = &mut self.u; //~ ERROR `Umm` held across + + other().await; + + *guard = Umm { + i: 2 + } + } +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/ref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/ref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/ref.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/ref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,27 @@ +error: `Umm` held across a suspend point, but should not be + --> $DIR/ref.rs:18:26 + | +LL | let guard = &mut self.u; + | ^^^^^^ +LL | +LL | other().await; + | ------------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/ref.rs:3:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +note: You gotta use Umm's, ya know? + --> $DIR/ref.rs:18:26 + | +LL | let guard = &mut self.u; + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/ref.rs:18:26 + | +LL | let guard = &mut self.u; + | ^^^^^^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/return.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/return.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/return.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/return.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend] //~ ERROR attribute should be +fn foo() -> i32 { + 0 +} +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/return.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/return.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/return.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/return.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +error: `must_not_suspend` attribute should be applied to a struct, enum, or trait + --> $DIR/return.rs:5:1 + | +LL | #[must_not_suspend] + | ^^^^^^^^^^^^^^^^^^^ +LL | / fn foo() -> i32 { +LL | | 0 +LL | | } + | |_- is not a struct, enum, or trait + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/trait.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,28 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend] +trait Wow {} + +impl Wow for i32 {} + +fn r#impl() -> impl Wow { + 1 +} + +fn r#dyn() -> Box { + Box::new(1) +} + +async fn other() {} + +pub async fn uhoh() { + let _guard1 = r#impl(); //~ ERROR implementer of `Wow` held across + let _guard2 = r#dyn(); //~ ERROR boxed `Wow` trait object held across + + other().await; +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/trait.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,37 @@ +error: implementer of `Wow` held across a suspend point, but should not be + --> $DIR/trait.rs:21:9 + | +LL | let _guard1 = r#impl(); + | ^^^^^^^ +... +LL | other().await; + | ------------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/trait.rs:3:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/trait.rs:21:9 + | +LL | let _guard1 = r#impl(); + | ^^^^^^^ + +error: boxed `Wow` trait object held across a suspend point, but should not be + --> $DIR/trait.rs:22:9 + | +LL | let _guard2 = r#dyn(); + | ^^^^^^^ +LL | +LL | other().await; + | ------------- the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/trait.rs:22:9 + | +LL | let _guard2 = r#dyn(); + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/unit.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/unit.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/unit.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/unit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,25 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + +#[must_not_suspend = "You gotta use Umm's, ya know?"] +struct Umm { + i: i64 +} + + +fn bar() -> Umm { + Umm { + i: 1 + } +} + +async fn other() {} + +pub async fn uhoh() { + let _guard = bar(); //~ ERROR `Umm` held across + other().await; +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/unit.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/unit.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/unit.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/unit.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +error: `Umm` held across a suspend point, but should not be + --> $DIR/unit.rs:20:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/unit.rs:3:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +note: You gotta use Umm's, ya know? + --> $DIR/unit.rs:20:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/unit.rs:20:9 + | +LL | let _guard = bar(); + | ^^^^^^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/warn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/warn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/warn.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/warn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +// edition:2018 +// run-pass +#![feature(must_not_suspend)] +#![warn(must_not_suspend)] + +#[must_not_suspend = "You gotta use Umm's, ya know?"] +struct Umm { + _i: i64 +} + + +fn bar() -> Umm { + Umm { + _i: 1 + } +} + +async fn other() {} + +pub async fn uhoh() { + let _guard = bar(); //~ WARNING `Umm` held across + other().await; +} + +fn main() { +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/warn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/warn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/warn.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/must_not_suspend/warn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +warning: `Umm` held across a suspend point, but should not be + --> $DIR/warn.rs:21:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/warn.rs:4:9 + | +LL | #![warn(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +note: You gotta use Umm's, ya know? + --> $DIR/warn.rs:21:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/warn.rs:21:9 + | +LL | let _guard = bar(); + | ^^^^^^ + +warning: 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/outer-forbid.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/outer-forbid.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/outer-forbid.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/outer-forbid.rs 2021-11-29 19:27:11.000000000 +0000 @@ -17,10 +17,9 @@ #![forbid(unused, non_snake_case)] #![forbid(forbidden_lint_groups)] -#[allow(unused_variables)] //~ ERROR incompatible with previous +#[allow(unused_variables)] //~^ ERROR incompatible with previous //~| WARNING this was previously accepted by the compiler -//~| WARNING this was previously accepted by the compiler fn foo() {} #[allow(unused)] //~ ERROR incompatible with previous diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/outer-forbid.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/outer-forbid.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/outer-forbid.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/outer-forbid.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,7 @@ = note: for more information, see issue #81670 error: allow(unused) incompatible with previous forbid - --> $DIR/outer-forbid.rs:26:9 + --> $DIR/outer-forbid.rs:25:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here @@ -28,7 +28,7 @@ = note: for more information, see issue #81670 error[E0453]: allow(nonstandard_style) incompatible with previous forbid - --> $DIR/outer-forbid.rs:30:9 + --> $DIR/outer-forbid.rs:29:9 | LL | #![forbid(unused, non_snake_case)] | -------------- `forbid` level set here @@ -36,18 +36,6 @@ LL | #[allow(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ overruled by previous forbid -error: allow(unused_variables) incompatible with previous forbid - --> $DIR/outer-forbid.rs:20:9 - | -LL | #![forbid(unused, non_snake_case)] - | ------ `forbid` level set here -... -LL | #[allow(unused_variables)] - | ^^^^^^^^^^^^^^^^ overruled by previous forbid - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #81670 - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0453`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,14 @@ #![deny(mixed_script_confusables)] struct ΑctuallyNotLatin; -//~^ ERROR The usage of Script Group `Greek` in this crate consists solely of +//~^ ERROR the usage of Script Group `Greek` in this crate consists solely of fn main() { let v = ΑctuallyNotLatin; } mod роре { -//~^ ERROR The usage of Script Group `Cyrillic` in this crate consists solely of +//~^ ERROR the usage of Script Group `Cyrillic` in this crate consists solely of const エ: &'static str = "アイウ"; - //~^ ERROR The usage of Script Group `Japanese, Katakana` in this crate consists solely of + //~^ ERROR the usage of Script Group `Japanese, Katakana` in this crate consists solely of } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: The usage of Script Group `Greek` in this crate consists solely of mixed script confusables +error: the usage of Script Group `Greek` in this crate consists solely of mixed script confusables --> $DIR/lint-mixed-script-confusables.rs:3:8 | LL | struct ΑctuallyNotLatin; @@ -9,26 +9,26 @@ | LL | #![deny(mixed_script_confusables)] | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: The usage includes 'Α' (U+0391). - = note: Please recheck to make sure their usages are indeed what you want. + = note: the usage includes 'Α' (U+0391) + = note: please recheck to make sure their usages are indeed what you want -error: The usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables +error: the usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables --> $DIR/lint-mixed-script-confusables.rs:10:5 | LL | mod роре { | ^^^^ | - = note: The usage includes 'е' (U+0435), 'о' (U+043E), 'Ñ€' (U+0440). - = note: Please recheck to make sure their usages are indeed what you want. + = note: the usage includes 'е' (U+0435), 'о' (U+043E), 'Ñ€' (U+0440) + = note: please recheck to make sure their usages are indeed what you want -error: The usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables +error: the usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables --> $DIR/lint-mixed-script-confusables.rs:12:11 | LL | const エ: &'static str = "アイウ"; | ^^ | - = note: The usage includes 'エ' (U+30A8). - = note: Please recheck to make sure their usages are indeed what you want. + = note: the usage includes 'エ' (U+30A8) + = note: please recheck to make sure their usages are indeed what you want error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/suggestions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/suggestions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/suggestions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/suggestions.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,13 +10,18 @@ --> $DIR/suggestions.rs:48:31 | LL | let mut registry_no = (format!("NX-{}", 74205)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/suggestions.rs:4:21 | LL | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896 | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let mut registry_no = (format!("NX-{}", 74205)); +LL + let mut registry_no = format!("NX-{}", 74205); + | warning: variable does not need to be mutable --> $DIR/suggestions.rs:48:13 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unaligned_references.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unaligned_references.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unaligned_references.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unaligned_references.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -47,7 +47,7 @@ --> $DIR/unaligned_references.rs:32:17 | LL | let _ = good.data.clone(); - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82523 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unreachable_pub-pub_crate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unreachable_pub-pub_crate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unreachable_pub-pub_crate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unreachable_pub-pub_crate.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -126,7 +126,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | define_empty_struct_with_visibility!(pub, Fluorine); - | ---------------------------------------------------- + | --------------------------------------------------- | | | | | help: consider restricting its visibility: `pub(crate)` | in this macro invocation diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unreachable_pub.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unreachable_pub.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unreachable_pub.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unreachable_pub.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -126,7 +126,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | define_empty_struct_with_visibility!(pub, Fluorine); - | ---------------------------------------------------- + | --------------------------------------------------- | | | | | help: consider restricting its visibility: `crate` | in this macro invocation diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unsafe_code/auxiliary/forge_unsafe_block.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unsafe_code/auxiliary/forge_unsafe_block.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unsafe_code/auxiliary/forge_unsafe_block.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unsafe_code/auxiliary/forge_unsafe_block.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; + +#[proc_macro] +pub fn forge_unsafe_block(input: TokenStream) -> TokenStream { + let mut output = TokenStream::new(); + output.extend(Some(TokenTree::from(Ident::new("unsafe", Span::call_site())))); + output.extend(Some(TokenTree::from(Group::new(Delimiter::Brace, input)))); + output +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unsafe_code/forge_unsafe_block.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unsafe_code/forge_unsafe_block.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unsafe_code/forge_unsafe_block.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unsafe_code/forge_unsafe_block.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// check-pass +// aux-build:forge_unsafe_block.rs + +#[macro_use] +extern crate forge_unsafe_block; + +unsafe fn foo() {} + +#[forbid(unsafe_code)] +fn main() { + // `forbid` doesn't work for non-user-provided unsafe blocks. + // see `UnsafeCode::check_expr`. + forge_unsafe_block! { + foo(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // check-pass -#![feature(box_syntax)] #![feature(box_patterns)] + #![warn(unused)] // UI tests pass `-A unused` (#43896) struct SoulHistory { @@ -67,7 +67,7 @@ }; // Boxed struct - match box bag { + match Box::new(bag) { box Large::Suit { case } => {} //~ WARNING unused variable: `case` }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/issue-54538-unused-parens-lint.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/issue-54538-unused-parens-lint.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/issue-54538-unused-parens-lint.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/issue-54538-unused-parens-lint.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,151 +2,294 @@ --> $DIR/issue-54538-unused-parens-lint.rs:16:9 | LL | let (a) = 0; - | ^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/issue-54538-unused-parens-lint.rs:13:9 | LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let (a) = 0; +LL + let a = 0; + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:17:9 | LL | for (a) in 0..1 {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - for (a) in 0..1 {} +LL + for a in 0..1 {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:18:12 | LL | if let (a) = 0 {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let (a) = 0 {} +LL + if let a = 0 {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:19:15 | LL | while let (a) = 0 {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - while let (a) = 0 {} +LL + while let a = 0 {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:20:12 | LL | fn foo((a): u8) {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - fn foo((a): u8) {} +LL + fn foo(a: u8) {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:21:14 | LL | let _ = |(a): u8| 0; - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = |(a): u8| 0; +LL + let _ = |a: u8| 0; + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:49:12 | LL | if let (0 | 1) = 0 {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let (0 | 1) = 0 {} +LL + if let 0 | 1 = 0 {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:50:13 | LL | if let ((0 | 1),) = (0,) {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let ((0 | 1),) = (0,) {} +LL + if let (0 | 1,) = (0,) {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:51:13 | LL | if let [(0 | 1)] = [0] {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let [(0 | 1)] = [0] {} +LL + if let [0 | 1] = [0] {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:52:16 | LL | if let 0 | (1 | 2) = 0 {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let 0 | (1 | 2) = 0 {} +LL + if let 0 | 1 | 2 = 0 {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:54:15 | LL | if let TS((0 | 1)) = TS(0) {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let TS((0 | 1)) = TS(0) {} +LL + if let TS(0 | 1) = TS(0) {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:56:20 | LL | if let NS { f: (0 | 1) } = (NS { f: 0 }) {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let NS { f: (0 | 1) } = (NS { f: 0 }) {} +LL + if let NS { f: 0 | 1 } = (NS { f: 0 }) {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:66:9 | LL | (_) => {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (_) => {} +LL + _ => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:67:9 | LL | (y) => {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (y) => {} +LL + y => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:68:9 | LL | (ref r) => {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (ref r) => {} +LL + ref r => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:69:9 | LL | (e @ 1...2) => {} - | ^^^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (e @ 1...2) => {} +LL + e @ 1...2 => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:75:9 | LL | (e @ &(1...2)) => {} - | ^^^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (e @ &(1...2)) => {} +LL + e @ &(1...2) => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:76:10 | LL | &(_) => {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - &(_) => {} +LL + &_ => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:87:9 | LL | (_) => {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (_) => {} +LL + _ => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:88:9 | LL | (y) => {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (y) => {} +LL + y => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:89:9 | LL | (ref r) => {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (ref r) => {} +LL + ref r => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:90:9 | LL | (e @ 1..=2) => {} - | ^^^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (e @ 1..=2) => {} +LL + e @ 1..=2 => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:96:9 | LL | (e @ &(1..=2)) => {} - | ^^^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - (e @ &(1..=2)) => {} +LL + e @ &(1..=2) => {} + | error: unnecessary parentheses around pattern --> $DIR/issue-54538-unused-parens-lint.rs:97:10 | LL | &(_) => {} - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - &(_) => {} +LL + &_ => {} + | error: aborting due to 24 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/issue-74883-unused-paren-baren-yield.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/issue-74883-unused-paren-baren-yield.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/issue-74883-unused-paren-baren-yield.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/issue-74883-unused-paren-baren-yield.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,49 +2,83 @@ --> $DIR/issue-74883-unused-paren-baren-yield.rs:14:29 | LL | while let Some(_) = ({yield}) {} - | ^^^^^^^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/issue-74883-unused-paren-baren-yield.rs:3:24 | LL | #![deny(unused_braces, unused_parens)] | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - while let Some(_) = ({yield}) {} +LL + while let Some(_) = {yield} {} + | error: unnecessary parentheses around `let` scrutinee expression --> $DIR/issue-74883-unused-paren-baren-yield.rs:15:29 | LL | while let Some(_) = ((yield)) {} - | ^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - while let Some(_) = ((yield)) {} +LL + while let Some(_) = (yield) {} + | error: unnecessary braces around block return value --> $DIR/issue-74883-unused-paren-baren-yield.rs:16:10 | LL | {{yield}}; - | ^^^^^^^ help: remove these braces + | ^ ^ | note: the lint level is defined here --> $DIR/issue-74883-unused-paren-baren-yield.rs:3:9 | LL | #![deny(unused_braces, unused_parens)] | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - {{yield}}; +LL + {yield}; + | error: unnecessary parentheses around block return value --> $DIR/issue-74883-unused-paren-baren-yield.rs:17:10 | LL | {( yield )}; - | ^^^^^^^^^ help: remove these parentheses + | ^^ ^^ + | +help: remove these parentheses + | +LL - {( yield )}; +LL + {yield}; + | error: unnecessary parentheses around block return value --> $DIR/issue-74883-unused-paren-baren-yield.rs:18:30 | LL | while let Some(_) = {(yield)} {} - | ^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - while let Some(_) = {(yield)} {} +LL + while let Some(_) = {yield} {} + | error: unnecessary braces around block return value --> $DIR/issue-74883-unused-paren-baren-yield.rs:19:30 | LL | while let Some(_) = {{yield}} {} - | ^^^^^^^ help: remove these braces + | ^ ^ + | +help: remove these braces + | +LL - while let Some(_) = {{yield}} {} +LL + while let Some(_) = {yield} {} + | error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/issue-88519-unused-paren.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/issue-88519-unused-paren.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/issue-88519-unused-paren.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/issue-88519-unused-paren.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,94 @@ +// check-pass +// Make sure unused parens lint doesn't emit a false positive. +// See https://github.com/rust-lang/rust/issues/88519 +#![deny(unused_parens)] +#![feature(type_ascription)] + +// binary ops are tested in issue-71290-unused-paren-binop.rs + +mod call { + fn noop() -> u8 { 0 } + fn outside() -> u8 { + ({ noop })() + } + fn inside() -> u8 { + ({ noop }()) + } + fn outside_match() -> u8 { + (match noop { x => x })() + } + fn inside_match() -> u8 { + (match noop { x => x }()) + } + fn outside_if() -> u8 { + (if false { noop } else { noop })() + } + fn inside_if() -> u8 { + (if false { noop } else { noop }()) + } +} + +mod casts { + fn outside() -> u8 { + ({ 0 }) as u8 + } + fn inside() -> u8 { + ({ 0 } as u8) + } + fn outside_match() -> u8 { + (match 0 { x => x }) as u8 + } + fn inside_match() -> u8 { + (match 0 { x => x } as u8) + } + fn outside_if() -> u8 { + (if false { 0 } else { 0 }) as u8 + } + fn inside_if() -> u8 { + (if false { 0 } else { 0 } as u8) + } +} + +mod typeascription { + fn outside() -> u8 { + ({ 0 }): u8 + } + fn inside() -> u8 { + ({ 0 }: u8) + } + fn outside_match() -> u8 { + (match 0 { x => x }): u8 + } + fn inside_match() -> u8 { + (match 0 { x => x }: u8) + } + fn outside_if() -> u8 { + (if false { 0 } else { 0 }): u8 + } + fn inside_if() -> u8 { + (if false { 0 } else { 0 }: u8) + } +} + +mod index { + fn outside(x: &[u8]) -> u8 { + ({ x })[0] + } + fn inside(x: &[u8]) -> u8 { + ({ x }[0]) + } + fn outside_match(x: &[u8]) -> u8 { + (match x { x => x })[0] + } + fn inside_match(x: &[u8]) -> u8 { + (match x { x => x }[0]) + } + fn outside_if(x: &[u8]) -> u8 { + (if false { x } else { x })[0] + } + fn inside_if(x: &[u8]) -> u8 { + (if false { x } else { x }[0]) + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/unused-macro-rules.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/unused-macro-rules.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused/unused-macro-rules.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused/unused-macro-rules.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -21,7 +21,7 @@ | |_________^ ... LL | create_macro!(); - | ---------------- in this macro invocation + | --------------- in this macro invocation | = note: this error originates in the macro `create_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused_braces_borrow.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused_braces_borrow.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused_braces_borrow.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused_braces_borrow.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,18 @@ --> $DIR/unused_braces_borrow.rs:24:13 | LL | consume({ a.b }); - | ^^^^^^^ help: remove these braces + | ^^ ^^ | note: the lint level is defined here --> $DIR/unused_braces_borrow.rs:4:9 | LL | #![warn(unused_braces)] | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - consume({ a.b }); +LL + consume(a.b); + | warning: 1 warning emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused_braces.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused_braces.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused_braces.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused_braces.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,43 +2,71 @@ --> $DIR/unused_braces.rs:10:13 | LL | let _ = (7); - | ^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/unused_braces.rs:4:24 | LL | #![warn(unused_braces, unused_parens)] | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let _ = (7); +LL + let _ = 7; + | warning: unnecessary braces around `if` condition --> $DIR/unused_braces.rs:26:8 | LL | if { true } { - | ^^^^^^^^ help: remove these braces + | ^^ ^^ | note: the lint level is defined here --> $DIR/unused_braces.rs:4:9 | LL | #![warn(unused_braces, unused_parens)] | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - if { true } { +LL + if true { + | warning: unnecessary braces around `while` condition --> $DIR/unused_braces.rs:30:11 | LL | while { false } { - | ^^^^^^^^^ help: remove these braces + | ^^ ^^ + | +help: remove these braces + | +LL - while { false } { +LL + while false { + | warning: unnecessary braces around const expression --> $DIR/unused_braces.rs:34:17 | LL | let _: [u8; { 3 }]; - | ^^^^^ help: remove these braces + | ^^ ^^ + | +help: remove these braces + | +LL - let _: [u8; { 3 }]; +LL + let _: [u8; 3]; + | warning: unnecessary braces around function argument --> $DIR/unused_braces.rs:37:13 | LL | consume({ 7 }); - | ^^^^^ help: remove these braces + | ^^ ^^ + | +help: remove these braces + | +LL - consume({ 7 }); +LL + consume(7); + | warning: 5 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused_parens_json_suggestion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused_parens_json_suggestion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused_parens_json_suggestion.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused_parens_json_suggestion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,19 @@ -{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":596,"byte_end":609,"line_start":16,"line_end":16,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3)); +{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":596,"byte_end":597,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3)); --> $DIR/unused_parens_json_suggestion.rs:16:14 | LL | let _a = (1 / (2 + 3)); - | ^^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/unused_parens_json_suggestion.rs:10:9 | LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let _a = (1 / (2 + 3)); +LL + let _a = 1 / (2 + 3); + | "} {"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,70 +1,123 @@ -{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":500,"byte_end":504,"line_start":17,"line_end":17,"column_start":8,"column_end":12,"is_primary":true,"text":[{"text":" if (_b) { +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":500,"byte_end":501,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) { --> $DIR/unused_parens_remove_json_suggestion.rs:17:8 | LL | if (_b) { - | ^^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/unused_parens_remove_json_suggestion.rs:10:9 | LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - if (_b) { +LL + if _b { + | "} -{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":631,"byte_end":634,"line_start":28,"line_end":28,"column_start":7,"column_end":10,"is_primary":true,"text":[{"text":" if(c) { +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":631,"byte_end":632,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) { --> $DIR/unused_parens_remove_json_suggestion.rs:28:7 | LL | if(c) { - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if(c) { +LL + if c { + | "} -{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":711,"byte_end":714,"line_start":32,"line_end":32,"column_start":8,"column_end":11,"is_primary":true,"text":[{"text":" if (c){ +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":711,"byte_end":712,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){ --> $DIR/unused_parens_remove_json_suggestion.rs:32:8 | LL | if (c){ - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if (c){ +LL + if c { + | "} -{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":808,"line_start":36,"line_end":36,"column_start":11,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":808,"line_start":36,"line_end":36,"column_start":11,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":26}],"label":null,"suggested_replacement":"false && true ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition --> $DIR/unused_parens_remove_json_suggestion.rs:36:11 | LL | while (false && true){ - | ^^^^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - while (false && true){ +LL + while false && true { + | "} -{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":824,"line_start":37,"line_end":37,"column_start":12,"column_end":15,"is_primary":true,"text":[{"text":" if (c) { +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) { --> $DIR/unused_parens_remove_json_suggestion.rs:37:12 | LL | if (c) { - | ^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if (c) { +LL + if c { + | "} -{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":918,"byte_end":933,"line_start":43,"line_end":43,"column_start":10,"column_end":25,"is_primary":true,"text":[{"text":" while(true && false) { +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":918,"byte_end":919,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) { --> $DIR/unused_parens_remove_json_suggestion.rs:43:10 | LL | while(true && false) { - | ^^^^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - while(true && false) { +LL + while true && false { + | "} -{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":987,"byte_end":995,"line_start":44,"line_end":44,"column_start":18,"column_end":26,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){ +{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":987,"byte_end":988,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){ --> $DIR/unused_parens_remove_json_suggestion.rs:44:18 | LL | for _ in (0 .. 3){ - | ^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - for _ in (0 .. 3){ +LL + for _ in 0 .. 3 { + | "} -{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1088,"byte_end":1096,"line_start":49,"line_end":49,"column_start":14,"column_end":22,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) { +{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1088,"byte_end":1089,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) { --> $DIR/unused_parens_remove_json_suggestion.rs:49:14 | LL | for _ in (0 .. 3) { - | ^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - for _ in (0 .. 3) { +LL + for _ in 0 .. 3 { + | "} -{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1147,"byte_end":1162,"line_start":50,"line_end":50,"column_start":15,"column_end":30,"is_primary":true,"text":[{"text":" while (true && false) { +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1147,"byte_end":1148,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) { --> $DIR/unused_parens_remove_json_suggestion.rs:50:15 | LL | while (true && false) { - | ^^^^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - while (true && false) { +LL + while true && false { + | "} {"message":"aborting due to 9 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 9 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/list.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/list.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/list.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/list.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,8 @@ #![allow(non_camel_case_types)] // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - enum list { cons(isize, Box), nil, } -pub fn main() { list::cons(10, box list::cons(11, box list::cons(12, box list::nil))); } +pub fn main() { + list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil)))))); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-call-arg.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-call-arg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-call-arg.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-call-arg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - fn take(_x: Box) {} + fn main() { - let x: Box = box 25; + let x: Box = Box::new(25); + loop { take(x); //~ ERROR use of moved value: `x` } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-call-arg.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-call-arg.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-call-arg.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-call-arg.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,9 @@ error[E0382]: use of moved value: `x` --> $DIR/liveness-move-call-arg.rs:9:14 | -LL | let x: Box = box 25; +LL | let x: Box = Box::new(25); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait -LL | loop { +... LL | take(x); | ^ value moved here, in previous iteration of loop diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-loop.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-loop.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-loop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-loop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn main() { - let y: Box = box 42; + + let y: Box = 42.into(); let mut x: Box; + loop { println!("{}", y); loop { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-loop.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-loop.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-loop.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-loop.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `y` --> $DIR/liveness-move-in-loop.rs:11:25 | -LL | let y: Box = box 42; +LL | let y: Box = 42.into(); | - move occurs because `y` has type `Box`, which does not implement the `Copy` trait ... LL | x = y; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-while.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-while.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-while.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-while.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn main() { - let y: Box = box 42; + + let y: Box = 42.into(); let mut x: Box; + loop { println!("{}", y); //~ ERROR borrow of moved value: `y` while true { while true { while true { x = y; x.clone(); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-while.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-while.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-while.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-move-in-while.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -21,7 +21,7 @@ error[E0382]: borrow of moved value: `y` --> $DIR/liveness-move-in-while.rs:7:24 | -LL | let y: Box = box 42; +LL | let y: Box = 42.into(); | - move occurs because `y` has type `Box`, which does not implement the `Copy` trait ... LL | println!("{}", y); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -28,13 +28,12 @@ --> $DIR/liveness-return-last-stmt-semi.rs:4:41 | LL | macro_rules! test { () => { fn foo() -> i32 { 1; } } } - | --- ^^^ - help: consider removing this semicolon - | | | - | | expected `i32`, found `()` + | --- ^^^ expected `i32`, found `()` + | | | implicitly returns `()` as its body has no tail or `return` expression ... LL | test!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-use-after-move.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-use-after-move.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-use-after-move.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-use-after-move.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn main() { - let x: Box<_> = box 5; + + let x: Box<_> = 5.into(); let y = x; + println!("{}", *x); //~ ERROR borrow of moved value: `x` y.clone(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-use-after-move.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-use-after-move.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/liveness/liveness-use-after-move.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/liveness/liveness-use-after-move.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,11 @@ error[E0382]: borrow of moved value: `x` --> $DIR/liveness-use-after-move.rs:6:20 | -LL | let x: Box<_> = box 5; +LL | let x: Box<_> = 5.into(); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | let y = x; | - value moved here +LL | LL | println!("{}", *x); | ^^ value borrowed here after move diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ --> $DIR/inline-asm-bad-constraint.rs:38:9 | LL | llvm_asm!("addb $1, $0" : "={rax}"((0i32, rax))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-37433.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-37433.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-37433.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-37433.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// build-fail +// ignore-emscripten no llvm_asm! support + +#![feature(llvm_asm)] +#![allow(deprecated)] // llvm_asm! + +fn main() { + unsafe { + llvm_asm!("" :: "r"("")); + //~^ ERROR: invalid value for constraint in inline assembly + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-37433.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-37433.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-37433.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-37433.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/issue-37433.rs:9:29 + | +LL | llvm_asm!("" :: "r"("")); + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0669`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-62046.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-62046.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-62046.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/issue-62046.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-62046.rs:9:9 | LL | llvm_asm!("nop" : "+r"("r15")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/llvm-asm-parse-errors.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/llvm-asm-parse-errors.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/llvm-asm/llvm-asm-parse-errors.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/llvm-asm/llvm-asm-parse-errors.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/llvm-asm-parse-errors.rs:5:5 | LL | llvm_asm!(); - | ^^^^^^^^^^^^ string literal required + | ^^^^^^^^^^^ string literal required error: expected string literal --> $DIR/llvm-asm-parse-errors.rs:6:23 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ // check-pass +#![feature(label_break_value)] - -// Issue #21633: reject duplicate loop labels in function bodies. +// Issue #21633: reject duplicate loop labels and block labels in function bodies. // // This is testing the generalization (to the whole function body) // discussed here: @@ -26,6 +26,8 @@ { 'lt: loop { break; } } { 'lt: while let Some(_) = None:: { break; } } //~^ WARN label name `'lt` shadows a label name that is already in scope + { 'bl: {} } + { 'bl: {} } //~ WARN label name `'bl` shadows a label name that is already in scope } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -62,5 +62,13 @@ LL | { 'lt: while let Some(_) = None:: { break; } } | ^^^ label `'lt` already in scope -warning: 8 warnings emitted +warning: label name `'bl` shadows a label name that is already in scope + --> $DIR/loops-reject-duplicate-labels-2.rs:30:7 + | +LL | { 'bl: {} } + | --- first declared here +LL | { 'bl: {} } + | ^^^ label `'bl` already in scope + +warning: 9 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,7 @@ // check-pass +#![feature(label_break_value)] - -// Issue #21633: reject duplicate loop labels in function bodies. -// This is testing the exact cases that are in the issue description. +// Issue #21633: reject duplicate loop labels and block labels in function bodies. #[allow(unused_labels)] fn foo() { @@ -24,6 +23,8 @@ 'lt: loop { break; } 'lt: while let Some(_) = None:: { break; } //~^ WARN label name `'lt` shadows a label name that is already in scope + 'bl: {} + 'bl: {} //~ WARN label name `'bl` shadows a label name that is already in scope } // Note however that it is okay for the same label to be reused in @@ -33,6 +34,8 @@ impl S { fn m1(&self) { 'okay: loop { break 'okay; } } fn m2(&self) { 'okay: loop { break 'okay; } } + fn m3(&self) { 'okay: { break 'okay; } } + fn m4(&self) { 'okay: { break 'okay; } } } @@ -40,5 +43,7 @@ let s = S; s.m1(); s.m2(); + s.m3(); + s.m4(); foo(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-duplicate-labels.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ warning: label name `'fl` shadows a label name that is already in scope - --> $DIR/loops-reject-duplicate-labels.rs:10:5 + --> $DIR/loops-reject-duplicate-labels.rs:9:5 | LL | 'fl: for _ in 0..10 { break; } | --- first declared here @@ -7,7 +7,7 @@ | ^^^ label `'fl` already in scope warning: label name `'lf` shadows a label name that is already in scope - --> $DIR/loops-reject-duplicate-labels.rs:13:5 + --> $DIR/loops-reject-duplicate-labels.rs:12:5 | LL | 'lf: loop { break; } | --- first declared here @@ -15,7 +15,7 @@ | ^^^ label `'lf` already in scope warning: label name `'wl` shadows a label name that is already in scope - --> $DIR/loops-reject-duplicate-labels.rs:15:5 + --> $DIR/loops-reject-duplicate-labels.rs:14:5 | LL | 'wl: while 2 > 1 { break; } | --- first declared here @@ -23,7 +23,7 @@ | ^^^ label `'wl` already in scope warning: label name `'lw` shadows a label name that is already in scope - --> $DIR/loops-reject-duplicate-labels.rs:17:5 + --> $DIR/loops-reject-duplicate-labels.rs:16:5 | LL | 'lw: loop { break; } | --- first declared here @@ -31,7 +31,7 @@ | ^^^ label `'lw` already in scope warning: label name `'fw` shadows a label name that is already in scope - --> $DIR/loops-reject-duplicate-labels.rs:19:5 + --> $DIR/loops-reject-duplicate-labels.rs:18:5 | LL | 'fw: for _ in 0..10 { break; } | --- first declared here @@ -39,7 +39,7 @@ | ^^^ label `'fw` already in scope warning: label name `'wf` shadows a label name that is already in scope - --> $DIR/loops-reject-duplicate-labels.rs:21:5 + --> $DIR/loops-reject-duplicate-labels.rs:20:5 | LL | 'wf: while 2 > 1 { break; } | --- first declared here @@ -47,7 +47,7 @@ | ^^^ label `'wf` already in scope warning: label name `'tl` shadows a label name that is already in scope - --> $DIR/loops-reject-duplicate-labels.rs:23:5 + --> $DIR/loops-reject-duplicate-labels.rs:22:5 | LL | 'tl: while let Some(_) = None:: { break; } | --- first declared here @@ -55,12 +55,20 @@ | ^^^ label `'tl` already in scope warning: label name `'lt` shadows a label name that is already in scope - --> $DIR/loops-reject-duplicate-labels.rs:25:5 + --> $DIR/loops-reject-duplicate-labels.rs:24:5 | LL | 'lt: loop { break; } | --- first declared here LL | 'lt: while let Some(_) = None:: { break; } | ^^^ label `'lt` already in scope -warning: 8 warnings emitted +warning: label name `'bl` shadows a label name that is already in scope + --> $DIR/loops-reject-duplicate-labels.rs:27:5 + | +LL | 'bl: {} + | --- first declared here +LL | 'bl: {} + | ^^^ label `'bl` already in scope + +warning: 9 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-lifetime-shadowing-label.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ // check-pass - +#![feature(label_break_value)] #![allow(dead_code, unused_variables)] -// Issue #21633: reject duplicate loop labels in function bodies. +// Issue #21633: reject duplicate loop labels and block labels in function bodies. // -// Test rejection of lifetimes in *expressions* that shadow loop labels. +// Test rejection of lifetimes in *expressions* that shadow labels. fn foo() { // Reusing lifetime `'a` in function item is okay. @@ -23,8 +23,13 @@ assert_eq!((*b)(&z), z); break 'a; } -} + 'b: { + let b = Box::new(|x: &()| ()) as Box Fn(&'b ())>; + //~^ WARN lifetime name `'b` shadows a label name that is already in scope + break 'b; + } +} pub fn main() { foo(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,5 +6,13 @@ LL | let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; | ^^ label `'a` already in scope -warning: 1 warning emitted +warning: lifetime name `'b` shadows a label name that is already in scope + --> $DIR/loops-reject-lifetime-shadowing-label.rs:28:55 + | +LL | 'b: { + | -- first declared here +LL | let b = Box::new(|x: &()| ()) as Box Fn(&'b ())>; + | ^^ label `'b` already in scope + +warning: 2 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,8 +4,8 @@ LL | _ => y, | ^ one type is more general than the other | - = note: expected fn pointer `for<'r, 's> fn(&'r u8, &'s u8) -> &'r u8` - found fn pointer `for<'r> fn(&'r u8, &'r u8) -> &'r u8` + = note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,8 +4,8 @@ LL | _ => y, | ^ one type is more general than the other | - = note: expected trait object `dyn for<'r, 's> Foo<&'r u8, &'s u8>` - found trait object `dyn for<'r> Foo<&'r u8, &'r u8>` + = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` + found trait object `dyn for<'a> Foo<&'a u8, &'a u8>` error[E0308]: mismatched types --> $DIR/old-lub-glb-object.rs:10:14 @@ -13,8 +13,8 @@ LL | _ => y, | ^ one type is more general than the other | - = note: expected trait object `dyn for<'r, 's> Foo<&'r u8, &'s u8>` - found trait object `dyn for<'r> Foo<&'r u8, &'r u8>` + = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` + found trait object `dyn for<'a> Foo<&'a u8, &'a u8>` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-if.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-if.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-if.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-if.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | s | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/lub-if.rs:35:9 @@ -17,8 +15,6 @@ ... LL | s | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-if.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-if.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-if.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-if.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 23:17 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/lub-if.rs:23:17 | LL | pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { @@ -18,7 +18,7 @@ | ^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 32:17 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/lub-if.rs:32:17 | LL | pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-match.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-match.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-match.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-match.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | s | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/lub-match.rs:39:13 @@ -17,8 +15,6 @@ ... LL | s | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-match.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-match.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/lub-match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/lub-match.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 25:17 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/lub-match.rs:25:17 | LL | pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { @@ -18,7 +18,7 @@ | ^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 35:17 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/lub-match.rs:35:17 | LL | pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macro_backtrace/main.default.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macro_backtrace/main.default.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macro_backtrace/main.default.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macro_backtrace/main.default.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^ expected one of 8 possible tokens ... LL | pong!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `pong` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^^ expected one of 8 possible tokens ... LL | ping!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `pong` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -27,7 +27,7 @@ | ^^^^^ expected one of 8 possible tokens ... LL | deep!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `pong` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | |_- in this expansion of `pong!` ... LL | pong!(); - | -------- in this macro invocation + | ------- in this macro invocation error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> $DIR/main.rs:10:20 @@ -20,14 +20,14 @@ | |__- in this expansion of `pong!` (#2) ... LL | ping!(); - | -------- in this macro invocation (#1) + | ------- in this macro invocation (#1) | ::: $DIR/auxiliary/ping.rs:5:1 | LL | / macro_rules! ping { LL | | () => { LL | | pong!(); - | | -------- in this macro invocation (#2) + | | ------- in this macro invocation (#2) LL | | } LL | | } | |_- in this expansion of `ping!` (#1) @@ -42,14 +42,14 @@ | |__- in this expansion of `pong!` (#5) ... LL | deep!(); - | -------- in this macro invocation (#1) + | ------- in this macro invocation (#1) | ::: $DIR/auxiliary/ping.rs:5:1 | LL | / macro_rules! ping { LL | | () => { LL | | pong!(); - | | -------- in this macro invocation (#5) + | | ------- in this macro invocation (#5) LL | | } LL | | } | |_- in this expansion of `ping!` (#4) @@ -57,7 +57,7 @@ LL | / macro_rules! deep { LL | | () => { LL | | foo!(); - | | ------- in this macro invocation (#2) + | | ------ in this macro invocation (#2) LL | | } LL | | } | |__- in this expansion of `deep!` (#1) @@ -65,7 +65,7 @@ LL | / macro_rules! foo { LL | | () => { LL | | bar!(); - | | ------- in this macro invocation (#3) + | | ------ in this macro invocation (#3) LL | | } LL | | } | |__- in this expansion of `foo!` (#2) @@ -73,7 +73,7 @@ LL | / macro_rules! bar { LL | | () => { LL | | ping!(); - | | -------- in this macro invocation (#4) + | | ------- in this macro invocation (#4) LL | | } LL | | } | |__- in this expansion of `bar!` (#3) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/assert.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/assert.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/assert.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/assert.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/assert.rs:2:5 | LL | assert!(); - | ^^^^^^^^^^ boolean expression required + | ^^^^^^^^^ boolean expression required error: expected expression, found keyword `struct` --> $DIR/assert.rs:3:13 @@ -14,7 +14,7 @@ --> $DIR/assert.rs:4:5 | LL | debug_assert!(); - | ^^^^^^^^^^^^^^^^ boolean expression required + | ^^^^^^^^^^^^^^^ boolean expression required | = note: this error originates in the macro `debug_assert` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/assert-trailing-junk.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/assert-trailing-junk.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/assert-trailing-junk.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/assert-trailing-junk.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,7 +38,7 @@ --> $DIR/assert-trailing-junk.rs:19:5 | LL | assert!(true;); - | ^^^^^^^^^^^^-^^ + | ^^^^^^^^^^^^-^ | | | help: try removing semicolon diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/auxiliary/define-macro.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/auxiliary/define-macro.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/auxiliary/define-macro.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/auxiliary/define-macro.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +#[macro_export] +macro_rules! define_macro { + ($i:ident) => { + macro_rules! $i { () => {} } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/auxiliary/macro-def-site-super.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/auxiliary/macro-def-site-super.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/auxiliary/macro-def-site-super.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/auxiliary/macro-def-site-super.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +#![feature(decl_macro)] + +mod inner1 { + pub struct Struct {} + + pub mod inner2 { + pub macro mac() { + super::Struct + } + } +} + +pub use inner1::inner2 as public; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +// run-rustfix +#[allow(unused_macros)] + +macro_rules! foo { //~ ERROR macro names aren't followed by a `!` + () => {}; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +// run-rustfix +#[allow(unused_macros)] + +macro_rules! foo! { //~ ERROR macro names aren't followed by a `!` + () => {}; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/bang-after-name.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: macro names aren't followed by a `!` + --> $DIR/bang-after-name.rs:4:17 + | +LL | macro_rules! foo! { + | ^ help: remove the `!` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/cfg.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/cfg.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/cfg.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/cfg.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/cfg.rs:2:5 | LL | cfg!(); - | ^^^^^^^ cfg-pattern required + | ^^^^^^ cfg-pattern required | = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/format-parse-errors.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/format-parse-errors.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/format-parse-errors.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/format-parse-errors.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/format-parse-errors.rs:4:5 | LL | format!(); - | ^^^^^^^^^^ + | ^^^^^^^^^ | = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/global-asm.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/global-asm.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/global-asm.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/global-asm.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/global-asm.rs:4:5 | LL | global_asm!(); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: expected expression, found keyword `struct` --> $DIR/global-asm.rs:5:17 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/issue-54441.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/issue-54441.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/issue-54441.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/issue-54441.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^ ... LL | m!(); - | ----- caused by the macro expansion here + | ---- caused by the macro expansion here | = note: the usage of `m!` is likely invalid in foreign item context diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/issue-78325-inconsistent-resolution.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/issue-78325-inconsistent-resolution.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/issue-78325-inconsistent-resolution.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/issue-78325-inconsistent-resolution.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | define_other_core!(); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ (A) => (concat!("", a!())); (A, $($A:ident),*) => (concat!("", a!($($A),*))) //~^ ERROR recursion limit reached - //~| HELP consider adding + //~| HELP consider increasing the recursion limit } fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,9 +5,9 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | a!(A, A, A, A, A, A, A, A, A, A, A); - | ------------------------------------ in this macro invocation + | ----------------------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="30"]` attribute to your crate (`issue_84632_eager_expansion_recursion_limit`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "30"]` attribute to your crate (`issue_84632_eager_expansion_recursion_limit`) = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-at-most-once-rep-2015.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-at-most-once-rep-2015.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-at-most-once-rep-2015.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-at-most-once-rep-2015.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,7 +38,7 @@ | -------------------- when calling this macro ... LL | barplus!(); - | ^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^ missing tokens in macro arguments error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2015.rs:30:15 @@ -74,7 +74,7 @@ | -------------------- when calling this macro ... LL | barstar!(); - | ^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^ missing tokens in macro arguments error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2015.rs:37:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-at-most-once-rep-2018.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-at-most-once-rep-2018.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-at-most-once-rep-2018.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-at-most-once-rep-2018.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,7 +38,7 @@ | -------------------- when calling this macro ... LL | barplus!(); - | ^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^ missing tokens in macro arguments error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2018.rs:30:15 @@ -74,7 +74,7 @@ | -------------------- when calling this macro ... LL | barstar!(); - | ^^^^^^^^^^^ missing tokens in macro arguments + | ^^^^^^^^^^ missing tokens in macro arguments error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2018.rs:37:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-invalid-internals.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-invalid-internals.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-invalid-internals.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-invalid-internals.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^ method not found in `{integer}` ... LL | fake_method_stmt!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `fake_method_stmt` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^ ... LL | fake_field_stmt!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `fake_field_stmt` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -27,7 +27,7 @@ | ^ ... LL | fake_anon_field_stmt!(); - | ------------------------ in this macro invocation + | ----------------------- in this macro invocation | = note: this error originates in the macro `fake_anon_field_stmt` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -38,7 +38,7 @@ | ^^^ ... LL | real_method_stmt!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `real_method_stmt` (in Nightly builds, run with -Z macro-backtrace for more info) help: you must specify a concrete type for this numeric value, like `f32` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-nested.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-nested.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-nested.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-nested.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,7 @@ | ^^^^ not found in this scope ... LL | call_nested_expr_sum!(); - | ------------------------ in this macro invocation + | ----------------------- in this macro invocation | = note: this error originates in the macro `nested_expr` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-println.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-println.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-println.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-backtrace-println.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | myprintln!("{}"); - | ----------------- in this macro invocation + | ---------------- in this macro invocation | = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-comma-support.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-comma-support.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-comma-support.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-comma-support.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,13 @@ --> $DIR/macro-comma-support.rs:6:5 | LL | compile_error!("lel"); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: lel --> $DIR/macro-comma-support.rs:7:5 | LL | compile_error!("lel",); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-context.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-context.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-context.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-context.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,7 +38,7 @@ | ^^^^^^ expected expression ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-def-site-super.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-def-site-super.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-def-site-super.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-def-site-super.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +// `super` in a `macro` refers to the parent module of the macro itself and not its reexport. + +// check-pass +// aux-build:macro-def-site-super.rs + +extern crate macro_def_site_super; + +type A = macro_def_site_super::public::mac!(); + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-inner-attributes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-inner-attributes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-inner-attributes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-inner-attributes.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -3,6 +3,11 @@ | LL | a::bar(); | ^ use of undeclared crate or module `a` + | +help: there is a crate or module with a similar name + | +LL | b::bar(); + | ~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-lifetime-used-with-labels.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-lifetime-used-with-labels.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-lifetime-used-with-labels.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-lifetime-used-with-labels.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | 'b: loop { | -- first declared here LL | br2!('b); - | --------- in this macro invocation + | -------- in this macro invocation | = note: this warning originates in the macro `br2` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-local-data-key-priv.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-local-data-key-priv.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-local-data-key-priv.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-local-data-key-priv.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ --> $DIR/macro-local-data-key-priv.rs:4:5 | LL | thread_local!(static baz: f64 = 0.0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::__thread_local_inner` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-shadowing.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-shadowing.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macro-shadowing.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macro-shadowing.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^ ... LL | m1!(); - | ------ in this macro invocation + | ----- in this macro invocation | = note: macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560) = note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -23,7 +23,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | m1!(); - | ------ in this macro invocation + | ----- in this macro invocation note: `foo` could also refer to the macro defined here --> $DIR/macro-shadowing.rs:5:1 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macros-nonfatal-errors.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macros-nonfatal-errors.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/macros-nonfatal-errors.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/macros-nonfatal-errors.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -138,11 +138,11 @@ LL | llvm_asm!(invalid); | ^^^^^^^ -error: concat_idents! requires ident args. +error: concat_idents! requires ident args --> $DIR/macros-nonfatal-errors.rs:102:5 | LL | concat_idents!("not", "idents"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal --> $DIR/macros-nonfatal-errors.rs:104:17 @@ -166,7 +166,7 @@ --> $DIR/macros-nonfatal-errors.rs:107:5 | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -197,7 +197,7 @@ --> $DIR/macros-nonfatal-errors.rs:114:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -211,7 +211,7 @@ --> $DIR/macros-nonfatal-errors.rs:116:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -219,7 +219,7 @@ --> $DIR/macros-nonfatal-errors.rs:118:5 | LL | trace_macros!(invalid); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 27 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/must-use-in-macro-55516.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/must-use-in-macro-55516.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/must-use-in-macro-55516.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/must-use-in-macro-55516.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/must-use-in-macro-55516.rs:9:5 | LL | write!(&mut example, "{}", 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-W unused-must-use` implied by `-W unused` = note: this `Result` may be an `Err` variant, which should be handled diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/nonterminal-matching.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/nonterminal-matching.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/nonterminal-matching.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/nonterminal-matching.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | ^^^^^^^^ no rules expected this token in macro call ... LL | complex_nonterminal!(enum E {}); - | -------------------------------- in this macro invocation + | ------------------------------- in this macro invocation | = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/out-of-order-shadowing.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/out-of-order-shadowing.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/out-of-order-shadowing.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/out-of-order-shadowing.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +// aux-build:define-macro.rs + +macro_rules! bar { () => {} } +define_macro!(bar); +bar!(); //~ ERROR `bar` is ambiguous + +macro_rules! m { () => { #[macro_use] extern crate define_macro; } } +m!(); + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/out-of-order-shadowing.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/out-of-order-shadowing.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/out-of-order-shadowing.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/out-of-order-shadowing.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0659]: `bar` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) + --> $DIR/out-of-order-shadowing.rs:5:1 + | +LL | bar!(); + | ^^^ ambiguous name + | +note: `bar` could refer to the macro defined here + --> $DIR/out-of-order-shadowing.rs:4:1 + | +LL | define_macro!(bar); + | ^^^^^^^^^^^^^^^^^^ +note: `bar` could also refer to the macro defined here + --> $DIR/out-of-order-shadowing.rs:3:1 + | +LL | macro_rules! bar { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `define_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0659`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/restricted-shadowing-legacy.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/restricted-shadowing-legacy.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/restricted-shadowing-legacy.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/restricted-shadowing-legacy.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:88:9 @@ -14,7 +14,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:97:9 | @@ -22,7 +22,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -32,7 +32,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:88:9 @@ -41,7 +41,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:135:9 | @@ -49,7 +49,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -59,7 +59,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:88:9 @@ -68,7 +68,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:144:9 | @@ -76,7 +76,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -86,7 +86,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:88:9 @@ -95,7 +95,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:85:9 | @@ -103,7 +103,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -113,7 +113,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:88:9 @@ -122,7 +122,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:85:9 | @@ -130,7 +130,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -140,7 +140,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:88:9 @@ -149,7 +149,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:85:9 | @@ -157,7 +157,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -167,7 +167,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:88:9 @@ -176,7 +176,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:227:13 | @@ -184,7 +184,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -194,7 +194,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:88:9 @@ -203,7 +203,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-legacy.rs:257:13 | @@ -211,7 +211,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 8 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/restricted-shadowing-modern.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/restricted-shadowing-modern.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/restricted-shadowing-modern.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/restricted-shadowing-modern.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:91:9 @@ -14,7 +14,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:99:9 | @@ -22,7 +22,7 @@ | ^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -32,7 +32,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:91:9 @@ -41,7 +41,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:143:9 | @@ -49,7 +49,7 @@ | ^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -59,7 +59,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:91:9 @@ -68,7 +68,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:153:9 | @@ -76,7 +76,7 @@ | ^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -86,7 +86,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:91:9 @@ -95,7 +95,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:87:9 | @@ -103,7 +103,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -113,7 +113,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:91:9 @@ -122,7 +122,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:87:9 | @@ -130,7 +130,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) @@ -140,7 +140,7 @@ | ^ ambiguous name ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation | note: `m` could refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:91:9 @@ -149,7 +149,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation note: `m` could also refer to the macro defined here --> $DIR/restricted-shadowing-modern.rs:87:9 | @@ -157,7 +157,7 @@ | ^^^^^^^^^^^^^^^^^^^ ... LL | include!(); - | ----------- in this macro invocation + | ---------- in this macro invocation = note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/same-sequence-span.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/same-sequence-span.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/same-sequence-span.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/same-sequence-span.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ --> $DIR/same-sequence-span.rs:19:1 | LL | proc_macro_sequence::make_foo!(); - | ^-------------------------------- + | ^------------------------------- | | | _in this macro invocation | | @@ -34,7 +34,7 @@ --> $DIR/same-sequence-span.rs:19:1 | LL | proc_macro_sequence::make_foo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` = note: this error originates in the macro `proc_macro_sequence::make_foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/span-covering-argument-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/span-covering-argument-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/span-covering-argument-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/span-covering-argument-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^^^^^^^ cannot borrow as mutable ... LL | bad!(foo whatever); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `bad` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/trace_faulty_macros.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/trace_faulty_macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/trace_faulty_macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/trace_faulty_macros.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | ^^^ no rules expected this token in macro call ... LL | my_faulty_macro!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `my_faulty_macro` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ --> $DIR/trace_faulty_macros.rs:31:5 | LL | my_faulty_macro!(); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: expanding `my_faulty_macro! { }` = note: to `my_faulty_macro! (bcd) ;` @@ -26,19 +26,19 @@ --> $DIR/trace_faulty_macros.rs:22:9 | LL | my_recursive_macro!(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ ... LL | my_recursive_macro!(); - | ---------------------- in this macro invocation + | --------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="8"]` attribute to your crate (`trace_faulty_macros`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`trace_faulty_macros`) = note: this error originates in the macro `my_recursive_macro` (in Nightly builds, run with -Z macro-backtrace for more info) note: trace_macro --> $DIR/trace_faulty_macros.rs:32:5 | LL | my_recursive_macro!(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = note: expanding `my_recursive_macro! { }` = note: to `my_recursive_macro! () ;` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/trace-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/trace-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/macros/trace-macro.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/macros/trace-macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/trace-macro.rs:5:5 | LL | println!("Hello, World!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: expanding `println! { "Hello, World!" }` = note: to `{ $crate :: io :: _print($crate :: format_args_nl! ("Hello, World!")) ; }` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/malformed/malformed-plugin-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/malformed/malformed-plugin-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/malformed/malformed-plugin-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/malformed/malformed-plugin-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/malformed-plugin-1.rs:2:1 | LL | #![plugin] - | ^^^^^^^^^^ help: must be of the form: `#[plugin(name)]` + | ^^^^^^^^^^ help: must be of the form: `#![plugin(name)]` warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 --> $DIR/malformed-plugin-1.rs:2:1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/malformed/malformed-plugin-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/malformed/malformed-plugin-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/malformed/malformed-plugin-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/malformed/malformed-plugin-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/malformed-plugin-2.rs:2:1 | LL | #![plugin="bleh"] - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name)]` + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![plugin(name)]` warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 --> $DIR/malformed-plugin-2.rs:2:1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/map-types.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/map-types.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/map-types.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/map-types.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - use std::collections::HashMap; + + trait Map { fn get(&self, k: K) -> V { panic!() } @@ -12,7 +12,7 @@ // Test that trait types printed in error msgs include the type arguments. fn main() { - let x: Box> = box HashMap::new(); + let x: Box> = HashMap::new().into(); let x: Box> = x; let y: Box> = Box::new(x); //~^ ERROR `Box>: Map` is not satisfied diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/guards.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/match/guards.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/guards.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/guards.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +// run-pass + +#![allow(non_shorthand_field_patterns)] + +#[derive(Copy, Clone)] +struct Pair { x: isize, y: isize } + +pub fn main() { + let a: isize = + match 10 { x if x < 7 => { 1 } x if x < 11 => { 2 } 10 => { 3 } _ => { 4 } }; + assert_eq!(a, 2); + + let b: isize = + match (Pair {x: 10, y: 20}) { + x if x.x < 5 && x.y < 5 => { 1 } + Pair {x: x, y: y} if x == 10 && y == 20 => { 2 } + Pair {x: _x, y: _y} => { 3 } + }; + assert_eq!(b, 2); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-33498.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-33498.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-33498.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-33498.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +// run-pass +#![allow(unused_variables)] +pub fn main() { + let x = (0, 2); + + match x { + (0, ref y) => {} + (y, 0) => {} + _ => (), + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-41255.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-41255.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-41255.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-41255.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +// Matching against float literals should result in a linter error + +#![feature(exclusive_range_pattern)] +#![feature(half_open_range_patterns)] +#![allow(unused)] +#![forbid(illegal_floating_point_literal_pattern)] + +fn main() { + let x = 42.0; + match x { + 5.0 => {}, //~ ERROR floating-point types cannot be used in patterns + //~| WARNING hard error + 5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns + //~| WARNING hard error + -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns + //~| WARNING hard error + 1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns + //~| WARNING hard error + //~| ERROR floating-point types cannot be used in patterns + //~| WARNING hard error + 39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns + //~| ERROR floating-point types cannot be used in patterns + //~| WARNING hard error + //~| WARNING hard error + + ..71.0 => {} + //~^ ERROR floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler + ..=72.0 => {} + //~^ ERROR floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler + 71.0.. => {} + //~^ ERROR floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler + _ => {}, + }; + let y = 5.0; + // Same for tuples + match (x, 5) { + (3.14, 1) => {}, //~ ERROR floating-point types cannot be used + //~| WARNING hard error + _ => {}, + } + // Or structs + struct Foo { x: f32 }; + match (Foo { x }) { + Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used + //~| WARNING hard error + _ => {}, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-41255.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-41255.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-41255.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-41255.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,115 @@ +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:11:9 + | +LL | 5.0 => {}, + | ^^^ + | +note: the lint level is defined here + --> $DIR/issue-41255.rs:6:11 + | +LL | #![forbid(illegal_floating_point_literal_pattern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:13:9 + | +LL | 5.0f32 => {}, + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:15:10 + | +LL | -5.0 => {}, + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:17:9 + | +LL | 1.0 .. 33.0 => {}, + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:17:16 + | +LL | 1.0 .. 33.0 => {}, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:21:9 + | +LL | 39.0 ..= 70.0 => {}, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:21:18 + | +LL | 39.0 ..= 70.0 => {}, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:26:11 + | +LL | ..71.0 => {} + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:29:12 + | +LL | ..=72.0 => {} + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:32:9 + | +LL | 71.0.. => {} + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:40:10 + | +LL | (3.14, 1) => {}, + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: floating-point types cannot be used in patterns + --> $DIR/issue-41255.rs:47:18 + | +LL | Foo { x: 2.0 } => {}, + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +error: aborting due to 12 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-56685.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-56685.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-56685.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-56685.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,44 @@ +#![allow(dead_code)] +#![deny(unused_variables)] + +// This test aims to check that unused variable suggestions update bindings in all +// match arms. + +fn main() { + enum E { + A(i32,), + B(i32,), + } + + match E::A(1) { + E::A(x) | E::B(x) => {} + //~^ ERROR unused variable: `x` + } + + enum F { + A(i32, i32,), + B(i32, i32,), + C(i32, i32,), + } + + let _ = match F::A(1, 2) { + F::A(x, y) | F::B(x, y) => { y }, + //~^ ERROR unused variable: `x` + F::C(a, b) => { 3 } + //~^ ERROR unused variable: `a` + //~^^ ERROR unused variable: `b` + }; + + let _ = if let F::A(x, y) | F::B(x, y) = F::A(1, 2) { + //~^ ERROR unused variable: `x` + y + } else { + 3 + }; + + while let F::A(x, y) | F::B(x, y) = F::A(1, 2) { + //~^ ERROR unused variable: `x` + let _ = y; + break; + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-56685.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-56685.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-56685.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-56685.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,63 @@ +error: unused variable: `x` + --> $DIR/issue-56685.rs:14:14 + | +LL | E::A(x) | E::B(x) => {} + | ^ ^ + | +note: the lint level is defined here + --> $DIR/issue-56685.rs:2:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ +help: if this is intentional, prefix it with an underscore + | +LL | E::A(_x) | E::B(_x) => {} + | ~~ ~~ + +error: unused variable: `x` + --> $DIR/issue-56685.rs:25:14 + | +LL | F::A(x, y) | F::B(x, y) => { y }, + | ^ ^ + | +help: if this is intentional, prefix it with an underscore + | +LL | F::A(_x, y) | F::B(_x, y) => { y }, + | ~~ ~~ + +error: unused variable: `a` + --> $DIR/issue-56685.rs:27:14 + | +LL | F::C(a, b) => { 3 } + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/issue-56685.rs:27:17 + | +LL | F::C(a, b) => { 3 } + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `x` + --> $DIR/issue-56685.rs:32:25 + | +LL | let _ = if let F::A(x, y) | F::B(x, y) = F::A(1, 2) { + | ^ ^ + | +help: if this is intentional, prefix it with an underscore + | +LL | let _ = if let F::A(_x, y) | F::B(_x, y) = F::A(1, 2) { + | ~~ ~~ + +error: unused variable: `x` + --> $DIR/issue-56685.rs:39:20 + | +LL | while let F::A(x, y) | F::B(x, y) = F::A(1, 2) { + | ^ ^ + | +help: if this is intentional, prefix it with an underscore + | +LL | while let F::A(_x, y) | F::B(_x, y) = F::A(1, 2) { + | ~~ ~~ + +error: aborting due to 6 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-74050-end-span.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-74050-end-span.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/issue-74050-end-span.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/issue-74050-end-span.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ---- borrow later stored here LL | Some(arg) => { LL | match arg.to_str() { - | ^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^ borrowed value does not live long enough ... LL | } | - `arg` dropped here while still borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/match-ref-mut-invariance.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/match/match-ref-mut-invariance.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/match-ref-mut-invariance.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/match-ref-mut-invariance.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected mutable reference `&'a mut &'a i32` found mutable reference `&'a mut &'b i32` -note: the lifetime `'a` as defined on the method body at 9:12... +note: the lifetime `'a` as defined here... --> $DIR/match-ref-mut-invariance.rs:9:12 | LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 8:6 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/match-ref-mut-invariance.rs:8:6 | LL | impl<'b> S<'b> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/match/match-ref-mut-let-invariance.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/match/match-ref-mut-let-invariance.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/match/match-ref-mut-let-invariance.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/match/match-ref-mut-let-invariance.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected mutable reference `&'a mut &'a i32` found mutable reference `&'a mut &'b i32` -note: the lifetime `'a` as defined on the method body at 9:12... +note: the lifetime `'a` as defined here... --> $DIR/match-ref-mut-let-invariance.rs:9:12 | LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 8:6 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/match-ref-mut-let-invariance.rs:8:6 | LL | impl<'b> S<'b> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/maybe-bounds-where.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/maybe-bounds-where.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/maybe-bounds-where.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/maybe-bounds-where.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,6 +11,7 @@ struct S4(T) where for<'a> T: ?Trait<'a>; //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +//~| WARN default bound relaxed for a type parameter struct S5(*const T) where T: ?Trait<'static> + ?Sized; //~^ ERROR type parameter has more than one relaxed default bound diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/maybe-bounds-where.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/maybe-bounds-where.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/maybe-bounds-where.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/maybe-bounds-where.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,45 +1,51 @@ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:1:23 + --> $DIR/maybe-bounds-where.rs:1:28 | LL | struct S1(T) where (T): ?Sized; - | ^^^ + | ^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:4:23 + --> $DIR/maybe-bounds-where.rs:4:27 | LL | struct S2(T) where u8: ?Sized; - | ^^ + | ^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:7:23 + --> $DIR/maybe-bounds-where.rs:7:35 | LL | struct S3(T) where &'static T: ?Sized; - | ^^^^^^^^^^ + | ^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:12:31 + --> $DIR/maybe-bounds-where.rs:12:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; - | ^ + | ^^^^^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:20:18 + --> $DIR/maybe-bounds-where.rs:21:21 | LL | fn f() where T: ?Sized {} - | ^ + | ^^^^^^ + +warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported + --> $DIR/maybe-bounds-where.rs:12:11 + | +LL | struct S4(T) where for<'a> T: ?Trait<'a>; + | ^ error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/maybe-bounds-where.rs:15:11 + --> $DIR/maybe-bounds-where.rs:16:11 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^ warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported - --> $DIR/maybe-bounds-where.rs:15:11 + --> $DIR/maybe-bounds-where.rs:16:11 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^ -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0203`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/meta/expected-error-correct-rev.a.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/meta/expected-error-correct-rev.a.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/meta/expected-error-correct-rev.a.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/meta/expected-error-correct-rev.a.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ help: change the type of the numeric literal from `usize` to `u32` | LL | let x: u32 = 22_u32; - | ~~~~~~ + | ~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/meta/meta-expected-error-wrong-rev.a.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/meta/meta-expected-error-wrong-rev.a.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/meta/meta-expected-error-wrong-rev.a.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/meta/meta-expected-error-wrong-rev.a.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ help: change the type of the numeric literal from `usize` to `u32` | LL | let x: u32 = 22_u32; - | ~~~~~~ + | ~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/auxiliary/method_self_arg1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/auxiliary/method_self_arg1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/auxiliary/method_self_arg1.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/auxiliary/method_self_arg1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ #![crate_type = "lib"] -#![feature(box_syntax)] - static mut COUNT: u64 = 1; pub fn get_count() -> u64 { unsafe { COUNT } } @@ -19,8 +17,8 @@ Foo::baz(self); Foo::baz(*x); - Foo::qux(box self); - Foo::qux(box *x); + Foo::qux(Box::new(self)); + Foo::qux(Box::new(*x)); } pub fn bar(&self) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/auxiliary/method_self_arg2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/auxiliary/method_self_arg2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/auxiliary/method_self_arg2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/auxiliary/method_self_arg2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ #![crate_type = "lib"] -#![feature(box_syntax)] - static mut COUNT: u64 = 1; pub fn get_count() -> u64 { unsafe { COUNT } } @@ -15,11 +13,11 @@ // Test internal call. Bar::foo1(&self); Bar::foo2(self); - Bar::foo3(box self); + Bar::foo3(Box::new(self)); Bar::bar1(&self); Bar::bar2(self); - Bar::bar3(box self); + Bar::bar3(Box::new(self)); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | let y: usize = x.foo().try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,12 +16,12 @@ | ^^^^^^^^ help: disambiguate the associated function for candidate #1 | -LL | A::foo(); - | ~~~ +LL | ::foo(); + | ~~~~~~~~~~~ help: disambiguate the associated function for candidate #2 | -LL | B::foo(); - | ~~~ +LL | ::foo(); + | ~~~~~~~~~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-call-err-msg.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-call-err-msg.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-call-err-msg.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-call-err-msg.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -55,6 +55,17 @@ = note: the following trait bounds were not satisfied: `Foo: Iterator` which is required by `&mut Foo: Iterator` +note: the following trait must be implemented + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + | +LL | / pub trait Iterator { +LL | | /// The type of the elements being iterated over. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Item; +... | +LL | | } +LL | | } + | |_^ = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `take`, perhaps you need to implement it: candidate #1: `Iterator` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | Foo::bar(&x); | ^^ immutable borrow occurs here LL | y.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/method-self-arg-2.rs:20:14 @@ -16,7 +16,7 @@ LL | Foo::baz(&mut x); | ^^^^^^ second mutable borrow occurs here LL | y.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-aux1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-aux1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-aux1.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-aux1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // Test method calls with self as an argument (cross-crate) -#![feature(box_syntax)] - // aux-build:method_self_arg1.rs extern crate method_self_arg1; use method_self_arg1::Foo; @@ -12,7 +10,7 @@ // Test external call. Foo::bar(&x); Foo::baz(x); - Foo::qux(box x); + Foo::qux(Box::new(x)); x.foo(&x); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-aux2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-aux2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-aux2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-aux2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // Test method calls with self as an argument (cross-crate) -#![feature(box_syntax)] - // aux-build:method_self_arg2.rs extern crate method_self_arg2; use method_self_arg2::{Foo, Bar}; @@ -12,11 +10,11 @@ // Test external call. Bar::foo1(&x); Bar::foo2(x); - Bar::foo3(box x); + Bar::foo3(Box::new(x)); Bar::bar1(&x); Bar::bar2(x); - Bar::bar3(box x); + Bar::bar3(Box::new(x)); x.run_trait(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // Test method calls with self as an argument -#![feature(box_syntax)] - static mut COUNT: usize = 1; #[derive(Copy, Clone)] @@ -18,8 +16,8 @@ Foo::baz(self); Foo::baz(*x); - Foo::qux(box self); - Foo::qux(box *x); + Foo::qux(Box::new(self)); + Foo::qux(Box::new(*x)); } fn bar(&self) { @@ -40,7 +38,7 @@ // Test external call. Foo::bar(&x); Foo::baz(x); - Foo::qux(box x); + Foo::qux(Box::new(x)); x.foo(&x); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-trait.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-self-arg-trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // Test method calls with self as an argument -#![feature(box_syntax)] - static mut COUNT: u64 = 1; #[derive(Copy, Clone)] @@ -44,11 +42,11 @@ // Test internal call. Bar::foo1(&self); Bar::foo2(self); - Bar::foo3(box self); + Bar::foo3(Box::new(self)); Bar::bar1(&self); Bar::bar2(self); - Bar::bar3(box self); + Bar::bar3(Box::new(self)); } } @@ -57,11 +55,11 @@ // Test external call. Bar::foo1(&x); Bar::foo2(x); - Bar::foo3(box x); + Bar::foo3(Box::new(x)); Bar::bar1(&x); Bar::bar2(x); - Bar::bar3(box x); + Bar::bar3(Box::new(x)); x.baz(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-two-trait-defer-resolution-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-two-trait-defer-resolution-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/methods/method-two-trait-defer-resolution-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/methods/method-two-trait-defer-resolution-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,8 +10,6 @@ // codegen the call as `Foo::foo(&x)` and let the specific impl get // chosen later. -#![feature(box_syntax)] - trait Foo { fn foo(&self) -> isize; } @@ -37,7 +35,7 @@ fn call_foo_other() -> isize { let mut x: Vec<_> = Vec::new(); let y = x.foo(); - let z: Box = box 0; + let z: Box = Box::new(0); x.push(z); y } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mid-path-type-params.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/mid-path-type-params.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mid-path-type-params.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mid-path-type-params.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -// run-pass - -#![allow(dead_code)] -// pretty-expanded FIXME #23616 - -struct S { - contents: T, -} - -impl S { - fn new(x: T, _: U) -> S { - S { - contents: x, - } - } -} - -trait Trait { - fn new(x: T, y: U) -> Self; -} - -struct S2 { - contents: isize, -} - -impl Trait for S2 { - fn new(x: isize, _: U) -> S2 { - S2 { - contents: x, - } - } -} - -pub fn main() { - let _ = S::::new::(1, 1.0); - let _: S2 = Trait::::new::(1, 1.0); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mir-dataflow/liveness-enum.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/mir-dataflow/liveness-enum.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mir-dataflow/liveness-enum.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mir-dataflow/liveness-enum.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; + +#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)] +fn foo() -> Option { + let mut x = None; + + // `x` is live here since it is used in the next statement... + rustc_peek(x); + + dbg!(x); + + // But not here, since it is overwritten below + rustc_peek(x); //~ ERROR rustc_peek: bit not set + + x = Some(4); + + x +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mir-dataflow/liveness-enum.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mir-dataflow/liveness-enum.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mir-dataflow/liveness-enum.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mir-dataflow/liveness-enum.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: rustc_peek: bit not set + --> $DIR/liveness-enum.rs:15:5 + | +LL | rustc_peek(x); + | ^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/cast-rfc0401.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/cast-rfc0401.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/cast-rfc0401.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/cast-rfc0401.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -28,8 +28,9 @@ | help: consider borrowing the value | -LL | let _ = &*v as &u8; - | ++ +LL - let _ = v as &u8; +LL + let _ = &*v; + | error[E0605]: non-primitive cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:30:13 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-arg-count.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-arg-count.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-arg-count.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-arg-count.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -119,7 +119,9 @@ --> $DIR/closure-arg-count.rs:24:57 | LL | let _it = vec![1, 2, 3].into_iter().enumerate().map(foo); - | ^^^ expected function that takes a single 2-tuple as argument + | --- ^^^ expected function that takes a single 2-tuple as argument + | | + | required by a bound introduced by this call ... LL | fn foo() {} | -------- takes 0 arguments @@ -130,13 +132,17 @@ LL | let bar = |i, x, y| i; | --------- takes 3 distinct arguments LL | let _it = vec![1, 2, 3].into_iter().enumerate().map(bar); - | ^^^ expected closure that takes a single 2-tuple as argument + | --- ^^^ expected closure that takes a single 2-tuple as argument + | | + | required by a bound introduced by this call error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments --> $DIR/closure-arg-count.rs:29:57 | LL | let _it = vec![1, 2, 3].into_iter().enumerate().map(qux); - | ^^^ expected function that takes a single 2-tuple as argument + | --- ^^^ expected function that takes a single 2-tuple as argument + | | + | required by a bound introduced by this call ... LL | fn qux(x: usize, y: usize) {} | -------------------------- takes 2 distinct arguments @@ -145,13 +151,17 @@ --> $DIR/closure-arg-count.rs:32:45 | LL | let _it = vec![1, 2, 3].into_iter().map(usize::checked_add); - | ^^^^^^^^^^^^^^^^^^ expected function that takes 1 argument + | --- ^^^^^^^^^^^^^^^^^^ expected function that takes 1 argument + | | + | required by a bound introduced by this call error[E0593]: function is expected to take 0 arguments, but it takes 1 argument --> $DIR/closure-arg-count.rs:35:10 | LL | call(Foo); - | ^^^ expected function that takes 0 arguments + | ---- ^^^ expected function that takes 0 arguments + | | + | required by a bound introduced by this call ... LL | struct Foo(u8); | --------------- takes 1 argument diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -30,7 +30,7 @@ | = note: expected type `for<'r> Fn<(*mut &'r u32,)>` found type `Fn<(*mut &'a u32,)>` -note: the required lifetime does not necessarily outlive the lifetime `'a` as defined on the function body at 9:10 +note: the required lifetime does not necessarily outlive the lifetime `'a` as defined here --> $DIR/closure-arg-type-mismatch.rs:9:10 | LL | fn _test<'a>(f: fn(*mut &'a u32)) { @@ -58,7 +58,7 @@ | = note: expected type `for<'r> Fn<(*mut &'r u32,)>` found type `Fn<(*mut &'a u32,)>` -note: the lifetime `'a` as defined on the function body at 9:10 doesn't meet the lifetime requirements +note: the lifetime `'a` as defined here doesn't meet the lifetime requirements --> $DIR/closure-arg-type-mismatch.rs:9:10 | LL | fn _test<'a>(f: fn(*mut &'a u32)) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-mismatch.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-mismatch.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-mismatch.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/closure-mismatch.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,6 +20,11 @@ | LL | baz(|_| ()); | ^^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/closure-mismatch.rs:5:11 + | +LL | fn baz(_: T) {} + | ^^^ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/E0631.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/E0631.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/E0631.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/E0631.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -33,7 +33,9 @@ | ------------ found signature of `fn(u64) -> _` ... LL | foo(f); - | ^ expected signature of `fn(usize) -> _` + | --- ^ expected signature of `fn(usize) -> _` + | | + | required by a bound introduced by this call | note: required by a bound in `foo` --> $DIR/E0631.rs:3:11 @@ -48,7 +50,9 @@ | ------------ found signature of `fn(u64) -> _` ... LL | bar(f); - | ^ expected signature of `fn(usize) -> _` + | --- ^ expected signature of `fn(usize) -> _` + | | + | required by a bound introduced by this call | note: required by a bound in `bar` --> $DIR/E0631.rs:4:11 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/fn-variance-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/fn-variance-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/fn-variance-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/fn-variance-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,9 @@ | --------------------------- found signature of `for<'r> fn(&'r mut isize) -> _` ... LL | apply(&3, takes_mut); - | ^^^^^^^^^ expected signature of `fn(&{integer}) -> _` + | ----- ^^^^^^^^^ expected signature of `fn(&{integer}) -> _` + | | + | required by a bound introduced by this call | note: required by a bound in `apply` --> $DIR/fn-variance-1.rs:5:37 @@ -20,7 +22,9 @@ | ----------------------- found signature of `for<'r> fn(&'r isize) -> _` ... LL | apply(&mut 3, takes_imm); - | ^^^^^^^^^ expected signature of `fn(&mut {integer}) -> _` + | ----- ^^^^^^^^^ expected signature of `fn(&mut {integer}) -> _` + | | + | required by a bound introduced by this call | note: required by a bound in `apply` --> $DIR/fn-variance-1.rs:5:37 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/issue-26480.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/issue-26480.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/issue-26480.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/issue-26480.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,13 +5,13 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found `usize` ... LL | write!(hello); - | -------------- in this macro invocation + | ------------- in this macro invocation | = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | ($arr.len() * size_of($arr[0])).try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | + +++++++++++++++++++++ error[E0605]: non-primitive cast: `{integer}` as `()` --> $DIR/issue-26480.rs:22:19 @@ -20,7 +20,7 @@ | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object ... LL | cast!(2); - | --------- in this macro invocation + | -------- in this macro invocation | = note: this error originates in the macro `cast` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,10 @@ | = note: the following trait bounds were not satisfied: `Foo: Debug` +help: consider annotating `Foo` with `#[derive(Debug)]` + | +LL | #[derive(Debug)] + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/numeric-literal-cast.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/numeric-literal-cast.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/numeric-literal-cast.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/numeric-literal-cast.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `u8` to `u16` | LL | foo(1u16); - | ~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-literal-cast.rs:8:10 @@ -18,7 +18,7 @@ help: change the type of the numeric literal from `f32` to `f64` | LL | foo1(2f64); - | ~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-literal-cast.rs:10:10 @@ -29,7 +29,7 @@ help: change the type of the numeric literal from `i16` to `i32` | LL | foo2(3i32); - | ~~~~ + | ~~~ error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,5 +16,6 @@ let z = call_it(3, f); //~^ ERROR type mismatch //~| NOTE expected signature of `fn(isize, isize) -> _` + //~| NOTE required by a bound introduced by this call println!("{}", z); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,9 @@ | ----------------------------- found signature of `fn(usize, isize) -> _` LL | LL | let z = call_it(3, f); - | ^ expected signature of `fn(isize, isize) -> _` + | ------- ^ expected signature of `fn(isize, isize) -> _` + | | + | required by a bound introduced by this call | note: required by a bound in `call_it` --> $DIR/unboxed-closures-vtable-mismatch.rs:7:14 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/missing/missing-allocator.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/missing/missing-allocator.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/missing/missing-allocator.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/missing/missing-allocator.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait. +error: no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/missing/missing-alloc_error_handler.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/missing/missing-alloc_error_handler.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/missing/missing-alloc_error_handler.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/missing/missing-alloc_error_handler.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ -error: `#[alloc_error_handler]` function required, but not found. +error: `#[alloc_error_handler]` function required, but not found -note: Use `#![feature(default_alloc_error_handler)]` for a default error handler. +note: Use `#![feature(default_alloc_error_handler)]` for a default error handler error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/issue-56411.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/issue-56411.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/issue-56411.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/issue-56411.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ | you can use `as` to change the binding name of the import ... LL | import!(("issue-56411-aux.rs", issue_56411_aux)); - | ------------------------------------------------- in this macro invocation + | ------------------------------------------------ in this macro invocation | = note: `issue_56411_aux` must be defined only once in the type namespace of this module = note: this error originates in the macro `import` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -22,7 +22,7 @@ | ^^^^^^^^^^^ re-export of private `issue_56411_aux` ... LL | import!(("issue-56411-aux.rs", issue_56411_aux)); - | ------------------------------------------------- in this macro invocation + | ------------------------------------------------ in this macro invocation | = note: consider declaring type or module `issue_56411_aux` with `pub` = note: this error originates in the macro `import` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/path-invalid-form.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/path-invalid-form.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/path-invalid-form.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/path-invalid-form.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,4 @@ +#[path = 123] //~ ERROR malformed `path` attribute +mod foo; + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/path-invalid-form.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/path-invalid-form.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/path-invalid-form.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/path-invalid-form.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: malformed `path` attribute input + --> $DIR/path-invalid-form.rs:1:1 + | +LL | #[path = 123] + | ^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/path-macro.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/path-macro.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/path-macro.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/path-macro.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +macro_rules! foo { + () => {"bar.rs"}; +} + +#[path = foo!()] //~ ERROR malformed `path` attribute +mod abc; + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/path-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/path-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/modules/path-macro.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/modules/path-macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: malformed `path` attribute input + --> $DIR/path-macro.rs:5:1 + | +LL | #[path = foo!()] + | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/monomorphize-abi-alignment.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/monomorphize-abi-alignment.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/monomorphize-abi-alignment.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/monomorphize-abi-alignment.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ // run-pass #![allow(non_upper_case_globals)] +#![allow(dead_code)] /*! * On x86_64-linux-gnu and possibly other platforms, structs get 8-byte "preferred" alignment, * but their "ABI" alignment (i.e., what actually matters for data layout) is the largest alignment diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/issue-72649-uninit-in-loop.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/issue-72649-uninit-in-loop.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/issue-72649-uninit-in-loop.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/issue-72649-uninit-in-loop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,74 @@ +// Regression test for issue #72649 +// Tests that we don't emit spurious +// 'value moved in previous iteration of loop' message + +struct NonCopy; + +fn good() { + loop { + let value = NonCopy{}; + let _used = value; + } +} + +fn moved_here_1() { + loop { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + let _used = value; + //~^ NOTE value moved here + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value used here after move + } +} + +fn moved_here_2() { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + loop { + let _used = value; + //~^ NOTE value moved here + loop { + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value used here after move + } + } +} + +fn moved_loop_1() { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + loop { + let _used = value; //~ ERROR use of moved value: `value` + //~^ NOTE value moved here, in previous iteration of loop + } +} + +fn moved_loop_2() { + let mut value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + let _used = value; + value = NonCopy{}; + loop { + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value moved here, in previous iteration of loop + } +} + +fn uninit_1() { + loop { + let value: NonCopy; + let _used = value; //~ ERROR use of possibly-uninitialized variable: `value` + //~^ NOTE use of possibly-uninitialized `value` + } +} + +fn uninit_2() { + let mut value: NonCopy; + loop { + let _used = value; //~ ERROR use of possibly-uninitialized variable: `value` + //~^ NOTE use of possibly-uninitialized `value` + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/issue-72649-uninit-in-loop.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/issue-72649-uninit-in-loop.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/issue-72649-uninit-in-loop.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/issue-72649-uninit-in-loop.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,58 @@ +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:20:22 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +LL | +LL | let _used = value; + | ----- value moved here +LL | +LL | let _used2 = value; + | ^^^^^ value used here after move + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:32:26 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used = value; + | ----- value moved here +... +LL | let _used2 = value; + | ^^^^^ value used here after move + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:42:21 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used = value; + | ^^^^^ value moved here, in previous iteration of loop + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:53:22 + | +LL | let mut value = NonCopy{}; + | --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used2 = value; + | ^^^^^ value moved here, in previous iteration of loop + +error[E0381]: use of possibly-uninitialized variable: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:61:21 + | +LL | let _used = value; + | ^^^^^ use of possibly-uninitialized `value` + +error[E0381]: use of possibly-uninitialized variable: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:69:21 + | +LL | let _used = value; + | ^^^^^ use of possibly-uninitialized `value` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0381, E0382. +For more information about an error, try `rustc --explain E0381`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-1-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-1-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-1-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-1-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // run-pass #![allow(unused_mut)] -#![feature(box_syntax)] +#![allow(dead_code)] #[derive(Clone)] struct Triple { @@ -12,12 +12,12 @@ fn test(x: bool, foo: Box) -> isize { let bar = foo; let mut y: Box; - if x { y = bar; } else { y = box Triple{x: 4, y: 5, z: 6}; } + if x { y = bar; } else { y = Box::new(Triple{x: 4, y: 5, z: 6}); } return y.y; } pub fn main() { - let x: Box<_> = box Triple{x: 1, y: 2, z: 3}; + let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3}); assert_eq!(test(true, x.clone()), 2); assert_eq!(test(true, x.clone()), 2); assert_eq!(test(true, x.clone()), 2); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct X { x: isize, y: isize, z: isize } -pub fn main() { let x: Box<_> = box X {x: 1, y: 2, z: 3}; let y = x; assert_eq!(y.y, 2); } +pub fn main() { let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); let y = x; assert_eq!(y.y, 2); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-2-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-2-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-2-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-2-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,10 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct X { x: isize, y: isize, z: isize } pub fn main() { - let x: Box<_> = box X{x: 1, y: 2, z: 3}; + let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); let y = x; assert_eq!(y.y, 2); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-3-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-3-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-3-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-3-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // run-pass #![allow(unused_mut)] -#![feature(box_syntax)] +#![allow(dead_code)] #[derive(Clone)] struct Triple { @@ -12,12 +12,12 @@ fn test(x: bool, foo: Box) -> isize { let bar = foo; let mut y: Box; - if x { y = bar; } else { y = box Triple {x: 4, y: 5, z: 6}; } + if x { y = bar; } else { y = Box::new(Triple {x: 4, y: 5, z: 6}); } return y.y; } pub fn main() { - let x: Box<_> = box Triple{x: 1, y: 2, z: 3}; + let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3}); for _ in 0_usize..10000_usize { assert_eq!(test(true, x.clone()), 2); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-4.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-4.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-4.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-4.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct Triple { a: isize, b: isize, c: isize } @@ -13,7 +12,7 @@ } pub fn main() { - let x = box Triple{a: 1, b: 2, c: 3}; + let x = Box::new(Triple{ a: 1, b: 2, c: 3 }); let y = test(x); assert_eq!(y.c, 3); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-4-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-4-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-4-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-4-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct Triple {a: isize, b: isize, c: isize} @@ -13,7 +12,7 @@ } pub fn main() { - let x = box Triple{a: 1, b: 2, c: 3}; + let x = Box::new(Triple{a: 1, b: 2, c: 3}); let y = test(x); assert_eq!(y.c, 3); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-arg-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-arg-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-arg-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-arg-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,12 @@ // run-pass -#![feature(box_syntax)] fn test(foo: Box>) { assert_eq!((*foo)[0], 10); } pub fn main() { - let x = box vec![10]; + let x = Box::new(vec![10]); // Test forgetting a local by move-in test(x); // Test forgetting a temporary by move-in. - test(box vec![10]); + test(Box::new(vec![10])); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-arg-2-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-arg-2-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-arg-2-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-arg-2-unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,12 @@ // run-pass -#![feature(box_syntax)] fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } pub fn main() { - let x = box vec![10]; + let x = Box::new(vec![10]); // Test forgetting a local by move-in test(x); // Test forgetting a temporary by move-in. - test(box vec![10]); + test(Box::new(vec![10])); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-fn-self-receiver.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-fn-self-receiver.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-fn-self-receiver.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-fn-self-receiver.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -75,7 +75,7 @@ --> $DIR/move-fn-self-receiver.rs:50:5 | LL | let ret = mut_foo.use_mut_self(); - | ------- borrow of `mut_foo` occurs here + | ---------------------- borrow of `mut_foo` occurs here LL | mut_foo; | ^^^^^^^ move out of `mut_foo` occurs here LL | ret; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-guard-same-consts.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-guard-same-consts.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-guard-same-consts.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-guard-same-consts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,16 +2,16 @@ // arms whose patterns were composed solely of constants to not have // them linked in the cfg. // -// THis was broken for various reasons. In particular, that hack was +// This was broken for various reasons. In particular, that hack was // originally authored under the assunption that other checks // elsewhere would ensure that the two patterns did not overlap. But // that assumption did not hold, at least not in the long run (namely, // overlapping patterns were turned into warnings rather than errors). -#![feature(box_syntax)] + fn main() { - let x: Box<_> = box 1; + let x: Box<_> = Box::new(1); let v = (1, 2); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-guard-same-consts.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-guard-same-consts.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-guard-same-consts.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-guard-same-consts.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-guard-same-consts.rs:20:24 | -LL | let x: Box<_> = box 1; +LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (1, 2) if take(x) => (), diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-1.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - pub fn main() { - let x: Box<_> = box 1; + + + let x: Box<_> = Box::new(1); let v = (1, 2); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-in-guard-1.rs:10:24 | -LL | let x: Box<_> = box 1; +LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (1, _) if take(x) => (), diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ -#![feature(box_syntax)] - pub fn main() { - let x: Box<_> = box 1; + let x: Box<_> = Box::new(1); let v = (1, 2); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-in-guard-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `x` - --> $DIR/move-in-guard-2.rs:10:24 + --> $DIR/move-in-guard-2.rs:8:24 | -LL | let x: Box<_> = box 1; +LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (_, 2) if take(x) => (), diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-out-of-tuple-field.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-out-of-tuple-field.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/move-out-of-tuple-field.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/move-out-of-tuple-field.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,13 @@ -#![feature(box_syntax)] - struct Foo(Box); + + fn main() { - let x: (Box<_>,) = (box 1,); + let x: (Box<_>,) = (Box::new(1),); let y = x.0; let z = x.0; //~ ERROR use of moved value: `x.0` - let x = Foo(box 1); + let x = Foo(Box::new(1)); let y = x.0; let z = x.0; //~ ERROR use of moved value: `x.0` } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-block-bad.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-block-bad.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-block-bad.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-block-bad.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + struct S { x: Box @@ -16,7 +16,7 @@ } fn main() { - let s = S { x: box E::Bar(box 42) }; + let s = S { x: Box::new(E::Bar(Box::new(42))) }; loop { f(&s, |hellothere| { match hellothere.x { //~ ERROR cannot move out diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(box_syntax, unboxed_closures)] +#![feature(unboxed_closures)] fn to_fn>(f: F) -> F { f } fn test(_x: Box) {} fn main() { - let i = box 3; + let i = Box::new(3); let _f = to_fn(|| test(i)); //~ ERROR cannot move out } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,13 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:9:28 | -LL | let i = box 3; +LL | let i = Box::new(3); | - captured outer variable LL | let _f = to_fn(|| test(i)); - | ^ move occurs because `i` has type `Box`, which does not implement the `Copy` trait + | --------^- + | | | + | | move occurs because `i` has type `Box`, which does not implement the `Copy` trait + | captured by this `Fn` closure error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-tuple.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-tuple.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-tuple.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-tuple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - fn dup(x: Box) -> Box<(Box,Box)> { - box (x, x) + + + Box::new((x, x)) //~^ use of moved value: `x` [E0382] } fn main() { - dup(box 3); + dup(Box::new(3)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-tuple.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-tuple.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-tuple.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-based-on-type-tuple.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,13 @@ error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-tuple.rs:4:13 + --> $DIR/moves-based-on-type-tuple.rs:4:18 | LL | fn dup(x: Box) -> Box<(Box,Box)> { | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait -LL | box (x, x) - | - ^ value used here after move - | | - | value moved here +... +LL | Box::new((x, x)) + | - ^ value used here after move + | | + | value moved here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-sru-moved-field.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-sru-moved-field.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/moves/moves-sru-moved-field.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/moves/moves-sru-moved-field.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - type Noncopyable = Box; + + struct Foo { copied: isize, moved: Box, @@ -10,8 +10,8 @@ fn test0(f: Foo, g: Noncopyable, h: Noncopyable) { // just copy implicitly copyable fields from `f`, no moves: - let _b = Foo {moved: box 1, noncopyable: g, ..f}; - let _c = Foo {moved: box 2, noncopyable: h, ..f}; + let _b = Foo {moved: Box::new(1), noncopyable: g, ..f}; + let _c = Foo {moved: Box::new(2), noncopyable: h, ..f}; } fn test1(f: Foo, g: Noncopyable, h: Noncopyable) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mut/mut-cant-alias.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mut/mut-cant-alias.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mut/mut-cant-alias.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mut/mut-cant-alias.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | let b2 = &mut *b; | ^ second mutable borrow occurs here LL | b1.use_mut(); - | -- first borrow later used here + | ------------ first borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mut/mut-cross-borrowing.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/mut/mut-cross-borrowing.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mut/mut-cross-borrowing.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mut/mut-cross-borrowing.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn f(_: &mut isize) {} fn main() { - let mut x: Box<_> = box 3; + + let mut x: Box<_> = Box::new(3); + f(x) //~ ERROR mismatched types } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mut/mut-suggestion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mut/mut-suggestion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mut/mut-suggestion.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mut/mut-suggestion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | --- help: consider changing this to be mutable: `mut arg` ... LL | arg.mutate(); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable --> $DIR/mut-suggestion.rs:20:5 @@ -14,7 +14,7 @@ | ----- help: consider changing this to be mutable: `mut local` ... LL | local.mutate(); - | ^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mutexguard-sync.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/mutexguard-sync.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mutexguard-sync.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mutexguard-sync.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/mutexguard-sync.rs:11:15 | LL | test_sync(guard); - | ^^^^^ `Cell` cannot be shared between threads safely + | --------- ^^^^^ `Cell` cannot be shared between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `Cell` = note: required because of the requirements on the impl of `Sync` for `MutexGuard<'_, Cell>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/mut-function-arguments.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/mut-function-arguments.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/mut-function-arguments.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/mut-function-arguments.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ // run-pass -#![feature(box_syntax)] - fn f(mut y: Box) { *y = 5; assert_eq!(*y, 5); @@ -9,13 +7,13 @@ fn g() { let frob = |mut q: Box| { *q = 2; assert_eq!(*q, 2); }; - let w = box 37; + let w = Box::new(37); frob(w); } pub fn main() { - let z = box 17; + let z = Box::new(17); f(z); g(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/namespace/namespace-mix.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/namespace/namespace-mix.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/namespace/namespace-mix.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/namespace/namespace-mix.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -100,7 +100,9 @@ --> $DIR/namespace-mix.rs:33:11 | LL | check(m1::S{}); - | ^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -112,7 +114,9 @@ --> $DIR/namespace-mix.rs:35:11 | LL | check(m2::S{}); - | ^^^^^^^ the trait `Impossible` is not implemented for `c::S` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `c::S` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -124,7 +128,9 @@ --> $DIR/namespace-mix.rs:36:11 | LL | check(m2::S); - | ^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -136,7 +142,9 @@ --> $DIR/namespace-mix.rs:39:11 | LL | check(xm1::S{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -148,7 +156,9 @@ --> $DIR/namespace-mix.rs:41:11 | LL | check(xm2::S{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::S` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::S` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -160,7 +170,9 @@ --> $DIR/namespace-mix.rs:42:11 | LL | check(xm2::S); - | ^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -172,7 +184,9 @@ --> $DIR/namespace-mix.rs:55:11 | LL | check(m3::TS{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -184,7 +198,9 @@ --> $DIR/namespace-mix.rs:56:11 | LL | check(m3::TS); - | ^^^^^^ the trait `Impossible` is not implemented for `fn() -> c::TS {c::TS}` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `fn() -> c::TS {c::TS}` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -196,7 +212,9 @@ --> $DIR/namespace-mix.rs:57:11 | LL | check(m4::TS{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `c::TS` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::TS` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -208,7 +226,9 @@ --> $DIR/namespace-mix.rs:58:11 | LL | check(m4::TS); - | ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -220,7 +240,9 @@ --> $DIR/namespace-mix.rs:61:11 | LL | check(xm3::TS{}); - | ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -232,7 +254,9 @@ --> $DIR/namespace-mix.rs:62:11 | LL | check(xm3::TS); - | ^^^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -244,7 +268,9 @@ --> $DIR/namespace-mix.rs:63:11 | LL | check(xm4::TS{}); - | ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::TS` + | ----- ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::TS` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -256,7 +282,9 @@ --> $DIR/namespace-mix.rs:64:11 | LL | check(xm4::TS); - | ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -268,7 +296,9 @@ --> $DIR/namespace-mix.rs:77:11 | LL | check(m5::US{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -280,7 +310,9 @@ --> $DIR/namespace-mix.rs:78:11 | LL | check(m5::US); - | ^^^^^^ the trait `Impossible` is not implemented for `c::US` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::US` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -292,7 +324,9 @@ --> $DIR/namespace-mix.rs:79:11 | LL | check(m6::US{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `c::US` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::US` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -304,7 +338,9 @@ --> $DIR/namespace-mix.rs:80:11 | LL | check(m6::US); - | ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -316,7 +352,9 @@ --> $DIR/namespace-mix.rs:83:11 | LL | check(xm5::US{}); - | ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -328,7 +366,9 @@ --> $DIR/namespace-mix.rs:84:11 | LL | check(xm5::US); - | ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::US` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::US` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -340,7 +380,9 @@ --> $DIR/namespace-mix.rs:85:11 | LL | check(xm6::US{}); - | ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::US` + | ----- ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::US` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -352,7 +394,9 @@ --> $DIR/namespace-mix.rs:86:11 | LL | check(xm6::US); - | ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -364,7 +408,9 @@ --> $DIR/namespace-mix.rs:99:11 | LL | check(m7::V{}); - | ^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -376,7 +422,9 @@ --> $DIR/namespace-mix.rs:101:11 | LL | check(m8::V{}); - | ^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -388,7 +436,9 @@ --> $DIR/namespace-mix.rs:102:11 | LL | check(m8::V); - | ^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -400,7 +450,9 @@ --> $DIR/namespace-mix.rs:105:11 | LL | check(xm7::V{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -412,7 +464,9 @@ --> $DIR/namespace-mix.rs:107:11 | LL | check(xm8::V{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -424,7 +478,9 @@ --> $DIR/namespace-mix.rs:108:11 | LL | check(xm8::V); - | ^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -436,7 +492,9 @@ --> $DIR/namespace-mix.rs:121:11 | LL | check(m9::TV{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -448,7 +506,9 @@ --> $DIR/namespace-mix.rs:122:11 | LL | check(m9::TV); - | ^^^^^^ the trait `Impossible` is not implemented for `fn() -> c::E {c::E::TV}` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `fn() -> c::E {c::E::TV}` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -460,7 +520,9 @@ --> $DIR/namespace-mix.rs:123:11 | LL | check(mA::TV{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -472,7 +534,9 @@ --> $DIR/namespace-mix.rs:124:11 | LL | check(mA::TV); - | ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -484,7 +548,9 @@ --> $DIR/namespace-mix.rs:127:11 | LL | check(xm9::TV{}); - | ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -496,7 +562,9 @@ --> $DIR/namespace-mix.rs:128:11 | LL | check(xm9::TV); - | ^^^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -508,7 +576,9 @@ --> $DIR/namespace-mix.rs:129:11 | LL | check(xmA::TV{}); - | ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` + | ----- ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -520,7 +590,9 @@ --> $DIR/namespace-mix.rs:130:11 | LL | check(xmA::TV); - | ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -532,7 +604,9 @@ --> $DIR/namespace-mix.rs:143:11 | LL | check(mB::UV{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -544,7 +618,9 @@ --> $DIR/namespace-mix.rs:144:11 | LL | check(mB::UV); - | ^^^^^^ the trait `Impossible` is not implemented for `c::E` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::E` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -556,7 +632,9 @@ --> $DIR/namespace-mix.rs:145:11 | LL | check(mC::UV{}); - | ^^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -568,7 +646,9 @@ --> $DIR/namespace-mix.rs:146:11 | LL | check(mC::UV); - | ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -580,7 +660,9 @@ --> $DIR/namespace-mix.rs:149:11 | LL | check(xmB::UV{}); - | ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -592,7 +674,9 @@ --> $DIR/namespace-mix.rs:150:11 | LL | check(xmB::UV); - | ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -604,7 +688,9 @@ --> $DIR/namespace-mix.rs:151:11 | LL | check(xmC::UV{}); - | ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` + | ----- ^^^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 @@ -616,7 +702,9 @@ --> $DIR/namespace-mix.rs:152:11 | LL | check(xmC::UV); - | ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` + | | + | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/namespace-mix.rs:21:13 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// compile-flags: -Zunstable-options --crate-type rlib +// build-fail +// error-pattern: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs + +#![feature(native_link_modifiers)] +#![feature(native_link_modifiers_bundle)] +#![feature(native_link_modifiers_whole_archive)] + +#[link(name = "mylib", kind = "static", modifiers = "+bundle,+whole-archive")] +extern "C" { } + +fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive-link-attr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +error: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs + +error: could not find native static library `mylib`, perhaps an -L flag is missing? + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +// Mixing +bundle and +whole-archive is not allowed + +// compile-flags: -l static:+bundle,+whole-archive=mylib -Zunstable-options --crate-type rlib +// build-fail +// error-pattern: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs + +fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/native-library-link-flags/mix-bundle-and-whole-archive.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +error: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs + +error: could not find native static library `mylib`, perhaps an -L flag is missing? + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.fallback.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.fallback.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.fallback.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.fallback.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied + --> $DIR/defaulted-never-note.rs:30:5 + | +LL | foo(_x); + | ^^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` + | + = note: this trait is implemented for `()` + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) + = help: did you intend to use the type `()` here instead? +note: required by a bound in `foo` + --> $DIR/defaulted-never-note.rs:25:11 + | +LL | fn foo(_t: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,10 @@ +// revisions: nofallback fallback +//[nofallback] run-pass +//[fallback] check-fail + // We need to opt into the `never_type_fallback` feature // to trigger the requirement that this is testing. -#![feature(never_type, never_type_fallback)] +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] #![allow(unused)] @@ -19,16 +23,16 @@ impl ImplementedForUnitButNotNever for () {} fn foo(_t: T) {} -//~^ NOTE required by this bound in `foo` -//~| NOTE required by a bound in `foo` +//[fallback]~^ NOTE required by this bound in `foo` +//[fallback]~| NOTE required by a bound in `foo` fn smeg() { let _x = return; foo(_x); - //~^ ERROR the trait bound - //~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented - //~| NOTE this trait is implemented for `()` - //~| NOTE this error might have been caused - //~| HELP did you intend + //[fallback]~^ ERROR the trait bound + //[fallback]~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented + //[fallback]~| NOTE this trait is implemented for `()` + //[fallback]~| NOTE this error might have been caused + //[fallback]~| HELP did you intend } fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/defaulted-never-note.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied - --> $DIR/defaulted-never-note.rs:26:5 - | -LL | foo(_x); - | ^^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` - | - = note: this trait is implemented for `()`. - = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information). - = help: did you intend to use the type `()` here instead? -note: required by a bound in `foo` - --> $DIR/defaulted-never-note.rs:21:11 - | -LL | fn foo(_t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-control-flow.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-control-flow.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-control-flow.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-control-flow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,30 +1,28 @@ +// revisions: nofallback fallback // run-pass #![allow(dead_code)] #![allow(unused_assignments)] #![allow(unused_variables)] #![allow(unreachable_code)] - // Test various cases where we permit an unconstrained variable -// to fallback based on control-flow. -// -// These represent current behavior, but are pretty dubious. I would -// like to revisit these and potentially change them. --nmatsakis - -#![feature(never_type, never_type_fallback)] +// to fallback based on control-flow. In all of these cases, +// the type variable winds up being the target of both a `!` coercion +// and a coercion from a non-`!` variable, and hence falls back to `()`. +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] -trait BadDefault { +trait UnitDefault { fn default() -> Self; } -impl BadDefault for u32 { +impl UnitDefault for u32 { fn default() -> Self { 0 } } -impl BadDefault for ! { - fn default() -> ! { +impl UnitDefault for () { + fn default() -> () { panic!() } } @@ -33,7 +31,7 @@ let x; if true { - x = BadDefault::default(); + x = UnitDefault::default(); } else { x = return; } @@ -45,13 +43,13 @@ if true { x = return; } else { - x = BadDefault::default(); + x = UnitDefault::default(); } } fn if_then_else() { let _x = if true { - BadDefault::default() + UnitDefault::default() } else { return; }; @@ -61,19 +59,19 @@ let _x = if true { return; } else { - BadDefault::default() + UnitDefault::default() }; } fn match_arm() { - let _x = match Ok(BadDefault::default()) { + let _x = match Ok(UnitDefault::default()) { Ok(v) => v, Err(()) => return, }; } fn match_arm_rev() { - let _x = match Ok(BadDefault::default()) { + let _x = match Ok(UnitDefault::default()) { Err(()) => return, Ok(v) => v, }; @@ -84,7 +82,7 @@ if false { break return; } else { - break BadDefault::default(); + break UnitDefault::default(); } }; } @@ -94,9 +92,9 @@ if false { break return; } else { - break BadDefault::default(); + break UnitDefault::default(); } }; } -fn main() { } +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `!: Test` is not satisfied + --> $DIR/diverging-fallback-no-leak.rs:17:5 + | +LL | unconstrained_arg(return); + | ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!` + | + = note: this trait is implemented for `()` + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) + = help: did you intend to use the type `()` here instead? +note: required by a bound in `unconstrained_arg` + --> $DIR/diverging-fallback-no-leak.rs:12:25 + | +LL | fn unconstrained_arg(_: T) {} + | ^^^^ required by this bound in `unconstrained_arg` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-no-leak.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-no-leak.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-no-leak.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-no-leak.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +// revisions: nofallback fallback +//[nofallback] check-pass + +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] + +fn make_unit() {} + +trait Test {} +impl Test for i32 {} +impl Test for () {} + +fn unconstrained_arg(_: T) {} + +fn main() { + // Here the type variable falls back to `!`, + // and hence we get a type error. + unconstrained_arg(return); + //[fallback]~^ ERROR trait bound `!: Test` is not satisfied +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,37 @@ +// Variant of diverging-falllback-control-flow that tests +// the specific case of a free function with an unconstrained +// return type. This captures the pattern we saw in the wild +// in the objc crate, where changing the fallback from `!` to `()` +// resulted in unsoundness. +// +// check-pass + +// revisions: nofallback fallback + +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] + + +fn make_unit() {} + +trait UnitReturn {} +impl UnitReturn for i32 {} +impl UnitReturn for () {} + +fn unconstrained_return() -> T { + unsafe { + let make_unit_fn: fn() = make_unit; + let ffi: fn() -> T = std::mem::transmute(make_unit_fn); + ffi() + } +} + +fn main() { + // In Ye Olde Days, the `T` parameter of `unconstrained_return` + // winds up "entangled" with the `!` type that results from + // `panic!`, and hence falls back to `()`. This is kind of unfortunate + // and unexpected. When we introduced the `!` type, the original + // idea was to change that fallback to `!`, but that would have resulted + // in this code no longer compiling (or worse, in some cases it injected + // unsound results). + let _ = if true { unconstrained_return() } else { panic!() }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/expr-empty-ret.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/expr-empty-ret.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/expr-empty-ret.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/expr-empty-ret.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +// run-pass + +#![allow(dead_code)] +// Issue #521 + +// pretty-expanded FIXME #23616 + +fn f() { + let _x = match true { + true => { 10 } + false => { return } + }; +} + +pub fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-ret.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-ret.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-ret.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-ret.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +// This test verifies that never type fallback preserves the following code in a +// compiling state. This pattern is fairly common in the wild, notably seen in +// wasmtime v0.16. Typically this is some closure wrapper that expects a +// collection of 'known' signatures, and -> ! is not included in that set. +// +// This test is specifically targeted by the unit type fallback when +// encountering a set of obligations like `?T: Foo` and `Trait::Projection = +// ?T`. In the code below, these are `R: Bar` and `Fn::Output = R`. +// +// revisions: nofallback fallback +// check-pass + +#![cfg_attr(fallback, feature(never_type_fallback))] + +trait Bar { } +impl Bar for () { } +impl Bar for u32 { } + +fn foo(_: impl Fn() -> R) {} + +fn main() { + foo(|| panic!()); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 21:6] as FnOnce<()>>::Output == ()` + --> $DIR/fallback-closure-wrap.rs:18:31 + | +LL | let error = Closure::wrap(Box::new(move || { + | _______________________________^ +LL | | +LL | | panic!("Can't connect to server."); +LL | | }) as Box); + | |______^ expected `()`, found `!` + | + = note: expected unit type `()` + found type `!` + = note: required for the cast to the object type `dyn FnMut()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-wrap.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-wrap.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-wrap.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/fallback-closure-wrap.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +// This is a minified example from Crater breakage observed when attempting to +// stabilize never type, nstoddard/webgl-gui @ 22f0169f. +// +// This particular test case currently fails as the inference to `()` rather +// than `!` happens as a result of an `as` cast, which is not currently tracked. +// Crater did not find many cases of this occuring, but it is included for +// awareness. +// +// revisions: nofallback fallback +//[nofallback] check-pass +//[fallback] check-fail + +#![cfg_attr(fallback, feature(never_type_fallback))] + +use std::marker::PhantomData; + +fn main() { + let error = Closure::wrap(Box::new(move || { + //[fallback]~^ ERROR type mismatch resolving + panic!("Can't connect to server."); + }) as Box); +} + +struct Closure(PhantomData); + +impl Closure { + fn wrap(data: Box) -> Closure { + todo!() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `E: From<()>` is not satisfied + --> $DIR/never-value-fallback-issue-66757.rs:28:5 + | +LL | >::from(never); + | ^^^^^^^^^^^^^^^^^^^^ the trait `From<()>` is not implemented for `E` + | + = help: the following implementations were found: + > +note: required by `from` + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL + | +LL | fn from(_: T) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/never-value-fallback-issue-66757.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/never-value-fallback-issue-66757.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/never_type/never-value-fallback-issue-66757.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/never_type/never-value-fallback-issue-66757.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,13 @@ // never) and an uninferred variable (here the argument to `From`) it // doesn't fallback to `()` but rather `!`. // -// run-pass +// revisions: nofallback fallback +//[fallback] run-pass +//[nofallback] check-fail #![feature(never_type)] -// FIXME(#67225) -- this should be true even without the fallback gate. -#![feature(never_type_fallback)] +#![cfg_attr(fallback, feature(never_type_fallback))] struct E; @@ -21,9 +22,10 @@ #[allow(unreachable_code)] #[allow(dead_code)] +#[allow(unused_must_use)] fn foo(never: !) { >::from(never); // Ok - >::from(never); // Inference fails here + >::from(never); //[nofallback]~ ERROR trait bound `E: From<()>` is not satisfied } fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/new-box.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/new-box.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/new-box.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/new-box.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ // run-pass -#![feature(box_syntax)] - fn f(x: Box) { let y: &isize = &*x; println!("{}", *x); @@ -27,6 +25,6 @@ } fn main() { - f(box 1234); - g(box Struct as Box); + f(Box::new(1234)); + g(Box::new(Struct) as Box); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/new-box-syntax.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/new-box-syntax.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/new-box-syntax.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/new-box-syntax.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,6 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ #![allow(dead_code, unused_variables)] -#![feature(box_syntax)] // Tests that the new `box` syntax works with unique pointers. @@ -17,12 +16,12 @@ } pub fn main() { - let y: Box = box 2; - let b: Box = box (1 + 2); - let c = box (3 + 4); + let y: Box = Box::new(2); + let b: Box = Box::new(1 + 2); + let c = Box::new(3 + 4); - let s: Box = box Structure { + let s: Box = Box::new(Structure { x: 3, y: 4, - }; + }); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-access-spans.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-access-spans.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-access-spans.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-access-spans.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ | | | immutable borrow occurs here LL | r.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/closure-access-spans.rs:11:5 @@ -20,7 +20,7 @@ | | | second mutable borrow occurs here LL | r.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error[E0500]: closure requires unique access to `x` but it is already borrowed --> $DIR/closure-access-spans.rs:17:5 @@ -32,7 +32,7 @@ | | | closure construction occurs here LL | r.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/closure-access-spans.rs:23:13 @@ -42,7 +42,7 @@ LL | move || x; | ^ use of borrowed `x` LL | r.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/closure-access-spans.rs:29:5 @@ -54,7 +54,7 @@ | | | move out of `x` occurs here LL | r.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:35:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-borrow-spans.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-borrow-spans.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-borrow-spans.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-borrow-spans.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ LL | let y = x; | ^ move out of `x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/closure-borrow-spans.rs:11:13 @@ -20,7 +20,7 @@ LL | let y = &mut x; | ^^^^^^ mutable borrow occurs here LL | f.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:19:16 @@ -32,7 +32,7 @@ LL | } | - `x` dropped here while still borrowed LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-borrow-spans.rs:26:5 @@ -44,7 +44,7 @@ LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/closure-borrow-spans.rs:32:13 @@ -56,7 +56,7 @@ LL | let y = x; | ^ use of borrowed `x` LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/closure-borrow-spans.rs:38:13 @@ -68,7 +68,7 @@ LL | let y = &x; | ^^ immutable borrow occurs here LL | f.use_ref(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/closure-borrow-spans.rs:44:13 @@ -80,7 +80,7 @@ LL | let y = &mut x; | ^^^^^^ second mutable borrow occurs here LL | f.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:52:16 @@ -92,7 +92,7 @@ LL | } | - `x` dropped here while still borrowed LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-borrow-spans.rs:59:5 @@ -104,7 +104,7 @@ LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/closure-borrow-spans.rs:65:13 @@ -116,7 +116,7 @@ LL | let y = x; | ^ move out of `x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access --> $DIR/closure-borrow-spans.rs:71:13 @@ -128,7 +128,7 @@ LL | let y = &x; | ^^ second borrow occurs here LL | f.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error[E0501]: cannot borrow `x` as mutable because previous closure requires unique access --> $DIR/closure-borrow-spans.rs:77:13 @@ -140,7 +140,7 @@ LL | let y = &mut x; | ^^^^^^ second borrow occurs here LL | f.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:86:16 @@ -152,7 +152,7 @@ LL | } | - `x` dropped here while still borrowed LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/closure-borrow-spans.rs:93:5 @@ -164,7 +164,7 @@ LL | *x = 1; | ^^^^^^ assignment to borrowed `*x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to 14 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,16 +38,19 @@ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5 | LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | ------ `cell_a` is a reference that is only valid in the function body + | -- ------ `cell_a` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | }); - | |______^ `cell_a` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | | ^ + | | | + | |______`cell_a` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,16 +38,19 @@ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5 | LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | ------ `cell_a` is a reference that is only valid in the function body + | -- ------ `cell_a` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | }); - | |______^ `cell_a` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | | ^ + | | | + | |______`cell_a` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | &*x | ^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/get_default.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/get_default.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/get_default.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/get_default.nll.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:21:17 - | -LL | fn ok(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` -... -LL | map.set(String::new()); // Ideally, this would not error. - | ^^^ mutable borrow occurs here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:32:17 - | -LL | fn err(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here - | ^^^ mutable borrow occurs here -LL | -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:37:17 - | -LL | fn err(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` -... -LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^ mutable borrow occurs here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0502`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/get_default.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/get_default.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/get_default.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/get_default.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | - let's call the lifetime of this reference `'1` LL | loop { LL | match map.get() { - | --- immutable borrow occurs here + | --------- immutable borrow occurs here LL | Some(v) => { LL | return v; | - returning this value requires that `*map` is borrowed for `'1` @@ -20,7 +20,7 @@ | - let's call the lifetime of this reference `'1` LL | loop { LL | match map.get() { - | --- immutable borrow occurs here + | --------- immutable borrow occurs here LL | Some(v) => { LL | map.set(String::new()); // Both AST and MIR error here | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here @@ -35,7 +35,7 @@ | - let's call the lifetime of this reference `'1` LL | loop { LL | match map.get() { - | --- immutable borrow occurs here + | --------- immutable borrow occurs here ... LL | return v; | - returning this value requires that `*map` is borrowed for `'1` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-46036.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-46036.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-46036.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-46036.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `a` is borrowed for `'static` + | this usage requires that `a` is borrowed for `'static` LL | loop { } LL | } | - `a` dropped here while still borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-46589.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-46589.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-46589.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-46589.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,10 @@ --> $DIR/issue-46589.rs:23:21 | LL | *other = match (*other).get_self() { - | -------- first mutable borrow occurs here + | ------------------- first mutable borrow occurs here LL | Some(s) => s, LL | None => (*other).new_self() - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | | | second mutable borrow occurs here | first borrow later used here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-50716.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-50716.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-50716.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-50716.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | let _x = *s; | ^^ proving this value is `Sized` requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-50716.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-50716.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-50716.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-50716.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,9 +4,9 @@ LL | let _x = *s; | ^^ lifetime mismatch | - = note: expected type `Sized` - found type `Sized` -note: the lifetime `'a` as defined on the function body at 9:8... + = note: expected type `<<&'a T as A>::X as Sized>` + found type `<<&'static T as A>::X as Sized>` +note: the lifetime `'a` as defined here... --> $DIR/issue-50716.rs:9:8 | LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-51191.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-51191.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-51191.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-51191.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -45,7 +45,7 @@ --> $DIR/issue-51191.rs:22:9 | LL | (&mut self).bar(); - | ^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable --> $DIR/issue-51191.rs:28:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,10 @@ LL | let x = (vec![22], vec![44]); | - captured outer variable LL | expect_fn(|| drop(x.0)); - | ^^^ move occurs because `x.0` has type `Vec`, which does not implement the `Copy` trait + | --------^^^- + | | | + | | move occurs because `x.0` has type `Vec`, which does not implement the `Copy` trait + | captured by this `Fn` closure error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52663-trait-object.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52663-trait-object.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52663-trait-object.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52663-trait-object.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,16 +1,16 @@ -#![feature(box_syntax)] - trait Foo { fn get(&self); } impl Foo for A { fn get(&self) { } } + + fn main() { let _ = { let tmp0 = 3; let tmp1 = &tmp0; - box tmp1 as Box + Box::new(tmp1) as Box }; //~^^^ ERROR `tmp0` does not live long enough } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52663-trait-object.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52663-trait-object.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52663-trait-object.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52663-trait-object.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,8 @@ | LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough -LL | box tmp1 as Box - | ----------------------------- borrow later captured here by trait object +LL | Box::new(tmp1) as Box + | ----------------------------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52669.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52669.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52669.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52669.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | foo(a); | - value moved here LL | a.b.clone() - | ^^^ value borrowed here after move + | ^^^^^^^^^^^ value borrowed here after move error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52742.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52742.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-52742.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-52742.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | self.y = b.z | ^^^ | -note: ...the reference is valid for the lifetime `'_` as defined on the impl at 12:10... +note: ...the reference is valid for the lifetime `'_` as defined here... --> $DIR/issue-52742.rs:12:10 | LL | impl Foo<'_, '_> { | ^^ -note: ...but the borrowed content is only valid for the anonymous lifetime defined on the method body at 13:31 +note: ...but the borrowed content is only valid for the anonymous lifetime defined here --> $DIR/issue-52742.rs:13:31 | LL | fn take_bar(&mut self, b: Bar<'_>) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-53773.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-53773.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-53773.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-53773.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | } | - here, drop of `child` needs exclusive access to `*child.raw`, because the type `C<'_>` implements the `Drop` trait LL | members.len(); - | ------- borrow later used here + | ------------- borrow later used here | = note: consider using a `let` binding to create a longer lived value diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-54556-niconii.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-54556-niconii.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-54556-niconii.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-54556-niconii.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-54556-niconii.rs:22:20 | LL | if let Ok(_) = counter.lock() { } - | ^^^^^^^------- + | ^^^^^^^^^^^^^^ | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55394.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55394.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55394.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55394.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | Foo { bar } | ^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 8:17... +note: first, the lifetime cannot outlive the anonymous lifetime defined here... --> $DIR/issue-55394.rs:8:17 | LL | fn new(bar: &mut Bar) -> Self { @@ -14,12 +14,12 @@ | LL | Foo { bar } | ^^^ -note: but, the lifetime must be valid for the lifetime `'_` as defined on the impl at 7:10... +note: but, the lifetime must be valid for the lifetime `'_` as defined here... --> $DIR/issue-55394.rs:7:10 | LL | impl Foo<'_> { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/issue-55394.rs:9:9 | LL | Foo { bar } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55401.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55401.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55401.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55401.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ LL | let (ref y, _z): (&'a u32, u32) = (&22, 44); LL | *y | ^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55401.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55401.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55401.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55401.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 1:47 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/issue-55401.rs:1:47 | LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55825-const-fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55825-const-fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55825-const-fn.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55825-const-fn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +// Regression test for issue #55825 +// Tests that we don't emit a spurious warning in NLL mode + +#![feature(nll)] + +const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~ ERROR const + +fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55825-const-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55825-const-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-55825-const-fn.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-55825-const-fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +error[E0658]: trait objects in const fn are unstable + --> $DIR/issue-55825-const-fn.rs:6:32 + | +LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-58299.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-58299.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-58299.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-58299.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | A::<'a>::X..=A::<'static>::X => (), | ^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-58299.rs:24:27 @@ -17,8 +15,6 @@ ... LL | A::<'static>::X..=A::<'a>::X => (), | ^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-62007-assign-const-index.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-62007-assign-const-index.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-62007-assign-const-index.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-62007-assign-const-index.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ | - let's call the lifetime of this reference `'1` ... LL | if let Some(n) = list[0].next.as_mut() { - | ^^^^^^^^^^^^--------- + | ^^^^^^^^^^^^^^^^^^^^^ | | | `list[_].next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list[_].next` is borrowed for `'1` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-62007-assign-differing-fields.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-62007-assign-differing-fields.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-62007-assign-differing-fields.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-62007-assign-differing-fields.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ | -- lifetime `'a` defined here ... LL | if let Some(n) = (list.0).next.as_mut() { - | ^^^^^^^^^^^^^--------- + | ^^^^^^^^^^^^^^^^^^^^^^ | | | `list.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.next` is borrowed for `'a` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-67007-escaping-data.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-67007-escaping-data.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-67007-escaping-data.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-67007-escaping-data.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +// Regression test for issue #67007 +// Ensures that we show information about the specific regions involved + +#![feature(nll)] + +// Covariant over 'a, invariant over 'tcx +struct FnCtxt<'a, 'tcx: 'a>(&'a (), *mut &'tcx ()); + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + fn use_it(&self, _: &'tcx ()) {} +} + +struct Consumer<'tcx>(&'tcx ()); + +impl<'tcx> Consumer<'tcx> { + fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { + let other = self.use_fcx(fcx); //~ ERROR borrowed data + fcx.use_it(other); + } + + fn use_fcx<'a>(&self, _: &FnCtxt<'a, 'tcx>) -> &'a () { + &() + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-67007-escaping-data.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-67007-escaping-data.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-67007-escaping-data.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-67007-escaping-data.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0521]: borrowed data escapes outside of associated function + --> $DIR/issue-67007-escaping-data.rs:17:21 + | +LL | impl<'tcx> Consumer<'tcx> { + | ---- lifetime `'tcx` defined here +LL | fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { + | -- ----- --- `fcx` is a reference that is only valid in the associated function body + | | | + | | `self` declared here, outside of the associated function body + | lifetime `'a` defined here +LL | let other = self.use_fcx(fcx); + | ^^^^^^^^^^^^^^^^^ + | | + | `fcx` escapes the associated function body here + | argument requires that `'a` must outlive `'tcx` + | + = help: consider adding the following bound: `'a: 'tcx` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-73159-rpit-static.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-73159-rpit-static.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-73159-rpit-static.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-73159-rpit-static.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// Regression test for issue #73159 +// Tests thar we don't suggest replacing 'a with 'static' + +#![feature(nll)] + +struct Foo<'a>(&'a [u8]); + +impl<'a> Foo<'a> { + fn make_it(&self) -> impl Iterator { //~ ERROR lifetime may not live + self.0.iter().copied() + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-73159-rpit-static.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-73159-rpit-static.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/issue-73159-rpit-static.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/issue-73159-rpit-static.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/issue-73159-rpit-static.rs:9:26 + | +LL | impl<'a> Foo<'a> { + | -- lifetime `'a` defined here +LL | fn make_it(&self) -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/loan_ends_mid_block_vec.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/loan_ends_mid_block_vec.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/loan_ends_mid_block_vec.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/loan_ends_mid_block_vec.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | --------- first mutable borrow occurs here LL | capitalize(slice); LL | data.push('d'); - | ^^^^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^ second mutable borrow occurs here ... LL | capitalize(slice); | ----- first borrow later used here @@ -17,7 +17,7 @@ | --------- first mutable borrow occurs here ... LL | data.push('e'); - | ^^^^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^ second mutable borrow occurs here ... LL | capitalize(slice); | ----- first borrow later used here @@ -29,7 +29,7 @@ | --------- first mutable borrow occurs here ... LL | data.push('f'); - | ^^^^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^ second mutable borrow occurs here LL | LL | capitalize(slice); | ----- first borrow later used here diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_reify.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_reify.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_reify.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_reify.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | f(x) | ^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | unsafe { g(input) } | ^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_unsize.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_unsize.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_unsize.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/mir_check_cast_unsize.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | x | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/normalization-bounds-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/normalization-bounds-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/normalization-bounds-error.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/normalization-bounds-error.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} | ^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'d` as defined on the function body at 12:14... +note: first, the lifetime cannot outlive the lifetime `'d` as defined here... --> $DIR/normalization-bounds-error.rs:12:14 | LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} | ^^ -note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the function body at 12:18... +note: ...but the lifetime must also be valid for the lifetime `'a` as defined here... --> $DIR/normalization-bounds-error.rs:12:18 | LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/outlives-suggestion-more.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/outlives-suggestion-more.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/outlives-suggestion-more.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/outlives-suggestion-more.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -46,8 +46,6 @@ | -- lifetime `'b` defined here LL | (x, y) | ^^^^^^ returning this value requires that `'b` must outlive `'static` - | - = help: consider replacing `'b` with `'static` help: the following changes may resolve your lifetime errors | @@ -88,8 +86,6 @@ ... LL | (x, y, z) | ^^^^^^^^^ returning this value requires that `'c` must outlive `'static` - | - = help: consider replacing `'c` with `'static` help: the following changes may resolve your lifetime errors | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/outlives-suggestion-simple.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/outlives-suggestion-simple.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/outlives-suggestion-simple.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/outlives-suggestion-simple.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,8 +17,6 @@ | -- lifetime `'a` defined here LL | x | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/outlives-suggestion-simple.rs:14:5 @@ -66,8 +64,6 @@ | -- lifetime `'a` defined here LL | Foo { x } | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/outlives-suggestion-simple.rs:41:9 @@ -96,13 +92,20 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/outlives-suggestion-simple.rs:73:9 | +LL | impl<'a> Foo2<'a> { + | -- lifetime `'a` defined here +LL | // should not produce outlives suggestions to name 'self LL | fn get_bar(&self) -> Bar2 { | ----- | | | `self` declared here, outside of the associated function body | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | Bar2::new(&self) - | ^^^^^^^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to 9 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/polonius/assignment-to-differing-field.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/polonius/assignment-to-differing-field.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/polonius/assignment-to-differing-field.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/polonius/assignment-to-differing-field.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ | -- lifetime `'a` defined here ... LL | if let Some(n) = (list.0).next.as_mut() { - | ^^^^^^^^^^^^^--------- + | ^^^^^^^^^^^^^^^^^^^^^^ | | | `list.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.next` is borrowed for `'a` @@ -41,7 +41,7 @@ | -- lifetime `'a` defined here ... LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^--------- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.0.0.0.0.next` is borrowed for `'a` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/region-ends-after-if-condition.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/region-ends-after-if-condition.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/region-ends-after-if-condition.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/region-ends-after-if-condition.nll.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable - --> $DIR/region-ends-after-if-condition.rs:26:9 - | -LL | let value = &my_struct.field; - | ---------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | drop(value); - | ----- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/relate_tys/fn-subtype.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/relate_tys/fn-subtype.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/relate_tys/fn-subtype.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/relate_tys/fn-subtype.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let y: for<'a> fn(&'a ()) = x; | ^ one type is more general than the other | - = note: expected fn pointer `for<'r> fn(&'r ())` + = note: expected fn pointer `for<'a> fn(&'a ())` found fn pointer `fn(&())` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it(); | ^^^^^^^^^ one type is more general than the other | - = note: expected fn pointer `for<'r, 's> fn(&'r u32, &'s u32) -> &'r u32` + = note: expected fn pointer `for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32` found fn pointer `for<'a> fn(&'a u32, &'a u32) -> &'a u32` error[E0308]: mismatched types @@ -14,7 +14,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected fn pointer `for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32` - found fn pointer `for<'r> fn(&'r u32, &'r u32) -> &'r u32` + found fn pointer `for<'a> fn(&'a u32, &'a u32) -> &'a u32` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/relate_tys/trait-hrtb.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/relate_tys/trait-hrtb.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/relate_tys/trait-hrtb.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/relate_tys/trait-hrtb.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let y: Box Foo<'a>> = x; | ^ one type is more general than the other | - = note: expected trait object `dyn for<'r> Foo<'r>` + = note: expected trait object `dyn for<'a> Foo<'a>` found trait object `dyn Foo<'_>` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/return_from_loop.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/return_from_loop.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/return_from_loop.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/return_from_loop.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,10 +5,10 @@ | -------------------- first mutable borrow occurs here LL | loop { LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here LL | LL | value.len(); - | ----- first borrow later used here + | ----------- first borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/trait-associated-constant.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/trait-associated-constant.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/trait-associated-constant.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/trait-associated-constant.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected enum `Option<&'b str>` found enum `Option<&'c str>` -note: the lifetime `'c` as defined on the impl at 20:18... +note: the lifetime `'c` as defined here... --> $DIR/trait-associated-constant.rs:20:18 | LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct { | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 20:14 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/trait-associated-constant.rs:20:14 | LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/ty-outlives/wf-unreachable.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/ty-outlives/wf-unreachable.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/ty-outlives/wf-unreachable.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/ty-outlives/wf-unreachable.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ LL | return; LL | let x: &'static &'a (); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:13:12 @@ -17,8 +15,6 @@ LL | return; LL | let x: &'static &'a () = &&(); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:17:12 @@ -27,8 +23,6 @@ | -- lifetime `'a` defined here LL | let x: &'static &'a _; | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:23:12 @@ -38,8 +32,6 @@ LL | return; LL | let x: &'static &'a _ = &&(); | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:28:12 @@ -49,8 +41,6 @@ LL | return; LL | let _: &'static &'a (); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:33:12 @@ -60,8 +50,6 @@ LL | return; LL | let _: &'static &'a () = &&(); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:38:12 @@ -71,8 +59,6 @@ LL | return; LL | let _: &'static &'a _ = &&(); | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:51:12 @@ -82,8 +68,6 @@ LL | return; LL | let _: C<'static, 'a, _> = C((), &(), &()); | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 8 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/type-alias-free-regions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/type-alias-free-regions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/type-alias-free-regions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/type-alias-free-regions.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | C { f: b } | ^ | -note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 16:24... +note: first, the lifetime cannot outlive the anonymous lifetime defined here... --> $DIR/type-alias-free-regions.rs:16:24 | LL | fn from_box(b: Box) -> Self { @@ -16,12 +16,12 @@ | ^ = note: expected `Box>` found `Box>` -note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/type-alias-free-regions.rs:15:6 | LL | impl<'a> FromBox<'a> for C<'a> { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/type-alias-free-regions.rs:17:9 | LL | C { f: b } @@ -35,7 +35,7 @@ LL | C { f: Box::new(b.0) } | ^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 26:23... +note: first, the lifetime cannot outlive the anonymous lifetime defined here... --> $DIR/type-alias-free-regions.rs:26:23 | LL | fn from_tuple(b: (B,)) -> Self { @@ -47,12 +47,12 @@ | ^^^ = note: expected `Box<&isize>` found `Box<&isize>` -note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/type-alias-free-regions.rs:25:6 | LL | impl<'a> FromTuple<'a> for C<'a> { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/type-alias-free-regions.rs:27:9 | LL | C { f: Box::new(b.0) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-brace-enums.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-brace-enums.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-brace-enums.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-brace-enums.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'static` + | this usage requires that `c` is borrowed for `'static` LL | } | - `c` dropped here while still borrowed @@ -19,7 +19,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'a` + | this usage requires that `c` is borrowed for `'a` LL | } | - `c` dropped here while still borrowed @@ -33,7 +33,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'a` + | this usage requires that `c` is borrowed for `'a` LL | }; | - `c` dropped here while still borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-brace-structs.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-brace-structs.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-brace-structs.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-brace-structs.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'static` + | this usage requires that `c` is borrowed for `'static` LL | } | - `c` dropped here while still borrowed @@ -19,7 +19,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'a` + | this usage requires that `c` is borrowed for `'a` LL | } | - `c` dropped here while still borrowed @@ -33,7 +33,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'a` + | this usage requires that `c` is borrowed for `'a` LL | }; | - `c` dropped here while still borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'static` + | this usage requires that `c` is borrowed for `'static` LL | } | - `c` dropped here while still borrowed @@ -19,7 +19,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'a` + | this usage requires that `c` is borrowed for `'a` LL | } | - `c` dropped here while still borrowed @@ -33,7 +33,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'a` + | this usage requires that `c` is borrowed for `'a` LL | }; | - `c` dropped here while still borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'static` + | this usage requires that `c` is borrowed for `'static` LL | } | - `c` dropped here while still borrowed @@ -19,7 +19,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'a` + | this usage requires that `c` is borrowed for `'a` LL | } | - `c` dropped here while still borrowed @@ -33,7 +33,7 @@ | ^^ | | | borrowed value does not live long enough - | requires that `c` is borrowed for `'a` + | this usage requires that `c` is borrowed for `'a` LL | }; | - `c` dropped here while still borrowed diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/closure-substs.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/closure-substs.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/closure-substs.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/closure-substs.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | return x; | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/closure-substs.rs:15:16 @@ -25,16 +23,19 @@ ... LL | b(x); | ^^^^ argument requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error[E0521]: borrowed data escapes outside of closure --> $DIR/closure-substs.rs:29:9 | LL | |x: &i32, b: fn(&'static i32)| { - | - `x` is a reference that is only valid in the closure body + | - - let's call the lifetime of this reference `'1` + | | + | `x` is a reference that is only valid in the closure body LL | b(x); - | ^^^^ `x` escapes the closure body here + | ^^^^ + | | + | `x` escapes the closure body here + | argument requires that `'1` must outlive `'static` error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | >::C | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | <() as Foo<'a>>::C | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 17:8 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/constant-in-expr-normalize.rs:17:8 | LL | fn foo<'a>(_: &'a u32) -> &'static u32 { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | <() as Foo<'a>>::C | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 9:8 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/constant-in-expr-trait-item-1.rs:9:8 | LL | fn foo<'a>(_: &'a u32) -> &'static u32 { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | >::C | ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 9:8 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/constant-in-expr-trait-item-2.rs:9:8 | LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | T::C | ^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | T::C | ^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:8... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/constant-in-expr-trait-item-3.rs:9:8 | LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | A::<'a>::IC; | ^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-54124.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-54124.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-54124.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-54124.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -15,8 +15,6 @@ | -- lifetime `'a` defined here LL | let _:fn(&()) = |_:&'a ()| {}; | ^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-55748-pat-types-constrain-bindings.rs:49:5 @@ -17,8 +15,6 @@ ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-55748-pat-types-constrain-bindings.rs:62:5 @@ -28,8 +24,6 @@ ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ LL | let ((y, _z),) = ((s, _x),): (PairCoupledTypes<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:22:5 @@ -17,8 +15,6 @@ LL | let ((y, _z),) = ((s, _x),): (PairCoupledRegions<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:32:5 @@ -28,8 +24,6 @@ LL | let ((y, _z),) = ((s, _x),) as (PairCoupledTypes<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:37:5 @@ -39,8 +33,6 @@ LL | let ((y, _z),) = ((s, _x),) as (PairCoupledRegions<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/patterns.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/patterns.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/user-annotations/patterns.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/user-annotations/patterns.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -156,8 +156,6 @@ ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/patterns.rs:125:5 @@ -167,8 +165,6 @@ ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/patterns.rs:130:5 @@ -178,8 +174,6 @@ LL | let Single { value: y }: Single<&'a u32> = Single { value: &22 }; LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/patterns.rs:134:18 @@ -188,8 +182,6 @@ | -- lifetime `'a` defined here LL | let (y, _z): (&'static u32, u32) = (x, 44); | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 19 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/where_clauses_in_structs.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/where_clauses_in_structs.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nll/where_clauses_in_structs.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nll/where_clauses_in_structs.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | | | lifetime `'a` defined here LL | Foo { x, y }; - | ^ requires that `'a` must outlive `'b` + | ^ this usage requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/no_crate_type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/no_crate_type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/no_crate_type.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/no_crate_type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/no_crate_type.rs:2:1 | LL | #![crate_type] - | ^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]` + | ^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/non-fmt-panic.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/non-fmt-panic.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/non-fmt-panic.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/non-fmt-panic.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -199,7 +199,7 @@ --> $DIR/non-fmt-panic.rs:31:5 | LL | panic!(concat!("{", "{")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/no_send-rc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/no_send-rc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/no_send-rc.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/no_send-rc.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/no_send-rc.rs:7:9 | LL | bar(x); - | ^ `Rc<{integer}>` cannot be sent between threads safely + | --- ^ `Rc<{integer}>` cannot be sent between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `Rc<{integer}>` note: required by a bound in `bar` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/no_send-struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/no_send-struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/no_send-struct.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/no_send-struct.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/no_send-struct.rs:15:9 | LL | bar(x); - | ^ `Foo` cannot be sent between threads safely + | --- ^ `Foo` cannot be sent between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `Foo` note: required by a bound in `bar` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/no_share-struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/no_share-struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/no_share-struct.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/no_share-struct.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/no_share-struct.rs:12:9 | LL | bar(x); - | ^ `Foo` cannot be shared between threads safely + | --- ^ `Foo` cannot be shared between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `Foo` note: required by a bound in `bar` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/nullable-pointer-iotareduction.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/nullable-pointer-iotareduction.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/nullable-pointer-iotareduction.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/nullable-pointer-iotareduction.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ // run-pass -#![feature(box_syntax)] - // Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions, // which "says that a destructor applied to an object built from a constructor // behaves as expected". -- https://coq.inria.fr/doc/language/core/conversion.html#iota-reduction @@ -64,7 +62,7 @@ pub fn main() { check_type!(&17, &isize); - check_type!(box 18, Box); + check_type!(Box::new(18), Box); check_type!("foo".to_string(), String); check_type!(vec![20, 22], Vec); check_type!(main, fn(), |pthing| { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/const-scope.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/const-scope.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/const-scope.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/const-scope.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `i8` to `i32` | LL | const C: i32 = 1i32; - | ~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/const-scope.rs:2:15 @@ -26,7 +26,7 @@ help: change the type of the numeric literal from `i8` to `i32` | LL | let c: i32 = 1i32; - | ~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/const-scope.rs:6:17 @@ -47,7 +47,7 @@ help: change the type of the numeric literal from `i8` to `i32` | LL | let c: i32 = 1i32; - | ~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/const-scope.rs:11:17 @@ -60,7 +60,7 @@ help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | let d: i8 = c.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/len.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/len.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/len.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/len.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | test(array.len().try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,27 +9,33 @@ help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | let x: u16 = foo().try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-2.rs:7:18 | LL | let y: i64 = x + x; - | --- ^^^^^ - | | | - | | expected `i64`, found `u16` - | | help: you can convert a `u16` to an `i64`: `(x + x).into()` + | --- ^^^^^ expected `i64`, found `u16` + | | | expected due to this + | +help: you can convert a `u16` to an `i64` + | +LL | let y: i64 = (x + x).into(); + | + ++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-2.rs:9:18 | LL | let z: i32 = x + x; - | --- ^^^^^ - | | | - | | expected `i32`, found `u16` - | | help: you can convert a `u16` to an `i32`: `(x + x).into()` + | --- ^^^^^ expected `i32`, found `u16` + | | | expected due to this + | +help: you can convert a `u16` to an `i32` + | +LL | let z: i32 = (x + x).into(); + | + ++++++++ error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-binop.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-binop.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-binop.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-binop.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: you can convert `x_u8` from `u8` to `u16`, matching the type of `x_u16` | LL | u16::from(x_u8) > x_u16; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:25:16 @@ -18,7 +18,7 @@ help: you can convert `x_u8` from `u8` to `u32`, matching the type of `x_u32` | LL | u32::from(x_u8) > x_u32; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:27:16 @@ -29,7 +29,7 @@ help: you can convert `x_u8` from `u8` to `u64`, matching the type of `x_u64` | LL | u64::from(x_u8) > x_u64; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:29:16 @@ -40,7 +40,7 @@ help: you can convert `x_u8` from `u8` to `u128`, matching the type of `x_u128` | LL | u128::from(x_u8) > x_u128; - | ~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:31:16 @@ -51,16 +51,18 @@ help: you can convert `x_u8` from `u8` to `usize`, matching the type of `x_usize` | LL | usize::from(x_u8) > x_usize; - | ~~~~~~~~~~~~~~~~~ + | ++++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:34:17 | LL | x_u16 > x_u8; - | ^^^^ - | | - | expected `u16`, found `u8` - | help: you can convert a `u8` to a `u16`: `x_u8.into()` + | ^^^^ expected `u16`, found `u8` + | +help: you can convert a `u8` to a `u16` + | +LL | x_u16 > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:36:17 @@ -71,7 +73,7 @@ help: you can convert `x_u16` from `u16` to `u32`, matching the type of `x_u32` | LL | u32::from(x_u16) > x_u32; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:38:17 @@ -82,7 +84,7 @@ help: you can convert `x_u16` from `u16` to `u64`, matching the type of `x_u64` | LL | u64::from(x_u16) > x_u64; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:40:17 @@ -93,7 +95,7 @@ help: you can convert `x_u16` from `u16` to `u128`, matching the type of `x_u128` | LL | u128::from(x_u16) > x_u128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:42:17 @@ -104,25 +106,29 @@ help: you can convert `x_u16` from `u16` to `usize`, matching the type of `x_usize` | LL | usize::from(x_u16) > x_usize; - | ~~~~~~~~~~~~~~~~~~ + | ++++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:45:17 | LL | x_u32 > x_u8; - | ^^^^ - | | - | expected `u32`, found `u8` - | help: you can convert a `u8` to a `u32`: `x_u8.into()` + | ^^^^ expected `u32`, found `u8` + | +help: you can convert a `u8` to a `u32` + | +LL | x_u32 > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:47:17 | LL | x_u32 > x_u16; - | ^^^^^ - | | - | expected `u32`, found `u16` - | help: you can convert a `u16` to a `u32`: `x_u16.into()` + | ^^^^^ expected `u32`, found `u16` + | +help: you can convert a `u16` to a `u32` + | +LL | x_u32 > x_u16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:49:17 @@ -133,7 +139,7 @@ help: you can convert `x_u32` from `u32` to `u64`, matching the type of `x_u64` | LL | u64::from(x_u32) > x_u64; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:51:17 @@ -144,7 +150,7 @@ help: you can convert `x_u32` from `u32` to `u128`, matching the type of `x_u128` | LL | u128::from(x_u32) > x_u128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:53:17 @@ -155,34 +161,40 @@ help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:56:17 | LL | x_u64 > x_u8; - | ^^^^ - | | - | expected `u64`, found `u8` - | help: you can convert a `u8` to a `u64`: `x_u8.into()` + | ^^^^ expected `u64`, found `u8` + | +help: you can convert a `u8` to a `u64` + | +LL | x_u64 > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:58:17 | LL | x_u64 > x_u16; - | ^^^^^ - | | - | expected `u64`, found `u16` - | help: you can convert a `u16` to a `u64`: `x_u16.into()` + | ^^^^^ expected `u64`, found `u16` + | +help: you can convert a `u16` to a `u64` + | +LL | x_u64 > x_u16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:60:17 | LL | x_u64 > x_u32; - | ^^^^^ - | | - | expected `u64`, found `u32` - | help: you can convert a `u32` to a `u64`: `x_u32.into()` + | ^^^^^ expected `u64`, found `u32` + | +help: you can convert a `u32` to a `u64` + | +LL | x_u64 > x_u32.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:62:17 @@ -193,7 +205,7 @@ help: you can convert `x_u64` from `u64` to `u128`, matching the type of `x_u128` | LL | u128::from(x_u64) > x_u128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:64:17 @@ -204,43 +216,51 @@ help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:67:18 | LL | x_u128 > x_u8; - | ^^^^ - | | - | expected `u128`, found `u8` - | help: you can convert a `u8` to a `u128`: `x_u8.into()` + | ^^^^ expected `u128`, found `u8` + | +help: you can convert a `u8` to a `u128` + | +LL | x_u128 > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:69:18 | LL | x_u128 > x_u16; - | ^^^^^ - | | - | expected `u128`, found `u16` - | help: you can convert a `u16` to a `u128`: `x_u16.into()` + | ^^^^^ expected `u128`, found `u16` + | +help: you can convert a `u16` to a `u128` + | +LL | x_u128 > x_u16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:71:18 | LL | x_u128 > x_u32; - | ^^^^^ - | | - | expected `u128`, found `u32` - | help: you can convert a `u32` to a `u128`: `x_u32.into()` + | ^^^^^ expected `u128`, found `u32` + | +help: you can convert a `u32` to a `u128` + | +LL | x_u128 > x_u32.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:73:18 | LL | x_u128 > x_u64; - | ^^^^^ - | | - | expected `u128`, found `u64` - | help: you can convert a `u64` to a `u128`: `x_u64.into()` + | ^^^^^ expected `u128`, found `u64` + | +help: you can convert a `u64` to a `u128` + | +LL | x_u128 > x_u64.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:75:18 @@ -251,25 +271,29 @@ help: you can convert a `usize` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:78:19 | LL | x_usize > x_u8; - | ^^^^ - | | - | expected `usize`, found `u8` - | help: you can convert a `u8` to a `usize`: `x_u8.into()` + | ^^^^ expected `usize`, found `u8` + | +help: you can convert a `u8` to a `usize` + | +LL | x_usize > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:80:19 | LL | x_usize > x_u16; - | ^^^^^ - | | - | expected `usize`, found `u16` - | help: you can convert a `u16` to a `usize`: `x_u16.into()` + | ^^^^^ expected `usize`, found `u16` + | +help: you can convert a `u16` to a `usize` + | +LL | x_usize > x_u16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:82:19 @@ -280,7 +304,7 @@ help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:84:19 @@ -291,7 +315,7 @@ help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:86:19 @@ -302,7 +326,7 @@ help: you can convert a `u128` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:92:16 @@ -313,7 +337,7 @@ help: you can convert `x_i8` from `i8` to `i16`, matching the type of `x_i16` | LL | i16::from(x_i8) > x_i16; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:94:16 @@ -324,7 +348,7 @@ help: you can convert `x_i8` from `i8` to `i32`, matching the type of `x_i32` | LL | i32::from(x_i8) > x_i32; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:96:16 @@ -335,7 +359,7 @@ help: you can convert `x_i8` from `i8` to `i64`, matching the type of `x_i64` | LL | i64::from(x_i8) > x_i64; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:98:16 @@ -346,7 +370,7 @@ help: you can convert `x_i8` from `i8` to `i128`, matching the type of `x_i128` | LL | i128::from(x_i8) > x_i128; - | ~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:100:16 @@ -357,16 +381,18 @@ help: you can convert `x_i8` from `i8` to `isize`, matching the type of `x_isize` | LL | isize::from(x_i8) > x_isize; - | ~~~~~~~~~~~~~~~~~ + | ++++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:103:17 | LL | x_i16 > x_i8; - | ^^^^ - | | - | expected `i16`, found `i8` - | help: you can convert an `i8` to an `i16`: `x_i8.into()` + | ^^^^ expected `i16`, found `i8` + | +help: you can convert an `i8` to an `i16` + | +LL | x_i16 > x_i8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:105:17 @@ -377,7 +403,7 @@ help: you can convert `x_i16` from `i16` to `i32`, matching the type of `x_i32` | LL | i32::from(x_i16) > x_i32; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:107:17 @@ -388,7 +414,7 @@ help: you can convert `x_i16` from `i16` to `i64`, matching the type of `x_i64` | LL | i64::from(x_i16) > x_i64; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:109:17 @@ -399,7 +425,7 @@ help: you can convert `x_i16` from `i16` to `i128`, matching the type of `x_i128` | LL | i128::from(x_i16) > x_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:111:17 @@ -410,25 +436,29 @@ help: you can convert `x_i16` from `i16` to `isize`, matching the type of `x_isize` | LL | isize::from(x_i16) > x_isize; - | ~~~~~~~~~~~~~~~~~~ + | ++++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:114:17 | LL | x_i32 > x_i8; - | ^^^^ - | | - | expected `i32`, found `i8` - | help: you can convert an `i8` to an `i32`: `x_i8.into()` + | ^^^^ expected `i32`, found `i8` + | +help: you can convert an `i8` to an `i32` + | +LL | x_i32 > x_i8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:116:17 | LL | x_i32 > x_i16; - | ^^^^^ - | | - | expected `i32`, found `i16` - | help: you can convert an `i16` to an `i32`: `x_i16.into()` + | ^^^^^ expected `i32`, found `i16` + | +help: you can convert an `i16` to an `i32` + | +LL | x_i32 > x_i16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:118:17 @@ -439,7 +469,7 @@ help: you can convert `x_i32` from `i32` to `i64`, matching the type of `x_i64` | LL | i64::from(x_i32) > x_i64; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:120:17 @@ -450,7 +480,7 @@ help: you can convert `x_i32` from `i32` to `i128`, matching the type of `x_i128` | LL | i128::from(x_i32) > x_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:122:17 @@ -461,34 +491,40 @@ help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_isize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:125:17 | LL | x_i64 > x_i8; - | ^^^^ - | | - | expected `i64`, found `i8` - | help: you can convert an `i8` to an `i64`: `x_i8.into()` + | ^^^^ expected `i64`, found `i8` + | +help: you can convert an `i8` to an `i64` + | +LL | x_i64 > x_i8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:127:17 | LL | x_i64 > x_i16; - | ^^^^^ - | | - | expected `i64`, found `i16` - | help: you can convert an `i16` to an `i64`: `x_i16.into()` + | ^^^^^ expected `i64`, found `i16` + | +help: you can convert an `i16` to an `i64` + | +LL | x_i64 > x_i16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:129:17 | LL | x_i64 > x_i32; - | ^^^^^ - | | - | expected `i64`, found `i32` - | help: you can convert an `i32` to an `i64`: `x_i32.into()` + | ^^^^^ expected `i64`, found `i32` + | +help: you can convert an `i32` to an `i64` + | +LL | x_i64 > x_i32.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:131:17 @@ -499,7 +535,7 @@ help: you can convert `x_i64` from `i64` to `i128`, matching the type of `x_i128` | LL | i128::from(x_i64) > x_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:133:17 @@ -510,43 +546,51 @@ help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_isize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:136:18 | LL | x_i128 > x_i8; - | ^^^^ - | | - | expected `i128`, found `i8` - | help: you can convert an `i8` to an `i128`: `x_i8.into()` + | ^^^^ expected `i128`, found `i8` + | +help: you can convert an `i8` to an `i128` + | +LL | x_i128 > x_i8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:138:18 | LL | x_i128 > x_i16; - | ^^^^^ - | | - | expected `i128`, found `i16` - | help: you can convert an `i16` to an `i128`: `x_i16.into()` + | ^^^^^ expected `i128`, found `i16` + | +help: you can convert an `i16` to an `i128` + | +LL | x_i128 > x_i16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:140:18 | LL | x_i128 > x_i32; - | ^^^^^ - | | - | expected `i128`, found `i32` - | help: you can convert an `i32` to an `i128`: `x_i32.into()` + | ^^^^^ expected `i128`, found `i32` + | +help: you can convert an `i32` to an `i128` + | +LL | x_i128 > x_i32.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:142:18 | LL | x_i128 > x_i64; - | ^^^^^ - | | - | expected `i128`, found `i64` - | help: you can convert an `i64` to an `i128`: `x_i64.into()` + | ^^^^^ expected `i128`, found `i64` + | +help: you can convert an `i64` to an `i128` + | +LL | x_i128 > x_i64.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:144:18 @@ -557,25 +601,29 @@ help: you can convert an `isize` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_isize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:147:19 | LL | x_isize > x_i8; - | ^^^^ - | | - | expected `isize`, found `i8` - | help: you can convert an `i8` to an `isize`: `x_i8.into()` + | ^^^^ expected `isize`, found `i8` + | +help: you can convert an `i8` to an `isize` + | +LL | x_isize > x_i8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:149:19 | LL | x_isize > x_i16; - | ^^^^^ - | | - | expected `isize`, found `i16` - | help: you can convert an `i16` to an `isize`: `x_i16.into()` + | ^^^^^ expected `isize`, found `i16` + | +help: you can convert an `i16` to an `isize` + | +LL | x_isize > x_i16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:151:19 @@ -586,7 +634,7 @@ help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:153:19 @@ -597,7 +645,7 @@ help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:155:19 @@ -608,7 +656,7 @@ help: you can convert an `i128` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:161:16 @@ -619,7 +667,7 @@ help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit | LL | x_u8 > x_i8.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:163:16 @@ -630,7 +678,7 @@ help: you can convert `x_u8` from `u8` to `i16`, matching the type of `x_i16` | LL | i16::from(x_u8) > x_i16; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:165:16 @@ -641,7 +689,7 @@ help: you can convert `x_u8` from `u8` to `i32`, matching the type of `x_i32` | LL | i32::from(x_u8) > x_i32; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:167:16 @@ -652,7 +700,7 @@ help: you can convert `x_u8` from `u8` to `i64`, matching the type of `x_i64` | LL | i64::from(x_u8) > x_i64; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:169:16 @@ -663,7 +711,7 @@ help: you can convert `x_u8` from `u8` to `i128`, matching the type of `x_i128` | LL | i128::from(x_u8) > x_i128; - | ~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:171:16 @@ -674,7 +722,7 @@ help: you can convert `x_u8` from `u8` to `isize`, matching the type of `x_isize` | LL | isize::from(x_u8) > x_isize; - | ~~~~~~~~~~~~~~~~~ + | ++++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:174:17 @@ -685,7 +733,7 @@ help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_i8.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:176:17 @@ -696,7 +744,7 @@ help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_i16.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:178:17 @@ -707,7 +755,7 @@ help: you can convert `x_u16` from `u16` to `i32`, matching the type of `x_i32` | LL | i32::from(x_u16) > x_i32; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:180:17 @@ -718,7 +766,7 @@ help: you can convert `x_u16` from `u16` to `i64`, matching the type of `x_i64` | LL | i64::from(x_u16) > x_i64; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:182:17 @@ -729,7 +777,7 @@ help: you can convert `x_u16` from `u16` to `i128`, matching the type of `x_i128` | LL | i128::from(x_u16) > x_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:184:17 @@ -740,7 +788,7 @@ help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_isize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:187:17 @@ -751,7 +799,7 @@ help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i8.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:189:17 @@ -762,7 +810,7 @@ help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i16.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:191:17 @@ -773,7 +821,7 @@ help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:193:17 @@ -784,7 +832,7 @@ help: you can convert `x_u32` from `u32` to `i64`, matching the type of `x_i64` | LL | i64::from(x_u32) > x_i64; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:195:17 @@ -795,7 +843,7 @@ help: you can convert `x_u32` from `u32` to `i128`, matching the type of `x_i128` | LL | i128::from(x_u32) > x_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:197:17 @@ -806,7 +854,7 @@ help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_isize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:200:17 @@ -817,7 +865,7 @@ help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i8.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:202:17 @@ -828,7 +876,7 @@ help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i16.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:204:17 @@ -839,7 +887,7 @@ help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:206:17 @@ -850,7 +898,7 @@ help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:208:17 @@ -861,7 +909,7 @@ help: you can convert `x_u64` from `u64` to `i128`, matching the type of `x_i128` | LL | i128::from(x_u64) > x_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:210:17 @@ -872,7 +920,7 @@ help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_isize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:213:18 @@ -883,7 +931,7 @@ help: you can convert an `i8` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i8.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:215:18 @@ -894,7 +942,7 @@ help: you can convert an `i16` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i16.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:217:18 @@ -905,7 +953,7 @@ help: you can convert an `i32` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:219:18 @@ -916,7 +964,7 @@ help: you can convert an `i64` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:221:18 @@ -927,7 +975,7 @@ help: you can convert an `i128` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:223:18 @@ -938,7 +986,7 @@ help: you can convert an `isize` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_isize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:226:19 @@ -949,7 +997,7 @@ help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i8.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:228:19 @@ -960,7 +1008,7 @@ help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i16.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:230:19 @@ -971,7 +1019,7 @@ help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:232:19 @@ -982,7 +1030,7 @@ help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:234:19 @@ -993,7 +1041,7 @@ help: you can convert an `i128` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:236:19 @@ -1004,7 +1052,7 @@ help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_isize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:242:16 @@ -1015,7 +1063,7 @@ help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u8.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:244:16 @@ -1026,7 +1074,7 @@ help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u16.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:246:16 @@ -1037,7 +1085,7 @@ help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:248:16 @@ -1048,7 +1096,7 @@ help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:250:16 @@ -1059,7 +1107,7 @@ help: you can convert a `u128` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:252:16 @@ -1070,16 +1118,18 @@ help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:255:17 | LL | x_i16 > x_u8; - | ^^^^ - | | - | expected `i16`, found `u8` - | help: you can convert a `u8` to an `i16`: `x_u8.into()` + | ^^^^ expected `i16`, found `u8` + | +help: you can convert a `u8` to an `i16` + | +LL | x_i16 > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:257:17 @@ -1090,7 +1140,7 @@ help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u16.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:259:17 @@ -1101,7 +1151,7 @@ help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:261:17 @@ -1112,7 +1162,7 @@ help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:263:17 @@ -1123,7 +1173,7 @@ help: you can convert a `u128` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:265:17 @@ -1134,25 +1184,29 @@ help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:268:17 | LL | x_i32 > x_u8; - | ^^^^ - | | - | expected `i32`, found `u8` - | help: you can convert a `u8` to an `i32`: `x_u8.into()` + | ^^^^ expected `i32`, found `u8` + | +help: you can convert a `u8` to an `i32` + | +LL | x_i32 > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:270:17 | LL | x_i32 > x_u16; - | ^^^^^ - | | - | expected `i32`, found `u16` - | help: you can convert a `u16` to an `i32`: `x_u16.into()` + | ^^^^^ expected `i32`, found `u16` + | +help: you can convert a `u16` to an `i32` + | +LL | x_i32 > x_u16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:272:17 @@ -1163,7 +1217,7 @@ help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:274:17 @@ -1174,7 +1228,7 @@ help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:276:17 @@ -1185,7 +1239,7 @@ help: you can convert a `u128` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:278:17 @@ -1196,34 +1250,40 @@ help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:281:17 | LL | x_i64 > x_u8; - | ^^^^ - | | - | expected `i64`, found `u8` - | help: you can convert a `u8` to an `i64`: `x_u8.into()` + | ^^^^ expected `i64`, found `u8` + | +help: you can convert a `u8` to an `i64` + | +LL | x_i64 > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:283:17 | LL | x_i64 > x_u16; - | ^^^^^ - | | - | expected `i64`, found `u16` - | help: you can convert a `u16` to an `i64`: `x_u16.into()` + | ^^^^^ expected `i64`, found `u16` + | +help: you can convert a `u16` to an `i64` + | +LL | x_i64 > x_u16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:285:17 | LL | x_i64 > x_u32; - | ^^^^^ - | | - | expected `i64`, found `u32` - | help: you can convert a `u32` to an `i64`: `x_u32.into()` + | ^^^^^ expected `i64`, found `u32` + | +help: you can convert a `u32` to an `i64` + | +LL | x_i64 > x_u32.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:287:17 @@ -1234,7 +1294,7 @@ help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_u64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:289:17 @@ -1245,7 +1305,7 @@ help: you can convert a `u128` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_u128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:291:17 @@ -1256,43 +1316,51 @@ help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:294:18 | LL | x_i128 > x_u8; - | ^^^^ - | | - | expected `i128`, found `u8` - | help: you can convert a `u8` to an `i128`: `x_u8.into()` + | ^^^^ expected `i128`, found `u8` + | +help: you can convert a `u8` to an `i128` + | +LL | x_i128 > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:296:18 | LL | x_i128 > x_u16; - | ^^^^^ - | | - | expected `i128`, found `u16` - | help: you can convert a `u16` to an `i128`: `x_u16.into()` + | ^^^^^ expected `i128`, found `u16` + | +help: you can convert a `u16` to an `i128` + | +LL | x_i128 > x_u16.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:298:18 | LL | x_i128 > x_u32; - | ^^^^^ - | | - | expected `i128`, found `u32` - | help: you can convert a `u32` to an `i128`: `x_u32.into()` + | ^^^^^ expected `i128`, found `u32` + | +help: you can convert a `u32` to an `i128` + | +LL | x_i128 > x_u32.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:300:18 | LL | x_i128 > x_u64; - | ^^^^^ - | | - | expected `i128`, found `u64` - | help: you can convert a `u64` to an `i128`: `x_u64.into()` + | ^^^^^ expected `i128`, found `u64` + | +help: you can convert a `u64` to an `i128` + | +LL | x_i128 > x_u64.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:302:18 @@ -1303,7 +1371,7 @@ help: you can convert a `u128` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_u128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:304:18 @@ -1314,16 +1382,18 @@ help: you can convert a `usize` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:307:19 | LL | x_isize > x_u8; - | ^^^^ - | | - | expected `isize`, found `u8` - | help: you can convert a `u8` to an `isize`: `x_u8.into()` + | ^^^^ expected `isize`, found `u8` + | +help: you can convert a `u8` to an `isize` + | +LL | x_isize > x_u8.into(); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:309:19 @@ -1334,7 +1404,7 @@ help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u16.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:311:19 @@ -1345,7 +1415,7 @@ help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u32.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:313:19 @@ -1356,7 +1426,7 @@ help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u64.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:315:19 @@ -1367,7 +1437,7 @@ help: you can convert a `u128` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u128.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:317:19 @@ -1378,7 +1448,7 @@ help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_usize.try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to 132 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-no-fix.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-no-fix.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-no-fix.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast-no-fix.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -47,7 +47,7 @@ help: you can convert `x_u8` from `u8` to `isize`, matching the type of `-1_isize` | LL | isize::from(x_u8) > -1_isize; - | ~~~~~~~~~~~~~~~~~ + | ++++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:23:15 @@ -74,7 +74,7 @@ help: you can convert `x_u64` from `u64` to `i128`, matching the type of `-1_i128` | LL | i128::from(x_u64) > -1_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:29:13 @@ -85,7 +85,7 @@ help: you can convert `x_u32` from `u32` to `i128`, matching the type of `-1_i128` | LL | i128::from(x_u32) > -1_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:31:13 @@ -96,7 +96,7 @@ help: you can convert `x_u16` from `u16` to `i128`, matching the type of `-1_i128` | LL | i128::from(x_u16) > -1_i128; - | ~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:33:12 @@ -107,7 +107,7 @@ help: you can convert `x_u8` from `u8` to `i128`, matching the type of `-1_i128` | LL | i128::from(x_u8) > -1_i128; - | ~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:36:15 @@ -142,7 +142,7 @@ help: you can convert `x_u32` from `u32` to `i64`, matching the type of `-1_i64` | LL | i64::from(x_u32) > -1_i64; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:44:13 @@ -153,7 +153,7 @@ help: you can convert `x_u16` from `u16` to `i64`, matching the type of `-1_i64` | LL | i64::from(x_u16) > -1_i64; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:46:12 @@ -164,7 +164,7 @@ help: you can convert `x_u8` from `u8` to `i64`, matching the type of `-1_i64` | LL | i64::from(x_u8) > -1_i64; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:49:15 @@ -207,7 +207,7 @@ help: you can convert `x_u16` from `u16` to `i32`, matching the type of `-1_i32` | LL | i32::from(x_u16) > -1_i32; - | ~~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:59:12 @@ -218,7 +218,7 @@ help: you can convert `x_u8` from `u8` to `i32`, matching the type of `-1_i32` | LL | i32::from(x_u8) > -1_i32; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:62:15 @@ -269,7 +269,7 @@ help: you can convert `x_u8` from `u8` to `i16`, matching the type of `-1_i16` | LL | i16::from(x_u8) > -1_i16; - | ~~~~~~~~~~~~~~~ + | ++++++++++ + error[E0308]: mismatched types --> $DIR/numeric-cast-no-fix.rs:75:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-cast.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:25:18 @@ -18,25 +18,29 @@ help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:27:18 | LL | foo::(x_u16); - | ^^^^^ - | | - | expected `usize`, found `u16` - | help: you can convert a `u16` to a `usize`: `x_u16.into()` + | ^^^^^ expected `usize`, found `u16` + | +help: you can convert a `u16` to a `usize` + | +LL | foo::(x_u16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:29:18 | LL | foo::(x_u8); - | ^^^^ - | | - | expected `usize`, found `u8` - | help: you can convert a `u8` to a `usize`: `x_u8.into()` + | ^^^^ expected `usize`, found `u8` + | +help: you can convert a `u8` to a `usize` + | +LL | foo::(x_u8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:31:18 @@ -47,7 +51,7 @@ help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:33:18 @@ -58,7 +62,7 @@ help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:35:18 @@ -69,7 +73,7 @@ help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:37:18 @@ -80,7 +84,7 @@ help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:39:18 @@ -91,7 +95,7 @@ help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:44:18 @@ -102,7 +106,7 @@ help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:46:18 @@ -113,7 +117,7 @@ help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:48:18 @@ -124,7 +128,7 @@ help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:50:18 @@ -135,16 +139,18 @@ help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_u16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:52:18 | LL | foo::(x_u8); - | ^^^^ - | | - | expected `isize`, found `u8` - | help: you can convert a `u8` to an `isize`: `x_u8.into()` + | ^^^^ expected `isize`, found `u8` + | +help: you can convert a `u8` to an `isize` + | +LL | foo::(x_u8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:55:18 @@ -155,7 +161,7 @@ help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:57:18 @@ -166,25 +172,29 @@ help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:59:18 | LL | foo::(x_i16); - | ^^^^^ - | | - | expected `isize`, found `i16` - | help: you can convert an `i16` to an `isize`: `x_i16.into()` + | ^^^^^ expected `isize`, found `i16` + | +help: you can convert an `i16` to an `isize` + | +LL | foo::(x_i16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:61:18 | LL | foo::(x_i8); - | ^^^^ - | | - | expected `isize`, found `i8` - | help: you can convert an `i8` to an `isize`: `x_i8.into()` + | ^^^^ expected `isize`, found `i8` + | +help: you can convert an `i8` to an `isize` + | +LL | foo::(x_i8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:66:16 @@ -195,34 +205,40 @@ help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:69:16 | LL | foo::(x_u32); - | ^^^^^ - | | - | expected `u64`, found `u32` - | help: you can convert a `u32` to a `u64`: `x_u32.into()` + | ^^^^^ expected `u64`, found `u32` + | +help: you can convert a `u32` to a `u64` + | +LL | foo::(x_u32.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:71:16 | LL | foo::(x_u16); - | ^^^^^ - | | - | expected `u64`, found `u16` - | help: you can convert a `u16` to a `u64`: `x_u16.into()` + | ^^^^^ expected `u64`, found `u16` + | +help: you can convert a `u16` to a `u64` + | +LL | foo::(x_u16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:73:16 | LL | foo::(x_u8); - | ^^^^ - | | - | expected `u64`, found `u8` - | help: you can convert a `u8` to a `u64`: `x_u8.into()` + | ^^^^ expected `u64`, found `u8` + | +help: you can convert a `u8` to a `u64` + | +LL | foo::(x_u8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:75:16 @@ -233,7 +249,7 @@ help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:77:16 @@ -244,7 +260,7 @@ help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:79:16 @@ -255,7 +271,7 @@ help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:81:16 @@ -266,7 +282,7 @@ help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:83:16 @@ -277,7 +293,7 @@ help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:88:16 @@ -288,7 +304,7 @@ help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:90:16 @@ -299,34 +315,40 @@ help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:92:16 | LL | foo::(x_u32); - | ^^^^^ - | | - | expected `i64`, found `u32` - | help: you can convert a `u32` to an `i64`: `x_u32.into()` + | ^^^^^ expected `i64`, found `u32` + | +help: you can convert a `u32` to an `i64` + | +LL | foo::(x_u32.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:94:16 | LL | foo::(x_u16); - | ^^^^^ - | | - | expected `i64`, found `u16` - | help: you can convert a `u16` to an `i64`: `x_u16.into()` + | ^^^^^ expected `i64`, found `u16` + | +help: you can convert a `u16` to an `i64` + | +LL | foo::(x_u16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:96:16 | LL | foo::(x_u8); - | ^^^^ - | | - | expected `i64`, found `u8` - | help: you can convert a `u8` to an `i64`: `x_u8.into()` + | ^^^^ expected `i64`, found `u8` + | +help: you can convert a `u8` to an `i64` + | +LL | foo::(x_u8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:98:16 @@ -337,34 +359,40 @@ help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:101:16 | LL | foo::(x_i32); - | ^^^^^ - | | - | expected `i64`, found `i32` - | help: you can convert an `i32` to an `i64`: `x_i32.into()` + | ^^^^^ expected `i64`, found `i32` + | +help: you can convert an `i32` to an `i64` + | +LL | foo::(x_i32.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:103:16 | LL | foo::(x_i16); - | ^^^^^ - | | - | expected `i64`, found `i16` - | help: you can convert an `i16` to an `i64`: `x_i16.into()` + | ^^^^^ expected `i64`, found `i16` + | +help: you can convert an `i16` to an `i64` + | +LL | foo::(x_i16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:105:16 | LL | foo::(x_i8); - | ^^^^ - | | - | expected `i64`, found `i8` - | help: you can convert an `i8` to an `i64`: `x_i8.into()` + | ^^^^ expected `i64`, found `i8` + | +help: you can convert an `i8` to an `i64` + | +LL | foo::(x_i8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:110:16 @@ -375,7 +403,7 @@ help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:112:16 @@ -386,25 +414,29 @@ help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:115:16 | LL | foo::(x_u16); - | ^^^^^ - | | - | expected `u32`, found `u16` - | help: you can convert a `u16` to a `u32`: `x_u16.into()` + | ^^^^^ expected `u32`, found `u16` + | +help: you can convert a `u16` to a `u32` + | +LL | foo::(x_u16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:117:16 | LL | foo::(x_u8); - | ^^^^ - | | - | expected `u32`, found `u8` - | help: you can convert a `u8` to a `u32`: `x_u8.into()` + | ^^^^ expected `u32`, found `u8` + | +help: you can convert a `u8` to a `u32` + | +LL | foo::(x_u8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:119:16 @@ -415,7 +447,7 @@ help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:121:16 @@ -426,7 +458,7 @@ help: you can convert an `i64` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:123:16 @@ -437,7 +469,7 @@ help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:125:16 @@ -448,7 +480,7 @@ help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:127:16 @@ -459,7 +491,7 @@ help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:132:16 @@ -470,7 +502,7 @@ help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:134:16 @@ -481,7 +513,7 @@ help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:136:16 @@ -492,25 +524,29 @@ help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:138:16 | LL | foo::(x_u16); - | ^^^^^ - | | - | expected `i32`, found `u16` - | help: you can convert a `u16` to an `i32`: `x_u16.into()` + | ^^^^^ expected `i32`, found `u16` + | +help: you can convert a `u16` to an `i32` + | +LL | foo::(x_u16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:140:16 | LL | foo::(x_u8); - | ^^^^ - | | - | expected `i32`, found `u8` - | help: you can convert a `u8` to an `i32`: `x_u8.into()` + | ^^^^ expected `i32`, found `u8` + | +help: you can convert a `u8` to an `i32` + | +LL | foo::(x_u8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:142:16 @@ -521,7 +557,7 @@ help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:144:16 @@ -532,25 +568,29 @@ help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:147:16 | LL | foo::(x_i16); - | ^^^^^ - | | - | expected `i32`, found `i16` - | help: you can convert an `i16` to an `i32`: `x_i16.into()` + | ^^^^^ expected `i32`, found `i16` + | +help: you can convert an `i16` to an `i32` + | +LL | foo::(x_i16.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:149:16 | LL | foo::(x_i8); - | ^^^^ - | | - | expected `i32`, found `i8` - | help: you can convert an `i8` to an `i32`: `x_i8.into()` + | ^^^^ expected `i32`, found `i8` + | +help: you can convert an `i8` to an `i32` + | +LL | foo::(x_i8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:154:16 @@ -561,7 +601,7 @@ help: you can convert a `usize` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:156:16 @@ -572,7 +612,7 @@ help: you can convert a `u64` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:158:16 @@ -583,16 +623,18 @@ help: you can convert a `u32` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:161:16 | LL | foo::(x_u8); - | ^^^^ - | | - | expected `u16`, found `u8` - | help: you can convert a `u8` to a `u16`: `x_u8.into()` + | ^^^^ expected `u16`, found `u8` + | +help: you can convert a `u8` to a `u16` + | +LL | foo::(x_u8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:163:16 @@ -603,7 +645,7 @@ help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:165:16 @@ -614,7 +656,7 @@ help: you can convert an `i64` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:167:16 @@ -625,7 +667,7 @@ help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:169:16 @@ -636,7 +678,7 @@ help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:171:16 @@ -647,7 +689,7 @@ help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:176:16 @@ -658,7 +700,7 @@ help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:178:16 @@ -669,7 +711,7 @@ help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:180:16 @@ -680,7 +722,7 @@ help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:182:16 @@ -691,16 +733,18 @@ help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_u16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:184:16 | LL | foo::(x_u8); - | ^^^^ - | | - | expected `i16`, found `u8` - | help: you can convert a `u8` to an `i16`: `x_u8.into()` + | ^^^^ expected `i16`, found `u8` + | +help: you can convert a `u8` to an `i16` + | +LL | foo::(x_u8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:186:16 @@ -711,7 +755,7 @@ help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:188:16 @@ -722,7 +766,7 @@ help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:190:16 @@ -733,16 +777,18 @@ help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:193:16 | LL | foo::(x_i8); - | ^^^^ - | | - | expected `i16`, found `i8` - | help: you can convert an `i8` to an `i16`: `x_i8.into()` + | ^^^^ expected `i16`, found `i8` + | +help: you can convert an `i8` to an `i16` + | +LL | foo::(x_i8.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:198:15 @@ -753,7 +799,7 @@ help: you can convert a `usize` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:200:15 @@ -764,7 +810,7 @@ help: you can convert a `u64` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:202:15 @@ -775,7 +821,7 @@ help: you can convert a `u32` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:204:15 @@ -786,7 +832,7 @@ help: you can convert a `u16` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_u16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:207:15 @@ -797,7 +843,7 @@ help: you can convert an `isize` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:209:15 @@ -808,7 +854,7 @@ help: you can convert an `i64` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:211:15 @@ -819,7 +865,7 @@ help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:213:15 @@ -830,7 +876,7 @@ help: you can convert an `i16` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:215:15 @@ -841,7 +887,7 @@ help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:220:15 @@ -852,7 +898,7 @@ help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:222:15 @@ -863,7 +909,7 @@ help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:224:15 @@ -874,7 +920,7 @@ help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:226:15 @@ -885,7 +931,7 @@ help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_u16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:228:15 @@ -896,7 +942,7 @@ help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_u8.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:230:15 @@ -907,7 +953,7 @@ help: you can convert an `isize` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:232:15 @@ -918,7 +964,7 @@ help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:234:15 @@ -929,7 +975,7 @@ help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:236:15 @@ -940,7 +986,7 @@ help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:242:16 @@ -951,7 +997,7 @@ help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_usize as f64); - | ~~~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:244:16 @@ -962,7 +1008,7 @@ help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u64 as f64); - | ~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:246:16 @@ -973,7 +1019,7 @@ help: you can convert a `u32` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_u32.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:248:16 @@ -984,7 +1030,7 @@ help: you can convert a `u16` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_u16.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:250:16 @@ -995,7 +1041,7 @@ help: you can convert a `u8` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_u8.into()); - | ~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:252:16 @@ -1006,7 +1052,7 @@ help: you can convert an `isize` to an `f64`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_isize as f64); - | ~~~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:254:16 @@ -1017,7 +1063,7 @@ help: you can convert an `i64` to an `f64`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_i64 as f64); - | ~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:256:16 @@ -1028,7 +1074,7 @@ help: you can convert an `i32` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_i32.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:258:16 @@ -1039,7 +1085,7 @@ help: you can convert an `i16` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_i16.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:260:16 @@ -1050,16 +1096,18 @@ help: you can convert an `i8` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_i8.into()); - | ~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:263:16 | LL | foo::(x_f32); - | ^^^^^ - | | - | expected `f64`, found `f32` - | help: you can convert an `f32` to an `f64`: `x_f32.into()` + | ^^^^^ expected `f64`, found `f32` + | +help: you can convert an `f32` to an `f64` + | +LL | foo::(x_f32.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:266:16 @@ -1070,7 +1118,7 @@ help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_usize as f32); - | ~~~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:268:16 @@ -1081,7 +1129,7 @@ help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u64 as f32); - | ~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:270:16 @@ -1092,7 +1140,7 @@ help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u32 as f32); - | ~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:272:16 @@ -1103,7 +1151,7 @@ help: you can convert a `u16` to an `f32`, producing the floating point representation of the integer | LL | foo::(x_u16.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:274:16 @@ -1114,7 +1162,7 @@ help: you can convert a `u8` to an `f32`, producing the floating point representation of the integer | LL | foo::(x_u8.into()); - | ~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:276:16 @@ -1125,7 +1173,7 @@ help: you can convert an `isize` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_isize as f32); - | ~~~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:278:16 @@ -1136,7 +1184,7 @@ help: you can convert an `i64` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_i64 as f32); - | ~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:280:16 @@ -1147,7 +1195,7 @@ help: you can convert an `i32` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_i32 as f32); - | ~~~~~~~~~~~~ + | ++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:282:16 @@ -1158,7 +1206,7 @@ help: you can convert an `i16` to an `f32`, producing the floating point representation of the integer | LL | foo::(x_i16.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:284:16 @@ -1169,25 +1217,29 @@ help: you can convert an `i8` to an `f32`, producing the floating point representation of the integer | LL | foo::(x_i8.into()); - | ~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:289:16 | LL | foo::(x_u8 as u16); - | ^^^^^^^^^^^ - | | - | expected `u32`, found `u16` - | help: you can convert a `u16` to a `u32`: `(x_u8 as u16).into()` + | ^^^^^^^^^^^ expected `u32`, found `u16` + | +help: you can convert a `u16` to a `u32` + | +LL | foo::((x_u8 as u16).into()); + | + ++++++++ error[E0308]: mismatched types --> $DIR/numeric-cast.rs:291:16 | LL | foo::(-x_i8); - | ^^^^^ - | | - | expected `i32`, found `i8` - | help: you can convert an `i8` to an `i32`: `(-x_i8).into()` + | ^^^^^ expected `i32`, found `i8` + | +help: you can convert an `i8` to an `i32` + | +LL | foo::((-x_i8).into()); + | + ++++++++ error: aborting due to 113 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-fields.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-fields.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-fields.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-fields.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,15 +5,21 @@ | - `S` defined here ... LL | let s = S{0b1: 10, 0: 11}; - | - ^^^ field does not exist - | | - | help: `S` is a tuple struct, use the appropriate syntax: `S(/* fields */)` + | ^^^ field does not exist + | +help: `S` is a tuple struct, use the appropriate syntax + | +LL | let s = S(/* fields */); + | ~~~~~~~~~~~~~~~ error[E0026]: struct `S` does not have a field named `0x1` --> $DIR/numeric-fields.rs:7:17 | LL | S{0: a, 0x1: b, ..} => {} - | ^^^ struct `S` does not have this field + | ^^^ + | | + | struct `S` does not have this field + | help: `S` has a field named `1` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-suffix.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-suffix.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/numeric/numeric-suffix.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/numeric/numeric-suffix.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `u64` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:9:18 @@ -18,7 +18,7 @@ help: change the type of the numeric literal from `u32` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:11:18 @@ -29,7 +29,7 @@ help: change the type of the numeric literal from `u16` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:13:18 @@ -40,7 +40,7 @@ help: change the type of the numeric literal from `u8` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:15:18 @@ -51,7 +51,7 @@ help: change the type of the numeric literal from `isize` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:17:18 @@ -62,7 +62,7 @@ help: change the type of the numeric literal from `i64` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:19:18 @@ -73,7 +73,7 @@ help: change the type of the numeric literal from `i32` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:21:18 @@ -84,7 +84,7 @@ help: change the type of the numeric literal from `i16` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:23:18 @@ -95,7 +95,7 @@ help: change the type of the numeric literal from `i8` to `usize` | LL | foo::(42_usize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:25:18 @@ -106,7 +106,7 @@ help: change the type of the numeric literal from `f64` to `usize` | LL | foo::(42usize); - | ~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:27:18 @@ -117,7 +117,7 @@ help: change the type of the numeric literal from `f32` to `usize` | LL | foo::(42usize); - | ~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:30:18 @@ -128,7 +128,7 @@ help: change the type of the numeric literal from `usize` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:32:18 @@ -139,7 +139,7 @@ help: change the type of the numeric literal from `u64` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:34:18 @@ -150,7 +150,7 @@ help: change the type of the numeric literal from `u32` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:36:18 @@ -161,7 +161,7 @@ help: change the type of the numeric literal from `u16` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:38:18 @@ -172,7 +172,7 @@ help: change the type of the numeric literal from `u8` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:41:18 @@ -183,7 +183,7 @@ help: change the type of the numeric literal from `i64` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:43:18 @@ -194,7 +194,7 @@ help: change the type of the numeric literal from `i32` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:45:18 @@ -205,7 +205,7 @@ help: change the type of the numeric literal from `i16` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:47:18 @@ -216,7 +216,7 @@ help: change the type of the numeric literal from `i8` to `isize` | LL | foo::(42_isize); - | ~~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:49:18 @@ -227,7 +227,7 @@ help: change the type of the numeric literal from `f64` to `isize` | LL | foo::(42isize); - | ~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:51:18 @@ -238,7 +238,7 @@ help: change the type of the numeric literal from `f32` to `isize` | LL | foo::(42isize); - | ~~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:54:16 @@ -249,7 +249,7 @@ help: change the type of the numeric literal from `usize` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:57:16 @@ -260,7 +260,7 @@ help: change the type of the numeric literal from `u32` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:59:16 @@ -271,7 +271,7 @@ help: change the type of the numeric literal from `u16` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:61:16 @@ -282,7 +282,7 @@ help: change the type of the numeric literal from `u8` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:63:16 @@ -293,7 +293,7 @@ help: change the type of the numeric literal from `isize` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:65:16 @@ -304,7 +304,7 @@ help: change the type of the numeric literal from `i64` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:67:16 @@ -315,7 +315,7 @@ help: change the type of the numeric literal from `i32` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:69:16 @@ -326,7 +326,7 @@ help: change the type of the numeric literal from `i16` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:71:16 @@ -337,7 +337,7 @@ help: change the type of the numeric literal from `i8` to `u64` | LL | foo::(42_u64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:73:16 @@ -348,7 +348,7 @@ help: change the type of the numeric literal from `f64` to `u64` | LL | foo::(42u64); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:75:16 @@ -359,7 +359,7 @@ help: change the type of the numeric literal from `f32` to `u64` | LL | foo::(42u64); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:78:16 @@ -370,7 +370,7 @@ help: change the type of the numeric literal from `usize` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:80:16 @@ -381,7 +381,7 @@ help: change the type of the numeric literal from `u64` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:82:16 @@ -392,7 +392,7 @@ help: change the type of the numeric literal from `u32` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:84:16 @@ -403,7 +403,7 @@ help: change the type of the numeric literal from `u16` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:86:16 @@ -414,7 +414,7 @@ help: change the type of the numeric literal from `u8` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:88:16 @@ -425,7 +425,7 @@ help: change the type of the numeric literal from `isize` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:91:16 @@ -436,7 +436,7 @@ help: change the type of the numeric literal from `i32` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:93:16 @@ -447,7 +447,7 @@ help: change the type of the numeric literal from `i16` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:95:16 @@ -458,7 +458,7 @@ help: change the type of the numeric literal from `i8` to `i64` | LL | foo::(42_i64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:97:16 @@ -469,7 +469,7 @@ help: change the type of the numeric literal from `f64` to `i64` | LL | foo::(42i64); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:99:16 @@ -480,7 +480,7 @@ help: change the type of the numeric literal from `f32` to `i64` | LL | foo::(42i64); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:102:16 @@ -491,7 +491,7 @@ help: change the type of the numeric literal from `usize` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:104:16 @@ -502,7 +502,7 @@ help: change the type of the numeric literal from `u64` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:107:16 @@ -513,7 +513,7 @@ help: change the type of the numeric literal from `u16` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:109:16 @@ -524,7 +524,7 @@ help: change the type of the numeric literal from `u8` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:111:16 @@ -535,7 +535,7 @@ help: change the type of the numeric literal from `isize` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:113:16 @@ -546,7 +546,7 @@ help: change the type of the numeric literal from `i64` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:115:16 @@ -557,7 +557,7 @@ help: change the type of the numeric literal from `i32` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:117:16 @@ -568,7 +568,7 @@ help: change the type of the numeric literal from `i16` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:119:16 @@ -579,7 +579,7 @@ help: change the type of the numeric literal from `i8` to `u32` | LL | foo::(42_u32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:121:16 @@ -590,7 +590,7 @@ help: change the type of the numeric literal from `f64` to `u32` | LL | foo::(42u32); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:123:16 @@ -601,7 +601,7 @@ help: change the type of the numeric literal from `f32` to `u32` | LL | foo::(42u32); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:126:16 @@ -612,7 +612,7 @@ help: change the type of the numeric literal from `usize` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:128:16 @@ -623,7 +623,7 @@ help: change the type of the numeric literal from `u64` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:130:16 @@ -634,7 +634,7 @@ help: change the type of the numeric literal from `u32` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:132:16 @@ -645,7 +645,7 @@ help: change the type of the numeric literal from `u16` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:134:16 @@ -656,7 +656,7 @@ help: change the type of the numeric literal from `u8` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:136:16 @@ -667,7 +667,7 @@ help: change the type of the numeric literal from `isize` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:138:16 @@ -678,7 +678,7 @@ help: change the type of the numeric literal from `i64` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:141:16 @@ -689,7 +689,7 @@ help: change the type of the numeric literal from `i16` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:143:16 @@ -700,7 +700,7 @@ help: change the type of the numeric literal from `i8` to `i32` | LL | foo::(42_i32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:145:16 @@ -711,7 +711,7 @@ help: change the type of the numeric literal from `f64` to `i32` | LL | foo::(42i32); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:147:16 @@ -722,7 +722,7 @@ help: change the type of the numeric literal from `f32` to `i32` | LL | foo::(42i32); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:150:16 @@ -733,7 +733,7 @@ help: change the type of the numeric literal from `usize` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:152:16 @@ -744,7 +744,7 @@ help: change the type of the numeric literal from `u64` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:154:16 @@ -755,7 +755,7 @@ help: change the type of the numeric literal from `u32` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:157:16 @@ -766,7 +766,7 @@ help: change the type of the numeric literal from `u8` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:159:16 @@ -777,7 +777,7 @@ help: change the type of the numeric literal from `isize` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:161:16 @@ -788,7 +788,7 @@ help: change the type of the numeric literal from `i64` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:163:16 @@ -799,7 +799,7 @@ help: change the type of the numeric literal from `i32` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:165:16 @@ -810,7 +810,7 @@ help: change the type of the numeric literal from `i16` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:167:16 @@ -821,7 +821,7 @@ help: change the type of the numeric literal from `i8` to `u16` | LL | foo::(42_u16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:169:16 @@ -832,7 +832,7 @@ help: change the type of the numeric literal from `f64` to `u16` | LL | foo::(42u16); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:171:16 @@ -843,7 +843,7 @@ help: change the type of the numeric literal from `f32` to `u16` | LL | foo::(42u16); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:174:16 @@ -854,7 +854,7 @@ help: change the type of the numeric literal from `usize` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:176:16 @@ -865,7 +865,7 @@ help: change the type of the numeric literal from `u64` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:178:16 @@ -876,7 +876,7 @@ help: change the type of the numeric literal from `u32` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:180:16 @@ -887,7 +887,7 @@ help: change the type of the numeric literal from `u16` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:182:16 @@ -898,7 +898,7 @@ help: change the type of the numeric literal from `u8` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:184:16 @@ -909,7 +909,7 @@ help: change the type of the numeric literal from `isize` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:186:16 @@ -920,7 +920,7 @@ help: change the type of the numeric literal from `i64` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:188:16 @@ -931,7 +931,7 @@ help: change the type of the numeric literal from `i32` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:191:16 @@ -942,7 +942,7 @@ help: change the type of the numeric literal from `i8` to `i16` | LL | foo::(42_i16); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:193:16 @@ -953,7 +953,7 @@ help: change the type of the numeric literal from `f64` to `i16` | LL | foo::(42i16); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:195:16 @@ -964,7 +964,7 @@ help: change the type of the numeric literal from `f32` to `i16` | LL | foo::(42i16); - | ~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:198:15 @@ -975,7 +975,7 @@ help: change the type of the numeric literal from `usize` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:200:15 @@ -986,7 +986,7 @@ help: change the type of the numeric literal from `u64` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:202:15 @@ -997,7 +997,7 @@ help: change the type of the numeric literal from `u32` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:204:15 @@ -1008,7 +1008,7 @@ help: change the type of the numeric literal from `u16` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:207:15 @@ -1019,7 +1019,7 @@ help: change the type of the numeric literal from `isize` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:209:15 @@ -1030,7 +1030,7 @@ help: change the type of the numeric literal from `i64` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:211:15 @@ -1041,7 +1041,7 @@ help: change the type of the numeric literal from `i32` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:213:15 @@ -1052,7 +1052,7 @@ help: change the type of the numeric literal from `i16` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:215:15 @@ -1063,7 +1063,7 @@ help: change the type of the numeric literal from `i8` to `u8` | LL | foo::(42_u8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:217:15 @@ -1074,7 +1074,7 @@ help: change the type of the numeric literal from `f64` to `u8` | LL | foo::(42u8); - | ~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:219:15 @@ -1085,7 +1085,7 @@ help: change the type of the numeric literal from `f32` to `u8` | LL | foo::(42u8); - | ~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:222:15 @@ -1096,7 +1096,7 @@ help: change the type of the numeric literal from `usize` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:224:15 @@ -1107,7 +1107,7 @@ help: change the type of the numeric literal from `u64` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:226:15 @@ -1118,7 +1118,7 @@ help: change the type of the numeric literal from `u32` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:228:15 @@ -1129,7 +1129,7 @@ help: change the type of the numeric literal from `u16` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:230:15 @@ -1140,7 +1140,7 @@ help: change the type of the numeric literal from `u8` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:232:15 @@ -1151,7 +1151,7 @@ help: change the type of the numeric literal from `isize` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:234:15 @@ -1162,7 +1162,7 @@ help: change the type of the numeric literal from `i64` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:236:15 @@ -1173,7 +1173,7 @@ help: change the type of the numeric literal from `i32` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:238:15 @@ -1184,7 +1184,7 @@ help: change the type of the numeric literal from `i16` to `i8` | LL | foo::(42_i8); - | ~~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:241:15 @@ -1195,7 +1195,7 @@ help: change the type of the numeric literal from `f64` to `i8` | LL | foo::(42i8); - | ~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:243:15 @@ -1206,7 +1206,7 @@ help: change the type of the numeric literal from `f32` to `i8` | LL | foo::(42i8); - | ~~~~ + | ~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:246:16 @@ -1217,7 +1217,7 @@ help: change the type of the numeric literal from `usize` to `f64` | LL | foo::(42_f64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:248:16 @@ -1228,7 +1228,7 @@ help: change the type of the numeric literal from `u64` to `f64` | LL | foo::(42_f64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:250:16 @@ -1239,7 +1239,7 @@ help: you can convert a `u32` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_u32.into()); - | ~~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:252:16 @@ -1250,7 +1250,7 @@ help: you can convert a `u16` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_u16.into()); - | ~~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:254:16 @@ -1261,7 +1261,7 @@ help: you can convert a `u8` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_u8.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:256:16 @@ -1272,7 +1272,7 @@ help: change the type of the numeric literal from `isize` to `f64` | LL | foo::(42_f64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:258:16 @@ -1283,7 +1283,7 @@ help: change the type of the numeric literal from `i64` to `f64` | LL | foo::(42_f64); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:260:16 @@ -1294,7 +1294,7 @@ help: you can convert an `i32` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_i32.into()); - | ~~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:262:16 @@ -1305,7 +1305,7 @@ help: you can convert an `i16` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_i16.into()); - | ~~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:264:16 @@ -1316,7 +1316,7 @@ help: you can convert an `i8` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_i8.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:267:16 @@ -1327,7 +1327,7 @@ help: change the type of the numeric literal from `f32` to `f64` | LL | foo::(42.0_f64); - | ~~~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:270:16 @@ -1338,7 +1338,7 @@ help: change the type of the numeric literal from `usize` to `f32` | LL | foo::(42_f32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:272:16 @@ -1349,7 +1349,7 @@ help: change the type of the numeric literal from `u64` to `f32` | LL | foo::(42_f32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:274:16 @@ -1360,7 +1360,7 @@ help: change the type of the numeric literal from `u32` to `f32` | LL | foo::(42_f32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:276:16 @@ -1371,7 +1371,7 @@ help: you can convert a `u16` to an `f32`, producing the floating point representation of the integer | LL | foo::(42_u16.into()); - | ~~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:278:16 @@ -1382,7 +1382,7 @@ help: you can convert a `u8` to an `f32`, producing the floating point representation of the integer | LL | foo::(42_u8.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:280:16 @@ -1393,7 +1393,7 @@ help: change the type of the numeric literal from `isize` to `f32` | LL | foo::(42_f32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:282:16 @@ -1404,7 +1404,7 @@ help: change the type of the numeric literal from `i64` to `f32` | LL | foo::(42_f32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:284:16 @@ -1415,7 +1415,7 @@ help: change the type of the numeric literal from `i32` to `f32` | LL | foo::(42_f32); - | ~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:286:16 @@ -1426,7 +1426,7 @@ help: you can convert an `i16` to an `f32`, producing the floating point representation of the integer | LL | foo::(42_i16.into()); - | ~~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:288:16 @@ -1437,7 +1437,7 @@ help: you can convert an `i8` to an `f32`, producing the floating point representation of the integer | LL | foo::(42_i8.into()); - | ~~~~~~~~~~~~ + | +++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:290:16 @@ -1448,25 +1448,29 @@ help: change the type of the numeric literal from `f64` to `f32` | LL | foo::(42.0_f32); - | ~~~~~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:294:16 | LL | foo::(42_u8 as u16); - | ^^^^^^^^^^^^ - | | - | expected `u32`, found `u16` - | help: you can convert a `u16` to a `u32`: `(42_u8 as u16).into()` + | ^^^^^^^^^^^^ expected `u32`, found `u16` + | +help: you can convert a `u16` to a `u32` + | +LL | foo::((42_u8 as u16).into()); + | + ++++++++ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:296:16 | LL | foo::(-42_i8); - | ^^^^^^ - | | - | expected `i32`, found `i8` - | help: you can convert an `i8` to an `i32`: `(-42_i8).into()` + | ^^^^^^ expected `i32`, found `i8` + | +help: you can convert an `i8` to an `i32` + | +LL | foo::((-42_i8).into()); + | + ++++++++ error: aborting due to 134 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-does-not-impl-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-does-not-impl-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-does-not-impl-trait.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-does-not-impl-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/object-does-not-impl-trait.rs:6:44 | LL | fn take_object(f: Box) { take_foo(f); } - | ^ the trait `Foo` is not implemented for `Box` + | -------- ^ the trait `Foo` is not implemented for `Box` + | | + | required by a bound introduced by this call | note: required by a bound in `take_foo` --> $DIR/object-does-not-impl-trait.rs:5:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | ss | ^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 54:10... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/object-lifetime-default-elision.rs:54:10 | LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { @@ -14,12 +14,12 @@ | LL | ss | ^^ -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 54:13... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/object-lifetime-default-elision.rs:54:13 | LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/object-lifetime-default-elision.rs:71:5 | LL | ss @@ -33,7 +33,7 @@ LL | ss | ^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 54:10... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/object-lifetime-default-elision.rs:54:10 | LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { @@ -43,12 +43,12 @@ | LL | ss | ^^ -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 54:13... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/object-lifetime-default-elision.rs:54:13 | LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/object-lifetime-default-elision.rs:71:5 | LL | ss diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | ss.t = t; | ^^^^^^^^ assignment requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected reference `&'a Box<(dyn Test + 'static)>` found reference `&'a Box<(dyn Test + 'a)>` -note: the lifetime `'a` as defined on the function body at 14:6... +note: the lifetime `'a` as defined here... --> $DIR/object-lifetime-default-from-rptr-box-error.rs:14:6 | LL | fn c<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | ss.t = t; | ^^^^^^^^ assignment requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected reference `&'a MyBox<(dyn Test + 'static)>` found reference `&'a MyBox<(dyn Test + 'a)>` -note: the lifetime `'a` as defined on the function body at 20:6... +note: the lifetime `'a` as defined here... --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:20:6 | LL | fn c<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -15,11 +15,14 @@ --> $DIR/object-lifetime-default-mybox.rs:31:5 | LL | fn load2<'a>(ss: &MyBox) -> MyBox { - | -- `ss` is a reference that is only valid in the function body + | -- -- `ss` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | load0(ss) - | ^^^^^^^^^ `ss` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^ + | | + | `ss` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ | = note: expected reference `&MyBox<(dyn SomeTrait + 'static)>` found reference `&MyBox<(dyn SomeTrait + 'a)>` -note: the lifetime `'a` as defined on the function body at 30:10... +note: the lifetime `'a` as defined here... --> $DIR/object-lifetime-default-mybox.rs:30:10 | LL | fn load2<'a>(ss: &MyBox) -> MyBox { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^ `Bar` cannot be made into an object | - = help: consider moving `X` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-associated-consts.rs:9:11 | @@ -12,6 +11,7 @@ | --- this trait cannot be made into an object... LL | const X: usize; | ^ ...because it contains this associated `const` + = help: consider moving `X` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | t | ^ `Bar` cannot be made into an object | - = help: consider moving `X` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-associated-consts.rs:9:11 | @@ -12,6 +11,7 @@ | --- this trait cannot be made into an object... LL | const X: usize; | ^ ...because it contains this associated `const` + = help: consider moving `X` to another trait = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-by-value-self-use.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-by-value-self-use.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-by-value-self-use.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-by-value-self-use.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/object-safety-by-value-self-use.rs:15:5 | LL | t.bar() - | ^ + | ^^^^^^^ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-generics.curr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-generics.curr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-generics.curr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-generics.curr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^ `Bar` cannot be made into an object | - = help: consider moving `bar` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | @@ -12,6 +11,7 @@ | --- this trait cannot be made into an object... LL | fn bar(&self, t: T); | ^^^ ...because method `bar` has generic type parameters + = help: consider moving `bar` to another trait error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/object-safety-generics.rs:24:39 @@ -19,7 +19,6 @@ LL | fn make_bar_explicit(t: &T) -> &dyn Bar { | ^^^^^^^^ `Bar` cannot be made into an object | - = help: consider moving `bar` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | @@ -27,6 +26,7 @@ | --- this trait cannot be made into an object... LL | fn bar(&self, t: T); | ^^^ ...because method `bar` has generic type parameters + = help: consider moving `bar` to another trait error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | t | ^ `Bar` cannot be made into an object | - = help: consider moving `bar` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | @@ -12,6 +11,7 @@ | --- this trait cannot be made into an object... LL | fn bar(&self, t: T); | ^^^ ...because method `bar` has generic type parameters + = help: consider moving `bar` to another trait = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` @@ -21,7 +21,6 @@ LL | t as &dyn Bar | ^ `Bar` cannot be made into an object | - = help: consider moving `bar` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | @@ -29,6 +28,7 @@ | --- this trait cannot be made into an object... LL | fn bar(&self, t: T); | ^^^ ...because method `bar` has generic type parameters + = help: consider moving `bar` to another trait = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^ `Bar` cannot be made into an object | - = help: consider moving `bar` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:11:22 | @@ -12,6 +11,7 @@ | --- this trait cannot be made into an object... LL | fn bar(&self, x: &Self); | ^^^^^ ...because method `bar` references the `Self` type in this parameter + = help: consider moving `bar` to another trait error[E0038]: the trait `Baz` cannot be made into an object --> $DIR/object-safety-mentions-Self.rs:28:30 @@ -19,7 +19,6 @@ LL | fn make_baz(t: &T) -> &dyn Baz { | ^^^^^^^^ `Baz` cannot be made into an object | - = help: consider moving `baz` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:15:22 | @@ -27,6 +26,7 @@ | --- this trait cannot be made into an object... LL | fn baz(&self) -> Self; | ^^^^ ...because method `baz` references the `Self` type in its return type + = help: consider moving `baz` to another trait error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,6 @@ LL | t | ^ `Bar` cannot be made into an object | - = help: consider moving `bar` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:11:22 | @@ -12,6 +11,7 @@ | --- this trait cannot be made into an object... LL | fn bar(&self, x: &Self); | ^^^^^ ...because method `bar` references the `Self` type in this parameter + = help: consider moving `bar` to another trait = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` @@ -21,7 +21,6 @@ LL | t | ^ `Baz` cannot be made into an object | - = help: consider moving `baz` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:15:22 | @@ -29,6 +28,7 @@ | --- this trait cannot be made into an object... LL | fn baz(&self) -> Self; | ^^^^ ...because method `baz` references the `Self` type in its return type + = help: consider moving `baz` to another trait = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Baz>` for `&T` = note: required by cast to type `&dyn Baz` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/objects-owned-object-borrowed-method-headerless.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/objects-owned-object-borrowed-method-headerless.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/objects-owned-object-borrowed-method-headerless.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/objects-owned-object-borrowed-method-headerless.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,9 +3,6 @@ // closed over do not contain managed values, and thus the boxes do // not have headers. -#![feature(box_syntax)] - - trait FooTrait { fn foo(&self) -> usize; } @@ -22,9 +19,9 @@ pub fn main() { let foos: Vec> = vec![ - box BarStruct{ x: 0 } as Box, - box BarStruct{ x: 1 } as Box, - box BarStruct{ x: 2 } as Box + Box::new(BarStruct{ x: 0 }) as Box, + Box::new(BarStruct{ x: 1 }) as Box, + Box::new(BarStruct{ x: 2 }) as Box, ]; for i in 0..foos.len() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/objects-owned-object-owned-method.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/objects-owned-object-owned-method.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/objects-owned-object-owned-method.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/objects-owned-object-owned-method.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ // closed over contain managed values. This implies that the boxes // will have headers that must be skipped over. -#![feature(box_syntax)] - trait FooTrait { fn foo(self: Box) -> usize; } @@ -20,6 +18,6 @@ } pub fn main() { - let foo = box BarStruct{ x: 22 } as Box; + let foo = Box::new(BarStruct{ x: 22 }) as Box; assert_eq!(22, foo.foo()); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/occurs-check-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/occurs-check-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/occurs-check-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/occurs-check-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - fn main() { + let f; let g; + g = f; - f = box g; + f = Box::new(g); //~^ ERROR mismatched types //~| cyclic type of infinite size } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/occurs-check-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/occurs-check-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/occurs-check-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/occurs-check-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,10 @@ error[E0308]: mismatched types --> $DIR/occurs-check-2.rs:7:9 | -LL | f = box g; - | ^^^^^ cyclic type of infinite size - | -help: try using a conversion method - | -LL | f = (box g).to_string(); - | + +++++++++++++ +LL | f = Box::new(g); + | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | cyclic type of infinite size error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/occurs-check.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/occurs-check.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/occurs-check.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/occurs-check.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn main() { + let f; - f = box f; + + f = Box::new(f); //~^ ERROR mismatched types //~| cyclic type of infinite size } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/occurs-check.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/occurs-check.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/occurs-check.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/occurs-check.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,10 @@ error[E0308]: mismatched types --> $DIR/occurs-check.rs:5:9 | -LL | f = box f; - | ^^^^^ cyclic type of infinite size - | -help: try using a conversion method - | -LL | f = (box f).to_string(); - | + +++++++++++++ +LL | f = Box::new(f); + | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | cyclic type of infinite size error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/on-unimplemented/enclosing-scope.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/on-unimplemented/enclosing-scope.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/on-unimplemented/enclosing-scope.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/on-unimplemented/enclosing-scope.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,9 @@ LL | let x = || { | _____________- LL | | f(Foo{}); - | | ^^^^^ the trait `Trait` is not implemented for `Foo` + | | - ^^^^^ the trait `Trait` is not implemented for `Foo` + | | | + | | required by a bound introduced by this call LL | | let y = || { LL | | f(Foo{}); LL | | }; @@ -23,7 +25,9 @@ LL | let y = || { | _________________- LL | | f(Foo{}); - | | ^^^^^ the trait `Trait` is not implemented for `Foo` + | | - ^^^^^ the trait `Trait` is not implemented for `Foo` + | | | + | | required by a bound introduced by this call LL | | }; | |_________- in this scope | @@ -42,7 +46,9 @@ LL | | let y = || { ... | LL | | f(Foo{}); - | | ^^^^^ the trait `Trait` is not implemented for `Foo` + | | - ^^^^^ the trait `Trait` is not implemented for `Foo` + | | | + | | required by a bound introduced by this call ... | LL | | f(Foo{}); LL | | } @@ -63,7 +69,9 @@ LL | | let y = || { ... | LL | | f(Foo{}); - | | ^^^^^ the trait `Trait` is not implemented for `Foo` + | | - ^^^^^ the trait `Trait` is not implemented for `Foo` + | | | + | | required by a bound introduced by this call LL | | } | |_- in this scope | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/on-unimplemented/multiple-impls.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/on-unimplemented/multiple-impls.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/on-unimplemented/multiple-impls.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/on-unimplemented/multiple-impls.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/multiple-impls.rs:33:18 | LL | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^^ trait message + | ------------ ^^^^^^^^^^^^^ trait message + | | + | required by a bound introduced by this call | = help: the trait `Index` is not implemented for `[i32]` note: required by `Index::index` @@ -15,7 +17,9 @@ --> $DIR/multiple-impls.rs:36:18 | LL | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^^ on impl for Foo + | ------------ ^^^^^^^^^^^^^ on impl for Foo + | | + | required by a bound introduced by this call | = help: the trait `Index>` is not implemented for `[i32]` note: required by `Index::index` @@ -28,7 +32,9 @@ --> $DIR/multiple-impls.rs:39:18 | LL | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^^ on impl for Bar + | ------------ ^^^^^^^^^^^^^ on impl for Bar + | | + | required by a bound introduced by this call | = help: the trait `Index>` is not implemented for `[i32]` note: required by `Index::index` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/on-unimplemented/on-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/on-unimplemented/on-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/on-unimplemented/on-impl.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/on-unimplemented/on-impl.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/on-impl.rs:22:25 | LL | Index::::index(&[1, 2, 3] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice + | ------------------- ^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice + | | + | required by a bound introduced by this call | = help: the trait `Index` is not implemented for `[i32]` note: required by `Index::index` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -30,7 +30,22 @@ | | | E | - = note: an implementation of `std::ops::BitOr` might be missing for `E` +note: an implementation of `BitOr<_>` might be missing for `E` + --> $DIR/or-patterns-syntactic-fail.rs:6:1 + | +LL | enum E { A, B } + | ^^^^^^ must implement `BitOr<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait BitOr { +LL | | /// The resulting type after applying the `|` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn bitor(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error: aborting due to 5 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/out-of-order-shadowing.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/out-of-order-shadowing.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/out-of-order-shadowing.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/out-of-order-shadowing.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -// aux-build:define-macro.rs - -macro_rules! bar { () => {} } -define_macro!(bar); -bar!(); //~ ERROR `bar` is ambiguous - -macro_rules! m { () => { #[macro_use] extern crate define_macro; } } -m!(); - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/out-of-order-shadowing.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/out-of-order-shadowing.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/out-of-order-shadowing.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/out-of-order-shadowing.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -error[E0659]: `bar` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) - --> $DIR/out-of-order-shadowing.rs:5:1 - | -LL | bar!(); - | ^^^ ambiguous name - | -note: `bar` could refer to the macro defined here - --> $DIR/out-of-order-shadowing.rs:4:1 - | -LL | define_macro!(bar); - | ^^^^^^^^^^^^^^^^^^^ -note: `bar` could also refer to the macro defined here - --> $DIR/out-of-order-shadowing.rs:3:1 - | -LL | macro_rules! bar { () => {} } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `define_macro` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0659`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/output-slot-variants.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/output-slot-variants.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/output-slot-variants.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/output-slot-variants.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,22 +7,21 @@ #![allow(dead_assignment)] #![allow(unused_variables)] -#![feature(box_syntax)] struct A { a: isize, b: isize } struct Abox { a: Box, b: Box } fn ret_int_i() -> isize { 10 } -fn ret_ext_i() -> Box { box 10 } +fn ret_ext_i() -> Box { Box::new(10) } fn ret_int_rec() -> A { A {a: 10, b: 10} } -fn ret_ext_rec() -> Box { box A {a: 10, b: 10} } +fn ret_ext_rec() -> Box { Box::new(A {a: 10, b: 10}) } -fn ret_ext_mem() -> Abox { Abox {a: box 10, b: box 10} } +fn ret_ext_mem() -> Abox { Abox {a: Box::new(10), b: Box::new(10) } } -fn ret_ext_ext_mem() -> Box { box Abox{a: box 10, b: box 10} } +fn ret_ext_ext_mem() -> Box { Box::new(Abox{a: Box::new(10), b: Box::new(10) }) } pub fn main() { let mut int_i: isize; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-autoderef-order.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-autoderef-order.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-autoderef-order.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-autoderef-order.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,7 @@ // run-pass +#![allow(dead_code)] + use std::rc::Rc; use std::ops::Deref; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-autoderef.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-autoderef.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-autoderef.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-autoderef.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,6 @@ #![allow(unused_variables)] #![allow(stable_features)] -#![feature(box_syntax, core)] - use std::cell::RefCell; use std::rc::Rc; @@ -14,7 +12,7 @@ } pub fn main() { - let box_5: Box<_> = box 5_usize; + let box_5: Box<_> = Box::new(5_usize); let point = Rc::new(Point {x: 2, y: 4}); assert_eq!(point.x, 2); assert_eq!(point.y, 4); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-index-autoderef.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-index-autoderef.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-index-autoderef.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/overloaded/overloaded-index-autoderef.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ // Test overloaded indexing combined with autoderef. -#![feature(box_syntax, core)] - use std::ops::{Index, IndexMut}; struct Foo { @@ -47,10 +45,10 @@ } fn main() { - let mut f: Box<_> = box Foo { + let mut f: Box<_> = Box::new(Foo { x: 1, y: 2, - }; + }); assert_eq!(f[1], 2); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/panics/args-panic.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/panics/args-panic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/panics/args-panic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/panics/args-panic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,12 +2,10 @@ // error-pattern:meep // ignore-emscripten no processes -#![feature(box_syntax)] - fn f(_a: isize, _b: isize, _c: Box) { panic!("moop"); } fn main() { - f(1, panic!("meep"), box 42); + f(1, panic!("meep"), Box::new(42)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/panics/panic-macro-any.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/panics/panic-macro-any.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/panics/panic-macro-any.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/panics/panic-macro-any.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,8 @@ // error-pattern:panicked at 'Box' // ignore-emscripten no processes -#![feature(box_syntax)] #![allow(non_fmt_panics)] fn main() { - panic!(box 413 as Box); + panic!(Box::new(413) as Box); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/attr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/attr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/attr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/attr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,16 @@ | LL | #![lang = "foo"] | ^^^^^^^^^^^^^^^^ +LL | +LL | fn foo() {} + | ----------- the inner attribute doesn't annotate this function | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the function, change the attribute from inner to outer style + | +LL - #![lang = "foo"] +LL + #[lang = "foo"] + | error[E0522]: definition of an unknown language item: `foo` --> $DIR/attr.rs:5:1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = box #![attr] 0; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: expected expression, found `]` --> $DIR/attr-stmt-expr-attr-bad.rs:7:40 @@ -24,7 +25,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: expected expression, found `)` --> $DIR/attr-stmt-expr-attr-bad.rs:11:44 @@ -38,7 +40,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: expected expression, found `)` --> $DIR/attr-stmt-expr-attr-bad.rs:14:46 @@ -52,7 +55,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:19:33 @@ -60,7 +64,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:21:33 @@ -68,7 +73,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:23:34 @@ -82,7 +88,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:27:40 @@ -90,7 +97,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:29:35 @@ -98,7 +106,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:31:40 @@ -106,7 +115,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: expected expression, found `..` --> $DIR/attr-stmt-expr-attr-bad.rs:33:40 @@ -126,7 +136,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:39:45 @@ -134,7 +145,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:41:37 @@ -151,7 +163,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:45:40 @@ -174,7 +187,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:51:45 @@ -200,7 +214,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:57:45 @@ -217,7 +232,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:61:48 @@ -240,7 +256,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:67:53 @@ -266,7 +283,8 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } | ^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:74:32 @@ -276,7 +294,8 @@ | | | previous outer attribute | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:76:32 @@ -286,37 +305,56 @@ | | | previous outer attribute | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:78:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } - | ------- ^^^^^^^^ not permitted following an outer attribute - | | + | ------- ^^^^^^^^ ------- the inner attribute doesn't annotate this item macro invocation + | | | + | | not permitted following an outer attribute | previous outer attribute | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the item macro invocation, change the attribute from inner to outer style + | +LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } +LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo!(); } + | error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:80:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } - | ------- ^^^^^^^^ not permitted following an outer attribute - | | + | ------- ^^^^^^^^ ------- the inner attribute doesn't annotate this item macro invocation + | | | + | | not permitted following an outer attribute | previous outer attribute | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the item macro invocation, change the attribute from inner to outer style + | +LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } +LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo![]; } + | error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:82:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } - | ------- ^^^^^^^^ not permitted following an outer attribute - | | + | ------- ^^^^^^^^ ------ the inner attribute doesn't annotate this item macro invocation + | | | + | | not permitted following an outer attribute | previous outer attribute | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the item macro invocation, change the attribute from inner to outer style + | +LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } +LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo!{}; } + | error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:88:35 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/bad-interpolated-block.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/bad-interpolated-block.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/bad-interpolated-block.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/bad-interpolated-block.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | the `block` fragment is within this context ... LL | m!({}); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -20,7 +20,7 @@ | the `block` fragment is within this context ... LL | m!({}); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -31,7 +31,7 @@ | ^^ the `block` fragment is within this context ... LL | m!({}); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/doc-comment-in-if-statement.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/doc-comment-in-if-statement.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/doc-comment-in-if-statement.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/doc-comment-in-if-statement.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,6 +5,11 @@ | ^^^^^ | = note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items +help: you might have meant to write a regular comment + | +LL - if true /*!*/ {} +LL + if true /**/ {} + | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/doc-comment-in-if-statement.rs:2:13 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ } fn bar() -> i32 { - ({2}) + 2 //~ ERROR expected expression, found `+` + ({2}) + 2 //~ ERROR leading `+` is not supported //~^ ERROR mismatched types } @@ -32,4 +32,9 @@ }) > 0 //~ ERROR expected expression } +fn qux() -> u32 { + ({2}) - 2 //~ ERROR cannot apply unary operator `-` to type `u32` + //~^ ERROR mismatched types +} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ } fn bar() -> i32 { - {2} + 2 //~ ERROR expected expression, found `+` + {2} + 2 //~ ERROR leading `+` is not supported //~^ ERROR mismatched types } @@ -32,4 +32,9 @@ } > 0 //~ ERROR expected expression } +fn qux() -> u32 { + {2} - 2 //~ ERROR cannot apply unary operator `-` to type `u32` + //~^ ERROR mismatched types +} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/expr-as-stmt.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,11 +9,11 @@ LL | ({2}) + {2} | + + -error: expected expression, found `+` +error: leading `+` is not supported --> $DIR/expr-as-stmt.rs:13:9 | LL | {2} + 2 - | ^ expected expression + | ^ unexpected `+` | help: parentheses are required to parse this as an expression | @@ -99,7 +99,29 @@ LL | ({ 3 }) * 3 | + + -error: aborting due to 9 previous errors +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:36:6 + | +LL | {2} - 2 + | ^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | {return 2;} - 2 + | ++++++ + + +error[E0600]: cannot apply unary operator `-` to type `u32` + --> $DIR/expr-as-stmt.rs:36:9 + | +LL | {2} - 2 + | ^^^ cannot apply unary operator `-` + | +help: parentheses are required to parse this as an expression + | +LL | ({2}) - 2 + | + + + +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0308, E0614. +Some errors have detailed explanations: E0308, E0600, E0614. For more information about an error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/float-field-interpolated.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/float-field-interpolated.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/float-field-interpolated.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/float-field-interpolated.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ ... LL | generate_field_accesses!(1.1, 1.1, 1.1); - | ---------------------------------------- in this macro invocation + | --------------------------------------- in this macro invocation | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^ expected one of `.`, `;`, `?`, `}`, or an operator ... LL | generate_field_accesses!(1.1, 1.1, 1.1); - | ---------------------------------------- in this macro invocation + | --------------------------------------- in this macro invocation | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -27,7 +27,7 @@ | ^^ ... LL | generate_field_accesses!(1.1, 1.1, 1.1); - | ---------------------------------------- in this macro invocation + | --------------------------------------- in this macro invocation | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -38,7 +38,7 @@ | ^^ expected one of `.`, `;`, `?`, `}`, or an operator ... LL | generate_field_accesses!(1.1, 1.1, 1.1); - | ---------------------------------------- in this macro invocation + | --------------------------------------- in this macro invocation | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/inner-attr-after-doc-comment.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/inner-attr-after-doc-comment.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/inner-attr-after-doc-comment.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/inner-attr-after-doc-comment.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,8 +8,16 @@ LL | LL | #![recursion_limit="100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attribute +LL | +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the function, change the attribute from inner to outer style + | +LL - #![recursion_limit="100"] +LL + #[recursion_limit="100"] + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/inner-attr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/inner-attr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/inner-attr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/inner-attr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,15 @@ LL | LL | #![recursion_limit="100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attribute +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the function, change the attribute from inner to outer style + | +LL - #![recursion_limit="100"] +LL + #[recursion_limit="100"] + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/inverted-parameters.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/inverted-parameters.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/inverted-parameters.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/inverted-parameters.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,15 +38,15 @@ help: if this is a `self` type, give it a parameter name | LL | fn fizz(self: i32) {} - | ~~~~~~~~~ + | +++++ help: if this is a parameter name, give it a type | LL | fn fizz(i32: TypeName) {} - | ~~~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | fn fizz(_: i32) {} - | ~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `S` --> $DIR/inverted-parameters.rs:27:23 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-30318.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-30318.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-30318.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-30318.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,27 @@ +// run-rustfix +#![allow(unused)] +fn foo() { } + +/// Misplaced comment... +//~^ ERROR expected outer doc comment +fn bar() { } //~ NOTE the inner doc comment doesn't annotate this function + +#[test] //~ ERROR an inner attribute is not permitted in this context +fn baz() { } //~ NOTE the inner attribute doesn't annotate this function +//~^^ NOTE inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually + +/** Misplaced comment... */ +//~^ ERROR expected outer doc comment +fn bat() { } //~ NOTE the inner doc comment doesn't annotate this function + +fn main() { } + +// Misplaced comment... +//~^ ERROR expected outer doc comment +//~| NOTE inner doc comments like this (starting with `//!` or `/*!`) can only appear before items +//~| NOTE other attributes here +/* Misplaced comment... */ +//~^ ERROR expected outer doc comment +//~| NOTE this doc comment doesn't document anything +//~| ERROR expected item after doc comment +//~| NOTE inner doc comments like this (starting with `//!` or `/*!`) can only appear before items diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-30318.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-30318.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-30318.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-30318.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,27 @@ +// run-rustfix +#![allow(unused)] fn foo() { } //! Misplaced comment... //~^ ERROR expected outer doc comment -//~| NOTE inner doc comments like this (starting with `//!` or `/*!`) can only appear before items +fn bar() { } //~ NOTE the inner doc comment doesn't annotate this function + +#![test] //~ ERROR an inner attribute is not permitted in this context +fn baz() { } //~ NOTE the inner attribute doesn't annotate this function +//~^^ NOTE inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually + +/*! Misplaced comment... */ +//~^ ERROR expected outer doc comment +fn bat() { } //~ NOTE the inner doc comment doesn't annotate this function fn main() { } + +//! Misplaced comment... +//~^ ERROR expected outer doc comment +//~| NOTE inner doc comments like this (starting with `//!` or `/*!`) can only appear before items +//~| NOTE other attributes here +/*! Misplaced comment... */ +//~^ ERROR expected outer doc comment +//~| NOTE this doc comment doesn't document anything +//~| ERROR expected item after doc comment +//~| NOTE inner doc comments like this (starting with `//!` or `/*!`) can only appear before items diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-30318.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-30318.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-30318.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-30318.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,81 @@ error[E0753]: expected outer doc comment - --> $DIR/issue-30318.rs:3:1 + --> $DIR/issue-30318.rs:5:1 + | +LL | //! Misplaced comment... + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn bar() { } + | ------------ the inner doc comment doesn't annotate this function + | +help: to annotate the function, change the doc comment from inner to outer style + | +LL | /// Misplaced comment... + | ~ + +error: an inner attribute is not permitted in this context + --> $DIR/issue-30318.rs:9:1 + | +LL | #![test] + | ^^^^^^^^ +LL | fn baz() { } + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the function, change the attribute from inner to outer style + | +LL - #![test] +LL + #[test] + | + +error[E0753]: expected outer doc comment + --> $DIR/issue-30318.rs:13:1 + | +LL | /*! Misplaced comment... */ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn bat() { } + | ------------ the inner doc comment doesn't annotate this function + | +help: to annotate the function, change the doc comment from inner to outer style + | +LL | /** Misplaced comment... */ + | ~ + +error[E0753]: expected outer doc comment + --> $DIR/issue-30318.rs:19:1 | LL | //! Misplaced comment... | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items +help: you might have meant to write a regular comment + | +LL - //! Misplaced comment... +LL + // Misplaced comment... + | + +error[E0753]: expected outer doc comment + --> $DIR/issue-30318.rs:23:1 + | +LL | /*! Misplaced comment... */ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items +help: you might have meant to write a regular comment + | +LL - /*! Misplaced comment... */ +LL + /* Misplaced comment... */ + | + +error: expected item after doc comment + --> $DIR/issue-30318.rs:23:1 + | +LL | //! Misplaced comment... + | ------------------------ other attributes here +... +LL | /*! Misplaced comment... */ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this doc comment doesn't document anything -error: aborting due to previous error +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0753`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-44406.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-44406.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-44406.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-44406.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ macro_rules! foo { ($rest: tt) => { - bar(baz: $rest) + bar(baz: $rest) //~ ERROR invalid `struct` delimiters or `fn` call arguments } } fn main() { - foo!(true); //~ ERROR expected type, found keyword + foo!(true); //~^ ERROR expected identifier, found keyword } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-44406.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-44406.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-44406.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-44406.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -9,17 +9,25 @@ LL | foo!(r#true); | ~~~~~~ -error: expected type, found keyword `true` - --> $DIR/issue-44406.rs:8:10 +error: invalid `struct` delimiters or `fn` call arguments + --> $DIR/issue-44406.rs:3:9 | LL | bar(baz: $rest) - | - help: try using a semicolon: `;` + | ^^^^^^^^^^^^^^^ ... LL | foo!(true); - | ^^^^ expected type + | ---------- in this macro invocation | - = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` - = note: see issue #23416 for more information + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) +help: if `bar` is a struct, use braces as delimiters + | +LL | bar { } + | ~ +help: if `bar` is a function, use the arguments directly + | +LL - bar(baz: $rest) +LL + bar(: $rest) + | error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-45296.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-45296.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-45296.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-45296.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,4 +2,5 @@ let unused = (); #![allow(unused_variables)] //~ ERROR not permitted in this context + fn foo() {} } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-45296.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-45296.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-45296.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-45296.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,15 @@ | LL | #![allow(unused_variables)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo() {} + | ----------- the inner attribute doesn't annotate this function | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files +help: to annotate the function, change the attribute from inner to outer style + | +LL - #![allow(unused_variables)] +LL + #[allow(unused_variables)] + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ | ^^^^^^^^^ ... LL | expand_to_enum!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = help: consider moving the enum out to a nearby module scope = note: this error originates in the macro `expand_to_enum` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -33,7 +33,7 @@ | ^^^^^^^^^ ... LL | expand_to_enum!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = help: consider moving the enum out to a nearby module scope = note: this error originates in the macro `expand_to_enum` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -53,7 +53,7 @@ | ^^^^^^^^^ ... LL | expand_to_enum!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = help: consider moving the enum out to a nearby module scope = note: this error originates in the macro `expand_to_enum` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -17,7 +17,7 @@ | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut` ... LL | mac!('a); - | --------- in this macro invocation + | -------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-87812-path.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-87812-path.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-87812-path.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-87812-path.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | expected due to this ... LL | foo!(Baz); - | ---------- in this macro invocation + | --------- in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +// run-rustfix +#[allow(unused_parens)] +fn main() { + let _ = 1; //~ ERROR leading `+` is not supported + let _ = (1.0 + 2.0) * 3.0; //~ ERROR leading `+` is not supported + //~| ERROR leading `+` is not supported + let _ = [3, 4+6]; //~ ERROR leading `+` is not supported +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +// run-rustfix +#[allow(unused_parens)] +fn main() { + let _ = +1; //~ ERROR leading `+` is not supported + let _ = (1.0 + +2.0) * +3.0; //~ ERROR leading `+` is not supported + //~| ERROR leading `+` is not supported + let _ = [+3, 4+6]; //~ ERROR leading `+` is not supported +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88276-unary-plus.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,50 @@ +error: leading `+` is not supported + --> $DIR/issue-88276-unary-plus.rs:4:13 + | +LL | let _ = +1; + | ^ unexpected `+` + | +help: try removing the `+` + | +LL - let _ = +1; +LL + let _ = 1; + | + +error: leading `+` is not supported + --> $DIR/issue-88276-unary-plus.rs:5:20 + | +LL | let _ = (1.0 + +2.0) * +3.0; + | ^ unexpected `+` + | +help: try removing the `+` + | +LL - let _ = (1.0 + +2.0) * +3.0; +LL + let _ = (1.0 + 2.0) * +3.0; + | + +error: leading `+` is not supported + --> $DIR/issue-88276-unary-plus.rs:5:28 + | +LL | let _ = (1.0 + +2.0) * +3.0; + | ^ unexpected `+` + | +help: try removing the `+` + | +LL - let _ = (1.0 + +2.0) * +3.0; +LL + let _ = (1.0 + +2.0) * 3.0; + | + +error: leading `+` is not supported + --> $DIR/issue-88276-unary-plus.rs:7:14 + | +LL | let _ = [+3, 4+6]; + | ^ unexpected `+` + | +help: try removing the `+` + | +LL - let _ = [+3, 4+6]; +LL + let _ = [3, 4+6]; + | + +error: aborting due to 4 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88770.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88770.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88770.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88770.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +// Regression test for the ICE described in #88770. + +// error-pattern:this file contains an unclosed delimiter +// error-pattern:expected one of +// error-pattern:missing `in` in `for` loop +// error-pattern:expected `;`, found `e` + +fn m(){print!("",(c for&g +u +e +e diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88770.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88770.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88770.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88770.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,66 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-88770.rs:11:3 + | +LL | fn m(){print!("",(c for&g + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +... +LL | e + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-88770.rs:11:3 + | +LL | fn m(){print!("",(c for&g + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +... +LL | e + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-88770.rs:11:3 + | +LL | fn m(){print!("",(c for&g + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +... +LL | e + | ^ + +error: missing `in` in `for` loop + --> $DIR/issue-88770.rs:8:26 + | +LL | fn m(){print!("",(c for&g + | __________________________^ +LL | | u + | |_ help: try adding `in` here + +error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found keyword `for` + --> $DIR/issue-88770.rs:8:21 + | +LL | fn m(){print!("",(c for&g + | ^^^ expected one of 8 possible tokens + +error: expected `;`, found `e` + --> $DIR/issue-88770.rs:10:2 + | +LL | e + | ^ help: add `;` here +LL | e + | - unexpected token + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `)` + --> $DIR/issue-88770.rs:11:3 + | +LL | e + | ^ expected one of 7 possible tokens + +error: aborting due to 7 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88818.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88818.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88818.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88818.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +// Regression test for #88818 (improve error message for missing trait +// in `impl for X`). + +struct S { } +impl for S { } +//~^ ERROR: missing trait in a trait impl +//~| HELP: add a trait here +//~| HELP: for an inherent impl, drop this `for` + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88818.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88818.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-88818.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-88818.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +error: missing trait in a trait impl + --> $DIR/issue-88818.rs:5:5 + | +LL | impl for S { } + | ^ + | +help: add a trait here + | +LL | impl Trait for S { } + | +++++ +help: for an inherent impl, drop this `for` + | +LL - impl for S { } +LL + impl S { } + | + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89388.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89388.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89388.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89388.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +// Regression test for #89388. + +fn main() { + let option: Option<&[u8]> = Some(b"..."); + let _ = option.map([_]::to_vec); + //~^ ERROR: missing angle brackets in associated item path +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89388.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89388.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89388.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89388.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: missing angle brackets in associated item path + --> $DIR/issue-89388.rs:5:24 + | +LL | let _ = option.map([_]::to_vec); + | ^^^^^^^^^^^ help: try: `<[_]>::to_vec` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89396.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89396.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89396.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89396.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// Regression test for issue #89396: Try to recover from a +// `=>` -> `=` or `->` typo in a match arm. + +// run-rustfix + +fn main() { + let opt = Some(42); + let _ = match opt { + Some(_) => true, + //~^ ERROR: expected one of + //~| HELP: try using a fat arrow here + None => false, + //~^ ERROR: expected one of + //~| HELP: try using a fat arrow here + }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89396.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89396.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89396.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89396.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// Regression test for issue #89396: Try to recover from a +// `=>` -> `=` or `->` typo in a match arm. + +// run-rustfix + +fn main() { + let opt = Some(42); + let _ = match opt { + Some(_) = true, + //~^ ERROR: expected one of + //~| HELP: try using a fat arrow here + None -> false, + //~^ ERROR: expected one of + //~| HELP: try using a fat arrow here + }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89396.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89396.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/issue-89396.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/issue-89396.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,20 @@ +error: expected one of `=>`, `if`, or `|`, found `=` + --> $DIR/issue-89396.rs:9:17 + | +LL | Some(_) = true, + | ^ + | | + | expected one of `=>`, `if`, or `|` + | help: try using a fat arrow here: `=>` + +error: expected one of `=>`, `@`, `if`, or `|`, found `->` + --> $DIR/issue-89396.rs:12:14 + | +LL | None -> false, + | ^^ + | | + | expected one of `=>`, `@`, `if`, or `|` + | help: try using a fat arrow here: `=>` + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/labeled-no-colon-expr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/labeled-no-colon-expr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/labeled-no-colon-expr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/labeled-no-colon-expr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -68,7 +68,7 @@ | the `block` fragment is within this context ... LL | m!({}); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/lifetime-in-pattern.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/lifetime-in-pattern.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/lifetime-in-pattern.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/lifetime-in-pattern.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,16 +13,16 @@ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name | -LL | fn test(self: &str) { - | ~~~~~~~~~~ +LL | fn test(self: &'a str) { + | +++++ help: if this is a parameter name, give it a type | LL | fn test(str: &TypeName) { | ~~~~~~~~~~~~~~ help: if this is a type, explicitly ignore the parameter name | -LL | fn test(_: &str) { - | ~~~~~~~ +LL | fn test(_: &'a str) { + | ++ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/issue-37113.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/issue-37113.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/issue-37113.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/issue-37113.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ expected identifier ... LL | test_macro!(String,); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `test_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/issue-37234.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/issue-37234.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/issue-37234.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/issue-37234.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ expected one of `.`, `;`, `?`, `else`, or an operator ... LL | failed!(); - | ---------- in this macro invocation + | --------- in this macro invocation | = note: this error originates in the macro `failed` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/macro-incomplete-parse.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/macro-incomplete-parse.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/macro-incomplete-parse.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/macro-incomplete-parse.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ ... LL | ignored_item!(); - | ---------------- caused by the macro expansion here + | --------------- caused by the macro expansion here | = note: the usage of `ignored_item!` is likely invalid in item context @@ -16,7 +16,7 @@ | ^ expected one of `.`, `;`, `?`, `}`, or an operator ... LL | ignored_expr!(); - | ---------------- in this macro invocation + | --------------- in this macro invocation | = note: this error originates in the macro `ignored_expr` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/pub-item-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/pub-item-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/pub-item-macro.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/pub-item-macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^ help: remove the visibility ... LL | pub_x!(); - | --------- in this macro invocation + | -------- in this macro invocation | = help: try adjusting the macro to put `pub` inside the invocation = note: this error originates in the macro `pub_x` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -23,7 +23,7 @@ | ^^^^^^^^^^^^^^^^^^ ... LL | pub_x!(); - | --------- in this macro invocation + | -------- in this macro invocation = note: this error originates in the macro `priv_x` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/trait-non-item-macros.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/trait-non-item-macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro/trait-non-item-macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro/trait-non-item-macros.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ ... LL | bah!(2); - | -------- caused by the macro expansion here + | ------- caused by the macro expansion here | = note: the usage of `bah!` is likely invalid in trait item context diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro-braces-dot-question.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro-braces-dot-question.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/macro-braces-dot-question.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/macro-braces-dot-question.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +// check-pass + +use std::io::Write; + +fn main() -> Result<(), std::io::Error> { + vec! { 1, 2, 3 }.len(); + write! { vec![], "" }?; + println!{""} + [0]; // separate statement, not indexing into the result of println. + Ok(()) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/missing-semicolon.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/missing-semicolon.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/missing-semicolon.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/missing-semicolon.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^ expected one of `.`, `;`, `?`, `else`, or an operator ... LL | fn main() { m!(0, 0; 0, 0); } - | --------------- in this macro invocation + | -------------- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/mut-patterns.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/mut-patterns.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/mut-patterns.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/mut-patterns.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -106,7 +106,7 @@ | ^^ expected identifier ... LL | foo!(x); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/omitted-arg-in-item-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/omitted-arg-in-item-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/omitted-arg-in-item-fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/omitted-arg-in-item-fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,15 +8,15 @@ help: if this is a `self` type, give it a parameter name | LL | fn foo(self: x) { - | ~~~~~~~ + | +++++ help: if this is a parameter name, give it a type | LL | fn foo(x: TypeName) { - | ~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | fn foo(_: x) { - | ~~~~ + | ++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/pat-lt-bracket-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/pat-lt-bracket-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/pat-lt-bracket-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/pat-lt-bracket-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,11 +8,11 @@ help: if this is a `self` type, give it a parameter name | LL | fn a(self: B<) {} - | ~~~~~~~ + | +++++ help: if this is a type, explicitly ignore the parameter name | LL | fn a(_: B<) {} - | ~~~~ + | ++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-for-loop-parens-around-head.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-for-loop-parens-around-head.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-for-loop-parens-around-head.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-for-loop-parens-around-head.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ for ( elem in vec ) { //~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in` - //~| ERROR unexpected closing `)` + //~| ERROR unexpected parenthesis surrounding `for` loop head const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-for-loop-parens-around-head.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-for-loop-parens-around-head.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-for-loop-parens-around-head.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-for-loop-parens-around-head.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,14 +4,17 @@ LL | for ( elem in vec ) { | ^^ expected one of `)`, `,`, `@`, or `|` -error: unexpected closing `)` - --> $DIR/recover-for-loop-parens-around-head.rs:10:23 +error: unexpected parenthesis surrounding `for` loop head + --> $DIR/recover-for-loop-parens-around-head.rs:10:9 | LL | for ( elem in vec ) { - | --------------^ - | | - | opening `(` - | help: remove parenthesis in `for` loop: `elem in vec` + | ^ ^ + | +help: remove parenthesis in `for` loop + | +LL - for ( elem in vec ) { +LL + for elem in vec { + | error[E0308]: mismatched types --> $DIR/recover-for-loop-parens-around-head.rs:13:38 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-from-bad-variant.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-from-bad-variant.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-from-bad-variant.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-from-bad-variant.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ fn main() { let x = Enum::Foo(a: 3, b: 4); - //~^ ERROR expected type, found `3` + //~^ ERROR invalid `struct` delimiters or `fn` call arguments match x { Enum::Foo(a, b) => {} //~^ ERROR expected tuple struct or tuple variant, found struct variant `Enum::Foo` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-from-bad-variant.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-from-bad-variant.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-from-bad-variant.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-from-bad-variant.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,18 @@ -error: expected type, found `3` - --> $DIR/recover-from-bad-variant.rs:7:26 +error: invalid `struct` delimiters or `fn` call arguments + --> $DIR/recover-from-bad-variant.rs:7:13 | LL | let x = Enum::Foo(a: 3, b: 4); - | - ^ expected type - | | - | tried to parse a type due to this type ascription + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` - = note: see issue #23416 for more information +help: if `Enum::Foo` is a struct, use braces as delimiters + | +LL | let x = Enum::Foo { a: 3, b: 4 }; + | ~ ~ +help: if `Enum::Foo` is a function, use the arguments directly + | +LL - let x = Enum::Foo(a: 3, b: 4); +LL + let x = Enum::Foo(3, 4); + | error[E0532]: expected tuple struct or tuple variant, found struct variant `Enum::Foo` --> $DIR/recover-from-bad-variant.rs:10:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-range-pats.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-range-pats.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/recover-range-pats.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/recover-range-pats.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -165,7 +165,7 @@ | ^^^ help: use `..=` instead ... LL | mac!(0); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -176,7 +176,7 @@ | ^^^ help: use `..` instead ... LL | mac!(0); - | -------- in this macro invocation + | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -188,7 +188,7 @@ | ^^^ help: use `..` instead ... LL | mac!(0); - | -------- in this macro invocation + | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -277,7 +277,7 @@ | ^^^ help: use `..=` for an inclusive range ... LL | mac2!(0, 1); - | ------------ in this macro invocation + | ----------- in this macro invocation | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/stmt_expr_attrs_placement.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/stmt_expr_attrs_placement.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/stmt_expr_attrs_placement.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/stmt_expr_attrs_placement.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,8 @@ LL | let a = #![allow(warnings)] (1, 2); | ^^^^^^^^^^^^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/stmt_expr_attrs_placement.rs:10:14 @@ -12,7 +13,8 @@ LL | let b = (#![allow(warnings)] 1, 2); | ^^^^^^^^^^^^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/stmt_expr_attrs_placement.rs:15:10 @@ -20,7 +22,8 @@ LL | (#![allow(warnings)] 1, 2) | ^^^^^^^^^^^^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/stmt_expr_attrs_placement.rs:21:18 @@ -28,7 +31,8 @@ LL | let e = (#![allow(warnings)] 1, 2); | ^^^^^^^^^^^^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/stmt_expr_attrs_placement.rs:26:14 @@ -36,7 +40,8 @@ LL | let e = [#![allow(warnings)] 1, 2]; | ^^^^^^^^^^^^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/stmt_expr_attrs_placement.rs:29:14 @@ -44,7 +49,8 @@ LL | let f = [#![allow(warnings)] 1; 0]; | ^^^^^^^^^^^^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: an inner attribute is not permitted in this context --> $DIR/stmt_expr_attrs_placement.rs:36:24 @@ -52,7 +58,8 @@ LL | let h = MyStruct { #![allow(warnings)] field: 0 }; | ^^^^^^^^^^^^^^^^^^^ | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them error: aborting due to 7 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/trailing-plus-in-bounds.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/trailing-plus-in-bounds.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/trailing-plus-in-bounds.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/trailing-plus-in-bounds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,9 @@ // build-pass (FIXME(62277): could be check-pass?) -#![feature(box_syntax)] #![allow(bare_trait_objects)] use std::fmt::Debug; fn main() { - let x: Box = box 3 as Box; // Trailing `+` is OK + let x: Box = Box::new(3) as Box; // Trailing `+` is OK } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/trait-object-delimiters.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/trait-object-delimiters.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/trait-object-delimiters.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/trait-object-delimiters.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -52,7 +52,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0224]: at least one trait is required for an object type @@ -69,7 +69,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 9 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/trait-object-trait-parens.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/trait-object-trait-parens.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/trait-object-trait-parens.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/trait-object-trait-parens.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -52,7 +52,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + for<'a> Trait<'a> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + for<'a> Trait<'a> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -63,7 +63,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -74,7 +74,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 6 previous errors; 3 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +// Regression test for #88684: Improve diagnostics for combining marks +// in character literals. + +// run-rustfix + +fn main() { + let _spade = "â™ ï¸"; + //~^ ERROR: character literal may only contain one codepoint + //~| NOTE: this `â™ ` is followed by the combining mark `\u{fe0f}` + //~| HELP: if you meant to write a `str` literal, use double quotes + + let _s = "ṩ̂̊"; + //~^ ERROR: character literal may only contain one codepoint + //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` + //~| HELP: if you meant to write a `str` literal, use double quotes + + let _a = 'Ã…'; + //~^ ERROR: character literal may only contain one codepoint + //~| NOTE: this `A` is followed by the combining mark `\u{30a}` + //~| HELP: consider using the normalized form `\u{c5}` of this character +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +// Regression test for #88684: Improve diagnostics for combining marks +// in character literals. + +// run-rustfix + +fn main() { + let _spade = 'â™ ï¸'; + //~^ ERROR: character literal may only contain one codepoint + //~| NOTE: this `â™ ` is followed by the combining mark `\u{fe0f}` + //~| HELP: if you meant to write a `str` literal, use double quotes + + let _s = 'ṩ̂̊'; + //~^ ERROR: character literal may only contain one codepoint + //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` + //~| HELP: if you meant to write a `str` literal, use double quotes + + let _a = 'AÌŠ'; + //~^ ERROR: character literal may only contain one codepoint + //~| NOTE: this `A` is followed by the combining mark `\u{30a}` + //~| HELP: consider using the normalized form `\u{c5}` of this character +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-character-literal.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,48 @@ +error: character literal may only contain one codepoint + --> $DIR/unicode-character-literal.rs:7:18 + | +LL | let _spade = 'â™ ï¸'; + | ^^^ + | +note: this `â™ ` is followed by the combining mark `\u{fe0f}` + --> $DIR/unicode-character-literal.rs:7:19 + | +LL | let _spade = 'â™ ï¸'; + | ^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let _spade = "â™ ï¸"; + | ~~~ + +error: character literal may only contain one codepoint + --> $DIR/unicode-character-literal.rs:12:14 + | +LL | let _s = 'ṩ̂̊'; + | ^^^ + | +note: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` + --> $DIR/unicode-character-literal.rs:12:15 + | +LL | let _s = 'ṩ̂̊'; + | ^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let _s = "ṩ̂̊"; + | ~~~ + +error: character literal may only contain one codepoint + --> $DIR/unicode-character-literal.rs:17:14 + | +LL | let _a = 'AÌŠ'; + | ^-^ + | | + | help: consider using the normalized form `\u{c5}` of this character: `Ã…` + | +note: this `A` is followed by the combining mark `\u{30a}` + --> $DIR/unicode-character-literal.rs:17:15 + | +LL | let _a = 'AÌŠ'; + | ^ + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-control-codepoints.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-control-codepoints.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-control-codepoints.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-control-codepoints.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +fn main() { + // if access_level != "us‫e‪r" { // Check if admin + //~^ ERROR unicode codepoint changing visible direction of text present in comment + println!("us\u{202B}e\u{202A}r"); + println!("{:?}", r#"us\u{202B}e\u{202A}r"#); + println!("{:?}", b"us\u{202B}e\u{202A}r"); + //~^ ERROR unicode escape in byte string + //~| ERROR unicode escape in byte string + println!("{:?}", br##"us\u{202B}e\u{202A}r"##); + + println!("{:?}", "/*‮ } â¦if isAdmin⩠⦠begin admins only "); + //~^ ERROR unicode codepoint changing visible direction of text present in literal + + println!("{:?}", r##"/*‮ } â¦if isAdmin⩠⦠begin admins only "##); + //~^ ERROR unicode codepoint changing visible direction of text present in literal + println!("{:?}", b"/*‮ } â¦if isAdmin⩠⦠begin admins only "); + //~^ ERROR non-ASCII character in byte constant + //~| ERROR non-ASCII character in byte constant + //~| ERROR non-ASCII character in byte constant + //~| ERROR non-ASCII character in byte constant + println!("{:?}", br##"/*‮ } â¦if isAdmin⩠⦠begin admins only "##); + //~^ ERROR raw byte string must be ASCII + //~| ERROR raw byte string must be ASCII + //~| ERROR raw byte string must be ASCII + //~| ERROR raw byte string must be ASCII + println!("{:?}", '‮'); + //~^ ERROR unicode codepoint changing visible direction of text present in literal +} + +//"/*‮ } â¦if isAdmin⩠⦠begin admins only */" +//~^ ERROR unicode codepoint changing visible direction of text present in comment + +/** '‮'); */fn foo() {} +//~^ ERROR unicode codepoint changing visible direction of text present in doc comment + +/** + * + * '‮'); */fn bar() {} +//~^^^ ERROR unicode codepoint changing visible direction of text present in doc comment diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-control-codepoints.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-control-codepoints.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/parser/unicode-control-codepoints.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/parser/unicode-control-codepoints.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,192 @@ +error: unicode escape in byte string + --> $DIR/unicode-control-codepoints.rs:6:26 + | +LL | println!("{:?}", b"us\u{202B}e\u{202A}r"); + | ^^^^^^^^ unicode escape in byte string + | + = help: unicode escape sequences cannot be used as a byte or in a byte string + +error: unicode escape in byte string + --> $DIR/unicode-control-codepoints.rs:6:35 + | +LL | println!("{:?}", b"us\u{202B}e\u{202A}r"); + | ^^^^^^^^ unicode escape in byte string + | + = help: unicode escape sequences cannot be used as a byte or in a byte string + +error: non-ASCII character in byte constant + --> $DIR/unicode-control-codepoints.rs:16:26 + | +LL | println!("{:?}", b"/* } if isAdmin begin admins only "); + | ^ byte constant must be ASCII but is '\u{202e}' + | +help: if you meant to use the UTF-8 encoding of '\u{202e}', use \xHH escapes + | +LL | println!("{:?}", b"/*\xE2\x80\xAE } if isAdmin begin admins only "); + | ~~~~~~~~~~~~ + +error: non-ASCII character in byte constant + --> $DIR/unicode-control-codepoints.rs:16:30 + | +LL | println!("{:?}", b"/* } if isAdmin begin admins only "); + | ^ byte constant must be ASCII but is '\u{2066}' + | +help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes + | +LL | println!("{:?}", b"/* } \xE2\x81\xA6if isAdmin begin admins only "); + | ~~~~~~~~~~~~ + +error: non-ASCII character in byte constant + --> $DIR/unicode-control-codepoints.rs:16:41 + | +LL | println!("{:?}", b"/* } if isAdmin begin admins only "); + | ^ byte constant must be ASCII but is '\u{2069}' + | +help: if you meant to use the UTF-8 encoding of '\u{2069}', use \xHH escapes + | +LL | println!("{:?}", b"/* } if isAdmin\xE2\x81\xA9 begin admins only "); + | ~~~~~~~~~~~~ + +error: non-ASCII character in byte constant + --> $DIR/unicode-control-codepoints.rs:16:43 + | +LL | println!("{:?}", b"/* } if isAdmin begin admins only "); + | ^ byte constant must be ASCII but is '\u{2066}' + | +help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes + | +LL | println!("{:?}", b"/* } if isAdmin \xE2\x81\xA6 begin admins only "); + | ~~~~~~~~~~~~ + +error: raw byte string must be ASCII + --> $DIR/unicode-control-codepoints.rs:21:29 + | +LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##); + | ^ must be ASCII but is '\u{202e}' + +error: raw byte string must be ASCII + --> $DIR/unicode-control-codepoints.rs:21:33 + | +LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##); + | ^ must be ASCII but is '\u{2066}' + +error: raw byte string must be ASCII + --> $DIR/unicode-control-codepoints.rs:21:44 + | +LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##); + | ^ must be ASCII but is '\u{2069}' + +error: raw byte string must be ASCII + --> $DIR/unicode-control-codepoints.rs:21:46 + | +LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##); + | ^ must be ASCII but is '\u{2066}' + +error: unicode codepoint changing visible direction of text present in comment + --> $DIR/unicode-control-codepoints.rs:2:5 + | +LL | // if access_level != "user" { // Check if admin + | ^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^ + | | || + | | |'\u{202a}' + | | '\u{202b}' + | this comment contains invisible unicode text flow control codepoints + | + = note: `#[deny(text_direction_codepoint_in_comment)]` on by default + = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + = help: if their presence wasn't intentional, you can remove them + +error: unicode codepoint changing visible direction of text present in comment + --> $DIR/unicode-control-codepoints.rs:30:1 + | +LL | //"/* } if isAdmin begin admins only */" + | ^^^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^ + | | | | || + | | | | |'\u{2066}' + | | | | '\u{2069}' + | | | '\u{2066}' + | | '\u{202e}' + | this comment contains invisible unicode text flow control codepoints + | + = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + = help: if their presence wasn't intentional, you can remove them + +error: unicode codepoint changing visible direction of text present in literal + --> $DIR/unicode-control-codepoints.rs:11:22 + | +LL | println!("{:?}", "/* } if isAdmin begin admins only "); + | ^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^ + | | | | || + | | | | |'\u{2066}' + | | | | '\u{2069}' + | | | '\u{2066}' + | | '\u{202e}' + | this literal contains invisible unicode text flow control codepoints + | + = note: `#[deny(text_direction_codepoint_in_literal)]` on by default + = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + = help: if their presence wasn't intentional, you can remove them +help: if you want to keep them but make them visible in your source code, you can escape them + | +LL | println!("{:?}", "/*\u{202e} } \u{2066}if isAdmin\u{2069} \u{2066} begin admins only "); + | ~~~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~~ + +error: unicode codepoint changing visible direction of text present in literal + --> $DIR/unicode-control-codepoints.rs:14:22 + | +LL | println!("{:?}", r##"/* } if isAdmin begin admins only "##); + | ^^^^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^ + | | | | || + | | | | |'\u{2066}' + | | | | '\u{2069}' + | | | '\u{2066}' + | | '\u{202e}' + | this literal contains invisible unicode text flow control codepoints + | + = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + = help: if their presence wasn't intentional, you can remove them +help: if you want to keep them but make them visible in your source code, you can escape them + | +LL | println!("{:?}", r##"/*\u{202e} } \u{2066}if isAdmin\u{2069} \u{2066} begin admins only "##); + | ~~~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~~ + +error: unicode codepoint changing visible direction of text present in literal + --> $DIR/unicode-control-codepoints.rs:26:22 + | +LL | println!("{:?}", ''); + | ^- + | || + | |'\u{202e}' + | this literal contains an invisible unicode text flow control codepoint + | + = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + = help: if their presence wasn't intentional, you can remove them +help: if you want to keep them but make them visible in your source code, you can escape them + | +LL | println!("{:?}", '\u{202e}'); + | ~~~~~~~~ + +error: unicode codepoint changing visible direction of text present in doc comment + --> $DIR/unicode-control-codepoints.rs:33:1 + | +LL | /** ''); */fn foo() {} + | ^^^^^^^^^^^^ this doc comment contains an invisible unicode text flow control codepoint + | + = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + = note: if their presence wasn't intentional, you can remove them + = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}' + +error: unicode codepoint changing visible direction of text present in doc comment + --> $DIR/unicode-control-codepoints.rs:36:1 + | +LL | / /** +LL | | * +LL | | * ''); */fn bar() {} + | |___________^ this doc comment contains an invisible unicode text flow control codepoint + | + = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + = note: if their presence wasn't intentional, you can remove them + = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}' + +error: aborting due to 17 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/path-lookahead.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/path-lookahead.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/path-lookahead.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/path-lookahead.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,18 @@ --> $DIR/path-lookahead.rs:10:12 | LL | return (::to_string(&arg)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/path-lookahead.rs:5:9 | LL | #![warn(unused_parens)] | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - return (::to_string(&arg)); +LL + return ::to_string(&arg); + | warning: 1 warning emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // Here we check that type ascription is syntactically invalid when -// not in the top position of a ascribing a let binding or function parameter. +// not in the top position of an ascribing `let` binding or function parameter. // This has no effect. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,28 @@ +trait Zero { + const ZERO: Self; +} + +impl Zero for String { + const ZERO: Self = String::new(); +} + +fn foo() { + match String::new() { + Zero::ZERO ..= Zero::ZERO => {}, + //~^ ERROR only `char` and numeric types are allowed in range patterns + _ => {}, + } +} + +fn bar() { + match Zero::ZERO { + Zero::ZERO ..= Zero::ZERO => {}, + //~^ ERROR type annotations needed [E0282] + _ => {}, + } +} + +fn main() { + foo(); + bar(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0029]: only `char` and numeric types are allowed in range patterns + --> $DIR/issue-88074-pat-range-type-inference-err.rs:11:9 + | +LL | Zero::ZERO ..= Zero::ZERO => {}, + | ----------^^^^^---------- + | | | + | | this is of type `String` but it should be `char` or numeric + | this is of type `String` but it should be `char` or numeric + +error[E0282]: type annotations needed + --> $DIR/issue-88074-pat-range-type-inference-err.rs:19:9 + | +LL | Zero::ZERO ..= Zero::ZERO => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: type must be known at this point + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0029, E0282. +For more information about an error, try `rustc --explain E0029`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +// check-pass + +trait Zero { + const ZERO: Self; +} + +impl Zero for i32 { + const ZERO: Self = 0; +} + +fn main() { + match 1 { + Zero::ZERO ..= 1 => {}, + _ => {}, + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/patkind-litrange-no-expr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/patkind-litrange-no-expr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/patkind-litrange-no-expr.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/patkind-litrange-no-expr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -19,7 +19,6 @@ Neg = -1, Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns //~| ERROR arbitrary expressions aren't allowed in patterns - //~| ERROR only `char` and numeric types are allowed in range patterns }); fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/patkind-litrange-no-expr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/patkind-litrange-no-expr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/patkind-litrange-no-expr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/patkind-litrange-no-expr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,15 +10,5 @@ LL | Arith = 1 + 1, | ^^^^^ -error[E0029]: only `char` and numeric types are allowed in range patterns - --> $DIR/patkind-litrange-no-expr.rs:20:13 - | -LL | $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range - | -- this is of type `{integer}` -... -LL | Arith = 1 + 1, - | ^^^^^ this is of type `_` but it should be `char` or numeric - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0029`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/auxiliary/hidden.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/auxiliary/hidden.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/auxiliary/hidden.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/auxiliary/hidden.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +pub enum Foo { + A, + B, + #[doc(hidden)] + C, +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/auxiliary/unstable.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/auxiliary/unstable.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/auxiliary/unstable.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/auxiliary/unstable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +#![feature(staged_api)] +#![stable(feature = "stable_test_feature", since = "1.0.0")] + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Foo { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Stable, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Stable2, + #[unstable(feature = "unstable_test_feature", issue = "none")] + Unstable, +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/const-private-fields.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/const-private-fields.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/const-private-fields.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/const-private-fields.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +// check-pass +// +// Check that we don't ignore private fields in usefulness checking +#![deny(unreachable_patterns)] + +mod inner { + #[derive(PartialEq, Eq)] + pub struct PrivateField { + pub x: bool, + y: bool, + } + + pub const FOO: PrivateField = PrivateField { x: true, y: true }; + pub const BAR: PrivateField = PrivateField { x: true, y: false }; +} +use inner::*; + +fn main() { + match FOO { + FOO => {} + BAR => {} + _ => {} + } + + match FOO { + FOO => {} + PrivateField { x: true, .. } => {} + _ => {} + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/consts-opaque.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/consts-opaque.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/consts-opaque.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/consts-opaque.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,11 @@ error: unreachable pattern --> $DIR/consts-opaque.rs:32:9 | +LL | FOO => {} + | --- matches any value +LL | LL | _ => {} // should not be emitting unreachable warning - | ^ + | ^ unreachable pattern | note: the lint level is defined here --> $DIR/consts-opaque.rs:6:9 @@ -25,8 +28,11 @@ error: unreachable pattern --> $DIR/consts-opaque.rs:39:9 | +LL | FOO_REF => {} + | ------- matches any value +LL | LL | Foo(_) => {} // should not be emitting unreachable warning - | ^^^^^^ + | ^^^^^^ unreachable pattern warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:45:9 @@ -70,15 +76,18 @@ error: unreachable pattern --> $DIR/consts-opaque.rs:63:9 | +LL | BAR => {} + | --- matches any value +LL | LL | Bar => {} // should not be emitting unreachable warning - | ^^^ + | ^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:65:9 | -LL | Bar => {} // should not be emitting unreachable warning +LL | BAR => {} | --- matches any value -LL | +... LL | _ => {} | ^ unreachable pattern @@ -97,14 +106,20 @@ error: unreachable pattern --> $DIR/consts-opaque.rs:72:9 | +LL | BAR => {} + | --- matches any value +LL | LL | BAR => {} // should not be emitting unreachable warning - | ^^^ + | ^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:75:9 | +LL | BAR => {} + | --- matches any value +... LL | _ => {} // should not be emitting unreachable warning - | ^ + | ^ unreachable pattern error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:80:9 @@ -115,14 +130,20 @@ error: unreachable pattern --> $DIR/consts-opaque.rs:82:9 | +LL | BAZ => {} + | --- matches any value +LL | LL | Baz::Baz1 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ + | ^^^^^^^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:84:9 | +LL | BAZ => {} + | --- matches any value +... LL | _ => {} - | ^ + | ^ unreachable pattern error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:90:9 @@ -133,8 +154,11 @@ error: unreachable pattern --> $DIR/consts-opaque.rs:92:9 | +LL | BAZ => {} + | --- matches any value +LL | LL | _ => {} - | ^ + | ^ unreachable pattern error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:97:9 @@ -145,20 +169,28 @@ error: unreachable pattern --> $DIR/consts-opaque.rs:99:9 | +LL | BAZ => {} + | --- matches any value +LL | LL | Baz::Baz2 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ + | ^^^^^^^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:101:9 | +LL | BAZ => {} + | --- matches any value +... LL | _ => {} // should not be emitting unreachable warning - | ^ + | ^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:127:9 | +LL | Wrap(_) => {} + | ------- matches any value LL | WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer - | ^^^^^^^^ + | ^^^^^^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:141:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,30 @@ +// aux-build:hidden.rs + +extern crate hidden; + +use hidden::Foo; + +fn main() { + match Foo::A { + Foo::A => {} + Foo::B => {} + } + //~^^^^ non-exhaustive patterns: `_` not covered + + match Foo::A { + Foo::A => {} + Foo::C => {} + } + //~^^^^ non-exhaustive patterns: `B` not covered + + match Foo::A { + Foo::A => {} + } + //~^^^ non-exhaustive patterns: `B` and `_` not covered + + match None { + None => {} + Some(Foo::A) => {} + } + //~^^^^ non-exhaustive patterns: `Some(B)` and `Some(_)` not covered +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,54 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:8:11 + | +LL | match Foo::A { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error[E0004]: non-exhaustive patterns: `B` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:14:11 + | +LL | match Foo::A { + | ^^^^^^ pattern `B` not covered + | + ::: $DIR/auxiliary/hidden.rs:3:5 + | +LL | B, + | - not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error[E0004]: non-exhaustive patterns: `B` and `_` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:20:11 + | +LL | match Foo::A { + | ^^^^^^ patterns `B` and `_` not covered + | + ::: $DIR/auxiliary/hidden.rs:3:5 + | +LL | B, + | - not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:25:11 + | +LL | match None { + | ^^^^ patterns `Some(B)` and `Some(_)` not covered + | + ::: $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ---- not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Option` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -133,8 +133,10 @@ error: unreachable pattern --> $DIR/reachability.rs:83:9 | +LL | _ => {}, + | - matches any value LL | '\u{D7FF}'..='\u{E000}' => {}, - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern error: unreachable pattern --> $DIR/reachability.rs:104:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-12116.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-12116.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-12116.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-12116.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,9 @@ #![feature(box_patterns)] -#![feature(box_syntax)] #![allow(dead_code)] #![allow(unused_variables)] #![deny(unreachable_patterns)] + enum IntList { Cons(isize, Box), Nil @@ -12,9 +12,9 @@ fn tail(source_list: &IntList) -> IntList { match source_list { &IntList::Cons(val, box ref next_list) => tail(next_list), - &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil), -//~^ ERROR unreachable pattern - _ => panic!() + &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)), + //~^ ERROR unreachable pattern + _ => panic!(), } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-12116.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-12116.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-12116.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-12116.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ error: unreachable pattern --> $DIR/issue-12116.rs:15:9 | -LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil), +LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-12116.rs:5:9 + --> $DIR/issue-12116.rs:4:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-3601.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-3601.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-3601.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-3601.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ #![feature(box_patterns)] -#![feature(box_syntax)] struct HTMLImageData { image: Option @@ -23,8 +22,9 @@ fn main() { let mut id = HTMLImageData { image: None }; - let ed = ElementData { kind: box ElementKind::HTMLImageElement(id) }; - let n = NodeData {kind : box NodeKind::Element(ed)}; + let ed = ElementData { kind: Box::new(ElementKind::HTMLImageElement(id)) }; + let n = NodeData { kind: Box::new(NodeKind::Element(ed)) }; + // n.b. span could be better match n.kind { box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-3601.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-3601.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-3601.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-3601.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `Box(_, _)` not covered +error[E0004]: non-exhaustive patterns: `box _` not covered --> $DIR/issue-3601.rs:30:44 | LL | box NodeKind::Element(ed) => match ed.kind { - | ^^^^^^^ pattern `Box(_, _)` not covered + | ^^^^^^^ pattern `box _` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `Box` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,56 @@ +// check-pass + +// From https://github.com/rust-lang/rust/issues/72476 +// and https://github.com/rust-lang/rust/issues/89393 + +trait Trait { + type Projection; +} + +struct A; +impl Trait for A { + type Projection = bool; +} + +struct B; +impl Trait for B { + type Projection = (u32, u32); +} + +struct Next(T::Projection); + +fn foo1(item: Next) { + match item { + Next(true) => {} + Next(false) => {} + } +} + +fn foo2(x: ::Projection) { + match x { + true => {} + false => {} + } +} + +fn foo3(x: Next) { + let Next((_, _)) = x; + match x { + Next((_, _)) => {} + } +} + +fn foo4(x: ::Projection) { + let (_, _) = x; + match x { + (_, _) => {} + } +} + +fn foo5(x: ::Projection) { + match x { + _ => {} + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -// check-pass - -// From https://github.com/rust-lang/rust/issues/72476 - -trait A { - type Projection; -} - -impl A for () { - type Projection = bool; -} - -struct Next(T::Projection); - -fn f(item: Next<()>) { - match item { - Next(true) => {} - Next(false) => {} - } -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +// This used to ICE in exhaustiveness checking. Explanation here: +// https://github.com/rust-lang/rust/issues/82772#issuecomment-905946768 +fn main() { + let Box { 1: _, .. }: Box<()>; //~ ERROR field `1` of + let Box { .. }: Box<()>; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,9 @@ +error[E0451]: field `1` of struct `Box` is private + --> $DIR/issue-82772-match-box-as-struct.rs:4:15 + | +LL | let Box { 1: _, .. }: Box<()>; + | ^^^^ private field + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0451`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/stable-gated-patterns.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/stable-gated-patterns.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/stable-gated-patterns.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/stable-gated-patterns.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +// aux-build:unstable.rs + +extern crate unstable; + +use unstable::Foo; + +fn main() { + match Foo::Stable { + Foo::Stable => {} + } + //~^^^ non-exhaustive patterns: `Stable2` and `_` not covered + + match Foo::Stable { + Foo::Stable => {} + Foo::Stable2 => {} + } + //~^^^^ non-exhaustive patterns: `_` not covered +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +error[E0004]: non-exhaustive patterns: `Stable2` and `_` not covered + --> $DIR/stable-gated-patterns.rs:8:11 + | +LL | match Foo::Stable { + | ^^^^^^^^^^^ patterns `Stable2` and `_` not covered + | + ::: $DIR/auxiliary/unstable.rs:9:5 + | +LL | Stable2, + | ------- not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/stable-gated-patterns.rs:13:11 + | +LL | match Foo::Stable { + | ^^^^^^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,22 @@ +#![feature(unstable_test_feature)] + +// aux-build:unstable.rs + +extern crate unstable; + +use unstable::Foo; + +fn main() { + match Foo::Stable { + Foo::Stable => {} + Foo::Stable2 => {} + } + //~^^^^ non-exhaustive patterns: `Unstable` not covered + + // Ok: all variants are explicitly matched + match Foo::Stable { + Foo::Stable => {} + Foo::Stable2 => {} + Foo::Unstable => {} + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +error[E0004]: non-exhaustive patterns: `Unstable` not covered + --> $DIR/unstable-gated-patterns.rs:10:11 + | +LL | match Foo::Stable { + | ^^^^^^^^^^^ pattern `Unstable` not covered + | + ::: $DIR/auxiliary/unstable.rs:11:5 + | +LL | Unstable, + | -------- not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/phantom-auto-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/phantom-auto-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/phantom-auto-trait.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/phantom-auto-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/phantom-auto-trait.rs:21:12 | LL | is_zen(x) - | ^ `T` cannot be shared between threads safely + | ------ ^ `T` cannot be shared between threads safely + | | + | required by a bound introduced by this call | note: required because of the requirements on the impl of `Zen` for `&T` --> $DIR/phantom-auto-trait.rs:10:24 @@ -29,7 +31,9 @@ --> $DIR/phantom-auto-trait.rs:26:12 | LL | is_zen(x) - | ^ `T` cannot be shared between threads safely + | ------ ^ `T` cannot be shared between threads safely + | | + | required by a bound introduced by this call | note: required because of the requirements on the impl of `Zen` for `&T` --> $DIR/phantom-auto-trait.rs:10:24 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/polymorphization/issue-74614.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/polymorphization/issue-74614.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/polymorphization/issue-74614.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/polymorphization/issue-74614.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,18 @@ +// compile-flags:-Zpolymorphize=on +// build-pass + +fn test() { + std::mem::size_of::(); +} + +pub fn foo(_: T) -> &'static fn() { + &(test:: as fn()) +} + +fn outer() { + foo(|| ()); +} + +fn main() { + outer::(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/polymorphization/predicates.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/polymorphization/predicates.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/polymorphization/predicates.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/polymorphization/predicates.rs 2021-11-29 19:27:11.000000000 +0000 @@ -12,6 +12,7 @@ #[rustc_polymorphize_error] fn foo(_: I) +//~^ ERROR item has unused generic parameters where I: Iterator, { @@ -20,6 +21,7 @@ #[rustc_polymorphize_error] fn baz(_: I) +//~^ ERROR item has unused generic parameters where std::iter::Repeat: Iterator, { @@ -40,6 +42,7 @@ #[rustc_polymorphize_error] fn next(&mut self) -> Option { self.find(|_| true) + //~^ ERROR item has unused generic parameters } } @@ -53,6 +56,7 @@ #[rustc_polymorphize_error] fn quux() -> usize +//~^ ERROR item has unused generic parameters where A: Baz, B: Baz, @@ -69,6 +73,7 @@ #[rustc_polymorphize_error] fn foobar() -> usize +//~^ ERROR item has unused generic parameters where (): Foobar, { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/polymorphization/predicates.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/polymorphization/predicates.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/polymorphization/predicates.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/polymorphization/predicates.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,45 @@ error: item has unused generic parameters + --> $DIR/predicates.rs:14:4 + | +LL | fn foo(_: I) + | ^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/predicates.rs:23:4 + | +LL | fn baz(_: I) + | ^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/predicates.rs:44:19 + | +LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E> + | - - generic parameter `E` is unused + | | + | generic parameter `I` is unused +... +LL | self.find(|_| true) + | ^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/predicates.rs:58:4 + | +LL | fn quux() -> usize + | ^^^^ - - generic parameter `B` is unused + | | + | generic parameter `A` is unused + +error: item has unused generic parameters + --> $DIR/predicates.rs:75:4 + | +LL | fn foobar() -> usize + | ^^^^^^ - generic parameter `F` is unused + +error: item has unused generic parameters --> $DIR/predicates.rs:9:4 | LL | fn bar() { | ^^^ - generic parameter `I` is unused -error: aborting due to previous error +error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pptypedef.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/pptypedef.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pptypedef.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pptypedef.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `i32` to `u32` | LL | let_in(3u32, |i| { assert!(i == 3u32); }); - | ~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/pptypedef.rs:8:37 @@ -18,7 +18,7 @@ help: change the type of the numeric literal from `u32` to `i32` | LL | let_in(3i32, |i| { assert!(i == 3i32); }); - | ~~~~ + | ~~~ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/print_type_sizes/uninhabited.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/print_type_sizes/uninhabited.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/print_type_sizes/uninhabited.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/print_type_sizes/uninhabited.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,5 +11,5 @@ fn start(_: isize, _: *const *const u8) -> isize { let _x: Option = None; let _y: Result = Ok(42); - 0 + let _z: Result = loop {}; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/print_type_sizes/uninhabited.stdout rustc-1.57.0+dfsg1+llvm/src/test/ui/print_type_sizes/uninhabited.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/ui/print_type_sizes/uninhabited.stdout 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/print_type_sizes/uninhabited.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -3,3 +3,4 @@ print-type-size field `.0`: 4 bytes print-type-size type: `std::option::Option`: 0 bytes, alignment: 1 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `std::result::Result`: 0 bytes, alignment: 1 bytes diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-inherent.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-inherent.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-inherent.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-inherent.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^ private type ... LL | priv_nominal::mac!(); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `priv_nominal::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^^ private type ... LL | priv_nominal::mac!(); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `priv_nominal::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -27,7 +27,7 @@ | ^^^^^^ private type ... LL | priv_nominal::mac!(); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `priv_nominal::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -38,7 +38,7 @@ | ^^^^^^^^^^ private associated constant ... LL | priv_nominal::mac!(); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `priv_nominal::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -49,7 +49,7 @@ | ^^^^^^^^^^^ private type ... LL | priv_signature::mac!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `priv_signature::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -60,7 +60,7 @@ | ^^^^^ private type ... LL | priv_signature::mac!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `priv_signature::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -71,7 +71,7 @@ | ^^^^^^ private type ... LL | priv_signature::mac!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `priv_signature::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -82,7 +82,7 @@ | ^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_substs::mac!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -93,7 +93,7 @@ | ^^^^^ private type ... LL | priv_substs::mac!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -104,7 +104,7 @@ | ^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_substs::mac!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -115,7 +115,7 @@ | ^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -126,7 +126,7 @@ | ^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -137,7 +137,7 @@ | ^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -148,7 +148,7 @@ | ^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -159,7 +159,7 @@ | ^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -170,7 +170,7 @@ | ^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -181,7 +181,7 @@ | ^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -192,7 +192,7 @@ | ^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -203,7 +203,7 @@ | ^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -214,7 +214,7 @@ | ^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -225,7 +225,7 @@ | ^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-trait.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_trait::mac!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^^ private type ... LL | priv_trait::mac!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -27,7 +27,7 @@ | ^^^^^^ private type ... LL | priv_trait::mac!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -38,7 +38,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^ private associated constant ... LL | priv_trait::mac!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -49,7 +49,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^ private associated type ... LL | priv_trait::mac!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -60,7 +60,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^ private trait ... LL | priv_trait::mac!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -71,7 +71,7 @@ | ^^^^^^ private trait ... LL | priv_trait::mac!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -82,7 +82,7 @@ | ^^^^^^ private trait ... LL | priv_trait::mac!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -93,7 +93,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_signature::mac!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `priv_signature::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -104,7 +104,7 @@ | ^^^^^ private type ... LL | priv_signature::mac!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `priv_signature::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -115,7 +115,7 @@ | ^^^^^^ private type ... LL | priv_signature::mac!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `priv_signature::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -126,7 +126,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_substs::mac!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -137,7 +137,7 @@ | ^^^^^ private type ... LL | priv_substs::mac!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -148,7 +148,7 @@ | ^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_substs::mac!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -159,7 +159,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -170,7 +170,7 @@ | ^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -181,7 +181,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -192,7 +192,7 @@ | ^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -203,7 +203,7 @@ | ^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -214,7 +214,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -225,7 +225,7 @@ | ^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -236,7 +236,7 @@ | ^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -247,7 +247,7 @@ | ^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -258,7 +258,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -269,7 +269,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -280,7 +280,7 @@ | ^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -291,7 +291,7 @@ | ^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -302,7 +302,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -313,7 +313,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -324,7 +324,7 @@ | ^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-type-binding.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-type-binding.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-type-binding.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/associated-item-privacy-type-binding.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ private trait ... LL | priv_trait::mac1!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_trait::mac1` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private trait ... LL | priv_trait::mac1!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_trait::mac1` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -27,7 +27,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private trait ... LL | priv_trait::mac1!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_trait::mac1` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -38,7 +38,7 @@ | ^^^^^^^^^^^^^^^^^^^ private trait ... LL | priv_trait::mac1!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_trait::mac1` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -49,7 +49,7 @@ | ^ private trait ... LL | priv_trait::mac2!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_trait::mac2` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -60,7 +60,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private trait ... LL | priv_trait::mac2!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_trait::mac2` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -71,7 +71,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private trait ... LL | priv_trait::mac2!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_trait::mac2` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -82,7 +82,7 @@ | ^^^^^^^^^^^^^^^^^^^^ private trait ... LL | priv_trait::mac2!(); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `priv_trait::mac2` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -93,7 +93,7 @@ | ^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -104,7 +104,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -115,7 +115,7 @@ | ^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -126,7 +126,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -137,7 +137,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -148,7 +148,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -159,7 +159,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -170,7 +170,7 @@ | ^^^^^^^^^^^^^^^^^^^ private type ... LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation + | -------------------------- in this macro invocation | = note: this error originates in the macro `priv_parent_substs::mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/issue-79593.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/issue-79593.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/issue-79593.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/issue-79593.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +mod foo { + pub struct Pub { private: () } + + pub enum Enum { + Variant { x: (), y: () }, + Other + } + + fn correct() { + Pub {}; + //~^ ERROR missing field `private` in initializer of `Pub` + Enum::Variant { x: () }; + //~^ ERROR missing field `y` in initializer of `Enum` + } +} + +fn correct() { + foo::Pub {}; + //~^ ERROR cannot construct `Pub` with struct literal syntax due to inaccessible fields +} + +fn wrong() { + foo::Enum::Variant { x: () }; + //~^ ERROR missing field `y` in initializer of `Enum` + foo::Enum::Variant { }; + //~^ ERROR missing fields `x` and `y` in initializer of `Enum` +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/issue-79593.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/issue-79593.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/issue-79593.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/issue-79593.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +error[E0063]: missing field `private` in initializer of `Pub` + --> $DIR/issue-79593.rs:10:9 + | +LL | Pub {}; + | ^^^ missing `private` + +error[E0063]: missing field `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:12:9 + | +LL | Enum::Variant { x: () }; + | ^^^^^^^^^^^^^ missing `y` + +error: cannot construct `Pub` with struct literal syntax due to inaccessible fields + --> $DIR/issue-79593.rs:18:5 + | +LL | foo::Pub {}; + | ^^^^^^^^ + +error[E0063]: missing field `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:23:5 + | +LL | foo::Enum::Variant { x: () }; + | ^^^^^^^^^^^^^^^^^^ missing `y` + +error[E0063]: missing fields `x` and `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:25:5 + | +LL | foo::Enum::Variant { }; + | ^^^^^^^^^^^^^^^^^^ missing `x` and `y` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0063`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/privacy2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/privacy2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/privacy2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/privacy2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -23,7 +23,13 @@ error: requires `sized` lang_item -error: aborting due to 3 previous errors +error: requires `sized` lang_item + +error: requires `sized` lang_item + +error: requires `sized` lang_item + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0432, E0603. For more information about an error, try `rustc --explain E0432`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/privacy3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/privacy3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/privacy3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/privacy3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,6 +6,12 @@ error: requires `sized` lang_item -error: aborting due to 2 previous errors +error: requires `sized` lang_item + +error: requires `sized` lang_item + +error: requires `sized` lang_item + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0432`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/private-inferred-type-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/private-inferred-type-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/private-inferred-type-3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/private-inferred-type-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); - | ^^^^^^^^^^ private type + | ^^^^^^^^^ private type | = note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -10,7 +10,7 @@ --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); - | ^^^^^^^^^^ private static + | ^^^^^^^^^ private static | = note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -18,7 +18,7 @@ --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); - | ^^^^^^^^^^ private type + | ^^^^^^^^^ private type | = note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -26,7 +26,7 @@ --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); - | ^^^^^^^^^^ private type + | ^^^^^^^^^ private type | = note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); - | ^^^^^^^^^^ private type + | ^^^^^^^^^ private type | = note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -42,7 +42,7 @@ --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); - | ^^^^^^^^^^ private type + | ^^^^^^^^^ private type | = note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -50,7 +50,7 @@ --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); - | ^^^^^^^^^^ private type + | ^^^^^^^^^ private type | = note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/private-inferred-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/private-inferred-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/privacy/private-inferred-type.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/privacy/private-inferred-type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -113,7 +113,7 @@ | ^^^^^^^ private type ... LL | m::m!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `m::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -124,7 +124,7 @@ | ^^^^^^^^^^^^^^^^^ private type ... LL | m::m!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `m::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -135,7 +135,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^ private type ... LL | m::m!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `m::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -146,7 +146,7 @@ | ^^^^^^^^^^^^^^^ private type ... LL | m::m!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `m::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -157,7 +157,7 @@ | ^^^^^^^^^^^^^^ private type ... LL | m::m!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `m::m` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -168,7 +168,7 @@ | ^^^^^^^^^^^ private type ... LL | m::m!(); - | -------- in this macro invocation + | ------- in this macro invocation | = note: this error originates in the macro `m::m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/process/process-panic-after-fork.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/process/process-panic-after-fork.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/process/process-panic-after-fork.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/process/process-panic-after-fork.rs 2021-11-29 19:27:11.000000000 +0000 @@ -23,21 +23,6 @@ use libc::c_int; -#[cfg(not(target_os = "linux"))] -fn getpid() -> u32 { - process::id() -} - -/// We need to directly use the getpid syscall instead of using `process::id()` -/// because the libc wrapper might return incorrect values after a process was -/// forked. -#[cfg(target_os = "linux")] -fn getpid() -> u32 { - unsafe { - libc::syscall(libc::SYS_getpid) as _ - } -} - /// This stunt allocator allows us to spot heap allocations in the child. struct PidChecking { parent: A, @@ -59,7 +44,7 @@ fn check(&self) { let require_pid = self.require_pid.load(Ordering::Acquire); if require_pid != 0 { - let actual_pid = getpid(); + let actual_pid = process::id(); if require_pid != actual_pid { unsafe { libc::raise(libc::SIGUSR1); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -// gate-test-macro_attributes_in_derive_output -// aux-build: test-macros.rs - -#![feature(proc_macro_hygiene)] -#![feature(stmt_expr_attributes)] - -#[macro_use] -extern crate test_macros; - -#[derive(Empty)] -#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable -struct S1 { - field: [u8; 10], -} - -#[derive(Empty)] -#[empty_helper] -#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable -struct S2 { - field: [u8; 10], -} - -#[derive(Empty)] -struct S3 { - field: [u8; #[identity_attr] 10], //~ ERROR macro attributes in `#[derive]` output are unstable -} - -#[derive(Empty)] -struct S4 { - field: [u8; { - #[derive(Empty)] // OK, not gated - struct Inner; - 10 - }] -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -error[E0658]: macro attributes in `#[derive]` output are unstable - --> $DIR/attribute-after-derive-feature-gate.rs:11:3 - | -LL | #[empty_attr] - | ^^^^^^^^^^ - | - = note: see issue #81119 for more information - = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable - -error[E0658]: macro attributes in `#[derive]` output are unstable - --> $DIR/attribute-after-derive-feature-gate.rs:18:3 - | -LL | #[empty_attr] - | ^^^^^^^^^^ - | - = note: see issue #81119 for more information - = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable - -error[E0658]: macro attributes in `#[derive]` output are unstable - --> $DIR/attribute-after-derive-feature-gate.rs:25:19 - | -LL | field: [u8; #[identity_attr] 10], - | ^^^^^^^^^^^^^ - | - = note: see issue #81119 for more information - = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ // compile-flags: -Z span-debug // aux-build: test-macros.rs -#![feature(macro_attributes_in_derive_output)] - #![no_std] // Don't load unnecessary hygiene information from std extern crate std; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive.stdout rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive.stdout 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/attribute-after-derive.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -3,35 +3,35 @@ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:17:1: 17:2 (#0), + span: $DIR/attribute-after-derive.rs:15:1: 15:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "derive", - span: $DIR/attribute-after-derive.rs:17:3: 17:9 (#0), + span: $DIR/attribute-after-derive.rs:15:3: 15:9 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "Print", - span: $DIR/attribute-after-derive.rs:17:10: 17:15 (#0), + span: $DIR/attribute-after-derive.rs:15:10: 15:15 (#0), }, ], - span: $DIR/attribute-after-derive.rs:17:9: 17:16 (#0), + span: $DIR/attribute-after-derive.rs:15:9: 15:16 (#0), }, ], - span: $DIR/attribute-after-derive.rs:17:2: 17:17 (#0), + span: $DIR/attribute-after-derive.rs:15:2: 15:17 (#0), }, Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0), + span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0), }, Ident { ident: "AttributeDerive", - span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0), + span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0), }, Group { delimiter: Brace, @@ -39,64 +39,64 @@ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:19:5: 19:6 (#0), + span: $DIR/attribute-after-derive.rs:17:5: 17:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/attribute-after-derive.rs:19:7: 19:10 (#0), + span: $DIR/attribute-after-derive.rs:17:7: 17:10 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/attribute-after-derive.rs:19:11: 19:16 (#0), + span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0), }, ], - span: $DIR/attribute-after-derive.rs:19:10: 19:17 (#0), + span: $DIR/attribute-after-derive.rs:17:10: 17:17 (#0), }, ], - span: $DIR/attribute-after-derive.rs:19:6: 19:18 (#0), + span: $DIR/attribute-after-derive.rs:17:6: 17:18 (#0), }, Ident { ident: "field", - span: $DIR/attribute-after-derive.rs:20:5: 20:10 (#0), + span: $DIR/attribute-after-derive.rs:18:5: 18:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/attribute-after-derive.rs:20:10: 20:11 (#0), + span: $DIR/attribute-after-derive.rs:18:10: 18:11 (#0), }, Ident { ident: "u8", - span: $DIR/attribute-after-derive.rs:20:12: 20:14 (#0), + span: $DIR/attribute-after-derive.rs:18:12: 18:14 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/attribute-after-derive.rs:20:14: 20:15 (#0), + span: $DIR/attribute-after-derive.rs:18:14: 18:15 (#0), }, ], - span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0), + span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0), + span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0), }, Ident { ident: "AttributeDerive", - span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0), + span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0), + span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { } @@ -104,45 +104,89 @@ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:24:1: 24:2 (#0), + span: $DIR/attribute-after-derive.rs:22:1: 22:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_attr", - span: $DIR/attribute-after-derive.rs:24:3: 24:13 (#0), + span: $DIR/attribute-after-derive.rs:22:3: 22:13 (#0), }, ], - span: $DIR/attribute-after-derive.rs:24:2: 24:14 (#0), + span: $DIR/attribute-after-derive.rs:22:2: 22:14 (#0), }, Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0), + span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0), }, Ident { ident: "DeriveAttribute", - span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0), + span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0), + span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { } +PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0), + span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0), }, Ident { ident: "DeriveAttribute", - span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0), + span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0), }, Group { delimiter: Brace, - stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0), + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attribute-after-derive.rs:24:5: 24:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/attribute-after-derive.rs:24:7: 24:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/attribute-after-derive.rs:24:11: 24:16 (#0), + }, + ], + span: $DIR/attribute-after-derive.rs:24:10: 24:17 (#0), + }, + ], + span: $DIR/attribute-after-derive.rs:24:6: 24:18 (#0), + }, + Ident { + ident: "field", + span: $DIR/attribute-after-derive.rs:25:5: 25:10 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/attribute-after-derive.rs:25:10: 25:11 (#0), + }, + Ident { + ident: "u8", + span: $DIR/attribute-after-derive.rs:25:12: 25:14 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/attribute-after-derive.rs:25:14: 25:15 (#0), + }, + ], + span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0), }, ] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/auxiliary/is-available.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/auxiliary/is-available.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/auxiliary/is-available.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/auxiliary/is-available.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,6 @@ // no-prefer-dynamic #![crate_type = "proc-macro"] -#![feature(proc_macro_is_available)] extern crate proc_macro; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/derive-helper-shadowing.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/derive-helper-shadowing.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/derive-helper-shadowing.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/derive-helper-shadowing.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -27,7 +27,7 @@ | ^^^^^^^^^^^^ ... LL | gen_helper_use!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: consider importing this attribute macro: crate::empty_helper diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/generate-mod.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/generate-mod.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/generate-mod.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/generate-mod.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/generate-mod.rs:9:1 | LL | generate_mod::check!(); - | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | = note: consider importing this struct: FromOutside @@ -12,7 +12,7 @@ --> $DIR/generate-mod.rs:9:1 | LL | generate_mod::check!(); - | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | = note: consider importing this struct: Outer @@ -82,3 +82,75 @@ error: aborting due to 4 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0412`. +Future incompatibility report: Future breakage diagnostic: +warning: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:16:10 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `OuterDerive` in this scope + --> $DIR/generate-mod.rs:16:10 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:23:14 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `OuterDerive` in this scope + --> $DIR/generate-mod.rs:23:14 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | +note: the lint level is defined here + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `OuterDeriveLint` in this scope + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,10 @@ --> $DIR/gen-macro-rules-hygiene.rs:12:1 | LL | gen_macro_rules!(); - | ^^^^^^^^^^^^^^^^^^^ undeclared label `'label_use` + | ^^^^^^^^^^^^^^^^^^ undeclared label `'label_use` ... LL | generated!(); - | ------------- in this macro invocation + | ------------ in this macro invocation | = note: this error originates in the macro `generated` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -13,10 +13,10 @@ --> $DIR/gen-macro-rules-hygiene.rs:12:1 | LL | gen_macro_rules!(); - | ^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^ not found in this scope ... LL | generated!(); - | ------------- in this macro invocation + | ------------ in this macro invocation | = note: this error originates in the macro `generated` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ ::: $DIR/group-compat-hack.rs:27:5 | LL | impl_macros!(Foo); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: `#[warn(proc_macro_back_compat)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -24,7 +24,7 @@ ::: $DIR/group-compat-hack.rs:44:5 | LL | impl_macros!(Foo); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 @@ -40,7 +40,7 @@ ::: $DIR/group-compat-hack.rs:46:5 | LL | arrays!(Foo); - | ------------- in this macro invocation + | ------------ in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 @@ -56,7 +56,7 @@ ::: $DIR/group-compat-hack.rs:55:5 | LL | tuple_from_req!(Foo); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 @@ -72,7 +72,7 @@ ::: $DIR/group-compat-hack.rs:63:5 | LL | tuple_from_req!(Foo); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 @@ -91,7 +91,7 @@ ::: $DIR/group-compat-hack.rs:27:5 | LL | impl_macros!(Foo); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: `#[warn(proc_macro_back_compat)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -109,7 +109,7 @@ ::: $DIR/group-compat-hack.rs:44:5 | LL | impl_macros!(Foo); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 @@ -126,7 +126,7 @@ ::: $DIR/group-compat-hack.rs:46:5 | LL | arrays!(Foo); - | ------------- in this macro invocation + | ------------ in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 @@ -143,7 +143,7 @@ ::: $DIR/group-compat-hack.rs:55:5 | LL | tuple_from_req!(Foo); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 @@ -160,7 +160,7 @@ ::: $DIR/group-compat-hack.rs:63:5 | LL | tuple_from_req!(Foo); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/invalid-punct-ident-1.rs:19:1 | LL | invalid_punct!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: message: unsupported character `'`'` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/invalid-punct-ident-2.rs:19:1 | LL | invalid_ident!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: message: `"*"` is not a valid identifier diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/invalid-punct-ident-3.rs:19:1 | LL | invalid_raw_ident!(); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = help: message: `self` cannot be a raw identifier diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-4.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/invalid-punct-ident-4.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/invalid-punct-ident-4.rs:6:1 | LL | lexer_failure!(); - | ^^^^^^^^^^^^^^^^^ unexpected closing delimiter + | ^^^^^^^^^^^^^^^^ unexpected closing delimiter | = note: this error originates in the macro `lexer_failure` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -10,7 +10,7 @@ --> $DIR/invalid-punct-ident-4.rs:6:1 | LL | lexer_failure!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/invalid-punct-ident-4.rs:11:33 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/is-available.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/is-available.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/is-available.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/is-available.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,5 @@ // run-pass -#![feature(proc_macro_is_available)] - extern crate proc_macro; // aux-build:is-available.rs diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/issue-83510.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/issue-83510.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/issue-83510.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/issue-83510.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-83510.rs:5:1 | LL | issue_83510::dance_like_you_want_to_ice!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | = note: this error originates in the macro `issue_83510::dance_like_you_want_to_ice` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -10,7 +10,7 @@ --> $DIR/issue-83510.rs:5:1 | LL | issue_83510::dance_like_you_want_to_ice!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait | = note: this error originates in the macro `issue_83510::dance_like_you_want_to_ice` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -18,7 +18,7 @@ --> $DIR/issue-83510.rs:5:1 | LL | issue_83510::dance_like_you_want_to_ice!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | = note: this error originates in the macro `issue_83510::dance_like_you_want_to_ice` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -26,7 +26,7 @@ --> $DIR/issue-83510.rs:5:1 | LL | issue_83510::dance_like_you_want_to_ice!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #8995 for more information = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.fixed 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// aux-build:test-macros.rs +// run-rustfix + +#[macro_use] +extern crate test_macros; + +/// Inner doc comment +//~^ ERROR expected outer doc comment +#[derive(Empty)] +pub struct Foo; //~ NOTE the inner doc comment doesn't annotate this struct + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,5 @@ // aux-build:test-macros.rs +// run-rustfix #[macro_use] extern crate test_macros; @@ -6,6 +7,6 @@ //! Inner doc comment //~^ ERROR expected outer doc comment #[derive(Empty)] -pub struct Foo; +pub struct Foo; //~ NOTE the inner doc comment doesn't annotate this struct fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/issue-86781-bad-inner-doc.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,16 @@ error[E0753]: expected outer doc comment - --> $DIR/issue-86781-bad-inner-doc.rs:6:1 + --> $DIR/issue-86781-bad-inner-doc.rs:7:1 | LL | //! Inner doc comment | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | pub struct Foo; + | --------------- the inner doc comment doesn't annotate this struct | - = note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items +help: to annotate the struct, change the doc comment from inner to outer style + | +LL | /// Inner doc comment + | ~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/lints_in_proc_macros.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/lints_in_proc_macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/lints_in_proc_macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/lints_in_proc_macros.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/lints_in_proc_macros.rs:9:5 | LL | bang_proc_macro2!(); - | ^^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `foobar` + | ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `foobar` | = note: this error originates in the macro `bang_proc_macro2` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/macro-rules-derive.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/macro-rules-derive.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/macro-rules-derive.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/macro-rules-derive.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^ not found in this scope ... LL | produce_it!(MyName); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `produce_it` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/meta-macro-hygiene.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/meta-macro-hygiene.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/meta-macro-hygiene.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/meta-macro-hygiene.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,6 +4,7 @@ // compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene -Z trim-diagnostic-paths=no // check-pass // normalize-stdout-test "\d+#" -> "0#" +// normalize-stdout-test "expn\d{3,}" -> "expnNNN" // // We don't care about symbol ids, so we set them all to 0 // in the stdout diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/meta-macro-hygiene.stdout rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/meta-macro-hygiene.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/meta-macro-hygiene.stdout 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/meta-macro-hygiene.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) -Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:23:37: 23:43 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#4) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:23:45: 23:50 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:50: 23:51 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:23:51: 23:53 (#4) }] +Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:24:37: 24:43 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:24:45: 24:50 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:50: 24:51 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:24:51: 24:53 (#4) }] Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }] #![feature /* 0#0 */(prelude_import)] // aux-build:make-macro.rs @@ -8,6 +8,7 @@ // compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene -Z trim-diagnostic-paths=no // check-pass // normalize-stdout-test "\d+#" -> "0#" +// normalize-stdout-test "expn\d{3,}" -> "expnNNN" // // We don't care about symbol ids, so we set them all to 0 // in the stdout @@ -48,6 +49,7 @@ crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) SyntaxContexts: diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/mixed-site-span.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/mixed-site-span.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/mixed-site-span.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/mixed-site-span.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/mixed-site-span.rs:13:9 | LL | proc_macro_rules!(); - | ^^^^^^^^^^^^^^^^^^^^ undeclared label `'label_use` + | ^^^^^^^^^^^^^^^^^^^ undeclared label `'label_use` | = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -10,7 +10,7 @@ --> $DIR/mixed-site-span.rs:13:9 | LL | proc_macro_rules!(); - | ^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^^^^^^^^^^^^ not found in this scope | = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ --> $DIR/mixed-site-span.rs:24:1 | LL | pass_dollar_crate!(); - | ^^^^^^^^^^^^^^^^^^^^^ not found in `$crate` + | ^^^^^^^^^^^^^^^^^^^^ not found in `$crate` | = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/multispan.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/multispan.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/multispan.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/multispan.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/multispan.rs:12:5 | LL | hello!(hi); - | ^^^^^^^^^^^ + | ^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:12:12 @@ -15,7 +15,7 @@ --> $DIR/multispan.rs:15:5 | LL | hello!(hi hi); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:15:12 @@ -28,7 +28,7 @@ --> $DIR/multispan.rs:18:5 | LL | hello!(hi hi hi); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:18:12 @@ -41,7 +41,7 @@ --> $DIR/multispan.rs:21:5 | LL | hello!(hi hey hi yo hi beep beep hi hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:21:12 @@ -54,7 +54,7 @@ --> $DIR/multispan.rs:22:5 | LL | hello!(hi there, hi how are you? hi... hi.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:22:12 @@ -67,7 +67,7 @@ --> $DIR/multispan.rs:23:5 | LL | hello!(whoah. hi di hi di ho); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:23:19 @@ -80,7 +80,7 @@ --> $DIR/multispan.rs:24:5 | LL | hello!(hi good hi and good bye); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:24:12 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/nonterminal-token-hygiene.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/nonterminal-token-hygiene.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/nonterminal-token-hygiene.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/nonterminal-token-hygiene.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,6 +4,7 @@ // compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene // compile-flags: -Z trim-diagnostic-paths=no // normalize-stdout-test "\d+#" -> "0#" +// normalize-stdout-test "expn\d{3,}" -> "expnNNN" // aux-build:test-macros.rs #![feature(decl_macro)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout 2021-11-29 19:27:11.000000000 +0000 @@ -6,19 +6,19 @@ stream: TokenStream [ Ident { ident: "struct", - span: $DIR/nonterminal-token-hygiene.rs:30:5: 30:11 (#5), + span: $DIR/nonterminal-token-hygiene.rs:31:5: 31:11 (#5), }, Ident { ident: "S", - span: $DIR/nonterminal-token-hygiene.rs:30:12: 30:13 (#5), + span: $DIR/nonterminal-token-hygiene.rs:31:12: 31:13 (#5), }, Punct { ch: ';', spacing: Alone, - span: $DIR/nonterminal-token-hygiene.rs:30:13: 30:14 (#5), + span: $DIR/nonterminal-token-hygiene.rs:31:13: 31:14 (#5), }, ], - span: $DIR/nonterminal-token-hygiene.rs:20:27: 20:32 (#6), + span: $DIR/nonterminal-token-hygiene.rs:21:27: 21:32 (#6), }, ] #![feature /* 0#0 */(prelude_import)] @@ -29,6 +29,7 @@ // compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene // compile-flags: -Z trim-diagnostic-paths=no // normalize-stdout-test "\d+#" -> "0#" +// normalize-stdout-test "expn\d{3,}" -> "expnNNN" // aux-build:test-macros.rs #![feature /* 0#0 */(decl_macro)] @@ -72,6 +73,7 @@ crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) SyntaxContexts: diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/parent-source-spans.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/parent-source-spans.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/parent-source-spans.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/parent-source-spans.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^ ... LL | one!("hello", "world"); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^ ... LL | one!("hello", "world"); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,10 +24,10 @@ --> $DIR/parent-source-spans.rs:10:5 | LL | two!($a, $b); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ ... LL | one!("hello", "world"); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -35,10 +35,10 @@ --> $DIR/parent-source-spans.rs:10:5 | LL | two!($a, $b); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ ... LL | one!("hello", "world"); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -46,25 +46,25 @@ --> $DIR/parent-source-spans.rs:36:5 | LL | one!("hello", "world"); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: second grandparent: "world" --> $DIR/parent-source-spans.rs:36:5 | LL | one!("hello", "world"); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: first source: "hello" --> $DIR/parent-source-spans.rs:36:5 | LL | one!("hello", "world"); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: second source: "world" --> $DIR/parent-source-spans.rs:36:5 | LL | one!("hello", "world"); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: first final: "yay" --> $DIR/parent-source-spans.rs:16:12 @@ -73,7 +73,7 @@ | ^^ ... LL | two!("yay", "rust"); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -84,7 +84,7 @@ | ^^ ... LL | two!("yay", "rust"); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -92,25 +92,25 @@ --> $DIR/parent-source-spans.rs:42:5 | LL | two!("yay", "rust"); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: second parent: "rust" --> $DIR/parent-source-spans.rs:42:5 | LL | two!("yay", "rust"); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: first source: "yay" --> $DIR/parent-source-spans.rs:42:5 | LL | two!("yay", "rust"); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: second source: "rust" --> $DIR/parent-source-spans.rs:42:5 | LL | two!("yay", "rust"); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: first final: "hip" --> $DIR/parent-source-spans.rs:48:12 @@ -140,10 +140,10 @@ --> $DIR/parent-source-spans.rs:29:5 | LL | parent_source_spans!($($tokens)*); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` ... LL | one!("hello", "world"); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | ::: $SRC_DIR/core/src/result.rs:LL:COL | @@ -156,10 +156,10 @@ --> $DIR/parent-source-spans.rs:29:5 | LL | parent_source_spans!($($tokens)*); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` ... LL | two!("yay", "rust"); - | -------------------- in this macro invocation + | ------------------- in this macro invocation | ::: $SRC_DIR/core/src/result.rs:LL:COL | @@ -172,10 +172,10 @@ --> $DIR/parent-source-spans.rs:29:5 | LL | parent_source_spans!($($tokens)*); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` ... LL | three!("hip", "hop"); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | ::: $SRC_DIR/core/src/result.rs:LL:COL | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/raw-ident.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/raw-ident.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/raw-ident.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/raw-ident.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/raw-ident.rs:15:5 | LL | make_bad_struct!(S); - | ^^^^^^^^^^^^^^^^^^^^ expected one of 8 possible tokens + | ^^^^^^^^^^^^^^^^^^^ expected one of 8 possible tokens | = note: this error originates in the macro `make_bad_struct` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/span-api-tests.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/span-api-tests.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/span-api-tests.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/span-api-tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -41,7 +41,7 @@ reemit!(macro_stringify!(Hello, world!)), "reemit!(macro_stringify!(Hello, world!))" ); - let r = "reemit!(assert_eq!(macro_stringify!(Hello, world!), r));"; + let r = "reemit!(assert_eq!(macro_stringify!(Hello, world!), r))"; reemit!(assert_eq!(macro_stringify!(Hello, world!), r)); assert_eq!(macro_stringify!( diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/span-from-proc-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/span-from-proc-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/span-from-proc-macro.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/span-from-proc-macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -38,7 +38,7 @@ ::: $DIR/span-from-proc-macro.rs:16:5 | LL | other_error_from_bang!(); - | ------------------------- in this macro invocation + | ------------------------ in this macro invocation error[E0308]: mismatched types --> $DIR/auxiliary/span-from-proc-macro.rs:16:36 @@ -54,7 +54,7 @@ ::: $DIR/span-from-proc-macro.rs:15:5 | LL | error_from_bang!(); - | ------------------- in this macro invocation + | ------------------ in this macro invocation error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/span-preservation.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/span-preservation.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/span-preservation.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/span-preservation.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | Some(x) => { return x.try_into().unwrap() }, - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/span-preservation.rs:33:22 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/subspan.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/subspan.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/subspan.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/subspan.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/subspan.rs:11:1 | LL | subspan!("hi"); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:11:11 @@ -15,7 +15,7 @@ --> $DIR/subspan.rs:14:1 | LL | subspan!("hihi"); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:14:11 @@ -28,7 +28,7 @@ --> $DIR/subspan.rs:17:1 | LL | subspan!("hihihi"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:17:11 @@ -41,7 +41,7 @@ --> $DIR/subspan.rs:20:1 | LL | subspan!("why I hide? hi!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:20:17 @@ -54,7 +54,7 @@ --> $DIR/subspan.rs:21:1 | LL | subspan!("hey, hi, hidy, hidy, hi hi"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:21:16 @@ -67,7 +67,7 @@ --> $DIR/subspan.rs:22:1 | LL | subspan!("this is a hi, and this is another hi"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:22:12 @@ -80,7 +80,7 @@ --> $DIR/subspan.rs:23:1 | LL | subspan!("how are you this evening"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:23:24 @@ -93,7 +93,7 @@ --> $DIR/subspan.rs:24:1 | LL | subspan!("this is highly eradic"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: here --> $DIR/subspan.rs:24:12 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/three-equals.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/three-equals.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/three-equals.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/three-equals.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/three-equals.rs:12:5 | LL | three_equals!(==); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = help: input must be: `===` = note: this error originates in the macro `three_equals` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/weird-hygiene.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/weird-hygiene.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/proc-macro/weird-hygiene.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/proc-macro/weird-hygiene.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^ not found in this scope ... LL | other!(50); - | ----------- in this macro invocation + | ---------- in this macro invocation | = note: this error originates in the macro `inner` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,7 +16,7 @@ | ^^^^^^^^^^^^ not found in this scope ... LL | invoke_it!(25); - | --------------- in this macro invocation + | -------------- in this macro invocation | = note: this error originates in the macro `invoke_it` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/pure-sum.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/pure-sum.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/pure-sum.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/pure-sum.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn sums_to(v: Vec , sum: isize) -> bool { let mut i = 0; let mut sum0 = 0; @@ -19,7 +17,7 @@ fn sums_to_using_uniq(v: Vec , sum: isize) -> bool { let mut i = 0; - let mut sum0: Box<_> = box 0; + let mut sum0: Box<_> = 0.into(); while i < v.len() { *sum0 += v[i]; i += 1; @@ -41,7 +39,7 @@ fn sums_to_using_uniq_rec(v: Vec , sum: isize) -> bool { let mut i = 0; - let mut sum0 = F::> {f: box 0}; + let mut sum0 = F::> {f: 0.into() }; while i < v.len() { *sum0.f += v[i]; i += 1; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rcvr-borrowed-to-region.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rcvr-borrowed-to-region.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rcvr-borrowed-to-region.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rcvr-borrowed-to-region.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait get { fn get(self) -> isize; @@ -17,7 +16,7 @@ } pub fn main() { - let x: Box<_> = box 6; + let x: Box<_> = 6.into(); let y = x.get(); println!("y={}", y); assert_eq!(y, 6); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_again.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_again.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_again.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_again.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ -#![feature(box_syntax)] #![allow(unused_variables)] + #![deny(unreachable_code)] fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_again.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_again.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_again.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_again.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | continue; | -------- any code following this expression is unreachable LL | println!("hi"); - | ^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/expr_again.rs:3:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_block.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_block.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_block.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_block.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ LL | return; | ------ any code following this expression is unreachable LL | println!("foo"); - | ^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^ unreachable statement | = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_if.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_if.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_if.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_if.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -22,7 +22,7 @@ | ------ any code following this expression is unreachable ... LL | println!("But I am."); - | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^ unreachable statement | = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_loop.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_loop.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_loop.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_loop.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | loop { return; } | ------ any code following this expression is unreachable LL | println!("I am dead."); - | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/expr_loop.rs:4:9 @@ -19,7 +19,7 @@ LL | loop { return; } | ------ any code following this expression is unreachable LL | println!("I am dead."); - | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -29,7 +29,7 @@ LL | loop { 'middle: loop { loop { break 'middle; } } } | -------------------------------------------------- any code following this expression is unreachable LL | println!("I am dead."); - | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_match.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_match.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/expr_match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/expr_match.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | match () { () => return } | ------------------------- any code following this `match` expression is unreachable, as all arms diverge LL | println!("I am dead"); - | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/expr_match.rs:4:9 @@ -19,7 +19,7 @@ LL | match () { () if false => return, () => return } | ------------------------------------------------ any code following this `match` expression is unreachable, as all arms diverge LL | println!("I am dead"); - | ^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^ unreachable statement | = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/unreachable-arm.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/unreachable-arm.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/unreachable-arm.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/unreachable-arm.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + #![allow(dead_code)] #![deny(unreachable_patterns)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/unreachable-code-ret.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/unreachable-code-ret.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/reachable/unreachable-code-ret.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/reachable/unreachable-code-ret.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | return; | ------ any code following this expression is unreachable LL | println!("Paul is dead"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | ^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here --> $DIR/unreachable-code-ret.rs:3:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ //~ ERROR cycle detected when computing layout of `S` -//~| NOTE ...which requires computing layout of `std::option::Option<::It>`... -//~| NOTE ...which requires computing layout of `std::option::Option`... +//~| NOTE ...which requires computing layout of `core::option::Option<::It>`... +//~| NOTE ...which requires computing layout of `core::option::Option`... //~| NOTE ...which again requires computing layout of `S`, completing the cycle -//~| NOTE cycle used when computing layout of `std::option::Option` +//~| NOTE cycle used when computing layout of `core::option::Option` // build-fail diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,9 @@ error[E0391]: cycle detected when computing layout of `S` | - = note: ...which requires computing layout of `std::option::Option<::It>`... - = note: ...which requires computing layout of `std::option::Option`... + = note: ...which requires computing layout of `core::option::Option<::It>`... + = note: ...which requires computing layout of `core::option::Option`... = note: ...which again requires computing layout of `S`, completing the cycle - = note: cycle used when computing layout of `std::option::Option` + = note: cycle used when computing layout of `core::option::Option` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion/issue-83150.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion/issue-83150.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion/issue-83150.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion/issue-83150.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>: Iterator` | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_83150`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) = note: required because of the requirements on the impl of `Iterator` for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_digit_type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_digit_type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_digit_type.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_digit_type.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,3 @@ +#![recursion_limit = 123] //~ ERROR malformed `recursion_limit` attribute + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_digit_type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_digit_type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_digit_type.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_digit_type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: malformed `recursion_limit` attribute input + --> $DIR/invalid_digit_type.rs:1:1 + | +LL | #![recursion_limit = 123] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_macro.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_macro.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_macro.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_macro.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +#![recursion_limit = foo!()] //~ ERROR malformed `recursion_limit` attribute + +macro_rules! foo { + () => {"128"}; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_macro.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/invalid_macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: malformed `recursion_limit` attribute input + --> $DIR/invalid_macro.rs:1:1 + | +LL | #![recursion_limit = foo!()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/no-value.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/no-value.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/no-value.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/no-value.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,6 @@ +// Test the parse error for no value provided to recursion_limit + +#![recursion_limit] +//~^ ERROR malformed `recursion_limit` attribute input + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/no-value.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/no-value.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/no-value.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/no-value.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,8 @@ +error: malformed `recursion_limit` attribute input + --> $DIR/no-value.rs:3:1 + | +LL | #![recursion_limit] + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/zero-overflow.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/zero-overflow.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/zero-overflow.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/zero-overflow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +//~ ERROR overflow evaluating the requirement `&mut Self: DispatchFromDyn<&mut RustaceansAreAwesome> +//~| HELP consider increasing the recursion limit +// build-fail + +#![recursion_limit = "0"] + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/zero-overflow.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/zero-overflow.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/zero-overflow.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/zero-overflow.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,7 @@ +error[E0275]: overflow evaluating the requirement `&mut Self: DispatchFromDyn<&mut RustaceansAreAwesome>` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`zero_overflow`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/zero.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/zero.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/zero.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/zero.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,6 +7,6 @@ ($tt:tt) => { test!(); }; } -test!(test); //~ ERROR 10:1: 10:13: recursion limit reached while expanding `test!` +test!(test); //~ ERROR recursion limit reached while expanding `test!` fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/zero.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/zero.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/recursion_limit/zero.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/recursion_limit/zero.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,9 +2,9 @@ --> $DIR/zero.rs:10:1 | LL | test!(test); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="0"]` attribute to your crate (`zero`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`zero`) error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-12470.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-12470.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-12470.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-12470.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - trait X { fn get_i(&self) -> isize; } + + struct B { i: isize } @@ -24,7 +24,7 @@ } fn make_make_a<'a>() -> A<'a> { - let b: Box = box B {i:1}; + let b: Box = Box::new(B { i: 1 }); let bb: &B = &*b; make_a(bb) //~ ERROR cannot return value referencing local data `*b` } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-28848.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-28848.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-28848.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-28848.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | Foo::<'a, 'b>::xmute(u) | ^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'b` as defined on the function body at 9:16 +note: lifetime parameter instantiated with the lifetime `'b` as defined here --> $DIR/issue-28848.rs:9:16 | LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () { | ^^ -note: but lifetime parameter must outlive the lifetime `'a` as defined on the function body at 9:12 +note: but lifetime parameter must outlive the lifetime `'a` as defined here --> $DIR/issue-28848.rs:9:12 | LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-78262.default.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-78262.default.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-78262.default.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-78262.default.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected reference `&(dyn TT + 'static)` found reference `&dyn TT` -note: the anonymous lifetime #1 defined on the body at 14:13... +note: the anonymous lifetime #1 defined here... --> $DIR/issue-78262.rs:14:13 | LL | let f = |x: &dyn TT| x.func(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-78262.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-78262.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-78262.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-78262.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,11 @@ --> $DIR/issue-78262.rs:14:26 | LL | let f = |x: &dyn TT| x.func(); - | - ^^^^^^^^ `x` escapes the closure body here - | | + | - - ^^^^^^^^ + | | | | + | | | `x` escapes the closure body here + | | | argument requires that `'1` must outlive `'static` + | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-78262.polonius.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-78262.polonius.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/issue-78262.polonius.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/issue-78262.polonius.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,11 @@ --> $DIR/issue-78262.rs:14:26 | LL | let f = |x: &dyn TT| x.func(); - | - ^^^^^^^^ `x` escapes the closure body here - | | + | - - ^^^^^^^^ + | | | | + | | | `x` escapes the closure body here + | | | argument requires that `'1` must outlive `'static` + | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,12 +10,12 @@ LL | z: Box+'b+'c>, | ^^^^^^^^^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 11:15 +note: lifetime parameter instantiated with the lifetime `'b` as defined here --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15 | LL | struct Foo<'a,'b,'c> { | ^^ -note: but lifetime parameter must outlive the lifetime `'a` as defined on the struct at 11:12 +note: but lifetime parameter must outlive the lifetime `'a` as defined here --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:12 | LL | struct Foo<'a,'b,'c> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,12 +2,15 @@ --> $DIR/region-invariant-static-error-reporting.rs:15:9 | LL | fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | let bad = if x.is_some() { LL | x.unwrap() - | ^^^^^^^^^^ `x` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-invariant-static-error-reporting.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-invariant-static-error-reporting.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-invariant-static-error-reporting.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-invariant-static-error-reporting.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ | = note: expected struct `Invariant<'a>` found struct `Invariant<'static>` -note: the lifetime `'a` as defined on the function body at 13:10... +note: the lifetime `'a` as defined here... --> $DIR/region-invariant-static-error-reporting.rs:13:10 | LL | fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | x.borrowed() | ^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:42... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/region-object-lifetime-2.rs:9:42 | LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { @@ -14,7 +14,7 @@ | LL | x.borrowed() | ^ -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 9:45... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/region-object-lifetime-2.rs:9:45 | LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-4.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-4.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | x.borrowed() | ^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 11:41... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/region-object-lifetime-4.rs:11:41 | LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () { @@ -14,7 +14,7 @@ | LL | x.borrowed() | ^ -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 11:44... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/region-object-lifetime-4.rs:11:44 | LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-5.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-5.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-5.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-5.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,7 @@ // Here, the object is bounded by an anonymous lifetime and returned // as `&'static`, so you get an error. fn owned_receiver(x: Box) -> &'static () { - x.borrowed() //~ ERROR cannot return value referencing local data `*x` + x.borrowed() //~ ERROR cannot return reference to local data `*x` } fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-5.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-5.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-5.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-5.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,8 @@ -error[E0515]: cannot return value referencing local data `*x` +error[E0515]: cannot return reference to local data `*x` --> $DIR/region-object-lifetime-5.rs:11:5 | LL | x.borrowed() - | -^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `*x` is borrowed here + | ^^^^^^^^^^^^ returns a reference to data owned by the current function error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-in-coercion.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-in-coercion.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-in-coercion.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/region-object-lifetime-in-coercion.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -52,7 +52,7 @@ LL | Box::new(v) | ^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:6... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/region-object-lifetime-in-coercion.rs:22:6 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box { @@ -64,12 +64,12 @@ | ^ = note: expected `&[u8]` found `&'a [u8]` -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 22:9... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/region-object-lifetime-in-coercion.rs:22:9 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/region-object-lifetime-in-coercion.rs:23:5 | LL | Box::new(v) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-addr-of-upvar-self.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-addr-of-upvar-self.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-addr-of-upvar-self.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-addr-of-upvar-self.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let p: &'static mut usize = &mut self.food; | ^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 7:18... +note: first, the lifetime cannot outlive the lifetime `'_` as defined here... --> $DIR/regions-addr-of-upvar-self.rs:7:18 | LL | let _f = || { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | let _: &'a WithAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 33:15 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:15 | LL | fn with_assoc<'a,'b>() { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 33:18 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:18 | LL | fn with_assoc<'a,'b>() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,7 +16,7 @@ LL | type Value = &'a i32; | ^^^^^^^^^^^^^^^^^^^^^ | -note: type must outlive the lifetime `'b` as defined on the impl at 19:10 as required by this binding +note: type must outlive the lifetime `'b` as defined here as required by this binding --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:10 | LL | impl<'a, 'b> Foo<'b> for &'a i64 { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-borrow-at.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-borrow-at.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-borrow-at.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-borrow-at.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] fn foo(x: &usize) -> usize { *x } pub fn main() { - let p: Box<_> = box 22; + let p: Box<_> = Box::new(22); let r = foo(&*p); println!("r={}", r); assert_eq!(r, 22); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-borrow-uniq.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-borrow-uniq.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-borrow-uniq.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-borrow-uniq.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] fn foo(x: &usize) -> usize { *x } pub fn main() { - let p: Box<_> = box 3; + let p: Box<_> = Box::new(3); let r = foo(&*p); assert_eq!(r, 3); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | assert_send::<&'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5 @@ -15,8 +13,6 @@ | -- lifetime `'a` defined here LL | assert_send::<&'a str>(); | ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5 @@ -25,8 +21,6 @@ | -- lifetime `'a` defined here LL | assert_send::<&'a [isize]>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5 @@ -35,8 +29,6 @@ | -- lifetime `'a` defined here LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5 @@ -45,8 +37,6 @@ | -- lifetime `'a` defined here LL | assert_send::<*const &'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5 @@ -55,8 +45,6 @@ | -- lifetime `'a` defined here LL | assert_send::<*mut &'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | Foo.some_method::<&'a isize>(); | ^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,12 +2,17 @@ --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5 | LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { - | - - `b` is a reference that is only valid in the function body - | | - | `a` declared here, outside of the function body + | -- -- - - `b` is a reference that is only valid in the function body + | | | | + | | | `a` declared here, outside of the function body + | | lifetime `'b` defined here + | lifetime `'a` defined here LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. LL | f.method(b); - | ^^^^^^^^^^^ `b` escapes the function body here + | ^^^^^^^^^^^ + | | + | `b` escapes the function body here + | argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-bounds.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-bounds.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-bounds.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-bounds.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `TupleStruct<'b>` found struct `TupleStruct<'a>` -note: the lifetime `'a` as defined on the function body at 8:10... +note: the lifetime `'a` as defined here... --> $DIR/regions-bounds.rs:8:10 | LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> { | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the function body at 8:13 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/regions-bounds.rs:8:13 | LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> { @@ -25,12 +25,12 @@ | = note: expected struct `Struct<'b>` found struct `Struct<'a>` -note: the lifetime `'a` as defined on the function body at 12:10... +note: the lifetime `'a` as defined here... --> $DIR/regions-bounds.rs:12:10 | LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> { | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the function body at 12:13 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/regions-bounds.rs:12:13 | LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-associated-type-into-object.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-associated-type-into-object.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-associated-type-into-object.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-associated-type-into-object.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - trait X {} + + trait Iter { type Item: X; @@ -18,7 +18,7 @@ fn bad2(v: T) -> Box where Box : X { - let item: Box<_> = box v.into_item(); + let item: Box<_> = Box::new(v.into_item()); Box::new(item) //~ ERROR associated type `::Item` may not live long enough } @@ -31,7 +31,7 @@ fn bad4<'a, T: Iter>(v: T) -> Box where Box : X { - let item: Box<_> = box v.into_item(); + let item: Box<_> = Box::new(v.into_item()); Box::new(item) //~ ERROR associated type `::Item` may not live long enough } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-1.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ -#![feature(box_syntax)] #![allow(warnings)] trait A { } + struct B<'a, T:'a>(&'a (A+'a)); trait X { } @@ -9,7 +9,7 @@ impl<'a, T> X for B<'a, T> {} fn f<'a, T:'static, U>(v: Box+'static>) -> Box { - box B(&*v) as Box //~ ERROR cannot return value referencing local data `*v` + Box::new(B(&*v)) as Box //~ ERROR cannot return value referencing local data `*v` } fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ error[E0515]: cannot return value referencing local data `*v` --> $DIR/regions-close-object-into-object-1.rs:12:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,20 +1,18 @@ error: lifetime may not live long enough - --> $DIR/regions-close-object-into-object-2.rs:10:5 + --> $DIR/regions-close-object-into-object-2.rs:9:5 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | -- lifetime `'a` defined here -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error[E0515]: cannot return value referencing local data `*v` - --> $DIR/regions-close-object-into-object-2.rs:10:5 + --> $DIR/regions-close-object-into-object-2.rs:9:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,12 @@ -#![feature(box_syntax)] - trait A { } + struct B<'a, T:'a>(&'a (dyn A + 'a)); trait X { } impl<'a, T> X for B<'a, T> {} fn g<'a, T: 'static>(v: Box + 'a>) -> Box { - box B(&*v) as Box //~ ERROR E0759 + Box::new(B(&*v)) as Box //~ ERROR E0759 } fn main() { } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/regions-close-object-into-object-2.rs:10:11 + --> $DIR/regions-close-object-into-object-2.rs:9:16 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... -LL | box B(&*v) as Box - | ^^^ ...is captured here, requiring it to live as long as `'static` +LL | Box::new(B(&*v)) as Box + | ^^^ ...is captured here, requiring it to live as long as `'static` | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-3.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-3.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,14 +1,14 @@ -#![feature(box_syntax)] #![allow(warnings)] trait A { } + struct B<'a, T:'a>(&'a (A+'a)); trait X { } impl<'a, T> X for B<'a, T> {} fn h<'a, T, U:'static>(v: Box+'static>) -> Box { - box B(&*v) as Box //~ ERROR cannot return value referencing local data `*v` + Box::new(B(&*v)) as Box //~ ERROR cannot return value referencing local data `*v` } fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ error[E0515]: cannot return value referencing local data `*v` --> $DIR/regions-close-object-into-object-3.rs:11:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,39 +1,53 @@ error[E0310]: the parameter type `U` may not live long enough - --> $DIR/regions-close-object-into-object-4.rs:10:5 + --> $DIR/regions-close-object-into-object-4.rs:9:5 | -LL | box B(&*v) as Box - | ^^^^^^^^^^ +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `U: 'static`... + +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `U: 'static`... + +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `U: 'static`... error: lifetime may not live long enough - --> $DIR/regions-close-object-into-object-4.rs:10:5 + --> $DIR/regions-close-object-into-object-4.rs:9:5 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | -- lifetime `'a` defined here -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error[E0515]: cannot return value referencing local data `*v` - --> $DIR/regions-close-object-into-object-4.rs:10:5 + --> $DIR/regions-close-object-into-object-4.rs:9:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error[E0310]: the parameter type `U` may not live long enough - --> $DIR/regions-close-object-into-object-4.rs:10:9 + --> $DIR/regions-close-object-into-object-4.rs:9:14 | -LL | box B(&*v) as Box - | ^^^^^^ +LL | Box::new(B(&*v)) as Box + | ^^^^^^ | = help: consider adding an explicit lifetime bound `U: 'static`... -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0310, E0515. For more information about an error, try `rustc --explain E0310`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,13 +1,12 @@ -#![feature(box_syntax)] - trait A { } + struct B<'a, T:'a>(&'a (dyn A + 'a)); trait X { } impl<'a, T> X for B<'a, T> {} fn i<'a, T, U>(v: Box+'a>) -> Box { - box B(&*v) as Box //~ ERROR E0759 + Box::new(B(&*v)) as Box //~ ERROR E0759 } fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-4.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/regions-close-object-into-object-4.rs:10:11 + --> $DIR/regions-close-object-into-object-4.rs:9:16 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... -LL | box B(&*v) as Box - | ^^^ ...is captured here, requiring it to live as long as `'static` +LL | Box::new(B(&*v)) as Box + | ^^^ ...is captured here, requiring it to live as long as `'static` | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,29 +1,45 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:5 | -LL | box B(&*v) as Box - | ^^^^^^^^^^ +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... error[E0515]: cannot return value referencing local data `*v` --> $DIR/regions-close-object-into-object-5.rs:17:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:9 + --> $DIR/regions-close-object-into-object-5.rs:17:14 | -LL | box B(&*v) as Box - | ^^^^^^ +LL | Box::new(B(&*v)) as Box + | ^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0310, E0515. For more information about an error, try `rustc --explain E0310`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ -#![feature(box_syntax)] #![allow(warnings)] + trait A { fn get(&self) -> T { panic!() } @@ -14,11 +14,12 @@ fn f<'a, T, U>(v: Box + 'static>) -> Box { // oh dear! - box B(&*v) as Box + Box::new(B(&*v)) as Box //~^ ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-object-into-object-5.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,26 +4,41 @@ LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... + | +note: ...that is required by this bound + --> $DIR/regions-close-object-into-object-5.rs:9:17 + | +LL | struct B<'a, T: 'a>(&'a (A + 'a)); + | ^^ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { + | - help: consider adding an explicit lifetime bound...: `T: 'static` +LL | // oh dear! +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:9 + --> $DIR/regions-close-object-into-object-5.rs:17:14 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^ ...so that the type `T` will meet its required lifetime bounds +LL | Box::new(B(&*v)) as Box + | ^ ...so that the type `T` will meet its required lifetime bounds error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:9 + --> $DIR/regions-close-object-into-object-5.rs:17:14 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds... +LL | Box::new(B(&*v)) as Box + | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds... | note: ...that is required by this bound --> $DIR/regions-close-object-into-object-5.rs:9:17 @@ -32,32 +47,32 @@ | ^^ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:11 + --> $DIR/regions-close-object-into-object-5.rs:17:16 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^ ...so that the reference type `&dyn A` does not outlive the data it points at +LL | Box::new(B(&*v)) as Box + | ^^^ ...so that the reference type `&dyn A` does not outlive the data it points at error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:11 + --> $DIR/regions-close-object-into-object-5.rs:17:16 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long +LL | Box::new(B(&*v)) as Box + | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:11 + --> $DIR/regions-close-object-into-object-5.rs:17:16 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long +LL | Box::new(B(&*v)) as Box + | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0310`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,16 +1,16 @@ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:12:5 | -LL | box v as Box - | ^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `A: 'static`... error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:21:5 | -LL | box v as Box - | ^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `A: 'b`... diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,24 +1,24 @@ -#![feature(box_syntax)] - // Test for what happens when a type parameter `A` is closed over into // an object. This should yield errors unless `A` (and the object) // both have suitable bounds. + trait SomeTrait { fn get(&self) -> isize; } + fn make_object1(v: A) -> Box { - box v as Box + Box::new(v) as Box //~^ ERROR the parameter type `A` may not live long enough } fn make_object2<'a, A: SomeTrait + 'a>(v: A) -> Box { - box v as Box + Box::new(v) as Box } fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { - box v as Box + Box::new(v) as Box //~^ ERROR the parameter type `A` may not live long enough } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -3,16 +3,16 @@ | LL | fn make_object1(v: A) -> Box { | -- help: consider adding an explicit lifetime bound...: `A: 'static +` -LL | box v as Box - | ^^^^^ ...so that the type `A` will meet its required lifetime bounds +LL | Box::new(v) as Box + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:21:5 | LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { | -- help: consider adding an explicit lifetime bound...: `A: 'b +` -LL | box v as Box - | ^^^^^ ...so that the type `A` will meet its required lifetime bounds +LL | Box::new(v) as Box + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,8 @@ | | | lifetime `'a` defined here LL | // A outlives 'a AND 'b...but not 'c. -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c` +LL | Box::new(v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c` | = help: consider adding the following bound: `'a: 'c` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,23 +1,23 @@ -#![feature(box_syntax)] - // Various tests where we over type parameters with multiple lifetime // bounds. + trait SomeTrait { fn get(&self) -> isize; } + fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b... - box v as Box // ...hence this type is safe. + Box::new(v) as Box // ...hence this type is safe. } fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b... - box v as Box // ...hence this type is safe. + Box::new(v) as Box // ...hence this type is safe. } fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR cannot infer an appropriate lifetime + Box::new(v) as Box //~ ERROR cannot infer an appropriate lifetime } fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5 | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 18:20... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/regions-close-over-type-parameter-multiple.rs:18:20 | LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { @@ -12,18 +12,18 @@ note: ...so that the declared lifetime parameter bounds are satisfied --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5 | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: but, the lifetime must be valid for the lifetime `'c` as defined on the function body at 18:26... +LL | Box::new(v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: but, the lifetime must be valid for the lifetime `'c` as defined here... --> $DIR/regions-close-over-type-parameter-multiple.rs:18:26 | LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5 | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected `Box<(dyn SomeTrait + 'c)>` found `Box` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,6 @@ // A test where we (successfully) close over a reference into // an object. -#![feature(box_syntax)] - trait SomeTrait { fn get(&self) -> isize; } impl<'a> SomeTrait for &'a isize { @@ -13,7 +11,7 @@ } fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box { - box v as Box + Box::new(v) as Box } fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-creating-enums4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-creating-enums4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-creating-enums4.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-creating-enums4.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | Ast::Add(x, y) | ^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 6:16... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/regions-creating-enums4.rs:6:16 | LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> { @@ -16,12 +16,12 @@ | ^ = note: expected `&Ast<'_>` found `&Ast<'a>` -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/regions-creating-enums4.rs:6:19 | LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/regions-creating-enums4.rs:7:5 | LL | Ast::Add(x, y) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-dependent-addr-of.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-dependent-addr-of.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-dependent-addr-of.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-dependent-addr-of.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,6 @@ // Issue #3148. #![feature(box_patterns)] -#![feature(box_syntax)] struct A { value: B @@ -81,7 +80,7 @@ v2: [23, 24, 25], v3: vec![26, 27, 28], v4: C { f: 29 }, - v5: box C { f: 30 }, + v5: Box::new(C { f: 30 }), v6: Some(C { f: 31 })}}; let p = get_v1(&a); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-error-method.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-error-method.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-error-method.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-error-method.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | g2.get() | ^^^^^^^^ | -note: ...the reference is valid for the lifetime `'a` as defined on the impl at 18:6... +note: ...the reference is valid for the lifetime `'a` as defined here... --> $DIR/regions-early-bound-error-method.rs:18:6 | LL | impl<'a> Box<'a> { | ^^ -note: ...but the borrowed content is only valid for the lifetime `'b` as defined on the method body at 19:11 +note: ...but the borrowed content is only valid for the lifetime `'b` as defined here --> $DIR/regions-early-bound-error-method.rs:19:11 | LL | fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-error.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-error.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | g1.get() | ^^^^^^^^ | -note: ...the reference is valid for the lifetime `'b` as defined on the function body at 18:11... +note: ...the reference is valid for the lifetime `'b` as defined here... --> $DIR/regions-early-bound-error.rs:18:11 | LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize { | ^^ -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 18:8 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/regions-early-bound-error.rs:18:8 | LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-trait-param.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-trait-param.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-trait-param.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-early-bound-trait-param.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,8 +2,6 @@ // Tests that you can use an early-bound lifetime parameter as // on of the generic parameters in a trait. -#![feature(box_syntax)] - trait Trait<'a> { fn long(&'a self) -> isize; fn short<'b>(&'b self) -> isize; @@ -72,7 +70,7 @@ impl<'t> MakerTrait for Box+'static> { fn mk() -> Box+'static> { - let tup: Box<(isize, isize)> = box (4,5); + let tup: Box<(isize, isize)> = Box::new((4,5)); tup as Box } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-escape-into-other-fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-escape-into-other-fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-escape-into-other-fn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-escape-into-other-fn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,8 @@ // run-pass -#![feature(box_syntax)] - fn foo(x: &usize) -> &usize { x } fn bar(x: &usize) -> usize { *x } pub fn main() { - let p: Box<_> = box 3; + let p: Box<_> = Box::new(3); assert_eq!(bar(foo(&*p)), 3); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) { | ^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 5:14 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-free-region-ordering-callee-4.rs:5:14 | LL | fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 5:18 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-free-region-ordering-callee-4.rs:5:18 | LL | fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | let z: Option<&'b &'a usize> = None; | ^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'b` as defined on the function body at 10:14 +note: the pointer is valid for the lifetime `'b` as defined here --> $DIR/regions-free-region-ordering-caller.rs:10:14 | LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ -note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 10:10 +note: but the referenced data is only valid for the lifetime `'a` as defined here --> $DIR/regions-free-region-ordering-caller.rs:10:10 | LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { @@ -21,12 +21,12 @@ LL | let z: Option<&'b Paramd<'a>> = None; | ^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'b` as defined on the function body at 15:14 +note: the pointer is valid for the lifetime `'b` as defined here --> $DIR/regions-free-region-ordering-caller.rs:15:14 | LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ -note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 15:10 +note: but the referenced data is only valid for the lifetime `'a` as defined here --> $DIR/regions-free-region-ordering-caller.rs:15:10 | LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { @@ -38,12 +38,12 @@ LL | let z: Option<&'a &'b usize> = None; | ^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 21:10 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-free-region-ordering-caller.rs:21:10 | LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 21:14 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-free-region-ordering-caller.rs:21:14 | LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | None => &self.val | ^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the method body at 14:12... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/regions-free-region-ordering-incorrect.rs:14:12 | LL | fn get<'a>(&'a self) -> &'b T { @@ -14,7 +14,7 @@ | LL | None => &self.val | ^^^^^^^^^ -note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 13:6... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/regions-free-region-ordering-incorrect.rs:13:6 | LL | impl<'b, T> Node<'b, T> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-borrow-scope.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-borrow-scope.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-borrow-scope.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-borrow-scope.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct Point {x: isize, y: isize} @@ -9,7 +8,7 @@ } pub fn main() { - let p: Box<_> = box Point {x: 3, y: 4}; + let p: Box<_> = Box::new(Point {x: 3, y: 4}); let xc = x_coord(&*p); assert_eq!(*xc, 3); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] fn borrow(x: &T) -> &T {x} pub fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); loop { let y = borrow(&*x); assert_eq!(*x, *y); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` - | - = help: consider replacing `'r` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected struct `Invariant<'static>` found struct `Invariant<'r>` -note: the lifetime `'r` as defined on the function body at 11:23... +note: the lifetime `'r` as defined here... --> $DIR/regions-infer-invariance-due-to-decl.rs:11:23 | LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` - | - = help: consider replacing `'r` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected struct `Invariant<'static>` found struct `Invariant<'r>` -note: the lifetime `'r` as defined on the function body at 9:23... +note: the lifetime `'r` as defined here... --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:9:23 | LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` - | - = help: consider replacing `'r` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected struct `Invariant<'static>` found struct `Invariant<'r>` -note: the lifetime `'r` as defined on the function body at 9:23... +note: the lifetime `'r` as defined here... --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:9:23 | LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-not-param.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-not-param.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-not-param.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-not-param.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `Direct<'b>` found struct `Direct<'a>` -note: the lifetime `'a` as defined on the function body at 15:16... +note: the lifetime `'a` as defined here... --> $DIR/regions-infer-not-param.rs:15:16 | LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the function body at 15:19 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/regions-infer-not-param.rs:15:19 | LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } @@ -25,12 +25,12 @@ | = note: expected struct `Indirect2<'b>` found struct `Indirect2<'a>` -note: the lifetime `'a` as defined on the function body at 19:19... +note: the lifetime `'a` as defined here... --> $DIR/regions-infer-not-param.rs:19:19 | LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the function body at 19:22 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/regions-infer-not-param.rs:19:22 | LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } @@ -44,12 +44,12 @@ | = note: expected struct `Indirect2<'b>` found struct `Indirect2<'a>` -note: the lifetime `'b` as defined on the function body at 19:22... +note: the lifetime `'b` as defined here... --> $DIR/regions-infer-not-param.rs:19:22 | LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | ^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the function body at 19:19 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/regions-infer-not-param.rs:19:19 | LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-paramd-indirect.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-paramd-indirect.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-infer-paramd-indirect.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-infer-paramd-indirect.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `Box>` found struct `Box>` -note: the anonymous lifetime defined on the method body at 21:36... +note: the anonymous lifetime defined here... --> $DIR/regions-infer-paramd-indirect.rs:21:36 | LL | fn set_f_bad(&mut self, b: Box) { | ^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 16:6 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/regions-infer-paramd-indirect.rs:16:6 | LL | impl<'a> SetF<'a> for C<'a> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,19 +15,17 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { fn explicit() { fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} - test(Some(box |_f: Box FnMut(&'a isize)>| {})); + test(Some(Box::new(|_f: Box FnMut(&'a isize)>| {}))); } // The code below is shorthand for the code above (and more likely // to represent what one encounters in practice). fn implicit() { fn test(_x: Option>) where F: FnMut(Box) {} - test(Some(box |_f: Box| {})); + test(Some(Box::new(|_f: Box| {}))); } explicit(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-nested-fns.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-nested-fns.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-nested-fns.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-nested-fns.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -45,8 +45,6 @@ ... LL | if false { return x; } | ^ returning this value requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-nested-fns.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-nested-fns.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-nested-fns.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-nested-fns.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | let mut ay = &y; | ^^ | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 7:58... +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here... --> $DIR/regions-nested-fns.rs:7:58 | LL | ignore:: FnMut(&'z isize)>>(Box::new(|z| { @@ -19,7 +19,7 @@ | LL | ay = z; | ^ -note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the body at 13:72... +note: but, the lifetime must be valid for the anonymous lifetime #1 defined here... --> $DIR/regions-nested-fns.rs:13:72 | LL | ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { @@ -48,7 +48,7 @@ LL | if false { return x; } | ^ | -note: ...the reference is valid for the anonymous lifetime #1 defined on the body at 13:72... +note: ...the reference is valid for the anonymous lifetime #1 defined here... --> $DIR/regions-nested-fns.rs:13:72 | LL | ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { @@ -58,7 +58,7 @@ LL | | return z; LL | | })); | |_____^ -note: ...but the borrowed content is only valid for the lifetime `'x` as defined on the function body at 3:11 +note: ...but the borrowed content is only valid for the lifetime `'x` as defined here --> $DIR/regions-nested-fns.rs:3:11 | LL | fn nested<'x>(x: &'x isize) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,12 +8,12 @@ LL | | <() as Project<'a, 'b>>::Item: Eq, | |______________________________________^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 24:8... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 | LL | fn bar<'a, 'b>() | ^^ -note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 24:12... +note: ...but the lifetime must also be valid for the lifetime `'b` as defined here... --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 | LL | fn bar<'a, 'b>() @@ -36,12 +36,12 @@ LL | fn bar<'a, 'b>() | ^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 24:8... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 | LL | fn bar<'a, 'b>() | ^^ -note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 24:12... +note: ...but the lifetime must also be valid for the lifetime `'b` as defined here... --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 | LL | fn bar<'a, 'b>() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | let _: &'a WithHrAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 27:15 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-projection-container-hrtb.rs:27:15 | LL | fn with_assoc<'a,'b>() { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 27:18 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-projection-container-hrtb.rs:27:18 | LL | fn with_assoc<'a,'b>() { @@ -21,12 +21,12 @@ LL | let _: &'a WithHrAssocSub> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 46:19 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-projection-container-hrtb.rs:46:19 | LL | fn with_assoc_sub<'a,'b>() { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 46:22 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-projection-container-hrtb.rs:46:22 | LL | fn with_assoc_sub<'a,'b>() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | let _x: &'a WithAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 28:15 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-projection-container.rs:28:15 | LL | fn with_assoc<'a,'b>() { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 28:18 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-projection-container.rs:28:18 | LL | fn with_assoc<'a,'b>() { @@ -21,12 +21,12 @@ LL | let _x: &'a WithoutAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 50:18 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-projection-container.rs:50:18 | LL | fn without_assoc<'a,'b>() { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 50:21 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-projection-container.rs:50:21 | LL | fn without_assoc<'a,'b>() { @@ -38,12 +38,12 @@ LL | call::<&'a WithAssoc>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 58:20 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-projection-container.rs:58:20 | LL | fn call_with_assoc<'a,'b>() { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 58:23 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-projection-container.rs:58:23 | LL | fn call_with_assoc<'a,'b>() { @@ -55,12 +55,12 @@ LL | call::<&'a WithoutAssoc>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 67:23 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-projection-container.rs:67:23 | LL | fn call_without_assoc<'a,'b>() { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 67:26 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-projection-container.rs:67:26 | LL | fn call_without_assoc<'a,'b>() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | let _: &'a WithAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the function body at 27:15 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-projection-container-wc.rs:27:15 | LL | fn with_assoc<'a,'b>() { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 27:18 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-projection-container-wc.rs:27:18 | LL | fn with_assoc<'a,'b>() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-ref-in-fn-arg.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-ref-in-fn-arg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-ref-in-fn-arg.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-ref-in-fn-arg.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + fn arg_item(box ref x: Box) -> &'static isize { x //~ ERROR cannot return value referencing function parameter } -fn with(f: F) -> R where F: FnOnce(Box) -> R { f(box 3) } +fn with(f: F) -> R where F: FnOnce(Box) -> R { f(Box::new(3)) } fn arg_closure() -> &'static isize { with(|box ref x| x) //~ ERROR cannot return value referencing function parameter diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,8 +9,6 @@ // changes were caught. However, those uses in the compiler could // easily get changed or refactored away in the future. -#![feature(box_syntax)] - struct Ctxt<'tcx> { x: &'tcx Vec } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-ret-borrowed-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-ret-borrowed-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-ret-borrowed-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-ret-borrowed-1.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,19 +4,19 @@ LL | with(|o| o) | ^ | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 10:10... +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here... --> $DIR/regions-ret-borrowed-1.rs:10:10 | LL | with(|o| o) | ^^^^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/regions-ret-borrowed-1.rs:10:14 | LL | with(|o| o) | ^ = note: expected `&isize` found `&isize` -note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/regions-ret-borrowed-1.rs:9:14 | LL | fn return_it<'a>() -> &'a isize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-ret-borrowed.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-ret-borrowed.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-ret-borrowed.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-ret-borrowed.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,19 +4,19 @@ LL | with(|o| o) | ^ | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 13:10... +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here... --> $DIR/regions-ret-borrowed.rs:13:10 | LL | with(|o| o) | ^^^^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/regions-ret-borrowed.rs:13:14 | LL | with(|o| o) | ^ = note: expected `&isize` found `&isize` -note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/regions-ret-borrowed.rs:12:14 | LL | fn return_it<'a>() -> &'a isize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.migrate.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.migrate.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.migrate.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.migrate.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | t | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error[E0621]: explicit lifetime required in the type of `u` --> $DIR/regions-static-bound.rs:14:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.migrate.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.migrate.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.migrate.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.migrate.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ | = note: ...the reference is valid for the static lifetime... -note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 8:24 +note: ...but the borrowed content is only valid for the lifetime `'a` as defined here --> $DIR/regions-static-bound.rs:8:24 | LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-static-bound.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | t | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error[E0621]: explicit lifetime required in the type of `u` --> $DIR/regions-static-bound.rs:14:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-trait-object-subtyping.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-trait-object-subtyping.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-trait-object-subtyping.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-trait-object-subtyping.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | x | ^ | -note: lifetime parameter instantiated with the lifetime `'a` as defined on the function body at 13:9 +note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/regions-trait-object-subtyping.rs:13:9 | LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { | ^^ -note: but lifetime parameter must outlive the lifetime `'b` as defined on the function body at 13:12 +note: but lifetime parameter must outlive the lifetime `'b` as defined here --> $DIR/regions-trait-object-subtyping.rs:13:12 | LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { @@ -21,7 +21,7 @@ LL | x | ^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 13:9... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/regions-trait-object-subtyping.rs:13:9 | LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { @@ -31,12 +31,12 @@ | LL | x | ^ -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 13:12... +note: but, the lifetime must be valid for the lifetime `'b` as defined here... --> $DIR/regions-trait-object-subtyping.rs:13:12 | LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { | ^^ -note: ...so that the expression is assignable +note: ...so that the types are compatible --> $DIR/regions-trait-object-subtyping.rs:15:5 | LL | x @@ -52,12 +52,12 @@ | = note: expected struct `Wrapper<&'b mut (dyn Dummy + 'b)>` found struct `Wrapper<&'a mut (dyn Dummy + 'a)>` -note: the lifetime `'b` as defined on the function body at 20:15... +note: the lifetime `'b` as defined here... --> $DIR/regions-trait-object-subtyping.rs:20:15 | LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> { | ^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the function body at 20:9 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/regions-trait-object-subtyping.rs:20:9 | LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-trait-variance.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-trait-variance.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-trait-variance.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-trait-variance.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - // Issue #12470. trait X { @@ -31,9 +29,11 @@ } fn make_make_a<'a>() -> A<'a> { - let b: Box = box B { + + let b: Box = Box::new(B { i: 1, - }; + }); + let bb: &B = &*b; make_a(bb) //~ ERROR cannot return value referencing local data `*b` } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ ... LL | let _: Invariant<'static> = c; | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'static` - | - = help: consider replacing `'b` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected struct `Invariant<'static>` found struct `Invariant<'b>` -note: the lifetime `'b` as defined on the function body at 11:9... +note: the lifetime `'b` as defined here... --> $DIR/regions-variance-invariant-use-covariant.rs:11:9 | LL | fn use_<'b>(c: Invariant<'b>) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-var-type-out-of-scope.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-var-type-out-of-scope.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-var-type-out-of-scope.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-var-type-out-of-scope.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ | | | creates a temporary which is freed while still in use LL | assert_eq!(*x, 3); - | ------------------ borrow later used here + | ----------------- borrow later used here | = note: consider using a `let` binding to create a longer lived value diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-wf-trait-object.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-wf-trait-object.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/regions/regions-wf-trait-object.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/regions/regions-wf-trait-object.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | x: Box+'b> | ^^^^^^^^^^^^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 6:15 +note: lifetime parameter instantiated with the lifetime `'b` as defined here --> $DIR/regions-wf-trait-object.rs:6:15 | LL | struct Foo<'a,'b> { | ^^ -note: but lifetime parameter must outlive the lifetime `'a` as defined on the struct at 6:12 +note: but lifetime parameter must outlive the lifetime `'a` as defined here --> $DIR/regions-wf-trait-object.rs:6:12 | LL | struct Foo<'a,'b> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/repeat_count.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/repeat_count.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/repeat_count.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/repeat_count.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -55,7 +55,7 @@ help: change the type of the numeric literal from `u8` to `usize` | LL | let f = [0; 4usize]; - | ~~~~~~ + | ~~~~~ error[E0308]: mismatched types --> $DIR/repeat_count.rs:31:17 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/repr/repr-transparent-issue-87496.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/repr/repr-transparent-issue-87496.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/repr/repr-transparent-issue-87496.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/repr/repr-transparent-issue-87496.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// Regression test for the ICE described in #87496. + +// check-pass + +#[repr(transparent)] +struct TransparentCustomZst(()); +extern "C" { + fn good17(p: TransparentCustomZst); + //~^ WARNING: `extern` block uses type `TransparentCustomZst`, which is not FFI-safe +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/repr/repr-transparent-issue-87496.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/repr/repr-transparent-issue-87496.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/repr/repr-transparent-issue-87496.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/repr/repr-transparent-issue-87496.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +warning: `extern` block uses type `TransparentCustomZst`, which is not FFI-safe + --> $DIR/repr-transparent-issue-87496.rs:8:18 + | +LL | fn good17(p: TransparentCustomZst); + | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: `#[warn(improper_ctypes)]` on by default + = note: this struct contains only zero-sized fields +note: the type is defined here + --> $DIR/repr-transparent-issue-87496.rs:6:1 + | +LL | struct TransparentCustomZst(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-42944.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-42944.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-42944.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-42944.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +mod foo { + pub struct Bx(()); +} + +mod bar { + use foo::Bx; + + fn foo() { + Bx(()); + //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] + } +} + +mod baz { + fn foo() { + Bx(()); + //~^ ERROR cannot find function, tuple struct or tuple variant `Bx` in this scope [E0425] + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-42944.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-42944.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-42944.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-42944.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,28 @@ +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/issue-42944.rs:9:9 + | +LL | Bx(()); + | ^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-42944.rs:2:19 + | +LL | pub struct Bx(()); + | ^^ private field + +error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope + --> $DIR/issue-42944.rs:16:9 + | +LL | Bx(()); + | ^^ not found in this scope + | +note: tuple struct `foo::Bx` exists but is inaccessible + --> $DIR/issue-42944.rs:2:5 + | +LL | pub struct Bx(()); + | ^^^^^^^^^^^^^^^^^^ not accessible + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0423, E0425. +For more information about an error, try `rustc --explain E0423`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-82865.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-82865.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-82865.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-82865.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ | ^ function or associated item not found in `Box<_, _>` ... LL | mac!(); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-85671.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-85671.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-85671.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-85671.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,37 @@ +// check-pass + +// Some trait with a function that returns a slice: +pub trait AsSlice { + type Element; + fn as_slice(&self) -> &[Self::Element]; +} + +// Some type +pub struct A(Cont); + +// Here we say that if A wraps a slice, then it implements AsSlice +impl<'a, Element> AsSlice for A<&'a [Element]> { + type Element = Element; + fn as_slice(&self) -> &[Self::Element] { + self.0 + } +} + +impl A { + // We want this function to work + pub fn failing(&self) + where + Self: AsSlice, + { + self.as_ref_a().as_ref_a(); + } + + pub fn as_ref_a(&self) -> A<&[::Element]> + where + Self: AsSlice, + { + A(self.as_slice()) + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-88472.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-88472.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-88472.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-88472.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,38 @@ +// Regression test for #88472, where a suggestion was issued to +// import an inaccessible struct. + +#![warn(unused_imports)] +//~^ NOTE: the lint level is defined here + +mod a { + struct Foo; + //~^ NOTE: struct `a::Foo` exists but is inaccessible + //~| NOTE: not accessible +} + +mod b { + use crate::a::*; + //~^ WARNING: unused import + type Bar = Foo; + //~^ ERROR: cannot find type `Foo` in this scope [E0412] + //~| NOTE: not found in this scope +} + +mod c { + enum Eee {} + //~^ NOTE: these enums exist but are inaccessible + //~| NOTE: `c::Eee`: not accessible + + mod d { + enum Eee {} + //~^ NOTE: `c::d::Eee`: not accessible + } +} + +mod e { + type Baz = Eee; + //~^ ERROR: cannot find type `Eee` in this scope [E0412] + //~| NOTE: not found in this scope +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-88472.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-88472.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/issue-88472.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/issue-88472.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,42 @@ +error[E0412]: cannot find type `Foo` in this scope + --> $DIR/issue-88472.rs:16:16 + | +LL | type Bar = Foo; + | ^^^ not found in this scope + | +note: struct `a::Foo` exists but is inaccessible + --> $DIR/issue-88472.rs:8:5 + | +LL | struct Foo; + | ^^^^^^^^^^^ not accessible + +error[E0412]: cannot find type `Eee` in this scope + --> $DIR/issue-88472.rs:33:16 + | +LL | type Baz = Eee; + | ^^^ not found in this scope + | +note: these enums exist but are inaccessible + --> $DIR/issue-88472.rs:22:5 + | +LL | enum Eee {} + | ^^^^^^^^ `c::Eee`: not accessible +... +LL | enum Eee {} + | ^^^^^^^^ `c::d::Eee`: not accessible + +warning: unused import: `crate::a::*` + --> $DIR/issue-88472.rs:14:9 + | +LL | use crate::a::*; + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-88472.rs:4:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0412`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/privacy-enum-ctor.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/privacy-enum-ctor.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/privacy-enum-ctor.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/privacy-enum-ctor.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -169,16 +169,13 @@ | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z; - | ^ + | ^ help: an enum with a similar name exists: `E` | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z; - | ~ -help: consider importing this enum - | -LL | use m::Z; +note: enum `m::Z` exists but is inaccessible + --> $DIR/privacy-enum-ctor.rs:11:9 | +LL | pub(in m) enum Z { + | ^^^^^^^^^^^^^^^^ not accessible error[E0423]: expected value, found enum `m::n::Z` --> $DIR/privacy-enum-ctor.rs:57:16 @@ -215,16 +212,13 @@ | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Fn; - | ^ + | ^ help: an enum with a similar name exists: `E` | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Fn; - | ~ -help: consider importing this enum - | -LL | use m::Z; +note: enum `m::Z` exists but is inaccessible + --> $DIR/privacy-enum-ctor.rs:11:9 | +LL | pub(in m) enum Z { + | ^^^^^^^^^^^^^^^^ not accessible error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:64:12 @@ -233,16 +227,13 @@ | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Struct; - | ^ + | ^ help: an enum with a similar name exists: `E` | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Struct; - | ~ -help: consider importing this enum - | -LL | use m::Z; +note: enum `m::Z` exists but is inaccessible + --> $DIR/privacy-enum-ctor.rs:11:9 | +LL | pub(in m) enum Z { + | ^^^^^^^^^^^^^^^^ not accessible error[E0423]: expected value, found struct variant `m::n::Z::Struct` --> $DIR/privacy-enum-ctor.rs:64:16 @@ -262,16 +253,13 @@ | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Unit {}; - | ^ + | ^ help: an enum with a similar name exists: `E` | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Unit {}; - | ~ -help: consider importing this enum - | -LL | use m::Z; +note: enum `m::Z` exists but is inaccessible + --> $DIR/privacy-enum-ctor.rs:11:9 | +LL | pub(in m) enum Z { + | ^^^^^^^^^^^^^^^^ not accessible error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:57:22 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/privacy-struct-ctor.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/privacy-struct-ctor.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/privacy-struct-ctor.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/privacy-struct-ctor.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -33,10 +33,11 @@ LL | xcrate::S; | ^^^^^^^^^ constructor is not visible here due to private fields | -help: consider importing this tuple struct instead - | -LL | use m::S; +note: tuple struct `m::S` exists but is inaccessible + --> $DIR/privacy-struct-ctor.rs:6:5 | +LL | pub struct S(u8); + | ^^^^^^^^^^^^^^^^^ not accessible error[E0603]: tuple struct constructor `Z` is private --> $DIR/privacy-struct-ctor.rs:18:12 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/suggest-path-for-tuple-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/suggest-path-for-tuple-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/suggest-path-for-tuple-struct.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/suggest-path-for-tuple-struct.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +mod module { + pub struct SomeTupleStruct(u8); + pub struct SomeRegularStruct { + foo: u8 + } + + impl SomeTupleStruct { + pub fn new() -> Self { + Self(0) + } + } + impl SomeRegularStruct { + pub fn new() -> Self { + Self { foo: 0 } + } + } +} + +use module::{SomeTupleStruct, SomeRegularStruct}; + +fn main() { + let _ = SomeTupleStruct.new(); + //~^ ERROR expected value, found struct `SomeTupleStruct` + let _ = SomeRegularStruct.new(); + //~^ ERROR expected value, found struct `SomeRegularStruct` +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +error[E0423]: expected value, found struct `SomeTupleStruct` + --> $DIR/suggest-path-for-tuple-struct.rs:22:13 + | +LL | let _ = SomeTupleStruct.new(); + | ^^^^^^^^^^^^^^^---- + | | + | help: use the path separator to refer to an item: `SomeTupleStruct::new` + +error[E0423]: expected value, found struct `SomeRegularStruct` + --> $DIR/suggest-path-for-tuple-struct.rs:24:13 + | +LL | let _ = SomeRegularStruct.new(); + | ^^^^^^^^^^^^^^^^^---- + | | + | help: use the path separator to refer to an item: `SomeRegularStruct::new` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0423`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/use-self-in-inner-fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/use-self-in-inner-fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/use-self-in-inner-fn.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/use-self-in-inner-fn.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +struct A; + +impl A { +//~^ NOTE `Self` type implicitly declared here, by this `impl` + fn banana(&mut self) { + fn peach(this: &Self) { + //~^ ERROR can't use generic parameters from outer function + //~| NOTE use of generic parameter from outer function + //~| NOTE use a type here instead + } + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/use-self-in-inner-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/use-self-in-inner-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/resolve/use-self-in-inner-fn.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/resolve/use-self-in-inner-fn.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0401]: can't use generic parameters from outer function + --> $DIR/use-self-in-inner-fn.rs:6:25 + | +LL | impl A { + | ---- `Self` type implicitly declared here, by this `impl` +... +LL | fn peach(this: &Self) { + | ^^^^ + | | + | use of generic parameter from outer function + | use a type here instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0401`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc1623.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc1623.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc1623.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc1623.nll.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -31,7 +31,7 @@ LL | | }; | |_^ one type is more general than the other | - = note: expected type `for<'r, 's> Fn<(&'r Foo<'s>,)>` + = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>` found type `Fn<(&Foo<'_>,)>` error[E0308]: mismatched types @@ -46,7 +46,7 @@ LL | | }; | |_^ one type is more general than the other | - = note: expected type `for<'r, 's> Fn<(&'r Foo<'s>,)>` + = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>` found type `Fn<(&Foo<'_>,)>` error: implementation of `FnOnce` is not general enough @@ -61,7 +61,7 @@ LL | | }; | |_^ implementation of `FnOnce` is not general enough | - = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'_>,)>`, for any lifetime `'1`... + = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough @@ -76,7 +76,7 @@ LL | | }; | |_^ implementation of `FnOnce` is not general enough | - = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&Foo<'1>,)>`, for any lifetime `'1`... + = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2` error: aborting due to 5 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: renaming of the library `foo` was specified, however this crate contains no `#[link(...)]` attributes referencing this library. +error: renaming of the library `foo` was specified, however this crate contains no `#[link(...)]` attributes referencing this library error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: multiple renamings were specified for library `foo` . +error: multiple renamings were specified for library `foo` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-issue-49631.rs:20:9 - | -LL | while let Some(Ok(string)) = foo.get() { - | --- immutable borrow occurs here -LL | foo.mutate(); - | ^^^ mutable borrow occurs here -LL | -LL | println!("foo={:?}", *string); - | ------- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/borrowck-issue-49631.rs:20:9 | LL | while let Some(Ok(string)) = foo.get() { - | --- immutable borrow occurs here + | --------- immutable borrow occurs here LL | foo.mutate(); | ^^^^^^^^^^^^ mutable borrow occurs here LL | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,8 +4,29 @@ pub enum NonExhaustiveEnum { Unit, Tuple(u32), - Struct { field: u32 } + Struct { field: u32 }, +} + +#[non_exhaustive] +pub enum NestedNonExhaustive { + A(NonExhaustiveEnum), + B, + C, } #[non_exhaustive] pub enum EmptyNonExhaustiveEnum {} + +pub enum VariantNonExhaustive { + #[non_exhaustive] + Bar { + x: u32, + y: u64, + }, + Baz(u32, u16), +} + +#[non_exhaustive] +pub enum NonExhaustiveSingleVariant { + A(bool), +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,4 @@ +#[derive(Default)] #[non_exhaustive] pub struct NormalStruct { pub first_field: u16, @@ -15,7 +16,7 @@ pub struct FunctionalRecord { pub first_field: u16, pub second_field: u16, - pub third_field: bool + pub third_field: bool, } impl Default for FunctionalRecord { @@ -23,3 +24,18 @@ FunctionalRecord { first_field: 640, second_field: 480, third_field: false } } } + +#[derive(Default)] +#[non_exhaustive] +pub struct NestedStruct { + pub foo: u16, + pub bar: NormalStruct, +} + +#[derive(Default)] +#[non_exhaustive] +pub struct MixedVisFields { + pub a: u16, + pub b: bool, + pub(crate) foo: bool, +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,29 @@ +#![feature(staged_api)] +#![stable(feature = "stable_test_feature", since = "1.0.0")] + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +#[non_exhaustive] +pub enum UnstableEnum { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Stable, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Stable2, + #[unstable(feature = "unstable_test_feature", issue = "none")] + Unstable, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +#[non_exhaustive] +pub enum OnlyUnstableEnum { + #[unstable(feature = "unstable_test_feature", issue = "none")] + Unstable, + #[unstable(feature = "unstable_test_feature", issue = "none")] + Unstable2, +} + +impl OnlyUnstableEnum { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new() -> Self { + Self::Unstable + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,170 @@ +// Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly. + +#![feature(non_exhaustive_omitted_patterns_lint, unstable_test_feature)] + +// aux-build:enums.rs +extern crate enums; +// aux-build:unstable.rs +extern crate unstable; +// aux-build:structs.rs +extern crate structs; + +use enums::{ + EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant, + VariantNonExhaustive, +}; +use unstable::{UnstableEnum, OnlyUnstableEnum}; +use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct}; + +#[non_exhaustive] +#[derive(Default)] +pub struct Foo { + a: u8, + b: usize, + c: String, +} + +#[non_exhaustive] +pub enum Bar { + A, + B, + C, +} + +fn main() { + let enumeration = Bar::A; + + // Ok: this is a crate local non_exhaustive enum + match enumeration { + Bar::A => {} + Bar::B => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + + let non_enum = NonExhaustiveEnum::Unit; + + // Ok: without the attribute + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + _ => {} + } + + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + match non_enum { + NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + let x = 5; + match non_enum { + NonExhaustiveEnum::Unit if x > 10 => {} + NonExhaustiveEnum::Tuple(_) => {} + NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: all covered and not `unreachable-patterns` + #[deny(unreachable_patterns)] + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match NestedNonExhaustive::B { + NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {} + NestedNonExhaustive::A(_) => {} + NestedNonExhaustive::B => {} + _ => {} + } + //~^^ some variants are not matched explicitly + //~^^^^^ some variants are not matched explicitly + + #[warn(non_exhaustive_omitted_patterns)] + match VariantNonExhaustive::Baz(1, 2) { + VariantNonExhaustive::Baz(_, _) => {} + VariantNonExhaustive::Bar { x, .. } => {} + } + //~^^ some fields are not explicitly listed + + #[warn(non_exhaustive_omitted_patterns)] + let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); + //~^ some fields are not explicitly listed + + // Ok: this is local + #[warn(non_exhaustive_omitted_patterns)] + let Foo { a, b, .. } = Foo::default(); + + #[warn(non_exhaustive_omitted_patterns)] + let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + //~^ some fields are not explicitly listed + //~^^ some fields are not explicitly listed + + // Ok: this tests https://github.com/rust-lang/rust/issues/89382 + #[warn(non_exhaustive_omitted_patterns)] + let MixedVisFields { a, b, .. } = MixedVisFields::default(); + + // Ok: because this only has 1 variant + #[deny(non_exhaustive_omitted_patterns)] + match NonExhaustiveSingleVariant::A(true) { + NonExhaustiveSingleVariant::A(true) => {} + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match NonExhaustiveSingleVariant::A(true) { + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: we don't lint on `if let` expressions + #[deny(non_exhaustive_omitted_patterns)] + if let NonExhaustiveEnum::Tuple(_) = non_enum {} + + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + #[deny(non_exhaustive_omitted_patterns)] + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + UnstableEnum::Unstable => {} + _ => {} + } + + // Ok: the feature is on and both variants are matched + #[deny(non_exhaustive_omitted_patterns)] + match OnlyUnstableEnum::Unstable { + OnlyUnstableEnum::Unstable => {} + OnlyUnstableEnum::Unstable2 => {} + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match OnlyUnstableEnum::Unstable { + OnlyUnstableEnum::Unstable => {} + _ => {} + } + //~^^ some variants are not matched explicitly +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,160 @@ +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:102:9 + | +LL | VariantNonExhaustive::Bar { x, .. } => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `y` not listed + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:99:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:107:9 + | +LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:106:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:115:29 + | +LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:114:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:115:9 + | +LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:58:9 + | +LL | _ => {} + | ^ pattern `Struct { .. }` not covered + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:57:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:65:9 + | +LL | _ => {} + | ^ pattern `Tuple(_)` not covered + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:64:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:75:9 + | +LL | _ => {} + | ^ pattern `Unit` not covered + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:74:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:92:32 + | +LL | NestedNonExhaustive::A(_) => {} + | ^ patterns `Tuple(_)` and `Struct { .. }` not covered + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:89:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:94:9 + | +LL | _ => {} + | ^ pattern `C` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:132:9 + | +LL | _ => {} + | ^ pattern `A(_)` not covered + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:130:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:144:9 + | +LL | _ => {} + | ^ pattern `Unstable` not covered + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:143:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:167:9 + | +LL | _ => {} + | ^ pattern `Unstable2` not covered + | +note: the lint level is defined here + --> $DIR/omitted-patterns.rs:164:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: aborting due to 8 previous errors; 4 warnings emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +// Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly with variants +// marked stable and unstable. + +#![feature(non_exhaustive_omitted_patterns_lint)] + +// aux-build:unstable.rs +extern crate unstable; + +use unstable::{UnstableEnum, OnlyUnstableEnum}; + +fn main() { + // OK: this matches all the stable variants + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: although this is a bit odd, we don't have anything to report + // since there is no stable variants and the feature is off + #[deny(non_exhaustive_omitted_patterns)] + match OnlyUnstableEnum::new() { + _ => {} + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,16 @@ +error: some variants are not matched explicitly + --> $DIR/stable-omitted-patterns.rs:23:9 + | +LL | _ => {} + | ^ pattern `Stable2` not covered + | +note: the lint level is defined here + --> $DIR/stable-omitted-patterns.rs:22:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/struct.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2008-non-exhaustive/struct.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -16,13 +16,13 @@ LL | let ts_explicit = structs::TupleStruct(640, 480); | ^^^^^^^^^^^ private tuple struct constructor | - ::: $DIR/auxiliary/structs.rs:11:24 + ::: $DIR/auxiliary/structs.rs:12:24 | LL | pub struct TupleStruct(pub u16, pub u16); | ---------------- a constructor is private if any of the fields is private | note: the tuple struct constructor `TupleStruct` is defined here - --> $DIR/auxiliary/structs.rs:11:1 + --> $DIR/auxiliary/structs.rs:12:1 | LL | pub struct TupleStruct(pub u16, pub u16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ | ^^^^^^^^^^ private unit struct | note: the unit struct `UnitStruct` is defined here - --> $DIR/auxiliary/structs.rs:8:1 + --> $DIR/auxiliary/structs.rs:9:1 | LL | pub struct UnitStruct; | ^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2091-track-caller/tracked-closure.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2091-track-caller/tracked-closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2091-track-caller/tracked-closure.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2091-track-caller/tracked-closure.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,154 @@ +// run-pass + +#![feature(stmt_expr_attributes)] +#![feature(closure_track_caller)] +#![feature(generator_trait)] +#![feature(generators)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; +use std::panic::Location; + +type Loc = &'static Location<'static>; + +#[track_caller] +fn mono_invoke_fn (&'static str, bool, Loc)>( + val: &F +) -> (&'static str, bool, Loc) { + val("from_mono", false) +} + +#[track_caller] +fn mono_invoke_fn_once (&'static str, bool, Loc)>( + val: F +) -> (&'static str, bool, Loc) { + val("from_mono", false) +} + +#[track_caller] +fn dyn_invoke_fn_mut( + val: &mut dyn FnMut(&'static str, bool) -> (&'static str, bool, Loc) +) -> (&'static str, bool, Loc) { + val("from_dyn", false) +} + +#[track_caller] +fn dyn_invoke_fn_once( + val: Box (&'static str, bool, Loc)> +) -> (&'static str, bool, Loc) { + val("from_dyn", false) +} + + +fn test_closure() { + let mut track_closure = #[track_caller] |first: &'static str, second: bool| { + (first, second, Location::caller()) + }; + let (first_arg, first_bool, first_loc) = track_closure("first_arg", true); + let first_line = line!() - 1; + assert_eq!(first_arg, "first_arg"); + assert_eq!(first_bool, true); + assert_eq!(first_loc.file(), file!()); + assert_eq!(first_loc.line(), first_line); + assert_eq!(first_loc.column(), 46); + + let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_mut(&mut track_closure); + assert_eq!(dyn_arg, "from_dyn"); + assert_eq!(dyn_bool, false); + // `FnMut::call_mut` does not have `#[track_caller]`, + // so this will not match + assert_ne!(dyn_loc.file(), file!()); + + let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_once(Box::new(track_closure)); + assert_eq!(dyn_arg, "from_dyn"); + assert_eq!(dyn_bool, false); + // `FnOnce::call_once` does not have `#[track_caller]` + // so this will not match + assert_ne!(dyn_loc.file(), file!()); + + + let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn(&track_closure); + let mono_line = line!() - 1; + assert_eq!(mono_arg, "from_mono"); + assert_eq!(mono_bool, false); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 43); + + let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn_once(track_closure); + let mono_line = line!() - 1; + assert_eq!(mono_arg, "from_mono"); + assert_eq!(mono_bool, false); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 43); + + let non_tracked_caller = || Location::caller(); + let non_tracked_line = line!() - 1; // This is the line of the closure, not its caller + let non_tracked_loc = non_tracked_caller(); + assert_eq!(non_tracked_loc.file(), file!()); + assert_eq!(non_tracked_loc.line(), non_tracked_line); + assert_eq!(non_tracked_loc.column(), 33); +} + + +#[track_caller] +fn mono_generator>( + val: Pin<&mut F> +) -> (&'static str, String, Loc) { + match val.resume("Mono".to_string()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + } +} + +#[track_caller] +fn dyn_generator( + val: Pin<&mut dyn Generator> +) -> (&'static str, String, Loc) { + match val.resume("Dyn".to_string()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + } +} + +fn test_generator() { + let generator = #[track_caller] |arg: String| { + yield ("first", arg.clone(), Location::caller()); + yield ("second", arg.clone(), Location::caller()); + }; + + let mut pinned = Box::pin(generator); + let (dyn_ret, dyn_arg, dyn_loc) = dyn_generator(pinned.as_mut()); + assert_eq!(dyn_ret, "first"); + assert_eq!(dyn_arg, "Dyn".to_string()); + // The `Generator` trait does not have `#[track_caller]` on `resume`, so + // this will not match. + assert_ne!(dyn_loc.file(), file!()); + + + let (mono_ret, mono_arg, mono_loc) = mono_generator(pinned.as_mut()); + let mono_line = line!() - 1; + assert_eq!(mono_ret, "second"); + // The generator ignores the argument to the second `resume` call + assert_eq!(mono_arg, "Dyn".to_string()); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 42); + + let non_tracked_generator = || { yield Location::caller(); }; + let non_tracked_line = line!() - 1; // This is the line of the generator, not its caller + let non_tracked_loc = match Box::pin(non_tracked_generator).as_mut().resume(()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + }; + assert_eq!(non_tracked_loc.file(), file!()); + assert_eq!(non_tracked_loc.line(), non_tracked_line); + assert_eq!(non_tracked_loc.column(), 44); + +} + +fn main() { + test_closure(); + test_generator(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | type Out = &'a Foo<'b>; | ^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the impl at 16:10 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-nominal-type-region-rev.rs:16:10 | LL | impl<'a, 'b> Trait<'a, 'b> for usize { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 16:14 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-nominal-type-region-rev.rs:16:14 | LL | impl<'a, 'b> Trait<'a, 'b> for usize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | type Out = &'a Foo<'b>; | ^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the impl at 16:10 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-nominal-type-region.rs:16:10 | LL | impl<'a, 'b> Trait<'a, 'b> for usize { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 16:14 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-nominal-type-region.rs:16:14 | LL | impl<'a, 'b> Trait<'a, 'b> for usize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | type Out = &'a Foo<&'b i32>; | ^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the impl at 16:10 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-nominal-type-type-rev.rs:16:10 | LL | impl<'a, 'b> Trait<'a, 'b> for usize { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 16:14 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-nominal-type-type-rev.rs:16:14 | LL | impl<'a, 'b> Trait<'a, 'b> for usize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,12 @@ LL | type Out = &'a Foo<&'b i32>; | ^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the impl at 16:10 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-outlives-nominal-type-type.rs:16:10 | LL | impl<'a, 'b> Trait<'a, 'b> for usize { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 16:14 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-outlives-nominal-type-type.rs:16:14 | LL | impl<'a, 'b> Trait<'a, 'b> for usize { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -26,12 +26,12 @@ LL | type Out = &'a &'b T; | ^^^^^^^^^ | -note: the pointer is valid for the lifetime `'a` as defined on the impl at 24:6 +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/regions-struct-not-wf.rs:24:6 | LL | impl<'a, 'b, T> Trait1<'a, 'b, T> for u32 { | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 24:10 +note: but the referenced data is only valid for the lifetime `'b` as defined here --> $DIR/regions-struct-not-wf.rs:24:10 | LL | impl<'a, 'b, T> Trait1<'a, 'b, T> for u32 { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2457/extern_block_nonascii_forbidden.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2457/extern_block_nonascii_forbidden.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2457/extern_block_nonascii_forbidden.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2457/extern_block_nonascii_forbidden.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -6,7 +6,7 @@ LL | type 一; | ^^ | - = note: This limitation may be lifted in the future; see issue #83942 for more information + = note: this limitation may be lifted in the future; see issue #83942 for more information error: items in `extern` blocks cannot use non-ascii identifiers --> $DIR/extern_block_nonascii_forbidden.rs:5:8 @@ -17,7 +17,7 @@ LL | fn 二(); | ^^ | - = note: This limitation may be lifted in the future; see issue #83942 for more information + = note: this limitation may be lifted in the future; see issue #83942 for more information error: items in `extern` blocks cannot use non-ascii identifiers --> $DIR/extern_block_nonascii_forbidden.rs:6:12 @@ -28,7 +28,7 @@ LL | static 三: usize; | ^^ | - = note: This limitation may be lifted in the future; see issue #83942 for more information + = note: this limitation may be lifted in the future; see issue #83942 for more information error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,15 +8,15 @@ help: if this is a `self` type, give it a parameter name | LL | trait Trait2015 { fn foo(#[allow(C)] self: i32); } - | ~~~~~~~~~ + | +++++ help: if this is a parameter name, give it a type | LL | trait Trait2015 { fn foo(#[allow(C)] i32: TypeName); } - | ~~~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | trait Trait2015 { fn foo(#[allow(C)] _: i32); } - | ~~~~~~ + | ++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +#![feature(raw_dylib)] +//~^ WARN the feature `raw_dylib` is incomplete + +#[link(name = "foo")] +extern "C" { + #[link_ordinal()] + //~^ ERROR incorrect number of arguments to `#[link_ordinal]` + fn foo(); +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/link-ordinal-missing-argument.rs:1:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 for more information + +error: incorrect number of arguments to `#[link_ordinal]` + --> $DIR/link-ordinal-missing-argument.rs:6:5 + | +LL | #[link_ordinal()] + | ^^^^^^^^^^^^^^^^^ + | + = note: the attribute requires exactly one argument + +error: aborting due to previous error; 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,13 @@ +// only-windows-msvc +#![feature(raw_dylib)] +//~^ WARN the feature `raw_dylib` is incomplete + +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + #[link_ordinal(1)] + #[link_ordinal(2)] + //~^ ERROR multiple `link_ordinal` attributes on a single definition + fn foo(); +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/link-ordinal-multiple.rs:2:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 for more information + +error: multiple `link_ordinal` attributes on a single definition + --> $DIR/link-ordinal-multiple.rs:8:5 + | +LL | #[link_ordinal(2)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,8 @@ #[link(name = "foo")] extern "C" { - #[link_ordinal(18446744073709551616)] - //~^ ERROR ordinal value in `link_ordinal` is too large: `18446744073709551616` + #[link_ordinal(72436)] + //~^ ERROR ordinal value in `link_ordinal` is too large: `72436` fn foo(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,13 +7,13 @@ = note: `#[warn(incomplete_features)]` on by default = note: see issue #58713 for more information -error: ordinal value in `link_ordinal` is too large: `18446744073709551616` +error: ordinal value in `link_ordinal` is too large: `72436` --> $DIR/link-ordinal-too-large.rs:6:5 | -LL | #[link_ordinal(18446744073709551616)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_ordinal(72436)] + | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: the value may not exceed `usize::MAX` + = note: the value may not exceed `u16::MAX` error: aborting due to previous error; 1 warning emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,11 @@ +#![feature(raw_dylib)] +//~^ WARN the feature `raw_dylib` is incomplete + +#[link(name = "foo")] +extern "C" { + #[link_ordinal(3, 4)] + //~^ ERROR incorrect number of arguments to `#[link_ordinal]` + fn foo(); +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/link-ordinal-too-many-arguments.rs:1:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 for more information + +error: incorrect number of arguments to `#[link_ordinal]` + --> $DIR/link-ordinal-too-many-arguments.rs:6:5 + | +LL | #[link_ordinal(3, 4)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the attribute requires exactly one argument + +error: aborting due to previous error; 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs 2021-11-29 19:27:11.000000000 +0000 @@ -16,12 +16,17 @@ // This duplicate bound should not result in ambiguities. It should be equivalent to a single ~const // bound. -// const fn equals_self(t: &T) -> bool { -// FIXME(fee1-dead)^ why should the order matter here? -const fn equals_self(t: &T) -> bool { +const fn equals_self(t: &T) -> bool { *t == *t } -pub const EQ: bool = equals_self(&S); +trait A: PartialEq {} +impl A for T {} + +const fn equals_self2(t: &T) -> bool { + *t == *t +} + +pub const EQ: bool = equals_self(&S) && equals_self2(&S); fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/call-generic-method-nonconst.rs:19:34 | LL | pub const EQ: bool = equals_self(&S); - | ^^ no implementation for `S == S` + | ----------- ^^ no implementation for `S == S` + | | + | required by a bound introduced by this call | = help: the trait `PartialEq` is not implemented for `S` note: required by a bound in `equals_self` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,31 @@ +// run-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +const fn answer_p1(f: &F) -> u8 + where + F: ~const FnOnce() -> u8, + F: ~const FnMut() -> u8, + F: ~const Fn() -> u8, +{ + f() * 7 +} + +const fn three() -> u8 { + 3 +} + +const fn answer_p2() -> u8 { + answer_p1(&three) +} + +const fn answer u8>(f: &F) -> u8 { + f() + f() +} + +const ANSWER: u8 = answer(&answer_p2); + +fn main() { + assert_eq!(ANSWER, 42) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,68 @@ +error: `~const` is not allowed here + --> $DIR/const-drop-fail.rs:27:35 + | +LL | struct ConstDropImplWithBounds(PhantomData); + | ^^^^^^^^ + | + = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions + +error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied + --> $DIR/const-drop-fail.rs:45:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | NonTrivialDrop, + | ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop` + | +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:36:19 + | +LL | const fn check(_: T) {} + | ^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: the trait bound `ConstImplWithDropGlue: Drop` is not satisfied + --> $DIR/const-drop-fail.rs:47:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | ConstImplWithDropGlue(NonTrivialDrop), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue` + | +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:36:19 + | +LL | const fn check(_: T) {} + | ^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied + --> $DIR/const-drop-fail.rs:49:5 + | +LL | ConstDropImplWithBounds::(PhantomData), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop` + | +note: required by `ConstDropImplWithBounds` + --> $DIR/const-drop-fail.rs:27:1 + | +LL | struct ConstDropImplWithBounds(PhantomData); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied + --> $DIR/const-drop-fail.rs:49:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | ConstDropImplWithBounds::(PhantomData), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop` + | +note: required by a bound in `ConstDropImplWithBounds` + --> $DIR/const-drop-fail.rs:27:35 + | +LL | struct ConstDropImplWithBounds(PhantomData); + | ^^^^^^^^ required by this bound in `ConstDropImplWithBounds` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,54 @@ +// revisions: stock precise +#![feature(const_trait_impl)] +#![feature(const_mut_refs)] +#![feature(const_fn_trait_bound)] +#![cfg_attr(precise, feature(const_precise_live_drops))] + +use std::marker::PhantomData; + +struct NonTrivialDrop; + +impl Drop for NonTrivialDrop { + fn drop(&mut self) { + println!("Non trivial drop"); + } +} + +struct ConstImplWithDropGlue(NonTrivialDrop); + +impl const Drop for ConstImplWithDropGlue { + fn drop(&mut self) {} +} + +trait A { fn a() { println!("A"); } } + +impl A for NonTrivialDrop {} + +struct ConstDropImplWithBounds(PhantomData); +//~^ ERROR `~const` is not allowed + +impl const Drop for ConstDropImplWithBounds { + fn drop(&mut self) { + T::a(); + } +} + +const fn check(_: T) {} + +macro_rules! check_all { + ($($exp:expr),*$(,)?) => {$( + const _: () = check($exp); + )*}; +} + +check_all! { + NonTrivialDrop, + //~^ ERROR the trait bound + ConstImplWithDropGlue(NonTrivialDrop), + //~^ ERROR the trait bound + ConstDropImplWithBounds::(PhantomData), + //~^ ERROR the trait bound + //~| ERROR the trait bound +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,68 @@ +error: `~const` is not allowed here + --> $DIR/const-drop-fail.rs:27:35 + | +LL | struct ConstDropImplWithBounds(PhantomData); + | ^^^^^^^^ + | + = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions + +error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied + --> $DIR/const-drop-fail.rs:45:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | NonTrivialDrop, + | ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop` + | +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:36:19 + | +LL | const fn check(_: T) {} + | ^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: the trait bound `ConstImplWithDropGlue: Drop` is not satisfied + --> $DIR/const-drop-fail.rs:47:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | ConstImplWithDropGlue(NonTrivialDrop), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue` + | +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:36:19 + | +LL | const fn check(_: T) {} + | ^^^^^^^^^^^ required by this bound in `check` + +error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied + --> $DIR/const-drop-fail.rs:49:5 + | +LL | ConstDropImplWithBounds::(PhantomData), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop` + | +note: required by `ConstDropImplWithBounds` + --> $DIR/const-drop-fail.rs:27:1 + | +LL | struct ConstDropImplWithBounds(PhantomData); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied + --> $DIR/const-drop-fail.rs:49:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | ConstDropImplWithBounds::(PhantomData), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop` + | +note: required by a bound in `ConstDropImplWithBounds` + --> $DIR/const-drop-fail.rs:27:35 + | +LL | struct ConstDropImplWithBounds(PhantomData); + | ^^^^^^^^ required by this bound in `ConstDropImplWithBounds` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,80 @@ +// run-pass +// revisions: stock precise +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] +#![feature(const_mut_refs)] +#![cfg_attr(precise, feature(const_precise_live_drops))] + +struct S<'a>(&'a mut u8); + +impl<'a> const Drop for S<'a> { + fn drop(&mut self) { + *self.0 += 1; + } +} + +const fn a(_: T) {} + +const fn b() -> u8 { + let mut c = 0; + let _ = S(&mut c); + a(S(&mut c)); + c +} + +const C: u8 = b(); + +macro_rules! implements_const_drop { + ($($exp:expr),*$(,)?) => { + $( + const _: () = a($exp); + )* + } +} + +#[allow(dead_code)] +mod t { + pub struct Foo; + pub enum Bar { A } + pub fn foo() {} + pub struct ConstDrop; + + impl const Drop for ConstDrop { + fn drop(&mut self) {} + } + + pub struct HasConstDrop(pub ConstDrop); + pub struct TrivialFields(pub u8, pub i8, pub usize, pub isize); +} + +use t::*; + +implements_const_drop! { + 1u8, + 2, + 3.0, + Foo, + Bar::A, + foo, + ConstDrop, + HasConstDrop(ConstDrop), + TrivialFields(1, 2, 3, 4), + &1, + &1 as *const i32, +} + +fn main() { + struct HasDropGlue(Box); + struct HasDropImpl; + impl Drop for HasDropImpl { + fn drop(&mut self) { + println!("not trivial drop"); + } + } + + // These types should pass because ~const in a non-const context should have no effect. + a(HasDropGlue(Box::new(0))); + a(HasDropImpl); + + assert_eq!(C, 2); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +trait Tr { + fn req(&self); + + fn prov(&self) { + println!("lul"); + self.req(); + } + + #[default_method_body_is_const] + fn default() {} +} + +struct S; + +impl const Tr for S { + fn req(&self) {} +} //~^^ ERROR const trait implementations may not use non-const default functions + +impl const Tr for u16 { + fn prov(&self) {} + fn default() {} +} //~^^^ ERROR not all trait items implemented + + +impl const Tr for u32 { + fn req(&self) {} + fn default() {} +} //~^^^ ERROR const trait implementations may not use non-const default functions + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +error: const trait implementations may not use non-const default functions + --> $DIR/impl-with-default-fn-fail.rs:18:1 + | +LL | / impl const Tr for S { +LL | | fn req(&self) {} +LL | | } + | |_^ + | + = note: `prov` not implemented + +error: const trait implementations may not use non-const default functions + --> $DIR/impl-with-default-fn-fail.rs:28:1 + | +LL | / impl const Tr for u32 { +LL | | fn req(&self) {} +LL | | fn default() {} +LL | | } + | |_^ + | + = note: `prov` not implemented + +error[E0046]: not all trait items implemented, missing: `req` + --> $DIR/impl-with-default-fn-fail.rs:22:1 + | +LL | fn req(&self); + | -------------- `req` from trait +... +LL | impl const Tr for u16 { + | ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0046`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,34 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +trait Tr { + fn req(&self); + + fn prov(&self) { + println!("lul"); + self.req(); + } + + #[default_method_body_is_const] + fn default() {} +} + +impl const Tr for u8 { + fn req(&self) {} + fn prov(&self) {} +} + +macro_rules! impl_tr { + ($ty: ty) => { + impl const Tr for $ty { + fn req(&self) {} + fn prov(&self) {} + } + } +} + +impl_tr!(u64); + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -#![feature(const_trait_impl)] - -trait Tr { - fn req(&self); - - fn prov(&self) { - println!("lul"); - self.req(); - } - - #[default_method_body_is_const] - fn default() {} -} - -struct S; - -impl const Tr for S { - fn req(&self) {} -} //~^^ ERROR const trait implementations may not use non-const default functions - -impl const Tr for u8 { - fn req(&self) {} - fn prov(&self) {} -} - -impl const Tr for u16 { - fn prov(&self) {} - fn default() {} -} //~^^^ ERROR not all trait items implemented - - -impl const Tr for u32 { - fn req(&self) {} - fn default() {} -} //~^^^ ERROR const trait implementations may not use non-const default functions - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -error: const trait implementations may not use non-const default functions - --> $DIR/impl-with-default-fn.rs:17:1 - | -LL | / impl const Tr for S { -LL | | fn req(&self) {} -LL | | } - | |_^ - | - = note: `prov` not implemented - -error: const trait implementations may not use non-const default functions - --> $DIR/impl-with-default-fn.rs:32:1 - | -LL | / impl const Tr for u32 { -LL | | fn req(&self) {} -LL | | fn default() {} -LL | | } - | |_^ - | - = note: `prov` not implemented - -error[E0046]: not all trait items implemented, missing: `req` - --> $DIR/impl-with-default-fn.rs:26:1 - | -LL | fn req(&self); - | -------------- `req` from trait -... -LL | impl const Tr for u16 { - | ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0046`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +// check-pass +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +struct S; + +trait A {} +trait B {} + +impl const A for S {} +impl const B for S {} + +impl S { + const fn a() where T: ~const B { + + } +} + +const _: () = S::a::(); + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/stability.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/stability.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/stability.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfc-2632-const-trait-impl/stability.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -13,7 +13,7 @@ LL | Int(1i32) + Int(2i32) | ^^^^^^^^^^^^^^^^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,11 +1,11 @@ // run-pass #![allow(unreachable_patterns)] -#![feature(box_syntax, box_patterns)] +#![feature(box_patterns)] struct Foo{} pub fn main() { - let b = box Foo{}; + let b = Box::new(Foo{}); let box f = &b; let _: &Foo = f; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/fn-traits.rs:24:10 | LL | call(foo); - | ^^^ expected an `Fn<()>` closure, found `fn() {foo}` + | ---- ^^^ expected an `Fn<()>` closure, found `fn() {foo}` + | | + | required by a bound introduced by this call | = help: the trait `Fn<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` @@ -17,7 +19,9 @@ --> $DIR/fn-traits.rs:25:14 | LL | call_mut(foo); - | ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` + | -------- ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` + | | + | required by a bound introduced by this call | = help: the trait `FnMut<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` @@ -32,7 +36,9 @@ --> $DIR/fn-traits.rs:26:15 | LL | call_once(foo); - | ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` + | --------- ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` + | | + | required by a bound introduced by this call | = help: the trait `FnOnce<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` @@ -47,7 +53,9 @@ --> $DIR/fn-traits.rs:28:10 | LL | call(foo_unsafe); - | ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + | ---- ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + | | + | required by a bound introduced by this call | = help: the trait `Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` @@ -62,7 +70,9 @@ --> $DIR/fn-traits.rs:30:14 | LL | call_mut(foo_unsafe); - | ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + | -------- ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + | | + | required by a bound introduced by this call | = help: the trait `FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` @@ -77,7 +87,9 @@ --> $DIR/fn-traits.rs:32:15 | LL | call_once(foo_unsafe); - | ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + | --------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + | | + | required by a bound introduced by this call | = help: the trait `FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2018/trait-import-suggestions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2018/trait-import-suggestions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2018/trait-import-suggestions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2018/trait-import-suggestions.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,8 +8,10 @@ | ^^^^^^ method not found in `u32` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope; perhaps add a `use` for it: - `use crate::foo::foobar::Foobar;` +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use crate::foo::foobar::Foobar; + | error[E0599]: no method named `bar` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:28:7 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2018/uniform-paths/ambiguity-macros-nested.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2018/uniform-paths/ambiguity-macros-nested.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2018/uniform-paths/ambiguity-macros-nested.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2018/uniform-paths/ambiguity-macros-nested.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -15,7 +15,7 @@ | |_____________^ ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation = help: use `self::std` to refer to this module unambiguously = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2018/uniform-paths/ambiguity-macros.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2018/uniform-paths/ambiguity-macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2018/uniform-paths/ambiguity-macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2018/uniform-paths/ambiguity-macros.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -15,7 +15,7 @@ | |_________^ ... LL | m!(); - | ----- in this macro invocation + | ---- in this macro invocation = help: use `crate::std` to refer to this module unambiguously = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -15,9 +15,6 @@ | the method is available for `Rc` here | = help: items from traits can only be used if the trait is in scope - = note: the following traits are implemented but not in scope; perhaps add a `use` for one of them: - candidate #1: `use crate::m::TryIntoU32;` - candidate #2: `use std::convert::TryInto;` help: consider wrapping the receiver expression with the appropriate type | LL | let _: u32 = Box::new(3u8).try_into().unwrap(); @@ -34,6 +31,12 @@ | LL | let _: u32 = Rc::new(3u8).try_into().unwrap(); | ++++++++ + +help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: + | +LL | use crate::m::TryIntoU32; + | +LL | use std::convert::TryInto; + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/reserved-prefixes-via-macro-2.rs:15:5 | LL | m2021::number_of_tokens_in_a_prefixed_integer_literal!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix | = note: prefixed identifiers and literals are reserved since Rust 2021 = note: this error originates in the macro `m2021::number_of_tokens_in_a_prefixed_integer_literal` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -11,7 +11,7 @@ --> $DIR/reserved-prefixes-via-macro-2.rs:17:5 | LL | m2021::number_of_tokens_in_a_prefixed_char_literal!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix | = note: prefixed identifiers and literals are reserved since Rust 2021 = note: this error originates in the macro `m2021::number_of_tokens_in_a_prefixed_char_literal` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -20,7 +20,7 @@ --> $DIR/reserved-prefixes-via-macro-2.rs:19:5 | LL | m2021::number_of_tokens_in_a_prefixed_string_literal!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix | = note: prefixed identifiers and literals are reserved since Rust 2021 = note: this error originates in the macro `m2021::number_of_tokens_in_a_prefixed_string_literal` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/sanitize/crt-static.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/sanitize/crt-static.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/sanitize/crt-static.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/sanitize/crt-static.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -error: Sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` +error: sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/explicit-self-generic.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/self/explicit-self-generic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/explicit-self-generic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/explicit-self-generic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] #[derive(Copy, Clone)] struct LM { resize_at: usize, size: usize } @@ -24,6 +23,6 @@ } pub fn main() { - let mut m: Box<_> = box linear_map::<(),()>(); + let mut m: Box<_> = Box::new(linear_map::<(),()>()); assert_eq!(m.len(), 0); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/explicit-self-objects-uniq.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/self/explicit-self-objects-uniq.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/explicit-self-objects-uniq.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/explicit-self-objects-uniq.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] trait Foo { fn f(self: Box); @@ -16,7 +15,7 @@ } pub fn main() { - let x = box S { x: 3 }; + let x = Box::new(S { x: 3 }); let y = x as Box; y.f(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/explicit-self.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/self/explicit-self.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/explicit-self.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/explicit-self.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,8 +3,6 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] -#![feature(box_syntax)] - static tau: f64 = 2.0*3.14159265358979323; struct Point {x: f64, y: f64} @@ -64,7 +62,7 @@ impl Nus for thing { fn f(&self) {} } pub fn main() { - let y: Box<_> = box thing(A {a: 10}); + let y: Box<_> = Box::new(thing(A {a: 10})); assert_eq!(y.clone().bar(), 10); assert_eq!(y.quux(), 10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/self-impl-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/self/self-impl-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/self-impl-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/self-impl-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,8 +5,6 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - struct Foo; // Test uses on inherent impl. @@ -57,14 +55,14 @@ let _: Self::SuperQux = true; let _: ::SuperQux = true; - box Baz { f: 42 } + Box::new(Baz { f: 42 }) } } fn main() { - let _: Foo = Foo::foo(Foo, &Foo, box Foo); - let _: Box> = Bar::bar(box Baz { f: 42 }, - &box Baz { f: 42 }, - box box Baz { f: 42 }, + let _: Foo = Foo::foo(Foo, &Foo, Box::new(Foo)); + let _: Box> = Bar::bar(Box::new(Baz { f: 42 }), + &Box::new(Baz { f: 42 }), + Box::new(Box::new(Baz { f: 42 })), true); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/self-in-mut-slot-default-method.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/self/self-in-mut-slot-default-method.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/self-in-mut-slot-default-method.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/self-in-mut-slot-default-method.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] struct X { a: isize @@ -30,7 +29,7 @@ let new_x = x.change(); assert_eq!(new_x.a, 55); - let x: Box<_> = box new_x; + let x: Box<_> = Box::new(new_x); let new_x = x.change_again(); assert_eq!(new_x.a, 45); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/self-re-assign.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/self/self-re-assign.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/self-re-assign.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/self-re-assign.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,13 +2,12 @@ // Ensure assigning an owned or managed variable to itself works. In particular, // that we do not glue_drop before we glue_take (#3290). -#![feature(box_syntax)] #![allow(dead_code)] use std::rc::Rc; pub fn main() { - let mut x: Box<_> = box 3; + let mut x: Box<_> = Box::new(3); x = x; assert_eq!(*x, 3); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/self_type_keyword.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/self/self_type_keyword.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/self_type_keyword.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/self_type_keyword.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -66,10 +66,11 @@ LL | mut Self => (), | ^^^^ not found in this scope | -help: consider importing this unit struct - | -LL | use foo::Self; +note: unit struct `foo::Self` exists but is inaccessible + --> $DIR/self_type_keyword.rs:2:3 | +LL | struct Self; + | ^^^^^^^^^^^^ not accessible error[E0392]: parameter `'Self` is never used --> $DIR/self_type_keyword.rs:6:12 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/ufcs-explicit-self.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/self/ufcs-explicit-self.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/ufcs-explicit-self.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/ufcs-explicit-self.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ // run-pass -#![feature(box_syntax)] +#![allow(dead_code)] #[derive(Copy, Clone)] struct Foo { @@ -36,13 +36,13 @@ } fn main() { - let foo: Box<_> = box Foo { + let foo: Box<_> = Box::new(Foo { f: 1, - }; + }); println!("{} {} {}", foo.foo(2), foo.bar(2), foo.baz(2)); - let bar: Box<_> = box Bar { + let bar: Box<_> = Box::new(Bar { f: 1, - }; + }); println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2)); let bar: Box> = bar; println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2)); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/self/uniq-self-in-mut-slot.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/self/uniq-self-in-mut-slot.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/self/uniq-self-in-mut-slot.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/self/uniq-self-in-mut-slot.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] struct X { a: isize @@ -17,7 +16,7 @@ } pub fn main() { - let x: Box<_> = box X { a: 32 }; + let x: Box<_> = Box::new(X { a: 32 }); let new_x = x.change(); assert_eq!(new_x.a, 55); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/shadowed/shadowed-type-parameter.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/shadowed/shadowed-type-parameter.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/shadowed/shadowed-type-parameter.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/shadowed/shadowed-type-parameter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,9 @@ // Test that shadowed lifetimes generate an error. -#![feature(box_syntax)] struct Foo(T); + impl Foo { fn shadow_in_method(&self) {} //~^ ERROR the name `T` is already used diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/shift-various-bad-types.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/shift-various-bad-types.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/shift-various-bad-types.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/shift-various-bad-types.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -33,7 +33,7 @@ help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | let _: i32 = (22_i64 >> 1_i32).try_into().unwrap(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | + +++++++++++++++++++++ error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/array-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/array-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/array-trait.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/array-trait.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,41 @@ +// Figuring out the size of a vector type that depends on traits doesn't ICE + +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd, platform_intrinsics, generic_const_exprs)] +#![allow(non_camel_case_types, incomplete_features)] + +pub trait Simd { + type Lane: Clone + Copy; + const SIZE: usize; +} + +pub struct i32x4; +impl Simd for i32x4 { + type Lane = i32; + const SIZE: usize = 4; +} + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct T([S::Lane; S::SIZE]); +//~^ ERROR unconstrained generic constant + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; +} + +pub fn main() { + let mut t = T::([0; 4]); + unsafe { + for i in 0_i32..4 { + t = simd_insert(t, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(t, i as u32)); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/array-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/array-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/array-trait.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/array-trait.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/array-trait.rs:23:23 + | +LL | pub struct T([S::Lane; S::SIZE]); + | ^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); S::SIZE]:` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/array-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/array-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/array-type.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/array-type.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,42 @@ +// run-pass +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct S([i32; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct T([i32; N]); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; +} + +pub fn main() { + let mut s = S([0; 4]); + + unsafe { + for i in 0_i32..4 { + s = simd_insert(s, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(s, i as u32)); + } + } + + let mut t = T::<4>([0; 4]); + unsafe { + for i in 0_i32..4 { + t = simd_insert(t, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(t, i as u32)); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/generics.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/generics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/generics.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/generics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,85 @@ +// run-pass +#![allow(non_camel_case_types)] +#![feature(repr_simd, platform_intrinsics)] + +use std::ops; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(f32, f32, f32, f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct A([f32; N]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct B([T; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct C([T; N]); + + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; +} + +fn add>(lhs: T, rhs: T) -> T { + lhs + rhs +} + +impl ops::Add for f32x4 { + type Output = f32x4; + + fn add(self, rhs: f32x4) -> f32x4 { + unsafe { simd_add(self, rhs) } + } +} + +impl ops::Add for A<4> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + unsafe { simd_add(self, rhs) } + } +} + +impl ops::Add for B { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + unsafe { simd_add(self, rhs) } + } +} + +impl ops::Add for C { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + unsafe { simd_add(self, rhs) } + } +} + + +pub fn main() { + let x = [1.0f32, 2.0f32, 3.0f32, 4.0f32]; + let y = [2.0f32, 4.0f32, 6.0f32, 8.0f32]; + + // lame-o + let a = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32); + let f32x4(a0, a1, a2, a3) = add(a, a); + assert_eq!(a0, 2.0f32); + assert_eq!(a1, 4.0f32); + assert_eq!(a2, 6.0f32); + assert_eq!(a3, 8.0f32); + + let a = A(x); + assert_eq!(add(a, a).0, y); + + let b = B(x); + assert_eq!(add(b, b).0, y); + + let c = C(x); + assert_eq!(add(c, c).0, y); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/float-math-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/float-math-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/float-math-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/float-math-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,114 @@ +// run-pass +// ignore-emscripten +// ignore-android + +// FIXME: this test fails on arm-android because the NDK version 14 is too old. +// It needs at least version 18. We disable it on all android build bots because +// there is no way in compile-test to disable it for an (arch,os) pair. + +// Test that the simd floating-point math intrinsics produce correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fsqrt(x: T) -> T; + fn simd_fabs(x: T) -> T; + fn simd_fsin(x: T) -> T; + fn simd_fcos(x: T) -> T; + fn simd_fexp(x: T) -> T; + fn simd_fexp2(x: T) -> T; + fn simd_fma(x: T, y: T, z: T) -> T; + fn simd_flog(x: T) -> T; + fn simd_flog10(x: T) -> T; + fn simd_flog2(x: T) -> T; + fn simd_fpow(x: T, y: T) -> T; + fn simd_fpowi(x: T, y: i32) -> T; + + // rounding functions + fn simd_ceil(x: T) -> T; + fn simd_floor(x: T) -> T; + fn simd_round(x: T) -> T; + fn simd_trunc(x: T) -> T; +} + +macro_rules! assert_approx_eq_f32 { + ($a:expr, $b:expr) => ({ + let (a, b) = (&$a, &$b); + assert!((*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", *a, *b); + }) +} +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => ({ + let a = $a; + let b = $b; + assert_approx_eq_f32!(a.0, b.0); + assert_approx_eq_f32!(a.1, b.1); + assert_approx_eq_f32!(a.2, b.2); + assert_approx_eq_f32!(a.3, b.3); + }) +} + +fn main() { + let x = f32x4(1.0, 1.0, 1.0, 1.0); + let y = f32x4(-1.0, -1.0, -1.0, -1.0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + let h = f32x4(0.5, 0.5, 0.5, 0.5); + + unsafe { + let r = simd_fabs(y); + assert_approx_eq!(x, r); + + let r = simd_fcos(z); + assert_approx_eq!(x, r); + + let r = simd_fexp(z); + assert_approx_eq!(x, r); + + let r = simd_fexp2(z); + assert_approx_eq!(x, r); + + let r = simd_fma(x, h, h); + assert_approx_eq!(x, r); + + let r = simd_fsqrt(x); + assert_approx_eq!(x, r); + + let r = simd_flog(x); + assert_approx_eq!(z, r); + + let r = simd_flog2(x); + assert_approx_eq!(z, r); + + let r = simd_flog10(x); + assert_approx_eq!(z, r); + + let r = simd_fpow(h, x); + assert_approx_eq!(h, r); + + let r = simd_fpowi(h, 1); + assert_approx_eq!(h, r); + + let r = simd_fsin(z); + assert_approx_eq!(z, r); + + // rounding functions + let r = simd_floor(h); + assert_eq!(z, r); + + let r = simd_ceil(h); + assert_eq!(x, r); + + let r = simd_round(h); + assert_eq!(x, r); + + let r = simd_trunc(h); + assert_eq!(z, r); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/float-minmax-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/float-minmax-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/float-minmax-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/float-minmax-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,52 @@ +// run-pass +// ignore-emscripten + +// Test that the simd_f{min,max} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fmin(x: T, y: T) -> T; + fn simd_fmax(x: T, y: T) -> T; +} + +fn main() { + let x = f32x4(1.0, 2.0, 3.0, 4.0); + let y = f32x4(2.0, 1.0, 4.0, 3.0); + + #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] + let nan = f32::NAN; + // MIPS hardware treats f32::NAN as SNAN. Clear the signaling bit. + // See https://github.com/rust-lang/rust/issues/52746. + #[cfg(any(target_arch = "mips", target_arch = "mips64"))] + let nan = f32::from_bits(f32::NAN.to_bits() - 1); + + let n = f32x4(nan, nan, nan, nan); + + unsafe { + let min0 = simd_fmin(x, y); + let min1 = simd_fmin(y, x); + assert_eq!(min0, min1); + let e = f32x4(1.0, 1.0, 3.0, 3.0); + assert_eq!(min0, e); + let minn = simd_fmin(x, n); + assert_eq!(minn, x); + let minn = simd_fmin(y, n); + assert_eq!(minn, y); + + let max0 = simd_fmax(x, y); + let max1 = simd_fmax(y, x); + assert_eq!(max0, max1); + let e = f32x4(2.0, 2.0, 4.0, 4.0); + assert_eq!(max0, e); + let maxn = simd_fmax(x, n); + assert_eq!(maxn, x); + let maxn = simd_fmax(y, n); + assert_eq!(maxn, y); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,103 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_rem(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; + + fn simd_neg(x: T) -> T; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + let y = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_add(x, x); + simd_add(y, y); + simd_add(z, z); + simd_sub(x, x); + simd_sub(y, y); + simd_sub(z, z); + simd_mul(x, x); + simd_mul(y, y); + simd_mul(z, z); + simd_div(x, x); + simd_div(y, y); + simd_div(z, z); + simd_rem(x, x); + simd_rem(y, y); + simd_rem(z, z); + + simd_shl(x, x); + simd_shl(y, y); + simd_shr(x, x); + simd_shr(y, y); + simd_and(x, x); + simd_and(y, y); + simd_or(x, x); + simd_or(y, y); + simd_xor(x, x); + simd_xor(y, y); + + simd_neg(x); + simd_neg(z); + + + simd_add(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_sub(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_mul(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_div(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shl(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shr(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_and(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_or(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_xor(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + simd_neg(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + + simd_shl(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_shr(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_and(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_or(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_xor(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-2.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,93 @@ +error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:69:9 + | +LL | simd_add(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_sub` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:71:9 + | +LL | simd_sub(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_mul` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:73:9 + | +LL | simd_mul(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_div` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:75:9 + | +LL | simd_div(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shl` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:77:9 + | +LL | simd_shl(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shr` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:79:9 + | +LL | simd_shr(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_and` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:81:9 + | +LL | simd_and(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_or` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:83:9 + | +LL | simd_or(0, 0); + | ^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_xor` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:85:9 + | +LL | simd_xor(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_neg` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:88:9 + | +LL | simd_neg(0); + | ^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:92:9 + | +LL | simd_shl(z, z); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:94:9 + | +LL | simd_shr(z, z); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:96:9 + | +LL | simd_and(z, z); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:98:9 + | +LL | simd_or(z, z); + | ^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:100:9 + | +LL | simd_xor(z, z); + | ^^^^^^^^^^^^^^ + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,136 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten FIXME(#45351) hits an LLVM assert + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct U32([u32; N]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +macro_rules! all_eq { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + assert!(a.0 == b.0 && a.1 == b.1 && a.2 == b.2 && a.3 == b.3); + }} +} + +macro_rules! all_eq_ { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + assert!(a.0 == b.0); + }} +} + + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_rem(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; + + fn simd_neg(x: T) -> T; +} + +fn main() { + let x1 = i32x4(1, 2, 3, 4); + let y1 = U32::<4>([1, 2, 3, 4]); + let z1 = f32x4(1.0, 2.0, 3.0, 4.0); + let x2 = i32x4(2, 3, 4, 5); + let y2 = U32::<4>([2, 3, 4, 5]); + let z2 = f32x4(2.0, 3.0, 4.0, 5.0); + + unsafe { + all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9)); + all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9)); + all_eq_!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9])); + all_eq_!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9])); + all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0)); + all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0)); + + all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20)); + all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20)); + all_eq_!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20])); + all_eq_!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20])); + all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0)); + all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0)); + + all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1)); + all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1)); + all_eq_!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1])); + all_eq_!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0])); + all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0)); + all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0)); + + all_eq!(simd_div(x1, x1), i32x4(1, 1, 1, 1)); + all_eq!(simd_div(i32x4(2, 4, 6, 8), i32x4(2, 2, 2, 2)), x1); + all_eq_!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1])); + all_eq_!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1); + all_eq!(simd_div(z1, z1), f32x4(1.0, 1.0, 1.0, 1.0)); + all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0)); + all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0)); + + all_eq!(simd_rem(x1, x1), i32x4(0, 0, 0, 0)); + all_eq!(simd_rem(x2, x1), i32x4(0, 1, 1, 1)); + all_eq_!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0])); + all_eq_!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1])); + all_eq!(simd_rem(z1, z1), f32x4(0.0, 0.0, 0.0, 0.0)); + all_eq!(simd_rem(z1, z2), z1); + all_eq!(simd_rem(z2, z1), f32x4(0.0, 1.0, 1.0, 1.0)); + + all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); + all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + all_eq_!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq_!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4])); + + // test right-shift by assuming left-shift is correct + all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); + all_eq!(simd_shr(simd_shl(x2, x1), x1), x2); + all_eq_!(simd_shr(simd_shl(y1, y2), y2), y1); + all_eq_!(simd_shr(simd_shl(y2, y1), y1), y2); + + // ensure we get logical vs. arithmetic shifts correct + let (a, b, c, d) = (-12, -123, -1234, -12345); + all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4)); + all_eq_!(simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1), + U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4])); + + all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4)); + all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4)); + all_eq_!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4])); + all_eq_!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4])); + + all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5)); + all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5)); + all_eq_!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5])); + all_eq_!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5])); + + all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1)); + all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1)); + all_eq_!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1])); + all_eq_!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); + + all_eq!(simd_neg(x1), i32x4(-1, -2, -3, -4)); + all_eq!(simd_neg(x2), i32x4(-2, -3, -4, -5)); + all_eq!(simd_neg(z1), f32x4(-1.0, -2.0, -3.0, -4.0)); + all_eq!(simd_neg(z2), f32x4(-2.0, -3.0, -4.0, -5.0)); + + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,38 @@ +// build-fail +// ignore-emscripten +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct x4(pub T, pub T, pub T, pub T); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_saturating_add(x: T, y: T) -> T; + fn simd_saturating_sub(x: T, y: T) -> T; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + let y = x4(0_usize, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_saturating_add(x, x); + simd_saturating_add(y, y); + simd_saturating_sub(x, x); + simd_saturating_sub(y, y); + + simd_saturating_add(z, z); + //~^ ERROR expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type + simd_saturating_sub(z, z); + //~^ ERROR expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0511]: invalid monomorphization of `simd_saturating_add` intrinsic: expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type + --> $DIR/generic-arithmetic-saturating-2.rs:33:9 + | +LL | simd_saturating_add(z, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_saturating_sub` intrinsic: expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type + --> $DIR/generic-arithmetic-saturating-2.rs:35:9 + | +LL | simd_saturating_sub(z, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,91 @@ +// run-pass +// ignore-emscripten + +#![allow(non_camel_case_types)] +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct I32([i32; N]); + +extern "platform-intrinsic" { + fn simd_saturating_add(x: T, y: T) -> T; + fn simd_saturating_sub(x: T, y: T) -> T; +} + +fn main() { + // unsigned + { + const M: u32 = u32::MAX; + + let a = u32x4(1, 2, 3, 4); + let b = u32x4(2, 4, 6, 8); + let m = u32x4(M, M, M, M); + let m1 = u32x4(M - 1, M - 1, M - 1, M - 1); + let z = u32x4(0, 0, 0, 0); + + unsafe { + assert_eq!(simd_saturating_add(z, z), z); + assert_eq!(simd_saturating_add(z, a), a); + assert_eq!(simd_saturating_add(b, z), b); + assert_eq!(simd_saturating_add(a, a), b); + assert_eq!(simd_saturating_add(a, m), m); + assert_eq!(simd_saturating_add(m, b), m); + assert_eq!(simd_saturating_add(m1, a), m); + + assert_eq!(simd_saturating_sub(b, z), b); + assert_eq!(simd_saturating_sub(b, a), a); + assert_eq!(simd_saturating_sub(a, a), z); + assert_eq!(simd_saturating_sub(a, b), z); + assert_eq!(simd_saturating_sub(a, m1), z); + assert_eq!(simd_saturating_sub(b, m1), z); + } + } + + // signed + { + const MIN: i32 = i32::MIN; + const MAX: i32 = i32::MAX; + + let a = I32::<4>([1, 2, 3, 4]); + let b = I32::<4>([2, 4, 6, 8]); + let c = I32::<4>([-1, -2, -3, -4]); + let d = I32::<4>([-2, -4, -6, -8]); + + let max = I32::<4>([MAX, MAX, MAX, MAX]); + let max1 = I32::<4>([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); + let min = I32::<4>([MIN, MIN, MIN, MIN]); + let min1 = I32::<4>([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); + + let z = I32::<4>([0, 0, 0, 0]); + + unsafe { + assert_eq!(simd_saturating_add(z, z).0, z.0); + assert_eq!(simd_saturating_add(z, a).0, a.0); + assert_eq!(simd_saturating_add(b, z).0, b.0); + assert_eq!(simd_saturating_add(a, a).0, b.0); + assert_eq!(simd_saturating_add(a, max).0, max.0); + assert_eq!(simd_saturating_add(max, b).0, max.0); + assert_eq!(simd_saturating_add(max1, a).0, max.0); + assert_eq!(simd_saturating_add(min1, z).0, min1.0); + assert_eq!(simd_saturating_add(min, z).0, min.0); + assert_eq!(simd_saturating_add(min1, c).0, min.0); + assert_eq!(simd_saturating_add(min, c).0, min.0); + assert_eq!(simd_saturating_add(min1, d).0, min.0); + assert_eq!(simd_saturating_add(min, d).0, min.0); + + assert_eq!(simd_saturating_sub(b, z).0, b.0); + assert_eq!(simd_saturating_sub(b, a).0, a.0); + assert_eq!(simd_saturating_sub(a, a).0, z.0); + assert_eq!(simd_saturating_sub(a, b).0, c.0); + assert_eq!(simd_saturating_sub(z, max).0, min1.0); + assert_eq!(simd_saturating_sub(min1, z).0, min1.0); + assert_eq!(simd_saturating_sub(min1, a).0, min.0); + assert_eq!(simd_saturating_sub(min1, b).0, min.0); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,62 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten +// ignore-endian-big behavior of simd_bitmask is endian-specific + +// Test that the simd_bitmask intrinsic produces correct results. + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u8x4(pub u8, pub u8, pub u8, pub u8); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct Tx4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_bitmask(x: T) -> U; +} + +fn main() { + let z = u32x4(0, 0, 0, 0); + let ez = 0_u8; + + let o = u32x4(!0, !0, !0, !0); + let eo = 0b_1111_u8; + + let m0 = u32x4(!0, 0, !0, 0); + let e0 = 0b_0000_0101_u8; + + // Check that the MSB is extracted: + let m = u8x4(0b_1000_0000, 0b_0100_0001, 0b_1100_0001, 0b_1111_1111); + let e = 0b_1101; + + // Check usize / isize + let msize: Tx4 = Tx4(usize::MAX, 0, usize::MAX, usize::MAX); + + unsafe { + let r: u8 = simd_bitmask(z); + assert_eq!(r, ez); + + let r: u8 = simd_bitmask(o); + assert_eq!(r, eo); + + let r: u8 = simd_bitmask(m0); + assert_eq!(r, e0); + + let r: u8 = simd_bitmask(m); + assert_eq!(r, e); + + let r: u8 = simd_bitmask(msize); + assert_eq!(r, e); + + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,69 @@ +// build-fail + +// Test that the simd_bitmask intrinsic produces ok-ish error +// messages when misused. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x2([u32; 2]); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4([u32; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x8([u8; 8]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x16([u8; 16]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x32([u8; 32]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x64([u8; 64]); + +extern "platform-intrinsic" { + fn simd_bitmask(x: T) -> U; +} + +fn main() { + let m2 = u32x2([0; 2]); + let m4 = u32x4([0; 4]); + let m8 = u8x8([0; 8]); + let m16 = u8x16([0; 16]); + let m32 = u8x32([0; 32]); + let m64 = u8x64([0; 64]); + + unsafe { + let _: u8 = simd_bitmask(m2); + let _: u8 = simd_bitmask(m4); + let _: u8 = simd_bitmask(m8); + let _: u16 = simd_bitmask(m16); + let _: u32 = simd_bitmask(m32); + let _: u64 = simd_bitmask(m64); + + let _: u16 = simd_bitmask(m2); + //~^ ERROR bitmask `u16`, expected `u8` + + let _: u16 = simd_bitmask(m8); + //~^ ERROR bitmask `u16`, expected `u8` + + let _: u32 = simd_bitmask(m16); + //~^ ERROR bitmask `u32`, expected `u16` + + let _: u64 = simd_bitmask(m32); + //~^ ERROR bitmask `u64`, expected `u32` + + let _: u128 = simd_bitmask(m64); + //~^ ERROR bitmask `u128`, expected `u64` + + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-bitmask.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8` + --> $DIR/generic-bitmask.rs:53:22 + | +LL | let _: u16 = simd_bitmask(m2); + | ^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8` + --> $DIR/generic-bitmask.rs:56:22 + | +LL | let _: u16 = simd_bitmask(m8); + | ^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u32`, expected `u16` + --> $DIR/generic-bitmask.rs:59:22 + | +LL | let _: u32 = simd_bitmask(m16); + | ^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u64`, expected `u32` + --> $DIR/generic-bitmask.rs:62:22 + | +LL | let _: u64 = simd_bitmask(m32); + | ^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u128`, expected `u64` + --> $DIR/generic-bitmask.rs:65:23 + | +LL | let _: u128 = simd_bitmask(m64); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,121 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten FIXME(#45351) hits an LLVM assert + +#![feature(repr_simd, platform_intrinsics, concat_idents, test)] +#![allow(non_camel_case_types)] + +extern crate test; + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i8x4(i8, i8, i8, i8); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct u32x4(u32, u32, u32, u32); +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct u8x4(u8, u8, u8, u8); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct f32x4(f32, f32, f32, f32); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct f64x4(f64, f64, f64, f64); + + +extern "platform-intrinsic" { + fn simd_cast(x: T) -> U; +} + +const A: i32 = -1234567; +const B: i32 = 12345678; +const C: i32 = -123456789; +const D: i32 = 1234567890; + +trait Foo { + fn is_float() -> bool { false } + fn in_range(x: i32) -> bool; +} +impl Foo for i32 { + fn in_range(_: i32) -> bool { true } +} +impl Foo for i8 { + fn in_range(x: i32) -> bool { -128 <= x && x < 128 } +} +impl Foo for u32 { + fn in_range(x: i32) -> bool { 0 <= x } +} +impl Foo for u8 { + fn in_range(x: i32) -> bool { 0 <= x && x < 128 } +} +impl Foo for f32 { + fn is_float() -> bool { true } + fn in_range(_: i32) -> bool { true } +} +impl Foo for f64 { + fn is_float() -> bool { true } + fn in_range(_: i32) -> bool { true } +} + +fn main() { + macro_rules! test { + ($from: ident, $to: ident) => {{ + // force the casts to actually happen, or else LLVM/rustc + // may fold them and get slightly different results. + let (a, b, c, d) = test::black_box((A as $from, B as $from, C as $from, D as $from)); + // the SIMD vectors are all FOOx4, so we can concat_idents + // so we don't have to pass in the extra args to the macro + let mut from = simd_cast(concat_idents!($from, x4)(a, b, c, d)); + let mut to = concat_idents!($to, x4)(a as $to, + b as $to, + c as $to, + d as $to); + // assist type inference, it needs to know what `from` is + // for the `if` statements. + to == from; + + // there are platform differences for some out of range + // casts, so we just normalize such things: it's OK for + // "invalid" calculations to result in nonsense answers. + // (e.g., negative float to unsigned integer goes through a + // library routine on the default i686 platforms, and the + // implementation of that routine differs on e.g., Linux + // vs. macOS, resulting in different answers.) + if $from::is_float() { + if !$to::in_range(A) { from.0 = 0 as $to; to.0 = 0 as $to; } + if !$to::in_range(B) { from.1 = 0 as $to; to.1 = 0 as $to; } + if !$to::in_range(C) { from.2 = 0 as $to; to.2 = 0 as $to; } + if !$to::in_range(D) { from.3 = 0 as $to; to.3 = 0 as $to; } + } + + assert!(to == from, + "{} -> {} ({:?} != {:?})", stringify!($from), stringify!($to), + from, to); + }} + } + macro_rules! tests { + (: $($to: ident),*) => { () }; + // repeating the list twice is easier than writing a cartesian + // product macro + ($from: ident $(, $from_: ident)*: $($to: ident),*) => { + fn $from() { unsafe { $( test!($from, $to); )* } } + tests!($($from_),*: $($to),*) + }; + ($($types: ident),*) => {{ + tests!($($types),* : $($types),*); + $($types();)* + }} + } + + // test various combinations, including truncation, + // signed/unsigned extension, and floating point casts. + tests!(i32, i8, u32, u8, f32); + tests!(i32, u32, f32, f64) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,43 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x8(f32, f32, f32, f32, + f32, f32, f32, f32); + + +extern "platform-intrinsic" { + fn simd_cast(x: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_cast::(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_cast::(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_cast::(x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_cast::<_, i32x8>(x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i32x8` with length 8 + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-cast.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,27 @@ +error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-cast.rs:34:9 + | +LL | simd_cast::(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-cast.rs:36:9 + | +LL | simd_cast::(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-cast.rs:38:9 + | +LL | simd_cast::(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i32x8` with length 8 + --> $DIR/generic-cast.rs:40:9 + | +LL | simd_cast::<_, i32x8>(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,106 @@ +// run-pass +// ignore-emscripten FIXME(#45351) hits an LLVM assert +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + +#![feature(repr_simd, platform_intrinsics, concat_idents)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_eq(x: T, y: T) -> U; + fn simd_ne(x: T, y: T) -> U; + fn simd_lt(x: T, y: T) -> U; + fn simd_le(x: T, y: T) -> U; + fn simd_gt(x: T, y: T) -> U; + fn simd_ge(x: T, y: T) -> U; +} + +macro_rules! cmp { + ($method: ident($lhs: expr, $rhs: expr)) => {{ + let lhs = $lhs; + let rhs = $rhs; + let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs); + // assume the scalar version is correct/the behaviour we want. + assert!((e.0 != 0) == lhs.0 .$method(&rhs.0)); + assert!((e.1 != 0) == lhs.1 .$method(&rhs.1)); + assert!((e.2 != 0) == lhs.2 .$method(&rhs.2)); + assert!((e.3 != 0) == lhs.3 .$method(&rhs.3)); + }} +} +macro_rules! tests { + ($($lhs: ident, $rhs: ident;)*) => {{ + $( + (|| { + cmp!(eq($lhs, $rhs)); + cmp!(ne($lhs, $rhs)); + + // test both directions + cmp!(lt($lhs, $rhs)); + cmp!(lt($rhs, $lhs)); + + cmp!(le($lhs, $rhs)); + cmp!(le($rhs, $lhs)); + + cmp!(gt($lhs, $rhs)); + cmp!(gt($rhs, $lhs)); + + cmp!(ge($lhs, $rhs)); + cmp!(ge($rhs, $lhs)); + })(); + )* + }} +} +fn main() { + // 13 vs. -100 tests that we get signed vs. unsigned comparisons + // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); + let i1 = i32x4(10, -11, 12, 13); + let i2 = i32x4(5, -5, 20, -100); + let i3 = i32x4(10, -11, 20, -100); + + let u1 = u32x4(10, !11+1, 12, 13); + let u2 = u32x4(5, !5+1, 20, !100+1); + let u3 = u32x4(10, !11+1, 20, !100+1); + + let f1 = f32x4(10.0, -11.0, 12.0, 13.0); + let f2 = f32x4(5.0, -5.0, 20.0, -100.0); + let f3 = f32x4(10.0, -11.0, 20.0, -100.0); + + unsafe { + tests! { + i1, i1; + u1, u1; + f1, f1; + + i1, i2; + u1, u2; + f1, f2; + + i1, i3; + u1, u3; + f1, f3; + } + } + + // NAN comparisons are special: + // -11 (*) 13 + // -5 -100 (*) + let f4 = f32x4(f32::NAN, f1.1, f32::NAN, f2.3); + + unsafe { + tests! { + f1, f4; + f2, f4; + f4, f4; + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,67 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i16x8(i16, i16, i16, i16, + i16, i16, i16, i16); + +extern "platform-intrinsic" { + fn simd_eq(x: T, y: T) -> U; + fn simd_ne(x: T, y: T) -> U; + fn simd_lt(x: T, y: T) -> U; + fn simd_le(x: T, y: T) -> U; + fn simd_gt(x: T, y: T) -> U; + fn simd_ge(x: T, y: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_eq::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_ne::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_lt::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_le::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_gt::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_ge::(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + simd_eq::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_ne::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_lt::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_le::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_gt::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_ge::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + + simd_eq::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_ne::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_lt::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_le::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_gt::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_ge::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-comparison.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,111 @@ +error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:28:9 + | +LL | simd_eq::(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:30:9 + | +LL | simd_ne::(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:32:9 + | +LL | simd_lt::(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:34:9 + | +LL | simd_le::(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:36:9 + | +LL | simd_gt::(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:38:9 + | +LL | simd_ge::(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:41:9 + | +LL | simd_eq::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:43:9 + | +LL | simd_ne::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:45:9 + | +LL | simd_lt::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:47:9 + | +LL | simd_le::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:49:9 + | +LL | simd_gt::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:51:9 + | +LL | simd_ge::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:54:9 + | +LL | simd_eq::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:56:9 + | +LL | simd_ne::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:58:9 + | +LL | simd_lt::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:60:9 + | +LL | simd_le::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:62:9 + | +LL | simd_gt::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:64:9 + | +LL | simd_ge::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 18 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,103 @@ +// run-pass +// ignore-emscripten FIXME(#45351) hits an LLVM assert + +#![feature(repr_simd, platform_intrinsics)] +#![allow(incomplete_features)] +#![feature(inline_const)] + +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; + + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; +} + +macro_rules! all_eq { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + // type inference works better with the concrete type on the + // left, but humans work better with the expected on the + // right. + assert!(b == a, + "{:?} != {:?}", a, b); + }} +} + +fn main() { + let x2 = i32x2(20, 21); + let x4 = i32x4(40, 41, 42, 43); + let x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); + unsafe { + all_eq!(simd_insert(x2, 0, 100), i32x2(100, 21)); + all_eq!(simd_insert(x2, 1, 100), i32x2(20, 100)); + + all_eq!(simd_insert(x4, 0, 100), i32x4(100, 41, 42, 43)); + all_eq!(simd_insert(x4, 1, 100), i32x4(40, 100, 42, 43)); + all_eq!(simd_insert(x4, 2, 100), i32x4(40, 41, 100, 43)); + all_eq!(simd_insert(x4, 3, 100), i32x4(40, 41, 42, 100)); + + all_eq!(simd_insert(x8, 0, 100), i32x8(100, 81, 82, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 1, 100), i32x8(80, 100, 82, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 2, 100), i32x8(80, 81, 100, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 3, 100), i32x8(80, 81, 82, 100, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 4, 100), i32x8(80, 81, 82, 83, 100, 85, 86, 87)); + all_eq!(simd_insert(x8, 5, 100), i32x8(80, 81, 82, 83, 84, 100, 86, 87)); + all_eq!(simd_insert(x8, 6, 100), i32x8(80, 81, 82, 83, 84, 85, 100, 87)); + all_eq!(simd_insert(x8, 7, 100), i32x8(80, 81, 82, 83, 84, 85, 86, 100)); + + all_eq!(simd_extract(x2, 0), 20); + all_eq!(simd_extract(x2, 1), 21); + + all_eq!(simd_extract(x4, 0), 40); + all_eq!(simd_extract(x4, 1), 41); + all_eq!(simd_extract(x4, 2), 42); + all_eq!(simd_extract(x4, 3), 43); + + all_eq!(simd_extract(x8, 0), 80); + all_eq!(simd_extract(x8, 1), 81); + all_eq!(simd_extract(x8, 2), 82); + all_eq!(simd_extract(x8, 3), 83); + all_eq!(simd_extract(x8, 4), 84); + all_eq!(simd_extract(x8, 5), 85); + all_eq!(simd_extract(x8, 6), 86); + all_eq!(simd_extract(x8, 7), 87); + } + + let y2 = i32x2(120, 121); + let y4 = i32x4(140, 141, 142, 143); + let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); + unsafe { + all_eq!(simd_shuffle2(x2, y2, const { [3u32, 0] }), i32x2(121, 20)); + all_eq!(simd_shuffle4(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120)); + all_eq!(simd_shuffle8(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }), + i32x8(121, 20, 21, 120, 21, 120, 121, 20)); + + all_eq!(simd_shuffle2(x4, y4, const { [7u32, 2] }), i32x2(143, 42)); + all_eq!(simd_shuffle4(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40)); + all_eq!(simd_shuffle8(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }), + i32x8(143, 42, 141, 40, 43, 142, 140, 41)); + + all_eq!(simd_shuffle2(x8, y8, const { [11u32, 5] }), i32x2(183, 85)); + all_eq!(simd_shuffle4(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80)); + all_eq!(simd_shuffle8(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }), + i32x8(183, 85, 187, 80, 83, 180, 184, 81)); + } + +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,77 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics, rustc_attrs)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x2(f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x8(f32, f32, f32, f32, + f32, f32, f32, f32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; + + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_insert(0, 0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_insert(x, 0, 1.0); + //~^ ERROR expected inserted type `i32` (element of input `i32x4`), found `f64` + simd_extract::<_, f32>(x, 0); + //~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32` + + const IDX2: [u32; 2] = [0; 2]; + simd_shuffle2::(0, 0, IDX2); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + const IDX4: [u32; 4] = [0; 4]; + simd_shuffle4::(0, 0, IDX4); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + const IDX8: [u32; 8] = [0; 8]; + simd_shuffle8::(0, 0, IDX8); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + simd_shuffle2::<_, f32x2>(x, x, IDX2); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + simd_shuffle4::<_, f32x4>(x, x, IDX4); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + simd_shuffle8::<_, f32x8>(x, x, IDX8); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + + simd_shuffle2::<_, i32x8>(x, x, IDX2); + //~^ ERROR expected return type of length 2, found `i32x8` with length 8 + simd_shuffle4::<_, i32x8>(x, x, IDX4); + //~^ ERROR expected return type of length 4, found `i32x8` with length 8 + simd_shuffle8::<_, i32x2>(x, x, IDX8); + //~^ ERROR expected return type of length 8, found `i32x2` with length 2 + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-elements.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,75 @@ +error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:46:9 + | +LL | simd_insert(0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64` + --> $DIR/generic-elements.rs:48:9 + | +LL | simd_insert(x, 0, 1.0); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32` + --> $DIR/generic-elements.rs:50:9 + | +LL | simd_extract::<_, f32>(x, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:54:9 + | +LL | simd_shuffle2::(0, 0, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:57:9 + | +LL | simd_shuffle4::(0, 0, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:60:9 + | +LL | simd_shuffle8::(0, 0, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + --> $DIR/generic-elements.rs:63:9 + | +LL | simd_shuffle2::<_, f32x2>(x, x, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + --> $DIR/generic-elements.rs:65:9 + | +LL | simd_shuffle4::<_, f32x4>(x, x, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + --> $DIR/generic-elements.rs:67:9 + | +LL | simd_shuffle8::<_, f32x8>(x, x, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return type of length 2, found `i32x8` with length 8 + --> $DIR/generic-elements.rs:70:9 + | +LL | simd_shuffle2::<_, i32x8>(x, x, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x8` with length 8 + --> $DIR/generic-elements.rs:72:9 + | +LL | simd_shuffle4::<_, i32x8>(x, x, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return type of length 8, found `i32x2` with length 2 + --> $DIR/generic-elements.rs:74:9 + | +LL | simd_shuffle8::<_, i32x2>(x, x, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-gather-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-gather-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-gather-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-gather-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,141 @@ +// run-pass +// ignore-emscripten + +// Test that the simd_{gather,scatter} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct x4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather(x: T, y: U, z: V) -> T; + fn simd_scatter(x: T, y: U, z: V) -> (); +} + +fn main() { + let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; + + let default = x4(-3_f32, -3., -3., -3.); + let s_strided = x4(0_f32, 2., -3., 6.); + let mask = x4(-1_i32, -1, 0, -1); + + // reading from *const + unsafe { + let pointer = &x[0] as *const f32; + let pointers = x4( + pointer.offset(0) as *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // reading from *mut + unsafe { + let pointer = &mut x[0] as *mut f32; + let pointers = x4( + pointer.offset(0) as *mut f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // writing to *mut + unsafe { + let pointer = &mut x[0] as *mut f32; + let pointers = x4( + pointer.offset(0) as *mut f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let values = x4(42_f32, 43_f32, 44_f32, 45_f32); + simd_scatter(values, pointers, mask); + + assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); + } + + // test modifying array of *const f32 + let mut y = [ + &x[0] as *const f32, + &x[1] as *const f32, + &x[2] as *const f32, + &x[3] as *const f32, + &x[4] as *const f32, + &x[5] as *const f32, + &x[6] as *const f32, + &x[7] as *const f32 + ]; + + let default = x4(y[0], y[0], y[0], y[0]); + let s_strided = x4(y[0], y[2], y[0], y[6]); + + // reading from *const + unsafe { + let pointer = &y[0] as *const *const f32; + let pointers = x4( + pointer.offset(0) as *const *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // reading from *mut + unsafe { + let pointer = &mut y[0] as *mut *const f32; + let pointers = x4( + pointer.offset(0) as *mut *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // writing to *mut + unsafe { + let pointer = &mut y[0] as *mut *const f32; + let pointers = x4( + pointer.offset(0) as *mut *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let values = x4(y[7], y[6], y[5], y[1]); + simd_scatter(values, pointers, mask); + + let s = [ + &x[7] as *const f32, + &x[1] as *const f32, + &x[6] as *const f32, + &x[3] as *const f32, + &x[4] as *const f32, + &x[5] as *const f32, + &x[1] as *const f32, + &x[7] as *const f32 + ]; + assert_eq!(y, s); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,155 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten + +// Test that the simd_reduce_{op} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct b8x4(pub i8, pub i8, pub i8, pub i8); + +extern "platform-intrinsic" { + fn simd_reduce_add_unordered(x: T) -> U; + fn simd_reduce_mul_unordered(x: T) -> U; + fn simd_reduce_add_ordered(x: T, acc: U) -> U; + fn simd_reduce_mul_ordered(x: T, acc: U) -> U; + fn simd_reduce_min(x: T) -> U; + fn simd_reduce_max(x: T) -> U; + fn simd_reduce_min_nanless(x: T) -> U; + fn simd_reduce_max_nanless(x: T) -> U; + fn simd_reduce_and(x: T) -> U; + fn simd_reduce_or(x: T) -> U; + fn simd_reduce_xor(x: T) -> U; + fn simd_reduce_all(x: T) -> bool; + fn simd_reduce_any(x: T) -> bool; +} + +fn main() { + unsafe { + let x = i32x4(1, -2, 3, 4); + let r: i32 = simd_reduce_add_unordered(x); + assert_eq!(r, 6_i32); + let r: i32 = simd_reduce_mul_unordered(x); + assert_eq!(r, -24_i32); + let r: i32 = simd_reduce_add_ordered(x, -1); + assert_eq!(r, 5_i32); + let r: i32 = simd_reduce_mul_ordered(x, -1); + assert_eq!(r, 24_i32); + + let r: i32 = simd_reduce_min(x); + assert_eq!(r, -2_i32); + let r: i32 = simd_reduce_max(x); + assert_eq!(r, 4_i32); + + let x = i32x4(-1, -1, -1, -1); + let r: i32 = simd_reduce_and(x); + assert_eq!(r, -1_i32); + let r: i32 = simd_reduce_or(x); + assert_eq!(r, -1_i32); + let r: i32 = simd_reduce_xor(x); + assert_eq!(r, 0_i32); + + let x = i32x4(-1, -1, 0, -1); + let r: i32 = simd_reduce_and(x); + assert_eq!(r, 0_i32); + let r: i32 = simd_reduce_or(x); + assert_eq!(r, -1_i32); + let r: i32 = simd_reduce_xor(x); + assert_eq!(r, -1_i32); + } + + unsafe { + let x = u32x4(1, 2, 3, 4); + let r: u32 = simd_reduce_add_unordered(x); + assert_eq!(r, 10_u32); + let r: u32 = simd_reduce_mul_unordered(x); + assert_eq!(r, 24_u32); + let r: u32 = simd_reduce_add_ordered(x, 1); + assert_eq!(r, 11_u32); + let r: u32 = simd_reduce_mul_ordered(x, 2); + assert_eq!(r, 48_u32); + + let r: u32 = simd_reduce_min(x); + assert_eq!(r, 1_u32); + let r: u32 = simd_reduce_max(x); + assert_eq!(r, 4_u32); + + let t = u32::MAX; + let x = u32x4(t, t, t, t); + let r: u32 = simd_reduce_and(x); + assert_eq!(r, t); + let r: u32 = simd_reduce_or(x); + assert_eq!(r, t); + let r: u32 = simd_reduce_xor(x); + assert_eq!(r, 0_u32); + + let x = u32x4(t, t, 0, t); + let r: u32 = simd_reduce_and(x); + assert_eq!(r, 0_u32); + let r: u32 = simd_reduce_or(x); + assert_eq!(r, t); + let r: u32 = simd_reduce_xor(x); + assert_eq!(r, t); + } + + unsafe { + let x = f32x4(1., -2., 3., 4.); + let r: f32 = simd_reduce_add_unordered(x); + assert_eq!(r, 6_f32); + let r: f32 = simd_reduce_mul_unordered(x); + assert_eq!(r, -24_f32); + let r: f32 = simd_reduce_add_ordered(x, 0.); + assert_eq!(r, 6_f32); + let r: f32 = simd_reduce_mul_ordered(x, 1.); + assert_eq!(r, -24_f32); + let r: f32 = simd_reduce_add_ordered(x, 1.); + assert_eq!(r, 7_f32); + let r: f32 = simd_reduce_mul_ordered(x, 2.); + assert_eq!(r, -48_f32); + + let r: f32 = simd_reduce_min(x); + assert_eq!(r, -2_f32); + let r: f32 = simd_reduce_max(x); + assert_eq!(r, 4_f32); + let r: f32 = simd_reduce_min_nanless(x); + assert_eq!(r, -2_f32); + let r: f32 = simd_reduce_max_nanless(x); + assert_eq!(r, 4_f32); + } + + unsafe { + let x = b8x4(!0, !0, !0, !0); + let r: bool = simd_reduce_all(x); + assert_eq!(r, true); + let r: bool = simd_reduce_any(x); + assert_eq!(r, true); + + let x = b8x4(!0, !0, 0, !0); + let r: bool = simd_reduce_all(x); + assert_eq!(r, false); + let r: bool = simd_reduce_any(x); + assert_eq!(r, true); + + let x = b8x4(0, 0, 0, 0); + let r: bool = simd_reduce_all(x); + assert_eq!(r, false); + let r: bool = simd_reduce_any(x); + assert_eq!(r, false); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,58 @@ +// build-fail +// ignore-emscripten + +// Test that the simd_reduce_{op} intrinsics produce ok-ish error +// messages when misused. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + + +extern "platform-intrinsic" { + fn simd_reduce_add_ordered(x: T, y: U) -> U; + fn simd_reduce_mul_ordered(x: T, y: U) -> U; + fn simd_reduce_and(x: T) -> U; + fn simd_reduce_or(x: T) -> U; + fn simd_reduce_xor(x: T) -> U; + fn simd_reduce_all(x: T) -> bool; + fn simd_reduce_any(x: T) -> bool; +} + +fn main() { + let x = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_reduce_add_ordered(z, 0); + //~^ ERROR expected return type `f32` (element of input `f32x4`), found `i32` + simd_reduce_mul_ordered(z, 1); + //~^ ERROR expected return type `f32` (element of input `f32x4`), found `i32` + + let _: f32 = simd_reduce_and(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + let _: f32 = simd_reduce_or(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + let _: f32 = simd_reduce_xor(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + + let _: f32 = simd_reduce_and(z); + //~^ ERROR unsupported simd_reduce_and from `f32x4` with element `f32` to `f32` + let _: f32 = simd_reduce_or(z); + //~^ ERROR unsupported simd_reduce_or from `f32x4` with element `f32` to `f32` + let _: f32 = simd_reduce_xor(z); + //~^ ERROR unsupported simd_reduce_xor from `f32x4` with element `f32` to `f32` + + let _: bool = simd_reduce_all(z); + //~^ ERROR unsupported simd_reduce_all from `f32x4` with element `f32` to `bool` + let _: bool = simd_reduce_any(z); + //~^ ERROR unsupported simd_reduce_any from `f32x4` with element `f32` to `bool` + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-reduction.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,63 @@ +error[E0511]: invalid monomorphization of `simd_reduce_add_ordered` intrinsic: expected return type `f32` (element of input `f32x4`), found `i32` + --> $DIR/generic-reduction.rs:34:9 + | +LL | simd_reduce_add_ordered(z, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_mul_ordered` intrinsic: expected return type `f32` (element of input `f32x4`), found `i32` + --> $DIR/generic-reduction.rs:36:9 + | +LL | simd_reduce_mul_ordered(z, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_and` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` + --> $DIR/generic-reduction.rs:39:22 + | +LL | let _: f32 = simd_reduce_and(x); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_or` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` + --> $DIR/generic-reduction.rs:41:22 + | +LL | let _: f32 = simd_reduce_or(x); + | ^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_xor` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` + --> $DIR/generic-reduction.rs:43:22 + | +LL | let _: f32 = simd_reduce_xor(x); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_and` intrinsic: unsupported simd_reduce_and from `f32x4` with element `f32` to `f32` + --> $DIR/generic-reduction.rs:46:22 + | +LL | let _: f32 = simd_reduce_and(z); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_or` intrinsic: unsupported simd_reduce_or from `f32x4` with element `f32` to `f32` + --> $DIR/generic-reduction.rs:48:22 + | +LL | let _: f32 = simd_reduce_or(z); + | ^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_xor` intrinsic: unsupported simd_reduce_xor from `f32x4` with element `f32` to `f32` + --> $DIR/generic-reduction.rs:50:22 + | +LL | let _: f32 = simd_reduce_xor(z); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_all` intrinsic: unsupported simd_reduce_all from `f32x4` with element `f32` to `bool` + --> $DIR/generic-reduction.rs:53:23 + | +LL | let _: bool = simd_reduce_all(z); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_any` intrinsic: unsupported simd_reduce_any from `f32x4` with element `f32` to `bool` + --> $DIR/generic-reduction.rs:55:23 + | +LL | let _: bool = simd_reduce_any(z); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select-pass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select-pass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select-pass.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select-pass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,195 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten +// ignore-endian-big behavior of simd_select_bitmask is endian-specific + +// Test that the simd_select intrinsics produces correct results. + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u32x8(u32, u32, u32, u32, u32, u32, u32, u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct b8x4(pub i8, pub i8, pub i8, pub i8); + +extern "platform-intrinsic" { + fn simd_select(x: T, a: U, b: U) -> U; + fn simd_select_bitmask(x: T, a: U, b: U) -> U; +} + +fn main() { + let m0 = b8x4(!0, !0, !0, !0); + let m1 = b8x4(0, 0, 0, 0); + let m2 = b8x4(!0, !0, 0, 0); + let m3 = b8x4(0, 0, !0, !0); + let m4 = b8x4(!0, 0, !0, 0); + + unsafe { + let a = i32x4(1, -2, 3, 4); + let b = i32x4(5, 6, -7, 8); + + let r: i32x4 = simd_select(m0, a, b); + let e = a; + assert_eq!(r, e); + + let r: i32x4 = simd_select(m1, a, b); + let e = b; + assert_eq!(r, e); + + let r: i32x4 = simd_select(m2, a, b); + let e = i32x4(1, -2, -7, 8); + assert_eq!(r, e); + + let r: i32x4 = simd_select(m3, a, b); + let e = i32x4(5, 6, 3, 4); + assert_eq!(r, e); + + let r: i32x4 = simd_select(m4, a, b); + let e = i32x4(1, 6, 3, 8); + assert_eq!(r, e); + } + + unsafe { + let a = u32x4(1, 2, 3, 4); + let b = u32x4(5, 6, 7, 8); + + let r: u32x4 = simd_select(m0, a, b); + let e = a; + assert_eq!(r, e); + + let r: u32x4 = simd_select(m1, a, b); + let e = b; + assert_eq!(r, e); + + let r: u32x4 = simd_select(m2, a, b); + let e = u32x4(1, 2, 7, 8); + assert_eq!(r, e); + + let r: u32x4 = simd_select(m3, a, b); + let e = u32x4(5, 6, 3, 4); + assert_eq!(r, e); + + let r: u32x4 = simd_select(m4, a, b); + let e = u32x4(1, 6, 3, 8); + assert_eq!(r, e); + } + + unsafe { + let a = f32x4(1., 2., 3., 4.); + let b = f32x4(5., 6., 7., 8.); + + let r: f32x4 = simd_select(m0, a, b); + let e = a; + assert_eq!(r, e); + + let r: f32x4 = simd_select(m1, a, b); + let e = b; + assert_eq!(r, e); + + let r: f32x4 = simd_select(m2, a, b); + let e = f32x4(1., 2., 7., 8.); + assert_eq!(r, e); + + let r: f32x4 = simd_select(m3, a, b); + let e = f32x4(5., 6., 3., 4.); + assert_eq!(r, e); + + let r: f32x4 = simd_select(m4, a, b); + let e = f32x4(1., 6., 3., 8.); + assert_eq!(r, e); + } + + unsafe { + let t = !0 as i8; + let f = 0 as i8; + let a = b8x4(t, f, t, f); + let b = b8x4(f, f, f, t); + + let r: b8x4 = simd_select(m0, a, b); + let e = a; + assert_eq!(r, e); + + let r: b8x4 = simd_select(m1, a, b); + let e = b; + assert_eq!(r, e); + + let r: b8x4 = simd_select(m2, a, b); + let e = b8x4(t, f, f, t); + assert_eq!(r, e); + + let r: b8x4 = simd_select(m3, a, b); + let e = b8x4(f, f, t, f); + assert_eq!(r, e); + + let r: b8x4 = simd_select(m4, a, b); + let e = b8x4(t, f, t, t); + assert_eq!(r, e); + } + + unsafe { + let a = u32x8(0, 1, 2, 3, 4, 5, 6, 7); + let b = u32x8(8, 9, 10, 11, 12, 13, 14, 15); + + let r: u32x8 = simd_select_bitmask(0u8, a, b); + let e = b; + assert_eq!(r, e); + + let r: u32x8 = simd_select_bitmask(0xffu8, a, b); + let e = a; + assert_eq!(r, e); + + let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b); + let e = u32x8(0, 9, 2, 11, 4, 13, 6, 15); + assert_eq!(r, e); + + let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b); + let e = u32x8(8, 1, 10, 3, 12, 5, 14, 7); + assert_eq!(r, e); + + let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b); + let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7); + assert_eq!(r, e); + } + + unsafe { + let a = u32x4(0, 1, 2, 3); + let b = u32x4(4, 5, 6, 7); + + let r: u32x4 = simd_select_bitmask(0u8, a, b); + let e = b; + assert_eq!(r, e); + + let r: u32x4 = simd_select_bitmask(0xfu8, a, b); + let e = a; + assert_eq!(r, e); + + let r: u32x4 = simd_select_bitmask(0b0101u8, a, b); + let e = u32x4(0, 5, 2, 7); + assert_eq!(r, e); + + let r: u32x4 = simd_select_bitmask(0b1010u8, a, b); + let e = u32x4(4, 1, 6, 3); + assert_eq!(r, e); + + let r: u32x4 = simd_select_bitmask(0b1100u8, a, b); + let e = u32x4(4, 5, 2, 3); + assert_eq!(r, e); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,64 @@ +// build-fail + +// Test that the simd_select intrinsic produces ok-ish error +// messages when misused. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq)] +struct b8x4(pub i8, pub i8, pub i8, pub i8); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq)] +struct b8x8(pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8); + +extern "platform-intrinsic" { + fn simd_select(x: T, a: U, b: U) -> U; + fn simd_select_bitmask(x: T, a: U, b: U) -> U; +} + +fn main() { + let m4 = b8x4(0, 0, 0, 0); + let m8 = b8x8(0, 0, 0, 0, 0, 0, 0, 0); + let x = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_select(m4, x, x); + + simd_select(m8, x, x); + //~^ ERROR mismatched lengths: mask length `8` != other vector length `4` + + simd_select(x, x, x); + //~^ ERROR mask element type is `u32`, expected `i_` + + simd_select(z, z, z); + //~^ ERROR mask element type is `f32`, expected `i_` + + simd_select(m4, 0u32, 1u32); + //~^ ERROR found non-SIMD `u32` + + simd_select_bitmask(0u16, x, x); + //~^ ERROR mask length `16` != other vector length `4` + // + simd_select_bitmask(0u8, 1u32, 2u32); + //~^ ERROR found non-SIMD `u32` + + simd_select_bitmask(0.0f32, x, x); + //~^ ERROR `f32` is not an integral type + + simd_select_bitmask("x", x, x); + //~^ ERROR `&str` is not an integral type + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-select.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +error[E0511]: invalid monomorphization of `simd_select` intrinsic: mismatched lengths: mask length `8` != other vector length `4` + --> $DIR/generic-select.rs:40:9 + | +LL | simd_select(m8, x, x); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `u32`, expected `i_` + --> $DIR/generic-select.rs:43:9 + | +LL | simd_select(x, x, x); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `f32`, expected `i_` + --> $DIR/generic-select.rs:46:9 + | +LL | simd_select(z, z, z); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32` + --> $DIR/generic-select.rs:49:9 + | +LL | simd_select(m4, 0u32, 1u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `16` != other vector length `4` + --> $DIR/generic-select.rs:52:9 + | +LL | simd_select_bitmask(0u16, x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32` + --> $DIR/generic-select.rs:55:9 + | +LL | simd_select_bitmask(0u8, 1u32, 2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type + --> $DIR/generic-select.rs:58:9 + | +LL | simd_select_bitmask(0.0f32, x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type + --> $DIR/generic-select.rs:61:9 + | +LL | simd_select_bitmask("x", x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-shuffle.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-shuffle.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-shuffle.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-shuffle.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +// build-fail + +// Test that the simd_shuffle intrinsic produces ok-ish error +// messages when misused. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct Simd([T; N]); + +extern "platform-intrinsic" { + fn simd_shuffle(a: T, b: T, i: I) -> U; +} + +fn main() { + const I: [u32; 2] = [0; 2]; + const I2: [f32; 2] = [0.; 2]; + let v = Simd::([0; 4]); + + unsafe { + let _: Simd = simd_shuffle(v, v, I); + + let _: Simd = simd_shuffle(v, v, I); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + + let _: Simd = simd_shuffle(v, v, I); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + + let _: Simd = simd_shuffle(v, v, I2); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-shuffle.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-shuffle.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-shuffle.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/generic-shuffle.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd` with length 4 + --> $DIR/generic-shuffle.rs:24:31 + | +LL | let _: Simd = simd_shuffle(v, v, I); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd`), found `Simd` with element type `f32` + --> $DIR/generic-shuffle.rs:27:31 + | +LL | let _: Simd = simd_shuffle(v, v, I); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: simd_shuffle index must be an array of `u32`, got `[f32; 2]` + --> $DIR/generic-shuffle.rs:30:31 + | +LL | let _: Simd = simd_shuffle(v, v, I2); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/inlining-issue67557-ice.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/inlining-issue67557-ice.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/inlining-issue67557-ice.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/inlining-issue67557-ice.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,26 @@ +// This used to cause an ICE for an internal index out of range due to simd_shuffle_indices being +// passed the wrong Instance, causing issues with inlining. See #67557. +// +// run-pass +// compile-flags: -Zmir-opt-level=4 +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; +} + +#[repr(simd)] +#[derive(Debug, PartialEq)] +struct Simd2(u8, u8); + +fn main() { + unsafe { + let _: Simd2 = inline_me(); + } +} + +#[inline(always)] +unsafe fn inline_me() -> Simd2 { + const IDX: [u32; 2] = [0, 3]; + simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/inlining-issue67557.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/inlining-issue67557.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/inlining-issue67557.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/inlining-issue67557.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,42 @@ +// This used to cause assert_10_13 to unexpectingly fail, due to simd_shuffle_indices being passed +// the wrong Instance, causing issues with inlining. See #67557. +// +// run-pass +// compile-flags: -Zmir-opt-level=4 +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; +} + +#[repr(simd)] +#[derive(Debug, PartialEq)] +struct Simd2(u8, u8); + +fn main() { + unsafe { + const IDX: [u32; 2] = [0, 1]; + let p_res: Simd2 = simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX); + let a_res: Simd2 = inline_me(); + + assert_10_11(p_res); + assert_10_13(a_res); + } +} + +#[inline(never)] +fn assert_10_11(x: Simd2) { + assert_eq!(x, Simd2(10, 11)); +} + +#[inline(never)] +fn assert_10_13(x: Simd2) { + assert_eq!(x, Simd2(10, 13)); +} + + +#[inline(always)] +unsafe fn inline_me() -> Simd2 { + const IDX: [u32; 2] = [0, 3]; + simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/issue-85855.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/issue-85855.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/issue-85855.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/issue-85855.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,19 @@ +// Check that appropriate errors are reported if an intrinsic is defined +// with the wrong number of generic lifetime/type/const parameters, and +// that no ICE occurs in these cases. + +#![feature(platform_intrinsics)] +#![crate_type="lib"] + +extern "platform-intrinsic" { + fn simd_saturating_add<'a, T: 'a>(x: T, y: T); + //~^ ERROR: intrinsic has wrong number of lifetime parameters + + fn simd_add<'a, T>(x: T, y: T) -> T; + + fn simd_sub(x: T, y: U); + //~^ ERROR: intrinsic has wrong number of type parameters + + fn simd_mul(x: T, y: T); + //~^ ERROR: intrinsic has wrong number of const parameters +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/issue-85855.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/issue-85855.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/intrinsic/issue-85855.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/intrinsic/issue-85855.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0094]: intrinsic has wrong number of lifetime parameters: found 1, expected 0 + --> $DIR/issue-85855.rs:9:27 + | +LL | fn simd_saturating_add<'a, T: 'a>(x: T, y: T); + | ^^^^^^^^^^^ expected 0 lifetime parameters + +error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1 + --> $DIR/issue-85855.rs:14:16 + | +LL | fn simd_sub(x: T, y: U); + | ^^^^^^ expected 1 type parameter + +error[E0094]: intrinsic has wrong number of const parameters: found 1, expected 0 + --> $DIR/issue-85855.rs:17:16 + | +LL | fn simd_mul(x: T, y: T); + | ^^^^^^^^^^^^^^^^^^^ expected 0 const parameters + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0094`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/issue-89193.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/issue-89193.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/issue-89193.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/issue-89193.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,51 @@ +// run-pass + +// Test that simd gather instructions on slice of usize don't cause crash +// See issue #89183 - https://github.com/rust-lang/rust/issues/89193 + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct x4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather(x: T, y: U, z: V) -> T; +} + +fn main() { + let x: [usize; 4] = [10, 11, 12, 13]; + let default = x4(0_usize, 1, 2, 3); + let mask = x4(1_i32, 1, 1, 1); + let expected = x4(10_usize, 11, 12, 13); + + unsafe { + let pointer = &x[0] as *const usize; + let pointers = x4( + pointer.offset(0) as *const usize, + pointer.offset(1), + pointer.offset(2), + pointer.offset(3) + ); + let result = simd_gather(default, pointers, mask); + assert_eq!(result, expected); + } + + // and again for isize + let x: [isize; 4] = [10, 11, 12, 13]; + let default = x4(0_isize, 1, 2, 3); + let expected = x4(10_isize, 11, 12, 13); + + unsafe { + let pointer = &x[0] as *const isize; + let pointers = x4( + pointer.offset(0) as *const isize, + pointer.offset(1), + pointer.offset(2), + pointer.offset(3) + ); + let result = simd_gather(default, pointers, mask); + assert_eq!(result, expected); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/monomorphize-shuffle-index.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/monomorphize-shuffle-index.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/monomorphize-shuffle-index.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/monomorphize-shuffle-index.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,40 @@ +//run-pass +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_shuffle(a: T, b: T, i: I) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct Simd([T; N]); + +trait Shuffle { + const I: [u32; N]; + + unsafe fn shuffle(&self, a: Simd, b: Simd) -> Simd { + simd_shuffle(a, b, Self::I) + } +} + +fn main() { + struct I1; + impl Shuffle<4> for I1 { + const I: [u32; 4] = [0, 2, 4, 6]; + } + + struct I2; + impl Shuffle<2> for I2 { + const I: [u32; 2] = [1, 5]; + } + + let a = Simd::([0, 1, 2, 3]); + let b = Simd::([4, 5, 6, 7]); + unsafe { + let x: Simd = I1.shuffle(a, b); + assert_eq!(x.0, [0, 2, 4, 6]); + + let y: Simd = I2.shuffle(a, b); + assert_eq!(y.0, [1, 5]); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/shuffle-not-out-of-bounds.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/shuffle-not-out-of-bounds.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/shuffle-not-out-of-bounds.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/shuffle-not-out-of-bounds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,148 +6,42 @@ #[repr(simd)] #[derive(Copy, Clone)] -struct u8x2(u8, u8); +struct u8x2([u8; 2]); #[repr(simd)] #[derive(Copy, Clone)] -struct u8x4(u8, u8, u8, u8); +struct u8x4([u8; 4]); #[repr(simd)] #[derive(Copy, Clone)] -struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x16( - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, -); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x32( - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, -); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x64( - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, - u8, -); +struct u8x8([u8; 8]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x16([u8; 16]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x32([u8; 32]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x64([u8; 64]); + +extern "platform-intrinsic" { + pub fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + pub fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + pub fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; + pub fn simd_shuffle16(x: T, y: T, idx: [u32; 16]) -> U; + pub fn simd_shuffle32(x: T, y: T, idx: [u32; 32]) -> U; + pub fn simd_shuffle64(x: T, y: T, idx: [u32; 64]) -> U; +} // Test vectors by lane size. Since LLVM does not distinguish between a shuffle // over two f32s and a shuffle over two u64s, or any other such combination, // it is not necessary to test every possible vector, only lane counts. macro_rules! test_shuffle_lanes { - ($n:literal, $x:ident, $y:ident, $t:tt) => { + ($n:literal, $x:ident, $y:ident) => { unsafe { let shuffle: $x = { const ARR: [u32; $n] = { @@ -155,11 +49,10 @@ arr[0] = $n * 2; arr }; - extern "platform-intrinsic" { - pub fn $y(x: T, y: T, idx: [u32; $n]) -> U; - } - let vec1 = $x$t; - let vec2 = $x$t; + let mut n: u8 = $n; + let vals = [0; $n].map(|_| { n = n - 1; n }); + let vec1 = $x(vals); + let vec2 = $x(vals); $y(vec1, vec2, ARR) }; } @@ -175,17 +68,20 @@ // And unfortunately, standard comments, as in the UI test harness, disappear in macros! fn main() { - test_shuffle_lanes!(2, u8x2, simd_shuffle2, (2, 1)); - test_shuffle_lanes!(4, u8x4, simd_shuffle4, (4, 3, 2, 1)); - test_shuffle_lanes!(8, u8x8, simd_shuffle8, (8, 7, 6, 5, 4, 3, 2, 1)); - test_shuffle_lanes!(16, u8x16, simd_shuffle16, - (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)); - test_shuffle_lanes!(32, u8x32, simd_shuffle32, - (32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)); - test_shuffle_lanes!(64, u8x64, simd_shuffle64, - (64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, - 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, - 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, - 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)); + test_shuffle_lanes!(2, u8x2, simd_shuffle2); + test_shuffle_lanes!(4, u8x4, simd_shuffle4); + test_shuffle_lanes!(8, u8x8, simd_shuffle8); + test_shuffle_lanes!(16, u8x16, simd_shuffle16); + test_shuffle_lanes!(32, u8x32, simd_shuffle32); + test_shuffle_lanes!(64, u8x64, simd_shuffle64); + + extern "platform-intrinsic" { + fn simd_shuffle(a: T, b: T, i: I) -> U; + } + let v = u8x2([0, 0]); + const I: [u32; 2] = [4, 4]; + unsafe { + let _: u8x2 = simd_shuffle(v, v, I); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/shuffle-not-out-of-bounds.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/shuffle-not-out-of-bounds.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/shuffle-not-out-of-bounds.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/shuffle-not-out-of-bounds.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -1,76 +1,75 @@ error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: shuffle index #0 is out of bounds (limit 4) - --> $DIR/shuffle-not-out-of-bounds.rs:163:21 + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(2, u8x2, simd_shuffle2, (2, 1)); - | ---------------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(2, u8x2, simd_shuffle2); + | ------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: shuffle index #0 is out of bounds (limit 8) - --> $DIR/shuffle-not-out-of-bounds.rs:163:21 + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(4, u8x4, simd_shuffle4, (4, 3, 2, 1)); - | ---------------------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(4, u8x4, simd_shuffle4); + | ------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: shuffle index #0 is out of bounds (limit 16) - --> $DIR/shuffle-not-out-of-bounds.rs:163:21 + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ ... -LL | test_shuffle_lanes!(8, u8x8, simd_shuffle8, (8, 7, 6, 5, 4, 3, 2, 1)); - | ---------------------------------------------------------------------- in this macro invocation +LL | test_shuffle_lanes!(8, u8x8, simd_shuffle8); + | ------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle16` intrinsic: shuffle index #0 is out of bounds (limit 32) - --> $DIR/shuffle-not-out-of-bounds.rs:163:21 + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 | -LL | $y(vec1, vec2, ARR) - | ^^^^^^^^^^^^^^^^^^^ +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ ... -LL | / test_shuffle_lanes!(16, u8x16, simd_shuffle16, -LL | | (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)); - | |_________________________________________________________________- in this macro invocation +LL | test_shuffle_lanes!(16, u8x16, simd_shuffle16); + | ---------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle32` intrinsic: shuffle index #0 is out of bounds (limit 64) - --> $DIR/shuffle-not-out-of-bounds.rs:163:21 + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 | -LL | $y(vec1, vec2, ARR) - | ^^^^^^^^^^^^^^^^^^^ +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ ... -LL | / test_shuffle_lanes!(32, u8x32, simd_shuffle32, -LL | | (32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, -LL | | 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)); - | |_____________________________________________________________- in this macro invocation +LL | test_shuffle_lanes!(32, u8x32, simd_shuffle32); + | ---------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle64` intrinsic: shuffle index #0 is out of bounds (limit 128) - --> $DIR/shuffle-not-out-of-bounds.rs:163:21 + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 | -LL | $y(vec1, vec2, ARR) - | ^^^^^^^^^^^^^^^^^^^ +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ ... -LL | / test_shuffle_lanes!(64, u8x64, simd_shuffle64, -LL | | (64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, -LL | | 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, -LL | | 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, -LL | | 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)); - | |_________________________________________________________________- in this macro invocation +LL | test_shuffle_lanes!(64, u8x64, simd_shuffle64); + | ---------------------------------------------- in this macro invocation | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4) + --> $DIR/shuffle-not-out-of-bounds.rs:84:23 + | +LL | let _: u8x2 = simd_shuffle(v, v, I); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/shuffle.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/shuffle.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/shuffle.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/shuffle.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,24 @@ +//run-pass +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_shuffle(a: T, b: T, i: I) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct Simd([T; N]); + +fn main() { + const I1: [u32; 4] = [0, 2, 4, 6]; + const I2: [u32; 2] = [1, 5]; + let a = Simd::([0, 1, 2, 3]); + let b = Simd::([4, 5, 6, 7]); + unsafe { + let x: Simd = simd_shuffle(a, b, I1); + assert_eq!(x.0, [0, 2, 4, 6]); + + let y: Simd = simd_shuffle(a, b, I2); + assert_eq!(y.0, [1, 5]); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-array-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-array-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-array-trait.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-array-trait.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -// Figuring out the size of a vector type that depends on traits doesn't ICE - -#![allow(dead_code)] - -// pretty-expanded FIXME #23616 - -#![feature(repr_simd, platform_intrinsics, generic_const_exprs)] -#![allow(non_camel_case_types, incomplete_features)] - -pub trait Simd { - type Lane: Clone + Copy; - const SIZE: usize; -} - -pub struct i32x4; -impl Simd for i32x4 { - type Lane = i32; - const SIZE: usize = 4; -} - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct T([S::Lane; S::SIZE]); -//~^ ERROR unconstrained generic constant - -extern "platform-intrinsic" { - fn simd_insert(x: T, idx: u32, y: E) -> T; - fn simd_extract(x: T, idx: u32) -> E; -} - -pub fn main() { - let mut t = T::([0; 4]); - unsafe { - for i in 0_i32..4 { - t = simd_insert(t, i as u32, i); - } - for i in 0_i32..4 { - assert_eq!(i, simd_extract(t, i as u32)); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-array-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-array-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-array-trait.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-array-trait.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -error: unconstrained generic constant - --> $DIR/simd-array-trait.rs:23:23 - | -LL | pub struct T([S::Lane; S::SIZE]); - | ^^^^^^^^^^^^^^^^^^ - | - = help: try adding a `where` bound using this expression: `where [(); S::SIZE]:` - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-array-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-array-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-array-type.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-array-type.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -// run-pass -#![allow(dead_code)] - -// pretty-expanded FIXME #23616 - -#![feature(repr_simd, platform_intrinsics)] - -#[repr(simd)] -#[derive(Copy, Clone)] -struct S([i32; 4]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct T([i32; N]); - -extern "platform-intrinsic" { - fn simd_insert(x: T, idx: u32, y: E) -> T; - fn simd_extract(x: T, idx: u32) -> E; -} - -pub fn main() { - let mut s = S([0; 4]); - - unsafe { - for i in 0_i32..4 { - s = simd_insert(s, i as u32, i); - } - for i in 0_i32..4 { - assert_eq!(i, simd_extract(s, i as u32)); - } - } - - let mut t = T::<4>([0; 4]); - unsafe { - for i in 0_i32..4 { - t = simd_insert(t, i as u32, i); - } - for i in 0_i32..4 { - assert_eq!(i, simd_extract(t, i as u32)); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-generics.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-generics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-generics.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-generics.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -// run-pass -#![allow(non_camel_case_types)] -#![feature(repr_simd, platform_intrinsics)] - -use std::ops; - -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(f32, f32, f32, f32); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct A([f32; N]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct B([T; 4]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct C([T; N]); - - -extern "platform-intrinsic" { - fn simd_add(x: T, y: T) -> T; -} - -fn add>(lhs: T, rhs: T) -> T { - lhs + rhs -} - -impl ops::Add for f32x4 { - type Output = f32x4; - - fn add(self, rhs: f32x4) -> f32x4 { - unsafe { simd_add(self, rhs) } - } -} - -impl ops::Add for A<4> { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - -impl ops::Add for B { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - -impl ops::Add for C { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - unsafe { simd_add(self, rhs) } - } -} - - -pub fn main() { - let x = [1.0f32, 2.0f32, 3.0f32, 4.0f32]; - let y = [2.0f32, 4.0f32, 6.0f32, 8.0f32]; - - // lame-o - let a = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32); - let f32x4(a0, a1, a2, a3) = add(a, a); - assert_eq!(a0, 2.0f32); - assert_eq!(a1, 4.0f32); - assert_eq!(a2, 6.0f32); - assert_eq!(a3, 8.0f32); - - let a = A(x); - assert_eq!(add(a, a).0, y); - - let b = B(x); - assert_eq!(add(b, b).0, y); - - let c = C(x); - assert_eq!(add(c, c).0, y); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-float-math.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-float-math.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-float-math.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-float-math.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -// run-pass -// ignore-emscripten -// ignore-android - -// FIXME: this test fails on arm-android because the NDK version 14 is too old. -// It needs at least version 18. We disable it on all android build bots because -// there is no way in compile-test to disable it for an (arch,os) pair. - -// Test that the simd floating-point math intrinsics produce correct results. - -#![feature(repr_simd, platform_intrinsics)] -#![allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); - -extern "platform-intrinsic" { - fn simd_fsqrt(x: T) -> T; - fn simd_fabs(x: T) -> T; - fn simd_fsin(x: T) -> T; - fn simd_fcos(x: T) -> T; - fn simd_fexp(x: T) -> T; - fn simd_fexp2(x: T) -> T; - fn simd_fma(x: T, y: T, z: T) -> T; - fn simd_flog(x: T) -> T; - fn simd_flog10(x: T) -> T; - fn simd_flog2(x: T) -> T; - fn simd_fpow(x: T, y: T) -> T; - fn simd_fpowi(x: T, y: i32) -> T; - - // rounding functions - fn simd_ceil(x: T) -> T; - fn simd_floor(x: T) -> T; - fn simd_round(x: T) -> T; - fn simd_trunc(x: T) -> T; -} - -macro_rules! assert_approx_eq_f32 { - ($a:expr, $b:expr) => ({ - let (a, b) = (&$a, &$b); - assert!((*a - *b).abs() < 1.0e-6, - "{} is not approximately equal to {}", *a, *b); - }) -} -macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => ({ - let a = $a; - let b = $b; - assert_approx_eq_f32!(a.0, b.0); - assert_approx_eq_f32!(a.1, b.1); - assert_approx_eq_f32!(a.2, b.2); - assert_approx_eq_f32!(a.3, b.3); - }) -} - -fn main() { - let x = f32x4(1.0, 1.0, 1.0, 1.0); - let y = f32x4(-1.0, -1.0, -1.0, -1.0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); - - let h = f32x4(0.5, 0.5, 0.5, 0.5); - - unsafe { - let r = simd_fabs(y); - assert_approx_eq!(x, r); - - let r = simd_fcos(z); - assert_approx_eq!(x, r); - - let r = simd_fexp(z); - assert_approx_eq!(x, r); - - let r = simd_fexp2(z); - assert_approx_eq!(x, r); - - let r = simd_fma(x, h, h); - assert_approx_eq!(x, r); - - let r = simd_fsqrt(x); - assert_approx_eq!(x, r); - - let r = simd_flog(x); - assert_approx_eq!(z, r); - - let r = simd_flog2(x); - assert_approx_eq!(z, r); - - let r = simd_flog10(x); - assert_approx_eq!(z, r); - - let r = simd_fpow(h, x); - assert_approx_eq!(h, r); - - let r = simd_fpowi(h, 1); - assert_approx_eq!(h, r); - - let r = simd_fsin(z); - assert_approx_eq!(z, r); - - // rounding functions - let r = simd_floor(h); - assert_eq!(z, r); - - let r = simd_ceil(h); - assert_eq!(x, r); - - let r = simd_round(h); - assert_eq!(x, r); - - let r = simd_trunc(h); - assert_eq!(z, r); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-float-minmax.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-float-minmax.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-float-minmax.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-float-minmax.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -// run-pass -// ignore-emscripten - -// Test that the simd_f{min,max} intrinsics produce the correct results. - -#![feature(repr_simd, platform_intrinsics)] -#![allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); - -extern "platform-intrinsic" { - fn simd_fmin(x: T, y: T) -> T; - fn simd_fmax(x: T, y: T) -> T; -} - -fn main() { - let x = f32x4(1.0, 2.0, 3.0, 4.0); - let y = f32x4(2.0, 1.0, 4.0, 3.0); - - #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] - let nan = f32::NAN; - // MIPS hardware treats f32::NAN as SNAN. Clear the signaling bit. - // See https://github.com/rust-lang/rust/issues/52746. - #[cfg(any(target_arch = "mips", target_arch = "mips64"))] - let nan = f32::from_bits(f32::NAN.to_bits() - 1); - - let n = f32x4(nan, nan, nan, nan); - - unsafe { - let min0 = simd_fmin(x, y); - let min1 = simd_fmin(y, x); - assert_eq!(min0, min1); - let e = f32x4(1.0, 1.0, 3.0, 3.0); - assert_eq!(min0, e); - let minn = simd_fmin(x, n); - assert_eq!(minn, x); - let minn = simd_fmin(y, n); - assert_eq!(minn, y); - - let max0 = simd_fmax(x, y); - let max1 = simd_fmax(y, x); - assert_eq!(max0, max1); - let e = f32x4(2.0, 2.0, 4.0, 4.0); - assert_eq!(max0, e); - let maxn = simd_fmax(x, n); - assert_eq!(maxn, x); - let maxn = simd_fmax(y, n); - assert_eq!(maxn, y); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -// run-pass -#![allow(non_camel_case_types)] - -// ignore-emscripten FIXME(#45351) hits an LLVM assert - -#![feature(repr_simd, platform_intrinsics)] - -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x4(pub i32, pub i32, pub i32, pub i32); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct U32([u32; N]); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); - -macro_rules! all_eq { - ($a: expr, $b: expr) => {{ - let a = $a; - let b = $b; - assert!(a.0 == b.0 && a.1 == b.1 && a.2 == b.2 && a.3 == b.3); - }} -} - -macro_rules! all_eq_ { - ($a: expr, $b: expr) => {{ - let a = $a; - let b = $b; - assert!(a.0 == b.0); - }} -} - - -extern "platform-intrinsic" { - fn simd_add(x: T, y: T) -> T; - fn simd_sub(x: T, y: T) -> T; - fn simd_mul(x: T, y: T) -> T; - fn simd_div(x: T, y: T) -> T; - fn simd_rem(x: T, y: T) -> T; - fn simd_shl(x: T, y: T) -> T; - fn simd_shr(x: T, y: T) -> T; - fn simd_and(x: T, y: T) -> T; - fn simd_or(x: T, y: T) -> T; - fn simd_xor(x: T, y: T) -> T; - - fn simd_neg(x: T) -> T; -} - -fn main() { - let x1 = i32x4(1, 2, 3, 4); - let y1 = U32::<4>([1, 2, 3, 4]); - let z1 = f32x4(1.0, 2.0, 3.0, 4.0); - let x2 = i32x4(2, 3, 4, 5); - let y2 = U32::<4>([2, 3, 4, 5]); - let z2 = f32x4(2.0, 3.0, 4.0, 5.0); - - unsafe { - all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9)); - all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9)); - all_eq_!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9])); - all_eq_!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9])); - all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0)); - all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0)); - - all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20)); - all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20)); - all_eq_!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20])); - all_eq_!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20])); - all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0)); - all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0)); - - all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1)); - all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1)); - all_eq_!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1])); - all_eq_!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0])); - all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0)); - all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0)); - - all_eq!(simd_div(x1, x1), i32x4(1, 1, 1, 1)); - all_eq!(simd_div(i32x4(2, 4, 6, 8), i32x4(2, 2, 2, 2)), x1); - all_eq_!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1])); - all_eq_!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1); - all_eq!(simd_div(z1, z1), f32x4(1.0, 1.0, 1.0, 1.0)); - all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0)); - all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0)); - - all_eq!(simd_rem(x1, x1), i32x4(0, 0, 0, 0)); - all_eq!(simd_rem(x2, x1), i32x4(0, 1, 1, 1)); - all_eq_!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0])); - all_eq_!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1])); - all_eq!(simd_rem(z1, z1), f32x4(0.0, 0.0, 0.0, 0.0)); - all_eq!(simd_rem(z1, z2), z1); - all_eq!(simd_rem(z2, z1), f32x4(0.0, 1.0, 1.0, 1.0)); - - all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); - all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); - all_eq_!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); - all_eq_!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4])); - - // test right-shift by assuming left-shift is correct - all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); - all_eq!(simd_shr(simd_shl(x2, x1), x1), x2); - all_eq_!(simd_shr(simd_shl(y1, y2), y2), y1); - all_eq_!(simd_shr(simd_shl(y2, y1), y1), y2); - - // ensure we get logical vs. arithmetic shifts correct - let (a, b, c, d) = (-12, -123, -1234, -12345); - all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4)); - all_eq_!(simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1), - U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4])); - - all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4)); - all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4)); - all_eq_!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4])); - all_eq_!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4])); - - all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5)); - all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5)); - all_eq_!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5])); - all_eq_!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5])); - - all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1)); - all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1)); - all_eq_!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1])); - all_eq_!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); - - all_eq!(simd_neg(x1), i32x4(-1, -2, -3, -4)); - all_eq!(simd_neg(x2), i32x4(-2, -3, -4, -5)); - all_eq!(simd_neg(z1), f32x4(-1.0, -2.0, -3.0, -4.0)); - all_eq!(simd_neg(z2), f32x4(-2.0, -3.0, -4.0, -5.0)); - - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -// run-pass -// ignore-emscripten - -#![allow(non_camel_case_types)] -#![feature(repr_simd, platform_intrinsics)] - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct I32([i32; N]); - -extern "platform-intrinsic" { - fn simd_saturating_add(x: T, y: T) -> T; - fn simd_saturating_sub(x: T, y: T) -> T; -} - -fn main() { - // unsigned - { - const M: u32 = u32::MAX; - - let a = u32x4(1, 2, 3, 4); - let b = u32x4(2, 4, 6, 8); - let m = u32x4(M, M, M, M); - let m1 = u32x4(M - 1, M - 1, M - 1, M - 1); - let z = u32x4(0, 0, 0, 0); - - unsafe { - assert_eq!(simd_saturating_add(z, z), z); - assert_eq!(simd_saturating_add(z, a), a); - assert_eq!(simd_saturating_add(b, z), b); - assert_eq!(simd_saturating_add(a, a), b); - assert_eq!(simd_saturating_add(a, m), m); - assert_eq!(simd_saturating_add(m, b), m); - assert_eq!(simd_saturating_add(m1, a), m); - - assert_eq!(simd_saturating_sub(b, z), b); - assert_eq!(simd_saturating_sub(b, a), a); - assert_eq!(simd_saturating_sub(a, a), z); - assert_eq!(simd_saturating_sub(a, b), z); - assert_eq!(simd_saturating_sub(a, m1), z); - assert_eq!(simd_saturating_sub(b, m1), z); - } - } - - // signed - { - const MIN: i32 = i32::MIN; - const MAX: i32 = i32::MAX; - - let a = I32::<4>([1, 2, 3, 4]); - let b = I32::<4>([2, 4, 6, 8]); - let c = I32::<4>([-1, -2, -3, -4]); - let d = I32::<4>([-2, -4, -6, -8]); - - let max = I32::<4>([MAX, MAX, MAX, MAX]); - let max1 = I32::<4>([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); - let min = I32::<4>([MIN, MIN, MIN, MIN]); - let min1 = I32::<4>([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); - - let z = I32::<4>([0, 0, 0, 0]); - - unsafe { - assert_eq!(simd_saturating_add(z, z).0, z.0); - assert_eq!(simd_saturating_add(z, a).0, a.0); - assert_eq!(simd_saturating_add(b, z).0, b.0); - assert_eq!(simd_saturating_add(a, a).0, b.0); - assert_eq!(simd_saturating_add(a, max).0, max.0); - assert_eq!(simd_saturating_add(max, b).0, max.0); - assert_eq!(simd_saturating_add(max1, a).0, max.0); - assert_eq!(simd_saturating_add(min1, z).0, min1.0); - assert_eq!(simd_saturating_add(min, z).0, min.0); - assert_eq!(simd_saturating_add(min1, c).0, min.0); - assert_eq!(simd_saturating_add(min, c).0, min.0); - assert_eq!(simd_saturating_add(min1, d).0, min.0); - assert_eq!(simd_saturating_add(min, d).0, min.0); - - assert_eq!(simd_saturating_sub(b, z).0, b.0); - assert_eq!(simd_saturating_sub(b, a).0, a.0); - assert_eq!(simd_saturating_sub(a, a).0, z.0); - assert_eq!(simd_saturating_sub(a, b).0, c.0); - assert_eq!(simd_saturating_sub(z, max).0, min1.0); - assert_eq!(simd_saturating_sub(min1, z).0, min1.0); - assert_eq!(simd_saturating_sub(min1, a).0, min.0); - assert_eq!(simd_saturating_sub(min1, b).0, min.0); - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -// run-pass -#![allow(non_camel_case_types)] - -// ignore-emscripten -// ignore-endian-big behavior of simd_bitmask is endian-specific - -// Test that the simd_bitmask intrinsic produces correct results. - -#![feature(repr_simd, platform_intrinsics)] -#[allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u8x4(pub u8, pub u8, pub u8, pub u8); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct Tx4(pub T, pub T, pub T, pub T); - -extern "platform-intrinsic" { - fn simd_bitmask(x: T) -> U; -} - -fn main() { - let z = u32x4(0, 0, 0, 0); - let ez = 0_u8; - - let o = u32x4(!0, !0, !0, !0); - let eo = 0b_1111_u8; - - let m0 = u32x4(!0, 0, !0, 0); - let e0 = 0b_0000_0101_u8; - - // Check that the MSB is extracted: - let m = u8x4(0b_1000_0000, 0b_0100_0001, 0b_1100_0001, 0b_1111_1111); - let e = 0b_1101; - - // Check usize / isize - let msize: Tx4 = Tx4(usize::MAX, 0, usize::MAX, usize::MAX); - - unsafe { - let r: u8 = simd_bitmask(z); - assert_eq!(r, ez); - - let r: u8 = simd_bitmask(o); - assert_eq!(r, eo); - - let r: u8 = simd_bitmask(m0); - assert_eq!(r, e0); - - let r: u8 = simd_bitmask(m); - assert_eq!(r, e); - - let r: u8 = simd_bitmask(msize); - assert_eq!(r, e); - - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-cast.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-cast.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-cast.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-cast.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -// run-pass -#![allow(unused_must_use)] -// ignore-emscripten FIXME(#45351) hits an LLVM assert - -#![feature(repr_simd, platform_intrinsics, concat_idents, test)] -#![allow(non_camel_case_types)] - -extern crate test; - -#[repr(simd)] -#[derive(PartialEq, Debug)] -struct i32x4(i32, i32, i32, i32); -#[repr(simd)] -#[derive(PartialEq, Debug)] -struct i8x4(i8, i8, i8, i8); - -#[repr(simd)] -#[derive(PartialEq, Debug)] -struct u32x4(u32, u32, u32, u32); -#[repr(simd)] -#[derive(PartialEq, Debug)] -struct u8x4(u8, u8, u8, u8); - -#[repr(simd)] -#[derive(PartialEq, Debug)] -struct f32x4(f32, f32, f32, f32); - -#[repr(simd)] -#[derive(PartialEq, Debug)] -struct f64x4(f64, f64, f64, f64); - - -extern "platform-intrinsic" { - fn simd_cast(x: T) -> U; -} - -const A: i32 = -1234567; -const B: i32 = 12345678; -const C: i32 = -123456789; -const D: i32 = 1234567890; - -trait Foo { - fn is_float() -> bool { false } - fn in_range(x: i32) -> bool; -} -impl Foo for i32 { - fn in_range(_: i32) -> bool { true } -} -impl Foo for i8 { - fn in_range(x: i32) -> bool { -128 <= x && x < 128 } -} -impl Foo for u32 { - fn in_range(x: i32) -> bool { 0 <= x } -} -impl Foo for u8 { - fn in_range(x: i32) -> bool { 0 <= x && x < 128 } -} -impl Foo for f32 { - fn is_float() -> bool { true } - fn in_range(_: i32) -> bool { true } -} -impl Foo for f64 { - fn is_float() -> bool { true } - fn in_range(_: i32) -> bool { true } -} - -fn main() { - macro_rules! test { - ($from: ident, $to: ident) => {{ - // force the casts to actually happen, or else LLVM/rustc - // may fold them and get slightly different results. - let (a, b, c, d) = test::black_box((A as $from, B as $from, C as $from, D as $from)); - // the SIMD vectors are all FOOx4, so we can concat_idents - // so we don't have to pass in the extra args to the macro - let mut from = simd_cast(concat_idents!($from, x4)(a, b, c, d)); - let mut to = concat_idents!($to, x4)(a as $to, - b as $to, - c as $to, - d as $to); - // assist type inference, it needs to know what `from` is - // for the `if` statements. - to == from; - - // there are platform differences for some out of range - // casts, so we just normalize such things: it's OK for - // "invalid" calculations to result in nonsense answers. - // (e.g., negative float to unsigned integer goes through a - // library routine on the default i686 platforms, and the - // implementation of that routine differs on e.g., Linux - // vs. macOS, resulting in different answers.) - if $from::is_float() { - if !$to::in_range(A) { from.0 = 0 as $to; to.0 = 0 as $to; } - if !$to::in_range(B) { from.1 = 0 as $to; to.1 = 0 as $to; } - if !$to::in_range(C) { from.2 = 0 as $to; to.2 = 0 as $to; } - if !$to::in_range(D) { from.3 = 0 as $to; to.3 = 0 as $to; } - } - - assert!(to == from, - "{} -> {} ({:?} != {:?})", stringify!($from), stringify!($to), - from, to); - }} - } - macro_rules! tests { - (: $($to: ident),*) => { () }; - // repeating the list twice is easier than writing a cartesian - // product macro - ($from: ident $(, $from_: ident)*: $($to: ident),*) => { - fn $from() { unsafe { $( test!($from, $to); )* } } - tests!($($from_),*: $($to),*) - }; - ($($types: ident),*) => {{ - tests!($($types),* : $($types),*); - $($types();)* - }} - } - - // test various combinations, including truncation, - // signed/unsigned extension, and floating point casts. - tests!(i32, i8, u32, u8, f32); - tests!(i32, u32, f32, f64) -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-comparison.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-comparison.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-comparison.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-comparison.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -// run-pass -// ignore-emscripten FIXME(#45351) hits an LLVM assert -// revisions: mir thir -// [thir]compile-flags: -Zthir-unsafeck - -#![feature(repr_simd, platform_intrinsics, concat_idents)] -#![allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x4(i32, i32, i32, i32); -#[repr(simd)] -#[derive(Copy, Clone)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); - -extern "platform-intrinsic" { - fn simd_eq(x: T, y: T) -> U; - fn simd_ne(x: T, y: T) -> U; - fn simd_lt(x: T, y: T) -> U; - fn simd_le(x: T, y: T) -> U; - fn simd_gt(x: T, y: T) -> U; - fn simd_ge(x: T, y: T) -> U; -} - -macro_rules! cmp { - ($method: ident($lhs: expr, $rhs: expr)) => {{ - let lhs = $lhs; - let rhs = $rhs; - let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs); - // assume the scalar version is correct/the behaviour we want. - assert!((e.0 != 0) == lhs.0 .$method(&rhs.0)); - assert!((e.1 != 0) == lhs.1 .$method(&rhs.1)); - assert!((e.2 != 0) == lhs.2 .$method(&rhs.2)); - assert!((e.3 != 0) == lhs.3 .$method(&rhs.3)); - }} -} -macro_rules! tests { - ($($lhs: ident, $rhs: ident;)*) => {{ - $( - (|| { - cmp!(eq($lhs, $rhs)); - cmp!(ne($lhs, $rhs)); - - // test both directions - cmp!(lt($lhs, $rhs)); - cmp!(lt($rhs, $lhs)); - - cmp!(le($lhs, $rhs)); - cmp!(le($rhs, $lhs)); - - cmp!(gt($lhs, $rhs)); - cmp!(gt($rhs, $lhs)); - - cmp!(ge($lhs, $rhs)); - cmp!(ge($rhs, $lhs)); - })(); - )* - }} -} -fn main() { - // 13 vs. -100 tests that we get signed vs. unsigned comparisons - // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); - let i1 = i32x4(10, -11, 12, 13); - let i2 = i32x4(5, -5, 20, -100); - let i3 = i32x4(10, -11, 20, -100); - - let u1 = u32x4(10, !11+1, 12, 13); - let u2 = u32x4(5, !5+1, 20, !100+1); - let u3 = u32x4(10, !11+1, 20, !100+1); - - let f1 = f32x4(10.0, -11.0, 12.0, 13.0); - let f2 = f32x4(5.0, -5.0, 20.0, -100.0); - let f3 = f32x4(10.0, -11.0, 20.0, -100.0); - - unsafe { - tests! { - i1, i1; - u1, u1; - f1, f1; - - i1, i2; - u1, u2; - f1, f2; - - i1, i3; - u1, u3; - f1, f3; - } - } - - // NAN comparisons are special: - // -11 (*) 13 - // -5 -100 (*) - let f4 = f32x4(f32::NAN, f1.1, f32::NAN, f2.3); - - unsafe { - tests! { - f1, f4; - f2, f4; - f4, f4; - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-elements.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-elements.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-elements.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-elements.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -// run-pass -// ignore-emscripten FIXME(#45351) hits an LLVM assert - -#![feature(repr_simd, platform_intrinsics)] -#![allow(incomplete_features)] -#![feature(inline_const)] - -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x2(i32, i32); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); - -extern "platform-intrinsic" { - fn simd_insert(x: T, idx: u32, y: E) -> T; - fn simd_extract(x: T, idx: u32) -> E; - - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; - fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; - fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; -} - -macro_rules! all_eq { - ($a: expr, $b: expr) => {{ - let a = $a; - let b = $b; - // type inference works better with the concrete type on the - // left, but humans work better with the expected on the - // right. - assert!(b == a, - "{:?} != {:?}", a, b); - }} -} - -fn main() { - let x2 = i32x2(20, 21); - let x4 = i32x4(40, 41, 42, 43); - let x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); - unsafe { - all_eq!(simd_insert(x2, 0, 100), i32x2(100, 21)); - all_eq!(simd_insert(x2, 1, 100), i32x2(20, 100)); - - all_eq!(simd_insert(x4, 0, 100), i32x4(100, 41, 42, 43)); - all_eq!(simd_insert(x4, 1, 100), i32x4(40, 100, 42, 43)); - all_eq!(simd_insert(x4, 2, 100), i32x4(40, 41, 100, 43)); - all_eq!(simd_insert(x4, 3, 100), i32x4(40, 41, 42, 100)); - - all_eq!(simd_insert(x8, 0, 100), i32x8(100, 81, 82, 83, 84, 85, 86, 87)); - all_eq!(simd_insert(x8, 1, 100), i32x8(80, 100, 82, 83, 84, 85, 86, 87)); - all_eq!(simd_insert(x8, 2, 100), i32x8(80, 81, 100, 83, 84, 85, 86, 87)); - all_eq!(simd_insert(x8, 3, 100), i32x8(80, 81, 82, 100, 84, 85, 86, 87)); - all_eq!(simd_insert(x8, 4, 100), i32x8(80, 81, 82, 83, 100, 85, 86, 87)); - all_eq!(simd_insert(x8, 5, 100), i32x8(80, 81, 82, 83, 84, 100, 86, 87)); - all_eq!(simd_insert(x8, 6, 100), i32x8(80, 81, 82, 83, 84, 85, 100, 87)); - all_eq!(simd_insert(x8, 7, 100), i32x8(80, 81, 82, 83, 84, 85, 86, 100)); - - all_eq!(simd_extract(x2, 0), 20); - all_eq!(simd_extract(x2, 1), 21); - - all_eq!(simd_extract(x4, 0), 40); - all_eq!(simd_extract(x4, 1), 41); - all_eq!(simd_extract(x4, 2), 42); - all_eq!(simd_extract(x4, 3), 43); - - all_eq!(simd_extract(x8, 0), 80); - all_eq!(simd_extract(x8, 1), 81); - all_eq!(simd_extract(x8, 2), 82); - all_eq!(simd_extract(x8, 3), 83); - all_eq!(simd_extract(x8, 4), 84); - all_eq!(simd_extract(x8, 5), 85); - all_eq!(simd_extract(x8, 6), 86); - all_eq!(simd_extract(x8, 7), 87); - } - - let y2 = i32x2(120, 121); - let y4 = i32x4(140, 141, 142, 143); - let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); - unsafe { - all_eq!(simd_shuffle2(x2, y2, const { [3u32, 0] }), i32x2(121, 20)); - all_eq!(simd_shuffle4(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120)); - all_eq!(simd_shuffle8(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }), - i32x8(121, 20, 21, 120, 21, 120, 121, 20)); - - all_eq!(simd_shuffle2(x4, y4, const { [7u32, 2] }), i32x2(143, 42)); - all_eq!(simd_shuffle4(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40)); - all_eq!(simd_shuffle8(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }), - i32x8(143, 42, 141, 40, 43, 142, 140, 41)); - - all_eq!(simd_shuffle2(x8, y8, const { [11u32, 5] }), i32x2(183, 85)); - all_eq!(simd_shuffle4(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80)); - all_eq!(simd_shuffle8(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }), - i32x8(183, 85, 187, 80, 83, 180, 184, 81)); - } - -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-gather.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-gather.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-gather.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-gather.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -// run-pass -// ignore-emscripten - -// Test that the simd_{gather,scatter} intrinsics produce the correct results. - -#![feature(repr_simd, platform_intrinsics)] -#![allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct x4(pub T, pub T, pub T, pub T); - -extern "platform-intrinsic" { - fn simd_gather(x: T, y: U, z: V) -> T; - fn simd_scatter(x: T, y: U, z: V) -> (); -} - -fn main() { - let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; - - let default = x4(-3_f32, -3., -3., -3.); - let s_strided = x4(0_f32, 2., -3., 6.); - let mask = x4(-1_i32, -1, 0, -1); - - // reading from *const - unsafe { - let pointer = &x[0] as *const f32; - let pointers = x4( - pointer.offset(0) as *const f32, - pointer.offset(2), - pointer.offset(4), - pointer.offset(6) - ); - - let r_strided = simd_gather(default, pointers, mask); - - assert_eq!(r_strided, s_strided); - } - - // reading from *mut - unsafe { - let pointer = &mut x[0] as *mut f32; - let pointers = x4( - pointer.offset(0) as *mut f32, - pointer.offset(2), - pointer.offset(4), - pointer.offset(6) - ); - - let r_strided = simd_gather(default, pointers, mask); - - assert_eq!(r_strided, s_strided); - } - - // writing to *mut - unsafe { - let pointer = &mut x[0] as *mut f32; - let pointers = x4( - pointer.offset(0) as *mut f32, - pointer.offset(2), - pointer.offset(4), - pointer.offset(6) - ); - - let values = x4(42_f32, 43_f32, 44_f32, 45_f32); - simd_scatter(values, pointers, mask); - - assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); - } - - // test modifying array of *const f32 - let mut y = [ - &x[0] as *const f32, - &x[1] as *const f32, - &x[2] as *const f32, - &x[3] as *const f32, - &x[4] as *const f32, - &x[5] as *const f32, - &x[6] as *const f32, - &x[7] as *const f32 - ]; - - let default = x4(y[0], y[0], y[0], y[0]); - let s_strided = x4(y[0], y[2], y[0], y[6]); - - // reading from *const - unsafe { - let pointer = &y[0] as *const *const f32; - let pointers = x4( - pointer.offset(0) as *const *const f32, - pointer.offset(2), - pointer.offset(4), - pointer.offset(6) - ); - - let r_strided = simd_gather(default, pointers, mask); - - assert_eq!(r_strided, s_strided); - } - - // reading from *mut - unsafe { - let pointer = &mut y[0] as *mut *const f32; - let pointers = x4( - pointer.offset(0) as *mut *const f32, - pointer.offset(2), - pointer.offset(4), - pointer.offset(6) - ); - - let r_strided = simd_gather(default, pointers, mask); - - assert_eq!(r_strided, s_strided); - } - - // writing to *mut - unsafe { - let pointer = &mut y[0] as *mut *const f32; - let pointers = x4( - pointer.offset(0) as *mut *const f32, - pointer.offset(2), - pointer.offset(4), - pointer.offset(6) - ); - - let values = x4(y[7], y[6], y[5], y[1]); - simd_scatter(values, pointers, mask); - - let s = [ - &x[7] as *const f32, - &x[1] as *const f32, - &x[6] as *const f32, - &x[3] as *const f32, - &x[4] as *const f32, - &x[5] as *const f32, - &x[1] as *const f32, - &x[7] as *const f32 - ]; - assert_eq!(y, s); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-reduction.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-reduction.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-reduction.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-reduction.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -// run-pass -#![allow(non_camel_case_types)] - -// ignore-emscripten - -// Test that the simd_reduce_{op} intrinsics produce the correct results. - -#![feature(repr_simd, platform_intrinsics)] -#[allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x4(pub i32, pub i32, pub i32, pub i32); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct b8x4(pub i8, pub i8, pub i8, pub i8); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct b8x16( - pub i8, pub i8, pub i8, pub i8, - pub i8, pub i8, pub i8, pub i8, - pub i8, pub i8, pub i8, pub i8, - pub i8, pub i8, pub i8, pub i8 -); - -extern "platform-intrinsic" { - fn simd_reduce_add_unordered(x: T) -> U; - fn simd_reduce_mul_unordered(x: T) -> U; - fn simd_reduce_add_ordered(x: T, acc: U) -> U; - fn simd_reduce_mul_ordered(x: T, acc: U) -> U; - fn simd_reduce_min(x: T) -> U; - fn simd_reduce_max(x: T) -> U; - fn simd_reduce_min_nanless(x: T) -> U; - fn simd_reduce_max_nanless(x: T) -> U; - fn simd_reduce_and(x: T) -> U; - fn simd_reduce_or(x: T) -> U; - fn simd_reduce_xor(x: T) -> U; - fn simd_reduce_all(x: T) -> bool; - fn simd_reduce_any(x: T) -> bool; -} - -fn main() { - unsafe { - let x = i32x4(1, -2, 3, 4); - let r: i32 = simd_reduce_add_unordered(x); - assert_eq!(r, 6_i32); - let r: i32 = simd_reduce_mul_unordered(x); - assert_eq!(r, -24_i32); - let r: i32 = simd_reduce_add_ordered(x, -1); - assert_eq!(r, 5_i32); - let r: i32 = simd_reduce_mul_ordered(x, -1); - assert_eq!(r, 24_i32); - - let r: i32 = simd_reduce_min(x); - assert_eq!(r, -2_i32); - let r: i32 = simd_reduce_max(x); - assert_eq!(r, 4_i32); - - let x = i32x4(-1, -1, -1, -1); - let r: i32 = simd_reduce_and(x); - assert_eq!(r, -1_i32); - let r: i32 = simd_reduce_or(x); - assert_eq!(r, -1_i32); - let r: i32 = simd_reduce_xor(x); - assert_eq!(r, 0_i32); - - let x = i32x4(-1, -1, 0, -1); - let r: i32 = simd_reduce_and(x); - assert_eq!(r, 0_i32); - let r: i32 = simd_reduce_or(x); - assert_eq!(r, -1_i32); - let r: i32 = simd_reduce_xor(x); - assert_eq!(r, -1_i32); - } - - unsafe { - let x = u32x4(1, 2, 3, 4); - let r: u32 = simd_reduce_add_unordered(x); - assert_eq!(r, 10_u32); - let r: u32 = simd_reduce_mul_unordered(x); - assert_eq!(r, 24_u32); - let r: u32 = simd_reduce_add_ordered(x, 1); - assert_eq!(r, 11_u32); - let r: u32 = simd_reduce_mul_ordered(x, 2); - assert_eq!(r, 48_u32); - - let r: u32 = simd_reduce_min(x); - assert_eq!(r, 1_u32); - let r: u32 = simd_reduce_max(x); - assert_eq!(r, 4_u32); - - let t = u32::MAX; - let x = u32x4(t, t, t, t); - let r: u32 = simd_reduce_and(x); - assert_eq!(r, t); - let r: u32 = simd_reduce_or(x); - assert_eq!(r, t); - let r: u32 = simd_reduce_xor(x); - assert_eq!(r, 0_u32); - - let x = u32x4(t, t, 0, t); - let r: u32 = simd_reduce_and(x); - assert_eq!(r, 0_u32); - let r: u32 = simd_reduce_or(x); - assert_eq!(r, t); - let r: u32 = simd_reduce_xor(x); - assert_eq!(r, t); - } - - unsafe { - let x = f32x4(1., -2., 3., 4.); - let r: f32 = simd_reduce_add_unordered(x); - assert_eq!(r, 6_f32); - let r: f32 = simd_reduce_mul_unordered(x); - assert_eq!(r, -24_f32); - let r: f32 = simd_reduce_add_ordered(x, 0.); - assert_eq!(r, 6_f32); - let r: f32 = simd_reduce_mul_ordered(x, 1.); - assert_eq!(r, -24_f32); - let r: f32 = simd_reduce_add_ordered(x, 1.); - assert_eq!(r, 7_f32); - let r: f32 = simd_reduce_mul_ordered(x, 2.); - assert_eq!(r, -48_f32); - - let r: f32 = simd_reduce_min(x); - assert_eq!(r, -2_f32); - let r: f32 = simd_reduce_max(x); - assert_eq!(r, 4_f32); - let r: f32 = simd_reduce_min_nanless(x); - assert_eq!(r, -2_f32); - let r: f32 = simd_reduce_max_nanless(x); - assert_eq!(r, 4_f32); - } - - unsafe { - let x = b8x4(!0, !0, !0, !0); - let r: bool = simd_reduce_all(x); - assert_eq!(r, true); - let r: bool = simd_reduce_any(x); - assert_eq!(r, true); - - let x = b8x4(!0, !0, 0, !0); - let r: bool = simd_reduce_all(x); - assert_eq!(r, false); - let r: bool = simd_reduce_any(x); - assert_eq!(r, true); - - let x = b8x4(0, 0, 0, 0); - let r: bool = simd_reduce_all(x); - assert_eq!(r, false); - let r: bool = simd_reduce_any(x); - assert_eq!(r, false); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-select.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-select.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-select.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-intrinsic-generic-select.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -// run-pass -#![allow(non_camel_case_types)] - -// ignore-emscripten -// ignore-endian-big behavior of simd_select_bitmask is endian-specific - -// Test that the simd_select intrinsics produces correct results. - -#![feature(repr_simd, platform_intrinsics)] -#[allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct i32x4(pub i32, pub i32, pub i32, pub i32); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct u32x8(u32, u32, u32, u32, u32, u32, u32, u32); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct b8x4(pub i8, pub i8, pub i8, pub i8); - -extern "platform-intrinsic" { - fn simd_select(x: T, a: U, b: U) -> U; - fn simd_select_bitmask(x: T, a: U, b: U) -> U; -} - -fn main() { - let m0 = b8x4(!0, !0, !0, !0); - let m1 = b8x4(0, 0, 0, 0); - let m2 = b8x4(!0, !0, 0, 0); - let m3 = b8x4(0, 0, !0, !0); - let m4 = b8x4(!0, 0, !0, 0); - - unsafe { - let a = i32x4(1, -2, 3, 4); - let b = i32x4(5, 6, -7, 8); - - let r: i32x4 = simd_select(m0, a, b); - let e = a; - assert_eq!(r, e); - - let r: i32x4 = simd_select(m1, a, b); - let e = b; - assert_eq!(r, e); - - let r: i32x4 = simd_select(m2, a, b); - let e = i32x4(1, -2, -7, 8); - assert_eq!(r, e); - - let r: i32x4 = simd_select(m3, a, b); - let e = i32x4(5, 6, 3, 4); - assert_eq!(r, e); - - let r: i32x4 = simd_select(m4, a, b); - let e = i32x4(1, 6, 3, 8); - assert_eq!(r, e); - } - - unsafe { - let a = u32x4(1, 2, 3, 4); - let b = u32x4(5, 6, 7, 8); - - let r: u32x4 = simd_select(m0, a, b); - let e = a; - assert_eq!(r, e); - - let r: u32x4 = simd_select(m1, a, b); - let e = b; - assert_eq!(r, e); - - let r: u32x4 = simd_select(m2, a, b); - let e = u32x4(1, 2, 7, 8); - assert_eq!(r, e); - - let r: u32x4 = simd_select(m3, a, b); - let e = u32x4(5, 6, 3, 4); - assert_eq!(r, e); - - let r: u32x4 = simd_select(m4, a, b); - let e = u32x4(1, 6, 3, 8); - assert_eq!(r, e); - } - - unsafe { - let a = f32x4(1., 2., 3., 4.); - let b = f32x4(5., 6., 7., 8.); - - let r: f32x4 = simd_select(m0, a, b); - let e = a; - assert_eq!(r, e); - - let r: f32x4 = simd_select(m1, a, b); - let e = b; - assert_eq!(r, e); - - let r: f32x4 = simd_select(m2, a, b); - let e = f32x4(1., 2., 7., 8.); - assert_eq!(r, e); - - let r: f32x4 = simd_select(m3, a, b); - let e = f32x4(5., 6., 3., 4.); - assert_eq!(r, e); - - let r: f32x4 = simd_select(m4, a, b); - let e = f32x4(1., 6., 3., 8.); - assert_eq!(r, e); - } - - unsafe { - let t = !0 as i8; - let f = 0 as i8; - let a = b8x4(t, f, t, f); - let b = b8x4(f, f, f, t); - - let r: b8x4 = simd_select(m0, a, b); - let e = a; - assert_eq!(r, e); - - let r: b8x4 = simd_select(m1, a, b); - let e = b; - assert_eq!(r, e); - - let r: b8x4 = simd_select(m2, a, b); - let e = b8x4(t, f, f, t); - assert_eq!(r, e); - - let r: b8x4 = simd_select(m3, a, b); - let e = b8x4(f, f, t, f); - assert_eq!(r, e); - - let r: b8x4 = simd_select(m4, a, b); - let e = b8x4(t, f, t, t); - assert_eq!(r, e); - } - - unsafe { - let a = u32x8(0, 1, 2, 3, 4, 5, 6, 7); - let b = u32x8(8, 9, 10, 11, 12, 13, 14, 15); - - let r: u32x8 = simd_select_bitmask(0u8, a, b); - let e = b; - assert_eq!(r, e); - - let r: u32x8 = simd_select_bitmask(0xffu8, a, b); - let e = a; - assert_eq!(r, e); - - let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b); - let e = u32x8(0, 9, 2, 11, 4, 13, 6, 15); - assert_eq!(r, e); - - let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b); - let e = u32x8(8, 1, 10, 3, 12, 5, 14, 7); - assert_eq!(r, e); - - let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b); - let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7); - assert_eq!(r, e); - } - - unsafe { - let a = u32x4(0, 1, 2, 3); - let b = u32x4(4, 5, 6, 7); - - let r: u32x4 = simd_select_bitmask(0u8, a, b); - let e = b; - assert_eq!(r, e); - - let r: u32x4 = simd_select_bitmask(0xfu8, a, b); - let e = a; - assert_eq!(r, e); - - let r: u32x4 = simd_select_bitmask(0b0101u8, a, b); - let e = u32x4(0, 5, 2, 7); - assert_eq!(r, e); - - let r: u32x4 = simd_select_bitmask(0b1010u8, a, b); - let e = u32x4(4, 1, 6, 3); - assert_eq!(r, e); - - let r: u32x4 = simd_select_bitmask(0b1100u8, a, b); - let e = u32x4(4, 5, 2, 3); - assert_eq!(r, e); - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-size-align.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-size-align.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-size-align.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-size-align.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -// run-pass -#![allow(deprecated)] - - -#![feature(repr_simd)] -#![allow(non_camel_case_types)] - -use std::mem; - -/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec` properly -/// Please consult the issue #20460 -fn check() { - assert_eq!(mem::size_of::() % mem::min_align_of::(), 0); - assert_eq!(mem::size_of::() % mem::min_align_of::(), 0); - assert_eq!(mem::size_of::() % mem::min_align_of::(), 0); -} - -#[repr(simd)] -struct U8([u8; N]); - -#[repr(simd)] -struct I16([i16; N]); - -#[repr(simd)] -struct F32([f32; N]); - -#[repr(simd)] -struct Usize([usize; N]); - -#[repr(simd)] -struct Isize([isize; N]); - -fn main() { - check::>(); - check::>(); - check::>(); - - check::>(); - check::>(); - check::>(); - - check::>(); - check::>(); - check::>(); - - check::>(); - check::>(); - check::>(); - - check::>(); - check::>(); - check::>(); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-target-feature-mixup.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-target-feature-mixup.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-target-feature-mixup.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-target-feature-mixup.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -// run-pass -#![allow(unused_variables)] -#![allow(stable_features)] -#![allow(overflowing_literals)] - -// ignore-emscripten -// ignore-sgx no processes - -#![feature(repr_simd, target_feature, cfg_target_feature)] -#![feature(avx512_target_feature)] - -use std::process::{Command, ExitStatus}; -use std::env; - -fn main() { - if let Some(level) = env::args().nth(1) { - return test::main(&level) - } - - let me = env::current_exe().unwrap(); - for level in ["sse", "avx", "avx512"].iter() { - let status = Command::new(&me).arg(level).status().unwrap(); - if status.success() { - println!("success with {}", level); - continue - } - - // We don't actually know if our computer has the requisite target features - // for the test below. Testing for that will get added to libstd later so - // for now just assume sigill means this is a machine that can't run this test. - if is_sigill(status) { - println!("sigill with {}, assuming spurious", level); - continue - } - panic!("invalid status at {}: {}", level, status); - } -} - -#[cfg(unix)] -fn is_sigill(status: ExitStatus) -> bool { - use std::os::unix::prelude::*; - status.signal() == Some(4) -} - -#[cfg(windows)] -fn is_sigill(status: ExitStatus) -> bool { - status.code() == Some(0xc000001d) -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[allow(nonstandard_style)] -mod test { - // An SSE type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m128i(u64, u64); - - // An AVX type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m256i(u64, u64, u64, u64); - - // An AVX-512 type - #[repr(simd)] - #[derive(PartialEq, Debug, Clone, Copy)] - struct __m512i(u64, u64, u64, u64, u64, u64, u64, u64); - - pub fn main(level: &str) { - unsafe { - main_normal(level); - main_sse(level); - if level == "sse" { - return - } - main_avx(level); - if level == "avx" { - return - } - main_avx512(level); - } - } - - macro_rules! mains { - ($( - $(#[$attr:meta])* - unsafe fn $main:ident(level: &str) { - ... - } - )*) => ($( - $(#[$attr])* - unsafe fn $main(level: &str) { - let m128 = __m128i(1, 2); - let m256 = __m256i(3, 4, 5, 6); - let m512 = __m512i(7, 8, 9, 10, 11, 12, 13, 14); - assert_eq!(id_sse_128(m128), m128); - assert_eq!(id_sse_256(m256), m256); - assert_eq!(id_sse_512(m512), m512); - - if level == "sse" { - return - } - assert_eq!(id_avx_128(m128), m128); - assert_eq!(id_avx_256(m256), m256); - assert_eq!(id_avx_512(m512), m512); - - if level == "avx" { - return - } - assert_eq!(id_avx512_128(m128), m128); - assert_eq!(id_avx512_256(m256), m256); - assert_eq!(id_avx512_512(m512), m512); - } - )*) - } - - mains! { - unsafe fn main_normal(level: &str) { ... } - #[target_feature(enable = "sse2")] - unsafe fn main_sse(level: &str) { ... } - #[target_feature(enable = "avx")] - unsafe fn main_avx(level: &str) { ... } - #[target_feature(enable = "avx512bw")] - unsafe fn main_avx512(level: &str) { ... } - } - - - #[target_feature(enable = "sse2")] - unsafe fn id_sse_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i(1, 2)); - a.clone() - } - - #[target_feature(enable = "sse2")] - unsafe fn id_sse_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i(3, 4, 5, 6)); - a.clone() - } - - #[target_feature(enable = "sse2")] - unsafe fn id_sse_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); - a.clone() - } - - #[target_feature(enable = "avx")] - unsafe fn id_avx_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i(1, 2)); - a.clone() - } - - #[target_feature(enable = "avx")] - unsafe fn id_avx_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i(3, 4, 5, 6)); - a.clone() - } - - #[target_feature(enable = "avx")] - unsafe fn id_avx_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); - a.clone() - } - - #[target_feature(enable = "avx512bw")] - unsafe fn id_avx512_128(a: __m128i) -> __m128i { - assert_eq!(a, __m128i(1, 2)); - a.clone() - } - - #[target_feature(enable = "avx512bw")] - unsafe fn id_avx512_256(a: __m256i) -> __m256i { - assert_eq!(a, __m256i(3, 4, 5, 6)); - a.clone() - } - - #[target_feature(enable = "avx512bw")] - unsafe fn id_avx512_512(a: __m512i) -> __m512i { - assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); - a.clone() - } -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -mod test { - pub fn main(level: &str) {} -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-empty.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-empty.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-empty.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-empty.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -// build-fail - -#![feature(repr_simd, platform_intrinsics)] - -// error-pattern:monomorphising SIMD type `Simd<0_usize>` of zero length - -#[repr(simd)] -struct Simd([f32; N]); - -fn main() { - let _ = Simd::<0>([]); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-empty.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-empty.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-empty.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-empty.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -error: monomorphising SIMD type `Simd<0_usize>` of zero length - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -// run-pass -// ignore-emscripten - -#![feature(extern_types)] -#![feature(repr_simd)] - -use std::ptr::NonNull; - -extern { - type Extern; -} - -#[repr(simd)] -struct S(T); - -#[inline(never)] -fn identity(v: T) -> T { - v -} - -fn main() { - let _v: S<[Option>; 4]> = identity(S([None; 4])); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -// build-fail - -#![feature(repr_simd)] - -struct E; - -// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `E` - -#[repr(simd)] -struct S([T; 4]); - -fn main() { - let _v: Option> = None; -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `E` - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-oversized.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-oversized.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-oversized.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-oversized.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -// build-fail - -#![feature(repr_simd, platform_intrinsics)] - -// error-pattern:monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768 - -#[repr(simd)] -struct Simd([f32; N]); - -fn main() { - let _ = Simd::<65536>([0.; 65536]); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-oversized.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-oversized.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-oversized.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-oversized.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -error: monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768 - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -// run-pass - -#![feature(repr_simd, platform_intrinsics)] - -#[repr(simd)] -struct Simd([f32; N]); - -fn main() { - let _ = Simd::<3>([0.; 3]); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -// build-fail - -#![feature(repr_simd, platform_intrinsics)] - - -// error-pattern:monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` - -struct X(Vec); -#[repr(simd)] -struct Simd2(T, T); - -fn main() { - let _ = Simd2(X(vec![]), X(vec![])); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -error: monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -// build-fail - -#![feature(repr_simd)] - -// error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` - -#[repr(simd)] -struct S(T); - -fn main() { - let _v: Option> = None; -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -#![feature(repr_simd)] -#![allow(non_camel_case_types)] - - -#[repr(simd)] -struct empty; //~ ERROR SIMD vector cannot be empty - -#[repr(simd)] -struct empty2([f32; 0]); //~ ERROR SIMD vector cannot be empty - -#[repr(simd)] -struct pow2([f32; 7]); - -#[repr(simd)] -struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous - -struct Foo; - -#[repr(simd)] -struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type - -#[repr(simd)] -struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type - -#[repr(simd)] -struct TooBig([f32; 65536]); //~ ERROR SIMD vector cannot have more than 32768 elements - -#[repr(simd)] -struct JustRight([u128; 32768]); - -#[repr(simd)] -struct RGBA { - r: f32, - g: f32, - b: f32, - a: f32 -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -error[E0075]: SIMD vector cannot be empty - --> $DIR/simd-type.rs:6:1 - | -LL | struct empty; - | ^^^^^^^^^^^^^ - -error[E0075]: SIMD vector cannot be empty - --> $DIR/simd-type.rs:9:1 - | -LL | struct empty2([f32; 0]); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0076]: SIMD vector should be homogeneous - --> $DIR/simd-type.rs:15:1 - | -LL | struct i64f64(i64, f64); - | ^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type - -error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type - --> $DIR/simd-type.rs:20:1 - | -LL | struct FooV(Foo, Foo); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type - --> $DIR/simd-type.rs:23:1 - | -LL | struct FooV2([Foo; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0075]: SIMD vector cannot have more than 32768 elements - --> $DIR/simd-type.rs:26:1 - | -LL | struct TooBig([f32; 65536]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 6 previous errors - -Some errors have detailed explanations: E0075, E0076, E0077. -For more information about an error, try `rustc --explain E0075`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-wide-ptr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-wide-ptr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-wide-ptr.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-wide-ptr.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -// build-fail - -#![feature(repr_simd)] - -// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` - -#[repr(simd)] -struct S([*mut [u8]; 4]); - -fn main() { - let _v: Option = None; -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-wide-ptr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-wide-ptr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/simd-type-wide-ptr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/simd-type-wide-ptr.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/size-align.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/size-align.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/size-align.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/size-align.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,53 @@ +// run-pass +#![allow(deprecated)] + + +#![feature(repr_simd)] +#![allow(non_camel_case_types)] + +use std::mem; + +/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec` properly +/// Please consult the issue #20460 +fn check() { + assert_eq!(mem::size_of::() % mem::min_align_of::(), 0); + assert_eq!(mem::size_of::() % mem::min_align_of::(), 0); + assert_eq!(mem::size_of::() % mem::min_align_of::(), 0); +} + +#[repr(simd)] +struct U8([u8; N]); + +#[repr(simd)] +struct I16([i16; N]); + +#[repr(simd)] +struct F32([f32; N]); + +#[repr(simd)] +struct Usize([usize; N]); + +#[repr(simd)] +struct Isize([isize; N]); + +fn main() { + check::>(); + check::>(); + check::>(); + + check::>(); + check::>(); + check::>(); + + check::>(); + check::>(); + check::>(); + + check::>(); + check::>(); + check::>(); + + check::>(); + check::>(); + check::>(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/target-feature-mixup.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/target-feature-mixup.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/target-feature-mixup.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/target-feature-mixup.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,185 @@ +// run-pass +#![allow(unused_variables)] +#![allow(stable_features)] +#![allow(overflowing_literals)] + +// ignore-emscripten +// ignore-sgx no processes + +#![feature(repr_simd, target_feature, cfg_target_feature)] +#![feature(avx512_target_feature)] + +use std::process::{Command, ExitStatus}; +use std::env; + +fn main() { + if let Some(level) = env::args().nth(1) { + return test::main(&level) + } + + let me = env::current_exe().unwrap(); + for level in ["sse", "avx", "avx512"].iter() { + let status = Command::new(&me).arg(level).status().unwrap(); + if status.success() { + println!("success with {}", level); + continue + } + + // We don't actually know if our computer has the requisite target features + // for the test below. Testing for that will get added to libstd later so + // for now just assume sigill means this is a machine that can't run this test. + if is_sigill(status) { + println!("sigill with {}, assuming spurious", level); + continue + } + panic!("invalid status at {}: {}", level, status); + } +} + +#[cfg(unix)] +fn is_sigill(status: ExitStatus) -> bool { + use std::os::unix::prelude::*; + status.signal() == Some(4) +} + +#[cfg(windows)] +fn is_sigill(status: ExitStatus) -> bool { + status.code() == Some(0xc000001d) +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[allow(nonstandard_style)] +mod test { + // An SSE type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m128i(u64, u64); + + // An AVX type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m256i(u64, u64, u64, u64); + + // An AVX-512 type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m512i(u64, u64, u64, u64, u64, u64, u64, u64); + + pub fn main(level: &str) { + unsafe { + main_normal(level); + main_sse(level); + if level == "sse" { + return + } + main_avx(level); + if level == "avx" { + return + } + main_avx512(level); + } + } + + macro_rules! mains { + ($( + $(#[$attr:meta])* + unsafe fn $main:ident(level: &str) { + ... + } + )*) => ($( + $(#[$attr])* + unsafe fn $main(level: &str) { + let m128 = __m128i(1, 2); + let m256 = __m256i(3, 4, 5, 6); + let m512 = __m512i(7, 8, 9, 10, 11, 12, 13, 14); + assert_eq!(id_sse_128(m128), m128); + assert_eq!(id_sse_256(m256), m256); + assert_eq!(id_sse_512(m512), m512); + + if level == "sse" { + return + } + assert_eq!(id_avx_128(m128), m128); + assert_eq!(id_avx_256(m256), m256); + assert_eq!(id_avx_512(m512), m512); + + if level == "avx" { + return + } + assert_eq!(id_avx512_128(m128), m128); + assert_eq!(id_avx512_256(m256), m256); + assert_eq!(id_avx512_512(m512), m512); + } + )*) + } + + mains! { + unsafe fn main_normal(level: &str) { ... } + #[target_feature(enable = "sse2")] + unsafe fn main_sse(level: &str) { ... } + #[target_feature(enable = "avx")] + unsafe fn main_avx(level: &str) { ... } + #[target_feature(enable = "avx512bw")] + unsafe fn main_avx512(level: &str) { ... } + } + + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +mod test { + pub fn main(level: &str) {} +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-empty.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-empty.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-empty.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-empty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + +// error-pattern:monomorphising SIMD type `Simd<0_usize>` of zero length + +#[repr(simd)] +struct Simd([f32; N]); + +fn main() { + let _ = Simd::<0>([]); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-empty.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-empty.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-empty.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-empty.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `Simd<0_usize>` of zero length + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,23 @@ +// run-pass +// ignore-emscripten + +#![feature(extern_types)] +#![feature(repr_simd)] + +use std::ptr::NonNull; + +extern { + type Extern; +} + +#[repr(simd)] +struct S(T); + +#[inline(never)] +fn identity(v: T) -> T { + v +} + +fn main() { + let _v: S<[Option>; 4]> = identity(S([None; 4])); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-non-primitive.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-non-primitive.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-non-primitive.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-non-primitive.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// build-fail + +#![feature(repr_simd)] + +struct E; + +// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `E` + +#[repr(simd)] +struct S([T; 4]); + +fn main() { + let _v: Option> = None; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-non-primitive.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-non-primitive.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-non-primitive.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-non-primitive.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `E` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-oversized.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-oversized.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-oversized.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-oversized.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + +// error-pattern:monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768 + +#[repr(simd)] +struct Simd([f32; N]); + +fn main() { + let _ = Simd::<65536>([0.; 65536]); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768 + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-power-of-two.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-power-of-two.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-power-of-two.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-power-of-two.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,10 @@ +// run-pass + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +struct Simd([f32; N]); + +fn main() { + let _ = Simd::<3>([0.; 3]); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,14 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + + +// error-pattern:monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` + +struct X(Vec); +#[repr(simd)] +struct Simd2(T, T); + +fn main() { + let _ = Simd2(X(vec![]), X(vec![])); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// build-fail + +#![feature(repr_simd)] + +// error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +#[repr(simd)] +struct S(T); + +fn main() { + let _v: Option> = None; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-len.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-len.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-len.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-len.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,39 @@ +#![feature(repr_simd)] +#![allow(non_camel_case_types)] + + +#[repr(simd)] +struct empty; //~ ERROR SIMD vector cannot be empty + +#[repr(simd)] +struct empty2([f32; 0]); //~ ERROR SIMD vector cannot be empty + +#[repr(simd)] +struct pow2([f32; 7]); + +#[repr(simd)] +struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous + +struct Foo; + +#[repr(simd)] +struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type + +#[repr(simd)] +struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type + +#[repr(simd)] +struct TooBig([f32; 65536]); //~ ERROR SIMD vector cannot have more than 32768 elements + +#[repr(simd)] +struct JustRight([u128; 32768]); + +#[repr(simd)] +struct RGBA { + r: f32, + g: f32, + b: f32, + a: f32 +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-len.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-len.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-len.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-len.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,40 @@ +error[E0075]: SIMD vector cannot be empty + --> $DIR/type-len.rs:6:1 + | +LL | struct empty; + | ^^^^^^^^^^^^^ + +error[E0075]: SIMD vector cannot be empty + --> $DIR/type-len.rs:9:1 + | +LL | struct empty2([f32; 0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0076]: SIMD vector should be homogeneous + --> $DIR/type-len.rs:15:1 + | +LL | struct i64f64(i64, f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type + +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/type-len.rs:20:1 + | +LL | struct FooV(Foo, Foo); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/type-len.rs:23:1 + | +LL | struct FooV2([Foo; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0075]: SIMD vector cannot have more than 32768 elements + --> $DIR/type-len.rs:26:1 + | +LL | struct TooBig([f32; 65536]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0075, E0076, E0077. +For more information about an error, try `rustc --explain E0075`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-wide-ptr.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-wide-ptr.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-wide-ptr.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-wide-ptr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,12 @@ +// build-fail + +#![feature(repr_simd)] + +// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +#[repr(simd)] +struct S([*mut [u8]; 4]); + +fn main() { + let _v: Option = None; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-wide-ptr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-wide-ptr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd/type-wide-ptr.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd/type-wide-ptr.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/issue-85855.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/issue-85855.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/issue-85855.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/issue-85855.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -// Check that appropriate errors are reported if an intrinsic is defined -// with the wrong number of generic lifetime/type/const parameters, and -// that no ICE occurs in these cases. - -#![feature(platform_intrinsics)] -#![crate_type="lib"] - -extern "platform-intrinsic" { - fn simd_saturating_add<'a, T: 'a>(x: T, y: T); - //~^ ERROR: intrinsic has wrong number of lifetime parameters - - fn simd_add<'a, T>(x: T, y: T) -> T; - - fn simd_sub(x: T, y: U); - //~^ ERROR: intrinsic has wrong number of type parameters - - fn simd_mul(x: T, y: T); - //~^ ERROR: intrinsic has wrong number of const parameters -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/issue-85855.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/issue-85855.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/issue-85855.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/issue-85855.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -error[E0094]: intrinsic has wrong number of lifetime parameters: found 1, expected 0 - --> $DIR/issue-85855.rs:9:27 - | -LL | fn simd_saturating_add<'a, T: 'a>(x: T, y: T); - | ^^^^^^^^^^^ expected 0 lifetime parameters - -error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1 - --> $DIR/issue-85855.rs:14:16 - | -LL | fn simd_sub(x: T, y: U); - | ^^^^^^ expected 1 type parameter - -error[E0094]: intrinsic has wrong number of const parameters: found 1, expected 0 - --> $DIR/issue-85855.rs:17:16 - | -LL | fn simd_mul(x: T, y: T); - | ^^^^^^^^^^^^^^^^^^^ expected 0 const parameters - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0094`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -// build-fail - -#![feature(repr_simd, platform_intrinsics)] -#![allow(non_camel_case_types)] -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct i32x4(pub i32, pub i32, pub i32, pub i32); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct u32x4(pub u32, pub u32, pub u32, pub u32); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct f32x4(pub f32, pub f32, pub f32, pub f32); - -extern "platform-intrinsic" { - fn simd_add(x: T, y: T) -> T; - fn simd_sub(x: T, y: T) -> T; - fn simd_mul(x: T, y: T) -> T; - fn simd_div(x: T, y: T) -> T; - fn simd_rem(x: T, y: T) -> T; - fn simd_shl(x: T, y: T) -> T; - fn simd_shr(x: T, y: T) -> T; - fn simd_and(x: T, y: T) -> T; - fn simd_or(x: T, y: T) -> T; - fn simd_xor(x: T, y: T) -> T; - - fn simd_neg(x: T) -> T; -} - -fn main() { - let x = i32x4(0, 0, 0, 0); - let y = u32x4(0, 0, 0, 0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); - - unsafe { - simd_add(x, x); - simd_add(y, y); - simd_add(z, z); - simd_sub(x, x); - simd_sub(y, y); - simd_sub(z, z); - simd_mul(x, x); - simd_mul(y, y); - simd_mul(z, z); - simd_div(x, x); - simd_div(y, y); - simd_div(z, z); - simd_rem(x, x); - simd_rem(y, y); - simd_rem(z, z); - - simd_shl(x, x); - simd_shl(y, y); - simd_shr(x, x); - simd_shr(y, y); - simd_and(x, x); - simd_and(y, y); - simd_or(x, x); - simd_or(y, y); - simd_xor(x, x); - simd_xor(y, y); - - simd_neg(x); - simd_neg(z); - - - simd_add(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_sub(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_mul(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_div(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_shl(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_shr(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_and(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_or(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_xor(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - - simd_neg(0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - - - simd_shl(z, z); -//~^ ERROR unsupported operation on `f32x4` with element `f32` - simd_shr(z, z); -//~^ ERROR unsupported operation on `f32x4` with element `f32` - simd_and(z, z); -//~^ ERROR unsupported operation on `f32x4` with element `f32` - simd_or(z, z); -//~^ ERROR unsupported operation on `f32x4` with element `f32` - simd_xor(z, z); -//~^ ERROR unsupported operation on `f32x4` with element `f32` - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -// build-fail -// ignore-emscripten -#![feature(repr_simd, platform_intrinsics)] -#![allow(non_camel_case_types)] -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct i32x4(pub i32, pub i32, pub i32, pub i32); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct x4(pub T, pub T, pub T, pub T); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct f32x4(pub f32, pub f32, pub f32, pub f32); - -extern "platform-intrinsic" { - fn simd_saturating_add(x: T, y: T) -> T; - fn simd_saturating_sub(x: T, y: T) -> T; -} - -fn main() { - let x = i32x4(0, 0, 0, 0); - let y = x4(0_usize, 0, 0, 0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); - - unsafe { - simd_saturating_add(x, x); - simd_saturating_add(y, y); - simd_saturating_sub(x, x); - simd_saturating_sub(y, y); - - simd_saturating_add(z, z); - //~^ ERROR expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type - simd_saturating_sub(z, z); - //~^ ERROR expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -error[E0511]: invalid monomorphization of `simd_saturating_add` intrinsic: expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type - --> $DIR/simd-intrinsic-generic-arithmetic-saturating.rs:33:9 - | -LL | simd_saturating_add(z, z); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_saturating_sub` intrinsic: expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type - --> $DIR/simd-intrinsic-generic-arithmetic-saturating.rs:35:9 - | -LL | simd_saturating_sub(z, z); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-arithmetic.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:69:9 - | -LL | simd_add(0, 0); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_sub` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:71:9 - | -LL | simd_sub(0, 0); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_mul` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:73:9 - | -LL | simd_mul(0, 0); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_div` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:75:9 - | -LL | simd_div(0, 0); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shl` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:77:9 - | -LL | simd_shl(0, 0); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shr` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:79:9 - | -LL | simd_shr(0, 0); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_and` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:81:9 - | -LL | simd_and(0, 0); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_or` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:83:9 - | -LL | simd_or(0, 0); - | ^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_xor` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:85:9 - | -LL | simd_xor(0, 0); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_neg` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:88:9 - | -LL | simd_neg(0); - | ^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:92:9 - | -LL | simd_shl(z, z); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:94:9 - | -LL | simd_shr(z, z); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:96:9 - | -LL | simd_and(z, z); - | ^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:98:9 - | -LL | simd_or(z, z); - | ^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/simd-intrinsic-generic-arithmetic.rs:100:9 - | -LL | simd_xor(z, z); - | ^^^^^^^^^^^^^^ - -error: aborting due to 15 previous errors - -For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -// build-fail - -// Test that the simd_bitmask intrinsic produces ok-ish error -// messages when misused. - -#![feature(repr_simd, platform_intrinsics)] -#![allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct u32x2(pub u32, pub u32); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct u32x4(pub u32, pub u32, pub u32, pub u32); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x8( - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, -); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x16( - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, -); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x32( - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, -); - -#[repr(simd)] -#[derive(Copy, Clone)] -struct u8x64( - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, - pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, -); - -extern "platform-intrinsic" { - fn simd_bitmask(x: T) -> U; -} - -fn main() { - let m2 = u32x2(0, 0); - let m4 = u32x4(0, 0, 0, 0); - let m8 = u8x8(0, 0, 0, 0, 0, 0, 0, 0); - let m16 = u8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - let m32 = u8x32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - let m64 = u8x64(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - - unsafe { - let _: u8 = simd_bitmask(m2); - let _: u8 = simd_bitmask(m4); - let _: u8 = simd_bitmask(m8); - let _: u16 = simd_bitmask(m16); - let _: u32 = simd_bitmask(m32); - let _: u64 = simd_bitmask(m64); - - let _: u16 = simd_bitmask(m2); - //~^ ERROR bitmask `u16`, expected `u8` - - let _: u16 = simd_bitmask(m8); - //~^ ERROR bitmask `u16`, expected `u8` - - let _: u32 = simd_bitmask(m16); - //~^ ERROR bitmask `u32`, expected `u16` - - let _: u64 = simd_bitmask(m32); - //~^ ERROR bitmask `u64`, expected `u32` - - let _: u128 = simd_bitmask(m64); - //~^ ERROR bitmask `u128`, expected `u64` - - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-bitmask.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8` - --> $DIR/simd-intrinsic-generic-bitmask.rs:76:22 - | -LL | let _: u16 = simd_bitmask(m2); - | ^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8` - --> $DIR/simd-intrinsic-generic-bitmask.rs:79:22 - | -LL | let _: u16 = simd_bitmask(m8); - | ^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u32`, expected `u16` - --> $DIR/simd-intrinsic-generic-bitmask.rs:82:22 - | -LL | let _: u32 = simd_bitmask(m16); - | ^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u64`, expected `u32` - --> $DIR/simd-intrinsic-generic-bitmask.rs:85:22 - | -LL | let _: u64 = simd_bitmask(m32); - | ^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u128`, expected `u64` - --> $DIR/simd-intrinsic-generic-bitmask.rs:88:23 - | -LL | let _: u128 = simd_bitmask(m64); - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -// build-fail - -#![feature(repr_simd, platform_intrinsics)] - -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); - -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct f32x4(f32, f32, f32, f32); -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct f32x8(f32, f32, f32, f32, - f32, f32, f32, f32); - - -extern "platform-intrinsic" { - fn simd_cast(x: T) -> U; -} - -fn main() { - let x = i32x4(0, 0, 0, 0); - - unsafe { - simd_cast::(0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_cast::(0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_cast::(x); - //~^ ERROR expected SIMD return type, found non-SIMD `i32` - simd_cast::<_, i32x8>(x); -//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i32x8` with length 8 - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-cast.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-cast.rs:34:9 - | -LL | simd_cast::(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-cast.rs:36:9 - | -LL | simd_cast::(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-cast.rs:38:9 - | -LL | simd_cast::(x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i32x8` with length 8 - --> $DIR/simd-intrinsic-generic-cast.rs:40:9 - | -LL | simd_cast::<_, i32x8>(x); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -// build-fail - -#![feature(repr_simd, platform_intrinsics)] - -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct i16x8(i16, i16, i16, i16, - i16, i16, i16, i16); - -extern "platform-intrinsic" { - fn simd_eq(x: T, y: T) -> U; - fn simd_ne(x: T, y: T) -> U; - fn simd_lt(x: T, y: T) -> U; - fn simd_le(x: T, y: T) -> U; - fn simd_gt(x: T, y: T) -> U; - fn simd_ge(x: T, y: T) -> U; -} - -fn main() { - let x = i32x4(0, 0, 0, 0); - - unsafe { - simd_eq::(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_ne::(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_lt::(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_le::(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_gt::(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_ge::(0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - - simd_eq::<_, i32>(x, x); - //~^ ERROR expected SIMD return type, found non-SIMD `i32` - simd_ne::<_, i32>(x, x); - //~^ ERROR expected SIMD return type, found non-SIMD `i32` - simd_lt::<_, i32>(x, x); - //~^ ERROR expected SIMD return type, found non-SIMD `i32` - simd_le::<_, i32>(x, x); - //~^ ERROR expected SIMD return type, found non-SIMD `i32` - simd_gt::<_, i32>(x, x); - //~^ ERROR expected SIMD return type, found non-SIMD `i32` - simd_ge::<_, i32>(x, x); - //~^ ERROR expected SIMD return type, found non-SIMD `i32` - - simd_eq::<_, i16x8>(x, x); -//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - simd_ne::<_, i16x8>(x, x); -//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - simd_lt::<_, i16x8>(x, x); -//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - simd_le::<_, i16x8>(x, x); -//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - simd_gt::<_, i16x8>(x, x); -//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - simd_ge::<_, i16x8>(x, x); -//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-comparison.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:28:9 - | -LL | simd_eq::(0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:30:9 - | -LL | simd_ne::(0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:32:9 - | -LL | simd_lt::(0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:34:9 - | -LL | simd_le::(0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:36:9 - | -LL | simd_gt::(0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:38:9 - | -LL | simd_ge::(0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:41:9 - | -LL | simd_eq::<_, i32>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:43:9 - | -LL | simd_ne::<_, i32>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:45:9 - | -LL | simd_lt::<_, i32>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:47:9 - | -LL | simd_le::<_, i32>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:49:9 - | -LL | simd_gt::<_, i32>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected SIMD return type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-comparison.rs:51:9 - | -LL | simd_ge::<_, i32>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/simd-intrinsic-generic-comparison.rs:54:9 - | -LL | simd_eq::<_, i16x8>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/simd-intrinsic-generic-comparison.rs:56:9 - | -LL | simd_ne::<_, i16x8>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/simd-intrinsic-generic-comparison.rs:58:9 - | -LL | simd_lt::<_, i16x8>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/simd-intrinsic-generic-comparison.rs:60:9 - | -LL | simd_le::<_, i16x8>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/simd-intrinsic-generic-comparison.rs:62:9 - | -LL | simd_gt::<_, i16x8>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 - --> $DIR/simd-intrinsic-generic-comparison.rs:64:9 - | -LL | simd_ge::<_, i16x8>(x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 18 previous errors - -For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -// build-fail - -#![feature(repr_simd, platform_intrinsics, rustc_attrs)] - -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct i32x2(i32, i32); -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct i32x4(i32, i32, i32, i32); -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); - -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct f32x2(f32, f32); -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct f32x4(f32, f32, f32, f32); -#[repr(simd)] -#[derive(Copy, Clone)] -#[allow(non_camel_case_types)] -struct f32x8(f32, f32, f32, f32, - f32, f32, f32, f32); - -extern "platform-intrinsic" { - fn simd_insert(x: T, idx: u32, y: E) -> T; - fn simd_extract(x: T, idx: u32) -> E; - - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; - fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; - fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; -} - -fn main() { - let x = i32x4(0, 0, 0, 0); - - unsafe { - simd_insert(0, 0, 0); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - simd_insert(x, 0, 1.0); - //~^ ERROR expected inserted type `i32` (element of input `i32x4`), found `f64` - simd_extract::<_, f32>(x, 0); - //~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32` - - const IDX2: [u32; 2] = [0; 2]; - simd_shuffle2::(0, 0, IDX2); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - const IDX4: [u32; 4] = [0; 4]; - simd_shuffle4::(0, 0, IDX4); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - const IDX8: [u32; 8] = [0; 8]; - simd_shuffle8::(0, 0, IDX8); - //~^ ERROR expected SIMD input type, found non-SIMD `i32` - - simd_shuffle2::<_, f32x2>(x, x, IDX2); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - simd_shuffle4::<_, f32x4>(x, x, IDX4); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - simd_shuffle8::<_, f32x8>(x, x, IDX8); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - - simd_shuffle2::<_, i32x8>(x, x, IDX2); - //~^ ERROR expected return type of length 2, found `i32x8` with length 8 - simd_shuffle4::<_, i32x8>(x, x, IDX4); - //~^ ERROR expected return type of length 4, found `i32x8` with length 8 - simd_shuffle8::<_, i32x2>(x, x, IDX8); - //~^ ERROR expected return type of length 8, found `i32x2` with length 2 - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-elements.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-elements.rs:46:9 - | -LL | simd_insert(0, 0, 0); - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64` - --> $DIR/simd-intrinsic-generic-elements.rs:48:9 - | -LL | simd_insert(x, 0, 1.0); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32` - --> $DIR/simd-intrinsic-generic-elements.rs:50:9 - | -LL | simd_extract::<_, f32>(x, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-elements.rs:54:9 - | -LL | simd_shuffle2::(0, 0, IDX2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-elements.rs:57:9 - | -LL | simd_shuffle4::(0, 0, IDX4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/simd-intrinsic-generic-elements.rs:60:9 - | -LL | simd_shuffle8::(0, 0, IDX8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/simd-intrinsic-generic-elements.rs:63:9 - | -LL | simd_shuffle2::<_, f32x2>(x, x, IDX2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/simd-intrinsic-generic-elements.rs:65:9 - | -LL | simd_shuffle4::<_, f32x4>(x, x, IDX4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/simd-intrinsic-generic-elements.rs:67:9 - | -LL | simd_shuffle8::<_, f32x8>(x, x, IDX8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/simd-intrinsic-generic-elements.rs:70:9 - | -LL | simd_shuffle2::<_, i32x8>(x, x, IDX2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/simd-intrinsic-generic-elements.rs:72:9 - | -LL | simd_shuffle4::<_, i32x8>(x, x, IDX4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/simd-intrinsic-generic-elements.rs:74:9 - | -LL | simd_shuffle8::<_, i32x2>(x, x, IDX8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 12 previous errors - -For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -// build-fail -// ignore-emscripten - -// Test that the simd_reduce_{op} intrinsics produce ok-ish error -// messages when misused. - -#![feature(repr_simd, platform_intrinsics)] -#![allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct f32x4(pub f32, pub f32, pub f32, pub f32); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct u32x4(pub u32, pub u32, pub u32, pub u32); - - -extern "platform-intrinsic" { - fn simd_reduce_add_ordered(x: T, y: U) -> U; - fn simd_reduce_mul_ordered(x: T, y: U) -> U; - fn simd_reduce_and(x: T) -> U; - fn simd_reduce_or(x: T) -> U; - fn simd_reduce_xor(x: T) -> U; - fn simd_reduce_all(x: T) -> bool; - fn simd_reduce_any(x: T) -> bool; -} - -fn main() { - let x = u32x4(0, 0, 0, 0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); - - unsafe { - simd_reduce_add_ordered(z, 0); - //~^ ERROR expected return type `f32` (element of input `f32x4`), found `i32` - simd_reduce_mul_ordered(z, 1); - //~^ ERROR expected return type `f32` (element of input `f32x4`), found `i32` - - let _: f32 = simd_reduce_and(x); - //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` - let _: f32 = simd_reduce_or(x); - //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` - let _: f32 = simd_reduce_xor(x); - //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` - - let _: f32 = simd_reduce_and(z); - //~^ ERROR unsupported simd_reduce_and from `f32x4` with element `f32` to `f32` - let _: f32 = simd_reduce_or(z); - //~^ ERROR unsupported simd_reduce_or from `f32x4` with element `f32` to `f32` - let _: f32 = simd_reduce_xor(z); - //~^ ERROR unsupported simd_reduce_xor from `f32x4` with element `f32` to `f32` - - let _: bool = simd_reduce_all(z); - //~^ ERROR unsupported simd_reduce_all from `f32x4` with element `f32` to `bool` - let _: bool = simd_reduce_any(z); - //~^ ERROR unsupported simd_reduce_any from `f32x4` with element `f32` to `bool` - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-reduction.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -error[E0511]: invalid monomorphization of `simd_reduce_add_ordered` intrinsic: expected return type `f32` (element of input `f32x4`), found `i32` - --> $DIR/simd-intrinsic-generic-reduction.rs:34:9 - | -LL | simd_reduce_add_ordered(z, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_mul_ordered` intrinsic: expected return type `f32` (element of input `f32x4`), found `i32` - --> $DIR/simd-intrinsic-generic-reduction.rs:36:9 - | -LL | simd_reduce_mul_ordered(z, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_and` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` - --> $DIR/simd-intrinsic-generic-reduction.rs:39:22 - | -LL | let _: f32 = simd_reduce_and(x); - | ^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_or` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` - --> $DIR/simd-intrinsic-generic-reduction.rs:41:22 - | -LL | let _: f32 = simd_reduce_or(x); - | ^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_xor` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` - --> $DIR/simd-intrinsic-generic-reduction.rs:43:22 - | -LL | let _: f32 = simd_reduce_xor(x); - | ^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_and` intrinsic: unsupported simd_reduce_and from `f32x4` with element `f32` to `f32` - --> $DIR/simd-intrinsic-generic-reduction.rs:46:22 - | -LL | let _: f32 = simd_reduce_and(z); - | ^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_or` intrinsic: unsupported simd_reduce_or from `f32x4` with element `f32` to `f32` - --> $DIR/simd-intrinsic-generic-reduction.rs:48:22 - | -LL | let _: f32 = simd_reduce_or(z); - | ^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_xor` intrinsic: unsupported simd_reduce_xor from `f32x4` with element `f32` to `f32` - --> $DIR/simd-intrinsic-generic-reduction.rs:50:22 - | -LL | let _: f32 = simd_reduce_xor(z); - | ^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_all` intrinsic: unsupported simd_reduce_all from `f32x4` with element `f32` to `bool` - --> $DIR/simd-intrinsic-generic-reduction.rs:53:23 - | -LL | let _: bool = simd_reduce_all(z); - | ^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_reduce_any` intrinsic: unsupported simd_reduce_any from `f32x4` with element `f32` to `bool` - --> $DIR/simd-intrinsic-generic-reduction.rs:55:23 - | -LL | let _: bool = simd_reduce_any(z); - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 10 previous errors - -For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -// build-fail - -// Test that the simd_select intrinsic produces ok-ish error -// messages when misused. - -#![feature(repr_simd, platform_intrinsics)] -#![allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct f32x4(pub f32, pub f32, pub f32, pub f32); - -#[repr(simd)] -#[derive(Copy, Clone)] -pub struct u32x4(pub u32, pub u32, pub u32, pub u32); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq)] -struct b8x4(pub i8, pub i8, pub i8, pub i8); - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq)] -struct b8x8(pub i8, pub i8, pub i8, pub i8, - pub i8, pub i8, pub i8, pub i8); - -extern "platform-intrinsic" { - fn simd_select(x: T, a: U, b: U) -> U; - fn simd_select_bitmask(x: T, a: U, b: U) -> U; -} - -fn main() { - let m4 = b8x4(0, 0, 0, 0); - let m8 = b8x8(0, 0, 0, 0, 0, 0, 0, 0); - let x = u32x4(0, 0, 0, 0); - let z = f32x4(0.0, 0.0, 0.0, 0.0); - - unsafe { - simd_select(m4, x, x); - - simd_select(m8, x, x); - //~^ ERROR mismatched lengths: mask length `8` != other vector length `4` - - simd_select(x, x, x); - //~^ ERROR mask element type is `u32`, expected `i_` - - simd_select(z, z, z); - //~^ ERROR mask element type is `f32`, expected `i_` - - simd_select(m4, 0u32, 1u32); - //~^ ERROR found non-SIMD `u32` - - simd_select_bitmask(0u16, x, x); - //~^ ERROR mask length `16` != other vector length `4` - // - simd_select_bitmask(0u8, 1u32, 2u32); - //~^ ERROR found non-SIMD `u32` - - simd_select_bitmask(0.0f32, x, x); - //~^ ERROR `f32` is not an integral type - - simd_select_bitmask("x", x, x); - //~^ ERROR `&str` is not an integral type - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -error[E0511]: invalid monomorphization of `simd_select` intrinsic: mismatched lengths: mask length `8` != other vector length `4` - --> $DIR/simd-intrinsic-generic-select.rs:40:9 - | -LL | simd_select(m8, x, x); - | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `u32`, expected `i_` - --> $DIR/simd-intrinsic-generic-select.rs:43:9 - | -LL | simd_select(x, x, x); - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `f32`, expected `i_` - --> $DIR/simd-intrinsic-generic-select.rs:46:9 - | -LL | simd_select(z, z, z); - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32` - --> $DIR/simd-intrinsic-generic-select.rs:49:9 - | -LL | simd_select(m4, 0u32, 1u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `16` != other vector length `4` - --> $DIR/simd-intrinsic-generic-select.rs:52:9 - | -LL | simd_select_bitmask(0u16, x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32` - --> $DIR/simd-intrinsic-generic-select.rs:55:9 - | -LL | simd_select_bitmask(0u8, 1u32, 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type - --> $DIR/simd-intrinsic-generic-select.rs:58:9 - | -LL | simd_select_bitmask(0.0f32, x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type - --> $DIR/simd-intrinsic-generic-select.rs:61:9 - | -LL | simd_select_bitmask("x", x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 8 previous errors - -For more information about this error, try `rustc --explain E0511`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-inlining-issue67557-ice.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-inlining-issue67557-ice.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-inlining-issue67557-ice.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-inlining-issue67557-ice.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -// This used to cause an ICE for an internal index out of range due to simd_shuffle_indices being -// passed the wrong Instance, causing issues with inlining. See #67557. -// -// run-pass -// compile-flags: -Zmir-opt-level=4 -#![feature(platform_intrinsics, repr_simd)] - -extern "platform-intrinsic" { - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; -} - -#[repr(simd)] -#[derive(Debug, PartialEq)] -struct Simd2(u8, u8); - -fn main() { - unsafe { - let _: Simd2 = inline_me(); - } -} - -#[inline(always)] -unsafe fn inline_me() -> Simd2 { - const IDX: [u32; 2] = [0, 3]; - simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX) -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-inlining-issue67557.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-inlining-issue67557.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-inlining-issue67557.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/simd-intrinsic/simd-intrinsic-inlining-issue67557.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -// This used to cause assert_10_13 to unexpectingly fail, due to simd_shuffle_indices being passed -// the wrong Instance, causing issues with inlining. See #67557. -// -// run-pass -// compile-flags: -Zmir-opt-level=4 -#![feature(platform_intrinsics, repr_simd)] - -extern "platform-intrinsic" { - fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; -} - -#[repr(simd)] -#[derive(Debug, PartialEq)] -struct Simd2(u8, u8); - -fn main() { - unsafe { - const IDX: [u32; 2] = [0, 1]; - let p_res: Simd2 = simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX); - let a_res: Simd2 = inline_me(); - - assert_10_11(p_res); - assert_10_13(a_res); - } -} - -#[inline(never)] -fn assert_10_11(x: Simd2) { - assert_eq!(x, Simd2(10, 11)); -} - -#[inline(never)] -fn assert_10_13(x: Simd2) { - assert_eq!(x, Simd2(10, 13)); -} - - -#[inline(always)] -unsafe fn inline_me() -> Simd2 { - const IDX: [u32; 2] = [0, 3]; - simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX) -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -56,7 +56,7 @@ LL | fn deref_mut_method1(x: Own) { | - help: consider changing this to be mutable: `mut x` LL | x.set(0, 0); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:121:5 @@ -64,7 +64,7 @@ LL | fn deref_extend_mut_method1(x: &Own) -> &mut isize { | ----------- help: consider changing this to be a mutable reference: `&mut Own` LL | x.y_mut() - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6 @@ -72,7 +72,7 @@ LL | fn assign_method1<'a>(x: Own) { | - help: consider changing this to be mutable: `mut x` LL | *x.y_mut() = 3; - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:133:6 @@ -80,7 +80,7 @@ LL | fn assign_method2<'a>(x: &'a Own) { | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` LL | *x.y_mut() = 3; - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 10 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -24,16 +24,22 @@ LL | fn test4(f: &Test) { | ----- help: consider changing this to be a mutable reference: `&mut Test<'_>` LL | f.f.call_mut(()) - | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13 | -LL | let mut f = move |g: Box, b: isize| { - | ----- captured outer variable +LL | let mut f = move |g: Box, b: isize| { + | ----- captured outer variable ... -LL | foo(f); - | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait +LL | f(Box::new(|a| { + | ________________- +LL | | +LL | | foo(f); + | | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait +LL | | +LL | | }), 3); + | |_____- captured by this `FnMut` closure error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ---- help: consider changing this to be a mutable reference: `&mut Foo` LL | x.f(); LL | x.h(); - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-fn-in-const-b.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-fn-in-const-b.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-fn-in-const-b.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-fn-in-const-b.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | fn broken(x: &Vec) { | ------------ help: consider changing this to be a mutable reference: `&mut Vec` LL | x.push(format!("this is broken")); - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -32,7 +32,7 @@ | creates a temporary which is freed while still in use ... LL | v4.use_ref(); - | -- borrow later used here + | ------------ borrow later used here | = note: consider using a `let` binding to create a longer lived value diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-object-mutability.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-object-mutability.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/borrowck-object-mutability.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/borrowck-object-mutability.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | -------- help: consider changing this to be a mutable reference: `&mut dyn Foo` LL | x.borrowed(); LL | x.borrowed_mut(); - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable --> $DIR/borrowck-object-mutability.rs:18:5 @@ -14,7 +14,7 @@ | - help: consider changing this to be mutable: `mut x` LL | x.borrowed(); LL | x.borrowed_mut(); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/coerce-suggestions.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/span/coerce-suggestions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/coerce-suggestions.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/coerce-suggestions.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn test(_x: &mut String) {} + fn test2(_x: &mut i32) {} + fn main() { let x: usize = String::new(); //~^ ERROR E0308 @@ -14,7 +14,7 @@ test2(&y); //~^ ERROR E0308 let f; - f = box f; + f = Box::new(f); //~^ ERROR E0308 let s = &mut String::new(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/coerce-suggestions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/coerce-suggestions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/coerce-suggestions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/coerce-suggestions.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -37,13 +37,10 @@ error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:17:9 | -LL | f = box f; - | ^^^^^ cyclic type of infinite size - | -help: try using a conversion method - | -LL | f = (box f).to_string(); - | + +++++++++++++ +LL | f = Box::new(f); + | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | cyclic type of infinite size error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:21:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/destructor-restrictions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/destructor-restrictions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/destructor-restrictions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/destructor-restrictions.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/destructor-restrictions.rs:8:10 | LL | *a.borrow() + 1 - | ^--------- + | ^^^^^^^^^^ | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-11925.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-11925.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-11925.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-11925.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,10 @@ -#![feature(box_syntax, unboxed_closures)] +#![feature(unboxed_closures)] fn to_fn_once>(f: F) -> F { f } fn main() { let r = { - let x: Box<_> = box 42; + let x: Box<_> = Box::new(42); let f = to_fn_once(move|| &x); //~ ERROR cannot return reference to local data `x` f() }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:10:5 | LL | y.borrow().clone() - | ^--------- + | ^^^^^^^^^^ | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... @@ -23,7 +23,7 @@ --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:17:9 | LL | y.borrow().clone() - | ^--------- + | ^^^^^^^^^^ | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-34264.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-34264.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-34264.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-34264.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -8,11 +8,11 @@ help: if this is a `self` type, give it a parameter name | LL | fn foo(self: Option, String) {} - | ~~~~~~~~~~~~ + | +++++ help: if this is a type, explicitly ignore the parameter name | LL | fn foo(_: Option, String) {} - | ~~~~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/issue-34264.rs:1:27 @@ -24,11 +24,11 @@ help: if this is a parameter name, give it a type | LL | fn foo(Option, String: TypeName) {} - | ~~~~~~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | fn foo(Option, _: String) {} - | ~~~~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/issue-34264.rs:3:9 @@ -40,15 +40,15 @@ help: if this is a `self` type, give it a parameter name | LL | fn bar(self: x, y: usize) {} - | ~~~~~~~ + | +++++ help: if this is a parameter name, give it a type | LL | fn bar(x: TypeName, y: usize) {} - | ~~~~~~~~~~~ + | ++++++++++ help: if this is a type, explicitly ignore the parameter name | LL | fn bar(_: x, y: usize) {} - | ~~~~ + | ++ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-36537.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-36537.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-36537.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-36537.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | } | - `a` dropped here while still borrowed LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-39018.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-39018.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-39018.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-39018.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -20,7 +20,22 @@ | | | World | - = note: an implementation of `std::ops::Add` might be missing for `World` +note: an implementation of `Add<_>` might be missing for `World` + --> $DIR/issue-39018.rs:15:1 + | +LL | enum World { + | ^^^^^^^^^^ must implement `Add<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Add { +LL | | /// The resulting type after applying the `+` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn add(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot add `String` to `&str` --> $DIR/issue-39018.rs:11:22 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-40157.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-40157.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-40157.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-40157.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-40157.rs:2:53 | LL | {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} - | ------------------------^^^--------- + | ------------------------^^^^^^^^^^-- | | | | | | | `foo` dropped here while still borrowed | | borrowed value does not live long enough diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-7575.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-7575.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/issue-7575.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/issue-7575.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -27,16 +27,16 @@ candidate #3: `UnusedTrait` help: disambiguate the associated function for candidate #1 | -LL | u.f8(42) + CtxtFn::f9(u, 342) + m.fff(42) - | ~~~~~~~~~~~~~~~~~~ +LL | u.f8(42) + ::f9(u, 342) + m.fff(42) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ help: disambiguate the associated function for candidate #2 | -LL | u.f8(42) + OtherTrait::f9(u, 342) + m.fff(42) - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | u.f8(42) + ::f9(u, 342) + m.fff(42) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ help: disambiguate the associated function for candidate #3 | -LL | u.f8(42) + UnusedTrait::f9(u, 342) + m.fff(42) - | ~~~~~~~~~~~~~~~~~~~~~~~ +LL | u.f8(42) + ::f9(u, 342) + m.fff(42) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0599]: no method named `fff` found for struct `Myisize` in the current scope --> $DIR/issue-7575.rs:62:30 @@ -72,7 +72,7 @@ = help: items from traits can only be used if the type parameter is bounded by the trait help: disambiguate the associated function for the candidate | -LL | ManyImplTrait::is_str(t) +LL | ::is_str(t) | error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/macro-span-replacement.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/macro-span-replacement.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/macro-span-replacement.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/macro-span-replacement.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ | ^ ... LL | m!(S struct); - | ------------- in this macro invocation + | ------------ in this macro invocation | note: the lint level is defined here --> $DIR/macro-span-replacement.rs:3:9 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/mut-arg-hint.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/mut-arg-hint.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/mut-arg-hint.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/mut-arg-hint.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -4,7 +4,7 @@ LL | fn foo(mut a: &String) { | ------- help: consider changing this to be a mutable reference: `&mut String` LL | a.push_str("bar"); - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:8:5 @@ -12,7 +12,7 @@ LL | pub fn foo<'a>(mut a: &'a String) { | ---------- help: consider changing this to be a mutable reference: `&'a mut String` LL | a.push_str("foo"); - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:15:9 @@ -20,7 +20,7 @@ LL | pub fn foo(mut a: &String) { | ------- help: consider changing this to be a mutable reference: `&mut String` LL | a.push_str("foo"); - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | - `b` dropped here while still borrowed LL | LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | } | - `c` dropped here while still borrowed LL | f.use_mut(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - fn id(x: T) -> T { x } trait Foo { } @@ -7,10 +5,12 @@ impl<'a> Foo for &'a isize { } fn main() { + let blah; + { let ss: &isize = &id(1); //~^ ERROR temporary value dropped while borrowed - blah = box ss as Box; + blah = Box::new(ss) as Box; } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/regions-close-over-type-parameter-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/span/regions-close-over-type-parameter-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/regions-close-over-type-parameter-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/regions-close-over-type-parameter-2.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - // Test for what happens when a type parameter `A` is closed over into // an object. This should yield errors unless `A` (and the object) // both have suitable bounds. @@ -7,14 +5,16 @@ trait Foo { fn get(&self); } impl Foo for A { - fn get(&self) { } + fn get(&self) { + } } fn repeater3<'a,A:'a>(v: A) -> Box { - box v as Box + Box::new(v) as Box } fn main() { + // Error results because the type of is inferred to be // ~Repeat<&'blk isize> where blk is the lifetime of the block below. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/regions-escape-loop-via-vec.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/regions-escape-loop-via-vec.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/regions-escape-loop-via-vec.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/regions-escape-loop-via-vec.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^ use of borrowed `x` LL | let mut z = x; LL | _y.push(&mut z); - | -- borrow later used here + | --------------- borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/regions-escape-loop-via-vec.rs:6:21 @@ -18,14 +18,15 @@ LL | let mut z = x; | ^ use of borrowed `x` LL | _y.push(&mut z); - | -- borrow later used here + | --------------- borrow later used here error[E0597]: `z` does not live long enough --> $DIR/regions-escape-loop-via-vec.rs:7:17 | LL | _y.push(&mut z); - | -- ^^^^^^ borrowed value does not live long enough - | | + | --------^^^^^^- + | | | + | | borrowed value does not live long enough | borrow later used here ... LL | } @@ -38,7 +39,7 @@ | ------ borrow of `x` occurs here ... LL | _y.push(&mut z); - | -- borrow later used here + | --------------- borrow later used here LL | LL | x += 1; | ^^^^^^ use of borrowed `x` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/send-is-not-static-std-sync.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/send-is-not-static-std-sync.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/send-is-not-static-std-sync.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/send-is-not-static-std-sync.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ | ^ move out of `y` occurs here ... LL | *lock.lock().unwrap() = &z; - | ---- borrow later used here + | ----------- borrow later used here error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:16:33 @@ -18,7 +18,7 @@ | - `z` dropped here while still borrowed LL | LL | lock.use_ref(); // (Mutex is #[may_dangle] so its dtor does not use `z` => needs explicit use) - | ---- borrow later used here + | -------------- borrow later used here error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/send-is-not-static-std-sync.rs:27:10 @@ -29,7 +29,7 @@ | ^ move out of `y` occurs here ... LL | *lock.write().unwrap() = &z; - | ---- borrow later used here + | ------------ borrow later used here error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:30:34 @@ -40,7 +40,7 @@ | - `z` dropped here while still borrowed LL | LL | lock.use_ref(); // (RwLock is #[may_dangle] so its dtor does not use `z` => needs explicit use) - | ---- borrow later used here + | -------------- borrow later used here error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/send-is-not-static-std-sync.rs:43:10 @@ -51,7 +51,7 @@ | ^ move out of `y` occurs here ... LL | tx.send(&z).unwrap(); - | -- borrow later used here + | ----------- borrow later used here error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:46:17 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/slice-borrow.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/slice-borrow.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/slice-borrow.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/slice-borrow.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -7,7 +7,7 @@ LL | } | - temporary value is freed at the end of this statement LL | y.use_ref(); - | - borrow later used here + | ----------- borrow later used here | = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/span/transitive-dep-span.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/span/transitive-dep-span.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/span/transitive-dep-span.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/span/transitive-dep-span.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ ::: $DIR/transitive-dep-span.rs:13:1 | LL | transitive_dep_two::parse_error!(); - | ----------------------------------- + | ---------------------------------- | | | in this macro invocation | in this macro invocation diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -22,6 +22,14 @@ | = note: the following trait bounds were not satisfied: `MyStruct: Foo` +note: the following trait must be implemented + --> $DIR/specialization-trait-not-implemented.rs:7:1 + | +LL | / trait Foo { +LL | | fn foo_one(&self) -> &'static str; +LL | | fn foo_two(&self) -> &'static str; +LL | | } + | |_^ = help: items from traits can only be used if the trait is implemented and in scope note: `Foo` defines an item `foo_one`, perhaps you need to implement it --> $DIR/specialization-trait-not-implemented.rs:7:1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/issue-35376.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/issue-35376.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/issue-35376.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/issue-35376.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,43 @@ +// check-pass +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete + +fn main() {} + +pub trait Alpha { } + +pub trait Beta { + type Event; +} + +pub trait Delta { + type Handle; + fn process(&self); +} + +pub struct Parent(A, T); + +impl Delta for Parent +where A: Alpha, + T: Delta, + T::Handle: Beta::Event> { + type Handle = Handle; + default fn process(&self) { + unimplemented!() + } +} + +impl Delta for Parent +where A: Alpha + Alpha, + T: Delta, + T::Handle: Beta::Event> { + fn process(&self) { + unimplemented!() + } +} + +pub struct Handle; + +impl Beta for Handle { + type Event = (); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/issue-35376.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/issue-35376.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/issue-35376.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/issue-35376.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-35376.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + +warning: 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/min_specialization/spec-marker-supertraits.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/min_specialization/spec-marker-supertraits.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/min_specialization/spec-marker-supertraits.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/min_specialization/spec-marker-supertraits.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,29 @@ +// Check that supertraits cannot be used to work around min_specialization +// limitations. + +#![feature(min_specialization)] +#![feature(rustc_attrs)] + +trait HasMethod { + fn method(&self); +} + +#[rustc_unsafe_specialization_marker] +trait Marker: HasMethod {} + +trait Spec { + fn spec_me(&self); +} + +impl Spec for T { + default fn spec_me(&self) {} +} + +impl Spec for T { + //~^ ERROR cannot specialize on trait `HasMethod` + fn spec_me(&self) { + self.method(); + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,13 @@ +error: cannot specialize on trait `HasMethod` + --> $DIR/spec-marker-supertraits.rs:22:1 + | +LL | / impl Spec for T { +LL | | +LL | | fn spec_me(&self) { +LL | | self.method(); +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/README-rpass.md rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/README-rpass.md --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/README-rpass.md 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/README-rpass.md 2021-11-29 19:27:12.000000000 +0000 @@ -8,7 +8,7 @@ - Specialization via concrete types vs unknown types - In top level of the trait reference - Embedded within another type (`Vec` vs `Vec`) - - [Specialization based on super trait relationships](specialization-super-traits.rs) + - [Specialization based on super trait relationships](specialization-supertraits.rs) - [On assoc fns](specialization-assoc-fns.rs) - [Ensure that impl order doesn't matter](specialization-out-of-order.rs) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/specialization-super-traits.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/specialization-super-traits.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/specialization-super-traits.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/specialization-super-traits.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -// run-pass - -#![feature(specialization)] //~ WARN the feature `specialization` is incomplete - -// Test that you can specialize via an explicit trait hierarchy - -// FIXME: this doesn't work yet... - -trait Parent {} -trait Child: Parent {} - -trait Foo {} - -impl Foo for T {} -impl Foo for T {} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/specialization-supertraits.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/specialization-supertraits.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/specialization-supertraits.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/specialization-supertraits.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,17 @@ +// run-pass + +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete + +// Test that you can specialize via an explicit trait hierarchy + +// FIXME: this doesn't work yet... + +trait Parent {} +trait Child: Parent {} + +trait Foo {} + +impl Foo for T {} +impl Foo for T {} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/specialization-super-traits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/specialization-super-traits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/specialization-super-traits.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/specialization-super-traits.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-super-traits.rs:3:12 - | -LL | #![feature(specialization)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #31844 for more information - = help: consider using `min_specialization` instead, which is more stable and complete - -warning: 1 warning emitted - diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/specialization-supertraits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/specialization-supertraits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/specialization/specialization-supertraits.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/specialization/specialization-supertraits.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-supertraits.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + +warning: 1 warning emitted + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/static/issue-34194.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/static/issue-34194.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/static/issue-34194.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/static/issue-34194.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,11 @@ +// build-pass +#![allow(dead_code)] + +struct A { + a: &'static (), +} + +static B: &'static A = &A { a: &() }; +static C: &'static A = &B; + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/static/static-lifetime.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/static/static-lifetime.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/static/static-lifetime.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/static/static-lifetime.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} | ^^^^^^^^^ | -note: lifetime parameter instantiated with the lifetime `'a` as defined on the impl at 3:6 +note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/static-lifetime.rs:3:6 | LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/static/static-region-bound.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/static/static-region-bound.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/static/static-region-bound.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/static/static-region-bound.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,12 @@ -#![feature(box_syntax)] - fn id(x: T) -> T { x } fn f(_: T) {} fn main() { - let x: Box<_> = box 3; + + let x: Box<_> = Box::new(3); f(x); + let x = &id(3); //~ ERROR temporary value dropped while borrowed f(x); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/str/str-idx.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/str/str-idx.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/str/str-idx.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/str/str-idx.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -13,7 +13,9 @@ --> $DIR/str-idx.rs:4:19 | LL | let _ = s.get(4); - | ^ string indices are ranges of `usize` + | --- ^ string indices are ranges of `usize` + | | + | required by a bound introduced by this call | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` @@ -23,7 +25,9 @@ --> $DIR/str-idx.rs:5:29 | LL | let _ = s.get_unchecked(4); - | ^ string indices are ranges of `usize` + | ------------- ^ string indices are ranges of `usize` + | | + | required by a bound introduced by this call | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/str/str-mut-idx.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/str/str-mut-idx.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/str/str-mut-idx.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/str/str-mut-idx.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -37,7 +37,9 @@ --> $DIR/str-mut-idx.rs:9:15 | LL | s.get_mut(1); - | ^ string indices are ranges of `usize` + | ------- ^ string indices are ranges of `usize` + | | + | required by a bound introduced by this call | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` @@ -47,7 +49,9 @@ --> $DIR/str-mut-idx.rs:11:25 | LL | s.get_unchecked_mut(1); - | ^ string indices are ranges of `usize` + | ----------------- ^ string indices are ranges of `usize` + | | + | required by a bound introduced by this call | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // aux-build:cci_class_cast.rs -#![feature(box_syntax)] - extern crate cci_class_cast; use std::string::ToString; @@ -15,6 +13,6 @@ } pub fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; print_out(nyan, "nyan".to_string()); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/class-cast-to-trait-multiple-types.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,6 @@ // run-pass #![allow(non_camel_case_types)] +#![allow(dead_code)] trait noisy { fn speak(&mut self) -> isize; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/class-implement-traits.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/class-implement-traits.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/class-implement-traits.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/class-implement-traits.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,6 @@ // run-pass #![allow(non_camel_case_types)] +#![allow(dead_code)] trait noisy { fn speak(&mut self); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/class-separate-impl.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/class-separate-impl.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/class-separate-impl.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/class-separate-impl.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,8 +2,6 @@ #![allow(dead_code)] #![allow(non_camel_case_types)] -#![feature(box_syntax)] - use std::fmt; struct cat { @@ -60,6 +58,6 @@ } pub fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; print_out(nyan, "nyan".to_string()); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] /*! * This is a regression test for a bug in LLVM, fixed in upstream r179587, @@ -9,7 +8,7 @@ enum List { Nil, Cons(X, Box>) } pub fn main() { - match List::Cons(10, box List::Nil) { + match List::Cons(10, Box::new(List::Nil)) { List::Cons(10, _) => {} List::Nil => {} _ => panic!() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/functional-struct-upd.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/functional-struct-upd.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/functional-struct-upd.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/functional-struct-upd.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,7 @@ // run-pass + +#![allow(dead_code)] + #[derive(Debug)] struct Foo { x: isize, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/issue-38002.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/issue-38002.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/issue-38002.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/issue-38002.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,35 @@ +// run-pass +#![allow(dead_code)] +// Check that constant ADTs are codegened OK, part k of N. + +enum Bar { + C +} + +enum Foo { + A {}, + B { + y: usize, + z: Bar + }, +} + +const LIST: [(usize, Foo); 2] = [ + (51, Foo::B { y: 42, z: Bar::C }), + (52, Foo::B { y: 45, z: Bar::C }), +]; + +pub fn main() { + match LIST { + [ + (51, Foo::B { y: 42, z: Bar::C }), + (52, Foo::B { y: 45, z: Bar::C }) + ] => {} + _ => { + // I would want to print the enum here, but if + // the discriminant is garbage this causes an + // `unreachable` and silent process exit. + panic!("trivial match failed") + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/tag-align-shape.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/tag-align-shape.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/structs-enums/tag-align-shape.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/structs-enums/tag-align-shape.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,6 @@ // run-pass #![allow(non_camel_case_types)] +#![allow(dead_code)] #[derive(Debug)] enum a_tag { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,7 +5,9 @@ | --- consider calling this function ... LL | bar(foo); - | ^^^ `fn() -> impl Future {foo}` is not a future + | --- ^^^ `fn() -> impl Future {foo}` is not a future + | | + | required by a bound introduced by this call | = help: the trait `Future` is not implemented for `fn() -> impl Future {foo}` note: required by a bound in `bar` @@ -24,7 +26,9 @@ LL | let async_closure = async || (); | -------- consider calling this closure LL | bar(async_closure); - | ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future + | --- ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future + | | + | required by a bound introduced by this call | = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` note: required by a bound in `bar` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/box-future-wrong-output.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/box-future-wrong-output.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/box-future-wrong-output.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/box-future-wrong-output.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,22 @@ +// Issue #72117 +// edition:2018 + +use core::future::Future; +use core::pin::Pin; + +pub type BoxFuture<'a, T> = Pin + Send + 'a>>; + +impl FutureExt for T where T: Future {} +trait FutureExt: Future { + fn boxed<'a>(self) -> BoxFuture<'a, Self::Output> + where + Self: Sized + Send + 'a, + { + Box::pin(self) + } +} + +fn main() { + let _: BoxFuture<'static, bool> = async {}.boxed(); + //~^ ERROR: mismatched types +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/box-future-wrong-output.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/box-future-wrong-output.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/box-future-wrong-output.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/box-future-wrong-output.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/box-future-wrong-output.rs:20:39 + | +LL | let _: BoxFuture<'static, bool> = async {}.boxed(); + | ------------------------ ^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | | + | expected due to this + | + = note: expected struct `Pin + Send + 'static)>>` + found struct `Pin + Send>>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/core-std-import-order-issue-83564.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/core-std-import-order-issue-83564.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/core-std-import-order-issue-83564.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/core-std-import-order-issue-83564.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,10 @@ +// edition:2018 + +// This is a regression test for #83564. +// For some reason, Rust 2018 or higher is required to reproduce the bug. + +fn main() { + //~^ HELP consider importing one of these items + let _x = NonZeroU32::new(5).unwrap(); + //~^ ERROR failed to resolve: use of undeclared type `NonZeroU32` +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/core-std-import-order-issue-83564.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/core-std-import-order-issue-83564.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/core-std-import-order-issue-83564.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/core-std-import-order-issue-83564.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,16 @@ +error[E0433]: failed to resolve: use of undeclared type `NonZeroU32` + --> $DIR/core-std-import-order-issue-83564.rs:8:14 + | +LL | let _x = NonZeroU32::new(5).unwrap(); + | ^^^^^^^^^^ not found in this scope + | +help: consider importing one of these items + | +LL | use std::num::NonZeroU32; + | +LL | use core::num::NonZeroU32; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/crate-or-module-typo.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/crate-or-module-typo.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/crate-or-module-typo.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/crate-or-module-typo.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,17 @@ +// edition:2018 + +use st::cell::Cell; //~ ERROR failed to resolve: use of undeclared crate or module `st` + +mod bar { + pub fn bar() { bar::baz(); } //~ ERROR failed to resolve: use of undeclared crate or module `bar` + + fn baz() {} +} + +use bas::bar; //~ ERROR unresolved import `bas` + +struct Foo { + bar: st::cell::Cell //~ ERROR failed to resolve: use of undeclared crate or module `st` +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/crate-or-module-typo.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/crate-or-module-typo.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/crate-or-module-typo.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/crate-or-module-typo.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,43 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `st` + --> $DIR/crate-or-module-typo.rs:3:5 + | +LL | use st::cell::Cell; + | ^^ use of undeclared crate or module `st` + | +help: there is a crate or module with a similar name + | +LL | use std::cell::Cell; + | ~~~ + +error[E0432]: unresolved import `bas` + --> $DIR/crate-or-module-typo.rs:11:5 + | +LL | use bas::bar; + | ^^^ use of undeclared crate or module `bas` + | +help: there is a crate or module with a similar name + | +LL | use bar::bar; + | ~~~ + +error[E0433]: failed to resolve: use of undeclared crate or module `bar` + --> $DIR/crate-or-module-typo.rs:6:20 + | +LL | pub fn bar() { bar::baz(); } + | ^^^ use of undeclared crate or module `bar` + +error[E0433]: failed to resolve: use of undeclared crate or module `st` + --> $DIR/crate-or-module-typo.rs:14:10 + | +LL | bar: st::cell::Cell + | ^^ use of undeclared crate or module `st` + | +help: there is a crate or module with a similar name + | +LL | bar: std::cell::Cell + | ~~~ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/derive-trait-for-method-call.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/derive-trait-for-method-call.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/derive-trait-for-method-call.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/derive-trait-for-method-call.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,44 @@ +use std::time::Instant; + +enum Enum { + First +} + +#[derive(Clone)] +enum CloneEnum { + First +} + +struct Struct { +} + +#[derive(Clone)] +struct CloneStruct { +} + +struct Foo (X, Y); +impl Foo { + fn test(&self) -> (X, Y) { + (self.0, self.1) + } +} + +fn test1() { + let x = Foo(Enum::First, CloneEnum::First); + let y = x.test(); + //~^the method `test` exists for struct `Foo`, but its trait bounds were not satisfied [E0599] +} + +fn test2() { + let x = Foo(Struct{}, CloneStruct{}); + let y = x.test(); + //~^the method `test` exists for struct `Foo`, but its trait bounds were not satisfied [E0599] +} + +fn test3() { + let x = Foo(Vec::::new(), Instant::now()); + let y = x.test(); + //~^the method `test` exists for struct `Foo, Instant>`, but its trait bounds were not satisfied [E0599] +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/derive-trait-for-method-call.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/derive-trait-for-method-call.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/derive-trait-for-method-call.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/derive-trait-for-method-call.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,95 @@ +error[E0599]: the method `test` exists for struct `Foo`, but its trait bounds were not satisfied + --> $DIR/derive-trait-for-method-call.rs:28:15 + | +LL | enum Enum { + | --------- + | | + | doesn't satisfy `Enum: Clone` + | doesn't satisfy `Enum: Default` +... +LL | enum CloneEnum { + | -------------- doesn't satisfy `CloneEnum: Default` +... +LL | struct Foo (X, Y); + | ------------------------ method `test` not found for this +... +LL | let y = x.test(); + | ^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Enum: Clone` + `Enum: Default` + `CloneEnum: Default` +note: the following trait must be implemented + --> $SRC_DIR/core/src/default.rs:LL:COL + | +LL | / pub trait Default: Sized { +LL | | /// Returns the "default value" for a type. +LL | | /// +LL | | /// Default values are often some kind of initial value, identity value, or anything else that +... | +LL | | fn default() -> Self; +LL | | } + | |_^ +help: consider annotating `Enum` with `#[derive(Clone)]` + | +LL | #[derive(Clone)] + | + +error[E0599]: the method `test` exists for struct `Foo`, but its trait bounds were not satisfied + --> $DIR/derive-trait-for-method-call.rs:34:15 + | +LL | struct Struct { + | ------------- + | | + | doesn't satisfy `Struct: Clone` + | doesn't satisfy `Struct: Default` +... +LL | struct CloneStruct { + | ------------------ doesn't satisfy `CloneStruct: Default` +... +LL | struct Foo (X, Y); + | ------------------------ method `test` not found for this +... +LL | let y = x.test(); + | ^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Struct: Clone` + `Struct: Default` + `CloneStruct: Default` +help: consider annotating `CloneStruct` with `#[derive(Default)]` + | +LL | #[derive(Default)] + | +help: consider annotating `Struct` with `#[derive(Clone, Default)]` + | +LL | #[derive(Clone, Default)] + | + +error[E0599]: the method `test` exists for struct `Foo, Instant>`, but its trait bounds were not satisfied + --> $DIR/derive-trait-for-method-call.rs:40:15 + | +LL | struct Foo (X, Y); + | ------------------------ method `test` not found for this +... +LL | let y = x.test(); + | ^^^^ method cannot be called on `Foo, Instant>` due to unsatisfied trait bounds + | + ::: $SRC_DIR/std/src/time.rs:LL:COL + | +LL | pub struct Instant(time::Instant); + | ---------------------------------- doesn't satisfy `Instant: Default` + | + ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | +LL | pub struct Vec { + | ------------------------------------------------------------------------------------------------ doesn't satisfy `Vec: Clone` + | + = note: the following trait bounds were not satisfied: + `Vec: Clone` + `Instant: Default` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ LL | / intrinsic_match! { LL | | "abc" LL | | }; - | |______^ expected `&str`, found struct `String` + | |_____^ expected `&str`, found struct `String` | = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,281 +1,487 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:28:21 | -LL | let x = X(Y); - | - captured outer variable +LL | let x = X(Y); + | - captured outer variable ... -LL | let X(_t) = x; - | -- ^ help: consider borrowing here: `&x` - | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; + | | -- ^ help: consider borrowing here: `&x` + | | | + | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | | +LL | | +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:32:34 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | if let Either::One(_t) = e { } - | -- ^ help: consider borrowing here: `&e` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +LL | | +LL | | if let Either::One(_t) = e { } + | | -- ^ help: consider borrowing here: `&e` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:36:37 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | while let Either::One(_t) = e { } - | -- ^ help: consider borrowing here: `&e` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | while let Either::One(_t) = e { } + | | -- ^ help: consider borrowing here: `&e` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:40:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | match e { - | ^ help: consider borrowing here: `&e` -... -LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match e { + | | ^ help: consider borrowing here: `&e` +... | +LL | | Either::One(_t) + | | -- + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:47:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | match e { - | ^ help: consider borrowing here: `&e` +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match e { + | | ^ help: consider borrowing here: `&e` +... | +LL | | Either::One(_t) => (), + | | -- + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:56:25 | -LL | let x = X(Y); - | - captured outer variable +LL | let x = X(Y); + | - captured outer variable ... -LL | let X(mut _t) = x; - | ------ ^ help: consider borrowing here: `&x` - | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | let X(mut _t) = x; + | | ------ ^ help: consider borrowing here: `&x` + | | | + | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:60:38 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | if let Either::One(mut _t) = em { } - | ------ ^^ help: consider borrowing here: `&em` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | if let Either::One(mut _t) = em { } + | | ------ ^^ help: consider borrowing here: `&em` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:64:41 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | while let Either::One(mut _t) = em { } - | ------ ^^ help: consider borrowing here: `&em` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | while let Either::One(mut _t) = em { } + | | ------ ^^ help: consider borrowing here: `&em` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:68:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | match em { - | ^^ help: consider borrowing here: `&em` +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | Either::One(mut _t) - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:75:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | match em { - | ^^ help: consider borrowing here: `&em` -... -LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) => (), + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:95:21 | -LL | let x = X(Y); - | - captured outer variable +LL | let x = X(Y); + | - captured outer variable ... -LL | let X(_t) = x; - | -- ^ help: consider borrowing here: `&x` - | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; + | | -- ^ help: consider borrowing here: `&x` + | | | + | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | | +LL | | +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:99:34 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | if let Either::One(_t) = e { } - | -- ^ help: consider borrowing here: `&e` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +LL | | +LL | | if let Either::One(_t) = e { } + | | -- ^ help: consider borrowing here: `&e` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:103:37 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | while let Either::One(_t) = e { } - | -- ^ help: consider borrowing here: `&e` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | while let Either::One(_t) = e { } + | | -- ^ help: consider borrowing here: `&e` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:107:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | match e { - | ^ help: consider borrowing here: `&e` +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match e { + | | ^ help: consider borrowing here: `&e` +... | +LL | | Either::One(_t) + | | -- + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:114:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | match e { - | ^ help: consider borrowing here: `&e` -... -LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match e { + | | ^ help: consider borrowing here: `&e` +... | +LL | | Either::One(_t) => (), + | | -- + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:123:25 | -LL | let x = X(Y); - | - captured outer variable +LL | let x = X(Y); + | - captured outer variable ... -LL | let X(mut _t) = x; - | ------ ^ help: consider borrowing here: `&x` - | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | let X(mut _t) = x; + | | ------ ^ help: consider borrowing here: `&x` + | | | + | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:127:38 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | if let Either::One(mut _t) = em { } - | ------ ^^ help: consider borrowing here: `&em` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | if let Either::One(mut _t) = em { } + | | ------ ^^ help: consider borrowing here: `&em` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:131:41 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | while let Either::One(mut _t) = em { } - | ------ ^^ help: consider borrowing here: `&em` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | while let Either::One(mut _t) = em { } + | | ------ ^^ help: consider borrowing here: `&em` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:135:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | match em { - | ^^ help: consider borrowing here: `&em` +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | Either::One(mut _t) - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:142:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | match em { - | ^^ help: consider borrowing here: `&em` -... -LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) => (), + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:150:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | match em { - | ^^ help: consider borrowing here: `&em` +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) => (), + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error: aborting due to 21 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-try_into-in-macros.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-try_into-in-macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-try_into-in-macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/dont-suggest-try_into-in-macros.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/dont-suggest-try_into-in-macros.rs:2:5 | LL | assert_eq!(10u64, 10usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found `usize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found `usize` | = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs 2021-11-29 19:27:12.000000000 +0000 @@ -11,9 +11,6 @@ x //~ ERROR mismatched types } -// This case is still subpar: -// `Pin::new(x)`: store this in the heap by calling `Box::new`: `Box::new(x)` -// Should suggest changing the code from `Pin::new` to `Box::pin`. fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { Box::new(x) //~ ERROR mismatched types } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -15,7 +15,7 @@ | +++++++++ + error[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:18:5 + --> $DIR/expected-boxed-future-isnt-pinned.rs:15:5 | LL | fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { | ----------------------- expected `Pin + Send + 'static)>>` because of return type @@ -27,23 +27,20 @@ = help: use `Box::pin` error[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:22:14 + --> $DIR/expected-boxed-future-isnt-pinned.rs:19:14 | LL | fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { | - this type parameter LL | Pin::new(x) - | ^ expected struct `Box`, found type parameter `F` + | -------- ^ expected struct `Box`, found type parameter `F` + | | + | help: use `Box::pin` to pin and box this expression: `Box::pin` | = note: expected struct `Box + Send>` found type parameter `F` - = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html -help: store this in the heap by calling `Box::new` - | -LL | Pin::new(Box::new(x)) - | +++++++++ + error[E0277]: `dyn Future + Send` cannot be unpinned - --> $DIR/expected-boxed-future-isnt-pinned.rs:22:5 + --> $DIR/expected-boxed-future-isnt-pinned.rs:19:5 | LL | Pin::new(x) | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future + Send` @@ -56,7 +53,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dyn Future + Send` cannot be unpinned - --> $DIR/expected-boxed-future-isnt-pinned.rs:27:5 + --> $DIR/expected-boxed-future-isnt-pinned.rs:24:5 | LL | Pin::new(Box::new(x)) | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future + Send` @@ -69,7 +66,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:31:5 + --> $DIR/expected-boxed-future-isnt-pinned.rs:28:5 | LL | fn zap() -> BoxFuture<'static, i32> { | ----------------------- expected `Pin + Send + 'static)>>` because of return type diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,7 +5,9 @@ | --- consider calling this function ... LL | bar(foo); - | ^^^ the trait `T` is not implemented for `fn() -> impl T {foo}` + | --- ^^^ the trait `T` is not implemented for `fn() -> impl T {foo}` + | | + | required by a bound introduced by this call | note: required by a bound in `bar` --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:14:16 @@ -23,7 +25,9 @@ LL | let closure = || S; | -- consider calling this closure LL | bar(closure); - | ^^^^^^^ the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]` + | --- ^^^^^^^ the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]` + | | + | required by a bound introduced by this call | note: required by a bound in `bar` --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:14:16 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,20 @@ +// Regression test for #88403, where prefixing with an underscore was +// erroneously suggested for a nested shorthand struct field binding. + +// run-rustfix +#![allow(unused)] +#![forbid(unused_variables)] + +struct Inner { i: i32 } +struct Outer { o: Inner } + +fn foo(Outer { o: Inner { i: _ } }: Outer) {} +//~^ ERROR: unused variable: `i` +//~| HELP: try ignoring the field + +fn main() { + let s = Outer { o: Inner { i: 42 } }; + let Outer { o: Inner { i: _ } } = s; + //~^ ERROR: unused variable: `i` + //~| HELP: try ignoring the field +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,20 @@ +// Regression test for #88403, where prefixing with an underscore was +// erroneously suggested for a nested shorthand struct field binding. + +// run-rustfix +#![allow(unused)] +#![forbid(unused_variables)] + +struct Inner { i: i32 } +struct Outer { o: Inner } + +fn foo(Outer { o: Inner { i } }: Outer) {} +//~^ ERROR: unused variable: `i` +//~| HELP: try ignoring the field + +fn main() { + let s = Outer { o: Inner { i: 42 } }; + let Outer { o: Inner { i } } = s; + //~^ ERROR: unused variable: `i` + //~| HELP: try ignoring the field +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/ignore-nested-field-binding.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,20 @@ +error: unused variable: `i` + --> $DIR/ignore-nested-field-binding.rs:11:27 + | +LL | fn foo(Outer { o: Inner { i } }: Outer) {} + | ^ help: try ignoring the field: `i: _` + | +note: the lint level is defined here + --> $DIR/ignore-nested-field-binding.rs:6:11 + | +LL | #![forbid(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: unused variable: `i` + --> $DIR/ignore-nested-field-binding.rs:17:28 + | +LL | let Outer { o: Inner { i } } = s; + | ^ help: try ignoring the field: `i: _` + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/imm-ref-trait-object-literal.rs:12:7 | LL | foo(&s); - | ^^ the trait `Trait` is not implemented for `&S` + | --- ^^ the trait `Trait` is not implemented for `&S` + | | + | required by a bound introduced by this call | = help: the following implementations were found: <&'a mut S as Trait> @@ -20,16 +22,19 @@ --> $DIR/imm-ref-trait-object-literal.rs:13:7 | LL | foo(s); - | ^ - | | - | expected an implementor of trait `Trait` - | help: consider mutably borrowing here: `&mut s` + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call | note: required by a bound in `foo` --> $DIR/imm-ref-trait-object-literal.rs:7:11 | LL | fn foo(_: X) {} | ^^^^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut s); + | ++++ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> { | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` LL | val.use_self() - | ^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^ borrowed value does not live long enough LL | } | - `val` dropped here while still borrowed | @@ -13,23 +13,17 @@ LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> + 'a { | ++++ -error[E0515]: cannot return value referencing function parameter `val` +error[E0515]: cannot return reference to function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9 | LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here + | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function -error[E0515]: cannot return value referencing function parameter `val` +error[E0515]: cannot return reference to function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9 | LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here + | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> { | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` LL | val.use_self() - | ^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^ borrowed value does not live long enough LL | } | - `val` dropped here while still borrowed | @@ -13,23 +13,17 @@ LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> + 'a { | ++++ -error[E0515]: cannot return value referencing function parameter `val` +error[E0515]: cannot return reference to function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9 | LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here + | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function -error[E0515]: cannot return value referencing function parameter `val` +error[E0515]: cannot return reference to function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9 | LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here + | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:13 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,41 +2,53 @@ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9 | LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self::() - | ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self() - | ^^^^^^^^^^^^^^ `val` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self() - | ^^^^^^^^^^^^^^ `val` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | MyTrait::use_self(val) - | ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/impl-trait-with-missing-bounds.rs:14:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by a bound introduced by this call | = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` @@ -19,7 +21,9 @@ --> $DIR/impl-trait-with-missing-bounds.rs:22:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by a bound introduced by this call | = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` @@ -36,7 +40,9 @@ --> $DIR/impl-trait-with-missing-bounds.rs:30:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by a bound introduced by this call | = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` @@ -53,7 +59,9 @@ --> $DIR/impl-trait-with-missing-bounds.rs:37:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by a bound introduced by this call | = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` @@ -70,7 +78,9 @@ --> $DIR/impl-trait-with-missing-bounds.rs:6:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by a bound introduced by this call | = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` @@ -87,7 +97,9 @@ --> $DIR/impl-trait-with-missing-bounds.rs:45:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by a bound introduced by this call | = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/invalid-bin-op.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/invalid-bin-op.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/invalid-bin-op.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/invalid-bin-op.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,16 @@ | | | S | +note: an implementation of `PartialEq<_>` might be missing for `S` + --> $DIR/invalid-bin-op.rs:5:1 + | +LL | struct S(T); + | ^^^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: the trait `std::cmp::PartialEq` is not implemented for `S` +help: consider annotating `S` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-62843.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-62843.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-62843.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-62843.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,13 +2,16 @@ --> $DIR/issue-62843.rs:4:32 | LL | println!("{:?}", line.find(pattern)); - | ^^^^^^^ - | | - | expected an implementor of trait `Pattern<'_>` - | help: consider borrowing here: `&pattern` + | ---- ^^^^^^^ expected an implementor of trait `Pattern<'_>` + | | + | required by a bound introduced by this call | = note: the trait bound `String: Pattern<'_>` is not satisfied = note: required because of the requirements on the impl of `Pattern<'_>` for `String` +help: consider borrowing here + | +LL | println!("{:?}", line.find(&pattern)); + | + error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-64252-self-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-64252-self-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-64252-self-type.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-64252-self-type.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -8,11 +8,11 @@ help: if this is a `self` type, give it a parameter name | LL | pub fn foo(self: Box) { } - | ~~~~~~~~~ + | +++++ help: if this is a type, explicitly ignore the parameter name | LL | pub fn foo(_: Box) { } - | ~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-64252-self-type.rs:10:15 @@ -24,11 +24,11 @@ help: if this is a `self` type, give it a parameter name | LL | fn bar(self: Box) { } - | ~~~~~~~~~ + | +++++ help: if this is a type, explicitly ignore the parameter name | LL | fn bar(_: Box) { } - | ~~~~~~ + | ++ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-72766.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-72766.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-72766.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-72766.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ // edition:2018 -// compile-flags: -Cincremental=tmp/issue-72766 +// incremental pub struct SadGirl; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:14:20 | LL | assert_is_send(&bar); - | ^^^^ `::Bar` cannot be sent between threads safely + | -------------- ^^^^ `::Bar` cannot be sent between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `::Bar` note: required by a bound in `assert_is_send` @@ -19,7 +21,9 @@ --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:24:20 | LL | assert_is_send(&bar); - | ^^^^ `::Bar` cannot be sent between threads safely + | -------------- ^^^^ `::Bar` cannot be sent between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `::Bar` note: required by a bound in `assert_is_send` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,16 +2,19 @@ --> $DIR/issue-84973-2.rs:11:9 | LL | foo(a); - | ^ - | | - | expected an implementor of trait `Tr` - | help: consider mutably borrowing here: `&mut a` + | --- ^ expected an implementor of trait `Tr` + | | + | required by a bound introduced by this call | note: required by a bound in `foo` --> $DIR/issue-84973-2.rs:7:11 | LL | fn foo(i: T) {} | ^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut a); + | ++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-blacklist.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-blacklist.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-blacklist.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-blacklist.rs 2021-11-29 19:27:12.000000000 +0000 @@ -21,7 +21,6 @@ let ref_cl: &dyn Fn() -> () = &cl; f_sized(*ref_cl); //~^ ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277] - //~| ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277] use std::rc::Rc; let rc = Rc::new(0); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-blacklist.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-blacklist.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-blacklist.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-blacklist.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-84973-blacklist.rs:15:12 | LL | f_copy("".to_string()); - | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | ------ ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | | + | required by a bound introduced by this call | note: required by a bound in `f_copy` --> $DIR/issue-84973-blacklist.rs:6:14 @@ -14,7 +16,9 @@ --> $DIR/issue-84973-blacklist.rs:16:13 | LL | f_clone(S); - | ^ the trait `Clone` is not implemented for `S` + | ------- ^ the trait `Clone` is not implemented for `S` + | | + | required by a bound introduced by this call | note: required by a bound in `f_clone` --> $DIR/issue-84973-blacklist.rs:7:15 @@ -39,7 +43,9 @@ --> $DIR/issue-84973-blacklist.rs:22:13 | LL | f_sized(*ref_cl); - | ^^^^^^^ doesn't have a size known at compile-time + | ------- ^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `dyn Fn()` note: required by a bound in `f_sized` @@ -49,10 +55,12 @@ | ^ required by this bound in `f_sized` error[E0277]: `Rc<{integer}>` cannot be sent between threads safely - --> $DIR/issue-84973-blacklist.rs:28:12 + --> $DIR/issue-84973-blacklist.rs:27:12 | LL | f_send(rc); - | ^^ `Rc<{integer}>` cannot be sent between threads safely + | ------ ^^ `Rc<{integer}>` cannot be sent between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `Rc<{integer}>` note: required by a bound in `f_send` @@ -61,16 +69,6 @@ LL | fn f_send(t: T) {} | ^^^^ required by this bound in `f_send` -error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time - --> $DIR/issue-84973-blacklist.rs:22:5 - | -LL | f_sized(*ref_cl); - | ^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `dyn Fn()` - = note: all function arguments must have a statically known size - = help: unsized fn params are gated as an unstable feature - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-negative.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-negative.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-negative.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973-negative.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/issue-84973-negative.rs:10:9 | LL | bar(a); - | ^ the trait `Tr` is not implemented for `i32` + | --- ^ the trait `Tr` is not implemented for `i32` + | | + | required by a bound introduced by this call | note: required by a bound in `bar` --> $DIR/issue-84973-negative.rs:5:11 @@ -14,16 +16,19 @@ --> $DIR/issue-84973-negative.rs:11:9 | LL | bar(b); - | ^ - | | - | expected an implementor of trait `Tr` - | help: consider borrowing here: `&b` + | --- ^ expected an implementor of trait `Tr` + | | + | required by a bound introduced by this call | note: required by a bound in `bar` --> $DIR/issue-84973-negative.rs:5:11 | LL | fn bar(t: T) {} | ^^ required by this bound in `bar` +help: consider borrowing here + | +LL | bar(&b); + | + error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-84973.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,16 +2,19 @@ --> $DIR/issue-84973.rs:6:24 | LL | let o = Other::new(f); - | ^ - | | - | expected an implementor of trait `SomeTrait` - | help: consider borrowing here: `&f` + | ---------- ^ expected an implementor of trait `SomeTrait` + | | + | required by a bound introduced by this call | note: required by `Other::<'a, G>::new` --> $DIR/issue-84973.rs:27:5 | LL | pub fn new(g: G) -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | let o = Other::new(&f); + | + error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-88730.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-88730.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-88730.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-88730.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,16 @@ +#![allow(unused, nonstandard_style)] +#![deny(bindings_with_variant_name)] + +// If an enum has two different variants, +// then it cannot be matched upon in a function argument. +// It still gets a warning, but no suggestions. +enum Foo { + C, + D, +} + +fn foo(C: Foo) {} //~ERROR + +fn main() { + let C = Foo::D; //~ERROR +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-88730.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-88730.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-88730.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-88730.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-88730.rs:12:8 + | +LL | fn foo(C: Foo) {} + | ^ + | +note: the lint level is defined here + --> $DIR/issue-88730.rs:2:9 + | +LL | #![deny(bindings_with_variant_name)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-88730.rs:15:9 + | +LL | let C = Foo::D; + | ^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0170`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-89333.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-89333.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-89333.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-89333.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,11 @@ +// check-fail +// Ensure we don't error when emitting trait bound not satisfied when self type +// has late bound var + +fn main() { + test(&|| 0); //~ ERROR the trait bound +} + +trait Trait {} + +fn test(arg: &impl Fn() -> T) where for<'a> &'a T: Trait {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-89333.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-89333.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-89333.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-89333.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `for<'a> &'a _: Trait` is not satisfied + --> $DIR/issue-89333.rs:6:5 + | +LL | test(&|| 0); + | ^^^^ the trait `for<'a> Trait` is not implemented for `&'a _` + | +note: required by a bound in `test` + --> $DIR/issue-89333.rs:11:55 + | +LL | fn test(arg: &impl Fn() -> T) where for<'a> &'a T: Trait {} + | ^^^^^ required by this bound in `test` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,13 @@ +// Checks that we do not ICE when comparing `Self` to `Pin` +// edition:2021 + +struct S; + +impl S { + fn foo(_: Box>) {} + fn bar() { + Self::foo(None) //~ ERROR mismatched types + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/issue-90213-expected-boxfuture-self-ice.rs:9:19 + | +LL | Self::foo(None) + | ^^^^ expected struct `Box`, found enum `Option` + | + = note: expected struct `Box>` + found enum `Option<_>` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | Self::foo(Box::new(None)) + | +++++++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -7,7 +7,7 @@ LL | | }); | |______^ | -note: the parameter type `T` must be valid for the anonymous lifetime defined on the function body at 19:24... +note: the parameter type `T` must be valid for the anonymous lifetime defined here... --> $DIR/missing-lifetimes-in-signature-2.rs:19:24 | LL | fn func(foo: &Foo, t: T) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ LL | foo.bar(move |_| { | ^^^ | -note: the parameter type `T` must be valid for the anonymous lifetime defined on the function body at 19:24... +note: the parameter type `T` must be valid for the anonymous lifetime defined here... --> $DIR/missing-lifetimes-in-signature-2.rs:19:24 | LL | fn func(foo: &Foo, t: T) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -32,8 +32,6 @@ LL | | remaining: self.0.iter(), LL | | } | |_________^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/trait-object-nested-in-impl-trait.rs:60:30 @@ -43,7 +41,6 @@ | | | lifetime `'a` defined here | - = help: consider replacing `'a` with `'static` help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,8 @@ +// run-rustfix + +fn two_type_params(_: B) {} + +fn main() { + two_type_params::(100); //~ ERROR this function takes 2 generic arguments + two_type_params::(100); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,8 @@ +// run-rustfix + +fn two_type_params(_: B) {} + +fn main() { + two_type_params::(100); //~ ERROR this function takes 2 generic arguments + two_type_params::(100); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/missing-type-param-used-in-param.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,21 @@ +error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/missing-type-param-used-in-param.rs:6:5 + | +LL | two_type_params::(100); + | ^^^^^^^^^^^^^^^ ------ supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: function defined here, with 2 generic parameters: `A`, `B` + --> $DIR/missing-type-param-used-in-param.rs:3:4 + | +LL | fn two_type_params(_: B) {} + | ^^^^^^^^^^^^^^^ - - +help: add missing generic argument + | +LL | two_type_params::(100); + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/mut-borrow-needed-by-trait.rs:17:29 | LL | let fp = BufWriter::new(fp); - | ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | -------------- ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | | + | required by a bound introduced by this call | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` note: required by `BufWriter::::new` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,22 @@ +// run-rustfix + +use std::ops::Index; +struct X; +impl Index for X { + type Output = (); + + fn index(&self, _: i32) -> &() { + &() + } +} + +fn main() { + let x = vec![1, 2, 3]; + x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a + let x = [1, 2, 3]; + x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a + let x = &[1, 2, 3]; + x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a + let _ = x; + X[-1]; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,22 @@ +// run-rustfix + +use std::ops::Index; +struct X; +impl Index for X { + type Output = (); + + fn index(&self, _: i32) -> &() { + &() + } +} + +fn main() { + let x = vec![1, 2, 3]; + x[-1]; //~ ERROR negative integers cannot be used to index on a + let x = [1, 2, 3]; + x[-1]; //~ ERROR negative integers cannot be used to index on a + let x = &[1, 2, 3]; + x[-1]; //~ ERROR negative integers cannot be used to index on a + let _ = x; + X[-1]; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/negative-literal-index.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,35 @@ +error: negative integers cannot be used to index on a `Vec<{integer}>` + --> $DIR/negative-literal-index.rs:15:7 + | +LL | x[-1]; + | ^^ cannot use a negative integer for indexing on `Vec<{integer}>` + | +help: to access an element starting from the end of the `Vec<{integer}>`, compute the index + | +LL | x[x.len() -1]; + | +++++++ + +error: negative integers cannot be used to index on a `[{integer}; 3]` + --> $DIR/negative-literal-index.rs:17:7 + | +LL | x[-1]; + | ^^ cannot use a negative integer for indexing on `[{integer}; 3]` + | +help: to access an element starting from the end of the `[{integer}; 3]`, compute the index + | +LL | x[x.len() -1]; + | +++++++ + +error: negative integers cannot be used to index on a `[{integer}; 3]` + --> $DIR/negative-literal-index.rs:19:7 + | +LL | x[-1]; + | ^^ cannot use a negative integer for indexing on `[{integer}; 3]` + | +help: to access an element starting from the end of the `[{integer}; 3]`, compute the index + | +LL | x[x.len() -1]; + | +++++++ + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/nested-non-tuple-tuple-struct.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/nested-non-tuple-tuple-struct.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/nested-non-tuple-tuple-struct.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/nested-non-tuple-tuple-struct.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,18 @@ +pub struct S(f32, f32); + +pub enum E { + V(f32, f32), +} + +fn main() { + let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); + //~^ ERROR struct `S` has no field named `x` + //~| ERROR struct `S` has no field named `y` + //~| ERROR struct `S` has no field named `x` + //~| ERROR struct `S` has no field named `y` + let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); + //~^ ERROR variant `E::V` has no field named `x` + //~| ERROR variant `E::V` has no field named `y` + //~| ERROR variant `E::V` has no field named `x` + //~| ERROR variant `E::V` has no field named `y` +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/nested-non-tuple-tuple-struct.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,116 @@ +error[E0560]: struct `S` has no field named `x` + --> $DIR/nested-non-tuple-tuple-struct.rs:8:19 + | +LL | pub struct S(f32, f32); + | - `S` defined here +... +LL | let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); + | ^ field does not exist + | +help: `S` is a tuple struct, use the appropriate syntax + | +LL | let _x = (S(/* fields */), S { x: 3.0, y: 4.0 }); + | ~~~~~~~~~~~~~~~ + +error[E0560]: struct `S` has no field named `y` + --> $DIR/nested-non-tuple-tuple-struct.rs:8:27 + | +LL | pub struct S(f32, f32); + | - `S` defined here +... +LL | let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); + | ^ field does not exist + | +help: `S` is a tuple struct, use the appropriate syntax + | +LL | let _x = (S(/* fields */), S { x: 3.0, y: 4.0 }); + | ~~~~~~~~~~~~~~~ + +error[E0560]: struct `S` has no field named `x` + --> $DIR/nested-non-tuple-tuple-struct.rs:8:41 + | +LL | pub struct S(f32, f32); + | - `S` defined here +... +LL | let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); + | ^ field does not exist + | +help: `S` is a tuple struct, use the appropriate syntax + | +LL | let _x = (S { x: 1.0, y: 2.0 }, S(/* fields */)); + | ~~~~~~~~~~~~~~~ + +error[E0560]: struct `S` has no field named `y` + --> $DIR/nested-non-tuple-tuple-struct.rs:8:49 + | +LL | pub struct S(f32, f32); + | - `S` defined here +... +LL | let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); + | ^ field does not exist + | +help: `S` is a tuple struct, use the appropriate syntax + | +LL | let _x = (S { x: 1.0, y: 2.0 }, S(/* fields */)); + | ~~~~~~~~~~~~~~~ + +error[E0559]: variant `E::V` has no field named `x` + --> $DIR/nested-non-tuple-tuple-struct.rs:13:22 + | +LL | V(f32, f32), + | - `E::V` defined here +... +LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); + | ^ field does not exist + | +help: `E::V` is a tuple variant, use the appropriate syntax + | +LL | let _y = (E::V(/* fields */), E::V { x: 3.0, y: 4.0 }); + | ~~~~~~~~~~~~~~~~~~ + +error[E0559]: variant `E::V` has no field named `y` + --> $DIR/nested-non-tuple-tuple-struct.rs:13:30 + | +LL | V(f32, f32), + | - `E::V` defined here +... +LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); + | ^ field does not exist + | +help: `E::V` is a tuple variant, use the appropriate syntax + | +LL | let _y = (E::V(/* fields */), E::V { x: 3.0, y: 4.0 }); + | ~~~~~~~~~~~~~~~~~~ + +error[E0559]: variant `E::V` has no field named `x` + --> $DIR/nested-non-tuple-tuple-struct.rs:13:47 + | +LL | V(f32, f32), + | - `E::V` defined here +... +LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); + | ^ field does not exist + | +help: `E::V` is a tuple variant, use the appropriate syntax + | +LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V(/* fields */)); + | ~~~~~~~~~~~~~~~~~~ + +error[E0559]: variant `E::V` has no field named `y` + --> $DIR/nested-non-tuple-tuple-struct.rs:13:55 + | +LL | V(f32, f32), + | - `E::V` defined here +... +LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); + | ^ field does not exist + | +help: `E::V` is a tuple variant, use the appropriate syntax + | +LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V(/* fields */)); + | ~~~~~~~~~~~~~~~~~~ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0559, E0560. +For more information about an error, try `rustc --explain E0559`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,8 +4,6 @@ LL | fn bar(x: &dyn Trait) {} | ^^^^^^^^^ `Trait` cannot be made into an object | - = help: consider moving `baz` to another trait - = help: consider moving `bat` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-references-self.rs:2:22 | @@ -15,6 +13,8 @@ | ^^^^ ...because method `baz` references the `Self` type in this parameter LL | fn bat(&self) -> Self {} | ^^^^ ...because method `bat` references the `Self` type in its return type + = help: consider moving `baz` to another trait + = help: consider moving `bat` to another trait error[E0038]: the trait `Other` cannot be made into an object --> $DIR/object-unsafe-trait-references-self.rs:10:12 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/option-content-move2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/option-content-move2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/option-content-move2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/option-content-move2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,17 +1,22 @@ error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure --> $DIR/option-content-move2.rs:9:9 | -LL | let mut var = None; - | ------- captured outer variable -... -LL | move || { - | ^^^^^^^ move out of `var` occurs here -LL | -LL | var = Some(NotCopyable); - | --- - | | - | move occurs because `var` has type `Option`, which does not implement the `Copy` trait - | move occurs due to use in closure +LL | let mut var = None; + | ------- captured outer variable +LL | func(|| { + | __________- +LL | | // Shouldn't suggest `move ||.as_ref()` here +LL | | move || { + | | ^^^^^^^ move out of `var` occurs here +LL | | +LL | | var = Some(NotCopyable); + | | --- + | | | + | | move occurs because `var` has type `Option`, which does not implement the `Copy` trait + | | move occurs due to use in closure +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/restrict-type-argument.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/restrict-type-argument.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/restrict-type-argument.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/restrict-type-argument.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/restrict-type-argument.rs:4:13 | LL | is_send(val); - | ^^^ `impl Sync` cannot be sent between threads safely + | ------- ^^^ `impl Sync` cannot be sent between threads safely + | | + | required by a bound introduced by this call | note: required by a bound in `is_send` --> $DIR/restrict-type-argument.rs:1:15 @@ -18,7 +20,9 @@ --> $DIR/restrict-type-argument.rs:8:13 | LL | is_send(val); - | ^^^ `S` cannot be sent between threads safely + | ------- ^^^ `S` cannot be sent between threads safely + | | + | required by a bound introduced by this call | note: required by a bound in `is_send` --> $DIR/restrict-type-argument.rs:1:15 @@ -34,7 +38,9 @@ --> $DIR/restrict-type-argument.rs:12:13 | LL | is_send(val); - | ^^^ `S` cannot be sent between threads safely + | ------- ^^^ `S` cannot be sent between threads safely + | | + | required by a bound introduced by this call | note: required by a bound in `is_send` --> $DIR/restrict-type-argument.rs:1:15 @@ -50,7 +56,9 @@ --> $DIR/restrict-type-argument.rs:20:13 | LL | is_send(val); - | ^^^ `S` cannot be sent between threads safely + | ------- ^^^ `S` cannot be sent between threads safely + | | + | required by a bound introduced by this call | note: required by a bound in `is_send` --> $DIR/restrict-type-argument.rs:1:15 @@ -66,7 +74,9 @@ --> $DIR/restrict-type-argument.rs:24:13 | LL | is_send(val); - | ^^^ `S` cannot be sent between threads safely + | ------- ^^^ `S` cannot be sent between threads safely + | | + | required by a bound introduced by this call | note: required by a bound in `is_send` --> $DIR/restrict-type-argument.rs:1:15 @@ -82,7 +92,9 @@ --> $DIR/restrict-type-argument.rs:28:13 | LL | is_send(val); - | ^^^ `S` cannot be sent between threads safely + | ------- ^^^ `S` cannot be sent between threads safely + | | + | required by a bound introduced by this call | note: required by a bound in `is_send` --> $DIR/restrict-type-argument.rs:1:15 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/slice-issue-87994.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/slice-issue-87994.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/slice-issue-87994.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/slice-issue-87994.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,16 @@ +fn main() { + let v = vec![1i32, 2, 3]; + for _ in v[1..] { + //~^ ERROR [i32]` is not an iterator [E0277] + //~^^ ERROR known at compilation time + } + struct K { + n: i32, + } + let mut v2 = vec![K { n: 1 }, K { n: 1 }, K { n: 1 }]; + for i2 in v2[1..] { + //~^ ERROR [K]` is not an iterator [E0277] + //~^^ ERROR known at compilation time + i2.n = 2; + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/slice-issue-87994.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/slice-issue-87994.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/slice-issue-87994.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/slice-issue-87994.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,83 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/slice-issue-87994.rs:3:12 + | +LL | for _ in v[1..] { + | ^^^^^^ expected an implementor of trait `IntoIterator` + | + = note: the trait bound `[i32]: IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` +note: required by `into_iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for _ in &v[1..] { + | + +LL | for _ in &mut v[1..] { + | ++++ + +error[E0277]: `[i32]` is not an iterator + --> $DIR/slice-issue-87994.rs:3:12 + | +LL | for _ in v[1..] { + | ^^^^^^ expected an implementor of trait `IntoIterator` + | + = note: the trait bound `[i32]: IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` +note: required by `into_iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for _ in &v[1..] { + | + +LL | for _ in &mut v[1..] { + | ++++ + +error[E0277]: the size for values of type `[K]` cannot be known at compilation time + --> $DIR/slice-issue-87994.rs:11:13 + | +LL | for i2 in v2[1..] { + | ^^^^^^^ expected an implementor of trait `IntoIterator` + | + = note: the trait bound `[K]: IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `IntoIterator` for `[K]` +note: required by `into_iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for i2 in &v2[1..] { + | + +LL | for i2 in &mut v2[1..] { + | ++++ + +error[E0277]: `[K]` is not an iterator + --> $DIR/slice-issue-87994.rs:11:13 + | +LL | for i2 in v2[1..] { + | ^^^^^^^ expected an implementor of trait `IntoIterator` + | + = note: the trait bound `[K]: IntoIterator` is not satisfied + = note: required because of the requirements on the impl of `IntoIterator` for `[K]` +note: required by `into_iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for i2 in &v2[1..] { + | + +LL | for i2 in &mut v2[1..] { + | ++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-change-mut.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-change-mut.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-change-mut.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-change-mut.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/suggest-change-mut.rs:12:48 | LL | let mut stream_reader = BufReader::new(&stream); - | ^^^^^^^ the trait `std::io::Read` is not implemented for `&T` + | -------------- ^^^^^^^ the trait `std::io::Read` is not implemented for `&T` + | | + | required by a bound introduced by this call | note: required by `BufReader::::new` --> $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,23 @@ +trait Trait {} + +struct A; +struct B; +struct C; + +impl Trait for &A {} +impl Trait for &mut A {} + +impl Trait for &B {} + +impl Trait for &mut C {} + +fn foo(_: X) {} + +fn main() { + let a = A; + let b = B; + let c = C; + foo(a); //~ ERROR the trait bound `A: Trait` is not satisfied + foo(b); //~ ERROR the trait bound `B: Trait` is not satisfied + foo(c); //~ ERROR the trait bound `C: Trait` is not satisfied +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,59 @@ +error[E0277]: the trait bound `A: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:20:9 + | +LL | foo(a); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider borrowing here + | +LL | foo(&a); + | + +LL | foo(&mut a); + | ++++ + +error[E0277]: the trait bound `B: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:21:9 + | +LL | foo(b); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider borrowing here + | +LL | foo(&b); + | + + +error[E0277]: the trait bound `C: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:22:9 + | +LL | foo(c); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut c); + | ++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-ref-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-ref-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-ref-macro.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-ref-macro.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -8,7 +8,7 @@ | help: consider mutably borrowing here: `&mut 123` ... LL | bla!(); - | ------- in this macro invocation + | ------ in this macro invocation | = note: this error originates in the macro `bla` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-trait-items.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-trait-items.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-trait-items.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-trait-items.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,48 @@ +trait Foo { + type Type; + + fn foo(); + fn bar(); + fn qux(); +} + +struct A; + +impl Foo for A { +//~^ ERROR not all trait items implemented + type Typ = (); + //~^ ERROR type `Typ` is not a member of trait + //~| HELP there is an associated type with a similar name + + fn fooo() {} + //~^ ERROR method `fooo` is not a member of trait + //~| HELP there is an associated function with a similar name + + fn barr() {} + //~^ ERROR method `barr` is not a member of trait + //~| HELP there is an associated function with a similar name + + fn quux() {} + //~^ ERROR method `quux` is not a member of trait + //~| HELP there is an associated function with a similar name +} +//~^ HELP implement the missing item +//~| HELP implement the missing item +//~| HELP implement the missing item +//~| HELP implement the missing item + +trait Bar { + const Const: i32; +} + +struct B; + +impl Bar for B { +//~^ ERROR not all trait items implemented + const Cnst: i32 = 0; + //~^ ERROR const `Cnst` is not a member of trait + //~| HELP there is an associated constant with a similar name +} +//~^ HELP implement the missing item + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-trait-items.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-trait-items.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/suggest-trait-items.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/suggest-trait-items.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,74 @@ +error[E0437]: type `Typ` is not a member of trait `Foo` + --> $DIR/suggest-trait-items.rs:13:5 + | +LL | type Typ = (); + | ^^^^^---^^^^^^ + | | | + | | help: there is an associated type with a similar name: `Type` + | not a member of trait `Foo` + +error[E0407]: method `fooo` is not a member of trait `Foo` + --> $DIR/suggest-trait-items.rs:17:5 + | +LL | fn fooo() {} + | ^^^----^^^^^ + | | | + | | help: there is an associated function with a similar name: `foo` + | not a member of trait `Foo` + +error[E0407]: method `barr` is not a member of trait `Foo` + --> $DIR/suggest-trait-items.rs:21:5 + | +LL | fn barr() {} + | ^^^----^^^^^ + | | | + | | help: there is an associated function with a similar name: `bar` + | not a member of trait `Foo` + +error[E0407]: method `quux` is not a member of trait `Foo` + --> $DIR/suggest-trait-items.rs:25:5 + | +LL | fn quux() {} + | ^^^----^^^^^ + | | | + | | help: there is an associated function with a similar name: `qux` + | not a member of trait `Foo` + +error[E0438]: const `Cnst` is not a member of trait `Bar` + --> $DIR/suggest-trait-items.rs:42:5 + | +LL | const Cnst: i32 = 0; + | ^^^^^^----^^^^^^^^^^ + | | | + | | help: there is an associated constant with a similar name: `Const` + | not a member of trait `Bar` + +error[E0046]: not all trait items implemented, missing: `Type`, `foo`, `bar`, `qux` + --> $DIR/suggest-trait-items.rs:11:1 + | +LL | type Type; + | ---------- `Type` from trait +LL | +LL | fn foo(); + | --------- `foo` from trait +LL | fn bar(); + | --------- `bar` from trait +LL | fn qux(); + | --------- `qux` from trait +... +LL | impl Foo for A { + | ^^^^^^^^^^^^^^ missing `Type`, `foo`, `bar`, `qux` in implementation + +error[E0046]: not all trait items implemented, missing: `Const` + --> $DIR/suggest-trait-items.rs:40:1 + | +LL | const Const: i32; + | ----------------- `Const` from trait +... +LL | impl Bar for B { + | ^^^^^^^^^^^^^^ missing `Const` in implementation + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0046, E0407, E0437, E0438. +For more information about an error, try `rustc --explain E0046`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,19 +2,23 @@ --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:19 | LL | let _ = RGB { r, g, c }; - | ^ - | | - | expected `f64`, found `f32` - | help: you can convert an `f32` to an `f64`: `r: r.into()` + | ^ expected `f64`, found `f32` + | +help: you can convert an `f32` to an `f64` + | +LL | let _ = RGB { r: r.into(), g, c }; + | ++ +++++++ error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:22 | LL | let _ = RGB { r, g, c }; - | ^ - | | - | expected `f64`, found `f32` - | help: you can convert an `f32` to an `f64`: `g: g.into()` + | ^ expected `f64`, found `f32` + | +help: you can convert an `f32` to an `f64` + | +LL | let _ = RGB { r, g: g.into(), c }; + | ++ +++++++ error[E0560]: struct `RGB` has no field named `c` --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:25 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,28 +2,34 @@ --> $DIR/type-mismatch-struct-field-shorthand.rs:8:19 | LL | let _ = RGB { r, g, b }; - | ^ - | | - | expected `f64`, found `f32` - | help: you can convert an `f32` to an `f64`: `r: r.into()` + | ^ expected `f64`, found `f32` + | +help: you can convert an `f32` to an `f64` + | +LL | let _ = RGB { r: r.into(), g, b }; + | ++ +++++++ error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:22 | LL | let _ = RGB { r, g, b }; - | ^ - | | - | expected `f64`, found `f32` - | help: you can convert an `f32` to an `f64`: `g: g.into()` + | ^ expected `f64`, found `f32` + | +help: you can convert an `f32` to an `f64` + | +LL | let _ = RGB { r, g: g.into(), b }; + | ++ +++++++ error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:25 | LL | let _ = RGB { r, g, b }; - | ^ - | | - | expected `f64`, found `f32` - | help: you can convert an `f32` to an `f64`: `b: b.into()` + | ^ expected `f64`, found `f32` + | +help: you can convert an `f32` to an `f64` + | +LL | let _ = RGB { r, g, b: b.into() }; + | ++ +++++++ error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/symbol-names/const-generics-structural-demangling.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/symbol-names/const-generics-structural-demangling.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/symbol-names/const-generics-structural-demangling.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/symbol-names/const-generics-structural-demangling.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -131,7 +131,7 @@ | ^^^^^^^^^^^^^^^^^^^^ ... LL | duplicate_field_name_test!(x); - | ------------------------------ in this macro invocation + | ----------------------------- in this macro invocation | = note: this error originates in the macro `duplicate_field_name_test` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -142,7 +142,7 @@ | ^^^^^^^^^^^^^^^^^^^^ ... LL | duplicate_field_name_test!(x); - | ------------------------------ in this macro invocation + | ----------------------------- in this macro invocation | = note: this error originates in the macro `duplicate_field_name_test` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -153,7 +153,7 @@ | ^^^^^^^^^^^^^^^^^^^^ ... LL | duplicate_field_name_test!(x); - | ------------------------------ in this macro invocation + | ----------------------------- in this macro invocation | = note: this error originates in the macro `duplicate_field_name_test` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/symbol-names/issue-53912.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/symbol-names/issue-53912.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/symbol-names/issue-53912.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/symbol-names/issue-53912.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,37 @@ +// build-pass + +// This test is the same code as in ui/symbol-names/issue-60925.rs but this checks that the +// reproduction compiles successfully and doesn't segfault, whereas that test just checks that the +// symbol mangling fix produces the correct result. + +fn dummy() {} + +mod llvm { + pub(crate) struct Foo; +} +mod foo { + pub(crate) struct Foo(T); + + impl Foo<::llvm::Foo> { + pub(crate) fn foo() { + for _ in 0..0 { + for _ in &[::dummy()] { + ::dummy(); + ::dummy(); + ::dummy(); + } + } + } + } + + pub(crate) fn foo() { + Foo::foo(); + Foo::foo(); + } +} + +pub fn foo() { + foo::foo(); +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/tail-typeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/tail-typeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/tail-typeck.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/tail-typeck.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | fn f() -> isize { return g().try_into().unwrap(); } - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/test-attrs/issue-36768.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/test-attrs/issue-36768.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/test-attrs/issue-36768.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/test-attrs/issue-36768.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,9 @@ +// run-pass +// compile-flags:--test +#![deny(private_in_public)] + +#[test] fn foo() {} +mod foo {} + +#[test] fn core() {} +extern crate core; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/test-attrs/test-should-panic-attr.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/test-attrs/test-should-panic-attr.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/test-attrs/test-should-panic-attr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/test-attrs/test-should-panic-attr.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ LL | #[should_panic(expected)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release. + = note: errors in this attribute were erroneously allowed and will become a hard error in a future release warning: argument must be of the form: `expected = "error message"` --> $DIR/test-should-panic-attr.rs:18:1 @@ -12,7 +12,7 @@ LL | #[should_panic(expect)] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release. + = note: errors in this attribute were erroneously allowed and will become a hard error in a future release warning: argument must be of the form: `expected = "error message"` --> $DIR/test-should-panic-attr.rs:25:1 @@ -20,7 +20,7 @@ LL | #[should_panic(expected(foo, bar))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release. + = note: errors in this attribute were erroneously allowed and will become a hard error in a future release warning: argument must be of the form: `expected = "error message"` --> $DIR/test-should-panic-attr.rs:32:1 @@ -28,7 +28,7 @@ LL | #[should_panic(expected = "foo", bar)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release. + = note: errors in this attribute were erroneously allowed and will become a hard error in a future release warning: 4 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/thread-local/tls.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/thread-local/tls.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/thread-local/tls.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/thread-local/tls.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +// run-pass +// ignore-emscripten no threads support +// compile-flags: -O + +#![feature(thread_local)] + +#[thread_local] +static S: u32 = 222; + +fn main() { + let local = &S as *const u32 as usize; + let foreign = std::thread::spawn(|| &S as *const u32 as usize).join().unwrap(); + assert_ne!(local, foreign); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; pub fn main() { test05(); } @@ -12,7 +10,7 @@ } fn test05() { - let three: Box<_> = box 3; + let three: Box<_> = Box::new(3); let fn_to_send = move|n:isize| { println!("{}", *three + n); // will copy x into the closure assert_eq!(*three, 3); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,15 +2,13 @@ #![allow(unused_must_use)] // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; use std::sync::mpsc::channel; pub fn main() { let (tx, rx) = channel::(); - let x: Box = box 1; + let x: Box = Box::new(1); let x_in_parent = &(*x) as *const isize as usize; let t = thread::spawn(move || { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/tls.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/tls.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/tls.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/tls.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -// run-pass -// ignore-emscripten no threads support -// compile-flags: -O - -#![feature(thread_local)] - -#[thread_local] -static S: u32 = 222; - -fn main() { - let local = &S as *const u32 as usize; - let foreign = std::thread::spawn(|| &S as *const u32 as usize).join().unwrap(); - assert_ne!(local, foreign); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trace_macros-format.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trace_macros-format.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trace_macros-format.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trace_macros-format.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,37 +2,37 @@ --> $DIR/trace_macros-format.rs:4:5 | LL | trace_macros!(); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:5:5 | LL | trace_macros!(1); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:6:5 | LL | trace_macros!(ident); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:7:5 | LL | trace_macros!(for); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:8:5 | LL | trace_macros!(true,); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` --> $DIR/trace_macros-format.rs:9:5 | LL | trace_macros!(false 1); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/alias/no-duplicates.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/alias/no-duplicates.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/alias/no-duplicates.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/alias/no-duplicates.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -12,7 +12,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -31,7 +31,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -53,7 +53,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -69,7 +69,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -85,7 +85,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -110,7 +110,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -129,7 +129,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -146,7 +146,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -171,7 +171,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -190,7 +190,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -209,7 +209,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -230,7 +230,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -251,7 +251,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -268,7 +268,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -282,7 +282,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -296,7 +296,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -310,7 +310,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -333,7 +333,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -356,7 +356,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -379,7 +379,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -398,7 +398,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -417,7 +417,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -441,7 +441,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -465,7 +465,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -489,7 +489,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -504,7 +504,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -519,7 +519,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjT fn(&'a u8)> + ObjT fn(&'b u8)> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjT fn(&'a u8)> + ObjT fn(&'b u8)> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 27 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/alias/no-extra-traits.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/alias/no-extra-traits.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/alias/no-extra-traits.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/alias/no-extra-traits.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -23,7 +23,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -39,7 +39,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -55,7 +55,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -74,7 +74,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -93,7 +93,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -114,7 +114,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -135,7 +135,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -154,7 +154,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -173,7 +173,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -187,7 +187,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -201,7 +201,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -220,7 +220,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -239,7 +239,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -253,7 +253,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -267,7 +267,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -292,7 +292,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -317,7 +317,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -342,7 +342,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -377,7 +377,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -412,7 +412,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -447,7 +447,7 @@ | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -466,7 +466,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -485,7 +485,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -509,7 +509,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -528,7 +528,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -547,7 +547,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -571,7 +571,7 @@ | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 28 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/auxiliary/issue_89119_intercrate_caching.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/auxiliary/issue_89119_intercrate_caching.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/auxiliary/issue_89119_intercrate_caching.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/auxiliary/issue_89119_intercrate_caching.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,60 @@ +// This is the auxiliary crate for the regression test for issue #89119, minimized +// from `zvariant-2.8.0`. + +use std::convert::TryFrom; +use std::borrow::Cow; + +pub struct Str<'a>(Cow<'a, str>); +impl<'a> Str<'a> { + pub fn to_owned(&self) -> Str<'static> { + todo!() + } +} + +pub enum Value<'a> { + Str(Str<'a>), + Value(Box>), +} +impl<'a> Value<'a> { + pub fn to_owned(&self) -> Value<'static> { + match self { + Value::Str(v) => Value::Str(v.to_owned()), + Value::Value(v) => { + let o = OwnedValue::from(&**v); + Value::Value(Box::new(o.into_inner())) + } + } + } +} + +struct OwnedValue(Value<'static>); +impl OwnedValue { + pub(crate) fn into_inner(self) -> Value<'static> { + todo!() + } +} +impl<'a, T> TryFrom for Vec +where + T: TryFrom, Error = ()>, +{ + type Error = (); + fn try_from(_: OwnedValue) -> Result { + todo!() + } +} +impl TryFrom for Vec { + type Error = (); + fn try_from(_: OwnedValue) -> Result { + todo!() + } +} +impl<'a> From> for OwnedValue { + fn from(_: Value<'a>) -> Self { + todo!() + } +} +impl<'a> From<&Value<'a>> for OwnedValue { + fn from(_: &Value<'a>) -> Self { + todo!() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/bad-sized.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/bad-sized.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/bad-sized.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/bad-sized.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Trait + Sized {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Trait + Sized {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/bound/in-arc.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/bound/in-arc.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/bound/in-arc.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/bound/in-arc.rs 2021-11-29 19:27:12.000000000 +0000 @@ -5,8 +5,6 @@ // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::sync::Arc; use std::sync::mpsc::channel; use std::thread; @@ -67,10 +65,11 @@ swim_speed: 998, name: "alec_guinness".to_string(), }; - let arc = Arc::new(vec![box catte as Box, - box dogge1 as Box, - box fishe as Box, - box dogge2 as Box]); + let arc = Arc::new(vec![ + Box::new(catte) as Box, + Box::new(dogge1) as Box, + Box::new(fishe) as Box, + Box::new(dogge2) as Box]); let (tx1, rx1) = channel(); let arc1 = arc.clone(); let t1 = thread::spawn(move|| { check_legs(arc1); tx1.send(()); }); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/bound/same-crate-name.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/bound/same-crate-name.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/bound/same-crate-name.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/bound/same-crate-name.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/same-crate-name.rs:31:20 | LL | a::try_foo(foo); - | ^^^ the trait `main::a::Bar` is not implemented for `Foo` + | ---------- ^^^ the trait `main::a::Bar` is not implemented for `Foo` + | | + | required by a bound introduced by this call | help: trait impl with same name found --> $DIR/auxiliary/crate_a2.rs:5:1 @@ -20,7 +22,9 @@ --> $DIR/same-crate-name.rs:38:20 | LL | a::try_foo(implements_no_traits); - | ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `DoesNotImplementTrait` + | ---------- ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `DoesNotImplementTrait` + | | + | required by a bound introduced by this call | note: required by a bound in `try_foo` --> $DIR/auxiliary/crate_a1.rs:3:24 @@ -32,7 +36,9 @@ --> $DIR/same-crate-name.rs:45:20 | LL | a::try_foo(other_variant_implements_mismatched_trait); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsWrongTraitConditionally` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsWrongTraitConditionally` + | | + | required by a bound introduced by this call | help: trait impl with same name found --> $DIR/auxiliary/crate_a2.rs:13:1 @@ -50,7 +56,9 @@ --> $DIR/same-crate-name.rs:51:20 | LL | a::try_foo(other_variant_implements_correct_trait); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsTraitForUsize` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsTraitForUsize` + | | + | required by a bound introduced by this call | = help: the following implementations were found: as main::a::Bar> diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/bug-7183-generics.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/bug-7183-generics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/bug-7183-generics.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/bug-7183-generics.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,36 @@ +// run-pass + +trait Speak : Sized { + fn say(&self, s:&str) -> String; + fn hi(&self) -> String { hello(self) } +} + +fn hello(s:&S) -> String{ + s.say("hello") +} + +impl Speak for isize { + fn say(&self, s:&str) -> String { + format!("{}: {}", s, *self) + } +} + +impl Speak for Option { + fn say(&self, s:&str) -> String { + match *self { + None => format!("{} - none", s), + Some(ref x) => { format!("something!{}", x.say(s)) } + } + } +} + + +pub fn main() { + assert_eq!(3.hi(), "hello: 3".to_string()); + assert_eq!(Some(Some(3)).hi(), + "something!something!hello: 3".to_string()); + assert_eq!(None::.hi(), "hello - none".to_string()); + + assert_eq!(Some(None::).hi(), "something!hello - none".to_string()); + assert_eq!(Some(3).hi(), "something!hello: 3".to_string()); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/coercion.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/coercion.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/coercion.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/coercion.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,6 @@ #![allow(dead_code)] #![allow(unused_mut)] #![allow(unused_variables)] -#![feature(box_syntax)] use std::io::{self, Write}; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/conditional-dispatch.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/conditional-dispatch.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/conditional-dispatch.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/conditional-dispatch.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,7 +3,6 @@ // blanket impl for T:Copy coexists with an impl for Box, because // Box does not impl Copy. -#![feature(box_syntax)] trait Get { fn get(&self) -> Self; @@ -20,7 +19,7 @@ } impl Get for Box { - fn get(&self) -> Box { box get_it(&**self) } + fn get(&self) -> Box { Box::new(get_it(&**self)) } } fn get_it(t: &T) -> T { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,12 +4,12 @@ LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { | ^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 24:6... +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:6 | LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { | ^^ -note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the impl at 24:9... +note: ...but the lifetime must also be valid for the lifetime `'b` as defined here... --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:9 | LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/inductive-overflow/supertrait-auto-trait.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/inductive-overflow/supertrait-auto-trait.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/inductive-overflow/supertrait-auto-trait.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/inductive-overflow/supertrait-auto-trait.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,16 +1,18 @@ -error[E0568]: auto traits cannot have super traits - --> $DIR/supertrait-auto-trait.rs:8:19 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/supertrait-auto-trait.rs:8:17 | LL | auto trait Magic: Copy {} - | ----- ^^^^ help: remove the super traits + | -----^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have super traits + | auto trait cannot have super traits or lifetime bounds error[E0277]: the trait bound `NoClone: Copy` is not satisfied --> $DIR/supertrait-auto-trait.rs:16:23 | LL | let (a, b) = copy(NoClone); - | ^^^^^^^ the trait `Copy` is not implemented for `NoClone` + | ---- ^^^^^^^ the trait `Copy` is not implemented for `NoClone` + | | + | required by a bound introduced by this call | = note: required because of the requirements on the impl of `Magic` for `NoClone` note: required by a bound in `copy` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-20692.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-20692.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-20692.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-20692.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,11 @@ +trait Array: Sized + Copy {} + +fn f(x: &T) { + let _ = x + //~^ ERROR `Array` cannot be made into an object + as + &dyn Array; + //~^ ERROR `Array` cannot be made into an object +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-20692.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-20692.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-20692.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-20692.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,35 @@ +error[E0038]: the trait `Array` cannot be made into an object + --> $DIR/issue-20692.rs:7:5 + | +LL | &dyn Array; + | ^^^^^^^^^^ `Array` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/issue-20692.rs:1:14 + | +LL | trait Array: Sized + Copy {} + | ----- ^^^^^ ^^^^ ...because it requires `Self: Sized` + | | | + | | ...because it requires `Self: Sized` + | this trait cannot be made into an object... + +error[E0038]: the trait `Array` cannot be made into an object + --> $DIR/issue-20692.rs:4:13 + | +LL | let _ = x + | ^ `Array` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/issue-20692.rs:1:14 + | +LL | trait Array: Sized + Copy {} + | ----- ^^^^^ ^^^^ ...because it requires `Self: Sized` + | | | + | | ...because it requires `Self: Sized` + | this trait cannot be made into an object... + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Array>` for `&T` + = note: required by cast to type `&dyn Array` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-23825.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-23825.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-23825.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-23825.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,21 @@ +// run-pass +trait Stringify { + fn to_string(&self) -> String; +} + +impl Stringify for u32 { + fn to_string(&self) -> String { format!("u32: {}", *self) } +} + +impl Stringify for f32 { + fn to_string(&self) -> String { format!("f32: {}", *self) } +} + +fn print(x: T) -> String { + x.to_string() +} + +fn main() { + assert_eq!(&print(5), "u32: 5"); + assert_eq!(&print(5.0), "f32: 5"); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-52893.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-52893.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-52893.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-52893.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,57 @@ +// check-fail +// +// regression test for issue 52893 +trait At { + type AtRes; + fn at(self) -> Self::AtRes; +} + +trait Push { + type PushRes; + fn push(self, other: T) -> Self::PushRes; +} + +trait AddClass { + type AddRes; + fn init(self, func: F); +} + +trait ToRef { + type RefRes; + fn to_ref(&self) -> Self::RefRes; +} + +struct Class

(P); + +impl

Class

{ + fn with(self) -> >::AddRes + where + Self: AddClass, + { + todo!() + } + + fn from(self) -> >::AddRes + where + Self: AddClass, + { + todo!() + } +} + +impl AddClass for Class

+where + Self: At, + >::AtRes: Push, + <>::AtRes as Push>::PushRes: ToRef + Push, +{ + type AddRes = (); + + fn init(self, func: F) { + let builder = self.at().push(func); + let output = builder.to_ref(); + builder.push(output); //~ ERROR mismatched types [E0308] + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-52893.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-52893.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-52893.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-52893.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-52893.rs:53:22 + | +LL | impl AddClass for Class

+ | - this type parameter +... +LL | builder.push(output); + | ^^^^^^ expected type parameter `F`, found struct `Class` + | + = note: expected type parameter `F` + found struct `Class

` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-6128.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-6128.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-6128.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-6128.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,5 @@ // run-pass -#![feature(box_syntax)] - use std::collections::HashMap; trait Graph { @@ -19,6 +17,6 @@ } pub fn main() { - let g : Box> = box HashMap::new(); + let g : Box> = Box::new(HashMap::new()); let _g2 : Box> = g as Box>; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-68295.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-68295.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-68295.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-68295.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,47 @@ +// check-fail +// +// regression test for #68295 + +struct Matrix(R, C, S); + +impl Matrix { + fn into_owned(self) -> Matrix> + where + (): Allocator, + { + unimplemented!() + } +} + +impl Matrix { + fn hermitian_part(&self) -> Matrix> + where + (): Allocator, + { + unimplemented!() + } +} + +trait Allocator { + type Buffer; +} + +trait Trait { + type Power; +} + +impl> Trait for () { + type Power = A::Buffer; +} + +type Owned = >::Power; + +fn crash(input: Matrix) -> Matrix +where + (): Allocator, +{ + input.into_owned() + //~^ ERROR mismatched types [E0308] +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-68295.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-68295.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-68295.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-68295.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/issue-68295.rs:43:5 + | +LL | fn crash(input: Matrix) -> Matrix + | ----------------- expected `Matrix` because of return type +... +LL | input.into_owned() + | ^^^^^^^^^^^^^^^^^^ expected `u32`, found associated type + | + = note: expected struct `Matrix<_, _, u32>` + found struct `Matrix<_, _, <() as Allocator>::Buffer>` + = help: consider constraining the associated type `<() as Allocator>::Buffer` to `u32` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-89119.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-89119.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/issue-89119.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/issue-89119.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,11 @@ +// This is a regression test for issue #89119: an issue in intercrate mode caching. +// +// It requires multiple crates, of course, but the bug is triggered by the code in the dependency, +// not the main crate. This is why this file is empty. +// +// The auxiliary crate used in the test contains the code minimized from `zvariant-2.8.0`. + +// check-pass +// aux-build: issue_89119_intercrate_caching.rs + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/item-privacy.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/item-privacy.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/item-privacy.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/item-privacy.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -127,9 +127,6 @@ LL | ::A; | ^^^^^ `assoc_const::C` cannot be made into an object | - = help: consider moving `C` to another trait - = help: consider moving `B` to another trait - = help: consider moving `A` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/item-privacy.rs:25:15 | @@ -143,6 +140,9 @@ | - this trait cannot be made into an object... LL | const C: u8 = 0; | ^ ...because it contains this associated `const` + = help: consider moving `C` to another trait + = help: consider moving `A` to another trait + = help: consider moving `B` to another trait error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:115:12 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/kindck-owned-contains-1.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/kindck-owned-contains-1.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/kindck-owned-contains-1.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/kindck-owned-contains-1.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,8 +2,6 @@ #![allow(non_snake_case)] #![allow(non_camel_case_types)] -#![feature(box_syntax)] - trait repeat { fn get(&self) -> A; } impl repeat for Box { @@ -13,11 +11,11 @@ } fn repeater(v: Box) -> Box+'static> { - box v as Box+'static> // No + Box::new(v) as Box+'static> // No } pub fn main() { let x = 3; - let y = repeater(box x); + let y = repeater(Box::new(x)); assert_eq!(x, y.get()); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/matching-lifetimes.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/matching-lifetimes.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/matching-lifetimes.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/matching-lifetimes.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected fn pointer `fn(Foo<'a, 'b>)` found fn pointer `fn(Foo<'b, 'a>)` -note: the lifetime `'b` as defined on the impl at 13:9... +note: the lifetime `'b` as defined here... --> $DIR/matching-lifetimes.rs:13:9 | LL | impl<'a,'b> Tr for Foo<'a,'b> { | ^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 13:6 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/matching-lifetimes.rs:13:6 | LL | impl<'a,'b> Tr for Foo<'a,'b> { @@ -25,12 +25,12 @@ | = note: expected fn pointer `fn(Foo<'a, 'b>)` found fn pointer `fn(Foo<'b, 'a>)` -note: the lifetime `'a` as defined on the impl at 13:6... +note: the lifetime `'a` as defined here... --> $DIR/matching-lifetimes.rs:13:6 | LL | impl<'a,'b> Tr for Foo<'a,'b> { | ^^ -note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 13:9 +note: ...does not necessarily outlive the lifetime `'b` as defined here --> $DIR/matching-lifetimes.rs:13:9 | LL | impl<'a,'b> Tr for Foo<'a,'b> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/multidispatch-bad.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/multidispatch-bad.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/multidispatch-bad.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/multidispatch-bad.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `i32` to `u32` | LL | test(22i32, 44u32); - | ~~~~~ + | ~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/mutual-recursion-issue-75860.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/mutual-recursion-issue-75860.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/mutual-recursion-issue-75860.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/mutual-recursion-issue-75860.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ LL | iso(left, right) | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`mutual_recursion_issue_75860`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mutual_recursion_issue_75860`) note: required by a bound in `Option` --> $SRC_DIR/core/src/option.rs:LL:COL | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/negated-auto-traits-error.rs:23:11 | LL | Outer(TestType); - | ^^^^^^^^ `dummy::TestType` cannot be sent between threads safely + | ----- ^^^^^^^^ `dummy::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `dummy::TestType` note: required by `Outer` @@ -28,7 +30,9 @@ --> $DIR/negated-auto-traits-error.rs:32:13 | LL | is_send(TestType); - | ^^^^^^^^ `dummy1b::TestType` cannot be sent between threads safely + | ------- ^^^^^^^^ `dummy1b::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `dummy1b::TestType` note: required by a bound in `is_send` @@ -41,9 +45,11 @@ --> $DIR/negated-auto-traits-error.rs:40:13 | LL | is_send((8, TestType)); - | ^^^^^^^^^^^^^ `dummy1c::TestType` cannot be sent between threads safely + | ------- ^^^^^^^^^^^^^ `dummy1c::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call | - = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType` + = help: the trait `Send` is not implemented for `dummy1c::TestType` = note: required because it appears within the type `({integer}, dummy1c::TestType)` note: required by a bound in `is_send` --> $DIR/negated-auto-traits-error.rs:16:15 @@ -55,10 +61,9 @@ --> $DIR/negated-auto-traits-error.rs:48:13 | LL | is_send(Box::new(TestType)); - | ^^^^^^^^^^^^^^^^^^ - | | - | expected an implementor of trait `Send` - | help: consider borrowing here: `&Box::new(TestType)` + | ------- ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Send` + | | + | required by a bound introduced by this call | = note: the trait bound `dummy2::TestType: Send` is not satisfied = note: required because of the requirements on the impl of `Send` for `Unique` @@ -68,14 +73,20 @@ | LL | fn is_send(_: T) {} | ^^^^ required by this bound in `is_send` +help: consider borrowing here + | +LL | is_send(&Box::new(TestType)); + | + error[E0277]: `dummy3::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:56:13 | LL | is_send(Box::new(Outer2(TestType))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `dummy3::TestType` cannot be sent between threads safely + | ------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ `dummy3::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call | - = help: within `Outer2`, the trait `Send` is not implemented for `dummy3::TestType` + = help: the trait `Send` is not implemented for `dummy3::TestType` note: required because it appears within the type `Outer2` --> $DIR/negated-auto-traits-error.rs:12:8 | @@ -93,10 +104,9 @@ --> $DIR/negated-auto-traits-error.rs:66:13 | LL | is_sync(Outer2(TestType)); - | ^^^^^^^^^^^^^^^^ - | | - | expected an implementor of trait `Sync` - | help: consider borrowing here: `&Outer2(TestType)` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Sync` + | | + | required by a bound introduced by this call | = note: the trait bound `main::TestType: Sync` is not satisfied note: required because of the requirements on the impl of `Sync` for `Outer2` @@ -109,6 +119,12 @@ | LL | fn is_sync(_: T) {} | ^^^^ required by this bound in `is_sync` +help: consider borrowing here + | +LL | is_sync(&Outer2(TestType)); + | + +LL | is_sync(&mut Outer2(TestType)); + | ++++ error: aborting due to 7 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/normalize-super-trait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/normalize-super-trait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/normalize-super-trait.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/normalize-super-trait.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -// Regression test for #77653 -// When monomorphizing `f` we need to prove `dyn Derived<()>: Base<()>`. This -// requires us to normalize the `Base<<() as Proj>::S>` to `Base<()>` when -// comparing the supertrait `Derived<()>` to the expected trait. - -// build-pass - -trait Proj { - type S; -} - -impl Proj for () { - type S = (); -} - -impl Proj for i32 { - type S = i32; -} - -trait Base { - fn is_base(&self); -} - -trait Derived: Base + Base<()> { - fn is_derived(&self); -} - -fn f(obj: &dyn Derived

) { - obj.is_derived(); - Base::::is_base(obj); - Base::<()>::is_base(obj); -} - -fn main() { - let x: fn(_) = f::<()>; - let x: fn(_) = f::; -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/normalize-supertrait.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/normalize-supertrait.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/normalize-supertrait.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/normalize-supertrait.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,37 @@ +// Regression test for #77653 +// When monomorphizing `f` we need to prove `dyn Derived<()>: Base<()>`. This +// requires us to normalize the `Base<<() as Proj>::S>` to `Base<()>` when +// comparing the supertrait `Derived<()>` to the expected trait. + +// build-pass + +trait Proj { + type S; +} + +impl Proj for () { + type S = (); +} + +impl Proj for i32 { + type S = i32; +} + +trait Base { + fn is_base(&self); +} + +trait Derived: Base + Base<()> { + fn is_derived(&self); +} + +fn f(obj: &dyn Derived

) { + obj.is_derived(); + Base::::is_base(obj); + Base::<()>::is_base(obj); +} + +fn main() { + let x: fn(_) = f::<()>; + let x: fn(_) = f::; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/object/generics.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/object/generics.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/object/generics.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/object/generics.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // test for #8664 -#![feature(box_syntax)] - use std::marker; pub trait Trait2 { @@ -38,6 +36,6 @@ } pub fn main() { - let a = box () as Box>; + let a = Box::new(()) as Box>; assert_eq!(a.method(Type::Constant((1, 2))), 0); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/object-one-type-two-traits.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/object-one-type-two-traits.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/object-one-type-two-traits.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/object-one-type-two-traits.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,8 +4,6 @@ // Testing creating two vtables with the same self type, but different // traits. -#![feature(box_syntax)] - use std::any::Any; trait Wrap { @@ -27,7 +25,7 @@ } fn main() { - let x = box 22isize as Box; + let x = Box::new(22isize) as Box; println!("x={}", x.get()); let y = x.wrap(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/reservation-impl/no-use.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/reservation-impl/no-use.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/reservation-impl/no-use.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/reservation-impl/no-use.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/no-use.rs:10:26 | LL | <() as MyTrait>::foo(&()); - | ^^^ the trait `MyTrait` is not implemented for `()` + | -------------------- ^^^ the trait `MyTrait` is not implemented for `()` + | | + | required by a bound introduced by this call | = help: the following implementations were found: <() as MyTrait> diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/issue-39029.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/issue-39029.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/issue-39029.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/issue-39029.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,10 +2,11 @@ --> $DIR/issue-39029.rs:16:37 | LL | let _errors = TcpListener::bind(&bad); - | ^^^^ - | | - | the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` - | help: consider adding dereference here: `&*bad` + | ----------------- ^^^^ + | | | + | | the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` + | | help: consider adding dereference here: `&*bad` + | required by a bound introduced by this call | = note: required because of the requirements on the impl of `ToSocketAddrs` for `&NoToSocketAddrs` note: required by a bound in `TcpListener::bind` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/issue-62530.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/issue-62530.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/issue-62530.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/issue-62530.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,10 +2,11 @@ --> $DIR/issue-62530.rs:13:26 | LL | takes_type_parameter(&string); // Error - | ^^^^^^^ - | | - | the trait `SomeTrait` is not implemented for `&String` - | help: consider adding dereference here: `&*string` + | -------------------- ^^^^^^^ + | | | + | | the trait `SomeTrait` is not implemented for `&String` + | | help: consider adding dereference here: `&*string` + | required by a bound introduced by this call | note: required by a bound in `takes_type_parameter` --> $DIR/issue-62530.rs:4:44 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/multiple-0.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/multiple-0.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/multiple-0.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/multiple-0.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,10 +2,11 @@ --> $DIR/multiple-0.rs:34:9 | LL | foo(&baz); - | ^^^^ - | | - | the trait `Happy` is not implemented for `&Baz` - | help: consider adding dereference here: `&***baz` + | --- ^^^^ + | | | + | | the trait `Happy` is not implemented for `&Baz` + | | help: consider adding dereference here: `&***baz` + | required by a bound introduced by this call | note: required by a bound in `foo` --> $DIR/multiple-0.rs:30:26 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/multiple-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/multiple-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/multiple-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/suggest-deferences/multiple-1.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/multiple-1.rs:52:9 | LL | foo(&mut baz); - | ^^^^^^^^ the trait `Happy` is not implemented for `&mut Baz` + | --- ^^^^^^^^ the trait `Happy` is not implemented for `&mut Baz` + | | + | required by a bound introduced by this call | note: required by a bound in `foo` --> $DIR/multiple-1.rs:45:26 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/test-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/test-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/test-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/test-2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ -#![feature(box_syntax)] - #[allow(non_camel_case_types)] + + trait bar { fn dup(&self) -> Self; fn blah(&self); } impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } @@ -10,7 +10,8 @@ //~^ ERROR this associated function takes 0 generic arguments but 1 10.blah::(); //~^ ERROR this associated function takes 1 generic argument but 2 - (box 10 as Box).dup(); + (Box::new(10) as Box).dup(); //~^ ERROR E0038 //~| ERROR E0038 + //~| ERROR E0038 } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/test-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/test-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/test-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/test-2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -27,13 +27,28 @@ | ^^^^ - error[E0038]: the trait `bar` cannot be made into an object - --> $DIR/test-2.rs:13:16 + --> $DIR/test-2.rs:13:22 | -LL | (box 10 as Box).dup(); - | ^^^^^^^^^^^^ `bar` cannot be made into an object +LL | (Box::new(10) as Box).dup(); + | ^^^^^^^^^^^^ `bar` cannot be made into an object | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/test-2.rs:4:30 + | +LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } + | --- ^^^^ ^^^^ ...because method `blah` has generic type parameters + | | | + | | ...because method `dup` references the `Self` type in its return type + | this trait cannot be made into an object... = help: consider moving `dup` to another trait = help: consider moving `blah` to another trait + +error[E0038]: the trait `bar` cannot be made into an object + --> $DIR/test-2.rs:13:5 + | +LL | (Box::new(10) as Box).dup(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` cannot be made into an object + | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/test-2.rs:4:30 | @@ -42,15 +57,15 @@ | | | | | ...because method `dup` references the `Self` type in its return type | this trait cannot be made into an object... + = help: consider moving `dup` to another trait + = help: consider moving `blah` to another trait error[E0038]: the trait `bar` cannot be made into an object --> $DIR/test-2.rs:13:6 | -LL | (box 10 as Box).dup(); - | ^^^^^^ `bar` cannot be made into an object +LL | (Box::new(10) as Box).dup(); + | ^^^^^^^^^^^^ `bar` cannot be made into an object | - = help: consider moving `dup` to another trait - = help: consider moving `blah` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/test-2.rs:4:30 | @@ -59,10 +74,12 @@ | | | | | ...because method `dup` references the `Self` type in its return type | this trait cannot be made into an object... + = help: consider moving `dup` to another trait + = help: consider moving `blah` to another trait = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box<{integer}>` = note: required by cast to type `Box` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ // run-pass -#![feature(box_syntax, trait_upcasting)] +#![feature(trait_upcasting)] #![allow(incomplete_features)] struct Test { @@ -8,6 +8,6 @@ fn main() { let closure: Box = Box::new(|| ()); - let mut test = box Test { func: closure }; + let mut test = Box::new(Test { func: closure }); (test.func)(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,25 @@ +#![deny(deref_into_dyn_supertrait)] + +extern crate core; + +use core::ops::Deref; + +// issue 89190 +trait A {} +trait B: A {} +impl<'a> Deref for dyn 'a + B { + type Target = dyn A; + fn deref(&self) -> &Self::Target { + todo!() + } +} + +fn take_a(_: &dyn A) {} + +fn whoops(b: &dyn B) { + take_a(b) + //~^ ERROR `dyn B` implements `Deref` with supertrait `(dyn A + 'static)` as output + //~^^ WARN this was previously accepted by the compiler but is being phased out; +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,16 @@ +error: `dyn B` implements `Deref` with supertrait `(dyn A + 'static)` as output + --> $DIR/migrate-lint-deny.rs:20:12 + | +LL | take_a(b) + | ^ + | +note: the lint level is defined here + --> $DIR/migrate-lint-deny.rs:1:9 + | +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #89460 + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected trait object `dyn Bar<'a>` found trait object `dyn Bar<'static>` -note: the lifetime `'a` as defined on the function body at 12:16... +note: the lifetime `'a` as defined here... --> $DIR/type-checking-test-3.rs:12:16 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { @@ -21,7 +21,7 @@ | = note: expected trait object `dyn Bar<'static>` found trait object `dyn Bar<'a>` -note: the lifetime `'a` as defined on the function body at 17:16... +note: the lifetime `'a` as defined here... --> $DIR/type-checking-test-3.rs:17:16 | LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected trait object `dyn Bar<'static, 'a>` found trait object `dyn Bar<'static, 'static>` -note: the lifetime `'a` as defined on the function body at 16:16... +note: the lifetime `'a` as defined here... --> $DIR/type-checking-test-4.rs:16:16 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { @@ -21,7 +21,7 @@ | = note: expected trait object `dyn Bar<'a, 'static>` found trait object `dyn Bar<'static, 'static>` -note: the lifetime `'a` as defined on the function body at 21:16... +note: the lifetime `'a` as defined here... --> $DIR/type-checking-test-4.rs:21:16 | LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-diamond.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-diamond.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-diamond.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-diamond.rs 2021-11-29 19:27:12.000000000 +0000 @@ -13,13 +13,13 @@ #[rustc_dump_vtable] trait C: A { - //~^ error Vtable + //~^ error vtable fn foo_c(&self) {} } #[rustc_dump_vtable] trait D: B + C { - //~^ error Vtable + //~^ error vtable fn foo_d(&self) {} } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-diamond.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-diamond.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-diamond.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-diamond.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -16,7 +16,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multi-level.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multi-level.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multi-level.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multi-level.rs 2021-11-29 19:27:12.000000000 +0000 @@ -17,7 +17,7 @@ #[rustc_dump_vtable] trait B { - //~^ error Vtable + //~^ error vtable fn foo_b(&self) {} } @@ -28,19 +28,19 @@ #[rustc_dump_vtable] trait D { - //~^ error Vtable + //~^ error vtable fn foo_d(&self) {} } #[rustc_dump_vtable] trait E { - //~^ error Vtable + //~^ error vtable fn foo_e(&self) {} } #[rustc_dump_vtable] trait F: D + E { - //~^ error Vtable + //~^ error vtable fn foo_f(&self) {} } @@ -51,49 +51,49 @@ #[rustc_dump_vtable] trait H { - //~^ error Vtable + //~^ error vtable fn foo_h(&self) {} } #[rustc_dump_vtable] trait I { - //~^ error Vtable + //~^ error vtable fn foo_i(&self) {} } #[rustc_dump_vtable] trait J: H + I { - //~^ error Vtable + //~^ error vtable fn foo_j(&self) {} } #[rustc_dump_vtable] trait K { - //~^ error Vtable + //~^ error vtable fn foo_k(&self) {} } #[rustc_dump_vtable] trait L { - //~^ error Vtable + //~^ error vtable fn foo_l(&self) {} } #[rustc_dump_vtable] trait M: K + L { - //~^ error Vtable + //~^ error vtable fn foo_m(&self) {} } #[rustc_dump_vtable] trait N: J + M { - //~^ error Vtable + //~^ error vtable fn foo_n(&self) {} } #[rustc_dump_vtable] trait O: G + N { - //~^ error Vtable + //~^ error vtable fn foo_o(&self) {} } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multi-level.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multi-level.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multi-level.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multi-level.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -37,7 +37,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -51,7 +51,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -65,7 +65,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -79,7 +79,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -96,7 +96,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -110,7 +110,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -124,7 +124,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -141,7 +141,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -155,7 +155,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -169,7 +169,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -186,7 +186,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multiple.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multiple.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multiple.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multiple.rs 2021-11-29 19:27:12.000000000 +0000 @@ -8,13 +8,13 @@ #[rustc_dump_vtable] trait B { - //~^ error Vtable + //~^ error vtable fn foo_b(&self) {} } #[rustc_dump_vtable] trait C: A + B { - //~^ error Vtable + //~^ error vtable fn foo_c(&self) {} } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multiple.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multiple.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multiple.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-multiple.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -15,7 +15,7 @@ LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-non-object-safe.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-non-object-safe.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-non-object-safe.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-non-object-safe.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,18 @@ +// build-fail +#![feature(rustc_attrs)] + +// Ensure that non-object-safe methods in Iterator does not generate +// vtable entries. + +#[rustc_dump_vtable] +trait A: Iterator {} +//~^ error vtable + +impl A for T where T: Iterator {} + +fn foo(_a: &mut dyn A) { +} + +fn main() { + foo(&mut vec![0, 1, 2, 3].into_iter()); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-non-object-safe.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-non-object-safe.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-non-object-safe.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-non-object-safe.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,16 @@ +error: vtable entries for ` as A>`: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method( as Iterator>::next), + Method( as Iterator>::size_hint), + Method( as Iterator>::advance_by), + Method( as Iterator>::nth), +] + --> $DIR/vtable-non-object-safe.rs:8:1 + | +LL | trait A: Iterator {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-vacant.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-vacant.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-vacant.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-vacant.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,22 +1,25 @@ // build-fail #![feature(rustc_attrs)] +#![feature(negative_impls)] +#![allow(where_clauses_object_safety)] // B --> A #[rustc_dump_vtable] trait A { fn foo_a1(&self) {} - fn foo_a2(&self) where Self: Sized {} + fn foo_a2(&self) where Self: Send {} } #[rustc_dump_vtable] trait B: A { - //~^ error Vtable + //~^ error vtable fn foo_b1(&self) {} - fn foo_b2() where Self: Sized {} + fn foo_b2(&self) where Self: Send {} } struct S; +impl !Send for S {} impl A for S {} impl B for S {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-vacant.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-vacant.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-vacant.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/vtable/vtable-vacant.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -7,12 +7,12 @@ Method(::foo_b1), Vacant, ] - --> $DIR/vtable-vacant.rs:13:1 + --> $DIR/vtable-vacant.rs:15:1 | LL | / trait B: A { LL | | LL | | fn foo_b1(&self) {} -LL | | fn foo_b2() where Self: Sized {} +LL | | fn foo_b2(&self) where Self: Send {} LL | | } | |_^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/wf-object/no-duplicates.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/wf-object/no-duplicates.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/traits/wf-object/no-duplicates.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/traits/wf-object/no-duplicates.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -17,7 +17,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -28,7 +28,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -39,7 +39,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -50,7 +50,7 @@ | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjT fn(&'a u8)> + ObjT fn(&'b u8)> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjT fn(&'a u8)> + ObjT fn(&'b u8)> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 5 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -warning: Trait bound String: Copy does not depend on any type or lifetime parameters +warning: trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:5:51 | LL | fn copy_string(t: String) -> String where String: Copy { @@ -6,19 +6,19 @@ | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound String: Copy does not depend on any type or lifetime parameters +warning: trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:12:56 | LL | fn copy_out_string(t: &String) -> String where String: Copy { | ^^^^ -warning: Trait bound String: Copy does not depend on any type or lifetime parameters +warning: trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:16:55 | LL | fn copy_string_with_param(x: String) where String: Copy { | ^^^^ -warning: Trait bound for<'b> &'b mut i32: Copy does not depend on any type or lifetime parameters +warning: trait bound for<'b> &'b mut i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:22:76 | LL | fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -10,7 +10,7 @@ help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit | LL | B::get_x().try_into().unwrap() - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:21:8 | LL | B: A @@ -6,37 +6,37 @@ | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:28:8 | LL | B: A | ^^^^^^^^^^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:35:8 | LL | B: A | ^^^^^^^^^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:42:8 | LL | B: A + A | ^^^^^^^^^^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:42:21 | LL | B: A + A | ^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:51:8 | LL | B: A + A | ^^^^^^^^^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:51:20 | LL | B: A + A diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -warning: Trait bound str: Sized does not depend on any type or lifetime parameters +warning: trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:14:31 | LL | struct S(str, str) where str: Sized; @@ -6,13 +6,13 @@ | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound for<'a> T<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters +warning: trait bound for<'a> T<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:17:49 | LL | fn unsized_local() where for<'a> T: Sized { | ^^^^^ -warning: Trait bound str: Sized does not depend on any type or lifetime parameters +warning: trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:22:35 | LL | fn return_str() -> str where str: Sized { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:14:19 | LL | enum E where i32: Foo { V } @@ -6,19 +6,19 @@ | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:16:21 | LL | struct S where i32: Foo; | ^^^ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:18:20 | LL | trait T where i32: Foo {} | ^^^ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:20:20 | LL | union U where i32: Foo { f: i32 } @@ -37,55 +37,55 @@ LL + type Y = (); | -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:22:19 | LL | type Y where i32: Foo = (); | ^^^ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:26:28 | LL | impl Foo for () where i32: Foo { | ^^^ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:34:19 | LL | fn f() where i32: Foo { | ^^^ -warning: Trait bound &'static str: Foo does not depend on any type or lifetime parameters +warning: trait bound &'static str: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:41:28 | LL | fn g() where &'static str: Foo { | ^^^ -warning: Trait bound str: Sized does not depend on any type or lifetime parameters +warning: trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:55:37 | LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^ -warning: Trait bound for<'a> Dst<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters +warning: trait bound for<'a> Dst<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:57:51 | LL | fn unsized_local() where for<'a> Dst: Sized { | ^^^^^ -warning: Trait bound str: Sized does not depend on any type or lifetime parameters +warning: trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:61:35 | LL | fn return_str() -> str where str: Sized { | ^^^^^ -warning: Trait bound String: Neg does not depend on any type or lifetime parameters +warning: trait bound String: Neg does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:65:46 | LL | fn use_op(s: String) -> String where String: ::std::ops::Neg { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: Trait bound i32: Iterator does not depend on any type or lifetime parameters +warning: trait bound i32: Iterator does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:70:25 | LL | fn use_for() where i32: Iterator { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -warning: Trait bound Vec: Debug does not depend on any type or lifetime parameters +warning: trait bound Vec: Debug does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-well-formed.rs:7:30 | LL | pub fn foo() where Vec: Debug, str: Copy { @@ -6,7 +6,7 @@ | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound str: Copy does not depend on any type or lifetime parameters +warning: trait bound str: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-well-formed.rs:7:42 | LL | pub fn foo() where Vec: Debug, str: Copy { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -24,7 +24,9 @@ --> $DIR/trivial-bounds-leak.rs:25:15 | LL | Foo::test(&4i32); - | ^^^^^ the trait `Foo` is not implemented for `i32` + | --------- ^^^^^ the trait `Foo` is not implemented for `i32` + | | + | required by a bound introduced by this call | note: required by `Foo::test` --> $DIR/trivial-bounds-leak.rs:5:5 @@ -36,7 +38,9 @@ --> $DIR/trivial-bounds-leak.rs:26:22 | LL | generic_function(5i32); - | ^^^^ the trait `Foo` is not implemented for `i32` + | ---------------- ^^^^ the trait `Foo` is not implemented for `i32` + | | + | required by a bound introduced by this call | note: required by a bound in `generic_function` --> $DIR/trivial-bounds-leak.rs:29:24 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -error: Trait bound i32: Copy does not depend on any type or lifetime parameters +error: trait bound i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:5:21 | LL | struct A where i32: Copy; @@ -10,37 +10,37 @@ LL | #![deny(trivial_bounds)] | ^^^^^^^^^^^^^^ -error: Trait bound i32: X<()> does not depend on any type or lifetime parameters +error: trait bound i32: X<()> does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:18:30 | LL | fn global_param() where i32: X<()> {} | ^^^^^ -error: Trait bound i32: Z does not depend on any type or lifetime parameters +error: trait bound i32: Z does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:22:35 | LL | fn global_projection() where i32: Z {} | ^^^^^^^^^^ -error: Lifetime bound i32: 'static does not depend on any type or lifetime parameters +error: lifetime bound i32: 'static does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:29:34 | LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {} | ^^^^^^^ -error: Lifetime bound &'static str: 'static does not depend on any type or lifetime parameters +error: lifetime bound &'static str: 'static does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:29:57 | LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {} | ^^^^^^^ -error: Lifetime bound 'static: 'static does not depend on any type or lifetime parameters +error: lifetime bound 'static: 'static does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:35:37 | LL | fn global_outlives() where 'static: 'static {} | ^^^^^^^ -error: Trait bound i32: Copy does not depend on any type or lifetime parameters +error: trait bound i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:38:46 | LL | fn mixed_bounds() where i32: X + Copy {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/try-block/try-block-opt-init.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/try-block/try-block-opt-init.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/try-block/try-block-opt-init.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/try-block/try-block-opt-init.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/try-block-opt-init.rs:15:5 | LL | assert_eq!(cfg_res, 5); - | ^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `cfg_res` + | ^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `cfg_res` | = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/try-block/try-block-unused-delims.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/try-block/try-block-unused-delims.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/try-block/try-block-unused-delims.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/try-block/try-block-unused-delims.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,43 +2,71 @@ --> $DIR/try-block-unused-delims.rs:11:13 | LL | consume((try {})); - | ^^^^^^^^ help: remove these parentheses + | ^ ^ | note: the lint level is defined here --> $DIR/try-block-unused-delims.rs:6:9 | LL | #![warn(unused_parens, unused_braces)] | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - consume((try {})); +LL + consume(try {}); + | warning: unnecessary braces around function argument --> $DIR/try-block-unused-delims.rs:14:13 | LL | consume({ try {} }); - | ^^^^^^^^^^ help: remove these braces + | ^^ ^^ | note: the lint level is defined here --> $DIR/try-block-unused-delims.rs:6:24 | LL | #![warn(unused_parens, unused_braces)] | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - consume({ try {} }); +LL + consume(try {}); + | warning: unnecessary parentheses around `match` scrutinee expression --> $DIR/try-block-unused-delims.rs:17:11 | LL | match (try {}) { - | ^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - match (try {}) { +LL + match try {} { + | warning: unnecessary parentheses around `let` scrutinee expression --> $DIR/try-block-unused-delims.rs:22:22 | LL | if let Err(()) = (try {}) {} - | ^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - if let Err(()) = (try {}) {} +LL + if let Err(()) = try {} {} + | warning: unnecessary parentheses around `match` scrutinee expression --> $DIR/try-block-unused-delims.rs:25:11 | LL | match (try {}) { - | ^^^^^^^^ help: remove these parentheses + | ^ ^ + | +help: remove these parentheses + | +LL - match (try {}) { +LL + match try {} { + | warning: 5 warnings emitted diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/tutorial-suffix-inference-test.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/tutorial-suffix-inference-test.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/tutorial-suffix-inference-test.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/tutorial-suffix-inference-test.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,10 +2,12 @@ --> $DIR/tutorial-suffix-inference-test.rs:9:18 | LL | identity_u16(x); - | ^ - | | - | expected `u16`, found `u8` - | help: you can convert a `u8` to a `u16`: `x.into()` + | ^ expected `u16`, found `u8` + | +help: you can convert a `u8` to a `u16` + | +LL | identity_u16(x.into()); + | +++++++ error[E0308]: mismatched types --> $DIR/tutorial-suffix-inference-test.rs:12:18 @@ -16,7 +18,7 @@ help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | identity_u16(y.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/tutorial-suffix-inference-test.rs:21:18 @@ -27,7 +29,7 @@ help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | identity_u16(a.try_into().unwrap()); - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type/type-ascription-precedence.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type/type-ascription-precedence.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type/type-ascription-precedence.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type/type-ascription-precedence.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -28,7 +28,22 @@ LL | -(S: Z); | ^^^^^^^ cannot apply unary operator `-` | - = note: an implementation of `std::ops::Neg` might be missing for `Z` +note: an implementation of `std::ops::Neg` might be missing for `Z` + --> $DIR/type-ascription-precedence.rs:9:1 + | +LL | struct Z; + | ^^^^^^^^^ must implement `std::ops::Neg` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Neg { +LL | | /// The resulting type after applying the `-` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn neg(self) -> Self::Output; +LL | | } + | |_^ error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:45:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,12 @@ +macro_rules! many_args { + ([$($t:tt)*]#$($h:tt)*) => { + many_args!{[$($t)*$($t)*]$($h)*} + }; + ([$($t:tt)*]) => { + fn _f($($t: ()),*) {} //~ ERROR function can not have more than 65535 arguments + } +} + +many_args!{[_]########## ######} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,13 @@ +error: function can not have more than 65535 arguments + --> $DIR/issue-88577-check-fn-with-more-than-65535-arguments.rs:6:24 + | +LL | fn _f($($t: ()),*) {} + | ________________________^ +LL | | } +LL | | } +LL | | +LL | | many_args!{[_]########## ######} + | |____________^ + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -16,7 +16,6 @@ LL | let y = x as dyn MyAdd; | ^^^^^^^^^^^^^^ `MyAdd` cannot be made into an object | - = help: consider moving `add` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:6:55 | @@ -24,6 +23,7 @@ | ----- ^^^^ ...because method `add` references the `Self` type in its return type | | | this trait cannot be made into an object... + = help: consider moving `add` to another trait error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ | LL | is_send(foo()); | ^^^^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::fmt::Debug: std::marker::Send`... + = note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`... = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in module `m` --> $DIR/auto-trait-leakage3.rs:6:1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bound_reduction2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bound_reduction2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bound_reduction2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bound_reduction2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -7,6 +7,7 @@ } type Foo = impl Trait; +//~^ ERROR could not find defining uses trait Trait {} @@ -14,5 +15,9 @@ fn foo_desugared(_: T) -> Foo { //~^ ERROR non-defining opaque type use in defining scope + //~| ERROR non-defining opaque type use in defining scope + //~| ERROR non-defining opaque type use in defining scope + //~| ERROR `T` is part of concrete type but not used in parameter list + //~| ERROR `T` is part of concrete type but not used in parameter list () } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,34 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/bound_reduction2.rs:16:60 + | +LL | fn foo_desugared(_: T) -> Foo { + | ____________________________________________________________^ +LL | | +LL | | +LL | | +... | +LL | | () +LL | | } + | |_^ + +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/bound_reduction2.rs:16:60 + | +LL | fn foo_desugared(_: T) -> Foo { + | ____________________________________________________________^ +LL | | +LL | | +LL | | +... | +LL | | () +LL | | } + | |_^ + error: non-defining opaque type use in defining scope - --> $DIR/bound_reduction2.rs:15:46 + --> $DIR/bound_reduction2.rs:16:1 | LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: used non-generic type `::Assoc` for generic parameter --> $DIR/bound_reduction2.rs:9:10 @@ -10,5 +36,35 @@ LL | type Foo = impl Trait; | ^ -error: aborting due to previous error +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:16:1 + | +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: used non-generic type `_` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 + | +LL | type Foo = impl Trait; + | ^ + +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:16:1 + | +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: used non-generic type `_` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 + | +LL | type Foo = impl Trait; + | ^ + +error: could not find defining uses + --> $DIR/bound_reduction2.rs:9:15 + | +LL | type Foo = impl Trait; + | ^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -14,7 +14,7 @@ | = note: expected trait `From<&'a str>` found trait `From<&'static str>` -note: the lifetime `'a` as defined on the item at 6:8... +note: the lifetime `'a` as defined here... --> $DIR/bounds-are-checked.rs:6:8 | LL | type X<'a> = impl Into<&'static str> + From<&'a str>; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,6 +3,7 @@ fn main() {} type Two<'a, 'b> = impl std::fmt::Debug; +//~^ ERROR could not find defining uses fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~^ ERROR non-defining opaque type use diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_lifetime_param.rs:7:26 + --> $DIR/generic_duplicate_lifetime_param.rs:8:26 | LL | fn one<'a>(t: &'a ()) -> Two<'a, 'a> { | ^^^^^^^^^^^ @@ -10,5 +10,11 @@ LL | type Two<'a, 'b> = impl std::fmt::Debug; | ^^ ^^ -error: aborting due to previous error +error: could not find defining uses + --> $DIR/generic_duplicate_lifetime_param.rs:5:20 + | +LL | type Two<'a, 'b> = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ // test that unused generic parameters are ok type Two = impl Debug; +//~^ ERROR `T` doesn't implement `Debug` fn one(t: T) -> Two { //~^ ERROR non-defining opaque type use in defining scope diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use2.rs:10:27 + --> $DIR/generic_duplicate_param_use2.rs:11:27 | LL | fn one(t: T) -> Two { | ^^^^^^^^^ @@ -10,5 +10,17 @@ LL | type Two = impl Debug; | ^ ^ -error: aborting due to previous error +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/generic_duplicate_param_use2.rs:8:18 + | +LL | type Two = impl Debug; + | ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +help: consider restricting type parameter `T` + | +LL | type Two = impl Debug; + | +++++++++++++++++ + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ // test that unused generic parameters are ok type Two = impl Debug; +//~^ ERROR `T` doesn't implement `Debug` fn one(t: T) -> Two { //~^ ERROR non-defining opaque type use in defining scope @@ -17,5 +18,6 @@ } fn three(_: T, u: U) -> Two { + //~^ ERROR concrete type differs from previous defining opaque type use u } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use3.rs:10:27 + --> $DIR/generic_duplicate_param_use3.rs:11:27 | LL | fn one(t: T) -> Two { | ^^^^^^^^^ @@ -10,5 +10,29 @@ LL | type Two = impl Debug; | ^ ^ -error: aborting due to previous error +error: concrete type differs from previous defining opaque type use + --> $DIR/generic_duplicate_param_use3.rs:20:1 + | +LL | fn three(_: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `U` + | +note: previous use here + --> $DIR/generic_duplicate_param_use3.rs:16:1 + | +LL | fn two(t: T, _: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/generic_duplicate_param_use3.rs:8:18 + | +LL | type Two = impl Debug; + | ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +help: consider restricting type parameter `T` + | +LL | type Two = impl Debug; + | +++++++++++++++++ + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ // test that unused generic parameters are ok type Two = impl Debug; +//~^ ERROR `U` doesn't implement `Debug` fn one(t: T) -> Two { //~^ ERROR non-defining opaque type use in defining scope diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use4.rs:10:27 + --> $DIR/generic_duplicate_param_use4.rs:11:27 | LL | fn one(t: T) -> Two { | ^^^^^^^^^ @@ -10,5 +10,17 @@ LL | type Two = impl Debug; | ^ ^ -error: aborting due to previous error +error[E0277]: `U` doesn't implement `Debug` + --> $DIR/generic_duplicate_param_use4.rs:8:18 + | +LL | type Two = impl Debug; + | ^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +help: consider restricting type parameter `U` + | +LL | type Two = impl Debug; + | +++++++++++++++++ + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,8 +6,11 @@ // test that unused generic parameters are ok type TwoTys = impl Debug; +//~^ ERROR could not find defining uses type TwoLifetimes<'a, 'b> = impl Debug; +//~^ ERROR could not find defining uses type TwoConsts = impl Debug; +//~^ ERROR could not find defining uses fn one_ty(t: T) -> TwoTys { //~^ ERROR non-defining opaque type use in defining scope diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:12:30 + --> $DIR/generic_duplicate_param_use.rs:15:30 | LL | fn one_ty(t: T) -> TwoTys { | ^^^^^^^^^^^^ @@ -10,29 +10,47 @@ LL | type TwoTys = impl Debug; | ^ ^ +error: could not find defining uses + --> $DIR/generic_duplicate_param_use.rs:8:21 + | +LL | type TwoTys = impl Debug; + | ^^^^^^^^^^ + error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:17:36 + --> $DIR/generic_duplicate_param_use.rs:20:36 | LL | fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> { | ^^^^^^^^^^^^^^^^^^^^ | note: lifetime used multiple times - --> $DIR/generic_duplicate_param_use.rs:9:19 + --> $DIR/generic_duplicate_param_use.rs:10:19 | LL | type TwoLifetimes<'a, 'b> = impl Debug; | ^^ ^^ +error: could not find defining uses + --> $DIR/generic_duplicate_param_use.rs:10:29 + | +LL | type TwoLifetimes<'a, 'b> = impl Debug; + | ^^^^^^^^^^ + error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:22:50 + --> $DIR/generic_duplicate_param_use.rs:25:50 | LL | fn one_const(t: *mut [u8; N]) -> TwoConsts { | ^^^^^^^^^^^^^^^ | note: constant used multiple times - --> $DIR/generic_duplicate_param_use.rs:10:22 + --> $DIR/generic_duplicate_param_use.rs:12:22 | LL | type TwoConsts = impl Debug; | ^ ^ -error: aborting due to 3 previous errors +error: could not find defining uses + --> $DIR/generic_duplicate_param_use.rs:12:50 + | +LL | type TwoConsts = impl Debug; + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs 2021-11-29 19:27:12.000000000 +0000 @@ -5,8 +5,11 @@ fn main() {} type OneTy = impl Debug; +//~^ ERROR could not find defining uses type OneLifetime<'a> = impl Debug; +//~^ ERROR could not find defining uses type OneConst = impl Debug; +//~^ ERROR could not find defining uses // Not defining uses, because they doesn't define *all* possible generics. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:13:21 + --> $DIR/generic_nondefining_use.rs:16:21 | LL | fn concrete_ty() -> OneTy { | ^^^^^^^^^^ @@ -10,8 +10,14 @@ LL | type OneTy = impl Debug; | ^ +error: could not find defining uses + --> $DIR/generic_nondefining_use.rs:7:17 + | +LL | type OneTy = impl Debug; + | ^^^^^^^^^^ + error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:18:27 + --> $DIR/generic_nondefining_use.rs:21:27 | LL | type OneLifetime<'a> = impl Debug; | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type @@ -19,17 +25,29 @@ LL | fn concrete_lifetime() -> OneLifetime<'static> { | ^^^^^^^^^^^^^^^^^^^^ +error: could not find defining uses + --> $DIR/generic_nondefining_use.rs:9:24 + | +LL | type OneLifetime<'a> = impl Debug; + | ^^^^^^^^^^ + error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:23:24 + --> $DIR/generic_nondefining_use.rs:26:24 | LL | fn concrete_const() -> OneConst<{ 123 }> { | ^^^^^^^^^^^^^^^^^ | note: used non-generic constant `123_usize` for generic parameter - --> $DIR/generic_nondefining_use.rs:9:21 + --> $DIR/generic_nondefining_use.rs:11:21 | LL | type OneConst = impl Debug; | ^ -error: aborting due to 3 previous errors +error: could not find defining uses + --> $DIR/generic_nondefining_use.rs:11:33 + | +LL | type OneConst = impl Debug; + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/incomplete-inference.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/incomplete-inference.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/incomplete-inference.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/incomplete-inference.rs 2021-11-29 19:27:12.000000000 +0000 @@ -8,7 +8,6 @@ } fn baz() -> Foo { - //~^ ERROR: concrete type differs from previous defining opaque type use Some(()) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,18 +4,6 @@ LL | None | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option` -error: concrete type differs from previous defining opaque type use - --> $DIR/incomplete-inference.rs:10:1 - | -LL | fn baz() -> Foo { - | ^^^^^^^^^^^^^^^ expected `[type error]`, got `Option<()>` - | -note: previous use here - --> $DIR/incomplete-inference.rs:5:1 - | -LL | fn bar() -> Foo { - | ^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0282`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/inference-cycle.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/inference-cycle.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/inference-cycle.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/inference-cycle.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ | LL | is_send(foo()); // Today: error | ^^^^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::fmt::Debug: std::marker::Send`... + = note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`... = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in module `m` --> $DIR/inference-cycle.rs:4:1 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60371.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60371.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60371.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60371.rs 2021-11-29 19:27:12.000000000 +0000 @@ -11,6 +11,7 @@ const FUN: fn() -> Self::Item = || (); //~^ ERROR the trait bound `(): Bug` is not satisfied + //~| ERROR non-defining opaque type use in defining scope } fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60371.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60371.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60371.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60371.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -16,7 +16,16 @@ = help: the following implementations were found: <&() as Bug> -error: aborting due to 2 previous errors +error: non-defining opaque type use in defining scope + --> $DIR/issue-60371.rs:12:37 + | +LL | impl Bug for &() { + | - cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +... +LL | const FUN: fn() -> Self::Item = || (); + | ^^^^^ + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60564.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60564.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60564.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60564.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ } type IterBitsIter = impl std::iter::Iterator; +//~^ ERROR could not find defining uses impl IterBits for T where diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60564.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60564.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60564.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-60564.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-60564.rs:19:34 + --> $DIR/issue-60564.rs:20:34 | LL | fn iter_bits(self, n: u8) -> Self::BitsIter { | ^^^^^^^^^^^^^^ @@ -10,5 +10,11 @@ LL | type IterBitsIter = impl std::iter::Iterator; | ^ -error: aborting due to previous error +error: could not find defining uses + --> $DIR/issue-60564.rs:8:30 + | +LL | type IterBitsIter = impl std::iter::Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +// Regression test for issue #68368 +// Ensures that we don't ICE when emitting an error +// for a non-defining use when lifetimes are involved + +#![feature(type_alias_impl_trait)] +trait Trait {} +type Alias<'a, U> = impl Trait; +//~^ ERROR could not find defining uses +fn f<'a>() -> Alias<'a, ()> {} +//~^ ERROR non-defining opaque type use in defining scope + +fn main() {} + +impl Trait for () {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,20 @@ +error: non-defining opaque type use in defining scope + --> $DIR/issue-68368-non-defining-use-2.rs:9:15 + | +LL | fn f<'a>() -> Alias<'a, ()> {} + | ^^^^^^^^^^^^^ + | +note: used non-generic type `()` for generic parameter + --> $DIR/issue-68368-non-defining-use-2.rs:7:16 + | +LL | type Alias<'a, U> = impl Trait; + | ^ + +error: could not find defining uses + --> $DIR/issue-68368-non-defining-use-2.rs:7:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs 2021-11-29 19:27:12.000000000 +0000 @@ -5,6 +5,7 @@ #![feature(type_alias_impl_trait)] trait Trait {} type Alias<'a, U> = impl Trait; +//~^ ERROR could not find defining uses fn f<'a>() -> Alias<'a, ()> {} //~^ ERROR non-defining opaque type use in defining scope diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-68368-non-defining-use.rs:8:15 + --> $DIR/issue-68368-non-defining-use.rs:9:15 | LL | fn f<'a>() -> Alias<'a, ()> {} | ^^^^^^^^^^^^^ @@ -10,5 +10,11 @@ LL | type Alias<'a, U> = impl Trait; | ^ -error: aborting due to previous error +error: could not find defining uses + --> $DIR/issue-68368-non-defining-use.rs:7:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-74761-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-74761-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-74761-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-74761-2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,3 @@ -#![feature(member_constraints)] #![feature(type_alias_impl_trait)] pub trait A { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,11 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-74761-2.rs:8:6 + --> $DIR/issue-74761-2.rs:7:6 | LL | impl<'a, 'b> A for () { | ^^ unconstrained lifetime parameter error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-74761-2.rs:8:10 + --> $DIR/issue-74761-2.rs:7:10 | LL | impl<'a, 'b> A for () { | ^^ unconstrained lifetime parameter diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs 2021-11-29 19:27:12.000000000 +0000 @@ -11,7 +11,6 @@ } fn g(a: A, b: B) -> (X, X) { - //~^ ERROR concrete type differs from previous defining opaque type (a, b) //~^ ERROR mismatched types } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,10 @@ error[E0308]: mismatched types - --> $DIR/multiple-def-uses-in-one-fn3.rs:15:9 + --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9 | LL | fn g(a: A, b: B) -> (X, X) { | - - found type parameter | | | expected type parameter -LL | LL | (a, b) | ^ expected type parameter `A`, found type parameter `B` | @@ -14,18 +13,6 @@ = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters -error: concrete type differs from previous defining opaque type use - --> $DIR/multiple-def-uses-in-one-fn3.rs:13:1 - | -LL | fn g(a: A, b: B) -> (X, X) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `[type error]` - | -note: previous use here - --> $DIR/multiple-def-uses-in-one-fn3.rs:9:1 - | -LL | fn f(a: A, b: B) -> (X, X) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs 2021-11-29 19:27:12.000000000 +0000 @@ -5,6 +5,7 @@ fn main() {} type Two = impl Debug; +//~^ ERROR `T` doesn't implement `Debug` fn two(t: T) -> Two { //~^ ERROR non-defining opaque type use in defining scope @@ -26,6 +27,7 @@ } fn four(t: T) -> Two { + //~^ ERROR concrete type differs from previous (t, ::FOO) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/not_a_defining_use.rs:9:27 + --> $DIR/not_a_defining_use.rs:10:27 | LL | fn two(t: T) -> Two { | ^^^^^^^^^^^ @@ -10,5 +10,30 @@ LL | type Two = impl Debug; | ^ -error: aborting due to previous error +error: concrete type differs from previous defining opaque type use + --> $DIR/not_a_defining_use.rs:29:1 + | +LL | fn four(t: T) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, ::Blub)` + | +note: previous use here + --> $DIR/not_a_defining_use.rs:15:1 + | +LL | fn three(t: T) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/not_a_defining_use.rs:7:18 + | +LL | type Two = impl Debug; + | ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = note: required because of the requirements on the impl of `Debug` for `(T, i8)` +help: consider restricting type parameter `T` + | +LL | type Two = impl Debug; + | +++++++++++++++++ + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/call-block.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/call-block.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/call-block.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/call-block.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,3 @@ +fn main() { + let _ = {42}(); //~ ERROR expected function, found `{integer}` +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/call-block.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/call-block.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/call-block.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/call-block.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,11 @@ +error[E0618]: expected function, found `{integer}` + --> $DIR/call-block.rs:2:13 + | +LL | let _ = {42}(); + | ^^^^-- + | | + | call expression requires function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,4 @@ +fn main() { + let mut a; + a = a = true; //~ ERROR mismatched types +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/issue-87771-ice-assign-assign-to-bool.rs:3:9 + | +LL | a = a = true; + | ^^^^^^^^ expected `bool`, found `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88609.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88609.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88609.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88609.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,19 @@ +// Regression test for #88609: +// The return type for `main` is not normalized while checking if it implements +// the trait `std::process::Termination`. + +// build-pass + +trait Same { + type Output; +} + +impl Same for T { + type Output = T; +} + +type Unit = <() as Same>::Output; + +fn main() -> Result { + unimplemented!() +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,9 @@ +// run-rustfix + +fn main() { + let a = Some(42); + println!( + "The value is {}.", + a.unwrap() //~ERROR [E0615] + ); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,9 @@ +// run-rustfix + +fn main() { + let a = Some(42); + println!( + "The value is {}.", + (a.unwrap)() //~ERROR [E0615] + ); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88803-call-expr-method.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,15 @@ +error[E0615]: attempted to take value of method `unwrap` on type `Option<{integer}>` + --> $DIR/issue-88803-call-expr-method.rs:7:12 + | +LL | (a.unwrap)() + | ^^^^^^ method, not a field + | +help: remove wrapping parentheses to call the method + | +LL - (a.unwrap)() +LL + a.unwrap() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0615`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88844.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88844.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88844.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88844.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +// Regression test for #88844. + +struct Struct { value: i32 } +//~^ NOTE: similarly named struct `Struct` defined here + +impl Stuct { +//~^ ERROR: cannot find type `Stuct` in this scope [E0412] +//~| HELP: a struct with a similar name exists + fn new() -> Self { + Self { value: 42 } + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88844.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88844.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-88844.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-88844.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,12 @@ +error[E0412]: cannot find type `Stuct` in this scope + --> $DIR/issue-88844.rs:6:6 + | +LL | struct Struct { value: i32 } + | ------------- similarly named struct `Struct` defined here +... +LL | impl Stuct { + | ^^^^^ help: a struct with a similar name exists: `Struct` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.fixed rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.fixed --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,9 @@ +// run-rustfix + +fn main() { + let a = Some(42); + println!( + "The value is {}.", + (a.unwrap()) //~ERROR [E0615] + ); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,9 @@ +// run-rustfix + +fn main() { + let a = Some(42); + println!( + "The value is {}.", + (a.unwrap) //~ERROR [E0615] + ); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89044-wrapped-expr-method.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0615]: attempted to take value of method `unwrap` on type `Option<{integer}>` + --> $DIR/issue-89044-wrapped-expr-method.rs:7:12 + | +LL | (a.unwrap) + | ^^^^^^ method, not a field + | +help: use parentheses to call the method + | +LL | (a.unwrap()) + | ++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0615`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89275.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89275.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89275.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89275.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,29 @@ +#![recursion_limit = "5"] // To reduce noise + +//expect mutability error when ambiguous traits are in scope +//and not an overflow error on the span in the main function. + +struct Ratio(T); + +pub trait Pow { + fn pow(self) -> Self; +} + +impl<'a, T> Pow for &'a Ratio +where + &'a T: Pow, +{ + fn pow(self) -> Self { + self + } +} + +fn downcast<'a, W: ?Sized>() -> &'a W { + todo!() +} + +struct Other; + +fn main() { + let other: &mut Other = downcast();//~ERROR 28:29: 28:39: mismatched types [E0308] +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89275.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89275.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89275.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89275.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-89275.rs:28:29 + | +LL | let other: &mut Other = downcast(); + | ---------- ^^^^^^^^^^ types differ in mutability + | | + | expected due to this + | + = note: expected mutable reference `&mut Other` + found reference `&_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89935.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89935.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-89935.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-89935.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,18 @@ +// check-pass + +trait Foo: Baz {} +trait Bar {} +trait Baz: Bar { + fn bar(&self); +} + +impl Bar for T {} +impl Baz for T { + fn bar(&self) {} +} + +fn accept_foo(x: Box) { + x.bar(); +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +// edition:2021 + +mod m { + pub struct S { foo: i32 } + impl S { + pub fn foo(&self) -> i32 { 42 } + } +} + +fn bar(s: &m::S) { + || s.foo() + s.foo; //~ ERROR E0616 +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/issue-90483-inaccessible-field-adjustment.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +error[E0616]: field `foo` of struct `S` is private + --> $DIR/issue-90483-inaccessible-field-adjustment.rs:11:18 + | +LL | || s.foo() + s.foo; + | ^^^ private field + | +help: a method `foo` also exists, call it with parentheses + | +LL | || s.foo() + s.foo(); + | ++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0616`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/typeck-unsafe-always-share.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/typeck-unsafe-always-share.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeck/typeck-unsafe-always-share.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeck/typeck-unsafe-always-share.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/typeck-unsafe-always-share.rs:19:10 | LL | test(us); - | ^^ `UnsafeCell>` cannot be shared between threads safely + | ---- ^^ `UnsafeCell>` cannot be shared between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `UnsafeCell>` note: required by a bound in `test` @@ -15,7 +17,9 @@ --> $DIR/typeck-unsafe-always-share.rs:23:10 | LL | test(uns); - | ^^^ `UnsafeCell` cannot be shared between threads safely + | ---- ^^^ `UnsafeCell` cannot be shared between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `UnsafeCell` note: required by a bound in `test` @@ -46,7 +50,9 @@ --> $DIR/typeck-unsafe-always-share.rs:30:10 | LL | test(NoSync); - | ^^^^^^ `NoSync` cannot be shared between threads safely + | ---- ^^^^^^ `NoSync` cannot be shared between threads safely + | | + | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `NoSync` note: required by a bound in `test` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeclasses-eq-example.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeclasses-eq-example.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeclasses-eq-example.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeclasses-eq-example.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,7 +3,6 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(dead_code)] -#![feature(box_syntax)] // Example from lkuper's intern talk, August 2012. use Color::{cyan, magenta, yellow, black}; @@ -55,11 +54,11 @@ assert!(leaf(cyan).isEq(&leaf(cyan))); assert!(!leaf(cyan).isEq(&leaf(yellow))); - assert!(branch(box leaf(magenta), box leaf(cyan)) - .isEq(&branch(box leaf(magenta), box leaf(cyan)))); + assert!(branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))) + .isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))))); - assert!(!branch(box leaf(magenta), box leaf(cyan)) - .isEq(&branch(box leaf(magenta), box leaf(magenta)))); + assert!(!branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))) + .isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(magenta))))); println!("Assertions all succeeded!"); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeclasses-eq-example-static.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/typeclasses-eq-example-static.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeclasses-eq-example-static.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeclasses-eq-example-static.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,7 +3,6 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(dead_code)] -#![feature(box_syntax)] // Example from lkuper's intern talk, August 2012 -- now with static // methods! @@ -59,11 +58,11 @@ assert!(Equal::isEq(&leaf(cyan), &leaf(cyan))); assert!(!Equal::isEq(&leaf(cyan), &leaf(yellow))); - assert!(Equal::isEq(&branch(box leaf(magenta), box leaf(cyan)), - &branch(box leaf(magenta), box leaf(cyan)))); + assert!(Equal::isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))), + &branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))))); - assert!(!Equal::isEq(&branch(box leaf(magenta), box leaf(cyan)), - &branch(box leaf(magenta), box leaf(magenta)))); + assert!(!Equal::isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))), + &branch(Box::new(leaf(magenta)), Box::new(leaf(magenta))))); println!("Assertions all succeeded!"); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/typeof/type_mismatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/typeof/type_mismatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/typeof/type_mismatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/typeof/type_mismatch.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -15,7 +15,7 @@ help: change the type of the numeric literal from `i8` to `u8` | LL | let b: typeof(a) = 1u8; - | ~~~ + | ~~ error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/type-param-constraints.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/type-param-constraints.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/type-param-constraints.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/type-param-constraints.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,8 +4,6 @@ #![allow(dead_code)] // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn p_foo(_pinned: T) { } fn s_foo(_shared: T) { } fn u_foo(_unique: T) { } @@ -27,13 +25,13 @@ pub fn main() { p_foo(r(10)); - p_foo::>(box r(10)); - p_foo::>(box 10); + p_foo::>(Box::new(r(10))); + p_foo::>(Box::new(10)); p_foo(10); - s_foo::>(box 10); + s_foo::>(Box::new(10)); s_foo(10); - u_foo::>(box 10); + u_foo::>(Box::new(10)); u_foo(10); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-explicit-self-bad.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-explicit-self-bad.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-explicit-self-bad.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-explicit-self-bad.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,9 @@ -#![feature(box_syntax)] - struct Foo { f: isize, } + + impl Foo { fn foo(self: isize, x: isize) -> isize { //~^ ERROR invalid `self` parameter type @@ -48,12 +48,12 @@ } fn main() { - let foo = box Foo { + let foo = Box::new(Foo { f: 1, - }; + }); println!("{}", foo.foo(2)); - let bar = box Bar { + let bar = Box::new(Bar { f: 1, - }; + }); println!("{} {}", bar.foo(2), bar.bar(2)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -33,12 +33,12 @@ | = note: expected reference `&'a Bar` found reference `&Bar` -note: the anonymous lifetime defined on the method body at 37:21... +note: the anonymous lifetime defined here... --> $DIR/ufcs-explicit-self-bad.rs:37:21 | LL | fn dummy2(self: &Bar) {} | ^^^^^^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 35:6 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/ufcs-explicit-self-bad.rs:35:6 | LL | impl<'a, T> SomeTrait for &'a Bar { @@ -52,12 +52,12 @@ | = note: expected reference `&'a Bar` found reference `&Bar` -note: the lifetime `'a` as defined on the impl at 35:6... +note: the lifetime `'a` as defined here... --> $DIR/ufcs-explicit-self-bad.rs:35:6 | LL | impl<'a, T> SomeTrait for &'a Bar { | ^^ -note: ...does not necessarily outlive the anonymous lifetime defined on the method body at 37:21 +note: ...does not necessarily outlive the anonymous lifetime defined here --> $DIR/ufcs-explicit-self-bad.rs:37:21 | LL | fn dummy2(self: &Bar) {} @@ -71,12 +71,12 @@ | = note: expected reference `&'a Bar` found reference `&Bar` -note: the anonymous lifetime defined on the method body at 39:22... +note: the anonymous lifetime defined here... --> $DIR/ufcs-explicit-self-bad.rs:39:22 | LL | fn dummy3(self: &&Bar) {} | ^^^^^^^ -note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 35:6 +note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/ufcs-explicit-self-bad.rs:35:6 | LL | impl<'a, T> SomeTrait for &'a Bar { @@ -90,12 +90,12 @@ | = note: expected reference `&'a Bar` found reference `&Bar` -note: the lifetime `'a` as defined on the impl at 35:6... +note: the lifetime `'a` as defined here... --> $DIR/ufcs-explicit-self-bad.rs:35:6 | LL | impl<'a, T> SomeTrait for &'a Bar { | ^^ -note: ...does not necessarily outlive the anonymous lifetime defined on the method body at 39:22 +note: ...does not necessarily outlive the anonymous lifetime defined here --> $DIR/ufcs-explicit-self-bad.rs:39:22 | LL | fn dummy3(self: &&Bar) {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -20,7 +20,7 @@ help: change the type of the numeric literal from `u32` to `i32` | LL | >::add(1i32, 2); - | ~~~~ + | ~~~ error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:8:31 @@ -31,7 +31,7 @@ help: change the type of the numeric literal from `u32` to `i32` | LL | >::add(1, 2i32); - | ~~~~ + | ~~~ error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,10 @@ LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(|| drop(x)); - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | --------^- + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `Fn` closure error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:19:35 @@ -12,7 +15,10 @@ LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(|| drop(x)); - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | --------^- + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `FnMut` closure error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:28:36 @@ -20,7 +26,10 @@ LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(move || drop(x)); - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | -------------^- + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `Fn` closure error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:32:40 @@ -28,7 +37,10 @@ LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(move || drop(x)); - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | -------------^- + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `FnMut` closure error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-boxed.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-boxed.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-boxed.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-boxed.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] use std::ops::FnMut; fn make_adder(x: i32) -> Boxi32+'static> { - (box move |y: i32| -> i32 { x + y }) as + Box::new(move |y: i32| -> i32 { x + y }) as Boxi32+'static> } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/unboxed-closures-fnmut-as-fn.rs:28:21 | LL | let x = call_it(&S, 22); - | ^^ expected an `Fn<(isize,)>` closure, found `S` + | ------- ^^ expected an `Fn<(isize,)>` closure, found `S` + | | + | required by a bound introduced by this call | = help: the trait `Fn<(isize,)>` is not implemented for `S` note: required by a bound in `call_it` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ LL | x.set(y); | ^ | -note: ...the reference is valid for the anonymous lifetime #2 defined on the body at 16:14... +note: ...the reference is valid for the anonymous lifetime #2 defined here... --> $DIR/unboxed-closures-infer-argument-types-two-region-pointers.rs:16:14 | LL | doit(0, &|x, y| { @@ -12,7 +12,7 @@ LL | | x.set(y); LL | | }); | |_____^ -note: ...but the borrowed content is only valid for the anonymous lifetime #3 defined on the body at 16:14 +note: ...but the borrowed content is only valid for the anonymous lifetime #3 defined here --> $DIR/unboxed-closures-infer-argument-types-two-region-pointers.rs:16:14 | LL | doit(0, &|x, y| { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -7,7 +7,7 @@ help: change the type of the numeric literal from `usize` to `isize` | LL | let z = f(1_isize, 2); - | ~~~~~~~ + | ~~~~~ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21 | LL | let x = call_it(&square, 22); - | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` note: required by a bound in `call_it` @@ -15,7 +17,9 @@ --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25 | LL | let y = call_it_mut(&mut square, 22); - | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` note: required by a bound in `call_it_mut` @@ -28,7 +32,9 @@ --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26 | LL | let z = call_it_once(square, 22); - | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` note: required by a bound in `call_it_once` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/unboxed-closures-wrong-abi.rs:20:21 | LL | let x = call_it(&square, 22); - | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` + | ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` note: required by a bound in `call_it` @@ -15,7 +17,9 @@ --> $DIR/unboxed-closures-wrong-abi.rs:25:25 | LL | let y = call_it_mut(&mut square, 22); - | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` + | ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` note: required by a bound in `call_it_mut` @@ -28,7 +32,9 @@ --> $DIR/unboxed-closures-wrong-abi.rs:30:26 | LL | let z = call_it_once(square, 22); - | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` + | ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` note: required by a bound in `call_it_once` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21 | LL | let x = call_it(&square, 22); - | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` note: required by a bound in `call_it` @@ -15,7 +17,9 @@ --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25 | LL | let y = call_it_mut(&mut square, 22); - | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` note: required by a bound in `call_it_mut` @@ -28,7 +32,9 @@ --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26 | LL | let z = call_it_once(square, 22); - | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | | + | required by a bound introduced by this call | = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` note: required by a bound in `call_it_once` diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/underscore-imports/shadow.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/underscore-imports/shadow.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/underscore-imports/shadow.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/underscore-imports/shadow.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,8 +5,10 @@ | ^^^^^ method not found in `&()` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope; perhaps add a `use` for it: - `use std::ops::Deref;` +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use std::ops::Deref; + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/uninhabited/uninhabited-patterns.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/uninhabited/uninhabited-patterns.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/uninhabited/uninhabited-patterns.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/uninhabited/uninhabited-patterns.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,8 @@ #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(never_type)] #![feature(exhaustive_patterns)] + #![deny(unreachable_patterns)] mod foo { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/union/union-derive-clone.mirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/union/union-derive-clone.mirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/union/union-derive-clone.mirunsafeck.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/union/union-derive-clone.mirunsafeck.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -16,6 +16,10 @@ = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` which is required by `U5: Clone` +help: consider annotating `CloneNoCopy` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | error[E0277]: the trait bound `U1: Copy` is not satisfied --> $DIR/union-derive-clone.rs:6:10 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/union/union-derive-clone.thirunsafeck.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/union/union-derive-clone.thirunsafeck.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/union/union-derive-clone.thirunsafeck.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/union/union-derive-clone.thirunsafeck.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -16,6 +16,10 @@ = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` which is required by `U5: Clone` +help: consider annotating `CloneNoCopy` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | error[E0277]: the trait bound `U1: Copy` is not satisfied --> $DIR/union-derive-clone.rs:6:10 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-assign-copy.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-assign-copy.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-assign-copy.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-assign-copy.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let mut i: Box<_> = box 1; + let mut i: Box<_> = Box::new(1); // Should be a copy let mut j; j = i.clone(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-assign-drop.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-assign-drop.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-assign-drop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-assign-drop.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,9 @@ // run-pass #![allow(unused_assignments)] -#![feature(box_syntax)] - pub fn main() { - let i: Box<_> = box 1; - let mut j: Box<_> = box 2; + let i: Box<_> = Box::new(1); + let mut j: Box<_> = Box::new(2); // Should drop the previous value of j j = i; assert_eq!(*j, 1); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-assign-generic.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-assign-generic.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-assign-generic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-assign-generic.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn f(t: T) -> T { let t1 = t; @@ -7,6 +6,6 @@ } pub fn main() { - let t = f::>(box 100); - assert_eq!(t, box 100); + let t = f::>(Box::new(100)); + assert_eq!(t, Box::new(100)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-assign.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-assign.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-assign.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-assign.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,8 @@ // run-pass #![allow(unused_mut)] -#![feature(box_syntax)] pub fn main() { let mut i: Box<_>; - i = box 1; + i = Box::new(1); assert_eq!(*i, 1); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-autoderef-field.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-autoderef-field.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-autoderef-field.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-autoderef-field.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,10 @@ // run-pass -#![feature(box_syntax)] struct J { j: isize } pub fn main() { - let i: Box<_> = box J { + let i: Box<_> = Box::new(J { j: 100 - }; + }); assert_eq!(i.j, 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-autoderef-index.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-autoderef-index.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-autoderef-index.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-autoderef-index.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,6 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box vec![100]; + let i: Box<_> = Box::new(vec![100]); assert_eq!((*i)[0], 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-cmp.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-cmp.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-cmp.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-cmp.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,11 @@ // run-pass #![allow(unused_allocation)] -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; - assert_eq!(i, box 100); - assert!(i < box 101); - assert!(i <= box 100); - assert!(i > box 99); - assert!(i >= box 99); + let i: Box<_> = Box::new(100); + assert_eq!(i, Box::new(100)); + assert!(i < Box::new(101)); + assert!(i <= Box::new(100)); + assert!(i > Box::new(99)); + assert!(i >= Box::new(99)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-containing-tag.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-containing-tag.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-containing-tag.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-containing-tag.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,12 +4,10 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { enum t { t1(isize), t2(isize), } - let _x: Box<_> = box t::t1(10); + let _x: Box<_> = Box::new(t::t1(10)); /*alt *x { t1(a) { @@ -19,9 +17,9 @@ }*/ /*alt x { - box t1(a) { + Box::new(t1(a) { assert_eq!(a, 10); - } + }) _ { panic!(); } }*/ } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-create.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-create.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-create.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-create.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,10 +2,8 @@ #![allow(dead_code)] // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let _: Box<_> = box 100; + let _: Box<_> = Box::new(100); } fn vec() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-decl-init-copy.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-decl-init-copy.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-decl-init-copy.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-decl-init-copy.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let mut i: Box<_> = box 1; + let mut i: Box<_> = Box::new(1); // Should be a copy let mut j = i.clone(); *i = 2; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-decl-init.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-decl-init.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-decl-init.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-decl-init.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 1; + let i: Box<_> = Box::new(1); let j = i; assert_eq!(*j, 1); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-decl-move.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-decl-move.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-decl-move.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-decl-move.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; + let i: Box<_> = Box::new(100); let j = i; assert_eq!(*j, 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-deref.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-deref.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-deref.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-deref.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,6 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; + let i: Box<_> = Box::new(100); assert_eq!(*i, 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-destructure.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-destructure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-destructure.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-destructure.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,9 @@ // run-pass #![feature(box_patterns)] -#![feature(box_syntax)] struct Foo { a: isize, b: isize } pub fn main() { - let box Foo{a, b} = box Foo{a: 100, b: 200}; + let box Foo{ a, b } = Box::new(Foo { a: 100, b: 200 }); assert_eq!(a + b, 300); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-drop-complex.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-drop-complex.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-drop-complex.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-drop-complex.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let _x: Box<_> = box vec![0,0,0,0,0]; + let _x: Box<_> = Box::new(vec![0,0,0,0,0]); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg-move.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg-move.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg-move.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg-move.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,10 @@ // run-pass -#![feature(box_syntax)] fn f(i: Box) { assert_eq!(*i, 100); } pub fn main() { - let i = box 100; + let i = Box::new(100); f(i); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg-mut.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg-mut.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg-mut.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg-mut.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] fn f(i: &mut Box) { - *i = box 200; + *i = Box::new(200); } pub fn main() { - let mut i = box 100; + let mut i = Box::new(100); f(&mut i); assert_eq!(*i, 200); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-fn-arg.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] fn f(i: Box) { assert_eq!(*i, 100); } pub fn main() { - f(box 100); - let i = box 100; + f(Box::new(100)); + let i = Box::new(100); f(i); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-fn-ret.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-fn-ret.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-fn-ret.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-fn-ret.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] fn f() -> Box { - box 100 + Box::new(100) } pub fn main() { - assert_eq!(f(), box 100); + assert_eq!(f(), Box::new(100)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-init.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-init.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-init.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-init.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let _i: Box<_> = box 100; + let _i: Box<_> = Box::new(100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-in-tag.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-in-tag.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-in-tag.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-in-tag.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,12 +2,10 @@ #![allow(dead_code)] #![allow(non_camel_case_types)] -#![feature(box_syntax)] - fn test1() { enum bar { u(Box), w(isize), } - let x = bar::u(box 10); + let x = bar::u(Box::new(10)); assert!(match x { bar::u(a) => { println!("{}", a); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-in-vec-copy.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-in-vec-copy.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-in-vec-copy.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-in-vec-copy.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let mut a: Vec> = vec![box 10]; + let mut a: Vec> = vec![Box::new(10)]; let b = a.clone(); assert_eq!(*a[0], 10); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-in-vec.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-in-vec.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-in-vec.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-in-vec.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,6 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let vect : Vec> = vec![box 100]; - assert_eq!(vect[0], box 100); + let vect : Vec> = vec![Box::new(100)]; + assert_eq!(vect[0], Box::new(100)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-kinds.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-kinds.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-kinds.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-kinds.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] use std::cmp::PartialEq; use std::fmt::Debug; @@ -14,11 +13,11 @@ assert!(i != j); } - let i: Box<_> = box 100; - let j: Box<_> = box 100; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(100); f(i, j); - let i: Box<_> = box 100; - let j: Box<_> = box 101; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(101); g(i, j); } @@ -32,11 +31,11 @@ assert!(i != j); } - let i: Box<_> = box 100; - let j: Box<_> = box 100; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(100); f(i, j); - let i: Box<_> = box 100; - let j: Box<_> = box 101; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(101); g(i, j); } @@ -50,11 +49,11 @@ assert!(i != j); } - let i: Box<_> = box 100; - let j: Box<_> = box 100; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(100); f(i, j); - let i: Box<_> = box 100; - let j: Box<_> = box 101; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(101); g(i, j); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-log.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-log.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-log.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-log.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,6 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; + let i: Box<_> = Box::new(100); println!("{}", i); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-move-drop.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-move-drop.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-move-drop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-move-drop.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,10 @@ // run-pass #![allow(unused_variables)] -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; - let j: Box<_> = box 200; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(200); let j = i; assert_eq!(*j, 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-move.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-move.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-move.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-move.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,8 @@ // run-pass #![allow(unused_mut)] -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; + let i: Box<_> = Box::new(100); let mut j; j = i; assert_eq!(*j, 100); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-move-temp.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-move-temp.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-move-temp.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-move-temp.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,8 @@ // run-pass #![allow(unused_mut)] -#![feature(box_syntax)] pub fn main() { let mut i: Box<_>; - i = box 100; + i = Box::new(100); assert_eq!(*i, 100); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-mutable.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-mutable.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-mutable.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-mutable.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let mut i: Box<_> = box 0; + let mut i: Box<_> = Box::new(0); *i = 1; assert_eq!(*i, 1); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-object-move.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-object-move.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-object-move.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-object-move.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,8 +4,6 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub trait EventLoop { fn foo(&self) {} } pub struct UvEventLoop { @@ -15,6 +13,6 @@ impl EventLoop for UvEventLoop { } pub fn main() { - let loop_: Box = box UvEventLoop { uvio: 0 } as Box; + let loop_: Box = Box::new(UvEventLoop { uvio: 0 }) as Box; let _loop2_ = loop_; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-pat-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-pat-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-pat-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-pat-2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,15 +4,15 @@ #![allow(non_shorthand_field_patterns)] #![feature(box_patterns)] -#![feature(box_syntax)] struct Foo {a: isize, b: usize} enum bar { u(Box), w(isize), } pub fn main() { - assert!(match bar::u(box Foo{a: 10, b: 40}) { - bar::u(box Foo{a: a, b: b}) => { a + (b as isize) } - _ => { 66 } - } == 50); + let v = match bar::u(Box::new(Foo{ a: 10, b: 40 })) { + bar::u(box Foo{ a: a, b: b }) => { a + (b as isize) } + _ => { 66 } + }; + assert_eq!(v, 50); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-pat-3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-pat-3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-pat-3.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-pat-3.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,16 +2,15 @@ #![allow(dead_code)] #![allow(non_camel_case_types)] -#![feature(box_syntax)] - enum bar { u(Box), w(isize), } pub fn main() { - assert!(match bar::u(box 10) { - bar::u(a) => { - println!("{}", a); - *a - } - _ => { 66 } - } == 10); + let v = match bar::u(10.into()) { + bar::u(a) => { + println!("{}", a); + *a + } + _ => { 66 } + }; + assert_eq!(v, 10); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-pat.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-pat.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-pat.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-pat.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,9 @@ // run-pass #![feature(box_patterns)] -#![feature(box_syntax)] fn simple() { - match box true { + match Box::new(true) { box true => { } _ => { panic!(); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-rec.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-rec.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-rec.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-rec.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] struct X { x: isize } pub fn main() { - let x: Box<_> = box X {x: 1}; + let x: Box<_> = Box::new(X {x: 1}); let bar = x; assert_eq!(bar.x, 1); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-send-2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-send-2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-send-2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-send-2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,13 +2,11 @@ #![allow(unused_must_use)] // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::sync::mpsc::{channel, Sender}; use std::thread; fn child(tx: &Sender>, i: usize) { - tx.send(box i).unwrap(); + tx.send(Box::new(i)).unwrap(); } pub fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-send.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-send.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-send.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-send.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,10 @@ // run-pass -#![feature(box_syntax)] use std::sync::mpsc::channel; pub fn main() { let (tx, rx) = channel::>(); - tx.send(box 100).unwrap(); + tx.send(Box::new(100)).unwrap(); let v = rx.recv().unwrap(); - assert_eq!(v, box 100); + assert_eq!(v, Box::new(100)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-swap.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-swap.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique/unique-swap.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique/unique-swap.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] use std::mem::swap; pub fn main() { - let mut i: Box<_> = box 100; - let mut j: Box<_> = box 200; + let mut i: Box<_> = Box::new(100); + let mut j: Box<_> = Box::new(200); swap(&mut i, &mut j); - assert_eq!(i, box 200); - assert_eq!(j, box 100); + assert_eq!(i, Box::new(200)); + assert_eq!(j, Box::new(100)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique-object-noncopyable.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unique-object-noncopyable.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique-object-noncopyable.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique-object-noncopyable.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - trait Foo { fn f(&self); } @@ -18,8 +16,10 @@ } } + + fn main() { - let x = box Bar { x: 10 }; + let x = Box::new(Bar { x: 10 }); let y: Box = x as Box; let _z = y.clone(); //~ ERROR the method } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unique-pinned-nocopy.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unique-pinned-nocopy.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unique-pinned-nocopy.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unique-pinned-nocopy.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -21,6 +21,10 @@ = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` +help: consider annotating `R` with `#[derive(Clone)]` + | +LL | #[derive(Clone)] + | error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unop-move-semantics.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unop-move-semantics.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unop-move-semantics.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unop-move-semantics.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -7,7 +7,7 @@ | -- `x` moved due to usage in operator LL | LL | x.clone(); - | ^ value borrowed here after move + | ^^^^^^^^^ value borrowed here after move | note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/inline_asm.mir.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/inline_asm.mir.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/inline_asm.mir.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/inline_asm.mir.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/inline_asm.rs:10:5 | LL | asm!("nop"); - | ^^^^^^^^^^^^ use of inline assembly + | ^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior @@ -10,7 +10,7 @@ --> $DIR/inline_asm.rs:11:5 | LL | llvm_asm!("nop"); - | ^^^^^^^^^^^^^^^^^ use of inline assembly + | ^^^^^^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/inline_asm.thir.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/inline_asm.thir.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/inline_asm.thir.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/inline_asm.thir.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/inline_asm.rs:10:5 | LL | asm!("nop"); - | ^^^^^^^^^^^^ use of inline assembly + | ^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior @@ -10,7 +10,7 @@ --> $DIR/inline_asm.rs:11:5 | LL | llvm_asm!("nop"); - | ^^^^^^^^^^^^^^^^^ use of inline assembly + | ^^^^^^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.mir.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.mir.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.mir.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.mir.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,35 @@ +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | let f = |v: &mut Vec<_>| { +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | |w: &mut Vec| { unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | |x: &mut Vec| { unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,28 @@ +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + +#[deny(unused_unsafe)] +fn main() { + let mut v = Vec::::with_capacity(24); + + unsafe { + let f = |v: &mut Vec<_>| { + unsafe { //~ ERROR unnecessary `unsafe` + v.set_len(24); + |w: &mut Vec| { unsafe { //~ ERROR unnecessary `unsafe` + w.set_len(32); + } }; + } + |x: &mut Vec| { unsafe { //~ ERROR unnecessary `unsafe` + x.set_len(40); + } }; + }; + + v.set_len(0); + f(&mut v); + } + + |y: &mut Vec| { unsafe { + y.set_len(48); + } }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,35 @@ +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | let f = |v: &mut Vec<_>| { +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | |w: &mut Vec| { unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | |x: &mut Vec| { unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized/unsized2.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized/unsized2.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized/unsized2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized/unsized2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,6 @@ #![allow(dead_code)] #![allow(unused_variables)] #![allow(unused_imports)] -#![feature(box_syntax)] // Test sized-ness checking in substitution. @@ -36,7 +35,7 @@ struct S; impl T2 for S { fn f() -> Box { - box S + Box::new(S) } } fn f5(x: &X) { @@ -51,7 +50,7 @@ } impl T3 for S { fn f() -> Box { - box S + Box::new(S) } } fn f7(x: &X) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized/unsized3-rpass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized/unsized3-rpass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized/unsized3-rpass.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized/unsized3-rpass.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ // Test structs with always-unsized fields. #![allow(warnings)] -#![feature(box_syntax, unsize, ptr_metadata)] +#![feature(unsize, ptr_metadata)] use std::mem; use std::ptr; @@ -58,7 +58,7 @@ f: [T; 3], } - let data: Box> = box Foo_ { f: [1, 2, 3] }; + let data: Box> = Box::new(Foo_ { f: [1, 2, 3] }); let x: &Foo = mem::transmute(slice::from_raw_parts(&*data, 3)); assert_eq!(x.f.len(), 3); assert_eq!(x.f[0], 1); @@ -69,7 +69,7 @@ } let data: Box<_> = - box Baz_ { f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] }; + Box::new(Baz_ { f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] }); let x: &Baz = mem::transmute(slice::from_raw_parts(&*data, 5)); assert_eq!(x.f1, 42); let chs: Vec = x.f2.chars().collect(); @@ -84,9 +84,9 @@ f: St, } - let obj: Box = box St { f: 42 }; + let obj: Box = Box::new(St { f: 42 }); let obj: &Tr = &*obj; - let data: Box<_> = box Qux_ { f: St { f: 234 } }; + let data: Box<_> = Box::new(Qux_ { f: St { f: 234 } }); let x: &Qux = &*ptr::from_raw_parts::((&*data as *const _).cast(), ptr::metadata(obj)); assert_eq!(x.f.foo(), 234); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized/unsized3.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized/unsized3.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized/unsized3.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized/unsized3.rs 2021-11-29 19:27:12.000000000 +0000 @@ -44,8 +44,6 @@ fn f10(x1: Box>) { f5(&(32, *x1)); //~^ ERROR the size for values of type - //~| ERROR the size for values of type } -pub fn main() { -} +pub fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized/unsized3.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized/unsized3.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized/unsized3.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized/unsized3.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,9 @@ LL | fn f1(x: &X) { | - this type parameter needs to be `std::marker::Sized` LL | f2::(x); - | ^ doesn't have a size known at compile-time + | ------- ^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required by a bound in `f2` --> $DIR/unsized3.rs:10:7 @@ -27,7 +29,9 @@ LL | fn f3(x: &X) { | - this type parameter needs to be `std::marker::Sized` LL | f4::(x); - | ^ doesn't have a size known at compile-time + | ------- ^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required by a bound in `f4` --> $DIR/unsized3.rs:21:7 @@ -50,7 +54,9 @@ LL | fn f8(x1: &S, x2: &S) { | - this type parameter needs to be `std::marker::Sized` LL | f5(x1); - | ^^ doesn't have a size known at compile-time + | -- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required because it appears within the type `S` --> $DIR/unsized3.rs:28:8 @@ -78,7 +84,9 @@ LL | fn f9(x1: Box>) { | - this type parameter needs to be `std::marker::Sized` LL | f5(&(*x1, 34)); - | ^^^^^^^^^^ doesn't have a size known at compile-time + | -- ^^^^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required because it appears within the type `S` --> $DIR/unsized3.rs:28:8 @@ -93,33 +101,14 @@ | error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized3.rs:45:9 - | -LL | fn f10(x1: Box>) { - | - this type parameter needs to be `std::marker::Sized` -LL | f5(&(32, *x1)); - | ^^^^^^^^^ doesn't have a size known at compile-time - | -note: required because it appears within the type `S` - --> $DIR/unsized3.rs:28:8 - | -LL | struct S { - | ^ - = note: required because it appears within the type `({integer}, S)` - = note: tuples must have a statically known size to be initialized -help: consider removing the `?Sized` bound to make the type parameter `Sized` - | -LL - fn f10(x1: Box>) { -LL + fn f10(x1: Box>) { - | - -error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:45:8 | LL | fn f10(x1: Box>) { | - this type parameter needs to be `std::marker::Sized` LL | f5(&(32, *x1)); - | ^^^^^^^^^^ doesn't have a size known at compile-time + | -- ^^^^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required because it appears within the type `S` --> $DIR/unsized3.rs:28:8 @@ -127,21 +116,13 @@ LL | struct S { | ^ = note: required because it appears within the type `({integer}, S)` -note: required by a bound in `f5` - --> $DIR/unsized3.rs:24:7 - | -LL | fn f5(x: &Y) {} - | ^ required by this bound in `f5` + = note: tuples must have a statically known size to be initialized help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f10(x1: Box>) { LL + fn f10(x1: Box>) { | -help: consider relaxing the implicit `Sized` restriction - | -LL | fn f5(x: &Y) {} - | ++++++++ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized-locals/unsized-exprs.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized-locals/unsized-exprs.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unsized-locals/unsized-exprs.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unsized-locals/unsized-exprs.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -12,9 +12,11 @@ --> $DIR/unsized-exprs.rs:24:22 | LL | udrop::>(A { 0: *foo() }); - | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ---------------- ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | - = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `A<[u8]>` --> $DIR/unsized-exprs.rs:3:8 | diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unused-move-capture.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unused-move-capture.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unused-move-capture.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unused-move-capture.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let _x: Box<_> = box 1; + let _x: Box<_> = Box::new(1); let lam_move = || {}; lam_move(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unused-move.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unused-move.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unused-move.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unused-move.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,10 +6,8 @@ // pretty-expanded FIXME #23616 #![allow(path_statements)] -#![feature(box_syntax)] -pub fn main() -{ - let y: Box<_> = box 1; +pub fn main() { + let y: Box<_> = Box::new(1); y; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/unwind-unique.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/unwind-unique.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/unwind-unique.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/unwind-unique.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,10 @@ // run-pass // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; fn f() { - let _a: Box<_> = box 0; + let _a: Box<_> = Box::new(0); panic!(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/use/use-after-move-implicity-coerced-object.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/use/use-after-move-implicity-coerced-object.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/use/use-after-move-implicity-coerced-object.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/use/use-after-move-implicity-coerced-object.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - use std::fmt; struct Number { @@ -22,9 +20,11 @@ } fn main() { - let n: Box<_> = box Number { n: 42 }; - let mut l: Box<_> = box List { list: Vec::new() }; + + let n: Box<_> = Number { n: 42 }.into(); + let mut l: Box<_> = List { list: Vec::new() }.into(); l.push(n); + let x = n.to_string(); //~^ ERROR: borrow of moved value: `n` } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/use/use-after-move-implicity-coerced-object.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/use/use-after-move-implicity-coerced-object.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/use/use-after-move-implicity-coerced-object.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/use/use-after-move-implicity-coerced-object.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,13 +1,14 @@ error[E0382]: borrow of moved value: `n` --> $DIR/use-after-move-implicity-coerced-object.rs:28:13 | -LL | let n: Box<_> = box Number { n: 42 }; +LL | let n: Box<_> = Number { n: 42 }.into(); | - move occurs because `n` has type `Box`, which does not implement the `Copy` trait -LL | let mut l: Box<_> = box List { list: Vec::new() }; +LL | let mut l: Box<_> = List { list: Vec::new() }.into(); LL | l.push(n); | - value moved here +LL | LL | let x = n.to_string(); - | ^ value borrowed here after move + | ^^^^^^^^^^^^^ value borrowed here after move error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/use/use-after-move-self.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/use/use-after-move-self.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/use/use-after-move-self.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/use/use-after-move-self.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,9 @@ -#![feature(box_syntax)] - struct S { x: Box, } + + impl S { pub fn foo(self) -> isize { self.bar(); @@ -14,6 +14,6 @@ } fn main() { - let x = S { x: box 1 }; + let x = S { x: 1.into() }; println!("{}", x.foo()); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/use/use-from-trait-xc.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/use/use-from-trait-xc.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/use/use-from-trait-xc.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/use/use-from-trait-xc.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -38,7 +38,7 @@ --> $DIR/use-from-trait-xc.rs:23:5 | LL | use use_from_trait_xc::Baz::new as baznew; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `new` in `Baz` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `new` in `sub::Baz` error[E0603]: struct `Foo` is private --> $DIR/use-from-trait-xc.rs:14:24 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/use-self-in-inner-fn.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/use-self-in-inner-fn.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/use-self-in-inner-fn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/use-self-in-inner-fn.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -struct A; - -impl A { -//~^ NOTE `Self` type implicitly declared here, by this `impl` - fn banana(&mut self) { - fn peach(this: &Self) { - //~^ ERROR can't use generic parameters from outer function - //~| NOTE use of generic parameter from outer function - //~| NOTE use a type here instead - } - } -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/use-self-in-inner-fn.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/use-self-in-inner-fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/use-self-in-inner-fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/use-self-in-inner-fn.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -error[E0401]: can't use generic parameters from outer function - --> $DIR/use-self-in-inner-fn.rs:6:25 - | -LL | impl A { - | ---- `Self` type implicitly declared here, by this `impl` -... -LL | fn peach(this: &Self) { - | ^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0401`. diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-associated-types2.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-associated-types2.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-associated-types2.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-associated-types2.nll.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,8 +5,6 @@ | -- lifetime `'a` defined here LL | let _: Box> = make(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-associated-types2.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-associated-types2.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-associated-types2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-associated-types2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected trait object `dyn Foo` found trait object `dyn Foo` -note: the lifetime `'a` as defined on the function body at 12:9... +note: the lifetime `'a` as defined here... --> $DIR/variance-associated-types2.rs:12:9 | LL | fn take<'a>(_: &'a u32) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-btree-invariant-types.nll.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-btree-invariant-types.nll.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-btree-invariant-types.nll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-btree-invariant-types.nll.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,8 +5,6 @@ | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:7:5 @@ -15,8 +13,6 @@ | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:10:5 @@ -25,8 +21,6 @@ | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:13:5 @@ -35,8 +29,6 @@ | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:17:5 @@ -45,8 +37,6 @@ | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:20:5 @@ -55,8 +45,6 @@ | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:23:5 @@ -65,8 +53,6 @@ | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:26:5 @@ -75,8 +61,6 @@ | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:31:5 @@ -86,8 +70,6 @@ LL | -> OccupiedEntry<'a, &'new (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:35:5 @@ -97,8 +79,6 @@ LL | -> OccupiedEntry<'a, (), &'new ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:39:5 @@ -108,8 +88,6 @@ LL | -> OccupiedEntry<'a, &'static (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:43:5 @@ -119,8 +97,6 @@ LL | -> OccupiedEntry<'a, (), &'static ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:48:5 @@ -130,8 +106,6 @@ LL | -> VacantEntry<'a, &'new (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:52:5 @@ -141,8 +115,6 @@ LL | -> VacantEntry<'a, (), &'new ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:56:5 @@ -152,8 +124,6 @@ LL | -> VacantEntry<'a, &'static (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:60:5 @@ -163,8 +133,6 @@ LL | -> VacantEntry<'a, (), &'static ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: aborting due to 16 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-btree-invariant-types.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-btree-invariant-types.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-btree-invariant-types.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-btree-invariant-types.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected struct `std::collections::btree_map::IterMut<'_, &'new (), _>` found struct `std::collections::btree_map::IterMut<'_, &'static (), _>` -note: the lifetime `'new` as defined on the function body at 3:21... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:3:21 | LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> { @@ -21,7 +21,7 @@ | = note: expected struct `std::collections::btree_map::IterMut<'_, _, &'new ()>` found struct `std::collections::btree_map::IterMut<'_, _, &'static ()>` -note: the lifetime `'new` as defined on the function body at 6:21... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:6:21 | LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> { @@ -36,7 +36,7 @@ | = note: expected struct `std::collections::btree_map::IterMut<'_, &'static (), _>` found struct `std::collections::btree_map::IterMut<'_, &'new (), _>` -note: the lifetime `'new` as defined on the function body at 9:24... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:9:24 | LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> { @@ -51,7 +51,7 @@ | = note: expected struct `std::collections::btree_map::IterMut<'_, _, &'static ()>` found struct `std::collections::btree_map::IterMut<'_, _, &'new ()>` -note: the lifetime `'new` as defined on the function body at 12:24... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:12:24 | LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> { @@ -66,7 +66,7 @@ | = note: expected struct `RangeMut<'_, &'new (), _>` found struct `RangeMut<'_, &'static (), _>` -note: the lifetime `'new` as defined on the function body at 16:22... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:16:22 | LL | fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a, &'new (), ()> { @@ -81,7 +81,7 @@ | = note: expected struct `RangeMut<'_, _, &'new ()>` found struct `RangeMut<'_, _, &'static ()>` -note: the lifetime `'new` as defined on the function body at 19:22... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:19:22 | LL | fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a, (), &'new ()> { @@ -96,7 +96,7 @@ | = note: expected struct `RangeMut<'_, &'static (), _>` found struct `RangeMut<'_, &'new (), _>` -note: the lifetime `'new` as defined on the function body at 22:25... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:22:25 | LL | fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a, &'static (), ()> { @@ -111,7 +111,7 @@ | = note: expected struct `RangeMut<'_, _, &'static ()>` found struct `RangeMut<'_, _, &'new ()>` -note: the lifetime `'new` as defined on the function body at 25:25... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:25:25 | LL | fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a, (), &'static ()> { @@ -126,7 +126,7 @@ | = note: expected struct `std::collections::btree_map::OccupiedEntry<'_, &'new (), _>` found struct `std::collections::btree_map::OccupiedEntry<'_, &'static (), _>` -note: the lifetime `'new` as defined on the function body at 29:20... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:29:20 | LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>) @@ -141,7 +141,7 @@ | = note: expected struct `std::collections::btree_map::OccupiedEntry<'_, _, &'new ()>` found struct `std::collections::btree_map::OccupiedEntry<'_, _, &'static ()>` -note: the lifetime `'new` as defined on the function body at 33:20... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:33:20 | LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>) @@ -156,7 +156,7 @@ | = note: expected struct `std::collections::btree_map::OccupiedEntry<'_, &'static (), _>` found struct `std::collections::btree_map::OccupiedEntry<'_, &'new (), _>` -note: the lifetime `'new` as defined on the function body at 37:23... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:37:23 | LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>) @@ -171,7 +171,7 @@ | = note: expected struct `std::collections::btree_map::OccupiedEntry<'_, _, &'static ()>` found struct `std::collections::btree_map::OccupiedEntry<'_, _, &'new ()>` -note: the lifetime `'new` as defined on the function body at 41:23... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:41:23 | LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>) @@ -186,7 +186,7 @@ | = note: expected struct `std::collections::btree_map::VacantEntry<'_, &'new (), _>` found struct `std::collections::btree_map::VacantEntry<'_, &'static (), _>` -note: the lifetime `'new` as defined on the function body at 46:20... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:46:20 | LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>) @@ -201,7 +201,7 @@ | = note: expected struct `std::collections::btree_map::VacantEntry<'_, _, &'new ()>` found struct `std::collections::btree_map::VacantEntry<'_, _, &'static ()>` -note: the lifetime `'new` as defined on the function body at 50:20... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:50:20 | LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>) @@ -216,7 +216,7 @@ | = note: expected struct `std::collections::btree_map::VacantEntry<'_, &'static (), _>` found struct `std::collections::btree_map::VacantEntry<'_, &'new (), _>` -note: the lifetime `'new` as defined on the function body at 54:23... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:54:23 | LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>) @@ -231,7 +231,7 @@ | = note: expected struct `std::collections::btree_map::VacantEntry<'_, _, &'static ()>` found struct `std::collections::btree_map::VacantEntry<'_, _, &'new ()>` -note: the lifetime `'new` as defined on the function body at 58:23... +note: the lifetime `'new` as defined here... --> $DIR/variance-btree-invariant-types.rs:58:23 | LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-arg-object.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-arg-object.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-arg-object.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-arg-object.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected trait object `dyn Get<&'min i32>` found trait object `dyn Get<&'max i32>` -note: the lifetime `'min` as defined on the function body at 10:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-contravariant-arg-object.rs:10:21 | LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-contravariant-arg-object.rs:10:27 | LL | fn get_min_from_max<'min, 'max>(v: Box>) @@ -25,12 +25,12 @@ | = note: expected trait object `dyn Get<&'max i32>` found trait object `dyn Get<&'min i32>` -note: the lifetime `'min` as defined on the function body at 17:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-contravariant-arg-object.rs:17:21 | LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 17:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-contravariant-arg-object.rs:17:27 | LL | fn get_max_from_min<'min, 'max, G>(v: Box>) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected type `Get<&'min i32>` found type `Get<&'max i32>` -note: the lifetime `'min` as defined on the function body at 10:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-contravariant-arg-trait-match.rs:10:21 | LL | fn get_min_from_max<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-contravariant-arg-trait-match.rs:10:27 | LL | fn get_min_from_max<'min, 'max, G>() @@ -25,12 +25,12 @@ | = note: expected type `Get<&'max i32>` found type `Get<&'min i32>` -note: the lifetime `'min` as defined on the function body at 16:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-contravariant-arg-trait-match.rs:16:21 | LL | fn get_max_from_min<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 16:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-contravariant-arg-trait-match.rs:16:27 | LL | fn get_max_from_min<'min, 'max, G>() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-self-trait-match.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-self-trait-match.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-self-trait-match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-contravariant-self-trait-match.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,14 +4,14 @@ LL | impls_get::<&'min G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Get` - found type `Get` -note: the lifetime `'min` as defined on the function body at 10:21... + = note: expected type `<&'min G as Get>` + found type `<&'max G as Get>` +note: the lifetime `'min` as defined here... --> $DIR/variance-contravariant-self-trait-match.rs:10:21 | LL | fn get_min_from_max<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-contravariant-self-trait-match.rs:10:27 | LL | fn get_min_from_max<'min, 'max, G>() @@ -23,14 +23,14 @@ LL | impls_get::<&'max G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Get` - found type `Get` -note: the lifetime `'min` as defined on the function body at 16:21... + = note: expected type `<&'max G as Get>` + found type `<&'min G as Get>` +note: the lifetime `'min` as defined here... --> $DIR/variance-contravariant-self-trait-match.rs:16:21 | LL | fn get_max_from_min<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 16:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-contravariant-self-trait-match.rs:16:27 | LL | fn get_max_from_min<'min, 'max, G>() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-arg-object.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-arg-object.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-arg-object.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-arg-object.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected trait object `dyn Get<&'min i32>` found trait object `dyn Get<&'max i32>` -note: the lifetime `'min` as defined on the function body at 10:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-covariant-arg-object.rs:10:21 | LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-covariant-arg-object.rs:10:27 | LL | fn get_min_from_max<'min, 'max>(v: Box>) @@ -25,12 +25,12 @@ | = note: expected trait object `dyn Get<&'max i32>` found trait object `dyn Get<&'min i32>` -note: the lifetime `'min` as defined on the function body at 18:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-covariant-arg-object.rs:18:21 | LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 18:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-covariant-arg-object.rs:18:27 | LL | fn get_max_from_min<'min, 'max, G>(v: Box>) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-arg-trait-match.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-arg-trait-match.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-arg-trait-match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-arg-trait-match.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected type `Get<&'min i32>` found type `Get<&'max i32>` -note: the lifetime `'min` as defined on the function body at 10:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-covariant-arg-trait-match.rs:10:21 | LL | fn get_min_from_max<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-covariant-arg-trait-match.rs:10:27 | LL | fn get_min_from_max<'min, 'max, G>() @@ -25,12 +25,12 @@ | = note: expected type `Get<&'max i32>` found type `Get<&'min i32>` -note: the lifetime `'min` as defined on the function body at 17:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-covariant-arg-trait-match.rs:17:21 | LL | fn get_max_from_min<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 17:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-covariant-arg-trait-match.rs:17:27 | LL | fn get_max_from_min<'min, 'max, G>() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-self-trait-match.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-self-trait-match.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-self-trait-match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-covariant-self-trait-match.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,14 +4,14 @@ LL | impls_get::<&'min G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Get` - found type `Get` -note: the lifetime `'min` as defined on the function body at 10:21... + = note: expected type `<&'min G as Get>` + found type `<&'max G as Get>` +note: the lifetime `'min` as defined here... --> $DIR/variance-covariant-self-trait-match.rs:10:21 | LL | fn get_min_from_max<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-covariant-self-trait-match.rs:10:27 | LL | fn get_min_from_max<'min, 'max, G>() @@ -23,14 +23,14 @@ LL | impls_get::<&'max G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Get` - found type `Get` -note: the lifetime `'min` as defined on the function body at 17:21... + = note: expected type `<&'max G as Get>` + found type `<&'min G as Get>` +note: the lifetime `'min` as defined here... --> $DIR/variance-covariant-self-trait-match.rs:17:21 | LL | fn get_max_from_min<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 17:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-covariant-self-trait-match.rs:17:27 | LL | fn get_max_from_min<'min, 'max, G>() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-arg-object.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-arg-object.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-arg-object.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-arg-object.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected trait object `dyn Get<&'min i32>` found trait object `dyn Get<&'max i32>` -note: the lifetime `'min` as defined on the function body at 7:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-invariant-arg-object.rs:7:21 | LL | fn get_min_from_max<'min, 'max>(v: Box>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 7:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-invariant-arg-object.rs:7:27 | LL | fn get_min_from_max<'min, 'max>(v: Box>) @@ -25,12 +25,12 @@ | = note: expected trait object `dyn Get<&'max i32>` found trait object `dyn Get<&'min i32>` -note: the lifetime `'min` as defined on the function body at 14:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-invariant-arg-object.rs:14:21 | LL | fn get_max_from_min<'min, 'max, G>(v: Box>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 14:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-invariant-arg-object.rs:14:27 | LL | fn get_max_from_min<'min, 'max, G>(v: Box>) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-arg-trait-match.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-arg-trait-match.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-arg-trait-match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-arg-trait-match.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected type `Get<&'min i32>` found type `Get<&'max i32>` -note: the lifetime `'min` as defined on the function body at 7:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-invariant-arg-trait-match.rs:7:21 | LL | fn get_min_from_max<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 7:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-invariant-arg-trait-match.rs:7:27 | LL | fn get_min_from_max<'min, 'max, G>() @@ -25,12 +25,12 @@ | = note: expected type `Get<&'max i32>` found type `Get<&'min i32>` -note: the lifetime `'min` as defined on the function body at 13:21... +note: the lifetime `'min` as defined here... --> $DIR/variance-invariant-arg-trait-match.rs:13:21 | LL | fn get_max_from_min<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 13:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-invariant-arg-trait-match.rs:13:27 | LL | fn get_max_from_min<'min, 'max, G>() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-self-trait-match.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-self-trait-match.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-self-trait-match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-invariant-self-trait-match.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,14 +4,14 @@ LL | impls_get::<&'min G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Get` - found type `Get` -note: the lifetime `'min` as defined on the function body at 7:21... + = note: expected type `<&'min G as Get>` + found type `<&'max G as Get>` +note: the lifetime `'min` as defined here... --> $DIR/variance-invariant-self-trait-match.rs:7:21 | LL | fn get_min_from_max<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 7:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-invariant-self-trait-match.rs:7:27 | LL | fn get_min_from_max<'min, 'max, G>() @@ -23,14 +23,14 @@ LL | impls_get::<&'max G>(); | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected type `Get` - found type `Get` -note: the lifetime `'min` as defined on the function body at 13:21... + = note: expected type `<&'max G as Get>` + found type `<&'min G as Get>` +note: the lifetime `'min` as defined here... --> $DIR/variance-invariant-self-trait-match.rs:13:21 | LL | fn get_max_from_min<'min, 'max, G>() | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 13:27 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-invariant-self-trait-match.rs:13:27 | LL | fn get_max_from_min<'min, 'max, G>() diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-use-contravariant-struct-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-use-contravariant-struct-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-use-contravariant-struct-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-use-contravariant-struct-1.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `SomeStruct<&'min ()>` found struct `SomeStruct<&'max ()>` -note: the lifetime `'min` as defined on the function body at 8:8... +note: the lifetime `'min` as defined here... --> $DIR/variance-use-contravariant-struct-1.rs:8:8 | LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 8:13 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-use-contravariant-struct-1.rs:8:13 | LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-use-covariant-struct-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-use-covariant-struct-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-use-covariant-struct-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-use-covariant-struct-1.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `SomeStruct<&'max ()>` found struct `SomeStruct<&'min ()>` -note: the lifetime `'min` as defined on the function body at 6:8... +note: the lifetime `'min` as defined here... --> $DIR/variance-use-covariant-struct-1.rs:6:8 | LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 6:13 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-use-covariant-struct-1.rs:6:13 | LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-use-invariant-struct-1.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-use-invariant-struct-1.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/variance/variance-use-invariant-struct-1.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/variance/variance-use-invariant-struct-1.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,12 +6,12 @@ | = note: expected struct `SomeStruct<&'min ()>` found struct `SomeStruct<&'max ()>` -note: the lifetime `'min` as defined on the function body at 8:8... +note: the lifetime `'min` as defined here... --> $DIR/variance-use-invariant-struct-1.rs:8:8 | LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 8:13 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-use-invariant-struct-1.rs:8:13 | LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) @@ -25,12 +25,12 @@ | = note: expected struct `SomeStruct<&'max ()>` found struct `SomeStruct<&'min ()>` -note: the lifetime `'min` as defined on the function body at 15:8... +note: the lifetime `'min` as defined here... --> $DIR/variance-use-invariant-struct-1.rs:15:8 | LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>) | ^^^^ -note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 15:13 +note: ...does not necessarily outlive the lifetime `'max` as defined here --> $DIR/variance-use-invariant-struct-1.rs:15:13 | LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/vtable-res-trait-param.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/vtable-res-trait-param.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/vtable-res-trait-param.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/vtable-res-trait-param.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/vtable-res-trait-param.rs:17:18 | LL | b.gimme_an_a(y) - | ^ the trait `TraitA` is not implemented for `{integer}` + | ---------- ^ the trait `TraitA` is not implemented for `{integer}` + | | + | required by a bound introduced by this call error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/wasm/simd-to-array-80108.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/wasm/simd-to-array-80108.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/wasm/simd-to-array-80108.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/wasm/simd-to-array-80108.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,15 @@ +// only-wasm32 +// compile-flags: --crate-type=lib -Copt-level=2 +// build-pass +#![feature(repr_simd)] + +// Regression test for #80108 + +#[repr(simd)] +pub struct Vector([i32; 4]); + +impl Vector { + pub const fn to_array(self) -> [i32; 4] { + self.0 + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/weak-new-uninhabited-issue-48493.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/weak-new-uninhabited-issue-48493.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/weak-new-uninhabited-issue-48493.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/weak-new-uninhabited-issue-48493.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,6 +2,6 @@ fn main() { enum Void {} - std::rc::Weak::::new(); - std::sync::Weak::::new(); + let _ = std::rc::Weak::::new(); + let _ = std::sync::Weak::::new(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/hir-wf-check-erase-regions.rs rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/hir-wf-check-erase-regions.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/hir-wf-check-erase-regions.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/hir-wf-check-erase-regions.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ // Regression test for #87549. -// compile-flags: -C incremental=tmp/wf/hir-wf-check-erase-regions +// incremental pub struct Table([Option; N]); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/issue-87495.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/issue-87495.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/issue-87495.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/issue-87495.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,6 @@ LL | const CONST: (bool, dyn T); | ^^^^^ `T` cannot be made into an object | - = help: consider moving `CONST` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-87495.rs:4:11 | @@ -12,6 +11,7 @@ | - this trait cannot be made into an object... LL | const CONST: (bool, dyn T); | ^^^^^ ...because it contains this associated `const` + = help: consider moving `CONST` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -17,7 +17,7 @@ | LL | pub struct Wrapper(T); | ^^^^^ introduces a `'static` lifetime requirement -note: the anonymous lifetime #1 defined on the method body at 16:5... +note: the anonymous lifetime #1 defined here... --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:5 | LL | pub fn repro(_: Wrapper); diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/wf-object-safe.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/wf-object-safe.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/wf-object-safe.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/wf-object-safe.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,6 @@ LL | let _x: &dyn A; | ^^^^^^ `A` cannot be made into an object | - = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-object-safe.rs:5:23 | @@ -12,6 +11,7 @@ | - this trait cannot be made into an object... LL | fn foo(&self, _x: &Self); | ^^^^^ ...because method `foo` references the `Self` type in this parameter + = help: consider moving `foo` to another trait error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/wf-static-method.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/wf-static-method.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/wf/wf-static-method.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/wf/wf-static-method.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,12 +4,12 @@ LL | u | ^ | -note: ...the reference is valid for the lifetime `'a` as defined on the impl at 14:6... +note: ...the reference is valid for the lifetime `'a` as defined here... --> $DIR/wf-static-method.rs:14:6 | LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () { | ^^ -note: ...but the borrowed content is only valid for the lifetime `'b` as defined on the impl at 14:10 +note: ...but the borrowed content is only valid for the lifetime `'b` as defined here --> $DIR/wf-static-method.rs:14:10 | LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () { @@ -21,12 +21,12 @@ LL | let me = Self::make_me(); | ^^^^ | -note: lifetime parameter instantiated with the lifetime `'b` as defined on the impl at 23:10 +note: lifetime parameter instantiated with the lifetime `'b` as defined here --> $DIR/wf-static-method.rs:23:10 | LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> { | ^^ -note: but lifetime parameter must outlive the lifetime `'a` as defined on the impl at 23:6 +note: but lifetime parameter must outlive the lifetime `'a` as defined here --> $DIR/wf-static-method.rs:23:6 | LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> { @@ -38,12 +38,12 @@ LL | u | ^ | -note: ...the reference is valid for the lifetime `'a` as defined on the impl at 31:6... +note: ...the reference is valid for the lifetime `'a` as defined here... --> $DIR/wf-static-method.rs:31:6 | LL | impl<'a, 'b> Evil<'a, 'b> { | ^^ -note: ...but the borrowed content is only valid for the lifetime `'b` as defined on the impl at 31:10 +note: ...but the borrowed content is only valid for the lifetime `'b` as defined here --> $DIR/wf-static-method.rs:31:10 | LL | impl<'a, 'b> Evil<'a, 'b> { @@ -55,7 +55,7 @@ LL | <()>::static_evil(b) | ^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 40:13... +note: first, the lifetime cannot outlive the lifetime `'b` as defined here... --> $DIR/wf-static-method.rs:40:13 | LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { @@ -65,7 +65,7 @@ | LL | <()>::static_evil(b) | ^ -note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 40:9... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/wf-static-method.rs:40:9 | LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { @@ -82,7 +82,7 @@ LL | ::static_evil(b) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 44:22... +note: first, the lifetime cannot outlive the lifetime `'b` as defined here... --> $DIR/wf-static-method.rs:44:22 | LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { @@ -92,7 +92,7 @@ | LL | ::static_evil(b) | ^ -note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 44:18... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/wf-static-method.rs:44:18 | LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { @@ -109,7 +109,7 @@ LL | ::inherent_evil(b) | ^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 49:22... +note: first, the lifetime cannot outlive the lifetime `'b` as defined here... --> $DIR/wf-static-method.rs:49:22 | LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { @@ -119,7 +119,7 @@ | LL | ::inherent_evil(b) | ^ -note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 49:18... +note: but, the lifetime must be valid for the lifetime `'a` as defined here... --> $DIR/wf-static-method.rs:49:18 | LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/where-clause-constraints-are-local-for-inherent-impl.rs:13:22 | LL | require_copy(self.x); - | ^^^^^^ the trait `Copy` is not implemented for `T` + | ------------ ^^^^^^ the trait `Copy` is not implemented for `T` + | | + | required by a bound introduced by this call | note: required by a bound in `require_copy` --> $DIR/where-clause-constraints-are-local-for-inherent-impl.rs:1:20 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/where-clause-constraints-are-local-for-trait-impl.rs:18:22 | LL | require_copy(self.x); - | ^^^^^^ the trait `Copy` is not implemented for `T` + | ------------ ^^^^^^ the trait `Copy` is not implemented for `T` + | | + | required by a bound introduced by this call | note: required by a bound in `require_copy` --> $DIR/where-clause-constraints-are-local-for-trait-impl.rs:1:20 diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,9 @@ --> $DIR/where-clauses-method-unsatisfied.rs:18:14 | LL | x.equals(&x); - | ^^ the trait `Eq` is not implemented for `Bar` + | ------ ^^ the trait `Eq` is not implemented for `Bar` + | | + | required by a bound introduced by this call error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/while-let.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/while-let.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/while-let.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/while-let.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -7,7 +7,7 @@ LL | / foo!(_a, 1, { LL | | println!("irrefutable pattern"); LL | | }); - | |_______- in this macro invocation + | |______- in this macro invocation | = note: `#[warn(irrefutable_let_patterns)]` on by default = note: this pattern will always match, so the loop will never exit @@ -23,7 +23,7 @@ LL | / bar!(_a, 1, { LL | | println!("irrefutable pattern"); LL | | }); - | |_______- in this macro invocation + | |______- in this macro invocation | = note: this pattern will always match, so the loop will never exit = help: consider instead using a `loop { ... }` with a `let` inside it diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui/wrong-ret-type.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui/wrong-ret-type.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui/wrong-ret-type.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui/wrong-ret-type.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); } - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++ error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -#![feature(box_syntax, plugin, rustc_private)] +#![feature(plugin, rustc_private)] #![crate_type = "dylib"] extern crate rustc_ast_pretty; @@ -21,7 +21,7 @@ #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]); - reg.lint_store.register_late_pass(|| box MissingAllowedAttrPass); + reg.lint_store.register_late_pass(|| Box::new(MissingAllowedAttrPass)); } declare_lint! { diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ // force-host #![feature(rustc_private)] -#![feature(box_syntax)] extern crate rustc_driver; extern crate rustc_hir; @@ -14,6 +13,7 @@ use rustc_ast::attr; use rustc_driver::plugin::Registry; use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass}; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::Symbol; macro_rules! fake_lint_pass { @@ -27,13 +27,14 @@ } impl LateLintPass<'_> for $struct { - fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) { + fn check_crate(&mut self, cx: &LateContext) { let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let span = cx.tcx.def_span(CRATE_DEF_ID); $( if !cx.sess().contains_name(attrs, $attr) { cx.lint(CRATE_NOT_OKAY, |lint| { let msg = format!("crate is not marked with #![{}]", $attr); - lint.build(&msg).set_span(krate.module().inner).emit() + lint.build(&msg).set_span(span).emit() }); } )* @@ -73,7 +74,7 @@ &CRATE_NOT_GREY, &CRATE_NOT_GREEN, ]); - reg.lint_store.register_late_pass(|| box PassOkay); - reg.lint_store.register_late_pass(|| box PassRedBlue); - reg.lint_store.register_late_pass(|| box PassGreyGreen); + reg.lint_store.register_late_pass(|| Box::new(PassOkay)); + reg.lint_store.register_late_pass(|| Box::new(PassRedBlue)); + reg.lint_store.register_late_pass(|| Box::new(PassGreyGreen)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ // force-host #![feature(rustc_private)] -#![feature(box_syntax)] extern crate rustc_driver; extern crate rustc_hir; @@ -9,13 +8,13 @@ extern crate rustc_lint; #[macro_use] extern crate rustc_session; -extern crate rustc_span; extern crate rustc_ast; +extern crate rustc_span; use rustc_driver::plugin::Registry; -use rustc_lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::Symbol; -use rustc_ast::attr; declare_lint! { CRATE_NOT_OKAY, @@ -26,13 +25,12 @@ declare_lint_pass!(Pass => [CRATE_NOT_OKAY]); impl<'tcx> LateLintPass<'tcx> for Pass { - fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) { + fn check_crate(&mut self, cx: &LateContext) { let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let span = cx.tcx.def_span(CRATE_DEF_ID); if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) { cx.lint(CRATE_NOT_OKAY, |lint| { - lint.build("crate is not marked with #![crate_okay]") - .set_span(krate.module().inner) - .emit() + lint.build("crate is not marked with #![crate_okay]").set_span(span).emit() }); } } @@ -41,5 +39,5 @@ #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]); - reg.lint_store.register_late_pass(|| box Pass); + reg.lint_store.register_late_pass(|| Box::new(Pass)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] // Load rustc as a plugin to get macros. extern crate rustc_driver; @@ -36,7 +36,7 @@ #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]); - reg.lint_store.register_late_pass(|| box Pass); + reg.lint_store.register_late_pass(|| Box::new(Pass)); reg.lint_store.register_group( true, "lint_me", diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_ast; @@ -31,5 +31,5 @@ #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_early_pass(|| Box::new(Pass)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_ast; @@ -46,7 +46,7 @@ #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]); - reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_early_pass(|| Box::new(Pass)); reg.lint_store.register_group( true, "clippy::group", diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_middle; extern crate rustc_driver; @@ -20,5 +20,5 @@ #[no_mangle] fn __rustc_plugin_registrar(_: &mut Registry) { thread_local!(static FOO: RefCell>> = RefCell::new(None)); - FOO.with(|s| *s.borrow_mut() = Some(box Foo { foo: 10 } as Box)); + FOO.with(|s| *s.borrow_mut() = Some(Box::new(Foo { foo: 10 }) as Box)); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,6 @@ // run-pass #![allow(unused_imports)] -#![feature(box_syntax)] #![feature(rustc_private)] extern crate rustc_macros; diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/hash-stable-is-unstable.rs rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/hash-stable-is-unstable.rs --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/hash-stable-is-unstable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/hash-stable-is-unstable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,10 +2,10 @@ extern crate rustc_data_structures; //~^ use of unstable library feature 'rustc_private' -extern crate rustc_middle; -//~^ use of unstable library feature 'rustc_private' extern crate rustc_macros; //~^ use of unstable library feature 'rustc_private' +extern crate rustc_query_system; +//~^ use of unstable library feature 'rustc_private' use rustc_macros::HashStable; //~^ use of unstable library feature 'rustc_private' diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/hash-stable-is-unstable.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/hash-stable-is-unstable.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/hash-stable-is-unstable.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/hash-stable-is-unstable.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:5:1 | -LL | extern crate rustc_middle; +LL | extern crate rustc_macros; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #27812 for more information @@ -19,8 +19,8 @@ error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:7:1 | -LL | extern crate rustc_macros; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern crate rustc_query_system; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #27812 for more information = help: add `#![feature(rustc_private)]` to the crate attributes to enable diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ | ^^^^^^^^ ... LL | custom_lint_pass_macro!(); - | -------------------------- in this macro invocation + | ------------------------- in this macro invocation | = help: try using `declare_lint_pass!` or `impl_lint_pass!` instead = note: this error originates in the macro `custom_lint_pass_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/issue-76270-panic-in-libproc-macro.rs:15:1 | LL | proc_macro_panic::panic_in_libproc_macro!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: message: `""` is not a valid identifier diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/build-manifest/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/build-manifest/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/build-manifest/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/build-manifest/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "build-manifest" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] toml = "0.5" diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/build-manifest/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/build-manifest/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/build-manifest/src/main.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/build-manifest/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -99,6 +99,7 @@ "i686-unknown-freebsd", "i686-unknown-linux-gnu", "i686-unknown-linux-musl", + "m68k-unknown-linux-gnu", "mips-unknown-linux-gnu", "mips-unknown-linux-musl", "mips64-unknown-linux-gnuabi64", diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/bump-stage0/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/bump-stage0/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/bump-stage0/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/bump-stage0/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,14 @@ +[package] +name = "bump-stage0" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.34" +curl = "0.4.38" +indexmap = { version = "1.7.0", features = ["serde"] } +serde = { version = "1.0.125", features = ["derive"] } +serde_json = "1.0.59" +toml = "0.5.7" diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/bump-stage0/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/bump-stage0/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/bump-stage0/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/bump-stage0/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,204 @@ +use anyhow::Error; +use curl::easy::Easy; +use indexmap::IndexMap; +use std::collections::HashMap; +use std::convert::TryInto; + +const DIST_SERVER: &str = "https://static.rust-lang.org"; +const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo"]; +const RUSTFMT_COMPONENTS: &[&str] = &["rustfmt-preview"]; + +struct Tool { + channel: Channel, + version: [u16; 3], + checksums: IndexMap, +} + +impl Tool { + fn new() -> Result { + let channel = match std::fs::read_to_string("src/ci/channel")?.trim() { + "stable" => Channel::Stable, + "beta" => Channel::Beta, + "nightly" => Channel::Nightly, + other => anyhow::bail!("unsupported channel: {}", other), + }; + + // Split "1.42.0" into [1, 42, 0] + let version = std::fs::read_to_string("src/version")? + .trim() + .split('.') + .map(|val| val.parse()) + .collect::, _>>()? + .try_into() + .map_err(|_| anyhow::anyhow!("failed to parse version"))?; + + Ok(Self { channel, version, checksums: IndexMap::new() }) + } + + fn update_json(mut self) -> Result<(), Error> { + std::fs::write( + "src/stage0.json", + format!( + "{}\n", + serde_json::to_string_pretty(&Stage0 { + comment: "Generated by `./x.py run src/tools/bump-stage0`. \ + Run that command again to update the bootstrap compiler.", + dist_server: DIST_SERVER.into(), + compiler: self.detect_compiler()?, + rustfmt: self.detect_rustfmt()?, + checksums_sha256: { + // Keys are sorted here instead of beforehand because values in this map + // are added while filling the other struct fields just above this block. + self.checksums.sort_keys(); + self.checksums + } + })? + ), + )?; + Ok(()) + } + + // Currently Rust always bootstraps from the previous stable release, and in our train model + // this means that the master branch bootstraps from beta, beta bootstraps from current stable, + // and stable bootstraps from the previous stable release. + // + // On the master branch the compiler version is configured to `beta` whereas if you're looking + // at the beta or stable channel you'll likely see `1.x.0` as the version, with the previous + // release's version number. + fn detect_compiler(&mut self) -> Result { + let channel = match self.channel { + Channel::Stable | Channel::Beta => { + // The 1.XX manifest points to the latest point release of that minor release. + format!("{}.{}", self.version[0], self.version[1] - 1) + } + Channel::Nightly => "beta".to_string(), + }; + + let manifest = fetch_manifest(&channel)?; + self.collect_checksums(&manifest, COMPILER_COMPONENTS)?; + Ok(Stage0Toolchain { + date: manifest.date, + version: if self.channel == Channel::Nightly { + "beta".to_string() + } else { + // The version field is like "1.42.0 (abcdef1234 1970-01-01)" + manifest.pkg["rust"] + .version + .split_once(' ') + .expect("invalid version field") + .0 + .to_string() + }, + }) + } + + /// We use a nightly rustfmt to format the source because it solves some bootstrapping issues + /// with use of new syntax in this repo. For the beta/stable channels rustfmt is not provided, + /// as we don't want to depend on rustfmt from nightly there. + fn detect_rustfmt(&mut self) -> Result, Error> { + if self.channel != Channel::Nightly { + return Ok(None); + } + + let manifest = fetch_manifest("nightly")?; + self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?; + Ok(Some(Stage0Toolchain { date: manifest.date, version: "nightly".into() })) + } + + fn collect_checksums(&mut self, manifest: &Manifest, components: &[&str]) -> Result<(), Error> { + let prefix = format!("{}/", DIST_SERVER); + for component in components { + let pkg = manifest + .pkg + .get(*component) + .ok_or_else(|| anyhow::anyhow!("missing component from manifest: {}", component))?; + for target in pkg.target.values() { + for pair in &[(&target.url, &target.hash), (&target.xz_url, &target.xz_hash)] { + if let (Some(url), Some(sha256)) = pair { + let url = url + .strip_prefix(&prefix) + .ok_or_else(|| { + anyhow::anyhow!("url doesn't start with dist server base: {}", url) + })? + .to_string(); + self.checksums.insert(url, sha256.clone()); + } + } + } + } + Ok(()) + } +} + +fn main() -> Result<(), Error> { + let tool = Tool::new()?; + tool.update_json()?; + Ok(()) +} + +fn fetch_manifest(channel: &str) -> Result { + Ok(toml::from_slice(&http_get(&format!( + "{}/dist/channel-rust-{}.toml", + DIST_SERVER, channel + ))?)?) +} + +fn http_get(url: &str) -> Result, Error> { + let mut data = Vec::new(); + let mut handle = Easy::new(); + handle.fail_on_error(true)?; + handle.url(url)?; + { + let mut transfer = handle.transfer(); + transfer.write_function(|new_data| { + data.extend_from_slice(new_data); + Ok(new_data.len()) + })?; + transfer.perform()?; + } + Ok(data) +} + +#[derive(Debug, PartialEq, Eq)] +enum Channel { + Stable, + Beta, + Nightly, +} + +#[derive(Debug, serde::Serialize)] +struct Stage0 { + #[serde(rename = "__comment")] + comment: &'static str, + dist_server: String, + compiler: Stage0Toolchain, + rustfmt: Option, + checksums_sha256: IndexMap, +} + +#[derive(Debug, serde::Serialize)] +struct Stage0Toolchain { + date: String, + version: String, +} + +#[derive(Debug, serde::Deserialize)] +struct Manifest { + date: String, + pkg: HashMap, +} + +#[derive(Debug, serde::Deserialize)] +struct ManifestPackage { + version: String, + target: HashMap, +} + +#[derive(Debug, serde::Deserialize)] +struct ManifestTargetPackage { + available: bool, + url: Option, + hash: Option, + xz_url: Option, + xz_hash: Option, +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/cargotest/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/cargotest/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/cargotest/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/cargotest/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "cargotest2" version = "0.1.0" -edition = "2018" +edition = "2021" [[bin]] name = "cargotest" diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.cargo/config rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.cargo/config --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.cargo/config 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.cargo/config 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,10 @@ [alias] uitest = "test --test compile-test" -dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" -lintcheck = "run --target-dir lintcheck/target --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " +dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" +lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored" [build] -rustflags = ["-Zunstable-options"] +# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests +rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"] +target-dir = "target" diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.56" +version = "0.1.57" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -8,7 +8,7 @@ keywords = ["clippy", "lint", "plugin"] categories = ["development-tools", "development-tools::cargo-plugins"] build = "build.rs" -edition = "2018" +edition = "2021" publish = false [[bin]] @@ -21,32 +21,35 @@ path = "src/driver.rs" [dependencies] -# begin automatic update -clippy_lints = { version = "0.1.50", path = "clippy_lints" } -# end automatic update +clippy_lints = { version = "0.1", path = "clippy_lints" } semver = "0.11" -rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } -tempfile = { version = "3.1.0", optional = true } +rustc_tools_util = { version = "0.2", path = "rustc_tools_util" } +tempfile = { version = "3.2", optional = true } [dev-dependencies] cargo_metadata = "0.12" -compiletest_rs = { version = "0.6.0", features = ["tmp"] } +compiletest_rs = { version = "0.7", features = ["tmp"] } tester = "0.9" -serde = { version = "1.0", features = ["derive"] } -derive-new = "0.5" -regex = "1.4" -quote = "1" -syn = { version = "1", features = ["full"] } +regex = "1.5" # This is used by the `collect-metadata` alias. filetime = "0.2" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. -rustc-workspace-hack = "1.0.0" +rustc-workspace-hack = "1.0" + +# UI test dependencies +clippy_utils = { path = "clippy_utils" } +derive-new = "0.5" +if_chain = "1.0" +itertools = "0.10" +quote = "1.0" +serde = { version = "1.0", features = ["derive"] } +syn = { version = "1.0", features = ["full"] } [build-dependencies] -rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } +rustc_tools_util = { version = "0.2", path = "rustc_tools_util" } [features] deny-warnings = ["clippy_lints/deny-warnings"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/CHANGELOG.md rustc-1.57.0+dfsg1+llvm/src/tools/clippy/CHANGELOG.md --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/CHANGELOG.md 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/CHANGELOG.md 2021-11-29 19:27:12.000000000 +0000 @@ -6,11 +6,81 @@ ## Unreleased / In Rust Nightly -[74d1561...master](https://github.com/rust-lang/rust-clippy/compare/74d1561...master) +[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master) + +## Rust 1.56 + +Current beta, release 2021-10-21 + +[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e) + +### New Lints + +* [`unwrap_or_else_default`] + [#7516](https://github.com/rust-lang/rust-clippy/pull/7516) + +### Enhancements + +* [`needless_continue`]: Now also lints in `loop { continue; }` case + [#7477](https://github.com/rust-lang/rust-clippy/pull/7477) +* [`disallowed_type`]: Now also primitive types can be disallowed + [#7488](https://github.com/rust-lang/rust-clippy/pull/7488) +* [`manual_swap`]: Now also lints on xor swaps + [#7506](https://github.com/rust-lang/rust-clippy/pull/7506) +* [`map_flatten`]: Now also lints on the `Result` type + [#7522](https://github.com/rust-lang/rust-clippy/pull/7522) +* [`no_effect`]: Now also lints on inclusive ranges + [#7556](https://github.com/rust-lang/rust-clippy/pull/7556) + +### False Positive Fixes + +* [`nonstandard_macro_braces`]: No longer lints on similar named nested macros + [#7478](https://github.com/rust-lang/rust-clippy/pull/7478) +* [`too_many_lines`]: No longer lints in closures to avoid duplicated diagnostics + [#7534](https://github.com/rust-lang/rust-clippy/pull/7534) +* [`similar_names`]: No longer complains about `iter` and `item` being too + similar [#7546](https://github.com/rust-lang/rust-clippy/pull/7546) + +### Suggestion Fixes/Improvements + +* [`similar_names`]: No longer suggests to insert or add an underscore as a fix + [#7221](https://github.com/rust-lang/rust-clippy/pull/7221) +* [`new_without_default`]: No longer shows the full qualified type path when + suggesting adding a `Default` implementation + [#7493](https://github.com/rust-lang/rust-clippy/pull/7493) +* [`while_let_on_iterator`]: Now suggests re-borrowing mutable references + [#7520](https://github.com/rust-lang/rust-clippy/pull/7520) +* [`extend_with_drain`]: Improve code suggestion for mutable and immutable + references [#7533](https://github.com/rust-lang/rust-clippy/pull/7533) +* [`trivially_copy_pass_by_ref`]: Now properly handles `Self` type + [#7535](https://github.com/rust-lang/rust-clippy/pull/7535) +* [`never_loop`]: Now suggests using `if let` instead of a `for` loop when + applicable [#7541](https://github.com/rust-lang/rust-clippy/pull/7541) + +### Documentation Improvements + +* Clippy now uses a lint to generate its lint documentation. [Lints all the way + down](https://en.wikipedia.org/wiki/Turtles_all_the_way_down). + [#7502](https://github.com/rust-lang/rust-clippy/pull/7502) +* Reworked Clippy's website: + [#7172](https://github.com/rust-lang/rust-clippy/issues/7172) + [#7279](https://github.com/rust-lang/rust-clippy/pull/7279) + * Added applicability information about lints + * Added a link to jump into the implementation + * Improved loading times + * Adapted some styling +* `cargo clippy --help` now also explains the `--fix` and `--no-deps` flag + [#7492](https://github.com/rust-lang/rust-clippy/pull/7492) +* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code + example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507) + +### New Lints + +* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case. ## Rust 1.55 -Current beta, release 2021-09-09 +Current stable, released 2021-09-09 [3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561) @@ -126,21 +196,9 @@ * [`use_self`] [#7428](https://github.com/rust-lang/rust-clippy/pull/7428) -### Documentation Improvements - -* Reworked Clippy's website: - [#7279](https://github.com/rust-lang/rust-clippy/pull/7279) - [#7172](https://github.com/rust-lang/rust-clippy/issues/7172) - * Added applicability information about lints - * Added a link to jump into the implementation - * Improved loading times - * Adapted some styling -* Clippy now uses a lint to generate its documentation - [#7298](https://github.com/rust-lang/rust-clippy/pull/7298) - ## Rust 1.54 -Current stable, released 2021-07-29 +Released 2021-07-29 [7c7683c...3ae8faf](https://github.com/rust-lang/rust-clippy/compare/7c7683c...3ae8faf) @@ -964,7 +1022,7 @@ [#5907](https://github.com/rust-lang/rust-clippy/pull/5907) * [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr` [#5884](https://github.com/rust-lang/rust-clippy/pull/5884) -* [`invalid_atomic_ordering`]: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update` +* `invalid_atomic_ordering`: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update` [#6025](https://github.com/rust-lang/rust-clippy/pull/6025) * Avoid [`redundant_pattern_matching`] triggering in macros [#6069](https://github.com/rust-lang/rust-clippy/pull/6069) @@ -1050,7 +1108,7 @@ [#5913](https://github.com/rust-lang/rust-clippy/pull/5913) * Add example of false positive to [`ptr_arg`] docs. [#5885](https://github.com/rust-lang/rust-clippy/pull/5885) -* [`box_vec`], [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box` +* [`box_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection), [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box` [#6023](https://github.com/rust-lang/rust-clippy/pull/6023) ## Rust 1.47 @@ -1451,7 +1509,7 @@ * [`option_as_ref_deref`] [#4945](https://github.com/rust-lang/rust-clippy/pull/4945) * [`wildcard_in_or_patterns`] [#4960](https://github.com/rust-lang/rust-clippy/pull/4960) * [`iter_nth_zero`] [#4966](https://github.com/rust-lang/rust-clippy/pull/4966) -* [`invalid_atomic_ordering`] [#4999](https://github.com/rust-lang/rust-clippy/pull/4999) +* `invalid_atomic_ordering` [#4999](https://github.com/rust-lang/rust-clippy/pull/4999) * [`skip_while_next`] [#5067](https://github.com/rust-lang/rust-clippy/pull/5067) ### Moves and Deprecations @@ -1491,7 +1549,7 @@ * `unknown_clippy_lints` [#4963](https://github.com/rust-lang/rust-clippy/pull/4963) * [`explicit_into_iter_loop`] [#4978](https://github.com/rust-lang/rust-clippy/pull/4978) * [`useless_attribute`] [#5022](https://github.com/rust-lang/rust-clippy/pull/5022) -* [`if_let_some_result`] [#5032](https://github.com/rust-lang/rust-clippy/pull/5032) +* `if_let_some_result` [#5032](https://github.com/rust-lang/rust-clippy/pull/5032) ### ICE fixes @@ -1815,10 +1873,10 @@ [2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be) -* New lints: [`slow_vector_initialization`], [`mem_discriminant_non_enum`], +* New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`, [`redundant_clone`], [`wildcard_dependencies`], [`into_iter_on_ref`], `into_iter_on_array`, [`deprecated_cfg_attr`], - [`mem_discriminant_non_enum`], [`cargo_common_metadata`] + [`cargo_common_metadata`] * Add support for `u128` and `i128` to integer related lints * Add float support to `mistyped_literal_suffixes` * Fix false positives in `use_self` @@ -2570,7 +2628,7 @@ [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box -[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec +[`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow @@ -2613,6 +2671,7 @@ [`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr [`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof +[`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method @@ -2636,6 +2695,7 @@ [`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use [`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names [`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op +[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision @@ -2684,7 +2744,6 @@ [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op [`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching -[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none @@ -2712,7 +2771,6 @@ [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref -[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering [`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons @@ -2722,6 +2780,7 @@ [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice +[`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next @@ -2744,6 +2803,7 @@ [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion +[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map @@ -2754,6 +2814,7 @@ [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic +[`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap @@ -2772,12 +2833,12 @@ [`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items [`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm [`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats +[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok [`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms [`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm [`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter -[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none [`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default @@ -2795,6 +2856,7 @@ [`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals +[`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files [`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception [`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions [`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic @@ -2821,6 +2883,7 @@ [`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main [`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes +[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark [`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop @@ -2828,12 +2891,14 @@ [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update [`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord [`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply +[`negative_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#negative_feature_names [`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop [`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self [`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions +[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options [`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces @@ -2881,6 +2946,7 @@ [`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call [`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls [`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else +[`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching @@ -2900,9 +2966,11 @@ [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push +[`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors +[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,16 +1,16 @@ [package] name = "clippy_dev" version = "0.0.1" -edition = "2018" +edition = "2021" [dependencies] bytecount = "0.6" clap = "2.33" -itertools = "0.9" +itertools = "0.10" opener = "0.5" -regex = "1" +regex = "1.5" shell-escape = "0.1" -walkdir = "2" +walkdir = "2.3" [features] deny-warnings = [] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/bless.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/bless.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/bless.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/bless.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,6 @@ //! `bless` updates the reference files in the repo with changed output files //! from the last test run. -use std::env; use std::ffi::OsStr; use std::fs; use std::lazy::SyncLazy; @@ -10,17 +9,9 @@ use crate::clippy_project_root; -// NOTE: this is duplicated with tests/cargo/mod.rs What to do? -pub static CARGO_TARGET_DIR: SyncLazy = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") { - Some(v) => v.into(), - None => env::current_dir().unwrap().join("target"), -}); - static CLIPPY_BUILD_TIME: SyncLazy> = SyncLazy::new(|| { - let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); - let mut path = PathBuf::from(&**CARGO_TARGET_DIR); - path.push(profile); - path.push("cargo-clippy"); + let mut path = std::env::current_exe().unwrap(); + path.set_file_name("cargo-clippy"); fs::metadata(path).ok()?.modified().ok() }); @@ -94,10 +85,7 @@ } fn build_dir() -> PathBuf { - let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); - let mut path = PathBuf::new(); - path.push(CARGO_TARGET_DIR.clone()); - path.push(profile); - path.push("test_build_base"); + let mut path = std::env::current_exe().unwrap(); + path.set_file_name("test"); path } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/lib.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/lib.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/lib.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,340 +3,15 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] -use itertools::Itertools; -use regex::Regex; -use std::collections::HashMap; -use std::ffi::OsStr; -use std::fs; -use std::lazy::SyncLazy; -use std::path::{Path, PathBuf}; -use walkdir::WalkDir; +use std::path::PathBuf; pub mod bless; pub mod fmt; pub mod new_lint; pub mod serve; pub mod setup; -pub mod stderr_length_check; pub mod update_lints; -static DEC_CLIPPY_LINT_RE: SyncLazy = SyncLazy::new(|| { - Regex::new( - r#"(?x) - declare_clippy_lint!\s*[\{(] - (?:\s+///.*)* - \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* - (?P[a-z_]+)\s*,\s* - "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] -"#, - ) - .unwrap() -}); - -static DEC_DEPRECATED_LINT_RE: SyncLazy = SyncLazy::new(|| { - Regex::new( - r#"(?x) - declare_deprecated_lint!\s*[{(]\s* - (?:\s+///.*)* - \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* - "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] -"#, - ) - .unwrap() -}); -static NL_ESCAPE_RE: SyncLazy = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap()); - -pub static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; - -/// Lint data parsed from the Clippy source code. -#[derive(Clone, PartialEq, Debug)] -pub struct Lint { - pub name: String, - pub group: String, - pub desc: String, - pub deprecation: Option, - pub module: String, -} - -impl Lint { - #[must_use] - pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self { - Self { - name: name.to_lowercase(), - group: group.to_string(), - desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(), - deprecation: deprecation.map(ToString::to_string), - module: module.to_string(), - } - } - - /// Returns all non-deprecated lints and non-internal lints - #[must_use] - pub fn usable_lints(lints: &[Self]) -> Vec { - lints - .iter() - .filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal")) - .cloned() - .collect() - } - - /// Returns all internal lints (not `internal_warn` lints) - #[must_use] - pub fn internal_lints(lints: &[Self]) -> Vec { - lints.iter().filter(|l| l.group == "internal").cloned().collect() - } - - /// Returns all deprecated lints - #[must_use] - pub fn deprecated_lints(lints: &[Self]) -> Vec { - lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect() - } - - /// Returns the lints in a `HashMap`, grouped by the different lint groups - #[must_use] - pub fn by_lint_group(lints: impl Iterator) -> HashMap> { - lints.map(|lint| (lint.group.to_string(), lint)).into_group_map() - } -} - -/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`. -#[must_use] -pub fn gen_lint_group_list<'a>(lints: impl Iterator) -> Vec { - lints - .map(|l| format!(" LintId::of({}::{}),", l.module, l.name.to_uppercase())) - .sorted() - .collect::>() -} - -/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`. -#[must_use] -pub fn gen_modules_list<'a>(lints: impl Iterator) -> Vec { - lints - .map(|l| &l.module) - .unique() - .map(|module| format!("mod {};", module)) - .sorted() - .collect::>() -} - -/// Generates the list of lint links at the bottom of the README -#[must_use] -pub fn gen_changelog_lint_list<'a>(lints: impl Iterator) -> Vec { - lints - .sorted_by_key(|l| &l.name) - .map(|l| format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name)) - .collect() -} - -/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`. -#[must_use] -pub fn gen_deprecated<'a>(lints: impl Iterator) -> Vec { - lints - .flat_map(|l| { - l.deprecation - .clone() - .map(|depr_text| { - vec![ - " store.register_removed(".to_string(), - format!(" \"clippy::{}\",", l.name), - format!(" \"{}\",", depr_text), - " );".to_string(), - ] - }) - .expect("only deprecated lints should be passed") - }) - .collect::>() -} - -#[must_use] -pub fn gen_register_lint_list<'a>( - internal_lints: impl Iterator, - usable_lints: impl Iterator, -) -> Vec { - let header = " store.register_lints(&[".to_string(); - let footer = " ]);".to_string(); - let internal_lints = internal_lints - .sorted_by_key(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) - .map(|l| { - format!( - " #[cfg(feature = \"internal-lints\")]\n {}::{},", - l.module, - l.name.to_uppercase() - ) - }); - let other_lints = usable_lints - .sorted_by_key(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) - .map(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) - .sorted(); - let mut lint_list = vec![header]; - lint_list.extend(internal_lints); - lint_list.extend(other_lints); - lint_list.push(footer); - lint_list -} - -/// Gathers all files in `src/clippy_lints` and gathers all lints inside -pub fn gather_all() -> impl Iterator { - lint_files().flat_map(|f| gather_from_file(&f)) -} - -fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator { - let content = fs::read_to_string(dir_entry.path()).unwrap(); - let path = dir_entry.path(); - let filename = path.file_stem().unwrap(); - let path_buf = path.with_file_name(filename); - let mut rel_path = path_buf - .strip_prefix(clippy_project_root().join("clippy_lints/src")) - .expect("only files in `clippy_lints/src` should be looked at"); - // If the lints are stored in mod.rs, we get the module name from - // the containing directory: - if filename == "mod" { - rel_path = rel_path.parent().unwrap(); - } - - let module = rel_path - .components() - .map(|c| c.as_os_str().to_str().unwrap()) - .collect::>() - .join("::"); - - parse_contents(&content, &module) -} - -fn parse_contents(content: &str, module: &str) -> impl Iterator { - let lints = DEC_CLIPPY_LINT_RE - .captures_iter(content) - .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, module)); - let deprecated = DEC_DEPRECATED_LINT_RE - .captures_iter(content) - .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), module)); - // Removing the `.collect::>().into_iter()` causes some lifetime issues due to the map - lints.chain(deprecated).collect::>().into_iter() -} - -/// Collects all .rs files in the `clippy_lints/src` directory -fn lint_files() -> impl Iterator { - // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories. - // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`. - let path = clippy_project_root().join("clippy_lints/src"); - WalkDir::new(path) - .into_iter() - .filter_map(Result::ok) - .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) -} - -/// Whether a file has had its text changed or not -#[derive(PartialEq, Debug)] -pub struct FileChange { - pub changed: bool, - pub new_lines: String, -} - -/// Replaces a region in a file delimited by two lines matching regexes. -/// -/// `path` is the relative path to the file on which you want to perform the replacement. -/// -/// See `replace_region_in_text` for documentation of the other options. -/// -/// # Panics -/// -/// Panics if the path could not read or then written -pub fn replace_region_in_file( - path: &Path, - start: &str, - end: &str, - replace_start: bool, - write_back: bool, - replacements: F, -) -> FileChange -where - F: FnOnce() -> Vec, -{ - let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.display(), e)); - let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements); - - if write_back { - if let Err(e) = fs::write(path, file_change.new_lines.as_bytes()) { - panic!("Cannot write to {}: {}", path.display(), e); - } - } - file_change -} - -/// Replaces a region in a text delimited by two lines matching regexes. -/// -/// * `text` is the input text on which you want to perform the replacement -/// * `start` is a `&str` that describes the delimiter line before the region you want to replace. -/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. -/// * `end` is a `&str` that describes the delimiter line until where the replacement should happen. -/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. -/// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end` -/// delimiter line is never replaced. -/// * `replacements` is a closure that has to return a `Vec` which contains the new text. -/// -/// If you want to perform the replacement on files instead of already parsed text, -/// use `replace_region_in_file`. -/// -/// # Example -/// -/// ``` -/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end"; -/// let result = -/// clippy_dev::replace_region_in_text(the_text, "replace_start", "replace_end", false, || { -/// vec!["a different".to_string(), "text".to_string()] -/// }) -/// .new_lines; -/// assert_eq!("replace_start\na different\ntext\nreplace_end", result); -/// ``` -/// -/// # Panics -/// -/// Panics if start or end is not valid regex -pub fn replace_region_in_text(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange -where - F: FnOnce() -> Vec, -{ - let replace_it = replacements(); - let mut in_old_region = false; - let mut found = false; - let mut new_lines = vec![]; - let start = Regex::new(start).unwrap(); - let end = Regex::new(end).unwrap(); - - for line in text.lines() { - if in_old_region { - if end.is_match(line) { - in_old_region = false; - new_lines.extend(replace_it.clone()); - new_lines.push(line.to_string()); - } - } else if start.is_match(line) { - if !replace_start { - new_lines.push(line.to_string()); - } - in_old_region = true; - found = true; - } else { - new_lines.push(line.to_string()); - } - } - - if !found { - // This happens if the provided regex in `clippy_dev/src/main.rs` does not match in the - // given text or file. Most likely this is an error on the programmer's side and the Regex - // is incorrect. - eprintln!("error: regex \n{:?}\ndoesn't match. You may have to update it.", start); - std::process::exit(1); - } - - let mut new_lines = new_lines.join("\n"); - if text.ends_with('\n') { - new_lines.push('\n'); - } - let changed = new_lines != text; - FileChange { changed, new_lines } -} - /// Returns the path to the Clippy project directory /// /// # Panics @@ -361,200 +36,3 @@ } panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); } - -#[test] -fn test_parse_contents() { - let result: Vec = parse_contents( - r#" -declare_clippy_lint! { - pub PTR_ARG, - style, - "really long \ - text" -} - -declare_clippy_lint!{ - pub DOC_MARKDOWN, - pedantic, - "single line" -} - -/// some doc comment -declare_deprecated_lint! { - pub SHOULD_ASSERT_EQ, - "`assert!()` will be more flexible with RFC 2011" -} - "#, - "module_name", - ) - .collect(); - - let expected = vec![ - Lint::new("ptr_arg", "style", "really long text", None, "module_name"), - Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"), - Lint::new( - "should_assert_eq", - "Deprecated", - "`assert!()` will be more flexible with RFC 2011", - Some("`assert!()` will be more flexible with RFC 2011"), - "module_name", - ), - ]; - assert_eq!(expected, result); -} - -#[test] -fn test_replace_region() { - let text = "\nabc\n123\n789\ndef\nghi"; - let expected = FileChange { - changed: true, - new_lines: "\nabc\nhello world\ndef\nghi".to_string(), - }; - let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || { - vec!["hello world".to_string()] - }); - assert_eq!(expected, result); -} - -#[test] -fn test_replace_region_with_start() { - let text = "\nabc\n123\n789\ndef\nghi"; - let expected = FileChange { - changed: true, - new_lines: "\nhello world\ndef\nghi".to_string(), - }; - let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || { - vec!["hello world".to_string()] - }); - assert_eq!(expected, result); -} - -#[test] -fn test_replace_region_no_changes() { - let text = "123\n456\n789"; - let expected = FileChange { - changed: false, - new_lines: "123\n456\n789".to_string(), - }; - let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new); - assert_eq!(expected, result); -} - -#[test] -fn test_usable_lints() { - let lints = vec![ - Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"), - Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"), - Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"), - Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"), - ]; - let expected = vec![Lint::new( - "should_assert_eq2", - "Not Deprecated", - "abc", - None, - "module_name", - )]; - assert_eq!(expected, Lint::usable_lints(&lints)); -} - -#[test] -fn test_by_lint_group() { - let lints = vec![ - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), - Lint::new("incorrect_match", "group1", "abc", None, "module_name"), - ]; - let mut expected: HashMap> = HashMap::new(); - expected.insert( - "group1".to_string(), - vec![ - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("incorrect_match", "group1", "abc", None, "module_name"), - ], - ); - expected.insert( - "group2".to_string(), - vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")], - ); - assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); -} - -#[test] -fn test_gen_changelog_lint_list() { - let lints = vec![ - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), - ]; - let expected = vec![ - format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()), - format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()), - ]; - assert_eq!(expected, gen_changelog_lint_list(lints.iter())); -} - -#[test] -fn test_gen_deprecated() { - let lints = vec![ - Lint::new( - "should_assert_eq", - "group1", - "abc", - Some("has been superseded by should_assert_eq2"), - "module_name", - ), - Lint::new( - "another_deprecated", - "group2", - "abc", - Some("will be removed"), - "module_name", - ), - ]; - let expected: Vec = vec![ - " store.register_removed(", - " \"clippy::should_assert_eq\",", - " \"has been superseded by should_assert_eq2\",", - " );", - " store.register_removed(", - " \"clippy::another_deprecated\",", - " \"will be removed\",", - " );", - ] - .into_iter() - .map(String::from) - .collect(); - assert_eq!(expected, gen_deprecated(lints.iter())); -} - -#[test] -#[should_panic] -fn test_gen_deprecated_fail() { - let lints = vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")]; - let _deprecated_lints = gen_deprecated(lints.iter()); -} - -#[test] -fn test_gen_modules_list() { - let lints = vec![ - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"), - ]; - let expected = vec!["mod another_module;".to_string(), "mod module_name;".to_string()]; - assert_eq!(expected, gen_modules_list(lints.iter())); -} - -#[test] -fn test_gen_lint_group_list() { - let lints = vec![ - Lint::new("abc", "group1", "abc", None, "module_name"), - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("internal", "internal_style", "abc", None, "module_name"), - ]; - let expected = vec![ - " LintId::of(module_name::ABC),".to_string(), - " LintId::of(module_name::INTERNAL),".to_string(), - " LintId::of(module_name::SHOULD_ASSERT_EQ),".to_string(), - ]; - assert_eq!(expected, gen_lint_group_list(lints.iter())); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/main.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,7 +3,7 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; -use clippy_dev::{bless, fmt, new_lint, serve, setup, stderr_length_check, update_lints}; +use clippy_dev::{bless, fmt, new_lint, serve, setup, update_lints}; fn main() { let matches = get_clap_config(); @@ -33,9 +33,6 @@ Err(e) => eprintln!("Unable to create lint: {}", e), } }, - ("limit_stderr_length", _) => { - stderr_length_check::check(); - }, ("setup", Some(sub_command)) => match sub_command.subcommand() { ("intellij", Some(matches)) => setup::intellij::setup_rustc_src( matches @@ -153,10 +150,6 @@ ), ) .subcommand( - SubCommand::with_name("limit_stderr_length") - .about("Ensures that stderr files do not grow longer than a certain amount of lines."), - ) - .subcommand( SubCommand::with_name("setup") .about("Support for setting up your personal development environment") .setting(AppSettings::ArgRequiredElseHelp) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/stderr_length_check.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/stderr_length_check.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/stderr_length_check.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/stderr_length_check.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -use crate::clippy_project_root; -use std::ffi::OsStr; -use std::fs; -use std::path::{Path, PathBuf}; -use walkdir::WalkDir; - -// The maximum length allowed for stderr files. -// -// We limit this because small files are easier to deal with than bigger files. -const LENGTH_LIMIT: usize = 200; - -pub fn check() { - let exceeding_files: Vec<_> = exceeding_stderr_files(); - - if !exceeding_files.is_empty() { - eprintln!("Error: stderr files exceeding limit of {} lines:", LENGTH_LIMIT); - for (path, count) in exceeding_files { - println!("{}: {}", path.display(), count); - } - std::process::exit(1); - } -} - -fn exceeding_stderr_files() -> Vec<(PathBuf, usize)> { - // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories. - WalkDir::new(clippy_project_root().join("tests/ui")) - .into_iter() - .filter_map(Result::ok) - .filter(|f| !f.file_type().is_dir()) - .filter_map(|e| { - let p = e.into_path(); - let count = count_linenumbers(&p); - if p.extension() == Some(OsStr::new("stderr")) && count > LENGTH_LIMIT { - Some((p, count)) - } else { - None - } - }) - .collect() -} - -#[must_use] -fn count_linenumbers(filepath: &Path) -> usize { - match fs::read(filepath) { - Ok(content) => bytecount::count(&content, b'\n'), - Err(e) => { - eprintln!("Failed to read file: {}", e); - 0 - }, - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/update_lints.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/update_lints.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/update_lints.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dev/src/update_lints.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,45 @@ -use crate::{ - gather_all, gen_changelog_lint_list, gen_deprecated, gen_lint_group_list, gen_modules_list, gen_register_lint_list, - replace_region_in_file, Lint, DOCS_LINK, -}; +use itertools::Itertools; +use regex::Regex; +use std::collections::HashMap; +use std::ffi::OsStr; +use std::fs; +use std::lazy::SyncLazy; use std::path::Path; +use walkdir::WalkDir; + +use crate::clippy_project_root; + +const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\ + // Use that command to update this file and do not edit by hand.\n\ + // Manual edits will be overwritten.\n\n"; + +static DEC_CLIPPY_LINT_RE: SyncLazy = SyncLazy::new(|| { + Regex::new( + r#"(?x) + declare_clippy_lint!\s*[\{(] + (?:\s+///.*)* + \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* + (?P[a-z_]+)\s*,\s* + "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] +"#, + ) + .unwrap() +}); + +static DEC_DEPRECATED_LINT_RE: SyncLazy = SyncLazy::new(|| { + Regex::new( + r#"(?x) + declare_deprecated_lint!\s*[{(]\s* + (?:\s+///.*)* + \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* + "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] +"#, + ) + .unwrap() +}); +static NL_ESCAPE_RE: SyncLazy = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap()); + +static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; #[derive(Clone, Copy, PartialEq)] pub enum UpdateMode { @@ -10,6 +47,15 @@ Change, } +/// Runs the `update_lints` command. +/// +/// This updates various generated values from the lint source code. +/// +/// `update_mode` indicates if the files should be updated or if updates should be checked for. +/// +/// # Panics +/// +/// Panics if a file path could not read from or then written to #[allow(clippy::too_many_lines)] pub fn run(update_mode: UpdateMode) { let lint_list: Vec = gather_all().collect(); @@ -52,26 +98,7 @@ ) .changed; - file_change |= replace_region_in_file( - Path::new("clippy_lints/src/lib.rs"), - "begin deprecated lints", - "end deprecated lints", - false, - update_mode == UpdateMode::Change, - || gen_deprecated(deprecated_lints.iter()), - ) - .changed; - - file_change |= replace_region_in_file( - Path::new("clippy_lints/src/lib.rs"), - "begin register lints", - "end register lints", - false, - update_mode == UpdateMode::Change, - || gen_register_lint_list(internal_lints.iter(), usable_lints.iter()), - ) - .changed; - + // This has to be in lib.rs, otherwise rustfmt doesn't work file_change |= replace_region_in_file( Path::new("clippy_lints/src/lib.rs"), "begin lints modules", @@ -82,46 +109,37 @@ ) .changed; - // Generate lists of lints in the clippy::all lint group - file_change |= replace_region_in_file( - Path::new("clippy_lints/src/lib.rs"), - r#"store.register_group\(true, "clippy::all""#, - r#"\]\);"#, - false, - update_mode == UpdateMode::Change, - || { - // clippy::all should only include the following lint groups: - let all_group_lints = usable_lints.iter().filter(|l| { - matches!( - &*l.group, - "correctness" | "suspicious" | "style" | "complexity" | "perf" - ) - }); - - gen_lint_group_list(all_group_lints) - }, - ) - .changed; + if file_change && update_mode == UpdateMode::Check { + exit_with_failure(); + } - // Generate the list of lints for all other lint groups - for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { - file_change |= replace_region_in_file( - Path::new("clippy_lints/src/lib.rs"), - &format!("store.register_group\\(true, \"clippy::{}\"", lint_group), - r#"\]\);"#, - false, - update_mode == UpdateMode::Change, - || gen_lint_group_list(lints.iter()), + process_file( + "clippy_lints/src/lib.register_lints.rs", + update_mode, + &gen_register_lint_list(internal_lints.iter(), usable_lints.iter()), + ); + process_file( + "clippy_lints/src/lib.deprecated.rs", + update_mode, + &gen_deprecated(deprecated_lints.iter()), + ); + + let all_group_lints = usable_lints.iter().filter(|l| { + matches!( + &*l.group, + "correctness" | "suspicious" | "style" | "complexity" | "perf" ) - .changed; - } + }); + let content = gen_lint_group_list("all", all_group_lints); + process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content); - if update_mode == UpdateMode::Check && file_change { - println!( - "Not all lints defined properly. \ - Please run `cargo dev update_lints` to make sure all lints are defined properly." + for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { + let content = gen_lint_group_list(&lint_group, lints.iter()); + process_file( + &format!("clippy_lints/src/lib.register_{}.rs", lint_group), + update_mode, + &content, ); - std::process::exit(1); } } @@ -150,3 +168,538 @@ fn round_to_fifty(count: usize) -> usize { count / 50 * 50 } + +fn process_file(path: impl AsRef, update_mode: UpdateMode, content: &str) { + if update_mode == UpdateMode::Check { + let old_content = + fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.as_ref().display(), e)); + if content != old_content { + exit_with_failure(); + } + } else { + fs::write(&path, content.as_bytes()) + .unwrap_or_else(|e| panic!("Cannot write to {}: {}", path.as_ref().display(), e)); + } +} + +fn exit_with_failure() { + println!( + "Not all lints defined properly. \ + Please run `cargo dev update_lints` to make sure all lints are defined properly." + ); + std::process::exit(1); +} + +/// Lint data parsed from the Clippy source code. +#[derive(Clone, PartialEq, Debug)] +struct Lint { + name: String, + group: String, + desc: String, + deprecation: Option, + module: String, +} + +impl Lint { + #[must_use] + fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self { + Self { + name: name.to_lowercase(), + group: group.to_string(), + desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(), + deprecation: deprecation.map(ToString::to_string), + module: module.to_string(), + } + } + + /// Returns all non-deprecated lints and non-internal lints + #[must_use] + fn usable_lints(lints: &[Self]) -> Vec { + lints + .iter() + .filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal")) + .cloned() + .collect() + } + + /// Returns all internal lints (not `internal_warn` lints) + #[must_use] + fn internal_lints(lints: &[Self]) -> Vec { + lints.iter().filter(|l| l.group == "internal").cloned().collect() + } + + /// Returns all deprecated lints + #[must_use] + fn deprecated_lints(lints: &[Self]) -> Vec { + lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect() + } + + /// Returns the lints in a `HashMap`, grouped by the different lint groups + #[must_use] + fn by_lint_group(lints: impl Iterator) -> HashMap> { + lints.map(|lint| (lint.group.to_string(), lint)).into_group_map() + } +} + +/// Generates the code for registering a group +fn gen_lint_group_list<'a>(group_name: &str, lints: impl Iterator) -> String { + let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect(); + details.sort_unstable(); + + let mut output = GENERATED_FILE_COMMENT.to_string(); + + output.push_str(&format!( + "store.register_group(true, \"clippy::{0}\", Some(\"clippy_{0}\"), vec![\n", + group_name + )); + for (module, name) in details { + output.push_str(&format!(" LintId::of({}::{}),\n", module, name)); + } + output.push_str("])\n"); + + output +} + +/// Generates the module declarations for `lints` +#[must_use] +fn gen_modules_list<'a>(lints: impl Iterator) -> Vec { + lints + .map(|l| &l.module) + .unique() + .map(|module| format!("mod {};", module)) + .sorted() + .collect::>() +} + +/// Generates the list of lint links at the bottom of the CHANGELOG +#[must_use] +fn gen_changelog_lint_list<'a>(lints: impl Iterator) -> Vec { + lints + .sorted_by_key(|l| &l.name) + .map(|l| format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name)) + .collect() +} + +/// Generates the `register_removed` code +#[must_use] +fn gen_deprecated<'a>(lints: impl Iterator) -> String { + let mut output = GENERATED_FILE_COMMENT.to_string(); + output.push_str("{\n"); + for Lint { name, deprecation, .. } in lints { + output.push_str(&format!( + concat!( + " store.register_removed(\n", + " \"clippy::{}\",\n", + " \"{}\",\n", + " );\n" + ), + name, + deprecation.as_ref().expect("`lints` are deprecated") + )); + } + output.push_str("}\n"); + + output +} + +/// Generates the code for registering lints +#[must_use] +fn gen_register_lint_list<'a>( + internal_lints: impl Iterator, + usable_lints: impl Iterator, +) -> String { + let mut details: Vec<_> = internal_lints + .map(|l| (false, &l.module, l.name.to_uppercase())) + .chain(usable_lints.map(|l| (true, &l.module, l.name.to_uppercase()))) + .collect(); + details.sort_unstable(); + + let mut output = GENERATED_FILE_COMMENT.to_string(); + output.push_str("store.register_lints(&[\n"); + + for (is_public, module_name, lint_name) in details { + if !is_public { + output.push_str(" #[cfg(feature = \"internal-lints\")]\n"); + } + output.push_str(&format!(" {}::{},\n", module_name, lint_name)); + } + output.push_str("])\n"); + + output +} + +/// Gathers all files in `src/clippy_lints` and gathers all lints inside +fn gather_all() -> impl Iterator { + lint_files().flat_map(|f| gather_from_file(&f)) +} + +fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator { + let content = fs::read_to_string(dir_entry.path()).unwrap(); + let path = dir_entry.path(); + let filename = path.file_stem().unwrap(); + let path_buf = path.with_file_name(filename); + let mut rel_path = path_buf + .strip_prefix(clippy_project_root().join("clippy_lints/src")) + .expect("only files in `clippy_lints/src` should be looked at"); + // If the lints are stored in mod.rs, we get the module name from + // the containing directory: + if filename == "mod" { + rel_path = rel_path.parent().unwrap(); + } + + let module = rel_path + .components() + .map(|c| c.as_os_str().to_str().unwrap()) + .collect::>() + .join("::"); + + parse_contents(&content, &module) +} + +fn parse_contents(content: &str, module: &str) -> impl Iterator { + let lints = DEC_CLIPPY_LINT_RE + .captures_iter(content) + .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, module)); + let deprecated = DEC_DEPRECATED_LINT_RE + .captures_iter(content) + .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), module)); + // Removing the `.collect::>().into_iter()` causes some lifetime issues due to the map + lints.chain(deprecated).collect::>().into_iter() +} + +/// Collects all .rs files in the `clippy_lints/src` directory +fn lint_files() -> impl Iterator { + // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories. + // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`. + let path = clippy_project_root().join("clippy_lints/src"); + WalkDir::new(path) + .into_iter() + .filter_map(Result::ok) + .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) +} + +/// Whether a file has had its text changed or not +#[derive(PartialEq, Debug)] +struct FileChange { + changed: bool, + new_lines: String, +} + +/// Replaces a region in a file delimited by two lines matching regexes. +/// +/// `path` is the relative path to the file on which you want to perform the replacement. +/// +/// See `replace_region_in_text` for documentation of the other options. +/// +/// # Panics +/// +/// Panics if the path could not read or then written +fn replace_region_in_file( + path: &Path, + start: &str, + end: &str, + replace_start: bool, + write_back: bool, + replacements: F, +) -> FileChange +where + F: FnOnce() -> Vec, +{ + let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.display(), e)); + let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements); + + if write_back { + if let Err(e) = fs::write(path, file_change.new_lines.as_bytes()) { + panic!("Cannot write to {}: {}", path.display(), e); + } + } + file_change +} + +/// Replaces a region in a text delimited by two lines matching regexes. +/// +/// * `text` is the input text on which you want to perform the replacement +/// * `start` is a `&str` that describes the delimiter line before the region you want to replace. +/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. +/// * `end` is a `&str` that describes the delimiter line until where the replacement should happen. +/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. +/// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end` +/// delimiter line is never replaced. +/// * `replacements` is a closure that has to return a `Vec` which contains the new text. +/// +/// If you want to perform the replacement on files instead of already parsed text, +/// use `replace_region_in_file`. +/// +/// # Example +/// +/// ```ignore +/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end"; +/// let result = +/// replace_region_in_text(the_text, "replace_start", "replace_end", false, || { +/// vec!["a different".to_string(), "text".to_string()] +/// }) +/// .new_lines; +/// assert_eq!("replace_start\na different\ntext\nreplace_end", result); +/// ``` +/// +/// # Panics +/// +/// Panics if start or end is not valid regex +fn replace_region_in_text(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange +where + F: FnOnce() -> Vec, +{ + let replace_it = replacements(); + let mut in_old_region = false; + let mut found = false; + let mut new_lines = vec![]; + let start = Regex::new(start).unwrap(); + let end = Regex::new(end).unwrap(); + + for line in text.lines() { + if in_old_region { + if end.is_match(line) { + in_old_region = false; + new_lines.extend(replace_it.clone()); + new_lines.push(line.to_string()); + } + } else if start.is_match(line) { + if !replace_start { + new_lines.push(line.to_string()); + } + in_old_region = true; + found = true; + } else { + new_lines.push(line.to_string()); + } + } + + if !found { + // This happens if the provided regex in `clippy_dev/src/main.rs` does not match in the + // given text or file. Most likely this is an error on the programmer's side and the Regex + // is incorrect. + eprintln!("error: regex \n{:?}\ndoesn't match. You may have to update it.", start); + std::process::exit(1); + } + + let mut new_lines = new_lines.join("\n"); + if text.ends_with('\n') { + new_lines.push('\n'); + } + let changed = new_lines != text; + FileChange { changed, new_lines } +} + +#[test] +fn test_parse_contents() { + let result: Vec = parse_contents( + r#" +declare_clippy_lint! { + pub PTR_ARG, + style, + "really long \ + text" +} + +declare_clippy_lint!{ + pub DOC_MARKDOWN, + pedantic, + "single line" +} + +/// some doc comment +declare_deprecated_lint! { + pub SHOULD_ASSERT_EQ, + "`assert!()` will be more flexible with RFC 2011" +} + "#, + "module_name", + ) + .collect(); + + let expected = vec![ + Lint::new("ptr_arg", "style", "really long text", None, "module_name"), + Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"), + Lint::new( + "should_assert_eq", + "Deprecated", + "`assert!()` will be more flexible with RFC 2011", + Some("`assert!()` will be more flexible with RFC 2011"), + "module_name", + ), + ]; + assert_eq!(expected, result); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_replace_region() { + let text = "\nabc\n123\n789\ndef\nghi"; + let expected = FileChange { + changed: true, + new_lines: "\nabc\nhello world\ndef\nghi".to_string(), + }; + let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || { + vec!["hello world".to_string()] + }); + assert_eq!(expected, result); + } + + #[test] + fn test_replace_region_with_start() { + let text = "\nabc\n123\n789\ndef\nghi"; + let expected = FileChange { + changed: true, + new_lines: "\nhello world\ndef\nghi".to_string(), + }; + let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || { + vec!["hello world".to_string()] + }); + assert_eq!(expected, result); + } + + #[test] + fn test_replace_region_no_changes() { + let text = "123\n456\n789"; + let expected = FileChange { + changed: false, + new_lines: "123\n456\n789".to_string(), + }; + let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new); + assert_eq!(expected, result); + } + + #[test] + fn test_usable_lints() { + let lints = vec![ + Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"), + Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"), + ]; + let expected = vec![Lint::new( + "should_assert_eq2", + "Not Deprecated", + "abc", + None, + "module_name", + )]; + assert_eq!(expected, Lint::usable_lints(&lints)); + } + + #[test] + fn test_by_lint_group() { + let lints = vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), + Lint::new("incorrect_match", "group1", "abc", None, "module_name"), + ]; + let mut expected: HashMap> = HashMap::new(); + expected.insert( + "group1".to_string(), + vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("incorrect_match", "group1", "abc", None, "module_name"), + ], + ); + expected.insert( + "group2".to_string(), + vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")], + ); + assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); + } + + #[test] + fn test_gen_changelog_lint_list() { + let lints = vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), + ]; + let expected = vec![ + format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()), + format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()), + ]; + assert_eq!(expected, gen_changelog_lint_list(lints.iter())); + } + + #[test] + fn test_gen_deprecated() { + let lints = vec![ + Lint::new( + "should_assert_eq", + "group1", + "abc", + Some("has been superseded by should_assert_eq2"), + "module_name", + ), + Lint::new( + "another_deprecated", + "group2", + "abc", + Some("will be removed"), + "module_name", + ), + ]; + + let expected = GENERATED_FILE_COMMENT.to_string() + + &[ + "{", + " store.register_removed(", + " \"clippy::should_assert_eq\",", + " \"has been superseded by should_assert_eq2\",", + " );", + " store.register_removed(", + " \"clippy::another_deprecated\",", + " \"will be removed\",", + " );", + "}", + ] + .join("\n") + + "\n"; + + assert_eq!(expected, gen_deprecated(lints.iter())); + } + + #[test] + #[should_panic] + fn test_gen_deprecated_fail() { + let lints = vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")]; + let _deprecated_lints = gen_deprecated(lints.iter()); + } + + #[test] + fn test_gen_modules_list() { + let lints = vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"), + ]; + let expected = vec!["mod another_module;".to_string(), "mod module_name;".to_string()]; + assert_eq!(expected, gen_modules_list(lints.iter())); + } + + #[test] + fn test_gen_lint_group_list() { + let lints = vec![ + Lint::new("abc", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("internal", "internal_style", "abc", None, "module_name"), + ]; + let expected = GENERATED_FILE_COMMENT.to_string() + + &[ + "store.register_group(true, \"clippy::group1\", Some(\"clippy_group1\"), vec![", + " LintId::of(module_name::ABC),", + " LintId::of(module_name::INTERNAL),", + " LintId::of(module_name::SHOULD_ASSERT_EQ),", + "])", + ] + .join("\n") + + "\n"; + + let result = gen_lint_group_list("group1", lints.iter()); + + assert_eq!(expected, result); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dummy/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dummy/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_dummy/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_dummy/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -13,4 +13,4 @@ categories = ["development-tools", "development-tools::cargo-plugins"] [build-dependencies] -term = "0.6" +term = "0.7" diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,33 +1,31 @@ [package] name = "clippy_lints" -# begin automatic update -version = "0.1.56" -# end automatic update +version = "0.1.57" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" license = "MIT OR Apache-2.0" keywords = ["clippy", "lint", "plugin"] -edition = "2018" +edition = "2021" [dependencies] cargo_metadata = "0.12" clippy_utils = { path = "../clippy_utils" } -if_chain = "1.0.0" -itertools = "0.9" +if_chain = "1.0" +itertools = "0.10" pulldown-cmark = { version = "0.8", default-features = false } -quine-mc_cluskey = "0.2.2" +quine-mc_cluskey = "0.2" regex-syntax = "0.6" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } -toml = "0.5.3" +toml = "0.5" unicode-normalization = "0.1" -unicode-script = { version = "0.5.3", default-features = false } +unicode-script = { version = "0.5", default-features = false } semver = "0.11" -rustc-semver = "1.1.0" +rustc-semver = "1.1" # NOTE: cargo requires serde feat in its url dep # see -url = { version = "2.1.0", features = ["serde"] } +url = { version = "2.2", features = ["serde"] } [features] deny-warnings = ["clippy_utils/deny-warnings"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/approx_const.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/approx_const.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/approx_const.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/approx_const.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,10 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol; use std::f64::consts as f64; @@ -36,68 +38,82 @@ "the approximate of a known float constant (in `std::fXX::consts`)" } -// Tuples are of the form (constant, name, min_digits) -const KNOWN_CONSTS: [(f64, &str, usize); 18] = [ - (f64::E, "E", 4), - (f64::FRAC_1_PI, "FRAC_1_PI", 4), - (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), - (f64::FRAC_2_PI, "FRAC_2_PI", 5), - (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), - (f64::FRAC_PI_2, "FRAC_PI_2", 5), - (f64::FRAC_PI_3, "FRAC_PI_3", 5), - (f64::FRAC_PI_4, "FRAC_PI_4", 5), - (f64::FRAC_PI_6, "FRAC_PI_6", 5), - (f64::FRAC_PI_8, "FRAC_PI_8", 5), - (f64::LN_10, "LN_10", 5), - (f64::LN_2, "LN_2", 5), - (f64::LOG10_E, "LOG10_E", 5), - (f64::LOG2_E, "LOG2_E", 5), - (f64::LOG2_10, "LOG2_10", 5), - (f64::LOG10_2, "LOG10_2", 5), - (f64::PI, "PI", 3), - (f64::SQRT_2, "SQRT_2", 5), +// Tuples are of the form (constant, name, min_digits, msrv) +const KNOWN_CONSTS: [(f64, &str, usize, Option); 19] = [ + (f64::E, "E", 4, None), + (f64::FRAC_1_PI, "FRAC_1_PI", 4, None), + (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5, None), + (f64::FRAC_2_PI, "FRAC_2_PI", 5, None), + (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5, None), + (f64::FRAC_PI_2, "FRAC_PI_2", 5, None), + (f64::FRAC_PI_3, "FRAC_PI_3", 5, None), + (f64::FRAC_PI_4, "FRAC_PI_4", 5, None), + (f64::FRAC_PI_6, "FRAC_PI_6", 5, None), + (f64::FRAC_PI_8, "FRAC_PI_8", 5, None), + (f64::LN_2, "LN_2", 5, None), + (f64::LN_10, "LN_10", 5, None), + (f64::LOG2_10, "LOG2_10", 5, Some(msrvs::LOG2_10)), + (f64::LOG2_E, "LOG2_E", 5, None), + (f64::LOG10_2, "LOG10_2", 5, Some(msrvs::LOG10_2)), + (f64::LOG10_E, "LOG10_E", 5, None), + (f64::PI, "PI", 3, None), + (f64::SQRT_2, "SQRT_2", 5, None), + (f64::TAU, "TAU", 3, Some(msrvs::TAU)), ]; -declare_lint_pass!(ApproxConstant => [APPROX_CONSTANT]); +pub struct ApproxConstant { + msrv: Option, +} -impl<'tcx> LateLintPass<'tcx> for ApproxConstant { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Lit(lit) = &e.kind { - check_lit(cx, &lit.node, e); +impl ApproxConstant { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } + + fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { + match *lit { + LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { + FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"), + FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"), + }, + LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"), + _ => (), } } -} -fn check_lit(cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { - match *lit { - LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { - FloatTy::F32 => check_known_consts(cx, e, s, "f32"), - FloatTy::F64 => check_known_consts(cx, e, s, "f64"), - }, - LitKind::Float(s, LitFloatType::Unsuffixed) => check_known_consts(cx, e, s, "f{32, 64}"), - _ => (), + fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) { + let s = s.as_str(); + if s.parse::().is_ok() { + for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { + if is_approx_const(constant, &s, min_digits) + && msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv)) + { + span_lint_and_help( + cx, + APPROX_CONSTANT, + e.span, + &format!("approximate value of `{}::consts::{}` found", module, &name), + None, + "consider using the constant directly", + ); + return; + } + } + } } } -fn check_known_consts(cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) { - let s = s.as_str(); - if s.parse::().is_ok() { - for &(constant, name, min_digits) in &KNOWN_CONSTS { - if is_approx_const(constant, &s, min_digits) { - span_lint( - cx, - APPROX_CONSTANT, - e.span, - &format!( - "approximate value of `{}::consts::{}` found. \ - Consider using it directly", - module, &name - ), - ); - return; - } +impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]); + +impl<'tcx> LateLintPass<'tcx> for ApproxConstant { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Lit(lit) = &e.kind { + self.check_lit(cx, &lit.node, e); } } + + extract_msrv_attr!(LateContext); } /// Returns `false` if the number of significant figures in `value` are diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs 2021-11-29 19:27:12.000000000 +0000 @@ -118,7 +118,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { if_chain! { if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr); - if let ExprKind::Unary(UnOp::Not, ref expr) = cond.kind; + if let ExprKind::Unary(UnOp::Not, expr) = cond.kind; // bind the first argument of the `assert!` macro if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr); // block diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/attrs.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/attrs.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/attrs.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/attrs.rs 2021-11-29 19:27:12.000000000 +0000 @@ -527,8 +527,8 @@ return; } - let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt()); - let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt()); + let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); + let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent()); if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) { let lines = snippet.split('\n').collect::>(); @@ -563,7 +563,7 @@ skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym::skip; // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 - if let AttrStyle::Outer = attr.style; + if attr.style == AttrStyle::Outer; then { span_lint_and_sugg( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs 2021-11-29 19:27:12.000000000 +0000 @@ -16,7 +16,7 @@ /// The Mutex types found in std::sync and parking_lot /// are not designed to operate in an async context across await points. /// - /// There are two potential solutions. One is to use an asynx-aware Mutex + /// There are two potential solutions. One is to use an async-aware Mutex /// type. Many asynchronous foundation crates provide such a Mutex type. The /// other solution is to ensure the mutex is unlocked before calling await, /// either by introducing a scope or an explicit call to Drop::drop. diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs 2021-11-29 19:27:12.000000000 +0000 @@ -61,8 +61,8 @@ // do not lint if the closure is called using an iterator (see #1141) if_chain! { if let Some(parent) = get_parent_expr(self.cx, expr); - if let ExprKind::MethodCall(_, _, args, _) = parent.kind; - let caller = self.cx.typeck_results().expr_ty(&args[0]); + if let ExprKind::MethodCall(_, _, [self_arg, ..], _) = &parent.kind; + let caller = self.cx.typeck_results().expr_ty(self_arg); if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(self.cx, caller, iter_id, &[]); then { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,11 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{ast_utils, is_direct_expn_of}; -use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; +use clippy_utils::{diagnostics::span_lint_and_sugg, higher, is_direct_expn_of, ty::implements_trait}; +use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::{Expr, ExprKind, Lit}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does @@ -28,45 +30,77 @@ declare_lint_pass!(BoolAssertComparison => [BOOL_ASSERT_COMPARISON]); -fn is_bool_lit(e: &Expr) -> bool { +fn is_bool_lit(e: &Expr<'_>) -> bool { matches!( e.kind, ExprKind::Lit(Lit { - kind: LitKind::Bool(_), + node: LitKind::Bool(_), .. }) ) && !e.span.from_expansion() } -impl EarlyLintPass for BoolAssertComparison { - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { +fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(e); + + cx.tcx + .lang_items() + .not_trait() + .filter(|trait_id| implements_trait(cx, ty, *trait_id, &[])) + .and_then(|trait_id| { + cx.tcx.associated_items(trait_id).find_by_name_and_kind( + cx.tcx, + Ident::from_str("Output"), + ty::AssocKind::Type, + trait_id, + ) + }) + .map_or(false, |assoc_item| { + let proj = cx.tcx.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(ty, &[])); + let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj); + + nty.is_bool() + }) +} + +impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let macros = ["assert_eq", "debug_assert_eq"]; let inverted_macros = ["assert_ne", "debug_assert_ne"]; for mac in macros.iter().chain(inverted_macros.iter()) { - if let Some(span) = is_direct_expn_of(e.span, mac) { - if let Some([a, b]) = ast_utils::extract_assert_macro_args(e) { - let nb_bool_args = is_bool_lit(a) as usize + is_bool_lit(b) as usize; - - if nb_bool_args != 1 { - // If there are two boolean arguments, we definitely don't understand - // what's going on, so better leave things as is... - // - // Or there is simply no boolean and then we can leave things as is! + if let Some(span) = is_direct_expn_of(expr.span, mac) { + if let Some(args) = higher::extract_assert_macro_args(expr) { + if let [a, b, ..] = args[..] { + let nb_bool_args = is_bool_lit(a) as usize + is_bool_lit(b) as usize; + + if nb_bool_args != 1 { + // If there are two boolean arguments, we definitely don't understand + // what's going on, so better leave things as is... + // + // Or there is simply no boolean and then we can leave things as is! + return; + } + + if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) { + // At this point the expression which is not a boolean + // literal does not implement Not trait with a bool output, + // so we cannot suggest to rewrite our code + return; + } + + let non_eq_mac = &mac[..mac.len() - 3]; + span_lint_and_sugg( + cx, + BOOL_ASSERT_COMPARISON, + span, + &format!("used `{}!` with a literal bool", mac), + "replace it with", + format!("{}!(..)", non_eq_mac), + Applicability::MaybeIncorrect, + ); return; } - - let non_eq_mac = &mac[..mac.len() - 3]; - span_lint_and_sugg( - cx, - BOOL_ASSERT_COMPARISON, - span, - &format!("used `{}!` with a literal bool", mac), - "replace it with", - format!("{}!(..)", non_eq_mac), - Applicability::MaybeIncorrect, - ); - return; } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/booleans.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/booleans.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/booleans.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/booleans.rs 2021-11-29 19:27:12.000000000 +0000 @@ -260,8 +260,8 @@ }, ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => { let type_of_receiver = cx.typeck_results().expr_ty(&args[0]); - if !is_type_diagnostic_item(cx, type_of_receiver, sym::option_type) - && !is_type_diagnostic_item(cx, type_of_receiver, sym::result_type) + if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option) + && !is_type_diagnostic_item(cx, type_of_receiver, sym::Result) { return None; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/bytecount.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/bytecount.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/bytecount.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/bytecount.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::match_type; -use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::visitors::is_local_used; use clippy_utils::{path_to_local_id, paths, peel_ref_operators, remove_blocks, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -65,7 +65,7 @@ return; }; if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); - if !LocalUsedVisitor::new(cx, arg_id).check_expr(needle); + if !is_local_used(cx, needle, arg_id); then { let haystack = if let ExprKind::MethodCall(path, _, args, _) = filter_recv.kind { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,7 @@ //! lint on missing cargo common metadata -use std::path::PathBuf; - use clippy_utils::{diagnostics::span_lint, is_lint_allowed}; -use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; +use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::DUMMY_SP; @@ -69,12 +67,8 @@ span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); } -fn is_empty_str(value: &Option) -> bool { - value.as_ref().map_or(true, String::is_empty) -} - -fn is_empty_path(value: &Option) -> bool { - value.as_ref().and_then(|x| x.to_str()).map_or(true, str::is_empty) +fn is_empty_str>(value: &Option) -> bool { + value.as_ref().map_or(true, |s| s.as_ref().is_empty()) } fn is_empty_vec(value: &[String]) -> bool { @@ -83,7 +77,7 @@ } impl LateLintPass<'_> for CargoCommonMetadata { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'_>) { if is_lint_allowed(cx, CARGO_COMMON_METADATA, CRATE_HIR_ID) { return; } @@ -98,7 +92,7 @@ missing_warning(cx, &package, "package.description"); } - if is_empty_str(&package.license) && is_empty_path(&package.license_file) { + if is_empty_str(&package.license) && is_empty_str(&package.license_file) { missing_warning(cx, &package, "either package.license or package.license_file"); } @@ -106,7 +100,7 @@ missing_warning(cx, &package, "package.repository"); } - if is_empty_path(&package.readme) { + if is_empty_str(&package.readme) { missing_warning(cx, &package, "package.readme"); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs 2021-11-29 19:27:12.000000000 +0000 @@ -55,7 +55,7 @@ return Some(span); }, ty::Adt(&ty::AdtDef { did, .. }, _) => { - if ctx.tcx.is_diagnostic_item(sym::string_type, did) { + if ctx.tcx.is_diagnostic_item(sym::String, did) { return Some(span); } }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs 2021-11-29 19:27:12.000000000 +0000 @@ -12,7 +12,7 @@ } let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() { + let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) { 32 } else { 64 diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,9 +3,9 @@ use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; -use rustc_target::abi::LayoutOf; use super::CAST_PTR_ALIGNMENT; @@ -19,7 +19,7 @@ cx.typeck_results().expr_ty(expr), ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); - } else if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind { + } else if let ExprKind::MethodCall(method_path, _, [self_arg, ..], _) = &expr.kind { if_chain! { if method_path.ident.name == sym!(cast); if let Some(generic_args) = method_path.args; @@ -28,7 +28,7 @@ if !is_hir_ty_cfg_dependant(cx, cast_to); then { let (cast_from, cast_to) = - (cx.typeck_results().expr_ty(&args[0]), cx.typeck_results().expr_ty(expr)); + (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs 2021-11-29 19:27:12.000000000 +0000 @@ -67,7 +67,7 @@ helper.visit_expr(expr); let CcHelper { cc, returns } = helper; let ret_ty = cx.typeck_results().node_type(expr.hir_id); - let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::result_type) { + let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) { returns } else { #[allow(clippy::integer_division)] @@ -95,7 +95,7 @@ }); if let Some((low, high)) = pos { - Span::new(low, high, header_span.ctxt()) + Span::new(low, high, header_span.ctxt(), header_span.parent()) } else { return; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/collapsible_match.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/collapsible_match.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/collapsible_match.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/collapsible_match.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::LocalUsedVisitor; -use clippy_utils::{higher, is_lang_ctor, is_unit_expr, path_to_local, peel_ref_operators, SpanlessEq}; +use clippy_utils::higher::IfLetOrMatch; +use clippy_utils::visitors::is_local_used; +use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_ref_operators, SpanlessEq}; use if_chain::if_chain; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, MatchSource, Pat, PatKind, StmtKind}; +use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{MultiSpan, Span}; @@ -56,11 +57,11 @@ check_arm(cx, true, arm.pat, arm.body, arm.guard.as_ref(), Some(els_arm.body)); } } - } + }, Some(IfLetOrMatch::IfLet(_, pat, body, els)) => { check_arm(cx, false, pat, body, None, els); - } - None => {} + }, + None => {}, } } } @@ -71,7 +72,7 @@ outer_pat: &'tcx Pat<'tcx>, outer_then_body: &'tcx Expr<'tcx>, outer_guard: Option<&'tcx Guard<'tcx>>, - outer_else_body: Option<&'tcx Expr<'tcx>> + outer_else_body: Option<&'tcx Expr<'tcx>>, ) { let inner_expr = strip_singleton_blocks(outer_then_body); if_chain! { @@ -106,14 +107,13 @@ (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b), }; // the binding must not be used in the if guard - let mut used_visitor = LocalUsedVisitor::new(cx, binding_id); - if outer_guard.map_or(true, |(Guard::If(e) | Guard::IfLet(_, e))| !used_visitor.check_expr(e)); + if outer_guard.map_or(true, |(Guard::If(e) | Guard::IfLet(_, e))| !is_local_used(cx, *e, binding_id)); // ...or anywhere in the inner expression if match inner { IfLetOrMatch::IfLet(_, _, body, els) => { - !used_visitor.check_expr(body) && els.map_or(true, |e| !used_visitor.check_expr(e)) + !is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id)) }, - IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| used_visitor.check_arm(arm)), + IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)), }; then { let msg = format!( @@ -151,23 +151,6 @@ expr } -enum IfLetOrMatch<'hir> { - Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource), - /// scrutinee, pattern, then block, else block - IfLet(&'hir Expr<'hir>, &'hir Pat<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>), -} - -impl<'hir> IfLetOrMatch<'hir> { - fn parse(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option { - match expr.kind { - ExprKind::Match(expr, arms, source) => Some(Self::Match(expr, arms, source)), - _ => higher::IfLet::hir(cx, expr).map(|higher::IfLet { let_expr, let_pat, if_then, if_else }| { - Self::IfLet(let_expr, let_pat, if_then, if_else) - }) - } - } -} - /// A "wild-like" arm has a wild (`_`) or `None` pattern and no guard. Such arms can be "collapsed" /// into a single wild arm without any significant loss in semantics or readability. fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/copies.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/copies.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/copies.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/copies.rs 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{source_map::Span, symbol::Symbol, BytePos}; @@ -148,7 +148,7 @@ /// }; /// ``` pub BRANCHES_SHARING_CODE, - complexity, + nursery, "`if` statement with shared code in all blocks" } @@ -432,10 +432,11 @@ let mut add_expr_note = false; // Construct suggestions + let sm = cx.sess().source_map(); if start_stmts > 0 { let block = blocks[0]; let span_start = first_line_of_span(cx, if_expr.span).shrink_to_lo(); - let span_end = block.stmts[start_stmts - 1].span.source_callsite(); + let span_end = sm.stmt_span(block.stmts[start_stmts - 1].span, block.span); let cond_span = first_line_of_span(cx, if_expr.span).until(block.span); let cond_snippet = reindent_multiline(snippet(cx, cond_span, "_"), false, None); @@ -454,15 +455,16 @@ let span_end = block.span.shrink_to_hi(); let moved_start = if end_stmts == 0 && block.expr.is_some() { - block.expr.unwrap().span + block.expr.unwrap().span.source_callsite() } else { - block.stmts[block.stmts.len() - end_stmts].span - } - .source_callsite(); + sm.stmt_span(block.stmts[block.stmts.len() - end_stmts].span, block.span) + }; let moved_end = block .expr - .map_or_else(|| block.stmts[block.stmts.len() - 1].span, |expr| expr.span) - .source_callsite(); + .map_or_else( + || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span), + |expr| expr.span.source_callsite(), + ); let moved_span = moved_start.to(moved_end); let moved_snipped = reindent_multiline(snippet(cx, moved_span, "_"), true, None); @@ -472,7 +474,7 @@ let mut span = moved_start.to(span_end); // Improve formatting if the inner block has indention (i.e. normal Rust formatting) - let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt()); + let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt(), span.parent()); if snippet_opt(cx, test_span) .map(|snip| snip == " ") .unwrap_or_default() diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/dereference.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/dereference.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/dereference.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/dereference.rs 2021-11-29 19:27:12.000000000 +0000 @@ -126,7 +126,7 @@ target_mut, }, )); - } + }, _ => (), } }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/derivable_impls.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/derivable_impls.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/derivable_impls.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/derivable_impls.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,118 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{in_macro, is_automatically_derived, is_default_equivalent, remove_blocks}; +use rustc_hir::{ + def::{DefKind, Res}, + Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Detects manual `std::default::Default` implementations that are identical to a derived implementation. + /// + /// ### Why is this bad? + /// It is less concise. + /// + /// ### Example + /// ```rust + /// struct Foo { + /// bar: bool + /// } + /// + /// impl std::default::Default for Foo { + /// fn default() -> Self { + /// Self { + /// bar: false + /// } + /// } + /// } + /// ``` + /// + /// Could be written as: + /// + /// ```rust + /// #[derive(Default)] + /// struct Foo { + /// bar: bool + /// } + /// ``` + /// + /// ### Known problems + /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925) + /// in generic types and the user defined `impl` maybe is more generalized or + /// specialized than what derive will produce. This lint can't detect the manual `impl` + /// has exactly equal bounds, and therefore this lint is disabled for types with + /// generic parameters. + /// + pub DERIVABLE_IMPLS, + complexity, + "manual implementation of the `Default` trait which is equal to a derive" +} + +declare_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]); + +fn is_path_self(e: &Expr<'_>) -> bool { + if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind { + matches!(p.res, Res::SelfCtor(..) | Res::Def(DefKind::Ctor(..), _)) + } else { + false + } +} + +impl<'tcx> LateLintPass<'tcx> for DerivableImpls { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if_chain! { + if let ItemKind::Impl(Impl { + of_trait: Some(ref trait_ref), + items: [child], + self_ty, + .. + }) = item.kind; + if let attrs = cx.tcx.hir().attrs(item.hir_id()); + if !is_automatically_derived(attrs); + if !in_macro(item.span); + if let Some(def_id) = trait_ref.trait_def_id(); + if cx.tcx.is_diagnostic_item(sym::Default, def_id); + if let impl_item_hir = child.id.hir_id(); + if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir); + if let ImplItemKind::Fn(_, b) = &impl_item.kind; + if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b); + if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def(); + if !attrs.iter().any(|attr| attr.doc_str().is_some()); + if let child_attrs = cx.tcx.hir().attrs(impl_item_hir); + if !child_attrs.iter().any(|attr| attr.doc_str().is_some()); + if adt_def.is_struct(); + then { + if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind { + if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() { + for arg in a.args { + if !matches!(arg, GenericArg::Lifetime(_)) { + return; + } + } + } + } + let should_emit = match remove_blocks(func_expr).kind { + ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)), + ExprKind::Call(callee, args) + if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)), + ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)), + _ => false, + }; + if should_emit { + let path_string = cx.tcx.def_path_str(adt_def.did); + span_lint_and_help( + cx, + DERIVABLE_IMPLS, + item.span, + "this `impl` can be derived", + None, + &format!("try annotating `{}` with `#[derive(Default)]`", path_string), + ); + } + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/derive.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/derive.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/derive.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/derive.rs 2021-11-29 19:27:12.000000000 +0000 @@ -105,9 +105,6 @@ /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]` /// gets you. /// - /// ### Known problems - /// Bounds of generic types are sometimes wrong: https://github.com/rust-lang/rust/issues/26925 - /// /// ### Example /// ```rust,ignore /// #[derive(Copy)] @@ -396,7 +393,7 @@ if_chain! { if let Some(header) = kind.header(); - if let Unsafety::Unsafe = header.unsafety; + if header.unsafety == Unsafety::Unsafe; then { self.has_unsafe = true; } @@ -411,7 +408,7 @@ } if let ExprKind::Block(block, _) = expr.kind { - if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules { + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { self.has_unsafe = true; } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/disallowed_method.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/disallowed_method.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/disallowed_method.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/disallowed_method.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,33 +1,44 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fn_def_id; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{def::Res, def_id::DefId, Crate, Expr}; +use rustc_hir::{def::Res, def_id::DefIdMap, Expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Symbol; + +use crate::utils::conf; declare_clippy_lint! { /// ### What it does /// Denies the configured methods and functions in clippy.toml /// /// ### Why is this bad? - /// Some methods are undesirable in certain contexts, - /// and it's beneficial to lint for them as needed. + /// Some methods are undesirable in certain contexts, and it's beneficial to + /// lint for them as needed. /// /// ### Example /// An example clippy.toml configuration: /// ```toml /// # clippy.toml - /// disallowed-methods = ["std::vec::Vec::leak", "std::time::Instant::now"] + /// disallowed-methods = [ + /// # Can use a string as the path of the disallowed method. + /// "std::boxed::Box::new", + /// # Can also use an inline table with a `path` key. + /// { path = "std::time::Instant::now" }, + /// # When using an inline table, can add a `reason` for why the method + /// # is disallowed. + /// { path = "std::vec::Vec::leak", reason = "no leaking memory" }, + /// ] /// ``` /// /// ```rust,ignore /// // Example code where clippy issues a warning /// let xs = vec![1, 2, 3, 4]; /// xs.leak(); // Vec::leak is disallowed in the config. + /// // The diagnostic contains the message "no leaking memory". /// /// let _now = Instant::now(); // Instant::now is disallowed in the config. + /// + /// let _box = Box::new(3); // Box::new is disallowed in the config. /// ``` /// /// Use instead: @@ -43,18 +54,15 @@ #[derive(Clone, Debug)] pub struct DisallowedMethod { - disallowed: FxHashSet>, - def_ids: FxHashSet<(DefId, Vec)>, + conf_disallowed: Vec, + disallowed: DefIdMap>, } impl DisallowedMethod { - pub fn new(disallowed: &FxHashSet) -> Self { + pub fn new(conf_disallowed: Vec) -> Self { Self { - disallowed: disallowed - .iter() - .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::>()) - .collect(), - def_ids: FxHashSet::default(), + conf_disallowed, + disallowed: DefIdMap::default(), } } } @@ -62,33 +70,37 @@ impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethod { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { - for path in &self.disallowed { - let segs = path.iter().map(ToString::to_string).collect::>(); - if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::>()) - { - self.def_ids.insert((id, path.clone())); + fn check_crate(&mut self, cx: &LateContext<'_>) { + for conf in &self.conf_disallowed { + let (path, reason) = match conf { + conf::DisallowedMethod::Simple(path) => (path, None), + conf::DisallowedMethod::WithReason { path, reason } => ( + path, + reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)), + ), + }; + let segs: Vec<_> = path.split("::").collect(); + if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs) { + self.disallowed.insert(id, reason); } } } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(def_id) = fn_def_id(cx, expr) { - if self.def_ids.iter().any(|(id, _)| def_id == *id) { - let func_path = cx.get_def_path(def_id); - let func_path_string = func_path - .into_iter() - .map(Symbol::to_ident_string) - .collect::>() - .join("::"); - - span_lint( - cx, - DISALLOWED_METHOD, - expr.span, - &format!("use of a disallowed method `{}`", func_path_string), - ); + let def_id = match fn_def_id(cx, expr) { + Some(def_id) => def_id, + None => return, + }; + let reason = match self.disallowed.get(&def_id) { + Some(reason) => reason, + None => return, + }; + let func_path = cx.tcx.def_path_str(def_id); + let msg = format!("use of a disallowed method `{}`", func_path); + span_lint_and_then(cx, DISALLOWED_METHOD, expr.span, &msg, |diag| { + if let Some(reason) = reason { + diag.note(reason); } - } + }); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/disallowed_type.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/disallowed_type.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/disallowed_type.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/disallowed_type.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::{ - def::Res, def_id::DefId, Crate, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, Ty, TyKind, UseKind, + def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, Ty, TyKind, UseKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -48,7 +48,7 @@ Self { disallowed: disallowed .iter() - .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::>()) + .map(|s| s.split("::").map(Symbol::intern).collect::>()) .collect(), def_ids: FxHashSet::default(), prim_tys: FxHashSet::default(), @@ -75,7 +75,7 @@ impl_lint_pass!(DisallowedType => [DISALLOWED_TYPE]); impl<'tcx> LateLintPass<'tcx> for DisallowedType { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'_>) { for path in &self.disallowed { let segs = path.iter().map(ToString::to_string).collect::>(); match clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::>()) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/doc.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/doc.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/doc.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/doc.rs 2021-11-29 19:27:12.000000000 +0000 @@ -212,7 +212,7 @@ ); impl<'tcx> LateLintPass<'tcx> for DocMarkdown { - fn check_crate(&mut self, cx: &LateContext<'tcx>, _: &'tcx hir::Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); check_attrs(cx, &self.valid_idents, attrs); } @@ -236,7 +236,17 @@ hir::ItemKind::Impl(ref impl_) => { self.in_trait_impl = impl_.of_trait.is_some(); }, - _ => {}, + hir::ItemKind::Trait(_, unsafety, ..) => { + if !headers.safety && unsafety == hir::Unsafety::Unsafe { + span_lint( + cx, + MISSING_SAFETY_DOC, + item.span, + "docs for unsafe trait missing `# Safety` section", + ); + } + }, + _ => (), } } @@ -307,7 +317,7 @@ } if !headers.errors { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); - if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { + if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) { span_lint( cx, MISSING_ERRORS_DOC, @@ -325,7 +335,7 @@ if let ty::Opaque(_, subs) = ret_ty.kind(); if let Some(gen) = subs.types().next(); if let ty::Generator(_, subs, _) = gen.kind(); - if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::result_type); + if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result); then { span_lint( cx, @@ -396,6 +406,15 @@ } fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &'a [Attribute]) -> DocHeaders { + use pulldown_cmark::{BrokenLink, CowStr, Options}; + /// We don't want the parser to choke on intra doc links. Since we don't + /// actually care about rendering them, just pretend that all broken links are + /// point to a fake address. + #[allow(clippy::unnecessary_wraps)] // we're following a type signature + fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> { + Some(("fake".into(), "fake".into())) + } + let mut doc = String::new(); let mut spans = vec![]; @@ -430,7 +449,10 @@ }; } - let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter(); + let mut cb = fake_broken_link_callback; + + let parser = + pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter(); // Iterate over all `Events` and combine consecutive events into one let events = parser.coalesce(|previous, current| { use pulldown_cmark::Event::Text; @@ -665,6 +687,7 @@ span.lo() + BytePos::from_usize(offset), span.lo() + BytePos::from_usize(offset + word.len()), span.ctxt(), + span.parent(), ); check_word(cx, word, span); @@ -759,8 +782,8 @@ // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.cx, reciever_ty, sym::option_type) - || is_type_diagnostic_item(self.cx, reciever_ty, sym::result_type) + if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option) + || is_type_diagnostic_item(self.cx, reciever_ty, sym::Result) { self.panic_span = Some(expr.span); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/entry.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/entry.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/entry.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/entry.rs 2021-11-29 19:27:12.000000000 +0000 @@ -9,8 +9,9 @@ use core::fmt::Write; use rustc_errors::Applicability; use rustc_hir::{ + hir_id::HirIdSet, intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor}, - Block, Expr, ExprKind, Guard, HirId, Local, Stmt, StmtKind, UnOp, + Block, Expr, ExprKind, Guard, HirId, Pat, Stmt, StmtKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -244,11 +245,14 @@ ExprKind::MethodCall( _, _, - [map, Expr { - kind: ExprKind::AddrOf(_, _, key), - span: key_span, - .. - }], + [ + map, + Expr { + kind: ExprKind::AddrOf(_, _, key), + span: key_span, + .. + }, + ], _, ) if key_span.ctxt() == expr.span.ctxt() => { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; @@ -338,6 +342,8 @@ edits: Vec>, /// A stack of loops the visitor is currently in. loops: Vec, + /// Local variables created in the expression. These don't need to be captured. + locals: HirIdSet, } impl<'tcx> InsertSearcher<'_, 'tcx> { /// Visit the expression as a branch in control flow. Multiple insert calls can be used, but @@ -385,13 +391,16 @@ } }, StmtKind::Expr(e) => self.visit_expr(e), - StmtKind::Local(Local { init: Some(e), .. }) => { - self.allow_insert_closure &= !self.in_tail_pos; - self.in_tail_pos = false; - self.is_single_insert = false; - self.visit_expr(e); + StmtKind::Local(l) => { + self.visit_pat(l.pat); + if let Some(e) = l.init { + self.allow_insert_closure &= !self.in_tail_pos; + self.in_tail_pos = false; + self.is_single_insert = false; + self.visit_expr(e); + } }, - _ => { + StmtKind::Item(_) => { self.allow_insert_closure &= !self.in_tail_pos; self.is_single_insert = false; }, @@ -473,6 +482,7 @@ // Each branch may contain it's own insert expression. let mut is_map_used = self.is_map_used; for arm in arms { + self.visit_pat(arm.pat); if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard { self.visit_non_tail_expr(guard); } @@ -498,7 +508,8 @@ }, _ => { self.allow_insert_closure &= !self.in_tail_pos; - self.allow_insert_closure &= can_move_expr_to_closure_no_visit(self.cx, expr, &self.loops); + self.allow_insert_closure &= + can_move_expr_to_closure_no_visit(self.cx, expr, &self.loops, &self.locals); // Sub expressions are no longer in the tail position. self.is_single_insert = false; self.in_tail_pos = false; @@ -507,6 +518,12 @@ }, } } + + fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) { + p.each_binding_or_first(&mut |_, id, _, _| { + self.locals.insert(id); + }); + } } struct InsertSearchResults<'tcx> { @@ -632,6 +649,7 @@ in_tail_pos: true, is_single_insert: true, loops: Vec::new(), + locals: HirIdSet::default(), }; s.visit_expr(expr); let allow_insert_closure = s.allow_insert_closure; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/equatable_if_let.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/equatable_if_let.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/equatable_if_let.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/equatable_if_let.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,100 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::implements_trait; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for pattern matchings that can be expressed using equality. + /// + /// ### Why is this bad? + /// + /// * It reads better and has less cognitive load because equality won't cause binding. + /// * It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely + /// criticized for increasing the cognitive load of reading the code. + /// * Equality is a simple bool expression and can be merged with `&&` and `||` and + /// reuse if blocks + /// + /// ### Example + /// ```rust,ignore + /// if let Some(2) = x { + /// do_thing(); + /// } + /// ``` + /// Should be written + /// ```rust,ignore + /// if x == Some(2) { + /// do_thing(); + /// } + /// ``` + pub EQUATABLE_IF_LET, + nursery, + "using pattern matching instead of equality" +} + +declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET]); + +/// detects if pattern matches just one thing +fn unary_pattern(pat: &Pat<'_>) -> bool { + fn array_rec(pats: &[Pat<'_>]) -> bool { + pats.iter().all(unary_pattern) + } + match &pat.kind { + PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => { + false + }, + PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a), + PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), + PatKind::Path(_) | PatKind::Lit(_) => true, + } +} + +fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool { + if let Some(def_id) = cx.tcx.lang_items().eq_trait() { + implements_trait(cx, ty, def_id, &[other.into()]) + } else { + false + } +} + +impl<'tcx> LateLintPass<'tcx> for PatternEquality { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if let ExprKind::Let(pat, exp, _) = expr.kind; + if unary_pattern(pat); + let exp_ty = cx.typeck_results().expr_ty(exp); + let pat_ty = cx.typeck_results().pat_ty(pat); + if is_structural_partial_eq(cx, exp_ty, pat_ty); + then { + + let mut applicability = Applicability::MachineApplicable; + let pat_str = match pat.kind { + PatKind::Struct(..) => format!( + "({})", + snippet_with_applicability(cx, pat.span, "..", &mut applicability), + ), + _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(), + }; + span_lint_and_sugg( + cx, + EQUATABLE_IF_LET, + expr.span, + "this pattern matching can be expressed using equality", + "try", + format!( + "{} == {}", + snippet_with_applicability(cx, exp.span, "..", &mut applicability), + pat_str, + ), + applicability, + ); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/erasing_op.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/erasing_op.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/erasing_op.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/erasing_op.rs 2021-11-29 19:27:12.000000000 +0000 @@ -47,7 +47,7 @@ } fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) { - if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), e) { + if constant_simple(cx, cx.typeck_results(), e) == Some(Constant::Int(0)) { span_lint( cx, ERASING_OP, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/escape.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/escape.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/escape.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/escape.rs 2021-11-29 19:27:12.000000000 +0000 @@ -5,11 +5,11 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::kw; -use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; @@ -90,9 +90,12 @@ for trait_item in items { if trait_item.id.hir_id() == hir_id { // be sure we have `self` parameter in this function - if let AssocItemKind::Fn { has_self: true } = trait_item.kind { - trait_self_ty = - Some(TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()).self_ty()); + if trait_item.kind == (AssocItemKind::Fn { has_self: true }) { + trait_self_ty = Some( + TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()) + .self_ty() + .skip_binder(), + ); } } } @@ -171,7 +174,8 @@ // skip if there is a `self` parameter binding to a type // that contains `Self` (i.e.: `self: Box`), see #4804 if let Some(trait_self_ty) = self.trait_self_ty { - if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(self.cx.tcx, cmt.place.ty(), trait_self_ty) { + if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(self.cx.tcx, cmt.place.ty(), trait_self_ty) + { return; } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/eta_reduction.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/eta_reduction.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/eta_reduction.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/eta_reduction.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,16 +1,16 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{implements_trait, type_is_unsafe_function}; use clippy_utils::usage::UsedAfterExprVisitor; -use clippy_utils::{get_enclosing_loop_or_closure, higher}; -use clippy_utils::{is_adjusted, iter_input_pats}; +use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, ClosureKind, Ty}; +use rustc_hir::def_id::DefId; +use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -52,12 +52,6 @@ /// ### Why is this bad? /// It's unnecessary to create the closure. /// - /// ### Known problems - /// [#3071](https://github.com/rust-lang/rust-clippy/issues/3071), - /// [#3942](https://github.com/rust-lang/rust-clippy/issues/3942), - /// [#4002](https://github.com/rust-lang/rust-clippy/issues/4002) - /// - /// /// ### Example /// ```rust,ignore /// Some('a').map(|s| s.to_uppercase()); @@ -75,32 +69,16 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) { + if expr.span.from_expansion() { return; } - - match expr.kind { - ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => { - for arg in args { - // skip `foo(macro!())` - if arg.span.ctxt() == expr.span.ctxt() { - check_closure(cx, arg); - } - } - }, - _ => (), - } - } -} - -fn check_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Closure(_, decl, eid, _, _) = expr.kind { - let body = cx.tcx.hir().body(eid); - let ex = &body.value; - - if ex.span.ctxt() != expr.span.ctxt() { - if decl.inputs.is_empty() { - if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, ex) { + let body = match expr.kind { + ExprKind::Closure(_, _, id, _, _) => cx.tcx.hir().body(id), + _ => return, + }; + if body.value.span.from_expansion() { + if body.params.is_empty() { + if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) { // replace `|| vec![]` with `Vec::new` span_lint_and_sugg( cx, @@ -117,33 +95,30 @@ return; } - if_chain!( - if let ExprKind::Call(caller, args) = ex.kind; - - if let ExprKind::Path(_) = caller.kind; - - // Not the same number of arguments, there is no way the closure is the same as the function return; - if args.len() == decl.inputs.len(); - - // Are the expression or the arguments type-adjusted? Then we need the closure - if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg))); - - let fn_ty = cx.typeck_results().expr_ty(caller); - - if matches!(fn_ty.kind(), ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _)); - - if !type_is_unsafe_function(cx, fn_ty); - - if compare_inputs(&mut iter_input_pats(decl, body), &mut args.iter()); + let closure_ty = cx.typeck_results().expr_ty(expr); + if_chain!( + if let ExprKind::Call(callee, args) = body.value.kind; + if let ExprKind::Path(_) = callee.kind; + if check_inputs(cx, body.params, args); + let callee_ty = cx.typeck_results().expr_ty_adjusted(callee); + let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id) + .map_or(callee_ty, |id| cx.tcx.type_of(id)); + if check_sig(cx, closure_ty, call_ty); + let substs = cx.typeck_results().node_substs(callee.hir_id); + // This fixes some false positives that I don't entirely understand + if substs.is_empty() || !cx.typeck_results().expr_ty(expr).has_late_bound_regions(); + // A type param function ref like `T::f` is not 'static, however + // it is if cast like `T::f as fn()`. This seems like a rustc bug. + if !substs.types().any(|t| matches!(t.kind(), ty::Param(_))); then { span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { - if let Some(mut snippet) = snippet_opt(cx, caller.span) { + if let Some(mut snippet) = snippet_opt(cx, callee.span) { if_chain! { - if let ty::Closure(_, substs) = fn_ty.kind(); - if let ClosureKind::FnMut = substs.as_closure().kind(); - if UsedAfterExprVisitor::is_found(cx, caller) - || get_enclosing_loop_or_closure(cx.tcx, expr).is_some(); + if let ty::Closure(_, substs) = callee_ty.peel_refs().kind(); + if substs.as_closure().kind() == ClosureKind::FnMut; + if get_enclosing_loop_or_closure(cx.tcx, expr).is_some() + || UsedAfterExprVisitor::is_found(cx, callee); then { // Mutable closure is used after current expr; we cannot consume it. @@ -162,110 +137,82 @@ ); if_chain!( - if let ExprKind::MethodCall(path, _, args, _) = ex.kind; - - // Not the same number of arguments, there is no way the closure is the same as the function return; - if args.len() == decl.inputs.len(); - - // Are the expression or the arguments type-adjusted? Then we need the closure - if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg))); - - let method_def_id = cx.typeck_results().type_dependent_def_id(ex.hir_id).unwrap(); - if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id)); - - if compare_inputs(&mut iter_input_pats(decl, body), &mut args.iter()); - - if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]); - + if let ExprKind::MethodCall(path, _, args, _) = body.value.kind; + if check_inputs(cx, body.params, args); + let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap(); + let substs = cx.typeck_results().node_substs(body.value.hir_id); + let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs); + if check_sig(cx, closure_ty, call_ty); then { - span_lint_and_sugg( - cx, - REDUNDANT_CLOSURE_FOR_METHOD_CALLS, - expr.span, - "redundant closure", - "replace the closure with the method itself", - format!("{}::{}", name, path.ident.name), - Applicability::MachineApplicable, - ); + span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| { + let name = get_ufcs_type_name(cx, method_def_id); + diag.span_suggestion( + expr.span, + "replace the closure with the method itself", + format!("{}::{}", name, path.ident.name), + Applicability::MachineApplicable, + ); + }) } ); } } -/// Tries to determine the type for universal function call to be used instead of the closure -fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_arg: &Expr<'_>) -> Option { - let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0]; - let actual_type_of_self = &cx.typeck_results().node_type(self_arg.hir_id); - - if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) { - if match_borrow_depth(expected_type_of_self, actual_type_of_self) - && implements_trait(cx, actual_type_of_self, trait_id, &[]) - { - return Some(cx.tcx.def_path_str(trait_id)); - } - } - - cx.tcx.impl_of_method(method_def_id).and_then(|_| { - //a type may implicitly implement other type's methods (e.g. Deref) - if match_types(expected_type_of_self, actual_type_of_self) { - Some(get_type_name(cx, actual_type_of_self)) - } else { - None +fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool { + if params.len() != call_args.len() { + return false; + } + std::iter::zip(params, call_args).all(|(param, arg)| { + match param.pat.kind { + PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {}, + _ => return false, + } + match *cx.typeck_results().expr_adjustments(arg) { + [] => true, + [ + Adjustment { + kind: Adjust::Deref(None), + .. + }, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)), + .. + }, + ] => { + // re-borrow with the same mutability is allowed + let ty = cx.typeck_results().expr_ty(arg); + matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into()) + }, + _ => false, } }) } -fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { - match (&lhs.kind(), &rhs.kind()) { - (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(t1, t2), - (l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))), - } -} - -fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { - match (&lhs.kind(), &rhs.kind()) { - (ty::Bool, ty::Bool) - | (ty::Char, ty::Char) - | (ty::Int(_), ty::Int(_)) - | (ty::Uint(_), ty::Uint(_)) - | (ty::Str, ty::Str) => true, - (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_types(t1, t2), - (ty::Array(t1, _), ty::Array(t2, _)) | (ty::Slice(t1), ty::Slice(t2)) => match_types(t1, t2), - (ty::Adt(def1, _), ty::Adt(def2, _)) => def1 == def2, - (_, _) => false, - } -} - -fn get_type_name(cx: &LateContext<'_>, ty: Ty<'_>) -> String { - match ty.kind() { - ty::Adt(t, _) => cx.tcx.def_path_str(t.did), - ty::Ref(_, r, _) => get_type_name(cx, r), - _ => ty.to_string(), - } -} - -fn compare_inputs( - closure_inputs: &mut dyn Iterator>, - call_args: &mut dyn Iterator>, -) -> bool { - for (closure_input, function_arg) in closure_inputs.zip(call_args) { - if let PatKind::Binding(_, _, ident, _) = closure_input.pat.kind { - // XXXManishearth Should I be checking the binding mode here? - if let ExprKind::Path(QPath::Resolved(None, p)) = function_arg.kind { - if p.segments.len() != 1 { - // If it's a proper path, it can't be a local variable - return false; - } - if p.segments[0].ident.name != ident.name { - // The two idents should be the same - return false; - } - } else { - return false; +fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool { + let call_sig = call_ty.fn_sig(cx.tcx); + if call_sig.unsafety() == Unsafety::Unsafe { + return false; + } + if !closure_ty.has_late_bound_regions() { + return true; + } + let substs = match closure_ty.kind() { + ty::Closure(_, substs) => substs, + _ => return false, + }; + let closure_sig = cx.tcx.signature_unclosure(substs.as_closure().sig(), Unsafety::Normal); + cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig) +} + +fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String { + match cx.tcx.associated_item(method_def_id).container { + ty::TraitContainer(def_id) => cx.tcx.def_path_str(def_id), + ty::ImplContainer(def_id) => { + let ty = cx.tcx.type_of(def_id); + match ty.kind() { + ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did), + _ => ty.to_string(), } - } else { - return false; - } + }, } - true } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs 2021-11-29 19:27:12.000000000 +0000 @@ -15,8 +15,8 @@ /// order of sub-expressions. /// /// ### Why is this bad? - /// It is often confusing to read. In addition, the - /// sub-expression evaluation order for Rust is not well documented. + /// It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands), + /// the operands of these expressions are evaluated before applying the effects of the expression. /// /// ### Known problems /// Code which intentionally depends on the evaluation @@ -141,7 +141,7 @@ match typ.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let sig = typ.fn_sig(self.cx.tcx); - if let ty::Never = self.cx.tcx.erase_late_bound_regions(sig).output().kind() { + if self.cx.tcx.erase_late_bound_regions(sig).output().kind() == &ty::Never { self.report_diverging_sub_expr(e); } }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs 2021-11-29 19:27:12.000000000 +0000 @@ -57,7 +57,7 @@ if_chain! { if let hir::ItemKind::Impl(impl_) = &item.kind; if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id); - if cx.tcx.is_diagnostic_item(sym::from_trait, impl_trait_ref.def_id); + if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.def_id); then { lint_impl_body(cx, item.span, impl_.items); } @@ -65,7 +65,7 @@ } } -fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef<'_>]) { +fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) { use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, ImplItemKind, QPath}; @@ -94,8 +94,8 @@ // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::Option) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::Result) { self.result.push(expr.span); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/feature_name.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/feature_name.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/feature_name.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/feature_name.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,164 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{diagnostics::span_lint, is_lint_allowed}; +use rustc_hir::CRATE_HIR_ID; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::DUMMY_SP; + +declare_clippy_lint! { + /// ### What it does + /// Checks for feature names with prefix `use-`, `with-` or suffix `-support` + /// + /// ### Why is this bad? + /// These prefixes and suffixes have no significant meaning. + /// + /// ### Example + /// ```toml + /// # The `Cargo.toml` with feature name redundancy + /// [features] + /// default = ["use-abc", "with-def", "ghi-support"] + /// use-abc = [] // redundant + /// with-def = [] // redundant + /// ghi-support = [] // redundant + /// ``` + /// + /// Use instead: + /// ```toml + /// [features] + /// default = ["abc", "def", "ghi"] + /// abc = [] + /// def = [] + /// ghi = [] + /// ``` + /// + pub REDUNDANT_FEATURE_NAMES, + cargo, + "usage of a redundant feature name" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for negative feature names with prefix `no-` or `not-` + /// + /// ### Why is this bad? + /// Features are supposed to be additive, and negatively-named features violate it. + /// + /// ### Example + /// ```toml + /// # The `Cargo.toml` with negative feature names + /// [features] + /// default = [] + /// no-abc = [] + /// not-def = [] + /// + /// ``` + /// Use instead: + /// ```toml + /// [features] + /// default = ["abc", "def"] + /// abc = [] + /// def = [] + /// + /// ``` + pub NEGATIVE_FEATURE_NAMES, + cargo, + "usage of a negative feature name" +} + +declare_lint_pass!(FeatureName => [REDUNDANT_FEATURE_NAMES, NEGATIVE_FEATURE_NAMES]); + +static PREFIXES: [&str; 8] = ["no-", "no_", "not-", "not_", "use-", "use_", "with-", "with_"]; +static SUFFIXES: [&str; 2] = ["-support", "_support"]; + +fn is_negative_prefix(s: &str) -> bool { + s.starts_with("no") +} + +fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) { + let is_negative = is_prefix && is_negative_prefix(substring); + span_lint_and_help( + cx, + if is_negative { + NEGATIVE_FEATURE_NAMES + } else { + REDUNDANT_FEATURE_NAMES + }, + DUMMY_SP, + &format!( + "the \"{}\" {} in the feature name \"{}\" is {}", + substring, + if is_prefix { "prefix" } else { "suffix" }, + feature, + if is_negative { "negative" } else { "redundant" } + ), + None, + &format!( + "consider renaming the feature to \"{}\"{}", + if is_prefix { + feature.strip_prefix(substring) + } else { + feature.strip_suffix(substring) + } + .unwrap(), + if is_negative { + ", but make sure the feature adds functionality" + } else { + "" + } + ), + ); +} + +impl LateLintPass<'_> for FeatureName { + fn check_crate(&mut self, cx: &LateContext<'_>) { + if is_lint_allowed(cx, REDUNDANT_FEATURE_NAMES, CRATE_HIR_ID) + && is_lint_allowed(cx, NEGATIVE_FEATURE_NAMES, CRATE_HIR_ID) + { + return; + } + + let metadata = unwrap_cargo_metadata!(cx, REDUNDANT_FEATURE_NAMES, false); + + for package in metadata.packages { + let mut features: Vec<&String> = package.features.keys().collect(); + features.sort(); + for feature in features { + let prefix_opt = { + let i = PREFIXES.partition_point(|prefix| prefix < &feature.as_str()); + if i > 0 && feature.starts_with(PREFIXES[i - 1]) { + Some(PREFIXES[i - 1]) + } else { + None + } + }; + if let Some(prefix) = prefix_opt { + lint(cx, feature, prefix, true); + } + + let suffix_opt: Option<&str> = { + let i = SUFFIXES.partition_point(|suffix| { + suffix.bytes().rev().cmp(feature.bytes().rev()) == std::cmp::Ordering::Less + }); + if i > 0 && feature.ends_with(SUFFIXES[i - 1]) { + Some(SUFFIXES[i - 1]) + } else { + None + } + }; + if let Some(suffix) = suffix_opt { + lint(cx, feature, suffix, false); + } + } + } + } +} + +#[test] +fn test_prefixes_sorted() { + let mut sorted_prefixes = PREFIXES; + sorted_prefixes.sort_unstable(); + assert_eq!(PREFIXES, sorted_prefixes); + let mut sorted_suffixes = SUFFIXES; + sorted_suffixes.sort_by(|a, b| a.bytes().rev().cmp(b.bytes().rev())); + assert_eq!(SUFFIXES, sorted_suffixes); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs 2021-11-29 19:27:12.000000000 +0000 @@ -332,8 +332,6 @@ ), Applicability::MachineApplicable, ); - - return; } } } @@ -364,22 +362,22 @@ if_chain! { if let ExprKind::MethodCall( PathSegment { ident: lmethod_name, .. }, - ref _lspan, - largs, + _lspan, + [largs_0, largs_1, ..], _ - ) = add_lhs.kind; + ) = &add_lhs.kind; if let ExprKind::MethodCall( PathSegment { ident: rmethod_name, .. }, - ref _rspan, - rargs, + _rspan, + [rargs_0, rargs_1, ..], _ - ) = add_rhs.kind; + ) = &add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), &largs[1]); - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), &rargs[1]); + if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1); + if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1); if Int(2) == lvalue && Int(2) == rvalue; then { - return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."))); + return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, ".."), Sugg::hir(cx, rargs_0, ".."))); } } } @@ -409,8 +407,8 @@ if cx.typeck_results().expr_ty(lhs).is_floating_point(); if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; - if let ExprKind::MethodCall(path, _, method_args, _) = lhs.kind; - if cx.typeck_results().expr_ty(&method_args[0]).is_floating_point(); + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &lhs.kind; + if cx.typeck_results().expr_ty(self_arg).is_floating_point(); if path.ident.name.as_str() == "exp"; then { span_lint_and_sugg( @@ -421,7 +419,7 @@ "consider using", format!( "{}.exp_m1()", - Sugg::hir(cx, &method_args[0], "..") + Sugg::hir(cx, self_arg, "..") ), Applicability::MachineApplicable, ); @@ -619,8 +617,8 @@ rhs, ) = &expr.kind; if are_same_base_logs(cx, lhs, rhs); - if let ExprKind::MethodCall(_, _, largs, _) = lhs.kind; - if let ExprKind::MethodCall(_, _, rargs, _) = rhs.kind; + if let ExprKind::MethodCall(_, _, [largs_self, ..], _) = &lhs.kind; + if let ExprKind::MethodCall(_, _, [rargs_self, ..], _) = &rhs.kind; then { span_lint_and_sugg( cx, @@ -628,7 +626,7 @@ expr.span, "log base can be expressed more clearly", "consider using", - format!("{}.log({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."),), + format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),), Applicability::MachineApplicable, ); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/float_literal.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/float_literal.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/float_literal.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/float_literal.rs 2021-11-29 19:27:12.000000000 +0000 @@ -111,7 +111,7 @@ Applicability::MachineApplicable, ); } - } else if digits > max as usize && sym_str != float_str { + } else if digits > max as usize && float_str.len() < sym_str.len() { span_lint_and_sugg( cx, EXCESSIVE_PRECISION, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/format.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/format.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/format.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/format.rs 2021-11-29 19:27:12.000000000 +0000 @@ -65,12 +65,12 @@ if_chain! { if format_args.format_string_symbols == [kw::Empty]; if match cx.typeck_results().expr_ty(value).peel_refs().kind() { - ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::string_type, adt.did), + ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did), ty::Str => true, _ => false, }; - if format_args.args.iter().all(|e| is_display_arg(e)); - if format_args.fmt_expr.map_or(true, |e| check_unformatted(e)); + if format_args.args.iter().all(is_display_arg); + if format_args.fmt_expr.map_or(true, check_unformatted); then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, @@ -90,12 +90,7 @@ } } -fn span_useless_format(cx: &LateContext<'_>, span: Span, mut sugg: String, mut applicability: Applicability) { - // The callsite span contains the statement semicolon for some reason. - if snippet_with_applicability(cx, span, "..", &mut applicability).ends_with(';') { - sugg.push(';'); - } - +fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) { span_lint_and_sugg( cx, USELESS_FORMAT, @@ -112,7 +107,7 @@ if let ExprKind::Call(_, [_, fmt]) = expr.kind; if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind; if let [.., t, _] = path.segments; - if t.ident.name.as_str() == "Display"; + if t.ident.name == sym::Display; then { true } else { false } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/formatting.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/formatting.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/formatting.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/formatting.rs 2021-11-29 19:27:12.000000000 +0000 @@ -286,34 +286,39 @@ } fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { - if !differing_macro_contexts(first.span, second.span) - && !first.span.from_expansion() - && is_if(first) - && (is_block(second) || is_if(second)) - { - // where the else would be - let else_span = first.span.between(second.span); + if_chain! { + if !differing_macro_contexts(first.span, second.span); + if !first.span.from_expansion(); + if let ExprKind::If(cond_expr, ..) = &first.kind; + if is_block(second) || is_if(second); + + // Proc-macros can give weird spans. Make sure this is actually an `if`. + if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span)); + if if_snip.starts_with("if"); - if let Some(else_snippet) = snippet_opt(cx, else_span) { - if !else_snippet.contains('\n') { - let (looks_like, next_thing) = if is_if(second) { - ("an `else if`", "the second `if`") - } else { - ("an `else {..}`", "the next block") - }; + // If there is a line break between the two expressions, don't lint. + // If there is a non-whitespace character, this span came from a proc-macro. + let else_span = first.span.between(second.span); + if let Some(else_snippet) = snippet_opt(cx, else_span); + if !else_snippet.chars().any(|c| c == '\n' || !c.is_whitespace()); + then { + let (looks_like, next_thing) = if is_if(second) { + ("an `else if`", "the second `if`") + } else { + ("an `else {..}`", "the next block") + }; - span_lint_and_note( - cx, - SUSPICIOUS_ELSE_FORMATTING, - else_span, - &format!("this looks like {} but the `else` is missing", looks_like), - None, - &format!( - "to remove this lint, add the missing `else` or add a new line before {}", - next_thing, - ), - ); - } + span_lint_and_note( + cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + &format!("this looks like {} but the `else` is missing", looks_like), + None, + &format!( + "to remove this lint, add the missing `else` or add a new line before {}", + next_thing, + ), + ); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/from_over_into.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/from_over_into.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/from_over_into.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/from_over_into.rs 2021-11-29 19:27:12.000000000 +0000 @@ -61,7 +61,7 @@ if_chain! { if let hir::ItemKind::Impl{ .. } = &item.kind; if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id); - if cx.tcx.is_diagnostic_item(sym::into_trait, impl_trait_ref.def_id); + if cx.tcx.is_diagnostic_item(sym::Into, impl_trait_ref.def_id); then { span_lint_and_help( diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs 2021-11-29 19:27:12.000000000 +0000 @@ -98,5 +98,5 @@ /// Checks if a Ty is `String` or `&str` fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - is_type_diagnostic_item(cx, ty, sym::string_type) || is_type_diagnostic_item(cx, ty, sym::str) + is_type_diagnostic_item(cx, ty, sym::String) || is_type_diagnostic_item(cx, ty, sym::str) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/functions/must_use.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/functions/must_use.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/functions/must_use.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/functions/must_use.rs 2021-11-29 19:27:12.000000000 +0000 @@ -26,7 +26,6 @@ let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); - return; } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs 2021-11-29 19:27:12.000000000 +0000 @@ -48,7 +48,7 @@ if !in_external_macro(cx.sess(), item_span); if let hir::FnRetTy::Return(ty) = decl.output; let ty = hir_ty_to_ty(cx.tcx, ty); - if is_type_diagnostic_item(cx, ty, sym::result_type); + if is_type_diagnostic_item(cx, ty, sym::Result); if let ty::Adt(_, substs) = ty.kind(); let err_ty = substs.type_at(1); if err_ty.is_unit(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/future_not_send.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/future_not_send.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/future_not_send.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/future_not_send.rs 2021-11-29 19:27:12.000000000 +0000 @@ -75,7 +75,7 @@ } } if is_future { - let send_trait = cx.tcx.get_diagnostic_item(sym::send_trait).unwrap(); + let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let send_result = cx.tcx.infer_ctxt().enter(|infcx| { let cause = traits::ObligationCause::misc(span, hir_id); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/get_last_with_len.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/get_last_with_len.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/get_last_with_len.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/get_last_with_len.rs 2021-11-29 19:27:12.000000000 +0000 @@ -58,7 +58,7 @@ // Argument 0 (the struct we're calling the method on) is a vector if let Some(struct_calling_on) = args.get(0); let struct_ty = cx.typeck_results().expr_ty(struct_calling_on); - if is_type_diagnostic_item(cx, struct_ty, sym::vec_type); + if is_type_diagnostic_item(cx, struct_ty, sym::Vec); // Argument to "get" is a subtraction if let Some(get_index_arg) = args.get(1); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/identity_op.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/identity_op.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/identity_op.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/identity_op.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,4 @@ use clippy_utils::source::snippet; -use if_chain::if_chain; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -62,16 +61,9 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool { // `1 << 0` is a common pattern in bit manipulation code - if_chain! { - if let BinOpKind::Shl = cmp.node; - if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), right); - if let Some(Constant::Int(1)) = constant_simple(cx, cx.typeck_results(), left); - then { - return true; - } - } - - false + cmp.node == BinOpKind::Shl + && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0)) + && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)) } #[allow(clippy::cast_possible_wrap)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/if_let_mutex.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/if_let_mutex.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/if_let_mutex.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/if_let_mutex.rs 2021-11-29 19:27:12.000000000 +0000 @@ -8,6 +8,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -138,12 +139,12 @@ fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind; + if let ExprKind::MethodCall(path, _span, [self_arg, ..], _) = &expr.kind; if path.ident.as_str() == "lock"; - let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym!(mutex_type)); + let ty = cx.typeck_results().expr_ty(self_arg); + if is_type_diagnostic_item(cx, ty, sym::Mutex); then { - Some(&args[0]) + Some(self_arg) } else { None } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/if_let_some_result.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/if_let_some_result.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/if_let_some_result.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/if_let_some_result.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; -use clippy_utils::method_chain_args; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, PatKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - ///* Checks for unnecessary `ok()` in if let. - /// - /// ### Why is this bad? - /// Calling `ok()` in if let is unnecessary, instead match - /// on `Ok(pat)` - /// - /// ### Example - /// ```ignore - /// for i in iter { - /// if let Some(value) = i.parse().ok() { - /// vec.push(value) - /// } - /// } - /// ``` - /// Could be written: - /// - /// ```ignore - /// for i in iter { - /// if let Ok(value) = i.parse() { - /// vec.push(value) - /// } - /// } - /// ``` - pub IF_LET_SOME_RESULT, - style, - "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead" -} - -declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]); - -impl<'tcx> LateLintPass<'tcx> for OkIfLet { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { //begin checking variables - if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr); - if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) - if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = let_pat.kind; //get operation - if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym::result_type); - if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some"; - - then { - let mut applicability = Applicability::MachineApplicable; - let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); - let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_span), "", &mut applicability); - let sugg = format!( - "if let Ok({}) = {}", - some_expr_string, - trimmed_ok.trim().trim_end_matches('.'), - ); - span_lint_and_sugg( - cx, - IF_LET_SOME_RESULT, - expr.span.with_hi(let_expr.span.hi()), - "matching on `Some` with `ok()` is redundant", - &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), - sugg, - applicability, - ); - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/implicit_hasher.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/implicit_hasher.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/implicit_hasher.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/implicit_hasher.rs 2021-11-29 19:27:12.000000000 +0000 @@ -130,7 +130,7 @@ let pos = snippet_opt(cx, item.span.until(target.span())) .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4))); if let Some(pos) = pos { - Span::new(pos, pos, item.span.data().ctxt) + Span::new(pos, pos, item.span.ctxt(), item.span.parent()) } else { return; } @@ -167,13 +167,21 @@ continue; } let generics_suggestion_span = generics.span.substitute_dummy({ - let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span)) - .and_then(|snip| { - let i = snip.find("fn")?; - Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32)) - }) - .expect("failed to create span for type parameters"); - Span::new(pos, pos, item.span.data().ctxt) + let pos = snippet_opt( + cx, + Span::new( + item.span.lo(), + body.params[0].pat.span.lo(), + item.span.ctxt(), + item.span.parent(), + ), + ) + .and_then(|snip| { + let i = snip.find("fn")?; + Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32)) + }) + .expect("failed to create span for type parameters"); + Span::new(pos, pos, item.span.ctxt(), item.span.parent()) }); let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target); @@ -225,14 +233,14 @@ let ty = hir_ty_to_ty(cx.tcx, hir_ty); - if is_type_diagnostic_item(cx, ty, sym::hashmap_type) && params_len == 2 { + if is_type_diagnostic_item(cx, ty, sym::HashMap) && params_len == 2 { Some(ImplicitHasherType::HashMap( hir_ty.span, ty, snippet(cx, params[0].span, "K"), snippet(cx, params[1].span, "V"), )) - } else if is_type_diagnostic_item(cx, ty, sym::hashset_type) && params_len == 1 { + } else if is_type_diagnostic_item(cx, ty, sym::HashSet) && params_len == 1 { Some(ImplicitHasherType::HashSet( hir_ty.span, ty, @@ -347,7 +355,7 @@ return; } - if self.cx.tcx.is_diagnostic_item(sym::hashmap_type, ty_did) { + if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashMap::default()".to_string()); @@ -360,7 +368,7 @@ ), ); } - } else if self.cx.tcx.is_diagnostic_item(sym::hashset_type, ty_did) { + } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) { if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashSet::default()".to_string()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/infinite_iter.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/infinite_iter.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/infinite_iter.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/infinite_iter.rs 2021-11-29 19:27:12.000000000 +0000 @@ -210,11 +210,11 @@ sym::BinaryHeap, sym::BTreeMap, sym::BTreeSet, - sym::hashmap_type, - sym::hashset_type, + sym::HashMap, + sym::HashSet, sym::LinkedList, - sym::vec_type, - sym::vecdeque_type, + sym::Vec, + sym::VecDeque, ]; fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/inherent_impl.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/inherent_impl.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/inherent_impl.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/inherent_impl.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::{in_macro, is_lint_allowed}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{def_id::LocalDefId, Crate, Item, ItemKind, Node}; +use rustc_hir::{def_id::LocalDefId, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; @@ -44,7 +44,7 @@ declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]); impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { - fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) { + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { // Map from a type to it's first impl block. Needed to distinguish generic arguments. // e.g. `Foo` and `Foo` let mut type_map = FxHashMap::default(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/inherent_to_string.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/inherent_to_string.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/inherent_to_string.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/inherent_to_string.rs 2021-11-29 19:27:12.000000000 +0000 @@ -111,7 +111,7 @@ if impl_item.generics.params.is_empty(); // Check if return type is String - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::string_type); + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String); // Filters instances of to_string which are required by a trait if trait_ref_of_method(cx, impl_item.hir_id()).is_none(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/integer_division.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/integer_division.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/integer_division.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/integer_division.rs 2021-11-29 19:27:12.000000000 +0000 @@ -48,7 +48,7 @@ fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool { if_chain! { if let hir::ExprKind::Binary(binop, left, right) = &expr.kind; - if let hir::BinOpKind::Div = &binop.node; + if binop.node == hir::BinOpKind::Div; then { let (left_ty, right_ty) = (cx.typeck_results().expr_ty(left), cx.typeck_results().expr_ty(right)); return left_ty.is_integral() && right_ty.is_integral(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/int_plus_one.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/int_plus_one.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/int_plus_one.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/int_plus_one.rs 2021-11-29 19:27:12.000000000 +0000 @@ -89,7 +89,7 @@ }, _ => None, } - } + }, // case where `x + 1 <= ...` or `1 + x <= ...` (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => @@ -104,7 +104,7 @@ }, _ => None, } - } + }, // case where `... >= y - 1` or `... >= -1 + y` (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,10 +2,10 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, IntTy, UintTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; -use rustc_target::abi::LayoutOf; use clippy_utils::comparisons::Rel; use clippy_utils::consts::{constant, Constant}; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,64 @@ +use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait}; +use rustc_hir::{ImplItem, ImplItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::kw; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`. + /// + /// ### Why is this bad? + /// Methods named `iter` or `iter_mut` conventionally return an `Iterator`. + /// + /// ### Example + /// ```rust + /// // `String` does not implement `Iterator` + /// struct Data {} + /// impl Data { + /// fn iter(&self) -> String { + /// todo!() + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::str::Chars; + /// struct Data {} + /// impl Data { + /// fn iter(&self) -> Chars<'static> { + /// todo!() + /// } + /// } + /// ``` + pub ITER_NOT_RETURNING_ITERATOR, + pedantic, + "methods named `iter` or `iter_mut` that do not return an `Iterator`" +} + +declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]); + +impl LateLintPass<'_> for IterNotReturningIterator { + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) { + let name: &str = &impl_item.ident.name.as_str(); + if_chain! { + if let ImplItemKind::Fn(fn_sig, _) = &impl_item.kind; + let ret_ty = return_ty(cx, impl_item.hir_id()); + if matches!(name, "iter" | "iter_mut"); + if let [param] = cx.tcx.fn_arg_names(impl_item.def_id); + if param.name == kw::SelfLower; + if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + if !implements_trait(cx, ret_ty, iter_trait_id, &[]); + + then { + span_lint( + cx, + ITER_NOT_RETURNING_ITERATOR, + fn_sig.span, + &format!("this method is named `{}` but its return type does not implement `Iterator`", name), + ); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_const_arrays.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_const_arrays.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_const_arrays.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_const_arrays.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,10 @@ -use crate::rustc_target::abi::LayoutOf; use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::ConstValue; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{BytePos, Pos, Span}; @@ -63,6 +63,7 @@ hi_pos - BytePos::from_usize("const".len()), hi_pos, item.span.ctxt(), + item.span.parent(), ); span_lint_and_then( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_enum_variant.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_enum_variant.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_enum_variant.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_enum_variant.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,13 +1,14 @@ //! lint when there is a large size difference between variants on an enum use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; -use rustc_hir::{Item, ItemKind, VariantData}; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::layout::LayoutOf; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_target::abi::LayoutOf; +use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does @@ -58,6 +59,17 @@ } } +struct FieldInfo { + ind: usize, + size: u64, +} + +struct VariantInfo { + ind: usize, + size: u64, + fields_size: Vec, +} + impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]); impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { @@ -68,72 +80,95 @@ if let ItemKind::Enum(ref def, _) = item.kind { let ty = cx.tcx.type_of(item.def_id); let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); - - let mut largest_variant: Option<(_, _)> = None; - let mut second_variant: Option<(_, _)> = None; - - for (i, variant) in adt.variants.iter().enumerate() { - let size: u64 = variant - .fields - .iter() - .filter_map(|f| { - let ty = cx.tcx.type_of(f.did); - // don't count generics by filtering out everything - // that does not have a layout - cx.layout_of(ty).ok().map(|l| l.size.bytes()) - }) - .sum(); - - let grouped = (size, (i, variant)); - - if grouped.0 >= largest_variant.map_or(0, |x| x.0) { - second_variant = largest_variant; - largest_variant = Some(grouped); - } + if adt.variants.len() <= 1 { + return; } - - if let (Some(largest), Some(second)) = (largest_variant, second_variant) { - let difference = largest.0 - second.0; - - if difference > self.maximum_size_difference_allowed { - let (i, variant) = largest.1; - - let help_text = "consider boxing the large fields to reduce the total size of the enum"; - span_lint_and_then( - cx, - LARGE_ENUM_VARIANT, - def.variants[i].span, - "large size difference between variants", - |diag| { - diag.span_label( - def.variants[(largest.1).0].span, - &format!("this variant is {} bytes", largest.0), - ); - diag.span_note( - def.variants[(second.1).0].span, - &format!("and the second-largest variant is {} bytes:", second.0), - ); - if variant.fields.len() == 1 { - let span = match def.variants[i].data { - VariantData::Struct(fields, ..) | VariantData::Tuple(fields, ..) => { - fields[0].ty.span - }, - VariantData::Unit(..) => unreachable!(), - }; - if let Some(snip) = snippet_opt(cx, span) { - diag.span_suggestion( - span, - help_text, - format!("Box<{}>", snip), - Applicability::MaybeIncorrect, - ); - return; + let mut variants_size: Vec = adt + .variants + .iter() + .enumerate() + .map(|(i, variant)| { + let mut fields_size = Vec::new(); + let size: u64 = variant + .fields + .iter() + .enumerate() + .filter_map(|(i, f)| { + let ty = cx.tcx.type_of(f.did); + // don't count generics by filtering out everything + // that does not have a layout + cx.layout_of(ty).ok().map(|l| { + let size = l.size.bytes(); + fields_size.push(FieldInfo { ind: i, size }); + size + }) + }) + .sum(); + VariantInfo { + ind: i, + size, + fields_size, + } + }) + .collect(); + + variants_size.sort_by(|a, b| (b.size.cmp(&a.size))); + + let mut difference = variants_size[0].size - variants_size[1].size; + if difference > self.maximum_size_difference_allowed { + let help_text = "consider boxing the large fields to reduce the total size of the enum"; + span_lint_and_then( + cx, + LARGE_ENUM_VARIANT, + def.variants[variants_size[0].ind].span, + "large size difference between variants", + |diag| { + diag.span_label( + def.variants[variants_size[0].ind].span, + &format!("this variant is {} bytes", variants_size[0].size), + ); + diag.span_note( + def.variants[variants_size[1].ind].span, + &format!("and the second-largest variant is {} bytes:", variants_size[1].size), + ); + + let fields = def.variants[variants_size[0].ind].data.fields(); + variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size))); + let mut applicability = Applicability::MaybeIncorrect; + let sugg: Vec<(Span, String)> = variants_size[0] + .fields_size + .iter() + .rev() + .map_while(|val| { + if difference > self.maximum_size_difference_allowed { + difference = difference.saturating_sub(val.size); + Some(( + fields[val.ind].ty.span, + format!( + "Box<{}>", + snippet_with_applicability( + cx, + fields[val.ind].ty.span, + "..", + &mut applicability + ) + .into_owned() + ), + )) + } else { + None } - } - diag.span_help(def.variants[i].span, help_text); - }, - ); - } + }) + .collect(); + + if !sugg.is_empty() { + diag.multipart_suggestion(help_text, sugg, Applicability::MaybeIncorrect); + return; + } + + diag.span_help(def.variants[variants_size[0].ind].span, help_text); + }, + ); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,11 +4,10 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::ConstValue; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::rustc_target::abi::LayoutOf; - declare_clippy_lint! { /// ### What it does /// Checks for local arrays that may be too large. diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/len_zero.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/len_zero.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/len_zero.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/len_zero.rs 2021-11-29 19:27:12.000000000 +0000 @@ -245,10 +245,10 @@ fn parse_len_output(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option> { match *sig.output().kind() { ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral), - ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) => { + ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => { subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did)) }, - ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::result_type, adt.did) => subs + ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did) => subs .type_at(0) .is_integral() .then(|| LenOutput::Result(adt.did, subs.type_at(1))), @@ -455,14 +455,10 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { - if let ty::AssocKind::Fn = item.kind { - if item.ident.name.as_str() == "is_empty" { - let sig = cx.tcx.fn_sig(item.def_id); - let ty = sig.skip_binder(); - ty.inputs().len() == 1 - } else { - false - } + if item.kind == ty::AssocKind::Fn && item.ident.name.as_str() == "is_empty" { + let sig = cx.tcx.fn_sig(item.def_id); + let ty = sig.skip_binder(); + ty.inputs().len() == 1 } else { false } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/let_if_seq.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/let_if_seq.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/let_if_seq.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/let_if_seq.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{path_to_local_id, visitors::LocalUsedVisitor}; +use clippy_utils::{path_to_local_id, visitors::is_local_used}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -65,11 +65,10 @@ if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; if let hir::StmtKind::Expr(if_) = expr.kind; if let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind; - let mut used_visitor = LocalUsedVisitor::new(cx, canonical_id); - if !used_visitor.check_expr(cond); + if !is_local_used(cx, *cond, canonical_id); if let hir::ExprKind::Block(then, _) = then.kind; if let Some(value) = check_assign(cx, canonical_id, &*then); - if !used_visitor.check_expr(value); + if !is_local_used(cx, value, canonical_id); then { let span = stmt.span.to(if_.span); @@ -148,15 +147,13 @@ if let hir::ExprKind::Assign(var, value, _) = expr.kind; if path_to_local_id(var, decl); then { - let mut v = LocalUsedVisitor::new(cx, decl); - - if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| v.check_stmt(stmt)) { - return None; + if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| is_local_used(cx, stmt, decl)) { + None + } else { + Some(value) } - - return Some(value); + } else { + None } } - - None } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.deprecated.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.deprecated.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.deprecated.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.deprecated.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,70 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +{ + store.register_removed( + "clippy::should_assert_eq", + "`assert!()` will be more flexible with RFC 2011", + ); + store.register_removed( + "clippy::extend_from_slice", + "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice", + ); + store.register_removed( + "clippy::range_step_by_zero", + "`iterator.step_by(0)` panics nowadays", + ); + store.register_removed( + "clippy::unstable_as_slice", + "`Vec::as_slice` has been stabilized in 1.7", + ); + store.register_removed( + "clippy::unstable_as_mut_slice", + "`Vec::as_mut_slice` has been stabilized in 1.7", + ); + store.register_removed( + "clippy::misaligned_transmute", + "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", + ); + store.register_removed( + "clippy::assign_ops", + "using compound assignment operators (e.g., `+=`) is harmless", + ); + store.register_removed( + "clippy::if_let_redundant_pattern_matching", + "this lint has been changed to redundant_pattern_matching", + ); + store.register_removed( + "clippy::unsafe_vector_initialization", + "the replacement suggested by this lint had substantially different behavior", + ); + store.register_removed( + "clippy::unused_collect", + "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint", + ); + store.register_removed( + "clippy::replace_consts", + "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants", + ); + store.register_removed( + "clippy::regex_macro", + "the regex! macro has been removed from the regex crate in 2018", + ); + store.register_removed( + "clippy::find_map", + "this lint has been replaced by `manual_find_map`, a more specific lint", + ); + store.register_removed( + "clippy::filter_map", + "this lint has been replaced by `manual_filter_map`, a more specific lint", + ); + store.register_removed( + "clippy::pub_enum_variant_names", + "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items", + ); + store.register_removed( + "clippy::wrong_pub_self_convention", + "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items", + ); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_all.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_all.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_all.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_all.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,302 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::all", Some("clippy_all"), vec![ + LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), + LintId::of(approx_const::APPROX_CONSTANT), + LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(assign_ops::ASSIGN_OP_PATTERN), + LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), + LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), + LintId::of(attrs::DEPRECATED_CFG_ATTR), + LintId::of(attrs::DEPRECATED_SEMVER), + LintId::of(attrs::MISMATCHED_TARGET_OS), + LintId::of(attrs::USELESS_ATTRIBUTE), + LintId::of(bit_mask::BAD_BIT_MASK), + LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), + LintId::of(blacklisted_name::BLACKLISTED_NAME), + LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), + LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), + LintId::of(booleans::LOGIC_BUG), + LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(casts::CAST_REF_TO_MUT), + LintId::of(casts::CHAR_LIT_AS_U8), + LintId::of(casts::FN_TO_NUMERIC_CAST), + LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(casts::UNNECESSARY_CAST), + LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), + LintId::of(collapsible_if::COLLAPSIBLE_IF), + LintId::of(collapsible_match::COLLAPSIBLE_MATCH), + LintId::of(comparison_chain::COMPARISON_CHAIN), + LintId::of(copies::IFS_SAME_COND), + LintId::of(copies::IF_SAME_THEN_ELSE), + LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), + LintId::of(derivable_impls::DERIVABLE_IMPLS), + LintId::of(derive::DERIVE_HASH_XOR_EQ), + LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), + LintId::of(doc::MISSING_SAFETY_DOC), + LintId::of(doc::NEEDLESS_DOCTEST_MAIN), + LintId::of(double_comparison::DOUBLE_COMPARISONS), + LintId::of(double_parens::DOUBLE_PARENS), + LintId::of(drop_forget_ref::DROP_COPY), + LintId::of(drop_forget_ref::DROP_REF), + LintId::of(drop_forget_ref::FORGET_COPY), + LintId::of(drop_forget_ref::FORGET_REF), + LintId::of(duration_subsec::DURATION_SUBSEC), + LintId::of(entry::MAP_ENTRY), + LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), + LintId::of(enum_variants::ENUM_VARIANT_NAMES), + LintId::of(enum_variants::MODULE_INCEPTION), + LintId::of(eq_op::EQ_OP), + LintId::of(eq_op::OP_REF), + LintId::of(erasing_op::ERASING_OP), + LintId::of(escape::BOXED_LOCAL), + LintId::of(eta_reduction::REDUNDANT_CLOSURE), + LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), + LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(explicit_write::EXPLICIT_WRITE), + LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(float_literal::EXCESSIVE_PRECISION), + LintId::of(format::USELESS_FORMAT), + LintId::of(formatting::POSSIBLE_MISSING_COMMA), + LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(from_over_into::FROM_OVER_INTO), + LintId::of(from_str_radix_10::FROM_STR_RADIX_10), + LintId::of(functions::DOUBLE_MUST_USE), + LintId::of(functions::MUST_USE_UNIT), + LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(functions::RESULT_UNIT_ERR), + LintId::of(functions::TOO_MANY_ARGUMENTS), + LintId::of(get_last_with_len::GET_LAST_WITH_LEN), + LintId::of(identity_op::IDENTITY_OP), + LintId::of(if_let_mutex::IF_LET_MUTEX), + LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), + LintId::of(infinite_iter::INFINITE_ITER), + LintId::of(inherent_to_string::INHERENT_TO_STRING), + LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(int_plus_one::INT_PLUS_ONE), + LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), + LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(len_zero::COMPARISON_TO_EMPTY), + LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), + LintId::of(len_zero::LEN_ZERO), + LintId::of(let_underscore::LET_UNDERSCORE_LOCK), + LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), + LintId::of(lifetimes::NEEDLESS_LIFETIMES), + LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), + LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), + LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), + LintId::of(loops::EMPTY_LOOP), + LintId::of(loops::EXPLICIT_COUNTER_LOOP), + LintId::of(loops::FOR_KV_MAP), + LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), + LintId::of(loops::ITER_NEXT_LOOP), + LintId::of(loops::MANUAL_FLATTEN), + LintId::of(loops::MANUAL_MEMCPY), + LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(loops::NEEDLESS_COLLECT), + LintId::of(loops::NEEDLESS_RANGE_LOOP), + LintId::of(loops::NEVER_LOOP), + LintId::of(loops::SAME_ITEM_PUSH), + LintId::of(loops::SINGLE_ELEMENT_LOOP), + LintId::of(loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(loops::WHILE_LET_LOOP), + LintId::of(loops::WHILE_LET_ON_ITERATOR), + LintId::of(main_recursion::MAIN_RECURSION), + LintId::of(manual_async_fn::MANUAL_ASYNC_FN), + LintId::of(manual_map::MANUAL_MAP), + LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), + LintId::of(manual_strip::MANUAL_STRIP), + LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), + LintId::of(map_clone::MAP_CLONE), + LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), + LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(match_result_ok::MATCH_RESULT_OK), + LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(matches::MATCH_AS_REF), + LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), + LintId::of(matches::MATCH_OVERLAPPING_ARM), + LintId::of(matches::MATCH_REF_PATS), + LintId::of(matches::MATCH_SINGLE_BINDING), + LintId::of(matches::REDUNDANT_PATTERN_MATCHING), + LintId::of(matches::SINGLE_MATCH), + LintId::of(matches::WILDCARD_IN_OR_PATTERNS), + LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_NTH), + LintId::of(methods::CHARS_LAST_CMP), + LintId::of(methods::CHARS_NEXT_CMP), + LintId::of(methods::CLONE_DOUBLE_REF), + LintId::of(methods::CLONE_ON_COPY), + LintId::of(methods::EXPECT_FUN_CALL), + LintId::of(methods::EXTEND_WITH_DRAIN), + LintId::of(methods::FILTER_MAP_IDENTITY), + LintId::of(methods::FILTER_NEXT), + LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::INSPECT_FOR_EACH), + LintId::of(methods::INTO_ITER_ON_REF), + LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::ITER_CLONED_COLLECT), + LintId::of(methods::ITER_COUNT), + LintId::of(methods::ITER_NEXT_SLICE), + LintId::of(methods::ITER_NTH), + LintId::of(methods::ITER_NTH_ZERO), + LintId::of(methods::ITER_SKIP_NEXT), + LintId::of(methods::MANUAL_FILTER_MAP), + LintId::of(methods::MANUAL_FIND_MAP), + LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MANUAL_SPLIT_ONCE), + LintId::of(methods::MANUAL_STR_REPEAT), + LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::OK_EXPECT), + LintId::of(methods::OPTION_AS_REF_DEREF), + LintId::of(methods::OPTION_FILTER_MAP), + LintId::of(methods::OPTION_MAP_OR_NONE), + LintId::of(methods::OR_FUN_CALL), + LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), + LintId::of(methods::SEARCH_IS_SOME), + LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(methods::SINGLE_CHAR_ADD_STR), + LintId::of(methods::SINGLE_CHAR_PATTERN), + LintId::of(methods::SKIP_WHILE_NEXT), + LintId::of(methods::STRING_EXTEND_CHARS), + LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(methods::SUSPICIOUS_SPLITN), + LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNNECESSARY_FILTER_MAP), + LintId::of(methods::UNNECESSARY_FOLD), + LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), + LintId::of(methods::USELESS_ASREF), + LintId::of(methods::WRONG_SELF_CONVENTION), + LintId::of(methods::ZST_OFFSET), + LintId::of(minmax::MIN_MAX), + LintId::of(misc::CMP_NAN), + LintId::of(misc::CMP_OWNED), + LintId::of(misc::MODULO_ONE), + LintId::of(misc::SHORT_CIRCUIT_STATEMENT), + LintId::of(misc::TOPLEVEL_REF_ARG), + LintId::of(misc::ZERO_PTR), + LintId::of(misc_early::BUILTIN_TYPE_SHADOW), + LintId::of(misc_early::DOUBLE_NEG), + LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), + LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), + LintId::of(misc_early::REDUNDANT_PATTERN), + LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), + LintId::of(misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), + LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(mutex_atomic::MUTEX_ATOMIC), + LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), + LintId::of(needless_bool::BOOL_COMPARISON), + LintId::of(needless_bool::NEEDLESS_BOOL), + LintId::of(needless_borrow::NEEDLESS_BORROW), + LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), + LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF), + LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), + LintId::of(needless_update::NEEDLESS_UPDATE), + LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), + LintId::of(neg_multiply::NEG_MULTIPLY), + LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(no_effect::NO_EFFECT), + LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), + LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), + LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), + LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), + LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(precedence::PRECEDENCE), + LintId::of(ptr::CMP_NULL), + LintId::of(ptr::INVALID_NULL_PTR_USAGE), + LintId::of(ptr::MUT_FROM_REF), + LintId::of(ptr::PTR_ARG), + LintId::of(ptr_eq::PTR_EQ), + LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), + LintId::of(question_mark::QUESTION_MARK), + LintId::of(ranges::MANUAL_RANGE_CONTAINS), + LintId::of(ranges::RANGE_ZIP_WITH_LEN), + LintId::of(ranges::REVERSED_EMPTY_RANGES), + LintId::of(redundant_clone::REDUNDANT_CLONE), + LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), + LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), + LintId::of(redundant_slicing::REDUNDANT_SLICING), + LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), + LintId::of(reference::DEREF_ADDROF), + LintId::of(reference::REF_IN_DEREF), + LintId::of(regex::INVALID_REGEX), + LintId::of(repeat_once::REPEAT_ONCE), + LintId::of(returns::LET_AND_RETURN), + LintId::of(returns::NEEDLESS_RETURN), + LintId::of(self_assignment::SELF_ASSIGNMENT), + LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), + LintId::of(serde_api::SERDE_API_MISUSE), + LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), + LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), + LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), + LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), + LintId::of(swap::ALMOST_SWAPPED), + LintId::of(swap::MANUAL_SWAP), + LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), + LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), + LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), + LintId::of(transmute::CROSSPOINTER_TRANSMUTE), + LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), + LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), + LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), + LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), + LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), + LintId::of(transmute::WRONG_TRANSMUTE), + LintId::of(transmuting_null::TRANSMUTING_NULL), + LintId::of(try_err::TRY_ERR), + LintId::of(types::BORROWED_BOX), + LintId::of(types::BOX_COLLECTION), + LintId::of(types::REDUNDANT_ALLOCATION), + LintId::of(types::TYPE_COMPLEXITY), + LintId::of(types::VEC_BOX), + LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), + LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), + LintId::of(unit_types::UNIT_ARG), + LintId::of(unit_types::UNIT_CMP), + LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), + LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(unused_unit::UNUSED_UNIT), + LintId::of(unwrap::PANICKING_UNWRAP), + LintId::of(unwrap::UNNECESSARY_UNWRAP), + LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), + LintId::of(useless_conversion::USELESS_CONVERSION), + LintId::of(vec::USELESS_VEC), + LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), + LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), + LintId::of(write::PRINTLN_EMPTY_STRING), + LintId::of(write::PRINT_LITERAL), + LintId::of(write::PRINT_WITH_NEWLINE), + LintId::of(write::WRITELN_EMPTY_STRING), + LintId::of(write::WRITE_LITERAL), + LintId::of(write::WRITE_WITH_NEWLINE), + LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_cargo.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_cargo.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_cargo.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_cargo.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,11 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![ + LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA), + LintId::of(feature_name::NEGATIVE_FEATURE_NAMES), + LintId::of(feature_name::REDUNDANT_FEATURE_NAMES), + LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS), + LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,94 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![ + LintId::of(attrs::DEPRECATED_CFG_ATTR), + LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(casts::CHAR_LIT_AS_U8), + LintId::of(casts::UNNECESSARY_CAST), + LintId::of(derivable_impls::DERIVABLE_IMPLS), + LintId::of(double_comparison::DOUBLE_COMPARISONS), + LintId::of(double_parens::DOUBLE_PARENS), + LintId::of(duration_subsec::DURATION_SUBSEC), + LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), + LintId::of(explicit_write::EXPLICIT_WRITE), + LintId::of(format::USELESS_FORMAT), + LintId::of(functions::TOO_MANY_ARGUMENTS), + LintId::of(get_last_with_len::GET_LAST_WITH_LEN), + LintId::of(identity_op::IDENTITY_OP), + LintId::of(int_plus_one::INT_PLUS_ONE), + LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), + LintId::of(lifetimes::NEEDLESS_LIFETIMES), + LintId::of(loops::EXPLICIT_COUNTER_LOOP), + LintId::of(loops::MANUAL_FLATTEN), + LintId::of(loops::SINGLE_ELEMENT_LOOP), + LintId::of(loops::WHILE_LET_LOOP), + LintId::of(manual_strip::MANUAL_STRIP), + LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), + LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), + LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(matches::MATCH_AS_REF), + LintId::of(matches::MATCH_SINGLE_BINDING), + LintId::of(matches::WILDCARD_IN_OR_PATTERNS), + LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::CLONE_ON_COPY), + LintId::of(methods::FILTER_MAP_IDENTITY), + LintId::of(methods::FILTER_NEXT), + LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::INSPECT_FOR_EACH), + LintId::of(methods::ITER_COUNT), + LintId::of(methods::MANUAL_FILTER_MAP), + LintId::of(methods::MANUAL_FIND_MAP), + LintId::of(methods::MANUAL_SPLIT_ONCE), + LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::OPTION_AS_REF_DEREF), + LintId::of(methods::OPTION_FILTER_MAP), + LintId::of(methods::SEARCH_IS_SOME), + LintId::of(methods::SKIP_WHILE_NEXT), + LintId::of(methods::UNNECESSARY_FILTER_MAP), + LintId::of(methods::USELESS_ASREF), + LintId::of(misc::SHORT_CIRCUIT_STATEMENT), + LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), + LintId::of(misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), + LintId::of(needless_bool::BOOL_COMPARISON), + LintId::of(needless_bool::NEEDLESS_BOOL), + LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), + LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF), + LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), + LintId::of(needless_update::NEEDLESS_UPDATE), + LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), + LintId::of(no_effect::NO_EFFECT), + LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), + LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(precedence::PRECEDENCE), + LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), + LintId::of(ranges::RANGE_ZIP_WITH_LEN), + LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), + LintId::of(redundant_slicing::REDUNDANT_SLICING), + LintId::of(reference::DEREF_ADDROF), + LintId::of(reference::REF_IN_DEREF), + LintId::of(repeat_once::REPEAT_ONCE), + LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), + LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), + LintId::of(swap::MANUAL_SWAP), + LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(transmute::CROSSPOINTER_TRANSMUTE), + LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), + LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), + LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), + LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), + LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(types::BORROWED_BOX), + LintId::of(types::TYPE_COMPLEXITY), + LintId::of(types::VEC_BOX), + LintId::of(unit_types::UNIT_ARG), + LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(unwrap::UNNECESSARY_UNWRAP), + LintId::of(useless_conversion::USELESS_CONVERSION), + LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,72 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ + LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), + LintId::of(approx_const::APPROX_CONSTANT), + LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), + LintId::of(attrs::DEPRECATED_SEMVER), + LintId::of(attrs::MISMATCHED_TARGET_OS), + LintId::of(attrs::USELESS_ATTRIBUTE), + LintId::of(bit_mask::BAD_BIT_MASK), + LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), + LintId::of(booleans::LOGIC_BUG), + LintId::of(casts::CAST_REF_TO_MUT), + LintId::of(copies::IFS_SAME_COND), + LintId::of(copies::IF_SAME_THEN_ELSE), + LintId::of(derive::DERIVE_HASH_XOR_EQ), + LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), + LintId::of(drop_forget_ref::DROP_COPY), + LintId::of(drop_forget_ref::DROP_REF), + LintId::of(drop_forget_ref::FORGET_COPY), + LintId::of(drop_forget_ref::FORGET_REF), + LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), + LintId::of(eq_op::EQ_OP), + LintId::of(erasing_op::ERASING_OP), + LintId::of(formatting::POSSIBLE_MISSING_COMMA), + LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(if_let_mutex::IF_LET_MUTEX), + LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), + LintId::of(infinite_iter::INFINITE_ITER), + LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(let_underscore::LET_UNDERSCORE_LOCK), + LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), + LintId::of(loops::ITER_NEXT_LOOP), + LintId::of(loops::NEVER_LOOP), + LintId::of(loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(methods::CLONE_DOUBLE_REF), + LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::SUSPICIOUS_SPLITN), + LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::ZST_OFFSET), + LintId::of(minmax::MIN_MAX), + LintId::of(misc::CMP_NAN), + LintId::of(misc::MODULO_ONE), + LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), + LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), + LintId::of(ptr::INVALID_NULL_PTR_USAGE), + LintId::of(ptr::MUT_FROM_REF), + LintId::of(ranges::REVERSED_EMPTY_RANGES), + LintId::of(regex::INVALID_REGEX), + LintId::of(self_assignment::SELF_ASSIGNMENT), + LintId::of(serde_api::SERDE_API_MISUSE), + LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), + LintId::of(swap::ALMOST_SWAPPED), + LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), + LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), + LintId::of(transmute::WRONG_TRANSMUTE), + LintId::of(transmuting_null::TRANSMUTING_NULL), + LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), + LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), + LintId::of(unit_types::UNIT_CMP), + LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), + LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(unwrap::PANICKING_UNWRAP), + LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_internal.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_internal.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_internal.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_internal.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,18 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ + LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL), + LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), + LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS), + LintId::of(utils::internal_lints::DEFAULT_LINT), + LintId::of(utils::internal_lints::IF_CHAIN_STYLE), + LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL), + LintId::of(utils::internal_lints::INVALID_PATHS), + LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS), + LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), + LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA), + LintId::of(utils::internal_lints::PRODUCE_ICE), + LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_lints.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_lints.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_lints.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_lints.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,509 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_lints(&[ + #[cfg(feature = "internal-lints")] + utils::internal_lints::CLIPPY_LINTS_INTERNAL, + #[cfg(feature = "internal-lints")] + utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, + #[cfg(feature = "internal-lints")] + utils::internal_lints::COMPILER_LINT_FUNCTIONS, + #[cfg(feature = "internal-lints")] + utils::internal_lints::DEFAULT_LINT, + #[cfg(feature = "internal-lints")] + utils::internal_lints::IF_CHAIN_STYLE, + #[cfg(feature = "internal-lints")] + utils::internal_lints::INTERNING_DEFINED_SYMBOL, + #[cfg(feature = "internal-lints")] + utils::internal_lints::INVALID_PATHS, + #[cfg(feature = "internal-lints")] + utils::internal_lints::LINT_WITHOUT_LINT_PASS, + #[cfg(feature = "internal-lints")] + utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + #[cfg(feature = "internal-lints")] + utils::internal_lints::OUTER_EXPN_EXPN_DATA, + #[cfg(feature = "internal-lints")] + utils::internal_lints::PRODUCE_ICE, + #[cfg(feature = "internal-lints")] + utils::internal_lints::UNNECESSARY_SYMBOL_STR, + absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, + approx_const::APPROX_CONSTANT, + arithmetic::FLOAT_ARITHMETIC, + arithmetic::INTEGER_ARITHMETIC, + as_conversions::AS_CONVERSIONS, + asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, + asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, + assertions_on_constants::ASSERTIONS_ON_CONSTANTS, + assign_ops::ASSIGN_OP_PATTERN, + assign_ops::MISREFACTORED_ASSIGN_OP, + async_yields_async::ASYNC_YIELDS_ASYNC, + attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, + attrs::DEPRECATED_CFG_ATTR, + attrs::DEPRECATED_SEMVER, + attrs::EMPTY_LINE_AFTER_OUTER_ATTR, + attrs::INLINE_ALWAYS, + attrs::MISMATCHED_TARGET_OS, + attrs::USELESS_ATTRIBUTE, + await_holding_invalid::AWAIT_HOLDING_LOCK, + await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, + bit_mask::BAD_BIT_MASK, + bit_mask::INEFFECTIVE_BIT_MASK, + bit_mask::VERBOSE_BIT_MASK, + blacklisted_name::BLACKLISTED_NAME, + blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, + bool_assert_comparison::BOOL_ASSERT_COMPARISON, + booleans::LOGIC_BUG, + booleans::NONMINIMAL_BOOL, + bytecount::NAIVE_BYTECOUNT, + cargo_common_metadata::CARGO_COMMON_METADATA, + case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + casts::CAST_LOSSLESS, + casts::CAST_POSSIBLE_TRUNCATION, + casts::CAST_POSSIBLE_WRAP, + casts::CAST_PRECISION_LOSS, + casts::CAST_PTR_ALIGNMENT, + casts::CAST_REF_TO_MUT, + casts::CAST_SIGN_LOSS, + casts::CHAR_LIT_AS_U8, + casts::FN_TO_NUMERIC_CAST, + casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, + casts::PTR_AS_PTR, + casts::UNNECESSARY_CAST, + checked_conversions::CHECKED_CONVERSIONS, + cognitive_complexity::COGNITIVE_COMPLEXITY, + collapsible_if::COLLAPSIBLE_ELSE_IF, + collapsible_if::COLLAPSIBLE_IF, + collapsible_match::COLLAPSIBLE_MATCH, + comparison_chain::COMPARISON_CHAIN, + copies::BRANCHES_SHARING_CODE, + copies::IFS_SAME_COND, + copies::IF_SAME_THEN_ELSE, + copies::SAME_FUNCTIONS_IN_IF_CONDITION, + copy_iterator::COPY_ITERATOR, + create_dir::CREATE_DIR, + dbg_macro::DBG_MACRO, + default::DEFAULT_TRAIT_ACCESS, + default::FIELD_REASSIGN_WITH_DEFAULT, + default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK, + dereference::EXPLICIT_DEREF_METHODS, + derivable_impls::DERIVABLE_IMPLS, + derive::DERIVE_HASH_XOR_EQ, + derive::DERIVE_ORD_XOR_PARTIAL_ORD, + derive::EXPL_IMPL_CLONE_ON_COPY, + derive::UNSAFE_DERIVE_DESERIALIZE, + disallowed_method::DISALLOWED_METHOD, + disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS, + disallowed_type::DISALLOWED_TYPE, + doc::DOC_MARKDOWN, + doc::MISSING_ERRORS_DOC, + doc::MISSING_PANICS_DOC, + doc::MISSING_SAFETY_DOC, + doc::NEEDLESS_DOCTEST_MAIN, + double_comparison::DOUBLE_COMPARISONS, + double_parens::DOUBLE_PARENS, + drop_forget_ref::DROP_COPY, + drop_forget_ref::DROP_REF, + drop_forget_ref::FORGET_COPY, + drop_forget_ref::FORGET_REF, + duration_subsec::DURATION_SUBSEC, + else_if_without_else::ELSE_IF_WITHOUT_ELSE, + empty_enum::EMPTY_ENUM, + entry::MAP_ENTRY, + enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, + enum_variants::ENUM_VARIANT_NAMES, + enum_variants::MODULE_INCEPTION, + enum_variants::MODULE_NAME_REPETITIONS, + eq_op::EQ_OP, + eq_op::OP_REF, + equatable_if_let::EQUATABLE_IF_LET, + erasing_op::ERASING_OP, + escape::BOXED_LOCAL, + eta_reduction::REDUNDANT_CLOSURE, + eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, + eval_order_dependence::DIVERGING_SUB_EXPRESSION, + eval_order_dependence::EVAL_ORDER_DEPENDENCE, + excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, + excessive_bools::STRUCT_EXCESSIVE_BOOLS, + exhaustive_items::EXHAUSTIVE_ENUMS, + exhaustive_items::EXHAUSTIVE_STRUCTS, + exit::EXIT, + explicit_write::EXPLICIT_WRITE, + fallible_impl_from::FALLIBLE_IMPL_FROM, + feature_name::NEGATIVE_FEATURE_NAMES, + feature_name::REDUNDANT_FEATURE_NAMES, + float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, + float_literal::EXCESSIVE_PRECISION, + float_literal::LOSSY_FLOAT_LITERAL, + floating_point_arithmetic::IMPRECISE_FLOPS, + floating_point_arithmetic::SUBOPTIMAL_FLOPS, + format::USELESS_FORMAT, + formatting::POSSIBLE_MISSING_COMMA, + formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, + formatting::SUSPICIOUS_ELSE_FORMATTING, + formatting::SUSPICIOUS_UNARY_OP_FORMATTING, + from_over_into::FROM_OVER_INTO, + from_str_radix_10::FROM_STR_RADIX_10, + functions::DOUBLE_MUST_USE, + functions::MUST_USE_CANDIDATE, + functions::MUST_USE_UNIT, + functions::NOT_UNSAFE_PTR_ARG_DEREF, + functions::RESULT_UNIT_ERR, + functions::TOO_MANY_ARGUMENTS, + functions::TOO_MANY_LINES, + future_not_send::FUTURE_NOT_SEND, + get_last_with_len::GET_LAST_WITH_LEN, + identity_op::IDENTITY_OP, + if_let_mutex::IF_LET_MUTEX, + if_not_else::IF_NOT_ELSE, + if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, + implicit_hasher::IMPLICIT_HASHER, + implicit_return::IMPLICIT_RETURN, + implicit_saturating_sub::IMPLICIT_SATURATING_SUB, + inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR, + indexing_slicing::INDEXING_SLICING, + indexing_slicing::OUT_OF_BOUNDS_INDEXING, + infinite_iter::INFINITE_ITER, + infinite_iter::MAYBE_INFINITE_ITER, + inherent_impl::MULTIPLE_INHERENT_IMPL, + inherent_to_string::INHERENT_TO_STRING, + inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, + inline_fn_without_body::INLINE_FN_WITHOUT_BODY, + int_plus_one::INT_PLUS_ONE, + integer_division::INTEGER_DIVISION, + invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS, + items_after_statements::ITEMS_AFTER_STATEMENTS, + iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, + large_const_arrays::LARGE_CONST_ARRAYS, + large_enum_variant::LARGE_ENUM_VARIANT, + large_stack_arrays::LARGE_STACK_ARRAYS, + len_zero::COMPARISON_TO_EMPTY, + len_zero::LEN_WITHOUT_IS_EMPTY, + len_zero::LEN_ZERO, + let_if_seq::USELESS_LET_IF_SEQ, + let_underscore::LET_UNDERSCORE_DROP, + let_underscore::LET_UNDERSCORE_LOCK, + let_underscore::LET_UNDERSCORE_MUST_USE, + lifetimes::EXTRA_UNUSED_LIFETIMES, + lifetimes::NEEDLESS_LIFETIMES, + literal_representation::DECIMAL_LITERAL_REPRESENTATION, + literal_representation::INCONSISTENT_DIGIT_GROUPING, + literal_representation::LARGE_DIGIT_GROUPS, + literal_representation::MISTYPED_LITERAL_SUFFIXES, + literal_representation::UNREADABLE_LITERAL, + literal_representation::UNUSUAL_BYTE_GROUPINGS, + loops::EMPTY_LOOP, + loops::EXPLICIT_COUNTER_LOOP, + loops::EXPLICIT_INTO_ITER_LOOP, + loops::EXPLICIT_ITER_LOOP, + loops::FOR_KV_MAP, + loops::FOR_LOOPS_OVER_FALLIBLES, + loops::ITER_NEXT_LOOP, + loops::MANUAL_FLATTEN, + loops::MANUAL_MEMCPY, + loops::MUT_RANGE_BOUND, + loops::NEEDLESS_COLLECT, + loops::NEEDLESS_RANGE_LOOP, + loops::NEVER_LOOP, + loops::SAME_ITEM_PUSH, + loops::SINGLE_ELEMENT_LOOP, + loops::WHILE_IMMUTABLE_CONDITION, + loops::WHILE_LET_LOOP, + loops::WHILE_LET_ON_ITERATOR, + macro_use::MACRO_USE_IMPORTS, + main_recursion::MAIN_RECURSION, + manual_assert::MANUAL_ASSERT, + manual_async_fn::MANUAL_ASYNC_FN, + manual_map::MANUAL_MAP, + manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, + manual_ok_or::MANUAL_OK_OR, + manual_strip::MANUAL_STRIP, + manual_unwrap_or::MANUAL_UNWRAP_OR, + map_clone::MAP_CLONE, + map_err_ignore::MAP_ERR_IGNORE, + map_unit_fn::OPTION_MAP_UNIT_FN, + map_unit_fn::RESULT_MAP_UNIT_FN, + match_on_vec_items::MATCH_ON_VEC_ITEMS, + match_result_ok::MATCH_RESULT_OK, + matches::INFALLIBLE_DESTRUCTURING_MATCH, + matches::MATCH_AS_REF, + matches::MATCH_BOOL, + matches::MATCH_LIKE_MATCHES_MACRO, + matches::MATCH_OVERLAPPING_ARM, + matches::MATCH_REF_PATS, + matches::MATCH_SAME_ARMS, + matches::MATCH_SINGLE_BINDING, + matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + matches::MATCH_WILD_ERR_ARM, + matches::REDUNDANT_PATTERN_MATCHING, + matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, + matches::SINGLE_MATCH, + matches::SINGLE_MATCH_ELSE, + matches::WILDCARD_ENUM_MATCH_ARM, + matches::WILDCARD_IN_OR_PATTERNS, + mem_forget::MEM_FORGET, + mem_replace::MEM_REPLACE_OPTION_WITH_NONE, + mem_replace::MEM_REPLACE_WITH_DEFAULT, + mem_replace::MEM_REPLACE_WITH_UNINIT, + methods::BIND_INSTEAD_OF_MAP, + methods::BYTES_NTH, + methods::CHARS_LAST_CMP, + methods::CHARS_NEXT_CMP, + methods::CLONED_INSTEAD_OF_COPIED, + methods::CLONE_DOUBLE_REF, + methods::CLONE_ON_COPY, + methods::CLONE_ON_REF_PTR, + methods::EXPECT_FUN_CALL, + methods::EXPECT_USED, + methods::EXTEND_WITH_DRAIN, + methods::FILETYPE_IS_FILE, + methods::FILTER_MAP_IDENTITY, + methods::FILTER_MAP_NEXT, + methods::FILTER_NEXT, + methods::FLAT_MAP_IDENTITY, + methods::FLAT_MAP_OPTION, + methods::FROM_ITER_INSTEAD_OF_COLLECT, + methods::GET_UNWRAP, + methods::IMPLICIT_CLONE, + methods::INEFFICIENT_TO_STRING, + methods::INSPECT_FOR_EACH, + methods::INTO_ITER_ON_REF, + methods::ITERATOR_STEP_BY_ZERO, + methods::ITER_CLONED_COLLECT, + methods::ITER_COUNT, + methods::ITER_NEXT_SLICE, + methods::ITER_NTH, + methods::ITER_NTH_ZERO, + methods::ITER_SKIP_NEXT, + methods::MANUAL_FILTER_MAP, + methods::MANUAL_FIND_MAP, + methods::MANUAL_SATURATING_ARITHMETIC, + methods::MANUAL_SPLIT_ONCE, + methods::MANUAL_STR_REPEAT, + methods::MAP_COLLECT_RESULT_UNIT, + methods::MAP_FLATTEN, + methods::MAP_IDENTITY, + methods::MAP_UNWRAP_OR, + methods::NEW_RET_NO_SELF, + methods::OK_EXPECT, + methods::OPTION_AS_REF_DEREF, + methods::OPTION_FILTER_MAP, + methods::OPTION_MAP_OR_NONE, + methods::OR_FUN_CALL, + methods::RESULT_MAP_OR_INTO_OPTION, + methods::SEARCH_IS_SOME, + methods::SHOULD_IMPLEMENT_TRAIT, + methods::SINGLE_CHAR_ADD_STR, + methods::SINGLE_CHAR_PATTERN, + methods::SKIP_WHILE_NEXT, + methods::STRING_EXTEND_CHARS, + methods::SUSPICIOUS_MAP, + methods::SUSPICIOUS_SPLITN, + methods::UNINIT_ASSUMED_INIT, + methods::UNNECESSARY_FILTER_MAP, + methods::UNNECESSARY_FOLD, + methods::UNNECESSARY_LAZY_EVALUATIONS, + methods::UNWRAP_OR_ELSE_DEFAULT, + methods::UNWRAP_USED, + methods::USELESS_ASREF, + methods::WRONG_SELF_CONVENTION, + methods::ZST_OFFSET, + minmax::MIN_MAX, + misc::CMP_NAN, + misc::CMP_OWNED, + misc::FLOAT_CMP, + misc::FLOAT_CMP_CONST, + misc::MODULO_ONE, + misc::SHORT_CIRCUIT_STATEMENT, + misc::TOPLEVEL_REF_ARG, + misc::USED_UNDERSCORE_BINDING, + misc::ZERO_PTR, + misc_early::BUILTIN_TYPE_SHADOW, + misc_early::DOUBLE_NEG, + misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, + misc_early::MIXED_CASE_HEX_LITERALS, + misc_early::REDUNDANT_PATTERN, + misc_early::UNNEEDED_FIELD_PATTERN, + misc_early::UNNEEDED_WILDCARD_PATTERN, + misc_early::UNSEPARATED_LITERAL_SUFFIX, + misc_early::ZERO_PREFIXED_LITERAL, + missing_const_for_fn::MISSING_CONST_FOR_FN, + missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, + missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES, + missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, + module_style::MOD_MODULE_FILES, + module_style::SELF_NAMED_MODULE_FILES, + modulo_arithmetic::MODULO_ARITHMETIC, + multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, + mut_key::MUTABLE_KEY_TYPE, + mut_mut::MUT_MUT, + mut_mutex_lock::MUT_MUTEX_LOCK, + mut_reference::UNNECESSARY_MUT_PASSED, + mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, + mutex_atomic::MUTEX_ATOMIC, + mutex_atomic::MUTEX_INTEGER, + needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, + needless_bitwise_bool::NEEDLESS_BITWISE_BOOL, + needless_bool::BOOL_COMPARISON, + needless_bool::NEEDLESS_BOOL, + needless_borrow::NEEDLESS_BORROW, + needless_borrow::REF_BINDING_TO_REFERENCE, + needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, + needless_continue::NEEDLESS_CONTINUE, + needless_for_each::NEEDLESS_FOR_EACH, + needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF, + needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, + needless_question_mark::NEEDLESS_QUESTION_MARK, + needless_update::NEEDLESS_UPDATE, + neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, + neg_multiply::NEG_MULTIPLY, + new_without_default::NEW_WITHOUT_DEFAULT, + no_effect::NO_EFFECT, + no_effect::UNNECESSARY_OPERATION, + non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, + non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, + non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, + non_expressive_names::MANY_SINGLE_CHAR_NAMES, + non_expressive_names::SIMILAR_NAMES, + non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS, + non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY, + nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, + open_options::NONSENSICAL_OPEN_OPTIONS, + option_env_unwrap::OPTION_ENV_UNWRAP, + option_if_let_else::OPTION_IF_LET_ELSE, + overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, + panic_in_result_fn::PANIC_IN_RESULT_FN, + panic_unimplemented::PANIC, + panic_unimplemented::TODO, + panic_unimplemented::UNIMPLEMENTED, + panic_unimplemented::UNREACHABLE, + partialeq_ne_impl::PARTIALEQ_NE_IMPL, + pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, + pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, + path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, + pattern_type_mismatch::PATTERN_TYPE_MISMATCH, + precedence::PRECEDENCE, + ptr::CMP_NULL, + ptr::INVALID_NULL_PTR_USAGE, + ptr::MUT_FROM_REF, + ptr::PTR_ARG, + ptr_eq::PTR_EQ, + ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, + question_mark::QUESTION_MARK, + ranges::MANUAL_RANGE_CONTAINS, + ranges::RANGE_MINUS_ONE, + ranges::RANGE_PLUS_ONE, + ranges::RANGE_ZIP_WITH_LEN, + ranges::REVERSED_EMPTY_RANGES, + redundant_clone::REDUNDANT_CLONE, + redundant_closure_call::REDUNDANT_CLOSURE_CALL, + redundant_else::REDUNDANT_ELSE, + redundant_field_names::REDUNDANT_FIELD_NAMES, + redundant_pub_crate::REDUNDANT_PUB_CRATE, + redundant_slicing::REDUNDANT_SLICING, + redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, + ref_option_ref::REF_OPTION_REF, + reference::DEREF_ADDROF, + reference::REF_IN_DEREF, + regex::INVALID_REGEX, + regex::TRIVIAL_REGEX, + repeat_once::REPEAT_ONCE, + returns::LET_AND_RETURN, + returns::NEEDLESS_RETURN, + same_name_method::SAME_NAME_METHOD, + self_assignment::SELF_ASSIGNMENT, + self_named_constructors::SELF_NAMED_CONSTRUCTORS, + semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, + serde_api::SERDE_API_MISUSE, + shadow::SHADOW_REUSE, + shadow::SHADOW_SAME, + shadow::SHADOW_UNRELATED, + single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, + size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, + slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, + stable_sort_primitive::STABLE_SORT_PRIMITIVE, + strings::STRING_ADD, + strings::STRING_ADD_ASSIGN, + strings::STRING_FROM_UTF8_AS_BYTES, + strings::STRING_LIT_AS_BYTES, + strings::STRING_TO_STRING, + strings::STR_TO_STRING, + strlen_on_c_strings::STRLEN_ON_C_STRINGS, + suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS, + suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, + suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, + swap::ALMOST_SWAPPED, + swap::MANUAL_SWAP, + tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, + temporary_assignment::TEMPORARY_ASSIGNMENT, + to_digit_is_some::TO_DIGIT_IS_SOME, + to_string_in_display::TO_STRING_IN_DISPLAY, + trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, + trait_bounds::TYPE_REPETITION_IN_BOUNDS, + transmute::CROSSPOINTER_TRANSMUTE, + transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, + transmute::TRANSMUTE_BYTES_TO_STR, + transmute::TRANSMUTE_FLOAT_TO_INT, + transmute::TRANSMUTE_INT_TO_BOOL, + transmute::TRANSMUTE_INT_TO_CHAR, + transmute::TRANSMUTE_INT_TO_FLOAT, + transmute::TRANSMUTE_PTR_TO_PTR, + transmute::TRANSMUTE_PTR_TO_REF, + transmute::UNSOUND_COLLECTION_TRANSMUTE, + transmute::USELESS_TRANSMUTE, + transmute::WRONG_TRANSMUTE, + transmuting_null::TRANSMUTING_NULL, + try_err::TRY_ERR, + types::BORROWED_BOX, + types::BOX_COLLECTION, + types::LINKEDLIST, + types::OPTION_OPTION, + types::RC_BUFFER, + types::RC_MUTEX, + types::REDUNDANT_ALLOCATION, + types::TYPE_COMPLEXITY, + types::VEC_BOX, + undropped_manually_drops::UNDROPPED_MANUALLY_DROPS, + unicode::INVISIBLE_CHARACTERS, + unicode::NON_ASCII_LITERAL, + unicode::UNICODE_NOT_NFC, + unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, + unit_types::LET_UNIT_VALUE, + unit_types::UNIT_ARG, + unit_types::UNIT_CMP, + unnamed_address::FN_ADDRESS_COMPARISONS, + unnamed_address::VTABLE_ADDRESS_COMPARISONS, + unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS, + unnecessary_sort_by::UNNECESSARY_SORT_BY, + unnecessary_wraps::UNNECESSARY_WRAPS, + unnested_or_patterns::UNNESTED_OR_PATTERNS, + unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + unused_async::UNUSED_ASYNC, + unused_io_amount::UNUSED_IO_AMOUNT, + unused_self::UNUSED_SELF, + unused_unit::UNUSED_UNIT, + unwrap::PANICKING_UNWRAP, + unwrap::UNNECESSARY_UNWRAP, + unwrap_in_result::UNWRAP_IN_RESULT, + upper_case_acronyms::UPPER_CASE_ACRONYMS, + use_self::USE_SELF, + useless_conversion::USELESS_CONVERSION, + vec::USELESS_VEC, + vec_init_then_push::VEC_INIT_THEN_PUSH, + vec_resize_to_zero::VEC_RESIZE_TO_ZERO, + verbose_file_reads::VERBOSE_FILE_READS, + wildcard_dependencies::WILDCARD_DEPENDENCIES, + wildcard_imports::ENUM_GLOB_USE, + wildcard_imports::WILDCARD_IMPORTS, + write::PRINTLN_EMPTY_STRING, + write::PRINT_LITERAL, + write::PRINT_STDERR, + write::PRINT_STDOUT, + write::PRINT_WITH_NEWLINE, + write::USE_DEBUG, + write::WRITELN_EMPTY_STRING, + write::WRITE_LITERAL, + write::WRITE_WITH_NEWLINE, + zero_div_zero::ZERO_DIVIDED_BY_ZERO, + zero_sized_map_values::ZERO_SIZED_MAP_VALUES, +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,30 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ + LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR), + LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY), + LintId::of(copies::BRANCHES_SHARING_CODE), + LintId::of(disallowed_method::DISALLOWED_METHOD), + LintId::of(disallowed_type::DISALLOWED_TYPE), + LintId::of(equatable_if_let::EQUATABLE_IF_LET), + LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS), + LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS), + LintId::of(future_not_send::FUTURE_NOT_SEND), + LintId::of(let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), + LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), + LintId::of(mutex_atomic::MUTEX_INTEGER), + LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY), + LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), + LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), + LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), + LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), + LintId::of(regex::TRIVIAL_REGEX), + LintId::of(strings::STRING_LIT_AS_BYTES), + LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), + LintId::of(transmute::USELESS_TRANSMUTE), + LintId::of(use_self::USE_SELF), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,101 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ + LintId::of(attrs::INLINE_ALWAYS), + LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), + LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), + LintId::of(bit_mask::VERBOSE_BIT_MASK), + LintId::of(bytecount::NAIVE_BYTECOUNT), + LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), + LintId::of(casts::CAST_LOSSLESS), + LintId::of(casts::CAST_POSSIBLE_TRUNCATION), + LintId::of(casts::CAST_POSSIBLE_WRAP), + LintId::of(casts::CAST_PRECISION_LOSS), + LintId::of(casts::CAST_PTR_ALIGNMENT), + LintId::of(casts::CAST_SIGN_LOSS), + LintId::of(casts::PTR_AS_PTR), + LintId::of(checked_conversions::CHECKED_CONVERSIONS), + LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION), + LintId::of(copy_iterator::COPY_ITERATOR), + LintId::of(default::DEFAULT_TRAIT_ACCESS), + LintId::of(dereference::EXPLICIT_DEREF_METHODS), + LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY), + LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE), + LintId::of(doc::DOC_MARKDOWN), + LintId::of(doc::MISSING_ERRORS_DOC), + LintId::of(doc::MISSING_PANICS_DOC), + LintId::of(empty_enum::EMPTY_ENUM), + LintId::of(enum_variants::MODULE_NAME_REPETITIONS), + LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), + LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), + LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS), + LintId::of(functions::MUST_USE_CANDIDATE), + LintId::of(functions::TOO_MANY_LINES), + LintId::of(if_not_else::IF_NOT_ELSE), + LintId::of(implicit_hasher::IMPLICIT_HASHER), + LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB), + LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), + LintId::of(infinite_iter::MAYBE_INFINITE_ITER), + LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), + LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), + LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR), + LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), + LintId::of(let_underscore::LET_UNDERSCORE_DROP), + LintId::of(literal_representation::LARGE_DIGIT_GROUPS), + LintId::of(literal_representation::UNREADABLE_LITERAL), + LintId::of(loops::EXPLICIT_INTO_ITER_LOOP), + LintId::of(loops::EXPLICIT_ITER_LOOP), + LintId::of(macro_use::MACRO_USE_IMPORTS), + LintId::of(manual_assert::MANUAL_ASSERT), + LintId::of(manual_ok_or::MANUAL_OK_OR), + LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS), + LintId::of(matches::MATCH_BOOL), + LintId::of(matches::MATCH_SAME_ARMS), + LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), + LintId::of(matches::MATCH_WILD_ERR_ARM), + LintId::of(matches::SINGLE_MATCH_ELSE), + LintId::of(methods::CLONED_INSTEAD_OF_COPIED), + LintId::of(methods::FILTER_MAP_NEXT), + LintId::of(methods::FLAT_MAP_OPTION), + LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), + LintId::of(methods::IMPLICIT_CLONE), + LintId::of(methods::INEFFICIENT_TO_STRING), + LintId::of(methods::MAP_FLATTEN), + LintId::of(methods::MAP_UNWRAP_OR), + LintId::of(misc::FLOAT_CMP), + LintId::of(misc::USED_UNDERSCORE_BINDING), + LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), + LintId::of(mut_mut::MUT_MUT), + LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL), + LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE), + LintId::of(needless_continue::NEEDLESS_CONTINUE), + LintId::of(needless_for_each::NEEDLESS_FOR_EACH), + LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), + LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), + LintId::of(non_expressive_names::SIMILAR_NAMES), + LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE), + LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), + LintId::of(ranges::RANGE_MINUS_ONE), + LintId::of(ranges::RANGE_PLUS_ONE), + LintId::of(redundant_else::REDUNDANT_ELSE), + LintId::of(ref_option_ref::REF_OPTION_REF), + LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), + LintId::of(strings::STRING_ADD_ASSIGN), + LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), + LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS), + LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), + LintId::of(types::LINKEDLIST), + LintId::of(types::OPTION_OPTION), + LintId::of(unicode::NON_ASCII_LITERAL), + LintId::of(unicode::UNICODE_NOT_NFC), + LintId::of(unit_types::LET_UNIT_VALUE), + LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS), + LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS), + LintId::of(unused_async::UNUSED_ASYNC), + LintId::of(unused_self::UNUSED_SELF), + LintId::of(wildcard_imports::ENUM_GLOB_USE), + LintId::of(wildcard_imports::WILDCARD_IMPORTS), + LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_perf.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_perf.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_perf.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_perf.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,27 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ + LintId::of(entry::MAP_ENTRY), + LintId::of(escape::BOXED_LOCAL), + LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), + LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(loops::MANUAL_MEMCPY), + LintId::of(loops::NEEDLESS_COLLECT), + LintId::of(methods::EXPECT_FUN_CALL), + LintId::of(methods::EXTEND_WITH_DRAIN), + LintId::of(methods::ITER_NTH), + LintId::of(methods::MANUAL_STR_REPEAT), + LintId::of(methods::OR_FUN_CALL), + LintId::of(methods::SINGLE_CHAR_PATTERN), + LintId::of(misc::CMP_OWNED), + LintId::of(mutex_atomic::MUTEX_ATOMIC), + LintId::of(redundant_clone::REDUNDANT_CLONE), + LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(types::BOX_COLLECTION), + LintId::of(types::REDUNDANT_ALLOCATION), + LintId::of(vec::USELESS_VEC), + LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,65 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ + LintId::of(arithmetic::FLOAT_ARITHMETIC), + LintId::of(arithmetic::INTEGER_ARITHMETIC), + LintId::of(as_conversions::AS_CONVERSIONS), + LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), + LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), + LintId::of(create_dir::CREATE_DIR), + LintId::of(dbg_macro::DBG_MACRO), + LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK), + LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS), + LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE), + LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS), + LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS), + LintId::of(exit::EXIT), + LintId::of(float_literal::LOSSY_FLOAT_LITERAL), + LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE), + LintId::of(implicit_return::IMPLICIT_RETURN), + LintId::of(indexing_slicing::INDEXING_SLICING), + LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL), + LintId::of(integer_division::INTEGER_DIVISION), + LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), + LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), + LintId::of(map_err_ignore::MAP_ERR_IGNORE), + LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), + LintId::of(matches::WILDCARD_ENUM_MATCH_ARM), + LintId::of(mem_forget::MEM_FORGET), + LintId::of(methods::CLONE_ON_REF_PTR), + LintId::of(methods::EXPECT_USED), + LintId::of(methods::FILETYPE_IS_FILE), + LintId::of(methods::GET_UNWRAP), + LintId::of(methods::UNWRAP_USED), + LintId::of(misc::FLOAT_CMP_CONST), + LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), + LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), + LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES), + LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), + LintId::of(module_style::MOD_MODULE_FILES), + LintId::of(module_style::SELF_NAMED_MODULE_FILES), + LintId::of(modulo_arithmetic::MODULO_ARITHMETIC), + LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN), + LintId::of(panic_unimplemented::PANIC), + LintId::of(panic_unimplemented::TODO), + LintId::of(panic_unimplemented::UNIMPLEMENTED), + LintId::of(panic_unimplemented::UNREACHABLE), + LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH), + LintId::of(same_name_method::SAME_NAME_METHOD), + LintId::of(shadow::SHADOW_REUSE), + LintId::of(shadow::SHADOW_SAME), + LintId::of(shadow::SHADOW_UNRELATED), + LintId::of(strings::STRING_ADD), + LintId::of(strings::STRING_TO_STRING), + LintId::of(strings::STR_TO_STRING), + LintId::of(types::RC_BUFFER), + LintId::of(types::RC_MUTEX), + LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), + LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), + LintId::of(verbose_file_reads::VERBOSE_FILE_READS), + LintId::of(write::PRINT_STDERR), + LintId::of(write::PRINT_STDOUT), + LintId::of(write::USE_DEBUG), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_style.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_style.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_style.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_style.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,113 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::style", Some("clippy_style"), vec![ + LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(assign_ops::ASSIGN_OP_PATTERN), + LintId::of(blacklisted_name::BLACKLISTED_NAME), + LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), + LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), + LintId::of(casts::FN_TO_NUMERIC_CAST), + LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), + LintId::of(collapsible_if::COLLAPSIBLE_IF), + LintId::of(collapsible_match::COLLAPSIBLE_MATCH), + LintId::of(comparison_chain::COMPARISON_CHAIN), + LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), + LintId::of(doc::MISSING_SAFETY_DOC), + LintId::of(doc::NEEDLESS_DOCTEST_MAIN), + LintId::of(enum_variants::ENUM_VARIANT_NAMES), + LintId::of(enum_variants::MODULE_INCEPTION), + LintId::of(eq_op::OP_REF), + LintId::of(eta_reduction::REDUNDANT_CLOSURE), + LintId::of(float_literal::EXCESSIVE_PRECISION), + LintId::of(from_over_into::FROM_OVER_INTO), + LintId::of(from_str_radix_10::FROM_STR_RADIX_10), + LintId::of(functions::DOUBLE_MUST_USE), + LintId::of(functions::MUST_USE_UNIT), + LintId::of(functions::RESULT_UNIT_ERR), + LintId::of(inherent_to_string::INHERENT_TO_STRING), + LintId::of(len_zero::COMPARISON_TO_EMPTY), + LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), + LintId::of(len_zero::LEN_ZERO), + LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), + LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), + LintId::of(loops::FOR_KV_MAP), + LintId::of(loops::NEEDLESS_RANGE_LOOP), + LintId::of(loops::SAME_ITEM_PUSH), + LintId::of(loops::WHILE_LET_ON_ITERATOR), + LintId::of(main_recursion::MAIN_RECURSION), + LintId::of(manual_async_fn::MANUAL_ASYNC_FN), + LintId::of(manual_map::MANUAL_MAP), + LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), + LintId::of(map_clone::MAP_CLONE), + LintId::of(match_result_ok::MATCH_RESULT_OK), + LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), + LintId::of(matches::MATCH_OVERLAPPING_ARM), + LintId::of(matches::MATCH_REF_PATS), + LintId::of(matches::REDUNDANT_PATTERN_MATCHING), + LintId::of(matches::SINGLE_MATCH), + LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(methods::BYTES_NTH), + LintId::of(methods::CHARS_LAST_CMP), + LintId::of(methods::CHARS_NEXT_CMP), + LintId::of(methods::INTO_ITER_ON_REF), + LintId::of(methods::ITER_CLONED_COLLECT), + LintId::of(methods::ITER_NEXT_SLICE), + LintId::of(methods::ITER_NTH_ZERO), + LintId::of(methods::ITER_SKIP_NEXT), + LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::OK_EXPECT), + LintId::of(methods::OPTION_MAP_OR_NONE), + LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), + LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(methods::SINGLE_CHAR_ADD_STR), + LintId::of(methods::STRING_EXTEND_CHARS), + LintId::of(methods::UNNECESSARY_FOLD), + LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), + LintId::of(methods::WRONG_SELF_CONVENTION), + LintId::of(misc::TOPLEVEL_REF_ARG), + LintId::of(misc::ZERO_PTR), + LintId::of(misc_early::BUILTIN_TYPE_SHADOW), + LintId::of(misc_early::DOUBLE_NEG), + LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), + LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), + LintId::of(misc_early::REDUNDANT_PATTERN), + LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), + LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(needless_borrow::NEEDLESS_BORROW), + LintId::of(neg_multiply::NEG_MULTIPLY), + LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), + LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(ptr::CMP_NULL), + LintId::of(ptr::PTR_ARG), + LintId::of(ptr_eq::PTR_EQ), + LintId::of(question_mark::QUESTION_MARK), + LintId::of(ranges::MANUAL_RANGE_CONTAINS), + LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), + LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), + LintId::of(returns::LET_AND_RETURN), + LintId::of(returns::NEEDLESS_RETURN), + LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), + LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), + LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), + LintId::of(try_err::TRY_ERR), + LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(unused_unit::UNUSED_UNIT), + LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), + LintId::of(write::PRINTLN_EMPTY_STRING), + LintId::of(write::PRINT_LITERAL), + LintId::of(write::PRINT_WITH_NEWLINE), + LintId::of(write::WRITELN_EMPTY_STRING), + LintId::of(write::WRITE_LITERAL), + LintId::of(write::WRITE_WITH_NEWLINE), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,20 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![ + LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), + LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(loops::EMPTY_LOOP), + LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), + LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), +]) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/lib.rs 2021-11-29 19:27:12.000000000 +0000 @@ -31,7 +31,7 @@ extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_middle; -extern crate rustc_mir; +extern crate rustc_mir_dataflow; extern crate rustc_parse; extern crate rustc_parse_format; extern crate rustc_session; @@ -187,6 +187,7 @@ mod default; mod default_numeric_fallback; mod dereference; +mod derivable_impls; mod derive; mod disallowed_method; mod disallowed_script_idents; @@ -202,6 +203,7 @@ mod enum_clike; mod enum_variants; mod eq_op; +mod equatable_if_let; mod erasing_op; mod escape; mod eta_reduction; @@ -211,6 +213,7 @@ mod exit; mod explicit_write; mod fallible_impl_from; +mod feature_name; mod float_equality_without_abs; mod float_literal; mod floating_point_arithmetic; @@ -223,7 +226,6 @@ mod get_last_with_len; mod identity_op; mod if_let_mutex; -mod if_let_some_result; mod if_not_else; mod if_then_some_else_none; mod implicit_hasher; @@ -239,6 +241,7 @@ mod integer_division; mod invalid_upcast_comparisons; mod items_after_statements; +mod iter_not_returning_iterator; mod large_const_arrays; mod large_enum_variant; mod large_stack_arrays; @@ -250,6 +253,7 @@ mod loops; mod macro_use; mod main_recursion; +mod manual_assert; mod manual_async_fn; mod manual_map; mod manual_non_exhaustive; @@ -260,8 +264,8 @@ mod map_err_ignore; mod map_unit_fn; mod match_on_vec_items; +mod match_result_ok; mod matches; -mod mem_discriminant; mod mem_forget; mod mem_replace; mod methods; @@ -272,6 +276,7 @@ mod missing_doc; mod missing_enforced_import_rename; mod missing_inline; +mod module_style; mod modulo_arithmetic; mod multiple_crate_versions; mod mut_key; @@ -287,6 +292,7 @@ mod needless_borrowed_ref; mod needless_continue; mod needless_for_each; +mod needless_option_as_deref; mod needless_pass_by_value; mod needless_question_mark; mod needless_update; @@ -297,6 +303,7 @@ mod non_copy_const; mod non_expressive_names; mod non_octal_unix_permissions; +mod non_send_fields_in_send_ty; mod nonstandard_macro_braces; mod open_options; mod option_env_unwrap; @@ -326,6 +333,7 @@ mod regex; mod repeat_once; mod returns; +mod same_name_method; mod self_assignment; mod self_named_constructors; mod semicolon_if_nothing_returned; @@ -431,1380 +439,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { register_removed_non_tool_lints(store); - // begin deprecated lints, do not remove this comment, it’s used in `update_lints` - store.register_removed( - "clippy::should_assert_eq", - "`assert!()` will be more flexible with RFC 2011", - ); - store.register_removed( - "clippy::extend_from_slice", - "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice", - ); - store.register_removed( - "clippy::range_step_by_zero", - "`iterator.step_by(0)` panics nowadays", - ); - store.register_removed( - "clippy::unstable_as_slice", - "`Vec::as_slice` has been stabilized in 1.7", - ); - store.register_removed( - "clippy::unstable_as_mut_slice", - "`Vec::as_mut_slice` has been stabilized in 1.7", - ); - store.register_removed( - "clippy::misaligned_transmute", - "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", - ); - store.register_removed( - "clippy::assign_ops", - "using compound assignment operators (e.g., `+=`) is harmless", - ); - store.register_removed( - "clippy::if_let_redundant_pattern_matching", - "this lint has been changed to redundant_pattern_matching", - ); - store.register_removed( - "clippy::unsafe_vector_initialization", - "the replacement suggested by this lint had substantially different behavior", - ); - store.register_removed( - "clippy::unused_collect", - "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint", - ); - store.register_removed( - "clippy::replace_consts", - "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants", - ); - store.register_removed( - "clippy::regex_macro", - "the regex! macro has been removed from the regex crate in 2018", - ); - store.register_removed( - "clippy::find_map", - "this lint has been replaced by `manual_find_map`, a more specific lint", - ); - store.register_removed( - "clippy::filter_map", - "this lint has been replaced by `manual_filter_map`, a more specific lint", - ); - store.register_removed( - "clippy::pub_enum_variant_names", - "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items", - ); - store.register_removed( - "clippy::wrong_pub_self_convention", - "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items", - ); - // end deprecated lints, do not remove this comment, it’s used in `update_lints` + include!("lib.deprecated.rs"); - // begin register lints, do not remove this comment, it’s used in `update_lints` - store.register_lints(&[ - #[cfg(feature = "internal-lints")] - utils::internal_lints::CLIPPY_LINTS_INTERNAL, - #[cfg(feature = "internal-lints")] - utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, - #[cfg(feature = "internal-lints")] - utils::internal_lints::COMPILER_LINT_FUNCTIONS, - #[cfg(feature = "internal-lints")] - utils::internal_lints::DEFAULT_LINT, - #[cfg(feature = "internal-lints")] - utils::internal_lints::IF_CHAIN_STYLE, - #[cfg(feature = "internal-lints")] - utils::internal_lints::INTERNING_DEFINED_SYMBOL, - #[cfg(feature = "internal-lints")] - utils::internal_lints::INVALID_PATHS, - #[cfg(feature = "internal-lints")] - utils::internal_lints::LINT_WITHOUT_LINT_PASS, - #[cfg(feature = "internal-lints")] - utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, - #[cfg(feature = "internal-lints")] - utils::internal_lints::OUTER_EXPN_EXPN_DATA, - #[cfg(feature = "internal-lints")] - utils::internal_lints::PRODUCE_ICE, - #[cfg(feature = "internal-lints")] - utils::internal_lints::UNNECESSARY_SYMBOL_STR, - absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, - approx_const::APPROX_CONSTANT, - arithmetic::FLOAT_ARITHMETIC, - arithmetic::INTEGER_ARITHMETIC, - as_conversions::AS_CONVERSIONS, - asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, - asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, - assertions_on_constants::ASSERTIONS_ON_CONSTANTS, - assign_ops::ASSIGN_OP_PATTERN, - assign_ops::MISREFACTORED_ASSIGN_OP, - async_yields_async::ASYNC_YIELDS_ASYNC, - attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, - attrs::DEPRECATED_CFG_ATTR, - attrs::DEPRECATED_SEMVER, - attrs::EMPTY_LINE_AFTER_OUTER_ATTR, - attrs::INLINE_ALWAYS, - attrs::MISMATCHED_TARGET_OS, - attrs::USELESS_ATTRIBUTE, - await_holding_invalid::AWAIT_HOLDING_LOCK, - await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, - bit_mask::BAD_BIT_MASK, - bit_mask::INEFFECTIVE_BIT_MASK, - bit_mask::VERBOSE_BIT_MASK, - blacklisted_name::BLACKLISTED_NAME, - blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, - bool_assert_comparison::BOOL_ASSERT_COMPARISON, - booleans::LOGIC_BUG, - booleans::NONMINIMAL_BOOL, - bytecount::NAIVE_BYTECOUNT, - cargo_common_metadata::CARGO_COMMON_METADATA, - case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - casts::CAST_LOSSLESS, - casts::CAST_POSSIBLE_TRUNCATION, - casts::CAST_POSSIBLE_WRAP, - casts::CAST_PRECISION_LOSS, - casts::CAST_PTR_ALIGNMENT, - casts::CAST_REF_TO_MUT, - casts::CAST_SIGN_LOSS, - casts::CHAR_LIT_AS_U8, - casts::FN_TO_NUMERIC_CAST, - casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, - casts::PTR_AS_PTR, - casts::UNNECESSARY_CAST, - checked_conversions::CHECKED_CONVERSIONS, - cognitive_complexity::COGNITIVE_COMPLEXITY, - collapsible_if::COLLAPSIBLE_ELSE_IF, - collapsible_if::COLLAPSIBLE_IF, - collapsible_match::COLLAPSIBLE_MATCH, - comparison_chain::COMPARISON_CHAIN, - copies::BRANCHES_SHARING_CODE, - copies::IFS_SAME_COND, - copies::IF_SAME_THEN_ELSE, - copies::SAME_FUNCTIONS_IN_IF_CONDITION, - copy_iterator::COPY_ITERATOR, - create_dir::CREATE_DIR, - dbg_macro::DBG_MACRO, - default::DEFAULT_TRAIT_ACCESS, - default::FIELD_REASSIGN_WITH_DEFAULT, - default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK, - dereference::EXPLICIT_DEREF_METHODS, - derive::DERIVE_HASH_XOR_EQ, - derive::DERIVE_ORD_XOR_PARTIAL_ORD, - derive::EXPL_IMPL_CLONE_ON_COPY, - derive::UNSAFE_DERIVE_DESERIALIZE, - disallowed_method::DISALLOWED_METHOD, - disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS, - disallowed_type::DISALLOWED_TYPE, - doc::DOC_MARKDOWN, - doc::MISSING_ERRORS_DOC, - doc::MISSING_PANICS_DOC, - doc::MISSING_SAFETY_DOC, - doc::NEEDLESS_DOCTEST_MAIN, - double_comparison::DOUBLE_COMPARISONS, - double_parens::DOUBLE_PARENS, - drop_forget_ref::DROP_COPY, - drop_forget_ref::DROP_REF, - drop_forget_ref::FORGET_COPY, - drop_forget_ref::FORGET_REF, - duration_subsec::DURATION_SUBSEC, - else_if_without_else::ELSE_IF_WITHOUT_ELSE, - empty_enum::EMPTY_ENUM, - entry::MAP_ENTRY, - enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, - enum_variants::ENUM_VARIANT_NAMES, - enum_variants::MODULE_INCEPTION, - enum_variants::MODULE_NAME_REPETITIONS, - eq_op::EQ_OP, - eq_op::OP_REF, - erasing_op::ERASING_OP, - escape::BOXED_LOCAL, - eta_reduction::REDUNDANT_CLOSURE, - eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, - eval_order_dependence::DIVERGING_SUB_EXPRESSION, - eval_order_dependence::EVAL_ORDER_DEPENDENCE, - excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, - excessive_bools::STRUCT_EXCESSIVE_BOOLS, - exhaustive_items::EXHAUSTIVE_ENUMS, - exhaustive_items::EXHAUSTIVE_STRUCTS, - exit::EXIT, - explicit_write::EXPLICIT_WRITE, - fallible_impl_from::FALLIBLE_IMPL_FROM, - float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, - float_literal::EXCESSIVE_PRECISION, - float_literal::LOSSY_FLOAT_LITERAL, - floating_point_arithmetic::IMPRECISE_FLOPS, - floating_point_arithmetic::SUBOPTIMAL_FLOPS, - format::USELESS_FORMAT, - formatting::POSSIBLE_MISSING_COMMA, - formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, - formatting::SUSPICIOUS_ELSE_FORMATTING, - formatting::SUSPICIOUS_UNARY_OP_FORMATTING, - from_over_into::FROM_OVER_INTO, - from_str_radix_10::FROM_STR_RADIX_10, - functions::DOUBLE_MUST_USE, - functions::MUST_USE_CANDIDATE, - functions::MUST_USE_UNIT, - functions::NOT_UNSAFE_PTR_ARG_DEREF, - functions::RESULT_UNIT_ERR, - functions::TOO_MANY_ARGUMENTS, - functions::TOO_MANY_LINES, - future_not_send::FUTURE_NOT_SEND, - get_last_with_len::GET_LAST_WITH_LEN, - identity_op::IDENTITY_OP, - if_let_mutex::IF_LET_MUTEX, - if_let_some_result::IF_LET_SOME_RESULT, - if_not_else::IF_NOT_ELSE, - if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, - implicit_hasher::IMPLICIT_HASHER, - implicit_return::IMPLICIT_RETURN, - implicit_saturating_sub::IMPLICIT_SATURATING_SUB, - inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR, - indexing_slicing::INDEXING_SLICING, - indexing_slicing::OUT_OF_BOUNDS_INDEXING, - infinite_iter::INFINITE_ITER, - infinite_iter::MAYBE_INFINITE_ITER, - inherent_impl::MULTIPLE_INHERENT_IMPL, - inherent_to_string::INHERENT_TO_STRING, - inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, - inline_fn_without_body::INLINE_FN_WITHOUT_BODY, - int_plus_one::INT_PLUS_ONE, - integer_division::INTEGER_DIVISION, - invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS, - items_after_statements::ITEMS_AFTER_STATEMENTS, - large_const_arrays::LARGE_CONST_ARRAYS, - large_enum_variant::LARGE_ENUM_VARIANT, - large_stack_arrays::LARGE_STACK_ARRAYS, - len_zero::COMPARISON_TO_EMPTY, - len_zero::LEN_WITHOUT_IS_EMPTY, - len_zero::LEN_ZERO, - let_if_seq::USELESS_LET_IF_SEQ, - let_underscore::LET_UNDERSCORE_DROP, - let_underscore::LET_UNDERSCORE_LOCK, - let_underscore::LET_UNDERSCORE_MUST_USE, - lifetimes::EXTRA_UNUSED_LIFETIMES, - lifetimes::NEEDLESS_LIFETIMES, - literal_representation::DECIMAL_LITERAL_REPRESENTATION, - literal_representation::INCONSISTENT_DIGIT_GROUPING, - literal_representation::LARGE_DIGIT_GROUPS, - literal_representation::MISTYPED_LITERAL_SUFFIXES, - literal_representation::UNREADABLE_LITERAL, - literal_representation::UNUSUAL_BYTE_GROUPINGS, - loops::EMPTY_LOOP, - loops::EXPLICIT_COUNTER_LOOP, - loops::EXPLICIT_INTO_ITER_LOOP, - loops::EXPLICIT_ITER_LOOP, - loops::FOR_KV_MAP, - loops::FOR_LOOPS_OVER_FALLIBLES, - loops::ITER_NEXT_LOOP, - loops::MANUAL_FLATTEN, - loops::MANUAL_MEMCPY, - loops::MUT_RANGE_BOUND, - loops::NEEDLESS_COLLECT, - loops::NEEDLESS_RANGE_LOOP, - loops::NEVER_LOOP, - loops::SAME_ITEM_PUSH, - loops::SINGLE_ELEMENT_LOOP, - loops::WHILE_IMMUTABLE_CONDITION, - loops::WHILE_LET_LOOP, - loops::WHILE_LET_ON_ITERATOR, - macro_use::MACRO_USE_IMPORTS, - main_recursion::MAIN_RECURSION, - manual_async_fn::MANUAL_ASYNC_FN, - manual_map::MANUAL_MAP, - manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, - manual_ok_or::MANUAL_OK_OR, - manual_strip::MANUAL_STRIP, - manual_unwrap_or::MANUAL_UNWRAP_OR, - map_clone::MAP_CLONE, - map_err_ignore::MAP_ERR_IGNORE, - map_unit_fn::OPTION_MAP_UNIT_FN, - map_unit_fn::RESULT_MAP_UNIT_FN, - match_on_vec_items::MATCH_ON_VEC_ITEMS, - matches::INFALLIBLE_DESTRUCTURING_MATCH, - matches::MATCH_AS_REF, - matches::MATCH_BOOL, - matches::MATCH_LIKE_MATCHES_MACRO, - matches::MATCH_OVERLAPPING_ARM, - matches::MATCH_REF_PATS, - matches::MATCH_SAME_ARMS, - matches::MATCH_SINGLE_BINDING, - matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, - matches::MATCH_WILD_ERR_ARM, - matches::REDUNDANT_PATTERN_MATCHING, - matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, - matches::SINGLE_MATCH, - matches::SINGLE_MATCH_ELSE, - matches::WILDCARD_ENUM_MATCH_ARM, - matches::WILDCARD_IN_OR_PATTERNS, - mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, - mem_forget::MEM_FORGET, - mem_replace::MEM_REPLACE_OPTION_WITH_NONE, - mem_replace::MEM_REPLACE_WITH_DEFAULT, - mem_replace::MEM_REPLACE_WITH_UNINIT, - methods::BIND_INSTEAD_OF_MAP, - methods::BYTES_NTH, - methods::CHARS_LAST_CMP, - methods::CHARS_NEXT_CMP, - methods::CLONED_INSTEAD_OF_COPIED, - methods::CLONE_DOUBLE_REF, - methods::CLONE_ON_COPY, - methods::CLONE_ON_REF_PTR, - methods::EXPECT_FUN_CALL, - methods::EXPECT_USED, - methods::EXTEND_WITH_DRAIN, - methods::FILETYPE_IS_FILE, - methods::FILTER_MAP_IDENTITY, - methods::FILTER_MAP_NEXT, - methods::FILTER_NEXT, - methods::FLAT_MAP_IDENTITY, - methods::FLAT_MAP_OPTION, - methods::FROM_ITER_INSTEAD_OF_COLLECT, - methods::GET_UNWRAP, - methods::IMPLICIT_CLONE, - methods::INEFFICIENT_TO_STRING, - methods::INSPECT_FOR_EACH, - methods::INTO_ITER_ON_REF, - methods::ITERATOR_STEP_BY_ZERO, - methods::ITER_CLONED_COLLECT, - methods::ITER_COUNT, - methods::ITER_NEXT_SLICE, - methods::ITER_NTH, - methods::ITER_NTH_ZERO, - methods::ITER_SKIP_NEXT, - methods::MANUAL_FILTER_MAP, - methods::MANUAL_FIND_MAP, - methods::MANUAL_SATURATING_ARITHMETIC, - methods::MANUAL_STR_REPEAT, - methods::MAP_COLLECT_RESULT_UNIT, - methods::MAP_FLATTEN, - methods::MAP_IDENTITY, - methods::MAP_UNWRAP_OR, - methods::NEW_RET_NO_SELF, - methods::OK_EXPECT, - methods::OPTION_AS_REF_DEREF, - methods::OPTION_FILTER_MAP, - methods::OPTION_MAP_OR_NONE, - methods::OR_FUN_CALL, - methods::RESULT_MAP_OR_INTO_OPTION, - methods::SEARCH_IS_SOME, - methods::SHOULD_IMPLEMENT_TRAIT, - methods::SINGLE_CHAR_ADD_STR, - methods::SINGLE_CHAR_PATTERN, - methods::SKIP_WHILE_NEXT, - methods::STRING_EXTEND_CHARS, - methods::SUSPICIOUS_MAP, - methods::SUSPICIOUS_SPLITN, - methods::UNINIT_ASSUMED_INIT, - methods::UNNECESSARY_FILTER_MAP, - methods::UNNECESSARY_FOLD, - methods::UNNECESSARY_LAZY_EVALUATIONS, - methods::UNWRAP_OR_ELSE_DEFAULT, - methods::UNWRAP_USED, - methods::USELESS_ASREF, - methods::WRONG_SELF_CONVENTION, - methods::ZST_OFFSET, - minmax::MIN_MAX, - misc::CMP_NAN, - misc::CMP_OWNED, - misc::FLOAT_CMP, - misc::FLOAT_CMP_CONST, - misc::MODULO_ONE, - misc::SHORT_CIRCUIT_STATEMENT, - misc::TOPLEVEL_REF_ARG, - misc::USED_UNDERSCORE_BINDING, - misc::ZERO_PTR, - misc_early::BUILTIN_TYPE_SHADOW, - misc_early::DOUBLE_NEG, - misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, - misc_early::MIXED_CASE_HEX_LITERALS, - misc_early::REDUNDANT_PATTERN, - misc_early::UNNEEDED_FIELD_PATTERN, - misc_early::UNNEEDED_WILDCARD_PATTERN, - misc_early::UNSEPARATED_LITERAL_SUFFIX, - misc_early::ZERO_PREFIXED_LITERAL, - missing_const_for_fn::MISSING_CONST_FOR_FN, - missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, - missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES, - missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, - modulo_arithmetic::MODULO_ARITHMETIC, - multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, - mut_key::MUTABLE_KEY_TYPE, - mut_mut::MUT_MUT, - mut_mutex_lock::MUT_MUTEX_LOCK, - mut_reference::UNNECESSARY_MUT_PASSED, - mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, - mutex_atomic::MUTEX_ATOMIC, - mutex_atomic::MUTEX_INTEGER, - needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, - needless_bitwise_bool::NEEDLESS_BITWISE_BOOL, - needless_bool::BOOL_COMPARISON, - needless_bool::NEEDLESS_BOOL, - needless_borrow::NEEDLESS_BORROW, - needless_borrow::REF_BINDING_TO_REFERENCE, - needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, - needless_continue::NEEDLESS_CONTINUE, - needless_for_each::NEEDLESS_FOR_EACH, - needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, - needless_question_mark::NEEDLESS_QUESTION_MARK, - needless_update::NEEDLESS_UPDATE, - neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, - neg_multiply::NEG_MULTIPLY, - new_without_default::NEW_WITHOUT_DEFAULT, - no_effect::NO_EFFECT, - no_effect::UNNECESSARY_OPERATION, - non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, - non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, - non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, - non_expressive_names::MANY_SINGLE_CHAR_NAMES, - non_expressive_names::SIMILAR_NAMES, - non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS, - nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, - open_options::NONSENSICAL_OPEN_OPTIONS, - option_env_unwrap::OPTION_ENV_UNWRAP, - option_if_let_else::OPTION_IF_LET_ELSE, - overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, - panic_in_result_fn::PANIC_IN_RESULT_FN, - panic_unimplemented::PANIC, - panic_unimplemented::TODO, - panic_unimplemented::UNIMPLEMENTED, - panic_unimplemented::UNREACHABLE, - partialeq_ne_impl::PARTIALEQ_NE_IMPL, - pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, - pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, - path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, - pattern_type_mismatch::PATTERN_TYPE_MISMATCH, - precedence::PRECEDENCE, - ptr::CMP_NULL, - ptr::INVALID_NULL_PTR_USAGE, - ptr::MUT_FROM_REF, - ptr::PTR_ARG, - ptr_eq::PTR_EQ, - ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, - question_mark::QUESTION_MARK, - ranges::MANUAL_RANGE_CONTAINS, - ranges::RANGE_MINUS_ONE, - ranges::RANGE_PLUS_ONE, - ranges::RANGE_ZIP_WITH_LEN, - ranges::REVERSED_EMPTY_RANGES, - redundant_clone::REDUNDANT_CLONE, - redundant_closure_call::REDUNDANT_CLOSURE_CALL, - redundant_else::REDUNDANT_ELSE, - redundant_field_names::REDUNDANT_FIELD_NAMES, - redundant_pub_crate::REDUNDANT_PUB_CRATE, - redundant_slicing::REDUNDANT_SLICING, - redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, - ref_option_ref::REF_OPTION_REF, - reference::DEREF_ADDROF, - reference::REF_IN_DEREF, - regex::INVALID_REGEX, - regex::TRIVIAL_REGEX, - repeat_once::REPEAT_ONCE, - returns::LET_AND_RETURN, - returns::NEEDLESS_RETURN, - self_assignment::SELF_ASSIGNMENT, - self_named_constructors::SELF_NAMED_CONSTRUCTORS, - semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, - serde_api::SERDE_API_MISUSE, - shadow::SHADOW_REUSE, - shadow::SHADOW_SAME, - shadow::SHADOW_UNRELATED, - single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, - size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, - slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - stable_sort_primitive::STABLE_SORT_PRIMITIVE, - strings::STRING_ADD, - strings::STRING_ADD_ASSIGN, - strings::STRING_FROM_UTF8_AS_BYTES, - strings::STRING_LIT_AS_BYTES, - strings::STRING_TO_STRING, - strings::STR_TO_STRING, - strlen_on_c_strings::STRLEN_ON_C_STRINGS, - suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS, - suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, - suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, - swap::ALMOST_SWAPPED, - swap::MANUAL_SWAP, - tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, - temporary_assignment::TEMPORARY_ASSIGNMENT, - to_digit_is_some::TO_DIGIT_IS_SOME, - to_string_in_display::TO_STRING_IN_DISPLAY, - trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, - trait_bounds::TYPE_REPETITION_IN_BOUNDS, - transmute::CROSSPOINTER_TRANSMUTE, - transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, - transmute::TRANSMUTE_BYTES_TO_STR, - transmute::TRANSMUTE_FLOAT_TO_INT, - transmute::TRANSMUTE_INT_TO_BOOL, - transmute::TRANSMUTE_INT_TO_CHAR, - transmute::TRANSMUTE_INT_TO_FLOAT, - transmute::TRANSMUTE_PTR_TO_PTR, - transmute::TRANSMUTE_PTR_TO_REF, - transmute::UNSOUND_COLLECTION_TRANSMUTE, - transmute::USELESS_TRANSMUTE, - transmute::WRONG_TRANSMUTE, - transmuting_null::TRANSMUTING_NULL, - try_err::TRY_ERR, - types::BORROWED_BOX, - types::BOX_VEC, - types::LINKEDLIST, - types::OPTION_OPTION, - types::RC_BUFFER, - types::RC_MUTEX, - types::REDUNDANT_ALLOCATION, - types::TYPE_COMPLEXITY, - types::VEC_BOX, - undropped_manually_drops::UNDROPPED_MANUALLY_DROPS, - unicode::INVISIBLE_CHARACTERS, - unicode::NON_ASCII_LITERAL, - unicode::UNICODE_NOT_NFC, - unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, - unit_types::LET_UNIT_VALUE, - unit_types::UNIT_ARG, - unit_types::UNIT_CMP, - unnamed_address::FN_ADDRESS_COMPARISONS, - unnamed_address::VTABLE_ADDRESS_COMPARISONS, - unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS, - unnecessary_sort_by::UNNECESSARY_SORT_BY, - unnecessary_wraps::UNNECESSARY_WRAPS, - unnested_or_patterns::UNNESTED_OR_PATTERNS, - unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - unused_async::UNUSED_ASYNC, - unused_io_amount::UNUSED_IO_AMOUNT, - unused_self::UNUSED_SELF, - unused_unit::UNUSED_UNIT, - unwrap::PANICKING_UNWRAP, - unwrap::UNNECESSARY_UNWRAP, - unwrap_in_result::UNWRAP_IN_RESULT, - upper_case_acronyms::UPPER_CASE_ACRONYMS, - use_self::USE_SELF, - useless_conversion::USELESS_CONVERSION, - vec::USELESS_VEC, - vec_init_then_push::VEC_INIT_THEN_PUSH, - vec_resize_to_zero::VEC_RESIZE_TO_ZERO, - verbose_file_reads::VERBOSE_FILE_READS, - wildcard_dependencies::WILDCARD_DEPENDENCIES, - wildcard_imports::ENUM_GLOB_USE, - wildcard_imports::WILDCARD_IMPORTS, - write::PRINTLN_EMPTY_STRING, - write::PRINT_LITERAL, - write::PRINT_STDERR, - write::PRINT_STDOUT, - write::PRINT_WITH_NEWLINE, - write::USE_DEBUG, - write::WRITELN_EMPTY_STRING, - write::WRITE_LITERAL, - write::WRITE_WITH_NEWLINE, - zero_div_zero::ZERO_DIVIDED_BY_ZERO, - zero_sized_map_values::ZERO_SIZED_MAP_VALUES, - ]); - // end register lints, do not remove this comment, it’s used in `update_lints` - - store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ - LintId::of(arithmetic::FLOAT_ARITHMETIC), - LintId::of(arithmetic::INTEGER_ARITHMETIC), - LintId::of(as_conversions::AS_CONVERSIONS), - LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), - LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), - LintId::of(create_dir::CREATE_DIR), - LintId::of(dbg_macro::DBG_MACRO), - LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK), - LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS), - LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE), - LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS), - LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS), - LintId::of(exit::EXIT), - LintId::of(float_literal::LOSSY_FLOAT_LITERAL), - LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE), - LintId::of(implicit_return::IMPLICIT_RETURN), - LintId::of(indexing_slicing::INDEXING_SLICING), - LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL), - LintId::of(integer_division::INTEGER_DIVISION), - LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), - LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), - LintId::of(map_err_ignore::MAP_ERR_IGNORE), - LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), - LintId::of(matches::WILDCARD_ENUM_MATCH_ARM), - LintId::of(mem_forget::MEM_FORGET), - LintId::of(methods::CLONE_ON_REF_PTR), - LintId::of(methods::EXPECT_USED), - LintId::of(methods::FILETYPE_IS_FILE), - LintId::of(methods::GET_UNWRAP), - LintId::of(methods::UNWRAP_USED), - LintId::of(misc::FLOAT_CMP_CONST), - LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), - LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), - LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES), - LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), - LintId::of(modulo_arithmetic::MODULO_ARITHMETIC), - LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN), - LintId::of(panic_unimplemented::PANIC), - LintId::of(panic_unimplemented::TODO), - LintId::of(panic_unimplemented::UNIMPLEMENTED), - LintId::of(panic_unimplemented::UNREACHABLE), - LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH), - LintId::of(shadow::SHADOW_REUSE), - LintId::of(shadow::SHADOW_SAME), - LintId::of(strings::STRING_ADD), - LintId::of(strings::STRING_TO_STRING), - LintId::of(strings::STR_TO_STRING), - LintId::of(types::RC_BUFFER), - LintId::of(types::RC_MUTEX), - LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), - LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), - LintId::of(verbose_file_reads::VERBOSE_FILE_READS), - LintId::of(write::PRINT_STDERR), - LintId::of(write::PRINT_STDOUT), - LintId::of(write::USE_DEBUG), - ]); - - store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ - LintId::of(attrs::INLINE_ALWAYS), - LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), - LintId::of(bit_mask::VERBOSE_BIT_MASK), - LintId::of(bytecount::NAIVE_BYTECOUNT), - LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), - LintId::of(casts::CAST_LOSSLESS), - LintId::of(casts::CAST_POSSIBLE_TRUNCATION), - LintId::of(casts::CAST_POSSIBLE_WRAP), - LintId::of(casts::CAST_PRECISION_LOSS), - LintId::of(casts::CAST_PTR_ALIGNMENT), - LintId::of(casts::CAST_SIGN_LOSS), - LintId::of(casts::PTR_AS_PTR), - LintId::of(checked_conversions::CHECKED_CONVERSIONS), - LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION), - LintId::of(copy_iterator::COPY_ITERATOR), - LintId::of(default::DEFAULT_TRAIT_ACCESS), - LintId::of(dereference::EXPLICIT_DEREF_METHODS), - LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY), - LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE), - LintId::of(doc::DOC_MARKDOWN), - LintId::of(doc::MISSING_ERRORS_DOC), - LintId::of(doc::MISSING_PANICS_DOC), - LintId::of(empty_enum::EMPTY_ENUM), - LintId::of(enum_variants::MODULE_NAME_REPETITIONS), - LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), - LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), - LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS), - LintId::of(functions::MUST_USE_CANDIDATE), - LintId::of(functions::TOO_MANY_LINES), - LintId::of(if_not_else::IF_NOT_ELSE), - LintId::of(implicit_hasher::IMPLICIT_HASHER), - LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB), - LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), - LintId::of(infinite_iter::MAYBE_INFINITE_ITER), - LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), - LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), - LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), - LintId::of(let_underscore::LET_UNDERSCORE_DROP), - LintId::of(literal_representation::LARGE_DIGIT_GROUPS), - LintId::of(literal_representation::UNREADABLE_LITERAL), - LintId::of(loops::EXPLICIT_INTO_ITER_LOOP), - LintId::of(loops::EXPLICIT_ITER_LOOP), - LintId::of(macro_use::MACRO_USE_IMPORTS), - LintId::of(manual_ok_or::MANUAL_OK_OR), - LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS), - LintId::of(matches::MATCH_BOOL), - LintId::of(matches::MATCH_SAME_ARMS), - LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), - LintId::of(matches::MATCH_WILD_ERR_ARM), - LintId::of(matches::SINGLE_MATCH_ELSE), - LintId::of(methods::CLONED_INSTEAD_OF_COPIED), - LintId::of(methods::FILTER_MAP_NEXT), - LintId::of(methods::FLAT_MAP_OPTION), - LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), - LintId::of(methods::IMPLICIT_CLONE), - LintId::of(methods::INEFFICIENT_TO_STRING), - LintId::of(methods::MAP_FLATTEN), - LintId::of(methods::MAP_UNWRAP_OR), - LintId::of(misc::USED_UNDERSCORE_BINDING), - LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), - LintId::of(mut_mut::MUT_MUT), - LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL), - LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE), - LintId::of(needless_continue::NEEDLESS_CONTINUE), - LintId::of(needless_for_each::NEEDLESS_FOR_EACH), - LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), - LintId::of(non_expressive_names::SIMILAR_NAMES), - LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), - LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE), - LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), - LintId::of(ranges::RANGE_MINUS_ONE), - LintId::of(ranges::RANGE_PLUS_ONE), - LintId::of(redundant_else::REDUNDANT_ELSE), - LintId::of(ref_option_ref::REF_OPTION_REF), - LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), - LintId::of(shadow::SHADOW_UNRELATED), - LintId::of(strings::STRING_ADD_ASSIGN), - LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), - LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS), - LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), - LintId::of(types::LINKEDLIST), - LintId::of(types::OPTION_OPTION), - LintId::of(unicode::NON_ASCII_LITERAL), - LintId::of(unicode::UNICODE_NOT_NFC), - LintId::of(unit_types::LET_UNIT_VALUE), - LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS), - LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS), - LintId::of(unused_async::UNUSED_ASYNC), - LintId::of(unused_self::UNUSED_SELF), - LintId::of(wildcard_imports::ENUM_GLOB_USE), - LintId::of(wildcard_imports::WILDCARD_IMPORTS), - LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES), - ]); + include!("lib.register_lints.rs"); + include!("lib.register_restriction.rs"); + include!("lib.register_pedantic.rs"); #[cfg(feature = "internal-lints")] - store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ - LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL), - LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), - LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS), - LintId::of(utils::internal_lints::DEFAULT_LINT), - LintId::of(utils::internal_lints::IF_CHAIN_STYLE), - LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL), - LintId::of(utils::internal_lints::INVALID_PATHS), - LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS), - LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), - LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA), - LintId::of(utils::internal_lints::PRODUCE_ICE), - LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR), - ]); - - store.register_group(true, "clippy::all", Some("clippy"), vec![ - LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), - LintId::of(approx_const::APPROX_CONSTANT), - LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assign_ops::ASSIGN_OP_PATTERN), - LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), - LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), - LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), - LintId::of(attrs::DEPRECATED_CFG_ATTR), - LintId::of(attrs::DEPRECATED_SEMVER), - LintId::of(attrs::MISMATCHED_TARGET_OS), - LintId::of(attrs::USELESS_ATTRIBUTE), - LintId::of(bit_mask::BAD_BIT_MASK), - LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), - LintId::of(blacklisted_name::BLACKLISTED_NAME), - LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), - LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), - LintId::of(booleans::LOGIC_BUG), - LintId::of(booleans::NONMINIMAL_BOOL), - LintId::of(casts::CAST_REF_TO_MUT), - LintId::of(casts::CHAR_LIT_AS_U8), - LintId::of(casts::FN_TO_NUMERIC_CAST), - LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(casts::UNNECESSARY_CAST), - LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), - LintId::of(collapsible_if::COLLAPSIBLE_IF), - LintId::of(collapsible_match::COLLAPSIBLE_MATCH), - LintId::of(comparison_chain::COMPARISON_CHAIN), - LintId::of(copies::BRANCHES_SHARING_CODE), - LintId::of(copies::IFS_SAME_COND), - LintId::of(copies::IF_SAME_THEN_ELSE), - LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), - LintId::of(derive::DERIVE_HASH_XOR_EQ), - LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), - LintId::of(doc::MISSING_SAFETY_DOC), - LintId::of(doc::NEEDLESS_DOCTEST_MAIN), - LintId::of(double_comparison::DOUBLE_COMPARISONS), - LintId::of(double_parens::DOUBLE_PARENS), - LintId::of(drop_forget_ref::DROP_COPY), - LintId::of(drop_forget_ref::DROP_REF), - LintId::of(drop_forget_ref::FORGET_COPY), - LintId::of(drop_forget_ref::FORGET_REF), - LintId::of(duration_subsec::DURATION_SUBSEC), - LintId::of(entry::MAP_ENTRY), - LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), - LintId::of(enum_variants::ENUM_VARIANT_NAMES), - LintId::of(enum_variants::MODULE_INCEPTION), - LintId::of(eq_op::EQ_OP), - LintId::of(eq_op::OP_REF), - LintId::of(erasing_op::ERASING_OP), - LintId::of(escape::BOXED_LOCAL), - LintId::of(eta_reduction::REDUNDANT_CLOSURE), - LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), - LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), - LintId::of(explicit_write::EXPLICIT_WRITE), - LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), - LintId::of(float_literal::EXCESSIVE_PRECISION), - LintId::of(format::USELESS_FORMAT), - LintId::of(formatting::POSSIBLE_MISSING_COMMA), - LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), - LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), - LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), - LintId::of(from_over_into::FROM_OVER_INTO), - LintId::of(from_str_radix_10::FROM_STR_RADIX_10), - LintId::of(functions::DOUBLE_MUST_USE), - LintId::of(functions::MUST_USE_UNIT), - LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), - LintId::of(functions::RESULT_UNIT_ERR), - LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_last_with_len::GET_LAST_WITH_LEN), - LintId::of(identity_op::IDENTITY_OP), - LintId::of(if_let_mutex::IF_LET_MUTEX), - LintId::of(if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), - LintId::of(infinite_iter::INFINITE_ITER), - LintId::of(inherent_to_string::INHERENT_TO_STRING), - LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), - LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), - LintId::of(int_plus_one::INT_PLUS_ONE), - LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), - LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), - LintId::of(len_zero::COMPARISON_TO_EMPTY), - LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), - LintId::of(len_zero::LEN_ZERO), - LintId::of(let_underscore::LET_UNDERSCORE_LOCK), - LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), - LintId::of(lifetimes::NEEDLESS_LIFETIMES), - LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), - LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), - LintId::of(loops::EMPTY_LOOP), - LintId::of(loops::EXPLICIT_COUNTER_LOOP), - LintId::of(loops::FOR_KV_MAP), - LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), - LintId::of(loops::ITER_NEXT_LOOP), - LintId::of(loops::MANUAL_FLATTEN), - LintId::of(loops::MANUAL_MEMCPY), - LintId::of(loops::MUT_RANGE_BOUND), - LintId::of(loops::NEEDLESS_COLLECT), - LintId::of(loops::NEEDLESS_RANGE_LOOP), - LintId::of(loops::NEVER_LOOP), - LintId::of(loops::SAME_ITEM_PUSH), - LintId::of(loops::SINGLE_ELEMENT_LOOP), - LintId::of(loops::WHILE_IMMUTABLE_CONDITION), - LintId::of(loops::WHILE_LET_LOOP), - LintId::of(loops::WHILE_LET_ON_ITERATOR), - LintId::of(main_recursion::MAIN_RECURSION), - LintId::of(manual_async_fn::MANUAL_ASYNC_FN), - LintId::of(manual_map::MANUAL_MAP), - LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(manual_strip::MANUAL_STRIP), - LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), - LintId::of(map_clone::MAP_CLONE), - LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), - LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), - LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), - LintId::of(matches::MATCH_AS_REF), - LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), - LintId::of(matches::MATCH_OVERLAPPING_ARM), - LintId::of(matches::MATCH_REF_PATS), - LintId::of(matches::MATCH_SINGLE_BINDING), - LintId::of(matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(matches::SINGLE_MATCH), - LintId::of(matches::WILDCARD_IN_OR_PATTERNS), - LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), - LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), - LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), - LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), - LintId::of(methods::BIND_INSTEAD_OF_MAP), - LintId::of(methods::BYTES_NTH), - LintId::of(methods::CHARS_LAST_CMP), - LintId::of(methods::CHARS_NEXT_CMP), - LintId::of(methods::CLONE_DOUBLE_REF), - LintId::of(methods::CLONE_ON_COPY), - LintId::of(methods::EXPECT_FUN_CALL), - LintId::of(methods::EXTEND_WITH_DRAIN), - LintId::of(methods::FILTER_MAP_IDENTITY), - LintId::of(methods::FILTER_NEXT), - LintId::of(methods::FLAT_MAP_IDENTITY), - LintId::of(methods::INSPECT_FOR_EACH), - LintId::of(methods::INTO_ITER_ON_REF), - LintId::of(methods::ITERATOR_STEP_BY_ZERO), - LintId::of(methods::ITER_CLONED_COLLECT), - LintId::of(methods::ITER_COUNT), - LintId::of(methods::ITER_NEXT_SLICE), - LintId::of(methods::ITER_NTH), - LintId::of(methods::ITER_NTH_ZERO), - LintId::of(methods::ITER_SKIP_NEXT), - LintId::of(methods::MANUAL_FILTER_MAP), - LintId::of(methods::MANUAL_FIND_MAP), - LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), - LintId::of(methods::MANUAL_STR_REPEAT), - LintId::of(methods::MAP_COLLECT_RESULT_UNIT), - LintId::of(methods::MAP_IDENTITY), - LintId::of(methods::NEW_RET_NO_SELF), - LintId::of(methods::OK_EXPECT), - LintId::of(methods::OPTION_AS_REF_DEREF), - LintId::of(methods::OPTION_FILTER_MAP), - LintId::of(methods::OPTION_MAP_OR_NONE), - LintId::of(methods::OR_FUN_CALL), - LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), - LintId::of(methods::SEARCH_IS_SOME), - LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), - LintId::of(methods::SINGLE_CHAR_ADD_STR), - LintId::of(methods::SINGLE_CHAR_PATTERN), - LintId::of(methods::SKIP_WHILE_NEXT), - LintId::of(methods::STRING_EXTEND_CHARS), - LintId::of(methods::SUSPICIOUS_MAP), - LintId::of(methods::SUSPICIOUS_SPLITN), - LintId::of(methods::UNINIT_ASSUMED_INIT), - LintId::of(methods::UNNECESSARY_FILTER_MAP), - LintId::of(methods::UNNECESSARY_FOLD), - LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), - LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), - LintId::of(methods::USELESS_ASREF), - LintId::of(methods::WRONG_SELF_CONVENTION), - LintId::of(methods::ZST_OFFSET), - LintId::of(minmax::MIN_MAX), - LintId::of(misc::CMP_NAN), - LintId::of(misc::CMP_OWNED), - LintId::of(misc::FLOAT_CMP), - LintId::of(misc::MODULO_ONE), - LintId::of(misc::SHORT_CIRCUIT_STATEMENT), - LintId::of(misc::TOPLEVEL_REF_ARG), - LintId::of(misc::ZERO_PTR), - LintId::of(misc_early::BUILTIN_TYPE_SHADOW), - LintId::of(misc_early::DOUBLE_NEG), - LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), - LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), - LintId::of(misc_early::REDUNDANT_PATTERN), - LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), - LintId::of(misc_early::ZERO_PREFIXED_LITERAL), - LintId::of(mut_key::MUTABLE_KEY_TYPE), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), - LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), - LintId::of(mutex_atomic::MUTEX_ATOMIC), - LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), - LintId::of(needless_bool::BOOL_COMPARISON), - LintId::of(needless_bool::NEEDLESS_BOOL), - LintId::of(needless_borrow::NEEDLESS_BORROW), - LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), - LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), - LintId::of(needless_update::NEEDLESS_UPDATE), - LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), - LintId::of(neg_multiply::NEG_MULTIPLY), - LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), - LintId::of(no_effect::NO_EFFECT), - LintId::of(no_effect::UNNECESSARY_OPERATION), - LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), - LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), - LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), - LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), - LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), - LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), - LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), - LintId::of(precedence::PRECEDENCE), - LintId::of(ptr::CMP_NULL), - LintId::of(ptr::INVALID_NULL_PTR_USAGE), - LintId::of(ptr::MUT_FROM_REF), - LintId::of(ptr::PTR_ARG), - LintId::of(ptr_eq::PTR_EQ), - LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(question_mark::QUESTION_MARK), - LintId::of(ranges::MANUAL_RANGE_CONTAINS), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), - LintId::of(ranges::REVERSED_EMPTY_RANGES), - LintId::of(redundant_clone::REDUNDANT_CLONE), - LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), - LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(redundant_slicing::REDUNDANT_SLICING), - LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(reference::DEREF_ADDROF), - LintId::of(reference::REF_IN_DEREF), - LintId::of(regex::INVALID_REGEX), - LintId::of(repeat_once::REPEAT_ONCE), - LintId::of(returns::LET_AND_RETURN), - LintId::of(returns::NEEDLESS_RETURN), - LintId::of(self_assignment::SELF_ASSIGNMENT), - LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), - LintId::of(serde_api::SERDE_API_MISUSE), - LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), - LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), - LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), - LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), - LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), - LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), - LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), - LintId::of(swap::ALMOST_SWAPPED), - LintId::of(swap::MANUAL_SWAP), - LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), - LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), - LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), - LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), - LintId::of(transmute::CROSSPOINTER_TRANSMUTE), - LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), - LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), - LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), - LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), - LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), - LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), - LintId::of(transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), - LintId::of(transmute::WRONG_TRANSMUTE), - LintId::of(transmuting_null::TRANSMUTING_NULL), - LintId::of(try_err::TRY_ERR), - LintId::of(types::BORROWED_BOX), - LintId::of(types::BOX_VEC), - LintId::of(types::REDUNDANT_ALLOCATION), - LintId::of(types::TYPE_COMPLEXITY), - LintId::of(types::VEC_BOX), - LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), - LintId::of(unicode::INVISIBLE_CHARACTERS), - LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), - LintId::of(unit_types::UNIT_ARG), - LintId::of(unit_types::UNIT_CMP), - LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), - LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), - LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), - LintId::of(unused_unit::UNUSED_UNIT), - LintId::of(unwrap::PANICKING_UNWRAP), - LintId::of(unwrap::UNNECESSARY_UNWRAP), - LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), - LintId::of(useless_conversion::USELESS_CONVERSION), - LintId::of(vec::USELESS_VEC), - LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), - LintId::of(write::PRINTLN_EMPTY_STRING), - LintId::of(write::PRINT_LITERAL), - LintId::of(write::PRINT_WITH_NEWLINE), - LintId::of(write::WRITELN_EMPTY_STRING), - LintId::of(write::WRITE_LITERAL), - LintId::of(write::WRITE_WITH_NEWLINE), - LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), - ]); - - store.register_group(true, "clippy::style", Some("clippy_style"), vec![ - LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assign_ops::ASSIGN_OP_PATTERN), - LintId::of(blacklisted_name::BLACKLISTED_NAME), - LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), - LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), - LintId::of(casts::FN_TO_NUMERIC_CAST), - LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), - LintId::of(collapsible_if::COLLAPSIBLE_IF), - LintId::of(collapsible_match::COLLAPSIBLE_MATCH), - LintId::of(comparison_chain::COMPARISON_CHAIN), - LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), - LintId::of(doc::MISSING_SAFETY_DOC), - LintId::of(doc::NEEDLESS_DOCTEST_MAIN), - LintId::of(enum_variants::ENUM_VARIANT_NAMES), - LintId::of(enum_variants::MODULE_INCEPTION), - LintId::of(eq_op::OP_REF), - LintId::of(eta_reduction::REDUNDANT_CLOSURE), - LintId::of(float_literal::EXCESSIVE_PRECISION), - LintId::of(from_over_into::FROM_OVER_INTO), - LintId::of(from_str_radix_10::FROM_STR_RADIX_10), - LintId::of(functions::DOUBLE_MUST_USE), - LintId::of(functions::MUST_USE_UNIT), - LintId::of(functions::RESULT_UNIT_ERR), - LintId::of(if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(inherent_to_string::INHERENT_TO_STRING), - LintId::of(len_zero::COMPARISON_TO_EMPTY), - LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), - LintId::of(len_zero::LEN_ZERO), - LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), - LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), - LintId::of(loops::FOR_KV_MAP), - LintId::of(loops::NEEDLESS_RANGE_LOOP), - LintId::of(loops::SAME_ITEM_PUSH), - LintId::of(loops::WHILE_LET_ON_ITERATOR), - LintId::of(main_recursion::MAIN_RECURSION), - LintId::of(manual_async_fn::MANUAL_ASYNC_FN), - LintId::of(manual_map::MANUAL_MAP), - LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(map_clone::MAP_CLONE), - LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), - LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), - LintId::of(matches::MATCH_OVERLAPPING_ARM), - LintId::of(matches::MATCH_REF_PATS), - LintId::of(matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(matches::SINGLE_MATCH), - LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), - LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), - LintId::of(methods::BYTES_NTH), - LintId::of(methods::CHARS_LAST_CMP), - LintId::of(methods::CHARS_NEXT_CMP), - LintId::of(methods::INTO_ITER_ON_REF), - LintId::of(methods::ITER_CLONED_COLLECT), - LintId::of(methods::ITER_NEXT_SLICE), - LintId::of(methods::ITER_NTH_ZERO), - LintId::of(methods::ITER_SKIP_NEXT), - LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), - LintId::of(methods::MAP_COLLECT_RESULT_UNIT), - LintId::of(methods::NEW_RET_NO_SELF), - LintId::of(methods::OK_EXPECT), - LintId::of(methods::OPTION_MAP_OR_NONE), - LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), - LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), - LintId::of(methods::SINGLE_CHAR_ADD_STR), - LintId::of(methods::STRING_EXTEND_CHARS), - LintId::of(methods::UNNECESSARY_FOLD), - LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), - LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), - LintId::of(methods::WRONG_SELF_CONVENTION), - LintId::of(misc::TOPLEVEL_REF_ARG), - LintId::of(misc::ZERO_PTR), - LintId::of(misc_early::BUILTIN_TYPE_SHADOW), - LintId::of(misc_early::DOUBLE_NEG), - LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), - LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), - LintId::of(misc_early::REDUNDANT_PATTERN), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), - LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), - LintId::of(needless_borrow::NEEDLESS_BORROW), - LintId::of(neg_multiply::NEG_MULTIPLY), - LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), - LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), - LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), - LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), - LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(ptr::CMP_NULL), - LintId::of(ptr::PTR_ARG), - LintId::of(ptr_eq::PTR_EQ), - LintId::of(question_mark::QUESTION_MARK), - LintId::of(ranges::MANUAL_RANGE_CONTAINS), - LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(returns::LET_AND_RETURN), - LintId::of(returns::NEEDLESS_RETURN), - LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), - LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), - LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), - LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), - LintId::of(try_err::TRY_ERR), - LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(unused_unit::UNUSED_UNIT), - LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), - LintId::of(write::PRINTLN_EMPTY_STRING), - LintId::of(write::PRINT_LITERAL), - LintId::of(write::PRINT_WITH_NEWLINE), - LintId::of(write::WRITELN_EMPTY_STRING), - LintId::of(write::WRITE_LITERAL), - LintId::of(write::WRITE_WITH_NEWLINE), - ]); - - store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![ - LintId::of(attrs::DEPRECATED_CFG_ATTR), - LintId::of(booleans::NONMINIMAL_BOOL), - LintId::of(casts::CHAR_LIT_AS_U8), - LintId::of(casts::UNNECESSARY_CAST), - LintId::of(copies::BRANCHES_SHARING_CODE), - LintId::of(double_comparison::DOUBLE_COMPARISONS), - LintId::of(double_parens::DOUBLE_PARENS), - LintId::of(duration_subsec::DURATION_SUBSEC), - LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), - LintId::of(explicit_write::EXPLICIT_WRITE), - LintId::of(format::USELESS_FORMAT), - LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_last_with_len::GET_LAST_WITH_LEN), - LintId::of(identity_op::IDENTITY_OP), - LintId::of(int_plus_one::INT_PLUS_ONE), - LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), - LintId::of(lifetimes::NEEDLESS_LIFETIMES), - LintId::of(loops::EXPLICIT_COUNTER_LOOP), - LintId::of(loops::MANUAL_FLATTEN), - LintId::of(loops::SINGLE_ELEMENT_LOOP), - LintId::of(loops::WHILE_LET_LOOP), - LintId::of(manual_strip::MANUAL_STRIP), - LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), - LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), - LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), - LintId::of(matches::MATCH_AS_REF), - LintId::of(matches::MATCH_SINGLE_BINDING), - LintId::of(matches::WILDCARD_IN_OR_PATTERNS), - LintId::of(methods::BIND_INSTEAD_OF_MAP), - LintId::of(methods::CLONE_ON_COPY), - LintId::of(methods::FILTER_MAP_IDENTITY), - LintId::of(methods::FILTER_NEXT), - LintId::of(methods::FLAT_MAP_IDENTITY), - LintId::of(methods::INSPECT_FOR_EACH), - LintId::of(methods::ITER_COUNT), - LintId::of(methods::MANUAL_FILTER_MAP), - LintId::of(methods::MANUAL_FIND_MAP), - LintId::of(methods::MAP_IDENTITY), - LintId::of(methods::OPTION_AS_REF_DEREF), - LintId::of(methods::OPTION_FILTER_MAP), - LintId::of(methods::SEARCH_IS_SOME), - LintId::of(methods::SKIP_WHILE_NEXT), - LintId::of(methods::UNNECESSARY_FILTER_MAP), - LintId::of(methods::USELESS_ASREF), - LintId::of(misc::SHORT_CIRCUIT_STATEMENT), - LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), - LintId::of(misc_early::ZERO_PREFIXED_LITERAL), - LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), - LintId::of(needless_bool::BOOL_COMPARISON), - LintId::of(needless_bool::NEEDLESS_BOOL), - LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), - LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), - LintId::of(needless_update::NEEDLESS_UPDATE), - LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), - LintId::of(no_effect::NO_EFFECT), - LintId::of(no_effect::UNNECESSARY_OPERATION), - LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), - LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), - LintId::of(precedence::PRECEDENCE), - LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), - LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), - LintId::of(redundant_slicing::REDUNDANT_SLICING), - LintId::of(reference::DEREF_ADDROF), - LintId::of(reference::REF_IN_DEREF), - LintId::of(repeat_once::REPEAT_ONCE), - LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), - LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), - LintId::of(swap::MANUAL_SWAP), - LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), - LintId::of(transmute::CROSSPOINTER_TRANSMUTE), - LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), - LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), - LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), - LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), - LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), - LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), - LintId::of(transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(types::BORROWED_BOX), - LintId::of(types::TYPE_COMPLEXITY), - LintId::of(types::VEC_BOX), - LintId::of(unit_types::UNIT_ARG), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), - LintId::of(unwrap::UNNECESSARY_UNWRAP), - LintId::of(useless_conversion::USELESS_CONVERSION), - LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), - ]); - - store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ - LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), - LintId::of(approx_const::APPROX_CONSTANT), - LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), - LintId::of(attrs::DEPRECATED_SEMVER), - LintId::of(attrs::MISMATCHED_TARGET_OS), - LintId::of(attrs::USELESS_ATTRIBUTE), - LintId::of(bit_mask::BAD_BIT_MASK), - LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), - LintId::of(booleans::LOGIC_BUG), - LintId::of(casts::CAST_REF_TO_MUT), - LintId::of(copies::IFS_SAME_COND), - LintId::of(copies::IF_SAME_THEN_ELSE), - LintId::of(derive::DERIVE_HASH_XOR_EQ), - LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), - LintId::of(drop_forget_ref::DROP_COPY), - LintId::of(drop_forget_ref::DROP_REF), - LintId::of(drop_forget_ref::FORGET_COPY), - LintId::of(drop_forget_ref::FORGET_REF), - LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), - LintId::of(eq_op::EQ_OP), - LintId::of(erasing_op::ERASING_OP), - LintId::of(formatting::POSSIBLE_MISSING_COMMA), - LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), - LintId::of(if_let_mutex::IF_LET_MUTEX), - LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), - LintId::of(infinite_iter::INFINITE_ITER), - LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), - LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), - LintId::of(let_underscore::LET_UNDERSCORE_LOCK), - LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(loops::ITER_NEXT_LOOP), - LintId::of(loops::NEVER_LOOP), - LintId::of(loops::WHILE_IMMUTABLE_CONDITION), - LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), - LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), - LintId::of(methods::CLONE_DOUBLE_REF), - LintId::of(methods::ITERATOR_STEP_BY_ZERO), - LintId::of(methods::SUSPICIOUS_SPLITN), - LintId::of(methods::UNINIT_ASSUMED_INIT), - LintId::of(methods::ZST_OFFSET), - LintId::of(minmax::MIN_MAX), - LintId::of(misc::CMP_NAN), - LintId::of(misc::FLOAT_CMP), - LintId::of(misc::MODULO_ONE), - LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), - LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), - LintId::of(ptr::INVALID_NULL_PTR_USAGE), - LintId::of(ptr::MUT_FROM_REF), - LintId::of(ranges::REVERSED_EMPTY_RANGES), - LintId::of(regex::INVALID_REGEX), - LintId::of(self_assignment::SELF_ASSIGNMENT), - LintId::of(serde_api::SERDE_API_MISUSE), - LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), - LintId::of(swap::ALMOST_SWAPPED), - LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), - LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), - LintId::of(transmute::WRONG_TRANSMUTE), - LintId::of(transmuting_null::TRANSMUTING_NULL), - LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), - LintId::of(unicode::INVISIBLE_CHARACTERS), - LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), - LintId::of(unit_types::UNIT_CMP), - LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), - LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), - LintId::of(unwrap::PANICKING_UNWRAP), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), - ]); - - store.register_group(true, "clippy::suspicious", None, vec![ - LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), - LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), - LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), - LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), - LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), - LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), - LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), - LintId::of(loops::EMPTY_LOOP), - LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), - LintId::of(loops::MUT_RANGE_BOUND), - LintId::of(methods::SUSPICIOUS_MAP), - LintId::of(mut_key::MUTABLE_KEY_TYPE), - LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), - LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), - ]); - - store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ - LintId::of(entry::MAP_ENTRY), - LintId::of(escape::BOXED_LOCAL), - LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), - LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), - LintId::of(loops::MANUAL_MEMCPY), - LintId::of(loops::NEEDLESS_COLLECT), - LintId::of(methods::EXPECT_FUN_CALL), - LintId::of(methods::EXTEND_WITH_DRAIN), - LintId::of(methods::ITER_NTH), - LintId::of(methods::MANUAL_STR_REPEAT), - LintId::of(methods::OR_FUN_CALL), - LintId::of(methods::SINGLE_CHAR_PATTERN), - LintId::of(misc::CMP_OWNED), - LintId::of(mutex_atomic::MUTEX_ATOMIC), - LintId::of(redundant_clone::REDUNDANT_CLONE), - LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), - LintId::of(types::BOX_VEC), - LintId::of(types::REDUNDANT_ALLOCATION), - LintId::of(vec::USELESS_VEC), - LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - ]); - - store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![ - LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA), - LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS), - LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES), - ]); - - store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ - LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR), - LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY), - LintId::of(disallowed_method::DISALLOWED_METHOD), - LintId::of(disallowed_type::DISALLOWED_TYPE), - LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM), - LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS), - LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS), - LintId::of(future_not_send::FUTURE_NOT_SEND), - LintId::of(let_if_seq::USELESS_LET_IF_SEQ), - LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), - LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), - LintId::of(mutex_atomic::MUTEX_INTEGER), - LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), - LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), - LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), - LintId::of(regex::TRIVIAL_REGEX), - LintId::of(strings::STRING_LIT_AS_BYTES), - LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), - LintId::of(transmute::USELESS_TRANSMUTE), - LintId::of(use_self::USE_SELF), - ]); + include!("lib.register_internal.rs"); + + include!("lib.register_all.rs"); + include!("lib.register_style.rs"); + include!("lib.register_complexity.rs"); + include!("lib.register_correctness.rs"); + include!("lib.register_suspicious.rs"); + include!("lib.register_perf.rs"); + include!("lib.register_cargo.rs"); + include!("lib.register_nursery.rs"); #[cfg(feature = "metadata-collector-lint")] { @@ -1835,7 +486,12 @@ store.register_late_pass(|| Box::new(serde_api::SerdeApi)); let vec_box_size_threshold = conf.vec_box_size_threshold; let type_complexity_threshold = conf.type_complexity_threshold; - store.register_late_pass(move || Box::new(types::Types::new(vec_box_size_threshold, type_complexity_threshold))); + let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; + store.register_late_pass(move || Box::new(types::Types::new( + vec_box_size_threshold, + type_complexity_threshold, + avoid_breaking_exported_api, + ))); store.register_late_pass(|| Box::new(booleans::NonminimalBool)); store.register_late_pass(|| Box::new(needless_bitwise_bool::NeedlessBitwiseBool)); store.register_late_pass(|| Box::new(eq_op::EqOp)); @@ -1846,9 +502,9 @@ store.register_late_pass(|| Box::new(ptr::Ptr)); store.register_late_pass(|| Box::new(ptr_eq::PtrEq)); store.register_late_pass(|| Box::new(needless_bool::NeedlessBool)); + store.register_late_pass(|| Box::new(needless_option_as_deref::OptionNeedlessDeref)); store.register_late_pass(|| Box::new(needless_bool::BoolComparison)); store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach)); - store.register_late_pass(|| Box::new(approx_const::ApproxConstant)); store.register_late_pass(|| Box::new(misc::MiscLints)); store.register_late_pass(|| Box::new(eta_reduction::EtaReduction)); store.register_late_pass(|| Box::new(identity_op::IdentityOp)); @@ -1877,6 +533,7 @@ }); let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; + store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv))); store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv))); store.register_late_pass(move || Box::new(matches::Matches::new(msrv))); store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustive::new(msrv))); @@ -1894,9 +551,10 @@ store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount)); + store.register_late_pass(|| Box::new(same_name_method::SameNameMethod)); store.register_late_pass(|| Box::new(map_clone::MapClone)); store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore)); - store.register_late_pass(|| Box::new(shadow::Shadow)); + store.register_late_pass(|| Box::new(shadow::Shadow::default())); store.register_late_pass(|| Box::new(unit_types::UnitTypes)); store.register_late_pass(|| Box::new(loops::Loops)); store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default())); @@ -1920,12 +578,13 @@ store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented)); store.register_late_pass(|| Box::new(strings::StringLitAsBytes)); store.register_late_pass(|| Box::new(derive::Derive)); + store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls)); store.register_late_pass(|| Box::new(get_last_with_len::GetLastWithLen)); store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef)); store.register_late_pass(|| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons)); store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); - store.register_late_pass(|| Box::new(regex::Regex::default())); + store.register_late_pass(|| Box::new(regex::Regex)); store.register_late_pass(|| Box::new(copies::CopyAndPaste)); store.register_late_pass(|| Box::new(copy_iterator::CopyIterator)); store.register_late_pass(|| Box::new(format::UselessFormat)); @@ -1940,7 +599,6 @@ let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); store.register_late_pass(|| Box::new(neg_multiply::NegMultiply)); - store.register_late_pass(|| Box::new(mem_discriminant::MemDiscriminant)); store.register_late_pass(|| Box::new(mem_forget::MemForget)); store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default())); store.register_late_pass(|| Box::new(assign_ops::AssignOps)); @@ -1949,7 +607,7 @@ store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new())); store.register_late_pass(|| Box::new(missing_inline::MissingInline)); store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems)); - store.register_late_pass(|| Box::new(if_let_some_result::OkIfLet)); + store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk)); store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl)); store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount)); let enum_variant_size_threshold = conf.enum_variant_size_threshold; @@ -2056,6 +714,7 @@ store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); + store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock)); store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems)); store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); @@ -2078,8 +737,8 @@ store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); - let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(disallowed_method::DisallowedMethod::new(&disallowed_methods))); + let disallowed_methods = conf.disallowed_methods.clone(); + store.register_late_pass(move || Box::new(disallowed_method::DisallowedMethod::new(disallowed_methods.clone()))); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax)); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax)); store.register_late_pass(|| Box::new(undropped_manually_drops::UndroppedManuallyDrops)); @@ -2092,7 +751,8 @@ store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10)); store.register_late_pass(|| Box::new(manual_map::ManualMap)); store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); - store.register_early_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison)); + store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison)); + store.register_early_pass(move || Box::new(module_style::ModStyle)); store.register_late_pass(|| Box::new(unused_async::UnusedAsync)); let disallowed_types = conf.disallowed_types.iter().cloned().collect::>(); store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(&disallowed_types))); @@ -2102,6 +762,11 @@ store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts))); store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings)); store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors)); + store.register_late_pass(move || Box::new(feature_name::FeatureName)); + store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator)); + store.register_late_pass(move || Box::new(manual_assert::ManualAssert)); + let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; + store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send))); } #[rustfmt::skip] @@ -2157,6 +822,7 @@ ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"); ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"); ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map"); + ls.register_renamed("clippy::box_vec", "clippy::box_collection"); ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"); ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"); ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"); @@ -2171,6 +837,7 @@ ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion"); ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters"); ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str"); + ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok"); // uplifted lints ls.register_renamed("clippy::invalid_ref", "invalid_value"); @@ -2181,6 +848,7 @@ ls.register_renamed("clippy::panic_params", "non_fmt_panics"); ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints"); ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"); + ls.register_renamed("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"); } // only exists to let the dogfood integration test works. diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs 2021-11-29 19:27:12.000000000 +0000 @@ -54,11 +54,11 @@ // will allow further borrows afterwards let ty = cx.typeck_results().expr_ty(e); is_iterable_array(ty, cx) || - is_type_diagnostic_item(cx, ty, sym::vec_type) || + is_type_diagnostic_item(cx, ty, sym::Vec) || is_type_diagnostic_item(cx, ty, sym::LinkedList) || - is_type_diagnostic_item(cx, ty, sym::hashmap_type) || - is_type_diagnostic_item(cx, ty, sym::hashset_type) || - is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || + is_type_diagnostic_item(cx, ty, sym::HashMap) || + is_type_diagnostic_item(cx, ty, sym::HashSet) || + is_type_diagnostic_item(cx, ty, sym::VecDeque) || is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) || is_type_diagnostic_item(cx, ty, sym::BTreeSet) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,20 +3,14 @@ use clippy_utils::source::snippet; use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::visitors::is_local_used; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::sym; /// Checks for the `FOR_KV_MAP` lint. -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - pat: &'tcx Pat<'_>, - arg: &'tcx Expr<'_>, - body: &'tcx Expr<'_>, - expr: &'tcx Expr<'_>, -) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { let pat_span = pat.span; if let PatKind::Tuple(pat, _) = pat.kind { @@ -39,11 +33,11 @@ _ => arg, }; - if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) { + if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) { span_lint_and_then( cx, FOR_KV_MAP, - expr.span, + arg_span, &format!("you seem to want to iterate on a map's {}s", kind), |diag| { let map = sugg::Sugg::hir(cx, arg, "map"); @@ -66,9 +60,7 @@ fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { match *pat { PatKind::Wild => true, - PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => { - !LocalUsedVisitor::new(cx, id).check_expr(body) - }, + PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), _ => false, } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ /// Checks for `for` loops over `Option`s and `Result`s. pub(super) fn check(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(arg); - if is_type_diagnostic_item(cx, ty, sym::option_type) { + if is_type_diagnostic_item(cx, ty, sym::Option) { span_lint_and_help( cx, FOR_LOOPS_OVER_FALLIBLES, @@ -26,7 +26,7 @@ snippet(cx, arg.span, "_") ), ); - } else if is_type_diagnostic_item(cx, ty, sym::result_type) { + } else if is_type_diagnostic_item(cx, ty, sym::Result) { span_lint_and_help( cx, FOR_LOOPS_OVER_FALLIBLES, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs 2021-11-29 19:27:12.000000000 +0000 @@ -5,12 +5,12 @@ use rustc_lint::LateContext; use rustc_span::sym; -pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, expr: &Expr<'_>) -> bool { +pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool { if is_trait_method(cx, arg, sym::Iterator) { span_lint( cx, ITER_NEXT_LOOP, - expr.span, + arg.span, "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ probably not what you want", ); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,6 +2,7 @@ use super::MANUAL_FLATTEN; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; +use clippy_utils::visitors::is_local_used; use clippy_utils::{is_lang_ctor, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -37,7 +38,8 @@ if_chain! { if let Some(inner_expr) = inner_expr; - if let Some(higher::IfLet { let_pat, let_expr, if_else: None, .. }) = higher::IfLet::hir(cx, inner_expr); + if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None }) + = higher::IfLet::hir(cx, inner_expr); // Ensure match_expr in `if let` statement is the same as the pat from the for-loop if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; if path_to_local_id(let_expr, pat_hir_id); @@ -46,6 +48,8 @@ let some_ctor = is_lang_ctor(cx, qpath, OptionSome); let ok_ctor = is_lang_ctor(cx, qpath, ResultOk); if some_ctor || ok_ctor; + // Ensure epxr in `if let` is not used afterwards + if !is_local_used(cx, if_then, pat_hir_id); then { let if_let_type = if some_ctor { "Some" } else { "Ok" }; // Prepare the error message diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs 2021-11-29 19:27:12.000000000 +0000 @@ -332,7 +332,7 @@ _ => false, }; - is_slice || is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) + is_slice || is_type_diagnostic_item(cx, ty, sym::Vec) || is_type_diagnostic_item(cx, ty, sym::VecDeque) } fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/mod.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -397,6 +397,21 @@ /// ### Why is this bad? /// One might think that modifying the mutable variable changes the loop bounds /// + /// ### Known problems + /// False positive when mutation is followed by a `break`, but the `break` is not immediately + /// after the mutation: + /// + /// ```rust + /// let mut x = 5; + /// for _ in 0..x { + /// x += 1; // x is a range bound that is mutated + /// ..; // some other expression + /// break; // leaves the loop, so mutation is not an issue + /// } + /// ``` + /// + /// False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072)) + /// /// ### Example /// ```rust /// let mut foo = 42; @@ -580,8 +595,8 @@ while_let_on_iterator::check(cx, expr); - if let Some(higher::While { if_cond, if_then, .. }) = higher::While::hir(&expr) { - while_immutable_condition::check(cx, if_cond, if_then); + if let Some(higher::While { condition, body }) = higher::While::hir(expr) { + while_immutable_condition::check(cx, condition, body); } needless_collect::check(expr, cx); @@ -601,15 +616,15 @@ needless_range_loop::check(cx, pat, arg, body, expr); explicit_counter_loop::check(cx, pat, arg, body, expr); } - check_for_loop_arg(cx, pat, arg, expr); - for_kv_map::check(cx, pat, arg, body, expr); + check_for_loop_arg(cx, pat, arg); + for_kv_map::check(cx, pat, arg, body); mut_range_bound::check(cx, arg, body); single_element_loop::check(cx, pat, arg, body, expr); same_item_push::check(cx, pat, arg, body, expr); manual_flatten::check(cx, pat, arg, body, span); } -fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) { +fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used if let ExprKind::MethodCall(method, _, [self_arg], _) = arg.kind { @@ -622,7 +637,7 @@ explicit_into_iter_loop::check(cx, self_arg, arg); }, "next" => { - next_loop_linted = iter_next_loop::check(cx, arg, expr); + next_loop_linted = iter_next_loop::check(cx, arg); }, _ => {}, } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,24 +1,27 @@ use super::MUT_RANGE_BOUND; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::{higher, path_to_local}; +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{get_enclosing_block, higher, path_to_local}; use if_chain::if_chain; -use rustc_hir::{BindingAnnotation, Expr, HirId, Node, PatKind}; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; use rustc_middle::{mir::FakeReadCause, ty}; use rustc_span::source_map::Span; use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) { - if let Some(higher::Range { - start: Some(start), - end: Some(end), - .. - }) = higher::Range::hir(arg) - { - let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)]; - if mut_ids[0].is_some() || mut_ids[1].is_some() { - let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids); + if_chain! { + if let Some(higher::Range { + start: Some(start), + end: Some(end), + .. + }) = higher::Range::hir(arg); + let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end)); + if mut_id_start.is_some() || mut_id_end.is_some(); + then { + let (span_low, span_high) = check_for_mutation(cx, body, mut_id_start, mut_id_end); mut_warn_with_span(cx, span_low); mut_warn_with_span(cx, span_high); } @@ -27,11 +30,13 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option) { if let Some(sp) = span { - span_lint( + span_lint_and_note( cx, MUT_RANGE_BOUND, sp, - "attempt to mutate range bound within loop; note that the range of the loop is unchanged", + "attempt to mutate range bound within loop", + None, + "the range of the loop is unchanged", ); } } @@ -51,12 +56,13 @@ fn check_for_mutation<'tcx>( cx: &LateContext<'tcx>, body: &Expr<'_>, - bound_ids: &[Option], + bound_id_start: Option, + bound_id_end: Option, ) -> (Option, Option) { let mut delegate = MutatePairDelegate { cx, - hir_id_low: bound_ids[0], - hir_id_high: bound_ids[1], + hir_id_low: bound_id_start, + hir_id_high: bound_id_end, span_low: None, span_high: None, }; @@ -70,6 +76,7 @@ ) .walk_expr(body); }); + delegate.mutation_span() } @@ -85,12 +92,12 @@ fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { - if let ty::BorrowKind::MutBorrow = bk { + if bk == ty::BorrowKind::MutBorrow { if let PlaceBase::Local(id) = cmt.place.base { - if Some(id) == self.hir_id_low { + if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); } - if Some(id) == self.hir_id_high { + if Some(id) == self.hir_id_high && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); } } @@ -99,10 +106,10 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { if let PlaceBase::Local(id) = cmt.place.base { - if Some(id) == self.hir_id_low { + if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); } - if Some(id) == self.hir_id_high { + if Some(id) == self.hir_id_high && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); } } @@ -116,3 +123,52 @@ (self.span_low, self.span_high) } } + +struct BreakAfterExprVisitor { + hir_id: HirId, + past_expr: bool, + past_candidate: bool, + break_after_expr: bool, +} + +impl BreakAfterExprVisitor { + pub fn is_found(cx: &LateContext<'_>, hir_id: HirId) -> bool { + let mut visitor = BreakAfterExprVisitor { + hir_id, + past_expr: false, + past_candidate: false, + break_after_expr: false, + }; + + get_enclosing_block(cx, hir_id).map_or(false, |block| { + visitor.visit_block(block); + visitor.break_after_expr + }) + } +} + +impl intravisit::Visitor<'tcx> for BreakAfterExprVisitor { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if self.past_candidate { + return; + } + + if expr.hir_id == self.hir_id { + self.past_expr = true; + } else if self.past_expr { + if matches!(&expr.kind, ExprKind::Break(..)) { + self.break_after_expr = true; + } + + self.past_candidate = true; + } else { + intravisit::walk_expr(self, expr); + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs 2021-11-29 19:27:12.000000000 +0000 @@ -26,11 +26,11 @@ if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator); then { let ty = cx.typeck_results().expr_ty(&args[0]); - let mut applicability = Applicability::MachineApplicable; + let mut applicability = Applicability::MaybeIncorrect; let is_empty_sugg = "next().is_none()".to_string(); let method_name = &*method.ident.name.as_str(); - let sugg = if is_type_diagnostic_item(cx, ty, sym::vec_type) || - is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || + let sugg = if is_type_diagnostic_item(cx, ty, sym::Vec) || + is_type_diagnostic_item(cx, ty, sym::VecDeque) || is_type_diagnostic_item(cx, ty, sym::LinkedList) || is_type_diagnostic_item(cx, ty, sym::BinaryHeap) { match method_name { @@ -47,7 +47,7 @@ } } else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) || - is_type_diagnostic_item(cx, ty, sym::hashmap_type) { + is_type_diagnostic_item(cx, ty, sym::HashMap) { match method_name { "is_empty" => is_empty_sugg, _ => return, @@ -79,8 +79,8 @@ if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind; if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator); let ty = cx.typeck_results().expr_ty(init_expr); - if is_type_diagnostic_item(cx, ty, sym::vec_type) || - is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || + if is_type_diagnostic_item(cx, ty, sym::Vec) || + is_type_diagnostic_item(cx, ty, sym::VecDeque) || is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || is_type_diagnostic_item(cx, ty, sym::LinkedList); if let Some(iter_calls) = detect_iter_and_into_iters(block, id); @@ -113,7 +113,7 @@ (stmt.span, String::new()), (iter_call.span, iter_replacement) ], - Applicability::MachineApplicable,// MaybeIncorrect, + Applicability::MaybeIncorrect, ); }, ); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,10 +2,8 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; -use clippy_utils::visitors::LocalUsedVisitor; -use clippy_utils::{ - contains_name, higher, is_integer_const, match_trait_method, path_to_local_id, paths, sugg, SpanlessEq, -}; +use clippy_utils::visitors::is_local_used; +use clippy_utils::{contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -97,7 +95,7 @@ let mut take_expr = end; if let ExprKind::Binary(ref op, left, right) = end.kind { - if let BinOpKind::Add = op.node { + if op.node == BinOpKind::Add { let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left); let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right); @@ -146,7 +144,7 @@ span_lint_and_then( cx, NEEDLESS_RANGE_LOOP, - expr.span, + arg.span, &format!("the loop variable `{}` is used to index `{}`", ident.name, indexed), |diag| { multispan_sugg( @@ -172,7 +170,7 @@ span_lint_and_then( cx, NEEDLESS_RANGE_LOOP, - expr.span, + arg.span, &format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed), |diag| { multispan_sugg( @@ -256,43 +254,36 @@ if let ExprKind::Path(ref seqpath) = seqexpr.kind; if let QPath::Resolved(None, seqvar) = *seqpath; if seqvar.segments.len() == 1; - let index_used_directly = path_to_local_id(idx, self.var); - let indexed_indirectly = { - let mut used_visitor = LocalUsedVisitor::new(self.cx, self.var); - walk_expr(&mut used_visitor, idx); - used_visitor.used - }; - if indexed_indirectly || index_used_directly; + if is_local_used(self.cx, idx, self.var); then { if self.prefer_mutable { self.indexed_mut.insert(seqvar.segments[0].ident.name); } + let index_used_directly = matches!(idx.kind, ExprKind::Path(_)); let res = self.cx.qpath_res(seqpath, seqexpr.hir_id); match res { Res::Local(hir_id) => { let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id); let parent_def_id = self.cx.tcx.hir().local_def_id(parent_id); let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id); - if indexed_indirectly { - self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent)); - } if index_used_directly { self.indexed_directly.insert( seqvar.segments[0].ident.name, (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)), ); + } else { + self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent)); } return false; // no need to walk further *on the variable* } Res::Def(DefKind::Static | DefKind::Const, ..) => { - if indexed_indirectly { - self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None); - } if index_used_directly { self.indexed_directly.insert( seqvar.segments[0].ident.name, (None, self.cx.typeck_results().node_type(seqexpr.hir_id)), ); + } else { + self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None); } return false; // no need to walk further *on the variable* } @@ -310,10 +301,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { // a range index op - if let ExprKind::MethodCall(meth, _, args, _) = expr.kind; + if let ExprKind::MethodCall(meth, _, [args_0, args_1, ..], _) = &expr.kind; if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); - if !self.check(&args[1], &args[0], expr); + if !self.check(args_1, args_0, expr); then { return } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/never_loop.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/never_loop.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/never_loop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/never_loop.rs 2021-11-29 19:27:12.000000000 +0000 @@ -14,7 +14,7 @@ NeverLoopResult::AlwaysBreak => { span_lint_and_then(cx, NEVER_LOOP, expr.span, "this loop never actually loops", |diag| { if_chain! { - if let LoopSource::ForLoop = source; + if source == LoopSource::ForLoop; if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1); if let Some(ForLoop { arg: iterator, pat, span: for_span, .. }) = ForLoop::hir(parent_match); then { @@ -87,7 +87,7 @@ fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult { let stmts = block.stmts.iter().map(stmt_to_expr); - let expr = once(block.expr.as_deref()); + let expr = once(block.expr); let mut iter = stmts.chain(expr).flatten(); never_loop_expr_seq(&mut iter, main_loop_id) } @@ -100,7 +100,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> { match stmt.kind { StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e), - StmtKind::Local(local) => local.init.as_deref(), + StmtKind::Local(local) => local.init, StmtKind::Item(..) => None, } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs 2021-11-29 19:27:12.000000000 +0000 @@ -192,7 +192,7 @@ if let Some(self_expr) = args.get(0); if let Some(pushed_item) = args.get(1); // Check that the method being called is push() on a Vec - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::vec_type); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; then { return Some((self_expr, pushed_item)) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/utils.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/utils.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/utils.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/utils.rs 2021-11-29 19:27:12.000000000 +0000 @@ -338,7 +338,7 @@ sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(), meth_name, ) - } + }, _ => format!( "{}.into_iter()", sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par() diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs 2021-11-29 19:27:12.000000000 +0000 @@ -24,13 +24,13 @@ } } - if let ExprKind::Match(ref matchexpr, ref arms, MatchSource::Normal) = inner.kind { + if let ExprKind::Match(matchexpr, arms, MatchSource::Normal) = inner.kind { if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() - && is_simple_break_expr(&arms[1].body) + && is_simple_break_expr(arms[1].body) { - could_be_while_let(cx, expr, &arms[0].pat, matchexpr); + could_be_while_let(cx, expr, arms[0].pat, matchexpr); } } } @@ -65,7 +65,7 @@ fn is_simple_break_expr(expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Break(dest, ref passed_expr) if dest.label.is_none() && passed_expr.is_none() => true, - ExprKind::Block(b, _) => extract_first_expr(b).map_or(false, |subexpr| is_simple_break_expr(subexpr)), + ExprKind::Block(b, _) => extract_first_expr(b).map_or(false, is_simple_break_expr), _ => false, } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs 2021-11-29 19:27:12.000000000 +0000 @@ -8,18 +8,13 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor}; -use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; +use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_span::{symbol::sym, Span, Symbol}; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! { - if let Some(higher::WhileLet { - if_then, - let_pat, - let_expr, - .. - }) = higher::WhileLet::hir(expr); + if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr); // check for `Some(..)` pattern if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = let_pat.kind; if let Res::Def(_, pat_did) = pat_path.res; @@ -52,13 +47,8 @@ // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used // afterwards a mutable borrow of a field isn't necessary. - let ref_mut = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) { - if cx.typeck_results().node_type(iter_expr.hir_id).ref_mutability() == Some(Mutability::Mut) { - // Reborrow for mutable references. It may not be possible to get a mutable reference here. - "&mut *" - } else { - "&mut " - } + let by_ref = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) { + ".by_ref()" } else { "" }; @@ -70,7 +60,7 @@ expr.span.with_hi(scrutinee_expr.span.hi()), "this loop could be written as a `for` loop", "try", - format!("for {} in {}{}", loop_var, ref_mut, iterator), + format!("for {} in {}{}", loop_var, iterator, by_ref), applicability, ); } @@ -79,8 +69,6 @@ struct IterExpr { /// The span of the whole expression, not just the path and fields stored here. span: Span, - /// The HIR id of the whole expression, not just the path and fields stored here. - hir_id: HirId, /// The fields used, in order of child to parent. fields: Vec, /// The path being used. @@ -91,14 +79,12 @@ /// the expression might have side effects. fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option { let span = e.span; - let hir_id = e.hir_id; let mut fields = Vec::new(); loop { match e.kind { ExprKind::Path(ref path) => { break Some(IterExpr { span, - hir_id, fields, path: cx.qpath_res(path, e.hir_id), }); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/macro_use.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/macro_use.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/macro_use.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/macro_use.rs 2021-11-29 19:27:12.000000000 +0000 @@ -29,37 +29,21 @@ "#[macro_use] is no longer needed" } -const BRACKETS: &[char] = &['<', '>']; - #[derive(Clone, Debug, PartialEq, Eq)] struct PathAndSpan { path: String, span: Span, } -/// `MacroRefData` includes the name of the macro -/// and the path from `SourceMap::span_to_filename`. +/// `MacroRefData` includes the name of the macro. #[derive(Debug, Clone)] pub struct MacroRefData { name: String, - path: String, } impl MacroRefData { - pub fn new(name: String, callee: Span, cx: &LateContext<'_>) -> Self { - let sm = cx.sess().source_map(); - let mut path = sm.filename_for_diagnostics(&sm.span_to_filename(callee)) - .to_string(); - - // std lib paths are <::std::module::file type> - // so remove brackets, space and type. - if path.contains('<') { - path = path.replace(BRACKETS, ""); - } - if path.contains(' ') { - path = path.split(' ').next().unwrap().to_string(); - } - Self { name, path } + pub fn new(name: String) -> Self { + Self { name } } } @@ -79,29 +63,24 @@ fn push_unique_macro(&mut self, cx: &LateContext<'_>, span: Span) { let call_site = span.source_callsite(); let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_"); - if let Some(callee) = span.source_callee() { - if !self.collected.contains(&call_site) { - let name = if name.contains("::") { - name.split("::").last().unwrap().to_string() - } else { - name.to_string() - }; + if span.source_callee().is_some() && !self.collected.contains(&call_site) { + let name = if name.contains("::") { + name.split("::").last().unwrap().to_string() + } else { + name.to_string() + }; - self.mac_refs.push(MacroRefData::new(name, callee.def_site, cx)); - self.collected.insert(call_site); - } + self.mac_refs.push(MacroRefData::new(name)); + self.collected.insert(call_site); } } fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_>, span: Span) { let call_site = span.source_callsite(); let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_"); - if let Some(callee) = span.source_callee() { - if !self.collected.contains(&call_site) { - self.mac_refs - .push(MacroRefData::new(name.to_string(), callee.def_site, cx)); - self.collected.insert(call_site); - } + if span.source_callee().is_some() && !self.collected.contains(&call_site) { + self.mac_refs.push(MacroRefData::new(name.to_string())); + self.collected.insert(call_site); } } } @@ -156,7 +135,7 @@ } } #[allow(clippy::too_many_lines)] - fn check_crate_post(&mut self, cx: &LateContext<'_>, _krate: &hir::Crate<'_>) { + fn check_crate_post(&mut self, cx: &LateContext<'_>) { let mut used = FxHashMap::default(); let mut check_dup = vec![]; for (import, span) in &self.imports { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/main_recursion.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/main_recursion.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/main_recursion.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/main_recursion.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ use clippy_utils::source::snippet; use clippy_utils::{is_entrypoint_fn, is_no_std_crate}; use if_chain::if_chain; -use rustc_hir::{Crate, Expr, ExprKind, QPath}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -33,7 +33,7 @@ impl_lint_pass!(MainRecursion => [MAIN_RECURSION]); impl LateLintPass<'_> for MainRecursion { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'_>) { self.has_no_std_attr = is_no_std_crate(cx); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_assert.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_assert.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_assert.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_assert.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,99 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::PanicExpn; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{is_expn_of, sugg}; +use rustc_errors::Applicability; +use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Detects `if`-then-`panic!` that can be replaced with `assert!`. + /// + /// ### Why is this bad? + /// `assert!` is simpler than `if`-then-`panic!`. + /// + /// ### Example + /// ```rust + /// let sad_people: Vec<&str> = vec![]; + /// if !sad_people.is_empty() { + /// panic!("there are sad people: {:?}", sad_people); + /// } + /// ``` + /// Use instead: + /// ```rust + /// let sad_people: Vec<&str> = vec![]; + /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); + /// ``` + pub MANUAL_ASSERT, + pedantic, + "`panic!` and only a `panic!` in `if`-then statement" +} + +declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]); + +impl LateLintPass<'_> for ManualAssert { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let Expr { + kind: ExprKind:: If(cond, Expr { + kind: ExprKind::Block( + Block { + stmts: [stmt], + .. + }, + _), + .. + }, None), + .. + } = &expr; + if is_expn_of(stmt.span, "panic").is_some(); + if !matches!(cond.kind, ExprKind::Let(_, _, _)); + if let StmtKind::Semi(semi) = stmt.kind; + if !cx.tcx.sess.source_map().is_multiline(cond.span); + + then { + let span = if let Some(panic_expn) = PanicExpn::parse(semi) { + match *panic_expn.format_args.value_args { + [] => panic_expn.format_args.format_string_span, + [.., last] => panic_expn.format_args.format_string_span.to(last.span), + } + } else { + if_chain! { + if let ExprKind::Block(block, _) = semi.kind; + if let Some(init) = block.expr; + if let ExprKind::Call(_, [format_args]) = init.kind; + + then { + format_args.span + } else { + return + } + } + }; + let mut applicability = Applicability::MachineApplicable; + let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); + let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind { + if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e { + sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string() + } else { + format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par().to_string()) + } + } else { + format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par().to_string()) + }; + + span_lint_and_sugg( + cx, + MANUAL_ASSERT, + expr.span, + "only a `panic!` in `if`-then statement", + "try", + format!("assert!({}, {});", cond_sugg, sugg), + Applicability::MachineApplicable, + ); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_async_fn.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_async_fn.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_async_fn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_async_fn.rs 2021-11-29 19:27:12.000000000 +0000 @@ -49,7 +49,7 @@ ) { if_chain! { if let Some(header) = kind.header(); - if let IsAsync::NotAsync = header.asyncness; + if header.asyncness == IsAsync::NotAsync; // Check that this function returns `impl Future` if let FnRetTy::Return(ret_ty) = decl.output; if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty); @@ -178,7 +178,7 @@ if args.len() == 1; if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0]; let closure_body = cx.tcx.hir().body(body_id); - if let Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) = closure_body.generator_kind; + if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); then { return Some(closure_body); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_map.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_map.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_map.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_map.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,16 +1,18 @@ use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; +use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use clippy_utils::{ can_move_expr_to_closure, in_constant, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id, - peel_hir_expr_refs, + peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, }; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; -use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Pat, PatKind}; +use rustc_hir::{ + def::Res, Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -44,168 +46,169 @@ impl LateLintPass<'_> for ManualMap { #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(higher::IfLet { - let_pat, - let_expr, - if_then, - if_else: Some(if_else), - }) = higher::IfLet::hir(cx, expr) - { - manage_lint(cx, expr, (&let_pat.kind, if_then), (&PatKind::Wild, if_else), let_expr); + let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) { + Some(IfLetOrMatch::IfLet(scrutinee, pat, body, Some(r#else))) => (scrutinee, pat, body, None, r#else), + Some(IfLetOrMatch::Match( + scrutinee, + [arm1 @ Arm { guard: None, .. }, arm2 @ Arm { guard: None, .. }], + _, + )) => (scrutinee, arm1.pat, arm1.body, Some(arm2.pat), arm2.body), + _ => return, + }; + if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) { + return; } - if let ExprKind::Match(scrutinee, [then @ Arm { guard: None, .. }, r#else @ Arm { guard: None, .. }], _) = - expr.kind + let (scrutinee_ty, ty_ref_count, ty_mutability) = + peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee)); + if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option)) { - manage_lint( - cx, - expr, - (&then.pat.kind, then.body), - (&r#else.pat.kind, r#else.body), - scrutinee, - ); + return; } - } -} - -fn manage_lint<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - then: (&'tcx PatKind<'_>, &'tcx Expr<'_>), - r#else: (&'tcx PatKind<'_>, &'tcx Expr<'_>), - scrut: &'tcx Expr<'_>, -) { - if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) { - return; - } - - let (scrutinee_ty, ty_ref_count, ty_mutability) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrut)); - if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::option_type) - && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::option_type)) - { - return; - } - let (then_pat, then_expr) = then; - let (else_pat, else_expr) = r#else; - - let expr_ctxt = expr.span.ctxt(); - let (some_expr, some_pat, pat_ref_count, is_wild_none) = match ( - try_parse_pattern(cx, then_pat, expr_ctxt), - try_parse_pattern(cx, else_pat, expr_ctxt), - ) { - (Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_expr) => { - (else_expr, pattern, ref_count, true) - }, - (Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_expr) => { - (else_expr, pattern, ref_count, false) - }, - (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_expr) => { - (then_expr, pattern, ref_count, true) - }, - (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_expr) => { - (then_expr, pattern, ref_count, false) - }, - _ => return, - }; - - // Top level or patterns aren't allowed in closures. - if matches!(some_pat.kind, PatKind::Or(_)) { - return; - } - - let some_expr = match get_some_expr(cx, some_expr, expr_ctxt) { - Some(expr) => expr, - None => return, - }; + let expr_ctxt = expr.span.ctxt(); + let (some_expr, some_pat, pat_ref_count, is_wild_none) = match ( + try_parse_pattern(cx, then_pat, expr_ctxt), + else_pat.map_or(Some(OptionPat::Wild), |p| try_parse_pattern(cx, p, expr_ctxt)), + ) { + (Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => { + (else_body, pattern, ref_count, true) + }, + (Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => { + (else_body, pattern, ref_count, false) + }, + (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_body) => { + (then_body, pattern, ref_count, true) + }, + (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_body) => { + (then_body, pattern, ref_count, false) + }, + _ => return, + }; - if cx.typeck_results().expr_ty(some_expr) == cx.tcx.types.unit && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id) { - return; - } + // Top level or patterns aren't allowed in closures. + if matches!(some_pat.kind, PatKind::Or(_)) { + return; + } - // `map` won't perform any adjustments. - if !cx.typeck_results().expr_adjustments(some_expr).is_empty() { - return; - } + let some_expr = match get_some_expr(cx, some_expr, expr_ctxt) { + Some(expr) => expr, + None => return, + }; + + // These two lints will go back and forth with each other. + if cx.typeck_results().expr_ty(some_expr) == cx.tcx.types.unit + && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id) + { + return; + } - if !can_move_expr_to_closure(cx, some_expr) { - return; - } + // `map` won't perform any adjustments. + if !cx.typeck_results().expr_adjustments(some_expr).is_empty() { + return; + } - // Determine which binding mode to use. - let explicit_ref = some_pat.contains_explicit_ref_binding(); - let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability)); - - let as_ref_str = match binding_ref { - Some(Mutability::Mut) => ".as_mut()", - Some(Mutability::Not) => ".as_ref()", - None => "", - }; - - let mut app = Applicability::MachineApplicable; - - // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or - // it's being passed by value. - let scrutinee = peel_hir_expr_refs(scrut).0; - let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); - let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { - format!("({})", scrutinee_str) - } else { - scrutinee_str.into() - }; - - let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind { - match can_pass_as_func(cx, id, some_expr) { - Some(func) if func.span.ctxt() == some_expr.span.ctxt() => { - snippet_with_applicability(cx, func.span, "..", &mut app).into_owned() - }, - _ => { - if path_to_local_id(some_expr, id) - && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id) - && binding_ref.is_some() - { - return; + // Determine which binding mode to use. + let explicit_ref = some_pat.contains_explicit_ref_binding(); + let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability)); + + let as_ref_str = match binding_ref { + Some(Mutability::Mut) => ".as_mut()", + Some(Mutability::Not) => ".as_ref()", + None => "", + }; + + match can_move_expr_to_closure(cx, some_expr) { + Some(captures) => { + // Check if captures the closure will need conflict with borrows made in the scrutinee. + // TODO: check all the references made in the scrutinee expression. This will require interacting + // with the borrow checker. Currently only `[.]*` is checked for. + if let Some(binding_ref_mutability) = binding_ref { + let e = peel_hir_expr_while(scrutinee, |e| match e.kind { + ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e), + _ => None, + }); + if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind { + match captures.get(l) { + Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return, + Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => { + return; + }, + Some(CaptureKind::Ref(Mutability::Not)) | None => (), + } + } } - - // `ref` and `ref mut` annotations were handled earlier. - let annotation = if matches!(annotation, BindingAnnotation::Mutable) { - "mut " - } else { - "" - }; - format!( - "|{}{}| {}", - annotation, - some_binding, - snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0 - ) }, - } - } else if !is_wild_none && explicit_ref.is_none() { - // TODO: handle explicit reference annotations. - format!( - "|{}| {}", - snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0, - snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0 - ) - } else { - // Refutable bindings and mixed reference annotations can't be handled by `map`. - return; - }; - - span_lint_and_sugg( - cx, - MANUAL_MAP, - expr.span, - "manual implementation of `Option::map`", - "try this", - if is_else_clause(cx.tcx, expr) { - format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str) + None => return, + }; + + let mut app = Applicability::MachineApplicable; + + // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or + // it's being passed by value. + let scrutinee = peel_hir_expr_refs(scrutinee).0; + let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); + let scrutinee_str = + if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { + format!("({})", scrutinee_str) + } else { + scrutinee_str.into() + }; + + let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind { + match can_pass_as_func(cx, id, some_expr) { + Some(func) if func.span.ctxt() == some_expr.span.ctxt() => { + snippet_with_applicability(cx, func.span, "..", &mut app).into_owned() + }, + _ => { + if path_to_local_id(some_expr, id) + && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id) + && binding_ref.is_some() + { + return; + } + + // `ref` and `ref mut` annotations were handled earlier. + let annotation = if matches!(annotation, BindingAnnotation::Mutable) { + "mut " + } else { + "" + }; + format!( + "|{}{}| {}", + annotation, + some_binding, + snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0 + ) + }, + } + } else if !is_wild_none && explicit_ref.is_none() { + // TODO: handle explicit reference annotations. + format!( + "|{}| {}", + snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0, + snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0 + ) } else { - format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str) - }, - app, - ); + // Refutable bindings and mixed reference annotations can't be handled by `map`. + return; + }; + + span_lint_and_sugg( + cx, + MANUAL_MAP, + expr.span, + "manual implementation of `Option::map`", + "try this", + if else_pat.is_none() && is_else_clause(cx.tcx, expr) { + format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str) + } else { + format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str) + }, + app, + ); + } } // Checks whether the expression could be passed as a function, or whether a closure is needed. @@ -213,7 +216,7 @@ fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { match expr.kind { ExprKind::Call(func, [arg]) - if path_to_local_id (arg, binding) && cx.typeck_results().expr_adjustments(arg).is_empty() => + if path_to_local_id(arg, binding) && cx.typeck_results().expr_adjustments(arg).is_empty() => { Some(func) }, @@ -235,28 +238,21 @@ // Try to parse into a recognized `Option` pattern. // i.e. `_`, `None`, `Some(..)`, or a reference to any of those. -fn try_parse_pattern( - cx: &LateContext<'tcx>, - pat_kind: &'tcx PatKind<'_>, - ctxt: SyntaxContext, -) -> Option> { - fn f( - cx: &LateContext<'tcx>, - pat_kind: &'tcx PatKind<'_>, - ref_count: usize, - ctxt: SyntaxContext, - ) -> Option> { - match pat_kind { +fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option> { + fn f(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ref_count: usize, ctxt: SyntaxContext) -> Option> { + match pat.kind { PatKind::Wild => Some(OptionPat::Wild), - PatKind::Ref(ref_pat, _) => f(cx, &ref_pat.kind, ref_count + 1, ctxt), + PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt), PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone) => Some(OptionPat::None), - PatKind::TupleStruct(ref qpath, [pattern], _) if is_lang_ctor(cx, qpath, OptionSome) => { + PatKind::TupleStruct(ref qpath, [pattern], _) + if is_lang_ctor(cx, qpath, OptionSome) && pat.span.ctxt() == ctxt => + { Some(OptionPat::Some { pattern, ref_count }) }, _ => None, } } - f(cx, pat_kind, 0, ctxt) + f(cx, pat, 0, ctxt) } // Checks for an expression wrapped by the `Some` constructor. Returns the contained expression. diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_ok_or.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_ok_or.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_ok_or.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_ok_or.rs 2021-11-29 19:27:12.000000000 +0000 @@ -51,7 +51,7 @@ if args.len() == 3; let method_receiver = &args[0]; let ty = cx.typeck_results().expr_ty(method_receiver); - if is_type_diagnostic_item(cx, ty, sym::option_type); + if is_type_diagnostic_item(cx, ty, sym::Option); let or_expr = &args[1]; if is_ok_wrapping(cx, &args[2]); if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs 2021-11-29 19:27:12.000000000 +0000 @@ -82,9 +82,9 @@ if_chain! { if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind; let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::option_type) { + if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) { Some("Option") - } else if is_type_diagnostic_item(cx, ty, sym::result_type) { + } else if is_type_diagnostic_item(cx, ty, sym::Result) { Some("Result") } else { None diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/map_clone.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/map_clone.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/map_clone.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/map_clone.rs 2021-11-29 19:27:12.000000000 +0000 @@ -55,7 +55,7 @@ if args.len() == 2; if method.ident.name == sym::map; let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym::option_type) || is_trait_method(cx, e, sym::Iterator); + if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator); if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind; then { let closure_body = cx.tcx.hir().body(body_id); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/map_unit_fn.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/map_unit_fn.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/map_unit_fn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/map_unit_fn.rs 2021-11-29 19:27:12.000000000 +0000 @@ -205,14 +205,13 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) { let var_arg = &map_args[0]; - let (map_type, variant, lint) = - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::option_type) { - ("Option", "Some", OPTION_MAP_UNIT_FN) - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::result_type) { - ("Result", "Ok", RESULT_MAP_UNIT_FN) - } else { - return; - }; + let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) { + ("Option", "Some", OPTION_MAP_UNIT_FN) + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Result) { + ("Result", "Ok", RESULT_MAP_UNIT_FN) + } else { + return; + }; let fn_arg = &map_args[1]; if is_unit_function(cx, fn_arg) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/matches.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/matches.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/matches.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/matches.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; -use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::visitors::is_local_used; use clippy_utils::{ get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, @@ -183,8 +183,8 @@ /// ```rust /// let x = 5; /// match x { - /// 1...10 => println!("1 ... 10"), - /// 5...15 => println!("5 ... 15"), + /// 1..=10 => println!("1 ... 10"), + /// 5..=15 => println!("5 ... 15"), /// _ => (), /// } /// ``` @@ -631,7 +631,7 @@ check_match_single_binding(cx, ex, arms, expr); } } - if let ExprKind::Match(ref ex, ref arms, _) = expr.kind { + if let ExprKind::Match(ex, arms, _) = expr.kind { check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr); } if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) { @@ -948,7 +948,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) { let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs(); - if is_type_diagnostic_item(cx, ex_ty, sym::result_type) { + if is_type_diagnostic_item(cx, ex_ty, sym::Result) { for arm in arms { if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind { let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); @@ -959,9 +959,7 @@ // Looking for unused bindings (i.e.: `_e`) for pat in inner.iter() { if let PatKind::Binding(_, id, ident, None) = pat.kind { - if ident.as_str().starts_with('_') - && !LocalUsedVisitor::new(cx, id).check_expr(arm.body) - { + if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) { ident_bind_name = (&ident.name.as_str()).to_string(); matching_wild = true; } @@ -1027,8 +1025,7 @@ let adt_def = match ty.kind() { ty::Adt(adt_def, _) if adt_def.is_enum() - && !(is_type_diagnostic_item(cx, ty, sym::option_type) - || is_type_diagnostic_item(cx, ty, sym::result_type)) => + && !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) => { adt_def }, @@ -1196,7 +1193,7 @@ let (first_sugg, msg, title); let span = ex.span.source_callsite(); - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = ex.kind { + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind { first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string())); msg = "try"; title = "you don't need to add `&` to both the expression and the patterns"; @@ -1207,7 +1204,7 @@ } let remaining_suggs = pats.filter_map(|pat| { - if let PatKind::Ref(ref refp, _) = pat.kind { + if let PatKind::Ref(refp, _) = pat.kind { Some((pat.span, snippet(cx, refp.span, "..").to_string())) } else { None @@ -1367,7 +1364,7 @@ find_bool_lit(&arm.2.kind, is_if_let).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty() }); then { - if let Some(ref last_pat) = last_pat_opt { + if let Some(last_pat) = last_pat_opt { if !is_wild(last_pat) { return false; } @@ -1829,13 +1826,13 @@ .. }) = higher::IfLet::hir(cx, expr) { - find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some()) + find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some()); } if let ExprKind::Match(op, arms, MatchSource::Normal) = &expr.kind { - find_sugg_for_match(cx, expr, op, arms) + find_sugg_for_match(cx, expr, op, arms); } if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { - find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false) + find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false); } } @@ -1871,7 +1868,7 @@ } } // Check for std types which implement drop, but only for memory allocation. - else if is_type_diagnostic_item(cx, ty, sym::vec_type) + else if is_type_diagnostic_item(cx, ty, sym::Vec) || is_type_lang_item(cx, ty, LangItem::OwnedBox) || is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs 2021-11-29 19:27:12.000000000 +0000 @@ -93,7 +93,7 @@ fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); let ty = ty.peel_refs(); - is_type_diagnostic_item(cx, ty, sym::vec_type) + is_type_diagnostic_item(cx, ty, sym::Vec) } fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/match_result_ok.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/match_result_ok.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/match_result_ok.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/match_result_ok.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,89 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher; +use clippy_utils::method_chain_args; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, PatKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for unnecessary `ok()` in `while let`. + /// + /// ### Why is this bad? + /// Calling `ok()` in `while let` is unnecessary, instead match + /// on `Ok(pat)` + /// + /// ### Example + /// ```ignore + /// while let Some(value) = iter.next().ok() { + /// vec.push(value) + /// } + /// + /// if let Some(valie) = iter.next().ok() { + /// vec.push(value) + /// } + /// ``` + /// Use instead: + /// ```ignore + /// while let Ok(value) = iter.next() { + /// vec.push(value) + /// } + /// + /// if let Ok(value) = iter.next() { + /// vec.push_value) + /// } + /// ``` + pub MATCH_RESULT_OK, + style, + "usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead" +} + +declare_lint_pass!(MatchResultOk => [MATCH_RESULT_OK]); + +impl<'tcx> LateLintPass<'tcx> for MatchResultOk { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (let_pat, let_expr, ifwhile) = + if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) { + (let_pat, let_expr, "if") + } else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { + (let_pat, let_expr, "while") + } else { + return; + }; + + if_chain! { + if let ExprKind::MethodCall(_, ok_span, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) + if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation + if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result); + if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some"; + + then { + + let mut applicability = Applicability::MachineApplicable; + let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); + let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_span), "", &mut applicability); + let sugg = format!( + "{} let Ok({}) = {}", + ifwhile, + some_expr_string, + trimmed_ok.trim().trim_end_matches('.'), + ); + span_lint_and_sugg( + cx, + MATCH_RESULT_OK, + expr.span.with_hi(let_expr.span.hi()), + "matching on `Some` with `ok()` is redundant", + &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + sugg, + applicability, + ); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_discriminant.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_discriminant.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_discriminant.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_discriminant.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; -use clippy_utils::ty::walk_ptrs_ty_depth; -use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls of `mem::discriminant()` on a non-enum type. - /// - /// ### Why is this bad? - /// The value of `mem::discriminant()` on non-enum types - /// is unspecified. - /// - /// ### Example - /// ```rust - /// use std::mem; - /// - /// mem::discriminant(&"hello"); - /// mem::discriminant(&&Some(2)); - /// ``` - pub MEM_DISCRIMINANT_NON_ENUM, - correctness, - "calling `mem::descriminant` on non-enum type" -} - -declare_lint_pass!(MemDiscriminant => [MEM_DISCRIMINANT_NON_ENUM]); - -impl<'tcx> LateLintPass<'tcx> for MemDiscriminant { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Call(func, func_args) = expr.kind; - // is `mem::discriminant` - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::MEM_DISCRIMINANT); - // type is non-enum - let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0); - if !ty_param.is_enum(); - - then { - span_lint_and_then( - cx, - MEM_DISCRIMINANT_NON_ENUM, - expr.span, - &format!("calling `mem::discriminant` on non-enum type `{}`", ty_param), - |diag| { - // if this is a reference to an enum, suggest dereferencing - let (base_ty, ptr_depth) = walk_ptrs_ty_depth(ty_param); - if ptr_depth >= 1 && base_ty.is_enum() { - let param = &func_args[0]; - - // cancel out '&'s first - let mut derefs_needed = ptr_depth; - let mut cur_expr = param; - while derefs_needed > 0 { - if let ExprKind::AddrOf(BorrowKind::Ref, _, inner_expr) = cur_expr.kind { - derefs_needed -= 1; - cur_expr = inner_expr; - } else { - break; - } - } - - let derefs = "*".repeat(derefs_needed); - diag.span_suggestion( - param.span, - "try dereferencing", - format!("{}{}", derefs, snippet(cx, cur_expr.span, "")), - Applicability::MachineApplicable, - ); - } - }, - ) - } - } - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_forget.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_forget.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_forget.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_forget.rs 2021-11-29 19:27:12.000000000 +0000 @@ -28,11 +28,11 @@ impl<'tcx> LateLintPass<'tcx> for MemForget { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Call(path_expr, args) = e.kind { + if let ExprKind::Call(path_expr, [ref first_arg, ..]) = e.kind { if let ExprKind::Path(ref qpath) = path_expr.kind { if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() { if match_def_path(cx, def_id, &paths::MEM_FORGET) { - let forgot_ty = cx.typeck_results().expr_ty(&args[0]); + let forgot_ty = cx.typeck_results().expr_ty(first_arg); if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) { span_lint(cx, MEM_FORGET, e.span, "usage of `mem::forget` on `Drop` type"); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_replace.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_replace.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_replace.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mem_replace.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths}; +use clippy_utils::ty::is_non_aggregate_primitive_type; +use clippy_utils::{in_macro, is_default_equivalent, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::def_id::DefId; use rustc_hir::LangItem::OptionNone; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -194,64 +194,37 @@ } } -/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent" -/// constructor from the std library -fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool { - let std_types_symbols = &[ - sym::string_type, - sym::vec_type, - sym::vecdeque_type, - sym::LinkedList, - sym::hashmap_type, - sym::BTreeMap, - sym::hashset_type, - sym::BTreeSet, - sym::BinaryHeap, - ]; - - if let QPath::TypeRelative(_, method) = path { - if method.ident.name == sym::new { - if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { - if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() { - return std_types_symbols - .iter() - .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did)); - } - } +fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { + // disable lint for primitives + let expr_type = cx.typeck_results().expr_ty_adjusted(src); + if is_non_aggregate_primitive_type(expr_type) { + return; + } + // disable lint for Option since it is covered in another lint + if let ExprKind::Path(q) = &src.kind { + if is_lang_ctor(cx, q, OptionNone) { + return; } } - false -} - -fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { - if_chain! { - if let ExprKind::Call(repl_func, _) = src.kind; - if !in_external_macro(cx.tcx.sess, expr_span); - if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; - if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - if is_diag_trait_item(cx, repl_def_id, sym::Default) - || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); - - then { - span_lint_and_then( - cx, - MEM_REPLACE_WITH_DEFAULT, - expr_span, - "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", - |diag| { - if !in_macro(expr_span) { - let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, "")); - - diag.span_suggestion( - expr_span, - "consider using", - suggestion, - Applicability::MachineApplicable - ); - } + if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { + span_lint_and_then( + cx, + MEM_REPLACE_WITH_DEFAULT, + expr_span, + "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", + |diag| { + if !in_macro(expr_span) { + let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, "")); + + diag.span_suggestion( + expr_span, + "consider using", + suggestion, + Applicability::MachineApplicable, + ); } - ); - } + }, + ); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs 2021-11-29 19:27:12.000000000 +0000 @@ -12,7 +12,7 @@ let ty = cx.typeck_results().expr_ty(recv).peel_refs(); let caller_type = if ty.is_str() { "str" - } else if is_type_diagnostic_item(cx, ty, sym::string_type) { + } else if is_type_diagnostic_item(cx, ty, sym::String) { "String" } else { return; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs 2021-11-29 19:27:12.000000000 +0000 @@ -15,7 +15,7 @@ let inner_ty = match recv_ty.kind() { // `Option` -> `T` ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => + if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => { subst.type_at(0) }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs 2021-11-29 19:27:12.000000000 +0000 @@ -85,7 +85,7 @@ if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) => { return; - } + }, ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) @@ -100,7 +100,7 @@ ) => { return; - } + }, _ => false, }; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs 2021-11-29 19:27:12.000000000 +0000 @@ -28,7 +28,7 @@ && { let arg_type = cx.typeck_results().expr_ty(&call_args[0]); let base_type = arg_type.peel_refs(); - *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::string_type) + *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String) } { &call_args[0] @@ -46,7 +46,7 @@ // converted to string. fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { let arg_ty = cx.typeck_results().expr_ty(arg); - if is_type_diagnostic_item(cx, arg_ty, sym::string_type) { + if is_type_diagnostic_item(cx, arg_ty, sym::String) { return false; } if let ty::Ref(_, ty, ..) = arg_ty.kind() { @@ -113,9 +113,9 @@ } let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]); - let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::option_type) { + let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) { "||" - } else if is_type_diagnostic_item(cx, receiver_type, sym::result_type) { + } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) { "|_|" } else { return; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/expect_used.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/expect_used.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/expect_used.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/expect_used.rs 2021-11-29 19:27:12.000000000 +0000 @@ -10,9 +10,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { Some((EXPECT_USED, "an Option", "None")) - } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { + } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { Some((EXPECT_USED, "a Result", "Err")) } else { None diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs 2021-11-29 19:27:12.000000000 +0000 @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); if_chain! { - if is_type_diagnostic_item(cx, ty, sym::vec_type); + if is_type_diagnostic_item(cx, ty, sym::Vec); //check source object if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind; if src_method.ident.as_str() == "drain"; @@ -20,7 +20,7 @@ //check if actual src type is mutable for code suggestion let immutable = src_ty.is_mutable_ptr(); let src_ty = src_ty.peel_refs(); - if is_type_diagnostic_item(cx, src_ty, sym::vec_type); + if is_type_diagnostic_item(cx, src_ty, sym::Vec); //check drain range if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs(); if is_type_lang_item(cx, src_ty_range, LangItem::RangeFull); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/filter_map.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/filter_map.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/filter_map.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/filter_map.rs 2021-11-29 19:27:12.000000000 +0000 @@ -61,7 +61,7 @@ methods_span: Span, ) { let iterator = is_trait_method(cx, expr, sym::Iterator); - let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::option_type); + let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::Option); if (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg) { let msg = "`filter` for `Some` followed by `unwrap`"; let help = "consider using `flatten` instead"; @@ -120,9 +120,9 @@ if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind; if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def(); - if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) { + if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did) { Some(false) - } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) { + } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did) { Some(true) } else { None diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/filter_next.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/filter_next.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/filter_next.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/filter_next.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet; +use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -16,7 +16,10 @@ filter_arg: &'tcx hir::Expr<'_>, ) { // lint if caller of `.filter().next()` is an Iterator - if is_trait_method(cx, expr, sym::Iterator) { + let recv_impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| { + implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[]) + }); + if recv_impls_iterator { let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find(..)` instead"; let filter_snippet = snippet(cx, filter_arg.span, ".."); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs 2021-11-29 19:27:12.000000000 +0000 @@ -19,7 +19,7 @@ _ if arg_ty.is_fn() => arg_ty.fn_sig(cx.tcx), _ => return, }; - if !is_type_diagnostic_item(cx, sig.output().skip_binder(), sym::option_type) { + if !is_type_diagnostic_item(cx, sig.output().skip_binder(), sym::Option) { return; } span_lint_and_sugg( diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs 2021-11-29 19:27:12.000000000 +0000 @@ -27,13 +27,13 @@ let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() { needs_ref = get_args_str.parse::().is_ok(); "slice" - } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) { + } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) { needs_ref = get_args_str.parse::().is_ok(); "Vec" - } else if is_type_diagnostic_item(cx, expr_ty, sym::vecdeque_type) { + } else if is_type_diagnostic_item(cx, expr_ty, sym::VecDeque) { needs_ref = get_args_str.parse::().is_ok(); "VecDeque" - } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::hashmap_type) { + } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::HashMap) { needs_ref = true; "HashMap" } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::BTreeMap) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs 2021-11-29 19:27:12.000000000 +0000 @@ -55,7 +55,7 @@ return true; } - if is_type_diagnostic_item(cx, ty, sym::string_type) { + if is_type_diagnostic_item(cx, ty, sym::String) { return true; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs 2021-11-29 19:27:12.000000000 +0000 @@ -11,7 +11,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { if_chain! { - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec); if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)); if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_count.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_count.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_count.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_count.rs 2021-11-29 19:27:12.000000000 +0000 @@ -13,13 +13,13 @@ let ty = cx.typeck_results().expr_ty(recv); let caller_type = if derefs_to_slice(cx, recv, ty).is_some() { "slice" - } else if is_type_diagnostic_item(cx, ty, sym::vec_type) { + } else if is_type_diagnostic_item(cx, ty, sym::Vec) { "Vec" - } else if is_type_diagnostic_item(cx, ty, sym::vecdeque_type) { + } else if is_type_diagnostic_item(cx, ty, sym::VecDeque) { "VecDeque" - } else if is_type_diagnostic_item(cx, ty, sym::hashset_type) { + } else if is_type_diagnostic_item(cx, ty, sym::HashSet) { "HashSet" - } else if is_type_diagnostic_item(cx, ty, sym::hashmap_type) { + } else if is_type_diagnostic_item(cx, ty, sym::HashMap) { "HashMap" } else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) { "BTreeMap" diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs 2021-11-29 19:27:12.000000000 +0000 @@ -64,6 +64,6 @@ } fn is_vec_or_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool { - is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type) + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) || matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _)) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs 2021-11-29 19:27:12.000000000 +0000 @@ -19,9 +19,9 @@ let mut_str = if is_mut { "_mut" } else { "" }; let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() { "slice" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::vec_type) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::Vec) { "Vec" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::vecdeque_type) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::VecDeque) { "VecDeque" } else { iter_nth_zero::check(cx, expr, nth_recv, nth_arg); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty::layout::LayoutOf; pub fn check( cx: &LateContext<'_>, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_split_once.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_split_once.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_split_once.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_split_once.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,211 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::{is_diag_item_method, match_def_path, paths}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, adjustment::Adjust}; +use rustc_span::{symbol::sym, Span, SyntaxContext}; + +use super::MANUAL_SPLIT_ONCE; + +pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { + if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { + return; + } + + let ctxt = expr.span.ctxt(); + let (method_name, msg, reverse) = if method_name == "splitn" { + ("split_once", "manual implementation of `split_once`", false) + } else { + ("rsplit_once", "manual implementation of `rsplit_once`", true) + }; + let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), reverse) { + Some(x) => x, + None => return, + }; + + let mut app = Applicability::MachineApplicable; + let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; + let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; + + let sugg = match usage.kind { + IterUsageKind::NextTuple => { + format!("{}.{}({})", self_snip, method_name, pat_snip) + }, + IterUsageKind::RNextTuple => format!("{}.{}({}).map(|(x, y)| (y, x))", self_snip, method_name, pat_snip), + IterUsageKind::Next => { + let self_deref = { + let adjust = cx.typeck_results().expr_adjustments(self_arg); + if adjust.is_empty() { + String::new() + } else if cx.typeck_results().expr_ty(self_arg).is_box() + || adjust + .iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(_))) || a.target.is_box()) + { + format!("&{}", "*".repeat(adjust.len() - 1)) + } else { + "*".repeat(adjust.len() - 2) + } + }; + if usage.unwrap_kind.is_some() { + format!( + "{}.{}({}).map_or({}{}, |x| x.0)", + &self_snip, method_name, pat_snip, self_deref, &self_snip + ) + } else { + format!( + "Some({}.{}({}).map_or({}{}, |x| x.0))", + &self_snip, method_name, pat_snip, self_deref, &self_snip + ) + } + }, + IterUsageKind::Second => { + let access_str = match usage.unwrap_kind { + Some(UnwrapKind::Unwrap) => ".unwrap().1", + Some(UnwrapKind::QuestionMark) => "?.1", + None => ".map(|x| x.1)", + }; + format!("{}.{}({}){}", self_snip, method_name, pat_snip, access_str) + }, + }; + + span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); +} + +enum IterUsageKind { + Next, + Second, + NextTuple, + RNextTuple, +} + +enum UnwrapKind { + Unwrap, + QuestionMark, +} + +struct IterUsage { + kind: IterUsageKind, + unwrap_kind: Option, + span: Span, +} + +#[allow(clippy::too_many_lines)] +fn parse_iter_usage( + cx: &LateContext<'tcx>, + ctxt: SyntaxContext, + mut iter: impl Iterator)>, + reverse: bool, +) -> Option { + let (kind, span) = match iter.next() { + Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { + let (name, args) = if let ExprKind::MethodCall(name, _, [_, args @ ..], _) = e.kind { + (name, args) + } else { + return None; + }; + let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; + let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; + + match (&*name.ident.as_str(), args) { + ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + if reverse { + (IterUsageKind::Second, e.span) + } else { + (IterUsageKind::Next, e.span) + } + }, + ("next_tuple", []) => { + return if_chain! { + if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE); + if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind(); + if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did); + if let ty::Tuple(subs) = subs.type_at(0).kind(); + if subs.len() == 2; + then { + Some(IterUsage { + kind: if reverse { IterUsageKind::RNextTuple } else { IterUsageKind::NextTuple }, + span: e.span, + unwrap_kind: None + }) + } else { + None + } + }; + }, + ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { + let span = if name.ident.as_str() == "nth" { + e.span + } else { + if_chain! { + if let Some((_, Node::Expr(next_expr))) = iter.next(); + if let ExprKind::MethodCall(next_name, _, [_], _) = next_expr.kind; + if next_name.ident.name == sym::next; + if next_expr.span.ctxt() == ctxt; + if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id); + if cx.tcx.trait_of_item(next_id) == Some(iter_id); + then { + next_expr.span + } else { + return None; + } + } + }; + match if reverse { idx ^ 1 } else { idx } { + 0 => (IterUsageKind::Next, span), + 1 => (IterUsageKind::Second, span), + _ => return None, + } + } else { + return None; + } + }, + _ => return None, + } + }, + _ => return None, + }; + + let (unwrap_kind, span) = if let Some((_, Node::Expr(e))) = iter.next() { + match e.kind { + ExprKind::Call( + Expr { + kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)), + .. + }, + _, + ) => { + let parent_span = e.span.parent_callsite().unwrap(); + if parent_span.ctxt() == ctxt { + (Some(UnwrapKind::QuestionMark), parent_span) + } else { + (None, span) + } + }, + _ if e.span.ctxt() != ctxt => (None, span), + ExprKind::MethodCall(name, _, [_], _) + if name.ident.name == sym::unwrap + && cx + .typeck_results() + .type_dependent_def_id(e.hir_id) + .map_or(false, |id| is_diag_item_method(cx, id, sym::Option)) => + { + (Some(UnwrapKind::Unwrap), e.span) + }, + _ => (None, span), + } + } else { + (None, span) + }; + + Some(IterUsage { + kind, + unwrap_kind, + span, + }) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs 2021-11-29 19:27:12.000000000 +0000 @@ -36,14 +36,14 @@ } } else { let ty = cx.typeck_results().expr_ty(e); - if is_type_diagnostic_item(cx, ty, sym::string_type) + if is_type_diagnostic_item(cx, ty, sym::String) || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str)) || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str)) { Some(RepeatKind::String) } else { let ty = ty.peel_refs(); - (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::String) + (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)).then(|| RepeatKind::String) } } } @@ -58,7 +58,7 @@ if_chain! { if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind; if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT); - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::string_type); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String); if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id); if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id); if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs 2021-11-29 19:27:12.000000000 +0000 @@ -23,7 +23,7 @@ if is_trait_method(cx, collect_recv, sym::Iterator); // return of collect `Result<(),_>` let collect_ret_ty = cx.typeck_results().expr_ty(expr); - if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type); + if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result); if let ty::Adt(_, substs) = collect_ret_ty.kind(); if let Some(result_t) = substs.types().next(); if result_t.is_unit(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs 2021-11-29 19:27:12.000000000 +0000 @@ -27,7 +27,7 @@ _ => map_closure_ty.fn_sig(cx.tcx), }; let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output()); - is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type) + is_type_diagnostic_item(cx, map_closure_return_ty, sym::Option) }, _ => false, }; @@ -55,9 +55,9 @@ // lint if caller of `.map().flatten()` is an Option or Result let caller_type = match cx.typeck_results().expr_ty(recv).kind() { ty::Adt(adt, _) => { - if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) { + if cx.tcx.is_diagnostic_item(sym::Option, adt.did) { "Option" - } else if cx.tcx.is_diagnostic_item(sym::result_type, adt.did) { + } else if cx.tcx.is_diagnostic_item(sym::Result, adt.did) { "Result" } else { return; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_identity.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_identity.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_identity.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_identity.rs 2021-11-29 19:27:12.000000000 +0000 @@ -19,8 +19,8 @@ if_chain! { if is_trait_method(cx, expr, sym::Iterator) - || is_type_diagnostic_item(cx, caller_ty, sym::result_type) - || is_type_diagnostic_item(cx, caller_ty, sym::option_type); + || is_type_diagnostic_item(cx, caller_ty, sym::Result) + || is_type_diagnostic_item(cx, caller_ty, sym::Option); if is_expr_identity_function(cx, map_arg); if let Some(sugg_span) = expr.span.trim_start(caller.span); then { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs 2021-11-29 19:27:12.000000000 +0000 @@ -22,8 +22,8 @@ msrv: Option<&RustcVersion>, ) -> bool { // lint if the caller of `map()` is an `Option` - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); if is_result && !meets_msrv(msrv, &msrvs::RESULT_MAP_OR_ELSE) { return false; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/mod.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -33,6 +33,7 @@ mod iter_skip_next; mod iterator_step_by_zero; mod manual_saturating_arithmetic; +mod manual_split_once; mod manual_str_repeat; mod map_collect_result_unit; mod map_flatten; @@ -64,6 +65,7 @@ mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; @@ -262,6 +264,8 @@ /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait /// (see e.g. the `std::string::ToString` trait). /// + /// Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required. + /// /// Please find more info here: /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv /// @@ -993,7 +997,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for use of `.iter().nth()` (and the related - /// `.iter_mut().nth()`) on standard library types with O(1) element access. + /// `.iter_mut().nth()`) on standard library types with *O*(1) element access. /// /// ### Why is this bad? /// `.get()` and `.get_mut()` are more efficient and more @@ -1280,8 +1284,9 @@ /// /// ### Why is this bad? /// It looks suspicious. Maybe `map` was confused with `filter`. - /// If the `map` call is intentional, this should be rewritten. Or, if you intend to - /// drive the iterator to completion, you can just use `for_each` instead. + /// If the `map` call is intentional, this should be rewritten + /// using `inspect`. Or, if you intend to drive the iterator to + /// completion, you can just use `for_each` instead. /// /// ### Example /// ```rust @@ -1771,6 +1776,29 @@ "manual implementation of `str::repeat`" } +declare_clippy_lint! { + /// **What it does:** Checks for usages of `str::splitn(2, _)` + /// + /// **Why is this bad?** `split_once` is both clearer in intent and slightly more efficient. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,ignore + /// // Bad + /// let (key, value) = _.splitn(2, '=').next_tuple()?; + /// let value = _.splitn(2, '=').nth(1)?; + /// + /// // Good + /// let (key, value) = _.split_once('=')?; + /// let value = _.split_once('=')?.1; + /// ``` + pub MANUAL_SPLIT_ONCE, + complexity, + "replace `.splitn(2, pat)` with `.split_once(pat)`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -1848,7 +1876,8 @@ IMPLICIT_CLONE, SUSPICIOUS_SPLITN, MANUAL_STR_REPEAT, - EXTEND_WITH_DRAIN + EXTEND_WITH_DRAIN, + MANUAL_SPLIT_ONCE ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2035,7 +2064,7 @@ then { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); - let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); + let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder(); wrong_self_convention::check( cx, &item.ident.name.as_str(), @@ -2052,7 +2081,7 @@ if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id()); - let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); + let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder(); if !contains_ty(cx.tcx, ret_ty, self_ty); then { @@ -2176,8 +2205,18 @@ unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, - ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => { - suspicious_splitn::check(cx, name, expr, recv, count_arg); + ("splitn" | "rsplitn", [count_arg, pat_arg]) => { + if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + suspicious_splitn::check(cx, name, expr, recv, count); + if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) { + manual_split_once::check(cx, name, expr, recv, pat_arg); + } + } + }, + ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { + if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + suspicious_splitn::check(cx, name, expr, recv, count); + } }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs 2021-11-29 19:27:12.000000000 +0000 @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if_chain! { // lint if the caller of `ok()` is a `Result` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let result_type = cx.typeck_results().expr_ty(recv); if let Some(error_type) = get_error_type(cx, result_type); if has_debug_impl(error_type, cx); @@ -33,7 +33,7 @@ /// Given a `Result` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { match ty.kind() { - ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::result_type) => substs.types().nth(1), + ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::Result) => substs.types().nth(1), _ => None, } } @@ -41,6 +41,6 @@ /// This checks whether a given type is known to implement Debug. fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { cx.tcx - .get_diagnostic_item(sym::debug_trait) + .get_diagnostic_item(sym::Debug) .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs 2021-11-29 19:27:12.000000000 +0000 @@ -28,7 +28,7 @@ let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); let option_ty = cx.typeck_results().expr_ty(as_ref_recv); - if !is_type_diagnostic_item(cx, option_ty, sym::option_type) { + if !is_type_diagnostic_item(cx, option_ty, sym::Option) { return; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs 2021-11-29 19:27:12.000000000 +0000 @@ -19,8 +19,8 @@ def_arg: &'tcx hir::Expr<'_>, map_arg: &'tcx hir::Expr<'_>, ) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); // There are two variants of this `map_or` lint: // (1) using `map_or` as an adapter from `Result` to `Option` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs 2021-11-29 19:27:12.000000000 +0000 @@ -25,7 +25,7 @@ map_span: Span, ) { // lint if the caller of `map()` is an `Option` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) { if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { // Do not lint if the `map` argument uses identifiers in the `map` // argument that are also used in the `unwrap_or` argument diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs 2021-11-29 19:27:12.000000000 +0000 @@ -96,16 +96,16 @@ (&paths::RESULT, true, &["or", "unwrap_or"], "else"), ]; - if let hir::ExprKind::MethodCall(path, _, args, _) = &arg.kind { + if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &arg.kind { if path.ident.name == sym::len { - let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); + let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); match ty.kind() { ty::Slice(_) | ty::Array(_, _) | ty::Str => return, _ => (), } - if is_type_diagnostic_item(cx, ty, sym::vec_type) { + if is_type_diagnostic_item(cx, ty, sym::Vec) { return; } } @@ -178,12 +178,12 @@ hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); }, - hir::ExprKind::Block(block, _) => { - if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules { - if let Some(block_expr) = block.expr { - if let hir::ExprKind::MethodCall(..) = block_expr.kind { - check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); - } + hir::ExprKind::Block(block, _) + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => + { + if let Some(block_expr) = block.expr { + if let hir::ExprKind::MethodCall(..) = block_expr.kind { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); } } }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs 2021-11-29 19:27:12.000000000 +0000 @@ -101,7 +101,7 @@ else if search_method == "find" { let is_string_or_str_slice = |e| { let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); - if is_type_diagnostic_item(cx, self_ty, sym::string_type) { + if is_type_diagnostic_item(cx, self_ty, sym::String) { true } else { *self_ty.kind() == ty::Str diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs 2021-11-29 19:27:12.000000000 +0000 @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if !is_type_diagnostic_item(cx, obj_ty, sym::string_type) { + if !is_type_diagnostic_item(cx, obj_ty, sym::String) { return; } if let Some(arglists) = method_chain_args(arg, &["chars"]) { @@ -20,7 +20,7 @@ let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { "" - } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { + } else if is_type_diagnostic_item(cx, self_ty, sym::String) { "&" } else { return; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs 2021-11-29 19:27:12.000000000 +0000 @@ -28,7 +28,7 @@ expr.span, "this call to `map()` won't have an effect on the call to `count()`", None, - "make sure you did not confuse `map` with `filter` or `for_each`", + "make sure you did not confuse `map` with `filter`, `for_each` or `inspect`", ); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,3 @@ -use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_note; use if_chain::if_chain; use rustc_ast::LitKind; @@ -8,15 +7,8 @@ use super::SUSPICIOUS_SPLITN; -pub(super) fn check( - cx: &LateContext<'_>, - method_name: &str, - expr: &Expr<'_>, - self_arg: &Expr<'_>, - count_arg: &Expr<'_>, -) { +pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) { if_chain! { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg); if count <= 1; if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(call_id); @@ -24,9 +16,9 @@ if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id); then { // Ignore empty slice and string literals when used with a literal count. - if (matches!(self_arg.kind, ExprKind::Array([])) + if matches!(self_arg.kind, ExprKind::Array([])) || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()) - ) && matches!(count_arg.kind, ExprKind::Lit(_)) + { return; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs 2021-11-29 19:27:12.000000000 +0000 @@ -35,8 +35,7 @@ let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); match cx.typeck_results().expr_ty(&body.value).kind() { ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) - && TyS::same_type(in_ty, subst.type_at(0)) => + if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && TyS::same_type(in_ty, subst.type_at(0)) => { "filter" }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs 2021-11-29 19:27:12.000000000 +0000 @@ -18,8 +18,8 @@ arg: &'tcx hir::Expr<'_>, simplify_using: &str, ) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); if is_option || is_result { if let hir::ExprKind::Closure(_, _, eid, _, _) = arg.kind { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs 2021-11-29 19:27:12.000000000 +0000 @@ -19,8 +19,8 @@ // ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr let recv_ty = cx.typeck_results().expr_ty(recv); - let is_option = is_type_diagnostic_item(cx, recv_ty, sym::option_type); - let is_result = is_type_diagnostic_item(cx, recv_ty, sym::result_type); + let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option); + let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result); if_chain! { if is_option || is_result; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs 2021-11-29 19:27:12.000000000 +0000 @@ -10,9 +10,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { Some((UNWRAP_USED, "an Option", "None")) - } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { + } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { Some((UNWRAP_USED, "a Result", "Err")) } else { None diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/utils.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/utils.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/utils.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/methods/utils.rs 2021-11-29 19:27:12.000000000 +0000 @@ -17,16 +17,16 @@ match ty.kind() { ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), - ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), + ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec), ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(), ty::Ref(_, inner, _) => may_slice(cx, inner), _ => false, } } - if let hir::ExprKind::MethodCall(path, _, args, _) = expr.kind { - if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { - Some(&args[0]) + if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind { + if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) { + Some(self_arg) } else { None } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/misc.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/misc.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/misc.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/misc.rs 2021-11-29 19:27:12.000000000 +0000 @@ -113,7 +113,7 @@ /// if (y - x).abs() > error_margin { } /// ``` pub FLOAT_CMP, - correctness, + pedantic, "using `==` or `!=` on float values instead of comparing difference with an epsilon" } @@ -513,12 +513,12 @@ } if_chain! { - if let ExprKind::MethodCall(method_name, _, expressions, _) = expr.kind; + if let ExprKind::MethodCall(method_name, _, [ref self_arg, ..], _) = expr.kind; if sym!(signum) == method_name.ident.name; // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) then { - return is_float(cx, &expressions[0]); + return is_float(cx, self_arg); } } false diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/missing_doc.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/missing_doc.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/missing_doc.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/missing_doc.rs 2021-11-29 19:27:12.000000000 +0000 @@ -12,6 +12,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Span; use rustc_span::sym; @@ -78,9 +79,7 @@ return; } - let has_doc = attrs - .iter() - .any(|a| a.doc_str().is_some()); + let has_doc = attrs.iter().any(|a| a.doc_str().is_some()); if !has_doc { span_lint( cx, @@ -104,9 +103,9 @@ self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); - self.check_missing_docs_attrs(cx, attrs, krate.module().inner, "the", "crate"); + self.check_missing_docs_attrs(cx, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate"); } fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; -use rustc_hir::{def::Res, def_id::DefId, Crate, Item, ItemKind, UseKind}; +use rustc_hir::{def::Res, def_id::DefId, Item, ItemKind, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; @@ -55,7 +55,7 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]); impl LateLintPass<'_> for ImportRename { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'_>) { for Rename { path, rename } in &self.conf_renames { if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &path.split("::").collect::>()) { self.renames.insert(id, Symbol::intern(rename)); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/module_style.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/module_style.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/module_style.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/module_style.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,178 @@ +use std::{ + ffi::OsString, + path::{Component, Path}, +}; + +use rustc_ast::ast; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{FileName, RealFileName, SourceFile, Span, SyntaxContext}; + +declare_clippy_lint! { + /// ### What it does + /// Checks that module layout uses only self named module files, bans mod.rs files. + /// + /// ### Why is this bad? + /// Having multiple module layout styles in a project can be confusing. + /// + /// ### Example + /// ```text + /// src/ + /// stuff/ + /// stuff_files.rs + /// mod.rs + /// lib.rs + /// ``` + /// Use instead: + /// ```text + /// src/ + /// stuff/ + /// stuff_files.rs + /// stuff.rs + /// lib.rs + /// ``` + pub MOD_MODULE_FILES, + restriction, + "checks that module layout is consistent" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks that module layout uses only mod.rs files. + /// + /// ### Why is this bad? + /// Having multiple module layout styles in a project can be confusing. + /// + /// ### Example + /// ```text + /// src/ + /// stuff/ + /// stuff_files.rs + /// stuff.rs + /// lib.rs + /// ``` + /// Use instead: + /// ```text + /// src/ + /// stuff/ + /// stuff_files.rs + /// mod.rs + /// lib.rs + /// ``` + + pub SELF_NAMED_MODULE_FILES, + restriction, + "checks that module layout is consistent" +} + +pub struct ModStyle; + +impl_lint_pass!(ModStyle => [MOD_MODULE_FILES, SELF_NAMED_MODULE_FILES]); + +impl EarlyLintPass for ModStyle { + fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { + if cx.builder.lint_level(MOD_MODULE_FILES).0 == Level::Allow + && cx.builder.lint_level(SELF_NAMED_MODULE_FILES).0 == Level::Allow + { + return; + } + + let files = cx.sess.source_map().files(); + + let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess.opts.working_dir { + p.to_string_lossy() + } else { + return; + }; + + // `folder_segments` is all unique folder path segments `path/to/foo.rs` gives + // `[path, to]` but not foo + let mut folder_segments = FxHashSet::default(); + // `mod_folders` is all the unique folder names that contain a mod.rs file + let mut mod_folders = FxHashSet::default(); + // `file_map` maps file names to the full path including the file name + // `{ foo => path/to/foo.rs, .. } + let mut file_map = FxHashMap::default(); + for file in files.iter() { + match &file.name { + FileName::Real(RealFileName::LocalPath(lp)) + if lp.to_string_lossy().starts_with(trim_to_src.as_ref()) => + { + let p = lp.to_string_lossy(); + let path = Path::new(p.trim_start_matches(trim_to_src.as_ref())); + if let Some(stem) = path.file_stem() { + file_map.insert(stem.to_os_string(), (file, path.to_owned())); + } + process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders); + check_self_named_mod_exists(cx, path, file); + }, + _ => {}, + } + } + + for folder in &folder_segments { + if !mod_folders.contains(folder) { + if let Some((file, path)) = file_map.get(folder) { + let mut correct = path.clone(); + correct.pop(); + correct.push(folder); + correct.push("mod.rs"); + cx.struct_span_lint( + SELF_NAMED_MODULE_FILES, + Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), + |build| { + let mut lint = + build.build(&format!("`mod.rs` files are required, found `{}`", path.display())); + lint.help(&format!("move `{}` to `{}`", path.display(), correct.display(),)); + lint.emit(); + }, + ); + } + } + } + } +} + +/// For each `path` we add each folder component to `folder_segments` and if the file name +/// is `mod.rs` we add it's parent folder to `mod_folders`. +fn process_paths_for_mod_files( + path: &Path, + folder_segments: &mut FxHashSet, + mod_folders: &mut FxHashSet, +) { + let mut comp = path.components().rev().peekable(); + let _ = comp.next(); + if path.ends_with("mod.rs") { + mod_folders.insert(comp.peek().map(|c| c.as_os_str().to_owned()).unwrap_or_default()); + } + let folders = comp + .filter_map(|c| { + if let Component::Normal(s) = c { + Some(s.to_os_string()) + } else { + None + } + }) + .collect::>(); + folder_segments.extend(folders); +} + +/// Checks every path for the presence of `mod.rs` files and emits the lint if found. +fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &SourceFile) { + if path.ends_with("mod.rs") { + let mut mod_file = path.to_path_buf(); + mod_file.pop(); + mod_file.set_extension("rs"); + + cx.struct_span_lint( + MOD_MODULE_FILES, + Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), + |build| { + let mut lint = build.build(&format!("`mod.rs` files are not allowed, found `{}`", path.display())); + lint.help(&format!("move `{}` to `{}`", path.display(), mod_file.display(),)); + lint.emit(); + }, + ); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs 2021-11-29 19:27:12.000000000 +0000 @@ -128,7 +128,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { match &expr.kind { ExprKind::Binary(op, lhs, rhs) | ExprKind::AssignOp(op, lhs, rhs) => { - if let BinOpKind::Rem = op.node { + if op.node == BinOpKind::Rem { let lhs_operand = analyze_operand(lhs, cx, expr); let rhs_operand = analyze_operand(rhs, cx, expr); if_chain! { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::{Crate, CRATE_HIR_ID}; +use rustc_hir::CRATE_HIR_ID; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::DUMMY_SP; @@ -41,7 +41,7 @@ declare_lint_pass!(MultipleCrateVersions => [MULTIPLE_CRATE_VERSIONS]); impl LateLintPass<'_> for MultipleCrateVersions { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'_>) { if is_lint_allowed(cx, MULTIPLE_CRATE_VERSIONS, CRATE_HIR_ID) { return; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mutex_atomic.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mutex_atomic.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mutex_atomic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mutex_atomic.rs 2021-11-29 19:27:12.000000000 +0000 @@ -8,6 +8,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -74,7 +75,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(_, subst) = ty.kind() { - if is_type_diagnostic_item(cx, ty, sym!(mutex_type)) { + if is_type_diagnostic_item(cx, ty, sym::Mutex) { let mutex_param = subst.type_at(0); if let Some(atomic_name) = get_atomic_name(mutex_param) { let msg = format!( diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mut_key.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mut_key.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mut_key.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mut_key.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TypeFoldable; -use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; +use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::sym; @@ -19,10 +19,29 @@ /// so having types with interior mutability is a bad idea. /// /// ### Known problems - /// It's correct to use a struct, that contains interior mutability - /// as a key, when its `Hash` implementation doesn't access any of the interior mutable types. - /// However, this lint is unable to recognize this, so it causes a false positive in theses cases. - /// The `bytes` crate is a great example of this. + /// + /// #### False Positives + /// It's correct to use a struct that contains interior mutability as a key, when its + /// implementation of `Hash` or `Ord` doesn't access any of the interior mutable types. + /// However, this lint is unable to recognize this, so it will often cause false positives in + /// theses cases. The `bytes` crate is a great example of this. + /// + /// #### False Negatives + /// For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind + /// indirection. For example, `struct BadKey<'a>(&'a Cell)` will be seen as immutable + /// and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`. + /// + /// This lint does check a few cases for indirection. Firstly, using some standard library + /// types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and + /// `BTreeSet`) directly as keys (e.g. in `HashMap>, ()>`) **will** trigger the + /// lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their + /// contained type. + /// + /// Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`) + /// apply only to the **address** of the contained value. Therefore, interior mutability + /// behind raw pointers (e.g. in `HashSet<*mut Cell>`) can't impact the value of `Hash` + /// or `Ord`, and therefore will not trigger this link. For more info, see issue + /// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745). /// /// ### Example /// ```rust @@ -103,30 +122,52 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { let ty = ty.peel_refs(); if let Adt(def, substs) = ty.kind() { - if [sym::hashmap_type, sym::BTreeMap, sym::hashset_type, sym::BTreeMap] + let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did)) - && is_mutable_type(cx, substs.type_at(0), span) - { + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did)); + if is_keyed_type && is_interior_mutable_type(cx, substs.type_at(0), span) { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); } } } -fn is_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool { +/// Determines if a type contains interior mutability which would affect its implementation of +/// [`Hash`] or [`Ord`]. +fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool { match *ty.kind() { - RawPtr(TypeAndMut { ty: inner_ty, mutbl }) | Ref(_, inner_ty, mutbl) => { - mutbl == hir::Mutability::Mut || is_mutable_type(cx, inner_ty, span) - }, - Slice(inner_ty) => is_mutable_type(cx, inner_ty, span), + Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span), + Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span), Array(inner_ty, size) => { - size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && is_mutable_type(cx, inner_ty, span) + size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) + && is_interior_mutable_type(cx, inner_ty, span) }, - Tuple(..) => ty.tuple_fields().any(|ty| is_mutable_type(cx, ty, span)), - Adt(..) => { - !ty.has_escaping_bound_vars() - && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() - && !ty.is_freeze(cx.tcx.at(span), cx.param_env) + Tuple(..) => ty.tuple_fields().any(|ty| is_interior_mutable_type(cx, ty, span)), + Adt(def, substs) => { + // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to + // that of their type parameters. Note: we don't include `HashSet` and `HashMap` + // because they have no impl for `Hash` or `Ord`. + let is_std_collection = [ + sym::Option, + sym::Result, + sym::LinkedList, + sym::Vec, + sym::VecDeque, + sym::BTreeMap, + sym::BTreeSet, + sym::Rc, + sym::Arc, + ] + .iter() + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did)); + let is_box = Some(def.did) == cx.tcx.lang_items().owned_box(); + if is_std_collection || is_box { + // The type is mutable if any of its type parameters are + substs.types().any(|ty| is_interior_mutable_type(cx, ty, span)) + } else { + !ty.has_escaping_bound_vars() + && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() + && !ty.is_freeze(cx.tcx.at(span), cx.param_env) + } }, _ => false, } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -47,11 +48,11 @@ impl<'tcx> LateLintPass<'tcx> for MutMutexLock { fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) { if_chain! { - if let ExprKind::MethodCall(path, method_span, args, _) = &ex.kind; + if let ExprKind::MethodCall(path, method_span, [self_arg, ..], _) = &ex.kind; if path.ident.name == sym!(lock); - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind(); - if is_type_diagnostic_item(cx, inner_ty, sym!(mutex_type)); + if is_type_diagnostic_item(cx, inner_ty, sym::Mutex); then { span_lint_and_sugg( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_bool.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_bool.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_bool.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_bool.rs 2021-11-29 19:27:12.000000000 +0000 @@ -248,7 +248,7 @@ if l_ty.is_bool() && r_ty.is_bool() { let mut applicability = Applicability::MachineApplicable; - if let BinOpKind::Eq = op.node { + if op.node == BinOpKind::Eq { let expression_info = one_side_is_unary_not(left_side, right_side); if expression_info.one_side_is_unary_not { span_lint_and_sugg( diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_borrow.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_borrow.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_borrow.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_borrow.rs 2021-11-29 19:27:12.000000000 +0000 @@ -104,26 +104,36 @@ if e.span.from_expansion() { return; } - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind { + if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() { for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) { - if let [Adjustment { - kind: Adjust::Deref(_), .. - }, Adjustment { - kind: Adjust::Deref(_), .. - }, Adjustment { - kind: Adjust::Borrow(_), - .. - }] = *adj3 + if let [ + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Borrow(_), + .. + }, + ] = *adj3 { + let help_msg_ty = if matches!(mutability, Mutability::Not) { + format!("&{}", ty) + } else { + format!("&mut {}", ty) + }; + span_lint_and_then( cx, NEEDLESS_BORROW, e.span, &format!( - "this expression borrows a reference (`&{}`) that is immediately dereferenced \ + "this expression borrows a reference (`{}`) that is immediately dereferenced \ by the compiler", - ty + help_msg_ty ), |diag| { if let Some(snippet) = snippet_opt(cx, inner.span) { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_continue.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_continue.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_continue.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_continue.rs 2021-11-29 19:27:12.000000000 +0000 @@ -36,9 +36,8 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::Span; declare_clippy_lint! { @@ -270,7 +269,7 @@ /// The 0-based index of the `if` statement in the containing loop block. stmt_idx: usize, /// The statements of the loop block. - block_stmts: &'a [ast::Stmt], + loop_block: &'a ast::Block, } const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant"; @@ -343,10 +342,10 @@ let indent = span_of_first_expr_in_block(data.if_block) .and_then(|span| indent_of(cx, span)) .unwrap_or(0); - let to_annex = data.block_stmts[data.stmt_idx + 1..] + let to_annex = data.loop_block.stmts[data.stmt_idx + 1..] .iter() - .map(|stmt| original_sp(stmt.span, DUMMY_SP)) - .map(|span| { + .map(|stmt| { + let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span); let snip = snippet_block(cx, span, "..", None).into_owned(); snip.lines() .map(|line| format!("{}{}", " ".repeat(indent), line)) @@ -393,7 +392,7 @@ if_cond: cond, if_block: then_block, else_expr, - block_stmts: &loop_block.stmts, + loop_block, }; if needless_continue_in_else(else_expr, label) { emit_warning( diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,66 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyS; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for no-op uses of Option::{as_deref,as_deref_mut}, + /// for example, `Option<&T>::as_deref()` returns the same type. + /// + /// ### Why is this bad? + /// Redundant code and improving readability. + /// + /// ### Example + /// ```rust + /// let a = Some(&1); + /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> + /// ``` + /// Could be written as: + /// ```rust + /// let a = Some(&1); + /// let b = a; + /// ``` + pub NEEDLESS_OPTION_AS_DEREF, + complexity, + "no-op use of `deref` or `deref_mut` method to `Option`." +} + +declare_lint_pass!(OptionNeedlessDeref=> [ + NEEDLESS_OPTION_AS_DEREF, +]); + +impl<'tcx> LateLintPass<'tcx> for OptionNeedlessDeref { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if expr.span.from_expansion() || in_macro(expr.span) { + return; + } + let typeck = cx.typeck_results(); + let outer_ty = typeck.expr_ty(expr); + + if_chain! { + if is_type_diagnostic_item(cx,outer_ty,sym::Option); + if let ExprKind::MethodCall(path, _, [sub_expr], _) = expr.kind; + let symbol = path.ident.as_str(); + if symbol=="as_deref" || symbol=="as_deref_mut"; + if TyS::same_type( outer_ty, typeck.expr_ty(sub_expr) ); + then{ + span_lint_and_sugg( + cx, + NEEDLESS_OPTION_AS_DEREF, + expr.span, + "derefed type is same as origin", + "try this", + snippet_opt(cx,sub_expr.span).unwrap(), + Applicability::MachineApplicable + ); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs 2021-11-29 19:27:12.000000000 +0000 @@ -206,7 +206,7 @@ let deref_span = spans_need_deref.get(&canonical_id); if_chain! { - if is_type_diagnostic_item(cx, ty, sym::vec_type); + if is_type_diagnostic_item(cx, ty, sym::Vec); if let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]); if let TyKind::Path(QPath::Resolved(_, path)) = input.kind; @@ -245,7 +245,7 @@ } } - if is_type_diagnostic_item(cx, ty, sym::string_type) { + if is_type_diagnostic_item(cx, ty, sym::String) { if let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) { diag.span_suggestion( diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/neg_multiply.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/neg_multiply.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/neg_multiply.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/neg_multiply.rs 2021-11-29 19:27:12.000000000 +0000 @@ -46,7 +46,7 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { if_chain! { if let ExprKind::Lit(ref l) = lit.kind; - if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)); + if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1); if cx.typeck_results().expr_ty(exp).is_integral(); then { span_lint(cx, NEG_MULTIPLY, span, "negation by multiplying with `-1`"); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/new_without_default.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/new_without_default.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/new_without_default.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/new_without_default.rs 2021-11-29 19:27:12.000000000 +0000 @@ -69,7 +69,7 @@ }) = item.kind { for assoc_item in items { - if let hir::AssocItemKind::Fn { has_self: false } = assoc_item.kind { + if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) { let impl_item = cx.tcx.hir().impl_item(assoc_item.id); if in_external_macro(cx.sess(), impl_item.span) { return; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/no_effect.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/no_effect.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/no_effect.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/no_effect.rs 2021-11-29 19:27:12.000000000 +0000 @@ -96,28 +96,63 @@ if has_no_effect(cx, expr) { span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect"); } else if let Some(reduced) = reduce_expression(cx, expr) { - let mut snippet = String::new(); - for e in reduced { + for e in &reduced { if e.span.from_expansion() { return; } - if let Some(snip) = snippet_opt(cx, e.span) { - snippet.push_str(&snip); - snippet.push(';'); - } else { - return; + } + if let ExprKind::Index(..) = &expr.kind { + let snippet; + if_chain! { + if let Some(arr) = snippet_opt(cx, reduced[0].span); + if let Some(func) = snippet_opt(cx, reduced[1].span); + then { + snippet = format!("assert!({}.len() > {});", &arr, &func); + } else { + return; + } + } + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be written as", + snippet, + Applicability::MaybeIncorrect, + ); + }, + ); + } else { + let mut snippet = String::new(); + for e in reduced { + if let Some(snip) = snippet_opt(cx, e.span) { + snippet.push_str(&snip); + snippet.push(';'); + } else { + return; + } } + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be reduced to", + snippet, + Applicability::MachineApplicable, + ); + }, + ); } - span_lint_hir_and_then( - cx, - UNNECESSARY_OPERATION, - expr.hir_id, - stmt.span, - "statement can be reduced", - |diag| { - diag.span_suggestion(stmt.span, "replace it with", snippet, Applicability::MachineApplicable); - }, - ); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/non_expressive_names.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/non_expressive_names.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/non_expressive_names.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/non_expressive_names.rs 2021-11-29 19:27:12.000000000 +0000 @@ -43,7 +43,7 @@ /// let (a, b, c, d, e, f, g) = (...); /// ``` pub MANY_SINGLE_CHAR_NAMES, - style, + pedantic, "too many single character bindings" } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,238 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_lint_allowed; +use clippy_utils::source::snippet; +use clippy_utils::ty::{implements_trait, is_copy}; +use rustc_ast::ImplPolarity; +use rustc_hir::def_id::DefId; +use rustc_hir::{FieldDef, Item, ItemKind, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Warns about fields in struct implementing `Send` that are neither `Send` nor `Copy`. + /// + /// ### Why is this bad? + /// Sending the struct to another thread will transfer the ownership to + /// the new thread by dropping in the current thread during the transfer. + /// This causes soundness issues for non-`Send` fields, as they are also + /// dropped and might not be set up to handle this. + /// + /// See: + /// * [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html) + /// * [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html) + /// + /// ### Known Problems + /// Data structures that contain raw pointers may cause false positives. + /// They are sometimes safe to be sent across threads but do not implement + /// the `Send` trait. This lint has a heuristic to filter out basic cases + /// such as `Vec<*const T>`, but it's not perfect. Feel free to create an + /// issue if you have a suggestion on how this heuristic can be improved. + /// + /// ### Example + /// ```rust,ignore + /// struct ExampleStruct { + /// rc_is_not_send: Rc, + /// unbounded_generic_field: T, + /// } + /// + /// // This impl is unsound because it allows sending `!Send` types through `ExampleStruct` + /// unsafe impl Send for ExampleStruct {} + /// ``` + /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) + /// or specify correct bounds on generic type parameters (`T: Send`). + pub NON_SEND_FIELDS_IN_SEND_TY, + nursery, + "there is field that does not implement `Send` in a `Send` struct" +} + +#[derive(Copy, Clone)] +pub struct NonSendFieldInSendTy { + enable_raw_pointer_heuristic: bool, +} + +impl NonSendFieldInSendTy { + pub fn new(enable_raw_pointer_heuristic: bool) -> Self { + Self { + enable_raw_pointer_heuristic, + } + } +} + +impl_lint_pass!(NonSendFieldInSendTy => [NON_SEND_FIELDS_IN_SEND_TY]); + +impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + let ty_allowed_in_send = if self.enable_raw_pointer_heuristic { + ty_allowed_with_raw_pointer_heuristic + } else { + ty_allowed_without_raw_pointer_heuristic + }; + + // Checks if we are in `Send` impl item. + // We start from `Send` impl instead of `check_field_def()` because + // single `AdtDef` may have multiple `Send` impls due to generic + // parameters, and the lint is much easier to implement in this way. + if_chain! { + if let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send); + if let ItemKind::Impl(hir_impl) = &item.kind; + if let Some(trait_ref) = &hir_impl.of_trait; + if let Some(trait_id) = trait_ref.trait_def_id(); + if send_trait == trait_id; + if hir_impl.polarity == ImplPolarity::Positive; + if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.def_id); + if let self_ty = ty_trait_ref.self_ty(); + if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind(); + then { + let mut non_send_fields = Vec::new(); + + let hir_map = cx.tcx.hir(); + for variant in &adt_def.variants { + for field in &variant.fields { + if_chain! { + if let Some(field_hir_id) = field + .did + .as_local() + .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id)); + if !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id); + if let field_ty = field.ty(cx.tcx, impl_trait_substs); + if !ty_allowed_in_send(cx, field_ty, send_trait); + if let Node::Field(field_def) = hir_map.get(field_hir_id); + then { + non_send_fields.push(NonSendField { + def: field_def, + ty: field_ty, + generic_params: collect_generic_params(cx, field_ty), + }) + } + } + } + } + + if !non_send_fields.is_empty() { + span_lint_and_then( + cx, + NON_SEND_FIELDS_IN_SEND_TY, + item.span, + &format!( + "this implementation is unsound, as some fields in `{}` are `!Send`", + snippet(cx, hir_impl.self_ty.span, "Unknown") + ), + |diag| { + for field in non_send_fields { + diag.span_note( + field.def.span, + &format!("the type of field `{}` is `!Send`", field.def.ident.name), + ); + + match field.generic_params.len() { + 0 => diag.help("use a thread-safe type that implements `Send`"), + 1 if is_ty_param(field.ty) => diag.help(&format!("add `{}: Send` bound in `Send` impl", field.ty)), + _ => diag.help(&format!( + "add bounds on type parameter{} `{}` that satisfy `{}: Send`", + if field.generic_params.len() > 1 { "s" } else { "" }, + field.generic_params_string(), + snippet(cx, field.def.ty.span, "Unknown"), + )), + }; + } + }, + ); + } + } + } + } +} + +struct NonSendField<'tcx> { + def: &'tcx FieldDef<'tcx>, + ty: Ty<'tcx>, + generic_params: Vec>, +} + +impl<'tcx> NonSendField<'tcx> { + fn generic_params_string(&self) -> String { + self.generic_params + .iter() + .map(ToString::to_string) + .collect::>() + .join(", ") + } +} + +/// Given a type, collect all of its generic parameters. +/// Example: `MyStruct>` => `vec![P, Q, R]` +fn collect_generic_params<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Vec> { + ty.walk(cx.tcx) + .filter_map(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => Some(inner_ty), + _ => None, + }) + .filter(|&inner_ty| is_ty_param(inner_ty)) + .collect() +} + +/// Be more strict when the heuristic is disabled +fn ty_allowed_without_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool { + if implements_trait(cx, ty, send_trait, &[]) { + return true; + } + + if is_copy(cx, ty) && !contains_raw_pointer(cx, ty) { + return true; + } + + false +} + +/// Heuristic to allow cases like `Vec<*const u8>` +fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool { + if implements_trait(cx, ty, send_trait, &[]) || is_copy(cx, ty) { + return true; + } + + // The type is known to be `!Send` and `!Copy` + match ty.kind() { + ty::Tuple(_) => ty + .tuple_fields() + .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)), + ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait), + ty::Adt(_, substs) => { + if contains_raw_pointer(cx, ty) { + // descends only if ADT contains any raw pointers + substs.iter().all(|generic_arg| match generic_arg.unpack() { + GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait), + // Lifetimes and const generics are not solid part of ADT and ignored + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true, + }) + } else { + false + } + }, + // Raw pointers are `!Send` but allowed by the heuristic + ty::RawPtr(_) => true, + _ => false, + } +} + +/// Checks if the type contains any raw pointers in substs (including nested ones). +fn contains_raw_pointer<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool { + for ty_node in target_ty.walk(cx.tcx) { + if_chain! { + if let GenericArgKind::Type(inner_ty) = ty_node.unpack(); + if let ty::RawPtr(_) = inner_ty.kind(); + then { + return true; + } + } + } + + false +} + +/// Returns `true` if the type is a type parameter such as `T`. +fn is_ty_param(target_ty: Ty<'_>) -> bool { + matches!(target_ty.kind(), ty::Param(_)) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/open_options.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/open_options.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/open_options.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/open_options.rs 2021-11-29 19:27:12.000000000 +0000 @@ -31,11 +31,11 @@ impl<'tcx> LateLintPass<'tcx> for OpenOptions { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(path, _, arguments, _) = e.kind { - let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &e.kind { + let obj_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { let mut options = Vec::new(); - get_open_options(cx, &arguments[0], &mut options); + get_open_options(cx, self_arg, &mut options); check_open_options(cx, &options, e.span); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/option_if_let_else.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/option_if_let_else.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/option_if_let_else.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/option_if_let_else.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,12 +2,14 @@ use clippy_utils::higher; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{eager_or_lazy, in_macro, is_else_clause, is_lang_ctor}; +use clippy_utils::{ + can_move_expr_to_closure, eager_or_lazy, in_constant, in_macro, is_else_clause, is_lang_ctor, peel_hir_expr_while, + CaptureKind, +}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionSome; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Mutability, PatKind, UnOp}; +use rustc_hir::{def::Res, BindingAnnotation, Block, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -58,7 +60,7 @@ /// }, |foo| foo); /// ``` pub OPTION_IF_LET_ELSE, - pedantic, + nursery, "reimplementation of Option::map_or" } @@ -68,7 +70,7 @@ fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { if let ExprKind::MethodCall(path, _, &[ref receiver], _) = &expr.kind { path.ident.name.as_str() == "ok" - && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::result_type) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::Result) } else { false } @@ -125,20 +127,30 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { if_chain! { if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly - if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(cx, expr); + if !in_constant(cx, expr.hir_id); + if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) + = higher::IfLet::hir(cx, expr); if !is_else_clause(cx.tcx, expr); if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind; if is_lang_ctor(cx, struct_qpath, OptionSome); if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind; - if !contains_return_break_continue_macro(if_then); - if !contains_return_break_continue_macro(if_else); + if let Some(some_captures) = can_move_expr_to_closure(cx, if_then); + if let Some(none_captures) = can_move_expr_to_closure(cx, if_else); + if some_captures + .iter() + .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2))) + .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref()); then { let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; let some_body = extract_body_from_expr(if_then)?; let none_body = extract_body_from_expr(if_else)?; - let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" }; + let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { + "map_or" + } else { + "map_or_else" + }; let capture_name = id.name.to_ident_string(); let (as_ref, as_mut) = match &let_expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), @@ -150,6 +162,24 @@ ExprKind::Unary(UnOp::Deref, expr) | ExprKind::AddrOf(_, _, expr) => expr, _ => let_expr, }; + // Check if captures the closure will need conflict with borrows made in the scrutinee. + // TODO: check all the references made in the scrutinee expression. This will require interacting + // with the borrow checker. Currently only `[.]*` is checked for. + if as_ref || as_mut { + let e = peel_hir_expr_while(cond_expr, |e| match e.kind { + ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e), + _ => None, + }); + if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind { + match some_captures.get(local_id) + .or_else(|| (method_sugg == "map_or_else").then(|| ()).and_then(|_| none_captures.get(local_id))) + { + Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, + Some(CaptureKind::Ref(Mutability::Not)) | None => (), + } + } + } Some(OptionIfLetElseOccurence { option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), method_sugg: method_sugg.to_string(), diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs 2021-11-29 19:27:12.000000000 +0000 @@ -26,6 +26,9 @@ declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]); +const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust"; +const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust"; + impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { // a + b < a, a > a + b, a < a - b, a - b > a fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -40,17 +43,11 @@ if cx.typeck_results().expr_ty(ident1).is_integral(); if cx.typeck_results().expr_ty(ident2).is_integral(); then { - if let BinOpKind::Lt = op.node { - if let BinOpKind::Add = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C overflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); } - if let BinOpKind::Gt = op.node { - if let BinOpKind::Sub = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C underflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); } } } @@ -65,17 +62,11 @@ if cx.typeck_results().expr_ty(ident1).is_integral(); if cx.typeck_results().expr_ty(ident2).is_integral(); then { - if let BinOpKind::Gt = op.node { - if let BinOpKind::Add = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C overflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); } - if let BinOpKind::Lt = op.node { - if let BinOpKind::Sub = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C underflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs 2021-11-29 19:27:12.000000000 +0000 @@ -47,7 +47,7 @@ span: Span, hir_id: hir::HirId, ) { - if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { + if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) { lint_impl_body(cx, span, body); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs 2021-11-29 19:27:12.000000000 +0000 @@ -13,10 +13,10 @@ use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; +use rustc_middle::ty::layout::LayoutOf; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; -use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; use rustc_target::spec::Target; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs 2021-11-29 19:27:12.000000000 +0000 @@ -118,7 +118,7 @@ } } if let ExprKind::Let(let_pat, let_expr, _) = expr.kind { - if let Some(ref expr_ty) = cx.typeck_results().node_type_opt(let_expr.hir_id) { + if let Some(expr_ty) = cx.typeck_results().node_type_opt(let_expr.hir_id) { if in_external_macro(cx.sess(), let_pat.span) { return; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs 2021-11-29 19:27:12.000000000 +0000 @@ -92,13 +92,13 @@ cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { - if let ExprKind::MethodCall(path_segment, _, args, _) = expr.kind { - if is_expr_ty_raw_ptr(cx, &args[0]) { + if let ExprKind::MethodCall(path_segment, _, [arg_0, arg_1, ..], _) = &expr.kind { + if is_expr_ty_raw_ptr(cx, arg_0) { if path_segment.ident.name == sym::offset { - return Some((&args[0], &args[1], Method::Offset)); + return Some((arg_0, arg_1, Method::Offset)); } if path_segment.ident.name == sym!(wrapping_offset) { - return Some((&args[0], &args[1], Method::WrappingOffset)); + return Some((arg_0, arg_1, Method::WrappingOffset)); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ptr.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ptr.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ptr.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ptr.rs 2021-11-29 19:27:12.000000000 +0000 @@ -258,7 +258,7 @@ } if let ty::Ref(_, ty, Mutability::Not) = ty.kind() { - if is_type_diagnostic_item(cx, ty, sym::vec_type) { + if is_type_diagnostic_item(cx, ty, sym::Vec) { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) { span_lint_and_then( cx, @@ -288,7 +288,7 @@ }, ); } - } else if is_type_diagnostic_item(cx, ty, sym::string_type) { + } else if is_type_diagnostic_item(cx, ty, sym::String) { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) { span_lint_and_then( cx, @@ -372,7 +372,7 @@ for (_, ref mutbl, ref argspan) in decl .inputs .iter() - .filter_map(|ty| get_rptr_lm(ty)) + .filter_map(get_rptr_lm) .filter(|&(lt, _, _)| lt.name == out.name) { if *mutbl == Mutability::Mut { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/question_mark.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/question_mark.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/question_mark.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/question_mark.rs 2021-11-29 19:27:12.000000000 +0000 @@ -97,7 +97,8 @@ fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(cx, expr); + if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) + = higher::IfLet::hir(cx, expr); if Self::is_option(cx, let_expr); if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind; @@ -105,7 +106,7 @@ if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind; let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut); - if let ExprKind::Block(ref block, None) = if_then.kind; + if let ExprKind::Block(block, None) = if_then.kind; if block.stmts.is_empty(); if let Some(trailing_expr) = &block.expr; if path_to_local_id(trailing_expr, bind_id); @@ -142,7 +143,7 @@ fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expression); - is_type_diagnostic_item(cx, expr_ty, sym::option_type) + is_type_diagnostic_item(cx, expr_ty, sym::Option) } fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_clone.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_clone.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_clone.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_clone.rs 2021-11-29 19:27:12.000000000 +0000 @@ -15,7 +15,7 @@ Mutability, }; use rustc_middle::ty::{self, fold::TypeVisitor, Ty, TyCtxt}; -use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; +use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; use rustc_span::sym; @@ -123,7 +123,7 @@ let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD) || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD) || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD) - && is_type_diagnostic_item(cx, arg_ty, sym::string_type)); + && is_type_diagnostic_item(cx, arg_ty, sym::String)); let from_deref = !from_borrow && (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF) @@ -625,7 +625,10 @@ .flat_map(HybridBitSet::iter) .collect(); - if ContainsRegion(self.cx.tcx).visit_ty(self.body.local_decls[*dest].ty).is_break() { + if ContainsRegion(self.cx.tcx) + .visit_ty(self.body.local_decls[*dest].ty) + .is_break() + { mutable_variables.push(*dest); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs 2021-11-29 19:27:12.000000000 +0000 @@ -51,9 +51,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor { fn visit_expr(&mut self, ex: &'ast ast::Expr) { - if let ast::ExprKind::Ret(_) = ex.kind { - self.found_return = true; - } else if let ast::ExprKind::Try(_) = ex.kind { + if let ast::ExprKind::Ret(_) | ast::ExprKind::Try(_) = ex.kind { self.found_return = true; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs 2021-11-29 19:27:12.000000000 +0000 @@ -41,25 +41,23 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let VisibilityKind::Crate { .. } = item.vis.node { - if !cx.access_levels.is_exported(item.def_id) { - if let Some(false) = self.is_exported.last() { - let span = item.span.with_hi(item.ident.span.hi()); - let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id()); - span_lint_and_then( - cx, - REDUNDANT_PUB_CRATE, - span, - &format!("pub(crate) {} inside private module", descr), - |diag| { - diag.span_suggestion( - item.vis.span, - "consider using", - "pub".to_string(), - Applicability::MachineApplicable, - ); - }, - ); - } + if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false) { + let span = item.span.with_hi(item.ident.span.hi()); + let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id()); + span_lint_and_then( + cx, + REDUNDANT_PUB_CRATE, + span, + &format!("pub(crate) {} inside private module", descr), + |diag| { + diag.span_suggestion( + item.vis.span, + "consider using", + "pub".to_string(), + Applicability::MachineApplicable, + ); + }, + ); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ref_option_ref.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ref_option_ref.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ref_option_ref.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/ref_option_ref.rs 2021-11-29 19:27:12.000000000 +0000 @@ -45,7 +45,7 @@ if let Some(res) = last.res; if let Some(def_id) = res.opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::option_type, def_id); + if cx.tcx.is_diagnostic_item(sym::Option, def_id); if let Some(params) = last_path_segment(qpath).args ; if !params.parenthesized; if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/regex.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/regex.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/regex.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/regex.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,10 +3,9 @@ use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::{LitKind, StrStyle}; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{BorrowKind, Expr, ExprKind, HirId}; +use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; use std::convert::TryFrom; @@ -52,13 +51,7 @@ "trivial regular expressions" } -#[derive(Clone, Default)] -pub struct Regex { - spans: FxHashSet, - last: Option, -} - -impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); +declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -91,7 +84,7 @@ let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset); let start = base.lo() + BytePos(u32::try_from(c.start.offset).expect("offset too large") + offset); assert!(start <= end); - Span::new(start, end, base.ctxt()) + Span::new(start, end, base.ctxt(), base.parent()) } fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/repeat_once.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/repeat_once.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/repeat_once.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/repeat_once.rs 2021-11-29 19:27:12.000000000 +0000 @@ -48,7 +48,7 @@ if_chain! { if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind; if path.ident.name == sym!(repeat); - if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(count); + if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1)); if !in_macro(receiver.span); then { let ty = cx.typeck_results().expr_ty(receiver).peel_refs(); @@ -72,7 +72,7 @@ format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)), Applicability::MachineApplicable, ); - } else if is_type_diagnostic_item(cx, ty, sym::string_type) { + } else if is_type_diagnostic_item(cx, ty, sym::String) { span_lint_and_sugg( cx, REPEAT_ONCE, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/returns.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/returns.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/returns.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/returns.rs 2021-11-29 19:27:12.000000000 +0000 @@ -11,6 +11,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::sym; @@ -199,20 +200,19 @@ check_block_return(cx, ifblock); } if let Some(else_clause) = else_clause_opt { - check_final_expr(cx, else_clause, None, RetReplacement::Empty); + if expr.span.desugaring_kind() != Some(DesugaringKind::LetElse) { + check_final_expr(cx, else_clause, None, RetReplacement::Empty); + } } }, // a match expr, check all arms // an if/if let expr, check both exprs // note, if without else is going to be a type checking error anyways // (except for unit type functions) so we don't match it - ExprKind::Match(_, arms, source) => match source { - MatchSource::Normal => { - for arm in arms.iter() { - check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Block); - } - }, - _ => (), + ExprKind::Match(_, arms, MatchSource::Normal) => { + for arm in arms.iter() { + check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Block); + } }, ExprKind::DropTemps(expr) => check_final_expr(cx, expr, None, RetReplacement::Empty), _ => (), diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/same_name_method.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/same_name_method.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/same_name_method.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/same_name_method.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,160 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::AssocKind; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::Symbol; +use rustc_span::Span; +use std::collections::{BTreeMap, BTreeSet}; + +declare_clippy_lint! { + /// ### What it does + /// It lints if a struct has two method with same time: + /// one from a trait, another not from trait. + /// + /// ### Why is this bad? + /// Confusing. + /// + /// ### Example + /// ```rust + /// trait T { + /// fn foo(&self) {} + /// } + /// + /// struct S; + /// + /// impl T for S { + /// fn foo(&self) {} + /// } + /// + /// impl S { + /// fn foo(&self) {} + /// } + /// ``` + pub SAME_NAME_METHOD, + restriction, + "two method with same name" +} + +declare_lint_pass!(SameNameMethod => [SAME_NAME_METHOD]); + +struct ExistingName { + impl_methods: BTreeMap, + trait_methods: BTreeMap>, +} + +impl<'tcx> LateLintPass<'tcx> for SameNameMethod { + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + let mut map = FxHashMap::::default(); + + for item in cx.tcx.hir().items() { + if let ItemKind::Impl(Impl { + items, + of_trait, + self_ty, + .. + }) = &item.kind + { + if let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind { + if !map.contains_key(res) { + map.insert( + *res, + ExistingName { + impl_methods: BTreeMap::new(), + trait_methods: BTreeMap::new(), + }, + ); + } + let existing_name = map.get_mut(res).unwrap(); + + match of_trait { + Some(trait_ref) => { + let mut methods_in_trait: BTreeSet = if_chain! { + if let Some(Node::TraitRef(TraitRef { path, .. })) = + cx.tcx.hir().find(trait_ref.hir_ref_id); + if let Res::Def(DefKind::Trait, did) = path.res; + then{ + // FIXME: if + // `rustc_middle::ty::assoc::AssocItems::items` is public, + // we can iterate its keys instead of `in_definition_order`, + // which's more efficient + cx.tcx + .associated_items(did) + .in_definition_order() + .filter(|assoc_item| { + matches!(assoc_item.kind, AssocKind::Fn) + }) + .map(|assoc_item| assoc_item.ident.name) + .collect() + }else{ + BTreeSet::new() + } + }; + + let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| { + if let Some(impl_span) = existing_name.impl_methods.get(&method_name) { + span_lint_and_then( + cx, + SAME_NAME_METHOD, + *impl_span, + "method's name is same to an existing method in a trait", + |diag| { + diag.span_note( + trait_method_span, + &format!("existing `{}` defined here", method_name), + ); + }, + ); + } + if let Some(v) = existing_name.trait_methods.get_mut(&method_name) { + v.push(trait_method_span); + } else { + existing_name.trait_methods.insert(method_name, vec![trait_method_span]); + } + }; + + for impl_item_ref in (*items).iter().filter(|impl_item_ref| { + matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }) + }) { + let method_name = impl_item_ref.ident.name; + methods_in_trait.remove(&method_name); + check_trait_method(method_name, impl_item_ref.span); + } + + for method_name in methods_in_trait { + check_trait_method(method_name, item.span); + } + }, + None => { + for impl_item_ref in (*items).iter().filter(|impl_item_ref| { + matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }) + }) { + let method_name = impl_item_ref.ident.name; + let impl_span = impl_item_ref.span; + if let Some(trait_spans) = existing_name.trait_methods.get(&method_name) { + span_lint_and_then( + cx, + SAME_NAME_METHOD, + impl_span, + "method's name is same to an existing method in a trait", + |diag| { + // TODO should we `span_note` on every trait? + // iterate on trait_spans? + diag.span_note( + trait_spans[0], + &format!("existing `{}` defined here", method_name), + ); + }, + ); + } + existing_name.impl_methods.insert(method_name, impl_span); + } + }, + } + } + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/shadow.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/shadow.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/shadow.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/shadow.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,17 +1,14 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::source::snippet; -use clippy_utils::{contains_name, higher, iter_input_pats}; -use rustc_hir::intravisit::FnKind; -use rustc_hir::{ - Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind, - UnOp, -}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use clippy_utils::visitors::is_local_used; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def::Res; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::hir_id::ItemLocalId; +use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -23,10 +20,6 @@ /// code. Still, some may opt to avoid it in their code base, they can set this /// lint to `Warn`. /// - /// ### Known problems - /// This lint, as the other shadowing related lints, - /// currently only catches very simple patterns. - /// /// ### Example /// ```rust /// # let x = 1; @@ -52,10 +45,6 @@ /// because a value may be bound to different things depending on position in /// the code. /// - /// ### Known problems - /// This lint, as the other shadowing related lints, - /// currently only catches very simple patterns. - /// /// ### Example /// ```rust /// let x = 2; @@ -83,12 +72,6 @@ /// any place in the code. This can be alleviated by either giving more specific /// names to bindings or introducing more scopes to contain the bindings. /// - /// ### Known problems - /// This lint, as the other shadowing related lints, - /// currently only catches very simple patterns. Note that - /// `allow`/`warn`/`deny`/`forbid` attributes only work on the function level - /// for this lint. - /// /// ### Example /// ```rust /// # let y = 1; @@ -102,307 +85,151 @@ /// let w = z; // use different variable name /// ``` pub SHADOW_UNRELATED, - pedantic, + restriction, "rebinding a name without even using the original value" } -declare_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]); +#[derive(Default)] +pub(crate) struct Shadow { + bindings: Vec>>, +} + +impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]); impl<'tcx> LateLintPass<'tcx> for Shadow { - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - _: FnKind<'tcx>, - decl: &'tcx FnDecl<'_>, - body: &'tcx Body<'_>, - _: Span, - _: HirId, - ) { - if in_external_macro(cx.sess(), body.value.span) { + fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { + let (id, ident) = match pat.kind { + PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident), + _ => return, + }; + if ident.span.from_expansion() || ident.span.is_dummy() { return; } - check_fn(cx, decl, body); - } -} + let HirId { owner, local_id } = id; -fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>) { - let mut bindings = Vec::with_capacity(decl.inputs.len()); - for arg in iter_input_pats(decl, body) { - if let PatKind::Binding(.., ident, _) = arg.pat.kind { - bindings.push((ident.name, ident.span)); + // get (or insert) the list of items for this owner and symbol + let data = self.bindings.last_mut().unwrap(); + let items_with_name = data.entry(ident.name).or_default(); + + // check other bindings with the same name, most recently seen first + for &prev in items_with_name.iter().rev() { + if prev == local_id { + // repeated binding in an `Or` pattern + return; + } + + if is_shadow(cx, owner, prev, local_id) { + let prev_hir_id = HirId { owner, local_id: prev }; + lint_shadow(cx, pat, prev_hir_id, ident.span); + // only lint against the "nearest" shadowed binding + break; + } } + // store the binding + items_with_name.push(local_id); } - check_expr(cx, &body.value, &mut bindings); -} -fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>, bindings: &mut Vec<(Symbol, Span)>) { - let len = bindings.len(); - for stmt in block.stmts { - match stmt.kind { - StmtKind::Local(local) => check_local(cx, local, bindings), - StmtKind::Expr(e) | StmtKind::Semi(e) => check_expr(cx, e, bindings), - StmtKind::Item(..) => {}, + fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { + let hir = cx.tcx.hir(); + if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) { + self.bindings.push(FxHashMap::default()); } } - if let Some(o) = block.expr { - check_expr(cx, o, bindings); - } - bindings.truncate(len); -} -fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &mut Vec<(Symbol, Span)>) { - if in_external_macro(cx.sess(), local.span) { - return; - } - if higher::is_from_for_desugar(local) { - return; - } - let Local { - pat, - ref ty, - ref init, - span, - .. - } = *local; - if let Some(t) = *ty { - check_ty(cx, t, bindings); - } - if let Some(o) = *init { - check_expr(cx, o, bindings); - check_pat(cx, pat, Some(o), span, bindings); - } else { - check_pat(cx, pat, None, span, bindings); + fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { + let hir = cx.tcx.hir(); + if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) { + self.bindings.pop(); + } } } -fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool { - let var_ty = cx.typeck_results().node_type_opt(pat_id); - var_ty.map_or(false, |var_ty| !matches!(var_ty.kind(), ty::Adt(..))) -} - -fn check_pat<'tcx>( - cx: &LateContext<'tcx>, - pat: &'tcx Pat<'_>, - init: Option<&'tcx Expr<'_>>, - span: Span, - bindings: &mut Vec<(Symbol, Span)>, -) { - // TODO: match more stuff / destructuring - match pat.kind { - PatKind::Binding(.., ident, ref inner) => { - let name = ident.name; - if is_binding(cx, pat.hir_id) { - let mut new_binding = true; - for tup in bindings.iter_mut() { - if tup.0 == name { - lint_shadow(cx, name, span, pat.span, init, tup.1); - tup.1 = ident.span; - new_binding = false; - break; - } - } - if new_binding { - bindings.push((name, ident.span)); - } - } - if let Some(p) = *inner { - check_pat(cx, p, init, span, bindings); - } - }, - PatKind::Struct(_, pfields, _) => { - if let Some(init_struct) = init { - if let ExprKind::Struct(_, efields, _) = init_struct.kind { - for field in pfields { - let name = field.ident.name; - let efield = efields - .iter() - .find_map(|f| if f.ident.name == name { Some(&*f.expr) } else { None }); - check_pat(cx, field.pat, efield, span, bindings); - } - } else { - for field in pfields { - check_pat(cx, field.pat, init, span, bindings); - } - } - } else { - for field in pfields { - check_pat(cx, field.pat, None, span, bindings); - } - } - }, - PatKind::Tuple(inner, _) => { - if let Some(init_tup) = init { - if let ExprKind::Tup(tup) = init_tup.kind { - for (i, p) in inner.iter().enumerate() { - check_pat(cx, p, Some(&tup[i]), p.span, bindings); - } - } else { - for p in inner { - check_pat(cx, p, init, span, bindings); - } - } - } else { - for p in inner { - check_pat(cx, p, None, span, bindings); - } - } - }, - PatKind::Box(inner) => { - if let Some(initp) = init { - if let ExprKind::Box(inner_init) = initp.kind { - check_pat(cx, inner, Some(inner_init), span, bindings); - } else { - check_pat(cx, inner, init, span, bindings); - } - } else { - check_pat(cx, inner, init, span, bindings); - } - }, - PatKind::Ref(inner, _) => check_pat(cx, inner, init, span, bindings), - // PatVec(Vec>, Option>, Vec>), - _ => (), - } +fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool { + let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id()); + let first_scope = scope_tree.var_scope(first); + let second_scope = scope_tree.var_scope(second); + scope_tree.is_subscope_of(second_scope, first_scope) } -fn lint_shadow<'tcx>( - cx: &LateContext<'tcx>, - name: Symbol, - span: Span, - pattern_span: Span, - init: Option<&'tcx Expr<'_>>, - prev_span: Span, -) { - if let Some(expr) = init { - if is_self_shadow(name, expr) { - span_lint_and_then( - cx, - SHADOW_SAME, - span, - &format!( - "`{}` is shadowed by itself in `{}`", - snippet(cx, pattern_span, "_"), - snippet(cx, expr.span, "..") - ), - |diag| { - diag.span_note(prev_span, "previous binding is here"); - }, +fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) { + let (lint, msg) = match find_init(cx, pat.hir_id) { + Some(expr) if is_self_shadow(cx, pat, expr, shadowed) => { + let msg = format!( + "`{}` is shadowed by itself in `{}`", + snippet(cx, pat.span, "_"), + snippet(cx, expr.span, "..") ); - } else if contains_name(name, expr) { - span_lint_and_then( - cx, - SHADOW_REUSE, - pattern_span, - &format!( - "`{}` is shadowed by `{}` which reuses the original value", - snippet(cx, pattern_span, "_"), - snippet(cx, expr.span, "..") - ), - |diag| { - diag.span_note(expr.span, "initialization happens here"); - diag.span_note(prev_span, "previous binding is here"); - }, + (SHADOW_SAME, msg) + }, + Some(expr) if is_local_used(cx, expr, shadowed) => { + let msg = format!( + "`{}` is shadowed by `{}` which reuses the original value", + snippet(cx, pat.span, "_"), + snippet(cx, expr.span, "..") ); - } else { - span_lint_and_then( - cx, - SHADOW_UNRELATED, - pattern_span, - &format!("`{}` is being shadowed", snippet(cx, pattern_span, "_")), - |diag| { - diag.span_note(expr.span, "initialization happens here"); - diag.span_note(prev_span, "previous binding is here"); + (SHADOW_REUSE, msg) + }, + _ => { + let msg = format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_")); + (SHADOW_UNRELATED, msg) + }, + }; + span_lint_and_note( + cx, + lint, + span, + &msg, + Some(cx.tcx.hir().span(shadowed)), + "previous binding is here", + ); +} + +/// Returns true if the expression is a simple transformation of a local binding such as `&x` +fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_id: HirId) -> bool { + let hir = cx.tcx.hir(); + let is_direct_binding = hir + .parent_iter(pat.hir_id) + .map_while(|(_id, node)| match node { + Node::Pat(pat) => Some(pat), + _ => None, + }) + .all(|pat| matches!(pat.kind, PatKind::Ref(..) | PatKind::Or(_))); + if !is_direct_binding { + return false; + } + loop { + expr = match expr.kind { + ExprKind::Box(e) + | ExprKind::AddrOf(_, _, e) + | ExprKind::Block( + &Block { + stmts: [], + expr: Some(e), + .. }, - ); + _, + ) + | ExprKind::Unary(UnOp::Deref, e) => e, + ExprKind::Path(QPath::Resolved(None, path)) => break path.res == Res::Local(hir_id), + _ => break false, } - } else { - span_lint_and_then( - cx, - SHADOW_UNRELATED, - span, - &format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")), - |diag| { - diag.span_note(prev_span, "previous binding is here"); - }, - ); - } -} - -fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut Vec<(Symbol, Span)>) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - match expr.kind { - ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => { - check_expr(cx, e, bindings); - }, - ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings), - // ExprKind::Call - // ExprKind::MethodCall - ExprKind::Array(v) | ExprKind::Tup(v) => { - for e in v { - check_expr(cx, e, bindings); - } - }, - ExprKind::If(cond, then, ref otherwise) => { - check_expr(cx, cond, bindings); - check_expr(cx, then, bindings); - if let Some(o) = *otherwise { - check_expr(cx, o, bindings); - } - }, - ExprKind::Match(init, arms, _) => { - check_expr(cx, init, bindings); - let len = bindings.len(); - for arm in arms { - check_pat(cx, arm.pat, Some(init), arm.pat.span, bindings); - // This is ugly, but needed to get the right type - if let Some(ref guard) = arm.guard { - match guard { - Guard::If(if_expr) => check_expr(cx, if_expr, bindings), - Guard::IfLet(guard_pat, guard_expr) => { - check_pat(cx, guard_pat, Some(*guard_expr), guard_pat.span, bindings); - check_expr(cx, guard_expr, bindings); - }, - } - } - check_expr(cx, arm.body, bindings); - bindings.truncate(len); - } - }, - _ => (), - } -} - -fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(Symbol, Span)>) { - match ty.kind { - TyKind::Slice(sty) => check_ty(cx, sty, bindings), - TyKind::Array(fty, ref anon_const) => { - check_ty(cx, fty, bindings); - check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings); - }, - TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings), - TyKind::Tup(tup) => { - for t in tup { - check_ty(cx, t, bindings); - } - }, - TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings), - _ => (), } } -fn is_self_shadow(name: Symbol, expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Box(inner) | ExprKind::AddrOf(_, _, inner) => is_self_shadow(name, inner), - ExprKind::Block(block, _) => { - block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e)) - }, - ExprKind::Unary(op, inner) => (UnOp::Deref == op) && is_self_shadow(name, inner), - ExprKind::Path(QPath::Resolved(_, path)) => path_eq_name(name, path), - _ => false, +/// Finds the "init" expression for a pattern: `let = ;` or +/// `match { .., => .., .. }` +fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { + for (_, node) in cx.tcx.hir().parent_iter(hir_id) { + let init = match node { + Node::Arm(_) | Node::Pat(_) => continue, + Node::Expr(expr) => match expr.kind { + ExprKind::Match(e, _, _) => Some(e), + _ => None, + }, + Node::Local(local) => local.init, + _ => None, + }; + return init; } -} - -fn path_eq_name(name: Symbol, path: &Path<'_>) -> bool { - !path.is_global() && path.segments.len() == 1 && path.segments[0].ident.name == name + None } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs 2021-11-29 19:27:12.000000000 +0000 @@ -120,7 +120,7 @@ if let ExprKind::Call(func, [arg]) = expr.kind; if let ExprKind::Path(QPath::TypeRelative(ty, name)) = func.kind; if name.ident.as_str() == "with_capacity"; - if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::vec_type); + if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec); then { Some(arg) } else { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/strings.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/strings.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/strings.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/strings.rs 2021-11-29 19:27:12.000000000 +0000 @@ -157,7 +157,7 @@ } fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::string_type) + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String) } fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { @@ -345,9 +345,9 @@ impl LateLintPass<'_> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind; if path.ident.name == sym!(to_string); - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, ty, ..) = ty.kind(); if *ty.kind() == ty::Str; then { @@ -394,10 +394,10 @@ impl LateLintPass<'_> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind; if path.ident.name == sym!(to_string); - let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym::string_type); + let ty = cx.typeck_results().expr_ty(self_arg); + if is_type_diagnostic_item(cx, ty, sym::String); then { span_lint_and_help( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/swap.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/swap.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/swap.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/swap.rs 2021-11-29 19:27:12.000000000 +0000 @@ -86,8 +86,8 @@ if matches!(ty.kind(), ty::Slice(_)) || matches!(ty.kind(), ty::Array(_, _)) - || is_type_diagnostic_item(cx, ty, sym::vec_type) - || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) + || is_type_diagnostic_item(cx, ty, sym::Vec) + || is_type_diagnostic_item(cx, ty, sym::VecDeque) { let slice = Sugg::hir_with_applicability(cx, lhs1, "", &mut applicability); span_lint_and_sugg( @@ -231,7 +231,7 @@ } } -/// Returns the lhs and rhs of an xor assignment statement. +/// Returns the lhs and rhs of an xor assignment statement. fn extract_sides_of_xor_assign<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(&'a Expr<'hir>, &'a Expr<'hir>)> { if let StmtKind::Semi(expr) = stmt.kind { if let ExprKind::AssignOp( diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs 2021-11-29 19:27:12.000000000 +0000 @@ -69,6 +69,7 @@ attr.span.lo() + BytePos(3 + lo), attr.span.lo() + BytePos(3 + hi), attr.span.ctxt(), + attr.span.parent(), ); span_lint_and_sugg( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/to_string_in_display.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/to_string_in_display.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/to_string_in_display.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/to_string_in_display.rs 2021-11-29 19:27:12.000000000 +0000 @@ -92,11 +92,11 @@ if_chain! { if self.in_display_impl; if let Some(self_hir_id) = self.self_hir_id; - if let ExprKind::MethodCall(path, _, args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, [ref self_arg, ..], _) = expr.kind; if path.ident.name == sym!(to_string); if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if is_diag_trait_item(cx, expr_def_id, sym::ToString); - if path_to_local_id(&args[0], self_hir_id); + if path_to_local_id(self_arg, self_hir_id); then { span_lint( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs 2021-11-29 19:27:12.000000000 +0000 @@ -9,13 +9,13 @@ // used to check for UNSOUND_COLLECTION_TRANSMUTE static COLLECTIONS: &[Symbol] = &[ - sym::vec_type, - sym::vecdeque_type, + sym::Vec, + sym::VecDeque, sym::BinaryHeap, sym::BTreeSet, sym::BTreeMap, - sym::hashset_type, - sym::hashmap_type, + sym::HashSet, + sym::HashMap, ]; /// Checks for `unsound_collection_transmute` lint. diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/transmuting_null.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/transmuting_null.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/transmuting_null.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/transmuting_null.rs 2021-11-29 19:27:12.000000000 +0000 @@ -49,8 +49,8 @@ let mut const_eval_context = constant_context(cx, cx.typeck_results()); if_chain! { if let ExprKind::Path(ref _qpath) = arg.kind; - let x = const_eval_context.expr(arg); - if let Some(Constant::RawPtr(0)) = x; + if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg); + if x == 0; then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/try_err.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/try_err.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/try_err.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/try_err.rs 2021-11-29 19:27:12.000000000 +0000 @@ -143,7 +143,7 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if_chain! { if let ty::Adt(_, subst) = ty.kind(); - if is_type_diagnostic_item(cx, ty, sym::result_type); + if is_type_diagnostic_item(cx, ty, sym::Result); then { Some(subst.type_at(1)) } else { @@ -160,7 +160,7 @@ let ready_ty = subst.type_at(0); if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::result_type, ready_def.did); + if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did); then { Some(ready_subst.type_at(1)) } else { @@ -177,11 +177,11 @@ let ready_ty = subst.type_at(0); if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::option_type, ready_def.did); + if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did); let some_ty = ready_subst.type_at(0); if let ty::Adt(some_def, some_subst) = some_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::result_type, some_def.did); + if cx.tcx.is_diagnostic_item(sym::Result, some_def.did); then { Some(some_subst.type_at(1)) } else { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/box_collection.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/box_collection.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/box_collection.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/box_collection.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,50 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_ty_param_diagnostic_item; +use rustc_hir::{self as hir, def_id::DefId, QPath}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::BOX_COLLECTION; + +pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { + if_chain! { + if Some(def_id) == cx.tcx.lang_items().owned_box(); + if let Some(item_type) = get_std_collection(cx, qpath); + then { + let generic = if item_type == "String" { + "" + } else { + "<..>" + }; + span_lint_and_help( + cx, + BOX_COLLECTION, + hir_ty.span, + &format!( + "you seem to be trying to use `Box<{outer}{generic}>`. Consider using just `{outer}{generic}`", + outer=item_type, + generic = generic), + None, + &format!( + "`{outer}{generic}` is already on the heap, `Box<{outer}{generic}>` makes an extra allocation", + outer=item_type, + generic = generic) + ); + true + } else { + false + } + } +} + +fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> { + if is_ty_param_diagnostic_item(cx, qpath, sym::Vec).is_some() { + Some("Vec") + } else if is_ty_param_diagnostic_item(cx, qpath, sym::String).is_some() { + Some("String") + } else if is_ty_param_diagnostic_item(cx, qpath, sym::HashMap).is_some() { + Some("HashMap") + } else { + None + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/box_vec.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/box_vec.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/box_vec.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/box_vec.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_ty_param_diagnostic_item; -use rustc_hir::{self as hir, def_id::DefId, QPath}; -use rustc_lint::LateContext; -use rustc_span::symbol::sym; - -use super::BOX_VEC; - -pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { - if Some(def_id) == cx.tcx.lang_items().owned_box() - && is_ty_param_diagnostic_item(cx, qpath, sym::vec_type).is_some() - { - span_lint_and_help( - cx, - BOX_VEC, - hir_ty.span, - "you seem to be trying to use `Box>`. Consider using just `Vec`", - None, - "`Vec` is already on the heap, `Box>` makes an extra allocation", - ); - true - } else { - false - } -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/mod.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ mod borrowed_box; -mod box_vec; +mod box_collection; mod linked_list; mod option_option; mod rc_buffer; @@ -21,12 +21,12 @@ declare_clippy_lint! { /// ### What it does - /// Checks for use of `Box>` anywhere in the code. + /// Checks for use of `Box` where T is a collection such as Vec anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? - /// `Vec` already keeps its contents in a separate area on - /// the heap. So if you `Box` it, you just add another level of indirection + /// Collections already keeps their contents in a separate area on + /// the heap. So if you `Box` them, you just add another level of indirection /// without any benefit whatsoever. /// /// ### Example @@ -43,7 +43,7 @@ /// values: Vec, /// } /// ``` - pub BOX_VEC, + pub BOX_COLLECTION, perf, "usage of `Box>`, vector elements are already on the heap" } @@ -295,9 +295,10 @@ pub struct Types { vec_box_size_threshold: u64, type_complexity_threshold: u64, + avoid_breaking_exported_api: bool, } -impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]); +impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]); impl<'tcx> LateLintPass<'tcx> for Types { fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) { @@ -308,19 +309,31 @@ false }; + let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(id)); + self.check_fn_decl( cx, decl, CheckTyContext { is_in_trait_impl, + is_exported, ..CheckTyContext::default() }, ); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + let is_exported = cx.access_levels.is_exported(item.def_id); + match item.kind { - ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(cx, ty, CheckTyContext::default()), + ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty( + cx, + ty, + CheckTyContext { + is_exported, + ..CheckTyContext::default() + }, + ), // functions, enums, structs, impls and traits are covered _ => (), } @@ -342,15 +355,31 @@ } fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { - self.check_ty(cx, field.ty, CheckTyContext::default()); + let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(field.hir_id)); + + self.check_ty( + cx, + field.ty, + CheckTyContext { + is_exported, + ..CheckTyContext::default() + }, + ); } - fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'_>) { + let is_exported = cx.access_levels.is_exported(item.def_id); + + let context = CheckTyContext { + is_exported, + ..CheckTyContext::default() + }; + match item.kind { TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => { - self.check_ty(cx, ty, CheckTyContext::default()); + self.check_ty(cx, ty, context); }, - TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()), + TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, context), TraitItemKind::Type(..) => (), } } @@ -370,10 +399,11 @@ } impl Types { - pub fn new(vec_box_size_threshold: u64, type_complexity_threshold: u64) -> Self { + pub fn new(vec_box_size_threshold: u64, type_complexity_threshold: u64, avoid_breaking_exported_api: bool) -> Self { Self { vec_box_size_threshold, type_complexity_threshold, + avoid_breaking_exported_api, } } @@ -410,17 +440,24 @@ let hir_id = hir_ty.hir_id; let res = cx.qpath_res(qpath, hir_id); if let Some(def_id) = res.opt_def_id() { - let mut triggered = false; - triggered |= box_vec::check(cx, hir_ty, qpath, def_id); - triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id); - triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id); - triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold); - triggered |= option_option::check(cx, hir_ty, qpath, def_id); - triggered |= linked_list::check(cx, hir_ty, def_id); - triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id); + if self.is_type_change_allowed(context) { + // All lints that are being checked in this block are guarded by + // the `avoid_breaking_exported_api` configuration. When adding a + // new lint, please also add the name to the configuration documentation + // in `clippy_lints::utils::conf.rs` + + let mut triggered = false; + triggered |= box_collection::check(cx, hir_ty, qpath, def_id); + triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id); + triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id); + triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold); + triggered |= option_option::check(cx, hir_ty, qpath, def_id); + triggered |= linked_list::check(cx, hir_ty, def_id); + triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id); - if triggered { - return; + if triggered { + return; + } } } match *qpath { @@ -487,11 +524,21 @@ _ => {}, } } + + /// This function checks if the type is allowed to change in the current context + /// based on the `avoid_breaking_exported_api` configuration + fn is_type_change_allowed(&self, context: CheckTyContext) -> bool { + !(context.is_exported && self.avoid_breaking_exported_api) + } } +#[allow(clippy::struct_excessive_bools)] #[derive(Clone, Copy, Default)] struct CheckTyContext { is_in_trait_impl: bool, + /// `true` for types on local variables. is_local: bool, + /// `true` for types that are part of the public API. + is_exported: bool, is_nested_call: bool, } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/option_option.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/option_option.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/option_option.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/option_option.rs 2021-11-29 19:27:12.000000000 +0000 @@ -7,9 +7,7 @@ use super::OPTION_OPTION; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { - if cx.tcx.is_diagnostic_item(sym::option_type, def_id) - && is_ty_param_diagnostic_item(cx, qpath, sym::option_type).is_some() - { + if cx.tcx.is_diagnostic_item(sym::Option, def_id) && is_ty_param_diagnostic_item(cx, qpath, sym::Option).is_some() { span_lint( cx, OPTION_OPTION, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs 2021-11-29 19:27:12.000000000 +0000 @@ -20,7 +20,7 @@ format!("Rc<{}>", alternate), Applicability::MachineApplicable, ); - } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::vec_type) { + } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Vec) { let qpath = match &ty.kind { TyKind::Path(qpath) => qpath, _ => return false, @@ -55,7 +55,7 @@ format!("Arc<{}>", alternate), Applicability::MachineApplicable, ); - } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::vec_type) { + } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Vec) { let qpath = match &ty.kind { TyKind::Path(qpath) => qpath, _ => return false, @@ -85,7 +85,7 @@ } fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> { - if is_ty_param_diagnostic_item(cx, qpath, sym::string_type).is_some() { + if is_ty_param_diagnostic_item(cx, qpath, sym::String).is_some() { Some("str") } else if is_ty_param_diagnostic_item(cx, qpath, sym::OsString).is_some() { Some("std::ffi::OsStr") diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_ty_param_diagnostic_item; use if_chain::if_chain; use rustc_hir::{self as hir, def_id::DefId, QPath}; @@ -10,14 +10,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { if_chain! { if cx.tcx.is_diagnostic_item(sym::Rc, def_id) ; - if let Some(_) = is_ty_param_diagnostic_item(cx, qpath, sym!(mutex_type)) ; - - then{ - span_lint( + if let Some(_) = is_ty_param_diagnostic_item(cx, qpath, sym::Mutex) ; + then { + span_lint_and_help( cx, RC_MUTEX, hir_ty.span, - "found `Rc>`. Consider using `Rc>` or `Arc>` instead", + "usage of `Rc>`", + None, + "consider using `Rc>` or `Arc>` instead", ); return true; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs 2021-11-29 19:27:12.000000000 +0000 @@ -54,7 +54,13 @@ _ => return false, }; let inner_span = match get_qpath_generic_tys(inner_qpath).next() { - Some(ty) => ty.span, + Some(ty) => { + // Box> is smaller than Box because of wide pointers + if matches!(ty.kind, TyKind::TraitObject(..)) { + return false; + } + ty.span + }, None => return false, }; if inner_sym == outer_sym { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/vec_box.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/vec_box.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/vec_box.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/types/vec_box.rs 2021-11-29 19:27:12.000000000 +0000 @@ -5,9 +5,9 @@ use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind}; use rustc_lint::LateContext; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::TypeFoldable; use rustc_span::symbol::sym; -use rustc_target::abi::LayoutOf; use rustc_typeck::hir_ty_to_ty; use super::VEC_BOX; @@ -19,7 +19,7 @@ def_id: DefId, box_size_threshold: u64, ) -> bool { - if cx.tcx.is_diagnostic_item(sym::vec_type, def_id) { + if cx.tcx.is_diagnostic_item(sym::Vec, def_id) { if_chain! { // Get the _ part of Vec<_> if let Some(last) = last_path_segment(qpath).args; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs 2021-11-29 19:27:12.000000000 +0000 @@ -37,8 +37,8 @@ impl LateLintPass<'tcx> for UndroppedManuallyDrops { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(args) = match_function_call(cx, expr, &paths::DROP) { - let ty = cx.typeck_results().expr_ty(&args[0]); + if let Some([arg_0, ..]) = match_function_call(cx, expr, &paths::DROP) { + let ty = cx.typeck_results().expr_ty(arg_0); if is_type_lang_item(cx, ty, lang_items::LangItem::ManuallyDrop) { span_lint_and_help( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs 2021-11-29 19:27:12.000000000 +0000 @@ -168,7 +168,7 @@ if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::vec_type); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, @@ -218,7 +218,10 @@ fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - matches!(ty.kind(), ty::Ref(..)) || ty.walk(cx.tcx).any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) + matches!(ty.kind(), ty::Ref(..)) + || ty + .walk(cx.tcx) + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) } impl LateLintPass<'_> for UnnecessarySortBy { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs 2021-11-29 19:27:12.000000000 +0000 @@ -101,9 +101,9 @@ // Get the wrapper and inner types, if can't, abort. let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() { - if cx.tcx.is_diagnostic_item(sym::option_type, adt_def.did) { + if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did) { ("Option", OptionSome, subst.type_at(0)) - } else if cx.tcx.is_diagnostic_item(sym::result_type, adt_def.did) { + } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did) { ("Result", ResultOk, subst.type_at(0)) } else { return; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_async.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_async.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_async.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_async.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnHeader, HirId, IsAsync, Item, ItemKind, YieldSource}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnHeader, HirId, IsAsync, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -57,11 +57,6 @@ } impl<'tcx> LateLintPass<'tcx> for UnusedAsync { - fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Trait(..) = item.kind { - return; - } - } fn check_fn( &mut self, cx: &LateContext<'tcx>, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_io_amount.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_io_amount.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_io_amount.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_io_amount.rs 2021-11-29 19:27:12.000000000 +0000 @@ -45,20 +45,20 @@ match expr.kind { hir::ExprKind::Match(res, _, _) if is_try(cx, expr).is_some() => { - if let hir::ExprKind::Call(func, args) = res.kind { + if let hir::ExprKind::Call(func, [ref arg_0, ..]) = res.kind { if matches!( func.kind, hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _)) ) { - check_map_error(cx, &args[0], expr); + check_map_error(cx, arg_0, expr); } } else { check_map_error(cx, res, expr); } }, - hir::ExprKind::MethodCall(path, _, args, _) => match &*path.ident.as_str() { + hir::ExprKind::MethodCall(path, _, [ref arg_0, ..], _) => match &*path.ident.as_str() { "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { - check_map_error(cx, &args[0], expr); + check_map_error(cx, arg_0, expr); }, _ => (), }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_self.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_self.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_self.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unused_self.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::visitors::is_local_used; use if_chain::if_chain; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -50,8 +50,7 @@ if let ImplItemKind::Fn(.., body_id) = &impl_item.kind; let body = cx.tcx.hir().body(*body_id); if let [self_param, ..] = body.params; - let self_hir_id = self_param.pat.hir_id; - if !LocalUsedVisitor::new(cx, self_hir_id).check_body(body); + if !is_local_used(cx, body, self_param.pat.hir_id); then { span_lint_and_help( cx, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs 2021-11-29 19:27:12.000000000 +0000 @@ -64,8 +64,8 @@ // first check if it's a method or function if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; // checking if its return type is `result` or `option` - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::result_type) - || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::option_type); + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Result) + || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Option); then { lint_impl_body(cx, impl_item.span, impl_item); } @@ -86,8 +86,8 @@ // check for `expect` if let Some(arglists) = method_chain_args(expr, &["expect"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::Option) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::Result) { self.result.push(expr.span); } @@ -96,8 +96,8 @@ // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::Option) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::Result) { self.result.push(expr.span); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unwrap.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unwrap.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unwrap.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/unwrap.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, usage::is_potentially_mutated}; +use clippy_utils::{differing_macro_contexts, path_to_local, usage::is_potentially_mutated}; use if_chain::if_chain; +use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; -use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp}; +use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, PathSegment, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; @@ -74,50 +75,85 @@ unwrappables: Vec>, cx: &'a LateContext<'tcx>, } + +/// What kind of unwrappable this is. +#[derive(Copy, Clone, Debug)] +enum UnwrappableKind { + Option, + Result, +} + +impl UnwrappableKind { + fn success_variant_pattern(self) -> &'static str { + match self { + UnwrappableKind::Option => "Some(..)", + UnwrappableKind::Result => "Ok(..)", + } + } + + fn error_variant_pattern(self) -> &'static str { + match self { + UnwrappableKind::Option => "None", + UnwrappableKind::Result => "Err(..)", + } + } +} + /// Contains information about whether a variable can be unwrapped. #[derive(Copy, Clone, Debug)] struct UnwrapInfo<'tcx> { /// The variable that is checked - ident: &'tcx Path<'tcx>, + local_id: HirId, + /// The if itself + if_expr: &'tcx Expr<'tcx>, /// The check, like `x.is_ok()` check: &'tcx Expr<'tcx>, + /// The check's name, like `is_ok` + check_name: &'tcx PathSegment<'tcx>, /// The branch where the check takes place, like `if x.is_ok() { .. }` branch: &'tcx Expr<'tcx>, /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`). safe_to_unwrap: bool, + /// What kind of unwrappable this is. + kind: UnwrappableKind, + /// If the check is the entire condition (`if x.is_ok()`) or only a part of it (`foo() && + /// x.is_ok()`) + is_entire_condition: bool, } /// Collects the information about unwrappable variables from an if condition /// The `invert` argument tells us whether the condition is negated. fn collect_unwrap_info<'tcx>( cx: &LateContext<'tcx>, + if_expr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>, branch: &'tcx Expr<'_>, invert: bool, + is_entire_condition: bool, ) -> Vec> { fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool { - is_type_diagnostic_item(cx, ty, sym::option_type) && ["is_some", "is_none"].contains(&method_name) + is_type_diagnostic_item(cx, ty, sym::Option) && ["is_some", "is_none"].contains(&method_name) } fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool { - is_type_diagnostic_item(cx, ty, sym::result_type) && ["is_ok", "is_err"].contains(&method_name) + is_type_diagnostic_item(cx, ty, sym::Result) && ["is_ok", "is_err"].contains(&method_name) } if let ExprKind::Binary(op, left, right) = &expr.kind { match (invert, op.node) { (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) => { - let mut unwrap_info = collect_unwrap_info(cx, left, branch, invert); - unwrap_info.append(&mut collect_unwrap_info(cx, right, branch, invert)); + let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false); + unwrap_info.append(&mut collect_unwrap_info(cx, if_expr, right, branch, invert, false)); return unwrap_info; }, _ => (), } } else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind { - return collect_unwrap_info(cx, expr, branch, !invert); + return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false); } else { if_chain! { if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind; - if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind; + if let Some(local_id) = path_to_local(&args[0]); let ty = cx.typeck_results().expr_ty(&args[0]); let name = method_name.ident.as_str(); if is_relevant_option_call(cx, ty, &name) || is_relevant_result_call(cx, ty, &name); @@ -129,7 +165,24 @@ _ => unreachable!(), }; let safe_to_unwrap = unwrappable != invert; - return vec![UnwrapInfo { ident: path, check: expr, branch, safe_to_unwrap }]; + let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { + UnwrappableKind::Option + } else { + UnwrappableKind::Result + }; + + return vec![ + UnwrapInfo { + local_id, + if_expr, + check: expr, + check_name: method_name, + branch, + safe_to_unwrap, + kind, + is_entire_condition, + } + ] } } } @@ -137,11 +190,17 @@ } impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> { - fn visit_branch(&mut self, cond: &'tcx Expr<'_>, branch: &'tcx Expr<'_>, else_branch: bool) { + fn visit_branch( + &mut self, + if_expr: &'tcx Expr<'_>, + cond: &'tcx Expr<'_>, + branch: &'tcx Expr<'_>, + else_branch: bool, + ) { let prev_len = self.unwrappables.len(); - for unwrap_info in collect_unwrap_info(self.cx, cond, branch, else_branch) { - if is_potentially_mutated(unwrap_info.ident, cond, self.cx) - || is_potentially_mutated(unwrap_info.ident, branch, self.cx) + for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) { + if is_potentially_mutated(unwrap_info.local_id, cond, self.cx) + || is_potentially_mutated(unwrap_info.local_id, branch, self.cx) { // if the variable is mutated, we don't know whether it can be unwrapped: continue; @@ -163,32 +222,62 @@ } if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) { walk_expr(self, cond); - self.visit_branch(cond, then, false); + self.visit_branch(expr, cond, then, false); if let Some(else_inner) = r#else { - self.visit_branch(cond, else_inner, true); + self.visit_branch(expr, cond, else_inner, true); } } else { // find `unwrap[_err]()` calls: if_chain! { if let ExprKind::MethodCall(method_name, _, args, _) = expr.kind; - if let ExprKind::Path(QPath::Resolved(None, path)) = args[0].kind; - if [sym::unwrap, sym!(unwrap_err)].contains(&method_name.ident.name); - let call_to_unwrap = method_name.ident.name == sym::unwrap; + if let Some(id) = path_to_local(&args[0]); + if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name); + let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name); if let Some(unwrappable) = self.unwrappables.iter() - .find(|u| u.ident.res == path.res); + .find(|u| u.local_id == id); // Span contexts should not differ with the conditional branch if !differing_macro_contexts(unwrappable.branch.span, expr.span); if !differing_macro_contexts(unwrappable.branch.span, unwrappable.check.span); then { if call_to_unwrap == unwrappable.safe_to_unwrap { + let is_entire_condition = unwrappable.is_entire_condition; + let unwrappable_variable_name = self.cx.tcx.hir().name(unwrappable.local_id); + let suggested_pattern = if call_to_unwrap { + unwrappable.kind.success_variant_pattern() + } else { + unwrappable.kind.error_variant_pattern() + }; + span_lint_and_then( self.cx, UNNECESSARY_UNWRAP, expr.span, - &format!("you checked before that `{}()` cannot fail, \ - instead of checking and unwrapping, it's better to use `if let` or `match`", - method_name.ident.name), - |diag| { diag.span_label(unwrappable.check.span, "the check is happening here"); }, + &format!( + "called `{}` on `{}` after checking its variant with `{}`", + method_name.ident.name, + unwrappable_variable_name, + unwrappable.check_name.ident.as_str(), + ), + |diag| { + if is_entire_condition { + diag.span_suggestion( + unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()), + "try", + format!( + "if let {} = {}", + suggested_pattern, + unwrappable_variable_name, + ), + // We don't track how the unwrapped value is used inside the + // block or suggest deleting the unwrap, so we can't offer a + // fixable solution. + Applicability::Unspecified, + ); + } else { + diag.span_label(unwrappable.check.span, "the check is happening here"); + diag.help("try using `if let` or `match`"); + } + }, ); } else { span_lint_and_then( diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/useless_conversion.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/useless_conversion.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/useless_conversion.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/useless_conversion.rs 2021-11-29 19:27:12.000000000 +0000 @@ -63,7 +63,7 @@ }, ExprKind::MethodCall(name, .., args, _) => { - if is_trait_method(cx, e, sym::into_trait) && &*name.ident.as_str() == "into" { + if is_trait_method(cx, e, sym::Into) && &*name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); if same_type_and_consts(a, b) { @@ -103,10 +103,10 @@ } } if_chain! { - if is_trait_method(cx, e, sym::try_into_trait) && name.ident.name == sym::try_into; + if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into; let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, a, sym::result_type); + if is_type_diagnostic_item(cx, a, sym::Result); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); if same_type_and_consts(a_type, b); @@ -134,7 +134,7 @@ let b = cx.typeck_results().expr_ty(&args[0]); if_chain! { if match_def_path(cx, def_id, &paths::TRY_FROM); - if is_type_diagnostic_item(cx, a, sym::result_type); + if is_type_diagnostic_item(cx, a, sym::Result); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); if same_type_and_consts(a_type, b); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/conf.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/conf.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/conf.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/conf.rs 2021-11-29 19:27:12.000000000 +0000 @@ -15,6 +15,14 @@ pub rename: String, } +/// A single disallowed method, used by the `DISALLOWED_METHOD` lint. +#[derive(Clone, Debug, Deserialize)] +#[serde(untagged)] +pub enum DisallowedMethod { + Simple(String), + WithReason { path: String, reason: Option }, +} + /// Conf with parse errors #[derive(Default)] pub struct TryConf { @@ -31,9 +39,6 @@ } } -/// Note that the configuration parsing currently doesn't support documentation that will -/// that spans over several lines. This will be possible with the new implementation -/// See (rust-clippy#7172) macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ @@ -130,13 +135,12 @@ }; } -// N.B., this macro is parsed by util/lintlib.py define_Conf! { - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT. /// /// The minimum rust version that the project supports (msrv: Option = None), @@ -247,7 +251,7 @@ /// Lint: DISALLOWED_METHOD. /// /// The list of disallowed methods, written as fully qualified paths. - (disallowed_methods: Vec = Vec::new()), + (disallowed_methods: Vec = Vec::new()), /// Lint: DISALLOWED_TYPE. /// /// The list of disallowed types, written as fully qualified paths. @@ -280,6 +284,10 @@ /// /// The list of unicode scripts allowed to be used in the scope. (allowed_scripts: Vec = vec!["Latin".to_string()]), + /// Lint: NON_SEND_FIELDS_IN_SEND_TY. + /// + /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. + (enable_raw_pointer_heuristic_for_send: bool = true), } /// Search for the configuration file. diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/inspector.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/inspector.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/inspector.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/inspector.rs 2021-11-29 19:27:12.000000000 +0000 @@ -142,7 +142,7 @@ print_expr(cx, arg, indent + 1); } }, - hir::ExprKind::Let(ref pat, ref expr, _) => { + hir::ExprKind::Let(pat, expr, _) => { print_pat(cx, pat, indent + 1); print_expr(cx, expr, indent + 1); }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs 2021-11-29 19:27:12.000000000 +0000 @@ -82,7 +82,7 @@ /// `default` macro_rules! CONFIGURATION_VALUE_TEMPLATE { () => { - "* {name}: `{ty}`: {doc} (defaults to `{default}`)\n" + "* `{name}`: `{ty}`: {doc} (defaults to `{default}`)\n" }; } @@ -298,6 +298,7 @@ default: String, lints: Vec, doc: String, + #[allow(dead_code)] deprecation_reason: Option<&'static str>, } @@ -786,8 +787,6 @@ } }; - // TODO xFrednet 2021-03-01: support function arguments? - intravisit::walk_expr(self, expr); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,6 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::higher; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use clippy_utils::{ @@ -7,7 +8,7 @@ paths, SpanlessEq, }; use if_chain::if_chain; -use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; +use rustc_ast::ast::{Crate, ItemKind, LitKind, ModKind, NodeId}; use rustc_ast::visit::FnKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; @@ -17,8 +18,8 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{ - BinOpKind, Block, Crate, Expr, ExprKind, HirId, Item, Local, MatchSource, MutTy, Mutability, Node, Path, Stmt, - StmtKind, Ty, TyKind, UnOp, + BinOpKind, Block, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, TyKind, + UnOp, }; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -241,7 +242,7 @@ /// /// Good: /// ```rust,ignore - /// utils::is_type_diagnostic_item(cx, ty, sym::vec_type) + /// utils::is_type_diagnostic_item(cx, ty, sym::Vec) /// ``` pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM, internal, @@ -316,7 +317,7 @@ declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); impl EarlyLintPass for ClippyLintsInternal { - fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") { if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind { if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") { @@ -411,7 +412,7 @@ } } - fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) { + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) { return; } @@ -503,10 +504,10 @@ } if_chain! { - if let ExprKind::MethodCall(path, _, args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind; let fn_name = path.ident; if let Some(sugg) = self.map.get(&*fn_name.as_str()); - let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); + let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT); then { @@ -560,9 +561,7 @@ impl EarlyLintPass for ProduceIce { fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) { - if is_trigger_fn(fn_kind) { - panic!("Would you like some help with that?"); - } + assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?"); } } @@ -893,7 +892,7 @@ }).collect(); if !check_path(cx, &path[..]); then { - span_lint(cx, CLIPPY_LINTS_INTERNAL, item.span, "invalid path"); + span_lint(cx, INVALID_PATHS, item.span, "invalid path"); } } } @@ -908,7 +907,7 @@ impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]); impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'_>) { if !self.symbol_map.is_empty() { return; } @@ -1106,16 +1105,10 @@ } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - let (cond, then, els) = match expr.kind { - ExprKind::If(cond, then, els) => (Some(cond), then, els.is_some()), - ExprKind::Match( - _, - [arm, ..], - MatchSource::IfLetDesugar { - contains_else_clause: els, - }, - ) => (None, arm.body, els), - _ => return, + let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) { + (cond, then, r#else.is_some()) + } else { + return; }; let then_block = match then.kind { ExprKind::Block(block, _) => block, @@ -1131,7 +1124,6 @@ }; // check for `if a && b;` if_chain! { - if let Some(cond) = cond; if let ExprKind::Binary(op, _, _) = cond.kind; if op.node == BinOpKind::And; if cx.sess().source_map().is_multiline(cond.span); @@ -1166,9 +1158,7 @@ _ => return, }; if_chain! { - if matches!(tail.kind, - ExprKind::If(_, _, None) - | ExprKind::Match(.., MatchSource::IfLetDesugar { contains_else_clause: false })); + if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail); let sm = cx.sess().source_map(); if head .iter() @@ -1232,5 +1222,10 @@ let sm = cx.sess().source_map(); let span = sm.span_extend_to_prev_str(span, "let", false); let span = sm.span_extend_to_next_char(span, ';', false); - Span::new(span.lo() - BytePos(3), span.hi() + BytePos(1), span.ctxt()) + Span::new( + span.lo() - BytePos(3), + span.hi() + BytePos(1), + span.ctxt(), + span.parent(), + ) } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs 2021-11-29 19:27:12.000000000 +0000 @@ -157,7 +157,7 @@ if let ExprKind::Call(func, args) = expr.kind { match func.kind { ExprKind::Path(QPath::TypeRelative(ty, name)) - if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::vec_type) => + if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) => { if name.ident.name == sym::new { return Some(VecInitKind::New); @@ -174,13 +174,13 @@ } }); } - } + }, ExprKind::Path(QPath::Resolved(_, path)) if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) - && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type) => + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => { return Some(VecInitKind::New); - } + }, _ => (), } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/vec.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/vec.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/vec.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/vec.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,3 @@ -use crate::rustc_target::abi::LayoutOf; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher; @@ -8,6 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -49,7 +49,7 @@ if_chain! { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind(); if let ty::Slice(..) = ty.kind(); - if let ExprKind::AddrOf(BorrowKind::Ref, mutability, ref addressee) = expr.kind; + if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind; if let Some(vec_args) = higher::VecArgs::hir(cx, addressee); then { self.check_vec_macro(cx, &vec_args, mutability, expr.span); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ use clippy_utils::{diagnostics::span_lint, is_lint_allowed}; -use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; +use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::DUMMY_SP; @@ -28,7 +28,7 @@ declare_lint_pass!(WildcardDependencies => [WILDCARD_DEPENDENCIES]); impl LateLintPass<'_> for WildcardDependencies { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'_>) { if is_lint_allowed(cx, WILDCARD_DEPENDENCIES, CRATE_HIR_ID) { return; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/zero_div_zero.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/zero_div_zero.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/zero_div_zero.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/zero_div_zero.rs 2021-11-29 19:27:12.000000000 +0000 @@ -32,7 +32,7 @@ // check for instances of 0.0/0.0 if_chain! { if let ExprKind::Binary(ref op, left, right) = expr.kind; - if let BinOpKind::Div = op.node; + if op.node == BinOpKind::Div; // TODO - constant_simple does not fold many operations involving floats. // That's probably fine for this lint - it's pretty unlikely that someone would // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,10 +3,10 @@ use if_chain::if_chain; use rustc_hir::{self as hir, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{Adt, Ty, TypeFoldable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use rustc_target::abi::LayoutOf as _; use rustc_typeck::hir_ty_to_ty; declare_clippy_lint! { @@ -49,7 +49,7 @@ if !hir_ty.span.from_expansion(); if !in_trait_impl(cx, hir_ty.hir_id); let ty = ty_from_hir_ty(cx, hir_ty); - if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || is_type_diagnostic_item(cx, ty, sym::BTreeMap); + if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap); if let Adt(_, substs) = ty.kind(); let ty = substs.type_at(1); // Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_utils/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_utils/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_utils/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_utils/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,16 +1,12 @@ [package] name = "clippy_utils" -version = "0.1.56" -edition = "2018" +version = "0.1.57" +edition = "2021" publish = false [dependencies] -if_chain = "1.0.0" -itertools = "0.9" -regex-syntax = "0.6" -serde = { version = "1.0", features = ["derive"] } -unicode-normalization = "0.1" -rustc-semver="1.1.0" +if_chain = "1.0" +rustc-semver = "1.1" [features] deny-warnings = [] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_utils/src/ast_utils.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_utils/src/ast_utils.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/clippy_utils/src/ast_utils.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/clippy_utils/src/ast_utils.rs 2021-11-29 19:27:12.000000000 +0000 @@ -46,15 +46,12 @@ | (Ref(l, Mutability::Not), Ref(r, Mutability::Not)) | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), - (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => { eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)) }, (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => { - lr == rr - && eq_maybe_qself(lqself, rqself) - && eq_path(lp, rp) - && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf)) + lr == rr && eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && unordered_over(lfs, rfs, eq_field_pat) }, (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), @@ -76,7 +73,7 @@ l.is_placeholder == r.is_placeholder && eq_id(l.ident, r.ident) && eq_pat(&l.pat, &r.pat) - && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + && over(&l.attrs, &r.attrs, eq_attr) } pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool { @@ -92,7 +89,7 @@ } pub fn eq_path(l: &Path, r: &Path) -> bool { - over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r)) + over(&l.segments, &r.segments, eq_path_seg) } pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool { @@ -101,9 +98,7 @@ pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool { match (l, r) { - (GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => { - over(&l.args, &r.args, |l, r| eq_angle_arg(l, r)) - }, + (GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => over(&l.args, &r.args, eq_angle_arg), (GenericArgs::Parenthesized(l), GenericArgs::Parenthesized(r)) => { over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output) }, @@ -142,7 +137,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { use ExprKind::*; - if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) { + if !over(&l.attrs, &r.attrs, eq_attr) { return false; } match (&l.kind, &r.kind) { @@ -173,20 +168,20 @@ (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2), (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv), (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp), - (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, |l, r| eq_arm(l, r)), + (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm), (Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => { lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb) }, (Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb), (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt), (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), - (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (Struct(lse), Struct(rse)) => { eq_maybe_qself(&lse.qself, &rse.qself) && eq_path(&lse.path, &rse.path) && eq_struct_rest(&lse.rest, &rse.rest) - && unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r)) + && unordered_over(&lse.fields, &rse.fields, eq_field) }, _ => false, } @@ -196,7 +191,7 @@ l.is_placeholder == r.is_placeholder && eq_id(l.ident, r.ident) && eq_expr(&l.expr, &r.expr) - && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + && over(&l.attrs, &r.attrs, eq_attr) } pub fn eq_arm(l: &Arm, r: &Arm) -> bool { @@ -204,7 +199,7 @@ && eq_pat(&l.pat, &r.pat) && eq_expr(&l.body, &r.body) && eq_expr_opt(&l.guard, &r.guard) - && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + && over(&l.attrs, &r.attrs, eq_attr) } pub fn eq_label(l: &Option

Backtrace -

- - ``` - - ``` - -

-
diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.md rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.md --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.md 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.md 2021-11-29 19:27:12.000000000 +0000 @@ -22,14 +22,14 @@ ### Meta -- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20) -- `rustc -Vv`: - ``` - rustc 1.46.0-nightly (f455e46ea 2020-06-20) - binary: rustc - commit-hash: f455e46eae1a227d735091091144601b467e1565 - commit-date: 2020-06-20 - host: x86_64-unknown-linux-gnu - release: 1.46.0-nightly - LLVM version: 10.0 - ``` +**Rust version (`rustc -Vv`):** + +``` +rustc 1.46.0-nightly (f455e46ea 2020-06-20) +binary: rustc +commit-hash: f455e46eae1a227d735091091144601b467e1565 +commit-date: 2020-06-20 +host: x86_64-unknown-linux-gnu +release: 1.46.0-nightly +LLVM version: 10.0 +``` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.md rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.md --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.md 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.md 2021-11-29 19:27:12.000000000 +0000 @@ -22,14 +22,23 @@ ### Meta -- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20) -- `rustc -Vv`: - ``` - rustc 1.46.0-nightly (f455e46ea 2020-06-20) - binary: rustc - commit-hash: f455e46eae1a227d735091091144601b467e1565 - commit-date: 2020-06-20 - host: x86_64-unknown-linux-gnu - release: 1.46.0-nightly - LLVM version: 10.0 - ``` +**Rust version (`rustc -Vv`):** +``` +rustc 1.46.0-nightly (f455e46ea 2020-06-20) +binary: rustc +commit-hash: f455e46eae1a227d735091091144601b467e1565 +commit-date: 2020-06-20 +host: x86_64-unknown-linux-gnu +release: 1.46.0-nightly +LLVM version: 10.0 +``` + + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md 2021-11-29 19:27:12.000000000 +0000 @@ -20,17 +20,16 @@ ### Meta -- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20) -- `rustc -Vv`: - ``` - rustc 1.46.0-nightly (f455e46ea 2020-06-20) - binary: rustc - commit-hash: f455e46eae1a227d735091091144601b467e1565 - commit-date: 2020-06-20 - host: x86_64-unknown-linux-gnu - release: 1.46.0-nightly - LLVM version: 10.0 - ``` +**Rust version (`rustc -Vv`):** +``` +rustc 1.46.0-nightly (f455e46ea 2020-06-20) +binary: rustc +commit-hash: f455e46eae1a227d735091091144601b467e1565 +commit-date: 2020-06-20 +host: x86_64-unknown-linux-gnu +release: 1.46.0-nightly +LLVM version: 10.0 +``` ### Error output diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.github/workflows/clippy_dev.yml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.github/workflows/clippy_dev.yml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/.github/workflows/clippy_dev.yml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/.github/workflows/clippy_dev.yml 2021-11-29 19:27:12.000000000 +0000 @@ -42,9 +42,6 @@ run: cargo build --features deny-warnings working-directory: clippy_dev - - name: Test limit_stderr_length - run: cargo dev limit_stderr_length - - name: Test update_lints run: cargo dev update_lints --check diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/lintcheck/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/lintcheck/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/lintcheck/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/lintcheck/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -11,14 +11,15 @@ [dependencies] clap = "2.33" -flate2 = {version = "1.0.19"} -fs_extra = {version = "1.2.0"} -rayon = {version = "1.5.0"} -serde = {version = "1.0", features = ["derive"]} -serde_json = {version = "1.0"} -tar = {version = "0.4.30"} -toml = {version = "0.5"} -ureq = {version = "2.0.0-rc3"} +flate2 = "1.0" +fs_extra = "1.2" +rayon = "1.5" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tar = "0.4" +toml = "0.5" +ureq = "2.2" +walkdir = "2.3" [features] deny-warnings = [] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/lintcheck/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/lintcheck/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/lintcheck/src/main.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/lintcheck/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -15,12 +15,15 @@ env, fmt, fs::write, path::{Path, PathBuf}, + thread, + time::Duration, }; use clap::{App, Arg, ArgMatches}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use serde_json::Value; +use walkdir::{DirEntry, WalkDir}; #[cfg(not(windows))] const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver"; @@ -108,6 +111,22 @@ } } +fn get(path: &str) -> Result { + const MAX_RETRIES: u8 = 4; + let mut retries = 0; + loop { + match ureq::get(path).call() { + Ok(res) => return Ok(res), + Err(e) if retries >= MAX_RETRIES => return Err(e), + Err(ureq::Error::Transport(e)) => eprintln!("Error: {}", e), + Err(e) => return Err(e), + } + eprintln!("retrying in {} seconds...", retries); + thread::sleep(Duration::from_secs(retries as u64)); + retries += 1; + } +} + impl CrateSource { /// Makes the sources available on the disk for clippy to check. /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or @@ -128,7 +147,7 @@ if !krate_file_path.is_file() { // create a file path to download and write the crate data into let mut krate_dest = std::fs::File::create(&krate_file_path).unwrap(); - let mut krate_req = ureq::get(&url).call().unwrap().into_reader(); + let mut krate_req = get(&url).unwrap().into_reader(); // copy the crate into the file std::io::copy(&mut krate_req, &mut krate_dest).unwrap(); @@ -193,32 +212,41 @@ } }, CrateSource::Path { name, path, options } => { - use fs_extra::dir; - - // simply copy the entire directory into our target dir - let copy_dest = PathBuf::from(format!("{}/", LINTCHECK_SOURCES)); - - // the source path of the crate we copied, ${copy_dest}/crate_name - let crate_root = copy_dest.join(name); // .../crates/local_crate - - if crate_root.exists() { - println!( - "Not copying {} to {}, destination already exists", - path.display(), - crate_root.display() - ); - } else { - println!("Copying {} to {}", path.display(), copy_dest.display()); - - dir::copy(path, ©_dest, &dir::CopyOptions::new()).unwrap_or_else(|_| { - panic!("Failed to copy from {}, to {}", path.display(), crate_root.display()) - }); + // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. + // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory + // as a result of this filter. + let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); + if dest_crate_root.exists() { + println!("Deleting existing directory at {:?}", dest_crate_root); + std::fs::remove_dir_all(&dest_crate_root).unwrap(); + } + + println!("Copying {:?} to {:?}", path, dest_crate_root); + + fn is_cache_dir(entry: &DirEntry) -> bool { + std::fs::read(entry.path().join("CACHEDIR.TAG")) + .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) + .unwrap_or(false) + } + + for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) { + let entry = entry.unwrap(); + let entry_path = entry.path(); + let relative_entry_path = entry_path.strip_prefix(path).unwrap(); + let dest_path = dest_crate_root.join(relative_entry_path); + let metadata = entry_path.symlink_metadata().unwrap(); + + if metadata.is_dir() { + std::fs::create_dir(dest_path).unwrap(); + } else if metadata.is_file() { + std::fs::copy(entry_path, dest_path).unwrap(); + } } Crate { version: String::from("local"), name: name.clone(), - path: crate_root, + path: dest_crate_root, options: options.clone(), } }, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/README.md rustc-1.57.0+dfsg1+llvm/src/tools/clippy/README.md --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/README.md 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/README.md 2021-11-29 19:27:12.000000000 +0000 @@ -18,7 +18,7 @@ | `clippy::style` | code that should be written in a more idiomatic way | **warn** | | `clippy::complexity` | code that does something simple but in a complex way | **warn** | | `clippy::perf` | code that can be written to run faster | **warn** | -| `clippy::pedantic` | lints which are rather strict or might have false positives | allow | +| `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow | | `clippy::nursery` | new lints that are still under development | allow | | `clippy::cargo` | lints for the cargo manifest | allow | @@ -45,13 +45,13 @@ One way to use Clippy is by installing Clippy through rustup as a cargo subcommand. -#### Step 1: Install rustup +#### Step 1: Install Rustup -You can install [rustup](https://rustup.rs/) on supported platforms. This will help +You can install [Rustup](https://rustup.rs/) on supported platforms. This will help us install Clippy and its dependencies. -If you already have rustup installed, update to ensure you have the latest -rustup and compiler: +If you already have Rustup installed, update to ensure you have the latest +Rustup and compiler: ```terminal rustup update diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/rust-toolchain rustc-1.57.0+dfsg1+llvm/src/tools/clippy/rust-toolchain --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/rust-toolchain 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/rust-toolchain 2021-11-29 19:27:12.000000000 +0000 @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-08-12" +channel = "nightly-2021-10-07" components = ["llvm-tools-preview", "rustc-dev", "rust-src"] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/src/main.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,6 @@ use rustc_tools_util::VersionInfo; use std::env; -use std::ffi::OsString; use std::path::PathBuf; use std::process::{self, Command}; @@ -14,7 +13,7 @@ cargo clippy [options] [--] [...] Common options: - --no-deps Run Clippy only on the given crate, without linting the dependencies + --no-deps Run Clippy only on the given crate, without linting the dependencies --fix Automatically apply lint suggestions. This flag implies `--no-deps` -h, --help Print this message -V, --version Print version info and exit @@ -116,22 +115,6 @@ path } - fn target_dir() -> Option<(&'static str, OsString)> { - env::var_os("CLIPPY_DOGFOOD") - .map(|_| { - env::var_os("CARGO_MANIFEST_DIR").map_or_else( - || std::ffi::OsString::from("clippy_dogfood"), - |d| { - std::path::PathBuf::from(d) - .join("target") - .join("dogfood") - .into_os_string() - }, - ) - }) - .map(|p| ("CARGO_TARGET_DIR", p)) - } - fn into_std_cmd(self) -> Command { let mut cmd = Command::new("cargo"); let clippy_args: String = self @@ -141,7 +124,6 @@ .collect(); cmd.env("RUSTC_WORKSPACE_WRAPPER", Self::path()) - .envs(ClippyCmd::target_dir()) .env("CLIPPY_ARGS", clippy_args) .arg(self.cargo_subcommand) .args(&self.args); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/cargo/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/cargo/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/cargo/mod.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/cargo/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,25 +1,3 @@ -use std::env; -use std::lazy::SyncLazy; -use std::path::PathBuf; - -pub static CARGO_TARGET_DIR: SyncLazy = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") { - Some(v) => v.into(), - None => env::current_dir().unwrap().join("target"), -}); - -pub static TARGET_LIB: SyncLazy = SyncLazy::new(|| { - if let Some(path) = option_env!("TARGET_LIBS") { - path.into() - } else { - let mut dir = CARGO_TARGET_DIR.clone(); - if let Some(target) = env::var_os("CARGO_BUILD_TARGET") { - dir.push(target); - } - dir.push(env!("PROFILE")); - dir - } -}); - #[must_use] pub fn is_rustc_test_suite() -> bool { option_env!("RUSTC_TEST_SUITE").is_some() diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/compile-test.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/compile-test.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/compile-test.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/compile-test.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,11 @@ #![feature(test)] // compiletest_rs requires this attribute -#![feature(once_cell)] -#![feature(try_blocks)] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] use compiletest_rs as compiletest; use compiletest_rs::common::Mode as TestMode; +use std::collections::HashMap; use std::env::{self, remove_var, set_var, var_os}; use std::ffi::{OsStr, OsString}; use std::fs; @@ -16,79 +17,90 @@ // whether to run internal tests or not const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints"); -fn host_lib() -> PathBuf { - option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from) -} - -fn clippy_driver_path() -> PathBuf { - option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from) -} - -// When we'll want to use `extern crate ..` for a dependency that is used -// both by the crate and the compiler itself, we can't simply pass -L flags -// as we'll get a duplicate matching versions. Instead, disambiguate with -// `--extern dep=path`. -// See https://github.com/rust-lang/rust-clippy/issues/4015. -// -// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files. -// Because it would force-rebuild if the options passed to `build` command is not the same -// as what we manually pass to `cargo` invocation -fn third_party_crates() -> String { - use std::collections::HashMap; - static CRATES: &[&str] = &[ - "clippy_lints", - "clippy_utils", - "if_chain", - "quote", - "regex", - "serde", - "serde_derive", - "syn", - ]; - let dep_dir = cargo::TARGET_LIB.join("deps"); - let mut crates: HashMap<&str, Vec> = HashMap::with_capacity(CRATES.len()); - let mut flags = String::new(); - for entry in fs::read_dir(dep_dir).unwrap().flatten() { - let path = entry.path(); - if let Some(name) = try { - let name = path.file_name()?.to_str()?; - let (name, _) = name.strip_suffix(".rlib")?.strip_prefix("lib")?.split_once('-')?; - CRATES.iter().copied().find(|&c| c == name)? - } { - flags += &format!(" --extern {}={}", name, path.display()); - crates.entry(name).or_default().push(path.clone()); - } - } - crates.retain(|_, paths| paths.len() > 1); - if !crates.is_empty() { - let crate_names = crates.keys().map(|s| format!("`{}`", s)).collect::>().join(", "); - // add backslashes for an easy copy-paste `rm` command - let paths = crates - .into_values() - .flatten() - .map(|p| strip_current_dir(&p).display().to_string()) - .collect::>() - .join(" \\\n"); - // Check which action should be done in order to remove compiled deps. - // If pre-installed version of compiler is used, `cargo clean` will do. - // Otherwise (for bootstrapped compiler), the dependencies directory - // must be removed manually. - let suggested_action = if std::env::var_os("RUSTC_BOOTSTRAP").is_some() { - "removing the stageN-tools directory" - } else { - "running `cargo clean`" +/// All crates used in UI tests are listed here +static TEST_DEPENDENCIES: &[&str] = &[ + "clippy_utils", + "derive_new", + "if_chain", + "itertools", + "quote", + "regex", + "serde", + "serde_derive", + "syn", +]; + +// Test dependencies may need an `extern crate` here to ensure that they show up +// in the depinfo file (otherwise cargo thinks they are unused) +#[allow(unused_extern_crates)] +extern crate clippy_utils; +#[allow(unused_extern_crates)] +extern crate derive_new; +#[allow(unused_extern_crates)] +extern crate if_chain; +#[allow(unused_extern_crates)] +extern crate itertools; +#[allow(unused_extern_crates)] +extern crate quote; +#[allow(unused_extern_crates)] +extern crate syn; + +/// Produces a string with an `--extern` flag for all UI test crate +/// dependencies. +/// +/// The dependency files are located by parsing the depinfo file for this test +/// module. This assumes the `-Z binary-dep-depinfo` flag is enabled. All test +/// dependencies must be added to Cargo.toml at the project root. Test +/// dependencies that are not *directly* used by this test module require an +/// `extern crate` declaration. +fn extern_flags() -> String { + let current_exe_depinfo = { + let mut path = env::current_exe().unwrap(); + path.set_extension("d"); + std::fs::read_to_string(path).unwrap() + }; + let mut crates: HashMap<&str, &str> = HashMap::with_capacity(TEST_DEPENDENCIES.len()); + for line in current_exe_depinfo.lines() { + // each dependency is expected to have a Makefile rule like `/path/to/crate-hash.rlib:` + let parse_name_path = || { + if line.starts_with(char::is_whitespace) { + return None; + } + let path_str = line.strip_suffix(':')?; + let path = Path::new(path_str); + if !matches!(path.extension()?.to_str()?, "rlib" | "so" | "dylib" | "dll") { + return None; + } + let (name, _hash) = path.file_stem()?.to_str()?.rsplit_once('-')?; + // the "lib" prefix is not present for dll files + let name = name.strip_prefix("lib").unwrap_or(name); + Some((name, path_str)) }; - - panic!( - "\n----------------------------------------------------------------------\n\ - ERROR: Found multiple rlibs for crates: {}\n\ - Try {} or remove the following files:\n\n{}\n\n\ - For details on this error see https://github.com/rust-lang/rust-clippy/issues/7343\n\ - ----------------------------------------------------------------------\n", - crate_names, suggested_action, paths - ); + if let Some((name, path)) = parse_name_path() { + if TEST_DEPENDENCIES.contains(&name) { + // A dependency may be listed twice if it is available in sysroot, + // and the sysroot dependencies are listed first. As of the writing, + // this only seems to apply to if_chain. + crates.insert(name, path); + } + } } - flags + let not_found: Vec<&str> = TEST_DEPENDENCIES + .iter() + .copied() + .filter(|n| !crates.contains_key(n)) + .collect(); + assert!( + not_found.is_empty(), + "dependencies not found in depinfo: {:?}\n\ + help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\ + help: Try adding to dev-dependencies in Cargo.toml", + not_found + ); + crates + .into_iter() + .map(|(name, path)| format!(" --extern {}={}", name, path)) + .collect() } fn default_config() -> compiletest::Config { @@ -103,16 +115,29 @@ config.run_lib_path = path.clone(); config.compile_lib_path = path; } - + let current_exe_path = std::env::current_exe().unwrap(); + let deps_path = current_exe_path.parent().unwrap(); + let profile_path = deps_path.parent().unwrap(); + + // Using `-L dependency={}` enforces that external dependencies are added with `--extern`. + // This is valuable because a) it allows us to monitor what external dependencies are used + // and b) it ensures that conflicting rlibs are resolved properly. + let host_libs = option_env!("HOST_LIBS") + .map(|p| format!(" -L dependency={}", Path::new(p).join("deps").display())) + .unwrap_or_default(); config.target_rustcflags = Some(format!( - "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}", - host_lib().join("deps").display(), - cargo::TARGET_LIB.join("deps").display(), - third_party_crates(), + "--emit=metadata -Dwarnings -Zui-testing -L dependency={}{}{}", + deps_path.display(), + host_libs, + extern_flags(), )); - config.build_base = host_lib().join("test_build_base"); - config.rustc_path = clippy_driver_path(); + config.build_base = profile_path.join("test"); + config.rustc_path = profile_path.join(if cfg!(windows) { + "clippy-driver.exe" + } else { + "clippy-driver" + }); config } @@ -315,12 +340,3 @@ } } } - -fn strip_current_dir(path: &Path) -> &Path { - if let Ok(curr) = env::current_dir() { - if let Ok(stripped) = path.strip_prefix(curr) { - return stripped; - } - } - path -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/dogfood.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/dogfood.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/dogfood.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/dogfood.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,8 @@ // Dogfood cannot run on Windows #![cfg(not(windows))] #![feature(once_cell)] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] use std::lazy::SyncLazy; use std::path::PathBuf; @@ -13,7 +15,12 @@ mod cargo; -static CLIPPY_PATH: SyncLazy = SyncLazy::new(|| cargo::TARGET_LIB.join("cargo-clippy")); +static CLIPPY_PATH: SyncLazy = SyncLazy::new(|| { + let mut path = std::env::current_exe().unwrap(); + assert!(path.pop()); // deps + path.set_file_name("cargo-clippy"); + path +}); #[test] fn dogfood_clippy() { @@ -26,7 +33,6 @@ let mut command = Command::new(&*CLIPPY_PATH); command .current_dir(root_dir) - .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") .arg("clippy") .arg("--all-targets") @@ -72,7 +78,6 @@ // Make sure that with the `--no-deps` argument Clippy does not run on `path_dep`. let output = Command::new(&*CLIPPY_PATH) .current_dir(&cwd) - .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") .arg("clippy") .args(&["-p", "subcrate"]) @@ -92,7 +97,6 @@ // Test that without the `--no-deps` argument, `path_dep` is linted. let output = Command::new(&*CLIPPY_PATH) .current_dir(&cwd) - .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") .arg("clippy") .args(&["-p", "subcrate"]) @@ -119,7 +123,6 @@ let successful_build = || { let output = Command::new(&*CLIPPY_PATH) .current_dir(&cwd) - .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") .arg("clippy") .args(&["-p", "subcrate"]) @@ -221,7 +224,6 @@ command .current_dir(root_dir.join(project)) - .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") .arg("clippy") .arg("--all-targets") diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/fmt.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/fmt.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/fmt.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/fmt.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,3 +1,6 @@ +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] + use std::path::PathBuf; use std::process::Command; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/integration.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/integration.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/integration.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/integration.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,6 @@ #![cfg(feature = "integration")] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] use std::env; use std::ffi::OsStr; @@ -72,8 +74,11 @@ panic!("incompatible crate versions"); } else if stderr.contains("failed to run `rustc` to learn about target-specific information") { panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`"); - } else if stderr.contains("toolchain") && stderr.contains("is not installed") { - panic!("missing required toolchain"); + } else { + assert!( + !stderr.contains("toolchain") || !stderr.contains("is not installed"), + "missing required toolchain" + ); } match output.status.code() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/lint_message_convention.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/lint_message_convention.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/lint_message_convention.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/lint_message_convention.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,3 +1,6 @@ +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] + use std::ffi::OsStr; use std::path::PathBuf; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/missing-test-files.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/missing-test-files.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/missing-test-files.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/missing-test-files.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::assertions_on_constants)] use std::fs::{self, DirEntry}; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/approx_const.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/approx_const.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/approx_const.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/approx_const.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ #[warn(clippy::approx_constant)] -#[allow(unused, clippy::shadow_unrelated, clippy::similar_names)] +#[allow(clippy::similar_names)] fn main() { let my_e = 2.7182; let almost_e = 2.718; @@ -57,4 +57,8 @@ let my_sq2 = 1.4142; let no_sq2 = 1.414; + + let my_tau = 6.2832; + let almost_tau = 6.28; + let no_tau = 6.3; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/approx_const.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/approx_const.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/approx_const.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/approx_const.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,130 +1,187 @@ -error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::E` found --> $DIR/approx_const.rs:4:16 | LL | let my_e = 2.7182; | ^^^^^^ | = note: `-D clippy::approx-constant` implied by `-D warnings` + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::E` found --> $DIR/approx_const.rs:5:20 | LL | let almost_e = 2.718; | ^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_1_PI` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_1_PI` found --> $DIR/approx_const.rs:8:24 | LL | let my_1_frac_pi = 0.3183; | ^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found --> $DIR/approx_const.rs:11:28 | LL | let my_frac_1_sqrt_2 = 0.70710678; | ^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found --> $DIR/approx_const.rs:12:32 | LL | let almost_frac_1_sqrt_2 = 0.70711; | ^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_2_PI` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_2_PI` found --> $DIR/approx_const.rs:15:24 | LL | let my_frac_2_pi = 0.63661977; | ^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found --> $DIR/approx_const.rs:18:27 | LL | let my_frac_2_sq_pi = 1.128379; | ^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_PI_2` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_PI_2` found --> $DIR/approx_const.rs:21:24 | LL | let my_frac_pi_2 = 1.57079632679; | ^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_PI_3` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_PI_3` found --> $DIR/approx_const.rs:24:24 | LL | let my_frac_pi_3 = 1.04719755119; | ^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_PI_4` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_PI_4` found --> $DIR/approx_const.rs:27:24 | LL | let my_frac_pi_4 = 0.785398163397; | ^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_PI_6` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_PI_6` found --> $DIR/approx_const.rs:30:24 | LL | let my_frac_pi_6 = 0.523598775598; | ^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::FRAC_PI_8` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::FRAC_PI_8` found --> $DIR/approx_const.rs:33:24 | LL | let my_frac_pi_8 = 0.3926990816987; | ^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::LN_10` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::LN_10` found --> $DIR/approx_const.rs:36:20 | LL | let my_ln_10 = 2.302585092994046; | ^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::LN_2` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::LN_2` found --> $DIR/approx_const.rs:39:19 | LL | let my_ln_2 = 0.6931471805599453; | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::LOG10_E` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::LOG10_E` found --> $DIR/approx_const.rs:42:22 | LL | let my_log10_e = 0.4342944819032518; | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::LOG2_E` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::LOG2_E` found --> $DIR/approx_const.rs:45:21 | LL | let my_log2_e = 1.4426950408889634; | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::LOG2_10` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::LOG2_10` found --> $DIR/approx_const.rs:48:19 | LL | let log2_10 = 3.321928094887362; | ^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::LOG10_2` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::LOG10_2` found --> $DIR/approx_const.rs:51:19 | LL | let log10_2 = 0.301029995663981; | ^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::PI` found --> $DIR/approx_const.rs:54:17 | LL | let my_pi = 3.1415; | ^^^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::PI` found --> $DIR/approx_const.rs:55:21 | LL | let almost_pi = 3.14; | ^^^^ + | + = help: consider using the constant directly -error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::SQRT_2` found --> $DIR/approx_const.rs:58:18 | LL | let my_sq2 = 1.4142; | ^^^^^^ + | + = help: consider using the constant directly + +error: approximate value of `f{32, 64}::consts::TAU` found + --> $DIR/approx_const.rs:61:18 + | +LL | let my_tau = 6.2832; + | ^^^^^^ + | + = help: consider using the constant directly + +error: approximate value of `f{32, 64}::consts::TAU` found + --> $DIR/approx_const.rs:62:22 + | +LL | let almost_tau = 6.28; + | ^^^^ + | + = help: consider using the constant directly -error: aborting due to 21 previous errors +error: aborting due to 23 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/asm_syntax.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/asm_syntax.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/asm_syntax.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/asm_syntax.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/asm_syntax.rs:9:9 | LL | asm!(""); - | ^^^^^^^^^ + | ^^^^^^^^ | = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` = help: use AT&T x86 assembly syntax @@ -11,7 +11,7 @@ --> $DIR/asm_syntax.rs:10:9 | LL | asm!("", options()); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = help: use AT&T x86 assembly syntax @@ -19,7 +19,7 @@ --> $DIR/asm_syntax.rs:11:9 | LL | asm!("", options(nostack)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use AT&T x86 assembly syntax @@ -27,7 +27,7 @@ --> $DIR/asm_syntax.rs:23:9 | LL | asm!("", options(att_syntax)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` = help: use Intel x86 assembly syntax @@ -36,7 +36,7 @@ --> $DIR/asm_syntax.rs:24:9 | LL | asm!("", options(nostack, att_syntax)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use Intel x86 assembly syntax diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/assertions_on_constants.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/assertions_on_constants.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/assertions_on_constants.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/assertions_on_constants.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/assertions_on_constants.rs:11:5 | LL | assert!(true); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: `-D clippy::assertions-on-constants` implied by `-D warnings` = help: remove it @@ -12,7 +12,7 @@ --> $DIR/assertions_on_constants.rs:12:5 | LL | assert!(false); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: use `panic!()` or `unreachable!()` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -21,7 +21,7 @@ --> $DIR/assertions_on_constants.rs:13:5 | LL | assert!(true, "true message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: remove it = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -30,7 +30,7 @@ --> $DIR/assertions_on_constants.rs:14:5 | LL | assert!(false, "false message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `panic!("false message")` or `unreachable!("false message")` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -39,7 +39,7 @@ --> $DIR/assertions_on_constants.rs:17:5 | LL | assert!(false, msg.to_uppercase()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -48,7 +48,7 @@ --> $DIR/assertions_on_constants.rs:20:5 | LL | assert!(B); - | ^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: remove it = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -57,7 +57,7 @@ --> $DIR/assertions_on_constants.rs:23:5 | LL | assert!(C); - | ^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: use `panic!()` or `unreachable!()` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -66,7 +66,7 @@ --> $DIR/assertions_on_constants.rs:24:5 | LL | assert!(C, "C message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `panic!("C message")` or `unreachable!("C message")` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -75,7 +75,7 @@ --> $DIR/assertions_on_constants.rs:26:5 | LL | debug_assert!(true); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = help: remove it = note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs 2021-11-29 19:27:12.000000000 +0000 @@ -53,3 +53,12 @@ self.foo as usize } } + +#[derive(Copy, Clone)] +pub struct IteratorMethodFalsePositives; + +impl IteratorMethodFalsePositives { + pub fn filter(&self, _s: i32) -> std::vec::IntoIter { + unimplemented!(); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,75 @@ +// compile-flags: --emit=link +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::{token_stream, Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +use std::iter::FromIterator; + +fn read_ident(iter: &mut token_stream::IntoIter) -> Ident { + match iter.next() { + Some(TokenTree::Ident(i)) => i, + _ => panic!("expected ident"), + } +} + +#[proc_macro_derive(DeriveBadSpan)] +pub fn derive_bad_span(input: TokenStream) -> TokenStream { + let mut input = input.into_iter(); + assert_eq!(read_ident(&mut input).to_string(), "struct"); + let ident = read_ident(&mut input); + let mut tys = match input.next() { + Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => g.stream().into_iter(), + _ => panic!(), + }; + let field1 = read_ident(&mut tys); + tys.next(); + let field2 = read_ident(&mut tys); + + >::from_iter( + [ + Ident::new("impl", Span::call_site()).into(), + ident.into(), + Group::new( + Delimiter::Brace, + >::from_iter( + [ + Ident::new("fn", Span::call_site()).into(), + Ident::new("_foo", Span::call_site()).into(), + Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), + Group::new( + Delimiter::Brace, + >::from_iter( + [ + Ident::new("if", field1.span()).into(), + Ident::new("true", field1.span()).into(), + { + let mut group = Group::new(Delimiter::Brace, TokenStream::new()); + group.set_span(field1.span()); + group.into() + }, + Ident::new("if", field2.span()).into(), + Ident::new("true", field2.span()).into(), + { + let mut group = Group::new(Delimiter::Brace, TokenStream::new()); + group.set_span(field2.span()); + group.into() + }, + ] + .iter() + .cloned(), + ), + ) + .into(), + ] + .iter() + .cloned(), + ), + ) + .into(), + ] + .iter() + .cloned(), + ) +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/bool_assert_comparison.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/bool_assert_comparison.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/bool_assert_comparison.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/bool_assert_comparison.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,7 @@ #![warn(clippy::bool_assert_comparison)] +use std::ops::Not; + macro_rules! a { () => { true @@ -11,7 +13,58 @@ }; } +// Implements the Not trait but with an output type +// that's not bool. Should not suggest a rewrite +#[derive(Debug)] +enum ImplNotTraitWithoutBool { + VariantX(bool), + VariantY(u32), +} + +impl PartialEq for ImplNotTraitWithoutBool { + fn eq(&self, other: &bool) -> bool { + match *self { + ImplNotTraitWithoutBool::VariantX(b) => b == *other, + _ => false, + } + } +} + +impl Not for ImplNotTraitWithoutBool { + type Output = Self; + + fn not(self) -> Self::Output { + match self { + ImplNotTraitWithoutBool::VariantX(b) => ImplNotTraitWithoutBool::VariantX(!b), + ImplNotTraitWithoutBool::VariantY(0) => ImplNotTraitWithoutBool::VariantY(1), + ImplNotTraitWithoutBool::VariantY(_) => ImplNotTraitWithoutBool::VariantY(0), + } + } +} + +// This type implements the Not trait with an Output of +// type bool. Using assert!(..) must be suggested +#[derive(Debug)] +struct ImplNotTraitWithBool; + +impl PartialEq for ImplNotTraitWithBool { + fn eq(&self, other: &bool) -> bool { + false + } +} + +impl Not for ImplNotTraitWithBool { + type Output = bool; + + fn not(self) -> Self::Output { + true + } +} + fn main() { + let a = ImplNotTraitWithoutBool::VariantX(true); + let b = ImplNotTraitWithBool; + assert_eq!("a".len(), 1); assert_eq!("a".is_empty(), false); assert_eq!("".is_empty(), true); @@ -19,6 +72,8 @@ assert_eq!(a!(), b!()); assert_eq!(a!(), "".is_empty()); assert_eq!("".is_empty(), b!()); + assert_eq!(a, true); + assert_eq!(b, true); assert_ne!("a".len(), 1); assert_ne!("a".is_empty(), false); @@ -27,6 +82,8 @@ assert_ne!(a!(), b!()); assert_ne!(a!(), "".is_empty()); assert_ne!("".is_empty(), b!()); + assert_ne!(a, true); + assert_ne!(b, true); debug_assert_eq!("a".len(), 1); debug_assert_eq!("a".is_empty(), false); @@ -35,6 +92,8 @@ debug_assert_eq!(a!(), b!()); debug_assert_eq!(a!(), "".is_empty()); debug_assert_eq!("".is_empty(), b!()); + debug_assert_eq!(a, true); + debug_assert_eq!(b, true); debug_assert_ne!("a".len(), 1); debug_assert_ne!("a".is_empty(), false); @@ -43,6 +102,8 @@ debug_assert_ne!(a!(), b!()); debug_assert_ne!(a!(), "".is_empty()); debug_assert_ne!("".is_empty(), b!()); + debug_assert_ne!(a, true); + debug_assert_ne!(b, true); // assert with error messages assert_eq!("a".len(), 1, "tadam {}", 1); @@ -50,10 +111,12 @@ assert_eq!("a".is_empty(), false, "tadam {}", 1); assert_eq!("a".is_empty(), false, "tadam {}", true); assert_eq!(false, "a".is_empty(), "tadam {}", true); + assert_eq!(a, true, "tadam {}", false); debug_assert_eq!("a".len(), 1, "tadam {}", 1); debug_assert_eq!("a".len(), 1, "tadam {}", true); debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); debug_assert_eq!("a".is_empty(), false, "tadam {}", true); debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); + debug_assert_eq!(a, true, "tadam {}", false); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/bool_assert_comparison.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/bool_assert_comparison.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/bool_assert_comparison.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/bool_assert_comparison.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,112 +1,136 @@ error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:16:5 + --> $DIR/bool_assert_comparison.rs:69:5 | LL | assert_eq!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = note: `-D clippy::bool-assert-comparison` implied by `-D warnings` error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:17:5 + --> $DIR/bool_assert_comparison.rs:70:5 | LL | assert_eq!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:18:5 + --> $DIR/bool_assert_comparison.rs:71:5 | LL | assert_eq!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + +error: used `assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:76:5 + | +LL | assert_eq!(b, true); + | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:24:5 + --> $DIR/bool_assert_comparison.rs:79:5 | LL | assert_ne!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:25:5 + --> $DIR/bool_assert_comparison.rs:80:5 | LL | assert_ne!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:26:5 + --> $DIR/bool_assert_comparison.rs:81:5 | LL | assert_ne!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + +error: used `assert_ne!` with a literal bool + --> $DIR/bool_assert_comparison.rs:86:5 + | +LL | assert_ne!(b, true); + | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:32:5 + --> $DIR/bool_assert_comparison.rs:89:5 | LL | debug_assert_eq!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:33:5 + --> $DIR/bool_assert_comparison.rs:90:5 | LL | debug_assert_eq!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:34:5 + --> $DIR/bool_assert_comparison.rs:91:5 | LL | debug_assert_eq!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + +error: used `debug_assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:96:5 + | +LL | debug_assert_eq!(b, true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:40:5 + --> $DIR/bool_assert_comparison.rs:99:5 | LL | debug_assert_ne!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:41:5 + --> $DIR/bool_assert_comparison.rs:100:5 | LL | debug_assert_ne!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:42:5 + --> $DIR/bool_assert_comparison.rs:101:5 | LL | debug_assert_ne!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + +error: used `debug_assert_ne!` with a literal bool + --> $DIR/bool_assert_comparison.rs:106:5 + | +LL | debug_assert_ne!(b, true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:50:5 + --> $DIR/bool_assert_comparison.rs:111:5 | LL | assert_eq!("a".is_empty(), false, "tadam {}", 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:51:5 + --> $DIR/bool_assert_comparison.rs:112:5 | LL | assert_eq!("a".is_empty(), false, "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:52:5 + --> $DIR/bool_assert_comparison.rs:113:5 | LL | assert_eq!(false, "a".is_empty(), "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:56:5 + --> $DIR/bool_assert_comparison.rs:118:5 | LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:57:5 + --> $DIR/bool_assert_comparison.rs:119:5 | LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:58:5 + --> $DIR/bool_assert_comparison.rs:120:5 | LL | debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` -error: aborting due to 18 previous errors +error: aborting due to 22 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_collection.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_collection.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_collection.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_collection.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,44 @@ +#![warn(clippy::all)] +#![allow( + clippy::boxed_local, + clippy::needless_pass_by_value, + clippy::blacklisted_name, + unused +)] + +use std::collections::HashMap; + +macro_rules! boxit { + ($init:expr, $x:ty) => { + let _: Box<$x> = Box::new($init); + }; +} + +fn test_macro() { + boxit!(Vec::new(), Vec); +} + +fn test(foo: Box>) {} + +fn test2(foo: Box)>) { + // pass if #31 is fixed + foo(vec![1, 2, 3]) +} + +fn test3(foo: Box) {} + +fn test4(foo: Box>) {} + +fn test_local_not_linted() { + let _: Box>; +} + +// All of these test should be allowed because they are part of the +// public api and `avoid_breaking_exported_api` is `false` by default. +pub fn pub_test(foo: Box>) {} + +pub fn pub_test_ret() -> Box> { + Box::new(Vec::new()) +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_collection.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_collection.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_collection.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_collection.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,27 @@ +error: you seem to be trying to use `Box>`. Consider using just `Vec<..>` + --> $DIR/box_collection.rs:21:14 + | +LL | fn test(foo: Box>) {} + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::box-collection` implied by `-D warnings` + = help: `Vec<..>` is already on the heap, `Box>` makes an extra allocation + +error: you seem to be trying to use `Box`. Consider using just `String` + --> $DIR/box_collection.rs:28:15 + | +LL | fn test3(foo: Box) {} + | ^^^^^^^^^^^ + | + = help: `String` is already on the heap, `Box` makes an extra allocation + +error: you seem to be trying to use `Box>`. Consider using just `HashMap<..>` + --> $DIR/box_collection.rs:30:15 + | +LL | fn test4(foo: Box>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `HashMap<..>` is already on the heap, `Box>` makes an extra allocation + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_vec.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_vec.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_vec.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_vec.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -#![warn(clippy::all)] -#![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name)] - -macro_rules! boxit { - ($init:expr, $x:ty) => { - let _: Box<$x> = Box::new($init); - }; -} - -fn test_macro() { - boxit!(Vec::new(), Vec); -} -pub fn test(foo: Box>) { - println!("{:?}", foo.get(0)) -} - -pub fn test2(foo: Box)>) { - // pass if #31 is fixed - foo(vec![1, 2, 3]) -} - -pub fn test_local_not_linted() { - let _: Box>; -} - -fn main() { - test(Box::new(Vec::new())); - test2(Box::new(|v| println!("{:?}", v))); - test_macro(); - test_local_not_linted(); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_vec.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_vec.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_vec.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/box_vec.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -error: you seem to be trying to use `Box>`. Consider using just `Vec` - --> $DIR/box_vec.rs:14:18 - | -LL | pub fn test(foo: Box>) { - | ^^^^^^^^^^^^^^ - | - = note: `-D clippy::box-vec` implied by `-D warnings` - = help: `Vec` is already on the heap, `Box>` makes an extra allocation - -error: aborting due to previous error - diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -#![allow(dead_code)] +#![allow(dead_code, clippy::equatable_if_let)] #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] // This tests the branches_sharing_code lint at the end of blocks diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -6,24 +6,24 @@ fn main() { // Test clippy::cast_lossless with casts to floating-point types let x0 = 1i8; - f32::from(x0); - f64::from(x0); + let _ = f32::from(x0); + let _ = f64::from(x0); let x1 = 1u8; - f32::from(x1); - f64::from(x1); + let _ = f32::from(x1); + let _ = f64::from(x1); let x2 = 1i16; - f32::from(x2); - f64::from(x2); + let _ = f32::from(x2); + let _ = f64::from(x2); let x3 = 1u16; - f32::from(x3); - f64::from(x3); + let _ = f32::from(x3); + let _ = f64::from(x3); let x4 = 1i32; - f64::from(x4); + let _ = f64::from(x4); let x5 = 1u32; - f64::from(x5); + let _ = f64::from(x5); // Test with casts from floating-point types - f64::from(1.0f32); + let _ = f64::from(1.0f32); } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,24 +6,24 @@ fn main() { // Test clippy::cast_lossless with casts to floating-point types let x0 = 1i8; - x0 as f32; - x0 as f64; + let _ = x0 as f32; + let _ = x0 as f64; let x1 = 1u8; - x1 as f32; - x1 as f64; + let _ = x1 as f32; + let _ = x1 as f64; let x2 = 1i16; - x2 as f32; - x2 as f64; + let _ = x2 as f32; + let _ = x2 as f64; let x3 = 1u16; - x3 as f32; - x3 as f64; + let _ = x3 as f32; + let _ = x3 as f64; let x4 = 1i32; - x4 as f64; + let _ = x4 as f64; let x5 = 1u32; - x5 as f64; + let _ = x5 as f64; // Test with casts from floating-point types - 1.0f32 as f64; + let _ = 1.0f32 as f64; } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_float.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,70 +1,70 @@ error: casting `i8` to `f32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:9:5 + --> $DIR/cast_lossless_float.rs:9:13 | -LL | x0 as f32; - | ^^^^^^^^^ help: try: `f32::from(x0)` +LL | let _ = x0 as f32; + | ^^^^^^^^^ help: try: `f32::from(x0)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting `i8` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:10:5 + --> $DIR/cast_lossless_float.rs:10:13 | -LL | x0 as f64; - | ^^^^^^^^^ help: try: `f64::from(x0)` +LL | let _ = x0 as f64; + | ^^^^^^^^^ help: try: `f64::from(x0)` error: casting `u8` to `f32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:12:5 + --> $DIR/cast_lossless_float.rs:12:13 | -LL | x1 as f32; - | ^^^^^^^^^ help: try: `f32::from(x1)` +LL | let _ = x1 as f32; + | ^^^^^^^^^ help: try: `f32::from(x1)` error: casting `u8` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:13:5 + --> $DIR/cast_lossless_float.rs:13:13 | -LL | x1 as f64; - | ^^^^^^^^^ help: try: `f64::from(x1)` +LL | let _ = x1 as f64; + | ^^^^^^^^^ help: try: `f64::from(x1)` error: casting `i16` to `f32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:15:5 + --> $DIR/cast_lossless_float.rs:15:13 | -LL | x2 as f32; - | ^^^^^^^^^ help: try: `f32::from(x2)` +LL | let _ = x2 as f32; + | ^^^^^^^^^ help: try: `f32::from(x2)` error: casting `i16` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:16:5 + --> $DIR/cast_lossless_float.rs:16:13 | -LL | x2 as f64; - | ^^^^^^^^^ help: try: `f64::from(x2)` +LL | let _ = x2 as f64; + | ^^^^^^^^^ help: try: `f64::from(x2)` error: casting `u16` to `f32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:18:5 + --> $DIR/cast_lossless_float.rs:18:13 | -LL | x3 as f32; - | ^^^^^^^^^ help: try: `f32::from(x3)` +LL | let _ = x3 as f32; + | ^^^^^^^^^ help: try: `f32::from(x3)` error: casting `u16` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:19:5 + --> $DIR/cast_lossless_float.rs:19:13 | -LL | x3 as f64; - | ^^^^^^^^^ help: try: `f64::from(x3)` +LL | let _ = x3 as f64; + | ^^^^^^^^^ help: try: `f64::from(x3)` error: casting `i32` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:21:5 + --> $DIR/cast_lossless_float.rs:21:13 | -LL | x4 as f64; - | ^^^^^^^^^ help: try: `f64::from(x4)` +LL | let _ = x4 as f64; + | ^^^^^^^^^ help: try: `f64::from(x4)` error: casting `u32` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:23:5 + --> $DIR/cast_lossless_float.rs:23:13 | -LL | x5 as f64; - | ^^^^^^^^^ help: try: `f64::from(x5)` +LL | let _ = x5 as f64; + | ^^^^^^^^^ help: try: `f64::from(x5)` error: casting `f32` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:26:5 + --> $DIR/cast_lossless_float.rs:26:13 | -LL | 1.0f32 as f64; - | ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)` +LL | let _ = 1.0f32 as f64; + | ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)` error: aborting due to 11 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -5,27 +5,27 @@ fn main() { // Test clippy::cast_lossless with casts to integer types - i16::from(1i8); - i32::from(1i8); - i64::from(1i8); - i16::from(1u8); - i32::from(1u8); - i64::from(1u8); - u16::from(1u8); - u32::from(1u8); - u64::from(1u8); - i32::from(1i16); - i64::from(1i16); - i32::from(1u16); - i64::from(1u16); - u32::from(1u16); - u64::from(1u16); - i64::from(1i32); - i64::from(1u32); - u64::from(1u32); + let _ = i16::from(1i8); + let _ = i32::from(1i8); + let _ = i64::from(1i8); + let _ = i16::from(1u8); + let _ = i32::from(1u8); + let _ = i64::from(1u8); + let _ = u16::from(1u8); + let _ = u32::from(1u8); + let _ = u64::from(1u8); + let _ = i32::from(1i16); + let _ = i64::from(1i16); + let _ = i32::from(1u16); + let _ = i64::from(1u16); + let _ = u32::from(1u16); + let _ = u64::from(1u16); + let _ = i64::from(1i32); + let _ = i64::from(1u32); + let _ = u64::from(1u32); // Test with an expression wrapped in parens - u16::from(1u8 + 1u8); + let _ = u16::from(1u8 + 1u8); } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.rs 2021-11-29 19:27:12.000000000 +0000 @@ -5,27 +5,27 @@ fn main() { // Test clippy::cast_lossless with casts to integer types - 1i8 as i16; - 1i8 as i32; - 1i8 as i64; - 1u8 as i16; - 1u8 as i32; - 1u8 as i64; - 1u8 as u16; - 1u8 as u32; - 1u8 as u64; - 1i16 as i32; - 1i16 as i64; - 1u16 as i32; - 1u16 as i64; - 1u16 as u32; - 1u16 as u64; - 1i32 as i64; - 1u32 as i64; - 1u32 as u64; + let _ = 1i8 as i16; + let _ = 1i8 as i32; + let _ = 1i8 as i64; + let _ = 1u8 as i16; + let _ = 1u8 as i32; + let _ = 1u8 as i64; + let _ = 1u8 as u16; + let _ = 1u8 as u32; + let _ = 1u8 as u64; + let _ = 1i16 as i32; + let _ = 1i16 as i64; + let _ = 1u16 as i32; + let _ = 1u16 as i64; + let _ = 1u16 as u32; + let _ = 1u16 as u64; + let _ = 1i32 as i64; + let _ = 1u32 as i64; + let _ = 1u32 as u64; // Test with an expression wrapped in parens - (1u8 + 1u8) as u16; + let _ = (1u8 + 1u8) as u16; } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/cast_lossless_integer.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,118 +1,118 @@ error: casting `i8` to `i16` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:8:5 + --> $DIR/cast_lossless_integer.rs:8:13 | -LL | 1i8 as i16; - | ^^^^^^^^^^ help: try: `i16::from(1i8)` +LL | let _ = 1i8 as i16; + | ^^^^^^^^^^ help: try: `i16::from(1i8)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting `i8` to `i32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:9:5 + --> $DIR/cast_lossless_integer.rs:9:13 | -LL | 1i8 as i32; - | ^^^^^^^^^^ help: try: `i32::from(1i8)` +LL | let _ = 1i8 as i32; + | ^^^^^^^^^^ help: try: `i32::from(1i8)` error: casting `i8` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:10:5 + --> $DIR/cast_lossless_integer.rs:10:13 | -LL | 1i8 as i64; - | ^^^^^^^^^^ help: try: `i64::from(1i8)` +LL | let _ = 1i8 as i64; + | ^^^^^^^^^^ help: try: `i64::from(1i8)` error: casting `u8` to `i16` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:11:5 + --> $DIR/cast_lossless_integer.rs:11:13 | -LL | 1u8 as i16; - | ^^^^^^^^^^ help: try: `i16::from(1u8)` +LL | let _ = 1u8 as i16; + | ^^^^^^^^^^ help: try: `i16::from(1u8)` error: casting `u8` to `i32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:12:5 + --> $DIR/cast_lossless_integer.rs:12:13 | -LL | 1u8 as i32; - | ^^^^^^^^^^ help: try: `i32::from(1u8)` +LL | let _ = 1u8 as i32; + | ^^^^^^^^^^ help: try: `i32::from(1u8)` error: casting `u8` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:13:5 + --> $DIR/cast_lossless_integer.rs:13:13 | -LL | 1u8 as i64; - | ^^^^^^^^^^ help: try: `i64::from(1u8)` +LL | let _ = 1u8 as i64; + | ^^^^^^^^^^ help: try: `i64::from(1u8)` error: casting `u8` to `u16` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:14:5 + --> $DIR/cast_lossless_integer.rs:14:13 | -LL | 1u8 as u16; - | ^^^^^^^^^^ help: try: `u16::from(1u8)` +LL | let _ = 1u8 as u16; + | ^^^^^^^^^^ help: try: `u16::from(1u8)` error: casting `u8` to `u32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:15:5 + --> $DIR/cast_lossless_integer.rs:15:13 | -LL | 1u8 as u32; - | ^^^^^^^^^^ help: try: `u32::from(1u8)` +LL | let _ = 1u8 as u32; + | ^^^^^^^^^^ help: try: `u32::from(1u8)` error: casting `u8` to `u64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:16:5 + --> $DIR/cast_lossless_integer.rs:16:13 | -LL | 1u8 as u64; - | ^^^^^^^^^^ help: try: `u64::from(1u8)` +LL | let _ = 1u8 as u64; + | ^^^^^^^^^^ help: try: `u64::from(1u8)` error: casting `i16` to `i32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:17:5 + --> $DIR/cast_lossless_integer.rs:17:13 | -LL | 1i16 as i32; - | ^^^^^^^^^^^ help: try: `i32::from(1i16)` +LL | let _ = 1i16 as i32; + | ^^^^^^^^^^^ help: try: `i32::from(1i16)` error: casting `i16` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:18:5 + --> $DIR/cast_lossless_integer.rs:18:13 | -LL | 1i16 as i64; - | ^^^^^^^^^^^ help: try: `i64::from(1i16)` +LL | let _ = 1i16 as i64; + | ^^^^^^^^^^^ help: try: `i64::from(1i16)` error: casting `u16` to `i32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:19:5 + --> $DIR/cast_lossless_integer.rs:19:13 | -LL | 1u16 as i32; - | ^^^^^^^^^^^ help: try: `i32::from(1u16)` +LL | let _ = 1u16 as i32; + | ^^^^^^^^^^^ help: try: `i32::from(1u16)` error: casting `u16` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:20:5 + --> $DIR/cast_lossless_integer.rs:20:13 | -LL | 1u16 as i64; - | ^^^^^^^^^^^ help: try: `i64::from(1u16)` +LL | let _ = 1u16 as i64; + | ^^^^^^^^^^^ help: try: `i64::from(1u16)` error: casting `u16` to `u32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:21:5 + --> $DIR/cast_lossless_integer.rs:21:13 | -LL | 1u16 as u32; - | ^^^^^^^^^^^ help: try: `u32::from(1u16)` +LL | let _ = 1u16 as u32; + | ^^^^^^^^^^^ help: try: `u32::from(1u16)` error: casting `u16` to `u64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:22:5 + --> $DIR/cast_lossless_integer.rs:22:13 | -LL | 1u16 as u64; - | ^^^^^^^^^^^ help: try: `u64::from(1u16)` +LL | let _ = 1u16 as u64; + | ^^^^^^^^^^^ help: try: `u64::from(1u16)` error: casting `i32` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:23:5 + --> $DIR/cast_lossless_integer.rs:23:13 | -LL | 1i32 as i64; - | ^^^^^^^^^^^ help: try: `i64::from(1i32)` +LL | let _ = 1i32 as i64; + | ^^^^^^^^^^^ help: try: `i64::from(1i32)` error: casting `u32` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:24:5 + --> $DIR/cast_lossless_integer.rs:24:13 | -LL | 1u32 as i64; - | ^^^^^^^^^^^ help: try: `i64::from(1u32)` +LL | let _ = 1u32 as i64; + | ^^^^^^^^^^^ help: try: `i64::from(1u32)` error: casting `u32` to `u64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:25:5 + --> $DIR/cast_lossless_integer.rs:25:13 | -LL | 1u32 as u64; - | ^^^^^^^^^^^ help: try: `u64::from(1u32)` +LL | let _ = 1u32 as u64; + | ^^^^^^^^^^^ help: try: `u64::from(1u32)` error: casting `u8` to `u16` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:28:5 + --> $DIR/cast_lossless_integer.rs:28:13 | -LL | (1u8 + 1u8) as u16; - | ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)` +LL | let _ = (1u8 + 1u8) as u16; + | ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)` error: aborting due to 19 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,8 @@ -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap` on `x` after checking its variant with `is_some` --> $DIR/complex_conditionals_nested.rs:8:13 | LL | if x.is_some() { - | ----------- the check is happening here + | -------------- help: try: `if let Some(..) = x` LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ | diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap` on `x` after checking its variant with `is_ok` --> $DIR/complex_conditionals.rs:8:9 | LL | if x.is_ok() && y.is_err() { @@ -11,6 +11,7 @@ | LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic --> $DIR/complex_conditionals.rs:9:9 @@ -36,7 +37,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap_err` on `y` after checking its variant with `is_err` --> $DIR/complex_conditionals.rs:11:9 | LL | if x.is_ok() && y.is_err() { @@ -44,6 +45,8 @@ ... LL | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ + | + = help: try using `if let` or `match` error: this call to `unwrap()` will always panic --> $DIR/complex_conditionals.rs:25:9 @@ -54,7 +57,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap_err` on `x` after checking its variant with `is_ok` --> $DIR/complex_conditionals.rs:26:9 | LL | if x.is_ok() || y.is_ok() { @@ -62,6 +65,8 @@ ... LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ + | + = help: try using `if let` or `match` error: this call to `unwrap()` will always panic --> $DIR/complex_conditionals.rs:27:9 @@ -72,7 +77,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap_err` on `y` after checking its variant with `is_ok` --> $DIR/complex_conditionals.rs:28:9 | LL | if x.is_ok() || y.is_ok() { @@ -80,14 +85,18 @@ ... LL | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ + | + = help: try using `if let` or `match` -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap` on `x` after checking its variant with `is_ok` --> $DIR/complex_conditionals.rs:32:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ + | + = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic --> $DIR/complex_conditionals.rs:33:9 @@ -107,7 +116,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap_err` on `y` after checking its variant with `is_ok` --> $DIR/complex_conditionals.rs:35:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { @@ -115,8 +124,10 @@ ... LL | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ + | + = help: try using `if let` or `match` -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap` on `z` after checking its variant with `is_err` --> $DIR/complex_conditionals.rs:36:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { @@ -124,6 +135,8 @@ ... LL | z.unwrap(); // unnecessary | ^^^^^^^^^^ + | + = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic --> $DIR/complex_conditionals.rs:37:9 @@ -143,7 +156,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap_err` on `x` after checking its variant with `is_ok` --> $DIR/complex_conditionals.rs:46:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { @@ -151,8 +164,10 @@ ... LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ + | + = help: try using `if let` or `match` -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap` on `y` after checking its variant with `is_ok` --> $DIR/complex_conditionals.rs:47:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { @@ -160,6 +175,8 @@ ... LL | y.unwrap(); // unnecessary | ^^^^^^^^^^ + | + = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic --> $DIR/complex_conditionals.rs:48:9 @@ -179,7 +196,7 @@ LL | z.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap_err` on `z` after checking its variant with `is_err` --> $DIR/complex_conditionals.rs:50:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { @@ -187,6 +204,8 @@ ... LL | z.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ + | + = help: try using `if let` or `match` error: aborting due to 20 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs 2021-11-29 19:27:12.000000000 +0000 @@ -37,8 +37,10 @@ let x = Some(()); if x.is_some() { x.unwrap(); // unnecessary + x.expect("an error message"); // unnecessary } else { x.unwrap(); // will panic + x.expect("an error message"); // will panic } if x.is_none() { x.unwrap(); // will panic @@ -52,9 +54,11 @@ let mut x: Result<(), ()> = Ok(()); if x.is_ok() { x.unwrap(); // unnecessary + x.expect("an error message"); // unnecessary x.unwrap_err(); // will panic } else { x.unwrap(); // will panic + x.expect("an error message"); // will panic x.unwrap_err(); // unnecessary } if x.is_err() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,8 +1,8 @@ -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap` on `x` after checking its variant with `is_some` --> $DIR/simple_conditionals.rs:39:9 | LL | if x.is_some() { - | ----------- the check is happening here + | -------------- help: try: `if let Some(..) = x` LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ | @@ -12,8 +12,17 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: called `expect` on `x` after checking its variant with `is_some` + --> $DIR/simple_conditionals.rs:40:9 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some(..) = x` +LL | x.unwrap(); // unnecessary +LL | x.expect("an error message"); // unnecessary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:41:9 + --> $DIR/simple_conditionals.rs:42:9 | LL | if x.is_some() { | ----------- because of this check @@ -27,55 +36,73 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: this call to `expect()` will always panic + --> $DIR/simple_conditionals.rs:43:9 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | x.expect("an error message"); // will panic + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:44:9 + --> $DIR/simple_conditionals.rs:46:9 | LL | if x.is_none() { | ----------- because of this check LL | x.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` - --> $DIR/simple_conditionals.rs:46:9 +error: called `unwrap` on `x` after checking its variant with `is_none` + --> $DIR/simple_conditionals.rs:48:9 | LL | if x.is_none() { - | ----------- the check is happening here + | -------------- help: try: `if let Some(..) = x` ... LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` +error: called `unwrap` on `x` after checking its variant with `is_some` --> $DIR/simple_conditionals.rs:7:13 | LL | if $a.is_some() { - | ------------ the check is happening here + | --------------- help: try: `if let Some(..) = x` LL | $a.unwrap(); // unnecessary | ^^^^^^^^^^^ ... LL | m!(x); - | ------ in this macro invocation + | ----- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` - --> $DIR/simple_conditionals.rs:54:9 +error: called `unwrap` on `x` after checking its variant with `is_ok` + --> $DIR/simple_conditionals.rs:56:9 | LL | if x.is_ok() { - | --------- the check is happening here + | ------------ help: try: `if let Ok(..) = x` LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ +error: called `expect` on `x` after checking its variant with `is_ok` + --> $DIR/simple_conditionals.rs:57:9 + | +LL | if x.is_ok() { + | ------------ help: try: `if let Ok(..) = x` +LL | x.unwrap(); // unnecessary +LL | x.expect("an error message"); // unnecessary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: this call to `unwrap_err()` will always panic - --> $DIR/simple_conditionals.rs:55:9 + --> $DIR/simple_conditionals.rs:58:9 | LL | if x.is_ok() { | --------- because of this check -LL | x.unwrap(); // unnecessary +... LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:57:9 + --> $DIR/simple_conditionals.rs:60:9 | LL | if x.is_ok() { | --------- because of this check @@ -83,43 +110,52 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` - --> $DIR/simple_conditionals.rs:58:9 +error: this call to `expect()` will always panic + --> $DIR/simple_conditionals.rs:61:9 + | +LL | if x.is_ok() { + | --------- because of this check +... +LL | x.expect("an error message"); // will panic + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap_err` on `x` after checking its variant with `is_ok` + --> $DIR/simple_conditionals.rs:62:9 | LL | if x.is_ok() { - | --------- the check is happening here + | ------------ help: try: `if let Err(..) = x` ... LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:61:9 + --> $DIR/simple_conditionals.rs:65:9 | LL | if x.is_err() { | ---------- because of this check LL | x.unwrap(); // will panic | ^^^^^^^^^^ -error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` - --> $DIR/simple_conditionals.rs:62:9 +error: called `unwrap_err` on `x` after checking its variant with `is_err` + --> $DIR/simple_conditionals.rs:66:9 | LL | if x.is_err() { - | ---------- the check is happening here + | ------------- help: try: `if let Err(..) = x` LL | x.unwrap(); // will panic LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ -error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match` - --> $DIR/simple_conditionals.rs:64:9 +error: called `unwrap` on `x` after checking its variant with `is_err` + --> $DIR/simple_conditionals.rs:68:9 | LL | if x.is_err() { - | ---------- the check is happening here + | ------------- help: try: `if let Ok(..) = x` ... LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> $DIR/simple_conditionals.rs:65:9 + --> $DIR/simple_conditionals.rs:69:9 | LL | if x.is_err() { | ---------- because of this check @@ -127,5 +163,5 @@ LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 17 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_else_if.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_else_if.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_else_if.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_else_if.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_else_if.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_else_if.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_else_if.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_else_if.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_if.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_if.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_if.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_if.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_if.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_if.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_if.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_if.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match2.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match2.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -46,7 +46,7 @@ | |_____________________^ ... LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); - | ------------------------------------------------- in this macro invocation + | ------------------------------------------------ in this macro invocation | help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:46:28 diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,10 @@ #![warn(clippy::collapsible_match)] -#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)] +#![allow( + clippy::needless_return, + clippy::no_effect, + clippy::single_match, + clippy::equatable_if_let +)] fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { // match without block diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/collapsible_match.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:7:20 + --> $DIR/collapsible_match.rs:12:20 | LL | Ok(val) => match val { | ____________________^ @@ -10,7 +10,7 @@ | = note: `-D clippy::collapsible-match` implied by `-D warnings` help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:7:12 + --> $DIR/collapsible_match.rs:12:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -18,7 +18,7 @@ | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:16:20 + --> $DIR/collapsible_match.rs:21:20 | LL | Ok(val) => match val { | ____________________^ @@ -28,7 +28,7 @@ | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:16:12 + --> $DIR/collapsible_match.rs:21:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -36,7 +36,7 @@ | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:25:9 + --> $DIR/collapsible_match.rs:30:9 | LL | / if let Some(n) = val { LL | | take(n); @@ -44,7 +44,7 @@ | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:24:15 + --> $DIR/collapsible_match.rs:29:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -52,7 +52,7 @@ | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:32:9 + --> $DIR/collapsible_match.rs:37:9 | LL | / if let Some(n) = val { LL | | take(n); @@ -62,7 +62,7 @@ | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:31:15 + --> $DIR/collapsible_match.rs:36:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -70,7 +70,7 @@ | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:43:9 + --> $DIR/collapsible_match.rs:48:9 | LL | / match val { LL | | Some(n) => foo(n), @@ -79,7 +79,7 @@ | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:42:15 + --> $DIR/collapsible_match.rs:47:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -88,7 +88,7 @@ | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:52:13 + --> $DIR/collapsible_match.rs:57:13 | LL | / if let Some(n) = val { LL | | take(n); @@ -96,7 +96,7 @@ | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:51:12 + --> $DIR/collapsible_match.rs:56:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -104,7 +104,7 @@ | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:61:9 + --> $DIR/collapsible_match.rs:66:9 | LL | / match val { LL | | Some(n) => foo(n), @@ -113,7 +113,7 @@ | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:60:15 + --> $DIR/collapsible_match.rs:65:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -122,7 +122,7 @@ | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:72:13 + --> $DIR/collapsible_match.rs:77:13 | LL | / if let Some(n) = val { LL | | take(n); @@ -132,7 +132,7 @@ | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:71:12 + --> $DIR/collapsible_match.rs:76:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -140,7 +140,7 @@ | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:83:20 + --> $DIR/collapsible_match.rs:88:20 | LL | Ok(val) => match val { | ____________________^ @@ -150,7 +150,7 @@ | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:83:12 + --> $DIR/collapsible_match.rs:88:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -158,7 +158,7 @@ | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:92:22 + --> $DIR/collapsible_match.rs:97:22 | LL | Some(val) => match val { | ______________________^ @@ -168,7 +168,7 @@ | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:92:14 + --> $DIR/collapsible_match.rs:97:14 | LL | Some(val) => match val { | ^^^ replace this binding diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-3462.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-3462.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-3462.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-3462.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::blacklisted_name, clippy::equatable_if_let)] #![allow(unused)] /// Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-6255.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-6255.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-6255.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-6255.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | define_other_core!(); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-6256.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-6256.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-6256.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/ice-6256.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,7 +6,7 @@ | = note: expected reference `&(dyn TT + 'static)` found reference `&dyn TT` -note: the anonymous lifetime #1 defined on the body at 13:13... +note: the anonymous lifetime #1 defined here... --> $DIR/ice-6256.rs:13:13 | LL | let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,3 @@ -#![allow(clippy::blocks_in_if_conditions)] #![allow(dead_code)] /// Issue: https://github.com/rust-lang/rust-clippy/issues/2596 diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -31,7 +31,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^ ... LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable - | ------------------------------------------ in this macro invocation + | ----------------------------------------- in this macro invocation | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -13,7 +13,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^ ... LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable - | ----------------------------------------------------------- in this macro invocation + | ---------------------------------------------------------- in this macro invocation | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -139,7 +139,7 @@ | ^^^ help: consider adding suffix: `22.0_f64` ... LL | internal_macro!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -151,7 +151,7 @@ | ^^ help: consider adding suffix: `22_i32` ... LL | internal_macro!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_trait_access.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_trait_access.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_trait_access.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_trait_access.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_imports)] +#![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] use std::default; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_trait_access.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_trait_access.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_trait_access.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/default_trait_access.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_imports)] +#![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] use std::default; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/def_id_nocore.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/def_id_nocore.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/def_id_nocore.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/def_id_nocore.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,6 +3,7 @@ #![feature(no_core, lang_items, start)] #![no_core] +#![allow(clippy::missing_safety_doc)] #[link(name = "c")] extern "C" {} @@ -15,11 +16,12 @@ pub unsafe trait Freeze {} #[lang = "start"] -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { +fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { 0 } +fn main() {} + struct A; impl A { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/def_id_nocore.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/def_id_nocore.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/def_id_nocore.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/def_id_nocore.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/def_id_nocore.rs:26:19 + --> $DIR/def_id_nocore.rs:28:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/deref_addrof.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/deref_addrof.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/deref_addrof.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/deref_addrof.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ n } -#[allow(clippy::many_single_char_names, clippy::double_parens)] +#[allow(clippy::double_parens)] #[allow(unused_variables, unused_parens)] fn main() { let a = 10; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/deref_addrof.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/deref_addrof.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/deref_addrof.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/deref_addrof.rs 2021-11-29 19:27:12.000000000 +0000 @@ -9,7 +9,7 @@ n } -#[allow(clippy::many_single_char_names, clippy::double_parens)] +#[allow(clippy::double_parens)] #[allow(unused_variables, unused_parens)] fn main() { let a = 10; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/derivable_impls.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/derivable_impls.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/derivable_impls.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/derivable_impls.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,243 @@ +use std::collections::HashMap; + +struct FooDefault<'a> { + a: bool, + b: i32, + c: u64, + d: Vec, + e: FooND1, + f: FooND2, + g: HashMap, + h: (i32, Vec), + i: [Vec; 3], + j: [i32; 5], + k: Option, + l: &'a [i32], +} + +impl std::default::Default for FooDefault<'_> { + fn default() -> Self { + Self { + a: false, + b: 0, + c: 0u64, + d: vec![], + e: Default::default(), + f: FooND2::default(), + g: HashMap::new(), + h: (0, vec![]), + i: [vec![], vec![], vec![]], + j: [0; 5], + k: None, + l: &[], + } + } +} + +struct TupleDefault(bool, i32, u64); + +impl std::default::Default for TupleDefault { + fn default() -> Self { + Self(false, 0, 0u64) + } +} + +struct FooND1 { + a: bool, +} + +impl std::default::Default for FooND1 { + fn default() -> Self { + Self { a: true } + } +} + +struct FooND2 { + a: i32, +} + +impl std::default::Default for FooND2 { + fn default() -> Self { + Self { a: 5 } + } +} + +struct FooNDNew { + a: bool, +} + +impl FooNDNew { + fn new() -> Self { + Self { a: true } + } +} + +impl Default for FooNDNew { + fn default() -> Self { + Self::new() + } +} + +struct FooNDVec(Vec); + +impl Default for FooNDVec { + fn default() -> Self { + Self(vec![5, 12]) + } +} + +struct StrDefault<'a>(&'a str); + +impl Default for StrDefault<'_> { + fn default() -> Self { + Self("") + } +} + +#[derive(Default)] +struct AlreadyDerived(i32, bool); + +macro_rules! mac { + () => { + 0 + }; + ($e:expr) => { + struct X(u32); + impl Default for X { + fn default() -> Self { + Self($e) + } + } + }; +} + +mac!(0); + +struct Y(u32); +impl Default for Y { + fn default() -> Self { + Self(mac!()) + } +} + +struct RustIssue26925 { + a: Option, +} + +// We should watch out for cases where a manual impl is needed because a +// derive adds different type bounds (https://github.com/rust-lang/rust/issues/26925). +// For example, a struct with Option does not require T: Default, but a derive adds +// that type bound anyways. So until #26925 get fixed we should disable lint +// for the following case +impl Default for RustIssue26925 { + fn default() -> Self { + Self { a: None } + } +} + +struct SpecializedImpl { + a: A, + b: B, +} + +impl Default for SpecializedImpl { + fn default() -> Self { + Self { + a: T::default(), + b: T::default(), + } + } +} + +struct WithoutSelfCurly { + a: bool, +} + +impl Default for WithoutSelfCurly { + fn default() -> Self { + WithoutSelfCurly { a: false } + } +} + +struct WithoutSelfParan(bool); + +impl Default for WithoutSelfParan { + fn default() -> Self { + WithoutSelfParan(false) + } +} + +// https://github.com/rust-lang/rust-clippy/issues/7655 + +pub struct SpecializedImpl2 { + v: Vec, +} + +impl Default for SpecializedImpl2 { + fn default() -> Self { + Self { v: Vec::new() } + } +} + +// https://github.com/rust-lang/rust-clippy/issues/7654 + +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, +} + +/// `#000000` +impl Default for Color { + fn default() -> Self { + Color { r: 0, g: 0, b: 0 } + } +} + +pub struct Color2 { + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl Default for Color2 { + /// `#000000` + fn default() -> Self { + Self { r: 0, g: 0, b: 0 } + } +} + +pub struct RepeatDefault1 { + a: [i8; 32], +} + +impl Default for RepeatDefault1 { + fn default() -> Self { + RepeatDefault1 { a: [0; 32] } + } +} + +pub struct RepeatDefault2 { + a: [i8; 33], +} + +impl Default for RepeatDefault2 { + fn default() -> Self { + RepeatDefault2 { a: [0; 33] } + } +} + +// https://github.com/rust-lang/rust-clippy/issues/7753 + +pub enum IntOrString { + Int(i32), + String(String), +} + +impl Default for IntOrString { + fn default() -> Self { + IntOrString::Int(0) + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/derivable_impls.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/derivable_impls.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/derivable_impls.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/derivable_impls.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,89 @@ +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:18:1 + | +LL | / impl std::default::Default for FooDefault<'_> { +LL | | fn default() -> Self { +LL | | Self { +LL | | a: false, +... | +LL | | } +LL | | } + | |_^ + | + = note: `-D clippy::derivable-impls` implied by `-D warnings` + = help: try annotating `FooDefault` with `#[derive(Default)]` + +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:39:1 + | +LL | / impl std::default::Default for TupleDefault { +LL | | fn default() -> Self { +LL | | Self(false, 0, 0u64) +LL | | } +LL | | } + | |_^ + | + = help: try annotating `TupleDefault` with `#[derive(Default)]` + +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:91:1 + | +LL | / impl Default for StrDefault<'_> { +LL | | fn default() -> Self { +LL | | Self("") +LL | | } +LL | | } + | |_^ + | + = help: try annotating `StrDefault` with `#[derive(Default)]` + +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:117:1 + | +LL | / impl Default for Y { +LL | | fn default() -> Self { +LL | | Self(mac!()) +LL | | } +LL | | } + | |_^ + | + = help: try annotating `Y` with `#[derive(Default)]` + +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:156:1 + | +LL | / impl Default for WithoutSelfCurly { +LL | | fn default() -> Self { +LL | | WithoutSelfCurly { a: false } +LL | | } +LL | | } + | |_^ + | + = help: try annotating `WithoutSelfCurly` with `#[derive(Default)]` + +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:164:1 + | +LL | / impl Default for WithoutSelfParan { +LL | | fn default() -> Self { +LL | | WithoutSelfParan(false) +LL | | } +LL | | } + | |_^ + | + = help: try annotating `WithoutSelfParan` with `#[derive(Default)]` + +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:214:1 + | +LL | / impl Default for RepeatDefault1 { +LL | | fn default() -> Self { +LL | | RepeatDefault1 { a: [0; 32] } +LL | | } +LL | | } + | |_^ + | + = help: try annotating `RepeatDefault1` with `#[derive(Default)]` + +error: aborting due to 7 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc/doc.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc/doc.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc/doc.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc/doc.rs 2021-11-29 19:27:12.000000000 +0000 @@ -203,6 +203,11 @@ /// __|_ _|__||_| fn pulldown_cmark_crash() {} +/// This should not lint +/// (regression test for #7758) +/// [plain text][path::to::item] +fn intra_doc_link() {} + // issue #7033 - generic_const_exprs ICE struct S where [(); N.checked_next_power_of_two().unwrap()]: { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc_unsafe.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc_unsafe.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc_unsafe.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc_unsafe.rs 2021-11-29 19:27:12.000000000 +0000 @@ -34,16 +34,25 @@ pub use private_mod::republished; -pub trait UnsafeTrait { +pub trait SafeTraitUnsafeMethods { unsafe fn woefully_underdocumented(self); /// # Safety unsafe fn at_least_somewhat_documented(self); } +pub unsafe trait UnsafeTrait { + fn method(); +} + +/// # Safety +pub unsafe trait DocumentedUnsafeTrait { + fn method2(); +} + pub struct Struct; -impl UnsafeTrait for Struct { +impl SafeTraitUnsafeMethods for Struct { unsafe fn woefully_underdocumented(self) { // all is well } @@ -53,6 +62,14 @@ } } +unsafe impl UnsafeTrait for Struct { + fn method() {} +} + +unsafe impl DocumentedUnsafeTrait for Struct { + fn method2() {} +} + impl Struct { pub unsafe fn more_undocumented_unsafe() -> Self { unimplemented!(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc_unsafe.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc_unsafe.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc_unsafe.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/doc_unsafe.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -22,8 +22,16 @@ LL | unsafe fn woefully_underdocumented(self); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: docs for unsafe trait missing `# Safety` section + --> $DIR/doc_unsafe.rs:44:1 + | +LL | / pub unsafe trait UnsafeTrait { +LL | | fn method(); +LL | | } + | |_^ + error: unsafe function's docs miss `# Safety` section - --> $DIR/doc_unsafe.rs:57:5 + --> $DIR/doc_unsafe.rs:74:5 | LL | / pub unsafe fn more_undocumented_unsafe() -> Self { LL | | unimplemented!(); @@ -31,7 +39,7 @@ | |_____^ error: unsafe function's docs miss `# Safety` section - --> $DIR/doc_unsafe.rs:73:9 + --> $DIR/doc_unsafe.rs:90:9 | LL | / pub unsafe fn whee() { LL | | unimplemented!() @@ -39,9 +47,9 @@ | |_________^ ... LL | very_unsafe!(); - | --------------- in this macro invocation + | -------------- in this macro invocation | = note: this error originates in the macro `very_unsafe` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,18 @@ +// run-rustfix + +#![warn(clippy::map_entry)] +#![allow(dead_code)] + +use std::collections::BTreeMap; + +fn foo() {} + +fn btree_map(m: &mut BTreeMap, k: K, v: V) { + // insert then do something, use if let + if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) { + e.insert(v); + foo(); + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,18 @@ +// run-rustfix + +#![warn(clippy::map_entry)] +#![allow(dead_code)] + +use std::collections::BTreeMap; + +fn foo() {} + +fn btree_map(m: &mut BTreeMap, k: K, v: V) { + // insert then do something, use if let + if !m.contains_key(&k) { + m.insert(k, v); + foo(); + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry_btree.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,20 @@ +error: usage of `contains_key` followed by `insert` on a `BTreeMap` + --> $DIR/entry_btree.rs:12:5 + | +LL | / if !m.contains_key(&k) { +LL | | m.insert(k, v); +LL | | foo(); +LL | | } + | |_____^ + | + = note: `-D clippy::map-entry` implied by `-D warnings` +help: try this + | +LL ~ if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) { +LL + e.insert(v); +LL + foo(); +LL + } + | + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ #![warn(clippy::map_entry)] #![feature(asm)] -use std::collections::{BTreeMap, HashMap}; +use std::collections::HashMap; use std::hash::Hash; macro_rules! m { @@ -142,14 +142,13 @@ if !m.contains_key(&k) { insert!(m, k, v); } -} -fn btree_map(m: &mut BTreeMap, k: K, v: V, v2: V) { - // insert then do something, use if let - if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) { - e.insert(v); - foo(); - } + // or_insert_with. Partial move of a local declared in the closure is ok. + m.entry(k).or_insert_with(|| { + let x = (String::new(), String::new()); + let _ = x.0; + v + }); } fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ #![warn(clippy::map_entry)] #![feature(asm)] -use std::collections::{BTreeMap, HashMap}; +use std::collections::HashMap; use std::hash::Hash; macro_rules! m { @@ -146,13 +146,12 @@ if !m.contains_key(&k) { insert!(m, k, v); } -} -fn btree_map(m: &mut BTreeMap, k: K, v: V, v2: V) { - // insert then do something, use if let + // or_insert_with. Partial move of a local declared in the closure is ok. if !m.contains_key(&k) { + let x = (String::new(), String::new()); + let _ = x.0; m.insert(k, v); - foo(); } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/entry.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -165,21 +165,23 @@ LL | | } | |_____^ help: try this: `m.entry(m!(k)).or_insert_with(|| m!(v));` -error: usage of `contains_key` followed by `insert` on a `BTreeMap` - --> $DIR/entry.rs:153:5 +error: usage of `contains_key` followed by `insert` on a `HashMap` + --> $DIR/entry.rs:151:5 | LL | / if !m.contains_key(&k) { +LL | | let x = (String::new(), String::new()); +LL | | let _ = x.0; LL | | m.insert(k, v); -LL | | foo(); LL | | } | |_____^ | help: try this | -LL ~ if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) { -LL + e.insert(v); -LL + foo(); -LL + } +LL ~ m.entry(k).or_insert_with(|| { +LL + let x = (String::new(), String::new()); +LL + let _ = x.0; +LL + v +LL + }); | error: aborting due to 10 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eq_op_macros.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eq_op_macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eq_op_macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eq_op_macros.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^ ... LL | assert_in_macro_def!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: `-D clippy::eq-op` implied by `-D warnings` = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -17,7 +17,7 @@ | ^^^^ ... LL | assert_in_macro_def!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -52,7 +52,7 @@ | ^^^^ ... LL | assert_in_macro_def!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -63,7 +63,7 @@ | ^^^^ ... LL | assert_in_macro_def!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eq_op.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eq_op.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eq_op.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eq_op.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ #[rustfmt::skip] #[warn(clippy::eq_op)] -#[allow(clippy::identity_op, clippy::double_parens, clippy::many_single_char_names)] +#[allow(clippy::identity_op, clippy::double_parens)] #[allow(clippy::no_effect, unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)] #[allow(clippy::nonminimal_bool)] #[allow(unused)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,69 @@ +// run-rustfix + +#![allow(unused_variables, dead_code)] +#![warn(clippy::equatable_if_let)] + +use std::cmp::Ordering; + +#[derive(PartialEq)] +enum Enum { + TupleVariant(i32, u64), + RecordVariant { a: i64, b: u32 }, + UnitVariant, + Recursive(Struct), +} + +#[derive(PartialEq)] +struct Struct { + a: i32, + b: bool, +} + +enum NotPartialEq { + A, + B, +} + +enum NotStructuralEq { + A, + B, +} + +impl PartialEq for NotStructuralEq { + fn eq(&self, _: &NotStructuralEq) -> bool { + false + } +} + +fn main() { + let a = 2; + let b = 3; + let c = Some(2); + let d = Struct { a: 2, b: false }; + let e = Enum::UnitVariant; + let f = NotPartialEq::A; + let g = NotStructuralEq::A; + + // true + + if a == 2 {} + if a.cmp(&b) == Ordering::Greater {} + if c == Some(2) {} + if d == (Struct { a: 2, b: false }) {} + if e == Enum::TupleVariant(32, 64) {} + if e == (Enum::RecordVariant { a: 64, b: 32 }) {} + if e == Enum::UnitVariant {} + if (e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false }) {} + + // false + + if let 2 | 3 = a {} + if let x @ 2 = a {} + if let Some(3 | 4) = c {} + if let Struct { a, b: false } = d {} + if let Struct { a: 2, b: x } = d {} + if let NotPartialEq::A = f {} + if g == NotStructuralEq::A {} + if let Some(NotPartialEq::A) = Some(f) {} + if Some(g) == Some(NotStructuralEq::A) {} +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,69 @@ +// run-rustfix + +#![allow(unused_variables, dead_code)] +#![warn(clippy::equatable_if_let)] + +use std::cmp::Ordering; + +#[derive(PartialEq)] +enum Enum { + TupleVariant(i32, u64), + RecordVariant { a: i64, b: u32 }, + UnitVariant, + Recursive(Struct), +} + +#[derive(PartialEq)] +struct Struct { + a: i32, + b: bool, +} + +enum NotPartialEq { + A, + B, +} + +enum NotStructuralEq { + A, + B, +} + +impl PartialEq for NotStructuralEq { + fn eq(&self, _: &NotStructuralEq) -> bool { + false + } +} + +fn main() { + let a = 2; + let b = 3; + let c = Some(2); + let d = Struct { a: 2, b: false }; + let e = Enum::UnitVariant; + let f = NotPartialEq::A; + let g = NotStructuralEq::A; + + // true + + if let 2 = a {} + if let Ordering::Greater = a.cmp(&b) {} + if let Some(2) = c {} + if let Struct { a: 2, b: false } = d {} + if let Enum::TupleVariant(32, 64) = e {} + if let Enum::RecordVariant { a: 64, b: 32 } = e {} + if let Enum::UnitVariant = e {} + if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} + + // false + + if let 2 | 3 = a {} + if let x @ 2 = a {} + if let Some(3 | 4) = c {} + if let Struct { a, b: false } = d {} + if let Struct { a: 2, b: x } = d {} + if let NotPartialEq::A = f {} + if let NotStructuralEq::A = g {} + if let Some(NotPartialEq::A) = Some(f) {} + if let Some(NotStructuralEq::A) = Some(g) {} +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/equatable_if_let.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,64 @@ +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:49:8 + | +LL | if let 2 = a {} + | ^^^^^^^^^ help: try: `a == 2` + | + = note: `-D clippy::equatable-if-let` implied by `-D warnings` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:50:8 + | +LL | if let Ordering::Greater = a.cmp(&b) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:51:8 + | +LL | if let Some(2) = c {} + | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:52:8 + | +LL | if let Struct { a: 2, b: false } = d {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:53:8 + | +LL | if let Enum::TupleVariant(32, 64) = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:54:8 + | +LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:55:8 + | +LL | if let Enum::UnitVariant = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:56:8 + | +LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:66:8 + | +LL | if let NotStructuralEq::A = g {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:68:8 + | +LL | if let Some(NotStructuralEq::A) = Some(g) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` + +error: aborting due to 10 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,6 @@ unused, clippy::no_effect, clippy::redundant_closure_call, - clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn )] @@ -14,7 +13,7 @@ clippy::needless_borrow )] -use std::path::PathBuf; +use std::path::{Path, PathBuf}; macro_rules! mac { () => { @@ -30,19 +29,18 @@ fn main() { let a = Some(1u8).map(foo); - meta(foo); let c = Some(1u8).map(|a| {1+2; foo}(a)); true.then(|| mac!()); // don't lint function in macro expansion Some(1).map(closure_mac!()); // don't lint closure in macro expansion let _: Option> = true.then(std::vec::Vec::new); // special case vec! - let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? - all(&[1, 2, 3], &2, |x, y| below(x, y)); //is adjusted + let d = Some(1u8).map(|a| foo(foo2(a))); //is adjusted? + all(&[1, 2, 3], &2, below); //is adjusted unsafe { Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn } // See #815 - let e = Some(1u8).map(|a| divergent(a)); + let e = Some(1u8).map(divergent); let e = Some(1u8).map(generic); let e = Some(1u8).map(generic); // See #515 @@ -90,24 +88,17 @@ fn test_redundant_closures_containing_method_calls() { let i = 10; let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo); - let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo); let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo); let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref()); - let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo); - let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear); let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear); unsafe { let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe()); } let e = Some("str").map(std::string::ToString::to_string); - let e = Some("str").map(str::to_string); - let e = Some('a').map(char::to_uppercase); let e = Some('a').map(char::to_uppercase); let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect(); let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect(); - let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect(); - let p = Some(PathBuf::new()); - let e = p.as_ref().and_then(|s| s.to_str()); + let e = Some(PathBuf::new()).as_ref().and_then(|s| s.to_str()); let c = Some(TestStruct { some_ref: &i }) .as_ref() .map(|c| c.to_ascii_uppercase()); @@ -119,10 +110,6 @@ t.iter().filter(|x| x.trait_foo_ref()); t.iter().map(|x| x.trait_foo_ref()); } - - let mut some = Some(|x| x * x); - let arr = [Ok(1), Err(2)]; - let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect(); } struct Thunk(Box T>); @@ -145,13 +132,6 @@ thunk.unwrap() } -fn meta(f: F) -where - F: Fn(u8), -{ - f(1u8) -} - fn foo(_: u8) {} fn foo2(_: u8) -> u8 { @@ -180,7 +160,7 @@ } fn passes_fn_mut(mut x: Box) { - requires_fn_once(|| x()); + requires_fn_once(x); } fn requires_fn_once(_: T) {} @@ -236,3 +216,35 @@ Some(1).map(&mut closure); } } + +fn late_bound_lifetimes() { + fn take_asref_path>(path: P) {} + + fn map_str(thunk: F) + where + F: FnOnce(&str), + { + } + + fn map_str_to_path(thunk: F) + where + F: FnOnce(&str) -> &Path, + { + } + map_str(|s| take_asref_path(s)); + map_str_to_path(std::convert::AsRef::as_ref); +} + +mod type_param_bound { + trait Trait { + fn fun(); + } + + fn take(_: T) {} + + fn test() { + // don't lint, but it's questionable that rust requires a cast + take(|| X::fun()); + take(X::fun as fn()); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,6 @@ unused, clippy::no_effect, clippy::redundant_closure_call, - clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn )] @@ -14,7 +13,7 @@ clippy::needless_borrow )] -use std::path::PathBuf; +use std::path::{Path, PathBuf}; macro_rules! mac { () => { @@ -30,7 +29,6 @@ fn main() { let a = Some(1u8).map(|a| foo(a)); - meta(|a| foo(a)); let c = Some(1u8).map(|a| {1+2; foo}(a)); true.then(|| mac!()); // don't lint function in macro expansion Some(1).map(closure_mac!()); // don't lint closure in macro expansion @@ -90,24 +88,17 @@ fn test_redundant_closures_containing_method_calls() { let i = 10; let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); - let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo); let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref()); - let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo); let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); - let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear); unsafe { let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe()); } let e = Some("str").map(|s| s.to_string()); - let e = Some("str").map(str::to_string); let e = Some('a').map(|s| s.to_uppercase()); - let e = Some('a').map(char::to_uppercase); let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect(); let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); - let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect(); - let p = Some(PathBuf::new()); - let e = p.as_ref().and_then(|s| s.to_str()); + let e = Some(PathBuf::new()).as_ref().and_then(|s| s.to_str()); let c = Some(TestStruct { some_ref: &i }) .as_ref() .map(|c| c.to_ascii_uppercase()); @@ -119,10 +110,6 @@ t.iter().filter(|x| x.trait_foo_ref()); t.iter().map(|x| x.trait_foo_ref()); } - - let mut some = Some(|x| x * x); - let arr = [Ok(1), Err(2)]; - let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect(); } struct Thunk(Box T>); @@ -145,13 +132,6 @@ thunk.unwrap() } -fn meta(f: F) -where - F: Fn(u8), -{ - f(1u8) -} - fn foo(_: u8) {} fn foo2(_: u8) -> u8 { @@ -236,3 +216,35 @@ Some(1).map(|n| closure(n)); } } + +fn late_bound_lifetimes() { + fn take_asref_path>(path: P) {} + + fn map_str(thunk: F) + where + F: FnOnce(&str), + { + } + + fn map_str_to_path(thunk: F) + where + F: FnOnce(&str) -> &Path, + { + } + map_str(|s| take_asref_path(s)); + map_str_to_path(|s| s.as_ref()); +} + +mod type_param_bound { + trait Trait { + fn fun(); + } + + fn take(_: T) {} + + fn test() { + // don't lint, but it's questionable that rust requires a cast + take(|| X::fun()); + take(X::fun as fn()); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eta.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: redundant closure - --> $DIR/eta.rs:32:27 + --> $DIR/eta.rs:31:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -7,19 +7,19 @@ = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:33:10 + --> $DIR/eta.rs:35:40 | -LL | meta(|a| foo(a)); - | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` +LL | let _: Option> = true.then(|| vec![]); // special case vec! + | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> $DIR/eta.rs:37:40 + --> $DIR/eta.rs:36:35 | -LL | let _: Option> = true.then(|| vec![]); // special case vec! - | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` +LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? + | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: this expression borrows a reference (`&u8`) that is immediately dereferenced by the compiler - --> $DIR/eta.rs:39:21 + --> $DIR/eta.rs:37:21 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^ help: change this to: `&2` @@ -27,13 +27,25 @@ = note: `-D clippy::needless-borrow` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:46:27 + --> $DIR/eta.rs:37:26 + | +LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted + | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` + +error: redundant closure + --> $DIR/eta.rs:43:27 + | +LL | let e = Some(1u8).map(|a| divergent(a)); + | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `divergent` + +error: redundant closure + --> $DIR/eta.rs:44:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> $DIR/eta.rs:92:51 + --> $DIR/eta.rs:90:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -41,70 +53,82 @@ = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:94:51 + --> $DIR/eta.rs:91:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> $DIR/eta.rs:97:42 + --> $DIR/eta.rs:93:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> $DIR/eta.rs:102:29 + --> $DIR/eta.rs:97:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> $DIR/eta.rs:104:27 + --> $DIR/eta.rs:98:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> $DIR/eta.rs:107:65 + --> $DIR/eta.rs:100:65 | LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> $DIR/eta.rs:190:27 + --> $DIR/eta.rs:163:22 + | +LL | requires_fn_once(|| x()); + | ^^^^^^ help: replace the closure with the function itself: `x` + +error: redundant closure + --> $DIR/eta.rs:170:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> $DIR/eta.rs:195:27 + --> $DIR/eta.rs:175:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> $DIR/eta.rs:227:28 + --> $DIR/eta.rs:207:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:228:28 + --> $DIR/eta.rs:208:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:229:28 + --> $DIR/eta.rs:209:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> $DIR/eta.rs:236:21 + --> $DIR/eta.rs:216:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` -error: aborting due to 17 previous errors +error: redundant closure + --> $DIR/eta.rs:235:21 + | +LL | map_str_to_path(|s| s.as_ref()); + | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::convert::AsRef::as_ref` + +error: aborting due to 21 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eval_order_dependence.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eval_order_dependence.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eval_order_dependence.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eval_order_dependence.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,6 @@ #[allow( unused_assignments, unused_variables, - clippy::many_single_char_names, clippy::no_effect, dead_code, clippy::blacklisted_name diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eval_order_dependence.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eval_order_dependence.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/eval_order_dependence.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/eval_order_dependence.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,48 +1,48 @@ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:17:9 + --> $DIR/eval_order_dependence.rs:16:9 | LL | } + x; | ^ | = note: `-D clippy::eval-order-dependence` implied by `-D warnings` note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:15:9 + --> $DIR/eval_order_dependence.rs:14:9 | LL | x = 1; | ^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:20:5 + --> $DIR/eval_order_dependence.rs:19:5 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:21:9 + --> $DIR/eval_order_dependence.rs:20:9 | LL | x = 20; | ^^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:33:12 + --> $DIR/eval_order_dependence.rs:32:12 | LL | a: x, | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:35:13 + --> $DIR/eval_order_dependence.rs:34:13 | LL | x = 6; | ^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:42:9 + --> $DIR/eval_order_dependence.rs:41:9 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:43:13 + --> $DIR/eval_order_dependence.rs:42:13 | LL | x = 20; | ^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -17,8 +17,8 @@ const BAD32_3: f32 = 0.1; const BAD32_EDGE: f32 = 1.000_001; - const BAD64_1: f64 = 0.123_456_789_012_345_66_f64; - const BAD64_2: f64 = 0.123_456_789_012_345_66; + const BAD64_1: f64 = 0.123_456_789_012_345_67f64; + const BAD64_2: f64 = 0.123_456_789_012_345_67; const BAD64_3: f64 = 0.1; // Literal as param @@ -37,9 +37,9 @@ let bad32_suf: f32 = 1.123_456_8_f32; let bad32_inf = 1.123_456_8_f32; - let bad64: f64 = 0.123_456_789_012_345_66; - let bad64_suf: f64 = 0.123_456_789_012_345_66_f64; - let bad64_inf = 0.123_456_789_012_345_66; + let bad64: f64 = 0.123_456_789_012_345_67; + let bad64_suf: f64 = 0.123_456_789_012_345_67f64; + let bad64_inf = 0.123_456_789_012_345_67; // Vectors let good_vec32: Vec = vec![0.123_456]; @@ -60,4 +60,10 @@ // issue #2840 let num = 0.000_000_000_01e-10f64; + + // issue #7744 + let _ = 2.225_073_858_507_201e-308_f64; + + // issue #7745 + let _ = 0_f64; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.rs 2021-11-29 19:27:12.000000000 +0000 @@ -60,4 +60,10 @@ // issue #2840 let num = 0.000_000_000_01e-10f64; + + // issue #7744 + let _ = 2.225_073_858_507_201_1e-308_f64; + + // issue #7745 + let _ = 1.000_000_000_000_001e-324_f64; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/excessive_precision.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -25,18 +25,6 @@ | ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001` error: float has excessive precision - --> $DIR/excessive_precision.rs:20:26 - | -LL | const BAD64_1: f64 = 0.123_456_789_012_345_67f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66_f64` - -error: float has excessive precision - --> $DIR/excessive_precision.rs:21:26 - | -LL | const BAD64_2: f64 = 0.123_456_789_012_345_67; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` - -error: float has excessive precision --> $DIR/excessive_precision.rs:22:26 | LL | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; @@ -67,24 +55,6 @@ | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32` error: float has excessive precision - --> $DIR/excessive_precision.rs:40:22 - | -LL | let bad64: f64 = 0.123_456_789_012_345_67; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` - -error: float has excessive precision - --> $DIR/excessive_precision.rs:41:26 - | -LL | let bad64_suf: f64 = 0.123_456_789_012_345_67f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66_f64` - -error: float has excessive precision - --> $DIR/excessive_precision.rs:42:21 - | -LL | let bad64_inf = 0.123_456_789_012_345_67; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` - -error: float has excessive precision --> $DIR/excessive_precision.rs:48:36 | LL | let bad_vec32: Vec = vec![0.123_456_789]; @@ -108,5 +78,17 @@ LL | let bad_bige32: f32 = 1.123_456_788_888E-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10` -error: aborting due to 18 previous errors +error: float has excessive precision + --> $DIR/excessive_precision.rs:65:13 + | +LL | let _ = 2.225_073_858_507_201_1e-308_f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `2.225_073_858_507_201e-308_f64` + +error: float has excessive precision + --> $DIR/excessive_precision.rs:68:13 + | +LL | let _ = 1.000_000_000_000_001e-324_f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0_f64` + +error: aborting due to 15 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/explicit_deref_methods.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/explicit_deref_methods.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/explicit_deref_methods.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/explicit_deref_methods.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)] +#![allow(unused_variables, clippy::clone_double_ref)] #![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/explicit_deref_methods.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/explicit_deref_methods.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/explicit_deref_methods.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/explicit_deref_methods.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)] +#![allow(unused_variables, clippy::clone_double_ref)] #![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/fallible_impl_from.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/fallible_impl_from.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/fallible_impl_from.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/fallible_impl_from.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -37,7 +37,7 @@ --> $DIR/fallible_impl_from.rs:29:13 | LL | panic!(); - | ^^^^^^^^^ + | ^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead @@ -60,11 +60,11 @@ | ^^^^^^^^^^ LL | if !s.is_empty() { LL | panic!("42"); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ LL | } else if s.parse::().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead @@ -86,7 +86,7 @@ LL | if s.parse::().ok().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/float_cmp.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/float_cmp.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/float_cmp.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/float_cmp.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,8 +4,7 @@ clippy::no_effect, clippy::op_ref, clippy::unnecessary_operation, - clippy::cast_lossless, - clippy::many_single_char_names + clippy::cast_lossless )] use std::ops::Add; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/float_cmp.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/float_cmp.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/float_cmp.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/float_cmp.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:58:5 + --> $DIR/float_cmp.rs:57:5 | LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin` @@ -8,7 +8,7 @@ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:63:5 + --> $DIR/float_cmp.rs:62:5 | LL | x == 1.0; | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin` @@ -16,7 +16,7 @@ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:66:5 + --> $DIR/float_cmp.rs:65:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin` @@ -24,7 +24,7 @@ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:86:5 + --> $DIR/float_cmp.rs:85:5 | LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin` @@ -32,7 +32,7 @@ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` arrays - --> $DIR/float_cmp.rs:91:5 + --> $DIR/float_cmp.rs:90:5 | LL | a1 == a2; | ^^^^^^^^ @@ -40,7 +40,7 @@ = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:92:5 + --> $DIR/float_cmp.rs:91:5 | LL | a1[0] == a2[0]; | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -23,13 +23,8 @@ clippy::iter_next_loop, clippy::for_kv_map )] -#[allow( - clippy::linkedlist, - clippy::shadow_unrelated, - clippy::unnecessary_mut_passed, - clippy::similar_names -)] -#[allow(clippy::many_single_char_names, unused_variables)] +#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] +#[allow(unused_variables)] fn main() { let mut vec = vec![1, 2, 3, 4]; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.rs 2021-11-29 19:27:12.000000000 +0000 @@ -23,13 +23,8 @@ clippy::iter_next_loop, clippy::for_kv_map )] -#[allow( - clippy::linkedlist, - clippy::shadow_unrelated, - clippy::unnecessary_mut_passed, - clippy::similar_names -)] -#[allow(clippy::many_single_char_names, unused_variables)] +#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] +#[allow(unused_variables)] fn main() { let mut vec = vec![1, 2, 3, 4]; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_fixable.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:43:15 + --> $DIR/for_loop_fixable.rs:38:15 | LL | for _v in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -7,13 +7,13 @@ = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:45:15 + --> $DIR/for_loop_fixable.rs:40:15 | LL | for _v in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:48:15 + --> $DIR/for_loop_fixable.rs:43:15 | LL | for _v in out_vec.into_iter() {} | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` @@ -21,73 +21,73 @@ = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:53:15 + --> $DIR/for_loop_fixable.rs:48:15 | LL | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:57:15 + --> $DIR/for_loop_fixable.rs:52:15 | LL | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:62:15 + --> $DIR/for_loop_fixable.rs:57:15 | LL | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:65:15 + --> $DIR/for_loop_fixable.rs:60:15 | LL | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:68:15 + --> $DIR/for_loop_fixable.rs:63:15 | LL | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:71:15 + --> $DIR/for_loop_fixable.rs:66:15 | LL | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:74:15 + --> $DIR/for_loop_fixable.rs:69:15 | LL | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:77:15 + --> $DIR/for_loop_fixable.rs:72:15 | LL | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:80:15 + --> $DIR/for_loop_fixable.rs:75:15 | LL | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:255:18 + --> $DIR/for_loop_fixable.rs:250:18 | LL | for i in iterator.into_iter() { | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:275:18 + --> $DIR/for_loop_fixable.rs:270:18 | LL | for _ in t.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:277:18 + --> $DIR/for_loop_fixable.rs:272:18 | LL | for _ in r.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_unfixable.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_unfixable.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_unfixable.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_unfixable.rs 2021-11-29 19:27:12.000000000 +0000 @@ -7,14 +7,7 @@ clippy::iter_next_loop, clippy::for_kv_map )] -#[allow( - clippy::linkedlist, - clippy::shadow_unrelated, - clippy::unnecessary_mut_passed, - clippy::similar_names, - unused, - dead_code -)] +#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] fn main() { let vec = vec![1, 2, 3, 4]; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_unfixable.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_unfixable.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_unfixable.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/for_loop_unfixable.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop_unfixable.rs:21:15 + --> $DIR/for_loop_unfixable.rs:14:15 | LL | for _v in vec.iter().next() {} | ^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/format.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/format.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/format.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/format.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/format.rs:13:5 | LL | format!("foo"); - | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();` + | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` | = note: `-D clippy::useless-format` implied by `-D warnings` @@ -10,13 +10,13 @@ --> $DIR/format.rs:14:5 | LL | format!("{{}}"); - | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string();` + | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()` error: useless use of `format!` --> $DIR/format.rs:15:5 | LL | format!("{{}} abc {{}}"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()` error: useless use of `format!` --> $DIR/format.rs:16:5 @@ -25,61 +25,61 @@ LL | | r##"foo {{}} LL | | " bar"## LL | | ); - | |______^ + | |_____^ | help: consider using `.to_string()` | LL ~ r##"foo {} -LL + " bar"##.to_string(); +LL ~ " bar"##.to_string(); | error: useless use of `format!` --> $DIR/format.rs:21:5 | LL | format!("{}", "foo"); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` --> $DIR/format.rs:25:5 | LL | format!("{:+}", "foo"); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` --> $DIR/format.rs:26:5 | LL | format!("{:<}", "foo"); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` --> $DIR/format.rs:31:5 | LL | format!("{}", arg); - | ^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();` + | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` --> $DIR/format.rs:35:5 | LL | format!("{:+}", arg); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` --> $DIR/format.rs:36:5 | LL | format!("{:<}", arg); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` --> $DIR/format.rs:63:5 | LL | format!("{}", 42.to_string()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` --> $DIR/format.rs:65:5 | LL | format!("{}", x.display().to_string()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` --> $DIR/format.rs:69:18 diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.fixed 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -// run-rustfix - -#![warn(clippy::if_let_some_result)] -#![allow(dead_code)] - -fn str_to_int(x: &str) -> i32 { - if let Ok(y) = x.parse() { y } else { 0 } -} - -fn str_to_int_ok(x: &str) -> i32 { - if let Ok(y) = x.parse() { y } else { 0 } -} - -#[rustfmt::skip] -fn strange_some_no_else(x: &str) -> i32 { - { - if let Ok(y) = x . parse() { - return y; - }; - 0 - } -} - -fn negative() { - while let Some(1) = "".parse().ok() {} -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -// run-rustfix - -#![warn(clippy::if_let_some_result)] -#![allow(dead_code)] - -fn str_to_int(x: &str) -> i32 { - if let Some(y) = x.parse().ok() { y } else { 0 } -} - -fn str_to_int_ok(x: &str) -> i32 { - if let Ok(y) = x.parse() { y } else { 0 } -} - -#[rustfmt::skip] -fn strange_some_no_else(x: &str) -> i32 { - { - if let Some(y) = x . parse() . ok () { - return y; - }; - 0 - } -} - -fn negative() { - while let Some(1) = "".parse().ok() {} -} - -fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_let_some_result.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -error: matching on `Some` with `ok()` is redundant - --> $DIR/if_let_some_result.rs:7:5 - | -LL | if let Some(y) = x.parse().ok() { y } else { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::if-let-some-result` implied by `-D warnings` -help: consider matching on `Ok(y)` and removing the call to `ok` instead - | -LL | if let Ok(y) = x.parse() { y } else { 0 } - | ~~~~~~~~~~~~~~~~~~~~~~~~ - -error: matching on `Some` with `ok()` is redundant - --> $DIR/if_let_some_result.rs:17:9 - | -LL | if let Some(y) = x . parse() . ok () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider matching on `Ok(y)` and removing the call to `ok` instead - | -LL | if let Ok(y) = x . parse() { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -error: aborting due to 2 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_same_then_else2.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_same_then_else2.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_same_then_else2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_same_then_else2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,6 +2,7 @@ #![allow( clippy::blacklisted_name, clippy::collapsible_else_if, + clippy::equatable_if_let, clippy::collapsible_if, clippy::ifs_same_cond, clippy::needless_return, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_same_then_else2.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_same_then_else2.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_same_then_else2.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/if_same_then_else2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:13:13 + --> $DIR/if_same_then_else2.rs:14:13 | LL | if true { | _____________^ @@ -13,7 +13,7 @@ | = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this - --> $DIR/if_same_then_else2.rs:22:12 + --> $DIR/if_same_then_else2.rs:23:12 | LL | } else { | ____________^ @@ -26,7 +26,7 @@ | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:34:13 + --> $DIR/if_same_then_else2.rs:35:13 | LL | if true { | _____________^ @@ -35,7 +35,7 @@ | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:36:12 + --> $DIR/if_same_then_else2.rs:37:12 | LL | } else { | ____________^ @@ -45,7 +45,7 @@ | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:41:13 + --> $DIR/if_same_then_else2.rs:42:13 | LL | if true { | _____________^ @@ -54,7 +54,7 @@ | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:43:12 + --> $DIR/if_same_then_else2.rs:44:12 | LL | } else { | ____________^ @@ -64,7 +64,7 @@ | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:91:21 + --> $DIR/if_same_then_else2.rs:92:21 | LL | let _ = if true { | _____________________^ @@ -73,7 +73,7 @@ | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:93:12 + --> $DIR/if_same_then_else2.rs:94:12 | LL | } else { | ____________^ @@ -83,7 +83,7 @@ | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:98:13 + --> $DIR/if_same_then_else2.rs:99:13 | LL | if true { | _____________^ @@ -92,7 +92,7 @@ | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:100:12 + --> $DIR/if_same_then_else2.rs:101:12 | LL | } else { | ____________^ @@ -102,7 +102,7 @@ | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:122:20 + --> $DIR/if_same_then_else2.rs:123:20 | LL | } else if true { | ____________________^ @@ -112,7 +112,7 @@ | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:125:12 + --> $DIR/if_same_then_else2.rs:126:12 | LL | } else { | ____________^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/implicit_hasher.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/implicit_hasher.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/implicit_hasher.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/implicit_hasher.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,3 +1,4 @@ +// edition:2018 // aux-build:implicit_hasher_macros.rs #![deny(clippy::implicit_hasher)] #![allow(unused)] @@ -96,4 +97,7 @@ // #4260 implicit_hasher_fn!(); +// #7712 +pub async fn election_vote(_data: HashMap) {} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/implicit_hasher.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/implicit_hasher.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/implicit_hasher.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/implicit_hasher.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,11 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:16:35 + --> $DIR/implicit_hasher.rs:17:35 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/implicit_hasher.rs:2:9 + --> $DIR/implicit_hasher.rs:3:9 | LL | #![deny(clippy::implicit_hasher)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:25:36 + --> $DIR/implicit_hasher.rs:26:36 | LL | impl Foo for (HashMap,) { | ^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:30:19 + --> $DIR/implicit_hasher.rs:31:19 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:47:32 + --> $DIR/implicit_hasher.rs:48:32 | LL | impl Foo for HashSet { | ^^^^^^^^^^ @@ -64,7 +64,7 @@ | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:52:19 + --> $DIR/implicit_hasher.rs:53:19 | LL | impl Foo for HashSet { | ^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:23 + --> $DIR/implicit_hasher.rs:70:23 | LL | pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:53 + --> $DIR/implicit_hasher.rs:70:53 | LL | pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^ @@ -101,13 +101,13 @@ | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:73:43 + --> $DIR/implicit_hasher.rs:74:43 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ ... LL | gen!(impl); - | ----------- in this macro invocation + | ---------- in this macro invocation | = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter @@ -120,13 +120,13 @@ | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:33 + --> $DIR/implicit_hasher.rs:82:33 | LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^^^^^^ ... LL | gen!(fn bar); - | ------------- in this macro invocation + | ------------ in this macro invocation | = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter @@ -135,13 +135,13 @@ | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:63 + --> $DIR/implicit_hasher.rs:82:63 | LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^ ... LL | gen!(fn bar); - | ------------- in this macro invocation + | ------------ in this macro invocation | = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter @@ -149,5 +149,16 @@ LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ -error: aborting due to 10 previous errors +error: parameter of type `HashMap` should be generalized over different hashers + --> $DIR/implicit_hasher.rs:101:35 + | +LL | pub async fn election_vote(_data: HashMap) {} + | ^^^^^^^^^^^^^^^^^ + | +help: consider adding a type parameter + | +LL | pub async fn election_vote(_data: HashMap) {} + | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 11 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/infinite_loop.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/infinite_loop.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/infinite_loop.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/infinite_loop.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,3 @@ -#![allow(clippy::blocks_in_if_conditions)] - fn fn_val(i: i32) -> i32 { unimplemented!() } @@ -16,7 +14,6 @@ unimplemented!() } -#[allow(clippy::many_single_char_names)] fn immutable_condition() { // Should warn when all vars mentioned are immutable let y = 0; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/infinite_loop.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/infinite_loop.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/infinite_loop.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/infinite_loop.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:23:11 + --> $DIR/infinite_loop.rs:20:11 | LL | while y < 10 { | ^^^^^^ @@ -8,7 +8,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:28:11 + --> $DIR/infinite_loop.rs:25:11 | LL | while y < 10 && x < 3 { | ^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:35:11 + --> $DIR/infinite_loop.rs:32:11 | LL | while !cond { | ^^^^^ @@ -24,7 +24,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:79:11 + --> $DIR/infinite_loop.rs:76:11 | LL | while i < 3 { | ^^^^^ @@ -32,7 +32,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:84:11 + --> $DIR/infinite_loop.rs:81:11 | LL | while i < 3 && j > 0 { | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:88:11 + --> $DIR/infinite_loop.rs:85:11 | LL | while i < 3 { | ^^^^^ @@ -48,7 +48,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:103:11 + --> $DIR/infinite_loop.rs:100:11 | LL | while i < 3 { | ^^^^^ @@ -56,7 +56,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:108:11 + --> $DIR/infinite_loop.rs:105:11 | LL | while i < 3 { | ^^^^^ @@ -64,7 +64,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:174:15 + --> $DIR/infinite_loop.rs:171:15 | LL | while self.count < n { | ^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:182:11 + --> $DIR/infinite_loop.rs:179:11 | LL | while y < 10 { | ^^^^^^ @@ -82,7 +82,7 @@ = help: rewrite it as `if cond { loop { } }` error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:189:11 + --> $DIR/infinite_loop.rs:186:11 | LL | while y < 10 { | ^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/inherent_to_string.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/inherent_to_string.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/inherent_to_string.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/inherent_to_string.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,5 @@ #![warn(clippy::inherent_to_string)] #![deny(clippy::inherent_to_string_shadow_display)] -#![allow(clippy::many_single_char_names)] use std::fmt; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/inherent_to_string.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/inherent_to_string.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/inherent_to_string.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/inherent_to_string.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: implementation of inherent method `to_string(&self) -> String` for type `A` - --> $DIR/inherent_to_string.rs:21:5 + --> $DIR/inherent_to_string.rs:20:5 | LL | / fn to_string(&self) -> String { LL | | "A.to_string()".to_string() @@ -10,7 +10,7 @@ = help: implement trait `Display` for type `A` instead error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display` - --> $DIR/inherent_to_string.rs:45:5 + --> $DIR/inherent_to_string.rs:44:5 | LL | / fn to_string(&self) -> String { LL | | "C.to_string()".to_string() diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/integer_arithmetic.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/integer_arithmetic.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/integer_arithmetic.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/integer_arithmetic.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,5 @@ #![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] -#![allow( - unused, - clippy::shadow_reuse, - clippy::shadow_unrelated, - clippy::no_effect, - clippy::unnecessary_operation, - clippy::op_ref -)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)] #[rustfmt::skip] fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/integer_arithmetic.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/integer_arithmetic.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/integer_arithmetic.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/integer_arithmetic.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:37:5 + --> $DIR/integer_arithmetic.rs:30:5 | LL | i /= 0; | ^^^^^^ attempt to divide `_` by zero @@ -7,13 +7,13 @@ = note: `#[deny(unconditional_panic)]` on by default error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:42:5 + --> $DIR/integer_arithmetic.rs:35:5 | LL | i %= 0; | ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:16:5 + --> $DIR/integer_arithmetic.rs:9:5 | LL | 1 + i; | ^^^^^ @@ -21,146 +21,146 @@ = note: `-D clippy::integer-arithmetic` implied by `-D warnings` error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:17:5 + --> $DIR/integer_arithmetic.rs:10:5 | LL | i * 2; | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:18:5 + --> $DIR/integer_arithmetic.rs:11:5 | LL | / 1 % LL | | i / 2; // no error, this is part of the expression in the preceding line | |_____^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:20:5 + --> $DIR/integer_arithmetic.rs:13:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:21:5 + --> $DIR/integer_arithmetic.rs:14:5 | LL | -i; | ^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:22:5 + --> $DIR/integer_arithmetic.rs:15:5 | LL | i >> 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:23:5 + --> $DIR/integer_arithmetic.rs:16:5 | LL | i << 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:33:5 + --> $DIR/integer_arithmetic.rs:26:5 | LL | i += 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:34:5 + --> $DIR/integer_arithmetic.rs:27:5 | LL | i -= 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:35:5 + --> $DIR/integer_arithmetic.rs:28:5 | LL | i *= 2; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:38:11 + --> $DIR/integer_arithmetic.rs:31:11 | LL | i /= -1; | ^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:39:5 + --> $DIR/integer_arithmetic.rs:32:5 | LL | i /= var1; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:40:5 + --> $DIR/integer_arithmetic.rs:33:5 | LL | i /= var2; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:43:11 + --> $DIR/integer_arithmetic.rs:36:11 | LL | i %= -1; | ^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:44:5 + --> $DIR/integer_arithmetic.rs:37:5 | LL | i %= var1; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:45:5 + --> $DIR/integer_arithmetic.rs:38:5 | LL | i %= var2; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:46:5 + --> $DIR/integer_arithmetic.rs:39:5 | LL | i <<= 3; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:47:5 + --> $DIR/integer_arithmetic.rs:40:5 | LL | i >>= 2; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:89:5 + --> $DIR/integer_arithmetic.rs:82:5 | LL | 3 + &1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:90:5 + --> $DIR/integer_arithmetic.rs:83:5 | LL | &3 + 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:91:5 + --> $DIR/integer_arithmetic.rs:84:5 | LL | &3 + &1; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:96:5 + --> $DIR/integer_arithmetic.rs:89:5 | LL | a + x | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:100:5 + --> $DIR/integer_arithmetic.rs:93:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:104:5 + --> $DIR/integer_arithmetic.rs:97:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:108:5 + --> $DIR/integer_arithmetic.rs:101:5 | LL | (&x + &y) | ^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/item_after_statement.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/item_after_statement.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/item_after_statement.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/item_after_statement.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -25,7 +25,7 @@ | |_____________^ ... LL | b!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,47 @@ +#![warn(clippy::iter_not_returning_iterator)] + +struct Data { + begin: u32, +} + +struct Counter { + count: u32, +} + +impl Data { + fn iter(&self) -> Counter { + todo!() + } + + fn iter_mut(&self) -> Counter { + todo!() + } +} + +struct Data2 { + begin: u32, +} + +struct Counter2 { + count: u32, +} + +impl Data2 { + fn iter(&self) -> Counter2 { + todo!() + } + + fn iter_mut(&self) -> Counter2 { + todo!() + } +} + +impl Iterator for Counter { + type Item = u32; + + fn next(&mut self) -> Option { + todo!() + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,16 @@ +error: this method is named `iter` but its return type does not implement `Iterator` + --> $DIR/iter_not_returning_iterator.rs:30:5 + | +LL | fn iter(&self) -> Counter2 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::iter-not-returning-iterator` implied by `-D warnings` + +error: this method is named `iter_mut` but its return type does not implement `Iterator` + --> $DIR/iter_not_returning_iterator.rs:34:5 + | +LL | fn iter_mut(&self) -> Counter2 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/large_enum_variant.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/large_enum_variant.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/large_enum_variant.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/large_enum_variant.rs 2021-11-29 19:27:12.000000000 +0000 @@ -35,6 +35,7 @@ VariantOk(i32, u32), ContainingLargeEnum(LargeEnum), } + enum LargeEnum3 { ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), VoidVariant, @@ -56,6 +57,23 @@ LargeB([i32; 8001]), } +enum LargeEnum6 { + A, + B([u8; 255]), + C([u8; 200]), +} + +enum LargeEnum7 { + A, + B([u8; 1255]), + C([u8; 200]), +} + +enum LargeEnum8 { + VariantOk(i32, u32), + ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), +} + fn main() { large_enum_variant!(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/large_enum_variant.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/large_enum_variant.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/large_enum_variant.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/large_enum_variant.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -32,30 +32,45 @@ | ~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:46:5 + --> $DIR/large_enum_variant.rs:40:5 + | +LL | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes + | +note: and the second-largest variant is 8 bytes: + --> $DIR/large_enum_variant.rs:42:5 + | +LL | StructLikeLittle { x: i32, y: i32 }, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider boxing the large fields to reduce the total size of the enum + | +LL | ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), + | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:47:5 | LL | StructLikeLarge { x: [i32; 8000], y: i32 }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes | note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:45:5 + --> $DIR/large_enum_variant.rs:46:5 | LL | VariantOk(i32, u32), | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum - --> $DIR/large_enum_variant.rs:46:5 | -LL | StructLikeLarge { x: [i32; 8000], y: i32 }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, + | ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:51:5 + --> $DIR/large_enum_variant.rs:52:5 | LL | StructLikeLarge2 { x: [i32; 8000] }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes | note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:50:5 + --> $DIR/large_enum_variant.rs:51:5 | LL | VariantOk(i32, u32), | ^^^^^^^^^^^^^^^^^^^ @@ -64,5 +79,37 @@ LL | StructLikeLarge2 { x: Box<[i32; 8000]> }, | ~~~~~~~~~~~~~~~~ -error: aborting due to 4 previous errors +error: large size difference between variants + --> $DIR/large_enum_variant.rs:68:5 + | +LL | B([u8; 1255]), + | ^^^^^^^^^^^^^ this variant is 1255 bytes + | +note: and the second-largest variant is 200 bytes: + --> $DIR/large_enum_variant.rs:69:5 + | +LL | C([u8; 200]), + | ^^^^^^^^^^^^ +help: consider boxing the large fields to reduce the total size of the enum + | +LL | B(Box<[u8; 1255]>), + | ~~~~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:74:5 + | +LL | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes + | +note: and the second-largest variant is 8 bytes: + --> $DIR/large_enum_variant.rs:73:5 + | +LL | VariantOk(i32, u32), + | ^^^^^^^^^^^^^^^^^^^ +help: consider boxing the large fields to reduce the total size of the enum + | +LL | ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), + | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ + +error: aborting due to 7 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/linkedlist.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/linkedlist.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/linkedlist.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/linkedlist.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ #![feature(associated_type_defaults)] #![warn(clippy::linkedlist)] -#![allow(dead_code, clippy::needless_pass_by_value)] +#![allow(unused, dead_code, clippy::needless_pass_by_value)] extern crate alloc; use alloc::collections::linked_list::LinkedList; @@ -20,24 +20,29 @@ const BAR: Option> = None; } -struct Bar; +pub struct Bar { + priv_linked_list_field: LinkedList, + pub pub_linked_list_field: LinkedList, +} impl Bar { fn foo(_: LinkedList) {} } -pub fn test(my_favourite_linked_list: LinkedList) { - println!("{:?}", my_favourite_linked_list) -} - -pub fn test_ret() -> Option> { - unimplemented!(); +// All of these test should be trigger the lint because they are not +// part of the public api +fn test(my_favorite_linked_list: LinkedList) {} +fn test_ret() -> Option> { + None } - -pub fn test_local_not_linted() { +fn test_local_not_linted() { let _: LinkedList; } -fn main() { - test(LinkedList::new()); - test_local_not_linted(); +// All of these test should be allowed because they are part of the +// public api and `avoid_breaking_exported_api` is `false` by default. +pub fn pub_test(the_most_awesome_linked_list: LinkedList) {} +pub fn pub_test_ret() -> Option> { + None } + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/linkedlist.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/linkedlist.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/linkedlist.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/linkedlist.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -40,7 +40,15 @@ = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> $DIR/linkedlist.rs:25:15 + --> $DIR/linkedlist.rs:24:29 + | +LL | priv_linked_list_field: LinkedList, + | ^^^^^^^^^^^^^^ + | + = help: a `VecDeque` might work + +error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? + --> $DIR/linkedlist.rs:28:15 | LL | fn foo(_: LinkedList) {} | ^^^^^^^^^^^^^^ @@ -48,20 +56,20 @@ = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> $DIR/linkedlist.rs:28:39 + --> $DIR/linkedlist.rs:33:34 | -LL | pub fn test(my_favourite_linked_list: LinkedList) { - | ^^^^^^^^^^^^^^ +LL | fn test(my_favorite_linked_list: LinkedList) {} + | ^^^^^^^^^^^^^^ | = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> $DIR/linkedlist.rs:32:29 + --> $DIR/linkedlist.rs:34:25 | -LL | pub fn test_ret() -> Option> { - | ^^^^^^^^^^^^^^ +LL | fn test_ret() -> Option> { + | ^^^^^^^^^^^^^^ | = help: a `VecDeque` might work -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/logic_bug.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/logic_bug.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/logic_bug.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/logic_bug.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)] +#![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::logic_bug)] fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,40 @@ +// run-rustfix +#![warn(clippy::manual_assert)] + +fn main() { + let a = vec![1, 2, 3]; + let c = Some(2); + if !a.is_empty() + && a.len() == 3 + && c != None + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + { + panic!("qaqaq{:?}", a); + } + assert!(a.is_empty(), "qaqaq{:?}", a); + assert!(a.is_empty(), "qwqwq"); + if a.len() == 3 { + println!("qwq"); + println!("qwq"); + println!("qwq"); + } + if let Some(b) = c { + panic!("orz {}", b); + } + if a.len() == 3 { + panic!("qaqaq"); + } else { + println!("qwq"); + } + let b = vec![1, 2, 3]; + assert!(!b.is_empty(), "panic1"); + assert!(!(b.is_empty() && a.is_empty()), "panic2"); + assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + assert!(!(b.is_empty() || a.is_empty()), "panic4"); + assert!(!(a.is_empty() || !b.is_empty()), "panic5"); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,54 @@ +// run-rustfix +#![warn(clippy::manual_assert)] + +fn main() { + let a = vec![1, 2, 3]; + let c = Some(2); + if !a.is_empty() + && a.len() == 3 + && c != None + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + { + panic!("qaqaq{:?}", a); + } + if !a.is_empty() { + panic!("qaqaq{:?}", a); + } + if !a.is_empty() { + panic!("qwqwq"); + } + if a.len() == 3 { + println!("qwq"); + println!("qwq"); + println!("qwq"); + } + if let Some(b) = c { + panic!("orz {}", b); + } + if a.len() == 3 { + panic!("qaqaq"); + } else { + println!("qwq"); + } + let b = vec![1, 2, 3]; + if b.is_empty() { + panic!("panic1"); + } + if b.is_empty() && a.is_empty() { + panic!("panic2"); + } + if a.is_empty() && !b.is_empty() { + panic!("panic3"); + } + if b.is_empty() || a.is_empty() { + panic!("panic4"); + } + if a.is_empty() || !b.is_empty() { + panic!("panic5"); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_assert.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,60 @@ +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:19:5 + | +LL | / if !a.is_empty() { +LL | | panic!("qaqaq{:?}", a); +LL | | } + | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);` + | + = note: `-D clippy::manual-assert` implied by `-D warnings` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:22:5 + | +LL | / if !a.is_empty() { +LL | | panic!("qwqwq"); +LL | | } + | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:39:5 + | +LL | / if b.is_empty() { +LL | | panic!("panic1"); +LL | | } + | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:42:5 + | +LL | / if b.is_empty() && a.is_empty() { +LL | | panic!("panic2"); +LL | | } + | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:45:5 + | +LL | / if a.is_empty() && !b.is_empty() { +LL | | panic!("panic3"); +LL | | } + | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:48:5 + | +LL | / if b.is_empty() || a.is_empty() { +LL | | panic!("panic4"); +LL | | } + | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:51:5 + | +LL | / if a.is_empty() || !b.is_empty() { +LL | | panic!("panic5"); +LL | | } + | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` + +error: aborting due to 7 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_flatten.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_flatten.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_flatten.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_flatten.rs 2021-11-29 19:27:12.000000000 +0000 @@ -91,6 +91,19 @@ } } + struct Test { + a: usize, + } + + let mut vec_of_struct = [Some(Test { a: 1 }), None]; + + // Usage of `if let` expression should not trigger lint + for n in vec_of_struct.iter_mut() { + if let Some(z) = n { + *n = None; + } + } + // Using manual flatten should not trigger the lint for n in vec![Some(1), Some(2), Some(3)].iter().flatten() { println!("{}", n); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,50 @@ +// run-rustfix + +#![warn(clippy::manual_map)] +#![allow(clippy::toplevel_ref_arg)] + +fn main() { + // Lint. `y` is declared within the arm, so it isn't captured by the map closure + let _ = Some(0).map(|x| { + let y = (String::new(), String::new()); + (x, y.0) + }); + + // Don't lint. `s` is borrowed until partway through the arm, but needs to be captured by the map + // closure + let s = Some(String::new()); + let _ = match &s { + Some(x) => Some((x.clone(), s)), + None => None, + }; + + // Don't lint. `s` is borrowed until partway through the arm, but needs to be captured by the map + // closure + let s = Some(String::new()); + let _ = match &s { + Some(x) => Some({ + let clone = x.clone(); + let s = || s; + (clone, s()) + }), + None => None, + }; + + // Don't lint. `s` is borrowed until partway through the arm, but needs to be captured as a mutable + // reference by the map closure + let mut s = Some(String::new()); + let _ = match &s { + Some(x) => Some({ + let clone = x.clone(); + let ref mut s = s; + (clone, s) + }), + None => None, + }; + + // Lint. `s` is captured by reference, so no lifetime issues. + let s = Some(String::new()); + let _ = s.as_ref().map(|x| { + if let Some(ref s) = s { (x.clone(), s) } else { panic!() } + }); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,56 @@ +// run-rustfix + +#![warn(clippy::manual_map)] +#![allow(clippy::toplevel_ref_arg)] + +fn main() { + // Lint. `y` is declared within the arm, so it isn't captured by the map closure + let _ = match Some(0) { + Some(x) => Some({ + let y = (String::new(), String::new()); + (x, y.0) + }), + None => None, + }; + + // Don't lint. `s` is borrowed until partway through the arm, but needs to be captured by the map + // closure + let s = Some(String::new()); + let _ = match &s { + Some(x) => Some((x.clone(), s)), + None => None, + }; + + // Don't lint. `s` is borrowed until partway through the arm, but needs to be captured by the map + // closure + let s = Some(String::new()); + let _ = match &s { + Some(x) => Some({ + let clone = x.clone(); + let s = || s; + (clone, s()) + }), + None => None, + }; + + // Don't lint. `s` is borrowed until partway through the arm, but needs to be captured as a mutable + // reference by the map closure + let mut s = Some(String::new()); + let _ = match &s { + Some(x) => Some({ + let clone = x.clone(); + let ref mut s = s; + (clone, s) + }), + None => None, + }; + + // Lint. `s` is captured by reference, so no lifetime issues. + let s = Some(String::new()); + let _ = match &s { + Some(x) => Some({ + if let Some(ref s) = s { (x.clone(), s) } else { panic!() } + }), + None => None, + }; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_map_option_2.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,43 @@ +error: manual implementation of `Option::map` + --> $DIR/manual_map_option_2.rs:8:13 + | +LL | let _ = match Some(0) { + | _____________^ +LL | | Some(x) => Some({ +LL | | let y = (String::new(), String::new()); +LL | | (x, y.0) +LL | | }), +LL | | None => None, +LL | | }; + | |_____^ + | + = note: `-D clippy::manual-map` implied by `-D warnings` +help: try this + | +LL ~ let _ = Some(0).map(|x| { +LL + let y = (String::new(), String::new()); +LL + (x, y.0) +LL ~ }); + | + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option_2.rs:50:13 + | +LL | let _ = match &s { + | _____________^ +LL | | Some(x) => Some({ +LL | | if let Some(ref s) = s { (x.clone(), s) } else { panic!() } +LL | | }), +LL | | None => None, +LL | | }; + | |_____^ + | +help: try this + | +LL ~ let _ = s.as_ref().map(|x| { +LL + if let Some(ref s) = s { (x.clone(), s) } else { panic!() } +LL ~ }); + | + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,56 @@ +// run-rustfix + +#![feature(custom_inner_attributes)] +#![warn(clippy::manual_split_once)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] + +extern crate itertools; + +#[allow(unused_imports)] +use itertools::Itertools; + +fn main() { + let _ = Some("key=value".split_once('=').map_or("key=value", |x| x.0)); + let _ = "key=value".splitn(2, '=').nth(2); + let _ = "key=value".split_once('=').map_or("key=value", |x| x.0); + let _ = "key=value".split_once('=').map_or("key=value", |x| x.0); + let _ = "key=value".split_once('=').unwrap().1; + let _ = "key=value".split_once('=').unwrap().1; + let (_, _) = "key=value".split_once('=').unwrap(); + + let s = String::from("key=value"); + let _ = s.split_once('=').map_or(&*s, |x| x.0); + + let s = Box::::from("key=value"); + let _ = s.split_once('=').map_or(&*s, |x| x.0); + + let s = &"key=value"; + let _ = s.split_once('=').map_or(*s, |x| x.0); + + fn _f(s: &str) -> Option<&str> { + let _ = s.split_once("key=value").map_or(s, |x| x.0); + let _ = s.split_once("key=value")?.1; + let _ = s.split_once("key=value")?.1; + None + } + + // Don't lint, slices don't have `split_once` + let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); + + // `rsplitn` gives the results in the reverse order of `rsplit_once` + let _ = "key=value".rsplit_once('=').unwrap().1; + let _ = "key=value".rsplit_once('=').map_or("key=value", |x| x.0); + let _ = "key=value".rsplit_once('=').map(|x| x.1); + let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap(); +} + +fn _msrv_1_51() { + #![clippy::msrv = "1.51"] + // `str::split_once` was stabilized in 1.16. Do not lint this + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); +} + +fn _msrv_1_52() { + #![clippy::msrv = "1.52"] + let _ = "key=value".split_once('=').unwrap().1; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,56 @@ +// run-rustfix + +#![feature(custom_inner_attributes)] +#![warn(clippy::manual_split_once)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] + +extern crate itertools; + +#[allow(unused_imports)] +use itertools::Itertools; + +fn main() { + let _ = "key=value".splitn(2, '=').next(); + let _ = "key=value".splitn(2, '=').nth(2); + let _ = "key=value".splitn(2, '=').next().unwrap(); + let _ = "key=value".splitn(2, '=').nth(0).unwrap(); + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); + let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); + + let s = String::from("key=value"); + let _ = s.splitn(2, '=').next().unwrap(); + + let s = Box::::from("key=value"); + let _ = s.splitn(2, '=').nth(0).unwrap(); + + let s = &"key=value"; + let _ = s.splitn(2, '=').skip(0).next().unwrap(); + + fn _f(s: &str) -> Option<&str> { + let _ = s.splitn(2, "key=value").next()?; + let _ = s.splitn(2, "key=value").nth(1)?; + let _ = s.splitn(2, "key=value").skip(1).next()?; + None + } + + // Don't lint, slices don't have `split_once` + let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); + + // `rsplitn` gives the results in the reverse order of `rsplit_once` + let _ = "key=value".rsplitn(2, '=').next().unwrap(); + let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); + let _ = "key=value".rsplitn(2, '=').nth(0); + let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); +} + +fn _msrv_1_51() { + #![clippy::msrv = "1.51"] + // `str::split_once` was stabilized in 1.16. Do not lint this + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); +} + +fn _msrv_1_52() { + #![clippy::msrv = "1.52"] + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/manual_split_once.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,106 @@ +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:13:13 + | +LL | let _ = "key=value".splitn(2, '=').next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some("key=value".split_once('=').map_or("key=value", |x| x.0))` + | + = note: `-D clippy::manual-split-once` implied by `-D warnings` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:15:13 + | +LL | let _ = "key=value".splitn(2, '=').next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').map_or("key=value", |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:16:13 + | +LL | let _ = "key=value".splitn(2, '=').nth(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').map_or("key=value", |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:17:13 + | +LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:18:13 + | +LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:19:18 + | +LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=')` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:22:13 + | +LL | let _ = s.splitn(2, '=').next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(&*s, |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:25:13 + | +LL | let _ = s.splitn(2, '=').nth(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(&*s, |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:28:13 + | +LL | let _ = s.splitn(2, '=').skip(0).next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(*s, |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:31:17 + | +LL | let _ = s.splitn(2, "key=value").next()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value").map_or(s, |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:32:17 + | +LL | let _ = s.splitn(2, "key=value").nth(1)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:33:17 + | +LL | let _ = s.splitn(2, "key=value").skip(1).next()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1` + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:41:13 + | +LL | let _ = "key=value".rsplitn(2, '=').next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().1` + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:42:13 + | +LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map_or("key=value", |x| x.0)` + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:43:13 + | +LL | let _ = "key=value".rsplitn(2, '=').nth(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|x| x.1)` + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:44:18 + | +LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:55:13 + | +LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + +error: aborting due to 17 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/many_single_char_names.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/many_single_char_names.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/many_single_char_names.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/many_single_char_names.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -#[warn(clippy::many_single_char_names)] +#![warn(clippy::many_single_char_names)] fn bla() { let a: i32; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_clone.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_clone.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_clone.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_clone.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,11 @@ // run-rustfix -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::iter_cloned_collect)] -#![allow(clippy::clone_on_copy, clippy::redundant_clone)] -#![allow(clippy::let_underscore_drop)] -#![allow(clippy::missing_docs_in_private_items)] -#![allow(clippy::redundant_closure_for_method_calls)] -#![allow(clippy::many_single_char_names)] +#![warn(clippy::map_clone)] +#![allow( + clippy::clone_on_copy, + clippy::iter_cloned_collect, + clippy::many_single_char_names, + clippy::redundant_clone +)] fn main() { let _: Vec = vec![5_i8; 6].iter().copied().collect(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_clone.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_clone.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_clone.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_clone.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,11 +1,11 @@ // run-rustfix -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::iter_cloned_collect)] -#![allow(clippy::clone_on_copy, clippy::redundant_clone)] -#![allow(clippy::let_underscore_drop)] -#![allow(clippy::missing_docs_in_private_items)] -#![allow(clippy::redundant_closure_for_method_calls)] -#![allow(clippy::many_single_char_names)] +#![warn(clippy::map_clone)] +#![allow( + clippy::clone_on_copy, + clippy::iter_cloned_collect, + clippy::many_single_char_names, + clippy::redundant_clone +)] fn main() { let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -4,6 +4,7 @@ #![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] +#![allow(clippy::redundant_closure)] #![allow(clippy::unnecessary_wraps)] #![feature(result_flattening)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,6 +4,7 @@ #![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] +#![allow(clippy::redundant_closure)] #![allow(clippy::unnecessary_wraps)] #![feature(result_flattening)] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/map_flatten.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:17:46 + --> $DIR/map_flatten.rs:18:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)` @@ -7,37 +7,37 @@ = note: `-D clippy::map-flatten` implied by `-D warnings` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:18:46 + --> $DIR/map_flatten.rs:19:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:19:46 + --> $DIR/map_flatten.rs:20:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:20:46 + --> $DIR/map_flatten.rs:21:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:23:46 + --> $DIR/map_flatten.rs:24:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)` error: called `map(..).flatten()` on an `Option` - --> $DIR/map_flatten.rs:26:39 + --> $DIR/map_flatten.rs:27:39 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` error: called `map(..).flatten()` on an `Result` - --> $DIR/map_flatten.rs:29:41 + --> $DIR/map_flatten.rs:30:41 | LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::match_like_matches_macro)] -#![allow(unreachable_patterns, dead_code)] +#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)] fn main() { let x = Some(5); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::match_like_matches_macro)] -#![allow(unreachable_patterns, dead_code)] +#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)] fn main() { let x = Some(5); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_overlapping_arm.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_overlapping_arm.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_overlapping_arm.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_overlapping_arm.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ #![feature(half_open_range_patterns)] #![warn(clippy::match_overlapping_arm)] #![allow(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] /// Tests for match_overlapping_arm diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_ref_pats.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_ref_pats.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_ref_pats.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_ref_pats.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,5 @@ #![warn(clippy::match_ref_pats)] +#![allow(clippy::equatable_if_let)] fn ref_pats() { { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_ref_pats.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_ref_pats.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_ref_pats.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_ref_pats.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:6:9 + --> $DIR/match_ref_pats.rs:7:9 | LL | / match v { LL | | &Some(v) => println!("{:?}", v), @@ -16,7 +16,7 @@ | error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:17:5 + --> $DIR/match_ref_pats.rs:18:5 | LL | / match tup { LL | | &(v, 1) => println!("{}", v), @@ -31,7 +31,7 @@ | error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:23:5 + --> $DIR/match_ref_pats.rs:24:5 | LL | / match &w { LL | | &Some(v) => println!("{:?}", v), @@ -47,7 +47,7 @@ | error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:35:12 + --> $DIR/match_ref_pats.rs:36:12 | LL | if let &None = a { | -------^^^^^---- help: try this: `if a.is_none()` @@ -55,7 +55,7 @@ = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:35:5 + --> $DIR/match_ref_pats.rs:36:5 | LL | / if let &None = a { LL | | println!("none"); @@ -68,13 +68,13 @@ | ~~~~ ~~ error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:40:12 + --> $DIR/match_ref_pats.rs:41:12 | LL | if let &None = &b { | -------^^^^^----- help: try this: `if b.is_none()` error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:40:5 + --> $DIR/match_ref_pats.rs:41:5 | LL | / if let &None = &b { LL | | println!("none"); @@ -87,7 +87,7 @@ | ~~~~ ~ error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:67:9 + --> $DIR/match_ref_pats.rs:68:9 | LL | / match foo_variant!(0) { LL | | &Foo::A => println!("A"), diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,63 @@ +// run-rustfix + +#![warn(clippy::match_result_ok)] +#![allow(clippy::boxed_local)] +#![allow(dead_code)] + +// Checking `if` cases + +fn str_to_int(x: &str) -> i32 { + if let Ok(y) = x.parse() { y } else { 0 } +} + +fn str_to_int_ok(x: &str) -> i32 { + if let Ok(y) = x.parse() { y } else { 0 } +} + +#[rustfmt::skip] +fn strange_some_no_else(x: &str) -> i32 { + { + if let Ok(y) = x . parse() { + return y; + }; + 0 + } +} + +// Checking `while` cases + +struct Wat { + counter: i32, +} + +impl Wat { + fn next(&mut self) -> Result { + self.counter += 1; + if self.counter < 5 { + Ok(self.counter) + } else { + Err("Oh no") + } + } +} + +fn base_1(x: i32) { + let mut wat = Wat { counter: x }; + while let Ok(a) = wat.next() { + println!("{}", a); + } +} + +fn base_2(x: i32) { + let mut wat = Wat { counter: x }; + while let Ok(a) = wat.next() { + println!("{}", a); + } +} + +fn base_3(test_func: Box>) { + // Expected to stay as is + while let Some(_b) = test_func.ok() {} +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,63 @@ +// run-rustfix + +#![warn(clippy::match_result_ok)] +#![allow(clippy::boxed_local)] +#![allow(dead_code)] + +// Checking `if` cases + +fn str_to_int(x: &str) -> i32 { + if let Some(y) = x.parse().ok() { y } else { 0 } +} + +fn str_to_int_ok(x: &str) -> i32 { + if let Ok(y) = x.parse() { y } else { 0 } +} + +#[rustfmt::skip] +fn strange_some_no_else(x: &str) -> i32 { + { + if let Some(y) = x . parse() . ok () { + return y; + }; + 0 + } +} + +// Checking `while` cases + +struct Wat { + counter: i32, +} + +impl Wat { + fn next(&mut self) -> Result { + self.counter += 1; + if self.counter < 5 { + Ok(self.counter) + } else { + Err("Oh no") + } + } +} + +fn base_1(x: i32) { + let mut wat = Wat { counter: x }; + while let Some(a) = wat.next().ok() { + println!("{}", a); + } +} + +fn base_2(x: i32) { + let mut wat = Wat { counter: x }; + while let Ok(a) = wat.next() { + println!("{}", a); + } +} + +fn base_3(test_func: Box>) { + // Expected to stay as is + while let Some(_b) = test_func.ok() {} +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_result_ok.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,36 @@ +error: matching on `Some` with `ok()` is redundant + --> $DIR/match_result_ok.rs:10:5 + | +LL | if let Some(y) = x.parse().ok() { y } else { 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::match-result-ok` implied by `-D warnings` +help: consider matching on `Ok(y)` and removing the call to `ok` instead + | +LL | if let Ok(y) = x.parse() { y } else { 0 } + | ~~~~~~~~~~~~~~~~~~~~~~~~ + +error: matching on `Some` with `ok()` is redundant + --> $DIR/match_result_ok.rs:20:9 + | +LL | if let Some(y) = x . parse() . ok () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider matching on `Ok(y)` and removing the call to `ok` instead + | +LL | if let Ok(y) = x . parse() { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: matching on `Some` with `ok()` is redundant + --> $DIR/match_result_ok.rs:46:5 + | +LL | while let Some(a) = wat.next().ok() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider matching on `Ok(a)` and removing the call to `ok` instead + | +LL | while let Ok(a) = wat.next() { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 3 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_same_arms.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_same_arms.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_same_arms.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_same_arms.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -107,24 +107,6 @@ = help: ...or consider changing the match arm bodies error: this `match` has identical arm bodies - --> $DIR/match_same_arms.rs:33:14 - | -LL | 3 => 2, //~ ERROR 3rd matched arms have same body - | ^ - | -note: same as this - --> $DIR/match_same_arms.rs:32:14 - | -LL | 2 => 2, //~ ERROR 2nd matched arms have same body - | ^ -help: consider refactoring into `2 | 3` - --> $DIR/match_same_arms.rs:32:9 - | -LL | 2 => 2, //~ ERROR 2nd matched arms have same body - | ^ - = help: ...or consider changing the match arm bodies - -error: this `match` has identical arm bodies --> $DIR/match_same_arms.rs:50:55 | LL | CommandInfo::External { name, .. } => name.to_string(), @@ -142,5 +124,5 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: ...or consider changing the match arm bodies -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_single_binding.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_single_binding.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_single_binding.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_single_binding.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::match_single_binding)] -#![allow(unused_variables, clippy::many_single_char_names, clippy::toplevel_ref_arg)] +#![allow(unused_variables, clippy::toplevel_ref_arg)] struct Point { x: i32, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_single_binding.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_single_binding.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_single_binding.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/match_single_binding.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::match_single_binding)] -#![allow(unused_variables, clippy::many_single_char_names, clippy::toplevel_ref_arg)] +#![allow(unused_variables, clippy::toplevel_ref_arg)] struct Point { x: i32, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.fixed 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -// run-rustfix - -#![deny(clippy::mem_discriminant_non_enum)] - -use std::mem; - -enum Foo { - One(usize), - Two(u8), -} - -fn main() { - // bad - mem::discriminant(&Some(2)); - mem::discriminant(&None::); - mem::discriminant(&Foo::One(5)); - mem::discriminant(&Foo::Two(5)); - - let ro = &Some(3); - let rro = &ro; - mem::discriminant(ro); - mem::discriminant(*rro); - mem::discriminant(*rro); - - macro_rules! mem_discriminant_but_in_a_macro { - ($param:expr) => { - mem::discriminant($param) - }; - } - - mem_discriminant_but_in_a_macro!(*rro); - - let rrrrro = &&&rro; - mem::discriminant(****rrrrro); - mem::discriminant(****rrrrro); - - // ok - mem::discriminant(&Some(2)); - mem::discriminant(&None::); - mem::discriminant(&Foo::One(5)); - mem::discriminant(&Foo::Two(5)); - mem::discriminant(ro); - mem::discriminant(*rro); - mem::discriminant(****rrrrro); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -// run-rustfix - -#![deny(clippy::mem_discriminant_non_enum)] - -use std::mem; - -enum Foo { - One(usize), - Two(u8), -} - -fn main() { - // bad - mem::discriminant(&&Some(2)); - mem::discriminant(&&None::); - mem::discriminant(&&Foo::One(5)); - mem::discriminant(&&Foo::Two(5)); - - let ro = &Some(3); - let rro = &ro; - mem::discriminant(&ro); - mem::discriminant(rro); - mem::discriminant(&rro); - - macro_rules! mem_discriminant_but_in_a_macro { - ($param:expr) => { - mem::discriminant($param) - }; - } - - mem_discriminant_but_in_a_macro!(&rro); - - let rrrrro = &&&rro; - mem::discriminant(&rrrrro); - mem::discriminant(*rrrrro); - - // ok - mem::discriminant(&Some(2)); - mem::discriminant(&None::); - mem::discriminant(&Foo::One(5)); - mem::discriminant(&Foo::Two(5)); - mem::discriminant(ro); - mem::discriminant(*rro); - mem::discriminant(****rrrrro); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -error: calling `mem::discriminant` on non-enum type `&std::option::Option` - --> $DIR/mem_discriminant.rs:14:5 - | -LL | mem::discriminant(&&Some(2)); - | ^^^^^^^^^^^^^^^^^^---------^ - | | - | help: try dereferencing: `&Some(2)` - | -note: the lint level is defined here - --> $DIR/mem_discriminant.rs:3:9 - | -LL | #![deny(clippy::mem_discriminant_non_enum)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: calling `mem::discriminant` on non-enum type `&std::option::Option` - --> $DIR/mem_discriminant.rs:15:5 - | -LL | mem::discriminant(&&None::); - | ^^^^^^^^^^^^^^^^^^------------^ - | | - | help: try dereferencing: `&None::` - -error: calling `mem::discriminant` on non-enum type `&Foo` - --> $DIR/mem_discriminant.rs:16:5 - | -LL | mem::discriminant(&&Foo::One(5)); - | ^^^^^^^^^^^^^^^^^^-------------^ - | | - | help: try dereferencing: `&Foo::One(5)` - -error: calling `mem::discriminant` on non-enum type `&Foo` - --> $DIR/mem_discriminant.rs:17:5 - | -LL | mem::discriminant(&&Foo::Two(5)); - | ^^^^^^^^^^^^^^^^^^-------------^ - | | - | help: try dereferencing: `&Foo::Two(5)` - -error: calling `mem::discriminant` on non-enum type `&std::option::Option` - --> $DIR/mem_discriminant.rs:21:5 - | -LL | mem::discriminant(&ro); - | ^^^^^^^^^^^^^^^^^^---^ - | | - | help: try dereferencing: `ro` - -error: calling `mem::discriminant` on non-enum type `&std::option::Option` - --> $DIR/mem_discriminant.rs:22:5 - | -LL | mem::discriminant(rro); - | ^^^^^^^^^^^^^^^^^^---^ - | | - | help: try dereferencing: `*rro` - -error: calling `mem::discriminant` on non-enum type `&&std::option::Option` - --> $DIR/mem_discriminant.rs:23:5 - | -LL | mem::discriminant(&rro); - | ^^^^^^^^^^^^^^^^^^----^ - | | - | help: try dereferencing: `*rro` - -error: calling `mem::discriminant` on non-enum type `&&std::option::Option` - --> $DIR/mem_discriminant.rs:27:13 - | -LL | mem::discriminant($param) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | mem_discriminant_but_in_a_macro!(&rro); - | --------------------------------------- - | | | - | | help: try dereferencing: `*rro` - | in this macro invocation - | - = note: this error originates in the macro `mem_discriminant_but_in_a_macro` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: calling `mem::discriminant` on non-enum type `&&&&&std::option::Option` - --> $DIR/mem_discriminant.rs:34:5 - | -LL | mem::discriminant(&rrrrro); - | ^^^^^^^^^^^^^^^^^^-------^ - | | - | help: try dereferencing: `****rrrrro` - -error: calling `mem::discriminant` on non-enum type `&&&std::option::Option` - --> $DIR/mem_discriminant.rs:35:5 - | -LL | mem::discriminant(*rrrrro); - | ^^^^^^^^^^^^^^^^^^-------^ - | | - | help: try dereferencing: `****rrrrro` - -error: aborting due to 10 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -#![deny(clippy::mem_discriminant_non_enum)] - -use std::mem; - -enum Foo { - One(usize), - Two(u8), -} - -struct A(Foo); - -fn main() { - // bad - mem::discriminant(&"hello"); - mem::discriminant(&A(Foo::One(0))); -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -error: calling `mem::discriminant` on non-enum type `&str` - --> $DIR/mem_discriminant_unfixable.rs:14:5 - | -LL | mem::discriminant(&"hello"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/mem_discriminant_unfixable.rs:1:9 - | -LL | #![deny(clippy::mem_discriminant_non_enum)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: calling `mem::discriminant` on non-enum type `A` - --> $DIR/mem_discriminant_unfixable.rs:15:5 - | -LL | mem::discriminant(&A(Foo::One(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -51,9 +51,29 @@ let mut binary_heap: BinaryHeap = BinaryHeap::new(); let _ = std::mem::take(&mut binary_heap); + + let mut tuple = (vec![1, 2], BinaryHeap::::new()); + let _ = std::mem::take(&mut tuple); + + let mut refstr = "hello"; + let _ = std::mem::take(&mut refstr); + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = std::mem::take(&mut slice); +} + +// lint is disabled for primitives because in this case `take` +// has no clear benefit over `replace` and sometimes is harder to read +fn dont_lint_primitive() { + let mut pbool = true; + let _ = std::mem::replace(&mut pbool, false); + + let mut pint = 5; + let _ = std::mem::replace(&mut pint, 0); } fn main() { replace_option_with_none(); replace_with_default(); + dont_lint_primitive(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace_macro.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace_macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace_macro.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace_macro.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | take!(s); - | --------- in this macro invocation + | -------- in this macro invocation | = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` = note: this error originates in the macro `take` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.rs 2021-11-29 19:27:12.000000000 +0000 @@ -51,9 +51,29 @@ let mut binary_heap: BinaryHeap = BinaryHeap::new(); let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); + + let mut tuple = (vec![1, 2], BinaryHeap::::new()); + let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new())); + + let mut refstr = "hello"; + let _ = std::mem::replace(&mut refstr, ""); + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = std::mem::replace(&mut slice, &[]); +} + +// lint is disabled for primitives because in this case `take` +// has no clear benefit over `replace` and sometimes is harder to read +fn dont_lint_primitive() { + let mut pbool = true; + let _ = std::mem::replace(&mut pbool, false); + + let mut pint = 5; + let _ = std::mem::replace(&mut pint, 0); } fn main() { replace_option_with_none(); replace_with_default(); + dont_lint_primitive(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mem_replace.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -98,5 +98,23 @@ LL | let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)` -error: aborting due to 16 previous errors +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:56:13 + | +LL | let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut tuple)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:59:13 + | +LL | let _ = std::mem::replace(&mut refstr, ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut refstr)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:62:13 + | +LL | let _ = std::mem::replace(&mut slice, &[]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)` + +error: aborting due to 19 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/methods.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/methods.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/methods.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/methods.rs 2021-11-29 19:27:12.000000000 +0000 @@ -32,7 +32,7 @@ use std::rc::{self, Rc}; use std::sync::{self, Arc}; -use option_helpers::IteratorFalsePositives; +use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives}; struct Lt<'a> { foo: &'a u32, @@ -131,6 +131,9 @@ // Check that we don't lint if the caller is not an `Iterator`. let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.filter().next(); + + let foo = IteratorMethodFalsePositives {}; + let _ = foo.filter(42).next(); } fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/min_rust_version_attr.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/min_rust_version_attr.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/min_rust_version_attr.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/min_rust_version_attr.rs 2021-11-29 19:27:12.000000000 +0000 @@ -4,6 +4,11 @@ use std::ops::{Deref, RangeFrom}; +fn approx_const() { + let log2_10 = 3.321928094887362; + let log10_2 = 0.301029995663981; +} + fn cloned_instead_of_copied() { let _ = [1].iter().cloned(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/min_rust_version_attr.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/min_rust_version_attr.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/min_rust_version_attr.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/min_rust_version_attr.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,12 @@ error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:160:24 + --> $DIR/min_rust_version_attr.rs:165:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-strip` implied by `-D warnings` note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:159:9 + --> $DIR/min_rust_version_attr.rs:164:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,13 +17,13 @@ | error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:172:24 + --> $DIR/min_rust_version_attr.rs:177:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:171:9 + --> $DIR/min_rust_version_attr.rs:176:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/missing_panics_doc.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/missing_panics_doc.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/missing_panics_doc.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/missing_panics_doc.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -91,7 +91,7 @@ --> $DIR/missing_panics_doc.rs:39:5 | LL | assert_eq!(x, 0); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section @@ -107,7 +107,7 @@ --> $DIR/missing_panics_doc.rs:45:5 | LL | assert_ne!(x, 0); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 7 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,5 @@ #![warn(clippy::modulo_arithmetic)] -#![allow( - unused, - clippy::shadow_reuse, - clippy::shadow_unrelated, - clippy::no_effect, - clippy::unnecessary_operation, - clippy::modulo_one -)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] fn main() { // Lint when both sides are const and of the opposite sign diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: you are using modulo operator on constants with different signs: `-1.600 % 2.100` - --> $DIR/modulo_arithmetic_float.rs:13:5 + --> $DIR/modulo_arithmetic_float.rs:6:5 | LL | -1.6 % 2.1; | ^^^^^^^^^^ @@ -8,7 +8,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on constants with different signs: `1.600 % -2.100` - --> $DIR/modulo_arithmetic_float.rs:14:5 + --> $DIR/modulo_arithmetic_float.rs:7:5 | LL | 1.6 % -2.1; | ^^^^^^^^^^ @@ -16,7 +16,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on constants with different signs: `-1.200 % 3.400` - --> $DIR/modulo_arithmetic_float.rs:15:5 + --> $DIR/modulo_arithmetic_float.rs:8:5 | LL | (1.1 - 2.3) % (1.1 + 2.3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on constants with different signs: `3.400 % -1.200` - --> $DIR/modulo_arithmetic_float.rs:16:5 + --> $DIR/modulo_arithmetic_float.rs:9:5 | LL | (1.1 + 2.3) % (1.1 - 2.3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:21:5 + --> $DIR/modulo_arithmetic_float.rs:14:5 | LL | a_f32 % b_f32; | ^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:22:5 + --> $DIR/modulo_arithmetic_float.rs:15:5 | LL | b_f32 % a_f32; | ^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:23:5 + --> $DIR/modulo_arithmetic_float.rs:16:5 | LL | b_f32 %= a_f32; | ^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:27:5 + --> $DIR/modulo_arithmetic_float.rs:20:5 | LL | a_f64 % b_f64; | ^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:28:5 + --> $DIR/modulo_arithmetic_float.rs:21:5 | LL | b_f64 % a_f64; | ^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:29:5 + --> $DIR/modulo_arithmetic_float.rs:22:5 | LL | b_f64 %= a_f64; | ^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,5 @@ #![warn(clippy::modulo_arithmetic)] -#![allow( - unused, - clippy::shadow_reuse, - clippy::shadow_unrelated, - clippy::no_effect, - clippy::unnecessary_operation, - clippy::modulo_one -)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] fn main() { // Lint when both sides are const and of the opposite sign diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:13:5 + --> $DIR/modulo_arithmetic_integral_const.rs:6:5 | LL | -1 % 2; | ^^^^^^ @@ -9,7 +9,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:14:5 + --> $DIR/modulo_arithmetic_integral_const.rs:7:5 | LL | 1 % -2; | ^^^^^^ @@ -18,7 +18,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 3` - --> $DIR/modulo_arithmetic_integral_const.rs:15:5 + --> $DIR/modulo_arithmetic_integral_const.rs:8:5 | LL | (1 - 2) % (1 + 2); | ^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `3 % -1` - --> $DIR/modulo_arithmetic_integral_const.rs:16:5 + --> $DIR/modulo_arithmetic_integral_const.rs:9:5 | LL | (1 + 2) % (1 - 2); | ^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-35 % 300000` - --> $DIR/modulo_arithmetic_integral_const.rs:17:5 + --> $DIR/modulo_arithmetic_integral_const.rs:10:5 | LL | 35 * (7 - 4 * 2) % (-500 * -600); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:19:5 + --> $DIR/modulo_arithmetic_integral_const.rs:12:5 | LL | -1i8 % 2i8; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:20:5 + --> $DIR/modulo_arithmetic_integral_const.rs:13:5 | LL | 1i8 % -2i8; | ^^^^^^^^^^ @@ -63,7 +63,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:21:5 + --> $DIR/modulo_arithmetic_integral_const.rs:14:5 | LL | -1i16 % 2i16; | ^^^^^^^^^^^^ @@ -72,7 +72,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:22:5 + --> $DIR/modulo_arithmetic_integral_const.rs:15:5 | LL | 1i16 % -2i16; | ^^^^^^^^^^^^ @@ -81,7 +81,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:23:5 + --> $DIR/modulo_arithmetic_integral_const.rs:16:5 | LL | -1i32 % 2i32; | ^^^^^^^^^^^^ @@ -90,7 +90,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:24:5 + --> $DIR/modulo_arithmetic_integral_const.rs:17:5 | LL | 1i32 % -2i32; | ^^^^^^^^^^^^ @@ -99,7 +99,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:25:5 + --> $DIR/modulo_arithmetic_integral_const.rs:18:5 | LL | -1i64 % 2i64; | ^^^^^^^^^^^^ @@ -108,7 +108,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:26:5 + --> $DIR/modulo_arithmetic_integral_const.rs:19:5 | LL | 1i64 % -2i64; | ^^^^^^^^^^^^ @@ -117,7 +117,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:27:5 + --> $DIR/modulo_arithmetic_integral_const.rs:20:5 | LL | -1i128 % 2i128; | ^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:28:5 + --> $DIR/modulo_arithmetic_integral_const.rs:21:5 | LL | 1i128 % -2i128; | ^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:29:5 + --> $DIR/modulo_arithmetic_integral_const.rs:22:5 | LL | -1isize % 2isize; | ^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:30:5 + --> $DIR/modulo_arithmetic_integral_const.rs:23:5 | LL | 1isize % -2isize; | ^^^^^^^^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,5 @@ #![warn(clippy::modulo_arithmetic)] -#![allow( - unused, - clippy::shadow_reuse, - clippy::shadow_unrelated, - clippy::no_effect, - clippy::unnecessary_operation, - clippy::modulo_one -)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] fn main() { // Lint on signed integral numbers diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:15:5 + --> $DIR/modulo_arithmetic_integral.rs:8:5 | LL | a % b; | ^^^^^ @@ -9,7 +9,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:16:5 + --> $DIR/modulo_arithmetic_integral.rs:9:5 | LL | b % a; | ^^^^^ @@ -18,7 +18,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:17:5 + --> $DIR/modulo_arithmetic_integral.rs:10:5 | LL | b %= a; | ^^^^^^ @@ -27,7 +27,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:21:5 + --> $DIR/modulo_arithmetic_integral.rs:14:5 | LL | a_i8 % b_i8; | ^^^^^^^^^^^ @@ -36,7 +36,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:22:5 + --> $DIR/modulo_arithmetic_integral.rs:15:5 | LL | b_i8 %= a_i8; | ^^^^^^^^^^^^ @@ -45,7 +45,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:26:5 + --> $DIR/modulo_arithmetic_integral.rs:19:5 | LL | a_i16 % b_i16; | ^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:27:5 + --> $DIR/modulo_arithmetic_integral.rs:20:5 | LL | b_i16 %= a_i16; | ^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:31:5 + --> $DIR/modulo_arithmetic_integral.rs:24:5 | LL | a_i32 % b_i32; | ^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:32:5 + --> $DIR/modulo_arithmetic_integral.rs:25:5 | LL | b_i32 %= a_i32; | ^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:36:5 + --> $DIR/modulo_arithmetic_integral.rs:29:5 | LL | a_i64 % b_i64; | ^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:37:5 + --> $DIR/modulo_arithmetic_integral.rs:30:5 | LL | b_i64 %= a_i64; | ^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:41:5 + --> $DIR/modulo_arithmetic_integral.rs:34:5 | LL | a_i128 % b_i128; | ^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:42:5 + --> $DIR/modulo_arithmetic_integral.rs:35:5 | LL | b_i128 %= a_i128; | ^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:46:5 + --> $DIR/modulo_arithmetic_integral.rs:39:5 | LL | a_isize % b_isize; | ^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:47:5 + --> $DIR/modulo_arithmetic_integral.rs:40:5 | LL | b_isize %= a_isize; | ^^^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:51:5 + --> $DIR/modulo_arithmetic_integral.rs:44:5 | LL | a % b; | ^^^^^ @@ -144,7 +144,7 @@ = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:52:5 + --> $DIR/modulo_arithmetic_integral.rs:45:5 | LL | b %= a; | ^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_one.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_one.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_one.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/modulo_one.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -46,12 +46,6 @@ | = note: `-D clippy::identity-op` implied by `-D warnings` -error: the operation is ineffective. Consider reducing it to `1` - --> $DIR/modulo_one.rs:13:22 - | -LL | const ONE: u32 = 1 * 1; - | ^^^^^ - error: any number modulo 1 will be 0 --> $DIR/modulo_one.rs:17:5 | @@ -70,5 +64,5 @@ LL | INT_MIN % NEG_ONE; // also caught by rustc | ^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_key.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_key.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_key.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_key.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,9 @@ -use std::collections::{HashMap, HashSet}; +use std::cell::Cell; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::hash::{Hash, Hasher}; +use std::rc::Rc; use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; +use std::sync::Arc; struct Key(AtomicUsize); @@ -31,11 +34,19 @@ fn this_is_ok(_m: &mut HashMap) {} +// Raw pointers are hashed by the address they point to, so it doesn't matter if they point to a +// type with interior mutability. See: +// - clippy issue: https://github.com/rust-lang/rust-clippy/issues/6745 +// - std lib: https://github.com/rust-lang/rust/blob/1.54.0/library/core/src/hash/mod.rs#L717-L736 +// So these are OK: +fn raw_ptr_is_ok(_m: &mut HashMap<*const Key, ()>) {} +fn raw_mut_ptr_is_ok(_m: &mut HashMap<*mut Key, ()>) {} + #[allow(unused)] trait Trait { type AssociatedType; - fn trait_fn(&self, set: std::collections::HashSet); + fn trait_fn(&self, set: HashSet); } fn generics_are_ok_too(_m: &mut HashSet) { @@ -52,4 +63,23 @@ tuples::(&mut HashMap::new()); tuples::<()>(&mut HashMap::new()); tuples_bad::<()>(&mut HashMap::new()); + + raw_ptr_is_ok(&mut HashMap::new()); + raw_mut_ptr_is_ok(&mut HashMap::new()); + + let _map = HashMap::, usize>::new(); + let _map = HashMap::<&mut Cell, usize>::new(); + let _map = HashMap::<&mut usize, usize>::new(); + // Collection types from `std` who's impl of `Hash` or `Ord` delegate their type parameters + let _map = HashMap::>, usize>::new(); + let _map = HashMap::, ()>, usize>::new(); + let _map = HashMap::>, usize>::new(); + let _map = HashMap::>, usize>::new(); + let _map = HashMap::>, usize>::new(); + let _map = HashMap::>>, usize>::new(); + let _map = HashMap::, usize>::new(); + // Smart pointers from `std` who's impl of `Hash` or `Ord` delegate their type parameters + let _map = HashMap::>, usize>::new(); + let _map = HashMap::>, usize>::new(); + let _map = HashMap::>, usize>::new(); } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_key.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_key.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_key.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_key.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: mutable key type - --> $DIR/mut_key.rs:27:32 + --> $DIR/mut_key.rs:30:32 | LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,22 +7,100 @@ = note: `-D clippy::mutable-key-type` implied by `-D warnings` error: mutable key type - --> $DIR/mut_key.rs:27:72 + --> $DIR/mut_key.rs:30:72 | LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:28:5 + --> $DIR/mut_key.rs:31:5 | LL | let _other: HashMap = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:47:22 + --> $DIR/mut_key.rs:58:22 | LL | fn tuples_bad(_m: &mut HashMap<(Key, U), bool>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: mutable key type + --> $DIR/mut_key.rs:70:5 + | +LL | let _map = HashMap::, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:71:5 + | +LL | let _map = HashMap::<&mut Cell, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:72:5 + | +LL | let _map = HashMap::<&mut usize, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:74:5 + | +LL | let _map = HashMap::>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:75:5 + | +LL | let _map = HashMap::, ()>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:76:5 + | +LL | let _map = HashMap::>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:77:5 + | +LL | let _map = HashMap::>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:78:5 + | +LL | let _map = HashMap::>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:79:5 + | +LL | let _map = HashMap::>>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:80:5 + | +LL | let _map = HashMap::, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:82:5 + | +LL | let _map = HashMap::>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:83:5 + | +LL | let _map = HashMap::>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:84:5 + | +LL | let _map = HashMap::>, usize>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_range_bound.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_range_bound.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_range_bound.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_range_bound.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,14 +1,6 @@ #![allow(unused)] -fn main() { - mut_range_bound_upper(); - mut_range_bound_lower(); - mut_range_bound_both(); - mut_range_bound_no_mutation(); - immut_range_bound(); - mut_borrow_range_bound(); - immut_borrow_range_bound(); -} +fn main() {} fn mut_range_bound_upper() { let mut m = 4; @@ -61,3 +53,32 @@ continue; } // no warning } + +fn mut_range_bound_break() { + let mut m = 4; + for i in 0..m { + if m == 4 { + m = 5; // no warning because of immediate break + break; + } + } +} + +fn mut_range_bound_no_immediate_break() { + let mut m = 4; + for i in 0..m { + m = 2; // warning because it is not immediately followed by break + if m == 4 { + break; + } + } + + let mut n = 3; + for i in n..10 { + if n == 4 { + n = 1; // FIXME: warning because is is not immediately followed by break + let _ = 2; + break; + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_range_bound.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_range_bound.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_range_bound.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/mut_range_bound.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,34 +1,59 @@ -error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:16:9 +error: attempt to mutate range bound within loop + --> $DIR/mut_range_bound.rs:8:9 | LL | m = 5; | ^ | = note: `-D clippy::mut-range-bound` implied by `-D warnings` + = note: the range of the loop is unchanged -error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:23:9 +error: attempt to mutate range bound within loop + --> $DIR/mut_range_bound.rs:15:9 | LL | m *= 2; | ^ + | + = note: the range of the loop is unchanged -error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:31:9 +error: attempt to mutate range bound within loop + --> $DIR/mut_range_bound.rs:23:9 | LL | m = 5; | ^ + | + = note: the range of the loop is unchanged -error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:32:9 +error: attempt to mutate range bound within loop + --> $DIR/mut_range_bound.rs:24:9 | LL | n = 7; | ^ + | + = note: the range of the loop is unchanged -error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:46:22 +error: attempt to mutate range bound within loop + --> $DIR/mut_range_bound.rs:38:22 | LL | let n = &mut m; // warning | ^ + | + = note: the range of the loop is unchanged + +error: attempt to mutate range bound within loop + --> $DIR/mut_range_bound.rs:70:9 + | +LL | m = 2; // warning because it is not immediately followed by break + | ^ + | + = note: the range of the loop is unchanged + +error: attempt to mutate range bound within loop + --> $DIR/mut_range_bound.rs:79:13 + | +LL | n = 1; // FIXME: warning because is is not immediately followed by break + | ^ + | + = note: the range of the loop is unchanged -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ dead_code, clippy::no_effect, clippy::if_same_then_else, + clippy::equatable_if_let, clippy::needless_return, clippy::self_named_constructors )] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ dead_code, clippy::no_effect, clippy::if_same_then_else, + clippy::equatable_if_let, clippy::needless_return, clippy::self_named_constructors )] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_bool/fixable.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:40:5 + --> $DIR/fixable.rs:41:5 | LL | / if x { LL | | true @@ -11,7 +11,7 @@ = note: `-D clippy::needless-bool` implied by `-D warnings` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:45:5 + --> $DIR/fixable.rs:46:5 | LL | / if x { LL | | false @@ -21,7 +21,7 @@ | |_____^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:50:5 + --> $DIR/fixable.rs:51:5 | LL | / if x && y { LL | | false @@ -31,7 +31,7 @@ | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:70:5 + --> $DIR/fixable.rs:71:5 | LL | / if x { LL | | return true; @@ -41,7 +41,7 @@ | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:78:5 + --> $DIR/fixable.rs:79:5 | LL | / if x { LL | | return false; @@ -51,7 +51,7 @@ | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:86:5 + --> $DIR/fixable.rs:87:5 | LL | / if x && y { LL | | return true; @@ -61,7 +61,7 @@ | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:94:5 + --> $DIR/fixable.rs:95:5 | LL | / if x && y { LL | | return false; @@ -71,7 +71,7 @@ | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:102:8 + --> $DIR/fixable.rs:103:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -79,25 +79,25 @@ = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:106:8 + --> $DIR/fixable.rs:107:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:116:8 + --> $DIR/fixable.rs:117:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:117:8 + --> $DIR/fixable.rs:118:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:126:12 + --> $DIR/fixable.rs:127:12 | LL | } else if returns_bool() { | ____________^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,17 +1,16 @@ // run-rustfix -#![allow(clippy::needless_borrowed_reference)] - -fn x(y: &i32) -> i32 { - *y -} - #[warn(clippy::all, clippy::needless_borrow)] #[allow(unused_variables)] fn main() { let a = 5; - let b = x(&a); - let c = x(&a); + let _ = x(&a); // no warning + let _ = x(&a); // warn + + let mut b = 5; + mut_ref(&mut b); // no warning + mut_ref(&mut b); // warn + let s = &String::from("hi"); let s_ident = f(&s); // should not error, because `&String` implements Copy, but `String` does not let g_val = g(&Vec::new()); // should not error, because `&Vec` derefs to `&[T]` @@ -29,6 +28,15 @@ }; } +#[allow(clippy::needless_borrowed_reference)] +fn x(y: &i32) -> i32 { + *y +} + +fn mut_ref(y: &mut i32) { + *y = 5; +} + fn f(y: &T) -> T { *y } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,17 +1,16 @@ // run-rustfix -#![allow(clippy::needless_borrowed_reference)] - -fn x(y: &i32) -> i32 { - *y -} - #[warn(clippy::all, clippy::needless_borrow)] #[allow(unused_variables)] fn main() { let a = 5; - let b = x(&a); - let c = x(&&a); + let _ = x(&a); // no warning + let _ = x(&&a); // warn + + let mut b = 5; + mut_ref(&mut b); // no warning + mut_ref(&mut &mut b); // warn + let s = &String::from("hi"); let s_ident = f(&s); // should not error, because `&String` implements Copy, but `String` does not let g_val = g(&Vec::new()); // should not error, because `&Vec` derefs to `&[T]` @@ -29,6 +28,15 @@ }; } +#[allow(clippy::needless_borrowed_reference)] +fn x(y: &i32) -> i32 { + *y +} + +fn mut_ref(y: &mut i32) { + *y = 5; +} + fn f(y: &T) -> T { *y } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_borrow.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,16 +1,22 @@ error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:14:15 + --> $DIR/needless_borrow.rs:8:15 | -LL | let c = x(&&a); +LL | let _ = x(&&a); // warn | ^^^ help: change this to: `&a` | = note: `-D clippy::needless-borrow` implied by `-D warnings` +error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:12:13 + | +LL | mut_ref(&mut &mut b); // warn + | ^^^^^^^^^^^ help: change this to: `&mut b` + error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:27:15 + --> $DIR/needless_borrow.rs:26:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.fixed 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,13 @@ +// run-rustfix + +#[warn(clippy::needless_option_as_deref)] + +fn main() { + // should lint + let _: Option<&usize> = Some(&1); + let _: Option<&mut usize> = Some(&mut 1); + + // should not lint + let _ = Some(Box::new(1)).as_deref(); + let _ = Some(Box::new(1)).as_deref_mut(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,13 @@ +// run-rustfix + +#[warn(clippy::needless_option_as_deref)] + +fn main() { + // should lint + let _: Option<&usize> = Some(&1).as_deref(); + let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); + + // should not lint + let _ = Some(Box::new(1)).as_deref(); + let _ = Some(Box::new(1)).as_deref_mut(); +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_option_as_deref.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,16 @@ +error: derefed type is same as origin + --> $DIR/needless_option_as_deref.rs:7:29 + | +LL | let _: Option<&usize> = Some(&1).as_deref(); + | ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)` + | + = note: `-D clippy::needless-option-as-deref` implied by `-D warnings` + +error: derefed type is same as origin + --> $DIR/needless_option_as_deref.rs:8:33 + | +LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)` + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_pass_by_value.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_pass_by_value.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_pass_by_value.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_pass_by_value.rs 2021-11-29 19:27:12.000000000 +0000 @@ -3,7 +3,6 @@ dead_code, clippy::single_match, clippy::redundant_pattern_matching, - clippy::many_single_char_names, clippy::option_option, clippy::redundant_clone )] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_pass_by_value.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_pass_by_value.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_pass_by_value.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_pass_by_value.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:18:23 + --> $DIR/needless_pass_by_value.rs:17:23 | LL | fn foo(v: Vec, w: Vec, mut x: Vec, y: Vec) -> Vec { | ^^^^^^ help: consider changing the type to: `&[T]` @@ -7,55 +7,55 @@ = note: `-D clippy::needless-pass-by-value` implied by `-D warnings` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:32:11 + --> $DIR/needless_pass_by_value.rs:31:11 | LL | fn bar(x: String, y: Wrapper) { | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:32:22 + --> $DIR/needless_pass_by_value.rs:31:22 | LL | fn bar(x: String, y: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:38:71 + --> $DIR/needless_pass_by_value.rs:37:71 | LL | fn test_borrow_trait, U: AsRef, V>(t: T, u: U, v: V) { | ^ help: consider taking a reference instead: `&V` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:50:18 + --> $DIR/needless_pass_by_value.rs:49:18 | LL | fn test_match(x: Option>, y: Option>) { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&Option>` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:63:24 + --> $DIR/needless_pass_by_value.rs:62:24 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:63:36 + --> $DIR/needless_pass_by_value.rs:62:36 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:79:49 + --> $DIR/needless_pass_by_value.rs:78:49 | LL | fn test_blanket_ref(_foo: T, _serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:81:18 + --> $DIR/needless_pass_by_value.rs:80:18 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:81:29 + --> $DIR/needless_pass_by_value.rs:80:29 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^ @@ -70,13 +70,13 @@ | ~~~~~~~~~~~~~ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:81:40 + --> $DIR/needless_pass_by_value.rs:80:40 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^^^ help: consider taking a reference instead: `&Vec` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:81:53 + --> $DIR/needless_pass_by_value.rs:80:53 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^^^ @@ -91,85 +91,85 @@ | ~~~~~~~~~~~~ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:94:12 + --> $DIR/needless_pass_by_value.rs:93:12 | LL | s: String, | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:95:12 + --> $DIR/needless_pass_by_value.rs:94:12 | LL | t: String, | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:104:23 + --> $DIR/needless_pass_by_value.rs:103:23 | LL | fn baz(&self, _u: U, _s: Self) {} | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:104:30 + --> $DIR/needless_pass_by_value.rs:103:30 | LL | fn baz(&self, _u: U, _s: Self) {} | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:126:24 + --> $DIR/needless_pass_by_value.rs:125:24 | LL | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as `Copy` - --> $DIR/needless_pass_by_value.rs:124:1 + --> $DIR/needless_pass_by_value.rs:123:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:132:29 + --> $DIR/needless_pass_by_value.rs:131:29 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as `Copy` - --> $DIR/needless_pass_by_value.rs:124:1 + --> $DIR/needless_pass_by_value.rs:123:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:132:45 + --> $DIR/needless_pass_by_value.rs:131:45 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as `Copy` - --> $DIR/needless_pass_by_value.rs:124:1 + --> $DIR/needless_pass_by_value.rs:123:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:132:61 + --> $DIR/needless_pass_by_value.rs:131:61 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as `Copy` - --> $DIR/needless_pass_by_value.rs:124:1 + --> $DIR/needless_pass_by_value.rs:123:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:144:40 + --> $DIR/needless_pass_by_value.rs:143:40 | LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:149:20 + --> $DIR/needless_pass_by_value.rs:148:20 | LL | fn more_fun(_item: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,13 @@ // run-rustfix // edition:2018 +#![feature(let_else)] #![allow(unused)] #![allow( clippy::if_same_then_else, clippy::single_match, - clippy::branches_sharing_code, - clippy::needless_bool + clippy::needless_bool, + clippy::equatable_if_let )] #![warn(clippy::needless_return)] @@ -207,4 +208,8 @@ needed_return!(0); } +fn let_else() { + let Some(1) = Some(1) else { return }; +} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,12 +1,13 @@ // run-rustfix // edition:2018 +#![feature(let_else)] #![allow(unused)] #![allow( clippy::if_same_then_else, clippy::single_match, - clippy::branches_sharing_code, - clippy::needless_bool + clippy::needless_bool, + clippy::equatable_if_let )] #![warn(clippy::needless_return)] @@ -207,4 +208,8 @@ needed_return!(0); } +fn let_else() { + let Some(1) = Some(1) else { return }; +} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/needless_return.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> $DIR/needless_return.rs:24:5 + --> $DIR/needless_return.rs:25:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` @@ -7,187 +7,187 @@ = note: `-D clippy::needless-return` implied by `-D warnings` error: unneeded `return` statement - --> $DIR/needless_return.rs:28:5 + --> $DIR/needless_return.rs:29:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:33:9 + --> $DIR/needless_return.rs:34:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:35:9 + --> $DIR/needless_return.rs:36:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:41:17 + --> $DIR/needless_return.rs:42:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:43:13 + --> $DIR/needless_return.rs:44:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:50:9 + --> $DIR/needless_return.rs:51:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:52:16 + --> $DIR/needless_return.rs:53:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:60:5 + --> $DIR/needless_return.rs:61:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:65:9 + --> $DIR/needless_return.rs:66:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:67:9 + --> $DIR/needless_return.rs:68:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:74:14 + --> $DIR/needless_return.rs:75:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:89:9 + --> $DIR/needless_return.rs:90:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:91:9 + --> $DIR/needless_return.rs:92:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:112:32 + --> $DIR/needless_return.rs:113:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:117:13 + --> $DIR/needless_return.rs:118:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:119:20 + --> $DIR/needless_return.rs:120:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:125:32 + --> $DIR/needless_return.rs:126:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:134:5 + --> $DIR/needless_return.rs:135:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:138:5 + --> $DIR/needless_return.rs:139:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:143:9 + --> $DIR/needless_return.rs:144:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:145:9 + --> $DIR/needless_return.rs:146:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:151:17 + --> $DIR/needless_return.rs:152:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:153:13 + --> $DIR/needless_return.rs:154:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:160:9 + --> $DIR/needless_return.rs:161:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:162:16 + --> $DIR/needless_return.rs:163:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:170:5 + --> $DIR/needless_return.rs:171:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:175:9 + --> $DIR/needless_return.rs:176:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:177:9 + --> $DIR/needless_return.rs:178:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:184:14 + --> $DIR/needless_return.rs:185:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:199:9 + --> $DIR/needless_return.rs:200:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:201:9 + --> $DIR/needless_return.rs:202:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)] +#![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] fn methods_with_negation() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/nonminimal_bool.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/nonminimal_bool.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/nonminimal_bool.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/nonminimal_bool.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)] +#![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,127 @@ +#![warn(clippy::non_send_fields_in_send_ty)] +#![feature(extern_types)] + +use std::cell::UnsafeCell; +use std::ptr::NonNull; +use std::rc::Rc; +use std::sync::{Arc, Mutex, MutexGuard}; + +// disrustor / RUSTSEC-2020-0150 +pub struct RingBuffer { + data: Vec>, + capacity: usize, + mask: usize, +} + +unsafe impl Send for RingBuffer {} + +// noise_search / RUSTSEC-2020-0141 +pub struct MvccRwLock { + raw: *const T, + lock: Mutex>, +} + +unsafe impl Send for MvccRwLock {} + +// async-coap / RUSTSEC-2020-0124 +pub struct ArcGuard { + inner: T, + head: Arc, +} + +unsafe impl Send for ArcGuard {} + +// rusb / RUSTSEC-2020-0098 +extern "C" { + type libusb_device_handle; +} + +pub trait UsbContext { + // some user trait that does not guarantee `Send` +} + +pub struct DeviceHandle { + context: T, + handle: NonNull, +} + +unsafe impl Send for DeviceHandle {} + +// Other basic tests +pub struct NoGeneric { + rc_is_not_send: Rc, +} + +unsafe impl Send for NoGeneric {} + +pub struct MultiField { + field1: T, + field2: T, + field3: T, +} + +unsafe impl Send for MultiField {} + +pub enum MyOption { + MySome(T), + MyNone, +} + +unsafe impl Send for MyOption {} + +// Multiple type parameters +pub struct MultiParam { + vec: Vec<(A, B)>, +} + +unsafe impl Send for MultiParam {} + +// Tests for raw pointer heuristic +extern "C" { + type NonSend; +} + +pub struct HeuristicTest { + // raw pointers are allowed + field1: Vec<*const NonSend>, + field2: [*const NonSend; 3], + field3: (*const NonSend, *const NonSend, *const NonSend), + // not allowed when it contains concrete `!Send` field + field4: (*const NonSend, Rc), + // nested raw pointer is also allowed + field5: Vec>, +} + +unsafe impl Send for HeuristicTest {} + +// Test attributes +#[allow(clippy::non_send_fields_in_send_ty)] +pub struct AttrTest1(T); + +pub struct AttrTest2 { + #[allow(clippy::non_send_fields_in_send_ty)] + field: T, +} + +pub enum AttrTest3 { + #[allow(clippy::non_send_fields_in_send_ty)] + Enum1(T), + Enum2(T), +} + +unsafe impl Send for AttrTest1 {} +unsafe impl Send for AttrTest2 {} +unsafe impl Send for AttrTest3 {} + +// Multiple non-overlapping `Send` for a single type +pub struct Complex { + field1: A, + field2: B, +} + +unsafe impl

Send for Complex {} + +// `MutexGuard` is non-Send +unsafe impl Send for Complex> {} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,171 @@ +error: this implementation is unsound, as some fields in `RingBuffer` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:16:1 + | +LL | unsafe impl Send for RingBuffer {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` +note: the type of field `data` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:11:5 + | +LL | data: Vec>, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = help: add bounds on type parameter `T` that satisfy `Vec>: Send` + +error: this implementation is unsound, as some fields in `MvccRwLock` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:24:1 + | +LL | unsafe impl Send for MvccRwLock {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `lock` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:21:5 + | +LL | lock: Mutex>, + | ^^^^^^^^^^^^^^^^^^^ + = help: add bounds on type parameter `T` that satisfy `Mutex>: Send` + +error: this implementation is unsound, as some fields in `ArcGuard` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:32:1 + | +LL | unsafe impl Send for ArcGuard {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `head` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:29:5 + | +LL | head: Arc, + | ^^^^^^^^^^^^^ + = help: add bounds on type parameter `RC` that satisfy `Arc: Send` + +error: this implementation is unsound, as some fields in `DeviceHandle` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:48:1 + | +LL | unsafe impl Send for DeviceHandle {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `context` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:44:5 + | +LL | context: T, + | ^^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `NoGeneric` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:55:1 + | +LL | unsafe impl Send for NoGeneric {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `rc_is_not_send` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:52:5 + | +LL | rc_is_not_send: Rc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: this implementation is unsound, as some fields in `MultiField` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:63:1 + | +LL | unsafe impl Send for MultiField {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field1` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:58:5 + | +LL | field1: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl +note: the type of field `field2` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:59:5 + | +LL | field2: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl +note: the type of field `field3` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:60:5 + | +LL | field3: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `MyOption` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:70:1 + | +LL | unsafe impl Send for MyOption {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `0` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:66:12 + | +LL | MySome(T), + | ^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `MultiParam` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:77:1 + | +LL | unsafe impl Send for MultiParam {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `vec` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:74:5 + | +LL | vec: Vec<(A, B)>, + | ^^^^^^^^^^^^^^^^ + = help: add bounds on type parameters `A, B` that satisfy `Vec<(A, B)>: Send` + +error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:95:1 + | +LL | unsafe impl Send for HeuristicTest {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field4` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:90:5 + | +LL | field4: (*const NonSend, Rc), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: this implementation is unsound, as some fields in `AttrTest3` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:114:1 + | +LL | unsafe impl Send for AttrTest3 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `0` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:109:11 + | +LL | Enum2(T), + | ^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `Complex` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:122:1 + | +LL | unsafe impl

Send for Complex {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field1` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:118:5 + | +LL | field1: A, + | ^^^^^^^^^ + = help: add `P: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `Complex>` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:125:1 + | +LL | unsafe impl Send for Complex> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field2` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:119:5 + | +LL | field2: B, + | ^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: aborting due to 12 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/op_ref.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/op_ref.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/op_ref.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/op_ref.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,5 @@ #![allow(unused_variables, clippy::blacklisted_name)] #![warn(clippy::op_ref)] -#![allow(clippy::many_single_char_names)] use std::collections::HashSet; use std::ops::BitAnd; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/op_ref.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/op_ref.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/op_ref.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/op_ref.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: needlessly taken reference of both operands - --> $DIR/op_ref.rs:12:15 + --> $DIR/op_ref.rs:11:15 | LL | let foo = &5 - &6; | ^^^^^^^ @@ -11,7 +11,7 @@ | ~ ~ error: taken reference of right operand - --> $DIR/op_ref.rs:57:13 + --> $DIR/op_ref.rs:56:13 | LL | let z = x & &y; | ^^^^-- diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,8 @@ +// edition:2018 // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure)] -#![allow(clippy::ref_option_ref)] +#![allow(clippy::ref_option_ref, clippy::equatable_if_let)] fn bad1(string: Option<&str>) -> (bool, &str) { string.map_or((false, "hello"), |x| (true, x)) @@ -86,4 +87,65 @@ test_map_or_else(None); let _ = negative_tests(None); let _ = impure_else(None); + + let _ = Some(0).map_or(0, |x| loop { + if x == 0 { + break x; + } + }); + + // #7576 + const fn _f(x: Option) -> u32 { + // Don't lint, `map_or` isn't const + if let Some(x) = x { x } else { 10 } + } + + // #5822 + let s = String::new(); + // Don't lint, `Some` branch consumes `s`, but else branch uses `s` + let _ = if let Some(x) = Some(0) { + let s = s; + s.len() + x + } else { + s.len() + }; + + let s = String::new(); + // Lint, both branches immutably borrow `s`. + let _ = Some(0).map_or_else(|| s.len(), |x| s.len() + x); + + let s = String::new(); + // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`. + let _ = Some(0).map_or(1, |x| { + let s = s; + s.len() + x + }); + + let s = Some(String::new()); + // Don't lint, `Some` branch borrows `s`, but else branch consumes `s` + let _ = if let Some(x) = &s { + x.len() + } else { + let _s = s; + 10 + }; + + let mut s = Some(String::new()); + // Don't lint, `Some` branch mutably borrows `s`, but else branch also borrows `s` + let _ = if let Some(x) = &mut s { + x.push_str("test"); + x.len() + } else { + let _s = &s; + 10 + }; + + async fn _f1(x: u32) -> u32 { + x + } + + async fn _f2() { + // Don't lint. `await` can't be moved into a closure. + let _ = if let Some(x) = Some(0) { _f1(x).await } else { 0 }; + } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,8 @@ +// edition:2018 // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure)] -#![allow(clippy::ref_option_ref)] +#![allow(clippy::ref_option_ref, clippy::equatable_if_let)] fn bad1(string: Option<&str>) -> (bool, &str) { if let Some(x) = string { @@ -105,4 +106,71 @@ test_map_or_else(None); let _ = negative_tests(None); let _ = impure_else(None); + + let _ = if let Some(x) = Some(0) { + loop { + if x == 0 { + break x; + } + } + } else { + 0 + }; + + // #7576 + const fn _f(x: Option) -> u32 { + // Don't lint, `map_or` isn't const + if let Some(x) = x { x } else { 10 } + } + + // #5822 + let s = String::new(); + // Don't lint, `Some` branch consumes `s`, but else branch uses `s` + let _ = if let Some(x) = Some(0) { + let s = s; + s.len() + x + } else { + s.len() + }; + + let s = String::new(); + // Lint, both branches immutably borrow `s`. + let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; + + let s = String::new(); + // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`. + let _ = if let Some(x) = Some(0) { + let s = s; + s.len() + x + } else { + 1 + }; + + let s = Some(String::new()); + // Don't lint, `Some` branch borrows `s`, but else branch consumes `s` + let _ = if let Some(x) = &s { + x.len() + } else { + let _s = s; + 10 + }; + + let mut s = Some(String::new()); + // Don't lint, `Some` branch mutably borrows `s`, but else branch also borrows `s` + let _ = if let Some(x) = &mut s { + x.push_str("test"); + x.len() + } else { + let _s = &s; + 10 + }; + + async fn _f1(x: u32) -> u32 { + x + } + + async fn _f2() { + // Don't lint. `await` can't be moved into a closure. + let _ = if let Some(x) = Some(0) { _f1(x).await } else { 0 }; + } } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/option_if_let_else.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:7:5 + --> $DIR/option_if_let_else.rs:8:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -11,19 +11,19 @@ = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:25:13 + --> $DIR/option_if_let_else.rs:26:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:26:13 + --> $DIR/option_if_let_else.rs:27:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:27:13 + --> $DIR/option_if_let_else.rs:28:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -43,13 +43,13 @@ | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:33:13 + --> $DIR/option_if_let_else.rs:34:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:34:13 + --> $DIR/option_if_let_else.rs:35:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -69,7 +69,7 @@ | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:40:13 + --> $DIR/option_if_let_else.rs:41:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -89,7 +89,7 @@ | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:49:5 + --> $DIR/option_if_let_else.rs:50:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -108,7 +108,7 @@ | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:62:13 + --> $DIR/option_if_let_else.rs:63:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -120,7 +120,7 @@ | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:71:13 + --> $DIR/option_if_let_else.rs:72:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -143,10 +143,58 @@ | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:100:13 + --> $DIR/option_if_let_else.rs:101:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` -error: aborting due to 11 previous errors +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:110:13 + | +LL | let _ = if let Some(x) = Some(0) { + | _____________^ +LL | | loop { +LL | | if x == 0 { +LL | | break x; +... | +LL | | 0 +LL | | }; + | |_____^ + | +help: try + | +LL ~ let _ = Some(0).map_or(0, |x| loop { +LL + if x == 0 { +LL + break x; +LL + } +LL ~ }); + | + +error: use Option::map_or_else instead of an if let/else + --> $DIR/option_if_let_else.rs:138:13 + | +LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:142:13 + | +LL | let _ = if let Some(x) = Some(0) { + | _____________^ +LL | | let s = s; +LL | | s.len() + x +LL | | } else { +LL | | 1 +LL | | }; + | |_____^ + | +help: try + | +LL ~ let _ = Some(0).map_or(1, |x| { +LL + let s = s; +LL + s.len() + x +LL ~ }); + | + +error: aborting due to 14 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/overflow_check_conditional.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/overflow_check_conditional.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/overflow_check_conditional.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/overflow_check_conditional.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,3 @@ -#![allow(clippy::many_single_char_names)] #![warn(clippy::overflow_check_conditional)] fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/overflow_check_conditional.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/overflow_check_conditional.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/overflow_check_conditional.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/overflow_check_conditional.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:8:8 + --> $DIR/overflow_check_conditional.rs:7:8 | LL | if a + b < a {} | ^^^^^^^^^ @@ -7,43 +7,43 @@ = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:9:8 + --> $DIR/overflow_check_conditional.rs:8:8 | LL | if a > a + b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:10:8 + --> $DIR/overflow_check_conditional.rs:9:8 | LL | if a + b < b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:11:8 + --> $DIR/overflow_check_conditional.rs:10:8 | LL | if b > a + b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:12:8 + --> $DIR/overflow_check_conditional.rs:11:8 | LL | if a - b > b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:13:8 + --> $DIR/overflow_check_conditional.rs:12:8 | LL | if b < a - b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:14:8 + --> $DIR/overflow_check_conditional.rs:13:8 | LL | if a - b > a {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:15:8 + --> $DIR/overflow_check_conditional.rs:14:8 | LL | if a < a - b {} | ^^^^^^^^^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -14,7 +14,7 @@ --> $DIR/panic_in_result_fn_assertions.rs:9:9 | LL | assert!(x == 5, "wrong argument"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -32,7 +32,7 @@ --> $DIR/panic_in_result_fn_assertions.rs:15:9 | LL | assert_eq!(x, 5); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -50,7 +50,7 @@ --> $DIR/panic_in_result_fn_assertions.rs:21:9 | LL | assert_ne!(x, 1); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/panic_in_result_fn.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/panic_in_result_fn.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/panic_in_result_fn.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/panic_in_result_fn.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -13,7 +13,7 @@ --> $DIR/panic_in_result_fn.rs:9:9 | LL | panic!("error"); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -30,7 +30,7 @@ --> $DIR/panic_in_result_fn.rs:14:9 | LL | unimplemented!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -47,7 +47,7 @@ --> $DIR/panic_in_result_fn.rs:19:9 | LL | unreachable!(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -64,7 +64,7 @@ --> $DIR/panic_in_result_fn.rs:24:9 | LL | todo!("Finish this"); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -81,7 +81,7 @@ --> $DIR/panic_in_result_fn.rs:55:5 | LL | panic!("error"); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -98,7 +98,7 @@ --> $DIR/panic_in_result_fn.rs:69:5 | LL | todo!("finish main method"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/panicking_macros.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/panicking_macros.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/panicking_macros.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/panicking_macros.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/panicking_macros.rs:8:5 | LL | panic!(); - | ^^^^^^^^^ + | ^^^^^^^^ | = note: `-D clippy::panic` implied by `-D warnings` @@ -10,19 +10,19 @@ --> $DIR/panicking_macros.rs:9:5 | LL | panic!("message"); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code --> $DIR/panicking_macros.rs:10:5 | LL | panic!("{} {}", "panic with", "multiple arguments"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:16:5 | LL | todo!(); - | ^^^^^^^^ + | ^^^^^^^ | = note: `-D clippy::todo` implied by `-D warnings` = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -31,7 +31,7 @@ --> $DIR/panicking_macros.rs:17:5 | LL | todo!("message"); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -39,7 +39,7 @@ --> $DIR/panicking_macros.rs:18:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -47,7 +47,7 @@ --> $DIR/panicking_macros.rs:24:5 | LL | unimplemented!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unimplemented` implied by `-D warnings` = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -56,7 +56,7 @@ --> $DIR/panicking_macros.rs:25:5 | LL | unimplemented!("message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -64,7 +64,7 @@ --> $DIR/panicking_macros.rs:26:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -72,7 +72,7 @@ --> $DIR/panicking_macros.rs:32:5 | LL | unreachable!(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = note: `-D clippy::unreachable` implied by `-D warnings` = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -81,7 +81,7 @@ --> $DIR/panicking_macros.rs:33:5 | LL | unreachable!("message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `$crate::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -89,7 +89,7 @@ --> $DIR/panicking_macros.rs:34:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -97,13 +97,13 @@ --> $DIR/panicking_macros.rs:40:5 | LL | panic!(); - | ^^^^^^^^^ + | ^^^^^^^^ error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:41:5 | LL | todo!(); - | ^^^^^^^^ + | ^^^^^^^ | = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -111,7 +111,7 @@ --> $DIR/panicking_macros.rs:42:5 | LL | unimplemented!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -119,7 +119,7 @@ --> $DIR/panicking_macros.rs:43:5 | LL | unreachable!(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -70,7 +70,7 @@ | ^^^^^^^ ... LL | matching_macro!(value); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings = note: this error originates in the macro `matching_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/proc_macro.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/proc_macro.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/proc_macro.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/proc_macro.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,10 +1,11 @@ -error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly +error: approximate value of `f{32, 64}::consts::PI` found --> $DIR/proc_macro.rs:10:14 | LL | let _x = 3.14; | ^^^^ | = note: `#[deny(clippy::approx_constant)]` on by default + = help: consider using the constant directly error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rc_mutex.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rc_mutex.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rc_mutex.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rc_mutex.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,13 +1,17 @@ #![warn(clippy::rc_mutex)] -#![allow(clippy::blacklisted_name)] +#![allow(unused, clippy::blacklisted_name)] use std::rc::Rc; use std::sync::Mutex; -pub struct MyStruct { +pub struct MyStructWithPrivItem { foo: Rc>, } +pub struct MyStructWithPubItem { + pub foo: Rc>, +} + pub struct SubT { foo: T, } @@ -17,18 +21,16 @@ Two, } -pub fn test1(foo: Rc>) {} - -pub fn test2(foo: Rc>) {} +// All of these test should be trigger the lint because they are not +// part of the public api +fn test1(foo: Rc>) {} +fn test2(foo: Rc>) {} +fn test3(foo: Rc>>) {} + +// All of these test should be allowed because they are part of the +// public api and `avoid_breaking_exported_api` is `false` by default. +pub fn pub_test1(foo: Rc>) {} +pub fn pub_test2(foo: Rc>) {} +pub fn pub_test3(foo: Rc>>) {} -pub fn test3(foo: Rc>>) {} - -fn main() { - test1(Rc::new(Mutex::new(1))); - test2(Rc::new(Mutex::new(MyEnum::One))); - test3(Rc::new(Mutex::new(SubT { foo: 1 }))); - - let _my_struct = MyStruct { - foo: Rc::new(Mutex::new(1)), - }; -} +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rc_mutex.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rc_mutex.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rc_mutex.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rc_mutex.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,28 +1,35 @@ -error: found `Rc>`. Consider using `Rc>` or `Arc>` instead +error: usage of `Rc>` --> $DIR/rc_mutex.rs:8:10 | LL | foo: Rc>, | ^^^^^^^^^^^^^^ | = note: `-D clippy::rc-mutex` implied by `-D warnings` + = help: consider using `Rc>` or `Arc>` instead -error: found `Rc>`. Consider using `Rc>` or `Arc>` instead - --> $DIR/rc_mutex.rs:20:22 +error: usage of `Rc>` + --> $DIR/rc_mutex.rs:26:18 | -LL | pub fn test1(foo: Rc>) {} - | ^^^^^^^^^^^^ +LL | fn test1(foo: Rc>) {} + | ^^^^^^^^^^^^ + | + = help: consider using `Rc>` or `Arc>` instead -error: found `Rc>`. Consider using `Rc>` or `Arc>` instead - --> $DIR/rc_mutex.rs:22:19 +error: usage of `Rc>` + --> $DIR/rc_mutex.rs:27:15 + | +LL | fn test2(foo: Rc>) {} + | ^^^^^^^^^^^^^^^^^ | -LL | pub fn test2(foo: Rc>) {} - | ^^^^^^^^^^^^^^^^^ + = help: consider using `Rc>` or `Arc>` instead -error: found `Rc>`. Consider using `Rc>` or `Arc>` instead - --> $DIR/rc_mutex.rs:24:19 +error: usage of `Rc>` + --> $DIR/rc_mutex.rs:28:15 + | +LL | fn test3(foo: Rc>>) {} + | ^^^^^^^^^^^^^^^^^^^^^^ | -LL | pub fn test3(foo: Rc>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^ + = help: consider using `Rc>` or `Arc>` instead error: aborting due to 4 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_allocation.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_allocation.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_allocation.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_allocation.rs 2021-11-29 19:27:12.000000000 +0000 @@ -77,4 +77,24 @@ } } +// https://github.com/rust-lang/rust-clippy/issues/7487 +mod box_dyn { + use std::boxed::Box; + use std::rc::Rc; + use std::sync::Arc; + + pub trait T {} + + struct S { + a: Box>, + b: Rc>, + c: Arc>, + } + + pub fn test_box(_: Box>) {} + pub fn test_rc(_: Rc>) {} + pub fn test_arc(_: Arc>) {} + pub fn test_rc_box(_: Rc>>) {} +} + fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_allocation.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_allocation.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_allocation.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_allocation.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -134,5 +134,14 @@ = note: `Rc>` is already on the heap, `Arc>>` makes an extra allocation = help: consider using just `Arc>` or `Rc>` -error: aborting due to 15 previous errors +error: usage of `Rc>>` + --> $DIR/redundant_allocation.rs:97:27 + | +LL | pub fn test_rc_box(_: Rc>>) {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `Box>` is already on the heap, `Rc>>` makes an extra allocation + = help: consider using just `Rc>` or `Box>` + +error: aborting due to 16 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ // Issue #5746 #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] use std::task::Poll::{Pending, Ready}; fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ // Issue #5746 #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] use std::task::Poll::{Pending, Ready}; fn main() { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:13:12 + --> $DIR/redundant_pattern_matching_option.rs:14:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` @@ -7,43 +7,43 @@ = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:15:12 + --> $DIR/redundant_pattern_matching_option.rs:16:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:17:12 + --> $DIR/redundant_pattern_matching_option.rs:18:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:23:15 + --> $DIR/redundant_pattern_matching_option.rs:24:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:25:15 + --> $DIR/redundant_pattern_matching_option.rs:26:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try this: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:27:15 + --> $DIR/redundant_pattern_matching_option.rs:28:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:30:15 + --> $DIR/redundant_pattern_matching_option.rs:31:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:38:5 + --> $DIR/redundant_pattern_matching_option.rs:39:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -52,7 +52,7 @@ | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:43:5 + --> $DIR/redundant_pattern_matching_option.rs:44:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -61,7 +61,7 @@ | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:48:13 + --> $DIR/redundant_pattern_matching_option.rs:49:13 | LL | let _ = match None::<()> { | _____________^ @@ -71,49 +71,49 @@ | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:54:20 + --> $DIR/redundant_pattern_matching_option.rs:55:20 | LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:58:20 + --> $DIR/redundant_pattern_matching_option.rs:59:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:60:19 + --> $DIR/redundant_pattern_matching_option.rs:61:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:79:12 + --> $DIR/redundant_pattern_matching_option.rs:80:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:81:12 + --> $DIR/redundant_pattern_matching_option.rs:82:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:83:15 + --> $DIR/redundant_pattern_matching_option.rs:84:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:85:15 + --> $DIR/redundant_pattern_matching_option.rs:86:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:87:5 + --> $DIR/redundant_pattern_matching_option.rs:88:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -122,7 +122,7 @@ | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:92:5 + --> $DIR/redundant_pattern_matching_option.rs:93:5 | LL | / match None::<()> { LL | | Some(_) => false, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:15:12 + --> $DIR/redundant_pattern_matching_poll.rs:16:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` @@ -7,37 +7,37 @@ = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:17:12 + --> $DIR/redundant_pattern_matching_poll.rs:18:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:19:12 + --> $DIR/redundant_pattern_matching_poll.rs:20:12 | LL | if let Ready(_) = Ready(42) { | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:25:15 + --> $DIR/redundant_pattern_matching_poll.rs:26:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:27:15 + --> $DIR/redundant_pattern_matching_poll.rs:28:15 | LL | while let Pending = Ready(42) {} | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:29:15 + --> $DIR/redundant_pattern_matching_poll.rs:30:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:35:5 + --> $DIR/redundant_pattern_matching_poll.rs:36:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -46,7 +46,7 @@ | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:40:5 + --> $DIR/redundant_pattern_matching_poll.rs:41:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, @@ -55,7 +55,7 @@ | |_____^ help: try this: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:45:13 + --> $DIR/redundant_pattern_matching_poll.rs:46:13 | LL | let _ = match Pending::<()> { | _____________^ @@ -65,49 +65,49 @@ | |_____^ help: try this: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:51:20 + --> $DIR/redundant_pattern_matching_poll.rs:52:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; | -------^^^^^^^^------- help: try this: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:55:20 + --> $DIR/redundant_pattern_matching_poll.rs:56:20 | LL | let _ = if let Ready(_) = gen_poll() { | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:57:19 + --> $DIR/redundant_pattern_matching_poll.rs:58:19 | LL | } else if let Pending = gen_poll() { | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:73:12 + --> $DIR/redundant_pattern_matching_poll.rs:74:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:75:12 + --> $DIR/redundant_pattern_matching_poll.rs:76:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:77:15 + --> $DIR/redundant_pattern_matching_poll.rs:78:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:79:15 + --> $DIR/redundant_pattern_matching_poll.rs:80:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:81:5 + --> $DIR/redundant_pattern_matching_poll.rs:82:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -116,7 +116,7 @@ | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:86:5 + --> $DIR/redundant_pattern_matching_poll.rs:87:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -8,6 +8,7 @@ #![allow(clippy::redundant_static_lifetimes)] // warn for the old lint name here, to test if the renaming worked #![warn(clippy::cognitive_complexity)] +#![warn(enum_intrinsics_non_enums)] #[warn(clippy::module_name_repetitions)] fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.rs 2021-11-29 19:27:12.000000000 +0000 @@ -8,6 +8,7 @@ #![allow(clippy::redundant_static_lifetimes)] // warn for the old lint name here, to test if the renaming worked #![warn(clippy::cyclomatic_complexity)] +#![warn(clippy::mem_discriminant_non_enum)] #[warn(clippy::stutter)] fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/rename.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -6,23 +6,29 @@ | = note: `-D renamed-and-removed-lints` implied by `-D warnings` +error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` + --> $DIR/rename.rs:11:9 + | +LL | #![warn(clippy::mem_discriminant_non_enum)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` + error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:12:8 + --> $DIR/rename.rs:13:8 | LL | #[warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:15:8 + --> $DIR/rename.rs:16:8 | LL | #[warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:18:8 + --> $DIR/rename.rs:19:8 | LL | #[warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/repeat_once.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/repeat_once.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/repeat_once.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/repeat_once.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::repeat_once)] -#[allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] +#[allow(unused, clippy::redundant_clone)] fn main() { const N: usize = 1; let s = "str"; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/repeat_once.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/repeat_once.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/repeat_once.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/repeat_once.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::repeat_once)] -#[allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] +#[allow(unused, clippy::redundant_clone)] fn main() { const N: usize = 1; let s = "str"; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/same_name_method.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/same_name_method.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/same_name_method.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/same_name_method.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,111 @@ +#![warn(clippy::same_name_method)] +#![allow(dead_code, non_camel_case_types)] + +trait T1 { + fn foo() {} +} + +trait T2 { + fn foo() {} +} + +mod should_lint { + + mod test_basic_case { + use crate::T1; + + struct S; + + impl S { + fn foo() {} + } + + impl T1 for S { + fn foo() {} + } + } + + mod test_derive { + + #[derive(Clone)] + struct S; + + impl S { + fn clone() {} + } + } + + mod with_generic { + use crate::T1; + + struct S(U); + + impl S { + fn foo() {} + } + + impl T1 for S { + fn foo() {} + } + } + + mod default_method { + use crate::T1; + + struct S; + + impl S { + fn foo() {} + } + + impl T1 for S {} + } + + mod mulitply_conflicit_trait { + use crate::{T1, T2}; + + struct S; + + impl S { + fn foo() {} + } + + impl T1 for S {} + + impl T2 for S {} + } +} + +mod should_not_lint { + + mod not_lint_two_trait_method { + use crate::{T1, T2}; + + struct S; + + impl T1 for S { + fn foo() {} + } + + impl T2 for S { + fn foo() {} + } + } + + mod only_lint_on_method { + trait T3 { + type foo; + } + + struct S; + + impl S { + fn foo() {} + } + impl T3 for S { + type foo = usize; + } + } +} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/same_name_method.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/same_name_method.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/same_name_method.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/same_name_method.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,64 @@ +error: method's name is same to an existing method in a trait + --> $DIR/same_name_method.rs:20:13 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | + = note: `-D clippy::same-name-method` implied by `-D warnings` +note: existing `foo` defined here + --> $DIR/same_name_method.rs:24:13 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: method's name is same to an existing method in a trait + --> $DIR/same_name_method.rs:44:13 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | +note: existing `foo` defined here + --> $DIR/same_name_method.rs:48:13 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: method's name is same to an existing method in a trait + --> $DIR/same_name_method.rs:58:13 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | +note: existing `foo` defined here + --> $DIR/same_name_method.rs:61:9 + | +LL | impl T1 for S {} + | ^^^^^^^^^^^^^^^^ + +error: method's name is same to an existing method in a trait + --> $DIR/same_name_method.rs:70:13 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | +note: existing `foo` defined here + --> $DIR/same_name_method.rs:73:9 + | +LL | impl T1 for S {} + | ^^^^^^^^^^^^^^^^ + +error: method's name is same to an existing method in a trait + --> $DIR/same_name_method.rs:34:13 + | +LL | fn clone() {} + | ^^^^^^^^^^^^^ + | +note: existing `clone` defined here + --> $DIR/same_name_method.rs:30:18 + | +LL | #[derive(Clone)] + | ^^^^^ + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,5 @@ #![warn(clippy::semicolon_if_nothing_returned)] +#![allow(clippy::redundant_closure)] #![feature(label_break_value)] fn get_unit() {} @@ -30,8 +31,8 @@ use std::ptr; let mut s = MaybeUninit::::uninit(); - let _d = || unsafe { - ptr::drop_in_place(s.as_mut_ptr()) + let _d = || unsafe { + ptr::drop_in_place(s.as_mut_ptr()) }; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:8:5 + --> $DIR/semicolon_if_nothing_returned.rs:9:5 | LL | println!("Hello") | ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");` @@ -7,27 +7,27 @@ = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:12:5 + --> $DIR/semicolon_if_nothing_returned.rs:13:5 | LL | get_unit() | ^^^^^^^^^^ help: add a `;` here: `get_unit();` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:17:5 + --> $DIR/semicolon_if_nothing_returned.rs:18:5 | LL | y = x + 1 | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:23:9 + --> $DIR/semicolon_if_nothing_returned.rs:24:9 | LL | hello() | ^^^^^^^ help: add a `;` here: `hello();` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:34:9 + --> $DIR/semicolon_if_nothing_returned.rs:35:9 | -LL | ptr::drop_in_place(s.as_mut_ptr()) +LL | ptr::drop_in_place(s.as_mut_ptr()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());` error: aborting due to 5 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/shadow.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/shadow.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/shadow.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/shadow.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,54 +1,77 @@ -#![warn( - clippy::all, - clippy::pedantic, - clippy::shadow_same, - clippy::shadow_reuse, - clippy::shadow_unrelated -)] -#![allow( - unused_parens, - unused_variables, - clippy::manual_unwrap_or, - clippy::missing_docs_in_private_items, - clippy::single_match -)] - -fn id(x: T) -> T { - x -} - -#[must_use] -fn first(x: (isize, isize)) -> isize { - x.0 -} +#![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)] -fn main() { - let mut x = 1; +fn shadow_same() { + let x = 1; + let x = x; + let mut x = &x; let x = &mut x; - let x = { x }; - let x = (&*x); - let x = { *x + 1 }; - let x = id(x); - let x = (1, x); - let x = first(x); - let y = 1; - let x = y; + let x = *x; +} - let x; - x = 42; +fn shadow_reuse() -> Option<()> { + let x = ([[0]], ()); + let x = x.0; + let x = x[0]; + let [x] = x; + let x = Some(x); + let x = foo(x); + let x = || x; + let x = Some(1).map(|_| x)?; + None +} - let o = Some(1_u8); +fn shadow_unrelated() { + let x = 1; + let x = 2; +} - if let Some(p) = o { - assert_eq!(1, p); +fn syntax() { + fn f(x: u32) { + let x = 1; + } + let x = 1; + match Some(1) { + Some(1) => {}, + Some(x) => { + let x = 1; + }, + _ => {}, } - match o { - Some(p) => p, // no error, because the p above is in its own scope - None => 0, + if let Some(x) = Some(1) {} + while let Some(x) = Some(1) {} + let _ = |[x]: [u32; 1]| { + let x = 1; }; +} - match (x, o) { - (1, Some(a)) | (a, Some(1)) => (), // no error though `a` appears twice - _ => (), +fn negative() { + match Some(1) { + Some(x) if x == 1 => {}, + Some(x) => {}, + None => {}, } + match [None, Some(1)] { + [Some(x), None] | [None, Some(x)] => {}, + _ => {}, + } + if let Some(x) = Some(1) { + let y = 1; + } else { + let x = 1; + let y = 1; + } + let x = 1; + #[allow(clippy::shadow_unrelated)] + let x = 1; +} + +fn foo(_: T) {} + +fn question_mark() -> Option<()> { + let val = 1; + // `?` expands with a `val` binding + None?; + None } + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/shadow.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/shadow.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/shadow.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/shadow.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,138 +1,233 @@ -error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:27:5 +error: `x` is shadowed by itself in `x` + --> $DIR/shadow.rs:5:9 | -LL | let x = &mut x; - | ^^^^^^^^^^^^^^^ +LL | let x = x; + | ^ | = note: `-D clippy::shadow-same` implied by `-D warnings` note: previous binding is here - --> $DIR/shadow.rs:26:13 + --> $DIR/shadow.rs:4:9 | -LL | let mut x = 1; - | ^ +LL | let x = 1; + | ^ -error: `x` is shadowed by itself in `{ x }` - --> $DIR/shadow.rs:28:5 +error: `mut x` is shadowed by itself in `&x` + --> $DIR/shadow.rs:6:13 | -LL | let x = { x }; - | ^^^^^^^^^^^^^^ +LL | let mut x = &x; + | ^ | note: previous binding is here - --> $DIR/shadow.rs:27:9 + --> $DIR/shadow.rs:5:9 + | +LL | let x = x; + | ^ + +error: `x` is shadowed by itself in `&mut x` + --> $DIR/shadow.rs:7:9 | LL | let x = &mut x; | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:6:9 + | +LL | let mut x = &x; + | ^^^^^ -error: `x` is shadowed by itself in `(&*x)` - --> $DIR/shadow.rs:29:5 +error: `x` is shadowed by itself in `*x` + --> $DIR/shadow.rs:8:9 | -LL | let x = (&*x); - | ^^^^^^^^^^^^^^ +LL | let x = *x; + | ^ | note: previous binding is here - --> $DIR/shadow.rs:28:9 + --> $DIR/shadow.rs:7:9 | -LL | let x = { x }; +LL | let x = &mut x; | ^ -error: `x` is shadowed by `{ *x + 1 }` which reuses the original value - --> $DIR/shadow.rs:30:9 +error: `x` is shadowed by `x.0` which reuses the original value + --> $DIR/shadow.rs:13:9 | -LL | let x = { *x + 1 }; +LL | let x = x.0; | ^ | = note: `-D clippy::shadow-reuse` implied by `-D warnings` -note: initialization happens here - --> $DIR/shadow.rs:30:13 - | -LL | let x = { *x + 1 }; - | ^^^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:29:9 + --> $DIR/shadow.rs:12:9 | -LL | let x = (&*x); +LL | let x = ([[0]], ()); | ^ -error: `x` is shadowed by `id(x)` which reuses the original value - --> $DIR/shadow.rs:31:9 +error: `x` is shadowed by `x[0]` which reuses the original value + --> $DIR/shadow.rs:14:9 | -LL | let x = id(x); +LL | let x = x[0]; | ^ | -note: initialization happens here - --> $DIR/shadow.rs:31:13 +note: previous binding is here + --> $DIR/shadow.rs:13:9 + | +LL | let x = x.0; + | ^ + +error: `x` is shadowed by `x` which reuses the original value + --> $DIR/shadow.rs:15:10 + | +LL | let [x] = x; + | ^ | -LL | let x = id(x); - | ^^^^^ note: previous binding is here - --> $DIR/shadow.rs:30:9 + --> $DIR/shadow.rs:14:9 | -LL | let x = { *x + 1 }; +LL | let x = x[0]; | ^ -error: `x` is shadowed by `(1, x)` which reuses the original value - --> $DIR/shadow.rs:32:9 +error: `x` is shadowed by `Some(x)` which reuses the original value + --> $DIR/shadow.rs:16:9 | -LL | let x = (1, x); +LL | let x = Some(x); | ^ | -note: initialization happens here - --> $DIR/shadow.rs:32:13 +note: previous binding is here + --> $DIR/shadow.rs:15:10 + | +LL | let [x] = x; + | ^ + +error: `x` is shadowed by `foo(x)` which reuses the original value + --> $DIR/shadow.rs:17:9 + | +LL | let x = foo(x); + | ^ | -LL | let x = (1, x); - | ^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:16:9 | -LL | let x = id(x); +LL | let x = Some(x); | ^ -error: `x` is shadowed by `first(x)` which reuses the original value - --> $DIR/shadow.rs:33:9 +error: `x` is shadowed by `|| x` which reuses the original value + --> $DIR/shadow.rs:18:9 | -LL | let x = first(x); +LL | let x = || x; | ^ | -note: initialization happens here - --> $DIR/shadow.rs:33:13 +note: previous binding is here + --> $DIR/shadow.rs:17:9 + | +LL | let x = foo(x); + | ^ + +error: `x` is shadowed by `Some(1).map(|_| x)?` which reuses the original value + --> $DIR/shadow.rs:19:9 + | +LL | let x = Some(1).map(|_| x)?; + | ^ | -LL | let x = first(x); - | ^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:18:9 | -LL | let x = (1, x); +LL | let x = || x; | ^ -error: `x` is being shadowed - --> $DIR/shadow.rs:35:9 +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:25:9 | -LL | let x = y; +LL | let x = 2; | ^ | = note: `-D clippy::shadow-unrelated` implied by `-D warnings` -note: initialization happens here - --> $DIR/shadow.rs:35:13 +note: previous binding is here + --> $DIR/shadow.rs:24:9 | -LL | let x = y; +LL | let x = 1; + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:30:13 + | +LL | let x = 1; | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:29:10 + | +LL | fn f(x: u32) { + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:35:14 + | +LL | Some(x) => { + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:32:9 + | +LL | let x = 1; + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:36:17 + | +LL | let x = 1; + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:35:14 + | +LL | Some(x) => { + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:40:17 + | +LL | if let Some(x) = Some(1) {} + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:32:9 + | +LL | let x = 1; + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:41:20 + | +LL | while let Some(x) = Some(1) {} + | ^ + | note: previous binding is here - --> $DIR/shadow.rs:33:9 + --> $DIR/shadow.rs:32:9 | -LL | let x = first(x); +LL | let x = 1; | ^ -error: `x` shadows a previous declaration - --> $DIR/shadow.rs:37:5 +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:42:15 | -LL | let x; - | ^^^^^^ +LL | let _ = |[x]: [u32; 1]| { + | ^ | note: previous binding is here - --> $DIR/shadow.rs:35:9 + --> $DIR/shadow.rs:32:9 | -LL | let x = y; +LL | let x = 1; | ^ -error: aborting due to 9 previous errors +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:43:13 + | +LL | let x = 1; + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:42:15 + | +LL | let _ = |[x]: [u32; 1]| { + | ^ + +error: aborting due to 19 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_else_formatting.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_else_formatting.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_else_formatting.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_else_formatting.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,10 @@ +// aux-build:proc_macro_suspicious_else_formatting.rs + #![warn(clippy::suspicious_else_formatting)] +extern crate proc_macro_suspicious_else_formatting; +use proc_macro_suspicious_else_formatting::DeriveBadSpan; + fn foo() -> bool { true } @@ -103,3 +108,7 @@ { } } + +// #7650 - Don't lint. Proc-macro using bad spans for `if` expressions. +#[derive(DeriveBadSpan)] +struct _Foo(u32, u32); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this looks like an `else {..}` but the `else` is missing - --> $DIR/suspicious_else_formatting.rs:11:6 + --> $DIR/suspicious_else_formatting.rs:16:6 | LL | } { | ^ @@ -8,7 +8,7 @@ = note: to remove this lint, add the missing `else` or add a new line before the next block error: this looks like an `else if` but the `else` is missing - --> $DIR/suspicious_else_formatting.rs:15:6 + --> $DIR/suspicious_else_formatting.rs:20:6 | LL | } if foo() { | ^ @@ -16,7 +16,7 @@ = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> $DIR/suspicious_else_formatting.rs:22:10 + --> $DIR/suspicious_else_formatting.rs:27:10 | LL | } if foo() { | ^ @@ -24,7 +24,7 @@ = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> $DIR/suspicious_else_formatting.rs:30:10 + --> $DIR/suspicious_else_formatting.rs:35:10 | LL | } if foo() { | ^ @@ -32,7 +32,7 @@ = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this is an `else {..}` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:39:6 + --> $DIR/suspicious_else_formatting.rs:44:6 | LL | } else | ______^ @@ -42,7 +42,7 @@ = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` error: this is an `else if` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:51:6 + --> $DIR/suspicious_else_formatting.rs:56:6 | LL | } else | ______^ @@ -52,7 +52,7 @@ = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this is an `else if` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:56:6 + --> $DIR/suspicious_else_formatting.rs:61:6 | LL | } | ______^ @@ -63,7 +63,7 @@ = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this is an `else {..}` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:83:6 + --> $DIR/suspicious_else_formatting.rs:88:6 | LL | } | ______^ @@ -75,7 +75,7 @@ = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` error: this is an `else {..}` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:91:6 + --> $DIR/suspicious_else_formatting.rs:96:6 | LL | } | ______^ diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_map.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_map.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_map.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_map.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -5,7 +5,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::suspicious-map` implied by `-D warnings` - = help: make sure you did not confuse `map` with `filter` or `for_each` + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` error: this call to `map()` won't have an effect on the call to `count()` --> $DIR/suspicious_map.rs:7:13 @@ -13,7 +13,7 @@ LL | let _ = (0..3).map(f).count(); | ^^^^^^^^^^^^^^^^^^^^^ | - = help: make sure you did not confuse `map` with `filter` or `for_each` + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` error: aborting due to 2 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -7,12 +7,6 @@ = note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:14:9 - | -LL | self.x == other.y && self.y == other.y && self.z == other.z - | ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x` - -error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:27:20 | LL | s1.a < s2.a && s1.a < s2.b @@ -162,5 +156,5 @@ LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) | ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b` -error: aborting due to 27 previous errors +error: aborting due to 26 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -13,7 +13,7 @@ | ^^^^^^ ... LL | gen_function!(); - | ---------------- in this macro invocation + | --------------- in this macro invocation | = note: this error originates in the macro `gen_function` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -37,7 +37,7 @@ | ----^^^^^^------ help: try: `let _y = &42;` ... LL | gen_binding!(); - | --------------- in this macro invocation + | -------------- in this macro invocation | = note: this error originates in the macro `gen_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,11 +2,7 @@ // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] -#![allow( - clippy::many_single_char_names, - clippy::blacklisted_name, - clippy::redundant_field_names -)] +#![allow(clippy::blacklisted_name, clippy::redundant_field_names)] #[derive(Copy, Clone)] struct Foo(u32); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:11 + --> $DIR/trivially_copy_pass_by_ref.rs:47:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` @@ -11,97 +11,97 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:20 + --> $DIR/trivially_copy_pass_by_ref.rs:47:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:29 + --> $DIR/trivially_copy_pass_by_ref.rs:47:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:12 + --> $DIR/trivially_copy_pass_by_ref.rs:54:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:22 + --> $DIR/trivially_copy_pass_by_ref.rs:54:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:31 + --> $DIR/trivially_copy_pass_by_ref.rs:54:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:40 + --> $DIR/trivially_copy_pass_by_ref.rs:54:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:16 + --> $DIR/trivially_copy_pass_by_ref.rs:56:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:25 + --> $DIR/trivially_copy_pass_by_ref.rs:56:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:34 + --> $DIR/trivially_copy_pass_by_ref.rs:56:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:62:35 + --> $DIR/trivially_copy_pass_by_ref.rs:58:35 | LL | fn bad_issue7518(self, other: &Self) {} | ^^^^^ help: consider passing by value instead: `Self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:74:16 + --> $DIR/trivially_copy_pass_by_ref.rs:70:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:74:25 + --> $DIR/trivially_copy_pass_by_ref.rs:70:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:74:34 + --> $DIR/trivially_copy_pass_by_ref.rs:70:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:78:34 + --> $DIR/trivially_copy_pass_by_ref.rs:74:34 | LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:110:21 + --> $DIR/trivially_copy_pass_by_ref.rs:106:21 | LL | fn foo_never(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:115:15 + --> $DIR/trivially_copy_pass_by_ref.rs:111:15 | LL | fn foo(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/try_err.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/try_err.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/try_err.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/try_err.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -35,7 +35,7 @@ | ^^^^^^^ help: try this: `return Err(1)` ... LL | try_validation!(Ok::<_, i32>(5)); - | --------------------------------- in this macro invocation + | -------------------------------- in this macro invocation | = note: this error originates in the macro `try_validation` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -46,7 +46,7 @@ | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` ... LL | try_validation_in_macro!(Ok::<_, i32>(5)); - | ------------------------------------------ in this macro invocation + | ----------------------------------------- in this macro invocation | = note: this error originates in the macro `try_validation_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/unit_cmp.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/unit_cmp.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/unit_cmp.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/unit_cmp.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -32,7 +32,7 @@ ... | LL | | } LL | | ); - | |______^ + | |_____^ | = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -46,7 +46,7 @@ ... | LL | | } LL | | ); - | |______^ + | |_____^ | = note: this error originates in the macro `$crate::assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -60,7 +60,7 @@ ... | LL | | } LL | | ); - | |______^ + | |_____^ | = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -74,7 +74,7 @@ ... | LL | | } LL | | ); - | |______^ + | |_____^ | = note: this error originates in the macro `$crate::assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/unnecessary_operation.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/unnecessary_operation.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/unnecessary_operation.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/unnecessary_operation.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -62,10 +62,10 @@ get_number(); 5;get_number(); 42;get_number(); - [42, 55];get_usize(); + assert!([42, 55].len() > get_usize()); 42;get_number(); get_number(); - [42; 55];get_usize(); + assert!([42; 55].len() > get_usize()); get_number(); String::from("blah"); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/unnecessary_operation.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/unnecessary_operation.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/unnecessary_operation.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/unnecessary_operation.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,128 +1,128 @@ -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:51:5 | LL | Tuple(get_number()); - | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | = note: `-D clippy::unnecessary-operation` implied by `-D warnings` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:52:5 | LL | Struct { field: get_number() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:53:5 | LL | Struct { ..get_struct() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_struct();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:54:5 | LL | Enum::Tuple(get_number()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:55:5 | LL | Enum::Struct { field: get_number() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:56:5 | LL | 5 + get_number(); - | ^^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();` + | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:57:5 | LL | *&get_number(); - | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:58:5 | LL | &get_number(); - | ^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:59:5 | LL | (5, 6, get_number()); - | ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `5;6;get_number();` + | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:60:5 | LL | box get_number(); - | ^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:61:5 | LL | get_number()..; - | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:62:5 | LL | ..get_number(); - | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:63:5 | LL | 5..get_number(); - | ^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();` + | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:64:5 | LL | [42, get_number()]; - | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();` + | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:65:5 | LL | [42, 55][get_usize()]; - | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42, 55];get_usize();` + | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:66:5 | LL | (42, get_number()).1; - | ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();` + | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:67:5 | LL | [get_number(); 55]; - | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:68:5 | LL | [42; 55][get_usize()]; - | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42; 55];get_usize();` + | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:69:5 | LL | / { LL | | get_number() LL | | }; - | |______^ help: replace it with: `get_number();` + | |______^ help: statement can be reduced to: `get_number();` -error: statement can be reduced +error: unnecessary operation --> $DIR/unnecessary_operation.rs:72:5 | LL | / FooString { LL | | s: String::from("blah"), LL | | }; - | |______^ help: replace it with: `String::from("blah");` + | |______^ help: statement can be reduced to: `String::from("blah");` error: aborting due to 20 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.fixed rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.fixed --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.fixed 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.fixed 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,13 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] +#![allow( + clippy::never_loop, + unreachable_code, + unused_mut, + dead_code, + clippy::equatable_if_let +)] fn base() { let mut iter = 1..20; @@ -188,7 +194,7 @@ // Used in outer loop, needs &mut let mut it = 1..40; while let Some(n) = it.next() { - for m in &mut it { + for m in it.by_ref() { if m % 10 == 0 { break; } @@ -219,7 +225,7 @@ // Used after the loop, needs &mut. let mut it = 1..40; - for m in &mut it { + for m in it.by_ref() { if m % 10 == 0 { break; } @@ -236,7 +242,7 @@ let mut it = 1..40; let mut opt = Some(0); while let Some(n) = opt.take().or_else(|| it.next()) { - for m in &mut it { + for m in it.by_ref() { if n % 10 == 0 { break; } @@ -251,7 +257,7 @@ impl> S { fn f(&mut self) -> Option { // Used as a field. - for i in &mut self.0 { + for i in self.0.by_ref() { if !(3..=7).contains(&i) { return Some(i); } @@ -283,7 +289,7 @@ } } // This one is fine, a different field is borrowed - for i in &mut self.0.0.0 { + for i in self.0.0.0.by_ref() { if i == 1 { return self.0.1.take(); } else { @@ -312,7 +318,7 @@ // Needs &mut, field of the iterator is accessed after the loop let mut it = S2(1..40, 0); - for n in &mut it { + for n in it.by_ref() { if n == 0 { break; } @@ -324,7 +330,7 @@ let mut it = 0..10; let mut x = || { // Needs &mut, the closure can be called multiple times - for x in &mut it { + for x in it.by_ref() { if x % 2 == 0 { break; } @@ -338,7 +344,7 @@ let mut it = 0..10; let it = &mut it; // Needs to reborrow `it` as the binding isn't mutable - for x in &mut *it { + for x in it.by_ref() { if x % 2 == 0 { break; } @@ -349,7 +355,7 @@ let mut it = 0..10; let it = S(&mut it); // Needs to reborrow `it.0` as the binding isn't mutable - for x in &mut *it.0 { + for x in it.0.by_ref() { if x % 2 == 0 { break; } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,13 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] +#![allow( + clippy::never_loop, + unreachable_code, + unused_mut, + dead_code, + clippy::equatable_if_let +)] fn base() { let mut iter = 1..20; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/while_let_on_iterator.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:8:5 + --> $DIR/while_let_on_iterator.rs:14:5 | LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` @@ -7,85 +7,85 @@ = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:13:5 + --> $DIR/while_let_on_iterator.rs:19:5 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:18:5 + --> $DIR/while_let_on_iterator.rs:24:5 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:94:9 + --> $DIR/while_let_on_iterator.rs:100:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:101:9 + --> $DIR/while_let_on_iterator.rs:107:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:114:9 + --> $DIR/while_let_on_iterator.rs:120:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:134:9 + --> $DIR/while_let_on_iterator.rs:140:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:191:9 + --> $DIR/while_let_on_iterator.rs:197:9 | LL | while let Some(m) = it.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:202:5 + --> $DIR/while_let_on_iterator.rs:208:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:204:9 + --> $DIR/while_let_on_iterator.rs:210:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:213:9 + --> $DIR/while_let_on_iterator.rs:219:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:222:9 + --> $DIR/while_let_on_iterator.rs:228:9 | LL | while let Some(m) = it.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:239:9 + --> $DIR/while_let_on_iterator.rs:245:9 | LL | while let Some(m) = it.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:254:13 + --> $DIR/while_let_on_iterator.rs:260:13 | LL | while let Some(i) = self.0.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` error: manual `!RangeInclusive::contains` implementation - --> $DIR/while_let_on_iterator.rs:255:20 + --> $DIR/while_let_on_iterator.rs:261:20 | LL | if i < 3 || i > 7 { | ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)` @@ -93,37 +93,37 @@ = note: `-D clippy::manual-range-contains` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:286:13 + --> $DIR/while_let_on_iterator.rs:292:13 | LL | while let Some(i) = self.0.0.0.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0.0.0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:315:5 + --> $DIR/while_let_on_iterator.rs:321:5 | LL | while let Some(n) = it.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in &mut it` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:327:9 + --> $DIR/while_let_on_iterator.rs:333:9 | LL | while let Some(x) = it.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in &mut it` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:341:5 + --> $DIR/while_let_on_iterator.rs:347:5 | LL | while let Some(x) = it.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in &mut *it` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:352:5 + --> $DIR/while_let_on_iterator.rs:358:5 | LL | while let Some(x) = it.0.next() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in &mut *it.0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:371:5 + --> $DIR/while_let_on_iterator.rs:377:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/wrong_self_convention2.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/wrong_self_convention2.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui/wrong_self_convention2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui/wrong_self_convention2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -68,3 +68,40 @@ fn as_byte_slice(slice: &[Self]) -> &[u8]; } } + +mod issue3414 { + struct CellLikeThing(T); + + impl CellLikeThing { + // don't trigger + fn into_inner(this: Self) -> T { + this.0 + } + } + + impl std::ops::Deref for CellLikeThing { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } +} + +// don't trigger +mod issue4546 { + use std::pin::Pin; + + struct S; + impl S { + pub fn as_mut(self: Pin<&mut Self>) {} + + pub fn as_other_thingy(self: Pin<&Self>) {} + + pub fn is_other_thingy(self: Pin<&Self>) {} + + pub fn to_mut(self: Pin<&mut Self>) {} + + pub fn to_other_thingy(self: Pin<&Self>) {} + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,21 @@ + +# Content that triggers the lint goes here + +[package] +name = "feature_name" +version = "0.1.0" +publish = false + +[workspace] + +[features] +use-qwq = [] +use_qwq = [] +with-owo = [] +with_owo = [] +qvq-support = [] +qvq_support = [] +no-qaq = [] +no_qaq = [] +not-orz = [] +not_orz = [] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,7 @@ +// compile-flags: --crate-name=feature_name +#![warn(clippy::redundant_feature_names)] +#![warn(clippy::negative_feature_names)] + +fn main() { + // test code goes here +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,44 @@ +error: the "no-" prefix in the feature name "no-qaq" is negative + | + = note: `-D clippy::negative-feature-names` implied by `-D warnings` + = help: consider renaming the feature to "qaq", but make sure the feature adds functionality + +error: the "no_" prefix in the feature name "no_qaq" is negative + | + = help: consider renaming the feature to "qaq", but make sure the feature adds functionality + +error: the "not-" prefix in the feature name "not-orz" is negative + | + = help: consider renaming the feature to "orz", but make sure the feature adds functionality + +error: the "not_" prefix in the feature name "not_orz" is negative + | + = help: consider renaming the feature to "orz", but make sure the feature adds functionality + +error: the "-support" suffix in the feature name "qvq-support" is redundant + | + = note: `-D clippy::redundant-feature-names` implied by `-D warnings` + = help: consider renaming the feature to "qvq" + +error: the "_support" suffix in the feature name "qvq_support" is redundant + | + = help: consider renaming the feature to "qvq" + +error: the "use-" prefix in the feature name "use-qwq" is redundant + | + = help: consider renaming the feature to "qwq" + +error: the "use_" prefix in the feature name "use_qwq" is redundant + | + = help: consider renaming the feature to "qwq" + +error: the "with-" prefix in the feature name "with-owo" is redundant + | + = help: consider renaming the feature to "owo" + +error: the "with_" prefix in the feature name "with_owo" is redundant + | + = help: consider renaming the feature to "owo" + +error: aborting due to 10 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/pass/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/pass/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/pass/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/pass/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,9 @@ + +# This file should not trigger the lint + +[package] +name = "feature_name" +version = "0.1.0" +publish = false + +[workspace] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,7 @@ +// compile-flags: --crate-name=feature_name +#![warn(clippy::redundant_feature_names)] +#![warn(clippy::negative_feature_names)] + +fn main() { + // test code goes here +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,8 @@ +[package] +name = "fail" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner/stuff/most.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner/stuff/most.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner/stuff/most.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner/stuff/most.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1 @@ +pub struct Snarks; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner/stuff.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner/stuff.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner/stuff.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner/stuff.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,3 @@ +pub mod most; + +pub struct Inner; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/inner.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1 @@ +pub mod stuff; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/bad/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,3 @@ +pub mod inner; + +pub struct Thing; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,9 @@ +#![warn(clippy::self_named_module_files)] + +mod bad; + +fn main() { + let _ = bad::Thing; + let _ = bad::inner::stuff::Inner; + let _ = bad::inner::stuff::most::Snarks; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,19 @@ +error: `mod.rs` files are required, found `/bad/inner.rs` + --> $DIR/bad/inner.rs:1:1 + | +LL | pub mod stuff; + | ^ + | + = note: `-D clippy::self-named-module-files` implied by `-D warnings` + = help: move `/bad/inner.rs` to `/bad/inner/mod.rs` + +error: `mod.rs` files are required, found `/bad/inner/stuff.rs` + --> $DIR/bad/inner/stuff.rs:1:1 + | +LL | pub mod most; + | ^ + | + = help: move `/bad/inner/stuff.rs` to `/bad/inner/stuff/mod.rs` + +error: aborting due to 2 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,8 @@ +[package] +name = "fail" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/bad/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/bad/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/bad/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/bad/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1 @@ +pub struct Thing; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,7 @@ +#![warn(clippy::mod_module_files)] + +mod bad; + +fn main() { + let _ = bad::Thing; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,11 @@ +error: `mod.rs` files are not allowed, found `/bad/mod.rs` + --> $DIR/bad/mod.rs:1:1 + | +LL | pub struct Thing; + | ^ + | + = note: `-D clippy::mod-module-files` implied by `-D warnings` + = help: move `/bad/mod.rs` to `/bad.rs` + +error: aborting due to previous error + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,8 @@ +[package] +name = "fail" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/bad/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/bad/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/bad/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/bad/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1 @@ +pub struct Thing; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,10 @@ +#![warn(clippy::self_named_module_files)] + +mod bad; +mod more; + +fn main() { + let _ = bad::Thing; + let _ = more::foo::Foo; + let _ = more::inner::Inner; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/foo.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/foo.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/foo.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/foo.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1 @@ +pub struct Foo; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/inner/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/inner/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/inner/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/inner/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1 @@ +pub struct Inner; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/mod.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/mod.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_mod/src/more/mod.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,2 @@ +pub mod foo; +pub mod inner; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,8 @@ +[package] +name = "pass" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/src/good.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/src/good.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/src/good.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/src/good.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1 @@ +pub struct Thing; diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/src/main.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-cargo/module_style/pass_no_mod/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,7 @@ +#![warn(clippy::mod_module_files)] + +mod good; + +fn main() { + let _ = good::Thing; +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-internal/invalid_paths.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-internal/invalid_paths.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-internal/invalid_paths.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-internal/invalid_paths.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -4,7 +4,7 @@ LL | pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::clippy-lints-internal` implied by `-D warnings` + = note: `-D clippy::invalid-paths` implied by `-D warnings` error: invalid path --> $DIR/invalid_paths.rs:20:5 diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,7 @@ --> $DIR/match_type_on_diag_item.rs:30:17 | LL | let _ = match_type(cx, ty, &OPTION); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::option_type)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Option)` | note: the lint level is defined here --> $DIR/match_type_on_diag_item.rs:1:9 @@ -15,7 +15,7 @@ --> $DIR/match_type_on_diag_item.rs:31:17 | LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::result_type)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Result)` error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:34:17 diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -82,13 +82,13 @@ --> $DIR/conf_nonstandard_macro_braces.rs:57:5 | LL | eprint!("test if user config overrides defaults"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: consider writing `eprint!["test if user config overrides defaults"];` +help: consider writing `eprint!["test if user config overrides defaults"]` --> $DIR/conf_nonstandard_macro_braces.rs:57:5 | LL | eprint!("test if user config overrides defaults"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1 @@ +enable-raw-pointer-heuristic-for-send = false diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,43 @@ +#![warn(clippy::non_send_fields_in_send_ty)] +#![feature(extern_types)] + +use std::rc::Rc; + +// Basic tests should not be affected +pub struct NoGeneric { + rc_is_not_send: Rc, +} + +unsafe impl Send for NoGeneric {} + +pub struct MultiField { + field1: T, + field2: T, + field3: T, +} + +unsafe impl Send for MultiField {} + +pub enum MyOption { + MySome(T), + MyNone, +} + +unsafe impl Send for MyOption {} + +// All fields are disallowed when raw pointer heuristic is off +extern "C" { + type NonSend; +} + +pub struct HeuristicTest { + field1: Vec<*const NonSend>, + field2: [*const NonSend; 3], + field3: (*const NonSend, *const NonSend, *const NonSend), + field4: (*const NonSend, Rc), + field5: Vec>, +} + +unsafe impl Send for HeuristicTest {} + +fn main() {} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,91 @@ +error: this implementation is unsound, as some fields in `NoGeneric` are `!Send` + --> $DIR/test.rs:11:1 + | +LL | unsafe impl Send for NoGeneric {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` +note: the type of field `rc_is_not_send` is `!Send` + --> $DIR/test.rs:8:5 + | +LL | rc_is_not_send: Rc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: this implementation is unsound, as some fields in `MultiField` are `!Send` + --> $DIR/test.rs:19:1 + | +LL | unsafe impl Send for MultiField {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field1` is `!Send` + --> $DIR/test.rs:14:5 + | +LL | field1: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl +note: the type of field `field2` is `!Send` + --> $DIR/test.rs:15:5 + | +LL | field2: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl +note: the type of field `field3` is `!Send` + --> $DIR/test.rs:16:5 + | +LL | field3: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `MyOption` are `!Send` + --> $DIR/test.rs:26:1 + | +LL | unsafe impl Send for MyOption {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `0` is `!Send` + --> $DIR/test.rs:22:12 + | +LL | MySome(T), + | ^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send` + --> $DIR/test.rs:41:1 + | +LL | unsafe impl Send for HeuristicTest {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field1` is `!Send` + --> $DIR/test.rs:34:5 + | +LL | field1: Vec<*const NonSend>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` +note: the type of field `field2` is `!Send` + --> $DIR/test.rs:35:5 + | +LL | field2: [*const NonSend; 3], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` +note: the type of field `field3` is `!Send` + --> $DIR/test.rs:36:5 + | +LL | field3: (*const NonSend, *const NonSend, *const NonSend), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` +note: the type of field `field4` is `!Send` + --> $DIR/test.rs:37:5 + | +LL | field4: (*const NonSend, Rc), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` +note: the type of field `field5` is `!Send` + --> $DIR/test.rs:38:5 + | +LL | field5: Vec>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: aborting due to 4 previous errors + diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,8 @@ disallowed-methods = [ + # just a string is shorthand for path only "std::iter::Iterator::sum", - "regex::Regex::is_match", - "regex::Regex::new" + # can give path and reason with an inline table + { path = "regex::Regex::is_match", reason = "no matching allowed" }, + # can use an inline table but omit reason + { path = "regex::Regex::new" }, ] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -error: use of a disallowed method `regex::re_unicode::Regex::new` +error: use of a disallowed method `regex::Regex::new` --> $DIR/conf_disallowed_method.rs:7:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); @@ -6,13 +6,15 @@ | = note: `-D clippy::disallowed-method` implied by `-D warnings` -error: use of a disallowed method `regex::re_unicode::Regex::is_match` +error: use of a disallowed method `regex::Regex::is_match` --> $DIR/conf_disallowed_method.rs:8:5 | LL | re.is_match("abc"); | ^^^^^^^^^^^^^^^^^^ + | + = note: no matching allowed (from clippy.toml) -error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum` +error: use of a disallowed method `std::iter::Iterator::sum` --> $DIR/conf_disallowed_method.rs:11:5 | LL | a.iter().sum::(); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,7 +2,6 @@ // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] -#![allow(clippy::many_single_char_names)] #[derive(Copy, Clone)] struct Foo(u8); diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,5 +1,5 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/test.rs:15:11 + --> $DIR/test.rs:14:11 | LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `u16` @@ -11,7 +11,7 @@ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/test.rs:15:20 + --> $DIR/test.rs:14:20 | LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `Foo` diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `third-party` at line 5 column 1 error: aborting due to previous error diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/versioncheck.rs rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/versioncheck.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/tests/versioncheck.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/tests/versioncheck.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,4 +1,7 @@ +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::single_match_else)] + use rustc_tools_util::VersionInfo; #[test] diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/clippy/util/etc/pre-commit.sh rustc-1.57.0+dfsg1+llvm/src/tools/clippy/util/etc/pre-commit.sh --- rustc-1.56.0+dfsg1+llvm/src/tools/clippy/util/etc/pre-commit.sh 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/clippy/util/etc/pre-commit.sh 2021-11-29 19:27:12.000000000 +0000 @@ -6,6 +6,7 @@ # Update lints cargo dev update_lints git add clippy_lints/src/lib.rs +git add clippy_lints/src/lib.*.rs # Formatting: # Git will not automatically add the formatted code to the staged changes once diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "compiletest" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] colored = "2" diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/common.rs rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/common.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/common.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/common.rs 2021-11-29 19:27:12.000000000 +0000 @@ -459,3 +459,9 @@ pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap()) } + +/// Absolute path to the directory to use for incremental compilation. Example: +/// /path/to/build/host-triple/test/ui/relative/testname.mode/testname.inc +pub fn incremental_dir(config: &Config, testpaths: &TestPaths) -> PathBuf { + output_base_name(config, testpaths, None).with_extension("inc") +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/compute_diff.rs rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/compute_diff.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/compute_diff.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/compute_diff.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,157 @@ +use std::collections::VecDeque; +use std::fs::{File, FileType}; +use std::path::Path; + +#[derive(Debug, PartialEq)] +pub enum DiffLine { + Context(String), + Expected(String), + Resulting(String), +} + +#[derive(Debug, PartialEq)] +pub struct Mismatch { + pub line_number: u32, + pub lines: Vec, +} + +impl Mismatch { + fn new(line_number: u32) -> Mismatch { + Mismatch { line_number, lines: Vec::new() } + } +} + +// Produces a diff between the expected output and actual output. +pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { + let mut line_number = 1; + let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size); + let mut lines_since_mismatch = context_size + 1; + let mut results = Vec::new(); + let mut mismatch = Mismatch::new(0); + + for result in diff::lines(expected, actual) { + match result { + diff::Result::Left(str) => { + if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { + results.push(mismatch); + mismatch = Mismatch::new(line_number - context_queue.len() as u32); + } + + while let Some(line) = context_queue.pop_front() { + mismatch.lines.push(DiffLine::Context(line.to_owned())); + } + + mismatch.lines.push(DiffLine::Expected(str.to_owned())); + line_number += 1; + lines_since_mismatch = 0; + } + diff::Result::Right(str) => { + if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { + results.push(mismatch); + mismatch = Mismatch::new(line_number - context_queue.len() as u32); + } + + while let Some(line) = context_queue.pop_front() { + mismatch.lines.push(DiffLine::Context(line.to_owned())); + } + + mismatch.lines.push(DiffLine::Resulting(str.to_owned())); + lines_since_mismatch = 0; + } + diff::Result::Both(str, _) => { + if context_queue.len() >= context_size { + let _ = context_queue.pop_front(); + } + + if lines_since_mismatch < context_size { + mismatch.lines.push(DiffLine::Context(str.to_owned())); + } else if context_size > 0 { + context_queue.push_back(str); + } + + line_number += 1; + lines_since_mismatch += 1; + } + } + } + + results.push(mismatch); + results.remove(0); + + results +} + +pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> String { + use std::fmt::Write; + let mut output = String::new(); + let diff_results = make_diff(expected, actual, context_size); + for result in diff_results { + let mut line_number = result.line_number; + for line in result.lines { + match line { + DiffLine::Expected(e) => { + writeln!(output, "-\t{}", e).unwrap(); + line_number += 1; + } + DiffLine::Context(c) => { + writeln!(output, "{}\t{}", line_number, c).unwrap(); + line_number += 1; + } + DiffLine::Resulting(r) => { + writeln!(output, "+\t{}", r).unwrap(); + } + } + } + writeln!(output).unwrap(); + } + output +} + +/// Filters based on filetype and extension whether to diff a file. +/// +/// Returns whether any data was actually written. +pub(crate) fn write_filtered_diff( + diff_filename: &str, + out_dir: &Path, + compare_dir: &Path, + verbose: bool, + filter: Filter, +) -> bool +where + Filter: Fn(FileType, Option<&str>) -> bool, +{ + use std::io::{Read, Write}; + let mut diff_output = File::create(diff_filename).unwrap(); + let mut wrote_data = false; + for entry in walkdir::WalkDir::new(out_dir) { + let entry = entry.expect("failed to read file"); + let extension = entry.path().extension().and_then(|p| p.to_str()); + if filter(entry.file_type(), extension) { + let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap()); + let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; + let actual_path = entry.path(); + let actual = std::fs::read(&actual_path).unwrap(); + let diff = unified_diff::diff( + &expected, + &expected_path.to_string_lossy(), + &actual, + &actual_path.to_string_lossy(), + 3, + ); + wrote_data |= !diff.is_empty(); + diff_output.write_all(&diff).unwrap(); + } + } + + if !wrote_data { + println!("note: diff is identical to nightly rustdoc"); + assert!(diff_output.metadata().unwrap().len() == 0); + return false; + } else if verbose { + eprintln!("printing diff:"); + let mut buf = Vec::new(); + diff_output.read_to_end(&mut buf).unwrap(); + std::io::stderr().lock().write_all(&mut buf).unwrap(); + } + true +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/header.rs rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/header.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/header.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/header.rs 2021-11-29 19:27:12.000000000 +0000 @@ -113,6 +113,21 @@ // testing harness and used when generating compilation // arguments. (In particular, it propagates to the aux-builds.) pub incremental_dir: Option, + // If `true`, this test will use incremental compilation. + // + // This can be set manually with the `incremental` header, or implicitly + // by being a part of an incremental mode test. Using the `incremental` + // header should be avoided if possible; using an incremental mode test is + // preferred. Incremental mode tests support multiple passes, which can + // verify that the incremental cache can be loaded properly after being + // created. Just setting the header will only verify the behavior with + // creating an incremental cache, but doesn't check that it is created + // correctly. + // + // Compiletest will create the incremental directory, and ensure it is + // empty before the test starts. Incremental mode tests will reuse the + // incremental directory between passes in the same test. + pub incremental: bool, // How far should the test proceed while still passing. pass_mode: Option, // Ignore `--pass` overrides from the command line for this test. @@ -163,6 +178,7 @@ pretty_compare_only: false, forbid_output: vec![], incremental_dir: None, + incremental: false, pass_mode: None, fail_mode: None, ignore_pass: false, @@ -350,6 +366,10 @@ if !self.stderr_per_bitwidth { self.stderr_per_bitwidth = config.parse_stderr_per_bitwidth(ln); } + + if !self.incremental { + self.incremental = config.parse_incremental(ln); + } }); } @@ -360,6 +380,10 @@ self.failure_status = 101; } + if config.mode == Mode::Incremental { + self.incremental = true; + } + for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { if let Ok(val) = env::var(key) { if self.exec_env.iter().find(|&&(ref x, _)| x == key).is_none() { @@ -731,6 +755,10 @@ fn parse_edition(&self, line: &str) -> Option { self.parse_name_value_directive(line, "edition") } + + fn parse_incremental(&self, line: &str) -> bool { + self.parse_name_directive(line, "incremental") + } } fn expand_variables(mut value: String, config: &Config) -> String { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/main.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -28,6 +28,7 @@ mod tests; pub mod common; +pub mod compute_diff; pub mod errors; pub mod header; mod json; @@ -505,6 +506,8 @@ Err(_) => false, }, color: config.color, + shuffle: false, + shuffle_seed: None, test_threads: None, skip: vec![], list: false, diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/read2.rs rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/read2.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/read2.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/read2.rs 2021-11-29 19:27:12.000000000 +0000 @@ -2,6 +2,77 @@ // Consider unify the read2() in libstd, cargo and this to prevent further code duplication. pub use self::imp::read2; +use std::io; +use std::process::{Child, Output}; + +pub fn read2_abbreviated(mut child: Child) -> io::Result { + use io::Write; + use std::mem::replace; + + const HEAD_LEN: usize = 160 * 1024; + const TAIL_LEN: usize = 256 * 1024; + + enum ProcOutput { + Full(Vec), + Abbreviated { head: Vec, skipped: usize, tail: Box<[u8]> }, + } + + impl ProcOutput { + fn extend(&mut self, data: &[u8]) { + let new_self = match *self { + ProcOutput::Full(ref mut bytes) => { + bytes.extend_from_slice(data); + let new_len = bytes.len(); + if new_len <= HEAD_LEN + TAIL_LEN { + return; + } + let tail = bytes.split_off(new_len - TAIL_LEN).into_boxed_slice(); + let head = replace(bytes, Vec::new()); + let skipped = new_len - HEAD_LEN - TAIL_LEN; + ProcOutput::Abbreviated { head, skipped, tail } + } + ProcOutput::Abbreviated { ref mut skipped, ref mut tail, .. } => { + *skipped += data.len(); + if data.len() <= TAIL_LEN { + tail[..data.len()].copy_from_slice(data); + tail.rotate_left(data.len()); + } else { + tail.copy_from_slice(&data[(data.len() - TAIL_LEN)..]); + } + return; + } + }; + *self = new_self; + } + + fn into_bytes(self) -> Vec { + match self { + ProcOutput::Full(bytes) => bytes, + ProcOutput::Abbreviated { mut head, skipped, tail } => { + write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap(); + head.extend_from_slice(&tail); + head + } + } + } + } + + let mut stdout = ProcOutput::Full(Vec::new()); + let mut stderr = ProcOutput::Full(Vec::new()); + + drop(child.stdin.take()); + read2( + child.stdout.take().unwrap(), + child.stderr.take().unwrap(), + &mut |is_stdout, data, _| { + if is_stdout { &mut stdout } else { &mut stderr }.extend(data); + data.clear(); + }, + )?; + let status = child.wait()?; + + Ok(Output { status, stdout: stdout.into_bytes(), stderr: stderr.into_bytes() }) +} #[cfg(not(any(unix, windows)))] mod imp { diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/runtest/debugger.rs rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/runtest/debugger.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/runtest/debugger.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/runtest/debugger.rs 2021-11-29 19:27:12.000000000 +0000 @@ -0,0 +1,115 @@ +use crate::common::Config; +use crate::runtest::ProcRes; + +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; + +pub(super) struct DebuggerCommands { + pub commands: Vec, + pub check_lines: Vec, + pub breakpoint_lines: Vec, +} + +impl DebuggerCommands { + pub(super) fn parse_from( + file: &Path, + config: &Config, + debugger_prefixes: &[&str], + ) -> Result { + let directives = debugger_prefixes + .iter() + .map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix))) + .collect::>(); + + let mut breakpoint_lines = vec![]; + let mut commands = vec![]; + let mut check_lines = vec![]; + let mut counter = 1; + let reader = BufReader::new(File::open(file).unwrap()); + for line in reader.lines() { + match line { + Ok(line) => { + let line = + if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() }; + + if line.contains("#break") { + breakpoint_lines.push(counter); + } + + for &(ref command_directive, ref check_directive) in &directives { + config + .parse_name_value_directive(&line, command_directive) + .map(|cmd| commands.push(cmd)); + + config + .parse_name_value_directive(&line, check_directive) + .map(|cmd| check_lines.push(cmd)); + } + } + Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)), + } + counter += 1; + } + + Ok(Self { commands, check_lines, breakpoint_lines }) + } +} + +pub(super) fn check_debugger_output( + debugger_run_result: &ProcRes, + check_lines: &[String], +) -> Result<(), String> { + let num_check_lines = check_lines.len(); + + let mut check_line_index = 0; + for line in debugger_run_result.stdout.lines() { + if check_line_index >= num_check_lines { + break; + } + + if check_single_line(line, &(check_lines[check_line_index])[..]) { + check_line_index += 1; + } + } + if check_line_index != num_check_lines && num_check_lines > 0 { + Err(format!("line not found in debugger output: {}", check_lines[check_line_index])) + } else { + Ok(()) + } +} + +fn check_single_line(line: &str, check_line: &str) -> bool { + // Allow check lines to leave parts unspecified (e.g., uninitialized + // bits in the wrong case of an enum) with the notation "[...]". + let line = line.trim(); + let check_line = check_line.trim(); + let can_start_anywhere = check_line.starts_with("[...]"); + let can_end_anywhere = check_line.ends_with("[...]"); + + let check_fragments: Vec<&str> = + check_line.split("[...]").filter(|frag| !frag.is_empty()).collect(); + if check_fragments.is_empty() { + return true; + } + + let (mut rest, first_fragment) = if can_start_anywhere { + match line.find(check_fragments[0]) { + Some(pos) => (&line[pos + check_fragments[0].len()..], 1), + None => return false, + } + } else { + (line, 0) + }; + + for current_fragment in &check_fragments[first_fragment..] { + match rest.find(current_fragment) { + Some(pos) => { + rest = &rest[pos + current_fragment.len()..]; + } + None => return false, + } + } + + if !can_end_anywhere && !rest.is_empty() { false } else { true } +} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/runtest.rs rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/runtest.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/runtest.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/runtest.rs 2021-11-29 19:27:12.000000000 +0000 @@ -1,16 +1,18 @@ // ignore-tidy-filelength use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT}; -use crate::common::{output_base_dir, output_base_name, output_testname_unique}; +use crate::common::{incremental_dir, output_base_dir, output_base_name, output_testname_unique}; use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui}; use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; use crate::common::{Pretty, RunPassValgrind}; use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT}; +use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; +use crate::read2::read2_abbreviated; use crate::util::get_pointer_width; use crate::util::{logv, PathBufExt}; use crate::ColorConfig; @@ -18,7 +20,7 @@ use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; use std::collections::hash_map::DefaultHasher; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::{OsStr, OsString}; use std::fs::{self, create_dir_all, File, OpenOptions}; @@ -26,7 +28,7 @@ use std::io::prelude::*; use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; -use std::process::{Child, Command, ExitStatus, Output, Stdio}; +use std::process::{Command, ExitStatus, Output, Stdio}; use std::str; use glob::glob; @@ -36,6 +38,9 @@ use crate::extract_gdb_version; use crate::is_android_gdb_target; +mod debugger; +use debugger::{check_debugger_output, DebuggerCommands}; + #[cfg(test)] mod tests; @@ -100,111 +105,6 @@ } } -#[derive(Debug, PartialEq)] -pub enum DiffLine { - Context(String), - Expected(String), - Resulting(String), -} - -#[derive(Debug, PartialEq)] -pub struct Mismatch { - pub line_number: u32, - pub lines: Vec, -} - -impl Mismatch { - fn new(line_number: u32) -> Mismatch { - Mismatch { line_number, lines: Vec::new() } - } -} - -// Produces a diff between the expected output and actual output. -pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { - let mut line_number = 1; - let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size); - let mut lines_since_mismatch = context_size + 1; - let mut results = Vec::new(); - let mut mismatch = Mismatch::new(0); - - for result in diff::lines(expected, actual) { - match result { - diff::Result::Left(str) => { - if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { - results.push(mismatch); - mismatch = Mismatch::new(line_number - context_queue.len() as u32); - } - - while let Some(line) = context_queue.pop_front() { - mismatch.lines.push(DiffLine::Context(line.to_owned())); - } - - mismatch.lines.push(DiffLine::Expected(str.to_owned())); - line_number += 1; - lines_since_mismatch = 0; - } - diff::Result::Right(str) => { - if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { - results.push(mismatch); - mismatch = Mismatch::new(line_number - context_queue.len() as u32); - } - - while let Some(line) = context_queue.pop_front() { - mismatch.lines.push(DiffLine::Context(line.to_owned())); - } - - mismatch.lines.push(DiffLine::Resulting(str.to_owned())); - lines_since_mismatch = 0; - } - diff::Result::Both(str, _) => { - if context_queue.len() >= context_size { - let _ = context_queue.pop_front(); - } - - if lines_since_mismatch < context_size { - mismatch.lines.push(DiffLine::Context(str.to_owned())); - } else if context_size > 0 { - context_queue.push_back(str); - } - - line_number += 1; - lines_since_mismatch += 1; - } - } - } - - results.push(mismatch); - results.remove(0); - - results -} - -fn write_diff(expected: &str, actual: &str, context_size: usize) -> String { - use std::fmt::Write; - let mut output = String::new(); - let diff_results = make_diff(expected, actual, context_size); - for result in diff_results { - let mut line_number = result.line_number; - for line in result.lines { - match line { - DiffLine::Expected(e) => { - writeln!(output, "-\t{}", e).unwrap(); - line_number += 1; - } - DiffLine::Context(c) => { - writeln!(output, "{}\t{}", line_number, c).unwrap(); - line_number += 1; - } - DiffLine::Resulting(r) => { - writeln!(output, "+\t{}", r).unwrap(); - } - } - } - writeln!(output).unwrap(); - } - output -} - pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) { match &*config.target { "arm-linux-androideabi" @@ -229,18 +129,24 @@ print!("\n\n"); } debug!("running {:?}", testpaths.file.display()); - let props = TestProps::from_file(&testpaths.file, revision, &config); + let mut props = TestProps::from_file(&testpaths.file, revision, &config); + if props.incremental { + props.incremental_dir = Some(incremental_dir(&config, testpaths)); + } let cx = TestCx { config: &config, props: &props, testpaths, revision }; create_dir_all(&cx.output_base_dir()).unwrap(); + if props.incremental { + cx.init_incremental_test(); + } if config.mode == Incremental { // Incremental tests are special because they cannot be run in // parallel. assert!(!props.revisions.is_empty(), "Incremental tests require revisions."); - cx.init_incremental_test(); for revision in &props.revisions { - let revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config); + let mut revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config); + revision_props.incremental_dir = props.incremental_dir.clone(); let rev_cx = TestCx { config: &config, props: &revision_props, @@ -297,12 +203,6 @@ revision: Option<&'test str>, } -struct DebuggerCommands { - commands: Vec, - check_lines: Vec, - breakpoint_lines: Vec, -} - enum ReadFrom { Path, Stdin(String), @@ -332,10 +232,8 @@ /// Code executed for each revision in turn (or, if there are no /// revisions, exactly once, with revision == None). fn run_revision(&self) { - if self.props.should_ice { - if self.config.mode != Incremental { - self.fatal("cannot use should-ice in a test that is not cfail"); - } + if self.props.should_ice && self.config.mode != Incremental { + self.fatal("cannot use should-ice in a test that is not cfail"); } match self.config.mode { RunPassValgrind => self.run_valgrind_test(), @@ -771,7 +669,10 @@ // Parse debugger commands etc from test files let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } = - self.parse_debugger_commands(prefixes); + match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { + Ok(cmds) => cmds, + Err(e) => self.fatal(&e), + }; // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands let mut script_str = String::with_capacity(2048); @@ -823,7 +724,9 @@ self.fatal_proc_rec("Error while running CDB", &debugger_run_result); } - self.check_debugger_output(&debugger_run_result, &check_lines); + if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) { + self.fatal_proc_rec(&e, &debugger_run_result); + } } fn run_debuginfo_gdb_test(&self) { @@ -854,7 +757,10 @@ }; let DebuggerCommands { commands, check_lines, breakpoint_lines } = - self.parse_debugger_commands(prefixes); + match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { + Ok(cmds) => cmds, + Err(e) => self.fatal(&e), + }; let mut cmds = commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) @@ -1057,7 +963,9 @@ self.fatal_proc_rec("gdb failed to execute", &debugger_run_result); } - self.check_debugger_output(&debugger_run_result, &check_lines); + if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) { + self.fatal_proc_rec(&e, &debugger_run_result); + } } fn run_debuginfo_lldb_test(&self) { @@ -1115,7 +1023,10 @@ // Parse debugger commands etc from test files let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } = - self.parse_debugger_commands(prefixes); + match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { + Ok(cmds) => cmds, + Err(e) => self.fatal(&e), + }; // Write debugger script: // We don't want to hang when calling `quit` while the process is still running @@ -1191,7 +1102,9 @@ self.fatal_proc_rec("Error while running LLDB", &debugger_run_result); } - self.check_debugger_output(&debugger_run_result, &check_lines); + if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) { + self.fatal_proc_rec(&e, &debugger_run_result); + } } fn run_lldb( @@ -1228,45 +1141,6 @@ ProcRes { status, stdout: out, stderr: err, cmdline: format!("{:?}", cmd) } } - fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands { - let directives = debugger_prefixes - .iter() - .map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix))) - .collect::>(); - - let mut breakpoint_lines = vec![]; - let mut commands = vec![]; - let mut check_lines = vec![]; - let mut counter = 1; - let reader = BufReader::new(File::open(&self.testpaths.file).unwrap()); - for line in reader.lines() { - match line { - Ok(line) => { - let line = - if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() }; - - if line.contains("#break") { - breakpoint_lines.push(counter); - } - - for &(ref command_directive, ref check_directive) in &directives { - self.config - .parse_name_value_directive(&line, command_directive) - .map(|cmd| commands.push(cmd)); - - self.config - .parse_name_value_directive(&line, check_directive) - .map(|cmd| check_lines.push(cmd)); - } - } - Err(e) => self.fatal(&format!("Error while parsing debugger commands: {}", e)), - } - counter += 1; - } - - DebuggerCommands { commands, check_lines, breakpoint_lines } - } - fn cleanup_debug_info_options(&self, options: &Option) -> Option { if options.is_none() { return None; @@ -1313,66 +1187,6 @@ } } - fn check_debugger_output(&self, debugger_run_result: &ProcRes, check_lines: &[String]) { - let num_check_lines = check_lines.len(); - - let mut check_line_index = 0; - for line in debugger_run_result.stdout.lines() { - if check_line_index >= num_check_lines { - break; - } - - if check_single_line(line, &(check_lines[check_line_index])[..]) { - check_line_index += 1; - } - } - if check_line_index != num_check_lines && num_check_lines > 0 { - self.fatal_proc_rec( - &format!("line not found in debugger output: {}", check_lines[check_line_index]), - debugger_run_result, - ); - } - - fn check_single_line(line: &str, check_line: &str) -> bool { - // Allow check lines to leave parts unspecified (e.g., uninitialized - // bits in the wrong case of an enum) with the notation "[...]". - let line = line.trim(); - let check_line = check_line.trim(); - let can_start_anywhere = check_line.starts_with("[...]"); - let can_end_anywhere = check_line.ends_with("[...]"); - - let check_fragments: Vec<&str> = - check_line.split("[...]").filter(|frag| !frag.is_empty()).collect(); - if check_fragments.is_empty() { - return true; - } - - let (mut rest, first_fragment) = if can_start_anywhere { - match line.find(check_fragments[0]) { - Some(pos) => (&line[pos + check_fragments[0].len()..], 1), - None => return false, - } - } else { - (line, 0) - }; - - for current_fragment in &check_fragments[first_fragment..] { - match rest.find(current_fragment) { - Some(pos) => { - rest = &rest[pos + current_fragment.len()..]; - } - None => return false, - } - } - - if !can_end_anywhere && !rest.is_empty() { - return false; - } - - true - } - } - fn check_error_patterns( &self, output_to_check: &str, @@ -2251,9 +2065,9 @@ fn maybe_dump_to_stdout(&self, out: &str, err: &str) { if self.config.verbose { - println!("------{}------------------------------", "stdout"); + println!("------stdout------------------------------"); println!("{}", out); - println!("------{}------------------------------", "stderr"); + println!("------stderr------------------------------"); println!("{}", err); println!("------------------------------------------"); } @@ -2501,43 +2315,17 @@ let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id()); - { - let mut diff_output = File::create(&diff_filename).unwrap(); - let mut wrote_data = false; - for entry in walkdir::WalkDir::new(out_dir) { - let entry = entry.expect("failed to read file"); - let extension = entry.path().extension().and_then(|p| p.to_str()); - if entry.file_type().is_file() + if !write_filtered_diff( + &diff_filename, + out_dir, + &compare_dir, + self.config.verbose, + |file_type, extension| { + file_type.is_file() && (extension == Some("html".into()) || extension == Some("js".into())) - { - let expected_path = - compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap()); - let expected = - if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; - let actual_path = entry.path(); - let actual = std::fs::read(&actual_path).unwrap(); - let diff = unified_diff::diff( - &expected, - &expected_path.to_string_lossy(), - &actual, - &actual_path.to_string_lossy(), - 3, - ); - wrote_data |= !diff.is_empty(); - diff_output.write_all(&diff).unwrap(); - } - } - - if !wrote_data { - println!("note: diff is identical to nightly rustdoc"); - assert!(diff_output.metadata().unwrap().len() == 0); - return; - } else if self.config.verbose { - eprintln!("printing diff:"); - let mut buf = Vec::new(); - diff_output.read_to_end(&mut buf).unwrap(); - std::io::stderr().lock().write_all(&mut buf).unwrap(); - } + }, + ) { + return; } match self.config.color { @@ -2937,7 +2725,7 @@ // incremental workproduct directory. Delete any old // incremental work products that may be there from prior // runs. - let incremental_dir = self.incremental_dir(); + let incremental_dir = self.props.incremental_dir.as_ref().unwrap(); if incremental_dir.exists() { // Canonicalizing the path will convert it to the //?/ format // on Windows, which enables paths longer than 260 character @@ -2947,7 +2735,7 @@ fs::create_dir_all(&incremental_dir).unwrap(); if self.config.verbose { - print!("init_incremental_test: incremental_dir={}", incremental_dir.display()); + println!("init_incremental_test: incremental_dir={}", incremental_dir.display()); } } @@ -2974,46 +2762,30 @@ let revision = self.revision.expect("incremental tests require a list of revisions"); // Incremental workproduct directory should have already been created. - let incremental_dir = self.incremental_dir(); + let incremental_dir = self.props.incremental_dir.as_ref().unwrap(); assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir"); - // Add an extra flag pointing at the incremental directory. - let mut revision_props = self.props.clone(); - revision_props.incremental_dir = Some(incremental_dir); - - let revision_cx = TestCx { - config: self.config, - props: &revision_props, - testpaths: self.testpaths, - revision: self.revision, - }; - if self.config.verbose { - print!("revision={:?} revision_props={:#?}", revision, revision_props); + print!("revision={:?} props={:#?}", revision, self.props); } if revision.starts_with("rpass") { - if revision_cx.props.should_ice { - revision_cx.fatal("can only use should-ice in cfail tests"); + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); } - revision_cx.run_rpass_test(); + self.run_rpass_test(); } else if revision.starts_with("rfail") { - if revision_cx.props.should_ice { - revision_cx.fatal("can only use should-ice in cfail tests"); + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); } - revision_cx.run_rfail_test(); + self.run_rfail_test(); } else if revision.starts_with("cfail") { - revision_cx.run_cfail_test(); + self.run_cfail_test(); } else { - revision_cx.fatal("revision name must begin with rpass, rfail, or cfail"); + self.fatal("revision name must begin with rpass, rfail, or cfail"); } } - /// Directory where incremental work products are stored. - fn incremental_dir(&self) -> PathBuf { - self.output_base_name().with_extension("inc") - } - fn run_rmake_test(&self) { let cwd = env::current_dir().unwrap(); let src_root = self.config.src_base.parent().unwrap().parent().unwrap().parent().unwrap(); @@ -3388,11 +3160,10 @@ if !proc_res.status.success() { self.fatal_proc_rec("test run failed!", &proc_res); } - } else { - if proc_res.status.success() { - self.fatal_proc_rec("test run succeeded!", &proc_res); - } + } else if proc_res.status.success() { + self.fatal_proc_rec("test run succeeded!", &proc_res); } + if !self.props.error_patterns.is_empty() { // "// error-pattern" comments self.check_error_patterns(&proc_res.stderr, &proc_res, pm); @@ -3439,10 +3210,11 @@ if !res.status.success() { self.fatal_proc_rec("failed to compile fixed code", &res); } - if !res.stderr.is_empty() && !self.props.rustfix_only_machine_applicable { - if !json::rustfix_diagnostics_only(&res.stderr).is_empty() { - self.fatal_proc_rec("fixed code is still producing diagnostics", &res); - } + if !res.stderr.is_empty() + && !self.props.rustfix_only_machine_applicable + && !json::rustfix_diagnostics_only(&res.stderr).is_empty() + { + self.fatal_proc_rec("fixed code is still producing diagnostics", &res); } } } @@ -3960,72 +3732,3 @@ Yes, No, } - -fn read2_abbreviated(mut child: Child) -> io::Result { - use crate::read2::read2; - use std::mem::replace; - - const HEAD_LEN: usize = 160 * 1024; - const TAIL_LEN: usize = 256 * 1024; - - enum ProcOutput { - Full(Vec), - Abbreviated { head: Vec, skipped: usize, tail: Box<[u8]> }, - } - - impl ProcOutput { - fn extend(&mut self, data: &[u8]) { - let new_self = match *self { - ProcOutput::Full(ref mut bytes) => { - bytes.extend_from_slice(data); - let new_len = bytes.len(); - if new_len <= HEAD_LEN + TAIL_LEN { - return; - } - let tail = bytes.split_off(new_len - TAIL_LEN).into_boxed_slice(); - let head = replace(bytes, Vec::new()); - let skipped = new_len - HEAD_LEN - TAIL_LEN; - ProcOutput::Abbreviated { head, skipped, tail } - } - ProcOutput::Abbreviated { ref mut skipped, ref mut tail, .. } => { - *skipped += data.len(); - if data.len() <= TAIL_LEN { - tail[..data.len()].copy_from_slice(data); - tail.rotate_left(data.len()); - } else { - tail.copy_from_slice(&data[(data.len() - TAIL_LEN)..]); - } - return; - } - }; - *self = new_self; - } - - fn into_bytes(self) -> Vec { - match self { - ProcOutput::Full(bytes) => bytes, - ProcOutput::Abbreviated { mut head, skipped, tail } => { - write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap(); - head.extend_from_slice(&tail); - head - } - } - } - } - - let mut stdout = ProcOutput::Full(Vec::new()); - let mut stderr = ProcOutput::Full(Vec::new()); - - drop(child.stdin.take()); - read2( - child.stdout.take().unwrap(), - child.stderr.take().unwrap(), - &mut |is_stdout, data, _| { - if is_stdout { &mut stdout } else { &mut stderr }.extend(data); - data.clear(); - }, - )?; - let status = child.wait()?; - - Ok(Output { status, stdout: stdout.into_bytes(), stderr: stderr.into_bytes() }) -} diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/util.rs rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/util.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/compiletest/src/util.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/compiletest/src/util.rs 2021-11-29 19:27:12.000000000 +0000 @@ -54,6 +54,7 @@ ("i386", "x86"), ("i586", "x86"), ("i686", "x86"), + ("m68k", "m68k"), ("mips", "mips"), ("mips64", "mips64"), ("mips64el", "mips64"), @@ -95,7 +96,8 @@ ]; pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[ - "aarch64-apple-darwin", + // FIXME: currently broken, see #88132 + // "aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/error_index_generator/Cargo.toml rustc-1.57.0+dfsg1+llvm/src/tools/error_index_generator/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/src/tools/error_index_generator/Cargo.toml 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/error_index_generator/Cargo.toml 2021-11-29 19:27:12.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "error_index_generator" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustdoc = { path = "../../librustdoc" } diff -Nru rustc-1.56.0+dfsg1+llvm/src/tools/error_index_generator/main.rs rustc-1.57.0+dfsg1+llvm/src/tools/error_index_generator/main.rs --- rustc-1.56.0+dfsg1+llvm/src/tools/error_index_generator/main.rs 2021-10-18 09:52:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/src/tools/error_index_generator/main.rs 2021-11-29 19:27:12.000000000 +0000 @@ -14,7 +14,7 @@ use rustc_span::edition::DEFAULT_EDITION; -use rustdoc::html::markdown::{ErrorCodes, IdMap, Markdown, Playground}; +use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; pub struct ErrorMetadata { pub description: Option, @@ -119,14 +119,15 @@ write!( output, "{}", - Markdown( - desc, - &[], - &mut id_map, - ErrorCodes::Yes, - DEFAULT_EDITION, - &Some(playground) - ) + Markdown { + content: desc, + links: &[], + ids: &mut id_map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &Some(playground), + heading_offset: HeadingOffset::H1, + } .into_string() )? } @@ -143,56 +144,41 @@ r##"

` (where P is one \ of the previous types except `Self`)"; @@ -1290,10 +1186,10 @@ cause: ObligationCause<'tcx>, receiver_ty: Ty<'tcx>, ) -> bool { - let trait_ref = ty::TraitRef { + let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id: receiver_trait_def_id, substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), - }; + }); let obligation = traits::Obligation::new( cause, @@ -1439,20 +1335,23 @@ hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir()) } + #[instrument(skip(self, i), level = "debug")] fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - debug!("visit_item: {:?}", i); + trace!(?i); self.tcx.ensure().check_item_well_formed(i.def_id); hir_visit::walk_item(self, i); } + #[instrument(skip(self, trait_item), level = "debug")] fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - debug!("visit_trait_item: {:?}", trait_item); + trace!(?trait_item); self.tcx.ensure().check_trait_item_well_formed(trait_item.def_id); hir_visit::walk_trait_item(self, trait_item); } + #[instrument(skip(self, impl_item), level = "debug")] fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - debug!("visit_impl_item: {:?}", impl_item); + trace!(?impl_item); self.tcx.ensure().check_impl_item_well_formed(impl_item.def_id); hir_visit::walk_impl_item(self, impl_item); } @@ -1513,7 +1412,11 @@ .collect() } - pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec> { + pub(super) fn impl_implied_bounds( + &self, + impl_def_id: DefId, + span: Span, + ) -> FxHashSet> { match self.tcx.impl_trait_ref(impl_def_id) { Some(trait_ref) => { // Trait impl: take implied bounds from all types that @@ -1526,7 +1429,7 @@ // Inherent impl: take implied bounds from the `self` type. let self_ty = self.tcx.type_of(impl_def_id); let self_ty = self.normalize_associated_types_in(span, self_ty); - vec![self_ty] + std::array::IntoIter::new([self_ty]).collect() } } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/writeback.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/writeback.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check/writeback.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check/writeback.rs 2021-11-29 19:27:11.000000000 +0000 @@ -140,7 +140,7 @@ // operating on scalars, we clear the overload. fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) { match e.kind { - hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, ref inner) => { + hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, inner) => { let inner_ty = self.fcx.node_ty(inner.hir_id); let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty); @@ -150,8 +150,7 @@ typeck_results.node_substs_mut().remove(e.hir_id); } } - hir::ExprKind::Binary(ref op, ref lhs, ref rhs) - | hir::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => { + hir::ExprKind::Binary(ref op, lhs, rhs) | hir::ExprKind::AssignOp(ref op, lhs, rhs) => { let lhs_ty = self.fcx.node_ty(lhs.hir_id); let lhs_ty = self.fcx.resolve_vars_if_possible(lhs_ty); @@ -198,7 +197,7 @@ // All valid indexing looks like this; might encounter non-valid indexes at this point. let base_ty = typeck_results - .expr_ty_adjusted_opt(&base) + .expr_ty_adjusted_opt(base) .map(|t| self.fcx.resolve_vars_if_possible(t).kind()); if base_ty.is_none() { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base @@ -207,7 +206,7 @@ self.tcx().sess.delay_span_bug(e.span, &format!("bad base: `{:?}`", base)); } if let Some(ty::Ref(_, base_ty, _)) = base_ty { - let index_ty = typeck_results.expr_ty_adjusted_opt(&index).unwrap_or_else(|| { + let index_ty = typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| { // When encountering `return [0][0]` outside of a `fn` body we would attempt // to access an unexistend index. We assume that more relevant errors will // already have been emitted, so we only gate on this with an ICE if no @@ -497,6 +496,7 @@ fcx_typeck_results.generator_interior_types.clone(); } + #[instrument(skip(self, span), level = "debug")] fn visit_opaque_types(&mut self, span: Span) { let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone(); for (opaque_type_key, opaque_defn) in opaque_types { @@ -564,6 +564,7 @@ } } + #[instrument(skip(self, span), level = "debug")] fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) { // Export associated path extensions and method resolutions. if let Some(def) = @@ -579,7 +580,7 @@ let n_ty = self.fcx.node_ty(hir_id); let n_ty = self.resolve(n_ty, &span); self.write_ty_to_typeck_results(hir_id, n_ty); - debug!("node {:?} has type {:?}", hir_id, n_ty); + debug!(?n_ty); // Resolve any substitutions if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) { @@ -590,31 +591,33 @@ } } + #[instrument(skip(self, span), level = "debug")] fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) { let adjustment = self.fcx.typeck_results.borrow_mut().adjustments_mut().remove(hir_id); match adjustment { None => { - debug!("no adjustments for node {:?}", hir_id); + debug!("no adjustments for node"); } Some(adjustment) => { let resolved_adjustment = self.resolve(adjustment, &span); - debug!("adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); + debug!(?resolved_adjustment); self.typeck_results.adjustments_mut().insert(hir_id, resolved_adjustment); } } } + #[instrument(skip(self, span), level = "debug")] fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) { let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id); match adjustment { None => { - debug!("no pat_adjustments for node {:?}", hir_id); + debug!("no pat_adjustments for node"); } Some(adjustment) => { let resolved_adjustment = self.resolve(adjustment, &span); - debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); + debug!(?resolved_adjustment); self.typeck_results.pat_adjustments_mut().insert(hir_id, resolved_adjustment); } } @@ -732,6 +735,26 @@ } } +struct EraseEarlyRegions<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) { + ty.super_fold_with(self) + } else { + ty + } + } + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased } + } +} + impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx @@ -739,7 +762,13 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match self.infcx.fully_resolve(t) { - Ok(t) => self.infcx.tcx.erase_regions(t), + Ok(t) => { + // Do not anonymize late-bound regions + // (e.g. keep `for<'a>` named `for<'a>`). + // This allows NLL to generate error messages that + // refer to the higher-ranked lifetime names written by the user. + EraseEarlyRegions { tcx: self.infcx.tcx }.fold_ty(t) + } Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); self.report_type_error(t); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check_unused.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check_unused.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/check_unused.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/check_unused.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,14 +9,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let mut used_trait_imports = FxHashSet::default(); - for item_def_id in tcx.body_owners() { + for item_def_id in tcx.hir().body_owners() { let imports = tcx.used_trait_imports(item_def_id); debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); used_trait_imports.extend(imports.iter()); } let mut visitor = CheckVisitor { tcx, used_trait_imports }; - tcx.hir().krate().visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes(&mut visitor); unused_crates_lint(tcx); } @@ -26,7 +26,7 @@ if item.vis.node.is_pub() || item.span.is_dummy() { return; } - if let hir::ItemKind::Use(ref path, _) = item.kind { + if let hir::ItemKind::Use(path, _) = item.kind { self.check_import(item.item_id(), path.span); } } @@ -111,7 +111,7 @@ // Collect all the extern crates (in a reliable order). let mut crates_to_lint = vec![]; - tcx.hir().krate().visit_all_item_likes(&mut CollectExternCrateVisitor { + tcx.hir().visit_all_item_likes(&mut CollectExternCrateVisitor { crates_to_lint: &mut crates_to_lint, }); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,6 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_index::vec::IndexVec; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; use rustc_trait_selection::traits::{self, SkipLeakCheck}; @@ -10,8 +11,7 @@ use std::collections::hash_map::Entry; pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) { - let krate = tcx.hir().krate(); - krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx }); + tcx.hir().visit_all_item_likes(&mut InherentOverlapChecker { tcx }); } struct InherentOverlapChecker<'tcx> { @@ -159,14 +159,18 @@ // This is advantageous to running the algorithm over the // entire graph when there are many connected regions. + rustc_index::newtype_index! { + pub struct RegionId { + ENCODABLE = custom + } + } struct ConnectedRegion { idents: SmallVec<[Symbol; 8]>, impl_blocks: FxHashSet, } - // Highest connected region id - let mut highest_region_id = 0; + let mut connected_regions: IndexVec = Default::default(); + // Reverse map from the Symbol to the connected region id. let mut connected_region_ids = FxHashMap::default(); - let mut connected_regions = FxHashMap::default(); for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() { if impl_items.len() == 0 { @@ -174,7 +178,7 @@ } // First obtain a list of existing connected region ids let mut idents_to_add = SmallVec::<[Symbol; 8]>::new(); - let ids = impl_items + let mut ids = impl_items .in_definition_order() .filter_map(|item| { let entry = connected_region_ids.entry(item.ident.name); @@ -185,62 +189,65 @@ None } }) - .collect::>(); - match ids.len() { - 0 | 1 => { - let id_to_set = if ids.len() == 0 { - // Create a new connected region - let region = ConnectedRegion { + .collect::>(); + // Sort the id list so that the algorithm is deterministic + ids.sort_unstable(); + ids.dedup(); + let ids = ids; + match &ids[..] { + // Create a new connected region + [] => { + let id_to_set = connected_regions.next_index(); + // Update the connected region ids + for ident in &idents_to_add { + connected_region_ids.insert(*ident, id_to_set); + } + connected_regions.insert( + id_to_set, + ConnectedRegion { idents: idents_to_add, impl_blocks: std::iter::once(i).collect(), - }; - connected_regions.insert(highest_region_id, region); - (highest_region_id, highest_region_id += 1).0 - } else { - // Take the only id inside the list - let id_to_set = *ids.iter().next().unwrap(); - let region = connected_regions.get_mut(&id_to_set).unwrap(); - region.impl_blocks.insert(i); - region.idents.extend_from_slice(&idents_to_add); - id_to_set - }; - let (_id, region) = connected_regions.iter().next().unwrap(); + }, + ); + } + // Take the only id inside the list + &[id_to_set] => { + let region = connected_regions[id_to_set].as_mut().unwrap(); + region.impl_blocks.insert(i); + region.idents.extend_from_slice(&idents_to_add); // Update the connected region ids - for ident in region.idents.iter() { + for ident in &idents_to_add { connected_region_ids.insert(*ident, id_to_set); } } - _ => { - // We have multiple connected regions to merge. - // In the worst case this might add impl blocks - // one by one and can thus be O(n^2) in the size - // of the resulting final connected region, but - // this is no issue as the final step to check - // for overlaps runs in O(n^2) as well. - - // Take the smallest id from the list - let id_to_set = *ids.iter().min().unwrap(); - - // Sort the id list so that the algorithm is deterministic - let mut ids = ids.into_iter().collect::>(); - ids.sort_unstable(); - - let mut region = connected_regions.remove(&id_to_set).unwrap(); - region.idents.extend_from_slice(&idents_to_add); + // We have multiple connected regions to merge. + // In the worst case this might add impl blocks + // one by one and can thus be O(n^2) in the size + // of the resulting final connected region, but + // this is no issue as the final step to check + // for overlaps runs in O(n^2) as well. + &[id_to_set, ..] => { + let mut region = connected_regions.remove(id_to_set).unwrap(); region.impl_blocks.insert(i); + region.idents.extend_from_slice(&idents_to_add); + // Update the connected region ids + for ident in &idents_to_add { + connected_region_ids.insert(*ident, id_to_set); + } + // Remove other regions from ids. for &id in ids.iter() { if id == id_to_set { continue; } - let r = connected_regions.remove(&id).unwrap(); - // Update the connected region ids + let r = connected_regions.remove(id).unwrap(); for ident in r.idents.iter() { connected_region_ids.insert(*ident, id_to_set); } region.idents.extend_from_slice(&r.idents); region.impl_blocks.extend(r.impl_blocks); } + connected_regions.insert(id_to_set, region); } } @@ -255,16 +262,22 @@ let avg = impls.len() / connected_regions.len(); let s = connected_regions .iter() - .map(|r| r.1.impl_blocks.len() as isize - avg as isize) + .flatten() + .map(|r| r.impl_blocks.len() as isize - avg as isize) .map(|v| v.abs() as usize) .sum::(); s / connected_regions.len() }, - connected_regions.iter().map(|r| r.1.impl_blocks.len()).max().unwrap() + connected_regions + .iter() + .flatten() + .map(|r| r.impl_blocks.len()) + .max() + .unwrap() ); // List of connected regions is built. Now, run the overlap check // for each pair of impl blocks in the same connected region. - for (_id, region) in connected_regions.into_iter() { + for region in connected_regions.into_iter().flatten() { let mut impl_blocks = region.impl_blocks.into_iter().collect::>(); impl_blocks.sort_unstable(); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/inherent_impls.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/inherent_impls.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/inherent_impls.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/inherent_impls.rs 2021-11-29 19:27:11.000000000 +0000 @@ -17,9 +17,8 @@ /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { - let krate = tcx.hir().krate(); let mut collect = InherentCollect { tcx, impls_map: Default::default() }; - krate.visit_all_item_likes(&mut collect); + tcx.hir().visit_all_item_likes(&mut collect); collect.impls_map } @@ -57,7 +56,7 @@ ty::Foreign(did) => { self.check_def_id(item, did); } - ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => { + ty::Dynamic(data, ..) if data.principal_def_id().is_some() => { self.check_def_id(item, data.principal_def_id().unwrap()); } ty::Dynamic(..) => { @@ -401,7 +400,7 @@ lang: &str, ty: &str, span: Span, - assoc_items: &[hir::ImplItemRef<'_>], + assoc_items: &[hir::ImplItemRef], ) { match (lang_def_id, lang_def_id2) { (Some(lang_def_id), _) if lang_def_id == impl_def_id.to_def_id() => { @@ -411,7 +410,7 @@ // OK } _ => { - let to_implement = if assoc_items.len() == 0 { + let to_implement = if assoc_items.is_empty() { String::new() } else { let plural = assoc_items.len() > 1; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -221,7 +221,7 @@ } // check for overlap with the automatic `impl Trait for dyn Trait` - if let ty::Dynamic(ref data, ..) = trait_ref.self_ty().kind() { + if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() { // This is something like impl Trait1 for Trait2. Illegal // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/orphan.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/orphan.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/orphan.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/orphan.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ pub fn check(tcx: TyCtxt<'_>) { let mut orphan = OrphanChecker { tcx }; - tcx.hir().krate().visit_all_item_likes(&mut orphan); + tcx.hir().visit_all_item_likes(&mut orphan); } struct OrphanChecker<'tcx> { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/unsafety.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/unsafety.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/unsafety.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/coherence/unsafety.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,7 +9,7 @@ pub fn check(tcx: TyCtxt<'_>) { let mut unsafety = UnsafetyChecker { tcx }; - tcx.hir().krate().visit_all_item_likes(&mut unsafety); + tcx.hir().visit_all_item_likes(&mut unsafety); } struct UnsafetyChecker<'tcx> { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/collect/item_bounds.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/collect/item_bounds.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/collect/item_bounds.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/collect/item_bounds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ use super::ItemCtxt; -use crate::astconv::{AstConv, SizedByDefault}; +use crate::astconv::AstConv; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; @@ -17,7 +17,7 @@ fn associated_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, assoc_item_def_id: DefId, - bounds: &'tcx [hir::GenericBound<'tcx>], + ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { let item_ty = tcx.mk_projection( @@ -25,13 +25,10 @@ InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); - let bounds = >::compute_bounds( - &ItemCtxt::new(tcx, assoc_item_def_id), - item_ty, - &bounds, - SizedByDefault::Yes, - span, - ); + let icx = ItemCtxt::new(tcx, assoc_item_def_id); + let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds); + // Associated types are implicitly sized unless a `?Sized` bound is found + >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id(); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local()); @@ -59,21 +56,18 @@ fn opaque_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, opaque_def_id: DefId, - bounds: &'tcx [hir::GenericBound<'tcx>], + ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { ty::print::with_no_queries(|| { let item_ty = tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id)); - let bounds = >::compute_bounds( - &ItemCtxt::new(tcx, opaque_def_id), - item_ty, - &bounds, - SizedByDefault::Yes, - span, - ) - .predicates(tcx, item_ty); + let icx = ItemCtxt::new(tcx, opaque_def_id); + let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds); + // Opaque types are implicitly sized unless a `?Sized` bound is found + >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); + let bounds = bounds.predicates(tcx, item_ty); debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/collect/type_of.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/collect/type_of.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/collect/type_of.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/collect/type_of.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,3 @@ -use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, ErrorReported, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -7,7 +6,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, Node}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef}; +use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::Ident; @@ -313,7 +312,7 @@ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) } - TraitItemKind::Const(ref ty, body_id) => body_id + TraitItemKind::Const(ty, body_id) => body_id .and_then(|body_id| { if is_suggestable_infer_ty(ty) { Some(infer_placeholder_type( @@ -324,7 +323,7 @@ } }) .unwrap_or_else(|| icx.to_ty(ty)), - TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), + TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty), TraitItemKind::Type(_, None) => { span_bug!(item.span, "associated type missing default"); } @@ -335,14 +334,14 @@ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) } - ImplItemKind::Const(ref ty, body_id) => { + ImplItemKind::Const(ty, body_id) => { if is_suggestable_infer_ty(ty) { infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") } else { icx.to_ty(ty) } } - ImplItemKind::TyAlias(ref ty) => { + ImplItemKind::TyAlias(ty) => { if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id).to_def_id()).is_none() { check_feature_inherent_assoc_ty(tcx, item.span); } @@ -353,7 +352,7 @@ Node::Item(item) => { match item.kind { - ItemKind::Static(ref ty, .., body_id) => { + ItemKind::Static(ty, .., body_id) => { if is_suggestable_infer_ty(ty) { infer_placeholder_type( tcx, @@ -367,7 +366,7 @@ icx.to_ty(ty) } } - ItemKind::Const(ref ty, body_id) => { + ItemKind::Const(ty, body_id) => { if is_suggestable_infer_ty(ty) { infer_placeholder_type( tcx, def_id, body_id, ty.span, item.ident, "constant", @@ -376,8 +375,8 @@ icx.to_ty(ty) } } - ItemKind::TyAlias(ref self_ty, _) - | ItemKind::Impl(hir::Impl { ref self_ty, .. }) => icx.to_ty(self_ty), + ItemKind::TyAlias(self_ty, _) + | ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(self_ty), ItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) @@ -396,7 +395,7 @@ .mir_borrowck(owner.expect_local()) .concrete_opaque_types .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id()) - .map(|concrete_ty| *concrete_ty) + .copied() .unwrap_or_else(|| { tcx.sess.delay_span_bug( DUMMY_SP, @@ -447,7 +446,7 @@ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) } - ForeignItemKind::Static(ref t, _) => icx.to_ty(t), + ForeignItemKind::Static(t, _) => icx.to_ty(t), ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()), }, @@ -461,7 +460,7 @@ } }, - Node::Field(field) => icx.to_ty(&field.ty), + Node::Field(field) => icx.to_ty(field.ty), Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); @@ -539,6 +538,25 @@ } #[instrument(skip(tcx), level = "debug")] +/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions +/// laid for "higher-order pattern unification". +/// This ensures that inference is tractable. +/// In particular, definitions of opaque types can only use other generics as arguments, +/// and they cannot repeat an argument. Example: +/// +/// ```rust +/// type Foo = impl Bar; +/// +/// // Okay -- `Foo` is applied to two distinct, generic types. +/// fn a() -> Foo { .. } +/// +/// // Not okay -- `Foo` is applied to `T` twice. +/// fn b() -> Foo { .. } +/// +/// // Not okay -- `Foo` is applied to a non-generic type. +/// fn b() -> Foo { .. } +/// ``` +/// fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { use rustc_hir::{Expr, ImplItem, Item, TraitItem}; @@ -584,50 +602,8 @@ // FIXME(oli-obk): trace the actual span from inference to improve errors. let span = self.tcx.def_span(def_id); - // HACK(eddyb) this check shouldn't be needed, as `wfcheck` - // performs the same checks, in theory, but I've kept it here - // using `delay_span_bug`, just in case `wfcheck` slips up. - let opaque_generics = self.tcx.generics_of(self.def_id); - let mut used_params: FxHashSet<_> = FxHashSet::default(); - for (i, arg) in opaque_type_key.substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) => { - matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) - } - GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), - }; - - if arg_is_param { - if !used_params.insert(arg) { - // There was already an entry for `arg`, meaning a generic parameter - // was used twice. - self.tcx.sess.delay_span_bug( - span, - &format!( - "defining opaque type use restricts opaque \ - type by using the generic parameter `{}` twice", - arg, - ), - ); - } - } else { - let param = opaque_generics.param_at(i, self.tcx); - self.tcx.sess.delay_span_bug( - span, - &format!( - "defining opaque type use does not fully define opaque type: \ - generic parameter `{}` is specified as concrete {} `{}`", - param.name, - param.kind.descr(), - arg, - ), - ); - } - } - if let Some((prev_span, prev_ty)) = self.found { - if *concrete_type != prev_ty { + if *concrete_type != prev_ty && !(*concrete_type, prev_ty).references_error() { debug!(?span); // Found different concrete types for the opaque type. let mut err = self.tcx.sess.struct_span_err( @@ -691,7 +667,7 @@ debug!("find_opaque_ty_constraints: scope={:?}", scope); if scope == hir::CRATE_HIR_ID { - intravisit::walk_crate(&mut locator, tcx.hir().krate()); + tcx.hir().walk_toplevel_module(&mut locator); } else { debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope)); match tcx.hir().get(scope) { @@ -709,9 +685,9 @@ // // requires us to explicitly process `foo()` in order // to notice the defining usage of `Blah`. - Node::Item(ref it) => locator.visit_item(it), - Node::ImplItem(ref it) => locator.visit_impl_item(it), - Node::TraitItem(ref it) => locator.visit_trait_item(it), + Node::Item(it) => locator.visit_item(it), + Node::ImplItem(it) => locator.visit_impl_item(it), + Node::TraitItem(it) => locator.visit_trait_item(it), other => bug!("{:?} is not a valid scope for an opaque type item", other), } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/collect.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/collect.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/collect.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/collect.rs 2021-11-29 19:27:11.000000000 +0000 @@ -14,7 +14,7 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. -use crate::astconv::{AstConv, SizedByDefault}; +use crate::astconv::AstConv; use crate::bounds::Bounds; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::constrained_generic_params as cgp; @@ -40,13 +40,13 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness}; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::spec::{abi, SanitizerSet}; +use rustc_target::spec::{abi, PanicStrategy, SanitizerSet}; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use std::iter; @@ -199,20 +199,16 @@ let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id); let parent_node = tcx.hir().get(parent_id); - is_const_or_static = match parent_node { + is_const_or_static = matches!( + parent_node, Node::Item(&hir::Item { kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), .. - }) - | Node::TraitItem(&hir::TraitItem { + }) | Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. - }) - | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Const(..), .. - }) => true, - _ => false, - }; + }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) + ); } } @@ -450,9 +446,9 @@ let suggestions = vec![ (lt_sp, sugg), ( - span, + span.with_hi(item_segment.ident.span.lo()), format!( - "{}::{}", + "{}::", // Replace the existing lifetimes with a new named lifetime. self.tcx .replace_late_bound_regions(poly_trait_ref, |_| { @@ -465,7 +461,6 @@ )) }) .0, - item_segment.ident ), ), ]; @@ -487,14 +482,13 @@ | hir::Node::ForeignItem(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => { - err.span_suggestion( - span, + err.span_suggestion_verbose( + span.with_hi(item_segment.ident.span.lo()), "use a fully qualified path with inferred lifetimes", format!( - "{}::{}", + "{}::", // Erase named lt, we want `::C`, not `::C`. self.tcx.anonymize_late_bound_regions(poly_trait_ref).skip_binder(), - item_segment.ident ), Applicability::MaybeIncorrect, ); @@ -683,10 +677,10 @@ _ => None, }) .flat_map(|bp| { - let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) { + let bt = if is_param(self.tcx, bp.bounded_ty, param_id) { Some(ty) } else if !only_self_bounds.0 { - Some(self.to_ty(&bp.bounded_ty)) + Some(self.to_ty(bp.bounded_ty)) } else { None }; @@ -725,7 +719,7 @@ /// `ast_ty_to_ty`, because we want to avoid triggering an all-out /// conversion of the type to avoid inducing unnecessary cycles. fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty<'_>, param_id: hir::HirId) -> bool { - if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = ast_ty.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ast_ty.kind { match path.res { Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => { def_id == tcx.hir().local_def_id(param_id).to_def_id() @@ -778,7 +772,7 @@ tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); - convert_enum_variant_types(tcx, def_id.to_def_id(), &enum_definition.variants); + convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants); } hir::ItemKind::Impl { .. } => { tcx.ensure().generics_of(def_id); @@ -1155,19 +1149,11 @@ >::compute_bounds_that_match_assoc_type( &icx, self_param_ty, - &bounds, - SizedByDefault::No, - item.span, + bounds, assoc_name, ) } else { - >::compute_bounds( - &icx, - self_param_ty, - &bounds, - SizedByDefault::No, - item.span, - ) + >::compute_bounds(&icx, self_param_ty, bounds) }; let superbounds1 = superbounds1.predicates(tcx, self_param_ty); @@ -1344,25 +1330,25 @@ match node { Node::TraitItem(item) => match item.kind { hir::TraitItemKind::Fn(ref sig, _) => { - has_late_bound_regions(tcx, &item.generics, &sig.decl) + has_late_bound_regions(tcx, &item.generics, sig.decl) } _ => None, }, Node::ImplItem(item) => match item.kind { hir::ImplItemKind::Fn(ref sig, _) => { - has_late_bound_regions(tcx, &item.generics, &sig.decl) + has_late_bound_regions(tcx, &item.generics, sig.decl) } _ => None, }, Node::ForeignItem(item) => match item.kind { - hir::ForeignItemKind::Fn(ref fn_decl, _, ref generics) => { + hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => { has_late_bound_regions(tcx, generics, fn_decl) } _ => None, }, Node::Item(item) => match item.kind { hir::ItemKind::Fn(ref sig, .., ref generics, _) => { - has_late_bound_regions(tcx, generics, &sig.decl) + has_late_bound_regions(tcx, generics, sig.decl) } _ => None, }, @@ -1384,7 +1370,7 @@ } fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { - if let GenericParamKind::Const { ref ty, default: _ } = p.kind { + if let GenericParamKind::Const { ty, default: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; self.visit_ty(ty); @@ -1597,7 +1583,7 @@ let mut own_start = has_self as u32; let parent_count = parent_def_id.map_or(0, |def_id| { let generics = tcx.generics_of(def_id); - assert_eq!(has_self, false); + assert!(!has_self); parent_has_self = generics.has_self; own_start = generics.count() as u32; generics.parent_count + generics.params.len() @@ -1748,9 +1734,9 @@ } pub fn get_infer_ret_ty(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> { - if let hir::FnRetTy::Return(ref ty) = output { + if let hir::FnRetTy::Return(ty) = output { if is_suggestable_infer_ty(ty) { - return Some(&**ty); + return Some(&*ty); } } None @@ -1820,8 +1806,8 @@ hir_id, sig.header.unsafety, sig.header.abi, - &sig.decl, - &generics, + sig.decl, + generics, Some(ident.span), None, ), @@ -1839,15 +1825,13 @@ header.unsafety, header.abi, decl, - &generics, + generics, Some(ident.span), None, ), ForeignItem(&hir::ForeignItem { - kind: ForeignItemKind::Fn(ref fn_decl, _, _), - ident, - .. + kind: ForeignItemKind::Fn(fn_decl, _, _), ident, .. }) => { let abi = tcx.hir().get_foreign_abi(hir_id); compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi, ident) @@ -2052,7 +2036,7 @@ match item.kind { ItemKind::Impl(ref impl_) => { if impl_.defaultness.is_default() { - is_default_impl_trait = tcx.impl_trait_ref(def_id); + is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy); } &impl_.generics } @@ -2132,10 +2116,7 @@ // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.insert(( - trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx), - tcx.def_span(def_id), - )); + predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id))); } // Collect the region predicates that were declared inline as @@ -2154,7 +2135,7 @@ GenericParamKind::Lifetime { .. } => { param.bounds.iter().for_each(|bound| match bound { hir::GenericBound::Outlives(lt) => { - let bound = >::ast_region_to_region(&icx, <, None); + let bound = >::ast_region_to_region(&icx, lt, None); let outlives = ty::Binder::dummy(ty::OutlivesPredicate(region, bound)); predicates.insert((outlives.to_predicate(tcx), lt.span)); } @@ -2176,12 +2157,13 @@ let param_ty = ty::ParamTy::new(index, name).to_ty(tcx); index += 1; - let sized = SizedByDefault::Yes; - let bounds = >::compute_bounds( + let mut bounds = >::compute_bounds(&icx, param_ty, param.bounds); + // Params are implicitly sized unless a `?Sized` bound is found + >::add_implicitly_sized( &icx, - param_ty, - ¶m.bounds, - sized, + &mut bounds, + param.bounds, + Some((param.hir_id, ast_generics.where_clause.predicates)), param.span, ); predicates.extend(bounds.predicates(tcx, param_ty)); @@ -2199,7 +2181,7 @@ for predicate in where_clause.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { - let ty = icx.to_ty(&bound_pred.bounded_ty); + let ty = icx.to_ty(bound_pred.bounded_ty); let bound_vars = icx.tcx.late_bound_vars(bound_pred.bounded_ty.hir_id); // Keep the type around in a dummy predicate, in case of no bounds. @@ -2227,64 +2209,15 @@ } } - for bound in bound_pred.bounds.iter() { - match bound { - hir::GenericBound::Trait(poly_trait_ref, modifier) => { - let constness = match modifier { - hir::TraitBoundModifier::None => ty::BoundConstness::NotConst, - hir::TraitBoundModifier::MaybeConst => { - ty::BoundConstness::ConstIfConst - } - // We ignore `where T: ?Sized`, it is already part of - // type parameter `T`. - hir::TraitBoundModifier::Maybe => continue, - }; - - let mut bounds = Bounds::default(); - let _ = >::instantiate_poly_trait_ref( - &icx, - &poly_trait_ref.trait_ref, - poly_trait_ref.span, - constness, - ty, - &mut bounds, - false, - ); - predicates.extend(bounds.predicates(tcx, ty)); - } - - &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { - let mut bounds = Bounds::default(); - >::instantiate_lang_item_trait_ref( - &icx, - lang_item, - span, - hir_id, - args, - ty, - &mut bounds, - ); - predicates.extend(bounds.predicates(tcx, ty)); - } - - hir::GenericBound::Unsized(_) => {} - - hir::GenericBound::Outlives(lifetime) => { - let region = - >::ast_region_to_region(&icx, lifetime, None); - predicates.insert(( - ty::Binder::bind_with_vars( - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate( - ty, region, - )), - bound_vars, - ) - .to_predicate(tcx), - lifetime.span, - )); - } - } - } + let mut bounds = Bounds::default(); + >::add_bounds( + &icx, + ty, + bound_pred.bounds.iter(), + &mut bounds, + bound_vars, + ); + predicates.extend(bounds.predicates(tcx, ty)); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -2296,8 +2229,10 @@ } _ => bug!(), }; - let pred = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) - .to_predicate(icx.tcx); + let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives( + ty::OutlivesPredicate(r1, r2), + )) + .to_predicate(icx.tcx); (pred, span) })) @@ -2362,7 +2297,8 @@ assert_eq!(uv.promoted, None); let span = self.tcx.hir().span(c.hir_id); self.preds.insert(( - ty::PredicateKind::ConstEvaluatable(uv.shrink()).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink())) + .to_predicate(self.tcx), span, )); } @@ -2466,7 +2402,7 @@ } else { if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() { // In `generics_of` we set the generics' parent to be our parent's parent which means that // we lose out on the predicates of our actual parent if we dont return those predicates here. // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) @@ -2498,45 +2434,14 @@ param_ty: Ty<'tcx>, bound: &'tcx hir::GenericBound<'tcx>, ) -> Vec<(ty::Predicate<'tcx>, Span)> { - match *bound { - hir::GenericBound::Trait(ref tr, modifier) => { - let constness = match modifier { - hir::TraitBoundModifier::Maybe => return vec![], - hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst, - hir::TraitBoundModifier::None => ty::BoundConstness::NotConst, - }; - - let mut bounds = Bounds::default(); - let _ = astconv.instantiate_poly_trait_ref( - &tr.trait_ref, - tr.span, - constness, - param_ty, - &mut bounds, - false, - ); - bounds.predicates(astconv.tcx(), param_ty) - } - hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { - let mut bounds = Bounds::default(); - astconv.instantiate_lang_item_trait_ref( - lang_item, - span, - hir_id, - args, - param_ty, - &mut bounds, - ); - bounds.predicates(astconv.tcx(), param_ty) - } - hir::GenericBound::Unsized(_) => vec![], - hir::GenericBound::Outlives(ref lifetime) => { - let region = astconv.ast_region_to_region(lifetime, None); - let pred = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(param_ty, region)) - .to_predicate(astconv.tcx()); - vec![(pred, lifetime.span)] - } - } + let mut bounds = Bounds::default(); + astconv.add_bounds( + param_ty, + std::array::IntoIter::new([bound]), + &mut bounds, + ty::List::empty(), + ); + bounds.predicates(astconv.tcx(), param_ty) } fn compute_sig_of_foreign_fn_decl<'tcx>( @@ -2590,10 +2495,10 @@ } }; for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { - check(&input, ty) + check(input, ty) } if let hir::FnRetTy::Return(ref ty) = decl.output { - check(&ty, fty.output().skip_binder()) + check(ty, fty.output().skip_binder()) } } @@ -2648,7 +2553,7 @@ let msg = "malformed `target_feature` attribute input"; let code = "enable = \"..\"".to_owned(); tcx.sess - .struct_span_err(span, &msg) + .struct_span_err(span, msg) .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) .emit(); }; @@ -2770,6 +2675,13 @@ codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } + // With -Z panic-in-drop=abort, drop_in_place never unwinds. + if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort { + if Some(id) == tcx.lang_items().drop_in_place_fn() { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; + } + } + let supported_target_features = tcx.supported_target_features(LOCAL_CRATE); let mut inline_span = None; @@ -2860,10 +2772,19 @@ } else if attr.has_name(sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if attr.has_name(sym::track_caller) { - if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust { + if !tcx.is_closure(id) && tcx.fn_sig(id).abi() != abi::Abi::Rust { struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") .emit(); } + if tcx.is_closure(id) && !tcx.features().closure_track_caller { + feature_err( + &tcx.sess.parse_sess, + sym::closure_track_caller, + attr.span, + "`#[track_caller]` on closures is currently unstable", + ) + .emit(); + } codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } else if attr.has_name(sym::export_name) { if let Some(s) = attr.value_str() { @@ -2917,7 +2838,7 @@ tcx, id, attr, - &supported_target_features, + supported_target_features, &mut codegen_fn_attrs.target_features, ); } else if attr.has_name(sym::linkage) { @@ -2940,6 +2861,14 @@ } else if attr.has_name(sym::link_name) { codegen_fn_attrs.link_name = attr.value_str(); } else if attr.has_name(sym::link_ordinal) { + if link_ordinal_span.is_some() { + tcx.sess + .struct_span_err( + attr.span, + "multiple `link_ordinal` attributes on a single definition", + ) + .emit(); + } link_ordinal_span = Some(attr.span); if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { codegen_fn_attrs.link_ordinal = ordinal; @@ -3184,7 +3113,7 @@ codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } let check_name = |attr: &Attribute, sym| attr.has_name(sym); - if let Some(name) = weak_lang_items::link_name(check_name, &attrs) { + if let Some(name) = weak_lang_items::link_name(check_name, attrs) { codegen_fn_attrs.export_name = Some(name); codegen_fn_attrs.link_name = Some(name); } @@ -3235,22 +3164,41 @@ false } -fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { +fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { use rustc_ast::{Lit, LitIntType, LitKind}; let meta_item_list = attr.meta_item_list(); let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref); let sole_meta_list = match meta_item_list { Some([item]) => item.literal(), + Some(_) => { + tcx.sess + .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`") + .note("the attribute requires exactly one argument") + .emit(); + return None; + } _ => None, }; if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list { - if *ordinal <= usize::MAX as u128 { - Some(*ordinal as usize) + // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, + // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined + // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information + // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t. + // + // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this: + // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies + // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library + // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import + // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet + // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment + // about LINK.EXE failing.) + if *ordinal <= u16::MAX as u128 { + Some(*ordinal as u16) } else { let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal); tcx.sess .struct_span_err(attr.span, &msg) - .note("the value may not exceed `usize::MAX`") + .note("the value may not exceed `u16::MAX`") .emit(); None } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/constrained_generic_params.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/constrained_generic_params.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/constrained_generic_params.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/constrained_generic_params.rs 2021-11-29 19:27:11.000000000 +0000 @@ -206,7 +206,7 @@ // Then the projection only applies if `T` is known, but it still // does not determine `U`. let inputs = parameters_for(tcx, &projection.projection_ty, true); - let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); + let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); if !relies_only_on_inputs { continue; } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/errors.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/errors.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/errors.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/errors.rs 2021-11-29 19:27:11.000000000 +0000 @@ -122,14 +122,6 @@ } #[derive(SessionDiagnostic)] -#[error = "E0439"] -pub struct SimdShuffleMissingLength { - #[message = "invalid `simd_shuffle`, needs length: `{name}`"] - pub span: Span, - pub name: Symbol, -} - -#[derive(SessionDiagnostic)] #[error = "E0436"] pub struct FunctionalRecordUpdateOnNonStruct { #[message = "functional record update syntax requires a struct"] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/expr_use_visitor.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/expr_use_visitor.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/expr_use_visitor.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/expr_use_visitor.rs 2021-11-29 19:27:11.000000000 +0000 @@ -124,12 +124,12 @@ #[instrument(skip(self), level = "debug")] pub fn consume_body(&mut self, body: &hir::Body<'_>) { for param in body.params { - let param_ty = return_if_err!(self.mc.pat_ty_adjusted(¶m.pat)); + let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat)); debug!("consume_body: param_ty = {:?}", param_ty); let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty); - self.walk_irrefutable_pat(¶m_place, ¶m.pat); + self.walk_irrefutable_pat(¶m_place, param.pat); } self.consume_expr(&body.value); @@ -145,7 +145,7 @@ fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) { for expr in exprs { - self.consume_expr(&expr); + self.consume_expr(expr); } } @@ -184,57 +184,57 @@ match expr.kind { hir::ExprKind::Path(_) => {} - hir::ExprKind::Type(ref subexpr, _) => self.walk_expr(subexpr), + hir::ExprKind::Type(subexpr, _) => self.walk_expr(subexpr), - hir::ExprKind::Unary(hir::UnOp::Deref, ref base) => { + hir::ExprKind::Unary(hir::UnOp::Deref, base) => { // *base self.select_from_expr(base); } - hir::ExprKind::Field(ref base, _) => { + hir::ExprKind::Field(base, _) => { // base.f self.select_from_expr(base); } - hir::ExprKind::Index(ref lhs, ref rhs) => { + hir::ExprKind::Index(lhs, rhs) => { // lhs[rhs] self.select_from_expr(lhs); self.consume_expr(rhs); } - hir::ExprKind::Call(ref callee, ref args) => { + hir::ExprKind::Call(callee, args) => { // callee(args) self.consume_expr(callee); self.consume_exprs(args); } - hir::ExprKind::MethodCall(.., ref args, _) => { + hir::ExprKind::MethodCall(.., args, _) => { // callee.m(args) self.consume_exprs(args); } - hir::ExprKind::Struct(_, ref fields, ref opt_with) => { + hir::ExprKind::Struct(_, fields, ref opt_with) => { self.walk_struct_expr(fields, opt_with); } - hir::ExprKind::Tup(ref exprs) => { + hir::ExprKind::Tup(exprs) => { self.consume_exprs(exprs); } hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => { - self.consume_expr(&cond_expr); - self.consume_expr(&then_expr); + self.consume_expr(cond_expr); + self.consume_expr(then_expr); if let Some(ref else_expr) = *opt_else_expr { - self.consume_expr(&else_expr); + self.consume_expr(else_expr); } } - hir::ExprKind::Let(ref pat, ref expr, _) => { - self.walk_local(expr, pat, |t| t.borrow_expr(&expr, ty::ImmBorrow)); + hir::ExprKind::Let(pat, ref expr, _) => { + self.walk_local(expr, pat, |t| t.borrow_expr(expr, ty::ImmBorrow)); } hir::ExprKind::Match(ref discr, arms, _) => { - let discr_place = return_if_err!(self.mc.cat_expr(&discr)); + let discr_place = return_if_err!(self.mc.cat_expr(discr)); // Matching should not always be considered a use of the place, hence // discr does not necessarily need to be borrowed. @@ -243,7 +243,7 @@ let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; let mut needs_to_be_read = false; for arm in arms.iter() { - return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |place, pat| { + return_if_err!(mc.cat_pattern(discr_place.clone(), arm.pat, |place, pat| { match &pat.kind { PatKind::Binding(.., opt_sub_pat) => { // If the opt_sub_pat is None, than the binding does not count as @@ -303,7 +303,7 @@ } if needs_to_be_read { - self.borrow_expr(&discr, ty::ImmBorrow); + self.borrow_expr(discr, ty::ImmBorrow); } else { let closure_def_id = match discr_place.place.base { PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), @@ -318,7 +318,7 @@ // We always want to walk the discriminant. We want to make sure, for instance, // that the discriminant has been initialized. - self.walk_expr(&discr); + self.walk_expr(discr); } // treatment of the discriminant is handled while walking the arms. @@ -327,7 +327,7 @@ } } - hir::ExprKind::Array(ref exprs) => { + hir::ExprKind::Array(exprs) => { self.consume_exprs(exprs); } @@ -336,10 +336,10 @@ // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: let bk = ty::BorrowKind::from_mutbl(m); - self.borrow_expr(&base, bk); + self.borrow_expr(base, bk); } - hir::ExprKind::InlineAsm(ref asm) => { + hir::ExprKind::InlineAsm(asm) => { for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } @@ -360,7 +360,7 @@ } } - hir::ExprKind::LlvmInlineAsm(ref ia) => { + hir::ExprKind::LlvmInlineAsm(ia) => { for (o, output) in iter::zip(&ia.inner.outputs, ia.outputs_exprs) { if o.is_indirect { self.consume_expr(output); @@ -368,7 +368,7 @@ self.mutate_expr(output); } } - self.consume_exprs(&ia.inputs_exprs); + self.consume_exprs(ia.inputs_exprs); } hir::ExprKind::Continue(..) @@ -376,43 +376,43 @@ | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err => {} - hir::ExprKind::Loop(ref blk, ..) => { + hir::ExprKind::Loop(blk, ..) => { self.walk_block(blk); } - hir::ExprKind::Unary(_, ref lhs) => { + hir::ExprKind::Unary(_, lhs) => { self.consume_expr(lhs); } - hir::ExprKind::Binary(_, ref lhs, ref rhs) => { + hir::ExprKind::Binary(_, lhs, rhs) => { self.consume_expr(lhs); self.consume_expr(rhs); } - hir::ExprKind::Block(ref blk, _) => { + hir::ExprKind::Block(blk, _) => { self.walk_block(blk); } hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => { - if let Some(ref expr) = *opt_expr { + if let Some(expr) = *opt_expr { self.consume_expr(expr); } } - hir::ExprKind::Assign(ref lhs, ref rhs, _) => { + hir::ExprKind::Assign(lhs, rhs, _) => { self.mutate_expr(lhs); self.consume_expr(rhs); } - hir::ExprKind::Cast(ref base, _) => { + hir::ExprKind::Cast(base, _) => { self.consume_expr(base); } - hir::ExprKind::DropTemps(ref expr) => { + hir::ExprKind::DropTemps(expr) => { self.consume_expr(expr); } - hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { + hir::ExprKind::AssignOp(_, lhs, rhs) => { if self.mc.typeck_results.is_method_call(expr) { self.consume_expr(lhs); } else { @@ -421,7 +421,7 @@ self.consume_expr(rhs); } - hir::ExprKind::Repeat(ref base, _) => { + hir::ExprKind::Repeat(base, _) => { self.consume_expr(base); } @@ -433,7 +433,7 @@ self.consume_expr(base); } - hir::ExprKind::Yield(ref value, _) => { + hir::ExprKind::Yield(value, _) => { self.consume_expr(value); } } @@ -441,7 +441,7 @@ fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) { match stmt.kind { - hir::StmtKind::Local(hir::Local { pat, init: Some(ref expr), .. }) => { + hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }) => { self.walk_local(expr, pat, |_| {}); } @@ -453,7 +453,7 @@ } hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { - self.consume_expr(&expr); + self.consume_expr(expr); } } } @@ -462,8 +462,8 @@ where F: FnMut(&mut Self), { - self.walk_expr(&expr); - let expr_place = return_if_err!(self.mc.cat_expr(&expr)); + self.walk_expr(expr); + let expr_place = return_if_err!(self.mc.cat_expr(expr)); f(self); self.walk_irrefutable_pat(&expr_place, &pat); } @@ -478,7 +478,7 @@ } if let Some(ref tail_expr) = blk.expr { - self.consume_expr(&tail_expr); + self.consume_expr(tail_expr); } } @@ -489,17 +489,17 @@ ) { // Consume the expressions supplying values for each field. for field in fields { - self.consume_expr(&field.expr); + self.consume_expr(field.expr); } let with_expr = match *opt_with { - Some(ref w) => &**w, + Some(w) => &*w, None => { return; } }; - let with_place = return_if_err!(self.mc.cat_expr(&with_expr)); + let with_place = return_if_err!(self.mc.cat_expr(with_expr)); // Select just those fields of the `with` // expression that will actually be used @@ -569,7 +569,7 @@ } } place_with_id = - return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, &adjustment)); + return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, adjustment)); } } @@ -615,15 +615,15 @@ FakeReadCause::ForMatchedPlace(closure_def_id), discr_place.hir_id, ); - self.walk_pat(discr_place, &arm.pat); + self.walk_pat(discr_place, arm.pat); - if let Some(hir::Guard::If(ref e)) = arm.guard { + if let Some(hir::Guard::If(e)) = arm.guard { self.consume_expr(e) } else if let Some(hir::Guard::IfLet(_, ref e)) = arm.guard { self.consume_expr(e) } - self.consume_expr(&arm.body); + self.consume_expr(arm.body); } /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or @@ -836,7 +836,7 @@ ) { debug!("delegate_consume(place_with_id={:?})", place_with_id); - let mode = copy_or_move(&mc, place_with_id); + let mode = copy_or_move(mc, place_with_id); match mode { ConsumeMode::Move => delegate.consume(place_with_id, diag_expr_id), diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/hir_wf_check.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/hir_wf_check.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/hir_wf_check.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/hir_wf_check.rs 2021-11-29 19:27:11.000000000 +0000 @@ -83,7 +83,8 @@ traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(tcx_ty.into()).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())) + .to_predicate(self.tcx), ), ); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs 2021-11-29 19:27:11.000000000 +0000 @@ -74,7 +74,7 @@ use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; -use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::{self, translate_substs, wf}; @@ -294,13 +294,27 @@ span: Span, ) { let tcx = infcx.tcx; - let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs); + let impl1_predicates: Vec<_> = traits::elaborate_predicates( + tcx, + tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(), + ) + .map(|obligation| obligation.predicate) + .collect(); + let mut impl2_predicates = if impl2_node.is_from_trait() { // Always applicable traits have to be always applicable without any // assumptions. - InstantiatedPredicates::empty() + Vec::new() } else { - tcx.predicates_of(impl2_node.def_id()).instantiate(tcx, impl2_substs) + traits::elaborate_predicates( + tcx, + tcx.predicates_of(impl2_node.def_id()) + .instantiate(tcx, impl2_substs) + .predicates + .into_iter(), + ) + .map(|obligation| obligation.predicate) + .collect() }; debug!( "check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)", @@ -322,13 +336,12 @@ // which is sound because we forbid impls like the following // // impl AlwaysApplicable for D { } - let always_applicable_traits = - impl1_predicates.predicates.iter().copied().filter(|&predicate| { - matches!( - trait_predicate_kind(tcx, predicate), - Some(TraitSpecializationKind::AlwaysApplicable) - ) - }); + let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| { + matches!( + trait_predicate_kind(tcx, predicate), + Some(TraitSpecializationKind::AlwaysApplicable) + ) + }); // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs { @@ -340,18 +353,19 @@ arg, span, ) { - impl2_predicates - .predicates - .extend(obligations.into_iter().map(|obligation| obligation.predicate)) + impl2_predicates.extend( + traits::elaborate_obligations(tcx, obligations) + .map(|obligation| obligation.predicate), + ) } } - impl2_predicates.predicates.extend( + impl2_predicates.extend( traits::elaborate_predicates(tcx, always_applicable_traits) .map(|obligation| obligation.predicate), ); - for predicate in impl1_predicates.predicates { - if !impl2_predicates.predicates.contains(&predicate) { + for predicate in impl1_predicates { + if !impl2_predicates.contains(&predicate) { check_specialization_on(tcx, predicate, span) } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/impl_wf_check.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/impl_wf_check.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/impl_wf_check.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/impl_wf_check.rs 2021-11-29 19:27:11.000000000 +0000 @@ -58,9 +58,7 @@ // We will tag this as part of the WF check -- logically, it is, // but it's one that we must perform earlier than the rest of // WfCheck. - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_impl_wf(module); - } + tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)) } fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { @@ -99,7 +97,7 @@ fn enforce_impl_params_are_constrained( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, - impl_item_refs: &[hir::ImplItemRef<'_>], + impl_item_refs: &[hir::ImplItemRef], ) { // Every lifetime used in an associated type must be constrained. let impl_self_ty = tcx.type_of(impl_def_id); @@ -230,7 +228,7 @@ } /// Enforce that we do not have two items in an impl with the same name. -fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplItemRef<'_>]) { +fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplItemRef]) { let mut seen_type_items = FxHashMap::default(); let mut seen_value_items = FxHashMap::default(); for impl_item_ref in impl_item_refs { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -56,7 +56,6 @@ */ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![cfg_attr(bootstrap, feature(bindings_after_at))] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] @@ -64,12 +63,12 @@ #![feature(in_band_lifetimes)] #![feature(is_sorted)] #![feature(iter_zip)] +#![feature(min_specialization)] #![feature(nll)] #![feature(try_blocks)] #![feature(never_type)] #![feature(slice_partition_dedup)] #![feature(control_flow_enum)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard #![recursion_limit = "256"] #[macro_use] @@ -109,6 +108,7 @@ use rustc_session::config::EntryFnType; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, @@ -145,7 +145,7 @@ tcx.infer_ctxt().enter(|ref infcx| { let param_env = ty::ParamEnv::empty(); let mut fulfill_cx = >::new(infcx.tcx); - match infcx.at(&cause, param_env).eq(expected, actual) { + match infcx.at(cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, .. }) => { fulfill_cx.register_predicate_obligations(infcx, obligations); } @@ -189,9 +189,11 @@ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { - let generics_param_span = - if !generics.params.is_empty() { Some(generics.span) } else { None }; - generics_param_span + if !generics.params.is_empty() { + Some(generics.span) + } else { + None + } } _ => { span_bug!(tcx.def_span(def_id), "main has a non-function type"); @@ -328,7 +330,26 @@ ObligationCauseCode::MainFunctionType, ); let mut fulfillment_cx = traits::FulfillmentContext::new(); - fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause); + // normalize any potential projections in the return type, then add + // any possible obligations to the fulfillment context. + // HACK(ThePuzzlemaker) this feels symptomatic of a problem within + // checking trait fulfillment, not this here. I'm not sure why it + // works in the example in `fn test()` given in #88609? This also + // probably isn't the best way to do this. + let InferOk { value: norm_return_ty, obligations } = infcx + .partially_normalize_associated_types_in( + cause.clone(), + ty::ParamEnv::empty(), + return_ty, + ); + fulfillment_cx.register_predicate_obligations(&infcx, obligations); + fulfillment_cx.register_bound( + &infcx, + ty::ParamEnv::empty(), + norm_return_ty, + term_id, + cause, + ); if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { infcx.report_fulfillment_errors(&err, None, false); error = true; @@ -475,9 +496,7 @@ // FIXME(matthewjasper) We shouldn't need to use `track_errors`. tcx.sess.track_errors(|| { tcx.sess.time("type_collecting", || { - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().collect_mod_item_types(module); - } + tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module)) }); })?; @@ -507,9 +526,7 @@ // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync. tcx.sess.time("item_types_checking", || { - for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_item_types(module); - } + tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(())); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/mem_categorization.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/mem_categorization.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/mem_categorization.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/mem_categorization.rs 2021-11-29 19:27:11.000000000 +0000 @@ -307,13 +307,13 @@ if self.typeck_results.is_method_call(expr) { self.cat_overloaded_place(expr, e_base) } else { - let base = self.cat_expr(&e_base)?; + let base = self.cat_expr(e_base)?; self.cat_deref(expr, base) } } hir::ExprKind::Field(ref base, _) => { - let base = self.cat_expr(&base)?; + let base = self.cat_expr(base)?; debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base); let field_idx = self @@ -340,7 +340,7 @@ // dereferencing. self.cat_overloaded_place(expr, base) } else { - let base = self.cat_expr(&base)?; + let base = self.cat_expr(base)?; Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index)) } } @@ -350,7 +350,7 @@ self.cat_res(expr.hir_id, expr.span, expr_ty, res) } - hir::ExprKind::Type(ref e, _) => self.cat_expr(&e), + hir::ExprKind::Type(ref e, _) => self.cat_expr(e), hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) @@ -674,31 +674,31 @@ op(&place_with_id, pat); match pat.kind { - PatKind::Tuple(ref subpats, dots_pos) => { + PatKind::Tuple(subpats, dots_pos) => { // (p1, ..., pN) let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?; for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { - let subpat_ty = self.pat_ty_adjusted(&subpat)?; + let subpat_ty = self.pat_ty_adjusted(subpat)?; let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0)); let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); - self.cat_pattern_(sub_place, &subpat, op)?; + self.cat_pattern_(sub_place, subpat, op)?; } } - PatKind::TupleStruct(ref qpath, ref subpats, dots_pos) => { + PatKind::TupleStruct(ref qpath, subpats, dots_pos) => { // S(p1, ..., pN) let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; let total_fields = self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?; for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { - let subpat_ty = self.pat_ty_adjusted(&subpat)?; + let subpat_ty = self.pat_ty_adjusted(subpat)?; let projection_kind = ProjectionKind::Field(i as u32, variant_index); let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); - self.cat_pattern_(sub_place, &subpat, op)?; + self.cat_pattern_(sub_place, subpat, op)?; } } @@ -708,7 +708,7 @@ let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; for fp in field_pats { - let field_ty = self.pat_ty_adjusted(&fp.pat)?; + let field_ty = self.pat_ty_adjusted(fp.pat)?; let field_index = self .typeck_results .field_indices() @@ -722,18 +722,18 @@ field_ty, ProjectionKind::Field(field_index as u32, variant_index), ); - self.cat_pattern_(field_place, &fp.pat, op)?; + self.cat_pattern_(field_place, fp.pat, op)?; } } PatKind::Or(pats) => { for pat in pats { - self.cat_pattern_(place_with_id.clone(), &pat, op)?; + self.cat_pattern_(place_with_id.clone(), pat, op)?; } } PatKind::Binding(.., Some(ref subpat)) => { - self.cat_pattern_(place_with_id, &subpat, op)?; + self.cat_pattern_(place_with_id, subpat, op)?; } PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => { @@ -741,7 +741,7 @@ // PatKind::Ref since that information is already contained // in the type. let subplace = self.cat_deref(pat, place_with_id)?; - self.cat_pattern_(subplace, &subpat, op)?; + self.cat_pattern_(subplace, subpat, op)?; } PatKind::Slice(before, ref slice, after) => { @@ -759,20 +759,20 @@ ProjectionKind::Index, ); for before_pat in before { - self.cat_pattern_(elt_place.clone(), &before_pat, op)?; + self.cat_pattern_(elt_place.clone(), before_pat, op)?; } if let Some(ref slice_pat) = *slice { - let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?; + let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?; let slice_place = self.cat_projection( pat, place_with_id, slice_pat_ty, ProjectionKind::Subslice, ); - self.cat_pattern_(slice_place, &slice_pat, op)?; + self.cat_pattern_(slice_place, slice_pat, op)?; } for after_pat in after { - self.cat_pattern_(elt_place.clone(), &after_pat, op)?; + self.cat_pattern_(elt_place.clone(), after_pat, op)?; } } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/explicit.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/explicit.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/explicit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/explicit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -30,20 +30,20 @@ // process predicates and convert to `RequiredPredicates` entry, see below for &(predicate, span) in predicates.predicates { match predicate.kind().skip_binder() { - ty::PredicateKind::TypeOutlives(OutlivesPredicate(ref ty, ref reg)) => { + ty::PredicateKind::TypeOutlives(OutlivesPredicate(ty, reg)) => { insert_outlives_predicate( tcx, - (*ty).into(), + ty.into(), reg, span, &mut required_predicates, ) } - ty::PredicateKind::RegionOutlives(OutlivesPredicate(ref reg1, ref reg2)) => { + ty::PredicateKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => { insert_outlives_predicate( tcx, - (*reg1).into(), + reg1.into(), reg2, span, &mut required_predicates, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/implicit_infer.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/implicit_infer.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/implicit_infer.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/implicit_infer.rs 2021-11-29 19:27:11.000000000 +0000 @@ -37,7 +37,7 @@ }; // Visit all the crates and infer predicates - tcx.hir().krate().visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes(&mut visitor); } global_inferred_outlives diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/mod.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/mod.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -9,6 +9,7 @@ mod explicit; mod implicit_infer; +crate mod outlives_bounds; /// Code to write unit test for outlives. pub mod test; mod utils; @@ -22,7 +23,7 @@ if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() { - if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) { + if tcx.hir().opt_const_param_default_param_hir_id(id).is_some() { // In `generics_of` we set the generics' parent to be our parent's parent which means that // we lose out on the predicates of our actual parent if we dont return those predicates here. // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) @@ -104,13 +105,15 @@ |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2)) - .to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(ty1, region2), + )) + .to_predicate(tcx), span, )), GenericArgKind::Lifetime(region1) => Some(( - ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( - region1, region2, + ty::Binder::dummy(ty::PredicateKind::RegionOutlives( + ty::OutlivesPredicate(region1, region2), )) .to_predicate(tcx), span, diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/outlives_bounds.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/outlives_bounds.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/outlives_bounds.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/outlives_bounds.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,95 @@ +use rustc_hir as hir; +use rustc_infer::traits::TraitEngineExt as _; +use rustc_middle::ty::{self, Ty}; +use rustc_span::source_map::Span; +use rustc_trait_selection::infer::canonical::OriginalQueryValues; +use rustc_trait_selection::infer::InferCtxt; +use rustc_trait_selection::traits::query::NoSolution; +use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine}; + +pub use rustc_middle::traits::query::OutlivesBound; + +pub trait InferCtxtExt<'tcx> { + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + span: Span, + ) -> Vec>; +} + +impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { + /// Implied bounds are region relationships that we deduce + /// automatically. The idea is that (e.g.) a caller must check that a + /// function's argument types are well-formed immediately before + /// calling that fn, and hence the *callee* can assume that its + /// argument types are well-formed. This may imply certain relationships + /// between generic parameters. For example: + /// + /// fn foo<'a,T>(x: &'a T) + /// + /// can only be called with a `'a` and `T` such that `&'a T` is WF. + /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. + /// + /// # Parameters + /// + /// - `param_env`, the where-clauses in scope + /// - `body_id`, the body-id to use when normalizing assoc types. + /// Note that this may cause outlives obligations to be injected + /// into the inference context with this body-id. + /// - `ty`, the type that we are supposed to assume is WF. + /// - `span`, a span to use when normalizing, hopefully not important, + /// might be useful if a `bug!` occurs. + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + span: Span, + ) -> Vec> { + debug!("implied_outlives_bounds(ty = {:?})", ty); + + let mut orig_values = OriginalQueryValues::default(); + let key = self.canonicalize_query(param_env.and(ty), &mut orig_values); + let result = match self.tcx.implied_outlives_bounds(key) { + Ok(r) => r, + Err(NoSolution) => { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve all obligations", + ); + return vec![]; + } + }; + assert!(result.value.is_proven()); + + let result = self.instantiate_query_response_and_region_obligations( + &ObligationCause::misc(span, body_id), + param_env, + &orig_values, + result, + ); + debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); + let result = match result { + Ok(v) => v, + Err(_) => { + self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate"); + return vec![]; + } + }; + + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let mut fulfill_cx = FulfillmentContext::new(); + fulfill_cx.register_predicate_obligations(self, result.obligations); + if fulfill_cx.select_all_or_error(self).is_err() { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve obligations from instantiation", + ); + } + + result.value + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/test.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/test.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ use rustc_span::symbol::sym; pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { - tcx.hir().krate().visit_all_item_likes(&mut OutlivesTest { tcx }); + tcx.hir().visit_all_item_likes(&mut OutlivesTest { tcx }); } struct OutlivesTest<'tcx> { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/utils.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/utils.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/utils.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/outlives/utils.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -use rustc_middle::ty::outlives::Component; +use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, Region, RegionKind, Ty, TyCtxt}; use rustc_span::Span; @@ -35,7 +35,7 @@ // Or if within `struct Foo` you had `T = Vec`, then // we would want to add `U: 'outlived_region` let mut components = smallvec![]; - tcx.push_outlives_components(ty, &mut components); + push_outlives_components(tcx, ty, &mut components); for component in components { match component { Component::Region(r) => { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ use crate::structured_errors::StructuredDiagnostic; use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; +use rustc_middle::hir::map::fn_sig; use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath; use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::Session; @@ -136,10 +137,7 @@ AngleBrackets::Missing => 0, // Only lifetime arguments can be implied AngleBrackets::Implied => self.gen_args.args.len(), - AngleBrackets::Available => self.gen_args.args.iter().fold(0, |acc, arg| match arg { - hir::GenericArg::Lifetime(_) => acc + 1, - _ => acc, - }), + AngleBrackets::Available => self.gen_args.num_lifetime_params(), } } @@ -148,10 +146,7 @@ AngleBrackets::Missing => 0, // Only lifetime arguments can be implied AngleBrackets::Implied => 0, - AngleBrackets::Available => self.gen_args.args.iter().fold(0, |acc, arg| match arg { - hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => acc + 1, - _ => acc, - }), + AngleBrackets::Available => self.gen_args.num_generic_params(), } } @@ -298,12 +293,30 @@ &self, num_params_to_take: usize, ) -> String { + let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(fn_sig); + let is_used_in_input = |def_id| { + fn_sig.map_or(false, |fn_sig| { + fn_sig.decl.inputs.iter().any(|ty| match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::Def(_, id), .. }, + )) if *id == def_id => true, + _ => false, + }) + }) + }; self.gen_params .params .iter() .skip(self.params_offset + self.num_provided_type_or_const_args()) .take(num_params_to_take) - .map(|param| param.name.to_string()) + .map(|param| match param.kind { + // This is being infered from the item's inputs, no need to set it. + ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => { + "_".to_string() + } + _ => param.name.to_string(), + }) .collect::>() .join(", ") } @@ -651,7 +664,9 @@ let mut found_redundant = false; for arg in self.gen_args.args { match arg { - hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => { + hir::GenericArg::Type(_) + | hir::GenericArg::Const(_) + | hir::GenericArg::Infer(_) => { gen_arg_spans.push(arg.span()); if gen_arg_spans.len() > self.num_expected_type_or_const_args() { found_redundant = true; @@ -716,7 +731,11 @@ /// Builds the `type defined here` message. fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) { let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { - def_span.into() + if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() { + def_span.into() + } else { + return; + } } else { return; }; diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/constraints.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/constraints.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/constraints.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/constraints.rs 2021-11-29 19:27:11.000000000 +0000 @@ -62,7 +62,7 @@ constraints: Vec::new(), }; - tcx.hir().krate().visit_all_item_likes(&mut constraint_cx); + tcx.hir().visit_all_item_likes(&mut constraint_cx); constraint_cx } @@ -293,7 +293,7 @@ self.add_constraints_from_invariant_substs(current, substs, variance); } - ty::Dynamic(ref data, r) => { + ty::Dynamic(data, r) => { // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); self.add_constraints_from_region(current, r, contra); diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/terms.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/terms.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/terms.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/terms.rs 2021-11-29 19:27:11.000000000 +0000 @@ -79,7 +79,7 @@ // // - https://rustc-dev-guide.rust-lang.org/query.html // - https://rustc-dev-guide.rust-lang.org/variance.html - tcx.hir().krate().visit_all_item_likes(&mut terms_cx); + tcx.hir().visit_all_item_likes(&mut terms_cx); terms_cx } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/test.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/test.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_typeck/src/variance/test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,7 +5,7 @@ use rustc_span::symbol::sym; pub fn test_variance(tcx: TyCtxt<'_>) { - tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx }); + tcx.hir().visit_all_item_likes(&mut VarianceTest { tcx }); } struct VarianceTest<'tcx> { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_type_ir/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_type_ir/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_type_ir/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_type_ir/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_type_ir" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_type_ir/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_type_ir/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_type_ir/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_type_ir/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -363,10 +363,11 @@ #[derive(Clone, Copy, PartialEq, Eq)] pub struct FloatVarValue(pub FloatTy); -/// A **ty**pe **v**ariable **ID**. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct TyVid { - pub index: u32, +rustc_index::newtype_index! { + /// A **ty**pe **v**ariable **ID**. + pub struct TyVid { + DEBUG_FORMAT = "_#{}t" + } } /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. @@ -422,10 +423,10 @@ impl UnifyKey for TyVid { type Value = (); fn index(&self) -> u32 { - self.index + self.as_u32() } fn from_index(i: u32) -> TyVid { - TyVid { index: i } + TyVid::from_u32(i) } fn tag() -> &'static str { "TyVid" @@ -436,6 +437,7 @@ impl UnifyKey for IntVid { type Value = Option; + #[inline] // make this function eligible for inlining - it is quite hot. fn index(&self) -> u32 { self.index } @@ -558,7 +560,7 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { use InferTy::*; match self { - TyVar(v) => v.index.hash_stable(ctx, hasher), + TyVar(v) => v.as_u32().hash_stable(ctx, hasher), IntVar(v) => v.index.hash_stable(ctx, hasher), FloatVar(v) => v.index.hash_stable(ctx, hasher), FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher), @@ -587,12 +589,6 @@ } } -impl fmt::Debug for TyVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}t", self.index) - } -} - impl fmt::Debug for IntVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "_#{}i", self.index) diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/Cargo.toml rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -1,7 +1,7 @@ [package] name = "rustc_ty_utils" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] tracing = "0.1" diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/src/instance.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/src/instance.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/src/instance.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/src/instance.rs 2021-11-29 19:27:11.000000000 +0000 @@ -386,7 +386,8 @@ | traits::ImplSource::TraitAlias(..) | traits::ImplSource::DiscriminantKind(..) | traits::ImplSource::Pointee(..) - | traits::ImplSource::TraitUpcasting(_) => None, + | traits::ImplSource::TraitUpcasting(_) + | traits::ImplSource::ConstDrop(_) => None, }) } diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/src/lib.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(control_flow_enum)] -#![feature(half_open_range_patterns)] -#![feature(exclusive_range_pattern)] #![feature(nll)] #![recursion_limit = "256"] diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/src/needs_drop.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/src/needs_drop.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/src/needs_drop.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/src/needs_drop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -12,13 +12,13 @@ type NeedsDropResult = Result; fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - let adt_fields = - move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); - // If we don't know a type doesn't need drop, for example if it's a type // parameter without a `Copy` bound, then we conservatively return that it // needs drop. - let res = NeedsDropTypes::new(tcx, query.param_env, query.value, adt_fields).next().is_some(); + let adt_has_dtor = + |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); + let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some(); + debug!("needs_drop_raw({:?}) = {:?}", query, res); res } @@ -27,12 +27,10 @@ tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> bool { - let significant_drop_fields = move |adt_def: &ty::AdtDef, _| { - tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()) - }; - let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields) - .next() - .is_some(); + let res = + drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx)) + .next() + .is_some(); debug!("has_significant_drop_raw({:?}) = {:?}", query, res); res } @@ -143,10 +141,8 @@ Ok(tys) => tys, }; for required_ty in tys { - let subst_ty = tcx.normalize_erasing_regions( - self.param_env, - required_ty.subst(tcx, substs), - ); + let subst_ty = + tcx.normalize_erasing_regions(self.param_env, required_ty); queue_type(self, subst_ty); } } @@ -185,23 +181,24 @@ // Depending on the implentation of `adt_has_dtor`, it is used to check if the // ADT has a destructor or if the ADT only has a significant destructor. For // understanding significant destructor look at `adt_significant_drop_tys`. -fn adt_drop_tys_helper<'tcx>( +fn drop_tys_helper<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + ty: Ty<'tcx>, + param_env: rustc_middle::ty::ParamEnv<'tcx>, adt_has_dtor: impl Fn(&ty::AdtDef) -> Option, -) -> Result<&ty::List>, AlwaysRequiresDrop> { +) -> impl Iterator>> { let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| { if adt_def.is_manually_drop() { - debug!("adt_drop_tys: `{:?}` is manually drop", adt_def); + debug!("drop_tys_helper: `{:?}` is manually drop", adt_def); return Ok(Vec::new().into_iter()); } else if let Some(dtor_info) = adt_has_dtor(adt_def) { match dtor_info { DtorType::Significant => { - debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); + debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def); return Err(AlwaysRequiresDrop); } DtorType::Insignificant => { - debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def); + debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def); // Since the destructor is insignificant, we just want to make sure all of // the passed in type parameters are also insignificant. @@ -210,34 +207,27 @@ } } } else if adt_def.is_union() { - debug!("adt_drop_tys: `{:?}` is a union", adt_def); + debug!("drop_tys_helper: `{:?}` is a union", adt_def); return Ok(Vec::new().into_iter()); } - Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::>().into_iter()) + Ok(adt_def + .all_fields() + .map(|field| { + let r = tcx.type_of(field.did).subst(tcx, substs); + debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r); + r + }) + .collect::>() + .into_iter()) }; - let adt_ty = tcx.type_of(def_id); - let param_env = tcx.param_env(def_id); - let res: Result, _> = - NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect(); - - debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res); - res.map(|components| tcx.intern_type_list(&components)) -} - -fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List>, AlwaysRequiresDrop> { - // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are - // significant. - let adt_has_dtor = - |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); - adt_drop_tys_helper(tcx, def_id, adt_has_dtor) + NeedsDropTypes::new(tcx, param_env, ty, adt_components) } -fn adt_significant_drop_tys( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_has_dtor = |adt_def: &ty::AdtDef| { +fn adt_consider_insignificant_dtor<'tcx>( + tcx: TyCtxt<'tcx>, +) -> impl Fn(&ty::AdtDef) -> Option + 'tcx { + move |adt_def: &ty::AdtDef| { let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor); if is_marked_insig { // In some cases like `std::collections::HashMap` where the struct is a wrapper around @@ -254,8 +244,31 @@ // treat this as the simple case of Drop impl for type. None } - }; - adt_drop_tys_helper(tcx, def_id, adt_has_dtor) + } +} + +fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List>, AlwaysRequiresDrop> { + // This is for the "adt_drop_tys" query, that considers all `Drop` impls, therefore all dtors are + // significant. + let adt_has_dtor = + |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); + drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor) + .collect::, _>>() + .map(|components| tcx.intern_type_list(&components)) +} + +fn adt_significant_drop_tys( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> Result<&ty::List>, AlwaysRequiresDrop> { + drop_tys_helper( + tcx, + tcx.type_of(def_id), + tcx.param_env(def_id), + adt_consider_insignificant_dtor(tcx), + ) + .collect::, _>>() + .map(|components| tcx.intern_type_list(&components)) } pub(crate) fn provide(providers: &mut ty::query::Providers) { diff -Nru rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/src/ty.rs rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/src/ty.rs --- rustc-1.56.0+dfsg1+llvm/compiler/rustc_ty_utils/src/ty.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/compiler/rustc_ty_utils/src/ty.rs 2021-11-29 19:27:11.000000000 +0000 @@ -100,7 +100,7 @@ fn associated_item_from_impl_item_ref( tcx: TyCtxt<'_>, parent_def_id: LocalDefId, - impl_item_ref: &hir::ImplItemRef<'_>, + impl_item_ref: &hir::ImplItemRef, ) -> ty::AssocItem { let def_id = impl_item_ref.id.def_id; let (kind, has_self) = match impl_item_ref.kind { @@ -248,6 +248,7 @@ } /// See `ParamEnv` struct definition for details. +#[instrument(level = "debug", skip(tcx))] fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // The param_env of an impl Trait type is its defining function's param_env if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { @@ -275,9 +276,20 @@ predicates.extend(environment); } + // It's important that we include the default substs in unevaluated + // constants, since `Unevaluated` instances in predicates whose substs are None + // can lead to "duplicate" caller bounds candidates during trait selection, + // duplicate in the sense that both have their default substs, but the + // candidate that resulted from a superpredicate still uses `None` in its + // `substs_` field of `Unevaluated` to indicate that it has its default substs, + // whereas the other candidate has `substs_: Some(default_substs)`, see + // issue #89334 + predicates = tcx.expose_default_const_substs(predicates); + let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing); + debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds()); let body_id = def_id .as_local() .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) diff -Nru rustc-1.56.0+dfsg1+llvm/config.toml.example rustc-1.57.0+dfsg1+llvm/config.toml.example --- rustc-1.56.0+dfsg1+llvm/config.toml.example 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/config.toml.example 2021-11-29 19:27:11.000000000 +0000 @@ -103,7 +103,7 @@ # the same format as above, but since these targets are experimental, they are # not built by default and the experimental Rust compilation targets that depend # on them will not work unless the user opts in to building them. -#experimental-targets = "AVR" +#experimental-targets = "AVR;M68k" # Cap the number of parallel linker invocations when compiling LLVM. # This can be useful when building LLVM with debug info, which significantly @@ -202,15 +202,15 @@ # You can use "$ROOT" to indicate the root of the git repository. #build-dir = "build" -# Instead of downloading the src/stage0.txt version of Cargo specified, use +# Instead of downloading the src/stage0.json version of Cargo specified, use # this Cargo binary instead to build all Rust code #cargo = "/path/to/cargo" -# Instead of downloading the src/stage0.txt version of the compiler +# Instead of downloading the src/stage0.json version of the compiler # specified, use this rustc binary instead as the stage0 snapshot compiler. #rustc = "/path/to/rustc" -# Instead of download the src/stage0.txt version of rustfmt specified, +# Instead of download the src/stage0.json version of rustfmt specified, # use this rustfmt binary instead as the stage0 snapshot rustfmt. #rustfmt = "/path/to/rustfmt" @@ -313,6 +313,12 @@ # this setting's very existence, are all subject to change.) #print-step-rusage = false +# Always patch binaries for usage with Nix toolchains. If `true` then binaries +# will be patched unconditionally. If `false` or unset, binaries will be patched +# only if the current distribution is NixOS. This option is useful when using +# a Nix toolchain on non-NixOS distributions. +#patch-binaries-for-nix = false + # ============================================================================= # General install configuration options # ============================================================================= @@ -417,6 +423,18 @@ # set this value to `true`. #debug-logging = rust.debug-assertions (boolean) +# Whether or not overflow checks are enabled for the compiler and standard +# library. +# +# Defaults to rust.debug value +#overflow-checks = rust.debug (boolean) + +# Whether or not overflow checks are enabled for the standard library. +# Overrides the `overflow-checks` option, if defined. +# +# Defaults to rust.overflow-checks value +#overflow-checks-std = rust.overflow-checks (boolean) + # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info # `1` - line tables only - sufficient to generate backtraces that include line diff -Nru rustc-1.56.0+dfsg1+llvm/debian/changelog rustc-1.57.0+dfsg1+llvm/debian/changelog --- rustc-1.56.0+dfsg1+llvm/debian/changelog 2021-12-16 01:31:34.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/changelog 2022-01-21 03:41:59.000000000 +0000 @@ -1,8 +1,30 @@ -rustc (1.56.0+dfsg1+llvm-2ubuntu1~21.10.1) impish; urgency=medium +rustc (1.57.0+dfsg1+llvm-0ubuntu1~21.10.1) impish; urgency=medium * Backport to Impish. (LP: #1952104) - -- Michael Hudson-Doyle Thu, 16 Dec 2021 14:31:34 +1300 + -- Michael Hudson-Doyle Fri, 21 Jan 2022 16:41:59 +1300 + +rustc (1.57.0+dfsg1+llvm-0ubuntu1) jammy; urgency=medium + + * New upstream version. + * Refresh patches. + * d/patches/{u-89591.patch,u-88668.patch,u-89772.patch}: Remove as upstream + now includes these patches. + * d/patches/d-bootstrap-dont-download-stage0.patch: Remove, no longer + needed. + * d/patches/ubuntu-memchr-features.patch: Fix obscure ftbfs from mismatched + features. + + -- Michael Hudson-Doyle Fri, 21 Jan 2022 08:42:03 +1300 + +rustc (1.56.0+dfsg1+llvm-2ubuntu2) jammy; urgency=medium + + * debian/patches/u-ensure-aarch64-lse-object-files-have-distinct-names-in-an-archive.patch: + Backport patch from upstream, to fix "error: object name conflicts in + archive" when building rust programs on arm64 (librsvg is currently + affected). + + -- Iain Lane Tue, 18 Jan 2022 10:25:30 +0000 rustc (1.56.0+dfsg1+llvm-2ubuntu1) jammy; urgency=medium diff -Nru rustc-1.56.0+dfsg1+llvm/debian/changelog.orig rustc-1.57.0+dfsg1+llvm/debian/changelog.orig --- rustc-1.56.0+dfsg1+llvm/debian/changelog.orig 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/changelog.orig 2022-01-19 22:55:15.000000000 +0000 @@ -0,0 +1,3017 @@ +rustc (1.57.0+dfsg1+llvm-0ubuntu1) UNRELEASED; urgency=medium + + * New upstream version. + * Refresh patches. + + -- Michael Hudson-Doyle Wed, 19 Jan 2022 23:09:27 +1300 + +rustc (1.56.0+dfsg1+llvm-2ubuntu1) jammy; urgency=medium + + * Merge 1.56.0+dfsg1-2 from Debian unstable. (LP: #1952104) + Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + - Reduce parallelism on all arches other than riscv64 to avoid OOMs + during build. + + -- Michael Hudson-Doyle Tue, 14 Dec 2021 10:24:02 +1300 + +rustc (1.56.0+dfsg1-2) unstable; urgency=medium + + * Update to debhelper 13. + + -- Ximin Luo Fri, 22 Oct 2021 23:29:14 +0100 + +rustc (1.56.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + * Support terse and verbose DEB_BUILD_OPTIONS. + * Support -Z gcc-ld=lld via symlinks. + * Fix RUSTC_SYSROOT in rust-gdb and rust-lldb, thanks James McCoy. + + -- Ximin Luo Fri, 22 Oct 2021 18:54:49 +0100 + +rustc (1.56.0~beta.4+dfsg1-1~exp2) experimental; urgency=medium + + * Include upstream patch for x32 support. (Closes: #993855) + * Update to LLVM 13. + + -- Ximin Luo Fri, 15 Oct 2021 10:44:35 +0100 + +rustc (1.56.0~beta.4+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Thu, 14 Oct 2021 22:50:58 +0100 + +rustc (1.55.0+dfsg1+llvm-2ubuntu1) jammy; urgency=medium + + * Merge 1.55.0+dfsg1-2 from Debian unstable. (LP: #1952104) + Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + - Reduce parallelism on all arches other than riscv64 to avoid OOMs + during build. + * Dropped changes, fixed upstream: + - Adjust -march setting on armhf + + -- Michael Hudson-Doyle Mon, 13 Dec 2021 15:07:06 +1300 + +rustc (1.55.0+dfsg1-2) unstable; urgency=medium + + * Actually work around segfault on ppc64el. + * Fix FTBFS on armhf caused by GCC 11 changes. + + -- Ximin Luo Thu, 14 Oct 2021 00:36:15 +0100 + +rustc (1.55.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Bump test failures-allowed on s390x to 40. + * Work around a segfault on ppc64el + + -- Ximin Luo Wed, 13 Oct 2021 22:06:15 +0100 + +rustc (1.55.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Sat, 09 Oct 2021 03:22:08 +0100 + +rustc (1.54.0+dfsg2+llvm-3ubuntu1) jammy; urgency=medium + + * Merge 1.54.0+dfsg1-3 from Debian unstable. (LP: #1952104) + Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + - Adjust -march setting on armhf + * Reduce parallelism on all arches other than riscv64 to avoid OOMs + during build. + + -- Michael Hudson-Doyle Fri, 10 Dec 2021 08:13:40 +1300 + +rustc (1.54.0+dfsg1-3) unstable; urgency=medium + + * Fix links to cargo-doc. + + -- Ximin Luo Sat, 09 Oct 2021 11:46:08 +0100 + +rustc (1.54.0+dfsg1-2) unstable; urgency=medium + + * Fix some more build & test failures. + + -- Ximin Luo Sat, 09 Oct 2021 03:12:35 +0100 + +rustc (1.54.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Re-enable backported patch for armhf & reset its allowed-failures. + * Add compatibility patch for cargo 0.47. + * Ignore more spurious test failures, and filed upstream. + * Bump powerpc allowed-failures to 180 at the request of ports maintainers. + + -- Ximin Luo Sat, 09 Oct 2021 00:24:37 +0100 + +rustc (1.54.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Wed, 06 Oct 2021 10:37:55 +0100 + +rustc (1.53.0+dfsg1+llvm-4ubuntu1) jammy; urgency=medium + + * Merge 1.53.0+dfsg1-4 from Debian unstable. (LP: #1943842) + Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + - Reduce parallelism on all arches to avoid OOMs during build. + - Adjust -march setting on armhf + + -- Michael Hudson-Doyle Wed, 27 Oct 2021 20:12:14 +1300 + +rustc (1.53.0+dfsg1-4) unstable; urgency=medium + + * Ignore some hanging test regressions on non-release arches powerpc, ppc64. + + -- Ximin Luo Wed, 06 Oct 2021 19:24:11 +0100 + +rustc (1.53.0+dfsg1-3) unstable; urgency=medium + + * Disable patch that was backported incorrectly. + * Temporarily increase armhf allowed-failures to 12. + + -- Ximin Luo Wed, 06 Oct 2021 19:01:54 +0100 + +rustc (1.53.0+dfsg1-2) unstable; urgency=medium + + * Fix some test failures. + + -- Ximin Luo Wed, 06 Oct 2021 10:29:03 +0100 + +rustc (1.53.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Update mips patches, disable a test as our workaround makes it invalid. + * Temporarily ignore some tests that fail on big-endian. + + -- Ximin Luo Tue, 05 Oct 2021 23:19:31 +0100 + +rustc (1.53.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. (Closes: #986803) + * Honour parallel option in DEB_BUILD_OPTIONS. (Closes: #993871) + + -- Ximin Luo Sat, 02 Oct 2021 12:46:49 +0100 + +rustc (1.52.1+dfsg1+llvm-1ubuntu1) impish; urgency=medium + + * Merge 1.52.1+dfsg1-1 from Debian unstable. (LP: #1943842) + Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + * Reduce parallelism on all arches to avoid OOMs during build. + * Adjust -march setting on armhf. + + -- Michael Hudson-Doyle Wed, 13 Oct 2021 14:30:46 +1300 + +rustc (1.52.1+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Reorganise dependencies, move optional rustc deps to rust-all. + + -- Ximin Luo Wed, 29 Sep 2021 20:05:55 +0100 + +rustc (1.52.1+dfsg1-1~exp3) experimental; urgency=medium + + * Update to LLVM 12. + + -- Ximin Luo Wed, 19 May 2021 17:52:44 +0100 + +rustc (1.52.1+dfsg1-1~exp2) experimental; urgency=medium + + * Fix rust-clippy dependency on libstd-rust-* + + -- Ximin Luo Sat, 15 May 2021 22:42:38 +0100 + +rustc (1.52.1+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Sat, 15 May 2021 15:21:27 +0100 + +rustc (1.52.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Fri, 07 May 2021 20:38:38 +0100 + +rustc (1.52.0~beta.3+dfsg1-1~exp4) experimental; urgency=medium + + * Fix issue with dh_missing --fail-missing + + -- Ximin Luo Thu, 06 May 2021 01:52:30 +0100 + +rustc (1.52.0~beta.3+dfsg1-1~exp3) experimental; urgency=medium + + * Fix Makefile addition syntax. + + -- Ximin Luo Wed, 05 May 2021 22:24:22 +0100 + +rustc (1.52.0~beta.3+dfsg1-1~exp2) experimental; urgency=medium + + * Install the rust-llvm-dwp symlink. + + -- Ximin Luo Wed, 05 May 2021 22:20:13 +0100 + +rustc (1.52.0~beta.3+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Mon, 26 Apr 2021 12:31:27 +0100 + +rustc (1.51.0+dfsg1+llvm-1~exp3ubuntu1) impish; urgency=medium + + * Merge 1.51.0+dfsg1-1~exp3 from Debian experimental (LP #1932145). + Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + - Try reducing parallelism in rustbuild on arm64 to avoid OOM. + - Reduce parallelism during build on s390x too. + * Disable check against uploading ~exp versions. + + -- Michael Hudson-Doyle Tue, 06 Jul 2021 13:16:52 +1200 + +rustc (1.51.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Install the rust-llvm-dwp symlink. + * Bump ppc64 allowed-failures to 24. + + -- Ximin Luo Sun, 19 Sep 2021 19:48:33 +0100 + +rustc (1.51.0+dfsg1-1~exp3) experimental; urgency=medium + + * Restore patch, not actually fixed upstream. + + -- Ximin Luo Mon, 26 Apr 2021 16:17:12 +0100 + +rustc (1.51.0+dfsg1-1~exp2) experimental; urgency=medium + + * Drop patch fixed upstream. + * Fix bootstrap with self version. + + -- Ximin Luo Mon, 26 Apr 2021 12:26:43 +0100 + +rustc (1.51.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Enable 32-bit windows support. + + -- Ximin Luo Mon, 12 Apr 2021 11:04:36 +0100 + +rustc (1.50.0+dfsg1+llvm-0ubuntu5) hirsute; urgency=medium + + * No change rebuild rebootstrap. + + -- Dimitri John Ledkov Thu, 01 Apr 2021 21:54:48 +0100 + +rustc (1.50.0+dfsg1+llvm-0ubuntu4) hirsute; urgency=medium + + * Drop d/patches/0001-Revert-Auto-merge-of-79547.patch. + * Cherrypick llvm toolchain fix for s390x from 1.51 beta. + * Build against older 1.49 rustc. + + -- Dimitri John Ledkov Thu, 25 Mar 2021 13:30:52 +0000 + +rustc (1.50.0+dfsg1+llvm-0ubuntu3) hirsute; urgency=medium + + * Rebuild against the previous upload. + * Restore the upper cap on the rustc build-dependency. + + -- Dimitri John Ledkov Wed, 24 Mar 2021 22:27:48 +0000 + +rustc (1.50.0+dfsg1+llvm-0ubuntu2) hirsute; urgency=medium + + [ Michael Hudson-Doyle ] + * d/patches/0001-Revert-Auto-merge-of-79547.patch: Revert a patch that + causes LLVM to generate bad code on s390x. See + https://github.com/rust-lang/rust/issues/80810. + + [ Dimitri John Ledkov ] + * Built against older 1.49 rustc. + + -- Dimitri John Ledkov Tue, 23 Mar 2021 18:45:53 +0000 + +rustc (1.50.0+dfsg1+llvm-0ubuntu1) hirsute; urgency=medium + + * New upstream release. (LP: #1915722) + * Update patches. + * Update d/copyright. + + -- Michael Hudson-Doyle Thu, 04 Mar 2021 10:17:58 +1300 + +rustc (1.50.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + + -- Ximin Luo Sat, 18 Sep 2021 11:45:21 +0100 + +rustc (1.50.0+dfsg1-1~exp4) experimental; urgency=medium + + * Fix more tests with a backported upstream PR. + + -- Ximin Luo Mon, 12 Apr 2021 01:51:22 +0100 + +rustc (1.50.0+dfsg1-1~exp3) experimental; urgency=medium + + * Fix cross-compile to windows using same-version stage0. + + -- Ximin Luo Sun, 11 Apr 2021 13:52:41 +0100 + +rustc (1.50.0+dfsg1-1~exp2) experimental; urgency=medium + + * Fix tests, fix s390x breakage. + + -- Ximin Luo Fri, 09 Apr 2021 16:54:20 +0100 + +rustc (1.50.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Mon, 05 Apr 2021 21:30:18 +0100 + +rustc (1.49.0+dfsg1+llvm-0ubuntu1) hirsute; urgency=medium + + * Merge 1.49.0~beta.4+dfsg1-1~exp1 from Debian experimental (LP #1915722). + Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + - Try reducing parallelism in rustbuild on arm64 to avoid OOM. + * Update to 1.49.0 final release. + * Drop d-fix-mips64el-bootstrap.patch. + * Reduce parallelism during build on s390x too. + + -- Michael Hudson-Doyle Mon, 01 Mar 2021 21:39:26 +1300 + +rustc (1.49.0+dfsg1-2) unstable; urgency=medium + + * Backport upstream PR 85807 to fix powerpc test issues. + + -- Ximin Luo Sat, 18 Sep 2021 11:33:09 +0100 + +rustc (1.49.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + + -- Ximin Luo Sat, 28 Aug 2021 10:48:11 +0100 + +rustc (1.49.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Mon, 05 Apr 2021 14:59:34 +0100 + +rustc (1.49.0~beta.4+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Sun, 20 Dec 2020 23:26:55 +0000 + +rustc (1.48.0+dfsg1+llvm-2ubuntu1) hirsute; urgency=medium + + * Merge 1.48.0+dfsg1-2 from Debian unstable (LP #1915722). Remaining + changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + - Try reducing parallelism in rustbuild on arm64 to avoid OOM. + + -- Michael Hudson-Doyle Fri, 26 Feb 2021 08:13:28 +1300 + +rustc (1.48.0+dfsg1-2) unstable; urgency=medium + + * Enable +xgot on mips64*, see upstream #52108 for details. + + -- Ximin Luo Sun, 20 Dec 2020 18:52:10 +0000 + +rustc (1.48.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + + -- Ximin Luo Tue, 01 Dec 2020 19:57:48 +0000 + +rustc (1.48.0~beta.8+dfsg1-1~exp3) experimental; urgency=medium + + * Update u-update-version-check.patch + + -- Ximin Luo Fri, 13 Nov 2020 01:36:31 +0000 + +rustc (1.48.0~beta.8+dfsg1-1~exp2) experimental; urgency=medium + + * Disable copy_file_range optimisation for now, see upstream #78979. + * Ignore some other minor tests, bugs have been filed upstream. + + -- Ximin Luo Thu, 12 Nov 2020 23:51:53 +0000 + +rustc (1.48.0~beta.8+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Wed, 11 Nov 2020 12:31:18 +0000 + +rustc (1.47.0+dfsg1+llvm-1ubuntu2) hirsute; urgency=medium + + * No change rebuild against new glibc-32 ABI. + + -- Dimitri John Ledkov Mon, 15 Feb 2021 22:37:11 +0000 + +rustc (1.47.0+dfsg1+llvm-1ubuntu1) hirsute; urgency=medium + + * Merge 1.47.0+dfsg1-1 from Debian unstable (LP #1901571). Remaining + changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + - Do not build windows cross compiler. + * Try reducing parallelism in rustbuild on arm64 to avoid OOM. + + -- Michael Hudson-Doyle Tue, 08 Dec 2020 12:50:59 +1300 + +rustc (1.47.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + * Update to LLVM 11. + * Ignore more tests on big-endian. + + -- Ximin Luo Sat, 07 Nov 2020 21:21:03 +0000 + +rustc (1.47.0~beta.2+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Sat, 05 Sep 2020 16:11:16 +0100 + +rustc (1.46.0+dfsg1+llvm-1ubuntu1) hirsute; urgency=medium + + * Merge 1.46.0 from Debian unstable. Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + * Do not build windows cross compiler. + + -- Michael Hudson-Doyle Sun, 06 Dec 2020 21:56:18 +1300 + +rustc (1.46.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + + -- Ximin Luo Sat, 29 Aug 2020 16:54:36 +0100 + +rustc (1.46.0~beta.2+dfsg1-1~exp5) experimental; urgency=medium + + * Fix rust-gdb install path. (Closes: #968279) + * Drop powerpc allowed-failures to 12. (Closes: #955774) + * Update d-fix-mips64el-bootstrap.patch for newer LLVM. + + -- Ximin Luo Fri, 14 Aug 2020 23:45:25 +0100 + +rustc (1.46.0~beta.2+dfsg1-1~exp4) experimental; urgency=medium + + * Move cross-linker Depends to Recommends - for cross-compiling support + libraries should never hard-depend on toolchains. This also allows us to + add the usual M-A annotations for libraries. + + -- Ximin Luo Sun, 09 Aug 2020 18:16:16 +0100 + +rustc (1.46.0~beta.2+dfsg1-1~exp3) experimental; urgency=medium + + * Drop "-cross" suffix from libstd naming, after discussion with Helmut + Grohne. Since libstd-rust-dev-wasm-cross is not yet in stable and only + has 4 installed users, we do not retain a migration package. + + -- Ximin Luo Sun, 09 Aug 2020 14:27:54 +0100 + +rustc (1.46.0~beta.2+dfsg1-1~exp2) experimental; urgency=medium + + * Add support for cross-compiling to windows. See README.Debian for details. + Currently only 64-bit works, we are waiting on #540782 for 32-bit. + + -- Ximin Luo Sun, 09 Aug 2020 03:52:34 +0100 + +rustc (1.46.0~beta.2+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Fri, 07 Aug 2020 00:15:46 +0100 + +rustc (1.45.0+dfsg1+llvm-2ubuntu1) hirsute; urgency=medium + + * Merge 1.45.0 from Debian unstable. Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - Revert workaround for upstream bug #74786 + - Disable wasm build as build dependencies not currently available in + Ubuntu. + * Dropped change, patches no longer apply and riscv64 build fails + anyway: + - riscv64 support patches which no longer completely work: + - Add more rustc patches from Debian. + - Apply relevant llvm-toolchain-9 patches to the embedded llvm. + - Avoid the LDFLAGS -latomic hacks from llvm-toolchain-9: + - debian/patches/riscv64-atomic-fixes.patch: Fix libatomic detection for + riscv64. + - debian/patches/dsymutil-atomic.patch: Link dsymutil with -latomic. + * Dropped change, upstream now includes LLVM with the fix: + - Backport patch fixing miscompliation and subsequent crash on s390x + (adapted from https://src.fedoraproject.org/rpms/llvm/pull-request/49): + - add debian/patches/0001-InstCombine-Fix-big-endian-miscompile-of-bitcast-zex.patch + - update debian/patches/series + + -- Michael Hudson-Doyle Fri, 04 Dec 2020 11:20:49 +1300 + +rustc (1.45.0+dfsg1-2) unstable; urgency=medium + + * Add some more big-endian test patches. + * Backport some patches to fix some testsuite ICEs. + + -- Ximin Luo Thu, 06 Aug 2020 21:11:39 +0100 + +rustc (1.45.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + + -- Ximin Luo Wed, 05 Aug 2020 21:41:39 +0100 + +rustc (1.45.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Mon, 27 Jul 2020 17:45:24 +0100 + +rustc (1.44.1+dfsg1+llvm-3ubuntu1) hirsute; urgency=medium + + * Merge 1.44.1 from Debian unstable. Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - riscv64 support patches which no longer completely work: + - Add more rustc patches from Debian. + - Apply relevant llvm-toolchain-9 patches to the embedded llvm. + - Avoid the LDFLAGS -latomic hacks from llvm-toolchain-9: + - debian/patches/riscv64-atomic-fixes.patch: Fix libatomic detection for + riscv64. + - debian/patches/dsymutil-atomic.patch: Link dsymutil with -latomic. + - Backport patch fixing miscompliation and subsequent crash on s390x + (adapted from https://src.fedoraproject.org/rpms/llvm/pull-request/49): + - add debian/patches/0001-InstCombine-Fix-big-endian-miscompile-of-bitcast-zex.patch + - update debian/patches/series + * Dropped change: + - Disable check for ~exp in version number. + * Revert workaround for upstream bug #74786 + * Disable wasm build as build dependencies not currently available in + Ubuntu. + + -- Michael Hudson-Doyle Thu, 03 Dec 2020 14:03:38 +1300 + +rustc (1.44.1+dfsg1-3) unstable; urgency=medium + + * Fix patch for line numbers on little-endian arches. + + -- Ximin Luo Tue, 28 Jul 2020 21:51:36 +0100 + +rustc (1.44.1+dfsg1-2) unstable; urgency=medium + + * Ignore tests that assume little-endian on big-endian arches. + See upstream #74829 for details. + + -- Ximin Luo Tue, 28 Jul 2020 21:20:24 +0100 + +rustc (1.44.1+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Backport a typenum fix for i386. + * Work around upstream #74786 involving debuginfo maps. + + -- Ximin Luo Mon, 27 Jul 2020 13:15:20 +0100 + +rustc (1.44.1+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Sat, 04 Jul 2020 18:04:42 +0100 + +rustc (1.43.0+dfsg1+llvm-1~exp1ubuntu3) UNRELEASED; urgency=medium + + * Relax rustc version constraint in Build-Depends to see if 1.41 can + build 1.43 on riscv64. + + -- Michael Hudson-Doyle Thu, 25 Jun 2020 09:50:02 +1200 + +rustc (1.43.0+dfsg1+llvm-1~exp1ubuntu2) groovy; urgency=medium + + * Fix mismerge preventing tests from running. + * Backport patch fixing miscompliation and subsequent crash on s390x + (adapted from https://src.fedoraproject.org/rpms/llvm/pull-request/49): + - add debian/patches/0001-InstCombine-Fix-big-endian-miscompile-of-bitcast-zex.patch + - update debian/patches/series + + -- Michael Hudson-Doyle Tue, 23 Jun 2020 19:35:09 +1200 + +rustc (1.43.0+dfsg1+llvm-1~exp1ubuntu1) groovy; urgency=medium + + * Merge from Debian NEW (LP: #1876942). Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + - riscv64 support patches which no longer completely work: + - Add more rustc patches from Debian. + - Apply relevant llvm-toolchain-9 patches to the embedded llvm. + - Avoid the LDFLAGS -latomic hacks from llvm-toolchain-9: + - debian/patches/riscv64-atomic-fixes.patch: Fix libatomic detection for + riscv64. + - debian/patches/dsymutil-atomic.patch: Link dsymutil with -latomic. + * Disable check for ~exp in version number. + + -- Michael Hudson-Doyle Thu, 28 May 2020 07:59:18 +1200 + +rustc (1.43.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Bump LLVM B-D version for some backported fixes affecting rustc. + + -- Ximin Luo Sun, 05 Jul 2020 15:06:52 +0100 + +rustc (1.43.0+dfsg1-1~exp1) experimental; urgency=medium + + * Drop sparc64 workaround. (Closes: #956413) + * Drop stack-gap workaround for old kernels and rust versions. + * New upstream release. + + -- Ximin Luo Mon, 27 Apr 2020 13:09:20 +0100 + +rustc (1.42.0+dfsg1+llvm-1ubuntu2) groovy; urgency=medium + + * Re-add riscv64 support patches which where accidentally dropped in + previous upload and no longer completely work: + - Add more rustc patches from Debian. + - Apply relevant llvm-toolchain-9 patches to the embedded llvm. + - Avoid the LDFLAGS -latomic hacks from llvm-toolchain-9: + - debian/patches/riscv64-atomic-fixes.patch: Fix libatomic detection for + riscv64. + - debian/patches/dsymutil-atomic.patch: Link dsymutil with -latomic. + + -- Michael Hudson-Doyle Thu, 21 May 2020 08:04:00 +1200 + +rustc (1.42.0+dfsg1+llvm-1ubuntu1) groovy; urgency=medium + + * Merge from Debian unstable (LP #1876942). Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + + -- Michael Hudson-Doyle Mon, 18 May 2020 20:29:59 +1200 + +rustc (1.42.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + + -- Ximin Luo Fri, 10 Apr 2020 11:33:25 +0100 + +rustc (1.42.0+dfsg1-1~exp1) experimental; urgency=medium + + [ Fabian Grünbichler ] + * Team upload. + * New upstream release. + + -- Ximin Luo Sat, 04 Apr 2020 16:06:03 +0100 + +rustc (1.41.1+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + + -- Ximin Luo Fri, 03 Apr 2020 23:41:11 +0100 + +rustc (1.41.1+dfsg1-1~exp1) experimental; urgency=medium + + [ Ximin Luo ] + * More python 2 -> 3 fixes. + * Enable the wasm32-wasi target for code that needs a "real" libstd. + * Don't strip static rlibs. This sometimes breaks wasm, and more generally + the stripped debuginfo is actually totally lost rather than being moved + into the -dbgsym packages. Shared libraries are unaffected and work. + * Allow 180 failing tests on riscv64, none were actually run last time. + + [ Fabian Grünbichler ] + * New upstream release. + + -- Ximin Luo Mon, 09 Mar 2020 00:31:34 +0000 + +rustc (1.41.0+dfsg1+llvm-0ubuntu2) focal; urgency=medium + + * Add riscv64 support: + - Add more rustc patches from Debian. + - Apply relevant llvm-toolchain-9 patches to the embedded llvm. + - debian/patches/riscv64-vendor-cc.diff: Update one last rustc lp64 ABI + reference to lp64d. + - Avoid the LDFLAGS -latomic hacks from llvm-toolchain-9: + - debian/patches/riscv64-atomic-fixes.patch: Fix libatomic detection for + riscv64. + - debian/patches/dsymutil-atomic.patch: Link dsymutil with -latomic. + + -- William Grant Wed, 08 Apr 2020 10:18:39 +1000 + +rustc (1.41.0+dfsg1+llvm-0ubuntu1) focal; urgency=medium + + * New upstream version (LP: #1856851) + * Cherry-pick several commits from + https://salsa.debian.org/rust-team/rust/-/merge_requests/4, + thanks Fabian Grünbichler: + - convert orig Cargo.lock to v1 format + - d/patches: update for 1.41.0 import + - Update Files-Excluded for new upstream version 1.41.0 + - d/update-version.sh: fix python3 compat + - drop patches which were applied upstream + - rebase and update patches + - don't attempt to install llvm codegen so + - update d/copyright + - update changelog and versions + - (adjusted somewhat by me) + + -- Michael Hudson-Doyle Mon, 02 Mar 2020 21:22:50 +0100 + +rustc (1.40.0+dfsg1+llvm-5ubuntu1) focal; urgency=medium + + * Merge from Debian unstable (LP #1856851). Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + * Dropped change, now fixed in Debian: + - Run build scripts with Python 3. + + -- Michael Hudson-Doyle Sat, 29 Feb 2020 16:21:22 +0000 + +rustc (1.40.0+dfsg1-5) unstable; urgency=medium + + * More python 2 -> 3 fixes. + * Allow 24 failing tests on riscv64. + * Reenable debuginfo for rustc, not just libstd. + * Reenable backtraces during tests. + + -- Ximin Luo Sun, 05 Jan 2020 13:35:46 +0000 + +rustc (1.40.0+dfsg1-4) unstable; urgency=medium + + * Experimental riscv64 support. + + -- Ximin Luo Sat, 04 Jan 2020 05:40:11 +0000 + +rustc (1.40.0+dfsg1-3) unstable; urgency=medium + + * Work around upstream #59264 again. :/ + + -- Ximin Luo Fri, 03 Jan 2020 22:05:16 +0000 + +rustc (1.40.0+dfsg1-2) unstable; urgency=medium + + * Fix more internal build scripts so they use python3. + * Don't add -L/usr/lib/llvm when cross-compiling. (Closes: #941783) + + -- Ximin Luo Fri, 03 Jan 2020 20:18:46 +0000 + +rustc (1.40.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Ignore new test failing on arm that also fails in previous versions. + + -- Ximin Luo Sun, 29 Dec 2019 22:17:04 +0000 + +rustc (1.40.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Wed, 25 Dec 2019 00:09:24 +0000 + +rustc (1.39.0+dfsg1+llvm-3ubuntu1) focal; urgency=medium + + * Merge from Debian unstable (LP #1856851). Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + - Add Build-Depends-Indep: libssl-dev + * Run build scripts with Python 3. + + -- Michael Hudson-Doyle Wed, 22 Jan 2020 20:21:38 +1300 + +rustc (1.39.0+dfsg1-4) unstable; urgency=medium + + * Update to LLVM 9. (Closes: #946886) + + -- Ximin Luo Mon, 23 Dec 2019 03:21:02 +0000 + +rustc (1.39.0+dfsg1-3) unstable; urgency=medium + + * Fix mips patch involving mxgot for new RUSTFLAGS behaviour. + + -- Ximin Luo Fri, 06 Dec 2019 22:18:53 +0000 + +rustc (1.39.0+dfsg1-2) unstable; urgency=medium + + * Include reproducibility patch for compiler-builtins. + * Use python3 instead of python to run rustbuild. (Closes: #938422) + * Expand d-ignore-error-detail-diff.patch for unfixed upstream #53081. + + -- Ximin Luo Thu, 05 Dec 2019 22:51:41 +0000 + +rustc (1.39.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + + -- Ximin Luo Sat, 30 Nov 2019 22:20:48 +0000 + +rustc (1.38.0+dfsg1-2) unstable; urgency=medium + + * Fix building with rustc 1.38.0 + * Fix building with cargo 0.40.0 + + -- Ximin Luo Fri, 29 Nov 2019 00:05:16 +0000 + +rustc (1.38.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + + -- Ximin Luo Tue, 26 Nov 2019 14:41:46 +0000 + +rustc (1.38.0+dfsg0.2+llvm-0ubuntu2) focal; urgency=medium + + * d/patches/d-fix-1.38-self-bootstrap.patch: backport patch from upstream + to allow warnings to not fail the build, which allows rustc 1.38 to be + bootstrapped with itself. + - adds d/patches/d-fix-1.38-self-bootstrap.patch + - updates d/patches/series + - updates debian/config.toml.in + + -- Michael Hudson-Doyle Fri, 29 Nov 2019 07:57:13 +1300 + +rustc (1.38.0+dfsg0.2+llvm-0ubuntu1) focal; urgency=medium + + * New upstream release. + * Add Build-Depends-Indep: libssl-dev + * Update Files-Excluded for new upstream version 1.38.0 + * d/patches/d-0004-mdbook-2-1-compat.patch: Removed. + * Refresh other patches. + + -- Michael Hudson-Doyle Wed, 13 Nov 2019 09:29:49 +1300 + +rustc (1.37.0+dfsg1+llvm-1ubuntu1) eoan; urgency=medium + + * Merge from Debian unstable (LP #1843765). Remaning changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + * Revert "Support cross-compiling to wasm32" as it breaks with the + bundled snapshot of LLVM 9. + - delete debian/libstd-rust-dev-wasm32-cross.lintian-overrides + - delete debian/rustc.links + - update debian/config.toml.in + - update debian/control + - update debian/rules + + -- Michael Hudson-Doyle Wed, 18 Sep 2019 14:31:31 +0200 + +rustc (1.37.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Fix a typo in debian/rules regex causing FTBFS on some arches. + + -- Ximin Luo Thu, 05 Sep 2019 00:06:23 -0700 + +rustc (1.37.0+dfsg1-1~exp2) experimental; urgency=medium + + * Support cross-compiling to wasm32. (Closes: #903110) + To do that, install the libstd-rust-dev-wasm32-cross package and give + --target wasm32-unknown-unknown. + * Drop dependency on system compiler-rt, these new versions of rustc + actually don't need it at all. + + -- Ximin Luo Thu, 29 Aug 2019 09:00:03 -0700 + +rustc (1.37.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Use system compiler-rt. + + -- Ximin Luo Sun, 25 Aug 2019 03:06:33 -0700 + +rustc (1.36.0+dfsg1+llvm-2ubuntu1) eoan; urgency=medium + + * Merge from Debian unstable. Remaning changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + + -- Michael Hudson-Doyle Sat, 17 Aug 2019 13:58:25 +1200 + +rustc (1.36.0+dfsg1-2) unstable; urgency=medium + + * Set CARGO_HOME to debian/cargo_home (instead of $HOME/.cargo) as newer + versions of cargo must take a file lock that has to exist. + + -- Ximin Luo Wed, 17 Jul 2019 18:25:06 -0700 + +rustc (1.36.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + + -- Ximin Luo Tue, 16 Jul 2019 20:27:55 -0700 + +rustc (1.36.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Sat, 13 Jul 2019 12:42:05 -0700 + +rustc (1.35.0+dfsg1-1) unstable; urgency=medium + + * Add entry in 1.34.2+dfsg1-1 to note that it uses LLVM 7. + * Add entry in 1.35.0+dfsg1-1~exp2 to note that it uses LLVM 8. + * Fix ICE on sparc64 by including upstream PR #61881. + + -- Ximin Luo Sat, 13 Jul 2019 10:30:35 -0700 + +rustc (1.35.0+dfsg1-1~exp1) experimental; urgency=medium + + * Don't use system compiler-rt, it's not ready yet. + * Update to LLVM 8. + * New upstream release. + + -- Ximin Luo Sun, 09 Jun 2019 23:20:52 -0700 + +rustc (1.35.0+dfsg0.1+llvm-0ubuntu1) eoan; urgency=medium + + * New upstream release. + - Refresh patches. + - Bump rustc versions in d/control. + + -- Åukasz 'sil2100' Zemczak Mon, 08 Jul 2019 12:10:17 +0200 + +rustc (1.34.2+dfsg1-1) unstable; urgency=medium + + * Don't use system compiler-rt, there are issues with that for now. + * Use LLVM 7 for the Debian buster release. + + -- Ximin Luo Wed, 29 May 2019 21:52:37 -0700 + +rustc (1.34.2+dfsg1-1~exp2) experimental; urgency=medium + + * Fix doc build, add version 1 compat mode hack for mdBook 2. + * Use system compiler-rt from libclang-common-*-dev. + + -- Ximin Luo Fri, 24 May 2019 00:39:59 -0700 + +rustc (1.34.2+dfsg1-1~exp1) experimental; urgency=medium + + * Ensure Cargo.toml is in rust-src. + * New upstream release. + * Update to LLVM 8. + + -- Ximin Luo Sun, 19 May 2019 02:40:02 -0700 + +rustc (1.34.1+dfsg2+llvm-0ubuntu1) eoan; urgency=medium + + * New upstream release. + - Refresh patches. + - Bump rustc versions in d/control. + * Add d-no-web-dependencies-in-doc-0.1.7.patch: there are now two copies of + mdbook that need patching. + * Adjust d/rules to cope with the fact that src/llvm is now src/llvm-project. + + -- Michael Hudson-Doyle Fri, 17 May 2019 10:58:38 +1200 + +rustc (1.33.0+dfsg1+llvm-1~exp1ubuntu1) eoan; urgency=medium + + * Merge from Debian unstabl^Wexperimenta^WNEW. Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + + -- Michael Hudson-Doyle Mon, 13 May 2019 14:15:10 +1200 + +rustc (1.33.0+dfsg1-2) unstable; urgency=medium + + * Add Fedora patches. + * Bump i386 allowed test failures to 12. + + -- Ximin Luo Sat, 18 May 2019 12:18:25 -0700 + +rustc (1.33.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Fix build on mips, flags needed whitespace massaging. + * Drop obsolete patches. + + -- Ximin Luo Fri, 17 May 2019 21:04:20 -0700 + +rustc (1.33.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + [ Hiroaki Nakamura ] + * Delete obsolete patch. + + [ Sylvestre Ledru ] + * Update compiler-rt patch. + * Improve build-related docs a bit. + + -- Ximin Luo Mon, 29 Apr 2019 11:43:26 -0700 + +rustc (1.32.0+dfsg1+llvm-1ubuntu1) disco; urgency=medium + + * Merge from Debian unstable. Remaning changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + - update debian/watch + + -- Michael Hudson-Doyle Thu, 14 Feb 2019 10:24:51 +1300 + +rustc (1.32.0+dfsg1-3) unstable; urgency=medium + + * Conditionally-apply u-compiletest.patch based on stage0 compiler. + * Fix syntax error in d/rules compiletest check. + + -- Ximin Luo Sun, 17 Mar 2019 16:40:05 -0700 + +rustc (1.32.0+dfsg1-2) unstable; urgency=medium + + * More verbose logging during builds. + * Fix compiletest compile error, and check log has at least 1 pass. + + -- Ximin Luo Sun, 17 Mar 2019 12:52:57 -0700 + +rustc (1.32.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + + -- Ximin Luo Sun, 27 Jan 2019 22:02:48 -0800 + +rustc (1.32.0~beta.2+dfsg1-1~exp2) experimental; urgency=medium + + * Note that this upstream version already Closes: #917191. + * Backport other upstream fixes. (Closes: #916818, #917000, #917192). + + -- Ximin Luo Tue, 01 Jan 2019 15:26:57 -0800 + +rustc (1.32.0~beta.2+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Drop obsolete d-sparc64-dont-pack-spans.patch + + -- Ximin Luo Sun, 16 Dec 2018 13:48:25 -0800 + +rustc (1.31.0+dfsg1+llvm-2ubuntu1) disco; urgency=medium + + * Merge from Debian unstable. Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + + -- Michael Hudson-Doyle Fri, 18 Jan 2019 11:43:00 +1300 + +rustc (1.31.0+dfsg1-2) unstable; urgency=medium + + * Bump mips mipsel s390x allowed-failures to 24. + + -- Ximin Luo Sun, 16 Dec 2018 14:34:44 -0800 + +rustc (1.31.0+dfsg1-1) unstable; urgency=medium + + * Revert debuginfo patches, they're not ready yet. + + -- Ximin Luo Sun, 16 Dec 2018 09:58:06 -0800 + +rustc (1.31.0+dfsg1-1~exp2) experimental; urgency=medium + + * Drop redundant patches. + * Fix line numbers in some test-case patches. + * Backport an updated patch for gdb 8.2. + + -- Ximin Luo Sat, 15 Dec 2018 13:52:26 -0800 + +rustc (1.31.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Fri, 14 Dec 2018 21:30:56 -0800 + +rustc (1.31.0~beta.19+dfsg1-1~exp2) experimental; urgency=medium + + * Filter LLVM build flags to not be stupid. + + -- Ximin Luo Sat, 01 Dec 2018 12:17:52 -0800 + +rustc (1.31.0~beta.19+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Thu, 29 Nov 2018 22:29:16 -0800 + +rustc (1.31.0~beta.4+dfsg1-1~exp2) experimental; urgency=medium + + * Merge changes from Debian unstable. + + -- Ximin Luo Tue, 06 Nov 2018 19:45:26 -0800 + +rustc (1.31.0~beta.4+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Drop old maintainers from Uploaders. + + -- Ximin Luo Sun, 04 Nov 2018 19:00:16 -0800 + +rustc (1.30.0+dfsg1+llvm-2ubuntu1) disco; urgency=medium + + * Merge from Debian unstable: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + - Adjust debian/watch to include +llvm in upstream version. + + -- Michael Hudson-Doyle Thu, 08 Nov 2018 16:10:16 +1300 + +rustc (1.30.0+dfsg1-2) unstable; urgency=medium + + * Increase FAILURES_ALLOWED for mips mipsel to 20. + * Set debuginfo-only-std = false for 32-bit powerpc architectures. + + -- Ximin Luo Fri, 02 Nov 2018 01:42:36 -0700 + +rustc (1.30.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. (Closes: #881845) + * Increase FAILURES_ALLOWED for mips architectures. + * Set debuginfo-only-std = false for mips architectures. + + -- Ximin Luo Thu, 01 Nov 2018 10:05:52 -0700 + +rustc (1.30.0+dfsg1-1~exp2) experimental; urgency=medium + + * Disable debuginfo-gdb tests relating to enums. These will be fixed in an + upcoming version, see upstream #54614 for details. + + -- Ximin Luo Wed, 31 Oct 2018 00:02:25 -0700 + +rustc (1.30.0+dfsg1-1~exp1) experimental; urgency=medium + + * Actually don't build docs in an arch-only build. + * Add mips patch, hopefully closes #881845 but let's see. + * New upstream release. + + -- Ximin Luo Tue, 30 Oct 2018 22:05:59 -0700 + +rustc (1.30.0~beta.7+dfsg1-1~exp3) experimental; urgency=medium + + * Do the necessary bookkeeping for the LLVM update. + + -- Ximin Luo Wed, 26 Sep 2018 23:29:18 -0700 + +rustc (1.30.0~beta.7+dfsg1-1~exp2) experimental; urgency=medium + + * Tweak test failure rules: armel <= 8, ppc64 <= 12. + * Update to LLVM 7. + + -- Ximin Luo Wed, 26 Sep 2018 21:43:30 -0700 + +rustc (1.30.0~beta.7+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Sun, 23 Sep 2018 10:40:30 -0700 + +rustc (1.29.2+dfsg1+llvm-0ubuntu1) cosmic; urgency=medium + + * Merge with Debian unstable. Remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + - Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an + upgrade issue + - update debian/control + * Adjust debian/watch to include +llvm in upstream version. + * Update to new upstream release. + + -- Michael Hudson-Doyle Thu, 11 Oct 2018 11:49:26 +1300 + +rustc (1.29.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Drop d-armel-disable-kernel-helpers.patch as a necessary part of the + fix to #906520, so it is actually fixed. + * Backport a patch to fix the rand crate on powerpc. (Closes: #909400) + * Lower the s390x allowed failures back to 25. + + -- Ximin Luo Sun, 23 Sep 2018 10:16:53 -0700 + +rustc (1.29.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Include patch for armel atomics. (Closes: #906520) + * Update to latest Standards-Version; no changes required. + + -- Ximin Luo Thu, 20 Sep 2018 22:33:20 -0700 + +rustc (1.28.0+dfsg1+llvm-0ubuntu2) cosmic; urgency=medium + + * Adjust the rustc Breaks/Replaces libstd-rust-dev version to fix an upgrade + issue + - update debian/control + + -- Chris Coulson Tue, 21 Aug 2018 23:31:55 +0100 + +rustc (1.28.0+dfsg1+llvm-0ubuntu1) cosmic; urgency=medium + + * Merge from Debian unstable, remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - On i386, only build debuginfo for libstd + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + - Version the Build-Conflict on gdb-minimal as gdb now Provides it + - update debian/control + + -- Chris Coulson Tue, 14 Aug 2018 21:57:50 +0100 + +rustc (1.28.0+dfsg1-3) unstable; urgency=medium + + * Team upload. + + [ Ximin Luo ] + * More sparc64 fixes, and increase allowed-test-failures there to 180. + + [ Julien Cristau ] + * Don't use pentium4 as i686 baseline (closes: #908561) + + -- Julien Cristau Tue, 11 Sep 2018 15:54:27 +0200 + +rustc (1.28.0+dfsg1-2) unstable; urgency=medium + + * Switch on verbose-tests to restore the old pre-1.28 behaviour, and restore + old failure-counting logic. + * Allow 50 test failures on s390x, restored failure-counting logic avoids + more double-counts. + + -- Ximin Luo Sun, 05 Aug 2018 02:18:10 -0700 + +rustc (1.28.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + * Add patches from Fedora to fix some test failures. + * Ignore a failure testing specific error output, under investigation. + * Allow 100 test failures on s390x, should be reducible later with LLVM 7. + * Temporary fix for mips64el bootstrap. + * Be even more verbose during the build. + * Update to latest Standards-Version. + + -- Ximin Luo Sat, 04 Aug 2018 23:04:41 -0700 + +rustc (1.28.0~beta.14+dfsg1-1~exp2) experimental; urgency=medium + + * Update test-failure counting logic. + * Fix version constraints for Recommends: cargo. + * Add patch to fix sparc64 CABI. + + -- Ximin Luo Fri, 27 Jul 2018 04:26:52 -0700 + +rustc (1.28.0~beta.14+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Update to latest Standards-Version; no changes required. + + -- Ximin Luo Wed, 25 Jul 2018 03:11:11 -0700 + +rustc (1.27.2+dfsg1-1) unstable; urgency=medium + + [ Sylvestre Ledru ] + * Update of the alioth ML address. + + [ Ximin Luo ] + * Fail the build if our version contains ~exp and we are not releasing to + experimental, this has happened by accident a few times already. + * Allow 36 and 44 test failures on armel and s390x respectively. + * New upstream release. + + -- Ximin Luo Tue, 24 Jul 2018 21:35:56 -0700 + +rustc (1.27.1+dfsg1-1~exp4) experimental; urgency=medium + + * Unconditonally prune crate checksums to avoid having to manually prune them + whenever we patch the vendored crates. + + -- Ximin Luo Thu, 19 Jul 2018 14:49:18 -0700 + +rustc (1.27.1+dfsg1-1~exp3) experimental; urgency=medium + + * Add patch from Fedora to fix rebuild against same version. + + -- Ximin Luo Thu, 19 Jul 2018 08:52:03 -0700 + +rustc (1.27.1+dfsg1-1~exp2) experimental; urgency=medium + + * Fix some failing tests. + + -- Ximin Luo Wed, 18 Jul 2018 09:06:44 -0700 + +rustc (1.27.1+dfsg1-1~exp1) unstable; urgency=medium + + * New upstream release. + + -- Ximin Luo Fri, 13 Jul 2018 22:58:02 -0700 + +rustc (1.27.0+dfsg0+llvm-0ubuntu1) cosmic; urgency=medium + + * Update to 1.27.0 + * Bump rustc build requirement to 1.26.0 + - update debian/control + * Rename libstd-rust-1.26 to libstd-rust-1.27 + - update debian/control + - debian/libstd-rust-1.26.lintian-overrides => + debian/libstd-rust-1.27.lintian-overrides + * Update debian/copyright + * Refresh patches + - update debian/patches/u-fixtestignores-ppc64el.patch + - update debian/patches/u-tag-private-modules-with-doc-cfg.patch + - update debian/patches/d-disable-cargo-vendor.patch + - update debian/patches/d-no-web-dependencies-in-doc.patch + * Drop patches that are fixed upstream + - remove debian/patches/u-fix-rustdoc-theme-test-without-rpath.patch + - remove debian/patches/u-fix-fp-target-warning.patch + - update debian/patches/series + * Disable search functionality in the documentation as it depends on + mark.js and elasticlunr.js, both of which are stripped from the tarball + (they are vendored in minified form) and neither of which are packaged + separately in Ubuntu yet + - add debian/patches/d-disable-doc-search.patch + - update debian/patches/series + + -- Chris Coulson Fri, 06 Jul 2018 17:02:31 +0100 + +rustc (1.26.2+dfsg1+llvm-0ubuntu1) cosmic; urgency=medium + + * Merge from Debian unstable, remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests + - update debian/control + - Exclude src/tools/lld from the tarball + - update debian/copyright + - update debian/rules + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - Ensure the build uses the bundled stage0 rustc when bootstrapping + - update debian/rules + - Only build debuginfo for libstd on i386 + - update debian/rules + - Ignore all test failures on every architecture + - update debian/rules + + -- Chris Coulson Thu, 21 Jun 2018 18:22:37 +0100 + +rustc (1.26.2+dfsg1-1) unstable; urgency=medium + + * New upstream release. + * Stop ignoring tests that now pass. + * Don't ignore tests that still fail, instead raise FAILURES_ALLOWED. + This allows us to see the test failures in the build logs, rather than + hiding them. + + -- Ximin Luo Sat, 16 Jun 2018 12:39:59 -0700 + +rustc (1.26.1+dfsg1-3) unstable; urgency=medium + + * Fix build-dep version range to build against myself. + + -- Ximin Luo Thu, 31 May 2018 09:25:17 -0700 + +rustc (1.26.1+dfsg1-2) unstable; urgency=medium + + * Also ignore test_loading_cosine on ppc64el. + + -- Ximin Luo Wed, 30 May 2018 20:58:46 -0700 + +rustc (1.26.1+dfsg1-1) unstable; urgency=medium + + * New upstream release. + + -- Ximin Luo Wed, 30 May 2018 08:18:04 -0700 + +rustc (1.26.0+dfsg1-1~exp4) experimental; urgency=medium + + * Try alternative patch to ignore x86 stdsimd tests suggested by upstream. + * Bump up allowed-test-failures to 8 to account for the fact that we're now + double-counting some failures. + + -- Ximin Luo Tue, 29 May 2018 20:36:56 -0700 + +rustc (1.26.0+dfsg1-1~exp3) experimental; urgency=medium + + * Ignore some irrelevant tests on ppc64 and non-x86 platforms. + + -- Ximin Luo Tue, 29 May 2018 09:32:38 -0700 + +rustc (1.26.0+dfsg1-1~exp2) experimental; urgency=medium + + * Add Breaks+Replaces for older libstd-rust-dev with codegen-backends. + (Closes: #899180) + * Backport some test and packaging fixes from Ubuntu. + + -- Ximin Luo Tue, 22 May 2018 22:00:53 -0700 + +rustc (1.26.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Update to latest Standards-Version; no changes required. + * Update doc-base files. (Closes: #876831) + + -- Ximin Luo Sun, 20 May 2018 03:11:45 -0700 + +rustc (1.25.0+dfsg1-2) unstable; urgency=medium + + * Add patches for LLVM's compiler-rt to fix bugs on sparc64 and mips64. + (Closes: #898982) + * Install codegen-backends into rustc rather than libstd-rust-dev. + (Closes: #899087) + + -- Ximin Luo Sat, 19 May 2018 13:10:33 -0700 + +rustc (1.25.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Allow up to 15 test failures on s390x. + * Set CARGO_INCREMENTAL=0 on sparc64. + + -- Ximin Luo Fri, 18 May 2018 01:11:15 -0700 + +rustc (1.26.1+dfsg0+llvm-0ubuntu1) cosmic; urgency=medium + + * Update to 1.26.1 + * Exclude src/tools/lld from the tarball + - update debian/copyright + - update debian/rules + + -- Chris Coulson Fri, 01 Jun 2018 16:10:34 +0100 + +rustc (1.26.0+dfsg0+llvm-0ubuntu3) cosmic; urgency=medium + + * Backport 'Fix "fp" feature for AArch64', as the console warnings appear + to be making the cargo tests fail + - add debian/patches/u-fix-fp-feature-for-aarch64.patch + - update debian/patches/series + * Drop src/tools/lld from rust-src (can be dropped after the next merge with + Debian when we have an updated tarball) + - update debian/rules + + -- Chris Coulson Fri, 01 Jun 2018 15:40:50 +0100 + +rustc (1.26.0+dfsg0+llvm-0ubuntu2) cosmic; urgency=medium + + * Ignore all test failures on every architecture. If anyone else wants to + spend time getting all of the tests to pass, be my guest + - update debian/rules + + -- Chris Coulson Fri, 25 May 2018 12:57:52 +0100 + +rustc (1.26.0+dfsg0+llvm-0ubuntu1) cosmic; urgency=medium + + * Update to 1.26.0 + * Bump rustc build requirement to 1.25.0 + - update debian/control + * Rename libstd-rust-1.25 to libstd-rust-1.26 + - update debian/control + - debian/libstd-rust-1.25.lintian-overrides => + debian/libstd-rust-1.26.lintian-overrides + * Update debian/copyright + * Refresh patches + - update debian/patches/d-armel-disable-kernel-helpers.patch + - update debian/patches/d-ignore-removed-submodules.patch + - update debian/patches/d-no-web-dependencies-in-doc.patch + - update debian/patches/u-ignoretest-armhf_01.patch + - update debian/patches/u-ignoretest-armhf_02.patch + - update debian/patches/u-ignoretest-armhf_06.patch + - update debian/patches/u-ignoretest-ppc64el.patch + - update debian/patches/u-make-tests-work-without-rpath.patch + * Drop patches that are fixed upstream or no longer applicable + - remove debian/patches/u-gperf-3.1.patch + - remove debian/patches/u-powerpcspe-support.patch + - update debian/patches/series + * No need to generate html_blocks.c now that hoedown is gone + - update debian/rules + * Backport upstream change to ensure that libraries build in stage0 have + unique metadata + - add debian/patches/u-ensure-libraries-built-in-stage0-have-unique-metadata.patch + - update debian/patches/series + * Use the new --remap-path-prefix syntax for stage != 0 and the old syntax for + stage 0 when building with rustc < 1.26 (see upstream issue #50910) + - update debian/rules + + -- Chris Coulson Tue, 15 May 2018 22:11:40 +0100 + +rustc (1.25.0+dfsg1+llvm-0ubuntu3) cosmic; urgency=medium + + * Don't Build-Conflict on gdb-minimal + - update debian/control + + -- Chris Coulson Wed, 16 May 2018 18:02:18 +0100 + +rustc (1.25.0+dfsg1+llvm-0ubuntu2) cosmic; urgency=medium + + * Update to cosmic + + -- Chris Coulson Wed, 16 May 2018 17:51:46 +0100 + +rustc (1.25.0+dfsg1+llvm-0ubuntu1) bionic; urgency=medium + + * Merge from Debian experimental, remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Don't run dynamic_lib::tests::test_loading_cosine on Aarch64 whilst if + fails there + - add debian/patches/u-ignoretest-arm64_02.patch + - update debian/patches/series + - Make test failures fatal, except on ppc64el and s390x, as there's nothing + in the archive yet that requires a working rust on these architectures + - update debian/rules + - Only build debuginfo for libstd on i386 + - update debian/rules + - Ensure the build uses the bundled stage0 rustc when bootstrapping + - update debian/rules + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + - Make RustdocTheme test work on builds where rust.rpath = false + - add debian/patches/u-fix-rustdoc-theme-test-without-rpath.patch + - update debian/patches/series + - Scrub -g from CFLAGS and CXXFLAGS in order to let rustbuild control + whether LLVM is compiled with debug symbols + - update debian/rules + - Build-Depend on libc6-dbg on armhf, to workaround a crash in ld.so + during some debuginfo tests. This isn't a proper fix and needs further + investigation + - update debian/control + - Ignore test failures on Aarch64. Upstream aren't even running tests on + this architecture so let's not care about test failures there + - update debian/rules + + -- Chris Coulson Tue, 10 Apr 2018 16:12:33 +0100 + +rustc (1.25.0+dfsg1-1~exp2) experimental; urgency=medium + + * Install missing codegen-backends. + + -- Ximin Luo Fri, 06 Apr 2018 14:05:36 -0700 + +rustc (1.25.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Update to LLVM 6.0. + + -- Ximin Luo Sun, 01 Apr 2018 15:59:47 +0200 + +rustc (1.24.1+dfsg1+llvm-0ubuntu1) bionic; urgency=medium + + [ Chris Coulson / Rico Tzschichholz ] + * Merge from Debian unstable, remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Don't run dynamic_lib::tests::test_loading_cosine on Aarch64 whilst if + fails there + - add debian/patches/u-ignoretest-arm64_02.patch + - update debian/patches/series + - Make test failures fatal, except on ppc64el and s390x, as there's nothing + in the archive yet that requires a working rust on these architectures + - update debian/rules + - Disable debuginfo when building on 32-bit architectures, as it seems to + be the only way we can get a successful build + - update debian/config.toml.in + - update debian/rules + - Ensure the build uses the bundled stage0 rustc when bootstrapping + - update debian/config.toml.in + - update debian/rules + - Add a hack to ensure the stage0 compiler is extracted to the correct + location + - update debian/make_orig-stage0_tarball.sh + + -- Chris Coulson Fri, 16 Mar 2018 02:16:14 +0000 + +rustc (1.24.1+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + * Raise allowed-test-failures to 160 on some non-release arches: powerpc, + powerpcspe, sparc64, x32. + + -- Ximin Luo Wed, 07 Mar 2018 20:07:27 +0100 + +rustc (1.24.1+dfsg1-1~exp2) experimental; urgency=medium + + * Steal some patches from Fedora to fix some test failures. + * Update debian/patches/u-make-tests-work-without-rpath.patch to try to fix + some more test failures. + + -- Ximin Luo Mon, 05 Mar 2018 16:25:26 +0100 + +rustc (1.24.1+dfsg1-1~exp1) experimental; urgency=medium + + * More sparc64 CABI fixes. (Closes: #888757) + * New upstream release. + * Note that s390x baseline was updated in the meantime. (Closes: #851150) + * Include Debian-specific patch to disable kernel helpers on armel. + (Closes: #891902) + * Include missing build-dependencies for pkg.rustc.dlstage0 build profile. + (Closes: #891022) + * Add architecture.mk mapping for armel => armv5te-unknown-linux-gnueabi. + (Closes: #891913) + * Enable debuginfo-only-std on armel as well. (Closes: #891961) + * Backport upstream patch to support powerpcspe. (Closes: #891542) + * Disable full-bootstrap again to work around upstream #48319. + + -- Ximin Luo Sat, 03 Mar 2018 14:23:29 +0100 + +rustc (1.23.0+dfsg1+llvm-0ubuntu2) bionic; urgency=medium + + * Merge from Debian experimental, remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Don't run dynamic_lib::tests::test_loading_cosine on Aarch64 whilst if + fails there + - add debian/patches/u-ignoretest-arm64_02.patch + - update debian/patches/series + - Make test failures fatal, except on ppc64el and s390x, as there's nothing + in the archive yet that requires a working rust on these architectures + - update debian/rules + - Disable debuginfo when building on 32-bit architectures, as it seems to + be the only way we can get a successful build + - update debian/config.toml.in + - update debian/rules + - Update debian/patches/u-make-tests-work-without-rpath.patch to fix some + test failures + - Backport an upstream change to make the stack overflow detection work + with a recent change in glibc 2.27 that moves the stack guard page for + threads beyond the end of the stack + - add debian/patches/u-stack-guard-glibc-2.27-fix.patch + - update debian/patches/series + + -- Chris Coulson Thu, 01 Feb 2018 13:59:02 +0000 + +rustc (1.23.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable. + + -- Ximin Luo Fri, 19 Jan 2018 11:49:31 +0100 + +rustc (1.23.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Update to latest Standards-Version; no changes required. + + -- Ximin Luo Sun, 14 Jan 2018 00:08:17 +0100 + +rustc (1.22.1+dfsg1-2) unstable; urgency=medium + + * Fix B-D rustc version so this package can be built using itself. + + -- Ximin Luo Mon, 01 Jan 2018 14:27:19 +0100 + +rustc (1.22.1+dfsg1-1) unstable; urgency=medium + + [ Ximin Luo ] + * Remove unimportant files that autoload remote resources from rust-src. + * Fix more symlinks in rust-doc. + * On armhf, only generate debuginfo for libstd and not the compiler itself. + This works around buildds running out of memory, see upstream #45854. + * Update to latest Standards-Version; no changes required. + + [ Chris Coulson ] + * Fix some test failures that occur because we build rust without an rpath. + + -- Ximin Luo Mon, 18 Dec 2017 19:46:25 +0100 + +rustc (1.22.1+dfsg1+llvm-0ubuntu2) bionic; urgency=medium + + * Merge from Debian experimental, remaining changes: + - Use the bundled llvm to avoid having to do llvm updates in order to + deliver rust updates + - update debian/config.toml.in + - update debian/control + - update debian/copyright + - update debian/rules + - Fix some test failures that occur because we build rust without an rpath + - add debian/patches/make-tests-work-without-rpath.patch + - update debian/patches/series + - Don't run dynamic_lib::tests::test_loading_cosine on Aarch64 whilst if + fails there + - add debian/patches/u-ignoretest-arm64_02.patch + - update debian/patches/series + - Make test failures fatal, except on ppc64el and s390x, as there's nothing + in the archive yet that requires a working rust on these architectures + - update debian/rules + - Disable debuginfo when building on 32-bit architectures, as it seems to + be the only way we can get a successful build + - update debian/config.toml.in + - update debian/rules + + -- Chris Coulson Wed, 29 Nov 2017 16:32:51 +0000 + +rustc (1.22.1+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Fix symlink target. (Closes: #877276) + + -- Ximin Luo Sat, 25 Nov 2017 22:29:12 +0100 + +rustc (1.21.0+dfsg1-3) unstable; urgency=medium + + * Add/fix detection for sparc64, thanks to John Paul Adrian Glaubitz. + * Workaround FTBFS when building docs. (Closes: #880262) + + -- Ximin Luo Mon, 06 Nov 2017 10:03:32 +0100 + +rustc (1.21.0+dfsg1+llvm-0ubuntu5) bionic; urgency=medium + + * Merge from Debian unstable, remaining changes: + - Don't run dynamic_lib::tests::test_loading_cosine on Aarch64 whilst if + fails there + - add debian/patches/u-ignoretest-arm64_02.patch + - update debian/patches/series + - Make test failures fatal, except on ppc64el and s390x, as there's nothing + in the archive yet that requires a working rust on these architectures + - update debian/rules + - Use the bundled llvm, as target_feature depends on a rust-specific llvm + API. This also means we have a different tarball to reinclude the llvm + parts, although we could probably do this with a supplementary tarball + in future + - update debian/control + - update debian/rules + - update debian/config.toml.in + - Fix some test failures that occur because we build rust without an rpath + - add debian/patches/make-tests-work-without-rpath.patch + - update debian/patches/series + - Set build.full-bootstrap to true to work-around a runtime link failure + when we're bootstrapping from the same rust version + - update debian/config.toml.in + + -- Chris Coulson Thu, 26 Oct 2017 18:00:24 +0100 + +rustc (1.21.0+dfsg1-2) unstable; urgency=medium + + * Upload to unstable. + * Fix bootstrapping using 1.21.0, which is more strict about redundant &mut + previously used in u-output-failed-commands.patch. + * Only allow up to 5 test failures. + + -- Ximin Luo Wed, 25 Oct 2017 20:27:30 +0200 + +rustc (1.21.0+dfsg1-1) experimental; urgency=medium + + * New upstream release. + * Fix the "install" target for cross-compilations; cross-compiling with + sbuild --host=$foreign-arch should work again. + * Update to latest Standards-Version; changes: + - Priority changed to optional from extra. + + -- Ximin Luo Tue, 17 Oct 2017 00:42:54 +0200 + +rustc (1.20.0+dfsg1-3) unstable; urgency=medium + + * Disable jemalloc to fix FTBFS with 1.21 on armhf. + + -- Ximin Luo Wed, 25 Oct 2017 12:01:19 +0200 + +rustc (1.20.0+dfsg1-2) unstable; urgency=medium + + * Update changelog entry for 1.20.0+dfsg1-1 to reflect that it was actually + and accidentally uploaded to unstable. No harm, no foul. + * We are no longer failing the build when tests fail, see NEWS or + README.Debian for details. + * Bump LLVM requirement to fix some failing tests. + + -- Ximin Luo Sat, 21 Oct 2017 14:20:17 +0200 + +rustc (1.20.0+dfsg1-1) unstable; urgency=medium + + * New upstream release. + + -- Ximin Luo Sun, 15 Oct 2017 23:30:35 +0200 + +rustc (1.19.0+dfsg3-4) unstable; urgency=medium + + * Bump LLVM requirement to pull in a fix for a FTBFS on ppc64el. + + -- Ximin Luo Sun, 15 Oct 2017 21:31:03 +0200 + +rustc (1.20.0+dfsg0-0ubuntu1) artful; urgency=medium + + * Update to 1.20.0 + - update debian/control + - libstd-rust-1.19.lintian-overrides + => libstd-rust-1.20.lintian-overrides + + * update debian/copyright + * Drop patches that are fixed upstream + - remove debian/patches/u-only-run-linkchecker-if-docs.patch + - remove debian/patches/u-skip-main-thread-stack-guard.patch + - remove debian/patches/u-fix-backtrace-build.patch + - remove debian/patches/u-ignoretest-arm64_02.patch + - update debian/patches/series + * Refresh patches + - update debian/patches/u-ignoretest-ppc64el_03.patch + - update debian/patches/u-output-failed-commands.patch + - update debian/patches/u-allow-stable-features.patch + - update debian/patches/gcc-4.8-aarch64-ice.diff + - update debian/patches/d-disable-cargo-vendor.patch + - update debian/patches/d-dont-download-stage0.patch + - update debian/patches/d-cross-compile-install.patch + - update debian/patches/d-no-web-dependencies-in-doc.patch + - update debian/patches/u-fix-unaligned-access-in-lto.patch + * Don't clean any Cargo.toml.orig files from the source tree + - update debian/rules + * Backport change from Debian git to fix prune-unused-deps + * Bump llvm build-dep to 1:4.0.1-6ubuntu0.17.10.3~ to pick up fixes + for llvm PR31142, PR32488 and PR32902 + - update debian/control + * Don't re-run the rustc_llvm build script if LLVM_CONFIG changes, as this + causes a failure when running the tests. This is a workaround - it needs + further investigation + - add debian/patches/dont-rerun-rustc_llvm-build-script-on-LLVM_CONFIG-change.patch + - update debian/patches/series + * Don't run dynamic_lib::tests::test_loading_cosine on Aarch64 whilst if + fails there + - add debian/patches/u-ignoretest-arm64_02.patch + - update debian/patches/series + * Ignore test failures on ppc64el. There's nothing in the archive yet that + requires a working rust on this architecture + - update debian/rules + + -- Chris Coulson Wed, 11 Oct 2017 19:47:47 +0100 + +rustc (1.19.0+dfsg3-3ubuntu1) artful; urgency=medium + + * Merge from Debian, remaining changes: + - Backport patch to fix unaligned access in LTO on armhf + + add debian/patches/u-fix-unaligned-access-in-lto.patch + + update debian/patches/series + + -- Chris Coulson Wed, 11 Oct 2017 14:00:38 +0100 + +rustc (1.19.0+dfsg3-3) unstable; urgency=medium + + * Fix a trailing whitespace for tidy. + + -- Ximin Luo Tue, 19 Sep 2017 16:09:41 +0200 + +rustc (1.19.0+dfsg3-2) unstable; urgency=medium + + * Upload to unstable. + * Add a patch to print extra information when tests fail. + + -- Ximin Luo Tue, 19 Sep 2017 12:32:03 +0200 + +rustc (1.19.0+dfsg3-1) experimental; urgency=medium + + * New upstream release. + * Upgrade to LLVM 4.0. (Closes: #873421) + * rust-src: install Debian patches as well + + -- Ximin Luo Fri, 15 Sep 2017 04:02:09 +0200 + +rustc (1.18.0+dfsg1-4ubuntu1) artful; urgency=medium + + * Backport patch to fix unaligned access in LTO on armhf + - add debian/patches/fix-unaligned-access-in-lto.patch + - update debian/patches/series + + -- Chris Coulson Tue, 15 Aug 2017 14:51:01 +0100 + +rustc (1.18.0+dfsg1-4) unstable; urgency=medium + + * Support gperf 3.1. (Closes: #869610) + + -- Ximin Luo Tue, 25 Jul 2017 23:19:47 +0200 + +rustc (1.18.0+dfsg1-3) unstable; urgency=medium + + * Upload to unstable. + * Disable failing run-make test on armhf. + + -- Ximin Luo Sat, 22 Jul 2017 20:30:25 +0200 + +rustc (1.18.0+dfsg1-2) experimental; urgency=medium + + * Update to latest Standards-Version; no changes required. + * Change rustc to Multi-Arch: allowed and update Build-Depends with :native + annotations. Multi-Arch: foreign is typically for arch-indep packages that + might need to satisfy dependency chains of different architectures. Also + update instructions on cross-compiling to match this newer situation. + * Build debugging symbols for non-libstd parts of rustc. + + -- Ximin Luo Mon, 17 Jul 2017 23:04:03 +0200 + +rustc (1.18.0+dfsg1-1) experimental; urgency=medium + + * New upstream release. + + -- Ximin Luo Tue, 27 Jun 2017 12:51:22 +0200 + +rustc (1.17.0+dfsg2-8) unstable; urgency=medium + + * Workaround for linux #865549, fix FTBFS on ppc64el. + + -- Ximin Luo Mon, 17 Jul 2017 13:41:59 +0200 + +rustc (1.17.0+dfsg2-7) unstable; urgency=medium + + * Show exception traceback in bootstrap.py to examine ppc64el build failure. + + -- Ximin Luo Wed, 21 Jun 2017 10:46:27 +0200 + +rustc (1.17.0+dfsg2-6) unstable; urgency=medium + + * Upload to unstable. + + -- Ximin Luo Wed, 21 Jun 2017 00:24:22 +0200 + +rustc (1.17.0+dfsg2-5) experimental; urgency=medium + + * More work-arounds for armhf test failures. + + -- Ximin Luo Fri, 16 Jun 2017 13:27:45 +0200 + +rustc (1.17.0+dfsg2-4) experimental; urgency=medium + + * Fix arch-indep and arch-dep tests. + * Bump the LLVM requirement to fix FTBFS on armhf. + + -- Ximin Luo Wed, 14 Jun 2017 21:37:16 +0200 + +rustc (1.17.0+dfsg2-3) experimental; urgency=medium + + * Try to force the real gdb package. Some resolvers like aspcud will select + gdb-minimal under some circumstances, but this causes the debuginfo-gdb + tests to break. + + -- Ximin Luo Wed, 14 Jun 2017 00:48:37 +0200 + +rustc (1.17.0+dfsg2-2) experimental; urgency=medium + + * Support and document cross-compiling of rustc itself. + * Document cross-compiling other rust packages such as cargo. + * Work around upstream #39015 by disabling those tests rather than by + disabling optimisation, which causes FTBFS on 1.17.0 ppc64el. See + upstream #42476 and #42532 for details. + + -- Ximin Luo Tue, 13 Jun 2017 21:13:31 +0200 + +rustc (1.17.0+dfsg2-1) experimental; urgency=medium + + [ Sylvestre Ledru ] + * New upstream release + + [ Ximin Luo ] + * Adapt packaging for rustbuild, the new upstream cargo-based build system. + + [ Matthijs van Otterdijk ] + * Add a binary package, rust-src. (Closes: #846177) + * Link to local Debian web resources in the docs, instead of remote ones. + + -- Ximin Luo Tue, 16 May 2017 18:00:53 +0200 + +rustc (1.16.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable so we have something to build 1.17 with. + * Update u-ignoretest-powerpc.patch for 1.16. + + -- Ximin Luo Wed, 19 Apr 2017 22:47:18 +0200 + +rustc (1.16.0+dfsg1-1~exp2) experimental; urgency=medium + + * Don't ignore test failures on Debian unstable. + * Re-fix ignoring armhf test, accidentally reverted in previous version. + * Try to fix buildd failure by swapping B-D alternatives. + + -- Ximin Luo Sun, 16 Apr 2017 15:05:47 +0200 + +rustc (1.16.0+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release + * u-ignoretest-jemalloc.patch removed (applied upstream) + + [ Matthias Klose ] + * Bootstrap using the rustc version in the archive, on all architectures. + * Work around a GCC 4.8 ICE on AArch64. + * Use alternative build dependencies on cmake3 and binutils-2.26 for + builds on 14.04 LTS (trusty). + * debian/make_orig*dl_tarball.sh: Include all Ubuntu architectures. + * debian/rules: Ignore test results for now. + + -- Sylvestre Ledru Thu, 13 Apr 2017 15:24:03 +0200 + +rustc (1.15.1+dfsg1-1) unstable; urgency=medium + + * Upload to unstable so we have something to build 1.16 with. + * Try to fix ignoring atomic-lock-free tests on armhf. + + -- Ximin Luo Wed, 22 Mar 2017 00:13:27 +0100 + +rustc (1.15.1+dfsg1-1~exp3) experimental; urgency=medium + + * Ignore atomic-lock-free tests on armhf. + * Update ignoretest-armhf_03.patch for newer 1.15.1 behaviour. + * Tidy up some other patches to do with ignoring tests. + + -- Ximin Luo Sun, 12 Mar 2017 04:15:33 +0100 + +rustc (1.15.1+dfsg1-1~exp2) experimental; urgency=medium + + * Update armhf ignoretest patch. + * Bootstrap armhf. (Closes: #809316, #834003) + * Bootstrap ppc4el. (Closes: #839643) + * Fix rust-lldb symlink. (Closes: #850639) + + -- Ximin Luo Thu, 02 Mar 2017 23:01:26 +0100 + +rustc (1.15.1+dfsg1-1~exp1) experimental; urgency=medium + + * New upstream release (won't probably be in stretch). + see the 1.4 git branch for the follow up for stable + * Call to the test renamed from check-notidy => check + * d/p/u-destdir-support.diff: Apply upstream patch to support + destdir in the make install (for rustbuild, in later versions) + * Overrides the 'binary-or-shlib-defines-rpath' lintian warnings. + We need them for now + * Refresh of the patches + + [ Sven Joachim ] + * Drop Pre-Depends on multiarch-support. (Closes: #856109) + + [ Erwan Prioul ] + * Fix test and build failures for ppc64el. (Closes: #839643) + + [ Ximin Luo ] + * Disable rustbuild for the time being (as it was in 1.14) and instead + bootstrap two new arches, armhf and ppc64el. + * Switch back to debhelper 9 to make backporting easier. + * Switch Build-Depends on binutils-multiarch back to binutils, the former is + no longer needed by the upstream tests. + + [ Matthias Klose ] + * Compatibility fixes and improvements to help work better on Ubuntu. + + -- Sylvestre Ledru Sun, 26 Feb 2017 21:12:27 +0100 + +rustc (1.14.0+dfsg1-3) unstable; urgency=medium + + * Fix mips64 Makefile patches. + * Don't run arch-dep tests in a arch-indep build. + + -- Ximin Luo Wed, 04 Jan 2017 21:34:56 +0100 + +rustc (1.14.0+dfsg1-2) unstable; urgency=medium + + * Update README.Debian, the old one was way out of date. + * Detect mips CPUs in ./configure and fill in mips Makefile rules. + * Work around jemalloc-related problems in the upstream bootstrapping + binaries for arm64, ppc64el, s390x. + * Disable jemalloc on s390x - upstream already disable it for some other + arches. + * Disable jemalloc tests for arches where jemalloc is disabled. + * We still expect the following failures: + * arm64 should be fixed (i.e. no failures) compared to the previous upload. + * armhf will FTBFS due to 'Illegal instruction' and this can only be fixed + with the next stable rustc release. + * mips mipsel mips64el ppc64 ppc64el s390x will FTBFS due to yet other + test failures beyond the ones I fixed above; this upload is only to save + me manual work in producing nice reports that exhibit these failures. + + -- Ximin Luo Thu, 29 Dec 2016 23:00:47 +0100 + +rustc (1.14.0+dfsg1-1) unstable; urgency=medium + + [ Sylvestre Ledru ] + * New upstream release + * Update debian/watch + + [ Ximin Luo ] + * Try to bootstrap armhf ppc64 ppc64el s390x mips mipsel mips64el. + (Closes: #809316, #834003, #839643) + * Make rust-gdb and rust-lldb arch:all packages. + * Switch to debhelper 10. + + -- Ximin Luo Sat, 24 Dec 2016 18:03:03 +0100 + +rustc (1.13.0+dfsg1-2) unstable; urgency=high + + * Skip macro-stepping test on arm64, until + https://github.com/rust-lang/rust/issues/37225 is resolved. + + -- Luca Bruno Sat, 26 Nov 2016 23:40:14 +0000 + +rustc (1.13.0+dfsg1-1) unstable; urgency=medium + + [ Sylvestre Ledru ] + * New upstream release. + + [ Ximin Luo ] + * Use Debian system jquery instead of upstream's embedded copy. + + -- Sylvestre Ledru Fri, 11 Nov 2016 13:35:23 +0100 + +rustc (1.12.1+dfsg1-1) unstable; urgency=medium + + [ Sylvestre Ledru ] + * New (minor) upstream release + * Missing dependency from rust-lldb to python-lldb-3.8 (Closes: #841833) + * Switch to llvm 3.9. (Closes: #841834) + + [ Ximin Luo ] + * Dynamically apply rust-boot-1.12.1-from-1.12.0.diff. + This allows us to bootstrap from either 1.11.0 or 1.12.0. + * Bump LLVM Build-Depends version to get the backported patches for LLVM + #30402 and #29163. + * Install debugger_pretty_printers_common to rust-gdb and rust-lldb. + (Closes: #841835) + + -- Ximin Luo Mon, 07 Nov 2016 14:15:14 +0100 + +rustc (1.12.0+dfsg1-2) unstable; urgency=medium + + * Ignore test run-make/no-duplicate-libs. Fails on i386 + * Ignore test run-pass-valgrind/down-with-thread-dtors.rs . Fails on arm64 + * I am not switching to llvm 3.9 now because a test freezes. The plan is + to silent the warning breaking the build and upload 1.12.1 after + + -- Sylvestre Ledru Wed, 05 Oct 2016 10:48:01 +0200 + +rustc (1.12.0+dfsg1-1) unstable; urgency=medium + + * new upstream release + - Rebase of the patches and removal of deprecated patches + + -- Sylvestre Ledru Thu, 29 Sep 2016 20:45:04 +0200 + +rustc (1.11.0+dfsg1-3) unstable; urgency=medium + + * Fix separate build-arch and build-indep builds. + + -- Ximin Luo Tue, 13 Sep 2016 12:30:41 +0200 + +rustc (1.11.0+dfsg1-2) unstable; urgency=medium + + * Fix rebuilding against the current version, by backporting a patch I wrote + that was already applied upstream. Should fix the FTBFS that was observed + by tests.reproducible-builds.org. + * Ignore a failing stdcall test on arm64; should fix the FTBFS there. + * Backport a doctest fix I wrote, already applied upstream. + + -- Ximin Luo Mon, 12 Sep 2016 17:40:12 +0200 + +rustc (1.11.0+dfsg1-1) unstable; urgency=medium + + * New upstream release + * Add versioned binutils dependency. (Closes: #819475, #823540) + + -- Ximin Luo Wed, 07 Sep 2016 10:31:57 +0200 + +rustc (1.10.0+dfsg1-3) unstable; urgency=medium + + * Rebuild with LLVM 3.8, same as what upstream are using + * Dynamically link against LLVM. (Closes: #832565) + + -- Ximin Luo Sat, 30 Jul 2016 22:36:41 +0200 + +rustc (1.10.0+dfsg1-2) unstable; urgency=medium + + * Tentatively support ARM architectures + * Include upstream arm64,armel,armhf stage0 compilers (i.e. 1.9.0 stable) + in a orig-dl tarball, like how we previously did for amd64,i386. + + -- Ximin Luo Fri, 22 Jul 2016 15:54:51 +0200 + +rustc (1.10.0+dfsg1-1) unstable; urgency=medium + + * New upstream release + * Add myself to uploaders + * Update our build process to bootstrap from the previous Debian rustc stable + version by default. See README.Debian for other options. + * Update to latest Standards-Version; no changes required. + + -- Ximin Luo Sun, 17 Jul 2016 03:40:49 +0200 + +rustc (1.9.0+dfsg1-1) unstable; urgency=medium + + * New upstream release (Closes: #825752) + + -- Sylvestre Ledru Sun, 29 May 2016 17:57:38 +0200 + +rustc (1.8.0+dfsg1-1) unstable; urgency=medium + + * New upstream release + + [ Ximin Luo ] + * Fix using XZ for the orig tarball: needs explicit --repack in debian/watch + * Drop wno-error patch; applied upstream. + + -- Sylvestre Ledru Fri, 15 Apr 2016 12:01:45 +0200 + +rustc (1.7.0+dfsg1-1) unstable; urgency=medium + + * New upstream release + + -- Sylvestre Ledru Thu, 03 Mar 2016 22:41:24 +0100 + +rustc (1.6.0+dfsg1-3) unstable; urgency=medium + + * Apply upstream fix to silent a valgrind issue in the test suite + (Closes: ##812825) + * Add gcc & libc-dev as dependency of rustc to make sure it works + out of the box + + [ Ximin Luo ] + * Work around rust bug https://github.com/rust-lang/rust/issues/31529 + * Enable optional tests, and add verbosity/backtraces to tests + * Use XZ instead of GZ compression (will apply to the next new upload) + + -- Sylvestre Ledru Tue, 02 Feb 2016 15:08:11 +0100 + +rustc (1.6.0+dfsg1-2) unstable; urgency=medium + + * mk/rt.mk: Modify upstream code to append -Wno-error rather than trying + to remove the string "-Werror". (Closes: #812448) + * Disable new gcc-6 "-Wmisleading-indentation" warning, which triggers + (incorrectly) on src/rt/miniz.c. (Closes: #811573) + * Guard arch-dependent dh_install commands appropriately, fixing + arch-indep-only builds. (Closes: #809124) + + -- Angus Lees Tue, 26 Jan 2016 05:40:14 +1100 + +rustc (1.6.0+dfsg1-1) unstable; urgency=medium + + * new upstream release + + [ Ximin Luo ] + * Use secure links for Vcs-* fields. + + -- Sylvestre Ledru Fri, 22 Jan 2016 10:56:08 +0100 + +rustc (1.5.0+dfsg1-1) unstable; urgency=medium + + * New upstream release + - We believe that we should let rust transit to testing + (Closes: #786836) + * Move away from hash to the same rust naming schema + + -- Sylvestre Ledru Thu, 10 Dec 2015 17:23:32 +0100 + +rustc (1.4.0+dfsg1-1) unstable; urgency=medium + + * New upstream release + 198068b3 => 1bf6e69c + * Update the download url in debian/watch + + -- Sylvestre Ledru Fri, 30 Oct 2015 09:36:02 +0100 + +rustc (1.3.0+dfsg1-1) unstable; urgency=medium + + * New upstream release + 62abc69f => 198068b3 + * jquery updated from 2.1.0 to 2.1.4 + + [ Ximin Luo ] + * Use LLVM 3.7 as upstream does, now that it's released. (Closes: #797626) + * Fix debian/copyright syntax mistakes. + * Don't Replace/Break previous versions of libstd-rust-* + * Check that the libstd-rust-* name in d/control matches upstream. + * Several other minor build tweaks. + + -- Sylvestre Ledru Sat, 19 Sep 2015 14:39:35 +0200 + +rustc (1.2.0+dfsg1-1) unstable; urgency=medium + + * New upstream release + libstd-rust-7d23ff90 => libstd-rust-62abc69f + * Add llvm-3.6-tools to the build dep as it is + now needed for tests + * Fix the Vcs-Browser value + + -- Sylvestre Ledru Sat, 08 Aug 2015 23:13:44 +0200 + +rustc (1.1.0+dfsg1-3) unstable; urgency=medium + + * rust-{gdb,lldb} now Replaces pre-split rustc package. + Closes: #793433. + * Several minor lintian cleanups. + + -- Angus Lees Fri, 24 Jul 2015 17:47:48 +1000 + +rustc (1.1.0+dfsg1-2) unstable; urgency=medium + + [ Angus Lees ] + * Replace remote Rust logo with local file in HTML docs. + * Symlink rust-{gdb,lldb}.1 to {gdb,lldb}.1 manpages. + Note that gdb.1 requires the gdb-doc package, and that lldb.1 doesn't + exist yet (see #792908). + * Restore "Architecture: amd64 i386" filter, mistakenly removed in + previous version. Unfortunately the toolchain bootstrap isn't ready + to support all Debian archs yet. Closes: #793147. + + -- Angus Lees Wed, 22 Jul 2015 09:51:08 +1000 + +rustc (1.1.0+dfsg1-1) unstable; urgency=low + + [ Angus Lees ] + * Set SONAME when building dylibs + * Split out libstd-rust, libstd-rust-dev, rust-gdb, rust-lldb from rustc + - libs are now installed into multiarch-friendly locations + - rpath is no longer required to use dylibs (but talk to Debian Rust + maintainers before building a package that depends on the dylibs) + * Install /usr/share/rustc/architecture.mk, which declares Rust arch + triples for Debian archs and is intended to help future Rust packaging + efforts. Warning: it may not be complete/accurate yet. + * New upstream release (1.1) + + -- Angus Lees Thu, 16 Jul 2015 14:23:47 +1000 + +rustc (1.0.0+dfsg1-1) unstable; urgency=medium + + [ Angus Lees ] + * New upstream release (1.0!) + + [ Sylvestre Ledru ] + * Fix the watch file + * Update of the repack to remove llvm sources + + -- Sylvestre Ledru Sat, 16 May 2015 08:24:32 +1000 + +rustc (1.0.0~beta.4-1~exp1) experimental; urgency=low + + [ Angus Lees ] + * New upstream release (beta 3) + - Drop manpage patch - now included upstream + * Replace duplicated compile-time dylibs with symlinks to run-time libs + (reduces installed size by ~68MB) + + [ Sylvestre Ledru ] + * New upstream release (beta 4) + * Replace two more occurrences of jquery by the package + * Repack upstream to remove an LLVM file with a non-DFSG license + + -- Sylvestre Ledru Wed, 06 May 2015 11:14:30 +0200 + +rustc (1.0.0~alpha.2-1~exp1) experimental; urgency=low + + [ Angus Lees ] + * Patch upstream manpages to address minor troff issues + * Make 'debian/rules clean' also clean LLVM source + * Rename primary 'rust' binary package to 'rustc' + * Fix potential FTBFS: rust-doc requires texlive-fonts-recommended (for + pzdr.tfm) + * Build against system LLVM + + [ Sylvestre Ledru ] + * New testing release + * Renaming of the source package + * Set a minimal version for dpkg-dev and debhelper (for profiles) + * For now, disable build profiles as they are not supported in Debian + * Introduce some changes by Angus Lees + - Introduction of build stages + - Disable the parallel execution of tests + - Improving of the parallel syntax + - Use override_dh_auto_build-arch + - Use override_dh_auto_build-indep + - Better declarations of the doc + - Update of the description + - Watch file updated (with key check) + + [ Luca Bruno ] + * rules: respect 'nocheck' DEB_BUILD_OPTIONS + + -- Sylvestre Ledru Sat, 07 Mar 2015 09:25:47 +0100 + +rust (1.0.0~alpha-0~exp1) experimental; urgency=low + + * Initial package (Closes: #689207) + Work done by Luca Bruno, Jordan Justen and Sylvestre Ledru + + -- Sylvestre Ledru Fri, 23 Jan 2015 15:47:37 +0100 diff -Nru rustc-1.56.0+dfsg1+llvm/debian/changelog.rej rustc-1.57.0+dfsg1+llvm/debian/changelog.rej --- rustc-1.56.0+dfsg1+llvm/debian/changelog.rej 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/changelog.rej 2022-01-19 22:55:15.000000000 +0000 @@ -0,0 +1,15 @@ +--- debian/changelog 2021-12-13 21:24:02.000000000 +0000 ++++ debian/changelog 2022-01-18 10:25:30.000000000 +0000 +@@ -1,3 +1,12 @@ ++rustc (1.56.0+dfsg1+llvm-2ubuntu2) jammy; urgency=medium ++ ++ * debian/patches/u-ensure-aarch64-lse-object-files-have-distinct-names-in-an-archive.patch: ++ Backport patch from upstream, to fix "error: object name conflicts in ++ archive" when building rust programs on arm64 (librsvg is currently ++ affected). ++ ++ -- Iain Lane Tue, 18 Jan 2022 10:25:30 +0000 ++ + rustc (1.56.0+dfsg1+llvm-2ubuntu1) jammy; urgency=medium + + * Merge 1.56.0+dfsg1-2 from Debian unstable. (LP: #1952104) diff -Nru rustc-1.56.0+dfsg1+llvm/debian/control rustc-1.57.0+dfsg1+llvm/debian/control --- rustc-1.56.0+dfsg1+llvm/debian/control 2021-12-16 01:31:27.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/control 2022-01-21 03:41:55.000000000 +0000 @@ -14,8 +14,8 @@ dpkg-dev (>= 1.17.14), python3:native, cargo:native (>= 0.40.0) , - rustc:native (>= 1.55.0+dfsg) , - rustc:native (<= 1.56.0++) , + rustc:native (>= 1.56.0+dfsg) , + rustc:native (<= 1.57.0++) , cmake (>= 3.0) | cmake3, # needed by some vendor crates pkg-config, @@ -75,7 +75,7 @@ generic programming and meta-programming, in both static and dynamic styles. -Package: libstd-rust-1.56 +Package: libstd-rust-1.57 Section: libs Architecture: any Multi-Arch: same @@ -102,7 +102,7 @@ Architecture: any Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends}, - libstd-rust-1.56 (= ${binary:Version}), + libstd-rust-1.57 (= ${binary:Version}), Description: Rust standard libraries - development files Rust is a curly-brace, block-structured expression language. It visually resembles the C language family, but differs significantly @@ -209,7 +209,7 @@ Architecture: any Multi-Arch: allowed Depends: ${misc:Depends}, ${shlibs:Depends}, - libstd-rust-1.56 (= ${binary:Version}) + libstd-rust-1.57 (= ${binary:Version}) Recommends: cargo Description: Rust linter Rust is a curly-brace, block-structured expression language. It diff -Nru rustc-1.56.0+dfsg1+llvm/debian/copyright rustc-1.57.0+dfsg1+llvm/debian/copyright --- rustc-1.56.0+dfsg1+llvm/debian/copyright 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/copyright 2022-01-19 22:25:19.000000000 +0000 @@ -49,7 +49,9 @@ vendor/adler-0.2.3 vendor/always-assert vendor/anyhow-1.0.34 + vendor/anyhow-1.0.42 vendor/anymap + vendor/arbitrary vendor/ar vendor/arrayvec-0.7.0 vendor/autocfg-1.0.0 @@ -62,6 +64,7 @@ vendor/cargo_metadata-0.8.2 vendor/cargo_metadata vendor/cargo-platform + vendor/cc-1.0.69 vendor/chalk-derive vendor/chalk-ir vendor/chalk-recursive @@ -86,20 +89,19 @@ vendor/crossbeam-channel-0.5.0 vendor/crossbeam-utils-0.8.3 vendor/crypto-hash - vendor/curl - vendor/curl-sys vendor/dashmap + vendor/derive_arbitrary vendor/derive_more vendor/directories + vendor/dissimilar vendor/dot vendor/drop_bomb vendor/either-1.6.0 vendor/enum-iterator vendor/enum-iterator-derive vendor/env_logger-0.6.2 - vendor/env_logger-0.8.1 vendor/env_logger - vendor/expect-test-1.0.1 + vendor/expect-test vendor/filetime-0.2.14 vendor/flate2-1.0.16 vendor/foreign-types @@ -134,8 +136,6 @@ vendor/inotify vendor/inotify-sys vendor/instant-0.1.6 - vendor/itertools-0.10.0 - vendor/itertools vendor/itoa-0.4.6 vendor/jod-thread vendor/json @@ -156,7 +156,6 @@ vendor/libmimalloc-sys vendor/libnghttp2-sys vendor/libssh2-sys - vendor/libz-sys vendor/linked-hash-map vendor/lock_api-0.4.1 vendor/lsp-codec @@ -176,11 +175,12 @@ vendor/once_cell-1.7.2 vendor/oorandom vendor/openssl - vendor/openssl-probe vendor/openssl-src - vendor/openssl-sys vendor/ordslice + vendor/os_info vendor/parity-tokio-ipc + vendor/parking_lot-0.11.1 + vendor/parking_lot_core-0.8.3 vendor/paste vendor/percent-encoding-1.0.1 vendor/perf-event @@ -194,11 +194,10 @@ vendor/pulldown-cmark-to-cmark vendor/quote-1.0.7 vendor/racer - vendor/rand_xoshiro + vendor/rand_xoshiro-0.4.0 vendor/rayon-1.3.1 vendor/rayon-core-1.7.1 vendor/regalloc - vendor/regex vendor/region vendor/rls-vfs vendor/rowan @@ -220,11 +219,10 @@ vendor/rustc-ap-rustc_session vendor/rustc-ap-rustc_span vendor/rustc-ap-rustc_target - vendor/rustc-demangle-0.1.20 + vendor/rustc_version-0.3.3 vendor/rustc_version vendor/salsa vendor/salsa-macros - vendor/schannel vendor/security-framework vendor/security-framework-sys vendor/semver-0.9.0 @@ -241,9 +239,9 @@ vendor/signal-hook-registry vendor/sized-chunks vendor/slab + vendor/smallvec-1.6.1 vendor/smol_str vendor/snap-1.0.1 - vendor/socket2 vendor/strip-ansi-escapes vendor/syn-1.0.65 vendor/synstructure-0.12.4 @@ -260,17 +258,16 @@ vendor/tokio-stream vendor/tokio-util vendor/tower-service - vendor/tracing-0.1.25 - vendor/tracing-attributes-0.1.13 - vendor/tracing-core-0.1.17 + vendor/tracing-attributes-0.1.16 + vendor/tracing-core-0.1.20 vendor/tracing-subscriber-0.2.16 + vendor/tracing-tree-0.1.9 vendor/ungrammar vendor/unicode-bidi-0.3.4 vendor/unicode-normalization-0.1.13 vendor/unicode-segmentation-1.6.0 vendor/url-1.7.2 vendor/utf8parse - vendor/vcpkg vendor/vergen vendor/vte vendor/walkdir-2.3.1 diff -Nru rustc-1.56.0+dfsg1+llvm/debian/libstd-rust-1.56.install rustc-1.57.0+dfsg1+llvm/debian/libstd-rust-1.56.install --- rustc-1.56.0+dfsg1+llvm/debian/libstd-rust-1.56.install 2021-12-16 01:31:27.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/libstd-rust-1.56.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/${DEB_HOST_MULTIARCH}/ diff -Nru rustc-1.56.0+dfsg1+llvm/debian/libstd-rust-1.56.lintian-overrides rustc-1.57.0+dfsg1+llvm/debian/libstd-rust-1.56.lintian-overrides --- rustc-1.56.0+dfsg1+llvm/debian/libstd-rust-1.56.lintian-overrides 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/libstd-rust-1.56.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -# "libstd" just seemed too generic -libstd-rust-1.56 binary: package-name-doesnt-match-sonames -libstd-rust-1.56 binary: sharedobject-in-library-directory-missing-soname - -# Rust doesn't use dev shlib symlinks nor any of the other shlib support stuff -libstd-rust-1.56 binary: dev-pkg-without-shlib-symlink -libstd-rust-1.56 binary: shlib-without-versioned-soname -libstd-rust-1.56 binary: unused-shlib-entry-in-control-file - -# Libraries that use libc symbols (libterm, libstd, etc) *are* linked -# to libc. Lintian gets upset that some Rust libraries don't need -# libc, boo hoo. -libstd-rust-1.56 binary: library-not-linked-against-libc diff -Nru rustc-1.56.0+dfsg1+llvm/debian/libstd-rust-1.57.install rustc-1.57.0+dfsg1+llvm/debian/libstd-rust-1.57.install --- rustc-1.56.0+dfsg1+llvm/debian/libstd-rust-1.57.install 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/libstd-rust-1.57.install 2022-01-21 03:41:55.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/${DEB_HOST_MULTIARCH}/ diff -Nru rustc-1.56.0+dfsg1+llvm/debian/libstd-rust-1.57.lintian-overrides rustc-1.57.0+dfsg1+llvm/debian/libstd-rust-1.57.lintian-overrides --- rustc-1.56.0+dfsg1+llvm/debian/libstd-rust-1.57.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/libstd-rust-1.57.lintian-overrides 2022-01-19 22:25:19.000000000 +0000 @@ -0,0 +1,13 @@ +# "libstd" just seemed too generic +libstd-rust-1.57 binary: package-name-doesnt-match-sonames +libstd-rust-1.57 binary: sharedobject-in-library-directory-missing-soname + +# Rust doesn't use dev shlib symlinks nor any of the other shlib support stuff +libstd-rust-1.57 binary: dev-pkg-without-shlib-symlink +libstd-rust-1.57 binary: shlib-without-versioned-soname +libstd-rust-1.57 binary: unused-shlib-entry-in-control-file + +# Libraries that use libc symbols (libterm, libstd, etc) *are* linked +# to libc. Lintian gets upset that some Rust libraries don't need +# libc, boo hoo. +libstd-rust-1.57 binary: library-not-linked-against-libc diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-0000-ignore-removed-submodules.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-0000-ignore-removed-submodules.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-0000-ignore-removed-submodules.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-0000-ignore-removed-submodules.patch 2022-01-19 22:25:19.000000000 +0000 @@ -15,7 +15,7 @@ 9 files changed, 7 insertions(+), 63 deletions(-) diff --git a/Cargo.toml b/Cargo.toml -index 626f9ae..36d39f9 100644 +index 8d6afd2..382e49f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,22 +17,12 @@ members = [ @@ -40,10 +40,10 @@ - "src/tools/expand-yaml-anchors", "src/tools/jsondocck", "src/tools/html-checker", - "src/tools/lld-wrapper", -@@ -87,25 +77,9 @@ gimli.debug = 0 - miniz_oxide.debug = 0 - object.debug = 0 + "src/tools/bump-stage0", +@@ -98,25 +88,9 @@ debug = 0 + # Only use debuginfo=1 to further reduce compile times. + bootstrap.debug = 1 -# We want the RLS to use the version of Cargo that we've got vendored in this -# repository to ensure that the same exact version of Cargo is used by both the @@ -68,10 +68,10 @@ # See comments in `library/rustc-std-workspace-core/README.md` for what's going on # here diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py -index e34768b..042c4e4 100644 +index 2594703..45f75fc 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py -@@ -934,10 +934,6 @@ class RustBuild(object): +@@ -961,10 +961,6 @@ class RustBuild(object): os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")] for _ in range(0, self.verbose): args.append("--verbose") @@ -83,7 +83,7 @@ def build_triple(self): diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs -index 5911309..1bf9b28 100644 +index ac1841b..83ab200 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -481,7 +481,6 @@ impl<'a> Builder<'a> { @@ -102,7 +102,7 @@ dist::BuildManifest, dist::ReproducibleArtifacts, ), -@@ -1509,10 +1507,7 @@ impl<'a> Builder<'a> { +@@ -1503,10 +1501,7 @@ impl<'a> Builder<'a> { } } @@ -115,7 +115,7 @@ } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs -index c871411..2e0e73d 100644 +index 6f2470b..3c1f794 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -76,7 +76,6 @@ macro_rules! book { @@ -127,10 +127,10 @@ EmbeddedBook, "src/doc/embedded-book", "embedded-book", submodule; Nomicon, "src/doc/nomicon", "nomicon", submodule; diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs -index d12e86b..927d56a 100644 +index 8594fa4..869d3a9 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs -@@ -1848,17 +1848,7 @@ impl Step for RustcGuide { +@@ -1846,17 +1846,7 @@ impl Step for RustcGuide { } fn run(self, builder: &Builder<'_>) { @@ -150,23 +150,23 @@ } diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml -index 16b6c20..e67910c 100644 +index ba3ed30..c2d77e9 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml -@@ -40,11 +40,6 @@ syn = { version = "1", features = ["full"] } +@@ -34,11 +34,6 @@ regex = "1.5" # This is used by the `collect-metadata` alias. filetime = "0.2" -# A noop dependency that changes in the Rust repository, it's a bit of a hack. -# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` -# for more information. --rustc-workspace-hack = "1.0.0" +-rustc-workspace-hack = "1.0" - - [build-dependencies] - rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } - + # UI test dependencies + clippy_utils = { path = "clippy_utils" } + derive-new = "0.5" diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml -index 81e3e26..049b105 100644 +index 7b4667c..39ef766 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -42,10 +42,10 @@ regex = "1.0" @@ -206,10 +206,10 @@ match cmd.exec() { Ok(metadata) => Ok(metadata), diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs -index 5f1267f..738f9f6 100644 +index c1719a9..81ba94e 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs -@@ -265,8 +265,8 @@ const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[ +@@ -267,8 +267,8 @@ const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[ // These two crates take quite a long time to build, so don't allow two versions of them // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times // under control. diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-0001-disable-miniz.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-0001-disable-miniz.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-0001-disable-miniz.patch 2021-10-26 02:55:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-0001-disable-miniz.patch 2022-01-19 22:25:19.000000000 +0000 @@ -7,10 +7,10 @@ 1 file changed, 4 deletions(-) diff --git a/vendor/flate2/Cargo.toml b/vendor/flate2/Cargo.toml -index 5352fb5..d3639ab 100644 +index 28649e8..1545c01 100644 --- a/vendor/flate2/Cargo.toml +++ b/vendor/flate2/Cargo.toml -@@ -45,10 +45,6 @@ version = "1.1.0" +@@ -44,10 +44,6 @@ version = "1.1.0" optional = true default-features = false diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-0003-mdbook-strip-embedded-libs.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-0003-mdbook-strip-embedded-libs.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-0003-mdbook-strip-embedded-libs.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-0003-mdbook-strip-embedded-libs.patch 2022-01-19 22:25:19.000000000 +0000 @@ -14,10 +14,10 @@ 7 files changed, 24 insertions(+), 202 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs -index 8cbe0a0..55a4116 100644 +index 94ebbb3..6617bec 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs -@@ -179,7 +179,15 @@ impl Checker { +@@ -193,7 +193,15 @@ impl Checker { fn check(&mut self, file: &Path, report: &mut Report) { let (pretty_path, entry) = self.load_file(file, report); let source = match entry { @@ -34,7 +34,7 @@ FileEntry::Dir => unreachable!("never with `check` path"), FileEntry::OtherFile => return, FileEntry::Redirect { .. } => return, -@@ -244,6 +252,12 @@ impl Checker { +@@ -258,6 +266,12 @@ impl Checker { let (target_pretty_path, target_entry) = self.load_file(&path, report); let (target_source, target_ids) = match target_entry { FileEntry::Missing => { diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-0004-cc-psm-rebuild-wasm32.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-0004-cc-psm-rebuild-wasm32.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-0004-cc-psm-rebuild-wasm32.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-0004-cc-psm-rebuild-wasm32.patch 2022-01-19 22:25:19.000000000 +0000 @@ -8,10 +8,10 @@ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/vendor/cc/src/lib.rs b/vendor/cc/src/lib.rs -index b62a1da..819506e 100644 +index 2de2457..916144d 100644 --- a/vendor/cc/src/lib.rs +++ b/vendor/cc/src/lib.rs -@@ -2075,7 +2075,7 @@ impl Build { +@@ -2173,7 +2173,7 @@ impl Build { || target == "wasm32-unknown-wasi" || target == "wasm32-unknown-unknown" { diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-0005-clippy-feature-sync.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-0005-clippy-feature-sync.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-0005-clippy-feature-sync.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-0005-clippy-feature-sync.patch 2022-01-19 22:25:19.000000000 +0000 @@ -5,25 +5,33 @@ enable features needed by rustfmt to make build system happy and speedup build. this is what rustc_workspace_hack does in the upstream build. --- - src/tools/clippy/Cargo.toml | 2 +- + src/tools/clippy/Cargo.toml | 3 +-- src/tools/rustfmt/Cargo.toml | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml -index e67910c..781600f 100644 +index c2d77e9..b600631 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml -@@ -36,7 +36,7 @@ serde = { version = "1.0", features = ["derive"] } - derive-new = "0.5" - regex = "1.4" - quote = "1" --syn = { version = "1", features = ["full"] } -+syn = { version = "1", features = ["full", "visit"] } +@@ -30,7 +30,6 @@ tempfile = { version = "3.2", optional = true } + cargo_metadata = "0.12" + compiletest_rs = { version = "0.7", features = ["tmp"] } + tester = "0.9" +-regex = "1.5" # This is used by the `collect-metadata` alias. filetime = "0.2" +@@ -41,7 +40,7 @@ if_chain = "1.0" + itertools = "0.10" + quote = "1.0" + serde = { version = "1.0", features = ["derive"] } +-syn = { version = "1.0", features = ["full"] } ++syn = { version = "1.0", features = ["full", "visit"] } + + [build-dependencies] + rustc_tools_util = { version = "0.2", path = "rustc_tools_util" } diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml -index 049b105..cc480a1 100644 +index 39ef766..b4f4a7c 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -36,7 +36,7 @@ generic-simd = ["bytecount/generic-simd"] diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-0006-no-jemalloc.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-0006-no-jemalloc.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-0006-no-jemalloc.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-0006-no-jemalloc.patch 2022-01-19 22:25:19.000000000 +0000 @@ -7,7 +7,7 @@ 1 file changed, 11 deletions(-) diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml -index 37f90bf..617ee4b 100644 +index 277cf0f..645ed3d 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -9,17 +9,6 @@ rustc_driver = { path = "../rustc_driver" } diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-bootstrap-cargo-doc-paths.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-bootstrap-cargo-doc-paths.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-bootstrap-cargo-doc-paths.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-bootstrap-cargo-doc-paths.patch 2022-01-19 22:25:19.000000000 +0000 @@ -4,7 +4,7 @@ --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs -@@ -258,6 +258,12 @@ +@@ -272,6 +272,12 @@ return; } } @@ -75,16 +75,16 @@ [`TokenStream`]: ../proc_macro/struct.TokenStream.html --- a/src/doc/rustc/src/tests/index.md +++ b/src/doc/rustc/src/tests/index.md -@@ -266,7 +266,7 @@ +@@ -300,7 +300,7 @@ [`--test` option]: ../command-line-arguments.md#option-test [`-Z panic-abort-tests`]: https://github.com/rust-lang/rust/issues/67650 - [`available_concurrency`]: ../../std/thread/fn.available_concurrency.html + [`available_parallelism`]: ../../std/thread/fn.available_parallelism.html -[`cargo test`]: ../../cargo/commands/cargo-test.html +[`cargo test`]: ../../../cargo-doc/doc/commands/cargo-test.html [`libtest`]: ../../test/index.html [`main` function]: ../../reference/crates-and-source-files.html#main-functions [`Result`]: ../../std/result/index.html -@@ -275,7 +275,7 @@ +@@ -309,7 +309,7 @@ [attribute-should_panic]: ../../reference/attributes/testing.html#the-should_panic-attribute [attribute-test]: ../../reference/attributes/testing.html#the-test-attribute [bench-docs]: ../../unstable-book/library-features/test.html @@ -166,7 +166,7 @@ [JSON messages]: ../../rustc/json.html --- a/src/doc/edition-guide/src/editions/transitioning-an-existing-project-to-a-new-edition.md +++ b/src/doc/edition-guide/src/editions/transitioning-an-existing-project-to-a-new-edition.md -@@ -92,7 +92,7 @@ +@@ -83,7 +83,7 @@ Congrats! Your code is now valid in both Rust 2015 and Rust 2018! @@ -178,16 +178,16 @@ [nightly channel]: ../../book/appendix-07-nightly-rust.html --- a/src/doc/edition-guide/src/rust-2021/default-cargo-resolver.md +++ b/src/doc/edition-guide/src/rust-2021/default-cargo-resolver.md -@@ -16,7 +16,7 @@ +@@ -21,7 +21,7 @@ crates that are depended on in multiple ways. See [the announcement of Rust 1.51][5] for details. -[4]: ../../cargo/reference/resolver.html#feature-resolver-version-2 +[4]: ../../../cargo-doc/doc/reference/resolver.html#feature-resolver-version-2 [5]: https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#cargos-new-feature-resolver - - ## Migration -@@ -168,4 +168,4 @@ + [workspace]: ../../cargo/reference/workspaces.html + [virtual workspace]: ../../cargo/reference/workspaces.html#virtual-manifest +@@ -176,4 +176,4 @@ Then, `bar` depends on `bstr` as a build-dependency with the "default" feature We can further see that `bstr`'s "default" feature enables "unicode" (among other features). diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-bootstrap-dont-download-stage0.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-bootstrap-dont-download-stage0.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-bootstrap-dont-download-stage0.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-bootstrap-dont-download-stage0.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -Description: Don't download SHA256 if it's already available locally - In Debian we provide the stage0 tarballs as a separate component so that the - buildds don't need to access the network during the build. -Author: Ximin Luo -Forwarded: not-needed ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/src/bootstrap/bootstrap.py -+++ b/src/bootstrap/bootstrap.py -@@ -24,17 +24,19 @@ - except tarfile.CompressionError: - return False - --def get(url, path, verbose=False, do_verify=True): -+def get(url, path, verbose=False, do_verify=True, use_local_hash_if_present=True): - suffix = '.sha256' - sha_url = url + suffix - with tempfile.NamedTemporaryFile(delete=False) as temp_file: - temp_path = temp_file.name -- with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as sha_file: -- sha_path = sha_file.name -+ sha_path = path + suffix - - try: - if do_verify: -- download(sha_path, sha_url, False, verbose) -+ if use_local_hash_if_present and os.path.exists(sha_path): -+ print("using already-download file " + sha_path) -+ else: -+ download(sha_path, sha_url, False, verbose) - if os.path.exists(path): - if verify(path, sha_path, False): - if verbose: -@@ -52,7 +54,6 @@ - print("moving {} to {}".format(temp_path, path)) - shutil.move(temp_path, path) - finally: -- delete_if_present(sha_path, verbose) - delete_if_present(temp_path, verbose) - - -@@ -513,7 +514,7 @@ - else: - url = "https://ci-artifacts.rust-lang.org/rustc-builds/{}".format(self.rustc_commit) - tarball = os.path.join(rustc_cache, filename) -- if not os.path.exists(tarball): -+ if True: - get("{}/{}".format(url, filename), tarball, verbose=self.verbose, do_verify=stage0) - unpack(tarball, tarball_suffix, self.bin_root(stage0), match=pattern, verbose=self.verbose) - diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-bootstrap-old-cargo-compat.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-bootstrap-old-cargo-compat.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-bootstrap-old-cargo-compat.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-bootstrap-old-cargo-compat.patch 2022-01-19 22:25:19.000000000 +0000 @@ -12,7 +12,7 @@ --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs -@@ -451,7 +451,6 @@ +@@ -443,7 +443,6 @@ cargo .arg("-p") .arg(package) @@ -20,15 +20,15 @@ .arg("--") .arg("--markdown-css") .arg("rust.css") -@@ -582,7 +581,6 @@ - cargo.rustdocflag("-Znormalize-docs"); - cargo.rustdocflag("--show-type-layout"); +@@ -589,7 +588,6 @@ + cargo.rustdocflag("--generate-link-to-definition"); compile::rustc_cargo(builder, &mut cargo, target); + cargo.arg("-Zunstable-options"); - cargo.arg("-Zskip-rustdoc-fingerprint"); // Only include compiler crates, no dependencies of those, such as `libc`. - cargo.arg("--no-deps"); -@@ -673,7 +671,6 @@ + // Do link to dependencies on `docs.rs` however using `rustdoc-map`. +@@ -722,7 +720,6 @@ &[], ); diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-bootstrap-use-local-css.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-bootstrap-use-local-css.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-bootstrap-use-local-css.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-bootstrap-use-local-css.patch 2022-01-19 22:25:19.000000000 +0000 @@ -1,6 +1,6 @@ --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs -@@ -383,6 +383,10 @@ +@@ -375,6 +375,10 @@ .arg(&builder.src.join("src/doc/index.md")) .arg("--markdown-playground-url") .arg("https://play.rust-lang.org/") @@ -11,7 +11,7 @@ .arg("-o") .arg(&out) .arg(&path); -@@ -391,17 +395,6 @@ +@@ -383,17 +387,6 @@ cmd.arg("--disable-minification"); } diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-rustc-fix-mips64el-bootstrap.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-rustc-fix-mips64el-bootstrap.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-rustc-fix-mips64el-bootstrap.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-rustc-fix-mips64el-bootstrap.patch 2022-01-19 22:25:19.000000000 +0000 @@ -1,15 +1,15 @@ Bug: https://github.com/rust-lang/rust/issues/52108 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py -@@ -904,6 +904,8 @@ +@@ -936,6 +936,8 @@ + # preserve existing RUSTFLAGS env.setdefault("RUSTFLAGS", "") - env["RUSTFLAGS"] += " -Cdebuginfo=2" + if self.build_triple().startswith('mips'): + env["RUSTFLAGS"] += " -Ctarget-feature=+xgot" - build_section = "target.{}".format(self.build) target_features = [] + if self.get_toml("crt-static", build_section) == "true": --- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs @@ -12,7 +12,7 @@ diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/d-rustdoc-disable-embedded-fonts.patch rustc-1.57.0+dfsg1+llvm/debian/patches/d-rustdoc-disable-embedded-fonts.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/d-rustdoc-disable-embedded-fonts.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/d-rustdoc-disable-embedded-fonts.patch 2022-01-19 22:25:19.000000000 +0000 @@ -1,32 +1,34 @@ --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs -@@ -39,8 +39,6 @@ +@@ -39,9 +39,6 @@ "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD, "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC, "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE, -- "noto-sans-kr-v13-korean-regular.woff" => static_files::noto_sans_kr::REGULAR, -- "noto-sans-kr-v13-korean-regular-LICENSE.txt" => static_files::noto_sans_kr::LICENSE, +- "noto-sans-kr-regular.woff2" => static_files::noto_sans_kr::REGULAR2, +- "noto-sans-kr-regular.woff" => static_files::noto_sans_kr::REGULAR, +- "noto-sans-kr-LICENSE.txt" => static_files::noto_sans_kr::LICENSE, "LICENSE-MIT.txt" => static_files::LICENSE_MIT, "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE, "COPYRIGHT.txt" => static_files::COPYRIGHT, --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css -@@ -75,14 +75,6 @@ +@@ -75,15 +75,6 @@ font-display: swap; } --/* Avoid using legacy CJK serif fonts in Windows like Batang */ +-/* Avoid using legacy CJK serif fonts in Windows like Batang. */ -@font-face { - font-family: 'Noto Sans KR'; -- src: url("noto-sans-kr-v13-korean-regular.woff") format("woff"); +- src: url("noto-sans-kr-regular.woff2") format("woff2"), +- url("noto-sans-kr-regular.woff") format("woff"); - font-display: swap; -- unicode-range: U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF; +- unicode-range: U+AC00-D7AF, U+3130-318F, U+1100-11FF, U+A960-A97F, U+D7B0-D7FF; -} - * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -@@ -107,7 +99,7 @@ +@@ -108,7 +99,7 @@ /* General structure and fonts */ body { @@ -37,20 +39,19 @@ padding: 10px 15px 20px 15px; --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs -@@ -152,18 +152,6 @@ +@@ -156,17 +156,6 @@ crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt"); } -crate mod noto_sans_kr { -- /// The file `noto-sans-kr-v13-korean-regular.woff`, the Regular variant of the Noto Sans KR -- /// font. -- crate static REGULAR: &[u8] = -- include_bytes!("static/fonts/noto-sans-kr-v13-korean-regular.woff"); +- /// The file `noto-sans-kr.woff`, the Regular variant of the Noto Sans KR font. +- crate static REGULAR: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff"); - -- /// The file `noto-sans-kr-v13-korean-regular-LICENSE.txt`, the license text of the Noto Sans KR -- /// font. -- crate static LICENSE: &[u8] = -- include_bytes!("static/fonts/noto-sans-kr-v13-korean-regular-LICENSE.txt"); +- /// The file `noto-sans-kr.woff2`, the Regular variant of the Noto Sans KR font. +- crate static REGULAR2: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff2"); +- +- /// The file `noto-sans-kr-LICENSE.txt`, the license text of the Noto Sans KR font. +- crate static LICENSE: &[u8] = include_bytes!("static/fonts/noto-sans-kr-LICENSE.txt"); -} - /// Files related to the sidebar in rustdoc sources. diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/series rustc-1.57.0+dfsg1+llvm/debian/patches/series --- rustc-1.56.0+dfsg1+llvm/debian/patches/series 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/series 2022-01-19 22:57:49.000000000 +0000 @@ -1,14 +1,12 @@ # Patches for upstream # pending, or forwarded +u-ensure-aarch64-lse-object-files-have-distinct-names-in-an-archive.patch u-ignore-reproducible-failure.patch -u-89591.patch -u-88668.patch u-reproducible-build.patch u-ignore-endian-big-diff.patch u-cc-627.patch u-89950.patch -u-89772.patch # not forwarded, or forwarded but unlikely to be merged u-ignore-ppc-hangs.patch @@ -37,7 +35,6 @@ d-bootstrap-read-beta-version-from-file.patch d-bootstrap-no-assume-tools.patch d-bootstrap-cargo-doc-paths.patch -d-bootstrap-dont-download-stage0.patch d-bootstrap-use-local-css.patch d-bootstrap-old-cargo-compat.patch #d-bootstrap-custom-debuginfo-path.patch @@ -57,3 +54,4 @@ # Experimental patch not yet working #d-rustc-prefer-dynamic.patch d-rustdoc-disable-embedded-fonts.patch +ubuntu-memchr-features.patch diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/series.orig rustc-1.57.0+dfsg1+llvm/debian/patches/series.orig --- rustc-1.56.0+dfsg1+llvm/debian/patches/series.orig 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/series.orig 2022-01-19 22:49:22.000000000 +0000 @@ -0,0 +1,56 @@ +# Patches for upstream + +# pending, or forwarded +u-ignore-reproducible-failure.patch +u-reproducible-build.patch +u-ignore-endian-big-diff.patch +u-cc-627.patch +u-89950.patch + +# not forwarded, or forwarded but unlikely to be merged +u-ignore-ppc-hangs.patch +u-ignore-bpf-test.patch +u-rustc-llvm-cross-flags.patch +u-reproducible-dl-stage0.patch +u-make-tests-work-without-rpath.patch +#u-allow-system-compiler-rt.patch + +# Debian-specific patches, not suitable for upstream + +## Patches needed by debian/prune-unused-deps, for building bootstrap +d-0000-ignore-removed-submodules.patch +d-0001-disable-miniz.patch +d-0002-pkg-config-no-special-snowflake.patch +d-0003-mdbook-strip-embedded-libs.patch +d-0004-cc-psm-rebuild-wasm32.patch +d-0005-clippy-feature-sync.patch +d-0006-no-jemalloc.patch + +## Patches to the build process, including doc path tweaks +## Should not change resulting rustc behaviour +d-bootstrap-rustflags.patch +d-bootstrap-install-symlinks.patch +d-bootstrap-disable-git.patch +d-bootstrap-read-beta-version-from-file.patch +d-bootstrap-no-assume-tools.patch +d-bootstrap-cargo-doc-paths.patch +d-bootstrap-use-local-css.patch +d-bootstrap-old-cargo-compat.patch +#d-bootstrap-custom-debuginfo-path.patch +d-test-ignore-avx-44056.patch +# Work around for some porterboxes, keep this commented +#d-test-host-duplicates.patch +# Experimental patch not yet working +#d-bootstrap-use-system-compiler-rt.patch + +## Patches to rustc behaviour, including path lookup tweaks +d-rust-gdb-paths +d-rust-lldb-paths +d-rustc-add-soname.patch +d-rustc-fix-mips64el-bootstrap.patch +d-rustc-windows-ssp.patch +d-rustc-i686-baseline.patch +# Experimental patch not yet working +#d-rustc-prefer-dynamic.patch +d-rustdoc-disable-embedded-fonts.patch +ubuntu-memchr-features.patch diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/u-88668.patch rustc-1.57.0+dfsg1+llvm/debian/patches/u-88668.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/u-88668.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/u-88668.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -From cd75af25e036301d7971f6f302cf6a5593b0a6b5 Mon Sep 17 00:00:00 2001 -From: Harald van Dijk -Date: Sun, 5 Sep 2021 16:42:36 +0100 -Subject: [PATCH] Change more x64 size checks to not apply to x32. - -Commit 95e096d6 changed a bunch of size checks already, but more have -been added, so this fixes the new ones the same way: the various size -checks that are conditional on target_arch = "x86_64" were not intended -to apply to x86_64-unknown-linux-gnux32, so add -target_pointer_width = "64" to the conditions. ---- - compiler/rustc_middle/src/mir/mod.rs | 8 ++++---- - compiler/rustc_parse/src/parser/attr_wrapper.rs | 2 +- - src/librustdoc/html/render/context.rs | 2 +- - 3 files changed, 6 insertions(+), 6 deletions(-) - -diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs -index 83f6e79d5fcf6..36afbc6cbf171 100644 ---- a/compiler/rustc_middle/src/mir/mod.rs -+++ b/compiler/rustc_middle/src/mir/mod.rs -@@ -1708,7 +1708,7 @@ pub struct Place<'tcx> { - pub projection: &'tcx List>, - } - --#[cfg(target_arch = "x86_64")] -+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - static_assert_size!(Place<'_>, 16); - - #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -@@ -2034,7 +2034,7 @@ pub enum Operand<'tcx> { - Constant(Box>), - } - --#[cfg(target_arch = "x86_64")] -+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - static_assert_size!(Operand<'_>, 24); - - impl<'tcx> Debug for Operand<'tcx> { -@@ -2172,7 +2172,7 @@ pub enum Rvalue<'tcx> { - Aggregate(Box>, Vec>), - } - --#[cfg(target_arch = "x86_64")] -+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - static_assert_size!(Rvalue<'_>, 40); - - #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -@@ -2198,7 +2198,7 @@ pub enum AggregateKind<'tcx> { - Generator(DefId, SubstsRef<'tcx>, hir::Movability), - } - --#[cfg(target_arch = "x86_64")] -+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - static_assert_size!(AggregateKind<'_>, 48); - - #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs -index 9f06bdcc135ba..568682cc3e4e0 100644 ---- a/compiler/rustc_parse/src/parser/attr_wrapper.rs -+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs -@@ -34,7 +34,7 @@ pub struct AttrWrapper { - - // This struct is passed around very frequently, - // so make sure it doesn't accidentally get larger --#[cfg(target_arch = "x86_64")] -+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - rustc_data_structures::static_assert_size!(AttrWrapper, 16); - - impl AttrWrapper { -diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs -index 733bedfdde9b4..34f9c0a8187a6 100644 ---- a/src/librustdoc/html/render/context.rs -+++ b/src/librustdoc/html/render/context.rs -@@ -69,7 +69,7 @@ crate struct Context<'tcx> { - } - - // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. --#[cfg(target_arch = "x86_64")] -+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - rustc_data_structures::static_assert_size!(Context<'_>, 104); - - /// Shared mutable state used in [`Context`] and elsewhere. diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/u-89591.patch rustc-1.57.0+dfsg1+llvm/debian/patches/u-89591.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/u-89591.patch 2021-10-26 02:55:37.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/u-89591.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -From b386959aca1fd25431b8f58b96ddefa556a4bd27 Mon Sep 17 00:00:00 2001 -From: Ximin Luo -Date: Wed, 6 Oct 2021 10:22:03 +0100 -Subject: [PATCH] fix: alloc-optimisation is only for rust llvm - ---- - src/test/codegen/alloc-optimisation.rs | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/test/codegen/alloc-optimisation.rs b/src/test/codegen/alloc-optimisation.rs -index 5b27f3f45457d..aee93b93e3737 100644 ---- a/src/test/codegen/alloc-optimisation.rs -+++ b/src/test/codegen/alloc-optimisation.rs -@@ -1,4 +1,5 @@ - // -+// no-system-llvm - // min-llvm-version: 10.0.1 - // compile-flags: -O - #![crate_type="lib"] diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/u-89772.patch rustc-1.57.0+dfsg1+llvm/debian/patches/u-89772.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/u-89772.patch 2021-12-15 02:09:45.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/u-89772.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -From 6531cd8cba18711f112d7b528ab8fd891a31903e Mon Sep 17 00:00:00 2001 -From: Michael Woerister -Date: Mon, 11 Oct 2021 17:20:45 +0200 -Subject: [PATCH] Fix function-names test for GDB 10.1 - ---- - src/test/debuginfo/function-names.rs | 31 ++++++++++++++-------------- - 1 file changed, 16 insertions(+), 15 deletions(-) - -diff --git a/src/test/debuginfo/function-names.rs b/src/test/debuginfo/function-names.rs -index dec25bb4c203c..61d5fc93cd2ad 100644 ---- a/src/test/debuginfo/function-names.rs -+++ b/src/test/debuginfo/function-names.rs -@@ -9,36 +9,37 @@ - // gdb-command:info functions -q function_names::main - // gdb-check:[...]static fn function_names::main(); - // gdb-command:info functions -q function_names::generic_func<* --// gdb-check:[...]static fn function_names::generic_func(i32) -> i32; -+// gdb-check:[...]static fn function_names::generic_func(i32) -> i32; - - // Implementations - // gdb-command:info functions -q function_names::.*::impl_function.* --// gdb-check:[...]static fn function_names::GenericStruct::impl_function(); -+// gdb-check:[...]static fn function_names::GenericStruct::impl_function(); - // gdb-check:[...]static fn function_names::Mod1::TestStruct2::impl_function(); - // gdb-check:[...]static fn function_names::TestStruct1::impl_function(); - - // Trait implementations - // gdb-command:info functions -q function_names::.*::trait_function.* --// gdb-check:[...]static fn as function_names::TestTrait1>::trait_function(); --// gdb-check:[...]static fn as function_names::TestTrait1>::trait_function(); --// gdb-check:[...]static fn ::trait_function(); --// gdb-check:[...]static fn ::trait_function(); -+// gdb-check:[...]static fn function_names::Mod1::{impl#1}::trait_function(); -+// gdb-check:[...]static fn function_names::{impl#1}::trait_function(); -+// gdb-check:[...]static fn function_names::{impl#3}::trait_function(); -+// gdb-check:[...]static fn function_names::{impl#5}::trait_function3(); -+// gdb-check:[...]static fn function_names::{impl#6}::trait_function(); - - // Closure --// gdb-command:info functions -q function_names::.*::{{closure.* --// gdb-check:[...]static fn function_names::GenericStruct::impl_function::{{closure}}(*mut function_names::{impl#2}::impl_function::{closure#0}); --// gdb-check:[...]static fn function_names::generic_func::{{closure}}(*mut function_names::generic_func::{closure#0}); --// gdb-check:[...]static fn function_names::main::{{closure}}(*mut function_names::main::{closure#0}); -+// gdb-command:info functions -q function_names::.*::{closure.* -+// gdb-check:[...]static fn function_names::generic_func::{closure#0}(*mut function_names::generic_func::{closure#0}); -+// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure#0}); -+// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}(*mut function_names::{impl#2}::impl_function::{closure#0}); - - // Generator - // Generators don't seem to appear in GDB's symbol table. - - // Const generic parameter - // gdb-command:info functions -q function_names::const_generic_fn.* --// gdb-check:[...]static fn function_names::const_generic_fn_bool(); --// gdb-check:[...]static fn function_names::const_generic_fn_non_int(); --// gdb-check:[...]static fn function_names::const_generic_fn_signed_int(); --// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int(); -+// gdb-check:[...]static fn function_names::const_generic_fn_bool(); -+// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>(); -+// gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>(); -+// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>(); - - // === CDB TESTS =================================================================================== - -@@ -103,7 +104,7 @@ fn main() { - GenericStruct::::trait_function3(); - - // Generic function -- let _ = generic_func(42); -+ let _ = generic_func(42i32); - - // Closure - let closure = || { TestStruct1 }; diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/ubuntu-memchr-features.patch rustc-1.57.0+dfsg1+llvm/debian/patches/ubuntu-memchr-features.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/ubuntu-memchr-features.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/ubuntu-memchr-features.patch 2022-01-19 22:49:43.000000000 +0000 @@ -0,0 +1,11 @@ +--- a/vendor/bstr/Cargo.toml ++++ b/vendor/bstr/Cargo.toml +@@ -59,7 +59,7 @@ + default = ["std", "unicode"] + serde1 = ["std", "serde1-nostd", "serde/std"] + serde1-nostd = ["serde"] +-std = ["memchr/use_std"] ++std = ["memchr/std"] + unicode = ["lazy_static", "regex-automata"] + [badges.appveyor] + repository = "BurntSushi/bstr" diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/u-ensure-aarch64-lse-object-files-have-distinct-names-in-an-archive.patch rustc-1.57.0+dfsg1+llvm/debian/patches/u-ensure-aarch64-lse-object-files-have-distinct-names-in-an-archive.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/u-ensure-aarch64-lse-object-files-have-distinct-names-in-an-archive.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/u-ensure-aarch64-lse-object-files-have-distinct-names-in-an-archive.patch 2022-01-19 22:55:15.000000000 +0000 @@ -0,0 +1,100 @@ +From eaab9d29ecbf538369d7f26953425eb78dae8229 Mon Sep 17 00:00:00 2001 +From: Amanieu d'Antras +Date: Sun, 28 Nov 2021 12:50:21 +0000 +Subject: [PATCH] Ensure AArch64 LSE object files have distinct names in an + archive + +This is needed by libtool which rejects archives that contain object +files with the same name multiple times. + +Fixes #443 + +Bug-Upstream: https://gitlab.gnome.org/GNOME/librsvg/-/issues/787 +Bug-Upstream: https://github.com/rust-lang/compiler-builtins/issues/443 +Origin: upstream, https://github.com/rust-lang/compiler-builtins/pull/444 + +--- + vendor/compiler_builtins/build.rs | 51 ++++++++++++++++++++++++++++----------------------- + 1 file changed, 28 insertions(+), 23 deletions(-) + +diff --git a/vendor/compiler_builtins/build.rs b/vendor/compiler_builtins/build.rs +index b930f1d8d61da3633dd40c8ce0d6a7c44771c3ea..90b8a04face73a2685c3cd763b2249f4e5b43143 100644 +--- a/vendor/compiler_builtins/build.rs ++++ b/vendor/compiler_builtins/build.rs +@@ -95,6 +95,8 @@ mod c { + + use std::collections::{BTreeMap, HashSet}; + use std::env; ++ use std::fs::File; ++ use std::io::Write; + use std::path::{Path, PathBuf}; + + struct Sources { +@@ -523,20 +525,13 @@ mod c { + cfg.compile("libcompiler-rt.a"); + } + +- fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &cc::Build) { +- // NOTE: because we're recompiling the same source file in N different ways, building +- // serially is necessary. If we want to lift this restriction, we can either: +- // - create symlinks to lse.S and build those_(though we'd still need to pass special +- // #define-like flags to each of these), or +- // - synthesizing tiny .S files in out/ with the proper #defines, which ultimately #include +- // lse.S. +- // That said, it's unclear how useful this added complexity will be, so just do the simple +- // thing for now. ++ fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) { ++ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); + println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + +- // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* +- // trivial to build an individual object. ++ cfg.include(&builtins_dir); ++ + for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { + for size in &[1, 2, 4, 8, 16] { + if *size == 16 && *instruction_type != "cas" { +@@ -546,20 +541,30 @@ mod c { + for (model_number, model_name) in + &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] + { +- let library_name = format!( +- "liboutline_atomic_helper_{}{}_{}.a", +- instruction_type, size, model_name ++ // The original compiler-rt build system compiles the same ++ // source file multiple times with different compiler ++ // options. Here we do something slightly different: we ++ // create multiple .S files with the proper #defines and ++ // then include the original file. ++ // ++ // This is needed because the cc crate doesn't allow us to ++ // override the name of object files and libtool requires ++ // all objects in an archive to have unique names. ++ let path = ++ out_dir.join(format!("lse_{}{}_{}.S", instruction_type, size, model_name)); ++ let mut file = File::create(&path).unwrap(); ++ writeln!(file, "#define L_{}", instruction_type).unwrap(); ++ writeln!(file, "#define SIZE {}", size).unwrap(); ++ writeln!(file, "#define MODEL {}", model_number).unwrap(); ++ writeln!( ++ file, ++ "#include \"{}\"", ++ outlined_atomics_file.canonicalize().unwrap().display() + ); +- let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); +- let mut cfg = cfg.clone(); +- +- cfg.include(&builtins_dir) +- .define(&format!("L_{}", instruction_type), None) +- .define("SIZE", size.to_string().as_str()) +- .define("MODEL", model_number.to_string().as_str()) +- .file(&outlined_atomics_file); +- cfg.compile(&library_name); ++ drop(file); ++ cfg.file(path); + ++ let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); + } + } diff -Nru rustc-1.56.0+dfsg1+llvm/debian/patches/u-ignore-bpf-test.patch rustc-1.57.0+dfsg1+llvm/debian/patches/u-ignore-bpf-test.patch --- rustc-1.56.0+dfsg1+llvm/debian/patches/u-ignore-bpf-test.patch 2021-12-08 21:52:30.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/patches/u-ignore-bpf-test.patch 2022-01-19 22:25:19.000000000 +0000 @@ -4,6 +4,6 @@ +++ b/src/test/assembly/asm/bpf-types.rs @@ -1,3 +1,4 @@ +// ignore-test - // min-llvm-version: 10.0.1 + // min-llvm-version: 13.0 // assembly-output: emit-asm // compile-flags: --target bpfel-unknown-none -C target_feature=+alu32 diff -Nru rustc-1.56.0+dfsg1+llvm/debian/prune-unused-deps rustc-1.57.0+dfsg1+llvm/debian/prune-unused-deps --- rustc-1.56.0+dfsg1+llvm/debian/prune-unused-deps 2021-07-04 23:04:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/prune-unused-deps 2022-01-19 22:25:19.000000000 +0000 @@ -2,7 +2,7 @@ # Run this script in an unpacked upstream tarball directory, and it will update # (i.e. overwrite) the "unused deps" part of Files-Excluded in d/copyright. -set -e +set -ex scriptdir=$(dirname "$(dirname "$(readlink -f "$0")")") had_config_toml=$(if test -e "$scriptdir/debian/config.toml"; then echo true; else echo false; fi) @@ -10,14 +10,14 @@ ( cd "$scriptdir" && debian/rules debian/config.toml ) cp "$scriptdir/debian/config.toml" config.toml -for i in "$scriptdir/debian/patches"/d-00*.patch; do +for i in ../debian/patches/u-89950.patch ../debian/patches/u-reproducible-dl-stage0.patch "$scriptdir/debian/patches"/d-00*.patch; do "$scriptdir/debian/ensure-patch" -N "$i" done test -f Cargo.lock.orig || cp Cargo.lock Cargo.lock.orig rm -f Cargo.lock find vendor -name .cargo-checksum.json -execdir "$scriptdir/debian/prune-checksums" "{}" + -sed -i -e 's/dev: 1/#dev: 1/g' src/stage0.txt # allow beta builds -./x.py build nonexistent/path/to/trigger/cargo/metadata src/bootstrap +#sed -i -e 's/dev: 1/#dev: 1/g' src/stage0.txt # allow beta builds +python3 ./x.py build nonexistent/path/to/trigger/cargo/metadata src/bootstrap needed_crates() { cat Cargo.lock \ diff -Nru rustc-1.56.0+dfsg1+llvm/debian/rules rustc-1.57.0+dfsg1+llvm/debian/rules --- rustc-1.56.0+dfsg1+llvm/debian/rules 2021-12-16 01:31:27.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/debian/rules 2022-01-21 03:41:55.000000000 +0000 @@ -192,11 +192,6 @@ v="$(DEB_VERSION)"; test "$$v" = "$${v%~exp*}" -o "$(DEB_DISTRIBUTION)" = "experimental" -o "$(DEB_DISTRIBUTION)" = "UNRELEASED" $(PRECONFIGURE_CHECK) if [ -d stage0 ]; then mkdir -p build && ln -sfT ../stage0 build/cache; fi - # work around #842634 - if test $$(grep "127.0.0.1\s*localhost" /etc/hosts | wc -l) -gt 1; then \ - debian/ensure-patch -N debian/patches/d-test-host-duplicates.patch; fi - # allow beta builds - sed -i -e 's/dev: 1/#dev: 1/g' src/stage0.txt # don't care about lock changes rm -f Cargo.lock # We patched some crates so have to rm the checksums diff -Nru rustc-1.56.0+dfsg1+llvm/git-commit-hash rustc-1.57.0+dfsg1+llvm/git-commit-hash --- rustc-1.56.0+dfsg1+llvm/git-commit-hash 2021-10-18 11:05:38.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/git-commit-hash 2021-11-29 20:27:18.000000000 +0000 @@ -1 +1 @@ -09c42c45858d5f3aedfa670698275303a3d19afa \ No newline at end of file +f1edd0429582dd29cccacaf50fd134b05593bd9c \ No newline at end of file diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/benches/btree/map.rs rustc-1.57.0+dfsg1+llvm/library/alloc/benches/btree/map.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/benches/btree/map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/benches/btree/map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -54,6 +54,50 @@ }; } +macro_rules! map_from_iter_rand_bench { + ($name: ident, $n: expr, $map: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + let n: usize = $n; + // setup + let mut rng = thread_rng(); + let mut vec = Vec::with_capacity(n); + + for _ in 0..n { + let i = rng.gen::() % n; + vec.push((i, i)); + } + + // measure + b.iter(|| { + let map: $map<_, _> = vec.iter().copied().collect(); + black_box(map); + }); + } + }; +} + +macro_rules! map_from_iter_seq_bench { + ($name: ident, $n: expr, $map: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + let n: usize = $n; + // setup + let mut vec = Vec::with_capacity(n); + + for i in 0..n { + vec.push((i, i)); + } + + // measure + b.iter(|| { + let map: $map<_, _> = vec.iter().copied().collect(); + black_box(map); + }); + } + }; +} + macro_rules! map_find_rand_bench { ($name: ident, $n: expr, $map: ident) => { #[bench] @@ -111,6 +155,12 @@ map_insert_seq_bench! {insert_seq_100, 100, BTreeMap} map_insert_seq_bench! {insert_seq_10_000, 10_000, BTreeMap} +map_from_iter_rand_bench! {from_iter_rand_100, 100, BTreeMap} +map_from_iter_rand_bench! {from_iter_rand_10_000, 10_000, BTreeMap} + +map_from_iter_seq_bench! {from_iter_seq_100, 100, BTreeMap} +map_from_iter_seq_bench! {from_iter_seq_10_000, 10_000, BTreeMap} + map_find_rand_bench! {find_rand_100, 100, BTreeMap} map_find_rand_bench! {find_rand_10_000, 10_000, BTreeMap} diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/benches/vec_deque.rs rustc-1.57.0+dfsg1+llvm/library/alloc/benches/vec_deque.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/benches/vec_deque.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/benches/vec_deque.rs 2021-11-29 19:27:11.000000000 +0000 @@ -52,3 +52,18 @@ b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b)))) } + +#[bench] +fn bench_from_array_1000(b: &mut Bencher) { + const N: usize = 1000; + let mut array: [usize; N] = [0; N]; + + for i in 0..N { + array[i] = i; + } + + b.iter(|| { + let deq: VecDeque<_> = array.into(); + black_box(deq); + }) +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/benches/vec.rs rustc-1.57.0+dfsg1+llvm/library/alloc/benches/vec.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/benches/vec.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/benches/vec.rs 2021-11-29 19:27:11.000000000 +0000 @@ -732,3 +732,18 @@ let v = vec![777u32; 500000]; b.iter(|| v.iter().flat_map(|color| color.rotate_left(8).to_be_bytes()).collect::>()); } + +#[bench] +fn bench_retain_100000(b: &mut Bencher) { + let v = (1..=100000).collect::>(); + b.iter(|| { + let mut v = v.clone(); + v.retain(|x| x & 1 == 0) + }); +} + +#[bench] +fn bench_retain_whole_100000(b: &mut Bencher) { + let mut v = black_box(vec![826u32; 100000]); + b.iter(|| v.retain(|x| *x == 826u32)); +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/alloc.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/alloc.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/alloc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/alloc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -307,7 +307,6 @@ } /// The allocator for unique pointers. -// This function must not unwind. If it does, MIR codegen will fail. #[cfg(all(not(no_global_oom_handling), not(test)))] #[lang = "exchange_malloc"] #[inline] diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/borrow.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/borrow.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/borrow.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/borrow.rs 2021-11-29 19:27:11.000000000 +0000 @@ -330,7 +330,11 @@ } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Cow<'_, B> { +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +impl const Deref for Cow<'_, B> +where + B::Owned: ~const Borrow, +{ type Target = B; fn deref(&self) -> &B { diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/boxed.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/boxed.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/boxed.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/boxed.rs 2021-11-29 19:27:11.000000000 +0000 @@ -187,6 +187,7 @@ #[cfg(not(no_global_oom_handling))] #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn new(x: T) -> Self { box x } @@ -211,6 +212,7 @@ /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] #[inline] pub fn new_uninit() -> Box> { Self::new_uninit_in(Global) @@ -237,6 +239,7 @@ #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_zeroed() -> Box> { Self::new_zeroed_in(Global) } @@ -245,6 +248,7 @@ /// `x` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] #[stable(feature = "pin", since = "1.33.0")] + #[must_use] #[inline(always)] pub fn pin(x: T) -> Pin> { (box x).into() @@ -339,6 +343,7 @@ /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[must_use] #[inline] pub fn new_in(x: T, alloc: A) -> Self { let mut boxed = Self::new_uninit_in(alloc); @@ -395,6 +400,7 @@ /// ``` #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(no_global_oom_handling))] + #[must_use] // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); @@ -459,6 +465,7 @@ #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(no_global_oom_handling))] // #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_zeroed_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. @@ -503,6 +510,7 @@ /// `x` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[must_use] #[inline(always)] pub fn pin_in(x: T, alloc: A) -> Pin where @@ -561,6 +569,7 @@ /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit]> { unsafe { RawVec::with_capacity(len).into_box(len) } } @@ -585,6 +594,7 @@ /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit]> { unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } } @@ -681,6 +691,7 @@ #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_uninit_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit], A> { unsafe { RawVec::with_capacity_in(len, alloc).into_box(len) } } @@ -708,6 +719,7 @@ #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit], A> { unsafe { RawVec::with_capacity_zeroed_in(len, alloc).into_box(len) } } @@ -1086,6 +1098,7 @@ } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { /// Creates a `Box`, with the `Default` value for T. @@ -1276,6 +1289,7 @@ /// from the stack into it. /// /// # Examples + /// /// ```rust /// let x = 5; /// let boxed = Box::new(5); @@ -1329,6 +1343,12 @@ #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box<[T]> { + /// Converts a `Cow<'_, [T]>` into a `Box<[T]>` + /// + /// When `cow` is the `Cow::Borrowed` variant, this + /// conversion allocates on the heap and copies the + /// underlying slice. Otherwise, it will try to reuse the owned + /// `Vec`'s allocation. #[inline] fn from(cow: Cow<'_, [T]>) -> Box<[T]> { match cow { @@ -1347,6 +1367,7 @@ /// and performs a copy of `s`. /// /// # Examples + /// /// ```rust /// let boxed: Box = Box::from("hello"); /// println!("{}", boxed); @@ -1360,6 +1381,29 @@ #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { + /// Converts a `Cow<'_, str>` into a `Box` + /// + /// When `cow` is the `Cow::Borrowed` variant, this + /// conversion allocates on the heap and copies the + /// underlying `str`. Otherwise, it will try to reuse the owned + /// `String`'s allocation. + /// + /// # Examples + /// + /// ```rust + /// use std::borrow::Cow; + /// + /// let unboxed = Cow::Borrowed("hello"); + /// let boxed: Box = Box::from(unboxed); + /// println!("{}", boxed); + /// ``` + /// + /// ```rust + /// # use std::borrow::Cow; + /// let unboxed = Cow::Owned("hello".to_string()); + /// let boxed: Box = Box::from(unboxed); + /// println!("{}", boxed); + /// ``` #[inline] fn from(cow: Cow<'_, str>) -> Box { match cow { @@ -1394,6 +1438,7 @@ } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_array", since = "1.45.0")] impl From<[T; N]> for Box<[T]> { /// Converts a `[T; N]` into a `Box<[T]>` @@ -1401,6 +1446,7 @@ /// This conversion moves the array to newly heap-allocated memory. /// /// # Examples + /// /// ```rust /// let boxed: Box<[u8]> = Box::from([4, 2]); /// println!("{:?}", boxed); @@ -1414,6 +1460,15 @@ impl TryFrom> for Box<[T; N]> { type Error = Box<[T]>; + /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`. + /// + /// The conversion occurs in-place and does not require a + /// new memory allocation. + /// + /// # Errors + /// + /// Returns the old `Box<[T]>` in the `Err` variant if + /// `boxed_slice.len()` does not equal `N`. fn try_from(boxed_slice: Box<[T]>) -> Result { if boxed_slice.len() == N { Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) }) diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/binary_heap.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/binary_heap.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/binary_heap.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/binary_heap.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,7 +3,7 @@ //! Insertion and popping the largest element have *O*(log(*n*)) time complexity. //! Checking the largest element is *O*(1). Converting a vector to a binary heap //! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be -//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*)) +//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*)) //! in-place heapsort. //! //! # Examples @@ -159,9 +159,9 @@ /// This will be a max-heap. /// /// It is a logic error for an item to be modified in such a way that the -/// item's ordering relative to any other item, as determined by the `Ord` +/// item's ordering relative to any other item, as determined by the [`Ord`] /// trait, changes while it is in the heap. This is normally only possible -/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. The +/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The /// behavior resulting from such a logic error is not specified, but will /// not result in undefined behavior. This could include panics, incorrect /// results, aborts, memory leaks, and non-termination. @@ -219,7 +219,7 @@ /// /// ## Min-heap /// -/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to +/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to /// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest /// value instead of the greatest one. /// @@ -243,13 +243,17 @@ /// /// # Time complexity /// -/// | [push] | [pop] | [peek]/[peek\_mut] | -/// |--------|-----------|--------------------| -/// | O(1)~ | *O*(log(*n*)) | *O*(1) | +/// | [push] | [pop] | [peek]/[peek\_mut] | +/// |---------|---------------|--------------------| +/// | *O*(1)~ | *O*(log(*n*)) | *O*(1) | /// /// The value for `push` is an expected cost; the method documentation gives a /// more detailed analysis. /// +/// [`core::cmp::Reverse`]: core::cmp::Reverse +/// [`Ord`]: core::cmp::Ord +/// [`Cell`]: core::cell::Cell +/// [`RefCell`]: core::cell::RefCell /// [push]: BinaryHeap::push /// [pop]: BinaryHeap::pop /// [peek]: BinaryHeap::peek @@ -360,6 +364,7 @@ /// heap.push(4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn new() -> BinaryHeap { BinaryHeap { data: vec![] } } @@ -379,6 +384,7 @@ /// heap.push(4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn with_capacity(capacity: usize) -> BinaryHeap { BinaryHeap { data: Vec::with_capacity(capacity) } } @@ -844,6 +850,7 @@ /// /// assert_eq!(heap.into_iter_sorted().take(2).collect::>(), vec![5, 4]); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] pub fn into_iter_sorted(self) -> IntoIterSorted { IntoIterSorted { inner: self } @@ -1002,6 +1009,7 @@ /// /// io::sink().write(heap.as_slice()).unwrap(); /// ``` + #[must_use] #[unstable(feature = "binary_heap_as_slice", issue = "83659")] pub fn as_slice(&self) -> &[T] { self.data.as_slice() @@ -1024,6 +1032,7 @@ /// println!("{}", x); /// } /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] pub fn into_vec(self) -> Vec { self.into() @@ -1255,9 +1264,10 @@ /// An owning iterator over the elements of a `BinaryHeap`. /// /// This `struct` is created by [`BinaryHeap::into_iter()`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: BinaryHeap::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/dedup_sorted_iter.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/dedup_sorted_iter.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/dedup_sorted_iter.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/dedup_sorted_iter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,47 @@ +use core::iter::Peekable; + +/// A iterator for deduping the key of a sorted iterator. +/// When encountering the duplicated key, only the last key-value pair is yielded. +/// +/// Used by [`BTreeMap::bulk_build_from_sorted_iter`]. +pub struct DedupSortedIter +where + I: Iterator, +{ + iter: Peekable, +} + +impl DedupSortedIter +where + I: Iterator, +{ + pub fn new(iter: I) -> Self { + Self { iter: iter.peekable() } + } +} + +impl Iterator for DedupSortedIter +where + K: Eq, + I: Iterator, +{ + type Item = (K, V); + + fn next(&mut self) -> Option<(K, V)> { + loop { + let next = match self.iter.next() { + Some(next) => next, + None => return None, + }; + + let peeked = match self.iter.peek() { + Some(peeked) => peeked, + None => return Some(next), + }; + + if next.0 != peeked.0 { + return Some(next); + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/map/entry.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/map/entry.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/map/entry.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/map/entry.rs 2021-11-29 19:27:11.000000000 +0000 @@ -448,6 +448,7 @@ /// } /// assert_eq!(map["poneyland"], 22); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] pub fn into_mut(self) -> &'a mut V { self.handle.into_val_mut() diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/map/tests.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/map/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/map/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/map/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1494,33 +1494,40 @@ map.check(); } +fn test_clone_panic_leak(size: usize) { + for i in 0..size { + let dummies: Vec = (0..size).map(|id| CrashTestDummy::new(id)).collect(); + let map: BTreeMap<_, ()> = dummies + .iter() + .map(|dummy| { + let panic = if dummy.id == i { Panic::InClone } else { Panic::Never }; + (dummy.spawn(panic), ()) + }) + .collect(); + + catch_unwind(|| map.clone()).unwrap_err(); + for d in &dummies { + assert_eq!(d.cloned(), if d.id <= i { 1 } else { 0 }, "id={}/{}", d.id, i); + assert_eq!(d.dropped(), if d.id < i { 1 } else { 0 }, "id={}/{}", d.id, i); + } + assert_eq!(map.len(), size); + + drop(map); + for d in &dummies { + assert_eq!(d.cloned(), if d.id <= i { 1 } else { 0 }, "id={}/{}", d.id, i); + assert_eq!(d.dropped(), if d.id < i { 2 } else { 1 }, "id={}/{}", d.id, i); + } + } +} + +#[test] +fn test_clone_panic_leak_height_0() { + test_clone_panic_leak(3) +} + #[test] -fn test_clone_panic_leak() { - let a = CrashTestDummy::new(0); - let b = CrashTestDummy::new(1); - let c = CrashTestDummy::new(2); - - let mut map = BTreeMap::new(); - map.insert(a.spawn(Panic::Never), ()); - map.insert(b.spawn(Panic::InClone), ()); - map.insert(c.spawn(Panic::Never), ()); - - catch_unwind(|| map.clone()).unwrap_err(); - assert_eq!(a.cloned(), 1); - assert_eq!(b.cloned(), 1); - assert_eq!(c.cloned(), 0); - assert_eq!(a.dropped(), 1); - assert_eq!(b.dropped(), 0); - assert_eq!(c.dropped(), 0); - assert_eq!(map.len(), 3); - - drop(map); - assert_eq!(a.cloned(), 1); - assert_eq!(b.cloned(), 1); - assert_eq!(c.cloned(), 0); - assert_eq!(a.dropped(), 2); - assert_eq!(b.dropped(), 1); - assert_eq!(c.dropped(), 1); +fn test_clone_panic_leak_height_1() { + test_clone_panic_leak(MIN_INSERTS_HEIGHT_1) } #[test] @@ -1748,20 +1755,20 @@ #[test] fn test_ord_absence() { fn map(mut map: BTreeMap) { - map.is_empty(); - map.len(); + let _ = map.is_empty(); + let _ = map.len(); map.clear(); - map.iter(); - map.iter_mut(); - map.keys(); - map.values(); - map.values_mut(); + let _ = map.iter(); + let _ = map.iter_mut(); + let _ = map.keys(); + let _ = map.values(); + let _ = map.values_mut(); if true { - map.into_values(); + let _ = map.into_values(); } else if true { - map.into_iter(); + let _ = map.into_iter(); } else { - map.into_keys(); + let _ = map.into_keys(); } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/map.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/map.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,4 @@ +use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering; use core::fmt::{self, Debug}; @@ -9,6 +10,7 @@ use core::ptr; use super::borrow::DormantMutRef; +use super::dedup_sorted_iter::DedupSortedIter; use super::navigate::{LazyLeafRange, LeafRange}; use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root}; use super::search::SearchResult::*; @@ -17,16 +19,16 @@ pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry}; use Entry::*; -/// Minimum number of elements in nodes that are not a root. +/// Minimum number of elements in a node that is not a root. /// We might temporarily have fewer elements during methods. pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; // A tree in a `BTreeMap` is a tree in the `node` module with additional invariants: // - Keys must appear in ascending order (according to the key's type). -// - If the root node is internal, it must contain at least 1 element. +// - Every non-leaf node contains at least 1 element (has at least 2 children). // - Every non-root node contains at least MIN_LEN elements. // -// An empty map may be represented both by the absence of a root node or by a +// An empty map is represented either by the absence of a root node or by a // root node that is an empty leaf. /// A map based on a [B-Tree]. @@ -325,9 +327,10 @@ /// An owning iterator over the entries of a `BTreeMap`. /// /// This `struct` is created by the [`into_iter`] method on [`BTreeMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct IntoIter { @@ -499,6 +502,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] + #[must_use] pub const fn new() -> BTreeMap { BTreeMap { root: None, length: 0 } } @@ -1261,6 +1265,7 @@ /// assert_eq!(keys, [1, 2]); /// ``` #[inline] + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_keys(self) -> IntoKeys { IntoKeys { inner: self.into_iter() } @@ -1283,10 +1288,23 @@ /// assert_eq!(values, ["hello", "goodbye"]); /// ``` #[inline] + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_values(self) -> IntoValues { IntoValues { inner: self.into_iter() } } + + /// Makes a `BTreeMap` from a sorted iterator. + pub(crate) fn bulk_build_from_sorted_iter(iter: I) -> Self + where + K: Ord, + I: Iterator, + { + let mut root = Root::new(); + let mut length = 0; + root.bulk_push(DedupSortedIter::new(iter), &mut length); + BTreeMap { root: Some(root), length } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1720,8 +1738,8 @@ pub(super) fn size_hint(&self) -> (usize, Option) { // In most of the btree iterators, `self.length` is the number of elements // yet to be visited. Here, it includes elements that were visited and that - // the predicate decided not to drain. Making this upper bound more accurate - // requires maintaining an extra field and is not worth while. + // the predicate decided not to drain. Making this upper bound more tight + // during iteration would require an extra field. (0, Some(*self.length)) } } @@ -1911,9 +1929,15 @@ #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator<(K, V)> for BTreeMap { fn from_iter>(iter: T) -> BTreeMap { - let mut map = BTreeMap::new(); - map.extend(iter); - map + let mut inputs: Vec<_> = iter.into_iter().collect(); + + if inputs.is_empty() { + return BTreeMap::new(); + } + + // use stable sort to preserve the insertion order. + inputs.sort_by(|a, b| a.0.cmp(&b.0)); + BTreeMap::bulk_build_from_sorted_iter(inputs.into_iter()) } } @@ -1947,6 +1971,7 @@ #[stable(feature = "rust1", since = "1.0.0")] impl Hash for BTreeMap { fn hash(&self, state: &mut H) { + self.len().hash(state); for elt in self { elt.hash(state); } @@ -2022,8 +2047,14 @@ /// let map2: BTreeMap<_, _> = [(1, 2), (3, 4)].into(); /// assert_eq!(map1, map2); /// ``` - fn from(arr: [(K, V); N]) -> Self { - core::array::IntoIter::new(arr).collect() + fn from(mut arr: [(K, V); N]) -> Self { + if N == 0 { + return BTreeMap::new(); + } + + // use stable sort to preserve the insertion order. + arr.sort_by(|a, b| a.0.cmp(&b.0)); + BTreeMap::bulk_build_from_sorted_iter(core::array::IntoIter::new(arr)) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/mod.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ mod append; mod borrow; +mod dedup_sorted_iter; mod fix; pub mod map; mod mem; diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/navigate.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/navigate.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/navigate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/navigate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -440,8 +440,7 @@ /// - The given edge must not have been previously returned by counterpart /// `deallocating_next_back`. /// - The returned KV handle is only valid to access the key and value, - /// and only valid until the next call to this method or counterpart - /// `deallocating_next_back`. + /// and only valid until the next call to a `deallocating_` method. unsafe fn deallocating_next( self, ) -> Option<(Self, Handle, marker::KV>)> @@ -470,8 +469,7 @@ /// - The given edge must not have been previously returned by counterpart /// `deallocating_next`. /// - The returned KV handle is only valid to access the key and value, - /// and only valid until the next call to this method or counterpart - /// `deallocating_next`. + /// and only valid until the next call to a `deallocating_` method. unsafe fn deallocating_next_back( self, ) -> Option<(Self, Handle, marker::KV>)> diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/node.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/node.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/node.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/node.rs 2021-11-29 19:27:11.000000000 +0000 @@ -574,7 +574,7 @@ /// no cleanup is done on any of the keys, values and other children. /// This decreases the height by 1 and is the opposite of `push_internal_level`. /// - /// Requires exclusive access to the `Root` object but not to the root node; + /// Requires exclusive access to the `NodeRef` object but not to the root node; /// it will not invalidate other handles or references to the root node. /// /// Panics if there is no internal level, i.e., if the root node is a leaf. @@ -1663,7 +1663,7 @@ const PERMITS_TRAVERSAL: bool = true; } impl BorrowType for Owned { - // Traversal isn't needede, it happens using the result of `borrow_mut`. + // Traversal isn't needed, it happens using the result of `borrow_mut`. // By disabling traversal, and only creating new references to roots, // we know that every reference of the `Owned` type is to a root node. const PERMITS_TRAVERSAL: bool = false; diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/set.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/set.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/set.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/set.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ // This is pretty much entirely stolen from TreeSet, since BTreeMap has an identical interface // to TreeMap +use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering::{Equal, Greater, Less}; use core::cmp::{max, min}; @@ -106,9 +107,10 @@ /// An owning iterator over the items of a `BTreeSet`. /// /// This `struct` is created by the [`into_iter`] method on [`BTreeSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: BTreeSet#method.into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IntoIter { @@ -246,6 +248,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] + #[must_use] pub const fn new() -> BTreeSet { BTreeSet { map: BTreeMap::new() } } @@ -532,6 +535,7 @@ /// b.insert(1); /// assert_eq!(a.is_disjoint(&b), false); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_disjoint(&self, other: &BTreeSet) -> bool where @@ -557,6 +561,7 @@ /// set.insert(4); /// assert_eq!(set.is_subset(&sup), false); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_subset(&self, other: &BTreeSet) -> bool where @@ -636,6 +641,7 @@ /// set.insert(2); /// assert_eq!(set.is_superset(&sub), true); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_superset(&self, other: &BTreeSet) -> bool where @@ -1056,9 +1062,17 @@ #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for BTreeSet { fn from_iter>(iter: I) -> BTreeSet { - let mut set = BTreeSet::new(); - set.extend(iter); - set + let mut inputs: Vec<_> = iter.into_iter().collect(); + + if inputs.is_empty() { + return BTreeSet::new(); + } + + // use stable sort to preserve the insertion order. + inputs.sort(); + let iter = inputs.into_iter().map(|k| (k, ())); + let map = BTreeMap::bulk_build_from_sorted_iter(iter); + BTreeSet { map } } } @@ -1071,8 +1085,16 @@ /// let set2: BTreeSet<_> = [1, 2, 3, 4].into(); /// assert_eq!(set1, set2); /// ``` - fn from(arr: [T; N]) -> Self { - core::array::IntoIter::new(arr).collect() + fn from(mut arr: [T; N]) -> Self { + if N == 0 { + return BTreeSet::new(); + } + + // use stable sort to preserve the insertion order. + arr.sort(); + let iter = core::array::IntoIter::new(arr).map(|k| (k, ())); + let map = BTreeMap::bulk_build_from_sorted_iter(iter); + BTreeSet { map } } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/testing/crash_test.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/testing/crash_test.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/btree/testing/crash_test.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/btree/testing/crash_test.rs 2021-11-29 19:27:11.000000000 +0000 @@ -11,7 +11,7 @@ /// on anything defined in the crate, apart from the `Debug` trait. #[derive(Debug)] pub struct CrashTestDummy { - id: usize, + pub id: usize, cloned: AtomicUsize, dropped: AtomicUsize, queried: AtomicUsize, diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/linked_list.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/linked_list.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/linked_list.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/linked_list.rs 2021-11-29 19:27:11.000000000 +0000 @@ -38,9 +38,12 @@ /// let list = LinkedList::from([1, 2, 3]); /// ``` /// -/// NOTE: It is almost always better to use `Vec` or `VecDeque` because +/// NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because /// array-based containers are generally faster, /// more memory efficient, and make better use of CPU cache. +/// +/// [`Vec`]: crate::vec::Vec +/// [`VecDeque`]: super::vec_deque::VecDeque #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] #[rustc_insignificant_dtor] @@ -122,9 +125,10 @@ /// An owning iterator over the elements of a `LinkedList`. /// /// This `struct` is created by the [`into_iter`] method on [`LinkedList`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: LinkedList::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { @@ -413,6 +417,7 @@ #[inline] #[rustc_const_stable(feature = "const_linked_list_new", since = "1.32.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub const fn new() -> Self { LinkedList { head: None, tail: None, len: 0, marker: PhantomData } } @@ -632,6 +637,8 @@ /// Returns `true` if the `LinkedList` contains an element equal to the /// given value. /// + /// This operation should compute in *O*(*n*) time. + /// /// # Examples /// /// ``` @@ -657,6 +664,8 @@ /// Provides a reference to the front element, or `None` if the list is /// empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -677,6 +686,8 @@ /// Provides a mutable reference to the front element, or `None` if the list /// is empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -703,6 +714,8 @@ /// Provides a reference to the back element, or `None` if the list is /// empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -723,6 +736,8 @@ /// Provides a mutable reference to the back element, or `None` if the list /// is empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -1370,6 +1385,7 @@ /// The lifetime of the returned `Cursor` is bound to that of the /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the /// `CursorMut` is frozen for the lifetime of the `Cursor`. + #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn as_cursor(&self) -> Cursor<'_, T> { Cursor { list: self.list, current: self.current, index: self.index } diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/mod.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -57,7 +57,7 @@ /// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +#[stable(feature = "try_reserve", since = "1.57.0")] pub struct TryReserveError { kind: TryReserveErrorKind, } @@ -126,7 +126,7 @@ } } -#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +#[stable(feature = "try_reserve", since = "1.57.0")] impl Display for TryReserveError { fn fmt( &self, diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/drain.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/drain.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/drain.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/drain.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,10 +18,21 @@ T: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { - pub(crate) after_tail: usize, - pub(crate) after_head: usize, - pub(crate) iter: Iter<'a, T>, - pub(crate) deque: NonNull>, + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: NonNull>, +} + +impl<'a, T, A: Allocator> Drain<'a, T, A> { + pub(super) unsafe fn new( + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: NonNull>, + ) -> Self { + Drain { after_tail, after_head, iter, deque } + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/into_iter.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/into_iter.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/into_iter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/into_iter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,16 +8,23 @@ /// An owning iterator over the elements of a `VecDeque`. /// /// This `struct` is created by the [`into_iter`] method on [`VecDeque`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: VecDeque::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { - pub(crate) inner: VecDeque, + inner: VecDeque, +} + +impl IntoIter { + pub(super) fn new(inner: VecDeque) -> Self { + IntoIter { inner } + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/iter_mut.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/iter_mut.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/iter_mut.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/iter_mut.rs 2021-11-29 19:27:11.000000000 +0000 @@ -13,10 +13,21 @@ #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { // Internal safety invariant: the entire slice is dereferencable. - pub(crate) ring: *mut [T], - pub(crate) tail: usize, - pub(crate) head: usize, - pub(crate) phantom: PhantomData<&'a mut [T]>, + ring: *mut [T], + tail: usize, + head: usize, + phantom: PhantomData<&'a mut [T]>, +} + +impl<'a, T> IterMut<'a, T> { + pub(super) unsafe fn new( + ring: *mut [T], + tail: usize, + head: usize, + phantom: PhantomData<&'a mut [T]>, + ) -> Self { + IterMut { ring, tail, head, phantom } + } } // SAFETY: we do nothing thread-local and there is no interior mutability, diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/mod.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -88,7 +88,7 @@ /// [`extend`]: VecDeque::extend /// [`append`]: VecDeque::append /// [`make_contiguous`]: VecDeque::make_contiguous -#[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "VecDeque")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct VecDeque< @@ -418,6 +418,25 @@ } } + /// Copies all values from `src` to `dst`, wrapping around if needed. + /// Assumes capacity is sufficient. + #[inline] + unsafe fn copy_slice(&mut self, dst: usize, src: &[T]) { + debug_assert!(src.len() <= self.cap()); + let head_room = self.cap() - dst; + if src.len() <= head_room { + unsafe { + ptr::copy_nonoverlapping(src.as_ptr(), self.ptr().add(dst), src.len()); + } + } else { + let (left, right) = src.split_at(head_room); + unsafe { + ptr::copy_nonoverlapping(left.as_ptr(), self.ptr().add(dst), left.len()); + ptr::copy_nonoverlapping(right.as_ptr(), self.ptr(), right.len()); + } + } + } + /// Frobs the head and tail sections around to handle the fact that we /// just reallocated. Unsafe because it trusts old_capacity. #[inline] @@ -475,6 +494,7 @@ /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn new() -> VecDeque { VecDeque::new_in(Global) } @@ -490,6 +510,7 @@ /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn with_capacity(capacity: usize) -> VecDeque { Self::with_capacity_in(capacity, Global) } @@ -711,7 +732,6 @@ /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// use std::collections::VecDeque; /// @@ -730,7 +750,7 @@ /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.try_reserve(additional) } @@ -749,7 +769,6 @@ /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// use std::collections::VecDeque; /// @@ -768,7 +787,7 @@ /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { let old_cap = self.cap(); let used_cap = self.len() + 1; @@ -1002,12 +1021,9 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> { // SAFETY: The internal `IterMut` safety invariant is established because the // `ring` we create is a dereferencable slice for lifetime '_. - IterMut { - tail: self.tail, - head: self.head, - ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()), - phantom: PhantomData, - } + let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()); + + unsafe { IterMut::new(ring, self.tail, self.head, PhantomData) } } /// Returns a pair of slices which contain, in order, the contents of the @@ -1194,12 +1210,9 @@ // SAFETY: The internal `IterMut` safety invariant is established because the // `ring` we create is a dereferencable slice for lifetime '_. - IterMut { - tail, - head, - ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()), - phantom: PhantomData, - } + let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()); + + unsafe { IterMut::new(ring, tail, head, PhantomData) } } /// Creates a draining iterator that removes the specified range in the @@ -1271,19 +1284,17 @@ // the drain is complete and the Drain destructor is run. self.head = drain_tail; - Drain { - deque: NonNull::from(&mut *self), - after_tail: drain_head, - after_head: head, - iter: Iter { - tail: drain_tail, - head: drain_head, - // Crucially, we only create shared references from `self` here and read from - // it. We do not write to `self` nor reborrow to a mutable reference. - // Hence the raw pointer we created above, for `deque`, remains valid. - ring: unsafe { self.buffer_as_slice() }, - }, - } + let deque = NonNull::from(&mut *self); + let iter = Iter { + tail: drain_tail, + head: drain_head, + // Crucially, we only create shared references from `self` here and read from + // it. We do not write to `self` nor reborrow to a mutable reference. + // Hence the raw pointer we created above, for `deque`, remains valid. + ring: unsafe { self.buffer_as_slice() }, + }; + + unsafe { Drain::new(drain_head, head, iter, deque) } } /// Clears the `VecDeque`, removing all values. @@ -2089,8 +2100,17 @@ #[inline] #[stable(feature = "append", since = "1.4.0")] pub fn append(&mut self, other: &mut Self) { - // naive impl - self.extend(other.drain(..)); + self.reserve(other.len()); + unsafe { + let (left, right) = other.as_slices(); + self.copy_slice(self.head, left); + self.copy_slice(self.wrap_add(self.head, left.len()), right); + } + // SAFETY: Update pointers after copying to avoid leaving doppelganger + // in case of panics. + self.head = self.wrap_add(self.head, other.len()); + // Silently drop values in `other`. + other.tail = other.head; } /// Retains only the elements specified by the predicate. @@ -2828,7 +2848,7 @@ /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by /// value. fn into_iter(self) -> IntoIter { - IntoIter { inner: self } + IntoIter::new(self) } } @@ -3004,6 +3024,16 @@ /// assert_eq!(deq1, deq2); /// ``` fn from(arr: [T; N]) -> Self { - core::array::IntoIter::new(arr).collect() + let mut deq = VecDeque::with_capacity(N); + let arr = ManuallyDrop::new(arr); + if mem::size_of::() != 0 { + // SAFETY: VecDeque::with_capacity ensures that there is enough capacity. + unsafe { + ptr::copy_nonoverlapping(arr.as_ptr(), deq.ptr(), N); + } + } + deq.tail = 0; + deq.head = N; + deq } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/pair_slices.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/pair_slices.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/pair_slices.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/pair_slices.rs 2021-11-29 19:27:11.000000000 +0000 @@ -20,10 +20,10 @@ /// /// and the uneven remainder of either A or B is skipped. pub struct PairSlices<'a, 'b, T> { - pub(crate) a0: &'a mut [T], - pub(crate) a1: &'a mut [T], - pub(crate) b0: &'b [T], - pub(crate) b1: &'b [T], + a0: &'a mut [T], + a1: &'a mut [T], + b0: &'b [T], + b1: &'b [T], } impl<'a, 'b, T> PairSlices<'a, 'b, T> { diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/tests.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/collections/vec_deque/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -508,6 +508,36 @@ } #[test] +fn test_from_array() { + fn test() { + let mut array: [usize; N] = [0; N]; + + for i in 0..N { + array[i] = i; + } + + let deq: VecDeque<_> = array.into(); + + for i in 0..N { + assert_eq!(deq[i], i); + } + + assert!(deq.cap().is_power_of_two()); + assert_eq!(deq.len(), N); + } + test::<0>(); + test::<1>(); + test::<2>(); + test::<32>(); + test::<35>(); + + let array = [(); MAXIMUM_ZST_CAPACITY - 1]; + let deq = VecDeque::from(array); + assert!(deq.cap().is_power_of_two()); + assert_eq!(deq.len(), MAXIMUM_ZST_CAPACITY - 1); +} + +#[test] fn test_vec_from_vecdeque() { use crate::vec::Vec; diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/fmt.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/fmt.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/fmt.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/fmt.rs 2021-11-29 19:27:11.000000000 +0000 @@ -348,7 +348,7 @@ //! provides some helper methods. //! //! Additionally, the return value of this function is [`fmt::Result`] which is a -//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations +//! type alias of [Result]<(), [std::fmt::Error]>. Formatting implementations //! should ensure that they propagate errors from the [`Formatter`] (e.g., when //! calling [`write!`]). However, they should never return errors spuriously. That //! is, a formatting implementation must and may only return an error if the @@ -505,23 +505,19 @@ //! it would internally pass around this structure until it has been determined //! where output should go to. //! -//! [`fmt::Result`]: Result -//! [`Result`]: core::result::Result -//! [`std::fmt::Error`]: Error -//! [`write!`]: core::write -//! [`write`]: core::write -//! [`format!`]: crate::format -//! [`to_string`]: crate::string::ToString -//! [`writeln!`]: core::writeln +//! [`fmt::Result`]: Result "fmt::Result" +//! [Result]: core::result::Result "std::result::Result" +//! [std::fmt::Error]: Error "fmt::Error" +//! [`write`]: write() "fmt::write" +//! [`to_string`]: crate::string::ToString::to_string "ToString::to_string" //! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt //! [`std::io::Write`]: ../../std/io/trait.Write.html -//! [`print!`]: ../../std/macro.print.html -//! [`println!`]: ../../std/macro.println.html -//! [`eprint!`]: ../../std/macro.eprint.html -//! [`eprintln!`]: ../../std/macro.eprintln.html -//! [`format_args!`]: core::format_args -//! [`fmt::Arguments`]: Arguments -//! [`format`]: crate::format +//! [`print!`]: ../../std/macro.print.html "print!" +//! [`println!`]: ../../std/macro.println.html "println!" +//! [`eprint!`]: ../../std/macro.eprint.html "eprint!" +//! [`eprintln!`]: ../../std/macro.eprintln.html "eprintln!" +//! [`fmt::Arguments`]: Arguments "fmt::Arguments" +//! [`format`]: format() "fmt::format" #![stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -67,6 +67,17 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) )] +#![cfg_attr( + not(bootstrap), + 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), + target_has_atomic = "ptr" + )) +)] #![no_std] #![needs_allocator] #![warn(deprecated_in_future)] @@ -85,7 +96,6 @@ #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(async_stream)] -#![cfg_attr(bootstrap, feature(bindings_after_at))] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(cfg_sanitize)] @@ -112,6 +122,7 @@ // that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs // from other crates, but since this can only appear for lang items, it doesn't seem worth fixing. #![feature(intra_doc_pointers)] +#![feature(iter_advance_by)] #![feature(iter_zip)] #![feature(lang_items)] #![feature(layout_for_ptr)] @@ -143,11 +154,11 @@ #![feature(alloc_layout_extra)] #![feature(trusted_random_access)] #![feature(try_trait_v2)] -#![cfg_attr(bootstrap, feature(min_type_alias_impl_trait))] -#![cfg_attr(not(bootstrap), feature(type_alias_impl_trait))] #![feature(associated_type_bounds)] #![feature(slice_group_by)] #![feature(decl_macro)] +#![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] // Allow testing this library #[cfg(test)] @@ -178,7 +189,6 @@ pub mod borrow; pub mod collections; pub mod fmt; -pub mod prelude; pub mod raw_vec; pub mod rc; pub mod slice; diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/prelude/mod.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/prelude/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/prelude/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/prelude/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -//! The alloc Prelude -//! -//! The purpose of this module is to alleviate imports of commonly-used -//! items of the `alloc` crate by adding a glob import to the top of modules: -//! -//! ``` -//! # #![allow(unused_imports)] -//! #![feature(alloc_prelude)] -//! extern crate alloc; -//! use alloc::prelude::v1::*; -//! ``` - -#![unstable(feature = "alloc_prelude", issue = "58935")] - -pub mod v1; diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/prelude/v1.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/prelude/v1.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/prelude/v1.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/prelude/v1.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -//! The first version of the prelude of `alloc` crate. -//! -//! See the [module-level documentation](../index.html) for more. - -#![unstable(feature = "alloc_prelude", issue = "58935")] - -#[unstable(feature = "alloc_prelude", issue = "58935")] -pub use crate::borrow::ToOwned; -#[unstable(feature = "alloc_prelude", issue = "58935")] -pub use crate::boxed::Box; -#[unstable(feature = "alloc_prelude", issue = "58935")] -pub use crate::string::{String, ToString}; -#[unstable(feature = "alloc_prelude", issue = "58935")] -pub use crate::vec::Vec; diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/raw_vec.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/raw_vec.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/raw_vec.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/raw_vec.rs 2021-11-29 19:27:11.000000000 +0000 @@ -69,6 +69,7 @@ /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. + #[must_use] pub const fn new() -> Self { Self::new_in(Global) } @@ -87,6 +88,7 @@ /// /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] + #[must_use] #[inline] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) @@ -94,6 +96,7 @@ /// Like `with_capacity`, but guarantees the buffer is zeroed. #[cfg(not(no_global_oom_handling))] + #[must_use] #[inline] pub fn with_capacity_zeroed(capacity: usize) -> Self { Self::with_capacity_zeroed_in(capacity, Global) @@ -323,7 +326,7 @@ pub fn reserve(&mut self, len: usize, additional: usize) { // Callers expect this function to be very cheap when there is already sufficient capacity. // Therefore, we move all the resizing and error-handling logic from grow_amortized and - // handle_reserve behind a call, while making sure that the this function is likely to be + // handle_reserve behind a call, while making sure that this function is likely to be // inlined as just a comparison and a call if the comparison fails. #[cold] fn do_reserve_and_handle( diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/rc.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/rc.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/rc.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/rc.rs 2021-11-29 19:27:11.000000000 +0000 @@ -452,6 +452,7 @@ /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_uninit() -> Rc> { unsafe { Rc::from_ptr(Rc::allocate_for_layout( @@ -484,6 +485,7 @@ /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_zeroed() -> Rc> { unsafe { Rc::from_ptr(Rc::allocate_for_layout( @@ -587,6 +589,7 @@ /// `value` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] #[stable(feature = "pin", since = "1.33.0")] + #[must_use] pub fn pin(value: T) -> Pin> { unsafe { Pin::new_unchecked(Rc::new(value)) } } @@ -658,6 +661,7 @@ /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit]> { unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) } } @@ -684,6 +688,7 @@ /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { unsafe { Rc::from_ptr(Rc::allocate_for_layout( @@ -782,9 +787,7 @@ /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw`][from_raw]. - /// - /// [from_raw]: Rc::from_raw + /// [`Rc::from_raw`]. /// /// # Examples /// @@ -835,7 +838,7 @@ /// and alignment as `T`. This is trivially true if `U` is `T`. /// Note that if `U` is not `T` but has the same size and alignment, this is /// basically like transmuting references of different types. See - /// [`mem::transmute`][transmute] for more information on what + /// [`mem::transmute`] for more information on what /// restrictions apply in this case. /// /// The user of `from_raw` has to make sure a specific value of `T` is only @@ -845,7 +848,6 @@ /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw - /// [transmute]: core::mem::transmute /// /// # Examples /// @@ -1087,8 +1089,6 @@ /// assert!(Rc::ptr_eq(&five, &same_five)); /// assert!(!Rc::ptr_eq(&five, &other_five)); /// ``` - /// - /// [`ptr::eq`]: core::ptr::eq pub fn ptr_eq(this: &Self, other: &Self) -> bool { this.ptr.as_ptr() == other.ptr.as_ptr() } @@ -1994,7 +1994,7 @@ /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [`Option`]`<`[`Rc`]`>`. +/// pointer, which returns an [Option]<[Rc]\>. /// /// Since a `Weak` reference does not count towards ownership, it will not /// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no @@ -2049,6 +2049,7 @@ /// assert!(empty.upgrade().is_none()); /// ``` #[stable(feature = "downgraded_weak", since = "1.10.0")] + #[must_use] pub fn new() -> Weak { Weak { ptr: NonNull::new(usize::MAX as *mut RcBox).expect("MAX is not 0") } } @@ -2091,7 +2092,8 @@ /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// - /// [`null`]: core::ptr::null + /// [`null`]: ptr::null + #[must_use] #[stable(feature = "rc_as_ptr", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); @@ -2135,6 +2137,7 @@ /// /// [`from_raw`]: Weak::from_raw /// [`as_ptr`]: Weak::as_ptr + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { let result = self.as_ptr(); @@ -2227,6 +2230,8 @@ /// /// assert!(weak_five.upgrade().is_none()); /// ``` + #[must_use = "this returns a new `Rc`, \ + without modifying the original weak pointer"] #[stable(feature = "rc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { let inner = self.inner()?; @@ -2318,8 +2323,6 @@ /// let third = Rc::downgrade(&third_rc); /// assert!(!first.ptr_eq(&third)); /// ``` - /// - /// [`ptr::eq`]: core::ptr::eq #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { @@ -2401,7 +2404,6 @@ /// Constructs a new `Weak`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [`None`]: Option /// [`upgrade`]: Weak::upgrade /// /// # Examples diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/slice.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/slice.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/slice.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/slice.rs 2021-11-29 19:27:11.000000000 +0000 @@ -662,6 +662,8 @@ /// /// [`make_ascii_uppercase`]: slice::make_ascii_uppercase #[cfg(not(no_global_oom_handling))] + #[must_use = "this returns the uppercase bytes as a new Vec, \ + without modifying the original"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> Vec { @@ -680,6 +682,8 @@ /// /// [`make_ascii_lowercase`]: slice::make_ascii_lowercase #[cfg(not(no_global_oom_handling))] + #[must_use = "this returns the lowercase bytes as a new Vec, \ + without modifying the original"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> Vec { diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/string.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/string.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/string.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/string.rs 2021-11-29 19:27:11.000000000 +0000 @@ -79,7 +79,7 @@ /// /// # Examples /// -/// You can create a `String` from [a literal string][`str`] with [`String::from`]: +/// You can create a `String` from [a literal string][`&str`] with [`String::from`]: /// /// [`String::from`]: From::from /// @@ -128,7 +128,7 @@ /// println!("The first letter of s is {}", s[0]); // ERROR!!! /// ``` /// -/// [`OsString`]: ../../std/ffi/struct.OsString.html +/// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString" /// /// Indexing is intended to be a constant-time operation, but UTF-8 encoding /// does not allow us to do this. Furthermore, it's not clear what sort of @@ -141,7 +141,7 @@ /// /// # Deref /// -/// `String`s implement [`Deref`]``, and so inherit all of [`str`]'s +/// `String` implements [Deref], and so inherits all of [`str`]'s /// methods. In addition, this means that you can pass a `String` to a /// function which takes a [`&str`] by using an ampersand (`&`): /// @@ -182,7 +182,7 @@ /// to explicitly extract the string slice containing the string. The second /// way changes `example_func(&example_string);` to /// `example_func(&*example_string);`. In this case we are dereferencing a -/// `String` to a [`str`][`&str`], then referencing the [`str`][`&str`] back to +/// `String` to a [`str`], then referencing the [`str`] back to /// [`&str`]. The second way is more idiomatic, however both work to do the /// conversion explicitly rather than relying on the implicit conversion. /// @@ -282,12 +282,14 @@ /// /// Here, there's no need to allocate more memory inside the loop. /// -/// [`str`]: prim@str -/// [`&str`]: prim@str -/// [`Deref`]: core::ops::Deref +/// [str]: prim@str "str" +/// [`str`]: prim@str "str" +/// [`&str`]: prim@str "&str" +/// [Deref]: core::ops::Deref "ops::Deref" +/// [`Deref`]: core::ops::Deref "ops::Deref" /// [`as_str()`]: String::as_str #[derive(PartialOrd, Eq, Ord)] -#[cfg_attr(not(test), rustc_diagnostic_item = "string_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "String")] #[stable(feature = "rust1", since = "1.0.0")] pub struct String { vec: Vec, @@ -308,10 +310,10 @@ /// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error` /// through the [`utf8_error`] method. /// -/// [`Utf8Error`]: core::str::Utf8Error -/// [`std::str`]: core::str -/// [`&str`]: prim@str -/// [`utf8_error`]: Self::utf8_error +/// [`Utf8Error`]: str::Utf8Error "std::str::Utf8Error" +/// [`std::str`]: core::str "std::str" +/// [`&str`]: prim@str "&str" +/// [`utf8_error`]: FromUtf8Error::utf8_error /// /// # Examples /// @@ -376,6 +378,7 @@ #[inline] #[rustc_const_stable(feature = "const_string_new", since = "1.39.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub const fn new() -> String { String { vec: Vec::new() } } @@ -420,6 +423,7 @@ #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn with_capacity(capacity: usize) -> String { String { vec: Vec::with_capacity(capacity) } } @@ -487,8 +491,8 @@ /// with this error. /// /// [`from_utf8_unchecked`]: String::from_utf8_unchecked - /// [`Vec`]: crate::vec::Vec - /// [`&str`]: prim@str + /// [`Vec`]: crate::vec::Vec "Vec" + /// [`&str`]: prim@str "&str" /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -524,7 +528,7 @@ /// it's already valid UTF-8, we don't need a new allocation. This return /// type allows us to handle both cases. /// - /// [`Cow<'a, str>`]: crate::borrow::Cow + /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow" /// /// # Examples /// @@ -625,7 +629,7 @@ /// conversion requires a memory allocation. /// /// [`from_utf8_lossy`]: String::from_utf8_lossy - /// [`Cow<'a, str>`]: crate::borrow::Cow + /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow" /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER /// /// # Examples @@ -674,6 +678,7 @@ /// let rebuilt = unsafe { String::from_raw_parts(ptr, len, cap) }; /// assert_eq!(rebuilt, "hello"); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] pub fn into_raw_parts(self) -> (*mut u8, usize, usize) { self.vec.into_raw_parts() @@ -759,6 +764,7 @@ /// assert_eq!("💖", sparkle_heart); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_utf8_unchecked(bytes: Vec) -> String { String { vec: bytes } @@ -779,6 +785,7 @@ /// assert_eq!(&[104, 101, 108, 108, 111][..], &bytes[..]); /// ``` #[inline] + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] pub fn into_bytes(self) -> Vec { self.vec @@ -796,6 +803,7 @@ /// assert_eq!("foo", s.as_str()); /// ``` #[inline] + #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] pub fn as_str(&self) -> &str { self @@ -816,6 +824,7 @@ /// assert_eq!("FOOBAR", s_mut_str); /// ``` #[inline] + #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] pub fn as_mut_str(&mut self) -> &mut str { self @@ -1007,7 +1016,6 @@ /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// /// fn process_data(data: &str) -> Result { @@ -1023,7 +1031,7 @@ /// } /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.vec.try_reserve(additional) } @@ -1047,7 +1055,6 @@ /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// /// fn process_data(data: &str) -> Result { @@ -1063,7 +1070,7 @@ /// } /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.vec.try_reserve_exact(additional) } @@ -1158,6 +1165,7 @@ /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes()); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes(&self) -> &[u8] { &self.vec @@ -1721,11 +1729,11 @@ unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes()); } - /// Converts this `String` into a [`Box`]`<`[`str`]`>`. + /// Converts this `String` into a [Box]<[str]>. /// /// This will drop any excess capacity. /// - /// [`str`]: prim@str + /// [str]: prim@str "str" /// /// # Examples /// @@ -1738,6 +1746,7 @@ /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_str", since = "1.4.0")] + #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub fn into_boxed_str(self) -> Box { let slice = self.vec.into_boxed_slice(); @@ -1760,6 +1769,7 @@ /// /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes()); /// ``` + #[must_use] #[stable(feature = "from_utf8_error_as_bytes", since = "1.26.0")] pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] @@ -1783,6 +1793,7 @@ /// /// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes()); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] pub fn into_bytes(self) -> Vec { self.bytes @@ -1795,8 +1806,8 @@ /// an analogue to `FromUtf8Error`. See its documentation for more details /// on using it. /// - /// [`std::str`]: core::str - /// [`&str`]: prim@str + /// [`std::str`]: core::str "std::str" + /// [`&str`]: prim@str "&str" /// /// # Examples /// @@ -2319,7 +2330,7 @@ /// /// This alias exists for backwards compatibility, and may be eventually deprecated. /// -/// [`Infallible`]: core::convert::Infallible +/// [`Infallible`]: core::convert::Infallible "convert::Infallible" #[stable(feature = "str_parse_error", since = "1.5.0")] pub type ParseError = core::convert::Infallible; @@ -2606,7 +2617,7 @@ /// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant")); /// ``` /// - /// [`Borrowed`]: crate::borrow::Cow::Borrowed + /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed" #[inline] fn from(s: &'a str) -> Cow<'a, str> { Cow::Borrowed(s) @@ -2629,7 +2640,7 @@ /// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2)); /// ``` /// - /// [`Owned`]: crate::borrow::Cow::Owned + /// [`Owned`]: crate::borrow::Cow::Owned "borrow::Cow::Owned" #[inline] fn from(s: String) -> Cow<'a, str> { Cow::Owned(s) @@ -2651,7 +2662,7 @@ /// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant")); /// ``` /// - /// [`Borrowed`]: crate::borrow::Cow::Borrowed + /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed" #[inline] fn from(s: &'a String) -> Cow<'a, str> { Cow::Borrowed(s.as_str()) @@ -2775,6 +2786,7 @@ /// let _ = drain.next().unwrap(); /// assert_eq!(drain.as_str(), "bc"); /// ``` + #[must_use] #[stable(feature = "string_drain_as_str", since = "1.55.0")] pub fn as_str(&self) -> &str { self.iter.as_str() diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/str.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/str.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/str.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/str.rs 2021-11-29 19:27:11.000000000 +0000 @@ -367,6 +367,8 @@ /// assert_eq!(new_year, new_year.to_lowercase()); /// ``` #[cfg(not(no_global_oom_handling))] + #[must_use = "this returns the lowercase string as a new String, \ + without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_lowercase(&self) -> String { let mut s = String::with_capacity(self.len()); @@ -447,6 +449,8 @@ /// assert_eq!("TSCHÃœSS", s.to_uppercase()); /// ``` #[cfg(not(no_global_oom_handling))] + #[must_use = "this returns the uppercase string as a new String, \ + without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { let mut s = String::with_capacity(self.len()); @@ -534,6 +538,7 @@ /// [`make_ascii_uppercase`]: str::make_ascii_uppercase /// [`to_uppercase`]: #method.to_uppercase #[cfg(not(no_global_oom_handling))] + #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase()`"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> String { @@ -565,6 +570,7 @@ /// [`make_ascii_lowercase`]: str::make_ascii_lowercase /// [`to_lowercase`]: #method.to_lowercase #[cfg(not(no_global_oom_handling))] + #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase()`"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> String { @@ -589,6 +595,7 @@ /// assert_eq!("☺", &*smile); /// ``` #[stable(feature = "str_box_extras", since = "1.20.0")] +#[must_use] #[inline] pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/sync.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/sync.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/sync.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/sync.rs 2021-11-29 19:27:11.000000000 +0000 @@ -99,8 +99,8 @@ /// first: after all, isn't the point of `Arc` thread safety? The key is /// this: `Arc` makes it thread safe to have multiple ownership of the same /// data, but it doesn't add thread safety to its data. Consider -/// `Arc<`[`RefCell`]`>`. [`RefCell`] isn't [`Sync`], and if `Arc` was always -/// [`Send`], `Arc<`[`RefCell`]`>` would be as well. But then we'd have a problem: +/// Arc<[RefCell\]>. [`RefCell`] isn't [`Sync`], and if `Arc` was always +/// [`Send`], Arc<[RefCell\]> would be as well. But then we'd have a problem: /// [`RefCell`] is not thread safe; it keeps track of the borrowing count using /// non-atomic operations. /// @@ -146,7 +146,7 @@ /// use std::sync::Arc; /// /// let my_arc = Arc::new(()); -/// Arc::downgrade(&my_arc); +/// let my_weak = Arc::downgrade(&my_arc); /// ``` /// /// `Arc`'s implementations of traits like `Clone` may also be called using @@ -176,6 +176,7 @@ /// [deref]: core::ops::Deref /// [downgrade]: Arc::downgrade /// [upgrade]: Weak::upgrade +/// [RefCell\]: core::cell::RefCell /// [`RefCell`]: core::cell::RefCell /// [`std::sync`]: ../../std/sync/index.html /// [`Arc::clone(&from)`]: Arc::clone @@ -206,7 +207,7 @@ /// /// Sharing a mutable [`AtomicUsize`]: /// -/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize +/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize" /// /// ```no_run /// use std::sync::Arc; @@ -262,7 +263,7 @@ /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. +/// pointer, which returns an [Option]<[Arc]\>. /// /// Since a `Weak` reference does not count towards ownership, it will not /// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no @@ -447,6 +448,7 @@ /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_uninit() -> Arc> { unsafe { Arc::from_ptr(Arc::allocate_for_layout( @@ -476,9 +478,10 @@ /// assert_eq!(*zero, 0) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_zeroed() -> Arc> { unsafe { Arc::from_ptr(Arc::allocate_for_layout( @@ -493,6 +496,7 @@ /// `data` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] #[stable(feature = "pin", since = "1.33.0")] + #[must_use] pub fn pin(data: T) -> Pin> { unsafe { Pin::new_unchecked(Arc::new(data)) } } @@ -661,6 +665,7 @@ /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit]> { unsafe { Arc::from_ptr(Arc::allocate_for_slice(len)) } } @@ -684,9 +689,10 @@ /// assert_eq!(*values, [0, 0, 0]) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use] pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit]> { unsafe { Arc::from_ptr(Arc::allocate_for_layout( @@ -712,7 +718,7 @@ /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -734,6 +740,7 @@ /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub unsafe fn assume_init(self) -> Arc { Arc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) @@ -751,7 +758,7 @@ /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -775,6 +782,7 @@ /// assert_eq!(*values, [1, 2, 3]) /// ``` #[unstable(feature = "new_uninit", issue = "63291")] + #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub unsafe fn assume_init(self) -> Arc<[T]> { unsafe { Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) } @@ -819,6 +827,7 @@ /// assert_eq!(x_ptr, Arc::as_ptr(&y)); /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` + #[must_use] #[stable(feature = "rc_as_ptr", since = "1.45.0")] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); @@ -889,6 +898,8 @@ /// /// let weak_five = Arc::downgrade(&five); /// ``` + #[must_use = "this returns a new `Weak` pointer, \ + without modifying the original `Arc`"] #[stable(feature = "arc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak { // This Relaxed is OK because we're checking the value in the CAS @@ -1086,7 +1097,7 @@ /// assert!(!Arc::ptr_eq(&five, &other_five)); /// ``` /// - /// [`ptr::eq`]: core::ptr::eq + /// [`ptr::eq`]: core::ptr::eq "ptr::eq" pub fn ptr_eq(this: &Self, other: &Self) -> bool { this.ptr.as_ptr() == other.ptr.as_ptr() } @@ -1677,6 +1688,7 @@ /// assert!(empty.upgrade().is_none()); /// ``` #[stable(feature = "downgraded_weak", since = "1.10.0")] + #[must_use] pub fn new() -> Weak { Weak { ptr: NonNull::new(usize::MAX as *mut ArcInner).expect("MAX is not 0") } } @@ -1714,7 +1726,8 @@ /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// - /// [`null`]: core::ptr::null + /// [`null`]: core::ptr::null "ptr::null" + #[must_use] #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); @@ -1758,6 +1771,7 @@ /// /// [`from_raw`]: Weak::from_raw /// [`as_ptr`]: Weak::as_ptr + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { let result = self.as_ptr(); @@ -1806,7 +1820,6 @@ /// [`new`]: Weak::new /// [`into_raw`]: Weak::into_raw /// [`upgrade`]: Weak::upgrade - /// [`forget`]: std::mem::forget #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { // See Weak::as_ptr for context on how the input pointer is derived. @@ -1852,6 +1865,8 @@ /// /// assert!(weak_five.upgrade().is_none()); /// ``` + #[must_use = "this returns a new `Arc`, \ + without modifying the original weak pointer"] #[stable(feature = "arc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { // We use a CAS loop to increment the strong count instead of a @@ -1982,7 +1997,7 @@ /// assert!(!first.ptr_eq(&third)); /// ``` /// - /// [`ptr::eq`]: core::ptr::eq + /// [`ptr::eq`]: core::ptr::eq "ptr::eq" #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/vec/drain.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/vec/drain.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/vec/drain.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/vec/drain.rs 2021-11-29 19:27:11.000000000 +0000 @@ -52,6 +52,7 @@ /// let _ = drain.next().unwrap(); /// assert_eq!(drain.as_slice(), &['b', 'c']); /// ``` + #[must_use] #[stable(feature = "vec_drain_as_slice", since = "1.46.0")] pub fn as_slice(&self) -> &[T] { self.iter.as_slice() diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/vec/into_iter.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/vec/into_iter.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/vec/into_iter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/vec/into_iter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -162,6 +162,29 @@ } #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let step_size = self.len().min(n); + let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size); + if mem::size_of::() == 0 { + // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound + // effectively results in unsigned pointers representing positions 0..usize::MAX, + // which is valid for ZSTs. + self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T } + } else { + // SAFETY: the min() above ensures that step_size is in bounds + self.ptr = unsafe { self.ptr.add(step_size) }; + } + // SAFETY: the min() above ensures that step_size is in bounds + unsafe { + ptr::drop_in_place(to_drop); + } + if step_size < n { + return Err(step_size); + } + Ok(()) + } + + #[inline] fn count(self) -> usize { self.len() } @@ -203,6 +226,29 @@ Some(unsafe { ptr::read(self.end) }) } } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let step_size = self.len().min(n); + if mem::size_of::() == 0 { + // SAFETY: same as for advance_by() + self.end = unsafe { + arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T + } + } else { + // SAFETY: same as for advance_by() + self.end = unsafe { self.end.offset(step_size.wrapping_neg() as isize) }; + } + let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size); + // SAFETY: same as for advance_by() + unsafe { + ptr::drop_in_place(to_drop); + } + if step_size < n { + return Err(step_size); + } + Ok(()) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -220,14 +266,21 @@ #[doc(hidden)] #[unstable(issue = "none", feature = "std_internals")] +#[rustc_unsafe_specialization_marker] +pub trait NonDrop {} + // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr // and thus we can't implement drop-handling -// +#[unstable(issue = "none", feature = "std_internals")] +impl NonDrop for T {} + +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] // TrustedRandomAccess (without NoCoerce) must not be implemented because -// subtypes/supertypes of `T` might not be `Copy` +// subtypes/supertypes of `T` might not be `NonDrop` unsafe impl TrustedRandomAccessNoCoerce for IntoIter where - T: Copy, + T: NonDrop, { const MAY_HAVE_SIDE_EFFECT: bool = false; } diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/vec/mod.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/vec/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/vec/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/vec/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,8 +1,8 @@ //! A contiguous growable array type with heap-allocated contents, written //! `Vec`. //! -//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and -//! `O(1)` pop (from the end). +//! Vectors have *O*(1) indexing, amortized *O*(1) push (to the end) and +//! *O*(1) pop (from the end). //! //! Vectors ensure they never allocate more than `isize::MAX` bytes. //! @@ -296,8 +296,8 @@ /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized /// types inside a `Vec`, it will not allocate space for them. *Note that in this case /// the `Vec` might not report a [`capacity`] of 0*. `Vec` will allocate if and only -/// if [`mem::size_of::`]`() * capacity() > 0`. In general, `Vec`'s allocation -/// details are very subtle — if you intend to allocate memory using a `Vec` +/// if [mem::size_of::\]\() * [capacity]\() > 0. In general, `Vec`'s allocation +/// details are very subtle --- if you intend to allocate memory using a `Vec` /// and use it for something else (either to pass to unsafe code, or to build your /// own memory-backed collection), be sure to deallocate this memory by using /// `from_raw_parts` to recover the `Vec` and then dropping it. @@ -305,8 +305,8 @@ /// If a `Vec` *has* allocated memory, then the memory it points to is on the heap /// (as defined by the allocator Rust is configured to use by default), and its /// pointer points to [`len`] initialized, contiguous elements in order (what -/// you would see if you coerced it to a slice), followed by [`capacity`]` - -/// `[`len`] logically uninitialized, contiguous elements. +/// you would see if you coerced it to a slice), followed by [capacity] - [len] +/// logically uninitialized, contiguous elements. /// /// A vector containing the elements `'a'` and `'b'` with capacity 4 can be /// visualized as below. The top part is the `Vec` struct, it contains a @@ -348,7 +348,7 @@ /// /// [`push`] and [`insert`] will never (re)allocate if the reported capacity is /// sufficient. [`push`] and [`insert`] *will* (re)allocate if -/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely +/// [len] == [capacity]. That is, the reported capacity is completely /// accurate, and can be relied on. It can even be used to manually free the memory /// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even /// when not necessary. @@ -360,7 +360,7 @@ /// /// `vec![x; n]`, `vec![a, b, c, d]`, and /// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec` -/// with exactly the requested capacity. If [`len`]` == `[`capacity`], +/// with exactly the requested capacity. If [len] == [capacity], /// (as is the case for the [`vec!`] macro), then a `Vec` can be converted to /// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements. /// @@ -369,7 +369,7 @@ /// scratch space that it may use however it wants. It will generally just do /// whatever is most efficient or otherwise easy to implement. Do not rely on /// removed data to be erased for security purposes. Even if you drop a `Vec`, its -/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory +/// buffer may simply be reused by another allocation. Even if you zero a `Vec`'s memory /// first, that might not actually happen because the optimizer does not consider /// this a side-effect that must be preserved. There is one case which we will /// not break, however: using `unsafe` code to write to the excess capacity, @@ -384,8 +384,10 @@ /// [`&str`]: type@str /// [`shrink_to_fit`]: Vec::shrink_to_fit /// [`shrink_to`]: Vec::shrink_to +/// [capacity]: Vec::capacity /// [`capacity`]: Vec::capacity -/// [`mem::size_of::`]: core::mem::size_of +/// [mem::size_of::\]: core::mem::size_of +/// [len]: Vec::len /// [`len`]: Vec::len /// [`push`]: Vec::push /// [`insert`]: Vec::insert @@ -393,7 +395,7 @@ /// [`MaybeUninit`]: core::mem::MaybeUninit /// [owned slice]: Box #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")] #[rustc_insignificant_dtor] pub struct Vec { buf: RawVec, @@ -418,6 +420,7 @@ #[inline] #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub const fn new() -> Self { Vec { buf: RawVec::NEW, len: 0 } } @@ -462,6 +465,7 @@ #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) } @@ -847,7 +851,6 @@ /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// /// fn process_data(data: &[u32]) -> Result, TryReserveError> { @@ -865,7 +868,7 @@ /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve(self.len, additional) } @@ -890,7 +893,6 @@ /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// /// fn process_data(data: &[u32]) -> Result, TryReserveError> { @@ -908,7 +910,7 @@ /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve_exact(self.len, additional) } @@ -1269,7 +1271,7 @@ /// /// The removed element is replaced by the last element of the vector. /// - /// This does not preserve ordering, but is O(1). + /// This does not preserve ordering, but is *O*(1). /// /// # Panics /// @@ -1486,7 +1488,15 @@ let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; - while g.processed_len < original_len { + // process_one return a bool indicates whether the processing element should be retained. + #[inline(always)] + fn process_one( + f: &mut F, + g: &mut BackshiftOnDrop<'_, T, A>, + ) -> bool + where + F: FnMut(&T) -> bool, + { // SAFETY: Unchecked element must be valid. let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; if !f(cur) { @@ -1496,9 +1506,9 @@ // SAFETY: We never touch this element again after dropped. unsafe { ptr::drop_in_place(cur) }; // We already advanced the counter. - continue; + return false; } - if g.deleted_cnt > 0 { + if DELETED { // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. // We use copy for move, and never touch this element again. unsafe { @@ -1507,6 +1517,19 @@ } } g.processed_len += 1; + return true; + } + + // Stage 1: Nothing was deleted. + while g.processed_len != original_len { + if !process_one::(&mut f, &mut g) { + break; + } + } + + // Stage 2: Some elements were deleted. + while g.processed_len != original_len { + process_one::(&mut f, &mut g); } // All item are processed. This can be optimized to `set_len` by LLVM. @@ -1950,8 +1973,9 @@ /// `'a`. If the type has only static references, or none at all, then this /// may be chosen to be `'static`. /// - /// This function is similar to the [`leak`][Box::leak] function on [`Box`] - /// except that there is no way to recover the leaked memory. + /// As of Rust 1.57, this method does not reallocate or shrink the `Vec`, + /// so the leaked allocation may include unused capacity that is not part + /// of the returned slice. /// /// This function is mainly useful for data that lives for the remainder of /// the program's life. Dropping the returned reference will cause a memory @@ -1974,7 +1998,8 @@ where A: 'a, { - Box::leak(self.into_boxed_slice()) + let mut me = ManuallyDrop::new(self); + unsafe { slice::from_raw_parts_mut(me.as_mut_ptr(), me.len) } } /// Returns the remaining spare capacity of the vector as a slice of @@ -2114,6 +2139,7 @@ /// in order to be able to clone the passed value. /// If you need more flexibility (or want to rely on [`Default`] instead of /// [`Clone`]), use [`Vec::resize_with`]. + /// If you only need to resize to a smaller size, use [`Vec::truncate`]. /// /// # Examples /// @@ -2165,7 +2191,12 @@ /// Copies elements from `src` range to the end of the vector. /// - /// ## Examples + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples /// /// ``` /// let mut vec = vec![0, 1, 2, 3, 4]; @@ -2842,6 +2873,7 @@ } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_from_array", since = "1.44.0")] impl From<[T; N]> for Vec { #[cfg(not(test))] diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/src/vec/source_iter_marker.rs rustc-1.57.0+dfsg1+llvm/library/alloc/src/vec/source_iter_marker.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/src/vec/source_iter_marker.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/src/vec/source_iter_marker.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,24 +6,14 @@ /// Specialization marker for collecting an iterator pipeline into a Vec while reusing the /// source allocation, i.e. executing the pipeline in place. -/// -/// The SourceIter parent trait is necessary for the specializing function to access the allocation -/// which is to be reused. But it is not sufficient for the specialization to be valid. See -/// additional bounds on the impl. #[rustc_unsafe_specialization_marker] -pub(super) trait SourceIterMarker: SourceIter {} +pub(super) trait InPlaceIterableMarker {} -// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of -// Adapter>> (all owned by core/std). Additional bounds -// on the adapter implementations (beyond `impl Trait for Adapter`) only depend on other -// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator). -// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which -// several other specializations already depend on. -impl SourceIterMarker for T where T: SourceIter + InPlaceIterable {} +impl InPlaceIterableMarker for T where T: InPlaceIterable {} impl SpecFromIter for Vec where - I: Iterator + SourceIterMarker, + I: Iterator + SourceIter + InPlaceIterableMarker, { default fn from_iter(mut iterator: I) -> Self { // Additional requirements which cannot expressed via trait bounds. We rely on const eval diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/tests/btree_set_hash.rs rustc-1.57.0+dfsg1+llvm/library/alloc/tests/btree_set_hash.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/tests/btree_set_hash.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/tests/btree_set_hash.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,9 +1,8 @@ +use crate::hash; use std::collections::BTreeSet; #[test] fn test_hash() { - use crate::hash; - let mut x = BTreeSet::new(); let mut y = BTreeSet::new(); @@ -17,3 +16,14 @@ assert_eq!(hash(&x), hash(&y)); } + +#[test] +fn test_prefix_free() { + let x = BTreeSet::from([1, 2, 3]); + let y = BTreeSet::::new(); + + // If hashed by iteration alone, `(x, y)` and `(y, x)` would visit the same + // order of elements, resulting in the same hash. But now that we also hash + // the length, they get distinct sequences of hashed data. + assert_ne!(hash(&(&x, &y)), hash(&(&y, &x))); +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/tests/lib.rs rustc-1.57.0+dfsg1+llvm/library/alloc/tests/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/tests/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/tests/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -8,7 +8,6 @@ #![feature(new_uninit)] #![feature(pattern)] #![feature(trusted_len)] -#![feature(try_reserve)] #![feature(try_reserve_kind)] #![feature(unboxed_closures)] #![feature(associated_type_bounds)] @@ -18,7 +17,7 @@ #![feature(binary_heap_retain)] #![feature(binary_heap_as_slice)] #![feature(inplace_iteration)] -#![feature(iter_map_while)] +#![feature(iter_advance_by)] #![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(vec_spare_capacity)] diff -Nru rustc-1.56.0+dfsg1+llvm/library/alloc/tests/vec.rs rustc-1.57.0+dfsg1+llvm/library/alloc/tests/vec.rs --- rustc-1.56.0+dfsg1+llvm/library/alloc/tests/vec.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/alloc/tests/vec.rs 2021-11-29 19:27:11.000000000 +0000 @@ -971,6 +971,24 @@ } #[test] +fn test_into_iter_advance_by() { + let mut i = vec![1, 2, 3, 4, 5].into_iter(); + i.advance_by(0).unwrap(); + i.advance_back_by(0).unwrap(); + assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]); + + i.advance_by(1).unwrap(); + i.advance_back_by(1).unwrap(); + assert_eq!(i.as_slice(), [2, 3, 4]); + + assert_eq!(i.advance_back_by(usize::MAX), Err(3)); + + assert_eq!(i.advance_by(usize::MAX), Err(0)); + + assert_eq!(i.len(), 0); +} + +#[test] fn test_from_iter_specialization() { let src: Vec = vec![0usize; 1]; let srcptr = src.as_ptr(); diff -Nru rustc-1.56.0+dfsg1+llvm/library/backtrace/src/symbolize/gimli.rs rustc-1.57.0+dfsg1+llvm/library/backtrace/src/symbolize/gimli.rs --- rustc-1.56.0+dfsg1+llvm/library/backtrace/src/symbolize/gimli.rs 2021-10-18 09:52:55.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/backtrace/src/symbolize/gimli.rs 2021-11-29 19:27:28.000000000 +0000 @@ -177,6 +177,7 @@ target_os = "linux", target_os = "fuchsia", target_os = "freebsd", + target_os = "openbsd", all(target_os = "android", feature = "dl_iterate_phdr"), ), not(target_env = "uclibc"), diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/benches/lib.rs rustc-1.57.0+dfsg1+llvm/library/core/benches/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/core/benches/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/benches/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,7 @@ // wasm32 does not support benches (no time). #![cfg(not(target_arch = "wasm32"))] #![feature(flt2dec)] +#![feature(int_log)] #![feature(test)] extern crate test; @@ -15,3 +16,4 @@ mod ops; mod pattern; mod slice; +mod str; diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/benches/num/int_log/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/benches/num/int_log/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/benches/num/int_log/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/benches/num/int_log/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,58 @@ +use rand::Rng; +use test::{black_box, Bencher}; + +macro_rules! int_log_bench { + ($t:ty, $predictable:ident, $random:ident, $random_small:ident) => { + #[bench] + fn $predictable(bench: &mut Bencher) { + bench.iter(|| { + for n in 0..(<$t>::BITS / 8) { + for i in 1..=(100 as $t) { + let x = black_box(i << (n * 8)); + black_box(x.log10()); + } + } + }); + } + + #[bench] + fn $random(bench: &mut Bencher) { + let mut rng = rand::thread_rng(); + /* Exponentially distributed random numbers from the whole range of the type. */ + let numbers: Vec<$t> = (0..256) + .map(|_| { + let x = rng.gen::<$t>() >> rng.gen_range(0, <$t>::BITS); + if x != 0 { x } else { 1 } + }) + .collect(); + bench.iter(|| { + for x in &numbers { + black_box(black_box(x).log10()); + } + }); + } + + #[bench] + fn $random_small(bench: &mut Bencher) { + let mut rng = rand::thread_rng(); + /* Exponentially distributed random numbers from the range 0..256. */ + let numbers: Vec<$t> = (0..256) + .map(|_| { + let x = (rng.gen::() >> rng.gen_range(0, u8::BITS)) as $t; + if x != 0 { x } else { 1 } + }) + .collect(); + bench.iter(|| { + for x in &numbers { + black_box(black_box(x).log10()); + } + }); + } + }; +} + +int_log_bench! {u8, u8_log10_predictable, u8_log10_random, u8_log10_random_small} +int_log_bench! {u16, u16_log10_predictable, u16_log10_random, u16_log10_random_small} +int_log_bench! {u32, u32_log10_predictable, u32_log10_random, u32_log10_random_small} +int_log_bench! {u64, u64_log10_predictable, u64_log10_random, u64_log10_random_small} +int_log_bench! {u128, u128_log10_predictable, u128_log10_random, u128_log10_random_small} diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/benches/num/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/benches/num/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/benches/num/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/benches/num/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ mod dec2flt; mod flt2dec; +mod int_log; use std::str::FromStr; use test::Bencher; diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/benches/str.rs rustc-1.57.0+dfsg1+llvm/library/core/benches/str.rs --- rustc-1.56.0+dfsg1+llvm/library/core/benches/str.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/benches/str.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,33 @@ +use std::str; +use test::{black_box, Bencher}; + +const LOREM_SHORT: &str = "Lorem ipsum"; + +const LOREM: &str = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. +Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. +Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. +At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur"; + +const EMOJI: &str = "😀😃😄ðŸ˜ðŸ˜†ðŸ˜…🤣😂🙂🙃😉😊😇🥰ðŸ˜ðŸ¤©ðŸ˜˜ðŸ˜—☺😚😙🥲😋😛😜🤪ðŸ˜ðŸ¤‘🤗🤭🤫🤔ðŸ¤ðŸ¤¨ðŸ˜ðŸ˜‘😶😶â€ðŸŒ«ï¸ðŸ˜ðŸ˜’🙄😬😮â€ðŸ’¨ðŸ¤¥ðŸ˜ŒðŸ˜”😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵â€ðŸ’«ðŸ¤¯ðŸ¤ ðŸ¥³ðŸ¥¸ðŸ˜ŽðŸ¤“ðŸ§ðŸ˜•ðŸ˜ŸðŸ™â˜¹ðŸ˜®ðŸ˜¯ðŸ˜²ðŸ˜³ðŸ¥ºðŸ˜¦ðŸ˜§ðŸ˜¨ðŸ˜°ðŸ˜¥ðŸ˜¢ðŸ˜­ðŸ˜±ðŸ˜–😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊💋💌💘ðŸ’💖💗💓💞💕💟â£ðŸ’”â¤ï¸â€ðŸ”¥â¤ï¸â€ðŸ©¹â¤ðŸ§¡ðŸ’›ðŸ’šðŸ’™ðŸ’œðŸ¤ŽðŸ–¤ðŸ¤ðŸ’¯ðŸ’¢ðŸ’¥ðŸ’«ðŸ’¦ðŸ’¨ðŸ•³ðŸ’£ðŸ’¬ðŸ‘ï¸â€ðŸ—¨ï¸ðŸ—¨ðŸ—¯ðŸ’­ðŸ’¤ðŸ‘‹ðŸ¤šðŸ–✋🖖👌🤌ðŸ¤âœŒðŸ¤žðŸ¤ŸðŸ¤˜ðŸ¤™ðŸ‘ˆðŸ‘‰ðŸ‘†ðŸ–•ðŸ‘‡â˜ðŸ‘👎✊👊🤛🤜ðŸ‘🙌ðŸ‘🤲ðŸ¤ðŸ™âœðŸ’…🤳💪🦾🦿🦵🦶👂🦻👃🧠🫀ðŸ«ðŸ¦·ðŸ¦´ðŸ‘€ðŸ‘👅👄👶🧒👦👧🧑👱👨🧔🧔â€â™‚ï¸ðŸ§”â€â™€ï¸ðŸ‘¨â€ðŸ¦°ðŸ‘¨â€ðŸ¦±ðŸ‘¨â€ðŸ¦³ðŸ‘¨â€ðŸ¦²ðŸ‘©ðŸ‘©â€ðŸ¦°ðŸ§‘â€ðŸ¦°ðŸ‘©â€ðŸ¦±ðŸ§‘â€ðŸ¦±ðŸ‘©â€ðŸ¦³ðŸ§‘â€ðŸ¦³ðŸ‘©â€ðŸ¦²ðŸ§‘â€ðŸ¦²ðŸ‘±â€â™€ï¸ðŸ‘±â€â™‚ï¸ðŸ§“👴👵ðŸ™ðŸ™â€â™‚ï¸ðŸ™â€â™€ï¸ðŸ™ŽðŸ™Žâ€â™‚ï¸ðŸ™Žâ€â™€ï¸ðŸ™…🙅â€â™‚ï¸ðŸ™…â€â™€ï¸ðŸ™†ðŸ™†â€â™‚ï¸ðŸ™†â€â™€ï¸ðŸ’ðŸ’â€â™‚ï¸ðŸ’â€â™€ï¸ðŸ™‹ðŸ™‹â€â™‚ï¸ðŸ™‹â€â™€ï¸ðŸ§ðŸ§â€â™‚ï¸ðŸ§â€â™€ï¸ðŸ™‡ðŸ™‡â€â™‚ï¸ðŸ™‡â€â™€ï¸ðŸ¤¦ðŸ¤¦â€â™‚ï¸ðŸ¤¦â€â™€ï¸ðŸ¤·ðŸ¤·â€â™‚ï¸ðŸ¤·â€â™€ï¸ðŸ§‘â€âš•ï¸ðŸ‘¨â€âš•ï¸ðŸ‘©â€âš•ï¸ðŸ§‘â€ðŸŽ“👨â€ðŸŽ“👩â€ðŸŽ“🧑â€ðŸ«ðŸ‘¨â€ðŸ«ðŸ‘©â€ðŸ«ðŸ§‘â€âš–ï¸ðŸ‘¨â€âš–ï¸ðŸ‘©â€âš–ï¸ðŸ§‘â€ðŸŒ¾ðŸ‘¨â€ðŸŒ¾ðŸ‘©â€ðŸŒ¾ðŸ§‘â€ðŸ³ðŸ‘¨â€ðŸ³ðŸ‘©â€ðŸ³ðŸ§‘â€ðŸ”§ðŸ‘¨â€ðŸ”§ðŸ‘©â€ðŸ”§ðŸ§‘â€ðŸ­ðŸ‘¨â€ðŸ­ðŸ‘©â€ðŸ­ðŸ§‘â€ðŸ’¼ðŸ‘¨â€ðŸ’¼ðŸ‘©â€ðŸ’¼ðŸ§‘â€ðŸ”¬ðŸ‘¨â€ðŸ”¬ðŸ‘©â€ðŸ”¬ðŸ§‘â€ðŸ’»ðŸ‘¨â€ðŸ’»ðŸ‘©â€ðŸ’»ðŸ§‘â€ðŸŽ¤ðŸ‘¨â€ðŸŽ¤ðŸ‘©â€ðŸŽ¤ðŸ§‘â€ðŸŽ¨ðŸ‘¨â€ðŸŽ¨ðŸ‘©â€ðŸŽ¨ðŸ§‘â€âœˆï¸ðŸ‘¨â€âœˆï¸ðŸ‘©â€âœˆï¸ðŸ§‘â€ðŸš€ðŸ‘¨â€ðŸš€ðŸ‘©â€ðŸš€ðŸ§‘â€ðŸš’👨â€ðŸš’👩â€ðŸš’👮👮â€â™‚ï¸ðŸ‘®â€â™€ï¸ðŸ•µðŸ•µï¸â€â™‚ï¸ðŸ•µï¸â€â™€ï¸ðŸ’‚💂â€â™‚ï¸ðŸ’‚â€â™€ï¸ðŸ¥·ðŸ‘·ðŸ‘·â€â™‚ï¸ðŸ‘·â€â™€ï¸ðŸ¤´ðŸ‘¸ðŸ‘³ðŸ‘³â€â™‚ï¸ðŸ‘³â€â™€ï¸ðŸ‘²ðŸ§•ðŸ¤µðŸ¤µâ€â™‚ï¸ðŸ¤µâ€â™€ï¸ðŸ‘°ðŸ‘°â€â™‚ï¸ðŸ‘°â€â™€ï¸ðŸ¤°ðŸ¤±ðŸ‘©â€ðŸ¼ðŸ‘¨â€ðŸ¼ðŸ§‘â€ðŸ¼ðŸ‘¼ðŸŽ…🤶🧑â€ðŸŽ„🦸🦸â€â™‚ï¸ðŸ¦¸â€â™€ï¸ðŸ¦¹ðŸ¦¹â€â™‚ï¸ðŸ¦¹â€â™€ï¸ðŸ§™ðŸ§™â€â™‚ï¸ðŸ§™â€â™€ï¸ðŸ§šðŸ§šâ€â™‚ï¸ðŸ§šâ€â™€ï¸ðŸ§›ðŸ§›â€â™‚ï¸ðŸ§›â€â™€ï¸ðŸ§œðŸ§œâ€â™‚ï¸ðŸ§œâ€â™€ï¸ðŸ§ðŸ§â€â™‚ï¸ðŸ§â€â™€ï¸ðŸ§žðŸ§žâ€â™‚ï¸ðŸ§žâ€â™€ï¸ðŸ§ŸðŸ§Ÿâ€â™‚ï¸ðŸ§Ÿâ€â™€ï¸ðŸ’†ðŸ’†â€â™‚ï¸ðŸ’†â€â™€ï¸ðŸ’‡ðŸ’‡â€â™‚ï¸ðŸ’‡â€â™€ï¸ðŸš¶ðŸš¶â€â™‚ï¸ðŸš¶â€â™€ï¸ðŸ§ðŸ§â€â™‚ï¸ðŸ§â€â™€ï¸ðŸ§ŽðŸ§Žâ€â™‚ï¸ðŸ§Žâ€â™€ï¸ðŸ§‘â€ðŸ¦¯ðŸ‘¨â€ðŸ¦¯ðŸ‘©â€ðŸ¦¯ðŸ§‘â€ðŸ¦¼ðŸ‘¨â€ðŸ¦¼ðŸ‘©â€ðŸ¦¼ðŸ§‘â€ðŸ¦½ðŸ‘¨â€ðŸ¦½ðŸ‘©â€ðŸ¦½ðŸƒðŸƒâ€â™‚ï¸ðŸƒâ€â™€ï¸ðŸ’ƒðŸ•ºðŸ•´ðŸ‘¯ðŸ‘¯â€â™‚ï¸ðŸ‘¯â€â™€ï¸ðŸ§–🧖â€â™‚ï¸ðŸ§–â€â™€ï¸ðŸ§—🧗â€â™‚ï¸ðŸ§—â€â™€ï¸ðŸ¤ºðŸ‡â›·ðŸ‚ðŸŒðŸŒï¸â€â™‚ï¸ðŸŒï¸â€â™€ï¸ðŸ„ðŸ„â€â™‚ï¸ðŸ„â€â™€ï¸ðŸš£ðŸš£â€â™‚ï¸ðŸš£â€â™€ï¸ðŸŠðŸŠâ€â™‚ï¸ðŸŠâ€â™€ï¸â›¹â›¹ï¸â€â™‚ï¸â›¹ï¸â€â™€ï¸ðŸ‹ðŸ‹ï¸â€â™‚ï¸ðŸ‹ï¸â€â™€ï¸ðŸš´ðŸš´â€â™‚ï¸ðŸš´â€â™€ï¸ðŸšµðŸšµâ€â™‚ï¸ðŸšµâ€â™€ï¸ðŸ¤¸ðŸ¤¸â€â™‚ï¸ðŸ¤¸â€â™€ï¸ðŸ¤¼ðŸ¤¼â€â™‚ï¸ðŸ¤¼â€â™€ï¸ðŸ¤½ðŸ¤½â€â™‚ï¸ðŸ¤½â€â™€ï¸ðŸ¤¾ðŸ¤¾â€â™‚ï¸ðŸ¤¾â€â™€ï¸ðŸ¤¹ðŸ¤¹â€â™‚ï¸ðŸ¤¹â€â™€ï¸ðŸ§˜ðŸ§˜â€â™‚ï¸ðŸ§˜â€â™€ï¸ðŸ›€ðŸ›ŒðŸ§‘â€ðŸ¤â€ðŸ§‘👭👫👬ðŸ’👩â€â¤ï¸â€ðŸ’‹â€ðŸ‘¨ðŸ‘¨â€â¤ï¸â€ðŸ’‹â€ðŸ‘¨ðŸ‘©â€â¤ï¸â€ðŸ’‹â€ðŸ‘©ðŸ’‘👩â€â¤ï¸â€ðŸ‘¨ðŸ‘¨â€â¤ï¸â€ðŸ‘¨ðŸ‘©â€â¤ï¸â€ðŸ‘©ðŸ‘ªðŸ‘¨â€ðŸ‘©â€ðŸ‘¦ðŸ‘¨â€ðŸ‘©â€ðŸ‘§ðŸ‘¨â€ðŸ‘©â€ðŸ‘§â€ðŸ‘¦ðŸ‘¨â€ðŸ‘©â€ðŸ‘¦â€ðŸ‘¦ðŸ‘¨â€ðŸ‘©â€ðŸ‘§â€ðŸ‘§ðŸ‘¨â€ðŸ‘¨â€ðŸ‘¦ðŸ‘¨â€ðŸ‘¨â€ðŸ‘§ðŸ‘¨â€ðŸ‘¨â€ðŸ‘§â€ðŸ‘¦ðŸ‘¨â€ðŸ‘¨â€ðŸ‘¦â€ðŸ‘¦ðŸ‘¨â€ðŸ‘¨â€ðŸ‘§â€ðŸ‘§ðŸ‘©â€ðŸ‘©â€ðŸ‘¦ðŸ‘©â€ðŸ‘©â€ðŸ‘§ðŸ‘©â€ðŸ‘©â€ðŸ‘§â€ðŸ‘¦ðŸ‘©â€ðŸ‘©â€ðŸ‘¦â€ðŸ‘¦ðŸ‘©â€ðŸ‘©â€ðŸ‘§â€ðŸ‘§ðŸ‘¨â€ðŸ‘¦ðŸ‘¨â€ðŸ‘¦â€ðŸ‘¦ðŸ‘¨â€ðŸ‘§ðŸ‘¨â€ðŸ‘§â€ðŸ‘¦ðŸ‘¨â€ðŸ‘§â€ðŸ‘§ðŸ‘©â€ðŸ‘¦ðŸ‘©â€ðŸ‘¦â€ðŸ‘¦ðŸ‘©â€ðŸ‘§ðŸ‘©â€ðŸ‘§â€ðŸ‘¦ðŸ‘©â€ðŸ‘§â€ðŸ‘§ðŸ—£ðŸ‘¤ðŸ‘¥ðŸ«‚👣🦰🦱🦳🦲ðŸµðŸ’ðŸ¦ðŸ¦§ðŸ¶ðŸ•ðŸ¦®ðŸ•â€ðŸ¦ºðŸ©ðŸºðŸ¦ŠðŸ¦ðŸ±ðŸˆðŸˆâ€â¬›ðŸ¦ðŸ¯ðŸ…ðŸ†ðŸ´ðŸŽðŸ¦„🦓🦌🦬ðŸ®ðŸ‚ðŸƒðŸ„ðŸ·ðŸ–ðŸ—ðŸ½ðŸðŸ‘ðŸðŸªðŸ«ðŸ¦™ðŸ¦’ðŸ˜ðŸ¦£ðŸ¦ðŸ¦›ðŸ­ðŸðŸ€ðŸ¹ðŸ°ðŸ‡ðŸ¿ðŸ¦«ðŸ¦”🦇ðŸ»ðŸ»â€â„ï¸ðŸ¨ðŸ¼ðŸ¦¥ðŸ¦¦ðŸ¦¨ðŸ¦˜ðŸ¦¡ðŸ¾ðŸ¦ƒðŸ”ðŸ“ðŸ£ðŸ¤ðŸ¥ðŸ¦ðŸ§ðŸ•ŠðŸ¦…🦆🦢🦉🦤🪶🦩🦚🦜ðŸ¸ðŸŠðŸ¢ðŸ¦ŽðŸðŸ²ðŸ‰ðŸ¦•ðŸ¦–ðŸ³ðŸ‹ðŸ¬ðŸ¦­ðŸŸðŸ ðŸ¡ðŸ¦ˆðŸ™ðŸšðŸŒðŸ¦‹ðŸ›ðŸœðŸðŸª²ðŸžðŸ¦—🪳🕷🕸🦂🦟🪰🪱🦠ðŸ’🌸💮ðŸµðŸŒ¹ðŸ¥€ðŸŒºðŸŒ»ðŸŒ¼ðŸŒ·ðŸŒ±ðŸª´ðŸŒ²ðŸŒ³ðŸŒ´ðŸŒµðŸŒ¾ðŸŒ¿â˜˜ðŸ€ðŸðŸ‚ðŸƒðŸ‡ðŸˆðŸ‰ðŸŠðŸ‹ðŸŒðŸðŸ¥­ðŸŽðŸðŸðŸ‘ðŸ’ðŸ“ðŸ«ðŸ¥ðŸ…🫒🥥🥑ðŸ†ðŸ¥”🥕🌽🌶🫑🥒🥬🥦🧄🧅ðŸ„🥜🌰ðŸžðŸ¥ðŸ¥–🫓🥨🥯🥞🧇🧀ðŸ–ðŸ—🥩🥓ðŸ”ðŸŸðŸ•ðŸŒ­ðŸ¥ªðŸŒ®ðŸŒ¯ðŸ«”🥙🧆🥚ðŸ³ðŸ¥˜ðŸ²ðŸ«•ðŸ¥£ðŸ¥—ðŸ¿ðŸ§ˆðŸ§‚🥫ðŸ±ðŸ˜ðŸ™ðŸšðŸ›ðŸœðŸðŸ ðŸ¢ðŸ£ðŸ¤ðŸ¥ðŸ¥®ðŸ¡ðŸ¥ŸðŸ¥ ðŸ¥¡ðŸ¦€ðŸ¦žðŸ¦ðŸ¦‘🦪ðŸ¦ðŸ§ðŸ¨ðŸ©ðŸªðŸŽ‚ðŸ°ðŸ§ðŸ¥§ðŸ«ðŸ¬ðŸ­ðŸ®ðŸ¯ðŸ¼ðŸ¥›â˜•ðŸ«–ðŸµðŸ¶ðŸ¾ðŸ·ðŸ¸ðŸ¹ðŸºðŸ»ðŸ¥‚🥃🥤🧋🧃🧉🧊🥢ðŸ½ðŸ´ðŸ¥„🔪ðŸºðŸŒðŸŒŽðŸŒðŸŒðŸ—ºðŸ—¾ðŸ§­ðŸ”⛰🌋🗻ðŸ•ðŸ–ðŸœðŸðŸžðŸŸðŸ›ðŸ—🧱🪨🪵🛖ðŸ˜ðŸšðŸ ðŸ¡ðŸ¢ðŸ£ðŸ¤ðŸ¥ðŸ¦ðŸ¨ðŸ©ðŸªðŸ«ðŸ¬ðŸ­ðŸ¯ðŸ°ðŸ’’🗼🗽⛪🕌🛕ðŸ•â›©ðŸ•‹â›²â›ºðŸŒðŸŒƒðŸ™ðŸŒ„🌅🌆🌇🌉♨🎠🎡🎢💈🎪🚂🚃🚄🚅🚆🚇🚈🚉🚊ðŸšðŸšžðŸš‹ðŸšŒðŸšðŸšŽðŸšðŸš‘🚒🚓🚔🚕🚖🚗🚘🚙🛻🚚🚛🚜ðŸŽðŸðŸ›µðŸ¦½ðŸ¦¼ðŸ›ºðŸš²ðŸ›´ðŸ›¹ðŸ›¼ðŸšðŸ›£ðŸ›¤ðŸ›¢â›½ðŸš¨ðŸš¥ðŸš¦ðŸ›‘🚧⚓⛵🛶🚤🛳⛴🛥🚢✈🛩🛫🛬🪂💺ðŸšðŸšŸðŸš ðŸš¡ðŸ›°ðŸš€ðŸ›¸ðŸ›ŽðŸ§³âŒ›â³âŒšâ°â±â²ðŸ•°ðŸ•›ðŸ•§ðŸ•ðŸ•œðŸ•‘ðŸ•ðŸ•’🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌡☀ðŸŒðŸŒžðŸªâ­ðŸŒŸðŸŒ ðŸŒŒâ˜â›…⛈🌤🌥🌦🌧🌨🌩🌪🌫🌬🌀🌈🌂☂☔⛱⚡â„☃⛄☄🔥💧🌊🎃🎄🎆🎇🧨✨🎈🎉🎊🎋ðŸŽðŸŽŽðŸŽðŸŽðŸŽ‘🧧🎀ðŸŽðŸŽ—🎟🎫🎖ðŸ†ðŸ…🥇🥈🥉⚽⚾🥎ðŸ€ðŸðŸˆðŸ‰ðŸŽ¾ðŸ¥ðŸŽ³ðŸðŸ‘ðŸ’ðŸ¥ðŸ“ðŸ¸ðŸ¥ŠðŸ¥‹ðŸ¥…⛳⛸🎣🤿🎽🎿🛷🥌🎯🪀ðŸªðŸŽ±ðŸ”®ðŸª„🧿🎮🕹🎰🎲🧩🧸🪅🪆♠♥♦♣♟ðŸƒðŸ€„🎴🎭🖼🎨🧵🪡🧶🪢👓🕶🥽🥼🦺👔👕👖🧣🧤🧥🧦👗👘🥻🩱🩲🩳👙👚👛👜ðŸ‘ðŸ›ðŸŽ’🩴👞👟🥾🥿👠👡🩰👢👑👒🎩🎓🧢🪖⛑📿💄ðŸ’💎🔇🔈🔉🔊📢📣📯🔔🔕🎼🎵🎶🎙🎚🎛🎤🎧📻🎷🪗🎸🎹🎺🎻🪕ðŸ¥"; + +#[bench] +fn str_char_count_lorem(b: &mut Bencher) { + b.iter(|| black_box(LOREM).chars().count()); +} + +#[bench] +fn str_char_count_lorem_short(b: &mut Bencher) { + b.iter(|| black_box(LOREM_SHORT).chars().count()); +} + +#[bench] +fn str_char_count_emoji(b: &mut Bencher) { + b.iter(|| black_box(EMOJI).chars().count()); +} + +#[bench] +fn str_validate_emoji(b: &mut Bencher) { + b.iter(|| str::from_utf8(black_box(EMOJI.as_bytes()))); +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/box_into_raw.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/box_into_raw.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/box_into_raw.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/box_into_raw.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/boxed/struct.Box.html#method.into_raw diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/fs_file.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/fs_file.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/fs_file.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/fs_file.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/fs/struct.File.html diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/io_bufread.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/io_bufread.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/io_bufread.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/io_bufread.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/io/trait.BufRead.html diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/io_read.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/io_read.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/io_read.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/io_read.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/io/trait.Read.html diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/io_seek.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/io_seek.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/io_seek.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/io_seek.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/io/trait.Seek.html diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/io_write.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/io_write.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/io_write.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/io_write.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/io/trait.Write.html diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/net_tosocketaddrs.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/net_tosocketaddrs.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/net_tosocketaddrs.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/net_tosocketaddrs.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/net/trait.ToSocketAddrs.html diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/process_exit.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/process_exit.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/process_exit.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/process_exit.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/process/fn.exit.html diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/string_string.md rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/string_string.md --- rustc-1.56.0+dfsg1+llvm/library/core/primitive_docs/string_string.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/primitive_docs/string_string.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +../std/string/struct.String.html diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/alloc/layout.rs rustc-1.57.0+dfsg1+llvm/library/core/src/alloc/layout.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/alloc/layout.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/alloc/layout.rs 2021-11-29 19:27:11.000000000 +0000 @@ -94,6 +94,7 @@ /// [`Layout::from_size_align`]. #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "alloc_layout", since = "1.36.0")] + #[must_use] #[inline] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { // SAFETY: the caller must ensure that `align` is greater than zero. @@ -111,6 +112,8 @@ /// The minimum byte alignment for a memory block of this layout. #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")] + #[must_use = "this returns the minimum alignment, \ + without modifying the layout"] #[inline] pub const fn align(&self) -> usize { self.align_.get() @@ -119,6 +122,7 @@ /// Constructs a `Layout` suitable for holding a value of type `T`. #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")] + #[must_use] #[inline] pub const fn new() -> Self { let (size, align) = size_align::(); @@ -227,6 +231,8 @@ /// satisfy this constraint is to ensure `align <= self.align()`. #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] + #[must_use = "this returns the padding needed, \ + without modifying the `Layout`"] #[inline] pub const fn padding_needed_for(&self, align: usize) -> usize { let len = self.size(); @@ -260,6 +266,8 @@ /// This is equivalent to adding the result of `padding_needed_for` /// to the layout's current size. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] + #[must_use = "this returns a new `Layout`, \ + without modifying the original"] #[inline] pub fn pad_to_align(&self) -> Layout { let pad = self.padding_needed_for(self.align()); diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/array/iter.rs rustc-1.57.0+dfsg1+llvm/library/core/src/array/iter.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/array/iter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/array/iter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ /// A by-value [array] iterator. #[stable(feature = "array_value_iter", since = "1.51.0")] -#[cfg_attr(not(bootstrap), rustc_insignificant_dtor)] +#[rustc_insignificant_dtor] pub struct IntoIter { /// This is the array we are iterating over. /// @@ -135,19 +135,12 @@ Fold: FnMut(Acc, Self::Item) -> Acc, { let data = &mut self.data; - // FIXME: This uses try_fold(&mut iter) instead of fold(iter) because the latter - // would go through the blanket `impl Iterator for &mut I` implementation - // which lacks inline annotations on its methods and adding those would be a larger - // perturbation than using try_fold here. - // Whether it would be beneficial to add those annotations should be investigated separately. - (&mut self.alive) - .try_fold::<_, _, Result<_, !>>(init, |acc, idx| { - // SAFETY: idx is obtained by folding over the `alive` range, which implies the - // value is currently considered alive but as the range is being consumed each value - // we read here will only be read once and then considered dead. - Ok(fold(acc, unsafe { data.get_unchecked(idx).assume_init_read() })) - }) - .unwrap() + self.alive.by_ref().fold(init, |acc, idx| { + // SAFETY: idx is obtained by folding over the `alive` range, which implies the + // value is currently considered alive but as the range is being consumed each value + // we read here will only be read once and then considered dead. + fold(acc, unsafe { data.get_unchecked(idx).assume_init_read() }) + }) } fn count(self) -> usize { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/array/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/array/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/array/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/array/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -20,6 +20,69 @@ #[stable(feature = "array_value_iter", since = "1.51.0")] pub use iter::IntoIter; +/// Creates an array `[T; N]` where each array element `T` is returned by the `cb` call. +/// +/// # Arguments +/// +/// * `cb`: Callback where the passed argument is the current array index. +/// +/// # Example +/// +/// ```rust +/// #![feature(array_from_fn)] +/// +/// let array = core::array::from_fn(|i| i); +/// assert_eq!(array, [0, 1, 2, 3, 4]); +/// ``` +#[inline] +#[unstable(feature = "array_from_fn", issue = "89379")] +pub fn from_fn(mut cb: F) -> [T; N] +where + F: FnMut(usize) -> T, +{ + let mut idx = 0; + [(); N].map(|_| { + let res = cb(idx); + idx += 1; + res + }) +} + +/// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call. +/// Unlike `core::array::from_fn`, where the element creation can't fail, this version will return an error +/// if any element creation was unsuccessful. +/// +/// # Arguments +/// +/// * `cb`: Callback where the passed argument is the current array index. +/// +/// # Example +/// +/// ```rust +/// #![feature(array_from_fn)] +/// +/// #[derive(Debug, PartialEq)] +/// enum SomeError { +/// Foo, +/// } +/// +/// let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i)); +/// assert_eq!(array, Ok([0, 1, 2, 3, 4])); +/// +/// let another_array = core::array::try_from_fn::(|_| Err(SomeError::Foo)); +/// assert_eq!(another_array, Err(SomeError::Foo)); +/// ``` +#[inline] +#[unstable(feature = "array_from_fn", issue = "89379")] +pub fn try_from_fn(cb: F) -> Result<[T; N], E> +where + F: FnMut(usize) -> Result, +{ + // SAFETY: we know for certain that this iterator will yield exactly `N` + // items. + unsafe { collect_into_array_rslt_unchecked(&mut (0..N).map(cb)) } +} + /// Converts a reference to `T` into a reference to an array of length 1 (without copying). #[stable(feature = "array_from_ref", since = "1.53.0")] pub fn from_ref(s: &T) -> &[T; 1] { @@ -368,14 +431,14 @@ } /// Returns a slice containing the entire array. Equivalent to `&s[..]`. - #[unstable(feature = "array_methods", issue = "76118")] - pub fn as_slice(&self) -> &[T] { + #[stable(feature = "array_as_slice", since = "1.57.0")] + pub const fn as_slice(&self) -> &[T] { self } /// Returns a mutable slice containing the entire array. Equivalent to /// `&mut s[..]`. - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_as_slice", since = "1.57.0")] pub fn as_mut_slice(&mut self) -> &mut [T] { self } @@ -396,7 +459,7 @@ /// /// This method is particularly useful if combined with other methods, like /// [`map`](#method.map). This way, you can avoid moving the original - /// array if its elements are not `Copy`. + /// array if its elements are not [`Copy`]. /// /// ``` /// #![feature(array_methods)] @@ -448,13 +511,15 @@ /// /// It is up to the caller to guarantee that `iter` yields at least `N` items. /// Violating this condition causes undefined behavior. -unsafe fn collect_into_array_unchecked(iter: &mut I) -> [I::Item; N] +unsafe fn collect_into_array_rslt_unchecked( + iter: &mut I, +) -> Result<[T; N], E> where // Note: `TrustedLen` here is somewhat of an experiment. This is just an // internal function, so feel free to remove if this bound turns out to be a // bad idea. In that case, remember to also remove the lower bound // `debug_assert!` below! - I: Iterator + TrustedLen, + I: Iterator> + TrustedLen, { debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX)); debug_assert!(N <= iter.size_hint().0); @@ -463,6 +528,21 @@ unsafe { collect_into_array(iter).unwrap_unchecked() } } +// Infallible version of `collect_into_array_rslt_unchecked`. +unsafe fn collect_into_array_unchecked(iter: &mut I) -> [I::Item; N] +where + I: Iterator + TrustedLen, +{ + let mut map = iter.map(Ok::<_, Infallible>); + + // SAFETY: The same safety considerations w.r.t. the iterator length + // apply for `collect_into_array_rslt_unchecked` as for + // `collect_into_array_unchecked` + match unsafe { collect_into_array_rslt_unchecked(&mut map) } { + Ok(array) => array, + } +} + /// Pulls `N` items from `iter` and returns them as an array. If the iterator /// yields fewer than `N` items, `None` is returned and all already yielded /// items are dropped. @@ -473,43 +553,49 @@ /// /// If `iter.next()` panicks, all items already yielded by the iterator are /// dropped. -fn collect_into_array(iter: &mut I) -> Option<[I::Item; N]> +fn collect_into_array(iter: &mut I) -> Option> where - I: Iterator, + I: Iterator>, { if N == 0 { // SAFETY: An empty array is always inhabited and has no validity invariants. - return unsafe { Some(mem::zeroed()) }; + return unsafe { Some(Ok(mem::zeroed())) }; } - struct Guard { - ptr: *mut T, + struct Guard<'a, T, const N: usize> { + array_mut: &'a mut [MaybeUninit; N], initialized: usize, } - impl Drop for Guard { + impl Drop for Guard<'_, T, N> { fn drop(&mut self) { debug_assert!(self.initialized <= N); - let initialized_part = crate::ptr::slice_from_raw_parts_mut(self.ptr, self.initialized); - - // SAFETY: this raw slice will contain only initialized objects. + // SAFETY: this slice will contain only initialized objects. unsafe { - crate::ptr::drop_in_place(initialized_part); + crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( + &mut self.array_mut.get_unchecked_mut(..self.initialized), + )); } } } let mut array = MaybeUninit::uninit_array::(); - let mut guard: Guard<_, N> = - Guard { ptr: MaybeUninit::slice_as_mut_ptr(&mut array), initialized: 0 }; + let mut guard = Guard { array_mut: &mut array, initialized: 0 }; + + while let Some(item_rslt) = iter.next() { + let item = match item_rslt { + Err(err) => { + return Some(Err(err)); + } + Ok(elem) => elem, + }; - while let Some(item) = iter.next() { // SAFETY: `guard.initialized` starts at 0, is increased by one in the // loop and the loop is aborted once it reaches N (which is // `array.len()`). unsafe { - array.get_unchecked_mut(guard.initialized).write(item); + guard.array_mut.get_unchecked_mut(guard.initialized).write(item); } guard.initialized += 1; @@ -520,7 +606,7 @@ // SAFETY: the condition above asserts that all elements are // initialized. let out = unsafe { MaybeUninit::array_assume_init(array) }; - return Some(out); + return Some(Ok(out)); } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/ascii.rs rustc-1.57.0+dfsg1+llvm/library/core/src/ascii.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/ascii.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/ascii.rs 2021-11-29 19:27:11.000000000 +0000 @@ -21,7 +21,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct EscapeDefault { - range: Range, + range: Range, data: [u8; 4], } @@ -114,7 +114,7 @@ impl Iterator for EscapeDefault { type Item = u8; fn next(&mut self) -> Option { - self.range.next().map(|i| self.data[i]) + self.range.next().map(|i| self.data[i as usize]) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() @@ -126,7 +126,7 @@ #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for EscapeDefault { fn next_back(&mut self) -> Option { - self.range.next_back().map(|i| self.data[i]) + self.range.next_back().map(|i| self.data[i as usize]) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -138,7 +138,9 @@ impl fmt::Display for EscapeDefault { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // SAFETY: ok because `escape_default` created only valid utf-8 data - f.write_str(unsafe { from_utf8_unchecked(&self.data[self.range.clone()]) }) + f.write_str(unsafe { + from_utf8_unchecked(&self.data[(self.range.start as usize)..(self.range.end as usize)]) + }) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/bool.rs rustc-1.57.0+dfsg1+llvm/library/core/src/bool.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/bool.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/bool.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2,7 +2,8 @@ #[lang = "bool"] impl bool { - /// Returns `Some(t)` if the `bool` is `true`, or `None` otherwise. + /// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html), + /// or `None` otherwise. /// /// # Examples /// @@ -18,7 +19,8 @@ if self { Some(t) } else { None } } - /// Returns `Some(f())` if the `bool` is `true`, or `None` otherwise. + /// Returns `Some(f())` if the `bool` is [`true`](../std/keyword.true.html), + /// or `None` otherwise. /// /// # Examples /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/cell.rs rustc-1.57.0+dfsg1+llvm/library/core/src/cell.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/cell.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/cell.rs 2021-11-29 19:27:11.000000000 +0000 @@ -349,7 +349,7 @@ drop(old); } - /// Swaps the values of two Cells. + /// Swaps the values of two `Cell`s. /// Difference with `std::mem::swap` is that this function doesn't require `&mut` reference. /// /// # Examples @@ -1303,6 +1303,11 @@ /// /// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a Ref across suspend \ + points can cause BorrowErrors" +)] pub struct Ref<'b, T: ?Sized + 'b> { value: &'b T, borrow: BorrowRef<'b>, @@ -1679,6 +1684,11 @@ /// /// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a RefMut across suspend \ + points can cause BorrowErrors" +)] pub struct RefMut<'b, T: ?Sized + 'b> { value: &'b mut T, borrow: BorrowRefMut<'b>, @@ -1916,7 +1926,8 @@ /// ``` #[inline(always)] #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_unsafecell_get_mut", issue = "88836")] + pub const fn get_mut(&mut self) -> &mut T { &mut self.value } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/char/convert.rs rustc-1.57.0+dfsg1+llvm/library/core/src/char/convert.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/char/convert.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/char/convert.rs 2021-11-29 19:27:11.000000000 +0000 @@ -48,6 +48,7 @@ /// assert_eq!(None, c); /// ``` #[doc(alias = "chr")] +#[must_use] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_u32(i: u32) -> Option { @@ -88,6 +89,7 @@ /// assert_eq!('â¤', c); /// ``` #[inline] +#[must_use] #[stable(feature = "char_from_unchecked", since = "1.5.0")] pub unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the caller must guarantee that `i` is a valid char value. @@ -319,6 +321,7 @@ /// let c = char::from_digit(1, 37); /// ``` #[inline] +#[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_digit(num: u32, radix: u32) -> Option { if radix > 36 { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/char/methods.rs rustc-1.57.0+dfsg1+llvm/library/core/src/char/methods.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/char/methods.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/char/methods.rs 2021-11-29 19:27:11.000000000 +0000 @@ -24,7 +24,7 @@ /// decoding error. /// /// It can occur, for example, when giving ill-formed UTF-8 bytes to - /// [`String::from_utf8_lossy`](string/struct.String.html#method.from_utf8_lossy). + /// [`String::from_utf8_lossy`](../std/string/struct.String.html#method.from_utf8_lossy). #[stable(feature = "assoc_char_consts", since = "1.52.0")] pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; @@ -96,7 +96,7 @@ /// Converts a `u32` to a `char`. /// /// Note that all `char`s are valid [`u32`]s, and can be cast to one with - /// `as`: + /// [`as`](../std/keyword.as.html): /// /// ``` /// let c = '💯'; @@ -136,6 +136,7 @@ /// assert_eq!(None, c); /// ``` #[stable(feature = "assoc_char_funcs", since = "1.52.0")] + #[must_use] #[inline] pub fn from_u32(i: u32) -> Option { super::convert::from_u32(i) @@ -177,6 +178,7 @@ /// assert_eq!('â¤', c); /// ``` #[stable(feature = "assoc_char_funcs", since = "1.52.0")] + #[must_use] #[inline] pub unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the safety contract must be upheld by the caller. @@ -230,9 +232,10 @@ /// use std::char; /// /// // this panics - /// char::from_digit(1, 37); + /// let _c = char::from_digit(1, 37); /// ``` #[stable(feature = "assoc_char_funcs", since = "1.52.0")] + #[must_use] #[inline] pub fn from_digit(num: u32, radix: u32) -> Option { super::convert::from_digit(num, radix) @@ -325,9 +328,11 @@ /// /// ```should_panic /// // this panics - /// '1'.to_digit(37); + /// let _ = '1'.to_digit(37); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn to_digit(self, radix: u32) -> Option { assert!(radix <= 36, "to_digit: radix is too high (maximum 36)"); @@ -372,11 +377,13 @@ /// println!("\\u{{2764}}"); /// ``` /// - /// Using `to_string`: + /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): /// /// ``` /// assert_eq!('â¤'.escape_unicode().to_string(), "\\u{2764}"); /// ``` + #[must_use = "this returns the escaped char as an iterator, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn escape_unicode(self) -> EscapeUnicode { @@ -422,7 +429,7 @@ /// Returns an iterator that yields the literal escape code of a character /// as `char`s. /// - /// This will escape the characters similar to the `Debug` implementations + /// This will escape the characters similar to the [`Debug`](core::fmt::Debug) implementations /// of `str` or `char`. /// /// # Examples @@ -448,11 +455,13 @@ /// println!("\\n"); /// ``` /// - /// Using `to_string`: + /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): /// /// ``` /// assert_eq!('\n'.escape_debug().to_string(), "\\n"); /// ``` + #[must_use = "this returns the escaped char as an iterator, \ + without modifying the original"] #[stable(feature = "char_escape_debug", since = "1.20.0")] #[inline] pub fn escape_debug(self) -> EscapeDebug { @@ -502,11 +511,13 @@ /// println!("\\\""); /// ``` /// - /// Using `to_string`: + /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): /// /// ``` /// assert_eq!('"'.escape_default().to_string(), "\\\""); /// ``` + #[must_use = "this returns the escaped char as an iterator, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn escape_default(self) -> EscapeDefault { @@ -692,6 +703,7 @@ /// // love is many things, but it is not alphabetic /// assert!(!c.is_alphabetic()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_alphabetic(self) -> bool { @@ -724,6 +736,7 @@ /// assert!(!'中'.is_lowercase()); /// assert!(!' '.is_lowercase()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_lowercase(self) -> bool { @@ -756,6 +769,7 @@ /// assert!(!'中'.is_uppercase()); /// assert!(!' '.is_uppercase()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_uppercase(self) -> bool { @@ -784,6 +798,7 @@ /// /// assert!(!'越'.is_whitespace()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_whitespace(self) -> bool { @@ -812,6 +827,7 @@ /// assert!('Ùˆ'.is_alphanumeric()); /// assert!('è—'.is_alphanumeric()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_alphanumeric(self) -> bool { @@ -837,6 +853,7 @@ /// assert!('Âœ'.is_control()); /// assert!(!'q'.is_control()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_control(self) -> bool { @@ -852,6 +869,7 @@ /// [uax29]: https://www.unicode.org/reports/tr29/ /// [ucd]: https://www.unicode.org/reports/tr44/ /// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt + #[must_use] #[inline] pub(crate) fn is_grapheme_extended(self) -> bool { unicode::Grapheme_Extend(self) @@ -881,6 +899,7 @@ /// assert!(!'Ùˆ'.is_numeric()); /// assert!(!'è—'.is_numeric()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_numeric(self) -> bool { @@ -937,7 +956,7 @@ /// println!("i\u{307}"); /// ``` /// - /// Using `to_string`: + /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): /// /// ``` /// assert_eq!('C'.to_lowercase().to_string(), "c"); @@ -949,6 +968,8 @@ /// // convert into themselves. /// assert_eq!('å±±'.to_lowercase().to_string(), "å±±"); /// ``` + #[must_use = "this returns the lowercase character as a new iterator, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_lowercase(self) -> ToLowercase { @@ -1002,7 +1023,7 @@ /// println!("SS"); /// ``` /// - /// Using `to_string`: + /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): /// /// ``` /// assert_eq!('c'.to_uppercase().to_string(), "C"); @@ -1039,6 +1060,8 @@ /// ``` /// /// holds across languages. + #[must_use = "this returns the uppercase character as a new iterator, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_uppercase(self) -> ToUppercase { @@ -1056,6 +1079,7 @@ /// assert!(ascii.is_ascii()); /// assert!(!non_ascii.is_ascii()); /// ``` + #[must_use] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.32.0")] #[inline] @@ -1085,6 +1109,7 @@ /// /// [`make_ascii_uppercase()`]: #method.make_ascii_uppercase /// [`to_uppercase()`]: #method.to_uppercase + #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase()`"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] @@ -1118,6 +1143,7 @@ /// /// [`make_ascii_lowercase()`]: #method.make_ascii_lowercase /// [`to_lowercase()`]: #method.to_lowercase + #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase()`"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] @@ -1131,7 +1157,7 @@ /// Checks that two values are an ASCII case-insensitive match. /// - /// Equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`. + /// Equivalent to [to_ascii_lowercase]\(a) == [to_ascii_lowercase]\(b). /// /// # Examples /// @@ -1144,6 +1170,8 @@ /// assert!(upper_a.eq_ignore_ascii_case(&upper_a)); /// assert!(!upper_a.eq_ignore_ascii_case(&lower_z)); /// ``` + /// + /// [to_ascii_lowercase]: #method.to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] @@ -1229,6 +1257,7 @@ /// assert!(!lf.is_ascii_alphabetic()); /// assert!(!esc.is_ascii_alphabetic()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1262,6 +1291,7 @@ /// assert!(!lf.is_ascii_uppercase()); /// assert!(!esc.is_ascii_uppercase()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1295,6 +1325,7 @@ /// assert!(!lf.is_ascii_lowercase()); /// assert!(!esc.is_ascii_lowercase()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1331,6 +1362,7 @@ /// assert!(!lf.is_ascii_alphanumeric()); /// assert!(!esc.is_ascii_alphanumeric()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1364,6 +1396,7 @@ /// assert!(!lf.is_ascii_digit()); /// assert!(!esc.is_ascii_digit()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1400,6 +1433,7 @@ /// assert!(!lf.is_ascii_hexdigit()); /// assert!(!esc.is_ascii_hexdigit()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1437,6 +1471,7 @@ /// assert!(!lf.is_ascii_punctuation()); /// assert!(!esc.is_ascii_punctuation()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1470,6 +1505,7 @@ /// assert!(!lf.is_ascii_graphic()); /// assert!(!esc.is_ascii_graphic()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1520,6 +1556,7 @@ /// assert!(lf.is_ascii_whitespace()); /// assert!(!esc.is_ascii_whitespace()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -1555,6 +1592,7 @@ /// assert!(lf.is_ascii_control()); /// assert!(esc.is_ascii_control()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/clone.rs rustc-1.57.0+dfsg1+llvm/library/core/src/clone.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/clone.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/clone.rs 2021-11-29 19:27:11.000000000 +0000 @@ -105,6 +105,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] #[rustc_diagnostic_item = "Clone"] +#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)] pub trait Clone: Sized { /// Returns a copy of the value. /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/cmp.rs rustc-1.57.0+dfsg1+llvm/library/core/src/cmp.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/cmp.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/cmp.rs 2021-11-29 19:27:11.000000000 +0000 @@ -203,6 +203,7 @@ message = "can't compare `{Self}` with `{Rhs}`", label = "no implementation for `{Self} == {Rhs}`" )] +#[rustc_diagnostic_item = "PartialEq"] pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used /// by `==`. @@ -269,6 +270,7 @@ #[doc(alias = "==")] #[doc(alias = "!=")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Eq"] pub trait Eq: PartialEq { // this method is used solely by #[deriving] to assert // that every component of a type implements #[deriving] @@ -321,6 +323,7 @@ /// ``` #[derive(Clone, Copy, PartialEq, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(i8)] pub enum Ordering { /// An ordering where a compared value is less than another. #[stable(feature = "rust1", since = "1.0.0")] @@ -728,6 +731,7 @@ #[doc(alias = "<=")] #[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Ord"] pub trait Ord: Eq + PartialOrd { /// This method returns an [`Ordering`] between `self` and `other`. /// @@ -984,6 +988,7 @@ message = "can't compare `{Self}` with `{Rhs}`", label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" )] +#[rustc_diagnostic_item = "PartialOrd"] pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/convert/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/convert/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/convert/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/convert/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -269,10 +269,11 @@ /// /// [`String`]: ../../std/string/struct.String.html /// [`Vec`]: ../../std/vec/struct.Vec.html -#[rustc_diagnostic_item = "into_trait"] +#[rustc_diagnostic_item = "Into"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { /// Performs the conversion. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn into(self) -> T; } @@ -358,7 +359,7 @@ /// [`String`]: ../../std/string/struct.String.html /// [`from`]: From::from /// [book]: ../../book/ch09-00-error-handling.html -#[rustc_diagnostic_item = "from_trait"] +#[rustc_diagnostic_item = "From"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( all(_Self = "&str", T = "std::string::String"), @@ -367,6 +368,7 @@ pub trait From: Sized { /// Performs the conversion. #[lang = "from"] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn from(_: T) -> Self; } @@ -385,7 +387,7 @@ /// /// This suffers the same restrictions and reasoning as implementing /// [`Into`], see there for details. -#[rustc_diagnostic_item = "try_into_trait"] +#[rustc_diagnostic_item = "TryInto"] #[stable(feature = "try_from", since = "1.34.0")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. @@ -465,7 +467,7 @@ /// ``` /// /// [`try_from`]: TryFrom::try_from -#[rustc_diagnostic_item = "try_from_trait"] +#[rustc_diagnostic_item = "TryFrom"] #[stable(feature = "try_from", since = "1.34.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. @@ -662,7 +664,7 @@ /// /// However there is one case where `!` syntax can be used /// before `!` is stabilized as a full-fledged type: in the position of a function’s return type. -/// Specifically, it is possible implementations for two different function pointer types: +/// Specifically, it is possible to have implementations for two different function pointer types: /// /// ``` /// trait MyTrait {} diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/fmt/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/fmt/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/fmt/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/fmt/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -265,6 +265,27 @@ formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, } +/// This struct represents the unsafety of constructing an `Arguments`. +/// It exists, rather than an unsafe function, in order to simplify the expansion +/// of `format_args!(..)` and reduce the scope of the `unsafe` block. +#[allow(missing_debug_implementations)] +#[doc(hidden)] +#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] +pub struct UnsafeArg { + _private: (), +} + +impl UnsafeArg { + /// See documentation where `UnsafeArg` is required to know when it is safe to + /// create and use `UnsafeArg`. + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[inline(always)] + pub unsafe fn new() -> Self { + Self { _private: () } + } +} + // This guarantees a single stable value for the function pointer associated with // indices/counts in the formatting infrastructure. // @@ -333,21 +354,6 @@ impl<'a> Arguments<'a> { /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. - #[cfg(not(bootstrap))] - #[doc(hidden)] - #[inline] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const unsafe fn new_v1( - pieces: &'a [&'static str], - args: &'a [ArgumentV1<'a>], - ) -> Arguments<'a> { - if pieces.len() < args.len() || pieces.len() > args.len() + 1 { - panic!("invalid args"); - } - Arguments { pieces, fmt: None, args } - } - #[cfg(bootstrap)] #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -360,29 +366,34 @@ } /// This function is used to specify nonstandard formatting parameters. - /// The `pieces` array must be at least as long as `fmt` to construct - /// a valid Arguments structure. Also, any `Count` within `fmt` that is - /// `CountIsParam` or `CountIsNextParam` has to point to an argument - /// created with `argumentusize`. However, failing to do so doesn't cause - /// unsafety, but will ignore invalid . + /// + /// An `UnsafeArg` is required because the following invariants must be held + /// in order for this function to be safe: + /// 1. The `pieces` slice must be at least as long as `fmt`. + /// 2. Every [`rt::v1::Argument::position`] value within `fmt` must be a + /// valid index of `args`. + /// 3. Every [`Count::Param`] within `fmt` must contain a valid index of + /// `args`. #[cfg(not(bootstrap))] #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const unsafe fn new_v1_formatted( + pub const fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument], + _unsafe_arg: UnsafeArg, ) -> Arguments<'a> { Arguments { pieces, fmt: Some(fmt), args } } + #[cfg(bootstrap)] #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const fn new_v1_formatted( + pub const unsafe fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument], @@ -480,6 +491,7 @@ /// ``` #[stable(feature = "fmt_as_str", since = "1.52.0")] #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "none")] + #[must_use] #[inline] pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { @@ -606,7 +618,8 @@ label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`" )] #[doc(alias = "{:?}")] -#[rustc_diagnostic_item = "debug_trait"] +#[rustc_diagnostic_item = "Debug"] +#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)] pub trait Debug { /// Formats the value using the given formatter. /// @@ -698,7 +711,7 @@ note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead" )] #[doc(alias = "{}")] -#[rustc_diagnostic_item = "display_trait"] +#[rustc_diagnostic_item = "Display"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Display { /// Formats the value using the given formatter. @@ -991,7 +1004,7 @@ /// assert_eq!(&l_ptr[..2], "0x"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "pointer_trait"] +#[rustc_diagnostic_item = "Pointer"] pub trait Pointer { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] @@ -1213,7 +1226,7 @@ /// Padding after the end of something. Returned by `Formatter::padding`. #[must_use = "don't forget to write the post padding"] -struct PostPadding { +pub(crate) struct PostPadding { fill: char, padding: usize, } @@ -1224,9 +1237,9 @@ } /// Write this post padding. - fn write(self, buf: &mut dyn Write) -> Result { + pub(crate) fn write(self, f: &mut Formatter<'_>) -> Result { for _ in 0..self.padding { - buf.write_char(self.fill)?; + f.buf.write_char(self.fill)?; } Ok(()) } @@ -1349,7 +1362,7 @@ write_prefix(self, sign, prefix)?; let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; self.buf.write_str(buf)?; - post_padding.write(self.buf)?; + post_padding.write(self)?; self.fill = old_fill; self.align = old_align; Ok(()) @@ -1359,7 +1372,7 @@ let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; write_prefix(self, sign, prefix)?; self.buf.write_str(buf)?; - post_padding.write(self.buf) + post_padding.write(self) } } } @@ -1434,7 +1447,7 @@ let align = rt::v1::Alignment::Left; let post_padding = self.padding(width - chars_count, align)?; self.buf.write_str(s)?; - post_padding.write(self.buf) + post_padding.write(self) } } } @@ -1443,7 +1456,7 @@ /// Write the pre-padding and return the unwritten post-padding. Callers are /// responsible for ensuring post-padding is written after the thing that is /// being padded. - fn padding( + pub(crate) fn padding( &mut self, padding: usize, default: rt::v1::Alignment, @@ -1498,7 +1511,7 @@ } else { let post_padding = self.padding(width - len, align)?; self.write_formatted_parts(&formatted)?; - post_padding.write(self.buf) + post_padding.write(self) }; self.fill = old_fill; self.align = old_align; diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/fmt/num.rs rustc-1.57.0+dfsg1+llvm/library/core/src/fmt/num.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/fmt/num.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/fmt/num.rs 2021-11-29 19:27:11.000000000 +0000 @@ -305,7 +305,6 @@ n /= 10; exponent += 1; } - let trailing_zeros = exponent; let (added_precision, subtracted_precision) = match f.precision() { Some(fmt_prec) => { @@ -333,7 +332,7 @@ n += 1; } } - (n, exponent, trailing_zeros, added_precision) + (n, exponent, exponent, added_precision) }; // 39 digits (worst case u128) + . = 40 diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/hash/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/hash/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/hash/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/hash/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -153,10 +153,23 @@ /// Thankfully, you won't need to worry about upholding this property when /// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`. /// +/// ## Prefix collisions +/// +/// Implementations of `hash` should ensure that the data they +/// pass to the `Hasher` are prefix-free. That is, +/// unequal values should cause two different sequences of values to be written, +/// and neither of the two sequences should be a prefix of the other. +/// +/// For example, the standard implementation of [`Hash` for `&str`][impl] passes an extra +/// `0xFF` byte to the `Hasher` so that the values `("ab", "c")` and `("a", +/// "bc")` hash differently. +/// /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html /// [`hash`]: Hash::hash +/// [impl]: ../../std/primitive.str.html#impl-Hash #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Hash"] pub trait Hash { /// Feeds this value into the given [`Hasher`]. /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/hash/sip.rs rustc-1.57.0+dfsg1+llvm/library/core/src/hash/sip.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/hash/sip.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/hash/sip.rs 2021-11-29 19:27:11.000000000 +0000 @@ -157,6 +157,7 @@ since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead" )] + #[must_use] pub fn new() -> SipHasher { SipHasher::new_with_keys(0, 0) } @@ -168,6 +169,7 @@ since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead" )] + #[must_use] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { SipHasher(SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) }) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/hint.rs rustc-1.57.0+dfsg1+llvm/library/core/src/hint.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/hint.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/hint.rs 2021-11-29 19:27:11.000000000 +0000 @@ -44,7 +44,7 @@ /// ``` #[inline] #[stable(feature = "unreachable", since = "1.27.0")] -#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] +#[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] pub const unsafe fn unreachable_unchecked() -> ! { // SAFETY: the safety contract for `intrinsics::unreachable` must // be upheld by the caller. @@ -154,18 +154,6 @@ /// [`std::convert::identity`]: crate::convert::identity #[inline] #[unstable(feature = "bench_black_box", issue = "64102")] -#[cfg_attr(not(bootstrap), allow(unused_mut))] -#[cfg_attr(bootstrap, allow(deprecated))] -pub fn black_box(mut dummy: T) -> T { - #[cfg(bootstrap)] - // SAFETY: the inline assembly is a no-op. - unsafe { - llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); - dummy - } - - #[cfg(not(bootstrap))] - { - crate::intrinsics::black_box(dummy) - } +pub fn black_box(dummy: T) -> T { + crate::intrinsics::black_box(dummy) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/intrinsics.rs rustc-1.57.0+dfsg1+llvm/library/core/src/intrinsics.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/intrinsics.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/intrinsics.rs 2021-11-29 19:27:11.000000000 +0000 @@ -735,7 +735,7 @@ /// reach code marked with this function. /// /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. - #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] + #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] pub fn unreachable() -> !; /// Informs the optimizer that a condition is always true. @@ -1937,7 +1937,6 @@ /// See documentation of [`std::hint::black_box`] for details. /// /// [`std::hint::black_box`]: crate::hint::black_box - #[cfg(not(bootstrap))] pub fn black_box(dummy: T) -> T; } @@ -2222,3 +2221,74 @@ // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. unsafe { write_bytes(dst, val, count) } } + +/// Selects which function to call depending on the context. +/// +/// If this function is evaluated at compile-time, then a call to this +/// intrinsic will be replaced with a call to `called_in_const`. It gets +/// replaced with a call to `called_at_rt` otherwise. +/// +/// # Type Requirements +/// +/// The two functions must be both function items. They cannot be function +/// pointers or closures. +/// +/// `arg` will be the arguments that will be passed to either one of the +/// two functions, therefore, both functions must accept the same type of +/// arguments. Both functions must return RET. +/// +/// # Safety +/// +/// This intrinsic allows breaking [referential transparency] in `const fn` +/// and is therefore `unsafe`. +/// +/// Code that uses this intrinsic must be extremely careful to ensure that +/// `const fn`s remain referentially-transparent independently of when they +/// are evaluated. +/// +/// The Rust compiler assumes that it is sound to replace a call to a `const +/// fn` with the result produced by evaluating it at compile-time. If +/// evaluating the function at run-time were to produce a different result, +/// or have any other observable side-effects, the behavior is undefined. +/// +/// [referential transparency]: https://en.wikipedia.org/wiki/Referential_transparency +#[cfg(not(bootstrap))] +#[unstable( + feature = "const_eval_select", + issue = "none", + reason = "const_eval_select will never be stable" +)] +#[rustc_const_unstable(feature = "const_eval_select", issue = "none")] +#[lang = "const_eval_select"] +#[rustc_do_not_const_check] +pub const unsafe fn const_eval_select( + arg: ARG, + _called_in_const: F, + called_at_rt: G, +) -> RET +where + F: ~const FnOnce, + G: FnOnce + ~const Drop, +{ + called_at_rt.call_once(arg) +} + +#[cfg(not(bootstrap))] +#[unstable( + feature = "const_eval_select", + issue = "none", + reason = "const_eval_select will never be stable" +)] +#[rustc_const_unstable(feature = "const_eval_select", issue = "none")] +#[lang = "const_eval_select_ct"] +pub const unsafe fn const_eval_select_ct( + arg: ARG, + called_in_const: F, + _called_at_rt: G, +) -> RET +where + F: ~const FnOnce, + G: FnOnce + ~const Drop, +{ + called_in_const.call_once(arg) +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/copied.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/copied.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/copied.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/copied.rs 2021-11-29 19:27:11.000000000 +0000 @@ -76,6 +76,11 @@ self.it.count() } + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.it.advance_by(n) + } + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where @@ -112,6 +117,11 @@ { self.it.rfold(init, copy_fold(f)) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.it.advance_back_by(n) + } } #[stable(feature = "iter_copied", since = "1.36.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/cycle.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/cycle.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/cycle.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/cycle.rs 2021-11-29 19:27:11.000000000 +0000 @@ -79,6 +79,27 @@ } } + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + match self.iter.advance_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + + while rem > 0 { + self.iter = self.orig.clone(); + match self.iter.advance_by(rem) { + ret @ Ok(_) => return ret, + Err(0) => return Err(n - rem), + Err(advanced) => rem -= advanced, + } + } + + Ok(()) + } + // No `fold` override, because `fold` doesn't make much sense for `Cycle`, // and we can't do anything better than the default. } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/enumerate.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/enumerate.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/enumerate.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/enumerate.rs 2021-11-29 19:27:11.000000000 +0000 @@ -112,6 +112,21 @@ self.iter.fold(init, enumerate(self.count, fold)) } + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + match self.iter.advance_by(n) { + ret @ Ok(_) => { + self.count += n; + ret + } + ret @ Err(advanced) => { + self.count += advanced; + ret + } + } + } + #[rustc_inherit_overflow_checks] #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item @@ -191,6 +206,13 @@ let count = self.count + self.iter.len(); self.iter.rfold(init, enumerate(count, fold)) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + // we do not need to update the count since that only tallies the number of items + // consumed from the front. consuming items from the back can never reduce that. + self.iter.advance_back_by(n) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -227,14 +249,14 @@ unsafe impl TrustedLen for Enumerate where I: TrustedLen {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Enumerate +unsafe impl SourceIter for Enumerate where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/filter_map.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/filter_map.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/filter_map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/filter_map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -129,15 +129,14 @@ impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for FilterMap +unsafe impl SourceIter for FilterMap where - F: FnMut(I::Item) -> Option, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/filter.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/filter.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/filter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/filter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -135,15 +135,14 @@ impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Filter +unsafe impl SourceIter for Filter where - P: FnMut(&I::Item) -> bool, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/flatten.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/flatten.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/flatten.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/flatten.rs 2021-11-29 19:27:11.000000000 +0000 @@ -391,6 +391,41 @@ init } + + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + loop { + if let Some(ref mut front) = self.frontiter { + match front.advance_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + } + self.frontiter = match self.iter.next() { + Some(iterable) => Some(iterable.into_iter()), + _ => break, + } + } + + self.frontiter = None; + + if let Some(ref mut back) = self.backiter { + match back.advance_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + } + + if rem > 0 { + return Err(n - rem); + } + + self.backiter = None; + + Ok(()) + } } impl DoubleEndedIterator for FlattenCompat @@ -486,6 +521,41 @@ init } + + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + loop { + if let Some(ref mut back) = self.backiter { + match back.advance_back_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + } + match self.iter.next_back() { + Some(iterable) => self.backiter = Some(iterable.into_iter()), + _ => break, + } + } + + self.backiter = None; + + if let Some(ref mut front) = self.frontiter { + match front.advance_back_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + } + + if rem > 0 { + return Err(n - rem); + } + + self.frontiter = None; + + Ok(()) + } } trait ConstSizeIntoIterator: IntoIterator { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/inspect.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/inspect.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/inspect.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/inspect.rs 2021-11-29 19:27:11.000000000 +0000 @@ -149,15 +149,14 @@ impl FusedIterator for Inspect where F: FnMut(&I::Item) {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Inspect +unsafe impl SourceIter for Inspect where - F: FnMut(&I::Item), - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/map.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/map.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -201,15 +201,14 @@ } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Map +unsafe impl SourceIter for Map where - F: FnMut(I::Item) -> B, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/map_while.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/map_while.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/map_while.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/map_while.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ /// [`map_while`]: Iterator::map_while /// [`Iterator`]: trait.Iterator.html #[must_use = "iterators are lazy and do nothing unless consumed"] -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] #[derive(Clone)] pub struct MapWhile { iter: I, @@ -23,14 +23,14 @@ } } -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] impl fmt::Debug for MapWhile { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MapWhile").field("iter", &self.iter).finish() } } -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] impl Iterator for MapWhile where P: FnMut(I::Item) -> Option, @@ -80,15 +80,14 @@ } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for MapWhile +unsafe impl SourceIter for MapWhile where - P: FnMut(I::Item) -> Option, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -45,7 +45,7 @@ #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::intersperse::{Intersperse, IntersperseWith}; -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] pub use self::map_while::MapWhile; #[unstable(feature = "trusted_random_access", issue = "none")] @@ -92,9 +92,10 @@ /// [`as_inner`]: SourceIter::as_inner #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] +#[rustc_specialization_trait] pub unsafe trait SourceIter { /// A source stage in an iterator pipeline. - type Source: Iterator; + type Source; /// Retrieve the source of an iterator pipeline. /// @@ -200,14 +201,14 @@ } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for ResultShunt<'_, I, E> +unsafe impl SourceIter for ResultShunt<'_, I, E> where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut Self::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/peekable.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/peekable.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/peekable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/peekable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -321,14 +321,14 @@ unsafe impl TrustedLen for Peekable where I: TrustedLen {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Peekable +unsafe impl SourceIter for Peekable where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/scan.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/scan.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/scan.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/scan.rs 2021-11-29 19:27:11.000000000 +0000 @@ -90,15 +90,14 @@ } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Scan +unsafe impl SourceIter for Scan where - I: SourceIter, - F: FnMut(&mut St, I::Item) -> Option, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/skip.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/skip.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/skip.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/skip.rs 2021-11-29 19:27:11.000000000 +0000 @@ -114,6 +114,38 @@ } self.iter.fold(init, fold) } + + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + + let step_one = self.n.saturating_add(rem); + match self.iter.advance_by(step_one) { + Ok(_) => { + rem -= step_one - self.n; + self.n = 0; + } + Err(advanced) => { + let advanced_without_skip = advanced.saturating_sub(self.n); + self.n = self.n.saturating_sub(advanced); + return Err(advanced_without_skip); + } + } + + // step_one calculation may have saturated + if unlikely(rem > 0) { + return match self.iter.advance_by(rem) { + ret @ Ok(_) => ret, + Err(advanced) => { + rem -= advanced; + Err(n - rem) + } + }; + } + + Ok(()) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -174,20 +206,30 @@ self.try_rfold(init, ok(fold)).unwrap() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let min = crate::cmp::min(self.len(), n); + return match self.iter.advance_back_by(min) { + ret @ Ok(_) if n <= min => ret, + Ok(_) => Err(min), + _ => panic!("ExactSizeIterator contract violation"), + }; + } } #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Skip where I: FusedIterator {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Skip +unsafe impl SourceIter for Skip where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/skip_while.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/skip_while.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/skip_while.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/skip_while.rs 2021-11-29 19:27:11.000000000 +0000 @@ -105,15 +105,14 @@ } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for SkipWhile +unsafe impl SourceIter for SkipWhile where - P: FnMut(&I::Item) -> bool, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/take.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/take.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/take.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/take.rs 2021-11-29 19:27:11.000000000 +0000 @@ -111,17 +111,33 @@ self.try_fold(init, ok(fold)).unwrap() } + + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let min = self.n.min(n); + match self.iter.advance_by(min) { + Ok(_) => { + self.n -= min; + if min < n { Err(min) } else { Ok(()) } + } + ret @ Err(advanced) => { + self.n -= advanced; + ret + } + } + } } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Take +unsafe impl SourceIter for Take where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } @@ -197,6 +213,24 @@ } } } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let inner_len = self.iter.len(); + let len = self.n; + let remainder = len.saturating_sub(n); + let to_advance = inner_len - remainder; + match self.iter.advance_back_by(to_advance) { + Ok(_) => { + self.n = remainder; + if n > len { + return Err(len); + } + return Ok(()); + } + _ => panic!("ExactSizeIterator contract violation"), + } + } } #[stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/take_while.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/take_while.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/take_while.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/take_while.rs 2021-11-29 19:27:11.000000000 +0000 @@ -118,15 +118,14 @@ } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for TakeWhile +unsafe impl SourceIter for TakeWhile where - P: FnMut(&I::Item) -> bool, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/zip.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/zip.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/adapters/zip.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/adapters/zip.rs 2021-11-29 19:27:11.000000000 +0000 @@ -414,16 +414,14 @@ // Arbitrarily selects the left side of the zip iteration as extractable "source" // it would require negative trait bounds to be able to try both #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Zip +unsafe impl SourceIter for Zip where - A: SourceIter, - B: Iterator, - S: Iterator, + A: SourceIter, { - type Source = S; + type Source = A::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut A::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.a) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -39,7 +39,7 @@ //! ``` //! //! An iterator has a method, [`next`], which when called, returns an -//! [`Option`]``. [`next`] will return [`Some(Item)`] as long as there +//! [Option]\. Calling [`next`] will return [`Some(Item)`] as long as there //! are elements, and once they've all been exhausted, will return `None` to //! indicate that iteration is finished. Individual iterators may choose to //! resume iteration, and so calling [`next`] again may or may not eventually @@ -399,7 +399,7 @@ pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] pub use self::adapters::MapWhile; #[unstable(feature = "inplace_iteration", issue = "none")] pub use self::adapters::SourceIter; diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/range.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/range.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/range.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/range.rs 2021-11-29 19:27:11.000000000 +0000 @@ -521,10 +521,12 @@ // Iterator fn spec_next(&mut self) -> Option; fn spec_nth(&mut self, n: usize) -> Option; + fn spec_advance_by(&mut self, n: usize) -> Result<(), usize>; // DoubleEndedIterator fn spec_next_back(&mut self) -> Option; fn spec_nth_back(&mut self, n: usize) -> Option; + fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>; } impl RangeIteratorImpl for ops::Range { @@ -556,6 +558,22 @@ } #[inline] + default fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> { + let available = if self.start <= self.end { + Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) + } else { + 0 + }; + + let taken = available.min(n); + + self.start = + Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld"); + + if taken < n { Err(taken) } else { Ok(()) } + } + + #[inline] default fn spec_next_back(&mut self) -> Option { if self.start < self.end { self.end = @@ -579,6 +597,22 @@ self.end = self.start.clone(); None } + + #[inline] + default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let available = if self.start <= self.end { + Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) + } else { + 0 + }; + + let taken = available.min(n); + + self.end = + Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld"); + + if taken < n { Err(taken) } else { Ok(()) } + } } impl RangeIteratorImpl for ops::Range { @@ -608,6 +642,25 @@ } #[inline] + fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> { + let available = if self.start <= self.end { + Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) + } else { + 0 + }; + + let taken = available.min(n); + + // SAFETY: the conditions above ensure that the count is in bounds. If start <= end + // then steps_between either returns a bound to which we clamp or returns None which + // together with the initial inequality implies more than usize::MAX steps. + // Otherwise 0 is returned which always safe to use. + self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) }; + + if taken < n { Err(taken) } else { Ok(()) } + } + + #[inline] fn spec_next_back(&mut self) -> Option { if self.start < self.end { // SAFETY: just checked precondition @@ -631,6 +684,22 @@ self.end = self.start.clone(); None } + + #[inline] + fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let available = if self.start <= self.end { + Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) + } else { + 0 + }; + + let taken = available.min(n); + + // SAFETY: same as the spec_advance_by() implementation + self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) }; + + if taken < n { Err(taken) } else { Ok(()) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -673,6 +742,16 @@ } #[inline] + fn is_sorted(self) -> bool { + true + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.spec_advance_by(n) + } + + #[inline] #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where @@ -745,6 +824,11 @@ fn nth_back(&mut self, n: usize) -> Option { self.spec_nth_back(n) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.spec_advance_back_by(n) + } } // Safety: @@ -1095,6 +1179,11 @@ fn max(mut self) -> Option { self.next_back() } + + #[inline] + fn is_sorted(self) -> bool { + true + } } #[stable(feature = "inclusive_range", since = "1.26.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/traits/double_ended.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/traits/double_ended.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/traits/double_ended.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/traits/double_ended.rs 2021-11-29 19:27:11.000000000 +0000 @@ -103,9 +103,15 @@ /// elements the iterator is advanced by before running out of elements (i.e. the length /// of the iterator). Note that `k` is always less than `n`. /// - /// Calling `advance_back_by(0)` does not consume any elements and always returns [`Ok(())`]. + /// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its + /// outer iterator until it finds an inner iterator that is not empty, which then often + /// allows it to return a more accurate `size_hint()` than in its initial state. + /// `advance_back_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information + /// whether the iterator is or is not exhausted, the latter can be treated as if [`next_back`] + /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`. /// /// [`advance_by`]: Iterator::advance_by + /// [`Flatten`]: crate::iter::Flatten /// [`next_back`]: DoubleEndedIterator::next_back /// /// # Examples diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/iter/traits/iterator.rs rustc-1.57.0+dfsg1+llvm/library/core/src/iter/traits/iterator.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/iter/traits/iterator.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/iter/traits/iterator.rs 2021-11-29 19:27:11.000000000 +0000 @@ -96,7 +96,7 @@ /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. /// - /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`. + /// The second half of the tuple that is returned is an [Option]<[usize]>. /// A [`None`] here means that either there is no known upper bound, or the /// upper bound is larger than [`usize`]. /// @@ -115,11 +115,9 @@ /// That said, the implementation should provide a correct estimation, /// because otherwise it would be a violation of the trait's protocol. /// - /// The default implementation returns `(0, `[`None`]`)` which is correct for any + /// The default implementation returns (0, [None]) which is correct for any /// iterator. /// - /// [`usize`]: type@usize - /// /// # Examples /// /// Basic usage: @@ -248,8 +246,14 @@ /// of elements the iterator is advanced by before running out of elements (i.e. the /// length of the iterator). Note that `k` is always less than `n`. /// - /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`][Ok]. + /// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`] + /// can advance its outer iterator until it finds an inner iterator that is not empty, which + /// then often allows it to return a more accurate `size_hint()` than in its initial state. + /// `advance_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information + /// whether the iterator is or is not exhausted, the latter can be treated as if [`next`] + /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`. /// + /// [`Flatten`]: crate::iter::Flatten /// [`next`]: Iterator::next /// /// # Examples @@ -870,7 +874,6 @@ /// The returned iterator might panic if the to-be-returned index would /// overflow a [`usize`]. /// - /// [`usize`]: type@usize /// [`zip`]: Iterator::zip /// /// # Examples @@ -1122,7 +1125,6 @@ /// Basic usage: /// /// ``` - /// #![feature(iter_map_while)] /// let a = [-1i32, 4, 0, 1]; /// /// let mut iter = a.iter().map_while(|x| 16i32.checked_div(*x)); @@ -1153,7 +1155,6 @@ /// Stopping after an initial [`None`]: /// /// ``` - /// #![feature(iter_map_while)] /// use std::convert::TryFrom; /// /// let a = [0, 1, 2, -3, 4, 5, -6]; @@ -1171,7 +1172,6 @@ /// removed: /// /// ``` - /// #![feature(iter_map_while)] /// use std::convert::TryFrom; /// /// let a = [1, 2, -3, 4]; @@ -1197,7 +1197,7 @@ /// /// [`fuse`]: Iterator::fuse #[inline] - #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] + #[stable(feature = "iter_map_while", since = "1.57.0")] fn map_while(self, predicate: P) -> MapWhile where Self: Sized, @@ -1807,10 +1807,11 @@ /// The relative order of partitioned items is not maintained. /// /// # Current implementation + /// /// Current algorithms tries finding the first element for which the predicate evaluates /// to false, and the last element for which it evaluates to true and repeatedly swaps them. /// - /// Time Complexity: *O*(*N*) + /// Time complexity: *O*(*n*) /// /// See also [`is_partitioned()`] and [`partition()`]. /// @@ -2178,8 +2179,9 @@ /// If the iterator is empty, returns [`None`]; otherwise, returns the /// result of the reduction. /// + /// The reducing function is a closure with two arguments: an 'accumulator', and an element. /// For iterators with at least one element, this is the same as [`fold()`] - /// with the first element of the iterator as the initial value, folding + /// with the first element of the iterator as the initial accumulator value, folding /// every subsequent element into it. /// /// [`fold()`]: Iterator::fold @@ -2193,8 +2195,8 @@ /// where I: Iterator, /// I::Item: Ord, /// { - /// iter.reduce(|a, b| { - /// if a >= b { a } else { b } + /// iter.reduce(|accum, item| { + /// if accum >= item { accum } else { item } /// }) /// } /// let a = [10, 20, 5, -23, 0]; @@ -3458,6 +3460,7 @@ #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for &mut I { type Item = I::Item; + #[inline] fn next(&mut self) -> Option { (**self).next() } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/lazy.rs rustc-1.57.0+dfsg1+llvm/library/core/src/lazy.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/lazy.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/lazy.rs 2021-11-29 19:27:11.000000000 +0000 @@ -83,6 +83,7 @@ impl OnceCell { /// Creates a new empty cell. #[unstable(feature = "once_cell", issue = "74465")] + #[must_use] pub const fn new() -> OnceCell { OnceCell { inner: UnsafeCell::new(None) } } @@ -214,7 +215,16 @@ if let Some(val) = self.get() { return Ok(val); } - let val = f()?; + /// Avoid inlining the initialization closure into the common path that fetches + /// the already initialized value + #[cold] + fn outlined_call(f: F) -> Result + where + F: FnOnce() -> Result, + { + f() + } + let val = outlined_call(f)?; // Note that *some* forms of reentrant initialization might lead to // UB (see `reentrant_init` test). I believe that just removing this // `assert`, while keeping `set/get` would be sound, but it seems diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/core/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -60,6 +60,32 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr( + not(bootstrap), + 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", + target_pointer_width = "64", + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr", + target_has_atomic_equal_alignment = "8", + target_has_atomic_equal_alignment = "16", + target_has_atomic_equal_alignment = "32", + target_has_atomic_equal_alignment = "64", + target_has_atomic_equal_alignment = "ptr", + target_has_atomic_load_store = "8", + target_has_atomic_load_store = "16", + target_has_atomic_load_store = "32", + target_has_atomic_load_store = "64", + target_has_atomic_load_store = "ptr", + )) +)] #![no_core] // // Lints: @@ -69,7 +95,6 @@ #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] -#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard // // Library features for const fns: #![feature(const_align_of_val)] @@ -92,6 +117,7 @@ #![feature(const_maybe_uninit_assume_init)] #![feature(const_option)] #![feature(const_pin)] +#![feature(const_replace)] #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_ptr_read)] @@ -104,7 +130,6 @@ #![feature(const_trait_impl)] #![feature(const_type_id)] #![feature(const_type_name)] -#![feature(const_unreachable_unchecked)] #![feature(const_default_impls)] #![feature(duration_consts_2)] #![feature(ptr_metadata)] @@ -122,18 +147,18 @@ #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] #![feature(const_fn_trait_bound)] -#![cfg_attr(bootstrap, feature(const_fn_transmute))] -#![cfg_attr(bootstrap, feature(const_fn_union))] #![feature(const_impl_trait)] #![feature(const_mut_refs)] -#![feature(const_panic)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(const_precise_live_drops)] #![feature(const_raw_ptr_deref)] #![feature(const_refs_to_cell)] #![feature(decl_macro)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] +#![feature(doc_primitive)] #![feature(exhaustive_patterns)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] #![feature(extern_types)] #![feature(fundamental)] #![feature(if_let_guard)] @@ -143,6 +168,8 @@ #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] +#![cfg_attr(not(bootstrap), feature(must_not_suspend))] #![feature(negative_impls)] #![feature(never_type)] #![feature(no_core)] @@ -358,3 +385,5 @@ /* compiler built-in */ } } + +include!("primitive_docs.rs"); diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/macros/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/macros/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/macros/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/macros/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -843,7 +843,6 @@ /// This macro is used by the panic macros for the `const_panic` feature. /// /// This macro will be removed once `format_args` is allowed in const contexts. - #[cfg(not(bootstrap))] #[unstable(feature = "const_format_args", issue = "none")] #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)] #[rustc_builtin_macro] @@ -853,16 +852,6 @@ ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; } - /// Same as `format_args`, but can be used in some const contexts. - #[cfg(bootstrap)] - #[unstable(feature = "const_format_args", issue = "none")] - #[macro_export] - macro_rules! const_format_args { - ($($t:tt)*) => { - $crate::format_args!($($t)*) - } - } - /// Same as `format_args`, but adds a newline in the end. #[unstable( feature = "format_args_nl", diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/marker.rs rustc-1.57.0+dfsg1+llvm/library/core/src/marker.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/marker.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/marker.rs 2021-11-29 19:27:11.000000000 +0000 @@ -30,7 +30,8 @@ /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")] +#[cfg_attr(all(not(test), bootstrap), rustc_diagnostic_item = "send_trait")] +#[cfg_attr(all(not(test), not(bootstrap)), rustc_diagnostic_item = "Send")] #[rustc_on_unimplemented( message = "`{Self}` cannot be sent between threads safely", label = "`{Self}` cannot be sent between threads safely" @@ -99,17 +100,15 @@ /// `Unsize`. /// /// All implementations of `Unsize` are provided automatically by the compiler. +/// Those implementations are: /// -/// `Unsize` is implemented for: -/// -/// - `[T; N]` is `Unsize<[T]>` -/// - `T` is `Unsize` when `T: Trait` -/// - `Foo<..., T, ...>` is `Unsize>` if: -/// - `T: Unsize` -/// - Foo is a struct -/// - Only the last field of `Foo` has a type involving `T` -/// - `T` is not part of the type of any other fields -/// - `Bar: Unsize>`, if the last field of `Foo` has type `Bar` +/// - Arrays `[T; N]` implement `Unsize<[T]>`. +/// - Types implementing a trait `Trait` also implement `Unsize`. +/// - Structs `Foo<..., T, ...>` implement `Unsize>` if all of these conditions +/// are met: +/// - `T: Unsize`. +/// - Only the last field of `Foo` has a type involving `T`. +/// - `Bar: Unsize>`, where `Bar` stands for the actual type of that last field. /// /// `Unsize` is used along with [`ops::CoerceUnsized`] to allow /// "user-defined" containers such as [`Rc`] to contain dynamically-sized @@ -382,6 +381,7 @@ // existing specializations on `Copy` that already exist in the standard // library, and there's no way to safely have this behavior right now. #[rustc_unsafe_specialization_marker] +#[rustc_diagnostic_item = "Copy"] pub trait Copy: Clone { // Empty. } @@ -460,7 +460,7 @@ /// [transmute]: crate::mem::transmute /// [nomicon-send-and-sync]: ../../nomicon/send-and-sync.html #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Sync")] #[lang = "sync"] #[rustc_on_unimplemented( message = "`{Self}` cannot be shared between threads safely", diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/mem/manually_drop.rs rustc-1.57.0+dfsg1+llvm/library/core/src/mem/manually_drop.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/mem/manually_drop.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/mem/manually_drop.rs 2021-11-29 19:27:11.000000000 +0000 @@ -145,7 +145,8 @@ } #[stable(feature = "manually_drop", since = "1.20.0")] -impl Deref for ManuallyDrop { +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +impl const Deref for ManuallyDrop { type Target = T; #[inline(always)] fn deref(&self) -> &T { @@ -154,7 +155,8 @@ } #[stable(feature = "manually_drop", since = "1.20.0")] -impl DerefMut for ManuallyDrop { +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +impl const DerefMut for ManuallyDrop { #[inline(always)] fn deref_mut(&mut self) -> &mut T { &mut self.value diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/mem/maybe_uninit.rs rustc-1.57.0+dfsg1+llvm/library/core/src/mem/maybe_uninit.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/mem/maybe_uninit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/mem/maybe_uninit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -291,6 +291,7 @@ /// [`assume_init`]: MaybeUninit::assume_init #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")] + #[must_use = "use `forget` to avoid running Drop code"] #[inline(always)] pub const fn new(val: T) -> MaybeUninit { MaybeUninit { value: ManuallyDrop::new(val) } @@ -312,6 +313,7 @@ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")] + #[must_use] #[inline(always)] #[rustc_diagnostic_item = "maybe_uninit_uninit"] pub const fn uninit() -> MaybeUninit { @@ -349,6 +351,7 @@ /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] #[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")] + #[must_use] #[inline(always)] pub const fn uninit_array() -> [Self; LEN] { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. @@ -391,6 +394,7 @@ /// // This is undefined behavior. âš ï¸ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[must_use] #[inline] #[rustc_diagnostic_item = "maybe_uninit_zeroed"] pub fn zeroed() -> MaybeUninit { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/mem/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/mem/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/mem/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/mem/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1053,6 +1053,7 @@ #[inline(always)] #[unstable(feature = "variant_count", issue = "73662")] #[rustc_const_unstable(feature = "variant_count", issue = "73662")] +#[rustc_diagnostic_item = "mem_variant_count"] pub const fn variant_count() -> usize { intrinsics::variant_count::() } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/f32.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/f32.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/f32.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/f32.rs 2021-11-29 19:27:11.000000000 +0000 @@ -436,6 +436,7 @@ /// assert!(nan.is_nan()); /// assert!(!f.is_nan()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -467,6 +468,7 @@ /// assert!(inf.is_infinite()); /// assert!(neg_inf.is_infinite()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -488,6 +490,7 @@ /// assert!(!inf.is_finite()); /// assert!(!neg_inf.is_finite()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -515,6 +518,7 @@ /// assert!(lower_than_min.is_subnormal()); /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[must_use] #[stable(feature = "is_subnormal", since = "1.53.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -541,6 +545,7 @@ /// assert!(!lower_than_min.is_normal()); /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -587,6 +592,7 @@ /// assert!(f.is_sign_positive()); /// assert!(!g.is_sign_positive()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -604,6 +610,7 @@ /// assert!(!f.is_sign_negative()); /// assert!(g.is_sign_negative()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -636,6 +643,8 @@ /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] #[inline] pub fn to_degrees(self) -> f32 { @@ -653,6 +662,8 @@ /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] #[inline] pub fn to_radians(self) -> f32 { @@ -712,6 +723,8 @@ /// * Not be `NaN` /// * Not be infinite /// * Be representable in the return type `Int`, after truncating off its fractional part + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_approx_unchecked_to", since = "1.44.0")] #[inline] pub unsafe fn to_int_unchecked(self) -> Int @@ -740,6 +753,8 @@ /// assert_eq!((12.5f32).to_bits(), 0x41480000); /// /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_bits_conv", since = "1.20.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] @@ -786,6 +801,7 @@ /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[must_use] #[inline] pub const fn from_bits(v: u32) -> Self { // SAFETY: `u32` is a plain old datatype so we can always transmute from it @@ -802,6 +818,8 @@ /// let bytes = 12.5f32.to_be_bytes(); /// assert_eq!(bytes, [0x41, 0x48, 0x00, 0x00]); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] @@ -818,6 +836,8 @@ /// let bytes = 12.5f32.to_le_bytes(); /// assert_eq!(bytes, [0x00, 0x00, 0x48, 0x41]); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] @@ -847,6 +867,8 @@ /// } /// ); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] @@ -864,6 +886,7 @@ /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[must_use] #[inline] pub const fn from_be_bytes(bytes: [u8; 4]) -> Self { Self::from_bits(u32::from_be_bytes(bytes)) @@ -879,6 +902,7 @@ /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[must_use] #[inline] pub const fn from_le_bytes(bytes: [u8; 4]) -> Self { Self::from_bits(u32::from_le_bytes(bytes)) @@ -905,6 +929,7 @@ /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[must_use] #[inline] pub const fn from_ne_bytes(bytes: [u8; 4]) -> Self { Self::from_bits(u32::from_ne_bytes(bytes)) diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/f64.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/f64.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/f64.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/f64.rs 2021-11-29 19:27:11.000000000 +0000 @@ -435,6 +435,7 @@ /// assert!(nan.is_nan()); /// assert!(!f.is_nan()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -466,6 +467,7 @@ /// assert!(inf.is_infinite()); /// assert!(neg_inf.is_infinite()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -487,6 +489,7 @@ /// assert!(!inf.is_finite()); /// assert!(!neg_inf.is_finite()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -514,6 +517,7 @@ /// assert!(lower_than_min.is_subnormal()); /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[must_use] #[stable(feature = "is_subnormal", since = "1.53.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -540,6 +544,7 @@ /// assert!(!lower_than_min.is_normal()); /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -586,6 +591,7 @@ /// assert!(f.is_sign_positive()); /// assert!(!g.is_sign_positive()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -593,6 +599,7 @@ !self.is_sign_negative() } + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] #[inline] @@ -611,6 +618,7 @@ /// assert!(!f.is_sign_negative()); /// assert!(g.is_sign_negative()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] @@ -618,6 +626,7 @@ self.to_bits() & 0x8000_0000_0000_0000 != 0 } + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] #[inline] @@ -649,6 +658,8 @@ /// /// assert!(abs_difference < 1e-10); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_degrees(self) -> f64 { @@ -667,6 +678,8 @@ /// /// assert!(abs_difference < 1e-10); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_radians(self) -> f64 { @@ -726,6 +739,8 @@ /// * Not be `NaN` /// * Not be infinite /// * Be representable in the return type `Int`, after truncating off its fractional part + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_approx_unchecked_to", since = "1.44.0")] #[inline] pub unsafe fn to_int_unchecked(self) -> Int @@ -754,6 +769,8 @@ /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); /// /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_bits_conv", since = "1.20.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] @@ -800,6 +817,7 @@ /// ``` #[stable(feature = "float_bits_conv", since = "1.20.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[must_use] #[inline] pub const fn from_bits(v: u64) -> Self { // SAFETY: `u64` is a plain old datatype so we can always transmute from it @@ -816,6 +834,8 @@ /// let bytes = 12.5f64.to_be_bytes(); /// assert_eq!(bytes, [0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] @@ -832,6 +852,8 @@ /// let bytes = 12.5f64.to_le_bytes(); /// assert_eq!(bytes, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] @@ -861,6 +883,8 @@ /// } /// ); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[inline] @@ -878,6 +902,7 @@ /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[must_use] #[inline] pub const fn from_be_bytes(bytes: [u8; 8]) -> Self { Self::from_bits(u64::from_be_bytes(bytes)) @@ -893,6 +918,7 @@ /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[must_use] #[inline] pub const fn from_le_bytes(bytes: [u8; 8]) -> Self { Self::from_bits(u64::from_le_bytes(bytes)) @@ -919,6 +945,7 @@ /// ``` #[stable(feature = "float_to_from_bytes", since = "1.40.0")] #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + #[must_use] #[inline] pub const fn from_ne_bytes(bytes: [u8; 8]) -> Self { Self::from_bits(u64::from_ne_bytes(bytes)) diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/fmt.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/fmt.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/fmt.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/fmt.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,8 +31,10 @@ } else { 3 } + } else if v < 10_000 { + 4 } else { - if v < 10_000 { 4 } else { 5 } + 5 } } Part::Copy(buf) => buf.len(), diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/int_log10.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/int_log10.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/int_log10.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/int_log10.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,114 +1,120 @@ mod unchecked { // 0 < val <= u8::MAX + #[inline] pub const fn u8(val: u8) -> u32 { - if val >= 100 { - 2 - } else if val >= 10 { - 1 - } else { - 0 - } + let val = val as u32; + + // For better performance, avoid branches by assembling the solution + // in the bits above the low 8 bits. + + // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10 + const C1: u32 = 0b11_00000000 - 10; // 758 + // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100 + const C2: u32 = 0b10_00000000 - 100; // 412 + + // Value of top bits: + // +c1 +c2 1&2 + // 0..=9 10 01 00 = 0 + // 10..=99 11 01 01 = 1 + // 100..=255 11 10 10 = 2 + ((val + C1) & (val + C2)) >> 8 + } + + // 0 < val < 100_000 + #[inline] + const fn less_than_5(val: u32) -> u32 { + // Similar to u8, when adding one of these constants to val, + // we get two possible bit patterns above the low 17 bits, + // depending on whether val is below or above the threshold. + const C1: u32 = 0b011_00000000000000000 - 10; // 393206 + const C2: u32 = 0b100_00000000000000000 - 100; // 524188 + const C3: u32 = 0b111_00000000000000000 - 1000; // 916504 + const C4: u32 = 0b100_00000000000000000 - 10000; // 514288 + + // Value of top bits: + // +c1 +c2 1&2 +c3 +c4 3&4 ^ + // 0..=9 010 011 010 110 011 010 000 = 0 + // 10..=99 011 011 011 110 011 010 001 = 1 + // 100..=999 011 100 000 110 011 010 010 = 2 + // 1000..=9999 011 100 000 111 011 011 011 = 3 + // 10000..=99999 011 100 000 111 100 100 100 = 4 + (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17 } // 0 < val <= u16::MAX + #[inline] pub const fn u16(val: u16) -> u32 { - if val >= 10_000 { - 4 - } else if val >= 1000 { - 3 - } else if val >= 100 { - 2 - } else if val >= 10 { - 1 - } else { - 0 - } - } - - // 0 < val < 100_000_000 - const fn less_than_8(mut val: u32) -> u32 { - let mut log = 0; - if val >= 10_000 { - val /= 10_000; - log += 4; - } - log + if val >= 1000 { - 3 - } else if val >= 100 { - 2 - } else if val >= 10 { - 1 - } else { - 0 - } + less_than_5(val as u32) } // 0 < val <= u32::MAX + #[inline] pub const fn u32(mut val: u32) -> u32 { let mut log = 0; - if val >= 100_000_000 { - val /= 100_000_000; - log += 8; + if val >= 100_000 { + val /= 100_000; + log += 5; } - log + less_than_8(val) - } - - // 0 < val < 10_000_000_000_000_000 - const fn less_than_16(mut val: u64) -> u32 { - let mut log = 0; - if val >= 100_000_000 { - val /= 100_000_000; - log += 8; - } - log + less_than_8(val as u32) + log + less_than_5(val) } // 0 < val <= u64::MAX + #[inline] pub const fn u64(mut val: u64) -> u32 { let mut log = 0; - if val >= 10_000_000_000_000_000 { - val /= 10_000_000_000_000_000; - log += 16; + if val >= 10_000_000_000 { + val /= 10_000_000_000; + log += 10; + } + if val >= 100_000 { + val /= 100_000; + log += 5; } - log + less_than_16(val) + log + less_than_5(val as u32) } // 0 < val <= u128::MAX + #[inline] pub const fn u128(mut val: u128) -> u32 { let mut log = 0; if val >= 100_000_000_000_000_000_000_000_000_000_000 { val /= 100_000_000_000_000_000_000_000_000_000_000; log += 32; - return log + less_than_8(val as u32); + return log + u32(val as u32); } if val >= 10_000_000_000_000_000 { val /= 10_000_000_000_000_000; log += 16; } - log + less_than_16(val as u64) + log + u64(val as u64) } // 0 < val <= i8::MAX + #[inline] pub const fn i8(val: i8) -> u32 { u8(val as u8) } // 0 < val <= i16::MAX + #[inline] pub const fn i16(val: i16) -> u32 { u16(val as u16) } // 0 < val <= i32::MAX + #[inline] pub const fn i32(val: i32) -> u32 { u32(val as u32) } // 0 < val <= i64::MAX + #[inline] pub const fn i64(val: i64) -> u32 { u64(val as u64) } // 0 < val <= i128::MAX + #[inline] pub const fn i128(val: i128) -> u32 { u128(val as u128) } @@ -116,8 +122,9 @@ macro_rules! impl_checked { ($T:ident) => { - pub const fn $T(val: $T) -> Option<$T> { - if val > 0 { Some(unchecked::$T(val) as $T) } else { None } + #[inline] + pub const fn $T(val: $T) -> Option { + if val > 0 { Some(unchecked::$T(val)) } else { None } } }; } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/int_macros.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/int_macros.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/int_macros.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/int_macros.rs 2021-11-29 19:27:11.000000000 +0000 @@ -81,6 +81,8 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } @@ -95,6 +97,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn count_zeros(self) -> u32 { (!self).count_ones() @@ -113,6 +117,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn leading_zeros(self) -> u32 { (self as $UnsignedT).leading_zeros() @@ -131,6 +137,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn trailing_zeros(self) -> u32 { (self as $UnsignedT).trailing_zeros() @@ -149,6 +157,8 @@ /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn leading_ones(self) -> u32 { (self as $UnsignedT).leading_ones() @@ -167,6 +177,8 @@ /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn trailing_ones(self) -> u32 { (self as $UnsignedT).trailing_ones() @@ -236,6 +248,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self @@ -257,8 +271,9 @@ /// ``` #[stable(feature = "reverse_bits", since = "1.37.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.37.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] - #[must_use] pub const fn reverse_bits(self) -> Self { (self as $UnsignedT).reverse_bits() as Self } @@ -282,6 +297,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[must_use] #[inline] pub const fn from_be(x: Self) -> Self { #[cfg(target_endian = "big")] @@ -313,6 +329,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[must_use] #[inline] pub const fn from_le(x: Self) -> Self { #[cfg(target_endian = "little")] @@ -344,6 +361,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_be(self) -> Self { // or not to be? #[cfg(target_endian = "big")] @@ -375,6 +394,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_le(self) -> Self { #[cfg(target_endian = "little")] @@ -433,6 +454,28 @@ unsafe { intrinsics::unchecked_add(self, rhs) } } + /// Checked addition with an unsigned integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option { + let (a, b) = self.overflowing_add_unsigned(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer subtraction. Computes `self - rhs`, returning `None` if /// overflow occurred. /// @@ -479,6 +522,28 @@ unsafe { intrinsics::unchecked_sub(self, rhs) } } + /// Checked subtraction with an unsigned integer. Computes `self - rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option { + let (a, b) = self.overflowing_sub_unsigned(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer multiplication. Computes `self * rhs`, returning `None` if /// overflow occurred. /// @@ -543,7 +608,8 @@ without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -569,7 +635,8 @@ without modifying the original"] #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { Some(self.div_euclid(rhs)) @@ -595,7 +662,8 @@ without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -621,7 +689,8 @@ without modifying the original"] #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { Some(self.rem_euclid(rhs)) @@ -641,6 +710,8 @@ /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); @@ -753,6 +824,8 @@ /// ``` #[stable(feature = "no_panic_abs", since = "1.13.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn checked_abs(self) -> Option { if self.is_negative() { @@ -822,6 +895,32 @@ intrinsics::saturating_add(self, rhs) } + /// Saturating addition with an unsigned integer. Computes `self + rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self { + // Overflow can only happen at the upper bound + // We cannot use `unwrap_or` here because it is not `const` + match self.checked_add_unsigned(rhs) { + Some(x) => x, + None => Self::MAX, + } + } + /// Saturating integer subtraction. Computes `self - rhs`, saturating at the /// numeric bounds instead of overflowing. /// @@ -843,6 +942,32 @@ intrinsics::saturating_sub(self, rhs) } + /// Saturating subtraction with an unsigned integer. Computes `self - rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self { + // Overflow can only happen at the lower bound + // We cannot use `unwrap_or` here because it is not `const` + match self.checked_sub_unsigned(rhs) { + Some(x) => x, + None => Self::MIN, + } + } + /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` /// instead of overflowing. /// @@ -859,6 +984,8 @@ #[stable(feature = "saturating_neg", since = "1.45.0")] #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn saturating_neg(self) -> Self { intrinsics::saturating_sub(0, self) @@ -880,6 +1007,8 @@ #[stable(feature = "saturating_neg", since = "1.45.0")] #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn saturating_abs(self) -> Self { if self.is_negative() { @@ -998,6 +1127,27 @@ intrinsics::wrapping_add(self, rhs) } + /// Wrapping (modular) addition with an unsigned integer. Computes + /// `self + rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn wrapping_add_unsigned(self, rhs: $UnsignedT) -> Self { + self.wrapping_add(rhs as Self) + } + /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the /// boundary of the type. /// @@ -1018,6 +1168,27 @@ intrinsics::wrapping_sub(self, rhs) } + /// Wrapping (modular) subtraction with an unsigned integer. Computes + /// `self - rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")] + #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn wrapping_sub_unsigned(self, rhs: $UnsignedT) -> Self { + self.wrapping_sub(rhs as Self) + } + /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at /// the boundary of the type. /// @@ -1166,6 +1337,8 @@ /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn wrapping_neg(self) -> Self { (0 as $SelfT).wrapping_sub(self) @@ -1248,6 +1421,8 @@ /// ``` #[stable(feature = "no_panic_abs", since = "1.13.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[allow(unused_attributes)] #[inline] pub const fn wrapping_abs(self) -> Self { @@ -1273,6 +1448,8 @@ /// ``` #[stable(feature = "unsigned_abs", since = "1.51.0")] #[rustc_const_stable(feature = "unsigned_abs", since = "1.51.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn unsigned_abs(self) -> $UnsignedT { self.wrapping_abs() as $UnsignedT @@ -1368,6 +1545,33 @@ (sum as $SelfT, carry) } + /// Calculates `self` + `rhs` with an unsigned `rhs` + /// + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { + let rhs = rhs as Self; + let (res, overflowed) = self.overflowing_add(rhs); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow @@ -1419,6 +1623,33 @@ (sum as $SelfT, borrow) } + /// Calculates `self` - `rhs` with an unsigned `rhs` + /// + /// Returns a tuple of the subtraction along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { + let rhs = rhs as Self; + let (res, overflowed) = self.overflowing_sub(rhs); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates the multiplication of `self` and `rhs`. /// /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow @@ -1466,7 +1697,8 @@ #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!((self == Self::MIN) & (rhs == -1)) { (self, true) } else { (self / rhs, false) @@ -1496,7 +1728,8 @@ #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!((self == Self::MIN) & (rhs == -1)) { (self, true) } else { (self.div_euclid(rhs), false) @@ -1527,8 +1760,8 @@ #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (0, true) + if unlikely!(rhs == -1) { + (0, self == Self::MIN) } else { (self % rhs, false) } @@ -1558,8 +1791,8 @@ without modifying the original"] #[inline] pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (0, true) + if unlikely!(rhs == -1) { + (0, self == Self::MIN) } else { (self.rem_euclid(rhs), false) } @@ -1583,6 +1816,8 @@ #[inline] #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[allow(unused_attributes)] pub const fn overflowing_neg(self) -> (Self, bool) { if unlikely!(self == Self::MIN) { @@ -1657,6 +1892,8 @@ /// ``` #[stable(feature = "no_panic_abs", since = "1.13.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_abs(self) -> (Self, bool) { (self.wrapping_abs(), self == Self::MIN) @@ -2001,7 +2238,8 @@ } } - /// Returns the logarithm of the number with respect to an arbitrary base. + /// Returns the logarithm of the number with respect to an arbitrary base, + /// rounded down. /// /// This method might not be optimized owing to implementation details; /// `log2` can produce results more efficiently for base 2, and `log10` @@ -2010,8 +2248,8 @@ /// # Panics /// /// When the number is zero, or if the base is not at least 2; it - /// panics in debug mode and the return value is wrapped to 0 in release - /// mode (the only situation in which the method can return 0). + /// panics in debug mode and the return value is 0 in release + /// mode. /// /// # Examples /// @@ -2021,12 +2259,12 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log(self, base: Self) -> Self { + pub const fn log(self, base: Self) -> u32 { match self.checked_log(base) { Some(n) => n, None => { @@ -2039,13 +2277,12 @@ } } - /// Returns the base 2 logarithm of the number. + /// Returns the base 2 logarithm of the number, rounded down. /// /// # Panics /// /// When the number is zero it panics in debug mode and the return value - /// is wrapped to 0 in release mode (the only situation in which the - /// method can return 0). + /// is 0 in release mode. /// /// # Examples /// @@ -2055,12 +2292,12 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log2(self) -> Self { + pub const fn log2(self) -> u32 { match self.checked_log2() { Some(n) => n, None => { @@ -2073,13 +2310,12 @@ } } - /// Returns the base 10 logarithm of the number. + /// Returns the base 10 logarithm of the number, rounded down. /// /// # Panics /// /// When the number is zero it panics in debug mode and the return value - /// is wrapped to 0 in release mode (the only situation in which the - /// method can return 0). + /// is 0 in release mode. /// /// # Example /// @@ -2089,12 +2325,12 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log10(self) -> Self { + pub const fn log10(self) -> u32 { match self.checked_log10() { Some(n) => n, None => { @@ -2107,7 +2343,8 @@ } } - /// Returns the logarithm of the number with respect to an arbitrary base. + /// Returns the logarithm of the number with respect to an arbitrary base, + /// rounded down. /// /// Returns `None` if the number is negative or zero, or if the base is not at least 2. /// @@ -2123,9 +2360,9 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] - pub const fn checked_log(self, base: Self) -> Option { + pub const fn checked_log(self, base: Self) -> Option { if self <= 0 || base <= 1 { None } else { @@ -2147,7 +2384,7 @@ } } - /// Returns the base 2 logarithm of the number. + /// Returns the base 2 logarithm of the number, rounded down. /// /// Returns `None` if the number is negative or zero. /// @@ -2159,19 +2396,19 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] - pub const fn checked_log2(self) -> Option { + pub const fn checked_log2(self) -> Option { if self <= 0 { None } else { // SAFETY: We just checked that this number is positive - let log = (Self::BITS - 1) as Self - unsafe { intrinsics::ctlz_nonzero(self) }; + let log = (Self::BITS - 1) - unsafe { intrinsics::ctlz_nonzero(self) as u32 }; Some(log) } } - /// Returns the base 10 logarithm of the number. + /// Returns the base 10 logarithm of the number, rounded down. /// /// Returns `None` if the number is negative or zero. /// @@ -2183,13 +2420,10 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] - pub const fn checked_log10(self) -> Option { - match int_log10::$ActualT(self as $ActualT) { - Some(s) => Some(s as Self), - None => None, - } + pub const fn checked_log10(self) -> Option { + int_log10::$ActualT(self as $ActualT) } /// Computes the absolute value of `self`. @@ -2217,6 +2451,8 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[allow(unused_attributes)] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub const fn abs(self) -> Self { @@ -2230,6 +2466,48 @@ } } + /// Computes the absolute difference between `self` and `other`. + /// + /// This function always returns the correct answer without overflow or + /// panics by returning an unsigned integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_abs_diff)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($UnsignedT), ");")] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($UnsignedT), ");")] + #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").abs_diff(80), 180", stringify!($UnsignedT), ");")] + #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").abs_diff(-120), 20", stringify!($UnsignedT), ");")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.abs_diff(", stringify!($SelfT), "::MAX), ", stringify!($UnsignedT), "::MAX);")] + /// ``` + #[unstable(feature = "int_abs_diff", issue = "89492")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn abs_diff(self, other: Self) -> $UnsignedT { + if self < other { + // Converting a non-negative x from signed to unsigned by using + // `x as U` is left unchanged, but a negative x is converted + // to value x + 2^N. Thus if `s` and `o` are binary variables + // respectively indicating whether `self` and `other` are + // negative, we are computing the mathematical value: + // + // (other + o*2^N) - (self + s*2^N) mod 2^N + // other - self + (o-s)*2^N mod 2^N + // other - self mod 2^N + // + // Finally, taking the mod 2^N of the mathematical value of + // `other - self` does not change it as it already is + // in the range [0, 2^N). + (other as $UnsignedT).wrapping_sub(self as $UnsignedT) + } else { + (self as $UnsignedT).wrapping_sub(other as $UnsignedT) + } + } + /// Returns a number representing sign of `self`. /// /// - `0` if the number is zero @@ -2247,6 +2525,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn signum(self) -> Self { match self { @@ -2267,6 +2547,7 @@ #[doc = concat!("assert!(10", stringify!($SelfT), ".is_positive());")] #[doc = concat!("assert!(!(-10", stringify!($SelfT), ").is_positive());")] /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[inline(always)] @@ -2283,6 +2564,7 @@ #[doc = concat!("assert!((-10", stringify!($SelfT), ").is_negative());")] #[doc = concat!("assert!(!10", stringify!($SelfT), ".is_negative());")] /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[inline(always)] @@ -2301,6 +2583,8 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { self.to_be().to_ne_bytes() @@ -2319,6 +2603,8 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { self.to_le().to_ne_bytes() @@ -2353,7 +2639,8 @@ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -2386,6 +2673,7 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use] #[inline] pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) @@ -2416,6 +2704,7 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use] #[inline] pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) @@ -2457,9 +2746,9 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -245,7 +245,7 @@ #[lang = "u8"] impl u8 { widening_impl! { u8, u16, 8 } - uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", + uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } /// Checks if the value is within the ASCII range. @@ -259,6 +259,7 @@ /// assert!(ascii.is_ascii()); /// assert!(!non_ascii.is_ascii()); /// ``` + #[must_use] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.43.0")] #[inline] @@ -282,6 +283,7 @@ /// ``` /// /// [`make_ascii_uppercase`]: Self::make_ascii_uppercase + #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase()`"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] @@ -306,6 +308,7 @@ /// ``` /// /// [`make_ascii_lowercase`]: Self::make_ascii_lowercase + #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase()`"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] @@ -417,6 +420,7 @@ /// assert!(!lf.is_ascii_alphabetic()); /// assert!(!esc.is_ascii_alphabetic()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -450,6 +454,7 @@ /// assert!(!lf.is_ascii_uppercase()); /// assert!(!esc.is_ascii_uppercase()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -483,6 +488,7 @@ /// assert!(!lf.is_ascii_lowercase()); /// assert!(!esc.is_ascii_lowercase()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -519,6 +525,7 @@ /// assert!(!lf.is_ascii_alphanumeric()); /// assert!(!esc.is_ascii_alphanumeric()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -552,6 +559,7 @@ /// assert!(!lf.is_ascii_digit()); /// assert!(!esc.is_ascii_digit()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -588,6 +596,7 @@ /// assert!(!lf.is_ascii_hexdigit()); /// assert!(!esc.is_ascii_hexdigit()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -625,6 +634,7 @@ /// assert!(!lf.is_ascii_punctuation()); /// assert!(!esc.is_ascii_punctuation()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -658,6 +668,7 @@ /// assert!(!lf.is_ascii_graphic()); /// assert!(!esc.is_ascii_graphic()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -708,6 +719,7 @@ /// assert!(lf.is_ascii_whitespace()); /// assert!(!esc.is_ascii_whitespace()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -743,6 +755,7 @@ /// assert!(lf.is_ascii_control()); /// assert!(esc.is_ascii_control()); /// ``` + #[must_use] #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] @@ -769,6 +782,8 @@ /// assert_eq!("\\\\", b'\\'.escape_ascii().to_string()); /// assert_eq!("\\x9d", b'\x9d'.escape_ascii().to_string()); /// ``` + #[must_use = "this returns the escaped byte as an iterator, \ + without modifying the original"] #[unstable(feature = "inherent_ascii_escape", issue = "77174")] #[inline] pub fn escape_ascii(&self) -> ascii::EscapeDefault { @@ -779,21 +794,21 @@ #[lang = "u16"] impl u16 { widening_impl! { u16, u32, 16 } - uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "u32"] impl u32 { widening_impl! { u32, u64, 32 } - uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", + uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "u64"] impl u64 { widening_impl! { u64, u128, 64 } - uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", + uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", @@ -802,7 +817,7 @@ #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, 16, + uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16, "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ @@ -816,7 +831,7 @@ #[lang = "usize"] impl usize { widening_impl! { usize, u32, 16 } - uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -824,7 +839,7 @@ #[lang = "usize"] impl usize { widening_impl! { usize, u64, 32 } - uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", + uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -833,7 +848,7 @@ #[lang = "usize"] impl usize { widening_impl! { usize, u128, 64 } - uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", + uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", @@ -865,23 +880,41 @@ #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum FpCategory { - /// "Not a Number", often obtained by dividing by zero. + /// NaN (not a number): this value results from calculations like `(-1.0).sqrt()`. + /// + /// See [the documentation for `f32`](f32) for more information on the unusual properties + /// of NaN. #[stable(feature = "rust1", since = "1.0.0")] Nan, - /// Positive or negative infinity. + /// Positive or negative infinity, which often results from dividing a nonzero number + /// by zero. #[stable(feature = "rust1", since = "1.0.0")] Infinite, /// Positive or negative zero. + /// + /// See [the documentation for `f32`](f32) for more information on the signedness of zeroes. #[stable(feature = "rust1", since = "1.0.0")] Zero, - /// De-normalized floating point representation (less precise than `Normal`). + /// “Subnormal†or “denormal†floating point representation (less precise, relative to + /// their magnitude, than [`Normal`]). + /// + /// Subnormal numbers are larger in magnitude than [`Zero`] but smaller in magnitude than all + /// [`Normal`] numbers. + /// + /// [`Normal`]: Self::Normal + /// [`Zero`]: Self::Zero #[stable(feature = "rust1", since = "1.0.0")] Subnormal, - /// A regular floating point number. + /// A regular floating point number, not any of the exceptional categories. + /// + /// The smallest positive normal numbers are [`f32::MIN_POSITIVE`] and [`f64::MIN_POSITIVE`], + /// and the largest positive normal numbers are [`f32::MAX`] and [`f64::MAX`]. (Unlike signed + /// integers, floating point numbers are symmetric in their range, so negating any of these + /// constants will produce their negative counterpart.) #[stable(feature = "rust1", since = "1.0.0")] Normal, } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/nonzero.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/nonzero.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/nonzero.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/nonzero.rs 2021-11-29 19:27:11.000000000 +0000 @@ -50,6 +50,7 @@ /// The value must not be zero. #[$stability] #[$const_new_unchecked_stability] + #[must_use] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { // SAFETY: this is guaranteed to be safe by the caller. @@ -59,6 +60,7 @@ /// Creates a non-zero if the given value is not zero. #[$stability] #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] + #[must_use] #[inline] pub const fn new(n: $Int) -> Option { if n != 0 { @@ -198,6 +200,8 @@ /// ``` #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn leading_zeros(self) -> u32 { // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero @@ -220,6 +224,8 @@ /// ``` #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn trailing_zeros(self) -> u32 { // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero @@ -315,6 +321,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn checked_add(self, other: $Int) -> Option<$Ty> { if let Some(result) = self.get().checked_add(other) { @@ -348,6 +356,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn saturating_add(self, other: $Int) -> $Ty { // SAFETY: $Int::saturating_add returns $Int::MAX on overflow @@ -378,8 +388,10 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] - pub unsafe fn unchecked_add(self, other: $Int) -> $Ty { + pub const unsafe fn unchecked_add(self, other: $Int) -> $Ty { // SAFETY: The caller ensures there is no overflow. unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) } } @@ -410,6 +422,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn checked_next_power_of_two(self) -> Option<$Ty> { if let Some(nz) = self.get().checked_next_power_of_two() { @@ -460,6 +474,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn abs(self) -> $Ty { // SAFETY: This cannot overflow to zero. @@ -490,6 +506,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn checked_abs(self) -> Option<$Ty> { if let Some(nz) = self.get().checked_abs() { @@ -524,6 +542,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn overflowing_abs(self) -> ($Ty, bool) { let (nz, flag) = self.get().overflowing_abs(); @@ -562,6 +582,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn saturating_abs(self) -> $Ty { // SAFETY: absolute value of nonzero cannot yield zero values. @@ -595,6 +617,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn wrapping_abs(self) -> $Ty { // SAFETY: absolute value of nonzero cannot yield zero values. @@ -628,6 +652,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn unsigned_abs(self) -> $Uty { // SAFETY: absolute value of nonzero cannot yield zero values. @@ -675,6 +701,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> { if let Some(result) = self.get().checked_mul(other.get()) { @@ -709,6 +737,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn saturating_mul(self, other: $Ty) -> $Ty { // SAFETY: saturating_mul returns u*::MAX on overflow @@ -749,8 +779,10 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] - pub unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { + pub const unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { // SAFETY: The caller ensures there is no overflow. unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } } @@ -778,6 +810,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn checked_pow(self, other: u32) -> Option<$Ty> { if let Some(result) = self.get().checked_pow(other) { @@ -820,6 +854,8 @@ /// # } /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn saturating_pow(self, other: u32) -> $Ty { // SAFETY: saturating_pow returns u*::MAX on overflow @@ -878,6 +914,7 @@ #[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")] /// assert!(!ten.is_power_of_two()); /// ``` + #[must_use] #[unstable(feature = "nonzero_is_power_of_two", issue = "81106")] #[inline] pub const fn is_power_of_two(self) -> bool { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/saturating.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/saturating.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/saturating.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/saturating.rs 2021-11-29 19:27:11.000000000 +0000 @@ -474,6 +474,8 @@ #[inline] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn count_ones(self) -> u32 { self.0.count_ones() @@ -492,6 +494,8 @@ #[doc = concat!("assert_eq!(Saturating(!0", stringify!($t), ").count_zeros(), 0);")] /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn count_zeros(self) -> u32 { self.0.count_zeros() @@ -512,6 +516,8 @@ /// assert_eq!(n.trailing_zeros(), 3); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn trailing_zeros(self) -> u32 { self.0.trailing_zeros() @@ -538,6 +544,8 @@ /// assert_eq!(n.rotate_left(32), m); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn rotate_left(self, n: u32) -> Self { Saturating(self.0.rotate_left(n)) @@ -564,6 +572,8 @@ /// assert_eq!(n.rotate_right(4), m); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn rotate_right(self, n: u32) -> Self { Saturating(self.0.rotate_right(n)) @@ -588,6 +598,8 @@ /// assert_eq!(m, Saturating(21760)); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn swap_bytes(self) -> Self { Saturating(self.0.swap_bytes()) @@ -614,10 +626,11 @@ /// assert_eq!(m.0 as u16, 0b10101010_00000000); /// assert_eq!(m, Saturating(-22016)); /// ``` + #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] #[rustc_const_stable(feature = "const_reverse_bits", since = "1.37.0")] - #[inline] - #[must_use] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub const fn reverse_bits(self) -> Self { Saturating(self.0.reverse_bits()) } @@ -644,6 +657,7 @@ /// } /// ``` #[inline] + #[must_use] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn from_be(x: Self) -> Self { Saturating(<$t>::from_be(x.0)) @@ -671,6 +685,7 @@ /// } /// ``` #[inline] + #[must_use] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn from_le(x: Self) -> Self { Saturating(<$t>::from_le(x.0)) @@ -699,6 +714,8 @@ /// ``` #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub const fn to_be(self) -> Self { Saturating(self.0.to_be()) } @@ -726,6 +743,8 @@ /// ``` #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub const fn to_le(self) -> Self { Saturating(self.0.to_le()) } @@ -754,6 +773,8 @@ /// ``` #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn pow(self, exp: u32) -> Self { Saturating(self.0.saturating_pow(exp)) } @@ -782,6 +803,8 @@ /// ``` #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub const fn leading_zeros(self) -> u32 { self.0.leading_zeros() } @@ -805,6 +828,8 @@ /// ``` #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn abs(self) -> Saturating<$t> { Saturating(self.0.saturating_abs()) } @@ -829,6 +854,8 @@ /// ``` #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn signum(self) -> Saturating<$t> { Saturating(self.0.signum()) } @@ -847,6 +874,7 @@ #[doc = concat!("assert!(Saturating(10", stringify!($t), ").is_positive());")] #[doc = concat!("assert!(!Saturating(-10", stringify!($t), ").is_positive());")] /// ``` + #[must_use] #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn is_positive(self) -> bool { @@ -867,6 +895,7 @@ #[doc = concat!("assert!(Saturating(-10", stringify!($t), ").is_negative());")] #[doc = concat!("assert!(!Saturating(10", stringify!($t), ").is_negative());")] /// ``` + #[must_use] #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub const fn is_negative(self) -> bool { @@ -908,6 +937,8 @@ /// ``` #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub const fn leading_zeros(self) -> u32 { self.0.leading_zeros() } @@ -925,6 +956,7 @@ #[doc = concat!("assert!(Saturating(16", stringify!($t), ").is_power_of_two());")] #[doc = concat!("assert!(!Saturating(10", stringify!($t), ").is_power_of_two());")] /// ``` + #[must_use] #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] pub fn is_power_of_two(self) -> bool { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/uint_macros.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/uint_macros.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/uint_macros.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/uint_macros.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,5 @@ macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ident, $BITS:expr, $MaxV:expr, + ($SelfT:ty, $ActualT:ident, $SignedT:ident, $BITS:expr, $MaxV:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, $reversed:expr, $le_bytes:expr, $be_bytes:expr, $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { @@ -80,6 +80,8 @@ #[rustc_const_stable(feature = "const_math", since = "1.32.0")] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn count_ones(self) -> u32 { intrinsics::ctpop(self as $ActualT) as u32 @@ -96,6 +98,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn count_zeros(self) -> u32 { (!self).count_ones() @@ -114,6 +118,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn leading_zeros(self) -> u32 { intrinsics::ctlz(self as $ActualT) as u32 @@ -133,6 +139,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn trailing_zeros(self) -> u32 { intrinsics::cttz(self) as u32 @@ -151,6 +159,8 @@ /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn leading_ones(self) -> u32 { (!self).leading_zeros() @@ -170,6 +180,8 @@ /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn trailing_ones(self) -> u32 { (!self).trailing_zeros() @@ -238,6 +250,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn swap_bytes(self) -> Self { intrinsics::bswap(self as $ActualT) as Self @@ -259,8 +273,9 @@ /// ``` #[stable(feature = "reverse_bits", since = "1.37.0")] #[rustc_const_stable(feature = "const_math", since = "1.37.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] - #[must_use] pub const fn reverse_bits(self) -> Self { intrinsics::bitreverse(self as $ActualT) as Self } @@ -285,6 +300,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use] #[inline(always)] pub const fn from_be(x: Self) -> Self { #[cfg(target_endian = "big")] @@ -317,6 +333,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use] #[inline(always)] pub const fn from_le(x: Self) -> Self { #[cfg(target_endian = "little")] @@ -349,6 +366,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn to_be(self) -> Self { // or not to be? #[cfg(target_endian = "big")] @@ -381,6 +400,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn to_le(self) -> Self { #[cfg(target_endian = "little")] @@ -442,6 +463,29 @@ unsafe { intrinsics::unchecked_add(self, rhs) } } + /// Checked addition with a signed integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add_signed(self, rhs: $SignedT) -> Option { + let (a, b) = self.overflowing_add_signed(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. /// @@ -635,7 +679,8 @@ } } - /// Returns the logarithm of the number with respect to an arbitrary base. + /// Returns the logarithm of the number with respect to an arbitrary base, + /// rounded down. /// /// This method might not be optimized owing to implementation details; /// `log2` can produce results more efficiently for base 2, and `log10` @@ -644,8 +689,7 @@ /// # Panics /// /// When the number is negative, zero, or if the base is not at least 2; - /// it panics in debug mode and the return value is wrapped to 0 in - /// release mode (the only situation in which the method can return 0). + /// it panics in debug mode and the return value is 0 in release mode. /// /// # Examples /// @@ -655,12 +699,12 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log(self, base: Self) -> Self { + pub const fn log(self, base: Self) -> u32 { match self.checked_log(base) { Some(n) => n, None => { @@ -673,13 +717,12 @@ } } - /// Returns the base 2 logarithm of the number. + /// Returns the base 2 logarithm of the number, rounded down. /// /// # Panics /// /// When the number is negative or zero it panics in debug mode and - /// the return value is wrapped to 0 in release mode (the only situation in - /// which the method can return 0). + /// the return value is 0 in release mode. /// /// # Examples /// @@ -689,12 +732,12 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log2(self) -> Self { + pub const fn log2(self) -> u32 { match self.checked_log2() { Some(n) => n, None => { @@ -707,13 +750,12 @@ } } - /// Returns the base 10 logarithm of the number. + /// Returns the base 10 logarithm of the number, rounded down. /// /// # Panics /// /// When the number is negative or zero it panics in debug mode and the - /// return value is wrapped to 0 in release mode (the only situation in - /// which the method can return 0). + /// return value is 0 in release mode. /// /// # Example /// @@ -723,12 +765,12 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log10(self) -> Self { + pub const fn log10(self) -> u32 { match self.checked_log10() { Some(n) => n, None => { @@ -741,7 +783,8 @@ } } - /// Returns the logarithm of the number with respect to an arbitrary base. + /// Returns the logarithm of the number with respect to an arbitrary base, + /// rounded down. /// /// Returns `None` if the number is zero, or if the base is not at least 2. /// @@ -757,9 +800,9 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] - pub const fn checked_log(self, base: Self) -> Option { + pub const fn checked_log(self, base: Self) -> Option { if self <= 0 || base <= 1 { None } else { @@ -781,7 +824,7 @@ } } - /// Returns the base 2 logarithm of the number. + /// Returns the base 2 logarithm of the number, rounded down. /// /// Returns `None` if the number is zero. /// @@ -793,19 +836,19 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] - pub const fn checked_log2(self) -> Option { + pub const fn checked_log2(self) -> Option { if self <= 0 { None } else { // SAFETY: We just checked that this number is positive - let log = (Self::BITS - 1) as Self - unsafe { intrinsics::ctlz_nonzero(self) }; + let log = (Self::BITS - 1) - unsafe { intrinsics::ctlz_nonzero(self) as u32 }; Some(log) } } - /// Returns the base 10 logarithm of the number. + /// Returns the base 10 logarithm of the number, rounded down. /// /// Returns `None` if the number is zero. /// @@ -817,13 +860,10 @@ /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] - pub const fn checked_log10(self) -> Option { - match int_log10::$ActualT(self as $ActualT) { - Some(s) => Some(s as Self), - None => None, - } + pub const fn checked_log10(self) -> Option { + int_log10::$ActualT(self as $ActualT) } /// Checked negation. Computes `-self`, returning `None` unless `self == @@ -841,6 +881,8 @@ /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); @@ -998,6 +1040,35 @@ intrinsics::saturating_add(self, rhs) } + /// Saturating addition with a signed integer. Computes `self + rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add_signed(self, rhs: $SignedT) -> Self { + let (res, overflow) = self.overflowing_add(rhs as Self); + if overflow == (rhs < 0) { + res + } else if overflow { + Self::MAX + } else { + 0 + } + } + /// Saturating integer subtraction. Computes `self - rhs`, saturating /// at the numeric bounds instead of overflowing. /// @@ -1114,6 +1185,28 @@ intrinsics::wrapping_add(self, rhs) } + /// Wrapping (modular) addition with a signed integer. Computes + /// `self + rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_add_signed(self, rhs: $SignedT) -> Self { + self.wrapping_add(rhs as Self) + } + /// Wrapping (modular) subtraction. Computes `self - rhs`, /// wrapping around at the boundary of the type. /// @@ -1151,7 +1244,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline(always)] pub const fn wrapping_mul(self, rhs: Self) -> Self { intrinsics::wrapping_mul(self, rhs) @@ -1276,6 +1369,8 @@ /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] pub const fn wrapping_neg(self) -> Self { (0 as $SelfT).wrapping_sub(self) @@ -1438,6 +1533,32 @@ (c, b | d) } + /// Calculates `self` + `rhs` with a signed `rhs` + /// + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add_signed(self, rhs: $SignedT) -> (Self, bool) { + let (res, overflowed) = self.overflowing_add(rhs as Self); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating @@ -1493,6 +1614,35 @@ (c, b | d) } + /// Computes the absolute difference between `self` and `other`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_abs_diff)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($SelfT), ");")] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($SelfT), ");")] + /// ``` + #[unstable(feature = "int_abs_diff", issue = "89492")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn abs_diff(self, other: Self) -> Self { + if mem::size_of::() == 1 { + // Trick LLVM into generating the psadbw instruction when SSE2 + // is available and this function is autovectorized for u8's. + (self as i32).wrapping_sub(other as i32).abs() as Self + } else { + if self < other { + other - self + } else { + self - other + } + } + } + /// Calculates the multiplication of `self` and `rhs`. /// /// Returns a tuple of the multiplication along with a boolean @@ -1652,6 +1802,8 @@ #[inline(always)] #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub const fn overflowing_neg(self) -> (Self, bool) { ((!self).wrapping_add(1), self != 0) } @@ -1768,7 +1920,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ - without modifying the original"] + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub const fn pow(self, mut exp: u32) -> Self { @@ -1865,6 +2017,8 @@ #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_floor(4), 1);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline(always)] #[rustc_inherit_overflow_checks] pub const fn unstable_div_floor(self, rhs: Self) -> Self { @@ -1886,6 +2040,8 @@ #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_ceil(4), 2);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub const fn unstable_div_ceil(self, rhs: Self) -> Self { @@ -1927,7 +2083,8 @@ } /// Calculates the smallest value greater than or equal to `self` that - /// is a multiple of `rhs`. If `rhs` is negative, + /// is a multiple of `rhs`. Returns `None` is `rhs` is zero or the + /// operation would result in overflow. /// /// # Examples /// @@ -1962,6 +2119,7 @@ #[doc = concat!("assert!(16", stringify!($SelfT), ".is_power_of_two());")] #[doc = concat!("assert!(!10", stringify!($SelfT), ".is_power_of_two());")] /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")] #[inline(always)] @@ -1995,7 +2153,7 @@ /// Returns the smallest power of two greater than or equal to `self`. /// /// When return value overflows (i.e., `self > (1 << (N-1))` for type - /// `uN`), it panics in debug mode and return value is wrapped to 0 in + /// `uN`), it panics in debug mode and the return value is wrapped to 0 in /// release mode (the only situation in which method can return 0). /// /// # Examples @@ -2008,6 +2166,8 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] pub const fn next_power_of_two(self) -> Self { @@ -2030,6 +2190,8 @@ #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub const fn checked_next_power_of_two(self) -> Option { self.one_less_than_next_power_of_two().checked_add(1) } @@ -2052,6 +2214,8 @@ #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", reason = "needs decision on wrapping behaviour")] #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub const fn wrapping_next_power_of_two(self) -> Self { self.one_less_than_next_power_of_two().wrapping_add(1) } @@ -2069,6 +2233,8 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { self.to_be().to_ne_bytes() @@ -2087,6 +2253,8 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { self.to_le().to_ne_bytes() @@ -2119,9 +2287,10 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -2154,6 +2323,7 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use] #[inline] pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) @@ -2184,6 +2354,7 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use] #[inline] pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) @@ -2225,9 +2396,9 @@ /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[must_use] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/num/wrapping.rs rustc-1.57.0+dfsg1+llvm/library/core/src/num/wrapping.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/num/wrapping.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/num/wrapping.rs 2021-11-29 19:27:11.000000000 +0000 @@ -32,6 +32,10 @@ /// /// assert_eq!(u32::MAX, (zero - one).0); /// ``` +/// +/// # Layout +/// +/// `Wrapping` is guaranteed to have the same layout and ABI as `T`. #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] #[repr(transparent)] @@ -465,6 +469,8 @@ #[inline] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn count_ones(self) -> u32 { self.0.count_ones() @@ -483,6 +489,8 @@ #[doc = concat!("assert_eq!(Wrapping(!0", stringify!($t), ").count_zeros(), 0);")] /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn count_zeros(self) -> u32 { self.0.count_zeros() @@ -503,6 +511,8 @@ /// assert_eq!(n.trailing_zeros(), 3); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn trailing_zeros(self) -> u32 { self.0.trailing_zeros() @@ -529,6 +539,8 @@ /// assert_eq!(n.rotate_left(32), m); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn rotate_left(self, n: u32) -> Self { Wrapping(self.0.rotate_left(n)) @@ -555,6 +567,8 @@ /// assert_eq!(n.rotate_right(4), m); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn rotate_right(self, n: u32) -> Self { Wrapping(self.0.rotate_right(n)) @@ -579,6 +593,8 @@ /// assert_eq!(m, Wrapping(21760)); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn swap_bytes(self) -> Self { Wrapping(self.0.swap_bytes()) @@ -606,8 +622,9 @@ /// ``` #[stable(feature = "reverse_bits", since = "1.37.0")] #[rustc_const_stable(feature = "const_reverse_bits", since = "1.37.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] - #[must_use] pub const fn reverse_bits(self) -> Self { Wrapping(self.0.reverse_bits()) } @@ -634,6 +651,7 @@ /// } /// ``` #[inline] + #[must_use] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn from_be(x: Self) -> Self { Wrapping(<$t>::from_be(x.0)) @@ -661,6 +679,7 @@ /// } /// ``` #[inline] + #[must_use] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn from_le(x: Self) -> Self { Wrapping(<$t>::from_le(x.0)) @@ -688,6 +707,8 @@ /// } /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn to_be(self) -> Self { Wrapping(self.0.to_be()) @@ -715,6 +736,8 @@ /// } /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn to_le(self) -> Self { Wrapping(self.0.to_le()) @@ -743,6 +766,8 @@ /// assert_eq!(Wrapping(3i8).pow(6), Wrapping(-39)); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub fn pow(self, exp: u32) -> Self { Wrapping(self.0.wrapping_pow(exp)) @@ -771,6 +796,8 @@ /// assert_eq!(n.leading_zeros(), 3); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn leading_zeros(self) -> u32 { self.0.leading_zeros() @@ -797,6 +824,8 @@ /// assert_eq!(Wrapping(-128i8).abs().0 as u8, 128u8); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub fn abs(self) -> Wrapping<$t> { Wrapping(self.0.wrapping_abs()) @@ -821,6 +850,8 @@ #[doc = concat!("assert_eq!(Wrapping(-10", stringify!($t), ").signum(), Wrapping(-1));")] /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub fn signum(self) -> Wrapping<$t> { Wrapping(self.0.signum()) @@ -840,6 +871,7 @@ #[doc = concat!("assert!(Wrapping(10", stringify!($t), ").is_positive());")] #[doc = concat!("assert!(!Wrapping(-10", stringify!($t), ").is_positive());")] /// ``` + #[must_use] #[inline] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn is_positive(self) -> bool { @@ -860,6 +892,7 @@ #[doc = concat!("assert!(Wrapping(-10", stringify!($t), ").is_negative());")] #[doc = concat!("assert!(!Wrapping(10", stringify!($t), ").is_negative());")] /// ``` + #[must_use] #[inline] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn is_negative(self) -> bool { @@ -889,6 +922,8 @@ /// assert_eq!(n.leading_zeros(), 2); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn leading_zeros(self) -> u32 { self.0.leading_zeros() @@ -907,6 +942,7 @@ #[doc = concat!("assert!(Wrapping(16", stringify!($t), ").is_power_of_two());")] #[doc = concat!("assert!(!Wrapping(10", stringify!($t), ").is_power_of_two());")] /// ``` + #[must_use] #[inline] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub fn is_power_of_two(self) -> bool { @@ -931,6 +967,8 @@ #[doc = concat!("assert_eq!(Wrapping(200_u8).next_power_of_two(), Wrapping(0));")] /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", reason = "needs decision on wrapping behaviour")] pub fn next_power_of_two(self) -> Self { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/ops/bit.rs rustc-1.57.0+dfsg1+llvm/library/core/src/ops/bit.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/ops/bit.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/ops/bit.rs 2021-11-29 19:27:11.000000000 +0000 @@ -30,6 +30,7 @@ /// ``` #[lang = "not"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "!")] pub trait Not { /// The resulting type after applying the `!` operator. #[stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/ops/deref.rs rustc-1.57.0+dfsg1+llvm/library/core/src/ops/deref.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/ops/deref.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/ops/deref.rs 2021-11-29 19:27:11.000000000 +0000 @@ -76,7 +76,8 @@ } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for &T { +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +impl const Deref for &T { type Target = T; #[rustc_diagnostic_item = "noop_method_deref"] @@ -89,7 +90,8 @@ impl !DerefMut for &T {} #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for &mut T { +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +impl const Deref for &mut T { type Target = T; fn deref(&self) -> &T { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/option.rs rustc-1.57.0+dfsg1+llvm/library/core/src/option.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/option.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/option.rs 2021-11-29 19:27:11.000000000 +0000 @@ -47,9 +47,9 @@ //! //! Rust's pointer types must always point to a valid location; there are //! no "null" references. Instead, Rust has *optional* pointers, like -//! the optional owned box, [`Option`]`<`[`Box`]`>`. +//! the optional owned box, [Option]<[Box\]>. //! -//! [`Box`]: ../../std/boxed/struct.Box.html +//! [Box\]: ../../std/boxed/struct.Box.html //! //! The following example uses [`Option`] to create an optional box of //! [`i32`]. Notice that in order to use the inner [`i32`] value, the @@ -111,16 +111,20 @@ //! //! ## Adapters for working with references //! -//! * [`as_ref`] converts from `&Option` to `Option<&T>` -//! * [`as_mut`] converts from `&mut Option` to `Option<&mut T>` -//! * [`as_deref`] converts from `&Option` to `Option<&T::Target>` -//! * [`as_deref_mut`] converts from `&mut Option` to -//! `Option<&mut T::Target>` -//! * [`as_pin_ref`] converts from [`Pin`]`<&Option>` to -//! `Option<`[`Pin`]`<&T>>` -//! * [`as_pin_mut`] converts from [`Pin`]`<&mut Option>` to -//! `Option<`[`Pin`]`<&mut T>>` -//! +//! * [`as_ref`] converts from [&][][Option]\ to [Option]<[&]T> +//! * [`as_mut`] converts from [&mut] [Option]\ to [Option]<[&mut] T> +//! * [`as_deref`] converts from [&][][Option]\ to +//! [Option]<[&]T::[Target]> +//! * [`as_deref_mut`] converts from [&mut] [Option]\ to +//! [Option]<[&mut] T::[Target]> +//! * [`as_pin_ref`] converts from [Pin]<[&][][Option]\> to +//! [Option]<[Pin]<[&]T>> +//! * [`as_pin_mut`] converts from [Pin]<[&mut] [Option]\> to +//! [Option]<[Pin]<[&mut] T>> +//! +//! [&]: reference "shared reference" +//! [&mut]: reference "mutable reference" +//! [Target]: Deref::Target "ops::Deref::Target" //! [`as_deref`]: Option::as_deref //! [`as_deref_mut`]: Option::as_deref_mut //! [`as_mut`]: Option::as_mut @@ -505,7 +509,7 @@ /// The `Option` type. See [the module level documentation](self) for more. #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] -#[rustc_diagnostic_item = "option_type"] +#[rustc_diagnostic_item = "Option"] #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { /// No value @@ -540,8 +544,8 @@ /// ``` #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] #[inline] - #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] pub const fn is_some(&self) -> bool { matches!(*self, Some(_)) } @@ -560,8 +564,8 @@ #[must_use = "if you intended to assert that this doesn't have a value, consider \ `.and_then(|_| panic!(\"`Option` had a value when expected `None`\"))` instead"] #[inline] - #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] pub const fn is_none(&self) -> bool { !self.is_some() } @@ -603,13 +607,13 @@ /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. - /// The [`map`] method takes the `self` argument by value, consuming the original, + /// Converts an Option<[String]> into an Option<[usize]>, preserving + /// the original. The [`map`] method takes the `self` argument by value, consuming the original, /// so this technique uses `as_ref` to first take an `Option` to a reference /// to the value inside the original. /// /// [`map`]: Option::map - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// /// ``` /// let text: Option = Some("Hello, world!".to_string()); @@ -642,15 +646,19 @@ /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_mut(&mut self) -> Option<&mut T> { + #[rustc_const_unstable(feature = "const_option", issue = "67441")] + pub const fn as_mut(&mut self) -> Option<&mut T> { match *self { Some(ref mut x) => Some(x), None => None, } } - /// Converts from [`Pin`]`<&Option>` to `Option<`[`Pin`]`<&T>>`. + /// Converts from [Pin]<[&]Option\> to Option<[Pin]<[&]T>>. + /// + /// [&]: reference "shared reference" #[inline] + #[must_use] #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_ref(self: Pin<&Self>) -> Option> { // SAFETY: `x` is guaranteed to be pinned because it comes from `self` @@ -658,8 +666,11 @@ unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } } - /// Converts from [`Pin`]`<&mut Option>` to `Option<`[`Pin`]`<&mut T>>`. + /// Converts from [Pin]<[&mut] Option\> to Option<[Pin]<[&mut] T>>. + /// + /// [&mut]: reference "mutable reference" #[inline] + #[must_use] #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_mut(self: Pin<&mut Self>) -> Option> { // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`. @@ -819,9 +830,10 @@ /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, consuming the original: + /// Converts an Option<[String]> into an Option<[usize]>, consuming + /// the original: /// - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// ``` /// let maybe_some_string = Some(String::from("Hello, World!")); /// // `Option::map` takes self *by value*, consuming `maybe_some_string` @@ -1173,7 +1185,7 @@ // Entry-like operations to insert a value and return a reference ///////////////////////////////////////////////////////////////////////// - /// Inserts `value` into the option then returns a mutable reference to it. + /// Inserts `value` into the option, then returns a mutable reference to it. /// /// If the option already contains a value, the old value is dropped. /// @@ -1309,8 +1321,10 @@ /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn take(&mut self) -> Option { - mem::take(self) + #[rustc_const_unstable(feature = "const_option", issue = "67441")] + pub const fn take(&mut self) -> Option { + // FIXME replace `mem::replace` by `mem::take` when the latter is const ready + mem::replace(self, None) } /// Replaces the actual value in the option by the value given in parameter, @@ -1331,8 +1345,9 @@ /// assert_eq!(old, None); /// ``` #[inline] + #[rustc_const_unstable(feature = "const_option", issue = "67441")] #[stable(feature = "option_replace", since = "1.31.0")] - pub fn replace(&mut self, value: T) -> Option { + pub const fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } @@ -1397,7 +1412,7 @@ } impl Option<(T, U)> { - /// Unzips an option containing a tuple of two options + /// Unzips an option containing a tuple of two options. /// /// If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`. /// Otherwise, `(None, None)` is returned. @@ -1437,8 +1452,14 @@ /// assert_eq!(copied, Some(12)); /// ``` #[stable(feature = "copied", since = "1.35.0")] - pub fn copied(self) -> Option { - self.map(|&t| t) + #[rustc_const_unstable(feature = "const_option", issue = "67441")] + pub const fn copied(self) -> Option { + // FIXME: this implementation, which sidesteps using `Option::map` since it's not const + // ready yet, should be reverted when possible to avoid code repetition + match self { + Some(&v) => Some(v), + None => None, + } } } @@ -1455,6 +1476,7 @@ /// let copied = opt_x.copied(); /// assert_eq!(copied, Some(12)); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "copied", since = "1.35.0")] pub fn copied(self) -> Option { self.map(|&mut t| t) @@ -1474,6 +1496,7 @@ /// let cloned = opt_x.cloned(); /// assert_eq!(cloned, Some(12)); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] pub fn cloned(self) -> Option { self.map(|t| t.clone()) @@ -1500,7 +1523,7 @@ } impl Option { - /// Returns the contained [`Some`] value or a default + /// Returns the contained [`Some`] value or a default. /// /// Consumes the `self` argument then, if [`Some`], returns the contained /// value, otherwise if [`None`], returns the [default value] for that @@ -1561,7 +1584,7 @@ /// Converts from `Option` (or `&mut Option`) to `Option<&mut T::Target>`. /// /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to - /// the inner type's `Deref::Target` type. + /// the inner type's [`Deref::Target`] type. /// /// # Examples /// @@ -1581,9 +1604,9 @@ impl Option> { /// Transposes an `Option` of a [`Result`] into a [`Result`] of an `Option`. /// - /// [`None`] will be mapped to [`Ok`]`(`[`None`]`)`. - /// [`Some`]`(`[`Ok`]`(_))` and [`Some`]`(`[`Err`]`(_))` will be mapped to - /// [`Ok`]`(`[`Some`]`(_))` and [`Err`]`(_)`. + /// [`None`] will be mapped to [Ok]\([None]). + /// [Some]\([Ok]\(\_)) and [Some]\([Err]\(\_)) will be mapped to + /// [Ok]\([Some]\(\_)) and [Err]\(\_). /// /// # Examples /// @@ -1701,7 +1724,7 @@ #[stable(since = "1.12.0", feature = "option_from")] impl From for Option { - /// Copies `val` into a new `Some`. + /// Moves `val` into a new [`Some`]. /// /// # Examples /// @@ -1721,13 +1744,13 @@ /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. - /// The [`map`] method takes the `self` argument by value, consuming the original, - /// so this technique uses `from` to first take an `Option` to a reference + /// Converts an [Option]<[String]> into an [Option]<[usize]>, preserving + /// the original. The [`map`] method takes the `self` argument by value, consuming the original, + /// so this technique uses `from` to first take an [`Option`] to a reference /// to the value inside the original. /// /// [`map`]: Option::map - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// /// ``` /// let s: Option = Some(String::from("Hello, Rustaceans!")); @@ -1942,8 +1965,8 @@ impl> FromIterator> for Option { /// Takes each element in the [`Iterator`]: if it is [`None`][Option::None], /// no further elements are taken, and the [`None`][Option::None] is - /// returned. Should no [`None`][Option::None] occur, a container with the - /// values of each [`Option`] is returned. + /// returned. Should no [`None`][Option::None] occur, a container of type + /// `V` containing the values of each [`Option`] is returned. /// /// # Examples /// @@ -2039,7 +2062,7 @@ } impl Option> { - /// Converts from `Option>` to `Option` + /// Converts from `Option>` to `Option`. /// /// # Examples /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/panicking.rs rustc-1.57.0+dfsg1+llvm/library/core/src/panicking.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/panicking.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/panicking.rs 2021-11-29 19:27:11.000000000 +0000 @@ -47,15 +47,7 @@ // truncation and padding (even though none is used here). Using // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. - panic_fmt( - #[cfg(bootstrap)] - fmt::Arguments::new_v1(&[expr], &[]), - #[cfg(not(bootstrap))] - // SAFETY: Arguments::new_v1 is safe with exactly one str and zero args - unsafe { - fmt::Arguments::new_v1(&[expr], &[]) - }, - ); + panic_fmt(fmt::Arguments::new_v1(&[expr], &[])); } #[inline] @@ -65,6 +57,13 @@ panic_fmt(format_args!("{}", expr)); } +#[inline] +#[track_caller] +#[cfg_attr(not(bootstrap), lang = "panic_display")] // needed for const-evaluated panics +pub fn panic_display(x: &T) -> ! { + panic_fmt(format_args!("{}", *x)); +} + #[cold] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] @@ -82,7 +81,7 @@ #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[cfg_attr(not(bootstrap), lang = "panic_fmt")] // needed for const-evaluated panics +#[lang = "panic_fmt"] // needed for const-evaluated panics pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() @@ -102,7 +101,6 @@ } /// This function is used instead of panic_fmt in const eval. -#[cfg(not(bootstrap))] #[lang = "const_panic_fmt"] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/panic.rs rustc-1.57.0+dfsg1+llvm/library/core/src/panic.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/panic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/panic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -27,9 +27,14 @@ ($msg:literal $(,)?) => ( $crate::panicking::panic($msg) ), + // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint. ($msg:expr $(,)?) => ( $crate::panicking::panic_str($msg) ), + // Special-case the single-argument case for const_panic. + ("{}", $arg:expr $(,)?) => ( + $crate::panicking::panic_display(&$arg) + ), ($fmt:expr, $($arg:tt)+) => ( $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+)) ), @@ -44,6 +49,10 @@ () => ( $crate::panicking::panic("explicit panic") ), + // Special-case the single-argument case for const_panic. + ("{}", $arg:expr $(,)?) => ( + $crate::panicking::panic_display(&$arg) + ), ($($t:tt)+) => ( $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)) ), diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/pin.rs rustc-1.57.0+dfsg1+llvm/library/core/src/pin.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/pin.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/pin.rs 2021-11-29 19:27:11.000000000 +0000 @@ -368,15 +368,15 @@ //! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push" //! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc" //! [RefCell]: crate::cell::RefCell "cell::RefCell" -//! [`drop`]: Drop::drop "Drop::drop" +//! [`drop`]: Drop::drop //! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque" //! [`ptr::write`]: crate::ptr::write "ptr::write" //! [`Future`]: crate::future::Future "future::Future" //! [drop-impl]: #drop-implementation //! [drop-guarantee]: #drop-guarantee //! [`poll`]: crate::future::Future::poll "future::Future::poll" -//! [&]: ../../std/primitive.reference.html "shared reference" -//! [&mut]: ../../std/primitive.reference.html "mutable reference" +//! [&]: reference "shared reference" +//! [&mut]: reference "mutable reference" //! [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe" #![stable(feature = "pin", since = "1.33.0")] @@ -715,6 +715,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. #[inline(always)] + #[must_use = "`self` will be dropped if the result is not used"] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const fn into_ref(self) -> Pin<&'a T> { @@ -731,6 +732,7 @@ /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. #[inline(always)] + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const fn get_mut(self) -> &'a mut T @@ -751,6 +753,7 @@ /// If the underlying data is `Unpin`, `Pin::get_mut` should be used /// instead. #[inline(always)] + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { @@ -772,6 +775,7 @@ /// not move out of the argument you receive to the interior function. /// /// [`pin` module]: self#projections-and-structural-pinning + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked_mut(self, func: F) -> Pin<&'a mut U> where @@ -811,6 +815,7 @@ /// implementations of `P::DerefMut` are likewise ruled out by the contract of /// `Pin::new_unchecked`. #[unstable(feature = "pin_deref_mut", issue = "86918")] + #[must_use = "`self` will be dropped if the result is not used"] #[inline(always)] pub fn as_deref_mut(self) -> Pin<&'a mut P::Target> { // SAFETY: What we're asserting here is that going from diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/primitive_docs.rs rustc-1.57.0+dfsg1+llvm/library/core/src/primitive_docs.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/primitive_docs.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/primitive_docs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,1307 @@ +// `library/{std,core}/src/primitive_docs.rs` should have the same contents. +// These are different files so that relative links work properly without +// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same. +#[doc(primitive = "bool")] +#[doc(alias = "true")] +#[doc(alias = "false")] +/// The boolean type. +/// +/// The `bool` represents a value, which could only be either [`true`] or [`false`]. If you cast +/// a `bool` into an integer, [`true`] will be 1 and [`false`] will be 0. +/// +/// # Basic usage +/// +/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc., +/// which allow us to perform boolean operations using `&`, `|` and `!`. +/// +/// [`if`] requires a `bool` value as its conditional. [`assert!`], which is an +/// important macro in testing, checks whether an expression is [`true`] and panics +/// if it isn't. +/// +/// ``` +/// let bool_val = true & false | false; +/// assert!(!bool_val); +/// ``` +/// +/// [`true`]: ../std/keyword.true.html +/// [`false`]: ../std/keyword.false.html +/// [`BitAnd`]: ops::BitAnd +/// [`BitOr`]: ops::BitOr +/// [`Not`]: ops::Not +/// [`if`]: ../std/keyword.if.html +/// +/// # Examples +/// +/// A trivial example of the usage of `bool`: +/// +/// ``` +/// let praise_the_borrow_checker = true; +/// +/// // using the `if` conditional +/// if praise_the_borrow_checker { +/// println!("oh, yeah!"); +/// } else { +/// println!("what?!!"); +/// } +/// +/// // ... or, a match pattern +/// match praise_the_borrow_checker { +/// true => println!("keep praising!"), +/// false => println!("you should praise!"), +/// } +/// ``` +/// +/// Also, since `bool` implements the [`Copy`] trait, we don't +/// have to worry about the move semantics (just like the integer and float primitives). +/// +/// Now an example of `bool` cast to integer type: +/// +/// ``` +/// assert_eq!(true as i32, 1); +/// assert_eq!(false as i32, 0); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_bool {} + +#[doc(primitive = "never")] +#[doc(alias = "!")] +// +/// The `!` type, also called "never". +/// +/// `!` represents the type of computations which never resolve to any value at all. For example, +/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and +/// so returns `!`. +/// +/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to +/// write: +/// +/// ``` +/// #![feature(never_type)] +/// # fn foo() -> u32 { +/// let x: ! = { +/// return 123 +/// }; +/// # } +/// ``` +/// +/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never +/// assigned a value (because `return` returns from the entire function), `x` can be given type +/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code +/// would still be valid. +/// +/// A more realistic usage of `!` is in this code: +/// +/// ``` +/// # fn get_a_number() -> Option { None } +/// # loop { +/// let num: u32 = match get_a_number() { +/// Some(num) => num, +/// None => break, +/// }; +/// # } +/// ``` +/// +/// Both match arms must produce values of type [`u32`], but since `break` never produces a value +/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another +/// behaviour of the `!` type - expressions with type `!` will coerce into any other type. +/// +/// [`u32`]: prim@u32 +#[doc = concat!("[`exit`]: ", include_str!("../primitive_docs/process_exit.md"))] +/// +/// # `!` and generics +/// +/// ## Infallible errors +/// +/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`] +/// trait: +/// +/// ``` +/// trait FromStr: Sized { +/// type Err; +/// fn from_str(s: &str) -> Result; +/// } +/// ``` +/// +/// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since +/// converting a string into a string will never result in an error, the appropriate type is `!`. +/// (Currently the type actually used is an enum with no variants, though this is only because `!` +/// was added to Rust at a later date and it may change in the future.) With an [`Err`] type of +/// `!`, if we have to call [`String::from_str`] for some reason the result will be a +/// [`Result`] which we can unpack like this: +/// +/// ``` +/// #![feature(exhaustive_patterns)] +/// use std::str::FromStr; +/// let Ok(s) = String::from_str("hello"); +/// ``` +/// +/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` +/// feature is present this means we can exhaustively match on [`Result`] by just taking the +/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain +/// enum variants from generic types like `Result`. +/// +/// ## Infinite loops +/// +/// While [`Result`] is very useful for removing errors, `!` can also be used to remove +/// successes as well. If we think of [`Result`] as "if this function returns, it has not +/// errored," we get a very intuitive idea of [`Result`] as well: if the function returns, it +/// *has* errored. +/// +/// For example, consider the case of a simple web server, which can be simplified to: +/// +/// ```ignore (hypothetical-example) +/// loop { +/// let (client, request) = get_request().expect("disconnected"); +/// let response = request.process(); +/// response.send(client); +/// } +/// ``` +/// +/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection. +/// Instead, we'd like to keep track of this error, like this: +/// +/// ```ignore (hypothetical-example) +/// loop { +/// match get_request() { +/// Err(err) => break err, +/// Ok((client, request)) => { +/// let response = request.process(); +/// response.send(client); +/// }, +/// } +/// } +/// ``` +/// +/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it +/// might be intuitive to simply return the error, we might want to wrap it in a [`Result`] +/// instead: +/// +/// ```ignore (hypothetical-example) +/// fn server_loop() -> Result { +/// loop { +/// let (client, request) = get_request()?; +/// let response = request.process(); +/// response.send(client); +/// } +/// } +/// ``` +/// +/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop +/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok` +/// because `!` coerces to `Result` automatically. +/// +/// [`String::from_str`]: str::FromStr::from_str +#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] +/// [`FromStr`]: str::FromStr +/// +/// # `!` and traits +/// +/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` +/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!` +/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other +/// words, they can't return `!` from every code path. As an example, this code doesn't compile: +/// +/// ```compile_fail +/// use std::ops::Add; +/// +/// fn foo() -> impl Add { +/// unimplemented!() +/// } +/// ``` +/// +/// But this code does: +/// +/// ``` +/// use std::ops::Add; +/// +/// fn foo() -> impl Add { +/// if true { +/// unimplemented!() +/// } else { +/// 0 +/// } +/// } +/// ``` +/// +/// The reason is that, in the first example, there are many possible types that `!` could coerce +/// to, because many types implement `Add`. However, in the second example, +/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type +/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375] +/// for more information on this quirk of `!`. +/// +/// [#36375]: https://github.com/rust-lang/rust/issues/36375 +/// +/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`] +/// for example: +/// +/// ``` +/// #![feature(never_type)] +/// # use std::fmt; +/// # trait Debug { +/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; +/// # } +/// impl Debug for ! { +/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { +/// *self +/// } +/// } +/// ``` +/// +/// Once again we're using `!`'s ability to coerce into any other type, in this case +/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be +/// called (because there is no value of type `!` for it to be called with). Writing `*self` +/// essentially tells the compiler "We know that this code can never be run, so just treat the +/// entire function body as having type [`fmt::Result`]". This pattern can be used a lot when +/// implementing traits for `!`. Generally, any trait which only has methods which take a `self` +/// parameter should have such an impl. +/// +/// On the other hand, one trait which would not be appropriate to implement is [`Default`]: +/// +/// ``` +/// trait Default { +/// fn default() -> Self; +/// } +/// ``` +/// +/// Since `!` has no values, it has no default value either. It's true that we could write an +/// `impl` for this which simply panics, but the same is true for any type (we could `impl +/// Default` for (eg.) [`File`] by just making [`default()`] panic.) +/// +#[doc = concat!("[`File`]: ", include_str!("../primitive_docs/fs_file.md"))] +/// [`Debug`]: fmt::Debug +/// [`default()`]: Default::default +/// +#[unstable(feature = "never_type", issue = "35121")] +mod prim_never {} + +#[doc(primitive = "char")] +/// A character type. +/// +/// The `char` type represents a single character. More specifically, since +/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode +/// scalar value]', which is similar to, but not the same as, a '[Unicode code +/// point]'. +/// +/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value +/// [Unicode code point]: https://www.unicode.org/glossary/#code_point +/// +/// This documentation describes a number of methods and trait implementations on the +/// `char` type. For technical reasons, there is additional, separate +/// documentation in [the `std::char` module](char/index.html) as well. +/// +/// # Representation +/// +/// `char` is always four bytes in size. This is a different representation than +/// a given character would have as part of a [`String`]. For example: +/// +/// ``` +/// let v = vec!['h', 'e', 'l', 'l', 'o']; +/// +/// // five elements times four bytes for each element +/// assert_eq!(20, v.len() * std::mem::size_of::()); +/// +/// let s = String::from("hello"); +/// +/// // five elements times one byte per element +/// assert_eq!(5, s.len() * std::mem::size_of::()); +/// ``` +/// +#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] +/// +/// As always, remember that a human intuition for 'character' might not map to +/// Unicode's definitions. For example, despite looking similar, the 'é' +/// character is one Unicode code point while 'eÌ' is two Unicode code points: +/// +/// ``` +/// let mut chars = "é".chars(); +/// // U+00e9: 'latin small letter e with acute' +/// assert_eq!(Some('\u{00e9}'), chars.next()); +/// assert_eq!(None, chars.next()); +/// +/// let mut chars = "eÌ".chars(); +/// // U+0065: 'latin small letter e' +/// assert_eq!(Some('\u{0065}'), chars.next()); +/// // U+0301: 'combining acute accent' +/// assert_eq!(Some('\u{0301}'), chars.next()); +/// assert_eq!(None, chars.next()); +/// ``` +/// +/// This means that the contents of the first string above _will_ fit into a +/// `char` while the contents of the second string _will not_. Trying to create +/// a `char` literal with the contents of the second string gives an error: +/// +/// ```text +/// error: character literal may only contain one codepoint: 'eÌ' +/// let c = 'eÌ'; +/// ^^^ +/// ``` +/// +/// Another implication of the 4-byte fixed size of a `char` is that +/// per-`char` processing can end up using a lot more memory: +/// +/// ``` +/// let s = String::from("love: â¤ï¸"); +/// let v: Vec = s.chars().collect(); +/// +/// assert_eq!(12, std::mem::size_of_val(&s[..])); +/// assert_eq!(32, std::mem::size_of_val(&v[..])); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_char {} + +#[doc(primitive = "unit")] +#[doc(alias = "(")] +#[doc(alias = ")")] +#[doc(alias = "()")] +// +/// The `()` type, also called "unit". +/// +/// The `()` type has exactly one value `()`, and is used when there +/// is no other meaningful value that could be returned. `()` is most +/// commonly seen implicitly: functions without a `-> ...` implicitly +/// have return type `()`, that is, these are equivalent: +/// +/// ```rust +/// fn long() -> () {} +/// +/// fn short() {} +/// ``` +/// +/// The semicolon `;` can be used to discard the result of an +/// expression at the end of a block, making the expression (and thus +/// the block) evaluate to `()`. For example, +/// +/// ```rust +/// fn returns_i64() -> i64 { +/// 1i64 +/// } +/// fn returns_unit() { +/// 1i64; +/// } +/// +/// let is_i64 = { +/// returns_i64() +/// }; +/// let is_unit = { +/// returns_i64(); +/// }; +/// ``` +/// +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_unit {} + +#[doc(primitive = "pointer")] +#[doc(alias = "ptr")] +#[doc(alias = "*")] +#[doc(alias = "*const")] +#[doc(alias = "*mut")] +// +/// Raw, unsafe pointers, `*const T`, and `*mut T`. +/// +/// *[See also the `std::ptr` module](ptr).* +/// +/// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. +/// Raw pointers can be unaligned or [`null`]. However, when a raw pointer is +/// dereferenced (using the `*` operator), it must be non-null and aligned. +/// +/// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so +/// [`write`] must be used if the type has drop glue and memory is not already +/// initialized - otherwise `drop` would be called on the uninitialized memory. +/// +/// Use the [`null`] and [`null_mut`] functions to create null pointers, and the +/// [`is_null`] method of the `*const T` and `*mut T` types to check for null. +/// The `*const T` and `*mut T` types also define the [`offset`] method, for +/// pointer math. +/// +/// # Common ways to create raw pointers +/// +/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). +/// +/// ``` +/// let my_num: i32 = 10; +/// let my_num_ptr: *const i32 = &my_num; +/// let mut my_speed: i32 = 88; +/// let my_speed_ptr: *mut i32 = &mut my_speed; +/// ``` +/// +/// To get a pointer to a boxed value, dereference the box: +/// +/// ``` +/// let my_num: Box = Box::new(10); +/// let my_num_ptr: *const i32 = &*my_num; +/// let mut my_speed: Box = Box::new(88); +/// let my_speed_ptr: *mut i32 = &mut *my_speed; +/// ``` +/// +/// This does not take ownership of the original allocation +/// and requires no resource management later, +/// but you must not use the pointer after its lifetime. +/// +/// ## 2. Consume a box (`Box`). +/// +/// The [`into_raw`] function consumes a box and returns +/// the raw pointer. It doesn't destroy `T` or deallocate any memory. +/// +/// ``` +/// let my_speed: Box = Box::new(88); +/// let my_speed: *mut i32 = Box::into_raw(my_speed); +/// +/// // By taking ownership of the original `Box` though +/// // we are obligated to put it together later to be destroyed. +/// unsafe { +/// drop(Box::from_raw(my_speed)); +/// } +/// ``` +/// +/// Note that here the call to [`drop`] is for clarity - it indicates +/// that we are done with the given value and it should be destroyed. +/// +/// ## 3. Create it using `ptr::addr_of!` +/// +/// Instead of coercing a reference to a raw pointer, you can use the macros +/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`). +/// These macros allow you to create raw pointers to fields to which you cannot +/// create a reference (without causing undefined behaviour), such as an +/// unaligned field. This might be necessary if packed structs or uninitialized +/// memory is involved. +/// +/// ``` +/// #[derive(Debug, Default, Copy, Clone)] +/// #[repr(C, packed)] +/// struct S { +/// aligned: u8, +/// unaligned: u32, +/// } +/// let s = S::default(); +/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion +/// ``` +/// +/// ## 4. Get it from C. +/// +/// ``` +/// # #![feature(rustc_private)] +/// extern crate libc; +/// +/// use std::mem; +/// +/// unsafe { +/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; +/// if my_num.is_null() { +/// panic!("failed to allocate memory"); +/// } +/// libc::free(my_num as *mut libc::c_void); +/// } +/// ``` +/// +/// Usually you wouldn't literally use `malloc` and `free` from Rust, +/// but C APIs hand out a lot of pointers generally, so are a common source +/// of raw pointers in Rust. +/// +/// [`null`]: ptr::null +/// [`null_mut`]: ptr::null_mut +/// [`is_null`]: pointer::is_null +/// [`offset`]: pointer::offset +#[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))] +/// [`drop`]: mem::drop +/// [`write`]: ptr::write +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_pointer {} + +#[doc(primitive = "array")] +#[doc(alias = "[]")] +#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases +#[doc(alias = "[T; N]")] +/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the +/// non-negative compile-time constant size, `N`. +/// +/// There are two syntactic forms for creating an array: +/// +/// * A list with each element, i.e., `[x, y, z]`. +/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. +/// The type of `x` must be [`Copy`]. +/// +/// Note that `[expr; 0]` is allowed, and produces an empty array. +/// This will still evaluate `expr`, however, and immediately drop the resulting value, so +/// be mindful of side effects. +/// +/// Arrays of *any* size implement the following traits if the element type allows it: +/// +/// - [`Copy`] +/// - [`Clone`] +/// - [`Debug`] +/// - [`IntoIterator`] (implemented for `[T; N]`, `&[T; N]` and `&mut [T; N]`) +/// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] +/// - [`Hash`] +/// - [`AsRef`], [`AsMut`] +/// - [`Borrow`], [`BorrowMut`] +/// +/// Arrays of sizes from 0 to 32 (inclusive) implement the [`Default`] trait +/// if the element type allows it. As a stopgap, trait implementations are +/// statically generated up to size 32. +/// +/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on +/// an array. Indeed, this provides most of the API for working with arrays. +/// Slices have a dynamic size and do not coerce to arrays. +/// +/// You can move elements out of an array with a [slice pattern]. If you want +/// one element, see [`mem::replace`]. +/// +/// # Examples +/// +/// ``` +/// let mut array: [i32; 3] = [0; 3]; +/// +/// array[1] = 1; +/// array[2] = 2; +/// +/// assert_eq!([1, 2], &array[1..]); +/// +/// // This loop prints: 0 1 2 +/// for x in array { +/// print!("{} ", x); +/// } +/// ``` +/// +/// You can also iterate over reference to the array's elements: +/// +/// ``` +/// let array: [i32; 3] = [0; 3]; +/// +/// for x in &array { } +/// ``` +/// +/// You can use a [slice pattern] to move elements out of an array: +/// +/// ``` +/// fn move_away(_: String) { /* Do interesting things. */ } +/// +/// let [john, roa] = ["John".to_string(), "Roa".to_string()]; +/// move_away(john); +/// move_away(roa); +/// ``` +/// +/// # Editions +/// +/// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call +/// `array.into_iter()` auto-referenced into a [slice iterator](slice::iter). Right now, the old +/// behavior is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring +/// [`IntoIterator`] by value. In the future, the behavior on the 2015 and 2018 edition +/// might be made consistent to the behavior of later editions. +/// +/// ```rust,edition2018 +/// // Rust 2015 and 2018: +/// +/// # #![allow(array_into_iter)] // override our `deny(warnings)` +/// let array: [i32; 3] = [0; 3]; +/// +/// // This creates a slice iterator, producing references to each value. +/// for item in array.into_iter().enumerate() { +/// let (i, x): (usize, &i32) = item; +/// println!("array[{}] = {}", i, x); +/// } +/// +/// // The `array_into_iter` lint suggests this change for future compatibility: +/// for item in array.iter().enumerate() { +/// let (i, x): (usize, &i32) = item; +/// println!("array[{}] = {}", i, x); +/// } +/// +/// // You can explicitly iterate an array by value using +/// // `IntoIterator::into_iter` or `std::array::IntoIter::new`: +/// for item in IntoIterator::into_iter(array).enumerate() { +/// let (i, x): (usize, i32) = item; +/// println!("array[{}] = {}", i, x); +/// } +/// ``` +/// +/// Starting in the 2021 edition, `array.into_iter()` uses `IntoIterator` normally to iterate +/// by value, and `iter()` should be used to iterate by reference like previous editions. +/// +/// ```rust,edition2021 +/// // Rust 2021: +/// +/// let array: [i32; 3] = [0; 3]; +/// +/// // This iterates by reference: +/// for item in array.iter().enumerate() { +/// let (i, x): (usize, &i32) = item; +/// println!("array[{}] = {}", i, x); +/// } +/// +/// // This iterates by value: +/// for item in array.into_iter().enumerate() { +/// let (i, x): (usize, i32) = item; +/// println!("array[{}] = {}", i, x); +/// } +/// ``` +/// +/// Future language versions might start treating the `array.into_iter()` +/// syntax on editions 2015 and 2018 the same as on edition 2021. So code using +/// those older editions should still be written with this change in mind, to +/// prevent breakage in the future. The safest way to accomplish this is to +/// avoid the `into_iter` syntax on those editions. If an edition update is not +/// viable/desired, there are multiple alternatives: +/// * use `iter`, equivalent to the old behavior, creating references +/// * use [`IntoIterator::into_iter`], equivalent to the post-2021 behavior (Rust 1.53+) +/// * replace `for ... in array.into_iter() {` with `for ... in array {`, +/// equivalent to the post-2021 behavior (Rust 1.53+) +/// +/// ```rust,edition2018 +/// // Rust 2015 and 2018: +/// +/// let array: [i32; 3] = [0; 3]; +/// +/// // This iterates by reference: +/// for item in array.iter() { +/// let x: &i32 = item; +/// println!("{}", x); +/// } +/// +/// // This iterates by value: +/// for item in IntoIterator::into_iter(array) { +/// let x: i32 = item; +/// println!("{}", x); +/// } +/// +/// // This iterates by value: +/// for item in array { +/// let x: i32 = item; +/// println!("{}", x); +/// } +/// +/// // IntoIter can also start a chain. +/// // This iterates by value: +/// for item in IntoIterator::into_iter(array).enumerate() { +/// let (i, x): (usize, i32) = item; +/// println!("array[{}] = {}", i, x); +/// } +/// ``` +/// +/// [slice]: prim@slice +/// [`Debug`]: fmt::Debug +/// [`Hash`]: hash::Hash +/// [`Borrow`]: borrow::Borrow +/// [`BorrowMut`]: borrow::BorrowMut +/// [slice pattern]: ../reference/patterns.html#slice-patterns +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_array {} + +#[doc(primitive = "slice")] +#[doc(alias = "[")] +#[doc(alias = "]")] +#[doc(alias = "[]")] +/// A dynamically-sized view into a contiguous sequence, `[T]`. Contiguous here +/// means that elements are laid out so that every element is the same +/// distance from its neighbors. +/// +/// *[See also the `std::slice` module](crate::slice).* +/// +/// Slices are a view into a block of memory represented as a pointer and a +/// length. +/// +/// ``` +/// // slicing a Vec +/// let vec = vec![1, 2, 3]; +/// let int_slice = &vec[..]; +/// // coercing an array to a slice +/// let str_slice: &[&str] = &["one", "two", "three"]; +/// ``` +/// +/// Slices are either mutable or shared. The shared slice type is `&[T]`, +/// while the mutable slice type is `&mut [T]`, where `T` represents the element +/// type. For example, you can mutate the block of memory that a mutable slice +/// points to: +/// +/// ``` +/// let mut x = [1, 2, 3]; +/// let x = &mut x[..]; // Take a full slice of `x`. +/// x[1] = 7; +/// assert_eq!(x, &[1, 7, 3]); +/// ``` +/// +/// As slices store the length of the sequence they refer to, they have twice +/// the size of pointers to [`Sized`](marker/trait.Sized.html) types. +/// Also see the reference on +/// [dynamically sized types](../reference/dynamically-sized-types.html). +/// +/// ``` +/// # use std::rc::Rc; +/// let pointer_size = std::mem::size_of::<&u8>(); +/// assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>()); +/// assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>()); +/// assert_eq!(2 * pointer_size, std::mem::size_of::>()); +/// assert_eq!(2 * pointer_size, std::mem::size_of::>()); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_slice {} + +#[doc(primitive = "str")] +// +/// String slices. +/// +/// *[See also the `std::str` module](crate::str).* +/// +/// The `str` type, also called a 'string slice', is the most primitive string +/// type. It is usually seen in its borrowed form, `&str`. It is also the type +/// of string literals, `&'static str`. +/// +/// String slices are always valid UTF-8. +/// +/// # Examples +/// +/// String literals are string slices: +/// +/// ``` +/// let hello = "Hello, world!"; +/// +/// // with an explicit type annotation +/// let hello: &'static str = "Hello, world!"; +/// ``` +/// +/// They are `'static` because they're stored directly in the final binary, and +/// so will be valid for the `'static` duration. +/// +/// # Representation +/// +/// A `&str` is made up of two components: a pointer to some bytes, and a +/// length. You can look at these with the [`as_ptr`] and [`len`] methods: +/// +/// ``` +/// use std::slice; +/// use std::str; +/// +/// let story = "Once upon a time..."; +/// +/// let ptr = story.as_ptr(); +/// let len = story.len(); +/// +/// // story has nineteen bytes +/// assert_eq!(19, len); +/// +/// // We can re-build a str out of ptr and len. This is all unsafe because +/// // we are responsible for making sure the two components are valid: +/// let s = unsafe { +/// // First, we build a &[u8]... +/// let slice = slice::from_raw_parts(ptr, len); +/// +/// // ... and then convert that slice into a string slice +/// str::from_utf8(slice) +/// }; +/// +/// assert_eq!(s, Ok(story)); +/// ``` +/// +/// [`as_ptr`]: str::as_ptr +/// [`len`]: str::len +/// +/// Note: This example shows the internals of `&str`. `unsafe` should not be +/// used to get a string slice under normal circumstances. Use `as_str` +/// instead. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_str {} + +#[doc(primitive = "tuple")] +#[doc(alias = "(")] +#[doc(alias = ")")] +#[doc(alias = "()")] +// +/// A finite heterogeneous sequence, `(T, U, ..)`. +/// +/// Let's cover each of those in turn: +/// +/// Tuples are *finite*. In other words, a tuple has a length. Here's a tuple +/// of length `3`: +/// +/// ``` +/// ("hello", 5, 'c'); +/// ``` +/// +/// 'Length' is also sometimes called 'arity' here; each tuple of a different +/// length is a different, distinct type. +/// +/// Tuples are *heterogeneous*. This means that each element of the tuple can +/// have a different type. In that tuple above, it has the type: +/// +/// ``` +/// # let _: +/// (&'static str, i32, char) +/// # = ("hello", 5, 'c'); +/// ``` +/// +/// Tuples are a *sequence*. This means that they can be accessed by position; +/// this is called 'tuple indexing', and it looks like this: +/// +/// ```rust +/// let tuple = ("hello", 5, 'c'); +/// +/// assert_eq!(tuple.0, "hello"); +/// assert_eq!(tuple.1, 5); +/// assert_eq!(tuple.2, 'c'); +/// ``` +/// +/// The sequential nature of the tuple applies to its implementations of various +/// traits. For example, in [`PartialOrd`] and [`Ord`], the elements are compared +/// sequentially until the first non-equal set is found. +/// +/// For more about tuples, see [the book](../book/ch03-02-data-types.html#the-tuple-type). +/// +/// # Trait implementations +/// +/// If every type inside a tuple implements one of the following traits, then a +/// tuple itself also implements it. +/// +/// * [`Clone`] +/// * [`Copy`] +/// * [`PartialEq`] +/// * [`Eq`] +/// * [`PartialOrd`] +/// * [`Ord`] +/// * [`Debug`] +/// * [`Default`] +/// * [`Hash`] +/// +/// [`Debug`]: fmt::Debug +/// [`Hash`]: hash::Hash +/// +/// Due to a temporary restriction in Rust's type system, these traits are only +/// implemented on tuples of arity 12 or less. In the future, this may change. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let tuple = ("hello", 5, 'c'); +/// +/// assert_eq!(tuple.0, "hello"); +/// ``` +/// +/// Tuples are often used as a return type when you want to return more than +/// one value: +/// +/// ``` +/// fn calculate_point() -> (i32, i32) { +/// // Don't do a calculation, that's not the point of the example +/// (4, 5) +/// } +/// +/// let point = calculate_point(); +/// +/// assert_eq!(point.0, 4); +/// assert_eq!(point.1, 5); +/// +/// // Combining this with patterns can be nicer. +/// +/// let (x, y) = calculate_point(); +/// +/// assert_eq!(x, 4); +/// assert_eq!(y, 5); +/// ``` +/// +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_tuple {} + +#[doc(primitive = "f32")] +/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008). +/// +/// This type can represent a wide range of decimal numbers, like `3.5`, `27`, +/// `-113.75`, `0.0078125`, `34359738368`, `0`, `-1`. So unlike integer types +/// (such as `i32`), floating point types can represent non-integer numbers, +/// too. +/// +/// However, being able to represent this wide range of numbers comes at the +/// cost of precision: floats can only represent some of the real numbers and +/// calculation with floats round to a nearby representable number. For example, +/// `5.0` and `1.0` can be exactly represented as `f32`, but `1.0 / 5.0` results +/// in `0.20000000298023223876953125` since `0.2` cannot be exactly represented +/// as `f32`. Note, however, that printing floats with `println` and friends will +/// often discard insignificant digits: `println!("{}", 1.0f32 / 5.0f32)` will +/// print `0.2`. +/// +/// Additionally, `f32` can represent some special values: +/// +/// - −0.0: IEEE 754 floating point numbers have a bit that indicates their sign, so −0.0 is a +/// possible value. For comparison −0.0 = +0.0, but floating point operations can carry +/// the sign bit through arithmetic operations. This means −0.0 × +0.0 produces −0.0 and +/// a negative number rounded to a value smaller than a float can represent also produces −0.0. +/// - [∞](#associatedconstant.INFINITY) and +/// [−∞](#associatedconstant.NEG_INFINITY): these result from calculations +/// like `1.0 / 0.0`. +/// - [NaN (not a number)](#associatedconstant.NAN): this value results from +/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected +/// behavior: it is unequal to any float, including itself! It is also neither +/// smaller nor greater than any float, making it impossible to sort. Lastly, +/// it is considered infectious as almost all calculations where one of the +/// operands is NaN will also result in NaN. +/// +/// For more information on floating point numbers, see [Wikipedia][wikipedia]. +/// +/// *[See also the `std::f32::consts` module](crate::f32::consts).* +/// +/// [wikipedia]: https://en.wikipedia.org/wiki/Single-precision_floating-point_format +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_f32 {} + +#[doc(primitive = "f64")] +/// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008). +/// +/// This type is very similar to [`f32`], but has increased +/// precision by using twice as many bits. Please see [the documentation for +/// `f32`][`f32`] or [Wikipedia on double precision +/// values][wikipedia] for more information. +/// +/// *[See also the `std::f64::consts` module](crate::f64::consts).* +/// +/// [`f32`]: prim@f32 +/// [wikipedia]: https://en.wikipedia.org/wiki/Double-precision_floating-point_format +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_f64 {} + +#[doc(primitive = "i8")] +// +/// The 8-bit signed integer type. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_i8 {} + +#[doc(primitive = "i16")] +// +/// The 16-bit signed integer type. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_i16 {} + +#[doc(primitive = "i32")] +// +/// The 32-bit signed integer type. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_i32 {} + +#[doc(primitive = "i64")] +// +/// The 64-bit signed integer type. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_i64 {} + +#[doc(primitive = "i128")] +// +/// The 128-bit signed integer type. +#[stable(feature = "i128", since = "1.26.0")] +mod prim_i128 {} + +#[doc(primitive = "u8")] +// +/// The 8-bit unsigned integer type. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_u8 {} + +#[doc(primitive = "u16")] +// +/// The 16-bit unsigned integer type. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_u16 {} + +#[doc(primitive = "u32")] +// +/// The 32-bit unsigned integer type. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_u32 {} + +#[doc(primitive = "u64")] +// +/// The 64-bit unsigned integer type. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_u64 {} + +#[doc(primitive = "u128")] +// +/// The 128-bit unsigned integer type. +#[stable(feature = "i128", since = "1.26.0")] +mod prim_u128 {} + +#[doc(primitive = "isize")] +// +/// The pointer-sized signed integer type. +/// +/// The size of this primitive is how many bytes it takes to reference any +/// location in memory. For example, on a 32 bit target, this is 4 bytes +/// and on a 64 bit target, this is 8 bytes. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_isize {} + +#[doc(primitive = "usize")] +// +/// The pointer-sized unsigned integer type. +/// +/// The size of this primitive is how many bytes it takes to reference any +/// location in memory. For example, on a 32 bit target, this is 4 bytes +/// and on a 64 bit target, this is 8 bytes. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_usize {} + +#[doc(primitive = "reference")] +#[doc(alias = "&")] +#[doc(alias = "&mut")] +// +/// References, both shared and mutable. +/// +/// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` +/// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or +/// [ref](../std/keyword.ref.html) [mut](../std/keyword.mut.html) pattern. +/// +/// For those familiar with pointers, a reference is just a pointer that is assumed to be +/// aligned, not null, and pointing to memory containing a valid value of `T` - for example, +/// &[bool] can only point to an allocation containing the integer values `1` +/// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but +/// creating a &[bool] that points to an allocation containing +/// the value `3` causes undefined behaviour. +/// In fact, [Option]\<&T> has the same memory representation as a +/// nullable but aligned pointer, and can be passed across FFI boundaries as such. +/// +/// In most cases, references can be used much like the original value. Field access, method +/// calling, and indexing work the same (save for mutability rules, of course). In addition, the +/// comparison operators transparently defer to the referent's implementation, allowing references +/// to be compared the same as owned values. +/// +/// References have a lifetime attached to them, which represents the scope for which the borrow is +/// valid. A lifetime is said to "outlive" another one if its representative scope is as long or +/// longer than the other. The `'static` lifetime is the longest lifetime, which represents the +/// total life of the program. For example, string literals have a `'static` lifetime because the +/// text data is embedded into the binary of the program, rather than in an allocation that needs +/// to be dynamically managed. +/// +/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and +/// references with longer lifetimes can be freely coerced into references with shorter ones. +/// +/// Reference equality by address, instead of comparing the values pointed to, is accomplished via +/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while +/// [`PartialEq`] compares values. +/// +/// ``` +/// use std::ptr; +/// +/// let five = 5; +/// let other_five = 5; +/// let five_ref = &five; +/// let same_five_ref = &five; +/// let other_five_ref = &other_five; +/// +/// assert!(five_ref == same_five_ref); +/// assert!(five_ref == other_five_ref); +/// +/// assert!(ptr::eq(five_ref, same_five_ref)); +/// assert!(!ptr::eq(five_ref, other_five_ref)); +/// ``` +/// +/// For more information on how to use references, see [the book's section on "References and +/// Borrowing"][book-refs]. +/// +/// [book-refs]: ../book/ch04-02-references-and-borrowing.html +/// +/// # Trait implementations +/// +/// The following traits are implemented for all `&T`, regardless of the type of its referent: +/// +/// * [`Copy`] +/// * [`Clone`] \(Note that this will not defer to `T`'s `Clone` implementation if it exists!) +/// * [`Deref`] +/// * [`Borrow`] +/// * [`Pointer`] +/// +/// [`Deref`]: ops::Deref +/// [`Borrow`]: borrow::Borrow +/// [`Pointer`]: fmt::Pointer +/// +/// `&mut T` references get all of the above except `Copy` and `Clone` (to prevent creating +/// multiple simultaneous mutable borrows), plus the following, regardless of the type of its +/// referent: +/// +/// * [`DerefMut`] +/// * [`BorrowMut`] +/// +/// [`DerefMut`]: ops::DerefMut +/// [`BorrowMut`]: borrow::BorrowMut +/// [bool]: prim@bool +/// +/// The following traits are implemented on `&T` references if the underlying `T` also implements +/// that trait: +/// +/// * All the traits in [`std::fmt`] except [`Pointer`] and [`fmt::Write`] +/// * [`PartialOrd`] +/// * [`Ord`] +/// * [`PartialEq`] +/// * [`Eq`] +/// * [`AsRef`] +/// * [`Fn`] \(in addition, `&T` references get [`FnMut`] and [`FnOnce`] if `T: Fn`) +/// * [`Hash`] +/// * [`ToSocketAddrs`] +/// +/// [`std::fmt`]: fmt +/// ['Pointer`]: fmt::Pointer +/// [`Hash`]: hash::Hash +#[doc = concat!("[`ToSocketAddrs`]: ", include_str!("../primitive_docs/net_tosocketaddrs.md"))] +/// +/// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T` +/// implements that trait: +/// +/// * [`AsMut`] +/// * [`FnMut`] \(in addition, `&mut T` references get [`FnOnce`] if `T: FnMut`) +/// * [`fmt::Write`] +/// * [`Iterator`] +/// * [`DoubleEndedIterator`] +/// * [`ExactSizeIterator`] +/// * [`FusedIterator`] +/// * [`TrustedLen`] +/// * [`Send`] \(note that `&T` references only get `Send` if T: [Sync]) +/// * [`io::Write`] +/// * [`Read`] +/// * [`Seek`] +/// * [`BufRead`] +/// +/// [`FusedIterator`]: iter::FusedIterator +/// [`TrustedLen`]: iter::TrustedLen +#[doc = concat!("[`Seek`]: ", include_str!("../primitive_docs/io_seek.md"))] +#[doc = concat!("[`BufRead`]: ", include_str!("../primitive_docs/io_bufread.md"))] +#[doc = concat!("[`Read`]: ", include_str!("../primitive_docs/io_read.md"))] +#[doc = concat!("[`io::Write`]: ", include_str!("../primitive_docs/io_write.md"))] +/// +/// Note that due to method call deref coercion, simply calling a trait method will act like they +/// work on references as well as they do on owned values! The implementations described here are +/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not +/// locally known. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_ref {} + +#[doc(primitive = "fn")] +// +/// Function pointers, like `fn(usize) -> bool`. +/// +/// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].* +/// +/// [`Fn`]: ops::Fn +/// [`FnMut`]: ops::FnMut +/// [`FnOnce`]: ops::FnOnce +/// +/// Function pointers are pointers that point to *code*, not data. They can be called +/// just like functions. Like references, function pointers are, among other things, assumed to +/// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null +/// pointers, make your type [`Option`](core::option#options-and-pointers-nullable-pointers) +/// with your required signature. +/// +/// ### Safety +/// +/// Plain function pointers are obtained by casting either plain functions, or closures that don't +/// capture an environment: +/// +/// ``` +/// fn add_one(x: usize) -> usize { +/// x + 1 +/// } +/// +/// let ptr: fn(usize) -> usize = add_one; +/// assert_eq!(ptr(5), 6); +/// +/// let clos: fn(usize) -> usize = |x| x + 5; +/// assert_eq!(clos(5), 10); +/// ``` +/// +/// In addition to varying based on their signature, function pointers come in two flavors: safe +/// and unsafe. Plain `fn()` function pointers can only point to safe functions, +/// while `unsafe fn()` function pointers can point to safe or unsafe functions. +/// +/// ``` +/// fn add_one(x: usize) -> usize { +/// x + 1 +/// } +/// +/// unsafe fn add_one_unsafely(x: usize) -> usize { +/// x + 1 +/// } +/// +/// let safe_ptr: fn(usize) -> usize = add_one; +/// +/// //ERROR: mismatched types: expected normal fn, found unsafe fn +/// //let bad_ptr: fn(usize) -> usize = add_one_unsafely; +/// +/// let unsafe_ptr: unsafe fn(usize) -> usize = add_one_unsafely; +/// let really_safe_ptr: unsafe fn(usize) -> usize = add_one; +/// ``` +/// +/// ### ABI +/// +/// On top of that, function pointers can vary based on what ABI they use. This +/// is achieved by adding the `extern` keyword before the type, followed by the +/// ABI in question. The default ABI is "Rust", i.e., `fn()` is the exact same +/// type as `extern "Rust" fn()`. A pointer to a function with C ABI would have +/// type `extern "C" fn()`. +/// +/// `extern "ABI" { ... }` blocks declare functions with ABI "ABI". The default +/// here is "C", i.e., functions declared in an `extern {...}` block have "C" +/// ABI. +/// +/// For more information and a list of supported ABIs, see [the nomicon's +/// section on foreign calling conventions][nomicon-abi]. +/// +/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions +/// +/// ### Variadic functions +/// +/// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them +/// to be called with a variable number of arguments. Normal Rust functions, even those with an +/// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on +/// variadic functions][nomicon-variadic]. +/// +/// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions +/// +/// ### Creating function pointers +/// +/// When `bar` is the name of a function, then the expression `bar` is *not* a +/// function pointer. Rather, it denotes a value of an unnameable type that +/// uniquely identifies the function `bar`. The value is zero-sized because the +/// type already identifies the function. This has the advantage that "calling" +/// the value (it implements the `Fn*` traits) does not require dynamic +/// dispatch. +/// +/// This zero-sized type *coerces* to a regular function pointer. For example: +/// +/// ```rust +/// use std::mem; +/// +/// fn bar(x: i32) {} +/// +/// let not_bar_ptr = bar; // `not_bar_ptr` is zero-sized, uniquely identifying `bar` +/// assert_eq!(mem::size_of_val(¬_bar_ptr), 0); +/// +/// let bar_ptr: fn(i32) = not_bar_ptr; // force coercion to function pointer +/// assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::()); +/// +/// let footgun = &bar; // this is a shared reference to the zero-sized type identifying `bar` +/// ``` +/// +/// The last line shows that `&bar` is not a function pointer either. Rather, it +/// is a reference to the function-specific ZST. `&bar` is basically never what you +/// want when `bar` is a function. +/// +/// ### Traits +/// +/// Function pointers implement the following traits: +/// +/// * [`Clone`] +/// * [`PartialEq`] +/// * [`Eq`] +/// * [`PartialOrd`] +/// * [`Ord`] +/// * [`Hash`] +/// * [`Pointer`] +/// * [`Debug`] +/// +/// [`Hash`]: hash::Hash +/// [`Pointer`]: fmt::Pointer +/// +/// Due to a temporary restriction in Rust's type system, these traits are only implemented on +/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this +/// may change. +/// +/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe* +/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits +/// are specially known to the compiler. +#[stable(feature = "rust1", since = "1.0.0")] +mod prim_fn {} diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/ptr/non_null.rs rustc-1.57.0+dfsg1+llvm/library/core/src/ptr/non_null.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/ptr/non_null.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/ptr/non_null.rs 2021-11-29 19:27:11.000000000 +0000 @@ -119,6 +119,7 @@ /// /// [the module documentation]: crate::ptr#safety #[inline] + #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_ref<'a>(&self) -> &'a MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the @@ -151,6 +152,7 @@ /// /// [the module documentation]: crate::ptr#safety #[inline] + #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_mut<'a>(&mut self) -> &'a mut MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the @@ -240,6 +242,8 @@ /// The pointer can be later reconstructed with [`NonNull::from_raw_parts`]. #[unstable(feature = "ptr_metadata", issue = "81513")] #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_raw_parts(self) -> (NonNull<()>, ::Metadata) { (self.cast(), super::metadata(self.as_ptr())) @@ -264,6 +268,7 @@ /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")] + #[must_use] #[inline] pub const fn as_ptr(self) -> *mut T { self.pointer as *mut T @@ -310,6 +315,7 @@ /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] + #[must_use] #[inline] pub unsafe fn as_ref<'a>(&self) -> &'a T { // SAFETY: the caller must guarantee that `self` meets all the @@ -359,6 +365,7 @@ /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] + #[must_use] #[inline] pub unsafe fn as_mut<'a>(&mut self) -> &'a mut T { // SAFETY: the caller must guarantee that `self` meets all the @@ -381,6 +388,8 @@ /// ``` #[stable(feature = "nonnull_cast", since = "1.27.0")] #[rustc_const_stable(feature = "const_nonnull_cast", since = "1.36.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn cast(self) -> NonNull { // SAFETY: `self` is a `NonNull` pointer which is necessarily non-null @@ -455,6 +464,7 @@ /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap()); /// ``` #[inline] + #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] pub const fn as_non_null_ptr(self) -> NonNull { @@ -474,6 +484,7 @@ /// assert_eq!(slice.as_mut_ptr(), 1 as *mut i8); /// ``` #[inline] + #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] pub const fn as_mut_ptr(self) -> *mut T { @@ -518,6 +529,7 @@ /// /// [valid]: crate::ptr#safety #[inline] + #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_slice<'a>(&self) -> &'a [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice`. @@ -579,6 +591,7 @@ /// # Ok::<_, std::alloc::AllocError>(()) /// ``` #[inline] + #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_slice_mut<'a>(&self) -> &'a mut [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice_mut`. diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/ptr/unique.rs rustc-1.57.0+dfsg1+llvm/library/core/src/ptr/unique.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/ptr/unique.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/ptr/unique.rs 2021-11-29 19:27:11.000000000 +0000 @@ -101,6 +101,7 @@ } /// Acquires the underlying `*mut` pointer. + #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub const fn as_ptr(self) -> *mut T { self.pointer as *mut T @@ -111,6 +112,7 @@ /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. + #[must_use] #[inline] pub unsafe fn as_ref(&self) -> &T { // SAFETY: the caller must guarantee that `self` meets all the @@ -123,6 +125,7 @@ /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. + #[must_use] #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` meets all the @@ -131,6 +134,7 @@ } /// Casts to a pointer of another type. + #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub const fn cast(self) -> Unique { // SAFETY: Unique::new_unchecked() creates a new unique and needs diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/result.rs rustc-1.57.0+dfsg1+llvm/library/core/src/result.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/result.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/result.rs 2021-11-29 19:27:11.000000000 +0000 @@ -88,7 +88,7 @@ //! ``` //! //! *Note: The actual definition of [`Write`] uses [`io::Result`], which -//! is just a synonym for [`Result`]``.* +//! is just a synonym for [Result].* //! //! This method doesn't produce a value, but the write may //! fail. It's crucial to handle the error case, and *not* write @@ -217,13 +217,13 @@ //! early return of [`Err`] that it provides. //! //! [`expect`]: Result::expect -//! [`Write`]: ../../std/io/trait.Write.html -//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all -//! [`io::Result`]: ../../std/io/type.Result.html +//! [`Write`]: ../../std/io/trait.Write.html "io::Write" +//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all "io::Write::write_all" +//! [`io::Result`]: ../../std/io/type.Result.html "io::Result" //! [`?`]: crate::ops::Try //! [`Ok(T)`]: Ok //! [`Err(E)`]: Err -//! [`io::Error`]: ../../std/io/struct.Error.html +//! [io::Error]: ../../std/io/struct.Error.html "io::Error" //! //! # Method overview //! @@ -329,8 +329,8 @@ //! [`Ok`], or returns the provided default value if the [`Result`] is //! [`Err`] //! * [`map_or_else`] applies the provided function to the contained value -//! of [`Ok`], or applies the provided fallback function to the contained -//! value of [`Err`] +//! of [`Ok`], or applies the provided default fallback function to the +//! contained value of [`Err`] //! //! [`map_or`]: Result::map_or //! [`map_or_else`]: Result::map_or_else @@ -498,7 +498,7 @@ /// See the [module documentation](self) for details. #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] -#[rustc_diagnostic_item = "result_type"] +#[rustc_diagnostic_item = "Result"] #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { /// Contains the success value @@ -795,9 +795,8 @@ } } - /// Maps a `Result` to `U` by applying a fallback function to a - /// contained [`Err`] value, or a default function to a - /// contained [`Ok`] value. + /// Maps a `Result` to `U` by applying fallback function `default` to + /// a contained [`Err`] value, or function `f` to a contained [`Ok`] value. /// /// This function can be used to unpack a successful result /// while handling an error. diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/slice/ascii.rs rustc-1.57.0+dfsg1+llvm/library/core/src/slice/ascii.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/slice/ascii.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/slice/ascii.rs 2021-11-29 19:27:11.000000000 +0000 @@ -72,6 +72,8 @@ /// let escaped = s.escape_ascii().to_string(); /// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d"); /// ``` + #[must_use = "this returns the escaped bytes as an iterator, \ + without modifying the original"] #[unstable(feature = "inherent_ascii_escape", issue = "77174")] pub fn escape_ascii(&self) -> EscapeAscii<'_> { EscapeAscii { inner: self.iter().flat_map(EscapeByte) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/slice/iter.rs rustc-1.57.0+dfsg1+llvm/library/core/src/slice/iter.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/slice/iter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/slice/iter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -124,6 +124,7 @@ /// // Now `as_slice` returns "[2, 3]": /// println!("{:?}", iter.as_slice()); /// ``` + #[must_use] #[stable(feature = "iter_to_slice", since = "1.4.0")] pub fn as_slice(&self) -> &'a [T] { self.make_slice() @@ -267,6 +268,7 @@ /// // Now slice is "[2, 2, 3]": /// println!("{:?}", slice); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "iter_to_slice", since = "1.4.0")] pub fn into_slice(self) -> &'a mut [T] { // SAFETY: the iterator was created from a mutable slice with pointer @@ -297,6 +299,7 @@ /// // Now `as_slice` returns "[2, 3]": /// assert_eq!(iter.as_slice(), &[2, 3]); /// ``` + #[must_use] #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] pub fn as_slice(&self) -> &[T] { self.make_slice() @@ -1869,6 +1872,7 @@ /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "chunks_exact", since = "1.31.0")] pub fn into_remainder(self) -> &'a mut [T] { self.rem @@ -2264,6 +2268,7 @@ /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `N-1` /// elements. + #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "array_chunks", issue = "74985")] pub fn into_remainder(self) -> &'a mut [T] { self.rem @@ -2875,6 +2880,7 @@ /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rchunks", since = "1.31.0")] pub fn into_remainder(self) -> &'a mut [T] { self.rem diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/slice/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/slice/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/slice/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/slice/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -98,7 +98,6 @@ #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_union))] pub const fn len(&self) -> usize { // FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable. // As of this writing this causes a "Const-stable functions can only call other @@ -561,15 +560,52 @@ #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn swap(&mut self, a: usize, b: usize) { - // Can't take two mutable loans from one vector, so instead use raw pointers. - let pa = ptr::addr_of_mut!(self[a]); - let pb = ptr::addr_of_mut!(self[b]); - // SAFETY: `pa` and `pb` have been created from safe mutable references and refer - // to elements in the slice and therefore are guaranteed to be valid and aligned. - // Note that accessing the elements behind `a` and `b` is checked and will - // panic when out of bounds. + let _ = &self[a]; + let _ = &self[b]; + + // SAFETY: we just checked that both `a` and `b` are in bounds + unsafe { self.swap_unchecked(a, b) } + } + + /// Swaps two elements in the slice, without doing bounds checking. + /// + /// For a safe alternative see [`swap`]. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]*. + /// The caller has to ensure that `a < self.len()` and `b < self.len()`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_swap_unchecked)] + /// + /// let mut v = ["a", "b", "c", "d"]; + /// // SAFETY: we know that 1 and 3 are both indices of the slice + /// unsafe { v.swap_unchecked(1, 3) }; + /// assert!(v == ["a", "d", "c", "b"]); + /// ``` + /// + /// [`swap`]: slice::swap + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_swap_unchecked", issue = "88539")] + pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { + #[cfg(debug_assertions)] + { + let _ = &self[a]; + let _ = &self[b]; + } + + let ptr = self.as_mut_ptr(); + // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` unsafe { - ptr::swap(pa, pb); + ptr::swap(ptr.add(a), ptr.add(b)); } } @@ -676,11 +712,7 @@ // The resulting pointers `pa` and `pb` are therefore valid and // aligned, and can be read from and written to. unsafe { - // Unsafe swap to avoid the bounds check in safe swap. - let ptr = self.as_mut_ptr(); - let pa = ptr.add(i); - let pb = ptr.add(ln - i - 1); - ptr::swap(pa, pb); + self.swap_unchecked(i, ln - i - 1); } i += 1; } @@ -1557,7 +1589,7 @@ /// /// # Examples /// - /// ```compile_fail + /// ``` /// #![feature(slice_split_at_unchecked)] /// /// let v = [1, 2, 3, 4, 5, 6]; @@ -1582,7 +1614,7 @@ /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] #[inline] - unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { // SAFETY: Caller has to check that `0 <= mid <= self.len()` unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) } } @@ -1606,7 +1638,7 @@ /// /// # Examples /// - /// ```compile_fail + /// ``` /// #![feature(slice_split_at_unchecked)] /// /// let mut v = [1, 0, 3, 0, 5, 6]; @@ -1622,7 +1654,7 @@ /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] #[inline] - unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { let len = self.len(); let ptr = self.as_mut_ptr(); @@ -2258,9 +2290,9 @@ /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` // Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is - // in crate `alloc`, and as such doesn't exists yet when building `core`. - // links to downstream crate: #74481. Since primitives are only documented in - // libstd (#73423), this never leads to broken links in practice. + // in crate `alloc`, and as such doesn't exists yet when building `core`: #74481. + // This breaks links when slice is displayed in core, but changing it to use relative links + // would break when the item is re-exported. So allow the core links to be broken for now. #[allow(rustdoc::broken_intra_doc_links)] #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/slice/sort.rs rustc-1.57.0+dfsg1+llvm/library/core/src/slice/sort.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/slice/sort.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/slice/sort.rs 2021-11-29 19:27:11.000000000 +0000 @@ -6,8 +6,6 @@ //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our //! stable sorting implementation. -// ignore-tidy-undocumented-unsafe - use crate::cmp; use crate::mem::{self, MaybeUninit}; use crate::ptr; @@ -291,6 +289,9 @@ } else if start_r < end_r { block_l = rem; } else { + // There were the same number of elements to switch on both blocks during the last + // iteration, so there are no remaining elements on either block. Cover the remaining + // items with roughly equally-sized blocks. block_l = rem / 2; block_r = rem - block_l; } @@ -437,6 +438,17 @@ // Move its remaining out-of-order elements to the far right. debug_assert_eq!(width(l, r), block_l); while start_l < end_l { + // remaining-elements-safety + // SAFETY: while the loop condition holds there are still elements in `offsets_l`, so it + // is safe to point `end_l` to the previous element. + // + // The `ptr::swap` is safe if both its arguments are valid for reads and writes: + // - Per the debug assert above, the distance between `l` and `r` is `block_l` + // elements, so there can be at most `block_l` remaining offsets between `start_l` + // and `end_l`. This means `r` will be moved at most `block_l` steps back, which + // makes the `r.offset` calls valid (at that point `l == r`). + // - `offsets_l` contains valid offsets into `v` collected during the partitioning of + // the last block, so the `l.offset` calls are valid. unsafe { end_l = end_l.offset(-1); ptr::swap(l.offset(*end_l as isize), r.offset(-1)); @@ -449,6 +461,7 @@ // Move its remaining out-of-order elements to the far left. debug_assert_eq!(width(l, r), block_r); while start_r < end_r { + // SAFETY: See the reasoning in [remaining-elements-safety]. unsafe { end_r = end_r.offset(-1); ptr::swap(l, r.offset(-(*end_r as isize) - 1)); @@ -481,6 +494,8 @@ // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. + + // SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe. let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot }; let pivot = &*tmp; @@ -646,6 +661,12 @@ if len >= 8 { // Swaps indices so that `v[a] <= v[b]`. + // SAFETY: `len >= 8` so there are at least two elements in the neighborhoods of + // `a`, `b` and `c`. This means the three calls to `sort_adjacent` result in + // corresponding calls to `sort3` with valid 3-item neighborhoods around each + // pointer, which in turn means the calls to `sort2` are done with valid + // references. Thus the `v.get_unchecked` calls are safe, as is the `ptr::swap` + // call. let mut sort2 = |a: &mut usize, b: &mut usize| unsafe { if is_less(v.get_unchecked(*b), v.get_unchecked(*a)) { ptr::swap(a, b); diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/str/converts.rs rustc-1.57.0+dfsg1+llvm/library/core/src/str/converts.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/str/converts.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/str/converts.rs 2021-11-29 19:27:11.000000000 +0000 @@ -155,9 +155,9 @@ /// assert_eq!("💖", sparkle_heart); /// ``` #[inline] +#[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] -#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. @@ -182,6 +182,7 @@ /// assert_eq!("💖", heart); /// ``` #[inline] +#[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/str/iter.rs rustc-1.57.0+dfsg1+llvm/library/core/src/str/iter.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/str/iter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/str/iter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -109,6 +109,7 @@ /// assert_eq!(chars.as_str(), ""); /// ``` #[stable(feature = "iter_to_slice", since = "1.4.0")] + #[must_use] #[inline] pub fn as_str(&self) -> &'a str { // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8. @@ -185,6 +186,7 @@ /// This has the same lifetime as the original slice, and so the /// iterator can continue to be used while this exists. #[stable(feature = "iter_to_slice", since = "1.4.0")] + #[must_use] #[inline] pub fn as_str(&self) -> &'a str { self.iter.as_str() @@ -1247,6 +1249,7 @@ /// assert_eq!(split.as_str(), ""); /// ``` #[inline] + #[must_use] #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.inner.iter.as_str() @@ -1302,6 +1305,7 @@ /// assert_eq!(split.as_str(), ""); /// ``` #[inline] + #[must_use] #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { if self.inner.iter.iter.finished { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/str/lossy.rs rustc-1.57.0+dfsg1+llvm/library/core/src/str/lossy.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/str/lossy.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/str/lossy.rs 2021-11-29 19:27:11.000000000 +0000 @@ -12,10 +12,12 @@ } impl Utf8Lossy { + #[must_use] pub fn from_str(s: &str) -> &Utf8Lossy { Utf8Lossy::from_bytes(s.as_bytes()) } + #[must_use] pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { // SAFETY: Both use the same memory layout, and UTF-8 correctness isn't required. unsafe { mem::transmute(bytes) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/str/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/str/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/str/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/str/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -188,6 +188,7 @@ /// // third byte of `è€` /// assert!(!s.is_char_boundary(8)); /// ``` + #[must_use] #[stable(feature = "is_char_boundary", since = "1.9.0")] #[inline] pub fn is_char_boundary(&self, index: usize) -> bool { @@ -229,9 +230,9 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "str_as_bytes", since = "1.39.0")] + #[must_use] #[inline(always)] #[allow(unused_attributes)] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] pub const fn as_bytes(&self) -> &[u8] { // SAFETY: const sound because we transmute two types with the same layout unsafe { mem::transmute(self) } @@ -274,6 +275,7 @@ /// assert_eq!("ðŸ”∈ðŸŒ", s); /// ``` #[stable(feature = "str_mut_extras", since = "1.20.0")] + #[must_use] #[inline(always)] pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { // SAFETY: the cast from `&str` to `&[u8]` is safe since `str` @@ -304,6 +306,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] + #[must_use] #[inline] pub const fn as_ptr(&self) -> *const u8 { self as *const str as *const u8 @@ -318,6 +321,7 @@ /// It is your responsibility to make sure that the string slice only gets /// modified in a way that it remains valid UTF-8. #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] + #[must_use] #[inline] pub fn as_mut_ptr(&mut self) -> *mut u8 { self as *mut str as *mut u8 @@ -799,6 +803,8 @@ /// /// assert_eq!(None, iter.next()); /// ``` + #[must_use = "this returns the split string as an iterator, \ + without modifying the original"] #[stable(feature = "split_whitespace", since = "1.1.0")] #[inline] pub fn split_whitespace(&self) -> SplitWhitespace<'_> { @@ -840,6 +846,8 @@ /// /// assert_eq!(None, iter.next()); /// ``` + #[must_use = "this returns the split string as an iterator, \ + without modifying the original"] #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] #[inline] pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> { @@ -915,6 +923,8 @@ /// /// assert!(utf16_len <= utf8_len); /// ``` + #[must_use = "this returns the encoded string as an iterator, \ + without modifying the original"] #[stable(feature = "encode_utf16", since = "1.8.0")] pub fn encode_utf16(&self) -> EncodeUtf16<'_> { EncodeUtf16 { chars: self.chars(), extra: 0 } @@ -1354,6 +1364,9 @@ /// /// let v: Vec<&str> = "A..B..".split_terminator(".").collect(); /// assert_eq!(v, ["A", "", "B", ""]); + /// + /// let v: Vec<&str> = "A.B:C.D".split_terminator(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["A", "B", "C", "D"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1397,6 +1410,9 @@ /// /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect(); /// assert_eq!(v, ["", "B", "", "A"]); + /// + /// let v: Vec<&str> = "A.B:C.D".rsplit_terminator(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["D", "C", "B", "A"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1525,7 +1541,8 @@ #[inline] pub fn split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> { let (start, end) = delimiter.into_searcher(self).next_match()?; - Some((&self[..start], &self[end..])) + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) } } /// Splits the string on the last occurrence of the specified delimiter and @@ -1545,7 +1562,8 @@ P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { let (start, end) = delimiter.into_searcher(self).next_match_back()?; - Some((&self[..start], &self[end..])) + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) } } /// An iterator over the disjoint matches of a pattern within the given string @@ -1841,6 +1859,8 @@ /// let s = " עברית"; /// assert!(Some('×¢') == s.trim_left().chars().next()); /// ``` + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated( @@ -1883,6 +1903,8 @@ /// let s = "עברית "; /// assert!(Some('ת') == s.trim_right().chars().rev().next()); /// ``` + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated( @@ -2347,6 +2369,8 @@ /// ``` /// assert_eq!("â¤\n!".escape_debug().to_string(), "â¤\\n!"); /// ``` + #[must_use = "this returns the escaped string as an iterator, \ + without modifying the original"] #[stable(feature = "str_escape", since = "1.34.0")] pub fn escape_debug(&self) -> EscapeDebug<'_> { let mut chars = self.chars(); @@ -2391,6 +2415,8 @@ /// ``` /// assert_eq!("â¤\n!".escape_default().to_string(), "\\u{2764}\\n!"); /// ``` + #[must_use = "this returns the escaped string as an iterator, \ + without modifying the original"] #[stable(feature = "str_escape", since = "1.34.0")] pub fn escape_default(&self) -> EscapeDefault<'_> { EscapeDefault { inner: self.chars().flat_map(CharEscapeDefault) } @@ -2427,6 +2453,8 @@ /// ``` /// assert_eq!("â¤\n!".escape_unicode().to_string(), "\\u{2764}\\u{a}\\u{21}"); /// ``` + #[must_use = "this returns the escaped string as an iterator, \ + without modifying the original"] #[stable(feature = "str_escape", since = "1.34.0")] pub fn escape_unicode(&self) -> EscapeUnicode<'_> { EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/str/traits.rs rustc-1.57.0+dfsg1+llvm/library/core/src/str/traits.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/str/traits.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/str/traits.rs 2021-11-29 19:27:11.000000000 +0000 @@ -536,7 +536,7 @@ /// /// If parsing succeeds, return the value inside [`Ok`], otherwise /// when the string is ill-formatted return an error specific to the - /// inside [`Err`]. The error type is specific to implementation of the trait. + /// inside [`Err`]. The error type is specific to the implementation of the trait. /// /// # Examples /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/str/validations.rs rustc-1.57.0+dfsg1+llvm/library/core/src/str/validations.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/str/validations.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/str/validations.rs 2021-11-29 19:27:11.000000000 +0000 @@ -22,7 +22,7 @@ /// bits `10`). #[inline] pub(super) fn utf8_is_cont_byte(byte: u8) -> bool { - (byte & !CONT_MASK) == TAG_CONT_U8 + (byte as i8) < -64 } #[inline] @@ -163,7 +163,7 @@ // %xF4 %x80-8F 2( UTF8-tail ) match w { 2 => { - if next!() & !CONT_MASK != TAG_CONT_U8 { + if next!() as i8 >= -64 { err!(Some(1)) } } @@ -175,7 +175,7 @@ | (0xEE..=0xEF, 0x80..=0xBF) => {} _ => err!(Some(1)), } - if next!() & !CONT_MASK != TAG_CONT_U8 { + if next!() as i8 >= -64 { err!(Some(2)) } } @@ -184,10 +184,10 @@ (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {} _ => err!(Some(1)), } - if next!() & !CONT_MASK != TAG_CONT_U8 { + if next!() as i8 >= -64 { err!(Some(2)) } - if next!() & !CONT_MASK != TAG_CONT_U8 { + if next!() as i8 >= -64 { err!(Some(3)) } } @@ -258,8 +258,6 @@ /// Mask of the value bits of a continuation byte. const CONT_MASK: u8 = 0b0011_1111; -/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. -const TAG_CONT_U8: u8 = 0b1000_0000; // truncate `&str` to length at most equal to `max` // return `true` if it were truncated, and the new str. diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/stream/stream/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/stream/stream/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/stream/stream/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/stream/stream/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -52,7 +52,7 @@ /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. /// - /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`. + /// The second half of the tuple that is returned is an [Option]<[usize]>. /// A [`None`] here means that either there is no known upper bound, or the /// upper bound is larger than [`usize`]. /// @@ -71,7 +71,7 @@ /// That said, the implementation should provide a correct estimation, /// because otherwise it would be a violation of the trait's protocol. /// - /// The default implementation returns `(0, `[`None`]`)` which is correct for any + /// The default implementation returns (0, [None]) which is correct for any /// stream. #[inline] fn size_hint(&self) -> (usize, Option) { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/sync/atomic.rs rustc-1.57.0+dfsg1+llvm/library/core/src/sync/atomic.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/sync/atomic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/sync/atomic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -62,7 +62,7 @@ //! some atomic operations. Maximally portable code will want to be careful //! about which atomic types are used. `AtomicUsize` and `AtomicIsize` are //! generally the most portable, but even then they're not available everywhere. -//! For reference, the `std` library requires pointer-sized atomics, although +//! For reference, the `std` library requires `AtomicBool`s and pointer-sized atomics, although //! `core` does not. //! //! Currently you'll need to use `#[cfg(target_arch)]` primarily to @@ -290,6 +290,7 @@ #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_atomic_new", since = "1.24.0")] + #[must_use] pub const fn new(v: bool) -> AtomicBool { AtomicBool { v: UnsafeCell::new(v as u8) } } @@ -1392,6 +1393,7 @@ #[inline] #[$stable] #[$const_stable] + #[must_use] pub const fn new(v: $int_type) -> Self { Self {v: UnsafeCell::new(v)} } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/task/mod.rs rustc-1.57.0+dfsg1+llvm/library/core/src/task/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/task/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/task/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -13,3 +13,5 @@ mod ready; #[unstable(feature = "ready_macro", issue = "70922")] pub use ready::ready; +#[unstable(feature = "poll_ready", issue = "89780")] +pub use ready::Ready; diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/task/poll.rs rustc-1.57.0+dfsg1+llvm/library/core/src/task/poll.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/task/poll.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/task/poll.rs 2021-11-29 19:27:11.000000000 +0000 @@ -3,6 +3,7 @@ use crate::convert; use crate::ops::{self, ControlFlow}; use crate::result::Result; +use crate::task::Ready; /// Indicates whether a value is available or if the current task has been /// scheduled to receive a wakeup instead. @@ -30,9 +31,10 @@ /// /// # Examples /// - /// Converts a `Poll<`[`String`]`>` into an `Poll<`[`usize`]`>`, consuming the original: + /// Converts a Poll<[String]> into a Poll<[usize]>, consuming + /// the original: /// - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// ``` /// # use core::task::Poll; /// let poll_some_string = Poll::Ready(String::from("Hello, World!")); @@ -91,6 +93,38 @@ pub const fn is_pending(&self) -> bool { !self.is_ready() } + + /// Extracts the successful type of a [`Poll`]. + /// + /// When combined with the `?` operator, this function will + /// propagate any [`Poll::Pending`] values to the caller, and + /// extract the `T` from [`Poll::Ready`]. + /// + /// # Examples + /// + /// ```rust + /// #![feature(poll_ready)] + /// + /// use std::task::{Context, Poll}; + /// use std::future::{self, Future}; + /// use std::pin::Pin; + /// + /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { + /// let mut fut = future::ready(42); + /// let fut = Pin::new(&mut fut); + /// + /// let num = fut.poll(cx).ready()?; + /// # drop(num); + /// // ... use num + /// + /// Poll::Ready(()) + /// } + /// ``` + #[inline] + #[unstable(feature = "poll_ready", issue = "89780")] + pub fn ready(self) -> Ready { + Ready(self) + } } impl Poll> { diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/task/ready.rs rustc-1.57.0+dfsg1+llvm/library/core/src/task/ready.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/task/ready.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/task/ready.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,3 +1,8 @@ +use core::convert; +use core::fmt; +use core::ops::{ControlFlow, FromResidual, Try}; +use core::task::Poll; + /// Extracts the successful type of a [`Poll`]. /// /// This macro bakes in propagation of [`Pending`] signals by returning early. @@ -58,3 +63,55 @@ } } } + +/// Extracts the successful type of a [`Poll`]. +/// +/// See [`Poll::ready`] for details. +#[unstable(feature = "poll_ready", issue = "89780")] +pub struct Ready(pub(crate) Poll); + +#[unstable(feature = "poll_ready", issue = "89780")] +impl Try for Ready { + type Output = T; + type Residual = Ready; + + #[inline] + fn from_output(output: Self::Output) -> Self { + Ready(Poll::Ready(output)) + } + + #[inline] + fn branch(self) -> ControlFlow { + match self.0 { + Poll::Ready(v) => ControlFlow::Continue(v), + Poll::Pending => ControlFlow::Break(Ready(Poll::Pending)), + } + } +} + +#[unstable(feature = "poll_ready", issue = "89780")] +impl FromResidual for Ready { + #[inline] + fn from_residual(residual: Ready) -> Self { + match residual.0 { + Poll::Pending => Ready(Poll::Pending), + } + } +} + +#[unstable(feature = "poll_ready", issue = "89780")] +impl FromResidual> for Poll { + #[inline] + fn from_residual(residual: Ready) -> Self { + match residual.0 { + Poll::Pending => Poll::Pending, + } + } +} + +#[unstable(feature = "poll_ready", issue = "89780")] +impl fmt::Debug for Ready { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Ready").finish() + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/task/wake.rs rustc-1.57.0+dfsg1+llvm/library/core/src/task/wake.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/task/wake.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/task/wake.rs 2021-11-29 19:27:11.000000000 +0000 @@ -39,6 +39,7 @@ #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] #[rustc_const_stable(feature = "futures_api", since = "1.36.0")] + #[must_use] pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { RawWaker { data, vtable } } @@ -158,6 +159,7 @@ impl<'a> Context<'a> { /// Create a new `Context` from a `&Waker`. #[stable(feature = "futures_api", since = "1.36.0")] + #[must_use] #[inline] pub fn from_waker(waker: &'a Waker) -> Self { Context { waker, _marker: PhantomData } @@ -251,6 +253,7 @@ /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. #[inline] + #[must_use] #[stable(feature = "futures_api", since = "1.36.0")] pub unsafe fn from_raw(waker: RawWaker) -> Waker { Waker { waker } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/time.rs rustc-1.57.0+dfsg1+llvm/library/core/src/time.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/time.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/time.rs 2021-11-29 19:27:11.000000000 +0000 @@ -181,6 +181,7 @@ #[stable(feature = "duration", since = "1.3.0")] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + #[must_use] pub const fn new(secs: u64, nanos: u32) -> Duration { let secs = match secs.checked_add((nanos / NANOS_PER_SEC) as u64) { Some(secs) => secs, @@ -203,6 +204,7 @@ /// assert_eq!(0, duration.subsec_nanos()); /// ``` #[stable(feature = "duration", since = "1.3.0")] + #[must_use] #[inline] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] pub const fn from_secs(secs: u64) -> Duration { @@ -222,6 +224,7 @@ /// assert_eq!(569_000_000, duration.subsec_nanos()); /// ``` #[stable(feature = "duration", since = "1.3.0")] + #[must_use] #[inline] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] pub const fn from_millis(millis: u64) -> Duration { @@ -244,6 +247,7 @@ /// assert_eq!(2000, duration.subsec_nanos()); /// ``` #[stable(feature = "duration_from_micros", since = "1.27.0")] + #[must_use] #[inline] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] pub const fn from_micros(micros: u64) -> Duration { @@ -266,6 +270,7 @@ /// assert_eq!(123, duration.subsec_nanos()); /// ``` #[stable(feature = "duration_extras", since = "1.27.0")] + #[must_use] #[inline] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] pub const fn from_nanos(nanos: u64) -> Duration { @@ -291,6 +296,7 @@ /// assert!(!Duration::from_nanos(1).is_zero()); /// assert!(!Duration::from_secs(1).is_zero()); /// ``` + #[must_use] #[stable(feature = "duration_zero", since = "1.53.0")] #[rustc_const_stable(feature = "duration_zero", since = "1.53.0")] #[inline] @@ -328,6 +334,7 @@ /// [`subsec_nanos`]: Duration::subsec_nanos #[stable(feature = "duration", since = "1.3.0")] #[rustc_const_stable(feature = "duration", since = "1.32.0")] + #[must_use] #[inline] pub const fn as_secs(&self) -> u64 { self.secs @@ -411,6 +418,7 @@ /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] + #[must_use] #[inline] pub const fn as_millis(&self) -> u128 { self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128 @@ -428,6 +436,7 @@ /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] + #[must_use] #[inline] pub const fn as_micros(&self) -> u128 { self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128 @@ -445,6 +454,7 @@ /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] + #[must_use] #[inline] pub const fn as_nanos(&self) -> u128 { self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128 @@ -464,6 +474,8 @@ /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); /// ``` #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn checked_add(self, rhs: Duration) -> Option { @@ -497,6 +509,8 @@ /// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); /// ``` #[stable(feature = "duration_saturating_ops", since = "1.53.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn saturating_add(self, rhs: Duration) -> Duration { @@ -520,6 +534,8 @@ /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); /// ``` #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn checked_sub(self, rhs: Duration) -> Option { @@ -551,6 +567,8 @@ /// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::ZERO); /// ``` #[stable(feature = "duration_saturating_ops", since = "1.53.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn saturating_sub(self, rhs: Duration) -> Duration { @@ -574,6 +592,8 @@ /// assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); /// ``` #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn checked_mul(self, rhs: u32) -> Option { @@ -603,6 +623,8 @@ /// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); /// ``` #[stable(feature = "duration_saturating_ops", since = "1.53.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn saturating_mul(self, rhs: u32) -> Duration { @@ -627,6 +649,8 @@ /// assert_eq!(Duration::new(2, 0).checked_div(0), None); /// ``` #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn checked_div(self, rhs: u32) -> Option { @@ -654,6 +678,7 @@ /// assert_eq!(dur.as_secs_f64(), 2.7); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn as_secs_f64(&self) -> f64 { @@ -672,6 +697,7 @@ /// assert_eq!(dur.as_secs_f32(), 2.7); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn as_secs_f32(&self) -> f32 { @@ -692,6 +718,7 @@ /// assert_eq!(dur, Duration::new(2, 700_000_000)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn from_secs_f64(secs: f64) -> Duration { @@ -753,6 +780,7 @@ /// assert_eq!(dur, Duration::new(2, 700_000_000)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn from_secs_f32(secs: f32) -> Duration { @@ -814,6 +842,8 @@ /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn mul_f64(self, rhs: f64) -> Duration { @@ -836,6 +866,8 @@ /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn mul_f32(self, rhs: f32) -> Duration { @@ -857,6 +889,8 @@ /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn div_f64(self, rhs: f64) -> Duration { @@ -880,6 +914,8 @@ /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn div_f32(self, rhs: f32) -> Duration { @@ -898,6 +934,8 @@ /// assert_eq!(dur1.div_duration_f64(dur2), 0.5); /// ``` #[unstable(feature = "div_duration", issue = "63139")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn div_duration_f64(self, rhs: Duration) -> f64 { @@ -916,6 +954,8 @@ /// assert_eq!(dur1.div_duration_f32(dur2), 0.5); /// ``` #[unstable(feature = "div_duration", issue = "63139")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn div_duration_f32(self, rhs: Duration) -> f32 { @@ -1049,11 +1089,16 @@ /// `divisor` must not be above 100_000_000. It also should be a power /// of 10, everything else doesn't make sense. `fractional_part` has /// to be less than `10 * divisor`! + /// + /// A prefix and postfix may be added. The whole thing is padded + /// to the formatter's `width`, if specified. fn fmt_decimal( f: &mut fmt::Formatter<'_>, mut integer_part: u64, mut fractional_part: u32, mut divisor: u32, + prefix: &str, + postfix: &str, ) -> fmt::Result { // Encode the fractional part into a temporary buffer. The buffer // only need to hold 9 elements, because `fractional_part` has to @@ -1114,48 +1159,91 @@ // set, we only use all digits up to the last non-zero one. let end = f.precision().map(|p| crate::cmp::min(p, 9)).unwrap_or(pos); - // If we haven't emitted a single fractional digit and the precision - // wasn't set to a non-zero value, we don't print the decimal point. - if end == 0 { - write!(f, "{}", integer_part) - } else { - // SAFETY: We are only writing ASCII digits into the buffer and it was - // initialized with '0's, so it contains valid UTF8. - let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) }; - - // If the user request a precision > 9, we pad '0's at the end. - let w = f.precision().unwrap_or(pos); - write!(f, "{}.{:0| { + write!(f, "{}{}", prefix, integer_part)?; + + // Write the decimal point and the fractional part (if any). + if end > 0 { + // SAFETY: We are only writing ASCII digits into the buffer and + // it was initialized with '0's, so it contains valid UTF8. + let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) }; + + // If the user request a precision > 9, we pad '0's at the end. + let w = f.precision().unwrap_or(pos); + write!(f, ".{:0 { + // No `width` specified. There's no need to calculate the + // length of the output in this case, just emit it. + emit_without_padding(f) + } + Some(requested_w) => { + // A `width` was specified. Calculate the actual width of + // the output in order to calculate the required padding. + // It consists of 4 parts: + // 1. The prefix: is either "+" or "", so we can just use len(). + // 2. The postfix: can be "µs" so we have to count UTF8 characters. + let mut actual_w = prefix.len() + postfix.chars().count(); + // 3. The integer part: + if let Some(log) = integer_part.checked_log10() { + // integer_part is > 0, so has length log10(x)+1 + actual_w += 1 + log as usize; + } else { + // integer_part is 0, so has length 1. + actual_w += 1; + } + // 4. The fractional part (if any): + if end > 0 { + let frac_part_w = f.precision().unwrap_or(pos); + actual_w += 1 + frac_part_w; + } + + if requested_w <= actual_w { + // Output is already longer than `width`, so don't pad. + emit_without_padding(f) + } else { + // We need to add padding. Use the `Formatter::padding` helper function. + let default_align = crate::fmt::rt::v1::Alignment::Left; + let post_padding = f.padding(requested_w - actual_w, default_align)?; + emit_without_padding(f)?; + post_padding.write(f) + } + } } } // Print leading '+' sign if requested - if f.sign_plus() { - write!(f, "+")?; - } + let prefix = if f.sign_plus() { "+" } else { "" }; if self.secs > 0 { - fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10)?; - f.write_str("s") + fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10, prefix, "s") } else if self.nanos >= NANOS_PER_MILLI { fmt_decimal( f, (self.nanos / NANOS_PER_MILLI) as u64, self.nanos % NANOS_PER_MILLI, NANOS_PER_MILLI / 10, - )?; - f.write_str("ms") + prefix, + "ms", + ) } else if self.nanos >= NANOS_PER_MICRO { fmt_decimal( f, (self.nanos / NANOS_PER_MICRO) as u64, self.nanos % NANOS_PER_MICRO, NANOS_PER_MICRO / 10, - )?; - f.write_str("µs") + prefix, + "µs", + ) } else { - fmt_decimal(f, self.nanos as u64, 0, 1)?; - f.write_str("ns") + fmt_decimal(f, self.nanos as u64, 0, 1, prefix, "ns") } } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/unicode/printable.rs rustc-1.57.0+dfsg1+llvm/library/core/src/unicode/printable.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/unicode/printable.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/unicode/printable.rs 2021-11-29 19:27:11.000000000 +0000 @@ -44,10 +44,10 @@ } else if x < 0x20000 { check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else { - if 0x2a6de <= x && x < 0x2a700 { + if 0x2a6e0 <= x && x < 0x2a700 { return false; } - if 0x2b735 <= x && x < 0x2b740 { + if 0x2b739 <= x && x < 0x2b740 { return false; } if 0x2b81e <= x && x < 0x2b820 { @@ -77,13 +77,13 @@ (0x00, 1), (0x03, 5), (0x05, 6), - (0x06, 3), + (0x06, 2), (0x07, 6), - (0x08, 8), + (0x08, 7), (0x09, 17), (0x0a, 28), (0x0b, 25), - (0x0c, 20), + (0x0c, 26), (0x0d, 16), (0x0e, 13), (0x0f, 4), @@ -91,16 +91,15 @@ (0x12, 18), (0x13, 9), (0x16, 1), - (0x17, 5), - (0x18, 2), + (0x17, 4), + (0x18, 1), (0x19, 3), (0x1a, 7), + (0x1b, 1), (0x1c, 2), - (0x1d, 1), (0x1f, 22), (0x20, 3), (0x2b, 3), - (0x2c, 2), (0x2d, 11), (0x2e, 1), (0x30, 3), @@ -112,49 +111,48 @@ (0xab, 8), (0xfa, 2), (0xfb, 5), - (0xfd, 4), + (0xfd, 2), (0xfe, 3), (0xff, 9), ]; #[rustfmt::skip] const SINGLETONS0L: &[u8] = &[ 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, - 0x58, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, 0xdd, 0x0e, - 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, - 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, - 0x91, 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, - 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, - 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, - 0x3d, 0x49, 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, - 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, - 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, - 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, - 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, - 0x57, 0x64, 0x65, 0x8d, 0x91, 0xa9, 0xb4, 0xba, - 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, - 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, - 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, 0xf1, 0x83, - 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, - 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, - 0xc6, 0xce, 0xcf, 0x49, 0x4e, 0x4f, 0x57, 0x59, - 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, - 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, - 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, 0xff, 0x80, 0x0d, - 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, - 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, - 0xbb, 0xbc, 0xfa, 0x16, 0x17, 0x1e, 0x1f, 0x46, - 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, - 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, - 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, 0x2f, - 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, + 0x58, 0x8b, 0x8c, 0x90, 0x1c, 0xdd, 0x0e, 0x0f, + 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, 0x5c, + 0x5d, 0x5f, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, + 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, + 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, + 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, + 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, + 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, + 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, + 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, + 0xcf, 0x0d, 0x11, 0x29, 0x3a, 0x3b, 0x45, 0x49, + 0x57, 0x5b, 0x5c, 0x5e, 0x5f, 0x64, 0x65, 0x8d, + 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, + 0xe4, 0xe5, 0xf0, 0x0d, 0x11, 0x45, 0x49, 0x64, + 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, + 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, + 0xbe, 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, + 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, + 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, + 0x8f, 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, + 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, + 0xfe, 0xff, 0x80, 0x6d, 0x71, 0xde, 0xdf, 0x0e, + 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, + 0xae, 0xaf, 0x7f, 0xbb, 0xbc, 0x16, 0x17, 0x1e, + 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, + 0x5e, 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, + 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, + 0x96, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, - 0x30, 0x8f, 0x1f, 0xc0, 0xc1, 0xce, 0xff, 0x4e, + 0x30, 0x8f, 0x1f, 0xd2, 0xd4, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, - 0x42, 0x45, 0x90, 0x91, 0xfe, 0xff, 0x53, 0x67, - 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, - 0xfe, 0xff, + 0x42, 0x45, 0x90, 0x91, 0x53, 0x67, 0x75, 0xc8, + 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, ]; #[rustfmt::skip] const SINGLETONS1U: &[(u8, u8)] = &[ @@ -162,6 +160,8 @@ (0x01, 1), (0x03, 1), (0x04, 2), + (0x05, 7), + (0x07, 2), (0x08, 8), (0x09, 2), (0x0a, 5), @@ -178,9 +178,11 @@ (0x1c, 5), (0x1d, 8), (0x24, 1), - (0x6a, 3), + (0x6a, 4), (0x6b, 2), + (0xaf, 3), (0xbc, 2), + (0xcf, 2), (0xd1, 2), (0xd4, 12), (0xd5, 9), @@ -189,38 +191,40 @@ (0xda, 1), (0xe0, 5), (0xe1, 2), + (0xe7, 4), (0xe8, 2), (0xee, 32), (0xf0, 4), (0xf8, 2), - (0xf9, 2), (0xfa, 2), (0xfb, 1), ]; #[rustfmt::skip] const SINGLETONS1L: &[u8] = &[ 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, - 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, - 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, - 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, - 0x35, 0xe0, 0x12, 0x87, 0x89, 0x8e, 0x9e, 0x04, - 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, - 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, - 0x5c, 0xb6, 0xb7, 0x1b, 0x1c, 0x07, 0x08, 0x0a, - 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, - 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, - 0x0a, 0x3b, 0x3e, 0x66, 0x69, 0x8f, 0x92, 0x6f, - 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, - 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, - 0xa8, 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, - 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, - 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, - 0x3e, 0x3f, 0xc5, 0xc6, 0x04, 0x20, 0x23, 0x25, - 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, - 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, - 0x60, 0x63, 0x65, 0x66, 0x6b, 0x73, 0x78, 0x7d, - 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, - 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, + 0x9e, 0x9f, 0x7b, 0x8b, 0x93, 0x96, 0xa2, 0xb2, + 0xba, 0x86, 0xb1, 0x06, 0x07, 0x09, 0x36, 0x3d, + 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, + 0x36, 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, + 0xbd, 0x35, 0xe0, 0x12, 0x87, 0x89, 0x8e, 0x9e, + 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, + 0x3a, 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, + 0x65, 0x5c, 0xb6, 0xb7, 0x1b, 0x1c, 0x07, 0x08, + 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, + 0xa9, 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, + 0x07, 0x0a, 0x3b, 0x3e, 0x66, 0x69, 0x8f, 0x92, + 0x6f, 0x5f, 0xbf, 0xee, 0xef, 0x5a, 0x62, 0xf4, + 0xfc, 0xff, 0x9a, 0x9b, 0x2e, 0x2f, 0x27, 0x28, + 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, + 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, + 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, + 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, + 0x3f, 0xe7, 0xec, 0xef, 0xff, 0xc5, 0xc6, 0x04, + 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, + 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, 0x58, + 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, 0x6b, + 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, + 0xb0, 0xc0, 0xd0, 0xae, 0xaf, 0x6e, 0x6f, 0x93, ]; #[rustfmt::skip] const NORMAL0: &[u8] = &[ @@ -231,9 +235,9 @@ 0x1b, 0x04, 0x06, 0x11, 0x81, 0xac, 0x0e, - 0x80, 0xab, 0x35, - 0x28, 0x0b, - 0x80, 0xe0, 0x03, + 0x80, 0xab, 0x05, + 0x1f, 0x09, + 0x81, 0x1b, 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, @@ -257,13 +261,11 @@ 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, - 0x3a, 0x03, - 0x11, 0x07, - 0x06, 0x05, - 0x10, 0x07, + 0x4e, 0x07, + 0x1b, 0x07, 0x57, 0x07, - 0x02, 0x07, - 0x15, 0x0d, + 0x02, 0x06, + 0x16, 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, @@ -280,8 +282,8 @@ 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, - 0x15, 0x0b, - 0x17, 0x09, + 0x16, 0x09, + 0x18, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, @@ -299,10 +301,9 @@ 0x0b, 0x03, 0x80, 0xac, 0x06, 0x0a, 0x06, - 0x21, 0x3f, - 0x4c, 0x04, - 0x2d, 0x03, - 0x74, 0x08, + 0x2f, 0x31, + 0x4d, 0x03, + 0x80, 0xa4, 0x08, 0x3c, 0x03, 0x0f, 0x03, 0x3c, 0x07, @@ -312,7 +313,7 @@ 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, - 0x20, 0x10, + 0x21, 0x0f, 0x21, 0x0f, 0x80, 0x8c, 0x04, 0x82, 0x97, 0x19, @@ -322,19 +323,19 @@ 0x3b, 0x07, 0x02, 0x0e, 0x18, 0x09, - 0x80, 0xb3, 0x2d, + 0x80, 0xbe, 0x22, 0x74, 0x0c, 0x80, 0xd6, 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, - 0xee, 0x0d, 0x03, - 0x84, 0x8d, 0x03, + 0xf2, 0x9d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, - 0x80, 0xcb, 0x2a, - 0x38, 0x03, + 0x80, 0xcb, 0x05, + 0x0a, 0x18, + 0x3b, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, @@ -354,9 +355,9 @@ 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, - 0x80, 0xa5, 0x11, - 0x81, 0x6d, 0x10, - 0x78, 0x28, + 0x80, 0xa6, 0x10, + 0x81, 0xf5, 0x07, + 0x01, 0x20, 0x2a, 0x06, 0x4c, 0x04, 0x80, 0x8d, 0x04, @@ -386,10 +387,11 @@ 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, - 0x01, 0x80, 0x90, + 0x4e, 0x43, 0x81, 0x37, 0x09, 0x16, 0x0a, - 0x08, 0x80, 0x98, + 0x08, 0x18, + 0x3b, 0x45, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, @@ -417,12 +419,13 @@ 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, - 0x2a, 0x56, + 0x2a, 0x16, + 0x1a, 0x26, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, - 0x1e, 0x0f, - 0x43, 0x0e, + 0x24, 0x09, + 0x44, 0x0d, 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, @@ -443,18 +446,18 @@ 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, - 0x39, 0x07, + 0x3a, 0x06, 0x0a, 0x36, 0x2c, 0x04, - 0x10, 0x80, 0xc0, + 0x17, 0x80, 0xb9, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, 0x1b, 0x48, 0x08, - 0x53, 0x1d, - 0x39, 0x81, 0x07, + 0x53, 0x0d, + 0x49, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, 0x47, 0x49, @@ -468,12 +471,13 @@ 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, 0x0b, - 0x80, 0xc4, 0x8a, 0xbc, + 0x80, 0xc4, 0x8a, 0x4c, + 0x63, 0x0d, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, - 0x02, 0x60, + 0x5c, 0x06, 0x26, 0x0a, 0x46, 0x0a, 0x28, 0x05, @@ -486,32 +490,36 @@ 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, - 0x09, 0xa2, 0xf7, - 0x81, 0x1f, 0x31, + 0x09, 0xa2, 0xe7, + 0x81, 0x33, 0x2d, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, - 0x10, 0x93, 0x60, + 0x10, 0x92, 0x60, + 0x47, 0x09, + 0x74, 0x3c, 0x80, 0xf6, 0x0a, 0x73, 0x08, - 0x6e, 0x17, + 0x70, 0x15, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, - 0x15, 0x85, 0x50, + 0x15, 0x84, 0x50, + 0x1f, 0x80, 0xe1, 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, - 0x02, 0x81, 0x70, + 0x02, 0x81, 0x40, + 0x1f, 0x11, 0x3a, 0x05, - 0x01, 0x85, 0x00, - 0x80, 0xd7, 0x29, + 0x01, 0x84, 0xe0, + 0x80, 0xf7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, 0x11, @@ -531,12 +539,13 @@ 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, 0x9a, - 0x83, 0xd8, 0x08, - 0x0d, 0x03, + 0x83, 0xd8, 0x05, + 0x10, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, - 0x0c, 0x14, + 0x0c, 0x04, + 0x01, 0x0f, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, @@ -544,12 +553,14 @@ 0x22, 0x4e, 0x81, 0x54, 0x0c, 0x15, 0x03, - 0x03, 0x05, + 0x05, 0x03, 0x07, 0x09, - 0x19, 0x07, + 0x1d, 0x03, + 0x0b, 0x05, + 0x06, 0x0a, + 0x0a, 0x06, + 0x08, 0x08, 0x07, 0x09, - 0x03, 0x0d, - 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, ]; diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/src/unicode/unicode_data.rs rustc-1.57.0+dfsg1+llvm/library/core/src/unicode/unicode_data.rs --- rustc-1.56.0+dfsg1+llvm/library/core/src/unicode/unicode_data.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/src/unicode/unicode_data.rs 2021-11-29 19:27:11.000000000 +0000 @@ -94,72 +94,74 @@ offset_idx % 2 == 1 } -pub const UNICODE_VERSION: (u8, u8, u8) = (13, 0, 0); +pub const UNICODE_VERSION: (u8, u8, u8) = (14, 0, 0); #[rustfmt::skip] pub mod alphabetic { - static SHORT_OFFSET_RUNS: [u32; 52] = [ - 706, 33559113, 868226669, 947920662, 1157637302, 1306536960, 1310732293, 1398813696, - 1449151936, 1451270141, 1455465613, 1459660301, 1468061604, 1648425216, 1658911342, - 1661009214, 1707147904, 1793132343, 1853951616, 1994464256, 2330009312, 2418090906, - 2428579840, 2439066671, 2441167872, 2443265607, 2445371392, 2447469113, 2449567296, - 2476836856, 2508295382, 2512498688, 2518790431, 2520888060, 2533473280, 2535576576, - 2556548774, 2634145792, 2682380992, 2715936768, 2720132608, 2736910640, 2875326464, - 2887952094, 2890053429, 2894253730, 2902649825, 2906847232, 2908944926, 2911043584, - 2913145675, 2916356939, + static SHORT_OFFSET_RUNS: [u32; 51] = [ + 706, 33559113, 876615277, 956309270, 1166025910, 1314925568, 1319120901, 1398813696, + 1449151936, 1451271309, 1455465997, 1463867300, 1652619520, 1663105646, 1665203518, + 1711342208, 1797326647, 1891700352, 2044795904, 2397118176, 2485199770, 2495688592, + 2506175535, 2512471040, 2514568775, 2516674560, 2518772281, 2520870464, 2552334328, + 2583792854, 2587996144, 2594287907, 2608968444, 2621553664, 2623656960, 2644629158, + 2722225920, 2770461328, 2808211424, 2816601600, 2850156848, 2988572672, 3001198304, + 3003299641, 3007499938, 3015896033, 3020093440, 3022191134, 3024289792, 3026391883, + 3029603147, ]; - static OFFSETS: [u8; 1391] = [ + static OFFSETS: [u8; 1445] = [ 65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 42, 5, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39, 14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10, - 3, 2, 1, 16, 48, 13, 101, 24, 33, 9, 2, 4, 1, 5, 24, 2, 19, 19, 25, 7, 11, 53, 21, 1, 18, - 12, 12, 3, 7, 6, 76, 1, 16, 1, 3, 4, 15, 13, 19, 1, 8, 2, 2, 2, 22, 1, 7, 1, 1, 3, 4, 3, 8, - 2, 2, 2, 2, 1, 1, 8, 1, 4, 2, 1, 5, 12, 2, 10, 1, 4, 3, 1, 6, 4, 2, 2, 22, 1, 7, 1, 2, 1, 2, - 1, 2, 4, 5, 4, 2, 2, 2, 4, 1, 7, 4, 1, 1, 17, 6, 11, 3, 1, 9, 1, 3, 1, 22, 1, 7, 1, 2, 1, 5, - 3, 9, 1, 3, 1, 2, 3, 1, 15, 4, 21, 4, 4, 3, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, - 2, 2, 9, 2, 4, 2, 1, 5, 13, 1, 16, 2, 1, 6, 3, 3, 1, 4, 3, 2, 1, 1, 1, 2, 3, 2, 3, 3, 3, 12, - 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 4, 1, 8, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, 2, 1, 3, - 5, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 7, 1, 1, 4, 13, 2, 13, - 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3, 24, 1, 9, 1, 1, - 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24, 1, 1, 1, 19, 1, - 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 17, 6, 16, 1, 36, 67, 55, 1, 1, 2, 5, - 16, 64, 10, 4, 2, 38, 1, 1, 5, 1, 2, 43, 1, 0, 1, 4, 2, 7, 1, 1, 1, 4, 2, 41, 1, 4, 2, 33, - 1, 4, 2, 7, 1, 1, 1, 4, 2, 15, 1, 57, 1, 4, 2, 67, 37, 16, 16, 86, 2, 6, 3, 0, 2, 17, 1, 26, - 5, 75, 3, 11, 7, 13, 1, 6, 12, 20, 12, 20, 12, 13, 1, 3, 1, 2, 12, 52, 2, 19, 14, 1, 4, 1, - 67, 89, 7, 43, 5, 70, 10, 31, 1, 12, 4, 9, 23, 30, 2, 5, 11, 44, 4, 26, 54, 28, 4, 63, 2, - 20, 50, 1, 23, 2, 63, 52, 1, 15, 1, 7, 52, 42, 2, 4, 10, 44, 1, 11, 14, 55, 22, 3, 10, 36, - 2, 9, 7, 43, 2, 3, 41, 4, 1, 6, 1, 2, 3, 1, 5, 192, 39, 14, 11, 0, 2, 6, 2, 38, 2, 6, 2, 8, - 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1, 7, 116, - 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, 1, 11, 2, 4, 5, - 5, 4, 1, 17, 41, 0, 52, 0, 47, 1, 47, 1, 133, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1, - 16, 23, 9, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2, - 5, 4, 86, 6, 3, 1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 3, 0, 67, 46, 2, 0, - 3, 16, 10, 2, 20, 47, 5, 8, 3, 113, 39, 9, 2, 103, 2, 53, 2, 9, 42, 17, 1, 33, 24, 52, 12, + 3, 2, 1, 16, 48, 13, 101, 24, 33, 9, 2, 4, 1, 5, 24, 2, 19, 19, 25, 7, 11, 5, 24, 1, 6, 17, + 42, 10, 12, 3, 7, 6, 76, 1, 16, 1, 3, 4, 15, 13, 19, 1, 8, 2, 2, 2, 22, 1, 7, 1, 1, 3, 4, 3, + 8, 2, 2, 2, 2, 1, 1, 8, 1, 4, 2, 1, 5, 12, 2, 10, 1, 4, 3, 1, 6, 4, 2, 2, 22, 1, 7, 1, 2, 1, + 2, 1, 2, 4, 5, 4, 2, 2, 2, 4, 1, 7, 4, 1, 1, 17, 6, 11, 3, 1, 9, 1, 3, 1, 22, 1, 7, 1, 2, 1, + 5, 3, 9, 1, 3, 1, 2, 3, 1, 15, 4, 21, 4, 4, 3, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, + 2, 2, 2, 9, 2, 4, 2, 1, 5, 13, 1, 16, 2, 1, 6, 3, 3, 1, 4, 3, 2, 1, 1, 1, 2, 3, 2, 3, 3, 3, + 12, 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 4, 1, 8, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, 2, + 1, 3, 2, 1, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 6, 2, 1, 4, + 13, 2, 13, 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3, 24, + 1, 9, 1, 1, 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24, 1, + 1, 1, 19, 1, 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 17, 6, 16, 1, 36, 67, 55, + 1, 1, 2, 5, 16, 64, 10, 4, 2, 38, 1, 1, 5, 1, 2, 43, 1, 0, 1, 4, 2, 7, 1, 1, 1, 4, 2, 41, 1, + 4, 2, 33, 1, 4, 2, 7, 1, 1, 1, 4, 2, 15, 1, 57, 1, 4, 2, 67, 37, 16, 16, 86, 2, 6, 3, 0, 2, + 17, 1, 26, 5, 75, 3, 11, 7, 20, 11, 21, 12, 20, 12, 13, 1, 3, 1, 2, 12, 52, 2, 19, 14, 1, 4, + 1, 67, 89, 7, 43, 5, 70, 10, 31, 1, 12, 4, 9, 23, 30, 2, 5, 11, 44, 4, 26, 54, 28, 4, 63, 2, + 20, 50, 1, 23, 2, 11, 3, 49, 52, 1, 15, 1, 8, 51, 42, 2, 4, 10, 44, 1, 11, 14, 55, 22, 3, + 10, 36, 2, 9, 7, 43, 2, 3, 41, 4, 1, 6, 1, 2, 3, 1, 5, 192, 39, 14, 11, 0, 2, 6, 2, 38, 2, + 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1, + 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, 1, 11, 2, + 4, 5, 5, 4, 1, 17, 41, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1, 16, 23, + 9, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2, 5, 4, + 86, 6, 3, 1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 67, 46, 2, 0, 3, 16, 10, + 2, 20, 47, 5, 8, 3, 113, 39, 9, 2, 103, 2, 64, 5, 2, 1, 1, 1, 5, 24, 20, 1, 33, 24, 52, 12, 68, 1, 1, 44, 6, 3, 1, 1, 3, 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5, 1, 55, 9, 14, 18, 23, 3, 69, 1, 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7, 1, 43, 1, 14, 6, 123, 21, 0, 12, 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5, 1, 1, 1, 2, 1, 2, 1, 108, 33, 0, 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11, 89, 3, 6, 2, 6, 2, 6, 2, 3, 35, 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0, 29, 3, 49, 47, 32, 13, 30, 5, 43, 5, 30, 2, 36, 4, 8, 1, 5, 42, 158, 18, 36, 4, 36, 4, 40, 8, 52, - 156, 0, 9, 22, 10, 8, 152, 6, 2, 1, 1, 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, - 10, 22, 10, 26, 70, 56, 6, 2, 64, 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, - 27, 54, 10, 22, 10, 19, 13, 18, 110, 73, 55, 51, 13, 51, 13, 40, 0, 42, 1, 2, 3, 2, 78, 29, - 10, 1, 8, 22, 106, 21, 27, 23, 9, 70, 60, 55, 23, 25, 23, 51, 17, 4, 8, 35, 3, 1, 9, 64, 1, - 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, 1, 65, 7, 1, 1, 1, 4, 1, 15, 1, 10, 7, 57, 23, - 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, 2, 2, 3, 1, 6, 1, 5, 7, 156, 66, 1, 3, - 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1, 3, 1, 59, 54, 2, 1, 71, - 27, 2, 14, 213, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30, 1, 2, 2, 2, 2, 4, 93, 8, 2, 46, - 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 34, 57, 0, 9, 1, 45, 1, 7, 1, 1, 49, 30, 2, - 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1, 1, 2, 2, 24, 6, 1, 2, 1, 37, 1, 2, 1, 4, - 1, 1, 0, 23, 185, 1, 79, 0, 102, 111, 17, 196, 0, 0, 0, 0, 0, 0, 7, 31, 113, 30, 18, 48, 16, - 4, 31, 21, 5, 19, 0, 64, 128, 75, 4, 57, 7, 17, 64, 2, 1, 1, 12, 2, 14, 0, 8, 0, 42, 9, 0, - 0, 49, 3, 17, 4, 8, 0, 0, 107, 5, 13, 3, 9, 7, 10, 4, 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, - 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, - 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 7, 1, 17, 2, 7, 1, - 2, 1, 5, 213, 45, 10, 7, 16, 1, 0, 44, 0, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, - 2, 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, - 26, 6, 26, 6, 26, 0, 0, 34, 0, 11, 222, 2, 0, 14, 0, 0, 0, 0, 0, 0, + 12, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 67, 0, 9, 22, 10, 8, 24, 6, 1, 42, 1, + 9, 69, 6, 2, 1, 1, 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, 10, 22, 10, 26, 70, + 56, 6, 2, 64, 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, 27, 54, 10, 22, 10, + 19, 13, 18, 110, 73, 55, 51, 13, 51, 13, 40, 0, 42, 1, 2, 3, 2, 78, 29, 10, 1, 8, 22, 42, + 18, 46, 21, 27, 23, 9, 70, 43, 5, 12, 55, 9, 1, 13, 25, 23, 51, 17, 4, 8, 35, 3, 1, 9, 64, + 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, 1, 65, 7, 1, 1, 1, 4, 1, 15, 1, 10, 7, 57, + 23, 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, 2, 2, 3, 1, 6, 1, 5, 7, 156, 66, 1, + 3, 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1, 3, 1, 59, 54, 2, 1, + 71, 27, 2, 14, 21, 7, 185, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30, 1, 2, 2, 2, 2, 4, + 93, 8, 2, 46, 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 18, 73, 0, 9, 1, 45, 1, 7, 1, + 1, 49, 30, 2, 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1, 1, 2, 2, 24, 6, 1, 2, 1, + 37, 1, 2, 1, 4, 1, 1, 0, 23, 185, 1, 79, 0, 102, 111, 17, 196, 0, 97, 15, 0, 0, 0, 0, 0, 7, + 31, 17, 79, 17, 30, 18, 48, 16, 4, 31, 21, 5, 19, 0, 64, 128, 75, 4, 57, 7, 17, 64, 2, 1, 1, + 12, 2, 14, 0, 8, 0, 42, 9, 0, 4, 1, 7, 1, 2, 1, 0, 45, 3, 17, 4, 8, 0, 0, 107, 5, 13, 3, 9, + 7, 10, 4, 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, + 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, + 25, 1, 31, 1, 25, 1, 8, 0, 31, 225, 7, 1, 17, 2, 7, 1, 2, 1, 5, 213, 45, 10, 7, 16, 1, 0, + 30, 18, 44, 0, 7, 1, 4, 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, + 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, + 6, 26, 6, 26, 0, 0, 32, 0, 7, 222, 2, 0, 14, 0, 0, 0, 0, 0, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -172,44 +174,45 @@ #[rustfmt::skip] pub mod case_ignorable { - static SHORT_OFFSET_RUNS: [u32; 32] = [ - 688, 44045149, 555751186, 559947709, 794831996, 866136069, 891330581, 916497656, 920692236, - 924908318, 1122041344, 1130430973, 1193347585, 1205931300, 1231097515, 1235294255, - 1445009723, 1453399088, 1512120051, 1575040048, 1579248368, 1583443791, 1596046493, - 1612829031, 1621219840, 1642192896, 1667359024, 1688330988, 1692526800, 1696723963, - 1705902081, 1711210992, + static SHORT_OFFSET_RUNS: [u32; 35] = [ + 688, 44045149, 572528402, 576724925, 807414908, 878718981, 903913493, 929080568, 933275148, + 937491230, 1138818560, 1147208189, 1210124160, 1222707713, 1235291428, 1260457643, + 1264654383, 1491147067, 1499536432, 1558257395, 1621177392, 1625385712, 1629581135, + 1642180592, 1658961053, 1671548672, 1679937895, 1688328704, 1709301760, 1734467888, + 1755439790, 1759635664, 1768027131, 1777205249, 1782514160, ]; - static OFFSETS: [u8; 821] = [ + static OFFSETS: [u8; 855] = [ 39, 1, 6, 1, 11, 1, 35, 1, 1, 1, 71, 1, 4, 1, 1, 1, 4, 1, 2, 2, 0, 192, 4, 2, 4, 1, 9, 2, 1, 1, 251, 7, 207, 1, 5, 1, 49, 45, 1, 1, 1, 2, 1, 2, 1, 1, 44, 1, 11, 6, 10, 11, 1, 1, 35, 1, 10, 21, 16, 1, 101, 8, 1, 10, 1, 4, 33, 1, 1, 1, 30, 27, 91, 11, 58, 11, 4, 1, 2, 1, 24, - 24, 43, 3, 119, 48, 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 13, 1, 15, 1, 58, 1, 4, 4, 8, 1, - 20, 2, 26, 1, 2, 2, 57, 1, 4, 2, 4, 2, 2, 3, 3, 1, 30, 2, 3, 1, 11, 2, 57, 1, 4, 5, 1, 2, 4, - 1, 20, 2, 22, 6, 1, 1, 58, 1, 2, 1, 1, 4, 8, 1, 7, 2, 11, 2, 30, 1, 61, 1, 12, 1, 50, 1, 3, - 1, 57, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 6, 1, 5, 2, 20, 2, 28, 2, 57, 2, 4, - 4, 8, 1, 20, 2, 29, 1, 72, 1, 7, 3, 1, 1, 90, 1, 2, 7, 11, 9, 98, 1, 2, 9, 9, 1, 1, 6, 74, - 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1, 102, 4, 1, 6, 1, 2, 2, 2, 25, - 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 94, 1, 0, 3, 0, 3, 29, 3, 29, 2, 30, 2, 64, 2, 1, - 7, 8, 1, 2, 11, 3, 1, 5, 1, 45, 4, 52, 1, 65, 2, 34, 1, 118, 3, 4, 2, 9, 1, 6, 3, 219, 2, 2, - 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 39, 1, 8, 17, 63, 4, 48, 1, 1, 5, 1, 1, 5, 1, - 40, 9, 12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3, 58, 8, 2, 2, 64, 6, 82, 3, 1, 13, - 1, 7, 4, 1, 6, 1, 3, 2, 50, 63, 13, 1, 34, 95, 1, 5, 0, 1, 1, 3, 11, 3, 13, 3, 13, 3, 13, 2, - 12, 5, 8, 2, 10, 1, 2, 1, 2, 5, 49, 5, 1, 10, 1, 1, 13, 1, 16, 13, 51, 33, 0, 2, 113, 3, - 125, 1, 15, 1, 96, 32, 47, 1, 0, 1, 36, 4, 3, 5, 5, 1, 93, 6, 93, 3, 0, 1, 0, 6, 0, 1, 98, - 4, 1, 10, 1, 1, 28, 4, 80, 2, 14, 34, 78, 1, 23, 3, 109, 2, 8, 1, 3, 1, 4, 1, 25, 2, 5, 1, - 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, 46, 3, 48, 1, 2, 4, 2, 2, 17, 1, 21, 2, 66, 6, 2, 2, - 2, 2, 12, 1, 8, 1, 35, 1, 11, 1, 51, 1, 1, 3, 2, 2, 5, 2, 1, 1, 27, 1, 14, 2, 5, 2, 1, 1, - 100, 5, 9, 3, 121, 1, 2, 1, 4, 1, 0, 1, 147, 16, 0, 16, 3, 1, 12, 16, 34, 1, 2, 1, 169, 1, - 7, 1, 6, 1, 11, 1, 35, 1, 1, 1, 47, 1, 45, 2, 67, 1, 21, 3, 0, 1, 226, 1, 149, 5, 0, 3, 1, - 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2, 153, 11, 176, 1, 54, 15, 56, 3, 49, 4, 2, 2, 2, 1, - 15, 1, 50, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 160, - 1, 3, 8, 21, 2, 57, 2, 3, 1, 37, 7, 3, 5, 195, 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4, 2, 1, - 2, 238, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, - 5, 0, 9, 1, 2, 0, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, - 46, 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, - 72, 2, 3, 1, 1, 1, 0, 2, 0, 9, 0, 5, 59, 7, 9, 4, 0, 1, 63, 17, 64, 2, 1, 2, 0, 2, 1, 4, 0, - 3, 9, 16, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, - 1, 2, 1, 5, 0, 14, 0, 4, 0, 7, 109, 8, 0, 5, 0, 1, 30, 96, 128, 240, 0, + 24, 43, 3, 44, 1, 7, 2, 6, 8, 41, 58, 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 13, 1, 15, 1, + 58, 1, 4, 4, 8, 1, 20, 2, 26, 1, 2, 2, 57, 1, 4, 2, 4, 2, 2, 3, 3, 1, 30, 2, 3, 1, 11, 2, + 57, 1, 4, 5, 1, 2, 4, 1, 20, 2, 22, 6, 1, 1, 58, 1, 2, 1, 1, 4, 8, 1, 7, 2, 11, 2, 30, 1, + 61, 1, 12, 1, 50, 1, 3, 1, 55, 1, 1, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 6, 1, + 5, 2, 20, 2, 28, 2, 57, 2, 4, 4, 8, 1, 20, 2, 29, 1, 72, 1, 7, 3, 1, 1, 90, 1, 2, 7, 11, 9, + 98, 1, 2, 9, 9, 1, 1, 6, 74, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1, + 102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 94, 1, 0, 3, 0, 3, + 29, 2, 30, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 3, 1, 5, 1, 45, 5, 51, 1, 65, 2, 34, 1, 118, + 3, 4, 2, 9, 1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 39, 1, 8, 31, + 49, 4, 48, 1, 1, 5, 1, 1, 5, 1, 40, 9, 12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3, + 58, 8, 2, 2, 64, 6, 82, 3, 1, 13, 1, 7, 4, 1, 6, 1, 3, 2, 50, 63, 13, 1, 34, 101, 0, 1, 1, + 3, 11, 3, 13, 3, 13, 3, 13, 2, 12, 5, 8, 2, 10, 1, 2, 1, 2, 5, 49, 5, 1, 10, 1, 1, 13, 1, + 16, 13, 51, 33, 0, 2, 113, 3, 125, 1, 15, 1, 96, 32, 47, 1, 0, 1, 36, 4, 3, 5, 5, 1, 93, 6, + 93, 3, 0, 1, 0, 6, 0, 1, 98, 4, 1, 10, 1, 1, 28, 4, 80, 2, 14, 34, 78, 1, 23, 3, 103, 3, 3, + 2, 8, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, 46, 3, 48, 1, 2, 4, + 2, 2, 17, 1, 21, 2, 66, 6, 2, 2, 2, 2, 12, 1, 8, 1, 35, 1, 11, 1, 51, 1, 1, 3, 2, 2, 5, 2, + 1, 1, 27, 1, 14, 2, 5, 2, 1, 1, 100, 5, 9, 3, 121, 1, 2, 1, 4, 1, 0, 1, 147, 17, 0, 16, 3, + 1, 12, 16, 34, 1, 2, 1, 169, 1, 7, 1, 6, 1, 11, 1, 35, 1, 1, 1, 47, 1, 45, 2, 67, 1, 21, 3, + 0, 1, 226, 1, 149, 5, 0, 6, 1, 42, 1, 9, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2, + 153, 11, 49, 4, 123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2, 1, 4, 1, 10, 1, 50, 3, + 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 160, 1, 3, 8, 21, 2, + 57, 2, 3, 1, 37, 7, 3, 5, 195, 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4, 2, 1, 2, 238, 4, 6, 2, + 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, 5, 0, 9, 1, 2, 0, + 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0, + 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, + 0, 2, 0, 9, 0, 5, 59, 7, 9, 4, 0, 1, 63, 17, 64, 2, 1, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4, 0, + 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, + 1, 17, 2, 7, 1, 2, 1, 5, 0, 14, 0, 1, 61, 4, 0, 7, 109, 8, 0, 5, 0, 1, 30, 96, 128, 240, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -222,23 +225,24 @@ #[rustfmt::skip] pub mod cased { - static SHORT_OFFSET_RUNS: [u32; 19] = [ - 4256, 115348384, 136322176, 144711446, 163587254, 320875520, 325101120, 358656816, - 392231680, 404815649, 413205504, 421596288, 434182304, 442592832, 446813184, 451008166, - 528607488, 576844080, 582152586, + static SHORT_OFFSET_RUNS: [u32; 21] = [ + 4256, 115348384, 136322176, 144711446, 163587254, 320875520, 325101120, 350268208, + 392231680, 404815649, 413205504, 421595008, 467733632, 484513952, 492924480, 497144832, + 501339814, 578936576, 627173632, 635564336, 640872842, ]; - static OFFSETS: [u8; 283] = [ + static OFFSETS: [u8; 311] = [ 65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 195, 1, 4, 4, 208, 1, 36, 7, 2, 30, 5, 96, 1, 42, 4, 2, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 9, 41, 0, 38, 1, 1, 5, 1, 2, 43, 2, 3, 0, 86, 2, 6, 0, 9, 7, 43, 2, 3, 64, 192, 64, 0, 2, 6, 2, 38, 2, 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1, 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, - 1, 6, 4, 1, 2, 4, 5, 5, 4, 1, 17, 32, 3, 2, 0, 52, 0, 47, 1, 47, 1, 133, 6, 4, 3, 2, 12, 38, - 1, 1, 5, 1, 0, 46, 18, 30, 132, 102, 3, 4, 1, 48, 2, 9, 42, 2, 1, 3, 0, 43, 1, 13, 7, 80, 0, - 7, 12, 5, 0, 26, 6, 26, 0, 80, 96, 36, 4, 36, 0, 51, 13, 51, 0, 64, 0, 64, 0, 85, 1, 71, 1, - 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, - 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 68, - 0, 26, 6, 26, 6, 26, 0, + 1, 6, 4, 1, 2, 4, 5, 5, 4, 1, 17, 32, 3, 2, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, + 0, 46, 18, 30, 132, 102, 3, 4, 1, 59, 5, 2, 1, 1, 1, 5, 27, 2, 1, 3, 0, 43, 1, 13, 7, 80, 0, + 7, 12, 5, 0, 26, 6, 26, 0, 80, 96, 36, 4, 36, 116, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, + 7, 1, 2, 0, 1, 2, 3, 1, 42, 1, 9, 0, 51, 13, 51, 0, 64, 0, 64, 0, 85, 1, 71, 1, 2, 2, 1, 2, + 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, + 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 10, 1, 20, 0, + 68, 0, 26, 6, 26, 6, 26, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -268,38 +272,40 @@ #[rustfmt::skip] pub mod grapheme_extend { - static SHORT_OFFSET_RUNS: [u32; 31] = [ - 768, 2098307, 6292881, 10490717, 513808146, 518004748, 723528943, 731918378, 744531567, - 752920578, 769719070, 899743232, 903937950, 912327165, 916523521, 929107236, 954273451, - 958470191, 1180769328, 1252073203, 1315007216, 1319202639, 1327611037, 1340199269, - 1344395776, 1373757440, 1398923568, 1419895532, 1424091344, 1429078048, 1438581232, + static SHORT_OFFSET_RUNS: [u32; 32] = [ + 768, 2098307, 6292881, 10490717, 522196754, 526393356, 731917551, 740306986, 752920175, + 761309186, 778107678, 908131840, 912326558, 920715773, 924912129, 937495844, 962662059, + 966858799, 1205935152, 1277239027, 1340173040, 1344368463, 1352776861, 1365364480, + 1369559397, 1377950208, 1407311872, 1432478000, 1453449902, 1457645776, 1466826784, + 1476329968, ]; - static OFFSETS: [u8; 689] = [ + static OFFSETS: [u8; 707] = [ 0, 112, 0, 7, 0, 45, 1, 1, 1, 2, 1, 2, 1, 1, 72, 11, 48, 21, 16, 1, 101, 7, 2, 6, 2, 2, 1, - 4, 35, 1, 30, 27, 91, 11, 58, 9, 9, 1, 24, 4, 1, 9, 1, 3, 1, 5, 43, 3, 119, 15, 1, 32, 55, - 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 29, 1, 58, 1, 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 26, 1, 2, 2, - 57, 1, 4, 2, 4, 2, 2, 3, 3, 1, 30, 2, 3, 1, 11, 2, 57, 1, 4, 5, 1, 2, 4, 1, 20, 2, 22, 6, 1, - 1, 58, 1, 1, 2, 1, 4, 8, 1, 7, 3, 10, 2, 30, 1, 59, 1, 1, 1, 12, 1, 9, 1, 40, 1, 3, 1, 57, - 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 2, 1, 3, 1, 5, 2, 7, 2, 11, 2, 28, 2, 57, 2, - 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 29, 1, 72, 1, 4, 1, 2, 3, 1, 1, 8, 1, 81, 1, 2, 7, 12, 8, 98, - 1, 2, 9, 11, 6, 74, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1, 102, 4, 1, - 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 0, 3, 0, 3, 29, 3, 29, 2, 30, - 2, 64, 2, 1, 7, 8, 1, 2, 11, 9, 1, 45, 3, 119, 2, 34, 1, 118, 3, 4, 2, 9, 1, 6, 3, 219, 2, - 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 48, 17, 63, 4, 48, 7, 1, 1, 5, 1, 40, 9, - 12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3, 58, 8, 2, 2, 152, 3, 1, 13, 1, 7, 4, 1, - 6, 1, 3, 2, 198, 58, 1, 5, 0, 1, 195, 33, 0, 3, 141, 1, 96, 32, 0, 6, 105, 2, 0, 4, 1, 10, - 32, 2, 80, 2, 0, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, 46, 3, - 48, 1, 2, 4, 2, 2, 39, 1, 67, 6, 2, 2, 2, 2, 12, 1, 8, 1, 47, 1, 51, 1, 1, 3, 2, 2, 5, 2, 1, - 1, 42, 2, 8, 1, 238, 1, 2, 1, 4, 1, 0, 1, 0, 16, 16, 16, 0, 2, 0, 1, 226, 1, 149, 5, 0, 3, - 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2, 153, 11, 176, 1, 54, 15, 56, 3, 49, 4, 2, 2, - 69, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 160, 1, 3, 8, - 21, 2, 57, 2, 1, 1, 1, 1, 22, 1, 14, 7, 3, 5, 195, 8, 2, 3, 1, 1, 23, 1, 81, 1, 2, 6, 1, 1, - 2, 1, 1, 2, 1, 2, 235, 1, 2, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, - 1, 101, 3, 2, 4, 1, 5, 0, 9, 1, 2, 245, 1, 10, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, - 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, - 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 0, 5, 59, 7, 0, 1, 63, 4, 81, 1, 0, - 2, 0, 1, 1, 3, 4, 5, 8, 8, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, - 7, 1, 17, 2, 7, 1, 2, 1, 5, 0, 7, 0, 4, 0, 7, 109, 7, 0, 96, 128, 240, 0, + 4, 35, 1, 30, 27, 91, 11, 58, 9, 9, 1, 24, 4, 1, 9, 1, 3, 1, 5, 43, 3, 60, 8, 42, 24, 1, 32, + 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 29, 1, 58, 1, 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 26, 1, 2, + 2, 57, 1, 4, 2, 4, 2, 2, 3, 3, 1, 30, 2, 3, 1, 11, 2, 57, 1, 4, 5, 1, 2, 4, 1, 20, 2, 22, 6, + 1, 1, 58, 1, 1, 2, 1, 4, 8, 1, 7, 3, 10, 2, 30, 1, 59, 1, 1, 1, 12, 1, 9, 1, 40, 1, 3, 1, + 55, 1, 1, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 2, 1, 3, 1, 5, 2, 7, 2, 11, 2, 28, + 2, 57, 2, 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 29, 1, 72, 1, 4, 1, 2, 3, 1, 1, 8, 1, 81, 1, 2, 7, + 12, 8, 98, 1, 2, 9, 11, 6, 74, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1, + 102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 0, 3, 0, 3, 29, 2, + 30, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 9, 1, 45, 3, 1, 1, 117, 2, 34, 1, 118, 3, 4, 2, 9, + 1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 48, 31, 49, 4, 48, 7, 1, + 1, 5, 1, 40, 9, 12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3, 58, 8, 2, 2, 152, 3, 1, + 13, 1, 7, 4, 1, 6, 1, 3, 2, 198, 64, 0, 1, 195, 33, 0, 3, 141, 1, 96, 32, 0, 6, 105, 2, 0, + 4, 1, 10, 32, 2, 80, 2, 0, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, + 46, 3, 48, 1, 2, 4, 2, 2, 39, 1, 67, 6, 2, 2, 2, 2, 12, 1, 8, 1, 47, 1, 51, 1, 1, 3, 2, 2, + 5, 2, 1, 1, 42, 2, 8, 1, 238, 1, 2, 1, 4, 1, 0, 1, 0, 16, 16, 16, 0, 2, 0, 1, 226, 1, 149, + 5, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2, 153, 11, 49, 4, 123, 1, 54, 15, 41, 1, + 2, 2, 10, 3, 49, 4, 2, 2, 7, 1, 61, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, + 2, 1, 1, 2, 6, 1, 160, 1, 3, 8, 21, 2, 57, 2, 1, 1, 1, 1, 22, 1, 14, 7, 3, 5, 195, 8, 2, 3, + 1, 1, 23, 1, 81, 1, 2, 6, 1, 1, 2, 1, 1, 2, 1, 2, 235, 1, 2, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, + 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, 5, 0, 9, 1, 2, 245, 1, 10, 2, 1, 1, 4, + 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1, + 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 0, 5, + 59, 7, 0, 1, 63, 4, 81, 1, 0, 2, 0, 46, 2, 23, 0, 1, 1, 3, 4, 5, 8, 8, 2, 7, 30, 4, 148, 3, + 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 0, 7, 0, 1, 61, 4, + 0, 7, 109, 7, 0, 96, 128, 240, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -313,33 +319,34 @@ #[rustfmt::skip] pub mod lowercase { static BITSET_CHUNKS_MAP: [u8; 123] = [ - 13, 16, 0, 0, 8, 0, 0, 11, 12, 9, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 3, 1, 0, 14, 0, 7, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, - 0, 0, 6, + 14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, + 3, 0, 0, 7, ]; - static BITSET_INDEX_CHUNKS: [[u8; 16]; 18] = [ + static BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 52, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 55, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 39, 0, 47, 43, 45, 30], - [0, 0, 0, 0, 10, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 42, 0, 50, 46, 48, 32], + [0, 0, 0, 0, 10, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26], - [0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 54, 0, 52, 52, 52, 0, 21, 21, 64, 21, 33, 24, 23, 34], - [0, 5, 71, 0, 28, 15, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 61, 31, 17, 22, 48, 49, 44, 42, 8, 32, 38, 0, 27, 13, 29], - [11, 55, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [16, 25, 21, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [16, 46, 2, 20, 63, 9, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [60, 37, 51, 12, 70, 58, 18, 1, 6, 59, 68, 19, 65, 66, 3, 41], + [0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26], + [0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 57, 0, 55, 55, 55, 0, 21, 21, 67, 21, 35, 24, 23, 36], + [0, 5, 74, 0, 28, 15, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 64, 33, 17, 22, 51, 52, 47, 45, 8, 34, 40, 0, 27, 13, 30], + [11, 58, 0, 4, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 31, 0], + [16, 25, 21, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [16, 49, 2, 20, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [63, 39, 54, 12, 73, 61, 18, 1, 6, 62, 71, 19, 68, 69, 3, 44], ]; - static BITSET_CANONICAL: [u64; 52] = [ + static BITSET_CANONICAL: [u64; 55] = [ 0b0000000000000000000000000000000000000000000000000000000000000000, 0b1111111111111111110000000000000000000000000011111111111111111111, 0b1010101010101010101010101010101010101010101010101010100000000010, @@ -365,12 +372,14 @@ 0b0101010110101010101010101010101010101010101010101010101010101010, 0b0100000011011111000000001111111100000000111111110000000011111111, 0b0011111111111111000000001111111100000000111111110000000000111111, - 0b0011111111011010000101010110001001111111111111111111111111111111, + 0b0011111111011010000101010110001011111111111111111111111111111111, 0b0011111100000000000000000000000000000000000000000000000000000000, 0b0011110010001010000000000000000000000000000000000000000000100000, 0b0011001000010000100000000000000000000000000010001100010000000000, + 0b0001101111111011111111111111101111111111100000000000000000000000, 0b0001100100101111101010101010101010101010111000110111111111111111, - 0b0000011101000000000000000000000000000000000000000000010100001000, + 0b0000011111111101111111111111111111111111111111111111111110111001, + 0b0000011101000000000000000000000000000010101010100000010100001010, 0b0000010000100000000001000000000000000000000000000000000000000000, 0b0000000111111111111111111111111111111111111011111111111111111111, 0b0000000011111111000000001111111100000000001111110000000011111111, @@ -379,6 +388,7 @@ 0b0000000000000000001000001011111111111111111111111111111111111111, 0b0000000000000000000000001111111111111111110111111100000000000000, 0b0000000000000000000000000001111100000000000000000000000000000011, + 0b0000000000000000000000000000000001111111111111111111101111111111, 0b0000000000000000000000000000000000111010101010101010101010101010, 0b0000000000000000000000000000000000000000111110000000000001111111, 0b0000000000000000000000000000000000000000000000000000101111110111, @@ -416,10 +426,10 @@ 1632, 18876774, 31461440, 102765417, 111154926, 115349830, 132128880, 165684320, 186656630, 195046653, 199241735, 203436434, 216049184, 241215536, 249605104, 274792208, 278987015, 283181793, 295766104, 320933114, 383848032, 392238160, 434181712, 442570976, 455154768, - 463544256, 476128256, 480340576, 484535936, 497144544, 501340110, 509731136, 513925872, - 518121671, 522316913, 530706688, 551681008, 556989434, + 463544256, 476128256, 480340576, 484535936, 501338848, 505534414, 513925440, 518120176, + 522315975, 526511217, 534900992, 555875312, 561183738, ]; - static OFFSETS: [u8; 267] = [ + static OFFSETS: [u8; 269] = [ 48, 10, 120, 2, 5, 1, 2, 3, 0, 10, 134, 10, 198, 10, 0, 10, 118, 10, 4, 6, 108, 10, 118, 10, 118, 10, 2, 6, 110, 13, 115, 10, 8, 7, 103, 10, 104, 7, 7, 19, 109, 10, 96, 10, 118, 10, 70, 20, 0, 10, 70, 10, 0, 20, 0, 3, 239, 10, 6, 10, 22, 10, 0, 10, 128, 11, 165, 10, 6, 10, @@ -429,8 +439,9 @@ 29, 1, 8, 1, 134, 5, 202, 10, 0, 8, 25, 7, 39, 9, 75, 5, 22, 6, 160, 2, 2, 16, 2, 46, 64, 9, 52, 2, 30, 3, 75, 5, 104, 8, 24, 8, 41, 7, 0, 6, 48, 10, 0, 31, 158, 10, 42, 4, 112, 7, 134, 30, 128, 10, 60, 10, 144, 10, 7, 20, 251, 10, 0, 10, 118, 10, 0, 10, 102, 10, 102, 12, 0, - 19, 93, 10, 0, 29, 227, 10, 70, 10, 0, 21, 0, 111, 0, 10, 230, 10, 1, 7, 0, 23, 0, 20, 108, - 25, 0, 50, 0, 10, 0, 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, 76, 45, 1, 15, 0, 13, 0, 10, 0, + 19, 93, 10, 0, 29, 227, 10, 70, 10, 0, 21, 0, 111, 0, 10, 86, 10, 134, 10, 1, 7, 0, 23, 0, + 20, 108, 25, 0, 50, 0, 10, 0, 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, 76, 45, 1, 15, 0, 13, 0, + 10, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( @@ -444,37 +455,37 @@ #[rustfmt::skip] pub mod uppercase { static BITSET_CHUNKS_MAP: [u8; 125] = [ - 12, 15, 5, 5, 0, 5, 5, 2, 4, 11, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 6, 5, 13, 5, 10, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 16, 5, 5, - 5, 5, 9, 5, 3, + 12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6, + 6, 6, 9, 6, 3, ]; static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [ - [41, 41, 5, 33, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 5, 0], - [41, 41, 5, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [41, 41, 38, 41, 41, 41, 41, 41, 17, 17, 61, 17, 40, 29, 24, 23], - [41, 41, 41, 41, 9, 8, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [41, 41, 41, 41, 35, 28, 65, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 56, 41, 41, 41], - [41, 41, 41, 41, 41, 41, 41, 41, 41, 46, 41, 41, 41, 41, 41, 41], - [41, 41, 41, 41, 41, 41, 41, 41, 41, 60, 59, 41, 20, 14, 16, 4], - [41, 41, 41, 41, 47, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [41, 41, 51, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [41, 41, 52, 43, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [41, 53, 41, 31, 34, 21, 22, 15, 13, 32, 41, 41, 41, 11, 30, 37], - [48, 41, 9, 44, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [49, 36, 17, 27, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [50, 19, 2, 18, 10, 45, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41], - [57, 1, 26, 54, 12, 7, 25, 55, 39, 58, 6, 3, 64, 63, 62, 66], + [43, 43, 5, 34, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 1], + [43, 43, 5, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [43, 43, 39, 43, 43, 43, 43, 43, 17, 17, 62, 17, 42, 29, 24, 23], + [43, 43, 43, 43, 9, 8, 44, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [43, 43, 43, 43, 36, 28, 66, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 0, 43, 43, 43], + [43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [43, 43, 43, 43, 43, 43, 43, 43, 43, 54, 43, 43, 43, 43, 43, 43], + [43, 43, 43, 43, 43, 43, 43, 43, 43, 61, 60, 43, 20, 14, 16, 4], + [43, 43, 43, 43, 55, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [43, 43, 58, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [43, 43, 59, 45, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [43, 48, 43, 31, 35, 21, 22, 15, 13, 33, 43, 43, 43, 11, 30, 38], + [51, 53, 26, 49, 12, 7, 25, 50, 40, 52, 6, 3, 65, 64, 63, 67], + [56, 43, 9, 46, 43, 41, 32, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [57, 19, 2, 18, 10, 47, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], + [57, 37, 17, 27, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], ]; - static BITSET_CANONICAL: [u64; 41] = [ + static BITSET_CANONICAL: [u64; 43] = [ + 0b0000011111111111111111111111111000000000000000000000000000000000, 0b0000000000111111111111111111111111111111111111111111111111111111, - 0b1111111111111111111111110000000000000000000000000011111111111111, 0b0101010101010101010101010101010101010101010101010101010000000001, 0b0000011111111111111111111111110000000000000000000000000000000001, - 0b0000000000100000000000000000000000000000000000000000001011110100, + 0b0000000000100000000000000000000000000001010000010000001011110101, 0b1111111111111111111111111111111100000000000000000000000000000000, 0b1111111111111111111111110000000000000000000000000000001111111111, 0b1111111111111111111100000000000000000000000000011111110001011111, @@ -502,6 +513,7 @@ 0b0000000000000000111111110000000010101010000000000011111100000000, 0b0000000000000000000011111111101111111111111111101101011101000000, 0b0000000000000000000000000000000001111111011111111111111111111111, + 0b0000000000000000000000000000000000000000001101111111011111111111, 0b0000000000000000000000000000000000000000000000000101010101111010, 0b0000000000000000000000000000000000000000000000000010000010111111, 0b1010101001010101010101010101010101010101010101010101010101010101, @@ -510,11 +522,12 @@ 0b1110011010010000010101010101010101010101000111001000000000000000, 0b1110011111111111111111111111111111111111111111110000000000000000, 0b1111000000000000000000000000001111111111111111111111111100000000, + 0b1111011111111111000000000000000000000000000000000000000000000000, 0b1111111100000000111111110000000000111111000000001111111100000000, ]; - static BITSET_MAPPING: [(u8, u8); 26] = [ - (0, 182), (0, 74), (0, 166), (0, 162), (0, 159), (0, 150), (0, 148), (0, 142), (0, 135), - (0, 134), (0, 131), (0, 64), (1, 115), (1, 66), (1, 70), (1, 83), (1, 12), (1, 8), (2, 164), + static BITSET_MAPPING: [(u8, u8); 25] = [ + (0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121), + (0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164), (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), ]; @@ -1051,113 +1064,116 @@ ('\u{2c28}', ['\u{2c58}', '\u{0}', '\u{0}']), ('\u{2c29}', ['\u{2c59}', '\u{0}', '\u{0}']), ('\u{2c2a}', ['\u{2c5a}', '\u{0}', '\u{0}']), ('\u{2c2b}', ['\u{2c5b}', '\u{0}', '\u{0}']), ('\u{2c2c}', ['\u{2c5c}', '\u{0}', '\u{0}']), ('\u{2c2d}', ['\u{2c5d}', '\u{0}', '\u{0}']), - ('\u{2c2e}', ['\u{2c5e}', '\u{0}', '\u{0}']), ('\u{2c60}', ['\u{2c61}', '\u{0}', '\u{0}']), - ('\u{2c62}', ['\u{26b}', '\u{0}', '\u{0}']), ('\u{2c63}', ['\u{1d7d}', '\u{0}', '\u{0}']), - ('\u{2c64}', ['\u{27d}', '\u{0}', '\u{0}']), ('\u{2c67}', ['\u{2c68}', '\u{0}', '\u{0}']), - ('\u{2c69}', ['\u{2c6a}', '\u{0}', '\u{0}']), ('\u{2c6b}', ['\u{2c6c}', '\u{0}', '\u{0}']), - ('\u{2c6d}', ['\u{251}', '\u{0}', '\u{0}']), ('\u{2c6e}', ['\u{271}', '\u{0}', '\u{0}']), - ('\u{2c6f}', ['\u{250}', '\u{0}', '\u{0}']), ('\u{2c70}', ['\u{252}', '\u{0}', '\u{0}']), - ('\u{2c72}', ['\u{2c73}', '\u{0}', '\u{0}']), ('\u{2c75}', ['\u{2c76}', '\u{0}', '\u{0}']), - ('\u{2c7e}', ['\u{23f}', '\u{0}', '\u{0}']), ('\u{2c7f}', ['\u{240}', '\u{0}', '\u{0}']), - ('\u{2c80}', ['\u{2c81}', '\u{0}', '\u{0}']), ('\u{2c82}', ['\u{2c83}', '\u{0}', '\u{0}']), - ('\u{2c84}', ['\u{2c85}', '\u{0}', '\u{0}']), ('\u{2c86}', ['\u{2c87}', '\u{0}', '\u{0}']), - ('\u{2c88}', ['\u{2c89}', '\u{0}', '\u{0}']), ('\u{2c8a}', ['\u{2c8b}', '\u{0}', '\u{0}']), - ('\u{2c8c}', ['\u{2c8d}', '\u{0}', '\u{0}']), ('\u{2c8e}', ['\u{2c8f}', '\u{0}', '\u{0}']), - ('\u{2c90}', ['\u{2c91}', '\u{0}', '\u{0}']), ('\u{2c92}', ['\u{2c93}', '\u{0}', '\u{0}']), - ('\u{2c94}', ['\u{2c95}', '\u{0}', '\u{0}']), ('\u{2c96}', ['\u{2c97}', '\u{0}', '\u{0}']), - ('\u{2c98}', ['\u{2c99}', '\u{0}', '\u{0}']), ('\u{2c9a}', ['\u{2c9b}', '\u{0}', '\u{0}']), - ('\u{2c9c}', ['\u{2c9d}', '\u{0}', '\u{0}']), ('\u{2c9e}', ['\u{2c9f}', '\u{0}', '\u{0}']), - ('\u{2ca0}', ['\u{2ca1}', '\u{0}', '\u{0}']), ('\u{2ca2}', ['\u{2ca3}', '\u{0}', '\u{0}']), - ('\u{2ca4}', ['\u{2ca5}', '\u{0}', '\u{0}']), ('\u{2ca6}', ['\u{2ca7}', '\u{0}', '\u{0}']), - ('\u{2ca8}', ['\u{2ca9}', '\u{0}', '\u{0}']), ('\u{2caa}', ['\u{2cab}', '\u{0}', '\u{0}']), - ('\u{2cac}', ['\u{2cad}', '\u{0}', '\u{0}']), ('\u{2cae}', ['\u{2caf}', '\u{0}', '\u{0}']), - ('\u{2cb0}', ['\u{2cb1}', '\u{0}', '\u{0}']), ('\u{2cb2}', ['\u{2cb3}', '\u{0}', '\u{0}']), - ('\u{2cb4}', ['\u{2cb5}', '\u{0}', '\u{0}']), ('\u{2cb6}', ['\u{2cb7}', '\u{0}', '\u{0}']), - ('\u{2cb8}', ['\u{2cb9}', '\u{0}', '\u{0}']), ('\u{2cba}', ['\u{2cbb}', '\u{0}', '\u{0}']), - ('\u{2cbc}', ['\u{2cbd}', '\u{0}', '\u{0}']), ('\u{2cbe}', ['\u{2cbf}', '\u{0}', '\u{0}']), - ('\u{2cc0}', ['\u{2cc1}', '\u{0}', '\u{0}']), ('\u{2cc2}', ['\u{2cc3}', '\u{0}', '\u{0}']), - ('\u{2cc4}', ['\u{2cc5}', '\u{0}', '\u{0}']), ('\u{2cc6}', ['\u{2cc7}', '\u{0}', '\u{0}']), - ('\u{2cc8}', ['\u{2cc9}', '\u{0}', '\u{0}']), ('\u{2cca}', ['\u{2ccb}', '\u{0}', '\u{0}']), - ('\u{2ccc}', ['\u{2ccd}', '\u{0}', '\u{0}']), ('\u{2cce}', ['\u{2ccf}', '\u{0}', '\u{0}']), - ('\u{2cd0}', ['\u{2cd1}', '\u{0}', '\u{0}']), ('\u{2cd2}', ['\u{2cd3}', '\u{0}', '\u{0}']), - ('\u{2cd4}', ['\u{2cd5}', '\u{0}', '\u{0}']), ('\u{2cd6}', ['\u{2cd7}', '\u{0}', '\u{0}']), - ('\u{2cd8}', ['\u{2cd9}', '\u{0}', '\u{0}']), ('\u{2cda}', ['\u{2cdb}', '\u{0}', '\u{0}']), - ('\u{2cdc}', ['\u{2cdd}', '\u{0}', '\u{0}']), ('\u{2cde}', ['\u{2cdf}', '\u{0}', '\u{0}']), - ('\u{2ce0}', ['\u{2ce1}', '\u{0}', '\u{0}']), ('\u{2ce2}', ['\u{2ce3}', '\u{0}', '\u{0}']), - ('\u{2ceb}', ['\u{2cec}', '\u{0}', '\u{0}']), ('\u{2ced}', ['\u{2cee}', '\u{0}', '\u{0}']), - ('\u{2cf2}', ['\u{2cf3}', '\u{0}', '\u{0}']), ('\u{a640}', ['\u{a641}', '\u{0}', '\u{0}']), - ('\u{a642}', ['\u{a643}', '\u{0}', '\u{0}']), ('\u{a644}', ['\u{a645}', '\u{0}', '\u{0}']), - ('\u{a646}', ['\u{a647}', '\u{0}', '\u{0}']), ('\u{a648}', ['\u{a649}', '\u{0}', '\u{0}']), - ('\u{a64a}', ['\u{a64b}', '\u{0}', '\u{0}']), ('\u{a64c}', ['\u{a64d}', '\u{0}', '\u{0}']), - ('\u{a64e}', ['\u{a64f}', '\u{0}', '\u{0}']), ('\u{a650}', ['\u{a651}', '\u{0}', '\u{0}']), - ('\u{a652}', ['\u{a653}', '\u{0}', '\u{0}']), ('\u{a654}', ['\u{a655}', '\u{0}', '\u{0}']), - ('\u{a656}', ['\u{a657}', '\u{0}', '\u{0}']), ('\u{a658}', ['\u{a659}', '\u{0}', '\u{0}']), - ('\u{a65a}', ['\u{a65b}', '\u{0}', '\u{0}']), ('\u{a65c}', ['\u{a65d}', '\u{0}', '\u{0}']), - ('\u{a65e}', ['\u{a65f}', '\u{0}', '\u{0}']), ('\u{a660}', ['\u{a661}', '\u{0}', '\u{0}']), - ('\u{a662}', ['\u{a663}', '\u{0}', '\u{0}']), ('\u{a664}', ['\u{a665}', '\u{0}', '\u{0}']), - ('\u{a666}', ['\u{a667}', '\u{0}', '\u{0}']), ('\u{a668}', ['\u{a669}', '\u{0}', '\u{0}']), - ('\u{a66a}', ['\u{a66b}', '\u{0}', '\u{0}']), ('\u{a66c}', ['\u{a66d}', '\u{0}', '\u{0}']), - ('\u{a680}', ['\u{a681}', '\u{0}', '\u{0}']), ('\u{a682}', ['\u{a683}', '\u{0}', '\u{0}']), - ('\u{a684}', ['\u{a685}', '\u{0}', '\u{0}']), ('\u{a686}', ['\u{a687}', '\u{0}', '\u{0}']), - ('\u{a688}', ['\u{a689}', '\u{0}', '\u{0}']), ('\u{a68a}', ['\u{a68b}', '\u{0}', '\u{0}']), - ('\u{a68c}', ['\u{a68d}', '\u{0}', '\u{0}']), ('\u{a68e}', ['\u{a68f}', '\u{0}', '\u{0}']), - ('\u{a690}', ['\u{a691}', '\u{0}', '\u{0}']), ('\u{a692}', ['\u{a693}', '\u{0}', '\u{0}']), - ('\u{a694}', ['\u{a695}', '\u{0}', '\u{0}']), ('\u{a696}', ['\u{a697}', '\u{0}', '\u{0}']), - ('\u{a698}', ['\u{a699}', '\u{0}', '\u{0}']), ('\u{a69a}', ['\u{a69b}', '\u{0}', '\u{0}']), - ('\u{a722}', ['\u{a723}', '\u{0}', '\u{0}']), ('\u{a724}', ['\u{a725}', '\u{0}', '\u{0}']), - ('\u{a726}', ['\u{a727}', '\u{0}', '\u{0}']), ('\u{a728}', ['\u{a729}', '\u{0}', '\u{0}']), - ('\u{a72a}', ['\u{a72b}', '\u{0}', '\u{0}']), ('\u{a72c}', ['\u{a72d}', '\u{0}', '\u{0}']), - ('\u{a72e}', ['\u{a72f}', '\u{0}', '\u{0}']), ('\u{a732}', ['\u{a733}', '\u{0}', '\u{0}']), - ('\u{a734}', ['\u{a735}', '\u{0}', '\u{0}']), ('\u{a736}', ['\u{a737}', '\u{0}', '\u{0}']), - ('\u{a738}', ['\u{a739}', '\u{0}', '\u{0}']), ('\u{a73a}', ['\u{a73b}', '\u{0}', '\u{0}']), - ('\u{a73c}', ['\u{a73d}', '\u{0}', '\u{0}']), ('\u{a73e}', ['\u{a73f}', '\u{0}', '\u{0}']), - ('\u{a740}', ['\u{a741}', '\u{0}', '\u{0}']), ('\u{a742}', ['\u{a743}', '\u{0}', '\u{0}']), - ('\u{a744}', ['\u{a745}', '\u{0}', '\u{0}']), ('\u{a746}', ['\u{a747}', '\u{0}', '\u{0}']), - ('\u{a748}', ['\u{a749}', '\u{0}', '\u{0}']), ('\u{a74a}', ['\u{a74b}', '\u{0}', '\u{0}']), - ('\u{a74c}', ['\u{a74d}', '\u{0}', '\u{0}']), ('\u{a74e}', ['\u{a74f}', '\u{0}', '\u{0}']), - ('\u{a750}', ['\u{a751}', '\u{0}', '\u{0}']), ('\u{a752}', ['\u{a753}', '\u{0}', '\u{0}']), - ('\u{a754}', ['\u{a755}', '\u{0}', '\u{0}']), ('\u{a756}', ['\u{a757}', '\u{0}', '\u{0}']), - ('\u{a758}', ['\u{a759}', '\u{0}', '\u{0}']), ('\u{a75a}', ['\u{a75b}', '\u{0}', '\u{0}']), - ('\u{a75c}', ['\u{a75d}', '\u{0}', '\u{0}']), ('\u{a75e}', ['\u{a75f}', '\u{0}', '\u{0}']), - ('\u{a760}', ['\u{a761}', '\u{0}', '\u{0}']), ('\u{a762}', ['\u{a763}', '\u{0}', '\u{0}']), - ('\u{a764}', ['\u{a765}', '\u{0}', '\u{0}']), ('\u{a766}', ['\u{a767}', '\u{0}', '\u{0}']), - ('\u{a768}', ['\u{a769}', '\u{0}', '\u{0}']), ('\u{a76a}', ['\u{a76b}', '\u{0}', '\u{0}']), - ('\u{a76c}', ['\u{a76d}', '\u{0}', '\u{0}']), ('\u{a76e}', ['\u{a76f}', '\u{0}', '\u{0}']), - ('\u{a779}', ['\u{a77a}', '\u{0}', '\u{0}']), ('\u{a77b}', ['\u{a77c}', '\u{0}', '\u{0}']), - ('\u{a77d}', ['\u{1d79}', '\u{0}', '\u{0}']), ('\u{a77e}', ['\u{a77f}', '\u{0}', '\u{0}']), - ('\u{a780}', ['\u{a781}', '\u{0}', '\u{0}']), ('\u{a782}', ['\u{a783}', '\u{0}', '\u{0}']), - ('\u{a784}', ['\u{a785}', '\u{0}', '\u{0}']), ('\u{a786}', ['\u{a787}', '\u{0}', '\u{0}']), - ('\u{a78b}', ['\u{a78c}', '\u{0}', '\u{0}']), ('\u{a78d}', ['\u{265}', '\u{0}', '\u{0}']), - ('\u{a790}', ['\u{a791}', '\u{0}', '\u{0}']), ('\u{a792}', ['\u{a793}', '\u{0}', '\u{0}']), - ('\u{a796}', ['\u{a797}', '\u{0}', '\u{0}']), ('\u{a798}', ['\u{a799}', '\u{0}', '\u{0}']), - ('\u{a79a}', ['\u{a79b}', '\u{0}', '\u{0}']), ('\u{a79c}', ['\u{a79d}', '\u{0}', '\u{0}']), - ('\u{a79e}', ['\u{a79f}', '\u{0}', '\u{0}']), ('\u{a7a0}', ['\u{a7a1}', '\u{0}', '\u{0}']), - ('\u{a7a2}', ['\u{a7a3}', '\u{0}', '\u{0}']), ('\u{a7a4}', ['\u{a7a5}', '\u{0}', '\u{0}']), - ('\u{a7a6}', ['\u{a7a7}', '\u{0}', '\u{0}']), ('\u{a7a8}', ['\u{a7a9}', '\u{0}', '\u{0}']), - ('\u{a7aa}', ['\u{266}', '\u{0}', '\u{0}']), ('\u{a7ab}', ['\u{25c}', '\u{0}', '\u{0}']), - ('\u{a7ac}', ['\u{261}', '\u{0}', '\u{0}']), ('\u{a7ad}', ['\u{26c}', '\u{0}', '\u{0}']), - ('\u{a7ae}', ['\u{26a}', '\u{0}', '\u{0}']), ('\u{a7b0}', ['\u{29e}', '\u{0}', '\u{0}']), - ('\u{a7b1}', ['\u{287}', '\u{0}', '\u{0}']), ('\u{a7b2}', ['\u{29d}', '\u{0}', '\u{0}']), - ('\u{a7b3}', ['\u{ab53}', '\u{0}', '\u{0}']), ('\u{a7b4}', ['\u{a7b5}', '\u{0}', '\u{0}']), - ('\u{a7b6}', ['\u{a7b7}', '\u{0}', '\u{0}']), ('\u{a7b8}', ['\u{a7b9}', '\u{0}', '\u{0}']), - ('\u{a7ba}', ['\u{a7bb}', '\u{0}', '\u{0}']), ('\u{a7bc}', ['\u{a7bd}', '\u{0}', '\u{0}']), - ('\u{a7be}', ['\u{a7bf}', '\u{0}', '\u{0}']), ('\u{a7c2}', ['\u{a7c3}', '\u{0}', '\u{0}']), + ('\u{2c2e}', ['\u{2c5e}', '\u{0}', '\u{0}']), ('\u{2c2f}', ['\u{2c5f}', '\u{0}', '\u{0}']), + ('\u{2c60}', ['\u{2c61}', '\u{0}', '\u{0}']), ('\u{2c62}', ['\u{26b}', '\u{0}', '\u{0}']), + ('\u{2c63}', ['\u{1d7d}', '\u{0}', '\u{0}']), ('\u{2c64}', ['\u{27d}', '\u{0}', '\u{0}']), + ('\u{2c67}', ['\u{2c68}', '\u{0}', '\u{0}']), ('\u{2c69}', ['\u{2c6a}', '\u{0}', '\u{0}']), + ('\u{2c6b}', ['\u{2c6c}', '\u{0}', '\u{0}']), ('\u{2c6d}', ['\u{251}', '\u{0}', '\u{0}']), + ('\u{2c6e}', ['\u{271}', '\u{0}', '\u{0}']), ('\u{2c6f}', ['\u{250}', '\u{0}', '\u{0}']), + ('\u{2c70}', ['\u{252}', '\u{0}', '\u{0}']), ('\u{2c72}', ['\u{2c73}', '\u{0}', '\u{0}']), + ('\u{2c75}', ['\u{2c76}', '\u{0}', '\u{0}']), ('\u{2c7e}', ['\u{23f}', '\u{0}', '\u{0}']), + ('\u{2c7f}', ['\u{240}', '\u{0}', '\u{0}']), ('\u{2c80}', ['\u{2c81}', '\u{0}', '\u{0}']), + ('\u{2c82}', ['\u{2c83}', '\u{0}', '\u{0}']), ('\u{2c84}', ['\u{2c85}', '\u{0}', '\u{0}']), + ('\u{2c86}', ['\u{2c87}', '\u{0}', '\u{0}']), ('\u{2c88}', ['\u{2c89}', '\u{0}', '\u{0}']), + ('\u{2c8a}', ['\u{2c8b}', '\u{0}', '\u{0}']), ('\u{2c8c}', ['\u{2c8d}', '\u{0}', '\u{0}']), + ('\u{2c8e}', ['\u{2c8f}', '\u{0}', '\u{0}']), ('\u{2c90}', ['\u{2c91}', '\u{0}', '\u{0}']), + ('\u{2c92}', ['\u{2c93}', '\u{0}', '\u{0}']), ('\u{2c94}', ['\u{2c95}', '\u{0}', '\u{0}']), + ('\u{2c96}', ['\u{2c97}', '\u{0}', '\u{0}']), ('\u{2c98}', ['\u{2c99}', '\u{0}', '\u{0}']), + ('\u{2c9a}', ['\u{2c9b}', '\u{0}', '\u{0}']), ('\u{2c9c}', ['\u{2c9d}', '\u{0}', '\u{0}']), + ('\u{2c9e}', ['\u{2c9f}', '\u{0}', '\u{0}']), ('\u{2ca0}', ['\u{2ca1}', '\u{0}', '\u{0}']), + ('\u{2ca2}', ['\u{2ca3}', '\u{0}', '\u{0}']), ('\u{2ca4}', ['\u{2ca5}', '\u{0}', '\u{0}']), + ('\u{2ca6}', ['\u{2ca7}', '\u{0}', '\u{0}']), ('\u{2ca8}', ['\u{2ca9}', '\u{0}', '\u{0}']), + ('\u{2caa}', ['\u{2cab}', '\u{0}', '\u{0}']), ('\u{2cac}', ['\u{2cad}', '\u{0}', '\u{0}']), + ('\u{2cae}', ['\u{2caf}', '\u{0}', '\u{0}']), ('\u{2cb0}', ['\u{2cb1}', '\u{0}', '\u{0}']), + ('\u{2cb2}', ['\u{2cb3}', '\u{0}', '\u{0}']), ('\u{2cb4}', ['\u{2cb5}', '\u{0}', '\u{0}']), + ('\u{2cb6}', ['\u{2cb7}', '\u{0}', '\u{0}']), ('\u{2cb8}', ['\u{2cb9}', '\u{0}', '\u{0}']), + ('\u{2cba}', ['\u{2cbb}', '\u{0}', '\u{0}']), ('\u{2cbc}', ['\u{2cbd}', '\u{0}', '\u{0}']), + ('\u{2cbe}', ['\u{2cbf}', '\u{0}', '\u{0}']), ('\u{2cc0}', ['\u{2cc1}', '\u{0}', '\u{0}']), + ('\u{2cc2}', ['\u{2cc3}', '\u{0}', '\u{0}']), ('\u{2cc4}', ['\u{2cc5}', '\u{0}', '\u{0}']), + ('\u{2cc6}', ['\u{2cc7}', '\u{0}', '\u{0}']), ('\u{2cc8}', ['\u{2cc9}', '\u{0}', '\u{0}']), + ('\u{2cca}', ['\u{2ccb}', '\u{0}', '\u{0}']), ('\u{2ccc}', ['\u{2ccd}', '\u{0}', '\u{0}']), + ('\u{2cce}', ['\u{2ccf}', '\u{0}', '\u{0}']), ('\u{2cd0}', ['\u{2cd1}', '\u{0}', '\u{0}']), + ('\u{2cd2}', ['\u{2cd3}', '\u{0}', '\u{0}']), ('\u{2cd4}', ['\u{2cd5}', '\u{0}', '\u{0}']), + ('\u{2cd6}', ['\u{2cd7}', '\u{0}', '\u{0}']), ('\u{2cd8}', ['\u{2cd9}', '\u{0}', '\u{0}']), + ('\u{2cda}', ['\u{2cdb}', '\u{0}', '\u{0}']), ('\u{2cdc}', ['\u{2cdd}', '\u{0}', '\u{0}']), + ('\u{2cde}', ['\u{2cdf}', '\u{0}', '\u{0}']), ('\u{2ce0}', ['\u{2ce1}', '\u{0}', '\u{0}']), + ('\u{2ce2}', ['\u{2ce3}', '\u{0}', '\u{0}']), ('\u{2ceb}', ['\u{2cec}', '\u{0}', '\u{0}']), + ('\u{2ced}', ['\u{2cee}', '\u{0}', '\u{0}']), ('\u{2cf2}', ['\u{2cf3}', '\u{0}', '\u{0}']), + ('\u{a640}', ['\u{a641}', '\u{0}', '\u{0}']), ('\u{a642}', ['\u{a643}', '\u{0}', '\u{0}']), + ('\u{a644}', ['\u{a645}', '\u{0}', '\u{0}']), ('\u{a646}', ['\u{a647}', '\u{0}', '\u{0}']), + ('\u{a648}', ['\u{a649}', '\u{0}', '\u{0}']), ('\u{a64a}', ['\u{a64b}', '\u{0}', '\u{0}']), + ('\u{a64c}', ['\u{a64d}', '\u{0}', '\u{0}']), ('\u{a64e}', ['\u{a64f}', '\u{0}', '\u{0}']), + ('\u{a650}', ['\u{a651}', '\u{0}', '\u{0}']), ('\u{a652}', ['\u{a653}', '\u{0}', '\u{0}']), + ('\u{a654}', ['\u{a655}', '\u{0}', '\u{0}']), ('\u{a656}', ['\u{a657}', '\u{0}', '\u{0}']), + ('\u{a658}', ['\u{a659}', '\u{0}', '\u{0}']), ('\u{a65a}', ['\u{a65b}', '\u{0}', '\u{0}']), + ('\u{a65c}', ['\u{a65d}', '\u{0}', '\u{0}']), ('\u{a65e}', ['\u{a65f}', '\u{0}', '\u{0}']), + ('\u{a660}', ['\u{a661}', '\u{0}', '\u{0}']), ('\u{a662}', ['\u{a663}', '\u{0}', '\u{0}']), + ('\u{a664}', ['\u{a665}', '\u{0}', '\u{0}']), ('\u{a666}', ['\u{a667}', '\u{0}', '\u{0}']), + ('\u{a668}', ['\u{a669}', '\u{0}', '\u{0}']), ('\u{a66a}', ['\u{a66b}', '\u{0}', '\u{0}']), + ('\u{a66c}', ['\u{a66d}', '\u{0}', '\u{0}']), ('\u{a680}', ['\u{a681}', '\u{0}', '\u{0}']), + ('\u{a682}', ['\u{a683}', '\u{0}', '\u{0}']), ('\u{a684}', ['\u{a685}', '\u{0}', '\u{0}']), + ('\u{a686}', ['\u{a687}', '\u{0}', '\u{0}']), ('\u{a688}', ['\u{a689}', '\u{0}', '\u{0}']), + ('\u{a68a}', ['\u{a68b}', '\u{0}', '\u{0}']), ('\u{a68c}', ['\u{a68d}', '\u{0}', '\u{0}']), + ('\u{a68e}', ['\u{a68f}', '\u{0}', '\u{0}']), ('\u{a690}', ['\u{a691}', '\u{0}', '\u{0}']), + ('\u{a692}', ['\u{a693}', '\u{0}', '\u{0}']), ('\u{a694}', ['\u{a695}', '\u{0}', '\u{0}']), + ('\u{a696}', ['\u{a697}', '\u{0}', '\u{0}']), ('\u{a698}', ['\u{a699}', '\u{0}', '\u{0}']), + ('\u{a69a}', ['\u{a69b}', '\u{0}', '\u{0}']), ('\u{a722}', ['\u{a723}', '\u{0}', '\u{0}']), + ('\u{a724}', ['\u{a725}', '\u{0}', '\u{0}']), ('\u{a726}', ['\u{a727}', '\u{0}', '\u{0}']), + ('\u{a728}', ['\u{a729}', '\u{0}', '\u{0}']), ('\u{a72a}', ['\u{a72b}', '\u{0}', '\u{0}']), + ('\u{a72c}', ['\u{a72d}', '\u{0}', '\u{0}']), ('\u{a72e}', ['\u{a72f}', '\u{0}', '\u{0}']), + ('\u{a732}', ['\u{a733}', '\u{0}', '\u{0}']), ('\u{a734}', ['\u{a735}', '\u{0}', '\u{0}']), + ('\u{a736}', ['\u{a737}', '\u{0}', '\u{0}']), ('\u{a738}', ['\u{a739}', '\u{0}', '\u{0}']), + ('\u{a73a}', ['\u{a73b}', '\u{0}', '\u{0}']), ('\u{a73c}', ['\u{a73d}', '\u{0}', '\u{0}']), + ('\u{a73e}', ['\u{a73f}', '\u{0}', '\u{0}']), ('\u{a740}', ['\u{a741}', '\u{0}', '\u{0}']), + ('\u{a742}', ['\u{a743}', '\u{0}', '\u{0}']), ('\u{a744}', ['\u{a745}', '\u{0}', '\u{0}']), + ('\u{a746}', ['\u{a747}', '\u{0}', '\u{0}']), ('\u{a748}', ['\u{a749}', '\u{0}', '\u{0}']), + ('\u{a74a}', ['\u{a74b}', '\u{0}', '\u{0}']), ('\u{a74c}', ['\u{a74d}', '\u{0}', '\u{0}']), + ('\u{a74e}', ['\u{a74f}', '\u{0}', '\u{0}']), ('\u{a750}', ['\u{a751}', '\u{0}', '\u{0}']), + ('\u{a752}', ['\u{a753}', '\u{0}', '\u{0}']), ('\u{a754}', ['\u{a755}', '\u{0}', '\u{0}']), + ('\u{a756}', ['\u{a757}', '\u{0}', '\u{0}']), ('\u{a758}', ['\u{a759}', '\u{0}', '\u{0}']), + ('\u{a75a}', ['\u{a75b}', '\u{0}', '\u{0}']), ('\u{a75c}', ['\u{a75d}', '\u{0}', '\u{0}']), + ('\u{a75e}', ['\u{a75f}', '\u{0}', '\u{0}']), ('\u{a760}', ['\u{a761}', '\u{0}', '\u{0}']), + ('\u{a762}', ['\u{a763}', '\u{0}', '\u{0}']), ('\u{a764}', ['\u{a765}', '\u{0}', '\u{0}']), + ('\u{a766}', ['\u{a767}', '\u{0}', '\u{0}']), ('\u{a768}', ['\u{a769}', '\u{0}', '\u{0}']), + ('\u{a76a}', ['\u{a76b}', '\u{0}', '\u{0}']), ('\u{a76c}', ['\u{a76d}', '\u{0}', '\u{0}']), + ('\u{a76e}', ['\u{a76f}', '\u{0}', '\u{0}']), ('\u{a779}', ['\u{a77a}', '\u{0}', '\u{0}']), + ('\u{a77b}', ['\u{a77c}', '\u{0}', '\u{0}']), ('\u{a77d}', ['\u{1d79}', '\u{0}', '\u{0}']), + ('\u{a77e}', ['\u{a77f}', '\u{0}', '\u{0}']), ('\u{a780}', ['\u{a781}', '\u{0}', '\u{0}']), + ('\u{a782}', ['\u{a783}', '\u{0}', '\u{0}']), ('\u{a784}', ['\u{a785}', '\u{0}', '\u{0}']), + ('\u{a786}', ['\u{a787}', '\u{0}', '\u{0}']), ('\u{a78b}', ['\u{a78c}', '\u{0}', '\u{0}']), + ('\u{a78d}', ['\u{265}', '\u{0}', '\u{0}']), ('\u{a790}', ['\u{a791}', '\u{0}', '\u{0}']), + ('\u{a792}', ['\u{a793}', '\u{0}', '\u{0}']), ('\u{a796}', ['\u{a797}', '\u{0}', '\u{0}']), + ('\u{a798}', ['\u{a799}', '\u{0}', '\u{0}']), ('\u{a79a}', ['\u{a79b}', '\u{0}', '\u{0}']), + ('\u{a79c}', ['\u{a79d}', '\u{0}', '\u{0}']), ('\u{a79e}', ['\u{a79f}', '\u{0}', '\u{0}']), + ('\u{a7a0}', ['\u{a7a1}', '\u{0}', '\u{0}']), ('\u{a7a2}', ['\u{a7a3}', '\u{0}', '\u{0}']), + ('\u{a7a4}', ['\u{a7a5}', '\u{0}', '\u{0}']), ('\u{a7a6}', ['\u{a7a7}', '\u{0}', '\u{0}']), + ('\u{a7a8}', ['\u{a7a9}', '\u{0}', '\u{0}']), ('\u{a7aa}', ['\u{266}', '\u{0}', '\u{0}']), + ('\u{a7ab}', ['\u{25c}', '\u{0}', '\u{0}']), ('\u{a7ac}', ['\u{261}', '\u{0}', '\u{0}']), + ('\u{a7ad}', ['\u{26c}', '\u{0}', '\u{0}']), ('\u{a7ae}', ['\u{26a}', '\u{0}', '\u{0}']), + ('\u{a7b0}', ['\u{29e}', '\u{0}', '\u{0}']), ('\u{a7b1}', ['\u{287}', '\u{0}', '\u{0}']), + ('\u{a7b2}', ['\u{29d}', '\u{0}', '\u{0}']), ('\u{a7b3}', ['\u{ab53}', '\u{0}', '\u{0}']), + ('\u{a7b4}', ['\u{a7b5}', '\u{0}', '\u{0}']), ('\u{a7b6}', ['\u{a7b7}', '\u{0}', '\u{0}']), + ('\u{a7b8}', ['\u{a7b9}', '\u{0}', '\u{0}']), ('\u{a7ba}', ['\u{a7bb}', '\u{0}', '\u{0}']), + ('\u{a7bc}', ['\u{a7bd}', '\u{0}', '\u{0}']), ('\u{a7be}', ['\u{a7bf}', '\u{0}', '\u{0}']), + ('\u{a7c0}', ['\u{a7c1}', '\u{0}', '\u{0}']), ('\u{a7c2}', ['\u{a7c3}', '\u{0}', '\u{0}']), ('\u{a7c4}', ['\u{a794}', '\u{0}', '\u{0}']), ('\u{a7c5}', ['\u{282}', '\u{0}', '\u{0}']), ('\u{a7c6}', ['\u{1d8e}', '\u{0}', '\u{0}']), ('\u{a7c7}', ['\u{a7c8}', '\u{0}', '\u{0}']), - ('\u{a7c9}', ['\u{a7ca}', '\u{0}', '\u{0}']), ('\u{a7f5}', ['\u{a7f6}', '\u{0}', '\u{0}']), - ('\u{ff21}', ['\u{ff41}', '\u{0}', '\u{0}']), ('\u{ff22}', ['\u{ff42}', '\u{0}', '\u{0}']), - ('\u{ff23}', ['\u{ff43}', '\u{0}', '\u{0}']), ('\u{ff24}', ['\u{ff44}', '\u{0}', '\u{0}']), - ('\u{ff25}', ['\u{ff45}', '\u{0}', '\u{0}']), ('\u{ff26}', ['\u{ff46}', '\u{0}', '\u{0}']), - ('\u{ff27}', ['\u{ff47}', '\u{0}', '\u{0}']), ('\u{ff28}', ['\u{ff48}', '\u{0}', '\u{0}']), - ('\u{ff29}', ['\u{ff49}', '\u{0}', '\u{0}']), ('\u{ff2a}', ['\u{ff4a}', '\u{0}', '\u{0}']), - ('\u{ff2b}', ['\u{ff4b}', '\u{0}', '\u{0}']), ('\u{ff2c}', ['\u{ff4c}', '\u{0}', '\u{0}']), - ('\u{ff2d}', ['\u{ff4d}', '\u{0}', '\u{0}']), ('\u{ff2e}', ['\u{ff4e}', '\u{0}', '\u{0}']), - ('\u{ff2f}', ['\u{ff4f}', '\u{0}', '\u{0}']), ('\u{ff30}', ['\u{ff50}', '\u{0}', '\u{0}']), - ('\u{ff31}', ['\u{ff51}', '\u{0}', '\u{0}']), ('\u{ff32}', ['\u{ff52}', '\u{0}', '\u{0}']), - ('\u{ff33}', ['\u{ff53}', '\u{0}', '\u{0}']), ('\u{ff34}', ['\u{ff54}', '\u{0}', '\u{0}']), - ('\u{ff35}', ['\u{ff55}', '\u{0}', '\u{0}']), ('\u{ff36}', ['\u{ff56}', '\u{0}', '\u{0}']), - ('\u{ff37}', ['\u{ff57}', '\u{0}', '\u{0}']), ('\u{ff38}', ['\u{ff58}', '\u{0}', '\u{0}']), - ('\u{ff39}', ['\u{ff59}', '\u{0}', '\u{0}']), ('\u{ff3a}', ['\u{ff5a}', '\u{0}', '\u{0}']), + ('\u{a7c9}', ['\u{a7ca}', '\u{0}', '\u{0}']), ('\u{a7d0}', ['\u{a7d1}', '\u{0}', '\u{0}']), + ('\u{a7d6}', ['\u{a7d7}', '\u{0}', '\u{0}']), ('\u{a7d8}', ['\u{a7d9}', '\u{0}', '\u{0}']), + ('\u{a7f5}', ['\u{a7f6}', '\u{0}', '\u{0}']), ('\u{ff21}', ['\u{ff41}', '\u{0}', '\u{0}']), + ('\u{ff22}', ['\u{ff42}', '\u{0}', '\u{0}']), ('\u{ff23}', ['\u{ff43}', '\u{0}', '\u{0}']), + ('\u{ff24}', ['\u{ff44}', '\u{0}', '\u{0}']), ('\u{ff25}', ['\u{ff45}', '\u{0}', '\u{0}']), + ('\u{ff26}', ['\u{ff46}', '\u{0}', '\u{0}']), ('\u{ff27}', ['\u{ff47}', '\u{0}', '\u{0}']), + ('\u{ff28}', ['\u{ff48}', '\u{0}', '\u{0}']), ('\u{ff29}', ['\u{ff49}', '\u{0}', '\u{0}']), + ('\u{ff2a}', ['\u{ff4a}', '\u{0}', '\u{0}']), ('\u{ff2b}', ['\u{ff4b}', '\u{0}', '\u{0}']), + ('\u{ff2c}', ['\u{ff4c}', '\u{0}', '\u{0}']), ('\u{ff2d}', ['\u{ff4d}', '\u{0}', '\u{0}']), + ('\u{ff2e}', ['\u{ff4e}', '\u{0}', '\u{0}']), ('\u{ff2f}', ['\u{ff4f}', '\u{0}', '\u{0}']), + ('\u{ff30}', ['\u{ff50}', '\u{0}', '\u{0}']), ('\u{ff31}', ['\u{ff51}', '\u{0}', '\u{0}']), + ('\u{ff32}', ['\u{ff52}', '\u{0}', '\u{0}']), ('\u{ff33}', ['\u{ff53}', '\u{0}', '\u{0}']), + ('\u{ff34}', ['\u{ff54}', '\u{0}', '\u{0}']), ('\u{ff35}', ['\u{ff55}', '\u{0}', '\u{0}']), + ('\u{ff36}', ['\u{ff56}', '\u{0}', '\u{0}']), ('\u{ff37}', ['\u{ff57}', '\u{0}', '\u{0}']), + ('\u{ff38}', ['\u{ff58}', '\u{0}', '\u{0}']), ('\u{ff39}', ['\u{ff59}', '\u{0}', '\u{0}']), + ('\u{ff3a}', ['\u{ff5a}', '\u{0}', '\u{0}']), ('\u{10400}', ['\u{10428}', '\u{0}', '\u{0}']), ('\u{10401}', ['\u{10429}', '\u{0}', '\u{0}']), ('\u{10402}', ['\u{1042a}', '\u{0}', '\u{0}']), @@ -1234,6 +1250,41 @@ ('\u{104d1}', ['\u{104f9}', '\u{0}', '\u{0}']), ('\u{104d2}', ['\u{104fa}', '\u{0}', '\u{0}']), ('\u{104d3}', ['\u{104fb}', '\u{0}', '\u{0}']), + ('\u{10570}', ['\u{10597}', '\u{0}', '\u{0}']), + ('\u{10571}', ['\u{10598}', '\u{0}', '\u{0}']), + ('\u{10572}', ['\u{10599}', '\u{0}', '\u{0}']), + ('\u{10573}', ['\u{1059a}', '\u{0}', '\u{0}']), + ('\u{10574}', ['\u{1059b}', '\u{0}', '\u{0}']), + ('\u{10575}', ['\u{1059c}', '\u{0}', '\u{0}']), + ('\u{10576}', ['\u{1059d}', '\u{0}', '\u{0}']), + ('\u{10577}', ['\u{1059e}', '\u{0}', '\u{0}']), + ('\u{10578}', ['\u{1059f}', '\u{0}', '\u{0}']), + ('\u{10579}', ['\u{105a0}', '\u{0}', '\u{0}']), + ('\u{1057a}', ['\u{105a1}', '\u{0}', '\u{0}']), + ('\u{1057c}', ['\u{105a3}', '\u{0}', '\u{0}']), + ('\u{1057d}', ['\u{105a4}', '\u{0}', '\u{0}']), + ('\u{1057e}', ['\u{105a5}', '\u{0}', '\u{0}']), + ('\u{1057f}', ['\u{105a6}', '\u{0}', '\u{0}']), + ('\u{10580}', ['\u{105a7}', '\u{0}', '\u{0}']), + ('\u{10581}', ['\u{105a8}', '\u{0}', '\u{0}']), + ('\u{10582}', ['\u{105a9}', '\u{0}', '\u{0}']), + ('\u{10583}', ['\u{105aa}', '\u{0}', '\u{0}']), + ('\u{10584}', ['\u{105ab}', '\u{0}', '\u{0}']), + ('\u{10585}', ['\u{105ac}', '\u{0}', '\u{0}']), + ('\u{10586}', ['\u{105ad}', '\u{0}', '\u{0}']), + ('\u{10587}', ['\u{105ae}', '\u{0}', '\u{0}']), + ('\u{10588}', ['\u{105af}', '\u{0}', '\u{0}']), + ('\u{10589}', ['\u{105b0}', '\u{0}', '\u{0}']), + ('\u{1058a}', ['\u{105b1}', '\u{0}', '\u{0}']), + ('\u{1058c}', ['\u{105b3}', '\u{0}', '\u{0}']), + ('\u{1058d}', ['\u{105b4}', '\u{0}', '\u{0}']), + ('\u{1058e}', ['\u{105b5}', '\u{0}', '\u{0}']), + ('\u{1058f}', ['\u{105b6}', '\u{0}', '\u{0}']), + ('\u{10590}', ['\u{105b7}', '\u{0}', '\u{0}']), + ('\u{10591}', ['\u{105b8}', '\u{0}', '\u{0}']), + ('\u{10592}', ['\u{105b9}', '\u{0}', '\u{0}']), + ('\u{10594}', ['\u{105bb}', '\u{0}', '\u{0}']), + ('\u{10595}', ['\u{105bc}', '\u{0}', '\u{0}']), ('\u{10c80}', ['\u{10cc0}', '\u{0}', '\u{0}']), ('\u{10c81}', ['\u{10cc1}', '\u{0}', '\u{0}']), ('\u{10c82}', ['\u{10cc2}', '\u{0}', '\u{0}']), @@ -1892,154 +1943,157 @@ ('\u{2c59}', ['\u{2c29}', '\u{0}', '\u{0}']), ('\u{2c5a}', ['\u{2c2a}', '\u{0}', '\u{0}']), ('\u{2c5b}', ['\u{2c2b}', '\u{0}', '\u{0}']), ('\u{2c5c}', ['\u{2c2c}', '\u{0}', '\u{0}']), ('\u{2c5d}', ['\u{2c2d}', '\u{0}', '\u{0}']), ('\u{2c5e}', ['\u{2c2e}', '\u{0}', '\u{0}']), - ('\u{2c61}', ['\u{2c60}', '\u{0}', '\u{0}']), ('\u{2c65}', ['\u{23a}', '\u{0}', '\u{0}']), - ('\u{2c66}', ['\u{23e}', '\u{0}', '\u{0}']), ('\u{2c68}', ['\u{2c67}', '\u{0}', '\u{0}']), - ('\u{2c6a}', ['\u{2c69}', '\u{0}', '\u{0}']), ('\u{2c6c}', ['\u{2c6b}', '\u{0}', '\u{0}']), - ('\u{2c73}', ['\u{2c72}', '\u{0}', '\u{0}']), ('\u{2c76}', ['\u{2c75}', '\u{0}', '\u{0}']), - ('\u{2c81}', ['\u{2c80}', '\u{0}', '\u{0}']), ('\u{2c83}', ['\u{2c82}', '\u{0}', '\u{0}']), - ('\u{2c85}', ['\u{2c84}', '\u{0}', '\u{0}']), ('\u{2c87}', ['\u{2c86}', '\u{0}', '\u{0}']), - ('\u{2c89}', ['\u{2c88}', '\u{0}', '\u{0}']), ('\u{2c8b}', ['\u{2c8a}', '\u{0}', '\u{0}']), - ('\u{2c8d}', ['\u{2c8c}', '\u{0}', '\u{0}']), ('\u{2c8f}', ['\u{2c8e}', '\u{0}', '\u{0}']), - ('\u{2c91}', ['\u{2c90}', '\u{0}', '\u{0}']), ('\u{2c93}', ['\u{2c92}', '\u{0}', '\u{0}']), - ('\u{2c95}', ['\u{2c94}', '\u{0}', '\u{0}']), ('\u{2c97}', ['\u{2c96}', '\u{0}', '\u{0}']), - ('\u{2c99}', ['\u{2c98}', '\u{0}', '\u{0}']), ('\u{2c9b}', ['\u{2c9a}', '\u{0}', '\u{0}']), - ('\u{2c9d}', ['\u{2c9c}', '\u{0}', '\u{0}']), ('\u{2c9f}', ['\u{2c9e}', '\u{0}', '\u{0}']), - ('\u{2ca1}', ['\u{2ca0}', '\u{0}', '\u{0}']), ('\u{2ca3}', ['\u{2ca2}', '\u{0}', '\u{0}']), - ('\u{2ca5}', ['\u{2ca4}', '\u{0}', '\u{0}']), ('\u{2ca7}', ['\u{2ca6}', '\u{0}', '\u{0}']), - ('\u{2ca9}', ['\u{2ca8}', '\u{0}', '\u{0}']), ('\u{2cab}', ['\u{2caa}', '\u{0}', '\u{0}']), - ('\u{2cad}', ['\u{2cac}', '\u{0}', '\u{0}']), ('\u{2caf}', ['\u{2cae}', '\u{0}', '\u{0}']), - ('\u{2cb1}', ['\u{2cb0}', '\u{0}', '\u{0}']), ('\u{2cb3}', ['\u{2cb2}', '\u{0}', '\u{0}']), - ('\u{2cb5}', ['\u{2cb4}', '\u{0}', '\u{0}']), ('\u{2cb7}', ['\u{2cb6}', '\u{0}', '\u{0}']), - ('\u{2cb9}', ['\u{2cb8}', '\u{0}', '\u{0}']), ('\u{2cbb}', ['\u{2cba}', '\u{0}', '\u{0}']), - ('\u{2cbd}', ['\u{2cbc}', '\u{0}', '\u{0}']), ('\u{2cbf}', ['\u{2cbe}', '\u{0}', '\u{0}']), - ('\u{2cc1}', ['\u{2cc0}', '\u{0}', '\u{0}']), ('\u{2cc3}', ['\u{2cc2}', '\u{0}', '\u{0}']), - ('\u{2cc5}', ['\u{2cc4}', '\u{0}', '\u{0}']), ('\u{2cc7}', ['\u{2cc6}', '\u{0}', '\u{0}']), - ('\u{2cc9}', ['\u{2cc8}', '\u{0}', '\u{0}']), ('\u{2ccb}', ['\u{2cca}', '\u{0}', '\u{0}']), - ('\u{2ccd}', ['\u{2ccc}', '\u{0}', '\u{0}']), ('\u{2ccf}', ['\u{2cce}', '\u{0}', '\u{0}']), - ('\u{2cd1}', ['\u{2cd0}', '\u{0}', '\u{0}']), ('\u{2cd3}', ['\u{2cd2}', '\u{0}', '\u{0}']), - ('\u{2cd5}', ['\u{2cd4}', '\u{0}', '\u{0}']), ('\u{2cd7}', ['\u{2cd6}', '\u{0}', '\u{0}']), - ('\u{2cd9}', ['\u{2cd8}', '\u{0}', '\u{0}']), ('\u{2cdb}', ['\u{2cda}', '\u{0}', '\u{0}']), - ('\u{2cdd}', ['\u{2cdc}', '\u{0}', '\u{0}']), ('\u{2cdf}', ['\u{2cde}', '\u{0}', '\u{0}']), - ('\u{2ce1}', ['\u{2ce0}', '\u{0}', '\u{0}']), ('\u{2ce3}', ['\u{2ce2}', '\u{0}', '\u{0}']), - ('\u{2cec}', ['\u{2ceb}', '\u{0}', '\u{0}']), ('\u{2cee}', ['\u{2ced}', '\u{0}', '\u{0}']), - ('\u{2cf3}', ['\u{2cf2}', '\u{0}', '\u{0}']), ('\u{2d00}', ['\u{10a0}', '\u{0}', '\u{0}']), - ('\u{2d01}', ['\u{10a1}', '\u{0}', '\u{0}']), ('\u{2d02}', ['\u{10a2}', '\u{0}', '\u{0}']), - ('\u{2d03}', ['\u{10a3}', '\u{0}', '\u{0}']), ('\u{2d04}', ['\u{10a4}', '\u{0}', '\u{0}']), - ('\u{2d05}', ['\u{10a5}', '\u{0}', '\u{0}']), ('\u{2d06}', ['\u{10a6}', '\u{0}', '\u{0}']), - ('\u{2d07}', ['\u{10a7}', '\u{0}', '\u{0}']), ('\u{2d08}', ['\u{10a8}', '\u{0}', '\u{0}']), - ('\u{2d09}', ['\u{10a9}', '\u{0}', '\u{0}']), ('\u{2d0a}', ['\u{10aa}', '\u{0}', '\u{0}']), - ('\u{2d0b}', ['\u{10ab}', '\u{0}', '\u{0}']), ('\u{2d0c}', ['\u{10ac}', '\u{0}', '\u{0}']), - ('\u{2d0d}', ['\u{10ad}', '\u{0}', '\u{0}']), ('\u{2d0e}', ['\u{10ae}', '\u{0}', '\u{0}']), - ('\u{2d0f}', ['\u{10af}', '\u{0}', '\u{0}']), ('\u{2d10}', ['\u{10b0}', '\u{0}', '\u{0}']), - ('\u{2d11}', ['\u{10b1}', '\u{0}', '\u{0}']), ('\u{2d12}', ['\u{10b2}', '\u{0}', '\u{0}']), - ('\u{2d13}', ['\u{10b3}', '\u{0}', '\u{0}']), ('\u{2d14}', ['\u{10b4}', '\u{0}', '\u{0}']), - ('\u{2d15}', ['\u{10b5}', '\u{0}', '\u{0}']), ('\u{2d16}', ['\u{10b6}', '\u{0}', '\u{0}']), - ('\u{2d17}', ['\u{10b7}', '\u{0}', '\u{0}']), ('\u{2d18}', ['\u{10b8}', '\u{0}', '\u{0}']), - ('\u{2d19}', ['\u{10b9}', '\u{0}', '\u{0}']), ('\u{2d1a}', ['\u{10ba}', '\u{0}', '\u{0}']), - ('\u{2d1b}', ['\u{10bb}', '\u{0}', '\u{0}']), ('\u{2d1c}', ['\u{10bc}', '\u{0}', '\u{0}']), - ('\u{2d1d}', ['\u{10bd}', '\u{0}', '\u{0}']), ('\u{2d1e}', ['\u{10be}', '\u{0}', '\u{0}']), - ('\u{2d1f}', ['\u{10bf}', '\u{0}', '\u{0}']), ('\u{2d20}', ['\u{10c0}', '\u{0}', '\u{0}']), - ('\u{2d21}', ['\u{10c1}', '\u{0}', '\u{0}']), ('\u{2d22}', ['\u{10c2}', '\u{0}', '\u{0}']), - ('\u{2d23}', ['\u{10c3}', '\u{0}', '\u{0}']), ('\u{2d24}', ['\u{10c4}', '\u{0}', '\u{0}']), - ('\u{2d25}', ['\u{10c5}', '\u{0}', '\u{0}']), ('\u{2d27}', ['\u{10c7}', '\u{0}', '\u{0}']), - ('\u{2d2d}', ['\u{10cd}', '\u{0}', '\u{0}']), ('\u{a641}', ['\u{a640}', '\u{0}', '\u{0}']), - ('\u{a643}', ['\u{a642}', '\u{0}', '\u{0}']), ('\u{a645}', ['\u{a644}', '\u{0}', '\u{0}']), - ('\u{a647}', ['\u{a646}', '\u{0}', '\u{0}']), ('\u{a649}', ['\u{a648}', '\u{0}', '\u{0}']), - ('\u{a64b}', ['\u{a64a}', '\u{0}', '\u{0}']), ('\u{a64d}', ['\u{a64c}', '\u{0}', '\u{0}']), - ('\u{a64f}', ['\u{a64e}', '\u{0}', '\u{0}']), ('\u{a651}', ['\u{a650}', '\u{0}', '\u{0}']), - ('\u{a653}', ['\u{a652}', '\u{0}', '\u{0}']), ('\u{a655}', ['\u{a654}', '\u{0}', '\u{0}']), - ('\u{a657}', ['\u{a656}', '\u{0}', '\u{0}']), ('\u{a659}', ['\u{a658}', '\u{0}', '\u{0}']), - ('\u{a65b}', ['\u{a65a}', '\u{0}', '\u{0}']), ('\u{a65d}', ['\u{a65c}', '\u{0}', '\u{0}']), - ('\u{a65f}', ['\u{a65e}', '\u{0}', '\u{0}']), ('\u{a661}', ['\u{a660}', '\u{0}', '\u{0}']), - ('\u{a663}', ['\u{a662}', '\u{0}', '\u{0}']), ('\u{a665}', ['\u{a664}', '\u{0}', '\u{0}']), - ('\u{a667}', ['\u{a666}', '\u{0}', '\u{0}']), ('\u{a669}', ['\u{a668}', '\u{0}', '\u{0}']), - ('\u{a66b}', ['\u{a66a}', '\u{0}', '\u{0}']), ('\u{a66d}', ['\u{a66c}', '\u{0}', '\u{0}']), - ('\u{a681}', ['\u{a680}', '\u{0}', '\u{0}']), ('\u{a683}', ['\u{a682}', '\u{0}', '\u{0}']), - ('\u{a685}', ['\u{a684}', '\u{0}', '\u{0}']), ('\u{a687}', ['\u{a686}', '\u{0}', '\u{0}']), - ('\u{a689}', ['\u{a688}', '\u{0}', '\u{0}']), ('\u{a68b}', ['\u{a68a}', '\u{0}', '\u{0}']), - ('\u{a68d}', ['\u{a68c}', '\u{0}', '\u{0}']), ('\u{a68f}', ['\u{a68e}', '\u{0}', '\u{0}']), - ('\u{a691}', ['\u{a690}', '\u{0}', '\u{0}']), ('\u{a693}', ['\u{a692}', '\u{0}', '\u{0}']), - ('\u{a695}', ['\u{a694}', '\u{0}', '\u{0}']), ('\u{a697}', ['\u{a696}', '\u{0}', '\u{0}']), - ('\u{a699}', ['\u{a698}', '\u{0}', '\u{0}']), ('\u{a69b}', ['\u{a69a}', '\u{0}', '\u{0}']), - ('\u{a723}', ['\u{a722}', '\u{0}', '\u{0}']), ('\u{a725}', ['\u{a724}', '\u{0}', '\u{0}']), - ('\u{a727}', ['\u{a726}', '\u{0}', '\u{0}']), ('\u{a729}', ['\u{a728}', '\u{0}', '\u{0}']), - ('\u{a72b}', ['\u{a72a}', '\u{0}', '\u{0}']), ('\u{a72d}', ['\u{a72c}', '\u{0}', '\u{0}']), - ('\u{a72f}', ['\u{a72e}', '\u{0}', '\u{0}']), ('\u{a733}', ['\u{a732}', '\u{0}', '\u{0}']), - ('\u{a735}', ['\u{a734}', '\u{0}', '\u{0}']), ('\u{a737}', ['\u{a736}', '\u{0}', '\u{0}']), - ('\u{a739}', ['\u{a738}', '\u{0}', '\u{0}']), ('\u{a73b}', ['\u{a73a}', '\u{0}', '\u{0}']), - ('\u{a73d}', ['\u{a73c}', '\u{0}', '\u{0}']), ('\u{a73f}', ['\u{a73e}', '\u{0}', '\u{0}']), - ('\u{a741}', ['\u{a740}', '\u{0}', '\u{0}']), ('\u{a743}', ['\u{a742}', '\u{0}', '\u{0}']), - ('\u{a745}', ['\u{a744}', '\u{0}', '\u{0}']), ('\u{a747}', ['\u{a746}', '\u{0}', '\u{0}']), - ('\u{a749}', ['\u{a748}', '\u{0}', '\u{0}']), ('\u{a74b}', ['\u{a74a}', '\u{0}', '\u{0}']), - ('\u{a74d}', ['\u{a74c}', '\u{0}', '\u{0}']), ('\u{a74f}', ['\u{a74e}', '\u{0}', '\u{0}']), - ('\u{a751}', ['\u{a750}', '\u{0}', '\u{0}']), ('\u{a753}', ['\u{a752}', '\u{0}', '\u{0}']), - ('\u{a755}', ['\u{a754}', '\u{0}', '\u{0}']), ('\u{a757}', ['\u{a756}', '\u{0}', '\u{0}']), - ('\u{a759}', ['\u{a758}', '\u{0}', '\u{0}']), ('\u{a75b}', ['\u{a75a}', '\u{0}', '\u{0}']), - ('\u{a75d}', ['\u{a75c}', '\u{0}', '\u{0}']), ('\u{a75f}', ['\u{a75e}', '\u{0}', '\u{0}']), - ('\u{a761}', ['\u{a760}', '\u{0}', '\u{0}']), ('\u{a763}', ['\u{a762}', '\u{0}', '\u{0}']), - ('\u{a765}', ['\u{a764}', '\u{0}', '\u{0}']), ('\u{a767}', ['\u{a766}', '\u{0}', '\u{0}']), - ('\u{a769}', ['\u{a768}', '\u{0}', '\u{0}']), ('\u{a76b}', ['\u{a76a}', '\u{0}', '\u{0}']), - ('\u{a76d}', ['\u{a76c}', '\u{0}', '\u{0}']), ('\u{a76f}', ['\u{a76e}', '\u{0}', '\u{0}']), - ('\u{a77a}', ['\u{a779}', '\u{0}', '\u{0}']), ('\u{a77c}', ['\u{a77b}', '\u{0}', '\u{0}']), - ('\u{a77f}', ['\u{a77e}', '\u{0}', '\u{0}']), ('\u{a781}', ['\u{a780}', '\u{0}', '\u{0}']), - ('\u{a783}', ['\u{a782}', '\u{0}', '\u{0}']), ('\u{a785}', ['\u{a784}', '\u{0}', '\u{0}']), - ('\u{a787}', ['\u{a786}', '\u{0}', '\u{0}']), ('\u{a78c}', ['\u{a78b}', '\u{0}', '\u{0}']), - ('\u{a791}', ['\u{a790}', '\u{0}', '\u{0}']), ('\u{a793}', ['\u{a792}', '\u{0}', '\u{0}']), - ('\u{a794}', ['\u{a7c4}', '\u{0}', '\u{0}']), ('\u{a797}', ['\u{a796}', '\u{0}', '\u{0}']), - ('\u{a799}', ['\u{a798}', '\u{0}', '\u{0}']), ('\u{a79b}', ['\u{a79a}', '\u{0}', '\u{0}']), - ('\u{a79d}', ['\u{a79c}', '\u{0}', '\u{0}']), ('\u{a79f}', ['\u{a79e}', '\u{0}', '\u{0}']), - ('\u{a7a1}', ['\u{a7a0}', '\u{0}', '\u{0}']), ('\u{a7a3}', ['\u{a7a2}', '\u{0}', '\u{0}']), - ('\u{a7a5}', ['\u{a7a4}', '\u{0}', '\u{0}']), ('\u{a7a7}', ['\u{a7a6}', '\u{0}', '\u{0}']), - ('\u{a7a9}', ['\u{a7a8}', '\u{0}', '\u{0}']), ('\u{a7b5}', ['\u{a7b4}', '\u{0}', '\u{0}']), - ('\u{a7b7}', ['\u{a7b6}', '\u{0}', '\u{0}']), ('\u{a7b9}', ['\u{a7b8}', '\u{0}', '\u{0}']), - ('\u{a7bb}', ['\u{a7ba}', '\u{0}', '\u{0}']), ('\u{a7bd}', ['\u{a7bc}', '\u{0}', '\u{0}']), - ('\u{a7bf}', ['\u{a7be}', '\u{0}', '\u{0}']), ('\u{a7c3}', ['\u{a7c2}', '\u{0}', '\u{0}']), + ('\u{2c5f}', ['\u{2c2f}', '\u{0}', '\u{0}']), ('\u{2c61}', ['\u{2c60}', '\u{0}', '\u{0}']), + ('\u{2c65}', ['\u{23a}', '\u{0}', '\u{0}']), ('\u{2c66}', ['\u{23e}', '\u{0}', '\u{0}']), + ('\u{2c68}', ['\u{2c67}', '\u{0}', '\u{0}']), ('\u{2c6a}', ['\u{2c69}', '\u{0}', '\u{0}']), + ('\u{2c6c}', ['\u{2c6b}', '\u{0}', '\u{0}']), ('\u{2c73}', ['\u{2c72}', '\u{0}', '\u{0}']), + ('\u{2c76}', ['\u{2c75}', '\u{0}', '\u{0}']), ('\u{2c81}', ['\u{2c80}', '\u{0}', '\u{0}']), + ('\u{2c83}', ['\u{2c82}', '\u{0}', '\u{0}']), ('\u{2c85}', ['\u{2c84}', '\u{0}', '\u{0}']), + ('\u{2c87}', ['\u{2c86}', '\u{0}', '\u{0}']), ('\u{2c89}', ['\u{2c88}', '\u{0}', '\u{0}']), + ('\u{2c8b}', ['\u{2c8a}', '\u{0}', '\u{0}']), ('\u{2c8d}', ['\u{2c8c}', '\u{0}', '\u{0}']), + ('\u{2c8f}', ['\u{2c8e}', '\u{0}', '\u{0}']), ('\u{2c91}', ['\u{2c90}', '\u{0}', '\u{0}']), + ('\u{2c93}', ['\u{2c92}', '\u{0}', '\u{0}']), ('\u{2c95}', ['\u{2c94}', '\u{0}', '\u{0}']), + ('\u{2c97}', ['\u{2c96}', '\u{0}', '\u{0}']), ('\u{2c99}', ['\u{2c98}', '\u{0}', '\u{0}']), + ('\u{2c9b}', ['\u{2c9a}', '\u{0}', '\u{0}']), ('\u{2c9d}', ['\u{2c9c}', '\u{0}', '\u{0}']), + ('\u{2c9f}', ['\u{2c9e}', '\u{0}', '\u{0}']), ('\u{2ca1}', ['\u{2ca0}', '\u{0}', '\u{0}']), + ('\u{2ca3}', ['\u{2ca2}', '\u{0}', '\u{0}']), ('\u{2ca5}', ['\u{2ca4}', '\u{0}', '\u{0}']), + ('\u{2ca7}', ['\u{2ca6}', '\u{0}', '\u{0}']), ('\u{2ca9}', ['\u{2ca8}', '\u{0}', '\u{0}']), + ('\u{2cab}', ['\u{2caa}', '\u{0}', '\u{0}']), ('\u{2cad}', ['\u{2cac}', '\u{0}', '\u{0}']), + ('\u{2caf}', ['\u{2cae}', '\u{0}', '\u{0}']), ('\u{2cb1}', ['\u{2cb0}', '\u{0}', '\u{0}']), + ('\u{2cb3}', ['\u{2cb2}', '\u{0}', '\u{0}']), ('\u{2cb5}', ['\u{2cb4}', '\u{0}', '\u{0}']), + ('\u{2cb7}', ['\u{2cb6}', '\u{0}', '\u{0}']), ('\u{2cb9}', ['\u{2cb8}', '\u{0}', '\u{0}']), + ('\u{2cbb}', ['\u{2cba}', '\u{0}', '\u{0}']), ('\u{2cbd}', ['\u{2cbc}', '\u{0}', '\u{0}']), + ('\u{2cbf}', ['\u{2cbe}', '\u{0}', '\u{0}']), ('\u{2cc1}', ['\u{2cc0}', '\u{0}', '\u{0}']), + ('\u{2cc3}', ['\u{2cc2}', '\u{0}', '\u{0}']), ('\u{2cc5}', ['\u{2cc4}', '\u{0}', '\u{0}']), + ('\u{2cc7}', ['\u{2cc6}', '\u{0}', '\u{0}']), ('\u{2cc9}', ['\u{2cc8}', '\u{0}', '\u{0}']), + ('\u{2ccb}', ['\u{2cca}', '\u{0}', '\u{0}']), ('\u{2ccd}', ['\u{2ccc}', '\u{0}', '\u{0}']), + ('\u{2ccf}', ['\u{2cce}', '\u{0}', '\u{0}']), ('\u{2cd1}', ['\u{2cd0}', '\u{0}', '\u{0}']), + ('\u{2cd3}', ['\u{2cd2}', '\u{0}', '\u{0}']), ('\u{2cd5}', ['\u{2cd4}', '\u{0}', '\u{0}']), + ('\u{2cd7}', ['\u{2cd6}', '\u{0}', '\u{0}']), ('\u{2cd9}', ['\u{2cd8}', '\u{0}', '\u{0}']), + ('\u{2cdb}', ['\u{2cda}', '\u{0}', '\u{0}']), ('\u{2cdd}', ['\u{2cdc}', '\u{0}', '\u{0}']), + ('\u{2cdf}', ['\u{2cde}', '\u{0}', '\u{0}']), ('\u{2ce1}', ['\u{2ce0}', '\u{0}', '\u{0}']), + ('\u{2ce3}', ['\u{2ce2}', '\u{0}', '\u{0}']), ('\u{2cec}', ['\u{2ceb}', '\u{0}', '\u{0}']), + ('\u{2cee}', ['\u{2ced}', '\u{0}', '\u{0}']), ('\u{2cf3}', ['\u{2cf2}', '\u{0}', '\u{0}']), + ('\u{2d00}', ['\u{10a0}', '\u{0}', '\u{0}']), ('\u{2d01}', ['\u{10a1}', '\u{0}', '\u{0}']), + ('\u{2d02}', ['\u{10a2}', '\u{0}', '\u{0}']), ('\u{2d03}', ['\u{10a3}', '\u{0}', '\u{0}']), + ('\u{2d04}', ['\u{10a4}', '\u{0}', '\u{0}']), ('\u{2d05}', ['\u{10a5}', '\u{0}', '\u{0}']), + ('\u{2d06}', ['\u{10a6}', '\u{0}', '\u{0}']), ('\u{2d07}', ['\u{10a7}', '\u{0}', '\u{0}']), + ('\u{2d08}', ['\u{10a8}', '\u{0}', '\u{0}']), ('\u{2d09}', ['\u{10a9}', '\u{0}', '\u{0}']), + ('\u{2d0a}', ['\u{10aa}', '\u{0}', '\u{0}']), ('\u{2d0b}', ['\u{10ab}', '\u{0}', '\u{0}']), + ('\u{2d0c}', ['\u{10ac}', '\u{0}', '\u{0}']), ('\u{2d0d}', ['\u{10ad}', '\u{0}', '\u{0}']), + ('\u{2d0e}', ['\u{10ae}', '\u{0}', '\u{0}']), ('\u{2d0f}', ['\u{10af}', '\u{0}', '\u{0}']), + ('\u{2d10}', ['\u{10b0}', '\u{0}', '\u{0}']), ('\u{2d11}', ['\u{10b1}', '\u{0}', '\u{0}']), + ('\u{2d12}', ['\u{10b2}', '\u{0}', '\u{0}']), ('\u{2d13}', ['\u{10b3}', '\u{0}', '\u{0}']), + ('\u{2d14}', ['\u{10b4}', '\u{0}', '\u{0}']), ('\u{2d15}', ['\u{10b5}', '\u{0}', '\u{0}']), + ('\u{2d16}', ['\u{10b6}', '\u{0}', '\u{0}']), ('\u{2d17}', ['\u{10b7}', '\u{0}', '\u{0}']), + ('\u{2d18}', ['\u{10b8}', '\u{0}', '\u{0}']), ('\u{2d19}', ['\u{10b9}', '\u{0}', '\u{0}']), + ('\u{2d1a}', ['\u{10ba}', '\u{0}', '\u{0}']), ('\u{2d1b}', ['\u{10bb}', '\u{0}', '\u{0}']), + ('\u{2d1c}', ['\u{10bc}', '\u{0}', '\u{0}']), ('\u{2d1d}', ['\u{10bd}', '\u{0}', '\u{0}']), + ('\u{2d1e}', ['\u{10be}', '\u{0}', '\u{0}']), ('\u{2d1f}', ['\u{10bf}', '\u{0}', '\u{0}']), + ('\u{2d20}', ['\u{10c0}', '\u{0}', '\u{0}']), ('\u{2d21}', ['\u{10c1}', '\u{0}', '\u{0}']), + ('\u{2d22}', ['\u{10c2}', '\u{0}', '\u{0}']), ('\u{2d23}', ['\u{10c3}', '\u{0}', '\u{0}']), + ('\u{2d24}', ['\u{10c4}', '\u{0}', '\u{0}']), ('\u{2d25}', ['\u{10c5}', '\u{0}', '\u{0}']), + ('\u{2d27}', ['\u{10c7}', '\u{0}', '\u{0}']), ('\u{2d2d}', ['\u{10cd}', '\u{0}', '\u{0}']), + ('\u{a641}', ['\u{a640}', '\u{0}', '\u{0}']), ('\u{a643}', ['\u{a642}', '\u{0}', '\u{0}']), + ('\u{a645}', ['\u{a644}', '\u{0}', '\u{0}']), ('\u{a647}', ['\u{a646}', '\u{0}', '\u{0}']), + ('\u{a649}', ['\u{a648}', '\u{0}', '\u{0}']), ('\u{a64b}', ['\u{a64a}', '\u{0}', '\u{0}']), + ('\u{a64d}', ['\u{a64c}', '\u{0}', '\u{0}']), ('\u{a64f}', ['\u{a64e}', '\u{0}', '\u{0}']), + ('\u{a651}', ['\u{a650}', '\u{0}', '\u{0}']), ('\u{a653}', ['\u{a652}', '\u{0}', '\u{0}']), + ('\u{a655}', ['\u{a654}', '\u{0}', '\u{0}']), ('\u{a657}', ['\u{a656}', '\u{0}', '\u{0}']), + ('\u{a659}', ['\u{a658}', '\u{0}', '\u{0}']), ('\u{a65b}', ['\u{a65a}', '\u{0}', '\u{0}']), + ('\u{a65d}', ['\u{a65c}', '\u{0}', '\u{0}']), ('\u{a65f}', ['\u{a65e}', '\u{0}', '\u{0}']), + ('\u{a661}', ['\u{a660}', '\u{0}', '\u{0}']), ('\u{a663}', ['\u{a662}', '\u{0}', '\u{0}']), + ('\u{a665}', ['\u{a664}', '\u{0}', '\u{0}']), ('\u{a667}', ['\u{a666}', '\u{0}', '\u{0}']), + ('\u{a669}', ['\u{a668}', '\u{0}', '\u{0}']), ('\u{a66b}', ['\u{a66a}', '\u{0}', '\u{0}']), + ('\u{a66d}', ['\u{a66c}', '\u{0}', '\u{0}']), ('\u{a681}', ['\u{a680}', '\u{0}', '\u{0}']), + ('\u{a683}', ['\u{a682}', '\u{0}', '\u{0}']), ('\u{a685}', ['\u{a684}', '\u{0}', '\u{0}']), + ('\u{a687}', ['\u{a686}', '\u{0}', '\u{0}']), ('\u{a689}', ['\u{a688}', '\u{0}', '\u{0}']), + ('\u{a68b}', ['\u{a68a}', '\u{0}', '\u{0}']), ('\u{a68d}', ['\u{a68c}', '\u{0}', '\u{0}']), + ('\u{a68f}', ['\u{a68e}', '\u{0}', '\u{0}']), ('\u{a691}', ['\u{a690}', '\u{0}', '\u{0}']), + ('\u{a693}', ['\u{a692}', '\u{0}', '\u{0}']), ('\u{a695}', ['\u{a694}', '\u{0}', '\u{0}']), + ('\u{a697}', ['\u{a696}', '\u{0}', '\u{0}']), ('\u{a699}', ['\u{a698}', '\u{0}', '\u{0}']), + ('\u{a69b}', ['\u{a69a}', '\u{0}', '\u{0}']), ('\u{a723}', ['\u{a722}', '\u{0}', '\u{0}']), + ('\u{a725}', ['\u{a724}', '\u{0}', '\u{0}']), ('\u{a727}', ['\u{a726}', '\u{0}', '\u{0}']), + ('\u{a729}', ['\u{a728}', '\u{0}', '\u{0}']), ('\u{a72b}', ['\u{a72a}', '\u{0}', '\u{0}']), + ('\u{a72d}', ['\u{a72c}', '\u{0}', '\u{0}']), ('\u{a72f}', ['\u{a72e}', '\u{0}', '\u{0}']), + ('\u{a733}', ['\u{a732}', '\u{0}', '\u{0}']), ('\u{a735}', ['\u{a734}', '\u{0}', '\u{0}']), + ('\u{a737}', ['\u{a736}', '\u{0}', '\u{0}']), ('\u{a739}', ['\u{a738}', '\u{0}', '\u{0}']), + ('\u{a73b}', ['\u{a73a}', '\u{0}', '\u{0}']), ('\u{a73d}', ['\u{a73c}', '\u{0}', '\u{0}']), + ('\u{a73f}', ['\u{a73e}', '\u{0}', '\u{0}']), ('\u{a741}', ['\u{a740}', '\u{0}', '\u{0}']), + ('\u{a743}', ['\u{a742}', '\u{0}', '\u{0}']), ('\u{a745}', ['\u{a744}', '\u{0}', '\u{0}']), + ('\u{a747}', ['\u{a746}', '\u{0}', '\u{0}']), ('\u{a749}', ['\u{a748}', '\u{0}', '\u{0}']), + ('\u{a74b}', ['\u{a74a}', '\u{0}', '\u{0}']), ('\u{a74d}', ['\u{a74c}', '\u{0}', '\u{0}']), + ('\u{a74f}', ['\u{a74e}', '\u{0}', '\u{0}']), ('\u{a751}', ['\u{a750}', '\u{0}', '\u{0}']), + ('\u{a753}', ['\u{a752}', '\u{0}', '\u{0}']), ('\u{a755}', ['\u{a754}', '\u{0}', '\u{0}']), + ('\u{a757}', ['\u{a756}', '\u{0}', '\u{0}']), ('\u{a759}', ['\u{a758}', '\u{0}', '\u{0}']), + ('\u{a75b}', ['\u{a75a}', '\u{0}', '\u{0}']), ('\u{a75d}', ['\u{a75c}', '\u{0}', '\u{0}']), + ('\u{a75f}', ['\u{a75e}', '\u{0}', '\u{0}']), ('\u{a761}', ['\u{a760}', '\u{0}', '\u{0}']), + ('\u{a763}', ['\u{a762}', '\u{0}', '\u{0}']), ('\u{a765}', ['\u{a764}', '\u{0}', '\u{0}']), + ('\u{a767}', ['\u{a766}', '\u{0}', '\u{0}']), ('\u{a769}', ['\u{a768}', '\u{0}', '\u{0}']), + ('\u{a76b}', ['\u{a76a}', '\u{0}', '\u{0}']), ('\u{a76d}', ['\u{a76c}', '\u{0}', '\u{0}']), + ('\u{a76f}', ['\u{a76e}', '\u{0}', '\u{0}']), ('\u{a77a}', ['\u{a779}', '\u{0}', '\u{0}']), + ('\u{a77c}', ['\u{a77b}', '\u{0}', '\u{0}']), ('\u{a77f}', ['\u{a77e}', '\u{0}', '\u{0}']), + ('\u{a781}', ['\u{a780}', '\u{0}', '\u{0}']), ('\u{a783}', ['\u{a782}', '\u{0}', '\u{0}']), + ('\u{a785}', ['\u{a784}', '\u{0}', '\u{0}']), ('\u{a787}', ['\u{a786}', '\u{0}', '\u{0}']), + ('\u{a78c}', ['\u{a78b}', '\u{0}', '\u{0}']), ('\u{a791}', ['\u{a790}', '\u{0}', '\u{0}']), + ('\u{a793}', ['\u{a792}', '\u{0}', '\u{0}']), ('\u{a794}', ['\u{a7c4}', '\u{0}', '\u{0}']), + ('\u{a797}', ['\u{a796}', '\u{0}', '\u{0}']), ('\u{a799}', ['\u{a798}', '\u{0}', '\u{0}']), + ('\u{a79b}', ['\u{a79a}', '\u{0}', '\u{0}']), ('\u{a79d}', ['\u{a79c}', '\u{0}', '\u{0}']), + ('\u{a79f}', ['\u{a79e}', '\u{0}', '\u{0}']), ('\u{a7a1}', ['\u{a7a0}', '\u{0}', '\u{0}']), + ('\u{a7a3}', ['\u{a7a2}', '\u{0}', '\u{0}']), ('\u{a7a5}', ['\u{a7a4}', '\u{0}', '\u{0}']), + ('\u{a7a7}', ['\u{a7a6}', '\u{0}', '\u{0}']), ('\u{a7a9}', ['\u{a7a8}', '\u{0}', '\u{0}']), + ('\u{a7b5}', ['\u{a7b4}', '\u{0}', '\u{0}']), ('\u{a7b7}', ['\u{a7b6}', '\u{0}', '\u{0}']), + ('\u{a7b9}', ['\u{a7b8}', '\u{0}', '\u{0}']), ('\u{a7bb}', ['\u{a7ba}', '\u{0}', '\u{0}']), + ('\u{a7bd}', ['\u{a7bc}', '\u{0}', '\u{0}']), ('\u{a7bf}', ['\u{a7be}', '\u{0}', '\u{0}']), + ('\u{a7c1}', ['\u{a7c0}', '\u{0}', '\u{0}']), ('\u{a7c3}', ['\u{a7c2}', '\u{0}', '\u{0}']), ('\u{a7c8}', ['\u{a7c7}', '\u{0}', '\u{0}']), ('\u{a7ca}', ['\u{a7c9}', '\u{0}', '\u{0}']), - ('\u{a7f6}', ['\u{a7f5}', '\u{0}', '\u{0}']), ('\u{ab53}', ['\u{a7b3}', '\u{0}', '\u{0}']), - ('\u{ab70}', ['\u{13a0}', '\u{0}', '\u{0}']), ('\u{ab71}', ['\u{13a1}', '\u{0}', '\u{0}']), - ('\u{ab72}', ['\u{13a2}', '\u{0}', '\u{0}']), ('\u{ab73}', ['\u{13a3}', '\u{0}', '\u{0}']), - ('\u{ab74}', ['\u{13a4}', '\u{0}', '\u{0}']), ('\u{ab75}', ['\u{13a5}', '\u{0}', '\u{0}']), - ('\u{ab76}', ['\u{13a6}', '\u{0}', '\u{0}']), ('\u{ab77}', ['\u{13a7}', '\u{0}', '\u{0}']), - ('\u{ab78}', ['\u{13a8}', '\u{0}', '\u{0}']), ('\u{ab79}', ['\u{13a9}', '\u{0}', '\u{0}']), - ('\u{ab7a}', ['\u{13aa}', '\u{0}', '\u{0}']), ('\u{ab7b}', ['\u{13ab}', '\u{0}', '\u{0}']), - ('\u{ab7c}', ['\u{13ac}', '\u{0}', '\u{0}']), ('\u{ab7d}', ['\u{13ad}', '\u{0}', '\u{0}']), - ('\u{ab7e}', ['\u{13ae}', '\u{0}', '\u{0}']), ('\u{ab7f}', ['\u{13af}', '\u{0}', '\u{0}']), - ('\u{ab80}', ['\u{13b0}', '\u{0}', '\u{0}']), ('\u{ab81}', ['\u{13b1}', '\u{0}', '\u{0}']), - ('\u{ab82}', ['\u{13b2}', '\u{0}', '\u{0}']), ('\u{ab83}', ['\u{13b3}', '\u{0}', '\u{0}']), - ('\u{ab84}', ['\u{13b4}', '\u{0}', '\u{0}']), ('\u{ab85}', ['\u{13b5}', '\u{0}', '\u{0}']), - ('\u{ab86}', ['\u{13b6}', '\u{0}', '\u{0}']), ('\u{ab87}', ['\u{13b7}', '\u{0}', '\u{0}']), - ('\u{ab88}', ['\u{13b8}', '\u{0}', '\u{0}']), ('\u{ab89}', ['\u{13b9}', '\u{0}', '\u{0}']), - ('\u{ab8a}', ['\u{13ba}', '\u{0}', '\u{0}']), ('\u{ab8b}', ['\u{13bb}', '\u{0}', '\u{0}']), - ('\u{ab8c}', ['\u{13bc}', '\u{0}', '\u{0}']), ('\u{ab8d}', ['\u{13bd}', '\u{0}', '\u{0}']), - ('\u{ab8e}', ['\u{13be}', '\u{0}', '\u{0}']), ('\u{ab8f}', ['\u{13bf}', '\u{0}', '\u{0}']), - ('\u{ab90}', ['\u{13c0}', '\u{0}', '\u{0}']), ('\u{ab91}', ['\u{13c1}', '\u{0}', '\u{0}']), - ('\u{ab92}', ['\u{13c2}', '\u{0}', '\u{0}']), ('\u{ab93}', ['\u{13c3}', '\u{0}', '\u{0}']), - ('\u{ab94}', ['\u{13c4}', '\u{0}', '\u{0}']), ('\u{ab95}', ['\u{13c5}', '\u{0}', '\u{0}']), - ('\u{ab96}', ['\u{13c6}', '\u{0}', '\u{0}']), ('\u{ab97}', ['\u{13c7}', '\u{0}', '\u{0}']), - ('\u{ab98}', ['\u{13c8}', '\u{0}', '\u{0}']), ('\u{ab99}', ['\u{13c9}', '\u{0}', '\u{0}']), - ('\u{ab9a}', ['\u{13ca}', '\u{0}', '\u{0}']), ('\u{ab9b}', ['\u{13cb}', '\u{0}', '\u{0}']), - ('\u{ab9c}', ['\u{13cc}', '\u{0}', '\u{0}']), ('\u{ab9d}', ['\u{13cd}', '\u{0}', '\u{0}']), - ('\u{ab9e}', ['\u{13ce}', '\u{0}', '\u{0}']), ('\u{ab9f}', ['\u{13cf}', '\u{0}', '\u{0}']), - ('\u{aba0}', ['\u{13d0}', '\u{0}', '\u{0}']), ('\u{aba1}', ['\u{13d1}', '\u{0}', '\u{0}']), - ('\u{aba2}', ['\u{13d2}', '\u{0}', '\u{0}']), ('\u{aba3}', ['\u{13d3}', '\u{0}', '\u{0}']), - ('\u{aba4}', ['\u{13d4}', '\u{0}', '\u{0}']), ('\u{aba5}', ['\u{13d5}', '\u{0}', '\u{0}']), - ('\u{aba6}', ['\u{13d6}', '\u{0}', '\u{0}']), ('\u{aba7}', ['\u{13d7}', '\u{0}', '\u{0}']), - ('\u{aba8}', ['\u{13d8}', '\u{0}', '\u{0}']), ('\u{aba9}', ['\u{13d9}', '\u{0}', '\u{0}']), - ('\u{abaa}', ['\u{13da}', '\u{0}', '\u{0}']), ('\u{abab}', ['\u{13db}', '\u{0}', '\u{0}']), - ('\u{abac}', ['\u{13dc}', '\u{0}', '\u{0}']), ('\u{abad}', ['\u{13dd}', '\u{0}', '\u{0}']), - ('\u{abae}', ['\u{13de}', '\u{0}', '\u{0}']), ('\u{abaf}', ['\u{13df}', '\u{0}', '\u{0}']), - ('\u{abb0}', ['\u{13e0}', '\u{0}', '\u{0}']), ('\u{abb1}', ['\u{13e1}', '\u{0}', '\u{0}']), - ('\u{abb2}', ['\u{13e2}', '\u{0}', '\u{0}']), ('\u{abb3}', ['\u{13e3}', '\u{0}', '\u{0}']), - ('\u{abb4}', ['\u{13e4}', '\u{0}', '\u{0}']), ('\u{abb5}', ['\u{13e5}', '\u{0}', '\u{0}']), - ('\u{abb6}', ['\u{13e6}', '\u{0}', '\u{0}']), ('\u{abb7}', ['\u{13e7}', '\u{0}', '\u{0}']), - ('\u{abb8}', ['\u{13e8}', '\u{0}', '\u{0}']), ('\u{abb9}', ['\u{13e9}', '\u{0}', '\u{0}']), - ('\u{abba}', ['\u{13ea}', '\u{0}', '\u{0}']), ('\u{abbb}', ['\u{13eb}', '\u{0}', '\u{0}']), - ('\u{abbc}', ['\u{13ec}', '\u{0}', '\u{0}']), ('\u{abbd}', ['\u{13ed}', '\u{0}', '\u{0}']), - ('\u{abbe}', ['\u{13ee}', '\u{0}', '\u{0}']), ('\u{abbf}', ['\u{13ef}', '\u{0}', '\u{0}']), - ('\u{fb00}', ['F', 'F', '\u{0}']), ('\u{fb01}', ['F', 'I', '\u{0}']), - ('\u{fb02}', ['F', 'L', '\u{0}']), ('\u{fb03}', ['F', 'F', 'I']), - ('\u{fb04}', ['F', 'F', 'L']), ('\u{fb05}', ['S', 'T', '\u{0}']), - ('\u{fb06}', ['S', 'T', '\u{0}']), ('\u{fb13}', ['\u{544}', '\u{546}', '\u{0}']), + ('\u{a7d1}', ['\u{a7d0}', '\u{0}', '\u{0}']), ('\u{a7d7}', ['\u{a7d6}', '\u{0}', '\u{0}']), + ('\u{a7d9}', ['\u{a7d8}', '\u{0}', '\u{0}']), ('\u{a7f6}', ['\u{a7f5}', '\u{0}', '\u{0}']), + ('\u{ab53}', ['\u{a7b3}', '\u{0}', '\u{0}']), ('\u{ab70}', ['\u{13a0}', '\u{0}', '\u{0}']), + ('\u{ab71}', ['\u{13a1}', '\u{0}', '\u{0}']), ('\u{ab72}', ['\u{13a2}', '\u{0}', '\u{0}']), + ('\u{ab73}', ['\u{13a3}', '\u{0}', '\u{0}']), ('\u{ab74}', ['\u{13a4}', '\u{0}', '\u{0}']), + ('\u{ab75}', ['\u{13a5}', '\u{0}', '\u{0}']), ('\u{ab76}', ['\u{13a6}', '\u{0}', '\u{0}']), + ('\u{ab77}', ['\u{13a7}', '\u{0}', '\u{0}']), ('\u{ab78}', ['\u{13a8}', '\u{0}', '\u{0}']), + ('\u{ab79}', ['\u{13a9}', '\u{0}', '\u{0}']), ('\u{ab7a}', ['\u{13aa}', '\u{0}', '\u{0}']), + ('\u{ab7b}', ['\u{13ab}', '\u{0}', '\u{0}']), ('\u{ab7c}', ['\u{13ac}', '\u{0}', '\u{0}']), + ('\u{ab7d}', ['\u{13ad}', '\u{0}', '\u{0}']), ('\u{ab7e}', ['\u{13ae}', '\u{0}', '\u{0}']), + ('\u{ab7f}', ['\u{13af}', '\u{0}', '\u{0}']), ('\u{ab80}', ['\u{13b0}', '\u{0}', '\u{0}']), + ('\u{ab81}', ['\u{13b1}', '\u{0}', '\u{0}']), ('\u{ab82}', ['\u{13b2}', '\u{0}', '\u{0}']), + ('\u{ab83}', ['\u{13b3}', '\u{0}', '\u{0}']), ('\u{ab84}', ['\u{13b4}', '\u{0}', '\u{0}']), + ('\u{ab85}', ['\u{13b5}', '\u{0}', '\u{0}']), ('\u{ab86}', ['\u{13b6}', '\u{0}', '\u{0}']), + ('\u{ab87}', ['\u{13b7}', '\u{0}', '\u{0}']), ('\u{ab88}', ['\u{13b8}', '\u{0}', '\u{0}']), + ('\u{ab89}', ['\u{13b9}', '\u{0}', '\u{0}']), ('\u{ab8a}', ['\u{13ba}', '\u{0}', '\u{0}']), + ('\u{ab8b}', ['\u{13bb}', '\u{0}', '\u{0}']), ('\u{ab8c}', ['\u{13bc}', '\u{0}', '\u{0}']), + ('\u{ab8d}', ['\u{13bd}', '\u{0}', '\u{0}']), ('\u{ab8e}', ['\u{13be}', '\u{0}', '\u{0}']), + ('\u{ab8f}', ['\u{13bf}', '\u{0}', '\u{0}']), ('\u{ab90}', ['\u{13c0}', '\u{0}', '\u{0}']), + ('\u{ab91}', ['\u{13c1}', '\u{0}', '\u{0}']), ('\u{ab92}', ['\u{13c2}', '\u{0}', '\u{0}']), + ('\u{ab93}', ['\u{13c3}', '\u{0}', '\u{0}']), ('\u{ab94}', ['\u{13c4}', '\u{0}', '\u{0}']), + ('\u{ab95}', ['\u{13c5}', '\u{0}', '\u{0}']), ('\u{ab96}', ['\u{13c6}', '\u{0}', '\u{0}']), + ('\u{ab97}', ['\u{13c7}', '\u{0}', '\u{0}']), ('\u{ab98}', ['\u{13c8}', '\u{0}', '\u{0}']), + ('\u{ab99}', ['\u{13c9}', '\u{0}', '\u{0}']), ('\u{ab9a}', ['\u{13ca}', '\u{0}', '\u{0}']), + ('\u{ab9b}', ['\u{13cb}', '\u{0}', '\u{0}']), ('\u{ab9c}', ['\u{13cc}', '\u{0}', '\u{0}']), + ('\u{ab9d}', ['\u{13cd}', '\u{0}', '\u{0}']), ('\u{ab9e}', ['\u{13ce}', '\u{0}', '\u{0}']), + ('\u{ab9f}', ['\u{13cf}', '\u{0}', '\u{0}']), ('\u{aba0}', ['\u{13d0}', '\u{0}', '\u{0}']), + ('\u{aba1}', ['\u{13d1}', '\u{0}', '\u{0}']), ('\u{aba2}', ['\u{13d2}', '\u{0}', '\u{0}']), + ('\u{aba3}', ['\u{13d3}', '\u{0}', '\u{0}']), ('\u{aba4}', ['\u{13d4}', '\u{0}', '\u{0}']), + ('\u{aba5}', ['\u{13d5}', '\u{0}', '\u{0}']), ('\u{aba6}', ['\u{13d6}', '\u{0}', '\u{0}']), + ('\u{aba7}', ['\u{13d7}', '\u{0}', '\u{0}']), ('\u{aba8}', ['\u{13d8}', '\u{0}', '\u{0}']), + ('\u{aba9}', ['\u{13d9}', '\u{0}', '\u{0}']), ('\u{abaa}', ['\u{13da}', '\u{0}', '\u{0}']), + ('\u{abab}', ['\u{13db}', '\u{0}', '\u{0}']), ('\u{abac}', ['\u{13dc}', '\u{0}', '\u{0}']), + ('\u{abad}', ['\u{13dd}', '\u{0}', '\u{0}']), ('\u{abae}', ['\u{13de}', '\u{0}', '\u{0}']), + ('\u{abaf}', ['\u{13df}', '\u{0}', '\u{0}']), ('\u{abb0}', ['\u{13e0}', '\u{0}', '\u{0}']), + ('\u{abb1}', ['\u{13e1}', '\u{0}', '\u{0}']), ('\u{abb2}', ['\u{13e2}', '\u{0}', '\u{0}']), + ('\u{abb3}', ['\u{13e3}', '\u{0}', '\u{0}']), ('\u{abb4}', ['\u{13e4}', '\u{0}', '\u{0}']), + ('\u{abb5}', ['\u{13e5}', '\u{0}', '\u{0}']), ('\u{abb6}', ['\u{13e6}', '\u{0}', '\u{0}']), + ('\u{abb7}', ['\u{13e7}', '\u{0}', '\u{0}']), ('\u{abb8}', ['\u{13e8}', '\u{0}', '\u{0}']), + ('\u{abb9}', ['\u{13e9}', '\u{0}', '\u{0}']), ('\u{abba}', ['\u{13ea}', '\u{0}', '\u{0}']), + ('\u{abbb}', ['\u{13eb}', '\u{0}', '\u{0}']), ('\u{abbc}', ['\u{13ec}', '\u{0}', '\u{0}']), + ('\u{abbd}', ['\u{13ed}', '\u{0}', '\u{0}']), ('\u{abbe}', ['\u{13ee}', '\u{0}', '\u{0}']), + ('\u{abbf}', ['\u{13ef}', '\u{0}', '\u{0}']), ('\u{fb00}', ['F', 'F', '\u{0}']), + ('\u{fb01}', ['F', 'I', '\u{0}']), ('\u{fb02}', ['F', 'L', '\u{0}']), + ('\u{fb03}', ['F', 'F', 'I']), ('\u{fb04}', ['F', 'F', 'L']), + ('\u{fb05}', ['S', 'T', '\u{0}']), ('\u{fb06}', ['S', 'T', '\u{0}']), + ('\u{fb13}', ['\u{544}', '\u{546}', '\u{0}']), ('\u{fb14}', ['\u{544}', '\u{535}', '\u{0}']), ('\u{fb15}', ['\u{544}', '\u{53b}', '\u{0}']), ('\u{fb16}', ['\u{54e}', '\u{546}', '\u{0}']), @@ -2133,6 +2187,41 @@ ('\u{104f9}', ['\u{104d1}', '\u{0}', '\u{0}']), ('\u{104fa}', ['\u{104d2}', '\u{0}', '\u{0}']), ('\u{104fb}', ['\u{104d3}', '\u{0}', '\u{0}']), + ('\u{10597}', ['\u{10570}', '\u{0}', '\u{0}']), + ('\u{10598}', ['\u{10571}', '\u{0}', '\u{0}']), + ('\u{10599}', ['\u{10572}', '\u{0}', '\u{0}']), + ('\u{1059a}', ['\u{10573}', '\u{0}', '\u{0}']), + ('\u{1059b}', ['\u{10574}', '\u{0}', '\u{0}']), + ('\u{1059c}', ['\u{10575}', '\u{0}', '\u{0}']), + ('\u{1059d}', ['\u{10576}', '\u{0}', '\u{0}']), + ('\u{1059e}', ['\u{10577}', '\u{0}', '\u{0}']), + ('\u{1059f}', ['\u{10578}', '\u{0}', '\u{0}']), + ('\u{105a0}', ['\u{10579}', '\u{0}', '\u{0}']), + ('\u{105a1}', ['\u{1057a}', '\u{0}', '\u{0}']), + ('\u{105a3}', ['\u{1057c}', '\u{0}', '\u{0}']), + ('\u{105a4}', ['\u{1057d}', '\u{0}', '\u{0}']), + ('\u{105a5}', ['\u{1057e}', '\u{0}', '\u{0}']), + ('\u{105a6}', ['\u{1057f}', '\u{0}', '\u{0}']), + ('\u{105a7}', ['\u{10580}', '\u{0}', '\u{0}']), + ('\u{105a8}', ['\u{10581}', '\u{0}', '\u{0}']), + ('\u{105a9}', ['\u{10582}', '\u{0}', '\u{0}']), + ('\u{105aa}', ['\u{10583}', '\u{0}', '\u{0}']), + ('\u{105ab}', ['\u{10584}', '\u{0}', '\u{0}']), + ('\u{105ac}', ['\u{10585}', '\u{0}', '\u{0}']), + ('\u{105ad}', ['\u{10586}', '\u{0}', '\u{0}']), + ('\u{105ae}', ['\u{10587}', '\u{0}', '\u{0}']), + ('\u{105af}', ['\u{10588}', '\u{0}', '\u{0}']), + ('\u{105b0}', ['\u{10589}', '\u{0}', '\u{0}']), + ('\u{105b1}', ['\u{1058a}', '\u{0}', '\u{0}']), + ('\u{105b3}', ['\u{1058c}', '\u{0}', '\u{0}']), + ('\u{105b4}', ['\u{1058d}', '\u{0}', '\u{0}']), + ('\u{105b5}', ['\u{1058e}', '\u{0}', '\u{0}']), + ('\u{105b6}', ['\u{1058f}', '\u{0}', '\u{0}']), + ('\u{105b7}', ['\u{10590}', '\u{0}', '\u{0}']), + ('\u{105b8}', ['\u{10591}', '\u{0}', '\u{0}']), + ('\u{105b9}', ['\u{10592}', '\u{0}', '\u{0}']), + ('\u{105bb}', ['\u{10594}', '\u{0}', '\u{0}']), + ('\u{105bc}', ['\u{10595}', '\u{0}', '\u{0}']), ('\u{10cc0}', ['\u{10c80}', '\u{0}', '\u{0}']), ('\u{10cc1}', ['\u{10c81}', '\u{0}', '\u{0}']), ('\u{10cc2}', ['\u{10c82}', '\u{0}', '\u{0}']), diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/array.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/array.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/array.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/array.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,5 +1,6 @@ use core::array; use core::convert::TryFrom; +use core::sync::atomic::{AtomicUsize, Ordering}; #[test] fn array_from_ref() { @@ -303,8 +304,6 @@ #[test] #[should_panic(expected = "test succeeded")] fn array_map_drop_safety() { - use core::sync::atomic::AtomicUsize; - use core::sync::atomic::Ordering; static DROPPED: AtomicUsize = AtomicUsize::new(0); struct DropCounter; impl Drop for DropCounter { @@ -356,3 +355,84 @@ b3.a[0].set(Some(&b1)); b3.a[1].set(Some(&b2)); } + +#[test] +fn array_from_fn() { + let array = core::array::from_fn(|idx| idx); + assert_eq!(array, [0, 1, 2, 3, 4]); +} + +#[test] +fn array_try_from_fn() { + #[derive(Debug, PartialEq)] + enum SomeError { + Foo, + } + + let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i)); + assert_eq!(array, Ok([0, 1, 2, 3, 4])); + + let another_array = core::array::try_from_fn::(|_| Err(SomeError::Foo)); + assert_eq!(another_array, Err(SomeError::Foo)); +} + +#[cfg(not(panic = "abort"))] +#[test] +fn array_try_from_fn_drops_inserted_elements_on_err() { + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct CountDrop; + impl Drop for CountDrop { + fn drop(&mut self) { + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + let _ = catch_unwind_silent(move || { + let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| { + if idx == 2 { + return Err(()); + } + Ok(CountDrop) + }); + }); + + assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2); +} + +#[cfg(not(panic = "abort"))] +#[test] +fn array_try_from_fn_drops_inserted_elements_on_panic() { + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct CountDrop; + impl Drop for CountDrop { + fn drop(&mut self) { + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + let _ = catch_unwind_silent(move || { + let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| { + if idx == 2 { + panic!("peek a boo"); + } + Ok(CountDrop) + }); + }); + + assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2); +} + +#[cfg(not(panic = "abort"))] +// https://stackoverflow.com/a/59211505 +fn catch_unwind_silent(f: F) -> std::thread::Result +where + F: FnOnce() -> R + core::panic::UnwindSafe, +{ + let prev_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(|_| {})); + let result = std::panic::catch_unwind(f); + std::panic::set_hook(prev_hook); + result +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/fmt/builders.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/fmt/builders.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/fmt/builders.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/fmt/builders.rs 2021-11-29 19:27:11.000000000 +0000 @@ -653,6 +653,7 @@ fn test_formatting_parameters_are_forwarded() { use std::collections::{BTreeMap, BTreeSet}; #[derive(Debug)] + #[allow(dead_code)] struct Foo { bar: u32, baz: u32, diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/fmt/num.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/fmt/num.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/fmt/num.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/fmt/num.rs 2021-11-29 19:27:11.000000000 +0000 @@ -146,6 +146,7 @@ assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000))); //test zero precision assert_eq!(format!("{:.0e}", 1), format!("1e0",)); + assert_eq!(format!("{:.0e}", 35), format!("4e1",)); //test padding with precision (and sign) assert_eq!(format!("{:+10.3e}", 1), " +1.000e0"); diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/iter/adapters/flatten.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/iter/adapters/flatten.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/iter/adapters/flatten.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/iter/adapters/flatten.rs 2021-11-29 19:27:11.000000000 +0000 @@ -59,6 +59,23 @@ } #[test] +fn test_flatten_advance_by() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + it.advance_by(5).unwrap(); + assert_eq!(it.next(), Some(5)); + it.advance_by(9).unwrap(); + assert_eq!(it.next(), Some(15)); + it.advance_back_by(4).unwrap(); + assert_eq!(it.next_back(), Some(35)); + it.advance_back_by(9).unwrap(); + assert_eq!(it.next_back(), Some(25)); + + assert_eq!(it.advance_by(usize::MAX), Err(9)); + assert_eq!(it.advance_back_by(usize::MAX), Err(0)); + assert_eq!(it.size_hint(), (0, Some(0))); +} + +#[test] fn test_flatten_non_fused_outer() { let mut iter = NonFused::new(once(0..2)).flatten(); diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/iter/range.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/iter/range.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/iter/range.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/iter/range.rs 2021-11-29 19:27:11.000000000 +0000 @@ -286,6 +286,29 @@ } #[test] +fn test_range_advance_by() { + let mut r = 0..usize::MAX; + r.advance_by(0).unwrap(); + r.advance_back_by(0).unwrap(); + + assert_eq!(r.len(), usize::MAX); + + r.advance_by(1).unwrap(); + r.advance_back_by(1).unwrap(); + + assert_eq!((r.start, r.end), (1, usize::MAX - 1)); + + assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2)); + + let mut r = 0u128..u128::MAX; + + r.advance_by(usize::MAX).unwrap(); + r.advance_back_by(usize::MAX).unwrap(); + + assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128)); +} + +#[test] fn test_range_inclusive_step() { assert_eq!((0..=50).step_by(10).collect::>(), [0, 10, 20, 30, 40, 50]); assert_eq!((0..=5).step_by(1).collect::>(), [0, 1, 2, 3, 4, 5]); diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/lib.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,6 +10,7 @@ #![feature(const_assume)] #![feature(const_cell_into_inner)] #![feature(const_maybe_uninit_assume_init)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_ptr_offset)] @@ -26,6 +27,7 @@ #![feature(extern_types)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(array_from_fn)] #![feature(hashmap_internals)] #![feature(try_find)] #![feature(is_sorted)] @@ -51,7 +53,6 @@ #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] -#![feature(iter_map_while)] #![feature(const_mut_refs)] #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/num/int_log.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/num/int_log.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/num/int_log.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/num/int_log.rs 2021-11-29 19:27:11.000000000 +0000 @@ -26,10 +26,10 @@ assert_eq!(i.checked_log(4), None); } for i in 1..=i16::MAX { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as i16)); + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); } for i in 1..=u16::MAX { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u16)); + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); } } @@ -46,19 +46,19 @@ assert_eq!(0i16.checked_log2(), None); for i in 1..=u8::MAX { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u8)); + assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); } for i in 1..=u16::MAX { // Guard against Android's imprecise f32::log2 implementation. if i != 8192 && i != 32768 { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u16)); + assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); } } for i in i8::MIN..=0 { assert_eq!(i.checked_log2(), None); } for i in 1..=i8::MAX { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as i8)); + assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); } for i in i16::MIN..=0 { assert_eq!(i.checked_log2(), None); @@ -66,7 +66,7 @@ for i in 1..=i16::MAX { // Guard against Android's imprecise f32::log2 implementation. if i != 8192 { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as i16)); + assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); } } } @@ -75,9 +75,9 @@ #[test] #[cfg(not(target_os = "android"))] fn checked_log2_not_android() { - assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u16)); - assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u16)); - assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as i16)); + assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32)); + assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32)); + assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32)); } #[test] @@ -91,10 +91,13 @@ assert_eq!(i.checked_log10(), None); } for i in 1..=i16::MAX { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as i16)); + assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); } for i in 1..=u16::MAX { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u16)); + assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + } + for i in 1..=100_000u32 { + assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/option.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/option.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/option.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/option.rs 2021-11-29 19:27:11.000000000 +0000 @@ -367,6 +367,27 @@ const IS_NONE: bool = OPTION.is_none(); assert!(!IS_NONE); + + const COPIED: Option = OPTION.as_ref().copied(); + assert_eq!(COPIED, OPTION); +} + +#[test] +const fn option_const_mut() { + // test that the methods of `Option` that take mutable references are usable in a const context + + let mut option: Option = Some(32); + + let _take = option.take(); + let _replace = option.replace(42); + + { + let as_mut = option.as_mut(); + match as_mut { + Some(v) => *v = 32, + None => unreachable!(), + } + } } #[test] diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/slice.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/slice.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/slice.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/slice.rs 2021-11-29 19:27:11.000000000 +0000 @@ -2152,3 +2152,42 @@ let mut a = [MaybeUninit::::uninit(); 10]; a.fill(MaybeUninit::uninit()); } + +#[test] +fn test_swap() { + let mut x = ["a", "b", "c", "d"]; + x.swap(1, 3); + assert_eq!(x, ["a", "d", "c", "b"]); + x.swap(0, 3); + assert_eq!(x, ["b", "d", "c", "a"]); +} + +mod swap_panics { + #[test] + #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")] + fn index_a_equals_len() { + let mut x = ["a", "b", "c", "d"]; + x.swap(4, 2); + } + + #[test] + #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")] + fn index_b_equals_len() { + let mut x = ["a", "b", "c", "d"]; + x.swap(2, 4); + } + + #[test] + #[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")] + fn index_a_greater_than_len() { + let mut x = ["a", "b", "c", "d"]; + x.swap(5, 2); + } + + #[test] + #[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")] + fn index_b_greater_than_len() { + let mut x = ["a", "b", "c", "d"]; + x.swap(2, 5); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/core/tests/time.rs rustc-1.57.0+dfsg1+llvm/library/core/tests/time.rs --- rustc-1.56.0+dfsg1+llvm/library/core/tests/time.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/core/tests/time.rs 2021-11-29 19:27:11.000000000 +0000 @@ -314,6 +314,34 @@ } #[test] +fn debug_formatting_padding() { + assert_eq!("0ns ", format!("{:<9?}", Duration::new(0, 0))); + assert_eq!(" 0ns", format!("{:>9?}", Duration::new(0, 0))); + assert_eq!(" 0ns ", format!("{:^9?}", Duration::new(0, 0))); + assert_eq!("123ns ", format!("{:<9.0?}", Duration::new(0, 123))); + assert_eq!(" 123ns", format!("{:>9.0?}", Duration::new(0, 123))); + assert_eq!(" 123ns ", format!("{:^9.0?}", Duration::new(0, 123))); + assert_eq!("123.0ns ", format!("{:<9.1?}", Duration::new(0, 123))); + assert_eq!(" 123.0ns", format!("{:>9.1?}", Duration::new(0, 123))); + assert_eq!(" 123.0ns ", format!("{:^9.1?}", Duration::new(0, 123))); + assert_eq!("7.1µs ", format!("{:<9?}", Duration::new(0, 7_100))); + assert_eq!(" 7.1µs", format!("{:>9?}", Duration::new(0, 7_100))); + assert_eq!(" 7.1µs ", format!("{:^9?}", Duration::new(0, 7_100))); + assert_eq!("999.123456ms", format!("{:<9?}", Duration::new(0, 999_123_456))); + assert_eq!("999.123456ms", format!("{:>9?}", Duration::new(0, 999_123_456))); + assert_eq!("999.123456ms", format!("{:^9?}", Duration::new(0, 999_123_456))); + assert_eq!("5s ", format!("{:<9?}", Duration::new(5, 0))); + assert_eq!(" 5s", format!("{:>9?}", Duration::new(5, 0))); + assert_eq!(" 5s ", format!("{:^9?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:<9.12?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:>9.12?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:^9.12?}", Duration::new(5, 0))); + + // default alignment is left: + assert_eq!("5s ", format!("{:9?}", Duration::new(5, 0))); +} + +#[test] fn debug_formatting_precision_high() { assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs"); diff -Nru rustc-1.56.0+dfsg1+llvm/library/panic_abort/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/panic_abort/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/panic_abort/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/panic_abort/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -44,6 +44,7 @@ libc::abort(); } } else if #[cfg(any(target_os = "hermit", + target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx") ))] { unsafe fn abort() -> ! { diff -Nru rustc-1.56.0+dfsg1+llvm/library/panic_unwind/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/panic_unwind/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/panic_unwind/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/panic_unwind/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -45,6 +45,7 @@ } else if #[cfg(any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", + target_os = "solid_asp3", all(target_family = "unix", not(target_os = "espidf")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { diff -Nru rustc-1.56.0+dfsg1+llvm/library/proc_macro/src/bridge/mod.rs rustc-1.57.0+dfsg1+llvm/library/proc_macro/src/bridge/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/proc_macro/src/bridge/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/proc_macro/src/bridge/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -162,6 +162,8 @@ fn source($self: $S::Span) -> $S::Span; fn start($self: $S::Span) -> LineColumn; fn end($self: $S::Span) -> LineColumn; + fn before($self: $S::Span) -> $S::Span; + fn after($self: $S::Span) -> $S::Span; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; fn source_text($self: $S::Span) -> Option; diff -Nru rustc-1.56.0+dfsg1+llvm/library/proc_macro/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/proc_macro/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/proc_macro/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/proc_macro/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -61,7 +61,7 @@ /// non-panicking way to detect whether the infrastructure required to use the /// API of proc_macro is presently available. Returns true if invoked from /// inside of a procedural macro, false if invoked from any other binary. -#[unstable(feature = "proc_macro_is_available", issue = "71436")] +#[stable(feature = "proc_macro_is_available", since = "1.57.0")] pub fn is_available() -> bool { bridge::Bridge::is_available() } @@ -357,6 +357,18 @@ self.0.end().add_1_to_column() } + /// Creates an empty span pointing to directly before this span. + #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] + pub fn before(&self) -> Span { + Span(self.0.before()) + } + + /// Creates an empty span pointing to directly after this span. + #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] + pub fn after(&self) -> Span { + Span(self.0.after()) + } + /// Creates a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/build.rs rustc-1.57.0+dfsg1+llvm/library/std/build.rs --- rustc-1.56.0+dfsg1+llvm/library/std/build.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/build.rs 2021-11-29 19:27:11.000000000 +0000 @@ -27,6 +27,7 @@ || target.contains("wasm32") || target.contains("asmjs") || target.contains("espidf") + || target.contains("solid") { // These platforms don't have any special requirements. } else { diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/Cargo.toml rustc-1.57.0+dfsg1+llvm/library/std/Cargo.toml --- rustc-1.56.0+dfsg1+llvm/library/std/Cargo.toml 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/Cargo.toml 2021-11-29 19:27:11.000000000 +0000 @@ -15,7 +15,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.99", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.103", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.44" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } @@ -72,6 +72,7 @@ # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = ["std_detect/std_detect_file_io"] std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] +std_detect_env_override = ["std_detect/std_detect_env_override"] [package.metadata.fortanix-sgx] # Maximum possible number of threads when testing diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/box_into_raw.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/box_into_raw.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/box_into_raw.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/box_into_raw.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +Box::into_raw diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/fs_file.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/fs_file.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/fs_file.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/fs_file.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +fs::File diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/io_bufread.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/io_bufread.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/io_bufread.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/io_bufread.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +io::BufRead diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/io_read.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/io_read.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/io_read.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/io_read.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +io::Read diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/io_seek.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/io_seek.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/io_seek.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/io_seek.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +io::Seek diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/io_write.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/io_write.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/io_write.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/io_write.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +io::Write diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/net_tosocketaddrs.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/net_tosocketaddrs.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/net_tosocketaddrs.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/net_tosocketaddrs.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +net::ToSocketAddrs diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/process_exit.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/process_exit.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/process_exit.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/process_exit.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +process::exit diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/string_string.md rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/string_string.md --- rustc-1.56.0+dfsg1+llvm/library/std/primitive_docs/string_string.md 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/primitive_docs/string_string.md 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1 @@ +string::String diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/collections/hash/map.rs rustc-1.57.0+dfsg1+llvm/library/std/src/collections/hash/map.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/collections/hash/map.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/collections/hash/map.rs 2021-11-29 19:27:11.000000000 +0000 @@ -203,9 +203,9 @@ /// } /// ``` -#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "HashMap")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), rustc_insignificant_dtor)] +#[rustc_insignificant_dtor] pub struct HashMap { base: base::HashMap, } @@ -223,6 +223,7 @@ /// let mut map: HashMap<&str, i32> = HashMap::new(); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> HashMap { Default::default() @@ -240,6 +241,7 @@ /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> HashMap { HashMap::with_capacity_and_hasher(capacity, Default::default()) @@ -625,14 +627,13 @@ /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, isize> = HashMap::new(); /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); /// ``` #[inline] - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.base.try_reserve(additional).map_err(map_try_reserve_error) } @@ -1258,9 +1259,10 @@ /// An owning iterator over the entries of a `HashMap`. /// /// This `struct` is created by the [`into_iter`] method on [`HashMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: crate::iter::IntoIterator /// /// # Example /// @@ -1720,6 +1722,7 @@ /// Converts the entry into a mutable reference to the key in the entry /// with a lifetime bound to the map itself. #[inline] + #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn into_key(self) -> &'a mut K { self.base.into_key() @@ -1735,6 +1738,7 @@ /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry /// with a lifetime bound to the map itself. #[inline] + #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn into_mut(self) -> &'a mut V { self.base.into_mut() @@ -1764,6 +1768,7 @@ /// Converts the `OccupiedEntry` into a mutable reference to the key and value in the entry /// with a lifetime bound to the map itself. #[inline] + #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "hash_raw_entry", issue = "56167")] pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { self.base.into_key_value() @@ -2891,6 +2896,7 @@ #[inline] #[allow(deprecated)] // rand + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn new() -> RandomState { // Historically this function did not cache keys from the OS and instead @@ -2943,6 +2949,7 @@ /// instances created through `new` or `default`. #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] #[allow(deprecated)] + #[must_use] pub fn new() -> DefaultHasher { DefaultHasher(SipHasher13::new_with_keys(0, 0)) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/collections/hash/set.rs rustc-1.57.0+dfsg1+llvm/library/std/src/collections/hash/set.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/collections/hash/set.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/collections/hash/set.rs 2021-11-29 19:27:11.000000000 +0000 @@ -107,7 +107,7 @@ /// [`HashMap`]: crate::collections::HashMap /// [`RefCell`]: crate::cell::RefCell /// [`Cell`]: crate::cell::Cell -#[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "HashSet")] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashSet { base: base::HashSet, @@ -126,6 +126,7 @@ /// let set: HashSet = HashSet::new(); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> HashSet { Default::default() @@ -144,6 +145,7 @@ /// assert!(set.capacity() >= 10); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> HashSet { HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, Default::default()) } @@ -423,13 +425,12 @@ /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::new(); /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); /// ``` #[inline] - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.base.try_reserve(additional).map_err(map_try_reserve_error) } @@ -1237,9 +1238,10 @@ /// An owning iterator over the items of a `HashSet`. /// /// This `struct` is created by the [`into_iter`] method on [`HashSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: crate::iter::IntoIterator /// /// # Examples /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/collections/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/collections/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/collections/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/collections/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -97,11 +97,11 @@ //! //! ## Sequences //! -//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | -//! |----------------|----------------|-----------------|----------------|--------|----------------| -//! | [`Vec`] | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | -//! | [`VecDeque`] | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) | -//! | [`LinkedList`] | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) | +//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | +//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------| +//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) | +//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) | +//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) | //! //! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and //! [`VecDeque`] is generally going to be faster than [`LinkedList`]. @@ -110,10 +110,10 @@ //! //! For Sets, all operations have the cost of the equivalent Map operation. //! -//! | | get | insert | remove | range | append | -//! |--------------|-----------|-----------|-----------|-----------|--------| -//! | [`HashMap`] | O(1)~ | O(1)~* | O(1)~ | N/A | N/A | -//! | [`BTreeMap`] | O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) | O(n+m) | +//! | | get | insert | remove | range | append | +//! |--------------|---------------|---------------|---------------|---------------|--------------| +//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A | +//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) | //! //! # Correct and Efficient Usage of Collections //! @@ -217,7 +217,7 @@ //! contents by-value. This is great when the collection itself is no longer //! needed, and the values are needed elsewhere. Using `extend` with `into_iter` //! is the main way that contents of one collection are moved into another. -//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`]. +//! `extend` automatically calls `into_iter`, and takes any T: [IntoIterator]. //! Calling `collect` on an iterator itself is also a great way to convert one //! collection into another. Both of these methods should internally use the //! capacity management tools discussed in the previous section to do this as @@ -239,7 +239,7 @@ //! Iterators also provide a series of *adapter* methods for performing common //! threads to sequences. Among the adapters are functional favorites like `map`, //! `fold`, `skip` and `take`. Of particular interest to collections is the -//! `rev` adapter, that reverses any iterator that supports this operation. Most +//! `rev` adapter, which reverses any iterator that supports this operation. Most //! collections provide reversible iterators as the way to iterate over them in //! reverse order. //! @@ -396,7 +396,7 @@ //! assert_eq!(map.keys().next().unwrap().b, "baz"); //! ``` //! -//! [`IntoIterator`]: crate::iter::IntoIterator +//! [IntoIterator]: crate::iter::IntoIterator "iter::IntoIterator" #![stable(feature = "rust1", since = "1.0.0")] @@ -420,7 +420,7 @@ #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; -#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +#[stable(feature = "try_reserve", since = "1.57.0")] pub use alloc_crate::collections::TryReserveError; #[unstable( feature = "try_reserve_kind", diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/env.rs rustc-1.57.0+dfsg1+llvm/library/std/src/env.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/env.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/env.rs 2021-11-29 19:27:11.000000000 +0000 @@ -879,6 +879,7 @@ /// - x86_64 /// - arm /// - aarch64 + /// - m68k /// - mips /// - mips64 /// - powerpc diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/error.rs rustc-1.57.0+dfsg1+llvm/library/std/src/error.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/error.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -31,6 +31,7 @@ use crate::str; use crate::string; use crate::sync::Arc; +use crate::time; /// `Error` is a trait representing the basic expectations for error values, /// i.e., values of type `E` in [`Result`]. @@ -182,7 +183,7 @@ /// /// impl fmt::Display for AnError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f , "An error") + /// write!(f, "An error") /// } /// } /// @@ -215,7 +216,7 @@ /// /// impl fmt::Display for AnError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f , "An error") + /// write!(f, "An error") /// } /// } /// @@ -594,11 +595,11 @@ } } -#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +#[stable(feature = "try_reserve", since = "1.57.0")] impl Error for alloc::collections::TryReserveError {} #[unstable(feature = "duration_checked_float", issue = "83400")] -impl Error for core::time::FromSecsError {} +impl Error for time::FromSecsError {} // Copied from `any.rs`. impl dyn Error + 'static { diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/ffi/c_str.rs rustc-1.57.0+dfsg1+llvm/library/std/src/ffi/c_str.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/ffi/c_str.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/ffi/c_str.rs 2021-11-29 19:27:11.000000000 +0000 @@ -29,18 +29,18 @@ /// type is a static guarantee that the underlying bytes contain no interior 0 /// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). /// -/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former +/// `CString` is to &[CStr] as [`String`] is to &[str]: the former /// in each pair are owned strings; the latter are borrowed /// references. /// /// # Creating a `CString` /// /// A `CString` is created from either a byte slice or a byte vector, -/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for +/// or anything that implements [Into]<[Vec]<[u8]>> (for /// example, you can build a `CString` straight out of a [`String`] or -/// a [`&str`], since both implement that trait). +/// a &[str], since both implement that trait). /// -/// The [`CString::new`] method will actually check that the provided `&[u8]` +/// The [`CString::new`] method will actually check that the provided &[[u8]] /// does not have 0 bytes in the middle, and return an error if it /// finds one. /// @@ -55,7 +55,7 @@ /// /// # Extracting a slice of the whole C string /// -/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a +/// Alternatively, you can obtain a &[[u8]] slice from a /// `CString` with the [`CString::as_bytes`] method. Slices produced in this /// way do *not* contain the trailing nul terminator. This is useful /// when you will be calling an extern function that takes a `*const @@ -64,7 +64,7 @@ /// You can of course get the slice's length with its /// [`len`][slice::len] method. /// -/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you +/// If you need a &[[u8]] slice *with* the nul terminator, you /// can use [`CString::as_bytes_with_nul`] instead. /// /// Once you have the kind of slice you need (with or without a nul @@ -73,9 +73,8 @@ /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// -/// [`&str`]: prim@str +/// [str]: prim@str "str" /// [`Deref`]: ops::Deref -/// [`&CStr`]: CStr /// /// # Examples /// @@ -120,12 +119,12 @@ /// Representation of a borrowed C string. /// /// This type represents a borrowed reference to a nul-terminated -/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` +/// array of bytes. It can be constructed safely from a &[[u8]] /// slice, or unsafely from a raw `*const c_char`. It can then be -/// converted to a Rust [`&str`] by performing UTF-8 validation, or +/// converted to a Rust &[str] by performing UTF-8 validation, or /// into an owned [`CString`]. /// -/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former +/// `&CStr` is to [`CString`] as &[str] is to [`String`]: the former /// in each pair are borrowed references; the latter are owned /// strings. /// @@ -183,7 +182,7 @@ /// println!("string: {}", my_string_safe()); /// ``` /// -/// [`&str`]: prim@str +/// [str]: prim@str "str" #[derive(Hash)] #[cfg_attr(not(test), rustc_diagnostic_item = "CStr")] #[stable(feature = "rust1", since = "1.0.0")] @@ -298,6 +297,7 @@ /// /// assert_eq!(&bytes[..], value.unwrap_err().as_bytes()); /// ``` + #[must_use] pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] } @@ -323,6 +323,7 @@ /// /// assert_eq!(bytes, value.unwrap_err().into_bytes()); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] pub fn into_bytes(self) -> Vec { self.bytes } @@ -410,6 +411,8 @@ /// Creates a C-compatible string by consuming a byte vector, /// without checking for interior 0 bytes. /// + /// Trailing 0 byte will be appended by this function. + /// /// This method is equivalent to [`CString::new`] except that no runtime /// assertion is made that `v` contains no 0 bytes, and it requires an /// actual byte vector, not anything that can be converted to one with Into. @@ -424,6 +427,7 @@ /// let c_string = CString::from_vec_unchecked(raw); /// } /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { v.reserve_exact(1); @@ -475,6 +479,7 @@ /// let c_string = CString::from_raw(raw); /// } /// ``` + #[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `CString`"] #[stable(feature = "cstr_memory", since = "1.4.0")] pub unsafe fn from_raw(ptr: *mut c_char) -> CString { // SAFETY: This is called with a pointer that was obtained from a call @@ -523,6 +528,7 @@ /// } /// ``` #[inline] + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstr_memory", since = "1.4.0")] pub fn into_raw(self) -> *mut c_char { Box::into_raw(self.into_inner()) as *mut c_char @@ -546,7 +552,6 @@ /// let err = cstring.into_string().err().expect("into_string().err() failed"); /// assert_eq!(err.utf8_error().valid_up_to(), 1); /// ``` - #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_string(self) -> Result { String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError { @@ -570,6 +575,7 @@ /// let bytes = c_string.into_bytes(); /// assert_eq!(bytes, vec![b'f', b'o', b'o']); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes(self) -> Vec { let mut vec = self.into_inner().into_vec(); @@ -590,6 +596,7 @@ /// let bytes = c_string.into_bytes_with_nul(); /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec { self.into_inner().into_vec() @@ -612,6 +619,7 @@ /// assert_eq!(bytes, &[b'f', b'o', b'o']); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes(&self) -> &[u8] { // SAFETY: CString has a length at least 1 @@ -631,6 +639,7 @@ /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes_with_nul(&self) -> &[u8] { &self.inner @@ -649,6 +658,7 @@ /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); /// ``` #[inline] + #[must_use] #[stable(feature = "as_c_str", since = "1.20.0")] pub fn as_c_str(&self) -> &CStr { &*self @@ -666,6 +676,7 @@ /// assert_eq!(&*boxed, /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "into_boxed_c_str", since = "1.20.0")] pub fn into_boxed_c_str(self) -> Box { unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) } @@ -682,7 +693,7 @@ unsafe { ptr::read(&this.inner) } } - /// Converts a [`Vec`]`` to a [`CString`] without checking the + /// Converts a [Vec]<[u8]> to a [`CString`] without checking the /// invariants on the given [`Vec`]. /// /// # Safety @@ -700,12 +711,13 @@ /// unsafe { CString::from_vec_unchecked(b"abc".to_vec()) } /// ); /// ``` + #[must_use] #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")] pub unsafe fn from_vec_with_nul_unchecked(v: Vec) -> Self { Self { inner: v.into_boxed_slice() } } - /// Attempts to converts a [`Vec`]`` to a [`CString`]. + /// Attempts to converts a [Vec]<[u8]> to a [`CString`]. /// /// Runtime checks are present to ensure there is only one nul byte in the /// [`Vec`], its last element. @@ -793,7 +805,7 @@ #[stable(feature = "cstring_into", since = "1.7.0")] impl From for Vec { - /// Converts a [`CString`] into a [`Vec`]``. + /// Converts a [`CString`] into a [Vec]<[u8]>. /// /// The conversion consumes the [`CString`], and removes the terminating NUL byte. #[inline] @@ -867,7 +879,7 @@ #[stable(feature = "c_string_from_box", since = "1.18.0")] impl From> for CString { - /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// Converts a [Box]<[CStr]> into a [`CString`] without copying or allocating. #[inline] fn from(s: Box) -> CString { s.into_c_string() @@ -876,7 +888,7 @@ #[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")] impl From> for CString { - /// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without + /// Converts a [Vec]<[NonZeroU8]> into a [`CString`] without /// copying nor checking for inner null bytes. #[inline] fn from(v: Vec) -> CString { @@ -906,7 +918,7 @@ #[stable(feature = "box_from_c_string", since = "1.20.0")] impl From for Box { - /// Converts a [`CString`] into a [`Box`]`` without copying or allocating. + /// Converts a [`CString`] into a [Box]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Box { s.into_boxed_c_str() @@ -915,6 +927,7 @@ #[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From for Cow<'a, CStr> { + /// Converts a [`CString`] into an owned [`Cow`] without copying or allocating. #[inline] fn from(s: CString) -> Cow<'a, CStr> { Cow::Owned(s) @@ -923,6 +936,7 @@ #[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From<&'a CStr> for Cow<'a, CStr> { + /// Converts a [`CStr`] into a borrowed [`Cow`] without copying or allocating. #[inline] fn from(s: &'a CStr) -> Cow<'a, CStr> { Cow::Borrowed(s) @@ -931,6 +945,7 @@ #[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From<&'a CString> for Cow<'a, CStr> { + /// Converts a `&`[`CString`] into a borrowed [`Cow`] without copying or allocating. #[inline] fn from(s: &'a CString) -> Cow<'a, CStr> { Cow::Borrowed(s.as_c_str()) @@ -939,7 +954,7 @@ #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts a [`CString`] into an [`Arc`]`` without copying or allocating. + /// Converts a [`CString`] into an [Arc]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Arc { let arc: Arc<[u8]> = Arc::from(s.into_inner()); @@ -958,7 +973,7 @@ #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts a [`CString`] into an [`Rc`]`` without copying or allocating. + /// Converts a [`CString`] into an [Rc]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Rc { let rc: Rc<[u8]> = Rc::from(s.into_inner()); @@ -1014,6 +1029,7 @@ /// let nul_error = CString::new("foo\0bar").unwrap_err(); /// assert_eq!(nul_error.into_vec(), b"foo\0bar"); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] pub fn into_vec(self) -> Vec { self.1 @@ -1088,6 +1104,7 @@ impl IntoStringError { /// Consumes this error, returning original [`CString`] which generated the /// error. + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_cstring(self) -> CString { self.inner @@ -1158,6 +1175,7 @@ /// } /// # } /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { // SAFETY: The caller has provided a pointer that points to a valid C @@ -1240,6 +1258,7 @@ /// } /// ``` #[inline] + #[must_use] #[stable(feature = "cstr_from_bytes", since = "1.10.0")] #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "none")] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { @@ -1298,6 +1317,7 @@ /// This way, the lifetime of the [`CString`] in `hello` encompasses /// the lifetime of `ptr` and the `unsafe` block. #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] pub const fn as_ptr(&self) -> *const c_char { @@ -1322,6 +1342,8 @@ /// assert_eq!(cstr.to_bytes(), b"foo"); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] pub fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); @@ -1347,18 +1369,20 @@ /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0"); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] pub fn to_bytes_with_nul(&self) -> &[u8] { unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } } - /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. + /// Yields a &[str] slice if the `CStr` contains valid UTF-8. /// /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return the corresponding [`&str`] slice. Otherwise, + /// function will return the corresponding &[str] slice. Otherwise, /// it will return an error with details of where UTF-8 validation failed. /// - /// [`&str`]: prim@str + /// [str]: prim@str "str" /// /// # Examples /// @@ -1377,20 +1401,19 @@ str::from_utf8(self.to_bytes()) } - /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. + /// Converts a `CStr` into a [Cow]<[str]>. /// /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` - /// with the corresponding [`&str`] slice. Otherwise, it will + /// function will return a [Cow]::[Borrowed]\(&[str]) + /// with the corresponding &[str] slice. Otherwise, it will /// replace any invalid UTF-8 sequences with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a - /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. + /// [Cow]::[Owned]\(&[str]) with the result. /// - /// [`str`]: primitive@str - /// [`&str`]: primitive@str - /// [`Borrowed`]: Cow::Borrowed - /// [`Owned`]: Cow::Owned - /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER + /// [str]: prim@str "str" + /// [Borrowed]: Cow::Borrowed + /// [Owned]: Cow::Owned + /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER" /// /// # Examples /// @@ -1418,12 +1441,14 @@ /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str> /// ); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "cstr_to_str", since = "1.4.0")] pub fn to_string_lossy(&self) -> Cow<'_, str> { String::from_utf8_lossy(self.to_bytes()) } - /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// Converts a [Box]<[CStr]> into a [`CString`] without copying or allocating. /// /// # Examples /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/ffi/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/ffi/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/ffi/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/ffi/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -43,8 +43,8 @@ //! terminator, so the buffer length is really `len+1` characters. //! Rust strings don't have a nul terminator; their length is always //! stored and does not need to be calculated. While in Rust -//! accessing a string's length is a `O(1)` operation (because the -//! length is stored); in C it is an `O(length)` operation because the +//! accessing a string's length is an *O*(1) operation (because the +//! length is stored); in C it is an *O*(*n*) operation because the //! length needs to be computed by scanning the string for the nul //! terminator. //! @@ -64,15 +64,15 @@ //! string: it is nul-terminated, and has no internal nul characters. //! Rust code can create a [`CString`] out of a normal string (provided //! that the string doesn't have nul characters in the middle), and -//! then use a variety of methods to obtain a raw `*mut `[`u8`] that can +//! then use a variety of methods to obtain a raw \*mut [u8] that can //! then be passed as an argument to functions which use the C //! conventions for strings. //! //! * **From C to Rust:** [`CStr`] represents a borrowed C string; it -//! is what you would use to wrap a raw `*const `[`u8`] that you got from +//! is what you would use to wrap a raw \*const [u8] that you got from //! a C function. A [`CStr`] is guaranteed to be a nul-terminated array //! of bytes. Once you have a [`CStr`], you can convert it to a Rust -//! [`&str`][`str`] if it's valid UTF-8, or lossily convert it by adding +//! &[str] if it's valid UTF-8, or lossily convert it by adding //! replacement characters. //! //! [`OsString`] and [`OsStr`] are useful when you need to transfer @@ -86,9 +86,9 @@ //! library, various APIs that transfer strings to/from the operating //! system use [`OsString`] instead of plain strings. For example, //! [`env::var_os()`] is used to query environment variables; it -//! returns an [`Option`]`<`[`OsString`]`>`. If the environment variable -//! exists you will get a [`Some`]`(os_string)`, which you can *then* try to -//! convert to a Rust string. This yields a [`Result`], so that +//! returns an [Option]<[OsString]>. If the environment variable +//! exists you will get a [Some]\(os_string), which you can +//! *then* try to convert to a Rust string. This yields a [`Result`], so that //! your code can detect errors in case the environment variable did //! not in fact contain valid Unicode data. //! @@ -102,44 +102,44 @@ //! ## On Unix //! //! On Unix, [`OsStr`] implements the -//! `std::os::unix::ffi::`[`OsStrExt`][unix.OsStrExt] trait, which +//! std::os::unix::ffi::[OsStrExt][unix.OsStrExt] trait, which //! augments it with two methods, [`from_bytes`] and [`as_bytes`]. //! These do inexpensive conversions from and to UTF-8 byte slices. //! //! Additionally, on Unix [`OsString`] implements the -//! `std::os::unix::ffi::`[`OsStringExt`][unix.OsStringExt] trait, +//! std::os::unix::ffi::[OsStringExt][unix.OsStringExt] trait, //! which provides [`from_vec`] and [`into_vec`] methods that consume //! their arguments, and take or produce vectors of [`u8`]. //! //! ## On Windows //! //! On Windows, [`OsStr`] implements the -//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait, +//! std::os::windows::ffi::[OsStrExt][windows.OsStrExt] trait, //! which provides an [`encode_wide`] method. This provides an //! iterator that can be [`collect`]ed into a vector of [`u16`]. //! //! Additionally, on Windows [`OsString`] implements the -//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt] +//! std::os::windows:ffi::[OsStringExt][windows.OsStringExt] //! trait, which provides a [`from_wide`] method. The result of this //! method is an [`OsString`] which can be round-tripped to a Windows //! string losslessly. //! //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value //! [Unicode code point]: https://www.unicode.org/glossary/#code_point -//! [`env::set_var()`]: crate::env::set_var -//! [`env::var_os()`]: crate::env::var_os -//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt -//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec -//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec -//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt -//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes -//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes -//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt -//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt -//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide -//! [`collect`]: crate::iter::Iterator::collect -//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt -//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide +//! [`env::set_var()`]: crate::env::set_var "env::set_var" +//! [`env::var_os()`]: crate::env::var_os "env::var_os" +//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt "os::unix::ffi::OsStringExt" +//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec "os::unix::ffi::OsStringExt::from_vec" +//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec "os::unix::ffi::OsStringExt::into_vec" +//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt" +//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes "os::unix::ffi::OsStrExt::from_bytes" +//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes "os::unix::ffi::OsStrExt::as_bytes" +//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt" +//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt "os::windows::ffi::OsStrExt" +//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide "os::windows::ffi::OsStrExt::encode_wide" +//! [`collect`]: crate::iter::Iterator::collect "iter::Iterator::collect" +//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt "os::windows::ffi::OsStringExt" +//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide" #![stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/ffi/os_str.rs rustc-1.57.0+dfsg1+llvm/library/std/src/ffi/os_str.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/ffi/os_str.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/ffi/os_str.rs 2021-11-29 19:27:11.000000000 +0000 @@ -33,7 +33,7 @@ /// of this is that `OsString` instances are *not* `NUL` terminated; in order /// to pass to e.g., Unix system call, you should create a [`CStr`]. /// -/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former +/// `OsString` is to &[OsStr] as [`String`] is to &[str]: the former /// in each pair are owned strings; the latter are borrowed /// references. /// @@ -47,18 +47,18 @@ /// # Creating an `OsString` /// /// **From a Rust string**: `OsString` implements -/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to +/// [From]<[String]>, so you can use my_string.[into]\() to /// create an `OsString` from a normal Rust string. /// /// **From slices:** Just like you can start with an empty Rust -/// [`String`] and then [`String::push_str`] `&str` +/// [`String`] and then [`String::push_str`] some &[str] /// sub-string slices into it, you can create an empty `OsString` with /// the [`OsString::new`] method and then push string slices into it with the /// [`OsString::push`] method. /// /// # Extracting a borrowed reference to the whole OS string /// -/// You can use the [`OsString::as_os_str`] method to get an `&`[`OsStr`] from +/// You can use the [`OsString::as_os_str`] method to get an &[OsStr] from /// an `OsString`; this is effectively a borrowed reference to the /// whole string. /// @@ -67,10 +67,9 @@ /// See the [module's toplevel documentation about conversions][conversions] for a discussion on /// the traits which `OsString` implements for [conversions] from/to native representations. /// -/// [`&OsStr`]: OsStr -/// [`&str`]: str /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions +/// [into]: Into::into #[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -86,13 +85,12 @@ /// This type represents a borrowed reference to a string in the operating system's preferred /// representation. /// -/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed -/// references; the latter are owned strings. +/// `&OsStr` is to [`OsString`] as &[str] is to [`String`]: the +/// former in each pair are borrowed references; the latter are owned strings. /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on /// the traits which `OsStr` implements for [conversions] from/to native representations. /// -/// [`&str`]: str /// [conversions]: super#conversions #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] @@ -121,6 +119,7 @@ /// let os_string = OsString::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn new() -> OsString { OsString { inner: Buf::from_string(String::new()) } @@ -138,6 +137,7 @@ /// assert_eq!(os_string.as_os_str(), os_str); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_os_str(&self) -> &OsStr { self @@ -162,9 +162,7 @@ self.inner.into_string().map_err(|buf| OsString { inner: buf }) } - /// Extends the string with the given [`&OsStr`] slice. - /// - /// [`&OsStr`]: OsStr + /// Extends the string with the given &[OsStr] slice. /// /// # Examples /// @@ -203,6 +201,7 @@ /// assert_eq!(capacity, os_string.capacity()); /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] + #[must_use] #[inline] pub fn with_capacity(capacity: usize) -> OsString { OsString { inner: Buf::with_capacity(capacity) } @@ -350,6 +349,7 @@ /// /// let b: Box = s.into_boxed_os_str(); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "into_boxed_os_str", since = "1.20.0")] pub fn into_boxed_os_str(self) -> Box { let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr; @@ -563,12 +563,10 @@ unsafe { &mut *(inner as *mut Slice as *mut OsStr) } } - /// Yields a [`&str`] slice if the `OsStr` is valid Unicode. + /// Yields a &[str] slice if the `OsStr` is valid Unicode. /// /// This conversion may entail doing a check for UTF-8 validity. /// - /// [`&str`]: str - /// /// # Examples /// /// ``` @@ -578,12 +576,14 @@ /// assert_eq!(os_str.to_str(), Some("foo")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn to_str(&self) -> Option<&str> { self.inner.to_str() } - /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. + /// Converts an `OsStr` to a [Cow]<[str]>. /// /// Any non-Unicode sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. @@ -629,6 +629,8 @@ /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy() @@ -646,6 +648,8 @@ /// assert_eq!(os_string, OsString::from("foo")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn to_os_string(&self) -> OsString { OsString { inner: self.inner.to_owned() } @@ -701,7 +705,7 @@ self.inner.inner.len() } - /// Converts a [`Box`]`` into an [`OsString`] without copying or allocating. + /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or allocating. #[stable(feature = "into_boxed_os_str", since = "1.20.0")] pub fn into_os_string(self: Box) -> OsString { let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; @@ -783,6 +787,7 @@ /// /// assert_eq!("grüße, jürgen â¤", s.to_ascii_lowercase()); /// ``` + #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase`"] #[stable(feature = "osstring_ascii", since = "1.53.0")] pub fn to_ascii_lowercase(&self) -> OsString { OsString::from_inner(self.inner.to_ascii_lowercase()) @@ -804,6 +809,7 @@ /// /// assert_eq!("GRüßE, JüRGEN â¤", s.to_ascii_uppercase()); /// ``` + #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase`"] #[stable(feature = "osstring_ascii", since = "1.53.0")] pub fn to_ascii_uppercase(&self) -> OsString { OsString::from_inner(self.inner.to_ascii_uppercase()) @@ -870,7 +876,7 @@ #[stable(feature = "os_string_from_box", since = "1.18.0")] impl From> for OsString { - /// Converts a [`Box`]`<`[`OsStr`]`>` into an [`OsString`] without copying or + /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or /// allocating. #[inline] fn from(boxed: Box) -> OsString { @@ -880,7 +886,7 @@ #[stable(feature = "box_from_os_string", since = "1.20.0")] impl From for Box { - /// Converts an [`OsString`] into a [`Box`]`` without copying or allocating. + /// Converts an [`OsString`] into a [Box]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Box { s.into_boxed_os_str() @@ -897,7 +903,7 @@ #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts an [`OsString`] into an [`Arc`]`` without copying or allocating. + /// Converts an [`OsString`] into an [Arc]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Arc { let arc = s.inner.into_arc(); @@ -916,7 +922,7 @@ #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts an [`OsString`] into an [`Rc`]`` without copying or allocating. + /// Converts an [`OsString`] into an [Rc]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Rc { let rc = s.inner.into_rc(); diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/fs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -106,7 +106,7 @@ /// Iterator over the entries in a directory. /// /// This iterator is returned from the [`read_dir`] function of this module and -/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`] +/// will yield instances of [io::Result]<[DirEntry]>. Through a [`DirEntry`] /// information like the entry's path and possibly other metadata can be /// learned. /// @@ -198,20 +198,10 @@ recursive: bool, } -/// Indicates how large a buffer to pre-allocate before reading the entire file. -fn initial_buffer_size(file: &File) -> usize { - // Allocate one extra byte so the buffer doesn't need to grow before the - // final `read` call at the end of the file. Don't worry about `usize` - // overflow because reading will fail regardless in that case. - file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0) -} - /// Read the entire contents of a file into a bytes vector. /// /// This is a convenience function for using [`File::open`] and [`read_to_end`] -/// with fewer imports and without an intermediate variable. It pre-allocates a -/// buffer based on the file size when available, so it is generally faster than -/// reading into a vector created with [`Vec::new()`]. +/// with fewer imports and without an intermediate variable. /// /// [`read_to_end`]: Read::read_to_end /// @@ -238,7 +228,7 @@ pub fn read>(path: P) -> io::Result> { fn inner(path: &Path) -> io::Result> { let mut file = File::open(path)?; - let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); + let mut bytes = Vec::new(); file.read_to_end(&mut bytes)?; Ok(bytes) } @@ -248,9 +238,7 @@ /// Read the entire contents of a file into a string. /// /// This is a convenience function for using [`File::open`] and [`read_to_string`] -/// with fewer imports and without an intermediate variable. It pre-allocates a -/// buffer based on the file size when available, so it is generally faster than -/// reading into a string created with [`String::new()`]. +/// with fewer imports and without an intermediate variable. /// /// [`read_to_string`]: Read::read_to_string /// @@ -279,7 +267,7 @@ pub fn read_to_string>(path: P) -> io::Result { fn inner(path: &Path) -> io::Result { let mut file = File::open(path)?; - let mut string = String::with_capacity(initial_buffer_size(&file)); + let mut string = String::new(); file.read_to_string(&mut string)?; Ok(string) } @@ -616,6 +604,15 @@ } } +/// Indicates how much extra capacity is needed to read the rest of the file. +fn buffer_capacity_required(mut file: &File) -> usize { + let size = file.metadata().map(|m| m.len()).unwrap_or(0); + let pos = file.stream_position().unwrap_or(0); + // Don't worry about `usize` overflow because reading will fail regardless + // in that case. + size.saturating_sub(pos) as usize +} + #[stable(feature = "rust1", since = "1.0.0")] impl Read for File { fn read(&mut self, buf: &mut [u8]) -> io::Result { @@ -636,6 +633,18 @@ // SAFETY: Read is guaranteed to work on uninitialized memory unsafe { Initializer::nop() } } + + // Reserves space in the buffer based on the file size when available. + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + buf.reserve(buffer_capacity_required(self)); + io::default_read_to_end(self, buf) + } + + // Reserves space in the buffer based on the file size when available. + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + buf.reserve(buffer_capacity_required(self)); + io::default_read_to_string(self, buf) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for File { @@ -682,6 +691,18 @@ // SAFETY: Read is guaranteed to work on uninitialized memory unsafe { Initializer::nop() } } + + // Reserves space in the buffer based on the file size when available. + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + buf.reserve(buffer_capacity_required(self)); + io::default_read_to_end(self, buf) + } + + // Reserves space in the buffer based on the file size when available. + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + buf.reserve(buffer_capacity_required(self)); + io::default_read_to_string(self, buf) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for &File { @@ -723,6 +744,7 @@ /// let file = options.read(true).open("foo.txt"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn new() -> Self { OpenOptions(fs_imp::OpenOptions::new()) } @@ -786,17 +808,17 @@ /// If a file is opened with both read and append access, beware that after /// opening, and after every write, the position for reading may be set at the /// end of the file. So, before writing, save the current position (using - /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read. + /// [seek]\([SeekFrom]::[Current]\(0))), and restore it before the next read. /// /// ## Note /// /// This function doesn't create the file if it doesn't exist. Use the /// [`OpenOptions::create`] method to do so. /// - /// [`write()`]: Write::write - /// [`flush()`]: Write::flush - /// [`seek`]: Seek::seek - /// [`Current`]: SeekFrom::Current + /// [`write()`]: Write::write "io::Write::write" + /// [`flush()`]: Write::flush "io::Write::flush" + /// [seek]: Seek::seek "io::Seek::seek" + /// [Current]: SeekFrom::Current "io::SeekFrom::Current" /// /// # Examples /// @@ -983,6 +1005,7 @@ /// Ok(()) /// } /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_dir(&self) -> bool { self.file_type().is_dir() @@ -1011,6 +1034,7 @@ /// Ok(()) /// } /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_file(&self) -> bool { self.file_type().is_file() @@ -1037,6 +1061,7 @@ /// Ok(()) /// } /// ``` + #[must_use] #[unstable(feature = "is_symlink", issue = "85748")] pub fn is_symlink(&self) -> bool { self.file_type().is_symlink() @@ -1284,6 +1309,7 @@ /// Ok(()) /// } /// ``` + #[must_use] #[stable(feature = "file_type", since = "1.1.0")] pub fn is_dir(&self) -> bool { self.0.is_dir() @@ -1316,6 +1342,7 @@ /// Ok(()) /// } /// ``` + #[must_use] #[stable(feature = "file_type", since = "1.1.0")] pub fn is_file(&self) -> bool { self.0.is_file() @@ -1351,6 +1378,7 @@ /// Ok(()) /// } /// ``` + #[must_use] #[stable(feature = "file_type", since = "1.1.0")] pub fn is_symlink(&self) -> bool { self.0.is_symlink() @@ -2043,7 +2071,7 @@ /// Returns an iterator over the entries within a directory. /// -/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. +/// The iterator will yield instances of [io::Result]<[DirEntry]>. /// New errors may be encountered after an iterator is initially constructed. /// Entries for the current and parent directories (typically `.` and `..`) are /// skipped. @@ -2163,6 +2191,7 @@ /// let builder = DirBuilder::new(); /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] + #[must_use] pub fn new() -> DirBuilder { DirBuilder { inner: fs_imp::DirBuilder::new(), recursive: false } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/buffered/bufreader.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/buffered/bufreader.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/buffered/bufreader.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/buffered/bufreader.rs 2021-11-29 19:27:11.000000000 +0000 @@ -15,7 +15,7 @@ /// *repeated* read calls to the same file or network socket. It does not /// help when reading very large amounts at once, or reading just one or a few /// times. It also provides no advantage when reading from a source that is -/// already in memory, like a [`Vec`]``. +/// already in memory, like a [Vec]\. /// /// When the `BufReader` is dropped, the contents of its buffer will be /// discarded. Creating multiple instances of a `BufReader` on the same @@ -242,14 +242,13 @@ self.pos = new_pos as usize; return Ok(()); } - } else { - if let Some(new_pos) = pos.checked_add(offset as u64) { - if new_pos <= self.cap as u64 { - self.pos = new_pos as usize; - return Ok(()); - } + } else if let Some(new_pos) = pos.checked_add(offset as u64) { + if new_pos <= self.cap as u64 { + self.pos = new_pos as usize; + return Ok(()); } } + self.seek(SeekFrom::Current(offset)).map(drop) } } @@ -308,6 +307,51 @@ unsafe fn initializer(&self) -> Initializer { self.inner.initializer() } + + // The inner reader might have an optimized `read_to_end`. Drain our buffer and then + // delegate to the inner implementation. + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + let nread = self.cap - self.pos; + buf.extend_from_slice(&self.buf[self.pos..self.cap]); + self.discard_buffer(); + Ok(nread + self.inner.read_to_end(buf)?) + } + + // The inner reader might have an optimized `read_to_end`. Drain our buffer and then + // delegate to the inner implementation. + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + // In the general `else` case below we must read bytes into a side buffer, check + // that they are valid UTF-8, and then append them to `buf`. This requires a + // potentially large memcpy. + // + // If `buf` is empty--the most common case--we can leverage `append_to_string` + // to read directly into `buf`'s internal byte buffer, saving an allocation and + // a memcpy. + if buf.is_empty() { + // `append_to_string`'s safety relies on the buffer only being appended to since + // it only checks the UTF-8 validity of new data. If there were existing content in + // `buf` then an untrustworthy reader (i.e. `self.inner`) could not only append + // bytes but also modify existing bytes and render them invalid. On the other hand, + // if `buf` is empty then by definition any writes must be appends and + // `append_to_string` will validate all of the new bytes. + unsafe { crate::io::append_to_string(buf, |b| self.read_to_end(b)) } + } else { + // We cannot append our byte buffer directly onto the `buf` String as there could + // be an incomplete UTF-8 sequence that has only been partially read. We must read + // everything into a side buffer first and then call `from_utf8` on the complete + // buffer. + let mut bytes = Vec::new(); + self.read_to_end(&mut bytes)?; + let string = crate::str::from_utf8(&bytes).map_err(|_| { + io::Error::new_const( + io::ErrorKind::InvalidData, + &"stream did not contain valid UTF-8", + ) + })?; + *buf += string; + Ok(string.len()) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -347,7 +391,7 @@ impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// - /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the + /// The position used for seeking with [SeekFrom::Current]\(_) is the /// position the underlying reader would be at if the `BufReader` had no /// internal buffer. /// @@ -360,11 +404,11 @@ /// /// See [`std::io::Seek`] for more details. /// - /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` + /// Note: In the edge case where you're seeking with [SeekFrom::Current]\(n) /// where `n` minus the internal buffer length overflows an `i64`, two /// seeks will be performed instead of one. If the second seek returns /// [`Err`], the underlying reader will be left at the same position it would - /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. + /// have if you called `seek` with [SeekFrom::Current]\(0). /// /// [`std::io::Seek`]: Seek fn seek(&mut self, pos: SeekFrom) -> io::Result { diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/buffered/bufwriter.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/buffered/bufwriter.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/buffered/bufwriter.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/buffered/bufwriter.rs 2021-11-29 19:27:11.000000000 +0000 @@ -18,7 +18,7 @@ /// *repeated* write calls to the same file or network socket. It does not /// help when writing very large amounts at once, or writing just one or a few /// times. It also provides no advantage when writing to a destination that is -/// in memory, like a [`Vec`]``. +/// in memory, like a [Vec]\. /// /// It is critical to call [`flush`] before `BufWriter` is dropped. Though /// dropping will attempt to flush the contents of the buffer, any errors @@ -476,6 +476,7 @@ impl WriterPanicked { /// Returns the perhaps-unwritten data. Some of this data may have been written by the /// panicking call(s) to the underlying writer, so simply writing it again is not a good idea. + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub fn into_inner(self) -> Vec { self.buf diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/buffered/tests.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/buffered/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/buffered/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/buffered/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -244,6 +244,28 @@ } #[test] +fn test_buffered_reader_read_to_end_consumes_buffer() { + let data: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7]; + let mut reader = BufReader::with_capacity(3, data); + let mut buf = Vec::new(); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2][..])); + assert_eq!(reader.read_to_end(&mut buf).ok(), Some(8)); + assert_eq!(&buf, &[0, 1, 2, 3, 4, 5, 6, 7]); + assert!(reader.buffer().is_empty()); +} + +#[test] +fn test_buffered_reader_read_to_string_consumes_buffer() { + let data: &[u8] = "deadbeef".as_bytes(); + let mut reader = BufReader::with_capacity(3, data); + let mut buf = String::new(); + assert_eq!(reader.fill_buf().ok(), Some("dea".as_bytes())); + assert_eq!(reader.read_to_string(&mut buf).ok(), Some(8)); + assert_eq!(&buf, "deadbeef"); + assert!(reader.buffer().is_empty()); +} + +#[test] fn test_buffered_writer() { let inner = Vec::new(); let mut writer = BufWriter::with_capacity(2, inner); @@ -468,9 +490,6 @@ // Writes append to this slice pub buffer: Vec, - // Flush sets this flag - pub flushed: bool, - // If true, writes will always be an error pub always_write_error: bool, @@ -520,7 +539,6 @@ if self.always_flush_error { Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error")) } else { - self.flushed = true; Ok(()) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/cursor.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/cursor.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/cursor.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/cursor.rs 2021-11-29 19:27:11.000000000 +0000 @@ -12,13 +12,13 @@ /// [`Seek`] implementation. /// /// `Cursor`s are used with in-memory buffers, anything implementing -/// [`AsRef`]`<[u8]>`, to allow them to implement [`Read`] and/or [`Write`], +/// [AsRef]<\[u8]>, to allow them to implement [`Read`] and/or [`Write`], /// allowing these buffers to be used anywhere you might use a reader or writer /// that does actual I/O. /// /// The standard library implements some I/O traits on various types which -/// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and -/// `Cursor<`[`&[u8]`][bytes]`>`. +/// are commonly used as a buffer, like Cursor<[Vec]\> and +/// Cursor<[&\[u8\]][bytes]>. /// /// # Examples /// @@ -26,7 +26,7 @@ /// code, but use an in-memory buffer in our tests. We can do this with /// `Cursor`: /// -/// [bytes]: crate::slice +/// [bytes]: crate::slice "slice" /// [`File`]: crate::fs::File /// /// ```no_run @@ -292,12 +292,7 @@ SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n), SeekFrom::Current(n) => (self.pos, n), }; - let new_pos = if offset >= 0 { - base_pos.checked_add(offset as u64) - } else { - base_pos.checked_sub((offset.wrapping_neg()) as u64) - }; - match new_pos { + match base_pos.checked_add_signed(offset) { Some(n) => { self.pos = n; Ok(self.pos) diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/error.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/error.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/error.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -473,6 +473,7 @@ /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn from_raw_os_error(code: i32) -> Error { Error { repr: Repr::Os(code) } @@ -657,6 +658,7 @@ /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] + #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub fn into_inner(self) -> Option> { match self.repr { diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -316,11 +316,12 @@ } } -// A few methods below (read_to_string, read_line) will append data into a -// `String` buffer, but we need to be pretty careful when doing this. The -// implementation will just call `.as_mut_vec()` and then delegate to a -// byte-oriented reading method, but we must ensure that when returning we never -// leave `buf` in a state such that it contains invalid UTF-8 in its bounds. +// Several `read_to_string` and `read_line` methods in the standard library will +// append data into a `String` buffer, but we need to be pretty careful when +// doing this. The implementation will just call `.as_mut_vec()` and then +// delegate to a byte-oriented reading method, but we must ensure that when +// returning we never leave `buf` in a state such that it contains invalid UTF-8 +// in its bounds. // // To this end, we use an RAII guard (to protect against panics) which updates // the length of the string when it is dropped. This guard initially truncates @@ -334,21 +335,19 @@ // 2. We're passing a raw buffer to the function `f`, and it is expected that // the function only *appends* bytes to the buffer. We'll get undefined // behavior if existing bytes are overwritten to have non-UTF-8 data. -fn append_to_string(buf: &mut String, f: F) -> Result +pub(crate) unsafe fn append_to_string(buf: &mut String, f: F) -> Result where F: FnOnce(&mut Vec) -> Result, { - unsafe { - let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() }; - let ret = f(g.buf); - if str::from_utf8(&g.buf[g.len..]).is_err() { - ret.and_then(|_| { - Err(Error::new_const(ErrorKind::InvalidData, &"stream did not contain valid UTF-8")) - }) - } else { - g.len = g.buf.len(); - ret - } + let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() }; + let ret = f(g.buf); + if str::from_utf8(&g.buf[g.len..]).is_err() { + ret.and_then(|_| { + Err(Error::new_const(ErrorKind::InvalidData, &"stream did not contain valid UTF-8")) + }) + } else { + g.len = g.buf.len(); + ret } } @@ -361,23 +360,19 @@ // // Because we're extending the buffer with uninitialized data for trusted // readers, we need to make sure to truncate that if any of this panics. -fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { - read_to_end_with_reservation(r, buf, |_| 32) -} - -fn read_to_end_with_reservation( - r: &mut R, - buf: &mut Vec, - mut reservation_size: F, -) -> Result -where - R: Read + ?Sized, - F: FnMut(&R) -> usize, -{ +pub(crate) fn default_read_to_end(r: &mut R, buf: &mut Vec) -> Result { let start_len = buf.len(); + let start_cap = buf.capacity(); let mut g = Guard { len: buf.len(), buf }; loop { - if g.len == g.buf.len() { + // If we've read all the way up to the capacity, reserve more space. + if g.len == g.buf.capacity() { + g.buf.reserve(32); + } + + // Initialize any excess capacity and adjust the length so we can write + // to it. + if g.buf.len() < g.buf.capacity() { unsafe { // FIXME(danielhenrymantilla): #42788 // @@ -387,7 +382,6 @@ // - Only the standard library gets to soundly "ignore" this, // based on its privileged knowledge of unstable rustc // internals; - g.buf.reserve(reservation_size(r)); let capacity = g.buf.capacity(); g.buf.set_len(capacity); r.initializer().initialize(&mut g.buf[g.len..]); @@ -404,12 +398,49 @@ assert!(n <= buf.len()); g.len += n; } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), } + + if g.len == g.buf.capacity() && g.buf.capacity() == start_cap { + // The buffer might be an exact fit. Let's read into a probe buffer + // and see if it returns `Ok(0)`. If so, we've avoided an + // unnecessary doubling of the capacity. But if not, append the + // probe buffer to the primary buffer and let its capacity grow. + let mut probe = [0u8; 32]; + + loop { + match r.read(&mut probe) { + Ok(0) => return Ok(g.len - start_len), + Ok(n) => { + g.buf.extend_from_slice(&probe[..n]); + g.len += n; + break; + } + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + } + } + } } } +pub(crate) fn default_read_to_string( + r: &mut R, + buf: &mut String, +) -> Result { + // Note that we do *not* call `r.read_to_end()` here. We are passing + // `&mut Vec` (the raw contents of `buf`) into the `read_to_end` + // method to fill it up. An arbitrary implementation could overwrite the + // entire contents of the vector, not just append to it (which is what + // we are expecting). + // + // To prevent extraneously checking the UTF-8-ness of the entire buffer + // we pass it to our hardcoded `default_read_to_end` implementation which + // we know is guaranteed to only read data into the end of the buffer. + unsafe { append_to_string(buf, |b| default_read_to_end(r, b)) } +} + pub(crate) fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result where F: FnOnce(&mut [u8]) -> Result, @@ -700,7 +731,7 @@ /// [`std::fs::read`]: crate::fs::read #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec) -> Result { - read_to_end(self, buf) + default_read_to_end(self, buf) } /// Read all bytes until EOF in this source, appending them to `buf`. @@ -743,16 +774,7 @@ /// [`std::fs::read_to_string`]: crate::fs::read_to_string #[stable(feature = "rust1", since = "1.0.0")] fn read_to_string(&mut self, buf: &mut String) -> Result { - // Note that we do *not* call `.read_to_end()` here. We are passing - // `&mut Vec` (the raw contents of `buf`) into the `read_to_end` - // method to fill it up. An arbitrary implementation could overwrite the - // entire contents of the vector, not just append to it (which is what - // we are expecting). - // - // To prevent extraneously checking the UTF-8-ness of the entire buffer - // we pass it to our hardcoded `read_to_end` implementation which we - // know is guaranteed to only read data into the end of the buffer. - append_to_string(buf, |b| read_to_end(self, b)) + default_read_to_string(self, buf) } /// Read the exact number of bytes required to fill `buf`. @@ -854,8 +876,8 @@ /// Transforms this `Read` instance to an [`Iterator`] over its bytes. /// - /// The returned type implements [`Iterator`] where the `Item` is - /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`. + /// The returned type implements [`Iterator`] where the [`Item`] is + /// [Result]<[u8], [io::Error]>. /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`] /// otherwise. EOF is mapped to returning [`None`] from this iterator. /// @@ -863,9 +885,10 @@ /// /// [`File`]s implement `Read`: /// - /// [`File`]: crate::fs::File - /// [`Result`]: crate::result::Result - /// [`io::Error`]: self::Error + /// [`Item`]: Iterator::Item + /// [`File`]: crate::fs::File "fs::File" + /// [Result]: crate::result::Result "Result" + /// [io::Error]: self::Error "io::Error" /// /// ```no_run /// use std::io; @@ -988,6 +1011,11 @@ /// need more control over performance, and in those cases you should definitely use /// [`Read::read_to_string`] directly. /// +/// Note that in some special cases, such as when reading files, this function will +/// pre-allocate memory based on the size of the input it is reading. In those +/// cases, the performance should be as good as if you had used +/// [`Read::read_to_string`] with a manually pre-allocated buffer. +/// /// # Errors /// /// This function forces you to handle errors because the output (the `String`) @@ -1178,6 +1206,7 @@ /// /// Panics on Windows if the slice is larger than 4GB. #[stable(feature = "iovec", since = "1.36.0")] + #[must_use] #[inline] pub fn new(buf: &'a [u8]) -> IoSlice<'a> { IoSlice(sys::io::IoSlice::new(buf)) @@ -1611,7 +1640,7 @@ /// encountered. /// /// This method is primarily used to interface with the - /// [`format_args!()`] macro, but it is rare that this should + /// [`format_args!()`] macro, and it is rare that this should /// explicitly be called. The [`write!()`] macro should be favored to /// invoke this method instead. /// @@ -2184,20 +2213,20 @@ // Note that we are not calling the `.read_until` method here, but // rather our hardcoded implementation. For more details as to why, see // the comments in `read_to_end`. - append_to_string(buf, |b| read_until(self, b'\n', b)) + unsafe { append_to_string(buf, |b| read_until(self, b'\n', b)) } } /// Returns an iterator over the contents of this reader split on the byte /// `byte`. /// /// The iterator returned from this function will return instances of - /// [`io::Result`]`<`[`Vec`]`>`. Each vector returned will *not* have + /// [io::Result]<[Vec]\>. Each vector returned will *not* have /// the delimiter byte at the end. /// /// This function will yield errors whenever [`read_until`] would have /// also yielded an error. /// - /// [`io::Result`]: self::Result + /// [io::Result]: self::Result "io::Result" /// [`read_until`]: BufRead::read_until /// /// # Examples @@ -2228,10 +2257,10 @@ /// Returns an iterator over the lines of this reader. /// /// The iterator returned from this function will yield instances of - /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline + /// [io::Result]<[String]>. Each string returned will *not* have a newline /// byte (the `0xA` byte) or `CRLF` (`0xD`, `0xA` bytes) at the end. /// - /// [`io::Result`]: self::Result + /// [io::Result]: self::Result "io::Result" /// /// # Examples /// @@ -2583,13 +2612,6 @@ unsafe fn initializer(&self) -> Initializer { self.inner.initializer() } - - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - // Pass in a reservation_size closure that respects the current value - // of limit for each read. If we hit the read limit, this prevents the - // final zero-byte read from allocating again. - read_to_end_with_reservation(self, buf, |self_| cmp::min(self_.limit, 32) as usize) - } } #[stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/stdio.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/stdio.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/stdio.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/stdio.rs 2021-11-29 19:27:11.000000000 +0000 @@ -256,6 +256,7 @@ /// Ok(()) /// } /// ``` +#[must_use = "if unused stdin will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct StdinLock<'a> { inner: MutexGuard<'a, BufReader>, @@ -463,6 +464,7 @@ /// println!("got a line: {}", line.unwrap()); /// } /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "stdin_forwarders", issue = "87096")] pub fn lines(self) -> Lines> { self.into_locked().lines() @@ -624,6 +626,7 @@ /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return /// an error. +#[must_use = "if unused stdout will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { inner: ReentrantMutexGuard<'a, RefCell>>, @@ -907,6 +910,7 @@ /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return /// an error. +#[must_use = "if unused stderr will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct StderrLock<'a> { inner: ReentrantMutexGuard<'a, RefCell>, diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/tests.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -290,7 +290,7 @@ b.iter(|| { let mut lr = repeat(1).take(10000000); let mut vec = Vec::with_capacity(1024); - super::read_to_end(&mut lr, &mut vec) + super::default_read_to_end(&mut lr, &mut vec) }); } @@ -362,24 +362,12 @@ fn test_read_to_end_capacity() -> io::Result<()> { let input = &b"foo"[..]; - // read_to_end() generally needs to over-allocate, both for efficiency - // and so that it can distinguish EOF. Assert that this is the case - // with this simple ExampleSliceReader struct, which uses the default - // implementation of read_to_end. Even though vec1 is allocated with - // exactly enough capacity for the read, read_to_end will allocate more - // space here. + // read_to_end() takes care not to over-allocate when a buffer is the + // exact size needed. let mut vec1 = Vec::with_capacity(input.len()); ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?; assert_eq!(vec1.len(), input.len()); - assert!(vec1.capacity() > input.len(), "allocated more"); - - // However, std::io::Take includes an implementation of read_to_end - // that will not allocate when the limit has already been reached. In - // this case, vec2 never grows. - let mut vec2 = Vec::with_capacity(input.len()); - ExampleSliceReader { slice: input }.take(input.len() as u64).read_to_end(&mut vec2)?; - assert_eq!(vec2.len(), input.len()); - assert_eq!(vec2.capacity(), input.len(), "did not allocate more"); + assert_eq!(vec1.capacity(), input.len(), "did not allocate more"); Ok(()) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/io/util.rs rustc-1.57.0+dfsg1+llvm/library/std/src/io/util.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/io/util.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/io/util.rs 2021-11-29 19:27:11.000000000 +0000 @@ -19,7 +19,7 @@ /// Constructs a new handle to an empty reader. /// -/// All reads from the returned reader will return [`Ok`]`(0)`. +/// All reads from the returned reader will return [Ok]\(0). /// /// # Examples /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/keyword_docs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/keyword_docs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/keyword_docs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/keyword_docs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -77,7 +77,7 @@ /// '_inner: for j in 1..=200 { /// println!(" inner iteration (j): {}", j); /// if j >= 3 { -/// // breaks from inner loop, let's outer loop continue. +/// // breaks from inner loop, lets outer loop continue. /// break; /// } /// if i >= 2 { @@ -119,7 +119,7 @@ #[doc(keyword = "const")] // -/// Compile-time constants and compile-time evaluable functions. +/// Compile-time constants, compile-time evaluable functions, and raw pointers. /// /// ## Compile-time constants /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/lazy.rs rustc-1.57.0+dfsg1+llvm/library/std/src/lazy.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/lazy.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/lazy.rs 2021-11-29 19:27:11.000000000 +0000 @@ -171,6 +171,7 @@ impl SyncOnceCell { /// Creates a new empty cell. #[unstable(feature = "once_cell", issue = "74465")] + #[must_use] pub const fn new() -> SyncOnceCell { SyncOnceCell { once: Once::new(), diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/lib.rs rustc-1.57.0+dfsg1+llvm/library/std/src/lib.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/lib.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/lib.rs 2021-11-29 19:27:11.000000000 +0000 @@ -195,6 +195,15 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr( + not(bootstrap), + doc(cfg_hide( + not(test), + not(any(test, bootstrap)), + no_global_oom_handling, + not(no_global_oom_handling) + )) +)] // Don't link to std. We are std. #![no_std] #![warn(deprecated_in_future)] @@ -234,6 +243,7 @@ #![feature(atomic_mut_ptr)] #![feature(auto_traits)] #![feature(bench_black_box)] +#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(c_unwind)] #![feature(c_variadic)] @@ -247,7 +257,6 @@ #![feature(const_cstr_unchecked)] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] -#![cfg_attr(bootstrap, feature(const_fn_transmute))] #![feature(const_format_args)] #![feature(const_io_structs)] #![feature(const_ip)] @@ -259,13 +268,15 @@ #![feature(const_trait_impl)] #![feature(container_error_extra)] #![feature(core_intrinsics)] +#![feature(core_panic)] #![feature(custom_test_frameworks)] #![feature(decl_macro)] #![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] #![feature(doc_keyword)] #![feature(doc_masked)] #![feature(doc_notable_trait)] -#![cfg_attr(not(bootstrap), feature(doc_primitive))] +#![feature(doc_primitive)] #![feature(dropck_eyepatch)] #![feature(duration_checked_float)] #![feature(duration_constants)] @@ -296,6 +307,8 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] +#![cfg_attr(not(bootstrap), feature(must_not_suspend))] #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] @@ -329,7 +342,6 @@ #![feature(total_cmp)] #![feature(trace_macros)] #![feature(try_blocks)] -#![feature(try_reserve)] #![feature(try_reserve_kind)] #![feature(unboxed_closures)] #![feature(unwrap_infallible)] @@ -519,20 +531,20 @@ pub use alloc::task::*; } -// Platform-abstraction modules +// The runtime entry point and a few unstable public functions used by the +// compiler #[macro_use] -mod sys_common; +pub mod rt; + +// Platform-abstraction modules mod sys; +mod sys_common; pub mod alloc; // Private support modules mod panicking; -// The runtime entry point and a few unstable public functions used by the -// compiler -pub mod rt; - #[path = "../../backtrace/src/lib.rs"] #[allow(dead_code, unused_attributes)] mod backtrace_rs; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/net/addr.rs rustc-1.57.0+dfsg1+llvm/library/std/src/net/addr.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/net/addr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/net/addr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -131,6 +131,7 @@ /// assert_eq!(socket.port(), 8080); /// ``` #[stable(feature = "ip_addr", since = "1.7.0")] + #[must_use] pub fn new(ip: IpAddr, port: u16) -> SocketAddr { match ip { IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), @@ -231,6 +232,7 @@ /// assert_eq!(socket.is_ipv4(), true); /// assert_eq!(socket.is_ipv6(), false); /// ``` + #[must_use] #[stable(feature = "sockaddr_checker", since = "1.16.0")] #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] pub const fn is_ipv4(&self) -> bool { @@ -252,6 +254,7 @@ /// assert_eq!(socket.is_ipv4(), false); /// assert_eq!(socket.is_ipv6(), true); /// ``` + #[must_use] #[stable(feature = "sockaddr_checker", since = "1.16.0")] #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] pub const fn is_ipv6(&self) -> bool { @@ -272,6 +275,7 @@ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { SocketAddrV4 { inner: c::sockaddr_in { @@ -368,6 +372,7 @@ /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { SocketAddrV6 { inner: c::sockaddr_in6 { @@ -765,15 +770,15 @@ /// /// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. /// -/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`, -/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: +/// * [`SocketAddrV4`], [`SocketAddrV6`], ([IpAddr], [u16]), +/// ([Ipv4Addr], [u16]), ([Ipv6Addr], [u16]): /// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(`[`&str`]`, `[`u16`]`)`: [`&str`] should be either a string representation +/// * (&[str], [u16]): &[str] should be either a string representation /// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host /// name. [`u16`] is the port number. /// -/// * [`&str`]: the string should be either a string representation of a +/// * &[str]: the string should be either a string representation of a /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like /// `:` pair where `` is a [`u16`] value. /// @@ -789,11 +794,10 @@ /// Addresses returned by the operating system that are not IP addresses are /// silently ignored. /// -/// [`FromStr`]: crate::str::FromStr -/// [`&str`]: str -/// [`TcpStream`]: crate::net::TcpStream +/// [`FromStr`]: crate::str::FromStr "std::str::FromStr" +/// [`TcpStream`]: crate::net::TcpStream "net::TcpStream" /// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs -/// [`UdpSocket`]: crate::net::UdpSocket +/// [`UdpSocket`]: crate::net::UdpSocket "net::UdpSocket" /// /// # Examples /// @@ -872,7 +876,7 @@ #[stable(feature = "rust1", since = "1.0.0")] type Iter: Iterator; - /// Converts this object to an iterator of resolved `SocketAddr`s. + /// Converts this object to an iterator of resolved [`SocketAddr`]s. /// /// The returned iterator might not actually yield any values depending on the /// outcome of any resolution performed. diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/net/ip/tests.rs rustc-1.57.0+dfsg1+llvm/library/std/src/net/ip/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/net/ip/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/net/ip/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -224,6 +224,7 @@ let global: u8 = 1 << 2; let multicast: u8 = 1 << 3; let doc: u8 = 1 << 4; + let benchmarking: u8 = 1 << 5; if ($mask & unspec) == unspec { assert!(ip!($s).is_unspecified()); @@ -254,6 +255,12 @@ } else { assert!(!ip!($s).is_documentation()); } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } }}; } @@ -262,6 +269,7 @@ let global: u8 = 1 << 2; let multicast: u8 = 1 << 3; let doc: u8 = 1 << 4; + let benchmarking: u8 = 1 << 5; check!("0.0.0.0", unspec); check!("0.0.0.1"); @@ -280,9 +288,9 @@ check!("239.255.255.255", global | multicast); check!("255.255.255.255"); // make sure benchmarking addresses are not global - check!("198.18.0.0"); - check!("198.18.54.2"); - check!("198.19.255.255"); + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); // make sure addresses reserved for protocol assignment are not global check!("192.0.0.0"); check!("192.0.0.255"); @@ -313,6 +321,7 @@ check!("ff08::", multicast); check!("ff0e::", global | multicast); check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("2001:2::ac32:23ff:21", global | benchmarking); check!("102:304:506:708:90a:b0c:d0e:f10", global); } @@ -467,21 +476,22 @@ assert_eq!(&ip!($s).octets(), octets); assert_eq!(Ipv6Addr::from(*octets), ip!($s)); - let unspecified: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let unique_local: u16 = 1 << 2; - let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_global: u16 = 1 << 7; - let documentation: u16 = 1 << 8; - let multicast_interface_local: u16 = 1 << 9; - let multicast_link_local: u16 = 1 << 10; - let multicast_realm_local: u16 = 1 << 11; - let multicast_admin_local: u16 = 1 << 12; - let multicast_site_local: u16 = 1 << 13; - let multicast_organization_local: u16 = 1 << 14; - let multicast_global: u16 = 1 << 15; - let multicast: u16 = multicast_interface_local + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let benchmarking: u32 = 1 << 16; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let multicast: u32 = multicast_interface_local | multicast_admin_local | multicast_global | multicast_link_local @@ -524,6 +534,11 @@ } else { assert!(!ip!($s).is_documentation()); } + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } if ($mask & multicast) != 0 { assert!(ip!($s).multicast_scope().is_some()); assert!(ip!($s).is_multicast()); @@ -562,20 +577,21 @@ } } - let unspecified: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let unique_local: u16 = 1 << 2; - let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_global: u16 = 1 << 7; - let documentation: u16 = 1 << 8; - let multicast_interface_local: u16 = 1 << 9; - let multicast_link_local: u16 = 1 << 10; - let multicast_realm_local: u16 = 1 << 11; - let multicast_admin_local: u16 = 1 << 12; - let multicast_site_local: u16 = 1 << 13; - let multicast_organization_local: u16 = 1 << 14; - let multicast_global: u16 = 1 << 15; + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let benchmarking: u32 = 1 << 16; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); @@ -672,6 +688,12 @@ ); check!( + "2001:2::ac32:23ff:21", + &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], + global | unicast_global | benchmarking + ); + + check!( "102:304:506:708:90a:b0c:d0e:f10", &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], global | unicast_global @@ -874,6 +896,9 @@ const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); assert!(!IS_DOCUMENTATION); + const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); assert!(!IS_UNICAST_GLOBAL); diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/net/ip.rs rustc-1.57.0+dfsg1+llvm/library/std/src/net/ip.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/net/ip.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/net/ip.rs 2021-11-29 19:27:11.000000000 +0000 @@ -233,6 +233,7 @@ /// ``` #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] + #[must_use] #[inline] pub const fn is_unspecified(&self) -> bool { match self { @@ -256,6 +257,7 @@ /// ``` #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] + #[must_use] #[inline] pub const fn is_loopback(&self) -> bool { match self { @@ -281,6 +283,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_global(&self) -> bool { match self { @@ -304,6 +307,7 @@ /// ``` #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] + #[must_use] #[inline] pub const fn is_multicast(&self) -> bool { match self { @@ -332,6 +336,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_documentation(&self) -> bool { match self { @@ -340,6 +345,31 @@ } } + /// Returns [`true`] if this address is in a range designated for benchmarking. + /// + /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and + /// [`Ipv6Addr::is_benchmarking()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); + /// ``` + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_benchmarking(), + IpAddr::V6(ip) => ip.is_benchmarking(), + } + } + /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] /// otherwise. /// @@ -355,6 +385,7 @@ /// ``` #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ipaddr_checker", since = "1.16.0")] + #[must_use] #[inline] pub const fn is_ipv4(&self) -> bool { matches!(self, IpAddr::V4(_)) @@ -375,6 +406,7 @@ /// ``` #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ipaddr_checker", since = "1.16.0")] + #[must_use] #[inline] pub const fn is_ipv6(&self) -> bool { matches!(self, IpAddr::V6(_)) @@ -394,6 +426,8 @@ /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); /// ``` #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] pub const fn to_canonical(&self) -> IpAddr { @@ -418,6 +452,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { // `s_addr` is stored as BE on all machine and the array is in BE order. @@ -502,6 +537,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")] #[stable(feature = "ip_shared", since = "1.12.0")] + #[must_use] #[inline] pub const fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 @@ -523,6 +559,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 @@ -553,6 +590,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_private(&self) -> bool { match self.octets() { @@ -580,6 +618,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_link_local(&self) -> bool { matches!(self.octets(), [169, 254, ..]) @@ -655,6 +694,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two @@ -695,6 +735,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) @@ -720,6 +761,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 @@ -754,6 +796,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() @@ -777,6 +820,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 @@ -798,6 +842,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_broadcast(&self) -> bool { u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) @@ -825,6 +870,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_documentation(&self) -> bool { match self.octets() { @@ -857,6 +903,8 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); @@ -882,6 +930,8 @@ /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); @@ -1166,9 +1216,9 @@ /// /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); /// ``` - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { let addr16 = [ @@ -1228,7 +1278,6 @@ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1267,6 +1316,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_unspecified(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) @@ -1290,6 +1340,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_loopback(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) @@ -1316,6 +1367,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_global(&self) -> bool { match self.multicast_scope() { @@ -1343,6 +1395,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 @@ -1371,6 +1424,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_unicast(&self) -> bool { !self.is_multicast() @@ -1422,6 +1476,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 @@ -1446,11 +1501,35 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } + /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). + /// + /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`. + /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`. + /// + /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180 + /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752 + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true); + /// ``` + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) + } + /// Returns [`true`] if the address is a globally routable unicast address. /// /// The following return false: @@ -1483,6 +1562,7 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use] #[inline] pub const fn is_unicast_global(&self) -> bool { self.is_unicast() @@ -1544,6 +1624,7 @@ /// ``` #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] #[inline] pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 @@ -1573,6 +1654,8 @@ /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_ipv4_mapped(&self) -> Option { match self.octets() { @@ -1591,7 +1674,7 @@ /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d` /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. /// - /// [IPv4 address]: Ipv4Addr + /// [`IPv4` address]: Ipv4Addr /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 @@ -1610,6 +1693,8 @@ /// ``` #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub const fn to_ipv4(&self) -> Option { if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { @@ -1633,9 +1718,11 @@ /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); /// ``` - #[inline] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] pub const fn to_canonical(&self) -> IpAddr { if let Some(mapped) = self.to_ipv4_mapped() { return IpAddr::V4(mapped); diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/net/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/net/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/net/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/net/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -44,16 +44,16 @@ pub enum Shutdown { /// The reading portion of the [`TcpStream`] should be shut down. /// - /// All currently blocked and future [reads] will return [`Ok`]`(0)`. + /// All currently blocked and future [reads] will return [Ok]\(0). /// - /// [reads]: crate::io::Read + /// [reads]: crate::io::Read "io::Read" #[stable(feature = "rust1", since = "1.0.0")] Read, /// The writing portion of the [`TcpStream`] should be shut down. /// /// All currently blocked and future [writes] will return an error. /// - /// [writes]: crate::io::Write + /// [writes]: crate::io::Write "io::Write" #[stable(feature = "rust1", since = "1.0.0")] Write, /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/net/tcp.rs rustc-1.57.0+dfsg1+llvm/library/std/src/net/tcp.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/net/tcp.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/net/tcp.rs 2021-11-29 19:27:11.000000000 +0000 @@ -96,6 +96,18 @@ listener: &'a TcpListener, } +/// An iterator that infinitely [`accept`]s connections on a [`TcpListener`]. +/// +/// This `struct` is created by the [`TcpListener::into_incoming`] method. +/// See its documentation for more. +/// +/// [`accept`]: TcpListener::accept +#[derive(Debug)] +#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +pub struct IntoIncoming { + listener: TcpListener, +} + impl TcpStream { /// Opens a TCP connection to a remote host. /// @@ -845,6 +857,38 @@ Incoming { listener: self } } + /// Turn this into an iterator over the connections being received on this + /// listener. + /// + /// The returned iterator will never return [`None`] and will also not yield + /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to + /// calling [`TcpListener::accept`] in a loop. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcplistener_into_incoming)] + /// use std::net::{TcpListener, TcpStream}; + /// + /// fn listen_on(port: u16) -> impl Iterator { + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.into_incoming() + /// .filter_map(Result::ok) /* Ignore failed connections */ + /// } + /// + /// fn main() -> std::io::Result<()> { + /// for stream in listen_on(80) { + /// /* handle the connection here */ + /// } + /// Ok(()) + /// } + /// ``` + #[must_use = "`self` will be dropped if the result is not used"] + #[unstable(feature = "tcplistener_into_incoming", issue = "88339")] + pub fn into_incoming(self) -> IntoIncoming { + IntoIncoming { listener: self } + } + /// Sets the value for the `IP_TTL` option on this socket. /// /// This value sets the time-to-live field that is used in every packet sent @@ -979,6 +1023,14 @@ type Item = io::Result; fn next(&mut self) -> Option> { Some(self.listener.accept().map(|p| p.0)) + } +} + +#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +impl Iterator for IntoIncoming { + type Item = io::Result; + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|p| p.0)) } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/linux/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/linux/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/linux/fs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/linux/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! Linux-specific extensions to primitives in the `std::fs` module. +//! Linux-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs #![stable(feature = "metadata_ext", since = "1.1.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/linux/process.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/linux/process.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/linux/process.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/linux/process.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! Linux-specific extensions to primitives in the `std::process` module. +//! Linux-specific extensions to primitives in the [`std::process`] module. +//! +//! [`std::process`]: crate::process #![unstable(feature = "linux_pidfd", issue = "82971")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/linux/raw.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/linux/raw.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/linux/raw.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/linux/raw.rs 2021-11-29 19:27:11.000000000 +0000 @@ -27,6 +27,7 @@ #[cfg(any( target_arch = "x86", target_arch = "le32", + target_arch = "m68k", target_arch = "powerpc", target_arch = "sparc", target_arch = "arm", diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,117 +10,138 @@ // of a macro that is not vendored by Rust and included in the toolchain. // See https://github.com/rust-analyzer/rust-analyzer/issues/6038. +// On certain platforms right now the "main modules" modules that are +// documented don't compile (missing things in `libc` which is empty), +// so just omit them with an empty module and add the "unstable" attribute. + +// Unix, linux, wasi and windows are handled a bit differently. +#[cfg(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +))] +#[unstable(issue = "none", feature = "std_internals")] +pub mod unix {} #[cfg(all( doc, - not(any( + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +))] +#[unstable(issue = "none", feature = "std_internals")] +pub mod linux {} +#[cfg(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +))] +#[unstable(issue = "none", feature = "std_internals")] +pub mod wasi {} +#[cfg(all( + doc, + any( all(target_arch = "wasm32", not(target_os = "wasi")), all(target_vendor = "fortanix", target_env = "sgx") - )) + ) ))] -#[path = "."] -mod doc { - // When documenting std we want to show the `unix`, `windows`, `linux` and `wasi` - // modules as these are the "main modules" that are used across platforms, - // so these modules are enabled when `cfg(doc)` is set. - // This should help show platform-specific functionality in a hopefully cross-platform - // way in the documentation. +#[unstable(issue = "none", feature = "std_internals")] +pub mod windows {} - pub mod unix; +// unix +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] +#[cfg(target_os = "hermit")] +#[path = "hermit/mod.rs"] +pub mod unix; +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] +#[cfg(all(not(target_os = "hermit"), any(unix, doc)))] +pub mod unix; - pub mod linux; +// linux +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] +#[cfg(any(target_os = "linux", target_os = "l4re", doc))] +pub mod linux; - pub mod wasi; +// wasi +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] +#[cfg(any(target_os = "wasi", doc))] +pub mod wasi; - pub mod windows; -} -#[cfg(all( +// windows +#[cfg(not(all( doc, any( all(target_arch = "wasm32", not(target_os = "wasi")), all(target_vendor = "fortanix", target_env = "sgx") ) -))] -mod doc { - // On certain platforms right now the "main modules" modules that are - // documented don't compile (missing things in `libc` which is empty), - // so just omit them with an empty module. - - #[unstable(issue = "none", feature = "std_internals")] - pub mod unix {} - - #[unstable(issue = "none", feature = "std_internals")] - pub mod linux {} - - #[unstable(issue = "none", feature = "std_internals")] - pub mod wasi {} - - #[unstable(issue = "none", feature = "std_internals")] - pub mod windows {} -} -#[cfg(doc)] -#[stable(feature = "os", since = "1.0.0")] -pub use doc::*; - -#[cfg(not(doc))] -#[path = "."] -mod imp { - // If we're not documenting std then we only expose modules appropriate for the - // current platform. - - #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] - pub mod fortanix_sgx; - - #[cfg(target_os = "hermit")] - #[path = "hermit/mod.rs"] - pub mod unix; - - #[cfg(target_os = "android")] - pub mod android; - #[cfg(target_os = "dragonfly")] - pub mod dragonfly; - #[cfg(target_os = "emscripten")] - pub mod emscripten; - #[cfg(target_os = "espidf")] - pub mod espidf; - #[cfg(target_os = "freebsd")] - pub mod freebsd; - #[cfg(target_os = "fuchsia")] - pub mod fuchsia; - #[cfg(target_os = "haiku")] - pub mod haiku; - #[cfg(target_os = "illumos")] - pub mod illumos; - #[cfg(target_os = "ios")] - pub mod ios; - #[cfg(target_os = "l4re")] - pub mod linux; - #[cfg(target_os = "linux")] - pub mod linux; - #[cfg(target_os = "macos")] - pub mod macos; - #[cfg(target_os = "netbsd")] - pub mod netbsd; - #[cfg(target_os = "openbsd")] - pub mod openbsd; - #[cfg(target_os = "redox")] - pub mod redox; - #[cfg(target_os = "solaris")] - pub mod solaris; - #[cfg(unix)] - pub mod unix; - - #[cfg(target_os = "vxworks")] - pub mod vxworks; - - #[cfg(target_os = "wasi")] - pub mod wasi; - - #[cfg(windows)] - pub mod windows; -} -#[cfg(not(doc))] -#[stable(feature = "os", since = "1.0.0")] -pub use imp::*; +)))] +#[cfg(any(windows, doc))] +pub mod windows; + +// Others. +#[cfg(target_os = "android")] +pub mod android; +#[cfg(target_os = "dragonfly")] +pub mod dragonfly; +#[cfg(target_os = "emscripten")] +pub mod emscripten; +#[cfg(target_os = "espidf")] +pub mod espidf; +#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] +pub mod fortanix_sgx; +#[cfg(target_os = "freebsd")] +pub mod freebsd; +#[cfg(target_os = "fuchsia")] +pub mod fuchsia; +#[cfg(target_os = "haiku")] +pub mod haiku; +#[cfg(target_os = "illumos")] +pub mod illumos; +#[cfg(target_os = "ios")] +pub mod ios; +#[cfg(target_os = "macos")] +pub mod macos; +#[cfg(target_os = "netbsd")] +pub mod netbsd; +#[cfg(target_os = "openbsd")] +pub mod openbsd; +#[cfg(target_os = "redox")] +pub mod redox; +#[cfg(target_os = "solaris")] +pub mod solaris; + +#[cfg(target_os = "solid_asp3")] +pub mod solid; +#[cfg(target_os = "vxworks")] +pub mod vxworks; #[cfg(any(unix, target_os = "wasi", doc))] mod fd; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/raw/char.md rustc-1.57.0+dfsg1+llvm/library/std/src/os/raw/char.md --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/raw/char.md 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/raw/char.md 2021-11-29 19:27:11.000000000 +0000 @@ -1,6 +1,6 @@ Equivalent to C's `char` type. -[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. This type will always be either [`i8`] or [`u8`], as the type is defined as being one byte long. +[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addresses memory with 8-bit bytes. C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information. diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/raw/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/raw/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/raw/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/raw/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -46,6 +46,7 @@ } type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; +#[doc(cfg(all()))] #[cfg(any( all( target_os = "linux", @@ -88,6 +89,7 @@ all(target_os = "fuchsia", target_arch = "aarch64") ))]} type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8; +#[doc(cfg(all()))] #[cfg(not(any( all( target_os = "linux", @@ -136,12 +138,16 @@ type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; } type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; } type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32; +#[doc(cfg(all()))] #[cfg(any(target_pointer_width = "32", windows))] } type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32; +#[doc(cfg(all()))] #[cfg(any(target_pointer_width = "32", windows))] } type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64; +#[doc(cfg(all()))] #[cfg(all(target_pointer_width = "64", not(windows)))] } type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64; +#[doc(cfg(all()))] #[cfg(all(target_pointer_width = "64", not(windows)))] } type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; } type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/solid/ffi.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/solid/ffi.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/solid/ffi.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/solid/ffi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,41 @@ +//! SOLID-specific extension to the primitives in the `std::ffi` module +//! +//! # Examples +//! +//! ``` +//! use std::ffi::OsString; +//! use std::os::solid::ffi::OsStringExt; +//! +//! let bytes = b"foo".to_vec(); +//! +//! // OsStringExt::from_vec +//! let os_string = OsString::from_vec(bytes); +//! assert_eq!(os_string.to_str(), Some("foo")); +//! +//! // OsStringExt::into_vec +//! let bytes = os_string.into_vec(); +//! assert_eq!(bytes, b"foo"); +//! ``` +//! +//! ``` +//! use std::ffi::OsStr; +//! use std::os::solid::ffi::OsStrExt; +//! +//! let bytes = b"foo"; +//! +//! // OsStrExt::from_bytes +//! let os_str = OsStr::from_bytes(bytes); +//! assert_eq!(os_str.to_str(), Some("foo")); +//! +//! // OsStrExt::as_bytes +//! let bytes = os_str.as_bytes(); +//! assert_eq!(bytes, b"foo"); +//! ``` + +#![stable(feature = "rust1", since = "1.0.0")] + +#[path = "../unix/ffi/os_str.rs"] +mod os_str; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::os_str::{OsStrExt, OsStringExt}; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/solid/io.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/solid/io.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/solid/io.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/solid/io.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,113 @@ +//! SOLID-specific extensions to general I/O primitives + +#![deny(unsafe_op_in_unsafe_fn)] +#![unstable(feature = "solid_ext", issue = "none")] + +use crate::net; +use crate::sys; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; + +/// Raw file descriptors. +pub type RawFd = i32; + +/// A trait to extract the raw SOLID Sockets file descriptor from an underlying +/// object. +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This method does **not** pass ownership of the raw file descriptor + /// to the caller. The descriptor is only guaranteed to be valid while + /// the original object has not yet been destroyed. + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +pub trait FromRawFd { + /// Constructs a new instance of `Self` from the given raw file + /// descriptor. + /// + /// This function **consumes ownership** of the specified file + /// descriptor. The returned object will take responsibility for closing + /// it when the object goes out of scope. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_fd(fd: RawFd) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + fn into_raw_fd(self) -> RawFd; +} + +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + +macro_rules! impl_as_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRawFd for net::$t { + #[inline] + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } + } + )*}; +} +impl_as_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_from_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "from_raw_os", since = "1.1.0")] + impl FromRawFd for net::$t { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> net::$t { + let socket = sys::net::Socket::from_inner(fd); + net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + } + } + )*}; +} +impl_from_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_into_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "into_raw_os", since = "1.4.0")] + impl IntoRawFd for net::$t { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } + } + )*}; +} +impl_into_raw_fd! { TcpStream TcpListener UdpSocket } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/solid/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/solid/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/solid/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/solid/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,17 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod ffi; +pub mod io; + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::ffi::{OsStrExt, OsStringExt}; + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/ffi/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/ffi/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/ffi/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/ffi/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -//! Unix-specific extension to the primitives in the `std::ffi` module. +//! Unix-specific extensions to primitives in the [`std::ffi`] module. //! //! # Examples //! @@ -31,6 +31,8 @@ //! let bytes = os_str.as_bytes(); //! assert_eq!(bytes, b"foo"); //! ``` +//! +//! [`std::ffi`]: crate::ffi #![stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/fs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,10 +1,13 @@ -//! Unix-specific extensions to primitives in the `std::fs` module. +//! Unix-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs #![stable(feature = "rust1", since = "1.0.0")] use super::platform::fs::MetadataExt as _; use crate::fs::{self, OpenOptions, Permissions}; use crate::io; +use crate::os::unix::io::{AsFd, AsRawFd}; use crate::path::Path; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; @@ -924,6 +927,75 @@ } } +/// Change the owner and group of the specified path. +/// +/// Specifying either the uid or gid as `None` will leave it unchanged. +/// +/// Changing the owner typically requires privileges, such as root or a specific capability. +/// Changing the group typically requires either being the owner and a member of the group, or +/// having privileges. +/// +/// If called on a symbolic link, this will change the owner and group of the link target. To +/// change the owner and group of the link itself, see [`lchown`]. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// fs::chown("/sandbox", Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "88989")] +pub fn chown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + +/// Change the owner and group of the file referenced by the specified open file descriptor. +/// +/// For semantics and required privileges, see [`chown`]. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// let f = std::fs::File::open("/file")?; +/// fs::fchown(f, Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "88989")] +pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + +/// Change the owner and group of the specified path, without dereferencing symbolic links. +/// +/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner +/// and group of the link itself rather than the owner and group of the link target. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// fs::lchown("/symlink", Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "88989")] +pub fn lchown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + /// Change the root directory of the current process to the specified path. /// /// This typically requires privileges, such as root or a specific capability. diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,8 +4,8 @@ //! exposes Unix-specific functions that would otherwise be inappropriate as //! part of the core `std` library. //! -//! It exposes more ways to deal with platform-specific strings (`OsStr`, -//! `OsString`), allows to set permissions more granularly, extract low-level +//! It exposes more ways to deal with platform-specific strings ([`OsStr`], +//! [`OsString`]), allows to set permissions more granularly, extract low-level //! file descriptors from files and sockets, and has platform-specific helpers //! for spawning processes. //! @@ -24,6 +24,9 @@ //! Ok(()) //! } //! ``` +//! +//! [`OsStr`]: crate::ffi::OsStr +//! [`OsString`]: crate::ffi::OsString #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(unix))] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/addr.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/addr.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/addr.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/addr.rs 2021-11-29 19:27:11.000000000 +0000 @@ -92,8 +92,8 @@ #[derive(Clone)] #[stable(feature = "unix_socket", since = "1.10.0")] pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, + pub(super) addr: libc::sockaddr_un, + pub(super) len: libc::socklen_t, } impl SocketAddr { @@ -156,6 +156,7 @@ /// Ok(()) /// } /// ``` + #[must_use] #[stable(feature = "unix_socket", since = "1.10.0")] pub fn is_unnamed(&self) -> bool { if let AddressKind::Unnamed = self.address() { true } else { false } @@ -192,10 +193,36 @@ /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[must_use] pub fn as_pathname(&self) -> Option<&Path> { if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } } + /// Returns the contents of this address if it is an abstract namespace + /// without the leading null byte. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let namespace = b"hidden"; + /// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?; + /// let socket = UnixListener::bind_addr(&namespace_addr)?; + /// let local_addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..])); + /// Ok(()) + /// } + /// ``` + #[doc(cfg(any(target_os = "android", target_os = "linux")))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn as_abstract_namespace(&self) -> Option<&[u8]> { + if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None } + } + fn address(&self) -> AddressKind<'_> { let len = self.len as usize - sun_path_offset(&self.addr); let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; @@ -212,6 +239,65 @@ AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) } } + + /// Creates an abstract domain socket address from a namespace + /// + /// An abstract address does not create a file unlike traditional path-based + /// Unix sockets. The advantage of this is that the address will disappear when + /// the socket bound to it is closed, so no filesystem clean up is required. + /// + /// The leading null byte for the abstract namespace is automatically added. + /// + /// This is a Linux-specific extension. See more at [`unix(7)`]. + /// + /// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html + /// + /// # Errors + /// + /// This will return an error if the given namespace is too long + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; + /// let listener = match UnixListener::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[doc(cfg(any(target_os = "android", target_os = "linux")))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + if namespace.len() + 1 > addr.sun_path.len() { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"namespace must be shorter than SUN_LEN", + )); + } + + crate::ptr::copy_nonoverlapping( + namespace.as_ptr(), + addr.sun_path.as_mut_ptr().offset(1) as *mut u8, + namespace.len(), + ); + let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t; + SocketAddr::from_parts(addr, len) + } + } } #[stable(feature = "unix_socket", since = "1.10.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/ancillary.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/ancillary.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/ancillary.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/ancillary.rs 2021-11-29 19:27:11.000000000 +0000 @@ -189,6 +189,7 @@ /// /// PID, UID and GID is set to 0. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + #[must_use] pub fn new() -> SocketCred { SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/datagram.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/datagram.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/datagram.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/datagram.rs 2021-11-29 19:27:11.000000000 +0000 @@ -112,6 +112,41 @@ } } + /// Creates a Unix datagram socket bound to an address. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram}; + /// + /// fn main() -> std::io::Result<()> { + /// let sock1 = UnixDatagram::bind("path/to/socket")?; + /// let addr = sock1.local_addr()?; + /// + /// let sock2 = match UnixDatagram::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { + unsafe { + let socket = UnixDatagram::unbound()?; + cvt(libc::bind( + socket.as_raw_fd(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len as _, + ))?; + Ok(socket) + } + } + /// Creates a Unix Datagram socket which is not bound to any address. /// /// # Examples @@ -156,7 +191,7 @@ Ok((UnixDatagram(i1), UnixDatagram(i2))) } - /// Connects the socket to the specified address. + /// Connects the socket to the specified path address. /// /// The [`send`] method may be used to send data to the specified address. /// [`recv`] and [`recv_from`] will only receive data from that address. @@ -192,6 +227,41 @@ Ok(()) } + /// Connects the socket to an address. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram}; + /// + /// fn main() -> std::io::Result<()> { + /// let bound = UnixDatagram::bind("/path/to/socket")?; + /// let addr = bound.local_addr()?; + /// + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect_addr(&addr) { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { + unsafe { + cvt(libc::connect( + self.as_raw_fd(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; + } + Ok(()) + } + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `UnixDatagram` is a reference to the same socket that this @@ -471,6 +541,42 @@ ))?; Ok(count as usize) } + } + + /// Sends data on the socket to the specified [SocketAddr]. + /// + /// On success, returns the number of bytes written. + /// + /// [SocketAddr]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram}; + /// + /// fn main() -> std::io::Result<()> { + /// let bound = UnixDatagram::bind("/path/to/socket")?; + /// let addr = bound.local_addr()?; + /// + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("send_to_addr function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result { + unsafe { + let count = cvt(libc::sendto( + self.as_raw_fd(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; + Ok(count as usize) + } } /// Sends data on the socket to the socket's peer. diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/listener.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/listener.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/listener.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/listener.rs 2021-11-29 19:27:11.000000000 +0000 @@ -81,6 +81,44 @@ } } + /// Creates a new `UnixListener` bound to the specified [`socket address`]. + /// + /// [`socket address`]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener}; + /// + /// fn main() -> std::io::Result<()> { + /// let listener1 = UnixListener::bind("path/to/socket")?; + /// let addr = listener1.local_addr()?; + /// + /// let listener2 = match UnixListener::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + cvt(libc::bind( + inner.as_raw_fd(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len as _, + ))?; + cvt(libc::listen(inner.as_raw_fd(), 128))?; + Ok(UnixListener(inner)) + } + } + /// Accepts a new incoming connection to this listener. /// /// This function will block the calling thread until a new Unix connection diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -//! Unix-specific networking functionality +//! Unix-specific networking functionality. #![stable(feature = "unix_socket", since = "1.10.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/stream.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/stream.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/stream.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/stream.rs 2021-11-29 19:27:11.000000000 +0000 @@ -106,6 +106,43 @@ } } + /// Connects to the socket specified by [`address`]. + /// + /// [`address`]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener, UnixStream}; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr()?; + /// + /// let sock = match UnixStream::connect_addr(&addr) { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ```` + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + cvt(libc::connect( + inner.as_raw_fd(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; + Ok(UnixStream(inner)) + } + } + /// Creates an unnamed pair of connected sockets. /// /// Returns two `UnixStream`s which are connected to each other. diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/tests.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/net/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/net/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -304,6 +304,30 @@ } #[test] +fn test_unix_datagram_connect_to_recv_addr() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::bind(&path2)); + + let msg = b"hello world"; + let sock1_addr = or_panic!(sock1.local_addr()); + or_panic!(sock2.send_to_addr(msg, &sock1_addr)); + let mut buf = [0; 11]; + let (_, addr) = or_panic!(sock1.recv_from(&mut buf)); + + let new_msg = b"hello back"; + let mut new_buf = [0; 10]; + or_panic!(sock2.connect_addr(&addr)); + or_panic!(sock2.send(new_msg)); // set by connect_addr + let usize = or_panic!(sock2.recv(&mut new_buf)); + assert_eq!(usize, 10); + assert_eq!(new_msg, &new_buf[..]); +} + +#[test] fn test_connect_unix_datagram() { let dir = tmpdir(); let path1 = dir.path().join("sock1"); @@ -388,10 +412,133 @@ } #[test] -fn abstract_namespace_not_allowed() { +fn abstract_namespace_not_allowed_connect() { assert!(UnixStream::connect("\0asdf").is_err()); } +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_stream_connect() { + let msg1 = b"hello"; + let msg2 = b"world"; + + let socket_addr = or_panic!(SocketAddr::from_abstract_namespace(b"namespace")); + let listener = or_panic!(UnixListener::bind_addr(&socket_addr)); + + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect_addr(&socket_addr)); + + let peer = or_panic!(stream.peer_addr()); + assert_eq!(peer.as_abstract_namespace().unwrap(), b"namespace"); + + or_panic!(stream.write_all(msg1)); + let mut buf = vec![]; + or_panic!(stream.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(stream); + + thread.join().unwrap(); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_stream_iter() { + let addr = or_panic!(SocketAddr::from_abstract_namespace(b"hidden")); + let listener = or_panic!(UnixListener::bind_addr(&addr)); + + let thread = thread::spawn(move || { + for stream in listener.incoming().take(2) { + let mut stream = or_panic!(stream); + let mut buf = [0]; + or_panic!(stream.read(&mut buf)); + } + }); + + for _ in 0..2 { + let mut stream = or_panic!(UnixStream::connect_addr(&addr)); + or_panic!(stream.write_all(&[0])); + } + + thread.join().unwrap(); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_datagram_bind_send_to_addr() { + let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns1")); + let sock1 = or_panic!(UnixDatagram::bind_addr(&addr1)); + + let local = or_panic!(sock1.local_addr()); + assert_eq!(local.as_abstract_namespace().unwrap(), b"ns1"); + + let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns2")); + let sock2 = or_panic!(UnixDatagram::bind_addr(&addr2)); + + let msg = b"hello world"; + or_panic!(sock1.send_to_addr(msg, &addr2)); + let mut buf = [0; 11]; + let (len, addr) = or_panic!(sock2.recv_from(&mut buf)); + assert_eq!(msg, &buf[..]); + assert_eq!(len, 11); + assert_eq!(addr.as_abstract_namespace().unwrap(), b"ns1"); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_datagram_connect_addr() { + let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns3")); + let bsock1 = or_panic!(UnixDatagram::bind_addr(&addr1)); + + let sock = or_panic!(UnixDatagram::unbound()); + or_panic!(sock.connect_addr(&addr1)); + + let msg = b"hello world"; + or_panic!(sock.send(msg)); + let mut buf = [0; 11]; + let (len, addr) = or_panic!(bsock1.recv_from(&mut buf)); + assert_eq!(len, 11); + assert_eq!(addr.is_unnamed(), true); + assert_eq!(msg, &buf[..]); + + let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns4")); + let bsock2 = or_panic!(UnixDatagram::bind_addr(&addr2)); + + or_panic!(sock.connect_addr(&addr2)); + or_panic!(sock.send(msg)); + or_panic!(bsock2.recv_from(&mut buf)); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_namespace_too_long() { + match SocketAddr::from_abstract_namespace( + b"abcdefghijklmnopqrstuvwxyzabcdefghijklmn\ + opqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi\ + jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + ) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_namespace_no_pathname_and_not_unnamed() { + let namespace = b"local"; + let addr = or_panic!(SocketAddr::from_abstract_namespace(&namespace[..])); + assert_eq!(addr.as_pathname(), None); + assert_eq!(addr.as_abstract_namespace(), Some(&namespace[..])); + assert_eq!(addr.is_unnamed(), false); +} + #[test] fn test_unix_stream_peek() { let (txdone, rxdone) = crate::sync::mpsc::channel(); diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/process.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/process.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/process.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/process.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! Unix-specific extensions to primitives in the `std::process` module. +//! Unix-specific extensions to primitives in the [`std::process`] module. +//! +//! [`std::process`]: crate::process #![stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/unix/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/unix/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! Unix-specific extensions to primitives in the `std::thread` module. +//! Unix-specific extensions to primitives in the [`std::thread`] module. +//! +//! [`std::thread`]: crate::thread #![stable(feature = "thread_extensions", since = "1.9.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/wasi/ffi.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/wasi/ffi.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/wasi/ffi.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/wasi/ffi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! WASI-specific extension to the primitives in the `std::ffi` module +//! WASI-specific extensions to primitives in the [`std::ffi`] module +//! +//! [`std::ffi`]: crate::ffi #![stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/wasi/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/wasi/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/wasi/fs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/wasi/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! WASI-specific extensions to primitives in the `std::fs` module. +//! WASI-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs #![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "71213")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/wasi/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/wasi/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/wasi/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/wasi/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -24,6 +24,9 @@ //! Ok(()) //! } //! ``` +//! +//! [`OsStr`]: crate::ffi::OsStr +//! [`OsString`]: crate::ffi::OsString #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/ffi.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/ffi.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/ffi.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/ffi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,4 @@ -//! Windows-specific extensions to the primitives in the `std::ffi` module. +//! Windows-specific extensions to primitives in the [`std::ffi`] module. //! //! # Overview //! @@ -49,6 +49,7 @@ //! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16 //! [`collect`]: crate::iter::Iterator::collect //! [U+FFFD]: crate::char::REPLACEMENT_CHARACTER +//! [`std::ffi`]: crate::ffi #![stable(feature = "rust1", since = "1.0.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/fs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/fs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/fs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/fs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! Windows-specific extensions for the primitives in the `std::fs` module. +//! Windows-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs #![stable(feature = "rust1", since = "1.0.0")] @@ -517,11 +519,20 @@ } } -/// Creates a new file symbolic link on the filesystem. +/// Creates a new symlink to a non-directory file on the filesystem. /// /// The `link` path will be a file symbolic link pointing to the `original` /// path. /// +/// The `original` path should not be a directory or a symlink to a directory, +/// otherwise the symlink will be broken. Use [`symlink_dir`] for directories. +/// +/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW]. +/// Note that this [may change in the future][changes]. +/// +/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw +/// [changes]: io#platform-specific-behavior +/// /// # Examples /// /// ```no_run @@ -537,11 +548,20 @@ sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false) } -/// Creates a new directory symlink on the filesystem. +/// Creates a new symlink to a directory on the filesystem. /// /// The `link` path will be a directory symbolic link pointing to the `original` /// path. /// +/// The `original` path must be a directory or a symlink to a directory, +/// otherwise the symlink will be broken. Use [`symlink_file`] for other files. +/// +/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW]. +/// Note that this [may change in the future][changes]. +/// +/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw +/// [changes]: io#platform-specific-behavior +/// /// # Examples /// /// ```no_run diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/io/handle.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/io/handle.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/io/handle.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/io/handle.rs 2021-11-29 19:27:11.000000000 +0000 @@ -4,12 +4,10 @@ use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use crate::convert::TryFrom; -use crate::ffi::c_void; use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; -use crate::ptr::NonNull; use crate::sys::c; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -20,17 +18,20 @@ /// /// This uses `repr(transparent)` and has the representation of a host handle, /// so it can be used in FFI in places where a handle is passed as an argument, -/// it is not captured or consumed, and it is never null. +/// it is not captured or consumed. /// /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is /// sometimes a valid handle value. See [here] for the full story. /// +/// And, it *may* have the value `NULL` (0), which can occur when consoles are +/// detached from processes, or when `windows_subsystem` is used. +/// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[derive(Copy, Clone)] #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct BorrowedHandle<'handle> { - handle: NonNull, + handle: RawHandle, _phantom: PhantomData<&'handle OwnedHandle>, } @@ -38,14 +39,11 @@ /// /// This closes the handle on drop. /// -/// This uses `repr(transparent)` and has the representation of a host handle, -/// so it can be used in FFI in places where a handle is passed as a consumed -/// argument or returned as an owned value, and is never null. -/// /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is -/// sometimes a valid handle value. See [here] for the full story. For APIs -/// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead -/// of null, use [`HandleOrInvalid`] instead of `Option`. +/// sometimes a valid handle value. See [here] for the full story. +/// +/// And, it *may* have the value `NULL` (0), which can occur when consoles are +/// detached from processes, or when `windows_subsystem` is used. /// /// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such, /// it must not be used with handles to open registry keys which need to be @@ -55,12 +53,31 @@ /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 -#[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedHandle { - handle: NonNull, + handle: RawHandle, } +/// FFI type for handles in return values or out parameters, where `NULL` is used +/// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses +/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such +/// FFI declarations. +/// +/// The only thing you can usefully do with a `HandleOrNull` is to convert it into an +/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for +/// `NULL`. This ensures that such FFI calls cannot start using the handle without +/// checking for `NULL` first. +/// +/// This type concerns any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`. +/// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE` +/// as special. +/// +/// If this holds a valid handle, it will close the handle on drop. +#[repr(transparent)] +#[unstable(feature = "io_safety", issue = "87074")] +#[derive(Debug)] +pub struct HandleOrNull(OwnedHandle); + /// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used /// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such @@ -71,11 +88,15 @@ /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without /// checking for `INVALID_HANDLE_VALUE` first. /// +/// This type concerns any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`. +/// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL` +/// under `windows_subsystem = "windows"` or other situations where I/O devices are detached. +/// /// If this holds a valid handle, it will close the handle on drop. #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] #[derive(Debug)] -pub struct HandleOrInvalid(Option); +pub struct HandleOrInvalid(OwnedHandle); // The Windows [`HANDLE`] type may be transferred across and shared between // thread boundaries (despite containing a `*mut void`, which in general isn't @@ -83,9 +104,11 @@ // // [`HANDLE`]: std::os::windows::raw::HANDLE unsafe impl Send for OwnedHandle {} +unsafe impl Send for HandleOrNull {} unsafe impl Send for HandleOrInvalid {} unsafe impl Send for BorrowedHandle<'_> {} unsafe impl Sync for OwnedHandle {} +unsafe impl Sync for HandleOrNull {} unsafe impl Sync for HandleOrInvalid {} unsafe impl Sync for BorrowedHandle<'_> {} @@ -95,18 +118,29 @@ /// # Safety /// /// The resource pointed to by `handle` must be a valid open handle, it - /// must remain open for the duration of the returned `BorrowedHandle`, and - /// it must not be null. + /// must remain open for the duration of the returned `BorrowedHandle`. /// /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is /// sometimes a valid handle value. See [here] for the full story. /// + /// And, it *may* have the value `NULL` (0), which can occur when consoles are + /// detached from processes, or when `windows_subsystem` is used. + /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] #[unstable(feature = "io_safety", issue = "87074")] pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self { - assert!(!handle.is_null()); - Self { handle: NonNull::new_unchecked(handle), _phantom: PhantomData } + Self { handle, _phantom: PhantomData } + } +} + +impl TryFrom for OwnedHandle { + type Error = (); + + #[inline] + fn try_from(handle_or_null: HandleOrNull) -> Result { + let owned_handle = handle_or_null.0; + if owned_handle.handle.is_null() { Err(()) } else { Ok(owned_handle) } } } @@ -115,44 +149,29 @@ #[inline] fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { - // In theory, we ought to be able to assume that the pointer here is - // never null, use `OwnedHandle` rather than `Option`, and - // obviate the the panic path here. Unfortunately, Win32 documentation - // doesn't explicitly guarantee this anywhere. - // - // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a - // null handle indicates an absent value, which wouldn't work if null - // were a valid handle value, so it seems very unlikely that it could - // ever return null. But who knows? - // - // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew - let owned_handle = handle_or_invalid.0.expect("A `HandleOrInvalid` was null!"); - if owned_handle.handle.as_ptr() == c::INVALID_HANDLE_VALUE { - Err(()) - } else { - Ok(owned_handle) - } + let owned_handle = handle_or_invalid.0; + if owned_handle.handle == c::INVALID_HANDLE_VALUE { Err(()) } else { Ok(owned_handle) } } } impl AsRawHandle for BorrowedHandle<'_> { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.handle.as_ptr() + self.handle } } impl AsRawHandle for OwnedHandle { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.handle.as_ptr() + self.handle } } impl IntoRawHandle for OwnedHandle { #[inline] fn into_raw_handle(self) -> RawHandle { - let handle = self.handle.as_ptr(); + let handle = self.handle; forget(self); handle } @@ -161,9 +180,6 @@ impl FromRawHandle for OwnedHandle { /// Constructs a new instance of `Self` from the given raw handle. /// - /// Use `HandleOrInvalid` instead of `Option` for APIs that - /// use `INVALID_HANDLE_VALUE` to indicate failure. - /// /// # Safety /// /// The resource pointed to by `handle` must be open and suitable for @@ -180,8 +196,28 @@ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { - assert!(!handle.is_null()); - Self { handle: NonNull::new_unchecked(handle) } + Self { handle } + } +} + +impl FromRawHandle for HandleOrNull { + /// Constructs a new instance of `Self` from the given `RawHandle` returned + /// from a Windows API that uses null to indicate failure, such as + /// `CreateThread`. + /// + /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that + /// use `INVALID_HANDLE_VALUE` to indicate failure. + /// + /// # Safety + /// + /// The resource pointed to by `handle` must be either open and otherwise + /// unowned, or null. Note that not all Windows APIs use null for errors; + /// see [here] for the full story. + /// + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 + #[inline] + unsafe fn from_raw_handle(handle: RawHandle) -> Self { + Self(OwnedHandle::from_raw_handle(handle)) } } @@ -190,21 +226,20 @@ /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate /// failure, such as `CreateFileW`. /// - /// Use `Option` instead of `HandleOrInvalid` for APIs that + /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that /// use null to indicate failure. /// /// # Safety /// /// The resource pointed to by `handle` must be either open and otherwise - /// unowned, or equal to `INVALID_HANDLE_VALUE` (-1). It must not be null. - /// Note that not all Windows APIs use `INVALID_HANDLE_VALUE` for errors; - /// see [here] for the full story. + /// unowned, null, or equal to `INVALID_HANDLE_VALUE` (-1). Note that not + /// all Windows APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for + /// the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { - // We require non-null here to catch errors earlier. - Self(Some(OwnedHandle::from_raw_handle(handle))) + Self(OwnedHandle::from_raw_handle(handle)) } } @@ -212,7 +247,7 @@ #[inline] fn drop(&mut self) { unsafe { - let _ = c::CloseHandle(self.handle.as_ptr()); + let _ = c::CloseHandle(self.handle); } } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/mod.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/mod.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/mod.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/mod.rs 2021-11-29 19:27:11.000000000 +0000 @@ -5,6 +5,22 @@ //! the core `std` library. These extensions allow developers to use //! `std` types and idioms with Windows in a way that the normal //! platform-agnostic idioms would not normally support. +//! +//! # Examples +//! +//! ```no_run +//! use std::fs::File; +//! use std::os::windows::prelude::*; +//! +//! fn main() -> std::io::Result<()> { +//! let f = File::create("foo.txt")?; +//! let handle = f.as_raw_handle(); +//! +//! // use handle with native windows bindings +//! +//! Ok(()) +//! } +//! ``` #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(windows))] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/process.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/process.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/process.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/process.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! Extensions to `std::process` for Windows. +//! Windows-specific extensions to primitives in the [`std::process`] module. +//! +//! [`std::process`]: crate::process #![stable(feature = "process_extensions", since = "1.2.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/raw.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/raw.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/raw.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/raw.rs 2021-11-29 19:27:11.000000000 +0000 @@ -7,8 +7,10 @@ #[stable(feature = "raw_ext", since = "1.1.0")] pub type HANDLE = *mut c_void; #[cfg(target_pointer_width = "32")] +#[doc(cfg(all()))] #[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u32; #[cfg(target_pointer_width = "64")] +#[doc(cfg(all()))] #[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u64; diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/os/windows/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/os/windows/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,4 +1,6 @@ -//! Extensions to `std::thread` for Windows. +//! Windows-specific extensions to primitives in the [`std::thread`] module. +//! +//! [`std::thread`]: crate::thread #![stable(feature = "thread_extensions", since = "1.9.0")] diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/panicking.rs rustc-1.57.0+dfsg1+llvm/library/std/src/panicking.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/panicking.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/panicking.rs 2021-11-29 19:27:11.000000000 +0000 @@ -450,7 +450,7 @@ #[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cfg_attr(all(not(bootstrap), not(test)), lang = "begin_panic_fmt")] +#[cfg_attr(not(test), lang = "begin_panic_fmt")] pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { intrinsics::abort() diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/panic.rs rustc-1.57.0+dfsg1+llvm/library/std/src/panic.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/panic.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/panic.rs 2021-11-29 19:27:11.000000000 +0000 @@ -10,7 +10,7 @@ #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(libstd_sys_internals, const_format_args)] +#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { @@ -20,6 +20,10 @@ ($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) }), + // Special-case the single-argument case for const_panic. + ("{}", $arg:expr $(,)?) => ({ + $crate::rt::panic_display(&$arg) + }), ($fmt:expr, $($arg:tt)+) => ({ $crate::rt::begin_panic_fmt(&$crate::const_format_args!($fmt, $($arg)+)) }), diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/path/tests.rs rustc-1.57.0+dfsg1+llvm/library/std/src/path/tests.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/path/tests.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/path/tests.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1262,6 +1262,16 @@ tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one + + tp!(r"\\?\C:\bar", "../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:\bar", "../../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:\", "../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:", r"D:\foo/./", r"D:\foo/./"); + tp!(r"\\?\C:", r"\\?\D:\foo\.\", r"\\?\D:\foo\.\"); + tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo"); + tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo"); + tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo"); + tp!(r"\\?\A:\x\y", r"", r"\\?\A:\x\y\"); } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/path.rs rustc-1.57.0+dfsg1+llvm/library/std/src/path.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/path.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/path.rs 2021-11-29 19:27:11.000000000 +0000 @@ -215,6 +215,7 @@ /// assert!(!Disk(b'C').is_verbatim()); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { use self::Prefix::*; @@ -247,6 +248,7 @@ /// assert!(path::is_separator('/')); // '/' works for both Unix and Windows /// assert!(!path::is_separator('â¤')); /// ``` +#[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_separator(c: char) -> bool { c.is_ascii() && is_sep_byte(c as u8) @@ -427,6 +429,7 @@ /// Returns the raw [`OsStr`] slice for this prefix. #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_os_str(&self) -> &'a OsStr { self.raw @@ -532,6 +535,7 @@ /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { @@ -675,6 +679,7 @@ /// /// assert_eq!(Path::new("foo/bar.txt"), components.as_path()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { let mut comps = self.clone(); @@ -820,6 +825,7 @@ /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -1145,6 +1151,7 @@ /// let path = PathBuf::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn new() -> PathBuf { PathBuf { inner: OsString::new() } @@ -1169,6 +1176,7 @@ /// /// [`with_capacity`]: OsString::with_capacity #[stable(feature = "path_buf_capacity", since = "1.44.0")] + #[must_use] #[inline] pub fn with_capacity(capacity: usize) -> PathBuf { PathBuf { inner: OsString::with_capacity(capacity) } @@ -1185,6 +1193,7 @@ /// assert_eq!(Path::new("/test"), p.as_path()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_path(&self) -> &Path { self @@ -1199,6 +1208,9 @@ /// * if `path` has a root but no prefix (e.g., `\windows`), it /// replaces everything except for the prefix (if any) of `self`. /// * if `path` has a prefix but no root, it replaces `self`. + /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`) + /// and `path` is not empty, the new path is normalized: all references + /// to `.` and `..` are removed. /// /// # Examples /// @@ -1231,20 +1243,59 @@ let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); // in the special case of `C:` on Windows, do *not* add a separator + let comps = self.components(); + + if comps.prefix_len() > 0 + && comps.prefix_len() == comps.path.len() + && comps.prefix.unwrap().is_drive() { - let comps = self.components(); - if comps.prefix_len() > 0 - && comps.prefix_len() == comps.path.len() - && comps.prefix.unwrap().is_drive() - { - need_sep = false - } + need_sep = false } // absolute `path` replaces `self` if path.is_absolute() || path.prefix().is_some() { self.as_mut_vec().truncate(0); + // verbatim paths need . and .. removed + } else if comps.prefix_verbatim() && !path.inner.is_empty() { + let mut buf: Vec<_> = comps.collect(); + for c in path.components() { + match c { + Component::RootDir => { + buf.truncate(1); + buf.push(c); + } + Component::CurDir => (), + Component::ParentDir => { + if let Some(Component::Normal(_)) = buf.last() { + buf.pop(); + } + } + _ => buf.push(c), + } + } + + let mut res = OsString::new(); + let mut need_sep = false; + + for c in buf { + if need_sep && c != Component::RootDir { + res.push(MAIN_SEP_STR); + } + res.push(c.as_os_str()); + + need_sep = match c { + Component::RootDir => false, + Component::Prefix(prefix) => { + !prefix.parsed.is_drive() && prefix.parsed.len() > 0 + } + _ => true, + } + } + + self.inner = res; + return; + // `path` has a root but no prefix, e.g., `\windows` (Windows only) } else if path.has_root() { let prefix_len = self.components().prefix_remaining(); @@ -1389,6 +1440,7 @@ /// let os_str = p.into_os_string(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub fn into_os_string(self) -> OsString { self.inner @@ -1396,6 +1448,7 @@ /// Converts this `PathBuf` into a [boxed](Box) [`Path`]. #[stable(feature = "into_boxed_path", since = "1.20.0")] + #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub fn into_boxed_path(self) -> Box { let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path; @@ -1879,6 +1932,7 @@ /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_os_str(&self) -> &OsStr { &self.inner @@ -1901,6 +1955,8 @@ /// assert_eq!(path.to_str(), Some("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn to_str(&self) -> Option<&str> { self.inner.to_str() @@ -1927,6 +1983,8 @@ /// Had `path` contained invalid unicode, the `to_string_lossy` call might /// have returned `"fo�.txt"`. #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[inline] pub fn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy() @@ -1943,6 +2001,8 @@ /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt")); /// ``` #[rustc_conversion_suggestion] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] pub fn to_path_buf(&self) -> PathBuf { PathBuf::from(self.inner.to_os_string()) @@ -1967,6 +2027,7 @@ /// /// [`has_root`]: Path::has_root #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { if cfg!(target_os = "redox") { @@ -1991,6 +2052,7 @@ /// /// [`is_absolute`]: Path::is_absolute #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -2017,6 +2079,7 @@ /// assert!(Path::new("/etc/passwd").has_root()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn has_root(&self) -> bool { self.components().has_root() @@ -2467,6 +2530,8 @@ /// println!("{}", path.display()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this does not display the path, \ + it returns an object that can be displayed"] #[inline] pub fn display(&self) -> Display<'_> { Display { path: self } @@ -2552,7 +2617,7 @@ /// Returns an iterator over the entries within a directory. /// - /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New + /// The iterator will yield instances of [io::Result]<[fs::DirEntry]>. New /// errors may be encountered after an iterator is initially constructed. /// /// This is an alias to [`fs::read_dir`]. @@ -2654,6 +2719,7 @@ /// a Unix-like system for example. See [`fs::File::open`] or /// [`fs::OpenOptions::open`] for more information. #[stable(feature = "path_ext", since = "1.5.0")] + #[must_use] pub fn is_file(&self) -> bool { fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) } @@ -2680,6 +2746,7 @@ /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call /// [`fs::Metadata::is_dir`] if it was [`Ok`]. #[stable(feature = "path_ext", since = "1.5.0")] + #[must_use] pub fn is_dir(&self) -> bool { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } @@ -2706,6 +2773,7 @@ /// assert_eq!(link_path.exists(), false); /// ``` #[unstable(feature = "is_symlink", issue = "85748")] + #[must_use] pub fn is_symlink(&self) -> bool { fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/primitive_docs.rs rustc-1.57.0+dfsg1+llvm/library/std/src/primitive_docs.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/primitive_docs.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/primitive_docs.rs 2021-11-29 19:27:11.000000000 +0000 @@ -1,18 +1,21 @@ +// `library/{std,core}/src/primitive_docs.rs` should have the same contents. +// These are different files so that relative links work properly without +// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same. #[doc(primitive = "bool")] #[doc(alias = "true")] #[doc(alias = "false")] /// The boolean type. /// -/// The `bool` represents a value, which could only be either `true` or `false`. If you cast -/// a `bool` into an integer, `true` will be 1 and `false` will be 0. +/// The `bool` represents a value, which could only be either [`true`] or [`false`]. If you cast +/// a `bool` into an integer, [`true`] will be 1 and [`false`] will be 0. /// /// # Basic usage /// /// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc., /// which allow us to perform boolean operations using `&`, `|` and `!`. /// -/// `if` requires a `bool` value as its conditional. [`assert!`], which is an -/// important macro in testing, checks whether an expression is `true` and panics +/// [`if`] requires a `bool` value as its conditional. [`assert!`], which is an +/// important macro in testing, checks whether an expression is [`true`] and panics /// if it isn't. /// /// ``` @@ -20,9 +23,12 @@ /// assert!(!bool_val); /// ``` /// +/// [`true`]: ../std/keyword.true.html +/// [`false`]: ../std/keyword.false.html /// [`BitAnd`]: ops::BitAnd /// [`BitOr`]: ops::BitOr /// [`Not`]: ops::Not +/// [`if`]: ../std/keyword.if.html /// /// # Examples /// @@ -100,7 +106,7 @@ /// behaviour of the `!` type - expressions with type `!` will coerce into any other type. /// /// [`u32`]: prim@u32 -/// [`exit`]: process::exit +#[doc = concat!("[`exit`]: ", include_str!("../primitive_docs/process_exit.md"))] /// /// # `!` and generics /// @@ -185,7 +191,7 @@ /// because `!` coerces to `Result` automatically. /// /// [`String::from_str`]: str::FromStr::from_str -/// [`String`]: string::String +#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] /// [`FromStr`]: str::FromStr /// /// # `!` and traits @@ -261,7 +267,7 @@ /// `impl` for this which simply panics, but the same is true for any type (we could `impl /// Default` for (eg.) [`File`] by just making [`default()`] panic.) /// -/// [`File`]: fs::File +#[doc = concat!("[`File`]: ", include_str!("../primitive_docs/fs_file.md"))] /// [`Debug`]: fmt::Debug /// [`default()`]: Default::default /// @@ -269,7 +275,6 @@ mod prim_never {} #[doc(primitive = "char")] -// /// A character type. /// /// The `char` type represents a single character. More specifically, since @@ -301,7 +306,7 @@ /// assert_eq!(5, s.len() * std::mem::size_of::()); /// ``` /// -/// [`String`]: string/struct.String.html +#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] /// /// As always, remember that a human intuition for 'character' might not map to /// Unicode's definitions. For example, despite looking similar, the 'é' @@ -385,8 +390,11 @@ #[stable(feature = "rust1", since = "1.0.0")] mod prim_unit {} -#[doc(alias = "ptr")] #[doc(primitive = "pointer")] +#[doc(alias = "ptr")] +#[doc(alias = "*")] +#[doc(alias = "*const")] +#[doc(alias = "*mut")] // /// Raw, unsafe pointers, `*const T`, and `*mut T`. /// @@ -493,16 +501,16 @@ /// [`null_mut`]: ptr::null_mut /// [`is_null`]: pointer::is_null /// [`offset`]: pointer::offset -/// [`into_raw`]: Box::into_raw +#[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))] /// [`drop`]: mem::drop /// [`write`]: ptr::write #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} +#[doc(primitive = "array")] #[doc(alias = "[]")] #[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases #[doc(alias = "[T; N]")] -#[doc(primitive = "array")] /// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the /// non-negative compile-time constant size, `N`. /// @@ -574,10 +582,10 @@ /// /// # Editions /// -/// Prior to Rust 1.53, arrays did not implement `IntoIterator` by value, so the method call -/// `array.into_iter()` auto-referenced into a slice iterator. Right now, the old behavior -/// is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring -/// `IntoIterator` by value. In the future, the behavior on the 2015 and 2018 edition +/// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call +/// `array.into_iter()` auto-referenced into a [slice iterator](slice::iter). Right now, the old +/// behavior is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring +/// [`IntoIterator`] by value. In the future, the behavior on the 2015 and 2018 edition /// might be made consistent to the behavior of later editions. /// /// ```rust,edition2018 @@ -609,8 +617,7 @@ /// Starting in the 2021 edition, `array.into_iter()` uses `IntoIterator` normally to iterate /// by value, and `iter()` should be used to iterate by reference like previous editions. /// -#[cfg_attr(bootstrap, doc = "```rust,edition2021,ignore")] -#[cfg_attr(not(bootstrap), doc = "```rust,edition2021")] +/// ```rust,edition2021 /// // Rust 2021: /// /// let array: [i32; 3] = [0; 3]; @@ -833,7 +840,7 @@ /// ``` /// /// The sequential nature of the tuple applies to its implementations of various -/// traits. For example, in `PartialOrd` and `Ord`, the elements are compared +/// traits. For example, in [`PartialOrd`] and [`Ord`], the elements are compared /// sequentially until the first non-equal set is found. /// /// For more about tuples, see [the book](../book/ch03-02-data-types.html#the-tuple-type). @@ -1037,14 +1044,16 @@ /// References, both shared and mutable. /// /// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` -/// operators on a value, or by using a `ref` or `ref mut` pattern. +/// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or +/// [ref](../std/keyword.ref.html) [mut](../std/keyword.mut.html) pattern. /// /// For those familiar with pointers, a reference is just a pointer that is assumed to be /// aligned, not null, and pointing to memory containing a valid value of `T` - for example, -/// `&bool` can only point to an allocation containing the integer values `1` (`true`) or `0` -/// (`false`), but creating a `&bool` that points to an allocation containing +/// &[bool] can only point to an allocation containing the integer values `1` +/// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but +/// creating a &[bool] that points to an allocation containing /// the value `3` causes undefined behaviour. -/// In fact, `Option<&T>` has the same memory representation as a +/// In fact, [Option]\<&T> has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// /// In most cases, references can be used much like the original value. Field access, method @@ -1110,6 +1119,7 @@ /// /// [`DerefMut`]: ops::DerefMut /// [`BorrowMut`]: borrow::BorrowMut +/// [bool]: prim@bool /// /// The following traits are implemented on `&T` references if the underlying `T` also implements /// that trait: @@ -1127,7 +1137,7 @@ /// [`std::fmt`]: fmt /// ['Pointer`]: fmt::Pointer /// [`Hash`]: hash::Hash -/// [`ToSocketAddrs`]: net::ToSocketAddrs +#[doc = concat!("[`ToSocketAddrs`]: ", include_str!("../primitive_docs/net_tosocketaddrs.md"))] /// /// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T` /// implements that trait: @@ -1140,7 +1150,7 @@ /// * [`ExactSizeIterator`] /// * [`FusedIterator`] /// * [`TrustedLen`] -/// * [`Send`] \(note that `&T` references only get `Send` if `T: Sync`) +/// * [`Send`] \(note that `&T` references only get `Send` if T: [Sync]) /// * [`io::Write`] /// * [`Read`] /// * [`Seek`] @@ -1148,9 +1158,10 @@ /// /// [`FusedIterator`]: iter::FusedIterator /// [`TrustedLen`]: iter::TrustedLen -/// [`Seek`]: io::Seek -/// [`BufRead`]: io::BufRead -/// [`Read`]: io::Read +#[doc = concat!("[`Seek`]: ", include_str!("../primitive_docs/io_seek.md"))] +#[doc = concat!("[`BufRead`]: ", include_str!("../primitive_docs/io_bufread.md"))] +#[doc = concat!("[`Read`]: ", include_str!("../primitive_docs/io_read.md"))] +#[doc = concat!("[`io::Write`]: ", include_str!("../primitive_docs/io_write.md"))] /// /// Note that due to method call deref coercion, simply calling a trait method will act like they /// work on references as well as they do on owned values! The implementations described here are @@ -1172,7 +1183,8 @@ /// Function pointers are pointers that point to *code*, not data. They can be called /// just like functions. Like references, function pointers are, among other things, assumed to /// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null -/// pointers, make your type `Option` with your required signature. +/// pointers, make your type [`Option`](core::option#options-and-pointers-nullable-pointers) +/// with your required signature. /// /// ### Safety /// diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/process.rs rustc-1.57.0+dfsg1+llvm/library/std/src/process.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/process.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/process.rs 2021-11-29 19:27:11.000000000 +0000 @@ -115,7 +115,7 @@ use crate::str; use crate::sys::pipe::{read2, AnonPipe}; use crate::sys::process as imp; -#[unstable(feature = "command_access", issue = "44434")] +#[stable(feature = "command_access", since = "1.57.0")] pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; @@ -943,13 +943,12 @@ /// # Examples /// /// ``` - /// # #![feature(command_access)] /// use std::process::Command; /// /// let cmd = Command::new("echo"); /// assert_eq!(cmd.get_program(), "echo"); /// ``` - #[unstable(feature = "command_access", issue = "44434")] + #[stable(feature = "command_access", since = "1.57.0")] pub fn get_program(&self) -> &OsStr { self.inner.get_program() } @@ -963,7 +962,6 @@ /// # Examples /// /// ``` - /// # #![feature(command_access)] /// use std::ffi::OsStr; /// use std::process::Command; /// @@ -972,7 +970,7 @@ /// let args: Vec<&OsStr> = cmd.get_args().collect(); /// assert_eq!(args, &["first", "second"]); /// ``` - #[unstable(feature = "command_access", issue = "44434")] + #[stable(feature = "command_access", since = "1.57.0")] pub fn get_args(&self) -> CommandArgs<'_> { CommandArgs { inner: self.inner.get_args() } } @@ -992,7 +990,6 @@ /// # Examples /// /// ``` - /// # #![feature(command_access)] /// use std::ffi::OsStr; /// use std::process::Command; /// @@ -1004,7 +1001,7 @@ /// (OsStr::new("TZ"), None) /// ]); /// ``` - #[unstable(feature = "command_access", issue = "44434")] + #[stable(feature = "command_access", since = "1.57.0")] pub fn get_envs(&self) -> CommandEnvs<'_> { self.inner.get_envs() } @@ -1016,7 +1013,6 @@ /// # Examples /// /// ``` - /// # #![feature(command_access)] /// use std::path::Path; /// use std::process::Command; /// @@ -1025,7 +1021,7 @@ /// cmd.current_dir("/bin"); /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin"))); /// ``` - #[unstable(feature = "command_access", issue = "44434")] + #[stable(feature = "command_access", since = "1.57.0")] pub fn get_current_dir(&self) -> Option<&Path> { self.inner.get_current_dir() } @@ -1057,13 +1053,13 @@ /// /// This struct is created by [`Command::get_args`]. See its documentation for /// more. -#[unstable(feature = "command_access", issue = "44434")] +#[stable(feature = "command_access", since = "1.57.0")] #[derive(Debug)] pub struct CommandArgs<'a> { inner: imp::CommandArgs<'a>, } -#[unstable(feature = "command_access", issue = "44434")] +#[stable(feature = "command_access", since = "1.57.0")] impl<'a> Iterator for CommandArgs<'a> { type Item = &'a OsStr; fn next(&mut self) -> Option<&'a OsStr> { @@ -1074,7 +1070,7 @@ } } -#[unstable(feature = "command_access", issue = "44434")] +#[stable(feature = "command_access", since = "1.57.0")] impl<'a> ExactSizeIterator for CommandArgs<'a> { fn len(&self) -> usize { self.inner.len() @@ -1907,7 +1903,7 @@ /// [platform-specific behavior]: #platform-specific-behavior #[stable(feature = "rust1", since = "1.0.0")] pub fn exit(code: i32) -> ! { - crate::sys_common::rt::cleanup(); + crate::rt::cleanup(); crate::sys::os::exit(code) } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/rt.rs rustc-1.57.0+dfsg1+llvm/library/std/src/rt.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/rt.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/rt.rs 2021-11-29 19:27:11.000000000 +0000 @@ -13,9 +13,92 @@ issue = "none" )] #![doc(hidden)] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow(unused_macros)] + +use crate::ffi::CString; // Re-export some of our utilities which are expected by other crates. pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count}; +pub use core::panicking::panic_display; + +use crate::sync::Once; +use crate::sys; +use crate::sys_common::thread_info; +use crate::thread::Thread; + +// Prints to the "panic output", depending on the platform this may be: +// - the standard error output +// - some dedicated platform specific output +// - nothing (so this macro is a no-op) +macro_rules! rtprintpanic { + ($($t:tt)*) => { + if let Some(mut out) = crate::sys::stdio::panic_output() { + let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); + } + } +} + +macro_rules! rtabort { + ($($t:tt)*) => { + { + rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*)); + crate::sys::abort_internal(); + } + } +} + +macro_rules! rtassert { + ($e:expr) => { + if !$e { + rtabort!(concat!("assertion failed: ", stringify!($e))); + } + }; +} + +macro_rules! rtunwrap { + ($ok:ident, $e:expr) => { + match $e { + $ok(v) => v, + ref err => { + let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug + rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) + } + } + }; +} + +// One-time runtime initialization. +// Runs before `main`. +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. +#[cfg_attr(test, allow(dead_code))] +unsafe fn init(argc: isize, argv: *const *const u8) { + unsafe { + sys::init(argc, argv); + + let main_guard = sys::thread::guard::init(); + // Next, set up the current Thread with the guard information we just + // created. Note that this isn't necessary in general for new threads, + // but we just do this to name the main thread and to give it correct + // info about the stack bounds. + let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main")))); + thread_info::set(main_guard, thread); + } +} + +// One-time runtime cleanup. +// Runs after `main` or at program exit. +// NOTE: this is not guaranteed to run, for example when the program aborts. +pub(crate) fn cleanup() { + static CLEANUP: Once = Once::new(); + CLEANUP.call_once(|| unsafe { + // Flush stdout and disable buffering. + crate::io::cleanup(); + // SAFETY: Only called once during runtime cleanup. + sys::cleanup(); + }); +} // To reduce the generated code of the new `lang_start`, this function is doing // the real work. @@ -25,7 +108,7 @@ argc: isize, argv: *const *const u8, ) -> Result { - use crate::{mem, panic, sys, sys_common}; + use crate::{mem, panic}; let rt_abort = move |e| { mem::forget(e); rtabort!("initialization or cleanup bug"); @@ -41,14 +124,14 @@ // prevent libstd from accidentally introducing a panic to these functions. Another is from // user code from `main` or, more nefariously, as described in e.g. issue #86030. // SAFETY: Only called once during runtime initialization. - panic::catch_unwind(move || unsafe { sys_common::rt::init(argc, argv) }).map_err(rt_abort)?; + panic::catch_unwind(move || unsafe { init(argc, argv) }).map_err(rt_abort)?; let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) .map_err(move |e| { mem::forget(e); rtprintpanic!("drop of the panic payload panicked"); sys::abort_internal() }); - panic::catch_unwind(sys_common::rt::cleanup).map_err(rt_abort)?; + panic::catch_unwind(cleanup).map_err(rt_abort)?; ret_code } @@ -59,10 +142,10 @@ argc: isize, argv: *const *const u8, ) -> isize { - lang_start_internal( + let Ok(v) = lang_start_internal( &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(), argc, argv, - ) - .into_ok() + ); + v } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sync/barrier.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sync/barrier.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sync/barrier.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sync/barrier.rs 2021-11-29 19:27:11.000000000 +0000 @@ -80,6 +80,7 @@ /// let barrier = Barrier::new(10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn new(n: usize) -> Barrier { Barrier { lock: Mutex::new(BarrierState { count: 0, generation_id: 0 }), @@ -166,6 +167,7 @@ /// println!("{:?}", barrier_wait_result.is_leader()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn is_leader(&self) -> bool { self.0 } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sync/condvar.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sync/condvar.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sync/condvar.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sync/condvar.rs 2021-11-29 19:27:11.000000000 +0000 @@ -121,6 +121,7 @@ /// let condvar = Condvar::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn new() -> Condvar { Condvar { inner: sys::Condvar::new() } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sync/mpsc/shared.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sync/mpsc/shared.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sync/mpsc/shared.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sync/mpsc/shared.rs 2021-11-29 19:27:11.000000000 +0000 @@ -248,7 +248,11 @@ // Returns true if blocking should proceed. fn decrement(&self, token: SignalToken) -> StartResult { unsafe { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!( + self.to_wake.load(Ordering::SeqCst), + 0, + "This is a known bug in the Rust standard library. See https://github.com/rust-lang/rust/issues/39364" + ); let ptr = token.cast_to_usize(); self.to_wake.store(ptr, Ordering::SeqCst); diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sync/mutex.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sync/mutex.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sync/mutex.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sync/mutex.rs 2021-11-29 19:27:11.000000000 +0000 @@ -162,7 +162,7 @@ /// assert_eq!(*res_mutex.lock().unwrap(), 800); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")] pub struct Mutex { inner: sys::MovableMutex, poison: poison::Flag, @@ -188,6 +188,12 @@ /// [`lock`]: Mutex::lock /// [`try_lock`]: Mutex::try_lock #[must_use = "if unused the Mutex will immediately unlock"] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a MutexGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`" +)] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex, diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sync/once.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sync/once.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sync/once.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sync/once.rs 2021-11-29 19:27:11.000000000 +0000 @@ -186,6 +186,7 @@ #[inline] #[stable(feature = "once_new", since = "1.2.0")] #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] + #[must_use] pub const fn new() -> Once { Once { state_and_queue: AtomicUsize::new(INCOMPLETE), _marker: marker::PhantomData } } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sync/rwlock.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sync/rwlock.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sync/rwlock.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sync/rwlock.rs 2021-11-29 19:27:11.000000000 +0000 @@ -95,6 +95,12 @@ /// [`read`]: RwLock::read /// [`try_read`]: RwLock::try_read #[must_use = "if unused the RwLock will immediately unlock"] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a RwLockReadGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`" +)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock, @@ -115,6 +121,12 @@ /// [`write`]: RwLock::write /// [`try_write`]: RwLock::try_write #[must_use = "if unused the RwLock will immediately unlock"] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a RwLockWriteGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Future's to not implement `Send`" +)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock, diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/hermit/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/hermit/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/hermit/thread.rs 2021-10-18 09:52:36.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/hermit/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -97,7 +97,7 @@ } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/abi.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/abi.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/abi.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/abi.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,155 @@ +//! ABI for μITRON derivatives +pub type int_t = crate::os::raw::c_int; +pub type uint_t = crate::os::raw::c_uint; +pub type bool_t = int_t; + +/// Kernel object ID +pub type ID = int_t; + +/// The current task. +pub const TSK_SELF: ID = 0; + +/// Relative time +pub type RELTIM = u32; + +/// Timeout (a valid `RELTIM` value or `TMO_FEVR`) +pub type TMO = u32; + +/// The infinite timeout value +pub const TMO_FEVR: TMO = TMO::MAX; + +/// The maximum valid value of `RELTIM` +pub const TMAX_RELTIM: RELTIM = 4_000_000_000; + +/// System time +pub type SYSTIM = u64; + +/// Error code type +pub type ER = int_t; + +/// Error code type, `ID` on success +pub type ER_ID = int_t; + +/// Task or interrupt priority +pub type PRI = int_t; + +/// The special value of `PRI` representing the current task's priority. +pub const TPRI_SELF: PRI = 0; + +/// Object attributes +pub type ATR = uint_t; + +/// Use the priority inheritance protocol +#[cfg(target_os = "solid_asp3")] +pub const TA_INHERIT: ATR = 0x02; + +/// Activate the task on creation +pub const TA_ACT: ATR = 0x01; + +/// The maximum count of a semaphore +pub const TMAX_MAXSEM: uint_t = uint_t::MAX; + +/// Callback parameter +pub type EXINF = isize; + +/// Task entrypoint +pub type TASK = Option; + +// Error codes +pub const E_OK: ER = 0; +pub const E_SYS: ER = -5; +pub const E_NOSPT: ER = -9; +pub const E_RSFN: ER = -10; +pub const E_RSATR: ER = -11; +pub const E_PAR: ER = -17; +pub const E_ID: ER = -18; +pub const E_CTX: ER = -25; +pub const E_MACV: ER = -26; +pub const E_OACV: ER = -27; +pub const E_ILUSE: ER = -28; +pub const E_NOMEM: ER = -33; +pub const E_NOID: ER = -34; +pub const E_NORES: ER = -35; +pub const E_OBJ: ER = -41; +pub const E_NOEXS: ER = -42; +pub const E_QOVR: ER = -43; +pub const E_RLWAI: ER = -49; +pub const E_TMOUT: ER = -50; +pub const E_DLT: ER = -51; +pub const E_CLS: ER = -52; +pub const E_RASTER: ER = -53; +pub const E_WBLK: ER = -57; +pub const E_BOVR: ER = -58; +pub const E_COMM: ER = -65; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CSEM { + pub sematr: ATR, + pub isemcnt: uint_t, + pub maxsem: uint_t, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CMTX { + pub mtxatr: ATR, + pub ceilpri: PRI, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CTSK { + pub tskatr: ATR, + pub exinf: EXINF, + pub task: TASK, + pub itskpri: PRI, + pub stksz: usize, + pub stk: *mut u8, +} + +extern "C" { + #[link_name = "__asp3_acre_tsk"] + pub fn acre_tsk(pk_ctsk: *const T_CTSK) -> ER_ID; + #[link_name = "__asp3_get_tid"] + pub fn get_tid(p_tskid: *mut ID) -> ER; + #[link_name = "__asp3_dly_tsk"] + pub fn dly_tsk(dlytim: RELTIM) -> ER; + #[link_name = "__asp3_ter_tsk"] + pub fn ter_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_del_tsk"] + pub fn del_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_get_pri"] + pub fn get_pri(tskid: ID, p_tskpri: *mut PRI) -> ER; + #[link_name = "__asp3_rot_rdq"] + pub fn rot_rdq(tskpri: PRI) -> ER; + #[link_name = "__asp3_slp_tsk"] + pub fn slp_tsk() -> ER; + #[link_name = "__asp3_tslp_tsk"] + pub fn tslp_tsk(tmout: TMO) -> ER; + #[link_name = "__asp3_wup_tsk"] + pub fn wup_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_unl_cpu"] + pub fn unl_cpu() -> ER; + #[link_name = "__asp3_dis_dsp"] + pub fn dis_dsp() -> ER; + #[link_name = "__asp3_ena_dsp"] + pub fn ena_dsp() -> ER; + #[link_name = "__asp3_sns_dsp"] + pub fn sns_dsp() -> bool_t; + #[link_name = "__asp3_get_tim"] + pub fn get_tim(p_systim: *mut SYSTIM) -> ER; + #[link_name = "__asp3_acre_mtx"] + pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID; + #[link_name = "__asp3_del_mtx"] + pub fn del_mtx(tskid: ID) -> ER; + #[link_name = "__asp3_loc_mtx"] + pub fn loc_mtx(mtxid: ID) -> ER; + #[link_name = "__asp3_ploc_mtx"] + pub fn ploc_mtx(mtxid: ID) -> ER; + #[link_name = "__asp3_tloc_mtx"] + pub fn tloc_mtx(mtxid: ID, tmout: TMO) -> ER; + #[link_name = "__asp3_unl_mtx"] + pub fn unl_mtx(mtxid: ID) -> ER; + pub fn exd_tsk() -> ER; +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/condvar.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/condvar.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/condvar.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/condvar.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,294 @@ +//! POSIX conditional variable implementation based on user-space wait queues. +use super::{abi, error::expect_success_aborting, spin::SpinMutex, task, time::with_tmos_strong}; +use crate::{mem::replace, ptr::NonNull, sys::mutex::Mutex, time::Duration}; + +// The implementation is inspired by the queue-based implementation shown in +// Andrew D. Birrell's paper "Implementing Condition Variables with Semaphores" + +pub struct Condvar { + waiters: SpinMutex, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +pub type MovableCondvar = Condvar; + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) } + } + + pub unsafe fn init(&mut self) {} + + pub unsafe fn notify_one(&self) { + self.waiters.with_locked(|waiters| { + if let Some(task) = waiters.pop_front() { + // Unpark the task + match unsafe { abi::wup_tsk(task) } { + // The task already has a token. + abi::E_QOVR => {} + // Can't undo the effect; abort the program on failure + er => { + expect_success_aborting(er, &"wup_tsk"); + } + } + } + }); + } + + pub unsafe fn notify_all(&self) { + self.waiters.with_locked(|waiters| { + while let Some(task) = waiters.pop_front() { + // Unpark the task + match unsafe { abi::wup_tsk(task) } { + // The task already has a token. + abi::E_QOVR => {} + // Can't undo the effect; abort the program on failure + er => { + expect_success_aborting(er, &"wup_tsk"); + } + } + } + }); + } + + pub unsafe fn wait(&self, mutex: &Mutex) { + // Construct `Waiter`. + let mut waiter = waiter_queue::Waiter::new(); + let waiter = NonNull::from(&mut waiter); + + self.waiters.with_locked(|waiters| unsafe { + waiters.insert(waiter); + }); + + unsafe { mutex.unlock() }; + + // Wait until `waiter` is removed from the queue + loop { + // Park the current task + expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk"); + + if !self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) { + break; + } + } + + unsafe { mutex.lock() }; + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + // Construct and pin `Waiter` + let mut waiter = waiter_queue::Waiter::new(); + let waiter = NonNull::from(&mut waiter); + + self.waiters.with_locked(|waiters| unsafe { + waiters.insert(waiter); + }); + + unsafe { mutex.unlock() }; + + // Park the current task and do not wake up until the timeout elapses + // or the task gets woken up by `notify_*` + match with_tmos_strong(dur, |tmo| { + let er = unsafe { abi::tslp_tsk(tmo) }; + if er == 0 { + // We were unparked. Are we really dequeued? + if self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) { + // No we are not. Continue waiting. + return abi::E_TMOUT; + } + } + er + }) { + abi::E_TMOUT => {} + er => { + expect_success_aborting(er, &"tslp_tsk"); + } + } + + // Remove `waiter` from `self.waiters`. If `waiter` is still in + // `waiters`, it means we woke up because of a timeout. Otherwise, + // we woke up because of `notify_*`. + let success = self.waiters.with_locked(|waiters| unsafe { !waiters.remove(waiter) }); + + unsafe { mutex.lock() }; + success + } + + pub unsafe fn destroy(&self) {} +} + +mod waiter_queue { + use super::*; + + pub struct WaiterQueue { + head: Option, + } + + #[derive(Copy, Clone)] + struct ListHead { + first: NonNull, + last: NonNull, + } + + unsafe impl Send for ListHead {} + unsafe impl Sync for ListHead {} + + pub struct Waiter { + // These fields are only accessed through `&[mut] WaiterQueue`. + /// The waiting task's ID. Will be zeroed when the task is woken up + /// and removed from a queue. + task: abi::ID, + priority: abi::PRI, + prev: Option>, + next: Option>, + } + + unsafe impl Send for Waiter {} + unsafe impl Sync for Waiter {} + + impl Waiter { + #[inline] + pub fn new() -> Self { + let task = task::current_task_id(); + let priority = task::task_priority(abi::TSK_SELF); + + // Zeroness of `Waiter::task` indicates whether the `Waiter` is + // linked to a queue or not. This invariant is important for + // the correctness. + debug_assert_ne!(task, 0); + + Self { task, priority, prev: None, next: None } + } + } + + impl WaiterQueue { + #[inline] + pub const fn new() -> Self { + Self { head: None } + } + + /// # Safety + /// + /// - The caller must own `*waiter_ptr`. The caller will lose the + /// ownership until `*waiter_ptr` is removed from `self`. + /// + /// - `*waiter_ptr` must be valid until it's removed from the queue. + /// + /// - `*waiter_ptr` must not have been previously inserted to a `WaiterQueue`. + /// + pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull) { + unsafe { + let waiter = waiter_ptr.as_mut(); + + debug_assert!(waiter.prev.is_none()); + debug_assert!(waiter.next.is_none()); + + if let Some(head) = &mut self.head { + // Find the insertion position and insert `waiter` + let insert_after = { + let mut cursor = head.last; + loop { + if waiter.priority <= cursor.as_ref().priority { + // `cursor` and all previous waiters have the same or higher + // priority than `current_task_priority`. Insert the new + // waiter right after `cursor`. + break Some(cursor); + } + cursor = if let Some(prev) = cursor.as_ref().prev { + prev + } else { + break None; + }; + } + }; + + if let Some(mut insert_after) = insert_after { + // Insert `waiter` after `insert_after` + let insert_before = insert_after.as_ref().prev; + + waiter.prev = Some(insert_after); + insert_after.as_mut().next = Some(waiter_ptr); + + waiter.next = insert_before; + if let Some(mut insert_before) = insert_before { + insert_before.as_mut().prev = Some(waiter_ptr); + } + } else { + // Insert `waiter` to the front + waiter.next = Some(head.first); + head.first.as_mut().prev = Some(waiter_ptr); + head.first = waiter_ptr; + } + } else { + // `waiter` is the only element + self.head = Some(ListHead { first: waiter_ptr, last: waiter_ptr }); + } + } + } + + /// Given a `Waiter` that was previously inserted to `self`, remove + /// it from `self` if it's still there. + #[inline] + pub unsafe fn remove(&mut self, mut waiter_ptr: NonNull) -> bool { + unsafe { + let waiter = waiter_ptr.as_mut(); + if waiter.task != 0 { + let head = self.head.as_mut().unwrap(); + + match (waiter.prev, waiter.next) { + (Some(mut prev), Some(mut next)) => { + prev.as_mut().next = Some(next); + next.as_mut().next = Some(prev); + } + (None, Some(mut next)) => { + head.first = next; + next.as_mut().next = None; + } + (Some(mut prev), None) => { + prev.as_mut().next = None; + head.last = prev; + } + (None, None) => { + self.head = None; + } + } + + waiter.task = 0; + + true + } else { + false + } + } + } + + /// Given a `Waiter` that was previously inserted to `self`, return a + /// flag indicating whether it's still in `self`. + #[inline] + pub unsafe fn is_queued(&self, waiter: NonNull) -> bool { + unsafe { waiter.as_ref().task != 0 } + } + + pub fn pop_front(&mut self) -> Option { + unsafe { + let head = self.head.as_mut()?; + let waiter = head.first.as_mut(); + + // Get the ID + let id = replace(&mut waiter.task, 0); + + // Unlink the waiter + if let Some(mut next) = waiter.next { + head.first = next; + next.as_mut().prev = None; + } else { + self.head = None; + } + + Some(id) + } + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/error.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/error.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/error.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/error.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,159 @@ +use crate::{fmt, io::ErrorKind}; + +use super::abi; + +/// Wraps a μITRON error code. +#[derive(Debug, Copy, Clone)] +pub struct ItronError { + er: abi::ER, +} + +impl ItronError { + /// Construct `ItronError` from the specified error code. Returns `None` if the + /// error code does not represent a failure or warning. + #[inline] + pub fn new(er: abi::ER) -> Option { + if er < 0 { Some(Self { er }) } else { None } + } + + /// Returns `Ok(er)` if `er` represents a success or `Err(_)` otherwise. + #[inline] + pub fn err_if_negative(er: abi::ER) -> Result { + if let Some(error) = Self::new(er) { Err(error) } else { Ok(er) } + } + + /// Get the raw error code. + #[inline] + pub fn as_raw(&self) -> abi::ER { + self.er + } +} + +impl fmt::Display for ItronError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Allow the platforms to extend `error_name` + if let Some(name) = crate::sys::error::error_name(self.er) { + write!(f, "{} ({})", name, self.er) + } else { + write!(f, "{}", self.er) + } + } +} + +/// Describe the specified μITRON error code. Returns `None` if it's an +/// undefined error code. +pub fn error_name(er: abi::ER) -> Option<&'static str> { + match er { + // Success + er if er >= 0 => None, + + // μITRON 4.0 + abi::E_SYS => Some("system error"), + abi::E_NOSPT => Some("unsupported function"), + abi::E_RSFN => Some("reserved function code"), + abi::E_RSATR => Some("reserved attribute"), + abi::E_PAR => Some("parameter error"), + abi::E_ID => Some("invalid ID number"), + abi::E_CTX => Some("context error"), + abi::E_MACV => Some("memory access violation"), + abi::E_OACV => Some("object access violation"), + abi::E_ILUSE => Some("illegal service call use"), + abi::E_NOMEM => Some("insufficient memory"), + abi::E_NOID => Some("no ID number available"), + abi::E_OBJ => Some("object state error"), + abi::E_NOEXS => Some("non-existent object"), + abi::E_QOVR => Some("queue overflow"), + abi::E_RLWAI => Some("forced release from waiting"), + abi::E_TMOUT => Some("polling failure or timeout"), + abi::E_DLT => Some("waiting object deleted"), + abi::E_CLS => Some("waiting object state changed"), + abi::E_WBLK => Some("non-blocking code accepted"), + abi::E_BOVR => Some("buffer overflow"), + + // The TOPPERS third generation kernels + abi::E_NORES => Some("insufficient system resources"), + abi::E_RASTER => Some("termination request raised"), + abi::E_COMM => Some("communication failure"), + + _ => None, + } +} + +pub fn decode_error_kind(er: abi::ER) -> ErrorKind { + match er { + // Success + er if er >= 0 => ErrorKind::Uncategorized, + + // μITRON 4.0 + // abi::E_SYS + abi::E_NOSPT => ErrorKind::Unsupported, // Some("unsupported function"), + abi::E_RSFN => ErrorKind::InvalidInput, // Some("reserved function code"), + abi::E_RSATR => ErrorKind::InvalidInput, // Some("reserved attribute"), + abi::E_PAR => ErrorKind::InvalidInput, // Some("parameter error"), + abi::E_ID => ErrorKind::NotFound, // Some("invalid ID number"), + // abi::E_CTX + abi::E_MACV => ErrorKind::PermissionDenied, // Some("memory access violation"), + abi::E_OACV => ErrorKind::PermissionDenied, // Some("object access violation"), + // abi::E_ILUSE + abi::E_NOMEM => ErrorKind::OutOfMemory, // Some("insufficient memory"), + abi::E_NOID => ErrorKind::OutOfMemory, // Some("no ID number available"), + // abi::E_OBJ + abi::E_NOEXS => ErrorKind::NotFound, // Some("non-existent object"), + // abi::E_QOVR + abi::E_RLWAI => ErrorKind::Interrupted, // Some("forced release from waiting"), + abi::E_TMOUT => ErrorKind::TimedOut, // Some("polling failure or timeout"), + // abi::E_DLT + // abi::E_CLS + // abi::E_WBLK + // abi::E_BOVR + + // The TOPPERS third generation kernels + abi::E_NORES => ErrorKind::OutOfMemory, // Some("insufficient system resources"), + // abi::E_RASTER + // abi::E_COMM + _ => ErrorKind::Uncategorized, + } +} + +/// Similar to `ItronError::err_if_negative(er).expect()` except that, while +/// panicking, it prints the message to `panic_output` and aborts the program +/// instead. This ensures the error message is not obscured by double +/// panicking. +/// +/// This is useful for diagnosing creation failures of synchronization +/// primitives that are used by `std`'s internal mechanisms. Such failures +/// are common when the system is mis-configured to provide a too-small pool for +/// kernel objects. +#[inline] +pub fn expect_success(er: abi::ER, msg: &&str) -> abi::ER { + match ItronError::err_if_negative(er) { + Ok(x) => x, + Err(e) => fail(e, msg), + } +} + +/// Similar to `ItronError::err_if_negative(er).expect()` but aborts instead. +/// +/// Use this where panicking is not allowed or the effect of the failure +/// would be persistent. +#[inline] +pub fn expect_success_aborting(er: abi::ER, msg: &&str) -> abi::ER { + match ItronError::err_if_negative(er) { + Ok(x) => x, + Err(e) => fail_aborting(e, msg), + } +} + +#[cold] +pub fn fail(e: impl fmt::Display, msg: &&str) -> ! { + if crate::thread::panicking() { + fail_aborting(e, msg) + } else { + panic!("{} failed: {}", *msg, e) + } +} + +#[cold] +pub fn fail_aborting(e: impl fmt::Display, msg: &&str) -> ! { + rtabort!("{} failed: {}", *msg, e) +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/mutex.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/mutex.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/mutex.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/mutex.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,183 @@ +//! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and +//! `TA_INHERIT` are available. +use super::{ + abi, + error::{expect_success, expect_success_aborting, fail, ItronError}, + spin::SpinIdOnceCell, +}; +use crate::cell::UnsafeCell; + +pub struct Mutex { + /// The ID of the underlying mutex object + mtx: SpinIdOnceCell<()>, +} + +pub type MovableMutex = Mutex; + +/// Create a mutex object. This function never panics. +fn new_mtx() -> Result { + ItronError::err_if_negative(unsafe { + abi::acre_mtx(&abi::T_CMTX { + // Priority inheritance mutex + mtxatr: abi::TA_INHERIT, + // Unused + ceilpri: 0, + }) + }) +} + +impl Mutex { + pub const fn new() -> Mutex { + Mutex { mtx: SpinIdOnceCell::new() } + } + + pub unsafe fn init(&mut self) { + // Initialize `self.mtx` eagerly + let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx")); + unsafe { self.mtx.set_unchecked((id, ())) }; + } + + /// Get the inner mutex's ID, which is lazily created. + fn raw(&self) -> abi::ID { + match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) { + Ok((id, ())) => id, + Err(e) => fail(e, &"acre_mtx"), + } + } + + pub unsafe fn lock(&self) { + let mtx = self.raw(); + expect_success(unsafe { abi::loc_mtx(mtx) }, &"loc_mtx"); + } + + pub unsafe fn unlock(&self) { + let mtx = unsafe { self.mtx.get_unchecked().0 }; + expect_success_aborting(unsafe { abi::unl_mtx(mtx) }, &"unl_mtx"); + } + + pub unsafe fn try_lock(&self) -> bool { + let mtx = self.raw(); + match unsafe { abi::ploc_mtx(mtx) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"ploc_mtx"); + true + } + } + } + + pub unsafe fn destroy(&self) { + if let Some(mtx) = self.mtx.get().map(|x| x.0) { + expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx"); + } + } +} + +pub(super) struct MutexGuard<'a>(&'a Mutex); + +impl<'a> MutexGuard<'a> { + #[inline] + pub(super) fn lock(x: &'a Mutex) -> Self { + unsafe { x.lock() }; + Self(x) + } +} + +impl Drop for MutexGuard<'_> { + #[inline] + fn drop(&mut self) { + unsafe { self.0.unlock() }; + } +} + +// All empty stubs because this platform does not yet support threads, so lock +// acquisition always succeeds. +pub struct ReentrantMutex { + /// The ID of the underlying mutex object + mtx: abi::ID, + /// The lock count. + count: UnsafeCell, +} + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { + ReentrantMutex { mtx: 0, count: UnsafeCell::new(0) } + } + + pub unsafe fn init(&mut self) { + self.mtx = expect_success( + unsafe { + abi::acre_mtx(&abi::T_CMTX { + // Priority inheritance mutex + mtxatr: abi::TA_INHERIT, + // Unused + ceilpri: 0, + }) + }, + &"acre_mtx", + ); + } + + pub unsafe fn lock(&self) { + match unsafe { abi::loc_mtx(self.mtx) } { + abi::E_OBJ => { + // Recursive lock + unsafe { + let count = &mut *self.count.get(); + if let Some(new_count) = count.checked_add(1) { + *count = new_count; + } else { + // counter overflow + rtabort!("lock count overflow"); + } + } + } + er => { + expect_success(er, &"loc_mtx"); + } + } + } + + pub unsafe fn unlock(&self) { + unsafe { + let count = &mut *self.count.get(); + if *count > 0 { + *count -= 1; + return; + } + } + + expect_success_aborting(unsafe { abi::unl_mtx(self.mtx) }, &"unl_mtx"); + } + + pub unsafe fn try_lock(&self) -> bool { + let er = unsafe { abi::ploc_mtx(self.mtx) }; + if er == abi::E_OBJ { + // Recursive lock + unsafe { + let count = &mut *self.count.get(); + if let Some(new_count) = count.checked_add(1) { + *count = new_count; + } else { + // counter overflow + rtabort!("lock count overflow"); + } + } + true + } else if er == abi::E_TMOUT { + // Locked by another thread + false + } else { + expect_success(er, &"ploc_mtx"); + // Top-level lock by the current thread + true + } + } + + pub unsafe fn destroy(&self) { + expect_success_aborting(unsafe { abi::del_mtx(self.mtx) }, &"del_mtx"); + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/spin.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/spin.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/spin.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/spin.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,164 @@ +use super::abi; +use crate::{ + cell::UnsafeCell, + convert::TryFrom, + mem::MaybeUninit, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, +}; + +/// A mutex implemented by `dis_dsp` (for intra-core synchronization) and a +/// spinlock (for inter-core synchronization). +pub struct SpinMutex { + locked: AtomicBool, + data: UnsafeCell, +} + +impl SpinMutex { + #[inline] + pub const fn new(x: T) -> Self { + Self { locked: AtomicBool::new(false), data: UnsafeCell::new(x) } + } + + /// Acquire a lock. + #[inline] + pub fn with_locked(&self, f: impl FnOnce(&mut T) -> R) -> R { + struct SpinMutexGuard<'a>(&'a AtomicBool); + + impl Drop for SpinMutexGuard<'_> { + #[inline] + fn drop(&mut self) { + self.0.store(false, Ordering::Release); + unsafe { abi::ena_dsp() }; + } + } + + let _guard; + if unsafe { abi::sns_dsp() } == 0 { + let er = unsafe { abi::dis_dsp() }; + debug_assert!(er >= 0); + + // Wait until the current processor acquires a lock. + while self.locked.swap(true, Ordering::Acquire) {} + + _guard = SpinMutexGuard(&self.locked); + } + + f(unsafe { &mut *self.data.get() }) + } +} + +/// `OnceCell<(abi::ID, T)>` implemented by `dis_dsp` (for intra-core +/// synchronization) and a spinlock (for inter-core synchronization). +/// +/// It's assumed that `0` is not a valid ID, and all kernel +/// object IDs fall into range `1..=usize::MAX`. +pub struct SpinIdOnceCell { + id: AtomicUsize, + spin: SpinMutex<()>, + extra: UnsafeCell>, +} + +const ID_UNINIT: usize = 0; + +impl SpinIdOnceCell { + #[inline] + pub const fn new() -> Self { + Self { + id: AtomicUsize::new(ID_UNINIT), + extra: UnsafeCell::new(MaybeUninit::uninit()), + spin: SpinMutex::new(()), + } + } + + #[inline] + pub fn get(&self) -> Option<(abi::ID, &T)> { + match self.id.load(Ordering::Acquire) { + ID_UNINIT => None, + id => Some((id as abi::ID, unsafe { (&*self.extra.get()).assume_init_ref() })), + } + } + + #[inline] + pub fn get_mut(&mut self) -> Option<(abi::ID, &mut T)> { + match *self.id.get_mut() { + ID_UNINIT => None, + id => Some((id as abi::ID, unsafe { (&mut *self.extra.get()).assume_init_mut() })), + } + } + + #[inline] + pub unsafe fn get_unchecked(&self) -> (abi::ID, &T) { + (self.id.load(Ordering::Acquire) as abi::ID, unsafe { + (&*self.extra.get()).assume_init_ref() + }) + } + + /// Assign the content without checking if it's already initialized or + /// being initialized. + pub unsafe fn set_unchecked(&self, (id, extra): (abi::ID, T)) { + debug_assert!(self.get().is_none()); + + // Assumption: A positive `abi::ID` fits in `usize`. + debug_assert!(id >= 0); + debug_assert!(usize::try_from(id).is_ok()); + let id = id as usize; + + unsafe { *self.extra.get() = MaybeUninit::new(extra) }; + self.id.store(id, Ordering::Release); + } + + /// 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. + /// + /// Warning: `f` must not perform a blocking operation, which + /// includes panicking. + #[inline] + pub fn get_or_try_init(&self, f: F) -> Result<(abi::ID, &T), E> + where + F: FnOnce() -> Result<(abi::ID, T), E>, + { + // Fast path + if let Some(x) = self.get() { + return Ok(x); + } + + self.initialize(f)?; + + debug_assert!(self.get().is_some()); + + // Safety: The inner value has been initialized + Ok(unsafe { self.get_unchecked() }) + } + + fn initialize(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result<(abi::ID, T), E>, + { + self.spin.with_locked(|_| { + if self.id.load(Ordering::Relaxed) == ID_UNINIT { + let (initialized_id, initialized_extra) = f()?; + + // Assumption: A positive `abi::ID` fits in `usize`. + debug_assert!(initialized_id >= 0); + debug_assert!(usize::try_from(initialized_id).is_ok()); + let initialized_id = initialized_id as usize; + + // Store the initialized contents. Use the release ordering to + // make sure the write is visible to the callers of `get`. + unsafe { *self.extra.get() = MaybeUninit::new(initialized_extra) }; + self.id.store(initialized_id, Ordering::Release); + } + Ok(()) + }) + } +} + +impl Drop for SpinIdOnceCell { + #[inline] + fn drop(&mut self) { + if self.get_mut().is_some() { + unsafe { (&mut *self.extra.get()).assume_init_drop() }; + } + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/task.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/task.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/task.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/task.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,44 @@ +use super::{ + abi, + error::{fail, fail_aborting, ItronError}, +}; + +use crate::mem::MaybeUninit; + +/// Get the ID of the task in Running state. Panics on failure. +#[inline] +pub fn current_task_id() -> abi::ID { + try_current_task_id().unwrap_or_else(|e| fail(e, &"get_tid")) +} + +/// Get the ID of the task in Running state. Aborts on failure. +#[inline] +pub fn current_task_id_aborting() -> abi::ID { + try_current_task_id().unwrap_or_else(|e| fail_aborting(e, &"get_tid")) +} + +/// Get the ID of the task in Running state. +#[inline] +pub fn try_current_task_id() -> Result { + unsafe { + let mut out = MaybeUninit::uninit(); + ItronError::err_if_negative(abi::get_tid(out.as_mut_ptr()))?; + Ok(out.assume_init()) + } +} + +/// Get the specified task's priority. Panics on failure. +#[inline] +pub fn task_priority(task: abi::ID) -> abi::PRI { + try_task_priority(task).unwrap_or_else(|e| fail(e, &"get_pri")) +} + +/// Get the specified task's priority. +#[inline] +pub fn try_task_priority(task: abi::ID) -> Result { + unsafe { + let mut out = MaybeUninit::uninit(); + ItronError::err_if_negative(abi::get_pri(task, out.as_mut_ptr()))?; + Ok(out.assume_init()) + } +} diff -Nru rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/thread.rs rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/thread.rs --- rustc-1.56.0+dfsg1+llvm/library/std/src/sys/itron/thread.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.57.0+dfsg1+llvm/library/std/src/sys/itron/thread.rs 2021-11-29 19:27:11.000000000 +0000 @@ -0,0 +1,352 @@ +//! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and +//! `exd_tsk` are available. +use super::{ + abi, + error::{expect_success, expect_success_aborting, ItronError}, + task, + time::dur2reltims, +}; +use crate::{ + cell::UnsafeCell, + convert::TryFrom, + ffi::CStr, + hint, io, + mem::ManuallyDrop, + sync::atomic::{AtomicUsize, Ordering}, + sys::thread_local_dtor::run_dtors, + time::Duration, +}; + +pub struct Thread { + inner: ManuallyDrop>, + + /// The ID of the underlying task. + task: abi::ID, +} + +/// State data shared between a parent thread and child thread. It's dropped on +/// a transition to one of the final states. +struct ThreadInner { + /// This field is used on thread creation to pass a closure from + /// `Thread::new` to the created task. + start: UnsafeCell>>, + + /// A state machine. Each transition is annotated with `[...]` in the + /// source code. + /// + /// ```text + /// + ///